refactor(ui): remove redundant KimiModelSelector and unify model configuration

Remove KimiModelSelector component and useKimiModelSelector hook to
eliminate code duplication and unify model configuration across all
Claude-compatible providers.

**Problem Statement:**
Previously, we maintained two separate implementations for the same
functionality:
- KimiModelSelector: API-driven dropdown with 211 lines of code
- ClaudeFormFields: Simple text inputs for model configuration

After removing API fetching logic from KimiModelSelector, both components
became functionally identical (4 text inputs), violating DRY principle
and creating unnecessary maintenance burden.

**Changes:**

Backend (Rust):
- No changes (model normalization logic already in place)

Frontend (React):
- Delete KimiModelSelector.tsx (-211 lines)
- Delete useKimiModelSelector.ts (-142 lines)
- Update ClaudeFormFields.tsx: remove Kimi-specific props (-35 lines)
- Update ProviderForm.tsx: unify display logic (-31 lines)
- Clean up hooks/index.ts: remove useKimiModelSelector export (-1 line)

Configuration:
- Update Kimi preset: kimi-k2-turbo-preview → kimi-k2-0905-preview
  * Uses official September 2025 release
  * 256K context window (vs 128K in older version)

Internationalization:
- Remove kimiSelector.* i18n keys (15 keys × 2 languages = -36 lines)
- Remove providerForm.kimiApiKeyHint

**Unified Architecture:**

Before (complex branching):
  ProviderForm
  ├─ if Kimi → useKimiModelSelector → KimiModelSelector (4 inputs)
  └─ else → useModelState → ClaudeFormFields inline (4 inputs)

After (single path):
  ProviderForm
  └─ useModelState → ClaudeFormFields (4 inputs for all providers)

Display logic simplified:
  - Old: shouldShowModelSelector = category !== "official" && !shouldShowKimiSelector
  - New: shouldShowModelSelector = category !== "official"

**Impact:**

Code Quality:
- Remove 457 lines of redundant code (-98.5%)
- Eliminate dual-track maintenance
- Improve code consistency
- Pass TypeScript type checking with zero errors
- Zero remaining references to deleted code

User Experience:
- Consistent UI across all providers (including Kimi)
- Same model configuration workflow for everyone
- No functional changes from user perspective

Architecture:
- Single source of truth for model configuration
- Easier to extend for future providers
- Reduced bundle size (removed lucide-react icons dependency)

**Testing:**
-  TypeScript compilation passes
-  No dangling references
-  All model configuration fields functional
-  Display logic works for official/cn_official/aggregator categories

**Migration Notes:**
- Existing Kimi users: configurations automatically upgraded to new model name
- No manual intervention required
- Backend normalization ensures backward compatibility
This commit is contained in:
Jason
2025-11-02 20:57:16 +08:00
parent 4811aa2dcd
commit ebb7106102
8 changed files with 7 additions and 457 deletions

View File

@@ -5,7 +5,6 @@ export { useModelState } from "./useModelState";
export { useCodexConfigState } from "./useCodexConfigState";
export { useApiKeyLink } from "./useApiKeyLink";
export { useCustomEndpoints } from "./useCustomEndpoints";
export { useKimiModelSelector } from "./useKimiModelSelector";
export { useTemplateValues } from "./useTemplateValues";
export { useCommonConfigSnippet } from "./useCommonConfigSnippet";
export { useCodexCommonConfig } from "./useCodexCommonConfig";

View File

