Skip to content

Commit 26833f2

Browse files
authored
feat(anthropic): v1 support (#32623)
1 parent 5bcf7d0 commit 26833f2

File tree

33 files changed

+2125
-265
lines changed

33 files changed

+2125
-265
lines changed

libs/core/langchain_core/language_models/_utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,7 @@ def _normalize_messages(
212212
}
213213
214214
"""
215-
from langchain_core.messages.block_translators.langchain import (
215+
from langchain_core.messages.block_translators.langchain_v0 import (
216216
_convert_legacy_v0_content_block_to_v1,
217217
_convert_openai_format_to_data_block,
218218
)

libs/core/langchain_core/language_models/chat_models.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ def _format_for_tracing(messages: list[BaseMessage]) -> list[BaseMessage]:
124124
if (
125125
block.get("type") == "image"
126126
and is_data_content_block(block)
127-
and block.get("source_type") != "id"
127+
and not ("file_id" in block or block.get("source_type") == "id")
128128
):
129129
if message_to_trace is message:
130130
# Shallow copy

libs/core/langchain_core/messages/ai.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,10 @@ def content_blocks(self) -> list[types.ContentBlock]:
231231

232232
translator = get_translator(model_provider)
233233
if translator:
234-
return translator["translate_content"](self)
234+
try:
235+
return translator["translate_content_chunk"](self)
236+
except NotImplementedError:
237+
pass
235238

236239
# Otherwise, use best-effort parsing
237240
blocks = super().content_blocks
@@ -380,7 +383,10 @@ def content_blocks(self) -> list[types.ContentBlock]:
380383

381384
translator = get_translator(model_provider)
382385
if translator:
383-
return translator["translate_content_chunk"](self)
386+
try:
387+
return translator["translate_content_chunk"](self)
388+
except NotImplementedError:
389+
pass
384390

385391
# Otherwise, use best-effort parsing
386392
blocks = super().content_blocks

libs/core/langchain_core/messages/base.py

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,14 @@
77
from pydantic import ConfigDict, Field
88

99
from langchain_core.load.serializable import Serializable
10-
from langchain_core.messages.block_translators.langchain import (
11-
_convert_legacy_v0_content_block_to_v1,
12-
_convert_v0_multimodal_input_to_v1,
13-
)
14-
from langchain_core.messages.block_translators.openai import (
15-
_convert_to_v1_from_chat_completions_input,
16-
)
10+
from langchain_core.messages import content as types
1711
from langchain_core.utils import get_bolded_text
1812
from langchain_core.utils._merge import merge_dicts, merge_lists
1913
from langchain_core.utils.interactive_env import is_interactive_env
2014

2115
if TYPE_CHECKING:
2216
from collections.abc import Sequence
2317

24-
from langchain_core.messages import content as types
2518
from langchain_core.prompts.chat import ChatPromptTemplate
2619

2720

@@ -129,6 +122,15 @@ def content_blocks(self) -> list[types.ContentBlock]:
129122
130123
"""
131124
from langchain_core.messages import content as types
125+
from langchain_core.messages.block_translators.anthropic import (
126+
_convert_to_v1_from_anthropic_input,
127+
)
128+
from langchain_core.messages.block_translators.langchain_v0 import (
129+
_convert_v0_multimodal_input_to_v1,
130+
)
131+
from langchain_core.messages.block_translators.openai import (
132+
_convert_to_v1_from_chat_completions_input,
133+
)
132134

133135
blocks: list[types.ContentBlock] = []
134136

@@ -143,26 +145,19 @@ def content_blocks(self) -> list[types.ContentBlock]:
143145
blocks.append({"type": "text", "text": item})
144146
elif isinstance(item, dict):
145147
item_type = item.get("type")
146-
# Try to convert potential v0 format first
147-
converted_block = _convert_legacy_v0_content_block_to_v1(item)
148-
if converted_block is not item: # Conversion happened
149-
blocks.append(cast("types.ContentBlock", converted_block))
150-
elif item_type is None or item_type not in types.KNOWN_BLOCK_TYPES:
151-
blocks.append(
152-
cast(
153-
"types.ContentBlock",
154-
{"type": "non_standard", "value": item},
155-
)
156-
)
148+
if item_type not in types.KNOWN_BLOCK_TYPES:
149+
blocks.append({"type": "non_standard", "value": item})
157150
else:
158151
blocks.append(cast("types.ContentBlock", item))
159152

160153
# Subsequent passes: attempt to unpack non-standard blocks
161-
blocks = _convert_v0_multimodal_input_to_v1(blocks)
162-
# blocks = _convert_to_v1_from_anthropic_input(blocks)
163-
# ...
164-
165-
return _convert_to_v1_from_chat_completions_input(blocks)
154+
for parsing_step in [
155+
_convert_v0_multimodal_input_to_v1,
156+
_convert_to_v1_from_chat_completions_input,
157+
_convert_to_v1_from_anthropic_input,
158+
]:
159+
blocks = parsing_step(blocks)
160+
return blocks
166161

167162
def text(self) -> str:
168163
"""Get the text content of the message.

libs/core/langchain_core/messages/block_translators/__init__.py

Lines changed: 42 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -45,37 +45,45 @@ def get_translator(
4545
return PROVIDER_TRANSLATORS.get(provider)
4646

4747

48-
def _auto_register_translators() -> None:
49-
"""Automatically register all available block translators."""
50-
import contextlib
51-
import importlib
52-
import pkgutil
53-
from pathlib import Path
54-
55-
package_path = Path(__file__).parent
56-
57-
# Discover all sub-modules
58-
for module_info in pkgutil.iter_modules([str(package_path)]):
59-
module_name = module_info.name
60-
61-
# Skip the __init__ module and any private modules
62-
if module_name.startswith("_"):
63-
continue
64-
65-
if module_info.ispkg:
66-
# For subpackages, discover their submodules
67-
subpackage_path = package_path / module_name
68-
for submodule_info in pkgutil.iter_modules([str(subpackage_path)]):
69-
submodule_name = submodule_info.name
70-
if not submodule_name.startswith("_"):
71-
with contextlib.suppress(ImportError, AttributeError):
72-
importlib.import_module(
73-
f".{module_name}.{submodule_name}", package=__name__
74-
)
75-
else:
76-
# Import top-level translator modules
77-
with contextlib.suppress(ImportError, AttributeError):
78-
importlib.import_module(f".{module_name}", package=__name__)
79-
80-
81-
_auto_register_translators()
48+
def _register_translators() -> None:
49+
"""Register all translators in langchain-core.
50+
51+
A unit test ensures all modules in ``block_translators`` are represented here.
52+
53+
For translators implemented outside langchain-core, they can be registered by
54+
calling ``register_translator`` from within the integration package.
55+
"""
56+
from langchain_core.messages.block_translators.anthropic import (
57+
_register_anthropic_translator,
58+
)
59+
from langchain_core.messages.block_translators.bedrock import (
60+
_register_bedrock_translator,
61+
)
62+
from langchain_core.messages.block_translators.bedrock_converse import (
63+
_register_bedrock_converse_translator,
64+
)
65+
from langchain_core.messages.block_translators.google_genai import (
66+
_register_google_genai_translator,
67+
)
68+
from langchain_core.messages.block_translators.google_vertexai import (
69+
_register_google_vertexai_translator,
70+
)
71+
from langchain_core.messages.block_translators.groq import _register_groq_translator
72+
from langchain_core.messages.block_translators.ollama import (
73+
_register_ollama_translator,
74+
)
75+
from langchain_core.messages.block_translators.openai import (
76+
_register_openai_translator,
77+
)
78+
79+
_register_bedrock_translator()
80+
_register_bedrock_converse_translator()
81+
_register_anthropic_translator()
82+
_register_google_genai_translator()
83+
_register_google_vertexai_translator()
84+
_register_groq_translator()
85+
_register_ollama_translator()
86+
_register_openai_translator()
87+
88+
89+
_register_translators()

libs/core/langchain_core/messages/block_translators/amazon/__init__.py

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)