55and configured according to their expected behavior.
66"""
77
8- from typing import Any , Dict , Optional
8+ from typing import Any , AsyncIterator , Dict , Iterator , Optional
99from unittest .mock import AsyncMock , Mock
1010
1111import pytest
1212
1313from agno .agent import Agent
1414from agno .exceptions import CheckTrigger , InputCheckError , OutputCheckError
15+ from agno .models .base import Model
16+ from agno .models .response import ModelResponse
1517from agno .run .team import TeamRunInput , TeamRunOutput
1618from agno .session .team import TeamSession
1719from agno .team import Team
@@ -109,28 +111,88 @@ def clear_hook_tracker():
109111 hook_execution_tracker ["post_hooks" ].clear ()
110112
111113
114+ class MockTestModel (Model ):
115+ """Test model class that inherits from Model for testing purposes."""
116+
117+ def __init__ (self , model_id : str , model_response_content : Optional [str ] = None ):
118+ super ().__init__ (id = model_id , name = f"{ model_id } -model" , provider = "test" )
119+ self .instructions = None
120+ self ._model_response_content = model_response_content or f"Response from { model_id } "
121+
122+ # Mock the response object
123+ self ._mock_response = Mock ()
124+ self ._mock_response .content = self ._model_response_content
125+ self ._mock_response .role = "assistant"
126+ self ._mock_response .reasoning_content = None
127+ self ._mock_response .tool_executions = None
128+ self ._mock_response .images = None
129+ self ._mock_response .videos = None
130+ self ._mock_response .audios = None
131+ self ._mock_response .files = None
132+ self ._mock_response .citations = None
133+ self ._mock_response .references = None
134+ self ._mock_response .metadata = None
135+ self ._mock_response .tool_calls = []
136+ self ._mock_response .updated_session_state = None
137+ # Set event to assistant_response by default (matches ModelResponse default)
138+ from agno .models .response import ModelResponseEvent
139+ self ._mock_response .event = ModelResponseEvent .assistant_response .value
140+
141+ # Create Mock objects for response methods
142+ self .response = Mock (return_value = self ._mock_response )
143+ self .aresponse = AsyncMock (return_value = self ._mock_response )
144+
145+ def get_instructions_for_model (self , * args , ** kwargs ):
146+ """Mock get_instructions_for_model."""
147+ return None
148+
149+ def get_system_message_for_model (self , * args , ** kwargs ):
150+ """Mock get_system_message_for_model."""
151+ return None
152+
153+ async def aget_instructions_for_model (self , * args , ** kwargs ):
154+ """Mock async get_instructions_for_model."""
155+ return None
156+
157+ async def aget_system_message_for_model (self , * args , ** kwargs ):
158+ """Mock async get_system_message_for_model."""
159+ return None
160+
161+ def parse_args (self , * args , ** kwargs ):
162+ """Mock parse_args."""
163+ return {}
164+
165+ # Implement abstract methods required by Model base class
166+ def invoke (self , * args , ** kwargs ) -> ModelResponse :
167+ """Mock invoke method."""
168+ return self ._mock_response
169+
170+ async def ainvoke (self , * args , ** kwargs ) -> ModelResponse :
171+ """Mock async invoke method."""
172+ return await self .aresponse (* args , ** kwargs )
173+
174+ def invoke_stream (self , * args , ** kwargs ) -> Iterator [ModelResponse ]:
175+ """Mock invoke_stream method."""
176+ yield self ._mock_response
177+
178+ async def ainvoke_stream (self , * args , ** kwargs ) -> AsyncIterator [ModelResponse ]:
179+ """Mock async invoke_stream method."""
180+ yield self ._mock_response
181+ return
182+
183+ def _parse_provider_response (self , response : Any , ** kwargs ) -> ModelResponse :
184+ """Mock _parse_provider_response method."""
185+ return self ._mock_response
186+
187+ def _parse_provider_response_delta (self , response : Any ) -> ModelResponse :
188+ """Mock _parse_provider_response_delta method."""
189+ return self ._mock_response
190+
191+
112192def create_mock_agent (name : str ) -> Agent :
113193 """Create a mock agent for team testing."""
114- mock_model = Mock ()
115- mock_model .id = f"mock-model-{ name .lower ()} "
116- mock_model .provider = "mock"
117- mock_model .instructions = None
118- mock_model .response .return_value = Mock (
119- content = f"Response from { name } " ,
120- role = "assistant" ,
121- reasoning_content = None ,
122- tool_executions = None ,
123- images = None ,
124- videos = None ,
125- audios = None ,
126- files = None ,
127- citations = None ,
128- references = None ,
129- metadata = None ,
130- tool_calls = None ,
131- )
132- mock_model .get_instructions_for_model .return_value = None
133- mock_model .get_system_message_for_model .return_value = None
194+ model_id = f"mock-model-{ name .lower ()} "
195+ mock_model = MockTestModel (model_id = model_id , model_response_content = f"Response from { name } " )
134196
135197 return Agent (name = name , model = mock_model , description = f"Mock { name } for testing" )
136198
@@ -141,43 +203,10 @@ def create_test_team(pre_hooks=None, post_hooks=None, model_response_content=Non
141203 agent1 = create_mock_agent ("Agent1" )
142204 agent2 = create_mock_agent ("Agent2" )
143205
144- # Mock the team model to avoid needing real API keys
145- mock_model = Mock ()
146- mock_model .id = "test-team-model"
147- mock_model .provider = "test"
148- mock_model .instructions = None
149- mock_model .name = "test-team-model"
150-
151- # Mock response object
152- mock_response = Mock ()
153- mock_response .content = model_response_content or "Test team response from mock model"
154- mock_response .role = "assistant"
155- mock_response .reasoning_content = None
156- mock_response .tool_executions = None
157- mock_response .images = None
158- mock_response .videos = None
159- mock_response .audios = None
160- mock_response .files = None
161- mock_response .citations = None
162- mock_response .references = None
163- mock_response .metadata = None
164- mock_response .tool_calls = []
165-
166- # Set up both sync and async response methods
167- mock_model .response .return_value = mock_response
168-
169- # For async operations, we need to mock the async methods
170- async_response_mock = AsyncMock (return_value = mock_response )
171- mock_model .aresponse = async_response_mock
172-
173- mock_model .get_instructions_for_model .return_value = None
174- mock_model .get_system_message_for_model .return_value = None
175- mock_model .structured_outputs = False
176- mock_model .parse_args = Mock (return_value = {})
177-
178- # Add async versions
179- mock_model .aget_instructions_for_model = AsyncMock (return_value = None )
180- mock_model .aget_system_message_for_model = AsyncMock (return_value = None )
206+ # Create a test model that inherits from Model
207+ mock_model = MockTestModel (
208+ model_id = "test-team-model" , model_response_content = model_response_content or "Test team response from mock model"
209+ )
181210
182211 return Team (
183212 name = "Test Team" ,
@@ -560,24 +589,10 @@ def output_validator(run_output: TeamRunOutput) -> None:
560589 agent2 = create_mock_agent ("Agent2" )
561590
562591 # Create mock team model with long response
563- mock_model = Mock ()
564- mock_model .id = "test-team-model"
565- mock_model .provider = "test"
566- mock_model .response .return_value = Mock (
567- content = "A" * 150 , # Long output to trigger post-hook
568- reasoning_content = None ,
569- tool_executions = None ,
570- images = None ,
571- videos = None ,
572- audios = None ,
573- files = None ,
574- citations = None ,
575- references = None ,
576- metadata = None ,
577- role = "assistant" ,
592+ mock_model = MockTestModel (
593+ model_id = "test-team-model" ,
594+ model_response_content = "A" * 150 , # Long output to trigger post-hook
578595 )
579- mock_model .get_instructions_for_model .return_value = None
580- mock_model .get_system_message_for_model .return_value = None
581596
582597 team = Team (
583598 name = "Validated Team" ,
0 commit comments