Skip to content

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Nov 11, 2025

ThreadPresenter 重构优化方案

问题分析

当前 src/main/presenter/threadPresenter/index.ts 文件存在以下问题:

  • 文件过大:3865行,远超200行的硬性指标
  • 职责过多:包含会话管理、流式生成、LLM事件处理、权限管理、工具调用、搜索处理、内容缓冲、辅助功能等8+个职责
  • 可维护性差:方法过多,逻辑耦合,难以测试和扩展

重构策略

采用职责分离 + Facade模式

  1. 将不同职责拆分到专门的Handler/Manager类
  2. ThreadPresenter作为协调者,保持IThreadPresenter接口不变
  3. 确保向后兼容,不影响上游调用

拆分方案

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 loop
  • continueAfterPermissionDenied() - 权限拒绝后继续
  • 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

  • 保持IThreadPresenter接口不变
  • 委托给各个Handler处理具体逻辑
  • 管理生成状态Map(generatingMessages
  • 管理活跃会话Map(activeConversationIds

结构:

export class ThreadPresenter implements IThreadPresenter {
  // 核心依赖
  private sqlitePresenter: ISQLitePresenter
  private messageManager: MessageManager
  private llmProviderPresenter: ILlmProviderPresenter
  private configPresenter: IConfigPresenter
  private searchManager: SearchManager
  
  // Handler实例
  private conversationManager: ConversationManager
  private streamGenerationHandler: StreamGenerationHandler
  private llmEventHandler: LLMEventHandler
  private permissionHandler: PermissionHandler
  private toolCallHandler: ToolCallHandler
  private searchHandler: SearchHandler
  private contentBufferHandler: ContentBufferHandler
  private utilityHandler: UtilityHandler
  
  // 状态管理
  private generatingMessages: Map<string, GeneratingMessageState>
  private activeConversationIds: Map<number, string>
  private searchingMessages: Set<string>
  
  // 接口方法委托给各个Handler
}

文件结构(优化后)

当前文件大小分析

  • 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行 ✅ 符合规范

优化后的文件结构

src/main/presenter/threadPresenter/
├── index.ts                           # 主类(Facade,~200行)
├── handlers/                          # Handler类目录(7个文件)
│   ├── streamGenerationHandler.ts     (~300行)
│   ├── llmEventHandler.ts             (~400行)
│   ├── permissionHandler.ts           (~500行)
│   ├── toolCallHandler.ts             (~200行)
│   ├── searchHandler.ts               (~300行)
│   ├── contentBufferHandler.ts        (~250行)
│   └── utilityHandler.ts              (~300行)
├── managers/                          # Manager类目录(4个文件)
│   ├── conversationManager.ts         (~400行,需拆分)
│   ├── messageManager.ts              (~200行,从379行拆分)
│   └── searchManager.ts               (~350行,从1404行拆分)
├── builders/                          # Builder类目录(3个文件)
│   ├── promptBuilder.ts               (~250行,从674行拆分)
│   └── contextBuilder.ts              (~200行,从promptBuilder拆分)
├── exporters/                         # Exporter类目录(2个文件)
│   ├── conversationExporter.ts       (~300行,从572行拆分)
│   └── exportFormatters.ts           (~250行,从conversationExporter拆分)
├── enrichers/                         # Enricher类目录(2个文件)
│   ├── contentEnricher.ts             (~200行,从383行拆分)
│   └── urlEnricher.ts                 (~180行,从contentEnricher拆分)
├── utils/                             # 工具函数目录(2个文件)
│   ├── messageContent.ts               (~164行,保持不变)
│   └── messageFormatter.ts            (~100行,从messageManager拆分)
├── types.ts                           # 类型定义(保持不变)
└── const.ts                           # 常量定义(保持不变)

文件拆分策略

1. searchManager.ts (1404行 → 2个文件)

  • searchManager.ts (~350行): 核心搜索管理逻辑
  • searchWindowManager.ts (~350行): 搜索窗口管理
  • searchExtractor.ts (~350行): 搜索结果提取逻辑
  • searchEngineConfig.ts (~350行): 搜索引擎配置和选择器

2. promptBuilder.ts (674行 → 2个文件)

  • promptBuilder.ts (~250行): 主要提示构建逻辑
  • contextBuilder.ts (~200行): 上下文构建逻辑
  • toolCallContextBuilder.ts (~224行): 工具调用上下文构建

3. conversationExporter.ts (572行 → 2个文件)

  • conversationExporter.ts (~300行): 导出协调逻辑
  • exportFormatters.ts (~272行): 各种格式的格式化器(markdown/html/txt)

4. contentEnricher.ts (383行 → 2个文件)

  • contentEnricher.ts (~200行): 核心内容提取逻辑
  • urlEnricher.ts (~183行): URL提取和丰富逻辑

5. messageManager.ts (379行 → 2个文件)

  • messageManager.ts (~200行): 核心消息CRUD操作
  • messageFormatter.ts (~179行): 消息格式化和转换逻辑

6. conversationManager.ts (新建,需控制大小)

  • conversationManager.ts (~400行): 会话管理,如果超过200行,拆分为:
    • conversationManager.ts (~200行): 核心CRUD
    • conversationListManager.ts (~200行): 列表和激活管理

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved trace dialog error handling to only update state for the latest request, preventing stale request errors and making previews more responsive.
  • Refactor

    • Enhanced internal architecture for streaming AI generation, search operations, and tool call management with new handler components and improved module organization.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 11, 2025

Walkthrough

This 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

Cohort / File(s) Summary
Package Configuration
package.json
Removes npx wrapper from lint script, adds oxlint as a direct dependency.
Base Handler Architecture
src/main/presenter/threadPresenter/handlers/baseHandler.ts
Introduces ThreadHandlerContext interface and abstract BaseHandler class to standardize dependency injection and context management for all handler subclasses.
Content Streaming & Buffering
src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
Implements adaptive content buffering with dynamic chunk sizing, asynchronous processing, and finalization logic for streaming LLM responses.
LLM Event Orchestration
src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
Manages LLM agent lifecycle events (response, error, end), tracks token usage and timing, coordinates tool calls and image blocks, and finalizes messages with computed metadata.
Permission Management
src/main/presenter/threadPresenter/handlers/permissionHandler.ts
Orchestrates permission-driven tool-call flows, including validation, MCP grant/deny operations, and agent loop resumption after user permissions.
Search Operations
src/main/presenter/threadPresenter/handlers/searchHandler.ts
Manages end-to-end streaming search with query rewriting, result processing, and block finalization. Extends BaseHandler.
Stream Generation
src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
Orchestrates end-to-end AI generation streaming with context preparation, continuation, regeneration, and message history retrieval.
Tool Call Management
src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
Manages tool-call lifecycle (start, update, end, permission) and integrates search results from tool calls.
Utility Operations
src/main/presenter/threadPresenter/handlers/utilityHandler.ts
Implements utility functions including text translation, AI responses, conversation export, title summarization, and message request previews. Extends BaseHandler.
Conversation Lifecycle Management
src/main/presenter/threadPresenter/managers/conversationManager.ts
Centralizes conversation CRUD, tab binding, forking with history replication, and thread list broadcasting.
Import Path Reorganization
src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts, src/main/presenter/threadPresenter/exporters/conversationExporter.ts, src/main/presenter/threadPresenter/managers/messageManager.ts, src/main/presenter/threadPresenter/managers/searchManager.ts, src/main/presenter/threadPresenter/types.ts, src/main/presenter/threadPresenter/utils/promptBuilder.ts, src/main/presenter/threadPresenter/utils/contentEnricher.ts
Updates import paths to use @shared/presenter alias and reorganizes utility modules into dedicated utils directory.
Utility Module Updates
src/main/presenter/threadPresenter/utils/messageContent.ts
Adds ESLint directive to suppress no-control-regex warning.
UI Race Condition Fix
src/renderer/src/components/trace/TraceDialog.vue
Modifies loadPreview error handling to only update state for latest in-flight request, preventing stale response processing.
Documentation Update
docs/trace-request-params-feature.md
Updates import path reference to reflect utils directory reorganization.

Sequence Diagram

sequenceDiagram
    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
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • BaseHandler and 7 new handler classes with dense logic for streaming, buffering, tool calls, permissions, and search workflows — each handler introduces significant state management and async orchestration patterns
  • ConversationManager with intricate conversation lifecycle, tab binding, and forking logic with variant handling and history replication
  • Import refactoring across 7+ files (repetitive pattern, but requires verification of module resolution correctness)
  • Integration complexity between handlers sharing state (generatingMessages map, searchingMessages set) and coordinating async flows
  • Multiple files with new public APIs requiring verification of signatures and contract correctness

Areas requiring extra attention:

  • LLMEventHandler finalization logic and metadata computation (token usage, timing calculations)
  • PermissionHandler permission flow orchestration and MCP readiness polling
  • StreamGenerationHandler context preparation and variant overrides
  • ToolCallHandler search result extraction and attachment storage
  • ConversationManager fork operation with history replication and variant resolution
  • Import path updates to ensure all alias mappings and relative paths resolve correctly

Possibly related PRs

  • PR #1061: Extracts conversation lifecycle logic into a dedicated ConversationManager, mirroring the refactoring in this PR to centralize thread presenter responsibilities.
  • PR #1064: Modifies MCP permission approval flow, adding/adjusting permission handling, pendingToolCall state, and post-permission restart logic that overlaps with PermissionHandler in this PR.
  • PR #847: Refactors shared presenter/type imports and event/type shapes (e.g., @shared/presenter alias), which this PR depends on for import reorganization.

Suggested labels

codex

Suggested reviewers

  • deepinfect

Poem

🐰 Eight handlers dance in harmony,
Buffering streams and tool calls free,
Permissions flow, searches thrive,
Conversations bloom and come alive!
With context wired and imports neat,
Thread presenter's refactor is complete!

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor: threadpresenter split' clearly summarizes the main change: refactoring threadPresenter by splitting large modules into focused, smaller ones.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/threadpresenter

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zerob13 zerob13 marked this pull request as ready for review November 11, 2025 06:50
Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 line

The block directive disables no-control-regex for 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

📥 Commits

Reviewing files that changed from the base of the PR and between 2295435 and 3b2fe98.

📒 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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/renderer/src/components/trace/TraceDialog.vue
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/renderer/src/components/trace/TraceDialog.vue
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/renderer/src/components/trace/TraceDialog.vue
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • package.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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/contentBufferHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/renderer/src/components/trace/TraceDialog.vue
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/baseHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/utilityHandler.ts
  • src/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.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • 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 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.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/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.ts
  • 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 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.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • 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/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.ts
  • 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 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.ts
  • 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 : 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.ts
  • src/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 guideline

Newly 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 comments
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/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

Comment on lines 164 to 172
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
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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 error

Apply 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 by findGeneratingState on 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 error

As 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 error

As 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:

  1. Making the prompt template configurable or multi-language aware
  2. 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.

prepareConversationContext modifies the userMessage.content object in place by setting search and think properties. 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

📥 Commits

Reviewing files that changed from the base of the PR and between 3b2fe98 and 7e9031d.

📒 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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/exporters/conversationExporter.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/main/presenter/threadPresenter/managers/searchManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/enrichers/contentEnricher.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/managers/messageManager.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/builders/promptBuilder.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/types.ts
  • 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: 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.ts
  • src/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.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/main/presenter/threadPresenter/managers/conversationManager.ts
  • src/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.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/main/presenter/threadPresenter/handlers/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/mcpPresenter/inMemoryServers/powerpackServer.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/handlers/toolCallHandler.ts
  • src/main/presenter/threadPresenter/handlers/llmEventHandler.ts
  • src/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.ts
  • src/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.ts
  • 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/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.ts
  • 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 : 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.ts
  • 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/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.ts
  • 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/searchHandler.ts
  • 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 : 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-regex rule is intentionally disabled here because the function escapeTagContent needs 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/presenter for 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 PreviewCapableProvider interface 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

📥 Commits

Reviewing files that changed from the base of the PR and between 7e9031d and cbac0d5.

📒 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)

Comment on lines +104 to +162
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
}
}
Copy link
Contributor

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
  }
}

