Skip to content

Commit fd717e6

Browse files
authored
Raise error when using Anthropic thinking with output tools (#3025)
1 parent a62a221 commit fd717e6

File tree

3 files changed

+102
-0
lines changed

3 files changed

+102
-0
lines changed

pydantic_ai_slim/pydantic_ai/models/anthropic.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,10 @@ async def _messages_create(
265265
else:
266266
if not model_request_parameters.allow_text_output:
267267
tool_choice = {'type': 'any'}
268+
if (thinking := model_settings.get('anthropic_thinking')) and thinking.get('type') == 'enabled':
269+
raise UserError(
270+
'Anthropic does not support thinking and output tools at the same time. Use `output_type=PromptedOutput(...)` instead.'
271+
)
268272
else:
269273
tool_choice = {'type': 'auto'}
270274

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
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+
- '471'
12+
content-type:
13+
- application/json
14+
host:
15+
- api.anthropic.com
16+
method: POST
17+
parsed_body:
18+
max_tokens: 4096
19+
messages:
20+
- content:
21+
- text: What is 3 + 3?
22+
type: text
23+
role: user
24+
model: claude-sonnet-4-0
25+
stream: false
26+
system: |-
27+
Always respond with a JSON object that's compatible with this schema:
28+
29+
{"properties": {"response": {"type": "integer"}}, "required": ["response"], "type": "object", "title": "int"}
30+
31+
Don't include any text or Markdown fencing before or after.
32+
thinking:
33+
budget_tokens: 3000
34+
type: enabled
35+
uri: https://api.anthropic.com/v1/messages?beta=true
36+
response:
37+
headers:
38+
connection:
39+
- keep-alive
40+
content-length:
41+
- '1032'
42+
content-type:
43+
- application/json
44+
strict-transport-security:
45+
- max-age=31536000; includeSubDomains; preload
46+
transfer-encoding:
47+
- chunked
48+
parsed_body:
49+
content:
50+
- signature: ErQCCkYICBgCKkDId3yuTWB+RmnrHX1N/m+Q+uvt6TTyU6tRWGzFYK1UmQo+lkK5PFjgRvLK6eXA/q8sbVIC6mO3/1eq5aTkSX7+EgzYnRzfZdWJZ1X+410aDC5zyOhlAbOmBiBUmiIwPC3/mI3lVg3woo5Q2jwuZ/u+Pl8LMzrFxG0YbK2F5YDVuCjhrJsOq5e1V36GWJjqKpsBsKiPfPZQ6wizN25g64pwJb+Wjm55hDeGpK8xJeVFuren6PNKKkruBtlK1PIVpjSXBGkdTJCC69xlhwaXF20zah/A8HDm/2QEqid8Gz8+7zu+b7OGa22WdW0uZEwQgJtydTscZFqWzyAm8CZtsCh8STbRNPggOaCNg9vX5ipu2D+jXnAaL6MIOOQ3FUO+CdljS0mvfoyeCabS8TUYAQ==
51+
thinking: The user is asking for 3 + 3, which equals 6. I need to respond with a JSON object that has a "response"
52+
field containing an integer value.
53+
type: thinking
54+
- text: '{"response": 6}'
55+
type: text
56+
id: msg_01Fo4JKsQzJMTQBgLSAeCJDG
57+
model: claude-sonnet-4-20250514
58+
role: assistant
59+
stop_reason: end_turn
60+
stop_sequence: null
61+
type: message
62+
usage:
63+
cache_creation:
64+
ephemeral_1h_input_tokens: 0
65+
ephemeral_5m_input_tokens: 0
66+
cache_creation_input_tokens: 0
67+
cache_read_input_tokens: 0
68+
input_tokens: 105
69+
output_tokens: 55
70+
service_tier: standard
71+
status:
72+
code: 200
73+
message: OK
74+
version: 1

tests/models/test_anthropic.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import json
44
import os
5+
import re
56
from collections.abc import Callable, Sequence
67
from dataclasses import dataclass, field
78
from datetime import timezone
@@ -4182,6 +4183,29 @@ class CityLocation(BaseModel):
41824183
await agent.run('What is the largest city in the user country?')
41834184

41844185

4186+
async def test_anthropic_output_tool_with_thinking(allow_model_requests: None, anthropic_api_key: str):
4187+
m = AnthropicModel(
4188+
'claude-sonnet-4-0',
4189+
provider=AnthropicProvider(api_key=anthropic_api_key),
4190+
settings=AnthropicModelSettings(anthropic_thinking={'type': 'enabled', 'budget_tokens': 3000}),
4191+
)
4192+
4193+
agent = Agent(m, output_type=int)
4194+
4195+
with pytest.raises(
4196+
UserError,
4197+
match=re.escape(
4198+
'Anthropic does not support thinking and output tools at the same time. Use `output_type=PromptedOutput(...)` instead.'
4199+
),
4200+
):
4201+
await agent.run('What is 3 + 3?')
4202+
4203+
agent = Agent(m, output_type=PromptedOutput(int))
4204+
4205+
result = await agent.run('What is 3 + 3?')
4206+
assert result.output == snapshot(6)
4207+
4208+
41854209
async def test_anthropic_tool_with_thinking(allow_model_requests: None, anthropic_api_key: str):
41864210
"""When using thinking with tool calls in Anthropic, we need to send the thinking part back to the provider.
41874211

0 commit comments

Comments
 (0)