diff --git a/docs/plans/2026-03-06-editor-embedded-flow-assist-design.md b/docs/plans/2026-03-06-editor-embedded-flow-assist-design.md new file mode 100644 index 00000000..94425c50 --- /dev/null +++ b/docs/plans/2026-03-06-editor-embedded-flow-assist-design.md @@ -0,0 +1,361 @@ +# Editor-Embedded Flow Assist - Design Document + +> **Date:** 2026-03-06 +> **Status:** Approved +> **Replaces:** Standalone AI Chat Builder (`/ai/chat`) + +--- + +## Overview + +Replace the standalone `/ai/chat` page with a context-aware AI side panel embedded directly in each editor (Troubleshooting + Procedural). The panel knows which node/step is focused, supports targeted and open-ended actions, and applies changes via a tiered suggestion system. Knowledge integration and variable inference are phased features built on the same panel architecture. + +**Key Principles:** +- Context-aware: panel knows the full tree/step structure + focal node +- Targeted actions auto-apply; open-ended suggestions require acceptance +- Output-based thresholds determine suggestion UX +- Model routing is config-driven, not hardcoded +- Chat history persists per-flow, per-user + +--- + +## Panel Layout & Behavior + +### Dimensions & Styling +- **Width:** 320px fixed, right side +- **Styling:** Glassmorphism (`.glass-card-static` bg, backdrop blur, `border-l border-border`) +- **Z-index:** Same layer as node editor panel (not overlay) + +### Single-Panel Rule +- **Tree editor:** AI panel occupies the right panel slot, closing the node editor panel. When AI panel closes, if a node was previously being edited, the node editor panel reopens for that node. +- **Procedural editor:** AI panel slides in from right, narrowing the step list (step list takes `flex-1`). No existing panel to replace. + +### Top Section: Context Summary +- **Node/step selected:** Read-only summary showing type, title, question/description of the focused item. +- **No selection:** Flow summary showing name, node/step count, flow type. +- Switching selection updates the summary live. + +### Tabs +- **Chat** — conversation + inline suggestions +- **Suggestions** — audit trail of all AI-applied changes to this flow (accepted, dismissed, pending) + +### Visibility +- Hidden by default +- Auto-opens on: AI-assisted flow creation, right-click AI action, toolbar toggle +- Auto-contextual: opens with focal node already set when triggered via context menu + +--- + +## Entry Points + +### 1. Create Flow Dropdown (AI-Assisted) +- "Blank" or "AI-assisted" option per flow type (Troubleshooting, Project, Maintenance) +- **AI-assisted** shows a simple prompt dialog modal: + - Text area: "Describe the flow you want to build" + - Flow type already known from dropdown selection + - Loading state during generation + - On failure: error message + retry button (stays in dialog) + - On success: creates tree via API, navigates to editor with AI panel auto-opened and generation chat history loaded +- No multi-phase interview, no preview — just prompt and go + +### 2. Right-Click Context Menu +- New `` component (no existing context menus in either editor) +- Positioned absolutely at right-click point +- Closes on click-away, Escape, or action selection +- **Tree editor items:** Generate branch, Add decision/action/solution, Explain node, Find known fixes, Delete +- **Procedural editor items:** Generate steps after, Add verification step, Expand step, Generate section, Delete +- Selecting an AI action sets the focal node/step and opens the AI panel + +### 3. Toolbar Toggle +- "AI Assist" button in editor toolbar to manually open/close the panel + +### 4. Existing Flows +- AI panel works on any flow — new or existing, AI-created or manually built +- No restriction to AI-created flows + +--- + +## Suggestion & Apply System + +### Ghost Node/Step Mechanics + +Ghost nodes/steps are added to `treeStructure`/steps array with a `_suggestion: true` flag: +- Canvas/step list renders them normally (auto-layout works) but with **dashed borders + reduced opacity** +- Zundo temporal store **paused** while suggestions are pending +- On **accept**: remove `_suggestion` flag, unpause zundo (creates one clean undo point) +- On **dismiss**: remove ghost nodes from structure, unpause zundo (no undo point created) +- Ghost nodes participate in auto-layout and connection drawing but are visually distinct + +### Addition vs Modification + +| Change Type | Visual Treatment | +|---|---| +| **New nodes/steps** | Ghost nodes: dashed borders, reduced opacity | +| **Modified existing nodes** | Subtle highlight + badge showing what changed | +| **Modified selected node** | Before/after shown in chat message with Apply button (not inline ghost) | + +### Output-Based Threshold + +| Output Size | Behavior | +|---|---| +| **1 node/step** | Auto-apply + toast notification with undo link | +| **2-4 nodes/steps** | Individual ghost suggestions + "Accept All" shortcut button | +| **5+ nodes/steps** | Ghost suggestions grouped by branch (tree) or section (procedural) with "Accept Branch"/"Accept Section" and "Accept All" controls + summary card in panel | + +All changes (accepted or dismissed) logged in the Suggestions tab as an audit trail. + +--- + +## Backend Action Types + +Each message to the AI includes an `action_type` that determines prompt construction, response schema, and model routing: + +| Action Type | Description | Model Tier | Response Format | +|---|---|---|---| +| `generate_full` | Initial skeleton from prompt dialog | standard | Full tree structure or step array | +| `generate_branch` | Generate children for a specific node | standard | Subtree delta (node + children) | +| `modify_node` | Update a specific node's content | fast | Single node delta (before/after) | +| `add_steps` | Add steps after a specific step | standard | Step array delta | +| `quick_action` | Single-node operations (explain, expand) | fast | Single node delta or text response | +| `open_chat` | General conversation about the flow | standard | Text + optional delta | +| `variable_inference` | Detect implicit variables in step content | fast | Variable suggestions | + +### Prompt Construction + +Each action type gets a tailored system prompt: +- **Full tree context** always included (so AI understands the complete flow) +- **Focal node** highlighted when present (the specific node/step being acted on) +- **Action instruction** describes what the AI should return +- **Response schema** constrains output format (full tree, subtree delta, single node, text) + +### Delta Response Format + +For partial updates, the AI returns a delta object: +```json +{ + "action": "add" | "modify" | "delete", + "target_node_id": "node-to-modify-or-insert-after", + "nodes": [{ /* node objects */ }], + "explanation": "What was changed and why" +} +``` + +The frontend applies the delta to the tree structure and renders ghost nodes as appropriate. + +--- + +## Model Routing (Config-Driven) + +### Configuration + +```python +# backend/app/core/config.py +AI_MODEL_TIERS = { + "fast": "claude-haiku-4-5-20251001", + "standard": "claude-sonnet-4-6-20250514", +} + +ACTION_MODEL_MAP = { + "generate_full": "standard", + "generate_branch": "standard", + "modify_node": "fast", + "add_steps": "standard", + "quick_action": "fast", + "open_chat": "standard", + "variable_inference": "fast", +} +``` + +### Routing Logic + +1. Message endpoint receives `action_type` parameter +2. Look up tier from `ACTION_MODEL_MAP` +3. Resolve model name from `AI_MODEL_TIERS` +4. Pass to Anthropic API call + +Both tiers can map to the same model initially. Changing model assignment is a config change, not a code change. + +--- + +## Knowledge Integration (Phased) + +### Phase 1 (Initial Release) +- Uses existing Microsoft Learn MCP server +- AI can cite KB articles, known issues, and official fix procedures in chat responses +- Citations rendered inline as collapsible cards with source URL and title +- AI response marker: `[KNOWLEDGE]{"title": "...", "url": "...", "excerpt": "..."}[/KNOWLEDGE]` + +### Phase 2 (Future) +- Additional vendor documentation sources +- Community knowledge bases +- Proactive suggestions ("Microsoft released KB5034441 addressing this scenario") + +--- + +## Chat Persistence + +### Session Model +- `ai_chat_session` model extended with: + - `tree_id` FK (which flow this session belongs to) + - `archived_at` timestamp (null = active) +- Per-flow, per-user sessions: multiple engineers on the same flow get separate chat histories +- Session loads on panel open if one exists for this flow + user + +### Suggestions Audit Trail +New `ai_suggestion` table: + +| Column | Type | Description | +|---|---|---| +| `id` | UUID | Primary key | +| `tree_id` | UUID FK | Which flow | +| `user_id` | UUID FK | Who triggered | +| `session_id` | UUID FK | Which chat session | +| `action_type` | String | Action that generated this suggestion | +| `target_node_id` | String | Node/step acted on (nullable) | +| `changes_json` | JSONB | Before/after snapshot | +| `status` | Enum | `pending`, `accepted`, `dismissed` | +| `created_at` | DateTime(tz) | When suggested | +| `resolved_at` | DateTime(tz) | When accepted/dismissed (nullable) | + +### Auto-Archive +- APScheduler task runs daily +- Archives sessions with no activity for 30 days (`archived_at = now()`) +- Archived sessions viewable in Suggestions tab but not resumable for chat + +--- + +## Troubleshooting Editor Integration + +### Panel Context +- Full tree structure included in AI context +- Focal node (when selected/right-clicked) highlighted in context +- Node summary at panel top shows: type icon, node ID, question/title, option count + +### Context Menu Actions +| Action | Description | Model Tier | +|---|---|---| +| Generate branch | Create child nodes from this decision | standard | +| Add decision node | Add a decision child | fast | +| Add action node | Add an action child | fast | +| Add solution node | Add a solution child | fast | +| Explain node | AI explains what this node does | fast | +| Find known fixes | Search knowledge sources for this scenario | standard | + +### Ghost Node Rendering +- Dashed `border-dashed border-primary/40` borders +- `opacity-60` on the node card +- Connection lines drawn with dashed stroke +- Accept/dismiss buttons overlaid on each ghost node +- "Accept All" button in the panel when 2+ ghost nodes + +--- + +## Procedural Editor Integration + +### Panel Context +- Full step list included in AI context +- Focal step (when selected/right-clicked) highlighted in context +- Step summary at panel top shows: step number, type badge, title, content type + +### Context Menu Actions +| Action | Description | Model Tier | +|---|---|---| +| Generate steps after | Add steps following this one | standard | +| Add verification step | Insert a verification step | fast | +| Expand step | Break this step into substeps | standard | +| Generate section | Create a section header + steps | standard | + +### Ghost Step Rendering +- Dashed left border (`border-l-2 border-dashed border-primary/40`) +- `opacity-60` background +- Accept/dismiss buttons on each ghost step +- Grouped by section when 5+ suggestions + +### Intake Variable Detection (Three Tiers) + +| Tier | Trigger | Timing | Model Tier | +|---|---|---|---| +| **Explicit** | `[VAR:name]` syntax in step content | Immediate on content save | None (regex match) | +| **Inference** | Natural language suggests variable ("check the customer's server") | Debounced on step save/blur | fast | +| **Cross-step** | Same implicit variable in 2+ steps | On panel open + when steps modified | fast | + +**Behavior:** +- Explicit: immediate inline suggestion card in panel ("Add `server_name` to intake form?") +- Inference: non-blocking suggestion in panel, lower confidence indicator +- Cross-step: promoted suggestion with gap flag ("Variable `server_name` used in steps 3, 7, 12 but not captured in intake form") +- Results cached per-session until step content changes + +--- + +## What Gets Removed + +| Item | Location | +|---|---| +| `AIChatBuilderPage.tsx` | `frontend/src/pages/` | +| `aiChatStore.ts` | `frontend/src/store/` | +| `ai-chat/` component directory | `frontend/src/components/` | +| `AIFlowBuilderModal` | `frontend/src/components/` | +| `/ai/chat` route | `frontend/src/router.tsx` | +| Flow type selection routing | URL params `?type=...` | + +--- + +## What Gets Repurposed + +| Item | Changes | +|---|---| +| `ai_chat_service.py` | Action-type dispatch, partial generation prompts, model routing, focal node context | +| `ai_tree_validator.py` | Validates AI-generated fragments (subtree, step batch) in addition to full trees | +| `ai_chat_session` model | Extended with `tree_id` FK, `archived_at` timestamp | +| AI chat endpoints | Tree-scoped sessions, `action_type` parameter, model tier routing | + +--- + +## What Gets Built (New) + +| Item | Description | +|---|---| +| `EditorAIPanel` component | Shared panel with Chat + Suggestions tabs, node summary, input | +| `ContextMenu` component | Shared right-click menu for nodes and steps | +| `useEditorAI` hook | Panel state, focal node, suggestion management, ghost node lifecycle | +| Prompt dialog modal | Simple "describe your flow" modal for AI-assisted create | +| `ai_suggestion` DB model | Audit trail table + Alembic migration | +| Ghost node CSS | Dashed borders, reduced opacity, accept/dismiss overlays | +| Model tier config | `AI_MODEL_TIERS` + `ACTION_MODEL_MAP` in `config.py` | +| APScheduler archive task | Daily job to archive stale sessions | + +--- + +## What Gets Modified + +| Item | Changes | +|---|---| +| `TreeEditorPage` | Right panel slot for AI, context menu handler, ghost node support | +| `TreeCanvas` / `TreeCanvasNode` | Ghost node rendering (dashed borders, overlays) | +| `ProceduralEditorPage` | Flex layout for AI panel, context menu on steps | +| `StepList` / `StepEditor` | Ghost step rendering | +| `treeEditorStore` | Ghost node state slice, zundo pause/resume, orphan bug fix | +| `proceduralEditorStore` | Ghost step state slice | +| `ai_chat_service.py` | Action-type dispatch, delta response format, model routing | +| `ai_chat_session` model | `tree_id` FK, `archived_at` | +| `config.py` | Model tier configuration | +| `CreateFlowDropdown` | AI-assisted option + prompt dialog trigger | +| `router.tsx` | Remove `/ai/chat` route | + +--- + +## Bug Fix (Included) + +**File:** `frontend/src/store/treeEditorStore.ts` line 858 + +**Current code:** +```typescript +if (id !== 'root' && !referencedIds.has(id)) { +``` + +**Fixed code:** +```typescript +if (id !== state.treeStructure?.id && !referencedIds.has(id)) { +``` + +**Root cause:** Orphan check hardcodes `'root'` as the expected root node ID. AI-generated trees use descriptive IDs (e.g., `"verify-account-exists"`). Since the root is never referenced by any other node's `next_node_id`, it gets flagged as orphaned. This is a false positive.