-
Notifications
You must be signed in to change notification settings - Fork 614
支持自定义模型参数 #516
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
支持自定义模型参数 #516
Conversation
|
Warning Rate limit exceeded@zerob13 has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 12 minutes and 23 seconds before requesting another review. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. 📒 Files selected for processing (1)
WalkthroughThis update introduces a modular and extensible system for managing model configurations, including a new persistent storage helper, APIs for batch operations, and a Vue-based dialog for editing model parameters. The changes add localization support, optimize batch status fetching, and ensure model configuration files are included in backup and sync workflows. Legacy documentation and obsolete configuration files are removed. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ModelConfigDialog (Vue)
participant Settings Store
participant ConfigPresenter (Main)
participant ModelConfigHelper
participant ElectronStore
User->>ModelConfigDialog (Vue): Open dialog to edit model config
ModelConfigDialog (Vue)->>Settings Store: getModelConfig(modelId, providerId)
Settings Store->>ConfigPresenter (Main): getModelConfig(modelId, providerId)
ConfigPresenter (Main)->>ModelConfigHelper: getModelConfig(modelId, providerId)
ModelConfigHelper->>ElectronStore: Retrieve config (layered fallback)
ElectronStore-->>ModelConfigHelper: Return config
ModelConfigHelper-->>ConfigPresenter (Main): Return config
ConfigPresenter (Main)-->>Settings Store: Return config
Settings Store-->>ModelConfigDialog (Vue): Return config
User->>ModelConfigDialog (Vue): Save changes
ModelConfigDialog (Vue)->>Settings Store: setModelConfig(modelId, providerId, config)
Settings Store->>ConfigPresenter (Main): setModelConfig(modelId, providerId, config)
ConfigPresenter (Main)->>ModelConfigHelper: setModelConfig(modelId, providerId, config)
ModelConfigHelper->>ElectronStore: Persist config
ElectronStore-->>ModelConfigHelper: Ack
ModelConfigHelper-->>ConfigPresenter (Main): Ack
ConfigPresenter (Main)-->>Settings Store: Ack
Settings Store-->>ModelConfigDialog (Vue): Ack
ConfigPresenter (Main)->>All Renderers: Emit MODEL_CONFIG_CHANGED event
Poem
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
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: 8
♻️ Duplicate comments (3)
src/renderer/src/i18n/zh-TW/settings.json (1)
104-160: Same newline-escape caveat as zh-HK file.
See previous comment for details.src/renderer/src/i18n/ru-RU/settings.json (1)
104-160: Same newline-escape caveat as zh-HK file.src/renderer/src/i18n/fa-IR/settings.json (1)
104-160: Same newline-escape caveat as zh-HK file.
🧹 Nitpick comments (20)
src/shared/model.ts (1)
8-9: Add a trailing comma to avoid noisy future diffsEvery other enum member ends with a comma; keep the pattern for the last entry as well.
- ImageGeneration = 'imageGeneration' + ImageGeneration = 'imageGeneration',src/renderer/src/components/settings/ModelProviderSettingsDetail.vue (1)
348-352: Consider throttlinginitData()to prevent excessive refreshes
config-changedmay fire repeatedly while a user tweaks multiple fields in the dialog.
Re-runninginitData()on every emission can cause unnecessary network / store calls.-const handleConfigChanged = async () => { - await initData() -} +import { throttle } from 'lodash-es' + +const handleConfigChanged = throttle(async () => { + await initData() +}, 500)A 500 ms throttle (or debounce) keeps the UI in sync without spamming the store.
src/renderer/src/components/settings/ProviderModelList.vue (1)
111-119: Same note for provider models – duplication of inline arrow fn.Nice symmetry with the custom-model block.
Minor:@enabled-change="(enabled) => handleModelEnabledChange(model, enabled)"plus the
new@config-changedarrow recreates two closures per row on every render.
If repaint frequency becomes a concern, consider hoisting those handlers
(handleConfigChanged) outside the template.src/renderer/src/i18n/zh-HK/settings.json (1)
103-160: Large localisation block added – only one nitpick.JSON includes explicit line-breaks (
\n) within theresetConfirm.message.
If your i18n extraction tooling strips escapes, the newline may render as\n
instead of an actual break in some UI libraries.
Consider using a real line break or separate paragraphs.src/renderer/src/i18n/en-US/settings.json (1)
125-133: Refine wording & drop superfluous repetition
Sentence reads a bit awkwardly (“The higher the higher the randomness.”). Consider tightening:- "description": "Control the randomness of the output. Most models are 0-1, and some support between 0-2. The higher the higher the randomness.", + "description": "Controls output randomness. Typical range is 0-1 (some models allow 0-2); higher values yield more random results.",src/renderer/src/components/settings/ModelConfigItem.vue (2)
42-50: Great UX touch – settings button addedButton wiring, i18n title and icon all check out.
Small nitpick:lucide:settingsicon colour could respond tohover:to match other action buttons.-<Icon icon="lucide:settings" class="w-4 h-4 text-muted-foreground" /> +<Icon icon="lucide:settings" class="w-4 h-4 text-muted-foreground hover:text-foreground" />
104-114: Emit payload for clarity
configChangedcurrently emits no data. Passing at least themodelId(and maybe the updated config) helps parents update state without having to refetch.-const onConfigSaved = () => { - emit('configChanged') -} +const onConfigSaved = (payload?: unknown) => { + emit('configChanged', { modelId, ...payload }) +}You’ll then need to extend
defineEmitsaccordingly.src/main/presenter/syncPresenter/index.ts (7)
163-169: Remove unnecessary empty lines.The empty lines break the flow of backup operations. Consider removing them to maintain consistency with the rest of the backup logic.
// 备份模型配置文件 if (fs.existsSync(this.MODEL_CONFIG_PATH)) { fs.copyFileSync(this.MODEL_CONFIG_PATH, tempModelConfigPath) } - - - // 如果 provider_models 目录存在,备份整个目录
224-231: Remove unnecessary empty lines for consistency.// 导入模型配置文件 if (fs.existsSync(modelConfigBackupPath)) { fs.copyFileSync(modelConfigBackupPath, this.MODEL_CONFIG_PATH) } - - - eventBus.send(SYNC_EVENTS.IMPORT_COMPLETED, SendTarget.ALL_WINDOWS)
256-262: Remove unnecessary empty lines for consistency.// 恢复模型配置文件 if (fs.existsSync(tempModelConfigPath)) { fs.copyFileSync(tempModelConfigPath, this.MODEL_CONFIG_PATH) } - - - eventBus.send(SYNC_EVENTS.IMPORT_ERROR, SendTarget.ALL_WINDOWS, (error as Error).message || 'sync.error.unknown')
334-336: Remove unnecessary empty line.const finalMcpSettingsBackupPath = path.join(syncFolderPath, 'mcp-settings.json') const finalModelConfigBackupPath = path.join(syncFolderPath, 'model-config.json') - // 确保数据库文件存在
370-382: Fix formatting issues.Remove unnecessary empty lines and maintain consistent formatting.
} - // 备份 MCP 设置 if (fs.existsSync(this.MCP_SETTINGS_PATH)) { fs.copyFileSync(this.MCP_SETTINGS_PATH, tempMcpSettingsBackupPath) } - // 备份模型配置文件 if (fs.existsSync(this.MODEL_CONFIG_PATH)) { fs.copyFileSync(this.MODEL_CONFIG_PATH, tempModelConfigBackupPath) } - - - // 备份 provider_models 目录
399-403: Remove unnecessary empty line.if (!fs.existsSync(tempAppSettingsBackupPath)) { throw new Error('sync.error.tempConfigFailed') } - if (!fs.existsSync(tempMcpSettingsBackupPath)) { throw new Error('sync.error.tempMcpSettingsFailed') }
422-436: Fix comment indentation and remove empty lines.The comment indentation is incorrect and there are unnecessary empty lines.
} - // 清理之前的模型配置文件备份 + // 清理之前的模型配置文件备份 if (fs.existsSync(finalModelConfigBackupPath)) { fs.unlinkSync(finalModelConfigBackupPath) } - // 确保临时文件存在后再执行重命名 fs.renameSync(tempDbBackupPath, finalDbBackupPath) fs.renameSync(tempAppSettingsBackupPath, finalAppSettingsBackupPath) fs.renameSync(tempMcpSettingsBackupPath, finalMcpSettingsBackupPath) - - // 重命名模型配置文件 + // 重命名模型配置文件 if (fs.existsSync(tempModelConfigBackupPath)) { fs.renameSync(tempModelConfigBackupPath, finalModelConfigBackupPath) } - // 重命名 provider_models 临时目录src/renderer/src/components/settings/ModelConfigDialog.vue (3)
13-31: Consider making max token limits configurable per model.The hardcoded maximum value of 1,000,000 tokens may not be appropriate for all models. Some models support much higher limits (e.g., 100M tokens for certain context windows), while others have lower limits.
Consider deriving these limits from the model's actual capabilities or making them configurable per provider/model.
217-226: Consider loading model-specific defaults.The hardcoded default values may not be appropriate for all models. Different models have different optimal defaults (e.g., embedding models don't need high maxTokens).
Consider initializing these values based on the model type or loading them from the model's default configuration:
// 配置数据 -const config = ref<ModelConfig>({ - maxTokens: 4096, - contextLength: 8192, - temperature: 0.7, - vision: false, - functionCall: false, - reasoning: false, - type: ModelType.Chat -}) +const config = ref<ModelConfig>({ + maxTokens: 0, + contextLength: 0, + temperature: 0, + vision: false, + functionCall: false, + reasoning: false, + type: ModelType.Chat +}) + +// Load defaults in loadConfig() based on model type
308-319: Potential duplicate config loading.The watch with
immediate: trueand theonMountedhook both callloadConfig()when the dialog opens, which could cause redundant API calls.// 监听props变化,重新加载配置 watch(() => [props.modelId, props.providerId, props.open], () => { if (props.open) { loadConfig() } -}, { immediate: true }) +}) onMounted(() => { if (props.open) { loadConfig() } })test/main/presenter/modelConfig.test.ts (1)
197-198: Remove debug console.log statements.Debug logging should be removed from test files.
- console.log('Default config maxTokens:', defaultConfig.maxTokens) - console.log('Provider config maxTokens:', providerConfig.maxTokens)src/renderer/src/stores/settings.ts (1)
1391-1409: Good implementation of model config methods. Remove empty lines.The model configuration methods are well-implemented and properly refresh model data after changes.
const resetModelConfig = async (modelId: string, providerId: string): Promise<void> => { await configP.resetModelConfig(modelId, providerId) // 配置重置后刷新相关模型数据 await refreshProviderModels(providerId) } - - - return {src/main/presenter/configPresenter/modelConfig.ts (1)
13-13: Consider using a more unique delimiter to avoid potential conflictsThe delimiter
-_-could potentially exist in provider or model IDs. Consider using a more unique separator like::or|:|that is less likely to appear in IDs.-const SPECIAL_CONCAT_CHAR = '-_-' +const SPECIAL_CONCAT_CHAR = '|:|'
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (26)
.cursor/rules/build-deploy.mdc(0 hunks).cursor/rules/development-setup.mdc(1 hunks)docs/config-presenter-design.md(0 hunks)src/main/events.ts(1 hunks)src/main/presenter/configPresenter/index.ts(6 hunks)src/main/presenter/configPresenter/modelConfig.ts(1 hunks)src/main/presenter/syncPresenter/index.ts(11 hunks)src/renderer/src/components/settings/ModelConfigDialog.vue(1 hunks)src/renderer/src/components/settings/ModelConfigItem.vue(3 hunks)src/renderer/src/components/settings/ModelProviderSettingsDetail.vue(2 hunks)src/renderer/src/components/settings/ProviderModelList.vue(4 hunks)src/renderer/src/components/settings/ProviderModelManager.vue(2 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/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/renderer/src/stores/settings.ts(4 hunks)src/renderer/src/views/WelcomeView.vue(1 hunks)src/shared/model.ts(1 hunks)src/shared/presenter.d.ts(2 hunks)test/main/presenter/modelConfig.test.ts(1 hunks)
💤 Files with no reviewable changes (2)
- .cursor/rules/build-deploy.mdc
- docs/config-presenter-design.md
🧰 Additional context used
🧬 Code Graph Analysis (1)
src/main/presenter/configPresenter/modelConfig.ts (3)
src/shared/presenter.d.ts (1)
ModelConfig(120-128)src/main/presenter/configPresenter/providerModelSettings.ts (1)
getProviderSpecificModelConfig(1115-1146)src/main/presenter/configPresenter/modelDefaultSettings.ts (1)
defaultModelsSettings(3-1669)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (20)
.cursor/rules/development-setup.mdc (1)
4-4: ClarifyalwaysApplyscope
Theglobs:list is currently empty, so turning onalwaysApply: truemay either match all files or none, depending on the engine’s defaults. Please specify the intended file patterns underglobs:or confirm that a global application is desired.src/main/events.ts (1)
27-30: Event-key naming fits conventions – ensure counterpart wiring existsThe new constants follow the existing
config:*naming style and look collision-free.
Just double-check that renderer processes (and any IPC listeners) have matching handlers, otherwise the events will never be observed.src/renderer/src/views/WelcomeView.vue (1)
366-367: Prop binding is correct — good use of template ref unwrappingPassing
:provider-id="selectedProvider"cleanly supplies context to eachModelConfigItem. No issues spotted.src/renderer/src/components/settings/ModelProviderSettingsDetail.vue (1)
41-42: Bubble-up listener added — OKListening for
config-changedand delegating to a local handler plugs the new config workflow into this view.src/renderer/src/components/settings/ProviderModelManager.vue (3)
39-40: Prop passthrough verifiedForwarding
provider.idensures downstream items know which provider they belong to.
47-48: Event forwarding keeps parent in syncRe-emitting
config-changedupward is the right move and keeps component boundaries thin.
74-75: Emit declaration updated — goodAdding
'config-changed'todefineEmitsavoids TS complaints and documents the contract.src/renderer/src/components/settings/ProviderModelList.vue (2)
14-24: Propagatingprovider-idandconfig-changedlooks correct – verify downstream usage.Passing the new
provider-idprop and re-emittingconfig-changedwill only work if
ModelConfigItem.vuedeclares the prop and the event exactly as used here.
Please double-check its prop name / casing and the emitted event string to prevent
runtime warnings such as “extraneous non-prop attributes” or “event not declared”.
161-164:defineEmitssignature is type-safe – LGTM.Literal key
'config-changed'keeps TS happy and prevents typos. No issues spotted.src/renderer/src/i18n/ja-JP/settings.json (1)
103-160: Localization additions look goodAll new keys follow the existing naming pattern and placeholders (
{name}etc.) are preserved. Nice work keeping the Japanese copy concise and consistent.src/renderer/src/i18n/zh-CN/settings.json (1)
103-160: Strings are consistent & completeNo placeholder or punctuation inconsistencies spotted. 👍
src/renderer/src/i18n/fr-FR/settings.json (1)
103-160: French translations LGTMKeys mirror the English reference and diacritics / plural forms look correct.
src/renderer/src/i18n/en-US/settings.json (1)
124-126: Avoid embedded newline in translation string
\\ninside JSON may render as literal\nin some UI libraries. Prefer\\n\\n(double newline) or split string into two i18n entries and handle line-break in the template.src/main/presenter/syncPresenter/index.ts (1)
28-28: LGTM!The
MODEL_CONFIG_PATHdeclaration follows the established pattern for other configuration file paths.src/renderer/src/i18n/ko-KR/settings.json (1)
103-160: LGTM!The Korean translations for the model configuration UI are comprehensive and well-structured, covering all necessary labels, descriptions, validation messages, and UI elements.
test/main/presenter/modelConfig.test.ts (1)
6-52: Well-implemented mock for electron-store.The in-memory mock correctly simulates electron-store behavior and properly isolates tests from file system dependencies.
src/renderer/src/stores/settings.ts (1)
336-348: Good optimization with batch status fetching.The implementation efficiently fetches all model statuses in a single call and properly handles the empty array case.
src/main/presenter/configPresenter/index.ts (3)
310-320: Good optimization with batch status retrievalThe implementation of
getBatchModelStatusprovides an efficient way to retrieve multiple model statuses in a single operation, avoiding repeated method calls.
411-413: Excellent use of batch retrieval for performanceGreat job using the new
getBatchModelStatusmethod to optimize thegetAllEnabledModelsmethod. This reduces the number of individual status lookups significantly.
822-826:Details
✅ Verification successful
Verify that MODEL_CONFIG_CHANGED event is defined
The code emits a
MODEL_CONFIG_CHANGEDevent. Please ensure this event constant is properly defined in the events file.
🏁 Script executed:
#!/bin/bash # Check if MODEL_CONFIG_CHANGED is defined in events.ts rg "MODEL_CONFIG_CHANGED" src/main/events.ts -A 2 -B 2Length of output: 380
No action needed:
MODEL_CONFIG_CHANGEDis definedA quick search confirms that
MODEL_CONFIG_CHANGEDis declared insrc/main/events.ts:// 模型配置相关事件 MODEL_CONFIG_CHANGED: 'config:model-config-changed', // 模型配置变更事件
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: 1
🔭 Outside diff range comments (1)
src/main/presenter/llmProviderPresenter/providers/siliconcloudProvider.ts (1)
123-129: 🛠️ Refactor suggestion
parseFloatmay yieldNaN, bypassing the exhausted-quota guardIf
totalBalanceis"--"or any non-numeric string,parseFloatreturnsNaN.
Later you compare with<= 0, butNaN <= 0isfalse, so an unusable key would be treated as valid. Consider guarding forNumber.isNaN:const totalBalance = parseFloat(keyResponse.data.totalBalance) -if (keyStatus.remainNum !== undefined && keyStatus.remainNum <= 0) { +if ( + keyStatus.remainNum === undefined || + Number.isNaN(keyStatus.remainNum) || + keyStatus.remainNum <= 0 +) {This prevents silent acceptance of malformed balances.
♻️ Duplicate comments (1)
src/main/presenter/configPresenter/index.ts (1)
859-896: 🛠️ Refactor suggestionReplace
anywith the correct interface (issue previously raised)The return/parameter types still use
Record<string, any>despite earlier feedback.
Switch toRecord<string, IModelConfig>(orModelConfig) to regain type safety.-importModelConfigs(configs: Record<string, any>, overwrite: boolean = false): void { +importModelConfigs(configs: Record<string, IModelConfig>, overwrite: boolean = false): void { -exportModelConfigs(): Record<string, any> { +exportModelConfigs(): Record<string, IModelConfig> { -getAllModelConfigs(): Record<string, any> { +getAllModelConfigs(): Record<string, IModelConfig> {Remember to:
import { IModelConfig } from './modelConfig'(or from the correct module).- Update
ModelConfigHelperAPI signatures accordingly.This change prevents accidental misuse and improves autocompletion in consumers.
🧹 Nitpick comments (10)
src/main/presenter/llmProviderPresenter/providers/siliconcloudProvider.ts (2)
105-107: Keep header-key quoting consistent & drop redundantContent-Typeon GETMixing quoted and unquoted object keys is perfectly legal, but it creates an inconsistent style within the same literal (
Authorizationis now unquoted whileContent-Typeremains quoted). Either quote both or neither to avoid diff-noise in future style passes.Additionally,
Content-Type: application/jsonis unnecessary on aGETrequest with no body—some servers even treat it as a hint that a body is coming. Consider removing it altogether:- headers: { - Authorization: `Bearer ${this.provider.apiKey}`, - 'Content-Type': 'application/json' - } + headers: { + Authorization: `Bearer ${this.provider.apiKey}` + }
112-114: Multi-line template string embeds hard newlines in the error messageThe new formatting improves readability in code, but it injects
\ncharacters into the thrown string, producing a multi-line error that can be awkward in logs or UI surfaces.
If single-line output is preferred, wrap the template or join parts explicitly:- throw new Error( - `SiliconCloud API key check failed: ${response.status} ${response.statusText} - ${errorText}` - ) + throw new Error( + `SiliconCloud API key check failed: ${response.status} ${response.statusText} - ${errorText}` + )(or use
[].join(' ')).Purely stylistic—feel free to keep as-is if multi-line output is desired.
src/main/presenter/llmProviderPresenter/providers/ppioProvider.ts (1)
87-90: Consider formatting the currency amount for readability
'¥' + keyResponse.credit_balance / 10000returns long floating-point values such as¥123.456789. A small formatting tweak improves UX:-const remaining = '¥' + keyResponse.credit_balance / 10000 +const remaining = `¥${(keyResponse.credit_balance / 10000).toFixed(2)}`If fractions of a cent matter, adjust precision accordingly.
test/main/presenter/llmProviderPresenter.test.ts (1)
403-448: Concurrent-stream test still runs streams sequentiallyThe loop awaits each generator before moving to the next, so at most one stream is active.
To exercise the concurrency limiter, start the handlers without awaiting them andawait Promise.alllater:- for (const { eventId, stream } of streams) { - try { - let count = 0 - for await (const event of stream) { - ... - } - } catch (error) { - // 预期的错误 - } - } + await Promise.all( + streams.map(async ({ eventId, stream }) => { + try { + let count = 0 + for await (const event of stream) { + ... + if (count >= 2) { + await llmProviderPresenter.stopStream(eventId) + break + } + } + } catch { + /* expected */ + } + }) + )This keeps the three streams truly concurrent, giving the limiter a chance to reject the third one.
src/main/presenter/configPresenter/index.ts (2)
310-320:getBatchModelStatusdoes unnecessary store look-ups; consider bulk accessThe method loops over
modelIdsand callsthis.getSettingfor every single model key.
BecauseElectronStorepersists data synchronously, this results in as many synchronous disk reads as there are models. Fetching all keys once (e.g.this.store.store) and resolving the status in memory would reduce I/O overhead, especially for providers that expose dozens of models.- for (const modelId of modelIds) { - const statusKey = this.getModelStatusKey(providerId, modelId) - const status = this.getSetting<boolean>(statusKey) - result[modelId] = typeof status === 'boolean' ? status : true - } + const cache = this.store.store // in-memory snapshot + for (const modelId of modelIds) { + const statusKey = this.getModelStatusKey(providerId, modelId) + const raw = cache[statusKey] as unknown + result[modelId] = typeof raw === 'boolean' ? raw : true + }
417-424: Minor: keepmodelStatusMapcreation outsidemapcallback
getAllEnabledModelsassembles amodelIdsarray only to callgetBatchModelStatus, which in turn rebuilds the keys.
Pre-computing the map once per provider is fine, but placing it outside themapcallback would avoid creating a large temporary array (modelIds) altogether.test/main/eventbus/eventbus.test.ts (1)
186-188: Prefer fake timers oversetTimeoutfor faster, deterministic testsUsing real timers (
await new Promise((resolve) => setTimeout(resolve, 0))) slows the suite and can introduce flakiness on CI.
Switching to Vitest’s fake-timer utilities makes the flush instant and deterministic:-beforeEach(() => { - vi.useFakeTimers() -}) - -// … -await new Promise((resolve) => setTimeout(resolve, 0)) +await vi.runOnlyPendingTimersAsync()Remember to pair
vi.useFakeTimers()in the relevantbeforeEach/afterEach.Also applies to: 200-202, 214-216, 281-283, 302-304, 319-321
test/main/presenter/modelConfig.test.ts (3)
197-199: Remove noisyconsole.logstatements from testsThese logs clutter CI output and offer no assertion value.
Simply delete them or convert to comments.- console.log('Default config maxTokens:', defaultConfig.maxTokens) - console.log('Provider config maxTokens:', providerConfig.maxTokens)
118-127: Hard-coding default numbers couples tests to implementation detailsAsserting exact defaults (
4096,8192, etc.) makes the suite brittle when defaults legitimately change.
Prefer semantic checks:- expect(defaultConfig).toEqual({ - maxTokens: 4096, - contextLength: 8192, - … - }) + expect(defaultConfig.maxTokens).toBeGreaterThan(0) + expect(defaultConfig.contextLength).toBeGreaterThan(defaultConfig.maxTokens) + // retain specific assertions only when they convey behaviour rather than constants
60-67:{ ...value }is a shallow copy – consider deep-cloning for safetyIf any stored config objects gain nested structures, mutations inside a test could leak to other tests despite the copy.
UsingstructuredClone(Node 18+) orJSON.parse(JSON.stringify(value))ensures isolation.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (40)
.prettierignore(1 hunks)src/main/presenter/configPresenter/index.ts(6 hunks)src/main/presenter/configPresenter/modelConfig.ts(1 hunks)src/main/presenter/llmProviderPresenter/index.ts(2 hunks)src/main/presenter/llmProviderPresenter/oauthHelper.ts(1 hunks)src/main/presenter/llmProviderPresenter/providers/anthropicProvider.ts(3 hunks)src/main/presenter/llmProviderPresenter/providers/deepseekProvider.ts(2 hunks)src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts(0 hunks)src/main/presenter/llmProviderPresenter/providers/openAIResponsesProvider.ts(1 hunks)src/main/presenter/llmProviderPresenter/providers/openRouterProvider.ts(4 hunks)src/main/presenter/llmProviderPresenter/providers/ppioProvider.ts(1 hunks)src/main/presenter/llmProviderPresenter/providers/siliconcloudProvider.ts(1 hunks)src/main/presenter/mcpPresenter/inMemoryServers/customPromptsServer.ts(1 hunks)src/main/presenter/mcpPresenter/index.ts(1 hunks)src/main/presenter/mcpPresenter/mcpClient.ts(1 hunks)src/main/presenter/notifactionPresenter.ts(1 hunks)src/main/presenter/shortcutPresenter.ts(1 hunks)src/main/presenter/syncPresenter/index.ts(13 hunks)src/main/presenter/tabPresenter.ts(1 hunks)src/main/presenter/upgradePresenter/index.ts(4 hunks)src/main/presenter/windowPresenter/index.ts(0 hunks)src/renderer/src/assets/style.css(2 hunks)src/renderer/src/components/editor/mention/MentionList.vue(4 hunks)src/renderer/src/components/editor/mention/PromptParamsDialog.vue(1 hunks)src/renderer/src/components/editor/mention/suggestion.ts(1 hunks)src/renderer/src/components/settings/ModelConfigDialog.vue(1 hunks)src/renderer/src/components/settings/PromptSetting.vue(7 hunks)src/renderer/src/components/settings/ProviderApiConfig.vue(3 hunks)src/renderer/src/i18n/en-US/contextMenu.json(1 hunks)src/renderer/src/i18n/fr-FR/contextMenu.json(1 hunks)src/renderer/src/i18n/fr-FR/index.ts(1 hunks)src/renderer/src/i18n/ja-JP/contextMenu.json(1 hunks)src/renderer/src/i18n/ko-KR/contextMenu.json(1 hunks)src/renderer/src/i18n/zh-CN/contextMenu.json(1 hunks)src/renderer/src/i18n/zh-TW/contextMenu.json(1 hunks)src/renderer/src/stores/settings.ts(4 hunks)test/main/eventbus/eventbus.test.ts(12 hunks)test/main/presenter/llmProviderPresenter.test.ts(12 hunks)test/main/presenter/modelConfig.test.ts(1 hunks)test/setup.renderer.ts(1 hunks)
💤 Files with no reviewable changes (2)
- src/main/presenter/windowPresenter/index.ts
- src/main/presenter/llmProviderPresenter/providers/githubCopilotProvider.ts
✅ Files skipped from review due to trivial changes (27)
- src/renderer/src/i18n/zh-TW/contextMenu.json
- src/main/presenter/shortcutPresenter.ts
- src/renderer/src/i18n/en-US/contextMenu.json
- src/renderer/src/i18n/ko-KR/contextMenu.json
- src/renderer/src/i18n/fr-FR/contextMenu.json
- src/renderer/src/i18n/ja-JP/contextMenu.json
- test/setup.renderer.ts
- src/renderer/src/i18n/zh-CN/contextMenu.json
- src/renderer/src/components/editor/mention/PromptParamsDialog.vue
- src/main/presenter/notifactionPresenter.ts
- src/main/presenter/llmProviderPresenter/oauthHelper.ts
- src/renderer/src/components/editor/mention/suggestion.ts
- src/renderer/src/i18n/fr-FR/index.ts
- src/main/presenter/llmProviderPresenter/providers/openAIResponsesProvider.ts
- src/main/presenter/mcpPresenter/mcpClient.ts
- src/main/presenter/mcpPresenter/inMemoryServers/customPromptsServer.ts
- src/main/presenter/llmProviderPresenter/providers/deepseekProvider.ts
- src/renderer/src/assets/style.css
- src/main/presenter/mcpPresenter/index.ts
- src/renderer/src/components/editor/mention/MentionList.vue
- src/renderer/src/components/settings/ProviderApiConfig.vue
- .prettierignore
- src/main/presenter/upgradePresenter/index.ts
- src/main/presenter/llmProviderPresenter/index.ts
- src/renderer/src/components/settings/PromptSetting.vue
- src/main/presenter/llmProviderPresenter/providers/openRouterProvider.ts
- src/main/presenter/llmProviderPresenter/providers/anthropicProvider.ts
🚧 Files skipped from review as they are similar to previous changes (4)
- src/renderer/src/components/settings/ModelConfigDialog.vue
- src/main/presenter/configPresenter/modelConfig.ts
- src/main/presenter/syncPresenter/index.ts
- src/renderer/src/stores/settings.ts
🧰 Additional context used
🧬 Code Graph Analysis (2)
src/main/presenter/tabPresenter.ts (2)
src/main/eventbus.ts (1)
eventBus(151-151)src/main/events.ts (1)
WINDOW_EVENTS(67-85)
test/main/presenter/llmProviderPresenter.test.ts (3)
src/main/presenter/configPresenter/index.ts (1)
ConfigPresenter(72-1018)src/main/presenter/llmProviderPresenter/index.ts (1)
LLMProviderPresenter(50-1051)src/shared/presenter.d.ts (2)
ChatMessage(1057-1069)LLMAgentEvent(1105-1108)
🔇 Additional comments (2)
src/main/presenter/tabPresenter.ts (1)
54-56: Change is purely stylistic – good to mergeOnly splits the inline handler into multiple lines; no functional impact.
test/main/eventbus/eventbus.test.ts (1)
71-71: Assertions look goodThe argument ordering and expectations accurately reflect the API contract after the formatting tweaks. No further action required.
Also applies to: 99-100, 108-109, 117-118, 152-153, 161-162
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: 0
🧹 Nitpick comments (2)
.cursor/rules/development-setup.mdc (2)
7-11: Add quick install hints for OxLint & pnpmThe list states the required tools/versions but omits how to get them. A one-liner per item improves first-time onboarding, e.g.:
- 使用 OxLint 进行代码检查(`npm i -g @oxlint/cli`) - 使用 pnpm 包管理(启用 corepack: `corepack enable`,然后 `corepack prepare pnpm@9 --activate`)This tiny addition saves contributors a round-trip to external docs.
13-26: Group dev commands in a fenced block & include testsInline back-ticked commands are harder to copy en masse. Present them as a single shell block and add the missing test script for completeness:
```bash pnpm install # install deps pnpm lint # lint with OxLint pnpm format # run Prettier pnpm dev # start electron/vue dev server pnpm test # run unit & e2e tests pnpm build # build production bundlesMakes the section copy-paste friendly and surfaces the testing workflow. </blockquote></details> </blockquote></details> <details> <summary>📜 Review details</summary> **Configuration used: CodeRabbit UI** **Review profile: CHILL** **Plan: Pro** <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between f4cc34b6b2d1e1315543bb1261b518e3731be580 and 438fd3d3186be15d358c0e9edbff10c564b49714. </details> <details> <summary>📒 Files selected for processing (5)</summary> * `.cursor/rules/development-setup.mdc` (1 hunks) * `src/main/presenter/configPresenter/index.ts` (7 hunks) * `src/main/presenter/configPresenter/modelConfig.ts` (1 hunks) * `src/renderer/src/components/settings/ModelConfigDialog.vue` (1 hunks) * `src/shared/presenter.d.ts` (3 hunks) </details> <details> <summary>🚧 Files skipped from review as they are similar to previous changes (4)</summary> * src/renderer/src/components/settings/ModelConfigDialog.vue * src/main/presenter/configPresenter/modelConfig.ts * src/main/presenter/configPresenter/index.ts * src/shared/presenter.d.ts </details> <details> <summary>🔇 Additional comments (1)</summary><blockquote> <details> <summary>.cursor/rules/development-setup.mdc (1)</summary> `4-4`: **Confirm `alwaysApply: true` is intentional** Setting `alwaysApply` to `true` forces this rule on every project clone, including forks and CI jobs. Double-check that such global scope is desired; otherwise keep it `false` and let teams opt-in. </details> </blockquote></details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
Pull Request Description (中文)
你的功能请求是否与某个问题有关?请描述一下。
请描述你希望的解决方案
桌面应用程序的 UI/UX 更改


Summary by CodeRabbit
New Features
Improvements
Documentation
Tests