Adapters
adapter 负责在 opencodex 的内部请求/响应模型与某个 provider 的 wire 格式之间转换。每个
adapter 都实现 ProviderAdapter 接口(src/adapters/base.ts):
interface ProviderAdapter { name: string; buildRequest(parsed, incoming?): AdapterRequest | Promise<AdapterRequest>; fetchResponse?(request, context): Promise<Response>; // custom retry/transport parseStream(response): AsyncGenerator<AdapterEvent>; parseResponse?(response): Promise<AdapterEvent[]>; // non-streaming runTurn?(parsed, incoming, emit): Promise<void>; // bidirectional transport}buildRequest 把 OcxParsedRequest 转成上游 HTTP 请求;parseStream / parseResponse 把 provider
回复转回内部 AdapterEvent。fetchResponse 允许 adapter 自己负责重试和 timeout;runTurn 支持
无法表示成一次 HTTP fetch 加一条响应流的 transport。随后
bridge.ts 把 event 转成 Responses SSE。
openai-chat
Section titled “openai-chat”目标: OpenAI Chat Completions(POST {baseUrl}/chat/completions)以及所有兼容 provider,
包括 xAI、Kimi、DeepSeek、GLM、Groq、OpenRouter、Ollama(本地)等。
认证: key(Bearer)。
- 把内部消息转换成 OpenAI role;工具映射为
{type:"function", function:{…}}和tool_choice(auto/none/required或具名函数)。 - 工具结果中的图片会在工具轮次结束后,作为后续 user vision 消息(
image_url部分)发送, 因为role:"tool"的内容只能是文本;[image]标记仍保留在工具消息中作为锚点。 - 重写 Codex 的 GPT-5 身份提示词,改成与模型无关的介绍,避免路由模型自称 OpenAI。
- 精确层级不可用时,把
reasoning_effort限制到模型公布的子集。除非 provider 显式配置 alias,xhigh与max保持为不同标签。对于provider.noReasoningModels中的 id,则完全 省略该参数。 - 流式输出
delta.content(文本)、delta.reasoning_content(thinking)和delta.tool_calls[],并收集usage。 - ClinePass 使用经实时验证的网关格式
reasoning: { enabled: true, effort };关闭 reasoning 时使用{ enabled: false }。其公开 API 文档目前没有说明这一请求格式。adapter 会保留请求的low、medium、high、xhigh或max档位,把delta.reasoning_content或delta.reasoning作为 reasoning delta,通过stream_options.include_usage请求流式 usage,并从非流式响应 envelope 中读取 usage。
ollama-native
Section titled “ollama-native”目标: Ollama 自有的 Chat API(POST /api/chat),而不是其 OpenAI 兼容接口。内置的
ollama-cloud 提供方由 registry 选择到该 adapter;也可以在单独命名的自定义 / 自托管 Ollama
提供方上配置 adapter: "ollama-native"。
认证: cloud / 自定义端点使用 key(Bearer);loopback 或 authMode: "local"
端点不会收到任何凭据。
- registry 选择起决定作用。 内置的
ollama-cloud行保留https://ollama.com/v1作为/v1/models动态发现的基础 URL,同时推理会规范化到POST https://ollama.com/api/chat。 对该提供方行,配置中的adapter会被丢弃。普通内置本地 Ollama 仍走openai-chat;为本 地或自托管端点选择ollama-native是显式的提供方配置决策,并按主机名判别,因此非 Ollama 目标永远不会被悄悄改写。 - 模型元数据:
/v1/models不携带任何模型级元数据,因此在正典 Ollama Cloud 上,提供方 会通过 有界限的POST /api/show(每响应 256 KiB、每请求 8 秒、并发 4、48 个请求、整阶段 12 秒期限)补全每个被发现 id 的真实 context window 与 vision 能力。show 请求同源且从不 跟随重定向;失败只降级该模型,不会令发现本身失败。 - 流式: Ollama 原生 NDJSON。文本与
message.thinkingdelta 到达即转发;回合仅在done: true终止记录上完成,缓冲的done: false或缺失终记录会完全抑制部分文本与工具调用。 - Reasoning: 映射到 Ollama 原生
think字段(low/medium/high/max,外加布尔值), 按模型声明的档位收紧,并遵守上游配置的__omit__sentinel 语义。 - 图像: 在模型具备 vision 能力时原样放入消息的
images数组发送;video 会被拒绝而非 误发,远程图像 URL 不会被拉取。 - 工具: 以 Ollama 原生形状声明;流式 tool call 是
arguments为对象的整调用记录, tool result 回放按 call id 与工具名严格配对。tool_choice: "none"与auto表现正常;required或精确命名选择会 fail closed,因为 Ollama 的/api/chat没有可用来强制它的tool_choice字段。 - 正典 Ollama Cloud 上拒绝结构化输出。 Ollama 目前在文档中说明其 Cloud 不支持结构化输出,
且 Cloud 不会强制
format字段,因此对按 schema 提出的请求,OpenCodex 会让其显式失败,而 不是返回不受约束的自由文本。本地 / 自定义ollama-native端点保留 Ollama 原生的format映射(json_object→"json",json_schema→ schema 对象本身)。
openai-responses
Section titled “openai-responses”目标: OpenAI Responses API。passthrough: true —— 通常原样转发请求与响应,仅对
路由网关应用范围有限的兼容性转换。
认证: 规范 OpenAI forward 只转发安全的调用方 header allowlist;非规范 forward 不会
转发调用方 authorization,只使用已配置的静态 header;key 使用已配置的 provider key。
对于非规范 Responses 网关,Codex 的客户端执行型 tool_search 声明会作为公共 function tool
以不与现有 function 名称冲突的方式发送;匹配的请求历史和 JSON/SSE function call 会恢复为
客户端私有的 tool_search 生命周期。规范 OpenAI forward 路径仍保持原生私有类型不变。
使用 key 认证时,retryOn429 同样适用:流开始前的 429
会等待并先于其他处理或故障转移,在相同 key 上重放完全相同请求,与翻译后的
openai-chat/Anthropic 请求路径一致。自定义 runTurn 传输不在 HTTP 重试循环之内。
-
DeepSeek 的 stateless Responses parser 会收到按 provider 范围的历史归一化:hook 注入的上下文会移动到 明确的 tool-call/result 批次之后。并行调用保持在其对应输出之前分组,因此每个调用都留在承载 推理的 assistant 回合中。宽容的 provider 和歧义的(重复、缺失或乱序的)call ID 保留原始输入顺序。
-
forwardURL →{baseUrl}/responses。keyprovider 默认保留原有的{baseUrl}/v1/responses构造。 -
keyprovider 可设置经过验证的相对responsesPath;adapter 会移除baseUrl末尾的一个/,并向{trimmedBaseUrl}{responsesPath}发送请求。Ark Agent Plan 使用baseUrl: "https://ark.cn-beijing.volces.com/api/plan/v3"和responsesPath: "/responses"。 -
forward模式只会转发安全的 header allowlist(FORWARD_HEADERS):authorization、ChatGPT account id 和 OpenAI beta/originator/session header。这条 ChatGPT 登录路径也为 sidecar 提供支持。
anthropic
Section titled “anthropic”目标: Anthropic Messages(/v1/messages)。
认证: key(默认 x-api-key,或设置 apiKeyTransport: "bearer" 后使用 Authorization: Bearer)或 oauth(Bearer + anthropic-beta,用于 Claude Pro/Max)。
- 把消息转换成 Anthropic content block(text、base64 image、
tool_use、thinking)。 - Extended thinking 计算: Anthropic 要求
max_tokens > thinking.budget_tokens。adapter 把 reasoning effort 映射成 budget(minimal 1024 … max 32000),再计算留有输出余量的安全max_tokens;启用 thinking 后会移除temperature/top_p,因为 Anthropic 禁止此组合。 - 始终发送
anthropic-version: 2023-06-01。流式输出content_block_delta(text_delta、thinking_delta、input_json_delta)。
google
Section titled “google”目标: Google Gemini、Vertex AI 和 Antigravity Cloud Code Assist。AI Studio 使用
/v1beta/models/{model}:streamGenerateContent,其他模式使用各自的 Google 原生 endpoint。
认证: 根据 googleMode 选择 API key、Vertex ADC 或 Google Antigravity OAuth。
- 系统提示词 →
systemInstruction;消息 →contents[](assistant →model);工具 →functionDeclarations;data URL 图像 →inline_data。 - Gemini 省略 tool-call id 时会合成 id。Vertex 与 Antigravity 会保留并重放不透明
thoughtSignature,使 tool-result 后续 turn 保持 reasoning continuity。签名缓存会快照到配置 目录,因此代理重启后后续 turn 仍可继续。
目标: Kiro 使用的 Amazon CodeWhisperer Streaming GenerateAssistantResponse 服务
(https://runtime.{region}.kiro.dev/)。
认证: Kiro credential 中的 region/profile metadata,加上作为 Bearer 的 Kiro OAuth access
token。
- 构建 Kiro
conversationState,映射 Codex 工具和工具结果,并发送 Kiro wire 支持的 image block。 - 解码
application/vnd.amazon.eventstream,重建 text/thinking/tool event,检测被截断的工具 JSON。上游不返回 token 数量,因此 usage 采用估算值。 - 经
fetchResponse负责有界重试和分类/脱敏后的错误;非流式 parser 会排空同一 event stream, 供 web-search loop 使用。
完成与原生 stop reason
Section titled “完成与原生 stop reason”Kiro 的 assistant 文本本身没有可靠的回合结束标记,但终止的 metadataEvent 可能带有原生 stopReason。
END_TURN 和 STOP_SEQUENCE 只能证明本次推理已停止;Kiro 也可能给进展文本加上该标记。因此在启用工具的
回合中,普通文本仍作为 commentary,并通过私有完成工具做一次校验。
END_TURN、STOP_SEQUENCE 或缺失 stop reason 时可以走一次完成兼容路径。其他显式原因已在上游终止本次推理,因此适配器直接报告而不是
再发一次请求:输出 token 上限表现为可继续的 incomplete,上下文窗口耗尽表现为不可重试的 context-length
错误,内容过滤或 guardrail 停止表现为 filtered incomplete。没有真实工具调用却出现的 TOOL_USE 被视为
矛盾而非进展。
启用工具时,opencodex 会添加私有 codex_kiro_final_answer。重试不会制造空的 assistant/user 回合,
而会保留原始 user/tool-result,并在发送前校验角色交替、非空结构消息以及 tool use/result 配对。
完成工具的回答即使与先前 commentary 完全相同,也会作为 final_answer 发出。
当缺少只有用户能提供的决定、信息或澄清而无法继续时,契约同样要求把该问题通过完成工具发出并停止;它也作为结束回合的 final_answer 到达,而不是 commentary。
Reasoning effort
Section titled “Reasoning effort”gpt-5.6-sol 和 claude-opus-5 支持原生 effort,且请求字段名不同。low / medium / high /
xhigh / max 分别通过 additionalModelRequestFields.reasoning.effort 和
output_config.effort 发送。
cursor
Section titled “cursor”目标: 默认使用 api2.cursor.sh 上采用 HTTP/2 Connect streaming 的
agent.v1.AgentService/Run。配置 upstreamHttpVersion: "http1.1"(或 "h1")后,改用
Cursor 的 HTTP/1.1 兼容传输:通过 agent.v1.AgentService/RunSSE 接收 server output,并通过
aiserver.v1.BidiService/BidiAppend 发送 client message。
认证: provider.apiKey 或转发 authorization header 中的 Cursor OAuth/access token。
- 使用
runTurn,而不是常规 fetch/parse 路径。请求、server event、工具参数、usage checkpoint 和 client reply 由cursor/gen/agent_pb.ts中的@bufbuild/protobufschema 编码,并 frame 成 Connect message。 - 经 content-addressed blob 重放对话状态,把 server tool call 映射回 Codex,用 protobuf
GetUsableModelsRPC 发现实时 Cursor 模型,并且只在 run request 尚未 commit 到 wire 前重试。 - 对不含工具且正常完成的 turn,会在进程本地保存返回的 ConversationStateStructure,并在经过验证的 线性 continuation 中复用 checkpoint。tool-result turn 会在已知覆盖消息边界时,复用最后一个已完成 turn 的 checkpoint,并只追加尚未覆盖的 suffix。无 ref 的 prefix lookup 仅在存在已记忆的 Cursor conversation 或稳定 client thread(包括受限的 Desktop session/thread fallback),且唯一匹配的 checkpoint 由同一 provider conversation 所有时才允许;否则执行 full replay。compaction、 helper/shadow 隔离、account/model 不匹配、ref 缺失、decode 失败、forced-fresh recovery 以及 invalid_argument 重试也会回退到 full replay。进程重启会丢弃内存 store 并执行 full replay。 Cursor Connect 不提供权威的 cache_read_tokens,因此 OpenCodex usage 不是 cache hit 计数器。 受限的 Desktop fallback 只保存进程本地由 HMAC 派生的 owner;原始 session/thread header 与 OAuth/authorization 材料不会写入 checkpoint state。基于 OAuth 的 live transport 和按账号过滤的 live model discovery 仍是实验功能;登录与 transport 设置参见提供商指南 和 Cursor 提供商配置。 checkpoint 复用本身是自动的,没有用户设置。
- 模型实时发现和推理都会遵守
upstreamHttpVersion。auto、http2与h2保持原有 HTTP/2 transport;只有http1.1与h1会选择兼容模式。 - 保留
cursor/grok-4.5-fast作为可选模型,但向 Cursor 发送规范的grok-4.5模型,并将独立的effort和fast=true值放入requested_model.parameters。 - Cursor 原生本地 filesystem/shell/network 执行默认被拒绝。显式
mcpServers与desktopExecutor集成分别需要 opt-in;nativeLocalExec: "on"会启用更广泛的内置 executor,并绕过 Codex 审批和 sandbox 语义;旧的unsafeAllowNativeLocalExec: true仅在nativeLocalExec未设置时等同。
azure-openai(别名:azure)
Section titled “azure-openai(别名:azure)”目标: Azure OpenAI。封装 openai-responses,因此同样是 passthrough: true。
认证: 用 api-key header 进行 key 认证,而非 Bearer。
- 把请求构建交给 Responses passthrough,验证
baseUrl不含未解析的 template placeholder, 再用api-key替换Authorization。配置的 URL 直接指向 Azure v1 Responses API,因此 adapter 不会追加api-version。
图像工具(image.ts)
Section titled “图像工具(image.ts)”支持视觉的 adapter 共用以下 helper:
parseDataUrl(url)—— 把data:<type>;base64,<data>URL 拆成{ mediaType, base64 },供 Anthropic/Google image block 使用。contentPartsToText(content)—— 为纯文本工具消息把 content part 扁平化成文本。未描述的图像 会变成简短的[image]marker,而不是导致 token 暴涨的 base64 blob。

