langchain-core 0.4.0.dev0__py3-none-any.whl → 1.0.0a2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- langchain_core/_api/beta_decorator.py +2 -2
- langchain_core/_api/deprecation.py +1 -1
- langchain_core/beta/runnables/context.py +1 -1
- langchain_core/callbacks/base.py +14 -23
- langchain_core/callbacks/file.py +13 -2
- langchain_core/callbacks/manager.py +74 -157
- langchain_core/callbacks/streaming_stdout.py +3 -4
- langchain_core/callbacks/usage.py +2 -12
- langchain_core/chat_history.py +6 -6
- langchain_core/documents/base.py +1 -1
- langchain_core/documents/compressor.py +9 -6
- langchain_core/indexing/base.py +2 -2
- langchain_core/language_models/_utils.py +232 -101
- langchain_core/language_models/base.py +35 -23
- langchain_core/language_models/chat_models.py +248 -54
- langchain_core/language_models/fake_chat_models.py +28 -81
- langchain_core/load/dump.py +3 -4
- langchain_core/messages/__init__.py +30 -24
- langchain_core/messages/ai.py +188 -30
- langchain_core/messages/base.py +164 -25
- langchain_core/messages/block_translators/__init__.py +89 -0
- langchain_core/messages/block_translators/anthropic.py +451 -0
- langchain_core/messages/block_translators/bedrock.py +45 -0
- langchain_core/messages/block_translators/bedrock_converse.py +47 -0
- langchain_core/messages/block_translators/google_genai.py +45 -0
- langchain_core/messages/block_translators/google_vertexai.py +47 -0
- langchain_core/messages/block_translators/groq.py +45 -0
- langchain_core/messages/block_translators/langchain_v0.py +164 -0
- langchain_core/messages/block_translators/ollama.py +45 -0
- langchain_core/messages/block_translators/openai.py +798 -0
- langchain_core/messages/{content_blocks.py → content.py} +303 -278
- langchain_core/messages/human.py +29 -9
- langchain_core/messages/system.py +29 -9
- langchain_core/messages/tool.py +94 -13
- langchain_core/messages/utils.py +34 -234
- langchain_core/output_parsers/base.py +14 -50
- langchain_core/output_parsers/json.py +2 -5
- langchain_core/output_parsers/list.py +2 -7
- langchain_core/output_parsers/openai_functions.py +5 -28
- langchain_core/output_parsers/openai_tools.py +49 -90
- langchain_core/output_parsers/pydantic.py +2 -3
- langchain_core/output_parsers/transform.py +12 -53
- langchain_core/output_parsers/xml.py +9 -17
- langchain_core/prompt_values.py +8 -112
- langchain_core/prompts/chat.py +1 -3
- langchain_core/runnables/base.py +500 -451
- langchain_core/runnables/branch.py +1 -1
- langchain_core/runnables/fallbacks.py +4 -4
- langchain_core/runnables/history.py +1 -1
- langchain_core/runnables/passthrough.py +3 -3
- langchain_core/runnables/retry.py +1 -1
- langchain_core/runnables/router.py +1 -1
- langchain_core/structured_query.py +3 -7
- langchain_core/tools/base.py +14 -41
- langchain_core/tools/convert.py +2 -22
- langchain_core/tools/retriever.py +1 -8
- langchain_core/tools/structured.py +2 -10
- langchain_core/tracers/_streaming.py +6 -7
- langchain_core/tracers/base.py +7 -14
- langchain_core/tracers/core.py +4 -27
- langchain_core/tracers/event_stream.py +4 -15
- langchain_core/tracers/langchain.py +3 -14
- langchain_core/tracers/log_stream.py +2 -3
- langchain_core/utils/_merge.py +45 -7
- langchain_core/utils/function_calling.py +22 -9
- langchain_core/utils/utils.py +29 -0
- langchain_core/version.py +1 -1
- {langchain_core-0.4.0.dev0.dist-info → langchain_core-1.0.0a2.dist-info}/METADATA +7 -9
- {langchain_core-0.4.0.dev0.dist-info → langchain_core-1.0.0a2.dist-info}/RECORD +71 -64
- langchain_core/v1/__init__.py +0 -1
- langchain_core/v1/chat_models.py +0 -1047
- langchain_core/v1/messages.py +0 -755
- {langchain_core-0.4.0.dev0.dist-info → langchain_core-1.0.0a2.dist-info}/WHEEL +0 -0
- {langchain_core-0.4.0.dev0.dist-info → langchain_core-1.0.0a2.dist-info}/entry_points.txt +0 -0
|
@@ -11,7 +11,6 @@ from typing import (
|
|
|
11
11
|
Optional,
|
|
12
12
|
TypeVar,
|
|
13
13
|
Union,
|
|
14
|
-
cast,
|
|
15
14
|
)
|
|
16
15
|
|
|
17
16
|
from typing_extensions import override
|
|
@@ -21,22 +20,19 @@ from langchain_core.messages import AnyMessage, BaseMessage
|
|
|
21
20
|
from langchain_core.outputs import ChatGeneration, Generation
|
|
22
21
|
from langchain_core.runnables import Runnable, RunnableConfig, RunnableSerializable
|
|
23
22
|
from langchain_core.runnables.config import run_in_executor
|
|
24
|
-
from langchain_core.v1.messages import AIMessage, MessageV1, MessageV1Types
|
|
25
23
|
|
|
26
24
|
if TYPE_CHECKING:
|
|
27
25
|
from langchain_core.prompt_values import PromptValue
|
|
28
26
|
|
|
29
27
|
T = TypeVar("T")
|
|
30
|
-
OutputParserLike = Runnable[
|
|
28
|
+
OutputParserLike = Runnable[LanguageModelOutput, T]
|
|
31
29
|
|
|
32
30
|
|
|
33
31
|
class BaseLLMOutputParser(ABC, Generic[T]):
|
|
34
32
|
"""Abstract base class for parsing the outputs of a model."""
|
|
35
33
|
|
|
36
34
|
@abstractmethod
|
|
37
|
-
def parse_result(
|
|
38
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
39
|
-
) -> T:
|
|
35
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> T:
|
|
40
36
|
"""Parse a list of candidate model Generations into a specific format.
|
|
41
37
|
|
|
42
38
|
Args:
|
|
@@ -50,7 +46,7 @@ class BaseLLMOutputParser(ABC, Generic[T]):
|
|
|
50
46
|
"""
|
|
51
47
|
|
|
52
48
|
async def aparse_result(
|
|
53
|
-
self, result:
|
|
49
|
+
self, result: list[Generation], *, partial: bool = False
|
|
54
50
|
) -> T:
|
|
55
51
|
"""Async parse a list of candidate model Generations into a specific format.
|
|
56
52
|
|
|
@@ -75,7 +71,7 @@ class BaseGenerationOutputParser(
|
|
|
75
71
|
@override
|
|
76
72
|
def InputType(self) -> Any:
|
|
77
73
|
"""Return the input type for the parser."""
|
|
78
|
-
return Union[str, AnyMessage
|
|
74
|
+
return Union[str, AnyMessage]
|
|
79
75
|
|
|
80
76
|
@property
|
|
81
77
|
@override
|
|
@@ -88,7 +84,7 @@ class BaseGenerationOutputParser(
|
|
|
88
84
|
@override
|
|
89
85
|
def invoke(
|
|
90
86
|
self,
|
|
91
|
-
input: Union[str, BaseMessage
|
|
87
|
+
input: Union[str, BaseMessage],
|
|
92
88
|
config: Optional[RunnableConfig] = None,
|
|
93
89
|
**kwargs: Any,
|
|
94
90
|
) -> T:
|
|
@@ -101,16 +97,9 @@ class BaseGenerationOutputParser(
|
|
|
101
97
|
config,
|
|
102
98
|
run_type="parser",
|
|
103
99
|
)
|
|
104
|
-
if isinstance(input, MessageV1Types):
|
|
105
|
-
return self._call_with_config(
|
|
106
|
-
lambda inner_input: self.parse_result(inner_input),
|
|
107
|
-
input,
|
|
108
|
-
config,
|
|
109
|
-
run_type="parser",
|
|
110
|
-
)
|
|
111
100
|
return self._call_with_config(
|
|
112
101
|
lambda inner_input: self.parse_result([Generation(text=inner_input)]),
|
|
113
|
-
|
|
102
|
+
input,
|
|
114
103
|
config,
|
|
115
104
|
run_type="parser",
|
|
116
105
|
)
|
|
@@ -131,13 +120,6 @@ class BaseGenerationOutputParser(
|
|
|
131
120
|
config,
|
|
132
121
|
run_type="parser",
|
|
133
122
|
)
|
|
134
|
-
if isinstance(input, MessageV1Types):
|
|
135
|
-
return await self._acall_with_config(
|
|
136
|
-
lambda inner_input: self.aparse_result(inner_input),
|
|
137
|
-
input,
|
|
138
|
-
config,
|
|
139
|
-
run_type="parser",
|
|
140
|
-
)
|
|
141
123
|
return await self._acall_with_config(
|
|
142
124
|
lambda inner_input: self.aparse_result([Generation(text=inner_input)]),
|
|
143
125
|
input,
|
|
@@ -147,7 +129,7 @@ class BaseGenerationOutputParser(
|
|
|
147
129
|
|
|
148
130
|
|
|
149
131
|
class BaseOutputParser(
|
|
150
|
-
BaseLLMOutputParser, RunnableSerializable[
|
|
132
|
+
BaseLLMOutputParser, RunnableSerializable[LanguageModelOutput, T]
|
|
151
133
|
):
|
|
152
134
|
"""Base class to parse the output of an LLM call.
|
|
153
135
|
|
|
@@ -180,7 +162,7 @@ class BaseOutputParser(
|
|
|
180
162
|
@override
|
|
181
163
|
def InputType(self) -> Any:
|
|
182
164
|
"""Return the input type for the parser."""
|
|
183
|
-
return Union[str, AnyMessage
|
|
165
|
+
return Union[str, AnyMessage]
|
|
184
166
|
|
|
185
167
|
@property
|
|
186
168
|
@override
|
|
@@ -207,7 +189,7 @@ class BaseOutputParser(
|
|
|
207
189
|
@override
|
|
208
190
|
def invoke(
|
|
209
191
|
self,
|
|
210
|
-
input: Union[str, BaseMessage
|
|
192
|
+
input: Union[str, BaseMessage],
|
|
211
193
|
config: Optional[RunnableConfig] = None,
|
|
212
194
|
**kwargs: Any,
|
|
213
195
|
) -> T:
|
|
@@ -220,16 +202,9 @@ class BaseOutputParser(
|
|
|
220
202
|
config,
|
|
221
203
|
run_type="parser",
|
|
222
204
|
)
|
|
223
|
-
if isinstance(input, MessageV1Types):
|
|
224
|
-
return self._call_with_config(
|
|
225
|
-
lambda inner_input: self.parse_result(inner_input),
|
|
226
|
-
input,
|
|
227
|
-
config,
|
|
228
|
-
run_type="parser",
|
|
229
|
-
)
|
|
230
205
|
return self._call_with_config(
|
|
231
206
|
lambda inner_input: self.parse_result([Generation(text=inner_input)]),
|
|
232
|
-
|
|
207
|
+
input,
|
|
233
208
|
config,
|
|
234
209
|
run_type="parser",
|
|
235
210
|
)
|
|
@@ -237,7 +212,7 @@ class BaseOutputParser(
|
|
|
237
212
|
@override
|
|
238
213
|
async def ainvoke(
|
|
239
214
|
self,
|
|
240
|
-
input: Union[str, BaseMessage
|
|
215
|
+
input: Union[str, BaseMessage],
|
|
241
216
|
config: Optional[RunnableConfig] = None,
|
|
242
217
|
**kwargs: Optional[Any],
|
|
243
218
|
) -> T:
|
|
@@ -250,24 +225,15 @@ class BaseOutputParser(
|
|
|
250
225
|
config,
|
|
251
226
|
run_type="parser",
|
|
252
227
|
)
|
|
253
|
-
if isinstance(input, MessageV1Types):
|
|
254
|
-
return await self._acall_with_config(
|
|
255
|
-
lambda inner_input: self.aparse_result(inner_input),
|
|
256
|
-
input,
|
|
257
|
-
config,
|
|
258
|
-
run_type="parser",
|
|
259
|
-
)
|
|
260
228
|
return await self._acall_with_config(
|
|
261
229
|
lambda inner_input: self.aparse_result([Generation(text=inner_input)]),
|
|
262
|
-
|
|
230
|
+
input,
|
|
263
231
|
config,
|
|
264
232
|
run_type="parser",
|
|
265
233
|
)
|
|
266
234
|
|
|
267
235
|
@override
|
|
268
|
-
def parse_result(
|
|
269
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
270
|
-
) -> T:
|
|
236
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> T:
|
|
271
237
|
"""Parse a list of candidate model Generations into a specific format.
|
|
272
238
|
|
|
273
239
|
The return value is parsed from only the first Generation in the result, which
|
|
@@ -282,8 +248,6 @@ class BaseOutputParser(
|
|
|
282
248
|
Returns:
|
|
283
249
|
Structured output.
|
|
284
250
|
"""
|
|
285
|
-
if isinstance(result, AIMessage):
|
|
286
|
-
return self.parse(result.text)
|
|
287
251
|
return self.parse(result[0].text)
|
|
288
252
|
|
|
289
253
|
@abstractmethod
|
|
@@ -298,7 +262,7 @@ class BaseOutputParser(
|
|
|
298
262
|
"""
|
|
299
263
|
|
|
300
264
|
async def aparse_result(
|
|
301
|
-
self, result:
|
|
265
|
+
self, result: list[Generation], *, partial: bool = False
|
|
302
266
|
) -> T:
|
|
303
267
|
"""Async parse a list of candidate model Generations into a specific format.
|
|
304
268
|
|
|
@@ -21,7 +21,6 @@ from langchain_core.utils.json import (
|
|
|
21
21
|
parse_json_markdown,
|
|
22
22
|
parse_partial_json,
|
|
23
23
|
)
|
|
24
|
-
from langchain_core.v1.messages import AIMessage
|
|
25
24
|
|
|
26
25
|
# Union type needs to be last assignment to PydanticBaseModel to make mypy happy.
|
|
27
26
|
PydanticBaseModel = Union[BaseModel, pydantic.BaseModel]
|
|
@@ -54,9 +53,7 @@ class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]):
|
|
|
54
53
|
return pydantic_object.schema()
|
|
55
54
|
return None
|
|
56
55
|
|
|
57
|
-
def parse_result(
|
|
58
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
59
|
-
) -> Any:
|
|
56
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
60
57
|
"""Parse the result of an LLM call to a JSON object.
|
|
61
58
|
|
|
62
59
|
Args:
|
|
@@ -73,7 +70,7 @@ class JsonOutputParser(BaseCumulativeTransformOutputParser[Any]):
|
|
|
73
70
|
Raises:
|
|
74
71
|
OutputParserException: If the output is not valid JSON.
|
|
75
72
|
"""
|
|
76
|
-
text = result
|
|
73
|
+
text = result[0].text
|
|
77
74
|
text = text.strip()
|
|
78
75
|
if partial:
|
|
79
76
|
try:
|
|
@@ -13,7 +13,6 @@ from typing_extensions import override
|
|
|
13
13
|
|
|
14
14
|
from langchain_core.messages import BaseMessage
|
|
15
15
|
from langchain_core.output_parsers.transform import BaseTransformOutputParser
|
|
16
|
-
from langchain_core.v1.messages import AIMessage
|
|
17
16
|
|
|
18
17
|
if TYPE_CHECKING:
|
|
19
18
|
from collections.abc import AsyncIterator, Iterator
|
|
@@ -72,7 +71,7 @@ class ListOutputParser(BaseTransformOutputParser[list[str]]):
|
|
|
72
71
|
|
|
73
72
|
@override
|
|
74
73
|
def _transform(
|
|
75
|
-
self, input: Iterator[Union[str, BaseMessage
|
|
74
|
+
self, input: Iterator[Union[str, BaseMessage]]
|
|
76
75
|
) -> Iterator[list[str]]:
|
|
77
76
|
buffer = ""
|
|
78
77
|
for chunk in input:
|
|
@@ -82,8 +81,6 @@ class ListOutputParser(BaseTransformOutputParser[list[str]]):
|
|
|
82
81
|
if not isinstance(chunk_content, str):
|
|
83
82
|
continue
|
|
84
83
|
buffer += chunk_content
|
|
85
|
-
elif isinstance(chunk, AIMessage):
|
|
86
|
-
buffer += chunk.text
|
|
87
84
|
else:
|
|
88
85
|
# add current chunk to buffer
|
|
89
86
|
buffer += chunk
|
|
@@ -108,7 +105,7 @@ class ListOutputParser(BaseTransformOutputParser[list[str]]):
|
|
|
108
105
|
|
|
109
106
|
@override
|
|
110
107
|
async def _atransform(
|
|
111
|
-
self, input: AsyncIterator[Union[str, BaseMessage
|
|
108
|
+
self, input: AsyncIterator[Union[str, BaseMessage]]
|
|
112
109
|
) -> AsyncIterator[list[str]]:
|
|
113
110
|
buffer = ""
|
|
114
111
|
async for chunk in input:
|
|
@@ -118,8 +115,6 @@ class ListOutputParser(BaseTransformOutputParser[list[str]]):
|
|
|
118
115
|
if not isinstance(chunk_content, str):
|
|
119
116
|
continue
|
|
120
117
|
buffer += chunk_content
|
|
121
|
-
elif isinstance(chunk, AIMessage):
|
|
122
|
-
buffer += chunk.text
|
|
123
118
|
else:
|
|
124
119
|
# add current chunk to buffer
|
|
125
120
|
buffer += chunk
|
|
@@ -17,7 +17,6 @@ from langchain_core.output_parsers import (
|
|
|
17
17
|
)
|
|
18
18
|
from langchain_core.output_parsers.json import parse_partial_json
|
|
19
19
|
from langchain_core.outputs import ChatGeneration, Generation
|
|
20
|
-
from langchain_core.v1.messages import AIMessage
|
|
21
20
|
|
|
22
21
|
|
|
23
22
|
class OutputFunctionsParser(BaseGenerationOutputParser[Any]):
|
|
@@ -27,9 +26,7 @@ class OutputFunctionsParser(BaseGenerationOutputParser[Any]):
|
|
|
27
26
|
"""Whether to only return the arguments to the function call."""
|
|
28
27
|
|
|
29
28
|
@override
|
|
30
|
-
def parse_result(
|
|
31
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
32
|
-
) -> Any:
|
|
29
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
33
30
|
"""Parse the result of an LLM call to a JSON object.
|
|
34
31
|
|
|
35
32
|
Args:
|
|
@@ -42,12 +39,6 @@ class OutputFunctionsParser(BaseGenerationOutputParser[Any]):
|
|
|
42
39
|
Raises:
|
|
43
40
|
OutputParserException: If the output is not valid JSON.
|
|
44
41
|
"""
|
|
45
|
-
if isinstance(result, AIMessage):
|
|
46
|
-
msg = (
|
|
47
|
-
"This output parser does not support v1 AIMessages. Use "
|
|
48
|
-
"JsonOutputToolsParser instead."
|
|
49
|
-
)
|
|
50
|
-
raise TypeError(msg)
|
|
51
42
|
generation = result[0]
|
|
52
43
|
if not isinstance(generation, ChatGeneration):
|
|
53
44
|
msg = "This output parser can only be used with a chat generation."
|
|
@@ -86,9 +77,7 @@ class JsonOutputFunctionsParser(BaseCumulativeTransformOutputParser[Any]):
|
|
|
86
77
|
def _diff(self, prev: Optional[Any], next: Any) -> Any:
|
|
87
78
|
return jsonpatch.make_patch(prev, next).patch
|
|
88
79
|
|
|
89
|
-
def parse_result(
|
|
90
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
91
|
-
) -> Any:
|
|
80
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
92
81
|
"""Parse the result of an LLM call to a JSON object.
|
|
93
82
|
|
|
94
83
|
Args:
|
|
@@ -101,12 +90,6 @@ class JsonOutputFunctionsParser(BaseCumulativeTransformOutputParser[Any]):
|
|
|
101
90
|
Raises:
|
|
102
91
|
OutputParserException: If the output is not valid JSON.
|
|
103
92
|
"""
|
|
104
|
-
if isinstance(result, AIMessage):
|
|
105
|
-
msg = (
|
|
106
|
-
"This output parser does not support v1 AIMessages. Use "
|
|
107
|
-
"JsonOutputToolsParser instead."
|
|
108
|
-
)
|
|
109
|
-
raise TypeError(msg)
|
|
110
93
|
if len(result) != 1:
|
|
111
94
|
msg = f"Expected exactly one result, but got {len(result)}"
|
|
112
95
|
raise OutputParserException(msg)
|
|
@@ -177,9 +160,7 @@ class JsonKeyOutputFunctionsParser(JsonOutputFunctionsParser):
|
|
|
177
160
|
key_name: str
|
|
178
161
|
"""The name of the key to return."""
|
|
179
162
|
|
|
180
|
-
def parse_result(
|
|
181
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
182
|
-
) -> Any:
|
|
163
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
183
164
|
"""Parse the result of an LLM call to a JSON object.
|
|
184
165
|
|
|
185
166
|
Args:
|
|
@@ -273,9 +254,7 @@ class PydanticOutputFunctionsParser(OutputFunctionsParser):
|
|
|
273
254
|
return values
|
|
274
255
|
|
|
275
256
|
@override
|
|
276
|
-
def parse_result(
|
|
277
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
278
|
-
) -> Any:
|
|
257
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
279
258
|
"""Parse the result of an LLM call to a JSON object.
|
|
280
259
|
|
|
281
260
|
Args:
|
|
@@ -315,9 +294,7 @@ class PydanticAttrOutputFunctionsParser(PydanticOutputFunctionsParser):
|
|
|
315
294
|
"""The name of the attribute to return."""
|
|
316
295
|
|
|
317
296
|
@override
|
|
318
|
-
def parse_result(
|
|
319
|
-
self, result: Union[list[Generation], AIMessage], *, partial: bool = False
|
|
320
|
-
) -> Any:
|
|
297
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
321
298
|
"""Parse the result of an LLM call to a JSON object.
|
|
322
299
|
|
|
323
300
|
Args:
|
|
@@ -4,7 +4,7 @@ import copy
|
|
|
4
4
|
import json
|
|
5
5
|
import logging
|
|
6
6
|
from json import JSONDecodeError
|
|
7
|
-
from typing import Annotated, Any, Optional
|
|
7
|
+
from typing import Annotated, Any, Optional
|
|
8
8
|
|
|
9
9
|
from pydantic import SkipValidation, ValidationError
|
|
10
10
|
|
|
@@ -16,7 +16,6 @@ from langchain_core.output_parsers.transform import BaseCumulativeTransformOutpu
|
|
|
16
16
|
from langchain_core.outputs import ChatGeneration, Generation
|
|
17
17
|
from langchain_core.utils.json import parse_partial_json
|
|
18
18
|
from langchain_core.utils.pydantic import TypeBaseModel
|
|
19
|
-
from langchain_core.v1.messages import AIMessage as AIMessageV1
|
|
20
19
|
|
|
21
20
|
logger = logging.getLogger(__name__)
|
|
22
21
|
|
|
@@ -157,9 +156,7 @@ class JsonOutputToolsParser(BaseCumulativeTransformOutputParser[Any]):
|
|
|
157
156
|
If no tool calls are found, None will be returned.
|
|
158
157
|
"""
|
|
159
158
|
|
|
160
|
-
def parse_result(
|
|
161
|
-
self, result: Union[list[Generation], AIMessageV1], *, partial: bool = False
|
|
162
|
-
) -> Any:
|
|
159
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
163
160
|
"""Parse the result of an LLM call to a list of tool calls.
|
|
164
161
|
|
|
165
162
|
Args:
|
|
@@ -176,45 +173,31 @@ class JsonOutputToolsParser(BaseCumulativeTransformOutputParser[Any]):
|
|
|
176
173
|
Raises:
|
|
177
174
|
OutputParserException: If the output is not valid JSON.
|
|
178
175
|
"""
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
raise OutputParserException(msg)
|
|
187
|
-
message = generation.message
|
|
188
|
-
if isinstance(message, AIMessage) and message.tool_calls:
|
|
189
|
-
tool_calls = [dict(tc) for tc in message.tool_calls]
|
|
190
|
-
for tool_call in tool_calls:
|
|
191
|
-
if not self.return_id:
|
|
192
|
-
_ = tool_call.pop("id")
|
|
193
|
-
else:
|
|
194
|
-
try:
|
|
195
|
-
raw_tool_calls = copy.deepcopy(
|
|
196
|
-
message.additional_kwargs["tool_calls"]
|
|
197
|
-
)
|
|
198
|
-
except KeyError:
|
|
199
|
-
return []
|
|
200
|
-
tool_calls = parse_tool_calls(
|
|
201
|
-
raw_tool_calls,
|
|
202
|
-
partial=partial,
|
|
203
|
-
strict=self.strict,
|
|
204
|
-
return_id=self.return_id,
|
|
205
|
-
)
|
|
206
|
-
elif result.tool_calls:
|
|
207
|
-
# v1 message
|
|
208
|
-
tool_calls = [dict(tc) for tc in result.tool_calls]
|
|
176
|
+
generation = result[0]
|
|
177
|
+
if not isinstance(generation, ChatGeneration):
|
|
178
|
+
msg = "This output parser can only be used with a chat generation."
|
|
179
|
+
raise OutputParserException(msg)
|
|
180
|
+
message = generation.message
|
|
181
|
+
if isinstance(message, AIMessage) and message.tool_calls:
|
|
182
|
+
tool_calls = [dict(tc) for tc in message.tool_calls]
|
|
209
183
|
for tool_call in tool_calls:
|
|
210
184
|
if not self.return_id:
|
|
211
185
|
_ = tool_call.pop("id")
|
|
212
186
|
else:
|
|
213
|
-
|
|
214
|
-
|
|
187
|
+
try:
|
|
188
|
+
raw_tool_calls = copy.deepcopy(message.additional_kwargs["tool_calls"])
|
|
189
|
+
except KeyError:
|
|
190
|
+
return []
|
|
191
|
+
tool_calls = parse_tool_calls(
|
|
192
|
+
raw_tool_calls,
|
|
193
|
+
partial=partial,
|
|
194
|
+
strict=self.strict,
|
|
195
|
+
return_id=self.return_id,
|
|
196
|
+
)
|
|
215
197
|
# for backwards compatibility
|
|
216
198
|
for tc in tool_calls:
|
|
217
199
|
tc["type"] = tc.pop("name")
|
|
200
|
+
|
|
218
201
|
if self.first_tool_only:
|
|
219
202
|
return tool_calls[0] if tool_calls else None
|
|
220
203
|
return tool_calls
|
|
@@ -237,9 +220,7 @@ class JsonOutputKeyToolsParser(JsonOutputToolsParser):
|
|
|
237
220
|
key_name: str
|
|
238
221
|
"""The type of tools to return."""
|
|
239
222
|
|
|
240
|
-
def parse_result(
|
|
241
|
-
self, result: Union[list[Generation], AIMessageV1], *, partial: bool = False
|
|
242
|
-
) -> Any:
|
|
223
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
243
224
|
"""Parse the result of an LLM call to a list of tool calls.
|
|
244
225
|
|
|
245
226
|
Args:
|
|
@@ -253,47 +234,34 @@ class JsonOutputKeyToolsParser(JsonOutputToolsParser):
|
|
|
253
234
|
Returns:
|
|
254
235
|
The parsed tool calls.
|
|
255
236
|
"""
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
parsed_tool_calls = [dict(tc) for tc in message.tool_calls]
|
|
264
|
-
for tool_call in parsed_tool_calls:
|
|
265
|
-
if not self.return_id:
|
|
266
|
-
_ = tool_call.pop("id")
|
|
267
|
-
else:
|
|
268
|
-
try:
|
|
269
|
-
raw_tool_calls = copy.deepcopy(
|
|
270
|
-
message.additional_kwargs["tool_calls"]
|
|
271
|
-
)
|
|
272
|
-
except KeyError:
|
|
273
|
-
if self.first_tool_only:
|
|
274
|
-
return None
|
|
275
|
-
return []
|
|
276
|
-
parsed_tool_calls = parse_tool_calls(
|
|
277
|
-
raw_tool_calls,
|
|
278
|
-
partial=partial,
|
|
279
|
-
strict=self.strict,
|
|
280
|
-
return_id=self.return_id,
|
|
281
|
-
)
|
|
282
|
-
elif result.tool_calls:
|
|
283
|
-
# v1 message
|
|
284
|
-
parsed_tool_calls = [dict(tc) for tc in result.tool_calls]
|
|
237
|
+
generation = result[0]
|
|
238
|
+
if not isinstance(generation, ChatGeneration):
|
|
239
|
+
msg = "This output parser can only be used with a chat generation."
|
|
240
|
+
raise OutputParserException(msg)
|
|
241
|
+
message = generation.message
|
|
242
|
+
if isinstance(message, AIMessage) and message.tool_calls:
|
|
243
|
+
parsed_tool_calls = [dict(tc) for tc in message.tool_calls]
|
|
285
244
|
for tool_call in parsed_tool_calls:
|
|
286
245
|
if not self.return_id:
|
|
287
246
|
_ = tool_call.pop("id")
|
|
288
247
|
else:
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
248
|
+
try:
|
|
249
|
+
# This exists purely for backward compatibility / cached messages
|
|
250
|
+
# All new messages should use `message.tool_calls`
|
|
251
|
+
raw_tool_calls = copy.deepcopy(message.additional_kwargs["tool_calls"])
|
|
252
|
+
except KeyError:
|
|
253
|
+
if self.first_tool_only:
|
|
254
|
+
return None
|
|
255
|
+
return []
|
|
256
|
+
parsed_tool_calls = parse_tool_calls(
|
|
257
|
+
raw_tool_calls,
|
|
258
|
+
partial=partial,
|
|
259
|
+
strict=self.strict,
|
|
260
|
+
return_id=self.return_id,
|
|
261
|
+
)
|
|
293
262
|
# For backwards compatibility
|
|
294
263
|
for tc in parsed_tool_calls:
|
|
295
264
|
tc["type"] = tc.pop("name")
|
|
296
|
-
|
|
297
265
|
if self.first_tool_only:
|
|
298
266
|
parsed_result = list(
|
|
299
267
|
filter(lambda x: x["type"] == self.key_name, parsed_tool_calls)
|
|
@@ -333,9 +301,7 @@ class PydanticToolsParser(JsonOutputToolsParser):
|
|
|
333
301
|
|
|
334
302
|
# TODO: Support more granular streaming of objects. Currently only streams once all
|
|
335
303
|
# Pydantic object fields are present.
|
|
336
|
-
def parse_result(
|
|
337
|
-
self, result: Union[list[Generation], AIMessageV1], *, partial: bool = False
|
|
338
|
-
) -> Any:
|
|
304
|
+
def parse_result(self, result: list[Generation], *, partial: bool = False) -> Any:
|
|
339
305
|
"""Parse the result of an LLM call to a list of Pydantic objects.
|
|
340
306
|
|
|
341
307
|
Args:
|
|
@@ -373,19 +339,12 @@ class PydanticToolsParser(JsonOutputToolsParser):
|
|
|
373
339
|
except (ValidationError, ValueError):
|
|
374
340
|
if partial:
|
|
375
341
|
continue
|
|
376
|
-
has_max_tokens_stop_reason =
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if isinstance(generation, ChatGeneration)
|
|
383
|
-
)
|
|
384
|
-
else:
|
|
385
|
-
# v1 message
|
|
386
|
-
has_max_tokens_stop_reason = (
|
|
387
|
-
result.response_metadata.get("stop_reason") == "max_tokens"
|
|
388
|
-
)
|
|
342
|
+
has_max_tokens_stop_reason = any(
|
|
343
|
+
generation.message.response_metadata.get("stop_reason")
|
|
344
|
+
== "max_tokens"
|
|
345
|
+
for generation in result
|
|
346
|
+
if isinstance(generation, ChatGeneration)
|
|
347
|
+
)
|
|
389
348
|
if has_max_tokens_stop_reason:
|
|
390
349
|
logger.exception(_MAX_TOKENS_ERROR)
|
|
391
350
|
raise
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"""Output parsers using Pydantic."""
|
|
2
2
|
|
|
3
3
|
import json
|
|
4
|
-
from typing import Annotated, Generic, Optional
|
|
4
|
+
from typing import Annotated, Generic, Optional
|
|
5
5
|
|
|
6
6
|
import pydantic
|
|
7
7
|
from pydantic import SkipValidation
|
|
@@ -14,7 +14,6 @@ from langchain_core.utils.pydantic import (
|
|
|
14
14
|
PydanticBaseModel,
|
|
15
15
|
TBaseModel,
|
|
16
16
|
)
|
|
17
|
-
from langchain_core.v1.messages import AIMessage
|
|
18
17
|
|
|
19
18
|
|
|
20
19
|
class PydanticOutputParser(JsonOutputParser, Generic[TBaseModel]):
|
|
@@ -44,7 +43,7 @@ class PydanticOutputParser(JsonOutputParser, Generic[TBaseModel]):
|
|
|
44
43
|
return OutputParserException(msg, llm_output=json_string)
|
|
45
44
|
|
|
46
45
|
def parse_result(
|
|
47
|
-
self, result:
|
|
46
|
+
self, result: list[Generation], *, partial: bool = False
|
|
48
47
|
) -> Optional[TBaseModel]:
|
|
49
48
|
"""Parse the result of an LLM call to a pydantic object.
|
|
50
49
|
|