langchain-core 0.3.79__py3-none-any.whl → 1.0.0__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.

Potentially problematic release.


This version of langchain-core might be problematic. Click here for more details.

Files changed (165) hide show
  1. langchain_core/__init__.py +1 -1
  2. langchain_core/_api/__init__.py +3 -4
  3. langchain_core/_api/beta_decorator.py +23 -26
  4. langchain_core/_api/deprecation.py +52 -65
  5. langchain_core/_api/path.py +3 -6
  6. langchain_core/_import_utils.py +3 -4
  7. langchain_core/agents.py +19 -19
  8. langchain_core/caches.py +53 -63
  9. langchain_core/callbacks/__init__.py +1 -8
  10. langchain_core/callbacks/base.py +323 -334
  11. langchain_core/callbacks/file.py +44 -44
  12. langchain_core/callbacks/manager.py +441 -507
  13. langchain_core/callbacks/stdout.py +29 -30
  14. langchain_core/callbacks/streaming_stdout.py +32 -32
  15. langchain_core/callbacks/usage.py +60 -57
  16. langchain_core/chat_history.py +48 -63
  17. langchain_core/document_loaders/base.py +23 -23
  18. langchain_core/document_loaders/langsmith.py +37 -37
  19. langchain_core/documents/__init__.py +0 -1
  20. langchain_core/documents/base.py +62 -65
  21. langchain_core/documents/compressor.py +4 -4
  22. langchain_core/documents/transformers.py +28 -29
  23. langchain_core/embeddings/fake.py +50 -54
  24. langchain_core/example_selectors/length_based.py +1 -1
  25. langchain_core/example_selectors/semantic_similarity.py +21 -25
  26. langchain_core/exceptions.py +10 -11
  27. langchain_core/globals.py +3 -151
  28. langchain_core/indexing/api.py +61 -66
  29. langchain_core/indexing/base.py +58 -58
  30. langchain_core/indexing/in_memory.py +3 -3
  31. langchain_core/language_models/__init__.py +14 -27
  32. langchain_core/language_models/_utils.py +270 -84
  33. langchain_core/language_models/base.py +55 -162
  34. langchain_core/language_models/chat_models.py +442 -402
  35. langchain_core/language_models/fake.py +11 -11
  36. langchain_core/language_models/fake_chat_models.py +61 -39
  37. langchain_core/language_models/llms.py +123 -231
  38. langchain_core/load/dump.py +4 -5
  39. langchain_core/load/load.py +18 -28
  40. langchain_core/load/mapping.py +2 -4
  41. langchain_core/load/serializable.py +39 -40
  42. langchain_core/messages/__init__.py +61 -22
  43. langchain_core/messages/ai.py +368 -163
  44. langchain_core/messages/base.py +214 -43
  45. langchain_core/messages/block_translators/__init__.py +111 -0
  46. langchain_core/messages/block_translators/anthropic.py +470 -0
  47. langchain_core/messages/block_translators/bedrock.py +94 -0
  48. langchain_core/messages/block_translators/bedrock_converse.py +297 -0
  49. langchain_core/messages/block_translators/google_genai.py +530 -0
  50. langchain_core/messages/block_translators/google_vertexai.py +21 -0
  51. langchain_core/messages/block_translators/groq.py +143 -0
  52. langchain_core/messages/block_translators/langchain_v0.py +301 -0
  53. langchain_core/messages/block_translators/openai.py +1010 -0
  54. langchain_core/messages/chat.py +2 -6
  55. langchain_core/messages/content.py +1423 -0
  56. langchain_core/messages/function.py +6 -10
  57. langchain_core/messages/human.py +41 -38
  58. langchain_core/messages/modifier.py +2 -2
  59. langchain_core/messages/system.py +38 -28
  60. langchain_core/messages/tool.py +96 -103
  61. langchain_core/messages/utils.py +478 -504
  62. langchain_core/output_parsers/__init__.py +1 -14
  63. langchain_core/output_parsers/base.py +58 -61
  64. langchain_core/output_parsers/json.py +7 -8
  65. langchain_core/output_parsers/list.py +5 -7
  66. langchain_core/output_parsers/openai_functions.py +49 -47
  67. langchain_core/output_parsers/openai_tools.py +14 -19
  68. langchain_core/output_parsers/pydantic.py +12 -13
  69. langchain_core/output_parsers/string.py +2 -2
  70. langchain_core/output_parsers/transform.py +15 -17
  71. langchain_core/output_parsers/xml.py +8 -10
  72. langchain_core/outputs/__init__.py +1 -1
  73. langchain_core/outputs/chat_generation.py +18 -18
  74. langchain_core/outputs/chat_result.py +1 -3
  75. langchain_core/outputs/generation.py +8 -8
  76. langchain_core/outputs/llm_result.py +10 -10
  77. langchain_core/prompt_values.py +12 -12
  78. langchain_core/prompts/__init__.py +3 -27
  79. langchain_core/prompts/base.py +45 -55
  80. langchain_core/prompts/chat.py +254 -313
  81. langchain_core/prompts/dict.py +5 -5
  82. langchain_core/prompts/few_shot.py +81 -88
  83. langchain_core/prompts/few_shot_with_templates.py +11 -13
  84. langchain_core/prompts/image.py +12 -14
  85. langchain_core/prompts/loading.py +6 -8
  86. langchain_core/prompts/message.py +3 -3
  87. langchain_core/prompts/prompt.py +24 -39
  88. langchain_core/prompts/string.py +4 -4
  89. langchain_core/prompts/structured.py +42 -50
  90. langchain_core/rate_limiters.py +51 -60
  91. langchain_core/retrievers.py +49 -190
  92. langchain_core/runnables/base.py +1484 -1709
  93. langchain_core/runnables/branch.py +45 -61
  94. langchain_core/runnables/config.py +80 -88
  95. langchain_core/runnables/configurable.py +117 -134
  96. langchain_core/runnables/fallbacks.py +83 -79
  97. langchain_core/runnables/graph.py +85 -95
  98. langchain_core/runnables/graph_ascii.py +27 -28
  99. langchain_core/runnables/graph_mermaid.py +38 -50
  100. langchain_core/runnables/graph_png.py +15 -16
  101. langchain_core/runnables/history.py +135 -148
  102. langchain_core/runnables/passthrough.py +124 -150
  103. langchain_core/runnables/retry.py +46 -51
  104. langchain_core/runnables/router.py +25 -30
  105. langchain_core/runnables/schema.py +79 -74
  106. langchain_core/runnables/utils.py +62 -68
  107. langchain_core/stores.py +81 -115
  108. langchain_core/structured_query.py +8 -8
  109. langchain_core/sys_info.py +27 -29
  110. langchain_core/tools/__init__.py +1 -14
  111. langchain_core/tools/base.py +179 -187
  112. langchain_core/tools/convert.py +131 -139
  113. langchain_core/tools/render.py +10 -10
  114. langchain_core/tools/retriever.py +11 -11
  115. langchain_core/tools/simple.py +19 -24
  116. langchain_core/tools/structured.py +30 -39
  117. langchain_core/tracers/__init__.py +1 -9
  118. langchain_core/tracers/base.py +97 -99
  119. langchain_core/tracers/context.py +29 -52
  120. langchain_core/tracers/core.py +50 -60
  121. langchain_core/tracers/evaluation.py +11 -11
  122. langchain_core/tracers/event_stream.py +115 -70
  123. langchain_core/tracers/langchain.py +21 -21
  124. langchain_core/tracers/log_stream.py +43 -43
  125. langchain_core/tracers/memory_stream.py +3 -3
  126. langchain_core/tracers/root_listeners.py +16 -16
  127. langchain_core/tracers/run_collector.py +2 -4
  128. langchain_core/tracers/schemas.py +0 -129
  129. langchain_core/tracers/stdout.py +3 -3
  130. langchain_core/utils/__init__.py +1 -4
  131. langchain_core/utils/_merge.py +46 -8
  132. langchain_core/utils/aiter.py +57 -61
  133. langchain_core/utils/env.py +9 -9
  134. langchain_core/utils/function_calling.py +89 -191
  135. langchain_core/utils/html.py +7 -8
  136. langchain_core/utils/input.py +6 -6
  137. langchain_core/utils/interactive_env.py +1 -1
  138. langchain_core/utils/iter.py +37 -42
  139. langchain_core/utils/json.py +4 -3
  140. langchain_core/utils/json_schema.py +8 -8
  141. langchain_core/utils/mustache.py +9 -11
  142. langchain_core/utils/pydantic.py +33 -35
  143. langchain_core/utils/strings.py +5 -5
  144. langchain_core/utils/usage.py +1 -1
  145. langchain_core/utils/utils.py +80 -54
  146. langchain_core/vectorstores/base.py +129 -164
  147. langchain_core/vectorstores/in_memory.py +99 -174
  148. langchain_core/vectorstores/utils.py +5 -5
  149. langchain_core/version.py +1 -1
  150. {langchain_core-0.3.79.dist-info → langchain_core-1.0.0.dist-info}/METADATA +28 -27
  151. langchain_core-1.0.0.dist-info/RECORD +172 -0
  152. {langchain_core-0.3.79.dist-info → langchain_core-1.0.0.dist-info}/WHEEL +1 -1
  153. langchain_core/beta/__init__.py +0 -1
  154. langchain_core/beta/runnables/__init__.py +0 -1
  155. langchain_core/beta/runnables/context.py +0 -447
  156. langchain_core/memory.py +0 -120
  157. langchain_core/messages/content_blocks.py +0 -176
  158. langchain_core/prompts/pipeline.py +0 -138
  159. langchain_core/pydantic_v1/__init__.py +0 -30
  160. langchain_core/pydantic_v1/dataclasses.py +0 -23
  161. langchain_core/pydantic_v1/main.py +0 -23
  162. langchain_core/tracers/langchain_v1.py +0 -31
  163. langchain_core/utils/loading.py +0 -35
  164. langchain_core-0.3.79.dist-info/RECORD +0 -174
  165. langchain_core-0.3.79.dist-info/entry_points.txt +0 -4
