/v1/research-agent) and the Workflows execution endpoint
(/v1/workflow/execute) return a single, long-lived HTTP response that streams a
sequence of typed events using Server-Sent Events (SSE). A submitted workflow
delivers the same events, either live from its event stream or replayed from the
stored run. This page is the canonical reference for that stream: the event format,
every public message type, the typical order of events in a request, and a complete
handler you can copy into your codebase.
The SSE format
Each event is a single line beginning withdata: , followed by a JSON document
terminated by a newline:
data: are heartbeats or comments and should be ignored.
The stream ends after a COMPLETE (or ERROR) event.
The Research Agent and Workflows use slightly different envelopes:
- Research Agent wraps the event in a
messagefield:{"chat_id": "...", "message": {"type": "...", ...}} - Workflows wraps it in a
deltafield:{"request_id": "...", "execution_id": "...", "delta": {"type": "...", ...}}
event["delta"] instead of event["message"].Where the stream comes from
The same typed events reach you through several routes, and one handler serves all of them:- Live, on the request that started the run —
POST /v1/research-agentorPOST /v1/workflow/execute. - Live, attached to a submitted run —
GET /v1/workflow/execute/async/{execution_id}/stream. Every event on this stream also carries an SSEid, so a dropped connection can resume from where it left off with theLast-Event-IDheader. See Running a workflow. - Replayed from a stored run — the
eventslist inGET /v1/workflow/executions/{execution_id}, in the order they were emitted.
type once and reuse it for all three. The only routes that
differ are the envelope (see the note above) and, when reading a stored run, that
the events arrive as a JSON array rather than as SSE lines.
Message types
The public message types are listed below. Thetype field is the only field
guaranteed to be present on every message and is the discriminator your handler
should dispatch on.
Every message also carries an optional
message_id (groups related chunks; see below)
and a role (defaults to "assistant"; sub-agents may use other role names).
Typical lifecycle
A request that runs to completion emits events in roughly this order. Some types are optional and depend on the request configuration.LLM_RETRY (informational,
agent retries automatically) or TOOL_ERROR (per-tool failure; the agent may try a
different approach). An unrecoverable failure emits ERROR and terminates the stream
without a COMPLETE event. A submitted workflow whose answer restarts emits
STREAM_ROLLBACK before the replacement text.
Per-type reference
PLANNING
Emitted when the agent’s research plan changes. The full plan is sent each time; clients should replace any previously displayed plan with the latest version rather than diffing.NOT_STARTED, IN_PROGRESS, COMPLETED, SKIPPED, FAILED.
THINKING
The agent’s intermediate reasoning between tool calls.content may be a partial
chunk; concatenate consecutive chunks that share the same message_id to assemble a
single reasoning block.
ACTION
Notification that the agent is calling a tool. Useful for showing per-tool progress in the UI (e.g., “Searching for earnings transcripts…”).AUDIT message.
AUDIT
Detailed traces of tool executions. Each entry inaudit_traces carries an
audit_type discriminator and a tool_id that matches references in subsequent
GROUNDING messages.
SearchAuditV1, MarkdownAuditV1, StructuredReportAuditV1,
SubAgentStartedAuditV1, and SubAgentCompletedAuditV1. The full schema for each is
defined in the OpenAPI specs.
GROUNDING
Citations linking spans of the upcomingANSWER text to their sources. Each
reference carries start and end offsets, in Unicode code points, into the
cumulative answer text. See the Grounding and citations
guide for the full citation-rendering pattern, including the buffering requirement.
CHART
The agent sends this when it produces a chart while running code. See Code execution and charts for how to turn it on.vega_lite_spec is a standard
Vega-Lite specification. You can render it
with any Vega-Lite renderer. A chart also has start and end offsets. They point
to a span of the cumulative ANSWER text, so you can place the chart where the
answer refers to it.
vega_lite_spec above is trimmed to one data point for space. A real spec
carries the full series.
ANSWER
A chunk of the final answer text. MultipleANSWER events fire as the model
generates output. Concatenate content values in arrival order to reassemble the
full answer. Grounding offsets index into this cumulative concatenated text.
STRUCTURED_OUTPUT
Only emitted when the request included astructured_output_schema. Fires once,
after the final ANSWER chunk, with the extracted JSON. See the request schema for
constraints on the input schema (top-level must be an object or list-of-objects).
LLM_RETRY
Informational: the agent is retrying a transient LLM failure (rate limit, timeout, etc.). No client action is required; the agent will continue automatically. Log if useful for observability.TOOL_ERROR
A specific tool failed. The agent may recover by calling a different tool or synthesizing without that source. The stream continues. See Error handling for guidance on what to surface to users.ERROR
Unrecoverable. The stream terminates without aCOMPLETE event. Surface this to
the user.
COMPLETE
End of stream. Carries the final token consumption breakdown and, for Research Agent requests, acheckpoint_id that can be passed as from_checkpoint_id in a
follow-up request. See Conversation continuity.
STREAM_ROLLBACK
Emitted when a run that had begun answering starts that answer again, so the text already sent is superseded. Discard every event whose SSEid is greater than
to_seq, then render what follows. A to_seq of 0 discards the whole answer.
Applying the same rollback twice is harmless.
GET /v1/workflow/execute/async/{execution_id}/stream), where every event carries
an SSE id to compare against. It never appears on the synchronous endpoints, and a
stored run’s events list never replays it — by the time a run is stored, the
superseded text is already gone.
Handle it if you render answer text as it arrives. If you buffer the whole run and
only display the result at the end, keep the events in a list keyed by their SSE
id, drop the ones above to_seq, and you are done.
message_id and chunk grouping
The optional message_id field groups chunks that belong to a single logical unit.
The most common case is ANSWER: a long answer arrives as many small ANSWER
events, all sharing the same message_id. Clients can use the id to detect a new
answer turn versus a continuation of the current one. For most use cases, simply
concatenating consecutive ANSWER chunks in arrival order works.
Canonical Python streaming handler
The handler below dispatches ontype, reassembles the answer text, collects
grounding references, and prints a useful per-event log. It is the reference
implementation the rest of the docs build on.
https://agents.bigdata.com/v1/workflow/execute with a workflow payload, and read
the typed event from event["delta"] instead of event["message"]. It also works
unchanged against a submitted run’s event stream and against the events list of a
stored run.
Forward compatibility
New message types may be added in future API versions. Clients should treat unknowntype values as informational and continue processing the stream rather than
raising. The else branch in the handler above demonstrates this pattern.
Next steps
Grounding and citations
How GROUNDING references map to answer text spans, and how to render inline citations.
Error handling
The difference between ERROR, TOOL_ERROR, and LLM_RETRY, plus HTTP-level failure modes.
Conversation continuity
Resuming Research Agent chats with checkpoints and Workflows runs with execution IDs.
Research Agent quickstart
Build your first Research Agent request end-to-end.
Running a workflow
Attach to a submitted run’s event stream and resume it after a dropped connection.