适用版本:ChengOS v0.1.0+ | 最后核对:2026-08-12 | 来源:
crates/cheng-api/src/ws/protocol.rs、crates/cheng-api/src/ws/manager.rs、crates/cheng-api/src/rest/routes.rs
工作流运行通过 WebSocket 流式推送。轮询 GET /executions/:id 告诉你结果;而 socket 告诉你正在发生什么——逐节点进度、逐 token 的模型输出、智能体迭代和审批请求。
连接
| 接口 | 说明 |
|---|---|
/ws/executions |
顶层 |
/api/v1/ws/executions |
同一个处理器,带版本前缀的别名 |
三种认证方式任选其一:
Authorization: Bearer <jwt> # 推荐
/ws/executions?token=<jwt> # 无法设置请求头时
/ws/executions?ticket=chtk_… # 渠道客户端
票据形式的存在,是为了让 chk_ 渠道密钥永远不出现在 URL 中。票据由已认证的渠道 REST 接口签发,并在升级时一次性消费——票据不是可重复使用的凭证。
协议版本
WS_PROTOCOL_VERSION = 1
事件结构发生任何不兼容变更时都会递增。外部客户端——cheng CLI 就是这么做的——在依赖事件语义之前,会通过 CLI 会话 API 比对该版本号。请检查它,不要假设;这个常量存在的意义就在于此。
消息信封
每条消息都被包裹:
{
"messageId": "uuid",
"timestamp": "2026-08-12T10:30:00Z",
"type": "NODE_COMPLETE",
"...": "各类型专有字段"
}
messageId 用于去重——重连之后你完全可能合理地收到同一条消息两次,因此请以它为键,而不要假设投递恰好一次。载荷被扁平化进信封,所以 type 与 messageId 平级,而不是嵌套在里面。
消息类型是 SCREAMING_SNAKE_CASE,字段名是 camelCase。
订阅
仅仅连接并不会收到事件;你需要订阅某个 scope。共三种粒度:
{ "type": "SUBSCRIBE", "scope": { "type": "workspace", "workspaceId": "…" } }
{ "type": "SUBSCRIBE", "scope": { "type": "conversation", "conversationId": "…" } }
{ "type": "SUBSCRIBE", "scope": { "type": "execution", "executionId": "…" } }
服务端以 SUBSCRIBED 确认。UNSUBSCRIBE 使用相同的 scope 结构,以 UNSUBSCRIBED 确认。
请选择能覆盖需求的最小 scope:观察单次运行用 execution;每轮都是一次新执行的对话界面用 conversation;看板用 workspace。为了观察一次运行而订阅整个工作区,意味着要在客户端过滤掉所有其他人的流量。
用 PING 保持连接活跃,服务端以 PONG 回应。两者都接受可选的 data 和 timestamp。
执行事件
| 类型 | 含义 |
|---|---|
EXECUTION_START |
运行开始——携带 executionId、workflowId、startedAt、inputs |
EXECUTION_PROGRESS |
总体进度 |
EXECUTION_STATE_CHANGED |
状态机转换 |
NODE_COMPLETE |
某个节点成功,附带其输出 |
NODE_FAILED |
某个节点失败,附带错误 |
EXECUTION_COMPLETE |
终态:成功 |
EXECUTION_FAILED |
终态:失败 |
EXECUTION_CANCELLED |
终态:已取消 |
ERROR |
协议或服务端错误 |
流式节点输出
| 类型 | 含义 |
|---|---|
NODE_STREAM_START |
某个节点开始流式输出 |
NODE_STREAM_CHUNK |
一段增量输出 |
NODE_STREAM_COMPLETE |
流式输出结束 |
NODE_STREAM_FAILED |
流式输出中途失败 |
请把 chunk 累积在与已完成消息分开的缓冲区里;若干 chunk 之后出现 *_FAILED,意味着你必须丢弃或标记这段不完整文本,而不能把它当作完整答案呈现。
智能体事件
智能体运行要健谈得多,而这正是它可调试的原因:
| 类型 | 含义 |
|---|---|
AGENT_ITERATION_COMPLETED |
一轮「推理—行动—观察」循环结束 |
AGENT_TURN_STARTED / AGENT_TURN_COMPLETED |
对话轮次边界 |
TOOL_EXECUTION_STARTED / _PROGRESS / _COMPLETED / _FAILED |
工具调用生命周期 |
CONTEXT_WINDOW_STATUS_UPDATED |
上下文用量——留意压缩时机 |
AGENT_PAUSED_FOR_REVIEW |
正在等待人工 |
审批事件
APPROVAL_REQUESTED 宣告需要一个决策;APPROVAL_RESOLVED 宣告决策已作出。请通过 REST(POST /executions/:id/approve)作答,而不是通过 socket——在这里 WebSocket 是通知通道,不是控制通道。
会话与消息事件
CONVERSATION_CREATED、MESSAGE_CREATED、WORKFLOW_TRIGGERED 和 MESSAGE_COMPLETED 是对话界面所消费的事件:用户消息触发工作流,输出流式返回,轮次结束。
容器与循环事件
CONTAINER_STARTED / CONTAINER_COMPLETED 包裹子流程和批量子流程;LOOP_ITERATION_STARTED / _COMPLETED / _FAILED 上报每次迭代,因此 100 个条目的批处理是逐条可观测的,而不是一个不透明的节点。
文档与表格事件
SHADOW_EVENT 和 TABLE_EVENT 承载实时的文档与电子表格变更,这正是工作流写入时协同编辑器能保持同步的原因。
客户端本地工作区事件
这些实现的是反方向——服务端请求客户端做事,也正是 cheng back 让浏览器会话操作你本机文件的机制:
| 类型 | 方向 |
|---|---|
CLIENT_WORKSPACE_READY |
客户端宣告其本地工作区 |
WORKSPACE_TOOL_REQUEST |
服务端请求客户端执行一个工具 |
WORKSPACE_TOOL_RESULT |
客户端返回结果 |
WORKSPACE_TOOL_CANCEL |
服务端取消一个待处理请求 |
CLIENT_WORKSPACE_DISCONNECTED |
本地工作区已断开 |
WORKSPACE_TOOL_RESULT 的错误除消息外还带有稳定的 LOCAL_EXECUTOR_* 错误码,因此客户端可以基于错误码分支,而不必解析文字描述。
重连
请实现带抖动的退避、重连后恢复订阅,并基于 messageId 去重。用 close code 区分主动关闭与网络故障——重试一次干净的关闭是白费功夫。内置的 @chengflow/chat WebSocket 客户端已经全部实现了这些;参见 SDK 快速开始。
如果事件流静默,请与 GET /executions/:id 对账,而不要无限等待。CLI 正是为此使用了 30 秒的静默阈值。
下一步
- REST API 总览——请求侧。
- 认证——令牌、密钥与票据。
- 执行模型——这些事件从何而来。

暂无评论内容