Skip to main content

codex_convert_proxy/convert/request/
tools.rs

1//! Tool conversion utilities for Responses API → Chat API.
2
3use crate::types::chat_api::{ChatTool, ChatToolChoice, ChatToolChoiceMode, FunctionChoice, FunctionDefinition};
4use crate::types::response_api::{
5    Tool as ResponseTool, ToolChoice as ResponseToolChoice,
6    ToolType as ResponseToolType,
7};
8
9/// Convert Responses API tools to Chat API tools.
10pub fn convert_tools(tools: Vec<ResponseTool>) -> Vec<ChatTool> {
11    tools
12        .into_iter()
13        .filter_map(|t| match t.tool_type {
14            ResponseToolType::Function | ResponseToolType::Custom | ResponseToolType::Other => {
15                Some(passthrough_tool(t))
16            }
17            ResponseToolType::WebSearchPreview => Some(builtin_tool(
18                t,
19                "web_search_preview",
20                "Web search tool",
21                serde_json::json!({
22                    "type": "object",
23                    "properties": {
24                        "query": {
25                            "type": "string",
26                            "description": "The search query"
27                        }
28                    },
29                    "required": ["query"]
30                }),
31            )),
32            ResponseToolType::CodeInterpreter => Some(builtin_tool(
33                t,
34                "code_interpreter",
35                "Code interpreter tool",
36                serde_json::json!({
37                    "type": "object",
38                    "properties": {
39                        "code": {
40                            "type": "string",
41                            "description": "The code to execute"
42                        }
43                    },
44                    "required": ["code"]
45                }),
46            )),
47            ResponseToolType::FileSearch => Some(builtin_tool(
48                t,
49                "file_search",
50                "File search tool",
51                serde_json::json!({
52                    "type": "object",
53                    "properties": {
54                        "query": {
55                            "type": "string",
56                            "description": "The search query"
57                        }
58                    },
59                    "required": ["query"]
60                }),
61            )),
62            ResponseToolType::Namespace => None,
63        })
64        .collect()
65}
66
67/// Pass through a tool as-is as a function tool.
68fn passthrough_tool(t: ResponseTool) -> ChatTool {
69    ChatTool {
70        tool_type: "function".to_string(),
71        function: FunctionDefinition {
72            name: t.name.unwrap_or_default(),
73            description: t.description,
74            parameters: t.parameters,
75        },
76    }
77}
78
79/// Convert a built-in tool to a function tool with default parameters.
80fn builtin_tool(
81    t: ResponseTool,
82    default_name: &str,
83    default_desc: &str,
84    param_schema: serde_json::Value,
85) -> ChatTool {
86    ChatTool {
87        tool_type: "function".to_string(),
88        function: FunctionDefinition {
89            name: t.name.unwrap_or_else(|| default_name.to_string()),
90            description: t.description.or_else(|| Some(default_desc.to_string())),
91            parameters: Some(param_schema),
92        },
93    }
94}
95
96/// Convert Responses API tool choice to Chat API tool choice.
97pub fn convert_tool_choice(choice: ResponseToolChoice) -> ChatToolChoice {
98    match choice {
99        ResponseToolChoice::Auto => ChatToolChoice::Mode(ChatToolChoiceMode::Auto),
100        ResponseToolChoice::None => ChatToolChoice::Mode(ChatToolChoiceMode::None),
101        ResponseToolChoice::Required => ChatToolChoice::Mode(ChatToolChoiceMode::Required),
102        ResponseToolChoice::Function(f) => ChatToolChoice::Function(FunctionChoice { name: f.name }),
103    }
104}
105
106/// Check if the tool choice is "none" (no tools).
107pub fn is_tool_choice_none(choice: &ChatToolChoice) -> bool {
108    match choice {
109        ChatToolChoice::Mode(mode) => *mode == ChatToolChoiceMode::None,
110        ChatToolChoice::Function(_) => false,
111    }
112}