Skip to content

HTTP 与 WebSocket API 参考 ​

连接 AI 助手

本页提供 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 响应格式 ​

六个方法使用相同的响应格式:

language-json
{
  "code": 0,
  "http_status_code": 200,
  "success_response": true,
  "data": {}
}

data 的内容由方法决定;下文的“成功响应 data”示例均放在这个外层结构内。调用方先检查实际 HTTP 状态,再检查 success_response。业务失败也可能返回 HTTP 200 和 code: 0,此时按 data.reason 处理,详见错误处理。

鉴权 ​

HTTP 请求使用:

language-text
Authorization: Bearer wst_<token>
Content-Type: application/json

wst_ 只存放在服务端。浏览器业务界面应调用你自己的后端,不把长期 Token 下发到浏览器。

握手阶段鉴权 ​

WebSocket 握手可使用:

language-text
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_idstring必填后端根据已认证用户提供的稳定标识
contentstring必填非空文本;以 / 开头时按渠道指令处理
chat_typestring可选group 或 p2p,默认 group
chat_idstring可选业务会话标识;省略时使用 user_id
user_namestring可选用户展示名
msg_idstring可选建议填写 UUID;省略时由服务端生成

请求体示例:

language-json
{
  "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。

成功信封示例:

language-json
{
  "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_idstring必填原业务上下文中经过授权检查的用户
msg_idstring必填产生中断的事件帧 mid
interrupt_idstring必填事件中的 d.pending.id
actionstring必填APPROVE、REJECT、RESPOND 或 ERROR
context_keystring建议填写产生中断的事件帧 sid
chat_type、chat_id、user_namestring可选与原请求保持一致;chat_id 不是 context_key
response_datastring可选工具结果、安全错误信息或拒绝原因;结构化内容先序列化为 JSON
additional_tool_rulearray可选附加一条后续工具自动审批规则,见下方说明

hitl 中断使用 APPROVE 或 REJECT;respond 中断使用 RESPOND 或 ERROR。用户工具需要应用实际执行后再回传结果。请求体示例:

language-json
{
  "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_idstring必填原业务上下文中的用户
chat_typestring可选与原输入相同,默认 group
chat_idstring可选与原输入相同;省略时使用 user_id
user_namestring可选用户展示名

请求体示例:

language-json
{"chat_type":"group","chat_id":"ticket-session-42","user_id":"user-17"}

成功响应 data 示例:

language-json
{
  "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 所属的渠道账号,适合检查客户端是否使用了预期凭证。无需业务参数,请求体使用空对象:

language-json
{}

成功响应 data 示例:

language-json
{
  "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_keystring必填服务端返回的会话标识
limitinteger可选返回条数,默认 20、上限 200;不与分页参数混用
pageinteger可选从 1 开始的页码,与 page_size 配合使用
page_sizeinteger可选每页条数;指定分页参数后按分页查询,不再使用 limit
from、tostring可选checkpoint 区间标识,使用已有响应提供的值

查询最近 20 条消息的请求体示例:

language-json
{"context_key":"account-1_ticket-session-42","limit":20}

成功响应 data 示例:

language-json
{
  "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:

language-json
{"context_key":"account-1_ticket-session-42"}

成功响应 data 示例:

language-json
{
  "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 后发送:

language-json
{"t":"sub","d":{"session_id":"account-1_ticket-session-42","since_seq":0,"mode":"full"}}

这里的 session_id 必须是服务端 context_key。等待 subd 并检查 subd.d.ok:

language-json
{"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 帧示例:

language-json
{
  "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,并检查任务所需的业务结果:

language-json
{
  "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 次:

language-json
{
  "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_scopestep 为单次调用重试,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 标识:

language-json
{
  "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 信封,两者与连接级错误分别处理。

升级现有客户端时查看 API 更新日志;旧协议的替换步骤见迁移旧版智能体接入。