fix(codex): preserve custom tool metadata in chat routing#3644
Conversation
|
@codex review |
|
To use Codex here, create a Codex account and connect to github. |
353598f to
e5bc84e
Compare
There was a problem hiding this comment.
感谢您的贡献!请查看一下这里是否存在 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?
另外,当前 fallback 和 serialize_tool_definition_for_description 的 None 分支看起来也基本不可达:走到 responses_custom_tool_description 时,responses_tool_name(tool) 已经成功,tool 实际上应当已经是 object。也可以顺手确认一下是否需要保留这些防御分支。
…#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
…#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
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:
改动后 DeepSeek 能够正常 Patch 成功:
Checklist / 检查清单
Clippy 的两条警告不是本次改动引入的
pnpm typecheckpasses / 通过 TypeScript 类型检查pnpm format:checkpasses / 通过代码格式检查cargo clippypasses (if Rust code changed) / 通过 Clippy 检查(如修改了 Rust 代码)