feat(gemini): add config.json editor and common config functionality

Implements dual-editor pattern for Gemini providers, following the Codex architecture:
- Environment variables (.env format) editor
- Extended configuration (config.json) editor with common config support

New Components:
- GeminiConfigSections: Separate sections for env and config editing
- GeminiCommonConfigModal: Modal for editing common config snippets

New Hooks:
- useGeminiConfigState: Manages env/config separation and conversion
  - Converts between .env string format and JSON object
  - Validates JSON config structure
  - Extracts API Key and Base URL from env
- useGeminiCommonConfig: Handles common config snippets
  - Deep merge algorithm for combining configs
  - Remove common config logic for toggling off
  - localStorage persistence for snippets

Features:
- Format buttons for both env and config editors
- Common config toggle with deep merge/remove
- Error validation and display
- Auto-open modal on common config errors

Configuration Structure:
{
  "env": {
    "GOOGLE_GEMINI_BASE_URL": "https://...",
    "GEMINI_API_KEY": "sk-...",
    "GEMINI_MODEL": "gemini-2.5-pro"
  },
  "config": {
    "timeout": 30000,
    "maxRetries": 3
  }
}

This brings Gemini providers to feature parity with Claude and Codex.
This commit is contained in:
Jason
2025-11-14 08:32:30 +08:00
parent 0ea434a485
commit 146b42fb68
7 changed files with 948 additions and 131 deletions
@@ -29,8 +29,9 @@ export function useCommonConfigSnippet({
initialData,
}: UseCommonConfigSnippetProps) {
const [useCommonConfig, setUseCommonConfig] = useState(false);
const [commonConfigSnippet, setCommonConfigSnippetState] =
useState<string>(DEFAULT_COMMON_CONFIG_SNIPPET);
const [commonConfigSnippet, setCommonConfigSnippetState] = useState<string>(
DEFAULT_COMMON_CONFIG_SNIPPET,
);
const [commonConfigError, setCommonConfigError] = useState("");
const [isLoading, setIsLoading] = useState(true);
@@ -64,7 +65,9 @@ export function useCommonConfigSnippet({
}
// 清理 localStorage
window.localStorage.removeItem(LEGACY_STORAGE_KEY);
console.log("[迁移] 通用配置已从 localStorage 迁移到 config.json");
console.log(
"[迁移] 通用配置已从 localStorage 迁移到 config.json",
);
}
} catch (e) {
console.warn("[迁移] 从 localStorage 迁移失败:", e);