Skip to content

How to

Stream a Run into a UI

Consume a run's event stream: deltas for display, the final message for state

Read this when
  • Rendering agent output live in a TUI or web UI
  • Handling errors and cancellation mid-run

Start one run, consume its stream once, then keep the final messages.

pkg/agent
fig. 01 — Which event drives which part of the screen

Events paint the screen while the run happens. Wait returns what your application keeps afterwards. Read the stream once: Events and Wait describe the same run.

Start the run

a, err := pi.Agent("openai-completions/gpt-5-mini")
defer a.Close()
stream := a.Run(ctx, ai.UserMessage("Explain agent events in two sentences."))

Run appends the user message and starts one agent loop. A second active run on the same agent fails through its stream.

Consume events by type

for event, err := range stream.Events() {
if err != nil {
return err // the run failed: show it, then stop reading
}
switch event.Type {
case agent.EventMessageUpdate:
if e := event.AssistantEvent; e != nil && e.Type == ai.EventTextDelta {
fmt.Print(e.Delta)
}
// ... thinking_delta for a reasoning pane, tool_delta for arguments
case agent.EventToolExecutionStart:
fmt.Fprintf(os.Stderr, "\ntool: %s\n", event.ToolName)
case agent.EventToolExecutionEnd:
fmt.Fprintf(os.Stderr, "result: %v\n", event.Result)
}
}

event.AssistantEvent is nil on message events that carry no model delta, such as a recorded tool result. Make sure that it is not nil before you read it.

Finish: result or error

ctx, cancel := context.WithTimeout(ctx, 45*time.Second)
defer cancel()
messages, err := stream.Wait()
if err != nil {
return err // a context timeout arrives here too
}
last := messages[len(messages)-1]
fmt.Println(last.JoinText(""))

If the context expires, Wait returns the context error. Store the returned messages after a successful run.

Which events to show

  • Show message_update with AssistantEvent.Type == ai.EventTextDelta.
  • Show tool_execution_start as a tool status line.
  • Show tool_execution_update when a tool streams progress.
  • Store final messages from Wait or agent_end.
  • Ignore turn_start and turn_end unless you show turn boundaries.

Next: agent streaming concepts.