Skip to content

fix: preserve validation error input on tool-call retries#5181

Merged
DouweM merged 1 commit intomainfrom
fix/retry-keep-input-for-tool-calls
Apr 23, 2026
Merged

fix: preserve validation error input on tool-call retries#5181
DouweM merged 1 commit intomainfrom
fix/retry-keep-input-for-tool-calls

Conversation

@DouweM
Copy link
Copy Markdown
Collaborator

@DouweM DouweM commented Apr 23, 2026

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 #5178 (comment).

Tests

  • New regression tests in test_messages.py for the tool-call paths (top-level and nested).
  • Existing NativeOutput-path tests continue to assert the strip behavior.
  • Two snapshots in test_agent.py updated to reflect input now 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.

Closes #5178

#4947 stripped `input` from top-level validation errors to avoid
duplicating the full generated JSON in NativeOutput retry messages.
That strip also applied to tool-call retries, where the validation
error is the model's only 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.

Scope the strip to `tool_name is None` (the NativeOutput path).
Tool-call retries (`tool_manager.py`, output-tool/output-validator
wrappers in `_output.py`) all set `tool_name` and keep `input`.
@github-actions github-actions Bot added size: S Small PR (≤100 weighted lines) bug Report that something isn't working, or PR implementing a fix and removed auto-review labels Apr 23, 2026
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 2 additional findings.

Open in Devin Review

@github-actions
Copy link
Copy Markdown
Contributor

@DouweM DouweM merged commit 84c8548 into main Apr 23, 2026
56 checks passed
@DouweM DouweM deleted the fix/retry-keep-input-for-tool-calls branch April 23, 2026 20:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Report that something isn't working, or PR implementing a fix size: S Small PR (≤100 weighted lines)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Tool call retries lose self-correction ability after #4947 strips input from validation errors

1 participant