Skip to main content
Agent Run 通过 Server-Sent Events(SSE)输出公开进度、回复文本、工具输入、积分结算、预览地址和交互请求。

订阅事件

所需权限:agent.read
Token 必须放在 Authorization Header 中;不要放入 URL Query。 Write/Edit 正文随事件流默认发送,不需要额外 Query 参数或 Scope。Read 文件名、Skill 名称及工具正文均使用普通 agent.read 授权;客户端必须忽略未知事件及新增字段。

SSE 帧

每个业务事件帧由 idevent 和 JSON data 组成:
  • id 只在本次连接内从 1 单调递增。
  • 心跳使用 SSE 注释帧,不包含业务数据,也没有 id
  • 服务端不支持 Last-Event-ID 断点续传。
  • 首个终态事件之后,服务端关闭连接。

事件语义

tool.call 的已知 phaseanalyzingbuildingvalidatingcoordinatingfinalizing。未知 phase 仍按进行中展示。 tool.call 的基础字段包含安全的工具名、状态、阶段和展示文案,不包含原始参数、目录路径或原始执行结果。支持以下结构化扩展:
  • Read 可携带 file_name,只含安全 basename,不含目录、读取内容、offset、limit 或 URL 查询信息。
  • Skill 可携带 skill,其中 skill_name 为服务端解析的 canonical 名称,display_name 为可选展示名;展示时使用 display_name ?? skill_name。不公开技能正文、配置、凭证或加载结果。
  • status: "completed" 可携带 outcomesucceededfailedcanceled)。completed 仅表示调用结束,实际结果以 outcome 为准。

积分结算

每次 Agent 计量 END 成功并返回有效积分时,事件流会发送一条 run.usage
  • credits_used 是这一次结算的积分,不是整个 Run 的累计值;它使用非负十进制整数字符串,"0" 是有效值。
  • 同一个 Run 在阻塞后恢复或发生 Session 轮换时可能有多次结算,因此可能收到多条 run.usage
  • 重连时缓存窗口内的结算事件可能重放。usage_id 对同一次结算保持稳定,客户端必须先按它去重,再对 credits_used 求和。
  • 计量 END 失败或没有返回有效积分时不会伪造 run.usage。 未收到 run.usage 不代表零消耗;事件用于本次运行的结算展示,不应把缺失事件伪装为零值。
  • 最终一条 run.usage(若有)会先于 run.completedrun.failedrun.canceledrun.interrupted;这些正常终态是该连接最后一个业务事件。
一个简单的累计器可以写成:

Write/Edit 输入流

默认会收到两类工具输入事件。tool.input.delta 使用追加语义:Write 只产生 field: "content";Edit 只产生 field: "old_string"field: "new_string"
tool.input.snapshot 是该 tool_call_id 的权威全量状态,必须替换本地工具输入,而不是继续追加:
  • Write 的 input 只使用 content;Edit 使用 old_stringnew_string,最终快照还可能带 replace_all
  • Edit 删除内容时 new_string 可以是空字符串,且可能没有对应 delta;以最终 snapshot 为准。
  • file_name 只含 basename,可能在无法安全解析时省略;同名文件仍必须用 tool_call_id 区分。
  • complete: false 表示参数仍在生成;complete: true 只表示参数生成完成,不表示工具执行成功,随后应读取 tool.call.outcome
  • truncated: true 表示公开投影达到大小或并发限制;Agent 内部仍使用完整参数执行。
  • 不保证 file_name 先于内容 delta 到达;客户端必须容忍字段顺序和事件交错。
客户端按 tool_call_id 分别维护状态:delta 追加到对应 field,snapshot 整体替换 file_nameinputcompletetruncated。断线重连时缓存窗口内可能先收到 snapshot,用它覆盖重连前的本地累计值。

最终与重连工具快照

