Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions tests/trace_server/test_genai_chat_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,40 @@ def test_inline_internal_ref_surfaces_without_span_content_refs() -> None:
assert _assistant_payload(assistant).content_refs == []


def test_blob_content_is_media_not_user_message_text() -> None:
"""A Weave blob's `content` is base64/ref data, not displayable prose."""
image_internal = "weave-trace-internal:///PID/object/Content:IMAGEDIGEST"
spans = [
_span(
span_id="agent",
operation_name="invoke_agent",
agent_name="image-analyzer",
input_messages=[
{
"role": "user",
"content": _parts(
{
"type": "blob",
"content": image_internal,
"mimeType": "image/png",
"modality": "image",
},
_text_part("Describe this image."),
),
}
],
)
]

messages = build_chat_messages(spans)
user = next(m for m in messages if m.type == "user_message")

assert _user_payload(user) == AgentChatUserMessage(
text="Describe this image.",
content_refs=[image_internal],
)


@pytest.mark.xfail(
reason=(
"Known limitation (PR #7489 discussion): the inline-ref sweep "
Expand Down
11 changes: 7 additions & 4 deletions weave/trace_server/agents/chat_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -690,9 +690,9 @@ def _display_text(content: str) -> str:
"""Extract human-readable text from a message content field.

Content is either plain text (legacy) or a JSON-serialized parts array
(multimodal messages). For parts arrays, concatenate the text parts;
reasoning parts are excluded (they surface separately via
`reasoning_content`). For plain text, return as-is.
(multimodal messages). For parts arrays, concatenate text parts. Reasoning
surfaces through ``reasoning_content``; media surfaces through
``content_refs``. For plain text, return as-is.
"""
if not content or not content.startswith("["):
return content
Expand All @@ -709,9 +709,12 @@ def _display_text(content: str) -> str:
# concatenating it here would duplicate it in the message body.
if p.get("type") == "reasoning":
continue
# Media belongs in content_refs, never chat text.
if p.get("type") in _MEDIA_PART_TYPES:
continue
# Support both the weave parts model (``content``) and the
# OpenAI-style multimodal shape (``text``). Non-text parts (e.g.
# images) carry neither and are skipped for display.
# images) are skipped for display.
if isinstance(p.get("content"), str):
texts.append(p["content"])
elif isinstance(p.get("text"), str):
Expand Down
Loading