Spaces:
Paused
Paused
| #!/usr/bin/env python3 | |
| """ | |
| Enhanced Launch Script with Genesis Integration | |
| Generated by Uatu Genesis Engine | |
| Handles: | |
| - Secure credential vault (local .env) | |
| - Avatar generation via Flux (first boot) | |
| - Construct narrative loading | |
| - System context injection | |
| """ | |
| import sys | |
| import os | |
| import time | |
| import logging | |
| from pathlib import Path | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, | |
| format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Add agent-zero to path | |
| agent_zero_path = Path(__file__).parent.parent.parent / "agent_zero_framework" | |
| sys.path.insert(0, str(agent_zero_path)) | |
| def secure_boot_sequence(): | |
| """ | |
| Handles secure credential injection via local .env vault. | |
| Ensures keys exist in memory but are not committed to git. | |
| """ | |
| print("\n" + "="*60) | |
| print(" 🛡️ GRIZZLY MEDICINE: SECURE BOOT PROTOCOL (V2.0)") | |
| print("="*60) | |
| # 1. Define Vault Paths | |
| # Navigate up from persona directory to repo root | |
| persona_dir = Path(__file__).parent | |
| agent_zero_dir = persona_dir.parent.parent | |
| repo_root = agent_zero_dir.parent | |
| vault_path = repo_root / ".env" | |
| # 2. Check for existing vault | |
| if vault_path.exists(): | |
| print(">> DETECTED LOCAL VAULT (.env)") | |
| print(">> DECRYPTING CREDENTIALS...") | |
| # Use python-dotenv for robust parsing (handles quotes, escaping, etc.) | |
| try: | |
| from dotenv import dotenv_values | |
| env_vars = dotenv_values(vault_path) | |
| # Validate and inject environment variables | |
| count = 0 | |
| allowed_keys = { | |
| 'OPENROUTER_API_KEY', 'HF_TOKEN', 'HUGGING_FACE_HUB_TOKEN', | |
| 'GITHUB_TOKEN', 'CONVEX_URL', 'CONVEX_ADMIN_KEY' | |
| } | |
| for key, value in env_vars.items(): | |
| # Only load whitelisted keys for security | |
| if key in allowed_keys and value: | |
| os.environ[key] = value | |
| count += 1 | |
| print(f">> {count} KEYS INJECTED FROM .env") | |
| # Also load .env.convex if it exists (auto-generated during genesis) | |
| convex_vault_path = repo_root / ".env.convex" | |
| if convex_vault_path.exists(): | |
| print(">> DETECTED CONVEX VAULT (.env.convex)") | |
| convex_vars = dotenv_values(convex_vault_path) | |
| convex_count = 0 | |
| for key, value in convex_vars.items(): | |
| if key in allowed_keys and value: | |
| os.environ[key] = value | |
| convex_count += 1 | |
| print(f">> {convex_count} CONVEX KEYS INJECTED") | |
| time.sleep(1) | |
| return | |
| except ImportError: | |
| # Fallback to manual parsing if python-dotenv not available | |
| count = 0 | |
| with open(vault_path, "r", encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| # Skip empty lines and comments | |
| if not line or line.startswith("#"): | |
| continue | |
| if "=" in line: | |
| key, value = line.split("=", 1) | |
| # Strip whitespace and remove quotes if present | |
| key = key.strip() | |
| value = value.strip().strip('"').strip("'") | |
| # Validate key format (alphanumeric and underscores only) | |
| if key and key.replace('_', '').isalnum(): | |
| os.environ[key] = value | |
| count += 1 | |
| print(f">> {count} KEYS INJECTED FROM .env") | |
| # Also load .env.convex if it exists (fallback parsing) | |
| convex_vault_path = repo_root / ".env.convex" | |
| if convex_vault_path.exists(): | |
| print(">> DETECTED CONVEX VAULT (.env.convex)") | |
| convex_count = 0 | |
| with open(convex_vault_path, "r", encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| if not line or line.startswith("#"): | |
| continue | |
| if "=" in line: | |
| key, value = line.split("=", 1) | |
| key = key.strip() | |
| value = value.strip().strip('"').strip("'") | |
| if key and key.replace('_', '').isalnum(): | |
| os.environ[key] = value | |
| convex_count += 1 | |
| print(f">> {convex_count} CONVEX KEYS INJECTED") | |
| time.sleep(1) | |
| return | |
| # 3. First Run - Manual Entry | |
| print("\n[FIRST RUN DETECTED - SYSTEM CONFIGURATION REQUIRED]") | |
| print("Please enter credentials. They will be saved locally to .env") | |
| print("and automatically added to .gitignore.\n") | |
| # The Four Pillars | |
| or_key = input("1. OpenRouter Key (The Brain): ").strip() | |
| hf_key = input("2. Hugging Face Token (The Face): ").strip() | |
| gh_key = input("3. GitHub Token (The Hands): ").strip() | |
| print("\n[CONVEX SETUP]") | |
| print(" Go to https://dashboard.convex.dev -> Create Project") | |
| print(" Settings -> URL & Deploy Key") | |
| convex_url = input("4. Convex Deployment URL (The Memory): ").strip() | |
| convex_key = input("5. Convex Admin Key (Optional - for Admin): ").strip() | |
| # Inject into current session immediately (only if non-empty) | |
| if or_key: os.environ["OPENROUTER_API_KEY"] = or_key | |
| if hf_key: | |
| os.environ["HF_TOKEN"] = hf_key | |
| os.environ["HUGGING_FACE_HUB_TOKEN"] = hf_key | |
| if gh_key: os.environ["GITHUB_TOKEN"] = gh_key | |
| if convex_url: os.environ["CONVEX_URL"] = convex_url | |
| if convex_key: os.environ["CONVEX_ADMIN_KEY"] = convex_key | |
| # 4. Save to Vault | |
| save = input("\n>> SAVE CREDENTIALS TO LOCAL VAULT (.env)? [Y/N]: ").strip().upper() | |
| if save == "Y": | |
| # Use python-dotenv for robust writing (handles escaping automatically) | |
| try: | |
| from dotenv import set_key | |
| # Write each credential safely with automatic escaping | |
| if or_key: | |
| set_key(vault_path, "OPENROUTER_API_KEY", or_key) | |
| if hf_key: | |
| set_key(vault_path, "HF_TOKEN", hf_key) | |
| set_key(vault_path, "HUGGING_FACE_HUB_TOKEN", hf_key) | |
| if gh_key: | |
| set_key(vault_path, "GITHUB_TOKEN", gh_key) | |
| if convex_url: | |
| set_key(vault_path, "CONVEX_URL", convex_url) | |
| if convex_key: | |
| set_key(vault_path, "CONVEX_ADMIN_KEY", convex_key) | |
| print(">> VAULT CREATED.") | |
| except ImportError: | |
| # Fallback to manual writing with proper escaping | |
| with open(vault_path, "w", encoding='utf-8') as f: | |
| # Escape double quotes in values | |
| if or_key: | |
| escaped_val = or_key.replace('"', '\\"') | |
| f.write(f'OPENROUTER_API_KEY="{escaped_val}"\n') | |
| if hf_key: | |
| escaped_val = hf_key.replace('"', '\\"') | |
| f.write(f'HF_TOKEN="{escaped_val}"\n') | |
| f.write(f'HUGGING_FACE_HUB_TOKEN="{escaped_val}"\n') | |
| if gh_key: | |
| escaped_val = gh_key.replace('"', '\\"') | |
| f.write(f'GITHUB_TOKEN="{escaped_val}"\n') | |
| if convex_url: | |
| escaped_val = convex_url.replace('"', '\\"') | |
| f.write(f'CONVEX_URL="{escaped_val}"\n') | |
| if convex_key: | |
| escaped_val = convex_key.replace('"', '\\"') | |
| f.write(f'CONVEX_ADMIN_KEY="{escaped_val}"\n') | |
| print(">> VAULT CREATED.") | |
| # 5. Secure the Vault (Update .gitignore) | |
| gitignore_path = repo_root / ".gitignore" | |
| if gitignore_path.exists(): | |
| with open(gitignore_path, "r", encoding='utf-8') as f: | |
| content = f.read() | |
| # Check if .env is already in gitignore (look for uncommented lines) | |
| lines = content.split('\n') | |
| has_env = False | |
| for line in lines: | |
| stripped = line.strip() | |
| # Skip comments | |
| if stripped.startswith('#'): | |
| continue | |
| # Check for .env patterns (with or without leading slash/wildcards) | |
| if stripped in ['.env', '*.env', '**/.env', '/.env']: | |
| has_env = True | |
| break | |
| if not has_env: | |
| with open(gitignore_path, "a", encoding='utf-8') as f: | |
| f.write("\n# Local Credential Vault\n.env\n") | |
| print(">> .env ADDED TO .gitignore (SAFE FROM UPLOAD)") | |
| else: | |
| # Create gitignore if missing | |
| with open(gitignore_path, "w", encoding='utf-8') as f: | |
| f.write(".env\n") | |
| print(">> .gitignore CREATED.") | |
| else: | |
| print(">> WARNING: RUNNING IN EPHEMERAL MODE. KEYS WILL VANISH ON EXIT.") | |
| print("\n>> SYSTEMS ONLINE. WAKING DIGITAL PERSON...") | |
| time.sleep(2) | |
| def genesis_sequence(): | |
| """Execute the Genesis Sequence (first boot initialization).""" | |
| try: | |
| # Check for avatar | |
| avatar_path = Path("/app/persona_data/avatar.png") | |
| if not avatar_path.exists(): | |
| logger.info(">> GENESIS SEQUENCE: FORGING PHYSICAL FORM VIA FLUX...") | |
| try: | |
| from python.helpers.rsi_generator import ensure_avatar_exists | |
| success = ensure_avatar_exists( | |
| persona_path="/Users/grizzmed/Stark/uatu-engine/agent_zero_framework/agents/agent" | |
| ) | |
| if success: | |
| logger.info(">> AVATAR FORGED SUCCESSFULLY") | |
| else: | |
| logger.warning(">> AVATAR GENERATION FAILED (CONTINUING WITHOUT AVATAR)") | |
| except Exception as e: | |
| logger.error(f">> AVATAR GENERATION ERROR: {e}") | |
| logger.warning(">> CONTINUING WITHOUT AVATAR") | |
| else: | |
| logger.info(">> AVATAR EXISTS: GENESIS COMPLETE") | |
| # Load construct narrative if it exists | |
| construct_path = Path(__file__).parent / "construct.txt" | |
| if construct_path.exists(): | |
| logger.info(">> LOADING CONSTRUCT NARRATIVE...") | |
| construct_text = construct_path.read_text() | |
| # Store in environment for agent context initialization | |
| os.environ["CONSTRUCT_NARRATIVE"] = construct_text | |
| logger.info(">> CONSTRUCT NARRATIVE LOADED INTO SYSTEM CONTEXT") | |
| else: | |
| logger.info(">> NO CONSTRUCT NARRATIVE FOUND (OPTIONAL)") | |
| except Exception as e: | |
| logger.error(f"Genesis Sequence Error: {e}") | |
| logger.warning("Continuing with launch despite errors...") | |
| # Set persona-specific environment | |
| os.environ["AGENT_PROMPTS_DIR"] = str(Path(__file__).parent / "prompts") | |
| os.environ["WORKSHOP_PERSONA_LOCKED"] = "true" | |
| # Execute Secure Boot Sequence FIRST | |
| secure_boot_sequence() | |
| # Verify critical credentials exist | |
| if "OPENROUTER_API_KEY" not in os.environ: | |
| logger.error("CRITICAL: OPENROUTER_API_KEY not found in environment") | |
| logger.error("The persona cannot think without OpenRouter API access") | |
| sys.exit(1) | |
| if "HUGGING_FACE_HUB_TOKEN" not in os.environ and "HF_TOKEN" not in os.environ: | |
| logger.warning("WARNING: HUGGING_FACE_HUB_TOKEN not found") | |
| logger.warning("Some features may be limited without Hugging Face access") | |
| # Execute Genesis Sequence | |
| genesis_sequence() | |
| # Import and run agent zero | |
| try: | |
| from run_ui import run | |
| logger.info("=" * 80) | |
| logger.info("⚙ THE WORKSHOP - GrizzlyMedicine R&D") | |
| logger.info("=" * 80) | |
| logger.info(f"Digital Person: Initializing from /Users/grizzmed/Stark/uatu-engine/agent_zero_framework/agents/agent") | |
| logger.info(f"Container Status: DEDICATED (No persona switching)") | |
| logger.info("=" * 80) | |
| # Launch the UI | |
| run() | |
| except ImportError as e: | |
| logger.error(f"Error importing agent-zero: {e}") | |
| logger.error("Make sure agent-zero dependencies are installed:") | |
| logger.error(" pip install -r agent_zero_framework/requirements.txt") | |
| sys.exit(1) | |
| except Exception as e: | |
| logger.error(f"Error launching: {e}") | |
| import traceback | |
| traceback.print_exc() | |
| sys.exit(1) | |