Skip to content

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

Description

@github-actions

本次变更提示

近期同步提交中与请求流程相关:

  • 3033afb fix(provider): normalize Mistral family tool call IDs — 影响 OpenAI-Compatible 协议 tool-call ID 规范化
  • 5a8ee27 fix(provider): update muse-spark reasoning default — 影响特定模型请求 Body 构造

一、请求流程(时序)

sequenceDiagram
    participant S as Session 层
    participant P as LLMRequestPrep (session/llm/request.ts)
    participant N as LLMNative (session/llm/native-request.ts)
    participant R as LLMNativeRuntime (session/llm/native-runtime.ts)
    participant C as LLMClient (llm/route/client.ts)
    participant T as httpJson Transport (route/transport/http.ts)
    participant E as RequestExecutor (route/executor.ts)
    participant API as Provider HTTP API

    S->>P: prepare(sessionID, messages, model)
    Note over P: 构造 User-Agent、会话追踪 Header、plugin Header
    P->>N: LLMNative.model() — api.npm → Provider Facade
    N->>R: LLMNative.request() → LLMRequest
    R->>C: llmClient.stream(LLMRequest)
    C->>C: Protocol.body.from() — Provider 原生 Body
    C->>T: httpJson.prepare(body)
    Note over T: renderEndpoint() URL, Auth.apply() 注入鉴权 Header
    T->>E: runtime.http.execute(httpRequest)
    E->>API: POST(/messages / /chat/completions / converse-stream)
    API-->>E: 200 + SSE stream
    E-->>C: frames via Framing.sse
    C-->>S: Stream LLMEvent(text-delta/tool-call/finish)
Loading

关键步骤

