langchain-core 0.3.75__py3-none-any.whl → 0.3.77__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 (119) hide show
  1. langchain_core/_api/beta_decorator.py +22 -44
  2. langchain_core/_api/deprecation.py +30 -17
  3. langchain_core/_api/path.py +19 -2
  4. langchain_core/_import_utils.py +7 -0
  5. langchain_core/agents.py +10 -6
  6. langchain_core/beta/runnables/context.py +1 -2
  7. langchain_core/callbacks/base.py +28 -15
  8. langchain_core/callbacks/manager.py +83 -71
  9. langchain_core/callbacks/usage.py +6 -4
  10. langchain_core/chat_history.py +29 -21
  11. langchain_core/document_loaders/base.py +34 -9
  12. langchain_core/document_loaders/langsmith.py +4 -1
  13. langchain_core/documents/base.py +35 -10
  14. langchain_core/documents/transformers.py +4 -2
  15. langchain_core/embeddings/fake.py +8 -5
  16. langchain_core/env.py +2 -3
  17. langchain_core/example_selectors/base.py +12 -0
  18. langchain_core/exceptions.py +7 -0
  19. langchain_core/globals.py +17 -28
  20. langchain_core/indexing/api.py +88 -76
  21. langchain_core/indexing/base.py +5 -8
  22. langchain_core/indexing/in_memory.py +23 -3
  23. langchain_core/language_models/__init__.py +3 -2
  24. langchain_core/language_models/base.py +31 -20
  25. langchain_core/language_models/chat_models.py +98 -27
  26. langchain_core/language_models/fake_chat_models.py +10 -9
  27. langchain_core/language_models/llms.py +52 -18
  28. langchain_core/load/dump.py +2 -3
  29. langchain_core/load/load.py +15 -1
  30. langchain_core/load/serializable.py +39 -44
  31. langchain_core/memory.py +7 -3
  32. langchain_core/messages/ai.py +53 -24
  33. langchain_core/messages/base.py +43 -22
  34. langchain_core/messages/chat.py +4 -1
  35. langchain_core/messages/content_blocks.py +23 -2
  36. langchain_core/messages/function.py +9 -5
  37. langchain_core/messages/human.py +13 -10
  38. langchain_core/messages/modifier.py +1 -0
  39. langchain_core/messages/system.py +11 -8
  40. langchain_core/messages/tool.py +60 -29
  41. langchain_core/messages/utils.py +250 -131
  42. langchain_core/output_parsers/base.py +5 -2
  43. langchain_core/output_parsers/json.py +4 -4
  44. langchain_core/output_parsers/list.py +7 -22
  45. langchain_core/output_parsers/openai_functions.py +3 -0
  46. langchain_core/output_parsers/openai_tools.py +6 -1
  47. langchain_core/output_parsers/pydantic.py +4 -0
  48. langchain_core/output_parsers/string.py +5 -1
  49. langchain_core/output_parsers/xml.py +19 -19
  50. langchain_core/outputs/chat_generation.py +25 -10
  51. langchain_core/outputs/generation.py +14 -3
  52. langchain_core/outputs/llm_result.py +8 -1
  53. langchain_core/prompt_values.py +16 -6
  54. langchain_core/prompts/base.py +4 -9
  55. langchain_core/prompts/chat.py +89 -57
  56. langchain_core/prompts/dict.py +16 -8
  57. langchain_core/prompts/few_shot.py +12 -11
  58. langchain_core/prompts/few_shot_with_templates.py +5 -1
  59. langchain_core/prompts/image.py +12 -5
  60. langchain_core/prompts/message.py +5 -6
  61. langchain_core/prompts/pipeline.py +13 -8
  62. langchain_core/prompts/prompt.py +22 -8
  63. langchain_core/prompts/string.py +18 -10
  64. langchain_core/prompts/structured.py +7 -2
  65. langchain_core/rate_limiters.py +2 -2
  66. langchain_core/retrievers.py +7 -6
  67. langchain_core/runnables/base.py +406 -186
  68. langchain_core/runnables/branch.py +14 -19
  69. langchain_core/runnables/config.py +9 -15
  70. langchain_core/runnables/configurable.py +34 -19
  71. langchain_core/runnables/fallbacks.py +20 -13
  72. langchain_core/runnables/graph.py +48 -38
  73. langchain_core/runnables/graph_ascii.py +41 -18
  74. langchain_core/runnables/graph_mermaid.py +54 -25
  75. langchain_core/runnables/graph_png.py +27 -31
  76. langchain_core/runnables/history.py +55 -58
  77. langchain_core/runnables/passthrough.py +44 -21
  78. langchain_core/runnables/retry.py +44 -23
  79. langchain_core/runnables/router.py +9 -8
  80. langchain_core/runnables/schema.py +2 -0
  81. langchain_core/runnables/utils.py +51 -89
  82. langchain_core/stores.py +19 -31
  83. langchain_core/sys_info.py +9 -8
  84. langchain_core/tools/base.py +37 -28
  85. langchain_core/tools/convert.py +26 -15
  86. langchain_core/tools/simple.py +36 -8
  87. langchain_core/tools/structured.py +25 -12
  88. langchain_core/tracers/base.py +2 -2
  89. langchain_core/tracers/context.py +5 -1
  90. langchain_core/tracers/core.py +109 -39
  91. langchain_core/tracers/evaluation.py +22 -26
  92. langchain_core/tracers/event_stream.py +45 -34
  93. langchain_core/tracers/langchain.py +12 -3
  94. langchain_core/tracers/langchain_v1.py +10 -2
  95. langchain_core/tracers/log_stream.py +56 -17
  96. langchain_core/tracers/root_listeners.py +4 -20
  97. langchain_core/tracers/run_collector.py +6 -16
  98. langchain_core/tracers/schemas.py +5 -1
  99. langchain_core/utils/aiter.py +15 -7
  100. langchain_core/utils/env.py +3 -0
  101. langchain_core/utils/function_calling.py +50 -28
  102. langchain_core/utils/interactive_env.py +6 -2
  103. langchain_core/utils/iter.py +12 -4
  104. langchain_core/utils/json.py +12 -3
  105. langchain_core/utils/json_schema.py +156 -40
  106. langchain_core/utils/loading.py +5 -1
  107. langchain_core/utils/mustache.py +24 -15
  108. langchain_core/utils/pydantic.py +38 -9
  109. langchain_core/utils/utils.py +25 -9
  110. langchain_core/vectorstores/base.py +7 -20
  111. langchain_core/vectorstores/in_memory.py +23 -17
  112. langchain_core/vectorstores/utils.py +18 -12
  113. langchain_core/version.py +1 -1
  114. langchain_core-0.3.77.dist-info/METADATA +67 -0
  115. langchain_core-0.3.77.dist-info/RECORD +174 -0
  116. langchain_core-0.3.75.dist-info/METADATA +0 -106
  117. langchain_core-0.3.75.dist-info/RECORD +0 -174
  118. {langchain_core-0.3.75.dist-info → langchain_core-0.3.77.dist-info}/WHEEL +0 -0
  119. {langchain_core-0.3.75.dist-info → langchain_core-0.3.77.dist-info}/entry_points.txt +0 -0
