Skip to content

[opencode 请求流程分析] OpenCode 请求流程与请求 Header 分析 (2026-07-18) #8

Description

@github-actions

近期相关变更

  • fix(provider): honor reasoning option semantics (#37519) — 修复 reasoning 选项语义,影响 ProviderTransform.providerOptions 下发逻辑
  • feat(session-ui): rewrite v2 prompt input (#37102) — Prompt 输入层重写,涉及 SessionV2 提交入口

1. 请求流程(时序)

架构分层

packages/opencode/src/session/
  llm.ts            ← 会话级编排(Runtime 路由选择:Native vs AI SDK)
  llm/request.ts    ← 参数/headers/tools 准备
  llm/native-runtime.ts ← 原生路由适配(实验性,需 flag)
  llm/native-request.ts ← AI SDK → LLMRequest 降型
  llm/ai-sdk.ts     ← AI SDK 流事件归一化

packages/llm/src/
  route/client.ts   ← LLMClient + Route.make(编译+执行)
  route/executor.ts ← HTTP 重试/错误映射
  route/transport/http.ts ← HTTP POST 构造
  route/auth.ts     ← 鉴权注入系统
  protocols/        ← 各 provider 协议(body 构造+流解析)
  providers/        ← provider 外观(endpoint/auth/model 配置)

关键步骤

步骤 说明 关键文件
1 Provider/Model 解析 Provider.Service.getProvider/getLanguage() 获取配置和 AI SDK 模型实例 session/llm.ts:run
2 鉴权凭据获取 Auth.Service.get(providerID) 从持久化存储/OAuth 读取凭据 session/llm.tsprovider/auth.ts
3 请求参数准备 LLMRequestPrep.prepare() 融合 system/messages/tools/params;构造会话级 headers;触发插件 chat.headers hook llm/request.ts:prepare
4 Runtime 路由选择 flags.experimentalNativeLlm=true 且 provider∈{openai,anthropic,opencode} 且有 apiKey → 原生路由;否则 → AI SDK session/llm.ts:220-280native-runtime.ts:status()
5 LLMRequest 构造 LLMNative.request() 将 ModelMessage/tools 降型为 LLMRequest schema llm/native-request.ts
6 路由编译 compile(): resolveRequestOptions → applyCachePolicy → route.body.from() 构造 provider body → route.prepareTransport() route/client.ts:compile
7 URL 构造 renderEndpoint() 渲染 baseURL+path;query 参数单独 append route/endpoint.tstransport/http.ts:applyQuery
8 Header 注入 jsonRequestParts() 合并静态路由 headers(如 anthropic-version)+ request.http.headers;再 Auth.toEffect(auth)() 注入凭据 transport/http.ts:jsonRequestParts
9 请求体序列化 Effect Schema Schema.encodeSync(Schema.fromJsonString(...)) 序列化 body;可通过 request.http.body 叠加(受 denylist 保护) route/client.ts:makeFromTransport
10 HTTP 发送+重试 RequestExecutor.execute() 通过 Effect HttpClient 发送;自动重试 429/503/504/529(最多 2 次,指数退避,尊重 retry-after) route/executor.ts:retryStatusFailures
11 流解析 framing.frame() 切帧(SSE/AWS event-stream)→ Schema 解码 → protocol.stream.step() 状态机产出 LLMEvent[] route/client.ts:streamPrepared

2. 请求 Header 明细

所有 Provider 公共

Header 取值 来源
content-type application/json protocols/shared.ts:jsonPost(硬编码)
User-Agent opencode/<version> llm/request.ts:USER_AGENT
x-session-affinity sessionID request.ts:191(非 opencode provider)
X-Session-Id sessionID request.ts:192
x-parent-session-id parentSessionID(可选) request.ts:193

Anthropic(`(api.anthropic.com/redacted)

Header 取值来源 说明
x-api-key ANTHROPIC_API_KEY / options.apiKey anthropic.ts:17Auth.header("x-api-key")
anthropic-version "2023-06-01"(硬编码) anthropic-messages.ts:852 route headers 函数

注: Anthropic 不用 Authorization: Bearer,专用 x-api-key

OpenAI((api.openai.com/redacted) 或 /chat/completions`)

Header 取值来源 说明
Authorization Bearer ${OPENAI_API_KEY} openai.tsAuthOptions.bearer(options, "OPENAI_API_KEY")

Azure OpenAI

端点:https://<resourceName>.openai.azure.com/openai/v1/responses?api-version=<ver>

Header 取值来源 说明
api-key AZURE_OPENAI_API_KEY / options.apiKey azure.ts:auth()Auth.header("api-key");同时 Auth.remove("authorization") 移除 Bearer

api-version 通过 URL 查询参数传递,不在 header 中。

Amazon Bedrock

端点:(bedrockruntime/redacted)<region>.amazonaws.com/model/<modelId>/converse-stream

Header 取值来源 说明
Authorization AWS4-HMAC-SHA256 Credential=.../Signature=... bedrock-auth.ts:signRequest 使用 aws4fetch.AwsV4Signer
x-amz-date SigV4 时间戳(自动生成) 防重放
x-amz-security-token sessionToken(STS 临时凭据,可选) 临时凭据标识
content-type application/json 先设置再签名(bedrock-auth.ts:sigV4)

若配置 options.apiKey 则退化为 Authorization: Bearer <apiKey>(跳过 SigV4)。

Google Gemini

端点:`(generativelanguage.googleapis.com/redacted)

Header 取值来源 说明
x-goog-api-key GOOGLE_GENERATIVE_AI_API_KEY / options.apiKey google.ts:17Auth.header("x-goog-api-key")

GitHub Copilot(baseURL 由调用方配置,无默认)

Header 取值来源 说明
Authorization Bearer (token) github-copilot.tsAuthOptions.bearer(options, [])

模型路由:gpt-5+(除 gpt-5-mini)走 Responses API,其余走 Chat Completions(shouldUseResponsesApi())。

OpenAI 兼容 / OpenRouter / xAI / Cloudflare Workers AI

Header 取值来源 说明
Authorization Bearer (apiKey) AuthOptions.bearer(options, "XAI_API_KEY"|"OPENROUTER_API_KEY"|"CLOUDFLARE_WORKERS_AI_TOKEN"...)

Cloudflare AI Gateway 额外:

Header 取值来源 说明
cf-aig-authorization Bearer (gatewayApiKey) cloudflare.ts:aiGatewayAuth()Auth.bearerHeader("cf-aig-authorization");fallback 到 CLOUDFLARE_API_TOKEN/CF_AIG_TOKEN
Authorization Bearer (apiKey)(后端 provider key) 后端鉴权

opencode 内部 Provider(providerID.startsWith("opencode"))

Header 取值来源
x-opencode-project InstanceState.context.project.id,request.ts:184
x-opencode-session sessionID,request.ts:185
x-opencode-request input.user.id,request.ts:186
x-opencode-client input.flags.client,request.ts:187

3. 鉴权机制

3.1 API Key 鉴权(大多数 provider)

AuthOptions.bearer(options, envVar)(auth-options.ts)统一封装:

  1. 先检查显式 auth override
  2. 再检查 options.apiKey
  3. Fallback 到 Config.redacted(envVar) 读环境变量
  4. 为空时 MissingCredentialErrorLLMError.Authentication.missing

Header 注入:Auth.bearer()Authorization: Bearer (key);Auth.header("name")name: (key)

3.2 AWS SigV4(Amazon Bedrock)

bedrock-auth.ts:sigV4(credentials) 返回 Auth.custom() 实例,每次请求调用 AwsV4Signer({url, method:"POST", headers, body, region, accessKeyId, secretAccessKey, sessionToken, service:"bedrock"}).sign(),签名结果(Authorizationx-amz-datex-amz-security-token)合并回 headers。content-type 必须在签名前设置。

3.3 OAuth(OpenAI)

Auth.Service.get(providerID) 读取 OAuth token;OpenAI OAuth 通过 provider.options.fetch 注入携带 token 的 fetch override,Native runtime 在有 fetch override 时支持 OAuth(native-runtime.ts:providerFetch)。

3.4 Plugin Headers

request.ts:prepare 触发 chat.headers hook,允许插件注入任意 header,通过 streamText({ headers })LLMRequest.http.headers 传递。


4. 关键代码位置索引

文件 关键符号
packages/opencode/src/session/llm.ts LLM.Service.stream — 编排入口,Runtime 路由选择
packages/opencode/src/session/llm/request.ts LLMRequestPrep.prepareUSER_AGENT
packages/opencode/src/session/llm/native-runtime.ts LLMNativeRuntime.stream/statusproviderFetch
packages/opencode/src/session/llm/native-request.ts LLMNative.request — LLMRequest 构造
packages/llm/src/route/client.ts Route.makeLLMClientcompile
packages/llm/src/route/executor.ts RequestExecutorretryStatusFailures
packages/llm/src/route/transport/http.ts httpJsonjsonRequestParts
packages/llm/src/route/auth.ts Auth.bearer/header/custom/toEffect
packages/llm/src/route/auth-options.ts AuthOptions.bearer
packages/llm/src/protocols/anthropic-messages.ts:852 anthropic-version: 2023-06-01 注册
packages/llm/src/protocols/utils/bedrock-auth.ts sigV4signRequest
packages/llm/src/providers/anthropic.ts:17 x-api-key 注入
packages/llm/src/providers/azure.ts:65 api-key + Auth.remove("authorization")
packages/llm/src/providers/google.ts:17 x-goog-api-key 注入
packages/llm/src/providers/cloudflare.ts:44 cf-aig-authorization 双重认证
packages/llm/src/protocols/shared.ts:314-322 jsonPostcontent-type 注入

Generated by Daily Upstream Sync + Request-Flow Analysis · 106.7 AIC · ⌖ 6.99 AIC · ⊞ 5.9K ·

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions