适配器与内容扩展 API
ChatKit 负责通用的对话交互、协议翻译和运行状态。接入方提供后端能力函数,决定地址、鉴权与部署参数。普通接入只需要 run;有特殊内容时,再使用下面三个入口。
适配器没有业务状态订阅回调。独立业务状态由应用请求并保存,再交给插槽组件;不经过聊天消息也能显示。
能力函数
ADK、A2A、OpenAI 兼容接口、Hermes 使用同样的能力名称。协议选择决定数据如何翻译,后端函数决定能做哪些操作。Mock 适配器不连接后端,默认实现会话、历史、停止、重新生成和编辑,某项传 false 关闭。
普通能力回调不接收 signal。SDK 在释放运行时时取消 Response 的 reader,或调用异步迭代器的 return();自定义事件流必须在 return() 中移除监听并结束 pending next(),不要关闭其他会话共享的连接。回调返回前的请求超时由应用自己的网络客户端管理。资源释放不请求后端停止。
不给对应函数就不启用远端能力。停止必须等待后端确认;会话目录由接入方维护。无历史接口,页面刷新后不恢复旧消息。SDK 不在浏览器落盘。
history 返回会话的协议历史响应,包括消息、已知轮次结果与可选的会话摘要、active_run;不另设单轮查询。连接关闭不代表执行完成,恢复不重新发起用户问题;OpenAI 在续接后执行工具、继续下一模型步骤时仍可能调用 run。
独立会话订阅
subscribe({ sessionId }) 返回 Promise<StreamResult<Event>>,返回时监听已经就绪。有 subscribe 时,run / resume / regenerate / edit 的返回值收窄为 Promise<Response>,仅表示受理;输出全部经过订阅,不能重复返回第二份流。没有 subscribe 时保持上表的返回值。会话监听只在运行时释放时取消,单轮停止不取消它。
输入转换:transformInput
同步返回完整请求体,建议展开 defaultInput 后改少量字段。恢复请求没有新用户输入,input 可以为空。只有携带协议请求体的能力经过此转换;OpenAI、Hermes 和 createAdapter 的 resume 只有编号与游标,没有 body,因此不调用转换。abort 不经过 transformInput,即使 A2A 的 abort 有 body。对照后端编号由能力函数收到的 runId 为准,内容更新使用 ChatKit 消息里的 runId。
onSend 在界面发送前处理用户输入;transformInput 在适配器默认编码后处理协议请求体。两者发生在不同位置。transformInput 不修改本地用户消息,不用来维护业务状态。
输出转换:transformOutput
OutputChange = DefaultContentChange | ContentChange。DefaultContentChange 是当前事件的只读默认内容凭据,含 messageId,可原样保留或过滤;不能自行构造、修改或传给 updateContent。这样扩展可以选择显示内容,又不能伪造协议的完成、失败或工具结果。
每次进入输出转换器的事件调用一次;不是每个传输帧都会进入。例如 ADK 心跳和 [DONE]、A2A JSON-RPC 错误不进入此回调,重复投递也不保证只调用一次。无法识别但已成功解析的业务事件可参与转换。messageId 是转换器当前定位到的内容消息,常为回答,但也可能来自本事件默认产生的用户或系统消息;使用前应确认目标。新增 data 必须挂到已有消息。
历史事件形状因适配器而异:ADK 回放事件;OpenAI 把助手/工具历史记录合成为 chunk;Hermes 包成 history.message;A2A 由任务历史合成 status-update/artifact-update;createAdapter 将整份原始历史响应视作 TEvent 调用一次。恢复流仍使用 source: stream,重新取历史使用 history;不能仅因类型里有 recovery 就依赖该值必然出现。
转换必须同步、无网络请求且无副作用。抛错或返回 Promise 时上报 onError 并保留默认内容;非法业务变更批量拒绝并上报,已选择的默认内容仍按选择结果应用;这不是整次回调连同默认内容一起回滚。稳定的消息、片段编号可用于同目标替换,但不提供任意事件的全局去重保证。后端历史必须保留业务字段,刷新后才可重新生成相同扩展。
内容更新:runtime.updateContent
ChatCoreRuntime 和 useChatRuntime 返回的运行时均提供此方法;会话层通过 sessions.runtime 取得当前运行时。
- title 只属于工具片段;工具名、args、result、status 由协议维护。
- metadata 是 JSON 对象;data 是可 JSON 序列化的业务值,只能用于 data 片段。对象按第一层合并,嵌套对象整份替换;set-part 整块替换。
- 不允许改正文、推理、消息归属、轮次、执行状态、游标、错误结果。业务状态需要新值时放到 metadata/data。
- 批量全部校验后原子提交,任何一项失败都不提交。正常完成后仍可补充标题;后端确认中止后内容封存,拒绝补写。
- 协议消息更新会重新叠加已保存的业务补充;前提是目标消息/片段仍存在且身份有效。目标被删除或轮次作废后清理补充数据。
- 同一消息内 partId 唯一;按 runId + toolCallId 定位时必须唯一。无法定位或有多个目标时明确拒绝,不缓存等待猜测。
可选 sourceId, changeId, version 用于异步去重:有 changeId/version 必须提供 sourceId;version 为非负安全整数。同一来源、同一目标的 version 只接受更大值,changeId 只接受一次;不同来源按接收顺序合并,不能拿两个来源的版本号比较。
异步请求开始时保存目标 runtime 与消息标识,回来后更新这份 runtime,不重新读取当前会话。runtime 本身绑定会话。删除/重建后旧目标或旧 runtime 会拒绝更新;不要复用已经作废的消息编号。
传输:Response 与事件序列
HTTP 返回 Response;WebSocket、SDK 回调或自有网关先变成事件序列。data 是该适配器的原始协议事件;eventId 是后端可续接的游标,不是消息 id,也不能用前端计数伪造。
序列结束只代表接收结束,必须收到协议结论或历史中的结论才认定执行结束。取消只归还本次迭代器,不关闭应用共享的 WebSocket;连接复用、重连、分发和鉴权由应用完成。会话、历史 等单次能力仍返回 Response,由适配器统一检查状态码和格式。
渲染器
renderers.tools 的组件拿到 title、metadata、defaultNode,以及已有的 toolCallId、toolName、args、result、status 等参数。直接返回 defaultNode 保留默认行,或把它和业务信息组合。配置的 label 优先,其次是单次调用的 title,最后是默认工具说明。
renderers.parts[kind] 拿到 data 与 part,part 含稳定 id 和 metadata。消息 metadata 在 message 上。未知 data 类型不显示;业务组件异常由错误边界隔离。
新协议接入
使用 createAdapter,实现 protocol.encodeInput、protocol.decodeEvent,以及需要的历史、会话解码器和订阅身份函数。应用无需实现 start/execute,也无需保存 RuntimeIngress 或手工接线。
创建工厂管理连接、取消与输出转换;协议函数负责稳定身份、内容转换和明确的执行结论。历史与流的转换粒度、异常出口并不完全相同,具体限制见新适配器页面。
独立接收
subscribe({ sessionId }) 返回 Promise<StreamResult<Event>>,此时 run/resume/regenerate/edit 只返回受理 Response,所有输出经过订阅统一转换。详见发送与接收。