refactor(models): migrate to granular model configuration architecture

Upgrade Claude model configuration from dual-key to quad-key system for
better model tier differentiation.

**Breaking Changes:**
- Replace `ANTHROPIC_SMALL_FAST_MODEL` with three granular keys:
  - `ANTHROPIC_DEFAULT_HAIKU_MODEL`
  - `ANTHROPIC_DEFAULT_SONNET_MODEL`
  - `ANTHROPIC_DEFAULT_OPUS_MODEL`

**Backend (Rust):**
- Add `normalize_claude_models_in_value()` for automatic migration
- Implement fallback chain: `DEFAULT_* || SMALL_FAST || MODEL`
- Auto-cleanup: remove legacy `SMALL_FAST` key after normalization
- Apply normalization across 6 critical paths:
  - Add/update provider
  - Read from live config
  - Write to live config
  - Refresh config snapshot

**Frontend (React):**
- Expand UI from 2 to 4 model input fields
- Implement smart fallback in `useModelState` hook
- Update `useKimiModelSelector` for Kimi model picker
- Add i18n keys for Haiku/Sonnet/Opus labels (zh/en)

**Configuration:**
- Update all 7 provider presets to new format
- DeepSeek/Qwen/Moonshot: use same model for all tiers
- Zhipu: preserve tier differentiation (glm-4.5-air for Haiku)

**Backward Compatibility:**
- Old configs auto-upgrade on first read/write
- Fallback chain ensures graceful degradation
- No manual migration required

Closes #[issue-number]
This commit is contained in:
Jason
2025-11-02 18:02:22 +08:00
parent 2ebe34810c
commit 4811aa2dcd
9 changed files with 336 additions and 91 deletions
@@ -12,9 +12,15 @@ interface KimiModel {
interface KimiModelSelectorProps {
apiKey: string;
anthropicModel: string;
anthropicSmallFastModel: string;
defaultHaikuModel: string;
defaultSonnetModel: string;
defaultOpusModel: string;
onModelChange: (
field: "ANTHROPIC_MODEL" | "ANTHROPIC_SMALL_FAST_MODEL",
field:
| "ANTHROPIC_MODEL"
| "ANTHROPIC_DEFAULT_HAIKU_MODEL"
| "ANTHROPIC_DEFAULT_SONNET_MODEL"
| "ANTHROPIC_DEFAULT_OPUS_MODEL",
value: string,
) => void;
disabled?: boolean;
@@ -23,7 +29,9 @@ interface KimiModelSelectorProps {
const KimiModelSelector: React.FC<KimiModelSelectorProps> = ({
apiKey,
anthropicModel,
anthropicSmallFastModel,
defaultHaikuModel,
defaultSonnetModel,
defaultOpusModel,
onModelChange,
disabled = false,
}) => {
@@ -173,11 +181,19 @@ const KimiModelSelector: React.FC<KimiModelSelectorProps> = ({
onChange={(value) => onModelChange("ANTHROPIC_MODEL", value)}
/>
<ModelSelect
label={t("kimiSelector.fastModel")}
value={anthropicSmallFastModel}
onChange={(value) =>
onModelChange("ANTHROPIC_SMALL_FAST_MODEL", value)
}
label={t("kimiSelector.haikuModel", { defaultValue: "Haiku 默认" })}
value={defaultHaikuModel}
onChange={(value) => onModelChange("ANTHROPIC_DEFAULT_HAIKU_MODEL", value)}
/>
<ModelSelect
label={t("kimiSelector.sonnetModel", { defaultValue: "Sonnet 默认" })}
value={defaultSonnetModel}
onChange={(value) => onModelChange("ANTHROPIC_DEFAULT_SONNET_MODEL", value)}
/>
<ModelSelect
label={t("kimiSelector.opusModel", { defaultValue: "Opus 默认" })}
value={defaultOpusModel}
onChange={(value) => onModelChange("ANTHROPIC_DEFAULT_OPUS_MODEL", value)}
/>
</div>