fix(agent): tolerate content-parts lists in interim visible text - #66235
null-runner wants to merge 1 commit into
Conversation
After context compaction (and with multimodal providers) an assistant message's `content` can be a list of parts instead of a string. `_interim_assistant_visible_text` passed that list straight into `_strip_think_blocks` -> `strip_think_blocks` (agent/agent_runtime_helpers.py), whose `re.sub` raised `TypeError: expected string or bytes-like object, got 'list'`. The exception then propagated to every subsequent API call in the turn, so the session appeared stuck to the user. Join the textual parts before stripping think-blocks; non-text parts (images) are ignored. Plain-string content is unchanged.
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved
Fix for content-parts lists in interim visible text. The change handles a real edge case where compaction or multimodal providers leave content as a list instead of a string. The implementation correctly joins only textual parts and ignores non-text entries. New tests cover the key scenarios.
Reviewed by Hermes Agent
tonydwb
left a comment
There was a problem hiding this comment.
Code Review Summary
Verdict: Approved (LGTM)
Overview
Tolerates content-parts lists in interim visible text for agent. +53/0.
Security
- No hardcoded secrets or credentials
Code Quality
- Clean multimodal content handling
Looks Good
- Proper edge case handling
Reviewed by Hermes Agent
|
Closing: main now fixes this at the shared helper level — 296494d hardens |
|
Merged via commit 296494d — Teknium's fix at the shared chokepoint (strip_think_blocks) covers the same bug class this PR addresses. The fix coerces list/dict content to visible text before any regex runs, protecting all callers including _interim_assistant_visible_text. Your contribution is appreciated — narrow fix in _interim_assistant_visible_text only. Credit preserved in the commit message investigation. Thanks for the report and fix! For the remaining gap (build_assistant_message defense-in-depth + error classifier concept), we're tracking in a follow-up issue. |
Bug
AIAgent._interim_assistant_visible_text(run_agent.py:4823-4824) reads the assistant message content and passes it straight into the think-block stripper:_strip_think_blocks(run_agent.py:1513) forwards tostrip_think_blocksinagent/agent_runtime_helpers.py, which runsre.sub(...)on that value (agent_runtime_helpers.py:678). Whencontentis a list of parts rather than a string,re.subraises:The exception propagates out of
_interim_assistant_visible_textand then out of every subsequent API call in the turn, so the conversation appears frozen to the user (observed in practice with several back-to-back API calls in one turn all dying the same way).When is
contenta list?An assistant message's
contentis a parts list (not a string) after context compaction, and with multimodal providers, e.g.:[{"type": "text", "text": "..."}, {"type": "image_url", "image_url": {...}}]The helper only ever handled string content, so this path was unguarded.
Fix
Join the textual parts before stripping think-blocks; non-text parts (images) are ignored, and plain-string content is unchanged. 8 lines in
run_agent.py.Tests
New
tests/run_agent/test_interim_visible_list_content.py— 3 cases: a mixed text/image parts list, an image-only list, and a plain string.run_agent.py,test_interim_visible_text_handles_content_parts_listfails withTypeError: expected string or bytes-like object, got 'list'.tests/run_agent/test_interim_visible_list_content.py3/3 pass;tests/run_agent/test_run_agent_codex_responses.py104/104 pass (107 total).