# 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 `<ContextMenu>` 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.
