fix(detection): preserve raw codepoints in tool-result extraction - #47
Open
Rahul-s-007 wants to merge 1 commit into
Open
fix(detection): preserve raw codepoints in tool-result extraction#47Rahul-s-007 wants to merge 1 commit into
Rahul-s-007 wants to merge 1 commit into
Conversation
Split out of PR uber#43 per review - this is a distinct benchmark-harness data-integrity bug, not the Unicode-detection feature itself. Fixes uber#46. SessionManager._parse_message passed tool_result message content - always a list of content blocks for Claude Code's JSONL - straight into _truncate_content, whose non-str branch called str() on it. str() on a list repr()s every element, which escapes non-printable Unicode (Tag Block "ASCII smuggling" characters are category Cf) into literal backslash text before json.dump ever writes claude_conversation.json. Irreversible: nothing downstream un-reprs it. Hits every MCP tool_result in a real recorded run (8112/~19k message contents). Adds SessionManager._extract_text_from_content, mirroring the two already-proven implementations in Sensor/adr_sensor/parsers/claude_parser.py and claude_desktop_parser.py, including the toolUseResult root-level override both reference parsers apply. Also fixes three edge cases found during review: - dict-shaped content now uses json.dumps(ensure_ascii=False) instead of falling to the same str()/repr() bug for a different content shape - a falsy toolUseResult['result'] (e.g. "") no longer overwrites a tool_result block's own real content - only a truthy override applies - a single root-level toolUseResult is only applied when there's exactly one tool_result block in the message, instead of clobbering every block with the same value when there are several (e.g. parallel tool calls) And fixes a regression the review surfaced in the same code path: ToolAnalyzer.analyze_tool_usage detected failed tool calls by string-matching repr artifacts ("'is_error': True", "'tool_use_id': '...'") that only existed because of the str()/repr() bug above - a correct fix for that bug makes the string match always fail, so failed_tool_ids stays permanently empty and every failed tool call gets counted as successful, for every task in tasks.json. Fixed by tracking failure structurally instead: SessionManager now extracts each tool_result block's own is_error/tool_use_id fields directly via a new _extract_failed_tool_ids helper, populating a failed_tool_use_ids field that ToolAnalyzer reads instead of string-matching. The pre-existing text-based fallback for a tool-not-found error (unrelated to this bug, not reported as broken) is left untouched. New test coverage: SessionManager content extraction (tag-block payload survival, toolUseResult override precedence, all three edge cases, failed_tool_use_ids extraction) and ToolAnalyzer (failed calls correctly excluded, successful calls still counted, the pre-existing text fallback still works). Verified the regression tests actually catch the bugs: temporarily reverted this fix, reran, confirmed 6 tests fail with the exact symptoms described (literal \U000e... text, KeyError on the new field, real content clobbered by an empty override), then confirmed all pass again with the fix restored. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This was referenced Aug 18, 2026
pengyuzhang
approved these changes
Aug 20, 2026
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.
What type of PR is this? (check all applicable)
Related issue: Closes #46
What changed?
SessionManager._parse_message(main_benchmark.py) now extracts real text fromtool_resultcontent via a new_extract_text_from_contentmethod instead of callingstr()on the raw content list, which was silently corrupting any non-printable Unicode into literal backslash text via Python'srepr()before it was ever written to disk. Mirrors the two already-proven implementations inSensor/adr_sensor/parsers/claude_parser.py/claude_desktop_parser.py, including thetoolUseResultroot-level override both apply. Also fixes 3 edge cases found during review (dict-shaped content, a falsytoolUseResult['result']discarding real content, onetoolUseResultclobbering multipletool_resultblocks), and a regression the review surfaced:ToolAnalyzer.analyze_tool_usagedetected failed tool calls by string-matching repr artifacts that only existed because of the bug above — fixing the bug correctly made that detection permanently silent. Fixed by tracking failure structurally via a newfailed_tool_use_idsfield instead of string-matching.Why?
This is the root-cause fix underlying a Unicode-obfuscation detection feature (separate PR to follow) — without it, that feature can never see real payloads on the actual benchmark execution path, only mangled text. Split out per review as its own, independently-reviewable harness bug fix.
How did you test it?
24 tests in
tests/test_main_benchmark.py(TestSessionManagerContentExtraction,TestToolAnalyzer) covering the core fix, all 3 edge cases, and the regression fix. Verified the regression tests actually catch the bugs — temporarily reverted just this fix, reran, confirmed 6 tests fail with the exact predicted symptoms (literal\U000e...text,KeyErroron the missing field, real content clobbered by an empty override), then confirmed all pass again with the fix restored.24 passed — click to expand
Potential risks
Low-medium. Touches a parsing path with zero prior test coverage (confirmed via grep before this PR). The
ToolAnalyzerfix changes what counts as a "failed" tool call — verified via dedicated tests that both the new structural detection and the pre-existing text-based fallback work correctly.