Skip to content

fix(codex): preserve custom tool metadata in chat routing#3644

Merged
farion1231 merged 4 commits into
farion1231:mainfrom
LanternCX:fix/codex-custom-tool-metadata
Jun 4, 2026
Merged

fix(codex): preserve custom tool metadata in chat routing#3644
farion1231 merged 4 commits into
farion1231:mainfrom
LanternCX:fix/codex-custom-tool-metadata

Conversation

@LanternCX

@LanternCX LanternCX commented Jun 3, 2026

Copy link
Copy Markdown
Contributor

Summary / 概述

在 Codex 请求经由 chat 协议提供方转发时,保留自定义工具的完整元数据,避免协议转换后工具说明丢失。

以 Codex 的 apply_patch 为例:

原始 Responses 工具定义里会包含一些 Chat Completions 没有直接对应位置的字段,例如 freeform grammar 相关元数据:

{
  "type": "custom",
  "name": "apply_patch",
  "description": "Use the `apply_patch` tool to edit files. This is a FREEFORM tool, so do not wrap the patch in JSON.",
  "format": {
    "type": "grammar",
    "syntax": "lark",
    "definition": "start: begin_patch hunk+ end_patch"
  }
}

改动前,CC Switch 会把这个工具转换成普通的 Chat Completions function,只保留基础说明。像 format 这类 Responses 专用元数据会被丢弃,这会导致上游 llm 无法按照正常的格式进行 patch:

{
  "type": "function",
  "function": {
    "name": "apply_patch",
    "description": "Use the `apply_patch` tool to edit files. This is a FREEFORM tool, so do not wrap the patch in JSON.",
    "parameters": {
      "type": "object",
      "properties": {
        "input": {
          "type": "string",
          "description": "Raw string input for the original Codex custom tool. Preserve formatting exactly and follow the original tool definition embedded in the description."
        }
      },
      "required": ["input"]
    }
  }
}

改动后,CC Switch 仍然把自定义工具暴露为 Chat Completions function,但会把原始工具定义嵌入到 function description 里。这样上游 chat 协议模型依然能看到原本会丢失的元数据:

{
  "type": "function",
  "function": {
    "name": "apply_patch",
    "description": "Original tool definition:\n```json\n{\"description\":\"Use the `apply_patch` tool to edit files. This is a FREEFORM tool, so do not wrap the patch in JSON.\",\"format\":{\"definition\":\"start: begin_patch hunk+ end_patch\",\"syntax\":\"lark\",\"type\":\"grammar\"},\"name\":\"apply_patch\",\"type\":\"custom\"}\n```",
    "parameters": {
      "type": "object",
      "properties": {
        "input": {
          "type": "string",
          "description": "Raw string input for the original custom tool. Preserve formatting exactly and follow the original tool definition embedded in the description."
        }
      },
      "required": ["input"]
    }
  }
}

Related Issue / 关联 Issue

Ref #2806
Ref #2553

Screenshots / 截图

改动前,接入 DeepSeek 无法正常 patch:

image

改动后 DeepSeek 能够正常 Patch 成功:

image

Checklist / 检查清单

Clippy 的两条警告不是本次改动引入的

  • pnpm typecheck passes / 通过 TypeScript 类型检查
  • pnpm format:check passes / 通过代码格式检查
  • cargo clippy passes (if Rust code changed) / 通过 Clippy 检查(如修改了 Rust 代码)
  • Updated i18n files if user-facing text changed / 如修改了用户可见文本,已更新国际化文件

@farion1231

Copy link
Copy Markdown
Owner

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

To use Codex here, create a Codex account and connect to github.

@LanternCX
LanternCX force-pushed the fix/codex-custom-tool-metadata branch from 353598f to e5bc84e Compare June 3, 2026 13:23

@farion1231 farion1231 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢您的贡献!请查看一下这里是否存在 cache 稳定性问题:

serialize_tool_definition_for_description 目前优先使用 serde_json::to_string_pretty(tool)。但本项目启用了 serde_json/preserve_order,因此 pretty JSON 会保留输入对象的 key 顺序。这样同一个语义上的 custom tool,只要客户端发送字段顺序不同,最终嵌入到 function.description 的字符串也会不同。

这段 description 会进入上游请求体和 prompt 前缀,可能影响 prompt cache 命中的稳定性。项目里已有 canonical_json_string 用于 cache-sensitive JSON 输出,它会排序 object key,而且输出更紧凑,token 开销也更低。

是否可以考虑这里直接使用 canonical_json_string(tool),而不是把它作为 to_string_pretty 失败时的 fallback?

另外,当前 fallbackserialize_tool_definition_for_descriptionNone 分支看起来也基本不可达:走到 responses_custom_tool_description 时,responses_tool_name(tool) 已经成功,tool 实际上应当已经是 object。也可以顺手确认一下是否需要保留这些防御分支。

@LanternCX

LanternCX commented Jun 3, 2026

Copy link
Copy Markdown
Contributor Author

@farion1231

  • d61d0d3
    custom tool metadata 现在直接使用 canonical_json_string 输出,避免字段顺序不同导致 description 不稳定,同时保持更紧凑的输出。

  • 48c6d30
    已移除 custom tool description 里基本不可达的 fallback / None 分支,让这一路径始终嵌入原始 tool definition。

@farion1231 farion1231 left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢您的贡献!

@farion1231
farion1231 merged commit c2337d6 into farion1231:main Jun 4, 2026
3 checks passed
AnXiYiZhi pushed a commit to AnXiYiZhi/DevCLaw-old that referenced this pull request Jun 9, 2026
…#3644)

* fix(codex): preserve custom tool metadata in chat routing

* fix(codex): reduce custom tool metadata description overhead

* fix(codex): stabilize custom tool metadata descriptions

* refactor(codex): remove unreachable custom tool description fallback
gfunc pushed a commit to gfunc/cc-switch that referenced this pull request Jun 19, 2026
…#3644)

* fix(codex): preserve custom tool metadata in chat routing

* fix(codex): reduce custom tool metadata description overhead

* fix(codex): stabilize custom tool metadata descriptions

* refactor(codex): remove unreachable custom tool description fallback
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants