Skip to content

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

Description

@github-actions

近期变更

近期同步 upstream 的相关提交(不影响 Header 结构,主要是请求体构造层面):

  • 20589d6 fix(provider): preserve Mistral reasoning history
  • fada1a5 fix(provider): serialize Mistral prompt cache keys
  • 542ba88 fix(provider): select prompt cache keys by SDK

一、请求流程

分层架构

  • 会话编排层:opencode/src/session/llm.ts — 决定走 Native runtime 还是 AI SDK path
  • 降级适配层:session/llm/native-request.ts — ModelMessage[] → LLMRequest
  • 核心执行层:@opencode-ai/llm(packages/llm/src/)

请求时序

sequenceDiagram
    participant Session as session/llm.ts
    participant LLMClient as route/client.ts (LLMClient)
    participant Protocol as Protocol.body.from
    participant Transport as HttpTransport
    participant Auth as Auth.apply
    participant Executor as RequestExecutor
    participant Provider as LLM Provider

    Session->>LLMClient: LLMClient.stream(llmRequest)
    LLMClient->>LLMClient: compile() — 合并 route/model/request defaults + applyCachePolicy
    LLMClient->>Protocol: route.body.from(resolved) — 构造 provider-native body
    LLMClient->>Transport: route.prepareTransport(body, resolved)
    Transport->>Transport: renderEndpoint() — 拼接 URL(含 query params)
    Transport->>Auth: Auth.apply({ request, url, body, headers })
    Auth-->>Transport: 注入鉴权 Header
    Transport->>Executor: RequestExecutor.execute(httpClientRequest)
    Executor->>Provider: POST endpoint (SSE / AWS event-stream)
    Provider-->>Executor: 200 流式响应
    Executor-->>LLMClient: Stream<LLMEvent>(Framing → Protocol.stream.step 解析)
Loading

Header 注入顺序

jsonRequestParts() [transport/http.ts]
  1. Headers.fromInput({ ...route.headers(request), ...request.http.headers })
  2. Auth.toEffect(auth)({ request, url, body, headers })   ← 注入凭据 Header
  3. ProviderShared.jsonPost(...)                           ← 追加 content-type: application/json

错误重试(route/executor.ts:retryStatusFailures)

状态码 429/503/504/529 自动重试,最多 2 次,尊重 retry-after / retry-after-ms 响应头。


二、请求 Header 明细

Anthropic(protocols/anthropic-messages.ts:845)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost:322 application/json
anthropic-version anthropic-messages.ts:852 headers:()=>({...}) 固定 2023-06-01
x-api-key providers/anthropic.ts:auth()→Auth.header("x-api-key") 优先 apiKey,回退 ANTHROPIC_API_KEY
anthropic-beta opencode/provider/provider.ts:175 按模型注入,如 interleaved-thinking-2025-05-14
anthropic-beta opencode/provider/provider.ts:622 context-1m-2025-08-07(超长上下文)

OpenAI(protocols/openai-responses.ts:984 / openai-chat.ts:497)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost application/json
authorization providers/openai.ts→AuthOptions.bearer Bearer <key>,回退 OPENAI_API_KEY

OpenAI 兼容(DeepSeek、Mistral、TogetherAI 等)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost application/json
authorization 各 provider configuredRoute→AuthOptions.bearer(options,"<PROVIDER>_API_KEY") Bearer <key>

Google Gemini(protocols/gemini.ts:500)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost application/json
x-goog-api-key providers/google.ts:auth()→Auth.header("x-goog-api-key") 回退 GOOGLE_GENERATIVE_AI_API_KEY

模型 ID 嵌入 URL 路径:/models/${model.id}:streamGenerateContent?alt=sse

Amazon Bedrock — SigV4(protocols/bedrock-converse.ts:658)

Header 取值来源 说明
content-type protocols/utils/bedrock-auth.ts:signRequest 参与 SigV4 规范化
x-amz-date bedrock-auth.ts→AwsV4Signer.sign() UTC 时间戳
x-amz-security-token bedrock-auth.ts→AwsV4Signer.sign()(STS) STS 会话令牌
authorization bedrock-auth.ts→AwsV4Signer.sign() AWS4-HMAC-SHA256 Credential=.../bedrock/...

apiKey 时改用 Auth.bearer(apiKey) Bearer 模式(providers/amazon-bedrock.ts)

