主题
WebSocket API
本文引用的源码文件
本文引用的文件
目录
简介
本文件是 AI Helper 扩展(Chrome 扩展端)与本地 Agent(Node.js)之间 WebSocket 实时通信的参考文档。重点覆盖:
- 连接建立、认证方式与协议路径
- 命令执行实时输出流:标准输出、错误输出、退出事件、进度与截断提示
- 日志订阅机制(HTTP 查询接口与语言设置)
- 连接管理:心跳检测、自动重连策略、断线处理与进程保活
- 客户端实现要点:连接建立、消息收发、错误处理
- 性能优化:批量处理、背压控制与超时策略
本项目为双进程架构:Chrome 扩展端 + 独立本地 Agent 端,两端版本号同步为 2.3.1。Agent 源码修改后必须重启进程,新接口才生效。
章节来源
项目结构
WebSocket 相关代码主要分布在以下位置:
- Agent 服务端:HTTP 路由与 WebSocket 升级、认证、心跳、命令输出广播
- Agent 命令执行器:子进程管理、stdout/stderr 流式广播、超时与终止策略
- 扩展端客户端:封装 HTTP/WebSocket 调用、Token 注入、消息转发
- 扩展端工具执行器:会话级超时、空闲挂起、取消与回退逻辑
graph TB
subgraph "Chrome 扩展端"
LC["local-agent-client.js<br/>创建 WebSocket、注入 Token"]
TE["tool-executor.js<br/>会话超时、取消、回退"]
end
subgraph "本地 Agent 端"
SRV["server.js<br/>HTTP + WebSocket 服务器"]
EXE["executor.js<br/>子进程 + 流式输出"]
end
LC --> |ws:/ws/exec/{execId}?token=...| SRV
SRV --> EXE
EXE --> |stdout/stderr/exit/error| SRV
SRV --> |JSON 消息| LC
LC --> TE
图表来源
- agent/src/server.js#L2086-L2153
- agent/src/executor.js#L198-L386
- src/background/local-agent-client.js#L662-L728
- src/background/tool-executor.js#L4333-L4699
章节来源
核心组件
- Agent WebSocket 服务器:监听
/ws/exec/{execId},校验 Token,注册到对应进程,发送心跳 ping,处理关闭。 - Agent 命令执行器:启动 shell 子进程,将 stdout/stderr 流式广播给所有连接的 WebSocket 客户端,并在进程结束或出错时发送 exit/error。
- 扩展端 WebSocket 客户端:通过
createExecWebSocket建立连接,附加 Bearer Token,解析 JSON 消息并转发给上层。 - 扩展端工具执行器:维护会话级超时、空闲检测、用户取消、Agent 超时兜底,以及 WebSocket 异常时的回退逻辑。
章节来源
- agent/src/server.js#L2086-L2153
- agent/src/executor.js#L198-L386
- src/background/local-agent-client.js#L662-L728
- src/background/tool-executor.js#L4333-L4699
架构总览
WebSocket 实时通信的核心流程如下:
- 扩展端发起命令执行,获取 execId 与 wsUrl。
- 扩展端使用
new WebSocket(wsUrl)建立连接,URL 中附带 token。 - Agent 端验证 Token,将连接加入对应进程的客户端集合。
- 命令 stdout/stderr 数据以 JSON 消息形式推送至客户端。
- 进程结束时发送 exit 事件;发生错误时发送 error 事件。
- 服务端周期性 ping 检测半开连接,未 pong 则 terminate。
sequenceDiagram
participant Ext as "扩展端 tool-executor.js"
participant Client as "扩展端 local-agent-client.js"
participant Server as "Agent server.js"
participant Exec as "Agent executor.js"
Ext->>Client : "execCommand(command, cwd, force, timeoutMs)"
Client-->>Ext : "{success, execId, wsUrl}"
Ext->>Client : "createExecWebSocket(wsUrl, onMessage, onClose, onError)"
Client->>Server : "WebSocket /ws/exec/{execId}?token=..."
Server->>Exec : "addWsClient(execId, ws)"
Exec-->>Server : "stdout/stderr 流式数据"
Server-->>Client : "JSON {type : 'stdout'|'stderr', data, execId}"
Exec-->>Server : "exit/error"
Server-->>Client : "JSON {type : 'exit'|'error', ...}"
Server->>Server : "ping/pong 心跳检测"
图表来源
- src/background/tool-executor.js#L4333-L4430
- src/background/local-agent-client.js#L662-L728
- agent/src/server.js#L2089-L2149
- agent/src/executor.js#L297-L386
详细组件分析
WebSocket 连接建立与认证
- 连接路径:
/ws/exec/{execId} - 认证方式:优先 Authorization Header,回退 URL query 参数
token - 浏览器限制:无法设置自定义 Header,因此扩展端通过 URL 传递 token
- 无效 Token:直接返回 403 并销毁 socket
flowchart TD
Start(["WebSocket 升级请求"]) --> Parse["解析路径与查询参数"]
Parse --> CheckPath{"路径为 /ws/exec/{execId} ?"}
CheckPath --> |否| Drop["丢弃连接"]
CheckPath --> |是| Auth["验证 Token<br/>Authorization 或 ?token="]
Auth --> Valid{"Token 有效?"}
Valid --> |否| Deny["403 Forbidden"]
Valid --> |是| Upgrade["wss.handleUpgrade"]
Upgrade --> Register["addWsClient(execId, ws)"]
Register --> Heartbeat["启动 ping/pong 心跳"]
Heartbeat --> Ready(["连接就绪"])
图表来源
章节来源
命令执行实时输出流
- 标准输出:
{ type: 'stdout', data: string, execId } - 错误输出:
{ type: 'stderr', data: string, execId } - 输出截断提示:
{ type: 'stdout_truncated' | 'stderr_truncated', message, execId } - 进程退出:
{ type: 'exit', exitCode, execId, killed, timedOut } - 进程错误:
{ type: 'error', error, execId }
flowchart TD
Spawn["spawn shell 子进程"] --> Stdout["监听 stdout"]
Spawn --> Stderr["监听 stderr"]
Stdout --> BroadcastStdout["广播 {type:'stdout'}"]
Stderr --> BroadcastStderr["广播 {type:'stderr'}"]
Close["进程 close"] --> Exit["广播 {type:'exit'}"]
Error["进程 error"] --> ErrMsg["广播 {type:'error'}"]
图表来源
章节来源
日志订阅机制
- 日志查询接口:
GET /api/logs(需认证),支持按日期范围查询 - 日志级别过滤:由 logger 模块提供,服务端根据请求语言设置日志 locale
- 实时推送:当前日志系统通过 HTTP 查询,非 WebSocket 推送;如需实时日志订阅,可在现有日志查询基础上扩展 WebSocket 通道
flowchart TD Request["GET /api/logs?from=&to="] --> Verify["Bearer Token 校验"] Verify --> Query["logger.queryLogs(from, to)"] Query --> Response["返回日志数组"]
图表来源
章节来源
连接管理与心跳检测
- 心跳间隔:每 30 秒 ping 一次
- 未 pong 处理:两次未收到 pong 则 terminate 连接
- 断开处理:从进程客户端集合移除,若所有客户端断开且非受管模式,则取消超时定时器
stateDiagram-v2 [*] --> Connected Connected --> Alive : "pong 收到" Connected --> Dead : "未 pong" Alive --> Connected : "ping 发送" Dead --> Terminated : "terminate" Terminated --> [*]
图表来源
章节来源
自动重连与断线处理
- 扩展端客户端:
createExecWebSocket在 onclose/onerror 中触发回调,由上层决定是否重连 - 工具执行器:会话级超时、空闲检测、用户取消;WebSocket 异常时尝试清理并回退到同步模式(仅当进程未启动)
- 测试用例:模拟
onmessage回调接线,确保 exit 事件能正确触发完成逻辑
flowchart TD
WSOpen["WebSocket 打开"] --> OnMessage["接收 stdout/stderr/exit"]
OnMessage --> NormalExit{"收到 exit?"}
NormalExit --> |是| Finish["正常结束"]
NormalExit --> |否| TimeoutCheck["检查空闲/总预算"]
TimeoutCheck --> IdleTimeout{"空闲超时?"}
IdleTimeout --> |是| Detach["detach 进程"]
IdleTimeout --> |否| Continue["继续等待"]
WSOpen --> OnClose["连接关闭"]
OnClose --> Cancelled{"用户取消?"}
Cancelled --> |是| Resolve["resolve 正常结束"]
Cancelled --> |否| Cleanup["cleanupAndStop"]
图表来源
章节来源
WebSocket 客户端实现示例
- 连接建立:使用
new WebSocket(authenticatedUrl),URL 包含 token - 消息接收:
ws.onmessage解析 JSON,调用 onMessage 回调 - 错误处理:
ws.onerror记录错误并 reject Promise - 关闭处理:
ws.onclose触发 onClose 回调
classDiagram
class LocalAgentClient {
+createExecWebSocket(wsUrl, onMessage, onClose, onError)
-getAgentConfig()
-agentRequest(path, body, method, timeoutMs)
}
class ToolExecutor {
+executeAgentExecCommand(args, toolCallId, sessionId)
-scheduleTimeoutCheck()
-cleanupAndStop(reason)
}
LocalAgentClient --> ToolExecutor : "被调用"
图表来源
章节来源
依赖关系分析
- Agent 服务端依赖:
ws库用于 WebSocket 服务器executor.js用于命令执行与输出广播auth.js用于 Token 验证logger.js用于日志记录
- 扩展端客户端依赖:
chrome.runtime用于消息传递shared/logger.js用于日志shared/i18n.js用于国际化
graph TB SRV["server.js"] --> WS["ws 库"] SRV --> EXEC["executor.js"] SRV --> AUTH["auth.js"] SRV --> LOG["logger.js"] LC["local-agent-client.js"] --> CHROME["chrome.runtime"] LC --> SHARED_LOG["shared/logger.js"] LC --> I18N["shared/i18n.js"]
图表来源
章节来源
性能与优化建议
- 批量处理:stdout/stderr 数据已流式传输,避免一次性加载大文件
- 背压控制:客户端应实现消息队列,避免 UI 渲染阻塞
- 超时策略:
- 空闲超时:长时间无输出视为挂起型命令,detach 进程
- 总预算封顶:Agent 端最大延长次数与总预算上限对齐扩展端
- 心跳检测:每 30 秒 ping,未 pong 则 terminate,防止半开连接占用资源
- 内存限制:输出缓冲区上限 5MB,超过后截断并通知客户端
章节来源
- agent/src/executor.js#L96-L114
- agent/src/executor.js#L165-L186
- src/background/tool-executor.js#L4315-L4327
- agent/src/server.js#L2133-L2143
故障排查指南
- 连接失败:检查 Token 是否正确,URL 是否包含
/ws/exec/{execId} - 无输出:确认进程是否启动,stdout/stderr 是否正常写入
- 连接中断:检查心跳是否响应,网络是否稳定
- 进程残留:确认 cleanupAndStop 是否调用,killProcess 是否成功
- 超时问题:检查空闲超时与总预算配置,Agent 端与扩展端是否一致
章节来源
结论
本 WebSocket API 提供了可靠的实时命令执行输出能力,结合心跳检测、超时策略与断线处理,确保了连接稳定性与资源安全。扩展端与 Agent 端的职责清晰,客户端实现简洁,便于集成与维护。建议在生产环境中启用批量处理与背压控制,进一步优化性能与用户体验。