fix(agent): close unclosed JSON delimiters in LIFO order when repairing truncated tool_call arguments - #42510
Conversation
…ng truncated tool_call arguments
When _repair_tool_call_arguments closed unclosed structures it appended all missing '}' then all missing ']', a fixed order that is wrong for nested payloads: '{"items": [1, 2' became '{"items": [1, 2}]' (invalid) instead of '{"items": [1, 2]}'. Every later repair pass then failed and the whole argument payload was dropped to '{}', so a truncated tool call ran with empty arguments.
Walk the text tracking string state and close open delimiters in LIFO order so nested truncations recover correctly; braces/brackets inside string values are ignored.
Strengthen the previously-misleading test_unclosed_bracket_and_brace into a real value assertion and add regression tests for nested arrays/objects, the flat-object case, and a brace-inside-string case.
|
Positive verification — LIFO JSON delimiter repair is correct and well-tested. Reviewed the full diff ( The replacement of the naive count-and-append approach (
Test coverage is thorough: unclosed bracket+brace, array of strings, nested write_file args, object inside array, flat object, and brace-in-string-value. All 6 new test cases exercise distinct edge paths. No issues found. |
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Correctness
- Critical bug fix: the old count-based approach closed delimiters in wrong order (
}then]), which would corrupt nested JSON like{"k": [1, 2-> invalid{"k": [1, 2]}. - The new LIFO stack-based approach correctly closes in reverse order of opening.
- Properly handles string literals (ignores braces/brackets inside quoted strings).
Code Quality
- Clean implementation using a stack with proper string/escape state tracking.
- Comments clearly explain the edge case being addressed.
Testing
- Excellent test coverage with 6 new test cases covering:
- Unclosed bracket and brace (the original bug)
- Unclosed array of strings
- Unclosed nested write_file args
- Object inside array closes LIFO
- Flat object regression guard
- Brace inside string value not treated as delimiter
Looks Good
- Important bug fix with comprehensive test coverage. The fix is minimal and focused.
Reviewed by Hermes Agent
|
Thanks for the focused investigation and regression coverage. The nested-delimiter case is real in the existing legacy repair path, but this PR takes a repair direction we do not accept.
Closed as not-planned per standing maintainer policy ( |
What does this PR do?
_repair_tool_call_argumentssalvages malformed tool-call JSON fromlocal/quantized models. When closing unclosed structures it appended all
missing
}first, then all missing]— a fixed order that is wrong fornested payloads.
{"items": [1, 2became{"items": [1, 2}](invalid)instead of
{"items": [1, 2]}, every later repair pass then failed, and thewhole argument payload was silently dropped to
{}. The tool then ran withempty arguments.
The fix walks the text tracking string state (so braces/brackets inside
string values are ignored) and closes open delimiters in LIFO nesting order,
so nested truncations recover correctly. The flat-object case keeps working.
Related Issue
N/A
Type of Change
Changes Made
agent/message_sanitization.py— replace the count-and-append delimiterclose in
_repair_tool_call_argumentswith a string-aware, stack-basedLIFO close. Trailing-comma strip and the excess-closer pass are unchanged.
tests/run_agent/test_repair_tool_call_arguments.py— turn the misleadingtest_unclosed_bracket_and_brace(asserted only "valid JSON", so it passedon the dropped
{}) into a real value assertion, plus 5 regression tests.How to Test
Results:
test_repair_tool_call_arguments.py— 26 passedtest_streaming_tool_call_repair.py(uses the same repair path) — 12 passedBefore the fix,
{"items": [1, 2→{}(args lost); after, it recovers to{"items": [1, 2]}.Checklist