> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runtools.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Stream Runs & Threads

> Stream immediate run output with SSE and live thread frames with WebSockets

Set `stream` to `true`, or omit it, to receive a Server-Sent Events response from `POST /v1/run`.

Use the thread WebSocket when you want durable thread state plus live token, reasoning, source, and tool-output deltas.

## Request

```bash theme={null}
curl -N -X POST https://api.runtools.ai/v1/run \
  -H "X-API-Key: $RUNTOOLS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: text/event-stream" \
  -d '{
    "agent": "code-assistant",
    "prompt": "Create a tiny TypeScript CLI.",
    "stream": true,
    "threadId": "thr_docs_example"
  }'
```

Streaming responses include:

```text theme={null}
Content-Type: text/event-stream
X-Run-ID: <run-id>
X-Thread-ID: <thread-id>
```

## Event Shape

Event names and payloads are produced by the active agent runtime and may vary by execution mode. Clients should parse SSE frames generically:

```typescript theme={null}
async function streamAgentRun() {
  const response = await fetch('https://api.runtools.ai/v1/run', {
    method: 'POST',
    headers: {
      'X-API-Key': process.env.RUNTOOLS_API_KEY!,
      'Content-Type': 'application/json',
      'Accept': 'text/event-stream',
    },
    body: JSON.stringify({
      agent: 'code-assistant',
      prompt: 'Run the test suite.',
      stream: true,
    }),
  });

  if (!response.body) throw new Error('No stream body');

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';

  for (;;) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });

    let boundary = buffer.indexOf('\n\n');
    while (boundary !== -1) {
      const frame = buffer.slice(0, boundary);
      buffer = buffer.slice(boundary + 2);
      console.log(frame);
      boundary = buffer.indexOf('\n\n');
    }
  }
}
```

Common SSE categories include agent text deltas, tool calls, tool results, errors, and completion frames. The exact run stream payload is produced by the active runtime.

## Thread WebSocket

The WebSocket surface is the canonical live thread stream:

```text theme={null}
wss://api.runtools.ai/v1/threads/{threadId}/events?api_key=<key>
wss://api.runtools.ai/v1/threads/{threadId}/events?token=<session-token>
```

The initial frame is a `snapshot` with `protocol_version: 1`. Owners receive live content. Admin broader-view sockets receive a metadata-only snapshot when they are not the thread owner.

Transient frames such as `assistant_message_delta`, `assistant_thinking_delta`, `assistant_message_source`, `tool_call_started`, `tool_output_delta`, and `tool_call_completed` are live-only. Final `assistant_message`, `tool_call`, and `tool_result` frames are durable thread events.

<Card title="Thread API" icon="book-open" href="/api-reference/threads">
  See the full frame catalog and thread-event publish route.
</Card>

## Non-Streaming Alternative

Use `stream: false` when you only need the final result:

```typescript theme={null}
const result = await rt.agent.run('code-assistant', 'Run the tests.', {
  stream: false,
});
```
