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 executionAPI 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
AbortErroras 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.signalinstead - Returning a response after abort — clients already disconnected
- Leaking listeners — always remove them