Adapters
An adapter translates between opencodex’s internal request/response model and one provider wire
format. Every adapter implements the ProviderAdapter interface (src/adapters/base.ts):
interface ProviderAdapter { name: string; buildRequest(parsed: OcxParsedRequest, incoming: IncomingMeta): AdapterRequest | Promise<AdapterRequest>; fetchResponse?(request: AdapterRequest, ctx?: AdapterFetchContext): Promise<Response>; parseStream(response: Response, budget: TranslatorBudget): AsyncGenerator<AdapterEvent>; parseResponse?(response: Response, budget: TranslatorBudget): Promise<AdapterEvent[]>; runTurn?(parsed: OcxParsedRequest, incoming: IncomingMeta, emit: (event: AdapterEvent) => void): Promise<void>;}buildRequest lowers an OcxParsedRequest into an upstream HTTP request; parseStream /
parseResponse lift the provider’s reply back into internal AdapterEvents. fetchResponse lets an
adapter own retries/timeouts, while runTurn supports transports that cannot be represented as one
HTTP fetch followed by one response stream. bridge.ts
then turns the events into Responses SSE.
External task input on translated Responses routes
Section titled “External task input on translated Responses routes”Codex task coordination can deliver input as function_call_output with nonblank
id, name and namespace fields and no call_id property. OpenCodex maps this
complete envelope to a user message before adapter translation. Its output must be
nonblank text or a fully supported array of text and input_image URL parts. Text
and image order are preserved; image detail original maps to high.
Empty content, malformed or opaque parts, file-id-only images and partial envelopes
remain invalid. Ordinary function/custom tool results still require a nonempty
call_id. The envelope metadata identifies a compatibility shape and grants no
additional permissions. Native passthrough and compaction retain their raw-body rules.
openai-chat
Section titled “openai-chat”Targets: OpenAI Chat Completions (POST {baseUrl}/chat/completions; a trailing /chat/completions or / on baseUrl is stripped first) and every compatible
provider — xAI, Kimi, DeepSeek, GLM, Groq, OpenRouter, Ollama (local), and more.
Auth: key (Bearer).
For xAI, the resolved upstream adapter can be openai-chat or openai-responses,
depending on model defaults and explicit modelAdapters overrides. Both support
public xAI API-key authentication and Grok CLI OAuth. The usage log’s
attempts[].credentialSource follows that resolved
transport; it does not infer subscription attribution from the inbound protocol.
- Converts internal messages to OpenAI roles; maps tools to
{type:"function", function:{…}}andtool_choice(auto/none/requiredor a named function). - Tool-result images ride in a follow-up user vision message (
image_urlparts) released once the tool round closes, sincerole:"tool"content is text-only; the[image]marker stays in the tool message as the anchor. - Rewrites Codex’s GPT-5 identity prompt to a model-agnostic intro so routed models don’t claim to be OpenAI.
- Clamps
reasoning_effortto the model’s advertised subset when an exact tier is unavailable;xhighandmaxremain distinct labels unless a provider explicitly configures an alias. The adapter omits it entirely for ids inprovider.noReasoningModels. - Streams
delta.content(text),delta.reasoning_content(thinking), anddelta.tool_calls[]; collectsusage. Providers listed inreasoningDetailsModels(MiniMax M-series) instead read structureddelta.reasoning_detailssegments, whosetextarrives as cumulative snapshots and is prefix-diffed, and replay preserved reasoning as areasoning_detailsarray. - ClinePass uses the live-verified gateway format
reasoning: { enabled: true, effort }(or{ enabled: false }when reasoning is disabled); its public API docs do not currently specify this request shape. The adapter preserves requestedlow,medium,high,xhigh, andmaxtiers, accepts reasoning deltas from eitherdelta.reasoning_contentordelta.reasoning, requests streamed usage withstream_options.include_usage, and reads usage from non-stream response envelopes.
Streaming tool calls retain their identity when a provider first sends an ID, then associates that ID with an index, and later sends index-only argument fragments. Those fragments assemble into one call with the original name and complete arguments; parallel calls retain separate identities. When present, streamed tool-call indexes must be non-negative safe integers. Non-numeric values and negative, fractional, or unsafe numbers terminate the stream with an upstream error before identity matching. Missing and null indexes remain absent-index placeholders; numeric strings are not coerced.
ollama-native
Section titled “ollama-native”Targets: Ollama’s own Chat API (POST /api/chat) rather than its OpenAI-compatible
surface. The built-in ollama-cloud provider is registry-selected onto this adapter; it can also
be configured on a separately named custom or self-hosted Ollama provider with
adapter: "ollama-native".
Auth: key (Bearer) for cloud/custom endpoints; no credential is sent to loopback or
authMode: "local" targets.
- Registry selection is load-bearing. The built-in
ollama-cloudrow keeps the base URLhttps://ollama.com/v1for/v1/modelslive discovery, while inference is normalized ontoPOST https://ollama.com/api/chat. A config-leveladapteris discarded for that provider row. Ordinary built-in local Ollama stays onopenai-chat; choosingollama-nativefor a local or self-hosted endpoint is an explicit provider-configuration decision, detected by host so a non-Ollama destination is never silently rewritten. - Model metadata:
/v1/modelscarries no per-model metadata, so for canonical Ollama Cloud the adapter’s provider enriches each discovered id through a boundedPOST /api/show(256 KiB per response, 8 s per request, concurrency 4, 48 requests, a 12 s deadline for the whole phase) to fill the true context window and vision capability. The show request is same-origin and never follows a redirect; failures degrade that one model and never fail discovery. - Streaming: Ollama’s native NDJSON. Text and
message.thinkingdeltas are forwarded as they arrive; a turn completes only on adone: trueterminal record, and buffereddone: falseor a missing terminal suppresses partial text and tool calls entirely. - Reasoning: maps onto Ollama’s native
thinkfield (low/medium/high/max, plus booleans), clamped to the model’s advertised ladder, and honours the__omit__sentinel semantics upstream configures. - Images: sent natively in the message
imagesarray where the model is vision-capable; video is refused rather than mis-sent, and remote image URLs are not fetched. - Tools: declared in Ollama’s native shape, streamed tool calls are whole-call records with
object-valued
arguments, and tool-result replay is paired strictly by call id and tool name.tool_choice: "none"andautobehave normally;requiredor an exact named choice fails closed, because Ollama’s/api/chathas notool_choicefield to enforce it with. - Structured output is refused on canonical Ollama Cloud. Ollama currently documents structured
outputs as unsupported on its Cloud, and Cloud does not enforce the
formatfield, so OpenCodex fails that request closed rather than returning unconstrained prose in answer to a schema-shaped request. Local and customollama-nativeendpoints keep Ollama’s nativeformatmapping (json_object→"json",json_schema→ the schema object).
openai-responses
Section titled “openai-responses”Targets: the OpenAI Responses API. passthrough: true — normally forwards the raw request
body and response, with narrow compatibility rewrites for routed gateways.
Auth: canonical OpenAI forward relays only the safe caller-header allowlist; noncanonical
forward uses configured static headers without relaying caller authorization; key uses the
configured provider key.
Adapter selection does not select the upstream transport. Eligible requests can use the
upstream WebSocket proxy route; invalid or unsupported
WebSocket proxy settings fall back to HTTP/SSE. HTTP fetch-based Responses handling uses Bun’s
HTTP proxy rules and does not inherit the WSS-specific ALL_PROXY fallback.
Noncanonical Responses gateways receive Codex’s client-executed tool_search declaration as a
collision-safe public function tool. Matching request history and JSON/SSE function calls are
translated back to the private tool_search lifecycle for the client. Canonical OpenAI forward
keeps the native private type unchanged.
For OpenCode Go at https://opencode.ai/zen/go/v1, requests with authMode other
than "forward" convert plaintext Codex agent_message items into public user messages, preserving content parts and readable author/recipient
metadata. This conversion leaves encrypted or unknown content unchanged and does not apply
to other destinations. Providers using authMode: "forward" retain these items unchanged.
See Go agent messages
for the separate opt-in encrypted-task recovery behavior.
The canonical ChatGPT Codex forward destination also normalizes two public Responses shapes that
its stricter backend rejects: fully textual system messages inside input are appended to the
top-level instructions string in request order, and the top-level truncation field is removed.
This rewrite is destination-scoped. Key-auth public/custom Responses providers and noncanonical
forward gateways keep both fields unchanged; a multimodal system message is never partially folded
or silently dropped.
For canonical forward continuations, client-only prompt_cache_breakpoint properties are removed
recursively within bounded traversal limits. When store: false, item_reference rows are also
omitted because the destination cannot resolve an item it did not persist. Function/tool call_id
pairs and reasoning.effort are preserved.
Luna Reserve compatibility uses this canonical ChatGPT-forward path, not key-auth or arbitrary Responses gateways. It retains the safe caller-header allowlist and destination-scoped request normalization described here. OpenCodex sends its Reserve capability header on the owned main-account usage lookup; that header is not itself permission. Eligible compatibility requests recheck credential-bound authorization at dispatch. Conversation and compaction are supported; vision helpers, web-search helpers, and standalone search relay are not.
For key auth, retryOn429 applies here too: a pre-stream 429
waits and replays the identical request on the same key before any other handling, exactly like
the translated openai-chat / Anthropic request path. Custom runTurn transports are not part
of the HTTP retry loop.
-
DeepSeek’s stateless Responses parser receives provider-scoped history normalization: hook-injected context moves after an unambiguous tool-call/result batch. Parallel calls remain grouped before their matching outputs so every call stays in the reasoning-bearing assistant turn. Tolerant providers and ambiguous duplicate, missing, or out-of-order call IDs keep their original input order.
-
forwardURL →{baseUrl}/responses. Akeyprovider defaults to the legacy{baseUrl}/v1/responsesconstruction. -
A
keyprovider may set a validated relativeresponsesPath; the adapter removes one trailing slash frombaseUrland sends{trimmedBaseUrl}{responsesPath}. For Ark Agent Plan, usebaseUrl: "https://ark.cn-beijing.volces.com/api/plan/v3"withresponsesPath: "/responses". -
In
forwardmode only a safe header allowlist is relayed (FORWARD_HEADERS): authorization, ChatGPT account id, and the OpenAI beta/originator/session headers. This is the ChatGPT-login path that also powers the sidecars.
Command Code session affinity
Section titled “Command Code session affinity”The OAuth command-code adapter derives an opaque x-session-id from the client
thread identity, then the reasoning-replay conversation identity. When neither is
available, it uses a prompt-cache key only if the integration has explicitly
classified that key as belonging to one conversation. Shared or unclassified cache
keys do not establish session affinity; requests without a usable identity receive
a fresh session ID. Recovery and cached-history replay preserve this classification.
The API-key commandcode provider uses the openai-chat adapter and supports
forwarding prompt_cache_key. This is separate from the OAuth adapter’s session
header and does not guarantee a provider cache hit.
anthropic
Section titled “anthropic”Targets: Anthropic Messages (/v1/messages).
Auth: key (x-api-key by default, or Authorization: Bearer with apiKeyTransport: "bearer") or oauth (Bearer + anthropic-beta, for Claude Pro/Max).
- Converts messages to Anthropic content blocks (text, base64 image,
tool_use,thinking). - Translated Anthropic Messages reasoning replay shares the request translation budget, including
encoding/decoding copy overhead. Requests exceeding it return HTTP 413 with
translation_buffer_limit; signatures and opaque reasoning data are never truncated to fit. Native Anthropic passthrough uses its separate body-size contract. - Extended thinking math: Anthropic requires
max_tokens > thinking.budget_tokens. The adapter maps reasoning effort to a budget (minimal 1024 … max 32000), then computes a safemax_tokenswith output headroom, and dropstemperature/top_pwhen thinking is enabled (Anthropic forbids them there). - Structured output: Responses
text.formatand Chat Completionsresponse_formatrequests withtype: "json_schema"become Anthropicoutput_config.format. The format merges into an existing adaptive-thinking output configuration, preserving a compatibleoutput_config.effort. Routed Anthropic Messages requests preserve the same format through stored-OAuth translation. The adapter mirrors the Anthropic TypeScript SDK’s supported JSON Schema subset: unsupported constraints are moved intodescriptionas model guidance,oneOfbecomesanyOf, and object schemas receiveadditionalProperties: false. A root$refretains its adjacent$defsso the local reference remains resolvable. OpenAI envelope fields such as schemaname, envelopedescription, andstrictare not part of the Anthropic wire format. JSON object mode without a schema has no Anthropic equivalent and is not translated. - Always sends
anthropic-version: 2023-06-01. Streamscontent_block_delta(text_delta,thinking_delta, compatiblereasoning_delta,input_json_delta). The SSE decoder preserves event state across fetch chunks and accepts a terminalmessage_stopwithout a trailing newline. - For routed Anthropic Responses turns with client tools, a bounded terminal guard detects the high-confidence case where the user requested an action but Claude ends with an execution claim and no tool call. It performs at most one internal continuation; normal answers, clarification questions, tool-using turns, and transport-incomplete responses are not auto-retried.
google
Section titled “google”Targets: Google Gemini, Vertex AI, and Antigravity Cloud Code Assist. AI Studio uses
/v1beta/models/{model}:streamGenerateContent; the other modes use their native Google endpoints.
Auth: API key, Vertex ADC, or Google Antigravity OAuth, selected by googleMode.
- Location denials are permission errors, not invalid requests. Google rejects unsupported
geographic or datacenter locations with HTTP 400
FAILED_PRECONDITION: User location is not supported for the API use.The proxy reports this as… location not supported: …and classifies it aspermission_errorwith codelocation_not_supported, so a client does not misread a network-location refusal as a malformed prompt. The direct HTTP response keeps the upstream 400; message-only terminal paths infer 403 (permission class). The restriction itself is Google’s — the proxy does not route around it. - System prompt →
systemInstruction; messages →contents[](assistant →model); tools →functionDeclarations. Data-URL images →inline_data. - Tool-call ids are synthesized when Gemini omits them. Vertex and Antigravity preserve and replay
opaque
thoughtSignaturevalues so tool-result continuations retain Gemini reasoning continuity. The signature cache is snapshotted to the config directory, so continuations also survive proxy restarts. - Malformed response shapes fail closed. A claimed candidate, its
content, or itscontent.partsthat is not the documented container terminates the turn with agoogle response contained invalid …error naming the structural reason and the offending value’s type — never its contents. Absence is handled separately from corruption: an absent,nullor emptycontentorpartsstill completes the turn normally, a streaming chunk whosecandidatesis absent,nullor empty is skipped so the turn completes on a later terminal frame, and a buffered response that carries no candidate at all returnsgoogle response contained no candidates. A rootdata: nullkeepalive frame is still skipped as padding. - Tool-call batches are closed by one immediately adjacent user turn containing one ordered
functionResponseper representable call. Interrupted histories receive an explicit missing-result marker; duplicate or standalone results are preserved as marked text (and image siblings) rather than emitted as invalid unpairedfunctionResponseparts. - Inline image output: when the model is one of the explicit image-capable chat IDs
(
gemini-3.1-flash-image,gemini-2.0-flash-preview-image-generation, orgemini-3-pro-image-preview), the adapter sendsresponseModalities: ["TEXT", "IMAGE"]. Standalone media-generation IDs such asgemini-3-pro-imageare not included. ReturnedinlineDataparts are materialized under the configured OpenCodexartifacts/directory and surfaced as markdown image links to the authenticated opaque route/v1/opencodex/artifacts/<id>(notfile:URIs or host filesystem paths). Each image is capped at 50 MB and each response at 100 MB of decoded data; malformed base64 payloads are rejected. Artifacts are pruned automatically when the count exceeds 200 files.
Targets: the Amazon CodeWhisperer Streaming GenerateAssistantResponse service used by Kiro
(https://runtime.{region}.kiro.dev/).
Auth: Kiro OAuth access token as Bearer, with region/profile metadata from the Kiro credential.
- Builds Kiro
conversationState, maps Codex tools and tool results, and sends image blocks supported by the Kiro wire. - Coalesces adjacent outputs from the same original tool call into one Kiro result. Text remains ordered, images retain the existing per-message limits, and any error flag remains set. User, developer, assistant or another tool’s output ends the group. Distinct original IDs that map to the same normalized Kiro ID are rejected.
- Combined outputs keep real text and failure information without inserting an empty-output hint for a later blank chunk. A single result keeps its existing normalization; an entirely text-empty group receives one fallback, with neutral wording when images or an error flag are present.
- Treats a client
parallel_tool_calls: truevalue as permission rather than a wire requirement. Kiro remains serialized: the routed catalog advertises no parallel-tool capability and the adapter sends no parallel-control field upstream, but ordinary Codex tool turns are not rejected solely because the client permits parallel calls. - Accepts Responses
textcontrols that are not structured output —text.verbosityandtext.format: {"type":"text"}— without forwarding them. Kiro has no wire field for either, so they are ignored rather than rejected. Structured output (text.formatof typejson_schemaorjson_object) is still refused: the Kiro wire cannot constrain the response shape, and a caller expecting JSON would otherwise receive prose. - Decodes
application/vnd.amazon.eventstream, reconstructs text/thinking/tool events, detects truncated tool JSON, and estimates usage because the upstream does not return token counts. - Uses the configured
baseUrlverbatim when it is custom. A canonicalruntime.{region}.kiro.devURL follows the imported credential’s API region; only that canonical shape is eligible for one bounded fallback toq.{region}.amazonaws.comafter an endpoint, signature, DNS, or connection failure. - Owns replay-safe connection-reset recovery, that single eligible endpoint fallback, one OAuth refresh/replay after HTTP 401, and bounded recovery for transient Kiro 429s. A shared cooldown and single post-cooldown probe prevent concurrent requests from exhausting independent retry budgets; hard quota failures and ordinary service errors are not replayed.
- Its non-streaming parser drains the same event stream for the web-search loop.
- Reports per-account usage.
AmazonCodeWhispererService.GetUsageLimitsonhttps://management.{region}.kiro.dev/returns the plan allowance, which becomes the monthly quota window for that account; a free-trial balance is reported as its own window. The region comes from the account’s profile ARN, then its stored API/SSO region. An unreadable or unrecognised response is reported as unknown rather than as zero usage, and an account whose overage is enabled is not treated as exhausted merely for passing its limit. The operation is undocumented by AWS, so treat the numbers as best-effort. - Participates in multi-account rotation. Two or more logged-in Kiro accounts enable automatic failover on a 429, and rotation prefers the account with the most known headroom; an account whose allowance is provably spent is cooled until its window resets (bounded between five minutes and a day) instead of being retried every minute. Each rotated bearer carries its own profile ARN and region.
Completion semantics
Section titled “Completion semantics”Kiro assistant text carries no dependable end-turn phase of its own. Its terminal metadataEvent
can carry a native stopReason, but Kiro can label progress prose as END_TURN. On tool-enabled
turns, END_TURN and STOP_SEQUENCE therefore prove only that the inference stopped; ordinary text
remains commentary and enters the one bounded completion validation.
END_TURN, STOP_SEQUENCE, or a missing stop reason may use the compatibility path. Other explicit
reasons have already terminated the inference upstream, so the adapter reports them instead of
spending another model request: an output-token limit surfaces as incomplete output that a client may continue, while
context-window exhaustion surfaces as a non-retryable context-length error rather than as truncated
output. Filtering and guardrail stops surface as filtered incomplete output, and a TOOL_USE stop
that arrives without an actual tool call is reported as a contradiction rather than treated as
progress.
When an ordinary client tool exists, opencodex adds a private
codex_kiro_final_answer tool to the upstream request; progress text streams as commentary and
cannot terminate the turn. The adapter consumes the private call, emits its answer as final text,
and never exposes the private tool to Codex or Claude Code. Because the stop reason only arrives at
the end of the stream, assistant text in a tool-enabled turn is held until either a real tool call
starts or the stream ends, then releases it as commentary unless the private tool supplied the final
answer. When the web-search sidecar is active, released
commentary still streams ahead of the terminal event; only the events needed to decide whether the
model requested a synthetic search remain buffered.
A question the model cannot proceed without is also a final answer. The injected contract tells a
routed model that when it needs a decision, a piece of information, or a clarification only the user
can give, it should deliver that question through codex_kiro_final_answer and stop, rather than
writing the question as ordinary text and continuing. Such a turn arrives like any other completed
answer: final text with the turn ended, not commentary and not a client tool call. Without this,
the contract described only “still working” and “fully complete”, and a model holding a blocking
question had no way to say so — the observed result was a question and a self-override emitted as one
message, followed by another tool call from the same inference.
If Kiro stops without calling the completion tool, the adapter makes one continuation. Reasoning-
only retries preserve the original valid user/tool-result turn rather than manufacturing an empty
assistant message; visible progress is replayed with a non-empty adapter-owned instruction. Before
transport, the generated conversation is checked for alternating roles, non-empty structural turns,
and matched tool-use/result ids. Empty tool output receives a neutral non-empty placeholder. The
retry cannot recurse: an empty or reasoning-only retry is returned as retryable incomplete, while a
real client tool call keeps the turn open. A completion-tool answer is always emitted as
final_answer, even when it exactly repeats prior commentary, because phase correctness is more
important than cosmetic de-duplication. Tool-free requests retain normal text completion behavior.
Reasoning effort
Section titled “Reasoning effort”gpt-5.6-sol and claude-opus-5 have verified native effort support, and each model family names
the request field differently. A selected low, medium, high, xhigh, or max value is sent
as additionalModelRequestFields.reasoning.effort for gpt-5.6-sol and as
additionalModelRequestFields.output_config.effort for claude-opus-5. Other Kiro models currently
use emulated reasoning: opencodex converts the selected level into bounded thinking instructions in
the user content because their native effort field has not been verified. Do not interpret an
advertised effort control on those models as proof of upstream-native reasoning support.
cursor
Section titled “cursor”Targets: Cursor’s agent.v1.AgentService/Run over HTTP/2 Connect streaming at api2.cursor.sh
by default. With upstreamHttpVersion: "http1.1" (or "h1"), uses Cursor’s HTTP/1.1
compatibility pair: agent.v1.AgentService/RunSSE for server output and
aiserver.v1.BidiService/BidiAppend for client messages.
Auth: Cursor OAuth/access token from provider.apiKey or the forwarded authorization header.
- Uses
runTurnrather than the ordinary fetch/parse path. Requests, server events, tool arguments, usage checkpoints, and client replies are encoded with@bufbuild/protobufschemas incursor/gen/agent_pb.tsand framed as Connect messages. - Replays conversation state through content-addressed blobs, maps server tool calls back to Codex,
discovers live Cursor models through the protobuf
GetUsableModelsRPC, and retries only before a run request is committed to the wire. - After a successful no-tool turn, the adapter keeps Cursor’s returned ConversationStateStructure in a process-local store and reuses that checkpoint on the next validated linear continuation instead of rebuilding the full root history. Tool-result turns reuse the last completed-turn checkpoint plus only the uncovered suffix when the covered message boundary is known. Ref-less prefix lookup requires a remembered Cursor conversation or stable client thread (including the bounded Desktop session/thread fallback) and a checkpoint owned by that same provider conversation; otherwise it full-replays. Compaction, helper/shadow isolation, account/model mismatch, missing refs, decode failures, forced-fresh recovery, and invalid_argument retries fall back to the existing full replay. A process restart drops the in-memory store and full-replays. Cursor Connect still does not expose authoritative cache_read_tokens, so OpenCodex usage is not a cache-hit counter. The bounded Desktop fallback stores only a process-local HMAC-derived owner; raw session/thread headers and OAuth/authorization material are never written to checkpoint state. Cursor’s OAuth-backed live transport and account-filtered model discovery remain experimental; see the provider guide and Cursor provider configuration for login and transport settings. Checkpoint reuse itself is automatic and has no user setting.
- Honors
upstreamHttpVersionfor both live model discovery and inference.auto,http2, andh2preserve the existing HTTP/2 transport; onlyhttp1.1andh1select compatibility mode. - Exposes Cursor Router as
cursor/autoplus explicitcursor/auto-cost,cursor/auto-balance, andcursor/auto-intelligenceentries. Explicit levels are encoded inrequested_model.parameterswhile the legacycursor/autoentry retains the account/team default. - Sends regular
cursor/grok-4.5tiers with Cursor’s exact live-discovery wire ids (cursor-grok-4.5-low,-medium, or-high). Keepscursor/grok-4.5-fastselectable while sending the canonicalgrok-4.5model with separateeffortandfast=trueparameters. - Cursor-native local filesystem/shell/network execution is denied by default. Explicit
mcpServersanddesktopExecutorintegrations have separate opt-ins;nativeLocalExec: "on"enables the broader built-in executor and bypasses Codex approval/sandbox semantics, and legacyunsafeAllowNativeLocalExec: trueremains equivalent only whennativeLocalExecis unset.
Codex-compatible shell schemas retain sandbox permissions, justification, reusable
prefix rules and login mode. Freeform tools expose one required string input
and preserve its tool-specific guidance, such as the required patch envelope;
bare exec_command and shell_command names are reserved for non-freeform shell
bridges. Namespace a custom freeform tool that uses either name. These schema
declarations do not grant approval or change execution policy.
azure-openai (alias: azure)
Section titled “azure-openai (alias: azure)”Targets: Azure OpenAI. Wraps openai-responses (so also passthrough: true).
Auth: key via the api-key header (not Bearer).
- Delegates request building to the Responses passthrough, validates that
baseUrlcontains no unresolved template placeholder, and replacesAuthorizationwithapi-key. The configured URL targets Azure’s v1 Responses API directly, so the adapter does not appendapi-version.
Image utilities (image.ts)
Section titled “Image utilities (image.ts)”Shared helpers used by the vision-aware adapters:
parseDataUrl(url)— split adata:<type>;base64,<data>URL into{ mediaType, base64 }for Anthropic/Google image blocks.contentPartsToText(content)— flatten content parts to text for text-only tool messages (an undescribed image becomes a short[image]marker, never a token-exploding base64 blob).
Grok Build terminal snapshots
Section titled “Grok Build terminal snapshots”Requests marked with x-opencodex-grok: 1 opt into a narrow Responses terminal
repair. If response.completed.response.output is missing or empty, opencodex
can reconstruct it from real, uniquely indexed, contiguous output_item.done
items whose raw fields satisfy the supported shapes. Deltas alone do not create
output. Malformed, contradictory, duplicated, gapped or oversized evidence keeps
the empty terminal unchanged; failed and incomplete responses never become success.
The marker is a client-selected compatibility option, not authenticated identity
or a permission grant. Unmarked clients retain their existing behavior. This
repair runs before the separate provider responsesSnapshotRepair option and
does not enable that broader lifecycle repair. Existing tool-search, custom-tool,
function-completion and undeclared-tool handling keep their established order.

