streaming capability, so UIs can paint reasoning, tool progress, model fallbacks, retries, live todos, tool results, and the final answer as they arrive.
accepted ack from the final answer.
Quick Start
1
Open a streaming client
2
Print each event type
Event Vocabulary
Each streaming event maps to anEventType in praisonaiagents.gateway.protocols and is advertised in hello_ok.features["events"] when the client negotiates streaming.
What each new event means to a live UI
model_fallback_stream— the primary model went down and the agent switched to a backup mid-turn. Render a “switched to backup model” banner instead of leaving the token stream frozen.metadata.from_modelis the model that failed,metadata.to_modelis now serving the turn,metadata.reason_categoryclassifies the failure (rate_limit,unavailable,error), andmetadata.fallback_indexis the 0-based position in the fallback chain.retry_stream— the agent is backing off before retrying a rate-limited or transient failure. Render a countdown (“retrying in 3s… attempt 2/5”) so the pause reads as progress, not a freeze.metadata.attempt/metadata.max_attemptsdrive the counter,metadata.delayis seconds until the next attempt, andmetadata.reasonis a short human string.todo_stream— the agent mutated its plan.metadata.todosis the full ordered list (each item carries its status and text), so re-render the whole checklist from it.tool_result_stream— a tool finished with a result.tool_callcarries the name, args, id, and result — render a tool result card;metadataholds any extra context.
reasoning_stream, tool_progress_stream, stream_error, and the four newer events — model_fallback_stream, retry_stream, todo_stream, and tool_result_stream — are additive. Existing token_stream consumers keep working unchanged — gate each new event on client.supports_event(...) so a legacy gateway that never advertises them degrades silently.reasoning_stream now fires for async agent runs on OpenAI Responses-API reasoning models too, matching the sync path. Gateway consumers of async runs on these models will start seeing this signal where they previously did not.Response Frame States
Every WebSocket response frame carries astatus: a provisional accepted ack arrives first, then the real answer as final with a structured outcome.
User Interaction Flow
A streaming UI paints each event as it arrives — reasoning bubble, then a tool progress chip, then the final answer. When the primary model fails mid-turn,model_fallback_stream and retry_stream fill the visible-progress gap so the token stream never looks frozen.
Common Patterns
- Reasoning Inline with Answer
- Tool Progress Chip
- Live Todo / Plan Progress
Best Practices
Gate rendering on client.supports_event(...)
Gate rendering on client.supports_event(...)
Wrap new-event rendering in
client.supports_event("reasoning_stream") and client.supports_event("tool_progress_stream") so legacy gateways — which never advertise these events — degrade silently instead of breaking.Treat stream_error as a soft signal
Treat stream_error as a soft signal
A
stream_error frame does not end the run. The gateway may still deliver a final response with outcome.status="error". Surface the error but keep listening until stream_end / final.Never assume type: response means done
Never assume type: response means done
Both the provisional ack and the real answer share
type: "response". Branch on status: show a spinner on accepted, render only on final, and read outcome.status for the completion state.Related
Gateway Handshake Protocol
Negotiate
streaming and read the advertised event setGateway Client
Reconnecting client that streams these events
Frame Codec
Validate inbound frames at the WebSocket boundary
Session Protocol
How sessions carry these events

