langchain-core 0.3.75__py3-none-any.whl → 0.3.77__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of langchain-core might be problematic. Click here for more details.
- langchain_core/_api/beta_decorator.py +22 -44
- langchain_core/_api/deprecation.py +30 -17
- langchain_core/_api/path.py +19 -2
- langchain_core/_import_utils.py +7 -0
- langchain_core/agents.py +10 -6
- langchain_core/beta/runnables/context.py +1 -2
- langchain_core/callbacks/base.py +28 -15
- langchain_core/callbacks/manager.py +83 -71
- langchain_core/callbacks/usage.py +6 -4
- langchain_core/chat_history.py +29 -21
- langchain_core/document_loaders/base.py +34 -9
- langchain_core/document_loaders/langsmith.py +4 -1
- langchain_core/documents/base.py +35 -10
- langchain_core/documents/transformers.py +4 -2
- langchain_core/embeddings/fake.py +8 -5
- langchain_core/env.py +2 -3
- langchain_core/example_selectors/base.py +12 -0
- langchain_core/exceptions.py +7 -0
- langchain_core/globals.py +17 -28
- langchain_core/indexing/api.py +88 -76
- langchain_core/indexing/base.py +5 -8
- langchain_core/indexing/in_memory.py +23 -3
- langchain_core/language_models/__init__.py +3 -2
- langchain_core/language_models/base.py +31 -20
- langchain_core/language_models/chat_models.py +98 -27
- langchain_core/language_models/fake_chat_models.py +10 -9
- langchain_core/language_models/llms.py +52 -18
- langchain_core/load/dump.py +2 -3
- langchain_core/load/load.py +15 -1
- langchain_core/load/serializable.py +39 -44
- langchain_core/memory.py +7 -3
- langchain_core/messages/ai.py +53 -24
- langchain_core/messages/base.py +43 -22
- langchain_core/messages/chat.py +4 -1
- langchain_core/messages/content_blocks.py +23 -2
- langchain_core/messages/function.py +9 -5
- langchain_core/messages/human.py +13 -10
- langchain_core/messages/modifier.py +1 -0
- langchain_core/messages/system.py +11 -8
- langchain_core/messages/tool.py +60 -29
- langchain_core/messages/utils.py +250 -131
- langchain_core/output_parsers/base.py +5 -2
- langchain_core/output_parsers/json.py +4 -4
- langchain_core/output_parsers/list.py +7 -22
- langchain_core/output_parsers/openai_functions.py +3 -0
- langchain_core/output_parsers/openai_tools.py +6 -1
- langchain_core/output_parsers/pydantic.py +4 -0
- langchain_core/output_parsers/string.py +5 -1
- langchain_core/output_parsers/xml.py +19 -19
- langchain_core/outputs/chat_generation.py +25 -10
- langchain_core/outputs/generation.py +14 -3
- langchain_core/outputs/llm_result.py +8 -1
- langchain_core/prompt_values.py +16 -6
- langchain_core/prompts/base.py +4 -9
- langchain_core/prompts/chat.py +89 -57
- langchain_core/prompts/dict.py +16 -8
- langchain_core/prompts/few_shot.py +12 -11
- langchain_core/prompts/few_shot_with_templates.py +5 -1
- langchain_core/prompts/image.py +12 -5
- langchain_core/prompts/message.py +5 -6
- langchain_core/prompts/pipeline.py +13 -8
- langchain_core/prompts/prompt.py +22 -8
- langchain_core/prompts/string.py +18 -10
- langchain_core/prompts/structured.py +7 -2
- langchain_core/rate_limiters.py +2 -2
- langchain_core/retrievers.py +7 -6
- langchain_core/runnables/base.py +406 -186
- langchain_core/runnables/branch.py +14 -19
- langchain_core/runnables/config.py +9 -15
- langchain_core/runnables/configurable.py +34 -19
- langchain_core/runnables/fallbacks.py +20 -13
- langchain_core/runnables/graph.py +48 -38
- langchain_core/runnables/graph_ascii.py +41 -18
- langchain_core/runnables/graph_mermaid.py +54 -25
- langchain_core/runnables/graph_png.py +27 -31
- langchain_core/runnables/history.py +55 -58
- langchain_core/runnables/passthrough.py +44 -21
- langchain_core/runnables/retry.py +44 -23
- langchain_core/runnables/router.py +9 -8
- langchain_core/runnables/schema.py +2 -0
- langchain_core/runnables/utils.py +51 -89
- langchain_core/stores.py +19 -31
- langchain_core/sys_info.py +9 -8
- langchain_core/tools/base.py +37 -28
- langchain_core/tools/convert.py +26 -15
- langchain_core/tools/simple.py +36 -8
- langchain_core/tools/structured.py +25 -12
- langchain_core/tracers/base.py +2 -2
- langchain_core/tracers/context.py +5 -1
- langchain_core/tracers/core.py +109 -39
- langchain_core/tracers/evaluation.py +22 -26
- langchain_core/tracers/event_stream.py +45 -34
- langchain_core/tracers/langchain.py +12 -3
- langchain_core/tracers/langchain_v1.py +10 -2
- langchain_core/tracers/log_stream.py +56 -17
- langchain_core/tracers/root_listeners.py +4 -20
- langchain_core/tracers/run_collector.py +6 -16
- langchain_core/tracers/schemas.py +5 -1
- langchain_core/utils/aiter.py +15 -7
- langchain_core/utils/env.py +3 -0
- langchain_core/utils/function_calling.py +50 -28
- langchain_core/utils/interactive_env.py +6 -2
- langchain_core/utils/iter.py +12 -4
- langchain_core/utils/json.py +12 -3
- langchain_core/utils/json_schema.py +156 -40
- langchain_core/utils/loading.py +5 -1
- langchain_core/utils/mustache.py +24 -15
- langchain_core/utils/pydantic.py +38 -9
- langchain_core/utils/utils.py +25 -9
- langchain_core/vectorstores/base.py +7 -20
- langchain_core/vectorstores/in_memory.py +23 -17
- langchain_core/vectorstores/utils.py +18 -12
- langchain_core/version.py +1 -1
- langchain_core-0.3.77.dist-info/METADATA +67 -0
- langchain_core-0.3.77.dist-info/RECORD +174 -0
- langchain_core-0.3.75.dist-info/METADATA +0 -106
- langchain_core-0.3.75.dist-info/RECORD +0 -174
- {langchain_core-0.3.75.dist-info → langchain_core-0.3.77.dist-info}/WHEEL +0 -0
- {langchain_core-0.3.75.dist-info → langchain_core-0.3.77.dist-info}/entry_points.txt +0 -0
|
@@ -7,6 +7,7 @@ import contextlib
|
|
|
7
7
|
import copy
|
|
8
8
|
import threading
|
|
9
9
|
from collections import defaultdict
|
|
10
|
+
from pprint import pformat
|
|
10
11
|
from typing import (
|
|
11
12
|
TYPE_CHECKING,
|
|
12
13
|
Any,
|
|
@@ -20,10 +21,11 @@ from typing import (
|
|
|
20
21
|
import jsonpatch # type: ignore[import-untyped]
|
|
21
22
|
from typing_extensions import NotRequired, TypedDict, override
|
|
22
23
|
|
|
24
|
+
from langchain_core.callbacks.base import BaseCallbackManager
|
|
23
25
|
from langchain_core.load import dumps
|
|
24
26
|
from langchain_core.load.load import load
|
|
25
27
|
from langchain_core.outputs import ChatGenerationChunk, GenerationChunk
|
|
26
|
-
from langchain_core.runnables import
|
|
28
|
+
from langchain_core.runnables import RunnableConfig, ensure_config
|
|
27
29
|
from langchain_core.tracers._streaming import _StreamingCallbackHandler
|
|
28
30
|
from langchain_core.tracers.base import BaseTracer
|
|
29
31
|
from langchain_core.tracers.memory_stream import _MemoryStream
|
|
@@ -32,6 +34,7 @@ if TYPE_CHECKING:
|
|
|
32
34
|
from collections.abc import AsyncIterator, Iterator, Sequence
|
|
33
35
|
from uuid import UUID
|
|
34
36
|
|
|
37
|
+
from langchain_core.runnables import Runnable
|
|
35
38
|
from langchain_core.runnables.utils import Input, Output
|
|
36
39
|
from langchain_core.tracers.schemas import Run
|
|
37
40
|
|
|
@@ -110,7 +113,17 @@ class RunLogPatch:
|
|
|
110
113
|
self.ops = list(ops)
|
|
111
114
|
|
|
112
115
|
def __add__(self, other: Union[RunLogPatch, Any]) -> RunLog:
|
|
113
|
-
"""Combine two RunLogPatch instances.
|
|
116
|
+
"""Combine two ``RunLogPatch`` instances.
|
|
117
|
+
|
|
118
|
+
Args:
|
|
119
|
+
other: The other ``RunLogPatch`` to combine with.
|
|
120
|
+
|
|
121
|
+
Raises:
|
|
122
|
+
TypeError: If the other object is not a ``RunLogPatch``.
|
|
123
|
+
|
|
124
|
+
Returns:
|
|
125
|
+
A new ``RunLog`` representing the combination of the two.
|
|
126
|
+
"""
|
|
114
127
|
if type(other) is RunLogPatch:
|
|
115
128
|
ops = self.ops + other.ops
|
|
116
129
|
state = jsonpatch.apply_patch(None, copy.deepcopy(ops))
|
|
@@ -121,8 +134,6 @@ class RunLogPatch:
|
|
|
121
134
|
|
|
122
135
|
@override
|
|
123
136
|
def __repr__(self) -> str:
|
|
124
|
-
from pprint import pformat
|
|
125
|
-
|
|
126
137
|
# 1:-1 to get rid of the [] around the list
|
|
127
138
|
return f"RunLogPatch({pformat(self.ops)[1:-1]})"
|
|
128
139
|
|
|
@@ -150,7 +161,17 @@ class RunLog(RunLogPatch):
|
|
|
150
161
|
self.state = state
|
|
151
162
|
|
|
152
163
|
def __add__(self, other: Union[RunLogPatch, Any]) -> RunLog:
|
|
153
|
-
"""Combine two
|
|
164
|
+
"""Combine two ``RunLog``s.
|
|
165
|
+
|
|
166
|
+
Args:
|
|
167
|
+
other: The other ``RunLog`` or ``RunLogPatch`` to combine with.
|
|
168
|
+
|
|
169
|
+
Raises:
|
|
170
|
+
TypeError: If the other object is not a ``RunLog`` or ``RunLogPatch``.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
A new ``RunLog`` representing the combination of the two.
|
|
174
|
+
"""
|
|
154
175
|
if type(other) is RunLogPatch:
|
|
155
176
|
ops = self.ops + other.ops
|
|
156
177
|
state = jsonpatch.apply_patch(self.state, other.ops)
|
|
@@ -161,13 +182,18 @@ class RunLog(RunLogPatch):
|
|
|
161
182
|
|
|
162
183
|
@override
|
|
163
184
|
def __repr__(self) -> str:
|
|
164
|
-
from pprint import pformat
|
|
165
|
-
|
|
166
185
|
return f"RunLog({pformat(self.state)})"
|
|
167
186
|
|
|
168
187
|
@override
|
|
169
188
|
def __eq__(self, other: object) -> bool:
|
|
170
|
-
"""Check if two
|
|
189
|
+
"""Check if two ``RunLog``s are equal.
|
|
190
|
+
|
|
191
|
+
Args:
|
|
192
|
+
other: The other ``RunLog`` to compare to.
|
|
193
|
+
|
|
194
|
+
Returns:
|
|
195
|
+
True if the ``RunLog``s are equal, False otherwise.
|
|
196
|
+
"""
|
|
171
197
|
# First compare that the state is the same
|
|
172
198
|
if not isinstance(other, RunLog):
|
|
173
199
|
return False
|
|
@@ -250,7 +276,11 @@ class LogStreamCallbackHandler(BaseTracer, _StreamingCallbackHandler):
|
|
|
250
276
|
self.root_id: Optional[UUID] = None
|
|
251
277
|
|
|
252
278
|
def __aiter__(self) -> AsyncIterator[RunLogPatch]:
|
|
253
|
-
"""Iterate over the stream of run logs.
|
|
279
|
+
"""Iterate over the stream of run logs.
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
An async iterator over the run log patches.
|
|
283
|
+
"""
|
|
254
284
|
return self.receive_stream.__aiter__()
|
|
255
285
|
|
|
256
286
|
def send(self, *ops: dict[str, Any]) -> bool:
|
|
@@ -623,15 +653,24 @@ async def _astream_log_implementation(
|
|
|
623
653
|
|
|
624
654
|
The implementation has been factored out (at least temporarily) as both
|
|
625
655
|
astream_log and astream_events relies on it.
|
|
626
|
-
"""
|
|
627
|
-
import jsonpatch
|
|
628
|
-
|
|
629
|
-
from langchain_core.callbacks.base import BaseCallbackManager
|
|
630
|
-
from langchain_core.tracers.log_stream import (
|
|
631
|
-
RunLog,
|
|
632
|
-
RunLogPatch,
|
|
633
|
-
)
|
|
634
656
|
|
|
657
|
+
Args:
|
|
658
|
+
runnable: The runnable to run in streaming mode.
|
|
659
|
+
value: The input to the runnable.
|
|
660
|
+
config: The config to pass to the runnable.
|
|
661
|
+
stream: The stream to send the run logs to.
|
|
662
|
+
diff: Whether to yield run log patches (True) or full run logs (False).
|
|
663
|
+
with_streamed_output_list: Whether to include a list of all streamed
|
|
664
|
+
outputs in each patch. If False, only the final output will be included
|
|
665
|
+
in the patches.
|
|
666
|
+
**kwargs: Additional keyword arguments to pass to the runnable.
|
|
667
|
+
|
|
668
|
+
Raises:
|
|
669
|
+
ValueError: If the callbacks in the config are of an unexpected type.
|
|
670
|
+
|
|
671
|
+
Yields:
|
|
672
|
+
The run log patches or states, depending on the value of ``diff``.
|
|
673
|
+
"""
|
|
635
674
|
# Assign the stream handler to the config
|
|
636
675
|
config = ensure_config(config)
|
|
637
676
|
callbacks = config.get("callbacks")
|
|
@@ -21,18 +21,10 @@ AsyncListener = Union[
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class RootListenersTracer(BaseTracer):
|
|
24
|
-
"""Tracer that calls listeners on run start, end, and error.
|
|
25
|
-
|
|
26
|
-
Parameters:
|
|
27
|
-
log_missing_parent: Whether to log a warning if the parent is missing.
|
|
28
|
-
Default is False.
|
|
29
|
-
config: The runnable config.
|
|
30
|
-
on_start: The listener to call on run start.
|
|
31
|
-
on_end: The listener to call on run end.
|
|
32
|
-
on_error: The listener to call on run error.
|
|
33
|
-
"""
|
|
24
|
+
"""Tracer that calls listeners on run start, end, and error."""
|
|
34
25
|
|
|
35
26
|
log_missing_parent = False
|
|
27
|
+
"""Whether to log a warning if the parent is missing. Default is False."""
|
|
36
28
|
|
|
37
29
|
def __init__(
|
|
38
30
|
self,
|
|
@@ -84,18 +76,10 @@ class RootListenersTracer(BaseTracer):
|
|
|
84
76
|
|
|
85
77
|
|
|
86
78
|
class AsyncRootListenersTracer(AsyncBaseTracer):
|
|
87
|
-
"""Async Tracer that calls listeners on run start, end, and error.
|
|
88
|
-
|
|
89
|
-
Parameters:
|
|
90
|
-
log_missing_parent: Whether to log a warning if the parent is missing.
|
|
91
|
-
Default is False.
|
|
92
|
-
config: The runnable config.
|
|
93
|
-
on_start: The listener to call on run start.
|
|
94
|
-
on_end: The listener to call on run end.
|
|
95
|
-
on_error: The listener to call on run error.
|
|
96
|
-
"""
|
|
79
|
+
"""Async Tracer that calls listeners on run start, end, and error."""
|
|
97
80
|
|
|
98
81
|
log_missing_parent = False
|
|
82
|
+
"""Whether to log a warning if the parent is missing. Default is False."""
|
|
99
83
|
|
|
100
84
|
def __init__(
|
|
101
85
|
self,
|
|
@@ -11,12 +11,6 @@ class RunCollectorCallbackHandler(BaseTracer):
|
|
|
11
11
|
"""Tracer that collects all nested runs in a list.
|
|
12
12
|
|
|
13
13
|
This tracer is useful for inspection and evaluation purposes.
|
|
14
|
-
|
|
15
|
-
Parameters
|
|
16
|
-
----------
|
|
17
|
-
name : str, default="run-collector_callback_handler"
|
|
18
|
-
example_id : Optional[Union[UUID, str]], default=None
|
|
19
|
-
The ID of the example being traced. It can be either a UUID or a string.
|
|
20
14
|
"""
|
|
21
15
|
|
|
22
16
|
name: str = "run-collector_callback_handler"
|
|
@@ -26,12 +20,10 @@ class RunCollectorCallbackHandler(BaseTracer):
|
|
|
26
20
|
) -> None:
|
|
27
21
|
"""Initialize the RunCollectorCallbackHandler.
|
|
28
22
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
**kwargs : Any
|
|
34
|
-
Additional keyword arguments
|
|
23
|
+
Args:
|
|
24
|
+
example_id: The ID of the example being traced. (default: None).
|
|
25
|
+
It can be either a UUID or a string.
|
|
26
|
+
**kwargs: Additional keyword arguments.
|
|
35
27
|
"""
|
|
36
28
|
super().__init__(**kwargs)
|
|
37
29
|
self.example_id = (
|
|
@@ -42,10 +34,8 @@ class RunCollectorCallbackHandler(BaseTracer):
|
|
|
42
34
|
def _persist_run(self, run: Run) -> None:
|
|
43
35
|
"""Persist a run by adding it to the traced_runs list.
|
|
44
36
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
run : Run
|
|
48
|
-
The run to be persisted.
|
|
37
|
+
Args:
|
|
38
|
+
run: The run to be persisted.
|
|
49
39
|
"""
|
|
50
40
|
run_ = run.copy()
|
|
51
41
|
run_.reference_example_id = self.example_id
|
|
@@ -18,7 +18,11 @@ from langchain_core._api import deprecated
|
|
|
18
18
|
|
|
19
19
|
@deprecated("0.1.0", alternative="Use string instead.", removal="1.0")
|
|
20
20
|
def RunTypeEnum() -> type[RunTypeEnumDep]: # noqa: N802
|
|
21
|
-
"""RunTypeEnum
|
|
21
|
+
"""``RunTypeEnum``.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
The ``RunTypeEnum`` class.
|
|
25
|
+
"""
|
|
22
26
|
warnings.warn(
|
|
23
27
|
"RunTypeEnum is deprecated. Please directly use a string instead"
|
|
24
28
|
" (e.g. 'llm', 'chain', 'tool').",
|
langchain_core/utils/aiter.py
CHANGED
|
@@ -37,7 +37,7 @@ _no_default = object()
|
|
|
37
37
|
# before 3.10, the builtin anext() was not available
|
|
38
38
|
def py_anext(
|
|
39
39
|
iterator: AsyncIterator[T], default: Union[T, Any] = _no_default
|
|
40
|
-
) -> Awaitable[Union[T,
|
|
40
|
+
) -> Awaitable[Union[T, Any, None]]:
|
|
41
41
|
"""Pure-Python implementation of anext() for testing purposes.
|
|
42
42
|
|
|
43
43
|
Closely matches the builtin anext() C implementation.
|
|
@@ -94,7 +94,7 @@ class NoLock:
|
|
|
94
94
|
exc_val: Optional[BaseException],
|
|
95
95
|
exc_tb: Optional[TracebackType],
|
|
96
96
|
) -> bool:
|
|
97
|
-
"""
|
|
97
|
+
"""Return False, exception not suppressed."""
|
|
98
98
|
return False
|
|
99
99
|
|
|
100
100
|
|
|
@@ -165,7 +165,7 @@ class Tee(Generic[T]):
|
|
|
165
165
|
A ``tee`` works lazily and can handle an infinite ``iterable``, provided
|
|
166
166
|
that all iterators advance.
|
|
167
167
|
|
|
168
|
-
.. code-block::
|
|
168
|
+
.. code-block:: python
|
|
169
169
|
|
|
170
170
|
async def derivative(sensor_data):
|
|
171
171
|
previous, current = a.tee(sensor_data, n=2)
|
|
@@ -236,7 +236,11 @@ class Tee(Generic[T]):
|
|
|
236
236
|
return self._children[item]
|
|
237
237
|
|
|
238
238
|
def __iter__(self) -> Iterator[AsyncIterator[T]]:
|
|
239
|
-
"""Iterate over the child iterators.
|
|
239
|
+
"""Iterate over the child iterators.
|
|
240
|
+
|
|
241
|
+
Yields:
|
|
242
|
+
The child iterators.
|
|
243
|
+
"""
|
|
240
244
|
yield from self._children
|
|
241
245
|
|
|
242
246
|
async def __aenter__(self) -> "Tee[T]":
|
|
@@ -249,7 +253,11 @@ class Tee(Generic[T]):
|
|
|
249
253
|
exc_val: Optional[BaseException],
|
|
250
254
|
exc_tb: Optional[TracebackType],
|
|
251
255
|
) -> bool:
|
|
252
|
-
"""Close all child iterators.
|
|
256
|
+
"""Close all child iterators.
|
|
257
|
+
|
|
258
|
+
Returns:
|
|
259
|
+
False, exceptions not suppressed.
|
|
260
|
+
"""
|
|
253
261
|
await self.aclose()
|
|
254
262
|
return False
|
|
255
263
|
|
|
@@ -318,8 +326,8 @@ async def abatch_iterate(
|
|
|
318
326
|
size: The size of the batch.
|
|
319
327
|
iterable: The async iterable to batch.
|
|
320
328
|
|
|
321
|
-
|
|
322
|
-
|
|
329
|
+
Yields:
|
|
330
|
+
The batches.
|
|
323
331
|
"""
|
|
324
332
|
batch: list[T] = []
|
|
325
333
|
async for element in iterable:
|
langchain_core/utils/env.py
CHANGED
|
@@ -39,6 +39,9 @@ def get_from_dict_or_env(
|
|
|
39
39
|
in the dictionary.
|
|
40
40
|
default: The default value to return if the key is not in the dictionary
|
|
41
41
|
or the environment. Defaults to None.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
The dict value or the environment variable value.
|
|
42
45
|
"""
|
|
43
46
|
if isinstance(key, (list, tuple)):
|
|
44
47
|
for k in key:
|
|
@@ -21,8 +21,10 @@ from typing import (
|
|
|
21
21
|
|
|
22
22
|
from pydantic import BaseModel
|
|
23
23
|
from pydantic.v1 import BaseModel as BaseModelV1
|
|
24
|
+
from pydantic.v1 import Field, create_model
|
|
24
25
|
from typing_extensions import TypedDict, get_args, get_origin, is_typeddict
|
|
25
26
|
|
|
27
|
+
import langchain_core
|
|
26
28
|
from langchain_core._api import beta, deprecated
|
|
27
29
|
from langchain_core.messages import AIMessage, BaseMessage, HumanMessage, ToolMessage
|
|
28
30
|
from langchain_core.utils.json_schema import dereference_refs
|
|
@@ -146,6 +148,9 @@ def _convert_pydantic_to_openai_function(
|
|
|
146
148
|
of the schema will be used.
|
|
147
149
|
rm_titles: Whether to remove titles from the schema. Defaults to True.
|
|
148
150
|
|
|
151
|
+
Raises:
|
|
152
|
+
TypeError: If the model is not a Pydantic model.
|
|
153
|
+
|
|
149
154
|
Returns:
|
|
150
155
|
The function description.
|
|
151
156
|
"""
|
|
@@ -217,10 +222,8 @@ def _convert_python_function_to_openai_function(
|
|
|
217
222
|
Returns:
|
|
218
223
|
The OpenAI function description.
|
|
219
224
|
"""
|
|
220
|
-
from langchain_core.tools.base import create_schema_from_function
|
|
221
|
-
|
|
222
225
|
func_name = _get_python_function_name(function)
|
|
223
|
-
model = create_schema_from_function(
|
|
226
|
+
model = langchain_core.tools.base.create_schema_from_function(
|
|
224
227
|
func_name,
|
|
225
228
|
function,
|
|
226
229
|
filter_args=(),
|
|
@@ -261,9 +264,6 @@ def _convert_any_typed_dicts_to_pydantic(
|
|
|
261
264
|
visited: dict,
|
|
262
265
|
depth: int = 0,
|
|
263
266
|
) -> type:
|
|
264
|
-
from pydantic.v1 import Field as Field_v1
|
|
265
|
-
from pydantic.v1 import create_model as create_model_v1
|
|
266
|
-
|
|
267
267
|
if type_ in visited:
|
|
268
268
|
return visited[type_]
|
|
269
269
|
if depth >= _MAX_TYPED_DICT_RECURSION:
|
|
@@ -294,7 +294,7 @@ def _convert_any_typed_dicts_to_pydantic(
|
|
|
294
294
|
raise ValueError(msg)
|
|
295
295
|
if arg_desc := arg_descriptions.get(arg):
|
|
296
296
|
field_kwargs["description"] = arg_desc
|
|
297
|
-
fields[arg] = (new_arg_type,
|
|
297
|
+
fields[arg] = (new_arg_type, Field(**field_kwargs))
|
|
298
298
|
else:
|
|
299
299
|
new_arg_type = _convert_any_typed_dicts_to_pydantic(
|
|
300
300
|
arg_type, depth=depth + 1, visited=visited
|
|
@@ -302,8 +302,8 @@ def _convert_any_typed_dicts_to_pydantic(
|
|
|
302
302
|
field_kwargs = {"default": ...}
|
|
303
303
|
if arg_desc := arg_descriptions.get(arg):
|
|
304
304
|
field_kwargs["description"] = arg_desc
|
|
305
|
-
fields[arg] = (new_arg_type,
|
|
306
|
-
model =
|
|
305
|
+
fields[arg] = (new_arg_type, Field(**field_kwargs))
|
|
306
|
+
model = create_model(typed_dict.__name__, **fields)
|
|
307
307
|
model.__doc__ = description
|
|
308
308
|
visited[typed_dict] = model
|
|
309
309
|
return model
|
|
@@ -323,12 +323,15 @@ def _format_tool_to_openai_function(tool: BaseTool) -> FunctionDescription:
|
|
|
323
323
|
Args:
|
|
324
324
|
tool: The tool to format.
|
|
325
325
|
|
|
326
|
+
Raises:
|
|
327
|
+
ValueError: If the tool call schema is not supported.
|
|
328
|
+
|
|
326
329
|
Returns:
|
|
327
330
|
The function description.
|
|
328
331
|
"""
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
+
is_simple_oai_tool = (
|
|
333
|
+
isinstance(tool, langchain_core.tools.simple.Tool) and not tool.args_schema
|
|
334
|
+
)
|
|
332
335
|
if tool.tool_call_schema and not is_simple_oai_tool:
|
|
333
336
|
if isinstance(tool.tool_call_schema, dict):
|
|
334
337
|
return _convert_json_schema_to_openai_function(
|
|
@@ -429,8 +432,6 @@ def convert_to_openai_function(
|
|
|
429
432
|
'description' and 'parameters' keys are now optional. Only 'name' is
|
|
430
433
|
required and guaranteed to be part of the output.
|
|
431
434
|
"""
|
|
432
|
-
from langchain_core.tools import BaseTool
|
|
433
|
-
|
|
434
435
|
# an Anthropic format tool
|
|
435
436
|
if isinstance(function, dict) and all(
|
|
436
437
|
k in function for k in ("name", "input_schema")
|
|
@@ -470,7 +471,7 @@ def convert_to_openai_function(
|
|
|
470
471
|
oai_function = cast(
|
|
471
472
|
"dict", _convert_typed_dict_to_openai_function(cast("type", function))
|
|
472
473
|
)
|
|
473
|
-
elif isinstance(function, BaseTool):
|
|
474
|
+
elif isinstance(function, langchain_core.tools.base.BaseTool):
|
|
474
475
|
oai_function = cast("dict", _format_tool_to_openai_function(function))
|
|
475
476
|
elif callable(function):
|
|
476
477
|
oai_function = cast(
|
|
@@ -515,6 +516,7 @@ _WellKnownOpenAITools = (
|
|
|
515
516
|
"mcp",
|
|
516
517
|
"image_generation",
|
|
517
518
|
"web_search_preview",
|
|
519
|
+
"web_search",
|
|
518
520
|
)
|
|
519
521
|
|
|
520
522
|
|
|
@@ -575,7 +577,8 @@ def convert_to_openai_tool(
|
|
|
575
577
|
|
|
576
578
|
Added support for OpenAI's image generation built-in tool.
|
|
577
579
|
"""
|
|
578
|
-
|
|
580
|
+
# Import locally to prevent circular import
|
|
581
|
+
from langchain_core.tools import Tool # noqa: PLC0415
|
|
579
582
|
|
|
580
583
|
if isinstance(tool, dict):
|
|
581
584
|
if tool.get("type") in _WellKnownOpenAITools:
|
|
@@ -601,7 +604,20 @@ def convert_to_json_schema(
|
|
|
601
604
|
*,
|
|
602
605
|
strict: Optional[bool] = None,
|
|
603
606
|
) -> dict[str, Any]:
|
|
604
|
-
"""Convert a schema representation to a JSON schema.
|
|
607
|
+
"""Convert a schema representation to a JSON schema.
|
|
608
|
+
|
|
609
|
+
Args:
|
|
610
|
+
schema: The schema to convert.
|
|
611
|
+
strict: If True, model output is guaranteed to exactly match the JSON Schema
|
|
612
|
+
provided in the function definition. If None, ``strict`` argument will not
|
|
613
|
+
be included in function definition.
|
|
614
|
+
|
|
615
|
+
Raises:
|
|
616
|
+
ValueError: If the input is not a valid OpenAI-format tool.
|
|
617
|
+
|
|
618
|
+
Returns:
|
|
619
|
+
A JSON schema representation of the input schema.
|
|
620
|
+
"""
|
|
605
621
|
openai_tool = convert_to_openai_tool(schema, strict=strict)
|
|
606
622
|
if (
|
|
607
623
|
not isinstance(openai_tool, dict)
|
|
@@ -651,14 +667,13 @@ def tool_example_to_messages(
|
|
|
651
667
|
The ``ToolMessage`` is required because some chat models are hyper-optimized for
|
|
652
668
|
agents rather than for an extraction use case.
|
|
653
669
|
|
|
654
|
-
|
|
655
|
-
input:
|
|
656
|
-
tool_calls:
|
|
657
|
-
|
|
658
|
-
tool_outputs: Optional[list[str]], a list of tool call outputs.
|
|
670
|
+
Args:
|
|
671
|
+
input: The user input
|
|
672
|
+
tool_calls: Tool calls represented as Pydantic BaseModels
|
|
673
|
+
tool_outputs: Tool call outputs.
|
|
659
674
|
Does not need to be provided. If not provided, a placeholder value
|
|
660
675
|
will be inserted. Defaults to None.
|
|
661
|
-
ai_response:
|
|
676
|
+
ai_response: If provided, content for a final ``AIMessage``.
|
|
662
677
|
|
|
663
678
|
Returns:
|
|
664
679
|
A list of messages
|
|
@@ -671,8 +686,10 @@ def tool_example_to_messages(
|
|
|
671
686
|
from pydantic import BaseModel, Field
|
|
672
687
|
from langchain_openai import ChatOpenAI
|
|
673
688
|
|
|
689
|
+
|
|
674
690
|
class Person(BaseModel):
|
|
675
691
|
'''Information about a person.'''
|
|
692
|
+
|
|
676
693
|
name: Optional[str] = Field(..., description="The name of the person")
|
|
677
694
|
hair_color: Optional[str] = Field(
|
|
678
695
|
..., description="The color of the person's hair if known"
|
|
@@ -681,6 +698,7 @@ def tool_example_to_messages(
|
|
|
681
698
|
..., description="Height in METERS"
|
|
682
699
|
)
|
|
683
700
|
|
|
701
|
+
|
|
684
702
|
examples = [
|
|
685
703
|
(
|
|
686
704
|
"The ocean is vast and blue. It's more than 20,000 feet deep.",
|
|
@@ -696,9 +714,7 @@ def tool_example_to_messages(
|
|
|
696
714
|
messages = []
|
|
697
715
|
|
|
698
716
|
for txt, tool_call in examples:
|
|
699
|
-
messages.extend(
|
|
700
|
-
tool_example_to_messages(txt, [tool_call])
|
|
701
|
-
)
|
|
717
|
+
messages.extend(tool_example_to_messages(txt, [tool_call]))
|
|
702
718
|
|
|
703
719
|
"""
|
|
704
720
|
messages: list[BaseMessage] = [HumanMessage(content=input)]
|
|
@@ -816,8 +832,14 @@ def _recursive_set_additional_properties_false(
|
|
|
816
832
|
if isinstance(schema, dict):
|
|
817
833
|
# Check if 'required' is a key at the current level or if the schema is empty,
|
|
818
834
|
# in which case additionalProperties still needs to be specified.
|
|
819
|
-
if
|
|
820
|
-
"
|
|
835
|
+
if (
|
|
836
|
+
"required" in schema
|
|
837
|
+
or ("properties" in schema and not schema["properties"])
|
|
838
|
+
# Since Pydantic 2.11, it will always add `additionalProperties: True`
|
|
839
|
+
# for arbitrary dictionary schemas
|
|
840
|
+
# See: https://pydantic.dev/articles/pydantic-v2-11-release#changes
|
|
841
|
+
# If it is already set to True, we need override it to False
|
|
842
|
+
or "additionalProperties" in schema
|
|
821
843
|
):
|
|
822
844
|
schema["additionalProperties"] = False
|
|
823
845
|
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
"""Utilities for working with interactive environments."""
|
|
2
2
|
|
|
3
|
+
import sys
|
|
4
|
+
|
|
3
5
|
|
|
4
6
|
def is_interactive_env() -> bool:
|
|
5
|
-
"""Determine if running within IPython or Jupyter.
|
|
6
|
-
import sys
|
|
7
|
+
"""Determine if running within IPython or Jupyter.
|
|
7
8
|
|
|
9
|
+
Returns:
|
|
10
|
+
True if running in an interactive environment, False otherwise.
|
|
11
|
+
"""
|
|
8
12
|
return hasattr(sys, "ps2")
|
langchain_core/utils/iter.py
CHANGED
|
@@ -31,7 +31,7 @@ class NoLock:
|
|
|
31
31
|
exc_val: Optional[BaseException],
|
|
32
32
|
exc_tb: Optional[TracebackType],
|
|
33
33
|
) -> Literal[False]:
|
|
34
|
-
"""
|
|
34
|
+
"""Return False (exception not suppressed)."""
|
|
35
35
|
return False
|
|
36
36
|
|
|
37
37
|
|
|
@@ -102,7 +102,7 @@ class Tee(Generic[T]):
|
|
|
102
102
|
A ``tee`` works lazily and can handle an infinite ``iterable``, provided
|
|
103
103
|
that all iterators advance.
|
|
104
104
|
|
|
105
|
-
.. code-block::
|
|
105
|
+
.. code-block:: python
|
|
106
106
|
|
|
107
107
|
async def derivative(sensor_data):
|
|
108
108
|
previous, current = a.tee(sensor_data, n=2)
|
|
@@ -173,7 +173,11 @@ class Tee(Generic[T]):
|
|
|
173
173
|
return self._children[item]
|
|
174
174
|
|
|
175
175
|
def __iter__(self) -> Iterator[Iterator[T]]:
|
|
176
|
-
"""Return an iterator over the child iterators.
|
|
176
|
+
"""Return an iterator over the child iterators.
|
|
177
|
+
|
|
178
|
+
Yields:
|
|
179
|
+
The child iterators.
|
|
180
|
+
"""
|
|
177
181
|
yield from self._children
|
|
178
182
|
|
|
179
183
|
def __enter__(self) -> "Tee[T]":
|
|
@@ -186,7 +190,11 @@ class Tee(Generic[T]):
|
|
|
186
190
|
exc_val: Optional[BaseException],
|
|
187
191
|
exc_tb: Optional[TracebackType],
|
|
188
192
|
) -> Literal[False]:
|
|
189
|
-
"""Close all child iterators.
|
|
193
|
+
"""Close all child iterators.
|
|
194
|
+
|
|
195
|
+
Returns:
|
|
196
|
+
False (exception not suppressed).
|
|
197
|
+
"""
|
|
190
198
|
self.close()
|
|
191
199
|
return False
|
|
192
200
|
|
langchain_core/utils/json.py
CHANGED
|
@@ -4,7 +4,7 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import re
|
|
7
|
-
from typing import Any, Callable
|
|
7
|
+
from typing import Any, Callable, Union
|
|
8
8
|
|
|
9
9
|
from langchain_core.exceptions import OutputParserException
|
|
10
10
|
|
|
@@ -19,13 +19,16 @@ def _replace_new_line(match: re.Match[str]) -> str:
|
|
|
19
19
|
return match.group(1) + value + match.group(3)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def _custom_parser(multiline_string: str) -> str:
|
|
22
|
+
def _custom_parser(multiline_string: Union[str, bytes, bytearray]) -> str:
|
|
23
23
|
r"""Custom parser for multiline strings.
|
|
24
24
|
|
|
25
25
|
The LLM response for `action_input` may be a multiline
|
|
26
26
|
string containing unescaped newlines, tabs or quotes. This function
|
|
27
27
|
replaces those characters with their escaped counterparts.
|
|
28
28
|
(newlines in JSON must be double-escaped: `\\n`).
|
|
29
|
+
|
|
30
|
+
Returns:
|
|
31
|
+
The modified string with escaped newlines, tabs and quotes.
|
|
29
32
|
"""
|
|
30
33
|
if isinstance(multiline_string, (bytes, bytearray)):
|
|
31
34
|
multiline_string = multiline_string.decode()
|
|
@@ -98,7 +101,7 @@ def parse_partial_json(s: str, *, strict: bool = False) -> Any:
|
|
|
98
101
|
# If we're still inside a string at the end of processing,
|
|
99
102
|
# we need to close the string.
|
|
100
103
|
if is_inside_string:
|
|
101
|
-
if escaped: #
|
|
104
|
+
if escaped: # Remove unterminated escape character
|
|
102
105
|
new_chars.pop()
|
|
103
106
|
new_chars.append('"')
|
|
104
107
|
|
|
@@ -187,6 +190,12 @@ def parse_and_check_json_markdown(text: str, expected_keys: list[str]) -> dict:
|
|
|
187
190
|
except json.JSONDecodeError as e:
|
|
188
191
|
msg = f"Got invalid JSON object. Error: {e}"
|
|
189
192
|
raise OutputParserException(msg) from e
|
|
193
|
+
if not isinstance(json_obj, dict):
|
|
194
|
+
error_message = (
|
|
195
|
+
f"Expected JSON object (dict), but got: {type(json_obj).__name__}. "
|
|
196
|
+
)
|
|
197
|
+
raise OutputParserException(error_message, llm_output=text)
|
|
198
|
+
|
|
190
199
|
for key in expected_keys:
|
|
191
200
|
if key not in json_obj:
|
|
192
201
|
msg = (
|