diff --git a/src/strands_evals/simulation/tool_simulator.py b/src/strands_evals/simulation/tool_simulator.py index da844c51..133f2b63 100644 --- a/src/strands_evals/simulation/tool_simulator.py +++ b/src/strands_evals/simulation/tool_simulator.py @@ -166,6 +166,7 @@ def __init__( state_registry: StateRegistry | None = None, model: Model | str | None = None, max_tool_call_cache_size: int = 20, + tools: list | None = None, ): """ Initialize a ToolSimulator instance. @@ -178,8 +179,12 @@ def __init__( Only used when creating a new StateRegistry (ignored if state_registry is provided). Older calls are automatically evicted when limit is exceeded. Default is 20. + tools: Optional list of tools to provide to the internal simulation agent. + When provided, the agent can use these tools (e.g. calculator) to improve + accuracy of generated responses. Defaults to an empty list. """ self.model = model + self.tools = tools or [] self.state_registry = state_registry or StateRegistry(max_tool_call_cache_size=max_tool_call_cache_size) self._registered_tools: dict[str, RegisteredTool] = {} @@ -229,7 +234,7 @@ def wrapper(*args, **kwargs): def _simulate_tool_call(self, prompt: str, structured_output_model=None) -> Any: """Tool simulation agent creation and response generation.""" agent = Agent( - tools=[], + tools=self.tools, model=self.model, callback_handler=None, ) diff --git a/tests/strands_evals/simulation/test_tool_simulator.py b/tests/strands_evals/simulation/test_tool_simulator.py index a7000852..b9aa4599 100644 --- a/tests/strands_evals/simulation/test_tool_simulator.py +++ b/tests/strands_evals/simulation/test_tool_simulator.py @@ -465,3 +465,75 @@ def test_tool_no_params() -> dict: properties = schema.get("properties", {}) # Empty model should mean no properties assert len(properties) == 0, "Tool with empty schema should have no properties" + + +def test_tool_simulator_init_default_tools(): + """Test ToolSimulator initializes with empty tools list by default.""" + simulator = ToolSimulator() + assert simulator.tools == [] + + +def test_tool_simulator_init_with_tools(): + """Test ToolSimulator stores provided tools.""" + mock_tool = MagicMock() + simulator = ToolSimulator(tools=[mock_tool]) + assert simulator.tools == [mock_tool] + + +def test_tool_simulator_init_tools_none_becomes_empty_list(): + """Test ToolSimulator converts None tools to empty list.""" + simulator = ToolSimulator(tools=None) + assert simulator.tools == [] + + +def test_simulate_tool_call_passes_tools_to_agent(mock_model): + """Test that tools are passed through to the internal Agent.""" + mock_tool = MagicMock() + simulator = ToolSimulator(model=mock_model, tools=[mock_tool]) + + @simulator.tool(output_schema=GenericOutput) + def test_func(message: str) -> dict: + """Test function.""" + pass + + captured_kwargs = {} + + def mock_agent_constructor(**kwargs): + captured_kwargs.update(kwargs) + mock_agent = MagicMock() + mock_result = MagicMock() + mock_result.__str__ = MagicMock(return_value='{"result": "response"}') + mock_agent.return_value = mock_result + return mock_agent + + with pytest.MonkeyPatch().context() as m: + m.setattr("strands_evals.simulation.tool_simulator.Agent", mock_agent_constructor) + simulator.test_func("hello") + + assert captured_kwargs["tools"] == [mock_tool] + + +def test_simulate_tool_call_default_empty_tools(mock_model): + """Test that default simulator passes empty tools list to Agent.""" + simulator = ToolSimulator(model=mock_model) + + @simulator.tool(output_schema=GenericOutput) + def test_func(message: str) -> dict: + """Test function.""" + pass + + captured_kwargs = {} + + def mock_agent_constructor(**kwargs): + captured_kwargs.update(kwargs) + mock_agent = MagicMock() + mock_result = MagicMock() + mock_result.__str__ = MagicMock(return_value='{"result": "response"}') + mock_agent.return_value = mock_result + return mock_agent + + with pytest.MonkeyPatch().context() as m: + m.setattr("strands_evals.simulation.tool_simulator.Agent", mock_agent_constructor) + simulator.test_func("hello") + + assert captured_kwargs["tools"] == []