langchain-core 1.0.0a4__py3-none-any.whl → 1.0.0a6__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/_api/beta_decorator.py +6 -5
- langchain_core/_api/deprecation.py +11 -11
- langchain_core/callbacks/manager.py +2 -2
- langchain_core/callbacks/usage.py +2 -2
- langchain_core/document_loaders/langsmith.py +1 -1
- langchain_core/indexing/api.py +30 -30
- langchain_core/language_models/chat_models.py +1 -1
- langchain_core/language_models/fake_chat_models.py +5 -2
- langchain_core/load/serializable.py +1 -1
- langchain_core/messages/__init__.py +9 -15
- langchain_core/messages/ai.py +75 -9
- langchain_core/messages/base.py +79 -37
- langchain_core/messages/block_translators/__init__.py +26 -3
- langchain_core/messages/block_translators/anthropic.py +143 -128
- langchain_core/messages/block_translators/bedrock_converse.py +15 -1
- langchain_core/messages/block_translators/google_genai.py +502 -20
- langchain_core/messages/block_translators/langchain_v0.py +180 -43
- langchain_core/messages/block_translators/openai.py +224 -42
- langchain_core/messages/chat.py +4 -1
- langchain_core/messages/content.py +56 -112
- langchain_core/messages/function.py +9 -5
- langchain_core/messages/human.py +6 -2
- langchain_core/messages/modifier.py +1 -0
- langchain_core/messages/system.py +9 -2
- langchain_core/messages/tool.py +31 -14
- langchain_core/messages/utils.py +89 -83
- langchain_core/outputs/chat_generation.py +10 -6
- langchain_core/prompt_values.py +6 -2
- langchain_core/prompts/chat.py +6 -3
- langchain_core/prompts/few_shot.py +4 -1
- langchain_core/runnables/base.py +14 -13
- langchain_core/runnables/graph_ascii.py +1 -1
- langchain_core/tools/base.py +2 -2
- langchain_core/tools/convert.py +1 -1
- langchain_core/utils/aiter.py +1 -1
- langchain_core/utils/function_calling.py +5 -6
- langchain_core/utils/iter.py +1 -1
- langchain_core/vectorstores/in_memory.py +5 -5
- langchain_core/version.py +1 -1
- {langchain_core-1.0.0a4.dist-info → langchain_core-1.0.0a6.dist-info}/METADATA +8 -18
- {langchain_core-1.0.0a4.dist-info → langchain_core-1.0.0a6.dist-info}/RECORD +43 -43
- {langchain_core-1.0.0a4.dist-info → langchain_core-1.0.0a6.dist-info}/WHEEL +0 -0
- {langchain_core-1.0.0a4.dist-info → langchain_core-1.0.0a6.dist-info}/entry_points.txt +0 -0
|
@@ -174,6 +174,7 @@ def beta(
|
|
|
174
174
|
def finalize(_wrapper: Callable[..., Any], new_doc: str) -> Any:
|
|
175
175
|
"""Finalize the property."""
|
|
176
176
|
return property(fget=_fget, fset=_fset, fdel=_fdel, doc=new_doc)
|
|
177
|
+
|
|
177
178
|
else:
|
|
178
179
|
_name = _name or obj.__qualname__
|
|
179
180
|
if not _obj_type:
|
|
@@ -226,17 +227,17 @@ def warn_beta(
|
|
|
226
227
|
) -> None:
|
|
227
228
|
"""Display a standardized beta annotation.
|
|
228
229
|
|
|
229
|
-
|
|
230
|
-
message
|
|
230
|
+
Args:
|
|
231
|
+
message:
|
|
231
232
|
Override the default beta message. The
|
|
232
233
|
%(name)s, %(obj_type)s, %(addendum)s
|
|
233
234
|
format specifiers will be replaced by the
|
|
234
235
|
values of the respective arguments passed to this function.
|
|
235
|
-
name
|
|
236
|
+
name:
|
|
236
237
|
The name of the annotated object.
|
|
237
|
-
obj_type
|
|
238
|
+
obj_type:
|
|
238
239
|
The object type being annotated.
|
|
239
|
-
addendum
|
|
240
|
+
addendum:
|
|
240
241
|
Additional text appended directly to the final message.
|
|
241
242
|
"""
|
|
242
243
|
if not message:
|
|
@@ -431,35 +431,35 @@ def warn_deprecated(
|
|
|
431
431
|
) -> None:
|
|
432
432
|
"""Display a standardized deprecation.
|
|
433
433
|
|
|
434
|
-
|
|
435
|
-
since
|
|
434
|
+
Args:
|
|
435
|
+
since:
|
|
436
436
|
The release at which this API became deprecated.
|
|
437
|
-
message
|
|
437
|
+
message:
|
|
438
438
|
Override the default deprecation message. The %(since)s,
|
|
439
439
|
%(name)s, %(alternative)s, %(obj_type)s, %(addendum)s,
|
|
440
440
|
and %(removal)s format specifiers will be replaced by the
|
|
441
441
|
values of the respective arguments passed to this function.
|
|
442
|
-
name
|
|
442
|
+
name:
|
|
443
443
|
The name of the deprecated object.
|
|
444
|
-
alternative
|
|
444
|
+
alternative:
|
|
445
445
|
An alternative API that the user may use in place of the
|
|
446
446
|
deprecated API. The deprecation warning will tell the user
|
|
447
447
|
about this alternative if provided.
|
|
448
|
-
alternative_import:
|
|
448
|
+
alternative_import:
|
|
449
449
|
An alternative import that the user may use instead.
|
|
450
|
-
pending
|
|
450
|
+
pending:
|
|
451
451
|
If True, uses a PendingDeprecationWarning instead of a
|
|
452
452
|
DeprecationWarning. Cannot be used together with removal.
|
|
453
|
-
obj_type
|
|
453
|
+
obj_type:
|
|
454
454
|
The object type being deprecated.
|
|
455
|
-
addendum
|
|
455
|
+
addendum:
|
|
456
456
|
Additional text appended directly to the final message.
|
|
457
|
-
removal
|
|
457
|
+
removal:
|
|
458
458
|
The expected removal version. With the default (an empty
|
|
459
459
|
string), a removal version is automatically computed from
|
|
460
460
|
since. Set to other Falsy values to not schedule a removal
|
|
461
461
|
date. Cannot be used together with pending.
|
|
462
|
-
package:
|
|
462
|
+
package:
|
|
463
463
|
The package of the deprecated object.
|
|
464
464
|
"""
|
|
465
465
|
if not pending:
|
|
@@ -92,7 +92,7 @@ def trace_as_chain_group(
|
|
|
92
92
|
metadata (dict[str, Any], optional): The metadata to apply to all runs.
|
|
93
93
|
Defaults to None.
|
|
94
94
|
|
|
95
|
-
.. note
|
|
95
|
+
.. note::
|
|
96
96
|
Must have ``LANGCHAIN_TRACING_V2`` env var set to true to see the trace in
|
|
97
97
|
LangSmith.
|
|
98
98
|
|
|
@@ -179,7 +179,7 @@ async def atrace_as_chain_group(
|
|
|
179
179
|
Yields:
|
|
180
180
|
The async callback manager for the chain group.
|
|
181
181
|
|
|
182
|
-
.. note
|
|
182
|
+
.. note::
|
|
183
183
|
Must have ``LANGCHAIN_TRACING_V2`` env var set to true to see the trace in
|
|
184
184
|
LangSmith.
|
|
185
185
|
|
|
@@ -32,7 +32,7 @@ class UsageMetadataCallbackHandler(BaseCallbackHandler):
|
|
|
32
32
|
result_2 = llm_2.invoke("Hello", config={"callbacks": [callback]})
|
|
33
33
|
callback.usage_metadata
|
|
34
34
|
|
|
35
|
-
.. code-block::
|
|
35
|
+
.. code-block::
|
|
36
36
|
|
|
37
37
|
{'gpt-4o-mini-2024-07-18': {'input_tokens': 8,
|
|
38
38
|
'output_tokens': 10,
|
|
@@ -119,7 +119,7 @@ def get_usage_metadata_callback(
|
|
|
119
119
|
llm_2.invoke("Hello")
|
|
120
120
|
print(cb.usage_metadata)
|
|
121
121
|
|
|
122
|
-
.. code-block::
|
|
122
|
+
.. code-block::
|
|
123
123
|
|
|
124
124
|
{'gpt-4o-mini-2024-07-18': {'input_tokens': 8,
|
|
125
125
|
'output_tokens': 10,
|
langchain_core/indexing/api.py
CHANGED
|
@@ -296,7 +296,11 @@ def index(
|
|
|
296
296
|
For the time being, documents are indexed using their hashes, and users
|
|
297
297
|
are not able to specify the uid of the document.
|
|
298
298
|
|
|
299
|
-
|
|
299
|
+
.. versionchanged:: 0.3.25
|
|
300
|
+
Added ``scoped_full`` cleanup mode.
|
|
301
|
+
|
|
302
|
+
.. important::
|
|
303
|
+
|
|
300
304
|
* In full mode, the loader should be returning
|
|
301
305
|
the entire dataset, and not just a subset of the dataset.
|
|
302
306
|
Otherwise, the auto_cleanup will remove documents that it is not
|
|
@@ -309,7 +313,7 @@ def index(
|
|
|
309
313
|
chunks, and we index them using a batch size of 5, we'll have 3 batches
|
|
310
314
|
all with the same source id. In general, to avoid doing too much
|
|
311
315
|
redundant work select as big a batch size as possible.
|
|
312
|
-
* The
|
|
316
|
+
* The ``scoped_full`` mode is suitable if determining an appropriate batch size
|
|
313
317
|
is challenging or if your data loader cannot return the entire dataset at
|
|
314
318
|
once. This mode keeps track of source IDs in memory, which should be fine
|
|
315
319
|
for most use cases. If your dataset is large (10M+ docs), you will likely
|
|
@@ -378,10 +382,6 @@ def index(
|
|
|
378
382
|
TypeError: If ``vectorstore`` is not a VectorStore or a DocumentIndex.
|
|
379
383
|
AssertionError: If ``source_id`` is None when cleanup mode is incremental.
|
|
380
384
|
(should be unreachable code).
|
|
381
|
-
|
|
382
|
-
.. version_modified:: 0.3.25
|
|
383
|
-
|
|
384
|
-
* Added `scoped_full` cleanup mode.
|
|
385
385
|
"""
|
|
386
386
|
# Behavior is deprecated, but we keep it for backwards compatibility.
|
|
387
387
|
# # Warn only once per process.
|
|
@@ -636,26 +636,30 @@ async def aindex(
|
|
|
636
636
|
documents were deleted, which documents should be skipped.
|
|
637
637
|
|
|
638
638
|
For the time being, documents are indexed using their hashes, and users
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
639
|
+
are not able to specify the uid of the document.
|
|
640
|
+
|
|
641
|
+
.. versionchanged:: 0.3.25
|
|
642
|
+
Added ``scoped_full`` cleanup mode.
|
|
643
|
+
|
|
644
|
+
.. important::
|
|
645
|
+
|
|
646
|
+
* In full mode, the loader should be returning
|
|
647
|
+
the entire dataset, and not just a subset of the dataset.
|
|
648
|
+
Otherwise, the auto_cleanup will remove documents that it is not
|
|
649
|
+
supposed to.
|
|
650
|
+
* In incremental mode, if documents associated with a particular
|
|
651
|
+
source id appear across different batches, the indexing API
|
|
652
|
+
will do some redundant work. This will still result in the
|
|
653
|
+
correct end state of the index, but will unfortunately not be
|
|
654
|
+
100% efficient. For example, if a given document is split into 15
|
|
655
|
+
chunks, and we index them using a batch size of 5, we'll have 3 batches
|
|
656
|
+
all with the same source id. In general, to avoid doing too much
|
|
657
|
+
redundant work select as big a batch size as possible.
|
|
658
|
+
* The ``scoped_full`` mode is suitable if determining an appropriate batch size
|
|
659
|
+
is challenging or if your data loader cannot return the entire dataset at
|
|
660
|
+
once. This mode keeps track of source IDs in memory, which should be fine
|
|
661
|
+
for most use cases. If your dataset is large (10M+ docs), you will likely
|
|
662
|
+
need to parallelize the indexing process regardless.
|
|
659
663
|
|
|
660
664
|
Args:
|
|
661
665
|
docs_source: Data loader or iterable of documents to index.
|
|
@@ -720,10 +724,6 @@ async def aindex(
|
|
|
720
724
|
TypeError: If ``vector_store`` is not a VectorStore or DocumentIndex.
|
|
721
725
|
AssertionError: If ``source_id_key`` is None when cleanup mode is
|
|
722
726
|
incremental or ``scoped_full`` (should be unreachable).
|
|
723
|
-
|
|
724
|
-
.. version_modified:: 0.3.25
|
|
725
|
-
|
|
726
|
-
* Added `scoped_full` cleanup mode.
|
|
727
727
|
"""
|
|
728
728
|
# Behavior is deprecated, but we keep it for backwards compatibility.
|
|
729
729
|
# # Warn only once per process.
|
|
@@ -519,7 +519,7 @@ class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
|
|
|
519
519
|
**kwargs: Any,
|
|
520
520
|
) -> Iterator[AIMessageChunk]:
|
|
521
521
|
if not self._should_stream(async_api=False, **{**kwargs, "stream": True}):
|
|
522
|
-
#
|
|
522
|
+
# Model doesn't implement streaming, so use default implementation
|
|
523
523
|
yield cast(
|
|
524
524
|
"AIMessageChunk",
|
|
525
525
|
self.invoke(input, config=config, stop=stop, **kwargs),
|
|
@@ -19,7 +19,7 @@ from langchain_core.runnables import RunnableConfig
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class FakeMessagesListChatModel(BaseChatModel):
|
|
22
|
-
"""Fake ChatModel for testing purposes."""
|
|
22
|
+
"""Fake ``ChatModel`` for testing purposes."""
|
|
23
23
|
|
|
24
24
|
responses: list[BaseMessage]
|
|
25
25
|
"""List of responses to **cycle** through in order."""
|
|
@@ -222,10 +222,11 @@ class GenericFakeChatModel(BaseChatModel):
|
|
|
222
222
|
"""Generic fake chat model that can be used to test the chat model interface.
|
|
223
223
|
|
|
224
224
|
* Chat model should be usable in both sync and async tests
|
|
225
|
-
* Invokes on_llm_new_token to allow for testing of callback related code for new
|
|
225
|
+
* Invokes ``on_llm_new_token`` to allow for testing of callback related code for new
|
|
226
226
|
tokens.
|
|
227
227
|
* Includes logic to break messages into message chunk to facilitate testing of
|
|
228
228
|
streaming.
|
|
229
|
+
|
|
229
230
|
"""
|
|
230
231
|
|
|
231
232
|
messages: Iterator[Union[AIMessage, str]]
|
|
@@ -240,6 +241,7 @@ class GenericFakeChatModel(BaseChatModel):
|
|
|
240
241
|
.. warning::
|
|
241
242
|
Streaming is not implemented yet. We should try to implement it in the future by
|
|
242
243
|
delegating to invoke and then breaking the resulting output into message chunks.
|
|
244
|
+
|
|
243
245
|
"""
|
|
244
246
|
|
|
245
247
|
@override
|
|
@@ -367,6 +369,7 @@ class ParrotFakeChatModel(BaseChatModel):
|
|
|
367
369
|
"""Generic fake chat model that can be used to test the chat model interface.
|
|
368
370
|
|
|
369
371
|
* Chat model should be usable in both sync and async tests
|
|
372
|
+
|
|
370
373
|
"""
|
|
371
374
|
|
|
372
375
|
@override
|
|
@@ -111,7 +111,7 @@ class Serializable(BaseModel, ABC):
|
|
|
111
111
|
|
|
112
112
|
# Remove default BaseModel init docstring.
|
|
113
113
|
def __init__(self, *args: Any, **kwargs: Any) -> None:
|
|
114
|
-
"""""" # noqa: D419
|
|
114
|
+
"""""" # noqa: D419 # Intentional blank docstring
|
|
115
115
|
super().__init__(*args, **kwargs)
|
|
116
116
|
|
|
117
117
|
@classmethod
|
|
@@ -41,9 +41,6 @@ if TYPE_CHECKING:
|
|
|
41
41
|
Annotation,
|
|
42
42
|
AudioContentBlock,
|
|
43
43
|
Citation,
|
|
44
|
-
CodeInterpreterCall,
|
|
45
|
-
CodeInterpreterOutput,
|
|
46
|
-
CodeInterpreterResult,
|
|
47
44
|
ContentBlock,
|
|
48
45
|
DataContentBlock,
|
|
49
46
|
FileContentBlock,
|
|
@@ -53,10 +50,11 @@ if TYPE_CHECKING:
|
|
|
53
50
|
NonStandardContentBlock,
|
|
54
51
|
PlainTextContentBlock,
|
|
55
52
|
ReasoningContentBlock,
|
|
53
|
+
ServerToolCall,
|
|
54
|
+
ServerToolCallChunk,
|
|
55
|
+
ServerToolResult,
|
|
56
56
|
TextContentBlock,
|
|
57
57
|
VideoContentBlock,
|
|
58
|
-
WebSearchCall,
|
|
59
|
-
WebSearchResult,
|
|
60
58
|
is_data_content_block,
|
|
61
59
|
)
|
|
62
60
|
from langchain_core.messages.function import FunctionMessage, FunctionMessageChunk
|
|
@@ -96,9 +94,6 @@ __all__ = (
|
|
|
96
94
|
"ChatMessage",
|
|
97
95
|
"ChatMessageChunk",
|
|
98
96
|
"Citation",
|
|
99
|
-
"CodeInterpreterCall",
|
|
100
|
-
"CodeInterpreterOutput",
|
|
101
|
-
"CodeInterpreterResult",
|
|
102
97
|
"ContentBlock",
|
|
103
98
|
"DataContentBlock",
|
|
104
99
|
"FileContentBlock",
|
|
@@ -114,6 +109,9 @@ __all__ = (
|
|
|
114
109
|
"PlainTextContentBlock",
|
|
115
110
|
"ReasoningContentBlock",
|
|
116
111
|
"RemoveMessage",
|
|
112
|
+
"ServerToolCall",
|
|
113
|
+
"ServerToolCallChunk",
|
|
114
|
+
"ServerToolResult",
|
|
117
115
|
"SystemMessage",
|
|
118
116
|
"SystemMessageChunk",
|
|
119
117
|
"TextContentBlock",
|
|
@@ -122,8 +120,6 @@ __all__ = (
|
|
|
122
120
|
"ToolMessage",
|
|
123
121
|
"ToolMessageChunk",
|
|
124
122
|
"VideoContentBlock",
|
|
125
|
-
"WebSearchCall",
|
|
126
|
-
"WebSearchResult",
|
|
127
123
|
"_message_from_dict",
|
|
128
124
|
"convert_to_messages",
|
|
129
125
|
"convert_to_openai_data_block",
|
|
@@ -156,9 +152,6 @@ _dynamic_imports = {
|
|
|
156
152
|
"ContentBlock": "content",
|
|
157
153
|
"ChatMessage": "chat",
|
|
158
154
|
"ChatMessageChunk": "chat",
|
|
159
|
-
"CodeInterpreterCall": "content",
|
|
160
|
-
"CodeInterpreterOutput": "content",
|
|
161
|
-
"CodeInterpreterResult": "content",
|
|
162
155
|
"DataContentBlock": "content",
|
|
163
156
|
"FileContentBlock": "content",
|
|
164
157
|
"FunctionMessage": "function",
|
|
@@ -170,10 +163,11 @@ _dynamic_imports = {
|
|
|
170
163
|
"PlainTextContentBlock": "content",
|
|
171
164
|
"ReasoningContentBlock": "content",
|
|
172
165
|
"RemoveMessage": "modifier",
|
|
166
|
+
"ServerToolCall": "content",
|
|
167
|
+
"ServerToolCallChunk": "content",
|
|
168
|
+
"ServerToolResult": "content",
|
|
173
169
|
"SystemMessage": "system",
|
|
174
170
|
"SystemMessageChunk": "system",
|
|
175
|
-
"WebSearchCall": "content",
|
|
176
|
-
"WebSearchResult": "content",
|
|
177
171
|
"ImageContentBlock": "content",
|
|
178
172
|
"InvalidToolCall": "tool",
|
|
179
173
|
"TextContentBlock": "content",
|
langchain_core/messages/ai.py
CHANGED
|
@@ -13,6 +13,7 @@ from langchain_core.messages import content as types
|
|
|
13
13
|
from langchain_core.messages.base import (
|
|
14
14
|
BaseMessage,
|
|
15
15
|
BaseMessageChunk,
|
|
16
|
+
_extract_reasoning_from_additional_kwargs,
|
|
16
17
|
merge_content,
|
|
17
18
|
)
|
|
18
19
|
from langchain_core.messages.content import InvalidToolCall
|
|
@@ -39,7 +40,6 @@ class InputTokenDetails(TypedDict, total=False):
|
|
|
39
40
|
Does *not* need to sum to full input token count. Does *not* need to have all keys.
|
|
40
41
|
|
|
41
42
|
Example:
|
|
42
|
-
|
|
43
43
|
.. code-block:: python
|
|
44
44
|
|
|
45
45
|
{
|
|
@@ -66,6 +66,7 @@ class InputTokenDetails(TypedDict, total=False):
|
|
|
66
66
|
|
|
67
67
|
Since there was a cache hit, the tokens were read from the cache. More precisely,
|
|
68
68
|
the model state given these tokens was read from the cache.
|
|
69
|
+
|
|
69
70
|
"""
|
|
70
71
|
|
|
71
72
|
|
|
@@ -75,7 +76,6 @@ class OutputTokenDetails(TypedDict, total=False):
|
|
|
75
76
|
Does *not* need to sum to full output token count. Does *not* need to have all keys.
|
|
76
77
|
|
|
77
78
|
Example:
|
|
78
|
-
|
|
79
79
|
.. code-block:: python
|
|
80
80
|
|
|
81
81
|
{
|
|
@@ -94,6 +94,7 @@ class OutputTokenDetails(TypedDict, total=False):
|
|
|
94
94
|
|
|
95
95
|
Tokens generated by the model in a chain of thought process (i.e. by OpenAI's o1
|
|
96
96
|
models) that are not returned as part of model output.
|
|
97
|
+
|
|
97
98
|
"""
|
|
98
99
|
|
|
99
100
|
|
|
@@ -103,7 +104,6 @@ class UsageMetadata(TypedDict):
|
|
|
103
104
|
This is a standard representation of token usage that is consistent across models.
|
|
104
105
|
|
|
105
106
|
Example:
|
|
106
|
-
|
|
107
107
|
.. code-block:: python
|
|
108
108
|
|
|
109
109
|
{
|
|
@@ -142,6 +142,7 @@ class UsageMetadata(TypedDict):
|
|
|
142
142
|
"""Breakdown of output token counts.
|
|
143
143
|
|
|
144
144
|
Does *not* need to sum to full output token count. Does *not* need to have all keys.
|
|
145
|
+
|
|
145
146
|
"""
|
|
146
147
|
|
|
147
148
|
|
|
@@ -153,6 +154,7 @@ class AIMessage(BaseMessage):
|
|
|
153
154
|
This message represents the output of the model and consists of both
|
|
154
155
|
the raw output as returned by the model together standardized fields
|
|
155
156
|
(e.g., tool calls, usage metadata) added by the LangChain framework.
|
|
157
|
+
|
|
156
158
|
"""
|
|
157
159
|
|
|
158
160
|
tool_calls: list[ToolCall] = []
|
|
@@ -163,6 +165,7 @@ class AIMessage(BaseMessage):
|
|
|
163
165
|
"""If provided, usage metadata for a message, such as token counts.
|
|
164
166
|
|
|
165
167
|
This is a standard representation of token usage that is consistent across models.
|
|
168
|
+
|
|
166
169
|
"""
|
|
167
170
|
|
|
168
171
|
type: Literal["ai"] = "ai"
|
|
@@ -189,7 +192,15 @@ class AIMessage(BaseMessage):
|
|
|
189
192
|
content_blocks: Optional[list[types.ContentBlock]] = None,
|
|
190
193
|
**kwargs: Any,
|
|
191
194
|
) -> None:
|
|
192
|
-
"""
|
|
195
|
+
"""Initialize ``AIMessage``.
|
|
196
|
+
|
|
197
|
+
Specify ``content`` as positional arg or ``content_blocks`` for typing.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
content: The content of the message.
|
|
201
|
+
content_blocks: Typed standard content.
|
|
202
|
+
kwargs: Additional arguments to pass to the parent class.
|
|
203
|
+
"""
|
|
193
204
|
if content_blocks is not None:
|
|
194
205
|
# If there are tool calls in content_blocks, but not in tool_calls, add them
|
|
195
206
|
content_tool_calls = [
|
|
@@ -215,7 +226,12 @@ class AIMessage(BaseMessage):
|
|
|
215
226
|
|
|
216
227
|
@property
|
|
217
228
|
def content_blocks(self) -> list[types.ContentBlock]:
|
|
218
|
-
"""Return content blocks of the message.
|
|
229
|
+
"""Return content blocks of the message.
|
|
230
|
+
|
|
231
|
+
If the message has a known model provider, use the provider-specific translator
|
|
232
|
+
first before falling back to best-effort parsing. For details, see the property
|
|
233
|
+
on ``BaseMessage``.
|
|
234
|
+
"""
|
|
219
235
|
if self.response_metadata.get("output_version") == "v1":
|
|
220
236
|
return cast("list[types.ContentBlock]", self.content)
|
|
221
237
|
|
|
@@ -256,6 +272,15 @@ class AIMessage(BaseMessage):
|
|
|
256
272
|
tool_call_block["extras"] = tool_call["extras"] # type: ignore[typeddict-item]
|
|
257
273
|
blocks.append(tool_call_block)
|
|
258
274
|
|
|
275
|
+
# Best-effort reasoning extraction from additional_kwargs
|
|
276
|
+
# Only add reasoning if not already present
|
|
277
|
+
# Insert before all other blocks to keep reasoning at the start
|
|
278
|
+
has_reasoning = any(block.get("type") == "reasoning" for block in blocks)
|
|
279
|
+
if not has_reasoning and (
|
|
280
|
+
reasoning_block := _extract_reasoning_from_additional_kwargs(self)
|
|
281
|
+
):
|
|
282
|
+
blocks.insert(0, reasoning_block)
|
|
283
|
+
|
|
259
284
|
return blocks
|
|
260
285
|
|
|
261
286
|
# TODO: remove this logic if possible, reducing breaking nature of changes
|
|
@@ -315,6 +340,7 @@ class AIMessage(BaseMessage):
|
|
|
315
340
|
|
|
316
341
|
Returns:
|
|
317
342
|
A pretty representation of the message.
|
|
343
|
+
|
|
318
344
|
"""
|
|
319
345
|
base = super().pretty_repr(html=html)
|
|
320
346
|
lines = []
|
|
@@ -354,7 +380,10 @@ class AIMessageChunk(AIMessage, BaseMessageChunk):
|
|
|
354
380
|
# non-chunk variant.
|
|
355
381
|
type: Literal["AIMessageChunk"] = "AIMessageChunk" # type: ignore[assignment]
|
|
356
382
|
"""The type of the message (used for deserialization).
|
|
357
|
-
|
|
383
|
+
|
|
384
|
+
Defaults to ``AIMessageChunk``.
|
|
385
|
+
|
|
386
|
+
"""
|
|
358
387
|
|
|
359
388
|
tool_call_chunks: list[ToolCallChunk] = []
|
|
360
389
|
"""If provided, tool call chunks associated with the message."""
|
|
@@ -417,6 +446,15 @@ class AIMessageChunk(AIMessage, BaseMessageChunk):
|
|
|
417
446
|
tc["index"] = idx
|
|
418
447
|
blocks.append(tc)
|
|
419
448
|
|
|
449
|
+
# Best-effort reasoning extraction from additional_kwargs
|
|
450
|
+
# Only add reasoning if not already present
|
|
451
|
+
# Insert before all other blocks to keep reasoning at the start
|
|
452
|
+
has_reasoning = any(block.get("type") == "reasoning" for block in blocks)
|
|
453
|
+
if not has_reasoning and (
|
|
454
|
+
reasoning_block := _extract_reasoning_from_additional_kwargs(self)
|
|
455
|
+
):
|
|
456
|
+
blocks.insert(0, reasoning_block)
|
|
457
|
+
|
|
420
458
|
return blocks
|
|
421
459
|
|
|
422
460
|
@model_validator(mode="after")
|
|
@@ -424,7 +462,10 @@ class AIMessageChunk(AIMessage, BaseMessageChunk):
|
|
|
424
462
|
"""Initialize tool calls from tool call chunks.
|
|
425
463
|
|
|
426
464
|
Returns:
|
|
427
|
-
|
|
465
|
+
The values with tool calls initialized.
|
|
466
|
+
|
|
467
|
+
Raises:
|
|
468
|
+
ValueError: If the tool call chunks are malformed.
|
|
428
469
|
"""
|
|
429
470
|
if not self.tool_call_chunks:
|
|
430
471
|
if self.tool_calls:
|
|
@@ -508,6 +549,31 @@ class AIMessageChunk(AIMessage, BaseMessageChunk):
|
|
|
508
549
|
|
|
509
550
|
return self
|
|
510
551
|
|
|
552
|
+
@model_validator(mode="after")
|
|
553
|
+
def init_server_tool_calls(self) -> Self:
|
|
554
|
+
"""Parse server_tool_call_chunks."""
|
|
555
|
+
if (
|
|
556
|
+
self.chunk_position == "last"
|
|
557
|
+
and self.response_metadata.get("output_version") == "v1"
|
|
558
|
+
and isinstance(self.content, list)
|
|
559
|
+
):
|
|
560
|
+
for idx, block in enumerate(self.content):
|
|
561
|
+
if (
|
|
562
|
+
isinstance(block, dict)
|
|
563
|
+
and block.get("type")
|
|
564
|
+
in ("server_tool_call", "server_tool_call_chunk")
|
|
565
|
+
and (args_str := block.get("args"))
|
|
566
|
+
and isinstance(args_str, str)
|
|
567
|
+
):
|
|
568
|
+
try:
|
|
569
|
+
args = json.loads(args_str)
|
|
570
|
+
if isinstance(args, dict):
|
|
571
|
+
self.content[idx]["type"] = "server_tool_call" # type: ignore[index]
|
|
572
|
+
self.content[idx]["args"] = args # type: ignore[index]
|
|
573
|
+
except json.JSONDecodeError:
|
|
574
|
+
pass
|
|
575
|
+
return self
|
|
576
|
+
|
|
511
577
|
@overload # type: ignore[override] # summing BaseMessages gives ChatPromptTemplate
|
|
512
578
|
def __add__(self, other: "AIMessageChunk") -> "AIMessageChunk": ...
|
|
513
579
|
|
|
@@ -677,9 +743,9 @@ def add_usage(
|
|
|
677
743
|
def subtract_usage(
|
|
678
744
|
left: Optional[UsageMetadata], right: Optional[UsageMetadata]
|
|
679
745
|
) -> UsageMetadata:
|
|
680
|
-
"""Recursively subtract two UsageMetadata objects.
|
|
746
|
+
"""Recursively subtract two ``UsageMetadata`` objects.
|
|
681
747
|
|
|
682
|
-
Token counts cannot be negative so the actual operation is max(left - right, 0)
|
|
748
|
+
Token counts cannot be negative so the actual operation is ``max(left - right, 0)``.
|
|
683
749
|
|
|
684
750
|
Example:
|
|
685
751
|
.. code-block:: python
|