langchain-core 1.0.0a2__py3-none-any.whl → 1.0.0a3__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 (130) hide show
  1. langchain_core/_api/beta_decorator.py +17 -40
  2. langchain_core/_api/deprecation.py +20 -7
  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/callbacks/base.py +28 -15
  7. langchain_core/callbacks/manager.py +81 -69
  8. langchain_core/callbacks/usage.py +4 -2
  9. langchain_core/chat_history.py +29 -21
  10. langchain_core/document_loaders/base.py +34 -9
  11. langchain_core/document_loaders/langsmith.py +3 -0
  12. langchain_core/documents/base.py +35 -10
  13. langchain_core/documents/transformers.py +4 -2
  14. langchain_core/embeddings/fake.py +8 -5
  15. langchain_core/env.py +2 -3
  16. langchain_core/example_selectors/base.py +12 -0
  17. langchain_core/exceptions.py +7 -0
  18. langchain_core/globals.py +17 -28
  19. langchain_core/indexing/api.py +57 -45
  20. langchain_core/indexing/base.py +5 -8
  21. langchain_core/indexing/in_memory.py +23 -3
  22. langchain_core/language_models/__init__.py +6 -2
  23. langchain_core/language_models/_utils.py +27 -5
  24. langchain_core/language_models/base.py +33 -21
  25. langchain_core/language_models/chat_models.py +99 -27
  26. langchain_core/language_models/fake_chat_models.py +5 -7
  27. langchain_core/language_models/llms.py +54 -20
  28. langchain_core/load/dump.py +2 -3
  29. langchain_core/load/load.py +15 -1
  30. langchain_core/load/serializable.py +38 -43
  31. langchain_core/memory.py +7 -3
  32. langchain_core/messages/__init__.py +1 -1
  33. langchain_core/messages/ai.py +41 -34
  34. langchain_core/messages/base.py +16 -7
  35. langchain_core/messages/block_translators/__init__.py +10 -8
  36. langchain_core/messages/block_translators/anthropic.py +3 -1
  37. langchain_core/messages/block_translators/bedrock.py +3 -1
  38. langchain_core/messages/block_translators/bedrock_converse.py +3 -1
  39. langchain_core/messages/block_translators/google_genai.py +3 -1
  40. langchain_core/messages/block_translators/google_vertexai.py +3 -1
  41. langchain_core/messages/block_translators/groq.py +3 -1
  42. langchain_core/messages/block_translators/ollama.py +3 -1
  43. langchain_core/messages/block_translators/openai.py +50 -20
  44. langchain_core/messages/content.py +23 -13
  45. langchain_core/messages/human.py +2 -13
  46. langchain_core/messages/system.py +2 -6
  47. langchain_core/messages/tool.py +34 -14
  48. langchain_core/messages/utils.py +186 -73
  49. langchain_core/output_parsers/base.py +5 -2
  50. langchain_core/output_parsers/json.py +4 -4
  51. langchain_core/output_parsers/list.py +7 -22
  52. langchain_core/output_parsers/openai_functions.py +3 -0
  53. langchain_core/output_parsers/openai_tools.py +6 -1
  54. langchain_core/output_parsers/pydantic.py +4 -0
  55. langchain_core/output_parsers/string.py +5 -1
  56. langchain_core/output_parsers/xml.py +19 -19
  57. langchain_core/outputs/chat_generation.py +18 -7
  58. langchain_core/outputs/generation.py +14 -3
  59. langchain_core/outputs/llm_result.py +8 -1
  60. langchain_core/prompt_values.py +10 -4
  61. langchain_core/prompts/base.py +6 -11
  62. langchain_core/prompts/chat.py +88 -60
  63. langchain_core/prompts/dict.py +16 -8
  64. langchain_core/prompts/few_shot.py +9 -11
  65. langchain_core/prompts/few_shot_with_templates.py +5 -1
  66. langchain_core/prompts/image.py +12 -5
  67. langchain_core/prompts/loading.py +2 -2
  68. langchain_core/prompts/message.py +5 -6
  69. langchain_core/prompts/pipeline.py +13 -8
  70. langchain_core/prompts/prompt.py +22 -8
  71. langchain_core/prompts/string.py +18 -10
  72. langchain_core/prompts/structured.py +7 -2
  73. langchain_core/rate_limiters.py +2 -2
  74. langchain_core/retrievers.py +7 -6
  75. langchain_core/runnables/base.py +387 -246
  76. langchain_core/runnables/branch.py +11 -28
  77. langchain_core/runnables/config.py +20 -17
  78. langchain_core/runnables/configurable.py +34 -19
  79. langchain_core/runnables/fallbacks.py +20 -13
  80. langchain_core/runnables/graph.py +48 -38
  81. langchain_core/runnables/graph_ascii.py +40 -17
  82. langchain_core/runnables/graph_mermaid.py +54 -25
  83. langchain_core/runnables/graph_png.py +27 -31
  84. langchain_core/runnables/history.py +55 -58
  85. langchain_core/runnables/passthrough.py +44 -21
  86. langchain_core/runnables/retry.py +44 -23
  87. langchain_core/runnables/router.py +9 -8
  88. langchain_core/runnables/schema.py +9 -0
  89. langchain_core/runnables/utils.py +53 -90
  90. langchain_core/stores.py +19 -31
  91. langchain_core/sys_info.py +9 -8
  92. langchain_core/tools/base.py +36 -27
  93. langchain_core/tools/convert.py +25 -14
  94. langchain_core/tools/simple.py +36 -8
  95. langchain_core/tools/structured.py +25 -12
  96. langchain_core/tracers/base.py +2 -2
  97. langchain_core/tracers/context.py +5 -1
  98. langchain_core/tracers/core.py +110 -46
  99. langchain_core/tracers/evaluation.py +22 -26
  100. langchain_core/tracers/event_stream.py +97 -42
  101. langchain_core/tracers/langchain.py +12 -3
  102. langchain_core/tracers/langchain_v1.py +10 -2
  103. langchain_core/tracers/log_stream.py +56 -17
  104. langchain_core/tracers/root_listeners.py +4 -20
  105. langchain_core/tracers/run_collector.py +6 -16
  106. langchain_core/tracers/schemas.py +5 -1
  107. langchain_core/utils/aiter.py +14 -6
  108. langchain_core/utils/env.py +3 -0
  109. langchain_core/utils/function_calling.py +46 -20
  110. langchain_core/utils/interactive_env.py +6 -2
  111. langchain_core/utils/iter.py +12 -5
  112. langchain_core/utils/json.py +12 -3
  113. langchain_core/utils/json_schema.py +156 -40
  114. langchain_core/utils/loading.py +5 -1
  115. langchain_core/utils/mustache.py +25 -16
  116. langchain_core/utils/pydantic.py +38 -9
  117. langchain_core/utils/utils.py +25 -9
  118. langchain_core/vectorstores/base.py +7 -20
  119. langchain_core/vectorstores/in_memory.py +20 -14
  120. langchain_core/vectorstores/utils.py +18 -12
  121. langchain_core/version.py +1 -1
  122. langchain_core-1.0.0a3.dist-info/METADATA +77 -0
  123. langchain_core-1.0.0a3.dist-info/RECORD +181 -0
  124. langchain_core/beta/__init__.py +0 -1
  125. langchain_core/beta/runnables/__init__.py +0 -1
  126. langchain_core/beta/runnables/context.py +0 -448
  127. langchain_core-1.0.0a2.dist-info/METADATA +0 -106
  128. langchain_core-1.0.0a2.dist-info/RECORD +0 -184
  129. {langchain_core-1.0.0a2.dist-info → langchain_core-1.0.0a3.dist-info}/WHEEL +0 -0
  130. {langchain_core-1.0.0a2.dist-info → langchain_core-1.0.0a3.dist-info}/entry_points.txt +0 -0
