| title | description |
|---|---|
Events |
Understanding the agent event stream |
Agent sessions emit events via the onEvent callback. Each event has a type field. The wrapper forwards Claude Agent SDK messages as-is — tolerate unknown event types and preserve unknown fields for forward compatibility.
const session = await sandbox.agent.start({
prompt: "Build a REST API",
onEvent: (event) => {
switch (event.type) {
case "assistant":
process.stdout.write(String(event.message ?? ""));
break;
case "result":
console.log("Done:", event);
break;
default:
// Log unknown events rather than ignoring them
console.log(`[${event.type}]`, event);
}
},
});A typical successful session emits events in this order:
ready → configured → assistant / system / tool_use_summary → result → turn_complete
This is illustrative — the exact sequence depends on what the agent does. Multiple assistant, system, and tool_use_summary events may interleave as the agent works.
The agent process started and is waiting for configuration. Emitted once at session start.
Configuration applied, agent is working on the prompt.
Claude's text output. This is the agent "thinking out loud" or explaining what it's doing. The message field contains the text, but the exact payload shape comes from the upstream Claude SDK and may evolve.
System-level messages from the SDK. Common subtypes include initialization, task progress, and status updates.
Summary of a tool the agent just used — typically includes tool name and a brief description of what it did.
Progress updates from long-running tools. Common fields include tool_name and elapsed_time_seconds.
Final result of the agent's work. The subtype field indicates the kind of result. Payload varies by run mode — may include structured output, a summary, or error details.
The agent finished its current turn. Includes claude_session_id which you can use to resume the conversation in a new session.
onEvent: (event) => {
if (event.type === "turn_complete") {
savedSessionId = event.claude_session_id;
}
}The agent was stopped via session.interrupt().
The agent emitted an error. The message field describes what went wrong.
Common patterns:
// Capture only assistant output
const session = await sandbox.agent.start({
prompt: "Explain this codebase",
onEvent: (event) => {
if (event.type === "assistant") {
process.stdout.write(String(event.message ?? ""));
}
},
});# Collect all events and filter afterward
session = await sandbox.agent.start(prompt="Explain this codebase")
events = await session.collect_events()
assistant_messages = [e for e in events if e.type == "assistant"]
result = next((e for e in events if e.type == "result"), None)There are three error surfaces:
| Surface | When | Example |
|---|---|---|
error event |
Agent reports an error during execution | Invalid tool use, model error |
onError callback |
Raw stderr output from the agent process | Crash logs, unhandled exceptions |
| Promise rejection | WebSocket or API failure | Network error, auth expired |
Handle all three for robust agent monitoring:
const session = await sandbox.agent.start({
prompt: "...",
onEvent: (event) => {
if (event.type === "error") {
console.error("Agent error:", event.message);
}
},
onError: (data) => {
console.error("Process stderr:", data);
},
});
try {
await session.done;
} catch (err) {
console.error("Connection error:", err);
}