fix: handle list content in _serialize_for_summary for multimodal messages
msg.get('content') can return a list of parts for multimodal messages
(containing text, images, etc.). The old code passed this list directly
to redact_sensitive_text(text: str), which raised AttributeError on
list.replace(), causing context compression to fail entirely for any
session with attached images.
Fix: detect list content and extract text parts before redacting.
Image parts are replaced with '[image]' placeholder.
This commit is contained in:
parent
1600008ab0
commit
868a2f7d17
2 changed files with 61 additions and 1 deletions
|
|
@ -1664,7 +1664,21 @@ class ContextCompressor(ContextEngine):
|
|||
parts = []
|
||||
for msg in turns:
|
||||
role = msg.get("role", "unknown")
|
||||
content = redact_sensitive_text(msg.get("content") or "")
|
||||
content = msg.get("content")
|
||||
if isinstance(content, list):
|
||||
text_parts: list[str] = []
|
||||
for part in content:
|
||||
if isinstance(part, dict):
|
||||
if part.get("type") == "text":
|
||||
text_parts.append(part.get("text", ""))
|
||||
elif part.get("type") in {
|
||||
"image", "image_url", "input_image",
|
||||
}:
|
||||
text_parts.append("[image]")
|
||||
elif isinstance(part, str):
|
||||
text_parts.append(part)
|
||||
content = "\n".join(text_parts)
|
||||
content = redact_sensitive_text(content or "")
|
||||
content = _MEDIA_DIRECTIVE_RE.sub("[media attachment]", content)
|
||||
# Strip inline reasoning blocks (<think>, <reasoning>, etc.) from
|
||||
# assistant content before it reaches the summarizer. Reasoning
|
||||
|
|
|
|||
|
|
@ -54,3 +54,49 @@ class TestMediaDirectiveStripping:
|
|||
result = compressor._serialize_for_summary(turns)
|
||||
assert "MEDIA:" not in result
|
||||
assert result.count("[media attachment]") == 2
|
||||
|
||||
def test_multimodal_list_content_does_not_crash(self, compressor):
|
||||
"""content as a list (multimodal) must not crash redact_sensitive_text.
|
||||
|
||||
Regression: msg.get('content') can return a list of parts for
|
||||
multimodal messages (images + text). The old code passed this
|
||||
list directly to redact_sensitive_text(str), which raised
|
||||
AttributeError on list.replace().
|
||||
"""
|
||||
turns = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "text": "What is in this image?"},
|
||||
{"type": "image_url", "image_url": {"url": "data:image/png;base64,abc123"}},
|
||||
],
|
||||
},
|
||||
]
|
||||
# Must not raise
|
||||
result = compressor._serialize_for_summary(turns)
|
||||
assert "What is in this image?" in result
|
||||
assert "[image]" in result
|
||||
|
||||
def test_multimodal_list_text_parts_extracted(self, compressor):
|
||||
"""Text parts from multimodal list content are preserved in output."""
|
||||
turns = [
|
||||
{
|
||||
"role": "user",
|
||||
"content": [
|
||||
{"type": "text", "text": "first part"},
|
||||
{"type": "text", "text": "second part"},
|
||||
],
|
||||
},
|
||||
]
|
||||
result = compressor._serialize_for_summary(turns)
|
||||
assert "first part" in result
|
||||
assert "second part" in result
|
||||
|
||||
def test_multimodal_list_bare_strings_handled(self, compressor):
|
||||
"""Bare strings inside a content list are joined."""
|
||||
turns = [
|
||||
{"role": "user", "content": ["hello", "world"]},
|
||||
]
|
||||
result = compressor._serialize_for_summary(turns)
|
||||
assert "hello" in result
|
||||
assert "world" in result
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue