fix(core): (v1) trace PDFs in v0 standard format (#33009)

This commit is contained in:
ccurme
2025-09-18 11:45:12 -04:00
committed by GitHub
parent b6bd507198
commit 8be4adccd1
3 changed files with 62 additions and 5 deletions

View File

@@ -48,7 +48,6 @@ from langchain_core.messages import (
message_chunk_to_message,
)
from langchain_core.messages.block_translators.openai import (
convert_to_openai_data_block,
convert_to_openai_image_block,
)
from langchain_core.output_parsers.openai_tools import (
@@ -149,16 +148,18 @@ def _format_for_tracing(messages: list[BaseMessage]) -> list[BaseMessage]:
block.get("type") == "file"
and is_data_content_block(block) # v0 (image/audio/file) or v1
and "base64" in block
# Narrows to old Base64ContentBlock or new FileContentBlock
# Backward compat: convert v1 base64 blocks to v0
):
if message_to_trace is message:
# Shallow copy
message_to_trace = message.model_copy()
message_to_trace.content = list(message_to_trace.content)
message_to_trace.content[idx] = convert_to_openai_data_block( # type: ignore[index]
block
)
message_to_trace.content[idx] = { # type: ignore[index]
**{k: v for k, v in block.items() if k != "base64"},
"data": block["base64"],
"source_type": "base64",
}
elif len(block) == 1 and "type" not in block:
# Tracing assumes all content blocks have a "type" key. Here
# we add this key if it is missing, and there's an obvious

View File

@@ -1,6 +1,7 @@
"""Test base chat model."""
import uuid
import warnings
from collections.abc import AsyncIterator, Iterator
from typing import TYPE_CHECKING, Any, Literal, Optional, Union
@@ -505,6 +506,45 @@ def test_trace_images_in_openai_format() -> None:
]
def test_trace_pdfs() -> None:
# For backward compat
llm = ParrotFakeChatModel()
messages = [
{
"role": "user",
"content": [
{
"type": "file",
"mime_type": "application/pdf",
"base64": "<base64 string>",
}
],
}
]
tracer = FakeChatModelStartTracer()
with warnings.catch_warnings():
warnings.simplefilter("error")
llm.invoke(messages, config={"callbacks": [tracer]})
assert tracer.messages == [
[
[
HumanMessage(
content=[
{
"type": "file",
"mime_type": "application/pdf",
"source_type": "base64",
"data": "<base64 string>",
}
]
)
]
]
]
def test_content_block_transformation_v0_to_v1_image() -> None:
"""Test that v0 format image content blocks are transformed to v1 format."""
# Create a message with v0 format image content

View File

@@ -789,6 +789,22 @@ def test_format_message_content() -> None:
for content in contents:
assert expected == _format_message_content([content])
# Test warn if PDF is missing a filename
pdf_block = {
"type": "file",
"base64": "<base64 data>",
"mime_type": "application/pdf",
}
expected = [
# N.B. this format is invalid for OpenAI
{
"type": "file",
"file": {"file_data": "data:application/pdf;base64,<base64 data>"},
}
]
with pytest.warns(match="filename"):
assert expected == _format_message_content([pdf_block])
contents = [
{"type": "file", "source_type": "id", "id": "file-abc123"},
{"type": "file", "file_id": "file-abc123"},