Get started
Обвязка Copilot SDK
Внешний plugin @openclaw/copilot позволяет OpenClaw выполнять встроенные агентские ходы Copilot по подписке через GitHub Copilot CLI (@github/copilot-sdk) вместо встроенного PI harness.
Используйте Copilot SDK harness, когда нужно, чтобы сеанс Copilot CLI владел низкоуровневым агентским циклом: нативное выполнение инструментов, нативная Compaction (infiniteSessions) и состояние потока, управляемое CLI, в copilotHome. OpenClaw по-прежнему владеет чат-каналами, файлами сеансов, выбором модели, динамическими инструментами OpenClaw (через мост), approvals, доставкой медиа, видимым зеркалом transcript, побочными вопросами /btw (обрабатываются встроенным PI fallback — см. Побочные вопросы (/btw)) и openclaw doctor.
Общее разделение моделей, провайдеров и runtime см. в разделе Агентские runtime.
Требования
- OpenClaw с установленным plugin
@openclaw/copilot. - Если ваша конфигурация использует
plugins.allow, включитеcopilot(id манифеста, объявленный plugin). Ограничительный allowlist, использующий npm-имя пакета@openclaw/copilot, оставит plugin заблокированным, и runtime не загрузится даже сagentRuntime.id: "copilot". - Подписка GitHub Copilot, которая может запускать Copilot CLI (или запись
gitHubTokenenv / auth-profile для headless / cron-запусков). - Доступный для записи каталог
copilotHome. По умолчанию harness использует<agentDir>/copilot, когда OpenClaw предоставляет каталог агента, иначе~/.openclaw/agents/<agentId>/copilotдля полной изоляции каждого агента.
openclaw doctor запускает doctor contract plugin для декларативного владения состоянием сеанса и будущих миграций совместимости. Он не запускает проверки окружения Copilot CLI.
Установка Plugin
Copilot runtime является внешним plugin, поэтому основной пакет openclaw не несет зависимость @github/copilot-sdk или ее платформенно-специфичный CLI-бинарник @github/copilot-<platform>-<arch>. Вместе они добавляют примерно 260 МБ, поэтому устанавливайте их только для агентов, которые явно выбирают этот runtime:
openclaw plugins install @openclaw/copilotМастер устанавливает plugin при первом выборе модели github-copilot/* и когда ваша конфигурация подключает модель (или ее провайдер) к агентскому runtime Copilot через agentRuntime: { id: "copilot" } (см. Быстрый старт ниже). Без явного подключения openclaw использует встроенный провайдер GitHub Copilot и никогда не устанавливает runtime plugin.
Runtime разрешает SDK в следующем порядке:
import("@github/copilot-sdk")из установленного пакета@openclaw/copilot.- Хорошо известный резервный каталог
~/.openclaw/npm-runtime/copilot/(устаревшая цель установки по требованию).
Отсутствующий SDK дает одну ошибку с кодом COPILOT_SDK_MISSING и командой переустановки plugin выше.
Быстрый старт
Закрепите одну модель (или одного провайдера) за harness:
{ agents: { defaults: { model: "github-copilot/auto", models: { "github-copilot/auto": { agentRuntime: { id: "copilot" }, }, }, }, },}Оба маршрута эквивалентны. Используйте agentRuntime.id в записи одной модели, когда только эта модель должна маршрутизироваться через harness; задайте agentRuntime.id на провайдере, когда все модели этого провайдера должны его использовать.
github-copilot/auto — переносимая отправная точка. Именованные модели Copilot зависят от политики учетной записи и организации, поэтому закрепляйте такую модель только после подтверждения, что аутентифицированный Copilot CLI ее предоставляет.
Поддерживаемые провайдеры
Harness объявляет поддержку канонического провайдера github-copilot (тот же id, которым владеет extensions/github-copilot):
github-copilot
Он также поддерживает пользовательские записи models.providers, когда выбранная модель имеет непустой baseUrl и одну из следующих форм API:
openai-responsesopenai-completionsollama(OpenAI-совместимые completions)azure-openai-responsesanthropic-messages
Нативные id провайдеров, такие как openai, anthropic, google и ollama, остаются во владении их нативных runtime. Используйте отдельный пользовательский id провайдера при маршрутизации endpoint через Copilot BYOK.
Copilot BYOK endpoints должны быть публичными HTTPS URL в сети. Harness передает Copilot SDK URL loopback-прокси для каждой попытки, затем пересылает трафик провайдера через защищенный путь fetch OpenClaw, чтобы DNS pinning и SSRF-политика оставались во владении OpenClaw. Используйте нативный runtime OpenClaw для локального Ollama, LM Studio или LAN-серверов моделей.
BYOK
Copilot BYOK использует контракт пользовательского провайдера уровня сеанса из SDK. OpenClaw передает разрешенный endpoint модели, API-ключ, режим bearer-token, заголовки, id модели и лимиты контекста/вывода, не перенося транспортную логику провайдера в core.
Например:
{ 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 ключуются отдельно от сеансов подписки и от других endpoints или отпечатков учетных данных. Ротация ключа, заголовков, модели или endpoint создает новый сеанс Copilot SDK вместо возобновления несовместимого состояния.
Аутентификация
Приоритет для каждого агента, применяемый во время runCopilotAttempt:
-
Явное
useLoggedInUser: trueво входных данных попытки. Использует вошедшего пользователя Copilot CLI, разрешенного вcopilotHomeагента. -
Явное
gitHubTokenво входных данных попытки (сprofileId+profileVersion). Полезно для прямых вызовов CLI и тестов, где вызывающая сторона хочет обойти разрешение auth-profile. -
Разрешенные контрактом
resolvedApiKey+authProfileIdиз формыEmbeddedRunAttemptParams. Это основной производственный путь: core разрешает настроенный для агента auth profilegithub-copilot(черезsrc/infra/provider-usage.auth.ts:resolveProviderAuths) перед вызовом harness, а harness напрямую потребляет оба поля. Благодаря этому auth profilegithub-copilot:<profile>работает end-to-end для headless / cron / многопрофильных конфигураций без env vars. -
Резервный env-var для прямых запусков CLI / dogfood, где auth profile не настроен. Runtime проверяет следующие переменные в порядке приоритета, отражая поставляемый провайдер
github-copilot(extensions/github-copilot/auth.ts) и документированную настройку Copilot SDK:OPENCLAW_GITHUB_TOKEN-- переопределение, специфичное для harness; задайте его, чтобы закрепить токен для OpenClaw harness, не затрагивая общесистемную конфигурациюgh/ Copilot CLI.COPILOT_GITHUB_TOKEN-- стандартная env var Copilot SDK / CLI.GH_TOKEN-- стандартная env varghCLI (совпадает с существующим приоритетом провайдераgithub-copilot).GITHUB_TOKEN-- общий резервный токен GitHub.
Побеждает первое непустое значение; пустые строки считаются отсутствующими. Синтезированный id профиля пула имеет вид
env:<NAME>, а profileVersion является необратимым sha256-отпечатком токена, поэтому ротация значения env корректно сбрасывает пул клиентов. -
useLoggedInUserпо умолчанию, когда сигнал токена недоступен.
Каждый агент получает выделенный copilotHome, поэтому токены, сеансы и конфигурация Copilot CLI не перетекают между агентами на одной машине. По умолчанию используется <agentDir>/copilot, когда хост передает harness каталог агента (изолируя состояние SDK от models.json / auth-profiles.json OpenClaw в том же каталоге), или ~/.openclaw/agents/<agentId>/copilot в остальных случаях. Переопределите через copilotHome: <path> во входных данных попытки, когда нужно пользовательское расположение (например, общий mount для миграции).
Live-тесты harness используют OPENCLAW_COPILOT_AGENT_LIVE_TOKEN, когда нужен прямой токен. Общая настройка live-тестов намеренно очищает COPILOT_GITHUB_TOKEN, GH_TOKEN и GITHUB_TOKEN после подготовки реальных auth profiles в изолированном тестовом home, поэтому передача значения gh auth token через выделенную переменную live-теста помогает избежать ложных пропусков, не раскрывая токен несвязанным наборам тестов.
Поверхность конфигурации
Harness читает свою конфигурацию из входных данных каждой попытки (runCopilotAttempt({...})) плюс небольшого набора env defaults внутри extensions/copilot/src/:
copilotHome— каталог состояния CLI для каждого агента (значения по умолчанию описаны выше).model— строка или{ provider, id, api?, baseUrl?, headers?, authHeader? }. Если опущено, OpenClaw использует обычный выбор модели агента, а harness проверяет, что разрешенный провайдер поддерживается.reasoningEffort—"low" | "medium" | "high" | "xhigh". Сопоставляется из разрешенияThinkLevel/ReasoningLevelOpenClaw вauto-reply/thinking.ts.infiniteSessionConfig— необязательное переопределение для блока SDKinfiniteSessions, которым управляетharness.compact. Значения по умолчанию безопасно оставлять как есть.hooksConfig— необязательная конфигурация совместимости нативного Copilot SDKSessionHooksдля обратных вызовов инструментов/MCP, пользовательского prompt, сеанса и ошибок. Она отделена от переносимых lifecycle hooks OpenClaw.permissionPolicy— необязательное переопределение обработчика SDKonPermissionRequest, используемого для встроенных видов инструментов SDK (shell,write,read,url,mcp,memory,hook). По умолчанию используетсяrejectAllPolicyкак защитная сетка; на практике SDK никогда не вызывает ни один из этих видов, потому что каждый подключенный через мост инструмент OpenClaw зарегистрирован сoverridesBuiltInTool: trueиskipPermission: true, поэтому 100% вызовов инструментов проходят через обернутый OpenClawexecute(). См. Разрешения и ask_user.enableSessionTelemetry— необязательный флаг телеметрии сеанса SDK.
Hooks plugin OpenClaw не требуют специфичной для Copilot конфигурации попытки. Harness запускает before_prompt_build (и устаревший compatibility hook before_agent_start), llm_input, llm_output и agent_end через стандартные helpers harness. Успешные Compaction SDK также запускают before_compaction и after_compaction. Подключенные через мост инструменты OpenClaw продолжают запускать before_tool_call и сообщать after_tool_call; hooksConfig остается для нативных callback только SDK, у которых нет переносимого эквивалента.
Остальным частям OpenClaw не нужно знать об этих полях. Другие plugins, каналы и core-код видят только стандартную форму AgentHarnessAttemptParams / AgentHarnessAttemptResult.
Compaction
Когда выполняется harness.compact, Copilot SDK harness:
- Возобновляет отслеживаемый сеанс SDK без продолжения ожидающей работы.
- Вызывает RPC сжатия истории, scoped to session, из SDK.
- Возвращает результат Compaction SDK без записи файлов-маркеров совместимости в рабочей области.
Зеркало transcript на стороне OpenClaw (см. ниже) продолжает получать сообщения после Compaction, поэтому пользовательская история чата остается согласованной.
Зеркалирование transcript
runCopilotAttempt выполняет двойную запись mirrorable-сообщений каждого хода в audit transcript OpenClaw через extensions/copilot/src/dual-write-transcripts.ts. Зеркало scoped to session (copilot:${sessionId}) и использует идентичность сообщения (${role}:${sha256_16(role,content)}), чтобы повторные эмиты записей предыдущих ходов сталкивались с существующими on-disk keys и не дублировались.
Зеркало обернуто двумя уровнями containment отказов, поэтому сбой записи transcript не может провалить попытку: внутренней best-effort-оберткой и defense-in-depth .catch(...) на уровне попытки. Сбои логируются, но не выводятся наружу.
Побочные вопросы (/btw)
/btw не является нативной функцией в этом harness. createCopilotAgentHarness()
намеренно оставляет harness.runSideQuestion неопределенным, поэтому диспетчер
OpenClaw для /btw (src/agents/btw.ts) переходит к тому же встроенному
резервному пути PI, который используется для любой среды выполнения, отличной
от Codex: настроенный поставщик модели вызывается напрямую с коротким промптом
для дополнительного вопроса, а ответ передается потоково через streamSimple
(без CLI-сессии и без дополнительного слота в пуле).
Так CLI-сессии Copilot остаются зарезервированными для основного цикла хода
агента, а поведение /btw остается идентичным другим средам выполнения на базе
PI. Контракт проверяется в
extensions/copilot/harness.test.ts
в разделе describe("runSideQuestion").
Doctor
extensions/copilot/doctor-contract-api.ts автоматически загружается
src/plugins/doctor-contract-registry.ts. Он добавляет:
- Пустой
legacyConfigRules(на этапе MVP нет устаревших полей). normalizeCompatibilityConfigбез действий (оставлен, чтобы у будущих выводов полей из эксплуатации было стабильное встроенное место).- Одну запись
sessionRouteStateOwners, заявляющую поставщикаgithub-copilot; среду выполненияcopilot; ключ CLI-сессииcopilot; префикс профиля авторизацииgithub-copilot:.
Ограничения
- Harness заявляет
github-copilotплюс непринадлежащие пользовательские идентификаторы поставщиков BYOK. Нативные идентификаторы поставщиков, принадлежащие манифесту, остаются на своей среде выполнения даже когдаagentRuntime.idпринудительно установлен вcopilot. - Harness не предоставляет TUI; TUI в PI не затрагивается и остается резервным вариантом для любых сред выполнения, у которых нет парной поверхности.
- Состояние PI-сессии не мигрируется, когда агент переключается на
copilot. Выбор выполняется для каждой попытки; существующие PI-сессии остаются действительными. ask_userиспользует тот же путь OpenClaw с промптом и ответом, что и harness Codex. Когда Copilot SDK запрашивает ввод пользователя, OpenClaw публикует блокирующий промпт в активный канал/TUI, а следующее сообщение пользователя в очереди завершает запрос SDK.
Разрешения и ask_user
Применение разрешений для мостовых инструментов OpenClaw происходит
внутри обертки инструмента, а не через callback onPermissionRequest
в SDK. Тот же wrapToolWithBeforeToolCallHook, который использует PI
(src/agents/pi-tools.before-tool-call.ts), применяется
createOpenClawCodingTools ко всем инструментам для кодинга: обнаружение
циклов, политики доверенных Plugin, хуки before-tool-call и двухфазные
подтверждения Plugin через Gateway (plugin.approval.request) выполняются
тем же самым путем кода, что и в нативных попытках PI.
Чтобы эта обертка владела решением, SDK Tool, возвращаемый
convertOpenClawToolToSdkTool, помечается так:
overridesBuiltInTool: true— заменяет встроенный инструмент Copilot CLI с тем же именем (edit, read, write, bash, …), чтобы каждый вызов инструмента маршрутизировался обратно в OpenClaw.skipPermission: true— сообщает SDK не вызыватьonPermissionRequest({kind: "custom-tool"})перед вызовом инструмента. Обернутыйexecute()выполняет более богатую проверку политики OpenClaw внутри; промпт уровня SDK либо обошел бы применение правил OpenClaw (если разрешить все), либо блокировал бы каждый вызов инструмента (если отклонять все) — ни один вариант не соответствует паритету с PI.
Встроенный harness 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 — политика rejectAllPolicy, которая закрывается отказом для любого вида,
отличного от custom-tool, если он когда-либо дойдет до onPermissionRequest,
— является той же защитной сеткой, и на практике она не срабатывает, потому что
overridesBuiltInTool: true вытесняет каждый встроенный инструмент.
Чтобы слой обернутых инструментов принимал решения по политикам, эквивалентные
PI, harness передает полный контекст инструмента попытки PI в
createOpenClawCodingTools — идентичность (senderIsOwner,
memberRoleIds, ownerOnlyToolAllowlist, …), канал/маршрутизацию
(groupId, currentChannelId, replyToMode, переключатели
message-tool), авторизацию (authProfileStore), идентичность запуска
(sessionKey/runSessionKey, полученные из sandboxSessionKey,
runId), контекст модели (modelApi, modelContextWindowTokens,
modelCompat, modelHasVision) и хуки запуска (onToolOutcome,
onYield). Без этих полей allowlist только для владельца незаметно
ведут себя как deny-by-default, политики доверия Plugin не могут разрешиться
в правильную область, а session_status: "current" разрешается в устаревший
ключ sandbox. Сборщик моста находится в
extensions/copilot/src/tool-bridge.ts и зеркалирует авторитетный вызов PI
в src/agents/pi-embedded-runner/run/attempt.ts:1029-1117. runAttempt
уже разрешает контекст sandbox через общий seam resolveSandboxContext,
передает SDK эффективный рабочий каталог и пересылает sandbox вместе с
рабочим пространством subagent-spawn в мост инструментов. Мост также передает
ограниченные элементы управления построением инструментов, которые он может
обеспечить на границе SDK: includeCoreTools, allowlist инструментов среды
выполнения и toolConstructionPlan.
Мост также использует общий вспомогательный инструмент поверхности инструментов
harness из openclaw/plugin-sdk/agent-harness-tool-runtime для паритета с PI.
Когда включен поиск инструментов, SDK видит компактные управляющие инструменты
плюс скрытый исполнитель каталога вместо каждой схемы инструмента OpenClaw.
Когда включен режим кода, вспомогательный модуль строит ту же управляющую
поверхность режима кода и жизненный цикл каталога, которые используются
другими agent harness. Экономные настройки по умолчанию для локальных моделей,
фильтрация схем, совместимая со средой выполнения, гидратация каталогов и
очистка каталога остаются в общем вспомогательном модуле, чтобы harness Copilot
и соседние с Codex harness не расходились.
Токен GitHub уровня сессии
Контракт Copilot SDK различает GitHub-токен уровня клиента
(CopilotClientOptions.gitHubToken, используется для аутентификации самого
процесса CLI) и токен уровня сессии
(SessionConfig.gitHubToken, который определяет исключение контента,
маршрутизацию модели и квоту для этой сессии и учитывается как при
createSession, так и при resumeSession). Harness один раз разрешает
авторизацию через resolveCopilotAuth и задает оба поля, когда режим
авторизации равен gitHubToken (явный auth.gitHubToken или
resolvedApiKey, разрешенный по контракту из настроенного профиля авторизации
github-copilot). Когда разрешенный режим равен useLoggedInUser, поле
уровня сессии опускается, чтобы SDK продолжал выводить идентичность из
вошедшей учетной записи.
ask_user использует SessionConfig.onUserInputRequest. Мост принимает
индексы или метки вариантов для запросов с фиксированным выбором, принимает
ответы в свободной форме, когда запрос SDK их допускает, и отменяет ожидающий
запрос, когда попытка OpenClaw прерывается.