fix(openai): flatten tools and tool_choice for Responses API
Some checks failed
CI / Check (push) Has been cancelled
CI / Clippy (push) Has been cancelled
CI / Formatting (push) Has been cancelled
CI / Test (push) Has been cancelled
CI / Release Build (push) Has been cancelled

- Map nested 'function' object to top-level fields
- Support string and object-based 'tool_choice' formats
- Fix 400 Bad Request 'Missing required parameter: tools[0].name'
This commit is contained in:
2026-03-18 14:00:49 +00:00
parent 275ce34d05
commit 83e0ad0240

View File

@@ -226,10 +226,33 @@ impl super::Provider for OpenAIProvider {
} }
if let Some(tools) = &request.tools { if let Some(tools) = &request.tools {
body["tools"] = serde_json::json!(tools); let flattened: Vec<serde_json::Value> = tools.iter().map(|t| {
let mut obj = serde_json::json!({
"type": t.tool_type,
"name": t.function.name,
});
if let Some(desc) = &t.function.description {
obj["description"] = serde_json::json!(desc);
}
if let Some(params) = &t.function.parameters {
obj["parameters"] = params.clone();
}
obj
}).collect();
body["tools"] = serde_json::json!(flattened);
} }
if let Some(tool_choice) = &request.tool_choice { if let Some(tool_choice) = &request.tool_choice {
body["tool_choice"] = serde_json::json!(tool_choice); match tool_choice {
crate::models::ToolChoice::Mode(mode) => {
body["tool_choice"] = serde_json::json!(mode);
}
crate::models::ToolChoice::Specific(specific) => {
body["tool_choice"] = serde_json::json!({
"type": specific.choice_type,
"name": specific.function.name,
});
}
}
} }
let resp = self let resp = self
@@ -574,10 +597,33 @@ impl super::Provider for OpenAIProvider {
} }
if let Some(tools) = &request.tools { if let Some(tools) = &request.tools {
body["tools"] = serde_json::json!(tools); let flattened: Vec<serde_json::Value> = tools.iter().map(|t| {
let mut obj = serde_json::json!({
"type": t.tool_type,
"name": t.function.name,
});
if let Some(desc) = &t.function.description {
obj["description"] = serde_json::json!(desc);
}
if let Some(params) = &t.function.parameters {
obj["parameters"] = params.clone();
}
obj
}).collect();
body["tools"] = serde_json::json!(flattened);
} }
if let Some(tool_choice) = &request.tool_choice { if let Some(tool_choice) = &request.tool_choice {
body["tool_choice"] = serde_json::json!(tool_choice); match tool_choice {
crate::models::ToolChoice::Mode(mode) => {
body["tool_choice"] = serde_json::json!(mode);
}
crate::models::ToolChoice::Specific(specific) => {
body["tool_choice"] = serde_json::json!({
"type": specific.choice_type,
"name": specific.function.name,
});
}
}
} }
let url = format!("{}/responses", self.config.base_url); let url = format!("{}/responses", self.config.base_url);