如何通过本地端点注册表让外部客户端连接正在运行的 VS Code Agent Host
【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscode
如果你写了一个同机运行的本地进程(工具、脚本或桥接服务),希望它作为外部客户端接入正在运行的 VS Code Agent Host 并使用 Agent Host Protocol(AHP),VS Code 提供了一条官方路径:本地端点注册表(local endpoint registry)。每个本机上运行的 agent host 进程——VS Code 编辑器自己的 utility 进程、其他编辑器窗口,以及独立的code agent hostCLI——都会在注册表中发布一条包含端点地址和连接令牌的条目;你的客户端只需按规则读出条目、带上令牌完成 WebSocket 升级、再执行 AHP 的initialize协商,即可接入。协议规范见 LOCAL_ENDPOINT.md。
适用前提(文档明确给出的边界):
- 外部客户端必须与 agent host 以同一用户运行,端点暴露对象是“other processes running as the same user”;
- 注册表条目是可选的:如果 VS Code 无法准备或发布外部端点,它会记录错误并继续在内部 MessagePort 传输上运行 agent host,此时注册表里读不到该编辑器实例;
- 端点形态取决于宿主类型:编辑器(
editor)发布 Unix domain socket(macOS/Linux)或命名管道(Windows),独立 CLI(standalone)发布 TCP 监听。
注册表位置与条目文件格式
注册表是“每个实例一个条目文件”的目录结构:
<userDataPath>/agent-host/local-endpoint/entries/<identity>.json其中<identity>是${type}\0${pid}\0${instanceId}(NUL 分隔)这个 UTF-8 字符串的小写 SHA-256 十六进制摘要,因此文件名跨语言、路径安全且抗碰撞;读取方通过枚举该目录发现所有存活的本地 agent host。<userDataPath>是当前 VS Code 用户数据目录,其值取决于产品质量(Stable/Insiders)和是否传了--user-data-dir,文档明确要求实现方解析当前实际使用的用户数据目录,而不是假设默认的 Stable 或 Insiders 位置。
每个条目文件是一个 JSON 对象,当前 schema 版本为2。以下是文档中的示例(示例结果,字段值不要当作固定预期):
{ "schemaVersion": 2, "type": "editor", "pid": 12345, "instanceId": "base64url-instance-id", "protocolVersion": "0.7.0", "connectionToken": "base64url-bearer-token", "endpoint": { "type": "socket", "path": "\\\\.\\pipe\\vscode-agent-host-..." } }各字段含义(来自文档的字段表):
| 字段 | 说明 |
|---|---|
schemaVersion | 元数据 schema 版本。客户端必须忽略自己不理解版本的条目,而不是拒绝整个文件 |
type | 端点所有者进程类型:editor(VS Code utility 进程)或standalone(code agent hostCLI)。它只影响客户端的所有权/默认选择策略,不是信任度指标 |
pid | 端点所属进程的 PID |
instanceId | 随机标识,用于区分同一进程的前后继端点所有者;与type、pid一起构成条目身份,因为 PID 可能被系统复用 |
protocolVersion | host 支持的 AHP 版本,供发现与诊断使用,不能替代正常的 AHPinitialize协商 |
connectionToken | WebSocket 升级阶段必需的随机 bearer 令牌 |
endpoint | 区分联合体:socket 端点为{ "type": "socket", "path": string }(编辑器当前使用),TCP 端点为{ "type": "tcp", "host": string, "port": number }(独立 CLI 使用) |
quality/tunnelName | 可选,standalone 端点的产品质量 / 隧道名,不属于条目身份 |
目录权限:注册表根目录和entries/目录仅当前用户可访问(POSIX 上 mode0700,Windows 上是 owner-only ACL),条目文件 mode0600。条目文件只在端点开始监听且协议处理器安装完成后才被原子写入。
旧版构建写的是单文件数组<userDataPath>/agent-host/local-endpoint/metadata.json。读取方仍会只读合并该遗留文件中的有效条目,使升级前启动的 host 依然可被发现;新条目文件在(type, pid, instanceId)冲突时获胜,遗留条目会随旧进程退出被 PID 存活检查自然清掉。
用code agent endpoints一次性读出全部活跃端点
手写客户端不必自己解析注册表目录:Rust CLI 提供了机器可读命令code agent endpoints(实现见 agent_endpoints.rs)。它向 stdout 恰好输出一个 JSON 文档,包含解析后的userDataPath和全部存活端点——并且完整保留connectionToken,目的正是交给可信的已认证调用方(例如通过 SSH 桥接进来的工具)自己去拨号:
code agent endpoints # 如果 agent host 使用了自定义用户数据目录: code agent endpoints --user-data-dir <你的用户数据目录>输出文档形状如下(以下取自 CLI 测试,属于文档示例):
{ "userDataPath": "<解析后的用户数据目录>", "endpoints": [ { "schemaVersion": 2, "type": "standalone", "pid": 42, "instanceId": "instance-a", "protocolVersion": "0.1.0", "connectionToken": "<令牌>", "endpoint": { "type": "tcp", "host": "127.0.0.1", "port": 8080 } } ] }注意两点判定语义(源码注释明确给出):endpoints为空数组是合法且有意义的答案,表示“当前没有 agent host 在运行”,与“注册表读取失败”是两回事;命令不会因为没有端点而报错。
如果你的客户端是自己实现读取逻辑(不走 CLI),共享的解析器/模型在 agentHostEndpointRegistry.ts,编辑器侧发布与读取在 localAgentHostMetadata.ts,Rust 侧对应实现是 agent_host_registry.rs,文档要求每一处本地读取/写入都用它做一致的校验。
按客户端规则校验与去重条目
文档要求客户端把每个条目和每个字段都当作不可信输入处理,规则如下(缺失一条都会导致选到坏端点或误删有效条目):
- 逐条做结构校验,坏条目单独丢弃,不要让整个读取失败;
- 忽略
schemaVersion不受支持的条目(例如版本1的旧扁平格式,当前读取方直接忽略); - 在可以做 PID 存活检查时,忽略确认已死的 PID 的条目;
- 按
(type, pid, instanceId)去重; - 永远不要自行重建
endpoint值——总是原样使用发布出来的地址。
端点路径规律仅供识别,不能用来拼路径:Windows 上编辑器的endpoint.path是\\.\pipe\vscode-agent-host-<user-data-hash>-<instance-id>;macOS/Linux 上是<os.tmpdir()>/vscode-ah-<user-data-hash>/<instance-id>.sock(短目录是为了避开 Unix socket 路径长度限制)。
CLI 的活跃端点枚举(list_live_endpoints)在 PID 存活检查之外还会做可达性验证:对 socket 端点尝试建立连接、对 TCP 端点连接host:port,2 秒内未接受连接即判定不可达并过滤该条目(不会删除其注册表文件)。你的客户端如果要在重连期间判断哪个条目仍然可用,可以参考这一思路,但文档没有规定统一的客户端侧重试策略。
使用令牌连接端点
拿到条目后,按 LOCAL_ENDPOINT.md 的“Connecting”一节操作:
- 对 socket 端点,向
endpoint.path发起 WebSocket 连接(对 TCP 端点,连接host:port后同样走 WebSocket 帧); - 在升级请求上通过 VS Code 标准的 connection-token 查询参数携带令牌:
?tkn=<connectionToken>- WebSocket 升级成功后,发送正常的 AHP
initialize请求完成协商。条目里的protocolVersion只用于发现与诊断,不能替代这一步协商; - 缺少令牌或令牌错误的连接会在 WebSocket 升级阶段被以HTTP 403拒绝——这是判断令牌是否正确、端点是否要求认证的直接信号。
下面的片段是把上面规则组合起来的示意(变量来自条目 JSON,按你读到的条目值替换;ws为任意 WebSocket 客户端库):
// entry 是从注册表条目解析出的单个对象 const url = entry.endpoint.type === 'socket' ? `ws://${entry.endpoint.path.replace(/\\/g, '/')}?tkn=${encodeURIComponent(entry.connectionToken)}` : `ws://${entry.endpoint.host}:${entry.endpoint.port}?tkn=${encodeURIComponent(entry.connectionToken)}`; const socket = new WebSocket(url); socket.onopen = () => { // 升级成功后:发送 AHP initialize 请求完成协商(字段按 AHP 规范填写) }; socket.onerror = (e) => { // 升级阶段被拒(如 403)会走到这里 };文档只规定了?tkn=这一携带方式,未指定具体语言绑定;如果你的客户端从code agent endpoints的输出中取userDataPath,还可以直接用它去启动code agent host --user-data-dir <该目录>,不需要自行重实现用户数据目录解析规则。
验证结果与需要处理的情况
- 接入成功:WebSocket 升级未被拒绝(没有 403),且 AHP
initialize协商完成; - 令牌问题:升级阶段收到 HTTP 403,说明缺少
tkn参数或令牌与条目不符。standalone host 若以--without-connection-token启动,其注册表条目中connectionToken为空,此时不存在令牌校验; - 条目缺失:条目是可选的,VS Code 发布外部端点失败时会继续用内部 MessagePort 运行,客户端会看到缺失条目;
- 陈旧条目:进程退出后其条目会被 PID 存活检查清掉,读取日志中会出现
Pruning stale local endpoint registry entry: <type> PID <pid> (instance <instanceId>) is no longer running一类信息; - 重连健壮性:文档明确要求客户端处理“条目缺失、陈旧 PID、端点关闭、注册表在重连期间发生变化”这几种情况;
- 多条目选择:独立 CLI 选择器只考虑
standalone条目(editor条目归运行的 VS Code 窗口所有,CLI 不会替用户去选、替换或杀编辑器实例),多个存活 standalone 条目时选最近发布的并建议用--address消歧;你自己的客户端可按type区分所有权策略,但不要把它当信任等级用。
可选分支:没有存活 standalone host 时如何启动或替换
如果注册表里只有editor条目、或你想为自己的工具准备一个专用 host,可用code agent host(实现见 agent_host.rs)。它默认以后台守护进程方式启动 supervisor 并绑定 TCP 监听、发布 standalone 注册表条目;重复执行时若已有存活 supervisor 且配置兼容,只打印复用横幅(含端口和?tkn=令牌)并不启动新进程。常用参数:
code agent host # 默认绑定 127.0.0.1,随机端口 code agent host --host 0.0.0.0 --port 8080 code agent host --connection-token-file <文件> # 从文件读取令牌 code agent host --without-connection-token # 不启用令牌 code agent host --foreground # 前台运行,日志留在终端两个注意点:--replace会先杀掉现有 supervisor 进程树并删除其注册表条目再启动新实例,只在确认要替换时加;若请求的--host/--port/令牌配置与正在运行的 supervisor 冲突且未加--replace,命令会打印冲突说明并以状态码 2 退出,提示用code agent kill停止或传--replace接管。日常巡检和管理用横幅里给出的入口:code agent ps与code agent kill。
客户端侧的完整协议细节(注册表、发布、读取、清理)可以分别回到 LOCAL_ENDPOINT.md、agentHostEndpointRegistry.ts 与 agent_host_registry.rs 核对;TS 与 Rust 两端的 schema、哈希编码和身份命名是刻意保持逐字节一致的,字段改名或删除必须在两个语言实现间协同修改。
【免费下载链接】vscodeVisual Studio Code项目地址: https://gitcode.com/GitHub_Trending/vscode6/vscode
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考