Skip to content

Commit 4ec19d6

Browse files
committed
Add exception for tool output exceeding token limit
1 parent 78fb707 commit 4ec19d6

File tree

4 files changed

+29
-0
lines changed

4 files changed

+29
-0
lines changed

pydantic_ai_slim/pydantic_ai/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
FallbackExceptionGroup,
2525
ModelHTTPError,
2626
ModelRetry,
27+
ToolExceedsTokenLimitError,
2728
UnexpectedModelBehavior,
2829
UsageLimitExceeded,
2930
UserError,
@@ -124,6 +125,7 @@
124125
'ModelRetry',
125126
'ModelHTTPError',
126127
'FallbackExceptionGroup',
128+
'ToolExceedsTokenLimitError',
127129
'UnexpectedModelBehavior',
128130
'UsageLimitExceeded',
129131
'UserError',

pydantic_ai_slim/pydantic_ai/_agent_graph.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -576,6 +576,15 @@ async def _run_stream() -> AsyncIterator[_messages.HandleResponseEvent]: # noqa
576576
tool_calls: list[_messages.ToolCallPart] = []
577577
files: list[_messages.BinaryContent] = []
578578

579+
# If the model stopped due to token limit (length) and the last part is a tool call,
580+
# the args are incomplete.
581+
if self.model_response.finish_reason == 'length':
582+
last_part = self.model_response.parts[-1]
583+
if isinstance(last_part, _messages.ToolCallPart):
584+
raise exceptions.ToolExceedsTokenLimitError(
585+
'Model token limit exceeded while emitting a tool call.'
586+
)
587+
579588
for part in self.model_response.parts:
580589
if isinstance(part, _messages.TextPart):
581590
text += part.content

pydantic_ai_slim/pydantic_ai/exceptions.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
'UnexpectedModelBehavior',
2424
'UsageLimitExceeded',
2525
'ModelHTTPError',
26+
'ToolExceedsTokenLimitError',
2627
'FallbackExceptionGroup',
2728
)
2829

@@ -168,3 +169,7 @@ class ToolRetryError(Exception):
168169
def __init__(self, tool_retry: RetryPromptPart):
169170
self.tool_retry = tool_retry
170171
super().__init__()
172+
173+
174+
class ToolExceedsTokenLimitError(AgentRunError):
175+
"""Error raised when a model stops due to token limit while emitting a tool call."""

tests/test_agent.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
SystemPromptPart,
4141
TextPart,
4242
ToolCallPart,
43+
ToolExceedsTokenLimitError,
4344
ToolReturn,
4445
ToolReturnPart,
4546
UnexpectedModelBehavior,
@@ -2448,6 +2449,18 @@ def empty(m: list[ModelMessage], _info: AgentInfo) -> ModelResponse:
24482449
)
24492450

24502451

2452+
def test_tool_exceeds_token_limit_error():
2453+
def return_incomplete_tool(_: list[ModelMessage], info: AgentInfo) -> ModelResponse:
2454+
resp = ModelResponse(parts=[ToolCallPart('dummy_tool', args='{"foo": "bar",')])
2455+
resp.finish_reason = 'length'
2456+
return resp
2457+
2458+
agent = Agent(FunctionModel(return_incomplete_tool), output_type=str)
2459+
2460+
with pytest.raises(ToolExceedsTokenLimitError, match='Model token limit exceeded while emitting a tool call.'):
2461+
agent.run_sync('Hello')
2462+
2463+
24512464
def test_model_requests_blocked(env: TestEnv):
24522465
try:
24532466
env.set('GEMINI_API_KEY', 'foobar')

0 commit comments

Comments
 (0)