PhoneWork/main.py
Yuyao Huang (Sam) a3622ce26d refactor: 替换 asyncio.get_event_loop 为 get_running_loop 并优化会话卡片
- 将多处 asyncio.get_event_loop() 替换为更安全的 asyncio.get_running_loop()
- 重构 Feishu 卡片功能,新增 build_sessions_card 方法显示所有会话
- 优化文件路径处理逻辑,支持绝对路径和相对路径
- 在健康检查接口中添加 pending_requests 计数
- 更新会话状态命令以支持卡片显示
2026-03-28 14:59:33 +08:00

115 lines
2.8 KiB
Python

"""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()
from agent.scheduler import scheduler
await scheduler.start()
loop = asyncio.get_running_loop()
start_websocket_client(loop)
logger.info("PhoneWork started")
@app.on_event("shutdown")
async def shutdown_event() -> None:
await manager.stop()
from agent.scheduler import scheduler
await scheduler.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",
)