fix: send-time pad must skip multimodal (list) assistant content

The empty-content pad loop called .strip() on am.get("content") without
checking the type.  Multimodal assistant turns carry content as a list
of parts (text/image), so a session with any image-bearing turn crashed
during request assembly:

    AttributeError: 'list' object has no attribute 'strip'

Guard with isinstance(content, str) — a multimodal turn is never the
empty textless shape the pad repairs.  Adds a regression test driving a
multimodal history through the loop.
This commit is contained in:
0xprincess 2026-07-20 20:31:56 +03:00 committed by Teknium
parent 309f06b044
commit 2a26be69c9

View file

@ -861,3 +861,41 @@ class TestSendTimeEmptyAssistantPad:
"tool_calls is accepted by every provider and normalizing it "
"would alter prompt-cache keys."
)
class TestSendTimePadMultimodalSafety:
"""Regression: the send-time pad must skip multimodal (list) assistant
content instead of crashing a forked session whose new user turn
attaches an image hit AttributeError: 'list' object has no attribute
'strip' inside the pad loop."""
def test_multimodal_assistant_content_not_touched(self, loop_agent):
from tests.run_agent.test_run_agent import _mock_response
multimodal = [
{"role": "user", "content": "look at this"},
{"role": "assistant", "content": [
{"type": "text", "text": "I see an image"},
]},
{"role": "user", "content": [
{"type": "text", "text": "animate it"},
{"type": "image_url", "image_url": {"url": "data:image/png;base64,iVBORw0KGgo="}},
]},
]
loop_agent.client.chat.completions.create.return_value = _mock_response(
content="ok", finish_reason="stop",
)
with (
patch.object(loop_agent, "_persist_session"),
patch.object(loop_agent, "_save_trajectory"),
patch.object(loop_agent, "_cleanup_task_resources"),
):
result = loop_agent.run_conversation(
"animate it", conversation_history=multimodal,
)
assert result["completed"] is True
kwargs = loop_agent.client.chat.completions.create.call_args_list[0]
sent = kwargs.kwargs.get("messages") or kwargs.args[0].get("messages")
mm = next(m for m in sent if isinstance(m.get("content"), list) and m.get("role") == "assistant")
assert mm["content"] == [{"type": "text", "text": "I see an image"}], (
"Multimodal assistant content must pass through untouched."
)