Repository navigation
Description
Client or integration
Codex Desktop on Windows 11, using OpenCodex /v1/responses.
Provider or upstream service
CLIProxyAPI-compatible gateway exposing both Gemini and xAI Grok 4.5 from one OpenAI-compatible base URL.
OpenCodex version
Reproduced on 2.7.35, then reproduced again after upgrading to 2.7.39.
Endpoint or capability
- OpenCodex inbound:
/v1/responses - Provider wire selected by OpenCodex:
/v1/chat/completions - Hosted
web_search - Streaming Responses events
Current behaviour
OpenCodex is configured with one OpenAI-compatible provider using adapter: "openai-chat". The gateway exposes both Gemini and Grok models.
localmodels/gemini-3.6-flash-high: hostedweb_searchworks and returnsweb_search_callplus a final message.localmodels/grok-4.5: the same Codex Responses request produces only areasoningitem followed byresponse.completed. There is noweb_search_calland no assistant message, so Codex records a completed turn with an empty final response.
Direct controls against the same gateway isolate the protocol boundary:
POST /v1/chat/completionswithgrok-4.5and a function namedweb_searchreturnsfinish_reason=stop, empty content, and no usabletool_calls.POST /v1/responseswithgrok-4.5andtools:[{"type":"web_search"}]succeeds, emitsweb_search_call, and returns a cited final message.- Gemini continues to work over Chat Completions.
The issue is therefore not authentication, model discovery, or the Codex client. A single OpenAI-compatible endpoint serves models that require different wire adapters, while OpenCodex currently selects adapter at provider scope.
Minimal redacted reproduction
Provider configuration:
{
"providers": {
"localmodels": {
"adapter": "openai-chat",
"baseUrl": "http://127.0.0.1:8317/v1",
"allowPrivateNetwork": true,
"apiKey": "${CLIPROXY_API_KEY}",
"defaultModel": "grok-4.5"
}
}
}Request to OpenCodex:
curl -N http://127.0.0.1:10100/v1/responses \
-H "Content-Type: application/json" \
-d '{
"model":"localmodels/grok-4.5",
"stream":true,
"input":[{"role":"user","content":[{"type":"input_text","text":"Use web search to find the official xAI Grok documentation. Return one official URL."}]}],
"tools":[{"type":"web_search"}],
"reasoning":{"effort":"high"},
"max_output_tokens":500
}'Controls:
- Change only the model to
localmodels/gemini-3.6-flash-high: succeeds withweb_search_callplus message. - Call the gateway directly at
/v1/responseswithgrok-4.5and hostedweb_search: succeeds. - Call the gateway directly at
/v1/chat/completionswithgrok-4.5and a function namedweb_search: completes without a usable function call.
Actual response
Observed through OpenCodex with localmodels/grok-4.5:
{
"http": 200,
"event_types": [
"response.created",
"response.output_item.added",
"response.output_item.done",
"response.completed"
],
"done_item_types": ["reasoning"],
"final_status": "completed",
"final_output_count": 1,
"text_length": 0
}Validated configuration-only workaround
Create a second provider for only Grok using openai-responses, then preserve the original public model id with a combo alias:
{
"providers": {
"localgrok": {
"adapter": "openai-responses",
"baseUrl": "http://127.0.0.1:8317/v1",
"allowPrivateNetwork": true,
"apiKey": "${CLIPROXY_API_KEY}",
"defaultModel": "grok-4.5",
"models": ["grok-4.5"],
"selectedModels": ["grok-4.5"],
"liveModels": false
}
},
"combos": {
"grok45-responses": {
"targets": [{"provider":"localgrok","model":"grok-4.5"}],
"strategy": "failover",
"alias": "localmodels/grok-4.5"
}
}
}After applying this workaround, the exact original model id produced:
{
"requested": "localmodels/grok-4.5",
"response_model": "grok-4.5-build",
"search_calls": 1,
"final_status": "completed",
"final_output_count": 5,
"text_length": 152
}An existing Codex task then performed two real web searches and returned a final message in 11.8 seconds. Gemini remained unchanged and returned its control marker in 2.2 seconds.
Expected behaviour
OpenCodex should support selecting the wire adapter per model, for example:
{
"modelAdapters": {
"grok-4.5": "openai-responses"
}
}A request for localmodels/grok-4.5 should preserve the hosted web_search tool and use the gateway's /v1/responses endpoint, while Gemini models on the same provider remain on openai-chat.
Suggested implementation notes
- Add an optional provider field such as
modelAdaptersormodelWireProtocols, mapping exact model ids or patterns toopenai-chat,openai-responses,anthropic, orgoogle. - Apply the configured mapping before the existing hard-coded
resolveWireProtocolOverridelogic. - Preserve current provider-wide behaviour when no model override exists.
- Reuse the normal Responses URL normalization so a base URL ending in
/v1maps to/v1/responses. - For
openai-responsesmodels, preserve hostedweb_searchinstead of converting it into a synthetic client function.
Suggested regression coverage:
- One provider exposes Gemini and Grok.
- Gemini resolves to
openai-chat. grok-4.5resolves toopenai-responses.- The Grok response contains
web_search_callplus a final message. - The public alias
localmodels/grok-4.5continues to route correctly. - Existing configs remain unchanged when no per-model mapping is present.
Until a native field exists, please document the tested split-provider plus combo-alias workaround.
Upstream documentation and related issues
- xAI Web Search: https://docs.x.ai/developers/tools/web-search
- Related CLIProxyAPI native
x_search/ clientweb_searchinteraction: v7.2.73+ always injects native x_search and breaks client function tool web_search on /v1/responses router-for-me/CLIProxyAPI#4339 - Related OpenCodex sidecar limitation: [Bug] Web Search/Vision Sidecar Backend Fixed to OpenAI·Anthropic - Routing Turns Fail with 499/502 When Limits are Exhausted #398
Additional context
Timings from the same machine:
- Grok Chat Completions failure: about 3.8 s
- Direct Grok Responses native search success: about 5.4 s
- OpenCodex workaround using the original model id: about 9.7 s
- Existing Codex task end-to-end: 11.8 s
- Gemini control: 2.2 s
The gateway build version is not exposed by its public root endpoint, so it is intentionally reported as unknown.
- I searched existing provider and compatibility issues.
- The request and response were redacted.
- The expected behaviour is based on a concrete client requirement and a passing direct Responses control.
Activity
github-actions commentedon Jul 24, 2026
Maintainer decision respected
A maintainer has reopened this issue. The automated closure has been deactivated.
docs(devlog): 260725_bug_sweep 로드맵 — 미해결 비-GUI 버그 5건 diff-level 계획
docs(devlog): 260725_bug_sweep r2 — A-gate blocker 12건 반영
docs(devlog): #404 modelAdapters 구현 계약 (A-gate PASS)
feat(providers): allow a per-model wire override on mixed gateways (#404
lidge-jun commentedon Jul 25, 2026
Fixed on
devin a758bfcf, included in integration SHAa5ec15e3.Providers can now declare a validated per-model
modelAdapterswire override, allowing the affected Grok model to useopenai-responseswhile sibling models on the same mixed gateway retainopenai-chat. Hard-pinned models and the canonical forward provider cannot be overridden, and the management/config/resolver layers share the same allowlist. English and Korean configuration references were updated.This closure is based on the enforced adapter and endpoint regression contract; the reporter’s gateway was not live-retested here.
Validation: Cross-platform CI and Service lifecycle passed for the exact integration SHA.
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
feat(go): wp1 types/config + OpenAI tiers (#404) — ModelAdapters, wir…
docs(devlog): 260725_bug_sweep 로드맵 — 미해결 비-GUI 버그 5건 diff-level 계획
docs(devlog): 260725_bug_sweep r2 — A-gate blocker 12건 반영
docs(devlog): lidge-jun#404 modelAdapters 구현 계약 (A-gate PASS)
feat(providers): allow a per-model wire override on mixed gateways (l…