-
Notifications
You must be signed in to change notification settings - Fork 614
refactor: capability-driven model config + i18n #973
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughAdds capability-query APIs to ConfigPresenter and IConfigPresenter, delegating to modelCapabilities. Refactors ChatConfig.vue and ModelConfigDialog.vue to query capabilities and render unified UI for reasoning, thinking budget, and search. Standardizes i18n thinkingBudget strings across locales with generic description/placeholder/validation. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
participant U as User
participant C1 as ChatConfig.vue
participant C2 as ModelConfigDialog.vue
participant P as ConfigPresenter
participant MC as modelCapabilities
rect rgba(200,220,255,0.2)
note over U,C1: Open chat or change provider/model
U->>C1: Open / Change selection
C1->>P: fetchCapabilities(providerId, modelId)\n(supportsReasoning, getBudgetRange,\n supportsSearch, getSearchDefaults)
P->>MC: Query capability data
MC-->>P: capability info
P-->>C1: capability info
C1-->>C1: Derive UI flags & defaults
end
rect rgba(200,255,200,0.2)
note over U,C2: Open Model Config dialog
U->>C2: Open dialog
C2->>P: fetchCapabilities(providerId, modelId)
P->>MC: Query capability data
MC-->>P: capability info
P-->>C2: capability info
C2-->>C2: Render reasoning, budget, search sections
end
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/renderer/src/components/ChatConfig.vue (1)
435-460: Respect capability-provided defaults for search options.When the presenter exposes default/forced/strategy values via
getSearchDefaults, the UI still rendersenableSearch,forcedSearch, andsearchStrategyas if the defaults were false/'turbo'whenever the conversation hasn’t overridden them. This misleads users and can unintentionally disable provider-required behaviors. Please derive the displayed values fromcapabilitySearchDefaultsbefore falling back to hardcoded defaults. Suggested update:+const resolvedEnableSearch = computed(() => { + return props.enableSearch ?? capabilitySearchDefaults.value?.default ?? false +}) + +const resolvedForcedSearch = computed(() => { + if (!hasForcedSearchOption.value) return props.forcedSearch ?? false + return props.forcedSearch ?? capabilitySearchDefaults.value?.forced ?? false +}) + +const resolvedSearchStrategy = computed(() => { + if (!hasSearchStrategyOption.value) return props.searchStrategy ?? 'turbo' + return props.searchStrategy ?? capabilitySearchDefaults.value?.strategy ?? 'turbo' +})- <Switch - :model-value="props.enableSearch ?? false" + <Switch + :model-value="resolvedEnableSearch" @update:model-value="(value) => emit('update:enableSearch', value)" /> … - <div v-if="props.enableSearch && hasForcedSearchOption" class="flex items-center justify-between"> + <div v-if="resolvedEnableSearch && hasForcedSearchOption" class="flex items-center justify-between"> … - <Switch :model-value="props.forcedSearch ?? false" @update:model-value="(value) => emit('update:forcedSearch', value)" /> + <Switch + :model-value="resolvedForcedSearch" + @update:model-value="(value) => emit('update:forcedSearch', value)" + /> … - <div v-if="props.enableSearch && hasSearchStrategyOption" class="space-y-2"> + <div v-if="resolvedEnableSearch && hasSearchStrategyOption" class="space-y-2"> … - <Select :model-value="props.searchStrategy ?? 'turbo'" @update:model-value="(value) => emit('update:searchStrategy', value as 'turbo' | 'max')"> + <Select + :model-value="resolvedSearchStrategy" + @update:model-value="(value) => + emit('update:searchStrategy', value as 'turbo' | 'max')" + " + >Remember to import/use the new computed values where needed.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
src/main/presenter/configPresenter/index.ts(2 hunks)src/renderer/src/components/ChatConfig.vue(7 hunks)src/renderer/src/components/settings/ModelConfigDialog.vue(10 hunks)src/renderer/src/i18n/en-US/settings.json(1 hunks)src/renderer/src/i18n/fa-IR/settings.json(1 hunks)src/renderer/src/i18n/fr-FR/settings.json(1 hunks)src/renderer/src/i18n/ja-JP/settings.json(1 hunks)src/renderer/src/i18n/ko-KR/settings.json(1 hunks)src/renderer/src/i18n/pt-BR/settings.json(1 hunks)src/renderer/src/i18n/ru-RU/settings.json(1 hunks)src/renderer/src/i18n/zh-CN/settings.json(1 hunks)src/renderer/src/i18n/zh-HK/settings.json(1 hunks)src/renderer/src/i18n/zh-TW/settings.json(1 hunks)src/shared/types/presenters/legacy.presenters.d.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (25)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.jsonsrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/i18n/zh-TW/settings.jsonsrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Put application code for the Vue app under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.jsonsrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/i18n/zh-TW/settings.jsonsrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vuesrc/main/presenter/configPresenter/index.tssrc/shared/types/presenters/legacy.presenters.d.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vuesrc/main/presenter/configPresenter/index.tssrc/shared/types/presenters/legacy.presenters.d.ts
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings in the renderer must use vue-i18n keys defined in src/renderer/src/i18n
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
**/*.{js,jsx,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting: single quotes, no semicolons, max width 100
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vuesrc/main/presenter/configPresenter/index.tssrc/shared/types/presenters/legacy.presenters.d.ts
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue components in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
**/*.{js,jsx,ts,tsx}: Use OxLint for JS/TS code; pre-commit hooks run lint-staged and typecheck
Use camelCase for variables and functions
Use PascalCase for types and classes
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/configPresenter/index.tssrc/shared/types/presenters/legacy.presenters.d.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/configPresenter/index.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/configPresenter/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/configPresenter/index.tssrc/shared/types/presenters/legacy.presenters.d.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/configPresenter/index.ts
src/main/**
📄 CodeRabbit inference engine (AGENTS.md)
Place all Electron main-process code under src/main/
Files:
src/main/presenter/configPresenter/index.ts
src/main/presenter/**
📄 CodeRabbit inference engine (AGENTS.md)
src/main/presenter/**: Organize main-process presenters under src/main/presenter/ (Window/Tab/Thread/Mcp/Config/LLMProvider)
Follow the Presenter pattern for main-process modules
Files:
src/main/presenter/configPresenter/index.ts
src/shared/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
共享类型定义放在
shared目录
Files:
src/shared/types/presenters/legacy.presenters.d.ts
src/shared/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Place shared types, utilities, constants, and IPC contract definitions under src/shared/
Files:
src/shared/types/presenters/legacy.presenters.d.ts
src/shared/**
📄 CodeRabbit inference engine (AGENTS.md)
Store shared TypeScript types/utilities in src/shared/
Files:
src/shared/types/presenters/legacy.presenters.d.ts
🧠 Learnings (1)
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/{composables,utils}/**/*.ts : Use VueUse for common composables and utility functions.
Applied to files:
src/renderer/src/components/ChatConfig.vue
🧬 Code graph analysis (1)
src/main/presenter/configPresenter/index.ts (1)
src/main/presenter/configPresenter/modelCapabilities.ts (1)
modelCapabilities(103-103)
🪛 GitHub Actions: PR Check
src/renderer/src/components/settings/ModelConfigDialog.vue
[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.
src/renderer/src/components/ChatConfig.vue
[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.
🔇 Additional comments (2)
src/renderer/src/components/ChatConfig.vue (1)
1-200: Prettier check failing—please reformat before merge.CI reports a Prettier violation for this file. Please run the project’s Prettier configuration (e.g.
pnpm prettier --write src/renderer/src/components/ChatConfig.vue) and commit the formatted output so the pipeline passes.src/renderer/src/components/settings/ModelConfigDialog.vue (1)
1-366: Run Prettier so CI passesThe PR check is failing on Prettier for this file. Please run the project’s Prettier command (e.g.
pnpm prettier --write src/renderer/src/components/settings/ModelConfigDialog.vue) and commit the result.
| // 能力:统一控制思考预算和搜索配置显示 | ||
| const capabilitySupportsReasoning = ref<boolean | null>(null) | ||
| const capabilityBudgetRange = ref<{ min?: number; max?: number; default?: number } | null>(null) | ||
| const capabilitySupportsSearch = ref<boolean | null>(null) | ||
| const capabilitySearchDefaults = ref<{ default?: boolean; forced?: boolean; strategy?: 'turbo' | 'max' } | null>(null) | ||
| const fetchCapabilities = async () => { | ||
| if (!props.providerId || !props.modelId) { | ||
| capabilitySupportsReasoning.value = null | ||
| capabilityBudgetRange.value = null | ||
| capabilitySupportsSearch.value = null | ||
| return | ||
| } | ||
| try { | ||
| const [sr, br, ss, sd] = await Promise.all([ | ||
| configPresenter.supportsReasoningCapability?.(props.providerId, props.modelId), | ||
| configPresenter.getThinkingBudgetRange?.(props.providerId, props.modelId), | ||
| configPresenter.supportsSearchCapability?.(props.providerId, props.modelId), | ||
| configPresenter.getSearchDefaults?.(props.providerId, props.modelId) | ||
| ]) | ||
| capabilitySupportsReasoning.value = typeof sr === 'boolean' ? sr : null | ||
| capabilityBudgetRange.value = br || {} | ||
| capabilitySupportsSearch.value = typeof ss === 'boolean' ? ss : null | ||
| capabilitySearchDefaults.value = sd || null | ||
| } catch { | ||
| capabilitySupportsReasoning.value = null | ||
| capabilityBudgetRange.value = null | ||
| capabilitySupportsSearch.value = null | ||
| capabilitySearchDefaults.value = null | ||
| } | ||
| } | ||
| return (isGemini && isGemini25) || (isDashscope && isQwenThinking && modelReasoning.value) | ||
| }) | ||
| watch( | ||
| () => [props.providerId, props.modelId], | ||
| async () => { | ||
| await fetchCapabilities() | ||
| }, | ||
| { immediate: true } | ||
| ) | ||
| // 是否显示搜索配置 - 支持 Dashscope 的特定模型 | ||
| const showDashscopeSearchConfig = computed(() => { | ||
| const isDashscope = props.providerId === 'dashscope' | ||
| if (!isDashscope || !props.modelId) return false | ||
| // Dashscope - ENABLE_SEARCH_MODELS | ||
| const enableSearchModels = [ | ||
| 'qwen3-max-preview', | ||
| 'qwen3-max-2025-09-23', | ||
| 'qwen3-max', | ||
| 'qwen-max', | ||
| 'qwen-plus', | ||
| 'qwen-plus-latest', | ||
| 'qwen-plus-2025-07-14', | ||
| 'qwen-flash', | ||
| 'qwen-flash-2025-07-28', | ||
| 'qwen-turbo', | ||
| 'qwen-turbo-latest', | ||
| 'qwen-turbo-2025-07-15', | ||
| 'qwq-plus' | ||
| ] | ||
| return enableSearchModels.some((modelName) => | ||
| props.modelId?.toLowerCase().includes(modelName.toLowerCase()) | ||
| const showThinkingBudget = computed(() => { | ||
| return ( | ||
| modelReasoning.value && | ||
| capabilitySupportsReasoning.value === true && | ||
| !!capabilityBudgetRange.value && | ||
| (capabilityBudgetRange.value!.min !== undefined || | ||
| capabilityBudgetRange.value!.max !== undefined || | ||
| capabilityBudgetRange.value!.default !== undefined) | ||
| ) | ||
| }) | ||
| // 是否显示搜索配置 - 支持 Gemini 的特定模型 | ||
| const showGeminiSearchConfig = computed(() => { | ||
| const isSearchableModel = props.providerId === 'gemini' | ||
| if (!isSearchableModel || !props.modelId) return false | ||
| // ENABLE_SEARCH_MODELS | ||
| const enableSearchModels = [ | ||
| 'gemini-2.5-pro', | ||
| 'gemini-2.5-flash', | ||
| 'gemini-2.5-flash-lite', | ||
| 'gemini-2.5-flash-lite-preview-06-17', | ||
| 'gemini-2.0-flash', | ||
| 'gemini-2.0-flash-lite', | ||
| 'gemini-1.5-pro', | ||
| 'gemini-1.5-flash' | ||
| ] | ||
| return enableSearchModels.some((modelName) => | ||
| props.modelId?.toLowerCase().includes(modelName.toLowerCase()) | ||
| ) | ||
| }) | ||
| // 是否显示搜索配置(统一基于能力) | ||
| const showSearchConfig = computed(() => capabilitySupportsSearch.value === true) | ||
| const hasForcedSearchOption = computed(() => capabilitySearchDefaults.value?.forced !== undefined) | ||
| const hasSearchStrategyOption = computed( | ||
| () => capabilitySearchDefaults.value?.strategy !== undefined | ||
| ) | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Convert inline comments to English.
The newly added comments (lines 130, 182, 375, 440, 448) are written in Chinese, but our renderer guidelines require English for all comments/logs. Please translate or remove them to stay compliant.
🤖 Prompt for AI Agents
In src/renderer/src/components/ChatConfig.vue around lines 130-188 (and also
update lines 182, 375, 440, 448 mentioned in the review), replace the Chinese
inline comments with concise English equivalents (or remove them) to comply with
renderer guidelines; keep the comment meaning unchanged (e.g., translate
"能力:统一控制思考预算和搜索配置显示" to "Capability: unified control for thinking budget and
search config display", "是否显示搜索配置(统一基于能力)" to "Show search configuration
(controlled by capability)", etc.), ensuring comment style and placement remain
the same.
| const [sr, br, ss, sd] = await Promise.all([ | ||
| configPresenter.supportsReasoningCapability?.(props.providerId, props.modelId), | ||
| configPresenter.getThinkingBudgetRange?.(props.providerId, props.modelId), | ||
| configPresenter.supportsSearchCapability?.(props.providerId, props.modelId), | ||
| configPresenter.getSearchDefaults?.(props.providerId, props.modelId) | ||
| ]) | ||
| capabilitySupportsReasoning.value = typeof sr === 'boolean' ? sr : null | ||
| capabilityBudgetRange.value = br || {} | ||
| capabilitySupportsSearch.value = typeof ss === 'boolean' ? ss : null | ||
| capabilitySearchDefaults.value = sd || null | ||
| } catch { | ||
| capabilitySupportsReasoning.value = null | ||
| capabilityBudgetRange.value = null | ||
| capabilitySupportsSearch.value = null | ||
| capabilitySearchDefaults.value = null | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reset unsupported capability fields before saving
We hide the reasoning/search controls when the presenter says the model can’t handle them, but we never clear the underlying config values. If a user previously enabled reasoning or search, those stale config.value flags stay true and get persisted even though the capability is now false, leaving us with an invalid, non-editable state. Please zero out the related fields as soon as the capability check fails.
capabilitySupportsReasoning.value = typeof sr === 'boolean' ? sr : null
+ if (capabilitySupportsReasoning.value === false) {
+ config.value.reasoning = false
+ config.value.thinkingBudget = undefined
+ }
capabilityBudgetRange.value = br || {}
capabilitySupportsSearch.value = typeof ss === 'boolean' ? ss : null
+ if (capabilitySupportsSearch.value !== true) {
+ config.value.enableSearch = false
+ config.value.forcedSearch = false
+ config.value.searchStrategy = 'turbo'
+ }
capabilitySearchDefaults.value = sd || null📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const [sr, br, ss, sd] = await Promise.all([ | |
| configPresenter.supportsReasoningCapability?.(props.providerId, props.modelId), | |
| configPresenter.getThinkingBudgetRange?.(props.providerId, props.modelId), | |
| configPresenter.supportsSearchCapability?.(props.providerId, props.modelId), | |
| configPresenter.getSearchDefaults?.(props.providerId, props.modelId) | |
| ]) | |
| capabilitySupportsReasoning.value = typeof sr === 'boolean' ? sr : null | |
| capabilityBudgetRange.value = br || {} | |
| capabilitySupportsSearch.value = typeof ss === 'boolean' ? ss : null | |
| capabilitySearchDefaults.value = sd || null | |
| } catch { | |
| capabilitySupportsReasoning.value = null | |
| capabilityBudgetRange.value = null | |
| capabilitySupportsSearch.value = null | |
| capabilitySearchDefaults.value = null | |
| } | |
| const [sr, br, ss, sd] = await Promise.all([ | |
| configPresenter.supportsReasoningCapability?.(props.providerId, props.modelId), | |
| configPresenter.getThinkingBudgetRange?.(props.providerId, props.modelId), | |
| configPresenter.supportsSearchCapability?.(props.providerId, props.modelId), | |
| configPresenter.getSearchDefaults?.(props.providerId, props.modelId) | |
| ]) | |
| capabilitySupportsReasoning.value = typeof sr === 'boolean' ? sr : null | |
| if (capabilitySupportsReasoning.value === false) { | |
| config.value.reasoning = false | |
| config.value.thinkingBudget = undefined | |
| } | |
| capabilityBudgetRange.value = br || {} | |
| capabilitySupportsSearch.value = typeof ss === 'boolean' ? ss : null | |
| if (capabilitySupportsSearch.value !== true) { | |
| config.value.enableSearch = false | |
| config.value.forcedSearch = false | |
| config.value.searchStrategy = 'turbo' | |
| } | |
| capabilitySearchDefaults.value = sd || null | |
| } catch { | |
| capabilitySupportsReasoning.value = null | |
| capabilityBudgetRange.value = null | |
| capabilitySupportsSearch.value = null | |
| capabilitySearchDefaults.value = null | |
| } |
| supportsReasoningCapability?(providerId: string, modelId: string): boolean | ||
| getThinkingBudgetRange?( | ||
| providerId: string, | ||
| modelId: string | ||
| ): { min?: number; max?: number; default?: number } | ||
| supportsSearchCapability?(providerId: string, modelId: string): boolean | ||
| getSearchDefaults?( | ||
| providerId: string, | ||
| modelId: string | ||
| ): { default?: boolean; forced?: boolean; strategy?: 'turbo' | 'max' } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Declare capability helpers as async in the contract.
These helpers are consumed with await and implemented asynchronously in the presenter layer, but the declaration still returns plain booleans/objects. Please update the signatures to return Promise<...> so implementations type-check correctly and downstream usage matches reality.
- supportsReasoningCapability?(providerId: string, modelId: string): boolean
+ supportsReasoningCapability?(
+ providerId: string,
+ modelId: string
+ ): Promise<boolean>
getThinkingBudgetRange?(
providerId: string,
modelId: string
- ): { min?: number; max?: number; default?: number }
- supportsSearchCapability?(providerId: string, modelId: string): boolean
+ ): Promise<{ min?: number; max?: number; default?: number }>
+ supportsSearchCapability?(
+ providerId: string,
+ modelId: string
+ ): Promise<boolean>
getSearchDefaults?(
providerId: string,
modelId: string
- ): { default?: boolean; forced?: boolean; strategy?: 'turbo' | 'max' }
+ ): Promise<{ default?: boolean; forced?: boolean; strategy?: 'turbo' | 'max' }>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| supportsReasoningCapability?(providerId: string, modelId: string): boolean | |
| getThinkingBudgetRange?( | |
| providerId: string, | |
| modelId: string | |
| ): { min?: number; max?: number; default?: number } | |
| supportsSearchCapability?(providerId: string, modelId: string): boolean | |
| getSearchDefaults?( | |
| providerId: string, | |
| modelId: string | |
| ): { default?: boolean; forced?: boolean; strategy?: 'turbo' | 'max' } | |
| supportsReasoningCapability?( | |
| providerId: string, | |
| modelId: string | |
| ): Promise<boolean> | |
| getThinkingBudgetRange?( | |
| providerId: string, | |
| modelId: string | |
| ): Promise<{ min?: number; max?: number; default?: number }> | |
| supportsSearchCapability?( | |
| providerId: string, | |
| modelId: string | |
| ): Promise<boolean> | |
| getSearchDefaults?( | |
| providerId: string, | |
| modelId: string | |
| ): Promise<{ default?: boolean; forced?: boolean; strategy?: 'turbo' | 'max' }> |
🤖 Prompt for AI Agents
In src/shared/types/presenters/legacy.presenters.d.ts around lines 387 to 396,
the capability helper signatures are declared as synchronous (returning boolean
or object) but are implemented and consumed asynchronously; update the four
method signatures—supportsReasoningCapability, getThinkingBudgetRange,
supportsSearchCapability, and getSearchDefaults—to return Promise<boolean> and
Promise<{ min?: number; max?: number; default?: number }> / Promise<{ default?:
boolean; forced?: boolean; strategy?: 'turbo' | 'max' }> respectively so
implementations and callers type-check correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Nitpick comments (6)
src/renderer/src/components/ChatConfig.vue (2)
140-164: Prevent stale capability state on rapid model/provider changeswatch triggers fetchCapabilities concurrently; late responses can overwrite newer state. Add a simple request token to guard:
+let capabilityReqId = 0 const fetchCapabilities = async () => { - if (!props.providerId || !props.modelId) { + const reqId = ++capabilityReqId + if (!props.providerId || !props.modelId) { capabilitySupportsReasoning.value = null capabilityBudgetRange.value = null capabilitySupportsSearch.value = null return } try { const [sr, br, ss, sd] = await Promise.all([ configPresenter.supportsReasoningCapability?.(props.providerId, props.modelId), configPresenter.getThinkingBudgetRange?.(props.providerId, props.modelId), configPresenter.supportsSearchCapability?.(props.providerId, props.modelId), configPresenter.getSearchDefaults?.(props.providerId, props.modelId) ]) + if (reqId !== capabilityReqId) return capabilitySupportsReasoning.value = typeof sr === 'boolean' ? sr : null capabilityBudgetRange.value = br || {} capabilitySupportsSearch.value = typeof ss === 'boolean' ? ss : null capabilitySearchDefaults.value = sd || null } catch { + if (reqId !== capabilityReqId) return capabilitySupportsReasoning.value = null capabilityBudgetRange.value = null capabilitySupportsSearch.value = null capabilitySearchDefaults.value = null } }
130-139: Non-English commentsComments are in Chinese. Use English for all logs and comments.
As per coding guidelines
Also applies to: 378-410, 412-487
src/renderer/src/components/settings/ModelConfigDialog.vue (4)
483-509: Deduplicate applying search capability defaultsDefaults for enableSearch/forcedSearch/strategy are set twice. Extract once to avoid drift.
- await fetchCapabilities() - - if (config.value.thinkingBudget === undefined) { - const range = capabilityBudgetRange.value - if (range && typeof range.default === 'number') { - config.value.thinkingBudget = range.default - } - if (capabilitySupportsSearch.value === true && capabilitySearchDefaults.value) { - if (config.value.isUserDefined !== true) { - const def = capabilitySearchDefaults.value - if (typeof def.default === 'boolean') config.value.enableSearch = def.default - if (typeof def.forced === 'boolean') config.value.forcedSearch = def.forced - if (def.strategy === 'turbo' || def.strategy === 'max') - config.value.searchStrategy = def.strategy - } - } - } - - if (capabilitySupportsSearch.value === true && capabilitySearchDefaults.value) { - if (config.value.isUserDefined !== true) { - const def = capabilitySearchDefaults.value - if (typeof def.default === 'boolean') config.value.enableSearch = def.default - if (typeof def.forced === 'boolean') config.value.forcedSearch = def.forced - if (def.strategy === 'turbo' || def.strategy === 'max') - config.value.searchStrategy = def.strategy - } - } + await fetchCapabilities() + + // Apply capability-driven defaults when not user-defined + const applyCapabilityDefaults = () => { + const range = capabilityBudgetRange.value + if (config.value.thinkingBudget === undefined && range && typeof range.default === 'number') { + config.value.thinkingBudget = range.default + } + if (config.value.isUserDefined !== true && capabilitySupportsSearch.value === true) { + const def = capabilitySearchDefaults.value + if (def) { + if (typeof def.default === 'boolean') config.value.enableSearch = def.default + if (typeof def.forced === 'boolean') config.value.forcedSearch = def.forced + if (def.strategy === 'turbo' || def.strategy === 'max') config.value.searchStrategy = def.strategy + } + } + } + applyCapabilityDefaults()Also applies to: 501-509
661-676: Align thinking-budget validation with ChatConfig (required vs optional)Here the field is required when visible; in ChatConfig it’s optional. Decide one behavior and apply consistently. If optional, remove the “required” branch:
- if (value === undefined || value === null) { - return t('settings.model.modelConfig.thinkingBudget.validation.required') - } + if (value === undefined || value === null) return ''
736-739: Reasoning toggle should be shown only when supported, or already enabledUsing “!== false” shows toggle even when capability is unknown. Prefer explicit support or preserving existing true:
-const showReasoningToggle = computed(() => { - return capabilitySupportsReasoning.value !== false -}) +const showReasoningToggle = computed(() => { + return capabilitySupportsReasoning.value === true || config.value.reasoning === true +})
372-407: Non-English commentsComments are in Chinese. Use English for all logs and comments.
As per coding guidelines
Also applies to: 217-257, 258-314
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
src/main/presenter/configPresenter/index.ts(2 hunks)src/renderer/src/components/ChatConfig.vue(8 hunks)src/renderer/src/components/settings/ModelConfigDialog.vue(11 hunks)src/renderer/src/i18n/en-US/settings.json(1 hunks)src/renderer/src/i18n/fa-IR/settings.json(1 hunks)src/renderer/src/i18n/fr-FR/settings.json(1 hunks)src/renderer/src/i18n/ja-JP/settings.json(1 hunks)src/renderer/src/i18n/ko-KR/settings.json(1 hunks)src/renderer/src/i18n/pt-BR/settings.json(1 hunks)src/renderer/src/i18n/ru-RU/settings.json(1 hunks)src/renderer/src/i18n/zh-CN/settings.json(1 hunks)src/renderer/src/i18n/zh-HK/settings.json(1 hunks)src/renderer/src/i18n/zh-TW/settings.json(1 hunks)src/shared/types/presenters/legacy.presenters.d.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (25)
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/en-US/settings.jsonsrc/renderer/src/i18n/zh-TW/settings.jsonsrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.json
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Put application code for the Vue app under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/ko-KR/settings.jsonsrc/renderer/src/i18n/fr-FR/settings.jsonsrc/renderer/src/i18n/fa-IR/settings.jsonsrc/renderer/src/i18n/pt-BR/settings.jsonsrc/renderer/src/i18n/en-US/settings.jsonsrc/renderer/src/i18n/zh-TW/settings.jsonsrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/i18n/ru-RU/settings.jsonsrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/i18n/ja-JP/settings.jsonsrc/renderer/src/i18n/zh-HK/settings.json
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
**/*.{js,jsx,ts,tsx}: Use OxLint for JS/TS code; pre-commit hooks run lint-staged and typecheck
Use camelCase for variables and functions
Use PascalCase for types and classes
Use SCREAMING_SNAKE_CASE for constants
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/configPresenter/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/configPresenter/index.ts
src/shared/**/*.{ts,tsx,d.ts}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
共享类型定义放在
shared目录
Files:
src/shared/types/presenters/legacy.presenters.d.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vuesrc/main/presenter/configPresenter/index.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vuesrc/main/presenter/configPresenter/index.ts
src/shared/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Place shared types, utilities, constants, and IPC contract definitions under src/shared/
Files:
src/shared/types/presenters/legacy.presenters.d.ts
src/shared/**
📄 CodeRabbit inference engine (AGENTS.md)
Store shared TypeScript types/utilities in src/shared/
Files:
src/shared/types/presenters/legacy.presenters.d.ts
**/*.{js,jsx,ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
Apply Prettier formatting: single quotes, no semicolons, max width 100
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vuesrc/main/presenter/configPresenter/index.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings in the renderer must use vue-i18n keys defined in src/renderer/src/i18n
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue components in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/settings/ModelConfigDialog.vuesrc/renderer/src/components/ChatConfig.vue
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/configPresenter/index.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/configPresenter/index.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/configPresenter/index.ts
src/main/**
📄 CodeRabbit inference engine (AGENTS.md)
Place all Electron main-process code under src/main/
Files:
src/main/presenter/configPresenter/index.ts
src/main/presenter/**
📄 CodeRabbit inference engine (AGENTS.md)
src/main/presenter/**: Organize main-process presenters under src/main/presenter/ (Window/Tab/Thread/Mcp/Config/LLMProvider)
Follow the Presenter pattern for main-process modules
Files:
src/main/presenter/configPresenter/index.ts
🧠 Learnings (2)
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/{composables,utils}/**/*.ts : Use VueUse for common composables and utility functions.
Applied to files:
src/renderer/src/components/ChatConfig.vue
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/configPresenter/providers.ts : Add provider configuration entries in src/main/presenter/configPresenter/providers.ts
Applied to files:
src/main/presenter/configPresenter/index.ts
🧬 Code graph analysis (1)
src/main/presenter/configPresenter/index.ts (1)
src/main/presenter/configPresenter/modelCapabilities.ts (1)
modelCapabilities(103-103)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (12)
src/renderer/src/i18n/fa-IR/settings.json (1)
160-167: Unify terminology and include missing{min}placeholder in fa-IR/settings.json
- In
thinkingBudget.description, replace “توکن” with “نشانههای” for consistency.- In
thinkingBudget.validation.minValue, change to “مقدار نمیتواند کمتر از {min} باشد”.Verify that all other locales define identical
thinkingBudgetkeys and include both{min}and{max}placeholders.src/renderer/src/i18n/zh-CN/settings.json (1)
172-179: Unified thinkingBudget keys look goodConsolidation to description/placeholder/validation is consistent and clear. Placeholders align with range text.
src/renderer/src/i18n/zh-TW/settings.json (1)
160-167: LGTM on unified thinkingBudgetConsistent keys and correct {min}/{max} placeholders.
src/renderer/src/i18n/ko-KR/settings.json (1)
160-167: Thinking budget i18n updated correctlyUnified keys and validation messages are consistent with other locales.
src/renderer/src/i18n/zh-HK/settings.json (1)
160-167: Good consolidationUnified thinkingBudget fields and validation read well; placeholders OK.
src/renderer/src/i18n/ru-RU/settings.json (1)
159-167: LGTM, plus minor label polishUnified structure is correct; label case change is fine. Placeholders align with range.
src/renderer/src/i18n/ja-JP/settings.json (1)
160-167: Looks goodUnified thinkingBudget keys and validation are consistent across locales.
src/renderer/src/i18n/pt-BR/settings.json (1)
160-167: Consolidation approvedDescription/placeholder/validation for thinkingBudget are correct; placeholders match range.
src/renderer/src/i18n/en-US/settings.json (1)
160-167: No stale thinkingBudget.gemini/qwen3 keys found; unified thinkingBudget keys confirmed in all localessrc/main/presenter/configPresenter/index.ts (1)
36-36: Capability-query methods added and wired correctlyDelegations to modelCapabilities with precise return types; matches IConfigPresenter optional surface.
Confirm these methods are exposed through the preload/bridge so usePresenter('configPresenter') sees them. If exposure is reflective, no action needed; otherwise add them to the exposed API.
Also applies to: 212-233
src/shared/types/presenters/legacy.presenters.d.ts (1)
387-396: Interface surface extended for capabilitiesOptional methods and their types align with presenter and renderer usage.
src/renderer/src/i18n/fr-FR/settings.json (1)
159-167: ThinkingBudget i18n keys defined across all locales
All required subkeys (label, description, placeholder, range, validation.required, minValue, maxValue) are present and align with the renderer’s UI usage.
| const showThinkingBudget = computed(() => { | ||
| return ( | ||
| modelReasoning.value && | ||
| capabilitySupportsReasoning.value === true && | ||
| !!capabilityBudgetRange.value && | ||
| (capabilityBudgetRange.value!.min !== undefined || | ||
| capabilityBudgetRange.value!.max !== undefined || | ||
| capabilityBudgetRange.value!.default !== undefined) | ||
| ) | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unify thinking-budget visibility criteria with ModelConfigDialog
Here you show when any of min/max/default exists. In ModelConfigDialog, visibility depends only on max being defined, which can hide this section for valid ranges. Align both to the “any-of min/max/default” rule to avoid inconsistent UI.
🤖 Prompt for AI Agents
In src/renderer/src/components/ChatConfig.vue around lines 174 to 183, the
computed showThinkingBudget uses "any-of min/max/default" to decide visibility;
update the corresponding visibility logic in ModelConfigDialog to match this
rule so the UI is consistent: change its condition to check
capabilityBudgetRange exists and that at least one of min, max, or default is
not undefined (instead of only checking max), and keep any existing
capabilitySupportsReasoning/modelReasoning checks so the combined predicate
mirrors ChatConfig.vue.
| const showThinkingBudget = computed(() => { | ||
| const hasReasoning = config.value.reasoning | ||
| const modelConfig = getThinkingBudgetConfig(props.modelId) | ||
| const isSupported = modelConfig !== null | ||
| return isGemini && hasReasoning && isSupported | ||
| }) | ||
| // 是否显示Qwen3思考预算配置 | ||
| const showQwen3ThinkingBudget = computed(() => { | ||
| const isDashscope = props.providerId === 'dashscope' | ||
| const hasReasoning = config.value.reasoning | ||
| const modelId = props.modelId.toLowerCase() | ||
| // DashScope - ENABLE_THINKING_MODELS | ||
| const supportedThinkingModels = [ | ||
| // Open source versions | ||
| 'qwen3-next-80b-a3b-thinking', | ||
| 'qwen3-235b-a22b', | ||
| 'qwen3-32b', | ||
| 'qwen3-30b-a3b', | ||
| 'qwen3-14b', | ||
| 'qwen3-8b', | ||
| 'qwen3-4b', | ||
| 'qwen3-1.7b', | ||
| 'qwen3-0.6b', | ||
| // Commercial versions | ||
| 'qwen3-vl-plus', | ||
| 'qwen-plus', | ||
| 'qwen-plus-latest', | ||
| 'qwen-plus-2025-04-28', | ||
| 'qwen-flash', | ||
| 'qwen-flash-2025-07-28', | ||
| 'qwen-turbo', | ||
| 'qwen-turbo-latest', | ||
| 'qwen-turbo-2025-04-28' | ||
| ] | ||
| const isSupported = supportedThinkingModels.some((supportedModel) => | ||
| modelId.includes(supportedModel) | ||
| ) | ||
| const modelConfig = getThinkingBudgetConfig(props.modelId) | ||
| const hasValidConfig = modelConfig !== null | ||
| return isDashscope && hasReasoning && isSupported && hasValidConfig | ||
| }) | ||
| // 是否显示DashScope搜索配置 | ||
| const showDashScopeSearch = computed(() => { | ||
| const isDashscope = props.providerId === 'dashscope' | ||
| const modelId = props.modelId.toLowerCase() | ||
| // DashScope - ENABLE_SEARCH_MODELS | ||
| const supportedSearchModels = [ | ||
| 'qwen3-max-2025-09-23', | ||
| 'qwen3-max-preview', | ||
| 'qwen3-max', | ||
| 'qwen-max', | ||
| 'qwen-plus', | ||
| 'qwen-flash', | ||
| 'qwen-turbo', | ||
| 'qwq-plus' | ||
| ] | ||
| const isSupported = supportedSearchModels.some((supportedModel) => | ||
| modelId.includes(supportedModel) | ||
| ) | ||
| return isDashscope && isSupported | ||
| }) | ||
| // 是否显示Grok搜索配置 | ||
| const showGrokSearch = computed(() => { | ||
| const isGrok = props.providerId === 'grok' | ||
| const modelId = props.modelId.toLowerCase() | ||
| // According to requirements, all Grok models support internet search | ||
| const supportedSearchModels = [ | ||
| 'grok-4', | ||
| 'grok-3-mini', | ||
| 'grok-3-mini-fast', | ||
| 'grok-3-fast', | ||
| 'grok-3', | ||
| 'grok-2', | ||
| 'grok-2-vision', | ||
| 'grok-2-image' | ||
| ] | ||
| const isSupported = | ||
| supportedSearchModels.some((supportedModel) => modelId.includes(supportedModel)) || | ||
| modelId.includes('grok') | ||
| return isGrok && isSupported | ||
| }) | ||
| // 是否显示Gemini搜索配置 | ||
| const showGeminiSearch = computed(() => { | ||
| const isGemini = props.providerId === 'gemini' | ||
| const modelId = props.modelId.toLowerCase() | ||
| const supportedSearchModels = [ | ||
| 'gemini-2.5-pro', | ||
| 'gemini-2.5-flash', | ||
| 'gemini-2.5-flash-lite', | ||
| 'gemini-2.5-flash-lite-preview-06-17', | ||
| 'gemini-2.0-flash', | ||
| 'gemini-2.0-flash-lite', | ||
| 'gemini-1.5-pro', | ||
| 'gemini-1.5-flash' | ||
| ] | ||
| const isSupported = | ||
| supportedSearchModels.some((supportedModel) => modelId.includes(supportedModel)) || | ||
| modelId.includes('gemini') | ||
| return isGemini && isSupported | ||
| const supported = capabilitySupportsReasoning.value === true | ||
| const hasRange = !!thinkingBudgetRange.value && thinkingBudgetRange.value.max !== undefined | ||
| return hasReasoning && supported && hasRange | ||
| }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fix thinking-budget visibility to match ChatConfig
Current logic requires max to be defined. Use any-of min/max/default to avoid hiding valid fields.
-const showThinkingBudget = computed(() => {
- const hasReasoning = config.value.reasoning
- const supported = capabilitySupportsReasoning.value === true
- const hasRange = !!thinkingBudgetRange.value && thinkingBudgetRange.value.max !== undefined
- return hasReasoning && supported && hasRange
-})
+const showThinkingBudget = computed(() => {
+ const hasReasoning = config.value.reasoning
+ const supported = capabilitySupportsReasoning.value === true
+ const r = thinkingBudgetRange.value
+ const hasAny = !!r && (r.min !== undefined || r.max !== undefined || r.default !== undefined)
+ return hasReasoning && supported && hasAny
+})📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const showThinkingBudget = computed(() => { | |
| const hasReasoning = config.value.reasoning | |
| const modelConfig = getThinkingBudgetConfig(props.modelId) | |
| const isSupported = modelConfig !== null | |
| return isGemini && hasReasoning && isSupported | |
| }) | |
| // 是否显示Qwen3思考预算配置 | |
| const showQwen3ThinkingBudget = computed(() => { | |
| const isDashscope = props.providerId === 'dashscope' | |
| const hasReasoning = config.value.reasoning | |
| const modelId = props.modelId.toLowerCase() | |
| // DashScope - ENABLE_THINKING_MODELS | |
| const supportedThinkingModels = [ | |
| // Open source versions | |
| 'qwen3-next-80b-a3b-thinking', | |
| 'qwen3-235b-a22b', | |
| 'qwen3-32b', | |
| 'qwen3-30b-a3b', | |
| 'qwen3-14b', | |
| 'qwen3-8b', | |
| 'qwen3-4b', | |
| 'qwen3-1.7b', | |
| 'qwen3-0.6b', | |
| // Commercial versions | |
| 'qwen3-vl-plus', | |
| 'qwen-plus', | |
| 'qwen-plus-latest', | |
| 'qwen-plus-2025-04-28', | |
| 'qwen-flash', | |
| 'qwen-flash-2025-07-28', | |
| 'qwen-turbo', | |
| 'qwen-turbo-latest', | |
| 'qwen-turbo-2025-04-28' | |
| ] | |
| const isSupported = supportedThinkingModels.some((supportedModel) => | |
| modelId.includes(supportedModel) | |
| ) | |
| const modelConfig = getThinkingBudgetConfig(props.modelId) | |
| const hasValidConfig = modelConfig !== null | |
| return isDashscope && hasReasoning && isSupported && hasValidConfig | |
| }) | |
| // 是否显示DashScope搜索配置 | |
| const showDashScopeSearch = computed(() => { | |
| const isDashscope = props.providerId === 'dashscope' | |
| const modelId = props.modelId.toLowerCase() | |
| // DashScope - ENABLE_SEARCH_MODELS | |
| const supportedSearchModels = [ | |
| 'qwen3-max-2025-09-23', | |
| 'qwen3-max-preview', | |
| 'qwen3-max', | |
| 'qwen-max', | |
| 'qwen-plus', | |
| 'qwen-flash', | |
| 'qwen-turbo', | |
| 'qwq-plus' | |
| ] | |
| const isSupported = supportedSearchModels.some((supportedModel) => | |
| modelId.includes(supportedModel) | |
| ) | |
| return isDashscope && isSupported | |
| }) | |
| // 是否显示Grok搜索配置 | |
| const showGrokSearch = computed(() => { | |
| const isGrok = props.providerId === 'grok' | |
| const modelId = props.modelId.toLowerCase() | |
| // According to requirements, all Grok models support internet search | |
| const supportedSearchModels = [ | |
| 'grok-4', | |
| 'grok-3-mini', | |
| 'grok-3-mini-fast', | |
| 'grok-3-fast', | |
| 'grok-3', | |
| 'grok-2', | |
| 'grok-2-vision', | |
| 'grok-2-image' | |
| ] | |
| const isSupported = | |
| supportedSearchModels.some((supportedModel) => modelId.includes(supportedModel)) || | |
| modelId.includes('grok') | |
| return isGrok && isSupported | |
| }) | |
| // 是否显示Gemini搜索配置 | |
| const showGeminiSearch = computed(() => { | |
| const isGemini = props.providerId === 'gemini' | |
| const modelId = props.modelId.toLowerCase() | |
| const supportedSearchModels = [ | |
| 'gemini-2.5-pro', | |
| 'gemini-2.5-flash', | |
| 'gemini-2.5-flash-lite', | |
| 'gemini-2.5-flash-lite-preview-06-17', | |
| 'gemini-2.0-flash', | |
| 'gemini-2.0-flash-lite', | |
| 'gemini-1.5-pro', | |
| 'gemini-1.5-flash' | |
| ] | |
| const isSupported = | |
| supportedSearchModels.some((supportedModel) => modelId.includes(supportedModel)) || | |
| modelId.includes('gemini') | |
| return isGemini && isSupported | |
| const supported = capabilitySupportsReasoning.value === true | |
| const hasRange = !!thinkingBudgetRange.value && thinkingBudgetRange.value.max !== undefined | |
| return hasReasoning && supported && hasRange | |
| }) | |
| const showThinkingBudget = computed(() => { | |
| const hasReasoning = config.value.reasoning | |
| const supported = capabilitySupportsReasoning.value === true | |
| const r = thinkingBudgetRange.value | |
| const hasAny = !!r && (r.min !== undefined || r.max !== undefined || r.default !== undefined) | |
| return hasReasoning && supported && hasAny | |
| }) |
🤖 Prompt for AI Agents
In src/renderer/src/components/settings/ModelConfigDialog.vue around lines 601
to 606, the computed showThinkingBudget currently requires
thinkingBudgetRange.value.max to be defined which hides valid fields; change the
range check to accept any of min, max, or default being present (e.g., compute
hasRange as !!thinkingBudgetRange.value && (thinkingBudgetRange.value.min !==
undefined || thinkingBudgetRange.value.max !== undefined ||
thinkingBudgetRange.value.default !== undefined)), then return hasReasoning &&
supported && hasRange so the visibility matches ChatConfig.
refactor capability-driven model config + i18n
Summary by CodeRabbit
New Features
Refactor
i18n