-
Notifications
You must be signed in to change notification settings - Fork 614
feat(ollama): support custom providers #1046
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
WalkthroughRefactors Ollama-related APIs to be provider-scoped by adding a required Changes
Sequence Diagram(s)sequenceDiagram
participant UI as Renderer UI / Component
participant Store as Settings Store
participant Presenter as LlmProviderPresenter
participant Provider as Provider Instance (Ollama)
UI->>Store: request refresh/pull (providerId, modelName)
Store->>Presenter: call refreshOllamaModels(providerId) / pullOllamaModel(providerId, modelName)
Presenter->>Presenter: getOllamaProviderInstance(providerId)
Presenter->>Provider: perform list/pull/show actions
Provider-->>Presenter: results / emit PULL_MODEL_PROGRESS(providerId, modelName, progress)
Presenter->>Store: forward events/results (providerId-scoped)
Store->>UI: update reactive per-provider state (running/local/pulling)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 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 |
|
@codex review |
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (9)
src/renderer/src/views/WelcomeView.vue (3)
292-299: Use apiType, not provider ID, to control API-key visibility and URL hint
v-if="selectedProvider !== 'gemini'"andv-show="selectedProvider !== 'ollama'"compare IDs, breaking for custom providers (IDs won’t equal'ollama'/'gemini'). Derive booleans from the selected provider’sapiType.- <div v-if="selectedProvider !== 'gemini'" class="text-xs text-muted-foreground"> + <div v-if="isOpenAICompatible" class="text-xs text-muted-foreground"> {{ `${baseUrl ?? ''}/chat/completions` }} </div> - <div v-show="selectedProvider !== 'ollama'" class="flex flex-col gap-2"> + <div v-show="!isOllamaApi" class="flex flex-col gap-2">And add:
+const currentProvider = computed(() => + settingsStore.providers.find(p => p.id === selectedProvider.value) +) +const isOllamaApi = computed(() => currentProvider.value?.apiType === 'ollama') +const isOpenAICompatible = computed(() => + ['openai', 'openai-compatible', 'openai-responses'].includes(currentProvider.value?.apiType ?? '') +)As per coding guidelines.
167-175: Guard router push when no models are available to prevent runtime crash
providerModels.value[0]may beundefined(e.g., failed fetch). Add a safe fallback.- router.push({ - name: 'chat', - query: { modelId: providerModels.value[0].id, providerId: selectedProvider.value } - }) + const firstModel = providerModels.value[0] + if (!firstModel) { + showErrorDialog.value = true + dialogMessage.value = t('settings.provider.dialog.verify.missingModels') + return + } + router.push({ name: 'chat', query: { modelId: firstModel.id, providerId: selectedProvider.value } })
265-268: Replace hardcoded user-visible strings with i18n keys
- Select placeholder, API URL/API Key placeholders, and “同步模型失败...” should use
t(...)per renderer i18n rules.Example:
- <SelectValue placeholder="Select a provider" /> + <SelectValue :placeholder="t('welcome.provider.selectPlaceholder')" /> - <Input id="api-url" v-model="baseUrl" placeholder="Enter API URL" /> + <Input id="api-url" v-model="baseUrl" :placeholder="t('welcome.provider.apiUrlPlaceholder')" /> - placeholder="Enter API Key" + :placeholder="t('welcome.provider.apiKeyPlaceholder')" - <div v-if="!providerModelLoading && providerModels.length <= 0">同步模型失败...</div> + <div v-if="!providerModelLoading && providerModels.length <= 0"> + {{ t('welcome.provider.syncModelsFailed') }} + </div>As per coding guidelines.
Also applies to: 292-293, 305-306, 381-381
src/shared/types/presenters/legacy.presenters.d.ts (1)
1119-1121: Fix typo in TypeScript type definition
env: Record<string, unknow>contains an invalid type. Changeunknowtounknown.- env: Record<string, unknow> + env: Record<string, unknown>src/renderer/settings/components/OllamaProviderSettingsDetail.vue (1)
916-934: Replace Chinese console logs with English messagesLines 919 and 925 contain Chinese console logs ('验证成功', '验证失败') that violate the coding guideline requiring English for all logs and comments in renderer files. Update to English equivalents:
console.log('Validation successful') console.log('Validation failed', resp.errorMsg)src/main/presenter/llmProviderPresenter/index.ts (1)
1647-1686: I need to examine how callers actually handle the return values and error cases to understand the impact of this inconsistency.Now let me examine the actual call site behavior in settings.ts to confirm the inconsistency is problematic:
Make error handling consistent across Ollama methods
The review is correct. Currently
listOllamaModelsandlistOllamaRunningModelsreturn empty arrays on missing provider, whileshowOllamaModelInfoandpullOllamaModelsthrow errors. This inconsistency is problematic because:
- Promise.all() immediately rejects when any promise rejects, so callers using
Promise.all()(as in settings.ts lines 1261-1262) cannot uniformly handle missing providers- The two patterns prevent consistent error handling—some failures silently return
[]while others trigger catch blocks- Per coding guidelines, error-prone operations should uniformly throw, not mix return-empty-array patterns with exceptions
Change all four methods to throw on missing provider:
listOllamaModels(providerId: string): Promise<OllamaModel[]> { const provider = this.getOllamaProviderInstance(providerId) if (!provider) { - return Promise.resolve([]) + throw new Error('Ollama provider not found') } return provider.listModels() } listOllamaRunningModels(providerId: string): Promise<OllamaModel[]> { const provider = this.getOllamaProviderInstance(providerId) if (!provider) { - return Promise.resolve([]) + throw new Error('Ollama provider not found') } return provider.listRunningModels() }src/shared/types/presenters/llmprovider.presenter.d.ts (1)
93-113: Type collision: OllamaModel is defined in two places with different shapesThis file declares
OllamaModel, butsrc/shared/types/presenters/legacy.presenters.d.tsalso exports anOllamaModel(different fields likemodel,capabilities,modified_at: Date | string). Barrel@shared/presenterlikely re-exports one/both, causing ambiguity and unsafe casts downstream (renderer casts toanyforcapabilities). Unify to a single canonical type or rename one to avoid collisions.Suggested direction:
- Rename this interface to
OllamaShowModel(orOllamaModelCore) and update method signatures to use it.- Or re-export the legacy one and extend via intersection for optional show fields.
I can prep a minimal refactor if you confirm the intended canonical shape.
src/renderer/src/stores/settings.ts (2)
1274-1391: Type mismatch: writing unknown propertyproviderto RENDERER_MODEL_META
RENDERER_MODEL_METAin shared types doesn’t includeprovider, onlyproviderId. Two places assignprovider: providerId, which will fail excess property checks under strict TS.Fix by removing
providerassignments:@@ refreshStandardModels(...) - provider: providerId, group: meta.group || 'default', @@ syncOllamaModelsToGlobal(...) - provider: providerId, group: existingModel?.group || 'local',Additionally, consider consolidating capability detection to avoid repeated
as any(optional).
374-374: Duplicate listener registration: setupProviderListener called twice
setupProviderListener()is called ininitSettings()and again inonMounted(), causing duplicated IPC listeners and repeated work. Call it only once.- setupProviderListener() + // setupProviderListener() is invoked in onMounted; avoid double registration
🧹 Nitpick comments (4)
src/renderer/settings/components/AddCustomProviderDialog.vue (2)
39-40: Conditional API-key requirement and ollama-specific defaults look good
:required="formData.apiType !== 'ollama'"is correct.- Auto-filling
baseUrland clearingapiKeywhen switching to/from Ollama is sensible.Optional: prefer
http://127.0.0.1:11434to avoid potential IPv6/hosts issues.Also applies to: 57-58, 178-190
152-169: Translate comments/logs to EnglishComments are in Chinese. Project rule: logs/comments in English. Please update for consistency. As per coding guidelines.
Also applies to: 170-176
src/shared/types/presenters/legacy.presenters.d.ts (1)
1085-1107: Two differentOllamaModelinterfaces exist across shared d.ts filesThis file’s
OllamaModeldiffers fromsrc/shared/types/presenters/llmprovider.presenter.d.ts. Consider consolidating or aliasing to avoid confusion and accidental misuse.src/renderer/src/stores/settings.ts (1)
1108-1124: Minor: order of cleanup vs refreshYou refresh all models then clear Ollama maps for the removed provider. Clearing first slightly reduces transient work; current order is functionally fine.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
src/main/presenter/llmProviderPresenter/index.ts(2 hunks)src/renderer/settings/components/AddCustomProviderDialog.vue(3 hunks)src/renderer/settings/components/OllamaProviderSettingsDetail.vue(6 hunks)src/renderer/src/stores/settings.ts(15 hunks)src/renderer/src/views/WelcomeView.vue(1 hunks)src/shared/types/presenters/legacy.presenters.d.ts(1 hunks)src/shared/types/presenters/llmprovider.presenter.d.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (26)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/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/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/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.tssrc/shared/types/presenters/llmprovider.presenter.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/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/index.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/renderer/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/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.tssrc/shared/types/presenters/llmprovider.presenter.d.ts
src/shared/**
📄 CodeRabbit inference engine (AGENTS.md)
Put shared TypeScript types and utilities under src/shared
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/renderer/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/index.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/renderer/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/index.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
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/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
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/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/settings/components/OllamaProviderSettingsDetail.vuesrc/renderer/settings/components/AddCustomProviderDialog.vuesrc/renderer/src/views/WelcomeView.vue
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/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
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/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
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/views/WelcomeView.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/views/WelcomeView.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/views/WelcomeView.vuesrc/renderer/src/stores/settings.ts
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/views/WelcomeView.vuesrc/renderer/src/stores/settings.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/renderer/src/stores/settings.tssrc/main/presenter/llmProviderPresenter/index.ts
src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/pinia-best-practices.mdc)
src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx}: Use modules to organize related state and actions
Implement proper state persistence for maintaining data across sessions
Use getters for computed state properties
Utilize actions for side effects and asynchronous operations
Keep the store focused on global state, not component-specific data
Files:
src/renderer/src/stores/settings.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/llmProviderPresenter/index.ts
src/main/presenter/llmProviderPresenter/index.ts
📄 CodeRabbit inference engine (.cursor/rules/llm-agent-loop.mdc)
src/main/presenter/llmProviderPresenter/index.ts:src/main/presenter/llmProviderPresenter/index.tsshould manage the overall Agent loop, conversation history, tool execution viaMcpPresenter, and frontend communication viaeventBus.
The main Agent loop inllmProviderPresenter/index.tsshould handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop withneedContinueConversationandtoolCallCount.
The main Agent loop should send standardizedSTREAM_EVENTS(RESPONSE,END,ERROR) to the frontend viaeventBus.
The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Files:
src/main/presenter/llmProviderPresenter/index.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/llmProviderPresenter/index.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/llmProviderPresenter/index.ts
🧠 Learnings (7)
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 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/llmProviderPresenter/providers/*.ts : New LLM providers must be added under src/main/presenter/llmProviderPresenter/providers/ as separate files
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/LLMProvider/**/*.ts : Implement the two-layer LLM provider (Agent Loop + Provider) under src/main/presenter/LLMProvider
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2025-09-04T11:03:30.184Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/provider-guidelines.mdc:0-0
Timestamp: 2025-09-04T11:03:30.184Z
Learning: Integrate via the llmProviderPresenter entry point (src/main/presenter/llmProviderPresenter/index.ts) as the related implementation entry
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : All provider implementations must parse provider-specific data chunks and yield standardized events for text, reasoning, tool calls, usage, errors, stop reasons, and image data.
Applied to files:
src/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.
Applied to files:
src/shared/types/presenters/llmprovider.presenter.d.ts
🧬 Code graph analysis (4)
src/shared/types/presenters/legacy.presenters.d.ts (1)
src/shared/types/presenters/llmprovider.presenter.d.ts (1)
OllamaModel(93-113)
src/shared/types/presenters/llmprovider.presenter.d.ts (2)
src/shared/types/presenters/legacy.presenters.d.ts (1)
OllamaModel(1085-1107)src/shared/types/presenters/index.d.ts (1)
OllamaModel(17-17)
src/renderer/src/stores/settings.ts (2)
src/shared/types/presenters/legacy.presenters.d.ts (2)
OllamaModel(1085-1107)RENDERER_MODEL_META(550-564)src/shared/types/presenters/llmprovider.presenter.d.ts (2)
OllamaModel(93-113)RENDERER_MODEL_META(10-25)
src/main/presenter/llmProviderPresenter/index.ts (3)
src/main/presenter/llmProviderPresenter/providers/ollamaProvider.ts (1)
OllamaProvider(40-1186)src/shared/types/presenters/legacy.presenters.d.ts (1)
OllamaModel(1085-1107)src/shared/types/presenters/llmprovider.presenter.d.ts (1)
OllamaModel(93-113)
⏰ 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 (18)
src/main/presenter/llmProviderPresenter/index.ts (1)
1633-1644: Provider-scoped Ollama instance lookup looks goodType-guarding with
instanceof OllamaProviderand gracefulnullfallback is solid.src/renderer/src/views/WelcomeView.vue (1)
142-146: Correctly skip API key/base URL validation for OllamaUsing
provider.apiType === 'ollama'is the right gate.src/shared/types/presenters/legacy.presenters.d.ts (1)
688-692: Type signatures updated to provider-scoped: LGTMInterface now requires
providerIdfor all Ollama operations. Matches presenter changes.src/renderer/settings/components/OllamaProviderSettingsDetail.vue (1)
7-16: Provider-scoped Ollama store calls and delete dialog are on point
getOllamaRunningModels/getOllamaLocalModels/pullOllamaModel/refreshOllamaModelsnow all passprovider.id— correct for multi-provider.- Delete-provider flow with confirmation dialog looks clean.
Also applies to: 250-267, 307-315, 846-848, 852-855, 891-895, 940-947
src/shared/types/presenters/llmprovider.presenter.d.ts (1)
177-180: Interface update aligns with multi‑provider OllamaAdding
providerIdfirst in all Ollama methods is consistent with the PR direction. No issues.src/renderer/src/stores/settings.ts (13)
39-41: Good: provider‑scoped Ollama stateSwitching to
Record<providerId, ...>removes cross‑provider bleed and simplifies lookups.
367-369: Eager refresh for disabled Ollama providersIntent is clear and wrapped by
refreshOllamaModelstry/catch. Keep as is.If many Ollama providers are configured, consider deferring these calls until first use to reduce startup latency.
568-571: Ollama‑specific refresh path looks correctSpecial‑casing Ollama to use its dedicated fetch + custom models pipeline is appropriate.
676-676: Cleanup on provider removal
clearOllamaProviderDataon single‑provider change avoids stale progress/state.
678-685: Targeted refresh on Ollama provider updatesScoped refresh avoids full reloads. Looks good.
705-705: Batch removal: Ollama state cleanupGood catch to clear Ollama maps when a provider is removed.
707-713: Batch updates: provider‑type aware refreshPer‑provider branching for Ollama vs others is correct.
1194-1256: Accessor/mutator helpers for Ollama stateAPI surface is clear and cohesive.
1258-1271: Parallel fetch for running/local models + robust error loggingGood use of
Promise.alland scoped provider logs.
1412-1437: Progress handler is defensive and id‑scopedValidates
providerIdand computes progress safely; also handles 'manifest' edge to show activity.
1453-1459: Helper predicates per providerSimple, correct lookups against provider‑scoped maps.
1827-1835: Exporting provider‑scoped Ollama helpersGood to expose getters and cleanup for UI/state consumers.
1393-1409: Pull flow + progress tracking verifiedEvent wiring is correct. The main process presenter emits events with
eventId: 'pullOllamaModels'viaOLLAMA_EVENTS.PULL_MODEL_PROGRESS, matching the renderer's listener and handler filter. Flow is sound: optimistic progress initialization → presenter invocation → event-driven state updates on pull completion or failure.
| <div class="w-full h-full p-2 flex flex-col gap-2 overflow-y-auto"> | ||
| <div class="flex flex-col items-start p-2 gap-2"> | ||
| <div class="flex justify-between items-center w-full"> | ||
| <Label :for="`${provider.id}-url`" class="flex-1 cursor-pointer">API URL</Label> |
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.
Localize labels
“API URL” and “API Key” labels are hardcoded. Replace with i18n keys.
- <Label ...>API URL</Label>
+ <Label ...>{{ t('settings.provider.apiUrl') }}</Label>
- <Label ...>API Key</Label>
+ <Label ...>{{ t('settings.provider.apiKey') }}</Label>As per coding guidelines.
Also applies to: 35-35
🤖 Prompt for AI Agents
In src/renderer/settings/components/OllamaProviderSettingsDetail.vue around
lines 6 and 35, the labels "API URL" and "API Key" are hardcoded — replace them
with i18n keys (e.g. settings.apiUrl, settings.apiKey) by using the project's
i18n call in the template (so the Label text comes from $t('...')/t('...') per
project convention) and add corresponding entries to the locale JSON/YAML files;
ensure keys follow existing naming conventions and run a quick lint/compile to
verify the translations resolve.
|
Codex Review: Didn't find any major issues. Chef's kiss. ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
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
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/renderer/src/components/icons/ModelIcon.vue(3 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
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/components/icons/ModelIcon.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/icons/ModelIcon.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/icons/ModelIcon.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/icons/ModelIcon.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/icons/ModelIcon.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/icons/ModelIcon.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/icons/ModelIcon.vue
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/icons/ModelIcon.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/renderer/src/components/icons/ModelIcon.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/icons/ModelIcon.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/icons/ModelIcon.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/icons/ModelIcon.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/components/icons/ModelIcon.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/renderer/src/components/icons/ModelIcon.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/renderer/src/components/icons/ModelIcon.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/icons/ModelIcon.vue
⏰ 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 (3)
src/renderer/src/components/icons/ModelIcon.vue (3)
3-3: LGTM! Store import added appropriately.The settings store import is necessary to access provider data for the enhanced icon resolution logic.
170-182: Good enhancement: apiType-based icon fallback.The fallback logic that uses
provider.apiTypeto find a matching icon is a sensible addition. This allows custom providers (e.g., multiple Ollama servers) to inherit the appropriate icon based on their API type when they don't have a direct modelId match.
189-206: Excellent refactor of the inversion logic.The refactored inversion logic using arrays and array methods is much more maintainable than explicit string checks. It's easier to extend with new keywords and more declarative. The addition of provider.apiType to the check targets also aligns well with the provider-scoped changes.
| const provider = computed(() => { | ||
| if (!props.modelId) return undefined | ||
| return settingsStore.providers.find((item) => item.id === props.modelId) | ||
| }) |
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.
🧩 Analysis chain
Verify the provider lookup logic.
The provider lookup matches item.id === props.modelId, which semantically suggests a modelId prop is being used to search for providers by their ID. This could indicate either:
- A naming inconsistency where
modelIdcan actually hold provider IDs in some contexts - A logic error where providers should be looked up differently
Please verify this is the intended behavior. If modelId can represent both model and provider IDs, consider renaming the prop to something more generic (e.g., itemId or identifier) or adding a comment explaining the dual usage.
🏁 Script executed:
#!/bin/bash
# Description: Check how ModelIcon component is used across the codebase to verify if modelId is passed provider IDs
# Search for ModelIcon usage patterns to see what values are passed to modelId prop
rg -nP --type=vue -A3 -B3 '<ModelIcon\s+.*?modelId'
# Also search for modelId prop bindings
rg -nP --type=vue -A2 'modelId\s*='Length of output: 55
🏁 Script executed:
#!/bin/bash
# Description: Check how ModelIcon component is used and how modelId prop is set
# Search for ModelIcon usage patterns in .vue files
echo "=== ModelIcon Usage Patterns ==="
rg -n '<ModelIcon' -g '*.vue' -A3 -B1
echo -e "\n=== modelId Prop Bindings ==="
# Search for modelId prop assignments/bindings
rg -n 'modelId\s*=' -g '*.vue' -A2 -B1
echo -e "\n=== File containing ModelIcon.vue definition ==="
# Verify the ModelIcon.vue file location
fd -e vue -x grep -l 'ModelIcon' {}Length of output: 9425
🏁 Script executed:
#!/bin/bash
# Description: Verify the structure of model objects passed to ModelIcon to understand if their .id is provider ID or model ID
# Search for selectedImageModel definition/assignment
echo "=== selectedImageModel definition ==="
rg -n 'selectedImageModel' -g '*.vue' -B2 -A2 | head -40
# Search for selectEmbeddingModel definition/assignment
echo -e "\n=== selectEmbeddingModel definition ==="
rg -n 'selectEmbeddingModel' -g '*.vue' -B2 -A2 | head -40
# Check the settingsStore to understand provider structure
echo -e "\n=== settingsStore providers structure ==="
rg -n 'providers' -g '*.ts' -B3 -A3 | grep -A5 -B5 'interface.*Provider\|type.*Provider' | head -50Length of output: 10211
🏁 Script executed:
#!/bin/bash
# Description: Find RENDERER_MODEL_META type definition
echo "=== RENDERER_MODEL_META type definition ==="
rg -n 'RENDERER_MODEL_META' -g '*.ts' -B2 -A8 | head -60
echo -e "\n=== MODEL_META type definition ==="
rg -n 'type MODEL_META\|interface MODEL_META' -g '*.ts' -B2 -A10 | head -60Length of output: 4682
Pass provider ID instead of model ID to ModelIcon component.
The ModelIcon component searches the providers array by ID, but several components are incorrectly passing model IDs instead of provider IDs. This causes the provider lookup to fail.
Affected locations:
src/renderer/src/components/mcp-config/mcpServerForm.vue:879— should passselectedImageModelProviderinstead ofselectedImageModel?.idsrc/renderer/settings/components/BuiltinKnowledgeSettings.vue:187, 227— should passselectEmbeddingModel?.providerIdandselectRerankModel?.providerIdsrc/renderer/settings/components/common/SearchAssistantModelSection.vue:16— should passselectedSearchModel?.providerId
All model objects (RENDERER_MODEL_META) have a providerId field available for this lookup.

Add custom providers of the ollama type to support multiple ollama server.
Summary by CodeRabbit
New Features
Improvements