跳转到主要内容

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.

Qoder Cloud Agents 使用 Server-Sent Events (SSE) 协议将 Agent 的实时执行状态推送到客户端。你无需轮询——建立一次连接即可持续接收所有事件。

连接 URL

GET https://api.qoder.com/api/v1/cloud/sessions/{session_id}/events/stream
请求头:
Authorization: Bearer $QODER_PAT
Accept: text/event-stream

SSE 格式

每个事件由三行组成,以空行分隔:
id: evt_01abc123
event: agent.message
data: {"content":[{"type":"text","text":"Hello, I'm ready to help."}]}

字段说明
id事件唯一标识,用于断线重连
event事件类型,决定 data 的结构
dataJSON 格式的事件负载

完整事件类型

事件类型含义触发时机data 结构
user.message用户发送消息客户端 POST 事件后{"content": "..."}
user.interrupt用户中断当前执行客户端发送中断事件{}
user.define_outcome用户定义预期结果客户端设定目标{"outcome": "..."}
session.status_runningSession 开始执行收到消息后开始处理{"status": "running"}
span.model_request_start模型请求开始Agent 发起 LLM 调用{"model": "...", "span_id": "..."}
agent.thinkingAgent 思考中模型推理过程中{"content": "..."}
agent.messageAgent 回复消息模型产出文本{"content": [{"type":"text","text":"..."}]}
agent.tool_useAgent 发起的工具调用(Bash/Read/Write/Edit/Glob/Grep/WebFetch/WebSearch)模型决定调用工具见下文「工具调用对」
agent.tool_result工具执行回执,通过 tool_use_id 与 tool_use 配对工具执行完成后见下文「工具调用对」
session.status_idleSession 进入空闲一轮对话完成见下文「status_idle 完整 schema」
span.model_request_end模型请求结束LLM 调用完成{"span_id": "...", "usage": {...}}
session.errorSession 出错运行时异常{"error": "...", "code": "..."}
terminatedSession 终止Session 被关闭或超时{"reason": "..."}

典型事件生命周期

一次完整的对话轮次,事件按以下顺序触发:
user.message                  ← 用户输入
session.status_running    ← 开始执行
span.model_request_start      ← 模型请求
agent.thinking                ← 推理中(可选)
agent.message                 ← 回复内容(可能多次 delta)
span.model_request_end        ← 模型完成
session.status_idle           ← 空闲,等待下一轮

工具调用对(pair)

每个 agent.tool_use 必有同 turn_idagent.tool_result 配对,靠 tool_use_id 关联。 agent.tool_use 关键字段:
{
  "type": "agent.tool_use",
  "id": "toolu_bdrk_01Kj...",
  "name": "Bash",
  "input": { "command": "...", "description": "..." },
  "tool_use_id": "toolu_bdrk_01Kj...",
  "turn_id": "turn_...",
  "session_id": "sess_...",
  "requires_confirmation": false
}
注意此事件的 id 不是 evt_ 前缀,而是外部模型方格式 toolu_bdrk_<24>name 首字母大写。 agent.tool_result 关键字段:
{
  "type": "agent.tool_result",
  "id": "evt_<32hex>",
  "name": "Bash",
  "content": [{ "type": "text", "text": "..." }],
  "tool_use_id": "toolu_bdrk_01Kj...",
  "turn_id": "turn_...",
  "is_error": false
}
排序建议:按 created_at → 类型(tool_use 在 tool_result 前)→ id 三级排序。不要单靠 id 排序——平台生成的 tool_result id 可能字典序小于 tool_use id。

status_idle 完整 schema

session.status_idle 事件除 status 外还携带 stop_reasonusageturn_idsession_id
{
  "type": "session.status_idle",
  "id": "evt_840b8dc4b1534e52a2b858bf26b7de00",
  "status": "idle",
  "stop_reason": { "type": "end_turn" },
  "usage": {
    "input_tokens": 23487,
    "output_tokens": 1024,
    "cache_read_input_tokens": 11223,
    "cache_creation_input_tokens": 0
  },
  "turn_id": "turn_...",
  "session_id": "sess_..."
}
stop_reason.type 当前观察值为 end_turn;其他枚举值(cancel / max_turns / error 等)按实际场景出现。

断线重连与 after_id

SSE 连接建立后,默认从头重放所有历史事件。若只需增量事件,传入 after_id 参数:
GET /sessions/{session_id}/events/stream?after_id=evt_01abc123
浏览器原生 EventSource 会在断线重连时自动携带 Last-Event-ID 请求头,服务端据此返回增量事件。
长时间保持连接时建议客户端记录最后收到的 id,断线后用 after_id 恢复。

delta_flush_interval_ms

通过查询参数控制 agent.message delta 事件的刷新间隔:
GET /sessions/{session_id}/events/stream?delta_flush_interval_ms=100
默认值为 50ms。增大该值可减少事件频率、降低客户端渲染压力。

curl 示例

curl -N \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Accept: text/event-stream" \
  "https://api.qoder.com/api/v1/cloud/sessions/sess_abc123/events/stream"
after_id 的增量连接:
curl -N \
  -H "Authorization: Bearer $QODER_PAT" \
  -H "Accept: text/event-stream" \
  "https://api.qoder.com/api/v1/cloud/sessions/sess_abc123/events/stream?after_id=evt_01abc123"

JavaScript EventSource 示例

const url = new URL('https://api.qoder.com/api/v1/cloud/sessions/sess_abc123/events/stream');
// 如需增量:url.searchParams.set('after_id', lastEventId);

const es = new EventSource(url, {
  headers: { 'Authorization': `Bearer ${QODER_PAT}` }
});

es.addEventListener('agent.message', (e) => {
  const data = JSON.parse(e.data);
  console.log('Agent:', data.content);
});

es.addEventListener('session.status_idle', () => {
  console.log('轮次完成,等待下一轮输入');
});

es.addEventListener('session.error', (e) => {
  const data = JSON.parse(e.data);
  console.error('错误:', data.error);
  es.close();
});

es.onerror = () => {
  console.warn('连接断开,浏览器将自动重连');
};

客户端实现建议

  1. 记录 last event id —— 每收到事件就更新,用于重连恢复。
  2. 处理 delta 拼接 —— agent.message 可能以流式 delta 到达,客户端需拼接为完整文本。
  3. 监听 terminated —— 收到后主动关闭连接,不再重连。
  4. 超时重试 —— 若 30 秒无事件,主动断开并重连(避免静默断连)。
  5. 过滤事件 —— 仅监听业务关心的事件类型,忽略 span 级别事件可减少处理开销。

常见问题

Q:连接后收到大量历史事件怎么办? A:传入 after_id 参数,指向最后处理过的事件 ID,服务端只返回该 ID 之后的事件。 Q:SSE 连接会自动关闭吗? A:Session 终止时服务端发送 terminated 事件后关闭连接。空闲超时由 Session 配置决定。 Q:能否用 WebSocket 替代? A:当前仅支持 SSE。SSE 对单向推送场景更轻量,且天然支持断线重连。 Q:delta_flush_interval_ms 设太大会丢事件吗? A:不会丢失,只是批量合并后发送。最终内容完整性不受影响。