diff --git a/README.md b/README.md index 899b74b..a080826 100644 --- a/README.md +++ b/README.md @@ -4,45 +4,54 @@ Feishu bot integration with Claude Code CLI. ## Architecture -- **Agent CLI**: Claude Code (print mode) -- **Chat Server**: FastAPI -- **Client**: Feishu bot API (long-connection) +``` +┌─────────────┐ WebSocket ┌──────────────┐ LangChain ┌─────────────┐ +│ Feishu │ ◄──────────────► │ FastAPI │ ◄──────────────► │ LLM API │ +│ (client) │ │ (server) │ │ (OpenAI) │ +└─────────────┘ └──────────────┘ └─────────────┘ + │ + ▼ + ┌─────────────┐ + │ Claude Code │ + │ (PTY) │ + └─────────────┘ +``` + +**Components:** + +| Module | Purpose | +|--------|---------| +| `main.py` | FastAPI entry point, starts WebSocket client + session manager | +| `bot/handler.py` | Receives Feishu events, dispatches to orchestrator | +| `bot/feishu.py` | Sends replies back to Feishu chats | +| `orchestrator/agent.py` | LangChain agent with per-user history + active session tracking | +| `orchestrator/tools.py` | Tools: `create_conversation`, `send_to_conversation`, `close_conversation` | +| `agent/manager.py` | Session registry with idle timeout reaper | +| `agent/pty_process.py` | Runs `claude -p` headlessly, manages session continuity | + +**Flow:** User message → Feishu WebSocket → Handler → Orchestrator (LLM decides action) → Tool → Session Manager → Claude Code PTY → Response back to Feishu ## Setup -### 1. Feishu App -Create app at https://open.feishu.cn: -- Enable **Bot** capability -- Enable **long-connection event subscription** (no public URL needed) -- Get `FEISHU_APP_ID` and `FEISHU_APP_SECRET` +1. **Feishu App**: Create at https://open.feishu.cn + - Enable Bot capability + long-connection event subscription + - Get `FEISHU_APP_ID` and `FEISHU_APP_SECRET` -### 2. LLM Endpoint -Configure OpenAI-compatible endpoint: -- `OPENAI_BASE_URL` -- `OPENAI_API_KEY` -- `OPENAI_MODEL` +2. **LLM Endpoint**: Configure OpenAI-compatible endpoint + - `OPENAI_BASE_URL`, `OPENAI_API_KEY`, `OPENAI_MODEL` -### 3. Claude Code CLI -- Install and authenticate `claude` command -- Ensure available in PATH +3. **Claude Code CLI**: Install and authenticate `claude` command -### 4. Configuration -```bash -cp keyring.example.yaml keyring.yaml -# Edit keyring.yaml with your credentials -``` +4. **Configuration**: + ```bash + cp keyring.example.yaml keyring.yaml + # Edit keyring.yaml with your credentials + ``` -### 5. Run -```bash -pip install -r requirements.txt -python main.py -``` +5. **Run**: + ```bash + pip install -r requirements.txt + python main.py + ``` -## Requirements - -| Item | Notes | -|---|---| -| Python 3.11+ | Required | -| Feishu App | Bot + long-connection enabled | -| OpenAI-compatible LLM | API endpoint and key | -| Claude Code CLI | Installed + authenticated | +**Requirements**: Python 3.11+ diff --git a/ROADMAP.md b/ROADMAP.md new file mode 100644 index 0000000..56ef465 --- /dev/null +++ b/ROADMAP.md @@ -0,0 +1,93 @@ +# PhoneWork Roadmap + +Issues observed in real usage, grouped by impact. No priority order within each phase. + +--- + +## Phase 1 — Core Reliability + +These are friction points that directly break or degrade the basic send-message → get-reply loop. + +### 1.1 Long output splitting +**Problem:** Feishu truncates messages at 4000 chars. Long code output is silently cut. +**Fix:** Automatically split into multiple sequential messages with `[1/3]`, `[2/3]` headers. + +### 1.2 Concurrent message handling +**Problem:** If the user sends two messages quickly, both fire `agent.run()` simultaneously for the same user, causing race conditions in `_active_conv` and interleaved `--resume` calls to the same CC session. +**Fix:** Per-user async lock (or queue) so messages process one at a time per user. + +### 1.3 Session persistence across restarts +**Problem:** `manager._sessions` is in-memory. A server restart loses all active sessions. Users have to recreate them. +**Fix:** Persist `{conv_id, cwd, cc_session_id}` to a JSON file on disk; reload on startup. + +### 1.4 Mail boy passthrough mode +**Problem:** The mail boy (GLM) sometimes paraphrases or summarizes instead of relaying verbatim, losing code blocks and exact output. +**Fix:** Bypass the mail boy entirely for follow-up messages — detect that there's an active session and call `manager.send()` directly without an LLM round-trip. + +--- + +## Phase 2 — Better Interaction Model + +Reducing the number of messages needed to get things done. + +### 2.1 Slash commands +**Problem:** Users must phrase everything as natural language for the mail boy to interpret. +**Fix:** Recognize a small set of commands directly in `handler.py` before hitting the LLM: +- `/new