-
Notifications
You must be signed in to change notification settings - Fork 709
Expand file tree
/
Copy pathtest_foundry_integration.py
More file actions
280 lines (221 loc) · 11.6 KB
/
Copy pathtest_foundry_integration.py
File metadata and controls
280 lines (221 loc) · 11.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
"""
Integration tests for FoundryAgentTemplate functionality.
Tests Bing search, RAG, MCP tools, and Code Interpreter capabilities.
"""
# pylint: disable=E0401, E0611, C0413
import asyncio
import os
import sys
import time
from pathlib import Path
import pytest
# Add the backend path to sys.path so we can import v3 modules
backend_path = Path(__file__).parent.parent.parent / "backend"
sys.path.insert(0, str(backend_path))
# Now import from the v3 package
from v3.magentic_agents.foundry_agent import FoundryAgentTemplate
from v3.magentic_agents.models.agent_models import (BingConfig, MCPConfig,
SearchConfig)
class TestFoundryAgentIntegration:
"""Integration tests for FoundryAgentTemplate capabilities."""
def get_agent_configs(self):
"""Create agent configurations from environment variables."""
# These will return None if env vars are missing, which is expected behavior
mcp_config = MCPConfig.from_env()
bing_config = BingConfig.from_env()
search_config = SearchConfig.from_env()
return {
'mcp_config': mcp_config,
'bing_config': bing_config,
'search_config': search_config
}
# Creating agent for each test for now due to "E Failed: Bing search test failed
# with error: The thread could not be created due to an error response from the
# service" error when trying to use Pytest fixtures to share agent instance.
async def create_foundry_agent(self):
"""Create and initialize a FoundryAgentTemplate for testing."""
agent_configs = self.get_agent_configs()
agent_name = "TestFoundryAgent"
agent_description = "A comprehensive research assistant for integration testing"
agent_instructions = (
"You are an Enhanced Research Agent with multiple information sources:\n"
"1. Bing search for current web information and recent events\n"
"2. Azure AI Search for internal knowledge base and documents\n"
"3. MCP tools for specialized data access\n\n"
"Search Strategy:\n"
"- Use Azure AI Search first for internal/proprietary information\n"
"- Use Bing search for current events, recent news, and public information\n"
"- Always cite your sources and specify which search method provided the information\n"
"- Provide comprehensive answers combining multiple sources when relevant\n"
"- Ask for clarification only if the task is genuinely ambiguous"
)
model_deployment_name = "gpt-4.1"
agent = FoundryAgentTemplate(
agent_name=agent_name,
agent_description=agent_description,
agent_instructions=agent_instructions,
model_deployment_name=model_deployment_name,
enable_code_interpreter=True,
mcp_config=agent_configs['mcp_config'],
bing_config=agent_configs['bing_config'],
search_config=agent_configs['search_config']
)
await agent.open()
return agent
async def _get_agent_response(self, agent: FoundryAgentTemplate, query: str) -> str:
"""Helper method to get complete response from agent."""
response_parts = []
async for message in agent.invoke(query):
if hasattr(message, 'content'):
# Handle different content types properly
content = message.content
if hasattr(content, 'text'):
response_parts.append(str(content.text))
elif isinstance(content, list):
for item in content:
if hasattr(item, 'text'):
response_parts.append(str(item.text))
else:
response_parts.append(str(item))
else:
response_parts.append(str(content))
else:
response_parts.append(str(message))
return ''.join(response_parts)
@pytest.mark.asyncio
async def test_bing_search_functionality(self):
"""Test that Bing search is working correctly."""
agent = await self.create_foundry_agent()
try:
if not agent.bing or not agent.bing.connection_name:
pytest.skip("Bing configuration not available - skipping Bing search test")
query = "Please try to get todays weather in Redmond WA using a bing search. If this succeeds, please just respond with yes, if it does not, please respond with no "
response = await self._get_agent_response(agent, query)
# Check that we got a meaningful response
assert 'yes' in response.lower(), \
"Responsed that the agent could not perform the Bing search"
except Exception as e:
pytest.fail(f"Bing search test failed with error: {e}")
finally:
await agent.close()
@pytest.mark.asyncio
async def test_rag_search_functionality(self):
"""Test that Azure AI Search RAG is working correctly."""
""" Note: This test may fail without clear cause. Search usage seems to be intermittent. """
agent = await self.create_foundry_agent()
try:
if not agent.search or not agent.search.connection_name:
pytest.skip("Azure AI Search configuration not available - skipping RAG test")
# Starter query is necessary to increase likely hood of correct response
starter = "Do you have access to internal documents?"
starter_response = await self._get_agent_response(agent, starter)
query = "Can you tell me about any incident reports that have affected the warehouses??"
response = await self._get_agent_response(agent, query)
# Check for the expected indicator of successful RAG retrieval
assert any(indicator in response.lower() for indicator in [
'heavy rain', 'Logistics', '2023-07-18'
]), f"Expected code execution indicators in response, got: {response}\n" \
f"Starter response - can you see RAG?: {starter_response}"
except Exception as e:
pytest.fail(f"RAG search test failed with error: {e}")
finally:
await agent.close()
@pytest.mark.asyncio
async def test_mcp_functionality(self):
"""Test that MCP tools are working correctly."""
agent = await self.create_foundry_agent()
try:
if not agent.mcp or not agent.mcp.url:
pytest.skip("MCP configuration not available - skipping MCP test")
query = "Please greet Tom"
response = await self._get_agent_response(agent, query)
# Check for the expected MCP response indicator
assert "Hello from MACAE MCP Server, Tom" in response, \
f"Expected 'Hello from MACAE MCP Server, Tom' in MCP response, got: {response}"
except Exception as e:
pytest.fail(f"MCP test failed with error: {e}")
finally:
await agent.close()
@pytest.mark.asyncio
async def test_code_interpreter_functionality(self):
"""Test that Code Interpreter is working correctly."""
agent = await self.create_foundry_agent()
try:
if not agent.enable_code_interpreter:
pytest.skip("Code Interpreter not enabled - skipping code interpreter test")
query = "Can you write and execute Python code to calculate the factorial of 5?"
response = await self._get_agent_response(agent, query)
# Check for indicators that code was executed
assert any(indicator in response.lower() for indicator in [
'factorial', '120', 'code', 'python', 'execution', 'result'
]), f"Expected code execution indicators in response, got: {response}"
# The factorial of 5 is 120
assert "120" in response, \
f"Expected factorial result '120' in response, got: {response}"
except Exception as e:
pytest.fail(f"Code Interpreter test failed with error: {e}")
finally:
await agent.close()
@pytest.mark.asyncio
async def test_agent_initialization(self):
"""Test that the agent initializes correctly with available configurations."""
agent = await self.create_foundry_agent()
try:
assert agent.agent_name == "TestFoundryAgent"
assert agent._agent is not None, "Agent should be initialized"
# Check that tools were configured based on available configs
if agent.mcp and agent.mcp.url:
assert agent.mcp_plugin is not None, "MCP plugin should be available"
except Exception as e:
pytest.fail(f"Agent initialization test failed with error: {e}")
finally:
await agent.close()
@pytest.mark.asyncio
async def test_agent_handles_missing_configs_gracefully(self):
"""Test that agent handles missing configurations without crashing."""
model_deployment_name = "gpt-4.1"
agent = FoundryAgentTemplate(
agent_name="TestAgent",
agent_description="Test agent",
agent_instructions="Test instructions",
model_deployment_name=model_deployment_name,
enable_code_interpreter=False,
mcp_config=None,
bing_config=None,
search_config=None
)
try:
await agent.open()
# Should still be able to handle basic queries even without tools
response = await self._get_agent_response(agent, "Hello, how are you?")
assert len(response) > 0, "Should get some response even without tools"
except Exception as e:
pytest.fail(f"Agent should handle missing configs gracefully, but failed with: {e}")
finally:
await agent.close()
@pytest.mark.asyncio
async def test_multiple_capabilities_together(self):
"""Test that multiple capabilities can work together in a single query."""
agent = await self.create_foundry_agent()
try:
# Only run if we have at least some capabilities available
available_capabilities = []
if agent.bing and agent.bing.connection_name:
available_capabilities.append("Bing")
if agent.search and agent.search.connection_name:
available_capabilities.append("RAG")
if agent.mcp and agent.mcp.url:
available_capabilities.append("MCP")
if len(available_capabilities) < 2:
pytest.skip("Need at least 2 capabilities for integration test")
query = "Can you search for recent AI news and also check if you have any internal documents about AI?"
response = await self._get_agent_response(agent, query)
# Should get a comprehensive response that may use multiple tools
assert len(response) > 100, "Should get comprehensive response using multiple capabilities"
except Exception as e:
pytest.fail(f"Multi-capability test failed with error: {e}")
finally:
await agent.close()
if __name__ == "__main__":
"""Run the tests directly for debugging."""
pytest.main([__file__, "-v", "-s"])