langchain-core 0.3.68__py3-none-any.whl → 0.3.70__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 (60) hide show
  1. langchain_core/_api/deprecation.py +3 -3
  2. langchain_core/_import_utils.py +2 -2
  3. langchain_core/caches.py +1 -1
  4. langchain_core/callbacks/manager.py +2 -2
  5. langchain_core/chat_history.py +20 -16
  6. langchain_core/document_loaders/base.py +3 -3
  7. langchain_core/documents/base.py +3 -3
  8. langchain_core/indexing/api.py +6 -6
  9. langchain_core/language_models/_utils.py +1 -1
  10. langchain_core/language_models/base.py +1 -1
  11. langchain_core/language_models/chat_models.py +8 -8
  12. langchain_core/language_models/fake_chat_models.py +6 -2
  13. langchain_core/language_models/llms.py +23 -26
  14. langchain_core/load/load.py +23 -2
  15. langchain_core/load/serializable.py +4 -4
  16. langchain_core/messages/tool.py +1 -3
  17. langchain_core/messages/utils.py +29 -32
  18. langchain_core/output_parsers/base.py +1 -1
  19. langchain_core/output_parsers/openai_functions.py +7 -7
  20. langchain_core/output_parsers/openai_tools.py +38 -8
  21. langchain_core/output_parsers/xml.py +7 -7
  22. langchain_core/outputs/__init__.py +8 -9
  23. langchain_core/outputs/chat_generation.py +5 -3
  24. langchain_core/outputs/generation.py +2 -1
  25. langchain_core/outputs/llm_result.py +14 -14
  26. langchain_core/prompts/base.py +5 -5
  27. langchain_core/prompts/chat.py +22 -21
  28. langchain_core/prompts/dict.py +0 -2
  29. langchain_core/prompts/pipeline.py +13 -15
  30. langchain_core/prompts/prompt.py +4 -4
  31. langchain_core/prompts/string.py +4 -4
  32. langchain_core/rate_limiters.py +2 -3
  33. langchain_core/retrievers.py +6 -6
  34. langchain_core/runnables/base.py +21 -18
  35. langchain_core/runnables/branch.py +3 -3
  36. langchain_core/runnables/graph.py +1 -1
  37. langchain_core/runnables/history.py +3 -3
  38. langchain_core/runnables/router.py +1 -2
  39. langchain_core/runnables/utils.py +1 -1
  40. langchain_core/stores.py +1 -1
  41. langchain_core/sys_info.py +2 -2
  42. langchain_core/tools/base.py +7 -7
  43. langchain_core/tools/structured.py +8 -1
  44. langchain_core/tracers/core.py +4 -4
  45. langchain_core/tracers/event_stream.py +5 -5
  46. langchain_core/tracers/log_stream.py +5 -1
  47. langchain_core/utils/_merge.py +2 -0
  48. langchain_core/utils/env.py +2 -2
  49. langchain_core/utils/function_calling.py +4 -6
  50. langchain_core/utils/image.py +1 -1
  51. langchain_core/utils/json_schema.py +64 -59
  52. langchain_core/utils/mustache.py +9 -4
  53. langchain_core/vectorstores/base.py +10 -10
  54. langchain_core/vectorstores/in_memory.py +5 -5
  55. langchain_core/vectorstores/utils.py +21 -0
  56. langchain_core/version.py +1 -1
  57. {langchain_core-0.3.68.dist-info → langchain_core-0.3.70.dist-info}/METADATA +2 -2
  58. {langchain_core-0.3.68.dist-info → langchain_core-0.3.70.dist-info}/RECORD +60 -60
  59. {langchain_core-0.3.68.dist-info → langchain_core-0.3.70.dist-info}/WHEEL +0 -0
  60. {langchain_core-0.3.68.dist-info → langchain_core-0.3.70.dist-info}/entry_points.txt +0 -0
@@ -18,16 +18,14 @@ def _get_inputs(inputs: dict, input_variables: list[str]) -> dict:
18
18
  since="0.3.22",
19
19
  removal="1.0",
20
20
  message=(
21
- "This class is deprecated. Please see the docstring below or at the link"
22
- " for a replacement option: "
23
- "https://python.langchain.com/api_reference/core/prompts/langchain_core.prompts.pipeline.PipelinePromptTemplate.html"
21
+ "This class is deprecated in favor of chaining individual prompts together."
24
22
  ),
25
23
  )
26
24
  class PipelinePromptTemplate(BasePromptTemplate):
27
- """[DEPRECATED] Pipeline prompt template.
25
+ """Pipeline prompt template.
28
26
 
29
27
  This has been deprecated in favor of chaining individual prompts together in your
30
- code. E.g. using a for loop, you could do:
28
+ code; e.g. using a for loop, you could do:
31
29
 
32
30
  .. code-block:: python
33
31
 
@@ -81,13 +79,13 @@ class PipelinePromptTemplate(BasePromptTemplate):
81
79
  A formatted string.
82
80
  """
83
81
  for k, prompt in self.pipeline_prompts:
84
- _inputs = _get_inputs(kwargs, prompt.input_variables)
82
+ inputs = _get_inputs(kwargs, prompt.input_variables)
85
83
  if isinstance(prompt, BaseChatPromptTemplate):
86
- kwargs[k] = prompt.format_messages(**_inputs)
84
+ kwargs[k] = prompt.format_messages(**inputs)
87
85
  else:
88
- kwargs[k] = prompt.format(**_inputs)
89
- _inputs = _get_inputs(kwargs, self.final_prompt.input_variables)
90
- return self.final_prompt.format_prompt(**_inputs)
86
+ kwargs[k] = prompt.format(**inputs)
87
+ inputs = _get_inputs(kwargs, self.final_prompt.input_variables)
88
+ return self.final_prompt.format_prompt(**inputs)
91
89
 
92
90
  async def aformat_prompt(self, **kwargs: Any) -> PromptValue:
93
91
  """Async format the prompt with the inputs.
@@ -99,13 +97,13 @@ class PipelinePromptTemplate(BasePromptTemplate):
99
97
  A formatted string.
100
98
  """
101
99
  for k, prompt in self.pipeline_prompts:
102
- _inputs = _get_inputs(kwargs, prompt.input_variables)
100
+ inputs = _get_inputs(kwargs, prompt.input_variables)
103
101
  if isinstance(prompt, BaseChatPromptTemplate):
104
- kwargs[k] = await prompt.aformat_messages(**_inputs)
102
+ kwargs[k] = await prompt.aformat_messages(**inputs)
105
103
  else:
106
- kwargs[k] = await prompt.aformat(**_inputs)
107
- _inputs = _get_inputs(kwargs, self.final_prompt.input_variables)
108
- return await self.final_prompt.aformat_prompt(**_inputs)
104
+ kwargs[k] = await prompt.aformat(**inputs)
105
+ inputs = _get_inputs(kwargs, self.final_prompt.input_variables)
106
+ return await self.final_prompt.aformat_prompt(**inputs)
109
107
 
110
108
  def format(self, **kwargs: Any) -> str:
111
109
  """Format the prompt with the inputs.
@@ -287,17 +287,17 @@ class PromptTemplate(StringPromptTemplate):
287
287
  The prompt template loaded from the template.
288
288
  """
289
289
  input_variables = get_template_variables(template, template_format)
290
- _partial_variables = partial_variables or {}
290
+ partial_variables_ = partial_variables or {}
291
291
 
292
- if _partial_variables:
292
+ if partial_variables_:
293
293
  input_variables = [
294
- var for var in input_variables if var not in _partial_variables
294
+ var for var in input_variables if var not in partial_variables_
295
295
  ]
296
296
 
297
297
  return cls(
298
298
  input_variables=input_variables,
299
299
  template=template,
300
300
  template_format=template_format,
301
- partial_variables=_partial_variables,
301
+ partial_variables=partial_variables_,
302
302
  **kwargs,
303
303
  )
@@ -131,12 +131,12 @@ def mustache_template_vars(
131
131
  if type_ == "end":
132
132
  section_depth -= 1
133
133
  elif (
134
- type_ in ("variable", "section", "inverted section", "no escape")
134
+ type_ in {"variable", "section", "inverted section", "no escape"}
135
135
  and key != "."
136
136
  and section_depth == 0
137
137
  ):
138
138
  variables.add(key.split(".")[0])
139
- if type_ in ("section", "inverted section"):
139
+ if type_ in {"section", "inverted section"}:
140
140
  section_depth += 1
141
141
  return variables
142
142
 
@@ -164,11 +164,11 @@ def mustache_schema(
164
164
  if type_ == "end":
165
165
  if section_stack:
166
166
  prefix = section_stack.pop()
167
- elif type_ in ("section", "inverted section"):
167
+ elif type_ in {"section", "inverted section"}:
168
168
  section_stack.append(prefix)
169
169
  prefix = prefix + tuple(key.split("."))
170
170
  fields[prefix] = False
171
- elif type_ in ("variable", "no escape"):
171
+ elif type_ in {"variable", "no escape"}:
172
172
  fields[prefix + tuple(key.split("."))] = True
173
173
  defs: Defs = {} # None means leaf node
174
174
  while fields:
@@ -146,13 +146,12 @@ class InMemoryRateLimiter(BaseRateLimiter):
146
146
 
147
147
  Args:
148
148
  requests_per_second: The number of tokens to add per second to the bucket.
149
- Must be at least 1. The tokens represent "credit" that can be used
150
- to make requests.
149
+ The tokens represent "credit" that can be used to make requests.
151
150
  check_every_n_seconds: check whether the tokens are available
152
151
  every this many seconds. Can be a float to represent
153
152
  fractions of a second.
154
153
  max_bucket_size: The maximum number of tokens that can be in the bucket.
155
- This is used to prevent bursts of requests.
154
+ Must be at least 1. Used to prevent bursts of requests.
156
155
  """
157
156
  # Number of requests that we can make per second.
158
157
  self.requests_per_second = requests_per_second
@@ -254,13 +254,13 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
254
254
  run_id=kwargs.pop("run_id", None),
255
255
  )
256
256
  try:
257
- _kwargs = kwargs if self._expects_other_args else {}
257
+ kwargs_ = kwargs if self._expects_other_args else {}
258
258
  if self._new_arg_supported:
259
259
  result = self._get_relevant_documents(
260
- input, run_manager=run_manager, **_kwargs
260
+ input, run_manager=run_manager, **kwargs_
261
261
  )
262
262
  else:
263
- result = self._get_relevant_documents(input, **_kwargs)
263
+ result = self._get_relevant_documents(input, **kwargs_)
264
264
  except Exception as e:
265
265
  run_manager.on_retriever_error(e)
266
266
  raise
@@ -318,13 +318,13 @@ class BaseRetriever(RunnableSerializable[RetrieverInput, RetrieverOutput], ABC):
318
318
  run_id=kwargs.pop("run_id", None),
319
319
  )
320
320
  try:
321
- _kwargs = kwargs if self._expects_other_args else {}
321
+ kwargs_ = kwargs if self._expects_other_args else {}
322
322
  if self._new_arg_supported:
323
323
  result = await self._aget_relevant_documents(
324
- input, run_manager=run_manager, **_kwargs
324
+ input, run_manager=run_manager, **kwargs_
325
325
  )
326
326
  else:
327
- result = await self._aget_relevant_documents(input, **_kwargs)
327
+ result = await self._aget_relevant_documents(input, **kwargs_)
328
328
  except Exception as e:
329
329
  await run_manager.on_retriever_error(e)
330
330
  raise
@@ -108,7 +108,7 @@ if TYPE_CHECKING:
108
108
  Other = TypeVar("Other")
109
109
 
110
110
 
