---
read_when:
    - 你想为智能体使用 GitHub Copilot SDK harness
    - 你需要 `copilot` 运行时的配置示例
    - 你正在将智能体接入订阅版 Copilot（github / openclaw / copilot），并希望它通过 Copilot CLI 运行
summary: 通过外部 GitHub Copilot SDK harness 运行 OpenClaw 嵌入式智能体轮次
title: Copilot SDK harness
x-i18n:
    generated_at: "2026-07-26T06:54:46Z"
    model: gpt-5.6
    postprocess_version: locale-links-v1
    prompt_version: 32
    provider: openai
    source_hash: 4b67959c2c72bda97a81d0b45bc32ba363373064ec40c54f9709705dd15dd9fc
    source_path: plugins/copilot.md
    workflow: 16
---

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

有关更广泛的模型/提供商/运行时划分，请先阅读
[Agent Runtimes](/zh-CN/concepts/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 合约](#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 运行时时，设置向导会自动安装该插件；参见
[快速开始](#quickstart)。如果未选择使用，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（`openai`、`anthropic`、`google`、`ollama`）仍由各自的原生运行时所有。若要改为通过 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:<NAME>`；配置文件版本是令牌的不可逆 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_TOKEN`、`GH_TOKEN`
和 `GITHUB_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 工具类型（`shell`、`write`、`read`、`url`、`mcp`、`memory`、`hook`）。默认为 `rejectAllPolicy`，作为安全保障；关于它为何实际上永远不会触发，请参见[权限和 ask_user](#permissions-and-ask_user)。 |
| `enableSessionTelemetry` | 可选的 SDK 会话遥测标志。                                                                                                                                                                                                                                                            |

OpenClaw 插件钩子无需任何 Copilot 专用的尝试配置。该 harness 通过标准 harness 辅助程序运行 `before_prompt_build`、`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 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.ts`、`describe("runSideQuestion")` 中有断言），
因此 OpenClaw 的 `/btw` 分派器（`src/agents/btw.ts`）会回退到
所有非 Codex 运行时所使用的相同路径：直接调用已配置的模型提供商，
传入简短的旁支问题提示，并通过
`streamSimple` 流式返回（无 CLI 会话，不额外占用池槽位）。

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

## Doctor

`extensions/copilot/doctor-contract-api.ts` 由
`src/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 使用的同一
`wrapToolWithBeforeToolCallHook`
（`src/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/requestApproval`、`item/fileChange/requestApproval`、
`item/permissions/requestApproval`）通过 `plugin.approval.request`
（`extensions/codex/src/app-server/approval-bridge.ts`）路由。Copilot SDK
中的对应机制——对任何到达 `onPermissionRequest` 的非 `custom-tool` 类型
执行故障时关闭的 `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`，它对应 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`，决定
该会话的内容排除、模型路由和配额；在
`createSession` 和 `resumeSession` 上均会生效）。harness 通过
`resolveCopilotAuth` 一次性解析身份验证，并在身份验证模式为 `gitHubToken`
时设置这两个字段（显式的 `auth.gitHubToken`，或从
已配置的 `github-copilot` 身份验证配置文件中按合约解析出的 `resolvedApiKey`）。当解析出的模式为
`useLoggedInUser` 时，会省略会话级字段，使 SDK 继续
从已登录身份派生身份信息。

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

## 相关内容

- [Agent Runtimes](/zh-CN/concepts/agent-runtimes)
- [Codex harness](/zh-CN/plugins/codex-harness)
- [Agent harness plugins (SDK reference)](/zh-CN/plugins/sdk-agent-harness)
