本报告基于当前 dev 分支代码(已与上游 anomalyco/opencode 同步至 8a03fc265)。仅做只读分析,未修改任何业务代码。
0. 本次同步提示
本次从上游同步进来 6 个提交 (d09d5612f..8a03fc265):
SHA
提交
8a03fc265
feat(app): extract prompt state and add composer model selection (anomalyco#36227 )
d0ba53892
zen: track openai cache_write_tokens
772e976d8
fix(app): timeline width jumps around when review panel is open/closed (anomalyco#36202 )
c76938077
feat(app): visual improvements (anomalyco#36073 )
01131c75d
fix(app): focus input on new session (anomalyco#36077 )
ea982c383
fix(app): wrap session creation state updates in startTransition (anomalyco#36182 )
这些提交集中在 packages/app(UI/会话交互)与 zen 计费统计,均未触及 GitHub Copilot 的请求流程 / Header / Body 。故本报告结论相对上一次分析无变化。
1. 入口与整体架构
GitHub Copilot 的集成主要由一个插件驱动:
packages/opencode/src/plugin/github-copilot/copilot.ts —— CopilotAuthPlugin,负责鉴权(OAuth 设备码流程)、请求 fetch 包装(注入 Header)、模型列表拉取、以及 chat.params / chat.headers 钩子。注册于 packages/opencode/src/plugin/index.ts:15,72。
packages/opencode/src/plugin/github-copilot/models.ts —— 拉取 {base}/models 并根据 supported_endpoints 决定每个模型走哪个端点(messages / responses / chat)及使用哪个 ai-sdk 包。
packages/core/src/github-copilot/ —— OpenAI 兼容的 Chat / Responses 语言模型实现(真正构造 HTTP body 的地方)。
packages/llm/src/providers/github-copilot.ts 与 packages/core/src/plugin/provider/github-copilot.ts —— v2/effect 架构下的路由与端点选择。
Base URL (copilot.ts:26-28):
公有云:https://api.githubcopilot.com
企业版(GHE):https://copilot-api.<归一化后的企业域名>
端点与 npm 适配 (models.ts:92-111):
模型 supported_endpoints
endpoint
api.npm
实际路径
含 /v1/messages
messages
@ai-sdk/anthropic
https://api.githubcopilot.com/v1/messages
含 /responses
responses
@ai-sdk/github-copilot
.../responses
含 /chat/completions
chat
@ai-sdk/github-copilot
.../chat/completions
GPT‑5 类模型(gpt-N,N≥5,且非 gpt-5-mini)默认走 Responses API,否则走 Chat Completions —— shouldUseResponsesApi(packages/llm/src/providers/github-copilot.ts:19-25;packages/core/src/plugin/provider/github-copilot.ts:42-48)。
2. GitHub 身份验证与 Token 交换流程
采用 OAuth 2.0 设备授权码流程(Device Authorization Grant, RFC 8628) ,全部实现在 copilot.ts 的 auth.methods[0](copilot.ts:182-337)。
关键常量:CLIENT_ID = "Ov23li8tweQw6odWQebz"(copilot.ts:9),scope = "read:user"(copilot.ts:244)。
sequenceDiagram
participant U as 用户
participant OC as opencode (CopilotAuthPlugin)
participant GH as github.com (OAuth)
participant API as api.githubcopilot.com
Note over OC: authorize() copilot.ts:222
OC->>GH: POST /login/device/code<br/>{client_id, scope:"read:user"}
GH-->>OC: {device_code, user_code, verification_uri, interval}
OC-->>U: 显示 verification_uri + user_code
U->>GH: 浏览器打开并输入 user_code
Note over OC: callback() 轮询 copilot.ts:262
loop 每 interval(+3s) 秒
OC->>GH: POST /login/oauth/access_token<br/>{client_id, device_code,<br/>grant_type: device_code}
GH-->>OC: authorization_pending / slow_down / access_token
end
GH-->>OC: {access_token}
Note over OC: 存储 oauth{access=refresh=token, expires:0}<br/>provider/auth.ts:211-220
Note over OC,API: 后续每次推理请求
OC->>API: POST /chat|responses|v1/messages<br/>Authorization: Bearer GitHub-OAuth-token
API-->>OC: SSE 流式响应
Loading
要点:
设备码申请 (copilot.ts:234-256):POST https://{domain}/login/device/code,请求体 { client_id, scope: "read:user" }。企业版 domain 来自用户输入的 enterpriseUrl(copilot.ts:222-232)。
轮询换取 access_token (copilot.ts:262-333):POST https://{domain}/login/oauth/access_token,请求体 { client_id, device_code, grant_type: "urn:ietf:params:oauth:grant-type:device_code" };正确处理 authorization_pending、slow_down(按 RFC 8628 §3.5 增加 5s,并叠加 3s 安全余量 OAUTH_POLLING_SAFETY_MARGIN_MS)。
凭据落库 (copilot.ts:286-305 → provider/auth.ts:188-221):成功后写入 auth.json,类型 oauth,access = refresh = <GitHub OAuth token>,expires: 0,企业版另存 enterpriseUrl。
⚠️ 关于「Token 交换」的重要结论
当前代码不存在把 GitHub OAuth token 兑换成短时 Copilot token 的步骤。 全仓库检索确认 没有 对 https://api.github.com/copilot_internal/v2/token 之类端点的调用(git grep copilot_internal / api.github.com 无命中)。opencode 直接把设备码流程拿到的 GitHub OAuth 访问令牌 作为 Bearer 令牌发给 api.githubcopilot.com。
令牌注入位置:鉴权 loader 返回 { apiKey: "", fetch },其包装 fetch 在每次请求里设置 Authorization: Bearer <access>(copilot.ts:96-180,第 164 行)。
getAuth() 只是读取已存储的凭据(provider/auth.ts → provider.ts:1543),不做刷新 ;Copilot 的 auth 方法里 没有 refresh 回调 ,expires:0 也不会触发轮换。
对 OAuth 类 provider,provider.ts:893-915 明确「只用插件 auth loader 的合并 fetch」,跳过 provider 级 fetch,因此上面的 Header 集合就是最终生效版本。
3. 客户端发送给 GitHub Copilot 的 Request Header
推理请求的最终 Header 由两处叠加而成:chat.headers 钩子(copilot.ts:360-411,其输出经 request.ts:134-146 传入 ai-sdk 的 options.headers)+ 鉴权 loader 的包装 fetch(copilot.ts:160-173,最后一道、优先级最高)。
3.1 推理请求(/chat/completions、/responses、/v1/messages 通用)
Header
取值
来源(代码位置)
作用 / 说明
Authorization
Bearer <GitHub OAuth token>
copilot.ts:164(强制覆盖)
鉴权;直接使用 GitHub OAuth 令牌
User-Agent
opencode/<InstallationVersion>
copilot.ts:163(强制覆盖)
客户端标识
Openai-Intent
conversation-edits
copilot.ts:165
Copilot 意图标记
x-initiator
user 或 agent
copilot.ts:161;可被 chat.headers 覆盖(:394,:411)
标记请求由用户还是 agent 发起;依据「最后一条消息角色 / 合成图片消息 / tool_result / 压缩续跑 / 子 agent 会话」判定
X-GitHub-Api-Version
2026-06-01
copilot.ts:363(API_VERSION,:10)
Copilot API 版本
X-Interaction-Type
agent-session-name-generation
copilot.ts:364-366
仅在 title(会话命名)agent 时添加
anthropic-beta
interleaved-thinking-2025-05-14
copilot.ts:368-370
仅当模型走 @ai-sdk/anthropic(即 Claude 走 /v1/messages)时添加
Copilot-Vision-Request
true
copilot.ts:168-170
仅当请求体包含图片(vision)时添加
Content-Type
application/json
ai-sdk postJsonToApi
JSON 请求体
x-api-key / authorization(小写)
—(删除)
copilot.ts:172-173
主动剔除,避免与 Authorization 冲突
provider.options.headers.*
用户配置
copilot.ts:162 展开 init.headers
允许通过配置追加自定义 Header
Header 优先级:包装 fetch 里 User-Agent、Authorization、Openai-Intent 位于 ...init.headers 展开之后,始终覆盖 上游值;而 x-initiator 位于展开之前,故 chat.headers 钩子设置的 x-initiator 会生效。
说明:opencode 有意不发送 GitHub 官方 Copilot 客户端常见的 Editor-Version、Editor-Plugin-Version、Copilot-Integration-Id 等 Header(全仓库无命中),使用的是上面这套精简自定义 Header。
3.2 拉取模型列表请求(GET {base}/models)
见 copilot.ts:62-92 与 models.ts:213-226:
Header
取值
说明
Authorization
Bearer <GitHub OAuth token>
copilot.ts:74
User-Agent
opencode/<InstallationVersion>
copilot.ts:75
X-GitHub-Api-Version
2026-06-01
copilot.ts:76
provider.options.headers.*
用户配置
copilot.ts:73
3.3 设备码流程请求(github.com)
见 copilot.ts:236-240 与 :266-270:Accept: application/json、Content-Type: application/json、User-Agent: opencode/<InstallationVersion>。
4. 客户端发送给 GitHub Copilot 的 Request Body
请求体由 ai-sdk 语言模型类构造,通用参数先经 chat.params 钩子(copilot.ts:340-354)与 request.ts:114-175 处理:
GPT 系列模型 省略 max_tokens (chat.params 里 maxOutputTokens=undefined,copilot.ts:343-346)。
走 @ai-sdk/anthropic 的模型关闭 eager_input_streaming(toolStreaming=false,copilot.ts:351-353),以兼容 Copilot 的 /v1/messages shim。
回放历史 tool 调用但当前无启用工具时,注入占位 _noop 工具以满足 Copilot 对 tools 字段的要求(request.ts:159-175)。
通用参数 temperature / topP / topK / maxOutputTokens 来自 ProviderTransform(request.ts:124-129)。
4.1 Chat Completions(POST /chat/completions)
构造于 packages/core/src/github-copilot/chat/openai-compatible-chat-language-model.ts:139-212(流式 doStream 见 :306-320,追加 stream:true 及 stream_options):
主要字段:model、messages(convertToOpenAICompatibleChatMessages(prompt))、tools、tool_choice、max_tokens、temperature、top_p、frequency_penalty、presence_penalty、response_format(json_schema/json_object)、stop、seed、reasoning_effort、verbosity、thinking_budget、user,以及 provider options 透传字段。
4.2 Responses API(POST /responses)
构造于 packages/core/src/github-copilot/responses/openai-responses-language-model.ts:253-300(路径 :382-396、流式 :781-788 stream:true):
主要字段:model、input、temperature、top_p、max_output_tokens、text{format,verbosity}、tools、tool_choice、reasoning{effort,summary}、include、store(默认 true,:206)、previous_response_id、parallel_tool_calls、max_tool_calls、metadata、prompt_cache_key、safety_identifier、service_tier、user、instructions、top_logprobs。
4.3 Messages API(POST /v1/messages,Claude 系模型)
模型 api.npm = @ai-sdk/anthropic、base 为 {base}/v1(models.ts:109-110)。请求体为 Anthropic Messages 格式 ,由 @ai-sdk/anthropic 生成;opencode 侧通过 chat.params 关闭 toolStreaming,并补 anthropic-beta: interleaved-thinking-2025-05-14 Header。
5. 关键代码位置索引
主题
文件:行
Copilot 插件(鉴权/fetch/hooks)
packages/opencode/src/plugin/github-copilot/copilot.ts(:9-28 常量/Base、:56-93 models、:96-181 loader+fetch、:182-337 OAuth 设备码、:340-354 chat.params、:360-411 chat.headers)
模型列表 + 端点映射
packages/opencode/src/plugin/github-copilot/models.ts:82-256
插件注册
packages/opencode/src/plugin/index.ts:15,72
OAuth 回调落库
packages/opencode/src/provider/auth.ts:188-221
Provider 装配 / OAuth fetch 选择
packages/opencode/src/provider/provider.ts:131-132,225,893-915,1531-1550,1720-1751
body/headers 组装管线
packages/opencode/src/session/llm/request.ts:114-175
OpenAI 兼容 Provider 工厂
packages/core/src/github-copilot/copilot-provider.ts
Chat 语言模型(/chat/completions)
packages/core/src/github-copilot/chat/openai-compatible-chat-language-model.ts:139-212,306-320
Responses 语言模型(/responses)
packages/core/src/github-copilot/responses/openai-responses-language-model.ts:206,253-300,382-396,781-788
v2 端点选择
packages/core/src/plugin/provider/github-copilot.ts:20-50 / packages/llm/src/providers/github-copilot.ts:19-64
结论摘要
鉴权 :GitHub 设备码 OAuth → 拿到 GitHub OAuth 访问令牌并原样存储(expires:0,不刷新、无 Copilot token 兑换)。
Header :Authorization: Bearer <GH token>、User-Agent: opencode/<ver>、Openai-Intent、x-initiator、X-GitHub-Api-Version: 2026-06-01 为核心,另有 X-Interaction-Type / anthropic-beta / Copilot-Vision-Request 条件性追加。
Body :按模型分别走 /chat/completions(OpenAI 兼容)、/responses(OpenAI Responses)、/v1/messages(Anthropic shim)三种形态,字段由 packages/core/src/github-copilot/* 构造,并经 chat.params 做 Copilot 适配。
0. 本次同步提示
本次从上游同步进来 6 个提交(
d09d5612f..8a03fc265):8a03fc265d0ba53892772e976d8c7693807701131c75dea982c383这些提交集中在
packages/app(UI/会话交互)与 zen 计费统计,均未触及 GitHub Copilot 的请求流程 / Header / Body。故本报告结论相对上一次分析无变化。1. 入口与整体架构
GitHub Copilot 的集成主要由一个插件驱动:
packages/opencode/src/plugin/github-copilot/copilot.ts——CopilotAuthPlugin,负责鉴权(OAuth 设备码流程)、请求fetch包装(注入 Header)、模型列表拉取、以及chat.params/chat.headers钩子。注册于packages/opencode/src/plugin/index.ts:15,72。packages/opencode/src/plugin/github-copilot/models.ts—— 拉取{base}/models并根据supported_endpoints决定每个模型走哪个端点(messages/responses/chat)及使用哪个 ai-sdk 包。packages/core/src/github-copilot/—— OpenAI 兼容的 Chat / Responses 语言模型实现(真正构造 HTTP body 的地方)。packages/llm/src/providers/github-copilot.ts与packages/core/src/plugin/provider/github-copilot.ts—— v2/effect 架构下的路由与端点选择。Base URL(
copilot.ts:26-28):https://api.githubcopilot.comhttps://copilot-api.<归一化后的企业域名>端点与 npm 适配(
models.ts:92-111):supported_endpoints/v1/messagesmessages@ai-sdk/anthropichttps://api.githubcopilot.com/v1/messages/responsesresponses@ai-sdk/github-copilot.../responses/chat/completionschat@ai-sdk/github-copilot.../chat/completionsGPT‑5 类模型(
gpt-N,N≥5,且非gpt-5-mini)默认走 Responses API,否则走 Chat Completions ——shouldUseResponsesApi(packages/llm/src/providers/github-copilot.ts:19-25;packages/core/src/plugin/provider/github-copilot.ts:42-48)。2. GitHub 身份验证与 Token 交换流程
采用 OAuth 2.0 设备授权码流程(Device Authorization Grant, RFC 8628),全部实现在
copilot.ts的auth.methods[0](copilot.ts:182-337)。关键常量:
CLIENT_ID = "Ov23li8tweQw6odWQebz"(copilot.ts:9),scope = "read:user"(copilot.ts:244)。sequenceDiagram participant U as 用户 participant OC as opencode (CopilotAuthPlugin) participant GH as github.com (OAuth) participant API as api.githubcopilot.com Note over OC: authorize() copilot.ts:222 OC->>GH: POST /login/device/code<br/>{client_id, scope:"read:user"} GH-->>OC: {device_code, user_code, verification_uri, interval} OC-->>U: 显示 verification_uri + user_code U->>GH: 浏览器打开并输入 user_code Note over OC: callback() 轮询 copilot.ts:262 loop 每 interval(+3s) 秒 OC->>GH: POST /login/oauth/access_token<br/>{client_id, device_code,<br/>grant_type: device_code} GH-->>OC: authorization_pending / slow_down / access_token end GH-->>OC: {access_token} Note over OC: 存储 oauth{access=refresh=token, expires:0}<br/>provider/auth.ts:211-220 Note over OC,API: 后续每次推理请求 OC->>API: POST /chat|responses|v1/messages<br/>Authorization: Bearer GitHub-OAuth-token API-->>OC: SSE 流式响应要点:
copilot.ts:234-256):POST https://{domain}/login/device/code,请求体{ client_id, scope: "read:user" }。企业版domain来自用户输入的enterpriseUrl(copilot.ts:222-232)。copilot.ts:262-333):POST https://{domain}/login/oauth/access_token,请求体{ client_id, device_code, grant_type: "urn:ietf:params:oauth:grant-type:device_code" };正确处理authorization_pending、slow_down(按 RFC 8628 §3.5 增加 5s,并叠加 3s 安全余量OAUTH_POLLING_SAFETY_MARGIN_MS)。copilot.ts:286-305→provider/auth.ts:188-221):成功后写入auth.json,类型oauth,access = refresh = <GitHub OAuth token>,expires: 0,企业版另存enterpriseUrl。当前代码不存在把 GitHub OAuth token 兑换成短时 Copilot token 的步骤。 全仓库检索确认 没有 对
https://api.github.com/copilot_internal/v2/token之类端点的调用(git grep copilot_internal/api.github.com无命中)。opencode 直接把设备码流程拿到的 GitHub OAuth 访问令牌 作为Bearer令牌发给api.githubcopilot.com。loader返回{ apiKey: "", fetch },其包装fetch在每次请求里设置Authorization: Bearer <access>(copilot.ts:96-180,第 164 行)。getAuth()只是读取已存储的凭据(provider/auth.ts→provider.ts:1543),不做刷新;Copilot 的 auth 方法里 没有refresh回调,expires:0也不会触发轮换。provider.ts:893-915明确「只用插件 auth loader 的合并 fetch」,跳过 provider 级 fetch,因此上面的 Header 集合就是最终生效版本。3. 客户端发送给 GitHub Copilot 的 Request Header
推理请求的最终 Header 由两处叠加而成:
chat.headers钩子(copilot.ts:360-411,其输出经request.ts:134-146传入 ai-sdk 的options.headers)+ 鉴权loader的包装fetch(copilot.ts:160-173,最后一道、优先级最高)。3.1 推理请求(/chat/completions、/responses、/v1/messages 通用)
AuthorizationBearer <GitHub OAuth token>copilot.ts:164(强制覆盖)User-Agentopencode/<InstallationVersion>copilot.ts:163(强制覆盖)Openai-Intentconversation-editscopilot.ts:165x-initiatoruser或agentcopilot.ts:161;可被chat.headers覆盖(:394,:411)X-GitHub-Api-Version2026-06-01copilot.ts:363(API_VERSION,:10)X-Interaction-Typeagent-session-name-generationcopilot.ts:364-366title(会话命名)agent 时添加anthropic-betainterleaved-thinking-2025-05-14copilot.ts:368-370@ai-sdk/anthropic(即 Claude 走/v1/messages)时添加Copilot-Vision-Requesttruecopilot.ts:168-170Content-Typeapplication/jsonpostJsonToApix-api-key/authorization(小写)copilot.ts:172-173Authorization冲突provider.options.headers.*copilot.ts:162展开init.headers3.2 拉取模型列表请求(GET
{base}/models)见
copilot.ts:62-92与models.ts:213-226:AuthorizationBearer <GitHub OAuth token>copilot.ts:74User-Agentopencode/<InstallationVersion>copilot.ts:75X-GitHub-Api-Version2026-06-01copilot.ts:76provider.options.headers.*copilot.ts:733.3 设备码流程请求(github.com)
见
copilot.ts:236-240与:266-270:Accept: application/json、Content-Type: application/json、User-Agent: opencode/<InstallationVersion>。4. 客户端发送给 GitHub Copilot 的 Request Body
请求体由 ai-sdk 语言模型类构造,通用参数先经
chat.params钩子(copilot.ts:340-354)与request.ts:114-175处理:max_tokens(chat.params里maxOutputTokens=undefined,copilot.ts:343-346)。@ai-sdk/anthropic的模型关闭eager_input_streaming(toolStreaming=false,copilot.ts:351-353),以兼容 Copilot 的/v1/messagesshim。_noop工具以满足 Copilot 对tools字段的要求(request.ts:159-175)。temperature / topP / topK / maxOutputTokens来自ProviderTransform(request.ts:124-129)。4.1 Chat Completions(
POST /chat/completions)构造于
packages/core/src/github-copilot/chat/openai-compatible-chat-language-model.ts:139-212(流式doStream见:306-320,追加stream:true及stream_options):主要字段:
model、messages(convertToOpenAICompatibleChatMessages(prompt))、tools、tool_choice、max_tokens、temperature、top_p、frequency_penalty、presence_penalty、response_format(json_schema/json_object)、stop、seed、reasoning_effort、verbosity、thinking_budget、user,以及provider options透传字段。4.2 Responses API(
POST /responses)构造于
packages/core/src/github-copilot/responses/openai-responses-language-model.ts:253-300(路径:382-396、流式:781-788stream:true):主要字段:
model、input、temperature、top_p、max_output_tokens、text{format,verbosity}、tools、tool_choice、reasoning{effort,summary}、include、store(默认true,:206)、previous_response_id、parallel_tool_calls、max_tool_calls、metadata、prompt_cache_key、safety_identifier、service_tier、user、instructions、top_logprobs。4.3 Messages API(
POST /v1/messages,Claude 系模型)模型
api.npm = @ai-sdk/anthropic、base 为{base}/v1(models.ts:109-110)。请求体为 Anthropic Messages 格式,由@ai-sdk/anthropic生成;opencode 侧通过chat.params关闭toolStreaming,并补anthropic-beta: interleaved-thinking-2025-05-14Header。5. 关键代码位置索引
packages/opencode/src/plugin/github-copilot/copilot.ts(:9-28常量/Base、:56-93models、:96-181loader+fetch、:182-337OAuth 设备码、:340-354chat.params、:360-411chat.headers)packages/opencode/src/plugin/github-copilot/models.ts:82-256packages/opencode/src/plugin/index.ts:15,72packages/opencode/src/provider/auth.ts:188-221packages/opencode/src/provider/provider.ts:131-132,225,893-915,1531-1550,1720-1751packages/opencode/src/session/llm/request.ts:114-175packages/core/src/github-copilot/copilot-provider.tspackages/core/src/github-copilot/chat/openai-compatible-chat-language-model.ts:139-212,306-320packages/core/src/github-copilot/responses/openai-responses-language-model.ts:206,253-300,382-396,781-788packages/core/src/plugin/provider/github-copilot.ts:20-50/packages/llm/src/providers/github-copilot.ts:19-64结论摘要
expires:0,不刷新、无 Copilot token 兑换)。Authorization: Bearer <GH token>、User-Agent: opencode/<ver>、Openai-Intent、x-initiator、X-GitHub-Api-Version: 2026-06-01为核心,另有X-Interaction-Type/anthropic-beta/Copilot-Vision-Request条件性追加。/chat/completions(OpenAI 兼容)、/responses(OpenAI Responses)、/v1/messages(Anthropic shim)三种形态,字段由packages/core/src/github-copilot/*构造,并经chat.params做 Copilot 适配。