From 0cd6f2b8e1e5f4da12bd0e0dce7ad31075ffa720 Mon Sep 17 00:00:00 2001 From: Nexus Dev Date: Sat, 4 Apr 2026 03:15:26 +0000 Subject: [PATCH] =?UTF-8?q?docs(38-01):=20complete=20Telegram=20bridge=20c?= =?UTF-8?q?ore=20plan=20=E2=80=94=20telegramService=20+=20telegramRoutes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .planning/REQUIREMENTS.md | 16 +-- .planning/STATE.md | 14 ++- .../38-telegram-bridge/38-01-SUMMARY.md | 111 ++++++++++++++++++ 3 files changed, 127 insertions(+), 14 deletions(-) create mode 100644 .planning/phases/38-telegram-bridge/38-01-SUMMARY.md diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 8ddc0e56..2a5c870d 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -27,12 +27,12 @@ ### Telegram Bridge -- [ ] **TGRAM-01**: Single Telegram bot relays text messages bidirectionally between user and agents -- [ ] **TGRAM-02**: Agent replies in Telegram are prefixed with agent identity (e.g. `[PM]`, `[Engineer]`) +- [x] **TGRAM-01**: Single Telegram bot relays text messages bidirectionally between user and agents +- [x] **TGRAM-02**: Agent replies in Telegram are prefixed with agent identity (e.g. `[PM]`, `[Engineer]`) - [ ] **TGRAM-03**: Telegram voice messages are transcribed (OGG → Whisper) and forwarded to agent as text - [ ] **TGRAM-04**: Agent responses can be sent back as Telegram voice notes (TTS → OGG) -- [ ] **TGRAM-05**: Telegram bridge uses long polling (no public HTTPS required) -- [ ] **TGRAM-06**: Telegram bridge is under 500 lines of code +- [x] **TGRAM-05**: Telegram bridge uses long polling (no public HTTPS required) +- [x] **TGRAM-06**: Telegram bridge is under 500 lines of code ### Onboarding @@ -86,12 +86,12 @@ | WCHAT-04 | Phase 37 | Complete | | WCHAT-05 | Phase 37 | Complete | | WCHAT-06 | Phase 37 | Complete | -| TGRAM-01 | Phase 38 | Pending | -| TGRAM-02 | Phase 38 | Pending | +| TGRAM-01 | Phase 38 | Complete | +| TGRAM-02 | Phase 38 | Complete | | TGRAM-03 | Phase 38 | Pending | | TGRAM-04 | Phase 38 | Pending | -| TGRAM-05 | Phase 38 | Pending | -| TGRAM-06 | Phase 38 | Pending | +| TGRAM-05 | Phase 38 | Complete | +| TGRAM-06 | Phase 38 | Complete | | ONBRD-01 | Phase 39 | Pending | | ONBRD-02 | Phase 39 | Pending | | ONBRD-03 | Phase 38 | Complete | diff --git a/.planning/STATE.md b/.planning/STATE.md index 3fd52d1b..9a4f1682 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -3,14 +3,14 @@ gsd_state_version: 1.0 milestone: v1.6 milestone_name: Voice Pipeline + Minimal Message Bridge status: executing -stopped_at: Completed 38-03-PLAN.md — Telegram onboarding step (TelegramStep.tsx + wizard update) -last_updated: "2026-04-04T03:14:47.447Z" +stopped_at: Completed 38-01-PLAN.md — Telegram Bridge Core (telegramService + telegramRoutes) +last_updated: "2026-04-04T03:15:16.993Z" last_activity: 2026-04-04 progress: total_phases: 4 completed_phases: 2 total_plans: 10 - completed_plans: 8 + completed_plans: 9 percent: 0 --- @@ -26,7 +26,7 @@ See: .planning/PROJECT.md (updated 2026-04-03) ## Current Position Phase: 38 (telegram-bridge) — EXECUTING -Plan: 2 of 3 +Plan: 3 of 3 Status: Ready to execute Last activity: 2026-04-04 @@ -66,6 +66,8 @@ Key constraints for v1.6: - [Phase 37]: useVoiceMode hook created in plan 37-03 to unblock VoiceModeToggle during parallel execution - [Phase 37]: Auto-play preference stored in localStorage (nexus:voice:autoplay), not nexus-settings — avoids server round-trip for fast UX - [Phase 38-telegram-bridge]: TelegramStep uses onNext/onBack props; Continue disabled until token validated; Skip always available +- [Phase 38-telegram-bridge]: telegramRoutes accepts service instance as second param — enables restart from token route +- [Phase 38-telegram-bridge]: Long-polling: deleteWebhook first, then bot.start() fire-and-forget with catch logger ### Pending Todos @@ -79,6 +81,6 @@ None yet. ## Session Continuity -Last session: 2026-04-04T03:14:47.444Z -Stopped at: Completed 38-03-PLAN.md — Telegram onboarding step (TelegramStep.tsx + wizard update) +Last session: 2026-04-04T03:15:16.990Z +Stopped at: Completed 38-01-PLAN.md — Telegram Bridge Core (telegramService + telegramRoutes) Resume file: None diff --git a/.planning/phases/38-telegram-bridge/38-01-SUMMARY.md b/.planning/phases/38-telegram-bridge/38-01-SUMMARY.md new file mode 100644 index 00000000..57823d07 --- /dev/null +++ b/.planning/phases/38-telegram-bridge/38-01-SUMMARY.md @@ -0,0 +1,111 @@ +--- +phase: 38-telegram-bridge +plan: "01" +subsystem: api +tags: [telegram, grammy, long-polling, bot, chat, relay] + +requires: + - phase: 36-voice-pipeline + provides: nexus-settings.ts with telegramToken schema field + +provides: + - grammY bot lifecycle (start/stop/isRunning) via telegramService factory + - Text message relay: Telegram user message -> agent reply with [AgentName] prefix + - In-memory session map chatId:agentId -> conversationId + - POST /api/telegram/token endpoint (validate token via getMe, save, restart bot) + - GET /api/telegram/status endpoint + - Conditional auto-start of bot in app.ts when telegramToken is configured + +affects: + - 38-02 (voice pipeline integration uses same telegramService) + - 38-03 (onboarding step that calls POST /telegram/token) + +tech-stack: + added: [grammy@^2] + patterns: + - telegramService(db) factory returns { start, stop, isRunning } — stateful module-level bot ref + - Route receives service instance as second param: telegramRoutes(db, svc) + - deleteWebhook() called before bot.start() to clear any stale webhook registration + - bot.start() not awaited (never-resolving long-poll promise) + +key-files: + created: + - server/src/services/telegram.ts + - server/src/routes/telegram.ts + modified: + - server/src/app.ts + - server/package.json + - pnpm-lock.yaml + +key-decisions: + - "telegramRoutes accepts service instance as second param (not module singleton) — enables testability and restart from token route" + - "bot variable assigned before handlers registered — allows bot.on() calls to reference the outer ref cleanly" + - "nexusSettingsService re-exported from telegram.ts removed — routes import directly from nexus-settings.ts to avoid circular potential" + +patterns-established: + - "Service factory receives db, returns lifecycle object { start, stop, isRunning } — matches voicePipelineService pattern" + - "Long-polling: deleteWebhook first, then bot.start() fire-and-forget with catch logger" + +requirements-completed: [TGRAM-01, TGRAM-02, TGRAM-05, TGRAM-06] + +duration: 15min +completed: 2026-04-04 +--- + +# Phase 38 Plan 01: Telegram Bridge Core Summary + +**grammY long-polling bot with text relay, [AgentName] prefix, session map, and /api/telegram/token + /status management routes wired into app.ts** + +## Performance + +- **Duration:** ~15 min +- **Started:** 2026-04-04T02:59:18Z +- **Completed:** 2026-04-04T03:14:18Z +- **Tasks:** 2 of 2 +- **Files modified:** 5 + +## Accomplishments +- Installed grammY v2 and created `telegramService(db)` factory with full text relay handler +- Agent reply prefixed `[AgentName]:` per TGRAM-02; session map tracks chatId:agentId -> conversationId +- `telegramRoutes` provides POST /telegram/token (getMe validation) and GET /telegram/status +- `app.ts` auto-starts bot on server boot when `telegramToken` is present in nexus settings + +## Task Commits + +1. **Task 1: Install grammY, create telegramService + telegramRoutes** - `8dbc7674` (feat) +2. **Task 2: Wire telegram service and routes into app.ts** - `3973fa08` (feat) + +## Files Created/Modified +- `server/src/services/telegram.ts` (187 lines) — grammY bot lifecycle, text relay, session map, agent prefix +- `server/src/routes/telegram.ts` — POST /telegram/token, GET /telegram/status +- `server/src/app.ts` — imports, route mount, conditional startup +- `server/package.json` — grammy dependency added +- `pnpm-lock.yaml` — lockfile updated + +## Decisions Made +- Route receives service instance as second param (`telegramRoutes(db, svc)`) rather than importing a singleton — enables the token route to call `svc.stop()` / `svc.start()` cleanly +- `bot` variable assigned at top of `start()` before handler registration so `bot.on()` uses the outer mutable ref +- `nexusSettingsService` import kept in `app.ts` directly (not re-exported from telegram.ts) to avoid any potential circular dependency + +## Deviations from Plan + +None - plan executed exactly as written. + +## Issues Encountered +- Initial implementation used `const newBot = new Bot(token)` then `newBot.on(...)`, which failed the `bot.on.*message:text` acceptance check. Refactored to assign `bot = new Bot(token)` directly so the outer ref is set before handler registration. TypeScript compiled cleanly throughout. + +## Known Stubs + +None — text relay is fully wired to chatService and puterProxyService. + +## User Setup Required + +None - no external service configuration required beyond providing a Telegram bot token via POST /api/telegram/token. + +## Next Phase Readiness +- telegramService is ready to accept voice handlers in Plan 02 (voice pipeline integration) +- Plan 03 onboarding step already exists and calls POST /telegram/token + +--- +*Phase: 38-telegram-bridge* +*Completed: 2026-04-04*