mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-08 20:20:19 +08:00
fix(gemini): normalize mixed tools for same-format providers
This commit is contained in:
@@ -218,6 +218,18 @@ fn enable_server_side_tool_invocations_for_mixed_tools(
|
||||
if !gemini_model_supports_mixed_tools(mapped_model) {
|
||||
return None;
|
||||
}
|
||||
ensure_server_side_tool_invocations_for_mixed_tools(output)
|
||||
}
|
||||
|
||||
pub fn ensure_server_side_tool_invocations_for_mixed_tools(output: &mut Value) -> Option<()> {
|
||||
let output_object = output.as_object_mut()?;
|
||||
let tools = output_object.get("tools").and_then(Value::as_array);
|
||||
let Some(tools) = tools else {
|
||||
return Some(());
|
||||
};
|
||||
if !gemini_tools_are_mixed(tools) {
|
||||
return Some(());
|
||||
}
|
||||
|
||||
let tool_config = output_object
|
||||
.entry("toolConfig".to_string())
|
||||
|
||||
@@ -12,6 +12,7 @@ pub use formats::context::{
|
||||
ConversionFieldRecord, ConversionFieldStatus, ConversionReport, Converted, FormatContext,
|
||||
FormatError,
|
||||
};
|
||||
pub use formats::gemini::generate_content::request::ensure_server_side_tool_invocations_for_mixed_tools;
|
||||
pub use formats::id::{
|
||||
api_format_alias_matches, api_format_defaults_to_client_error_failover,
|
||||
api_format_defaults_to_non_stream, api_format_permission_covers,
|
||||
|
||||
@@ -413,6 +413,27 @@ fn build_same_format_provider_request_body_inner(
|
||||
"applied configured provider body rules",
|
||||
);
|
||||
}
|
||||
if matches!(input.family, SameFormatProviderFamily::Gemini)
|
||||
&& aether_ai_formats::api_format_alias_matches(
|
||||
input.provider_api_format,
|
||||
"gemini:generate_content",
|
||||
)
|
||||
{
|
||||
let before_mixed_tool_compatibility = compatibility_edits
|
||||
.is_some()
|
||||
.then(|| provider_request_body.clone());
|
||||
aether_ai_formats::ensure_server_side_tool_invocations_for_mixed_tools(
|
||||
&mut provider_request_body,
|
||||
)?;
|
||||
if before_mixed_tool_compatibility.is_some_and(|before| before != provider_request_body) {
|
||||
record_compatibility_edit(
|
||||
&mut compatibility_edits,
|
||||
"toolConfig.includeServerSideToolInvocations",
|
||||
SameFormatProviderCompatibilityEditAction::ProviderCompatibilityRewrite,
|
||||
"enabled Gemini server-side tool invocations for mixed built-in and function tools",
|
||||
);
|
||||
}
|
||||
}
|
||||
if matches!(input.family, SameFormatProviderFamily::Gemini)
|
||||
&& aether_ai_formats::api_format_alias_matches(
|
||||
input.provider_api_format,
|
||||
@@ -2057,6 +2078,60 @@ mod tests {
|
||||
assert_eq!(function_response["name"], "lookup_snake");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_format_gemini_body_enables_mixed_tool_invocations() {
|
||||
let output = build_same_format_provider_request_body_with_compatibility_report(
|
||||
SameFormatProviderRequestBodyInput {
|
||||
body_json: &json!({
|
||||
"contents": [{
|
||||
"role": "user",
|
||||
"parts": [{"text": "Search, then save the result."}]
|
||||
}],
|
||||
"tools": [
|
||||
{"googleSearch": {}},
|
||||
{
|
||||
"functionDeclarations": [{
|
||||
"name": "save_result",
|
||||
"parameters": {"type": "object"}
|
||||
}]
|
||||
}
|
||||
],
|
||||
"toolConfig": {
|
||||
"functionCallingConfig": {"mode": "AUTO"}
|
||||
}
|
||||
}),
|
||||
mapped_model: "gemini-3.7-flash",
|
||||
client_api_format: "gemini:generate_content",
|
||||
provider_api_format: "gemini:generate_content",
|
||||
source_model: Some("gemini-3.7-flash"),
|
||||
family: SameFormatProviderFamily::Gemini,
|
||||
body_rules: None,
|
||||
request_headers: None,
|
||||
upstream_is_stream: true,
|
||||
force_body_stream_field: false,
|
||||
kiro_auth_config: None,
|
||||
is_claude_code: false,
|
||||
enable_model_directives: false,
|
||||
},
|
||||
)
|
||||
.expect("same-format Gemini body should build");
|
||||
|
||||
assert_eq!(output.body["tools"][0]["googleSearch"], json!({}));
|
||||
assert_eq!(
|
||||
output.body["tools"][1]["functionDeclarations"][0]["name"],
|
||||
"save_result"
|
||||
);
|
||||
assert_eq!(
|
||||
output.body["toolConfig"]["includeServerSideToolInvocations"],
|
||||
true
|
||||
);
|
||||
assert!(output.compatibility_edits.iter().any(|edit| {
|
||||
edit.field == "toolConfig.includeServerSideToolInvocations"
|
||||
&& edit.action
|
||||
== SameFormatProviderCompatibilityEditAction::ProviderCompatibilityRewrite
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn same_format_body_report_records_provider_compatibility_edits() {
|
||||
let output = build_same_format_provider_request_body_with_compatibility_report(
|
||||
|
||||
Reference in New Issue
Block a user