Skip to main content

Kill Switch

session.kill() is an emergency stop for your AI agent. It blocks all subsequent tool calls immediately — no negotiation, no retries, no "one more call."


Why you need this

A Meta AI safety director's personal assistant agent started deleting every email older than one week. She said "STOP" multiple times. The agent ignored her. She had to physically run to her machine and kill the process.

There was no kill switch. There is now.


How it works

// Something's going wrong — stop immediately
session.kill();

// All subsequent calls throw ReplayKillError
try {
await session.client.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Continue processing" }],
tools,
});
} catch (e) {
if (e instanceof ReplayKillError) {
console.log("Session killed — no more tool calls");
}
}

After kill():

  • Every call through session.client.create() throws ReplayKillError
  • Session state is frozen — no further state changes
  • Pending captures are flushed
  • The session cannot be resumed
  • In Govern mode, the kill is propagated to the server

What kill can and can't do

What it does

  • Blocks all future calls through the wrapper
  • Freezes session state (stateVersion, forbiddenTools stop changing)
  • Sets killed: true permanently
  • Flushes any pending captures
  • In Govern mode, marks the server-side session as KILLED

What it can't do

  • Can't stop in-flight calls. If a tool executor is currently running (e.g., a database write), kill() doesn't interrupt it. The executor completes — its side effects have already occurred. After it returns, the SDK detects the kill, discards the result, and throws on the next call.
  • Can't stop server-side agent loops. If you're using OpenAI Assistants or another hosted agent platform where the execution loop runs server-side, kill() only affects your SDK client — it can't reach the server-side thread.
  • Can't undo what already happened. If the agent already issued a refund or deleted a file, kill() doesn't reverse that. It prevents the next action.

Automatic kill: circuit breaker

You don't always need to call kill() manually. The circuit breaker auto-kills the session after too many consecutive failures.

# session.yaml
session_limits:
circuit_breaker:
consecutive_blocks: 5 # Auto-kill after 5 consecutive blocked calls
consecutive_errors: 3 # Auto-kill after 3 consecutive internal errors

When the circuit breaker triggers, it calls kill() internally. Same behavior — all subsequent calls throw ReplayKillError.


After killing: recovery

A killed session is permanently dead. To continue, create a new session:

// Kill the broken session
session.kill();

// Restore the original client
session.restore();

// Start a new session (optionally in log-only mode for recovery)
const recoverySession = replay(client, {
contractsDir: "./contracts",
agent: "my-agent",
mode: "enforce", // or "log-only" for recovery actions
});

restore() releases the wrapper and returns the original client to its normal state. You must call restore() before creating a new replay() session on the same client.


Checking kill status

const state = session.getState();
console.log(state.killed); // true after kill()

const health = session.getHealth();
console.log(health.killed); // true
console.log(health.authorityState); // "killed"
console.log(health.status); // "inactive"

Kill in Govern mode

When connected to the Vesanor server, kill() propagates durably:

  1. SDK marks local session as killed
  2. Kill request sent to server
  3. Server marks session status as KILLED
  4. Future preflight/proposal/receipt requests are rejected
  5. Server-side session cannot be resumed
// Verify kill propagated
const health = session.getHealth();
console.log(health.durability); // "server" — kill is durable

When to use kill

ScenarioUse kill?
Agent is in a loopYes — or let circuit breaker handle it
Agent called a destructive tool it shouldn't haveYes — prevent further damage
Agent exceeded budgetAutomatic — max_cost_per_session triggers kill
User requests stopYes — wire to your UI's stop button
Debugging completeNo — use session.restore() to cleanly end
Normal session endNo — just stop calling session.client

Next steps