HTTP 与 WebSocket API 参考
本页提供 HTTP 方法及 WebSocket 帧的字段、示例和错误处理规则。第一次接入可先按教程发送第一条消息并接收回复。
连接和编码
这组智能体调用接口在平台技术文档中称为 Bridge Channel;HTTP 路径中的 /api/bridge/v1/ 和 WebSocket 子协议 infini.bridge.v2 都使用这个名称。它不是另一种通信协议,调用时请保留路径和子协议标识的原样写法。
HTTP 方法统一为 POST /api/bridge/v1/{Method},参数放入 JSON 请求体;不使用路径参数或查询参数。请求体上限为 1 MB,未知字段会被拒绝。WebSocket 使用 /ws/v1 路径、infini.bridge.v2 子协议和 JSON 文本帧。完整主机名及部署前缀以服务提供方给出的地址为准。
WebSocket 只处理订阅控制和心跳;提交消息和中断响应请使用对应的 HTTP 方法。
| HTTP 方法 | 用途 |
|---|---|
SendMessage | 提交用户输入,取得消息和会话标识 |
RespondInterrupt | 提交指定中断的审批决定或工具结果 |
CancelRun | 请求取消目标会话中的运行 |
GetIdentity | 查询当前 Token 对应的账号身份 |
ListMessages | 查询会话消息,供历史展示或恢复使用 |
ListPendingInterrupts | 收到 reset 后补齐待处理中断 |
HTTP 响应格式
六个方法使用相同的响应格式:
{
"code": 0,
"http_status_code": 200,
"success_response": true,
"data": {}
}data 的内容由方法决定;下文的“成功响应 data”示例均放在这个外层结构内。调用方先检查实际 HTTP 状态,再检查 success_response。业务失败也可能返回 HTTP 200 和 code: 0,此时按 data.reason 处理,详见错误处理。
鉴权
HTTP 请求使用:
Authorization: Bearer wst_<token>
Content-Type: application/jsonwst_ 只存放在服务端。浏览器业务界面应调用你自己的后端,不把长期 Token 下发到浏览器。
握手阶段鉴权
WebSocket 握手可使用:
Sec-WebSocket-Protocol: infini.bridge.v2, bearer.<base64url_token>base64url_token 为完整 Token 的无填充 Base64URL 编码;编码不等于加密。服务端只回显 infini.bridge.v2。能够设置请求头的非浏览器客户端也可使用 Authorization: Bearer。不支持 URL 查询参数传递 Token。
鉴权在握手阶段完成,不支持连接后发送 auth 帧。查询账号和绑定实例使用 HTTP GetIdentity。
标识及其用途
| 字段 | 用途 |
|---|---|
user_id | 业务服务根据已认证用户提供的稳定标识;不是模型生成的身份 |
chat_id | 业务会话标识,示例使用 group 模式;继续会话时保持不变 |
context_key / 帧 sid | 服务端会话标识;用于订阅、历史查询和中断定位 |
msg_id / 帧 mid | 关联一次输入和它产生的事件;每条新输入使用新 ID |
帧 seq | 会话事件续传游标;不能用 d.seq 或 d.server_seq 替代 |
帧 sub | 非空时表示子代理任务,不能把其终态当成主智能体终态 |
chat_id 使用应用生成的唯一字母、数字或连字符标识,避免点号等需规范化的字符。始终保存服务端返回的 context_key,不要自行拼接,也不要把它当成原始 chat_id 回传。
下面以 group 模式说明这些字段如何对应:左列是你从 HTTP 响应取得或本地保存的值,右列是使用它们的 WebSocket 帧字段。实线表示订阅或重连时把值填入字段,虚线表示收到帧后用值比对字段;两种箭头都只表示值的使用关系,不表示又发起了一次请求。
具体来说,将 context_key 填入 sub.d.session_id;收到事件后,用外层 sid 和 mid 分别匹配这个会话和本次输入的 msg_id。事件处理完成并保存后,再记录其外层 seq,重连时把已保存的值填入 since_seq。不要在事件尚未处理时提前推进游标;遇到 reset 则按重连与补偿规则恢复。
HTTP 方法
所有方法都使用同一渠道账号的 Token。chat_id、user_id 来自你的应用;context_key 使用服务端返回值。历史查询和中断处理也需要在应用侧检查当前用户的会话访问权限。
SendMessage:发送消息
POST /api/bridge/v1/SendMessage 提交一条文本输入。请求字段如下:
| 字段 | 类型 | 要求 | 说明 |
|---|---|---|---|
user_id | string | 必填 | 后端根据已认证用户提供的稳定标识 |
content | string | 必填 | 非空文本;以 / 开头时按渠道指令处理 |
chat_type | string | 可选 | group 或 p2p,默认 group |
chat_id | string | 可选 | 业务会话标识;省略时使用 user_id |
user_name | string | 可选 | 用户展示名 |
msg_id | string | 可选 | 建议填写 UUID;省略时由服务端生成 |
请求体示例:
{
"chat_type": "group",
"chat_id": "ticket-session-42",
"user_id": "user-17",
"msg_id": "6d8c49ab-88fd-411b-9bac-0a6ff9493108",
"content": "查询工单 INC-1024 的状态。"
}建议明确提供 chat_id 和 msg_id,以便隔离业务会话和关联事件。新输入使用新 msg_id;重试同一输入时保留原 ID。
成功信封示例:
{
"code": 0,
"http_status_code": 200,
"success_response": true,
"data": {
"msg_id": "6d8c49ab-88fd-411b-9bac-0a6ff9493108",
"context_key": "account-1_ticket-session-42"
}
}该响应表示已接收,不包含最终回答。本文示例使用 group 模式,便于从提交结果取得订阅标识;p2p 模式不在提交结果中提供可直接使用的 context_key,不能照搬本例的订阅步骤。
缺少必填值或包含未知字段时返回 invalid_request;消息提交失败时返回 publish_failed。最终运行结果从 WebSocket 运行事件取得。
RespondInterrupt:回传审批或工具结果
POST /api/bridge/v1/RespondInterrupt 响应已经收到的待处理中断事件。请求字段如下:
| 字段 | 类型 | 要求 | 说明 |
|---|---|---|---|
user_id | string | 必填 | 原业务上下文中经过授权检查的用户 |
msg_id | string | 必填 | 产生中断的事件帧 mid |
interrupt_id | string | 必填 | 事件中的 d.pending.id |
action | string | 必填 | APPROVE、REJECT、RESPOND 或 ERROR |
context_key | string | 建议填写 | 产生中断的事件帧 sid |
chat_type、chat_id、user_name | string | 可选 | 与原请求保持一致;chat_id 不是 context_key |
response_data | string | 可选 | 工具结果、安全错误信息或拒绝原因;结构化内容先序列化为 JSON |
additional_tool_rule | array | 可选 | 附加一条后续工具自动审批规则,见下方说明 |
hitl 中断使用 APPROVE 或 REJECT;respond 中断使用 RESPOND 或 ERROR。用户工具需要应用实际执行后再回传结果。请求体示例:
{
"chat_type": "group",
"chat_id": "ticket-session-42",
"user_id": "user-17",
"msg_id": "6d8c49ab-88fd-411b-9bac-0a6ff9493108",
"context_key": "account-1_ticket-session-42",
"interrupt_id": "interrupt-1",
"action": "RESPOND",
"response_data": "{\"status\":\"处理中\",\"team\":\"网络支持组\"}"
}成功响应 data 为 {},表示响应已提交。继续等待 pending_phase: "resolved" 和本轮运行终态;以中断 ID 和业务幂等键去重,避免事件重放导致工具重复写入。
批准工具时,可按需附加 additional_tool_rule。数组最多包含一条规则,规则中的 tool_name 指定工具,argument 指定参数名,pattern 指定该参数值需要匹配的正则表达式。省略 argument 表示整个工具放行;只在明确需要后续自动批准时设置。一次传入多条规则会被拒绝。
缺少 user_id、msg_id 或 interrupt_id,以及未知字段会返回 invalid_request;提交失败会返回 publish_failed。始终从中断事件读取关联标识,不为中断响应另建 msg_id。
CancelRun:取消会话中的运行
POST /api/bridge/v1/CancelRun 请求取消指定会话中正在处理的运行。它不按运行 ID 选择某个历史任务。请求字段如下:
| 字段 | 类型 | 要求 | 说明 |
|---|---|---|---|
user_id | string | 必填 | 原业务上下文中的用户 |
chat_type | string | 可选 | 与原输入相同,默认 group |
chat_id | string | 可选 | 与原输入相同;省略时使用 user_id |
user_name | string | 可选 | 用户展示名 |
请求体示例:
{"chat_type":"group","chat_id":"ticket-session-42","user_id":"user-17"}成功响应 data 示例:
{
"msg_id": "ce7a9eab-d5de-4e26-8c53-a576ae1459fe",
"context_key": "account-1_ticket-session-42"
}这里的 msg_id 是平台为取消指令生成的新标识,不是原输入的 msg_id。请求体不接受 msg_id、run_id 或 context_key;填写这些未知字段会返回 invalid_request。缺少 user_id 同样会被拒绝,提交失败返回 publish_failed。
成功响应表示取消请求已接收。继续观察目标会话中原运行的 lifecycle 事件,确认是否以 cancelled 结束;运行也可能在取消生效前已经完成。取消不会撤销已经完成的外部写入,处理方式见取消和恢复运行。
GetIdentity:核对 Token 对应的账号
POST /api/bridge/v1/GetIdentity 查询当前 Token 所属的渠道账号,适合检查客户端是否使用了预期凭证。无需业务参数,请求体使用空对象:
{}成功响应 data 示例:
{
"account_id": "account-1",
"tenant_id": "tenant-1",
"agent_instance_id": "instance-1"
}account_id 为渠道账号 ID;tenant_id 和 agent_instance_id 有值时才返回。agent_instance_id 表示账号直接绑定的实例,不是某个最终用户通过 /init 开通的实例查询结果。
查询成功只确认凭证身份,不能代替实际消息往返测试,也不代表最终用户已获得访问某个会话的权限。鉴权失败按握手和 HTTP 错误处理。
ListMessages:查询会话历史
POST /api/bridge/v1/ListMessages 读取历史消息,用于展示已有对话或在 reset 后恢复本地状态。请求字段如下:
| 字段 | 类型 | 要求 | 说明 |
|---|---|---|---|
context_key | string | 必填 | 服务端返回的会话标识 |
limit | integer | 可选 | 返回条数,默认 20、上限 200;不与分页参数混用 |
page | integer | 可选 | 从 1 开始的页码,与 page_size 配合使用 |
page_size | integer | 可选 | 每页条数;指定分页参数后按分页查询,不再使用 limit |
from、to | string | 可选 | checkpoint 区间标识,使用已有响应提供的值 |
查询最近 20 条消息的请求体示例:
{"context_key":"account-1_ticket-session-42","limit":20}成功响应 data 示例:
{
"items": [
{"id":"message-2","type":"ai","content":"工单正在处理中。"},
{"id":"message-1","type":"human","content":"查询工单 INC-1024。"}
],
"total": 2,
"from": "checkpoint-1",
"to": "checkpoint-2",
"has_more": false
}items 按新到旧排列;新会话尚无消息时返回空数组。total 为查询区间的消息总数,from、to 有值时才返回。has_more 按区间总数是否大于本次返回条数计算;翻页时也要检查本页是否为空。
消息必有 id 和 type;按内容可能包含 content、thinking、tool_call_id、tool_status 或 tool_calls。工具调用项包含 id、name 和字符串 args;用 tool_call_id 对应工具结果,不靠数组位置配对。
缺少会话标识或字段格式错误返回 invalid_request;无权读取目标会话返回 forbidden;历史暂不可用返回 history_unavailable。查询失败不能当成空历史。
ListPendingInterrupts:补查待处理中断
POST /api/bridge/v1/ListPendingInterrupts 在收到 reset 后补查仍需应用处理的中断。正常重连使用事件续传,无需每次连接都调用此方法。请求体只有必填的字符串 context_key:
{"context_key":"account-1_ticket-session-42"}成功响应 data 示例:
{
"items": [{
"id": "interrupt-1",
"tool_call_id": "call-1",
"type": "respond",
"name": "get_ticket_status",
"arguments": "{\"ticket_id\":\"INC-1024\"}"
}]
}没有待处理项时 items 为空数组。每项的 id、tool_call_id、type、name 与事件中的 pending 对应;arguments 有值时返回,是 JSON 字符串。
此响应不包含原请求 mid。收到中断事件时,应保存 pending.id 与 mid 的对应关系;无法从本地记录或回放恢复时,暂停自动应答,不用新 msg_id 或 tool_call_id 代替。
缺少会话标识或字段格式错误返回 invalid_request;无权读取会话返回 forbidden;查询暂不可用返回 pending_unavailable。恢复顺序见心跳、重连与补偿。
订阅和接收事件
取得 context_key 后发送:
{"t":"sub","d":{"session_id":"account-1_ticket-session-42","since_seq":0,"mode":"full"}}这里的 session_id 必须是服务端 context_key。等待 subd 并检查 subd.d.ok:
{"t":"subd","sid":"account-1_ticket-session-42","d":{"session_id":"account-1_ticket-session-42","ok":true,"cursor":0,"replaying":true}}since_seq 省略表示只接收新事件;0 表示从保留窗口最早事件开始;N 表示从 N 之后续传。mode 默认为 full,只关心状态的客户端可用 lifecycle,但需要工具中断的客户端必须接收完整事件。同一连接上不要重复提交未变化的订阅。
控制回复和会话通知
帧 t | 含义 |
|---|---|
hello | 握手完成;d 包含 conn_id、毫秒时间 server_time 和 protocol_version |
subd | 订阅结果;失败时检查 reason 和 message |
reply | 非运行事件回复;d.kind 为 directive_text 或 slash_commands |
opened | 新会话通知;仍需用 d.session_id 发送 sub 才会收到事件 |
reset | 续传游标已失效,例如超出历史保留范围或大于服务端最新序号,需要重建状态 |
err | 连接级错误 |
PONG | 客户端发送 JSON PING 后的应答 |
hello.d.protocol_version 的 v1 是帧版本,不是把握手子协议改回 infini.bridge.v1 的理由。
opened 的 d.cause 可为 cron 或 subagent,子代理还可包含 sub_agent_task_id。需要关注该会话时用 since_seq: 0 订阅。通知本身不重放;长时间断线不能保证补齐未保存标识的主动会话,业务服务应持久保存已经关注的会话标识。
运行事件和完成条件
ev 帧示例:
{
"t": "ev",
"sid": "account-1_ticket-session-42",
"seq": 184713,
"mid": "6d8c49ab-88fd-411b-9bac-0a6ff9493108",
"d": {
"kind": "message_delta",
"message_delta": {
"kind": "text",
"message_id": "message-1",
"text": "工单正在处理中。"
}
}
}d.kind 可为 message_delta、lifecycle、pending 或 custom。
message_delta.kind为text或thinking时,按message_id分别累加对应类型的text;思考内容与回答文本分开保存。tool_call包含完整id、name和字符串args;tool_result用tool_call_id对应工具调用。lifecycle.phase的graph_start表示开始,has_pending_interrupt表示等待,不是终态。lifecycle.phase = retry表示平台正在自动重试,也不是终态;继续接收原请求的事件,不重新提交消息。success、error、cancelled是终态。只结束匹配mid、且属于主智能体的当前请求。- 不认识的
custom事件类型应安全忽略,不应中断普通文本处理。
历史回放可能把同一消息中连续的多个 text 增量合为一帧,thinking 增量也会分别合并。按收到的文本内容追加即可;合并帧的外层 seq 使用这段内容最后一条事件的游标。不要按帧数计算消息数,也不要要求 seq 连续;工具调用、工具结果和中断仍需逐项处理。
例如,以下事件表示对应主智能体运行成功结束;客户端仍需核对 sid 和 mid,并检查任务所需的业务结果:
{
"t": "ev",
"sid": "account-1_ticket-session-42",
"seq": 184715,
"mid": "6d8c49ab-88fd-411b-9bac-0a6ff9493108",
"d": {
"kind": "lifecycle",
"lifecycle": { "phase": "success" }
}
}子代理使用独立会话流。需要处理子代理审批时,订阅该任务的会话,不要只监听父会话;也不要把子代理的完成事件当成整个用户任务完成。
自动重试与错误信息
重试事件通过 ev.d.lifecycle 提供状态和错误原因。例如,以下事件表示原请求正在进行任务级自动重试;本次错误发生在第 1 次运行,最多重试 3 次:
{
"t": "ev",
"sid": "account-1_ticket-session-42",
"mid": "request-42",
"seq": 184716,
"d": {
"kind": "lifecycle",
"lifecycle": {
"phase": "retry",
"error": {
"message": "模型调用异常,正在重试",
"retry_info": {
"fault_scope": "task",
"run_attempt": 1,
"max_retries": 3
}
}
}
}
}错误信息以下列字段为准,均可能缺省:
字段路径(相对于 d.lifecycle) | 含义 | 客户端处理 |
|---|---|---|
error.type、error.message | 错误类型和说明 | 用于诊断;不按文案判定任务是否结束 |
error.code | 数字错误码 | 未知值保留通用错误处理,不因新增错误码停止接收 |
error.retry_info.fault_scope | step 为单次调用重试,task 为任务级重试 | 单步重试保留运行状态;任务级重试显示“重试中” |
error.retry_info.run_attempt | 服务端报告的尝试序号:任务级从 1 开始;步骤级可能从 0 或 1 开始 | 可随重试或最终失败返回,仅用于诊断,不直接当作已重试次数或新的业务请求编号 |
error.retry_info.max_retries | 最大重试次数 | 有值时显示上限;不表示当前任务已经结束 |
error.retry_info.retry_checkpoint_id | 平台本次重试使用的上下文检查点 | 仅用于关联诊断,不替代 sid、mid 或续传游标 seq |
任务级重试仍属于原请求,不会再次发送 graph_start。客户端应把这次失败尝试的中间输出标为作废或折叠,再整理后续消息;不要把作废内容与最终结果拼在一起。只有明确为 step 时按单步处理;范围缺失时按任务级重试保守处理,但不显示猜测的次数。
单步重试不需要清空整个会话,但失败模型调用已经流出的半截文本也不能当作最终回复。客户端需要结合文本和工具事件区分已完成内容与失败尝试;retry_info 没有直接指出哪一条消息应作废,不能仅按最后一个 message_id 删除内容。
即使 retry 携带 error,也不能把任务标为失败。最终状态仍由主智能体的 success、error 或 cancelled 决定。自动重试、重连及继续会话都不会撤销已经完成的外部操作;应用仍需保存工具执行记录并检查幂等键。配置方法见配置超时、重试和备用模型。
选择并校验业务结果
准备把智能体回复用于后续业务处理时,先用 sid 和 mid 确认事件属于哪次请求,再按 message_delta.message_id 拼接每条文本消息。一次运行可能收到多条文本消息;按业务需要选出要用的内容,不要把不同消息、thinking、工具调用和工具结果混在一起。
收到主智能体这次运行的 success 事件,表示运行成功结束。这个事件不会告诉你哪条消息是业务结果,也不能保证内容格式正确。你的应用还要选出要用的回复,检查必填字段、允许值和当前用户权限,才能继续业务流程。具体示例见确认结果后再执行下一步。
待处理中断事件
新中断由 ev.d.kind = pending 且 pending_phase = created 标识:
{
"t": "ev",
"sid": "account-1_ticket-session-42",
"mid": "6d8c49ab-88fd-411b-9bac-0a6ff9493108",
"seq": 184714,
"d": {
"kind": "pending",
"pending_phase": "created",
"pending": {
"id": "interrupt-1",
"tool_call_id": "call-1",
"type": "respond",
"name": "get_ticket_status",
"arguments": "{\"ticket_id\":\"INC-1024\"}",
"meta": {}
}
}
}pending.type = hitl 使用 APPROVE 或 REJECT;respond 使用 RESPOND 或 ERROR。用户工具需要调用方执行业务代码,不是批准后由平台代为执行。
通过 HTTP RespondInterrupt 回传决定或结果。收到 pending_phase = resolved 时移除对应待处理项,并继续等待运行终态。
心跳、重连与补偿
服务端使用 WebSocket 协议层 ping 保持连接,通常由客户端库自动响应 pong。默认间隔为 30 秒,连续两个周期没有入站消息或协议层 pong 会断开;实际部署配置可能不同。客户端也可发送 JSON {"t":"PING"},服务端返回 {"t":"PONG"},不要把协议层 ping 与 JSON 业务帧混为一谈。
断线后退避重连,重新鉴权并重新订阅,每个会话使用最后持久保存的外层 seq。序号不一定连续,不要自行把跳号判定为丢包。
收到 reset 后,清除失效游标,以 reset.d.cursor ?? 0 作为恢复起点;帧中省略 cursor 时使用 0。暂存随后收到的事件,同时使用 HTTP ListMessages 重建历史、ListPendingInterrupts 补齐待处理项。恢复后将暂存事件与历史合并、去重,再继续处理并保存外层 seq。不要清除已执行业务工具的去重记录。
服务端发送 reset 后会继续回放,不需要每次都重新订阅。若连接或订阅也需要恢复,使用重置后最后已处理的外层 seq 作为 since_seq;尚未处理新事件时使用上述恢复起点。不要因 cursor 缺失而省略 since_seq,否则只会收到新事件。
补偿查询的字段和示例分别见 ListMessages 和 ListPendingInterrupts。后者不返回原 mid,应使用之前保存的中断关联记录。查询不可用时明确提示恢复失败,不假装任务已完成或重复执行业务操作。
退订使用 {"t":"unsub","d":{"session_id":"<context_key>"}}。同一会话发往平台的请求要按顺序发送。重试同一条消息时沿用原 msg_id;发送新消息时使用新 msg_id。服务端只会在短时间内对重复投递去重。你的应用还要保存处理记录,避免重连或重启后再次写入数据、重复执行下一步。具体做法见保存业务进度和调用记录。
错误处理
HTTP 客户端先检查实际状态码,再检查 success_response。业务失败可能使用 HTTP 200;按照 data.reason 分支,不用 code = 0 判断成功。
握手和 HTTP 错误
| 情况 | 处理 |
|---|---|
| HTTP 401 | 检查 Token、有效期和账号绑定;停止盲目重试 |
| HTTP 503 | 服务暂不可用,退避重试 |
invalid_request | 修正缺失、未知或无效字段 |
forbidden | 当前账号无权读取目标会话;核对会话归属和 Token,不用更换最终用户标识绕过校验 |
publish_failed | 先核对是否已接收;重试 SendMessage 或 RespondInterrupt 时保留原 msg_id |
history_unavailable / pending_unavailable | 状态补偿不可用,保留本地记录并联系服务提供方 |
Token 轮换后要主动替换客户端连接;不要假定已建立连接立即随 Token 停用而断开。参见分批轮换 WebSocket Token。
WebSocket 错误帧
根据 err.d.reason 处理:
too_many_connections:减少连接数,并退避重连。backpressure:向客户端发送事件持续受阻。检查网络连接和客户端接收、处理事件的速度,再携带已保存的游标重连;不必重新提交原业务请求。unknown_frame_type:客户端发送了不支持的帧,检查帧类型和所用协议。
订阅失败使用 subd.d.ok = false,业务写入失败使用 HTTP 信封,两者与连接级错误分别处理。