111
- class Runnable(Generic[Input, Output], ABC):
111
+ class Runnable(ABC, Generic[Input, Output]):
112
112
  """A unit of work that can be invoked, batched, streamed, transformed and composed.
113
113
 
114
114
  Key Methods
@@ -1160,22 +1160,21 @@ class Runnable(Generic[Input, Output], ABC):
1160
1160
 
1161
1161
  A StreamEvent is a dictionary with the following schema:
1162
1162
 
1163
- - ``event``: **str** - Event names are of the
1164
- format: on_[runnable_type]_(start|stream|end).
1163
+ - ``event``: **str** - Event names are of the format:
1164
+ on_[runnable_type]_(start|stream|end).
1165
1165
  - ``name``: **str** - The name of the Runnable that generated the event.
1166
- - ``run_id``: **str** - randomly generated ID associated with the given execution of
1167
- the Runnable that emitted the event.
1168
- A child Runnable that gets invoked as part of the execution of a
1169
- parent Runnable is assigned its own unique ID.
1170
- - ``parent_ids``: **list[str]** - The IDs of the parent runnables that
1171
- generated the event. The root Runnable will have an empty list.
1172
- The order of the parent IDs is from the root to the immediate parent.
1173
- Only available for v2 version of the API. The v1 version of the API
1174
- will return an empty list.
1166
+ - ``run_id``: **str** - randomly generated ID associated with the given
1167
+ execution of the Runnable that emitted the event. A child Runnable that gets
1168
+ invoked as part of the execution of a parent Runnable is assigned its own
1169
+ unique ID.
1170
+ - ``parent_ids``: **list[str]** - The IDs of the parent runnables that generated
1171
+ the event. The root Runnable will have an empty list. The order of the parent
1172
+ IDs is from the root to the immediate parent. Only available for v2 version of
1173
+ the API. The v1 version of the API will return an empty list.
1175
1174
  - ``tags``: **Optional[list[str]]** - The tags of the Runnable that generated
1176
- the event.
1177
- - ``metadata``: **Optional[dict[str, Any]]** - The metadata of the Runnable
1178
- that generated the event.
1175
+ the event.
1176
+ - ``metadata``: **Optional[dict[str, Any]]** - The metadata of the Runnable that
1177
+ generated the event.
1179
1178
  - ``data``: **dict[str, Any]**
1180
1179
 
1181
1180
 
@@ -1183,7 +1182,7 @@ class Runnable(Generic[Input, Output], ABC):
1183
1182
  chains. Metadata fields have been omitted from the table for brevity.
1184
1183
  Chain definitions have been included after the table.
1185
1184
 
1186
- **ATTENTION** This reference table is for the V2 version of the schema.
1185
+ .. NOTE:: This reference table is for the V2 version of the schema.
1187
1186
 
1188
1187
  +----------------------+------------------+---------------------------------+-----------------------------------------------+-------------------------------------------------+
1189
1188
  | event | name | chunk | input | output |
@@ -4205,6 +4204,8 @@ class RunnableGenerator(Runnable[Input, Output]):
4205
4204
  return False
4206
4205
  return False
4207
4206
 
4207
+ __hash__ = None # type: ignore[assignment]
4208
+
4208
4209
  @override
4209
4210
  def __repr__(self) -> str:
4210
4211
  return f"RunnableGenerator({self.name})"
@@ -4484,10 +4485,10 @@ class RunnableLambda(Runnable[Input, Output]):
4484
4485
  sig = inspect.signature(func)
4485
4486
  if sig.return_annotation != inspect.Signature.empty:
4486
4487
  # unwrap iterator types
4487
- if getattr(sig.return_annotation, "__origin__", None) in (
4488
+ if getattr(sig.return_annotation, "__origin__", None) in {
4488
4489
  collections.abc.Iterator,
4489
4490
  collections.abc.AsyncIterator,
4490
- ):
4491
+ }:
4491
4492
  return getattr(sig.return_annotation, "__args__", (Any,))[0]
4492
4493
  return sig.return_annotation
4493
4494
  except ValueError:
@@ -4588,6 +4589,8 @@ class RunnableLambda(Runnable[Input, Output]):
4588
4589
  return False
4589
4590
  return False
4590
4591
 
4592
+ __hash__ = None # type: ignore[assignment]
4593
+
4591
4594
  def __repr__(self) -> str:
4592
4595
  """A string representation of this Runnable."""
4593
4596
  if self._repr is None:
@@ -111,7 +111,7 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
111
111
  "Runnable[Input, Output]", coerce_to_runnable(cast("RunnableLike", default))
112
112
  )
113
113
 
114
- _branches = []
114
+ branches_ = []
115
115
 
116
116
  for branch in branches[:-1]:
117
117
  if not isinstance(branch, (tuple, list)):
@@ -130,10 +130,10 @@ class RunnableBranch(RunnableSerializable[Input, Output]):
130
130
  condition, runnable = branch
131
131
  condition = cast("Runnable[Input, bool]", coerce_to_runnable(condition))
132
132
  runnable = coerce_to_runnable(runnable)
133
- _branches.append((condition, runnable))
133
+ branches_.append((condition, runnable))
134
134
 
135
135
  super().__init__(
136
- branches=_branches,
136
+ branches=branches_,
137
137
  default=default_,
138
138
  ) # type: ignore[call-arg]
139
139
 
@@ -361,7 +361,7 @@ class Graph:
361
361
  """
362
362
  self.nodes.pop(node.id)
363
363
  self.edges = [
364
- edge for edge in self.edges if node.id not in (edge.source, edge.target)
364
+ edge for edge in self.edges if node.id not in {edge.source, edge.target}
365
365
  ]
366
366
 
367
367
  def add_edge(
@@ -339,10 +339,10 @@ class RunnableWithMessageHistory(RunnableBindingBase):
339
339
  ).with_config(run_name="RunnableWithMessageHistory")
340
340
 
341
341
  if history_factory_config:
342
- _config_specs = history_factory_config
342
+ config_specs = history_factory_config
343
343
  else:
344
344
  # If not provided, then we'll use the default session_id field
345
- _config_specs = [
345
+ config_specs = [
346
346
  ConfigurableFieldSpec(
347
347
  id="session_id",
348
348
  annotation=str,
@@ -359,7 +359,7 @@ class RunnableWithMessageHistory(RunnableBindingBase):
359
359
  output_messages_key=output_messages_key,
360
360
  bound=bound,
361
361
  history_messages_key=history_messages_key,
362
- history_factory_config=_config_specs,
362
+ history_factory_config=config_specs,
363
363
  **kwargs,
364
364
  )
365
365
  self._history_chain = history_chain
@@ -3,7 +3,6 @@
3
3
  from __future__ import annotations
4
4
 
5
5
  from collections.abc import Mapping
6
- from itertools import starmap
7
6
  from typing import (
8
7
  TYPE_CHECKING,
9
8
  Any,
@@ -206,7 +205,7 @@ class RouterRunnable(RunnableSerializable[RouterInput, Output]):
206
205
  configs = get_config_list(config, len(inputs))
207
206
  return await gather_with_concurrency(
208
207
  configs[0].get("max_concurrency"),
209
- *starmap(ainvoke, zip(runnables, actual_inputs, configs)),
208
+ *map(ainvoke, runnables, actual_inputs, configs),
210
209
  )
211
210
 
212
211
  @override
@@ -194,7 +194,7 @@ class IsLocalDict(ast.NodeVisitor):
194
194
  and isinstance(node.func.value, ast.Name)
195
195
  and node.func.value.id == self.name
196
196
  and node.func.attr == "get"
197
- and len(node.args) in (1, 2)
197
+ and len(node.args) in {1, 2}
198
198
  and isinstance(node.args[0], ast.Constant)
199
199
  and isinstance(node.args[0].value, str)
200
200
  ):
langchain_core/stores.py CHANGED
@@ -23,7 +23,7 @@ K = TypeVar("K")
23
23
  V = TypeVar("V")
24
24
 
25
25
 
26
- class BaseStore(Generic[K, V], ABC):
26
+ class BaseStore(ABC, Generic[K, V]):
27
27
  """Abstract interface for a key-value store.
28
28
 
29
29
  This is an interface that's meant to abstract away the details of
@@ -8,7 +8,7 @@ def _get_sub_deps(packages: Sequence[str]) -> list[str]:
8
8
  from importlib import metadata
9
9
 
10
10
  sub_deps = set()
11
- _underscored_packages = {pkg.replace("-", "_") for pkg in packages}
11
+ underscored_packages = {pkg.replace("-", "_") for pkg in packages}
12
12
 
13
13
  for pkg in packages:
14
14
  try:
@@ -21,7 +21,7 @@ def _get_sub_deps(packages: Sequence[str]) -> list[str]:
21
21
 
22
22
  for req in required:
23
23
  cleaned_req = req.split(" ")[0]
24
- if cleaned_req.replace("-", "_") not in _underscored_packages:
24
+ if cleaned_req.replace("-", "_") not in underscored_packages:
25
25
  sub_deps.add(cleaned_req)
26
26
 
27
27
  return sorted(sub_deps, key=lambda x: x.lower())
@@ -134,7 +134,7 @@ def _get_filtered_args(
134
134
  k: schema[k]
135
135
  for i, (k, param) in enumerate(valid_keys.items())
136
136
  if k not in filter_args
137
- and (i > 0 or param.name not in ("self", "cls"))
137
+ and (i > 0 or param.name not in {"self", "cls"})
138
138
  and (include_injected or not _is_injected_arg_type(param.annotation))
139
139
  }
140
140
 
@@ -336,7 +336,7 @@ def create_schema_from_function(
336
336
  else:
337
337
  # Handle classmethods and instance methods
338
338
  existing_params: list[str] = list(sig.parameters.keys())
339
- if existing_params and existing_params[0] in ("self", "cls") and in_class:
339
+ if existing_params and existing_params[0] in {"self", "cls"} and in_class:
340
340
  filter_args_ = [existing_params[0], *list(FILTERED_ARGS)]
341
341
  else:
342
342
  filter_args_ = list(FILTERED_ARGS)
@@ -776,7 +776,7 @@ class ChildTool(BaseTool):
776
776
  def run(
777
777
  self,
778
778
  tool_input: Union[str, dict[str, Any]],
779
- verbose: Optional[bool] = None,
779
+ verbose: Optional[bool] = None, # noqa: FBT001
780
780
  start_color: Optional[str] = "green",
781
781
  color: Optional[str] = "green",
782
782
  callbacks: Callbacks = None,
@@ -803,7 +803,7 @@ class ChildTool(BaseTool):
803
803
  run_id: The id of the run. Defaults to None.
804
804
  config: The configuration for the tool. Defaults to None.
805
805
  tool_call_id: The id of the tool call. Defaults to None.
806
- kwargs: Keyword arguments to be passed to tool callbacks
806
+ kwargs: Keyword arguments to be passed to tool callbacks (event handler)
807
807
 
808
808
  Returns:
809
809
  The output of the tool.
@@ -846,9 +846,9 @@ class ChildTool(BaseTool):
846
846
  tool_input, tool_call_id
847
847
  )
848
848
  if signature(self._run).parameters.get("run_manager"):
849
- tool_kwargs = tool_kwargs | {"run_manager": run_manager}
849
+ tool_kwargs |= {"run_manager": run_manager}
850
850
  if config_param := _get_runnable_config_param(self._run):
851
- tool_kwargs = tool_kwargs | {config_param: config}
851
+ tool_kwargs |= {config_param: config}
852
852
  response = context.run(self._run, *tool_args, **tool_kwargs)
853
853
  if self.response_format == "content_and_artifact":
854
854
  if not isinstance(response, tuple) or len(response) != 2:
@@ -888,7 +888,7 @@ class ChildTool(BaseTool):
888
888
  async def arun(
889
889
  self,
890
890
  tool_input: Union[str, dict],
891
- verbose: Optional[bool] = None,
891
+ verbose: Optional[bool] = None, # noqa: FBT001
892
892
  start_color: Optional[str] = "green",
893
893
  color: Optional[str] = "green",
894
894
  callbacks: Callbacks = None,
@@ -197,7 +197,14 @@ class StructuredTool(BaseTool):
197
197
  description_ = source_function.__doc__ or None
198
198
  if description_ is None and args_schema:
199
199
  if isinstance(args_schema, type) and is_basemodel_subclass(args_schema):
200
- description_ = args_schema.__doc__ or None
200
+ description_ = args_schema.__doc__
201
+ if (
202
+ description_
203
+ and "A base class for creating Pydantic models" in description_
204
+ ):
205
+ description_ = ""
206
+ elif not description_:
207
+ description_ = None
201
208
  elif isinstance(args_schema, dict):
202
209
  description_ = args_schema.get("description")
203
210
  else:
@@ -165,7 +165,7 @@ class _TracerCore(ABC):
165
165
  **kwargs: Any,
166
166
  ) -> Run:
167
167
  """Create a chat model run."""
168
- if self._schema_format not in ("streaming_events", "original+chat"):
168
+ if self._schema_format not in {"streaming_events", "original+chat"}:
169
169
  # Please keep this un-implemented for backwards compatibility.
170
170
  # When it's unimplemented old tracers that use the "original" format
171
171
  # fallback on the on_llm_start method implementation if they
@@ -352,7 +352,7 @@ class _TracerCore(ABC):
352
352
 
353
353
  def _get_chain_inputs(self, inputs: Any) -> Any:
354
354
  """Get the inputs for a chain run."""
355
- if self._schema_format in ("original", "original+chat"):
355
+ if self._schema_format in {"original", "original+chat"}:
356
356
  return inputs if isinstance(inputs, dict) else {"input": inputs}
357
357
  if self._schema_format == "streaming_events":
358
358
  return {
@@ -363,7 +363,7 @@ class _TracerCore(ABC):
363
363
 
364
364
  def _get_chain_outputs(self, outputs: Any) -> Any:
365
365
  """Get the outputs for a chain run."""
366
- if self._schema_format in ("original", "original+chat"):
366
+ if self._schema_format in {"original", "original+chat"}:
367
367
  return outputs if isinstance(outputs, dict) else {"output": outputs}
368
368
  if self._schema_format == "streaming_events":
369
369
  return {
@@ -423,7 +423,7 @@ class _TracerCore(ABC):
423
423
  if metadata:
424
424
  kwargs.update({"metadata": metadata})
425
425
 
426
- if self._schema_format in ("original", "original+chat"):
426
+ if self._schema_format in {"original", "original+chat"}:
427
427
  inputs = {"input": input_str}
428
428
  elif self._schema_format == "streaming_events":
429
429
  inputs = {"input": inputs}
@@ -773,7 +773,7 @@ async def _astream_events_implementation_v1(
773
773
  run_log = RunLog(state=None) # type: ignore[arg-type]
774
774
  encountered_start_event = False
775
775
 
776
- _root_event_filter = _RootEventFilter(
776
+ root_event_filter = _RootEventFilter(
777
777
  include_names=include_names,
778
778
  include_types=include_types,
779
779
  include_tags=include_tags,
@@ -796,7 +796,7 @@ async def _astream_events_implementation_v1(
796
796
  with_streamed_output_list=True,
797
797
  **kwargs,
798
798
  ):
799
- run_log = run_log + log
799
+ run_log += log
800
800
 
801
801
  if not encountered_start_event:
802
802
  # Yield the start event for the root runnable.
@@ -815,7 +815,7 @@ async def _astream_events_implementation_v1(
815
815
  parent_ids=[], # Not supported in v1
816
816
  )
817
817
 
818
- if _root_event_filter.include_event(event, state["type"]):
818
+ if root_event_filter.include_event(event, state["type"]):
819
819
  yield event
820
820
 
821
821
  paths = {
@@ -901,7 +901,7 @@ async def _astream_events_implementation_v1(
901
901
  data=data,
902
902
  parent_ids=[], # Not supported in v1
903
903
  )
904
- if _root_event_filter.include_event(event, state["type"]):
904
+ if root_event_filter.include_event(event, state["type"]):
905
905
  yield event
906
906
 
907
907
  state = run_log.state
@@ -918,7 +918,7 @@ async def _astream_events_implementation_v1(
918
918
  },
919
919
  parent_ids=[], # Not supported in v1
920
920
  )
921
- if _root_event_filter.include_event(event, state["type"]):
921
+ if root_event_filter.include_event(event, state["type"]):
922
922
  yield event
923
923
 
924
924
 
@@ -130,6 +130,8 @@ class RunLogPatch:
130
130
  def __eq__(self, other: object) -> bool:
131
131
  return isinstance(other, RunLogPatch) and self.ops == other.ops
132
132
 
133
+ __hash__ = None # type: ignore[assignment]
134
+
133
135
 
134
136
  class RunLog(RunLogPatch):
135
137
  """Run log."""
@@ -174,6 +176,8 @@ class RunLog(RunLogPatch):
174
176
  # Then compare that the ops are the same
175
177
  return super().__eq__(other)
176
178
 
179
+ __hash__ = None # type: ignore[assignment]
180
+
177
181
 
178
182
  T = TypeVar("T")
179
183
 
@@ -694,7 +698,7 @@ async def _astream_log_implementation(
694
698
  else:
695
699
  state = RunLog(state=None) # type: ignore[arg-type]
696
700
  async for log in stream:
697
- state = state + log
701
+ state += log
698
702
  yield state
699
703
  finally:
700
704
  # Wait for the runnable to finish, if not cancelled (eg. by break)
@@ -64,6 +64,8 @@ def merge_dicts(left: dict[str, Any], *others: dict[str, Any]) -> dict[str, Any]
64
64
  merged[right_k] = merge_lists(merged[right_k], right_v)
65
65
  elif merged[right_k] == right_v:
66
66
  continue
67
+ elif isinstance(merged[right_k], int):
68
+ merged[right_k] += right_v
67
69
  else:
68
70
  msg = (
69
71
  f"Additional kwargs key {right_k} already exists in left dict and "
@@ -15,12 +15,12 @@ def env_var_is_set(env_var: str) -> bool:
15
15
  Returns:
16
16
  bool: True if the environment variable is set, False otherwise.
17
17
  """
18
- return env_var in os.environ and os.environ[env_var] not in (
18
+ return env_var in os.environ and os.environ[env_var] not in {
19
19
  "",
20
20
  "0",
21
21
  "false",
22
22
  "False",
23
- )
23
+ }
24
24
 
25
25
 
26
26
  def get_from_dict_or_env(
@@ -294,8 +294,6 @@ def _convert_any_typed_dicts_to_pydantic(
294
294
  raise ValueError(msg)
295
295
  if arg_desc := arg_descriptions.get(arg):
296
296
  field_kwargs["description"] = arg_desc
297
- else:
298
- pass
299
297
  fields[arg] = (new_arg_type, Field_v1(**field_kwargs))
300
298
  else:
301
299
  new_arg_type = _convert_any_typed_dicts_to_pydantic(
@@ -456,7 +454,7 @@ def convert_to_openai_function(
456
454
  oai_function = {
457
455
  k: v
458
456
  for k, v in function.items()
459
- if k in ("name", "description", "parameters", "strict")
457
+ if k in {"name", "description", "parameters", "strict"}
460
458
  }
461
459
  # a JSON schema with title and description
462
460
  elif isinstance(function, dict) and "title" in function:
@@ -734,7 +732,7 @@ def _parse_google_docstring(
734
732
  docstring_blocks = docstring.split("\n\n")
735
733
  if error_on_invalid_docstring:
736
734
  filtered_annotations = {
737
- arg for arg in args if arg not in ("run_manager", "callbacks", "return")
735
+ arg for arg in args if arg not in {"run_manager", "callbacks", "return"}
738
736
  }
739
737
  if filtered_annotations and (
740
738
  len(docstring_blocks) < 2
@@ -770,8 +768,8 @@ def _parse_google_docstring(
770
768
  if ":" in line:
771
769
  arg, desc = line.split(":", maxsplit=1)
772
770
  arg = arg.strip()
773
- arg_name, _, _annotations = arg.partition(" ")
774
- if _annotations.startswith("(") and _annotations.endswith(")"):
771
+ arg_name, _, annotations_ = arg.partition(" ")
772
+ if annotations_.startswith("(") and annotations_.endswith(")"):
775
773
  arg = arg_name
776
774
  arg_descriptions[arg] = desc.strip()
777
775
  elif arg:
@@ -4,7 +4,7 @@ from typing import Any
4
4
 
5
5
 
6
6
  def __getattr__(name: str) -> Any:
7
- if name in ("encode_image", "image_to_data_url"):
7
+ if name in {"encode_image", "image_to_data_url"}:
8
8
  msg = (
9
9
  f"'{name}' has been removed for security reasons.\n\n"
10
10
  f"Usage of this utility in environments with user-input paths is a "