Skip to main content
When you drive chat entirely through the API using POST /v1/orchestrate/runs/stream, most agent responses arrive synchronously as SSE events. However, when the agent triggers an async flow (a tool flow that runs asynchronously), the stream pauses and the agent sends a holding message. Your application must detect this condition and poll the message thread until the flow completes and the agent resumes. This guide explains how to detect the async flow condition and how to poll for messages correctly.
This pattern applies only to applications that consume the watsonx Orchestrate chat API directly. If you use the embedded chat widget, the widget handles async flow polling automatically.

How async flows work

When the agent starts an async flow during a streaming run:
  1. The SSE stream emits a flow.slot.listen event containing the thread_id.
  2. The stream ends — no further message.delta events arrive on this connection.
  3. The flow runs asynchronously. The thread status changes to async_wait.
  4. When the flow needs user input (for example, a form or confirmation), the thread status changes to async_slot_request.
  5. When the flow completes, new messages are appended to the thread and the thread status returns to ready.
Your application is responsible for polling the thread’s messages between steps 2 and 5.

Step 1 — Start a streaming run and capture the thread ID

Send a message to POST /v1/orchestrate/runs/stream. Include the thread_id from the previous turn if you are continuing a conversation; omit it for a new conversation.

Step 2 — Detect the async flow condition

Check the return value of stream_run. When flow_started is True, the agent has handed off to a flow and you must poll.

Step 3 — Poll for new messages

Poll GET /v1/orchestrate/threads/{thread_id}/messages at a regular interval. Compare the message list with what you already have and display any new messages as they appear. The flow is still running while the thread status is async_wait. When the flow needs user input, the status changes to async_slot_request — this is your cue to prompt the user. When the status returns to ready, the flow has completed.

Putting it together

Thread status reference

SSE event reference

Notes

  • The flow.slot.listen event is the definitive signal that async polling is required. Do not rely on the absence of further message.delta events as the detection mechanism.
  • The WebSocket-based notification API (equivalent to how the native chat UI receives live flow updates) is not yet available for external API consumers. Polling /messages is the supported approach.
  • Poll intervals of 1–3 seconds are appropriate for most flows. Avoid polling faster than once per second.
  • Always use the thread_id returned in the SSE events — do not cache or infer it from elsewhere.