
AI SDK OpenCode Harness 实战通过沙箱桥接把 OpenCode 接入 HarnessAgent【免费下载链接】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本指南基于当前仓库中packages/harness-opencode/README.md展开系统讲解 AI SDK 的 OpenCode Harness 适配器它如何通过沙箱内的桥接进程把HarnessAgent与 OpenCode 连接起来如何使用openCodeConfig透传原生 OpenCode 配置、如何处理适配器托管设置与用户配置的优先级关系以及认证、沙箱、内置工具、MCP 与结构化输出等完整实操。读完本文你将掌握用createOpenCode()创建可运行、可配置、可恢复的 OpenCode Harness 会话的完整方案并能对照源码理解其底层工作方式。一、OpenCode Harness 是什么OpenCode Harness 是 AI SDK Harness 体系中的一个适配器adapter核心作用是把HarnessAgent连接到 OpenCode并且通过一个运行在沙箱内部的桥接bridge来完成连接。从packages/harness-opencode/README.md的定位描述来看The OpenCode harness connectsHarnessAgentto OpenCode through a sandboxed bridge.结合content/providers/02-ai-sdk-harnesses/04-opencode.mdx的架构说明可以进一步确认整体工作方式适配器在沙箱内部启动一个桥接进程bridge桥接进程在沙箱中拉起一个 OpenCode serverOpenCode 的会话事件通过沙箱暴露的 WebSocket 流式回传宿主机。换句话说OpenCode 的完整执行环境模型调用、文件读写、shell 命令、工具执行都发生在沙箱中宿主进程只负责通过 WebSocket 与桥接层通信从而获得隔离性与可控性。该包当前版本为1.0.109见packages/harness-opencode/package.json依赖ai-sdk/harness、ai-sdk/provider-utils与wspeer 依赖zod要求 Node.js22采用 ESM 模块格式。需要说明的是Harness 相关包在 AI SDK 中仍属实验特性接口可能随版本演进发生变化。二、安装与导入安装以下三个包即可开始使用参考官方文档中的 Setup 与 Import 小节pnpm add ai-sdk/harness ai-sdk/harness-opencode ai-sdk/sandbox-vercel导入方式import { openCode, createOpenCode } from ai-sdk/harness-opencode;其中openCode是一个使用默认配置创建好的开箱即用实例。从packages/harness-opencode/src/index.ts可以看到它的定义与文档说明完全一致export const openCode createOpenCode();ai-sdk/harness-opencode对外导出openCode默认实例等价于createOpenCode()createOpenCode工厂函数用于传入自定义设置VERSION当前包版本号类型OpenCodeHarnessSettings、OpenCodeAuthenticationMode。首次创建会话时适配器会在沙箱内引导bootstrap桥接所需的依赖。根据packages/harness-opencode/src/opencode-bootstrap.ts它会向沙箱写入package.json、pnpm-lock.yaml、pnpm-workspace.yaml、bridge.mjs与host-tool-mcp.mjs并依次执行pnpm install --frozen-lockfile --store-dir .pnpm-store ./node_modules/.bin/opencode --version桥接依赖opencode-ai/sdk与opencode-ai见packages/harness-opencode/src/bridge/package.json因此首次启动会有一次依赖安装过程。三、基本用法一个可运行的 HarnessAgent 示例下面的示例来自官方文档的 Basic Usage把 OpenCode Harness 接入HarnessAgent并使用 Vercel Sandbox 作为网络沙箱import { HarnessAgent } from ai-sdk/harness/agent; import { openCode } from ai-sdk/harness-opencode; import { createVercelSandbox } from ai-sdk/sandbox-vercel; const agent new HarnessAgent({ harness: openCode, model: anthropic/claude-sonnet-4-6, sandbox: createVercelSandbox({ runtime: node24, ports: [4000], }), }); const session await agent.createSession(); let exitCode 0; try { const result await agent.stream({ session, prompt: Check the test failures and fix the production code., }); for await (const part of result.stream) { if (part.type text-delta) { process.stdout.write(part.text); } } } catch (err) { exitCode 1; console.error(err); } finally { await session.destroy(); process.exit(exitCode); }运行前提宿主机环境需要VERCEL_OIDC_TOKEN用于 Vercel Sandbox 的认证同时需要配置 OpenCode 侧可用的认证凭据见下文“认证”小节ANTHROPIC_API_KEY、OPENAI_API_KEY、AI_GATEWAY_API_KEY等均可。仓库中的示例工程examples/ai-functions/src/harness-agent/opencode/with-model.ts展示了同等的精简用法在HarnessAgent上指定model: anthropic/claude-haiku-4-5用agent.generate()发起单轮请求最后session.destroy()清理会话。3.1 使用预创建的沙箱会话如果想自己管理沙箱生命周期可以参考examples/ai-functions/src/harness-agent/opencode/with-provided-sandbox.ts的模式先通过vercel/sandbox创建沙箱再用createVercelSandbox({ sandbox })包一层 provider最后把sandboxSession传给agent.createSession({ sandboxSession })结束时自行调用sandbox.stop()。四、适配器设置详解createOpenCode 配置项createOpenCode(settings)接受一个OpenCodeHarnessSettings对象。其完整字段定义在packages/harness-opencode/src/opencode-harness.ts的OpenCodeHarnessSettings类型中整理如下配置项类型作用authOpenCodeAuthenticationMode认证模式auto/anthropic/openai/ai-gateway或一个隔离的认证环境对象credentialForwardingHarnessV1CredentialForwarding可选同步/异步回调在凭据转发进沙箱进程前对每个凭据值做定制。注意它只控制转发进沙箱的值不限制适配器在宿主机进程中发现、读取或访问哪些凭据openCodeConfigRecordstring, unknown透传给 OpenCode 的原生配置键名必须使用 OpenCode 原生名称适配器托管的同名设置优先mcpServersRecordstring, unknown以服务器名为键的 MCP server 定义使用底层运行时原生 MCP 配置格式providerstring当HarnessAgent上的model没有 provider 前缀时用它指定 provider idreasoningVariantstring面向支持推理的模型指定 OpenCode 的思考变体例如low、medium、highportnumber覆盖桥接 WebSocket 使用的端口portEndpointHarnessV1PortEndpoint覆盖连接沙箱桥接的宿主机端端点使用基础沙箱会话basic sandbox session时必须与port一起提供startupTimeoutMsnumber等待桥接启动的超时时间默认 120 秒mintBridgeTokenHarnessV1MintBridgeTokenCallback生成沙箱桥接认证 token 的回调接收 sandbox id默认生成随机 32 字节十六进制 token。自定义实现必须返回足够机密的 token一个典型的组合配置官方文档示例import { createOpenCode } from ai-sdk/harness-opencode; const harness createOpenCode({ reasoningVariant: high, openCodeConfig: { agent: { general: { model: openai/gpt-5.4-mini, }, }, }, });仓库中的examples/ai-functions/src/harness-agent/opencode/with-reasoning.ts演示了reasoningVariant: high的实际效果要求模型“分步求解并证明”数学题并断言流式结果中必须出现非空的 reasoning 文本。从源码看reasoningVariant最终通过桥接协议中的variant字段下发packages/harness-opencode/src/opencode-harness.ts中startBase的...(reasoningVariant ? { variant: reasoningVariant } : {})桥接侧再把它作为 OpenCode prompt 的variant参数传入见packages/harness-opencode/src/bridge/index.ts的legacySessionPrompt。五、openCodeConfig原生 OpenCode 配置透传与优先级openCodeConfig是本文档的核心知识点。它的设计目的是对于 OpenCode 尚未提供专门适配项的原生设置可以直接透传。README 中的示例是为单个 agent 选择模型import { createOpenCode } from ai-sdk/harness-opencode; const adapter createOpenCode({ openCodeConfig: { agent: { general: { model: provider/model-id, }, }, }, });5.1 适配器托管设置优先README 明确指出两条优先级规则适配器托管的设置优先当openCodeConfig中出现了与适配器托管项同名的键时以适配器托管值为准。忽略 agent 局部的permission与已废弃的tools设置这是安全设计防止用户在配置层面绕过 harness 的权限系统或内置工具过滤。这两条规则在桥接源码中有非常具体的实现。在packages/harness-opencode/src/bridge/index.ts的buildOpenCodeConfig中适配器会先展开用户配置再强制写入自己托管的配置const config: Recordstring, unknown { ...withoutAgentPolicyOverrides(start.openCodeConfig), share: disabled, autoupdate: false, permission: { read: allow, glob: allow, grep: allow, list: allow, edit: ask, bash: ask, external_directory: ask, webfetch: ask, doom_loop: ask, task: ask, question: allow, }, };也就是说share、autoupdate以及整套permission映射都由适配器强制托管无论用户在openCodeConfig里写了什么都无法覆盖。而withoutAgentPolicyOverrides则遍历agent与mode两个配置段逐层删除每个 agent 对象上的permission与tools字段function withoutAgentPolicyOverrides(input) { const config { ...input }; for (const key of [agent, mode] as const) { const agents asOpenCodeObject(config[key]); if (!agents) continue; config[key] Object.fromEntries( Object.entries(agents).map(([name, value]) { const agent asOpenCodeObject(value); if (!agent) return [name, value]; const safeAgent { ...agent }; delete safeAgent.permission; delete safeAgent.tools; return [name, safeAgent]; }), ); } return config; }这正好印证了 README 中“Agent-localpermissionand deprecatedtoolssettings are ignored so they cannot bypass harness permissions or built-in tool filtering”的描述配置中的agent.name.permission与agent.name.tools会被静默剥离保留其余设置如model。因此在openCodeConfig中设置agent.general.model这类非策略字段是安全的而尝试通过它修改权限或工具列表是无效的。5.2 适配器还会自动追加的配置除了用户配置适配器在buildOpenCodeConfig中还会根据会话参数自动追加model当本次 turn 指定了模型时写入config.modelskills当存在 skills 目录时写入config.skills { paths: [skillsDir] }provider根据认证环境构建 provider 配置anthropic/openai/ AI Gateway / OpenAI 兼容端点mcp合并用户传入的mcpServers并注入名为harness-tools的本地 MCP server见下文。六、认证auth 模式与支持的环境变量auth设置决定凭据如何从宿主机环境解析。官方文档给出四种模式auto默认优先使用 AI Gateway 凭据其次使用所选模型 provider 的凭据anthropic仅使用 Anthropic 凭据openai仅使用 OpenAI 凭据ai-gateway仅使用 AI Gateway 凭据。显式指定模式const anthropicHarness createOpenCode({ auth: anthropic }); const openAIHarness createOpenCode({ auth: openai }); const gatewayHarness createOpenCode({ auth: ai-gateway });也可以传入一个认证环境对象使用编程方式解析出的凭据而不读取process.envconst harness createOpenCode({ auth: { OPENAI_API_KEY: await resolveOpenAIToken() }, provider: openai, });注意传入的环境记录会替换宿主环境用于认证发现且只有被认可的认证变量才会被转发。支持的认证环境变量见packages/harness-opencode/src/opencode-auth.ts与官方文档AI_GATEWAY_API_KEY、AI_GATEWAY_BASE_URLVERCEL_OIDC_TOKENANTHROPIC_API_KEY、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_BASE_URLOPENAI_API_KEY、OPENAI_BASE_URL、OPENAI_ORGANIZATION、OPENAI_PROJECT6.1 凭据代理credential brokering从packages/harness-opencode/src/opencode-auth.ts可以看到适配器声明的凭据环境变量集合为export const OPENCODE_CREDENTIAL_ENVIRONMENT_VARIABLES [ AI_GATEWAY_API_KEY, OPENAI_API_KEY, ANTHROPIC_API_KEY, ANTHROPIC_AUTH_TOKEN, ] as const;当沙箱支持“附加请求变换”additive request transformations时桥接进程内只放置占位符凭据由宿主机通过createOpenCodeRequestTransformations注入与出站请求匹配的真实凭据例如把 OpenAI 请求中的Authorization: Bearer 占位替换为宿主机真实 key。这是比直接转发凭据更安全的模式不支持该能力的沙箱则退化为直接转发凭据并通过warnCredentialBrokeringUnavailable输出警告。对应实现位于packages/harness-opencode/src/opencode-harness.ts的doStart流程中。七、沙箱要求OpenCode Harness必须使用带网络能力的沙箱且至少暴露一个 TCP 端口因为桥接 WebSocket 需要监听端口。官方推荐ai-sdk/sandbox-vercelimport { createVercelSandbox } from ai-sdk/sandbox-vercel; const sandbox createVercelSandbox({ runtime: node24, ports: [4000], });从源码看端口解析逻辑resolveBridgePort是如果显式传了settings.port则优先使用否则使用沙箱暴露的第一个端口如果都没有会抛出HarnessCapabilityUnsupportedError提示“Create the sandbox withports: [port]or passcreateOpenCode({ port })”。使用基础沙箱会话不带getPortEndpoint能力时validateBasicSandboxSettings会强制要求同时提供port与portEndpoint否则报错。另外mintBridgeToken只对带 id 的沙箱会话可用。八、内置工具映射与 HarnessAgent 工具适配器通过HarnessAgent的agent.tools暴露一组通用化的 OpenCode 内置工具。官方文档列出的有read、write、edit、bash、glob、grep、ls、webfetch、skill、todowrite、agent。从packages/harness-opencode/src/opencode-harness.ts的OPENCODE_BUILTIN_TOOLS定义可以看到工具映射的底层细节工具名、原生名与用途分类Harness 工具名OpenCode 原生名用途分类askUserQuestionsquestionreadonlyreadviewreadonlywritewriteediteditediteditbashbashbashglobglobreadonlygrepgrepreadonlylslist通用工具webfetchwebfetch通用工具skillskill通用工具todowritetodowrite通用工具agenttask/agent/subtask通用工具注意内置read工具在 schema 层面同时兼容file_path与path两种参数名z.looseObject宽松解析write/edit同理这降低了跨工具形态调用的摩擦。在桥接侧packages/harness-opencode/src/bridge/index.ts事件转换层通过PUBLIC_TO_NATIVE、NATIVE_TO_COMMON、OPENCODE_TO_WIRE三张映射表完成工具名的双向翻译例如宿主的read对应 OpenCode 的viewOpenCode 的question对应宿主的askUserQuestions。8.1 工具审批approvalOpenCode 原生支持内置工具审批请求。官方文档说明当permissionMode为allow-reads或allow-edits时OpenCode 内置工具会发起审批同时宿主机执行的 AI SDK 工具审批也正常工作。适配器声明supportsBuiltinToolApprovals: true并在桥接协议中定义了tool-approval-request与tool-approval-response消息见packages/harness-opencode/src/opencode-harness.ts的wireTurn转发的事件类型列表。参考示例examples/ai-functions/src/harness-agent/opencode/custom-tool-approval.ts在HarnessAgent上配置toolApproval: { weather: user-approval }首次agent.stream()会收到ToolApprovalRequestOutput再用createToolApprovalResponseMessages构造批准消息继续第二轮流式调用。8.2 自定义工具与 harness-tools 保留名用户传给HarnessAgent的自定义工具会通过“工具中继”tool relay注入沙箱桥接在沙箱内启动一个本地 MCP serverharness-tools其命令为node ${bootstrapDir}/host-tool-mcp.mjs环境变量携带TOOL_SCHEMASJSON 序列化的工具 schema 列表与TOOL_RELAY_URL指向本地中继服务从而让 OpenCode 可以通过 MCP 调用宿主侧执行的自定义工具。正因如此harness-tools是保留的 MCP 服务器名。在createOpenCode的入口处有显式校验如果用户在mcpServers中传入名为harness-tools的服务器会直接抛出错误throw new Error( OpenCode MCP server name harness-tools is reserved for HarnessAgent tools., );给用户自定义 MCP server 命名时务必避开这个名字。8.3 配置外部 MCP 服务器通过mcpServers可以给沙箱内的 OpenCode 配置额外的 MCP 服务器例如examples/ai-functions/src/harness-agent/opencode/with-mcp.ts中挂载远程 Context7 MCPconst agent new HarnessAgent({ harness: createOpenCode({ mcpServers: { context7: { type: remote, url: https://mcp.context7.com/mcp, enabled: true, oauth: false, }, }, }), sandbox: createVercelSandbox({ runtime: node24, ports: [4000], timeout: 10 * 60 * 1000, }), });桥接侧会把mcpServers原样合并进 OpenCode 配置的mcp字段并在ensureRuntime中查询 MCP 状态把已连接的服务器名注册为工具前缀用于后续工具调用的路由与过滤。九、结构化输出、推理变体与多轮会话9.1 结构化输出OpenCode 支持基于 JSON Schema 的HarnessAgent结构化输出。适配器使用 OpenCode 的json_schemaprompt format并把校验后的structured结果以 JSON 文本形式返回。从桥接代码看当responseFormat.type json时prompt 会带上format: { type: json_schema, schema }事件流中若消息携带info.structured字段桥接会把它包装为text-start/text-delta/text-end/finish-step事件流式发出。注意两个限制结构化输出必须提供 schema在packages/harness-opencode/src/opencode-harness.ts的prepareTurn中如果responseFormat.type json但schema null会抛出HarnessCapabilityUnsupportedError提示“Harness opencode requires a JSON schema for structured output”用户消息仅支持文本类型extractUserText遇到非文本 part 会抛出“The OpenCode harness does not yet support user message parts of type ...”。9.2 推理变体reasoningVariant用于为支持推理的模型指定思考强度取值如low、medium、high或其他模型支持的 OpenCode 变体。仓库测试packages/harness-opencode/src/opencode-harness.test.ts覆盖了不同变体下发的情况如createOpenCode({ reasoningVariant: high })可据此验证该配置的行为。9.3 多轮、模型切换与会话恢复OpenCode 会话天然支持多轮上下文保持。示例examples/ai-functions/src/harness-agent/opencode/changing-settings.ts展示了同一会话内切换模型、切换指令与技能的完整流程通过prepareCall按轮次改写model、instructions、skills与tools并断言第二轮仍然记得第一轮的用户名字验证上下文连续性。适配器通过openCodeResumeStateSchema定义生命周期状态包含openCodeSessionId、桥接坐标bridge与沙箱凭据环境支持会话的暂停、恢复与续跑。从源码看doStop/doDetach/doSuspendTurn都会返回resume-session或continue-turn状态其中携带openCodeSessionId、桥接端口、token 与lastSeenEventId下次启动时若检测到resumeFrom/continueFrom会先尝试直接 attach 到既有桥接coords分支失败后再以rerun或replay策略重新拉起桥接并回放事件日志bridge-state-dir下的event-log.ndjson。9.4 压缩compaction适配器支持原生手动压缩会话。doCompact通过桥接发送operation: compact的 start 消息桥接侧调用 OpenCode 的session.summarize。注意两个限制OpenCode 不支持自定义压缩指令传入customInstructions会报错且不支持在活跃 turn 进行中压缩。十、源码级原理从启动到事件流为了加深理解这里把关键调用链串起来依据packages/harness-opencode/src/opencode-harness.ts与packages/harness-opencode/src/bridge/index.tscreateOpenCode(settings)返回一个harness-v1规格的 Harness 对象harnessId为opencode内置工具集、生命周期 schema 与 bootstrap 提供器一并注册。doStart阶段解析默认工作目录与沙箱 home 目录 → 解析认证模式与环境 → 若沙箱支持创建凭据环境并注册请求变换 → 确定bootstrapDirworkdir/.harness-bootstrap/opencode、session 数据目录workdir/.agent-runs/sessionId与 skills 目录~/.agents/skills→ 解析桥接端口并生成桥接 token →markBridgeStarting写就绪标记 → 在沙箱内 spawnnode bootstrapDir/bridge.mjs \ --workdir workdir \ --bridge-state-dir bridge-state-dir \ --bootstrap-dir bootstrapDir \ --skills-dir skillsDir环境变量包含AI_SDK_HARNESS_CLIENT_APP值为ai-sdk/harness-opencode/version、BRIDGE_CHANNEL_TOKEN与BRIDGE_WS_PORTreplay 场景还会设置BRIDGE_REPLAY_FROM_DISK1。waitForBridgeReady等待桥接就绪并返回实际绑定端口openWebSocket建立 WebSocket 连接等待bridge-hello消息带helloTimeoutMs超时最短取min(startupTimeoutMs, 5000)并从中探测capabilities.experimental_userMessageResponses以决定是否启用实验性的用户消息响应通道。桥接进程内bridge/index.tsrunBridge注册onStart→ensureRuntime启动工具中继与 OpenCode servercreateOpencodeServer监听127.0.0.1:0→ensureSession复用或创建 OpenCode 会话 →switchSessionModel切换模型 →legacySessionPrompt提交 prompt携带system指令、variant、json_schemaformat→consumeEvents订阅 OpenCode 事件流并通过createEmitStreamEvent把 OpenCode 事件翻译成 Harness 流事件text-delta、reasoning-delta、tool-call、tool-approval-request、finish-step、file-change、compaction等→ 结束后汇总 usage通过会话 token 差值计算。宿主侧wireTurn把这些事件原样转发给调用方同时提供submitToolResult、submitToolApproval、可选submitUserMessage控制原语。桥接消息协议在packages/harness-opencode/src/opencode-bridge-protocol.ts中定义start消息扩展了operation: prompt | compact、provider、variant、instructions、skillsChanged、resumeSessionId、openCodeConfig、mcpServers、headers等字段出站消息复用harnessV1BridgeOutboundMessageSchema。十一、测试验证该包自带较完整的 vitest 测试pnpm test配置见packages/harness-opencode/vitest.node.config.js主要覆盖packages/harness-opencode/src/opencode-harness.test.tscreateOpenCode适配器行为如 harness id、内置工具声明、reasoningVariant下发、端口/凭据相关校验等测试用 Fake WebSocket 与 MockSandboxChannel 模拟桥接可直观看到宿主侧发出的start消息内容packages/harness-opencode/src/bridge/opencode-events.test.ts、packages/harness-opencode/src/bridge/tool-relay.test.ts、packages/harness-opencode/src/bridge/opencode-server-auth.test.ts等桥接侧事件翻译、工具中继、服务端认证等内部逻辑。如果你要改动或调试这个适配器建议以这些测试为行为基线运行验证。十二、进一步阅读官方使用文档content/providers/02-ai-sdk-harnesses/04-opencode.mdx适配器入口与设置类型packages/harness-opencode/src/opencode-harness.ts认证与凭据代理packages/harness-opencode/src/opencode-auth.ts沙箱内引导与依赖安装packages/harness-opencode/src/opencode-bootstrap.ts桥接进程实现packages/harness-opencode/src/bridge/index.ts桥接消息协议packages/harness-opencode/src/opencode-bridge-protocol.ts完整可运行示例examples/ai-functions/src/harness-agent/opencode/目录with-model.ts、with-reasoning.ts、with-mcp.ts、changing-settings.ts、custom-tool-approval.ts、with-provided-sandbox.ts等端到端示例页面examples/harness-e2e-next/app/harness/opencode/与examples/harness-e2e-tui/agents/opencode/总结OpenCode Harness 把 OpenCode 的编码智能与 AI SDK 的HarnessAgent编排能力结合在一起通过“沙箱内桥接 WebSocket 事件流”的架构保证了执行隔离与可观测性。使用时的三个关键点值得牢记一是openCodeConfig只适合透传非策略类原生配置如agent.general.modelpermission与tools会被安全剥离二是适配器托管项share、autoupdate、permission、mcp中的harness-tools永远优先三是沙箱必须暴露 TCP 端口并配置好对应 provider 的认证凭据。在此基础上你便可以组合reasoningVariant、mcpServers、结构化输出与多轮恢复能力构建出功能完整、行为可预期的编码型 AI Agent。【免费下载链接】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),仅供参考