@@ -633,3 +633,117 @@ def get_scores() -> dict[str, int]:
633633 # Test converted result
634634 result = await manager .call_tool ("get_scores" , {})
635635 assert result == expected
636+
637+
638+ class TestRemoveTools :
639+ """Test tool removal functionality in the tool manager."""
640+
641+ def test_remove_existing_tool (self , caplog : pytest .LogCaptureFixture ):
642+ """Test removing an existing tool."""
643+ def add (a : int , b : int ) -> int :
644+ """Add two numbers."""
645+ return a + b
646+
647+ manager = ToolManager ()
648+ manager .add_tool (add )
649+
650+ # Verify tool exists
651+ assert manager .get_tool ("add" ) is not None
652+ assert len (manager .list_tools ()) == 1
653+
654+ # Remove the tool
655+ with caplog .at_level (logging .WARNING ):
656+ manager .remove_tool ("add" )
657+ # Should not log a warning for removing existing tool
658+ assert "Tried to remove unknown tool: add" not in caplog .text
659+
660+ # Verify tool is removed
661+ assert manager .get_tool ("add" ) is None
662+ assert len (manager .list_tools ()) == 0
663+
664+ def test_remove_nonexistent_tool (self , caplog : pytest .LogCaptureFixture ):
665+ """Test removing a non-existent tool logs a warning."""
666+ manager = ToolManager ()
667+
668+ with caplog .at_level (logging .WARNING ):
669+ manager .remove_tool ("nonexistent" )
670+ assert "Tried to remove unknown tool: nonexistent" in caplog .text
671+
672+ def test_remove_tool_from_multiple_tools (self ):
673+ """Test removing one tool when multiple tools exist."""
674+ def add (a : int , b : int ) -> int :
675+ """Add two numbers."""
676+ return a + b
677+
678+ def multiply (a : int , b : int ) -> int :
679+ """Multiply two numbers."""
680+ return a * b
681+
682+ def divide (a : int , b : int ) -> float :
683+ """Divide two numbers."""
684+ return a / b
685+
686+ manager = ToolManager ()
687+ manager .add_tool (add )
688+ manager .add_tool (multiply )
689+ manager .add_tool (divide )
690+
691+ # Verify all tools exist
692+ assert len (manager .list_tools ()) == 3
693+ assert manager .get_tool ("add" ) is not None
694+ assert manager .get_tool ("multiply" ) is not None
695+ assert manager .get_tool ("divide" ) is not None
696+
697+ # Remove middle tool
698+ manager .remove_tool ("multiply" )
699+
700+ # Verify only multiply is removed
701+ assert len (manager .list_tools ()) == 2
702+ assert manager .get_tool ("add" ) is not None
703+ assert manager .get_tool ("multiply" ) is None
704+ assert manager .get_tool ("divide" ) is not None
705+
706+ @pytest .mark .anyio
707+ async def test_call_removed_tool_raises_error (self ):
708+ """Test that calling a removed tool raises ToolError."""
709+ def greet (name : str ) -> str :
710+ """Greet someone."""
711+ return f"Hello, { name } !"
712+
713+ manager = ToolManager ()
714+ manager .add_tool (greet )
715+
716+ # Verify tool works before removal
717+ result = await manager .call_tool ("greet" , {"name" : "World" })
718+ assert result == "Hello, World!"
719+
720+ # Remove the tool
721+ manager .remove_tool ("greet" )
722+
723+ # Verify calling removed tool raises error
724+ with pytest .raises (ToolError , match = "Unknown tool: greet" ):
725+ await manager .call_tool ("greet" , {"name" : "World" })
726+
727+ def test_remove_tool_case_sensitive (self , caplog : pytest .LogCaptureFixture ):
728+ """Test that tool removal is case-sensitive."""
729+ def test_func () -> str :
730+ """Test function."""
731+ return "test"
732+
733+ manager = ToolManager ()
734+ manager .add_tool (test_func )
735+
736+ # Verify tool exists
737+ assert manager .get_tool ("test_func" ) is not None
738+
739+ # Try to remove with different case
740+ with caplog .at_level (logging .WARNING ):
741+ manager .remove_tool ("Test_Func" )
742+ assert "Tried to remove unknown tool: Test_Func" in caplog .text
743+
744+ # Verify original tool still exists
745+ assert manager .get_tool ("test_func" ) is not None
746+
747+ # Remove with correct case
748+ manager .remove_tool ("test_func" )
749+ assert manager .get_tool ("test_func" ) is None
0 commit comments