🏖️ SandAgent

Abort Signal

Cancel long-running agent work with AbortSignal

SandAgent uses the standard AbortController/AbortSignal API to propagate cancellation from the API layer into the sandbox and runner.

Signal Flow

API Route (request.signal)

SandAgent Manager → sandbox.exec()

Sandbox Adapter → SIGTERM to remote process

Runner CLI → converts SIGTERM to AbortSignal, stops execution

API Layer

Pass request.signal directly — don't create a new controller on the server.

export async function POST(request: Request) {
  const response = await agent.stream({
    messages: [...],
    signal: request.signal,
  });
  return response;
}

Sandbox Adapter Behavior

Adapters listen to signal.abort and terminate the remote process. E2B/Sandock use PID capture to issue kill -TERM.

signal?.addEventListener("abort", abortHandler);

Runner Behavior

The runner converts OS signals to an internal AbortSignal and stops iteration.

process.on("SIGTERM", () => controller.abort());

for await (const chunk of runner.run(input, controller.signal)) {
  process.stdout.write(chunk);
}

Best Practices

  • Always pass the signal through your own wrappers
  • Clean up listeners in finally
  • Treat AbortError as normal cancellation, not a failure
try {
  await agent.stream({ messages, signal });
} catch (error) {
  if (error.name === "AbortError") {
    return; // Normal cancellation
  }
  throw error;
}

Common Pitfalls

  • Creating a new controller on the server — use request.signal instead
  • Returning a response after abort — clients already disconnected
  • Leaking listeners — always remove them

On this page