Skip to content

fix(agent): tolerate content-parts lists in interim visible text - #66235

Closed
null-runner wants to merge 1 commit into
NousResearch:mainfrom
null-runner:fix/interim-visible-list-content
Closed

null-runner wants to merge 1 commit into
NousResearch:mainfrom
null-runner:fix/interim-visible-list-content

Conversation

@null-runner

Copy link
Copy Markdown
Contributor

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:

content = assistant_msg.get("content")
return self._strip_think_blocks(content or "").strip()

_strip_think_blocks (run_agent.py:1513) forwards to strip_think_blocks in agent/agent_runtime_helpers.py, which runs re.sub(...) on that value (agent_runtime_helpers.py:678). When content is a list of parts rather than a string, re.sub raises:

TypeError: expected string or bytes-like object, got 'list'

The exception propagates out of _interim_assistant_visible_text and 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 content a list?

An assistant message's content is 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.

  • Failing-first verified: against the unfixed run_agent.py, test_interim_visible_text_handles_content_parts_list fails with TypeError: expected string or bytes-like object, got 'list'.
  • With the fix: tests/run_agent/test_interim_visible_list_content.py 3/3 pass; tests/run_agent/test_run_agent_codex_responses.py 104/104 pass (107 total).

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.
@alt-glitch alt-glitch added type/bug Something isn't working comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P1 High — major feature broken, no workaround labels Jul 17, 2026
@alt-glitch

Copy link
Copy Markdown
Contributor

This was generated by AI during triage.

Related to #66218: both prevent the multimodal content-list regex crash. This PR guards the interim-visible path, while #66218 applies coercion in the shared stripping helper.

@tonydwb tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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 tonydwb left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

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

@null-runner

Copy link
Copy Markdown
Contributor Author

Closing: main now fixes this at the shared helper level — 296494d hardens strip_think_blocks to flatten list/dict content for every caller (including _interim_assistant_visible_text, the path this PR patched), which supersedes the caller-side guard here. Verified the merged fix covers our production repro (post-compaction list content no longer raises).

@kshitijk4poor

Copy link
Copy Markdown
Contributor

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P1 High — major feature broken, no workaround type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants