Skip to content

Commit f4a6f0e

Browse files
Fix error when streaming from Gemini includes only executable_code or code_execution_result (#2719)
1 parent a7ae3c1 commit f4a6f0e

File tree

3 files changed

+90
-0
lines changed

3 files changed

+90
-0
lines changed

pydantic_ai_slim/pydantic_ai/models/google.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,10 @@ async def _get_event_iterator(self) -> AsyncIterator[ModelResponseStreamEvent]:
559559
)
560560
if maybe_event is not None: # pragma: no branch
561561
yield maybe_event
562+
elif part.executable_code is not None:
563+
pass
564+
elif part.code_execution_result is not None:
565+
pass
562566
else:
563567
assert part.function_response is not None, f'Unexpected part: {part}' # pragma: no cover
564568

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
interactions:
2+
- request:
3+
headers:
4+
accept:
5+
- '*/*'
6+
accept-encoding:
7+
- gzip, deflate
8+
connection:
9+
- keep-alive
10+
content-length:
11+
- '287'
12+
content-type:
13+
- application/json
14+
host:
15+
- generativelanguage.googleapis.com
16+
method: POST
17+
parsed_body:
18+
contents:
19+
- parts:
20+
- text: what is 65465-6544 * 65464-6+1.02255
21+
role: user
22+
generationConfig: {}
23+
systemInstruction:
24+
parts:
25+
- text: Be concise and always use Python to do calculations no matter how small.
26+
role: user
27+
tools:
28+
- codeExecution: {}
29+
uri: https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:streamGenerateContent?alt=sse
30+
response:
31+
body:
32+
string: "data: {\"candidates\": [{\"content\": {\"parts\": [{\"executableCode\": {\"language\": \"PYTHON\",\"code\":
33+
\"result = 65465 - 6544 * 65464 - 6 + 1.02255\\nprint(result)\\n\"}}],\"role\": \"model\"}}],\"usageMetadata\": {\"promptTokenCount\":
34+
46,\"totalTokenCount\": 46,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 46}]},\"modelVersion\":
35+
\"gemini-2.0-flash\",\"responseId\": \"_oizaOUTzpCEwg_H-YnYAg\"}\r\n\r\ndata: {\"candidates\": [{\"content\": {\"parts\":
36+
[{\"codeExecutionResult\": {\"outcome\": \"OUTCOME_OK\",\"output\": \"-428330955.97745\\n\"}}],\"role\": \"model\"}}],\"usageMetadata\":
37+
{\"promptTokenCount\": 46,\"totalTokenCount\": 46,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\":
38+
46}]},\"modelVersion\": \"gemini-2.0-flash\",\"responseId\": \"_oizaOUTzpCEwg_H-YnYAg\"}\r\n\r\ndata: {\"candidates\":
39+
[{\"content\": {\"parts\": [{\"text\": \"The\"}],\"role\": \"model\"}}],\"usageMetadata\": {\"promptTokenCount\":
40+
46,\"totalTokenCount\": 46,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 46}]},\"modelVersion\":
41+
\"gemini-2.0-flash\",\"responseId\": \"_oizaOUTzpCEwg_H-YnYAg\"}\r\n\r\ndata: {\"candidates\": [{\"content\": {\"parts\":
42+
[{\"text\": \" answer is -428330955.9774\"}],\"role\": \"model\"}}],\"usageMetadata\": {\"promptTokenCount\": 46,\"totalTokenCount\":
43+
46,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 46}]},\"modelVersion\": \"gemini-2.0-flash\",\"responseId\":
44+
\"_oizaOUTzpCEwg_H-YnYAg\"}\r\n\r\ndata: {\"candidates\": [{\"content\": {\"parts\": [{\"text\": \"5.\\n\"}],\"role\":
45+
\"model\"},\"finishReason\": \"STOP\"}],\"usageMetadata\": {\"promptTokenCount\": 44,\"candidatesTokenCount\": 77,\"totalTokenCount\":
46+
221,\"promptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\": 44}],\"candidatesTokensDetails\": [{\"modality\":
47+
\"TEXT\",\"tokenCount\": 77}],\"toolUsePromptTokenCount\": 100,\"toolUsePromptTokensDetails\": [{\"modality\": \"TEXT\",\"tokenCount\":
48+
100}]},\"modelVersion\": \"gemini-2.0-flash\",\"responseId\": \"_oizaOUTzpCEwg_H-YnYAg\"}\r\n\r\n"
49+
headers:
50+
alt-svc:
51+
- h3=":443"; ma=2592000,h3-29=":443"; ma=2592000
52+
content-disposition:
53+
- attachment
54+
content-type:
55+
- text/event-stream
56+
server-timing:
57+
- gfet4t7; dur=5315
58+
transfer-encoding:
59+
- chunked
60+
vary:
61+
- Origin
62+
- X-Origin
63+
- Referer
64+
status:
65+
code: 200
66+
message: OK
67+
version: 1

tests/models/test_google.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,25 @@ async def test_google_model_stream(allow_model_requests: None, google_provider:
230230
assert data == snapshot('The capital of France is Paris.\n')
231231

232232

233+
async def test_google_model_builtin_code_execution_stream(
234+
allow_model_requests: None,
235+
google_provider: GoogleProvider,
236+
):
237+
"""Test Gemini streaming only code execution result or executable_code."""
238+
model = GoogleModel('gemini-2.0-flash', provider=google_provider)
239+
agent = Agent(
240+
model=model,
241+
system_prompt='Be concise and always use Python to do calculations no matter how small.',
242+
builtin_tools=[CodeExecutionTool()],
243+
)
244+
event_parts: list[str] = []
245+
async with agent.run_stream(user_prompt='what is 65465-6544 * 65464-6+1.02255') as result:
246+
async for chunk in result.stream_text():
247+
event_parts.append(chunk)
248+
249+
assert event_parts == snapshot(['The answer is -428330955.97745.\n'])
250+
251+
233252
async def test_google_model_retry(allow_model_requests: None, google_provider: GoogleProvider):
234253
model = GoogleModel('gemini-2.5-pro-preview-03-25', provider=google_provider)
235254
agent = Agent(

0 commit comments

Comments
 (0)