Copilot SDK 工具
外部 @openclaw/copilotOpenClawGitHubCLI 插件允许 OpenClaw 通过 GitHub Copilot CLI (@github/copilot-sdk) 运行嵌入式订阅 Copilot agent 轮次,而不是使用内置的 PI 套件。
当您希望 Copilot CLI 会话拥有低级代理循环时,请使用 Copilot SDK 工具:原生工具执行、原生压缩 (CLIinfiniteSessions) 以及由 CLI 管理的 copilotHome 下的线程状态。OpenClaw 仍然拥有聊天通道、会话文件、模型选择、OpenClaw 动态工具(桥接)、批准、媒体交付、可见的转录镜像、/btw 侧问题(由树内 PI 回退处理 — 请参阅 Side questions (/btw)) 以及 openclaw doctor。
有关更广泛的模型/提供商/运行时划分,请从 Agent runtimes 开始。
- 安装了 OpenClaw
@openclaw/copilot插件的 OpenClaw。 - 如果您的配置使用
plugins.allow,请包含copilotnpm(插件声明的清单 ID)。如果限制性允许列表使用 npm 风格的@openclaw/copilot包名称,则插件将保持阻止状态,并且即使在agentRuntime.id: "copilot"下运行时也不会加载。 - 可以驱动 Copilot CLI 的 GitHub Copilot 订阅(或用于无头/定时运行的 GitHubCLI
gitHubTokenenv / auth-profile 条目)。 - 一个可写的
copilotHome目录。该工具默认使用~/.openclaw/agents/<agentId>/copilot以实现完全的每个代理隔离。当 没有显式设置主目录时,平台默认值(Windows 上的%APPDATA%\copilot,或其他地方的$XDG_CONFIG_HOME/copilot或~/.config/copilot)将用作诊断探针的回退项。
openclaw doctor 为该扩展运行插件 doctor contract;那里的失败是在选择加入代理之前确认环境准备就绪的标准方式。
Copilot 运行时是一个外部插件,因此核心 openclaw 包
不携带 @github/copilot-sdk 依赖项或其特定于平台的
@github/copilot-<platform>-<arch> CLI 二进制文件。它们加起来大约
260 MB,因此仅为选择加入此运行时的代理安装它们:
openclaw plugins install @openclaw/copilot向导会在您第一次选择 github-copilot/* 模型并且您的配置通过 agentRuntime: { id: "copilot" } 将该模型(或其提供商)选择加入 Copilot 代理运行时时安装该插件(请参阅下方的 Quickstart)。如果没有选择加入,openclaw 将使用其内置的 GitHub Copilot 提供商,并且永远不会安装运行时插件。
运行时按以下顺序解析 SDK:
- 来自已安装
@openclaw/copilot包的import("@github/copilot-sdk")。 - 众所周知的回退目录
~/.openclaw/npm-runtime/copilot/(即 传统的按需安装目标)。
缺少 SDK 会显示代码为 COPILOT_SDK_MISSING 的单个错误
以及上面的插件重新安装命令。
将一个模型(或一个提供商)固定到该工具:
{ agents: { defaults: { model: "github-copilot/gpt-5.5", models: { "github-copilot/gpt-5.5": { agentRuntime: { id: "copilot" }, }, }, }, },}这两种方法是等效的。当仅应通过该工具路由该模型时,在单个模型条目上使用
agentRuntime.id;当该提供商下的每个模型
都应使用它时,在提供商上设置 agentRuntime.id。
支持的提供商
Section titled “支持的提供商”该工具声明支持规范的 github-copilot 提供商
(由 extensions/github-copilot 拥有的相同 id):
github-copilot
超出该集合的任何内容都会通过 selection.ts 的 auto_pi 分支回退到 PI。
每个代理的优先级,在 runCopilotAttempt 期间应用:
-
显式
useLoggedInUser: true位于尝试输入上。使用在代理的copilotHome下解析的 Copilot CLI 已登录用户。 -
显式
gitHubToken位于尝试输入上(带有profileId+profileVersion)。适用于调用方想要绕过身份验证配置文件解析的直接 CLI 调用和测试。 -
从
EmbeddedRunAttemptParams形状解析的resolvedApiKey+authProfileId。这是生产主要路径: core 在调用 harness 之前解析代理已配置的github-copilot身份验证配置文件 (通过src/infra/provider-usage.auth.ts:resolveProviderAuths),并且 harness 直接使用这两个字段。 这使得github-copilot:<profile>身份验证配置文件可以在无头 / cron / 多配置文件设置中端到端工作,而无需环境变量。 -
环境变量回退,适用于未配置身份验证配置文件的直接 CLI / dogfood 运行。运行时按优先级顺序检查以下变量, 映射已发布的
github-copilot提供商 (extensions/github-copilot/auth.ts)和文档化的 Copilot SDK 设置:OPENCLAW_GITHUB_TOKEN— harness 特定覆盖;设置此项 可为 OpenClaw harness 固定令牌,而不会干扰 系统范围的gh/ Copilot CLI 配置。COPILOT_GITHUB_TOKEN— 标准 Copilot SDK / CLI 环境变量。GH_TOKEN— 标准ghCLI 环境变量(匹配现有的github-copilot提供商优先级)。GITHUB_TOKEN— 通用 GitHub 令牌回退。
第一个非空值优先;空字符串被视为不存在。综合的 pool profile id 为
env:<NAME>,而 profileVersion 是 token 的不可逆 sha256 指纹,因此轮换环境变量值会彻底清除客户端池。 -
当没有可用的 token 信号时的默认
useLoggedInUser。
每个代理都会获得一个专用的 copilotHome,以便 Copilot CLI token、会话和配置不会在同一台机器上的代理之间泄漏。默认情况下,当宿主向工具提供代理目录时(将 SDK 状态与同一目录中的 OpenClaw 的 models.json / auth-profiles.json 隔离),默认值为 <agentDir>/copilot,否则为 ~/.openclaw/agents/<agentId>/copilot。如果需要自定义位置(例如,用于迁移的共享挂载),可以在 attempt 输入中使用 copilotHome: <path> 进行覆盖。
probeCopilotAuthShape(请参阅 Doctor and probes)是纯形状检查,用于验证将使用上述哪种模式。它不执行实时 SDK 握手。
工具从每次尝试的输入 (runCopilotAttempt({...})) 以及 extensions/copilot/src/ 内部的一小组环境变量默认值中读取其配置:
copilotHome— 每个代理的 CLI 状态目录(默认值如上所述)。model— 字符串或{ provider, id, api? }。如果省略,OpenClaw 将使用代理的常规模型选择,并且工具会验证解析出的提供商是否在支持的集合中。reasoningEffort—"low" | "medium" | "high" | "xhigh"。从 OpenClaw 在auto-reply/thinking.ts中的ThinkLevel/ReasoningLevel解析进行映射。infiniteSessionConfig— 由harness.compact驱动的 SDKinfiniteSessions块的可选覆盖。默认值保持原样即可。hooksConfig— 可选的桥接配置,向 SDK 循环暴露 OpenClaw 的消息写入前/后挂钩。permissionPolicy— 用于 SDK 内置工具类型(shell、write、read、url、mcp、memory、hook)的onPermissionRequest处理程序的可选覆盖。 默认为rejectAllPolicy作为安全网;实际上 SDK 从不调用这些类型,因为每个桥接的 OpenClaw 工具 都注册了overridesBuiltInTool: true和skipPermission: true,所以 100%% 的工具调用都通过 OpenClaw 包装的execute()流转。 请参阅 权限和 ask_user。enableSessionTelemetry— 通过telemetry-bridge.ts选择加入 OpenTelemetry 路由。
OpenClaw 的其余部分不需要了解这些字段。其他插件、通道和核心代码只能看到标准的 AgentHarnessAttemptParams / AgentHarnessAttemptResult 形状。
当 harness.compact 运行时,Copilot SDK 套件:
- 恢复跟踪的 SDK 会话,而不继续待处理的工作。
- 调用 SDK 的会话作用域历史压缩 RPC。
- 返回 SDK 压缩结果,而不在工作区下写入兼容性标记文件。
OpenClaw 端转录镜像(见下文)继续接收压缩后消息,因此面向用户的聊天历史保持一致。
runCopilotAttempt 通过 extensions/copilot/src/dual-write-transcripts.ts 将每轮可镜像消息双重写入 OpenClaw 审计记录。
镜像是每会话作用域的(copilot:${sessionId}),并使用每条消息的唯一标识(${role}:${sha256_16(role,content)}),因此重新发出先前轮次的条目时会与现有磁盘键冲突,而不会重复。
镜像包装在两层故障遏制中,因此记录写入失败不会导致尝试失败:一个是内部尽力而为包装器,另一个是尝试级别的纵深防御 .catch(...)。故障会被记录但不会 surfaced。
侧面问题 (/btw)
Section titled “侧面问题 (/btw)”/btw 在此工具中不是原生的。createCopilotAgentHarness()
故意将 harness.runSideQuestionOpenClaw 保留为未定义,因此 OpenClaw 的 /btw
调度程序(src/agents/btw.ts)会回退到它为每个非 Codex 运行时使用的相同树内 PI 回退路径:直接使用简短的问题提示调用配置的模型提供商,并通过 streamSimpleCLI 流式传回(无 CLI 会话,无额外的池槽位)。
这将保留 Copilot CLI 会话供代理的主循环使用,并使 CLI/btw 行为与其他基于 PI 的运行时保持一致。该约定在
extensions/copilot/harness.test.ts
中的 describe("runSideQuestion") 下进行了断言。
extensions/copilot/doctor-contract-api.ts 由
src/plugins/doctor-contract-registry.ts 自动加载。它提供:
- 一个空的
legacyConfigRules(在 MVP 阶段没有废弃的字段)。 - 一个空操作的
normalizeCompatibilityConfig(保留以便将来字段废弃 时在树内有一个稳定的归属)。 - 一个
sessionRouteStateOwners条目,声明提供商github-copilot; 运行时copilotCLI;CLI 会话密钥copilot;身份验证配置文件 前缀github-copilot:。
extensions/copilot/src/doctor-probes.ts 导出了三个命令式探针,
主机(包括 openclaw doctor)可以调用这些探针来验证环境:
| 探针 | 检查内容 | 可能失败的原因 |
|---|---|---|
probeCopilotCliVersion | copilot --version 退出码为 0 并带有非空版本字符串 | non-zero-exit、empty-version、spawn-failed、spawn-error、probe-timeout |
probeCopilotHomeWritable | mkdir -p copilotHome + 写入 + 删除标记文件 | copilothome-not-writable(并在 details.rawError 中包含底层 fs 错误) |
probeCopilotAuthShape | 至少需要 useLoggedInUser、gitHubToken 或 profileId+profileVersion 之一 | no-auth-source |
每个探针都接受一个 DI 缝合点 (spawnFn, fsApi),以便测试不会生成真正的 Copilot CLI 或触及主机文件系统。
- 在 MVP 阶段,该连接器仅支持规范的
github-copilot提供商。 额外的提供商(BYOK 或其他)应该在后续的 PR 中落地,这些 PR 将适配器与连接代码一起发布。 - 该驱动不提供 TUI;PI 的 TUI 不受影响,并仍是 没有对等表面的任何运行时的回退方案。
- 当代理切换到
copilot时,PI 会话状态不会被迁移。 选择是基于每次尝试的;现有的 PI 会话仍然有效。 - 交互式
ask_user尚未连接。 故意未注册 SDK 的onUserInputRequest处理程序,根据 SDK 合同,这会完全从模型中 隐藏ask_user工具。在此连接器下运行的代理会根据初始提示 做出最佳判断决策,而不是在轮次中途询问澄清问题。 后续工作将把extensions/codex/src/app-server/user-input-bridge.ts中的 codex 模式移植过来,以便通过 OpenClaw 渠道/TUI 提示路径路由 SDKUserInputRequest;extensions/copilot/src/user-input-bridge.ts中 的休眠脚手架是后续工作将要连接的表面。
权限和 ask_user
Section titled “权限和 ask_user”桥接的 OpenClaw 工具的权限强制执行发生在工具包装器内部,
而不是通过 SDK 的 onPermissionRequest 回调。PI 使用的
相同 wrapToolWithBeforeToolCallHook (src/agents/pi-tools.before-tool-call.ts)
由 createOpenClawCodingTools 应用于每个编码工具:循环检测、
受信任的插件策略、工具调用前挂钩以及通过网关 (plugin.approval.request) 进行的
两阶段插件批准,所有这些都以与原生 PI 尝试完全相同的代码路径运行。
为了让该包装器拥有决策权,由
convertOpenClawToolToSdkTool 返回的 SDK 工具被标记为:
overridesBuiltInTool: true— 替换 Copilot CLI 内置的 同名工具(edit、read、write、bash 等),以便每次工具 调用都路由回 OpenClaw。skipPermission: true— 告诉 SDK 在调用工具之前不要触发onPermissionRequest({kind: "custom-tool"})。 被封装的execute()在内部执行更丰富的 OpenClaw 策略检查; SDK 级别的提示要么会绕过 OpenClaw 的 执行(如果我们全部允许),要么会阻止每一次工具调用(如果我们 全部拒绝)—— 两者都与 PI 对等性不匹配。
代码树内(in-tree)的 codex 控制线使用了相同的划分:桥接的 OpenClaw 工具
被封装(extensions/codex/src/app-server/dynamic-tools.ts),而
codex-app-server 自身的原生审批类型
(item/commandExecution/requestApproval、
item/fileChange/requestApproval、
item/permissions/requestApproval)则通过
plugin.approval.request
(extensions/codex/src/app-server/approval-bridge.ts)进行路由。Copilot SDK
的等效机制——对任何到达 onPermissionRequest 的非 custom-tool
类型进行失效闭合(fail-closed)rejectAllPolicy—— 是相同的安全保障,
它在实践中不会触发,因为 overridesBuiltInTool: true
取代了每一个内置工具。
为了使封装工具层能够做出与 PI 等效的策略决策,
此连接器将完整的 PI attempt-工具 上下文转发给
createOpenClawCodingTools —— 身份信息(senderIsOwner,
memberRoleIds, ownerOnlyToolAllowlist, …)、渠道/路由
(groupId, currentChannelId, replyToMode,消息工具开关)、
身份验证(authProfileStore)、运行身份
(从 sandboxSessionKey、
runId 派生的 sessionKey/runSessionKey),
模型上下文(modelApi, modelContextWindowTokens,
modelCompat, modelHasVision)以及运行钩子(onToolOutcome,
onYield)。如果没有这些字段,仅限所有者的允许列表将
静默地表现为默认拒绝,插件信任策略将无法解析到
正确的作用域,并且 session_status: "current" 将解析为过时的
沙箱密钥。桥接构建器位于
extensions/copilot/src/tool-bridge.ts 中,并镜像 PI 在
src/agents/pi-embedded-runner/run/attempt.ts:1029-1117 的权威调用。有两个 PI 字段
在 MVP 版本中故意不转发,并被跟踪为后续工作:
sandbox(连接器尚未通过 resolveSandboxContext 进行路由)
以及 PI 工具搜索/代码模式机制
(toolSearchCatalogRef, includeCoreTools,
includeToolSearchControls, toolSearchCatalogExecutor,
toolConstructionPlan),这些机制在 SDK 边界没有对应项。
会话级 GitHub 令牌
Section titled “会话级 GitHub 令牌”Copilot SDK 契约区分了 客户端级别 的 GitHub
令牌 (GitHubCopilotClientOptions.gitHubTokenCLI,用于验证
CLI 进程本身) 和 会话级别 的令牌
(SessionConfig.gitHubToken,它决定了该会话的内容排除、
模型路由和配额,并且在 createSession 和
resumeSession 上均受支持)。该通过 resolveCopilotAuth 一次解析身份验证,并在身份验证模式为
gitHubToken(显式的 auth.gitHubToken 或来自已配置 github-copilot 身份验证配置文件
的契约解析 resolvedApiKey)时设置这两个字段。
当解析的模式为 useLoggedInUser 时,会话级别字段
将被省略,以便 SDK 继续从已登录的
身份派生身份。
ask_user 是故意隐藏的 —— 请参阅上面的限制。