fix(gemini): override finish_reason to 'tool_calls' when tools are present
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

Gemini often reports 'STOP' even when tool calls are generated. To remain
OpenAI-compatible and ensure clients execute tools and continue, we must
report 'tool_calls' as the finish_reason when tools are present.
This commit is contained in:
2026-03-05 17:45:55 +00:00
parent febfcafed4
commit 5c5f836eca

View File

@@ -927,12 +927,18 @@ impl super::Provider for GeminiProvider {
let tool_calls = if deltas.is_empty() { None } else { Some(deltas) }; let tool_calls = if deltas.is_empty() { None } else { Some(deltas) };
// Determine finish_reason // Determine finish_reason
let finish_reason = candidate.finish_reason.as_ref().map(|fr| { // STRATEGY: If we have tool calls, the finish_reason MUST be "tool_calls"
match fr.as_str() { // to comply with OpenAI-style expectations and ensure the client continues.
"STOP" => "stop".to_string(), let finish_reason = if tool_calls.is_some() {
_ => fr.to_lowercase(), Some("tool_calls".to_string())
} } else {
}); candidate.finish_reason.as_ref().map(|fr| {
match fr.as_str() {
"STOP" => "stop".to_string(),
_ => fr.to_lowercase(),
}
})
};
// Avoid emitting completely empty chunks unless they carry usage. // Avoid emitting completely empty chunks unless they carry usage.
if !content.is_empty() || reasoning_content.is_some() || tool_calls.is_some() || stream_usage.is_some() { if !content.is_empty() || reasoning_content.is_some() || tool_calls.is_some() || stream_usage.is_some() {