Agent streams
An agent stream handle exposes the complete runtime loop plus convenient projections for visible text and the terminal outcome.
1. Stream a stateless run
const stream = agent.stream({
prompt: 'Has the latest invoice been paid?'
})
for await (const event of stream.events) {
switch (event.type) {
case 'text_delta':
process.stdout.write(event.delta)
break
case 'tool_call':
console.log('\nTool:', event.toolCall.toolName)
break
case 'tool_result':
console.log('Completed:', event.toolName)
break
case 'response':
console.log('\nRun:', event.runId)
console.log('Output:', event.output)
console.log('Tokens:', event.usage.totalTokens)
break
case 'interaction':
console.log('\nInteraction:', event.interaction)
break
case 'blocked':
console.log('\nBlocked:', event.reason)
break
}
}The final emitted item is the same response | interaction | blocked outcome returned by generate(). It carries run ID, cumulative usage, messages, and optional context usage, trace, guardrail decisions, sources, provider tool calls, or memory-compaction details.
2. Choose the smallest stream surface
Every AgentStream has one iterable consumer. Choose one iterable surface per run:
const stream = agent.stream({ prompt: 'Draft the incident update.' })
for await (const delta of stream.textStream) {
process.stdout.write(delta)
}
const outcome = await stream.result
if (outcome.type === 'response') console.log(outcome.output)- Iterate
streamorstream.eventsfor complete runtime events. - Iterate
stream.textStreamfor visible text deltas only. - Await
stream.textfor collected visible text. - Await
stream.resultfor the terminal outcome without manually draining events, or after the chosen iterator finishes.
Awaiting text or result starts an internal drain when no iterator is active. Do not start a second iterator on the same handle; the final promises remain safe to await after iteration.
3. Stream through a memory session
Use the session directly when the agent has configured memory:
const session = { sessionId: 'thread_123', userId: 'user_456' };
for await (const event of agent.stream({
prompt: 'Has my latest invoice been paid?',
session: session
})) {
await handleEvent(event);
}There is no intermediate prompt-request builder in v1. agent.stream({ prompt, session }) returns the stream directly.
4. Treat tool-call deltas as provisional
tool_call_delta events may contain partial names or argument fragments. When argumentsMode is replace, argumentsDelta is a full current snapshot rather than text to append.
Only the completed tool_call event is authoritative. Anvia validates and executes the completed call, not the provisional fragments.
Consumers that only understand completed calls should ignore tool_call_delta:
for await (const event of agent.stream({
prompt: input
})) {
if (event.type === 'tool_call') handleCompleteToolCall(event)
}5. Handle nested agent events
When an agent is exposed as a tool with asTool({ stream: true }), its child events are wrapped in agent_tool_event on the parent stream.
Internal operator views may inspect the nested event. Public interfaces should usually collapse it to a safe status such as “Checking specialist guidance.”
6. Steer an active stream
An AgentStream also exposes steer(input). Accepted input receives a stable queued receipt; an invalid or closed-run steer throws:
const stream = agent.stream({
prompt: 'Draft the incident update.'
})
const receipt = stream.steer({
prompt: 'Also mention that mitigation is already in progress.',
})
console.log(receipt.id, receipt.status) // queuedThe stream emits steering_applied with the same ID when that input enters a later turn. Steering does not replace cancellation or tool approval.
Next, review the complete event types.