# 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)
