feat: add model configuration support and fix Gemini deeplink bug (#251)
* feat(providers): add notes field for provider management - Add notes field to Provider model (backend and frontend) - Display notes with higher priority than URL in provider card - Style notes as non-clickable text to differentiate from URLs - Add notes input field in provider form - Add i18n support (zh/en) for notes field * chore: format code and clean up unused props - Run cargo fmt on Rust backend code - Format TypeScript imports and code style - Remove unused appId prop from ProviderPresetSelector - Clean up unused variables in tests - Integrate notes field handling in provider dialogs * feat(deeplink): implement ccswitch:// protocol for provider import Add deep link support to enable one-click provider configuration import via ccswitch:// URLs. Backend: - Implement URL parsing and validation (src-tauri/src/deeplink.rs) - Add Tauri commands for parse and import (src-tauri/src/commands/deeplink.rs) - Register ccswitch:// protocol in macOS Info.plist - Add comprehensive unit tests (src-tauri/tests/deeplink_import.rs) Frontend: - Create confirmation dialog with security review UI (src/components/DeepLinkImportDialog.tsx) - Add API wrapper (src/lib/api/deeplink.ts) - Integrate event listeners in App.tsx Configuration: - Update Tauri config for deep link handling - Add i18n support for Chinese and English - Include test page for deep link validation (deeplink-test.html) Files: 15 changed, 1312 insertions(+) * chore(deeplink): integrate deep link handling into app lifecycle Wire up deep link infrastructure with app initialization and event handling. Backend Integration: - Register deep link module and commands in mod.rs - Add URL handling in app setup (src-tauri/src/lib.rs:handle_deeplink_url) - Handle deep links from single instance callback (Windows/Linux CLI) - Handle deep links from macOS system events - Add tauri-plugin-deep-link dependency (Cargo.toml) Frontend Integration: - Listen for deeplink-import/deeplink-error events in App.tsx - Update DeepLinkImportDialog component imports Configuration: - Enable deep link plugin in tauri.conf.json - Update Cargo.lock for new dependencies Localization: - Add Chinese translations for deep link UI (zh.json) - Add English translations for deep link UI (en.json) Files: 9 changed, 359 insertions(+), 18 deletions(-) * refactor(deeplink): enhance Codex provider template generation Align deep link import with UI preset generation logic by: - Adding complete config.toml template matching frontend defaults - Generating safe provider name from sanitized input - Including model_provider, reasoning_effort, and wire_api settings - Removing minimal template that only contained base_url - Cleaning up deprecated test file deeplink-test.html * style: fix clippy uninlined_format_args warnings Apply clippy --fix to use inline format arguments in: - src/mcp.rs (8 fixes) - src/services/env_manager.rs (10 fixes) * style: apply code formatting and cleanup - Format TypeScript files with Prettier (App.tsx, EnvWarningBanner.tsx, formatters.ts) - Organize Rust imports and module order alphabetically - Add newline at end of JSON files (en.json, zh.json) - Update Cargo.lock for dependency changes * feat: add model name configuration support for Codex and fix Gemini model handling - Add visual model name input field for Codex providers - Add model name extraction and update utilities in providerConfigUtils - Implement model name state management in useCodexConfigState hook - Add conditional model field rendering in CodexFormFields (non-official only) - Integrate model name sync with TOML config in ProviderForm - Fix Gemini deeplink model injection bug - Correct environment variable name from GOOGLE_GEMINI_MODEL to GEMINI_MODEL - Add test cases for Gemini model injection (with/without model) - All tests passing (9/9) - Fix Gemini model field binding in edit mode - Add geminiModel state to useGeminiConfigState hook - Extract model value during initialization and reset - Sync model field with geminiEnv state to prevent data loss on submit - Fix missing model value display when editing Gemini providers Changes: - 6 files changed, 245 insertions(+), 13 deletions(-)
This commit is contained in:
@@ -35,7 +35,7 @@ export function parseSmartMcpJson(jsonText: string): {
|
||||
}
|
||||
|
||||
// 如果是键值对片段("key": {...}),包装成完整对象
|
||||
if (trimmed.startsWith('"') && !trimmed.startsWith('{')) {
|
||||
if (trimmed.startsWith('"') && !trimmed.startsWith("{")) {
|
||||
trimmed = `{${trimmed}}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -467,3 +467,66 @@ export const setCodexBaseUrl = (
|
||||
: normalizedText;
|
||||
return `${prefix}${replacementLine}\n`;
|
||||
};
|
||||
|
||||
// ========== Codex model name utils ==========
|
||||
|
||||
// 从 Codex 的 TOML 配置文本中提取 model 字段(支持单/双引号)
|
||||
export const extractCodexModelName = (
|
||||
configText: string | undefined | null,
|
||||
): string | undefined => {
|
||||
try {
|
||||
const raw = typeof configText === "string" ? configText : "";
|
||||
// 归一化中文/全角引号,避免正则提取失败
|
||||
const text = normalizeQuotes(raw);
|
||||
if (!text) return undefined;
|
||||
|
||||
// 匹配 model = "xxx" 或 model = 'xxx'
|
||||
const m = text.match(/^model\s*=\s*(['"])([^'"]+)\1/m);
|
||||
return m && m[2] ? m[2] : undefined;
|
||||
} catch {
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
// 在 Codex 的 TOML 配置文本中写入或更新 model 字段
|
||||
export const setCodexModelName = (
|
||||
configText: string,
|
||||
modelName: string,
|
||||
): string => {
|
||||
const trimmed = modelName.trim();
|
||||
if (!trimmed) {
|
||||
return configText;
|
||||
}
|
||||
|
||||
// 归一化原文本中的引号(既能匹配,也能输出稳定格式)
|
||||
const normalizedText = normalizeQuotes(configText);
|
||||
|
||||
const replacementLine = `model = "${trimmed}"`;
|
||||
const pattern = /^model\s*=\s*["']([^"']+)["']/m;
|
||||
|
||||
if (pattern.test(normalizedText)) {
|
||||
return normalizedText.replace(pattern, replacementLine);
|
||||
}
|
||||
|
||||
// 如果不存在 model 字段,尝试在 model_provider 之后插入
|
||||
// 如果 model_provider 也不存在,则插入到开头
|
||||
const providerPattern = /^model_provider\s*=\s*["'][^"']+["']/m;
|
||||
const match = normalizedText.match(providerPattern);
|
||||
|
||||
if (match && match.index !== undefined) {
|
||||
// 在 model_provider 行之后插入
|
||||
const endOfLine = normalizedText.indexOf("\n", match.index);
|
||||
if (endOfLine !== -1) {
|
||||
return (
|
||||
normalizedText.slice(0, endOfLine + 1) +
|
||||
replacementLine +
|
||||
"\n" +
|
||||
normalizedText.slice(endOfLine + 1)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 在文件开头插入
|
||||
const lines = normalizedText.split("\n");
|
||||
return `${replacementLine}\n${lines.join("\n")}`;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user