@openclaw/copilot 插件通过 GitHub Copilot CLI(@github/copilot-sdk)运行嵌入式订阅 Copilot 智能体轮次,而不是使用 OpenClaw 内置的 PI 运行框架。Copilot CLI 会话拥有底层 Agent loop:原生工具执行、原生压缩(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 订阅,或用于无头运行或 cron 运行的
gitHubToken环境变量 / auth-profile 条目。 - 一个可写的
copilotHome目录。当 OpenClaw 提供 Agent 目录时,默认值为<agentDir>/copilot,否则为~/.openclaw/agents/<agentId>/copilot。
openclaw doctor 会运行插件的 doctor contract,用于会话状态所有权和未来配置迁移。它不会探测 Copilot CLI 环境。
安装
Copilot 运行时作为外部插件发布,因此核心openclaw 包不会携带 @github/copilot-sdk 或其平台特定的 @github/copilot-<platform>-<arch> CLI 二进制文件(两者合计约 260 MB)。只为选择使用此运行时的智能体安装它:
github-copilot/* 模型,并且你的配置通过 agentRuntime: { id: "copilot" } 将该模型(或其提供商)路由到 Copilot 运行时时,设置向导会自动安装插件;见快速开始。如果没有该选择加入,OpenClaw 会使用内置的 GitHub Copilot provider,并且不会安装此插件。
运行时按以下顺序解析 SDK:
- 从已安装的
@openclaw/copilot包中import("@github/copilot-sdk")。 - 回退目录
~/.openclaw/npm-runtime/copilot/(旧版按需安装目标)。
COPILOT_SDK_MISSING 的错误,并显示上面的重新安装命令。
快速开始
将一个模型(或一个提供商)固定到运行框架:agentRuntime.id,只将该模型路由到运行框架;或在提供商上设置它,将该提供商下的每个模型都路由过去。
github-copilot/auto 是可移植的起点。具名 Copilot 模型取决于账号和组织策略;在固定前,请确认你已认证的 Copilot CLI 确实暴露了该模型。
支持的提供商
运行框架支持规范的github-copilot 提供商(由 extensions/github-copilot 拥有),以及在模型具有非空 baseUrl 且具备以下 api 形态之一时的自定义 models.providers 条目:
anthropic-messagesazure-openai-responsesollama(OpenAI 兼容补全)openai-completionsopenai-responses
openai、anthropic、google、ollama)仍由其原生运行时拥有。请改用一个不同的自定义提供商 id,通过 Copilot BYOK 路由端点。
Copilot BYOK 端点必须是公共 HTTPS URL。运行框架会向 Copilot SDK 提供每次尝试专用的 loopback 代理,然后通过 OpenClaw 的受保护 fetch 路径转发提供商流量,以便 DNS 固定和 SSRF 策略仍由 OpenClaw 拥有。对于本地 Ollama、LM Studio 或 LAN 模型服务器,请使用原生 OpenClaw 运行时。
BYOK
Copilot BYOK 使用 SDK 的会话级自定义提供商合约。OpenClaw 会传入解析后的模型端点、API key、bearer-token 模式、headers、模型 id,以及上下文/输出限制;提供商传输逻辑保留在 SDK 中,而不是核心中。认证
优先级,在runCopilotAttempt 期间按每个智能体应用:
-
尝试输入上的显式
useLoggedInUser: true— 使用智能体copilotHome下 Copilot CLI 的已登录用户。 -
尝试输入上的显式
gitHubToken(需要profileId+profileVersion)。用于需要绕过 auth-profile 解析的直接 CLI 调用和测试。 -
合约解析的
resolvedApiKey+authProfileId— 生产主路径。核心会在调用运行框架前解析智能体配置的github-copilot认证配置文件(src/infra/provider-usage.auth.ts:resolveProviderAuths),因此github-copilot:<profile>auth profile 可在无头、cron 或多配置文件设置中端到端工作,无需环境变量。 -
环境变量回退,按此顺序检查(第一个非空值获胜,空字符串视为不存在;镜像
extensions/github-copilot/auth.ts中已发布的github-copilot提供商优先级):OPENCLAW_GITHUB_TOKEN— 运行框架专用覆盖;允许你为 OpenClaw 运行框架固定一个 token,而不会干扰系统级gh/ Copilot CLI 配置。COPILOT_GITHUB_TOKEN— 标准 Copilot SDK / CLI 环境变量。GH_TOKEN— 标准ghCLI 环境变量。GITHUB_TOKEN— 通用 GitHub token 回退。
env:<NAME>;配置文件版本是 token 的不可逆 sha256 指纹,因此轮换环境变量值会干净地使客户端池失效。 -
当没有 token 信号可用时,使用默认
useLoggedInUser。
copilotHome,因此 Copilot CLI token、会话和配置永远不会在同一台机器上的智能体之间泄漏。默认值:<agentDir>/copilot(将 SDK 状态保留在 OpenClaw 的 models.json / auth-profiles.json 所在目录之外),或在未提供 Agent 目录时使用 ~/.openclaw/agents/<agentId>/copilot。可在尝试输入中用 copilotHome: <path> 覆盖为自定义位置(例如用于迁移的共享挂载)。
实时运行框架测试使用 OPENCLAW_COPILOT_AGENT_LIVE_TOKEN 作为直接 token。共享实时测试设置会在将真实 auth profile 暂存到隔离测试 home 后清除 COPILOT_GITHUB_TOKEN、GH_TOKEN 和 GITHUB_TOKEN,因此通过专用变量传入的 gh auth token 值可以避免误跳过,同时不会泄漏到无关套件中。
配置接口
运行框架从每次尝试输入(runCopilotAttempt({...}))以及 extensions/copilot/src/ 内的一小组环境默认值读取配置:
| 字段 | 用途 |
|---|---|
copilotHome | 每个智能体的 CLI 状态目录(默认值见上文)。 |
model | 字符串或 { provider, id, api?, baseUrl?, headers?, authHeader? }。省略则使用智能体的正常模型选择;运行框架会验证解析后的提供商受支持。 |
reasoningEffort | "low" | "medium" | "high" | "xhigh"。从 auto-reply/thinking.ts 中 OpenClaw 的 ThinkLevel / ReasoningLevel 解析映射而来。 |
infiniteSessionConfig | 可选覆盖项,用于由 harness.compact 驱动的 SDK infiniteSessions 块。保持原样即可。 |
hooksConfig | 可选的原生 Copilot SDK SessionHooks 配置,用于工具/MCP、用户提示、会话和错误回调。独立于 OpenClaw 的可移植生命周期钩子。 |
permissionPolicy | SDK 内置工具类型(shell、write、read、url、mcp、memory、hook)的 onPermissionRequest 处理程序可选覆盖项。默认使用 rejectAllPolicy 作为安全网;它为什么实际上永远不会触发,见权限和 ask_user。 |
enableSessionTelemetry | 可选的 SDK 会话遥测标志。 |
before_prompt_build(以及旧版 before_agent_start 兼容钩子)、llm_input、llm_output 和 agent_end。成功的 SDK 压缩还会运行 before_compaction 和 after_compaction。桥接的 OpenClaw 工具会运行 before_tool_call 并报告 after_tool_call;hooksConfig 仍用于没有可移植等价项的原生 SDK 专用回调。
OpenClaw 中的其他任何内容都不需要了解这些字段。其他插件、渠道和核心代码只会看到标准的 AgentHarnessAttemptParams / AgentHarnessAttemptResult 形态。
压缩
当harness.compact 运行时,Copilot SDK 运行框架会:
- 恢复被跟踪的 SDK 会话,但不继续待处理工作。
- 调用 SDK 的会话作用域历史压缩 RPC。
- 返回 SDK 压缩结果,而不会在工作区下写入兼容性标记文件。
转录镜像
runCopilotAttempt 会通过 extensions/copilot/src/dual-write-transcripts.ts 将每个轮次可镜像的消息双写入 OpenClaw 审计转录。镜像按会话作用域限定(copilot:${sessionId}),并按消息键控(${role}:${sha256_16(role,content)}),因此重新发出的前序轮次条目会与现有磁盘键冲突,而不是重复写入。
两层故障隔离包裹着镜像,因此转录写入失败永远不会导致尝试失败:一个内部的尽力而为包装器,以及尝试级别的纵深防御 .catch(...)。失败会被记录到日志中,而不会浮出。
旁路问题(/btw)
/btw 在这个 harness 上不是原生能力。createCopilotAgentHarness()
有意让 harness.runSideQuestion 保持未定义
(在 extensions/copilot/harness.test.ts 的 describe("runSideQuestion") 中断言),
因此 OpenClaw 的 /btw 分发器(src/agents/btw.ts)会落到
它用于所有非 Codex runtime 的相同路径:直接调用已配置的模型提供商,
传入简短的旁路问题提示,并通过 streamSimple 流式返回
(没有 CLI 会话,也不占用额外池槽位)。
这会让 Copilot CLI 会话保留给智能体的主轮次循环,
并让 /btw 行为与其他非 Codex runtime 保持一致。
Doctor
extensions/copilot/doctor-contract-api.ts 会由
src/plugins/doctor-contract-registry.ts 自动加载。它贡献了:
- 一个空的
legacyConfigRules(目前还没有退役字段)。 - 一个无操作的
normalizeCompatibilityConfig(保留它是为了让未来字段退役 有一个稳定的仓库内归宿)。 - 一个
sessionRouteStateOwners条目:提供商github-copilot,runtimecopilot,CLI 会话键copilot,凭证配置文件前缀github-copilot:。
限制
- 该 harness 声明
github-copilot以及无所有者的自定义 BYOK 提供商 ID。 清单拥有的原生提供商 ID 会继续留在其所属 runtime 上,即使agentRuntime.id被强制设为copilot。 - 没有 TUI 界面;对于没有对等界面的 runtime,PI 的 TUI 仍是回退。
- 当智能体切换到
copilot时,PI 会话状态不会迁移。 选择按每次尝试生效;现有 PI 会话仍然有效。 ask_user使用与 Codex harness 相同的 OpenClaw 提示与回复路径: 当 Copilot SDK 请求用户输入时,OpenClaw 会向活动渠道/TUI 发布一个 阻塞提示,下一条排队的用户消息会解析该 SDK 请求。
权限和 ask_user
桥接的 OpenClaw 工具的权限执行发生在工具包装器内部, 而不是通过 SDK 的onPermissionRequest 回调。PI 使用的同一个
wrapToolWithBeforeToolCallHook
(src/agents/agent-tools.before-tool-call.ts)会由
createOpenClawCodingTools 应用于每个代码工具:循环检测、受信插件策略、
before-tool-call 钩子,以及通过 Gateway 网关(plugin.approval.request)
进行的两阶段插件审批,全都走与原生 PI 尝试完全相同的代码路径。
convertOpenClawToolToSdkTool 返回的 SDK Tool 会标记为:
overridesBuiltInTool: true— 替换 Copilot CLI 中同名的内置工具 (edit、read、write、bash 等),因此每次工具调用都会路由回 OpenClaw。skipPermission: true— 告诉 SDK 在调用工具前不要触发onPermissionRequest({kind: "custom-tool"})。被包装的execute()已经执行了更丰富的 OpenClaw 策略检查;SDK 级提示要么会短路 OpenClaw 的执行(全部允许),要么会阻塞每次工具调用(全部拒绝)— 两者都不符合 PI 对等性。
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 等价的策略决策,该 harness 会把完整的 PI
尝试工具上下文转发给 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,
它镜像了 src/agents/embedded-agent-runner/run/attempt.ts:1262 处 PI
的权威调用。runAttempt 通过共享的 resolveSandboxContext seam 解析沙箱上下文,
向 SDK 传入有效工作目录,并将 sandbox 以及子智能体生成工作空间转发到工具桥接。
该桥接还转发它能在 SDK 边界执行的有界工具构造控制:includeCoreTools、
runtime 工具允许列表,以及 toolConstructionPlan。
该桥接还使用来自 openclaw/plugin-sdk/agent-harness-tool-runtime 的共享
harness 工具界面辅助模块,以保持 PI 对等性。启用工具搜索时,SDK 看到的是
紧凑的控制工具加一个隐藏目录执行器,而不是每个 OpenClaw 工具 schema。
启用代码模式时,该辅助模块会构建其他 agent harness 使用的相同代码模式控制界面
和目录生命周期。本地模型精简默认值、runtime 兼容 schema 过滤、目录水合以及目录清理
都保留在共享辅助模块中,因此 Copilot 和 Codex 相邻 harness 不会漂移。
会话级 GitHub 令牌
Copilot SDK 合约区分客户端级 GitHub 令牌 (CopilotClientOptions.gitHubToken,用于认证 CLI 进程本身)和
会话级令牌(SessionConfig.gitHubToken,决定该会话的内容排除、
模型路由和配额;在 createSession 和 resumeSession 上都会被遵守)。
该 harness 通过 resolveCopilotAuth 解析一次凭证,并在凭证模式为
gitHubToken 时设置这两个字段(显式 auth.gitHubToken,或来自已配置
github-copilot 凭证配置文件、由合约解析出的 resolvedApiKey)。
当解析出的模式为 useLoggedInUser 时,会省略会话级字段,让 SDK 继续
从已登录身份派生身份。
ask_user 使用 SessionConfig.onUserInputRequest。桥接会为固定选项请求接受选项索引或标签,
在 SDK 请求允许时接受自由形式答案,并在 OpenClaw 尝试被中止时取消待处理请求。