@@ -47,12 +47,17 @@ from langchain_core.messages.system import SystemMessage, SystemMessageChunk
47
47
  from langchain_core.messages.tool import ToolCall, ToolMessage, ToolMessageChunk
48
48
 
49
49
  if TYPE_CHECKING:
50
- from langchain_text_splitters import TextSplitter
51
-
52
50
  from langchain_core.language_models import BaseLanguageModel
53
51
  from langchain_core.prompt_values import PromptValue
54
52
  from langchain_core.runnables.base import Runnable
55
53
 
54
+ try:
55
+ from langchain_text_splitters import TextSplitter
56
+
57
+ _HAS_LANGCHAIN_TEXT_SPLITTERS = True
58
+ except ImportError:
59
+ _HAS_LANGCHAIN_TEXT_SPLITTERS = False
60
+
56
61
  logger = logging.getLogger(__name__)
57
62
 
58
63
 
@@ -97,7 +102,7 @@ def get_buffer_string(
97
102
  messages: Messages to be converted to strings.
98
103
  human_prefix: The prefix to prepend to contents of HumanMessages.
99
104
  Default is "Human".
100
- ai_prefix: THe prefix to prepend to contents of AIMessages. Default is "AI".
105
+ ai_prefix: The prefix to prepend to contents of AIMessages. Default is "AI".
101
106
 
102
107
  Returns:
103
108
  A single string concatenation of all input messages.
@@ -187,7 +192,7 @@ def messages_from_dict(messages: Sequence[dict]) -> list[BaseMessage]:
187
192
  return [_message_from_dict(m) for m in messages]
188
193
 
189
194
 
190
- def message_chunk_to_message(chunk: BaseMessageChunk) -> BaseMessage:
195
+ def message_chunk_to_message(chunk: BaseMessage) -> BaseMessage:
191
196
  """Convert a message chunk to a message.
192
197
 
193
198
  Args:
@@ -286,6 +291,9 @@ def _create_message_from_message_type(
286
291
  message = FunctionMessage(content=content, **kwargs)
287
292
  elif message_type == "tool":
288
293
  artifact = kwargs.get("additional_kwargs", {}).pop("artifact", None)
294
+ status = kwargs.get("additional_kwargs", {}).pop("status", None)
295
+ if status is not None:
296
+ kwargs["status"] = status
289
297
  message = ToolMessage(content=content, artifact=artifact, **kwargs)
290
298
  elif message_type == "remove":
291
299
  message = RemoveMessage(**kwargs)
@@ -366,7 +374,7 @@ def convert_to_messages(
366
374
  list of messages (BaseMessages).
367
375
  """
368
376
  # Import here to avoid circular imports
369
- from langchain_core.prompt_values import PromptValue
377
+ from langchain_core.prompt_values import PromptValue # noqa: PLC0415
370
378
 
371
379
  if isinstance(messages, PromptValue):
372
380
  return messages.to_messages()
@@ -391,7 +399,8 @@ def _runnable_support(func: Callable) -> Callable:
391
399
  list[BaseMessage],
392
400
  Runnable[Sequence[MessageLikeRepresentation], list[BaseMessage]],
393
401
  ]:
