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

# SSE 事件流

Qoder Cloud Agents 通过 **Server-Sent Events (SSE)** 流式输出 Session 公开事件。

## 连接 URL

```text theme={null}
GET https://api.qoder.com/api/v1/cloud/sessions/{session_id}/events/stream
```

请求头：

```text theme={null}
Authorization: Bearer $QODER_PAT
Accept: text/event-stream
```

默认情况下，Agent 响应会在生成完成后，以完整公开事件（例如 `agent.message`）的形式写入 Session 事件历史并通过 stream 输出。下文将这种完整事件称为 **buffered 事件**。

Stream endpoint 支持使用 `Last-Event-ID` header 断线重连。对于普通 buffered 事件，stream 从该 ID 之后继续；在途 event delta 的特殊行为见下文。

使用 `event_deltas[]` 可在当前 stream 连接中增量接收 Agent 响应。重复传入该参数可同时请求两种支持的事件类型：

```text theme={null}
GET /api/v1/cloud/sessions/{session_id}/events/stream?event_deltas[]=agent.message
GET /api/v1/cloud/sessions/{session_id}/events/stream?event_deltas[]=agent.thinking
GET /api/v1/cloud/sessions/{session_id}/events/stream?event_deltas[]=agent.message&event_deltas[]=agent.thinking
```

该选项只对当前 stream 连接生效，不会影响同一 Session 的其它连接。不传 `event_deltas[]` 时，连接只会在响应完成后收到完整事件。Thread event stream 不支持该参数。

## SSE 格式

每条事件使用标准 SSE 字段：

```text theme={null}
id: evt_019e392c0d787cfaa21bda98e06cd913
event: agent.message
data: {"id":"evt_019e392c0d787cfaa21bda98e06cd913","type":"agent.message","content":[{"type":"text","text":"Hello"}],"processed_at":"2026-05-18T03:40:48.888851795Z"}
```

服务端可能发送 heartbeat comment 以保持连接。

## Event Delta

`agent.message` 的增量输出以 `event_start` 开始，随后输出一个或多个 `event_delta`：

```text theme={null}
id: evt_00jjujk9fbnr4wkj2gh8
event: event_start
data: {"event":{"id":"evt_00jjujk9fbnr4wkj2gh8","type":"agent.message"},"type":"event_start"}

id: evt_00jjujk9fbnr4wkj2gh8
event: event_delta
data: {"delta":{"content":{"text":"你好","type":"text"},"index":0,"type":"content_delta"},"event_id":"evt_00jjujk9fbnr4wkj2gh8","type":"event_delta"}
```

`agent.thinking` 的增量输出只有开始事件，不会输出 `event_delta`：

```text theme={null}
id: evt_00jjujk9fbnr55q5rtyp
event: event_start
data: {"event":{"id":"evt_00jjujk9fbnr55q5rtyp","type":"agent.thinking"},"type":"event_start"}
```

对于同一个 message 或 thinking 事件，SSE `id:`、`event_start.event.id`、每个 `event_delta.event_id` 以及后续 buffered 事件的 `id` 完全相同。同时请求两种事件类型时，典型顺序如下：

```text theme={null}
span.model_request_start
event_start (agent.thinking)
agent.thinking
event_start (agent.message)
event_delta (agent.message)
agent.message
span.model_request_end
```

Event delta 帧的 JSON payload 不包含顶层 `id` 或 `processed_at` 字段，也不会出现在事件 list/history 响应中。buffered `agent.message` 是权威结果，`agent.thinking` 不会暴露思考内容。

## Event Delta 期间重连

断线重连时使用 SSE `Last-Event-ID` header。具体行为取决于游标位置，以及当前 message 是否仍在生成：

1. **游标指向当前 `event_start` 之前的事件，且 message 仍在生成。** Stream 会重新输出该 message 的 `event_start` 和已保留的历史 `event_delta`，然后继续输出新 delta。
2. **游标等于当前 `event_start.event.id`，且 message 仍在生成。** 该 message 已经输出过的历史 delta 不会重放；stream 只输出重连后新生成的 delta，随后输出 buffered 最终事件。
3. **Message 已经生成完成。** 该 message 的历史 delta 不再重放。从更早的 buffered 事件重连时，只会收到最终 `agent.message`；如果使用该最终 message 的 ID 重连，则从它之后继续。

同一个增量事件的所有帧使用相同 ID。如果客户端在断线后需要完整重建仍在生成的事件，应将游标回退到该事件 `event_start` 之前最近的 buffered 事件 ID，清空或去重本地的部分状态，并重新处理服务端返回的 `event_start` 和 `event_delta`。

## 常见事件流

```text theme={null}
session.status_running
session.thread_status_running
user.message
span.model_request_start
agent.thinking
agent.tool_use
agent.tool_result
agent.message
span.model_request_end
session.thread_status_idle
session.status_idle
```

并非每一轮都会包含全部事件。Managed-agent Session 还可能产生 `session.thread_created`、`session.thread_status_running`、`agent.thread_message_sent`、`agent.thread_message_received` 等 thread 事件。

### 模型请求 span

`span.model_request_start` 包含 `id`、`processed_at` 和 `type`。与之配对的 `span.model_request_end` 包含 `id`、`is_error`、`model_request_start_id`、`processed_at` 和 `type`，其中 `model_request_start_id` 等于对应 start 事件的 `id`。

> 说明：公开的 `agent.thinking` 事件 payload 只包含 `id`、`processed_at`、`type` 三个字段，思考内容不对外公开——把该事件当作"Agent 暂停推理"的标记即可。其它若干 agent.\* 事件也可能省略 `processed_at`，解析时请将其视为可选字段。

## 连接生命周期

* `session.status_idle` 表示当前 turn 结束，连接应当保持，等待下一轮。
* `session.status_terminated` 和 `session.deleted` 是终态事件——客户端应停止重连，不会再有更多事件。
* `session.status_rescheduled` 是临时信号，连接可能短暂断开，运行时恢复后会自动重连。
* 网络中断时使用 `Last-Event-ID` header 重连；在途增量事件的特殊处理见 [Event Delta 期间重连](#event-delta-期间重连)。

## 工具响应

当事件流产生需要确认的 `agent.tool_use` 时，向 `POST /api/v1/cloud/sessions/{session_id}/events` 发送 `user.tool_confirmation`，并使用工具事件 ID：

```json theme={null}
{
  "events": [
    {
      "type": "user.tool_confirmation",
      "tool_use_id": "evt_01JZ6Q3FB6SG8F7J1M2N",
      "result": "allow"
    }
  ]
}
```

当事件流产生 `agent.custom_tool_use` 时，由客户端执行自定义工具，并发送 `user.custom_tool_result`。

## 事件历史

历史事件和分页请使用 list endpoint：

```bash theme={null}
curl -s "https://api.qoder.com/api/v1/cloud/sessions/$SESSION_ID/events?limit=20&order=desc" \
  -H "Authorization: Bearer $QODER_PAT"
```

列表响应使用 `data` 和 `next_page`。详见 [列出事件](/zh/cloud-agents/api/sessions/list-events) 和 [Session 数据结构](/zh/cloud-agents/api/sessions/schemas#公开事件类型)。
