CascadingDev/olddocs/ai-provider-fallback.puml

164 lines
4.1 KiB
Plaintext

@startuml ai-provider-fallback
!theme plain
title AI Provider Fallback Chain with Model Hints
start
:Automation needs AI generation\n(from patcher.py or runner.py);
:Read config/ai.yml;
if (Rule has model_hint?) then (yes)
if (model_hint == "fast"?) then (yes)
:Use **command_chain_fast**:
- claude -p (→ Haiku subagent)
- codex --model gpt-5-mini
- gemini --model gemini-2.5-flash;
else if (model_hint == "quality"?) then (yes)
:Use **command_chain_quality**:
- claude -p (→ Sonnet subagent)
- codex --model o3
- gemini --model gemini-2.5-pro;
else (unknown hint)
:Fall back to default chain;
endif
else (no hint)
:Use **command_chain** (default):
- claude -p (→ auto-select subagent)
- codex --model gpt-5
- gemini --model gemini-2.5-flash;
endif
partition "Provider Loop" {
:Get next provider from chain;
if (Provider == "claude"?) then (yes)
:Execute: **claude -p**;
note right
Claude CLI uses TASK COMPLEXITY hint
from prompt to select subagent:
- FAST → cdev-patch (Haiku)
- QUALITY → cdev-patch-quality (Sonnet)
- Default → auto-select
end note
if (Returned output?) then (yes)
if (Contains diff markers?) then (yes)
:✓ Success! Extract diff;
stop
else (no - non-diff response)
:Log: "Claude non-diff output";
:Try next provider;
endif
else (command failed)
:Log: "Claude command failed";
:Try next provider;
endif
else if (Provider == "codex"?) then (yes)
:Execute: **codex exec --model X --json -**;
note right
Codex requires special handling:
- Add "exec" subcommand
- Add "--json" flag
- Add "--color=never"
- Add "-" to read from stdin
- Parse JSON output for agent_message
end note
if (Exit code == 0?) then (yes)
:Parse JSON lines;
:Extract agent_message text;
if (Contains diff?) then (yes)
:✓ Success! Extract diff;
stop
else (no diff)
:Log: "Codex no diff output";
:Try next provider;
endif
else (exit code 1)
:Log: "Codex exited with 1";
:Try next provider;
endif
else if (Provider == "gemini"?) then (yes)
:Execute: **gemini --model X**;
note right
Gemini is the most reliable fallback:
- Accepts plain text input
- Returns consistent output
- Supports sentinel token
end note
if (Returned output?) then (yes)
if (Output == sentinel token?) then (yes)
:Log: "No changes needed";
:Return empty (intentional);
stop
else if (Contains diff?) then (yes)
:✓ Success! Extract diff;
stop
else (no diff)
:Log: "Gemini no diff output";
:Try next provider;
endif
else (command failed)
:Log: "Gemini command failed";
:Try next provider;
endif
endif
if (More providers in chain?) then (yes)
:Continue loop;
else (no)
:✗ All providers failed;
:Raise PatchGenerationError;
stop
endif
}
stop
legend bottom
**Configuration Example (config/ai.yml):**
runner:
command_chain:
- "claude -p"
- "codex --model gpt-5"
- "gemini --model gemini-2.5-flash"
command_chain_fast:
- "claude -p"
- "codex --model gpt-5-mini"
- "gemini --model gemini-2.5-flash"
command_chain_quality:
- "claude -p"
- "codex --model o3"
- "gemini --model gemini-2.5-pro"
sentinel: "CASCADINGDEV_NO_CHANGES"
**Environment Override:**
export CDEV_AI_COMMAND="claude -p || gemini --model gemini-2.5-pro"
(Overrides config.yml for this commit only)
endlegend
note right
**Why Fallback Chain?**
1. **Redundancy**: Rate limits, API outages
2. **Model specialization**: Different models excel at different tasks
3. **Cost optimization**: Try cheaper models first
4. **Quality assurance**: Fast models for simple tasks, quality for complex
**Observed Behavior:**
- Claude occasionally returns non-diff output
- Codex consistently exits with code 1 (auth issues?)
- Gemini is the most reliable fallback
end note
@enduml