Move completed plan docs to docs/plans/archive/. Add survey migration 046 and reference HTML/plan files. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
210 lines
6.6 KiB
Markdown
210 lines
6.6 KiB
Markdown
# AI Auto-Fix & Gemini Flash Provider Design
|
|
|
|
> **Date:** 2026-02-26
|
|
> **Status:** Approved
|
|
|
|
---
|
|
|
|
## Overview
|
|
|
|
Two combined features:
|
|
|
|
1. **AI Provider Abstraction** — Add Gemini 2.5 Flash as the default AI provider with Claude as fallback, behind a unified interface.
|
|
2. **AI Auto-Fix for Validation Errors** — When a flow fails validation, offer an AI-powered "Fix with AI" button that generates structural fixes for review.
|
|
|
|
---
|
|
|
|
## Section 1: AI Provider Abstraction
|
|
|
|
### Design
|
|
|
|
New `backend/app/core/ai_provider.py` with a unified interface:
|
|
|
|
```python
|
|
class AIProvider(ABC):
|
|
async def generate_json(
|
|
self,
|
|
system_prompt: str,
|
|
messages: list[dict],
|
|
max_tokens: int = 4096,
|
|
) -> tuple[str, int, int]:
|
|
"""Returns (text, input_tokens, output_tokens)"""
|
|
```
|
|
|
|
Two implementations:
|
|
|
|
| Provider | Model | SDK | Role |
|
|
|----------|-------|-----|------|
|
|
| `GeminiProvider` | `gemini-2.5-flash` | `google-genai` | Default |
|
|
| `AnthropicProvider` | `claude-haiku-4-5-20251001` | `anthropic` | Fallback |
|
|
|
|
### Provider Selection
|
|
|
|
- `get_ai_provider()` factory reads `AI_PROVIDER` env var (default: `"gemini"`)
|
|
- Falls back to Anthropic if Gemini key is missing
|
|
- Existing `ai_tree_generator_service.py` swaps direct Anthropic calls for `get_ai_provider()`
|
|
|
|
### New Environment Variables
|
|
|
|
| Variable | Default | Purpose |
|
|
|----------|---------|---------|
|
|
| `AI_PROVIDER` | `"gemini"` | Which provider to use (`gemini` or `anthropic`) |
|
|
| `GOOGLE_AI_API_KEY` | — | Gemini API key |
|
|
|
|
Existing `ANTHROPIC_API_KEY` remains for fallback.
|
|
|
|
### Config Changes (`core/config.py`)
|
|
|
|
```python
|
|
AI_PROVIDER: str = "gemini"
|
|
GOOGLE_AI_API_KEY: str | None = None
|
|
AI_MODEL_GEMINI: str = "gemini-2.5-flash"
|
|
AI_MODEL_ANTHROPIC: str = "claude-haiku-4-5-20251001"
|
|
```
|
|
|
|
---
|
|
|
|
## Section 2: AI Auto-Fix Feature
|
|
|
|
### Backend Endpoint
|
|
|
|
**`POST /api/v1/ai/fix-tree`**
|
|
|
|
Request:
|
|
```json
|
|
{
|
|
"tree_structure": { /* full tree */ },
|
|
"tree_name": "Router Troubleshooting",
|
|
"tree_type": "troubleshooting",
|
|
"validation_errors": [
|
|
{
|
|
"node_id": "node_abc",
|
|
"message": "Decision node must have at least 2 children (branches)"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
Response:
|
|
```json
|
|
{
|
|
"fixes": [
|
|
{
|
|
"target_node_id": "node_abc",
|
|
"error_message": "Decision node must have at least 2 children (branches)",
|
|
"description": "Added second branch 'Check firmware version' with solution node",
|
|
"original_node": { /* snapshot before fix */ },
|
|
"fixed_node": { /* replacement node with corrected subtree */ }
|
|
}
|
|
],
|
|
"tokens_used": { "input": 1200, "output": 800 }
|
|
}
|
|
```
|
|
|
|
### How It Works
|
|
|
|
1. For each validation error tied to a `node_id`, extract that node + its parent + siblings from the tree.
|
|
2. Build a prompt with:
|
|
- The **full tree structure** serialized as a simplified outline (node titles + types + structure) for context
|
|
- The **specific failing node** highlighted with full JSON detail
|
|
- The **validation error message**
|
|
- Instructions: "Fix ONLY this node's structural issue. Keep all existing content. Generate domain-relevant additions that fit the flow's topic."
|
|
3. AI returns a corrected version of that node (with children/options adjusted).
|
|
4. Backend re-validates the fixed node before returning it.
|
|
5. If re-validation fails, retry once with the error fed back (corrective prompt pattern).
|
|
|
|
### Prompt Strategy
|
|
|
|
The prompt gives the AI the full tree as a compact outline, then zooms into the failing node:
|
|
|
|
```
|
|
You are fixing a validation error in a troubleshooting flow called "Router Troubleshooting".
|
|
|
|
FULL FLOW OUTLINE:
|
|
- [decision] Is the router powered on?
|
|
- [action] Check power cable → [solution] Power restored
|
|
- [decision] Are lights blinking? ← ERROR HERE
|
|
- [solution] Contact ISP
|
|
|
|
ERROR: Decision node "Are lights blinking?" must have at least 2 children (branches).
|
|
|
|
FAILING NODE (full detail):
|
|
{...json...}
|
|
|
|
Fix this node by adding the minimum structure needed to resolve the error.
|
|
Return ONLY the fixed node as JSON.
|
|
```
|
|
|
|
### Frontend UX
|
|
|
|
1. **Trigger**: "Fix with AI" button in `ValidationSummary` — appears when there are fixable errors (structural errors with a `node_id`).
|
|
2. **Loading state**: Button shows spinner + "Generating fixes..." — disabled during request.
|
|
3. **Review modal** (`AIFixReviewModal`): Shows each proposed fix as a card:
|
|
- Error message at top
|
|
- Before/after view of the node change
|
|
- "Apply" / "Skip" buttons per fix
|
|
- "Apply All" button in footer
|
|
4. **Apply**: Each accepted fix calls `updateNode(targetNodeId, fixedNode)` in the tree editor store.
|
|
5. **Re-validate**: After applying fixes, auto-run `validate()` to confirm resolution.
|
|
|
|
---
|
|
|
|
## Section 3: Scope & Constraints
|
|
|
|
### Fixable Errors (Auto-Fix Scope)
|
|
|
|
Only structural validation errors with a `node_id`:
|
|
- Decision node missing children/branches
|
|
- Decision node missing options
|
|
- Action node missing `next_node_id`
|
|
- Dead-end decision nodes (no children)
|
|
|
|
### NOT Fixable
|
|
|
|
- Global checks (tree too small/large, not enough solutions) — require rethinking the whole tree
|
|
- Content quality issues — out of scope
|
|
- Errors without a `node_id` (root-level issues)
|
|
|
|
Non-fixable errors still show in ValidationSummary but without the "Fix with AI" option.
|
|
|
|
### Token Budget
|
|
|
|
- Tree outline: ~50-100 tokens for a typical 15-node tree
|
|
- Failing node detail: ~100-200 tokens
|
|
- System prompt + instructions: ~300 tokens
|
|
- **Total input per fix: ~500-600 tokens**
|
|
- One API call per failing node (not batched)
|
|
|
|
### Error Handling
|
|
|
|
- Provider failure (rate limit, network): toast error, user can retry
|
|
- Fix fails re-validation: "AI couldn't generate a valid fix" with retry option
|
|
- Max 1 retry with corrective prompt per attempt
|
|
- Both provider and fallback fail: surface error to user
|
|
|
|
### Auth
|
|
|
|
- Requires `engineer` role or above (`require_engineer_or_admin`)
|
|
|
|
---
|
|
|
|
## New Files
|
|
|
|
| File | Purpose |
|
|
|------|---------|
|
|
| `backend/app/core/ai_provider.py` | Provider abstraction + Gemini/Anthropic implementations |
|
|
| `backend/app/core/ai_fix_service.py` | Fix generation logic + prompt building |
|
|
| `backend/app/api/endpoints/ai.py` | `POST /ai/fix-tree` endpoint |
|
|
| `backend/app/schemas/ai.py` | Request/response schemas for AI endpoints |
|
|
| `frontend/src/components/tree-editor/AIFixReviewModal.tsx` | Review modal for proposed fixes |
|
|
|
|
## Modified Files
|
|
|
|
| File | Change |
|
|
|------|--------|
|
|
| `backend/app/core/config.py` | Add Gemini config vars |
|
|
| `backend/app/core/ai_tree_generator_service.py` | Swap Anthropic calls for provider abstraction |
|
|
| `backend/app/api/router.py` | Register `/ai` routes |
|
|
| `frontend/src/api/trees.ts` | Add `fixTree()` API call |
|
|
| `frontend/src/components/tree-editor/ValidationSummary.tsx` | Add "Fix with AI" button |
|