"""PhoneWork entry point: FastAPI app + Feishu long-connection client.""" from __future__ import annotations import asyncio import logging import time import uvicorn from fastapi import FastAPI from rich.logging import RichHandler from agent.manager import manager from bot.handler import start_websocket_client, get_ws_status logging.basicConfig( level=logging.DEBUG, format="%(name)-20s %(message)s", datefmt="[%X]", handlers=[RichHandler( rich_tracebacks=True, markup=True, show_path=False, omit_repeated_times=False, )], ) for _noisy in ("httpcore", "httpx", "openai._base_client", "urllib3", "lark_oapi", "websockets"): logging.getLogger(_noisy).setLevel(logging.WARNING) logger = logging.getLogger(__name__) app = FastAPI(title="PhoneWork", version="0.1.0") START_TIME = time.time() @app.get("/health") async def health() -> dict: sessions = manager.list_sessions() ws_status = get_ws_status() uptime = time.time() - START_TIME result = { "status": "ok", "uptime_seconds": round(uptime, 1), "active_sessions": len(sessions), "websocket": ws_status, } if ws_status.get("connected"): result["status"] = "ok" else: result["status"] = "degraded" return result @app.get("/health/claude") async def health_claude() -> dict: """Smoke test: run a simple claude -p command.""" from agent.pty_process import run_claude import tempfile import os start = time.time() try: with tempfile.TemporaryDirectory() as tmpdir: output = await run_claude( "Say 'pong' and nothing else", cwd=tmpdir, timeout=30.0, ) elapsed = time.time() - start return { "status": "ok", "elapsed_seconds": round(elapsed, 2), "output_preview": output[:100] if output else None, } except asyncio.TimeoutError: return {"status": "timeout", "elapsed_seconds": 30.0} except Exception as e: return {"status": "error", "error": str(e)} @app.get("/sessions") async def list_sessions() -> list: return manager.list_sessions() @app.on_event("startup") async def startup_event() -> None: await manager.start() loop = asyncio.get_event_loop() start_websocket_client(loop) logger.info("PhoneWork started") @app.on_event("shutdown") async def shutdown_event() -> None: await manager.stop() logger.info("PhoneWork shut down") if __name__ == "__main__": uvicorn.run( "main:app", host="0.0.0.0", port=8000, reload=False, log_level="info", )