langchain-core 1.0.0a6__py3-none-any.whl → 1.0.4__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/__init__.py +1 -1
- langchain_core/_api/__init__.py +3 -4
- langchain_core/_api/beta_decorator.py +23 -26
- langchain_core/_api/deprecation.py +51 -64
- langchain_core/_api/path.py +3 -6
- langchain_core/_import_utils.py +3 -4
- langchain_core/agents.py +55 -48
- langchain_core/caches.py +65 -66
- langchain_core/callbacks/__init__.py +1 -8
- langchain_core/callbacks/base.py +321 -336
- langchain_core/callbacks/file.py +44 -44
- langchain_core/callbacks/manager.py +454 -514
- langchain_core/callbacks/stdout.py +29 -30
- langchain_core/callbacks/streaming_stdout.py +32 -32
- langchain_core/callbacks/usage.py +60 -57
- langchain_core/chat_history.py +53 -68
- langchain_core/document_loaders/base.py +27 -25
- langchain_core/document_loaders/blob_loaders.py +1 -1
- langchain_core/document_loaders/langsmith.py +44 -48
- langchain_core/documents/__init__.py +23 -3
- langchain_core/documents/base.py +102 -94
- langchain_core/documents/compressor.py +10 -10
- langchain_core/documents/transformers.py +34 -35
- langchain_core/embeddings/fake.py +50 -54
- langchain_core/example_selectors/length_based.py +2 -2
- langchain_core/example_selectors/semantic_similarity.py +28 -32
- langchain_core/exceptions.py +21 -20
- langchain_core/globals.py +3 -151
- langchain_core/indexing/__init__.py +1 -1
- langchain_core/indexing/api.py +121 -126
- langchain_core/indexing/base.py +73 -75
- langchain_core/indexing/in_memory.py +4 -6
- langchain_core/language_models/__init__.py +14 -29
- langchain_core/language_models/_utils.py +58 -61
- langchain_core/language_models/base.py +82 -172
- langchain_core/language_models/chat_models.py +329 -402
- langchain_core/language_models/fake.py +11 -11
- langchain_core/language_models/fake_chat_models.py +42 -36
- langchain_core/language_models/llms.py +189 -269
- langchain_core/load/dump.py +9 -12
- langchain_core/load/load.py +18 -28
- langchain_core/load/mapping.py +2 -4
- langchain_core/load/serializable.py +42 -40
- langchain_core/messages/__init__.py +10 -16
- langchain_core/messages/ai.py +148 -148
- langchain_core/messages/base.py +53 -51
- langchain_core/messages/block_translators/__init__.py +19 -22
- langchain_core/messages/block_translators/anthropic.py +6 -6
- langchain_core/messages/block_translators/bedrock_converse.py +5 -5
- langchain_core/messages/block_translators/google_genai.py +10 -7
- langchain_core/messages/block_translators/google_vertexai.py +4 -32
- langchain_core/messages/block_translators/groq.py +117 -21
- langchain_core/messages/block_translators/langchain_v0.py +5 -5
- langchain_core/messages/block_translators/openai.py +11 -11
- langchain_core/messages/chat.py +2 -6
- langchain_core/messages/content.py +339 -330
- langchain_core/messages/function.py +6 -10
- langchain_core/messages/human.py +24 -31
- langchain_core/messages/modifier.py +2 -2
- langchain_core/messages/system.py +19 -29
- langchain_core/messages/tool.py +74 -90
- langchain_core/messages/utils.py +484 -510
- langchain_core/output_parsers/__init__.py +13 -10
- langchain_core/output_parsers/base.py +61 -61
- langchain_core/output_parsers/format_instructions.py +9 -4
- langchain_core/output_parsers/json.py +12 -10
- langchain_core/output_parsers/list.py +21 -23
- langchain_core/output_parsers/openai_functions.py +49 -47
- langchain_core/output_parsers/openai_tools.py +30 -23
- langchain_core/output_parsers/pydantic.py +13 -14
- langchain_core/output_parsers/string.py +5 -5
- langchain_core/output_parsers/transform.py +15 -17
- langchain_core/output_parsers/xml.py +35 -34
- langchain_core/outputs/__init__.py +1 -1
- langchain_core/outputs/chat_generation.py +18 -18
- langchain_core/outputs/chat_result.py +1 -3
- langchain_core/outputs/generation.py +16 -16
- langchain_core/outputs/llm_result.py +10 -10
- langchain_core/prompt_values.py +13 -19
- langchain_core/prompts/__init__.py +3 -27
- langchain_core/prompts/base.py +81 -86
- langchain_core/prompts/chat.py +308 -351
- langchain_core/prompts/dict.py +6 -6
- langchain_core/prompts/few_shot.py +81 -88
- langchain_core/prompts/few_shot_with_templates.py +11 -13
- langchain_core/prompts/image.py +12 -14
- langchain_core/prompts/loading.py +4 -6
- langchain_core/prompts/message.py +7 -7
- langchain_core/prompts/prompt.py +24 -39
- langchain_core/prompts/string.py +26 -10
- langchain_core/prompts/structured.py +49 -53
- langchain_core/rate_limiters.py +51 -60
- langchain_core/retrievers.py +61 -198
- langchain_core/runnables/base.py +1551 -1656
- langchain_core/runnables/branch.py +68 -70
- langchain_core/runnables/config.py +72 -89
- langchain_core/runnables/configurable.py +145 -161
- langchain_core/runnables/fallbacks.py +102 -96
- langchain_core/runnables/graph.py +91 -97
- langchain_core/runnables/graph_ascii.py +27 -28
- langchain_core/runnables/graph_mermaid.py +42 -51
- langchain_core/runnables/graph_png.py +43 -16
- langchain_core/runnables/history.py +175 -177
- langchain_core/runnables/passthrough.py +151 -167
- langchain_core/runnables/retry.py +46 -51
- langchain_core/runnables/router.py +30 -35
- langchain_core/runnables/schema.py +75 -80
- langchain_core/runnables/utils.py +60 -67
- langchain_core/stores.py +85 -121
- langchain_core/structured_query.py +8 -8
- langchain_core/sys_info.py +29 -29
- langchain_core/tools/__init__.py +1 -14
- langchain_core/tools/base.py +306 -245
- langchain_core/tools/convert.py +160 -155
- langchain_core/tools/render.py +10 -10
- langchain_core/tools/retriever.py +12 -11
- langchain_core/tools/simple.py +19 -24
- langchain_core/tools/structured.py +32 -39
- langchain_core/tracers/__init__.py +1 -9
- langchain_core/tracers/base.py +97 -99
- langchain_core/tracers/context.py +29 -52
- langchain_core/tracers/core.py +49 -53
- langchain_core/tracers/evaluation.py +11 -11
- langchain_core/tracers/event_stream.py +65 -64
- langchain_core/tracers/langchain.py +21 -21
- langchain_core/tracers/log_stream.py +45 -45
- langchain_core/tracers/memory_stream.py +3 -3
- langchain_core/tracers/root_listeners.py +16 -16
- langchain_core/tracers/run_collector.py +2 -4
- langchain_core/tracers/schemas.py +0 -129
- langchain_core/tracers/stdout.py +3 -3
- langchain_core/utils/__init__.py +1 -4
- langchain_core/utils/_merge.py +2 -2
- langchain_core/utils/aiter.py +57 -61
- langchain_core/utils/env.py +9 -9
- langchain_core/utils/function_calling.py +94 -188
- langchain_core/utils/html.py +7 -8
- langchain_core/utils/input.py +9 -6
- langchain_core/utils/interactive_env.py +1 -1
- langchain_core/utils/iter.py +36 -40
- langchain_core/utils/json.py +4 -3
- langchain_core/utils/json_schema.py +9 -9
- langchain_core/utils/mustache.py +8 -10
- langchain_core/utils/pydantic.py +35 -37
- langchain_core/utils/strings.py +6 -9
- langchain_core/utils/usage.py +1 -1
- langchain_core/utils/utils.py +66 -62
- langchain_core/vectorstores/base.py +182 -216
- langchain_core/vectorstores/in_memory.py +101 -176
- langchain_core/vectorstores/utils.py +5 -5
- langchain_core/version.py +1 -1
- langchain_core-1.0.4.dist-info/METADATA +69 -0
- langchain_core-1.0.4.dist-info/RECORD +172 -0
- {langchain_core-1.0.0a6.dist-info → langchain_core-1.0.4.dist-info}/WHEEL +1 -1
- langchain_core/memory.py +0 -120
- langchain_core/messages/block_translators/ollama.py +0 -47
- langchain_core/prompts/pipeline.py +0 -138
- langchain_core/pydantic_v1/__init__.py +0 -30
- langchain_core/pydantic_v1/dataclasses.py +0 -23
- langchain_core/pydantic_v1/main.py +0 -23
- langchain_core/tracers/langchain_v1.py +0 -31
- langchain_core/utils/loading.py +0 -35
- langchain_core-1.0.0a6.dist-info/METADATA +0 -67
- langchain_core-1.0.0a6.dist-info/RECORD +0 -181
- langchain_core-1.0.0a6.dist-info/entry_points.txt +0 -4
langchain_core/utils/iter.py
CHANGED
|
@@ -9,9 +9,7 @@ from typing import (
|
|
|
9
9
|
Any,
|
|
10
10
|
Generic,
|
|
11
11
|
Literal,
|
|
12
|
-
Optional,
|
|
13
12
|
TypeVar,
|
|
14
|
-
Union,
|
|
15
13
|
overload,
|
|
16
14
|
)
|
|
17
15
|
|
|
@@ -26,9 +24,9 @@ class NoLock:
|
|
|
26
24
|
|
|
27
25
|
def __exit__(
|
|
28
26
|
self,
|
|
29
|
-
exc_type:
|
|
30
|
-
exc_val:
|
|
31
|
-
exc_tb:
|
|
27
|
+
exc_type: type[BaseException] | None,
|
|
28
|
+
exc_val: BaseException | None,
|
|
29
|
+
exc_tb: TracebackType | None,
|
|
32
30
|
) -> Literal[False]:
|
|
33
31
|
"""Return False (exception not suppressed)."""
|
|
34
32
|
return False
|
|
@@ -42,10 +40,10 @@ def tee_peer(
|
|
|
42
40
|
peers: list[deque[T]],
|
|
43
41
|
lock: AbstractContextManager[Any],
|
|
44
42
|
) -> Generator[T, None, None]:
|
|
45
|
-
"""An individual iterator of a
|
|
43
|
+
"""An individual iterator of a `.tee`.
|
|
46
44
|
|
|
47
45
|
This function is a generator that yields items from the shared iterator
|
|
48
|
-
|
|
46
|
+
`iterator`. It buffers items until the least advanced iterator has
|
|
49
47
|
yielded them as well. The buffer is shared with all other peers.
|
|
50
48
|
|
|
51
49
|
Args:
|
|
@@ -91,39 +89,39 @@ def tee_peer(
|
|
|
91
89
|
|
|
92
90
|
|
|
93
91
|
class Tee(Generic[T]):
|
|
94
|
-
"""Create
|
|
92
|
+
"""Create `n` separate asynchronous iterators over `iterable`.
|
|
95
93
|
|
|
96
|
-
This splits a single
|
|
94
|
+
This splits a single `iterable` into multiple iterators, each providing
|
|
97
95
|
the same items in the same order.
|
|
98
96
|
All child iterators may advance separately but share the same items
|
|
99
|
-
from
|
|
97
|
+
from `iterable` -- when the most advanced iterator retrieves an item,
|
|
100
98
|
it is buffered until the least advanced iterator has yielded it as well.
|
|
101
|
-
A
|
|
99
|
+
A `tee` works lazily and can handle an infinite `iterable`, provided
|
|
102
100
|
that all iterators advance.
|
|
103
101
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
Unlike
|
|
112
|
-
of a :py
|
|
113
|
-
to get the child iterators. In addition, its
|
|
114
|
-
immediately closes all children, and it can be used in an
|
|
102
|
+
```python
|
|
103
|
+
async def derivative(sensor_data):
|
|
104
|
+
previous, current = a.tee(sensor_data, n=2)
|
|
105
|
+
await a.anext(previous) # advance one iterator
|
|
106
|
+
return a.map(operator.sub, previous, current)
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Unlike `itertools.tee`, `.tee` returns a custom type instead
|
|
110
|
+
of a :py`tuple`. Like a tuple, it can be indexed, iterated and unpacked
|
|
111
|
+
to get the child iterators. In addition, its `.tee.aclose` method
|
|
112
|
+
immediately closes all children, and it can be used in an `async with` context
|
|
115
113
|
for the same effect.
|
|
116
114
|
|
|
117
|
-
If
|
|
118
|
-
provide these items. Also,
|
|
115
|
+
If `iterable` is an iterator and read elsewhere, `tee` will *not*
|
|
116
|
+
provide these items. Also, `tee` must internally buffer each item until the
|
|
119
117
|
last iterator has yielded it; if the most and least advanced iterator differ
|
|
120
|
-
by most data, using a :py
|
|
118
|
+
by most data, using a :py`list` is more efficient (but not lazy).
|
|
121
119
|
|
|
122
|
-
If the underlying iterable is concurrency safe (
|
|
120
|
+
If the underlying iterable is concurrency safe (`anext` may be awaited
|
|
123
121
|
concurrently) the resulting iterators are concurrency safe as well. Otherwise,
|
|
124
122
|
the iterators are safe if there is only ever one single "most advanced" iterator.
|
|
125
|
-
To enforce sequential use of
|
|
126
|
-
- e.g. an :py
|
|
123
|
+
To enforce sequential use of `anext`, provide a `lock`
|
|
124
|
+
- e.g. an :py`asyncio.Lock` instance in an :py:mod:`asyncio` application -
|
|
127
125
|
and access is automatically synchronised.
|
|
128
126
|
|
|
129
127
|
"""
|
|
@@ -133,15 +131,15 @@ class Tee(Generic[T]):
|
|
|
133
131
|
iterable: Iterator[T],
|
|
134
132
|
n: int = 2,
|
|
135
133
|
*,
|
|
136
|
-
lock:
|
|
134
|
+
lock: AbstractContextManager[Any] | None = None,
|
|
137
135
|
):
|
|
138
|
-
"""Create a
|
|
136
|
+
"""Create a `tee`.
|
|
139
137
|
|
|
140
138
|
Args:
|
|
141
139
|
iterable: The iterable to split.
|
|
142
|
-
n: The number of iterators to create.
|
|
140
|
+
n: The number of iterators to create.
|
|
143
141
|
lock: The lock to synchronise access to the shared buffers.
|
|
144
|
-
|
|
142
|
+
|
|
145
143
|
"""
|
|
146
144
|
self._iterator = iter(iterable)
|
|
147
145
|
self._buffers: list[deque[T]] = [deque() for _ in range(n)]
|
|
@@ -165,9 +163,7 @@ class Tee(Generic[T]):
|
|
|
165
163
|
@overload
|
|
166
164
|
def __getitem__(self, item: slice) -> tuple[Iterator[T], ...]: ...
|
|
167
165
|
|
|
168
|
-
def __getitem__(
|
|
169
|
-
self, item: Union[int, slice]
|
|
170
|
-
) -> Union[Iterator[T], tuple[Iterator[T], ...]]:
|
|
166
|
+
def __getitem__(self, item: int | slice) -> Iterator[T] | tuple[Iterator[T], ...]:
|
|
171
167
|
"""Return the child iterator(s) at the given index or slice."""
|
|
172
168
|
return self._children[item]
|
|
173
169
|
|
|
@@ -185,9 +181,9 @@ class Tee(Generic[T]):
|
|
|
185
181
|
|
|
186
182
|
def __exit__(
|
|
187
183
|
self,
|
|
188
|
-
exc_type:
|
|
189
|
-
exc_val:
|
|
190
|
-
exc_tb:
|
|
184
|
+
exc_type: type[BaseException] | None,
|
|
185
|
+
exc_val: BaseException | None,
|
|
186
|
+
exc_tb: TracebackType | None,
|
|
191
187
|
) -> Literal[False]:
|
|
192
188
|
"""Close all child iterators.
|
|
193
189
|
|
|
@@ -207,11 +203,11 @@ class Tee(Generic[T]):
|
|
|
207
203
|
safetee = Tee
|
|
208
204
|
|
|
209
205
|
|
|
210
|
-
def batch_iterate(size:
|
|
206
|
+
def batch_iterate(size: int | None, iterable: Iterable[T]) -> Iterator[list[T]]:
|
|
211
207
|
"""Utility batching function.
|
|
212
208
|
|
|
213
209
|
Args:
|
|
214
|
-
size: The size of the batch. If None
|
|
210
|
+
size: The size of the batch. If `None`, returns a single batch.
|
|
215
211
|
iterable: The iterable to batch.
|
|
216
212
|
|
|
217
213
|
Yields:
|
langchain_core/utils/json.py
CHANGED
|
@@ -4,7 +4,8 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json
|
|
6
6
|
import re
|
|
7
|
-
from
|
|
7
|
+
from collections.abc import Callable
|
|
8
|
+
from typing import Any
|
|
8
9
|
|
|
9
10
|
from langchain_core.exceptions import OutputParserException
|
|
10
11
|
|
|
@@ -19,7 +20,7 @@ def _replace_new_line(match: re.Match[str]) -> str:
|
|
|
19
20
|
return match.group(1) + value + match.group(3)
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
def _custom_parser(multiline_string:
|
|
23
|
+
def _custom_parser(multiline_string: str | bytes | bytearray) -> str:
|
|
23
24
|
r"""Custom parser for multiline strings.
|
|
24
25
|
|
|
25
26
|
The LLM response for `action_input` may be a multiline
|
|
@@ -50,7 +51,7 @@ def parse_partial_json(s: str, *, strict: bool = False) -> Any:
|
|
|
50
51
|
|
|
51
52
|
Args:
|
|
52
53
|
s: The JSON string to parse.
|
|
53
|
-
strict: Whether to use strict parsing.
|
|
54
|
+
strict: Whether to use strict parsing.
|
|
54
55
|
|
|
55
56
|
Returns:
|
|
56
57
|
The parsed JSON object as a Python dictionary.
|
|
@@ -3,13 +3,13 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from copy import deepcopy
|
|
6
|
-
from typing import TYPE_CHECKING, Any
|
|
6
|
+
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
8
|
if TYPE_CHECKING:
|
|
9
9
|
from collections.abc import Sequence
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
def _retrieve_ref(path: str, schema: dict) ->
|
|
12
|
+
def _retrieve_ref(path: str, schema: dict) -> list | dict:
|
|
13
13
|
components = path.split("/")
|
|
14
14
|
if components[0] != "#":
|
|
15
15
|
msg = (
|
|
@@ -17,7 +17,7 @@ def _retrieve_ref(path: str, schema: dict) -> Union[list, dict]:
|
|
|
17
17
|
"with #."
|
|
18
18
|
)
|
|
19
19
|
raise ValueError(msg)
|
|
20
|
-
out:
|
|
20
|
+
out: list | dict = schema
|
|
21
21
|
for component in components[1:]:
|
|
22
22
|
if component in out:
|
|
23
23
|
if isinstance(out, list):
|
|
@@ -67,7 +67,7 @@ def _process_dict_properties(
|
|
|
67
67
|
def _dereference_refs_helper(
|
|
68
68
|
obj: Any,
|
|
69
69
|
full_schema: dict[str, Any],
|
|
70
|
-
processed_refs:
|
|
70
|
+
processed_refs: set[str] | None,
|
|
71
71
|
skip_keys: Sequence[str],
|
|
72
72
|
shallow_refs: bool, # noqa: FBT001
|
|
73
73
|
) -> Any:
|
|
@@ -85,7 +85,7 @@ def _dereference_refs_helper(
|
|
|
85
85
|
full_schema: The complete schema containing all definitions
|
|
86
86
|
processed_refs: Set tracking currently processing refs (for cycle detection)
|
|
87
87
|
skip_keys: Keys under which to skip recursion
|
|
88
|
-
shallow_refs: If True
|
|
88
|
+
shallow_refs: If `True`, only break cycles; if False, deep-inline all refs
|
|
89
89
|
|
|
90
90
|
Returns:
|
|
91
91
|
The object with $ref properties resolved and merged with other properties.
|
|
@@ -167,8 +167,8 @@ def _dereference_refs_helper(
|
|
|
167
167
|
def dereference_refs(
|
|
168
168
|
schema_obj: dict,
|
|
169
169
|
*,
|
|
170
|
-
full_schema:
|
|
171
|
-
skip_keys:
|
|
170
|
+
full_schema: dict | None = None,
|
|
171
|
+
skip_keys: Sequence[str] | None = None,
|
|
172
172
|
) -> dict:
|
|
173
173
|
"""Resolve and inline JSON Schema $ref references in a schema object.
|
|
174
174
|
|
|
@@ -184,7 +184,7 @@ def dereference_refs(
|
|
|
184
184
|
point to. If not provided, defaults to schema_obj (useful when the
|
|
185
185
|
schema is self-contained).
|
|
186
186
|
skip_keys: Controls recursion behavior and reference resolution depth:
|
|
187
|
-
- If None (
|
|
187
|
+
- If `None` (Default): Only recurse under '$defs' and use shallow reference
|
|
188
188
|
resolution (break cycles but don't deep-inline nested refs)
|
|
189
189
|
- If provided (even as []): Recurse under all keys and use deep reference
|
|
190
190
|
resolution (fully inline all nested references)
|
|
@@ -226,7 +226,7 @@ def dereference_refs(
|
|
|
226
226
|
... }
|
|
227
227
|
>>> result = dereference_refs(schema) # Won't cause infinite recursion
|
|
228
228
|
|
|
229
|
-
|
|
229
|
+
!!! note
|
|
230
230
|
- Circular references are handled gracefully by breaking cycles
|
|
231
231
|
- Mixed $ref objects (with both $ref and other properties) are supported
|
|
232
232
|
- Additional properties in mixed $refs override resolved properties
|
langchain_core/utils/mustache.py
CHANGED
|
@@ -12,8 +12,6 @@ from typing import (
|
|
|
12
12
|
TYPE_CHECKING,
|
|
13
13
|
Any,
|
|
14
14
|
Literal,
|
|
15
|
-
Optional,
|
|
16
|
-
Union,
|
|
17
15
|
cast,
|
|
18
16
|
)
|
|
19
17
|
|
|
@@ -23,7 +21,7 @@ if TYPE_CHECKING:
|
|
|
23
21
|
logger = logging.getLogger(__name__)
|
|
24
22
|
|
|
25
23
|
|
|
26
|
-
Scopes: TypeAlias = list[
|
|
24
|
+
Scopes: TypeAlias = list[Literal[False, 0] | Mapping[str, Any]]
|
|
27
25
|
|
|
28
26
|
|
|
29
27
|
# Globals
|
|
@@ -48,7 +46,7 @@ def grab_literal(template: str, l_del: str) -> tuple[str, str]:
|
|
|
48
46
|
l_del: The left delimiter.
|
|
49
47
|
|
|
50
48
|
Returns:
|
|
51
|
-
|
|
49
|
+
The literal and the template.
|
|
52
50
|
"""
|
|
53
51
|
global _CURRENT_LINE
|
|
54
52
|
|
|
@@ -78,7 +76,7 @@ def l_sa_check(
|
|
|
78
76
|
is_standalone: Whether the tag is standalone.
|
|
79
77
|
|
|
80
78
|
Returns:
|
|
81
|
-
|
|
79
|
+
Whether the tag could be a standalone.
|
|
82
80
|
"""
|
|
83
81
|
# If there is a newline, or the previous tag was a standalone
|
|
84
82
|
if literal.find("\n") != -1 or is_standalone:
|
|
@@ -104,7 +102,7 @@ def r_sa_check(
|
|
|
104
102
|
is_standalone: Whether the tag is standalone.
|
|
105
103
|
|
|
106
104
|
Returns:
|
|
107
|
-
|
|
105
|
+
Whether the tag could be a standalone.
|
|
108
106
|
"""
|
|
109
107
|
# Check right side if we might be a standalone
|
|
110
108
|
if is_standalone and tag_type not in {"variable", "no escape"}:
|
|
@@ -126,7 +124,7 @@ def parse_tag(template: str, l_del: str, r_del: str) -> tuple[tuple[str, str], s
|
|
|
126
124
|
r_del: The right delimiter.
|
|
127
125
|
|
|
128
126
|
Returns:
|
|
129
|
-
|
|
127
|
+
The tag and the template.
|
|
130
128
|
|
|
131
129
|
Raises:
|
|
132
130
|
ChevronError: If the tag is unclosed.
|
|
@@ -331,7 +329,7 @@ def tokenize(
|
|
|
331
329
|
|
|
332
330
|
|
|
333
331
|
def _html_escape(string: str) -> str:
|
|
334
|
-
"""Return the HTML-escaped string with these characters escaped:
|
|
332
|
+
"""Return the HTML-escaped string with these characters escaped: `" & < >`."""
|
|
335
333
|
html_codes = {
|
|
336
334
|
'"': """,
|
|
337
335
|
"<": "<",
|
|
@@ -433,13 +431,13 @@ EMPTY_DICT: MappingProxyType[str, str] = MappingProxyType({})
|
|
|
433
431
|
|
|
434
432
|
|
|
435
433
|
def render(
|
|
436
|
-
template:
|
|
434
|
+
template: str | list[tuple[str, str]] = "",
|
|
437
435
|
data: Mapping[str, Any] = EMPTY_DICT,
|
|
438
436
|
partials_dict: Mapping[str, str] = EMPTY_DICT,
|
|
439
437
|
padding: str = "",
|
|
440
438
|
def_ldel: str = "{{",
|
|
441
439
|
def_rdel: str = "}}",
|
|
442
|
-
scopes:
|
|
440
|
+
scopes: Scopes | None = None,
|
|
443
441
|
warn: bool = False, # noqa: FBT001,FBT002
|
|
444
442
|
keep: bool = False, # noqa: FBT001,FBT002
|
|
445
443
|
) -> str:
|
langchain_core/utils/pydantic.py
CHANGED
|
@@ -5,16 +5,14 @@ from __future__ import annotations
|
|
|
5
5
|
import inspect
|
|
6
6
|
import textwrap
|
|
7
7
|
import warnings
|
|
8
|
+
from collections.abc import Callable
|
|
8
9
|
from contextlib import nullcontext
|
|
9
10
|
from functools import lru_cache, wraps
|
|
10
11
|
from types import GenericAlias
|
|
11
12
|
from typing import (
|
|
12
13
|
TYPE_CHECKING,
|
|
13
14
|
Any,
|
|
14
|
-
Callable,
|
|
15
|
-
Optional,
|
|
16
15
|
TypeVar,
|
|
17
|
-
Union,
|
|
18
16
|
cast,
|
|
19
17
|
overload,
|
|
20
18
|
)
|
|
@@ -67,8 +65,8 @@ def get_pydantic_major_version() -> int:
|
|
|
67
65
|
PYDANTIC_MAJOR_VERSION = PYDANTIC_VERSION.major
|
|
68
66
|
PYDANTIC_MINOR_VERSION = PYDANTIC_VERSION.minor
|
|
69
67
|
|
|
70
|
-
IS_PYDANTIC_V1 =
|
|
71
|
-
IS_PYDANTIC_V2 =
|
|
68
|
+
IS_PYDANTIC_V1 = False
|
|
69
|
+
IS_PYDANTIC_V2 = True
|
|
72
70
|
|
|
73
71
|
PydanticBaseModel = BaseModel
|
|
74
72
|
TypeBaseModel = type[BaseModel]
|
|
@@ -80,7 +78,7 @@ def is_pydantic_v1_subclass(cls: type) -> bool:
|
|
|
80
78
|
"""Check if the given class is Pydantic v1-like.
|
|
81
79
|
|
|
82
80
|
Returns:
|
|
83
|
-
True if the given class is a subclass of Pydantic
|
|
81
|
+
`True` if the given class is a subclass of Pydantic `BaseModel` 1.x.
|
|
84
82
|
"""
|
|
85
83
|
return issubclass(cls, BaseModelV1)
|
|
86
84
|
|
|
@@ -89,7 +87,7 @@ def is_pydantic_v2_subclass(cls: type) -> bool:
|
|
|
89
87
|
"""Check if the given class is Pydantic v2-like.
|
|
90
88
|
|
|
91
89
|
Returns:
|
|
92
|
-
True if the given class is a subclass of Pydantic BaseModel 2.x.
|
|
90
|
+
`True` if the given class is a subclass of Pydantic BaseModel 2.x.
|
|
93
91
|
"""
|
|
94
92
|
return issubclass(cls, BaseModel)
|
|
95
93
|
|
|
@@ -103,7 +101,7 @@ def is_basemodel_subclass(cls: type) -> bool:
|
|
|
103
101
|
* pydantic.v1.BaseModel in Pydantic 2.x
|
|
104
102
|
|
|
105
103
|
Returns:
|
|
106
|
-
True if the given class is a subclass of Pydantic
|
|
104
|
+
`True` if the given class is a subclass of Pydantic `BaseModel`.
|
|
107
105
|
"""
|
|
108
106
|
# Before we can use issubclass on the cls we need to check if it is a class
|
|
109
107
|
if not inspect.isclass(cls) or isinstance(cls, GenericAlias):
|
|
@@ -121,7 +119,7 @@ def is_basemodel_instance(obj: Any) -> bool:
|
|
|
121
119
|
* pydantic.v1.BaseModel in Pydantic 2.x
|
|
122
120
|
|
|
123
121
|
Returns:
|
|
124
|
-
True if the given class is an instance of Pydantic
|
|
122
|
+
`True` if the given class is an instance of Pydantic `BaseModel`.
|
|
125
123
|
"""
|
|
126
124
|
return isinstance(obj, (BaseModel, BaseModelV1))
|
|
127
125
|
|
|
@@ -131,10 +129,10 @@ def pre_init(func: Callable) -> Any:
|
|
|
131
129
|
"""Decorator to run a function before model initialization.
|
|
132
130
|
|
|
133
131
|
Args:
|
|
134
|
-
func
|
|
132
|
+
func: The function to run before model initialization.
|
|
135
133
|
|
|
136
134
|
Returns:
|
|
137
|
-
|
|
135
|
+
The decorated function.
|
|
138
136
|
"""
|
|
139
137
|
with warnings.catch_warnings():
|
|
140
138
|
warnings.filterwarnings(action="ignore", category=PydanticDeprecationWarning)
|
|
@@ -148,11 +146,11 @@ def pre_init(func: Callable) -> Any:
|
|
|
148
146
|
"""Decorator to run a function before model initialization.
|
|
149
147
|
|
|
150
148
|
Args:
|
|
151
|
-
cls
|
|
152
|
-
values
|
|
149
|
+
cls: The model class.
|
|
150
|
+
values: The values to initialize the model with.
|
|
153
151
|
|
|
154
152
|
Returns:
|
|
155
|
-
|
|
153
|
+
The values to initialize the model with.
|
|
156
154
|
"""
|
|
157
155
|
# Insert default values
|
|
158
156
|
fields = cls.model_fields
|
|
@@ -205,10 +203,10 @@ def _create_subset_model_v1(
|
|
|
205
203
|
model: type[BaseModelV1],
|
|
206
204
|
field_names: list,
|
|
207
205
|
*,
|
|
208
|
-
descriptions:
|
|
209
|
-
fn_description:
|
|
206
|
+
descriptions: dict | None = None,
|
|
207
|
+
fn_description: str | None = None,
|
|
210
208
|
) -> type[BaseModel]:
|
|
211
|
-
"""Create a
|
|
209
|
+
"""Create a Pydantic model with only a subset of model's fields."""
|
|
212
210
|
fields = {}
|
|
213
211
|
|
|
214
212
|
for field_name in field_names:
|
|
@@ -218,7 +216,7 @@ def _create_subset_model_v1(
|
|
|
218
216
|
# this isn't perfect but should work for most functions
|
|
219
217
|
field.outer_type_
|
|
220
218
|
if field.required and not field.allow_none
|
|
221
|
-
else
|
|
219
|
+
else field.outer_type_ | None
|
|
222
220
|
)
|
|
223
221
|
if descriptions and field_name in descriptions:
|
|
224
222
|
field.field_info.description = descriptions[field_name]
|
|
@@ -234,10 +232,10 @@ def _create_subset_model_v2(
|
|
|
234
232
|
model: type[BaseModel],
|
|
235
233
|
field_names: list[str],
|
|
236
234
|
*,
|
|
237
|
-
descriptions:
|
|
238
|
-
fn_description:
|
|
235
|
+
descriptions: dict | None = None,
|
|
236
|
+
fn_description: str | None = None,
|
|
239
237
|
) -> type[BaseModel]:
|
|
240
|
-
"""Create a
|
|
238
|
+
"""Create a Pydantic model with a subset of the model fields."""
|
|
241
239
|
descriptions_ = descriptions or {}
|
|
242
240
|
fields = {}
|
|
243
241
|
for field_name in field_names:
|
|
@@ -276,8 +274,8 @@ def _create_subset_model(
|
|
|
276
274
|
model: TypeBaseModel,
|
|
277
275
|
field_names: list[str],
|
|
278
276
|
*,
|
|
279
|
-
descriptions:
|
|
280
|
-
fn_description:
|
|
277
|
+
descriptions: dict | None = None,
|
|
278
|
+
fn_description: str | None = None,
|
|
281
279
|
) -> type[BaseModel]:
|
|
282
280
|
"""Create subset model using the same pydantic version as the input model.
|
|
283
281
|
|
|
@@ -318,8 +316,8 @@ def get_fields(model: BaseModelV1) -> dict[str, ModelField]: ...
|
|
|
318
316
|
|
|
319
317
|
|
|
320
318
|
def get_fields(
|
|
321
|
-
model:
|
|
322
|
-
) ->
|
|
319
|
+
model: type[BaseModel | BaseModelV1] | BaseModel | BaseModelV1,
|
|
320
|
+
) -> dict[str, FieldInfoV2] | dict[str, ModelField]:
|
|
323
321
|
"""Return the field names of a Pydantic model.
|
|
324
322
|
|
|
325
323
|
Args:
|
|
@@ -348,7 +346,7 @@ NO_DEFAULT = object()
|
|
|
348
346
|
def _create_root_model(
|
|
349
347
|
name: str,
|
|
350
348
|
type_: Any,
|
|
351
|
-
module_name:
|
|
349
|
+
module_name: str | None = None,
|
|
352
350
|
default_: object = NO_DEFAULT,
|
|
353
351
|
) -> type[BaseModel]:
|
|
354
352
|
"""Create a base class."""
|
|
@@ -413,7 +411,7 @@ def _create_root_model_cached(
|
|
|
413
411
|
model_name: str,
|
|
414
412
|
type_: Any,
|
|
415
413
|
*,
|
|
416
|
-
module_name:
|
|
414
|
+
module_name: str | None = None,
|
|
417
415
|
default_: object = NO_DEFAULT,
|
|
418
416
|
) -> type[BaseModel]:
|
|
419
417
|
return _create_root_model(
|
|
@@ -436,13 +434,13 @@ def _create_model_cached(
|
|
|
436
434
|
|
|
437
435
|
def create_model(
|
|
438
436
|
model_name: str,
|
|
439
|
-
module_name:
|
|
437
|
+
module_name: str | None = None,
|
|
440
438
|
/,
|
|
441
439
|
**field_definitions: Any,
|
|
442
440
|
) -> type[BaseModel]:
|
|
443
|
-
"""Create a
|
|
441
|
+
"""Create a Pydantic model with the given field definitions.
|
|
444
442
|
|
|
445
|
-
Please use create_model_v2 instead of this function.
|
|
443
|
+
Please use `create_model_v2` instead of this function.
|
|
446
444
|
|
|
447
445
|
Args:
|
|
448
446
|
model_name: The name of the model.
|
|
@@ -451,7 +449,7 @@ def create_model(
|
|
|
451
449
|
**field_definitions: The field definitions for the model.
|
|
452
450
|
|
|
453
451
|
Returns:
|
|
454
|
-
|
|
452
|
+
The created model.
|
|
455
453
|
"""
|
|
456
454
|
kwargs = {}
|
|
457
455
|
if "__root__" in field_definitions:
|
|
@@ -509,11 +507,11 @@ def _remap_field_definitions(field_definitions: dict[str, Any]) -> dict[str, Any
|
|
|
509
507
|
def create_model_v2(
|
|
510
508
|
model_name: str,
|
|
511
509
|
*,
|
|
512
|
-
module_name:
|
|
513
|
-
field_definitions:
|
|
514
|
-
root:
|
|
510
|
+
module_name: str | None = None,
|
|
511
|
+
field_definitions: dict[str, Any] | None = None,
|
|
512
|
+
root: Any | None = None,
|
|
515
513
|
) -> type[BaseModel]:
|
|
516
|
-
"""Create a
|
|
514
|
+
"""Create a Pydantic model with the given field definitions.
|
|
517
515
|
|
|
518
516
|
Attention:
|
|
519
517
|
Please do not use outside of langchain packages. This API
|
|
@@ -524,10 +522,10 @@ def create_model_v2(
|
|
|
524
522
|
module_name: The name of the module where the model is defined.
|
|
525
523
|
This is used by Pydantic to resolve any forward references.
|
|
526
524
|
field_definitions: The field definitions for the model.
|
|
527
|
-
root: Type for a root model (RootModel)
|
|
525
|
+
root: Type for a root model (`RootModel`)
|
|
528
526
|
|
|
529
527
|
Returns:
|
|
530
|
-
|
|
528
|
+
The created model.
|
|
531
529
|
"""
|
|
532
530
|
field_definitions = field_definitions or {}
|
|
533
531
|
|
langchain_core/utils/strings.py
CHANGED
|
@@ -10,7 +10,7 @@ def stringify_value(val: Any) -> str:
|
|
|
10
10
|
val: The value to stringify.
|
|
11
11
|
|
|
12
12
|
Returns:
|
|
13
|
-
|
|
13
|
+
The stringified value.
|
|
14
14
|
"""
|
|
15
15
|
if isinstance(val, str):
|
|
16
16
|
return val
|
|
@@ -28,12 +28,9 @@ def stringify_dict(data: dict) -> str:
|
|
|
28
28
|
data: The dictionary to stringify.
|
|
29
29
|
|
|
30
30
|
Returns:
|
|
31
|
-
|
|
31
|
+
The stringified dictionary.
|
|
32
32
|
"""
|
|
33
|
-
|
|
34
|
-
for key, value in data.items():
|
|
35
|
-
text += key + ": " + stringify_value(value) + "\n"
|
|
36
|
-
return text
|
|
33
|
+
return "".join(f"{key}: {stringify_value(value)}\n" for key, value in data.items())
|
|
37
34
|
|
|
38
35
|
|
|
39
36
|
def comma_list(items: list[Any]) -> str:
|
|
@@ -43,7 +40,7 @@ def comma_list(items: list[Any]) -> str:
|
|
|
43
40
|
items: The list to convert.
|
|
44
41
|
|
|
45
42
|
Returns:
|
|
46
|
-
|
|
43
|
+
The comma-separated string.
|
|
47
44
|
"""
|
|
48
45
|
return ", ".join(str(item) for item in items)
|
|
49
46
|
|
|
@@ -57,10 +54,10 @@ def sanitize_for_postgres(text: str, replacement: str = "") -> str:
|
|
|
57
54
|
|
|
58
55
|
Args:
|
|
59
56
|
text: The text to sanitize.
|
|
60
|
-
replacement: String to replace NUL bytes with.
|
|
57
|
+
replacement: String to replace NUL bytes with.
|
|
61
58
|
|
|
62
59
|
Returns:
|
|
63
|
-
|
|
60
|
+
The sanitized text with NUL bytes removed or replaced.
|
|
64
61
|
|
|
65
62
|
Example:
|
|
66
63
|
>>> sanitize_for_postgres("Hello\\x00world")
|