@@ -5,6 +5,7 @@ Some examples of what you can do with these functions include:
5
5
  * Convert messages to strings (serialization)
6
6
  * Convert messages from dicts to Message objects (deserialization)
7
7
  * Filter messages from a list of messages based on name, type or id etc.
8
+
8
9
  """
9
10
 
10
11
  from __future__ import annotations
@@ -42,12 +43,17 @@ from langchain_core.messages.system import SystemMessage, SystemMessageChunk
42
43
  from langchain_core.messages.tool import ToolCall, ToolMessage, ToolMessageChunk
43
44
 
44
45
  if TYPE_CHECKING:
45
- from langchain_text_splitters import TextSplitter
46
-
47
46
  from langchain_core.language_models import BaseLanguageModel
48
47
  from langchain_core.prompt_values import PromptValue
49
48
  from langchain_core.runnables.base import Runnable
50
49
 
50
+ try:
51
+ from langchain_text_splitters import TextSplitter
52
+
53
+ _HAS_LANGCHAIN_TEXT_SPLITTERS = True
54
+ except ImportError:
55
+ _HAS_LANGCHAIN_TEXT_SPLITTERS = False
56
+
51
57
  logger = logging.getLogger(__name__)
52
58
 
53
59
 
@@ -86,13 +92,14 @@ AnyMessage = Annotated[
86
92
  def get_buffer_string(
87
93
  messages: Sequence[BaseMessage], human_prefix: str = "Human", ai_prefix: str = "AI"
88
94
  ) -> str:
89
- r"""Convert a sequence of Messages to strings and concatenate them into one string.
95
+ r"""Convert a sequence of messages to strings and concatenate them into one string.
90
96
 
91
97
  Args:
92
98
  messages: Messages to be converted to strings.
93
- human_prefix: The prefix to prepend to contents of HumanMessages.
94
- Default is "Human".
95
- ai_prefix: THe prefix to prepend to contents of AIMessages. Default is "AI".
99
+ human_prefix: The prefix to prepend to contents of ``HumanMessage``s.
100
+ Default is ``'Human'``.
101
+ ai_prefix: The prefix to prepend to contents of ``AIMessage``. Default is
102
+ ``'AI'``.
96
103
 
97
104
  Returns:
98
105
  A single string concatenation of all input messages.
@@ -171,19 +178,20 @@ def _message_from_dict(message: dict) -> BaseMessage:
171
178
 
172
179
 
173
180
  def messages_from_dict(messages: Sequence[dict]) -> list[BaseMessage]:
174
- """Convert a sequence of messages from dicts to Message objects.
181
+ """Convert a sequence of messages from dicts to ``Message`` objects.
175
182
 
176
183
  Args:
177
184
  messages: Sequence of messages (as dicts) to convert.
178
185
 
179
186
  Returns:
180
187
  list of messages (BaseMessages).
188
+
181
189
  """
182
190
  return [_message_from_dict(m) for m in messages]
183
191
 
184
192
 
185
- def message_chunk_to_message(chunk: BaseMessageChunk) -> BaseMessage:
186
- """Convert a message chunk to a message.
193
+ def message_chunk_to_message(chunk: BaseMessage) -> BaseMessage:
194
+ """Convert a message chunk to a ``Message``.
187
195
 
188
196
  Args:
