Spaces:
Running
Running
File size: 13,586 Bytes
c2ea5ed 113e114 c2ea5ed 18efc55 c8243d5 18efc55 c2ea5ed 18efc55 c8243d5 18efc55 c2ea5ed 18efc55 c2ea5ed 18efc55 c2ea5ed 18efc55 c2ea5ed 18efc55 c2ea5ed 18efc55 c2ea5ed |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 |
#!/usr/bin/env python3
"""
Agent Monitoring System - Main Entry Point
This script serves as the main entry point for the agent monitoring system.
Updated: Graph visualization sizes optimized for better UI layout.
"""
# Import the complete LiteLLM fix FIRST, before any other imports that might use LiteLLM
from utils.fix_litellm_stop_param import * # This applies all the patches
# Import configuration and debug utilities
from utils.config import validate_config, debug_config
from utils.environment import debug_environment as debug_env_info
# Continue with regular imports
import argparse
import sys
import os
import logging
import subprocess
import signal
import time
import shutil
from pathlib import Path
# Add the current directory to the Python path to ensure imports work correctly
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
# Setup logging
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
datefmt="%Y-%m-%d %H:%M:%S"
)
logger = logging.getLogger("agent_monitoring")
# Helper utilities -----------------------------------------------------------
def is_command_available(cmd: str) -> bool:
"""Return True if *cmd* is found in PATH."""
return shutil.which(cmd) is not None
def in_virtualenv() -> bool:
"""Detect if running inside a virtual environment."""
return getattr(sys, 'base_prefix', sys.prefix) != sys.prefix
def run_subprocess(cmd: list[str], cwd: str | None = None, env: dict | None = None) -> bool:
"""Run subprocess, stream output, return True on success."""
try:
proc = subprocess.run(cmd, cwd=cwd, env=env, capture_output=True, text=True)
if proc.returncode != 0:
logger.error(f"Command failed: {' '.join(cmd)}\n{proc.stderr}")
return False
return True
except FileNotFoundError:
logger.error(f"Executable not found: {cmd[0]}")
return False
def parse_arguments():
"""Parse command line arguments"""
parser = argparse.ArgumentParser(description="Agent Monitoring System")
parser.add_argument("--setup", action="store_true", help="Set up the environment")
parser.add_argument("--server", action="store_true", help="Start the visualization server")
parser.add_argument("--dev", action="store_true", help="Start both frontend and backend in development mode")
parser.add_argument("--frontend", action="store_true", help="Start only the frontend development server")
parser.add_argument("--init-db", action="store_true", help="Initialize the database")
parser.add_argument("--port", type=int, default=5280, help="Port for the server")
parser.add_argument("--frontend-port", type=int, default=3001, help="Port for the frontend dev server")
parser.add_argument("--host", default="127.0.0.1", help="Host for the server")
parser.add_argument("--log-level", default="INFO",
choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"],
help="Set logging level")
parser.add_argument("--no-open-browser", action="store_true", help="Do not open browser automatically")
parser.add_argument("--first-run", action="store_true", help="Run setup + init DB, then start dev server")
return parser, parser.parse_args()
def start_frontend_dev_server(frontend_port=3001):
"""Start the React frontend development server"""
try:
logger.info(f"Starting frontend development server on port {frontend_port}...")
# Change to the React app directory
frontend_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), "frontend")
if not os.path.exists(frontend_dir):
logger.error(f"Frontend directory not found: {frontend_dir}")
return None
# Check if node_modules exists
node_modules_dir = os.path.join(frontend_dir, "node_modules")
if not os.path.exists(node_modules_dir):
logger.info("Installing frontend dependencies...")
install_process = subprocess.run(
["npm", "install"],
cwd=frontend_dir,
capture_output=True,
text=True
)
if install_process.returncode != 0:
logger.error(f"Failed to install frontend dependencies: {install_process.stderr}")
return None
# Start the development server
env = os.environ.copy()
env['PORT'] = str(frontend_port)
process = subprocess.Popen(
["npm", "run", "dev"],
cwd=frontend_dir,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True,
env=env,
bufsize=1,
universal_newlines=True
)
logger.info(f"β
Frontend development server started (PID: {process.pid})")
logger.info(f"π Frontend available at: http://localhost:{frontend_port}")
return process
except Exception as e:
logger.error(f"Failed to start frontend development server: {str(e)}")
return None
def start_backend_server(args):
"""Start the backend server"""
try:
logger.info(f"Starting backend server on port {args.port}...")
from backend.main import main as server_main
# Create a new argv to pass all relevant arguments to the server
server_args = [sys.argv[0]]
# Add port if specified
if args.port:
server_args.extend(["--port", str(args.port)])
# Preserve any other relevant flags
if args.no_open_browser:
server_args.append("--no-open-browser")
if args.log_level:
server_args.extend(["--log-level", args.log_level])
if args.host:
server_args.extend(["--host", args.host])
# Replace sys.argv with our server-specific arguments
original_argv = sys.argv.copy()
sys.argv = server_args
# Start server
logger.info(f"β
Backend server starting...")
logger.info(f"π Backend API available at: http://{args.host}:{args.port}")
server_main()
# Restore original argv
sys.argv = original_argv
except Exception as e:
logger.error(f"Failed to start backend server: {str(e)}")
def run_fullstack_dev(args):
"""Run both frontend and backend in development mode"""
logger.info("π Starting full-stack development environment...")
logger.info("=" * 60)
# Start frontend in a separate process
frontend_process = start_frontend_dev_server(args.frontend_port)
if frontend_process is None:
logger.error("Failed to start frontend. Exiting.")
return
# Wait a moment for frontend to start
time.sleep(2)
# Setup signal handlers for graceful shutdown
def signal_handler(signum, frame):
logger.info("\nπ Shutting down full-stack development environment...")
if frontend_process:
logger.info("Stopping frontend development server...")
frontend_process.terminate()
try:
frontend_process.wait(timeout=5)
except subprocess.TimeoutExpired:
frontend_process.kill()
logger.info("β
Shutdown complete")
sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)
signal.signal(signal.SIGTERM, signal_handler)
# Print startup summary
logger.info("π Full-stack development environment ready!")
logger.info("=" * 60)
logger.info(f"π Frontend (React): http://localhost:{args.frontend_port}")
logger.info(f"π Backend (FastAPI): http://{args.host}:{args.port}")
logger.info(f"π API Documentation: http://{args.host}:{args.port}/docs")
logger.info("=" * 60)
logger.info("Press Ctrl+C to stop both servers")
logger.info("=" * 60)
try:
# Start backend server (this will block)
start_backend_server(args)
except KeyboardInterrupt:
signal_handler(signal.SIGINT, None)
def main():
"""Main entry point"""
parser, args = parse_arguments()
# Update logging level if specified
if args.log_level:
logging.getLogger().setLevel(getattr(logging, args.log_level))
logger.setLevel(getattr(logging, args.log_level))
# Debug configuration on startup (but only if not just showing help)
if len(sys.argv) > 1:
debug_config()
debug_env_info() # Also show environment info
if not validate_config():
logger.error("β Configuration validation failed. Please check your environment variables.")
logger.error("π‘ Tip: Copy .env.example to .env and fill in your API keys")
return
# --------------------------------------------------
# First-run combo flag: environment setup + init DB + dev server
# --------------------------------------------------
if args.first_run:
logger.info("π° First-run initialization requested")
# 0. Ensure we're inside a virtual environment; if not, create one with uv
if not in_virtualenv():
if not is_command_available("uv"):
logger.error("β 'uv' CLI not found. Please install it first (e.g., 'pipx install uv' or 'brew install uv').")
return
logger.info("π¦ Creating virtual environment with uv ...")
if not run_subprocess(["uv", "venv", ".venv"]):
logger.error("Failed to create virtualenv via uv")
return
# Re-execute this script inside the new virtualenv
new_python = os.path.join(".venv", "Scripts" if os.name == "nt" else "bin", "python")
logger.info("π Re-execing inside virtualenv ...")
os.execv(new_python, [new_python] + sys.argv)
# 0.5 Ensure dependencies installed (run once)
deps_marker = Path(".venv/.deps_installed")
if not deps_marker.exists():
logger.info("π§ Installing project dependencies with uv ...")
if not run_subprocess(["uv", "pip", "install", "-e", "."]):
return
deps_marker.touch()
# 1. Environment setup (now handled by unified config system)
logger.info("π§ Environment setup...")
logger.info("β
Environment configuration loaded successfully")
# Note: Environment setup is now handled by the unified config system in utils/config.py
# 2. Database initialization
try:
from backend.database.init_db import init_database
logger.info("ποΈ Initializing the database...")
init_database(reset=False, force=False)
logger.info("β
Database initialization complete")
except Exception as e:
logger.error(f"Database initialization failed: {e}")
return
# 3. Decide runtime mode
if not any([args.server, args.frontend]):
args.dev = True # default to dev if nothing else specified
# 4. Verify npm if dev (frontend) requested
if args.dev and not is_command_available("npm"):
logger.warning("β οΈ 'npm' not found. Frontend will be skipped. Install Node.js & npm to enable full-stack mode.")
args.dev = False
args.server = True
# Prevent redundant checks later in the script
args.setup = False
args.init_db = False
# Proceed to regular argument handling below
# Environment setup
if args.setup:
logger.info("π§ Environment setup...")
logger.info("β
Environment configuration is handled by the unified config system")
logger.info("π‘ Configuration is automatically loaded from .env file or environment variables")
logger.info("π See .env.example for available configuration options")
return
# Initialize database
if args.init_db:
from backend.database.init_db import init_database
try:
logger.info("ποΈ Initializing database...")
init_database(reset=False, force=False)
logger.info("β
Database initialization complete")
except Exception as e:
logger.error(f"β Database initialization failed: {e}")
return
# Start full-stack development environment
if args.dev:
run_fullstack_dev(args)
return
# Start only frontend
if args.frontend:
logger.info("π Starting frontend development server only...")
frontend_process = start_frontend_dev_server(args.frontend_port)
if frontend_process:
try:
# Wait for the process and handle Ctrl+C
frontend_process.wait()
except KeyboardInterrupt:
logger.info("\nπ Stopping frontend development server...")
frontend_process.terminate()
try:
frontend_process.wait(timeout=5)
except subprocess.TimeoutExpired:
frontend_process.kill()
logger.info("β
Frontend stopped")
return
# Start server
if args.server:
start_backend_server(args)
return
# If no arguments are provided, show help
parser.print_help()
if __name__ == "__main__":
main() |