@@ -1,142 +0,0 @@
import { useState, useEffect, useCallback } from "react";
interface UseKimiModelSelectorProps {
initialData?: {
settingsConfig?: Record<string, unknown>;
};
settingsConfig: string;
onConfigChange: (config: string) => void;
selectedPresetId: string | null;
presetName?: string;
}
/**
* 管理 Kimi 模型选择器的状态和逻辑
*/
export function useKimiModelSelector({
initialData,
settingsConfig,
onConfigChange,
selectedPresetId,
presetName = "",
}: UseKimiModelSelectorProps) {
const [kimiAnthropicModel, setKimiAnthropicModel] = useState("");
const [kimiDefaultHaikuModel, setKimiDefaultHaikuModel] = useState("");
const [kimiDefaultSonnetModel, setKimiDefaultSonnetModel] = useState("");
const [kimiDefaultOpusModel, setKimiDefaultOpusModel] = useState("");
// 判断是否显示 Kimi 模型选择器
const shouldShowKimiSelector =
selectedPresetId !== null &&
selectedPresetId !== "custom" &&
presetName.includes("Kimi");
// 判断是否正在编辑 Kimi 供应商
const isEditingKimi = Boolean(
initialData &&
settingsConfig.includes("api.moonshot.cn") &&
settingsConfig.includes("ANTHROPIC_MODEL"),
);
const shouldShow = shouldShowKimiSelector || isEditingKimi;
// 初始化 Kimi 模型选择(编辑模式)
useEffect(() => {
if (
initialData?.settingsConfig &&
typeof initialData.settingsConfig === "object"
) {
const config = initialData.settingsConfig as {
env?: Record<string, unknown>;
};
if (config.env) {
const model =
typeof config.env.ANTHROPIC_MODEL === "string"
? config.env.ANTHROPIC_MODEL
: "";
const haiku =
typeof config.env.ANTHROPIC_DEFAULT_HAIKU_MODEL === "string"
? (config.env.ANTHROPIC_DEFAULT_HAIKU_MODEL as string)
: (typeof config.env.ANTHROPIC_SMALL_FAST_MODEL === "string"
? (config.env.ANTHROPIC_SMALL_FAST_MODEL as string)
: model);
const sonnet =
typeof config.env.ANTHROPIC_DEFAULT_SONNET_MODEL === "string"
? (config.env.ANTHROPIC_DEFAULT_SONNET_MODEL as string)
: model;
const opus =
typeof config.env.ANTHROPIC_DEFAULT_OPUS_MODEL === "string"
? (config.env.ANTHROPIC_DEFAULT_OPUS_MODEL as string)
: model;
setKimiAnthropicModel(model);
setKimiDefaultHaikuModel(haiku);
setKimiDefaultSonnetModel(sonnet);
setKimiDefaultOpusModel(opus);
}
}
}, [initialData]);
// 处理 Kimi 模型变化
const handleKimiModelChange = useCallback(
(
field:
| "ANTHROPIC_MODEL"
| "ANTHROPIC_DEFAULT_HAIKU_MODEL"
| "ANTHROPIC_DEFAULT_SONNET_MODEL"
| "ANTHROPIC_DEFAULT_OPUS_MODEL",
value: string,
) => {
if (field === "ANTHROPIC_MODEL") setKimiAnthropicModel(value);
if (field === "ANTHROPIC_DEFAULT_HAIKU_MODEL") setKimiDefaultHaikuModel(value);
if (field === "ANTHROPIC_DEFAULT_SONNET_MODEL") setKimiDefaultSonnetModel(value);
if (field === "ANTHROPIC_DEFAULT_OPUS_MODEL") setKimiDefaultOpusModel(value);
// 更新配置 JSON只写新键并清理旧键
try {
const currentConfig = JSON.parse(settingsConfig || "{}");
if (!currentConfig.env) currentConfig.env = {};
if (value.trim()) currentConfig.env[field] = value;
else delete currentConfig.env[field];
delete currentConfig.env["ANTHROPIC_SMALL_FAST_MODEL"];
const updatedConfigString = JSON.stringify(currentConfig, null, 2);
onConfigChange(updatedConfigString);
} catch (err) {
console.error("更新 Kimi 模型配置失败:", err);
}
},
[settingsConfig, onConfigChange],
);
// 当选择 Kimi 预设时,同步模型值
useEffect(() => {
if (shouldShowKimiSelector && settingsConfig) {
try {
const config = JSON.parse(settingsConfig);
if (config.env) {
const model = config.env.ANTHROPIC_MODEL || "";
const haiku =
config.env.ANTHROPIC_DEFAULT_HAIKU_MODEL ||
config.env.ANTHROPIC_SMALL_FAST_MODEL ||
model || "";
const sonnet = config.env.ANTHROPIC_DEFAULT_SONNET_MODEL || model || "";
const opus = config.env.ANTHROPIC_DEFAULT_OPUS_MODEL || model || "";
setKimiAnthropicModel(model);
setKimiDefaultHaikuModel(haiku);
setKimiDefaultSonnetModel(sonnet);
setKimiDefaultOpusModel(opus);
}
} catch {
// ignore
}
}
}, [shouldShowKimiSelector, settingsConfig]);
return {
shouldShow,
kimiAnthropicModel,
kimiDefaultHaikuModel,
kimiDefaultSonnetModel,
kimiDefaultOpusModel,
handleKimiModelChange,
};
}