> ## Documentation Index
> Fetch the complete documentation index at: https://docs2.openclaw.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Copilot SDK 測試框架

外部 `@openclaw/copilot` 外掛會透過 GitHub Copilot 命令列介面（`@github/copilot-sdk`）執行內嵌訂閱 Copilot
代理程式輪次，而不是使用 OpenClaw 的內建控管機制。Copilot 命令列介面工作階段負責底層
代理程式迴圈：原生工具執行、原生壓縮（`infiniteSessions`），以及
位於 `copilotHome` 下、由命令列介面管理的執行緒狀態。OpenClaw 仍負責聊天
頻道、工作階段檔案、模型選擇、動態工具（透過橋接）、核准、
媒體傳遞、可見的文字記錄鏡像、`/btw` 附帶問題（請參閱
[附帶問題（`/btw`）](#side-questions-btw)），以及 `openclaw doctor`。

若要瞭解更廣泛的模型／供應商／執行階段劃分，請先參閱
[代理程式執行階段](/zh-TW/concepts/agent-runtimes)。

## 需求

* 已安裝 `@openclaw/copilot` 外掛的 OpenClaw。
* 如果你的設定使用 `plugins.allow`，請包含 `copilot`（外掛所宣告的資訊清單 ID）。
  npm 套件名稱 `@openclaw/copilot` 的允許清單項目不會相符，即使已設定
  `agentRuntime.id: "copilot"`，外掛仍會遭到封鎖。
* 可驅動 Copilot 命令列介面的 GitHub Copilot 訂閱，或供無介面或排程執行使用的
  `gitHubToken` 環境變數／驗證設定檔項目。
* 可寫入的 `copilotHome` 目錄。當 OpenClaw 提供代理程式目錄時，
  預設為 `<agentDir>/copilot`，否則為
  `~/.openclaw/agents/<agentId>/copilot`。

`openclaw doctor` 會針對工作階段狀態擁有權及未來設定遷移，執行外掛的
[doctor 合約](#doctor)。它不會探測 Copilot 命令列介面環境。

## 安裝

Copilot 執行階段以外部外掛形式提供，因此核心 `openclaw`
套件不會攜帶 `@github/copilot-sdk` 或其平台專用的
`@github/copilot-<platform>-<arch>` 命令列介面二進位檔（合計約 260 MB）。
僅針對選擇使用此執行階段的代理程式安裝：

```bash theme={"theme":{"light":"min-light","dark":"min-dark"}}
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`，並附上
上述重新安裝命令。

## 快速入門

將一個模型（或一個供應商）固定至控管機制：

```json5 theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  agents: {
    defaults: {
      model: "github-copilot/auto",
      models: {
        "github-copilot/auto": {
          agentRuntime: { id: "copilot" },
        },
      },
    },
  },
}
```

在單一模型項目上設定 `agentRuntime.id`，即可僅透過
此控管機制路由該模型；或在供應商上設定，以路由該供應商下的每個模型。

`github-copilot/auto` 是可攜式起點。具名 Copilot 模型會因
帳戶及組織政策而異；固定模型前，請確認已驗證的
Copilot 命令列介面確實公開該模型。

## 支援的供應商

此控管機制支援標準 `github-copilot` 供應商（由
`extensions/github-copilot` 擁有），也支援自訂 `models.providers` 項目，前提是
模型具有非空白的 `baseUrl`，且使用下列其中一種 `api` 格式：

* `anthropic-messages`
* `azure-openai-responses`
* `ollama`（OpenAI 相容的補全）
* `openai-completions`
* `openai-responses`

原生供應商 ID（`openai`、`anthropic`、`google`、`ollama`）仍由
其原生執行階段擁有。若要透過 Copilot BYOK 路由端點，請改用不同的自訂供應商 ID。

Copilot BYOK 端點必須是公開的 HTTPS URL。此控管機制會為每次嘗試向
Copilot SDK 提供一個回送代理伺服器，接著透過 OpenClaw 的受保護擷取路徑轉送供應商流量，
使 DNS 固定及 SSRF 政策仍由 OpenClaw 負責。若使用本機 Ollama、LM
Studio 或區域網路模型伺服器，請使用原生 OpenClaw 執行階段。

## BYOK

Copilot BYOK 使用 SDK 的工作階段層級自訂供應商合約。OpenClaw
會傳遞已解析的模型端點、API 金鑰、持有人權杖模式、標頭、模型
ID，以及內容／輸出限制；供應商傳輸邏輯保留在 SDK 中，而非核心。

```json5 theme={"theme":{"light":"min-light","dark":"min-dark"}}
{
  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 命令列介面的已登入使用者。

2. 嘗試輸入上的**明確 `gitHubToken`**（需要 `profileId` +
   `profileVersion`）。供需要略過驗證設定檔解析的直接命令列介面叫用及測試使用。

3. **由合約解析的 `resolvedApiKey` + `authProfileId`** — 正式環境的
   主要路徑。核心會在叫用控管機制前解析代理程式已設定的 `github-copilot` 驗證
   設定檔（`src/infra/provider-usage.auth.ts:resolveProviderAuths`），因此 `github-copilot:<profile>` 驗證設定檔可在
   無介面、排程或多設定檔環境中端對端運作，無需環境變數。

4. **環境變數備援**，依此順序檢查（第一個非空白值優先，
   空字串視為不存在；比照 `extensions/github-copilot/auth.ts` 中已發行的 `github-copilot`
   供應商優先順序）：

   1. `OPENCLAW_GITHUB_TOKEN` — 控管機制專用覆寫；可為 OpenClaw 控管機制固定
      權杖，而不影響系統層級的 `gh` /
      Copilot 命令列介面設定。
   2. `COPILOT_GITHUB_TOKEN` — 標準 Copilot SDK／命令列介面環境變數。
   3. `GH_TOKEN` — 標準 `gh` 命令列介面環境變數。
   4. `GITHUB_TOKEN` — 通用 GitHub 權杖備援。

   合成的集區設定檔 ID 為 `env:<NAME>`；設定檔版本是權杖的
   不可逆 sha256 指紋，因此輪替環境變數值時，
   會完整清除用戶端集區。

5. 沒有可用的權杖訊號時，使用**預設 `useLoggedInUser`**。

每個代理程式都有各自的 `copilotHome`，因此同一台機器上的代理程式之間
絕不會洩漏 Copilot 命令列介面權杖、工作階段和設定。預設值：
`<agentDir>/copilot`（使 SDK 狀態不會與 OpenClaw 的
`models.json`／`auth-profiles.json` 位於同一目錄），若未提供代理程式目錄，
則為 `~/.openclaw/agents/<agentId>/copilot`。
若要使用自訂位置（例如供遷移使用的共用掛載點），請在嘗試輸入上以
`copilotHome: <path>` 覆寫。

即時控管機制測試使用 `OPENCLAW_COPILOT_AGENT_LIVE_TOKEN` 傳入直接
權杖。共用即時測試設定會在將實際驗證設定檔暫存至隔離測試
主目錄後，清除 `COPILOT_GITHUB_TOKEN`、`GH_TOKEN`
和 `GITHUB_TOKEN`，因此透過專用變數傳入 `gh auth token` 值可避免
錯誤略過，同時不會洩漏至無關的測試套件。

## 設定介面

此控管機制會從每次嘗試輸入（`runCopilotAttempt({...})`）
以及 `extensions/copilot/src/` 內的一小組環境預設值讀取設定：

| 欄位                       | 用途                                                                                                                                                                                               |
| ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `copilotHome`            | 每個代理程式的命令列介面狀態目錄（預設值如上）。                                                                                                                                                                         |
| `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 的 `onPermissionRequest` 處理常式選用覆寫，用於內建 SDK 工具種類（`shell`、`write`、`read`、`url`、`mcp`、`memory`、`hook`）。預設為 `rejectAllPolicy`，作為安全防護；請參閱[權限與 ask\_user](#permissions-and-ask_user)，瞭解為何它實際上絕不會觸發。 |
| `enableSessionTelemetry` | 選用的 SDK 工作階段遙測旗標。                                                                                                                                                                                |

OpenClaw 外掛掛鉤不需要 Copilot 專用的嘗試設定。此
控管機制會透過標準控管機制輔助程式執行 `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 控管機制會：

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` 在此執行框架上**不是**原生功能。`createCopilotAgentHarness()`
刻意讓 `harness.runSideQuestion` 保持未定義
（於 `extensions/copilot/harness.test.ts`、`describe("runSideQuestion")` 中斷言），
因此 OpenClaw 的 `/btw` 分派器（`src/agents/btw.ts`）會轉而使用
每個非 Codex 執行階段所採用的相同路徑：直接呼叫已設定的模型供應商，
並提供簡短的附帶問題提示，再透過
`streamSimple` 串流傳回（無命令列介面工作階段，也不占用額外的集區插槽）。

如此可將 Copilot CLI 工作階段保留給代理程式的主要輪次迴圈，並使
`/btw` 的行為與其他非 Codex 執行階段一致。

## Doctor

`extensions/copilot/doctor-contract-api.ts` 由
`src/plugins/doctor-contract-registry.ts` 自動載入。它提供：

* 空的 `legacyConfigRules`（目前尚無已淘汰欄位）。
* 不執行任何操作的 `normalizeCompatibilityConfig`（予以保留，讓未來淘汰欄位時
  在原始碼樹中有穩定的歸屬位置）。
* 一個 `sessionRouteStateOwners` 項目：供應商 `github-copilot`、執行階段
  `copilot`、命令列介面工作階段鍵 `copilot`、驗證設定檔前綴 `github-copilot:`。

## 限制

* 此執行框架會宣告 `github-copilot`，以及沒有擁有者的自訂 BYOK 供應商 ID。
  由資訊清單擁有的原生供應商 ID 仍會留在其所屬的執行階段，即使
  `agentRuntime.id` 被強制設為 `copilot` 亦然。
* 沒有終端介面介面；對於沒有對等介面的執行階段，PI 的終端介面仍是備援方案。
* 當代理程式切換至 `copilot` 時，不會遷移 PI 工作階段狀態。
  每次嘗試都會個別選擇；現有 PI 工作階段仍然有效。
* `ask_user` 使用不綁定供應商的閘道問題執行階段。Control
  UI 會顯示與其他 OpenClaw 問題相同的問題卡片，支援的
  頻道會呈現選項按鈕，而下一則排入佇列的純文字訊息
  會在 SDK 要求傳回前解析該閘道記錄。

## 權限與 ask\_user

橋接式 OpenClaw 工具的權限強制執行發生在**工具
包裝器內部**，而非透過 SDK 的 `onPermissionRequest` 回呼。PI 使用的同一個
`wrapToolWithBeforeToolCallHook`
（`src/agents/agent-tools.before-tool-call.ts`）會由
`createOpenClawCodingTools` 套用至每個程式設計工具：迴圈偵測、受信任的
外掛政策、工具呼叫前掛鉤，以及透過
閘道（`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 執行框架使用相同的分工：橋接式 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 等效的政策決策，
執行框架會將完整的 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` 的共用執行框架工具介面輔助程式，以實現與 PI 同等的行為。啟用
工具搜尋時，SDK 看到的是精簡的控制工具加上隱藏的
目錄執行器，而非每個 OpenClaw 工具結構描述。啟用程式碼模式時，
輔助程式會建構與其他代理程式執行框架相同的程式碼模式控制介面與目錄
生命週期。本機模型的精簡預設值、
與執行階段相容的結構描述篩選、目錄載入及目錄
清理全都保留在共用輔助程式中，因此 Copilot 與 Codex 相鄰的
執行框架不會產生差異。

### 工作階段層級的 GitHub 權杖

Copilot SDK 合約會區分**用戶端層級**的 GitHub 權杖
（`CopilotClientOptions.gitHubToken`，用於驗證 CLI 程序本身）
與**工作階段層級**的權杖（`SessionConfig.gitHubToken`，決定
該工作階段的內容排除、模型路由與配額；在
`createSession` 和 `resumeSession` 上皆會採用）。執行框架會透過
`resolveCopilotAuth` 解析一次驗證，並在驗證模式為 `gitHubToken`
時設定這兩個欄位（明確的 `auth.gitHubToken`，或從
已設定的 `github-copilot` 驗證設定檔依合約解析出的 `resolvedApiKey`）。
當解析出的模式為
`useLoggedInUser` 時，會省略工作階段層級欄位，讓 SDK 繼續
從已登入的身分推導身分資訊。

`ask_user` 使用 `SessionConfig.onUserInputRequest`。橋接器會將 SDK
選項或無選項的自由文字提示登錄為閘道問題；對固定選項要求，
接受選項索引或標籤；當 SDK 要求允許時，也接受自由格式的答案。
中止 OpenClaw 嘗試會取消
閘道記錄，並傳回空白的 SDK 答案。

## 相關內容

* [代理程式執行階段](/zh-TW/concepts/agent-runtimes)
* [Codex 執行框架](/zh-TW/plugins/codex-harness)
* [代理程式執行框架外掛（SDK 參考資料）](/zh-TW/plugins/sdk-agent-harness)
