diff --git a/.planning/REQUIREMENTS.md b/.planning/REQUIREMENTS.md index 84a1995f..f3e55c2f 100644 --- a/.planning/REQUIREMENTS.md +++ b/.planning/REQUIREMENTS.md @@ -33,7 +33,7 @@ - [x] **ASST-01**: User has persistent memory across chat sessions (summary-based, injected into system prompts) - [x] **ASST-02**: Memory content sanitized at write time to prevent prompt injection -- [ ] **ASST-03**: User can hand off an assistant conversation to a PM agent with one click, transferring context +- [x] **ASST-03**: User can hand off an assistant conversation to a PM agent with one click, transferring context - [x] **ASST-04**: Assistant and Project Builder modes work standalone or together ### CLI @@ -83,7 +83,7 @@ | ONBD-06 | Phase 32 | Complete | | ASST-01 | Phase 33 | Complete | | ASST-02 | Phase 33 | Complete | -| ASST-03 | Phase 33 | Pending | +| ASST-03 | Phase 33 | Complete | | ASST-04 | Phase 33 | Complete | | VOICE-01 | Phase 34 | Pending | | VOICE-02 | Phase 34 | Pending | diff --git a/.planning/ROADMAP.md b/.planning/ROADMAP.md index 86f90cd9..7aaac2d1 100644 --- a/.planning/ROADMAP.md +++ b/.planning/ROADMAP.md @@ -91,7 +91,7 @@ Plans: - [x] **Phase 30: Hardware Detection + Mode Selection** — Unauthenticated hardware probe, Apple Silicon unified memory handling, model recommendation database, and mode selector that gates all assistant-specific features (completed 2026-04-02) - [x] **Phase 31: Puter.js Zero-Config Cloud** — Server-proxied Puter.js adapter with full cost tracking, Google OAuth PKCE tier, and subscription auto-detection; no API keys required for zero-config path (completed 2026-04-03) - [x] **Phase 32: Multi-Step Onboarding Wizard** — Assemble all provider tiers and hardware data into a skippable multi-step wizard; summary screen routes directly into chat (completed 2026-04-03) -- [ ] **Phase 33: Persistent Memory + Personal Assistant Mode** — File-backed memory with write-time sanitization, PersonalAssistantPage, conversation handoff to PM agent +- [x] **Phase 33: Persistent Memory + Personal Assistant Mode** — File-backed memory with write-time sanitization, PersonalAssistantPage, conversation handoff to PM agent (completed 2026-04-03) - [ ] **Phase 34: Voice** — Piper TTS with pre-warm progress, Whisper STT wired into voice service, onboarding voice step activated - [ ] **Phase 35: npx buildthis CLI** — Standalone bootstrapper package with hardware detection and provider tiering parity with web onboarding @@ -161,7 +161,7 @@ Plans: Plans: - [x] 33-01-PLAN.md — Memory sanitizer, assistant memory service, REST routes, and unit tests - [x] 33-02-PLAN.md — PersonalAssistantPage, useNexusMode hook, sidebar navigation, route wiring -- [ ] 33-03-PLAN.md — Real AI streaming with memory injection, assistant-to-PM handoff route and UI +- [x] 33-03-PLAN.md — Real AI streaming with memory injection, assistant-to-PM handoff route and UI **UI hint**: yes ### Phase 34: Voice @@ -232,6 +232,6 @@ All 21 v1.5 requirements are mapped to exactly one phase. No orphans. | 30. Hardware Detection + Mode Selection | v1.5 | 2/2 | Complete | 2026-04-03 | | 31. Puter.js Zero-Config Cloud | v1.5 | 4/4 | Complete | 2026-04-03 | | 32. Multi-Step Onboarding Wizard | v1.5 | 1/1 | Complete | 2026-04-03 | -| 33. Persistent Memory + Personal Assistant Mode | v1.5 | 2/3 | In Progress| | +| 33. Persistent Memory + Personal Assistant Mode | v1.5 | 3/3 | Complete | 2026-04-03 | | 34. Voice | v1.5 | 0/TBD | Not started | - | | 35. npx buildthis CLI | v1.5 | 0/TBD | Not started | - | diff --git a/.planning/STATE.md b/.planning/STATE.md index e8222072..7f5b2256 100644 --- a/.planning/STATE.md +++ b/.planning/STATE.md @@ -2,15 +2,15 @@ gsd_state_version: 1.0 milestone: v1.5 milestone_name: Smart Onboarding + Personal AI Assistant -status: executing -stopped_at: Completed 33-persistent-memory/33-02 -last_updated: "2026-04-03T22:02:26.062Z" +status: verifying +stopped_at: Completed 33-persistent-memory/33-03 +last_updated: "2026-04-03T22:14:47.423Z" last_activity: 2026-04-03 progress: total_phases: 6 - completed_phases: 3 + completed_phases: 4 total_plans: 10 - completed_plans: 9 + completed_plans: 10 percent: 0 --- @@ -27,7 +27,7 @@ See: .planning/PROJECT.md (updated 2026-04-02) Phase: 33 (persistent-memory) — EXECUTING Plan: 3 of 3 -Status: Ready to execute +Status: Phase complete — ready for verification Last activity: 2026-04-03 Progress: [__________] 0% @@ -61,6 +61,7 @@ Progress: [__________] 0% | Phase 32-multi-step-onboarding-wizard P01 | 4 | 2 tasks | 3 files | | Phase 33 P01 | 4 | 2 tasks | 6 files | | Phase 33 P02 | 12 | 2 tasks | 8 files | +| Phase 33-persistent-memory P03 | 20 | 2 tasks | 6 files | ## Accumulated Context @@ -91,6 +92,9 @@ Key constraints for v1.5 (established at roadmap): - [Phase 33]: GitHub PAT regex changed from {36} to {36,} to handle tokens longer than the minimum expected length - [Phase 33]: PersonalAssistant uses chatApi directly for standalone full-page chat (no ChatPanel dependency) — maintains worktree isolation for parallel execution - [Phase 33]: useNexusMode defaults to 'both' while loading — prevents flash-redirect to dashboard on initial mount before settings resolve +- [Phase 33-persistent-memory]: Pre-fetch conversation/settings/memory BEFORE flushHeaders to avoid SSE header race (Pitfall 3 from research) +- [Phase 33-persistent-memory]: puterProxyService.resolveToken wrapped in try/catch — graceful fallback to streamEcho when no puter token configured +- [Phase 33-persistent-memory]: buildHandoffSummary exported as named pure function for direct unit testing without route test harness ### Pending Todos @@ -105,6 +109,6 @@ None yet. ## Session Continuity -Last session: 2026-04-03T22:02:26.059Z -Stopped at: Completed 33-persistent-memory/33-02 +Last session: 2026-04-03T22:14:47.420Z +Stopped at: Completed 33-persistent-memory/33-03 Resume file: None diff --git a/.planning/phases/33-persistent-memory/33-03-SUMMARY.md b/.planning/phases/33-persistent-memory/33-03-SUMMARY.md new file mode 100644 index 00000000..82370a90 --- /dev/null +++ b/.planning/phases/33-persistent-memory/33-03-SUMMARY.md @@ -0,0 +1,164 @@ +--- +phase: 33-persistent-memory +plan: 03 +subsystem: server/routes + ui/pages +tags: [ai-streaming, memory-injection, sse, handoff, react, express] + +requires: + - phase: 33-persistent-memory/01 + provides: assistantMemoryService (get/append/clear) + - phase: 33-persistent-memory/02 + provides: PersonalAssistant page, chatApi, useNexusMode + - phase: 31-puter-js-zero-config-cloud + provides: puterProxyService.chatStream, nexusSettingsService + +provides: + - Real AI streaming via puterProxyService with echo fallback (no puter token) + - Memory facts injected as system message prefix in AI calls + - Facts appended to memory after each assistant turn + - SSE format fixed to {type:"token"}, {type:"done"}, {type:"error"} + - POST /conversations/:id/assistant-handoff route + - chatApi.assistantHandoff UI method + - Wired "Turn into project" button in PersonalAssistant + +affects: + - server/src/routes/chat.ts + - server/src/routes/assistant-handoff.ts + - server/src/app.ts + - ui/src/api/chat.ts + - ui/src/pages/PersonalAssistant.tsx + +tech-stack: + added: [] + patterns: + - Pre-fetch conversation/settings/memory BEFORE flushHeaders (avoids SSE header race) + - puterProxyService try/catch for graceful echo fallback + - buildHandoffSummary pure function (exported + unit tested separately) + - Non-blocking memory append via .catch(() => {}) + +key-files: + created: + - server/src/routes/assistant-handoff.ts + - server/src/__tests__/33-assistant-handoff.test.ts + modified: + - server/src/routes/chat.ts + - server/src/app.ts + - ui/src/api/chat.ts + - ui/src/pages/PersonalAssistant.tsx + +key-decisions: + - "Pre-fetch conversation + settings + memory BEFORE res.flushHeaders() to avoid race condition (Pitfall 3 from research)" + - "puterProxyService.resolveToken wrapped in try/catch — graceful fallback to streamEcho when no puter token configured" + - "buildHandoffSummary exported as named function for direct unit testing without route test harness" + - "Personal Assistant handoff navigates to /dashboard after success — PM conversation will appear in conversation list" + - "Memory injection skipped for project_builder mode via isAssistant flag from nexus settings" + +metrics: + duration: 20 + completed_date: "2026-04-01" + tasks_completed: 2 + files_changed: 6 +--- + +# Phase 33 Plan 03: AI Streaming + Memory Injection + Handoff Summary + +**Real AI streaming via puterProxyService with memory-injected system prompt, SSE format fix, and assistant-to-PM handoff route with wired UI button.** + +## Performance + +- **Duration:** ~20 min +- **Completed:** 2026-04-01 +- **Tasks:** 2 +- **Files modified:** 6 + +## Accomplishments + +### Task 1: Replace streamEcho with real AI streaming + memory injection + +- `server/src/routes/chat.ts` updated with: + - Imports for `assistantMemoryService`, `nexusSettingsService`, `puterProxyService` + - Pre-flushHeaders block: resolves conversation, nexus settings, memory facts + - `puterProxyService(db).resolveToken()` try/catch for echo fallback + - Builds `messagesWithMemory` array: system message with memory facts (capped 2000 chars) + conversation history + new user message + - Uses `puterProxyService.chatStream` when token available, falls back to `streamEcho` + - **SSE format fixed**: `{type:"token", token}`, `{type:"done", messageId, content}`, `{type:"error", error}` — matches client parser + - Non-blocking memory fact append after each assistant turn + - Memory injection skipped when mode is `project_builder` + +### Task 2: Assistant handoff route and wired UI button (TDD) + +- RED: `server/src/__tests__/33-assistant-handoff.test.ts` — 7 tests written before implementation (all failing) +- GREEN: `server/src/routes/assistant-handoff.ts` created: + - `buildHandoffSummary()` pure function: filters user-role messages, concatenates, caps at 1500 chars + - `assistantHandoffRoutes(db)`: `POST /conversations/:id/assistant-handoff` with assertBoard auth + - Creates new conversation, inserts `handoff_context` system message with user summary + - Returns `{ targetConversationId }` +- `server/src/app.ts`: `assistantHandoffRoutes(db)` mounted via `api.use()` +- `ui/src/api/chat.ts`: `assistantHandoff(conversationId)` method added +- `ui/src/pages/PersonalAssistant.tsx`: "Turn into project" button fully wired + - `handleHandoff` callback using `chatApi.assistantHandoff` + - Success toast + navigate to `/dashboard` + - Error toast on failure + - Loading spinner during handoff + - Button disabled when no conversation selected or handing off + +## Task Commits + +1. **Task 1: Real AI streaming + memory injection** — `d9a00d25` +2. **Task 2 (RED): Failing tests for handoff route** — `b5028a5d` +3. **Task 2 (GREEN): Handoff route + app wiring + UI button** — `17564d9c` + +## Files Created/Modified + +- `server/src/routes/chat.ts` — Updated stream endpoint with real AI, memory injection, SSE format fix +- `server/src/routes/assistant-handoff.ts` — New handoff route with buildHandoffSummary +- `server/src/app.ts` — Added assistantHandoffRoutes mount +- `server/src/__tests__/33-assistant-handoff.test.ts` — 7 unit tests (4 for buildHandoffSummary, 3 for route handler) +- `ui/src/api/chat.ts` — Added assistantHandoff method +- `ui/src/pages/PersonalAssistant.tsx` — Wired "Turn into project" button with handoff flow + +## Deviations from Plan + +### Auto-fixed Issues + +**1. [Rule 3 - Blocking] Prerequisite files missing from worktree** + +- **Found during:** Task 1 setup +- **Issue:** Worktree `worktree-agent-acd379e3` is based on an older commit (4c8cfcd8) that predates phase-21 chat system, phase-30 nexus settings, and phase-33 memory services. Files referenced by this plan did not exist. +- **Fix:** Used `git checkout gsd/phase-33-persistent-memory -- ...` to bring 33-01/02 files, and `git checkout gsd/phase-31-puter-js-zero-config-cloud -- ...` for puter-proxy and nexus-settings. Also checked out `pushService.ts` from PAP-878 branch. +- **Files:** 18 prerequisite files checked out in Task 1 commit +- **Commit:** d9a00d25 + +**2. [Rule 3 - Blocking] Tooltip component removed from PersonalAssistant imports** + +- **Found during:** Task 2 (wiring UI button) +- **Issue:** The plan called for removing the disabled state from the button. The previous `Tooltip` wrapper was removed since the button is now fully functional (no need for "Coming soon" tooltip). +- **Fix:** Removed unused `Tooltip`, `TooltipTrigger`, `TooltipContent` imports; simplified button to direct `onClick` handler. +- **Files:** `ui/src/pages/PersonalAssistant.tsx` +- **Commit:** 17564d9c + +## Known Stubs + +None — all data paths are fully wired. The `puterProxyService` fallback to `streamEcho` is intentional behavior (not a stub) for users without a configured puter token. + +## Test Results + +- **24 tests pass** across 3 test files: + - `33-memory-sanitization.test.ts`: 10 tests + - `33-assistant-memory.test.ts`: 7 tests + - `33-assistant-handoff.test.ts`: 7 tests (4 buildHandoffSummary + 3 route integration) + +## Self-Check: PASSED + +Files exist: +- FOUND: /opt/nexus/.claude/worktrees/agent-acd379e3/server/src/routes/chat.ts +- FOUND: /opt/nexus/.claude/worktrees/agent-acd379e3/server/src/routes/assistant-handoff.ts +- FOUND: /opt/nexus/.claude/worktrees/agent-acd379e3/server/src/app.ts +- FOUND: /opt/nexus/.claude/worktrees/agent-acd379e3/server/src/__tests__/33-assistant-handoff.test.ts +- FOUND: /opt/nexus/.claude/worktrees/agent-acd379e3/ui/src/api/chat.ts +- FOUND: /opt/nexus/.claude/worktrees/agent-acd379e3/ui/src/pages/PersonalAssistant.tsx + +Commits: +- FOUND: d9a00d25 +- FOUND: b5028a5d +- FOUND: 17564d9c