Repository navigation
Conversation
Co-authored-by: chatgpt-codex-connector[bot] <199175422+chatgpt-codex-connector[bot]@users.noreply.github.com>
VectorPeak
temporarily deployed
to
maintainer-approved
July 7, 2026 13:02 — with
GitHub Actions
Inactive
VectorPeak
had a problem deploying
to
ai-review-approved
July 7, 2026 13:02 — with
GitHub Actions
Failure
|
Hi @VectorPeak, this is your 3rd Pull Request. 🙌 Join Developer CommunityThanks so much for your contribution! We'd love to invite you to join the official QwenPaw developer group! You can find the Discord and DingTalk group links under the "Developer Community" section on our docs page: We truly appreciate your enthusiasm—and look forward to your future contributions! 😊 We'll review your PR soon. |
This was referenced Jul 9, 2026
This branch had an error being deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Description
Recover tool-call JSON arguments when stored
inputorraw_inputstarts with JSON whitespace and then contains a valid JSON object followed by trailing garbage.What Problem This Solves
tool_message_utilsalready has two fallback paths for malformed-but-recoverable tool-call arguments:_repair_empty_tool_inputs()repairs an emptyinputfield fromraw_input_coerce_tool_inputs_to_json()recovers a leading JSON object before dropping malformed trailing bytesBoth paths first try strict
json.loads(). That is the right first step for clean JSON, but it rejects inputs with extra trailing bytes. When that happens, the code falls back toJSONDecoder.raw_decode(...)so it can recover the first valid JSON object.The missing edge case is leading JSON whitespace.
json.loads()accepts leading whitespace, butraw_decode(...)starts parsing at the index it is given. Before this PR, both fallback paths passed index0, so an otherwise recoverable payload like this was not recovered:In practice, that means a recoverable tool-call argument can be left empty or dropped before the next provider request. For users, the visible effect is a tool call that should still have arguments, but is normalized as if the arguments were missing or unrecoverable.
Why This Change Was Made
This mirrors the JSON recovery boundary that was accepted in #5766 for
safe_json_loads: strict parsing is tried first, then the fallback starts from the first JSON whitespace-adjusted document index before recovering the leading object.The fix belongs in
qwenpaw.agents.utils.tool_message_utilsbecause this module owns the tool-call repair/coercion step before messages are submitted to model providers. Keeping the repair here makes historical sessions, streamed tool-call artifacts, and provider request normalization follow the same recovery rule.Narrow Change
The implementation intentionally stays small and conservative:
raw_decodestart index in the two existing recovery pathsjson.loads()pathEvidence
The regression tests cover both affected fallback paths:
After this change, both paths recover the leading object as:
{"path": "README.md"}Existing tests still cover the unchanged behavior for ordinary trailing-garbage recovery, completely invalid JSON, and non-dict recovered values.
Possible Call Chain / Impact
This PR only changes the fallback start index for JSON whitespace. It does not broaden recovery to arbitrary leading garbage, scalar/list payloads, or otherwise unrecoverable malformed tool-call inputs.
Related Issue: Relates to #5766
Security Considerations: No new tool execution surface or permission behavior. This only normalizes already-recorded tool-call argument strings before provider submission; unrecoverable or non-object payloads continue to be rejected/dropped.
Type of Change
Component(s) Affected
Checklist
pre-commit run --all-fileslocally and it passespytestor as relevant) and they passFor Channel Changes (DingTalk, Lark, QQ, Console, etc.)
./scripts/check-channels.sh(or./scripts/check-channels.sh --changed) and it passestests/contract/channels/test_<channel>_contract.py(REQUIRED)create_instance()with proper channel initializationtests/contract/channels/__init__.py)tests/unit/channels/test_<channel>.pyfor complex internal logicTesting
The new regression tests cover both recovery paths:
_repair_empty_tool_inputsrecoversraw_input='\n {"path": "README.md"}trailing garbage'_coerce_tool_inputs_to_jsonrecoversinput='\n {"path": "README.md"}extra'Existing tests continue to cover the unchanged behavior for normal trailing-garbage recovery, completely invalid JSON, and non-dict recovered values.
Local Verification Evidence
pre-commit run --all-fileshas not been run locally for this PR.Channel-specific checklist items are not applicable because this PR does not change any channel implementation or contract surface.
Additional Notes
Possible call chain / impact:
This PR only changes the fallback start index for JSON whitespace. It does not broaden recovery to arbitrary leading garbage, scalar/list payloads, or otherwise unrecoverable malformed tool-call inputs.