-
Notifications
You must be signed in to change notification settings - Fork 620
Feat/acp model enhance #1272
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
base: dev
Are you sure you want to change the base?
Feat/acp model enhance #1272
Conversation
- Add SkillTools class for handling skill list and control actions. - Extend ConversationsTable to include active_skills field in the database. - Create SkillsSettings.vue component for managing skills in the UI. - Update router to include skills settings route. - Add translations for skills management in English and Chinese. - Implement skills store using Pinia for state management. - Define skill-related types in shared types directory. - Integrate skill installation and uninstallation functionalities.
- Add SkillTools class for handling skill list and control actions. - Extend ConversationsTable to include active_skills field in the database. - Create SkillsSettings.vue component for managing skills in the UI. - Update router to include skills settings route. - Add translations for skills management in English and Chinese. - Implement skills store using Pinia for state management. - Define skill-related types in shared types directory. - Integrate skill installation and uninstallation functionalities.
- Added `selectFiles` method to `IDevicePresenter` interface for file selection with options for filters and multiple selections. - Created comprehensive tests for `SkillPresenter`, covering skill discovery, installation, activation, and deactivation. - Introduced tests for `SkillTools` to validate skill handling, including edge cases and input validation. - Mocked necessary dependencies and ensured proper integration with the event bus for skill events.
…ll management - Delegated skills metadata prompt construction to skillPresenter.getMetadataPrompt() to reduce code duplication. - Initialized activeSkills in default conversation settings to maintain state. - Introduced SKILL_CONFIG constants for better configuration management, including limits on file sizes and download timeouts. - Implemented checks for file sizes and content types during skill downloads to prevent memory exhaustion and ensure valid files. - Enhanced folder tree building to limit depth and skip symbolic links, preventing infinite recursion. - Updated SkillEditorSheet.vue to use YAML serialization for SKILL.md content, improving format consistency. - Simplified drag-and-drop functionality in SkillInstallDialog.vue by removing unsupported features and adding URL validation. - Added user feedback for invalid URL formats in skill installation. - Updated translations for skill name hints in both English and Chinese.
…pchat into feat/skills
- Implement comprehensive unit tests for the security module, covering path safety, file size limits, permissions, and input validation. - Introduce unit tests for the ToolScanner class, validating external tool configurations, path expansion, and tool availability. - Mock filesystem interactions to isolate tests and ensure reliability. - Validate filename safety and prevent path traversal in directory scanning. - Ensure proper handling of oversized files during tool scanning.
…o Code, and OpenCode; update Cursor adapter to use SKILL.md format
…tences", "כישורים", "技能", "Habilidades", "Навыки" with "Skills" in various languages for consistency across the application.
- Introduced SkillsPanel.vue to display and manage user skills. - Implemented useSkillsData composable for managing skills state and interactions. - Added useSlashMentionData composable to handle slash mention functionality for skills, prompts, and tools. - Updated MentionList.vue to support new categorization and display logic for skills and prompts. - Created SlashMention extension for TipTap editor to handle slash-triggered mentions. - Enhanced slashSuggestion.ts to manage slash mention data and filtering. - Updated i18n files for English and Chinese to include new skills-related translations. - Added new events for skill activation and deactivation. - Removed unused watchers and code related to tools and prompts from useMentionData.
…content management
|
Important Review skippedReview was skipped as selected files did not have any reviewable changes. 💤 Files selected but had no reviewable changes (6)
You can disable this status message by setting the 📝 WalkthroughWalkthroughThis PR adds ACP session model management and UI, normalizes chat mode to 'agent', enables MCP by default, removes the local search stack, migrates to a single-WebContents chat window layout with sidebar/navigation, introduces many renderer composables/components for ACP (modes/models/commands/workdir), expands ACP builtin agents, and adds extensive architecture/spec documentation and governance tooling. Changes
Sequence Diagram(s)sequenceDiagram
participant Renderer as Renderer (ChatInput / ChatConfig)
participant Presenter as SessionPresenter / LLMProviderPresenter (Main)
participant AcpProv as AcpProvider
participant ProcMgr as AcpProcessManager
Renderer->>Presenter: ensureAcpWarmup(agentId, workdir) / getAcpProcessModels(agentId, workdir)
Presenter->>AcpProv: delegate ensureWarmup / getProcessModels
AcpProv->>ProcMgr: ensureWarmup / query handle for agent/workdir
ProcMgr-->>AcpProv: availableModels, currentModelId
AcpProv-->>Presenter: { availableModels, currentModelId }
Presenter-->>Renderer: IPC EVENT SESSION_MODELS_READY (conversationId, agentId, workdir, current, available)
Note over Renderer,ProcMgr: User selects model/mode
Renderer->>Presenter: setAcpSessionModel(conversationId, modelId) or setAcpPreferredProcessModel(agentId, workdir, modelId)
Presenter->>AcpProv: setSessionModel / setPreferredProcessModel
AcpProv->>ProcMgr: apply model to bound handle & persist
ProcMgr-->>AcpProv: confirmation / updated currentModelId
AcpProv-->>Presenter: ack + emit SESSION_MODELS_READY
Presenter-->>Renderer: IPC EVENT SESSION_MODELS_READY (updated)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~65 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 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
🤖 Fix all issues with AI agents
In @src/main/presenter/agentPresenter/message/messageBuilder.ts:
- Around line 101-108: The code awaits a synchronous method: remove the
unnecessary await from presenter.configPresenter.getSetting when assigning
storedChatMode, i.e., change "const storedChatMode = (await
presenter.configPresenter.getSetting(...)) as 'chat' | 'agent' | 'acp agent' |
undefined" to call getSetting synchronously and cast its return ("const
storedChatMode = presenter.configPresenter.getSetting(...) as 'chat' | 'agent' |
'acp agent' | undefined"); keep the subsequent normalization (normalizedChatMode
and chatMode) unchanged.
In @src/main/presenter/sessionPresenter/index.ts:
- Around line 932-933: The change is forcefully converting existing
conversation.settings.chatMode to 'agent' and defaulting new sessions to
'agent', which overwrites user data; revert this by (1) removing or guarding the
migration in conversationManager so it only sets settings.chatMode when
undefined (do not overwrite existing 'chat' values), and (2) change the
resolvedChatMode assignment in sessionPresenter (the resolvedChatMode expression
using conversation.settings.chatMode ?? 'agent') to default to 'chat' instead of
'agent' or only apply the 'agent' default for truly new sessions without any
stored chatMode; target the conversationManager migration logic and the
resolvedChatMode expression to preserve existing 'chat' settings.
In @src/renderer/src/i18n/zh-CN/settings.json:
- Around line 287-301: Add the missing "acpSession" translation block (same
keys: title, description, model.{label,description,placeholder,empty},
mode.{label,description,placeholder,empty}) to the 10 language files: da-DK,
fa-IR, fr-FR, he-IL, ja-JP, ko-KR, pt-BR, ru-RU, zh-HK, zh-TW, using the en-US
structure as the source; ensure the key names and JSON structure exactly match
the en-US/zh-CN versions and provide appropriate localized strings for each
field (including placeholders and empty messages) so all 12 locales contain an
identical "acpSession" block.
🧹 Nitpick comments (10)
src/renderer/src/stores/mcp.ts (1)
35-40: Comment should be in English per coding guidelines.The change to enable MCP by default aligns with the PR objective. However, the inline comment is in Chinese and should be translated to English.
Suggested fix
const config = ref<MCPConfig>({ mcpServers: {}, defaultServers: [], - mcpEnabled: true, // 添加MCP启用状态 + mcpEnabled: true, // MCP enabled by default ready: false // if init finished, the ready will be true })src/renderer/src/components/chat-input/composables/useChatMode.ts (1)
36-40: Consider future cleanup of 'chat' mode handling.The 'chat' case in
currentLabelis needed during the migration period. Once the migration is considered complete, this branch along withMODE_ICONS.chatand the 'chat' entry inChatModetype could be removed.src/renderer/src/components/chat-input/composables/useAcpSessionModel.ts (1)
183-191: Guard against potential null dereference.The non-null assertions
options.activeModel.value!.id!at line 185 could throw at runtime if the checks earlier insetModeldon't guarantee these values exist. WhileisAcpModelensuresproviderId === 'acp' && !!id, there's a race condition window between the check and the async call.♻️ Suggested safer approach
} else if (selectedWorkdir.value) { + const activeModelId = options.activeModel.value?.id + if (!activeModelId) { + console.warn('[useAcpSessionModel] Cannot set preferred model: activeModel.id is missing') + return + } await sessionPresenter.setAcpPreferredProcessModel( - options.activeModel.value!.id!, + activeModelId, selectedWorkdir.value, modelId )src/renderer/src/components/chat-input/composables/useAcpMode.ts (1)
188-216: Same non-null assertion concern as useAcpSessionModel.Line 204 uses
options.activeModel.value!.id!which could throw ifactiveModelbecomes null between the initial check and the async operation.♻️ Suggested safer approach
} else if (selectedWorkdir.value) { + const activeModelId = options.activeModel.value?.id + if (!activeModelId) { + console.warn('[useAcpMode] Cannot set preferred mode: activeModel.id is missing') + return + } await sessionPresenter.setAcpPreferredProcessMode( - options.activeModel.value!.id!, + activeModelId, selectedWorkdir.value, modeId )src/main/presenter/agentPresenter/message/messageBuilder.ts (1)
355-360: Hardcoded Chinese text should use i18n.The prompt text on line 356 is hardcoded in Chinese. Per coding guidelines, user-facing strings should use i18n keys for proper internationalization support. This appears to be a pre-existing issue but worth addressing.
♻️ Suggested approach
Consider extracting this string to an i18n key:
- const userPromptText = - '以上是你刚执行的工具调用及其响应信息,已帮你插入,请仔细阅读工具响应,并继续你的回答。' + // TODO: Move to i18n - this is a system prompt for the model + const userPromptText = + 'Above is the tool call you just executed and its response. Please carefully read the tool response and continue your answer.'src/main/presenter/agentPresenter/session/sessionManager.ts (1)
65-70: Consider extracting duplicated chat mode normalization logic.The pattern of retrieving
input_chatModeand normalizing'chat'to'agent'is duplicated three times (lines 65-70, 106-112, 132-138). This violates the DRY principle and increases maintenance burden.♻️ Suggested refactor: Extract helper method
+ private getNormalizedFallbackChatMode(): 'agent' | 'acp agent' { + const raw = this.options.configPresenter.getSetting('input_chatMode') as + | 'chat' + | 'agent' + | 'acp agent' + | undefined + return (raw === 'chat' ? 'agent' : raw) ?? 'agent' + } + async resolveSession(agentId: string): Promise<SessionContextResolved> { const conversation = await this.options.sessionPresenter.getConversation(agentId) - const rawFallbackChatMode = this.options.configPresenter.getSetting('input_chatMode') as - | 'chat' - | 'agent' - | 'acp agent' - | undefined - const fallbackChatMode = rawFallbackChatMode === 'chat' ? 'agent' : rawFallbackChatMode + const fallbackChatMode = this.getNormalizedFallbackChatMode()Then use
this.getNormalizedFallbackChatMode()in all three locations.src/renderer/src/stores/chat.ts (1)
40-41: Pre-existing: Chinese comments should be translated to English.Per coding guidelines, all comments must be in English. There are numerous Chinese comments in this file (lines 40, 73, 90, 93, 128, 131, etc.). While this is not introduced by this PR, consider addressing it in a follow-up to align with project standards.
src/shared/types/presenters/session.presenter.d.ts (1)
139-157: Consider usingAcpSessionModelInfotype for consistency.The inline type
{ id: string; name: string; description?: string }is defined inlegacy.presenters.d.tsasAcpSessionModelInfo. Using the shared type would improve maintainability and ensure consistency across the codebase.♻️ Suggested refactor
+import type { AcpSessionModelInfo } from './legacy.presenters' getAcpProcessModels( agentId: string, workdir: string ): Promise< | { - availableModels?: Array<{ id: string; name: string; description?: string }> + availableModels?: AcpSessionModelInfo[] currentModelId?: string } | undefined > // ... getAcpSessionModels(conversationId: string): Promise<{ current: string - available: Array<{ id: string; name: string; description?: string }> + available: AcpSessionModelInfo[] } | null>src/renderer/src/components/ChatConfig.vue (1)
155-156: Consider extracting eligible agents to a shared constant.The
acpSessionEligibleAgentsSet is hardcoded here. If this list is used elsewhere or may change, consider extracting it to a shared constants file for maintainability.src/renderer/src/components/chat-input/ChatInput.vue (1)
964-980: Consider extracting repeated loading guard pattern.Multiple handlers (
handleAcpSessionModelSelect,handleAcpSessionModeSelect,handleAcpModeSelect) share the same loading guard pattern. This is a minor code smell but acceptable for clarity.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (31)
docs/specs/acp-mode-defaults/plan.mddocs/specs/acp-mode-defaults/spec.mddocs/specs/acp-mode-defaults/tasks.mdsrc/main/events.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/main/presenter/toolPresenter/index.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/events.tssrc/renderer/src/i18n/en-US/settings.jsonsrc/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/stores/chat.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/shared/types/presenters/session.presenter.d.ts
🧰 Additional context used
📓 Path-based instructions (23)
**/*.{js,ts,tsx,jsx,vue,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
All logs and comments must be in English
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
**/*.{js,ts,tsx,jsx,vue,json,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
Use Prettier as the code formatter
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/renderer/src/i18n/zh-CN/settings.jsonsrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/i18n/en-US/settings.jsonsrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
src/renderer/src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*.{vue,ts,tsx}: Use vue-i18n framework for internationalization located at src/renderer/src/i18n/
All user-facing strings must use i18n keys, not hardcoded text
src/renderer/src/**/*.{vue,ts,tsx}: Usereffor primitives and references,reactivefor objects in Vue 3 Composition API
Prefercomputedproperties over methods for derived state in Vue components
Import Shadcn Vue components from@/shadcn/components/ui/path alias
Use thecn()utility function combining clsx and tailwind-merge for dynamic Tailwind classes
UsedefineAsyncComponent()for lazy loading heavy Vue components
Use TypeScript for all Vue components and composables with explicit type annotations
Define TypeScript interfaces for Vue component props and data structures
UseusePresentercomposable for main process communication instead of direct IPC calls
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/stores/mcp.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Import useI18n from vue-i18n in Vue components to access translation functions t and locale
src/renderer/src/**/*.vue: Use<script setup>syntax for concise Vue 3 component definitions with Composition API
Define props and emits explicitly in Vue components usingdefinePropsanddefineEmitswith TypeScript interfaces
Useprovide/injectfor dependency injection in Vue components instead of prop drilling
Use Tailwind CSS for all styling instead of writing scoped CSS files
Use mobile-first responsive design approach with Tailwind breakpoints
Use Iconify Vue with lucide icons as primary choice, following patternlucide:{icon-name}
Usev-memodirective for memoizing expensive computations in templates
Usev-oncedirective for rendering static content without reactivity updates
Use virtual scrolling withRecycleScrollercomponent for rendering long lists
Subscribe to events usingrendererEvents.on()and unsubscribe inonUnmountedlifecycle hook
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/ChatInput.vue
src/renderer/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Ensure all code comments are in English and all log messages are in English, with no non-English text in code comments or console statements
Use VueUse composables for common utilities like
useLocalStorage,useClipboard,useDebounceFnVue 3 renderer app code should be organized in
src/renderer/srcwith subdirectories forcomponents/,stores/,views/,i18n/, andlib/
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/stores/mcp.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
src/renderer/src/components/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
Name Vue components using PascalCase (e.g.,
ChatInput.vue,MessageItemUser.vue)
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/ChatInput.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Vue components must be named in PascalCase (e.g.,
ChatInput.vue) and use Vue 3 Composition API with Pinia for state management and Tailwind for styling
**/*.vue: Use Vue 3 Composition API with<script setup>syntax
Use Pinia stores for state management
Style Vue components using Tailwind CSS (v4) with shadcn/ui (reka-ui)
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/ChatInput.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use camelCase for variable and function names; use PascalCase for types and classes; use SCREAMING_SNAKE_CASE for constants
Configure Prettier with single quotes, no semicolons, and line width of 100 characters. Runpnpm run formatafter completing features
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
src/renderer/**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
All user-facing strings must use i18n keys (supports 12 languages)
Files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/stores/mcp.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/events.ts
**/*.{js,ts,tsx,jsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
Use OxLint as the linter
Files:
src/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/events.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Electron main process code should reside in
src/main/, with presenters organized inpresenter/subdirectory (Window, Tab, Thread, Mcp, Config, LLMProvider), and app events managed viaeventbus.ts
Files:
src/main/presenter/toolPresenter/index.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/main/events.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use OxLint for linting JavaScript and TypeScript files; ensure lint-staged hooks and typecheck pass before commits
Enable strict TypeScript type checking
Files:
src/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/events.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Implement all system capabilities as main-process presenters following the Presenter Pattern
Files:
src/main/presenter/toolPresenter/index.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.ts
{src/main,src/renderer,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use IPC communication: Renderer calls main process via
usePresentercomposable, Main sends to Renderer via EventBus
Files:
src/main/presenter/toolPresenter/index.tssrc/renderer/src/components/chat-input/composables/useChatMode.tssrc/main/presenter/sessionPresenter/const.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/main/presenter/agentPresenter/message/messageBuilder.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/main/presenter/agentPresenter/session/sessionResolver.tssrc/main/events.tssrc/renderer/src/stores/mcp.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpSessionManager.tssrc/main/presenter/sessionPresenter/managers/conversationManager.tssrc/main/presenter/agentPresenter/session/sessionManager.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/events.ts
src/renderer/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
Use class-variance-authority (CVA) for defining component variants with Tailwind classes
Files:
src/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/stores/mcp.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/events.ts
src/renderer/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
src/renderer/src/**/*.{ts,tsx}: UseshallowRefandshallowReactivefor optimizing reactivity with large objects
Prefertypeoverinterfacein TypeScript unless using inheritance withextends
Files:
src/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/stores/mcp.tssrc/renderer/src/stores/chat.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/events.ts
src/renderer/src/i18n/**/*.json
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/i18n/**/*.json: Use dot-separated hierarchical structure for translation key naming with lowercase letters and descriptive names grouped by feature/context (e.g., common.button.submit, chat.send.placeholder)
Add new translations to ALL language files (da-DK, en-US, fa-IR, fr-FR, he-IL, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-HK, zh-TW) with consistent key names across all locales
Keep proper nouns and technical terms untranslated (e.g., 'DeepChat', 'MCP', 'Agents' in English) unless established convention exists, and follow established conventions for well-known technical terms
Files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
src/renderer/src/i18n/{zh-CN,zh-HK,zh-TW}/**/*.json
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
For Chinese translations, consider using '智能体' for 'Agents' instead of the English term
Files:
src/renderer/src/i18n/zh-CN/settings.json
src/renderer/src/stores/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
src/renderer/src/stores/**/*.ts: Use Setup Store syntax withdefineStorefunction pattern in Pinia stores
Use getters (computed properties) for derived state in Pinia stores
Keep Pinia store actions focused on state mutations and async operations
Files:
src/renderer/src/stores/mcp.tssrc/renderer/src/stores/chat.ts
src/shared/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Shared TypeScript types and utilities should be placed in
src/shared/
Files:
src/shared/types/presenters/legacy.presenters.d.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/shared/types/presenters/session.presenter.d.ts
src/main/presenter/llmProviderPresenter/providers/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Implement
coreStreammethod following standardized event interface for LLM providers
Files:
src/main/presenter/llmProviderPresenter/providers/acpProvider.ts
src/renderer/src/i18n/en-US/**/*.json
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Use English (en-US) as the reference for translation accuracy when adding new keys
Files:
src/renderer/src/i18n/en-US/settings.json
🧠 Learnings (19)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-05T02:41:45.219Z
Learning: Use Presenter pattern in main process, EventBus for inter-process events, and two-layer LLM provider architecture (Agent Loop + Provider) with integrated MCP tools
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.vue : Define props and emits explicitly in Vue components using `defineProps` and `defineEmits` with TypeScript interfaces
Applied to files:
src/renderer/src/components/ChatConfig/ConfigSelectField.vuesrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/**/*.ts : Implement new MCP tools in the inMemoryServers directory and register in mcpPresenter/index.ts
Applied to files:
src/main/presenter/toolPresenter/index.tssrc/main/presenter/configPresenter/mcpConfHelper.tssrc/renderer/src/stores/mcp.tssrc/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/sessionPresenter/index.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/composables/**/*.ts : Name composables using camelCase with `use` prefix (e.g., `useChatState.ts`, `useMessageList.ts`)
Applied to files:
src/renderer/src/components/chat-input/composables/useChatMode.tssrc/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2025-06-21T15:49:17.044Z
Learnt from: neoragex2002
Repo: ThinkInAIXYZ/deepchat PR: 550
File: src/renderer/src/stores/chat.ts:1011-1035
Timestamp: 2025-06-21T15:49:17.044Z
Learning: In src/renderer/src/stores/chat.ts, the user prefers to keep both `text` and `content` properties in the `handleMeetingInstruction` function's `sendMessage` call, even though they are redundant, rather than removing the `content` property.
Applied to files:
src/main/presenter/sessionPresenter/const.tssrc/renderer/src/stores/chat.ts
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Add new translations to ALL language files (da-DK, en-US, fa-IR, fr-FR, he-IL, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-HK, zh-TW) with consistent key names across all locales
Applied to files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Use dot-separated hierarchical structure for translation key naming with lowercase letters and descriptive names grouped by feature/context (e.g., common.button.submit, chat.send.placeholder)
Applied to files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/{zh-CN,zh-HK,zh-TW}/**/*.json : For Chinese translations, consider using '智能体' for 'Agents' instead of the English term
Applied to files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep proper nouns and technical terms untranslated (e.g., 'DeepChat', 'MCP', 'Agents' in English) unless established convention exists, and follow established conventions for well-known technical terms
Applied to files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/en-US/**/*.json : Use English (en-US) as the reference for translation accuracy when adding new keys
Applied to files:
src/renderer/src/i18n/zh-CN/settings.jsonsrc/renderer/src/i18n/en-US/settings.json
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Use VueUse composables for common utilities like `useLocalStorage`, `useClipboard`, `useDebounceFn`
Applied to files:
src/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx} : Use `usePresenter` composable for main process communication instead of direct IPC calls
Applied to files:
src/renderer/src/components/chat-input/composables/useAcpSessionModel.tssrc/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/main/presenter/sessionPresenter/index.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/shared/types/presenters/session.presenter.d.tssrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/components/**/*.vue : Name Vue components using PascalCase (e.g., `ChatInput.vue`, `MessageItemUser.vue`)
Applied to files:
src/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/NewThread.vuesrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/components/ : Organize Vue component directories using lowercase with dashes (e.g., `chat-input/`, `message/`)
Applied to files:
src/renderer/src/components/ChatConfig.vuesrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx} : Use vue-i18n framework for internationalization located at src/renderer/src/i18n/
Applied to files:
src/renderer/src/components/ChatConfig.vue
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to {src/main,src/renderer,test}/**/*.{ts,tsx,js} : Use IPC communication: Renderer calls main process via `usePresenter` composable, Main sends to Renderer via EventBus
Applied to files:
src/renderer/src/components/NewThread.vuesrc/main/presenter/sessionPresenter/index.tssrc/shared/types/presenters/llmprovider.presenter.d.ts
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/main/presenter/**/*.ts : Implement all system capabilities as main-process presenters following the Presenter Pattern
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/session.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Implement `coreStream` method following standardized event interface for LLM providers
Applied to files:
src/shared/types/presenters/legacy.presenters.d.tssrc/main/presenter/sessionPresenter/index.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2026-01-05T02:41:45.219Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-05T02:41:45.219Z
Learning: Use Presenter pattern in main process, EventBus for inter-process events, and two-layer LLM provider architecture (Agent Loop + Provider) with integrated MCP tools
Applied to files:
src/main/presenter/sessionPresenter/index.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.ts
🧬 Code graph analysis (6)
src/main/presenter/agentPresenter/message/messageBuilder.ts (1)
src/main/presenter/index.ts (1)
presenter(334-334)
src/renderer/src/components/chat-input/composables/useAcpSessionModel.ts (2)
src/renderer/src/composables/usePresenter.ts (1)
usePresenter(103-105)src/renderer/src/events.ts (1)
ACP_WORKSPACE_EVENTS(208-211)
src/main/presenter/sessionPresenter/index.ts (1)
src/shared/types/presenters/session.presenter.d.ts (1)
Session(50-58)
src/main/presenter/agentPresenter/acp/acpSessionManager.ts (2)
test/mocks/electron.ts (1)
session(34-34)scripts/fetch-provider-db.mjs (1)
models(37-37)
src/shared/types/presenters/llmprovider.presenter.d.ts (1)
src/shared/types/presenters/legacy.presenters.d.ts (1)
AcpSessionModelInfo(906-910)
src/main/presenter/llmProviderPresenter/providers/acpProvider.ts (4)
test/mocks/electron.ts (1)
session(34-34)src/main/eventbus.ts (1)
eventBus(151-151)src/main/events.ts (1)
ACP_WORKSPACE_EVENTS(256-259)src/renderer/src/events.ts (1)
ACP_WORKSPACE_EVENTS(208-211)
🪛 LanguageTool
docs/specs/acp-mode-defaults/spec.md
[style] ~22-~22: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...ACP Agent modes and default to Agent. - As a user, switching to ACP Agent should i...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
[style] ~23-~23: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ...t without opening the model selector. - As a user, when using Claude Code or Codex...
(ENGLISH_WORD_REPEAT_BEGINNING_RULE)
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 (4)
src/renderer/src/components/chat-input/ChatInput.vue (4)
876-876: Confusing naming forisAgentModeSelected.The computed property returns
truewhen the mode is NOT 'acp agent', which makes it select the "Agent" row. The nameisAgentModeSelectedsuggests it checks if agent mode is selected, but it actually checks if we're NOT in ACP agent mode. Consider renaming for clarity.💡 Suggested rename for clarity
-const isAgentModeSelected = computed(() => chatMode.currentMode.value !== 'acp agent') +const isNonAcpAgentMode = computed(() => chatMode.currentMode.value !== 'acp agent')Or alternatively, if the intent is to highlight the "agent" row:
-const isAgentModeSelected = computed(() => chatMode.currentMode.value !== 'acp agent') +const isBuiltInAgentSelected = computed(() => chatMode.currentMode.value === 'agent')
312-331: Consider disabling click during loading state at the template level.The loading state adds visual disabled styling (
opacity-60 cursor-not-allowed) but the click handler is still attached. WhilehandleAcpModeSelectchecksacpMode.loading.valueinternally, adding@click.stopor a conditional guard at the template level would be more consistent.💡 Suggested improvement
@click="handleAcpModeSelect(mode.id)" + @click="!acpMode.loading.value && handleAcpModeSelect(mode.id)"Or using a modifier:
- @click="handleAcpModeSelect(mode.id)" + @click="acpMode.loading.value ? undefined : handleAcpModeSelect(mode.id)"
937-947: Consider adding error handling for async operations.Both handlers call async methods (
setModel,setMode) but don't handle potential failures. If these operations can fail, the popover would close without user feedback.💡 Suggested improvement
const handleAcpSessionModelSelect = async (modelId: string) => { if (acpSessionModel.loading.value) return - await acpSessionModel.setModel(modelId) - modelSelectOpen.value = false + try { + await acpSessionModel.setModel(modelId) + modelSelectOpen.value = false + } catch (error) { + console.warn('Failed to set ACP session model:', error) + } } const handleAcpModeSelect = async (modeId: string) => { if (acpMode.loading.value) return - await acpMode.setMode(modeId) - acpModeSelectOpen.value = false + try { + await acpMode.setMode(modeId) + acpModeSelectOpen.value = false + } catch (error) { + console.warn('Failed to set ACP mode:', error) + } }
1017-1021: Type casting withas anymay hide type mismatches.The casts at lines 1018 and 1020 suggest the payload type doesn't match what
config.handleModelUpdateor themodel-updateevent expect. Consider aligning the types properly to catch potential issues at compile time.💡 Investigation suggestion
#!/bin/bash # Check the expected type signature for handleModelUpdate and model-update event ast-grep --pattern 'handleModelUpdate($$$)' rg -n "emit\('model-update'" --type=vue --type=ts -A2 rg -n "defineEmits" src/renderer/src/components/chat-input/ChatInput.vue -A5
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/renderer/src/components/chat-input/ChatInput.vue
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,ts,tsx,jsx,vue,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
All logs and comments must be in English
Files:
src/renderer/src/components/chat-input/ChatInput.vue
**/*.{js,ts,tsx,jsx,vue,json,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
Use Prettier as the code formatter
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/renderer/src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*.{vue,ts,tsx}: Use vue-i18n framework for internationalization located at src/renderer/src/i18n/
All user-facing strings must use i18n keys, not hardcoded text
src/renderer/src/**/*.{vue,ts,tsx}: Usereffor primitives and references,reactivefor objects in Vue 3 Composition API
Prefercomputedproperties over methods for derived state in Vue components
Import Shadcn Vue components from@/shadcn/components/ui/path alias
Use thecn()utility function combining clsx and tailwind-merge for dynamic Tailwind classes
UsedefineAsyncComponent()for lazy loading heavy Vue components
Use TypeScript for all Vue components and composables with explicit type annotations
Define TypeScript interfaces for Vue component props and data structures
UseusePresentercomposable for main process communication instead of direct IPC calls
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Import useI18n from vue-i18n in Vue components to access translation functions t and locale
src/renderer/src/**/*.vue: Use<script setup>syntax for concise Vue 3 component definitions with Composition API
Define props and emits explicitly in Vue components usingdefinePropsanddefineEmitswith TypeScript interfaces
Useprovide/injectfor dependency injection in Vue components instead of prop drilling
Use Tailwind CSS for all styling instead of writing scoped CSS files
Use mobile-first responsive design approach with Tailwind breakpoints
Use Iconify Vue with lucide icons as primary choice, following patternlucide:{icon-name}
Usev-memodirective for memoizing expensive computations in templates
Usev-oncedirective for rendering static content without reactivity updates
Use virtual scrolling withRecycleScrollercomponent for rendering long lists
Subscribe to events usingrendererEvents.on()and unsubscribe inonUnmountedlifecycle hook
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/renderer/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Ensure all code comments are in English and all log messages are in English, with no non-English text in code comments or console statements
Use VueUse composables for common utilities like
useLocalStorage,useClipboard,useDebounceFnVue 3 renderer app code should be organized in
src/renderer/srcwith subdirectories forcomponents/,stores/,views/,i18n/, andlib/
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/renderer/src/components/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
Name Vue components using PascalCase (e.g.,
ChatInput.vue,MessageItemUser.vue)
Files:
src/renderer/src/components/chat-input/ChatInput.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Vue components must be named in PascalCase (e.g.,
ChatInput.vue) and use Vue 3 Composition API with Pinia for state management and Tailwind for styling
**/*.vue: Use Vue 3 Composition API with<script setup>syntax
Use Pinia stores for state management
Style Vue components using Tailwind CSS (v4) with shadcn/ui (reka-ui)
Files:
src/renderer/src/components/chat-input/ChatInput.vue
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use camelCase for variable and function names; use PascalCase for types and classes; use SCREAMING_SNAKE_CASE for constants
Configure Prettier with single quotes, no semicolons, and line width of 100 characters. Runpnpm run formatafter completing features
Files:
src/renderer/src/components/chat-input/ChatInput.vue
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/renderer/**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
All user-facing strings must use i18n keys (supports 12 languages)
Files:
src/renderer/src/components/chat-input/ChatInput.vue
🧠 Learnings (6)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-05T02:41:45.219Z
Learning: Use Presenter pattern in main process, EventBus for inter-process events, and two-layer LLM provider architecture (Agent Loop + Provider) with integrated MCP tools
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/components/**/*.vue : Name Vue components using PascalCase (e.g., `ChatInput.vue`, `MessageItemUser.vue`)
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/composables/**/*.ts : Name composables using camelCase with `use` prefix (e.g., `useChatState.ts`, `useMessageList.ts`)
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Use VueUse composables for common utilities like `useLocalStorage`, `useClipboard`, `useDebounceFn`
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx} : Use `usePresenter` composable for main process communication instead of direct IPC calls
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.vue : Define props and emits explicitly in Vue components using `defineProps` and `defineEmits` with TypeScript interfaces
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
🔇 Additional comments (9)
src/renderer/src/components/chat-input/ChatInput.vue (9)
121-146: LGTM!The ACP agent options section is well-structured with proper conditional rendering, i18n usage, and visual feedback for selection state.
371-386: LGTM!The model selector label and conditional badge rendering correctly adapts the UI based on whether ACP session model selection is active.
391-426: LGTM with minor note.The ACP session model selector is well-structured with proper empty states, selection indicators, and i18n compliance. Note: Same loading-state click handling consideration applies here as mentioned for the ACP mode selector.
858-874: LGTM!The computed properties correctly filter ACP models from the model store and extract the selected ACP agent ID with proper null safety.
914-935: LGTM!The ACP session model composable integration and derived computed properties follow consistent patterns with appropriate fallback handling for the label display.
1044-1071: LGTM!The mode selection handler correctly implements automatic model fallback logic when switching between ACP agent and built-in agent modes, with appropriate error handling for configuration persistence.
1073-1093: LGTM!The ACP agent selection handler correctly ensures mode is set before applying the model, with consistent error handling and popover management.
516-577: LGTM - Imports and initialization.The new imports (
useAcpSessionModel,useModelStore) and emit definition follow established patterns in the codebase.
436-437: Config button intentionally hidden for ACP agent mode.When chat mode is 'acp agent', the config button (temperature, system prompt, etc.) is hidden via the
!isAcpChatModecondition at line 437. This is intentional—ACP agents use a separate mode selection system (see line 922showAcpSessionModelSelector) rather than standard configuration options. Verify with the team whether this design aligns with ACP agent capabilities and if any config options should be exposed for ACP workflows.
- Add config warmup directory for fetching modes/models before workdir selection - Add ensureAcpWarmup method to support warmup without user-selected workdir - Add workdir change confirmation dialog to warn users about session reset - Add ACP commands support with COMMANDS_UPDATE event - Add useAcpCommands composable for handling agent commands - Clean up config warmup directory on shutdown
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
🤖 Fix all issues with AI agents
In `@src/renderer/src/components/chat-input/ChatInput.vue`:
- Line 909: The computed property isAgentModeSelected currently uses inverted
logic (chatMode.currentMode.value !== 'acp agent') causing it to be true for
'chat' and other modes; update the computed in ChatInput.vue
(isAgentModeSelected) to check for equality with 'agent' (i.e., use
chatMode.currentMode.value === 'agent') so the Agent button is only active when
the mode is 'agent'.
In `@src/renderer/src/i18n/en-US/chat.json`:
- Around line 24-27: The new translation keys acpWorkdirChangeTitle,
acpWorkdirChangeDescription, acpWorkdirChangeConfirm, and acpWorkdirChangeCancel
were added only to en-US (and zh-CN) but must exist in all 12 language JSON
files; update the remaining language files (da-DK, fa-IR, fr-FR, he-IL, ja-JP,
ko-KR, pt-BR, ru-RU, zh-HK, zh-TW) by adding those four keys with appropriate
localized strings (or temporary English placeholders if translations are not
available), using the exact key names so they match across locales and preserve
JSON formatting and trailing commas consistent with each file.
♻️ Duplicate comments (1)
src/main/presenter/sessionPresenter/index.ts (1)
936-937: Verify: DefaultchatModefallback changed to'agent'.This changes the default fallback for sessions without an explicit
chatModefrom'chat'to'agent'. While this affects only new sessions or sessions with no storedchatMode, the past review indicated there may be migration logic inconversationManager.tsthat forcefully converts existing'chat'settings to'agent'.Please confirm whether existing user sessions with
chatMode: 'chat'are preserved or migrated, and whether this behavioral change is intentional and documented for users.#!/bin/bash # Check for chatMode migration or conversion logic in conversationManager rg -n "chatMode" --type ts -C 5 src/main/presenter/sessionPresenter/managers/conversationManager.ts # Check if there's any migration that converts 'chat' to 'agent' rg -n "'chat'|\"chat\"" --type ts src/main/presenter/sessionPresenter/managers/conversationManager.ts
🧹 Nitpick comments (7)
src/renderer/src/components/chat-input/composables/useAcpWorkdir.ts (1)
195-206: Consider adding error handling to confirmWorkdirChange.The
confirmWorkdirChangefunction callsapplyWorkdirChangewithout a try/catch. If the apply fails, the dialog state is already cleared but the user has no feedback about the failure.🔧 Suggested improvement
const confirmWorkdirChange = async () => { showWorkdirChangeConfirm.value = false if (pendingWorkdirChange.value) { - await applyWorkdirChange(pendingWorkdirChange.value) - pendingWorkdirChange.value = null + const pathToApply = pendingWorkdirChange.value + pendingWorkdirChange.value = null + try { + await applyWorkdirChange(pathToApply) + } catch (error) { + console.warn('[useAcpWorkdir] Failed to apply confirmed workdir change', error) + } } }src/renderer/src/components/chat-input/composables/useAcpCommands.ts (1)
12-16: Consider importingAcpCommandtype from shared types to avoid duplication.This interface duplicates the definition in
src/main/presenter/agentPresenter/acp/acpContentMapper.ts(lines 10-14). To maintain consistency and avoid drift, consider either:
- Moving this type to
src/shared/types/and importing it in both locations, or- Re-exporting from the main process types if already exposed.
docs/specs/acp-integration/enhancement-spec.md (2)
34-51: Add language specifier to fenced code block.The ASCII diagram should have a language specifier for proper rendering and to satisfy the markdownlint rule MD040.
📝 Suggested fix
-``` +```text ┌─────────────────────────────────────────────────────────────┐ │ 配置获取流程(改进后) │
124-134: Add language specifier to fenced code block.Same markdownlint MD040 issue - add a language specifier.
📝 Suggested fix
-``` +```text Agent 发送 available_commands_update ↓ AcpContentMapper 处理通知docs/specs/acp-integration/spec.md (2)
1-69: Consider providing English documentation or bilingual content.The specification is well-structured with clear architecture diagrams and component descriptions. However, per the coding guidelines stating "All logs and comments must be in English", consider whether this extends to technical documentation for consistency across the codebase.
This is a minor concern for internal documentation, but if this spec is intended for broader consumption or contribution, an English version would improve accessibility.
23-69: Add language identifiers to fenced code blocks.Several code blocks are missing language specifiers as flagged by markdownlint. Adding identifiers improves syntax highlighting and tooling support.
Suggested fixes
For ASCII diagrams (line 23), use:
-``` +```textFor table-like content (line 91), use:
-``` +```textFor TypeScript interfaces (lines 133, 310, 322), use:
-``` +```typescriptAlso applies to: 91-99, 133-142, 310-316, 322-331
src/renderer/src/components/chat-input/composables/useAcpMode.ts (1)
96-108: Consider replacing the fixed 500ms delay with an event-driven approach.The hardcoded delay (
setTimeout(resolve, 500)) is a pragmatic workaround but could be fragile under varying system loads or slow agent startups. If the warmup takes longer, modes might not be available yet.Consider either:
- Listening for the
SESSION_MODES_READYevent after triggering warmup- Implementing a polling mechanism with backoff
- Documenting the limitation if the current approach is acceptable for now
That said, this is a warmup path for pre-session UI state, so the impact of occasional misses is limited.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
docs/specs/acp-integration/enhancement-spec.mddocs/specs/acp-integration/spec.mddocs/specs/acp-integration/ux-issues-research.mdsrc/main/events.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/agentPresenter/acp/index.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/sessionPresenter/index.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/events.tssrc/renderer/src/i18n/en-US/chat.jsonsrc/renderer/src/i18n/zh-CN/chat.jsonsrc/shared/types/presenters/llmprovider.presenter.d.tssrc/shared/types/presenters/session.presenter.d.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/shared/types/presenters/session.presenter.d.ts
- src/renderer/src/events.ts
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{js,ts,tsx,jsx,vue,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
All logs and comments must be in English
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
**/*.{js,ts,tsx,jsx,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
Use OxLint as the linter
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
**/*.{js,ts,tsx,jsx,vue,json,mjs,cjs}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
Use Prettier as the code formatter
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/i18n/zh-CN/chat.jsonsrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/renderer/src/i18n/en-US/chat.jsonsrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Electron main process code should reside in
src/main/, with presenters organized inpresenter/subdirectory (Window, Tab, Thread, Mcp, Config, LLMProvider), and app events managed viaeventbus.ts
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,vue}: Use camelCase for variable and function names; use PascalCase for types and classes; use SCREAMING_SNAKE_CASE for constants
Configure Prettier with single quotes, no semicolons, and line width of 100 characters. Runpnpm run formatafter completing features
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (AGENTS.md)
Use OxLint for linting JavaScript and TypeScript files; ensure lint-staged hooks and typecheck pass before commits
Enable strict TypeScript type checking
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Implement all system capabilities as main-process presenters following the Presenter Pattern
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
{src/main,src/renderer,test}/**/*.{ts,tsx,js}
📄 CodeRabbit inference engine (CLAUDE.md)
Use IPC communication: Renderer calls main process via
usePresentercomposable, Main sends to Renderer via EventBus
Files:
src/main/presenter/agentPresenter/acp/index.tssrc/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/events.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
src/renderer/src/**/*.{vue,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*.{vue,ts,tsx}: Use vue-i18n framework for internationalization located at src/renderer/src/i18n/
All user-facing strings must use i18n keys, not hardcoded text
src/renderer/src/**/*.{vue,ts,tsx}: Usereffor primitives and references,reactivefor objects in Vue 3 Composition API
Prefercomputedproperties over methods for derived state in Vue components
Import Shadcn Vue components from@/shadcn/components/ui/path alias
Use thecn()utility function combining clsx and tailwind-merge for dynamic Tailwind classes
UsedefineAsyncComponent()for lazy loading heavy Vue components
Use TypeScript for all Vue components and composables with explicit type annotations
Define TypeScript interfaces for Vue component props and data structures
UseusePresentercomposable for main process communication instead of direct IPC calls
Files:
src/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpWorkdir.ts
src/renderer/src/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Ensure all code comments are in English and all log messages are in English, with no non-English text in code comments or console statements
Use VueUse composables for common utilities like
useLocalStorage,useClipboard,useDebounceFnVue 3 renderer app code should be organized in
src/renderer/srcwith subdirectories forcomponents/,stores/,views/,i18n/, andlib/
Files:
src/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpWorkdir.ts
src/renderer/src/**/*.{ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
Use class-variance-authority (CVA) for defining component variants with Tailwind classes
Files:
src/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.ts
src/renderer/src/**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
src/renderer/src/**/*.{ts,tsx}: UseshallowRefandshallowReactivefor optimizing reactivity with large objects
Prefertypeoverinterfacein TypeScript unless using inheritance withextends
Files:
src/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/composables/useAcpWorkdir.ts
src/renderer/**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
All user-facing strings must use i18n keys (supports 12 languages)
Files:
src/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpWorkdir.ts
src/renderer/src/i18n/**/*.json
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/i18n/**/*.json: Use dot-separated hierarchical structure for translation key naming with lowercase letters and descriptive names grouped by feature/context (e.g., common.button.submit, chat.send.placeholder)
Add new translations to ALL language files (da-DK, en-US, fa-IR, fr-FR, he-IL, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-HK, zh-TW) with consistent key names across all locales
Keep proper nouns and technical terms untranslated (e.g., 'DeepChat', 'MCP', 'Agents' in English) unless established convention exists, and follow established conventions for well-known technical terms
Files:
src/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/en-US/chat.json
src/renderer/src/i18n/{zh-CN,zh-HK,zh-TW}/**/*.json
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
For Chinese translations, consider using '智能体' for 'Agents' instead of the English term
Files:
src/renderer/src/i18n/zh-CN/chat.json
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Import useI18n from vue-i18n in Vue components to access translation functions t and locale
src/renderer/src/**/*.vue: Use<script setup>syntax for concise Vue 3 component definitions with Composition API
Define props and emits explicitly in Vue components usingdefinePropsanddefineEmitswith TypeScript interfaces
Useprovide/injectfor dependency injection in Vue components instead of prop drilling
Use Tailwind CSS for all styling instead of writing scoped CSS files
Use mobile-first responsive design approach with Tailwind breakpoints
Use Iconify Vue with lucide icons as primary choice, following patternlucide:{icon-name}
Usev-memodirective for memoizing expensive computations in templates
Usev-oncedirective for rendering static content without reactivity updates
Use virtual scrolling withRecycleScrollercomponent for rendering long lists
Subscribe to events usingrendererEvents.on()and unsubscribe inonUnmountedlifecycle hook
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/renderer/src/components/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-stack-guide.mdc)
Name Vue components using PascalCase (e.g.,
ChatInput.vue,MessageItemUser.vue)
Files:
src/renderer/src/components/chat-input/ChatInput.vue
**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Vue components must be named in PascalCase (e.g.,
ChatInput.vue) and use Vue 3 Composition API with Pinia for state management and Tailwind for styling
**/*.vue: Use Vue 3 Composition API with<script setup>syntax
Use Pinia stores for state management
Style Vue components using Tailwind CSS (v4) with shadcn/ui (reka-ui)
Files:
src/renderer/src/components/chat-input/ChatInput.vue
src/main/presenter/llmProviderPresenter/providers/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Implement
coreStreammethod following standardized event interface for LLM providers
Files:
src/main/presenter/llmProviderPresenter/providers/acpProvider.ts
src/shared/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Shared TypeScript types and utilities should be placed in
src/shared/
Files:
src/shared/types/presenters/llmprovider.presenter.d.ts
src/renderer/src/i18n/en-US/**/*.json
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
Use English (en-US) as the reference for translation accuracy when adding new keys
Files:
src/renderer/src/i18n/en-US/chat.json
🧠 Learnings (22)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-05T02:41:45.219Z
Learning: Use Presenter pattern in main process, EventBus for inter-process events, and two-layer LLM provider architecture (Agent Loop + Provider) with integrated MCP tools
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/**/*.ts : Implement new MCP tools in the inMemoryServers directory and register in mcpPresenter/index.ts
Applied to files:
src/main/presenter/agentPresenter/acp/index.tssrc/main/presenter/agentPresenter/acp/acpContentMapper.tssrc/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/sessionPresenter/index.ts
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/composables/**/*.ts : Name composables using camelCase with `use` prefix (e.g., `useChatState.ts`, `useMessageList.ts`)
Applied to files:
src/renderer/src/components/chat-input/composables/useAgentWorkspace.tssrc/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/composables/useAcpMode.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpWorkdir.ts
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Use VueUse composables for common utilities like `useLocalStorage`, `useClipboard`, `useDebounceFn`
Applied to files:
src/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx} : Use `usePresenter` composable for main process communication instead of direct IPC calls
Applied to files:
src/renderer/src/components/chat-input/composables/useAcpCommands.tssrc/renderer/src/components/chat-input/ChatInput.vuesrc/renderer/src/components/chat-input/composables/useAcpWorkdir.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/sessionPresenter/index.ts
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Use dot-separated hierarchical structure for translation key naming with lowercase letters and descriptive names grouped by feature/context (e.g., common.button.submit, chat.send.placeholder)
Applied to files:
src/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/en-US/chat.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Add new translations to ALL language files (da-DK, en-US, fa-IR, fr-FR, he-IL, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-HK, zh-TW) with consistent key names across all locales
Applied to files:
src/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/en-US/chat.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/**/*.json : Keep proper nouns and technical terms untranslated (e.g., 'DeepChat', 'MCP', 'Agents' in English) unless established convention exists, and follow established conventions for well-known technical terms
Applied to files:
src/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/en-US/chat.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/{zh-CN,zh-HK,zh-TW}/**/*.json : For Chinese translations, consider using '智能体' for 'Agents' instead of the English term
Applied to files:
src/renderer/src/i18n/zh-CN/chat.json
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/renderer/**/*.{ts,tsx,js,jsx,vue} : All user-facing strings must use i18n keys (supports 12 languages)
Applied to files:
src/renderer/src/i18n/zh-CN/chat.jsonsrc/renderer/src/i18n/en-US/chat.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Ensure all code comments are in English and all log messages are in English, with no non-English text in code comments or console statements
Applied to files:
src/renderer/src/i18n/zh-CN/chat.json
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/components/**/*.vue : Name Vue components using PascalCase (e.g., `ChatInput.vue`, `MessageItemUser.vue`)
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/components/ : Organize Vue component directories using lowercase with dashes (e.g., `chat-input/`, `message/`)
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx} : Import Shadcn Vue components from `@/shadcn/components/ui/` path alias
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.vue : Define props and emits explicitly in Vue components using `defineProps` and `defineEmits` with TypeScript interfaces
Applied to files:
src/renderer/src/components/chat-input/ChatInput.vue
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Implement `coreStream` method following standardized event interface for LLM providers
Applied to files:
src/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.ts
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to src/main/presenter/**/*.ts : Implement all system capabilities as main-process presenters following the Presenter Pattern
Applied to files:
src/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/agentPresenter/acp/acpProcessManager.tssrc/main/presenter/sessionPresenter/index.ts
📚 Learning: 2026-01-05T02:41:45.219Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-05T02:41:45.219Z
Learning: Use Presenter pattern in main process, EventBus for inter-process events, and two-layer LLM provider architecture (Agent Loop + Provider) with integrated MCP tools
Applied to files:
src/main/presenter/llmProviderPresenter/providers/acpProvider.tssrc/shared/types/presenters/llmprovider.presenter.d.tssrc/main/presenter/llmProviderPresenter/index.tssrc/main/presenter/sessionPresenter/index.ts
📚 Learning: 2026-01-13T09:23:07.415Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-01-13T09:23:07.415Z
Learning: Applies to {src/main,src/renderer,test}/**/*.{ts,tsx,js} : Use IPC communication: Renderer calls main process via `usePresenter` composable, Main sends to Renderer via EventBus
Applied to files:
src/shared/types/presenters/llmprovider.presenter.d.ts
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/i18n/en-US/**/*.json : Use English (en-US) as the reference for translation accuracy when adding new keys
Applied to files:
src/renderer/src/i18n/en-US/chat.json
📚 Learning: 2026-01-05T02:41:45.219Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-05T02:41:45.219Z
Learning: Applies to src/renderer/src/i18n/**/*.ts : All user-facing strings must use vue-i18n keys defined in `src/renderer/src/i18n/`
Applied to files:
src/renderer/src/i18n/en-US/chat.json
📚 Learning: 2026-01-05T02:41:13.302Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2026-01-05T02:41:13.302Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx} : All user-facing strings must use i18n keys, not hardcoded text
Applied to files:
src/renderer/src/i18n/en-US/chat.json
🧬 Code graph analysis (6)
src/renderer/src/components/chat-input/composables/useAcpCommands.ts (4)
src/main/presenter/agentPresenter/acp/acpContentMapper.ts (2)
AcpCommand(11-15)handleCommandsUpdate(248-264)src/main/presenter/agentPresenter/acp/index.ts (1)
AcpCommand(13-13)src/main/events.ts (1)
ACP_WORKSPACE_EVENTS(256-260)src/renderer/src/events.ts (1)
ACP_WORKSPACE_EVENTS(208-212)
src/main/presenter/agentPresenter/acp/acpContentMapper.ts (2)
src/main/presenter/agentPresenter/acp/index.ts (1)
AcpCommand(13-13)src/renderer/src/components/chat-input/composables/useAcpCommands.ts (1)
AcpCommand(12-16)
src/main/presenter/llmProviderPresenter/providers/acpProvider.ts (3)
src/main/eventbus.ts (1)
eventBus(151-151)src/main/events.ts (1)
ACP_WORKSPACE_EVENTS(256-260)src/renderer/src/events.ts (1)
ACP_WORKSPACE_EVENTS(208-212)
src/shared/types/presenters/llmprovider.presenter.d.ts (1)
src/shared/types/presenters/legacy.presenters.d.ts (1)
AcpSessionModelInfo(906-910)
src/main/presenter/agentPresenter/acp/acpProcessManager.ts (6)
test/mocks/electron.ts (1)
app(2-10)src/shared/types/presenters/legacy.presenters.d.ts (1)
AcpAgentConfig(874-880)src/main/presenter/agentPresenter/acp/index.ts (1)
AcpProcessHandle(5-5)src/main/eventbus.ts (1)
eventBus(151-151)src/main/events.ts (1)
ACP_WORKSPACE_EVENTS(256-260)src/renderer/src/events.ts (1)
ACP_WORKSPACE_EVENTS(208-212)
src/main/presenter/sessionPresenter/index.ts (1)
src/shared/types/presenters/session.presenter.d.ts (1)
Session(50-58)
🪛 markdownlint-cli2 (0.18.1)
docs/specs/acp-integration/enhancement-spec.md
34-34: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
124-124: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
docs/specs/acp-integration/spec.md
23-23: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
91-91: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
133-133: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
310-310: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
322-322: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🔇 Additional comments (53)
src/main/events.ts (1)
256-260: LGTM!The new ACP workspace events
SESSION_MODELS_READYandCOMMANDS_UPDATEfollow the established naming convention and integrate well with the existing event structure. These events support the broader ACP model/session management changes in this PR.src/main/presenter/agentPresenter/acp/index.ts (1)
13-13: LGTM!The type-only export of
AcpCommandfollows the established pattern in this index file and properly exposes the new interface for consumers.src/main/presenter/agentPresenter/acp/acpContentMapper.ts (3)
11-26: LGTM!The
AcpCommandinterface is well-defined and matches the corresponding interface in the renderer (src/renderer/src/components/chat-input/composables/useAcpCommands.ts). The extension ofMappedContentwithavailableCommandsfollows the established pattern for optional payload fields.
66-72: LGTM!The
available_commands_updatecase is handled consistently with other session update types, with appropriate logging and delegation to the handler.
248-264: LGTM!The
handleCommandsUpdatemethod correctly maps ACP commands to the payload format. The null-coalescing toundefinedfor optional fields (description,input) ensures type consistency with the interface definition.src/renderer/src/components/chat-input/composables/useAcpWorkdir.ts (4)
24-27: LGTM!The confirmation dialog state refs follow Vue 3 composition API best practices with appropriate initial values.
151-174: LGTM!The
applyWorkdirChangefunction cleanly encapsulates the workdir change logic, correctly handling both active conversation and pre-conversation scenarios. The preference sync and warmup are properly sequenced.
176-193: Well-designed confirmation flow.The conditional at line 186 appropriately gates the confirmation dialog to only show when there's a meaningful change (existing conversation with different workdir). This prevents unnecessary prompts for new conversations or same-path selections.
210-221: LGTM!The return object properly exposes the new confirmation state and handlers, enabling the UI layer to implement the confirmation dialog.
src/renderer/src/components/chat-input/composables/useAgentWorkspace.ts (1)
237-243: LGTM!Clean composition pattern - exposing the ACP workdir confirmation state and methods through the unified
useAgentWorkspacefacade allows consumers to access the confirmation flow without needing to know the internal composition.src/renderer/src/components/chat-input/composables/useAcpCommands.ts (1)
18-103: LGTM! Well-structured composable with proper lifecycle management.The composable correctly:
- Uses
onMounted/onUnmountedfor IPC listener lifecycle management to prevent memory leaks- Clears commands appropriately when agent changes or when switching away from ACP model
- Uses computed properties for derived state (
isAcpModel,hasCommands)src/shared/types/presenters/llmprovider.presenter.d.ts (2)
5-10: LGTM! Import properly includesAcpSessionModelInfo.The type-only import correctly brings in the new
AcpSessionModelInfotype needed for the new model management methods.
272-304: LGTM! Well-designed API surface for ACP model management.The new methods follow the established pattern with symmetric process-level and session-level APIs:
getAcpProcessModels/setAcpPreferredProcessModelfor warmup process configurationgetAcpSessionModels/setAcpSessionModelfor active session configurationensureAcpWarmupallowsnullworkdir to support the config-warmup directory fallback described in the specAll implementations are complete and actively integrated with the renderer composables (
useAcpMode.tsanduseAcpSessionModel.ts), confirming the full feature is working end-to-end.docs/specs/acp-integration/enhancement-spec.md (1)
1-317: Well-structured design specification.The document clearly outlines the three-phase implementation plan for ACP UX enhancements:
- Mode/Model pre-fetch via warmup directory
- Available commands UI exposure
- Workdir switching with confirmation dialog
The API designs align with the interface changes in
llmprovider.presenter.d.ts.docs/specs/acp-integration/ux-issues-research.md (1)
1-388: Comprehensive UX research document.This research document provides excellent context for the design decisions, including:
- Analysis of the two-layer mode system (warmup vs session)
- Root cause identification for mode/model pre-loading issues
- Prioritized recommendations with feasibility ratings
The recommended solution (internal tmp directory for warmup) is now implemented as
ensureAcpWarmup(agentId, workdir: null)in the presenter interface.src/main/presenter/llmProviderPresenter/providers/acpProvider.ts (7)
343-355: LGTM! COMMANDS_UPDATE event emission is well-placed.The event emission is conditionally triggered only when
availableCommandsis present and non-empty, preventing unnecessary IPC traffic.
381-393: LGTM! SESSION_MODELS_READY event follows the same pattern as SESSION_MODES_READY.The implementation is consistent with the existing modes notification at lines 367-379, maintaining symmetry between mode and model handling.
459-475: LGTM! ensureWarmup provides a clean abstraction for pre-session model/mode discovery.The null coalescing to
getConfigWarmupDir()allows fetching modes/models before a user selects a workdir, which is a useful UX improvement for the ACP agent selection flow.
489-499: LGTM! getProcessModels mirrors getProcessModes for consistency.The method signature and implementation follow the established pattern.
515-527: LGTM! setPreferredProcessModel follows the setPreferredProcessMode pattern.Error handling is consistent with the mode counterpart at lines 501-513.
1188-1236: LGTM! setSessionModel is well-implemented with proper validation and notifications.The implementation:
- Validates session existence
- Logs available models for debugging
- Warns when requested model isn't in available list (but doesn't block - good for flexibility)
- Updates both session and process handle state
- Notifies renderer via SESSION_MODELS_READY event
- Has comprehensive error handling with re-throw
This mirrors the
setSessionModeimplementation pattern exactly, maintaining consistency.
1264-1288: LGTM! getSessionModels mirrors getSessionModes implementation.The method provides proper null handling and informative logging for debugging.
src/main/presenter/agentPresenter/acp/acpProcessManager.ts (11)
33-38: LGTM! AcpProcessHandle extension for model support.The interface extension cleanly adds model tracking fields alongside the existing mode fields, maintaining consistency.
152-203: Good implementation of config warmup directory management.The
getConfigWarmupDircreates a dedicated directory under userData for fetching modes/models before workdir selection. ThecleanupConfigWarmupDirproperly handles nested directories and files with appropriate error handling.One minor consideration: The cleanup iterates synchronously which could block if there are many files, but for a warmup directory this is unlikely to be an issue.
241-243: LGTM! Consistent application of preferred model alongside preferred mode.The warmup flow now applies both preferred mode and model to handles, ensuring user preferences are respected across all reuse paths (existing handle, inflight handle, and newly spawned handle).
Also applies to: 257-259, 273-275, 301-303
332-347: LGTM! setPreferredModel follows the setPreferredMode pattern exactly.The implementation correctly:
- Stores the preference keyed by agent+workdir
- Applies to existing warmup handles if available
- Notifies renderer of the change
419-420: Good practice: Cleanup warmup directory on shutdown.This prevents disk space accumulation from orphaned warmup files across application restarts.
463-465: LGTM! Model readiness notification added to bindProcess.The renderer is now notified of both modes and models when a process is bound to a conversation, enabling proper UI state initialization.
504-524: LGTM! getProcessModels mirrors getProcessModes implementation.The method follows the established pattern for retrieving process-level state.
647-658: LGTM! Model data mapping from init response.The mapping correctly transforms
modelIdtoidand provides sensible defaults fornameanddescriptionfields.
1061-1079: LGTM! Model handling in fetchProcessModes.The implementation correctly:
- Maps model data with proper field transformation
- Preserves user-selected preferred model if it exists in available list
- Falls back to agent's current model or first available
- Notifies renderer of model readiness
This mirrors the mode handling logic below it.
1130-1140: LGTM! notifyModelsReady follows notifyModesReady pattern.The guard condition and event payload structure are consistent with the mode notification at lines 1118-1128.
1197-1201: LGTM! applyPreferredModel helper mirrors applyPreferredMode.Simple and consistent implementation.
src/renderer/src/components/chat-input/composables/useAcpMode.ts (4)
34-34: LGTM! Clean extraction of agentId as a computed property.This provides a reusable reference for the current agent's ID throughout the composable.
66-69: LGTM! Explicit state reset on empty/failed results.Previously, the state might remain stale if
loadModesreturned no results. Explicitly resetting to defaults ensures consistent UI state.
155-161: LGTM! Agent change resets state appropriately.This prevents stale mode data from a previous agent from bleeding into the new agent's UI state. The guard
if (!newId || newId === oldId) returnprevents unnecessary resets.
209-254: LGTM! Clean refactor separating setMode from cycleMode.The
setModefunction now handles the core logic of mode changes, whilecycleModefocuses solely on computing the next mode ID. This separation of concerns improves testability and enables direct mode selection from UI dropdowns.src/renderer/src/components/chat-input/ChatInput.vue (9)
94-146: LGTM! ACP agent selection UI in mode popover.The implementation provides clear visual distinction between the generic "agent" mode and specific ACP agents. Model icons and selection checkmarks improve discoverability.
289-335: LGTM! ACP mode selector refactored to use popover.The dropdown approach is more user-friendly than cycling, especially when agents support multiple modes. The disabled state during loading prevents race conditions.
377-386: LGTM! Conditional badge rendering based on ACP session model state.Hiding the model tags when showing ACP session model selector prevents visual clutter and confusion.
391-426: LGTM! ACP session model selector integration.The selector follows the same UI patterns as other selectors in the component, with proper loading states and selection indicators.
513-535: LGTM! Workdir change confirmation dialog.Using AlertDialog for the confirmation provides a clear user interaction pattern. The event handlers properly delegate to the workspace composable methods.
947-980: LGTM! ACP session model and mode handlers are well-structured.Both handlers:
- Check loading state to prevent race conditions
- Close the popover after selection
- Delegate to the respective composable methods
1037-1075: LGTM! Centralized model selection logic.
applyModelSelectionproperly handles both chat and newThread variants, routing to the appropriate update mechanism. The fallback helperspickFirstAcpModelandpickFirstNonAcpModelensure valid model state when switching between modes.
1077-1104: LGTM! Enhanced handleModeSelect with automatic model switching.When switching between agent modes, the handler automatically selects an appropriate model:
- Switching away from ACP agent → picks first non-ACP model
- Switching to ACP agent → picks first ACP model
This provides a smoother UX by preventing invalid model/mode combinations.
1106-1126: LGTM! handleAcpAgentSelect properly sets mode and applies model.The handler ensures both the chat mode and model are updated atomically, with proper persistence to chat config.
src/main/presenter/llmProviderPresenter/index.ts (4)
505-525: LGTM! Consistent error handling pattern.The
ensureAcpWarmupmethod follows the same error handling pattern as the existingwarmupAcpProcessmethod (lines 488-503), including the graceful handling of shutdown scenarios. The JSDoc clearly documents the null workdir behavior.
544-559: LGTM! Consistent with existing modes API.The
getAcpProcessModelsmethod mirrors the structure ofgetAcpProcessModes, maintaining API consistency for the ACP model layer.
568-573: LGTM! Appropriate error handling differentiation.The
setAcpPreferredProcessModelsilently returns when provider is unavailable (consistent withsetAcpPreferredProcessMode), whilesetAcpSessionModelthrows an error (consistent withsetAcpSessionMode). This distinction makes sense: process-level preferences are optional configuration, whereas session-level operations are critical path actions that should fail explicitly.Also applies to: 583-589
602-611: LGTM! Consistent null handling.The
getAcpSessionModelsmethod properly returnsnullwhen the provider is unavailable, matching the behavior ofgetAcpSessionModes.src/main/presenter/sessionPresenter/index.ts (3)
792-794: LGTM! Simple delegation.The
ensureAcpWarmupmethod properly delegates to the LLM provider presenter.
809-820: LGTM! Consistent delegate pattern.The method properly delegates to
llmProviderPresenter.getAcpProcessModelswith matching return type.
826-828: LGTM! Consistent ACP model delegates.The
setAcpPreferredProcessModel,setAcpSessionModel, andgetAcpSessionModelsmethods follow the established delegation pattern to the LLM provider presenter.Also applies to: 834-836, 845-850
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
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: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
src/renderer/settings/components/common/SearchEngineSettingsSection.vue (3)
244-256: Use English for log messages.The error log at line 254 uses Chinese (
'添加自定义搜索引擎失败:'). Per coding guidelines, all logs must be in English.Proposed fix
} catch (error) { - console.error('添加自定义搜索引擎失败:', error) + console.error('Failed to add custom search engine:', error) }
267-290: Use English for log messages.The error log at line 288 uses Chinese (
'删除自定义搜索引擎失败:'). Per coding guidelines, all logs must be in English.Proposed fix
} catch (error) { - console.error('删除自定义搜索引擎失败:', error) + console.error('Failed to delete custom search engine:', error) }
300-307: Use English for log messages.The error log at line 305 uses Chinese (
'测试搜索引擎失败:'). Per coding guidelines, all logs must be in English.Proposed fix
} catch (error) { - console.error('测试搜索引擎失败:', error) + console.error('Failed to test search engine:', error) }src/renderer/settings/App.vue (1)
4-8: Typo in CSS class name.Line 6 has
'ounded-t-none'which should be'rounded-t-none'(missing therprefix).Proposed fix
:class="[ - isMacOS ? '' : ' ounded-t-none', + isMacOS ? '' : 'rounded-t-none', isMacOS ? 'bg-window-background' : 'bg-window-background/10' ]"
🤖 Fix all issues with AI agents
In `@docs/specs/domain-chat-input/plan.md`:
- Around line 9-10: The plan currently contradicts the adapter-only submission
rule: replace the direct call to chatStore.sendMessage with an adapter
entrypoint (e.g., Conversation adapter method such as
ConversationAdapter.sendMessage or a dedicated input adapter) that then invokes
chatStore.sendMessage internally; update the wording around the submission path
to state "submissions call the Conversation adapter which forwards to the
store/presenter via its own APIs" and remove any examples or flow steps that
show direct presenter/store calls so all flows consistently reference the
adapter entrypoint.
In `@docs/specs/domain-conversation/plan.md`:
- Line 10: Fix the typo "NowledgeMem" to "KnowledgeMem" where it appears (e.g.,
in the phrase "Export/NowledgeMem、MCP/Skills") so the document correctly reads
"Export/KnowledgeMem、MCP/Skills"; update all occurrences of the misspelled
symbol in the file to maintain consistency.
In `@src/renderer/src/components/ChatAppBar.vue`:
- Around line 12-78: The icon-only Buttons (handlers: onBrowserClick,
onHistoryClick, openSettings, minimizeWindow, toggleMaximize, closeWindow) lack
screen-reader labels; add aria-label attributes bound to the same i18n strings
used for the overlays (e.g., :aria-label="t('common.browser.name')" for the
browser Button, :aria-label="t('common.history')" for history,
:aria-label="t('routes.settings')" for settings,
:aria-label="t('common.minimize')" for minimize, for toggleMaximize use the
conditional label matching the overlay (:aria-label="isMaximized ?
t('common.restore') : t('common.maximize')"), and
:aria-label="t('common.close')" for close) so assistive tech receives proper
labels.
- Around line 179-182: The onBeforeUnmount block must also cancel any pending
tooltip timer to prevent stale tooltip events; locate where the tooltip timer is
stored (e.g., a variable like tooltipTimer, tooltipTimeoutId, or similar used
with setTimeout/setInterval where updateTooltipPosition or hideTooltip is
scheduled) and add a clearTimeout/clearInterval call for that variable inside
the onBeforeUnmount callback (then null it) in addition to the existing
window.removeEventListener('resize', updateTooltipPosition) and hideTooltip()
calls.
♻️ Duplicate comments (1)
src/renderer/src/components/ChatAppBar.vue (1)
205-209: Avoid deprecated settings APIIf
openOrFocusSettingsTabis deprecated, switch to the current settings API to avoid forward-compat issues.♻️ Proposed fix
const openSettings = () => { - const windowId = window.api.getWindowId() - if (windowId != null) { - windowPresenter.openOrFocusSettingsTab(windowId) - } + windowPresenter.openOrFocusSettingsWindow() }
🧹 Nitpick comments (19)
docs/specs/domain-sync-upgrade/domain-sync-upgrade.md (2)
1-8: Consider language consistency (or bilingual headings) for the spec.Right now the title/metadata are English while the body is Chinese. If this doc is meant for broader contributors, consider aligning to one language or adding bilingual headings for clarity.
30-31: Format “开放问题” as a list for easier future updates.Even when empty, a list makes this section easier to maintain (e.g., “- None”).
docs/specs/domain-workspace-artifacts/domain-workspace-artifacts.md (1)
14-16: Add cross-links to plan/tasks for traceability.Consider linking this spec to its plan/tasks docs (if present) so readers can navigate lifecycle artifacts quickly.
docs/specs/domain-workspace-artifacts/plan.md (1)
47-49: Optional: map tests back to acceptance criteria.If you want tighter traceability, map each test item to the acceptance criteria in the spec.
docs/specs/domain-search-retrieval/domain-search-retrieval.md (2)
23-25: Consider adding more detail to user stories (optional).The user stories are clear but brief. For implementation guidance, you might optionally expand them with scenarios like:
- Expected behavior when retrieval fails
- How results integrate with conversation context
- Configuration validation feedback
However, the current level of detail is acceptable for a draft specification.
34-35: No open questions for a draft (minor observation).It's somewhat unusual for a draft specification to have no open questions, but this may indicate thorough planning. If questions arise during implementation, consider documenting them here for future reference.
src/renderer/settings/App.vue (1)
182-203: Consider moving the sort outside the forEach loop.The sorting logic (
tempArray.sort(...)) is currently inside theforEachloop, causing it to run on every iteration. While this works correctly, moving it after the loop would be more efficient.Proposed optimization
routes.forEach((route) => { // In settings window, all routes are top-level, no parent 'settings' route if (route.path !== '/' && route.meta?.titleKey) { console.log(`Adding settings route: ${route.path} with titleKey: ${route.meta.titleKey}`) tempArray.push({ title: route.meta.titleKey as string, icon: route.meta.icon as string, path: route.path, name: route.name as string, position: (route.meta.position as number) || 999, group: (route.meta.group as string) || 'system', groupPosition: (route.meta.groupPosition as number) || 999, groupTitleKey: (route.meta.groupTitleKey as string) || 'settings.groups.system' }) } - // Sort by position meta field, default to 999 if not present - tempArray.sort((a, b) => { - return a.position - b.position - }) - settingsItems.value = tempArray - console.log('Final sorted settings routes:', settingsItems.value) }) + // Sort by position meta field, default to 999 if not present + tempArray.sort((a, b) => a.position - b.position) + settingsItems.value = tempArray + console.log('Final sorted settings routes:', settingsItems.value)docs/specs/domain-conversation/plan.md (2)
38-41: Consider expanding the migration strategy section.The migration strategy is sound but brief. Consider adding:
- Rollback/compatibility plans for each phase
- Success criteria or completion signals for each step
- Dependencies between migration steps
- Timeline or sequencing constraints
This would help ensure smooth execution of this large-scale refactor.
119-124: Consider expanding the testing strategy for this large refactor.Given the scope of this refactor (6 major migration steps across multiple domains), consider adding:
- Test coverage targets for each migration step
- Regression test strategy to ensure existing functionality isn't broken
- Performance testing for message streaming and event flow
- Cross-domain integration tests verifying adapter boundaries
- Migration validation tests to verify each step's completion
- E2E test scenarios covering critical user workflows
This would provide more confidence in the refactor's correctness and completeness.
docs/specs/domain-conversation/acp-runtime.md (2)
13-27: Consider consistent typing for modes similar to models.The
getAcpProcessModelsmethod provides detailed type definitions for models (lines 17-23), butgetAcpProcessModesandgetAcpSessionModesuseanyorany[]for mode structures. For better type safety and developer clarity, consider defining explicit shapes for mode objects similar to the model definitions.📝 Suggested type definition
getAcpProcessModes( agentId: string, workdir: string -): Promise<{ availableModes?: any; currentModeId?: string } | undefined> +): Promise<{ + availableModes?: Array<{ id: string; name: string; description?: string }> + currentModeId?: string +} | undefined> getAcpSessionModes( conversationId: string -): Promise<{ current: string; available: any[] } | null> +): Promise<{ + current: string + available: Array<{ id: string; name: string; description?: string }> +} | null>
41-46: Document event payload structures for completeness.The events section lists event names but doesn't document their payload structures. For a protocol specification, including the shape of event data would help developers understand the complete contract without needing to reference implementation code.
💡 Example payload documentation
Consider adding payload type definitions:
ACP_WORKSPACE_EVENTS.SESSION_MODES_READY // Payload: { conversationId: string; current: string; available: Array<...> } ACP_WORKSPACE_EVENTS.SESSION_MODELS_READY // Payload: { conversationId: string; current: string; available: Array<...> } ACP_WORKSPACE_EVENTS.COMMANDS_UPDATE // Payload: { conversationId: string; commands: Array<...> }docs/specs/domain-conversation/protocol.md (1)
108-121: Consider documenting event payload structures.Similar to the ACP runtime protocol, documenting the payload shapes for these events would improve the completeness of the protocol specification. This would help developers understand the full contract without referencing implementation code.
docs/specs/domain-conversation/data-model.md (1)
72-76: Minor formatting inconsistency in compatibility fields list.Line 76 has an extra space before the hyphen that's inconsistent with the formatting of the list items on lines 73-75.
✨ Formatting fix
- `ConversationSettings.artifacts` - `ConversationSettings.selectedVariantsMap` - - `ConversationSettings.enabledMcpTools` / `activeSkills` 为既有命名,暂不重命名 +- `ConversationSettings.enabledMcpTools` / `activeSkills` 为既有命名,暂不重命名src/renderer/src/components/ChatAppBar.vue (3)
90-92: Use the shadcn alias import pathAlign the Button import with the project’s shadcn alias convention. As per coding guidelines, ...
♻️ Proposed fix
-import { Button } from '@shadcn/components/ui/button' +import { Button } from '@/shadcn/components/ui/button'
109-129: Route tooltip IPC through a presenterDirect
ipcRenderercalls bypass theusePresenterIPC abstraction; consider a presenter (or rendererEvents) wrapper for tooltip show/hide to keep IPC centralized. As per coding guidelines, ...
4-77: Replace scoped app-region CSS with Tailwind utilitiesThe app-region styles are in scoped CSS; consider moving them into Tailwind
@layer utilitiesand using utility class names in the template to comply with the Tailwind-only styling rule. As per coding guidelines, ...♻️ Proposed refactor
- <div - class="h-full shrink-0 w-0 flex-1 flex select-none text-center text-sm font-medium flex-row items-center justify-start window-drag-region" - > - <div v-if="!isFullscreened && isMacOS" class="shrink-0 w-20 h-full window-drag-region"></div> + <div + class="h-full shrink-0 w-0 flex-1 flex select-none text-center text-sm font-medium flex-row items-center justify-start app-region-drag" + > + <div v-if="!isFullscreened && isMacOS" class="shrink-0 w-20 h-full app-region-drag"></div> ... - <div class="flex-1 window-drag-region"></div> + <div class="flex-1 app-region-drag"></div> ... - class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" + class="app-region-no-drag shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" ... - class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" + class="app-region-no-drag shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" ... -<style scoped> -.window-drag-region { - -webkit-app-region: drag; -} - -.window-no-drag-region { - -webkit-app-region: no-drag; -} - -button { - -webkit-app-region: no-drag; -} -</style> +<style> +@layer utilities { + .app-region-drag { + -webkit-app-region: drag; + } + .app-region-no-drag { + -webkit-app-region: no-drag; + } +} +</style>Also applies to: 221-233
src/renderer/src/App.vue (3)
32-38: Persist sidebar width across sessionsConsider persisting
sidebarWidthvia VueUseuseLocalStorageso users keep their resized width. As per coding guidelines, ...♻️ Proposed fix
-import { onMounted, ref, watch, onBeforeUnmount, computed } from 'vue' +import { onMounted, ref, watch, onBeforeUnmount, computed } from 'vue' +import { useLocalStorage } from '@vueuse/core' ... -const sidebarWidth = ref(DEFAULT_SIDEBAR_WIDTH) +const sidebarWidth = useLocalStorage('sidebarWidth', DEFAULT_SIDEBAR_WIDTH)Also applies to: 300-300
130-133: Handle potential async navigation errorsIf
navigateToConversationis async, attach error handling (or explicitlyawait) to avoid unhandled rejections.♻️ Proposed fix
-const handleSidebarConversationSelect = (conversationId: string) => { - navigateToConversation(conversationId) -} +const handleSidebarConversationSelect = async (conversationId: string) => { + try { + await navigateToConversation(conversationId) + } catch (error) { + console.error('Failed to navigate to conversation.', error) + } +}
169-186: Attach resize listeners only while resizingYou can avoid global mouse listeners by registering them on drag start and removing them on drag end.
♻️ Proposed refactor
const startResize = (e: MouseEvent) => { isResizing.value = true e.preventDefault() + window.addEventListener('mousemove', handleMouseMove) + window.addEventListener('mouseup', stopResize) } const stopResize = () => { isResizing.value = false + window.removeEventListener('mousemove', handleMouseMove) + window.removeEventListener('mouseup', stopResize) } onMounted(() => { window.addEventListener('keydown', handleEscKey) - window.addEventListener('mousemove', handleMouseMove) - window.addEventListener('mouseup', stopResize) }) onBeforeUnmount(() => { window.removeEventListener('keydown', handleEscKey) - window.removeEventListener('mousemove', handleMouseMove) - window.removeEventListener('mouseup', stopResize) })Also applies to: 196-197, 270-271
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/renderer/settings/App.vue (2)
6-6: Typo in CSS class:ounded-t-noneshould berounded-t-none.The leading space before
ounded-t-noneand the missingrwill cause the rounded corner styling to not apply on non-macOS platforms.🐛 Proposed fix
- isMacOS ? '' : ' ounded-t-none', + isMacOS ? '' : 'rounded-t-none',
199-220: Move sorting and assignment outside theforEachloop.The sorting and assignment to
settingsItems.valueare inside theforEachloop, causing them to execute on every iteration. This is inefficient and wastes cycles.♻️ Proposed fix
routes.forEach((route) => { // In settings window, all routes are top-level, no parent 'settings' route if (route.path !== '/' && route.meta?.titleKey) { console.log(`Adding settings route: ${route.path} with titleKey: ${route.meta.titleKey}`) tempArray.push({ title: route.meta.titleKey as string, icon: route.meta.icon as string, path: route.path, name: route.name as string, position: (route.meta.position as number) || 999, group: (route.meta.group as string) || 'system', groupPosition: (route.meta.groupPosition as number) || 999, groupTitleKey: (route.meta.groupTitleKey as string) || 'settings.groups.system' }) } - // Sort by position meta field, default to 999 if not present - tempArray.sort((a, b) => { - return a.position - b.position - }) - settingsItems.value = tempArray - console.log('Final sorted settings routes:', settingsItems.value) }) + // Sort by position meta field, default to 999 if not present + tempArray.sort((a, b) => a.position - b.position) + settingsItems.value = tempArray + console.log('Final sorted settings routes:', settingsItems.value)
♻️ Duplicate comments (1)
src/main/presenter/sessionPresenter/index.ts (1)
959-960: DefaultresolvedChatModebehavioral change previously flagged.This change defaults
resolvedChatModeto'agent'instead of'chat'whenconversation.settings.chatModeis undefined. The implications of this breaking change for existing user sessions have been raised in a prior review.
🧹 Nitpick comments (2)
src/main/presenter/sessionPresenter/index.ts (1)
849-851: Add explicit return type for consistency.Other similar methods in this file (e.g.,
setAcpSessionModelat line 857) have explicitPromise<void>return type annotations. Consider adding it here for consistency.♻️ Suggested fix
- async setAcpPreferredProcessModel(agentId: string, workdir: string, modelId: string) { + async setAcpPreferredProcessModel(agentId: string, workdir: string, modelId: string): Promise<void> { await this.llmProviderPresenter.setAcpPreferredProcessModel(agentId, workdir, modelId) }src/renderer/settings/App.vue (1)
187-221: Consider consolidating the twoonMountedhooks for clarity.The component has two separate
onMountedhooks (lines 187 and 278). While valid in Vue 3, consolidating them into a single hook would improve readability and make the initialization flow clearer.Also applies to: 278-328
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/main/presenter/agentPresenter/index.ts (1)
386-401: Unhandled promise rejection: try/catch won't catch async errors.The try/catch block wrapping the promise chain is ineffective. Synchronous try/catch cannot catch rejections from a promise chain that is not awaited. If
generateTitleorrenameConversationfails, this results in an unhandled promise rejection.Use the established
void promise.catch(...)pattern consistent with other fire-and-forget calls in this file (e.g., lines 173-182).🔧 Proposed fix
if (conversation.is_new === 1) { - try { - this.sessionPresenter - .generateTitle(state.conversationId) - .then((title) => { - return this.sessionPresenter.renameConversation(state.conversationId, title) - }) - .then(() => { - console.log('title updated') - }) - } catch (error) { - console.error('[AgentPresenter] Failed to summarize title', { - conversationId: state.conversationId, - err: error - }) - } + void this.sessionPresenter + .generateTitle(state.conversationId) + .then((title) => { + return this.sessionPresenter.renameConversation(state.conversationId, title) + }) + .then(() => { + console.log('[AgentPresenter] title updated') + }) + .catch((error) => { + console.error('[AgentPresenter] Failed to summarize title', { + conversationId: state.conversationId, + err: error + }) + }) }
…n tracking - Add provider initialization tracking to modelStore to handle timing issues - Create useModelSelection composable to centralize model selection logic - Implement smart fallback strategy: use fallback model when provider not ready, then automatically switch to preferred model when provider initializes - Refactor NewThread.vue to use new composable, reducing complexity significantly - Fixes issue where preferred model was lost if provider wasn't initialized yet
- Remove model selection state from NewThread component - Use chatStore.chatConfig for providerId/modelId when creating conversations - Remove console.log and handleModelUpdate function - Simplify NewThread by delegating model management to chatStore
…ettingsWindow - Update all components to use new openOrFocusSettingsWindow() API - Remove deprecated openOrFocusSettingsTab() method from WindowPresenter - Update IWindowPresenter interface to reflect new method signature - Fix tooltip timer cleanup in ChatAppBar onBeforeUnmount - Rename openSettingsTab to openSettingsWindow in useWindowAdapter
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
🤖 Fix all issues with AI agents
In `@src/main/presenter/windowPresenter/index.ts`:
- Around line 134-137: The shortcut handler currently calls the async method
createChatWindow() without handling its returned Promise, which can cause
unhandled rejections; update the shortcut callback in the window presenter to
either await createChatWindow() inside an async handler or explicitly suppress
the Promise with void (e.g., void this.createChatWindow()), and add a try/catch
around the awaited call to log or handle errors from createChatWindow() so
failures don't produce unhandled rejection warnings.
- Around line 1725-1728: The chatWindow.loadFile call is passing the renderer
directory instead of the HTML file referenced in the log; update the call so
chatWindow.loadFile receives the concrete HTML path (i.e., the same path used in
the console.log: join(__dirname, '../renderer/index.html')) to match other
usages (see chatWindow.loadFile and the console.log message) and ensure the
renderer loads correctly.
♻️ Duplicate comments (2)
src/renderer/src/components/ChatAppBar.vue (1)
12-78: Add aria-labels for icon-only controlsIcon-only buttons are missing accessible names; screen readers won’t announce their purpose. Bind
aria-labelto the same i18n strings used for tooltips.♿ Proposed fix (aria-labels)
<Button size="icon" + :aria-label="t('common.browser.name')" class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" `@click`="onBrowserClick" `@mouseenter`="onOverlayMouseEnter('browser', t('common.browser.name'), $event)" `@mouseleave`="onOverlayMouseLeave('browser')" > <Icon icon="lucide:compass" class="w-4 h-4" /> </Button> <Button size="icon" + :aria-label="t('common.history')" class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" `@click`="onHistoryClick" `@mouseenter`="onOverlayMouseEnter('history', t('common.history'), $event)" `@mouseleave`="onOverlayMouseLeave('history')" > <Icon icon="lucide:history" class="w-4 h-4" /> </Button> <Button size="icon" + :aria-label="t('routes.settings')" class="window-no-drag-region shrink-0 w-10 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" `@click`="openSettings" `@mouseenter`="onOverlayMouseEnter('settings', t('routes.settings'), $event)" `@mouseleave`="onOverlayMouseLeave('settings')" > <Icon icon="lucide:ellipsis" class="w-4 h-4" /> </Button> <Button v-if="!isMacOS" + :aria-label="t('common.minimize')" class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" `@click`="minimizeWindow" `@mouseenter`="onOverlayMouseEnter('minimize', t('common.minimize'), $event)" `@mouseleave`="onOverlayMouseLeave('minimize')" > <MinimizeIcon class="h-3! w-3!" /> </Button> <Button v-if="!isMacOS" + :aria-label="isMaximized ? t('common.restore') : t('common.maximize')" class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-card/80 text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" `@click`="toggleMaximize" `@mouseenter`=" onOverlayMouseEnter( 'toggle-maximize', isMaximized ? t('common.restore') : t('common.maximize'), $event ) " `@mouseleave`="onOverlayMouseLeave('toggle-maximize')" > <MaximizeIcon v-if="!isMaximized" class="h-3! w-3!" /> <RestoreIcon v-else class="h-3! w-3!" /> </Button> <Button v-if="!isMacOS" + :aria-label="t('common.close')" class="window-no-drag-region shrink-0 w-12 bg-transparent shadow-none rounded-none hover:bg-red-700/80 hover:text-white text-xs font-medium text-foreground flex items-center justify-center transition-all duration-200 group" `@click`="closeWindow" `@mouseenter`="onOverlayMouseEnter('close-window', t('common.close'), $event)" `@mouseleave`="onOverlayMouseLeave('close-window')" > <CloseIcon class="h-3! w-3!" /> </Button>src/main/presenter/windowPresenter/index.ts (1)
1641-1644: Shared chat window state file still causes collisions.
This is the same issue flagged earlier: all chat windows write tochat-window-state.json, so multiple windows overwrite each other’s state. Please switch to a per-window filename.
🧹 Nitpick comments (3)
src/renderer/src/components/ChatAppBar.vue (3)
90-92: Use the standard shadcn alias for ButtonThe import should use the
@/shadcn/components/ui/alias to match the repo conventions.As per coding guidelines, please align shadcn imports with the configured alias.♻️ Proposed fix
-import { Button } from '@shadcn/components/ui/button' +import { Button } from '@/shadcn/components/ui/button'
109-129: Route tooltip IPC through a presenter/event busDirect
ipcRenderer.sendbypasses the renderer↔main abstraction. Consider a presenter (or EventBus) wrapper forshell-tooltip:show/hideso IPC stays centralized and testable. Based on learnings, please useusePresenterfor main-process communication.
222-233: Move window-drag styles to Tailwind utilitiesThe scoped CSS block should be replaced with Tailwind utility classes (e.g.,
[-webkit-app-region:drag]/[-webkit-app-region:no-drag]) to keep styling consistent with the project’s Tailwind-only rule. As per coding guidelines, please avoid scoped CSS for styling.
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 (3)
src/renderer/settings/App.vue (3)
5-8: Fix the typo in the non‑macOS class name.Line 6 uses
ounded-t-none(missingr), so the class never applies.🩹 Proposed fix
- isMacOS ? '' : ' ounded-t-none', + isMacOS ? '' : 'rounded-t-none',
206-214: Preserve explicit0positions in route meta.Line 211 and Line 213 use
|| 999, which treats0as “missing” and reorders items unexpectedly. Use??for numeric defaults.🩹 Proposed fix
- position: (route.meta.position as number) || 999, + position: (route.meta.position as number) ?? 999, group: (route.meta.group as string) || 'system', - groupPosition: (route.meta.groupPosition as number) || 999, + groupPosition: (route.meta.groupPosition as number) ?? 999, groupTitleKey: (route.meta.groupTitleKey as string) || 'settings.groups.system'
240-247: Title can stay generic until navigation.
updateTitle()runs beforesettingsItemsis populated, and the watcher only reacts to route changes. Initial titles can stay as “Settings” until navigation. WatchsettingsItemstoo (or callupdateTitle()after the list is set).🩹 Proposed fix
-watch( - () => route.name, - () => { - updateTitle() - }, - { immediate: true } -) +watch( + [() => route.name, settingsItems], + () => { + updateTitle() + }, + { immediate: true } +)
🤖 Fix all issues with AI agents
In `@src/renderer/settings/App.vue`:
- Around line 337-346: onBeforeUnmount currently always calls
window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE,
handleSettingsNavigate) which can throw when window.electron is missing; mirror
the registration guard by first checking that window.electron and
window.electron.ipcRenderer exist before calling removeListener for
SETTINGS_EVENTS.NAVIGATE and handleSettingsNavigate, and leave the existing
cleanupErrorNotifications and cleanupSearchEngineListeners nulling as-is.
🧹 Nitpick comments (7)
docs/specs/renderer-store-composables-rules/plan.md (1)
7-27: Define category taxonomy + dependency direction explicitly to reduce ambiguity.Right now “UI/App/Adapter/Store” and dependency direction are implied but not spelled out. A short definition block will prevent inconsistent classification during the “现状盘点” phase.
♻️ Suggested addition
## 计划步骤 +### 定义与依赖方向(建议补充) +- UI: 仅视图与交互;禁止直接调用 Store/Adapter 内部实现。 +- App Composable: 编排流程与跨域协作;可调用 Store 与 Adapter。 +- Adapter Composable: 进程/IPC/外部系统边界;仅暴露最小 API 给 App。 +- Store: 状态与异步动作;禁止直接操作 UI 或 IPC。 +- 依赖方向:UI -> App -> Adapter/Store(单向)docs/specs/renderer-store-composables-rules/audit.md (3)
7-8: Consider adding English translation for consistency.The objectives section is only in Chinese, while the rest of the document mixes both languages. For better accessibility across the team, consider adding an English version of the objectives.
📝 Suggested addition
## 目标 +## Objectives 通过"重复性与必要性审计"确定权威入口,合并或移除重复职责,避免并行执行链。 +Identify authoritative entry points through "redundancy and necessity audit", merge or remove duplicate responsibilities, and avoid parallel execution chains.
17-19: Enhance next batch items with actionable details.The pending items lack specific details like file paths, assignees, priority, or links to tracking issues. Adding these would make the audit more actionable and easier to track.
📋 Suggested enhancements
Consider adding:
- File paths for each composable mentioned (e.g.,
src/renderer/src/composables/useCleanDialog.ts)- Priority levels (P0/P1/P2) for next batch items
- Assignees or team ownership
- Links to related GitHub issues for tracking
- Estimated effort or timeline
Example format:
### 仍需处理(下一批次) - **P1** `useCleanDialog` (`src/renderer/src/composables/useCleanDialog.ts`): UI 与流程耦合,建议拆为 UI Composable + App Composable。 - Assignee: [Name/Team] - Related issue: #[issue-number] - **P2** `useSearchResultState`: 混合 UI 状态与流程编排,建议拆分并明确权威入口。 - Assignee: [Name/Team] - Related issue: #[issue-number]
21-23: Consider expanding the authoritative entry points snapshot.While the current snapshot provides a useful quick reference, it could be more helpful with additional context such as file paths, usage guidelines, and examples.
📚 Suggested enhancement
## 权威入口清单(快照) -- Chat retry: `chatStore.retryFromUserMessage` -- Notifications: `useNotificationAdapter` / `useNotificationToasts` + +### Chat retry +- **Entry point**: `chatStore.retryFromUserMessage` +- **Location**: `src/renderer/src/stores/chatStore.ts` +- **Usage**: Call this method to retry a chat message from a user message node + +### Notifications +- **System notifications**: `useNotificationAdapter.showSystemNotification` + - **Location**: `src/renderer/src/composables/useNotificationAdapter.ts` + - **Usage**: Display OS-level system notifications +- **UI Toasts**: `useNotificationToasts.showErrorToast` + - **Location**: `src/renderer/src/composables/useNotificationToasts.ts` + - **Usage**: Display in-app error toast messagesscripts/check-renderer-adapters.mjs (1)
41-44: Consider handling inline comments.The current regex
^\s*\/\/.*$only strips full-line comments but misses inline comments (e.g.,const x = 1 // usePresenter deprecated). This could cause false positives if boundary patterns appear in trailing comments.♻️ Optional enhancement to strip inline comments
const stripComments = (source) => { const withoutBlock = source.replace(/\/\*[\s\S]*?\*\//g, '') - return withoutBlock.replace(/^\s*\/\/.*$/gm, '') + // Remove full-line comments and inline comments (outside strings - simplified approach) + return withoutBlock.replace(/\/\/.*$/gm, '') }Note: A fully accurate approach would need to handle strings containing
//, but the simplified version above covers most cases.src/renderer/settings/components/skills/SyncStatusSection.vue (1)
95-100: Remove the unusedtypefield from theshowErrorToastcall.The
typefield is defined as a required property in theErrorNotificationtype, but it's never actually used in the toast implementation—error styling is determined solely byvariant: 'destructive'. This suggests either removing the field from the type definition or making it optional if it's not needed.src/renderer/settings/App.vue (1)
218-223: Move sorting/assignment outside the loop.Sorting and assigning on every iteration causes repeated sorts, reactive updates, and “Final sorted” logs. Move them after the loop.
♻️ Suggested refactor
routes.forEach((route) => { // In settings window, all routes are top-level, no parent 'settings' route if (route.path !== '/' && route.meta?.titleKey) { console.log(`Adding settings route: ${route.path} with titleKey: ${route.meta.titleKey}`) tempArray.push({ title: route.meta.titleKey as string, icon: route.meta.icon as string, path: route.path, name: route.name as string, position: (route.meta.position as number) || 999, group: (route.meta.group as string) || 'system', groupPosition: (route.meta.groupPosition as number) || 999, groupTitleKey: (route.meta.groupTitleKey as string) || 'settings.groups.system' }) } - // Sort by position meta field, default to 999 if not present - tempArray.sort((a, b) => { - return a.position - b.position - }) - settingsItems.value = tempArray - console.log('Final sorted settings routes:', settingsItems.value) }) + // Sort by position meta field, default to 999 if not present + tempArray.sort((a, b) => { + return a.position - b.position + }) + settingsItems.value = tempArray + console.log('Final sorted settings routes:', settingsItems.value)
| onBeforeUnmount(() => { | ||
| if (errorDisplayTimer.value) { | ||
| clearTimeout(errorDisplayTimer.value) | ||
| errorDisplayTimer.value = null | ||
| if (cleanupErrorNotifications) { | ||
| cleanupErrorNotifications() | ||
| cleanupErrorNotifications = null | ||
| } | ||
| if (cleanupSearchEngineListeners) { | ||
| cleanupSearchEngineListeners() | ||
| cleanupSearchEngineListeners = null | ||
| } | ||
| window.electron.ipcRenderer.removeAllListeners(NOTIFICATION_EVENTS.SHOW_ERROR) | ||
| window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE, handleSettingsNavigate) |
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.
Guard IPC removal in non‑electron/test contexts.
You guard registration on Line 140; removal should match to avoid runtime errors when window.electron is absent.
🩹 Proposed fix
- window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE, handleSettingsNavigate)
+ if (window?.electron?.ipcRenderer) {
+ window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE, handleSettingsNavigate)
+ }📝 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.
| onBeforeUnmount(() => { | |
| if (errorDisplayTimer.value) { | |
| clearTimeout(errorDisplayTimer.value) | |
| errorDisplayTimer.value = null | |
| if (cleanupErrorNotifications) { | |
| cleanupErrorNotifications() | |
| cleanupErrorNotifications = null | |
| } | |
| if (cleanupSearchEngineListeners) { | |
| cleanupSearchEngineListeners() | |
| cleanupSearchEngineListeners = null | |
| } | |
| window.electron.ipcRenderer.removeAllListeners(NOTIFICATION_EVENTS.SHOW_ERROR) | |
| window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE, handleSettingsNavigate) | |
| onBeforeUnmount(() => { | |
| if (cleanupErrorNotifications) { | |
| cleanupErrorNotifications() | |
| cleanupErrorNotifications = null | |
| } | |
| if (cleanupSearchEngineListeners) { | |
| cleanupSearchEngineListeners() | |
| cleanupSearchEngineListeners = null | |
| } | |
| if (window?.electron?.ipcRenderer) { | |
| window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE, handleSettingsNavigate) | |
| } |
🤖 Prompt for AI Agents
In `@src/renderer/settings/App.vue` around lines 337 - 346, onBeforeUnmount
currently always calls
window.electron.ipcRenderer.removeListener(SETTINGS_EVENTS.NAVIGATE,
handleSettingsNavigate) which can throw when window.electron is missing; mirror
the registration guard by first checking that window.electron and
window.electron.ipcRenderer exist before calling removeListener for
SETTINGS_EVENTS.NAVIGATE and handleSettingsNavigate, and leave the existing
cleanupErrorNotifications and cleanupSearchEngineListeners nulling as-is.
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
🤖 Fix all issues with AI agents
In `@src/main/presenter/agentPresenter/index.ts`:
- Around line 365-372: The promise chain using
this.sessionPresenter.generateTitle(state.conversationId).then(...).then(...)
can produce unhandled rejections; modify the code that calls generateTitle and
renameConversation (on sessionPresenter) to handle failures by either awaiting
the chain inside the surrounding async function or appending a .catch(...) to
the chain (and optionally prefixing with void if keeping it fire-and-forget).
Ensure the .catch logs or forwards the error (e.g., via processLogger or
console.error) and references generateTitle and renameConversation so any
rejection is handled and doesn't bypass the outer try/catch.
🧹 Nitpick comments (2)
src/main/presenter/agentPresenter/message/messageBuilder.ts (1)
99-109: Consider removing or adjusting the debug log.The
console.log('store chat mode', storedChatMode)on line 104 appears to be debug output. Consider removing it or using a conditional log gated by a debug flag to avoid polluting production logs.The chat mode normalization logic (
'chat'→'agent') and the fallback chain are correctly implemented.🔧 Suggested change
const storedChatMode = presenter.configPresenter.getSetting('input_chatMode') as | 'chat' | 'agent' | 'acp agent' | undefined - console.log('store chat mode', storedChatMode) const normalizedChatMode = storedChatMode === 'chat' ? 'agent' : storedChatModesrc/main/presenter/index.ts (1)
411-423: Consider extracting the fallback logic to a helper.The
BrowserWindowfallback pattern for resolvingwindowIdis duplicated here and in the success path (lines 361-368). While not critical, extracting this to a small helper function would improve maintainability.♻️ Optional refactor to reduce duplication
+// Helper to resolve windowId from WebContents +function resolveWindowId(tabPresenter: ITabPresenter, webContentsId: number, sender: Electron.WebContents): number | undefined { + let windowId = tabPresenter.getWindowIdByWebContentsId(webContentsId) + if (windowId === undefined) { + const browserWindow = BrowserWindow.fromWebContents(sender) + if (browserWindow && !browserWindow.isDestroyed()) { + windowId = browserWindow.id + } + } + return windowId +} // Then use in both places: - let windowId = presenter.tabPresenter.getWindowIdByWebContentsId(webContentsId) - if (windowId === undefined) { - const browserWindow = BrowserWindow.fromWebContents(event.sender) - if (browserWindow && !browserWindow.isDestroyed()) { - windowId = browserWindow.id - } - } + const windowId = resolveWindowId(presenter.tabPresenter, webContentsId, event.sender)
| this.sessionPresenter | ||
| .generateTitle(state.conversationId) | ||
| .then((title) => { | ||
| return this.sessionPresenter.renameConversation(state.conversationId, title) | ||
| }) | ||
| .then(() => { | ||
| console.log('title updated') | ||
| }) |
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.
Handle async title-generation failures to avoid unhandled rejections.
The promise chain isn’t awaited and lacks .catch, so errors bypass the try/catch. Add a rejection handler (and optionally void the chain) to prevent unhandled rejections.
🐛 Proposed fix
- try {
- this.sessionPresenter
- .generateTitle(state.conversationId)
- .then((title) => {
- return this.sessionPresenter.renameConversation(state.conversationId, title)
- })
- .then(() => {
- console.log('title updated')
- })
- } catch (error) {
- console.error('[AgentPresenter] Failed to summarize title', {
- conversationId: state.conversationId,
- err: error
- })
- }
+ void this.sessionPresenter
+ .generateTitle(state.conversationId)
+ .then((title) => {
+ return this.sessionPresenter.renameConversation(state.conversationId, title)
+ })
+ .then(() => {
+ console.log('[AgentPresenter] Title updated')
+ })
+ .catch((error) => {
+ console.error('[AgentPresenter] Failed to summarize title', {
+ conversationId: state.conversationId,
+ err: error
+ })
+ })📝 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.
| this.sessionPresenter | |
| .generateTitle(state.conversationId) | |
| .then((title) => { | |
| return this.sessionPresenter.renameConversation(state.conversationId, title) | |
| }) | |
| .then(() => { | |
| console.log('title updated') | |
| }) | |
| void this.sessionPresenter | |
| .generateTitle(state.conversationId) | |
| .then((title) => { | |
| return this.sessionPresenter.renameConversation(state.conversationId, title) | |
| }) | |
| .then(() => { | |
| console.log('[AgentPresenter] Title updated') | |
| }) | |
| .catch((error) => { | |
| console.error('[AgentPresenter] Failed to summarize title', { | |
| conversationId: state.conversationId, | |
| err: error | |
| }) | |
| }) |
🤖 Prompt for AI Agents
In `@src/main/presenter/agentPresenter/index.ts` around lines 365 - 372, The
promise chain using
this.sessionPresenter.generateTitle(state.conversationId).then(...).then(...)
can produce unhandled rejections; modify the code that calls generateTitle and
renameConversation (on sessionPresenter) to handle failures by either awaiting
the chain inside the surrounding async function or appending a .catch(...) to
the chain (and optionally prefixing with void if keeping it fire-and-forget).
Ensure the .catch logs or forwards the error (e.g., via processLogger or
console.error) and references generateTitle and renameConversation so any
rejection is handled and doesn't bypass the outer try/catch.
- Redesigned splash window to a compact 320x80px transparent window with logo and progress bar - Deferred splash creation by 1s to avoid unnecessary splash on fast startups - Added progress state buffering to prevent missing updates when renderer not ready - Removed circular loader animation in favor of clean linear progress bar - Improved window configuration: transparent, frameless, unfocusable, no shadow - Added proper preload support for splash window - Removed artificial delays for faster, more responsive splash UX
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
🤖 Fix all issues with AI agents
In `@docs/specs/splash-window-ux/plan.md`:
- Around line 31-33: Add automated tests for the timing-sensitive splash logic:
create unit tests for SplashWindowManager that use fake timers to assert delayed
creation behavior (verify no BrowserWindow created before the 1s threshold and
created after), test progress caching by sending progress events before window
creation and asserting cached values are applied when createSplashWindow runs,
and test dismissal by simulating the app window ready/loaded events to ensure
splash removal; add integration-style tests that mock Electron BrowserWindow/IPC
to simulate fast vs slow startup scenarios and verify IPC event flow (progress
updates and close messages) between SplashWindowManager and the splash window.
Ensure tests reference SplashWindowManager, createSplashWindow,
scheduleDelayedSplash, handleProgressUpdate, and dismissSplash (or the
equivalent method names) and use Electron mocks and timer stubs to
deterministically reproduce timing edge cases.
In `@docs/specs/splash-window-ux/spec.md`:
- Around line 25-29: Update the "Acceptance Criteria" section so each item is
specific and testable: replace "compact (narrow bar)" with explicit dimensions
(e.g., height 48px, width 360px, or allowable range), define status update
behavior for "status text" (e.g., updates no faster than 250ms and on each
lifecycle progress event), specify visual details (background color hex, padding
in px, alignment/positioning like centered top-right with 16px margin), and add
edge-case criteria covering: failure to create splash (fallback behavior and
error logging), main window closing while splash is shown (expected transition
or auto-close behavior), and validation of the "1s" threshold (how to measure
startup completion — use monotonic timer and tolerance ±50ms and automated test
hook). Ensure you reference the existing acceptance items (e.g., "If startup
completes..." and "If no window exists after 1s...") when replacing them so the
new criteria directly map to the original bullets.
🧹 Nitpick comments (2)
docs/skills/deepchat-sdd-skills/SKILL.md (2)
14-16: Reduce repetitive sentence starts in Usage bullets.Optional rewording to improve readability.
✏️ Proposed wording tweak
- - You need a reliable `spec.md` / `plan.md` / `tasks.md` set under `docs/specs/<feature>/`. - - You are about to implement a non-trivial change and want spec → plan → code traceability. - - You need to clarify scope, risks, IPC surface, and test strategy before coding. + - Create a reliable `spec.md` / `plan.md` / `tasks.md` set under `docs/specs/<feature>/`. + - Prepare for non-trivial changes that need spec → plan → code traceability. + - Clarify scope, risks, IPC surface, and test strategy before coding.
205-210: Consider adding PR checklist items to DoD.If this template is the standard guardrail, include the repo’s PR expectations (issue linking, screenshots for UI changes) so they’re not missed.
✅ Proposed DoD addition
- Acceptance criteria satisfied (ideally with tests) - No unresolved `[NEEDS CLARIFICATION]` - i18n applied to user-facing strings - Security/privacy constraints met (no secrets leaked; IPC surface minimal) +- PR description includes `Closes #...` when applicable +- UI changes include BEFORE/AFTER screenshots or ASCII layout blocks - `pnpm run format && pnpm run lint && pnpm run typecheck` pass locally - Tests for critical paths pass (`pnpm test` or targeted suites)Based on learnings, ...
| ## Test strategy (pragmatic) | ||
| - Manual: verify fast start shows no splash; slow start shows compact splash with updating text. | ||
| - Optional later: main-process unit test via Electron mocks for delayed splash scheduling. |
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
Strengthen the test strategy beyond manual-only testing.
The test strategy relies solely on manual verification with unit tests marked as "optional later." Given the timing-sensitive logic (1s delay threshold, window existence checks, progress caching), automated tests should be part of the implementation to prevent regressions.
Consider adding:
- Unit tests for SplashWindowManager's delayed creation logic and progress caching
- Integration tests to verify splash creation conditions (fast vs. slow startup scenarios)
- Tests for IPC event flow and splash dismissal
🤖 Prompt for AI Agents
In `@docs/specs/splash-window-ux/plan.md` around lines 31 - 33, Add automated
tests for the timing-sensitive splash logic: create unit tests for
SplashWindowManager that use fake timers to assert delayed creation behavior
(verify no BrowserWindow created before the 1s threshold and created after),
test progress caching by sending progress events before window creation and
asserting cached values are applied when createSplashWindow runs, and test
dismissal by simulating the app window ready/loaded events to ensure splash
removal; add integration-style tests that mock Electron BrowserWindow/IPC to
simulate fast vs slow startup scenarios and verify IPC event flow (progress
updates and close messages) between SplashWindowManager and the splash window.
Ensure tests reference SplashWindowManager, createSplashWindow,
scheduleDelayedSplash, handleProgressUpdate, and dismissSplash (or the
equivalent method names) and use Electron mocks and timer stubs to
deterministically reproduce timing edge cases.
| ## Acceptance Criteria | ||
| - [ ] If startup completes and at least one non-splash window exists within 1s, splash is never created. | ||
| - [ ] If no window exists after 1s and startup is still running, splash is created and shown. | ||
| - [ ] Splash displays DeepChat icon and a status text that updates as lifecycle progress updates arrive. | ||
| - [ ] Splash window is compact (narrow bar) and avoids white/blank flashes. |
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
Make acceptance criteria more specific and measurable.
The acceptance criteria include subjective terms like "compact (narrow bar)" without concrete dimensions or measurements. To ensure consistent implementation and testability, consider specifying:
- Exact window dimensions or dimension ranges for the "narrow bar"
- Expected update frequency or conditions for status text updates
- Visual appearance details (e.g., background color, padding, positioning)
Additionally, the criteria don't cover edge cases such as:
- Behavior when splash creation fails
- Handling if the main window closes while splash is displayed
- Validation mechanism for the 1s timing threshold
🤖 Prompt for AI Agents
In `@docs/specs/splash-window-ux/spec.md` around lines 25 - 29, Update the
"Acceptance Criteria" section so each item is specific and testable: replace
"compact (narrow bar)" with explicit dimensions (e.g., height 48px, width 360px,
or allowable range), define status update behavior for "status text" (e.g.,
updates no faster than 250ms and on each lifecycle progress event), specify
visual details (background color hex, padding in px, alignment/positioning like
centered top-right with 16px margin), and add edge-case criteria covering:
failure to create splash (fallback behavior and error logging), main window
closing while splash is shown (expected transition or auto-close behavior), and
validation of the "1s" threshold (how to measure startup completion — use
monotonic timer and tolerance ±50ms and automated test hook). Ensure you
reference the existing acceptance items (e.g., "If startup completes..." and "If
no window exists after 1s...") when replacing them so the new criteria directly
map to the original bullets.
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
🤖 Fix all issues with AI agents
In `@src/main/presenter/agentPresenter/message/messageBuilder.ts`:
- Line 131: Remove the stray debug console.log from messageBuilder.ts: delete
the line console.log('store chat mode', storedChatMode) and, if diagnostic
logging is required, replace it with a structured logger call at debug level
(e.g., processLogger.debug or the existing logger.debug) that includes the
context and the storedChatMode variable; locate this in the MessageBuilder code
where storedChatMode is set/used and use the project’s logger instead of
console.log.
🧹 Nitpick comments (1)
docs/specs/model-selector-config-popover/tasks.md (1)
9-9: Specify the exact file path instead of using wildcards.The wildcard pattern
src/shared/**is too vague for implementers. Please specify the exact file whereCONVERSATION_SETTINGSis defined (e.g.,src/shared/types/conversation.tsor similar).
| | 'agent' | ||
| | 'acp agent' | ||
| | undefined | ||
| console.log('store chat mode', storedChatMode) |
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.
Remove debug console.log statement.
This appears to be a debug log that should not be present in production code. If logging is needed for diagnostics, consider using structured logging at an appropriate level.
Suggested fix
- console.log('store chat mode', storedChatMode)📝 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.
| console.log('store chat mode', storedChatMode) |
🤖 Prompt for AI Agents
In `@src/main/presenter/agentPresenter/message/messageBuilder.ts` at line 131,
Remove the stray debug console.log from messageBuilder.ts: delete the line
console.log('store chat mode', storedChatMode) and, if diagnostic logging is
required, replace it with a structured logger call at debug level (e.g.,
processLogger.debug or the existing logger.debug) that includes the context and
the storedChatMode variable; locate this in the MessageBuilder code where
storedChatMode is set/used and use the project’s logger instead of console.log.
Summary by CodeRabbit
New Features
Improvements
✏️ Tip: You can customize this high-level summary in your review settings.