import os import logging from fastapi import FastAPI, Depends, HTTPException, Header from qkernel import QKernel from qkernel.auth import verify_token from qkernel.memory import MemoryEngine from qkernel.policy import PolicyEngine from qkernel.observability import ObservabilityBrain from qkernel.event_bus import EventBus from qkernel.healing import SelfHealingEngine from qkernel.executors import ChatExecutor, MemoryExecutor, ToolExecutor from qkernel.queue import PersistentQueue logging.basicConfig(level=logging.INFO) logger = logging.getLogger("brain_api") app = FastAPI(title="Q Brain API") _queue = PersistentQueue() def require_auth(authorization: str | None = Header(None)) -> dict: if not authorization: raise HTTPException(status_code=401, detail="missing_authorization") token = authorization.removeprefix("Bearer ") payload = verify_token(token) if payload is None: raise HTTPException(status_code=401, detail="invalid_or_expired_token") return payload def optional_auth(authorization: str | None = Header(None)) -> dict | None: if not authorization: return None token = authorization.removeprefix("Bearer ") return verify_token(token) def build_kernel() -> QKernel: kernel = QKernel() from qkernel.policy import PolicyRule kernel.policy.add_rule(PolicyRule( name="boost_chat", condition=lambda e: e.get("type") == "chat", action=lambda e, ctx: setattr(ctx, "priority_boost", 5) or ctx, )) kernel.policy.add_rule(PolicyRule( name="long_message_route", condition=lambda e: len(e.get("message", "")) > 500, action=lambda e, ctx: setattr(ctx, "route_override", "brain") or ctx, )) kernel.policy.add_rule(PolicyRule( name="route_memory", condition=lambda e: e.get("type") == "memory", action=lambda e, ctx: setattr(ctx, "route_override", "memory") or ctx, )) kernel.policy.add_rule(PolicyRule( name="route_tool", condition=lambda e: e.get("type") == "tool", action=lambda e, ctx: setattr(ctx, "route_override", "tool") or ctx, )) kernel.policy.add_rule(PolicyRule( name="route_voice", condition=lambda e: e.get("type") == "voice", action=lambda e, ctx: setattr(ctx, "route_override", "brain") or ctx, )) chat = ChatExecutor() memory = MemoryExecutor() tool = ToolExecutor() tool.register("echo", lambda p: {"echo": p.get("text", "")}) tool.register("now", lambda p: {"utc_ms": __import__("time").time() * 1000}) kernel.register_service("brain", chat) kernel.register_service("voice", chat) kernel.register_service("network", chat) kernel.register_service("chat", chat) kernel.register_service("memory", memory) kernel.register_service("tool", tool) return kernel async def _run_task(event: dict, auth: dict | None): kernel = build_kernel() user_id = (auth or {}).get("user_id", "anonymous") event.setdefault("user_id", user_id) result = await kernel.handle(event) return result @app.get("/health") async def health(): return { "status": "ok", "brain": "q-core-v13", "openai": bool(os.getenv("OPENAI_API_KEY", "")), "groq": bool(os.getenv("GROQ_API_KEY", "")), "stripe": bool(os.getenv("STRIPE_SECRET_KEY", "")), "queue": _queue.stats(), } @app.post("/brain") async def brain(request: dict, auth: dict | None = Depends(optional_auth)): return await _run_task( { "type": "chat", "message": request.get("message", ""), "context": request.get("context", []), "model": request.get("model", "fast"), }, auth, ) @app.post("/v13/task") async def v13_task(request: dict, auth: dict | None = Depends(optional_auth)): task_type = request.get("type", "chat") payload = request.get("payload") or {} mode = request.get("mode", "sync") if mode != "async": return await _run_task({"type": task_type, **payload}, auth) task_id = _queue.enqueue(task_type, {"auth_user": (auth or {}).get("user_id"), **payload}) return {"task_id": task_id, "status": "queued", "mode": "async"} @app.get("/v13/task/{task_id}") async def v13_task_status(task_id: str, auth: dict | None = Depends(optional_auth)): row = _queue.get(task_id) if row is None: raise HTTPException(status_code=404, detail="task_not_found") return row @app.post("/v13/task/process") async def v13_process_queue(auth: dict | None = Depends(optional_auth)): processed = [] while True: task = _queue.dequeue() if task is None: break result = await _run_task( {"type": task["type"], **task["payload"]}, auth ) if result.get("error"): _queue.fail(task["id"], result["error"]) else: _queue.complete(task["id"], result) processed.append({"id": task["id"], "result": result}) return {"processed": processed, "stats": _queue.stats()} @app.get("/v13/queue/stats") async def v13_queue_stats(auth: dict | None = Depends(optional_auth)): return _queue.stats() @app.post("/event") async def handle_event(event: dict, auth: dict | None = Depends(optional_auth)): return await _run_task(event, auth) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8001)