diff --git a/libs/core/langchain_core/tools.py b/libs/core/langchain_core/tools.py index b84e6d5510b71..0b251881436c6 100644 --- a/libs/core/langchain_core/tools.py +++ b/libs/core/langchain_core/tools.py @@ -20,7 +20,6 @@ from __future__ import annotations import asyncio -import copy import functools import inspect import json @@ -1491,9 +1490,8 @@ def _prep_run_args( ) -> Tuple[Union[str, Dict], Dict]: config = ensure_config(config) if _is_tool_call(input): - input_copy = copy.deepcopy(input) - tool_call_id: Optional[str] = cast(ToolCall, input_copy)["id"] - tool_input: Union[str, dict] = cast(ToolCall, input_copy)["args"] + tool_call_id: Optional[str] = cast(ToolCall, input)["id"] + tool_input: Union[str, dict] = cast(ToolCall, input)["args"].copy() else: tool_call_id = None tool_input = cast(Union[str, dict], input) diff --git a/libs/core/tests/unit_tests/test_tools.py b/libs/core/tests/unit_tests/test_tools.py index ca2a04f9dcfee..1ba9e5961ab30 100644 --- a/libs/core/tests/unit_tests/test_tools.py +++ b/libs/core/tests/unit_tests/test_tools.py @@ -4,6 +4,7 @@ import json import sys import textwrap +import threading from datetime import datetime from enum import Enum from functools import partial @@ -977,7 +978,7 @@ async def _arun(self, bar: Any, bar_config: RunnableConfig, **kwargs: Any) -> An def test_tool_pass_config(tool: BaseTool) -> None: assert tool.invoke({"bar": "baz"}, {"configurable": {"foo": "not-bar"}}) == "baz" - # Test tool calls + # Test we don't mutate tool calls tool_call = { "name": tool.name, "args": {"bar": "baz"}, @@ -988,6 +989,25 @@ def test_tool_pass_config(tool: BaseTool) -> None: assert tool_call["args"] == {"bar": "baz"} +class FooBaseNonPickleable(FooBase): + def _run(self, bar: Any, bar_config: RunnableConfig, **kwargs: Any) -> Any: + return True + + +def test_tool_pass_config_non_pickleable() -> None: + tool = FooBaseNonPickleable() + + args = {"bar": threading.Lock()} + tool_call = { + "name": tool.name, + "args": args, + "id": "abc123", + "type": "tool_call", + } + _ = tool.invoke(tool_call, {"configurable": {"foo": "not-bar"}}) + assert tool_call["args"] == args + + @pytest.mark.parametrize( "tool", [foo, afoo, simple_foo, asimple_foo, FooBase(), AFooBase()] )