-
Notifications
You must be signed in to change notification settings - Fork 614
refactor: threadpresenter split #1091
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
WalkthroughThis pull request introduces a comprehensive handler-based architecture for the thread presenter, adding eight new handler classes (BaseHandler, ContentBufferHandler, LLMEventHandler, PermissionHandler, SearchHandler, StreamGenerationHandler, ToolCallHandler, UtilityHandler) to orchestrate LLM streaming, content buffering, tool calls, permissions, search, and utility operations. It also adds ConversationManager to centralize conversation lifecycle management, reorganizes imports using module aliases and utility directories, and refactors trace dialog loading to prevent race conditions. Changes
Sequence DiagramsequenceDiagram
participant UI as UI/Renderer
participant SG as StreamGenerationHandler
participant LLM as LLMEventHandler
participant CB as ContentBufferHandler
participant TC as ToolCallHandler
participant PM as PermissionHandler
participant MM as MessageManager
UI->>SG: startStreamCompletion(conversationId)
SG->>SG: prepareConversationContext()
SG->>SG: processUserMessageContent()
SG->>SG: updateGenerationState()
loop Stream LLM Events
SG->>LLM: handleLLMAgentResponse(event)
activate LLM
LLM->>CB: processBufferedContent()
activate CB
alt Large Content
CB->>CB: processLargeContentAsynchronously()
CB->>MM: editMessage()
else Normal Content
CB->>CB: processNormalContent()
CB->>MM: editMessage()
end
deactivate CB
deactivate LLM
end
alt Tool Call Event
LLM->>TC: processToolCallStart()
activate TC
TC->>MM: editMessage(tool_call block)
deactivate TC
TC->>TC: processToolCallEnd()
alt Permission Required
TC->>PM: handlePermissionRequired()
activate PM
PM->>UI: notify permission needed
UI->>PM: handlePermissionResponse()
PM->>LLM: restartAgentLoopAfterPermission()
LLM->>SG: continueStreamCompletion()
deactivate PM
else Permission Granted
TC->>MM: editMessage(success)
end
end
SG->>LLM: handleLLMAgentEnd(event)
activate LLM
LLM->>LLM: finalizeMessage()
LLM->>CB: finalizeLastBlock()
LLM->>MM: editMessage(final state)
deactivate LLM
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes
Areas requiring extra attention:
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
🧹 Nitpick comments (1)
src/main/presenter/threadPresenter/messageContent.ts (1)
51-52: Scope the ESLint suppression to a single lineThe block directive disables
no-control-regexfor everything that follows. Please keep the suppression local so future regexes still get linted.- /* eslint-disable no-control-regex */ + // eslint-disable-next-line no-control-regex
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
package.json(2 hunks)src/main/presenter/threadPresenter/handlers/baseHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/llmEventHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/permissionHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/searchHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/toolCallHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/utilityHandler.ts(1 hunks)src/main/presenter/threadPresenter/managers/conversationManager.ts(1 hunks)src/main/presenter/threadPresenter/messageContent.ts(1 hunks)src/renderer/src/components/trace/TraceDialog.vue(1 hunks)
🧰 Additional context used
📓 Path-based instructions (22)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/renderer/src/components/trace/TraceDialog.vuesrc/main/presenter/threadPresenter/managers/conversationManager.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/renderer/src/components/trace/TraceDialog.vuesrc/main/presenter/threadPresenter/managers/conversationManager.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/renderer/src/components/trace/TraceDialog.vuesrc/main/presenter/threadPresenter/managers/conversationManager.tspackage.json
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/renderer/src/components/trace/TraceDialog.vuesrc/main/presenter/threadPresenter/managers/conversationManager.ts
src/renderer/src/**/*
📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)
src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
渲染进程代码放在
src/renderer
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/src/**/*.vue
📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)
Use scoped styles to prevent CSS conflicts between components
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/**/*.{vue,ts}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
Implement lazy loading for routes and components.
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/**/*.{ts,vue}
📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)
src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.Use Pinia for frontend state management (do not introduce alternative state libraries)
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/{src,shell,floating}/**/*.vue
📄 CodeRabbit inference engine (CLAUDE.md)
src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/src/components/**/*
📄 CodeRabbit inference engine (CLAUDE.md)
Organize UI components by feature within src/renderer/src/
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/src/**
📄 CodeRabbit inference engine (AGENTS.md)
Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/src/**/*.{vue,ts}
📄 CodeRabbit inference engine (AGENTS.md)
All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Files:
src/renderer/src/components/trace/TraceDialog.vue
src/renderer/**/*.vue
📄 CodeRabbit inference engine (AGENTS.md)
Name Vue component files in PascalCase (e.g., ChatInput.vue)
Files:
src/renderer/src/components/trace/TraceDialog.vue
🧠 Learnings (28)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: The architecture should ensure consistent behavior for tool handling, reasoning content parsing, and event emission across all Providers.
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Applied to files:
src/main/presenter/threadPresenter/messageContent.tssrc/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/baseHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/contentBufferHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/LLMProvider/**/*.ts : Implement the two-layer LLM provider (Agent Loop + Provider) under src/main/presenter/LLMProvider
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : The `coreStream` method in each Provider must perform a single streaming API request per conversation round and must not contain multi-round tool call loop logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations must use a `coreStream` method that yields standardized stream events to decouple the main loop from provider-specific details.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/streamEvents.ts : Standardized stream events should conform to the `LLMCoreStreamEvent` interface, ideally defined in a shared file such as `src/main/presenter/llmProviderPresenter/streamEvents.ts`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each LLM provider implementation must expose a coreStream method following the standardized event interface
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should aggregate and yield usage events as part of the standardized stream.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should send standardized `STREAM_EVENTS` (`RESPONSE`, `END`, `ERROR`) to the frontend via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : All provider implementations must parse provider-specific data chunks and yield standardized events for text, reasoning, tool calls, usage, errors, stop reasons, and image data.
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : New LLM providers must be added under src/main/presenter/llmProviderPresenter/providers/ as separate files
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider supports native function calling, MCP tools must be converted to the provider's format (e.g., using `convertToProviderTools`) and included in the API request.
Applied to files:
src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
📚 Learning: 2025-09-04T11:03:30.184Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/provider-guidelines.mdc:0-0
Timestamp: 2025-09-04T11:03:30.184Z
Learning: Tool calls must follow tool_call_start → tool_call_chunk* → tool_call_end; tool_call_id is required and stable
Applied to files:
src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/{main,renderer}/**/*.ts : Implement proper error handling and logging for debugging
Applied to files:
src/renderer/src/components/trace/TraceDialog.vue
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Use Suspense for asynchronous components.
Applied to files:
src/renderer/src/components/trace/TraceDialog.vue
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to **/*.{ts,tsx,js,jsx,vue} : Use OxLint for JS/TS code; keep lint clean
Applied to files:
package.json
📚 Learning: 2025-07-21T01:45:40.036Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/development-setup.mdc:0-0
Timestamp: 2025-07-21T01:45:40.036Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : 使用 OxLint 进行代码检查
Applied to files:
package.json
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to **/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml} : Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Applied to files:
package.json
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: After completing a feature, run pnpm run format and pnpm run lint to keep formatting and lint status clean
Applied to files:
package.json
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Use Vitest (+ jsdom) and Vue Test Utils as the testing framework
Applied to files:
package.json
🧬 Code graph analysis (8)
src/main/presenter/threadPresenter/handlers/baseHandler.ts (3)
src/shared/types/presenters/legacy.presenters.d.ts (2)
ISQLitePresenter(277-330)IConfigPresenter(381-551)src/main/presenter/threadPresenter/messageManager.ts (1)
MessageManager(21-379)src/main/presenter/threadPresenter/searchManager.ts (1)
SearchManager(249-1404)
src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts (3)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/eventbus.ts (1)
eventBus(151-151)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/permissionHandler.ts (6)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/shared/types/presenters/legacy.presenters.d.ts (1)
IMCPPresenter(1248-1332)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/shared/chat.d.ts (1)
AssistantMessage(39-42)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/threadPresenter/promptBuilder.ts (3)
buildPostToolExecutionContext(235-316)buildContinueToolCallContext(172-233)PendingToolCall(24-31)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (9)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (1)
SearchHandler(16-349)src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/llmEventHandler.ts (1)
LLMEventHandler(14-347)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/index.ts (1)
presenter(223-223)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/threadPresenter/messageContent.ts (3)
formatUserMessageContent(77-117)buildUserMessageContext(156-165)getNormalizedUserMessageText(144-154)src/main/presenter/threadPresenter/contentEnricher.ts (1)
ContentEnricher(12-383)
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts (6)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/messageManager.ts (1)
MessageManager(21-379)src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts (1)
ContentBufferHandler(7-195)src/main/presenter/threadPresenter/handlers/toolCallHandler.ts (1)
ToolCallHandler(21-396)src/main/eventbus.ts (1)
eventBus(151-151)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/toolCallHandler.ts (4)
src/main/presenter/threadPresenter/messageManager.ts (1)
MessageManager(21-379)src/shared/types/presenters/legacy.presenters.d.ts (1)
ISQLitePresenter(277-330)src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (4)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/messageContent.ts (1)
buildUserMessageContext(156-165)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/managers/conversationManager.ts (4)
src/shared/types/presenters/legacy.presenters.d.ts (1)
ISQLitePresenter(277-330)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/index.ts (1)
presenter(223-223)src/main/presenter/threadPresenter/const.ts (1)
DEFAULT_SETTINGS(112-120)
🔇 Additional comments (2)
src/renderer/src/components/trace/TraceDialog.vue (1)
234-274: Excellent race condition fix!The staleness checks correctly prevent concurrent requests from causing UI inconsistencies. The pattern is consistently applied across all three state update paths (success at line 247, error at line 264, finally at line 270).
When rapid successive calls occur, only the most recent request updates the component state, avoiding flickers or stale error messages.
src/main/presenter/threadPresenter/managers/conversationManager.ts (1)
268-276: Align thrown errors/logs with English-only guidelineNewly added errors and logs (e.g., lines 268–276 and throughout the fork flow around 398–515) are written in Chinese. The project guideline mandates English for logs/comments, so please translate these user-facing error strings and log messages to English before merging. As per coding guidelines
Also applies to: 398-515
⛔ Skipped due to learnings
Learnt from: CR Repo: ThinkInAIXYZ/deepchat PR: 0 File: CLAUDE.md:0-0 Timestamp: 2025-09-06T03:07:23.817Z Learning: Applies to **/*.{ts,tsx,js,vue} : Use English for all logs and commentsLearnt from: CR Repo: ThinkInAIXYZ/deepchat PR: 0 File: .cursor/rules/electron-best-practices.mdc:0-0 Timestamp: 2025-07-21T01:45:54.229Z Learning: Applies to src/main/presenter/index.ts : The IPC messages from the main process to notify the view mainly rely on the EventBus index.ts to listen for events that need to be notified and then send them to the renderer through the mainWindow
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
Outdated
Show resolved
Hide resolved
| if (String(error).includes('userCanceledGeneration')) { | ||
| console.log('[StreamGenerationHandler] 消息生成已被用户取消') | ||
| return | ||
| } | ||
|
|
||
| console.error('[StreamGenerationHandler] 流式生成过程中出错:', error) | ||
| await this.ctx.messageManager.handleMessageError(state.message.id, String(error)) | ||
| throw error | ||
| } |
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.
Clear generation state on failure paths
When startStreamCompletion/continueStreamCompletion fail before the LLM stream yields events, the catch blocks log the error but never remove the entry from generatingMessages. That stale state will be returned by findGeneratingState on the next attempt, so new responses attach to an old (errored) message id and the new assistant message never streams. Please make sure the catch blocks clean up—at minimum delete state.message.id from generatingMessages (and stop any in-flight search) before rethrowing. For example:
console.error('[StreamGenerationHandler] 流式生成过程中出错:', error)
await this.ctx.messageManager.handleMessageError(state.message.id, String(error))
+ this.generatingMessages.delete(state.message.id)
+ this.ctx.searchManager.stopSearch(state.conversationId)
throw errorApply the same cleanup in the continueStreamCompletion catch block. This keeps the handler determinstic and prevents the next generation from binding to a dead state. As per coding guidelines
Also applies to: 347-349
🤖 Prompt for AI Agents
In src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts around
lines 164-172 (and similarly around 347-349), the catch blocks currently log and
rethrow errors but do not clear the transient generation state; before
rethrowing you must remove state.message.id from this.ctx.generatingMessages (or
the generatingMessages map used) and stop/cleanup any in-flight search related
to this state (e.g., call the search cancellation/stop routine or clear related
flags) so the stale entry won’t be returned by findGeneratingState on the next
attempt; perform the same cleanup in both catch blocks, then rethrow the error.
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
♻️ Duplicate comments (2)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (2)
163-172: Critical: Clear generation state on failure paths.When an error occurs before or during the LLM stream, this catch block logs the error and re-throws it but does not remove the entry from
generatingMessages. The stale state will be returned byfindGeneratingStateon the next generation attempt, causing the new response to attach to the old (errored) message ID.Apply this diff to ensure proper cleanup:
console.error('[StreamGenerationHandler] Error during streaming generation:', error) await this.ctx.messageManager.handleMessageError(state.message.id, String(error)) + this.generatingMessages.delete(state.message.id) + this.ctx.searchManager.stopSearch(state.conversationId) throw errorAs per coding guidelines
341-350: Critical: Clear generation state on failure paths.This catch block has the same issue as
startStreamCompletion: it does not clean up the generation state before throwing. Apply the same fix here to prevent stale state from interfering with subsequent generation attempts.Apply this diff:
console.error('[StreamGenerationHandler] Error during continue generation:', error) await this.ctx.messageManager.handleMessageError(state.message.id, String(error)) + this.generatingMessages.delete(state.message.id) + this.ctx.searchManager.stopSearch(state.conversationId) throw errorAs per coding guidelines
🧹 Nitpick comments (3)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (2)
166-189: Consider making the search query rewrite prompt configurable or locale-aware.The hardcoded Chinese prompt limits this feature to Chinese-speaking users. Additionally, the prompt references the Chinese string "无须搜索" which is then checked on line 99, creating a tight coupling between the prompt language and the code logic.
Consider:
- Making the prompt template configurable or multi-language aware
- Using a language-agnostic signal (e.g., a special token or structured response) instead of a locale-specific phrase like "无须搜索"
191-194: Silent fallback may hide configuration errors.When the conversation is not found, the method silently returns the original query without logging. This could make debugging difficult if the conversation lookup fails unexpectedly.
Apply this diff to add debug logging:
const conversation = await this.ctx.sqlitePresenter.getConversation(conversationId) if (!conversation) { + console.warn('[SearchHandler] Conversation not found, using original query:', conversationId) return query }src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (1)
424-427: Side effect: Method mutates input message.
prepareConversationContextmodifies theuserMessage.contentobject in place by settingsearchandthinkproperties. This mutation may be unexpected by callers and could cause issues if the same message object is used elsewhere.Consider returning a modified copy instead:
- const webSearchEnabled = this.ctx.configPresenter.getSetting('input_webSearch') as boolean - const thinkEnabled = this.ctx.configPresenter.getSetting('input_deepThinking') as boolean - ;(userMessage.content as UserMessageContent).search = webSearchEnabled - ;(userMessage.content as UserMessageContent).think = thinkEnabled - - return { conversation, userMessage, contextMessages } + const webSearchEnabled = this.ctx.configPresenter.getSetting('input_webSearch') as boolean + const thinkEnabled = this.ctx.configPresenter.getSetting('input_deepThinking') as boolean + + const enrichedUserMessage = { + ...userMessage, + content: { + ...(userMessage.content as UserMessageContent), + search: webSearchEnabled, + think: thinkEnabled + } + } as Message + + return { conversation, userMessage: enrichedUserMessage, contextMessages }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
docs/trace-request-params-feature.md(1 hunks)src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts(1 hunks)src/main/presenter/threadPresenter/builders/promptBuilder.ts(1 hunks)src/main/presenter/threadPresenter/enrichers/contentEnricher.ts(1 hunks)src/main/presenter/threadPresenter/exporters/conversationExporter.ts(1 hunks)src/main/presenter/threadPresenter/handlers/baseHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/llmEventHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/permissionHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/searchHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/toolCallHandler.ts(1 hunks)src/main/presenter/threadPresenter/managers/conversationManager.ts(1 hunks)src/main/presenter/threadPresenter/managers/messageManager.ts(1 hunks)src/main/presenter/threadPresenter/managers/searchManager.ts(1 hunks)src/main/presenter/threadPresenter/types.ts(1 hunks)src/main/presenter/threadPresenter/utils/messageContent.ts(1 hunks)
✅ Files skipped from review due to trivial changes (1)
- docs/trace-request-params-feature.md
🚧 Files skipped from review as they are similar to previous changes (1)
- src/main/presenter/threadPresenter/handlers/baseHandler.ts
🧰 Additional context used
📓 Path-based instructions (11)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/threadPresenter/utils/messageContent.tssrc/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
src/main/presenter/mcpPresenter/inMemoryServers/*.ts
📄 CodeRabbit inference engine (CLAUDE.md)
Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
Files:
src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
🧠 Learnings (40)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/enrichers/contentEnricher.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/managers/searchManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-07-21T01:47:11.608Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-07-21T01:47:11.608Z
Learning: Applies to src/shared/**/*.{ts,tsx,d.ts} : 共享类型定义放在 `shared` 目录
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/managers/messageManager.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : New LLM providers must be added under src/main/presenter/llmProviderPresenter/providers/ as separate files
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.tssrc/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/searchManager.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/shared/** : Put shared TypeScript types and utilities under src/shared
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.ts
📚 Learning: 2025-09-04T11:03:30.184Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/provider-guidelines.mdc:0-0
Timestamp: 2025-09-04T11:03:30.184Z
Learning: Do not emit AssistantMessageBlock or any UI-layer types from the Provider
Applied to files:
src/main/presenter/threadPresenter/exporters/conversationExporter.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider does not support native function calling, it must prepare messages using prompt wrapping (e.g., `prepareFunctionCallPrompt`) before making the API call.
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/configPresenter/providers.ts : Add provider configuration entries in src/main/presenter/configPresenter/providers.ts
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/managers/searchManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.tssrc/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider supports native function calling, MCP tools must be converted to the provider's format (e.g., using `convertToProviderTools`) and included in the API request.
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.
Applied to files:
src/main/presenter/threadPresenter/builders/promptBuilder.tssrc/main/presenter/threadPresenter/handlers/toolCallHandler.tssrc/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/types.ts
📚 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/threadPresenter/managers/messageManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should send standardized `STREAM_EVENTS` (`RESPONSE`, `END`, `ERROR`) to the frontend via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/LLMProvider/**/*.ts : Implement the two-layer LLM provider (Agent Loop + Provider) under src/main/presenter/LLMProvider
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/streamEvents.ts : Standardized stream events should conform to the `LLMCoreStreamEvent` interface, ideally defined in a shared file such as `src/main/presenter/llmProviderPresenter/streamEvents.ts`.
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : All provider implementations must parse provider-specific data chunks and yield standardized events for text, reasoning, tool calls, usage, errors, stop reasons, and image data.
Applied to files:
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to **/*.{ts,tsx,js,vue} : Use English for all logs and comments
Applied to files:
src/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Applied to files:
src/main/presenter/threadPresenter/handlers/searchHandler.ts
📚 Learning: 2025-07-21T01:45:40.036Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/development-setup.mdc:0-0
Timestamp: 2025-07-21T01:45:40.036Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Log和注释使用英文书写
Applied to files:
src/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/renderer/{src,shell,floating}/**/*.vue : All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Applied to files:
src/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : The `coreStream` method in each Provider must perform a single streaming API request per conversation round and must not contain multi-round tool call loop logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations must use a `coreStream` method that yields standardized stream events to decouple the main loop from provider-specific details.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each LLM provider implementation must expose a coreStream method following the standardized event interface
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should aggregate and yield usage events as part of the standardized stream.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供用户友好的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 记录详细的错误日志
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供有意义的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 日志级别应包括 ERROR、WARN、INFO、DEBUG
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 不要吞掉错误
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/{main,renderer}/**/*.ts : Implement proper error handling and logging for debugging
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/{main,renderer}/**/*.ts : Implement proper inter-process communication (IPC) patterns
Applied to files:
src/main/presenter/threadPresenter/managers/conversationManager.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/main/**/*.ts : Use Electron's built-in APIs for file system and native dialogs
Applied to files:
src/main/presenter/threadPresenter/managers/searchManager.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Use the Presenter pattern in the Electron main process and an EventBus for inter-process events
Applied to files:
src/main/presenter/threadPresenter/managers/searchManager.ts
🧬 Code graph analysis (7)
src/main/presenter/threadPresenter/handlers/toolCallHandler.ts (4)
src/main/presenter/threadPresenter/managers/messageManager.ts (1)
MessageManager(21-379)src/shared/types/presenters/legacy.presenters.d.ts (1)
ISQLitePresenter(277-330)src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts (3)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/eventbus.ts (1)
eventBus(151-151)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (4)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/utils/messageContent.ts (1)
buildUserMessageContext(156-165)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (9)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (1)
SearchHandler(16-349)src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/shared/chat.d.ts (2)
UserMessage(34-37)AssistantMessage(39-42)src/main/presenter/threadPresenter/builders/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/index.ts (1)
presenter(223-223)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/threadPresenter/utils/messageContent.ts (3)
formatUserMessageContent(77-117)buildUserMessageContext(156-165)getNormalizedUserMessageText(144-154)src/main/presenter/threadPresenter/enrichers/contentEnricher.ts (1)
ContentEnricher(12-383)
src/main/presenter/threadPresenter/handlers/permissionHandler.ts (8)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/shared/types/presenters/legacy.presenters.d.ts (1)
IMCPPresenter(1248-1332)src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (1)
StreamGenerationHandler(31-600)src/main/presenter/threadPresenter/handlers/llmEventHandler.ts (1)
LLMEventHandler(14-347)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/shared/chat.d.ts (1)
AssistantMessage(39-42)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/threadPresenter/builders/promptBuilder.ts (3)
buildPostToolExecutionContext(235-316)buildContinueToolCallContext(172-233)PendingToolCall(24-31)
src/main/presenter/threadPresenter/managers/conversationManager.ts (5)
src/shared/types/presenters/legacy.presenters.d.ts (2)
ISQLitePresenter(277-330)IConfigPresenter(381-551)src/main/presenter/threadPresenter/managers/messageManager.ts (1)
MessageManager(21-379)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/index.ts (1)
presenter(223-223)src/main/presenter/threadPresenter/const.ts (1)
DEFAULT_SETTINGS(112-120)
src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts (4)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/managers/messageManager.ts (1)
MessageManager(21-379)src/main/eventbus.ts (1)
eventBus(151-151)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (8)
src/main/presenter/threadPresenter/enrichers/contentEnricher.ts (1)
3-3: LGTM: Clean import path refactoring.The switch from relative path to alias-based import improves maintainability and aligns with the broader module reorganization.
src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts (1)
6-6: LGTM: Import path correctly updated.The updated import path reflects the move of ContentEnricher to the enrichers subdirectory as part of the threadPresenter refactoring.
src/main/presenter/threadPresenter/utils/messageContent.ts (1)
51-52: LGTM: ESLint directive appropriately applied.The
no-control-regexrule is intentionally disabled here because the functionescapeTagContentneeds to match and escape control characters (\u0000-\u001F) for security purposes. This is the correct use of the directive.src/main/presenter/threadPresenter/managers/messageManager.ts (1)
17-17: LGTM: Import path properly updated.The updated import path correctly reflects the relocation of messageContent to the utils subdirectory.
src/main/presenter/threadPresenter/types.ts (1)
2-2: LGTM: Import path correctly updated.The path change reflects the move of promptBuilder to the builders subdirectory as part of the module reorganization.
src/main/presenter/threadPresenter/managers/searchManager.ts (1)
4-4: LGTM: Import paths properly updated.Both import paths correctly reflect the new module organization:
- ContentEnricher moved to enrichers subdirectory
- SEARCH_PROMPT_TEMPLATE moved to parent const file
The changes are consistent with the refactoring strategy.
Also applies to: 11-11
src/main/presenter/threadPresenter/exporters/conversationExporter.ts (1)
2-4: LGTM: Import paths refactored correctly.The import updates reflect the new module structure:
- Alias-based import for shared types improves readability
- Relative paths correctly point to utils and templates subdirectories
All changes align with the refactoring objectives.
src/main/presenter/threadPresenter/builders/promptBuilder.ts (1)
17-21: LGTM: Comprehensive import refactoring.The import updates correctly reflect the new module organization:
- Alias-based imports from
@shared/presenterfor cleaner paths- Type-only import for MCPToolDefinition (proper TypeScript practice)
- Relative paths correctly updated for enrichers, utils, and managers subdirectories
All changes are consistent with the stated refactoring objectives.
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: 5
🧹 Nitpick comments (1)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts (1)
401-414: Consider defining a proper interface for preview-capable providers.The inline type assertion is fragile and will break if the provider interface changes. Consider defining a
PreviewCapableProviderinterface and using a type guard to check if the provider supports previews.// In a shared types file: interface PreviewCapableProvider { getRequestPreview( messages: ChatMessage[], modelId: string, modelConfig: unknown, temperature: number, maxTokens: number, mcpTools: MCPToolDefinition[] ): Promise<{ endpoint: string headers: Record<string, string> body: unknown }> } function isPreviewCapable(provider: unknown): provider is PreviewCapableProvider { return ( typeof provider === 'object' && provider !== null && 'getRequestPreview' in provider && typeof (provider as any).getRequestPreview === 'function' ) } // Then use: if (!isPreviewCapable(provider)) { return { notImplemented: true, providerId: effectiveProviderId, modelId: effectiveModelId } } const preview = await provider.getRequestPreview(...)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations must use a `coreStream` method that yields standardized stream events to decouple the main loop from provider-specific details.
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider does not support native function calling, it must prepare messages using prompt wrapping (e.g., `prepareFunctionCallPrompt`) before making the API call.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : Ensure all user-visible text in the renderer uses the translation system
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider supports native function calling, MCP tools must be converted to the provider's format (e.g., using `convertToProviderTools`) and included in the API request.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : The `coreStream` method in each Provider must perform a single streaming API request per conversation round and must not contain multi-round tool call loop logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧬 Code graph analysis (1)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts (7)
src/main/presenter/threadPresenter/managers/conversationManager.ts (1)
ConversationManager(19-522)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/exporters/conversationExporter.ts (3)
ConversationExportFormat(6-6)generateExportFilename(8-20)buildConversationExportContent(22-37)src/main/presenter/threadPresenter/utils/messageContent.ts (1)
buildUserMessageContext(156-165)src/main/presenter/threadPresenter/builders/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/index.ts (1)
presenter(223-223)src/main/lib/redact.ts (1)
redactRequestPreview(130-138)
| async askAI(text: string, tabId: number): Promise<string> { | ||
| try { | ||
| let conversation = await this.conversationManager.getActiveConversation(tabId) | ||
| if (!conversation) { | ||
| // Create a temporary conversation for AI query | ||
| const defaultProvider = this.ctx.configPresenter.getDefaultProviders()[0] | ||
| const models = await this.ctx.llmProviderPresenter.getModelList(defaultProvider.id) | ||
| const defaultModel = models[0] | ||
| const conversationId = await this.conversationManager.createConversation( | ||
| '临时AI对话', | ||
| { | ||
| modelId: defaultModel.id, | ||
| providerId: defaultProvider.id | ||
| }, | ||
| tabId | ||
| ) | ||
| conversation = await this.conversationManager.getConversation(conversationId) | ||
| } | ||
|
|
||
| const { providerId, modelId } = conversation.settings | ||
| const messages: ChatMessage[] = [ | ||
| { | ||
| role: 'system', | ||
| content: '你是一个AI助手。请简洁地回答用户的问题。' | ||
| }, | ||
| { | ||
| role: 'user', | ||
| content: text | ||
| } | ||
| ] | ||
|
|
||
| let aiAnswer = '' | ||
| const stream = this.ctx.llmProviderPresenter.startStreamCompletion( | ||
| providerId, | ||
| messages, | ||
| modelId, | ||
| 'ask-ai-' + Date.now(), | ||
| 0.7, | ||
| 1000 | ||
| ) | ||
|
|
||
| for await (const event of stream) { | ||
| if (event.type === 'response') { | ||
| const msg = event.data as LLMAgentEventData | ||
| if (msg.content) { | ||
| aiAnswer += msg.content | ||
| } | ||
| } else if (event.type === 'error') { | ||
| const msg = event.data as { eventId: string; error: string } | ||
| throw new Error(msg.error || 'AI回答失败') | ||
| } | ||
| } | ||
|
|
||
| return aiAnswer.trim() | ||
| } catch (error) { | ||
| console.error('AI query failed:', error) | ||
| throw error | ||
| } | ||
| } |
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
Eliminate duplication and replace Chinese strings.
This method duplicates ~80% of the logic from translateText (lines 43-102). Both methods follow the same pattern: retrieve/create conversation, build messages array, start stream, accumulate response. Consider extracting a private helper method like executeSimpleQuery(systemPrompt: string, userText: string, tabId: number, temperature: number). Additionally, Chinese strings appear at lines 113, 127, and 153.
As per coding guidelines.
Example refactor:
private static readonly ASK_AI_TEMPERATURE = 0.7
private static readonly ASK_AI_MAX_TOKENS = 1000
private async executeSimpleQuery(
systemPrompt: string,
userText: string,
tabId: number,
temperature: number,
maxTokens: number,
eventIdPrefix: string
): Promise<string> {
let conversation = await this.conversationManager.getActiveConversation(tabId)
if (!conversation) {
const defaultProvider = this.ctx.configPresenter.getDefaultProviders()[0]
const models = await this.ctx.llmProviderPresenter.getModelList(defaultProvider.id)
const defaultModel = models[0]
const conversationId = await this.conversationManager.createConversation(
`Temporary ${eventIdPrefix} conversation`,
{
modelId: defaultModel.id,
providerId: defaultProvider.id
},
tabId
)
conversation = await this.conversationManager.getConversation(conversationId)
}
const { providerId, modelId } = conversation.settings
const messages: ChatMessage[] = [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userText }
]
let result = ''
const stream = this.ctx.llmProviderPresenter.startStreamCompletion(
providerId,
messages,
modelId,
`${eventIdPrefix}-${Date.now()}`,
temperature,
maxTokens
)
for await (const event of stream) {
if (event.type === 'response') {
const msg = event.data as LLMAgentEventData
if (msg.content) {
result += msg.content
}
} else if (event.type === 'error') {
const msg = event.data as { eventId: string; error: string }
throw new Error(msg.error || `${eventIdPrefix} failed`)
}
}
return result.trim()
}
async askAI(text: string, tabId: number): Promise<string> {
try {
return await this.executeSimpleQuery(
'You are an AI assistant. Answer user questions concisely.',
text,
tabId,
UtilityHandler.ASK_AI_TEMPERATURE,
UtilityHandler.ASK_AI_MAX_TOKENS,
'ask-ai'
)
} catch (error) {
console.error('AI query failed:', error)
throw error
}
}| async exportConversation( | ||
| conversationId: string, | ||
| format: ConversationExportFormat = 'markdown' | ||
| ): Promise<{ filename: string; content: string }> { | ||
| try { | ||
| // Get conversation | ||
| const conversation = await this.conversationManager.getConversation(conversationId) | ||
| if (!conversation) { | ||
| throw new Error('会话不存在') | ||
| } | ||
|
|
||
| // Get all messages | ||
| const { list: messages } = await this.ctx.messageManager.getMessageThread( | ||
| conversationId, | ||
| 1, | ||
| 10000 | ||
| ) | ||
|
|
||
| // Filter out unsent messages | ||
| const validMessages = messages.filter((msg) => msg.status === 'sent') | ||
|
|
||
| // Apply variant selection | ||
| const selectedVariantsMap = conversation.settings.selectedVariantsMap || {} | ||
| const variantAwareMessages = validMessages.map((msg) => { | ||
| if (msg.role === 'assistant' && selectedVariantsMap[msg.id] && msg.variants) { | ||
| const selectedVariantId = selectedVariantsMap[msg.id] | ||
| const selectedVariant = msg.variants.find((v) => v.id === selectedVariantId) | ||
|
|
||
| if (selectedVariant) { | ||
| const newMsg = JSON.parse(JSON.stringify(msg)) | ||
| newMsg.content = selectedVariant.content | ||
| newMsg.usage = selectedVariant.usage | ||
| newMsg.model_id = selectedVariant.model_id | ||
| newMsg.model_provider = selectedVariant.model_provider | ||
| newMsg.model_name = selectedVariant.model_name | ||
| return newMsg | ||
| } | ||
| } | ||
| return msg | ||
| }) | ||
|
|
||
| // Generate filename | ||
| const filename = generateExportFilename(format) | ||
| const content = buildConversationExportContent(conversation, variantAwareMessages, format) | ||
|
|
||
| return { filename, content } | ||
| } catch (error) { | ||
| console.error('Failed to export conversation:', error) | ||
| throw error | ||
| } | ||
| } |
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.
Replace Chinese error message and extract magic number.
Line 172 contains a Chinese error message, and line 179 uses a magic number (10000) for the message retrieval limit. Per coding guidelines, use English for error messages and extract magic numbers as named constants.
As per coding guidelines.
Apply this diff:
+ private static readonly MAX_EXPORT_MESSAGES = 10000
+
async exportConversation(
conversationId: string,
format: ConversationExportFormat = 'markdown'
): Promise<{ filename: string; content: string }> {
try {
// Get conversation
const conversation = await this.conversationManager.getConversation(conversationId)
if (!conversation) {
- throw new Error('会话不存在')
+ throw new Error('Conversation not found')
}
// Get all messages
const { list: messages } = await this.ctx.messageManager.getMessageThread(
conversationId,
1,
- 10000
+ UtilityHandler.MAX_EXPORT_MESSAGES
)🤖 Prompt for AI Agents
In src/main/presenter/threadPresenter/handlers/utilityHandler.ts around lines
164 to 214, replace the Chinese error string at line 172 with an English message
(e.g., "Conversation not found") and extract the magic number 10000 used at line
179 into a named constant (e.g., MESSAGE_FETCH_LIMIT) defined at module scope or
near related constants; then use that constant in the getMessageThread call.
Ensure the thrown Error uses the new English message and the constant is
exported or scoped appropriately for readability and maintainability.
| } | ||
|
|
||
| // Convert SQLITE_MESSAGE to Message type | ||
| const userMessage = this.ctx.messageManager['convertToMessage'](userMessageSqlite) |
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.
Unsafe private method access breaks encapsulation.
Accessing the private convertToMessage method using bracket notation bypasses TypeScript's access controls and is fragile. If the method is renamed, moved, or its signature changes, this will fail at runtime. Consider making convertToMessage public in MessageManager or adding a public wrapper method.
// In MessageManager, add:
public convertSqliteToMessage(sqliteMessage: SQLITE_MESSAGE): Message {
return this.convertToMessage(sqliteMessage)
}
// Then use:
const userMessage = this.ctx.messageManager.convertSqliteToMessage(userMessageSqlite)🤖 Prompt for AI Agents
In src/main/presenter/threadPresenter/handlers/utilityHandler.ts around line
332, the code accesses a private MessageManager method via bracket notation
(this.ctx.messageManager['convertToMessage'](...)) which breaks encapsulation
and is fragile; to fix, expose a safe public method on MessageManager (e.g.,
convertSqliteToMessage or a public wrapper) that calls the existing private
convertToMessage, update MessageManager's type/signature accordingly, and
replace the bracket-access call with
this.ctx.messageManager.convertSqliteToMessage(userMessageSqlite) so the call is
type-safe and resilient to renames or signature changes.
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
♻️ Duplicate comments (4)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts (4)
112-170: Address Chinese strings, magic numbers, and code duplication.This method still has the following issues flagged in previous reviews:
- Chinese strings (lines 121, 135, 161) violate coding guidelines requiring English for all logs and comments.
- Magic numbers (0.7 at line 149, 1000 at line 150) should be extracted as named constants.
- Code duplication: ~80% of this logic is duplicated from
translateText(lines 47-110). Both methods follow the same pattern: get/create conversation, build messages, stream response, accumulate result.As per coding guidelines.
Apply these fixes:
1. Replace Chinese strings with English:
- '临时AI对话', + 'Temporary AI conversation',- content: '你是一个AI助手。请简洁地回答用户的问题。' + content: 'You are an AI assistant. Answer user questions concisely.'- throw new Error(msg.error || 'AI回答失败') + throw new Error(msg.error || 'AI query failed')2. Extract constants:
+const ASK_AI_TEMPERATURE = 0.7 +const ASK_AI_MAX_TOKENS = 1000 + export interface UtilityHandlerOptions {- 0.7, - 1000 + ASK_AI_TEMPERATURE, + ASK_AI_MAX_TOKENS3. Consider extracting a private helper method to eliminate duplication between
translateTextandaskAI:private async executeSimpleQuery( systemPrompt: string, userText: string, tabId: number, temperature: number, maxTokens: number, eventIdPrefix: string ): Promise<string> { let conversation = await this.conversationManager.getActiveConversation(tabId) if (!conversation) { const defaultProvider = this.ctx.configPresenter.getDefaultProviders()[0] const models = await this.ctx.llmProviderPresenter.getModelList(defaultProvider.id) const defaultModel = models[0] const conversationId = await this.conversationManager.createConversation( `Temporary ${eventIdPrefix} conversation`, { modelId: defaultModel.id, providerId: defaultProvider.id }, tabId ) conversation = await this.conversationManager.getConversation(conversationId) } const { providerId, modelId } = conversation.settings const messages: ChatMessage[] = [ { role: 'system', content: systemPrompt }, { role: 'user', content: userText } ] let result = '' const stream = this.ctx.llmProviderPresenter.startStreamCompletion( providerId, messages, modelId, `${eventIdPrefix}-${Date.now()}`, temperature, maxTokens ) for await (const event of stream) { if (event.type === 'response') { const msg = event.data as LLMAgentEventData if (msg.content) result += msg.content } else if (event.type === 'error') { const msg = event.data as { eventId: string; error: string } throw new Error(msg.error || `${eventIdPrefix} failed`) } } return result.trim() }Then simplify both methods to call this helper.
172-222: Replace Chinese error message and extract magic number.Line 180 contains a Chinese error message ('会话不存在'), and line 187 uses a magic number (10000) for the message retrieval limit. Per coding guidelines, use English for all error messages and extract magic numbers as named constants.
As per coding guidelines.
Apply this diff:
+ private static readonly MAX_EXPORT_MESSAGES = 10000 + async exportConversation( conversationId: string, format: ConversationExportFormat = 'markdown' ): Promise<{ filename: string; content: string }> { try { // Get conversation const conversation = await this.conversationManager.getConversation(conversationId) if (!conversation) { - throw new Error('会话不存在') + throw new Error('Conversation not found') } // Get all messages const { list: messages } = await this.ctx.messageManager.getMessageThread( conversationId, 1, - 10000 + UtilityHandler.MAX_EXPORT_MESSAGES )
224-303: Address Chinese strings, debug logs, magic number, and code duplication.This method has several issues flagged in previous reviews:
- Chinese error messages (lines 229, 233): '找不到当前对话' violates coding guidelines requiring English.
- Debug console.log statements (lines 298, 301) should be removed or converted to proper debug-level logging.
- Magic number 300 (line 240) should be extracted as a named constant.
- Code duplication: Lines 247-263 duplicate the variant selection logic from
exportConversation(lines 195-211).As per coding guidelines.
Apply these fixes:
1. Replace Chinese error messages:
- throw new Error('找不到当前对话') + throw new Error('Conversation not found')2. Remove or convert debug logs:
- console.log('-------------> title \n', title) let cleanedTitle = title.replace(/<think>.*?<\/think>/g, '').trim() cleanedTitle = cleanedTitle.replace(/^<think>/, '').trim() - console.log('-------------> cleanedTitle \n', cleanedTitle)3. Extract magic number:
+ private static readonly DEFAULT_MESSAGE_LENGTH = 300 + async summaryTitles(tabId?: number, conversationId?: string): Promise<string> { // ... - let messageCount = Math.ceil(conversation.settings.contextLength / 300) + let messageCount = Math.ceil(conversation.settings.contextLength / UtilityHandler.DEFAULT_MESSAGE_LENGTH)4. Extract variant selection into a helper method:
private applyVariantSelection( messages: Message[], selectedVariantsMap: Record<string, string> ): Message[] { return messages.map((msg) => { if (msg.role === 'assistant' && selectedVariantsMap[msg.id] && msg.variants) { const selectedVariantId = selectedVariantsMap[msg.id] const selectedVariant = msg.variants.find((v) => v.id === selectedVariantId) if (selectedVariant) { const newMsg = JSON.parse(JSON.stringify(msg)) newMsg.content = selectedVariant.content newMsg.usage = selectedVariant.usage newMsg.model_id = selectedVariant.model_id newMsg.model_provider = selectedVariant.model_provider newMsg.model_name = selectedVariant.model_name return newMsg } } return msg }) }Then replace the duplicated blocks in both
exportConversationandsummaryTitles:const variantAwareMessages = this.applyVariantSelection(validMessages, selectedVariantsMap)
340-340: Unsafe private method access breaks encapsulation.Accessing the private
convertToMessagemethod using bracket notation bypasses TypeScript's access controls and is fragile. If the method is renamed, moved, or its signature changes, this will fail at runtime without any compile-time warning.Consider making
convertToMessagepublic inMessageManageror adding a public wrapper method:// In MessageManager, add: public convertSqliteToMessage(sqliteMessage: SQLITE_MESSAGE): Message { return this.convertToMessage(sqliteMessage) }Then update line 340:
- const userMessage = this.ctx.messageManager['convertToMessage'](userMessageSqlite) + const userMessage = this.ctx.messageManager.convertSqliteToMessage(userMessageSqlite)
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider supports native function calling, MCP tools must be converted to the provider's format (e.g., using `convertToProviderTools`) and included in the API request.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/LLMProvider/**/*.ts : Implement the two-layer LLM provider (Agent Loop + Provider) under src/main/presenter/LLMProvider
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider does not support native function calling, it must prepare messages using prompt wrapping (e.g., `prepareFunctionCallPrompt`) before making the API call.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : Ensure all user-visible text in the renderer uses the translation system
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to **/*.{ts,tsx,js,vue} : Use English for all logs and comments
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/renderer/src/**/*.{vue,ts} : All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供用户友好的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧬 Code graph analysis (1)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts (7)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (1)
StreamGenerationHandler(31-600)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/exporters/conversationExporter.ts (3)
ConversationExportFormat(6-6)generateExportFilename(8-20)buildConversationExportContent(22-37)src/main/presenter/threadPresenter/utils/messageContent.ts (1)
buildUserMessageContext(156-165)src/main/presenter/threadPresenter/builders/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/index.ts (1)
presenter(223-223)src/main/lib/redact.ts (1)
redactRequestPreview(130-138)
| // Translation constants | ||
| const TRANSLATION_TEMPERATURE = 0.3 | ||
| const TRANSLATION_TIMEOUT_MS = 1000 |
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.
Rename TRANSLATION_TIMEOUT_MS to TRANSLATION_MAX_TOKENS for clarity.
The constant TRANSLATION_TIMEOUT_MS is used as the maxTokens parameter (line 86), not a timeout value. The name is misleading and reduces code clarity.
Apply this diff:
-const TRANSLATION_TIMEOUT_MS = 1000
+const TRANSLATION_MAX_TOKENS = 1000And update line 86:
- TRANSLATION_TIMEOUT_MS
+ TRANSLATION_MAX_TOKENSCommittable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/main/presenter/threadPresenter/handlers/utilityHandler.ts around lines 22
to 24 and usage at line 86, rename the constant TRANSLATION_TIMEOUT_MS to
TRANSLATION_MAX_TOKENS (value stays 1000) and update the maxTokens usage on line
86 to use TRANSLATION_MAX_TOKENS; also update any other references in this file
to use the new name so the identifier reflects that it represents a token limit
rather than a timeout.
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
♻️ Duplicate comments (5)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts (4)
24-24: Rename misleading constant.
TRANSLATION_TIMEOUT_MSis used as themaxTokensparameter (line 89), not a timeout value. The name misleads readers about its purpose.Apply this diff:
-const TRANSLATION_TIMEOUT_MS = 1000 +const TRANSLATION_MAX_TOKENS = 1000And update line 89:
modelId, 'translate-' + Date.now(), TRANSLATION_TEMPERATURE, - TRANSLATION_TIMEOUT_MS + TRANSLATION_MAX_TOKENS )
186-191: Extract magic number as named constant.The magic number
10000(line 190) is used as the message retrieval limit without explanation. Extract it as a named constant to improve code clarity.Apply this diff:
+ private static readonly MAX_EXPORT_MESSAGES = 10000 + async exportConversation( conversationId: string, format: ConversationExportFormat = 'markdown' ): Promise<{ filename: string; content: string }> { // ... const { list: messages } = await this.ctx.messageManager.getMessageThread( conversationId, 1, - 10000 + UtilityHandler.MAX_EXPORT_MESSAGES )
309-309: Unsafe private method access breaks encapsulation.Accessing the private
convertToMessagemethod using bracket notation bypasses TypeScript's access controls and is fragile. If the method is renamed, moved, or its signature changes, this will fail at runtime without compile-time safety.Consider adding a public wrapper method in
MessageManager:// In MessageManager, add: public convertSqliteToMessage(sqliteMessage: SQLITE_MESSAGE): Message { return this.convertToMessage(sqliteMessage) }Then use the public method:
const userMessage = this.ctx.messageManager.convertSqliteToMessage(userMessageSqlite)
115-173: Replace Chinese strings and extract magic numbers.The
askAImethod contains Chinese strings (lines 124, 138, 164) that violate the coding guideline requiring English logs and comments. Additionally, magic numbers0.7and1000(lines 152-153) should be extracted as named constants for maintainability.As per coding guidelines.
Apply this diff:
+const ASK_AI_TEMPERATURE = 0.7 +const ASK_AI_MAX_TOKENS = 1000 + async askAI(text: string, tabId: number): Promise<string> { try { let conversation = await this.conversationManager.getActiveConversation(tabId) if (!conversation) { // Create a temporary conversation for AI query const defaultProvider = this.ctx.configPresenter.getDefaultProviders()[0] const models = await this.ctx.llmProviderPresenter.getModelList(defaultProvider.id) const defaultModel = models[0] const conversationId = await this.conversationManager.createConversation( - '临时AI对话', + 'Temporary AI conversation', { modelId: defaultModel.id, providerId: defaultProvider.id }, tabId ) conversation = await this.conversationManager.getConversation(conversationId) } const { providerId, modelId } = conversation.settings const messages: ChatMessage[] = [ { role: 'system', - content: '你是一个AI助手。请简洁地回答用户的问题。' + content: 'You are an AI assistant. Answer user questions concisely.' }, { role: 'user', content: text } ] let aiAnswer = '' const stream = this.ctx.llmProviderPresenter.startStreamCompletion( providerId, messages, modelId, 'ask-ai-' + Date.now(), - 0.7, - 1000 + ASK_AI_TEMPERATURE, + ASK_AI_MAX_TOKENS ) for await (const event of stream) { if (event.type === 'response') { const msg = event.data as LLMAgentEventData if (msg.content) { aiAnswer += msg.content } } else if (event.type === 'error') { const msg = event.data as { eventId: string; error: string } - throw new Error(msg.error || 'AI回答失败') + throw new Error(msg.error || 'AI query failed') } }src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (1)
163-172: Critical: Clean up generation state on error paths.The catch block logs and rethrows errors but does not remove the failed entry from
generatingMessagesor stop any in-flight search. When the next generation attempt callsfindGeneratingState(conversationId), it retrieves this stale state, causing new responses to attach to the old (errored) message ID and preventing proper recovery.Apply this diff to clear state before rethrowing:
} catch (error) { if (String(error).includes('userCanceledGeneration')) { console.log('[StreamGenerationHandler] Message generation cancelled by user') return } console.error('[StreamGenerationHandler] Error during streaming generation:', error) await this.ctx.messageManager.handleMessageError(state.message.id, String(error)) + this.generatingMessages.delete(state.message.id) + this.ctx.searchManager.stopSearch(state.conversationId) throw error }Apply the same cleanup in the
continueStreamCompletioncatch block at lines 341-350.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
src/main/presenter/threadPresenter/handlers/searchHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/utilityHandler.ts(1 hunks)
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧠 Learnings (30)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : The `coreStream` method in each Provider must perform a single streaming API request per conversation round and must not contain multi-round tool call loop logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/streamEvents.ts : Standardized stream events should conform to the `LLMCoreStreamEvent` interface, ideally defined in a shared file such as `src/main/presenter/llmProviderPresenter/streamEvents.ts`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations must use a `coreStream` method that yields standardized stream events to decouple the main loop from provider-specific details.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should send standardized `STREAM_EVENTS` (`RESPONSE`, `END`, `ERROR`) to the frontend via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each LLM provider implementation must expose a coreStream method following the standardized event interface
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should aggregate and yield usage events as part of the standardized stream.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to **/*.{ts,tsx,js,vue} : Use English for all logs and comments
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供用户友好的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 记录详细的错误日志
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供有意义的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:45:40.036Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/development-setup.mdc:0-0
Timestamp: 2025-07-21T01:45:40.036Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Log和注释使用英文书写
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 日志级别应包括 ERROR、WARN、INFO、DEBUG
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 不要吞掉错误
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/{main,renderer}/**/*.ts : Implement proper error handling and logging for debugging
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/renderer/{src,shell,floating}/**/*.vue : All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.tssrc/main/presenter/threadPresenter/handlers/searchHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Applied to files:
src/main/presenter/threadPresenter/handlers/searchHandler.tssrc/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider supports native function calling, MCP tools must be converted to the provider's format (e.g., using `convertToProviderTools`) and included in the API request.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/LLMProvider/**/*.ts : Implement the two-layer LLM provider (Agent Loop + Provider) under src/main/presenter/LLMProvider
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider does not support native function calling, it must prepare messages using prompt wrapping (e.g., `prepareFunctionCallPrompt`) before making the API call.
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : Ensure all user-visible text in the renderer uses the translation system
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/renderer/src/**/*.{vue,ts} : All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Applied to files:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧬 Code graph analysis (3)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (10)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (1)
SearchHandler(16-349)src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/llmEventHandler.ts (1)
LLMEventHandler(14-347)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/shared/chat.d.ts (2)
UserMessage(34-37)AssistantMessage(39-42)src/main/presenter/threadPresenter/builders/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/index.ts (1)
presenter(223-223)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/threadPresenter/utils/messageContent.ts (3)
formatUserMessageContent(77-117)buildUserMessageContext(156-165)getNormalizedUserMessageText(144-154)src/main/presenter/threadPresenter/enrichers/contentEnricher.ts (1)
ContentEnricher(12-383)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (4)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/utils/messageContent.ts (1)
buildUserMessageContext(156-165)src/shared/chat/messageBlocks.ts (1)
finalizeAssistantMessageBlocks(3-25)
src/main/presenter/threadPresenter/handlers/utilityHandler.ts (7)
src/main/presenter/threadPresenter/managers/conversationManager.ts (1)
ConversationManager(19-522)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/exporters/conversationExporter.ts (3)
ConversationExportFormat(6-6)generateExportFilename(8-20)buildConversationExportContent(22-37)src/main/presenter/threadPresenter/utils/messageContent.ts (1)
buildUserMessageContext(156-165)src/main/presenter/threadPresenter/builders/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/index.ts (1)
presenter(223-223)src/main/lib/redact.ts (1)
redactRequestPreview(130-138)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-check (x64)
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
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (3)
src/main/presenter/threadPresenter/utils/contentEnricher.ts (3)
7-246: Translate all comments to English.All comments throughout this file are in Chinese, which violates the coding guidelines: "Log和注释使用英文书写" and "Use English for all logs and comments". Please translate JSDoc comments (lines 10-11, 13-17, 37-42, etc.) and inline comments (line 7, 19, 59, 62, etc.) to English for better maintainability and international collaboration.
As per coding guidelines.
181-183: Add error logging in catch block.The empty catch block silently swallows errors when fetching the config value, violating the guideline "不要吞掉错误" (Don't swallow errors). Even when using a default value, the error should be logged for debugging purposes.
Apply this diff to add minimal logging:
} catch { - // 忽略错误,使用默认值 + // Log error and use default value + console.error('Failed to fetch webContentLengthLimit config, using default:', lengthLimit) }As per coding guidelines.
280-284: Improve error handling in URL construction.Multiple catch blocks (lines 283, 357, 375) either silently swallow errors or provide minimal logging. Per the guideline "不要吞掉错误", these errors should be properly logged with context to aid debugging.
Consider adding structured error logging in these catch blocks:
} catch (error) { - // 如果URL构建失败,使用原始href - console.error('构建URL失败:', error) + // If URL construction fails, use original href + console.error('Failed to construct absolute URL:', { href, baseUrl, error }) }As per coding guidelines.
Also applies to: 354-358, 373-376
♻️ Duplicate comments (2)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (2)
341-350: Clean up generation state on failure paths.When
continueStreamCompletionfails (line 341), the catch block logs the error and updates the message status but does not remove the entry fromgeneratingMessagesbefore rethrowing at line 349. This leaves stale state that will interfere with subsequent generation attempts. This issue was flagged in a previous review but has not been addressed.Apply this diff to clean up state before rethrowing:
console.error('[StreamGenerationHandler] Error during continue generation:', error) await this.ctx.messageManager.handleMessageError(state.message.id, String(error)) + this.generatingMessages.delete(state.message.id) throw error
163-172: Clean up generation state on failure paths.When
startStreamCompletionfails (line 163), the catch block logs the error and updates the message status but does not remove the entry fromgeneratingMessagesor stop any in-flight search before rethrowing at line 171. This leaves stale state that will be returned byfindGeneratingStateon the next attempt, causing new responses to attach to an old (errored) message ID. This issue was flagged in a previous review but has not been addressed.Apply this diff to clean up state before rethrowing:
console.error('[StreamGenerationHandler] Error during streaming generation:', error) await this.ctx.messageManager.handleMessageError(state.message.id, String(error)) + this.generatingMessages.delete(state.message.id) + this.ctx.searchManager.stopSearch(state.conversationId) throw error
🧹 Nitpick comments (2)
src/main/presenter/threadPresenter/utils/contentEnricher.ts (1)
153-167: Remove duplicate content cleaning logic.The content cleaning operations (lines 153-157) are duplicated at lines 164-167. The first block also has a redundant
.trim()call. Since the second cleaning happens before the length check anyway, the first block can be removed.Apply this diff to eliminate duplication:
} - mainContent = mainContent - .replace(/[\r\n]+/g, ' ') - .replace(/\s+/g, ' ') - .trim() - .trim() // 如果没有找到主要内容,使用body if (!mainContent) {src/main/presenter/threadPresenter/handlers/permissionHandler.ts (1)
631-659: Remove arbitrary 200ms delay after MCP service is ready.Line 640 adds an extra 200ms delay after confirming the MCP service is running. This arbitrary delay unnecessarily slows down the permission grant flow and has no clear justification in the code or comments.
Apply this diff to remove the delay:
try { const isRunning = await this.getMcpPresenter().isServerRunning(serverName) if (isRunning) { - setTimeout(() => resolve(), 200) + resolve() return }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (9)
docs/trace-request-params-feature.md(1 hunks)src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts(1 hunks)src/main/presenter/threadPresenter/handlers/permissionHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts(1 hunks)src/main/presenter/threadPresenter/handlers/utilityHandler.ts(1 hunks)src/main/presenter/threadPresenter/managers/searchManager.ts(1 hunks)src/main/presenter/threadPresenter/types.ts(1 hunks)src/main/presenter/threadPresenter/utils/contentEnricher.ts(1 hunks)src/main/presenter/threadPresenter/utils/promptBuilder.ts(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- docs/trace-request-params-feature.md
- src/main/presenter/threadPresenter/managers/searchManager.ts
- src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
- src/main/presenter/threadPresenter/handlers/utilityHandler.ts
🧰 Additional context used
📓 Path-based instructions (10)
**/*.{js,jsx,ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)
**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
src/{main,renderer}/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
src/main/**/*.ts
📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)
Use Electron's built-in APIs for file system and native dialogs
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
**/*.{ts,tsx}
📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)
**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
src/main/**/*.{ts,js,tsx,jsx}
📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)
主进程代码放在
src/main
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
**/*.{ts,tsx,js,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Use English for all logs and comments
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
**/*.{ts,tsx,vue}
📄 CodeRabbit inference engine (CLAUDE.md)
Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)
Use PascalCase for TypeScript types and classes
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
src/main/presenter/**/*.ts
📄 CodeRabbit inference engine (AGENTS.md)
Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}
📄 CodeRabbit inference engine (AGENTS.md)
Prettier style: single quotes, no semicolons, print width 100; run pnpm run format
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
**/*.{ts,tsx,js,jsx,vue}
📄 CodeRabbit inference engine (AGENTS.md)
**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants
Files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
🧠 Learnings (32)
📓 Common learnings
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/**/*.ts : Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)
Applied to files:
src/main/presenter/threadPresenter/utils/contentEnricher.tssrc/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.ts
📚 Learning: 2025-07-21T01:47:11.608Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/project-structure.mdc:0-0
Timestamp: 2025-07-21T01:47:11.608Z
Learning: Applies to src/shared/**/*.{ts,tsx,d.ts} : 共享类型定义放在 `shared` 目录
Applied to files:
src/main/presenter/threadPresenter/utils/contentEnricher.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider supports native function calling, MCP tools must be converted to the provider's format (e.g., using `convertToProviderTools`) and included in the API request.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider files should implement helper methods such as `formatMessages`, `convertToProviderTools`, `parseFunctionCalls`, and `prepareFunctionCallPrompt` as needed for provider-specific logic.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : When a provider does not support native function calling, it must prepare messages using prompt wrapping (e.g., `prepareFunctionCallPrompt`) before making the API call.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : `src/main/presenter/llmProviderPresenter/index.ts` should manage the overall Agent loop, conversation history, tool execution via `McpPresenter`, and frontend communication via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each file in `src/main/presenter/llmProviderPresenter/providers/*.ts` should handle interaction with a specific LLM API, including request/response formatting, tool definition conversion, native/non-native tool call management, and standardizing output streams to a common event format.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/configPresenter/providers.ts : Add provider configuration entries in src/main/presenter/configPresenter/providers.ts
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : New LLM providers must be added under src/main/presenter/llmProviderPresenter/providers/ as separate files
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/types.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop in `llmProviderPresenter/index.ts` should handle multi-round LLM calls and tool usage, maintaining conversation state and controlling the loop with `needContinueConversation` and `toolCallCount`.
Applied to files:
src/main/presenter/threadPresenter/utils/promptBuilder.tssrc/main/presenter/threadPresenter/handlers/permissionHandler.tssrc/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.
Applied to files:
src/main/presenter/threadPresenter/types.ts
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/main/presenter/LLMProvider/**/*.ts : Implement the two-layer LLM provider (Agent Loop + Provider) under src/main/presenter/LLMProvider
Applied to files:
src/main/presenter/threadPresenter/handlers/permissionHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : The `coreStream` method in each Provider must perform a single streaming API request per conversation round and must not contain multi-round tool call loop logic.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/streamEvents.ts : Standardized stream events should conform to the `LLMCoreStreamEvent` interface, ideally defined in a shared file such as `src/main/presenter/llmProviderPresenter/streamEvents.ts`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations must use a `coreStream` method that yields standardized stream events to decouple the main loop from provider-specific details.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/index.ts : The main Agent loop should send standardized `STREAM_EVENTS` (`RESPONSE`, `END`, `ERROR`) to the frontend via `eventBus`.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Each LLM provider implementation must expose a coreStream method following the standardized event interface
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should aggregate and yield usage events as part of the standardized stream.
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to **/*.{ts,tsx,js,vue} : Use English for all logs and comments
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供用户友好的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 日志级别应包括 ERROR、WARN、INFO、DEBUG
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 提供有意义的错误信息
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:19.702Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/error-logging.mdc:0-0
Timestamp: 2025-07-21T01:46:19.702Z
Learning: Applies to **/*.{ts,tsx} : 记录详细的错误日志
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/{main,renderer}/**/*.ts : Implement proper error handling and logging for debugging
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:45:40.036Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/development-setup.mdc:0-0
Timestamp: 2025-07-21T01:45:40.036Z
Learning: Applies to **/*.{js,jsx,ts,tsx} : Log和注释使用英文书写
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/renderer/{src,shell,floating}/**/*.vue : All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Applied to files:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
🧬 Code graph analysis (2)
src/main/presenter/threadPresenter/handlers/permissionHandler.ts (7)
src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/shared/types/presenters/legacy.presenters.d.ts (1)
IMCPPresenter(1248-1332)src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (1)
StreamGenerationHandler(31-600)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/shared/chat.d.ts (1)
AssistantMessage(39-42)src/main/eventbus.ts (1)
eventBus(151-151)src/main/presenter/threadPresenter/utils/promptBuilder.ts (3)
buildPostToolExecutionContext(235-316)buildContinueToolCallContext(172-233)PendingToolCall(24-31)
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts (7)
src/main/presenter/threadPresenter/handlers/searchHandler.ts (1)
SearchHandler(16-349)src/main/presenter/threadPresenter/types.ts (1)
GeneratingMessageState(4-36)src/main/presenter/threadPresenter/handlers/llmEventHandler.ts (1)
LLMEventHandler(14-347)src/main/presenter/threadPresenter/handlers/baseHandler.ts (1)
ThreadHandlerContext(5-11)src/main/presenter/threadPresenter/utils/promptBuilder.ts (1)
preparePromptContent(64-170)src/main/presenter/threadPresenter/utils/messageContent.ts (3)
formatUserMessageContent(77-117)buildUserMessageContext(156-165)getNormalizedUserMessageText(144-154)src/main/presenter/threadPresenter/utils/contentEnricher.ts (1)
ContentEnricher(12-383)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build-check (x64)
🔇 Additional comments (3)
src/main/presenter/threadPresenter/utils/contentEnricher.ts (1)
3-3: LGTM! Import alias improves maintainability.The migration from relative path to module alias (
@shared/presenter) aligns with the PR's refactoring objectives and improves code maintainability.src/main/presenter/threadPresenter/types.ts (1)
2-2: LGTM! Import path correctly updated.The import path properly reflects the relocation of promptBuilder to the utils/ subdirectory, maintaining consistency with the refactoring.
src/main/presenter/threadPresenter/utils/promptBuilder.ts (1)
17-18: All import paths verified and resolve correctly.The verification confirms that:
- The
@shared/presenteralias resolves through the type export chain:src/shared/presenter.d.ts→src/shared/types/index.d.ts→src/shared/types/presenters/legacy.presenters.d.ts- All imported symbols (CONVERSATION, ModelConfig, SearchResult, ChatMessage, ChatMessageContent, MCPToolDefinition) are properly exported
- File locations are correct:
searchManager.tsatsrc/main/presenter/threadPresenter/managers/,promptBuilder.tsatsrc/main/presenter/threadPresenter/utils/- The
generateSearchPromptfunction is exported fromsearchManager.tsThe refactoring successfully modernizes the import structure with module aliases and maintains proper directory organization.
| async handlePermissionResponse( | ||
| messageId: string, | ||
| toolCallId: string, | ||
| granted: boolean, | ||
| permissionType: 'read' | 'write' | 'all', | ||
| remember: boolean = true | ||
| ): Promise<void> { | ||
| console.log('[PermissionHandler] Handling permission response', { | ||
| messageId, | ||
| toolCallId, | ||
| granted, | ||
| permissionType, | ||
| remember | ||
| }) | ||
|
|
||
| try { | ||
| const message = await this.ctx.messageManager.getMessage(messageId) | ||
| if (!message || message.role !== 'assistant') { | ||
| throw new Error(`Message not found or not assistant message (${messageId})`) | ||
| } | ||
|
|
||
| const content = message.content as AssistantMessageBlock[] | ||
| const permissionBlock = content.find( | ||
| (block) => | ||
| block.type === 'action' && | ||
| block.action_type === 'tool_call_permission' && | ||
| block.tool_call?.id === toolCallId | ||
| ) | ||
|
|
||
| if (!permissionBlock) { | ||
| throw new Error( | ||
| `Permission block not found (messageId: ${messageId}, toolCallId: ${toolCallId})` | ||
| ) | ||
| } | ||
|
|
||
| permissionBlock.status = granted ? 'granted' : 'denied' | ||
| if (permissionBlock.extra) { | ||
| permissionBlock.extra.needsUserAction = false | ||
| if (granted) { | ||
| permissionBlock.extra.grantedPermissions = permissionType | ||
| } | ||
| } | ||
|
|
||
| const generatingState = this.generatingMessages.get(messageId) | ||
| if (generatingState) { | ||
| const permissionIndex = generatingState.message.content.findIndex( | ||
| (block) => | ||
| block.type === 'action' && | ||
| block.action_type === 'tool_call_permission' && | ||
| block.tool_call?.id === toolCallId | ||
| ) | ||
|
|
||
| if (permissionIndex !== -1) { | ||
| const statePermissionBlock = generatingState.message.content[permissionIndex] | ||
| generatingState.message.content[permissionIndex] = { | ||
| ...statePermissionBlock, | ||
| ...permissionBlock, | ||
| extra: permissionBlock.extra | ||
| ? { | ||
| ...permissionBlock.extra | ||
| } | ||
| : undefined, | ||
| tool_call: permissionBlock.tool_call | ||
| ? { | ||
| ...permissionBlock.tool_call | ||
| } | ||
| : undefined | ||
| } | ||
| } else { | ||
| generatingState.message.content = content.map((block) => ({ | ||
| ...block, | ||
| extra: block.extra ? { ...block.extra } : undefined, | ||
| tool_call: block.tool_call ? { ...block.tool_call } : undefined | ||
| })) | ||
| } | ||
| } | ||
|
|
||
| await this.ctx.messageManager.editMessage(messageId, JSON.stringify(content)) | ||
|
|
||
| if (granted) { | ||
| const serverName = permissionBlock?.extra?.serverName as string | ||
| if (!serverName) { | ||
| throw new Error(`Server name not found in permission block (${messageId})`) | ||
| } | ||
|
|
||
| try { | ||
| await this.getMcpPresenter().grantPermission(serverName, permissionType, remember) | ||
| await this.waitForMcpServiceReady(serverName) | ||
| } catch (error) { | ||
| permissionBlock.status = 'error' | ||
| await this.ctx.messageManager.editMessage(messageId, JSON.stringify(content)) | ||
| throw error | ||
| } | ||
|
|
||
| await this.restartAgentLoopAfterPermission(messageId) | ||
| } else { | ||
| await this.continueAfterPermissionDenied(messageId) | ||
| } | ||
| } catch (error) { | ||
| console.error('[PermissionHandler] Failed to handle permission response:', error) | ||
|
|
||
| try { | ||
| const message = await this.ctx.messageManager.getMessage(messageId) | ||
| if (message) { | ||
| await this.ctx.messageManager.handleMessageError(messageId, String(error)) | ||
| } | ||
| } catch (updateError) { | ||
| console.error('[PermissionHandler] Failed to update message status:', updateError) | ||
| } | ||
|
|
||
| throw error | ||
| } | ||
| } |
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.
Clean up generation state on permission handling failure.
When restartAgentLoopAfterPermission or continueAfterPermissionDenied throw (lines 148, 150), the outer catch block (line 152) logs the error and updates the message status but does not remove the entry from generatingMessages before rethrowing at line 164. This leaves stale state that could interfere with subsequent generation attempts for the same conversation.
Apply this diff to clean up state before rethrowing:
} catch (error) {
console.error('[PermissionHandler] Failed to handle permission response:', error)
+ this.generatingMessages.delete(messageId)
+
try {
const message = await this.ctx.messageManager.getMessage(messageId)
if (message) {📝 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.
| async handlePermissionResponse( | |
| messageId: string, | |
| toolCallId: string, | |
| granted: boolean, | |
| permissionType: 'read' | 'write' | 'all', | |
| remember: boolean = true | |
| ): Promise<void> { | |
| console.log('[PermissionHandler] Handling permission response', { | |
| messageId, | |
| toolCallId, | |
| granted, | |
| permissionType, | |
| remember | |
| }) | |
| try { | |
| const message = await this.ctx.messageManager.getMessage(messageId) | |
| if (!message || message.role !== 'assistant') { | |
| throw new Error(`Message not found or not assistant message (${messageId})`) | |
| } | |
| const content = message.content as AssistantMessageBlock[] | |
| const permissionBlock = content.find( | |
| (block) => | |
| block.type === 'action' && | |
| block.action_type === 'tool_call_permission' && | |
| block.tool_call?.id === toolCallId | |
| ) | |
| if (!permissionBlock) { | |
| throw new Error( | |
| `Permission block not found (messageId: ${messageId}, toolCallId: ${toolCallId})` | |
| ) | |
| } | |
| permissionBlock.status = granted ? 'granted' : 'denied' | |
| if (permissionBlock.extra) { | |
| permissionBlock.extra.needsUserAction = false | |
| if (granted) { | |
| permissionBlock.extra.grantedPermissions = permissionType | |
| } | |
| } | |
| const generatingState = this.generatingMessages.get(messageId) | |
| if (generatingState) { | |
| const permissionIndex = generatingState.message.content.findIndex( | |
| (block) => | |
| block.type === 'action' && | |
| block.action_type === 'tool_call_permission' && | |
| block.tool_call?.id === toolCallId | |
| ) | |
| if (permissionIndex !== -1) { | |
| const statePermissionBlock = generatingState.message.content[permissionIndex] | |
| generatingState.message.content[permissionIndex] = { | |
| ...statePermissionBlock, | |
| ...permissionBlock, | |
| extra: permissionBlock.extra | |
| ? { | |
| ...permissionBlock.extra | |
| } | |
| : undefined, | |
| tool_call: permissionBlock.tool_call | |
| ? { | |
| ...permissionBlock.tool_call | |
| } | |
| : undefined | |
| } | |
| } else { | |
| generatingState.message.content = content.map((block) => ({ | |
| ...block, | |
| extra: block.extra ? { ...block.extra } : undefined, | |
| tool_call: block.tool_call ? { ...block.tool_call } : undefined | |
| })) | |
| } | |
| } | |
| await this.ctx.messageManager.editMessage(messageId, JSON.stringify(content)) | |
| if (granted) { | |
| const serverName = permissionBlock?.extra?.serverName as string | |
| if (!serverName) { | |
| throw new Error(`Server name not found in permission block (${messageId})`) | |
| } | |
| try { | |
| await this.getMcpPresenter().grantPermission(serverName, permissionType, remember) | |
| await this.waitForMcpServiceReady(serverName) | |
| } catch (error) { | |
| permissionBlock.status = 'error' | |
| await this.ctx.messageManager.editMessage(messageId, JSON.stringify(content)) | |
| throw error | |
| } | |
| await this.restartAgentLoopAfterPermission(messageId) | |
| } else { | |
| await this.continueAfterPermissionDenied(messageId) | |
| } | |
| } catch (error) { | |
| console.error('[PermissionHandler] Failed to handle permission response:', error) | |
| try { | |
| const message = await this.ctx.messageManager.getMessage(messageId) | |
| if (message) { | |
| await this.ctx.messageManager.handleMessageError(messageId, String(error)) | |
| } | |
| } catch (updateError) { | |
| console.error('[PermissionHandler] Failed to update message status:', updateError) | |
| } | |
| throw error | |
| } | |
| } | |
| async handlePermissionResponse( | |
| messageId: string, | |
| toolCallId: string, | |
| granted: boolean, | |
| permissionType: 'read' | 'write' | 'all', | |
| remember: boolean = true | |
| ): Promise<void> { | |
| console.log('[PermissionHandler] Handling permission response', { | |
| messageId, | |
| toolCallId, | |
| granted, | |
| permissionType, | |
| remember | |
| }) | |
| try { | |
| const message = await this.ctx.messageManager.getMessage(messageId) | |
| if (!message || message.role !== 'assistant') { | |
| throw new Error(`Message not found or not assistant message (${messageId})`) | |
| } | |
| const content = message.content as AssistantMessageBlock[] | |
| const permissionBlock = content.find( | |
| (block) => | |
| block.type === 'action' && | |
| block.action_type === 'tool_call_permission' && | |
| block.tool_call?.id === toolCallId | |
| ) | |
| if (!permissionBlock) { | |
| throw new Error( | |
| `Permission block not found (messageId: ${messageId}, toolCallId: ${toolCallId})` | |
| ) | |
| } | |
| permissionBlock.status = granted ? 'granted' : 'denied' | |
| if (permissionBlock.extra) { | |
| permissionBlock.extra.needsUserAction = false | |
| if (granted) { | |
| permissionBlock.extra.grantedPermissions = permissionType | |
| } | |
| } | |
| const generatingState = this.generatingMessages.get(messageId) | |
| if (generatingState) { | |
| const permissionIndex = generatingState.message.content.findIndex( | |
| (block) => | |
| block.type === 'action' && | |
| block.action_type === 'tool_call_permission' && | |
| block.tool_call?.id === toolCallId | |
| ) | |
| if (permissionIndex !== -1) { | |
| const statePermissionBlock = generatingState.message.content[permissionIndex] | |
| generatingState.message.content[permissionIndex] = { | |
| ...statePermissionBlock, | |
| ...permissionBlock, | |
| extra: permissionBlock.extra | |
| ? { | |
| ...permissionBlock.extra | |
| } | |
| : undefined, | |
| tool_call: permissionBlock.tool_call | |
| ? { | |
| ...permissionBlock.tool_call | |
| } | |
| : undefined | |
| } | |
| } else { | |
| generatingState.message.content = content.map((block) => ({ | |
| ...block, | |
| extra: block.extra ? { ...block.extra } : undefined, | |
| tool_call: block.tool_call ? { ...block.tool_call } : undefined | |
| })) | |
| } | |
| } | |
| await this.ctx.messageManager.editMessage(messageId, JSON.stringify(content)) | |
| if (granted) { | |
| const serverName = permissionBlock?.extra?.serverName as string | |
| if (!serverName) { | |
| throw new Error(`Server name not found in permission block (${messageId})`) | |
| } | |
| try { | |
| await this.getMcpPresenter().grantPermission(serverName, permissionType, remember) | |
| await this.waitForMcpServiceReady(serverName) | |
| } catch (error) { | |
| permissionBlock.status = 'error' | |
| await this.ctx.messageManager.editMessage(messageId, JSON.stringify(content)) | |
| throw error | |
| } | |
| await this.restartAgentLoopAfterPermission(messageId) | |
| } else { | |
| await this.continueAfterPermissionDenied(messageId) | |
| } | |
| } catch (error) { | |
| console.error('[PermissionHandler] Failed to handle permission response:', error) | |
| this.generatingMessages.delete(messageId) | |
| try { | |
| const message = await this.ctx.messageManager.getMessage(messageId) | |
| if (message) { | |
| await this.ctx.messageManager.handleMessageError(messageId, String(error)) | |
| } | |
| } catch (updateError) { | |
| console.error('[PermissionHandler] Failed to update message status:', updateError) | |
| } | |
| throw error | |
| } | |
| } |
🤖 Prompt for AI Agents
In src/main/presenter/threadPresenter/handlers/permissionHandler.ts around lines
54 to 166, the outer catch block logs and updates the message when handling
permission responses fails but never removes the in-memory generatingMessages
entry for the message, leaving stale state; before rethrowing the error, delete
the entry by calling this.generatingMessages.delete(messageId) (ensure this runs
even if message lookup/update fails) so any partial generation state is cleaned
up; place the delete just prior to the final throw in the outer catch (and keep
it safe if the map has no entry).
| this.startStreamCompletion(conversationId, userMessageId, selectedVariantsMap).catch( | ||
| (error) => { | ||
| console.error( | ||
| '[StreamGenerationHandler] Failed to start regeneration from user message:', | ||
| error | ||
| ) | ||
| } | ||
| ) |
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.
Swallowed errors in regenerateFromUserMessage.
The call to startStreamCompletion at line 517 uses .catch() to only log errors, swallowing them completely. If the stream fails to start or encounters an error mid-generation, the caller receives no indication that regeneration failed. Combined with the missing cleanup in startStreamCompletion's catch blocks (flagged separately), this can leave the UI showing a message in "generating" state indefinitely.
Consider propagating the error or emitting an error event to the renderer so the UI can reflect the failure state. For example:
this.startStreamCompletion(conversationId, userMessageId, selectedVariantsMap).catch(
(error) => {
console.error(
'[StreamGenerationHandler] Failed to start regeneration from user message:',
error
)
+ eventBus.sendToRenderer(STREAM_EVENTS.ERROR, SendTarget.ALL_WINDOWS, {
+ eventId: assistantMessage.id,
+ error: String(error)
+ })
}
)Committable suggestion skipped: line range outside the PR's diff.
ThreadPresenter 重构优化方案
问题分析
当前
src/main/presenter/threadPresenter/index.ts文件存在以下问题:重构策略
采用职责分离 + Facade模式:
拆分方案
1. 创建核心Handler类
1.1 StreamGenerationHandler
文件:
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts职责: 流式生成的协调逻辑
startStreamCompletion()- 启动流式生成continueStreamCompletion()- 继续流式生成prepareConversationContext()- 准备会话上下文processUserMessageContent()- 处理用户消息内容updateGenerationState()- 更新生成状态findGeneratingState()- 查找生成状态regenerateFromUserMessage()- 从用户消息重新生成依赖: MessageManager, LLMProviderPresenter, ConfigPresenter, SearchHandler, ContentBufferHandler
1.2 LLMEventHandler
文件:
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts职责: LLM事件处理
handleLLMAgentResponse()- 处理LLM响应事件handleLLMAgentError()- 处理LLM错误事件handleLLMAgentEnd()- 处理LLM结束事件finalizeMessage()- 完成消息处理finalizeLastBlock()- 完成最后一个块依赖: MessageManager, ContentBufferHandler, ToolCallHandler
1.3 PermissionHandler
文件:
src/main/presenter/threadPresenter/handlers/permissionHandler.ts职责: 权限管理
handlePermissionResponse()- 处理权限响应restartAgentLoopAfterPermission()- 权限授予后重启agent loopcontinueAfterPermissionDenied()- 权限拒绝后继续resumeStreamCompletion()- 恢复流式完成resumeAfterPermissionWithPendingToolCall()- 权限授予后恢复待执行工具调用waitForMcpServiceReady()- 等待MCP服务就绪findPendingToolCallAfterPermission()- 查找权限授予后的待执行工具调用依赖: MessageManager, LLMProviderPresenter, McpPresenter, StreamGenerationHandler
1.4 ToolCallHandler
文件:
src/main/presenter/threadPresenter/handlers/toolCallHandler.ts职责: 工具调用处理
processToolCallStart()- 处理工具调用开始processToolCallUpdate()- 处理工具调用更新processToolCallEnd()- 处理工具调用结束processToolCallPermission()- 处理工具调用权限请求processSearchResultsFromToolCall()- 从工具调用中提取搜索结果依赖: MessageManager, SQLitePresenter
1.5 SearchHandler
文件:
src/main/presenter/threadPresenter/handlers/searchHandler.ts职责: 搜索处理(与SearchManager配合)
startStreamSearch()- 启动流式搜索rewriteUserSearchQuery()- 重写用户搜索查询processSearchResults()- 处理搜索结果依赖: SearchManager, MessageManager, LLMProviderPresenter, SQLitePresenter
1.6 ContentBufferHandler
文件:
src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts职责: 内容缓冲处理
flushAdaptiveBuffer()- 刷新自适应缓冲processBufferedContent()- 处理缓冲内容processLargeContentAsynchronously()- 异步处理大内容processNormalContent()- 处理普通内容splitLargeContent()- 分割大内容cleanupContentBuffer()- 清理内容缓冲依赖: MessageManager
1.7 UtilityHandler
文件:
src/main/presenter/threadPresenter/handlers/utilityHandler.ts职责: 辅助功能
translateText()- 翻译文本askAI()- AI询问exportConversation()- 导出会话summaryTitles()- 摘要标题getMessageRequestPreview()- 获取消息请求预览依赖: LLMProviderPresenter, MessageManager, ConversationExporter
2. 创建ConversationManager
文件:
src/main/presenter/threadPresenter/managers/conversationManager.ts职责: 会话管理(相对独立,可单独管理)
createConversation()- 创建会话deleteConversation()- 删除会话renameConversation()- 重命名会话updateConversationSettings()- 更新会话设置forkConversation()- 分支会话getConversationList()- 获取会话列表setActiveConversation()- 设置活跃会话clearActiveConversation()- 清除活跃会话broadcastThreadListUpdate()- 广播会话列表更新依赖: SQLitePresenter, TabPresenter, EventBus
3. 重构ThreadPresenter主类
文件:
src/main/presenter/threadPresenter/index.ts(重构后)职责: 作为Facade协调各个Handler
generatingMessages)activeConversationIds)结构:
文件结构(优化后)
当前文件大小分析
index.ts: 3864行 ❌ 需要拆分searchManager.ts: 1404行 ❌ 需要拆分promptBuilder.ts: 674行 ❌ 需要拆分conversationExporter.ts: 572行 ❌ 需要拆分contentEnricher.ts: 383行 ❌ 需要拆分messageManager.ts: 379行 ❌ 需要拆分messageContent.ts: 164行 ✅ 符合规范const.ts: 120行 ✅ 符合规范types.ts: 36行 ✅ 符合规范优化后的文件结构
文件拆分策略
1. searchManager.ts (1404行 → 2个文件)
2. promptBuilder.ts (674行 → 2个文件)
3. conversationExporter.ts (572行 → 2个文件)
4. contentEnricher.ts (383行 → 2个文件)
5. messageManager.ts (379行 → 2个文件)
6. conversationManager.ts (新建,需控制大小)
Summary by CodeRabbit
Release Notes
Bug Fixes
Refactor