diff --git a/nanobot/agent/loop.py b/nanobot/agent/loop.py index 3505fb496..05ee27885 100644 --- a/nanobot/agent/loop.py +++ b/nanobot/agent/loop.py @@ -1422,6 +1422,10 @@ class AgentLoop: filtered.append({"type": "text", "text": image_placeholder_text(path)}) continue + if block.get("type") in ("input_audio", "video_url"): + filtered.append(LLMProvider._media_placeholder(block["type"], block)) + continue + if block.get("type") == "text" and isinstance(block.get("text"), str): text = block["text"] if should_truncate_text and len(text) > self.max_tool_result_chars: diff --git a/tests/test_truncate_text_shadowing.py b/tests/test_truncate_text_shadowing.py index 11132b511..67022308e 100644 --- a/tests/test_truncate_text_shadowing.py +++ b/tests/test_truncate_text_shadowing.py @@ -29,3 +29,47 @@ def test_sanitize_persisted_blocks_truncate_text_shadowing_regression() -> None: assert isinstance(out[0]["text"], str) assert out[0]["text"] != content[0]["text"] + +def test_sanitize_persisted_blocks_strips_audio_and_video() -> None: + """Audio and video blocks with base64 payloads must be replaced with placeholders.""" + from nanobot.agent.loop import AgentLoop + + dummy = SimpleNamespace(max_tool_result_chars=1000) + content = [ + {"type": "text", "text": "analyze this"}, + { + "type": "input_audio", + "input_audio": {"data": "aGVsbG8=", "format": "wav"}, + "_meta": {"path": "/tmp/voice.wav"}, + }, + { + "type": "video_url", + "video_url": {"url": "data:video/mp4;base64,aGVsbG8="}, + "_meta": {"path": "/tmp/clip.mp4"}, + }, + ] + + out = AgentLoop._sanitize_persisted_blocks(dummy, content) + + assert len(out) == 3 + assert out[0] == content[0] + assert out[1] == {"type": "text", "text": "[audio: /tmp/voice.wav]"} + assert out[2] == {"type": "text", "text": "[video: /tmp/clip.mp4]"} + + +def test_sanitize_persisted_blocks_strips_audio_video_without_meta() -> None: + """When _meta is absent, fallback placeholders use bare label.""" + from nanobot.agent.loop import AgentLoop + + dummy = SimpleNamespace(max_tool_result_chars=1000) + content = [ + {"type": "input_audio", "input_audio": {"data": "aGVsbG8=", "format": "wav"}}, + {"type": "video_url", "video_url": {"url": "data:video/mp4;base64,aGVsbG8="}}, + ] + + out = AgentLoop._sanitize_persisted_blocks(dummy, content) + + assert len(out) == 2 + assert out[0] == {"type": "text", "text": "[audio]"} + assert out[1] == {"type": "text", "text": "[video]"} +