OpenCode 协议参考
这一页列出 OpenCode server 适配器读写的请求与事件字段,以及它们怎么映射成 ChatKit 的消息、片段、交互请求与轮次结果。接入写法见 OpenCode;字段的完整定义以 OpenCode server 文档 与 server 的 GET /doc 为准。
传输
连接选项:
用的是 legacy 路由:/session/*、/permission/*、/question/*、/global/event,不用 v2 的 /api/*。
字段按 OpenCode 1.19 的 /doc OpenAPI 与实测事件序列核对。OpenCode 的协议仍在演进,升级后以包内 src/wire.types.ts 为准重新核对。
发出的请求
路径里的 id 都经 encodeURIComponent。其他接口(会话列表、改名、删除、fork、模型列表、/question/{id}/reject…)不在适配器里,用 connection.request(method, path, body?) 自行调用。
POST /session
请求体原样转发 createSession 的参数(如 { title });读取响应的 id 作为 ChatKit 的 sessionId,整个响应放在返回值的 session 里。
POST /session/{id}/prompt_async
受理即返回 204,回答从事件流来。默认请求体:
transformInput 收到默认编码后的请求体(defaultInput),必须返回完整请求体,可以改 parts,也可以加 model: { providerID, modelID }、agent、system 等 OpenCode 认的字段。runId 标记在它之后由连接补上,删不掉。
GET /session/{id}/message
回答
读取的事件
认定这一轮之后,连接只把属于它的事件交给解码与 transformOutput:
归属规则:回答消息看 parentID;片段与增量看 messageID 是否属于这一轮的回答消息;交互请求看 tool.messageID(没有 tool 的也归入);回复看 requestID 是否是这一轮的请求;session.error 只要分发到这个会话就归入。
片段:
工具片段按 state.status:
一轮的结束:回答消息 info.error 存在,或 info.time.completed 存在且 info.finish 有值、不是 tool-calls。finish 为 tool-calls 的回答只是一步,后面还有下一条回答消息。所有步骤拼成一条 ChatKit 回答消息。
没有内置处理的事件
这些事件或片段不变成聊天内容。能拿到它们的途径取决于是否归入这一轮:
驱动插槽(如会话忙闲):
把一步的用量放进回答消息(实时与刷新后走同一段逻辑,见下面的历史回放):
刷新加载历史时,适配器把历史回放成与实时同形的事件逐条交给 transformOutput(context.source 为 history,带这一轮的 runId 与 messageId):每个片段一条 message.part.updated(片段的最终状态),每条回答消息一条 message.updated。增量、审批与追问的信令只在实时里有。业务内容从回放里有的事件生成,刷新后就能还原。
审批与追问
读取的字段:
请求挂在 tool.callID 对应的工具片段上;没有 tool 时挂在合成的工具片段上(toolCallId 为 permission:{id} / question:{id},追问的工具名为 question)。写在 metadata['chatkit.interaction'],用 getOpenCodeInteraction(part) 读:
生命周期:
全部请求都有结论后阶段回到 tool。
回答:
question 工具 state.status 为 completed 时,以 state.input.questions 与 state.metadata.answers 补出 answered 的追问交互(不带 requestId)。历史里只有这个,所以刷新后追问仍显示问题与答案。
历史
GET /session/{id}/message?limit=&before= 返回 [{ info, parts }],从旧到新。
不保留:
编号
结束与错误
停止是会话级的:abort 停掉这个会话正在进行的一轮,结论仍从事件里来。不以 session.idle 收口。
断线后不续接:这一轮标记连接中断,由会话层经历史确认终态。listen 的监听按下文自动重连。
listen 断线重连
连接断开(或这个会话的订阅单独结束)时,有 listen 监听的会话:
- 监听先收到
{ kind: 'connection', status: 'disconnected' }; - 连接按退避自动重连并重新订阅(重新打开
global/event):第一次等reconnect.minDelayMs(缺省 1000),之后翻倍,最多等reconnect.maxDelayMs(缺省 30000); - 订阅恢复后收到
{ kind: 'connection', status: 'reconnected' }。断线期间的事件不会补发,需要时自行补拉状态(如GET /session/{id}、GET /session/{id}/todo)。
每次重新订阅失败经 onError('listen', error) 报告,之后继续重试。取消全部监听或调用 close() 后停止;连接选项 reconnect: false 关闭自动重连(仍会收到 disconnected)。正在进行的一轮不续接,仍由会话层经历史确认终态。
示例
一轮的事件(片段节选,directory 省略):
审批请求:
对应工具片段 tool:call_example 上的 metadata['chatkit.interaction']: