快速开始

Copilot SDK harness

外部 @openclaw/copilot 插件通过 GitHub Copilot CLI(@github/copilot-sdk)运行嵌入式订阅 Copilot 智能体轮次,而不是使用 OpenClaw 的内置 harness。Copilot CLI 会话负责底层智能体循环:原生工具执行、原生压缩(infiniteSessions),以及 copilotHome 下由 CLI 管理的线程状态。OpenClaw 仍负责聊天渠道、会话文件、模型选择、动态工具(通过桥接)、审批、媒体交付、可见的转录镜像、/btw 旁支问题(参见 旁支问题(/btw)以及 openclaw doctor

有关更广泛的模型/提供商/运行时划分,请先阅读 Agent Runtimes

要求

  • 已安装 @openclaw/copilot 插件的 OpenClaw。
  • 如果你的配置使用 plugins.allow,请包含 copilot(插件声明的清单 ID)。npm 软件包名称 @openclaw/copilot 的允许列表条目无法匹配,即使已设置 agentRuntime.id: "copilot",插件仍会被阻止。
  • 能够驱动 Copilot CLI 的 GitHub Copilot 订阅,或用于无头运行或定时任务的 gitHubToken 环境变量/身份验证配置文件条目。
  • 可写的 copilotHome 目录。当 OpenClaw 提供 Agent 目录时,默认为 <agentDir>/copilot;否则默认为 ~/.openclaw/agents/<agentId>/copilot

openclaw doctor 会针对会话状态所有权和未来配置迁移运行插件的 Doctor 合约。它不会探测 Copilot CLI 环境。

安装

Copilot 运行时以外部插件形式提供,因此核心 openclaw 软件包不会携带 @github/copilot-sdk 或其特定于平台的 @github/copilot-<platform>-<arch> CLI 二进制文件(两者合计约 260 MB)。 仅为选择使用此运行时的智能体安装它:

bash
openclaw plugins install @openclaw/copilot

首次选择 github-copilot/* 模型,并且你的配置通过 agentRuntime: { id: "copilot" } 将该模型(或其提供商)路由到 Copilot 运行时时,设置向导会自动安装该插件;参见 快速开始。如果未选择使用,OpenClaw 会使用其内置的 GitHub Copilot 提供商,并且绝不会安装此插件。

运行时按以下顺序解析 SDK:

  1. 来自已安装 @openclaw/copilot 软件包的 import("@github/copilot-sdk")
  2. 回退目录 ~/.openclaw/npm-runtime/copilot/(旧版按需安装目标)。

缺少 SDK 时,会显示一个代码为 COPILOT_SDK_MISSING 的错误以及上述重新安装命令。

快速开始

将一个模型(或一个提供商)固定到 harness:

json5
{  agents: {    defaults: {      model: "github-copilot/auto",      models: {        "github-copilot/auto": {          agentRuntime: { id: "copilot" },        },      },    },  },}

在单个模型条目上设置 agentRuntime.id,可仅通过 harness 路由该模型;在提供商上设置,则会路由该提供商下的所有模型。

github-copilot/auto 是可移植的起点。具名 Copilot 模型取决于账户和组织策略;固定模型前,请确认已通过身份验证的 Copilot CLI 确实公开了该模型。

支持的提供商

该 harness 支持规范的 github-copilot 提供商(由 extensions/github-copilot 所有),还支持自定义 models.providers 条目,前提是模型具有非空的 baseUrl,并采用以下 api 形式之一:

  • anthropic-messages
  • azure-openai-responses
  • ollama(兼容 OpenAI 的 completions)
  • openai-completions
  • openai-responses

原生提供商 ID(openaianthropicgoogleollama)仍由各自的原生运行时所有。若要改为通过 Copilot BYOK 路由某个端点,请使用不同的自定义提供商 ID。

Copilot BYOK 端点必须是公共 HTTPS URL。该 harness 会为每次尝试向 Copilot SDK 提供一个环回代理,然后通过 OpenClaw 受保护的 fetch 路径转发提供商流量,使 DNS 固定和 SSRF 策略仍由 OpenClaw 负责。对于本地 Ollama、LM Studio 或局域网模型服务器,请使用原生 OpenClaw 运行时。

BYOK

Copilot BYOK 使用 SDK 的会话级自定义提供商合约。OpenClaw 会传递解析后的模型端点、API 密钥、Bearer 令牌模式、请求头、模型 ID,以及上下文/输出限制;提供商传输逻辑保留在 SDK 中,而不是核心中。

json5
{  agents: {    defaults: {      model: "custom-proxy/llama-3.1-8b",      models: {        "custom-proxy/llama-3.1-8b": {          agentRuntime: { id: "copilot" },        },      },    },  },  models: {    mode: "merge",    providers: {      "custom-proxy": {        baseUrl: "https://api.example.com/v1",        apiKey: "${CUSTOM_PROXY_API_KEY}",        api: "openai-responses",        authHeader: true,        models: [{ id: "llama-3.1-8b", name: "Llama 3.1 8B" }],      },    },  },}

BYOK 会话与订阅会话、其他 BYOK 端点或凭据分别使用不同的键。轮换密钥、请求头、模型或端点时,会启动全新的 Copilot SDK 会话,而不是恢复不兼容的状态。

身份验证

runCopilotAttempt 期间按智能体应用以下优先级:

  1. 尝试输入中显式的 useLoggedInUser: true —— 使用智能体的 copilotHome 下 Copilot CLI 已登录的用户。

  2. 尝试输入中显式的 gitHubToken(需要 profileId + profileVersion)。供需要绕过身份验证配置文件解析的直接 CLI 调用和测试使用。

  3. 合约解析的 resolvedApiKey + authProfileId —— 生产环境主路径。核心会先解析智能体配置的 github-copilot 身份验证配置文件(src/infra/provider-usage.auth.ts:resolveProviderAuths),然后再调用 harness,因此 github-copilot:<profile> 身份验证配置文件可在无头运行、定时任务或多配置文件设置中实现端到端工作,而无需环境变量。

  4. 环境变量回退,按以下顺序检查(首个非空值生效,空字符串视为不存在;与 extensions/github-copilot/auth.ts 中已发布的 github-copilot 提供商优先级一致):

    1. OPENCLAW_GITHUB_TOKEN —— harness 专用覆盖项;允许你为 OpenClaw harness 固定令牌,而不影响系统级 gh / Copilot CLI 配置。
    2. COPILOT_GITHUB_TOKEN —— 标准 Copilot SDK / CLI 环境变量。
    3. GH_TOKEN —— 标准 gh CLI 环境变量。
    4. GITHUB_TOKEN —— 通用 GitHub 令牌回退项。

    合成的池配置文件 ID 为 env:&lt;NAME&gt;;配置文件版本是令牌的不可逆 sha256 指纹,因此轮换环境变量值会干净地使客户端池失效。

  5. 没有可用令牌信号时,默认使用 useLoggedInUser

每个智能体都有自己的 copilotHome,因此同一台机器上的不同智能体之间绝不会泄漏 Copilot CLI 令牌、会话和配置。默认值: <agentDir>/copilot(将 SDK 状态与 OpenClaw 的 models.json / auth-profiles.json 保存在不同目录中);未提供 Agent 目录时则为 ~/.openclaw/agents/<agentId>/copilot。 若要使用自定义位置(例如用于迁移的共享挂载点),请在尝试输入中使用 copilotHome: <path> 覆盖。

实时 harness 测试使用 OPENCLAW_COPILOT_AGENT_LIVE_TOKEN 传递直接令牌。在将真实身份验证配置文件暂存到隔离的测试主目录后,共享实时测试设置会清除 COPILOT_GITHUB_TOKENGH_TOKENGITHUB_TOKEN,因此通过专用变量传递 gh auth token 值可以避免误跳过,同时不会泄漏到无关的测试套件。

配置表面

该 harness 从每次尝试的输入(runCopilotAttempt({...}))以及 extensions/copilot/src/ 内的一小组环境默认值读取配置:

字段 用途
copilotHome 每个智能体的 CLI 状态目录(默认值见上文)。
model 字符串或 { provider, id, api?, baseUrl?, headers?, authHeader? }。省略则使用智能体的正常模型选择;harness 会验证解析出的提供商是否受支持。
reasoningEffort "low" | "medium" | "high" | "xhigh"。映射自 auto-reply/thinking.ts 中 OpenClaw 的 ThinkLevel / ReasoningLevel 解析。
infiniteSessionConfig harness.compact 驱动的 SDK infiniteSessions 块的可选覆盖项。保持原样即可。
hooksConfig 用于工具/MCP、用户提示、会话和错误回调的可选原生 Copilot SDK SessionHooks 配置。与 OpenClaw 的可移植生命周期钩子相互独立。
permissionPolicy SDK 的 onPermissionRequest 处理程序的可选覆盖项,适用于内置 SDK 工具类型(shellwritereadurlmcpmemoryhook)。默认为 rejectAllPolicy,作为安全保障;关于它为何实际上永远不会触发,请参见权限和 ask_user
enableSessionTelemetry 可选的 SDK 会话遥测标志。

OpenClaw 插件钩子无需任何 Copilot 专用的尝试配置。该 harness 通过标准 harness 辅助程序运行 before_prompt_buildllm_inputllm_outputagent_end。SDK 成功完成压缩时还会运行 before_compactionafter_compaction。桥接的 OpenClaw 工具会运行 before_tool_call 并报告 after_tool_callhooksConfig 保留用于没有可移植对应项的原生 SDK 专用回调。

OpenClaw 中的其他部分均无需了解这些字段。其他插件、渠道和核心代码只会看到标准的 AgentHarnessAttemptParams / AgentHarnessAttemptResult 形式。

压缩

运行 harness.compact 时,Copilot SDK harness 会:

  1. 恢复跟踪的 SDK 会话,但不继续执行待处理工作。
  2. 调用 SDK 的会话范围历史记录压缩 RPC。
  3. 返回 SDK 压缩结果,不在工作区下写入兼容性标记文件。

OpenClaw 侧的转录镜像(见下文)会继续接收压缩后的消息,因此面向用户的聊天历史记录保持一致。

转录镜像

runCopilotAttempt 将每个轮次中可镜像的消息双写入 OpenClaw 审计记录,具体通过 extensions/copilot/src/dual-write-transcripts.ts 实现。镜像按 会话(copilot:${sessionId})划分作用域,并按消息 (${role}:${sha256_16(role,content)})设定键,因此重新发出的先前轮次条目 会与磁盘上的现有键冲突,而不会产生重复项。

镜像外包裹了两层故障遏制,因此记录写入 失败绝不会导致尝试失败:一层内部尽力而为包装器,外加 尝试级别的纵深防御 .catch(...)。失败会被记录到日志,而不会 向上层暴露。

旁支问题(/btw

/btw 在此 harness 上不是原生功能。createCopilotAgentHarness() 有意将 harness.runSideQuestion 保持为未定义 (在 extensions/copilot/harness.test.tsdescribe("runSideQuestion") 中有断言), 因此 OpenClaw 的 /btw 分派器(src/agents/btw.ts)会回退到 所有非 Codex 运行时所使用的相同路径:直接调用已配置的模型提供商, 传入简短的旁支问题提示,并通过 streamSimple 流式返回(无 CLI 会话,不额外占用池槽位)。

这会将 Copilot CLI 会话保留给智能体的主轮次循环,并使 /btw 的行为与其他非 Codex 运行时完全一致。

Doctor

extensions/copilot/doctor-contract-api.tssrc/plugins/doctor-contract-registry.ts 自动加载。它提供:

  • 一个空的 legacyConfigRules(目前尚无已弃用字段)。
  • 一个无操作的 normalizeCompatibilityConfig(保留此项,以便未来弃用字段时 在源码树中拥有稳定的归属位置)。
  • 一个 sessionRouteStateOwners 条目:提供商 github-copilot、运行时 copilot、CLI 会话键 copilot、身份验证配置文件前缀 github-copilot:

限制

  • 该 harness 声明支持 github-copilot,以及无所有者的自定义 BYOK 提供商 ID。 清单所有者所拥有的原生提供商 ID 会继续使用其所属运行时,即使 agentRuntime.id 被强制设为 copilot
  • 没有 TUI 界面;对于没有同类界面的运行时,PI 的 TUI 仍作为后备。
  • 当智能体切换到 copilot 时,PI 会话状态不会迁移。 每次尝试单独选择;现有 PI 会话仍然有效。
  • ask_user 使用提供商中立的 Gateway 网关问题运行时。Control UI 显示与其他 OpenClaw 问题相同的问题卡片,受支持的 渠道会呈现选择按钮,而下一条排队的纯文本消息会先解析 该 Gateway 网关记录,然后 SDK 请求才会返回。

权限和 ask_user

桥接的 OpenClaw 工具的权限执行发生在工具 包装器内部,而非通过 SDK 的 onPermissionRequest 回调。PI 使用的同一 wrapToolWithBeforeToolCallHooksrc/agents/agent-tools.before-tool-call.ts)会由 createOpenClawCodingTools 应用于每个编码工具:循环检测、受信任 插件策略、工具调用前钩子,以及通过 Gateway 网关(plugin.approval.request)进行的两阶段插件审批,全都沿用与原生 PI 尝试 完全相同的代码路径。

Copilot 工具桥返回的每个 SDK 工具都带有:

  • overridesBuiltInTool: true — 替换 Copilot CLI 中 同名的内置工具(edit、read、write、bash 等),使每次工具调用都路由回 OpenClaw。
  • skipPermission: true — 告知 SDK 在调用工具前不要触发 onPermissionRequest({kind: "custom-tool"})。 已包装的 execute() 已执行功能更丰富的 OpenClaw 策略检查; SDK 级提示要么会绕过 OpenClaw 的执行机制 (全部允许),要么会阻止所有工具调用(全部拒绝)——两者都不符合 PI 的对等行为。

源码树内的 Codex harness 使用相同的职责划分:桥接的 OpenClaw 工具会被 包装(extensions/codex/src/app-server/dynamic-tools.ts),而 codex-app-server 自身的原生审批类型 (item/commandExecution/requestApprovalitem/fileChange/requestApprovalitem/permissions/requestApproval)通过 plugin.approval.requestextensions/codex/src/app-server/approval-bridge.ts)路由。Copilot SDK 中的对应机制——对任何到达 onPermissionRequest 的非 custom-tool 类型 执行故障时关闭的 rejectAllPolicy——是同样的安全网,并且 实际中从不会触发,因为 overridesBuiltInTool: true 会替换所有 内置工具。

为了让已包装工具层做出与 PI 等效的策略决策, harness 会将完整的 PI 尝试工具上下文转发给 createOpenClawCodingTools:身份信息(senderIsOwnermemberRoleIdsownerOnlyToolAllowlist 等)、渠道/路由(groupIdcurrentChannelIdreplyToMode、消息工具开关)、身份验证 (authProfileStore)、运行标识(由 sandboxSessionKeyrunId 派生的 sessionKey / runSessionKey)、模型上下文(modelApimodelContextWindowTokensmodelCompatmodelHasVision)以及运行钩子 (onToolOutcomeonYield)。缺少这些字段时,仅限所有者的允许列表 会默认静默拒绝,插件信任策略无法解析到正确的 作用域,并且 session_status: "current" 会解析到过期的沙箱键。 桥接构建器是 extensions/copilot/src/tool-bridge.ts,它对应 PI 在 src/agents/embedded-agent-runner/run/attempt.ts:1262 处的权威调用。 runAttempt 通过共享的 resolveSandboxContext 接缝解析沙箱上下文,向 SDK 传递有效工作目录, 并将 sandbox 以及子智能体生成工作区转发到工具 桥。该桥还会转发它能在 SDK 边界执行的有界工具构建控制项: includeCoreTools、运行时工具 允许列表和 toolConstructionPlan

该桥还使用来自 openclaw/plugin-sdk/agent-harness-tool-runtime 的共享 harness 工具界面辅助函数,以实现 PI 对等性。启用 工具搜索时,SDK 看到的是精简的控制工具加一个隐藏的 目录执行器,而不是每个 OpenClaw 工具架构。启用代码模式时, 该辅助函数会构建与其他 Agent harness 相同的代码模式控制界面和目录 生命周期。本地模型精简默认值、 运行时兼容的架构筛选、目录注入和目录 清理全都保留在共享辅助函数中,避免 Copilot 与 Codex 相邻的 harness 之间发生偏差。

会话级 GitHub 令牌

Copilot SDK 合约会区分客户端级 GitHub 令牌 (CopilotClientOptions.gitHubToken,用于验证 CLI 进程本身) 与会话级令牌(SessionConfig.gitHubToken,决定 该会话的内容排除、模型路由和配额;在 createSessionresumeSession 上均会生效)。harness 通过 resolveCopilotAuth 一次性解析身份验证,并在身份验证模式为 gitHubToken 时设置这两个字段(显式的 auth.gitHubToken,或从 已配置的 github-copilot 身份验证配置文件中按合约解析出的 resolvedApiKey)。当解析出的模式为 useLoggedInUser 时,会省略会话级字段,使 SDK 继续 从已登录身份派生身份信息。

ask_user 使用 SessionConfig.onUserInputRequest。该桥会将 SDK 选项或无选项的自由文本提示注册为 Gateway 网关问题;对于固定选项请求, 接受选项索引或标签;当 SDK 请求允许时, 也接受自由格式回答。中止 OpenClaw 尝试会取消 Gateway 网关记录,并返回空的 SDK 回答。

相关内容

Was this useful?
On this page

On this page