189
197
  chunk: Message chunk to convert.
@@ -216,10 +224,10 @@ def _create_message_from_message_type(
216
224
  id: Optional[str] = None,
217
225
  **additional_kwargs: Any,
218
226
  ) -> BaseMessage:
219
- """Create a message from a message type and content string.
227
+ """Create a message from a ``Message`` type and content string.
220
228
 
221
229
  Args:
222
- message_type: (str) the type of the message (e.g., "human", "ai", etc.).
230
+ message_type: (str) the type of the message (e.g., ``'human'``, ``'ai'``, etc.).
223
231
  content: (str) the content string.
224
232
  name: (str) the name of the message. Default is None.
225
233
  tool_call_id: (str) the tool call id. Default is None.
@@ -231,8 +239,9 @@ def _create_message_from_message_type(
231
239
  a message of the appropriate type.
232
240
 
233
241
  Raises:
234
- ValueError: if the message type is not one of "human", "user", "ai",
235
- "assistant", "function", "tool", "system", or "developer".
242
+ ValueError: if the message type is not one of ``'human'``, ``'user'``, ``'ai'``,
243
+ ``'assistant'``, ``'function'``, ``'tool'``, ``'system'``, or
244
+ ``'developer'``.
236
245
  """
237
246
  kwargs: dict[str, Any] = {}
238
247
  if name is not None:
@@ -281,6 +290,9 @@ def _create_message_from_message_type(
281
290
  message = FunctionMessage(content=content, **kwargs)
282
291
  elif message_type == "tool":
283
292
  artifact = kwargs.get("additional_kwargs", {}).pop("artifact", None)
293
+ status = kwargs.get("additional_kwargs", {}).pop("status", None)
294
+ if status is not None:
295
+ kwargs["status"] = status
284
296
  message = ToolMessage(content=content, artifact=artifact, **kwargs)
285
297
  elif message_type == "remove":
286
298
  message = RemoveMessage(**kwargs)
@@ -295,15 +307,15 @@ def _create_message_from_message_type(
295
307
 
296
308
 
297
309
  def _convert_to_message(message: MessageLikeRepresentation) -> BaseMessage:
298
- """Instantiate a message from a variety of message formats.
310
+ """Instantiate a ``Message`` from a variety of message formats.
299
311
 
300
312
  The message format can be one of the following:
301
313
 
302
- - BaseMessagePromptTemplate
303
- - BaseMessage
304
- - 2-tuple of (role string, template); e.g., ("human", "{user_input}")
314
+ - ``BaseMessagePromptTemplate``
315
+ - ``BaseMessage``
316
+ - 2-tuple of (role string, template); e.g., (``'human'``, ``'{user_input}'``)
305
317
  - dict: a message dict with role and content keys
306
- - string: shorthand for ("human", template); e.g., "{user_input}"
318
+ - string: shorthand for (``'human'``, template); e.g., ``'{user_input}'``
307
319
 
308
320
  Args:
309
321
  message: a representation of a message in one of the supported formats.
@@ -314,6 +326,7 @@ def _convert_to_message(message: MessageLikeRepresentation) -> BaseMessage:
314
326
  Raises:
315
327
  NotImplementedError: if the message type is not supported.
316
328
  ValueError: if the message dict does not contain the required keys.
329
+
317
330
  """
318
331
  if isinstance(message, BaseMessage):
319
332
  message_ = message
@@ -359,9 +372,10 @@ def convert_to_messages(
359
372
 
360
373
  Returns:
361
374
  list of messages (BaseMessages).
375
+
362
376
  """
363
377
  # Import here to avoid circular imports
364
- from langchain_core.prompt_values import PromptValue
378
+ from langchain_core.prompt_values import PromptValue # noqa: PLC0415
365
379
 
366
380
  if isinstance(messages, PromptValue):
367
381
  return messages.to_messages()
@@ -386,7 +400,8 @@ def _runnable_support(func: Callable) -> Callable:
386
400
  list[BaseMessage],
387
401
  Runnable[Sequence[MessageLikeRepresentation], list[BaseMessage]],
388
402
  ]:
389
- from langchain_core.runnables.base import RunnableLambda
403
+ # Import locally to prevent circular import.
404
+ from langchain_core.runnables.base import RunnableLambda # noqa: PLC0415
390
405
 
391
406
  if messages is not None:
392
407
  return func(messages, **kwargs)
@@ -408,31 +423,36 @@ def filter_messages(
408
423
  exclude_ids: Optional[Sequence[str]] = None,
409
424
  exclude_tool_calls: Optional[Sequence[str] | bool] = None,
410
425
  ) -> list[BaseMessage]:
411
- """Filter messages based on name, type or id.
426
+ """Filter messages based on ``name``, ``type`` or ``id``.
412
427
 
413
428
  Args:
414
429
  messages: Sequence Message-like objects to filter.
415
430
  include_names: Message names to include. Default is None.
416
431
  exclude_names: Messages names to exclude. Default is None.
417
- include_types: Message types to include. Can be specified as string names (e.g.
418
- "system", "human", "ai", ...) or as BaseMessage classes (e.g.
419
- SystemMessage, HumanMessage, AIMessage, ...). Default is None.
420
- exclude_types: Message types to exclude. Can be specified as string names (e.g.
421
- "system", "human", "ai", ...) or as BaseMessage classes (e.g.
422
- SystemMessage, HumanMessage, AIMessage, ...). Default is None.
432
+ include_types: Message types to include. Can be specified as string names
433
+ (e.g. ``'system'``, ``'human'``, ``'ai'``, ...) or as ``BaseMessage``
434
+ classes (e.g. ``SystemMessage``, ``HumanMessage``, ``AIMessage``, ...).
435
+ Default is None.
436
+ exclude_types: Message types to exclude. Can be specified as string names
437
+ (e.g. ``'system'``, ``'human'``, ``'ai'``, ...) or as ``BaseMessage``
438
+ classes (e.g. ``SystemMessage``, ``HumanMessage``, ``AIMessage``, ...).
439
+ Default is None.
423
440
  include_ids: Message IDs to include. Default is None.
424
441
  exclude_ids: Message IDs to exclude. Default is None.
425
442
  exclude_tool_calls: Tool call IDs to exclude. Default is None.
426
443
  Can be one of the following:
427
- - `True`: all AIMessages with tool calls and all ToolMessages will be excluded.
444
+ - ``True``: all ``AIMessage``s with tool calls and all
445
+ ``ToolMessage``s will be excluded.
428
446
  - a sequence of tool call IDs to exclude:
429
- - ToolMessages with the corresponding tool call ID will be excluded.
430
- - The `tool_calls` in the AIMessage will be updated to exclude matching tool calls.
431
- If all tool_calls are filtered from an AIMessage, the whole message is excluded.
447
+ - ``ToolMessage``s with the corresponding tool call ID will be
448
+ excluded.
449
+ - The ``tool_calls`` in the AIMessage will be updated to exclude
450
+ matching tool calls. If all ``tool_calls`` are filtered from an
451
+ AIMessage, the whole message is excluded.
432
452
 
433
453
  Returns:
434
- A list of Messages that meets at least one of the incl_* conditions and none
435
- of the excl_* conditions. If not incl_* conditions are specified then
454
+ A list of Messages that meets at least one of the ``incl_*`` conditions and none
455
+ of the ``excl_*`` conditions. If not ``incl_*`` conditions are specified then
436
456
  anything that is not explicitly excluded will be included.
437
457
 
438
458
  Raises:
@@ -441,14 +461,25 @@ def filter_messages(
441
461
  Example:
442
462
  .. code-block:: python
443
463
 
444
- from langchain_core.messages import filter_messages, AIMessage, HumanMessage, SystemMessage
464
+ from langchain_core.messages import (
465
+ filter_messages,
466
+ AIMessage,
467
+ HumanMessage,
468
+ SystemMessage,
469
+ )
445
470
 
446
471
  messages = [
447
472
  SystemMessage("you're a good assistant."),
448
473
  HumanMessage("what's your name", id="foo", name="example_user"),
449
474
  AIMessage("steve-o", id="bar", name="example_assistant"),
450
- HumanMessage("what's your favorite color", id="baz",),
451
- AIMessage("silicon blue", id="blah",),
475
+ HumanMessage(
476
+ "what's your favorite color",
477
+ id="baz",
478
+ ),
479
+ AIMessage(
480
+ "silicon blue",
481
+ id="blah",
482
+ ),
452
483
  ]
453
484
 
454
485
  filter_messages(
@@ -465,7 +496,7 @@ def filter_messages(
465
496
  HumanMessage("what's your name", id="foo", name="example_user"),
466
497
  ]
467
498
 
468
- """ # noqa: E501
499
+ """
469
500
  messages = convert_to_messages(messages)
470
501
  filtered: list[BaseMessage] = []
471
502
  for msg in messages:
@@ -533,23 +564,26 @@ def merge_message_runs(
533
564
  ) -> list[BaseMessage]:
534
565
  r"""Merge consecutive Messages of the same type.
535
566
 
536
- **NOTE**: ToolMessages are not merged, as each has a distinct tool call id that
537
- can't be merged.
567
+ .. note::
568
+ ToolMessages are not merged, as each has a distinct tool call id that can't be
569
+ merged.
538
570
 
539
571
  Args:
540
572
  messages: Sequence Message-like objects to merge.
541
573
  chunk_separator: Specify the string to be inserted between message chunks.
542
- Default is "\n".
574
+ Default is ``'\n'``.
543
575
 
544
576
  Returns:
545
577
  list of BaseMessages with consecutive runs of message types merged into single
546
578
  messages. By default, if two messages being merged both have string contents,
547
- the merged content is a concatenation of the two strings with a new-line separator.
579
+ the merged content is a concatenation of the two strings with a new-line
580
+ separator.
548
581
  The separator inserted between message chunks can be controlled by specifying
549
- any string with ``chunk_separator``. If at least one of the messages has a list of
550
- content blocks, the merged content is a list of content blocks.
582
+ any string with ``chunk_separator``. If at least one of the messages has a list
583
+ of content blocks, the merged content is a list of content blocks.
551
584
 
552
585
  Example:
586
+
553
587
  .. code-block:: python
554
588
 
555
589
  from langchain_core.messages import (
@@ -562,16 +596,33 @@ def merge_message_runs(
562
596
 
563
597
  messages = [
564
598
  SystemMessage("you're a good assistant."),
565
- HumanMessage("what's your favorite color", id="foo",),
566
- HumanMessage("wait your favorite food", id="bar",),
599
+ HumanMessage(
600
+ "what's your favorite color",
601
+ id="foo",
602
+ ),
603
+ HumanMessage(
604
+ "wait your favorite food",
605
+ id="bar",
606
+ ),
567
607
  AIMessage(
568
608
  "my favorite colo",
569
- tool_calls=[ToolCall(name="blah_tool", args={"x": 2}, id="123", type="tool_call")],
609
+ tool_calls=[
610
+ ToolCall(
611
+ name="blah_tool", args={"x": 2}, id="123", type="tool_call"
612
+ )
613
+ ],
570
614
  id="baz",
571
615
  ),
572
616
  AIMessage(
573
617
  [{"type": "text", "text": "my favorite dish is lasagna"}],
574
- tool_calls=[ToolCall(name="blah_tool", args={"x": -10}, id="456", type="tool_call")],
618
+ tool_calls=[
619
+ ToolCall(
620
+ name="blah_tool",
621
+ args={"x": -10},
622
+ id="456",
623
+ type="tool_call",
624
+ )
625
+ ],
575
626
  id="blur",
576
627
  ),
577
628
  ]
@@ -582,21 +633,34 @@ def merge_message_runs(
582
633
 
583
634
  [
584
635
  SystemMessage("you're a good assistant."),
585
- HumanMessage("what's your favorite color\\nwait your favorite food", id="foo",),
636
+ HumanMessage(
637
+ "what's your favorite color\\n"
638
+ "wait your favorite food", id="foo",
639
+ ),
586
640
  AIMessage(
587
641
  [
588
642
  "my favorite colo",
589
643
  {"type": "text", "text": "my favorite dish is lasagna"}
590
644
  ],
591
645
  tool_calls=[
592
- ToolCall({"name": "blah_tool", "args": {"x": 2}, "id": "123", "type": "tool_call"}),
593
- ToolCall({"name": "blah_tool", "args": {"x": -10}, "id": "456", "type": "tool_call"})
646
+ ToolCall({
647
+ "name": "blah_tool",
648
+ "args": {"x": 2},
649
+ "id": "123",
650
+ "type": "tool_call"
651
+ }),
652
+ ToolCall({
653
+ "name": "blah_tool",
654
+ "args": {"x": -10},
655
+ "id": "456",
656
+ "type": "tool_call"
657
+ })
594
658
  ]
595
659
  id="baz"
596
660
  ),
597
661
  ]
598
662
 
599
- """ # noqa: E501
663
+ """
600
664
  if not messages:
601
665
  return []
602
666
  messages = convert_to_messages(messages)
@@ -648,22 +712,22 @@ def trim_messages(
648
712
  ) -> list[BaseMessage]:
649
713
  r"""Trim messages to be below a token count.
650
714
 
651
- trim_messages can be used to reduce the size of a chat history to a specified token
652
- count or specified message count.
715
+ ``trim_messages`` can be used to reduce the size of a chat history to a specified
716
+ token count or specified message count.
653
717
 
654
718
  In either case, if passing the trimmed chat history back into a chat model
655
719
  directly, the resulting chat history should usually satisfy the following
656
720
  properties:
657
721
 
658
722
  1. The resulting chat history should be valid. Most chat models expect that chat
659
- history starts with either (1) a ``HumanMessage`` or (2) a ``SystemMessage`` followed
660
- by a ``HumanMessage``. To achieve this, set ``start_on="human"``.
723
+ history starts with either (1) a ``HumanMessage`` or (2) a ``SystemMessage``
724
+ followed by a ``HumanMessage``. To achieve this, set ``start_on='human'``.
661
725
  In addition, generally a ``ToolMessage`` can only appear after an ``AIMessage``
662
726
  that involved a tool call.
663
727
  Please see the following link for more information about messages:
664
728
  https://python.langchain.com/docs/concepts/#messages
665
729
  2. It includes recent messages and drops old messages in the chat history.
666
- To achieve this set the ``strategy="last"``.
730
+ To achieve this set the ``strategy='last'``.
667
731
  3. Usually, the new chat history should include the ``SystemMessage`` if it
668
732
  was present in the original chat history since the ``SystemMessage`` includes
669
733
  special instructions to the chat model. The ``SystemMessage`` is almost always
@@ -677,65 +741,67 @@ def trim_messages(
677
741
  Args:
678
742
  messages: Sequence of Message-like objects to trim.
679
743
  max_tokens: Max token count of trimmed messages.
680
- token_counter: Function or llm for counting tokens in a BaseMessage or a list of
681
- BaseMessage. If a BaseLanguageModel is passed in then
682
- BaseLanguageModel.get_num_tokens_from_messages() will be used.
683
- Set to `len` to count the number of **messages** in the chat history.
744
+ token_counter: Function or llm for counting tokens in a ``BaseMessage`` or a
745
+ list of ``BaseMessage``. If a ``BaseLanguageModel`` is passed in then
746
+ ``BaseLanguageModel.get_num_tokens_from_messages()`` will be used.
747
+ Set to ``len`` to count the number of **messages** in the chat history.
684
748
 
685
749
  .. note::
686
- Use `count_tokens_approximately` to get fast, approximate token counts.
687
- This is recommended for using `trim_messages` on the hot path, where
750
+ Use ``count_tokens_approximately`` to get fast, approximate token
751
+ counts.
752
+ This is recommended for using ``trim_messages`` on the hot path, where
688
753
  exact token counting is not necessary.
689
754
 
690
755
  strategy: Strategy for trimming.
691
- - "first": Keep the first <= n_count tokens of the messages.
692
- - "last": Keep the last <= n_count tokens of the messages.
693
- Default is "last".
756
+ - ``'first'``: Keep the first ``<= n_count`` tokens of the messages.
757
+ - ``'last'``: Keep the last ``<= n_count`` tokens of the messages.
758
+ Default is ``'last'``.
694
759
  allow_partial: Whether to split a message if only part of the message can be
695
- included. If ``strategy="last"`` then the last partial contents of a message
696
- are included. If ``strategy="first"`` then the first partial contents of a
760
+ included. If ``strategy='last'`` then the last partial contents of a message
761
+ are included. If ``strategy='first'`` then the first partial contents of a
697
762
  message are included.
698
763
  Default is False.
699
764
  end_on: The message type to end on. If specified then every message after the
700
- last occurrence of this type is ignored. If ``strategy=="last"`` then this
765
+ last occurrence of this type is ignored. If ``strategy='last'`` then this
701
766
  is done before we attempt to get the last ``max_tokens``. If
702
- ``strategy=="first"`` then this is done after we get the first
703
- ``max_tokens``. Can be specified as string names (e.g. "system", "human",
704
- "ai", ...) or as BaseMessage classes (e.g. SystemMessage, HumanMessage,
705
- AIMessage, ...). Can be a single type or a list of types.
767
+ ``strategy='first'`` then this is done after we get the first
768
+ ``max_tokens``. Can be specified as string names (e.g. ``'system'``,
769
+ ``'human'``, ``'ai'``, ...) or as ``BaseMessage`` classes (e.g.
770
+ ``SystemMessage``, ``HumanMessage``, ``AIMessage``, ...). Can be a single
771
+ type or a list of types.
706
772
  Default is None.
707
773
  start_on: The message type to start on. Should only be specified if
708
- ``strategy="last"``. If specified then every message before
774
+ ``strategy='last'``. If specified then every message before
709
775
  the first occurrence of this type is ignored. This is done after we trim
710
776
  the initial messages to the last ``max_tokens``. Does not
711
- apply to a SystemMessage at index 0 if ``include_system=True``. Can be
712
- specified as string names (e.g. "system", "human", "ai", ...) or as
713
- BaseMessage classes (e.g. SystemMessage, HumanMessage, AIMessage, ...). Can
714
- be a single type or a list of types.
777
+ apply to a ``SystemMessage`` at index 0 if ``include_system=True``. Can be
778
+ specified as string names (e.g. ``'system'``, ``'human'``, ``'ai'``, ...) or
779
+ as ``BaseMessage`` classes (e.g. ``SystemMessage``, ``HumanMessage``,
780
+ ``AIMessage``, ...). Can be a single type or a list of types.
715
781
  Default is None.
716
782
  include_system: Whether to keep the SystemMessage if there is one at index 0.
717
783
  Should only be specified if ``strategy="last"``.
718
784
  Default is False.
719
785
  text_splitter: Function or ``langchain_text_splitters.TextSplitter`` for
720
786
  splitting the string contents of a message. Only used if
721
- ``allow_partial=True``. If ``strategy="last"`` then the last split tokens
722
- from a partial message will be included. if ``strategy=="first"`` then the
787
+ ``allow_partial=True``. If ``strategy='last'`` then the last split tokens
788
+ from a partial message will be included. if ``strategy='first'`` then the
723
789
  first split tokens from a partial message will be included. Token splitter
724
790
  assumes that separators are kept, so that split contents can be directly
725
791
  concatenated to recreate the original text. Defaults to splitting on
726
792
  newlines.
727
793
 
728
794
  Returns:
729
- list of trimmed BaseMessages.
795
+ list of trimmed ``BaseMessage``.
730
796
 
731
797
  Raises:
732
798
  ValueError: if two incompatible arguments are specified or an unrecognized
733
799
  ``strategy`` is specified.
734
800
 
735
801
  Example:
736
- Trim chat history based on token count, keeping the SystemMessage if
737
- present, and ensuring that the chat history starts with a HumanMessage (
738
- or a SystemMessage followed by a HumanMessage).
802
+ Trim chat history based on token count, keeping the ``SystemMessage`` if
803
+ present, and ensuring that the chat history starts with a ``HumanMessage`` (
804
+ or a ``SystemMessage`` followed by a ``HumanMessage``).
739
805
 
740
806
  .. code-block:: python
741
807
 
@@ -748,14 +814,18 @@ def trim_messages(
748
814
  )
749
815
 
750
816
  messages = [
751
- SystemMessage("you're a good assistant, you always respond with a joke."),
817
+ SystemMessage(
818
+ "you're a good assistant, you always respond with a joke."
819
+ ),
752
820
  HumanMessage("i wonder why it's called langchain"),
753
821
  AIMessage(
754
- 'Well, I guess they thought "WordRope" and "SentenceString" just didn\'t have the same ring to it!'
822
+ 'Well, I guess they thought "WordRope" and "SentenceString" just '
823
+ "didn't have the same ring to it!"
755
824
  ),
756
825
  HumanMessage("and who is harrison chasing anyways"),
757
826
  AIMessage(
758
- "Hmmm let me think.\n\nWhy, he's probably chasing after the last cup of coffee in the office!"
827
+ "Hmmm let me think.\n\nWhy, he's probably chasing after the last "
828
+ "cup of coffee in the office!"
759
829
  ),
760
830
  HumanMessage("what do you call a speechless parrot"),
761
831
  ]
@@ -780,13 +850,15 @@ def trim_messages(
780
850
  .. code-block:: python
781
851
 
782
852
  [
783
- SystemMessage(content="you're a good assistant, you always respond with a joke."),
784
- HumanMessage(content='what do you call a speechless parrot'),
853
+ SystemMessage(
854
+ content="you're a good assistant, you always respond with a joke."
855
+ ),
856
+ HumanMessage(content="what do you call a speechless parrot"),
785
857
  ]
786
858
 
787
- Trim chat history based on the message count, keeping the SystemMessage if
788
- present, and ensuring that the chat history starts with a HumanMessage (
789
- or a SystemMessage followed by a HumanMessage).
859
+ Trim chat history based on the message count, keeping the ``SystemMessage`` if
860
+ present, and ensuring that the chat history starts with a ``HumanMessage`` (
861
+ or a ``SystemMessage`` followed by a ``HumanMessage``).
790
862
 
791
863
  trim_messages(
792
864
  messages,
@@ -811,10 +883,15 @@ def trim_messages(
811
883
  .. code-block:: python
812
884
 
813
885
  [
814
- SystemMessage(content="you're a good assistant, you always respond with a joke."),
815
- HumanMessage(content='and who is harrison chasing anyways'),
816
- AIMessage(content="Hmmm let me think.\n\nWhy, he's probably chasing after the last cup of coffee in the office!"),
817
- HumanMessage(content='what do you call a speechless parrot'),
886
+ SystemMessage(
887
+ content="you're a good assistant, you always respond with a joke."
888
+ ),
889
+ HumanMessage(content="and who is harrison chasing anyways"),
890
+ AIMessage(
891
+ content="Hmmm let me think.\n\nWhy, he's probably chasing after "
892
+ "the last cup of coffee in the office!"
893
+ ),
894
+ HumanMessage(content="what do you call a speechless parrot"),
818
895
  ]
819
896
 
820
897
 
@@ -825,7 +902,9 @@ def trim_messages(
825
902
 
826
903
  messages = [
827
904
  SystemMessage("This is a 4 token text. The full message is 10 tokens."),
828
- HumanMessage("This is a 4 token text. The full message is 10 tokens.", id="first"),
905
+ HumanMessage(
906
+ "This is a 4 token text. The full message is 10 tokens.", id="first"
907
+ ),
829
908
  AIMessage(
830
909
  [
831
910
  {"type": "text", "text": "This is the FIRST 4 token block."},
@@ -833,10 +912,16 @@ def trim_messages(
833
912
  ],
834
913
  id="second",
835
914
  ),
836
- HumanMessage("This is a 4 token text. The full message is 10 tokens.", id="third"),
837
- AIMessage("This is a 4 token text. The full message is 10 tokens.", id="fourth"),
915
+ HumanMessage(
916
+ "This is a 4 token text. The full message is 10 tokens.", id="third"
917
+ ),
918
+ AIMessage(
919
+ "This is a 4 token text. The full message is 10 tokens.",
920
+ id="fourth",
921
+ ),
838
922
  ]
839
923
 
924
+
840
925
  def dummy_token_counter(messages: list[BaseMessage]) -> int:
841
926
  # treat each message like it adds 3 default tokens at the beginning
842
927
  # of the message and at the end of the message. 3 + 4 + 3 = 10 tokens
@@ -849,9 +934,17 @@ def trim_messages(
849
934
  count = 0
850
935
  for msg in messages:
851
936
  if isinstance(msg.content, str):
852
- count += default_msg_prefix_len + default_content_len + default_msg_suffix_len
937
+ count += (
938
+ default_msg_prefix_len
939
+ + default_content_len
940
+ + default_msg_suffix_len
941
+ )
853
942
  if isinstance(msg.content, list):
854
- count += default_msg_prefix_len + len(msg.content) * default_content_len + default_msg_suffix_len
943
+ count += (
944
+ default_msg_prefix_len
945
+ + len(msg.content) * default_content_len
946
+ + default_msg_suffix_len
947
+ )
855
948
  return count
856
949
 
857
950
  First 30 tokens, allowing partial messages:
@@ -868,12 +961,20 @@ def trim_messages(
868
961
  .. code-block:: python
869
962
 
870
963
  [
871
- SystemMessage("This is a 4 token text. The full message is 10 tokens."),
872
- HumanMessage("This is a 4 token text. The full message is 10 tokens.", id="first"),
873
- AIMessage( [{"type": "text", "text": "This is the FIRST 4 token block."}], id="second"),
964
+ SystemMessage(
965
+ "This is a 4 token text. The full message is 10 tokens."
966
+ ),
967
+ HumanMessage(
968
+ "This is a 4 token text. The full message is 10 tokens.",
969
+ id="first",
970
+ ),
971
+ AIMessage(
972
+ [{"type": "text", "text": "This is the FIRST 4 token block."}],
973
+ id="second",
974
+ ),
874
975
  ]
875
976
 
876
- """ # noqa: E501
977
+ """
877
978
  # Validate arguments
878
979
  if start_on and strategy == "first":
879
980
  msg = "start_on parameter is only valid with strategy='last'"
@@ -904,17 +1005,12 @@ def trim_messages(
904
1005
  )
905
1006
  raise ValueError(msg)
906
1007
 
907
- try:
908
- from langchain_text_splitters import TextSplitter
909
- except ImportError:
910
- text_splitter_fn: Optional[Callable] = cast("Optional[Callable]", text_splitter)
1008
+ if _HAS_LANGCHAIN_TEXT_SPLITTERS and isinstance(text_splitter, TextSplitter):
1009
+ text_splitter_fn = text_splitter.split_text
1010
+ elif text_splitter:
1011
+ text_splitter_fn = cast("Callable", text_splitter)
911
1012
  else:
912
- if isinstance(text_splitter, TextSplitter):
913
- text_splitter_fn = text_splitter.split_text
914
- else:
915
- text_splitter_fn = text_splitter
916
-
917
- text_splitter_fn = text_splitter_fn or _default_text_splitter
1013
+ text_splitter_fn = _default_text_splitter
918
1014
 
919
1015
  if strategy == "first":
920
1016
  return _first_max_tokens(
@@ -951,26 +1047,30 @@ def convert_to_openai_messages(
951
1047
  messages: Message-like object or iterable of objects whose contents are
952
1048
  in OpenAI, Anthropic, Bedrock Converse, or VertexAI formats.
953
1049
  text_format: How to format string or text block contents:
954
-
955
- - "string":
1050
+ - ``'string'``:
956
1051
  If a message has a string content, this is left as a string. If
957
- a message has content blocks that are all of type 'text', these are
958
- joined with a newline to make a single string. If a message has
959
- content blocks and at least one isn't of type 'text', then
1052
+ a message has content blocks that are all of type ``'text'``, these
1053
+ are joined with a newline to make a single string. If a message has
1054
+ content blocks and at least one isn't of type ``'text'``, then
960
1055
  all blocks are left as dicts.
961
- - "block":
1056
+ - ``'block'``:
962
1057
  If a message has a string content, this is turned into a list
963
- with a single content block of type 'text'. If a message has content
964
- blocks these are left as is.
1058
+ with a single content block of type ``'text'``. If a message has
1059
+ content blocks these are left as is.
1060
+
1061
+ Raises:
1062
+ ValueError: if an unrecognized ``text_format`` is specified, or if a message
1063
+ content block is missing expected keys.
965
1064
 
966
1065
  Returns:
967
1066
  The return type depends on the input type:
968
- - dict:
969
- If a single message-like object is passed in, a single OpenAI message
970
- dict is returned.
971
- - list[dict]:
972
- If a sequence of message-like objects are passed in, a list of OpenAI
973
- message dicts is returned.
1067
+
1068
+ - dict:
1069
+ If a single message-like object is passed in, a single OpenAI message
1070
+ dict is returned.
1071
+ - list[dict]:
1072
+ If a sequence of message-like objects are passed in, a list of OpenAI
1073
+ message dicts is returned.
974
1074
 
975
1075
  Example:
976
1076
 
@@ -985,8 +1085,27 @@ def convert_to_openai_messages(
985
1085
 
986
1086
  messages = [
987
1087
  SystemMessage([{"type": "text", "text": "foo"}]),
988
- {"role": "user", "content": [{"type": "text", "text": "whats in this"}, {"type": "image_url", "image_url": {"url": "data:image/png;base64,'/9j/4AAQSk'"}}]},
989
- AIMessage("", tool_calls=[{"name": "analyze", "args": {"baz": "buz"}, "id": "1", "type": "tool_call"}]),
1088
+ {
1089
+ "role": "user",
1090
+ "content": [
1091
+ {"type": "text", "text": "whats in this"},
1092
+ {
1093
+ "type": "image_url",
1094
+ "image_url": {"url": "data:image/png;base64,'/9j/4AAQSk'"},
1095
+ },
1096
+ ],
1097
+ },
1098
+ AIMessage(
1099
+ "",
1100
+ tool_calls=[
1101
+ {
1102
+ "name": "analyze",
1103
+ "args": {"baz": "buz"},
1104
+ "id": "1",
1105
+ "type": "tool_call",
1106
+ }
1107
+ ],
1108
+ ),
990
1109
  ToolMessage("foobar", tool_call_id="1", name="bar"),
991
1110
  {"role": "assistant", "content": "thats nice"},
992
1111
  ]
@@ -1266,7 +1385,7 @@ def convert_to_openai_messages(
1266
1385
  },
1267
1386
  }
1268
1387
  )
1269
- elif block.get("type") == "thinking":
1388
+ elif block.get("type") in ["thinking", "reasoning"]:
1270
1389
  content.append(block)
1271
1390
  else:
1272
1391
  err = (