RUNTIME / STREAMING EVENTS
Observe the run as it happens.
Each run exposes a typed async event stream alongside a promise for the final result. Build a terminal renderer, UI, audit log, or JSONL output around the same events.
Consume events
Start a run and consume the async iterable to render progress while the model and tools run. Events are discriminated by type; narrow on that field before reading event-specific properties.
const run = runAgent({ model, prompt, system, tools });
let answer = "";
for await (const event of run.events) {
switch (event.type) {
case "text-delta":
answer += event.text;
renderAssistantText(answer);
break;
case "tool-call":
renderTool({ name: event.toolName, input: event.input, status: "running" });
break;
case "tool-result":
renderToolResult({
callId: event.toolCallId, output: event.output, failed: event.isError,
});
break;
case "finish":
renderRunStatus(event.reason);
break;
}
}
const result = await run.result;
saveTranscript(result.messages);Event types
run-startStep and token budgets for the run.step-startThe next model round-trip is starting.text-deltaA streamed text fragment.tool-callTool name, input, call ID, and step.tool-resultCapped textual output and error flag.tool-approval-requestA tool call held for a human decision.step-finishCumulative usage at the end of a step.compactedTranscript counts and summary size after compaction.user-messageA mid-turn message you sent: delivery, and queued or delivered.finishFinal stop reason, assistant text, and usage.errorAn error emitted before the run rejects.The finish.reason is one of completed, max-steps, max-tokens, aborted, or error.
Mid-turn messages
A message you send while the run is in flight emits user-message twice: once when the harness accepts it, and once when it actually enters the transcript. Those are different moments, and a UI needs both — render a pending chip on the first and clear it on the second.
{ type: "user-message", delivery: "steer", phase: "queued" }
{ type: "user-message", delivery: "steer", phase: "delivered" }delivery is steer or follow-up. For the semantics, and why a pending message prevents the run from ending, see steering a running turn.
Cancellation and errors
Pass an AbortSignal through abortSignal, or call run.interrupt(). Cancellation reaches executing tools, so a long-running command stops rather than merely appearing to. An aborted run emits a finish event with reason aborted. Other failures emit an error event and reject the result promise, so handle that promise with your normal error handling.
const controller = new AbortController();
const run = runAgent({ ...options, abortSignal: controller.signal });
setTimeout(() => controller.abort(), 30_000);
try {
const result = await run.result;
} catch (error) {
console.error("Agent run failed", error);
}