Skip to content

Commit 07a76ad

Browse files
authored
Allow missing content in OpenRouter reasoning details (#3674)
1 parent f2bb374 commit 07a76ad

File tree

3 files changed

+118
-3
lines changed

3 files changed

+118
-3
lines changed

pydantic_ai_slim/pydantic_ai/models/openrouter.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -261,21 +261,21 @@ class _ReasoningSummary(_BaseReasoningDetail, frozen=True):
261261
"""Represents a high-level summary of the reasoning process."""
262262

263263
type: Literal['reasoning.summary']
264-
summary: str
264+
summary: str = ''
265265

266266

267267
class _ReasoningEncrypted(_BaseReasoningDetail, frozen=True):
268268
"""Represents encrypted reasoning data."""
269269

270270
type: Literal['reasoning.encrypted']
271-
data: str
271+
data: str = ''
272272

273273

274274
class _ReasoningText(_BaseReasoningDetail, frozen=True):
275275
"""Represents raw text reasoning."""
276276

277277
type: Literal['reasoning.text']
278-
text: str
278+
text: str = ''
279279
signature: str | None = None
280280

281281

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
interactions:
2+
- request:
3+
headers:
4+
accept:
5+
- application/json
6+
accept-encoding:
7+
- gzip, deflate
8+
connection:
9+
- keep-alive
10+
content-length:
11+
- '176'
12+
content-type:
13+
- application/json
14+
host:
15+
- openrouter.ai
16+
method: POST
17+
parsed_body:
18+
messages:
19+
- content: What is 2+2?
20+
role: user
21+
model: anthropic/claude-sonnet-4.5
22+
reasoning:
23+
enabled: true
24+
stream: true
25+
stream_options:
26+
include_usage: true
27+
uri: https://openrouter.ai/api/v1/chat/completions
28+
response:
29+
body:
30+
string: |+
31+
: OPENROUTER PROCESSING
32+
33+
: OPENROUTER PROCESSING
34+
35+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
36+
37+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[{"type":"reasoning.text","text":"","signature":"","format":"anthropic-claude-v1","index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
38+
39+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"This","reasoning_details":[{"type":"reasoning.text","text":"This","format":"anthropic-claude-v1","index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
40+
41+
: OPENROUTER PROCESSING
42+
43+
: OPENROUTER PROCESSING
44+
45+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":" is a simple arithmetic question. ","reasoning_details":[{"type":"reasoning.text","text":" is a simple arithmetic question. ","format":"anthropic-claude-v1","index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
46+
47+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":"2+2 equals 4.","reasoning_details":[{"type":"reasoning.text","text":"2+2 equals 4.","format":"anthropic-claude-v1","index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
48+
49+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[{"type":"reasoning.text","text":"","format":"anthropic-claude-v1","index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
50+
51+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[{"type":"reasoning.text","signature":"Et0BCkgIChACGAIqQA2s7h7tA7IG35fbwVkou9PM2hANVJNUwcEM4q12fTRDK6y3v6YoEvJ+7bko8wnW/GLsQFXadaJPAEMCpLkhI9ISDLjFkeR1aVUIvdCtyBoMrUTovh0jwk+wpnZWIjANV3e6VVdgbGSsEyyTHO6KMmVtqqs79f9blnVdJmmMIwMyTi6bEtG59+jTU7v1zlsqQ2IKGZILOlr6adh0Aam7zYttvisys+wjyZZXU1y/Srz0nmp1cFgVOJe1BLKQI3SSRrjsqQC0uAEUZy0GX0Rq1AXjvIcYAQ==","format":"anthropic-claude-v1","index":0}]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
52+
53+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
54+
55+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
56+
57+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"2 ","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
58+
59+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"+ 2 = 4","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
60+
61+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":null,"native_finish_reason":null,"logprobs":null}]}
62+
63+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":"","reasoning":null,"reasoning_details":[]},"finish_reason":"stop","native_finish_reason":"stop","logprobs":null}]}
64+
65+
data: {"id":"gen-1765226419-AGrwjunAftQIAgweibL8","provider":"Google","model":"anthropic/claude-sonnet-4.5","object":"chat.completion.chunk","created":1765226419,"choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null,"native_finish_reason":null,"logprobs":null}],"usage":{"prompt_tokens":43,"completion_tokens":36,"total_tokens":79,"cost":0.000669,"is_byok":false,"prompt_tokens_details":{"cached_tokens":0,"audio_tokens":0,"video_tokens":0},"cost_details":{"upstream_inference_cost":null,"upstream_inference_prompt_cost":0.000129,"upstream_inference_completions_cost":0.00054},"completion_tokens_details":{"reasoning_tokens":13,"image_tokens":0}}}
66+
67+
data: [DONE]
68+
69+
headers:
70+
access-control-allow-origin:
71+
- '*'
72+
cache-control:
73+
- no-cache
74+
connection:
75+
- keep-alive
76+
content-type:
77+
- text/event-stream
78+
permissions-policy:
79+
- payment=(self "https://checkout.stripe.com" "https://connect-js.stripe.com" "https://js.stripe.com" "https://*.js.stripe.com"
80+
"https://hooks.stripe.com")
81+
referrer-policy:
82+
- no-referrer, strict-origin-when-cross-origin
83+
transfer-encoding:
84+
- chunked
85+
vary:
86+
- Accept-Encoding
87+
status:
88+
code: 200
89+
message: OK
90+
version: 1
91+
...

tests/models/test_openrouter.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,30 @@ class FindEducationContentFilters(BaseModel):
408408
)
409409

410410

411+
async def test_openrouter_streaming_reasoning(allow_model_requests: None, openrouter_api_key: str) -> None:
412+
provider = OpenRouterProvider(api_key=openrouter_api_key)
413+
model = OpenRouterModel('anthropic/claude-sonnet-4.5', provider=provider)
414+
agent = Agent(
415+
model=model,
416+
model_settings=OpenRouterModelSettings(openrouter_reasoning={'enabled': True}),
417+
)
418+
419+
async with agent.run_stream('What is 2+2?') as stream:
420+
_ = await stream.get_output()
421+
422+
assert stream.response.parts == snapshot(
423+
[
424+
ThinkingPart(
425+
content='This is a simple arithmetic question. 2+2 equals 4.',
426+
signature='Et0BCkgIChACGAIqQA2s7h7tA7IG35fbwVkou9PM2hANVJNUwcEM4q12fTRDK6y3v6YoEvJ+7bko8wnW/GLsQFXadaJPAEMCpLkhI9ISDLjFkeR1aVUIvdCtyBoMrUTovh0jwk+wpnZWIjANV3e6VVdgbGSsEyyTHO6KMmVtqqs79f9blnVdJmmMIwMyTi6bEtG59+jTU7v1zlsqQ2IKGZILOlr6adh0Aam7zYttvisys+wjyZZXU1y/Srz0nmp1cFgVOJe1BLKQI3SSRrjsqQC0uAEUZy0GX0Rq1AXjvIcYAQ==',
427+
provider_name='openrouter',
428+
provider_details={'format': 'anthropic-claude-v1', 'index': 0, 'type': 'reasoning.text'},
429+
),
430+
TextPart(content='2 + 2 = 4'),
431+
]
432+
)
433+
434+
411435
async def test_openrouter_google_nested_schema(allow_model_requests: None, openrouter_api_key: str) -> None:
412436
"""Test that nested schemas with $defs/$ref work correctly with OpenRouter + Gemini.
413437

0 commit comments

Comments
 (0)