Skip to content

Fix bug with google model safety handling #2066

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 11 additions & 6 deletions pydantic_ai_slim/pydantic_ai/models/google.py
Original file line number Diff line number Diff line change
Expand Up @@ -304,17 +304,18 @@ async def _generate_content(
def _process_response(self, response: GenerateContentResponse) -> ModelResponse:
if not response.candidates or len(response.candidates) != 1:
raise UnexpectedModelBehavior('Expected exactly one candidate in Gemini response') # pragma: no cover
if response.candidates[0].content is None or response.candidates[0].content.parts is None:
if response.candidates[0].finish_reason == 'SAFETY':
candidate = response.candidates[0]
if candidate.content is None or candidate.content.parts is None:
if candidate.finish_reason == 'SAFETY':
raise UnexpectedModelBehavior('Safety settings triggered', str(response))
else:
raise UnexpectedModelBehavior(
'Content field missing from Gemini response', str(response)
) # pragma: no cover
parts = response.candidates[0].content.parts or []
parts = candidate.content.parts or []
vendor_id = response.response_id or None
vendor_details: dict[str, Any] | None = None
finish_reason = response.candidates[0].finish_reason
finish_reason = candidate.finish_reason
if finish_reason: # pragma: no branch
vendor_details = {'finish_reason': finish_reason.value}
usage = _metadata_as_usage(response)
Expand Down Expand Up @@ -437,8 +438,12 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]:

assert chunk.candidates is not None
candidate = chunk.candidates[0]
if candidate.content is None:
raise UnexpectedModelBehavior('Streamed response has no content field') # pragma: no cover
if candidate.content is None or candidate.content.parts is None:
if candidate.finish_reason == 'SAFETY': # pragma: no cover
raise UnexpectedModelBehavior('Safety settings triggered', str(chunk))
else:
raise UnexpectedModelBehavior('Content field missing from streaming Gemini response', str(chunk))

assert candidate.content.parts is not None
for part in candidate.content.parts:
if part.text is not None:
Expand Down
Loading