394
- from langchain_core.runnables.base import RunnableLambda
402
+ # Import locally to prevent circular import.
403
+ from langchain_core.runnables.base import RunnableLambda # noqa: PLC0415
395
404
 
396
405
  if messages is not None:
397
406
  return func(messages, **kwargs)
@@ -429,11 +438,16 @@ def filter_messages(
429
438
  exclude_ids: Message IDs to exclude. Default is None.
430
439
  exclude_tool_calls: Tool call IDs to exclude. Default is None.
431
440
  Can be one of the following:
432
- - `True`: all AIMessages with tool calls and all ToolMessages will be excluded.
441
+
442
+ - ``True``: Each ``AIMessages`` with tool calls and all ``ToolMessages``
443
+ will be excluded.
433
444
  - a sequence of tool call IDs to exclude:
445
+
434
446
  - ToolMessages with the corresponding tool call ID will be excluded.
435
- - The `tool_calls` in the AIMessage will be updated to exclude matching tool calls.
436
- If all tool_calls are filtered from an AIMessage, the whole message is excluded.
447
+ - The ``tool_calls`` in the AIMessage will be updated to exclude matching
448
+ tool calls.
449
+ If all tool_calls are filtered from an AIMessage,
450
+ the whole message is excluded.
437
451
 
438
452
  Returns:
439
453
  A list of Messages that meets at least one of the incl_* conditions and none
@@ -446,14 +460,25 @@ def filter_messages(
446
460
  Example:
447
461
  .. code-block:: python
448
462
 
449
- from langchain_core.messages import filter_messages, AIMessage, HumanMessage, SystemMessage
463
+ from langchain_core.messages import (
464
+ filter_messages,
465
+ AIMessage,
466
+ HumanMessage,
467
+ SystemMessage,
468
+ )
450
469
 
451
470
  messages = [
452
471
  SystemMessage("you're a good assistant."),
453
472
  HumanMessage("what's your name", id="foo", name="example_user"),
454
473
  AIMessage("steve-o", id="bar", name="example_assistant"),
455
- HumanMessage("what's your favorite color", id="baz",),
456
- AIMessage("silicon blue", id="blah",),
474
+ HumanMessage(
475
+ "what's your favorite color",
476
+ id="baz",
477
+ ),
478
+ AIMessage(
479
+ "silicon blue",
480
+ id="blah",
481
+ ),
457
482
  ]
458
483
 
459
484
  filter_messages(
@@ -470,7 +495,7 @@ def filter_messages(
470
495
  HumanMessage("what's your name", id="foo", name="example_user"),
471
496
  ]
472
497
 
473
- """ # noqa: E501
498
+ """
474
499
  messages = convert_to_messages(messages)
475
500
  filtered: list[BaseMessage] = []
476
501
  for msg in messages:
@@ -549,12 +574,14 @@ def merge_message_runs(
549
574
  Returns:
550
575
  list of BaseMessages with consecutive runs of message types merged into single
551
576
  messages. By default, if two messages being merged both have string contents,
552
- the merged content is a concatenation of the two strings with a new-line separator.
577
+ the merged content is a concatenation of the two strings with a new-line
578
+ separator.
553
579
  The separator inserted between message chunks can be controlled by specifying
554
- any string with ``chunk_separator``. If at least one of the messages has a list of
555
- content blocks, the merged content is a list of content blocks.
580
+ any string with ``chunk_separator``. If at least one of the messages has a list
581
+ of content blocks, the merged content is a list of content blocks.
556
582
 
557
583
  Example:
584
+
558
585
  .. code-block:: python
559
586
 
560
587
  from langchain_core.messages import (
@@ -567,16 +594,33 @@ def merge_message_runs(
567
594
 
568
595
  messages = [
569
596
  SystemMessage("you're a good assistant."),
570
- HumanMessage("what's your favorite color", id="foo",),
571
- HumanMessage("wait your favorite food", id="bar",),
597
+ HumanMessage(
598
+ "what's your favorite color",
599
+ id="foo",
600
+ ),
601
+ HumanMessage(
602
+ "wait your favorite food",
603
+ id="bar",
604
+ ),
572
605
  AIMessage(
573
606
  "my favorite colo",
574
- tool_calls=[ToolCall(name="blah_tool", args={"x": 2}, id="123", type="tool_call")],
607
+ tool_calls=[
608
+ ToolCall(
609
+ name="blah_tool", args={"x": 2}, id="123", type="tool_call"
610
+ )
611
+ ],
575
612
  id="baz",
576
613
  ),
577
614
  AIMessage(
578
615
  [{"type": "text", "text": "my favorite dish is lasagna"}],
579
- tool_calls=[ToolCall(name="blah_tool", args={"x": -10}, id="456", type="tool_call")],
616
+ tool_calls=[
617
+ ToolCall(
618
+ name="blah_tool",
619
+ args={"x": -10},
620
+ id="456",
621
+ type="tool_call",
622
+ )
623
+ ],
580
624
  id="blur",
581
625
  ),
582
626
  ]
@@ -587,21 +631,34 @@ def merge_message_runs(
587
631
 
588
632
  [
589
633
  SystemMessage("you're a good assistant."),
590
- HumanMessage("what's your favorite color\\nwait your favorite food", id="foo",),
634
+ HumanMessage(
635
+ "what's your favorite color\\n"
636
+ "wait your favorite food", id="foo",
637
+ ),
591
638
  AIMessage(
592
639
  [
593
640
  "my favorite colo",
594
641
  {"type": "text", "text": "my favorite dish is lasagna"}
595
642
  ],
596
643
  tool_calls=[
597
- ToolCall({"name": "blah_tool", "args": {"x": 2}, "id": "123", "type": "tool_call"}),
598
- ToolCall({"name": "blah_tool", "args": {"x": -10}, "id": "456", "type": "tool_call"})
644
+ ToolCall({
645
+ "name": "blah_tool",
646
+ "args": {"x": 2},
647
+ "id": "123",
648
+ "type": "tool_call"
649
+ }),
650
+ ToolCall({
651
+ "name": "blah_tool",
652
+ "args": {"x": -10},
653
+ "id": "456",
654
+ "type": "tool_call"
655
+ })
599
656
  ]
600
657
  id="baz"
601
658
  ),
602
659
  ]
603
660
 
604
- """ # noqa: E501
661
+ """
605
662
  if not messages:
606
663
  return []
607
664
  messages = convert_to_messages(messages)
@@ -661,8 +718,8 @@ def trim_messages(
661
718
  properties:
662
719
 
663
720
  1. The resulting chat history should be valid. Most chat models expect that chat
664
- history starts with either (1) a ``HumanMessage`` or (2) a ``SystemMessage`` followed
665
- by a ``HumanMessage``. To achieve this, set ``start_on="human"``.
721
+ history starts with either (1) a ``HumanMessage`` or (2) a ``SystemMessage``
722
+ followed by a ``HumanMessage``. To achieve this, set ``start_on="human"``.
666
723
  In addition, generally a ``ToolMessage`` can only appear after an ``AIMessage``
667
724
  that involved a tool call.
668
725
  Please see the following link for more information about messages:
@@ -693,9 +750,11 @@ def trim_messages(
693
750
  exact token counting is not necessary.
694
751
 
695
752
  strategy: Strategy for trimming.
753
+
696
754
  - "first": Keep the first <= n_count tokens of the messages.
697
755
  - "last": Keep the last <= n_count tokens of the messages.
698
- Default is "last".
756
+
757
+ Default is ``'last'``.
699
758
  allow_partial: Whether to split a message if only part of the message can be
700
759
  included. If ``strategy="last"`` then the last partial contents of a message
701
760
  are included. If ``strategy="first"`` then the first partial contents of a
@@ -753,14 +812,18 @@ def trim_messages(
753
812
  )
754
813
 
755
814
  messages = [
756
- SystemMessage("you're a good assistant, you always respond with a joke."),
815
+ SystemMessage(
816
+ "you're a good assistant, you always respond with a joke."
817
+ ),
757
818
  HumanMessage("i wonder why it's called langchain"),
758
819
  AIMessage(
759
- 'Well, I guess they thought "WordRope" and "SentenceString" just didn\'t have the same ring to it!'
820
+ 'Well, I guess they thought "WordRope" and "SentenceString" just '
821
+ "didn't have the same ring to it!"
760
822
  ),
761
823
  HumanMessage("and who is harrison chasing anyways"),
762
824
  AIMessage(
763
- "Hmmm let me think.\n\nWhy, he's probably chasing after the last cup of coffee in the office!"
825
+ "Hmmm let me think.\n\nWhy, he's probably chasing after the last "
826
+ "cup of coffee in the office!"
764
827
  ),
765
828
  HumanMessage("what do you call a speechless parrot"),
766
829
  ]
@@ -785,8 +848,10 @@ def trim_messages(
785
848
  .. code-block:: python
786
849
 
787
850
  [
788
- SystemMessage(content="you're a good assistant, you always respond with a joke."),
789
- HumanMessage(content='what do you call a speechless parrot'),
851
+ SystemMessage(
852
+ content="you're a good assistant, you always respond with a joke."
853
+ ),
854
+ HumanMessage(content="what do you call a speechless parrot"),
790
855
  ]
791
856
 
792
857
  Trim chat history based on the message count, keeping the SystemMessage if
@@ -816,10 +881,15 @@ def trim_messages(
816
881
  .. code-block:: python
817
882
 
818
883
  [
819
- SystemMessage(content="you're a good assistant, you always respond with a joke."),
820
- HumanMessage(content='and who is harrison chasing anyways'),
821
- AIMessage(content="Hmmm let me think.\n\nWhy, he's probably chasing after the last cup of coffee in the office!"),
822
- HumanMessage(content='what do you call a speechless parrot'),
884
+ SystemMessage(
885
+ content="you're a good assistant, you always respond with a joke."
886
+ ),
887
+ HumanMessage(content="and who is harrison chasing anyways"),
888
+ AIMessage(
889
+ content="Hmmm let me think.\n\nWhy, he's probably chasing after "
890
+ "the last cup of coffee in the office!"
891
+ ),
892
+ HumanMessage(content="what do you call a speechless parrot"),
823
893
  ]
824
894
 
825
895
 
@@ -830,7 +900,9 @@ def trim_messages(
830
900
 
831
901
  messages = [
832
902
  SystemMessage("This is a 4 token text. The full message is 10 tokens."),
833
- HumanMessage("This is a 4 token text. The full message is 10 tokens.", id="first"),
903
+ HumanMessage(
904
+ "This is a 4 token text. The full message is 10 tokens.", id="first"
905
+ ),
834
906
  AIMessage(
835
907
  [
836
908
  {"type": "text", "text": "This is the FIRST 4 token block."},
@@ -838,10 +910,16 @@ def trim_messages(
838
910
  ],
839
911
  id="second",
840
912
  ),
841
- HumanMessage("This is a 4 token text. The full message is 10 tokens.", id="third"),
842
- AIMessage("This is a 4 token text. The full message is 10 tokens.", id="fourth"),
913
+ HumanMessage(
914
+ "This is a 4 token text. The full message is 10 tokens.", id="third"
915
+ ),
916
+ AIMessage(
917
+ "This is a 4 token text. The full message is 10 tokens.",
918
+ id="fourth",
919
+ ),
843
920
  ]
844
921
 
922
+
845
923
  def dummy_token_counter(messages: list[BaseMessage]) -> int:
846
924
  # treat each message like it adds 3 default tokens at the beginning
847
925
  # of the message and at the end of the message. 3 + 4 + 3 = 10 tokens
@@ -854,9 +932,17 @@ def trim_messages(
854
932
  count = 0
855
933
  for msg in messages:
856
934
  if isinstance(msg.content, str):
857
- count += default_msg_prefix_len + default_content_len + default_msg_suffix_len
935
+ count += (
936
+ default_msg_prefix_len
937
+ + default_content_len
938
+ + default_msg_suffix_len
939
+ )
858
940
  if isinstance(msg.content, list):
859
- count += default_msg_prefix_len + len(msg.content) * default_content_len + default_msg_suffix_len
941
+ count += (
942
+ default_msg_prefix_len
943
+ + len(msg.content) * default_content_len
944
+ + default_msg_suffix_len
945
+ )
860
946
  return count
861
947
 
862
948
  First 30 tokens, allowing partial messages:
@@ -873,12 +959,20 @@ def trim_messages(
873
959
  .. code-block:: python
874
960
 
875
961
  [
876
- SystemMessage("This is a 4 token text. The full message is 10 tokens."),
877
- HumanMessage("This is a 4 token text. The full message is 10 tokens.", id="first"),
878
- AIMessage( [{"type": "text", "text": "This is the FIRST 4 token block."}], id="second"),
962
+ SystemMessage(
963
+ "This is a 4 token text. The full message is 10 tokens."
964
+ ),
965
+ HumanMessage(
966
+ "This is a 4 token text. The full message is 10 tokens.",
967
+ id="first",
968
+ ),
969
+ AIMessage(
970
+ [{"type": "text", "text": "This is the FIRST 4 token block."}],
971
+ id="second",
972
+ ),
879
973
  ]
880
974
 
881
- """ # noqa: E501
975
+ """
882
976
  # Validate arguments
883
977
  if start_on and strategy == "first":
884
978
  msg = "start_on parameter is only valid with strategy='last'"
@@ -909,17 +1003,12 @@ def trim_messages(
909
1003
  )
910
1004
  raise ValueError(msg)
911
1005
 
912
- try:
913
- from langchain_text_splitters import TextSplitter
914
- except ImportError:
915
- text_splitter_fn: Optional[Callable] = cast("Optional[Callable]", text_splitter)
1006
+ if _HAS_LANGCHAIN_TEXT_SPLITTERS and isinstance(text_splitter, TextSplitter):
1007
+ text_splitter_fn = text_splitter.split_text
1008
+ elif text_splitter:
1009
+ text_splitter_fn = cast("Callable", text_splitter)
916
1010
  else:
917
- if isinstance(text_splitter, TextSplitter):
918
- text_splitter_fn = text_splitter.split_text
919
- else:
920
- text_splitter_fn = text_splitter
921
-
922
- text_splitter_fn = text_splitter_fn or _default_text_splitter
1011
+ text_splitter_fn = _default_text_splitter
923
1012
 
924
1013
  if strategy == "first":
925
1014
  return _first_max_tokens(
@@ -957,25 +1046,30 @@ def convert_to_openai_messages(
957
1046
  in OpenAI, Anthropic, Bedrock Converse, or VertexAI formats.
958
1047
  text_format: How to format string or text block contents:
959
1048
 
960
- - "string":
961
- If a message has a string content, this is left as a string. If
962
- a message has content blocks that are all of type 'text', these are
963
- joined with a newline to make a single string. If a message has
964
- content blocks and at least one isn't of type 'text', then
965
- all blocks are left as dicts.
966
- - "block":
967
- If a message has a string content, this is turned into a list
968
- with a single content block of type 'text'. If a message has content
969
- blocks these are left as is.
1049
+ - ``'string'``:
1050
+ If a message has a string content, this is left as a string. If
1051
+ a message has content blocks that are all of type 'text', these are
1052
+ joined with a newline to make a single string. If a message has
1053
+ content blocks and at least one isn't of type 'text', then
1054
+ all blocks are left as dicts.
1055
+ - ``'block'``:
1056
+ If a message has a string content, this is turned into a list
1057
+ with a single content block of type 'text'. If a message has content
1058
+ blocks these are left as is.
1059
+
1060
+ Raises:
1061
+ ValueError: if an unrecognized ``text_format`` is specified, or if a message
1062
+ content block is missing expected keys.
970
1063
 
971
1064
  Returns:
972
1065
  The return type depends on the input type:
973
- - dict:
974
- If a single message-like object is passed in, a single OpenAI message
975
- dict is returned.
976
- - list[dict]:
977
- If a sequence of message-like objects are passed in, a list of OpenAI
978
- message dicts is returned.
1066
+
1067
+ - dict:
1068
+ If a single message-like object is passed in, a single OpenAI message
1069
+ dict is returned.
1070
+ - list[dict]:
1071
+ If a sequence of message-like objects are passed in, a list of OpenAI
1072
+ message dicts is returned.
979
1073
 
980
1074
  Example:
981
1075
 
@@ -990,8 +1084,27 @@ def convert_to_openai_messages(
990
1084
 
991
1085
  messages = [
992
1086
  SystemMessage([{"type": "text", "text": "foo"}]),
993
- {"role": "user", "content": [{"type": "text", "text": "whats in this"}, {"type": "image_url", "image_url": {"url": "data:image/png;base64,'/9j/4AAQSk'"}}]},
994
- AIMessage("", tool_calls=[{"name": "analyze", "args": {"baz": "buz"}, "id": "1", "type": "tool_call"}]),
1087
+ {
1088
+ "role": "user",
1089
+ "content": [
1090
+ {"type": "text", "text": "whats in this"},
1091
+ {
1092
+ "type": "image_url",
1093
+ "image_url": {"url": "data:image/png;base64,'/9j/4AAQSk'"},
1094
+ },
1095
+ ],
1096
+ },
1097
+ AIMessage(
1098
+ "",
1099
+ tool_calls=[
1100
+ {
1101
+ "name": "analyze",
1102
+ "args": {"baz": "buz"},
1103
+ "id": "1",
1104
+ "type": "tool_call",
1105
+ }
1106
+ ],
1107
+ ),
995
1108
  ToolMessage("foobar", tool_call_id="1", name="bar"),
996
1109
  {"role": "assistant", "content": "thats nice"},
997
1110
  ]
@@ -144,7 +144,10 @@ class BaseOutputParser(
144
144
 
145
145
  def parse(self, text: str) -> bool:
146
146
  cleaned_text = text.strip().upper()
147
- if cleaned_text not in (self.true_val.upper(), self.false_val.upper()):
147
+ if cleaned_text not in (
148
+ self.true_val.upper(),
149
+ self.false_val.upper(),
150
+ ):
148
151
  raise OutputParserException(
149
152
  f"BooleanOutputParser expected output value to either be "
150
153
  f"{self.true_val} or {self.false_val} (case-insensitive). "
@@ -156,7 +159,7 @@ class BaseOutputParser(
156
159
  def _type(self) -> str:
157
160
  return "boolean_output_parser"
158
161
 
159
- """ # noqa: E501
162
+ """
160
163
 
161
164
  @property
162
165
  @override
@@ -46,13 +46,13 @@ class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]):
46
46
  def _diff(self, prev: Optional[Any], next: Any) -> Any:
47
47
  return jsonpatch.make_patch(prev, next).patch
48
48
 
49
- def _get_schema(self, pydantic_object: type[TBaseModel]) -> dict[str, Any]:
49
+ @staticmethod
50
+ def _get_schema(pydantic_object: type[TBaseModel]) -> dict[str, Any]:
50
51
  if issubclass(pydantic_object, pydantic.BaseModel):
51
52
  return pydantic_object.model_json_schema()
52
- if issubclass(pydantic_object, pydantic.v1.BaseModel):
53
- return pydantic_object.schema()
54
- return None
53
+ return pydantic_object.schema()
55
54
 
55
+ @override
56
56
  def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
57
57
  """Parse the result of an LLM call to a JSON object.
58
58
 
@@ -143,10 +143,7 @@ class CommaSeparatedListOutputParser(ListOutputParser):
143
143
 
144
144
  @classmethod
145
145
  def is_lc_serializable(cls) -> bool:
146
- """Check if the langchain object is serializable.
147
-
148
- Returns True.
149
- """
146
+ """Return True as this class is serializable."""
150
147
  return True
151
148
 
152
149
  @classmethod
@@ -154,11 +151,11 @@ class CommaSeparatedListOutputParser(ListOutputParser):
154
151
  """Get the namespace of the langchain object.
155
152
 
156
153
  Returns:
157
- A list of strings.
158
- Default is ["langchain", "output_parsers", "list"].
154
+ ``["langchain", "output_parsers", "list"]``
159
155
  """
160
156
  return ["langchain", "output_parsers", "list"]
161
157
 
158
+ @override
162
159
  def get_format_instructions(self) -> str:
163
160
  """Return the format instructions for the comma-separated list output."""
164
161
  return (
@@ -166,6 +163,7 @@ class CommaSeparatedListOutputParser(ListOutputParser):
166
163
  "eg: `foo, bar, baz` or `foo,bar,baz`"
167
164
  )
168
165
 
166
+ @override
169
167
  def parse(self, text: str) -> list[str]:
170
168
  """Parse the output of an LLM call.
171
169
 
@@ -213,15 +211,8 @@ class NumberedListOutputParser(ListOutputParser):
213
211
  """
214
212
  return re.findall(self.pattern, text)
215
213
 
214
+ @override
216
215
  def parse_iter(self, text: str) -> Iterator[re.Match]:
217
- """Parse the output of an LLM call.
218
-
219
- Args:
220
- text: The output of an LLM call.
221
-
222
- Yields:
223
- A match object for each part of the output.
224
- """
225
216
  return re.finditer(self.pattern, text)
226
217
 
227
218
  @property
@@ -235,6 +226,7 @@ class MarkdownListOutputParser(ListOutputParser):
235
226
  pattern: str = r"^\s*[-*]\s([^\n]+)$"
236
227
  """The pattern to match a Markdown list item."""
237
228
 
229
+ @override
238
230
  def get_format_instructions(self) -> str:
239
231
  """Return the format instructions for the Markdown list output."""
240
232
  return "Your response should be a markdown list, eg: `- foo\n- bar\n- baz`"
@@ -250,15 +242,8 @@ class MarkdownListOutputParser(ListOutputParser):
250
242
  """
251
243
  return re.findall(self.pattern, text, re.MULTILINE)
252
244
 
245
+ @override
253
246
  def parse_iter(self, text: str) -> Iterator[re.Match]:
254
- """Parse the output of an LLM call.
255
-
256
- Args:
257
- text: The output of an LLM call.
258
-
259
- Yields:
260
- A match object for each part of the output.
261
- """
262
247
  return re.finditer(self.pattern, text, re.MULTILINE)
263
248
 
264
249
  @property
@@ -261,6 +261,9 @@ class PydanticOutputFunctionsParser(OutputFunctionsParser):
261
261
  result: The result of the LLM call.
262
262
  partial: Whether to parse partial JSON objects. Default is False.
263
263
 
264
+ Raises:
265
+ ValueError: If the pydantic schema is not valid.
266
+
264
267
  Returns:
265
268
  The parsed JSON object.
266
269
  """
@@ -231,6 +231,9 @@ class JsonOutputKeyToolsParser(JsonOutputToolsParser):
231
231
  If False, the output will be the full JSON object.
232
232
  Default is False.
233
233
 
234
+ Raises:
235
+ OutputParserException: If the generation is not a chat generation.
236
+
234
237
  Returns:
235
238
  The parsed tool calls.
236
239
  """
@@ -316,7 +319,9 @@ class PydanticToolsParser(JsonOutputToolsParser):
316
319
  The parsed Pydantic objects.
317
320
 
318
321
  Raises:
319
- OutputParserException: If the output is not valid JSON.
322
+ ValueError: If the tool call arguments are not a dict.
323
+ ValidationError: If the tool call arguments do not conform
324
+ to the Pydantic model.
320
325
  """
321
326
  json_results = super().parse_result(result, partial=partial)
322
327
  if not json_results:
@@ -54,6 +54,10 @@ class PydanticOutputParser(JsonOutputParser, Generic[TBaseModel]):
54
54
  all the keys that have been returned so far.
55
55
  Defaults to False.
56
56
 
57
+ Raises:
58
+ OutputParserException: If the result is not valid JSON
59
+ or does not conform to the pydantic model.
60
+
57
61
  Returns:
58
62
  The parsed pydantic object.
59
63
  """
@@ -1,5 +1,7 @@
1
1
  """String output parser."""
2
2
 
3
+ from typing_extensions import override
4
+
3
5
  from langchain_core.output_parsers.transform import BaseTransformOutputParser
4
6
 
5
7
 
@@ -19,7 +21,8 @@ class StrOutputParser(BaseTransformOutputParser[str]):
19
21
  def get_lc_namespace(cls) -> list[str]:
20
22
  """Get the namespace of the langchain object.
21
23
 
22
- Default is ["langchain", "schema", "output_parser"].
24
+ Returns:
25
+ ``["langchain", "schema", "output_parser"]``
23
26
  """
24
27
  return ["langchain", "schema", "output_parser"]
25
28
 
@@ -28,6 +31,7 @@ class StrOutputParser(BaseTransformOutputParser[str]):
28
31
  """Return the output parser type for serialization."""
29
32
  return "default"
30
33
 
34
+ @override
31
35
  def parse(self, text: str) -> str:
32
36
  """Returns the input text with no changes."""
33
37
  return text