Skip to content

Codex Responses proxy drops tool_search during request normalization #1907

@TerenceXin

Description

@TerenceXin

Summary

When 9Router is used as a Codex Responses API proxy, tool_search is removed from the outgoing request before the request is forwarded upstream.

This breaks Codex deferred tool discovery. In Codex Desktop, tools such as app automation, thread-management tools, and multi_agent_v1 tools are normally discovered through tool_search. Once the proxy drops tool_search, the model has no entrypoint to discover those deferred tools, so they appear to be missing in the session.

This is a request-normalization issue in 9Router, not a model capability issue.

Affected code

open-sse/executors/codex.js

normalizeCodexTools(body) currently keeps:

  • function
  • namespace
  • tool types listed in CODEX_HOSTED_TOOL_TYPES

But tool_search is neither a function nor in CODEX_HOSTED_TOOL_TYPES, so it is filtered out.

Minimal reproduction

Run this from the 9Router source checkout:

node --input-type=module <<'EOF'
import { CodexExecutor } from './open-sse/executors/codex.js';

const executor = new CodexExecutor();
const body = {
  model: 'gpt-5.5',
  input: [
    { type: 'message', role: 'user', content: [{ type: 'input_text', text: 'probe' }] }
  ],
  tools: [
    { type: 'tool_search', execution: 'sync', description: 'Discover deferred tools', parameters: { type: 'object', properties: {} } },
    { type: 'namespace', name: 'codex_app', description: 'app tools', tools: [
      { type: 'function', name: 'automation_update', description: 'automation', parameters: { type: 'object', properties: {} }, defer_loading: true }
    ] },
    { type: 'function', name: 'plain_fn', description: 'plain', parameters: { type: 'object', properties: {} } }
  ],
  stream: true
};

const before = body.tools.map(t => t.type + ':' + (t.name || ''));
executor.transformRequest('gpt-5.5', body, true, { connectionId: 'probe', providerSpecificData: {} });
const after = body.tools.map(t => t.type + ':' + (t.name || ''));

console.log(JSON.stringify({ before, after, dropped: before.filter(x => !after.includes(x)) }, null, 2));
EOF

Actual output:

{
  "before": [
    "tool_search:",
    "namespace:codex_app",
    "function:plain_fn"
  ],
  "after": [
    "namespace:codex_app",
    "function:plain_fn"
  ],
  "dropped": [
    "tool_search:"
  ]
}

Expected behavior

9Router should preserve tool_search for Codex/OpenAI Responses requests when forwarding to a Codex-compatible upstream.

Impact

  • Codex Desktop deferred tools cannot be discovered through tool_search.
  • App automation tools, thread-management tools, and multi_agent_v1 tools appear missing when using 9Router as the provider.
  • This can be mistaken for a Codex version/configuration problem, but the immediate cause is that the proxy removes the discovery tool from the request.

Additional observation

The same request-normalization path also drops custom / freeform tools, because custom is also not in the allowlist. For example:

{ type: 'custom', name: 'apply_patch', description: 'patch', format: { type: 'grammar', syntax: 'lark', definition: 'start: /.+/' } }

This may be related to #1371, but it is a different code path: this issue is about request-time filtering in open-sse/executors/codex.js, while #1371 describes response translation not preserving custom_tool_call output.

Related issues

Suggested fix

Update normalizeCodexTools() to preserve tool_search for Codex Responses requests, and add regression coverage showing that these tool types survive request normalization:

  • function
  • namespace
  • tool_search
  • hosted tools such as web_search, image_generation, mcp, local_shell, code_interpreter, computer

If custom tools are intended to be supported, preserve them there as well, including their format payload.

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