实现后台任务调度器(scheduler.py)和任务运行器(task_runner.py),支持长时间运行任务的异步执行和状态跟踪 新增多种工具支持:Shell命令执行、文件操作(读写/搜索/发送)、网页搜索/问答、定时提醒等 扩展README和ROADMAP文档,描述新功能和未来多主机架构规划 在配置文件中添加METASO_API_KEY支持秘塔AI搜索功能 优化代理逻辑,自动识别通用问题直接回答而不创建会话
115 lines
2.8 KiB
Python
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_event_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",
|
|
)
|