近期相关变更
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.ts、provider/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-280、native-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.ts、transport/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:17 → Auth.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.ts → AuthOptions.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:17 → Auth.header("x-goog-api-key") |
GitHub Copilot(baseURL 由调用方配置,无默认)
| Header |
取值来源 |
说明 |
Authorization |
Bearer (token) |
github-copilot.ts → AuthOptions.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)统一封装:
- 先检查显式
auth override
- 再检查
options.apiKey
- Fallback 到
Config.redacted(envVar) 读环境变量
- 为空时
MissingCredentialError → LLMError.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(),签名结果(Authorization、x-amz-date、x-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.prepare、USER_AGENT |
packages/opencode/src/session/llm/native-runtime.ts |
LLMNativeRuntime.stream/status、providerFetch |
packages/opencode/src/session/llm/native-request.ts |
LLMNative.request — LLMRequest 构造 |
packages/llm/src/route/client.ts |
Route.make、LLMClient、compile |
packages/llm/src/route/executor.ts |
RequestExecutor、retryStatusFailures |
packages/llm/src/route/transport/http.ts |
httpJson、jsonRequestParts |
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 |
sigV4、signRequest |
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 |
jsonPost — content-type 注入 |
Generated by Daily Upstream Sync + Request-Flow Analysis · 106.7 AIC · ⌖ 6.99 AIC · ⊞ 5.9K · ◷
近期相关变更
fix(provider): honor reasoning option semantics (#37519)— 修复 reasoning 选项语义,影响ProviderTransform.providerOptions下发逻辑feat(session-ui): rewrite v2 prompt input (#37102)— Prompt 输入层重写,涉及 SessionV2 提交入口1. 请求流程(时序)
架构分层
关键步骤
Provider.Service.getProvider/getLanguage()获取配置和 AI SDK 模型实例session/llm.ts:runAuth.Service.get(providerID)从持久化存储/OAuth 读取凭据session/llm.ts、provider/auth.tsLLMRequestPrep.prepare()融合 system/messages/tools/params;构造会话级 headers;触发插件chat.headershookllm/request.ts:prepareflags.experimentalNativeLlm=true且 provider∈{openai,anthropic,opencode} 且有 apiKey → 原生路由;否则 → AI SDKsession/llm.ts:220-280、native-runtime.ts:status()LLMNative.request()将 ModelMessage/tools 降型为LLMRequestschemallm/native-request.tscompile(): resolveRequestOptions → applyCachePolicy →route.body.from()构造 provider body →route.prepareTransport()route/client.ts:compilerenderEndpoint()渲染 baseURL+path;query 参数单独 appendroute/endpoint.ts、transport/http.ts:applyQueryjsonRequestParts()合并静态路由 headers(如anthropic-version)+request.http.headers;再Auth.toEffect(auth)()注入凭据transport/http.ts:jsonRequestPartsSchema.encodeSync(Schema.fromJsonString(...))序列化 body;可通过request.http.body叠加(受 denylist 保护)route/client.ts:makeFromTransportRequestExecutor.execute()通过 Effect HttpClient 发送;自动重试 429/503/504/529(最多 2 次,指数退避,尊重retry-after)route/executor.ts:retryStatusFailuresframing.frame()切帧(SSE/AWS event-stream)→ Schema 解码 →protocol.stream.step()状态机产出LLMEvent[]route/client.ts:streamPrepared2. 请求 Header 明细
所有 Provider 公共
content-typeapplication/jsonprotocols/shared.ts:jsonPost(硬编码)User-Agentopencode/<version>llm/request.ts:USER_AGENTx-session-affinityrequest.ts:191(非 opencode provider)X-Session-Idrequest.ts:192x-parent-session-idrequest.ts:193Anthropic(`(api.anthropic.com/redacted)
x-api-keyANTHROPIC_API_KEY/options.apiKeyanthropic.ts:17→Auth.header("x-api-key")anthropic-version"2023-06-01"(硬编码)anthropic-messages.ts:852route headers 函数OpenAI(
(api.openai.com/redacted) 或/chat/completions`)AuthorizationBearer ${OPENAI_API_KEY}openai.ts→AuthOptions.bearer(options, "OPENAI_API_KEY")Azure OpenAI
端点:
https://<resourceName>.openai.azure.com/openai/v1/responses?api-version=<ver>api-keyAZURE_OPENAI_API_KEY/options.apiKeyazure.ts:auth()→Auth.header("api-key");同时Auth.remove("authorization")移除 BearerAmazon Bedrock
端点:
(bedrockruntime/redacted)<region>.amazonaws.com/model/<modelId>/converse-streamAuthorizationAWS4-HMAC-SHA256 Credential=.../Signature=...bedrock-auth.ts:signRequest使用aws4fetch.AwsV4Signerx-amz-datex-amz-security-tokensessionToken(STS 临时凭据,可选)content-typeapplication/jsonbedrock-auth.ts:sigV4)Google Gemini
端点:`(generativelanguage.googleapis.com/redacted)
x-goog-api-keyGOOGLE_GENERATIVE_AI_API_KEY/options.apiKeygoogle.ts:17→Auth.header("x-goog-api-key")GitHub Copilot(baseURL 由调用方配置,无默认)
AuthorizationBearer (token)github-copilot.ts→AuthOptions.bearer(options, [])OpenAI 兼容 / OpenRouter / xAI / Cloudflare Workers AI
AuthorizationBearer (apiKey)AuthOptions.bearer(options, "XAI_API_KEY"|"OPENROUTER_API_KEY"|"CLOUDFLARE_WORKERS_AI_TOKEN"...)Cloudflare AI Gateway 额外:
cf-aig-authorizationBearer (gatewayApiKey)cloudflare.ts:aiGatewayAuth()→Auth.bearerHeader("cf-aig-authorization");fallback 到CLOUDFLARE_API_TOKEN/CF_AIG_TOKENAuthorizationBearer (apiKey)(后端 provider key)opencode 内部 Provider(
providerID.startsWith("opencode"))x-opencode-projectInstanceState.context.project.id,request.ts:184x-opencode-sessionrequest.ts:185x-opencode-requestinput.user.id,request.ts:186x-opencode-clientinput.flags.client,request.ts:1873. 鉴权机制
3.1 API Key 鉴权(大多数 provider)
AuthOptions.bearer(options, envVar)(auth-options.ts)统一封装:authoverrideoptions.apiKeyConfig.redacted(envVar)读环境变量MissingCredentialError→LLMError.Authentication.missingHeader 注入:
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(),签名结果(Authorization、x-amz-date、x-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.headershook,允许插件注入任意 header,通过streamText({ headers })或LLMRequest.http.headers传递。4. 关键代码位置索引
packages/opencode/src/session/llm.tsLLM.Service.stream— 编排入口,Runtime 路由选择packages/opencode/src/session/llm/request.tsLLMRequestPrep.prepare、USER_AGENTpackages/opencode/src/session/llm/native-runtime.tsLLMNativeRuntime.stream/status、providerFetchpackages/opencode/src/session/llm/native-request.tsLLMNative.request— LLMRequest 构造packages/llm/src/route/client.tsRoute.make、LLMClient、compilepackages/llm/src/route/executor.tsRequestExecutor、retryStatusFailurespackages/llm/src/route/transport/http.tshttpJson、jsonRequestPartspackages/llm/src/route/auth.tsAuth.bearer/header/custom/toEffectpackages/llm/src/route/auth-options.tsAuthOptions.bearerpackages/llm/src/protocols/anthropic-messages.ts:852anthropic-version: 2023-06-01注册packages/llm/src/protocols/utils/bedrock-auth.tssigV4、signRequestpackages/llm/src/providers/anthropic.ts:17x-api-key注入packages/llm/src/providers/azure.ts:65api-key+Auth.remove("authorization")packages/llm/src/providers/google.ts:17x-goog-api-key注入packages/llm/src/providers/cloudflare.ts:44cf-aig-authorization双重认证packages/llm/src/protocols/shared.ts:314-322jsonPost—content-type注入