Design for two combined features: Gemini 2.5 Flash as primary AI provider with Claude fallback, and AI-powered auto-fix for validation errors in the tree editor. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.6 KiB
6.6 KiB
AI Auto-Fix & Gemini Flash Provider Design
Date: 2026-02-26 Status: Approved
Overview
Two combined features:
- AI Provider Abstraction — Add Gemini 2.5 Flash as the default AI provider with Claude as fallback, behind a unified interface.
- 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:
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 readsAI_PROVIDERenv var (default:"gemini")- Falls back to Anthropic if Gemini key is missing
- Existing
ai_tree_generator_service.pyswaps direct Anthropic calls forget_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)
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:
{
"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:
{
"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
- For each validation error tied to a
node_id, extract that node + its parent + siblings from the tree. - 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."
- AI returns a corrected version of that node (with children/options adjusted).
- Backend re-validates the fixed node before returning it.
- 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
- Trigger: "Fix with AI" button in
ValidationSummary— appears when there are fixable errors (structural errors with anode_id). - Loading state: Button shows spinner + "Generating fixes..." — disabled during request.
- 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
- Apply: Each accepted fix calls
updateNode(targetNodeId, fixedNode)in the tree editor store. - 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
engineerrole 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 |