Feature request: expose a provider-compatible native edit tool for third-party models

Open 💬 4 comments Opened Jul 15, 2026 by biaobiaobiao108

Summary

Codex advertises support for third-party/custom model providers, but third-party models currently do not receive the same native file-editing capabilities as OpenAI models. In particular, apply_patch is often absent from the tool list or cannot be used because the provider only accepts a different tool schema.

This makes third-party model support feel incomplete: the model can connect, call shell_command, and even find the injected apply_patch executable in the session environment, but it cannot call apply_patch as a first-class Codex tool.

Reproduction

  1. Configure a custom provider such as MiniMax, Azure, Ollama, or LM Studio.
  2. Use a custom model catalog entry.
  3. Try to enable apply_patch with:
"apply_patch_tool_type": "freeform"
  1. Ask the model to edit a file.

Depending on the provider and Codex version, one of the following happens:

  • apply_patch is not present in the model's tool list.
  • The model prints a patch as plain text instead of invoking a tool.
  • The provider rejects the generated custom/freeform tool schema.
  • The model can only invoke apply_patch indirectly through exec_command.

The current workaround is to run the session-injected apply_patch command through Shell, but that is not equivalent to exposing the native tool. The executable path is also session-local and unstable, for example:

~/.codex/tmp/arg0/<random-session>/apply_patch

Why this matters

Third-party model support should ideally mean feature parity for the Codex runtime, not only endpoint connectivity. File editing is a core coding-agent capability. Without a native edit tool, custom providers are forced to rely on fragile prompt behavior or Shell workarounds.

The current setup also makes debugging unnecessarily difficult because the relevant behavior depends on internal model metadata such as:

  • apply_patch_tool_type
  • base_instructions
  • provider-specific tool schema compatibility

Suggested improvements

1. Make native edit-tool support explicitly configurable

Allow users to declare tool compatibility per provider/model, for example:

[model_providers.minimax]
...
apply_patch_tool_type = "function"

or in the model catalog:

{
  "tools": {
    "shell": "shell_command",
    "file_edit": "function"
  }
}

The configuration should support at least:

  • standard function tools
  • freeform/custom tools
  • disabled tools

2. Provide a compatibility fallback

If a provider cannot accept the native freeform tool, Codex should be able to expose a standard JSON function wrapper that accepts a patch string, then execute the same safe patch engine locally.

This would allow providers that support ordinary function calling to use file editing without requiring the provider to understand OpenAI-specific freeform tool types.

3. Improve model-catalog diagnostics

When a model has no apply_patch capability, Codex should report why:

  • tool disabled by catalog
  • provider schema incompatible
  • unsupported tool type
  • missing model metadata

A startup diagnostic such as the following would be very helpful:

Model MiniMax-M3: apply_patch disabled
Reason: provider only supports standard function tools; catalog requests freeform
Suggested configuration: apply_patch_tool_type = "function"

4. Rename or alias the tool to something more understandable

apply_patch is an implementation-oriented name. It is familiar to Unix developers, but it is not immediately clear to users or many models that it edits files.

Please consider exposing a user/model-facing alias such as:

  • edit_file
  • apply_file_changes
  • modify_file

while keeping apply_patch as an internal compatibility alias.

A tool description such as this would also help:

edit_file:
Apply a structured, context-checked change to one or more files in the workspace.

The implementation can remain patch-based while the public tool name becomes self-explanatory.

Expected behavior

When a custom provider supports standard function calling, Codex should be able to expose a first-class file-editing tool with a provider-compatible schema:

edit_file({
  "patch": "..."
})

The Codex host should execute the patch locally, apply the same workspace and permission checks used by the native tool, and return a structured result to the model.

This would preserve the safety and atomicity of patch-based editing while making third-party provider support reliable and understandable.

View original on GitHub ↗

4 Comments

zazula · 1 month ago

