Streaming
Pass a block to run and it receives every event in the exchange, as it
happens. Text, thinking, and half-written tool arguments stream mid-turn;
the loop adds its own events around tools, approvals, and compaction.
agent.run("Summarize this thread.") do |event| case event.type when :text_delta then print event.delta when :tool_result then render(event.message.ui) when :approval_needed then notify_reviewers(event) endendThe event types
Stream events from the provider:
:start:text_start :text_delta :text_end:thinking_start :thinking_delta :thinking_end:toolcall_start :toolcall_delta :toolcall_end:done :error :retryLoop events from the harness: :tool_result after each tool runs,
:approval_needed when a gated call parks, and :compacting /
:compaction around a context fold. Events carry origin when they come
from a sub-agent, and duration where timing is meaningful.
Sinks
Sinks bridge the event stream to a transport and compose as blocks:
cable = Mistri::Sinks::ActionCable.new("agent_#{session.id}")sink = Mistri::Sinks::Coalesced.new(cable) # merge token bursts
agent.run(input, &sink)Mistri::Sinks::SSE.new(response.stream) does the same for
ActionController::Live.