步骤 描述 关键文件/符号
1 Provider/Model 解析 api.npm 包名 → Provider Facade → Route native-request.ts LLMNative.model()
2 会话 Header 构造 User-Agent、会话追踪、plugin 贡献 Header request.ts LLMRequestPrep.prepare()
3 凭据获取 AuthOptions.bearer() 惰性解析 apiKey/env route/auth-options.ts:47–55
4 Protocol Body LLMRequest → Provider 原生 Body(Schema 验证+JSON 编码) protocols/*.ts body.from()
5 URL 渲染 Endpoint.render() 静态/动态路径(Bedrock 含 modelId) route/endpoint.ts
6 Auth 注入 Auth.apply() 注入鉴权 Header route/auth.ts
7 HTTP 发送+重试 POST;读取 retry-after[-ms];最多重试 2 次 route/executor.ts
8 流解析 SSE/AWS event-stream → protocol.stream.step() → LLMEvent route/framing.ts

二、请求 Header 明细

鉴权类 Header(按 Provider)

Provider Header 取值来源 代码位置
Anthropic x-api-key options.apiKey → env ANTHROPIC_API_KEY providers/anthropic.ts:13–18
Anthropic anthropic-version 硬编码 "2023-06-01" protocols/anthropic-messages.ts:852
OpenAI Authorization Bearer <key>;env OPENAI_API_KEY providers/openai.ts:24
Azure OpenAI api-key options.apiKey;env AZURE_OPENAI_API_KEY providers/azure.ts:65–72
Azure OpenAI Authorization 移除 Auth.remove("authorization") providers/azure.ts:10
Google Gemini x-goog-api-key options.apiKey;env GOOGLE_GENERATIVE_AI_API_KEY providers/google.ts:13–17
GitHub Copilot Authorization Bearer <key>;无 env 回退 providers/github-copilot.ts:40,46
Bedrock API Key Authorization Bearer <key> providers/amazon-bedrock.ts:29
Bedrock SigV4 Authorization AWS4-HMAC-SHA256 Credential=... protocols/utils/bedrock-auth.ts:20–45
Bedrock SigV4 x-amz-date 签名时间戳(AwsV4Signer 注入) protocols/utils/bedrock-auth.ts
Bedrock SigV4 x-amz-security-token STS sessionToken(可选) protocols/utils/bedrock-auth.ts
OpenAI-Compatible Authorization Bearer <key>;无 env 回退 providers/openai-compatible.ts:29

会话追踪 Header(session/llm/request.ts:187–204)

条件 Header 取值来源
所有 User-Agent opencode/<InstallationVersion>(line 18)
provider === "opencode" x-opencode-project/session/request/client 实例/会话/用户/flags 值
非 opencode x-session-affinity, X-Session-Id sessionID
非 opencode(若有) x-parent-session-id parentSessionID
所有 model/plugin 级 model.headers.*;plugin chat.headers hook

HTTP 通用 Header

Header 来源
content-type application/json protocols/shared.ts ProviderShared.jsonPost()

三、鉴权机制

Auth 原语(route/auth.ts):所有鉴权均为惰性 Effect,真正凭据在请求时才解析。

凭据优先级(route/auth-options.ts:47–55):

  1. 显式 auth 对象
  2. options.apiKey(内联/Redacted/Config)
  3. Auth.config(envVar) — 环境变量回退
机制 Provider 实现
Auth.header("x-api-key") Anthropic providers/anthropic.ts
Auth.bearer() OpenAI、Copilot、Compatible route/auth.ts
Auth.header("api-key") + Auth.remove("authorization") Azure providers/azure.ts
Auth.header("x-goog-api-key") Google providers/google.ts
AWS SigV4 via aws4fetch.AwsV4Signer Bedrock protocols/utils/bedrock-auth.ts:20–45
自定义 OAuth fetch 注入 OpenAI OAuth session/llm/native-runtime.ts:148–153

Bedrock SigV4:用 accessKeyId + secretAccessKey + sessionToken 对 URL+Body+Headers 整体签名(service="bedrock"),签名前设 content-type: application/json(line 56)。

OAuth 交互流程(provider/auth.ts):authorize() → plugin hook → 重定向;callback() 持久化 {type:"oauth", access, refresh, expires}{type:"api", key}


四、Endpoint / URL 构造

Provider Default Base URL Path
Anthropic `(api.anthropic.com/redacted) /messages
OpenAI Chat `(api.openai.com/redacted) /chat/completions
OpenAI Responses `(api.openai.com/redacted) /responses
Google Gemini `(generativelanguage.googleapis.com/redacted) /models/${modelId}:streamGenerateContent?alt=sse
Amazon Bedrock (bedrockruntime/redacted)<region>.amazonaws.com /model/${encodedModelId}/converse-stream
Azure OpenAI https://<resourceName>.openai.azure.com/openai/v1 /responses/chat/completions?api-version=<ver>
GitHub Copilot / Compatible 需外部配置(无默认) /chat/completions

五、错误处理与重试(route/executor.ts)

  • 最大重试次数:2;初始延迟:500 ms(含抖动);最大延迟:10,000 ms
  • 可重试状态码:429、503、504、529
  • 状态映射:401→Authentication(invalid);403→Authentication(insufficient-permissions);429(配额)→QuotaExceeded;429→RateLimit;400/404/422→InvalidRequest;5xx→ProviderInternal;内容政策→ContentPolicy
  • Secret 脱敏:Header/query/Body 中匹配 authorization|api[-_]?key|token|secret|signature 的字段均被脱敏(executor.ts:48–54, 166–195)

六、关键代码位置索引

文件 核心符号
packages/opencode/src/session/llm/request.ts LLMRequestPrep.prepare()
packages/opencode/src/session/llm/native-request.ts LLMNative.model/request()
packages/opencode/src/session/llm/native-runtime.ts LLMNativeRuntime.stream()
packages/opencode/src/provider/auth.ts ProviderAuth.Service
packages/llm/src/route/client.ts LLMClient.stream/generate/prepare()
packages/llm/src/route/auth.ts Auth interface + constructors
packages/llm/src/route/auth-options.ts AuthOptions.bearer()
packages/llm/src/route/executor.ts RequestExecutor
packages/llm/src/route/transport/http.ts httpJson
packages/llm/src/route/transport/websocket.ts WebSocketTransport.json
packages/llm/src/route/endpoint.ts Endpoint.path/render()
packages/llm/src/protocols/anthropic-messages.ts AnthropicMessages.protocol
packages/llm/src/protocols/openai-chat.ts OpenAIChat.protocol
packages/llm/src/protocols/openai-responses.ts OpenAIResponses.protocol
packages/llm/src/protocols/bedrock-converse.ts BedrockConverse.protocol
packages/llm/src/protocols/utils/bedrock-auth.ts bedrockSigV4Auth()
packages/llm/src/providers/anthropic.ts Anthropic.configure()
packages/llm/src/providers/openai.ts OpenAI.configure()
packages/llm/src/providers/amazon-bedrock.ts AmazonBedrock.configure()
packages/llm/src/providers/azure.ts Azure.configure()
packages/llm/src/providers/github-copilot.ts GitHubCopilot.configure()
packages/llm/src/providers/google.ts Google.configure()
packages/llm/src/providers/openai-compatible.ts OpenAICompatible.configure()

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