ReferenceProtocols and contracts

Streaming protocol

Blazing Agents uses AI SDK UI-message SSE for Session activity and chunked plain text for stateless generation. Use this page when relaying a response, reading it in the SDK, or handling cancellation and failures.

Contract

SurfaceHTTP responseBodySDK result
New Session Turn201; Location contains the new Session ID; text/event-stream; x-vercel-ai-ui-message-stream: v1AI SDK UIMessageChunk SSEsessionId, toUIMessageStream(), toResponse()
Resumed Session Turn200; no Location; same stream headersAI SDK UIMessageChunk SSEsame, using the supplied Session ID
Session Turn with stream: false201 on create or 200 on resume; application/json; create still includes Location{ "message": UIMessage }REST only; the SDK always requests a stream
Text generation200; text/plain; charset=utf-8chunked texttextStream, awaited text, toResponse()
Object generation200; text/plain; charset=utf-8chunked partial JSON textpartialObjectStream, awaited object, toResponse()
Tool approval continuation200; UI-message SSE headerspersisted continuation chunksjoinToolApprovalContinuation() terminal result

UI-message streams contain data: records whose values are AI SDK UIMessageChunk objects, followed by data: [DONE]. They are not OpenAI-compatible delta streams. Stateless object mode uses the same text wire format as text mode; the SDK parses partial and final JSON.

The create Session route mints an ss_... ID. result.sessionId reads it from the Location header before the body is consumed. On resume it resolves to the ID supplied by the caller. For interactive creation, a failed or aborted first Turn does not materialize the Session, so attempting to resume that ID returns not_found.

Chat and Tool approval continuation results allow one body claim: call either toUIMessageStream() or toResponse(). A second claim throws SDK stream_error. Completion and object results tee the successful body internally, so their iterator, awaited final value, and relay are all available from one result. toResponse() always constructs a new relay response with status 200; on a newly created Session it does not preserve the upstream 201 or Location header. Read result.sessionId separately.

Failures have two phases:

  • A fetch failure before an HTTP exchange is SDK network_error.
  • A non-2xx response before streaming starts uses the normal error envelope.
  • After a Session stream starts, failure is a native { "type": "error", "errorText": "safe prose" } chunk and the HTTP status remains successful.
  • A failed text/object transport, invalid final JSON, malformed SSE, or invalid create Location becomes SDK stream_error. Await text or object when the terminal outcome matters.

Cancellation depends on the surface. For chat, an input AbortSignal aborts the request and canceling the selected decoded or relay stream propagates to the active Turn. Completion and object inputs also forward AbortSignal; use it to cancel the Turn rather than relying on cancellation of one tee branch. Canceling a Tool approval join only detaches that polling response: it does not cancel the durable continuation. Failed and canceled Turns are metered but do not commit interactive Session transcript changes; external Tool side effects are not rolled back. Durable Tasks differ: the worker attaches a fresh Session before execution and incrementally commits user, assistant, and failure events, so failed or canceled Task runs can leave transcript and failure history.

A Tool approval decision returns 202 and a continuation identifier. Joining that continuation returns its terminal SSE stream; it does not reopen the original HTTP response.

Examples

This is a minimal valid UI-message stream. Production finish chunks also carry the platform's message usage metadata.

data: {"type":"start","messageId":"msg_1"}

data: {"type":"text-start","id":"text_1"}

data: {"type":"text-delta","id":"text_1","delta":"Hello"}

data: {"type":"text-end","id":"text_1"}

data: {"type":"finish","finishReason":"stop"}

data: [DONE]

Iterate deltas and await the assembled final text:

const result = await client.completion({
  agentId,
  prompt: "Write a two-sentence release note.",
});

for await (const delta of result.textStream) {
  process.stdout.write(delta);
}

const finalText = await result.text;

Forward cancellation from the caller:

const controller = new AbortController();
const result = await client.completion({
  agentId,
  prompt: "Analyze the report.",
  signal: controller.signal,
});

controller.abort();
await result.text;

Used by

Source of truth

  • packages/core/src/entities/chat.ts
  • packages/sdk/src/generation.ts
  • packages/sdk/src/generation.chat-results.test.ts
  • packages/sdk/src/generation.chat-requests.test.ts
  • packages/sdk/src/generation.chat-errors.test.ts
  • packages/sdk/src/generation.transport-errors.test.ts
  • packages/sdk/src/generation.completion.test.ts
  • packages/sdk/src/generation.object.test.ts
  • servers/api/src/routes/agents/generation.ts
  • servers/api/src/routes/agents/generation.test.ts
  • servers/api/src/routes/sessions/turns.ts
  • servers/api/src/routes/sessions/create-responses.test.ts
  • servers/api/src/routes/sessions/create-errors.test.ts
  • servers/api/src/routes/sessions/resume.test.ts
  • servers/api/src/routes/sessions/tool-approvals.ts
  • servers/api/src/routes/sessions/tool-approvals.test.ts
  • servers/task-worker/src/task-run-execution.ts
  • servers/task-worker/src/run-workflow-lifecycle.test.ts
  • servers/task-worker/src/run-workflow-persistence.test.ts

See the capability and guide links under Used by.

Reference

See the implementation inventory under Source of truth.

On this page