Skip to content

Commit 4581393

Browse files
committed
fix: update Agno integration for v1.7.11 architecture
- Replace Tool class with tool decorator approach - Use agno.tools.tool decorator for function-based tools - Update tests to match new Agno tool architecture - Add comprehensive MyPy configuration for Agno modules - Fix compatibility with current Agno version
1 parent 8544d2e commit 4581393

File tree

3 files changed

+60
-32
lines changed

3 files changed

+60
-32
lines changed

pyproject.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,11 @@ ignore_missing_imports = true
115115
[[tool.mypy.overrides]]
116116
module = "agno.tools"
117117
ignore_missing_imports = true
118+
119+
[[tool.mypy.overrides]]
120+
module = "agno.agent"
121+
ignore_missing_imports = true
122+
123+
[[tool.mypy.overrides]]
124+
module = "agno.models.openai"
125+
ignore_missing_imports = true

stackone_ai/models.py

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -401,10 +401,10 @@ def to_agno(self) -> Any:
401401
"""Convert this tool to Agno format
402402
403403
Returns:
404-
Tool in Agno format
404+
Function callable in Agno format
405405
"""
406406
try:
407-
from agno.tools import Tool as AgnoBaseTool
407+
from agno.tools import tool
408408
except ImportError as e:
409409
raise ImportError(
410410
"Agno is not installed. Please install it with 'pip install agno>=1.7.0' "
@@ -413,18 +413,17 @@ def to_agno(self) -> Any:
413413

414414
parent_tool = self
415415

416-
class StackOneAgnoTool(AgnoBaseTool):
417-
def __init__(self) -> None:
418-
super().__init__(
419-
name=parent_tool.name,
420-
description=parent_tool.description,
421-
)
416+
def agno_tool_function(**kwargs: Any) -> JsonDict:
417+
"""Execute the StackOne tool with the provided arguments"""
418+
return parent_tool.execute(kwargs)
422419

423-
def run(self, **kwargs: Any) -> JsonDict:
424-
"""Run the tool with the provided arguments"""
425-
return parent_tool.execute(kwargs)
420+
# Apply Agno tool decorator with metadata
421+
decorated_tool = tool(
422+
name=parent_tool.name,
423+
description=parent_tool.description,
424+
)(agno_tool_function)
426425

427-
return StackOneAgnoTool()
426+
return decorated_tool
428427

429428
def set_account_id(self, account_id: str | None) -> None:
430429
"""Set the account ID for this tool

tests/test_agno_integration.py

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -53,43 +53,54 @@ def test_to_agno_without_agno_installed(self, mock_tool: StackOneTool) -> None:
5353
assert "pip install agno>=1.7.0" in str(exc_info.value)
5454

5555
def test_to_agno_with_mocked_agno(self, mock_tool: StackOneTool) -> None:
56-
"""Test Agno conversion with mocked Agno classes"""
57-
# Mock the Agno Tool class
58-
mock_agno_base_tool = MagicMock()
56+
"""Test Agno conversion with mocked Agno decorator"""
57+
# Mock the Agno tool decorator
58+
mock_tool_decorator = MagicMock()
5959
mock_agno_module = MagicMock()
60-
mock_agno_module.Tool = mock_agno_base_tool
60+
mock_agno_module.tool = mock_tool_decorator
61+
62+
# Configure the decorator to return the decorated function
63+
mock_tool_decorator.return_value = lambda func: func
6164

6265
with patch.dict("sys.modules", {"agno.tools": mock_agno_module}):
6366
agno_tool = mock_tool.to_agno()
6467

65-
# Verify an Agno tool instance was created
68+
# Verify an Agno tool function was created
6669
assert agno_tool is not None
70+
assert callable(agno_tool)
6771

6872
def test_to_agno_tool_execution(self, mock_tool: StackOneTool) -> None:
6973
"""Test that the Agno tool can execute the underlying StackOne tool"""
70-
mock_agno_base_tool = MagicMock()
74+
mock_tool_decorator = MagicMock()
7175
mock_agno_module = MagicMock()
72-
mock_agno_module.Tool = mock_agno_base_tool
76+
mock_agno_module.tool = mock_tool_decorator
77+
78+
# Configure the decorator to return the decorated function
79+
mock_tool_decorator.return_value = lambda func: func
7380

7481
with patch.dict("sys.modules", {"agno.tools": mock_agno_module}):
7582
agno_tool = mock_tool.to_agno()
7683

77-
# Verify the tool was created (basic functionality test)
84+
# Verify the tool was created and can be called
7885
assert agno_tool is not None
79-
assert hasattr(agno_tool, "run")
86+
assert callable(agno_tool)
8087

8188
def test_tools_to_agno(self, tools_collection: Tools) -> None:
8289
"""Test converting Tools collection to Agno format"""
83-
mock_agno_base_tool = MagicMock()
90+
mock_tool_decorator = MagicMock()
8491
mock_agno_module = MagicMock()
85-
mock_agno_module.Tool = mock_agno_base_tool
92+
mock_agno_module.tool = mock_tool_decorator
93+
94+
# Configure the decorator to return the decorated function
95+
mock_tool_decorator.return_value = lambda func: func
8696

8797
with patch.dict("sys.modules", {"agno.tools": mock_agno_module}):
8898
agno_tools = tools_collection.to_agno()
8999

90100
# Verify we got the expected number of tools
91101
assert len(agno_tools) == 1
92102
assert agno_tools[0] is not None
103+
assert callable(agno_tools[0])
93104

94105
def test_tools_to_agno_multiple_tools(self) -> None:
95106
"""Test converting multiple tools to Agno format"""
@@ -113,30 +124,40 @@ def test_tools_to_agno_multiple_tools(self) -> None:
113124

114125
tools = Tools([tool1, tool2])
115126

116-
mock_agno_base_tool = MagicMock()
127+
mock_tool_decorator = MagicMock()
117128
mock_agno_module = MagicMock()
118-
mock_agno_module.Tool = mock_agno_base_tool
129+
mock_agno_module.tool = mock_tool_decorator
130+
131+
# Configure the decorator to return the decorated function
132+
mock_tool_decorator.return_value = lambda func: func
119133

120134
with patch.dict("sys.modules", {"agno.tools": mock_agno_module}):
121135
agno_tools = tools.to_agno()
122136

123137
assert len(agno_tools) == 2
124-
assert all(tool is not None for tool in agno_tools)
138+
assert all(tool is not None and callable(tool) for tool in agno_tools)
125139

126140
def test_agno_tool_preserves_metadata(self, mock_tool: StackOneTool) -> None:
127141
"""Test that Agno tool conversion preserves important metadata"""
128-
mock_agno_base_tool = MagicMock()
142+
mock_tool_decorator = MagicMock()
129143
mock_agno_module = MagicMock()
130-
mock_agno_module.Tool = mock_agno_base_tool
144+
mock_agno_module.tool = mock_tool_decorator
145+
146+
# Configure the decorator to return the decorated function
147+
mock_tool_decorator.return_value = lambda func: func
131148

132149
with patch.dict("sys.modules", {"agno.tools": mock_agno_module}):
133150
agno_tool = mock_tool.to_agno()
134151

135-
# Verify the tool was created with expected attributes
152+
# Verify the tool was created
136153
assert agno_tool is not None
137-
# For real integration, name and description would be set by the Agno base class
138-
assert hasattr(agno_tool, "name")
139-
assert hasattr(agno_tool, "description")
154+
assert callable(agno_tool)
155+
156+
# Verify the decorator was called with the correct metadata
157+
mock_tool_decorator.assert_called_once_with(
158+
name=mock_tool.name,
159+
description=mock_tool.description,
160+
)
140161

141162

142163
class TestAgnoIntegrationErrors:

0 commit comments

Comments
 (0)