Skip to main content
This example builds on Use an agent. It implements every event handler pattern in one runnable client.

Overview

This client handles every event the harness can emit:
  • Streams assistant tokens in real time
  • Shows tool calls and tool results inline
  • Prompts the user to answer ask_user_question calls
  • Prompts the user to allow or deny tool approvals
  • Shows in-chat MCP OAuth prompts
  • Handles parallel sub-agents
  • Continues the conversation across turns

Sample run

Adapting the flow

A few common variations on top of the same skeleton:
  • Persisted history. Save session.id after the first turn. On the next process start, call client.getSession({ sessionId }) and use listTurns() with listEvents() to rebuild UI state, or turn.stream() if the latest turn is still running.
  • JSON output for piping. Replace the print calls inside _handle_event with json.dumps(event.model_dump()) to emit one event per line for downstream tools.
  • Generative UI. When you detect a fenced ```openui block in assembled model.message content, hand the block to the OpenUI React renderer instead of printing it. Everything else stays the same.
  • Browser / web UI. The same event shape is delivered over Server-Sent Events on POST /sessions/{session_id}/turns. Replace turn.execute({ stream: true }) with an SSE consumer; the handlers above are unchanged.