langchain-core 1.0.0rc3__py3-none-any.whl → 1.0.2__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/agents.py +2 -4
- langchain_core/caches.py +16 -7
- langchain_core/callbacks/base.py +0 -4
- langchain_core/callbacks/manager.py +0 -11
- langchain_core/chat_history.py +5 -5
- langchain_core/document_loaders/base.py +6 -4
- langchain_core/document_loaders/blob_loaders.py +1 -1
- langchain_core/document_loaders/langsmith.py +9 -13
- langchain_core/documents/__init__.py +24 -3
- langchain_core/documents/base.py +72 -61
- langchain_core/documents/compressor.py +6 -6
- langchain_core/documents/transformers.py +6 -6
- langchain_core/embeddings/fake.py +2 -2
- langchain_core/example_selectors/semantic_similarity.py +7 -7
- langchain_core/exceptions.py +2 -2
- langchain_core/indexing/__init__.py +1 -1
- langchain_core/indexing/api.py +62 -62
- langchain_core/indexing/base.py +20 -22
- langchain_core/indexing/in_memory.py +2 -4
- langchain_core/language_models/__init__.py +6 -5
- langchain_core/language_models/base.py +7 -8
- langchain_core/language_models/chat_models.py +84 -78
- langchain_core/language_models/fake_chat_models.py +1 -1
- langchain_core/language_models/llms.py +20 -18
- langchain_core/load/dump.py +6 -8
- langchain_core/load/serializable.py +4 -1
- langchain_core/messages/__init__.py +9 -0
- langchain_core/messages/ai.py +11 -7
- langchain_core/messages/base.py +4 -0
- langchain_core/messages/block_translators/google_genai.py +5 -3
- langchain_core/messages/content.py +4 -4
- langchain_core/messages/utils.py +17 -17
- langchain_core/output_parsers/__init__.py +17 -1
- langchain_core/output_parsers/base.py +3 -0
- langchain_core/output_parsers/format_instructions.py +9 -4
- langchain_core/output_parsers/json.py +5 -2
- langchain_core/output_parsers/list.py +16 -16
- langchain_core/output_parsers/openai_tools.py +2 -2
- langchain_core/output_parsers/pydantic.py +1 -1
- langchain_core/output_parsers/string.py +3 -3
- langchain_core/output_parsers/xml.py +28 -25
- langchain_core/outputs/generation.py +2 -3
- langchain_core/prompt_values.py +0 -6
- langchain_core/prompts/base.py +5 -3
- langchain_core/prompts/chat.py +60 -52
- langchain_core/prompts/string.py +5 -2
- langchain_core/prompts/structured.py +12 -8
- langchain_core/rate_limiters.py +1 -3
- langchain_core/retrievers.py +41 -37
- langchain_core/runnables/base.py +25 -29
- langchain_core/runnables/branch.py +9 -9
- langchain_core/runnables/config.py +2 -4
- langchain_core/runnables/configurable.py +3 -3
- langchain_core/runnables/fallbacks.py +1 -1
- langchain_core/runnables/graph.py +7 -3
- langchain_core/runnables/retry.py +1 -1
- langchain_core/runnables/schema.py +2 -5
- langchain_core/runnables/utils.py +3 -3
- langchain_core/stores.py +4 -6
- langchain_core/tools/base.py +68 -14
- langchain_core/tools/convert.py +8 -7
- langchain_core/tools/retriever.py +6 -5
- langchain_core/tools/structured.py +7 -5
- langchain_core/tracers/event_stream.py +4 -1
- langchain_core/tracers/log_stream.py +6 -3
- langchain_core/utils/function_calling.py +8 -0
- langchain_core/utils/json_schema.py +1 -1
- langchain_core/utils/strings.py +1 -4
- langchain_core/utils/utils.py +12 -5
- langchain_core/vectorstores/base.py +130 -130
- langchain_core/vectorstores/in_memory.py +4 -4
- langchain_core/vectorstores/utils.py +1 -1
- langchain_core/version.py +1 -1
- {langchain_core-1.0.0rc3.dist-info → langchain_core-1.0.2.dist-info}/METADATA +8 -7
- {langchain_core-1.0.0rc3.dist-info → langchain_core-1.0.2.dist-info}/RECORD +76 -76
- {langchain_core-1.0.0rc3.dist-info → langchain_core-1.0.2.dist-info}/WHEEL +0 -0
langchain_core/tools/base.py
CHANGED
|
@@ -483,7 +483,7 @@ class ChildTool(BaseTool):
|
|
|
483
483
|
"""The tool response format.
|
|
484
484
|
|
|
485
485
|
If `"content"` then the output of the tool is interpreted as the contents of a
|
|
486
|
-
ToolMessage
|
|
486
|
+
`ToolMessage`. If `"content_and_artifact"` then the output is expected to be a
|
|
487
487
|
two-tuple corresponding to the (content, artifact) of a `ToolMessage`.
|
|
488
488
|
"""
|
|
489
489
|
|
|
@@ -615,7 +615,7 @@ class ChildTool(BaseTool):
|
|
|
615
615
|
The parsed and validated input.
|
|
616
616
|
|
|
617
617
|
Raises:
|
|
618
|
-
ValueError: If string input is provided with JSON schema `args_schema`.
|
|
618
|
+
ValueError: If `string` input is provided with JSON schema `args_schema`.
|
|
619
619
|
ValueError: If InjectedToolCallId is required but `tool_call_id` is not
|
|
620
620
|
provided.
|
|
621
621
|
TypeError: If args_schema is not a Pydantic `BaseModel` or dict.
|
|
@@ -707,6 +707,35 @@ class ChildTool(BaseTool):
|
|
|
707
707
|
kwargs["run_manager"] = kwargs["run_manager"].get_sync()
|
|
708
708
|
return await run_in_executor(None, self._run, *args, **kwargs)
|
|
709
709
|
|
|
710
|
+
def _filter_injected_args(self, tool_input: dict) -> dict:
|
|
711
|
+
"""Filter out injected tool arguments from the input dictionary.
|
|
712
|
+
|
|
713
|
+
Injected arguments are those annotated with InjectedToolArg or its
|
|
714
|
+
subclasses, or arguments in FILTERED_ARGS like run_manager and callbacks.
|
|
715
|
+
|
|
716
|
+
Args:
|
|
717
|
+
tool_input: The tool input dictionary to filter.
|
|
718
|
+
|
|
719
|
+
Returns:
|
|
720
|
+
A filtered dictionary with injected arguments removed.
|
|
721
|
+
"""
|
|
722
|
+
# Start with filtered args from the constant
|
|
723
|
+
filtered_keys = set[str](FILTERED_ARGS)
|
|
724
|
+
|
|
725
|
+
# If we have an args_schema, use it to identify injected args
|
|
726
|
+
if self.args_schema is not None:
|
|
727
|
+
try:
|
|
728
|
+
annotations = get_all_basemodel_annotations(self.args_schema)
|
|
729
|
+
for field_name, field_type in annotations.items():
|
|
730
|
+
if _is_injected_arg_type(field_type):
|
|
731
|
+
filtered_keys.add(field_name)
|
|
732
|
+
except Exception: # noqa: S110
|
|
733
|
+
# If we can't get annotations, just use FILTERED_ARGS
|
|
734
|
+
pass
|
|
735
|
+
|
|
736
|
+
# Filter out the injected keys from tool_input
|
|
737
|
+
return {k: v for k, v in tool_input.items() if k not in filtered_keys}
|
|
738
|
+
|
|
710
739
|
def _to_args_and_kwargs(
|
|
711
740
|
self, tool_input: str | dict, tool_call_id: str | None
|
|
712
741
|
) -> tuple[tuple, dict]:
|
|
@@ -794,17 +823,29 @@ class ChildTool(BaseTool):
|
|
|
794
823
|
self.metadata,
|
|
795
824
|
)
|
|
796
825
|
|
|
826
|
+
# Filter out injected arguments from callback inputs
|
|
827
|
+
filtered_tool_input = (
|
|
828
|
+
self._filter_injected_args(tool_input)
|
|
829
|
+
if isinstance(tool_input, dict)
|
|
830
|
+
else None
|
|
831
|
+
)
|
|
832
|
+
|
|
833
|
+
# Use filtered inputs for the input_str parameter as well
|
|
834
|
+
tool_input_str = (
|
|
835
|
+
tool_input
|
|
836
|
+
if isinstance(tool_input, str)
|
|
837
|
+
else str(
|
|
838
|
+
filtered_tool_input if filtered_tool_input is not None else tool_input
|
|
839
|
+
)
|
|
840
|
+
)
|
|
841
|
+
|
|
797
842
|
run_manager = callback_manager.on_tool_start(
|
|
798
843
|
{"name": self.name, "description": self.description},
|
|
799
|
-
|
|
844
|
+
tool_input_str,
|
|
800
845
|
color=start_color,
|
|
801
846
|
name=run_name,
|
|
802
847
|
run_id=run_id,
|
|
803
|
-
|
|
804
|
-
# For now, it's unclear whether this assumption is ever violated,
|
|
805
|
-
# but if it is we will send a `None` value to the callback instead
|
|
806
|
-
# TODO: will need to address issue via a patch.
|
|
807
|
-
inputs=tool_input if isinstance(tool_input, dict) else None,
|
|
848
|
+
inputs=filtered_tool_input,
|
|
808
849
|
**kwargs,
|
|
809
850
|
)
|
|
810
851
|
|
|
@@ -905,17 +946,30 @@ class ChildTool(BaseTool):
|
|
|
905
946
|
metadata,
|
|
906
947
|
self.metadata,
|
|
907
948
|
)
|
|
949
|
+
|
|
950
|
+
# Filter out injected arguments from callback inputs
|
|
951
|
+
filtered_tool_input = (
|
|
952
|
+
self._filter_injected_args(tool_input)
|
|
953
|
+
if isinstance(tool_input, dict)
|
|
954
|
+
else None
|
|
955
|
+
)
|
|
956
|
+
|
|
957
|
+
# Use filtered inputs for the input_str parameter as well
|
|
958
|
+
tool_input_str = (
|
|
959
|
+
tool_input
|
|
960
|
+
if isinstance(tool_input, str)
|
|
961
|
+
else str(
|
|
962
|
+
filtered_tool_input if filtered_tool_input is not None else tool_input
|
|
963
|
+
)
|
|
964
|
+
)
|
|
965
|
+
|
|
908
966
|
run_manager = await callback_manager.on_tool_start(
|
|
909
967
|
{"name": self.name, "description": self.description},
|
|
910
|
-
|
|
968
|
+
tool_input_str,
|
|
911
969
|
color=start_color,
|
|
912
970
|
name=run_name,
|
|
913
971
|
run_id=run_id,
|
|
914
|
-
|
|
915
|
-
# For now, it's unclear whether this assumption is ever violated,
|
|
916
|
-
# but if it is we will send a `None` value to the callback instead
|
|
917
|
-
# TODO: will need to address issue via a patch.
|
|
918
|
-
inputs=tool_input if isinstance(tool_input, dict) else None,
|
|
972
|
+
inputs=filtered_tool_input,
|
|
919
973
|
**kwargs,
|
|
920
974
|
)
|
|
921
975
|
content = None
|
langchain_core/tools/convert.py
CHANGED
|
@@ -89,6 +89,7 @@ def tool(
|
|
|
89
89
|
runnable: Optional runnable to convert to a tool. Must be provided as a
|
|
90
90
|
positional argument.
|
|
91
91
|
description: Optional description for the tool.
|
|
92
|
+
|
|
92
93
|
Precedence for the tool description value is as follows:
|
|
93
94
|
|
|
94
95
|
- `description` argument
|
|
@@ -105,11 +106,13 @@ def tool(
|
|
|
105
106
|
infer_schema: Whether to infer the schema of the arguments from
|
|
106
107
|
the function's signature. This also makes the resultant tool
|
|
107
108
|
accept a dictionary input to its `run()` function.
|
|
108
|
-
response_format: The tool response format.
|
|
109
|
-
|
|
110
|
-
`"
|
|
111
|
-
|
|
112
|
-
|
|
109
|
+
response_format: The tool response format.
|
|
110
|
+
|
|
111
|
+
If `"content"` then the output of the tool is interpreted as the contents of
|
|
112
|
+
a `ToolMessage`. If `"content_and_artifact"` then the output is expected to
|
|
113
|
+
be a two-tuple corresponding to the `(content, artifact)` of a
|
|
114
|
+
`ToolMessage`.
|
|
115
|
+
parse_docstring: If `infer_schema` and `parse_docstring`, will attempt to
|
|
113
116
|
parse parameter descriptions from Google Style function docstrings.
|
|
114
117
|
error_on_invalid_docstring: if `parse_docstring` is provided, configure
|
|
115
118
|
whether to raise `ValueError` on invalid Google Style docstrings.
|
|
@@ -151,8 +154,6 @@ def tool(
|
|
|
151
154
|
return "partial json of results", {"full": "object of results"}
|
|
152
155
|
```
|
|
153
156
|
|
|
154
|
-
!!! version-added "Added in version 0.2.14"
|
|
155
|
-
|
|
156
157
|
Parse Google-style docstrings:
|
|
157
158
|
|
|
158
159
|
```python
|
|
@@ -83,11 +83,12 @@ def create_retriever_tool(
|
|
|
83
83
|
model, so should be descriptive.
|
|
84
84
|
document_prompt: The prompt to use for the document.
|
|
85
85
|
document_separator: The separator to use between documents.
|
|
86
|
-
response_format: The tool response format.
|
|
87
|
-
|
|
88
|
-
`"
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
response_format: The tool response format.
|
|
87
|
+
|
|
88
|
+
If `"content"` then the output of the tool is interpreted as the contents of
|
|
89
|
+
a `ToolMessage`. If `"content_and_artifact"` then the output is expected to
|
|
90
|
+
be a two-tuple corresponding to the `(content, artifact)` of a `ToolMessage`
|
|
91
|
+
(artifact being a list of documents in this case).
|
|
91
92
|
|
|
92
93
|
Returns:
|
|
93
94
|
Tool class to pass to an agent.
|
|
@@ -151,11 +151,13 @@ class StructuredTool(BaseTool):
|
|
|
151
151
|
return_direct: Whether to return the result directly or as a callback.
|
|
152
152
|
args_schema: The schema of the tool's input arguments.
|
|
153
153
|
infer_schema: Whether to infer the schema from the function's signature.
|
|
154
|
-
response_format: The tool response format.
|
|
155
|
-
|
|
156
|
-
`"
|
|
157
|
-
|
|
158
|
-
|
|
154
|
+
response_format: The tool response format.
|
|
155
|
+
|
|
156
|
+
If `"content"` then the output of the tool is interpreted as the
|
|
157
|
+
contents of a `ToolMessage`. If `"content_and_artifact"` then the output
|
|
158
|
+
is expected to be a two-tuple corresponding to the `(content, artifact)`
|
|
159
|
+
of a `ToolMessage`.
|
|
160
|
+
parse_docstring: If `infer_schema` and `parse_docstring`, will attempt
|
|
159
161
|
to parse parameter descriptions from Google Style function docstrings.
|
|
160
162
|
error_on_invalid_docstring: if `parse_docstring` is provided, configure
|
|
161
163
|
whether to raise `ValueError` on invalid Google Style docstrings.
|
|
@@ -128,7 +128,10 @@ class _AstreamEventsCallbackHandler(AsyncCallbackHandler, _StreamingCallbackHand
|
|
|
128
128
|
exclude_tags=exclude_tags,
|
|
129
129
|
)
|
|
130
130
|
|
|
131
|
-
|
|
131
|
+
try:
|
|
132
|
+
loop = asyncio.get_event_loop()
|
|
133
|
+
except RuntimeError:
|
|
134
|
+
loop = asyncio.new_event_loop()
|
|
132
135
|
memory_stream = _MemoryStream[StreamEvent](loop)
|
|
133
136
|
self.send_stream = memory_stream.get_send_stream()
|
|
134
137
|
self.receive_stream = memory_stream.get_receive_stream()
|
|
@@ -96,10 +96,10 @@ class RunLogPatch:
|
|
|
96
96
|
"""Patch to the run log."""
|
|
97
97
|
|
|
98
98
|
ops: list[dict[str, Any]]
|
|
99
|
-
"""List of
|
|
99
|
+
"""List of JSONPatch operations, which describe how to create the run state
|
|
100
100
|
from an empty dict. This is the minimal representation of the log, designed to
|
|
101
101
|
be serialized as JSON and sent over the wire to reconstruct the log on the other
|
|
102
|
-
side. Reconstruction of the state can be done with any
|
|
102
|
+
side. Reconstruction of the state can be done with any JSONPatch-compliant library,
|
|
103
103
|
see https://jsonpatch.com for more information."""
|
|
104
104
|
|
|
105
105
|
def __init__(self, *ops: dict[str, Any]) -> None:
|
|
@@ -264,7 +264,10 @@ class LogStreamCallbackHandler(BaseTracer, _StreamingCallbackHandler):
|
|
|
264
264
|
self.exclude_types = exclude_types
|
|
265
265
|
self.exclude_tags = exclude_tags
|
|
266
266
|
|
|
267
|
-
|
|
267
|
+
try:
|
|
268
|
+
loop = asyncio.get_event_loop()
|
|
269
|
+
except RuntimeError:
|
|
270
|
+
loop = asyncio.new_event_loop()
|
|
268
271
|
memory_stream = _MemoryStream[RunLogPatch](loop)
|
|
269
272
|
self.lock = threading.Lock()
|
|
270
273
|
self.send_stream = memory_stream.get_send_stream()
|
|
@@ -425,6 +425,14 @@ def convert_to_openai_function(
|
|
|
425
425
|
oai_function["parameters"] = _recursive_set_additional_properties_false(
|
|
426
426
|
oai_function["parameters"]
|
|
427
427
|
)
|
|
428
|
+
# All fields must be `required`
|
|
429
|
+
parameters = oai_function.get("parameters")
|
|
430
|
+
if isinstance(parameters, dict):
|
|
431
|
+
fields = parameters.get("properties")
|
|
432
|
+
if isinstance(fields, dict) and fields:
|
|
433
|
+
parameters = dict(parameters)
|
|
434
|
+
parameters["required"] = list(fields.keys())
|
|
435
|
+
oai_function["parameters"] = parameters
|
|
428
436
|
return oai_function
|
|
429
437
|
|
|
430
438
|
|
|
@@ -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/strings.py
CHANGED
|
@@ -30,10 +30,7 @@ def stringify_dict(data: dict) -> str:
|
|
|
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:
|
langchain_core/utils/utils.py
CHANGED
|
@@ -218,7 +218,7 @@ def _build_model_kwargs(
|
|
|
218
218
|
values: dict[str, Any],
|
|
219
219
|
all_required_field_names: set[str],
|
|
220
220
|
) -> dict[str, Any]:
|
|
221
|
-
"""Build
|
|
221
|
+
"""Build `model_kwargs` param from Pydantic constructor values.
|
|
222
222
|
|
|
223
223
|
Args:
|
|
224
224
|
values: All init args passed in by user.
|
|
@@ -228,8 +228,8 @@ def _build_model_kwargs(
|
|
|
228
228
|
Extra kwargs.
|
|
229
229
|
|
|
230
230
|
Raises:
|
|
231
|
-
ValueError: If a field is specified in both values and extra_kwargs
|
|
232
|
-
ValueError: If a field is specified in model_kwargs
|
|
231
|
+
ValueError: If a field is specified in both `values` and `extra_kwargs`.
|
|
232
|
+
ValueError: If a field is specified in `model_kwargs`.
|
|
233
233
|
"""
|
|
234
234
|
extra_kwargs = values.get("model_kwargs", {})
|
|
235
235
|
for field_name in list(values):
|
|
@@ -267,6 +267,10 @@ def build_extra_kwargs(
|
|
|
267
267
|
) -> dict[str, Any]:
|
|
268
268
|
"""Build extra kwargs from values and extra_kwargs.
|
|
269
269
|
|
|
270
|
+
!!! danger "DON'T USE"
|
|
271
|
+
Kept for backwards-compatibility but should never have been public. Use the
|
|
272
|
+
internal `_build_model_kwargs` function instead.
|
|
273
|
+
|
|
270
274
|
Args:
|
|
271
275
|
extra_kwargs: Extra kwargs passed in by user.
|
|
272
276
|
values: Values passed in by user.
|
|
@@ -276,9 +280,10 @@ def build_extra_kwargs(
|
|
|
276
280
|
Extra kwargs.
|
|
277
281
|
|
|
278
282
|
Raises:
|
|
279
|
-
ValueError: If a field is specified in both values and extra_kwargs
|
|
280
|
-
ValueError: If a field is specified in model_kwargs
|
|
283
|
+
ValueError: If a field is specified in both `values` and `extra_kwargs`.
|
|
284
|
+
ValueError: If a field is specified in `model_kwargs`.
|
|
281
285
|
"""
|
|
286
|
+
# DON'T USE! Kept for backwards-compatibility but should never have been public.
|
|
282
287
|
for field_name in list(values):
|
|
283
288
|
if field_name in extra_kwargs:
|
|
284
289
|
msg = f"Found {field_name} supplied twice."
|
|
@@ -292,6 +297,7 @@ def build_extra_kwargs(
|
|
|
292
297
|
)
|
|
293
298
|
extra_kwargs[field_name] = values.pop(field_name)
|
|
294
299
|
|
|
300
|
+
# DON'T USE! Kept for backwards-compatibility but should never have been public.
|
|
295
301
|
invalid_model_kwargs = all_required_field_names.intersection(extra_kwargs.keys())
|
|
296
302
|
if invalid_model_kwargs:
|
|
297
303
|
msg = (
|
|
@@ -300,6 +306,7 @@ def build_extra_kwargs(
|
|
|
300
306
|
)
|
|
301
307
|
raise ValueError(msg)
|
|
302
308
|
|
|
309
|
+
# DON'T USE! Kept for backwards-compatibility but should never have been public.
|
|
303
310
|
return extra_kwargs
|
|
304
311
|
|
|
305
312
|
|