Comment on lines 164 to 214
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
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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:

  1. Chinese strings (lines 121, 135, 161) violate coding guidelines requiring English for all logs and comments.
  2. Magic numbers (0.7 at line 149, 1000 at line 150) should be extracted as named constants.
  3. 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_TOKENS

3. Consider extracting a private helper method to eliminate duplication between translateText and askAI:

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:

  1. Chinese error messages (lines 229, 233): '找不到当前对话' violates coding guidelines requiring English.
  2. Debug console.log statements (lines 298, 301) should be removed or converted to proper debug-level logging.
  3. Magic number 300 (line 240) should be extracted as a named constant.
  4. 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 exportConversation and summaryTitles:

const variantAwareMessages = this.applyVariantSelection(validMessages, selectedVariantsMap)

340-340: 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 without any compile-time warning.

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 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

📥 Commits

Reviewing files that changed from the base of the PR and between cbac0d5 and 34d8639.

📒 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)

Comment on lines +22 to +24
// Translation constants
const TRANSLATION_TEMPERATURE = 0.3
const TRANSLATION_TIMEOUT_MS = 1000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

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 = 1000

And update line 86:

-    TRANSLATION_TIMEOUT_MS
+    TRANSLATION_MAX_TOKENS

Committable 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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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_MS is used as the maxTokens parameter (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 = 1000

And 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 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 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 askAI method contains Chinese strings (lines 124, 138, 164) that violate the coding guideline requiring English logs and comments. Additionally, magic numbers 0.7 and 1000 (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 generatingMessages or stop any in-flight search. When the next generation attempt calls findGeneratingState(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 continueStreamCompletion catch block at lines 341-350.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34d8639 and eaf70d0.

📒 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.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • src/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.ts
  • 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/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.ts
  • 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/streamGenerationHandler.ts
  • 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 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.ts
  • 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 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
  • src/main/presenter/threadPresenter/handlers/searchHandler.ts
  • 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/streamGenerationHandler.ts
  • 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/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.ts
  • src/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.ts
  • src/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.ts
  • 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 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)

Copy link
Contributor

@coderabbitai coderabbitai bot left a 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 continueStreamCompletion fails (line 341), the catch block logs the error and updates the message status but does not remove the entry from generatingMessages before 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 startStreamCompletion fails (line 163), the catch block logs the error and updates the message status but does not remove the entry from generatingMessages or stop any in-flight search before rethrowing at line 171. This leaves stale state that will be returned by findGeneratingState on 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

📥 Commits

Reviewing files that changed from the base of the PR and between eaf70d0 and 93d3b86.

📒 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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/types.ts
  • 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 : 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.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/types.ts
  • 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 : 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.ts
  • src/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.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • 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/utils/promptBuilder.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • 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/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.ts
  • src/main/presenter/threadPresenter/types.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • 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 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.ts
  • src/main/presenter/threadPresenter/handlers/permissionHandler.ts
  • 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 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/presenter alias resolves through the type export chain: src/shared/presenter.d.tssrc/shared/types/index.d.tssrc/shared/types/presenters/legacy.presenters.d.ts
  • All imported symbols (CONVERSATION, ModelConfig, SearchResult, ChatMessage, ChatMessageContent, MCPToolDefinition) are properly exported
  • File locations are correct: searchManager.ts at src/main/presenter/threadPresenter/managers/, promptBuilder.ts at src/main/presenter/threadPresenter/utils/
  • The generateSearchPrompt function is exported from searchManager.ts

The refactoring successfully modernizes the import structure with module aliases and maintains proper directory organization.

Comment on lines +54 to +166
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
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

Suggested change
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).

Comment on lines +517 to +524
this.startStreamCompletion(conversationId, userMessageId, selectedVariantsMap).catch(
(error) => {
console.error(
'[StreamGenerationHandler] Failed to start regeneration from user message:',
error
)
}
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

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.

@zerob13 zerob13 merged commit 8e6abba into dev Nov 11, 2025
2 checks passed
@zerob13 zerob13 deleted the refactor/threadpresenter branch November 23, 2025 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants