/ test / tools / test_toolset_wrapper.py
test_toolset_wrapper.py
  1  # SPDX-FileCopyrightText: 2022-present deepset GmbH <info@deepset.ai>
  2  #
  3  # SPDX-License-Identifier: Apache-2.0
  4  
  5  import pytest
  6  
  7  from haystack.components.agents import Agent
  8  from haystack.core.component.component import component
  9  from haystack.tools import Tool, Toolset
 10  from haystack.tools.toolset import _ToolsetWrapper
 11  
 12  
 13  # Test fixtures
 14  def add_numbers(a: int, b: int) -> int:
 15      """Add two numbers."""
 16      return a + b
 17  
 18  
 19  def multiply_numbers(a: int, b: int) -> int:
 20      """Multiply two numbers."""
 21      return a * b
 22  
 23  
 24  def subtract_numbers(a: int, b: int) -> int:
 25      """Subtract b from a."""
 26      return a - b
 27  
 28  
 29  @pytest.fixture
 30  def add_tool():
 31      return Tool(
 32          name="add",
 33          description="Add two numbers",
 34          parameters={
 35              "type": "object",
 36              "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
 37              "required": ["a", "b"],
 38          },
 39          function=add_numbers,
 40      )
 41  
 42  
 43  @pytest.fixture
 44  def multiply_tool():
 45      return Tool(
 46          name="multiply",
 47          description="Multiply two numbers",
 48          parameters={
 49              "type": "object",
 50              "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
 51              "required": ["a", "b"],
 52          },
 53          function=multiply_numbers,
 54      )
 55  
 56  
 57  @pytest.fixture
 58  def subtract_tool():
 59      return Tool(
 60          name="subtract",
 61          description="Subtract two numbers",
 62          parameters={
 63              "type": "object",
 64              "properties": {"a": {"type": "integer"}, "b": {"type": "integer"}},
 65              "required": ["a", "b"],
 66          },
 67          function=subtract_numbers,
 68      )
 69  
 70  
 71  class TestToolsetWrapper:
 72      """Tests for the _ToolsetWrapper class"""
 73  
 74      def test_toolset_plus_toolset_creates_wrapper(self, add_tool, multiply_tool):
 75          """Test that combining two Toolsets creates a _ToolsetWrapper and works correctly."""
 76          toolset1 = Toolset([add_tool])
 77          toolset2 = Toolset([multiply_tool])
 78  
 79          result = toolset1 + toolset2
 80  
 81          assert isinstance(result, _ToolsetWrapper)
 82          assert len(result) == 2
 83          assert add_tool in result
 84          assert multiply_tool in result
 85  
 86      def test_wrapper_with_agent(self, add_tool, multiply_tool):
 87          """Test that _ToolsetWrapper works with Agent."""
 88  
 89          @component
 90          class MockChatGenerator:
 91              def run(self, messages, tools=None, **kwargs):
 92                  return {"replies": messages}
 93  
 94              def warm_up(self):
 95                  pass
 96  
 97          toolset1 = Toolset([add_tool])
 98          toolset2 = Toolset([multiply_tool])
 99          wrapper = toolset1 + toolset2
100  
101          agent = Agent(chat_generator=MockChatGenerator(), tools=wrapper)
102          agent.warm_up()
103  
104          assert len(list(agent.tools)) == 2
105  
106      def test_wrapper_chaining_and_duplicate_detection(self, add_tool, multiply_tool, subtract_tool):
107          """Test chaining operations and that duplicates are still detected."""
108          toolset1 = Toolset([add_tool])
109          toolset2 = Toolset([multiply_tool])
110          toolset3 = Toolset([subtract_tool])
111  
112          # Chaining should work
113          result = toolset1 + toolset2 + toolset3
114          assert len(result) == 3
115  
116          # Duplicates should be detected
117          toolset_with_dup = Toolset([add_tool])
118          with pytest.raises(ValueError, match="Duplicate tool names found"):
119              _ = result + toolset_with_dup