mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-08-03 19:12:04 +08:00
fix(codex): preserve custom tool metadata in chat routing (#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
This commit is contained in:
@@ -40,6 +40,8 @@ const EXTRA_CHAT_PASSTHROUGH_FIELDS: &[&str] = &[
|
|||||||
const TOOL_SEARCH_PROXY_NAME: &str = "tool_search";
|
const TOOL_SEARCH_PROXY_NAME: &str = "tool_search";
|
||||||
const CUSTOM_TOOL_INPUT_FIELD: &str = "input";
|
const CUSTOM_TOOL_INPUT_FIELD: &str = "input";
|
||||||
const CHAT_TOOL_NAME_MAX_LEN: usize = 64;
|
const CHAT_TOOL_NAME_MAX_LEN: usize = 64;
|
||||||
|
const CUSTOM_TOOL_INPUT_DESCRIPTION: &str = "Raw string input for the original custom tool. Preserve formatting exactly and follow the original tool definition embedded in the description.";
|
||||||
|
const CUSTOM_TOOL_PRESERVED_METADATA_HEADING: &str = "Original tool definition:";
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub(crate) enum CodexToolKind {
|
pub(crate) enum CodexToolKind {
|
||||||
@@ -132,10 +134,7 @@ impl CodexToolContext {
|
|||||||
let Some(name) = responses_tool_name(tool) else {
|
let Some(name) = responses_tool_name(tool) else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let description = tool
|
let description = json!(responses_custom_tool_description(tool));
|
||||||
.get("description")
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(|| json!("Custom Codex tool."));
|
|
||||||
let chat_tool = json!({
|
let chat_tool = json!({
|
||||||
"type": "function",
|
"type": "function",
|
||||||
"function": {
|
"function": {
|
||||||
@@ -146,7 +145,7 @@ impl CodexToolContext {
|
|||||||
"properties": {
|
"properties": {
|
||||||
CUSTOM_TOOL_INPUT_FIELD: {
|
CUSTOM_TOOL_INPUT_FIELD: {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Input to pass to the custom Codex tool."
|
"description": CUSTOM_TOOL_INPUT_DESCRIPTION
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [CUSTOM_TOOL_INPUT_FIELD]
|
"required": [CUSTOM_TOOL_INPUT_FIELD]
|
||||||
@@ -1016,6 +1015,22 @@ fn responses_tool_name(tool: &Value) -> Option<String> {
|
|||||||
.map(ToString::to_string)
|
.map(ToString::to_string)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn responses_custom_tool_description(tool: &Value) -> String {
|
||||||
|
let mut description = String::new();
|
||||||
|
description.push_str(CUSTOM_TOOL_PRESERVED_METADATA_HEADING);
|
||||||
|
description.push_str("\n```json\n");
|
||||||
|
description.push_str(&serialize_tool_definition_for_description(tool));
|
||||||
|
description.push_str("\n```");
|
||||||
|
description
|
||||||
|
}
|
||||||
|
|
||||||
|
fn serialize_tool_definition_for_description(tool: &Value) -> String {
|
||||||
|
// Keep the embedded definition compact to reduce tool-description token
|
||||||
|
// overhead for chat-only upstreams, while remaining stable across map
|
||||||
|
// storage order.
|
||||||
|
canonical_json_string(tool)
|
||||||
|
}
|
||||||
|
|
||||||
fn responses_function_tool_to_chat_tool(tool: &Value, chat_name: &str) -> Option<Value> {
|
fn responses_function_tool_to_chat_tool(tool: &Value, chat_name: &str) -> Option<Value> {
|
||||||
if tool.get("type").and_then(|v| v.as_str()) != Some("function") {
|
if tool.get("type").and_then(|v| v.as_str()) != Some("function") {
|
||||||
return None;
|
return None;
|
||||||
@@ -1857,6 +1872,34 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn responses_request_to_chat_preserves_custom_tool_metadata_in_description() {
|
||||||
|
let input = json!({
|
||||||
|
"model": "gpt-5.4",
|
||||||
|
"tools": [{
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
|
let result = responses_to_chat_completions(input).unwrap();
|
||||||
|
let description = result["tools"][0]["function"]["description"]
|
||||||
|
.as_str()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert!(description.starts_with("Original tool definition:"));
|
||||||
|
assert!(!description.contains("Original Codex tool definition"));
|
||||||
|
assert!(description.contains("\"type\":\"custom\""));
|
||||||
|
assert!(description.contains("\"format\":"));
|
||||||
|
assert!(description.contains("\"syntax\":\"lark\""));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn responses_request_to_chat_uses_provider_reasoning_effort_for_deepseek_model() {
|
fn responses_request_to_chat_uses_provider_reasoning_effort_for_deepseek_model() {
|
||||||
let input = json!({
|
let input = json!({
|
||||||
|
|||||||
Reference in New Issue
Block a user