[DELELTE OLD TESTS] [Tests][Agent] [Updated][Tests][Structs] [Agent Improvement][Fallback method] [N feature n samples]
parent
6f65541e8d
commit
6f4803ef0e
@ -0,0 +1,150 @@
|
||||
name: Test Main Features
|
||||
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'tests/test_main_features.py'
|
||||
- 'swarms/**'
|
||||
- 'requirements.txt'
|
||||
- 'pyproject.toml'
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
paths:
|
||||
- 'tests/test_main_features.py'
|
||||
- 'swarms/**'
|
||||
- 'requirements.txt'
|
||||
- 'pyproject.toml'
|
||||
branches: [ "master" ]
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
|
||||
jobs:
|
||||
test-main-features:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Cache pip dependencies
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pip-
|
||||
|
||||
- name: Install Poetry
|
||||
run: |
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Configure Poetry
|
||||
run: |
|
||||
poetry config virtualenvs.create true
|
||||
poetry config virtualenvs.in-project true
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
poetry install --with test --no-dev
|
||||
|
||||
- name: Set up environment variables
|
||||
run: |
|
||||
echo "OPENAI_API_KEY=${{ secrets.OPENAI_API_KEY }}" >> $GITHUB_ENV
|
||||
echo "ANTHROPIC_API_KEY=${{ secrets.ANTHROPIC_API_KEY }}" >> $GITHUB_ENV
|
||||
echo "GOOGLE_API_KEY=${{ secrets.GOOGLE_API_KEY }}" >> $GITHUB_ENV
|
||||
echo "COHERE_API_KEY=${{ secrets.COHERE_API_KEY }}" >> $GITHUB_ENV
|
||||
echo "HUGGINGFACE_API_KEY=${{ secrets.HUGGINGFACE_API_KEY }}" >> $GITHUB_ENV
|
||||
echo "REPLICATE_API_KEY=${{ secrets.REPLICATE_API_KEY }}" >> $GITHUB_ENV
|
||||
echo "TOGETHER_API_KEY=${{ secrets.TOGETHER_API_KEY }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run Main Features Tests
|
||||
run: |
|
||||
cd /Users/swarms_wd/Desktop/research/swarms
|
||||
poetry run python tests/test_main_features.py
|
||||
|
||||
- name: Upload test results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: test-results
|
||||
path: test_runs/
|
||||
retention-days: 7
|
||||
|
||||
- name: Comment on PR with test results
|
||||
if: github.event_name == 'pull_request' && always()
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
try {
|
||||
// Look for test result files
|
||||
const testRunsDir = 'test_runs';
|
||||
if (fs.existsSync(testRunsDir)) {
|
||||
const files = fs.readdirSync(testRunsDir);
|
||||
const latestReport = files
|
||||
.filter(f => f.endsWith('.md'))
|
||||
.sort()
|
||||
.pop();
|
||||
|
||||
if (latestReport) {
|
||||
const reportPath = path.join(testRunsDir, latestReport);
|
||||
const reportContent = fs.readFileSync(reportPath, 'utf8');
|
||||
|
||||
// Extract summary from markdown
|
||||
const summaryMatch = reportContent.match(/## Summary\n\n(.*?)\n\n## Detailed Results/s);
|
||||
const summary = summaryMatch ? summaryMatch[1] : 'Test results available in artifacts';
|
||||
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: `## Main Features Test Results\n\n${summary}\n\n📊 Full test report available in artifacts.`
|
||||
});
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
console.log('Could not read test results:', error.message);
|
||||
}
|
||||
|
||||
test-coverage:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
needs: test-main-features
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.10"
|
||||
|
||||
- name: Install Poetry
|
||||
run: |
|
||||
curl -sSL https://install.python-poetry.org | python3 -
|
||||
echo "$HOME/.local/bin" >> $GITHUB_PATH
|
||||
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
poetry install --with test
|
||||
|
||||
- name: Run coverage analysis
|
||||
run: |
|
||||
poetry run pytest tests/test_main_features.py --cov=swarms --cov-report=xml --cov-report=html
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
file: ./coverage.xml
|
||||
flags: main-features
|
||||
name: main-features-coverage
|
||||
fail_ci_if_error: false
|
||||
@ -1,114 +0,0 @@
|
||||
from unittest.mock import MagicMock
|
||||
import unittest
|
||||
from swarms.structs.agent import Agent
|
||||
from swarms.tools.tool_parse_exec import parse_and_execute_json
|
||||
|
||||
# Mock parse_and_execute_json for testing
|
||||
parse_and_execute_json = MagicMock()
|
||||
parse_and_execute_json.return_value = {
|
||||
"tool_name": "calculator",
|
||||
"args": {"numbers": [2, 2]},
|
||||
"output": "4",
|
||||
}
|
||||
|
||||
|
||||
class TestAgentLogging(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.mock_tokenizer = MagicMock()
|
||||
self.mock_tokenizer.count_tokens.return_value = 100
|
||||
|
||||
self.mock_short_memory = MagicMock()
|
||||
self.mock_short_memory.get_memory_stats.return_value = {
|
||||
"message_count": 2
|
||||
}
|
||||
|
||||
self.mock_long_memory = MagicMock()
|
||||
self.mock_long_memory.get_memory_stats.return_value = {
|
||||
"item_count": 5
|
||||
}
|
||||
|
||||
self.agent = Agent(
|
||||
tokenizer=self.mock_tokenizer,
|
||||
short_memory=self.mock_short_memory,
|
||||
long_term_memory=self.mock_long_memory,
|
||||
)
|
||||
|
||||
def test_log_step_metadata_basic(self):
|
||||
log_result = self.agent.log_step_metadata(
|
||||
1, "Test prompt", "Test response"
|
||||
)
|
||||
|
||||
self.assertIn("step_id", log_result)
|
||||
self.assertIn("timestamp", log_result)
|
||||
self.assertIn("tokens", log_result)
|
||||
self.assertIn("memory_usage", log_result)
|
||||
|
||||
self.assertEqual(log_result["tokens"]["total"], 200)
|
||||
|
||||
def test_log_step_metadata_no_long_term_memory(self):
|
||||
self.agent.long_term_memory = None
|
||||
log_result = self.agent.log_step_metadata(
|
||||
1, "prompt", "response"
|
||||
)
|
||||
self.assertEqual(log_result["memory_usage"]["long_term"], {})
|
||||
|
||||
def test_log_step_metadata_timestamp(self):
|
||||
log_result = self.agent.log_step_metadata(
|
||||
1, "prompt", "response"
|
||||
)
|
||||
self.assertIn("timestamp", log_result)
|
||||
|
||||
def test_token_counting_integration(self):
|
||||
self.mock_tokenizer.count_tokens.side_effect = [150, 250]
|
||||
log_result = self.agent.log_step_metadata(
|
||||
1, "prompt", "response"
|
||||
)
|
||||
|
||||
self.assertEqual(log_result["tokens"]["total"], 400)
|
||||
|
||||
def test_agent_output_updating(self):
|
||||
initial_total_tokens = sum(
|
||||
step["tokens"]["total"]
|
||||
for step in self.agent.agent_output.steps
|
||||
)
|
||||
self.agent.log_step_metadata(1, "prompt", "response")
|
||||
|
||||
final_total_tokens = sum(
|
||||
step["tokens"]["total"]
|
||||
for step in self.agent.agent_output.steps
|
||||
)
|
||||
self.assertEqual(
|
||||
final_total_tokens - initial_total_tokens, 200
|
||||
)
|
||||
self.assertEqual(len(self.agent.agent_output.steps), 1)
|
||||
|
||||
|
||||
class TestAgentLoggingIntegration(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.agent = Agent(agent_name="test-agent")
|
||||
|
||||
def test_full_logging_cycle(self):
|
||||
task = "Test task"
|
||||
max_loops = 1
|
||||
|
||||
result = self.agent._run(task, max_loops=max_loops)
|
||||
|
||||
self.assertIsInstance(result, dict)
|
||||
self.assertIn("steps", result)
|
||||
self.assertIsInstance(result["steps"], list)
|
||||
self.assertEqual(len(result["steps"]), max_loops)
|
||||
|
||||
if result["steps"]:
|
||||
step = result["steps"][0]
|
||||
self.assertIn("step_id", step)
|
||||
self.assertIn("timestamp", step)
|
||||
self.assertIn("task", step)
|
||||
self.assertIn("response", step)
|
||||
self.assertEqual(step["task"], task)
|
||||
self.assertEqual(step["response"], "Response for loop 1")
|
||||
|
||||
self.assertTrue(len(self.agent.agent_output.steps) > 0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@ -1,267 +0,0 @@
|
||||
import unittest
|
||||
from unittest.mock import patch
|
||||
from swarms import create_agents_from_yaml
|
||||
import os
|
||||
|
||||
|
||||
class TestCreateAgentsFromYaml(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
# Mock the environment variable for API key
|
||||
os.environ["OPENAI_API_KEY"] = "fake-api-key"
|
||||
|
||||
# Mock agent configuration YAML content
|
||||
self.valid_yaml_content = """
|
||||
agents:
|
||||
- agent_name: "Financial-Analysis-Agent"
|
||||
model:
|
||||
openai_api_key: "fake-api-key"
|
||||
model_name: "gpt-4o-mini"
|
||||
temperature: 0.1
|
||||
max_tokens: 2000
|
||||
system_prompt: "financial_agent_sys_prompt"
|
||||
max_loops: 1
|
||||
autosave: true
|
||||
dashboard: false
|
||||
verbose: true
|
||||
dynamic_temperature_enabled: true
|
||||
saved_state_path: "finance_agent.json"
|
||||
user_name: "swarms_corp"
|
||||
retry_attempts: 1
|
||||
context_length: 200000
|
||||
return_step_meta: false
|
||||
output_type: "str"
|
||||
task: "How can I establish a ROTH IRA to buy stocks and get a tax break?"
|
||||
|
||||
- agent_name: "Stock-Analysis-Agent"
|
||||
model:
|
||||
openai_api_key: "fake-api-key"
|
||||
model_name: "gpt-4o-mini"
|
||||
temperature: 0.2
|
||||
max_tokens: 1500
|
||||
system_prompt: "stock_agent_sys_prompt"
|
||||
max_loops: 2
|
||||
autosave: true
|
||||
dashboard: false
|
||||
verbose: true
|
||||
dynamic_temperature_enabled: false
|
||||
saved_state_path: "stock_agent.json"
|
||||
user_name: "stock_user"
|
||||
retry_attempts: 3
|
||||
context_length: 150000
|
||||
return_step_meta: true
|
||||
output_type: "json"
|
||||
task: "What is the best strategy for long-term stock investment?"
|
||||
"""
|
||||
|
||||
@patch(
|
||||
"builtins.open",
|
||||
new_callable=unittest.mock.mock_open,
|
||||
read_data="",
|
||||
)
|
||||
@patch("yaml.safe_load")
|
||||
def test_create_agents_return_agents(
|
||||
self, mock_safe_load, mock_open
|
||||
):
|
||||
# Mock YAML content parsing
|
||||
mock_safe_load.return_value = {
|
||||
"agents": [
|
||||
{
|
||||
"agent_name": "Financial-Analysis-Agent",
|
||||
"model": {
|
||||
"openai_api_key": "fake-api-key",
|
||||
"model_name": "gpt-4o-mini",
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
},
|
||||
"system_prompt": "financial_agent_sys_prompt",
|
||||
"max_loops": 1,
|
||||
"autosave": True,
|
||||
"dashboard": False,
|
||||
"verbose": True,
|
||||
"dynamic_temperature_enabled": True,
|
||||
"saved_state_path": "finance_agent.json",
|
||||
"user_name": "swarms_corp",
|
||||
"retry_attempts": 1,
|
||||
"context_length": 200000,
|
||||
"return_step_meta": False,
|
||||
"output_type": "str",
|
||||
"task": "How can I establish a ROTH IRA to buy stocks and get a tax break?",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Test if agents are returned correctly
|
||||
agents = create_agents_from_yaml(
|
||||
"fake_yaml_path.yaml", return_type="agents"
|
||||
)
|
||||
self.assertEqual(len(agents), 1)
|
||||
self.assertEqual(
|
||||
agents[0].agent_name, "Financial-Analysis-Agent"
|
||||
)
|
||||
|
||||
@patch(
|
||||
"builtins.open",
|
||||
new_callable=unittest.mock.mock_open,
|
||||
read_data="",
|
||||
)
|
||||
@patch("yaml.safe_load")
|
||||
@patch(
|
||||
"swarms.Agent.run", return_value="Task completed successfully"
|
||||
)
|
||||
def test_create_agents_return_tasks(
|
||||
self, mock_agent_run, mock_safe_load, mock_open
|
||||
):
|
||||
# Mock YAML content parsing
|
||||
mock_safe_load.return_value = {
|
||||
"agents": [
|
||||
{
|
||||
"agent_name": "Financial-Analysis-Agent",
|
||||
"model": {
|
||||
"openai_api_key": "fake-api-key",
|
||||
"model_name": "gpt-4o-mini",
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
},
|
||||
"system_prompt": "financial_agent_sys_prompt",
|
||||
"max_loops": 1,
|
||||
"autosave": True,
|
||||
"dashboard": False,
|
||||
"verbose": True,
|
||||
"dynamic_temperature_enabled": True,
|
||||
"saved_state_path": "finance_agent.json",
|
||||
"user_name": "swarms_corp",
|
||||
"retry_attempts": 1,
|
||||
"context_length": 200000,
|
||||
"return_step_meta": False,
|
||||
"output_type": "str",
|
||||
"task": "How can I establish a ROTH IRA to buy stocks and get a tax break?",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Test if tasks are executed and results are returned
|
||||
task_results = create_agents_from_yaml(
|
||||
"fake_yaml_path.yaml", return_type="tasks"
|
||||
)
|
||||
self.assertEqual(len(task_results), 1)
|
||||
self.assertEqual(
|
||||
task_results[0]["agent_name"], "Financial-Analysis-Agent"
|
||||
)
|
||||
self.assertIsNotNone(task_results[0]["output"])
|
||||
|
||||
@patch(
|
||||
"builtins.open",
|
||||
new_callable=unittest.mock.mock_open,
|
||||
read_data="",
|
||||
)
|
||||
@patch("yaml.safe_load")
|
||||
def test_create_agents_return_both(
|
||||
self, mock_safe_load, mock_open
|
||||
):
|
||||
# Mock YAML content parsing
|
||||
mock_safe_load.return_value = {
|
||||
"agents": [
|
||||
{
|
||||
"agent_name": "Financial-Analysis-Agent",
|
||||
"model": {
|
||||
"openai_api_key": "fake-api-key",
|
||||
"model_name": "gpt-4o-mini",
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
},
|
||||
"system_prompt": "financial_agent_sys_prompt",
|
||||
"max_loops": 1,
|
||||
"autosave": True,
|
||||
"dashboard": False,
|
||||
"verbose": True,
|
||||
"dynamic_temperature_enabled": True,
|
||||
"saved_state_path": "finance_agent.json",
|
||||
"user_name": "swarms_corp",
|
||||
"retry_attempts": 1,
|
||||
"context_length": 200000,
|
||||
"return_step_meta": False,
|
||||
"output_type": "str",
|
||||
"task": "How can I establish a ROTH IRA to buy stocks and get a tax break?",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Test if both agents and tasks are returned
|
||||
agents, task_results = create_agents_from_yaml(
|
||||
"fake_yaml_path.yaml", return_type="both"
|
||||
)
|
||||
self.assertEqual(len(agents), 1)
|
||||
self.assertEqual(len(task_results), 1)
|
||||
self.assertEqual(
|
||||
agents[0].agent_name, "Financial-Analysis-Agent"
|
||||
)
|
||||
self.assertIsNotNone(task_results[0]["output"])
|
||||
|
||||
@patch(
|
||||
"builtins.open",
|
||||
new_callable=unittest.mock.mock_open,
|
||||
read_data="",
|
||||
)
|
||||
@patch("yaml.safe_load")
|
||||
def test_missing_agents_in_yaml(self, mock_safe_load, mock_open):
|
||||
# Mock YAML content with missing "agents" key
|
||||
mock_safe_load.return_value = {}
|
||||
|
||||
# Test if the function raises an error for missing "agents" key
|
||||
with self.assertRaises(ValueError) as context:
|
||||
create_agents_from_yaml(
|
||||
"fake_yaml_path.yaml", return_type="agents"
|
||||
)
|
||||
self.assertTrue(
|
||||
"The YAML configuration does not contain 'agents'."
|
||||
in str(context.exception)
|
||||
)
|
||||
|
||||
@patch(
|
||||
"builtins.open",
|
||||
new_callable=unittest.mock.mock_open,
|
||||
read_data="",
|
||||
)
|
||||
@patch("yaml.safe_load")
|
||||
def test_invalid_return_type(self, mock_safe_load, mock_open):
|
||||
# Mock YAML content parsing
|
||||
mock_safe_load.return_value = {
|
||||
"agents": [
|
||||
{
|
||||
"agent_name": "Financial-Analysis-Agent",
|
||||
"model": {
|
||||
"openai_api_key": "fake-api-key",
|
||||
"model_name": "gpt-4o-mini",
|
||||
"temperature": 0.1,
|
||||
"max_tokens": 2000,
|
||||
},
|
||||
"system_prompt": "financial_agent_sys_prompt",
|
||||
"max_loops": 1,
|
||||
"autosave": True,
|
||||
"dashboard": False,
|
||||
"verbose": True,
|
||||
"dynamic_temperature_enabled": True,
|
||||
"saved_state_path": "finance_agent.json",
|
||||
"user_name": "swarms_corp",
|
||||
"retry_attempts": 1,
|
||||
"context_length": 200000,
|
||||
"return_step_meta": False,
|
||||
"output_type": "str",
|
||||
"task": "How can I establish a ROTH IRA to buy stocks and get a tax break?",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
# Test if an error is raised for invalid return_type
|
||||
with self.assertRaises(ValueError) as context:
|
||||
create_agents_from_yaml(
|
||||
"fake_yaml_path.yaml", return_type="invalid_type"
|
||||
)
|
||||
self.assertTrue(
|
||||
"Invalid return_type" in str(context.exception)
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
@ -1,184 +0,0 @@
|
||||
import sys
|
||||
|
||||
|
||||
from swarms import Agent
|
||||
|
||||
|
||||
def test_combined_llm_args():
|
||||
"""Test that llm_args, tools_list_dictionary, and MCP tools can be combined."""
|
||||
|
||||
# Mock tools list dictionary
|
||||
tools_list = [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "test_function",
|
||||
"description": "A test function",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"test_param": {
|
||||
"type": "string",
|
||||
"description": "A test parameter",
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
|
||||
# Mock llm_args with Azure OpenAI specific parameters
|
||||
llm_args = {
|
||||
"api_version": "2024-02-15-preview",
|
||||
"base_url": "https://your-resource.openai.azure.com/",
|
||||
"api_key": "your-api-key",
|
||||
}
|
||||
|
||||
try:
|
||||
# Test 1: Only llm_args
|
||||
print("Testing Agent with only llm_args...")
|
||||
Agent(
|
||||
agent_name="test-agent-1",
|
||||
model_name="gpt-4o-mini",
|
||||
llm_args=llm_args,
|
||||
)
|
||||
print("✓ Agent with only llm_args created successfully")
|
||||
|
||||
# Test 2: Only tools_list_dictionary
|
||||
print("Testing Agent with only tools_list_dictionary...")
|
||||
Agent(
|
||||
agent_name="test-agent-2",
|
||||
model_name="gpt-4o-mini",
|
||||
tools_list_dictionary=tools_list,
|
||||
)
|
||||
print(
|
||||
"✓ Agent with only tools_list_dictionary created successfully"
|
||||
)
|
||||
|
||||
# Test 3: Combined llm_args and tools_list_dictionary
|
||||
print(
|
||||
"Testing Agent with combined llm_args and tools_list_dictionary..."
|
||||
)
|
||||
agent3 = Agent(
|
||||
agent_name="test-agent-3",
|
||||
model_name="gpt-4o-mini",
|
||||
llm_args=llm_args,
|
||||
tools_list_dictionary=tools_list,
|
||||
)
|
||||
print(
|
||||
"✓ Agent with combined llm_args and tools_list_dictionary created successfully"
|
||||
)
|
||||
|
||||
# Test 4: Verify that the LLM instance has the correct configuration
|
||||
print("Verifying LLM configuration...")
|
||||
|
||||
# Check that agent3 has both llm_args and tools configured
|
||||
assert agent3.llm_args == llm_args, "llm_args not preserved"
|
||||
assert (
|
||||
agent3.tools_list_dictionary == tools_list
|
||||
), "tools_list_dictionary not preserved"
|
||||
|
||||
# Check that the LLM instance was created
|
||||
assert agent3.llm is not None, "LLM instance not created"
|
||||
|
||||
print("✓ LLM configuration verified successfully")
|
||||
|
||||
# Test 5: Test that the LLM can be called (without actually making API calls)
|
||||
print("Testing LLM call preparation...")
|
||||
try:
|
||||
# This should not fail due to configuration issues
|
||||
# We're not actually calling the API, just testing the setup
|
||||
print("✓ LLM call preparation successful")
|
||||
except Exception as e:
|
||||
print(f"✗ LLM call preparation failed: {e}")
|
||||
return False
|
||||
|
||||
print(
|
||||
"\n🎉 All tests passed! The LiteLLM initialization fix is working correctly."
|
||||
)
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Test failed: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
def test_azure_openai_example():
|
||||
"""Test the Azure OpenAI example with api_version parameter."""
|
||||
|
||||
print("\nTesting Azure OpenAI example with api_version...")
|
||||
|
||||
try:
|
||||
# Create an agent with Azure OpenAI configuration
|
||||
agent = Agent(
|
||||
agent_name="azure-test-agent",
|
||||
model_name="azure/gpt-4o",
|
||||
llm_args={
|
||||
"api_version": "2024-02-15-preview",
|
||||
"base_url": "https://your-resource.openai.azure.com/",
|
||||
"api_key": "your-api-key",
|
||||
},
|
||||
tools_list_dictionary=[
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "get_weather",
|
||||
"description": "Get weather information",
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"location": {
|
||||
"type": "string",
|
||||
"description": "The city and state",
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
)
|
||||
|
||||
print(
|
||||
"✓ Azure OpenAI agent with combined parameters created successfully"
|
||||
)
|
||||
|
||||
# Verify configuration
|
||||
assert agent.llm_args is not None, "llm_args not set"
|
||||
assert (
|
||||
"api_version" in agent.llm_args
|
||||
), "api_version not in llm_args"
|
||||
assert (
|
||||
agent.tools_list_dictionary is not None
|
||||
), "tools_list_dictionary not set"
|
||||
assert (
|
||||
len(agent.tools_list_dictionary) > 0
|
||||
), "tools_list_dictionary is empty"
|
||||
|
||||
print("✓ Azure OpenAI configuration verified")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"✗ Azure OpenAI test failed: {e}")
|
||||
import traceback
|
||||
|
||||
traceback.print_exc()
|
||||
return False
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🧪 Testing LiteLLM initialization fix...")
|
||||
|
||||
success1 = test_combined_llm_args()
|
||||
success2 = test_azure_openai_example()
|
||||
|
||||
if success1 and success2:
|
||||
print("\n✅ All tests passed! The fix is working correctly.")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(
|
||||
"\n❌ Some tests failed. Please check the implementation."
|
||||
)
|
||||
sys.exit(1)
|
||||
@ -1,62 +0,0 @@
|
||||
from swarms.structs.agent import Agent
|
||||
|
||||
|
||||
def test_llm_handling_args_kwargs():
|
||||
"""Test that llm_handling properly handles both args and kwargs."""
|
||||
|
||||
# Create an agent instance
|
||||
agent = Agent(
|
||||
agent_name="test-agent",
|
||||
model_name="gpt-4o-mini",
|
||||
temperature=0.7,
|
||||
max_tokens=1000,
|
||||
)
|
||||
|
||||
# Test 1: Call llm_handling with kwargs
|
||||
print("Test 1: Testing kwargs handling...")
|
||||
try:
|
||||
# This should work and add the kwargs to additional_args
|
||||
agent.llm_handling(top_p=0.9, frequency_penalty=0.1)
|
||||
print("✓ kwargs handling works")
|
||||
except Exception as e:
|
||||
print(f"✗ kwargs handling failed: {e}")
|
||||
|
||||
# Test 2: Call llm_handling with args (dictionary)
|
||||
print("\nTest 2: Testing args handling with dictionary...")
|
||||
try:
|
||||
# This should merge the dictionary into additional_args
|
||||
additional_config = {
|
||||
"presence_penalty": 0.2,
|
||||
"logit_bias": {"123": 1},
|
||||
}
|
||||
agent.llm_handling(additional_config)
|
||||
print("✓ args handling with dictionary works")
|
||||
except Exception as e:
|
||||
print(f"✗ args handling with dictionary failed: {e}")
|
||||
|
||||
# Test 3: Call llm_handling with both args and kwargs
|
||||
print("\nTest 3: Testing both args and kwargs...")
|
||||
try:
|
||||
# This should handle both
|
||||
additional_config = {"presence_penalty": 0.3}
|
||||
agent.llm_handling(
|
||||
additional_config, top_p=0.8, frequency_penalty=0.2
|
||||
)
|
||||
print("✓ combined args and kwargs handling works")
|
||||
except Exception as e:
|
||||
print(f"✗ combined args and kwargs handling failed: {e}")
|
||||
|
||||
# Test 4: Call llm_handling with non-dictionary args
|
||||
print("\nTest 4: Testing non-dictionary args...")
|
||||
try:
|
||||
# This should store args under 'additional_args' key
|
||||
agent.llm_handling(
|
||||
"some_string", 123, ["list", "of", "items"]
|
||||
)
|
||||
print("✓ non-dictionary args handling works")
|
||||
except Exception as e:
|
||||
print(f"✗ non-dictionary args handling failed: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_llm_handling_args_kwargs()
|
||||
@ -1,230 +0,0 @@
|
||||
from unittest.mock import Mock, patch
|
||||
import pytest
|
||||
|
||||
from transformers import AutoModelForCausalLM, AutoTokenizer
|
||||
|
||||
from swarms import ToolAgent
|
||||
from swarms.agents.exceptions import (
|
||||
ToolExecutionError,
|
||||
ToolNotFoundError,
|
||||
ToolParameterError,
|
||||
)
|
||||
|
||||
|
||||
def test_tool_agent_init():
|
||||
model = Mock(spec=AutoModelForCausalLM)
|
||||
tokenizer = Mock(spec=AutoTokenizer)
|
||||
json_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"age": {"type": "number"},
|
||||
"is_student": {"type": "boolean"},
|
||||
"courses": {"type": "array", "items": {"type": "string"}},
|
||||
},
|
||||
}
|
||||
name = "Test Agent"
|
||||
description = "This is a test agent"
|
||||
|
||||
agent = ToolAgent(
|
||||
name, description, model, tokenizer, json_schema
|
||||
)
|
||||
|
||||
assert agent.name == name
|
||||
assert agent.description == description
|
||||
assert agent.model == model
|
||||
assert agent.tokenizer == tokenizer
|
||||
assert agent.json_schema == json_schema
|
||||
|
||||
|
||||
@patch.object(ToolAgent, "run")
|
||||
def test_tool_agent_run(mock_run):
|
||||
model = Mock(spec=AutoModelForCausalLM)
|
||||
tokenizer = Mock(spec=AutoTokenizer)
|
||||
json_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"age": {"type": "number"},
|
||||
"is_student": {"type": "boolean"},
|
||||
"courses": {"type": "array", "items": {"type": "string"}},
|
||||
},
|
||||
}
|
||||
name = "Test Agent"
|
||||
description = "This is a test agent"
|
||||
task = (
|
||||
"Generate a person's information based on the following"
|
||||
" schema:"
|
||||
)
|
||||
|
||||
agent = ToolAgent(
|
||||
name, description, model, tokenizer, json_schema
|
||||
)
|
||||
agent.run(task)
|
||||
|
||||
mock_run.assert_called_once_with(task)
|
||||
|
||||
|
||||
def test_tool_agent_init_with_kwargs():
|
||||
model = Mock(spec=AutoModelForCausalLM)
|
||||
tokenizer = Mock(spec=AutoTokenizer)
|
||||
json_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"age": {"type": "number"},
|
||||
"is_student": {"type": "boolean"},
|
||||
"courses": {"type": "array", "items": {"type": "string"}},
|
||||
},
|
||||
}
|
||||
name = "Test Agent"
|
||||
description = "This is a test agent"
|
||||
|
||||
kwargs = {
|
||||
"debug": True,
|
||||
"max_array_length": 20,
|
||||
"max_number_tokens": 12,
|
||||
"temperature": 0.5,
|
||||
"max_string_token_length": 20,
|
||||
}
|
||||
|
||||
agent = ToolAgent(
|
||||
name, description, model, tokenizer, json_schema, **kwargs
|
||||
)
|
||||
|
||||
assert agent.name == name
|
||||
assert agent.description == description
|
||||
assert agent.model == model
|
||||
assert agent.tokenizer == tokenizer
|
||||
assert agent.json_schema == json_schema
|
||||
assert agent.debug == kwargs["debug"]
|
||||
assert agent.max_array_length == kwargs["max_array_length"]
|
||||
assert agent.max_number_tokens == kwargs["max_number_tokens"]
|
||||
assert agent.temperature == kwargs["temperature"]
|
||||
assert (
|
||||
agent.max_string_token_length
|
||||
== kwargs["max_string_token_length"]
|
||||
)
|
||||
|
||||
|
||||
def test_tool_agent_initialization():
|
||||
"""Test tool agent initialization with valid parameters."""
|
||||
agent = ToolAgent(
|
||||
model_name="test-model", temperature=0.7, max_tokens=1000
|
||||
)
|
||||
assert agent.model_name == "test-model"
|
||||
assert agent.temperature == 0.7
|
||||
assert agent.max_tokens == 1000
|
||||
assert agent.retry_attempts == 3
|
||||
assert agent.retry_interval == 1.0
|
||||
|
||||
|
||||
def test_tool_agent_initialization_error():
|
||||
"""Test tool agent initialization with invalid model."""
|
||||
with pytest.raises(ToolExecutionError) as exc_info:
|
||||
ToolAgent(model_name="invalid-model")
|
||||
assert "model_initialization" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_tool_validation():
|
||||
"""Test tool parameter validation."""
|
||||
tools_list = [
|
||||
{
|
||||
"name": "test_tool",
|
||||
"parameters": [
|
||||
{"name": "required_param", "required": True},
|
||||
{"name": "optional_param", "required": False},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
agent = ToolAgent(tools_list_dictionary=tools_list)
|
||||
|
||||
# Test missing required parameter
|
||||
with pytest.raises(ToolParameterError) as exc_info:
|
||||
agent._validate_tool("test_tool", {})
|
||||
assert "Missing required parameters" in str(exc_info.value)
|
||||
|
||||
# Test valid parameters
|
||||
agent._validate_tool("test_tool", {"required_param": "value"})
|
||||
|
||||
# Test non-existent tool
|
||||
with pytest.raises(ToolNotFoundError) as exc_info:
|
||||
agent._validate_tool("non_existent_tool", {})
|
||||
assert "Tool 'non_existent_tool' not found" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_retry_mechanism():
|
||||
"""Test retry mechanism for failed operations."""
|
||||
mock_llm = Mock()
|
||||
mock_llm.generate.side_effect = [
|
||||
Exception("First attempt failed"),
|
||||
Exception("Second attempt failed"),
|
||||
Mock(outputs=[Mock(text="Success")]),
|
||||
]
|
||||
|
||||
agent = ToolAgent(model_name="test-model")
|
||||
agent.llm = mock_llm
|
||||
|
||||
# Test successful retry
|
||||
result = agent.run("test task")
|
||||
assert result == "Success"
|
||||
assert mock_llm.generate.call_count == 3
|
||||
|
||||
# Test all retries failing
|
||||
mock_llm.generate.side_effect = Exception("All attempts failed")
|
||||
with pytest.raises(ToolExecutionError) as exc_info:
|
||||
agent.run("test task")
|
||||
assert "All attempts failed" in str(exc_info.value)
|
||||
|
||||
|
||||
def test_batched_execution():
|
||||
"""Test batched execution with error handling."""
|
||||
mock_llm = Mock()
|
||||
mock_llm.generate.side_effect = [
|
||||
Mock(outputs=[Mock(text="Success 1")]),
|
||||
Exception("Task 2 failed"),
|
||||
Mock(outputs=[Mock(text="Success 3")]),
|
||||
]
|
||||
|
||||
agent = ToolAgent(model_name="test-model")
|
||||
agent.llm = mock_llm
|
||||
|
||||
tasks = ["Task 1", "Task 2", "Task 3"]
|
||||
results = agent.batched_run(tasks)
|
||||
|
||||
assert len(results) == 3
|
||||
assert results[0] == "Success 1"
|
||||
assert "Error" in results[1]
|
||||
assert results[2] == "Success 3"
|
||||
|
||||
|
||||
def test_prompt_preparation():
|
||||
"""Test prompt preparation with and without system prompt."""
|
||||
# Test without system prompt
|
||||
agent = ToolAgent()
|
||||
prompt = agent._prepare_prompt("test task")
|
||||
assert prompt == "User: test task\nAssistant:"
|
||||
|
||||
# Test with system prompt
|
||||
agent = ToolAgent(system_prompt="You are a helpful assistant")
|
||||
prompt = agent._prepare_prompt("test task")
|
||||
assert (
|
||||
prompt
|
||||
== "You are a helpful assistant\n\nUser: test task\nAssistant:"
|
||||
)
|
||||
|
||||
|
||||
def test_tool_execution_error_handling():
|
||||
"""Test error handling during tool execution."""
|
||||
agent = ToolAgent(model_name="test-model")
|
||||
agent.llm = None # Simulate uninitialized LLM
|
||||
|
||||
with pytest.raises(ToolExecutionError) as exc_info:
|
||||
agent.run("test task")
|
||||
assert "LLM not initialized" in str(exc_info.value)
|
||||
|
||||
# Test with invalid parameters
|
||||
with pytest.raises(ToolExecutionError) as exc_info:
|
||||
agent.run("test task", invalid_param="value")
|
||||
assert "Error running task" in str(exc_info.value)
|
||||
@ -1,171 +0,0 @@
|
||||
from time import perf_counter_ns
|
||||
import psutil
|
||||
import os
|
||||
from rich.panel import Panel
|
||||
from rich.console import Console
|
||||
from rich.table import Table
|
||||
from statistics import mean, median, stdev, variance
|
||||
from swarms.structs.agent import Agent
|
||||
from swarms.prompts.finance_agent_sys_prompt import (
|
||||
FINANCIAL_AGENT_SYS_PROMPT,
|
||||
)
|
||||
|
||||
|
||||
def get_memory_stats(memory_readings):
|
||||
"""Calculate memory statistics"""
|
||||
return {
|
||||
"peak": max(memory_readings),
|
||||
"min": min(memory_readings),
|
||||
"mean": mean(memory_readings),
|
||||
"median": median(memory_readings),
|
||||
"stdev": (
|
||||
stdev(memory_readings) if len(memory_readings) > 1 else 0
|
||||
),
|
||||
"variance": (
|
||||
variance(memory_readings)
|
||||
if len(memory_readings) > 1
|
||||
else 0
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def get_time_stats(times):
|
||||
"""Calculate time statistics"""
|
||||
return {
|
||||
"total": sum(times),
|
||||
"mean": mean(times),
|
||||
"median": median(times),
|
||||
"min": min(times),
|
||||
"max": max(times),
|
||||
"stdev": stdev(times) if len(times) > 1 else 0,
|
||||
"variance": variance(times) if len(times) > 1 else 0,
|
||||
}
|
||||
|
||||
|
||||
def benchmark_multiple_agents(num_agents=100):
|
||||
console = Console()
|
||||
init_times = []
|
||||
memory_readings = []
|
||||
process = psutil.Process(os.getpid())
|
||||
|
||||
# Create benchmark tables
|
||||
time_table = Table(title="Time Statistics")
|
||||
time_table.add_column("Metric", style="cyan")
|
||||
time_table.add_column("Value", style="green")
|
||||
|
||||
memory_table = Table(title="Memory Statistics")
|
||||
memory_table.add_column("Metric", style="cyan")
|
||||
memory_table.add_column("Value", style="green")
|
||||
|
||||
initial_memory = process.memory_info().rss / 1024
|
||||
start_total_time = perf_counter_ns()
|
||||
|
||||
# Initialize agents and measure performance
|
||||
for i in range(num_agents):
|
||||
start_time = perf_counter_ns()
|
||||
|
||||
Agent(
|
||||
agent_name=f"Financial-Analysis-Agent-{i}",
|
||||
agent_description="Personal finance advisor agent",
|
||||
system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
max_loops=2,
|
||||
model_name="gpt-4o-mini",
|
||||
dynamic_temperature_enabled=True,
|
||||
interactive=False,
|
||||
)
|
||||
|
||||
init_time = (perf_counter_ns() - start_time) / 1_000_000
|
||||
init_times.append(init_time)
|
||||
|
||||
current_memory = process.memory_info().rss / 1024
|
||||
memory_readings.append(current_memory - initial_memory)
|
||||
|
||||
if (i + 1) % 10 == 0:
|
||||
console.print(
|
||||
f"Created {i + 1} agents...", style="bold blue"
|
||||
)
|
||||
|
||||
total_elapsed_time = (
|
||||
perf_counter_ns() - start_total_time
|
||||
) / 1_000_000
|
||||
|
||||
# Calculate statistics
|
||||
time_stats = get_time_stats(init_times)
|
||||
memory_stats = get_memory_stats(memory_readings)
|
||||
|
||||
# Add time measurements
|
||||
time_table.add_row(
|
||||
"Total Wall Time", f"{total_elapsed_time:.2f} ms"
|
||||
)
|
||||
time_table.add_row(
|
||||
"Total Init Time", f"{time_stats['total']:.2f} ms"
|
||||
)
|
||||
time_table.add_row(
|
||||
"Average Init Time", f"{time_stats['mean']:.2f} ms"
|
||||
)
|
||||
time_table.add_row(
|
||||
"Median Init Time", f"{time_stats['median']:.2f} ms"
|
||||
)
|
||||
time_table.add_row("Fastest Init", f"{time_stats['min']:.2f} ms")
|
||||
time_table.add_row("Slowest Init", f"{time_stats['max']:.2f} ms")
|
||||
time_table.add_row(
|
||||
"Std Deviation", f"{time_stats['stdev']:.2f} ms"
|
||||
)
|
||||
time_table.add_row(
|
||||
"Variance", f"{time_stats['variance']:.4f} ms²"
|
||||
)
|
||||
time_table.add_row(
|
||||
"Throughput",
|
||||
f"{(num_agents/total_elapsed_time) * 1000:.2f} agents/second",
|
||||
)
|
||||
time_table.add_row(
|
||||
"Agents per Minute",
|
||||
f"{(num_agents/total_elapsed_time) * 60000:.0f} agents/minute",
|
||||
)
|
||||
|
||||
# Add memory measurements
|
||||
memory_table.add_row(
|
||||
"Peak Memory Usage", f"{memory_stats['peak']:.2f} KB"
|
||||
)
|
||||
memory_table.add_row(
|
||||
"Minimum Memory Usage", f"{memory_stats['min']:.2f} KB"
|
||||
)
|
||||
memory_table.add_row(
|
||||
"Average Memory Usage", f"{memory_stats['mean']:.2f} KB"
|
||||
)
|
||||
memory_table.add_row(
|
||||
"Median Memory Usage", f"{memory_stats['median']:.2f} KB"
|
||||
)
|
||||
memory_table.add_row(
|
||||
"Memory Std Deviation", f"{memory_stats['stdev']:.2f} KB"
|
||||
)
|
||||
memory_table.add_row(
|
||||
"Memory Variance", f"{memory_stats['variance']:.2f} KB²"
|
||||
)
|
||||
memory_table.add_row(
|
||||
"Avg Memory Per Agent",
|
||||
f"{memory_stats['mean']/num_agents:.2f} KB",
|
||||
)
|
||||
|
||||
# Create and display panels
|
||||
time_panel = Panel(
|
||||
time_table,
|
||||
title="Time Benchmark Results",
|
||||
border_style="blue",
|
||||
padding=(1, 2),
|
||||
)
|
||||
|
||||
memory_panel = Panel(
|
||||
memory_table,
|
||||
title="Memory Benchmark Results",
|
||||
border_style="green",
|
||||
padding=(1, 2),
|
||||
)
|
||||
|
||||
console.print(time_panel)
|
||||
console.print("\n")
|
||||
console.print(memory_panel)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
benchmark_multiple_agents(1000)
|
||||
@ -1,284 +0,0 @@
|
||||
import asyncio
|
||||
import concurrent.futures
|
||||
import json
|
||||
import os
|
||||
import psutil
|
||||
import datetime
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Any, Optional
|
||||
from swarms.structs.agent import Agent
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class AgentBenchmark:
|
||||
def __init__(
|
||||
self,
|
||||
num_iterations: int = 5,
|
||||
output_dir: str = "benchmark_results",
|
||||
):
|
||||
self.num_iterations = num_iterations
|
||||
self.output_dir = Path(output_dir)
|
||||
self.output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# Use process pool for CPU-bound tasks
|
||||
self.process_pool = concurrent.futures.ProcessPoolExecutor(
|
||||
max_workers=min(os.cpu_count(), 4)
|
||||
)
|
||||
|
||||
# Use thread pool for I/O-bound tasks
|
||||
self.thread_pool = concurrent.futures.ThreadPoolExecutor(
|
||||
max_workers=min(os.cpu_count() * 2, 8)
|
||||
)
|
||||
|
||||
self.default_queries = [
|
||||
"Conduct an analysis of the best real undervalued ETFs",
|
||||
"What are the top performing tech stocks this quarter?",
|
||||
"Analyze current market trends in renewable energy sector",
|
||||
"Compare Bitcoin and Ethereum investment potential",
|
||||
"Evaluate the risk factors in emerging markets",
|
||||
]
|
||||
|
||||
self.agent = self._initialize_agent()
|
||||
self.process = psutil.Process()
|
||||
|
||||
# Cache for storing repeated query results
|
||||
self._query_cache = {}
|
||||
|
||||
def _initialize_agent(self) -> Agent:
|
||||
return Agent(
|
||||
agent_name="Financial-Analysis-Agent",
|
||||
agent_description="Personal finance advisor agent",
|
||||
# system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
max_loops=1,
|
||||
model_name="gpt-4o-mini",
|
||||
dynamic_temperature_enabled=True,
|
||||
interactive=False,
|
||||
)
|
||||
|
||||
def _get_system_metrics(self) -> Dict[str, float]:
|
||||
# Optimized system metrics collection
|
||||
return {
|
||||
"cpu_percent": self.process.cpu_percent(),
|
||||
"memory_mb": self.process.memory_info().rss / 1024 / 1024,
|
||||
}
|
||||
|
||||
def _calculate_statistics(
|
||||
self, values: List[float]
|
||||
) -> Dict[str, float]:
|
||||
if not values:
|
||||
return {}
|
||||
|
||||
sorted_values = sorted(values)
|
||||
n = len(sorted_values)
|
||||
mean_val = sum(values) / n
|
||||
|
||||
stats = {
|
||||
"mean": mean_val,
|
||||
"median": sorted_values[n // 2],
|
||||
"min": sorted_values[0],
|
||||
"max": sorted_values[-1],
|
||||
}
|
||||
|
||||
# Only calculate stdev if we have enough values
|
||||
if n > 1:
|
||||
stats["std_dev"] = (
|
||||
sum((x - mean_val) ** 2 for x in values) / n
|
||||
) ** 0.5
|
||||
|
||||
return {k: round(v, 3) for k, v in stats.items()}
|
||||
|
||||
async def process_iteration(
|
||||
self, query: str, iteration: int
|
||||
) -> Dict[str, Any]:
|
||||
"""Process a single iteration of a query"""
|
||||
try:
|
||||
# Check cache for repeated queries
|
||||
cache_key = f"{query}_{iteration}"
|
||||
if cache_key in self._query_cache:
|
||||
return self._query_cache[cache_key]
|
||||
|
||||
iteration_start = datetime.datetime.now()
|
||||
pre_metrics = self._get_system_metrics()
|
||||
|
||||
# Run the agent
|
||||
try:
|
||||
self.agent.run(query)
|
||||
success = True
|
||||
except Exception as e:
|
||||
str(e)
|
||||
success = False
|
||||
|
||||
execution_time = (
|
||||
datetime.datetime.now() - iteration_start
|
||||
).total_seconds()
|
||||
post_metrics = self._get_system_metrics()
|
||||
|
||||
result = {
|
||||
"execution_time": execution_time,
|
||||
"success": success,
|
||||
"pre_metrics": pre_metrics,
|
||||
"post_metrics": post_metrics,
|
||||
"iteration_data": {
|
||||
"iteration": iteration + 1,
|
||||
"execution_time": round(execution_time, 3),
|
||||
"success": success,
|
||||
"system_metrics": {
|
||||
"pre": pre_metrics,
|
||||
"post": post_metrics,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
# Cache the result
|
||||
self._query_cache[cache_key] = result
|
||||
return result
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error in iteration {iteration}: {e}")
|
||||
raise
|
||||
|
||||
async def run_benchmark(
|
||||
self, queries: Optional[List[str]] = None
|
||||
) -> Dict[str, Any]:
|
||||
"""Run the benchmark asynchronously"""
|
||||
queries = queries or self.default_queries
|
||||
benchmark_data = {
|
||||
"metadata": {
|
||||
"timestamp": datetime.datetime.now().isoformat(),
|
||||
"num_iterations": self.num_iterations,
|
||||
"agent_config": {
|
||||
"model_name": self.agent.model_name,
|
||||
"max_loops": self.agent.max_loops,
|
||||
},
|
||||
},
|
||||
"results": {},
|
||||
}
|
||||
|
||||
async def process_query(query: str):
|
||||
query_results = {
|
||||
"execution_times": [],
|
||||
"system_metrics": [],
|
||||
"iterations": [],
|
||||
}
|
||||
|
||||
# Process iterations concurrently
|
||||
tasks = [
|
||||
self.process_iteration(query, i)
|
||||
for i in range(self.num_iterations)
|
||||
]
|
||||
iteration_results = await asyncio.gather(*tasks)
|
||||
|
||||
for result in iteration_results:
|
||||
query_results["execution_times"].append(
|
||||
result["execution_time"]
|
||||
)
|
||||
query_results["system_metrics"].append(
|
||||
result["post_metrics"]
|
||||
)
|
||||
query_results["iterations"].append(
|
||||
result["iteration_data"]
|
||||
)
|
||||
|
||||
# Calculate statistics
|
||||
query_results["statistics"] = {
|
||||
"execution_time": self._calculate_statistics(
|
||||
query_results["execution_times"]
|
||||
),
|
||||
"memory_usage": self._calculate_statistics(
|
||||
[
|
||||
m["memory_mb"]
|
||||
for m in query_results["system_metrics"]
|
||||
]
|
||||
),
|
||||
"cpu_usage": self._calculate_statistics(
|
||||
[
|
||||
m["cpu_percent"]
|
||||
for m in query_results["system_metrics"]
|
||||
]
|
||||
),
|
||||
}
|
||||
|
||||
return query, query_results
|
||||
|
||||
# Execute all queries concurrently
|
||||
query_tasks = [process_query(query) for query in queries]
|
||||
query_results = await asyncio.gather(*query_tasks)
|
||||
|
||||
for query, results in query_results:
|
||||
benchmark_data["results"][query] = results
|
||||
|
||||
return benchmark_data
|
||||
|
||||
def save_results(self, benchmark_data: Dict[str, Any]) -> str:
|
||||
"""Save benchmark results efficiently"""
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = (
|
||||
self.output_dir / f"benchmark_results_{timestamp}.json"
|
||||
)
|
||||
|
||||
# Write results in a single operation
|
||||
with open(filename, "w") as f:
|
||||
json.dump(benchmark_data, f, indent=2)
|
||||
|
||||
logger.info(f"Benchmark results saved to: {filename}")
|
||||
return str(filename)
|
||||
|
||||
def print_summary(self, results: Dict[str, Any]):
|
||||
"""Print a summary of the benchmark results"""
|
||||
print("\n=== Benchmark Summary ===")
|
||||
for query, data in results["results"].items():
|
||||
print(f"\nQuery: {query[:50]}...")
|
||||
stats = data["statistics"]["execution_time"]
|
||||
print(f"Average time: {stats['mean']:.2f}s")
|
||||
print(
|
||||
f"Memory usage (avg): {data['statistics']['memory_usage']['mean']:.1f}MB"
|
||||
)
|
||||
print(
|
||||
f"CPU usage (avg): {data['statistics']['cpu_usage']['mean']:.1f}%"
|
||||
)
|
||||
|
||||
async def run_with_timeout(
|
||||
self, timeout: int = 300
|
||||
) -> Dict[str, Any]:
|
||||
"""Run benchmark with timeout"""
|
||||
try:
|
||||
return await asyncio.wait_for(
|
||||
self.run_benchmark(), timeout
|
||||
)
|
||||
except asyncio.TimeoutError:
|
||||
logger.error(
|
||||
f"Benchmark timed out after {timeout} seconds"
|
||||
)
|
||||
raise
|
||||
|
||||
def cleanup(self):
|
||||
"""Cleanup resources"""
|
||||
self.process_pool.shutdown()
|
||||
self.thread_pool.shutdown()
|
||||
self._query_cache.clear()
|
||||
|
||||
|
||||
async def main():
|
||||
try:
|
||||
# Create and run benchmark
|
||||
benchmark = AgentBenchmark(num_iterations=1)
|
||||
|
||||
# Run benchmark with timeout
|
||||
results = await benchmark.run_with_timeout(timeout=300)
|
||||
|
||||
# Save results
|
||||
benchmark.save_results(results)
|
||||
|
||||
# Print summary
|
||||
benchmark.print_summary(results)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Benchmark failed: {e}")
|
||||
finally:
|
||||
# Cleanup resources
|
||||
benchmark.cleanup()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run the async main function
|
||||
asyncio.run(main())
|
||||
@ -1,318 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import sys
|
||||
import traceback
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
import psutil
|
||||
import requests
|
||||
from loguru import logger
|
||||
from swarm_models import OpenAIChat
|
||||
|
||||
from swarms.structs.agent import Agent
|
||||
|
||||
|
||||
@dataclass
|
||||
class SwarmSystemInfo:
|
||||
"""System information for Swarms issue reports."""
|
||||
|
||||
os_name: str
|
||||
os_version: str
|
||||
python_version: str
|
||||
cpu_usage: float
|
||||
memory_usage: float
|
||||
disk_usage: float
|
||||
swarms_version: str # Added Swarms version tracking
|
||||
cuda_available: bool # Added CUDA availability check
|
||||
gpu_info: Optional[str] # Added GPU information
|
||||
|
||||
|
||||
class SwarmsIssueReporter:
|
||||
"""
|
||||
Production-grade GitHub issue reporter specifically designed for the Swarms library.
|
||||
Automatically creates detailed issues for the https://github.com/kyegomez/swarms repository.
|
||||
|
||||
Features:
|
||||
- Swarms-specific error categorization
|
||||
- Automatic version and dependency tracking
|
||||
- CUDA and GPU information collection
|
||||
- Integration with Swarms logging system
|
||||
- Detailed environment information
|
||||
"""
|
||||
|
||||
REPO_OWNER = "kyegomez"
|
||||
REPO_NAME = "swarms"
|
||||
ISSUE_CATEGORIES = {
|
||||
"agent": ["agent", "automation"],
|
||||
"memory": ["memory", "storage"],
|
||||
"tool": ["tools", "integration"],
|
||||
"llm": ["llm", "model"],
|
||||
"performance": ["performance", "optimization"],
|
||||
"compatibility": ["compatibility", "environment"],
|
||||
}
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
github_token: str,
|
||||
rate_limit: int = 10,
|
||||
rate_period: int = 3600,
|
||||
log_file: str = "swarms_issues.log",
|
||||
enable_duplicate_check: bool = True,
|
||||
):
|
||||
"""
|
||||
Initialize the Swarms Issue Reporter.
|
||||
|
||||
Args:
|
||||
github_token (str): GitHub personal access token
|
||||
rate_limit (int): Maximum number of issues to create per rate_period
|
||||
rate_period (int): Time period for rate limiting in seconds
|
||||
log_file (str): Path to log file
|
||||
enable_duplicate_check (bool): Whether to check for duplicate issues
|
||||
"""
|
||||
self.github_token = github_token
|
||||
self.rate_limit = rate_limit
|
||||
self.rate_period = rate_period
|
||||
self.enable_duplicate_check = enable_duplicate_check
|
||||
self.github_token = os.getenv("GITHUB_API_KEY")
|
||||
|
||||
# Initialize logging
|
||||
log_path = os.path.join(os.getcwd(), "logs", log_file)
|
||||
os.makedirs(os.path.dirname(log_path), exist_ok=True)
|
||||
|
||||
# Issue tracking
|
||||
self.issues_created = []
|
||||
self.last_issue_time = datetime.now()
|
||||
|
||||
def _get_swarms_version(self) -> str:
|
||||
"""Get the installed version of Swarms."""
|
||||
try:
|
||||
import swarms
|
||||
|
||||
return swarms.__version__
|
||||
except:
|
||||
return "Unknown"
|
||||
|
||||
def _get_system_info(self) -> SwarmSystemInfo:
|
||||
"""Collect system and Swarms-specific information."""
|
||||
|
||||
return SwarmSystemInfo(
|
||||
os_name=platform.system(),
|
||||
os_version=platform.version(),
|
||||
python_version=sys.version,
|
||||
cpu_usage=psutil.cpu_percent(),
|
||||
memory_usage=psutil.virtual_memory().percent,
|
||||
disk_usage=psutil.disk_usage("/").percent,
|
||||
swarms_version=self._get_swarms_version(),
|
||||
)
|
||||
|
||||
def _categorize_error(
|
||||
self, error: Exception, context: Dict
|
||||
) -> List[str]:
|
||||
"""Categorize the error and return appropriate labels."""
|
||||
error_str = str(error).lower()
|
||||
type(error).__name__
|
||||
|
||||
labels = ["bug", "automated"]
|
||||
|
||||
# Check error message and context for category keywords
|
||||
for (
|
||||
category,
|
||||
category_labels,
|
||||
) in self.ISSUE_CATEGORIES.items():
|
||||
if any(
|
||||
keyword in error_str for keyword in category_labels
|
||||
):
|
||||
labels.extend(category_labels)
|
||||
break
|
||||
|
||||
# Add severity label based on error type
|
||||
if issubclass(type(error), (SystemError, MemoryError)):
|
||||
labels.append("severity:critical")
|
||||
elif issubclass(type(error), (ValueError, TypeError)):
|
||||
labels.append("severity:medium")
|
||||
else:
|
||||
labels.append("severity:low")
|
||||
|
||||
return list(set(labels)) # Remove duplicates
|
||||
|
||||
def _format_swarms_issue_body(
|
||||
self,
|
||||
error: Exception,
|
||||
system_info: SwarmSystemInfo,
|
||||
context: Dict,
|
||||
) -> str:
|
||||
"""Format the issue body with Swarms-specific information."""
|
||||
return f"""
|
||||
## Swarms Error Report
|
||||
- **Error Type**: {type(error).__name__}
|
||||
- **Error Message**: {str(error)}
|
||||
- **Swarms Version**: {system_info.swarms_version}
|
||||
|
||||
## Environment Information
|
||||
- **OS**: {system_info.os_name} {system_info.os_version}
|
||||
- **Python Version**: {system_info.python_version}
|
||||
- **CUDA Available**: {system_info.cuda_available}
|
||||
- **GPU**: {system_info.gpu_info or "N/A"}
|
||||
- **CPU Usage**: {system_info.cpu_usage}%
|
||||
- **Memory Usage**: {system_info.memory_usage}%
|
||||
- **Disk Usage**: {system_info.disk_usage}%
|
||||
|
||||
## Stack Trace
|
||||
{traceback.format_exc()}
|
||||
|
||||
## Context
|
||||
{json.dumps(context, indent=2)}
|
||||
|
||||
## Dependencies
|
||||
{self._get_dependencies_info()}
|
||||
|
||||
## Time of Occurrence
|
||||
{datetime.now().isoformat()}
|
||||
|
||||
---
|
||||
*This issue was automatically generated by SwarmsIssueReporter*
|
||||
"""
|
||||
|
||||
def _get_dependencies_info(self) -> str:
|
||||
"""Get information about installed dependencies."""
|
||||
try:
|
||||
import pkg_resources
|
||||
|
||||
deps = []
|
||||
for dist in pkg_resources.working_set:
|
||||
deps.append(f"- {dist.key} {dist.version}")
|
||||
return "\n".join(deps)
|
||||
except:
|
||||
return "Unable to fetch dependency information"
|
||||
|
||||
# First, add this method to your SwarmsIssueReporter class
|
||||
def _check_rate_limit(self) -> bool:
|
||||
"""Check if we're within rate limits."""
|
||||
now = datetime.now()
|
||||
time_diff = (now - self.last_issue_time).total_seconds()
|
||||
|
||||
if (
|
||||
len(self.issues_created) >= self.rate_limit
|
||||
and time_diff < self.rate_period
|
||||
):
|
||||
logger.warning("Rate limit exceeded for issue creation")
|
||||
return False
|
||||
|
||||
# Clean up old issues from tracking
|
||||
self.issues_created = [
|
||||
time
|
||||
for time in self.issues_created
|
||||
if (now - time).total_seconds() < self.rate_period
|
||||
]
|
||||
|
||||
return True
|
||||
|
||||
def report_swarms_issue(
|
||||
self,
|
||||
error: Exception,
|
||||
agent: Optional[Agent] = None,
|
||||
context: Dict[str, Any] = None,
|
||||
priority: str = "normal",
|
||||
) -> Optional[int]:
|
||||
"""
|
||||
Report a Swarms-specific issue to GitHub.
|
||||
|
||||
Args:
|
||||
error (Exception): The exception to report
|
||||
agent (Optional[Agent]): The Swarms agent instance that encountered the error
|
||||
context (Dict[str, Any]): Additional context about the error
|
||||
priority (str): Issue priority ("low", "normal", "high", "critical")
|
||||
|
||||
Returns:
|
||||
Optional[int]: Issue number if created successfully
|
||||
"""
|
||||
try:
|
||||
if not self._check_rate_limit():
|
||||
logger.warning(
|
||||
"Skipping issue creation due to rate limit"
|
||||
)
|
||||
return None
|
||||
|
||||
# Collect system information
|
||||
system_info = self._get_system_info()
|
||||
|
||||
# Prepare context with agent information if available
|
||||
full_context = context or {}
|
||||
if agent:
|
||||
full_context.update(
|
||||
{
|
||||
"agent_name": agent.agent_name,
|
||||
"agent_description": agent.agent_description,
|
||||
"max_loops": agent.max_loops,
|
||||
"context_length": agent.context_length,
|
||||
}
|
||||
)
|
||||
|
||||
# Create issue title
|
||||
title = f"[{type(error).__name__}] {str(error)[:100]}"
|
||||
if agent:
|
||||
title = f"[Agent: {agent.agent_name}] {title}"
|
||||
|
||||
# Get appropriate labels
|
||||
labels = self._categorize_error(error, full_context)
|
||||
labels.append(f"priority:{priority}")
|
||||
|
||||
# Create the issue
|
||||
url = f"https://api.github.com/repos/{self.REPO_OWNER}/{self.REPO_NAME}/issues"
|
||||
data = {
|
||||
"title": title,
|
||||
"body": self._format_swarms_issue_body(
|
||||
error, system_info, full_context
|
||||
),
|
||||
"labels": labels,
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
url,
|
||||
headers={
|
||||
"Authorization": f"token {self.github_token}"
|
||||
},
|
||||
json=data,
|
||||
)
|
||||
response.raise_for_status()
|
||||
|
||||
issue_number = response.json()["number"]
|
||||
logger.info(
|
||||
f"Successfully created Swarms issue #{issue_number}"
|
||||
)
|
||||
|
||||
return issue_number
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating Swarms issue: {str(e)}")
|
||||
return None
|
||||
|
||||
|
||||
# Setup the reporter with your GitHub token
|
||||
reporter = SwarmsIssueReporter(
|
||||
github_token=os.getenv("GITHUB_API_KEY")
|
||||
)
|
||||
|
||||
|
||||
# Force an error to test the reporter
|
||||
try:
|
||||
# This will raise an error since the input isn't valid
|
||||
# Create an agent that might have issues
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(agent_name="Test-Agent", max_loops=1)
|
||||
|
||||
result = agent.run(None)
|
||||
|
||||
raise ValueError("test")
|
||||
except Exception as e:
|
||||
# Report the issue
|
||||
issue_number = reporter.report_swarms_issue(
|
||||
error=e,
|
||||
agent=agent,
|
||||
context={"task": "test_run"},
|
||||
priority="high",
|
||||
)
|
||||
print(f"Created issue number: {issue_number}")
|
||||
@ -1,180 +0,0 @@
|
||||
import requests
|
||||
import datetime
|
||||
from typing import List, Dict, Tuple
|
||||
from loguru import logger
|
||||
from swarms import Agent
|
||||
from swarm_models import OpenAIChat
|
||||
|
||||
# GitHub API Configurations
|
||||
GITHUB_REPO = "kyegomez/swarms" # Swarms GitHub repository
|
||||
GITHUB_API_URL = f"https://api.github.com/repos/{GITHUB_REPO}/commits"
|
||||
|
||||
|
||||
# Step 1: Fetch the latest commits from GitHub
|
||||
def fetch_latest_commits(
|
||||
repo_url: str, limit: int = 5
|
||||
) -> List[Dict[str, str]]:
|
||||
"""
|
||||
Fetch the latest commits from a public GitHub repository.
|
||||
"""
|
||||
logger.info(
|
||||
f"Fetching the latest {limit} commits from {repo_url}"
|
||||
)
|
||||
try:
|
||||
params = {"per_page": limit}
|
||||
response = requests.get(repo_url, params=params)
|
||||
response.raise_for_status()
|
||||
|
||||
commits = response.json()
|
||||
commit_data = []
|
||||
|
||||
for commit in commits:
|
||||
commit_data.append(
|
||||
{
|
||||
"sha": commit["sha"][:7], # Short commit hash
|
||||
"author": commit["commit"]["author"]["name"],
|
||||
"message": commit["commit"]["message"],
|
||||
"date": commit["commit"]["author"]["date"],
|
||||
}
|
||||
)
|
||||
|
||||
logger.success("Successfully fetched commit data")
|
||||
return commit_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error fetching commits: {e}")
|
||||
raise
|
||||
|
||||
|
||||
# Step 2: Format commits and fetch current time
|
||||
def format_commits_with_time(
|
||||
commits: List[Dict[str, str]],
|
||||
) -> Tuple[str, str]:
|
||||
"""
|
||||
Format commit data into a readable string and return current time.
|
||||
"""
|
||||
current_time = datetime.datetime.now().strftime(
|
||||
"%Y-%m-%d %H:%M:%S"
|
||||
)
|
||||
logger.info(f"Formatting commits at {current_time}")
|
||||
|
||||
commit_summary = "\n".join(
|
||||
[
|
||||
f"- `{commit['sha']}` by {commit['author']} on {commit['date']}: {commit['message']}"
|
||||
for commit in commits
|
||||
]
|
||||
)
|
||||
|
||||
logger.success("Commits formatted successfully")
|
||||
return current_time, commit_summary
|
||||
|
||||
|
||||
# Step 3: Build a dynamic system prompt
|
||||
def build_custom_system_prompt(
|
||||
current_time: str, commit_summary: str
|
||||
) -> str:
|
||||
"""
|
||||
Build a dynamic system prompt with the current time and commit summary.
|
||||
"""
|
||||
logger.info("Building the custom system prompt for the agent")
|
||||
prompt = f"""
|
||||
You are a software analyst tasked with summarizing the latest commits from the Swarms GitHub repository.
|
||||
|
||||
The current time is **{current_time}**.
|
||||
|
||||
Here are the latest commits:
|
||||
{commit_summary}
|
||||
|
||||
**Your task**:
|
||||
1. Summarize the changes into a clear and concise table in **markdown format**.
|
||||
2. Highlight the key improvements and fixes.
|
||||
3. End your output with the token `<DONE>`.
|
||||
|
||||
Make sure the table includes the following columns: Commit SHA, Author, Date, and Commit Message.
|
||||
"""
|
||||
logger.success("System prompt created successfully")
|
||||
return prompt
|
||||
|
||||
|
||||
# Step 4: Initialize the Agent
|
||||
def initialize_agent() -> Agent:
|
||||
"""
|
||||
Initialize the Swarms agent with OpenAI model.
|
||||
"""
|
||||
logger.info("Initializing the agent with GPT-4o")
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
|
||||
agent = Agent(
|
||||
agent_name="Commit-Summarization-Agent",
|
||||
agent_description="Fetch and summarize GitHub commits for Swarms repository.",
|
||||
system_prompt="", # Will set dynamically
|
||||
max_loops=1,
|
||||
llm=model,
|
||||
dynamic_temperature_enabled=True,
|
||||
user_name="Kye",
|
||||
retry_attempts=3,
|
||||
context_length=8192,
|
||||
return_step_meta=False,
|
||||
output_type="str",
|
||||
auto_generate_prompt=False,
|
||||
max_tokens=4000,
|
||||
stopping_token="<DONE>",
|
||||
interactive=False,
|
||||
)
|
||||
logger.success("Agent initialized successfully")
|
||||
return agent
|
||||
|
||||
|
||||
# Step 5: Run the Agent with Data
|
||||
def summarize_commits_with_agent(agent: Agent, prompt: str) -> str:
|
||||
"""
|
||||
Pass the system prompt to the agent and fetch the result.
|
||||
"""
|
||||
logger.info("Sending data to the agent for summarization")
|
||||
try:
|
||||
result = agent.run(
|
||||
f"{prompt}",
|
||||
all_cores=True,
|
||||
)
|
||||
logger.success("Agent completed the summarization task")
|
||||
return result
|
||||
except Exception as e:
|
||||
logger.error(f"Agent encountered an error: {e}")
|
||||
raise
|
||||
|
||||
|
||||
# Main Execution
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
logger.info("Starting commit summarization process")
|
||||
|
||||
# Fetch latest commits
|
||||
latest_commits = fetch_latest_commits(GITHUB_API_URL, limit=5)
|
||||
|
||||
# Format commits and get current time
|
||||
current_time, commit_summary = format_commits_with_time(
|
||||
latest_commits
|
||||
)
|
||||
|
||||
# Build the custom system prompt
|
||||
custom_system_prompt = build_custom_system_prompt(
|
||||
current_time, commit_summary
|
||||
)
|
||||
|
||||
# Initialize agent
|
||||
agent = initialize_agent()
|
||||
|
||||
# Set the dynamic system prompt
|
||||
agent.system_prompt = custom_system_prompt
|
||||
|
||||
# Run the agent and summarize commits
|
||||
result = summarize_commits_with_agent(
|
||||
agent, custom_system_prompt
|
||||
)
|
||||
|
||||
# Print the result
|
||||
print("### Commit Summary in Markdown:")
|
||||
print(result)
|
||||
|
||||
except Exception as e:
|
||||
logger.critical(f"Process failed: {e}")
|
||||
@ -1,46 +0,0 @@
|
||||
import os
|
||||
import uuid
|
||||
from swarms import Agent
|
||||
from swarm_models import OpenAIChat
|
||||
from swarms.prompts.finance_agent_sys_prompt import (
|
||||
FINANCIAL_AGENT_SYS_PROMPT,
|
||||
)
|
||||
import time
|
||||
|
||||
start_time = time.time()
|
||||
|
||||
|
||||
# Get the OpenAI API key from the environment variable
|
||||
api_key = os.getenv("OPENAI_API_KEY")
|
||||
|
||||
# Create an instance of the OpenAIChat class
|
||||
model = OpenAIChat(
|
||||
api_key=api_key, model_name="gpt-4o-mini", temperature=0.1
|
||||
)
|
||||
|
||||
|
||||
agent = Agent(
|
||||
agent_name=f"{uuid.uuid4().hex}",
|
||||
system_prompt=FINANCIAL_AGENT_SYS_PROMPT,
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
autosave=True,
|
||||
dashboard=False,
|
||||
verbose=True,
|
||||
dynamic_temperature_enabled=True,
|
||||
saved_state_path=f"{uuid.uuid4().hex}",
|
||||
user_name="swarms_corp",
|
||||
retry_attempts=1,
|
||||
context_length=3000,
|
||||
return_step_meta=False,
|
||||
)
|
||||
|
||||
out = agent.run(
|
||||
"How can I establish a ROTH IRA to buy stocks and get a tax break? What are the criteria"
|
||||
)
|
||||
print(out)
|
||||
|
||||
end_time = time.time()
|
||||
|
||||
print(f"Execution time: {end_time - start_time} seconds")
|
||||
# Execution time: 9.922541856765747 seconds for the whole script
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,600 +0,0 @@
|
||||
import asyncio
|
||||
import json
|
||||
import os
|
||||
import tempfile
|
||||
import time
|
||||
|
||||
import yaml
|
||||
from swarm_models import OpenAIChat
|
||||
|
||||
from swarms import Agent
|
||||
|
||||
|
||||
def test_basic_agent_functionality():
|
||||
"""Test basic agent initialization and simple task execution"""
|
||||
print("\nTesting basic agent functionality...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(agent_name="Test-Agent", llm=model, max_loops=1)
|
||||
|
||||
response = agent.run("What is 2+2?")
|
||||
assert response is not None, "Agent response should not be None"
|
||||
|
||||
# Test agent properties
|
||||
assert (
|
||||
agent.agent_name == "Test-Agent"
|
||||
), "Agent name not set correctly"
|
||||
assert agent.max_loops == 1, "Max loops not set correctly"
|
||||
assert agent.llm is not None, "LLM not initialized"
|
||||
|
||||
print("✓ Basic agent functionality test passed")
|
||||
|
||||
|
||||
def test_memory_management():
|
||||
"""Test agent memory management functionality"""
|
||||
print("\nTesting memory management...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Memory-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
context_length=8192,
|
||||
)
|
||||
|
||||
# Test adding to memory
|
||||
agent.add_memory("Test memory entry")
|
||||
assert (
|
||||
"Test memory entry"
|
||||
in agent.short_memory.return_history_as_string()
|
||||
)
|
||||
|
||||
# Test memory query
|
||||
agent.memory_query("Test query")
|
||||
|
||||
# Test token counting
|
||||
tokens = agent.check_available_tokens()
|
||||
assert isinstance(tokens, int), "Token count should be an integer"
|
||||
|
||||
print("✓ Memory management test passed")
|
||||
|
||||
|
||||
def test_agent_output_formats():
|
||||
"""Test all available output formats"""
|
||||
print("\nTesting all output formats...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
test_task = "Say hello!"
|
||||
|
||||
output_types = {
|
||||
"str": str,
|
||||
"string": str,
|
||||
"list": str, # JSON string containing list
|
||||
"json": str, # JSON string
|
||||
"dict": dict,
|
||||
"yaml": str,
|
||||
}
|
||||
|
||||
for output_type, expected_type in output_types.items():
|
||||
agent = Agent(
|
||||
agent_name=f"{output_type.capitalize()}-Output-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
output_type=output_type,
|
||||
)
|
||||
|
||||
response = agent.run(test_task)
|
||||
assert (
|
||||
response is not None
|
||||
), f"{output_type} output should not be None"
|
||||
|
||||
if output_type == "yaml":
|
||||
# Verify YAML can be parsed
|
||||
try:
|
||||
yaml.safe_load(response)
|
||||
print(f"✓ {output_type} output valid")
|
||||
except yaml.YAMLError:
|
||||
assert False, f"Invalid YAML output for {output_type}"
|
||||
elif output_type in ["json", "list"]:
|
||||
# Verify JSON can be parsed
|
||||
try:
|
||||
json.loads(response)
|
||||
print(f"✓ {output_type} output valid")
|
||||
except json.JSONDecodeError:
|
||||
assert False, f"Invalid JSON output for {output_type}"
|
||||
|
||||
print("✓ Output formats test passed")
|
||||
|
||||
|
||||
def test_agent_state_management():
|
||||
"""Test comprehensive state management functionality"""
|
||||
print("\nTesting state management...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
|
||||
# Create temporary directory for test files
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
state_path = os.path.join(temp_dir, "agent_state.json")
|
||||
|
||||
# Create agent with initial state
|
||||
agent1 = Agent(
|
||||
agent_name="State-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
saved_state_path=state_path,
|
||||
)
|
||||
|
||||
# Add some data to the agent
|
||||
agent1.run("Remember this: Test message 1")
|
||||
agent1.add_memory("Test message 2")
|
||||
|
||||
# Save state
|
||||
agent1.save()
|
||||
assert os.path.exists(state_path), "State file not created"
|
||||
|
||||
# Create new agent and load state
|
||||
agent2 = Agent(
|
||||
agent_name="State-Test-Agent", llm=model, max_loops=1
|
||||
)
|
||||
agent2.load(state_path)
|
||||
|
||||
# Verify state loaded correctly
|
||||
history2 = agent2.short_memory.return_history_as_string()
|
||||
assert (
|
||||
"Test message 1" in history2
|
||||
), "State not loaded correctly"
|
||||
assert (
|
||||
"Test message 2" in history2
|
||||
), "Memory not loaded correctly"
|
||||
|
||||
# Test autosave functionality
|
||||
agent3 = Agent(
|
||||
agent_name="Autosave-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
saved_state_path=os.path.join(
|
||||
temp_dir, "autosave_state.json"
|
||||
),
|
||||
autosave=True,
|
||||
)
|
||||
|
||||
agent3.run("Test autosave")
|
||||
time.sleep(2) # Wait for autosave
|
||||
assert os.path.exists(
|
||||
os.path.join(temp_dir, "autosave_state.json")
|
||||
), "Autosave file not created"
|
||||
|
||||
print("✓ State management test passed")
|
||||
|
||||
|
||||
def test_agent_tools_and_execution():
|
||||
"""Test agent tool handling and execution"""
|
||||
print("\nTesting tools and execution...")
|
||||
|
||||
def sample_tool(x: int, y: int) -> int:
|
||||
"""Sample tool that adds two numbers"""
|
||||
return x + y
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Tools-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
tools=[sample_tool],
|
||||
)
|
||||
|
||||
# Test adding tools
|
||||
agent.add_tool(lambda x: x * 2)
|
||||
assert len(agent.tools) == 2, "Tool not added correctly"
|
||||
|
||||
# Test removing tools
|
||||
agent.remove_tool(sample_tool)
|
||||
assert len(agent.tools) == 1, "Tool not removed correctly"
|
||||
|
||||
# Test tool execution
|
||||
response = agent.run("Calculate 2 + 2 using the sample tool")
|
||||
assert response is not None, "Tool execution failed"
|
||||
|
||||
print("✓ Tools and execution test passed")
|
||||
|
||||
|
||||
def test_agent_concurrent_execution():
|
||||
"""Test agent concurrent execution capabilities"""
|
||||
print("\nTesting concurrent execution...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Concurrent-Test-Agent", llm=model, max_loops=1
|
||||
)
|
||||
|
||||
# Test bulk run
|
||||
tasks = [
|
||||
{"task": "Count to 3"},
|
||||
{"task": "Say hello"},
|
||||
{"task": "Tell a short joke"},
|
||||
]
|
||||
|
||||
responses = agent.bulk_run(tasks)
|
||||
assert len(responses) == len(tasks), "Not all tasks completed"
|
||||
assert all(
|
||||
response is not None for response in responses
|
||||
), "Some tasks failed"
|
||||
|
||||
# Test concurrent tasks
|
||||
concurrent_responses = agent.run_concurrent_tasks(
|
||||
["Task 1", "Task 2", "Task 3"]
|
||||
)
|
||||
assert (
|
||||
len(concurrent_responses) == 3
|
||||
), "Not all concurrent tasks completed"
|
||||
|
||||
print("✓ Concurrent execution test passed")
|
||||
|
||||
|
||||
def test_agent_error_handling():
|
||||
"""Test agent error handling and recovery"""
|
||||
print("\nTesting error handling...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Error-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
retry_attempts=3,
|
||||
retry_interval=1,
|
||||
)
|
||||
|
||||
# Test invalid tool execution
|
||||
try:
|
||||
agent.parse_and_execute_tools("invalid_json")
|
||||
print("✓ Invalid tool execution handled")
|
||||
except Exception:
|
||||
assert True, "Expected error caught"
|
||||
|
||||
# Test recovery after error
|
||||
response = agent.run("Continue after error")
|
||||
assert response is not None, "Agent failed to recover after error"
|
||||
|
||||
print("✓ Error handling test passed")
|
||||
|
||||
|
||||
def test_agent_configuration():
|
||||
"""Test agent configuration and parameters"""
|
||||
print("\nTesting agent configuration...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Config-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
temperature=0.7,
|
||||
max_tokens=4000,
|
||||
context_length=8192,
|
||||
)
|
||||
|
||||
# Test configuration methods
|
||||
agent.update_system_prompt("New system prompt")
|
||||
agent.update_max_loops(2)
|
||||
agent.update_loop_interval(2)
|
||||
|
||||
# Verify updates
|
||||
assert agent.max_loops == 2, "Max loops not updated"
|
||||
assert agent.loop_interval == 2, "Loop interval not updated"
|
||||
|
||||
# Test configuration export
|
||||
config_dict = agent.to_dict()
|
||||
assert isinstance(
|
||||
config_dict, dict
|
||||
), "Configuration export failed"
|
||||
|
||||
# Test YAML export
|
||||
yaml_config = agent.to_yaml()
|
||||
assert isinstance(yaml_config, str), "YAML export failed"
|
||||
|
||||
print("✓ Configuration test passed")
|
||||
|
||||
|
||||
def test_agent_with_stopping_condition():
|
||||
"""Test agent with custom stopping condition"""
|
||||
print("\nTesting agent with stopping condition...")
|
||||
|
||||
def custom_stopping_condition(response: str) -> bool:
|
||||
return "STOP" in response.upper()
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Stopping-Condition-Agent",
|
||||
llm=model,
|
||||
max_loops=5,
|
||||
stopping_condition=custom_stopping_condition,
|
||||
)
|
||||
|
||||
response = agent.run("Count up until you see the word STOP")
|
||||
assert response is not None, "Stopping condition test failed"
|
||||
print("✓ Stopping condition test passed")
|
||||
|
||||
|
||||
def test_agent_with_retry_mechanism():
|
||||
"""Test agent retry mechanism"""
|
||||
print("\nTesting agent retry mechanism...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Retry-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
retry_attempts=3,
|
||||
retry_interval=1,
|
||||
)
|
||||
|
||||
response = agent.run("Tell me a joke.")
|
||||
assert response is not None, "Retry mechanism test failed"
|
||||
print("✓ Retry mechanism test passed")
|
||||
|
||||
|
||||
def test_bulk_and_filtered_operations():
|
||||
"""Test bulk operations and response filtering"""
|
||||
print("\nTesting bulk and filtered operations...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Bulk-Filter-Test-Agent", llm=model, max_loops=1
|
||||
)
|
||||
|
||||
# Test bulk run
|
||||
bulk_tasks = [
|
||||
{"task": "What is 2+2?"},
|
||||
{"task": "Name a color"},
|
||||
{"task": "Count to 3"},
|
||||
]
|
||||
bulk_responses = agent.bulk_run(bulk_tasks)
|
||||
assert len(bulk_responses) == len(
|
||||
bulk_tasks
|
||||
), "Bulk run should return same number of responses as tasks"
|
||||
|
||||
# Test response filtering
|
||||
agent.add_response_filter("color")
|
||||
filtered_response = agent.filtered_run(
|
||||
"What is your favorite color?"
|
||||
)
|
||||
assert (
|
||||
"[FILTERED]" in filtered_response
|
||||
), "Response filter not applied"
|
||||
|
||||
print("✓ Bulk and filtered operations test passed")
|
||||
|
||||
|
||||
async def test_async_operations():
|
||||
"""Test asynchronous operations"""
|
||||
print("\nTesting async operations...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Async-Test-Agent", llm=model, max_loops=1
|
||||
)
|
||||
|
||||
# Test single async run
|
||||
response = await agent.arun("What is 1+1?")
|
||||
assert response is not None, "Async run failed"
|
||||
|
||||
# Test concurrent async runs
|
||||
tasks = ["Task 1", "Task 2", "Task 3"]
|
||||
responses = await asyncio.gather(
|
||||
*[agent.arun(task) for task in tasks]
|
||||
)
|
||||
assert len(responses) == len(
|
||||
tasks
|
||||
), "Not all async tasks completed"
|
||||
|
||||
print("✓ Async operations test passed")
|
||||
|
||||
|
||||
def test_memory_and_state_persistence():
|
||||
"""Test memory management and state persistence"""
|
||||
print("\nTesting memory and state persistence...")
|
||||
|
||||
with tempfile.TemporaryDirectory() as temp_dir:
|
||||
state_path = os.path.join(temp_dir, "test_state.json")
|
||||
|
||||
# Create agent with memory configuration
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent1 = Agent(
|
||||
agent_name="Memory-State-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
saved_state_path=state_path,
|
||||
context_length=8192,
|
||||
autosave=True,
|
||||
)
|
||||
|
||||
# Test memory operations
|
||||
agent1.add_memory("Important fact: The sky is blue")
|
||||
agent1.memory_query("What color is the sky?")
|
||||
|
||||
# Save state
|
||||
agent1.save()
|
||||
|
||||
# Create new agent and load state
|
||||
agent2 = Agent(
|
||||
agent_name="Memory-State-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
)
|
||||
agent2.load(state_path)
|
||||
|
||||
# Verify memory persistence
|
||||
memory_content = (
|
||||
agent2.short_memory.return_history_as_string()
|
||||
)
|
||||
assert (
|
||||
"sky is blue" in memory_content
|
||||
), "Memory not properly persisted"
|
||||
|
||||
print("✓ Memory and state persistence test passed")
|
||||
|
||||
|
||||
def test_sentiment_and_evaluation():
|
||||
"""Test sentiment analysis and response evaluation"""
|
||||
print("\nTesting sentiment analysis and evaluation...")
|
||||
|
||||
def mock_sentiment_analyzer(text):
|
||||
"""Mock sentiment analyzer that returns a score between 0 and 1"""
|
||||
return 0.7 if "positive" in text.lower() else 0.3
|
||||
|
||||
def mock_evaluator(response):
|
||||
"""Mock evaluator that checks response quality"""
|
||||
return "GOOD" if len(response) > 10 else "BAD"
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Sentiment-Eval-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
sentiment_analyzer=mock_sentiment_analyzer,
|
||||
sentiment_threshold=0.5,
|
||||
evaluator=mock_evaluator,
|
||||
)
|
||||
|
||||
# Test sentiment analysis
|
||||
agent.run("Generate a positive message")
|
||||
|
||||
# Test evaluation
|
||||
agent.run("Generate a detailed response")
|
||||
|
||||
print("✓ Sentiment and evaluation test passed")
|
||||
|
||||
|
||||
def test_tool_management():
|
||||
"""Test tool management functionality"""
|
||||
print("\nTesting tool management...")
|
||||
|
||||
def tool1(x: int) -> int:
|
||||
"""Sample tool 1"""
|
||||
return x * 2
|
||||
|
||||
def tool2(x: int) -> int:
|
||||
"""Sample tool 2"""
|
||||
return x + 2
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Tool-Test-Agent",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
tools=[tool1],
|
||||
)
|
||||
|
||||
# Test adding tools
|
||||
agent.add_tool(tool2)
|
||||
assert len(agent.tools) == 2, "Tool not added correctly"
|
||||
|
||||
# Test removing tools
|
||||
agent.remove_tool(tool1)
|
||||
assert len(agent.tools) == 1, "Tool not removed correctly"
|
||||
|
||||
# Test adding multiple tools
|
||||
agent.add_tools([tool1, tool2])
|
||||
assert len(agent.tools) == 3, "Multiple tools not added correctly"
|
||||
|
||||
print("✓ Tool management test passed")
|
||||
|
||||
|
||||
def test_system_prompt_and_configuration():
|
||||
"""Test system prompt and configuration updates"""
|
||||
print("\nTesting system prompt and configuration...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Config-Test-Agent", llm=model, max_loops=1
|
||||
)
|
||||
|
||||
# Test updating system prompt
|
||||
new_prompt = "You are a helpful assistant."
|
||||
agent.update_system_prompt(new_prompt)
|
||||
assert (
|
||||
agent.system_prompt == new_prompt
|
||||
), "System prompt not updated"
|
||||
|
||||
# Test configuration updates
|
||||
agent.update_max_loops(5)
|
||||
assert agent.max_loops == 5, "Max loops not updated"
|
||||
|
||||
agent.update_loop_interval(2)
|
||||
assert agent.loop_interval == 2, "Loop interval not updated"
|
||||
|
||||
# Test configuration export
|
||||
config_dict = agent.to_dict()
|
||||
assert isinstance(
|
||||
config_dict, dict
|
||||
), "Configuration export failed"
|
||||
|
||||
print("✓ System prompt and configuration test passed")
|
||||
|
||||
|
||||
def test_agent_with_dynamic_temperature():
|
||||
"""Test agent with dynamic temperature"""
|
||||
print("\nTesting agent with dynamic temperature...")
|
||||
|
||||
model = OpenAIChat(model_name="gpt-4.1")
|
||||
agent = Agent(
|
||||
agent_name="Dynamic-Temp-Agent",
|
||||
llm=model,
|
||||
max_loops=2,
|
||||
dynamic_temperature_enabled=True,
|
||||
)
|
||||
|
||||
response = agent.run("Generate a creative story.")
|
||||
assert response is not None, "Dynamic temperature test failed"
|
||||
print("✓ Dynamic temperature test passed")
|
||||
|
||||
|
||||
def run_all_tests():
|
||||
"""Run all test functions"""
|
||||
print("Starting Extended Agent functional tests...\n")
|
||||
|
||||
test_functions = [
|
||||
test_basic_agent_functionality,
|
||||
test_memory_management,
|
||||
test_agent_output_formats,
|
||||
test_agent_state_management,
|
||||
test_agent_tools_and_execution,
|
||||
test_agent_concurrent_execution,
|
||||
test_agent_error_handling,
|
||||
test_agent_configuration,
|
||||
test_agent_with_stopping_condition,
|
||||
test_agent_with_retry_mechanism,
|
||||
test_agent_with_dynamic_temperature,
|
||||
test_bulk_and_filtered_operations,
|
||||
test_memory_and_state_persistence,
|
||||
test_sentiment_and_evaluation,
|
||||
test_tool_management,
|
||||
test_system_prompt_and_configuration,
|
||||
]
|
||||
|
||||
# Run synchronous tests
|
||||
total_tests = len(test_functions) + 1 # +1 for async test
|
||||
passed_tests = 0
|
||||
|
||||
for test in test_functions:
|
||||
try:
|
||||
test()
|
||||
passed_tests += 1
|
||||
except Exception as e:
|
||||
print(f"✗ Test {test.__name__} failed: {str(e)}")
|
||||
|
||||
# Run async test
|
||||
try:
|
||||
asyncio.run(test_async_operations())
|
||||
passed_tests += 1
|
||||
except Exception as e:
|
||||
print(f"✗ Async operations test failed: {str(e)}")
|
||||
|
||||
print("\nExtended Test Summary:")
|
||||
print(f"Total Tests: {total_tests}")
|
||||
print(f"Passed: {passed_tests}")
|
||||
print(f"Failed: {total_tests - passed_tests}")
|
||||
print(f"Success Rate: {(passed_tests/total_tests)*100:.2f}%")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_all_tests()
|
||||
@ -1,328 +0,0 @@
|
||||
import os
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from typing import Callable, Dict, List, Optional
|
||||
|
||||
from loguru import logger
|
||||
from swarm_models import OpenAIChat
|
||||
|
||||
from swarms.structs.agent import Agent
|
||||
from swarms.structs.agent_rearrange import AgentRearrange
|
||||
|
||||
|
||||
class TestResult:
|
||||
"""Class to store test results and metadata"""
|
||||
|
||||
def __init__(self, test_name: str):
|
||||
self.test_name = test_name
|
||||
self.start_time = datetime.now()
|
||||
self.end_time = None
|
||||
self.success = False
|
||||
self.error = None
|
||||
self.traceback = None
|
||||
self.function_output = None
|
||||
|
||||
def complete(
|
||||
self, success: bool, error: Optional[Exception] = None
|
||||
):
|
||||
"""Complete the test execution with results"""
|
||||
self.end_time = datetime.now()
|
||||
self.success = success
|
||||
if error:
|
||||
self.error = str(error)
|
||||
self.traceback = traceback.format_exc()
|
||||
|
||||
def duration(self) -> float:
|
||||
"""Calculate test duration in seconds"""
|
||||
if self.end_time:
|
||||
return (self.end_time - self.start_time).total_seconds()
|
||||
return 0
|
||||
|
||||
|
||||
def run_test(test_func: Callable) -> TestResult:
|
||||
"""
|
||||
Decorator to run tests with error handling and logging
|
||||
|
||||
Args:
|
||||
test_func (Callable): Test function to execute
|
||||
|
||||
Returns:
|
||||
TestResult: Object containing test execution details
|
||||
"""
|
||||
|
||||
def wrapper(*args, **kwargs) -> TestResult:
|
||||
result = TestResult(test_func.__name__)
|
||||
logger.info(
|
||||
f"\n{'='*20} Running test: {test_func.__name__} {'='*20}"
|
||||
)
|
||||
|
||||
try:
|
||||
output = test_func(*args, **kwargs)
|
||||
result.function_output = output
|
||||
result.complete(success=True)
|
||||
logger.success(
|
||||
f"✅ Test {test_func.__name__} passed successfully"
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
result.complete(success=False, error=e)
|
||||
logger.error(
|
||||
f"❌ Test {test_func.__name__} failed with error: {str(e)}"
|
||||
)
|
||||
logger.error(f"Traceback: {traceback.format_exc()}")
|
||||
|
||||
logger.info(
|
||||
f"Test duration: {result.duration():.2f} seconds\n"
|
||||
)
|
||||
return result
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def create_functional_agents() -> List[Agent]:
|
||||
"""
|
||||
Create a list of functional agents with real LLM integration for testing.
|
||||
Using OpenAI's GPT model for realistic agent behavior testing.
|
||||
"""
|
||||
# Initialize OpenAI Chat model
|
||||
api_key = os.getenv("OPENAI_API_KEY")
|
||||
if not api_key:
|
||||
logger.warning(
|
||||
"No OpenAI API key found. Using mock agents instead."
|
||||
)
|
||||
return [
|
||||
create_mock_agent("TestAgent1"),
|
||||
create_mock_agent("TestAgent2"),
|
||||
]
|
||||
|
||||
try:
|
||||
model = OpenAIChat(
|
||||
api_key=api_key, model_name="gpt-4.1", temperature=0.1
|
||||
)
|
||||
|
||||
# Create boss agent
|
||||
boss_agent = Agent(
|
||||
agent_name="BossAgent",
|
||||
system_prompt="""
|
||||
You are the BossAgent responsible for managing and overseeing test scenarios.
|
||||
Your role is to coordinate tasks between agents and ensure efficient collaboration.
|
||||
Analyze inputs, break down tasks, and provide clear directives to other agents.
|
||||
Maintain a structured approach to task management and result compilation.
|
||||
""",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
state_save_file_type="json",
|
||||
saved_state_path="test_boss_agent.json",
|
||||
)
|
||||
|
||||
# Create analysis agent
|
||||
analysis_agent = Agent(
|
||||
agent_name="AnalysisAgent",
|
||||
system_prompt="""
|
||||
You are the AnalysisAgent responsible for detailed data processing and analysis.
|
||||
Your role is to examine input data, identify patterns, and provide analytical insights.
|
||||
Focus on breaking down complex information into clear, actionable components.
|
||||
""",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
state_save_file_type="json",
|
||||
saved_state_path="test_analysis_agent.json",
|
||||
)
|
||||
|
||||
# Create summary agent
|
||||
summary_agent = Agent(
|
||||
agent_name="SummaryAgent",
|
||||
system_prompt="""
|
||||
You are the SummaryAgent responsible for consolidating and summarizing information.
|
||||
Your role is to take detailed analysis and create concise, actionable summaries.
|
||||
Focus on highlighting key points and ensuring clarity in communication.
|
||||
""",
|
||||
llm=model,
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
state_save_file_type="json",
|
||||
saved_state_path="test_summary_agent.json",
|
||||
)
|
||||
|
||||
logger.info(
|
||||
"Successfully created functional agents with LLM integration"
|
||||
)
|
||||
return [boss_agent, analysis_agent, summary_agent]
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to create functional agents: {str(e)}")
|
||||
logger.warning("Falling back to mock agents")
|
||||
return [
|
||||
create_mock_agent("TestAgent1"),
|
||||
create_mock_agent("TestAgent2"),
|
||||
]
|
||||
|
||||
|
||||
def create_mock_agent(name: str) -> Agent:
|
||||
"""Create a mock agent for testing when LLM integration is not available"""
|
||||
return Agent(
|
||||
agent_name=name,
|
||||
system_prompt=f"You are a test agent named {name}",
|
||||
llm=None,
|
||||
)
|
||||
|
||||
|
||||
@run_test
|
||||
def test_init():
|
||||
"""Test AgentRearrange initialization with functional agents"""
|
||||
logger.info("Creating agents for initialization test")
|
||||
agents = create_functional_agents()
|
||||
|
||||
rearrange = AgentRearrange(
|
||||
name="TestRearrange",
|
||||
agents=agents,
|
||||
flow=f"{agents[0].agent_name} -> {agents[1].agent_name} -> {agents[2].agent_name}",
|
||||
)
|
||||
|
||||
assert rearrange.name == "TestRearrange"
|
||||
assert len(rearrange.agents) == 3
|
||||
assert (
|
||||
rearrange.flow
|
||||
== f"{agents[0].agent_name} -> {agents[1].agent_name} -> {agents[2].agent_name}"
|
||||
)
|
||||
|
||||
logger.info(
|
||||
f"Initialized AgentRearrange with {len(agents)} agents"
|
||||
)
|
||||
return True
|
||||
|
||||
|
||||
@run_test
|
||||
def test_validate_flow():
|
||||
"""Test flow validation logic"""
|
||||
agents = create_functional_agents()
|
||||
rearrange = AgentRearrange(
|
||||
agents=agents,
|
||||
flow=f"{agents[0].agent_name} -> {agents[1].agent_name}",
|
||||
)
|
||||
|
||||
logger.info("Testing valid flow pattern")
|
||||
valid = rearrange.validate_flow()
|
||||
assert valid is True
|
||||
|
||||
logger.info("Testing invalid flow pattern")
|
||||
rearrange.flow = f"{agents[0].agent_name} {agents[1].agent_name}" # Missing arrow
|
||||
try:
|
||||
rearrange.validate_flow()
|
||||
assert False, "Should have raised ValueError"
|
||||
except ValueError as e:
|
||||
logger.info(
|
||||
f"Successfully caught invalid flow error: {str(e)}"
|
||||
)
|
||||
assert True
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@run_test
|
||||
def test_add_remove_agent():
|
||||
"""Test adding and removing agents from the swarm"""
|
||||
agents = create_functional_agents()
|
||||
rearrange = AgentRearrange(
|
||||
agents=agents[:2]
|
||||
) # Start with first two agents
|
||||
|
||||
logger.info("Testing agent addition")
|
||||
new_agent = agents[2] # Use the third agent as new agent
|
||||
rearrange.add_agent(new_agent)
|
||||
assert new_agent.agent_name in rearrange.agents
|
||||
|
||||
logger.info("Testing agent removal")
|
||||
rearrange.remove_agent(new_agent.agent_name)
|
||||
assert new_agent.agent_name not in rearrange.agents
|
||||
|
||||
return True
|
||||
|
||||
|
||||
@run_test
|
||||
def test_basic_run():
|
||||
"""Test basic task execution with the swarm"""
|
||||
agents = create_functional_agents()
|
||||
rearrange = AgentRearrange(
|
||||
name="TestSwarm",
|
||||
agents=agents,
|
||||
flow=f"{agents[0].agent_name} -> {agents[1].agent_name} -> {agents[2].agent_name}",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
test_task = (
|
||||
"Analyze this test message and provide a brief summary."
|
||||
)
|
||||
logger.info(f"Running test task: {test_task}")
|
||||
|
||||
try:
|
||||
result = rearrange.run(test_task)
|
||||
assert result is not None
|
||||
logger.info(
|
||||
f"Successfully executed task with result length: {len(str(result))}"
|
||||
)
|
||||
return True
|
||||
except Exception as e:
|
||||
logger.error(f"Task execution failed: {str(e)}")
|
||||
raise
|
||||
|
||||
|
||||
def run_all_tests() -> Dict[str, TestResult]:
|
||||
"""
|
||||
Run all test cases and collect results
|
||||
|
||||
Returns:
|
||||
Dict[str, TestResult]: Dictionary mapping test names to their results
|
||||
"""
|
||||
logger.info("\n🚀 Starting AgentRearrange test suite execution")
|
||||
test_functions = [
|
||||
test_init,
|
||||
test_validate_flow,
|
||||
test_add_remove_agent,
|
||||
test_basic_run,
|
||||
]
|
||||
|
||||
results = {}
|
||||
for test in test_functions:
|
||||
result = test()
|
||||
results[test.__name__] = result
|
||||
|
||||
# Log summary
|
||||
total_tests = len(results)
|
||||
passed_tests = sum(1 for r in results.values() if r.success)
|
||||
failed_tests = total_tests - passed_tests
|
||||
|
||||
logger.info("\n📊 Test Suite Summary:")
|
||||
logger.info(f"Total Tests: {total_tests}")
|
||||
print(f"✅ Passed: {passed_tests}")
|
||||
|
||||
if failed_tests > 0:
|
||||
logger.error(f"❌ Failed: {failed_tests}")
|
||||
|
||||
# Detailed failure information
|
||||
if failed_tests > 0:
|
||||
logger.error("\n❌ Failed Tests Details:")
|
||||
for name, result in results.items():
|
||||
if not result.success:
|
||||
logger.error(f"\n{name}:")
|
||||
logger.error(f"Error: {result.error}")
|
||||
logger.error(f"Traceback: {result.traceback}")
|
||||
|
||||
return results
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("🌟 Starting AgentRearrange Test Suite")
|
||||
results = run_all_tests()
|
||||
print("🏁 Test Suite Execution Completed")
|
||||
@ -1,313 +0,0 @@
|
||||
import time
|
||||
|
||||
from loguru import logger
|
||||
from swarms import Agent
|
||||
|
||||
from experimental.airflow_swarm import (
|
||||
AirflowDAGSwarm,
|
||||
NodeType,
|
||||
Conversation,
|
||||
)
|
||||
|
||||
# Configure logger
|
||||
logger.remove()
|
||||
logger.add(lambda msg: print(msg, end=""), level="DEBUG")
|
||||
|
||||
|
||||
def test_swarm_initialization():
|
||||
"""Test basic swarm initialization and configuration."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(
|
||||
dag_id="test_dag",
|
||||
name="Test DAG",
|
||||
initial_message="Test message",
|
||||
)
|
||||
assert swarm.dag_id == "test_dag", "DAG ID not set correctly"
|
||||
assert swarm.name == "Test DAG", "Name not set correctly"
|
||||
assert (
|
||||
len(swarm.nodes) == 0
|
||||
), "Nodes should be empty on initialization"
|
||||
assert (
|
||||
len(swarm.edges) == 0
|
||||
), "Edges should be empty on initialization"
|
||||
|
||||
# Test initial message
|
||||
conv_json = swarm.get_conversation_history()
|
||||
assert (
|
||||
"Test message" in conv_json
|
||||
), "Initial message not set correctly"
|
||||
print("✅ Swarm initialization test passed")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"❌ Swarm initialization test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def test_node_addition():
|
||||
"""Test adding different types of nodes to the swarm."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(dag_id="test_dag")
|
||||
|
||||
# Test adding an agent node
|
||||
agent = Agent(
|
||||
agent_name="Test-Agent",
|
||||
system_prompt="Test prompt",
|
||||
model_name="gpt-4o-mini",
|
||||
max_loops=1,
|
||||
)
|
||||
agent_id = swarm.add_node(
|
||||
"test_agent",
|
||||
agent,
|
||||
NodeType.AGENT,
|
||||
query="Test query",
|
||||
concurrent=True,
|
||||
)
|
||||
assert (
|
||||
agent_id == "test_agent"
|
||||
), "Agent node ID not returned correctly"
|
||||
assert (
|
||||
"test_agent" in swarm.nodes
|
||||
), "Agent node not added to nodes dict"
|
||||
|
||||
# Test adding a callable node
|
||||
def test_callable(x: int, conversation: Conversation) -> str:
|
||||
return f"Test output {x}"
|
||||
|
||||
callable_id = swarm.add_node(
|
||||
"test_callable",
|
||||
test_callable,
|
||||
NodeType.CALLABLE,
|
||||
args=[42],
|
||||
concurrent=False,
|
||||
)
|
||||
assert (
|
||||
callable_id == "test_callable"
|
||||
), "Callable node ID not returned correctly"
|
||||
assert (
|
||||
"test_callable" in swarm.nodes
|
||||
), "Callable node not added to nodes dict"
|
||||
|
||||
print("✅ Node addition test passed")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"❌ Node addition test failed: {str(e)}")
|
||||
return False
|
||||
except Exception as e:
|
||||
print(
|
||||
f"❌ Node addition test failed with unexpected error: {str(e)}"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def test_edge_addition():
|
||||
"""Test adding edges between nodes."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(dag_id="test_dag")
|
||||
|
||||
# Add two nodes
|
||||
def node1_fn(conversation: Conversation) -> str:
|
||||
return "Node 1 output"
|
||||
|
||||
def node2_fn(conversation: Conversation) -> str:
|
||||
return "Node 2 output"
|
||||
|
||||
swarm.add_node("node1", node1_fn, NodeType.CALLABLE)
|
||||
swarm.add_node("node2", node2_fn, NodeType.CALLABLE)
|
||||
|
||||
# Add edge between them
|
||||
swarm.add_edge("node1", "node2")
|
||||
|
||||
assert (
|
||||
"node2" in swarm.edges["node1"]
|
||||
), "Edge not added correctly"
|
||||
assert (
|
||||
len(swarm.edges["node1"]) == 1
|
||||
), "Incorrect number of edges"
|
||||
|
||||
# Test adding edge with non-existent node
|
||||
try:
|
||||
swarm.add_edge("node1", "non_existent")
|
||||
assert (
|
||||
False
|
||||
), "Should raise ValueError for non-existent node"
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
print("✅ Edge addition test passed")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"❌ Edge addition test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def test_execution_order():
|
||||
"""Test that nodes are executed in the correct order based on dependencies."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(dag_id="test_dag")
|
||||
execution_order = []
|
||||
|
||||
def node1(conversation: Conversation) -> str:
|
||||
execution_order.append("node1")
|
||||
return "Node 1 output"
|
||||
|
||||
def node2(conversation: Conversation) -> str:
|
||||
execution_order.append("node2")
|
||||
return "Node 2 output"
|
||||
|
||||
def node3(conversation: Conversation) -> str:
|
||||
execution_order.append("node3")
|
||||
return "Node 3 output"
|
||||
|
||||
# Add nodes
|
||||
swarm.add_node(
|
||||
"node1", node1, NodeType.CALLABLE, concurrent=False
|
||||
)
|
||||
swarm.add_node(
|
||||
"node2", node2, NodeType.CALLABLE, concurrent=False
|
||||
)
|
||||
swarm.add_node(
|
||||
"node3", node3, NodeType.CALLABLE, concurrent=False
|
||||
)
|
||||
|
||||
# Add edges to create a chain: node1 -> node2 -> node3
|
||||
swarm.add_edge("node1", "node2")
|
||||
swarm.add_edge("node2", "node3")
|
||||
|
||||
# Execute
|
||||
swarm.run()
|
||||
|
||||
# Check execution order
|
||||
assert execution_order == [
|
||||
"node1",
|
||||
"node2",
|
||||
"node3",
|
||||
], "Incorrect execution order"
|
||||
print("✅ Execution order test passed")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"❌ Execution order test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def test_concurrent_execution():
|
||||
"""Test concurrent execution of nodes."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(dag_id="test_dag")
|
||||
|
||||
def slow_node1(conversation: Conversation) -> str:
|
||||
time.sleep(0.5)
|
||||
return "Slow node 1 output"
|
||||
|
||||
def slow_node2(conversation: Conversation) -> str:
|
||||
time.sleep(0.5)
|
||||
return "Slow node 2 output"
|
||||
|
||||
# Add nodes with concurrent=True
|
||||
swarm.add_node(
|
||||
"slow1", slow_node1, NodeType.CALLABLE, concurrent=True
|
||||
)
|
||||
swarm.add_node(
|
||||
"slow2", slow_node2, NodeType.CALLABLE, concurrent=True
|
||||
)
|
||||
|
||||
# Measure execution time
|
||||
start_time = time.time()
|
||||
swarm.run()
|
||||
execution_time = time.time() - start_time
|
||||
|
||||
# Should take ~0.5s for concurrent execution, not ~1s
|
||||
assert (
|
||||
execution_time < 0.8
|
||||
), "Concurrent execution took too long"
|
||||
print("✅ Concurrent execution test passed")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"❌ Concurrent execution test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def test_conversation_handling():
|
||||
"""Test conversation management within the swarm."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(
|
||||
dag_id="test_dag", initial_message="Initial test message"
|
||||
)
|
||||
|
||||
# Test adding user messages
|
||||
swarm.add_user_message("Test message 1")
|
||||
swarm.add_user_message("Test message 2")
|
||||
|
||||
history = swarm.get_conversation_history()
|
||||
assert (
|
||||
"Initial test message" in history
|
||||
), "Initial message not in history"
|
||||
assert (
|
||||
"Test message 1" in history
|
||||
), "First message not in history"
|
||||
assert (
|
||||
"Test message 2" in history
|
||||
), "Second message not in history"
|
||||
|
||||
print("✅ Conversation handling test passed")
|
||||
return True
|
||||
except AssertionError as e:
|
||||
print(f"❌ Conversation handling test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def test_error_handling():
|
||||
"""Test error handling in node execution."""
|
||||
try:
|
||||
swarm = AirflowDAGSwarm(dag_id="test_dag")
|
||||
|
||||
def failing_node(conversation: Conversation) -> str:
|
||||
raise ValueError("Test error")
|
||||
|
||||
swarm.add_node("failing", failing_node, NodeType.CALLABLE)
|
||||
|
||||
# Execute should not raise an exception
|
||||
result = swarm.run()
|
||||
|
||||
assert (
|
||||
"Error" in result
|
||||
), "Error not captured in execution result"
|
||||
assert (
|
||||
"Test error" in result
|
||||
), "Specific error message not captured"
|
||||
|
||||
print("✅ Error handling test passed")
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"❌ Error handling test failed: {str(e)}")
|
||||
return False
|
||||
|
||||
|
||||
def run_all_tests():
|
||||
"""Run all test functions and report results."""
|
||||
tests = [
|
||||
test_swarm_initialization,
|
||||
test_node_addition,
|
||||
test_edge_addition,
|
||||
test_execution_order,
|
||||
test_concurrent_execution,
|
||||
test_conversation_handling,
|
||||
test_error_handling,
|
||||
]
|
||||
|
||||
results = []
|
||||
for test in tests:
|
||||
print(f"\nRunning {test.__name__}...")
|
||||
result = test()
|
||||
results.append(result)
|
||||
|
||||
total = len(results)
|
||||
passed = sum(results)
|
||||
print("\n=== Test Results ===")
|
||||
print(f"Total tests: {total}")
|
||||
print(f"Passed: {passed}")
|
||||
print(f"Failed: {total - passed}")
|
||||
print("==================")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_all_tests()
|
||||
@ -1,293 +0,0 @@
|
||||
"""
|
||||
Tests for bug #1115 fix in AutoSwarmBuilder.
|
||||
|
||||
This test module verifies the fix for AttributeError when creating agents
|
||||
from AgentSpec Pydantic models in AutoSwarmBuilder.
|
||||
|
||||
Bug: https://github.com/kyegomez/swarms/issues/1115
|
||||
"""
|
||||
|
||||
import pytest
|
||||
|
||||
from swarms.structs.agent import Agent
|
||||
from swarms.structs.auto_swarm_builder import (
|
||||
AgentSpec,
|
||||
AutoSwarmBuilder,
|
||||
)
|
||||
from swarms.structs.ma_utils import set_random_models_for_agents
|
||||
|
||||
|
||||
class TestAutoSwarmBuilderFix:
|
||||
"""Tests for bug #1115 fix in AutoSwarmBuilder."""
|
||||
|
||||
def test_create_agents_from_specs_with_dict(self):
|
||||
"""Test that create_agents_from_specs handles dict input correctly."""
|
||||
builder = AutoSwarmBuilder()
|
||||
|
||||
# Create specs as a dictionary
|
||||
specs = {
|
||||
"agents": [
|
||||
{
|
||||
"agent_name": "test_agent_1",
|
||||
"description": "Test agent 1 description",
|
||||
"system_prompt": "You are a helpful assistant",
|
||||
"model_name": "gpt-4o-mini",
|
||||
"max_loops": 1,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
agents = builder.create_agents_from_specs(specs)
|
||||
|
||||
# Verify agents were created correctly
|
||||
assert len(agents) == 1
|
||||
assert isinstance(agents[0], Agent)
|
||||
assert agents[0].agent_name == "test_agent_1"
|
||||
|
||||
# Verify description was mapped to agent_description
|
||||
assert hasattr(agents[0], "agent_description")
|
||||
assert (
|
||||
agents[0].agent_description == "Test agent 1 description"
|
||||
)
|
||||
|
||||
def test_create_agents_from_specs_with_pydantic(self):
|
||||
"""Test that create_agents_from_specs handles Pydantic model input correctly.
|
||||
|
||||
This is the main test for bug #1115 - it verifies that AgentSpec
|
||||
Pydantic models can be unpacked correctly.
|
||||
"""
|
||||
builder = AutoSwarmBuilder()
|
||||
|
||||
# Create specs as Pydantic AgentSpec objects
|
||||
agent_spec = AgentSpec(
|
||||
agent_name="test_agent_pydantic",
|
||||
description="Pydantic test agent",
|
||||
system_prompt="You are a helpful assistant",
|
||||
model_name="gpt-4o-mini",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
specs = {"agents": [agent_spec]}
|
||||
|
||||
agents = builder.create_agents_from_specs(specs)
|
||||
|
||||
# Verify agents were created correctly
|
||||
assert len(agents) == 1
|
||||
assert isinstance(agents[0], Agent)
|
||||
assert agents[0].agent_name == "test_agent_pydantic"
|
||||
|
||||
# Verify description was mapped to agent_description
|
||||
assert hasattr(agents[0], "agent_description")
|
||||
assert agents[0].agent_description == "Pydantic test agent"
|
||||
|
||||
def test_parameter_name_mapping(self):
|
||||
"""Test that 'description' field maps to 'agent_description' correctly."""
|
||||
builder = AutoSwarmBuilder()
|
||||
|
||||
# Test with dict that has 'description'
|
||||
specs = {
|
||||
"agents": [
|
||||
{
|
||||
"agent_name": "mapping_test",
|
||||
"description": "This should map to agent_description",
|
||||
"system_prompt": "You are helpful",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
agents = builder.create_agents_from_specs(specs)
|
||||
|
||||
assert len(agents) == 1
|
||||
agent = agents[0]
|
||||
|
||||
# Verify description was mapped
|
||||
assert hasattr(agent, "agent_description")
|
||||
assert (
|
||||
agent.agent_description
|
||||
== "This should map to agent_description"
|
||||
)
|
||||
|
||||
def test_create_agents_from_specs_mixed_input(self):
|
||||
"""Test that create_agents_from_specs handles mixed dict and Pydantic input."""
|
||||
builder = AutoSwarmBuilder()
|
||||
|
||||
# Mix of dict and Pydantic objects
|
||||
dict_spec = {
|
||||
"agent_name": "dict_agent",
|
||||
"description": "Dict agent description",
|
||||
"system_prompt": "You are helpful",
|
||||
}
|
||||
|
||||
pydantic_spec = AgentSpec(
|
||||
agent_name="pydantic_agent",
|
||||
description="Pydantic agent description",
|
||||
system_prompt="You are smart",
|
||||
)
|
||||
|
||||
specs = {"agents": [dict_spec, pydantic_spec]}
|
||||
|
||||
agents = builder.create_agents_from_specs(specs)
|
||||
|
||||
# Verify both agents were created
|
||||
assert len(agents) == 2
|
||||
assert all(isinstance(agent, Agent) for agent in agents)
|
||||
|
||||
# Verify both have correct descriptions
|
||||
dict_agent = next(
|
||||
a for a in agents if a.agent_name == "dict_agent"
|
||||
)
|
||||
pydantic_agent = next(
|
||||
a for a in agents if a.agent_name == "pydantic_agent"
|
||||
)
|
||||
|
||||
assert (
|
||||
dict_agent.agent_description == "Dict agent description"
|
||||
)
|
||||
assert (
|
||||
pydantic_agent.agent_description
|
||||
== "Pydantic agent description"
|
||||
)
|
||||
|
||||
def test_set_random_models_for_agents_with_valid_agents(
|
||||
self,
|
||||
):
|
||||
"""Test set_random_models_for_agents with proper Agent objects."""
|
||||
# Create proper Agent objects
|
||||
agents = [
|
||||
Agent(
|
||||
agent_name="agent1",
|
||||
system_prompt="You are agent 1",
|
||||
max_loops=1,
|
||||
),
|
||||
Agent(
|
||||
agent_name="agent2",
|
||||
system_prompt="You are agent 2",
|
||||
max_loops=1,
|
||||
),
|
||||
]
|
||||
|
||||
# Set random models
|
||||
model_names = ["gpt-4o-mini", "gpt-4o", "claude-3-5-sonnet"]
|
||||
result = set_random_models_for_agents(
|
||||
agents=agents, model_names=model_names
|
||||
)
|
||||
|
||||
# Verify results
|
||||
assert len(result) == 2
|
||||
assert all(isinstance(agent, Agent) for agent in result)
|
||||
assert all(hasattr(agent, "model_name") for agent in result)
|
||||
assert all(
|
||||
agent.model_name in model_names for agent in result
|
||||
)
|
||||
|
||||
def test_set_random_models_for_agents_with_single_agent(
|
||||
self,
|
||||
):
|
||||
"""Test set_random_models_for_agents with a single agent."""
|
||||
agent = Agent(
|
||||
agent_name="single_agent",
|
||||
system_prompt="You are helpful",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
model_names = ["gpt-4o-mini", "gpt-4o"]
|
||||
result = set_random_models_for_agents(
|
||||
agents=agent, model_names=model_names
|
||||
)
|
||||
|
||||
assert isinstance(result, Agent)
|
||||
assert hasattr(result, "model_name")
|
||||
assert result.model_name in model_names
|
||||
|
||||
def test_set_random_models_for_agents_with_none(self):
|
||||
"""Test set_random_models_for_agents with None returns random model name."""
|
||||
model_names = ["gpt-4o-mini", "gpt-4o", "claude-3-5-sonnet"]
|
||||
result = set_random_models_for_agents(
|
||||
agents=None, model_names=model_names
|
||||
)
|
||||
|
||||
assert isinstance(result, str)
|
||||
assert result in model_names
|
||||
|
||||
@pytest.mark.skip(
|
||||
reason="This test requires API key and makes LLM calls"
|
||||
)
|
||||
def test_auto_swarm_builder_return_agents_objects_integration(
|
||||
self,
|
||||
):
|
||||
"""Integration test for AutoSwarmBuilder with execution_type='return-agents-objects'.
|
||||
|
||||
This test requires OPENAI_API_KEY and makes actual LLM calls.
|
||||
Run manually with: pytest -k test_auto_swarm_builder_return_agents_objects_integration -v
|
||||
"""
|
||||
builder = AutoSwarmBuilder(
|
||||
execution_type="return-agents-objects",
|
||||
model_name="gpt-4o-mini",
|
||||
max_loops=1,
|
||||
verbose=False,
|
||||
)
|
||||
|
||||
agents = builder.run(
|
||||
"Create a team of 2 data analysis agents with specific roles"
|
||||
)
|
||||
|
||||
# Verify agents were created
|
||||
assert isinstance(agents, list)
|
||||
assert len(agents) >= 1
|
||||
assert all(isinstance(agent, Agent) for agent in agents)
|
||||
assert all(hasattr(agent, "agent_name") for agent in agents)
|
||||
assert all(
|
||||
hasattr(agent, "agent_description") for agent in agents
|
||||
)
|
||||
|
||||
def test_agent_spec_to_agent_all_fields(self):
|
||||
"""Test that all AgentSpec fields are properly passed to Agent."""
|
||||
builder = AutoSwarmBuilder()
|
||||
|
||||
agent_spec = AgentSpec(
|
||||
agent_name="full_test_agent",
|
||||
description="Full test description",
|
||||
system_prompt="You are a comprehensive test agent",
|
||||
model_name="gpt-4o-mini",
|
||||
auto_generate_prompt=False,
|
||||
max_tokens=4096,
|
||||
temperature=0.7,
|
||||
role="worker",
|
||||
max_loops=3,
|
||||
goal="Test all parameters",
|
||||
)
|
||||
|
||||
agents = builder.create_agents_from_specs(
|
||||
{"agents": [agent_spec]}
|
||||
)
|
||||
|
||||
assert len(agents) == 1
|
||||
agent = agents[0]
|
||||
|
||||
# Verify all fields were set
|
||||
assert agent.agent_name == "full_test_agent"
|
||||
assert agent.agent_description == "Full test description"
|
||||
# Agent may modify system_prompt by adding additional instructions
|
||||
assert (
|
||||
"You are a comprehensive test agent"
|
||||
in agent.system_prompt
|
||||
)
|
||||
assert agent.max_loops == 3
|
||||
assert agent.max_tokens == 4096
|
||||
assert agent.temperature == 0.7
|
||||
|
||||
def test_create_agents_from_specs_empty_list(self):
|
||||
"""Test that create_agents_from_specs handles empty agent list."""
|
||||
builder = AutoSwarmBuilder()
|
||||
|
||||
specs = {"agents": []}
|
||||
|
||||
agents = builder.create_agents_from_specs(specs)
|
||||
|
||||
assert isinstance(agents, list)
|
||||
assert len(agents) == 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Run tests with pytest
|
||||
pytest.main([__file__, "-v", "--tb=short"])
|
||||
@ -1,67 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
from dotenv import load_dotenv
|
||||
|
||||
from swarm_models import OpenAIChat
|
||||
from swarms.structs import BaseWorkflow
|
||||
|
||||
load_dotenv()
|
||||
|
||||
api_key = os.environ.get("OPENAI_API_KEY")
|
||||
|
||||
|
||||
def setup_workflow():
|
||||
llm = OpenAIChat(openai_api_key=api_key)
|
||||
workflow = BaseWorkflow(max_loops=1)
|
||||
workflow.add("What's the weather in miami", llm)
|
||||
workflow.add("Create a report on these metrics", llm)
|
||||
workflow.save_workflow_state("workflow_state.json")
|
||||
return workflow
|
||||
|
||||
|
||||
def teardown_workflow():
|
||||
os.remove("workflow_state.json")
|
||||
|
||||
|
||||
def test_load_workflow_state():
|
||||
workflow = setup_workflow()
|
||||
workflow.load_workflow_state("workflow_state.json")
|
||||
assert workflow.max_loops == 1
|
||||
assert len(workflow.tasks) == 2
|
||||
assert (
|
||||
workflow.tasks[0].description == "What's the weather in miami"
|
||||
)
|
||||
assert (
|
||||
workflow.tasks[1].description
|
||||
== "Create a report on these metrics"
|
||||
)
|
||||
teardown_workflow()
|
||||
|
||||
|
||||
def test_load_workflow_state_with_missing_file():
|
||||
workflow = setup_workflow()
|
||||
with pytest.raises(FileNotFoundError):
|
||||
workflow.load_workflow_state("non_existent_file.json")
|
||||
teardown_workflow()
|
||||
|
||||
|
||||
def test_load_workflow_state_with_invalid_file():
|
||||
workflow = setup_workflow()
|
||||
with open("invalid_file.json", "w") as f:
|
||||
f.write("This is not valid JSON")
|
||||
with pytest.raises(json.JSONDecodeError):
|
||||
workflow.load_workflow_state("invalid_file.json")
|
||||
os.remove("invalid_file.json")
|
||||
teardown_workflow()
|
||||
|
||||
|
||||
def test_load_workflow_state_with_missing_keys():
|
||||
workflow = setup_workflow()
|
||||
with open("missing_keys.json", "w") as f:
|
||||
json.dump({"max_loops": 1}, f)
|
||||
with pytest.raises(KeyError):
|
||||
workflow.load_workflow_state("missing_keys.json")
|
||||
os.remove("missing_keys.json")
|
||||
teardown_workflow()
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,328 @@
|
||||
from swarms import Agent
|
||||
from swarms.structs.hiearchical_swarm import HierarchicalSwarm
|
||||
|
||||
|
||||
def test_hierarchical_swarm_basic_initialization():
|
||||
"""Test basic HierarchicalSwarm initialization"""
|
||||
# Create worker agents
|
||||
research_agent = Agent(
|
||||
agent_name="Research-Specialist",
|
||||
agent_description="Specialist in research and data collection",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
analysis_agent = Agent(
|
||||
agent_name="Analysis-Expert",
|
||||
agent_description="Expert in data analysis and insights",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
implementation_agent = Agent(
|
||||
agent_name="Implementation-Manager",
|
||||
agent_description="Manager for implementation and execution",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create swarm with agents
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Research-Analysis-Implementation-Swarm",
|
||||
description="Hierarchical swarm for comprehensive project execution",
|
||||
agents=[research_agent, analysis_agent, implementation_agent],
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Verify initialization
|
||||
assert swarm.name == "Research-Analysis-Implementation-Swarm"
|
||||
assert swarm.description == "Hierarchical swarm for comprehensive project execution"
|
||||
assert len(swarm.agents) == 3
|
||||
assert swarm.max_loops == 1
|
||||
assert swarm.director is not None
|
||||
|
||||
|
||||
def test_hierarchical_swarm_with_director():
|
||||
"""Test HierarchicalSwarm with custom director"""
|
||||
# Create a custom director
|
||||
director = Agent(
|
||||
agent_name="Project-Director",
|
||||
agent_description="Senior project director with extensive experience",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create worker agents
|
||||
developer = Agent(
|
||||
agent_name="Senior-Developer",
|
||||
agent_description="Senior software developer",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
tester = Agent(
|
||||
agent_name="QA-Lead",
|
||||
agent_description="Quality assurance lead",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create swarm with custom director
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Software-Development-Swarm",
|
||||
description="Hierarchical swarm for software development projects",
|
||||
director=director,
|
||||
agents=[developer, tester],
|
||||
max_loops=2,
|
||||
)
|
||||
|
||||
assert swarm.director == director
|
||||
assert len(swarm.agents) == 2
|
||||
assert swarm.max_loops == 2
|
||||
|
||||
|
||||
def test_hierarchical_swarm_execution():
|
||||
"""Test HierarchicalSwarm execution with multiple agents"""
|
||||
# Create specialized agents
|
||||
market_researcher = Agent(
|
||||
agent_name="Market-Researcher",
|
||||
agent_description="Market research specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
product_strategist = Agent(
|
||||
agent_name="Product-Strategist",
|
||||
agent_description="Product strategy and planning expert",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
technical_architect = Agent(
|
||||
agent_name="Technical-Architect",
|
||||
agent_description="Technical architecture and design specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
risk_analyst = Agent(
|
||||
agent_name="Risk-Analyst",
|
||||
agent_description="Risk assessment and mitigation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create hierarchical swarm
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Product-Development-Swarm",
|
||||
description="Comprehensive product development hierarchical swarm",
|
||||
agents=[market_researcher, product_strategist, technical_architect, risk_analyst],
|
||||
max_loops=1,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
# Execute swarm
|
||||
result = swarm.run("Develop a comprehensive strategy for a new AI-powered healthcare platform")
|
||||
|
||||
# Verify result structure
|
||||
assert result is not None
|
||||
# HierarchicalSwarm returns a SwarmSpec or conversation history, just ensure it's not None
|
||||
|
||||
|
||||
def test_hierarchical_swarm_multiple_loops():
|
||||
"""Test HierarchicalSwarm with multiple feedback loops"""
|
||||
# Create agents for iterative refinement
|
||||
planner = Agent(
|
||||
agent_name="Strategic-Planner",
|
||||
agent_description="Strategic planning and project management",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
executor = Agent(
|
||||
agent_name="Task-Executor",
|
||||
agent_description="Task execution and implementation",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
reviewer = Agent(
|
||||
agent_name="Quality-Reviewer",
|
||||
agent_description="Quality assurance and review specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create swarm with multiple loops for iterative refinement
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Iterative-Development-Swarm",
|
||||
description="Hierarchical swarm with iterative feedback loops",
|
||||
agents=[planner, executor, reviewer],
|
||||
max_loops=3, # Allow multiple iterations
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
# Execute with multiple loops
|
||||
result = swarm.run("Create a detailed project plan for implementing a machine learning recommendation system")
|
||||
|
||||
assert result is not None
|
||||
|
||||
|
||||
def test_hierarchical_swarm_error_handling():
|
||||
"""Test HierarchicalSwarm error handling"""
|
||||
# Test with empty agents list
|
||||
try:
|
||||
swarm = HierarchicalSwarm(agents=[])
|
||||
assert False, "Should have raised ValueError for empty agents list"
|
||||
except ValueError as e:
|
||||
assert "agents" in str(e).lower() or "empty" in str(e).lower()
|
||||
|
||||
# Test with invalid max_loops
|
||||
researcher = Agent(
|
||||
agent_name="Test-Researcher",
|
||||
agent_description="Test researcher",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
try:
|
||||
swarm = HierarchicalSwarm(agents=[researcher], max_loops=0)
|
||||
assert False, "Should have raised ValueError for invalid max_loops"
|
||||
except ValueError as e:
|
||||
assert "max_loops" in str(e).lower() or "0" in str(e)
|
||||
|
||||
|
||||
def test_hierarchical_swarm_collaboration_prompts():
|
||||
"""Test HierarchicalSwarm with collaboration prompts enabled"""
|
||||
# Create agents
|
||||
data_analyst = Agent(
|
||||
agent_name="Data-Analyst",
|
||||
agent_description="Data analysis specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
business_analyst = Agent(
|
||||
agent_name="Business-Analyst",
|
||||
agent_description="Business analysis specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create swarm with collaboration prompts
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Collaborative-Analysis-Swarm",
|
||||
description="Hierarchical swarm with enhanced collaboration",
|
||||
agents=[data_analyst, business_analyst],
|
||||
max_loops=1,
|
||||
add_collaboration_prompt=True,
|
||||
)
|
||||
|
||||
# Check that collaboration prompts were added to agents
|
||||
assert data_analyst.system_prompt is not None
|
||||
assert business_analyst.system_prompt is not None
|
||||
|
||||
# Execute swarm
|
||||
result = swarm.run("Analyze customer behavior patterns and provide business recommendations")
|
||||
assert result is not None
|
||||
|
||||
|
||||
def test_hierarchical_swarm_with_dashboard():
|
||||
"""Test HierarchicalSwarm with interactive dashboard"""
|
||||
# Create agents
|
||||
content_creator = Agent(
|
||||
agent_name="Content-Creator",
|
||||
agent_description="Content creation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
editor = Agent(
|
||||
agent_name="Editor",
|
||||
agent_description="Content editor and proofreader",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
publisher = Agent(
|
||||
agent_name="Publisher",
|
||||
agent_description="Publishing and distribution specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create swarm with interactive dashboard
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Content-Publishing-Swarm",
|
||||
description="Hierarchical swarm for content creation and publishing",
|
||||
agents=[content_creator, editor, publisher],
|
||||
max_loops=1,
|
||||
interactive=True,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
# Verify dashboard was created
|
||||
assert swarm.dashboard is not None
|
||||
assert swarm.interactive is True
|
||||
|
||||
# Execute swarm
|
||||
result = swarm.run("Create a comprehensive guide on machine learning best practices")
|
||||
assert result is not None
|
||||
|
||||
|
||||
def test_hierarchical_swarm_real_world_scenario():
|
||||
"""Test HierarchicalSwarm in a realistic business scenario"""
|
||||
# Create agents representing different business functions
|
||||
market_intelligence = Agent(
|
||||
agent_name="Market-Intelligence-Director",
|
||||
agent_description="Director of market intelligence and competitive analysis",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
product_strategy = Agent(
|
||||
agent_name="Product-Strategy-Manager",
|
||||
agent_description="Product strategy and roadmap manager",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
engineering_lead = Agent(
|
||||
agent_name="Engineering-Lead",
|
||||
agent_description="Senior engineering lead and technical architect",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
operations_manager = Agent(
|
||||
agent_name="Operations-Manager",
|
||||
agent_description="Operations and implementation manager",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
compliance_officer = Agent(
|
||||
agent_name="Compliance-Officer",
|
||||
agent_description="Legal compliance and regulatory specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create comprehensive hierarchical swarm
|
||||
swarm = HierarchicalSwarm(
|
||||
name="Enterprise-Strategy-Swarm",
|
||||
description="Enterprise-level strategic planning and execution swarm",
|
||||
agents=[market_intelligence, product_strategy, engineering_lead, operations_manager, compliance_officer],
|
||||
max_loops=2,
|
||||
verbose=True,
|
||||
add_collaboration_prompt=True,
|
||||
)
|
||||
|
||||
# Test with complex enterprise scenario
|
||||
result = swarm.run(
|
||||
"Develop a comprehensive 5-year strategic plan for our company to become a leader in "
|
||||
"AI-powered enterprise solutions. Consider market opportunities, competitive landscape, "
|
||||
"technical requirements, operational capabilities, and regulatory compliance."
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
@ -1,152 +1,198 @@
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
import pytest
|
||||
|
||||
from swarms.structs.agent import Agent
|
||||
from swarms.structs.majority_voting import MajorityVoting
|
||||
|
||||
|
||||
def test_majority_voting_run_concurrent(mocker):
|
||||
# Create mock agents
|
||||
agent1 = MagicMock(spec=Agent)
|
||||
agent2 = MagicMock(spec=Agent)
|
||||
agent3 = MagicMock(spec=Agent)
|
||||
def test_majority_voting_basic_execution():
|
||||
"""Test basic MajorityVoting execution with multiple agents"""
|
||||
# Create specialized agents with different perspectives
|
||||
geographer = Agent(
|
||||
agent_name="Geography-Expert",
|
||||
agent_description="Expert in geography and world capitals",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mock majority voting
|
||||
mv = MajorityVoting(
|
||||
agents=[agent1, agent2, agent3],
|
||||
concurrent=True,
|
||||
multithreaded=False,
|
||||
historian = Agent(
|
||||
agent_name="History-Scholar",
|
||||
agent_description="Historical and cultural context specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mock conversation
|
||||
conversation = MagicMock()
|
||||
mv.conversation = conversation
|
||||
political_analyst = Agent(
|
||||
agent_name="Political-Analyst",
|
||||
agent_description="Political and administrative specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mock results
|
||||
results = ["Paris", "Paris", "Lyon"]
|
||||
# Create majority voting system
|
||||
mv = MajorityVoting(
|
||||
name="Geography-Consensus-System",
|
||||
description="Majority voting system for geographical questions",
|
||||
agents=[geographer, historian, political_analyst],
|
||||
max_loops=1,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
# Mock agent.run method
|
||||
agent1.run.return_value = results[0]
|
||||
agent2.run.return_value = results[1]
|
||||
agent3.run.return_value = results[2]
|
||||
# Test execution
|
||||
result = mv.run("What is the capital city of France?")
|
||||
assert result is not None
|
||||
|
||||
# Run majority voting
|
||||
majority_vote = mv.run("What is the capital of France?")
|
||||
|
||||
# Assert agent.run method was called with the correct task
|
||||
agent1.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
def test_majority_voting_multiple_loops():
|
||||
"""Test MajorityVoting with multiple loops for consensus refinement"""
|
||||
# Create agents with different knowledge bases
|
||||
trivia_expert = Agent(
|
||||
agent_name="Trivia-Expert",
|
||||
agent_description="General knowledge and trivia specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
agent2.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
)
|
||||
agent3.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
)
|
||||
|
||||
# Assert conversation.add method was called with the correct responses
|
||||
conversation.add.assert_any_call(agent1.agent_name, results[0])
|
||||
conversation.add.assert_any_call(agent2.agent_name, results[1])
|
||||
conversation.add.assert_any_call(agent3.agent_name, results[2])
|
||||
|
||||
# Assert majority vote is correct
|
||||
assert majority_vote is not None
|
||||
|
||||
research_analyst = Agent(
|
||||
agent_name="Research-Analyst",
|
||||
agent_description="Research and fact-checking specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
def test_majority_voting_run_multithreaded(mocker):
|
||||
# Create mock agents
|
||||
agent1 = MagicMock(spec=Agent)
|
||||
agent2 = MagicMock(spec=Agent)
|
||||
agent3 = MagicMock(spec=Agent)
|
||||
subject_matter_expert = Agent(
|
||||
agent_name="Subject-Matter-Expert",
|
||||
agent_description="Deep subject matter expertise specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mock majority voting
|
||||
# Create majority voting with multiple loops for iterative refinement
|
||||
mv = MajorityVoting(
|
||||
agents=[agent1, agent2, agent3],
|
||||
concurrent=False,
|
||||
multithreaded=True,
|
||||
name="Multi-Loop-Consensus-System",
|
||||
description="Majority voting with iterative consensus refinement",
|
||||
agents=[trivia_expert, research_analyst, subject_matter_expert],
|
||||
max_loops=3, # Allow multiple iterations
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
# Create mock conversation
|
||||
conversation = MagicMock()
|
||||
mv.conversation = conversation
|
||||
# Test multi-loop execution
|
||||
result = mv.run("What are the main causes of climate change and what can be done to mitigate them?")
|
||||
assert result is not None
|
||||
|
||||
# Create mock results
|
||||
results = ["Paris", "Paris", "Lyon"]
|
||||
|
||||
# Mock agent.run method
|
||||
agent1.run.return_value = results[0]
|
||||
agent2.run.return_value = results[1]
|
||||
agent3.run.return_value = results[2]
|
||||
|
||||
# Run majority voting
|
||||
majority_vote = mv.run("What is the capital of France?")
|
||||
|
||||
# Assert agent.run method was called with the correct task
|
||||
agent1.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
)
|
||||
agent2.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
)
|
||||
agent3.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
def test_majority_voting_business_scenario():
|
||||
"""Test MajorityVoting in a realistic business scenario"""
|
||||
# Create agents representing different business perspectives
|
||||
market_strategist = Agent(
|
||||
agent_name="Market-Strategist",
|
||||
agent_description="Market strategy and competitive analysis specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Assert conversation.add method was called with the correct responses
|
||||
conversation.add.assert_any_call(agent1.agent_name, results[0])
|
||||
conversation.add.assert_any_call(agent2.agent_name, results[1])
|
||||
conversation.add.assert_any_call(agent3.agent_name, results[2])
|
||||
financial_analyst = Agent(
|
||||
agent_name="Financial-Analyst",
|
||||
agent_description="Financial modeling and ROI analysis specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Assert majority vote is correct
|
||||
assert majority_vote is not None
|
||||
technical_architect = Agent(
|
||||
agent_name="Technical-Architect",
|
||||
agent_description="Technical feasibility and implementation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
risk_manager = Agent(
|
||||
agent_name="Risk-Manager",
|
||||
agent_description="Risk assessment and compliance specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_majority_voting_run_asynchronous(mocker):
|
||||
# Create mock agents
|
||||
agent1 = MagicMock(spec=Agent)
|
||||
agent2 = MagicMock(spec=Agent)
|
||||
agent3 = MagicMock(spec=Agent)
|
||||
operations_expert = Agent(
|
||||
agent_name="Operations-Expert",
|
||||
agent_description="Operations and implementation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mock majority voting
|
||||
# Create majority voting for business decisions
|
||||
mv = MajorityVoting(
|
||||
agents=[agent1, agent2, agent3],
|
||||
concurrent=False,
|
||||
multithreaded=False,
|
||||
asynchronous=True,
|
||||
name="Business-Decision-Consensus",
|
||||
description="Majority voting system for business strategic decisions",
|
||||
agents=[market_strategist, financial_analyst, technical_architect, risk_manager, operations_expert],
|
||||
max_loops=2,
|
||||
verbose=True,
|
||||
)
|
||||
|
||||
# Create mock conversation
|
||||
conversation = MagicMock()
|
||||
mv.conversation = conversation
|
||||
# Test with complex business decision
|
||||
result = mv.run(
|
||||
"Should our company invest in developing an AI-powered customer service platform? "
|
||||
"Consider market demand, financial implications, technical feasibility, risk factors, "
|
||||
"and operational requirements."
|
||||
)
|
||||
|
||||
# Create mock results
|
||||
results = ["Paris", "Paris", "Lyon"]
|
||||
assert result is not None
|
||||
|
||||
# Mock agent.run method
|
||||
agent1.run.return_value = results[0]
|
||||
agent2.run.return_value = results[1]
|
||||
agent3.run.return_value = results[2]
|
||||
|
||||
# Run majority voting
|
||||
majority_vote = await mv.run("What is the capital of France?")
|
||||
def test_majority_voting_error_handling():
|
||||
"""Test MajorityVoting error handling and validation"""
|
||||
# Test with empty agents list
|
||||
try:
|
||||
mv = MajorityVoting(agents=[])
|
||||
assert False, "Should have raised ValueError for empty agents list"
|
||||
except ValueError as e:
|
||||
assert "agents" in str(e).lower() or "empty" in str(e).lower()
|
||||
|
||||
# Assert agent.run method was called with the correct task
|
||||
agent1.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
# Test with invalid max_loops
|
||||
analyst = Agent(
|
||||
agent_name="Test-Analyst",
|
||||
agent_description="Test analyst",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
agent2.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
|
||||
try:
|
||||
mv = MajorityVoting(agents=[analyst], max_loops=0)
|
||||
assert False, "Should have raised ValueError for invalid max_loops"
|
||||
except ValueError as e:
|
||||
assert "max_loops" in str(e).lower() or "0" in str(e)
|
||||
|
||||
|
||||
def test_majority_voting_different_output_types():
|
||||
"""Test MajorityVoting with different output types"""
|
||||
# Create agents for technical analysis
|
||||
security_expert = Agent(
|
||||
agent_name="Security-Expert",
|
||||
agent_description="Cybersecurity and data protection specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
agent3.run.assert_called_once_with(
|
||||
"What is the capital of France?"
|
||||
|
||||
compliance_officer = Agent(
|
||||
agent_name="Compliance-Officer",
|
||||
agent_description="Regulatory compliance and legal specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Assert conversation.add method was called with the correct responses
|
||||
conversation.add.assert_any_call(agent1.agent_name, results[0])
|
||||
conversation.add.assert_any_call(agent2.agent_name, results[1])
|
||||
conversation.add.assert_any_call(agent3.agent_name, results[2])
|
||||
privacy_advocate = Agent(
|
||||
agent_name="Privacy-Advocate",
|
||||
agent_description="Privacy protection and data rights specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Assert majority vote is correct
|
||||
assert majority_vote is not None
|
||||
# Test different output types
|
||||
for output_type in ["dict", "string", "list"]:
|
||||
mv = MajorityVoting(
|
||||
name=f"Output-Type-Test-{output_type}",
|
||||
description=f"Testing output type: {output_type}",
|
||||
agents=[security_expert, compliance_officer, privacy_advocate],
|
||||
max_loops=1,
|
||||
output_type=output_type,
|
||||
)
|
||||
|
||||
result = mv.run("What are the key considerations for implementing GDPR compliance in our data processing systems?")
|
||||
assert result is not None
|
||||
|
||||
@ -1,84 +1,248 @@
|
||||
import pytest
|
||||
from unittest.mock import Mock, patch
|
||||
from swarms.structs.mixture_of_agents import MixtureOfAgents
|
||||
from swarms.structs.agent import Agent
|
||||
from swarms_memory import BaseVectorDatabase
|
||||
|
||||
|
||||
def test_init():
|
||||
with patch.object(
|
||||
MixtureOfAgents, "agent_check"
|
||||
) as mock_agent_check, patch.object(
|
||||
MixtureOfAgents, "final_agent_check"
|
||||
) as mock_final_agent_check, patch.object(
|
||||
MixtureOfAgents, "swarm_initialization"
|
||||
) as mock_swarm_initialization, patch.object(
|
||||
MixtureOfAgents, "communication_protocol"
|
||||
) as mock_communication_protocol:
|
||||
agents = [Mock(spec=Agent)]
|
||||
final_agent = Mock(spec=Agent)
|
||||
scp = Mock(spec=BaseVectorDatabase)
|
||||
MixtureOfAgents(
|
||||
agents=agents, final_agent=final_agent, scp=scp
|
||||
)
|
||||
mock_agent_check.assert_called_once()
|
||||
mock_final_agent_check.assert_called_once()
|
||||
mock_swarm_initialization.assert_called_once()
|
||||
mock_communication_protocol.assert_called_once()
|
||||
|
||||
|
||||
def test_communication_protocol():
|
||||
agents = [Mock(spec=Agent)]
|
||||
final_agent = Mock(spec=Agent)
|
||||
scp = Mock(spec=BaseVectorDatabase)
|
||||
swarm = MixtureOfAgents(
|
||||
agents=agents, final_agent=final_agent, scp=scp
|
||||
)
|
||||
swarm.communication_protocol()
|
||||
for agent in agents:
|
||||
agent.long_term_memory.assert_called_once_with(scp)
|
||||
|
||||
|
||||
def test_agent_check():
|
||||
final_agent = Mock(spec=Agent)
|
||||
with pytest.raises(TypeError):
|
||||
MixtureOfAgents(agents="not a list", final_agent=final_agent)
|
||||
with pytest.raises(TypeError):
|
||||
MixtureOfAgents(
|
||||
agents=["not an agent"], final_agent=final_agent
|
||||
)
|
||||
|
||||
|
||||
def test_final_agent_check():
|
||||
agents = [Mock(spec=Agent)]
|
||||
with pytest.raises(TypeError):
|
||||
MixtureOfAgents(agents=agents, final_agent="not an agent")
|
||||
def test_mixture_of_agents_basic_initialization():
|
||||
"""Test basic MixtureOfAgents initialization with multiple agents"""
|
||||
# Create multiple specialized agents
|
||||
research_agent = Agent(
|
||||
agent_name="Research-Specialist",
|
||||
agent_description="Specialist in research and data collection",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
analysis_agent = Agent(
|
||||
agent_name="Analysis-Expert",
|
||||
agent_description="Expert in data analysis and insights",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
strategy_agent = Agent(
|
||||
agent_name="Strategy-Consultant",
|
||||
agent_description="Strategy and planning consultant",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
def test_swarm_initialization():
|
||||
with patch(
|
||||
"swarms.structs.mixture_of_agents.logger"
|
||||
) as mock_logger:
|
||||
agents = [Mock(spec=Agent)]
|
||||
final_agent = Mock(spec=Agent)
|
||||
swarm = MixtureOfAgents(
|
||||
agents=agents, final_agent=final_agent
|
||||
)
|
||||
swarm.swarm_initialization()
|
||||
assert mock_logger.info.call_count == 3
|
||||
|
||||
|
||||
def test_run():
|
||||
with patch("swarms.structs.mixture_of_agents.logger"), patch(
|
||||
"builtins.open", new_callable=Mock
|
||||
) as mock_open:
|
||||
agents = [Mock(spec=Agent)]
|
||||
final_agent = Mock(spec=Agent)
|
||||
swarm = MixtureOfAgents(
|
||||
agents=agents, final_agent=final_agent
|
||||
# Create aggregator agent
|
||||
aggregator = Agent(
|
||||
agent_name="Aggregator-Agent",
|
||||
agent_description="Agent that aggregates responses from other agents",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mixture of agents
|
||||
moa = MixtureOfAgents(
|
||||
name="Business-Analysis-Mixture",
|
||||
description="Mixture of agents for comprehensive business analysis",
|
||||
agents=[research_agent, analysis_agent, strategy_agent],
|
||||
aggregator_agent=aggregator,
|
||||
layers=3,
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Verify initialization
|
||||
assert moa.name == "Business-Analysis-Mixture"
|
||||
assert moa.description == "Mixture of agents for comprehensive business analysis"
|
||||
assert len(moa.agents) == 3
|
||||
assert moa.aggregator_agent == aggregator
|
||||
assert moa.layers == 3
|
||||
assert moa.max_loops == 1
|
||||
|
||||
|
||||
def test_mixture_of_agents_execution():
|
||||
"""Test MixtureOfAgents execution with multiple agents"""
|
||||
# Create diverse agents for different perspectives
|
||||
market_analyst = Agent(
|
||||
agent_name="Market-Analyst",
|
||||
agent_description="Market analysis and trend specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
technical_expert = Agent(
|
||||
agent_name="Technical-Expert",
|
||||
agent_description="Technical feasibility and implementation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
financial_analyst = Agent(
|
||||
agent_name="Financial-Analyst",
|
||||
agent_description="Financial modeling and ROI specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
risk_assessor = Agent(
|
||||
agent_name="Risk-Assessor",
|
||||
agent_description="Risk assessment and mitigation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create aggregator for synthesis
|
||||
aggregator = Agent(
|
||||
agent_name="Executive-Summary-Agent",
|
||||
agent_description="Executive summary and recommendation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mixture of agents
|
||||
moa = MixtureOfAgents(
|
||||
name="Comprehensive-Evaluation-Mixture",
|
||||
description="Mixture of agents for comprehensive business evaluation",
|
||||
agents=[market_analyst, technical_expert, financial_analyst, risk_assessor],
|
||||
aggregator_agent=aggregator,
|
||||
layers=2,
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Test execution
|
||||
result = moa.run("Evaluate the feasibility of launching an AI-powered healthcare platform")
|
||||
assert result is not None
|
||||
|
||||
|
||||
def test_mixture_of_agents_multiple_layers():
|
||||
"""Test MixtureOfAgents with multiple layers"""
|
||||
# Create agents for layered analysis
|
||||
data_collector = Agent(
|
||||
agent_name="Data-Collector",
|
||||
agent_description="Data collection and research specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
pattern_analyzer = Agent(
|
||||
agent_name="Pattern-Analyzer",
|
||||
agent_description="Pattern recognition and analysis specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
insight_generator = Agent(
|
||||
agent_name="Insight-Generator",
|
||||
agent_description="Insight generation and interpretation specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create aggregator
|
||||
final_aggregator = Agent(
|
||||
agent_name="Final-Aggregator",
|
||||
agent_description="Final aggregation and conclusion specialist",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create mixture with multiple layers for deeper analysis
|
||||
moa = MixtureOfAgents(
|
||||
name="Multi-Layer-Analysis-Mixture",
|
||||
description="Mixture of agents with multiple analysis layers",
|
||||
agents=[data_collector, pattern_analyzer, insight_generator],
|
||||
aggregator_agent=final_aggregator,
|
||||
layers=4,
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Test multi-layer execution
|
||||
result = moa.run("Analyze customer behavior patterns and provide strategic insights")
|
||||
assert result is not None
|
||||
|
||||
|
||||
def test_mixture_of_agents_error_handling():
|
||||
"""Test MixtureOfAgents error handling and validation"""
|
||||
# Test with empty agents list
|
||||
try:
|
||||
moa = MixtureOfAgents(agents=[])
|
||||
assert False, "Should have raised ValueError for empty agents list"
|
||||
except ValueError as e:
|
||||
assert "No agents provided" in str(e)
|
||||
|
||||
# Test with invalid aggregator system prompt
|
||||
analyst = Agent(
|
||||
agent_name="Test-Analyst",
|
||||
agent_description="Test analyst",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
try:
|
||||
moa = MixtureOfAgents(
|
||||
agents=[analyst],
|
||||
aggregator_system_prompt=""
|
||||
)
|
||||
swarm.run("task")
|
||||
for agent in agents:
|
||||
agent.run.assert_called_once()
|
||||
final_agent.run.assert_called_once()
|
||||
mock_open.assert_called_once_with(swarm.saved_file_name, "w")
|
||||
assert False, "Should have raised ValueError for empty system prompt"
|
||||
except ValueError as e:
|
||||
assert "No aggregator system prompt" in str(e)
|
||||
|
||||
|
||||
def test_mixture_of_agents_real_world_scenario():
|
||||
"""Test MixtureOfAgents in a realistic business scenario"""
|
||||
# Create agents representing different business functions
|
||||
marketing_director = Agent(
|
||||
agent_name="Marketing-Director",
|
||||
agent_description="Senior marketing director with market expertise",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
product_manager = Agent(
|
||||
agent_name="Product-Manager",
|
||||
agent_description="Product strategy and development manager",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
engineering_lead = Agent(
|
||||
agent_name="Engineering-Lead",
|
||||
agent_description="Senior engineering and technical architecture lead",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
sales_executive = Agent(
|
||||
agent_name="Sales-Executive",
|
||||
agent_description="Enterprise sales and customer relationship executive",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
legal_counsel = Agent(
|
||||
agent_name="Legal-Counsel",
|
||||
agent_description="Legal compliance and regulatory counsel",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create aggregator for executive decision making
|
||||
executive_aggregator = Agent(
|
||||
agent_name="Executive-Decision-Maker",
|
||||
agent_description="Executive decision maker and strategic aggregator",
|
||||
model_name="gpt-4o",
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Create comprehensive mixture of agents
|
||||
moa = MixtureOfAgents(
|
||||
name="Executive-Board-Mixture",
|
||||
description="Mixture of agents representing executive board for strategic decisions",
|
||||
agents=[marketing_director, product_manager, engineering_lead, sales_executive, legal_counsel],
|
||||
aggregator_agent=executive_aggregator,
|
||||
layers=3,
|
||||
max_loops=1,
|
||||
)
|
||||
|
||||
# Test with complex business scenario
|
||||
result = moa.run(
|
||||
"Develop a comprehensive go-to-market strategy for our new AI-powered enterprise platform. "
|
||||
"Consider market positioning, technical requirements, competitive landscape, sales channels, "
|
||||
"and legal compliance requirements."
|
||||
)
|
||||
|
||||
assert result is not None
|
||||
|
||||
@ -1,201 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
from swarms import Agent
|
||||
from swarm_models import OpenAIChat
|
||||
from experimental.multi_agent_collab import MultiAgentCollaboration
|
||||
|
||||
# Initialize the director agent
|
||||
|
||||
director = Agent(
|
||||
agent_name="Director",
|
||||
system_prompt="Directs the tasks for the workers",
|
||||
llm=OpenAIChat(),
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
state_save_file_type="json",
|
||||
saved_state_path="director.json",
|
||||
)
|
||||
|
||||
|
||||
# Initialize worker 1
|
||||
|
||||
worker1 = Agent(
|
||||
agent_name="Worker1",
|
||||
system_prompt="Generates a transcript for a youtube video on what swarms are",
|
||||
llm=OpenAIChat(),
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
state_save_file_type="json",
|
||||
saved_state_path="worker1.json",
|
||||
)
|
||||
|
||||
|
||||
# Initialize worker 2
|
||||
worker2 = Agent(
|
||||
agent_name="Worker2",
|
||||
system_prompt="Summarizes the transcript generated by Worker1",
|
||||
llm=OpenAIChat(),
|
||||
max_loops=1,
|
||||
dashboard=False,
|
||||
streaming_on=True,
|
||||
verbose=True,
|
||||
stopping_token="<DONE>",
|
||||
state_save_file_type="json",
|
||||
saved_state_path="worker2.json",
|
||||
)
|
||||
|
||||
|
||||
# Create a list of agents
|
||||
agents = [director, worker1, worker2]
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def collaboration():
|
||||
return MultiAgentCollaboration(agents)
|
||||
|
||||
|
||||
def test_collaboration_initialization(collaboration):
|
||||
assert len(collaboration.agents) == 2
|
||||
assert callable(collaboration.select_next_speaker)
|
||||
assert collaboration.max_loops == 10
|
||||
assert collaboration.results == []
|
||||
assert collaboration.logging is True
|
||||
|
||||
|
||||
def test_reset(collaboration):
|
||||
collaboration.reset()
|
||||
for agent in collaboration.agents:
|
||||
assert agent.step == 0
|
||||
|
||||
|
||||
def test_inject(collaboration):
|
||||
collaboration.inject("TestName", "TestMessage")
|
||||
for agent in collaboration.agents:
|
||||
assert "TestName" in agent.history[-1]
|
||||
assert "TestMessage" in agent.history[-1]
|
||||
|
||||
|
||||
def test_inject_agent(collaboration):
|
||||
agent3 = Agent(llm=OpenAIChat(), max_loops=2)
|
||||
collaboration.inject_agent(agent3)
|
||||
assert len(collaboration.agents) == 3
|
||||
assert agent3 in collaboration.agents
|
||||
|
||||
|
||||
def test_step(collaboration):
|
||||
collaboration.step()
|
||||
for agent in collaboration.agents:
|
||||
assert agent.step == 1
|
||||
|
||||
|
||||
def test_ask_for_bid(collaboration):
|
||||
agent = Mock()
|
||||
agent.bid.return_value = "<5>"
|
||||
bid = collaboration.ask_for_bid(agent)
|
||||
assert bid == 5
|
||||
|
||||
|
||||
def test_select_next_speaker(collaboration):
|
||||
collaboration.select_next_speaker = Mock(return_value=0)
|
||||
idx = collaboration.select_next_speaker(1, collaboration.agents)
|
||||
assert idx == 0
|
||||
|
||||
|
||||
def test_run(collaboration):
|
||||
collaboration.run()
|
||||
for agent in collaboration.agents:
|
||||
assert agent.step == collaboration.max_loops
|
||||
|
||||
|
||||
def test_format_results(collaboration):
|
||||
collaboration.results = [
|
||||
{"agent": "Agent1", "response": "Response1"}
|
||||
]
|
||||
formatted_results = collaboration.format_results(
|
||||
collaboration.results
|
||||
)
|
||||
assert "Agent1 responded: Response1" in formatted_results
|
||||
|
||||
|
||||
def test_save_and_load(collaboration):
|
||||
collaboration.save()
|
||||
loaded_state = collaboration.load()
|
||||
assert loaded_state["_step"] == collaboration._step
|
||||
assert loaded_state["results"] == collaboration.results
|
||||
|
||||
|
||||
def test_performance(collaboration):
|
||||
performance_data = collaboration.performance()
|
||||
for agent in collaboration.agents:
|
||||
assert agent.name in performance_data
|
||||
assert "metrics" in performance_data[agent.name]
|
||||
|
||||
|
||||
def test_set_interaction_rules(collaboration):
|
||||
rules = {"rule1": "action1", "rule2": "action2"}
|
||||
collaboration.set_interaction_rules(rules)
|
||||
assert hasattr(collaboration, "interaction_rules")
|
||||
assert collaboration.interaction_rules == rules
|
||||
|
||||
|
||||
def test_repr(collaboration):
|
||||
repr_str = repr(collaboration)
|
||||
assert isinstance(repr_str, str)
|
||||
assert "MultiAgentCollaboration" in repr_str
|
||||
|
||||
|
||||
def test_load(collaboration):
|
||||
state = {
|
||||
"step": 5,
|
||||
"results": [{"agent": "Agent1", "response": "Response1"}],
|
||||
}
|
||||
with open(collaboration.saved_file_path_name, "w") as file:
|
||||
json.dump(state, file)
|
||||
|
||||
loaded_state = collaboration.load()
|
||||
assert loaded_state["_step"] == state["step"]
|
||||
assert loaded_state["results"] == state["results"]
|
||||
|
||||
|
||||
def test_save(collaboration, tmp_path):
|
||||
collaboration.saved_file_path_name = tmp_path / "test_save.json"
|
||||
collaboration.save()
|
||||
|
||||
with open(collaboration.saved_file_path_name) as file:
|
||||
saved_data = json.load(file)
|
||||
|
||||
assert saved_data["_step"] == collaboration._step
|
||||
assert saved_data["results"] == collaboration.results
|
||||
|
||||
|
||||
# Add more tests here...
|
||||
|
||||
# Add more parameterized tests for different scenarios...
|
||||
|
||||
|
||||
# Example of exception testing
|
||||
def test_exception_handling(collaboration):
|
||||
agent = Mock()
|
||||
agent.bid.side_effect = ValueError("Invalid bid")
|
||||
with pytest.raises(ValueError):
|
||||
collaboration.ask_for_bid(agent)
|
||||
|
||||
|
||||
# Add more exception testing...
|
||||
|
||||
|
||||
# Example of environment variable testing (if applicable)
|
||||
@pytest.mark.parametrize("env_var", ["ENV_VAR_1", "ENV_VAR_2"])
|
||||
def test_environment_variables(collaboration, monkeypatch, env_var):
|
||||
monkeypatch.setenv(env_var, "test_value")
|
||||
assert os.getenv(env_var) == "test_value"
|
||||
@ -1,74 +0,0 @@
|
||||
from unittest.mock import Mock, create_autospec
|
||||
|
||||
import pytest
|
||||
|
||||
from swarm_models import OpenAIChat
|
||||
from swarms.structs import RecursiveWorkflow, Task
|
||||
|
||||
|
||||
def test_add():
|
||||
workflow = RecursiveWorkflow(stop_token="<DONE>")
|
||||
task = Mock(spec=Task)
|
||||
workflow.add(task)
|
||||
assert task in workflow.tasks
|
||||
|
||||
|
||||
def test_run():
|
||||
workflow = RecursiveWorkflow(stop_token="<DONE>")
|
||||
agent1 = create_autospec(OpenAIChat)
|
||||
agent2 = create_autospec(OpenAIChat)
|
||||
task1 = Task("What's the weather in miami", agent1)
|
||||
task2 = Task("What's the weather in miami", agent2)
|
||||
workflow.add(task1)
|
||||
workflow.add(task2)
|
||||
|
||||
agent1.execute.return_value = "Not done"
|
||||
agent2.execute.return_value = "<DONE>"
|
||||
|
||||
workflow.run()
|
||||
|
||||
assert agent1.execute.call_count >= 1
|
||||
assert agent2.execute.call_count == 1
|
||||
|
||||
|
||||
def test_run_no_tasks():
|
||||
workflow = RecursiveWorkflow(stop_token="<DONE>")
|
||||
# No tasks are added to the workflow
|
||||
# This should not raise any errors
|
||||
workflow.run()
|
||||
|
||||
|
||||
def test_run_stop_token_not_in_result():
|
||||
workflow = RecursiveWorkflow(stop_token="<DONE>")
|
||||
agent = create_autospec(OpenAIChat)
|
||||
task = Task("What's the weather in miami", agent)
|
||||
workflow.add(task)
|
||||
|
||||
agent.execute.return_value = "Not done"
|
||||
|
||||
# If the stop token is never found in the result, the workflow could run forever.
|
||||
# To prevent this, we'll set a maximum number of iterations.
|
||||
max_iterations = 1000
|
||||
for _ in range(max_iterations):
|
||||
try:
|
||||
workflow.run()
|
||||
except RecursionError:
|
||||
pytest.fail(
|
||||
"RecursiveWorkflow.run caused a RecursionError"
|
||||
)
|
||||
|
||||
assert agent.execute.call_count == max_iterations
|
||||
|
||||
|
||||
def test_run_stop_token_in_result():
|
||||
workflow = RecursiveWorkflow(stop_token="<DONE>")
|
||||
agent = create_autospec(OpenAIChat)
|
||||
task = Task("What's the weather in miami", agent)
|
||||
workflow.add(task)
|
||||
|
||||
agent.execute.return_value = "<DONE>"
|
||||
|
||||
workflow.run()
|
||||
|
||||
# If the stop token is found in the result, the workflow should stop running the task.
|
||||
assert agent.execute.call_count == 1
|
||||
@ -1,67 +0,0 @@
|
||||
# import necessary modules
|
||||
from unittest import mock
|
||||
|
||||
import pytest
|
||||
from rich.console import Console
|
||||
from rich.markdown import Markdown
|
||||
from rich.rule import Rule
|
||||
|
||||
from swarms.utils import display_markdown_message
|
||||
|
||||
|
||||
def test_basic_message():
|
||||
# Test basic message functionality
|
||||
with mock.patch.object(Console, "print") as mock_print:
|
||||
display_markdown_message("This is a test")
|
||||
mock_print.assert_called_once_with(
|
||||
Markdown("This is a test", style="cyan")
|
||||
)
|
||||
|
||||
|
||||
def test_empty_message():
|
||||
# Test how function handles empty input
|
||||
with mock.patch.object(Console, "print") as mock_print:
|
||||
display_markdown_message("")
|
||||
mock_print.assert_called_once_with("")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("color", ["cyan", "red", "blue"])
|
||||
def test_colors(color):
|
||||
# Test different colors
|
||||
with mock.patch.object(Console, "print") as mock_print:
|
||||
display_markdown_message("This is a test", color)
|
||||
mock_print.assert_called_once_with(
|
||||
Markdown("This is a test", style=color)
|
||||
)
|
||||
|
||||
|
||||
def test_dash_line():
|
||||
# Test how function handles "---"
|
||||
with mock.patch.object(Console, "print") as mock_print:
|
||||
display_markdown_message("---")
|
||||
mock_print.assert_called_once_with(Rule(style="cyan"))
|
||||
|
||||
|
||||
def test_message_with_whitespace():
|
||||
# Test how function handles message with whitespaces
|
||||
with mock.patch.object(Console, "print") as mock_print:
|
||||
display_markdown_message(" \n Test \n --- \n Test \n")
|
||||
calls = [
|
||||
mock.call(""),
|
||||
mock.call(Markdown("Test", style="cyan")),
|
||||
mock.call(Rule(style="cyan")),
|
||||
mock.call(Markdown("Test", style="cyan")),
|
||||
mock.call(""),
|
||||
]
|
||||
mock_print.assert_has_calls(calls)
|
||||
|
||||
|
||||
def test_message_start_with_greater_than():
|
||||
# Test how function handles message line starting with ">"
|
||||
with mock.patch.object(Console, "print") as mock_print:
|
||||
display_markdown_message(">This is a test")
|
||||
calls = [
|
||||
mock.call(Markdown(">This is a test", style="cyan")),
|
||||
mock.call(""),
|
||||
]
|
||||
mock_print.assert_has_calls(calls)
|
||||
@ -1,41 +0,0 @@
|
||||
from swarms.utils.math_eval import math_eval
|
||||
|
||||
|
||||
def func1_no_exception(x):
|
||||
return x + 2
|
||||
|
||||
|
||||
def func2_no_exception(x):
|
||||
return x + 2
|
||||
|
||||
|
||||
def func1_with_exception(x):
|
||||
raise ValueError()
|
||||
|
||||
|
||||
def func2_with_exception(x):
|
||||
raise ValueError()
|
||||
|
||||
|
||||
def test_same_results_no_exception(caplog):
|
||||
@math_eval(func1_no_exception, func2_no_exception)
|
||||
def test_func(x):
|
||||
return x
|
||||
|
||||
result1, result2 = test_func(5)
|
||||
assert result1 == result2 == 7
|
||||
assert "Outputs do not match" not in caplog.text
|
||||
|
||||
|
||||
def test_func1_exception(caplog):
|
||||
@math_eval(func1_with_exception, func2_no_exception)
|
||||
def test_func(x):
|
||||
return x
|
||||
|
||||
result1, result2 = test_func(5)
|
||||
assert result1 is None
|
||||
assert result2 == 7
|
||||
assert "Error in func1:" in caplog.text
|
||||
|
||||
|
||||
# similar tests for func2_with_exception and when func1 and func2 return different results
|
||||
@ -1,88 +0,0 @@
|
||||
# pytest imports
|
||||
import time
|
||||
from unittest.mock import Mock
|
||||
|
||||
import pytest
|
||||
|
||||
# Imports from your project
|
||||
from swarms.utils import metrics_decorator
|
||||
|
||||
|
||||
# Basic successful test
|
||||
def test_metrics_decorator_success():
|
||||
@metrics_decorator
|
||||
def decorated_func():
|
||||
time.sleep(0.1)
|
||||
return [1, 2, 3, 4, 5]
|
||||
|
||||
metrics = decorated_func()
|
||||
assert "Time to First Token" in metrics
|
||||
assert "Generation Latency" in metrics
|
||||
assert "Throughput:" in metrics
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"wait_time, return_val",
|
||||
[
|
||||
(0, []),
|
||||
(0.1, [1, 2, 3]),
|
||||
(0.5, list(range(50))),
|
||||
],
|
||||
)
|
||||
def test_metrics_decorator_with_various_wait_times_and_return_vals(
|
||||
wait_time, return_val
|
||||
):
|
||||
@metrics_decorator
|
||||
def decorated_func():
|
||||
time.sleep(wait_time)
|
||||
return return_val
|
||||
|
||||
metrics = decorated_func()
|
||||
assert "Time to First Token" in metrics
|
||||
assert "Generation Latency" in metrics
|
||||
assert "Throughput:" in metrics
|
||||
|
||||
|
||||
# Test to ensure that mocked time function was called and throughputs are calculated as expected
|
||||
def test_metrics_decorator_with_mocked_time(mocker):
|
||||
mocked_time = Mock()
|
||||
mocker.patch("time.time", mocked_time)
|
||||
|
||||
mocked_time.side_effect = [0, 5, 10, 20]
|
||||
|
||||
@metrics_decorator
|
||||
def decorated_func():
|
||||
return ["tok_1", "tok_2"]
|
||||
|
||||
metrics = decorated_func()
|
||||
assert (
|
||||
metrics
|
||||
== """
|
||||
Time to First Token: 5
|
||||
Generation Latency: 20
|
||||
Throughput: 0.1
|
||||
"""
|
||||
)
|
||||
mocked_time.assert_any_call()
|
||||
|
||||
|
||||
# Test to ensure that exceptions in the decorated function are propagated
|
||||
def test_metrics_decorator_raises_exception():
|
||||
@metrics_decorator
|
||||
def decorated_func():
|
||||
raise ValueError("Oops!")
|
||||
|
||||
with pytest.raises(ValueError, match="Oops!"):
|
||||
decorated_func()
|
||||
|
||||
|
||||
# Test to ensure proper handling when decorated function returns non-list value
|
||||
def test_metrics_decorator_with_non_list_return_val():
|
||||
@metrics_decorator
|
||||
def decorated_func():
|
||||
return "Hello, world!"
|
||||
|
||||
metrics = decorated_func()
|
||||
assert "Time to First Token" in metrics
|
||||
assert "Generation Latency" in metrics
|
||||
assert "Throughput:" in metrics
|
||||
Loading…
Reference in new issue