ambivo-agents 1.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- ambivo_agents/__init__.py +91 -0
- ambivo_agents/agents/__init__.py +21 -0
- ambivo_agents/agents/assistant.py +203 -0
- ambivo_agents/agents/code_executor.py +133 -0
- ambivo_agents/agents/code_executor2.py +222 -0
- ambivo_agents/agents/knowledge_base.py +935 -0
- ambivo_agents/agents/media_editor.py +992 -0
- ambivo_agents/agents/moderator.py +617 -0
- ambivo_agents/agents/simple_web_search.py +404 -0
- ambivo_agents/agents/web_scraper.py +1027 -0
- ambivo_agents/agents/web_search.py +933 -0
- ambivo_agents/agents/youtube_download.py +784 -0
- ambivo_agents/cli.py +699 -0
- ambivo_agents/config/__init__.py +4 -0
- ambivo_agents/config/loader.py +301 -0
- ambivo_agents/core/__init__.py +33 -0
- ambivo_agents/core/base.py +1024 -0
- ambivo_agents/core/history.py +606 -0
- ambivo_agents/core/llm.py +333 -0
- ambivo_agents/core/memory.py +640 -0
- ambivo_agents/executors/__init__.py +8 -0
- ambivo_agents/executors/docker_executor.py +108 -0
- ambivo_agents/executors/media_executor.py +237 -0
- ambivo_agents/executors/youtube_executor.py +404 -0
- ambivo_agents/services/__init__.py +6 -0
- ambivo_agents/services/agent_service.py +605 -0
- ambivo_agents/services/factory.py +370 -0
- ambivo_agents-1.0.1.dist-info/METADATA +1090 -0
- ambivo_agents-1.0.1.dist-info/RECORD +33 -0
- ambivo_agents-1.0.1.dist-info/WHEEL +5 -0
- ambivo_agents-1.0.1.dist-info/entry_points.txt +3 -0
- ambivo_agents-1.0.1.dist-info/licenses/LICENSE +21 -0
- ambivo_agents-1.0.1.dist-info/top_level.txt +1 -0
ambivo_agents/cli.py
ADDED
@@ -0,0 +1,699 @@
|
|
1
|
+
#!/usr/bin/env python3
|
2
|
+
"""
|
3
|
+
ModeratorAgent CLI - Command Line Interface for the Ambivo ModeratorAgent
|
4
|
+
|
5
|
+
A comprehensive CLI tool for interacting with the ModeratorAgent that orchestrates
|
6
|
+
multiple specialized agents for various tasks including web search, knowledge base
|
7
|
+
operations, media editing, YouTube downloads, and more.
|
8
|
+
|
9
|
+
Features:
|
10
|
+
- Interactive chat interface with the ModeratorAgent
|
11
|
+
- Configuration management and validation
|
12
|
+
- Agent status monitoring and debugging
|
13
|
+
- Session management with conversation history
|
14
|
+
- Automated testing capabilities
|
15
|
+
- Multi-mode operation (interactive, single query, test mode)
|
16
|
+
|
17
|
+
Requirements:
|
18
|
+
- agent_config.yaml must be present in the current directory
|
19
|
+
- All required dependencies must be installed
|
20
|
+
- Redis server running (if configured)
|
21
|
+
|
22
|
+
Author: Hemant Gosain 'Sunny'
|
23
|
+
Company: Ambivo
|
24
|
+
Email: sgosain@ambivo.com
|
25
|
+
License: MIT
|
26
|
+
"""
|
27
|
+
|
28
|
+
import asyncio
|
29
|
+
import argparse
|
30
|
+
import json
|
31
|
+
import os
|
32
|
+
import sys
|
33
|
+
import time
|
34
|
+
import logging
|
35
|
+
from pathlib import Path
|
36
|
+
from typing import Dict, List, Any, Optional
|
37
|
+
from datetime import datetime
|
38
|
+
import signal
|
39
|
+
|
40
|
+
# Configure logging before other imports
|
41
|
+
logging.basicConfig(
|
42
|
+
level=logging.INFO,
|
43
|
+
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
44
|
+
handlers=[
|
45
|
+
logging.StreamHandler(sys.stdout)
|
46
|
+
]
|
47
|
+
)
|
48
|
+
|
49
|
+
# Import ModeratorAgent and related components
|
50
|
+
try:
|
51
|
+
from ambivo_agents.agents.moderator import ModeratorAgent
|
52
|
+
from ambivo_agents.config.loader import load_config, ConfigurationError
|
53
|
+
from ambivo_agents.core.base import AgentContext
|
54
|
+
|
55
|
+
MODERATOR_AVAILABLE = True
|
56
|
+
except ImportError as e:
|
57
|
+
print(f"ā ModeratorAgent not available: {e}")
|
58
|
+
print("š” Make sure ambivo_agents package is installed and configured properly")
|
59
|
+
MODERATOR_AVAILABLE = False
|
60
|
+
sys.exit(1)
|
61
|
+
|
62
|
+
|
63
|
+
class ModeratorCLI:
|
64
|
+
"""Comprehensive CLI for ModeratorAgent interactions"""
|
65
|
+
|
66
|
+
def __init__(self, config_path: str = "agent_config.yaml"):
|
67
|
+
"""Initialize the CLI with configuration"""
|
68
|
+
self.config_path = config_path
|
69
|
+
self.config = None
|
70
|
+
self.moderator = None
|
71
|
+
self.context = None
|
72
|
+
self.session_start_time = None
|
73
|
+
self.message_count = 0
|
74
|
+
self.conversation_history = []
|
75
|
+
self.enabled_agents = []
|
76
|
+
|
77
|
+
# CLI state
|
78
|
+
self.running = True
|
79
|
+
self.debug_mode = False
|
80
|
+
self.quiet_mode = False
|
81
|
+
|
82
|
+
# Load configuration
|
83
|
+
self._load_configuration()
|
84
|
+
|
85
|
+
# Setup signal handlers
|
86
|
+
self._setup_signal_handlers()
|
87
|
+
|
88
|
+
def _load_configuration(self):
|
89
|
+
"""Load and validate configuration from YAML file"""
|
90
|
+
if not Path(self.config_path).exists():
|
91
|
+
print(f"ā Configuration file not found: {self.config_path}")
|
92
|
+
print("š” Create a configuration file using: ambivo-agents config save-sample agent_config.yaml")
|
93
|
+
sys.exit(1)
|
94
|
+
|
95
|
+
try:
|
96
|
+
self.config = load_config(self.config_path)
|
97
|
+
print(f"ā
Configuration loaded from {self.config_path}")
|
98
|
+
except ConfigurationError as e:
|
99
|
+
print(f"ā Configuration error: {e}")
|
100
|
+
sys.exit(1)
|
101
|
+
except Exception as e:
|
102
|
+
print(f"ā Failed to load configuration: {e}")
|
103
|
+
sys.exit(1)
|
104
|
+
|
105
|
+
# Validate required sections
|
106
|
+
required_sections = ['agent_capabilities']
|
107
|
+
for section in required_sections:
|
108
|
+
if section not in self.config:
|
109
|
+
print(f"ā Missing required configuration section: {section}")
|
110
|
+
sys.exit(1)
|
111
|
+
|
112
|
+
def _setup_signal_handlers(self):
|
113
|
+
"""Setup signal handlers for graceful shutdown"""
|
114
|
+
|
115
|
+
def signal_handler(signum, frame):
|
116
|
+
print(f"\nš Received signal {signum}, initiating graceful shutdown...")
|
117
|
+
self.running = False
|
118
|
+
asyncio.create_task(self._shutdown())
|
119
|
+
|
120
|
+
signal.signal(signal.SIGINT, signal_handler)
|
121
|
+
signal.signal(signal.SIGTERM, signal_handler)
|
122
|
+
|
123
|
+
def _get_enabled_agents_from_config(self) -> List[str]:
|
124
|
+
"""Get enabled agents from configuration"""
|
125
|
+
capabilities = self.config.get('agent_capabilities', {})
|
126
|
+
enabled_agents = []
|
127
|
+
|
128
|
+
# Always include assistant as base agent
|
129
|
+
enabled_agents.append('assistant')
|
130
|
+
|
131
|
+
# Add agents based on capabilities
|
132
|
+
if capabilities.get('enable_knowledge_base', False):
|
133
|
+
enabled_agents.append('knowledge_base')
|
134
|
+
|
135
|
+
if capabilities.get('enable_web_search', False):
|
136
|
+
enabled_agents.append('web_search')
|
137
|
+
|
138
|
+
if capabilities.get('enable_code_execution', False):
|
139
|
+
enabled_agents.append('code_executor')
|
140
|
+
|
141
|
+
if capabilities.get('enable_media_editor', False):
|
142
|
+
enabled_agents.append('media_editor')
|
143
|
+
|
144
|
+
if capabilities.get('enable_youtube_download', False):
|
145
|
+
enabled_agents.append('youtube_download')
|
146
|
+
|
147
|
+
if capabilities.get('enable_web_scraping', False):
|
148
|
+
enabled_agents.append('web_scraper')
|
149
|
+
|
150
|
+
return enabled_agents
|
151
|
+
|
152
|
+
async def _initialize_moderator(self, user_id: str = None, enabled_agents: List[str] = None):
|
153
|
+
"""Initialize the ModeratorAgent"""
|
154
|
+
if not user_id:
|
155
|
+
user_id = f"cli_user_{int(time.time())}"
|
156
|
+
|
157
|
+
if not enabled_agents:
|
158
|
+
enabled_agents = self._get_enabled_agents_from_config()
|
159
|
+
|
160
|
+
self.enabled_agents = enabled_agents
|
161
|
+
|
162
|
+
try:
|
163
|
+
print("š Initializing ModeratorAgent...")
|
164
|
+
print(f"š¤ User ID: {user_id}")
|
165
|
+
print(f"š¤ Enabled agents: {', '.join(enabled_agents)}")
|
166
|
+
|
167
|
+
# Create ModeratorAgent with enabled agents
|
168
|
+
self.moderator, self.context = ModeratorAgent.create(
|
169
|
+
user_id=user_id,
|
170
|
+
tenant_id="cli_tenant",
|
171
|
+
enabled_agents=enabled_agents
|
172
|
+
)
|
173
|
+
|
174
|
+
self.session_start_time = datetime.now()
|
175
|
+
|
176
|
+
print(f"ā
ModeratorAgent initialized successfully!")
|
177
|
+
print(f"š Agent ID: {self.moderator.agent_id}")
|
178
|
+
print(f"š Session ID: {self.context.session_id}")
|
179
|
+
print(f"š£ļø Conversation ID: {self.context.conversation_id}")
|
180
|
+
|
181
|
+
# Get and display agent status
|
182
|
+
status = await self.moderator.get_agent_status()
|
183
|
+
print(f"š Active specialized agents: {status['total_agents']}")
|
184
|
+
|
185
|
+
if not self.quiet_mode:
|
186
|
+
for agent_type, agent_info in status['active_agents'].items():
|
187
|
+
print(f" ⢠{agent_type}: {agent_info['status']}")
|
188
|
+
|
189
|
+
except Exception as e:
|
190
|
+
print(f"ā Failed to initialize ModeratorAgent: {e}")
|
191
|
+
if self.debug_mode:
|
192
|
+
import traceback
|
193
|
+
traceback.print_exc()
|
194
|
+
sys.exit(1)
|
195
|
+
|
196
|
+
async def _shutdown(self):
|
197
|
+
"""Graceful shutdown"""
|
198
|
+
if self.moderator:
|
199
|
+
try:
|
200
|
+
print("š§¹ Cleaning up ModeratorAgent session...")
|
201
|
+
await self.moderator.cleanup_session()
|
202
|
+
print("ā
Cleanup completed")
|
203
|
+
except Exception as e:
|
204
|
+
print(f"ā ļø Cleanup warning: {e}")
|
205
|
+
|
206
|
+
def _print_banner(self):
|
207
|
+
"""Print CLI banner"""
|
208
|
+
if self.quiet_mode:
|
209
|
+
return
|
210
|
+
|
211
|
+
print("=" * 70)
|
212
|
+
print("šļø MODERATOR AGENT CLI")
|
213
|
+
print("=" * 70)
|
214
|
+
print("š¤ AI Agent Orchestrator - Route queries to specialized agents")
|
215
|
+
print("š Type 'help' for commands, 'quit' to exit")
|
216
|
+
print("š§ Configuration loaded from:", self.config_path)
|
217
|
+
print("=" * 70)
|
218
|
+
|
219
|
+
def _print_help(self):
|
220
|
+
"""Print help information"""
|
221
|
+
help_text = """
|
222
|
+
š MODERATOR AGENT CLI HELP
|
223
|
+
|
224
|
+
š BASIC COMMANDS:
|
225
|
+
help, h - Show this help message
|
226
|
+
quit, exit, bye - Exit the CLI
|
227
|
+
status - Show agent status and session info
|
228
|
+
config - Display current configuration
|
229
|
+
history - Show conversation history
|
230
|
+
clear - Clear conversation history
|
231
|
+
debug - Toggle debug mode
|
232
|
+
agents - List active agents and their status
|
233
|
+
|
234
|
+
š¬ CHAT COMMANDS:
|
235
|
+
Just type your message and press Enter to chat with the ModeratorAgent!
|
236
|
+
|
237
|
+
Examples:
|
238
|
+
⢠"Search for latest AI trends"
|
239
|
+
⢠"Download https://youtube.com/watch?v=example"
|
240
|
+
⢠"Ingest document.pdf into knowledge_base"
|
241
|
+
⢠"Extract audio from video.mp4"
|
242
|
+
⢠"Scrape https://example.com for content"
|
243
|
+
|
244
|
+
šÆ AGENT ROUTING:
|
245
|
+
The ModeratorAgent automatically routes your queries to appropriate agents:
|
246
|
+
⢠š Web searches ā WebSearchAgent
|
247
|
+
⢠šŗ YouTube operations ā YouTubeDownloadAgent
|
248
|
+
⢠š Knowledge base ā KnowledgeBaseAgent
|
249
|
+
⢠š¬ Media editing ā MediaEditorAgent
|
250
|
+
⢠š·ļø Web scraping ā WebScraperAgent
|
251
|
+
⢠š» Code execution ā CodeExecutorAgent
|
252
|
+
⢠š¬ General chat ā AssistantAgent
|
253
|
+
|
254
|
+
š§ ADVANCED:
|
255
|
+
Use Ctrl+C for graceful shutdown
|
256
|
+
Session state is maintained throughout your conversation
|
257
|
+
"""
|
258
|
+
print(help_text)
|
259
|
+
|
260
|
+
def _format_duration(self, seconds: float) -> str:
|
261
|
+
"""Format duration in human readable format"""
|
262
|
+
if seconds < 60:
|
263
|
+
return f"{seconds:.1f}s"
|
264
|
+
elif seconds < 3600:
|
265
|
+
minutes = int(seconds // 60)
|
266
|
+
remaining_seconds = seconds % 60
|
267
|
+
return f"{minutes}m {remaining_seconds:.1f}s"
|
268
|
+
else:
|
269
|
+
hours = int(seconds // 3600)
|
270
|
+
remaining_minutes = int((seconds % 3600) // 60)
|
271
|
+
remaining_seconds = seconds % 60
|
272
|
+
return f"{hours}h {remaining_minutes}m {remaining_seconds:.1f}s"
|
273
|
+
|
274
|
+
async def _handle_status_command(self):
|
275
|
+
"""Handle status command"""
|
276
|
+
try:
|
277
|
+
status = await self.moderator.get_agent_status()
|
278
|
+
session_duration = time.time() - self.session_start_time.timestamp()
|
279
|
+
|
280
|
+
print("\nš MODERATOR AGENT STATUS")
|
281
|
+
print("=" * 50)
|
282
|
+
print(f"š Moderator ID: {status['moderator_id']}")
|
283
|
+
print(f"š Session ID: {self.context.session_id}")
|
284
|
+
print(f"š¤ User ID: {self.context.user_id}")
|
285
|
+
print(f"ā±ļø Session Duration: {self._format_duration(session_duration)}")
|
286
|
+
print(f"š¬ Messages Processed: {self.message_count}")
|
287
|
+
print(f"š¤ Total Agents: {status['total_agents']}")
|
288
|
+
print(f"šÆ Enabled Agents: {', '.join(self.enabled_agents)}")
|
289
|
+
print(f"š Routing Patterns: {status['routing_patterns']}")
|
290
|
+
|
291
|
+
print(f"\nš ACTIVE AGENTS:")
|
292
|
+
for agent_type, agent_info in status['active_agents'].items():
|
293
|
+
agent_status = agent_info.get('status', 'unknown')
|
294
|
+
agent_id = agent_info.get('agent_id', 'unknown')
|
295
|
+
session_id = agent_info.get('session_id', 'unknown')
|
296
|
+
|
297
|
+
status_emoji = "ā
" if agent_status == "active" else "ā"
|
298
|
+
print(f" {status_emoji} {agent_type}")
|
299
|
+
print(f" ID: {agent_id}")
|
300
|
+
print(f" Session: {session_id}")
|
301
|
+
if 'error' in agent_info:
|
302
|
+
print(f" Error: {agent_info['error']}")
|
303
|
+
|
304
|
+
except Exception as e:
|
305
|
+
print(f"ā Error getting status: {e}")
|
306
|
+
|
307
|
+
def _handle_config_command(self):
|
308
|
+
"""Handle config command"""
|
309
|
+
print("\nāļø CONFIGURATION")
|
310
|
+
print("=" * 50)
|
311
|
+
print(f"š Config File: {self.config_path}")
|
312
|
+
|
313
|
+
# Agent capabilities
|
314
|
+
capabilities = self.config.get('agent_capabilities', {})
|
315
|
+
print(f"\nšļø AGENT CAPABILITIES:")
|
316
|
+
for capability, enabled in capabilities.items():
|
317
|
+
emoji = "ā
" if enabled else "ā"
|
318
|
+
print(f" {emoji} {capability}: {enabled}")
|
319
|
+
|
320
|
+
# Service configuration
|
321
|
+
service_config = self.config.get('service', {})
|
322
|
+
if service_config:
|
323
|
+
print(f"\nš§ SERVICE CONFIG:")
|
324
|
+
for key, value in service_config.items():
|
325
|
+
print(f" ⢠{key}: {value}")
|
326
|
+
|
327
|
+
# Memory configuration
|
328
|
+
memory_config = self.config.get('memory_management', {})
|
329
|
+
if memory_config:
|
330
|
+
print(f"\nš§ MEMORY CONFIG:")
|
331
|
+
for key, value in memory_config.items():
|
332
|
+
if isinstance(value, dict):
|
333
|
+
print(f" ⢠{key}:")
|
334
|
+
for sub_key, sub_value in value.items():
|
335
|
+
print(f" - {sub_key}: {sub_value}")
|
336
|
+
else:
|
337
|
+
print(f" ⢠{key}: {value}")
|
338
|
+
|
339
|
+
def _handle_history_command(self):
|
340
|
+
"""Handle history command"""
|
341
|
+
if not self.conversation_history:
|
342
|
+
print("\nš No conversation history yet")
|
343
|
+
return
|
344
|
+
|
345
|
+
print(f"\nš CONVERSATION HISTORY ({len(self.conversation_history)} messages)")
|
346
|
+
print("=" * 50)
|
347
|
+
|
348
|
+
for i, entry in enumerate(self.conversation_history[-10:], 1): # Show last 10
|
349
|
+
timestamp = entry['timestamp'].strftime("%H:%M:%S")
|
350
|
+
message_type = entry['type']
|
351
|
+
content = entry['content']
|
352
|
+
|
353
|
+
if message_type == 'user':
|
354
|
+
print(f"{i:2d}. [{timestamp}] š¤ You: {content}")
|
355
|
+
else:
|
356
|
+
agent_name = entry.get('agent', 'Assistant')
|
357
|
+
print(f"{i:2d}. [{timestamp}] š¤ {agent_name}: {content[:100]}{'...' if len(content) > 100 else ''}")
|
358
|
+
|
359
|
+
async def _handle_agents_command(self):
|
360
|
+
"""Handle agents command"""
|
361
|
+
try:
|
362
|
+
status = await self.moderator.get_agent_status()
|
363
|
+
|
364
|
+
print(f"\nš¤ AGENT REGISTRY")
|
365
|
+
print("=" * 50)
|
366
|
+
print(f"š Total Active Agents: {status['total_agents']}")
|
367
|
+
print(f"šÆ Enabled Agent Types: {', '.join(self.enabled_agents)}")
|
368
|
+
|
369
|
+
print(f"\nš DETAILED AGENT STATUS:")
|
370
|
+
for agent_type, agent_info in status['active_agents'].items():
|
371
|
+
agent_status = agent_info.get('status', 'unknown')
|
372
|
+
agent_id = agent_info.get('agent_id', 'unknown')
|
373
|
+
|
374
|
+
status_emoji = "ā
" if agent_status == "active" else "ā"
|
375
|
+
print(f"\n {status_emoji} {agent_type.upper()}")
|
376
|
+
print(f" š Agent ID: {agent_id}")
|
377
|
+
print(f" š Status: {agent_status}")
|
378
|
+
print(f" š Session: {agent_info.get('session_id', 'unknown')}")
|
379
|
+
|
380
|
+
if 'error' in agent_info:
|
381
|
+
print(f" ā Error: {agent_info['error']}")
|
382
|
+
|
383
|
+
# Add agent-specific capabilities description
|
384
|
+
if agent_type == 'web_search':
|
385
|
+
print(f" š Capabilities: Web search, news search, academic search")
|
386
|
+
elif agent_type == 'youtube_download':
|
387
|
+
print(f" šŗ Capabilities: YouTube video/audio download, info extraction")
|
388
|
+
elif agent_type == 'knowledge_base':
|
389
|
+
print(f" š Capabilities: Document ingestion, semantic search, Q&A")
|
390
|
+
elif agent_type == 'media_editor':
|
391
|
+
print(f" š¬ Capabilities: Video/audio conversion, extraction, editing")
|
392
|
+
elif agent_type == 'web_scraper':
|
393
|
+
print(f" š·ļø Capabilities: Web scraping, content extraction")
|
394
|
+
elif agent_type == 'code_executor':
|
395
|
+
print(f" š» Capabilities: Python/Bash code execution")
|
396
|
+
elif agent_type == 'assistant':
|
397
|
+
print(f" š¬ Capabilities: General conversation, help, coordination")
|
398
|
+
|
399
|
+
except Exception as e:
|
400
|
+
print(f"ā Error getting agent information: {e}")
|
401
|
+
|
402
|
+
async def _handle_clear_command(self):
|
403
|
+
"""Handle clear command"""
|
404
|
+
self.conversation_history.clear()
|
405
|
+
self.message_count = 0
|
406
|
+
print("š§¹ Conversation history cleared")
|
407
|
+
|
408
|
+
def _handle_debug_command(self):
|
409
|
+
"""Handle debug command"""
|
410
|
+
self.debug_mode = not self.debug_mode
|
411
|
+
status = "enabled" if self.debug_mode else "disabled"
|
412
|
+
print(f"š Debug mode {status}")
|
413
|
+
|
414
|
+
# Update logging level
|
415
|
+
if self.debug_mode:
|
416
|
+
logging.getLogger().setLevel(logging.DEBUG)
|
417
|
+
logging.getLogger("ambivo_agents").setLevel(logging.DEBUG)
|
418
|
+
else:
|
419
|
+
logging.getLogger().setLevel(logging.INFO)
|
420
|
+
logging.getLogger("ambivo_agents").setLevel(logging.INFO)
|
421
|
+
|
422
|
+
async def _process_user_input(self, user_input: str) -> bool:
|
423
|
+
"""Process user input and return True if should continue"""
|
424
|
+
user_input = user_input.strip()
|
425
|
+
|
426
|
+
if not user_input:
|
427
|
+
return True
|
428
|
+
|
429
|
+
# Handle commands
|
430
|
+
if user_input.lower() in ['quit', 'exit', 'bye']:
|
431
|
+
return False
|
432
|
+
elif user_input.lower() in ['help', 'h']:
|
433
|
+
self._print_help()
|
434
|
+
return True
|
435
|
+
elif user_input.lower() == 'status':
|
436
|
+
await self._handle_status_command()
|
437
|
+
return True
|
438
|
+
elif user_input.lower() == 'config':
|
439
|
+
self._handle_config_command()
|
440
|
+
return True
|
441
|
+
elif user_input.lower() == 'history':
|
442
|
+
self._handle_history_command()
|
443
|
+
return True
|
444
|
+
elif user_input.lower() == 'agents':
|
445
|
+
await self._handle_agents_command()
|
446
|
+
return True
|
447
|
+
elif user_input.lower() == 'clear':
|
448
|
+
await self._handle_clear_command()
|
449
|
+
return True
|
450
|
+
elif user_input.lower() == 'debug':
|
451
|
+
self._handle_debug_command()
|
452
|
+
return True
|
453
|
+
|
454
|
+
# Process as chat message
|
455
|
+
await self._handle_chat_message(user_input)
|
456
|
+
return True
|
457
|
+
|
458
|
+
async def _handle_chat_message(self, user_input: str):
|
459
|
+
"""Handle chat message through ModeratorAgent"""
|
460
|
+
start_time = time.time()
|
461
|
+
|
462
|
+
try:
|
463
|
+
# Store user message in history
|
464
|
+
self.conversation_history.append({
|
465
|
+
'type': 'user',
|
466
|
+
'content': user_input,
|
467
|
+
'timestamp': datetime.now()
|
468
|
+
})
|
469
|
+
|
470
|
+
# Send to ModeratorAgent
|
471
|
+
if not self.quiet_mode:
|
472
|
+
print("š¤ Processing...")
|
473
|
+
|
474
|
+
response = await self.moderator.chat(user_input)
|
475
|
+
|
476
|
+
processing_time = time.time() - start_time
|
477
|
+
self.message_count += 1
|
478
|
+
|
479
|
+
# Store response in history
|
480
|
+
self.conversation_history.append({
|
481
|
+
'type': 'agent',
|
482
|
+
'content': response,
|
483
|
+
'timestamp': datetime.now(),
|
484
|
+
'agent': 'ModeratorAgent'
|
485
|
+
})
|
486
|
+
|
487
|
+
# Display response
|
488
|
+
print(f"\nš¤ ModeratorAgent: {response}")
|
489
|
+
|
490
|
+
if not self.quiet_mode:
|
491
|
+
print(f"ā±ļø Processed in {processing_time:.2f}s")
|
492
|
+
|
493
|
+
except Exception as e:
|
494
|
+
print(f"ā Error processing message: {e}")
|
495
|
+
if self.debug_mode:
|
496
|
+
import traceback
|
497
|
+
traceback.print_exc()
|
498
|
+
|
499
|
+
async def run_interactive(self, user_id: str = None):
|
500
|
+
"""Run interactive CLI mode"""
|
501
|
+
await self._initialize_moderator(user_id)
|
502
|
+
|
503
|
+
self._print_banner()
|
504
|
+
|
505
|
+
print(f"\nš” ModeratorAgent ready! Type 'help' for commands or start chatting.")
|
506
|
+
print(f"š Your queries will be intelligently routed to appropriate agents.")
|
507
|
+
|
508
|
+
while self.running:
|
509
|
+
try:
|
510
|
+
user_input = input("\nš£ļø You: ").strip()
|
511
|
+
|
512
|
+
if not await self._process_user_input(user_input):
|
513
|
+
break
|
514
|
+
|
515
|
+
except KeyboardInterrupt:
|
516
|
+
print(f"\nš Shutting down gracefully...")
|
517
|
+
break
|
518
|
+
except EOFError:
|
519
|
+
print(f"\nš Session ended")
|
520
|
+
break
|
521
|
+
|
522
|
+
await self._shutdown()
|
523
|
+
|
524
|
+
async def run_single_query(self, query: str, user_id: str = None):
|
525
|
+
"""Run single query mode"""
|
526
|
+
await self._initialize_moderator(user_id)
|
527
|
+
|
528
|
+
print(f"š£ļø Query: {query}")
|
529
|
+
print("š¤ Processing...")
|
530
|
+
|
531
|
+
try:
|
532
|
+
start_time = time.time()
|
533
|
+
response = await self.moderator.chat(query)
|
534
|
+
processing_time = time.time() - start_time
|
535
|
+
|
536
|
+
print(f"\nš¤ Response: {response}")
|
537
|
+
print(f"ā±ļø Processed in {processing_time:.2f}s")
|
538
|
+
|
539
|
+
except Exception as e:
|
540
|
+
print(f"ā Error: {e}")
|
541
|
+
if self.debug_mode:
|
542
|
+
import traceback
|
543
|
+
traceback.print_exc()
|
544
|
+
|
545
|
+
await self._shutdown()
|
546
|
+
|
547
|
+
async def run_test_mode(self, user_id: str = None):
|
548
|
+
"""Run automated test mode"""
|
549
|
+
await self._initialize_moderator(user_id)
|
550
|
+
|
551
|
+
print("\nš§Ŗ RUNNING AUTOMATED TESTS")
|
552
|
+
print("=" * 50)
|
553
|
+
|
554
|
+
test_queries = [
|
555
|
+
"Hello, I need help with something",
|
556
|
+
"Search for latest AI trends in 2025",
|
557
|
+
"Download https://youtube.com/watch?v=dQw4w9WgXcQ",
|
558
|
+
"Extract audio from video.mp4 as MP3",
|
559
|
+
"What is machine learning and how does it work?",
|
560
|
+
"Scrape https://example.com for content"
|
561
|
+
]
|
562
|
+
|
563
|
+
results = []
|
564
|
+
|
565
|
+
for i, query in enumerate(test_queries, 1):
|
566
|
+
print(f"\nš Test {i}/{len(test_queries)}: {query}")
|
567
|
+
print("-" * 30)
|
568
|
+
|
569
|
+
try:
|
570
|
+
start_time = time.time()
|
571
|
+
response = await self.moderator.chat(query)
|
572
|
+
processing_time = time.time() - start_time
|
573
|
+
|
574
|
+
print(f"ā
Response: {response[:100]}{'...' if len(response) > 100 else ''}")
|
575
|
+
print(f"ā±ļø Time: {processing_time:.2f}s")
|
576
|
+
|
577
|
+
results.append({
|
578
|
+
'query': query,
|
579
|
+
'success': True,
|
580
|
+
'response_length': len(response),
|
581
|
+
'processing_time': processing_time
|
582
|
+
})
|
583
|
+
|
584
|
+
except Exception as e:
|
585
|
+
print(f"ā Error: {e}")
|
586
|
+
results.append({
|
587
|
+
'query': query,
|
588
|
+
'success': False,
|
589
|
+
'error': str(e)
|
590
|
+
})
|
591
|
+
|
592
|
+
# Print summary
|
593
|
+
print(f"\nš TEST SUMMARY")
|
594
|
+
print("=" * 50)
|
595
|
+
|
596
|
+
successful = sum(1 for r in results if r['success'])
|
597
|
+
total = len(results)
|
598
|
+
|
599
|
+
print(f"ā
Successful: {successful}/{total}")
|
600
|
+
print(f"ā Failed: {total - successful}/{total}")
|
601
|
+
|
602
|
+
if successful == total:
|
603
|
+
print("š All tests passed!")
|
604
|
+
else:
|
605
|
+
print("ā ļø Some tests failed")
|
606
|
+
|
607
|
+
avg_time = sum(r.get('processing_time', 0) for r in results if r['success']) / max(successful, 1)
|
608
|
+
print(f"ā±ļø Average processing time: {avg_time:.2f}s")
|
609
|
+
|
610
|
+
await self._shutdown()
|
611
|
+
|
612
|
+
|
613
|
+
def main():
|
614
|
+
"""Main CLI entry point"""
|
615
|
+
parser = argparse.ArgumentParser(
|
616
|
+
description="ModeratorAgent CLI - AI Agent Orchestrator",
|
617
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
618
|
+
epilog="""
|
619
|
+
Examples:
|
620
|
+
%(prog)s # Interactive mode
|
621
|
+
%(prog)s -q "Search for Python tutorials" # Single query
|
622
|
+
%(prog)s --test # Run automated tests
|
623
|
+
%(prog)s --config custom_config.yaml # Use custom config
|
624
|
+
%(prog)s --user myuser --debug # Debug mode with custom user
|
625
|
+
"""
|
626
|
+
)
|
627
|
+
|
628
|
+
parser.add_argument(
|
629
|
+
'-q', '--query',
|
630
|
+
type=str,
|
631
|
+
help='Run a single query and exit'
|
632
|
+
)
|
633
|
+
|
634
|
+
parser.add_argument(
|
635
|
+
'--test',
|
636
|
+
action='store_true',
|
637
|
+
help='Run automated test suite'
|
638
|
+
)
|
639
|
+
|
640
|
+
parser.add_argument(
|
641
|
+
'--config',
|
642
|
+
type=str,
|
643
|
+
default='agent_config.yaml',
|
644
|
+
help='Path to configuration file (default: agent_config.yaml)'
|
645
|
+
)
|
646
|
+
|
647
|
+
parser.add_argument(
|
648
|
+
'--user',
|
649
|
+
type=str,
|
650
|
+
help='User ID for the session'
|
651
|
+
)
|
652
|
+
|
653
|
+
parser.add_argument(
|
654
|
+
'--debug',
|
655
|
+
action='store_true',
|
656
|
+
help='Enable debug mode'
|
657
|
+
)
|
658
|
+
|
659
|
+
parser.add_argument(
|
660
|
+
'--quiet',
|
661
|
+
action='store_true',
|
662
|
+
help='Quiet mode - minimal output'
|
663
|
+
)
|
664
|
+
|
665
|
+
args = parser.parse_args()
|
666
|
+
|
667
|
+
if not MODERATOR_AVAILABLE:
|
668
|
+
print("ā ModeratorAgent not available. Please install the ambivo_agents package.")
|
669
|
+
sys.exit(1)
|
670
|
+
|
671
|
+
try:
|
672
|
+
# Initialize CLI
|
673
|
+
cli = ModeratorCLI(config_path=args.config)
|
674
|
+
cli.debug_mode = args.debug
|
675
|
+
cli.quiet_mode = args.quiet
|
676
|
+
|
677
|
+
# Determine mode and run
|
678
|
+
if args.query:
|
679
|
+
# Single query mode
|
680
|
+
asyncio.run(cli.run_single_query(args.query, args.user))
|
681
|
+
elif args.test:
|
682
|
+
# Test mode
|
683
|
+
asyncio.run(cli.run_test_mode(args.user))
|
684
|
+
else:
|
685
|
+
# Interactive mode
|
686
|
+
asyncio.run(cli.run_interactive(args.user))
|
687
|
+
|
688
|
+
except KeyboardInterrupt:
|
689
|
+
print("\nš CLI interrupted by user")
|
690
|
+
except Exception as e:
|
691
|
+
print(f"ā CLI error: {e}")
|
692
|
+
if args.debug:
|
693
|
+
import traceback
|
694
|
+
traceback.print_exc()
|
695
|
+
sys.exit(1)
|
696
|
+
|
697
|
+
|
698
|
+
if __name__ == "__main__":
|
699
|
+
main()
|