diff --git a/libs/core/langchain_core/tools.py b/libs/core/langchain_core/tools.py index 85db1d3b92e..633faa7b343 100644 --- a/libs/core/langchain_core/tools.py +++ b/libs/core/langchain_core/tools.py @@ -20,6 +20,7 @@ tool for the job. from __future__ import annotations import asyncio +import copy import functools import inspect import json @@ -1481,8 +1482,9 @@ def _prep_run_args( ) -> Tuple[Union[str, Dict], Dict]: config = ensure_config(config) if _is_tool_call(input): - tool_call_id: Optional[str] = cast(ToolCall, input)["id"] - tool_input: Union[str, dict] = cast(ToolCall, input)["args"] + 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"] 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 7f0fccbd050..489feeb7dca 100644 --- a/libs/core/tests/unit_tests/test_tools.py +++ b/libs/core/tests/unit_tests/test_tools.py @@ -977,6 +977,16 @@ class AFooBase(FooBase): def test_tool_pass_config(tool: BaseTool) -> None: assert tool.invoke({"bar": "baz"}, {"configurable": {"foo": "not-bar"}}) == "baz" + # Test tool calls + tool_call = { + "name": tool.name, + "args": {"bar": "baz"}, + "id": "abc123", + "type": "tool_call", + } + _ = tool.invoke(tool_call, {"configurable": {"foo": "not-bar"}}) + assert tool_call["args"] == {"bar": "baz"} + @pytest.mark.parametrize( "tool", [foo, afoo, simple_foo, asimple_foo, FooBase(), AFooBase()]