轉接器
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或具名函式)。 - 重寫 Codex 的 GPT-5 身份提示詞,改成與模型無關的介紹,避免路由模型自稱 OpenAI。
- 精確層級不可用時,把
reasoning_effort限制到模型公佈的子集。除非 provider 顯式設定 alias,xhigh與max保持為不同標籤。對於provider.noReasoningModels中的 id,則完全 省略該引數。 - 流式輸出
delta.content(文字)、delta.reasoning_content(thinking)和delta.tool_calls[],並收集usage。 - ClinePass 使用經即時驗證的 gateway 格式
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欄位,因此 OpenCodex 會讓該請求顯式失敗,而不是在 schema 指定的 請求上回傳不受約束的散文。本機 / 自訂ollama-native端點保留 Ollama 原生的format映射 (json_object→"json",json_schema→ schema 物件本身)。
openai-responses
Section titled “openai-responses”目標: OpenAI Responses API。passthrough: true —— 轉發原始請求 body,並把回應
不經轉換地流式傳回。
認證: forward(轉發呼叫方 header)或 key。
-
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)或 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。Antigravity 會保留並重放真實
thoughtSignature,使 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 視為權威結束,其文字直接作為最終回答發出,不再額外往返模型。
只有在 stop reason 缺失時才走相容路徑。任何顯式原因都已在上游終止了本次推理,因此適配器直接報告而不是
再發一次請求:輸出 token 上限表現為可繼續的 incomplete,上下文視窗耗盡表現為不可重試的 context-length
錯誤,內容過濾或 guardrail 停止表現為 filtered incomplete。沒有真實工具呼叫卻出現的 TOOL_USE 被視為
矛盾而非進展。
只有完全沒有 stop reason 時,opencodex 才新增私有的 codex_kiro_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。
認證: 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 前重試。 - Cursor 原生本機 filesystem/shell/network 執行預設被拒絕。顯式
mcpServers與desktopExecutor整合分別需要 opt-in;nativeLocalExec: "on"會啟用更廣泛的內建 executor,並繞過 Codex 審批和 sandbox 語義;舊的unsafeAllowNativeLocalExec: true僅在nativeLocalExec未設定時等效。
目標: Cognition 的 exa.api_server_pb.ApiServerService/GetChatMessage(server.codeium.com,Connect 串流)。
認證: 來自 provider.apiKey 或轉送 authorization 標頭的 Devin/Cognition API 金鑰。登入會先嘗試匯入已安裝 Devin CLI 已持有的憑證:devin auth login 會完成 CLI 自身的 PKCE 登入並把 devin-session-token 寫入它自己的 credentials.toml,這與 SeatManagementService.RegisterUser 為瀏覽器登入簽發的憑證相同。沒有可用的 CLI 憑證時,登入回退到 Auth0 瀏覽器頁面,再透過 RegisterUser 把貼上的權杖換成長期金鑰。devin-cli 僅作為已棄用的別名保留:ocx login devin-cli 仍會路由到 devin,以舊 id 儲存的設定會在啟動時被重寫。
- 使用
runTurn而非一般的 fetch/parse 路徑。請求與伺服器事件由devin/cloud-direct/wire.ts手寫的 protobuf 分幀處理。 - 以
GetCascadeModelConfigs依帳號取得模型;方案未涵蓋的模型在清單階段就被濾除。 - Cognition 對工具說明設有長度上限與完全比對的封鎖清單。轉接器會改寫已知語句並截斷過長說明。
- 金鑰不會更新。失效後請重新執行
ocx login devin。 - 即使走 CLI 匯入路徑,本機的也只有憑證,請求本身無論哪條路徑都發往 Cognition。早期版本曾在
devin-cliid 下提供第二個轉接器,把請求作為對本機devin acp子行程的 Agent Client Protocol 工作階段來執行,現已移除。仍引用該轉接器的已儲存設定會在啟動時重寫為devin,包括"devin-acp"這類自訂名稱的列。
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。

