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/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()
@@ -0,0 +1,4 @@
1
+ # ambivo_agents/config/__init__.py
2
+ from .loader import load_config, ConfigurationError
3
+
4
+ __all__ = ["load_config", "ConfigurationError"]