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.

Files changed (76) hide show
  1. langchain_core/agents.py +2 -4
  2. langchain_core/caches.py +16 -7
  3. langchain_core/callbacks/base.py +0 -4
  4. langchain_core/callbacks/manager.py +0 -11
  5. langchain_core/chat_history.py +5 -5
  6. langchain_core/document_loaders/base.py +6 -4
  7. langchain_core/document_loaders/blob_loaders.py +1 -1
  8. langchain_core/document_loaders/langsmith.py +9 -13
  9. langchain_core/documents/__init__.py +24 -3
  10. langchain_core/documents/base.py +72 -61
  11. langchain_core/documents/compressor.py +6 -6
  12. langchain_core/documents/transformers.py +6 -6
  13. langchain_core/embeddings/fake.py +2 -2
  14. langchain_core/example_selectors/semantic_similarity.py +7 -7
  15. langchain_core/exceptions.py +2 -2
  16. langchain_core/indexing/__init__.py +1 -1
  17. langchain_core/indexing/api.py +62 -62
  18. langchain_core/indexing/base.py +20 -22
  19. langchain_core/indexing/in_memory.py +2 -4
  20. langchain_core/language_models/__init__.py +6 -5
  21. langchain_core/language_models/base.py +7 -8
  22. langchain_core/language_models/chat_models.py +84 -78
  23. langchain_core/language_models/fake_chat_models.py +1 -1
  24. langchain_core/language_models/llms.py +20 -18
  25. langchain_core/load/dump.py +6 -8
  26. langchain_core/load/serializable.py +4 -1
  27. langchain_core/messages/__init__.py +9 -0
  28. langchain_core/messages/ai.py +11 -7
  29. langchain_core/messages/base.py +4 -0
  30. langchain_core/messages/block_translators/google_genai.py +5 -3
  31. langchain_core/messages/content.py +4 -4
  32. langchain_core/messages/utils.py +17 -17
  33. langchain_core/output_parsers/__init__.py +17 -1
  34. langchain_core/output_parsers/base.py +3 -0
  35. langchain_core/output_parsers/format_instructions.py +9 -4
  36. langchain_core/output_parsers/json.py +5 -2
  37. langchain_core/output_parsers/list.py +16 -16
  38. langchain_core/output_parsers/openai_tools.py +2 -2
  39. langchain_core/output_parsers/pydantic.py +1 -1
  40. langchain_core/output_parsers/string.py +3 -3
  41. langchain_core/output_parsers/xml.py +28 -25
  42. langchain_core/outputs/generation.py +2 -3
  43. langchain_core/prompt_values.py +0 -6
  44. langchain_core/prompts/base.py +5 -3
  45. langchain_core/prompts/chat.py +60 -52
  46. langchain_core/prompts/string.py +5 -2
  47. langchain_core/prompts/structured.py +12 -8
  48. langchain_core/rate_limiters.py +1 -3
  49. langchain_core/retrievers.py +41 -37
  50. langchain_core/runnables/base.py +25 -29
  51. langchain_core/runnables/branch.py +9 -9
  52. langchain_core/runnables/config.py +2 -4
  53. langchain_core/runnables/configurable.py +3 -3
  54. langchain_core/runnables/fallbacks.py +1 -1
  55. langchain_core/runnables/graph.py +7 -3
  56. langchain_core/runnables/retry.py +1 -1
  57. langchain_core/runnables/schema.py +2 -5
  58. langchain_core/runnables/utils.py +3 -3
  59. langchain_core/stores.py +4 -6
  60. langchain_core/tools/base.py +68 -14
  61. langchain_core/tools/convert.py +8 -7
  62. langchain_core/tools/retriever.py +6 -5
  63. langchain_core/tools/structured.py +7 -5
  64. langchain_core/tracers/event_stream.py +4 -1
  65. langchain_core/tracers/log_stream.py +6 -3
  66. langchain_core/utils/function_calling.py +8 -0
  67. langchain_core/utils/json_schema.py +1 -1
  68. langchain_core/utils/strings.py +1 -4
  69. langchain_core/utils/utils.py +12 -5
  70. langchain_core/vectorstores/base.py +130 -130
  71. langchain_core/vectorstores/in_memory.py +4 -4
  72. langchain_core/vectorstores/utils.py +1 -1
  73. langchain_core/version.py +1 -1
  74. {langchain_core-1.0.0rc3.dist-info → langchain_core-1.0.2.dist-info}/METADATA +8 -7
  75. {langchain_core-1.0.0rc3.dist-info → langchain_core-1.0.2.dist-info}/RECORD +76 -76
  76. {langchain_core-1.0.0rc3.dist-info → langchain_core-1.0.2.dist-info}/WHEEL +0 -0
@@ -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. If `"content_and_artifact"` then the output is expected to be a
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
- tool_input if isinstance(tool_input, str) else str(tool_input),
844
+ tool_input_str,
800
845
  color=start_color,
801
846
  name=run_name,
802
847
  run_id=run_id,
803
- # Inputs by definition should always be dicts.
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
- tool_input if isinstance(tool_input, str) else str(tool_input),
968
+ tool_input_str,
911
969
  color=start_color,
912
970
  name=run_name,
913
971
  run_id=run_id,
914
- # Inputs by definition should always be dicts.
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
@@ -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. If `"content"` then the output of
109
- the tool is interpreted as the contents of a `ToolMessage`. If
110
- `"content_and_artifact"` then the output is expected to be a two-tuple
111
- corresponding to the `(content, artifact)` of a `ToolMessage`.
112
- parse_docstring: if `infer_schema` and `parse_docstring`, will attempt to
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. If `"content"` then the output of
87
- the tool is interpreted as the contents of a `ToolMessage`. If
88
- `"content_and_artifact"` then the output is expected to be a two-tuple
89
- corresponding to the `(content, artifact)` of a `ToolMessage` (artifact
90
- being a list of documents in this case).
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. If `"content"` then the output of
155
- the tool is interpreted as the contents of a `ToolMessage`. If
156
- `"content_and_artifact"` then the output is expected to be a two-tuple
157
- corresponding to the `(content, artifact)` of a `ToolMessage`.
158
- parse_docstring: if `infer_schema` and `parse_docstring`, will attempt
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
- loop = asyncio.get_event_loop()
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 jsonpatch operations, which describe how to create the run state
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 jsonpatch-compliant library,
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
- loop = asyncio.get_event_loop()
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
- Note:
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
@@ -30,10 +30,7 @@ def stringify_dict(data: dict) -> str:
30
30
  Returns:
31
31
  The stringified dictionary.
32
32
  """
33
- text = ""
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:
@@ -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 "model_kwargs" param from Pydantic constructor values.
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