Skip to content

fix(claude): resolve web_search tool_choice and invalid reasoning summary when routing Claude Desktop to OpenAI models #1426

Closed

Description

@tqctqc1

Client or integration

Other

Provider or upstream service

OpenAI (Codex login / Responses API)

OpenCodex version

2.7.38

Endpoint or capability

/v1/responses (Claude Desktop Messages -> Responses translation)

Current behaviour

When routing Claude Desktop requests to OpenAI upstream models (gpt-5.6-luna, gpt-5.4-mini):

  1. Turns with disabled thinking (thinking: { type: "disabled" }) set reasoning: { effort: "none", summary: "none" }. OpenAI rejects summary: "none" with HTTP 400 invalid_request_error: Invalid value: 'none'. Supported values are: 'concise', 'detailed', and 'auto'.
  2. Enforced web_search tool choice (tool_choice: { type: "tool", name: "web_search" }) sets tool_choice: { type: "function", name: "web_search" } while tools array contains { type: "web_search" }. OpenAI rejects with HTTP 400 invalid_request_error: Tool choice 'function' not found in 'tools' parameter.

Expected behaviour

  1. Explicitly disabled thinking in inbound.ts should set reasoning: { effort: "none" } without emitting invalid summary: "none".
  2. Hosted web_search tool choice should map to { type: "web_search" } instead of { type: "function", name: "web_search" }.
  3. Unmatched function tool choices should be sanitized or downgraded to "auto" in openai-responses.ts before upstream dispatch.

Minimal redacted request or reproduction

// Inbound Anthropic request from Claude Desktop on WebSearch:
{
  "model": "gpt-5.6-luna",
  "thinking": { "type": "disabled" },
  "tools": [{ "name": "web_search", "type": "web_search" }],
  "tool_choice": { "type": "tool", "name": "web_search" }
}

Actual response or error

HTTP 400 Bad Request
{
  "error": {
    "type": "invalid_request_error",
    "message": "Invalid value: 'none'. Supported values are: 'concise', 'detailed', and 'auto'."
  }
}
// and subsequently:
{
  "error": {
    "type": "invalid_request_error",
    "message": "Tool choice 'function' not found in 'tools' parameter."
  }
}

Upstream documentation

https://docs.anthropic.com/en/api/messages

Suggested mapping or implementation notes

In src/claude/inbound.ts:

  1. Remove summary: "none" from body.reasoning when thinkingDisabled is true.
  2. Use isClaudeWebSearchToolName(choice.name) in toolChoiceToResponses to map tool_choice to { type: "web_search" } when target is a hosted web_search tool.

In src/responses/schema.ts:

  1. Add "web_search" to hostedToolType enum.

In src/adapters/openai-responses.ts:

  1. Add stripInvalidReasoningSummary to strip invalid summary values (like "none").
  2. Add sanitizeUnmatchedToolChoice to sanitize function tool choices that don't match any function declared in tools.

Additional context and attachments

Verified fix locally on Windows with Claude Desktop 3P mode.

Checks

  • I searched existing provider and compatibility issues.
  • The request and response were redacted.
  • The expected behaviour is based on an upstream specification or a concrete client requirement.

Activity

  1. added
    providerProvider adapters, OpenAI-compat presets, upstream API quirks
    on Aug 10, 2026
  2. Ingwannu commented on Aug 10, 2026

    @Ingwannu
    Owner

    Confirmed on current dev (08e7e0fda): this is a real Claude Messages to Responses translation bug, not only a 2.7.38 report.

    The current translator emits reasoning: { effort: "none", summary: "none" } for explicit disabled thinking even though the OpenAI Responses endpoint rejects summary: "none". It also translates every Anthropic named tool choice into a function choice, while the same request translates a Claude hosted web-search declaration into { type: "web_search" }; the choice and declaration therefore cannot match. The request schema also does not currently admit { type: "web_search" } as a hosted choice.

    I will make the narrow protocol fix:

    1. keep disabled thinking explicit as { effort: "none" } without the invalid summary value;
    2. reuse the existing Claude web-search name predicate so a forced WebSearch/web_search choice becomes { type: "web_search" };
    3. add web_search to the hosted Responses tool-choice schema;
    4. add regressions that pass both responsesRequestSchema and the real parseRequest boundary while preserving ordinary named function choices.

    I will not generically downgrade an unmatched forced function choice to auto: that would silently relax the caller's required-tool intent and could select a different tool. Other mismatches should remain fail-closed unless a separate, evidence-backed mapping exists. I will link the draft PR and exact verification here after the focused fix is pushed.

  3. Ingwannu commented on Aug 10, 2026

    @Ingwannu
    Owner

    Implemented in draft PR #1428: #1428

    The current-dev fix removes the invalid reasoning.summary: "none", preserves explicit disabled thinking as effort: "none", and maps a forced Claude WebSearch/web_search choice to the hosted Responses { type: "web_search" } declaration. Ordinary named function choices remain unchanged; arbitrary mismatches are not silently weakened to auto.

    Verification: 28 focused inbound tests passed, including both responsesRequestSchema and real parseRequest boundaries; typecheck, privacy scan, the 221-page docs build, and diff checks also passed. Leaving the issue open until exact-head CI and independent review complete and the PR is integrated into dev.

  4. Wibias commented on Aug 11, 2026

    @Wibias
    Contributor

    Fixed by #1428

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

    providerProvider adapters, OpenAI-compat presets, upstream API quirksprovider-compatibilityProvider compatibility reports

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions