news 2026/9/12 11:58:42

使用 @ai-sdk/harness-acp 将 ACP v1 Agent 接入 AI SDK:桥接架构、配置映射与实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
使用 @ai-sdk/harness-acp 将 ACP v1 Agent 接入 AI SDK:桥接架构、配置映射与实战

使用 @ai-sdk/harness-acp 将 ACP v1 Agent 接入 AI SDK:桥接架构、配置映射与实战

【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai

导读

@ai-sdk/harness-acp是 AI SDK 的 HarnessV1 适配器,它让HarnessAgent能够直接驱动遵循 Agent Client Protocol 为主线,结合该包源码,完整讲解它的桥接运行架构、安装配置、createACP全部核心选项(模型映射、指令映射、权限模式映射、凭据代理等),并给出一个可复制的端到端示例。读完本文,你将能基于任意 NPM 安装的 ACP v1 实现,在自己的沙箱中快速搭建一个 AI Agent Harness。

架构总览:桥接进程、沙箱与 WebSocket

@ai-sdk/harness-acp是一个HarnessV1适配器,其底层是一个通过 NPM 安装的Agent Client Protocol v1 实现(下称"ACP 实现")。整体运行模型可以用一句话概括:适配器在沙箱内托管一个桥接进程,桥接进程在沙箱代理的回环端口上通过 WebSocket 与宿主机通信,而配置的 ACP 实现与桥接进程一同运行在沙箱内部

具体链路(对应 acp-v1-harness.ts 中doStart的实现)为:

  1. 宿主侧的HarnessAgent调用createACP生成的适配器,在沙箱会话中启动桥接脚本bridge.mjs
  2. 桥接进程监听沙箱暴露的 TCP 端口(BRIDGE_WS_PORT),并携带一枚BRIDGE_CHANNEL_TOKEN令牌进行鉴权(见 acp-v1-harness.ts);
  3. 宿主通过SandboxChannel(底层为ws库的 WebSocket 客户端)连接到该端口,按照outboundMessageSchema/inboundMessageSchema(见 acp-v1-bridge-protocol.ts)收发桥接协议消息;
  4. 桥接进程内部加载 ACP v1 实现,将宿主的请求翻译为 ACP JSON-RPC 方法(session/newsession/startsession/set_modesession/set_config_option等),并把实现的流式事件翻译回宿主。

因此有两条硬性约束(README 也明确指出):

  • 桥接型 ACP harness 要求沙箱至少暴露一个端口ports: [4000]或显式配置port)。源码中resolveBridgePort会优先使用portOverride,否则取沙箱ports数组的第一个元素,两者都没有时直接抛出unsupported错误(见 acp-v1-harness.ts)。
  • 使用不支持getPortEndpoint的 basic 沙箱会话时,必须同时显式配置portportEndpoint(见 acp-v1-harness.ts)。

从源码结构看,桥接层还承担了相当多的职责,包括:ACP 流事件捕获(acp-stream-capture.ts)、Agent stderr 监控(agent-stderr-monitor.ts)、宿主工具 MCP 中继(host-tool-relay.tshost-tool-mcp.ts)、会话生命周期管理(session-lifecycle.ts)与流翻译(stream-translator.ts)等,这些都位于 bridge 目录 下。

安装与首次启动

安装共需三个包:适配器本身、harness 基座(提供HarnessAgent)以及沙箱实现:

npm i @ai-sdk/harness-acp @ai-sdk/harness @ai-sdk/sandbox-vercel

从 package.json 可以看到,@ai-sdk/harness-acp运行时依赖@ai-sdk/harness@ai-sdk/provider-utilsws,并将zod作为 peer 依赖(支持^3.25.76 || ^4.1.8),同时要求 Node.js>=22。包内声明了两个workspace:*依赖,说明在 monorepo 环境下与 harness 基座共同演进。

首次会话启动时,桥接进程会在沙箱内部安装配置的 ACP 实现。安装方式由source字段决定(见 implementation.ts):

  • npm-simple:按包名(可选精确版本)安装,内部生成package.json并执行pnpm install --prod
  • npm-locked:直接使用你提供的packageJsonpnpmLockYaml(可选pnpmWorkspaceYaml),以--frozen-lockfile锁定安装,保证可复现;
  • install-command:在沙箱内执行自定义安装命令,可执行文件路径固定为home/.local/bin/<executable>,并拥有独立的私有$HOME

最小可用示例:连接 Codex ACP

README 给出了一个完整示例——把HarnessAgent连接到 Codex ACP,并使用 OpenAI 直连鉴权:

import { HarnessAgent } from '@ai-sdk/harness/agent'; import { createACP } from '@ai-sdk/harness-acp'; import { createCredentialRequestTransformation } from '@ai-sdk/harness/utils'; import { createVercelSandbox } from '@ai-sdk/sandbox-vercel'; const codexACP = createACP({ harnessId: 'acp-codex', source: { type: 'npm-simple', packageName: '@agentclientprotocol/codex-acp', packageVersion: '1.1.4', }, executable: 'codex-acp', modelMapping: { type: 'session-config-option', path: 'model', }, credentialEnv: ['CODEX_API_KEY', 'OPENAI_API_KEY'], credentialBrokering: ({ env, sandboxEnv }) => { const environmentVariableName = env.CODEX_API_KEY ? 'CODEX_API_KEY' : 'OPENAI_API_KEY'; const credential = env[environmentVariableName]; const sandboxCredential = sandboxEnv?.[environmentVariableName]; if (!credential || !sandboxCredential) return []; return [ createCredentialRequestTransformation({ matchUrl: 'https://api.openai.com/v1', matchHeaders: { Authorization: `Bearer ${sandboxCredential}`, }, transformHeaders: { Authorization: `Bearer ${credential}` }, }), ]; }, instructionMapping: { type: 'launch-env-json', variable: 'CODEX_CONFIG', path: ['developer_instructions'], }, permissionModeMapping: { 'allow-reads': null, 'allow-edits': null, 'allow-all': { type: 'session-mode', modeId: 'agent-full-access' }, }, authentication: { methodId: 'api-key', }, }); const agent = new HarnessAgent({ harness: codexACP, sandbox: createVercelSandbox({ runtime: 'node24', ports: [4000], }), }); const session = await agent.createSession(); try { const result = await agent.generate({ session, prompt: 'Inspect this project and summarize its purpose.', }); console.log(result.text); } finally { await session.destroy(); }

运行前需在宿主机环境中设置CODEX_API_KEYOPENAI_API_KEY(二者取其一即可,credentialBrokering回调会按优先级选择)。session.destroy()放在finally中,确保任何情况下会话资源都能被释放。

配置项深度解析

createACP的入参类型为ACPHarnessSettings(见 acp-harness.ts),除上文示例外,下面逐个拆解核心配置。

harnessId 与版本

  • harnessId(必填):稳定的 kebab-case 标识符(正则^[a-z0-9]+(?:-[a-z0-9]+)*$),用于区分不同 ACP 实现、会话目录与生命周期状态。源码在 acp-v1-harness.ts 定义并在启动前校验。
  • version:默认'v1',目前仅支持'v1',传入其他值会抛出 "Unsupported ACP protocol version"(见 acp-harness.ts)。
  • clientApp:可选,默认{ name: 'ai-sdk/harness-acp', version: VERSION },会在 ACP 客户端身份(client/register)中上报。

实现安装:source 与 executable

  • source(必填):npm-simple/npm-locked/install-command三种安装源,详见上文"首次启动"一节。注意npm-simplepackageVersion必须是精确语义化版本,且省略版本号时安装latestdist-tag,此时版本不参与实现身份哈希——即上游发布新版本不会使既有生命周期状态失效(见 acp-v1-settings.ts 与 implementation.ts)。
  • executable(必填):裸命令名(不含路径),安装后从node_modules/.bin/(npm 源)或home/.local/bin/(install-command 源)解析。
  • args:可选,启动 ACP 实现时追加的命令行参数。

模型映射:modelMapping(必填)

ACP 实现的模型选择操作各不相同,因此modelMapping是必填项。两种取值(类型定义见 acp-v1-settings.ts,发送逻辑见 bridge/model-mapping.ts):

类型用途底层 ACP 方法
session-config-option通过 ACP 配置选项指定模型,path为配置选项 IDsession/set_config_optionconfigId: path,value: model
session-model使用传统session/set_model方法,path为 JSON-RPC 请求属性名session/set_model

例如 Codex 使用session-config-option+path: 'model';而 Grok Build 等实现沿用session/set_model,应改用session-model。另外,当HarnessAgent未配置模型时,适配器不会发送任何模型操作(见 model-mapping.ts 的if (model == null) return;)。

指令映射:instructionMapping

当 ACP 实现支持原生 system / developer prompt 时,用instructionMappingHarnessAgent的 instructions 路由进去。三种映射方式(见 acp-v1-settings.ts 与 bridge/instruction-mapping.ts):

  • session-meta:把指令写入 ACP 会话请求_meta字段下的指定路径(path为相对_meta的属性路径数组);
  • launch-env-json:实现启动前,把指令合并进某个 JSON 环境变量(variable)的指定路径(如示例中的CODEX_CONFIGdeveloper_instructions);
  • filesystem:把指令写成一个 markdown 文件,存放在实现有效$HOME下的相对路径。

重要兼容性说明:不配置instructionMapping时,适配器保留向后兼容行为——把指令前置拼接到第一条用户 prompt上。另外session-metalaunch-env-json的路径会做安全校验,禁止空属性名以及__proto__constructorprototype等危险段(见 instruction-mapping.ts)。

权限模式映射:permissionModeMapping

把 HarnessAgent 的三种权限模式(allow-reads/allow-edits/allow-all)映射为 ACP 目标(见 acp-v1-settings.ts):

  • 值为null:表示该权限模式不受支持,调用时直接报错;
  • { type: 'session-mode', modeId }:调用 ACPsession/set_mode
  • { type: 'session-config-option', configId, value }:调用session/set_config_option(布尔值会附带type: 'boolean')。

Codex 特例:Codex ACP 只支持permissionMode: 'allow-all',因为它更受限的模式会启用 Codex 内部的沙箱(导致嵌套沙箱冲突)。示例中把allow-readsallow-edits都置为null,仅allow-all映射到agent-full-access模式。若运行时请求了未映射的模式,适配器会抛出带提示的错误(见 bridge/permission-mode.ts)。

凭据与认证

  • authentication:ACP 认证方式声明,示例使用{ methodId: 'api-key' };类型定义见 acp-auth.ts(ACPClientAppACPAuthenticationMode)。
  • credentialEnvcredentialBrokering二者必须同时配置,否则createACP直接抛错("ACP credentialEnv and credentialBrokering must be configured together.",见 acp-harness.ts)。credentialEnv声明要进入沙箱凭据环境的宿主机环境变量;credentialBrokering是一个接收{ env, sandboxEnv, headers }并返回HarnessV1RequestTransformation[]的回调,用于把真实凭据"代理"给沙箱内发出的匹配请求。
  • 两种沙箱行为差异(README 明确强调)
    • 支持"additive request transformations"(即实现addRequestTransformations)的沙箱,只收到凭据占位符,真实值仅当发出的出站请求携带预期占位符时才被注入(对应createSandboxCredentialEnvironment+addRequestTransformations的流程,见 acp-v1-harness.ts);
    • 其他沙箱保留传统行为:直接把凭据值转发给 ACP 进程。
  • credentialForwarding:在凭据进入沙箱进程前做自定义改写;authenticationFiles:在实现启动前于其私有 home 目录下落地认证文件(写入后统一chmod 600保护,见 acp-v1-harness.ts)。

其他可选能力

  • mcpServers/isMcpToolCall:向 ACP 实现提供 MCP 服务器定义,ai-sdk-harness-tools这一名字被保留给 HarnessAgent 工具,占用会报错(见 acp-harness.ts)。
  • hostToolMcpTransport:harness 自有的、把宿主工具暴露给 ACP 实现的 MCP 服务器传输方式,默认stdio;某些只接受 HTTP/SSE MCP 服务器的实现需设为http(并要求实现声明agentCapabilities.mcpCapabilities.http)。
  • askUserQuestions:把 ACP 实现的原生提问请求桥接为 HarnessAgent 的askUserQuestions内置工具(配置了它,工具集会自动注入该内置工具,见 acp-harness.ts)。
  • outputSchemaMapping:把结构化输出的 JSON Schema 映射到 ACP 会话 prompt_meta下的指定路径(当前仅session-prompt-meta类型)。
  • session.meta:附加到 ACP 会话请求_meta的静态元数据。
  • startupTimeoutMs:桥接启动超时,默认120_000毫秒(见 acp-v1-harness.ts)。
  • mintBridgeToken:自定义沙箱桥接鉴权令牌,默认随机生成 32 字节十六进制串。
  • env/forwardEnv:运行环境字面量 / 按名转发的环境变量;三个来源(forwardEnvcredentialEnvenv)之间的键不允许重叠,否则校验失败(见 implementation.ts)。

Skills 与指令落盘机制

Skills 默认写入 ACP 实现有效$HOME下的.agents/skills目录(常量DEFAULT_ACP_SKILLS_DIRECTORY,见 acp-v1-skills.ts),由实现原生发现。需要换目录时,通过skillsDirectory指定其他相对路径,例如 Claude Code 系的实现可设为.claude/skills。源码同时做了严格的路径与命名校验:

  • skill 名称必须为 kebab-case 小写 slug(^[a-z0-9]+(?:-[a-z0-9]+)*$),不允许./../ 重复名称;
  • 附带文件路径必须是相对 POSIX 路径,禁止绝对路径、反斜杠与..穿越,且SKILL.md保留给 skill 定义文件,不能被附带文件占用(见 acp-v1-skills.ts)。

此外,每个会话的桥接状态目录位于~/.ai-sdk/harness-acp/<harnessId>/<sessionId 的 sha256 哈希>(见resolveACPPrivateSessionDirectory),事件日志event-log.ndjson落在此目录,供崩溃恢复(disk-replay/lossy-rerun/cold-restore三种重放策略,见 acp-v1-harness.ts)使用。

生命周期与崩溃恢复

ACP 适配器实现了较完整的会话生命周期管理(源码在 acp-v1-lifecycle.ts 与 bridge/session-lifecycle.ts):

  • 冷启动createSession()后首次generate()发起session/new+session/start
  • 恢复(resume):通过continueFrom/resumeFrom携带生命周期状态,优先尝试直接重连既有 WebSocket 桥(带lastSeenEventId);
  • 进程丢失恢复:桥接失败时,根据event-log.ndjson是否完整可重放,选择disk-replay(基于磁盘事件日志回放)或lossy-rerun(带turnStartConfigacpSessionId重新跑一轮);冷会话则走cold-restore(见 acp-v1-harness.ts)。

生命周期状态本身也经过 zod schema 校验(acpResumeStateSchema,见 acp-harness.ts),其中包含实现身份(implementationIdentity)、认证画像(authenticationProfile)、桥接坐标(bridge)与恢复/还原标记等字段。恢复前还会校验生命周期兼容性(validateACPLifecycleCompatibility),确保实现身份与认证画像匹配后才允许续跑。

常见问题与使用边界

  • 必须暴露端口createVercelSandbox({ runtime: 'node24', ports: [4000] })ports不能省略;basic 沙箱会话则必须同时给portportEndpoint
  • 凭据配置成对出现credentialEnvcredentialBrokering要么都不配,要么一起配,否则启动即抛错。
  • Codex 仅支持allow-all:不要向 Codex 请求allow-reads/allow-edits,其受限模式会启用 Codex 内部沙箱。
  • modelMapping必填:且选型取决于具体实现(session-config-optionvssession-model);未配置模型时不会发送模型操作。
  • 环境变量键冲突:同一键不能同时出现在forwardEnvcredentialEnvenv中的任意两处。
  • 指令映射缺省行为:不配instructionMapping时,指令会前置拼接到首个用户 prompt(向后兼容)。
  • Node 版本:包要求 Node.js>=22(见 package.json)。

小结

@ai-sdk/harness-acp通过"沙箱内桥接 + 回环 WebSocket + 协议翻译"的架构,把任意 ACP v1 实现无缝接入 AI SDK 的HarnessAgent,并借助modelMappinginstructionMappingpermissionModeMappingcredentialBrokering等声明式映射,弥合了不同 Agent 实现之间的协议差异。本文涉及的实现细节均可在 packages/harness-acp/src 下对应源码中验证:入口与配置类型见 acp-harness.ts,v1 运行逻辑见 acp-v1-harness.ts,桥接子模块见 bridge 目录,测试用例见各*.test.ts文件(如 acp-harness.test.ts、acp-v1-lifecycle.test.ts)。如需接入新的 ACP 实现,参照上文示例替换sourceexecutablemodelMappingpermissionModeMapping即可。

【免费下载链接】aiThe AI Toolkit for TypeScript. From the creators of Next.js, the AI SDK is a free open-source library for building AI-powered applications and agents项目地址: https://gitcode.com/GitHub_Trending/ai/ai

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 11:56:53

地震声波正演中的MATLAB射线追踪:打靶法与弯曲法实现解析

简介&#xff1a;这套基于 MATLAB 的二维射线追踪与地震声波正演源码包&#xff0c;面向地球物理、地震勘探专业的初学者与研究者&#xff0c;用于模拟地震波在地层中的传播路径与接收信号。程序涵盖射线理论基础、几何扩散法、速度模型构建、源项与接收器设置、数值求解&#…

作者头像 李华
网站建设 2026/9/12 11:56:16

开始制作远程升级app模块

就是那种一发现版本升级了&#xff0c;然后就每次打开app提示升级的那种&#xff0c;否则就无法使用

作者头像 李华
网站建设 2026/9/12 11:56:12

基于MATLAB的带通采样DSB数字收发机设计与仿真实现

简介&#xff1a;面向电子科大通信工程课程设计&#xff0c;压缩包内容围绕基于带通采样结构的双边带调幅&#xff08;DSB&#xff09;数字收发机设计展开&#xff0c;整合仿真代码、实验报告与配套硬件工程。压缩包共55个文件&#xff0c;整体约1018KB&#xff0c;核心内容包括…

作者头像 李华
网站建设 2026/9/12 11:54:49

项目管理三重境界:从工具依赖到心法修炼

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/12 11:54:40

AddFilter存储过滤框架:C++策略编排与Windows minifilter实战

简介&#xff1a;AddFilter存储过滤工具是一款面向IT系统管理员与存储工程师的轻量级实用工具&#xff0c;聚焦于数据写入前的策略化过滤与存储优化&#xff0c;适用于中小规模存储环境下的数据压缩、加密预处理及I/O性能调优等典型场景。资源包为RAR格式&#xff0c;共16个文件…

作者头像 李华