Streaming & Tracing
Real token-by-token streaming
runner.runStream(agent, input, options) returns immediately with an async-iterable event stream, plus a promise for the final result (same shape as runner.run()). Text deltas arrive in real-time as the model generates tokens — the Runner calls provider.stream() under the hood for genuine token-level delivery, not buffered chunks:
const { events, result } = runner.runStream(agent, "tell me a story");
for await (const evt of events) {
switch (evt.type) {
case "text_delta": process.stdout.write((evt.payload as any).delta); break;
case "tool_started": console.log("calling", (evt.payload as any).toolName); break;
case "tool_completed": console.log("tool done"); break;
case "handoff_started": console.log("handing off..."); break;
case "guardrail_triggered":console.log("guardrail tripped"); break;
case "retry": console.log("retrying provider call"); break;
case "run_completed": break;
case "run_failed": break;
}
}
const final = await result; // fully resolved RunResultFull event catalogue (AgentEventMap in events/AgentEvents.ts): run_started, text_delta, tool_started, tool_completed, tool_failed, guardrail_triggered, handoff_started, handoff_completed, retry, run_completed, run_failed.
You can also subscribe directly to a typed AgentEventBus if you're building the loop yourself (bus.on("tool_started", cb)), or bus.onAny(cb) for everything.
Tracing
Every run()/runStream() call creates a Trace (via the singleton Tracer), recording a span for every model call, tool call, handoff, retry, and guardrail check, each with timing:
const result = await runner.run(agent, "...");
console.log(result.trace.toPrettyString());Trace 3e1b... — agent "RouterAgent" — completed
total time: 2140ms
tokens: in=812 out=134 total=946
[model_call] turn_1 (610ms)
[handoff] RouterAgent -> WeatherAgent (0ms)
[model_call] turn_2 (540ms)
[tool_call] get_weather (612ms)
[model_call] turn_3 (378ms)Or pull the raw JSON for shipping to a logging backend:
result.trace.toJSON(); // { runId, agentName, status, spans: [...], totalTokenUsage, finalOutput, ... }
Tracer.instance().onFinish((trace) => sendToDatadog(trace)); // subscribe to every finished trace, process-wideThe CLI exposes this via /trace (toggle) or archadi chat --trace.