Skip to main content

Streaming and Events

A run gives you two streams. By the end of this page you will have printed an answer as the model writes it, and followed the run’s telemetry events — the model calls, tool calls and results, the final answer — while it ran and after it ended.
Every output on this page is what the code printed when it was run with gpt-5.4-mini. The model’s wording, and so the number of text deltas, will differ on your run.

Stream the answer

Pass on_event to run(). It is called with each piece of text the model writes; a plain function works, and so does a coroutine.
The first line appeared piece by piece. run() still returns the whole result when the run ends. The last line is the other stream: every event the run recorded, in order — two agent_steps, the tool call between them (asked of the policy first: policy_request_created, then policy_decision_allow, since governance is on by default), the final_answer.

Or iterate over the run

agent.stream() gives the same deltas as an async iterator, then one complete event carrying the whole result (or one error event):
The complete event has every key run() returns (response, status, run_id, trace_id, …). Leaving the loop early — or closing the iterator — cancels the run; aclosing makes sure that happens as soon as you stop.

What a delta carries

Text is streamed for every model turn, including what the model says before it calls a tool. resume(run_id, on_event=...) streams a resumed run the same way.

Follow the run’s events live

Take a cursor before the run starts, then read events after it as they are recorded. event_types narrows the stream:
stream_telemetry_after keeps waiting for new events, so stop it yourself — here at final_answer. Each event is a TelemetryEvent with event_type, event_id, trace_id, timestamp, actor, input, output, error, token_usage, estimated_cost_usd and metadata; runtime events carry run_id, session_id and agent_id in their metadata.

The events

These are the ones you will use most. What an event records (for example, whether a tool’s arguments are kept in full) follows your telemetry settings. run_resumed says why in its metadata: cause is approval, budget_grant, budget_denied, interrupted, or recovered_after_lapsed_lease, and trigger is explicit (a call to resume) or orphan_sweep (the server’s sweeper). A recovered run also carries previous_owner, lease_expired_at and orphaned_seconds, how long it sat with no process. A decided run the sweep resumed carries decision and decided_at instead.

Look up a finished run

Use trace_id for one exact trace; use run_id to find a run inside a session. A run that paused and resumed has one trace per segment, and the run_id lookup returns the latest. Traces can also be exported to OTLP, LangSmith or Opik (Observability).

Over HTTP

OmniServe serves the same streams:
  • POST /run runs the agent and streams its text deltas and telemetry events as Server-Sent Events, ending with complete.
  • GET /telemetry/events returns stored events as JSON, filtered by trace_id, run_id, session_id, task_id or event_type; 200 events by default.
  • GET /telemetry/events/stream?session_id=... replays a session’s stored events and follows new ones; add run_id for one run.
  • GET /telemetry/traces/{trace_id}, GET /telemetry/runs/{run_id}/trace and GET /telemetry/sessions/{session_id}/trace return one trace, or 404. GET /telemetry/traces lists traces, 100 by default.
The older /events/{session_id}, /events/{session_id}/list and /events/{session_id}/trace routes remain as compact session aliases; add ?run_id=... to isolate one run.

Background run events

Background agents add run lifecycle events, read with get_run_events(run_id) or GET /background/runs/{run_id}/events. They are recorded in telemetry, kept by the manager, and mirrored to the task workspace’s events.jsonl when its workspace policy allows.

Options

The full signatures are in the OmniCoreAgent reference.

When things go wrong

agent.stream(...) is iterated, not awaited: async for event in agent.stream(...).
Pass what to look up: get_trace(result["trace_id"]), or get_trace(run_id=...) / get_trace(session_id=...).
Trace lookups take one key at a time.
It follows new events until you stop it. Break on final_answer (or runtime_error), or await the run’s task and stop then.
Deltas go only to the on_event of the run you started (or stream()), and are not stored: they cannot be replayed from telemetry afterwards. The telemetry events are stored, and the finished answer is in final_answer and the run’s result.

Next

Observability

Read a run as a trajectory; export traces.

OmniServe

The same streams over REST and SSE.

Background agents

Scheduled and queued runs, and their lifecycle events.

Sub-agents

Child runs, linked traces, and their events.