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.

tsnah
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.

tsnah
{ 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.

tsnah
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);
}