langchain-core 0.4.0.dev0__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 (172) hide show
  1. langchain_core/__init__.py +1 -1
  2. langchain_core/_api/__init__.py +3 -4
  3. langchain_core/_api/beta_decorator.py +45 -70
  4. langchain_core/_api/deprecation.py +80 -80
  5. langchain_core/_api/path.py +22 -8
  6. langchain_core/_import_utils.py +10 -4
  7. langchain_core/agents.py +25 -21
  8. langchain_core/caches.py +53 -63
  9. langchain_core/callbacks/__init__.py +1 -8
  10. langchain_core/callbacks/base.py +341 -348
  11. langchain_core/callbacks/file.py +55 -44
  12. langchain_core/callbacks/manager.py +546 -683
  13. langchain_core/callbacks/stdout.py +29 -30
  14. langchain_core/callbacks/streaming_stdout.py +35 -36
  15. langchain_core/callbacks/usage.py +65 -70
  16. langchain_core/chat_history.py +48 -55
  17. langchain_core/document_loaders/base.py +46 -21
  18. langchain_core/document_loaders/langsmith.py +39 -36
  19. langchain_core/documents/__init__.py +0 -1
  20. langchain_core/documents/base.py +96 -74
  21. langchain_core/documents/compressor.py +12 -9
  22. langchain_core/documents/transformers.py +29 -28
  23. langchain_core/embeddings/fake.py +56 -57
  24. langchain_core/env.py +2 -3
  25. langchain_core/example_selectors/base.py +12 -0
  26. langchain_core/example_selectors/length_based.py +1 -1
  27. langchain_core/example_selectors/semantic_similarity.py +21 -25
  28. langchain_core/exceptions.py +15 -9
  29. langchain_core/globals.py +4 -163
  30. langchain_core/indexing/api.py +132 -125
  31. langchain_core/indexing/base.py +64 -67
  32. langchain_core/indexing/in_memory.py +26 -6
  33. langchain_core/language_models/__init__.py +15 -27
  34. langchain_core/language_models/_utils.py +267 -117
  35. langchain_core/language_models/base.py +92 -177
  36. langchain_core/language_models/chat_models.py +547 -407
  37. langchain_core/language_models/fake.py +11 -11
  38. langchain_core/language_models/fake_chat_models.py +72 -118
  39. langchain_core/language_models/llms.py +168 -242
  40. langchain_core/load/dump.py +8 -11
  41. langchain_core/load/load.py +32 -28
  42. langchain_core/load/mapping.py +2 -4
  43. langchain_core/load/serializable.py +50 -56
  44. langchain_core/messages/__init__.py +36 -51
  45. langchain_core/messages/ai.py +377 -150
  46. langchain_core/messages/base.py +239 -47
  47. langchain_core/messages/block_translators/__init__.py +111 -0
  48. langchain_core/messages/block_translators/anthropic.py +470 -0
  49. langchain_core/messages/block_translators/bedrock.py +94 -0
  50. langchain_core/messages/block_translators/bedrock_converse.py +297 -0
  51. langchain_core/messages/block_translators/google_genai.py +530 -0
  52. langchain_core/messages/block_translators/google_vertexai.py +21 -0
  53. langchain_core/messages/block_translators/groq.py +143 -0
  54. langchain_core/messages/block_translators/langchain_v0.py +301 -0
  55. langchain_core/messages/block_translators/openai.py +1010 -0
  56. langchain_core/messages/chat.py +2 -3
  57. langchain_core/messages/content.py +1423 -0
  58. langchain_core/messages/function.py +7 -7
  59. langchain_core/messages/human.py +44 -38
  60. langchain_core/messages/modifier.py +3 -2
  61. langchain_core/messages/system.py +40 -27
  62. langchain_core/messages/tool.py +160 -58
  63. langchain_core/messages/utils.py +527 -638
  64. langchain_core/output_parsers/__init__.py +1 -14
  65. langchain_core/output_parsers/base.py +68 -104
  66. langchain_core/output_parsers/json.py +13 -17
  67. langchain_core/output_parsers/list.py +11 -33
  68. langchain_core/output_parsers/openai_functions.py +56 -74
  69. langchain_core/output_parsers/openai_tools.py +68 -109
  70. langchain_core/output_parsers/pydantic.py +15 -13
  71. langchain_core/output_parsers/string.py +6 -2
  72. langchain_core/output_parsers/transform.py +17 -60
  73. langchain_core/output_parsers/xml.py +34 -44
  74. langchain_core/outputs/__init__.py +1 -1
  75. langchain_core/outputs/chat_generation.py +26 -11
  76. langchain_core/outputs/chat_result.py +1 -3
  77. langchain_core/outputs/generation.py +17 -6
  78. langchain_core/outputs/llm_result.py +15 -8
  79. langchain_core/prompt_values.py +29 -123
  80. langchain_core/prompts/__init__.py +3 -27
  81. langchain_core/prompts/base.py +48 -63
  82. langchain_core/prompts/chat.py +259 -288
  83. langchain_core/prompts/dict.py +19 -11
  84. langchain_core/prompts/few_shot.py +84 -90
  85. langchain_core/prompts/few_shot_with_templates.py +14 -12
  86. langchain_core/prompts/image.py +19 -14
  87. langchain_core/prompts/loading.py +6 -8
  88. langchain_core/prompts/message.py +7 -8
  89. langchain_core/prompts/prompt.py +42 -43
  90. langchain_core/prompts/string.py +37 -16
  91. langchain_core/prompts/structured.py +43 -46
  92. langchain_core/rate_limiters.py +51 -60
  93. langchain_core/retrievers.py +52 -192
  94. langchain_core/runnables/base.py +1727 -1683
  95. langchain_core/runnables/branch.py +52 -73
  96. langchain_core/runnables/config.py +89 -103
  97. langchain_core/runnables/configurable.py +128 -130
  98. langchain_core/runnables/fallbacks.py +93 -82
  99. langchain_core/runnables/graph.py +127 -127
  100. langchain_core/runnables/graph_ascii.py +63 -41
  101. langchain_core/runnables/graph_mermaid.py +87 -70
  102. langchain_core/runnables/graph_png.py +31 -36
  103. langchain_core/runnables/history.py +145 -161
  104. langchain_core/runnables/passthrough.py +141 -144
  105. langchain_core/runnables/retry.py +84 -68
  106. langchain_core/runnables/router.py +33 -37
  107. langchain_core/runnables/schema.py +79 -72
  108. langchain_core/runnables/utils.py +95 -139
  109. langchain_core/stores.py +85 -131
  110. langchain_core/structured_query.py +11 -15
  111. langchain_core/sys_info.py +31 -32
  112. langchain_core/tools/__init__.py +1 -14
  113. langchain_core/tools/base.py +221 -247
  114. langchain_core/tools/convert.py +144 -161
  115. langchain_core/tools/render.py +10 -10
  116. langchain_core/tools/retriever.py +12 -19
  117. langchain_core/tools/simple.py +52 -29
  118. langchain_core/tools/structured.py +56 -60
  119. langchain_core/tracers/__init__.py +1 -9
  120. langchain_core/tracers/_streaming.py +6 -7
  121. langchain_core/tracers/base.py +103 -112
  122. langchain_core/tracers/context.py +29 -48
  123. langchain_core/tracers/core.py +142 -105
  124. langchain_core/tracers/evaluation.py +30 -34
  125. langchain_core/tracers/event_stream.py +162 -117
  126. langchain_core/tracers/langchain.py +34 -36
  127. langchain_core/tracers/log_stream.py +87 -49
  128. langchain_core/tracers/memory_stream.py +3 -3
  129. langchain_core/tracers/root_listeners.py +18 -34
  130. langchain_core/tracers/run_collector.py +8 -20
  131. langchain_core/tracers/schemas.py +0 -125
  132. langchain_core/tracers/stdout.py +3 -3
  133. langchain_core/utils/__init__.py +1 -4
  134. langchain_core/utils/_merge.py +47 -9
  135. langchain_core/utils/aiter.py +70 -66
  136. langchain_core/utils/env.py +12 -9
  137. langchain_core/utils/function_calling.py +139 -206
  138. langchain_core/utils/html.py +7 -8
  139. langchain_core/utils/input.py +6 -6
  140. langchain_core/utils/interactive_env.py +6 -2
  141. langchain_core/utils/iter.py +48 -45
  142. langchain_core/utils/json.py +14 -4
  143. langchain_core/utils/json_schema.py +159 -43
  144. langchain_core/utils/mustache.py +32 -25
  145. langchain_core/utils/pydantic.py +67 -40
  146. langchain_core/utils/strings.py +5 -5
  147. langchain_core/utils/usage.py +1 -1
  148. langchain_core/utils/utils.py +104 -62
  149. langchain_core/vectorstores/base.py +131 -179
  150. langchain_core/vectorstores/in_memory.py +113 -182
  151. langchain_core/vectorstores/utils.py +23 -17
  152. langchain_core/version.py +1 -1
  153. langchain_core-1.0.0.dist-info/METADATA +68 -0
  154. langchain_core-1.0.0.dist-info/RECORD +172 -0
  155. {langchain_core-0.4.0.dev0.dist-info → langchain_core-1.0.0.dist-info}/WHEEL +1 -1
  156. langchain_core/beta/__init__.py +0 -1
  157. langchain_core/beta/runnables/__init__.py +0 -1
  158. langchain_core/beta/runnables/context.py +0 -448
  159. langchain_core/memory.py +0 -116
  160. langchain_core/messages/content_blocks.py +0 -1435
  161. langchain_core/prompts/pipeline.py +0 -133
  162. langchain_core/pydantic_v1/__init__.py +0 -30
  163. langchain_core/pydantic_v1/dataclasses.py +0 -23
  164. langchain_core/pydantic_v1/main.py +0 -23
  165. langchain_core/tracers/langchain_v1.py +0 -23
  166. langchain_core/utils/loading.py +0 -31
  167. langchain_core/v1/__init__.py +0 -1
  168. langchain_core/v1/chat_models.py +0 -1047
  169. langchain_core/v1/messages.py +0 -755
  170. langchain_core-0.4.0.dev0.dist-info/METADATA +0 -108
  171. langchain_core-0.4.0.dev0.dist-info/RECORD +0 -177
  172. langchain_core-0.4.0.dev0.dist-info/entry_points.txt +0 -4
@@ -5,8 +5,6 @@ from __future__ import annotations
5
5
  from typing import (
6
6
  TYPE_CHECKING,
7
7
  Any,
8
- Optional,
9
- Union,
10
8
  )
11
9
 
12
10
  from typing_extensions import override
@@ -20,7 +18,6 @@ from langchain_core.outputs import (
20
18
  GenerationChunk,
21
19
  )
22
20
  from langchain_core.runnables.config import run_in_executor
23
- from langchain_core.v1.messages import AIMessage, AIMessageChunk
24
21
 
25
22
  if TYPE_CHECKING:
26
23
  from collections.abc import AsyncIterator, Iterator
@@ -33,27 +30,23 @@ class BaseTransformOutputParser(BaseOutputParser[T]):
33
30
 
34
31
  def _transform(
35
32
  self,
36
- input: Iterator[Union[str, BaseMessage, AIMessage]],
33
+ input: Iterator[str | BaseMessage],
37
34
  ) -> Iterator[T]:
38
35
  for chunk in input:
39
36
  if isinstance(chunk, BaseMessage):
40
37
  yield self.parse_result([ChatGeneration(message=chunk)])
41
- elif isinstance(chunk, AIMessage):
42
- yield self.parse_result(chunk)
43
38
  else:
44
39
  yield self.parse_result([Generation(text=chunk)])