Azure OpenAI(providers/azure.ts)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost application/json
api-key providers/azure.ts:auth():67→Auth.remove("authorization").andThen(Auth.header("api-key")) 先移除 Bearer authorization,注入 api-key,回退 AZURE_OPENAI_API_KEY

api-version 通过 URL query 参数(非 Header)

GitHub Copilot(providers/github-copilot.ts)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost application/json
authorization providers/github-copilot.ts→AuthOptions.bearer OAuth2 token(plugin/github-copilot/copilot.ts 刷新)
anthropic-beta plugin/github-copilot/copilot.ts:369 interleaved-thinking-2025-05-14

OpenRouter(providers/openrouter.ts)

Header 取值来源 说明
content-type protocols/shared.ts:jsonPost application/json
authorization providers/openrouter.ts→AuthOptions.bearer Bearer <key>,回退 OPENROUTER_API_KEY
HTTP-Referer opencode/provider/provider.ts:461 `(opencode.ai/redacted)
X-Title opencode/provider/provider.ts:462 opencode

GitLab AI Gateway(opencode/provider/provider.ts:gitlab)

Header 取值来源 说明
authorization provider.ts:538 Bearer (token)(OAuth / GITLAB_TOKEN)
User-Agent provider.ts:aiGatewayHeaders opencode/\$\{ver} gitlab-ai-provider/\$\{ver} (\$\{os})
anthropic-beta provider.ts:622 / core/plugin/provider/gitlab.ts:23 context-1m-2025-08-07

三、鉴权机制

Provider 方式 核心代码
Anthropic API Key Header providers/anthropic.ts:auth()→Auth.optional(key).orElse(Auth.config("ANTHROPIC_API_KEY")).pipe(Auth.header("x-api-key"))
OpenAI Bearer providers/openai.ts→AuthOptions.bearer(options,"OPENAI_API_KEY")
OpenAI-兼容 Bearer 各 provider configuredRoute→AuthOptions.bearer(options,"(ENV)")
Google Gemini API Key Header providers/google.ts:auth()→Auth.header("x-goog-api-key")
Amazon Bedrock AWS SigV4 protocols/utils/bedrock-auth.ts:sigV4(),用 aws4fetch 库签名
Azure OpenAI api-key Header providers/azure.ts:67→Auth.remove("authorization").andThen(Auth.header("api-key"))
GitHub Copilot OAuth Bearer plugin/github-copilot/copilot.ts OAuth2 刷新
OpenRouter Bearer providers/openrouter.ts→AuthOptions.bearer
GitLab OAuth Bearer/PAT provider.ts:538 fetch 拦截注入

Auth 模块(packages/llm/src/route/auth.ts)核心 API:

  • Auth.bearer(src)Authorization: Bearer (value)
  • Auth.header(name, src) — 任意 Header 名
  • Auth.config(envVar) — Effect Config 读环境变量,缺失抛 AuthenticationReason
  • Auth.remove(name) — 删除 Header(Azure 用于替换 authorization)
  • Auth.custom(fn) — 完全自定义(Bedrock SigV4)
  • credential.orElse(that) — 链式回退

四、关键代码位置

文件 说明
packages/llm/src/route/client.ts Route.make, compile(), resolveRequestOptions()
packages/llm/src/route/auth.ts 所有 Auth 构造函数
packages/llm/src/route/transport/http.ts jsonRequestParts(), httpJson()
packages/llm/src/route/executor.ts RequestExecutor, 重试, 速率限制解析
packages/llm/src/protocols/anthropic-messages.ts:845 Anthropic 路由,anthropic-version
packages/llm/src/protocols/openai-responses.ts:984 OpenAI Responses 路由
packages/llm/src/protocols/gemini.ts:500 Gemini 路由
packages/llm/src/protocols/bedrock-converse.ts:658 Bedrock 路由
packages/llm/src/protocols/utils/bedrock-auth.ts SigV4 实现
packages/llm/src/protocols/shared.ts:322 jsonPost() 注入 content-type
packages/llm/src/providers/azure.ts:67 Azure api-key 替换 authorization
packages/opencode/src/session/llm.ts 会话编排,runtime 选择
packages/opencode/src/session/llm/native-request.ts ModelMessage → LLMRequest
packages/opencode/src/provider/provider.ts:175,461,538,622 anthropic-beta, OpenRouter HTTP-Referer, GitLab User-Agent

Generated by Daily Upstream Sync + Request-Flow Analysis · 138.1 AIC · ⌖ 9.51 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