|
| 1 | +"""CLI commands for BeeAI Platform GUI integration.""" |
| 2 | + |
| 3 | +import os |
| 4 | +import time |
| 5 | +import signal |
| 6 | +import sys |
| 7 | +from pathlib import Path |
| 8 | +from typing import Optional |
| 9 | + |
| 10 | +import typer |
| 11 | +from mellea.helpers.fancy_logger import FancyLogger |
| 12 | +from mellea.backends.beeai_platform import ( |
| 13 | + start_beeai_platform, |
| 14 | + create_beeai_agent_manifest, |
| 15 | + BeeAIPlatformBackend, |
| 16 | +) |
| 17 | + |
| 18 | +gui_app = typer.Typer(name="gui", help="BeeAI Platform GUI commands") |
| 19 | + |
| 20 | + |
| 21 | +@gui_app.command() |
| 22 | +def chat( |
| 23 | + script_path: Optional[str] = typer.Argument( |
| 24 | + None, |
| 25 | + help="Path to the Mellea program to serve (optional)" |
| 26 | + ), |
| 27 | + port: int = typer.Option(8080, help="Port to run the BeeAI platform on"), |
| 28 | + host: str = typer.Option("localhost", help="Host to bind to"), |
| 29 | + auto_manifest: bool = typer.Option( |
| 30 | + True, |
| 31 | + help="Automatically create agent manifest for the script" |
| 32 | + ), |
| 33 | + trace_granularity: str = typer.Option( |
| 34 | + "generate", |
| 35 | + help="Trace granularity level (none, generate, component, all)" |
| 36 | + ), |
| 37 | +): |
| 38 | + """Start a local BeeAI Platform instance with chat interface. |
| 39 | + |
| 40 | + This command spins up a local BeeAI platform instance that provides a web-based |
| 41 | + chat interface for interacting with Mellea programs. If a script path is provided, |
| 42 | + it will automatically create an agent manifest and configure the platform. |
| 43 | + """ |
| 44 | + |
| 45 | + logger = FancyLogger.get_logger() |
| 46 | + |
| 47 | + # Validate trace granularity |
| 48 | + valid_granularities = ["none", "generate", "component", "all"] |
| 49 | + if trace_granularity not in valid_granularities: |
| 50 | + typer.echo( |
| 51 | + f"Error: Invalid trace granularity '{trace_granularity}'. " |
| 52 | + f"Must be one of: {', '.join(valid_granularities)}" |
| 53 | + ) |
| 54 | + raise typer.Exit(1) |
| 55 | + |
| 56 | + try: |
| 57 | + # Check if BeeAI CLI is available |
| 58 | + import subprocess |
| 59 | + subprocess.run(["beeai", "--version"], check=True, capture_output=True) |
| 60 | + except (subprocess.CalledProcessError, FileNotFoundError): |
| 61 | + typer.echo("❌ BeeAI CLI not found.") |
| 62 | + typer.echo("📦 Install with: uv tool install beeai-cli") |
| 63 | + typer.echo("📖 See: https://docs.beeai.dev for more information") |
| 64 | + raise typer.Exit(1) |
| 65 | + |
| 66 | + # Create agent manifest if script is provided |
| 67 | + if script_path: |
| 68 | + script_path_obj = Path(script_path) |
| 69 | + if not script_path_obj.exists(): |
| 70 | + typer.echo(f"❌ Script not found: {script_path}") |
| 71 | + raise typer.Exit(1) |
| 72 | + |
| 73 | + if auto_manifest: |
| 74 | + try: |
| 75 | + agent_name = script_path_obj.stem |
| 76 | + manifest_path = create_beeai_agent_manifest( |
| 77 | + mellea_program=script_path, |
| 78 | + agent_name=agent_name, |
| 79 | + description=f"Mellea agent: {agent_name}", |
| 80 | + version="1.0.0", |
| 81 | + ) |
| 82 | + typer.echo(f"✅ Created agent manifest: {manifest_path}") |
| 83 | + except Exception as e: |
| 84 | + logger.warning(f"Failed to create agent manifest: {e}") |
| 85 | + typer.echo(f"⚠️ Warning: Could not create agent manifest: {e}") |
| 86 | + |
| 87 | + # Display startup information |
| 88 | + typer.echo("🚀 Starting BeeAI Platform...") |
| 89 | + typer.echo(f"🌐 Host: {host}") |
| 90 | + typer.echo(f"🔌 Port: {port}") |
| 91 | + typer.echo(f"📊 Trace granularity: {trace_granularity}") |
| 92 | + |
| 93 | + if script_path: |
| 94 | + typer.echo(f"📜 Mellea script: {script_path}") |
| 95 | + |
| 96 | + typer.echo(f"🖥️ Platform will be available at: http://{host}:{port}") |
| 97 | + typer.echo("🎯 Web UI will be available at: http://{host}:{port}/ui") |
| 98 | + typer.echo("\n💡 Tip: Use Ctrl+C to stop the platform") |
| 99 | + typer.echo("📖 Documentation: https://docs.beeai.dev") |
| 100 | + typer.echo("\n" + "="*50) |
| 101 | + |
| 102 | + # Set up signal handler for graceful shutdown |
| 103 | + def signal_handler(signum, frame): |
| 104 | + typer.echo("\n\n🛑 Shutting down BeeAI Platform...") |
| 105 | + sys.exit(0) |
| 106 | + |
| 107 | + signal.signal(signal.SIGINT, signal_handler) |
| 108 | + signal.signal(signal.SIGTERM, signal_handler) |
| 109 | + |
| 110 | + try: |
| 111 | + # Start the BeeAI platform |
| 112 | + start_beeai_platform(port=port, host=host, background=False) |
| 113 | + except KeyboardInterrupt: |
| 114 | + typer.echo("\n🛑 BeeAI Platform stopped by user") |
| 115 | + except Exception as e: |
| 116 | + logger.error(f"Failed to start BeeAI platform: {e}") |
| 117 | + typer.echo(f"❌ Error: {e}") |
| 118 | + raise typer.Exit(1) |
| 119 | + |
| 120 | + |
| 121 | +@gui_app.command() |
| 122 | +def status(): |
| 123 | + """Check the status of BeeAI Platform installation and configuration.""" |
| 124 | + |
| 125 | + typer.echo("🔍 Checking BeeAI Platform status...\n") |
| 126 | + |
| 127 | + # Check BeeAI CLI installation |
| 128 | + try: |
| 129 | + import subprocess |
| 130 | + result = subprocess.run( |
| 131 | + ["beeai", "--version"], |
| 132 | + check=True, |
| 133 | + capture_output=True, |
| 134 | + text=True |
| 135 | + ) |
| 136 | + typer.echo(f"✅ BeeAI CLI installed: {result.stdout.strip()}") |
| 137 | + except (subprocess.CalledProcessError, FileNotFoundError): |
| 138 | + typer.echo("❌ BeeAI CLI not found") |
| 139 | + typer.echo("📦 Install with: uv tool install beeai-cli") |
| 140 | + return |
| 141 | + |
| 142 | + # Check if platform is running |
| 143 | + try: |
| 144 | + import requests |
| 145 | + response = requests.get("http://localhost:8080/health", timeout=2) |
| 146 | + if response.status_code == 200: |
| 147 | + typer.echo("✅ BeeAI Platform is running on localhost:8080") |
| 148 | + else: |
| 149 | + typer.echo("⚠️ BeeAI Platform responded with non-200 status") |
| 150 | + except requests.RequestException: |
| 151 | + typer.echo("❌ BeeAI Platform is not running on localhost:8080") |
| 152 | + |
| 153 | + # Check Mellea BeeAI backend |
| 154 | + try: |
| 155 | + from mellea.backends.beeai import BeeAIBackend |
| 156 | + typer.echo("✅ Mellea BeeAI backend available") |
| 157 | + except ImportError as e: |
| 158 | + typer.echo(f"❌ Mellea BeeAI backend not available: {e}") |
| 159 | + |
| 160 | + # Check BeeAI Platform backend |
| 161 | + try: |
| 162 | + from mellea.backends.beeai_platform import BeeAIPlatformBackend |
| 163 | + typer.echo("✅ Mellea BeeAI Platform backend available") |
| 164 | + except ImportError as e: |
| 165 | + typer.echo(f"❌ Mellea BeeAI Platform backend not available: {e}") |
| 166 | + |
| 167 | + typer.echo("\n📖 For more information, visit: https://docs.beeai.dev") |
| 168 | + |
| 169 | + |
| 170 | +@gui_app.command() |
| 171 | +def manifest( |
| 172 | + script_path: str = typer.Argument(..., help="Path to the Mellea program"), |
| 173 | + agent_name: Optional[str] = typer.Option( |
| 174 | + None, |
| 175 | + help="Name for the agent (default: script filename)" |
| 176 | + ), |
| 177 | + description: Optional[str] = typer.Option( |
| 178 | + None, |
| 179 | + help="Description of the agent" |
| 180 | + ), |
| 181 | + output_dir: Optional[str] = typer.Option( |
| 182 | + None, |
| 183 | + help="Output directory for the manifest" |
| 184 | + ), |
| 185 | + version: str = typer.Option("1.0.0", help="Version of the agent"), |
| 186 | +): |
| 187 | + """Create a BeeAI agent manifest for a Mellea program. |
| 188 | + |
| 189 | + This command generates a manifest file that describes how to run a Mellea |
| 190 | + program as a BeeAI agent, enabling it to be discovered and used within |
| 191 | + the BeeAI Platform ecosystem. |
| 192 | + """ |
| 193 | + |
| 194 | + script_path_obj = Path(script_path) |
| 195 | + if not script_path_obj.exists(): |
| 196 | + typer.echo(f"❌ Script not found: {script_path}") |
| 197 | + raise typer.Exit(1) |
| 198 | + |
| 199 | + # Use defaults if not provided |
| 200 | + if not agent_name: |
| 201 | + agent_name = script_path_obj.stem |
| 202 | + |
| 203 | + if not description: |
| 204 | + description = f"Mellea agent based on {script_path_obj.name}" |
| 205 | + |
| 206 | + try: |
| 207 | + manifest_path = create_beeai_agent_manifest( |
| 208 | + mellea_program=script_path, |
| 209 | + agent_name=agent_name, |
| 210 | + description=description, |
| 211 | + version=version, |
| 212 | + output_dir=output_dir, |
| 213 | + ) |
| 214 | + |
| 215 | + typer.echo(f"✅ Agent manifest created successfully!") |
| 216 | + typer.echo(f"📄 Manifest file: {manifest_path}") |
| 217 | + typer.echo(f"🤖 Agent name: {agent_name}") |
| 218 | + typer.echo(f"📝 Description: {description}") |
| 219 | + typer.echo(f"🏷️ Version: {version}") |
| 220 | + |
| 221 | + typer.echo("\n💡 Next steps:") |
| 222 | + typer.echo("1. Start BeeAI Platform: m gui chat") |
| 223 | + typer.echo(f"2. Register your agent with the manifest file") |
| 224 | + typer.echo("3. Access the web UI to interact with your agent") |
| 225 | + |
| 226 | + except Exception as e: |
| 227 | + typer.echo(f"❌ Failed to create manifest: {e}") |
| 228 | + raise typer.Exit(1) |
| 229 | + |
| 230 | + |
| 231 | +@gui_app.command() |
| 232 | +def install(): |
| 233 | + """Install BeeAI CLI if not already installed.""" |
| 234 | + |
| 235 | + typer.echo("📦 Installing BeeAI CLI...") |
| 236 | + |
| 237 | + try: |
| 238 | + import subprocess |
| 239 | + |
| 240 | + # Check if already installed |
| 241 | + try: |
| 242 | + result = subprocess.run( |
| 243 | + ["beeai", "--version"], |
| 244 | + check=True, |
| 245 | + capture_output=True, |
| 246 | + text=True |
| 247 | + ) |
| 248 | + typer.echo(f"✅ BeeAI CLI already installed: {result.stdout.strip()}") |
| 249 | + return |
| 250 | + except (subprocess.CalledProcessError, FileNotFoundError): |
| 251 | + pass |
| 252 | + |
| 253 | + # Try to install using uv |
| 254 | + try: |
| 255 | + subprocess.run(["uv", "--version"], check=True, capture_output=True) |
| 256 | + typer.echo("📦 Installing BeeAI CLI using uv...") |
| 257 | + subprocess.run(["uv", "tool", "install", "beeai-cli"], check=True) |
| 258 | + typer.echo("✅ BeeAI CLI installed successfully!") |
| 259 | + except (subprocess.CalledProcessError, FileNotFoundError): |
| 260 | + typer.echo("❌ uv not found. Please install uv first:") |
| 261 | + typer.echo(" curl -LsSf https://astral.sh/uv/install.sh | sh") |
| 262 | + typer.echo(" Or visit: https://docs.astral.sh/uv/getting-started/installation/") |
| 263 | + raise typer.Exit(1) |
| 264 | + |
| 265 | + # Verify installation |
| 266 | + result = subprocess.run( |
| 267 | + ["beeai", "--version"], |
| 268 | + check=True, |
| 269 | + capture_output=True, |
| 270 | + text=True |
| 271 | + ) |
| 272 | + typer.echo(f"🎉 Installation verified: {result.stdout.strip()}") |
| 273 | + |
| 274 | + typer.echo("\n💡 Next steps:") |
| 275 | + typer.echo("1. Start BeeAI Platform: m gui chat") |
| 276 | + typer.echo("2. Configure LLM provider: beeai env setup") |
| 277 | + typer.echo("3. Access web UI when platform starts") |
| 278 | + |
| 279 | + except subprocess.CalledProcessError as e: |
| 280 | + typer.echo(f"❌ Installation failed: {e}") |
| 281 | + typer.echo("📖 Manual installation instructions: https://docs.beeai.dev/getting-started/installation/") |
| 282 | + raise typer.Exit(1) |
| 283 | + except Exception as e: |
| 284 | + typer.echo(f"❌ Unexpected error: {e}") |
| 285 | + raise typer.Exit(1) |
0 commit comments