Concrete Codex 0.145.0 datapoint with a self-hosted Qwen3-Coder-Next 36B no-think route over /v1/responses:

  • features.apply_patch_freeform=false: model inspected the repository and selected apply_patch; the turn failed HTTP 400 with Expecting property name enclosed in double quotes while parsing the tool arguments.
  • features.apply_patch_freeform=true: same bounded task and endpoint; first apply_patch failed HTTP 400 with Invalid control character.
  • Both failed before any worktree mutation. Ordinary command-execution tools worked.
  • The two modes therefore expose the tool, but neither yields a provider-compatible patch-call payload on this route.

Sanitized exact prompt/configs, filtered error events, stderr, exit codes, and SHA256SUMS: https://github.com/zazula/continuity/tree/f311441066580d1f14f75b4e9b2e49a05213cdaf/experiments/context-continuity/evidence/qwen36-codex-patch-20260725

This supports the proposed standard JSON function wrapper (edit_file({patch: ...})) as the compatibility boundary: the model demonstrated correct task diagnosis and tool choice, while the current patch serialization failed before host execution.

madmax24-ubuntu · 9 days ago

I implemented the function-wrapper fallback proposed here for local llama.cpp providers: https://github.com/madmax24-ubuntu/codex-proxy-llama.cpp

Codex's native apply_patch is bridged through a strict standard function schema on the model-facing side and translated back to the native freeform apply_patch call before Codex handles it. That keeps the IDE diff view / Codex patch execution while allowing function-only local models/backends to invoke edits reliably.

The same proxy also handles Responses streaming, MCP namespace translation, tool-history replay, reasoning and compaction. Posting this mainly as a working reference for the apply_patch_tool_type = "function" direction described in this issue.

louis-tepe · 9 days ago

OpenCodex 2.26.0 / Codex Desktop 0.148.0-alpha.15 datapoint for the code_mode_only path:

  • Native Code Mode exposes one freeform exec body containing JavaScript; apply_patch is a nested tools.apply_patch(input: string) helper rather than a top-level wire tool.
  • A routed openai-chat adapter lowers the outer custom exec to a standard {input:string} function. Offline fixtures containing multiline patches, quotes, backslashes, template syntax, and Unicode round-trip exactly, so I found no deterministic double-escaping corruption.
  • The remaining failure is model/provider compliance: in three fresh xai/grok-4.6 canaries, only 1/3 produced a real custom_tool_call event. The other two printed a semantically correct JSON-looking exec call as ordinary text. A Vercel-routed Muse model produced 0/3 tool events under tool_choice:auto.

This supports the standard JSON editing function proposed here as the clean long-term boundary. For nested Code Mode, an additional compatible improvement would be explicit helper usage metadata or a compact canonical await tools.apply_patch(...) example. I would avoid blindly attaching the direct Lark grammar to the nested JavaScript function: the outer custom-tool grammar validates JavaScript, while the helper still receives a raw string.

Sanitized OpenCodex reproduction and constraints: https://github.com/lidge-jun/opencodex/issues/2111

luoqianlin · 6 days ago

Additional reproduction: Qwen3 models using a Responses-compatible third-party provider can receive apply_patch as a freeform tool, but emit JSON object arguments instead of the raw patch text. Codex 0.149.0 then rejects every call in the router with:

apply_patch verification failed: invalid patch: The first line of the patch must be '*** Begin Patch'

Environment:

  • Codex CLI: 0.149.0
  • Models: qwen3.8-max and qwen3.7-max
  • Provider: Alibaba DashScope compatible Responses endpoint
  • Catalog: apply_patch_tool_type: "freeform"

Both models reproduced the failure repeatedly (17 consecutive failures in a headless qwen3.7-max run). The rollout records show the model sending apply_patch custom tool calls with JSON payloads, followed by the same freeform parser error. GPT-5.6 and DeepSeek-V4 succeeded with the same Add+Update test through their respective providers.

The shell-injected apply_patch executable works as a workaround, but this is not equivalent to a native tool. A provider/model capability that exposes a function/object form of apply_patch, or normalizes function arguments before the freeform handler, would address this class of third-party model incompatibility.