服务端从持久化消息生成的 message.snapshot 会附带 tool_calls,它是当前轮 Read、Write、Edit、Skill 公开状态的权威全量快照。实时文本更新产生的瞬态 message.snapshot 可能省略该字段:字段存在时整体替换本地工具列表,字段缺省时保留已有工具列表。
  • 快照只包含当前轮,即最近一条公开用户消息之后的工具调用,并按调用顺序排列。
  • Read 仍然只有 basename 文件名;Write/Edit 使用与实时事件完全相同的白名单正文;Skill 名称仍由服务端目录解析。
  • status: "completed" 表示找到了配对的持久化工具结果,outcome 是安全归一化状态。原始工具结果不会进入快照。
  • 最多返回 64 个工具调用,Write/Edit 正文继续受实时投影相同的字段和 Run 总大小限制;达到限制时可能带 truncated: true
  • 如果消息存储暂不可用,服务端退化为实时事件或纯文本快照,不会阻塞 Run 终态。

文本 reducer

客户端维护每个 Run 的单一文本缓冲区:
message.snapshot 可能在首次连接、重连和终态前出现。content 始终是当前完整文本;tool_calls 存在时是当前轮完整公开工具状态。两者使用替换语义;缺省的 tool_calls 不应清空已有工具列表。

预览事件

只有内部 dev server 状态精确变为 running,并且短时 Preview Link 签发成功时,服务端才发送 preview.readystarting、无效内部地址或签发失败都不发送 preview.ready,也绝不会向 Open API 客户端暴露 raw Sandbox URL。 url 是调用方应打开的短时 opaque Preview Link,不要依赖 host 或 path 形状;expires_at 是必填的 Unix 毫秒过期时间。 链接过期或需要续期时,第三方后端使用受保护的 POST /projects/{project_id}/agent/preview-links 重新签发;恢复仍在进行时接口返回 202,按 Retry-After 重试。不要等待 SSE 一定再次产生预览事件,也不要把 opaque Ticket 写入日志或长期存储。公开的 GET /open/preview/{preview_ticket} 只是 HTML 壳页面,不接受 API 凭证,也不会恢复 Sandbox。

断线重连

网络断开时:
  1. 保留当前 run_id、已展示文本和 UI 状态。
  2. 使用有限次数、带抖动的指数退避重新 GET 同一事件端点。
  3. 不发送 Last-Event-ID,也不使用重复 start 代替重连。
  4. 收到 message.snapshot 后整段替换已有文本;若存在 tool_calls,同时整体替换当前轮工具状态,缺省则保留已有工具状态。
  5. 对重放的 run.usageusage_id 去重,再累计字符串形式的 credits_used,不要重复计费展示。
  6. 收到终态后停止重连。
该端点当前使用 60 秒固定限频窗口。收到 429 时,Retry-After: 60 是固定窗口的安全等待上界,不是剩余 TTL;等待后增加少量随机抖动再重连。 页面刷新且不知道当前 Run 时,先调用 GET .../agent/runs/current,再决定是否订阅,详见 会话与恢复

run.input_required

可回复的交互事件包含 action
如果事件没有 action,而是 detail: "unsupported_action",表示当前阻塞工具不支持通过 OpenAPI 回复。客户端应停止自动提交,并引导用户到 Meoo Web 处理。 只要阻塞工具仍有效,每次建连或重连都会签发新的 action_idexpires_at;长连接存续时,服务端会在当前 Token 半 TTL 时续签。客户端必须用最新事件替换旧 Token。

回复 Action

所需权限:agent.run action_id 与项目和 Run 绑定,且只能在有效期和正确状态下使用。

问答回复

kind=answers 时,answers 包含 1~4 项;键长 1~1000,值为 1~10000 字符的非空字符串。服务端会先 trim 每个 key 和 value,再校验并传给 Agent;trim 后为空或产生重复 key 会返回 400

确认回复

kind=confirmation 时,decisionapprovereject
只有 action.input_schema 声明允许 comment 时才能附带非空 comment
成功响应是恢复后的 Run 对象。继续消费原 Run 的 SSE;如果原连接已关闭,则重新订阅该 run_id

Action 错误处理

Action 回复没有通用 Idempotency-Key。请求结果不确定时,先恢复 Run 状态;不要用新的 start 请求模拟 Action 回复。