Skip to main content
Pass an event handler to a run or continuation to receive an event when the run starts, each model turn begins and ends, each tool runs, the run pauses, and the run ends. Use it to update your interface, write audit records, or feed your existing telemetry.

Where the handler goes and what it receives

Events the runtime emits

Detail keys are listed in snake_case below; TypeScript uses the camelCase form. Rust 0.2 uses its own names for some events: A run that ends on a stop condition sends run.stopped in TypeScript and no terminal event in Python, Go, C#, PHP, Ruby or Java; read the run’s status instead. In TypeScript, step.completed is sent after the step has been checkpointed, so persistence and telemetry consumers can treat it as a stable boundary.

Stream events

With streaming, the same lifecycle events arrive alongside the model’s response.* events. In TypeScript, Python, Go, C# and Java the handler receives them; in PHP and Ruby they also appear in fullStream() / full_stream. Rust has no streaming. Streaming covers the stream consumers.

Keep handlers fast

The runtime waits for the handler before it continues, so return quickly and move slow storage or network work onto a queue. Redact sensitive tool inputs and outputs before events leave your process.

Pick events for a product interface

Use response.output_text.delta for live answer text, tool events for tool-call cards and progress indicators, run.waiting_for_human (Rust: run.paused) to show approval or input controls, and terminal run events to close loading states. For a local record of whole runs during development, use DevTools.
Last modified on November 5, 2026