fix(gemini): correct sibling positioning and snake_case naming of thought_signature
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

This commit is contained in:
2026-03-05 17:04:36 +00:00
parent f7f6768333
commit 90a3f5d7f8

View File

@@ -57,6 +57,8 @@ struct GeminiPart {
function_response: Option<GeminiFunctionResponse>, function_response: Option<GeminiFunctionResponse>,
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Option::is_none")]
thought: Option<String>, thought: Option<String>,
#[serde(skip_serializing_if = "Option::is_none", rename = "thought_signature")]
thought_signature: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -70,8 +72,6 @@ struct GeminiInlineData {
struct GeminiFunctionCall { struct GeminiFunctionCall {
name: String, name: String,
args: Value, args: Value,
#[serde(skip_serializing_if = "Option::is_none", rename = "thought_signature")]
thought_signature: Option<String>,
} }
#[derive(Debug, Clone, Serialize, Deserialize)] #[derive(Debug, Clone, Serialize, Deserialize)]
@@ -231,6 +231,7 @@ impl GeminiProvider {
function_call: None, function_call: None,
function_response: None, function_response: None,
thought: None, thought: None,
thought_signature: None,
}); });
} }
} }
@@ -270,6 +271,7 @@ impl GeminiProvider {
response: response_value, response: response_value,
}), }),
thought: None, thought: None,
thought_signature: None,
}); });
} else if msg.role == "assistant" { } else if msg.role == "assistant" {
// Assistant messages: handle text, thought (reasoning), and tool_calls // Assistant messages: handle text, thought (reasoning), and tool_calls
@@ -282,6 +284,7 @@ impl GeminiProvider {
function_call: None, function_call: None,
function_response: None, function_response: None,
thought: None, thought: None,
thought_signature: None,
}); });
} }
} }
@@ -296,6 +299,7 @@ impl GeminiProvider {
function_call: None, function_call: None,
function_response: None, function_response: None,
thought: Some(reasoning.clone()), thought: Some(reasoning.clone()),
thought_signature: None,
}); });
} }
} }
@@ -320,10 +324,10 @@ impl GeminiProvider {
function_call: Some(GeminiFunctionCall { function_call: Some(GeminiFunctionCall {
name: tc.function.name.clone(), name: tc.function.name.clone(),
args, args,
thought_signature,
}), }),
function_response: None, function_response: None,
thought: None, thought: None,
thought_signature,
}); });
} }
} }
@@ -339,6 +343,7 @@ impl GeminiProvider {
function_call: None, function_call: None,
function_response: None, function_response: None,
thought: None, thought: None,
thought_signature: None,
}); });
} }
} }
@@ -357,6 +362,7 @@ impl GeminiProvider {
function_call: None, function_call: None,
function_response: None, function_response: None,
thought: None, thought: None,
thought_signature: None,
}); });
} }
} }
@@ -392,6 +398,7 @@ impl GeminiProvider {
function_call: None, function_call: None,
function_response: None, function_response: None,
thought: None, thought: None,
thought_signature: None,
}], }],
}); });
} }
@@ -518,10 +525,11 @@ impl GeminiProvider {
fn extract_tool_calls(parts: &[GeminiPart]) -> Option<Vec<ToolCall>> { fn extract_tool_calls(parts: &[GeminiPart]) -> Option<Vec<ToolCall>> {
let calls: Vec<ToolCall> = parts let calls: Vec<ToolCall> = parts
.iter() .iter()
.filter_map(|p| p.function_call.as_ref()) .filter(|p| p.function_call.is_some())
.map(|fc| { .map(|p| {
// CAPTURE: Use thought_signature from functionCall as the ID if available let fc = p.function_call.as_ref().unwrap();
let id = fc.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple())); // CAPTURE: Use thought_signature from Part as the ID if available
let id = p.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
ToolCall { ToolCall {
id, id,
@@ -541,11 +549,12 @@ impl GeminiProvider {
fn extract_tool_call_deltas(parts: &[GeminiPart]) -> Option<Vec<ToolCallDelta>> { fn extract_tool_call_deltas(parts: &[GeminiPart]) -> Option<Vec<ToolCallDelta>> {
let deltas: Vec<ToolCallDelta> = parts let deltas: Vec<ToolCallDelta> = parts
.iter() .iter()
.filter_map(|p| p.function_call.as_ref())
.enumerate() .enumerate()
.map(|(i, fc)| { .filter(|(_, p)| p.function_call.is_some())
// CAPTURE: Use thought_signature from functionCall as the ID if available .map(|(i, p)| {
let id = fc.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple())); let fc = p.function_call.as_ref().unwrap();
// CAPTURE: Use thought_signature from Part as the ID if available
let id = p.thought_signature.clone().unwrap_or_else(|| format!("call_{}", Uuid::new_v4().simple()));
ToolCallDelta { ToolCallDelta {
index: i as u32, index: i as u32,