openai / openai/codex

Code Mode: support function-backed `exec` for providers without custom/freeform tool support

Open
#37,825 2 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

CLI custom-model enhancement tool-calls
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

Summary

Codex Code Mode currently exposes its public exec entrypoint as a custom/freeform tool.

This works with providers that support Codex/OpenAI custom tools, but prevents Code Mode from working with Responses-compatible providers that support ordinary function calling while rejecting type: "custom" / freeform tools.

A provider-capability-backed function transport for Code Mode exec could solve this without introducing a second Code Mode runtime.

Reproduction

Environment:

  • Codex CLI
  • Responses API provider: DeepSeek official endpoint
  • Model: deepseek-v4-flash

Enable Code Mode:

codex -c 'features.code_mode.enable=true'

Prompt:

Use code mode to analyze this project.
Please use JavaScript tool execution to inspect multiple files programmatically.

Observed:

Code Mode is enabled in configuration, but model `deepseek-v4-flash` does not advertise Code Mode support.

Unsupported custom tool: 'exec'. Only 'apply_patch' is supported.

The failure happens at the provider tool schema boundary before the Code Mode runtime is reached.

Current behavior

The current flow is effectively:

model
  -> custom/freeform exec(JavaScript)
  -> CodeModeExecuteHandler
  -> existing V8 runtime

The runtime itself is not the compatibility problem. The provider cannot accept the public representation of exec.

Proposed direction

Add a capability-based Code Mode exec transport:

CodeModeExecTransport:
  Freeform
  Function

For providers supporting custom/freeform tools, keep the existing behavior.

For providers supporting only function tools, expose something like:

{
  "type": "function",
  "name": "exec",
  "parameters": {
    "type": "object",
    "properties": {
      "code": {
        "type": "string"
      }
    },
    "required": ["code"]
  }
}

Then normalize the function payload at the handler boundary:

ToolPayload::Function
  -> extract code
  -> existing CodeModeExecuteHandler
  -> existing V8 execution path

This keeps one Code Mode implementation and only changes the model-facing tool representation.

Motivation

Responses API compatibility does not always mean full support for every OpenAI-specific tool type.

Many providers support:

  • Responses API
  • function calling
  • reasoning/tool use

but not arbitrary custom/freeform tools.

A function-backed Code Mode transport would allow more providers and models to reuse the existing Code Mode runtime without provider-specific hacks.

Potentially affected providers include:

  • DeepSeek
  • local Responses-compatible servers
  • other third-party model providers

Related areas

This appears related to existing provider compatibility discussions:

  • namespace tool flattening for providers without namespace support
  • Code Mode tool conversion
  • provider capability detection
  • custom tool compatibility

The main question is whether exec is intentionally tied to custom/freeform tools or whether it should support multiple wire representations depending on provider capabilities.

Suggested acceptance criteria

  1. Existing custom/freeform-capable providers continue using the current exec representation.
  2. Function-only providers can select a function-backed exec representation.
  3. Both paths reach the same Code Mode runtime.
  4. JavaScript execution, nested tools.* calls, MCP routing, and yielded execution continue to work unchanged.
  5. No model-specific checks such as if deepseek are required.

A small proof of concept should only need changes around the public tool specification and payload normalization, while keeping the existing Code Mode runtime untouched.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at the public Code Mode exec tool specification and provider capability detection, then trace function payload normalization into CodeModeExecuteHandler and the existing V8 execution path. Compare the Freeform and Function representations while preserving the shared runtime. Done means custom-tool providers remain unchanged and function-only providers pass JavaScript execution, nested tools.* calls, MCP routing, and yielded execution through the same runtime.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
api, cli, devtools
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.