"""Mini-OpenClaw Backend — FastAPI Entry Point""" import os from contextlib import asynccontextmanager from pathlib import Path from dotenv import load_dotenv from fastapi import FastAPI from fastapi.middleware.cors import CORSMiddleware load_dotenv() BASE_DIR = Path(__file__).resolve().parent @asynccontextmanager async def lifespan(app: FastAPI): """Startup: scan skills, initialize agent, build memory index.""" from tools.skills_scanner import scan_skills from graph.agent import agent_manager from graph.memory_indexer import get_memory_indexer scan_skills(BASE_DIR) agent_manager.initialize(BASE_DIR) # Initialize memory indexer for RAG mode try: indexer = get_memory_indexer(BASE_DIR) indexer.rebuild_index() except Exception as e: print(f"⚠️ Memory indexer initialization skipped: {e}") print("✅ mini OpenClaw backend ready") from services.project_assistant import ProjectAssistantService from services.assistant_worker import DurableWorker from services.assistant_settings import flags worker = DurableWorker(ProjectAssistantService()).start() if flags()["assistant"] else None from services.operations_demo import DemoService demo_worker = DurableWorker(DemoService()).start() if flags()["assistant"] and flags()["demo"] else None try: yield finally: if worker: worker.stop() if demo_worker: demo_worker.stop() app = FastAPI(title="mini OpenClaw", version="0.1.0", lifespan=lifespan) app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) from api.chat import router as chat_router from api.files import router as files_router from api.sessions import router as sessions_router from api.tokens import router as tokens_router from api.compress import router as compress_router from api.config_api import router as config_router from api.xingbang_router import router as xingbang_router from api.xingbang_v2 import router as xingbang_v2_router from api.review_assist import router as review_assist_router from api.xingbang_unified import router as xingbang_unified_router from api.risk_assess import router as risk_assess_router from api.xingbang_workspace import router as xingbang_workspace_router from api.risk_agent_config import router as risk_agent_config_router app.include_router(chat_router, prefix="/api") app.include_router(files_router, prefix="/api") app.include_router(sessions_router, prefix="/api") app.include_router(tokens_router, prefix="/api") app.include_router(compress_router, prefix="/api") app.include_router(config_router, prefix="/api") app.include_router(xingbang_router) app.include_router(xingbang_v2_router) app.include_router(review_assist_router) app.include_router(xingbang_unified_router) app.include_router(risk_assess_router, prefix="/api/risk-assess") app.include_router(xingbang_workspace_router) app.include_router(risk_agent_config_router) from api.report_agent import router as report_agent_router app.include_router(report_agent_router) from api.coordination_agent import router as coordination_agent_router app.include_router(coordination_agent_router) from api.collateral_agent import router as collateral_agent_router app.include_router(collateral_agent_router) from api.xingbang_projects import router as projects_router app.include_router(projects_router) from api.project_assistant import router as project_assistant_router from api.operations_center import router as operations_router app.include_router(operations_router) app.include_router(project_assistant_router) # S1 预审接口:必须注册在 project_assistant 之后(更具体的前缀先匹配; # 其路径为 .../project-assistant/prescreen/...)——见 claude_use/T00/04 §1 from fastapi.exceptions import RequestValidationError from api.prescreen import router as prescreen_router, validation_handler # 只为 prescreen 路径输出统一错误信封;处理器内部对其它路径交回 FastAPI 默认实现, # 因此既有端点的 {"detail": ...} 形状不变(有测试与冒烟锁定该隔离)。 app.add_exception_handler(RequestValidationError, validation_handler) app.include_router(prescreen_router) @app.get("/") async def root(): return {"name": "mini OpenClaw", "version": "0.1.0", "status": "running"} # 支持 `python app.py` 直接启动后端(FastAPI + uvicorn) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8002)