45
40
 
46
41
  async def _atransform(
47
42
  self,
48
- input: AsyncIterator[Union[str, BaseMessage, AIMessage]],
43
+ input: AsyncIterator[str | BaseMessage],
49
44
  ) -> AsyncIterator[T]:
50
45
  async for chunk in input:
51
46
  if isinstance(chunk, BaseMessage):
52
47
  yield await run_in_executor(
53
48
  None, self.parse_result, [ChatGeneration(message=chunk)]
54
49
  )
55
- elif isinstance(chunk, AIMessage):
56
- yield await run_in_executor(None, self.parse_result, chunk)
57
50
  else:
58
51
  yield await run_in_executor(
59
52
  None, self.parse_result, [Generation(text=chunk)]
@@ -62,8 +55,8 @@ class BaseTransformOutputParser(BaseOutputParser[T]):
62
55
  @override
63
56
  def transform(
64
57
  self,
65
- input: Iterator[Union[str, BaseMessage, AIMessage]],
66
- config: Optional[RunnableConfig] = None,
58
+ input: Iterator[str | BaseMessage],
59
+ config: RunnableConfig | None = None,
67
60
  **kwargs: Any,
68
61
  ) -> Iterator[T]:
69
62
  """Transform the input into the output format.
@@ -71,7 +64,7 @@ class BaseTransformOutputParser(BaseOutputParser[T]):
71
64
  Args:
72
65
  input: The input to transform.
73
66
  config: The configuration to use for the transformation.
74
- kwargs: Additional keyword arguments.
67
+ **kwargs: Additional keyword arguments.
75
68
 
76
69
  Yields:
77
70
  The transformed output.
@@ -83,8 +76,8 @@ class BaseTransformOutputParser(BaseOutputParser[T]):
83
76
  @override
84
77
  async def atransform(
85
78
  self,
86
- input: AsyncIterator[Union[str, BaseMessage, AIMessage]],
87
- config: Optional[RunnableConfig] = None,
79
+ input: AsyncIterator[str | BaseMessage],
80
+ config: RunnableConfig | None = None,
88
81
  **kwargs: Any,
89
82
  ) -> AsyncIterator[T]:
90
83
  """Async transform the input into the output format.
@@ -92,7 +85,7 @@ class BaseTransformOutputParser(BaseOutputParser[T]):
92
85
  Args:
93
86
  input: The input to transform.
94
87
  config: The configuration to use for the transformation.
95
- kwargs: Additional keyword arguments.
88
+ **kwargs: Additional keyword arguments.
96
89
 
97
90
  Yields:
98
91
  The transformed output.
@@ -113,7 +106,7 @@ class BaseCumulativeTransformOutputParser(BaseTransformOutputParser[T]):
113
106
 
114
107
  def _diff(
115
108
  self,
116
- prev: Optional[T],
109
+ prev: T | None,
117
110
  next: T, # noqa: A002
118
111
  ) -> T:
119
112
  """Convert parsed outputs into a diff format.
@@ -130,42 +123,23 @@ class BaseCumulativeTransformOutputParser(BaseTransformOutputParser[T]):
130
123
  raise NotImplementedError
131
124
 
132
125
  @override
133
- def _transform(
134
- self, input: Iterator[Union[str, BaseMessage, AIMessage]]
135
- ) -> Iterator[Any]:
126
+ def _transform(self, input: Iterator[str | BaseMessage]) -> Iterator[Any]:
136
127
  prev_parsed = None
137
- acc_gen: Union[GenerationChunk, ChatGenerationChunk, AIMessageChunk, None] = (
138
- None
139
- )
128
+ acc_gen: GenerationChunk | ChatGenerationChunk | None = None
140
129
  for chunk in input:
141
- chunk_gen: Union[GenerationChunk, ChatGenerationChunk, AIMessageChunk]
130
+ chunk_gen: GenerationChunk | ChatGenerationChunk
142
131
  if isinstance(chunk, BaseMessageChunk):
143
132
  chunk_gen = ChatGenerationChunk(message=chunk)
144
133
  elif isinstance(chunk, BaseMessage):
145
134
  chunk_gen = ChatGenerationChunk(
146
135
  message=BaseMessageChunk(**chunk.model_dump())
147
136
  )
148
- elif isinstance(chunk, AIMessageChunk):
149
- chunk_gen = chunk
150
- elif isinstance(chunk, AIMessage):
151
- chunk_gen = AIMessageChunk(
152
- content=chunk.content,
153
- id=chunk.id,
154
- name=chunk.name,
155
- lc_version=chunk.lc_version,
156
- response_metadata=chunk.response_metadata,
157
- usage_metadata=chunk.usage_metadata,
158
- parsed=chunk.parsed,
159
- )
160
137
  else:
161
138
  chunk_gen = GenerationChunk(text=chunk)
162
139
 
163
140
  acc_gen = chunk_gen if acc_gen is None else acc_gen + chunk_gen # type: ignore[operator]
164
141
 
165
- if isinstance(acc_gen, AIMessageChunk):
166
- parsed = self.parse_result(acc_gen, partial=True)
167
- else:
168
- parsed = self.parse_result([acc_gen], partial=True)
142
+ parsed = self.parse_result([acc_gen], partial=True)
169
143
  if parsed is not None and parsed != prev_parsed:
170
144
  if self.diff:
171
145
  yield self._diff(prev_parsed, parsed)
@@ -175,41 +149,24 @@ class BaseCumulativeTransformOutputParser(BaseTransformOutputParser[T]):
175
149
 
176
150
  @override
177
151
  async def _atransform(
178
- self, input: AsyncIterator[Union[str, BaseMessage, AIMessage]]
152
+ self, input: AsyncIterator[str | BaseMessage]
179
153
  ) -> AsyncIterator[T]:
180
154
  prev_parsed = None
181
- acc_gen: Union[GenerationChunk, ChatGenerationChunk, AIMessageChunk, None] = (
182
- None
183
- )
155
+ acc_gen: GenerationChunk | ChatGenerationChunk | None = None
184
156
  async for chunk in input:
185
- chunk_gen: Union[GenerationChunk, ChatGenerationChunk, AIMessageChunk]
157
+ chunk_gen: GenerationChunk | ChatGenerationChunk
186
158
  if isinstance(chunk, BaseMessageChunk):
187
159
  chunk_gen = ChatGenerationChunk(message=chunk)
188
160
  elif isinstance(chunk, BaseMessage):
189
161
  chunk_gen = ChatGenerationChunk(
190
162
  message=BaseMessageChunk(**chunk.model_dump())
191
163
  )
192
- elif isinstance(chunk, AIMessageChunk):
193
- chunk_gen = chunk
194
- elif isinstance(chunk, AIMessage):
195
- chunk_gen = AIMessageChunk(
196
- content=chunk.content,
197
- id=chunk.id,
198
- name=chunk.name,
199
- lc_version=chunk.lc_version,
200
- response_metadata=chunk.response_metadata,
201
- usage_metadata=chunk.usage_metadata,
202
- parsed=chunk.parsed,
203
- )
204
164
  else:
205
165
  chunk_gen = GenerationChunk(text=chunk)
206
166
 
207
167
  acc_gen = chunk_gen if acc_gen is None else acc_gen + chunk_gen # type: ignore[operator]
208
168
 
209
- if isinstance(acc_gen, AIMessageChunk):
210
- parsed = await self.aparse_result(acc_gen, partial=True)
211
- else:
212
- parsed = await self.aparse_result([acc_gen], partial=True)
169
+ parsed = await self.aparse_result([acc_gen], partial=True)
213
170
  if parsed is not None and parsed != prev_parsed:
214
171
  if self.diff:
215
172
  yield await run_in_executor(None, self._diff, prev_parsed, parsed)
@@ -5,17 +5,23 @@ import re
5
5
  import xml
6
6
  import xml.etree.ElementTree as ET
7
7
  from collections.abc import AsyncIterator, Iterator
8
- from typing import Any, Literal, Optional, Union
8
+ from typing import Any, Literal
9
9
  from xml.etree.ElementTree import TreeBuilder
10
10
 
11
11
  from typing_extensions import override
12
12
 
13
13
  from langchain_core.exceptions import OutputParserException
14
14
  from langchain_core.messages import BaseMessage
15
- from langchain_core.messages.utils import convert_from_v1_message
16
15
  from langchain_core.output_parsers.transform import BaseTransformOutputParser
17
16
  from langchain_core.runnables.utils import AddableDict
18
- from langchain_core.v1.messages import AIMessage
17
+
18
+ try:
19
+ from defusedxml import ElementTree # type: ignore[import-untyped]
20
+ from defusedxml.ElementTree import XMLParser # type: ignore[import-untyped]
21
+
22
+ _HAS_DEFUSEDXML = True
23
+ except ImportError:
24
+ _HAS_DEFUSEDXML = False
19
25
 
20
26
  XML_FORMAT_INSTRUCTIONS = """The output should be formatted as a XML file.
21
27
  1. Output should conform to the tags below.
@@ -52,17 +58,13 @@ class _StreamingParser:
52
58
  parser is requested.
53
59
  """
54
60
  if parser == "defusedxml":
55
- try:
56
- from defusedxml.ElementTree import ( # type: ignore[import-untyped]
57
- XMLParser,
58
- )
59
- except ImportError as e:
61
+ if not _HAS_DEFUSEDXML:
60
62
  msg = (
61
63
  "defusedxml is not installed. "
62
64
  "Please install it to use the defusedxml parser."
63
65
  "You can install it with `pip install defusedxml` "
64
66
  )
65
- raise ImportError(msg) from e
67
+ raise ImportError(msg)
66
68
  parser_ = XMLParser(target=TreeBuilder())
67
69
  else:
68
70
  parser_ = None
@@ -73,14 +75,14 @@ class _StreamingParser:
73
75
  self.buffer = ""
74
76
  self.xml_started = False
75
77
 
76
- def parse(self, chunk: Union[str, BaseMessage]) -> Iterator[AddableDict]:
78
+ def parse(self, chunk: str | BaseMessage) -> Iterator[AddableDict]:
77
79
  """Parse a chunk of text.
78
80
 
79
81
  Args:
80
82
  chunk: A chunk of text to parse. This can be a string or a BaseMessage.
81
83
 
82
84
  Yields:
83
- AddableDict: A dictionary representing the parsed XML element.
85
+ A dictionary representing the parsed XML element.
84
86
 
85
87
  Raises:
86
88
  xml.etree.ElementTree.ParseError: If the XML is not well-formed.
@@ -107,10 +109,11 @@ class _StreamingParser:
107
109
  self.buffer = ""
108
110
  # yield all events
109
111
  try:
110
- for event, elem in self.pull_parser.read_events():
112
+ events = self.pull_parser.read_events()
113
+ for event, elem in events: # type: ignore[misc]
111
114
  if event == "start":
112
115
  # update current path
113
- self.current_path.append(elem.tag)
116
+ self.current_path.append(elem.tag) # type: ignore[union-attr]
114
117
  self.current_path_has_children = False
115
118
  elif event == "end":
116
119
  # remove last element from current path
@@ -118,7 +121,7 @@ class _StreamingParser:
118
121
  self.current_path.pop()
119
122
  # yield element
120
123
  if not self.current_path_has_children:
121
- yield nested_element(self.current_path, elem)
124
+ yield nested_element(self.current_path, elem) # type: ignore[arg-type]
122
125
  # prevent yielding of parent element
123
126
  if self.current_path:
124
127
  self.current_path_has_children = True
@@ -137,9 +140,6 @@ class _StreamingParser:
137
140
  """Close the parser.
138
141
 
139
142
  This should be called after all chunks have been parsed.
140
-
141
- Raises:
142
- xml.etree.ElementTree.ParseError: If the XML is not well-formed.
143
143
  """
144
144
  # Ignore ParseError. This will ignore any incomplete XML at the end of the input
145
145
  with contextlib.suppress(xml.etree.ElementTree.ParseError):
@@ -149,20 +149,21 @@ class _StreamingParser:
149
149
  class XMLOutputParser(BaseTransformOutputParser):
150
150
  """Parse an output using xml format."""
151
151
 
152
- tags: Optional[list[str]] = None
152
+ tags: list[str] | None = None
153
153
  """Tags to tell the LLM to expect in the XML output.
154
154
 
155
155
  Note this may not be perfect depending on the LLM implementation.
156
156
 
157
157
  For example, with tags=["foo", "bar", "baz"]:
158
- 1. A well-formatted XML instance:
159
- "<foo>\n <bar>\n <baz></baz>\n </bar>\n</foo>"
160
158
 
161
- 2. A badly-formatted XML instance (missing closing tag for 'bar'):
162
- "<foo>\n <bar>\n </foo>"
159
+ 1. A well-formatted XML instance:
160
+ "<foo>\n <bar>\n <baz></baz>\n </bar>\n</foo>"
161
+
162
+ 2. A badly-formatted XML instance (missing closing tag for 'bar'):
163
+ "<foo>\n <bar>\n </foo>"
163
164
 
164
- 3. A badly-formatted XML instance (unexpected 'tag' element):
165
- "<foo>\n <tag>\n </tag>\n</foo>"
165
+ 3. A badly-formatted XML instance (unexpected 'tag' element):
166
+ "<foo>\n <tag>\n </tag>\n</foo>"
166
167
  """
167
168
  encoding_matcher: re.Pattern = re.compile(
168
169
  r"<([^>]*encoding[^>]*)>\n(.*)", re.MULTILINE | re.DOTALL
@@ -192,7 +193,7 @@ class XMLOutputParser(BaseTransformOutputParser):
192
193
  """Return the format instructions for the XML output."""
193
194
  return XML_FORMAT_INSTRUCTIONS.format(tags=self.tags)
194
195
 
195
- def parse(self, text: str) -> dict[str, Union[str, list[Any]]]:
196
+ def parse(self, text: str) -> dict[str, str | list[Any]]:
196
197
  """Parse the output of an LLM call.
197
198
 
198
199
  Args:
@@ -210,16 +211,14 @@ class XMLOutputParser(BaseTransformOutputParser):
210
211
  # Imports are temporarily placed here to avoid issue with caching on CI
211
212
  # likely if you're reading this you can move them to the top of the file
212
213
  if self.parser == "defusedxml":
213
- try:
214
- from defusedxml import ElementTree # type: ignore[import-untyped]
215
- except ImportError as e:
214
+ if not _HAS_DEFUSEDXML:
216
215
  msg = (
217
216
  "defusedxml is not installed. "
218
217
  "Please install it to use the defusedxml parser."
219
218
  "You can install it with `pip install defusedxml`"
220
219
  "See https://github.com/tiran/defusedxml for more details"
221
220
  )
222
- raise ImportError(msg) from e
221
+ raise ImportError(msg)
223
222
  et = ElementTree # Use the defusedxml parser
224
223
  else:
225
224
  et = ET # Use the standard library parser
@@ -241,32 +240,23 @@ class XMLOutputParser(BaseTransformOutputParser):
241
240
  raise OutputParserException(msg, llm_output=text) from e
242
241
 
243
242
  @override
244
- def _transform(
245
- self, input: Iterator[Union[str, BaseMessage, AIMessage]]
246
- ) -> Iterator[AddableDict]:
243
+ def _transform(self, input: Iterator[str | BaseMessage]) -> Iterator[AddableDict]:
247
244
  streaming_parser = _StreamingParser(self.parser)
248
245
  for chunk in input:
249
- if isinstance(chunk, AIMessage):
250
- yield from streaming_parser.parse(convert_from_v1_message(chunk))
251
- else:
252
- yield from streaming_parser.parse(chunk)
246
+ yield from streaming_parser.parse(chunk)
253
247
  streaming_parser.close()
254
248
 
255
249
  @override
256
250
  async def _atransform(
257
- self, input: AsyncIterator[Union[str, BaseMessage, AIMessage]]
251
+ self, input: AsyncIterator[str | BaseMessage]
258
252
  ) -> AsyncIterator[AddableDict]:
259
253
  streaming_parser = _StreamingParser(self.parser)
260
254
  async for chunk in input:
261
- if isinstance(chunk, AIMessage):
262
- for output in streaming_parser.parse(convert_from_v1_message(chunk)):
263
- yield output
264
- else:
265
- for output in streaming_parser.parse(chunk):
266
- yield output
255
+ for output in streaming_parser.parse(chunk):
256
+ yield output
267
257
  streaming_parser.close()
268
258
 
269
- def _root_to_dict(self, root: ET.Element) -> dict[str, Union[str, list[Any]]]:
259
+ def _root_to_dict(self, root: ET.Element) -> dict[str, str | list[Any]]:
270
260
  """Converts xml tree to python dictionary."""
271
261
  if root.text and bool(re.search(r"\S", root.text)):
272
262
  # If root text contains any non-whitespace character it
@@ -12,7 +12,7 @@ When invoking models via the standard runnable methods (e.g. invoke, batch, etc.
12
12
  - LLMs will return regular text strings.
13
13
 
14
14
  In addition, users can access the raw output of either LLMs or chat models via
15
- callbacks. The ``on_chat_model_end`` and ``on_llm_end`` callbacks will return an
15
+ callbacks. The `on_chat_model_end` and `on_llm_end` callbacks will return an
16
16
  LLMResult object containing the generated outputs and any additional information
17
17
  returned by the model provider.
18
18
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Literal, Union
5
+ from typing import Literal
6
6
 
7
7
  from pydantic import model_validator
8
8
  from typing_extensions import Self
@@ -15,7 +15,7 @@ from langchain_core.utils._merge import merge_dicts
15
15
  class ChatGeneration(Generation):
16
16
  """A single chat generation output.
17
17
 
18
- A subclass of Generation that represents the response from a chat model
18
+ A subclass of `Generation` that represents the response from a chat model
19
19
  that generates chat messages.
20
20
 
21
21
  The `message` attribute is a structured representation of the chat message.
@@ -29,8 +29,9 @@ class ChatGeneration(Generation):
29
29
  text: str = ""
30
30
  """The text contents of the output message.
31
31
 
32
- .. warning::
32
+ !!! warning
33
33
  SHOULD NOT BE SET DIRECTLY!
34
+
34
35
  """
35
36
  message: BaseMessage
36
37
  """The message output by the chat model."""
@@ -69,9 +70,9 @@ class ChatGeneration(Generation):
69
70
 
70
71
 
71
72
  class ChatGenerationChunk(ChatGeneration):
72
- """ChatGeneration chunk.
73
+ """`ChatGeneration` chunk.
73
74
 
74
- ChatGeneration chunks can be concatenated with other ChatGeneration chunks.
75
+ `ChatGeneration` chunks can be concatenated with other `ChatGeneration` chunks.
75
76
  """
76
77
 
77
78
  message: BaseMessageChunk
@@ -81,13 +82,20 @@ class ChatGenerationChunk(ChatGeneration):
81
82
  """Type is used exclusively for serialization purposes."""
82
83
 
83
84
  def __add__(
84
- self, other: Union[ChatGenerationChunk, list[ChatGenerationChunk]]
85
+ self, other: ChatGenerationChunk | list[ChatGenerationChunk]
85
86
  ) -> ChatGenerationChunk:
86
- """Concatenate two ChatGenerationChunks.
87
+ """Concatenate two `ChatGenerationChunk`s.
87
88
 
88
89
  Args:
89
- other: The other ChatGenerationChunk or list of ChatGenerationChunks to
90
- concatenate.
90
+ other: The other `ChatGenerationChunk` or list of `ChatGenerationChunk`
91
+ to concatenate.
92
+
93
+ Raises:
94
+ TypeError: If other is not a `ChatGenerationChunk` or list of
95
+ `ChatGenerationChunk`.
96
+
97
+ Returns:
98
+ A new `ChatGenerationChunk` concatenated from self and other.
91
99
  """
92
100
  if isinstance(other, ChatGenerationChunk):
93
101
  generation_info = merge_dicts(
@@ -115,8 +123,15 @@ class ChatGenerationChunk(ChatGeneration):
115
123
 
116
124
  def merge_chat_generation_chunks(
117
125
  chunks: list[ChatGenerationChunk],
118
- ) -> Union[ChatGenerationChunk, None]:
119
- """Merge a list of ChatGenerationChunks into a single ChatGenerationChunk."""
126
+ ) -> ChatGenerationChunk | None:
127
+ """Merge a list of `ChatGenerationChunk`s into a single `ChatGenerationChunk`.
128
+
129
+ Args:
130
+ chunks: A list of `ChatGenerationChunk` to merge.
131
+
132
+ Returns:
133
+ A merged `ChatGenerationChunk`, or None if the input list is empty.
134
+ """
120
135
  if not chunks:
121
136
  return None
122
137
 
@@ -1,7 +1,5 @@
1
1
  """Chat result schema."""
2
2
 
3
- from typing import Optional
4
-
5
3
  from pydantic import BaseModel
6
4
 
7
5
  from langchain_core.outputs.chat_generation import ChatGeneration
@@ -26,7 +24,7 @@ class ChatResult(BaseModel):
26
24
  Generations is a list to allow for multiple candidate generations for a single
27
25
  input prompt.
28
26
  """
29
- llm_output: Optional[dict] = None
27
+ llm_output: dict | None = None
30
28
  """For arbitrary LLM provider specific output.
31
29
 
32
30
  This dictionary is a free-form dictionary that can contain any information that the
@@ -2,7 +2,7 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
- from typing import Any, Literal, Optional
5
+ from typing import Any, Literal
6
6
 
7
7
  from langchain_core.load import Serializable
8
8
  from langchain_core.utils._merge import merge_dicts
@@ -28,7 +28,7 @@ class Generation(Serializable):
28
28
  text: str
29
29
  """Generated text output."""
30
30
 
31
- generation_info: Optional[dict[str, Any]] = None
31
+ generation_info: dict[str, Any] | None = None
32
32
  """Raw response from the provider.
33
33
 
34
34
  May include things like the reason for finishing or token log probabilities.
@@ -39,14 +39,15 @@ class Generation(Serializable):
39
39
 
40
40
  @classmethod
41
41
  def is_lc_serializable(cls) -> bool:
42
- """Return whether this class is serializable."""
42
+ """Return True as this class is serializable."""
43
43
  return True
44
44
 
45
45
  @classmethod
46
46
  def get_lc_namespace(cls) -> list[str]:
47
- """Get the namespace of the langchain object.
47
+ """Get the namespace of the LangChain object.
48
48
 
49
- Default namespace is ["langchain", "schema", "output"].
49
+ Returns:
50
+ `["langchain", "schema", "output"]`
50
51
  """
51
52
  return ["langchain", "schema", "output"]
52
53
 
@@ -55,7 +56,17 @@ class GenerationChunk(Generation):
55
56
  """Generation chunk, which can be concatenated with other Generation chunks."""
56
57
 
57
58
  def __add__(self, other: GenerationChunk) -> GenerationChunk:
58
- """Concatenate two GenerationChunks."""
59
+ """Concatenate two `GenerationChunk`s.
60
+
61
+ Args:
62
+ other: Another `GenerationChunk` to concatenate with.
63
+
64
+ Raises:
65
+ TypeError: If other is not a `GenerationChunk`.
66
+
67
+ Returns:
68
+ A new `GenerationChunk` concatenated from self and other.
69
+ """
59
70
  if isinstance(other, GenerationChunk):
60
71
  generation_info = merge_dicts(
61
72
  self.generation_info or {},
@@ -3,7 +3,7 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from copy import deepcopy
6
- from typing import Literal, Optional, Union
6
+ from typing import Literal
7
7
 
8
8
  from pydantic import BaseModel
9
9
 
@@ -21,7 +21,7 @@ class LLMResult(BaseModel):
21
21
  """
22
22
 
23
23
  generations: list[
24
- list[Union[Generation, ChatGeneration, GenerationChunk, ChatGenerationChunk]]
24
+ list[Generation | ChatGeneration | GenerationChunk | ChatGenerationChunk]
25
25
  ]
26
26
  """Generated outputs.
27
27
 
@@ -30,13 +30,13 @@ class LLMResult(BaseModel):
30
30
  The second dimension of the list represents different candidate generations for a
31
31
  given prompt.
32
32
 
33
- - When returned from **an LLM**, the type is ``list[list[Generation]]``.
34
- - When returned from a **chat model**, the type is ``list[list[ChatGeneration]]``.
33
+ - When returned from **an LLM**, the type is `list[list[Generation]]`.
34
+ - When returned from a **chat model**, the type is `list[list[ChatGeneration]]`.
35
35
 
36
36
  ChatGeneration is a subclass of Generation that has a field for a structured chat
37
37
  message.
38
38
  """
39
- llm_output: Optional[dict] = None
39
+ llm_output: dict | None = None
40
40
  """For arbitrary LLM provider specific output.
41
41
 
42
42
  This dictionary is a free-form dictionary that can contain any information that the
@@ -45,10 +45,10 @@ class LLMResult(BaseModel):
45
45
  Users should generally avoid relying on this field and instead rely on accessing
46
46
  relevant information from standardized fields present in AIMessage.
47
47
  """
48
- run: Optional[list[RunInfo]] = None
48
+ run: list[RunInfo] | None = None
49
49
  """List of metadata info for model call for each input.
50
50
 
51
- See :class:`~langchain_core.outputs.run_info.RunInfo` for details.
51
+ See `langchain_core.outputs.run_info.RunInfo` for details.
52
52
  """
53
53
 
54
54
  type: Literal["LLMResult"] = "LLMResult"
@@ -91,7 +91,14 @@ class LLMResult(BaseModel):
91
91
  return llm_results
92
92
 
93
93
  def __eq__(self, other: object) -> bool:
94
- """Check for LLMResult equality by ignoring any metadata related to runs."""
94
+ """Check for `LLMResult` equality by ignoring any metadata related to runs.
95
+
96
+ Args:
97
+ other: Another `LLMResult` object to compare against.
98
+
99
+ Returns:
100
+ `True` if the generations and `llm_output` are equal, `False` otherwise.
101
+ """
95
102
  if not isinstance(other, LLMResult):
96
103
  return NotImplemented
97
104
  return (