Long-running agents are in preview. APIs and package versions are subject to change.
The streaming model in brief
An event stream connects a producer (your agent work) to one or more subscribers (SSE, WebSocket, or polling). Two rules matter most:- Use a per-turn stream ID. Identify one request, turn, or invocation - never reuse a multiturm conversation ID as the stream ID.
- Choose a backing that matches the recovery you need. The backing decides whether late subscribers can replay and whether the stream survives a restart.
Choose a backing
With the Invocations and task primitives, pick a backing once at app startup, then look streams up by ID anywhere in your process:
For HTTP surfaces, prefer a replay backing so a subscriber can attach late without racing the producer. Choose
use_file_backed_replay when a producer might crash and a fresh worker must resume the same turn.
Pass
cursor_fn if you want cursored reconnect. It receives each event and returns an int cursor (a monotonically increasing sequence number is typical). Without it, subscribe(after=...) is ignored and last_cursor() returns None.Produce and subscribe
The producer and subscriber both callget_or_create(id) with the same ID and get the same stream:
Reconnect with the Responses protocol
The Responses protocol manages the SSE stream for you. A client reconnects by replaying from a cursor:Teach clients that any
response.in_progress event after the first one is a snapshot reset. On such an event the client replaces its local output with the snapshot in the event, discards partially accumulated content, and applies later events additively. Treat output indexes as slot identifiers, not monotonic counters - after a reset, an index might refer to an already-existing slot.