Skip to content

Proxy drops Codex tools sent as additional_tools input items — model receives no tools #466

Description

@HappyLiang12

Summary

Newer Codex builds (Codex Desktop 26.901 / codex.exe v0.153.4) no longer send tools in the top-level tools field of Responses requests. Instead, tools arrive as an input item of type additional_tools (with role: "developer"), containing the namespace/custom/function tool definitions.

The Responses→Chat Completions translation only collects tools from the top-level tools array, so every tool is silently dropped before forwarding to the upstream Chat backend. The model then receives a request with zero tools and truthfully answers that it has no callable tools — Codex effectively becomes text-only through the proxy.

This appears to be the same compatibility class as theagentrouter/agent-router#2586, which resolved it by adding support for the additional_tools input type.

Environment

  • cc-switch CLI 5.10.5 (latest release; also reproduced against main @ 1ae36f7), Windows x64
  • Codex: Codex Desktop 26.901 / codex.exe v0.153.4, provider with wire_api = "responses" pointing at the local proxy (http://127.0.0.1:15722/v1)
  • Upstream: Chat Completions backend (Azure OpenAI deployment)

Evidence

Captured request from Codex to the proxy (POST /v1/responses):

  • Top-level keys: client_metadata, include, input, model, parallel_tool_calls, prompt_cache_key, reasoning, store, stream, text, tool_choice — no tools key
  • input[0] is:
    {
      "type": "additional_tools",
      "id": "at_...",
      "role": "developer",
      "tools": [
        {
          "type": "namespace",
          "name": "functions",
          "tools": [
            { "type": "custom", "name": "exec", "..." : "..." },
            ...
          ]
        }
      ]
    }

A/B repro against the local proxy — identical tool and prompt, only tool placement differs:

  1. Tool in top-level tools → model returns a proper function_call:

    curl -s http://127.0.0.1:15722/v1/responses \
      -H "Content-Type: application/json" \
      -d '{"model":"<model>","stream":false,"tool_choice":"auto","tools":[{"type":"function","name":"get_weather","description":"Get current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}],"input":[{"type":"message","role":"user","content":"What is the weather in Hong Kong? You MUST use the get_weather tool."}]}'

    → output item {"type":"function_call","name":"get_weather","arguments":"{\"city\":\"Hong Kong\"}"}

  2. Same tool inside an additional_tools input item → model replies text-only:

    curl -s http://127.0.0.1:15722/v1/responses \
      -H "Content-Type: application/json" \
      -d '{"model":"<model>","stream":false,"tool_choice":"auto","input":[{"type":"additional_tools","id":"at_test_1","role":"developer","tools":[{"type":"function","name":"get_weather","description":"Get current weather for a city","parameters":{"type":"object","properties":{"city":{"type":"string"}},"required":["city"]}}]},{"type":"message","role":"user","content":"What is the weather in Hong Kong? You MUST use the get_weather tool."}]}'

    → assistant message: "I'm unable to access the get_weather tool in this chat" (no function_call)

Root cause

build_codex_tool_context_from_request in src-tauri/src/proxy/providers/transform_codex_chat.rs collects tools only from:

  • body["tools"], and
  • tool_search tool outputs found in input

additional_tools input items are never inspected, so add_response_tool never sees the tools nested inside them. grep -rn additional_tools src-tauri/src/ returns nothing, including on current main.

Suggested fix

Walk input for type == "additional_tools" and feed each nested tool through the existing add_response_tool (the nested shapes — namespace, custom, function — are already supported):

if let Some(input) = body.get("input").and_then(|v| v.as_array()) {
    for item in input {
        if item.get("type").and_then(|v| v.as_str()) == Some("additional_tools") {
            if let Some(tools) = item.get("tools").and_then(|v| v.as_array()) {
                for tool in tools {
                    context.add_response_tool(tool);
                }
            }
        }
    }
}

The response side (function_call → Chat tool_calls → function_call_output) looks already handled, so request-side tool extraction should restore the full loop.

Impact

Any user on the current Codex Desktop gets zero tool functionality (shell, file edits, MCP, plugins) through the proxy whenever the provider requires Responses→Chat translation.

Side note: the null-content fix from #448 is verified working in 5.10.5 — thank you. This is a separate gap exposed by the newer Codex.

Activity

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

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions