fix: preserve validation error `input` on tool-call retries
- Closes #5178
Summary
#4947 stripped input from top-level validation errors in RetryPromptPart.model_response() to reduce token bloat for NativeOutput retries (where input duplicates the entire generated JSON across every error, per #4919).
That strip also applied to tool-call retries. For tool calls, the validation error is the model's most direct signal of what arguments it sent — without input, models like Claude Sonnet 4 can't reliably self-correct and repeat the same malformed call until max_retries is exhausted (~0.5% permanent failure rate reported in #5178).
Fix
Scope the strip to tool_name is None (the NativeOutput path). All tool-call retry construction sites (tool_manager.py:181, _output.py:140,202) set tool_name, so input is preserved there.
Credit to @truffle-dev for the analysis and minimal patch in https://github.com/pydantic/pydantic-ai/issues/5178#issuecomment-4306739061.
Tests
- New regression tests in
test_messages.pyfor the tool-call paths (top-level and nested). - Existing
NativeOutput-path tests continue to assert the strip behavior. - Two snapshots in
test_agent.pyupdated to reflectinputnow surfacing in output-tool retries (expected behavior change).
Follow-up (not in this PR)
The NativeOutput strip itself may be over-aggressive — it assumes the model reliably cross-references errors against its own prior text output. Worth revisiting separately (dedupe-per-unique-payload likely cleaner than unconditional strip).
Checklist
- Any AI generated code has been reviewed line-by-line by the human PR author, who stands by it.
- No breaking changes in accordance with the version policy.
- PR title is fit for the release changelog.