langchain-core 1.0.0a5__py3-none-any.whl → 1.0.3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langchain_core/__init__.py +1 -1
- langchain_core/_api/__init__.py +3 -4
- langchain_core/_api/beta_decorator.py +23 -26
- langchain_core/_api/deprecation.py +51 -64
- langchain_core/_api/path.py +3 -6
- langchain_core/_import_utils.py +3 -4
- langchain_core/agents.py +20 -22
- langchain_core/caches.py +65 -66
- langchain_core/callbacks/__init__.py +1 -8
- langchain_core/callbacks/base.py +321 -336
- langchain_core/callbacks/file.py +44 -44
- langchain_core/callbacks/manager.py +436 -513
- langchain_core/callbacks/stdout.py +29 -30
- langchain_core/callbacks/streaming_stdout.py +32 -32
- langchain_core/callbacks/usage.py +60 -57
- langchain_core/chat_history.py +53 -68
- langchain_core/document_loaders/base.py +27 -25
- langchain_core/document_loaders/blob_loaders.py +1 -1
- langchain_core/document_loaders/langsmith.py +44 -48
- langchain_core/documents/__init__.py +23 -3
- langchain_core/documents/base.py +98 -90
- langchain_core/documents/compressor.py +10 -10
- langchain_core/documents/transformers.py +34 -35
- langchain_core/embeddings/fake.py +50 -54
- langchain_core/example_selectors/length_based.py +1 -1
- langchain_core/example_selectors/semantic_similarity.py +28 -32
- langchain_core/exceptions.py +21 -20
- langchain_core/globals.py +3 -151
- langchain_core/indexing/__init__.py +1 -1
- langchain_core/indexing/api.py +121 -126
- langchain_core/indexing/base.py +73 -75
- langchain_core/indexing/in_memory.py +4 -6
- langchain_core/language_models/__init__.py +14 -29
- langchain_core/language_models/_utils.py +58 -61
- langchain_core/language_models/base.py +53 -162
- langchain_core/language_models/chat_models.py +298 -387
- langchain_core/language_models/fake.py +11 -11
- langchain_core/language_models/fake_chat_models.py +42 -36
- langchain_core/language_models/llms.py +125 -235
- langchain_core/load/dump.py +9 -12
- langchain_core/load/load.py +18 -28
- langchain_core/load/mapping.py +2 -4
- langchain_core/load/serializable.py +42 -40
- langchain_core/messages/__init__.py +10 -16
- langchain_core/messages/ai.py +148 -148
- langchain_core/messages/base.py +58 -52
- langchain_core/messages/block_translators/__init__.py +27 -17
- langchain_core/messages/block_translators/anthropic.py +6 -6
- langchain_core/messages/block_translators/bedrock_converse.py +5 -5
- langchain_core/messages/block_translators/google_genai.py +505 -20
- langchain_core/messages/block_translators/google_vertexai.py +4 -32
- langchain_core/messages/block_translators/groq.py +117 -21
- langchain_core/messages/block_translators/langchain_v0.py +5 -5
- langchain_core/messages/block_translators/openai.py +11 -11
- langchain_core/messages/chat.py +2 -6
- langchain_core/messages/content.py +337 -328
- langchain_core/messages/function.py +6 -10
- langchain_core/messages/human.py +24 -31
- langchain_core/messages/modifier.py +2 -2
- langchain_core/messages/system.py +19 -29
- langchain_core/messages/tool.py +74 -90
- langchain_core/messages/utils.py +474 -504
- langchain_core/output_parsers/__init__.py +13 -10
- langchain_core/output_parsers/base.py +61 -61
- langchain_core/output_parsers/format_instructions.py +9 -4
- langchain_core/output_parsers/json.py +12 -10
- langchain_core/output_parsers/list.py +21 -23
- langchain_core/output_parsers/openai_functions.py +49 -47
- langchain_core/output_parsers/openai_tools.py +16 -21
- langchain_core/output_parsers/pydantic.py +13 -14
- langchain_core/output_parsers/string.py +5 -5
- langchain_core/output_parsers/transform.py +15 -17
- langchain_core/output_parsers/xml.py +35 -34
- langchain_core/outputs/__init__.py +1 -1
- langchain_core/outputs/chat_generation.py +18 -18
- langchain_core/outputs/chat_result.py +1 -3
- langchain_core/outputs/generation.py +10 -11
- langchain_core/outputs/llm_result.py +10 -10
- langchain_core/prompt_values.py +11 -17
- langchain_core/prompts/__init__.py +3 -27
- langchain_core/prompts/base.py +48 -56
- langchain_core/prompts/chat.py +275 -325
- langchain_core/prompts/dict.py +5 -5
- langchain_core/prompts/few_shot.py +81 -88
- langchain_core/prompts/few_shot_with_templates.py +11 -13
- langchain_core/prompts/image.py +12 -14
- langchain_core/prompts/loading.py +4 -6
- langchain_core/prompts/message.py +3 -3
- langchain_core/prompts/prompt.py +24 -39
- langchain_core/prompts/string.py +26 -10
- langchain_core/prompts/structured.py +49 -53
- langchain_core/rate_limiters.py +51 -60
- langchain_core/retrievers.py +61 -198
- langchain_core/runnables/base.py +1478 -1630
- langchain_core/runnables/branch.py +53 -57
- langchain_core/runnables/config.py +72 -89
- langchain_core/runnables/configurable.py +120 -137
- langchain_core/runnables/fallbacks.py +83 -79
- langchain_core/runnables/graph.py +91 -97
- langchain_core/runnables/graph_ascii.py +27 -28
- langchain_core/runnables/graph_mermaid.py +38 -50
- langchain_core/runnables/graph_png.py +15 -16
- langchain_core/runnables/history.py +135 -148
- langchain_core/runnables/passthrough.py +124 -150
- langchain_core/runnables/retry.py +46 -51
- langchain_core/runnables/router.py +25 -30
- langchain_core/runnables/schema.py +75 -80
- langchain_core/runnables/utils.py +60 -67
- langchain_core/stores.py +85 -121
- langchain_core/structured_query.py +8 -8
- langchain_core/sys_info.py +27 -29
- langchain_core/tools/__init__.py +1 -14
- langchain_core/tools/base.py +285 -229
- langchain_core/tools/convert.py +160 -155
- langchain_core/tools/render.py +10 -10
- langchain_core/tools/retriever.py +12 -11
- langchain_core/tools/simple.py +19 -24
- langchain_core/tools/structured.py +32 -39
- langchain_core/tracers/__init__.py +1 -9
- langchain_core/tracers/base.py +97 -99
- langchain_core/tracers/context.py +29 -52
- langchain_core/tracers/core.py +49 -53
- langchain_core/tracers/evaluation.py +11 -11
- langchain_core/tracers/event_stream.py +65 -64
- langchain_core/tracers/langchain.py +21 -21
- langchain_core/tracers/log_stream.py +45 -45
- langchain_core/tracers/memory_stream.py +3 -3
- langchain_core/tracers/root_listeners.py +16 -16
- langchain_core/tracers/run_collector.py +2 -4
- langchain_core/tracers/schemas.py +0 -129
- langchain_core/tracers/stdout.py +3 -3
- langchain_core/utils/__init__.py +1 -4
- langchain_core/utils/_merge.py +2 -2
- langchain_core/utils/aiter.py +57 -61
- langchain_core/utils/env.py +9 -9
- langchain_core/utils/function_calling.py +89 -186
- langchain_core/utils/html.py +7 -8
- langchain_core/utils/input.py +6 -6
- langchain_core/utils/interactive_env.py +1 -1
- langchain_core/utils/iter.py +36 -40
- langchain_core/utils/json.py +4 -3
- langchain_core/utils/json_schema.py +9 -9
- langchain_core/utils/mustache.py +8 -10
- langchain_core/utils/pydantic.py +33 -35
- langchain_core/utils/strings.py +6 -9
- langchain_core/utils/usage.py +1 -1
- langchain_core/utils/utils.py +66 -62
- langchain_core/vectorstores/base.py +182 -216
- langchain_core/vectorstores/in_memory.py +101 -176
- langchain_core/vectorstores/utils.py +5 -5
- langchain_core/version.py +1 -1
- langchain_core-1.0.3.dist-info/METADATA +69 -0
- langchain_core-1.0.3.dist-info/RECORD +172 -0
- {langchain_core-1.0.0a5.dist-info → langchain_core-1.0.3.dist-info}/WHEEL +1 -1
- langchain_core/memory.py +0 -120
- langchain_core/messages/block_translators/ollama.py +0 -47
- langchain_core/prompts/pipeline.py +0 -138
- langchain_core/pydantic_v1/__init__.py +0 -30
- langchain_core/pydantic_v1/dataclasses.py +0 -23
- langchain_core/pydantic_v1/main.py +0 -23
- langchain_core/tracers/langchain_v1.py +0 -31
- langchain_core/utils/loading.py +0 -35
- langchain_core-1.0.0a5.dist-info/METADATA +0 -77
- langchain_core-1.0.0a5.dist-info/RECORD +0 -181
- langchain_core-1.0.0a5.dist-info/entry_points.txt +0 -4
langchain_core/messages/base.py
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
-
from typing import TYPE_CHECKING, Any,
|
|
5
|
+
from typing import TYPE_CHECKING, Any, cast, overload
|
|
6
6
|
|
|
7
7
|
from pydantic import ConfigDict, Field
|
|
8
8
|
from typing_extensions import Self
|
|
@@ -22,7 +22,7 @@ if TYPE_CHECKING:
|
|
|
22
22
|
|
|
23
23
|
def _extract_reasoning_from_additional_kwargs(
|
|
24
24
|
message: BaseMessage,
|
|
25
|
-
) ->
|
|
25
|
+
) -> types.ReasoningContentBlock | None:
|
|
26
26
|
"""Extract `reasoning_content` from `additional_kwargs`.
|
|
27
27
|
|
|
28
28
|
Handles reasoning content stored in various formats:
|
|
@@ -34,13 +34,11 @@ def _extract_reasoning_from_additional_kwargs(
|
|
|
34
34
|
Returns:
|
|
35
35
|
A `ReasoningContentBlock` if reasoning content is found, None otherwise.
|
|
36
36
|
"""
|
|
37
|
-
from langchain_core.messages.content import create_reasoning_block # noqa: PLC0415
|
|
38
|
-
|
|
39
37
|
additional_kwargs = getattr(message, "additional_kwargs", {})
|
|
40
38
|
|
|
41
39
|
reasoning_content = additional_kwargs.get("reasoning_content")
|
|
42
40
|
if reasoning_content is not None and isinstance(reasoning_content, str):
|
|
43
|
-
return
|
|
41
|
+
return {"type": "reasoning", "reasoning": reasoning_content}
|
|
44
42
|
|
|
45
43
|
return None
|
|
46
44
|
|
|
@@ -50,13 +48,13 @@ class TextAccessor(str):
|
|
|
50
48
|
|
|
51
49
|
Exists to maintain backward compatibility while transitioning from method-based to
|
|
52
50
|
property-based text access in message objects. In LangChain <v1.0, message text was
|
|
53
|
-
accessed via
|
|
54
|
-
access via
|
|
51
|
+
accessed via `.text()` method calls. In v1.0=<, the preferred pattern is property
|
|
52
|
+
access via `.text`.
|
|
55
53
|
|
|
56
|
-
Rather than breaking existing code immediately,
|
|
54
|
+
Rather than breaking existing code immediately, `TextAccessor` allows both
|
|
57
55
|
patterns:
|
|
58
|
-
- Modern property access:
|
|
59
|
-
- Legacy method access:
|
|
56
|
+
- Modern property access: `message.text` (returns string directly)
|
|
57
|
+
- Legacy method access: `message.text()` (callable, emits deprecation warning)
|
|
60
58
|
|
|
61
59
|
"""
|
|
62
60
|
|
|
@@ -69,12 +67,12 @@ class TextAccessor(str):
|
|
|
69
67
|
def __call__(self) -> str:
|
|
70
68
|
"""Enable method-style text access for backward compatibility.
|
|
71
69
|
|
|
72
|
-
This method exists solely to support legacy code that calls
|
|
73
|
-
as a method. New code should use property access (
|
|
70
|
+
This method exists solely to support legacy code that calls `.text()`
|
|
71
|
+
as a method. New code should use property access (`.text`) instead.
|
|
74
72
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
instead. This method will be removed in 2.0.0.
|
|
73
|
+
!!! deprecated
|
|
74
|
+
As of `langchain-core` 1.0.0, calling `.text()` as a method is deprecated.
|
|
75
|
+
Use `.text` as a property instead. This method will be removed in 2.0.0.
|
|
78
76
|
|
|
79
77
|
Returns:
|
|
80
78
|
The string content, identical to property access.
|
|
@@ -94,11 +92,15 @@ class TextAccessor(str):
|
|
|
94
92
|
class BaseMessage(Serializable):
|
|
95
93
|
"""Base abstract message class.
|
|
96
94
|
|
|
97
|
-
Messages are the inputs and outputs of
|
|
95
|
+
Messages are the inputs and outputs of a chat model.
|
|
96
|
+
|
|
97
|
+
Examples include [`HumanMessage`][langchain.messages.HumanMessage],
|
|
98
|
+
[`AIMessage`][langchain.messages.AIMessage], and
|
|
99
|
+
[`SystemMessage`][langchain.messages.SystemMessage].
|
|
98
100
|
"""
|
|
99
101
|
|
|
100
|
-
content:
|
|
101
|
-
"""The
|
|
102
|
+
content: str | list[str | dict]
|
|
103
|
+
"""The contents of the message."""
|
|
102
104
|
|
|
103
105
|
additional_kwargs: dict = Field(default_factory=dict)
|
|
104
106
|
"""Reserved for additional payload data associated with the message.
|
|
@@ -119,7 +121,7 @@ class BaseMessage(Serializable):
|
|
|
119
121
|
|
|
120
122
|
"""
|
|
121
123
|
|
|
122
|
-
name:
|
|
124
|
+
name: str | None = None
|
|
123
125
|
"""An optional name for the message.
|
|
124
126
|
|
|
125
127
|
This can be used to provide a human-readable name for the message.
|
|
@@ -129,7 +131,7 @@ class BaseMessage(Serializable):
|
|
|
129
131
|
|
|
130
132
|
"""
|
|
131
133
|
|
|
132
|
-
id:
|
|
134
|
+
id: str | None = Field(default=None, coerce_numbers_to_str=True)
|
|
133
135
|
"""An optional unique identifier for the message.
|
|
134
136
|
|
|
135
137
|
This should ideally be provided by the provider/model which created the message.
|
|
@@ -143,32 +145,32 @@ class BaseMessage(Serializable):
|
|
|
143
145
|
@overload
|
|
144
146
|
def __init__(
|
|
145
147
|
self,
|
|
146
|
-
content:
|
|
148
|
+
content: str | list[str | dict],
|
|
147
149
|
**kwargs: Any,
|
|
148
150
|
) -> None: ...
|
|
149
151
|
|
|
150
152
|
@overload
|
|
151
153
|
def __init__(
|
|
152
154
|
self,
|
|
153
|
-
content:
|
|
154
|
-
content_blocks:
|
|
155
|
+
content: str | list[str | dict] | None = None,
|
|
156
|
+
content_blocks: list[types.ContentBlock] | None = None,
|
|
155
157
|
**kwargs: Any,
|
|
156
158
|
) -> None: ...
|
|
157
159
|
|
|
158
160
|
def __init__(
|
|
159
161
|
self,
|
|
160
|
-
content:
|
|
161
|
-
content_blocks:
|
|
162
|
+
content: str | list[str | dict] | None = None,
|
|
163
|
+
content_blocks: list[types.ContentBlock] | None = None,
|
|
162
164
|
**kwargs: Any,
|
|
163
165
|
) -> None:
|
|
164
|
-
"""Initialize
|
|
166
|
+
"""Initialize a `BaseMessage`.
|
|
165
167
|
|
|
166
|
-
Specify
|
|
168
|
+
Specify `content` as positional arg or `content_blocks` for typing.
|
|
167
169
|
|
|
168
170
|
Args:
|
|
169
|
-
content: The
|
|
171
|
+
content: The contents of the message.
|
|
170
172
|
content_blocks: Typed standard content.
|
|
171
|
-
kwargs: Additional arguments to pass to the parent class.
|
|
173
|
+
**kwargs: Additional arguments to pass to the parent class.
|
|
172
174
|
"""
|
|
173
175
|
if content_blocks is not None:
|
|
174
176
|
super().__init__(content=content_blocks, **kwargs)
|
|
@@ -177,7 +179,7 @@ class BaseMessage(Serializable):
|
|
|
177
179
|
|
|
178
180
|
@classmethod
|
|
179
181
|
def is_lc_serializable(cls) -> bool:
|
|
180
|
-
"""
|
|
182
|
+
"""`BaseMessage` is serializable.
|
|
181
183
|
|
|
182
184
|
Returns:
|
|
183
185
|
True
|
|
@@ -186,10 +188,10 @@ class BaseMessage(Serializable):
|
|
|
186
188
|
|
|
187
189
|
@classmethod
|
|
188
190
|
def get_lc_namespace(cls) -> list[str]:
|
|
189
|
-
"""Get the namespace of the
|
|
191
|
+
"""Get the namespace of the LangChain object.
|
|
190
192
|
|
|
191
193
|
Returns:
|
|
192
|
-
|
|
194
|
+
`["langchain", "schema", "messages"]`
|
|
193
195
|
"""
|
|
194
196
|
return ["langchain", "schema", "messages"]
|
|
195
197
|
|
|
@@ -197,7 +199,7 @@ class BaseMessage(Serializable):
|
|
|
197
199
|
def content_blocks(self) -> list[types.ContentBlock]:
|
|
198
200
|
r"""Load content blocks from the message content.
|
|
199
201
|
|
|
200
|
-
|
|
202
|
+
!!! version-added "Added in version 1.0.0"
|
|
201
203
|
|
|
202
204
|
"""
|
|
203
205
|
# Needed here to avoid circular import, as these classes import BaseMessages
|
|
@@ -208,6 +210,9 @@ class BaseMessage(Serializable):
|
|
|
208
210
|
from langchain_core.messages.block_translators.bedrock_converse import ( # noqa: PLC0415
|
|
209
211
|
_convert_to_v1_from_converse_input,
|
|
210
212
|
)
|
|
213
|
+
from langchain_core.messages.block_translators.google_genai import ( # noqa: PLC0415
|
|
214
|
+
_convert_to_v1_from_genai_input,
|
|
215
|
+
)
|
|
211
216
|
from langchain_core.messages.block_translators.langchain_v0 import ( # noqa: PLC0415
|
|
212
217
|
_convert_v0_multimodal_input_to_v1,
|
|
213
218
|
)
|
|
@@ -243,11 +248,12 @@ class BaseMessage(Serializable):
|
|
|
243
248
|
blocks.append(cast("types.ContentBlock", item))
|
|
244
249
|
|
|
245
250
|
# Subsequent passes: attempt to unpack non-standard blocks.
|
|
246
|
-
#
|
|
251
|
+
# This is the last stop - if we can't parse it here, it is left as non-standard
|
|
247
252
|
for parsing_step in [
|
|
248
253
|
_convert_v0_multimodal_input_to_v1,
|
|
249
254
|
_convert_to_v1_from_chat_completions_input,
|
|
250
255
|
_convert_to_v1_from_anthropic_input,
|
|
256
|
+
_convert_to_v1_from_genai_input,
|
|
251
257
|
_convert_to_v1_from_converse_input,
|
|
252
258
|
]:
|
|
253
259
|
blocks = parsing_step(blocks)
|
|
@@ -257,11 +263,11 @@ class BaseMessage(Serializable):
|
|
|
257
263
|
def text(self) -> TextAccessor:
|
|
258
264
|
"""Get the text content of the message as a string.
|
|
259
265
|
|
|
260
|
-
Can be used as both property (
|
|
266
|
+
Can be used as both property (`message.text`) and method (`message.text()`).
|
|
261
267
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
instead. This method will be removed in 2.0.0.
|
|
268
|
+
!!! deprecated
|
|
269
|
+
As of `langchain-core` 1.0.0, calling `.text()` as a method is deprecated.
|
|
270
|
+
Use `.text` as a property instead. This method will be removed in 2.0.0.
|
|
265
271
|
|
|
266
272
|
Returns:
|
|
267
273
|
The text content of the message.
|
|
@@ -304,8 +310,8 @@ class BaseMessage(Serializable):
|
|
|
304
310
|
"""Get a pretty representation of the message.
|
|
305
311
|
|
|
306
312
|
Args:
|
|
307
|
-
html: Whether to format the message as HTML. If True
|
|
308
|
-
formatted with HTML tags.
|
|
313
|
+
html: Whether to format the message as HTML. If `True`, the message will be
|
|
314
|
+
formatted with HTML tags.
|
|
309
315
|
|
|
310
316
|
Returns:
|
|
311
317
|
A pretty representation of the message.
|
|
@@ -323,20 +329,20 @@ class BaseMessage(Serializable):
|
|
|
323
329
|
|
|
324
330
|
|
|
325
331
|
def merge_content(
|
|
326
|
-
first_content:
|
|
327
|
-
*contents:
|
|
328
|
-
) ->
|
|
332
|
+
first_content: str | list[str | dict],
|
|
333
|
+
*contents: str | list[str | dict],
|
|
334
|
+
) -> str | list[str | dict]:
|
|
329
335
|
"""Merge multiple message contents.
|
|
330
336
|
|
|
331
337
|
Args:
|
|
332
|
-
first_content: The first
|
|
333
|
-
contents: The other
|
|
338
|
+
first_content: The first `content`. Can be a string or a list.
|
|
339
|
+
contents: The other `content`s. Can be a string or a list.
|
|
334
340
|
|
|
335
341
|
Returns:
|
|
336
342
|
The merged content.
|
|
337
343
|
|
|
338
344
|
"""
|
|
339
|
-
merged:
|
|
345
|
+
merged: str | list[str | dict]
|
|
340
346
|
merged = "" if first_content is None else first_content
|
|
341
347
|
|
|
342
348
|
for content in contents:
|
|
@@ -386,9 +392,9 @@ class BaseMessageChunk(BaseMessage):
|
|
|
386
392
|
|
|
387
393
|
For example,
|
|
388
394
|
|
|
389
|
-
|
|
395
|
+
`AIMessageChunk(content="Hello") + AIMessageChunk(content=" World")`
|
|
390
396
|
|
|
391
|
-
will give
|
|
397
|
+
will give `AIMessageChunk(content="Hello World")`
|
|
392
398
|
|
|
393
399
|
"""
|
|
394
400
|
if isinstance(other, BaseMessageChunk):
|
|
@@ -437,8 +443,8 @@ def message_to_dict(message: BaseMessage) -> dict:
|
|
|
437
443
|
message: Message to convert.
|
|
438
444
|
|
|
439
445
|
Returns:
|
|
440
|
-
Message as a dict. The dict will have a
|
|
441
|
-
and a
|
|
446
|
+
Message as a dict. The dict will have a `type` key with the message type
|
|
447
|
+
and a `data` key with the message data as a dict.
|
|
442
448
|
|
|
443
449
|
"""
|
|
444
450
|
return {"type": message.type, "data": message.model_dump()}
|
|
@@ -448,7 +454,7 @@ def messages_to_dict(messages: Sequence[BaseMessage]) -> list[dict]:
|
|
|
448
454
|
"""Convert a sequence of Messages to a list of dictionaries.
|
|
449
455
|
|
|
450
456
|
Args:
|
|
451
|
-
messages: Sequence of messages (as
|
|
457
|
+
messages: Sequence of messages (as `BaseMessage`s) to convert.
|
|
452
458
|
|
|
453
459
|
Returns:
|
|
454
460
|
List of messages as dicts.
|
|
@@ -462,7 +468,7 @@ def get_msg_title_repr(title: str, *, bold: bool = False) -> str:
|
|
|
462
468
|
|
|
463
469
|
Args:
|
|
464
470
|
title: The title.
|
|
465
|
-
bold: Whether to bold the title.
|
|
471
|
+
bold: Whether to bold the title.
|
|
466
472
|
|
|
467
473
|
Returns:
|
|
468
474
|
The title representation.
|
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
"""Derivations of standard content blocks from provider content.
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
`AIMessage` will first attempt to use a provider-specific translator if
|
|
4
|
+
`model_provider` is set in `response_metadata` on the message. Consequently, each
|
|
5
5
|
provider translator must handle all possible content response types from the provider,
|
|
6
6
|
including text.
|
|
7
7
|
|
|
8
8
|
If no provider is set, or if the provider does not have a registered translator,
|
|
9
|
-
|
|
10
|
-
the implementation in
|
|
9
|
+
`AIMessage` will fall back to best-effort parsing of the content into blocks using
|
|
10
|
+
the implementation in `BaseMessage`.
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
from __future__ import annotations
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from collections.abc import Callable
|
|
16
|
+
from typing import TYPE_CHECKING
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
18
19
|
from langchain_core.messages import AIMessage, AIMessageChunk
|
|
@@ -20,6 +21,18 @@ if TYPE_CHECKING:
|
|
|
20
21
|
|
|
21
22
|
# Provider to translator mapping
|
|
22
23
|
PROVIDER_TRANSLATORS: dict[str, dict[str, Callable[..., list[types.ContentBlock]]]] = {}
|
|
24
|
+
"""Map model provider names to translator functions.
|
|
25
|
+
|
|
26
|
+
The dictionary maps provider names (e.g. `'openai'`, `'anthropic'`) to another
|
|
27
|
+
dictionary with two keys:
|
|
28
|
+
- `'translate_content'`: Function to translate `AIMessage` content.
|
|
29
|
+
- `'translate_content_chunk'`: Function to translate `AIMessageChunk` content.
|
|
30
|
+
|
|
31
|
+
When calling `content_blocks` on an `AIMessage` or `AIMessageChunk`, if
|
|
32
|
+
`model_provider` is set in `response_metadata`, the corresponding translator
|
|
33
|
+
functions will be used to parse the content into blocks. Otherwise, best-effort parsing
|
|
34
|
+
in `BaseMessage` will be used.
|
|
35
|
+
"""
|
|
23
36
|
|
|
24
37
|
|
|
25
38
|
def register_translator(
|
|
@@ -27,12 +40,12 @@ def register_translator(
|
|
|
27
40
|
translate_content: Callable[[AIMessage], list[types.ContentBlock]],
|
|
28
41
|
translate_content_chunk: Callable[[AIMessageChunk], list[types.ContentBlock]],
|
|
29
42
|
) -> None:
|
|
30
|
-
"""Register content translators for a provider
|
|
43
|
+
"""Register content translators for a provider in `PROVIDER_TRANSLATORS`.
|
|
31
44
|
|
|
32
45
|
Args:
|
|
33
|
-
provider: The model provider name (e.g.
|
|
34
|
-
translate_content: Function to translate
|
|
35
|
-
translate_content_chunk: Function to translate
|
|
46
|
+
provider: The model provider name (e.g. `'openai'`, `'anthropic'`).
|
|
47
|
+
translate_content: Function to translate `AIMessage` content.
|
|
48
|
+
translate_content_chunk: Function to translate `AIMessageChunk` content.
|
|
36
49
|
"""
|
|
37
50
|
PROVIDER_TRANSLATORS[provider] = {
|
|
38
51
|
"translate_content": translate_content,
|
|
@@ -49,8 +62,9 @@ def get_translator(
|
|
|
49
62
|
provider: The model provider name.
|
|
50
63
|
|
|
51
64
|
Returns:
|
|
52
|
-
Dictionary with
|
|
53
|
-
functions, or None if no translator is registered for the provider.
|
|
65
|
+
Dictionary with `'translate_content'` and `'translate_content_chunk'`
|
|
66
|
+
functions, or None if no translator is registered for the provider. In such
|
|
67
|
+
case, best-effort parsing in `BaseMessage` will be used.
|
|
54
68
|
"""
|
|
55
69
|
return PROVIDER_TRANSLATORS.get(provider)
|
|
56
70
|
|
|
@@ -58,10 +72,10 @@ def get_translator(
|
|
|
58
72
|
def _register_translators() -> None:
|
|
59
73
|
"""Register all translators in langchain-core.
|
|
60
74
|
|
|
61
|
-
A unit test ensures all modules in
|
|
75
|
+
A unit test ensures all modules in `block_translators` are represented here.
|
|
62
76
|
|
|
63
77
|
For translators implemented outside langchain-core, they can be registered by
|
|
64
|
-
calling
|
|
78
|
+
calling `register_translator` from within the integration package.
|
|
65
79
|
"""
|
|
66
80
|
from langchain_core.messages.block_translators.anthropic import ( # noqa: PLC0415
|
|
67
81
|
_register_anthropic_translator,
|
|
@@ -81,9 +95,6 @@ def _register_translators() -> None:
|
|
|
81
95
|
from langchain_core.messages.block_translators.groq import ( # noqa: PLC0415
|
|
82
96
|
_register_groq_translator,
|
|
83
97
|
)
|
|
84
|
-
from langchain_core.messages.block_translators.ollama import ( # noqa: PLC0415
|
|
85
|
-
_register_ollama_translator,
|
|
86
|
-
)
|
|
87
98
|
from langchain_core.messages.block_translators.openai import ( # noqa: PLC0415
|
|
88
99
|
_register_openai_translator,
|
|
89
100
|
)
|
|
@@ -94,7 +105,6 @@ def _register_translators() -> None:
|
|
|
94
105
|
_register_google_genai_translator()
|
|
95
106
|
_register_google_vertexai_translator()
|
|
96
107
|
_register_groq_translator()
|
|
97
|
-
_register_ollama_translator()
|
|
98
108
|
_register_openai_translator()
|
|
99
109
|
|
|
100
110
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
4
|
from collections.abc import Iterable
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, cast
|
|
6
6
|
|
|
7
7
|
from langchain_core.messages import AIMessage, AIMessageChunk
|
|
8
8
|
from langchain_core.messages import content as types
|
|
@@ -31,12 +31,12 @@ def _convert_to_v1_from_anthropic_input(
|
|
|
31
31
|
) -> list[types.ContentBlock]:
|
|
32
32
|
"""Convert Anthropic format blocks to v1 format.
|
|
33
33
|
|
|
34
|
-
During the
|
|
35
|
-
block as a
|
|
34
|
+
During the `content_blocks` parsing process, we wrap blocks not recognized as a v1
|
|
35
|
+
block as a `'non_standard'` block with the original block stored in the `value`
|
|
36
36
|
field. This function attempts to unpack those blocks and convert any blocks that
|
|
37
37
|
might be Anthropic format to v1 ContentBlocks.
|
|
38
38
|
|
|
39
|
-
If conversion fails, the block is left as a
|
|
39
|
+
If conversion fails, the block is left as a `'non_standard'` block.
|
|
40
40
|
|
|
41
41
|
Args:
|
|
42
42
|
content: List of content blocks to process.
|
|
@@ -200,7 +200,7 @@ def _convert_citation_to_v1(citation: dict[str, Any]) -> types.Annotation:
|
|
|
200
200
|
def _convert_to_v1_from_anthropic(message: AIMessage) -> list[types.ContentBlock]:
|
|
201
201
|
"""Convert Anthropic message content to v1 format."""
|
|
202
202
|
if isinstance(message.content, str):
|
|
203
|
-
content: list[
|
|
203
|
+
content: list[str | dict] = [{"type": "text", "text": message.content}]
|
|
204
204
|
else:
|
|
205
205
|
content = message.content
|
|
206
206
|
|
|
@@ -252,7 +252,7 @@ def _convert_to_v1_from_anthropic(message: AIMessage) -> list[types.ContentBlock
|
|
|
252
252
|
tool_call_chunk["type"] = "tool_call_chunk"
|
|
253
253
|
yield tool_call_chunk
|
|
254
254
|
else:
|
|
255
|
-
tool_call_block:
|
|
255
|
+
tool_call_block: types.ToolCall | None = None
|
|
256
256
|
# Non-streaming or gathered chunk
|
|
257
257
|
if len(message.tool_calls) == 1:
|
|
258
258
|
tool_call_block = {
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import base64
|
|
4
4
|
from collections.abc import Iterable
|
|
5
|
-
from typing import Any,
|
|
5
|
+
from typing import Any, cast
|
|
6
6
|
|
|
7
7
|
from langchain_core.messages import AIMessage, AIMessageChunk
|
|
8
8
|
from langchain_core.messages import content as types
|
|
@@ -35,12 +35,12 @@ def _convert_to_v1_from_converse_input(
|
|
|
35
35
|
) -> list[types.ContentBlock]:
|
|
36
36
|
"""Convert Bedrock Converse format blocks to v1 format.
|
|
37
37
|
|
|
38
|
-
During the
|
|
39
|
-
block as a
|
|
38
|
+
During the `content_blocks` parsing process, we wrap blocks not recognized as a v1
|
|
39
|
+
block as a `'non_standard'` block with the original block stored in the `value`
|
|
40
40
|
field. This function attempts to unpack those blocks and convert any blocks that
|
|
41
41
|
might be Converse format to v1 ContentBlocks.
|
|
42
42
|
|
|
43
|
-
If conversion fails, the block is left as a
|
|
43
|
+
If conversion fails, the block is left as a `'non_standard'` block.
|
|
44
44
|
|
|
45
45
|
Args:
|
|
46
46
|
content: List of content blocks to process.
|
|
@@ -216,7 +216,7 @@ def _convert_to_v1_from_converse(message: AIMessage) -> list[types.ContentBlock]
|
|
|
216
216
|
tool_call_chunk["type"] = "tool_call_chunk"
|
|
217
217
|
yield tool_call_chunk
|
|
218
218
|
else:
|
|
219
|
-
tool_call_block:
|
|
219
|
+
tool_call_block: types.ToolCall | None = None
|
|
220
220
|
# Non-streaming or gathered chunk
|
|
221
221
|
if len(message.tool_calls) == 1:
|
|
222
222
|
tool_call_block = {
|