Skip to content

Grok 4.5 behind a mixed OpenAI-compatible gateway returns reasoning-only on web_search; needs per-model adapter override #404

Closed

Description

@xiaoke949

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: hosted web_search works and returns web_search_call plus a final message.
  • localmodels/grok-4.5: the same Codex Responses request produces only a reasoning item followed by response.completed. There is no web_search_call and no assistant message, so Codex records a completed turn with an empty final response.

Direct controls against the same gateway isolate the protocol boundary:

  1. POST /v1/chat/completions with grok-4.5 and a function named web_search returns finish_reason=stop, empty content, and no usable tool_calls.
  2. POST /v1/responses with grok-4.5 and tools:[{"type":"web_search"}] succeeds, emits web_search_call, and returns a cited final message.
  3. 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 with web_search_call plus message.
  • Call the gateway directly at /v1/responses with grok-4.5 and hosted web_search: succeeds.
  • Call the gateway directly at /v1/chat/completions with grok-4.5 and a function named web_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 modelAdapters or modelWireProtocols, mapping exact model ids or patterns to openai-chat, openai-responses, anthropic, or google.
  • Apply the configured mapping before the existing hard-coded resolveWireProtocolOverride logic.
  • Preserve current provider-wide behaviour when no model override exists.
  • Reuse the normal Responses URL normalization so a base URL ending in /v1 maps to /v1/responses.
  • For openai-responses models, preserve hosted web_search instead of converting it into a synthetic client function.

Suggested regression coverage:

  1. One provider exposes Gemini and Grok.
  2. Gemini resolves to openai-chat.
  3. grok-4.5 resolves to openai-responses.
  4. The Grok response contains web_search_call plus a final message.
  5. The public alias localmodels/grok-4.5 continues to route correctly.
  6. 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

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

  1. github-actions commented on Jul 24, 2026

    @github-actions
    Contributor

    Maintainer decision respected

    A maintainer has reopened this issue. The automated closure has been deactivated.

  2. reopened this on Jul 25, 2026
  3. lidge-jun commented on Jul 25, 2026

    @lidge-jun
    Owner

    Fixed on dev in a758bfcf, included in integration SHA a5ec15e3.

    Providers can now declare a validated per-model modelAdapters wire override, allowing the affected Grok model to use openai-responses while sibling models on the same mixed gateway retain openai-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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions