Skip to content

Conversation

@barp
Copy link
Contributor

@barp barp commented Nov 27, 2025

This only happens if you have a tool with all optional parameters.

for example the following response can return from open router:

{'id': 'gen-1764223032-90is29WrhzbOG2XawxiT', 'choices': [{'finish_reason': 'tool_calls', 'index': 0, 'logprobs': None, 'messag
e': {'content': '', 'refusal': None, 'role': 'assistant', 'annotations': None, 'audio': None, 'function_call': None, 'tool_call
s': [{'id': 'toolu_vrtx_0142STg84ZeUdDEVtucWMjys', 'function': {'arguments': None, 'name': 'find_education_content'}, 'type': '
function', 'index': 0}], 'reasoning': None}, 'native_finish_reason': 'tool_calls'}], 'created': 1764223033, 'model': 'anthropic
/claude-sonnet-4.5', 'object': 'chat.completion', 'service_tier': None, 'system_fingerprint': None, 'usage': {'completion_token
s': 23, 'prompt_tokens': 8146, 'total_tokens': 8169, 'completion_tokens_details': None, 'prompt_tokens_details': None}, 'provid
er': 'Google'}

as you can see the function arguments can be None.

The following code reproduces the issue:

from pydantic import BaseModel
from pydantic_ai import RunContext, Agent
from pydantic_ai.models.openrouter import OpenRouterModel

model = OpenRouterModel(
    'anthropic/claude-sonnet-4.5',
)

agent = Agent[None, str](
    model=model,
    output_type=str,
    instrument=True,
    retries=5,
)

class FindEducationContentFilters(BaseModel):
    title: str | None = None

@agent.tool
async def find_education_content(
    ctx: RunContext[None], filters: FindEducationContentFilters
) -> str:
    return "This is a content about education"

print(agent.run_sync("Can you find me education content?"))

@barp barp changed the title fix: Fix a case where a tool can have parameter with all elements being optional fix: Fix a case where a tool can have parameter with all elements being optional OpenRouterModel Nov 27, 2025
@barp barp changed the title fix: Fix a case where a tool can have parameter with all elements being optional OpenRouterModel fix: Fix a crash that happens when a tool have parameter with all elements being optional OpenRouterModel Nov 27, 2025
@barp barp changed the title fix: Fix a crash that happens when a tool have parameter with all elements being optional OpenRouterModel fix: crash that happens when a tool have parameter with all elements being optional OpenRouterModel Nov 27, 2025
@DouweM
Copy link
Collaborator

DouweM commented Nov 27, 2025

Thanks for the report. For context, the error looks like this:

  File "/home/DouweM/pydantic-ai/pydantic_ai_slim/pydantic_ai/models/openai.py", line 598, in _process_response
    raise UnexpectedModelBehavior(f'Invalid response from {self.system} chat completions endpoint: {e}') from e
pydantic_ai.exceptions.UnexpectedModelBehavior: Invalid response from openrouter chat completions endpoint: 3 validation errors for _OpenRouterChatCompletion
choices.0.message.tool_calls.0.ChatCompletionMessageFunctionToolCall.function.arguments
  Input should be a valid string [type=string_type, input_value=None, input_type=NoneType]
    For further information visit https://errors.pydantic.dev/2.11/v/string_type

@DouweM DouweM changed the title fix: crash that happens when a tool have parameter with all elements being optional OpenRouterModel Fix error when OpenRouter API returns None tool call arguments Nov 27, 2025
@DouweM DouweM self-assigned this Nov 27, 2025
Copy link
Collaborator

@DouweM DouweM left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@barp Thanks for working on this! In addition to my comments, can you please make sure we have a test for this?

@barp
Copy link
Contributor Author

barp commented Nov 27, 2025

@barp Thanks for working on this! In addition to my comments, can you please make sure we have a test for this?

Can you point me to where the test should be added?

Edit: NVM I think I got it.

@barp barp requested a review from DouweM November 27, 2025 23:12
@barp barp requested a review from DouweM November 28, 2025 22:25
@barp
Copy link
Contributor Author

barp commented Nov 28, 2025

The failure seems unrelated to my change and the CI should be re-run

@DouweM DouweM enabled auto-merge (squash) November 28, 2025 23:03
@DouweM DouweM disabled auto-merge November 28, 2025 23:11
@DouweM DouweM merged commit 1a35af5 into pydantic:main Nov 28, 2025
54 of 58 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants