from __future__ import annotations from unittest.mock import MagicMock import pytest from langchain_core.messages.tool import ToolCall pytest.importorskip( "anthropic", reason="Anthropic SDK is required for Claude middleware tests" ) from langchain.tools.tool_node import ToolCallRequest from langchain_core.messages import ToolMessage from langchain_anthropic.middleware.bash import ClaudeBashToolMiddleware def test_wrap_tool_call_handles_claude_bash(monkeypatch: pytest.MonkeyPatch) -> None: middleware = ClaudeBashToolMiddleware() sentinel = ToolMessage(content="ok", tool_call_id="call-1", name="bash") monkeypatch.setattr(middleware, "_run_shell_tool", MagicMock(return_value=sentinel)) monkeypatch.setattr( middleware, "_ensure_resources", MagicMock(return_value=MagicMock()) ) tool_call: ToolCall = { "name": "bash", "args": {"command": "echo hi"}, "id": "call-1", } request = ToolCallRequest( tool_call=tool_call, tool=MagicMock(), state={}, runtime=None, # type: ignore[arg-type] ) handler_called = False def handler(_: ToolCallRequest) -> ToolMessage: nonlocal handler_called handler_called = True return ToolMessage(content="should not be used", tool_call_id="call-1") result = middleware.wrap_tool_call(request, handler) assert result is sentinel assert handler_called is False def test_wrap_tool_call_passes_through_other_tools( monkeypatch: pytest.MonkeyPatch, ) -> None: middleware = ClaudeBashToolMiddleware() tool_call: ToolCall = {"name": "other", "args": {}, "id": "call-2"} request = ToolCallRequest( tool_call=tool_call, tool=MagicMock(), state={}, runtime=None, # type: ignore[arg-type] ) sentinel = ToolMessage(content="handled", tool_call_id="call-2", name="other") def handler(_: ToolCallRequest) -> ToolMessage: return sentinel result = middleware.wrap_tool_call(request, handler) assert result is sentinel