Open Responses API Streaming Events

This document describes the Server-Sent Events (SSE) emitted by an Open Responses API implementation.
It is written from the perspective of clients (UI, CLI, notebook integrations) that consume streaming responses.

Overview

The API uses SSE (text/event-stream) and emits events in this wire format:
event: <event_name>
data: {"type":"<event_name>","event":"<event_name>", ...payload...}
Notes:
  • Terminal state is represented by response.completed or response.failed.
  • Some runtimes also emit a separate error event before response.failed.

Common Event Families

Events can belong to different categories:

1. Response lifecycle

  • response.created
  • response.in_progress
  • response.completed
  • response.failed
  • error (non-terminal helper event; usually followed by response.failed)
response.* lifecycle events typically include:
  • response: a response snapshot object with fields such as:
    • id
    • object ("response")
    • status
    • model
    • createdAt
    • metadata
    • usage
    • output

2. Output/message assembly events

These allow a client to render an assistant message incrementally.
  • response.output_item.added
  • response.content_part.added
  • response.output_text.delta
  • response.text.done
  • response.content_part.done
  • response.output_item.done
Typical fields:
  • response_id
  • output_index
  • content_index
  • item or part
  • delta (incremental text)
  • text (final text for the part)

3. Function-call events

  • response.function_call.arguments.delta
  • response.function_call.arguments.done
Typical fields:
  • response_id
  • output_index
  • call_id
  • delta (JSON string chunk)
  • arguments (final JSON string)
Emitted in rich streams when file search style tools run.
  • response.file_search_call.in_progress
  • response.file_search_call.searching
  • response.file_search_call.completed
Typical fields:
  • response_id
  • call_id
  • tool_name

5. Code interpreter events

Emitted in code_mode, biomni, and ds_star.
  • response.code_interpreter.in_progress
  • response.code_interpreter.call.code.delta
  • response.code_interpreter.call.code.done
  • response.code_interpreter.call.interpreting
  • response.code_interpreter.call.completed
  • response.code_interpreter.output_text.delta
  • response.code_interpreter.output_image.delta
Typical fields:
  • response_id
  • call_id
  • delta (code or output text)
  • mime_type, base64 (for image deltas)

6. Refusal / annotation events

Some implementation also emit OpenAI-style text metadata events when available:
  • response.refusal.delta
  • response.refusal.done
  • response.output_text.annotation.added
These are optional and depend on upstream container output.

Response Snapshot Shape (what clients should expect)

Across runtimes, response.* events carry a response object with a similar core shape:
{
  "id": "uuid",
  "object": "response",
  "status": "running|completed|failed|deleted",
  "model": "gpt-5-mini",
  "createdAt": "unix-ts-string",
  "metadata": { "...": "..." },
  "usage": {
    "input_tokens": 0,
    "output_tokens": 0,
    "total_tokens": 0,
    "input_token_details": {},
    "output_token_details": {},
    "usage_usd": 0.0
  },
  "output": []
}

Client Integration Guidance

Event handling strategy (recommended)

Handle the stream as:
  1. response.created → initialize UI state
  2. response.in_progress → refresh status/usage/progress
  3. output/function/code events → render incremental content and tools
  4. error (optional) → show error banner/log
  5. response.completed or response.failed → finalize UI state

Treat unknown events as non-fatal

New event types may be added. A robust client should:
  • ignore unknown events
  • log them for debugging
  • continue processing

Use response snapshots as source of truth

Incremental events are useful for UX, but final status/usage should come from the latest response snapshot in:
  • response.in_progress
  • response.completed
  • response.failed

Cancellation / Delete Semantics

Current implementation notes:
  • A DELETE /responses/{id} marks the task deleted.
  • In coarse polling, a deleted task is streamed as response.failed (terminal mapping).
  • Rich streams typically terminate as soon as the server-side stream ends; deletion is primarily represented through the response object state and delete endpoint behavior.

Minimal SSE Client Example (Python)

from openai import OpenAI

client = OpenAI(
    api_key="<TWENTYMINDS_API_KEY>",
    base_url="https://api.20minds.ai/v1/border-collie",
)

stream = client.responses.create(
    model="gpt-5.2",
    stream=True,
    input="Hello",
)

for event in stream:
    print(event.type, event)
    if event.type in ("response.completed", "response.failed"):
        break

Minimal SSE Client Example (TypeScript)

Using the openai package (recommended for Node/server-side clients):
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env.TWENTYMINDS_API_KEY,
  baseURL: "https://api.20minds.ai/v1/border-collie",
});

async function streamResponse(): Promise<void> {
  const stream = await client.responses.create({
    model: "gpt-5.2",
    stream: true,
    input: "Hello",
  });

  for await (const event of stream) {
    console.log(event.type, event);
    if (event.type === "response.completed" || event.type === "response.failed") {
      break;
    }
  }
}
Notes:
  • Set baseURL to the runtime-specific endpoint prefix (for example /v1/border-collie).
  • The SDK yields typed stream events with event.type values like response.output_text.delta, response.in_progress, and response.completed.
  • Do not use this pattern directly in the browser with a secret API key.
For runtime base URLs and the full endpoint surface (/responses, /files, /health, /reset) across research agents, see Open Responses APIs for Research Agents.