@@ -6,28 +6,28 @@ import asyncio
6
6
  import inspect
7
7
  import json
8
8
  import typing
9
- import warnings
10
9
  from abc import ABC, abstractmethod
11
- from collections.abc import AsyncIterator, Iterator, Sequence
10
+ from collections.abc import AsyncIterator, Callable, Iterator, Sequence
12
11
  from functools import cached_property
13
12
  from operator import itemgetter
14
- from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, cast
13
+ from typing import TYPE_CHECKING, Any, Literal, cast
15
14
 
16
- from pydantic import BaseModel, ConfigDict, Field, model_validator
15
+ from pydantic import BaseModel, ConfigDict, Field
17
16
  from typing_extensions import override
18
17
 
19
- from langchain_core._api import deprecated
20
18
  from langchain_core.caches import BaseCache
21
19
  from langchain_core.callbacks import (
22
20
  AsyncCallbackManager,
23
21
  AsyncCallbackManagerForLLMRun,
24
- BaseCallbackManager,
25
22
  CallbackManager,
26
23
  CallbackManagerForLLMRun,
27
24
  Callbacks,
28
25
  )
29
26
  from langchain_core.globals import get_llm_cache
30
- from langchain_core.language_models._utils import _normalize_messages
27
+ from langchain_core.language_models._utils import (
28
+ _normalize_messages,
29
+ _update_message_content_to_blocks,
30
+ )
31
31
  from langchain_core.language_models.base import (
32
32
  BaseLanguageModel,
33
33
  LangSmithParams,
@@ -36,16 +36,17 @@ from langchain_core.language_models.base import (
36
36
  from langchain_core.load import dumpd, dumps
37
37
  from langchain_core.messages import (
38
38
  AIMessage,
39
+ AIMessageChunk,
39
40
  AnyMessage,
40
41
  BaseMessage,
41
- BaseMessageChunk,
42
- HumanMessage,
43
42
  convert_to_messages,
44
- convert_to_openai_image_block,
45
43
  is_data_content_block,
46
44
  message_chunk_to_message,
47
45
  )
48
- from langchain_core.messages.ai import _LC_ID_PREFIX
46
+ from langchain_core.messages import content as types
47
+ from langchain_core.messages.block_translators.openai import (
48
+ convert_to_openai_image_block,
49
+ )
49
50
  from langchain_core.output_parsers.openai_tools import (
50
51
  JsonOutputKeyToolsParser,
51
52
  PydanticToolsParser,
@@ -69,6 +70,7 @@ from langchain_core.utils.function_calling import (
69
70
  convert_to_openai_tool,
70
71
  )
71
72
  from langchain_core.utils.pydantic import TypeBaseModel, is_basemodel_subclass
73
+ from langchain_core.utils.utils import LC_ID_PREFIX, from_env
72
74
 
73
75
  if TYPE_CHECKING:
74
76
  import uuid
@@ -106,11 +108,11 @@ def _generate_response_from_error(error: BaseException) -> list[ChatGeneration]:
106
108
 
107
109
 
108
110
  def _format_for_tracing(messages: list[BaseMessage]) -> list[BaseMessage]:
109
- """Format messages for tracing in ``on_chat_model_start``.
111
+ """Format messages for tracing in `on_chat_model_start`.
110
112
 
111
113
  - Update image content blocks to OpenAI Chat Completions format (backward
112
114
  compatibility).
113
- - Add ``type`` key to content blocks that have a single key.
115
+ - Add `type` key to content blocks that have a single key.
114
116
 
115
117
  Args:
116
118
  messages: List of messages to format.
@@ -129,7 +131,7 @@ def _format_for_tracing(messages: list[BaseMessage]) -> list[BaseMessage]:
129
131
  if (
130
132
  block.get("type") == "image"
131
133
  and is_data_content_block(block)
132
- and block.get("source_type") != "id"
134
+ and not ("file_id" in block or block.get("source_type") == "id")
133
135
  ):
134
136
  if message_to_trace is message:
135
137
  # Shallow copy
@@ -139,6 +141,22 @@ def _format_for_tracing(messages: list[BaseMessage]) -> list[BaseMessage]:
139
141
  message_to_trace.content[idx] = ( # type: ignore[index] # mypy confused by .model_copy
140
142
  convert_to_openai_image_block(block)
141
143
  )
144
+ elif (
145
+ block.get("type") == "file"
146
+ and is_data_content_block(block) # v0 (image/audio/file) or v1
147
+ and "base64" in block
148
+ # Backward compat: convert v1 base64 blocks to v0
149
+ ):
150
+ if message_to_trace is message:
151
+ # Shallow copy
152
+ message_to_trace = message.model_copy()
153
+ message_to_trace.content = list(message_to_trace.content)
154
+
155
+ message_to_trace.content[idx] = { # type: ignore[index]
156
+ **{k: v for k, v in block.items() if k != "base64"},
157
+ "data": block["base64"],
158
+ "source_type": "base64",
159
+ }
142
160
  elif len(block) == 1 and "type" not in block:
143
161
  # Tracing assumes all content blocks have a "type" key. Here
144
162
  # we add this key if it is missing, and there's an obvious
@@ -161,13 +179,13 @@ def generate_from_stream(stream: Iterator[ChatGenerationChunk]) -> ChatResult:
161
179
  """Generate from a stream.
162
180
 
163
181
  Args:
164
- stream: Iterator of ``ChatGenerationChunk``.
182
+ stream: Iterator of `ChatGenerationChunk`.
165
183
 
166
184
  Raises:
167
185
  ValueError: If no generations are found in the stream.
168
186
 
169
187
  Returns:
170
- ChatResult: Chat result.
188
+ Chat result.
171
189
 
172
190
  """
173
191
  generation = next(stream, None)
@@ -192,17 +210,17 @@ async def agenerate_from_stream(
192
210
  """Async generate from a stream.
193
211
 
194
212
  Args:
195
- stream: Iterator of ``ChatGenerationChunk``.
213
+ stream: Iterator of `ChatGenerationChunk`.
196
214
 
197
215
  Returns:
198
- ChatResult: Chat result.
216
+ Chat result.
199
217
 
200
218
  """
201
219
  chunks = [chunk async for chunk in stream]
202
220
  return await run_in_executor(None, generate_from_stream, iter(chunks))
203
221
 
204
222
 
205
- def _format_ls_structured_output(ls_structured_output_format: Optional[dict]) -> dict:
223
+ def _format_ls_structured_output(ls_structured_output_format: dict | None) -> dict:
206
224
  if ls_structured_output_format:
207
225
  try:
208
226
  ls_structured_output_format_dict = {
@@ -221,135 +239,99 @@ def _format_ls_structured_output(ls_structured_output_format: Optional[dict]) ->
221
239
  return ls_structured_output_format_dict
222
240
 
223
241
 
224
- class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
225
- """Base class for chat models.
242
+ class BaseChatModel(BaseLanguageModel[AIMessage], ABC):
243
+ r"""Base class for chat models.
226
244
 
227
245
  Key imperative methods:
228
246
  Methods that actually call the underlying model.
229
247
 
230
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
231
- | Method | Input | Output | Description |
232
- +===========================+================================================================+=====================================================================+==================================================================================================+
233
- | `invoke` | str | list[dict | tuple | BaseMessage] | PromptValue | BaseMessage | A single chat model call. |
234
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
235
- | `ainvoke` | ''' | BaseMessage | Defaults to running invoke in an async executor. |
236
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
237
- | `stream` | ''' | Iterator[BaseMessageChunk] | Defaults to yielding output of invoke. |
238
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
239
- | `astream` | ''' | AsyncIterator[BaseMessageChunk] | Defaults to yielding output of ainvoke. |
240
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
241
- | `astream_events` | ''' | AsyncIterator[StreamEvent] | Event types: 'on_chat_model_start', 'on_chat_model_stream', 'on_chat_model_end'. |
242
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
243
- | `batch` | list['''] | list[BaseMessage] | Defaults to running invoke in concurrent threads. |
244
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
245
- | `abatch` | list['''] | list[BaseMessage] | Defaults to running ainvoke in concurrent threads. |
246
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
247
- | `batch_as_completed` | list['''] | Iterator[tuple[int, Union[BaseMessage, Exception]]] | Defaults to running invoke in concurrent threads. |
248
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
249
- | `abatch_as_completed` | list['''] | AsyncIterator[tuple[int, Union[BaseMessage, Exception]]] | Defaults to running ainvoke in concurrent threads. |
250
- +---------------------------+----------------------------------------------------------------+---------------------------------------------------------------------+--------------------------------------------------------------------------------------------------+
251
-
252
- This table provides a brief overview of the main imperative methods. Please see the base Runnable reference for full documentation.
248
+ This table provides a brief overview of the main imperative methods. Please see the base `Runnable` reference for full documentation.
249
+
250
+ | Method | Input | Output | Description |
251
+ | ---------------------- | ------------------------------------------------------------ | ---------------------------------------------------------- | -------------------------------------------------------------------------------- |
252
+ | `invoke` | `str` \| `list[dict | tuple | BaseMessage]` \| `PromptValue` | `BaseMessage` | A single chat model call. |
253
+ | `ainvoke` | `'''` | `BaseMessage` | Defaults to running `invoke` in an async executor. |
254
+ | `stream` | `'''` | `Iterator[BaseMessageChunk]` | Defaults to yielding output of `invoke`. |
255
+ | `astream` | `'''` | `AsyncIterator[BaseMessageChunk]` | Defaults to yielding output of `ainvoke`. |
256
+ | `astream_events` | `'''` | `AsyncIterator[StreamEvent]` | Event types: `on_chat_model_start`, `on_chat_model_stream`, `on_chat_model_end`. |
257
+ | `batch` | `list[''']` | `list[BaseMessage]` | Defaults to running `invoke` in concurrent threads. |
258
+ | `abatch` | `list[''']` | `list[BaseMessage]` | Defaults to running `ainvoke` in concurrent threads. |
259
+ | `batch_as_completed` | `list[''']` | `Iterator[tuple[int, Union[BaseMessage, Exception]]]` | Defaults to running `invoke` in concurrent threads. |
260
+ | `abatch_as_completed` | `list[''']` | `AsyncIterator[tuple[int, Union[BaseMessage, Exception]]]` | Defaults to running `ainvoke` in concurrent threads. |
253
261
 
254
262
  Key declarative methods:
255
- Methods for creating another Runnable using the ChatModel.
256
-
257
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
258
- | Method | Description |
259
- +==================================+===========================================================================================================+
260
- | `bind_tools` | Create ChatModel that can call tools. |
261
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
262
- | `with_structured_output` | Create wrapper that structures model output using schema. |
263
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
264
- | `with_retry` | Create wrapper that retries model calls on failure. |
265
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
266
- | `with_fallbacks` | Create wrapper that falls back to other models on failure. |
267
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
268
- | `configurable_fields` | Specify init args of the model that can be configured at runtime via the RunnableConfig. |
269
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
270
- | `configurable_alternatives` | Specify alternative models which can be swapped in at runtime via the RunnableConfig. |
271
- +----------------------------------+-----------------------------------------------------------------------------------------------------------+
263
+ Methods for creating another `Runnable` using the chat model.
272
264
 
273
265
  This table provides a brief overview of the main declarative methods. Please see the reference for each method for full documentation.
274
266
 
267
+ | Method | Description |
268
+ | ---------------------------- | ------------------------------------------------------------------------------------------ |
269
+ | `bind_tools` | Create chat model that can call tools. |
270
+ | `with_structured_output` | Create wrapper that structures model output using schema. |
271
+ | `with_retry` | Create wrapper that retries model calls on failure. |
272
+ | `with_fallbacks` | Create wrapper that falls back to other models on failure. |
273
+ | `configurable_fields` | Specify init args of the model that can be configured at runtime via the `RunnableConfig`. |
274
+ | `configurable_alternatives` | Specify alternative models which can be swapped in at runtime via the `RunnableConfig`. |
275
+
275
276
  Creating custom chat model:
276
277
  Custom chat model implementations should inherit from this class.
277
278
  Please reference the table below for information about which
278
279
  methods and properties are required or optional for implementations.
279
280
 
280
- +----------------------------------+--------------------------------------------------------------------+-------------------+
281
- | Method/Property | Description | Required/Optional |
282
- +==================================+====================================================================+===================+
281
+ | Method/Property | Description | Required |
282
+ | -------------------------------- | ------------------------------------------------------------------ | ----------------- |
283
283
  | `_generate` | Use to generate a chat result from a prompt | Required |
284
- +----------------------------------+--------------------------------------------------------------------+-------------------+
285
284
  | `_llm_type` (property) | Used to uniquely identify the type of the model. Used for logging. | Required |
286
- +----------------------------------+--------------------------------------------------------------------+-------------------+
287
285
  | `_identifying_params` (property) | Represent model parameterization for tracing purposes. | Optional |
288
- +----------------------------------+--------------------------------------------------------------------+-------------------+
289
286
  | `_stream` | Use to implement streaming | Optional |
290
- +----------------------------------+--------------------------------------------------------------------+-------------------+
291
287
  | `_agenerate` | Use to implement a native async method | Optional |
292
- +----------------------------------+--------------------------------------------------------------------+-------------------+
293
288
  | `_astream` | Use to implement async version of `_stream` | Optional |
294
- +----------------------------------+--------------------------------------------------------------------+-------------------+
295
-
296
- Follow the guide for more information on how to implement a custom Chat Model:
297
- [Guide](https://python.langchain.com/docs/how_to/custom_chat_model/).
298
289
 
299
290
  """ # noqa: E501
300
291
 
301
- callback_manager: Optional[BaseCallbackManager] = deprecated(
302
- name="callback_manager", since="0.1.7", removal="1.0", alternative="callbacks"
303
- )(
304
- Field(
305
- default=None,
306
- exclude=True,
307
- description="Callback manager to add to the run trace.",
308
- )
309
- )
310
-
311
- rate_limiter: Optional[BaseRateLimiter] = Field(default=None, exclude=True)
292
+ rate_limiter: BaseRateLimiter | None = Field(default=None, exclude=True)
312
293
  "An optional rate limiter to use for limiting the number of requests."
313
294
 
314
- disable_streaming: Union[bool, Literal["tool_calling"]] = False
295
+ disable_streaming: bool | Literal["tool_calling"] = False
315
296
  """Whether to disable streaming for this model.
316
297
 
317
- If streaming is bypassed, then ``stream()``/``astream()``/``astream_events()`` will
318
- defer to ``invoke()``/``ainvoke()``.
298
+ If streaming is bypassed, then `stream`/`astream`/`astream_events` will
299
+ defer to `invoke`/`ainvoke`.
319
300
 
320
- - If True, will always bypass streaming case.
321
- - If ``'tool_calling'``, will bypass streaming case only when the model is called
322
- with a ``tools`` keyword argument. In other words, LangChain will automatically
323
- switch to non-streaming behavior (``invoke()``) only when the tools argument is
324
- provided. This offers the best of both worlds.
325
- - If False (default), will always use streaming case if available.
301
+ - If `True`, will always bypass streaming case.
302
+ - If `'tool_calling'`, will bypass streaming case only when the model is called
303
+ with a `tools` keyword argument. In other words, LangChain will automatically
304
+ switch to non-streaming behavior (`invoke`) only when the tools argument is
305
+ provided. This offers the best of both worlds.
306
+ - If `False` (Default), will always use streaming case if available.
326
307
 
327
- The main reason for this flag is that code might be written using ``stream()`` and
308
+ The main reason for this flag is that code might be written using `stream` and
328
309
  a user may want to swap out a given model for another model whose the implementation
329
310
  does not properly support streaming.
330
-
331
311
  """
332
312
 
333
- @model_validator(mode="before")
334
- @classmethod
335
- def raise_deprecation(cls, values: dict) -> Any:
336
- """Emit deprecation warning if ``callback_manager`` is used.
313
+ output_version: str | None = Field(
314
+ default_factory=from_env("LC_OUTPUT_VERSION", default=None)
315
+ )
316
+ """Version of `AIMessage` output format to store in message content.
337
317
 
338
- Args:
339
- values (Dict): Values to validate.
318
+ `AIMessage.content_blocks` will lazily parse the contents of `content` into a
319
+ standard format. This flag can be used to additionally store the standard format
320
+ in message content, e.g., for serialization purposes.
340
321
 
341
- Returns:
342
- Dict: Validated values.
322
+ Supported values:
343
323
 
344
- """
345
- if values.get("callback_manager") is not None:
346
- warnings.warn(
347
- "callback_manager is deprecated. Please use callbacks instead.",
348
- DeprecationWarning,
349
- stacklevel=5,
350
- )
351
- values["callbacks"] = values.pop("callback_manager", None)
352
- return values
324
+ - `'v0'`: provider-specific format in content (can lazily-parse with
325
+ `content_blocks`)
326
+ - `'v1'`: standardized format in content (consistent with `content_blocks`)
327
+
328
+ Partner packages (e.g.,
329
+ [`langchain-openai`](https://pypi.org/project/langchain-openai)) can also use this
330
+ field to roll out new content formats in a backward-compatible way.
331
+
332
+ !!! version-added "Added in version 1.0"
333
+
334
+ """
353
335
 
354
336
  model_config = ConfigDict(
355
337
  arbitrary_types_allowed=True,
@@ -364,7 +346,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
364
346
  @property
365
347
  @override
366
348
  def OutputType(self) -> Any:
367
- """Get the output type for this runnable."""
349
+ """Get the output type for this `Runnable`."""
368
350
  return AnyMessage
369
351
 
370
352
  def _convert_input(self, model_input: LanguageModelInput) -> PromptValue:
@@ -384,35 +366,38 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
384
366
  def invoke(
385
367
  self,
386
368
  input: LanguageModelInput,
387
- config: Optional[RunnableConfig] = None,
369
+ config: RunnableConfig | None = None,
388
370
  *,
389
- stop: Optional[list[str]] = None,
371
+ stop: list[str] | None = None,
390
372
  **kwargs: Any,
391
- ) -> BaseMessage:
373
+ ) -> AIMessage:
392
374
  config = ensure_config(config)
393
375
  return cast(
394
- "ChatGeneration",
395
- self.generate_prompt(
396
- [self._convert_input(input)],
397
- stop=stop,
398
- callbacks=config.get("callbacks"),
399
- tags=config.get("tags"),
400
- metadata=config.get("metadata"),
401
- run_name=config.get("run_name"),
402
- run_id=config.pop("run_id", None),
403
- **kwargs,
404
- ).generations[0][0],
405
- ).message
376
+ "AIMessage",
377
+ cast(
378
+ "ChatGeneration",
379
+ self.generate_prompt(
380
+ [self._convert_input(input)],
381
+ stop=stop,
382
+ callbacks=config.get("callbacks"),
383
+ tags=config.get("tags"),
384
+ metadata=config.get("metadata"),
385
+ run_name=config.get("run_name"),
386
+ run_id=config.pop("run_id", None),
387
+ **kwargs,
388
+ ).generations[0][0],
389
+ ).message,
390
+ )
406
391
 
407
392
  @override
408
393
  async def ainvoke(
409
394
  self,
410
395
  input: LanguageModelInput,
411
- config: Optional[RunnableConfig] = None,
396
+ config: RunnableConfig | None = None,
412
397
  *,
413
- stop: Optional[list[str]] = None,
398
+ stop: list[str] | None = None,
414
399
  **kwargs: Any,
415
- ) -> BaseMessage:
400
+ ) -> AIMessage:
416
401
  config = ensure_config(config)
417
402
  llm_result = await self.agenerate_prompt(
418
403
  [self._convert_input(input)],
@@ -424,15 +409,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
424
409
  run_id=config.pop("run_id", None),
425
410
  **kwargs,
426
411
  )
427
- return cast("ChatGeneration", llm_result.generations[0][0]).message
412
+ return cast(
413
+ "AIMessage", cast("ChatGeneration", llm_result.generations[0][0]).message
414
+ )
428
415
 
429
416
  def _should_stream(
430
417
  self,
431
418
  *,
432
419
  async_api: bool,
433
- run_manager: Optional[
434
- Union[CallbackManagerForLLMRun, AsyncCallbackManagerForLLMRun]
435
- ] = None,
420
+ run_manager: CallbackManagerForLLMRun
421
+ | AsyncCallbackManagerForLLMRun
422
+ | None = None,
436
423
  **kwargs: Any,
437
424
  ) -> bool:
438
425
  """Determine if a given model call should hit the streaming API."""
@@ -457,6 +444,11 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
457
444
  if "stream" in kwargs:
458
445
  return kwargs["stream"]
459
446
 
447
+ if "streaming" in self.model_fields_set:
448
+ streaming_value = getattr(self, "streaming", None)
449
+ if isinstance(streaming_value, bool):
450
+ return streaming_value
451
+
460
452
  # Check if any streaming callback handlers have been passed in.
461
453
  handlers = run_manager.handlers if run_manager else []
462
454
  return any(isinstance(h, _StreamingCallbackHandler) for h in handlers)
@@ -465,15 +457,15 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
465
457
  def stream(
466
458
  self,
467
459
  input: LanguageModelInput,
468
- config: Optional[RunnableConfig] = None,
460
+ config: RunnableConfig | None = None,
469
461
  *,
470
- stop: Optional[list[str]] = None,
462
+ stop: list[str] | None = None,
471
463
  **kwargs: Any,
472
- ) -> Iterator[BaseMessageChunk]:
464
+ ) -> Iterator[AIMessageChunk]:
473
465
  if not self._should_stream(async_api=False, **{**kwargs, "stream": True}):
474
466
  # Model doesn't implement streaming, so use default implementation
475
467
  yield cast(
476
- "BaseMessageChunk",
468
+ "AIMessageChunk",
477
469
  self.invoke(input, config=config, stop=stop, **kwargs),
478
470
  )
479
471
  else:
@@ -518,16 +510,51 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
518
510
 
519
511
  try:
520
512
  input_messages = _normalize_messages(messages)
521
- run_id = "-".join((_LC_ID_PREFIX, str(run_manager.run_id)))
513
+ run_id = "-".join((LC_ID_PREFIX, str(run_manager.run_id)))
514
+ yielded = False
515
+ index = -1
516
+ index_type = ""
522
517
  for chunk in self._stream(input_messages, stop=stop, **kwargs):
523
518
  if chunk.message.id is None:
524
519
  chunk.message.id = run_id
525
520
  chunk.message.response_metadata = _gen_info_and_msg_metadata(chunk)
521
+ if self.output_version == "v1":
522
+ # Overwrite .content with .content_blocks
523
+ chunk.message = _update_message_content_to_blocks(
524
+ chunk.message, "v1"
525
+ )
526
+ for block in cast(
527
+ "list[types.ContentBlock]", chunk.message.content
528
+ ):
529
+ if block["type"] != index_type:
530
+ index_type = block["type"]
531
+ index = index + 1
532
+ if "index" not in block:
533
+ block["index"] = index
526
534
  run_manager.on_llm_new_token(
527
535
  cast("str", chunk.message.content), chunk=chunk
528
536
  )
529
537
  chunks.append(chunk)
530
- yield chunk.message
538
+ yield cast("AIMessageChunk", chunk.message)
539
+ yielded = True
540
+
541
+ # Yield a final empty chunk with chunk_position="last" if not yet
542
+ # yielded
543
+ if (
544
+ yielded
545
+ and isinstance(chunk.message, AIMessageChunk)
546
+ and not chunk.message.chunk_position
547
+ ):
548
+ empty_content: str | list = (
549
+ "" if isinstance(chunk.message.content, str) else []
550
+ )
551
+ msg_chunk = AIMessageChunk(
552
+ content=empty_content, chunk_position="last", id=run_id
553
+ )
554
+ run_manager.on_llm_new_token(
555
+ "", chunk=ChatGenerationChunk(message=msg_chunk)
556
+ )
557
+ yield msg_chunk
531
558
  except BaseException as e:
532
559
  generations_with_error_metadata = _generate_response_from_error(e)
533
560
  chat_generation_chunk = merge_chat_generation_chunks(chunks)
@@ -556,15 +583,15 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
556
583
  async def astream(
557
584
  self,
558
585
  input: LanguageModelInput,
559
- config: Optional[RunnableConfig] = None,
586
+ config: RunnableConfig | None = None,
560
587
  *,
561
- stop: Optional[list[str]] = None,
588
+ stop: list[str] | None = None,
562
589
  **kwargs: Any,
563
- ) -> AsyncIterator[BaseMessageChunk]:
590
+ ) -> AsyncIterator[AIMessageChunk]:
564
591
  if not self._should_stream(async_api=True, **{**kwargs, "stream": True}):
565
592
  # No async or sync stream is implemented, so fall back to ainvoke
566
593
  yield cast(
567
- "BaseMessageChunk",
594
+ "AIMessageChunk",
568
595
  await self.ainvoke(input, config=config, stop=stop, **kwargs),
569
596
  )
570
597
  return
@@ -611,7 +638,10 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
611
638
 
612
639
  try:
613
640
  input_messages = _normalize_messages(messages)
614
- run_id = "-".join((_LC_ID_PREFIX, str(run_manager.run_id)))
641
+ run_id = "-".join((LC_ID_PREFIX, str(run_manager.run_id)))
642
+ yielded = False
643
+ index = -1
644
+ index_type = ""
615
645
  async for chunk in self._astream(
616
646
  input_messages,
617
647
  stop=stop,
@@ -620,11 +650,42 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
620
650
  if chunk.message.id is None:
621
651
  chunk.message.id = run_id
622
652
  chunk.message.response_metadata = _gen_info_and_msg_metadata(chunk)
653
+ if self.output_version == "v1":
654
+ # Overwrite .content with .content_blocks
655
+ chunk.message = _update_message_content_to_blocks(
656
+ chunk.message, "v1"
657
+ )
658
+ for block in cast(
659
+ "list[types.ContentBlock]", chunk.message.content
660
+ ):
661
+ if block["type"] != index_type:
662
+ index_type = block["type"]
663
+ index = index + 1
664
+ if "index" not in block:
665
+ block["index"] = index
623
666
  await run_manager.on_llm_new_token(
624
667
  cast("str", chunk.message.content), chunk=chunk
625
668
  )
626
669
  chunks.append(chunk)
627
- yield chunk.message
670
+ yield cast("AIMessageChunk", chunk.message)
671
+ yielded = True
672
+
673
+ # Yield a final empty chunk with chunk_position="last" if not yet yielded
674
+ if (
675
+ yielded
676
+ and isinstance(chunk.message, AIMessageChunk)
677
+ and not chunk.message.chunk_position
678
+ ):
679
+ empty_content: str | list = (
680
+ "" if isinstance(chunk.message.content, str) else []
681
+ )
682
+ msg_chunk = AIMessageChunk(
683
+ content=empty_content, chunk_position="last", id=run_id
684
+ )
685
+ await run_manager.on_llm_new_token(
686
+ "", chunk=ChatGenerationChunk(message=msg_chunk)
687
+ )
688
+ yield msg_chunk
628
689
  except BaseException as e:
629
690
  generations_with_error_metadata = _generate_response_from_error(e)
630
691
  chat_generation_chunk = merge_chat_generation_chunks(chunks)
@@ -650,7 +711,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
650
711
 
651
712
  # --- Custom methods ---
652
713
 
653
- def _combine_llm_outputs(self, llm_outputs: list[Optional[dict]]) -> dict: # noqa: ARG002
714
+ def _combine_llm_outputs(self, llm_outputs: list[dict | None]) -> dict: # noqa: ARG002
654
715
  return {}
655
716
 
656
717
  def _convert_cached_generations(self, cache_val: list) -> list[ChatGeneration]:
@@ -694,7 +755,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
694
755
 
695
756
  def _get_invocation_params(
696
757
  self,
697
- stop: Optional[list[str]] = None,
758
+ stop: list[str] | None = None,
698
759
  **kwargs: Any,
699
760
  ) -> dict:
700
761
  params = self.dict()
@@ -703,7 +764,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
703
764
 
704
765
  def _get_ls_params(
705
766
  self,
706
- stop: Optional[list[str]] = None,
767
+ stop: list[str] | None = None,
707
768
  **kwargs: Any,
708
769
  ) -> LangSmithParams:
709
770
  """Get standard params for tracing."""
@@ -741,7 +802,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
741
802
 
742
803
  return ls_params
743
804
 
744
- def _get_llm_string(self, stop: Optional[list[str]] = None, **kwargs: Any) -> str:
805
+ def _get_llm_string(self, stop: list[str] | None = None, **kwargs: Any) -> str:
745
806
  if self.is_lc_serializable():
746
807
  params = {**kwargs, "stop": stop}
747
808
  param_string = str(sorted(params.items()))
@@ -758,13 +819,13 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
758
819
  def generate(
759
820
  self,
760
821
  messages: list[list[BaseMessage]],
761
- stop: Optional[list[str]] = None,
822
+ stop: list[str] | None = None,
762
823
  callbacks: Callbacks = None,
763
824
  *,
764
- tags: Optional[list[str]] = None,
765
- metadata: Optional[dict[str, Any]] = None,
766
- run_name: Optional[str] = None,
767
- run_id: Optional[uuid.UUID] = None,
825
+ tags: list[str] | None = None,
826
+ metadata: dict[str, Any] | None = None,
827
+ run_name: str | None = None,
828
+ run_id: uuid.UUID | None = None,
768
829
  **kwargs: Any,
769
830
  ) -> LLMResult:
770
831
  """Pass a sequence of prompts to the model and return model generations.
@@ -777,13 +838,13 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
777
838
  1. Take advantage of batched calls,
778
839
  2. Need more output from the model than just the top generated value,
779
840
  3. Are building chains that are agnostic to the underlying language model
780
- type (e.g., pure text completion models vs chat models).
841
+ type (e.g., pure text completion models vs chat models).
781
842
 
782
843
  Args:
783
844
  messages: List of list of messages.
784
845
  stop: Stop words to use when generating. Model output is cut off at the
785
846
  first occurrence of any of these substrings.
786
- callbacks: Callbacks to pass through. Used for executing additional
847
+ callbacks: `Callbacks` to pass through. Used for executing additional
787
848
  functionality, such as logging or streaming, throughout generation.
788
849
  tags: The tags to apply.
789
850
  metadata: The metadata to apply.
@@ -793,8 +854,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
793
854
  to the model provider API call.
794
855
 
795
856
  Returns:
796
- An LLMResult, which contains a list of candidate Generations for each input
797
- prompt and additional model provider-specific output.
857
+ An `LLMResult`, which contains a list of candidate `Generations` for each
858
+ input prompt and additional model provider-specific output.
798
859
 
799
860
  """
800
861
  ls_structured_output_format = kwargs.pop(
@@ -865,7 +926,9 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
865
926
  output = LLMResult(generations=generations, llm_output=llm_output)
866
927
  if run_managers:
867
928
  run_infos = []
868
- for manager, flattened_output in zip(run_managers, flattened_outputs):
929
+ for manager, flattened_output in zip(
930
+ run_managers, flattened_outputs, strict=False
931
+ ):
869
932
  manager.on_llm_end(flattened_output)
870
933
  run_infos.append(RunInfo(run_id=manager.run_id))
871
934
  output.run = run_infos
@@ -874,13 +937,13 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
874
937
  async def agenerate(
875
938
  self,
876
939
  messages: list[list[BaseMessage]],
877
- stop: Optional[list[str]] = None,
940
+ stop: list[str] | None = None,
878
941
  callbacks: Callbacks = None,
879
942
  *,
880
- tags: Optional[list[str]] = None,
881
- metadata: Optional[dict[str, Any]] = None,
882
- run_name: Optional[str] = None,
883
- run_id: Optional[uuid.UUID] = None,
943
+ tags: list[str] | None = None,
944
+ metadata: dict[str, Any] | None = None,
945
+ run_name: str | None = None,
946
+ run_id: uuid.UUID | None = None,
884
947
  **kwargs: Any,
885
948
  ) -> LLMResult:
886
949
  """Asynchronously pass a sequence of prompts to a model and return generations.
@@ -893,13 +956,13 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
893
956
  1. Take advantage of batched calls,
894
957
  2. Need more output from the model than just the top generated value,
895
958
  3. Are building chains that are agnostic to the underlying language model
896
- type (e.g., pure text completion models vs chat models).
959
+ type (e.g., pure text completion models vs chat models).
897
960
 
898
961
  Args:
899
962
  messages: List of list of messages.
900
963
  stop: Stop words to use when generating. Model output is cut off at the
901
964
  first occurrence of any of these substrings.
902
- callbacks: Callbacks to pass through. Used for executing additional
965
+ callbacks: `Callbacks` to pass through. Used for executing additional
903
966
  functionality, such as logging or streaming, throughout generation.
904
967
  tags: The tags to apply.
905
968
  metadata: The metadata to apply.
@@ -909,8 +972,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
909
972
  to the model provider API call.
910
973
 
911
974
  Returns:
912
- An LLMResult, which contains a list of candidate Generations for each input
913
- prompt and additional model provider-specific output.
975
+ An `LLMResult`, which contains a list of candidate `Generations` for each
976
+ input prompt and additional model provider-specific output.
914
977
 
915
978
  """
916
979
  ls_structured_output_format = kwargs.pop(
@@ -987,7 +1050,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
987
1050
  llm_output=res.llm_output, # type: ignore[union-attr]
988
1051
  )
989
1052
  )
990
- for run_manager, res in zip(run_managers, results)
1053
+ for run_manager, res in zip(run_managers, results, strict=False)
991
1054
  if not isinstance(res, Exception)
992
1055
  ]
993
1056
  )
@@ -1003,7 +1066,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1003
1066
  *[
1004
1067
  run_manager.on_llm_end(flattened_output)
1005
1068
  for run_manager, flattened_output in zip(
1006
- run_managers, flattened_outputs
1069
+ run_managers, flattened_outputs, strict=False
1007
1070
  )
1008
1071
  ]
1009
1072
  )
@@ -1017,7 +1080,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1017
1080
  def generate_prompt(
1018
1081
  self,
1019
1082
  prompts: list[PromptValue],
1020
- stop: Optional[list[str]] = None,
1083
+ stop: list[str] | None = None,
1021
1084
  callbacks: Callbacks = None,
1022
1085
  **kwargs: Any,
1023
1086
  ) -> LLMResult:
@@ -1028,7 +1091,7 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1028
1091
  async def agenerate_prompt(
1029
1092
  self,
1030
1093
  prompts: list[PromptValue],
1031
- stop: Optional[list[str]] = None,
1094
+ stop: list[str] | None = None,
1032
1095
  callbacks: Callbacks = None,
1033
1096
  **kwargs: Any,
1034
1097
  ) -> LLMResult:
@@ -1040,8 +1103,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1040
1103
  def _generate_with_cache(
1041
1104
  self,
1042
1105
  messages: list[BaseMessage],
1043
- stop: Optional[list[str]] = None,
1044
- run_manager: Optional[CallbackManagerForLLMRun] = None,
1106
+ stop: list[str] | None = None,
1107
+ run_manager: CallbackManagerForLLMRun | None = None,
1045
1108
  **kwargs: Any,
1046
1109
  ) -> ChatResult:
1047
1110
  llm_cache = self.cache if isinstance(self.cache, BaseCache) else get_llm_cache()
@@ -1077,15 +1140,53 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1077
1140
  **kwargs,
1078
1141
  ):
1079
1142
  chunks: list[ChatGenerationChunk] = []
1143
+ run_id: str | None = (
1144
+ f"{LC_ID_PREFIX}-{run_manager.run_id}" if run_manager else None
1145
+ )
1146
+ yielded = False
1147
+ index = -1
1148
+ index_type = ""
1080
1149
  for chunk in self._stream(messages, stop=stop, **kwargs):
1081
1150
  chunk.message.response_metadata = _gen_info_and_msg_metadata(chunk)
1151
+ if self.output_version == "v1":
1152
+ # Overwrite .content with .content_blocks
1153
+ chunk.message = _update_message_content_to_blocks(
1154
+ chunk.message, "v1"
1155
+ )
1156
+ for block in cast(
1157
+ "list[types.ContentBlock]", chunk.message.content
1158
+ ):
1159
+ if block["type"] != index_type:
1160
+ index_type = block["type"]
1161
+ index = index + 1
1162
+ if "index" not in block:
1163
+ block["index"] = index
1082
1164
  if run_manager:
1083
1165
  if chunk.message.id is None:
1084
- chunk.message.id = f"{_LC_ID_PREFIX}-{run_manager.run_id}"
1166
+ chunk.message.id = run_id
1085
1167
  run_manager.on_llm_new_token(
1086
1168
  cast("str", chunk.message.content), chunk=chunk
1087
1169
  )
1088
1170
  chunks.append(chunk)
1171
+ yielded = True
1172
+
1173
+ # Yield a final empty chunk with chunk_position="last" if not yet yielded
1174
+ if (
1175
+ yielded
1176
+ and isinstance(chunk.message, AIMessageChunk)
1177
+ and not chunk.message.chunk_position
1178
+ ):
1179
+ empty_content: str | list = (
1180
+ "" if isinstance(chunk.message.content, str) else []
1181
+ )
1182
+ chunk = ChatGenerationChunk(
1183
+ message=AIMessageChunk(
1184
+ content=empty_content, chunk_position="last", id=run_id
1185
+ )
1186
+ )
1187
+ if run_manager:
1188
+ run_manager.on_llm_new_token("", chunk=chunk)
1189
+ chunks.append(chunk)
1089
1190
  result = generate_from_stream(iter(chunks))
1090
1191
  elif inspect.signature(self._generate).parameters.get("run_manager"):
1091
1192
  result = self._generate(
@@ -1094,10 +1195,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1094
1195
  else:
1095
1196
  result = self._generate(messages, stop=stop, **kwargs)
1096
1197
 
1198
+ if self.output_version == "v1":
1199
+ # Overwrite .content with .content_blocks
1200
+ for generation in result.generations:
1201
+ generation.message = _update_message_content_to_blocks(
1202
+ generation.message, "v1"
1203
+ )
1204
+
1097
1205
  # Add response metadata to each generation
1098
1206
  for idx, generation in enumerate(result.generations):
1099
1207
  if run_manager and generation.message.id is None:
1100
- generation.message.id = f"{_LC_ID_PREFIX}-{run_manager.run_id}-{idx}"
1208
+ generation.message.id = f"{LC_ID_PREFIX}-{run_manager.run_id}-{idx}"
1101
1209
  generation.message.response_metadata = _gen_info_and_msg_metadata(
1102
1210
  generation
1103
1211
  )
@@ -1113,8 +1221,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1113
1221
  async def _agenerate_with_cache(
1114
1222
  self,
1115
1223
  messages: list[BaseMessage],
1116
- stop: Optional[list[str]] = None,
1117
- run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
1224
+ stop: list[str] | None = None,
1225
+ run_manager: AsyncCallbackManagerForLLMRun | None = None,
1118
1226
  **kwargs: Any,
1119
1227
  ) -> ChatResult:
1120
1228
  llm_cache = self.cache if isinstance(self.cache, BaseCache) else get_llm_cache()
@@ -1150,15 +1258,53 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1150
1258
  **kwargs,
1151
1259
  ):
1152
1260
  chunks: list[ChatGenerationChunk] = []
1261
+ run_id: str | None = (
1262
+ f"{LC_ID_PREFIX}-{run_manager.run_id}" if run_manager else None
1263
+ )
1264
+ yielded = False
1265
+ index = -1
1266
+ index_type = ""
1153
1267
  async for chunk in self._astream(messages, stop=stop, **kwargs):
1154
1268
  chunk.message.response_metadata = _gen_info_and_msg_metadata(chunk)
1269
+ if self.output_version == "v1":
1270
+ # Overwrite .content with .content_blocks
1271
+ chunk.message = _update_message_content_to_blocks(
1272
+ chunk.message, "v1"
1273
+ )
1274
+ for block in cast(
1275
+ "list[types.ContentBlock]", chunk.message.content
1276
+ ):
1277
+ if block["type"] != index_type:
1278
+ index_type = block["type"]
1279
+ index = index + 1
1280
+ if "index" not in block:
1281
+ block["index"] = index
1155
1282
  if run_manager:
1156
1283
  if chunk.message.id is None:
1157
- chunk.message.id = f"{_LC_ID_PREFIX}-{run_manager.run_id}"
1284
+ chunk.message.id = run_id
1158
1285
  await run_manager.on_llm_new_token(
1159
1286
  cast("str", chunk.message.content), chunk=chunk
1160
1287
  )
1161
1288
  chunks.append(chunk)
1289
+ yielded = True
1290
+
1291
+ # Yield a final empty chunk with chunk_position="last" if not yet yielded
1292
+ if (
1293
+ yielded
1294
+ and isinstance(chunk.message, AIMessageChunk)
1295
+ and not chunk.message.chunk_position
1296
+ ):
1297
+ empty_content: str | list = (
1298
+ "" if isinstance(chunk.message.content, str) else []
1299
+ )
1300
+ chunk = ChatGenerationChunk(
1301
+ message=AIMessageChunk(
1302
+ content=empty_content, chunk_position="last", id=run_id
1303
+ )
1304
+ )
1305
+ if run_manager:
1306
+ await run_manager.on_llm_new_token("", chunk=chunk)
1307
+ chunks.append(chunk)
1162
1308
  result = generate_from_stream(iter(chunks))
1163
1309
  elif inspect.signature(self._agenerate).parameters.get("run_manager"):
1164
1310
  result = await self._agenerate(
@@ -1167,10 +1313,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1167
1313
  else:
1168
1314
  result = await self._agenerate(messages, stop=stop, **kwargs)
1169
1315
 
1316
+ if self.output_version == "v1":
1317
+ # Overwrite .content with .content_blocks
1318
+ for generation in result.generations:
1319
+ generation.message = _update_message_content_to_blocks(
1320
+ generation.message, "v1"
1321
+ )
1322
+
1170
1323
  # Add response metadata to each generation
1171
1324
  for idx, generation in enumerate(result.generations):
1172
1325
  if run_manager and generation.message.id is None:
1173
- generation.message.id = f"{_LC_ID_PREFIX}-{run_manager.run_id}-{idx}"
1326
+ generation.message.id = f"{LC_ID_PREFIX}-{run_manager.run_id}-{idx}"
1174
1327
  generation.message.response_metadata = _gen_info_and_msg_metadata(
1175
1328
  generation
1176
1329
  )
@@ -1187,8 +1340,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1187
1340
  def _generate(
1188
1341
  self,
1189
1342
  messages: list[BaseMessage],
1190
- stop: Optional[list[str]] = None,
1191
- run_manager: Optional[CallbackManagerForLLMRun] = None,
1343
+ stop: list[str] | None = None,
1344
+ run_manager: CallbackManagerForLLMRun | None = None,
1192
1345
  **kwargs: Any,
1193
1346
  ) -> ChatResult:
1194
1347
  """Generate the result.
@@ -1206,8 +1359,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1206
1359
  async def _agenerate(
1207
1360
  self,
1208
1361
  messages: list[BaseMessage],
1209
- stop: Optional[list[str]] = None,
1210
- run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
1362
+ stop: list[str] | None = None,
1363
+ run_manager: AsyncCallbackManagerForLLMRun | None = None,
1211
1364
  **kwargs: Any,
1212
1365
  ) -> ChatResult:
1213
1366
  """Generate the result.
@@ -1233,8 +1386,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1233
1386
  def _stream(
1234
1387
  self,
1235
1388
  messages: list[BaseMessage],
1236
- stop: Optional[list[str]] = None,
1237
- run_manager: Optional[CallbackManagerForLLMRun] = None,
1389
+ stop: list[str] | None = None,
1390
+ run_manager: CallbackManagerForLLMRun | None = None,
1238
1391
  **kwargs: Any,
1239
1392
  ) -> Iterator[ChatGenerationChunk]:
1240
1393
  """Stream the output of the model.
@@ -1253,8 +1406,8 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1253
1406
  async def _astream(
1254
1407
  self,
1255
1408
  messages: list[BaseMessage],
1256
- stop: Optional[list[str]] = None,
1257
- run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
1409
+ stop: list[str] | None = None,
1410
+ run_manager: AsyncCallbackManagerForLLMRun | None = None,
1258
1411
  **kwargs: Any,
1259
1412
  ) -> AsyncIterator[ChatGenerationChunk]:
1260
1413
  """Stream the output of the model.
@@ -1288,44 +1441,10 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1288
1441
  break
1289
1442
  yield item # type: ignore[misc]
1290
1443
 
1291
- @deprecated("0.1.7", alternative="invoke", removal="1.0")
1292
- def __call__(
1293
- self,
1294
- messages: list[BaseMessage],
1295
- stop: Optional[list[str]] = None,
1296
- callbacks: Callbacks = None,
1297
- **kwargs: Any,
1298
- ) -> BaseMessage:
1299
- """Call the model.
1300
-
1301
- Args:
1302
- messages: List of messages.
1303
- stop: Stop words to use when generating. Model output is cut off at the
1304
- first occurrence of any of these substrings.
1305
- callbacks: Callbacks to pass through. Used for executing additional
1306
- functionality, such as logging or streaming, throughout generation.
1307
- **kwargs: Arbitrary additional keyword arguments. These are usually passed
1308
- to the model provider API call.
1309
-
1310
- Raises:
1311
- ValueError: If the generation is not a chat generation.
1312
-
1313
- Returns:
1314
- The model output message.
1315
-
1316
- """
1317
- generation = self.generate(
1318
- [messages], stop=stop, callbacks=callbacks, **kwargs
1319
- ).generations[0][0]
1320
- if isinstance(generation, ChatGeneration):
1321
- return generation.message
1322
- msg = "Unexpected generation type"
1323
- raise ValueError(msg)
1324
-
1325
1444
  async def _call_async(
1326
1445
  self,
1327
1446
  messages: list[BaseMessage],
1328
- stop: Optional[list[str]] = None,
1447
+ stop: list[str] | None = None,
1329
1448
  callbacks: Callbacks = None,
1330
1449
  **kwargs: Any,
1331
1450
  ) -> BaseMessage:
@@ -1338,91 +1457,6 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1338
1457
  msg = "Unexpected generation type"
1339
1458
  raise ValueError(msg)
1340
1459
 
1341
- @deprecated("0.1.7", alternative="invoke", removal="1.0")
1342
- def call_as_llm(
1343
- self, message: str, stop: Optional[list[str]] = None, **kwargs: Any
1344
- ) -> str:
1345
- """Call the model.
1346
-
1347
- Args:
1348
- message: The input message.
1349
- stop: Stop words to use when generating. Model output is cut off at the
1350
- first occurrence of any of these substrings.
1351
- **kwargs: Arbitrary additional keyword arguments. These are usually passed
1352
- to the model provider API call.
1353
-
1354
- Returns:
1355
- The model output string.
1356
-
1357
- """
1358
- return self.predict(message, stop=stop, **kwargs)
1359
-
1360
- @deprecated("0.1.7", alternative="invoke", removal="1.0")
1361
- @override
1362
- def predict(
1363
- self, text: str, *, stop: Optional[Sequence[str]] = None, **kwargs: Any
1364
- ) -> str:
1365
- """Predict the next message.
1366
-
1367
- Args:
1368
- text: The input message.
1369
- stop: Stop words to use when generating. Model output is cut off at the
1370
- first occurrence of any of these substrings.
1371
- **kwargs: Arbitrary additional keyword arguments. These are usually passed
1372
- to the model provider API call.
1373
-
1374
- Raises:
1375
- ValueError: If the output is not a string.
1376
-
1377
- Returns:
1378
- The predicted output string.
1379
-
1380
- """
1381
- stop_ = None if stop is None else list(stop)
1382
- result = self([HumanMessage(content=text)], stop=stop_, **kwargs)
1383
- if isinstance(result.content, str):
1384
- return result.content
1385
- msg = "Cannot use predict when output is not a string."
1386
- raise ValueError(msg)
1387
-
1388
- @deprecated("0.1.7", alternative="invoke", removal="1.0")
1389
- @override
1390
- def predict_messages(
1391
- self,
1392
- messages: list[BaseMessage],
1393
- *,
1394
- stop: Optional[Sequence[str]] = None,
1395
- **kwargs: Any,
1396
- ) -> BaseMessage:
1397
- stop_ = None if stop is None else list(stop)
1398
- return self(messages, stop=stop_, **kwargs)
1399
-
1400
- @deprecated("0.1.7", alternative="ainvoke", removal="1.0")
1401
- @override
1402
- async def apredict(
1403
- self, text: str, *, stop: Optional[Sequence[str]] = None, **kwargs: Any
1404
- ) -> str:
1405
- stop_ = None if stop is None else list(stop)
1406
- result = await self._call_async(
1407
- [HumanMessage(content=text)], stop=stop_, **kwargs
1408
- )
1409
- if isinstance(result.content, str):
1410
- return result.content
1411
- msg = "Cannot use predict when output is not a string."
1412
- raise ValueError(msg)
1413
-
1414
- @deprecated("0.1.7", alternative="ainvoke", removal="1.0")
1415
- @override
1416
- async def apredict_messages(
1417
- self,
1418
- messages: list[BaseMessage],
1419
- *,
1420
- stop: Optional[Sequence[str]] = None,
1421
- **kwargs: Any,
1422
- ) -> BaseMessage:
1423
- stop_ = None if stop is None else list(stop)
1424
- return await self._call_async(messages, stop=stop_, **kwargs)
1425
-
1426
1460
  @property
1427
1461
  @abstractmethod
1428
1462
  def _llm_type(self) -> str:
@@ -1438,12 +1472,12 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1438
1472
  def bind_tools(
1439
1473
  self,
1440
1474
  tools: Sequence[
1441
- Union[typing.Dict[str, Any], type, Callable, BaseTool] # noqa: UP006
1475
+ typing.Dict[str, Any] | type | Callable | BaseTool # noqa: UP006
1442
1476
  ],
1443
1477
  *,
1444
- tool_choice: Optional[Union[str]] = None,
1478
+ tool_choice: str | None = None,
1445
1479
  **kwargs: Any,
1446
- ) -> Runnable[LanguageModelInput, BaseMessage]:
1480
+ ) -> Runnable[LanguageModelInput, AIMessage]:
1447
1481
  """Bind tools to the model.
1448
1482
 
1449
1483
  Args:
@@ -1458,11 +1492,11 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1458
1492
 
1459
1493
  def with_structured_output(
1460
1494
  self,
1461
- schema: Union[typing.Dict, type], # noqa: UP006
1495
+ schema: typing.Dict | type, # noqa: UP006
1462
1496
  *,
1463
1497
  include_raw: bool = False,
1464
1498
  **kwargs: Any,
1465
- ) -> Runnable[LanguageModelInput, Union[typing.Dict, BaseModel]]: # noqa: UP006
1499
+ ) -> Runnable[LanguageModelInput, typing.Dict | BaseModel]: # noqa: UP006
1466
1500
  """Model wrapper that returns outputs formatted to match the given schema.
1467
1501
 
1468
1502
  Args:
@@ -1470,124 +1504,130 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1470
1504
 
1471
1505
  - an OpenAI function/tool schema,
1472
1506
  - a JSON Schema,
1473
- - a TypedDict class,
1507
+ - a `TypedDict` class,
1474
1508
  - or a Pydantic class.
1475
1509
 
1476
- If ``schema`` is a Pydantic class then the model output will be a
1510
+ If `schema` is a Pydantic class then the model output will be a
1477
1511
  Pydantic instance of that class, and the model-generated fields will be
1478
1512
  validated by the Pydantic class. Otherwise the model output will be a
1479
- dict and will not be validated. See :meth:`langchain_core.utils.function_calling.convert_to_openai_tool`
1480
- for more on how to properly specify types and descriptions of
1481
- schema fields when specifying a Pydantic or TypedDict class.
1513
+ dict and will not be validated.
1514
+
1515
+ See `langchain_core.utils.function_calling.convert_to_openai_tool` for
1516
+ more on how to properly specify types and descriptions of schema fields
1517
+ when specifying a Pydantic or `TypedDict` class.
1482
1518
 
1483
1519
  include_raw:
1484
- If False then only the parsed structured output is returned. If
1485
- an error occurs during model output parsing it will be raised. If True
1486
- then both the raw model response (a BaseMessage) and the parsed model
1520
+ If `False` then only the parsed structured output is returned. If
1521
+ an error occurs during model output parsing it will be raised. If `True`
1522
+ then both the raw model response (a `BaseMessage`) and the parsed model
1487
1523
  response will be returned. If an error occurs during output parsing it
1488
- will be caught and returned as well. The final output is always a dict
1489
- with keys ``'raw'``, ``'parsed'``, and ``'parsing_error'``.
1524
+ will be caught and returned as well.
1525
+
1526
+ The final output is always a `dict` with keys `'raw'`, `'parsed'`, and
1527
+ `'parsing_error'`.
1490
1528
 
1491
1529
  Raises:
1492
- ValueError: If there are any unsupported ``kwargs``.
1530
+ ValueError: If there are any unsupported `kwargs`.
1493
1531
  NotImplementedError: If the model does not implement
1494
- ``with_structured_output()``.
1532
+ `with_structured_output()`.
1495
1533
 
1496
1534
  Returns:
1497
- A Runnable that takes same inputs as a :class:`langchain_core.language_models.chat.BaseChatModel`.
1498
-
1499
- If ``include_raw`` is False and ``schema`` is a Pydantic class, Runnable outputs
1500
- an instance of ``schema`` (i.e., a Pydantic object).
1535
+ A `Runnable` that takes same inputs as a
1536
+ `langchain_core.language_models.chat.BaseChatModel`. If `include_raw` is
1537
+ `False` and `schema` is a Pydantic class, `Runnable` outputs an instance
1538
+ of `schema` (i.e., a Pydantic object). Otherwise, if `include_raw` is
1539
+ `False` then `Runnable` outputs a `dict`.
1501
1540
 
1502
- Otherwise, if ``include_raw`` is False then Runnable outputs a dict.
1541
+ If `include_raw` is `True`, then `Runnable` outputs a `dict` with keys:
1503
1542
 
1504
- If ``include_raw`` is True, then Runnable outputs a dict with keys:
1543
+ - `'raw'`: `BaseMessage`
1544
+ - `'parsed'`: `None` if there was a parsing error, otherwise the type
1545
+ depends on the `schema` as described above.
1546
+ - `'parsing_error'`: `BaseException | None`
1505
1547
 
1506
- - ``'raw'``: BaseMessage
1507
- - ``'parsed'``: None if there was a parsing error, otherwise the type depends on the ``schema`` as described above.
1508
- - ``'parsing_error'``: Optional[BaseException]
1548
+ Example: Pydantic schema (`include_raw=False`):
1509
1549
 
1510
- Example: Pydantic schema (include_raw=False):
1511
- .. code-block:: python
1550
+ ```python
1551
+ from pydantic import BaseModel
1512
1552
 
1513
- from pydantic import BaseModel
1514
1553
 
1554
+ class AnswerWithJustification(BaseModel):
1555
+ '''An answer to the user question along with justification for the answer.'''
1515
1556
 
1516
- class AnswerWithJustification(BaseModel):
1517
- '''An answer to the user question along with justification for the answer.'''
1557
+ answer: str
1558
+ justification: str
1518
1559
 
1519
- answer: str
1520
- justification: str
1521
1560
 
1561
+ model = ChatModel(model="model-name", temperature=0)
1562
+ structured_model = model.with_structured_output(AnswerWithJustification)
1522
1563
 
1523
- llm = ChatModel(model="model-name", temperature=0)
1524
- structured_llm = llm.with_structured_output(AnswerWithJustification)
1525
-
1526
- structured_llm.invoke(
1527
- "What weighs more a pound of bricks or a pound of feathers"
1528
- )
1529
-
1530
- # -> AnswerWithJustification(
1531
- # answer='They weigh the same',
1532
- # justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'
1533
- # )
1564
+ structured_model.invoke(
1565
+ "What weighs more a pound of bricks or a pound of feathers"
1566
+ )
1534
1567
 
1535
- Example: Pydantic schema (include_raw=True):
1536
- .. code-block:: python
1568
+ # -> AnswerWithJustification(
1569
+ # answer='They weigh the same',
1570
+ # justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'
1571
+ # )
1572
+ ```
1537
1573
 
1538
- from pydantic import BaseModel
1574
+ Example: Pydantic schema (`include_raw=True`):
1539
1575
 
1576
+ ```python
1577
+ from pydantic import BaseModel
1540
1578
 
1541
- class AnswerWithJustification(BaseModel):
1542
- '''An answer to the user question along with justification for the answer.'''
1543
1579
 
1544
- answer: str
1545
- justification: str
1580
+ class AnswerWithJustification(BaseModel):
1581
+ '''An answer to the user question along with justification for the answer.'''
1546
1582
 
1583
+ answer: str
1584
+ justification: str
1547
1585
 
1548
- llm = ChatModel(model="model-name", temperature=0)
1549
- structured_llm = llm.with_structured_output(
1550
- AnswerWithJustification, include_raw=True
1551
- )
1552
1586
 
1553
- structured_llm.invoke(
1554
- "What weighs more a pound of bricks or a pound of feathers"
1555
- )
1556
- # -> {
1557
- # 'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
1558
- # 'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
1559
- # 'parsing_error': None
1560
- # }
1587
+ model = ChatModel(model="model-name", temperature=0)
1588
+ structured_model = model.with_structured_output(
1589
+ AnswerWithJustification, include_raw=True
1590
+ )
1561
1591
 
1562
- Example: Dict schema (include_raw=False):
1563
- .. code-block:: python
1592
+ structured_model.invoke(
1593
+ "What weighs more a pound of bricks or a pound of feathers"
1594
+ )
1595
+ # -> {
1596
+ # 'raw': AIMessage(content='', additional_kwargs={'tool_calls': [{'id': 'call_Ao02pnFYXD6GN1yzc0uXPsvF', 'function': {'arguments': '{"answer":"They weigh the same.","justification":"Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ."}', 'name': 'AnswerWithJustification'}, 'type': 'function'}]}),
1597
+ # 'parsed': AnswerWithJustification(answer='They weigh the same.', justification='Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume or density of the objects may differ.'),
1598
+ # 'parsing_error': None
1599
+ # }
1600
+ ```
1564
1601
 
1565
- from pydantic import BaseModel
1566
- from langchain_core.utils.function_calling import convert_to_openai_tool
1602
+ Example: `dict` schema (`include_raw=False`):
1567
1603
 
1604
+ ```python
1605
+ from pydantic import BaseModel
1606
+ from langchain_core.utils.function_calling import convert_to_openai_tool
1568
1607
 
1569
- class AnswerWithJustification(BaseModel):
1570
- '''An answer to the user question along with justification for the answer.'''
1571
1608
 
1572
- answer: str
1573
- justification: str
1609
+ class AnswerWithJustification(BaseModel):
1610
+ '''An answer to the user question along with justification for the answer.'''
1574
1611
 
1612
+ answer: str
1613
+ justification: str
1575
1614
 
1576
- dict_schema = convert_to_openai_tool(AnswerWithJustification)
1577
- llm = ChatModel(model="model-name", temperature=0)
1578
- structured_llm = llm.with_structured_output(dict_schema)
1579
1615
 
1580
- structured_llm.invoke(
1581
- "What weighs more a pound of bricks or a pound of feathers"
1582
- )
1583
- # -> {
1584
- # 'answer': 'They weigh the same',
1585
- # 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
1586
- # }
1616
+ dict_schema = convert_to_openai_tool(AnswerWithJustification)
1617
+ model = ChatModel(model="model-name", temperature=0)
1618
+ structured_model = model.with_structured_output(dict_schema)
1587
1619
 
1588
- .. versionchanged:: 0.2.26
1620
+ structured_model.invoke(
1621
+ "What weighs more a pound of bricks or a pound of feathers"
1622
+ )
1623
+ # -> {
1624
+ # 'answer': 'They weigh the same',
1625
+ # 'justification': 'Both a pound of bricks and a pound of feathers weigh one pound. The weight is the same, but the volume and density of the two substances differ.'
1626
+ # }
1627
+ ```
1589
1628
 
1590
- Added support for TypedDict class.
1629
+ !!! warning "Behavior changed in 0.2.26"
1630
+ Added support for TypedDict class.
1591
1631
 
1592
1632
  """ # noqa: E501
1593
1633
  _ = kwargs.pop("method", None)
@@ -1632,17 +1672,17 @@ class BaseChatModel(BaseLanguageModel[BaseMessage], ABC):
1632
1672
  class SimpleChatModel(BaseChatModel):
1633
1673
  """Simplified implementation for a chat model to inherit from.
1634
1674
 
1635
- .. note::
1675
+ !!! note
1636
1676
  This implementation is primarily here for backwards compatibility. For new
1637
- implementations, please use ``BaseChatModel`` directly.
1677
+ implementations, please use `BaseChatModel` directly.
1638
1678
 
1639
1679
  """
1640
1680
 
1641
1681
  def _generate(
1642
1682
  self,
1643
1683
  messages: list[BaseMessage],
1644
- stop: Optional[list[str]] = None,
1645
- run_manager: Optional[CallbackManagerForLLMRun] = None,
1684
+ stop: list[str] | None = None,
1685
+ run_manager: CallbackManagerForLLMRun | None = None,
1646
1686
  **kwargs: Any,
1647
1687
  ) -> ChatResult:
1648
1688
  output_str = self._call(messages, stop=stop, run_manager=run_manager, **kwargs)
@@ -1654,8 +1694,8 @@ class SimpleChatModel(BaseChatModel):
1654
1694
  def _call(
1655
1695
  self,
1656
1696
  messages: list[BaseMessage],
1657
- stop: Optional[list[str]] = None,
1658
- run_manager: Optional[CallbackManagerForLLMRun] = None,
1697
+ stop: list[str] | None = None,
1698
+ run_manager: CallbackManagerForLLMRun | None = None,
1659
1699
  **kwargs: Any,
1660
1700
  ) -> str:
1661
1701
  """Simpler interface."""
@@ -1663,8 +1703,8 @@ class SimpleChatModel(BaseChatModel):
1663
1703
  async def _agenerate(
1664
1704
  self,
1665
1705
  messages: list[BaseMessage],
1666
- stop: Optional[list[str]] = None,
1667
- run_manager: Optional[AsyncCallbackManagerForLLMRun] = None,
1706
+ stop: list[str] | None = None,
1707
+ run_manager: AsyncCallbackManagerForLLMRun | None = None,
1668
1708
  **kwargs: Any,
1669
1709
  ) -> ChatResult:
1670
1710
  return await run_in_executor(
@@ -1678,7 +1718,7 @@ class SimpleChatModel(BaseChatModel):
1678
1718
 
1679
1719
 
1680
1720
  def _gen_info_and_msg_metadata(
1681
- generation: Union[ChatGeneration, ChatGenerationChunk],
1721
+ generation: ChatGeneration | ChatGenerationChunk,
1682
1722
  ) -> dict:
1683
1723
  return {
1684
1724
  **(generation.generation_info or {}),