diff --git a/.gitignore b/.gitignore index 4a123c2..f42f9fd 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,11 @@ dmypy.json # Ruff .ruff_cache/ + +# Runtime data (sessions, audit logs, scheduled jobs) +data/ + +# Legacy paths (pre-consolidation) +sessions.json +scheduled_jobs.json +audit/ diff --git a/README.md b/README.md index 706536f..f4b8fd1 100644 --- a/README.md +++ b/README.md @@ -4,27 +4,55 @@ Feishu bot that lets users control Claude Code CLI from their phone. ## Architecture +PhoneWork uses a **Router + Host Client** architecture that supports both single-machine and multi-host deployments: + ``` -┌─────────────┐ WebSocket ┌──────────────┐ LangChain ┌─────────────┐ -│ Feishu │ ◄──────────────► │ FastAPI │ ◄──────────────► │ LLM API │ -│ (client) │ │ (server) │ │ (ZhipuAI) │ -└─────────────┘ └──────────────┘ └─────────────┘ - │ - ▼ - ┌─────────────┐ - │ Claude Code │ - │ (headless) │ - └─────────────┘ +┌─────────────────┐ ┌──────────┐ WebSocket ┌────────────────────────────────────┐ +│ Feishu App │ │ Feishu │◄────────────►│ Router (public VPS) │ +│ (User's Phone) │◄───────►│ Cloud │ │ - Feishu event handler │ +└─────────────────┘ └──────────┘ │ - Router LLM (routing only) │ + │ - Node registry + active node map │ + └───────────┬────────────────────────┘ + │ WebSocket (host clients connect in) + ┌───────────┴────────────────────────┐ + │ │ + ┌──────────▼──────────┐ ┌────────────▼────────┐ + │ Host Client A │ │ Host Client B │ + │ (home-pc) │ │ (work-server) │ + │ - Mailboy LLM │ │ - Mailboy LLM │ + │ - CC sessions │ │ - CC sessions │ + │ - Shell / files │ │ - Shell / files │ + └─────────────────────┘ └─────────────────────┘ ``` +**Key design decisions:** +- Host clients connect TO the router (outbound WebSocket) — NAT-transparent +- A user can be registered on multiple nodes simultaneously +- The **router LLM** decides *which node* to route each message to +- The **node mailboy LLM** handles the full orchestration loop +- Each node maintains its own conversation history per user + +**Deployment modes:** +- **Standalone (`python standalone.py`):** Runs router + host client at localhost. Same architecture, simpler setup for single-machine use. +- **Multi-host:** Router on a public VPS, host clients behind NAT on different machines. + **Components:** | Module | Purpose | |--------|---------| -| `main.py` | FastAPI entry point, starts WebSocket client + session manager + scheduler | +| `standalone.py` | Single-process entry point: runs router + host client together | +| `main.py` | FastAPI entry point for router-only mode | +| `shared/protocol.py` | Wire protocol for router-host communication | +| `router/main.py` | FastAPI app factory, mounts `/ws/node` endpoint | +| `router/nodes.py` | Node registry, connection management, user-to-node mapping | +| `router/ws.py` | WebSocket endpoint for host clients, heartbeat, message routing | +| `router/rpc.py` | Request correlation with asyncio.Future, timeout handling | +| `router/routing_agent.py` | Single-shot routing LLM to decide which node handles each message | +| `host_client/main.py` | WebSocket client connecting to router, message handling, reconnection | +| `host_client/config.py` | Host client configuration loader | | `bot/handler.py` | Receives Feishu events via long-connection WebSocket | -| `bot/feishu.py` | Sends text/file/card replies back to Feishu | -| `bot/commands.py` | Slash command handler (`/new`, `/status`, `/shell`, `/remind`, `/tasks`, etc.) | +| `bot/feishu.py` | Sends text/file replies back to Feishu | +| `bot/commands.py` | Slash command handler (`/new`, `/status`, `/shell`, `/remind`, `/tasks`, `/nodes`, `/node`) | | `orchestrator/agent.py` | LangChain agent with per-user history + direct/smart mode + direct Q&A | | `orchestrator/tools.py` | Tools: session management, shell, file ops, web search, scheduler, task status | | `agent/manager.py` | Session registry with persistence, idle timeout, and auto-background tasks | @@ -122,6 +150,33 @@ ALLOWED_OPEN_IDS: # Optional: 秘塔AI Search API key for web search functionality # Get your key at: https://metaso.cn/search-api/api-keys METASO_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +# Optional: Multi-host mode configuration +# Set ROUTER_MODE to true to enable router mode (deploy on public VPS) +ROUTER_MODE: false +ROUTER_SECRET: your-shared-secret-for-router-host-auth +``` + +### Host Client Configuration (for multi-host mode) + +Create `host_config.yaml` for each host client: + +```yaml +NODE_ID: home-pc +DISPLAY_NAME: Home PC +ROUTER_URL: wss://router.example.com/ws/node +ROUTER_SECRET: + +OPENAI_BASE_URL: https://open.bigmodel.cn/api/paas/v4/ +OPENAI_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +OPENAI_MODEL: glm-4.7 + +WORKING_DIR: C:/Users/me/projects +METASO_API_KEY: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + +# Which Feishu open_ids this node serves +SERVES_USERS: + - ou_abc123def456 ``` --- @@ -162,6 +217,8 @@ Active sessions: `GET /sessions` | `/shell ` | Run a shell command directly (bypasses LLM) | | `/remind