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.
- langchain_core/__init__.py +1 -1
- langchain_core/_api/__init__.py +3 -4
- langchain_core/_api/beta_decorator.py +45 -70
- langchain_core/_api/deprecation.py +80 -80
- langchain_core/_api/path.py +22 -8
- langchain_core/_import_utils.py +10 -4
- langchain_core/agents.py +25 -21
- langchain_core/caches.py +53 -63
- langchain_core/callbacks/__init__.py +1 -8
- langchain_core/callbacks/base.py +341 -348
- langchain_core/callbacks/file.py +55 -44
- langchain_core/callbacks/manager.py +546 -683
- langchain_core/callbacks/stdout.py +29 -30
- langchain_core/callbacks/streaming_stdout.py +35 -36
- langchain_core/callbacks/usage.py +65 -70
- langchain_core/chat_history.py +48 -55
- langchain_core/document_loaders/base.py +46 -21
- langchain_core/document_loaders/langsmith.py +39 -36
- langchain_core/documents/__init__.py +0 -1
- langchain_core/documents/base.py +96 -74
- langchain_core/documents/compressor.py +12 -9
- langchain_core/documents/transformers.py +29 -28
- langchain_core/embeddings/fake.py +56 -57
- langchain_core/env.py +2 -3
- langchain_core/example_selectors/base.py +12 -0
- langchain_core/example_selectors/length_based.py +1 -1
- langchain_core/example_selectors/semantic_similarity.py +21 -25
- langchain_core/exceptions.py +15 -9
- langchain_core/globals.py +4 -163
- langchain_core/indexing/api.py +132 -125
- langchain_core/indexing/base.py +64 -67
- langchain_core/indexing/in_memory.py +26 -6
- langchain_core/language_models/__init__.py +15 -27
- langchain_core/language_models/_utils.py +267 -117
- langchain_core/language_models/base.py +92 -177
- langchain_core/language_models/chat_models.py +547 -407
- langchain_core/language_models/fake.py +11 -11
- langchain_core/language_models/fake_chat_models.py +72 -118
- langchain_core/language_models/llms.py +168 -242
- langchain_core/load/dump.py +8 -11
- langchain_core/load/load.py +32 -28
- langchain_core/load/mapping.py +2 -4
- langchain_core/load/serializable.py +50 -56
- langchain_core/messages/__init__.py +36 -51
- langchain_core/messages/ai.py +377 -150
- langchain_core/messages/base.py +239 -47
- langchain_core/messages/block_translators/__init__.py +111 -0
- langchain_core/messages/block_translators/anthropic.py +470 -0
- langchain_core/messages/block_translators/bedrock.py +94 -0
- langchain_core/messages/block_translators/bedrock_converse.py +297 -0
- langchain_core/messages/block_translators/google_genai.py +530 -0
- langchain_core/messages/block_translators/google_vertexai.py +21 -0
- langchain_core/messages/block_translators/groq.py +143 -0
- langchain_core/messages/block_translators/langchain_v0.py +301 -0
- langchain_core/messages/block_translators/openai.py +1010 -0
- langchain_core/messages/chat.py +2 -3
- langchain_core/messages/content.py +1423 -0
- langchain_core/messages/function.py +7 -7
- langchain_core/messages/human.py +44 -38
- langchain_core/messages/modifier.py +3 -2
- langchain_core/messages/system.py +40 -27
- langchain_core/messages/tool.py +160 -58
- langchain_core/messages/utils.py +527 -638
- langchain_core/output_parsers/__init__.py +1 -14
- langchain_core/output_parsers/base.py +68 -104
- langchain_core/output_parsers/json.py +13 -17
- langchain_core/output_parsers/list.py +11 -33
- langchain_core/output_parsers/openai_functions.py +56 -74
- langchain_core/output_parsers/openai_tools.py +68 -109
- langchain_core/output_parsers/pydantic.py +15 -13
- langchain_core/output_parsers/string.py +6 -2
- langchain_core/output_parsers/transform.py +17 -60
- langchain_core/output_parsers/xml.py +34 -44
- langchain_core/outputs/__init__.py +1 -1
- langchain_core/outputs/chat_generation.py +26 -11
- langchain_core/outputs/chat_result.py +1 -3
- langchain_core/outputs/generation.py +17 -6
- langchain_core/outputs/llm_result.py +15 -8
- langchain_core/prompt_values.py +29 -123
- langchain_core/prompts/__init__.py +3 -27
- langchain_core/prompts/base.py +48 -63
- langchain_core/prompts/chat.py +259 -288
- langchain_core/prompts/dict.py +19 -11
- langchain_core/prompts/few_shot.py +84 -90
- langchain_core/prompts/few_shot_with_templates.py +14 -12
- langchain_core/prompts/image.py +19 -14
- langchain_core/prompts/loading.py +6 -8
- langchain_core/prompts/message.py +7 -8
- langchain_core/prompts/prompt.py +42 -43
- langchain_core/prompts/string.py +37 -16
- langchain_core/prompts/structured.py +43 -46
- langchain_core/rate_limiters.py +51 -60
- langchain_core/retrievers.py +52 -192
- langchain_core/runnables/base.py +1727 -1683
- langchain_core/runnables/branch.py +52 -73
- langchain_core/runnables/config.py +89 -103
- langchain_core/runnables/configurable.py +128 -130
- langchain_core/runnables/fallbacks.py +93 -82
- langchain_core/runnables/graph.py +127 -127
- langchain_core/runnables/graph_ascii.py +63 -41
- langchain_core/runnables/graph_mermaid.py +87 -70
- langchain_core/runnables/graph_png.py +31 -36
- langchain_core/runnables/history.py +145 -161
- langchain_core/runnables/passthrough.py +141 -144
- langchain_core/runnables/retry.py +84 -68
- langchain_core/runnables/router.py +33 -37
- langchain_core/runnables/schema.py +79 -72
- langchain_core/runnables/utils.py +95 -139
- langchain_core/stores.py +85 -131
- langchain_core/structured_query.py +11 -15
- langchain_core/sys_info.py +31 -32
- langchain_core/tools/__init__.py +1 -14
- langchain_core/tools/base.py +221 -247
- langchain_core/tools/convert.py +144 -161
- langchain_core/tools/render.py +10 -10
- langchain_core/tools/retriever.py +12 -19
- langchain_core/tools/simple.py +52 -29
- langchain_core/tools/structured.py +56 -60
- langchain_core/tracers/__init__.py +1 -9
- langchain_core/tracers/_streaming.py +6 -7
- langchain_core/tracers/base.py +103 -112
- langchain_core/tracers/context.py +29 -48
- langchain_core/tracers/core.py +142 -105
- langchain_core/tracers/evaluation.py +30 -34
- langchain_core/tracers/event_stream.py +162 -117
- langchain_core/tracers/langchain.py +34 -36
- langchain_core/tracers/log_stream.py +87 -49
- langchain_core/tracers/memory_stream.py +3 -3
- langchain_core/tracers/root_listeners.py +18 -34
- langchain_core/tracers/run_collector.py +8 -20
- langchain_core/tracers/schemas.py +0 -125
- langchain_core/tracers/stdout.py +3 -3
- langchain_core/utils/__init__.py +1 -4
- langchain_core/utils/_merge.py +47 -9
- langchain_core/utils/aiter.py +70 -66
- langchain_core/utils/env.py +12 -9
- langchain_core/utils/function_calling.py +139 -206
- langchain_core/utils/html.py +7 -8
- langchain_core/utils/input.py +6 -6
- langchain_core/utils/interactive_env.py +6 -2
- langchain_core/utils/iter.py +48 -45
- langchain_core/utils/json.py +14 -4
- langchain_core/utils/json_schema.py +159 -43
- langchain_core/utils/mustache.py +32 -25
- langchain_core/utils/pydantic.py +67 -40
- langchain_core/utils/strings.py +5 -5
- langchain_core/utils/usage.py +1 -1
- langchain_core/utils/utils.py +104 -62
- langchain_core/vectorstores/base.py +131 -179
- langchain_core/vectorstores/in_memory.py +113 -182
- langchain_core/vectorstores/utils.py +23 -17
- langchain_core/version.py +1 -1
- langchain_core-1.0.0.dist-info/METADATA +68 -0
- langchain_core-1.0.0.dist-info/RECORD +172 -0
- {langchain_core-0.4.0.dev0.dist-info → langchain_core-1.0.0.dist-info}/WHEEL +1 -1
- langchain_core/beta/__init__.py +0 -1
- langchain_core/beta/runnables/__init__.py +0 -1
- langchain_core/beta/runnables/context.py +0 -448
- langchain_core/memory.py +0 -116
- langchain_core/messages/content_blocks.py +0 -1435
- langchain_core/prompts/pipeline.py +0 -133
- 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 -23
- langchain_core/utils/loading.py +0 -31
- 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/METADATA +0 -108
- langchain_core-0.4.0.dev0.dist-info/RECORD +0 -177
- langchain_core-0.4.0.dev0.dist-info/entry_points.txt +0 -4
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
|
)
|
|
@@ -57,6 +55,9 @@ def get_pydantic_major_version() -> int:
|
|
|
57
55
|
"""DEPRECATED - Get the major version of Pydantic.
|
|
58
56
|
|
|
59
57
|
Use PYDANTIC_VERSION.major instead.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
The major version of Pydantic.
|
|
60
61
|
"""
|
|
61
62
|
return PYDANTIC_VERSION.major
|
|
62
63
|
|
|
@@ -74,12 +75,20 @@ TBaseModel = TypeVar("TBaseModel", bound=PydanticBaseModel)
|
|
|
74
75
|
|
|
75
76
|
|
|
76
77
|
def is_pydantic_v1_subclass(cls: type) -> bool:
|
|
77
|
-
"""Check if the
|
|
78
|
+
"""Check if the given class is Pydantic v1-like.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
`True` if the given class is a subclass of Pydantic `BaseModel` 1.x.
|
|
82
|
+
"""
|
|
78
83
|
return issubclass(cls, BaseModelV1)
|
|
79
84
|
|
|
80
85
|
|
|
81
86
|
def is_pydantic_v2_subclass(cls: type) -> bool:
|
|
82
|
-
"""Check if the
|
|
87
|
+
"""Check if the given class is Pydantic v2-like.
|
|
88
|
+
|
|
89
|
+
Returns:
|
|
90
|
+
`True` if the given class is a subclass of Pydantic BaseModel 2.x.
|
|
91
|
+
"""
|
|
83
92
|
return issubclass(cls, BaseModel)
|
|
84
93
|
|
|
85
94
|
|
|
@@ -90,6 +99,9 @@ def is_basemodel_subclass(cls: type) -> bool:
|
|
|
90
99
|
|
|
91
100
|
* pydantic.BaseModel in Pydantic 2.x
|
|
92
101
|
* pydantic.v1.BaseModel in Pydantic 2.x
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
`True` if the given class is a subclass of Pydantic `BaseModel`.
|
|
93
105
|
"""
|
|
94
106
|
# Before we can use issubclass on the cls we need to check if it is a class
|
|
95
107
|
if not inspect.isclass(cls) or isinstance(cls, GenericAlias):
|
|
@@ -105,6 +117,9 @@ def is_basemodel_instance(obj: Any) -> bool:
|
|
|
105
117
|
|
|
106
118
|
* pydantic.BaseModel in Pydantic 2.x
|
|
107
119
|
* pydantic.v1.BaseModel in Pydantic 2.x
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
`True` if the given class is an instance of Pydantic `BaseModel`.
|
|
108
123
|
"""
|
|
109
124
|
return isinstance(obj, (BaseModel, BaseModelV1))
|
|
110
125
|
|
|
@@ -114,10 +129,10 @@ def pre_init(func: Callable) -> Any:
|
|
|
114
129
|
"""Decorator to run a function before model initialization.
|
|
115
130
|
|
|
116
131
|
Args:
|
|
117
|
-
func
|
|
132
|
+
func: The function to run before model initialization.
|
|
118
133
|
|
|
119
134
|
Returns:
|
|
120
|
-
|
|
135
|
+
The decorated function.
|
|
121
136
|
"""
|
|
122
137
|
with warnings.catch_warnings():
|
|
123
138
|
warnings.filterwarnings(action="ignore", category=PydanticDeprecationWarning)
|
|
@@ -125,17 +140,17 @@ def pre_init(func: Callable) -> Any:
|
|
|
125
140
|
# Ideally we would use @model_validator(mode="before") but this would change the
|
|
126
141
|
# order of the validators. See https://github.com/pydantic/pydantic/discussions/7434.
|
|
127
142
|
# So we keep root_validator for backward compatibility.
|
|
128
|
-
@root_validator(pre=True)
|
|
143
|
+
@root_validator(pre=True) # type: ignore[deprecated]
|
|
129
144
|
@wraps(func)
|
|
130
145
|
def wrapper(cls: type[BaseModel], values: dict[str, Any]) -> dict[str, Any]:
|
|
131
146
|
"""Decorator to run a function before model initialization.
|
|
132
147
|
|
|
133
148
|
Args:
|
|
134
|
-
cls
|
|
135
|
-
values
|
|
149
|
+
cls: The model class.
|
|
150
|
+
values: The values to initialize the model with.
|
|
136
151
|
|
|
137
152
|
Returns:
|
|
138
|
-
|
|
153
|
+
The values to initialize the model with.
|
|
139
154
|
"""
|
|
140
155
|
# Insert default values
|
|
141
156
|
fields = cls.model_fields
|
|
@@ -188,10 +203,10 @@ def _create_subset_model_v1(
|
|
|
188
203
|
model: type[BaseModelV1],
|
|
189
204
|
field_names: list,
|
|
190
205
|
*,
|
|
191
|
-
descriptions:
|
|
192
|
-
fn_description:
|
|
206
|
+
descriptions: dict | None = None,
|
|
207
|
+
fn_description: str | None = None,
|
|
193
208
|
) -> type[BaseModel]:
|
|
194
|
-
"""Create a
|
|
209
|
+
"""Create a Pydantic model with only a subset of model's fields."""
|
|
195
210
|
fields = {}
|
|
196
211
|
|
|
197
212
|
for field_name in field_names:
|
|
@@ -201,7 +216,7 @@ def _create_subset_model_v1(
|
|
|
201
216
|
# this isn't perfect but should work for most functions
|
|
202
217
|
field.outer_type_
|
|
203
218
|
if field.required and not field.allow_none
|
|
204
|
-
else
|
|
219
|
+
else field.outer_type_ | None
|
|
205
220
|
)
|
|
206
221
|
if descriptions and field_name in descriptions:
|
|
207
222
|
field.field_info.description = descriptions[field_name]
|
|
@@ -217,10 +232,10 @@ def _create_subset_model_v2(
|
|
|
217
232
|
model: type[BaseModel],
|
|
218
233
|
field_names: list[str],
|
|
219
234
|
*,
|
|
220
|
-
descriptions:
|
|
221
|
-
fn_description:
|
|
235
|
+
descriptions: dict | None = None,
|
|
236
|
+
fn_description: str | None = None,
|
|
222
237
|
) -> type[BaseModel]:
|
|
223
|
-
"""Create a
|
|
238
|
+
"""Create a Pydantic model with a subset of the model fields."""
|
|
224
239
|
descriptions_ = descriptions or {}
|
|
225
240
|
fields = {}
|
|
226
241
|
for field_name in field_names:
|
|
@@ -259,10 +274,14 @@ def _create_subset_model(
|
|
|
259
274
|
model: TypeBaseModel,
|
|
260
275
|
field_names: list[str],
|
|
261
276
|
*,
|
|
262
|
-
descriptions:
|
|
263
|
-
fn_description:
|
|
277
|
+
descriptions: dict | None = None,
|
|
278
|
+
fn_description: str | None = None,
|
|
264
279
|
) -> type[BaseModel]:
|
|
265
|
-
"""Create subset model using the same pydantic version as the input model.
|
|
280
|
+
"""Create subset model using the same pydantic version as the input model.
|
|
281
|
+
|
|
282
|
+
Returns:
|
|
283
|
+
The created subset model.
|
|
284
|
+
"""
|
|
266
285
|
if issubclass(model, BaseModelV1):
|
|
267
286
|
return _create_subset_model_v1(
|
|
268
287
|
name,
|
|
@@ -297,15 +316,23 @@ def get_fields(model: BaseModelV1) -> dict[str, ModelField]: ...
|
|
|
297
316
|
|
|
298
317
|
|
|
299
318
|
def get_fields(
|
|
300
|
-
model:
|
|
301
|
-
) ->
|
|
302
|
-
"""
|
|
303
|
-
if hasattr(model, "model_fields"):
|
|
304
|
-
return model.model_fields
|
|
319
|
+
model: type[BaseModel | BaseModelV1] | BaseModel | BaseModelV1,
|
|
320
|
+
) -> dict[str, FieldInfoV2] | dict[str, ModelField]:
|
|
321
|
+
"""Return the field names of a Pydantic model.
|
|
305
322
|
|
|
306
|
-
|
|
323
|
+
Args:
|
|
324
|
+
model: The Pydantic model or instance.
|
|
325
|
+
|
|
326
|
+
Raises:
|
|
327
|
+
TypeError: If the model is not a Pydantic model.
|
|
328
|
+
"""
|
|
329
|
+
if not isinstance(model, type):
|
|
330
|
+
model = type(model)
|
|
331
|
+
if issubclass(model, BaseModel):
|
|
332
|
+
return model.model_fields
|
|
333
|
+
if issubclass(model, BaseModelV1):
|
|
307
334
|
return model.__fields__
|
|
308
|
-
msg = f"Expected a Pydantic model. Got {
|
|
335
|
+
msg = f"Expected a Pydantic model. Got {model}"
|
|
309
336
|
raise TypeError(msg)
|
|
310
337
|
|
|
311
338
|
|
|
@@ -319,7 +346,7 @@ NO_DEFAULT = object()
|
|
|
319
346
|
def _create_root_model(
|
|
320
347
|
name: str,
|
|
321
348
|
type_: Any,
|
|
322
|
-
module_name:
|
|
349
|
+
module_name: str | None = None,
|
|
323
350
|
default_: object = NO_DEFAULT,
|
|
324
351
|
) -> type[BaseModel]:
|
|
325
352
|
"""Create a base class."""
|
|
@@ -384,7 +411,7 @@ def _create_root_model_cached(
|
|
|
384
411
|
model_name: str,
|
|
385
412
|
type_: Any,
|
|
386
413
|
*,
|
|
387
|
-
module_name:
|
|
414
|
+
module_name: str | None = None,
|
|
388
415
|
default_: object = NO_DEFAULT,
|
|
389
416
|
) -> type[BaseModel]:
|
|
390
417
|
return _create_root_model(
|
|
@@ -407,13 +434,13 @@ def _create_model_cached(
|
|
|
407
434
|
|
|
408
435
|
def create_model(
|
|
409
436
|
model_name: str,
|
|
410
|
-
module_name:
|
|
437
|
+
module_name: str | None = None,
|
|
411
438
|
/,
|
|
412
439
|
**field_definitions: Any,
|
|
413
440
|
) -> type[BaseModel]:
|
|
414
|
-
"""Create a
|
|
441
|
+
"""Create a Pydantic model with the given field definitions.
|
|
415
442
|
|
|
416
|
-
Please use create_model_v2 instead of this function.
|
|
443
|
+
Please use `create_model_v2` instead of this function.
|
|
417
444
|
|
|
418
445
|
Args:
|
|
419
446
|
model_name: The name of the model.
|
|
@@ -422,7 +449,7 @@ def create_model(
|
|
|
422
449
|
**field_definitions: The field definitions for the model.
|
|
423
450
|
|
|
424
451
|
Returns:
|
|
425
|
-
|
|
452
|
+
The created model.
|
|
426
453
|
"""
|
|
427
454
|
kwargs = {}
|
|
428
455
|
if "__root__" in field_definitions:
|
|
@@ -480,11 +507,11 @@ def _remap_field_definitions(field_definitions: dict[str, Any]) -> dict[str, Any
|
|
|
480
507
|
def create_model_v2(
|
|
481
508
|
model_name: str,
|
|
482
509
|
*,
|
|
483
|
-
module_name:
|
|
484
|
-
field_definitions:
|
|
485
|
-
root:
|
|
510
|
+
module_name: str | None = None,
|
|
511
|
+
field_definitions: dict[str, Any] | None = None,
|
|
512
|
+
root: Any | None = None,
|
|
486
513
|
) -> type[BaseModel]:
|
|
487
|
-
"""Create a
|
|
514
|
+
"""Create a Pydantic model with the given field definitions.
|
|
488
515
|
|
|
489
516
|
Attention:
|
|
490
517
|
Please do not use outside of langchain packages. This API
|
|
@@ -495,10 +522,10 @@ def create_model_v2(
|
|
|
495
522
|
module_name: The name of the module where the model is defined.
|
|
496
523
|
This is used by Pydantic to resolve any forward references.
|
|
497
524
|
field_definitions: The field definitions for the model.
|
|
498
|
-
root: Type for a root model (RootModel)
|
|
525
|
+
root: Type for a root model (`RootModel`)
|
|
499
526
|
|
|
500
527
|
Returns:
|
|
501
|
-
|
|
528
|
+
The created model.
|
|
502
529
|
"""
|
|
503
530
|
field_definitions = field_definitions or {}
|
|
504
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,7 +28,7 @@ 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
33
|
text = ""
|
|
34
34
|
for key, value in data.items():
|
|
@@ -43,7 +43,7 @@ def comma_list(items: list[Any]) -> str:
|
|
|
43
43
|
items: The list to convert.
|
|
44
44
|
|
|
45
45
|
Returns:
|
|
46
|
-
|
|
46
|
+
The comma-separated string.
|
|
47
47
|
"""
|
|
48
48
|
return ", ".join(str(item) for item in items)
|
|
49
49
|
|
|
@@ -57,10 +57,10 @@ def sanitize_for_postgres(text: str, replacement: str = "") -> str:
|
|
|
57
57
|
|
|
58
58
|
Args:
|
|
59
59
|
text: The text to sanitize.
|
|
60
|
-
replacement: String to replace NUL bytes with.
|
|
60
|
+
replacement: String to replace NUL bytes with.
|
|
61
61
|
|
|
62
62
|
Returns:
|
|
63
|
-
|
|
63
|
+
The sanitized text with NUL bytes removed or replaced.
|
|
64
64
|
|
|
65
65
|
Example:
|
|
66
66
|
>>> sanitize_for_postgres("Hello\\x00world")
|
langchain_core/utils/usage.py
CHANGED
langchain_core/utils/utils.py
CHANGED
|
@@ -6,9 +6,10 @@ import functools
|
|
|
6
6
|
import importlib
|
|
7
7
|
import os
|
|
8
8
|
import warnings
|
|
9
|
-
from collections.abc import Iterator, Sequence
|
|
9
|
+
from collections.abc import Callable, Iterator, Sequence
|
|
10
10
|
from importlib.metadata import version
|
|
11
|
-
from typing import Any,
|
|
11
|
+
from typing import Any, overload
|
|
12
|
+
from uuid import uuid4
|
|
12
13
|
|
|
13
14
|
from packaging.version import parse
|
|
14
15
|
from pydantic import SecretStr
|
|
@@ -21,17 +22,14 @@ from langchain_core.utils.pydantic import (
|
|
|
21
22
|
|
|
22
23
|
|
|
23
24
|
def xor_args(*arg_groups: tuple[str, ...]) -> Callable:
|
|
24
|
-
"""Validate specified keyword args are mutually exclusive.
|
|
25
|
+
"""Validate specified keyword args are mutually exclusive.
|
|
25
26
|
|
|
26
27
|
Args:
|
|
27
|
-
*arg_groups
|
|
28
|
+
*arg_groups: Groups of mutually exclusive keyword args.
|
|
28
29
|
|
|
29
30
|
Returns:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
Raises:
|
|
34
|
-
ValueError: If more than one arg in a group is defined.
|
|
31
|
+
Decorator that validates the specified keyword args
|
|
32
|
+
are mutually exclusive.
|
|
35
33
|
"""
|
|
36
34
|
|
|
37
35
|
def decorator(func: Callable) -> Callable:
|
|
@@ -62,7 +60,7 @@ def raise_for_status_with_text(response: Response) -> None:
|
|
|
62
60
|
"""Raise an error with the response text.
|
|
63
61
|
|
|
64
62
|
Args:
|
|
65
|
-
response
|
|
63
|
+
response: The response to check for errors.
|
|
66
64
|
|
|
67
65
|
Raises:
|
|
68
66
|
ValueError: If the response has an error status code.
|
|
@@ -81,11 +79,13 @@ def mock_now(dt_value: datetime.datetime) -> Iterator[type]:
|
|
|
81
79
|
dt_value: The datetime value to use for datetime.now().
|
|
82
80
|
|
|
83
81
|
Yields:
|
|
84
|
-
|
|
82
|
+
The mocked datetime class.
|
|
85
83
|
|
|
86
84
|
Example:
|
|
87
|
-
|
|
88
|
-
|
|
85
|
+
```python
|
|
86
|
+
with mock_now(datetime.datetime(2011, 2, 3, 10, 11)):
|
|
87
|
+
assert datetime.datetime.now() == datetime.datetime(2011, 2, 3, 10, 11)
|
|
88
|
+
```
|
|
89
89
|
"""
|
|
90
90
|
|
|
91
91
|
class MockDateTime(datetime.datetime):
|
|
@@ -93,7 +93,7 @@ def mock_now(dt_value: datetime.datetime) -> Iterator[type]:
|
|
|
93
93
|
|
|
94
94
|
@classmethod
|
|
95
95
|
@override
|
|
96
|
-
def now(cls, tz:
|
|
96
|
+
def now(cls, tz: datetime.tzinfo | None = None) -> "MockDateTime":
|
|
97
97
|
# Create a copy of dt_value.
|
|
98
98
|
return MockDateTime(
|
|
99
99
|
dt_value.year,
|
|
@@ -115,21 +115,19 @@ def mock_now(dt_value: datetime.datetime) -> Iterator[type]:
|
|
|
115
115
|
|
|
116
116
|
|
|
117
117
|
def guard_import(
|
|
118
|
-
module_name: str, *, pip_name:
|
|
118
|
+
module_name: str, *, pip_name: str | None = None, package: str | None = None
|
|
119
119
|
) -> Any:
|
|
120
120
|
"""Dynamically import a module.
|
|
121
121
|
|
|
122
122
|
Raise an exception if the module is not installed.
|
|
123
123
|
|
|
124
124
|
Args:
|
|
125
|
-
module_name
|
|
126
|
-
pip_name
|
|
127
|
-
|
|
128
|
-
package (str, optional): The package to import the module from.
|
|
129
|
-
Defaults to None.
|
|
125
|
+
module_name: The name of the module to import.
|
|
126
|
+
pip_name: The name of the module to install with pip.
|
|
127
|
+
package: The package to import the module from.
|
|
130
128
|
|
|
131
129
|
Returns:
|
|
132
|
-
|
|
130
|
+
The imported module.
|
|
133
131
|
|
|
134
132
|
Raises:
|
|
135
133
|
ImportError: If the module is not installed.
|
|
@@ -137,7 +135,7 @@ def guard_import(
|
|
|
137
135
|
try:
|
|
138
136
|
module = importlib.import_module(module_name, package)
|
|
139
137
|
except (ImportError, ModuleNotFoundError) as e:
|
|
140
|
-
pip_name = pip_name or module_name.split(".")[0].replace("_", "-")
|
|
138
|
+
pip_name = pip_name or module_name.split(".", maxsplit=1)[0].replace("_", "-")
|
|
141
139
|
msg = (
|
|
142
140
|
f"Could not import {module_name} python package. "
|
|
143
141
|
f"Please install it with `pip install {pip_name}`."
|
|
@@ -148,23 +146,20 @@ def guard_import(
|
|
|
148
146
|
|
|
149
147
|
def check_package_version(
|
|
150
148
|
package: str,
|
|
151
|
-
lt_version:
|
|
152
|
-
lte_version:
|
|
153
|
-
gt_version:
|
|
154
|
-
gte_version:
|
|
149
|
+
lt_version: str | None = None,
|
|
150
|
+
lte_version: str | None = None,
|
|
151
|
+
gt_version: str | None = None,
|
|
152
|
+
gte_version: str | None = None,
|
|
155
153
|
) -> None:
|
|
156
154
|
"""Check the version of a package.
|
|
157
155
|
|
|
158
156
|
Args:
|
|
159
|
-
package
|
|
160
|
-
lt_version
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
Defaults to None.
|
|
166
|
-
gte_version (str, optional): The version must be greater than or equal to this.
|
|
167
|
-
Defaults to None.
|
|
157
|
+
package: The name of the package.
|
|
158
|
+
lt_version: The version must be less than this.
|
|
159
|
+
lte_version: The version must be less than or equal to this.
|
|
160
|
+
gt_version: The version must be greater than this.
|
|
161
|
+
gte_version: The version must be greater than or equal to this.
|
|
162
|
+
|
|
168
163
|
|
|
169
164
|
Raises:
|
|
170
165
|
ValueError: If the package version does not meet the requirements.
|
|
@@ -203,7 +198,7 @@ def get_pydantic_field_names(pydantic_cls: Any) -> set[str]:
|
|
|
203
198
|
pydantic_cls: Pydantic class.
|
|
204
199
|
|
|
205
200
|
Returns:
|
|
206
|
-
|
|
201
|
+
Field names.
|
|
207
202
|
"""
|
|
208
203
|
all_required_field_names = set()
|
|
209
204
|
if is_pydantic_v1_subclass(pydantic_cls):
|
|
@@ -223,14 +218,14 @@ def _build_model_kwargs(
|
|
|
223
218
|
values: dict[str, Any],
|
|
224
219
|
all_required_field_names: set[str],
|
|
225
220
|
) -> dict[str, Any]:
|
|
226
|
-
"""Build "model_kwargs" param from
|
|
221
|
+
"""Build "model_kwargs" param from Pydantic constructor values.
|
|
227
222
|
|
|
228
223
|
Args:
|
|
229
224
|
values: All init args passed in by user.
|
|
230
225
|
all_required_field_names: All required field names for the pydantic class.
|
|
231
226
|
|
|
232
227
|
Returns:
|
|
233
|
-
|
|
228
|
+
Extra kwargs.
|
|
234
229
|
|
|
235
230
|
Raises:
|
|
236
231
|
ValueError: If a field is specified in both values and extra_kwargs.
|
|
@@ -278,7 +273,7 @@ def build_extra_kwargs(
|
|
|
278
273
|
all_required_field_names: All required field names for the pydantic class.
|
|
279
274
|
|
|
280
275
|
Returns:
|
|
281
|
-
|
|
276
|
+
Extra kwargs.
|
|
282
277
|
|
|
283
278
|
Raises:
|
|
284
279
|
ValueError: If a field is specified in both values and extra_kwargs.
|
|
@@ -308,14 +303,14 @@ def build_extra_kwargs(
|
|
|
308
303
|
return extra_kwargs
|
|
309
304
|
|
|
310
305
|
|
|
311
|
-
def convert_to_secret_str(value:
|
|
306
|
+
def convert_to_secret_str(value: SecretStr | str) -> SecretStr:
|
|
312
307
|
"""Convert a string to a SecretStr if needed.
|
|
313
308
|
|
|
314
309
|
Args:
|
|
315
|
-
value
|
|
310
|
+
value: The value to convert.
|
|
316
311
|
|
|
317
312
|
Returns:
|
|
318
|
-
|
|
313
|
+
The SecretStr value.
|
|
319
314
|
"""
|
|
320
315
|
if isinstance(value, SecretStr):
|
|
321
316
|
return value
|
|
@@ -347,29 +342,29 @@ def from_env(key: str, /, *, error_message: str) -> Callable[[], str]: ...
|
|
|
347
342
|
|
|
348
343
|
@overload
|
|
349
344
|
def from_env(
|
|
350
|
-
key:
|
|
345
|
+
key: str | Sequence[str], /, *, default: str, error_message: str | None
|
|
351
346
|
) -> Callable[[], str]: ...
|
|
352
347
|
|
|
353
348
|
|
|
354
349
|
@overload
|
|
355
350
|
def from_env(
|
|
356
|
-
key: str, /, *, default: None, error_message:
|
|
357
|
-
) -> Callable[[],
|
|
351
|
+
key: str, /, *, default: None, error_message: str | None
|
|
352
|
+
) -> Callable[[], str | None]: ...
|
|
358
353
|
|
|
359
354
|
|
|
360
355
|
@overload
|
|
361
356
|
def from_env(
|
|
362
|
-
key:
|
|
363
|
-
) -> Callable[[],
|
|
357
|
+
key: str | Sequence[str], /, *, default: None
|
|
358
|
+
) -> Callable[[], str | None]: ...
|
|
364
359
|
|
|
365
360
|
|
|
366
361
|
def from_env(
|
|
367
|
-
key:
|
|
362
|
+
key: str | Sequence[str],
|
|
368
363
|
/,
|
|
369
364
|
*,
|
|
370
|
-
default:
|
|
371
|
-
error_message:
|
|
372
|
-
) ->
|
|
365
|
+
default: str | _NoDefaultType | None = _NoDefault,
|
|
366
|
+
error_message: str | None = None,
|
|
367
|
+
) -> Callable[[], str] | Callable[[], str | None]:
|
|
373
368
|
"""Create a factory method that gets a value from an environment variable.
|
|
374
369
|
|
|
375
370
|
Args:
|
|
@@ -381,10 +376,21 @@ def from_env(
|
|
|
381
376
|
error_message: the error message which will be raised if the key is not found
|
|
382
377
|
and no default value is provided.
|
|
383
378
|
This will be raised as a ValueError.
|
|
379
|
+
|
|
380
|
+
Returns:
|
|
381
|
+
factory method that will look up the value from the environment.
|
|
384
382
|
"""
|
|
385
383
|
|
|
386
|
-
def get_from_env_fn() ->
|
|
387
|
-
"""Get a value from an environment variable.
|
|
384
|
+
def get_from_env_fn() -> str | None:
|
|
385
|
+
"""Get a value from an environment variable.
|
|
386
|
+
|
|
387
|
+
Raises:
|
|
388
|
+
ValueError: If the environment variable is not set and no default is
|
|
389
|
+
provided.
|
|
390
|
+
|
|
391
|
+
Returns:
|
|
392
|
+
The value from the environment.
|
|
393
|
+
"""
|
|
388
394
|
if isinstance(key, (list, tuple)):
|
|
389
395
|
for k in key:
|
|
390
396
|
if k in os.environ:
|
|
@@ -407,7 +413,7 @@ def from_env(
|
|
|
407
413
|
|
|
408
414
|
|
|
409
415
|
@overload
|
|
410
|
-
def secret_from_env(key:
|
|
416
|
+
def secret_from_env(key: str | Sequence[str], /) -> Callable[[], SecretStr]: ...
|
|
411
417
|
|
|
412
418
|
|
|
413
419
|
@overload
|
|
@@ -416,8 +422,8 @@ def secret_from_env(key: str, /, *, default: str) -> Callable[[], SecretStr]: ..
|
|
|
416
422
|
|
|
417
423
|
@overload
|
|
418
424
|
def secret_from_env(
|
|
419
|
-
key:
|
|
420
|
-
) -> Callable[[],
|
|
425
|
+
key: str | Sequence[str], /, *, default: None
|
|
426
|
+
) -> Callable[[], SecretStr | None]: ...
|
|
421
427
|
|
|
422
428
|
|
|
423
429
|
@overload
|
|
@@ -425,12 +431,12 @@ def secret_from_env(key: str, /, *, error_message: str) -> Callable[[], SecretSt
|
|
|
425
431
|
|
|
426
432
|
|
|
427
433
|
def secret_from_env(
|
|
428
|
-
key:
|
|
434
|
+
key: str | Sequence[str],
|
|
429
435
|
/,
|
|
430
436
|
*,
|
|
431
|
-
default:
|
|
432
|
-
error_message:
|
|
433
|
-
) ->
|
|
437
|
+
default: str | _NoDefaultType | None = _NoDefault,
|
|
438
|
+
error_message: str | None = None,
|
|
439
|
+
) -> Callable[[], SecretStr | None] | Callable[[], SecretStr]:
|
|
434
440
|
"""Secret from env.
|
|
435
441
|
|
|
436
442
|
Args:
|
|
@@ -444,8 +450,16 @@ def secret_from_env(
|
|
|
444
450
|
factory method that will look up the secret from the environment.
|
|
445
451
|
"""
|
|
446
452
|
|
|
447
|
-
def get_secret_from_env() ->
|
|
448
|
-
"""Get a value from an environment variable.
|
|
453
|
+
def get_secret_from_env() -> SecretStr | None:
|
|
454
|
+
"""Get a value from an environment variable.
|
|
455
|
+
|
|
456
|
+
Raises:
|
|
457
|
+
ValueError: If the environment variable is not set and no default is
|
|
458
|
+
provided.
|
|
459
|
+
|
|
460
|
+
Returns:
|
|
461
|
+
The secret from the environment.
|
|
462
|
+
"""
|
|
449
463
|
if isinstance(key, (list, tuple)):
|
|
450
464
|
for k in key:
|
|
451
465
|
if k in os.environ:
|
|
@@ -466,3 +480,31 @@ def secret_from_env(
|
|
|
466
480
|
raise ValueError(msg)
|
|
467
481
|
|
|
468
482
|
return get_secret_from_env
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
LC_AUTO_PREFIX = "lc_"
|
|
486
|
+
"""LangChain auto-generated ID prefix for messages and content blocks."""
|
|
487
|
+
|
|
488
|
+
LC_ID_PREFIX = "lc_run-"
|
|
489
|
+
"""Internal tracing/callback system identifier.
|
|
490
|
+
|
|
491
|
+
Used for:
|
|
492
|
+
- Tracing. Every LangChain operation (LLM call, chain execution, tool use, etc.)
|
|
493
|
+
gets a unique run_id (UUID)
|
|
494
|
+
- Enables tracking parent-child relationships between operations
|
|
495
|
+
"""
|
|
496
|
+
|
|
497
|
+
|
|
498
|
+
def ensure_id(id_val: str | None) -> str:
|
|
499
|
+
"""Ensure the ID is a valid string, generating a new UUID if not provided.
|
|
500
|
+
|
|
501
|
+
Auto-generated UUIDs are prefixed by `'lc_'` to indicate they are
|
|
502
|
+
LangChain-generated IDs.
|
|
503
|
+
|
|
504
|
+
Args:
|
|
505
|
+
id_val: Optional string ID value to validate.
|
|
506
|
+
|
|
507
|
+
Returns:
|
|
508
|
+
A string ID, either the validated provided value or a newly generated UUID4.
|
|
509
|
+
"""
|
|
510
|
+
return id_val or f"{LC_AUTO_PREFIX}{uuid4()}"
|