mirror of
https://github.com/fawney19/Aether.git
synced 2026-10-03 16:07:46 +08:00
fix(antigravity): send googleSearch instead of the Gemini 1.5 retrieval tool
The transport boundary rewrote `googleSearch` into the Gemini 1.5-era
`googleSearchRetrieval` spelling before every v1internal call, on the stated
grounds that the private backend rejects `googleSearch` when it is combined
with function declarations. That rewrite breaks grounding on Gemini 3.
Observed on stabey-124 against daily-cloudcode-pa.googleapis.com. A controlled
pair, same model and keys, 5 seconds apart:
- no `web_search_options` -> 200
- with `web_search_options` -> 502 on all three candidates
The outgoing body carried `tools: [{"googleSearchRetrieval": {}}]` and no
function declarations at all, so the documented mixed-tool rationale did not
apply. `request_candidates.error_message` holds what the backend actually
said:
Malformed function call: call:google_search{query:current UTC date time}
Malformed function call: call:google:search{query:current UTC date}
Malformed function call: call:google_search{queries:[current UTC date]}
The model reaches for `google_search`, the legacy declaration binds nothing,
and the turn dies unparsed. CLIProxyAPI sends `googleSearch` to this same
v1internal surface, including alongside function declarations.
Keep folding the snake_case `google_search` alias into the canonical
`googleSearch` key, and leave a request that already spells the tool
`googleSearchRetrieval` untouched.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -120,11 +120,18 @@ pub fn build_antigravity_safe_v1internal_request(
|
||||
AntigravityRequestEnvelopeSupport::Supported(envelope)
|
||||
}
|
||||
|
||||
/// Antigravity's private v1internal Gemini surface still uses the legacy
|
||||
/// `googleSearchRetrieval` spelling. The public Gemini converter emits the
|
||||
/// newer `googleSearch` spelling, which the private backend rejects when it is
|
||||
/// combined with function declarations. Normalize only at this transport
|
||||
/// boundary so public Gemini requests retain their native shape.
|
||||
/// Antigravity's private v1internal Gemini surface takes the same
|
||||
/// `googleSearch` grounding tool as the public one. Only the snake_case alias
|
||||
/// needs folding into the canonical camelCase key.
|
||||
///
|
||||
/// This used to rewrite `googleSearch` into the Gemini 1.5-era
|
||||
/// `googleSearchRetrieval` spelling. Gemini 3 rejects that: the model emits a
|
||||
/// `google_search` call the backend cannot bind to any declared tool, and the
|
||||
/// turn dies with `MALFORMED_FUNCTION_CALL`, e.g.
|
||||
/// `Malformed function call: call:google_search{query:current UTC date}`
|
||||
/// observed against `daily-cloudcode-pa.googleapis.com` with
|
||||
/// `tools: [{"googleSearchRetrieval": {}}]` and no function declarations.
|
||||
/// CLIProxyAPI sends `googleSearch` to the same v1internal surface.
|
||||
fn normalize_antigravity_builtin_tool_names(request: &mut Map<String, Value>) {
|
||||
let Some(tools) = request.get_mut("tools").and_then(Value::as_array_mut) else {
|
||||
return;
|
||||
@@ -135,14 +142,9 @@ fn normalize_antigravity_builtin_tool_names(request: &mut Map<String, Value>) {
|
||||
continue;
|
||||
};
|
||||
|
||||
if let Some(payload) = tool_object.remove("googleSearch") {
|
||||
tool_object
|
||||
.entry("googleSearchRetrieval".to_string())
|
||||
.or_insert(payload);
|
||||
}
|
||||
if let Some(payload) = tool_object.remove("google_search") {
|
||||
tool_object
|
||||
.entry("googleSearchRetrieval".to_string())
|
||||
.entry("googleSearch".to_string())
|
||||
.or_insert(payload);
|
||||
}
|
||||
}
|
||||
@@ -222,6 +224,43 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn search_only_request_keeps_the_modern_google_search_spelling() {
|
||||
// Reproduces the live failure: a grounding-only request (no function
|
||||
// declarations) that went out as `googleSearchRetrieval` came back as
|
||||
// `Malformed function call: call:google_search{query:current UTC date}`
|
||||
// from daily-cloudcode-pa.googleapis.com.
|
||||
let request_body = json!({
|
||||
"contents": [
|
||||
{ "role": "user", "parts": [{ "text": "today's UTC date?" }] }
|
||||
],
|
||||
"tools": [{ "googleSearch": {} }]
|
||||
});
|
||||
|
||||
let envelope = match build_antigravity_safe_v1internal_request(
|
||||
&sample_auth(),
|
||||
"request-ant-search-1",
|
||||
"gemini-3.8-flash-high",
|
||||
&request_body,
|
||||
AntigravityEnvelopeRequestType::Agent,
|
||||
) {
|
||||
AntigravityRequestEnvelopeSupport::Supported(envelope) => envelope,
|
||||
AntigravityRequestEnvelopeSupport::Unsupported(reason) => {
|
||||
panic!("search-only envelope should be supported: {reason:?}")
|
||||
}
|
||||
};
|
||||
|
||||
let tools = envelope["request"]["tools"]
|
||||
.as_array()
|
||||
.expect("tools should survive");
|
||||
assert_eq!(tools.len(), 1, "{tools:?}");
|
||||
assert_eq!(tools[0]["googleSearch"], json!({}));
|
||||
assert!(
|
||||
tools[0].get("googleSearchRetrieval").is_none(),
|
||||
"the Gemini 1.5 spelling must not be reintroduced: {tools:?}"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn real_agent_request_preserves_antigravity_agent_fields() {
|
||||
let request_body = json!({
|
||||
@@ -328,12 +367,9 @@ mod tests {
|
||||
.get("include_server_side_tool_invocations")
|
||||
.is_none());
|
||||
assert!(envelope["request"]["tools"][0]
|
||||
.get("googleSearch")
|
||||
.get("googleSearchRetrieval")
|
||||
.is_none());
|
||||
assert_eq!(
|
||||
envelope["request"]["tools"][0]["googleSearchRetrieval"],
|
||||
json!({})
|
||||
);
|
||||
assert_eq!(envelope["request"]["tools"][0]["googleSearch"], json!({}));
|
||||
assert_eq!(
|
||||
envelope["request"]["tools"][1]["functionDeclarations"][0]["name"],
|
||||
"run_command"
|
||||
@@ -471,7 +507,7 @@ mod tests {
|
||||
.get("google_search")
|
||||
.is_none());
|
||||
assert_eq!(
|
||||
envelope["request"]["tools"][0]["googleSearchRetrieval"],
|
||||
envelope["request"]["tools"][0]["googleSearch"],
|
||||
json!({
|
||||
"dynamicRetrievalConfig": {
|
||||
"mode": "MODE_UNSPECIFIED"
|
||||
|
||||
Reference in New Issue
Block a user