test_tool_factory_langchain.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. """
  2. Unit tests for ToolFactory LangChain integration.
  3. Tests the LangChain tool conversion functionality with REAL LangChain tools.
  4. """
  5. import builtins
  6. from unittest.mock import patch
  7. import pytest
  8. from agents import FunctionTool
  9. from agency_swarm.tools.tool_factory import ToolFactory
  10. class TestLangchainIntegration:
  11. """Test REAL LangChain tool integration."""
  12. def test_missing_langchain_import(self):
  13. """Test error when langchain_community is not available."""
  14. # Create a simple dummy tool class
  15. class DummyTool:
  16. def run(self):
  17. return "dummy"
  18. dummy_tool = DummyTool()
  19. # Mock import to simulate ImportError
  20. original_import = builtins.__import__
  21. with patch("builtins.__import__") as mock_import:
  22. def import_side_effect(name, *args, **kwargs):
  23. if name == "langchain_community.tools":
  24. raise ImportError("No module named 'langchain_community'")
  25. return original_import(name, *args, **kwargs)
  26. mock_import.side_effect = import_side_effect
  27. with pytest.raises(ImportError, match="You must install langchain"):
  28. ToolFactory.from_langchain_tool(dummy_tool)
  29. def test_converts_real_langchain_tool(self):
  30. """Test conversion of a real LangChain tool."""
  31. pytest.importorskip("langchain_core", reason="LangChain not available for testing")
  32. from langchain_core.tools import BaseTool as LangChainBaseTool
  33. class TestLangChainTool(LangChainBaseTool):
  34. name: str = "test_tool"
  35. description: str = "test tool for conversion"
  36. def _run(self, query: str = "") -> str:
  37. return f"Result for: {query}"
  38. tool = TestLangChainTool()
  39. result = ToolFactory.from_langchain_tool(tool)
  40. # Verify conversion worked
  41. assert isinstance(result, FunctionTool)
  42. assert result.name == "test_tool"
  43. assert "test tool" in result.description.lower()
  44. def test_converts_real_community_tool(self):
  45. """Test conversion of a real LangChain community tool."""
  46. pytest.importorskip("langchain_community", reason="LangChain community tools not available")
  47. pytest.importorskip(
  48. "langchain_experimental.tools.python.tool",
  49. reason="LangChain experimental python tool not available",
  50. )
  51. from langchain_experimental.tools.python.tool import PythonREPLTool
  52. tool = PythonREPLTool()
  53. result = ToolFactory.from_langchain_tool(tool)
  54. # Verify conversion worked
  55. assert isinstance(result, FunctionTool)
  56. assert result.name == "Python_REPL"
  57. assert "python" in result.description.lower()
  58. def test_handles_empty_list(self):
  59. """Test handling of empty tools list."""
  60. result = ToolFactory.from_langchain_tools([])
  61. assert result == []
  62. @pytest.mark.asyncio
  63. async def test_real_tool_execution(self):
  64. """Test that converted LangChain tool actually executes."""
  65. pytest.importorskip("langchain_core", reason="LangChain not available for execution test")
  66. from langchain_core.tools import BaseTool as LangChainBaseTool
  67. class SimpleLangChainTool(LangChainBaseTool):
  68. name: str = "simple_tool"
  69. description: str = "Simple test tool"
  70. def _run(self, input_text: str = "test") -> str:
  71. return f"Processed: {input_text}"
  72. function_tool = ToolFactory.from_langchain_tool(SimpleLangChainTool)
  73. import json
  74. result = await function_tool.on_invoke_tool(None, json.dumps({"input_text": "hello"}))
  75. assert "Processed: hello" in result