language_models: Treat a `block_reason` from Gemini as a refusal (#38670)

Marshall Bowers created

This PR updates the Gemini provider to treat a
`prompt_feedback.block_reason` as a refusal, as Gemini does not seem to
return a `stop_reason` to use in this case.

<img width="639" height="162" alt="Screenshot 2025-09-22 at 4 23 15 PM"
src="https://github.com/user-attachments/assets/7a86d67e-06c1-49ea-b58f-fa80666f0f8c"
/>

Previously this would just result in no feedback to the user.

Release Notes:

- Added an error message when a Gemini response contains a
`block_reason`.

Change summary

crates/language_models/src/provider/google.rs | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)

Detailed changes

crates/language_models/src/provider/google.rs 🔗

@@ -637,6 +637,24 @@ impl GoogleEventMapper {
                 convert_usage(&self.usage),
             )))
         }
+
+        if let Some(prompt_feedback) = event.prompt_feedback
+            && let Some(block_reason) = prompt_feedback.block_reason.as_deref()
+        {
+            self.stop_reason = match block_reason {
+                "SAFETY" | "OTHER" | "BLOCKLIST" | "PROHIBITED_CONTENT" | "IMAGE_SAFETY" => {
+                    StopReason::Refusal
+                }
+                _ => {
+                    log::error!("Unexpected Google block_reason: {block_reason}");
+                    StopReason::Refusal
+                }
+            };
+            events.push(Ok(LanguageModelCompletionEvent::Stop(self.stop_reason)));
+
+            return events;
+        }
+
         if let Some(candidates) = event.candidates {
             for candidate in candidates {
                 if let Some(finish_reason) = candidate.finish_reason.as_deref() {