""" Grimlock - AI-Native Company Operating System Main FastAPI Application """ from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager import logging from dotenv import load_dotenv import os from api.chat import router as chat_router from core.context_manager import ContextManager from core.ai_client import AIClient # Load environment variables load_dotenv() # Configure logging logging.basicConfig( level=os.getenv("LOG_LEVEL", "INFO"), format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # Global state context_manager = None ai_client = None @asynccontextmanager async def lifespan(app: FastAPI): """Startup and shutdown events""" global context_manager, ai_client logger.info("Starting Grimlock backend...") # Initialize context manager context_path = os.getenv("CONTEXT_PATH", "./context") context_manager = ContextManager(context_path) context_manager.load_all_context() logger.info(f"Loaded context from {context_path}") # Initialize AI client api_key = os.getenv("ANTHROPIC_API_KEY") if not api_key: logger.error("ANTHROPIC_API_KEY not set!") raise ValueError("ANTHROPIC_API_KEY environment variable is required") ai_client = AIClient(api_key=api_key) logger.info("AI client initialized") yield # Cleanup logger.info("Shutting down Grimlock backend...") # Create FastAPI app app = FastAPI( title="Grimlock", description="AI-Native Company Operating System", version="0.1.0", lifespan=lifespan ) # CORS middleware app.add_middleware( CORSMiddleware, allow_origins=["*"], # Configure appropriately for production allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(chat_router, prefix="/api/chat", tags=["chat"]) @app.get("/") async def root(): """Health check endpoint""" return { "status": "online", "service": "Grimlock", "version": "0.1.0" } @app.get("/api/health") async def health(): """Detailed health check""" return { "status": "healthy", "context_loaded": context_manager is not None and context_manager.is_loaded(), "ai_client_ready": ai_client is not None } def get_context_manager() -> ContextManager: """Dependency to get context manager""" if context_manager is None: raise HTTPException(status_code=500, detail="Context manager not initialized") return context_manager def get_ai_client() -> AIClient: """Dependency to get AI client""" if ai_client is None: raise HTTPException(status_code=500, detail="AI client not initialized") return ai_client