# Task Lane Minimize/Reopen + Resolve Documentation Streaming **Date:** 2026-03-28 **Status:** Approved --- ## Problem Two UX issues in the Assistant Chat page: 1. **Task Lane close destroys state.** The X button calls `clearTaskState()` and hides the panel. There's no way to bring it back without getting a new AI response with markers. Engineers lose in-progress task responses. 2. **Conclude → Resolved hangs.** The resolve flow blocks on an LLM call to generate documentation. The modal shows "Generating..." for 2-5s+ with no progressive feedback. The generated output needs to be structured ticket notes engineers can copy into their PSA. --- ## Feature 1: Task Lane Minimize/Reopen ### Close Button Change - Replace the X icon (`X` from Lucide) with `PanelRightClose` to signal "collapse" not "destroy." - On click: set `showTaskLane = false`. Do NOT call `clearTaskState(sessionId)`. - Task state (questions, actions, user responses) remains in sessionStorage and backend `pending_task_lane`. ### Reopen Pill on Input Toolbar - New pill button in the chat input toolbar row, alongside Attach / Paste Logs / Conclude. - **Visibility condition:** `(activeQuestions.length > 0 || activeActions.length > 0) && !showTaskLane` - **Label:** `Tasks (N)` where N = `activeQuestions.length + activeActions.length` - **Icon:** `ListChecks` from Lucide - **Action:** `setShowTaskLane(true)` - **Style:** Same ghost button style as Attach/Paste Logs — muted text, hover highlight. ### Files Changed | File | Change | |------|--------| | `frontend/src/components/assistant/TaskLane.tsx` | Replace `X` icon with `PanelRightClose` in header | | `frontend/src/pages/AssistantChatPage.tsx` | Remove `clearTaskState()` from onClose handler; add Tasks pill to input toolbar | --- ## Feature 2: Resolve with Streaming Documentation ### Two-Phase Resolve Flow **Phase 1 — Instant resolve:** 1. User clicks Resolve in `ConcludeSessionModal`, enters optional notes, confirms. 2. Frontend calls `POST /ai-sessions/{id}/resolve` with `{ resolution_summary }`. 3. Backend sets session status to `resolved`, saves summary, returns immediately. No LLM call on this path. 4. Modal transitions to the summary step instantly, showing a skeleton loading state for "Ticket Notes." **Phase 2 — Streamed doc generation:** 1. Immediately after phase 1, frontend opens an SSE connection to `GET /ai-sessions/{id}/documentation/stream`. 2. Backend streams the structured ticket notes as they generate, token by token. 3. Frontend renders chunks progressively into the summary step using `MarkdownContent`. 4. When stream completes, show a "Copy to Clipboard" button. ### Ticket Notes Format The LLM generates four structured sections: ```markdown ## Problem Summary [What the engineer reported / intake context] ## Steps Taken [Key diagnostic steps and findings from conversation] ## Resolution [What fixed it / final action taken] ## Next Steps [Follow-up items, if any — or "None"] ``` ### Fallback Behavior - If SSE stream fails or times out (30s): fall back to non-streaming `GET /ai-sessions/{id}/documentation`. - If that also fails: show "Documentation unavailable" with a "Copy Conversation" button that formats the raw `conversation_messages` into a basic structured summary (no LLM, pure template). ### Copy to Clipboard - Prominent button below the rendered ticket notes. - Copies the full markdown text. - Toast confirmation: "Ticket notes copied." ### AI Optimizations **1. Streaming (SSE endpoint):** - New endpoint: `GET /ai-sessions/{id}/documentation/stream` - Returns `text/event-stream` via FastAPI `StreamingResponse`. - Uses Anthropic's `client.messages.stream()` for token-level streaming. - Time-to-first-byte drops from ~2-5s to ~200ms. **2. Prompt caching:** - Apply `cache_control: {"type": "ephemeral"}` to the system prompt and conversation context prefix in the documentation generation call. - Pattern already exists in `assistant_chat_service.py` (`_call_anthropic_cached`). - Repeat calls for the same session (regenerate, different doc types) hit cache — up to 85% faster, 90% cheaper on input tokens. **3. Client reuse:** - Singleton `AsyncAnthropic` client instead of creating a new one per call. - Eliminates connection setup overhead. **Model tier:** Haiku (already configured as `quick_action` tier) — fastest model, appropriate for summarization. ### Backend Changes | File | Change | |------|--------| | `backend/app/api/endpoints/ai_sessions.py` | Modify `resolve_session` to only set status + save summary (remove the blocking `get_session_documentation` call); add new SSE streaming endpoint for doc generation | | `backend/app/services/flowpilot_engine.py` | Add `stream_session_documentation()` generator function using `client.messages.stream()` | | `backend/app/core/ai_provider.py` | Add `generate_text_stream()` method returning async iterator; singleton client | | `backend/app/services/flowpilot_engine.py` | Add prompt caching to `_build_status_update_prompt` call path | ### Frontend Changes | File | Change | |------|--------| | `frontend/src/components/assistant/ConcludeSessionModal.tsx` | Two-phase flow: instant resolve → streaming doc render with skeleton → copy button | | `frontend/src/api/aiSessions.ts` | Add `streamDocumentation(sessionId)` using fetch + ReadableStream | | `frontend/src/pages/AssistantChatPage.tsx` | Update `handleConclude` to not await documentation | ### ConcludeSessionModal Summary Step Layout ``` ┌─────────────────────────────────────┐ │ Session Resolved │ │ │ │ ┌─ Ticket Notes ─────────────────┐ │ │ │ ## Problem Summary │ │ │ │ [streaming text...] │ │ │ │ │ │ │ │ ## Steps Taken │ │ │ │ [streaming text...] │ │ │ │ │ │ │ │ ## Resolution │ │ │ │ [streaming text...] │ │ │ │ │ │ │ │ ## Next Steps │ │ │ │ [streaming text...] │ │ │ └────────────────────────────────┘ │ │ │ │ [ Copy to Clipboard ] [ Done ] │ └─────────────────────────────────────┘ ``` --- ## Out of Scope - Client-facing update generation (future feature, different audience prompt) - Direct PSA posting (requires ConnectWise integration to be wired to sessions) - Task lane drag-to-reorder - Task lane persistence across browser tabs (sessionStorage is per-tab by design)