Skip to content

Conversation

@maomaofeipu
Copy link

@maomaofeipu maomaofeipu commented Aug 21, 2025

Pull Request Description

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is.
*For example: I'm always frustrated when [...] *

Describe the solution you'd like
A clear and concise description of what you want to happen.

UI/UX changes for Desktop Application
If this PR introduces UI/UX changes, please describe them in detail.

  • Include screenshots or GIFs if applicable to visually demonstrate the changes.
  • Explain the reasoning behind the UI/UX decisions and how they improve the user experience of the desktop application.

Platform Compatibility Notes
If this PR has specific platform compatibility considerations (Windows, macOS, Linux), please describe them here.

  • Are there any platform-specific behaviors or code adjustments?
  • Have you tested on all relevant platforms?

Additional context
Add any other context about the pull request here.


Pull Request Description (中文)

你的功能请求是否与某个问题有关?请描述一下。
请对问题进行清晰扼要的描述。
*例如:我增加了 [...] 的功能 *

请描述你希望的解决方案
请对你希望实现的效果进行清晰扼要的描述。

桌面应用程序的 UI/UX 更改
如果此 PR 引入了 UI/UX 更改,请详细描述它们。

  • 如果适用,请包含屏幕截图或 GIF 以直观地演示更改。
  • 解释 UI/UX 决策背后的原因,以及它们如何改善桌面应用程序的用户体验。

平台兼容性注意事项
如果此 PR 具有特定的平台兼容性考虑因素(Windows、macOS、Linux),请在此处描述。

  • 是否有任何平台特定的行为或代码调整?
  • 你是否已在所有相关平台上进行过测试?

附加背景
在此处添加关于此 Pull Request 的任何其他背景信息。

Summary by CodeRabbit

  • New Features

    • AI Processing toggle in Chat Input with persisted state.
    • Voice input with live audio visualization and 15s auto-stop.
    • Tool call responses now render as Markdown (CSV→table), auto-expand on direct return, and emit a single “end” event.
  • Chores

    • Update checking and dialog disabled.
    • Electron/Vite build configuration added; dependencies updated.
    • Added zh-CN translations for AI toggle and Voice Input.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 21, 2025

Walkthrough

Introduces direct-return tool-call semantics across main/renderer, adds AI-change toggle and sound input with CapsLock IPC, simplifies tool-call renderer events to a single end event, disables the updater throughout, updates shared types, adds markdown-based tool-call rendering, and extends build/config and dependencies.

Changes

Cohort / File(s) Summary
Build config (Electron-Vite)
electron.vite.config.*
Adds electron-vite config for main/preload/renderer with aliases, externalization, Monaco/Vue plugins, multi-page inputs, esbuild minify, and dev server host.
Dependencies
package.json
Adds @nut-tree/nut-js and marked; reorders vue-renderer-markdown entry.
Upgrade disabled
src/main/presenter/upgradePresenter/index.ts, src/main/presenter/index.ts, src/main/index.ts, src/renderer/src/stores/upgrade.ts, src/renderer/src/App.vue, src/shared/presenter.d.ts
Comments out UpgradePresenter implementation, removes it from Presenter/types, disables check-for-updates trigger and UI/store flows; startUpdate becomes no-op.
Direct-return flow (types + logic)
src/shared/presenter.d.ts, src/shared/chat.d.ts, src/main/presenter/llmProviderPresenter/index.ts, src/main/presenter/threadPresenter/index.ts, src/renderer/src/stores/chat.ts, src/renderer/src/stores/mcp.ts, src/renderer/src/components/message/MessageBlockToolCall.vue
Adds direct_return/directReturn fields to public types; LLM agent loop emits end events and early-terminates on directReturn; threadPresenter consolidates tool_call events to single end; renderer marks tool calls as direct_return and renders responses as Markdown.
AI-change toggle + audio input
src/renderer/src/components/ChatInput.vue, src/renderer/src/stores/aiStore.ts, src/main/presenter/mcpPresenter/toolManager.ts, src/renderer/src/i18n/zh-CN/chat.json
Adds AI-change toggle with persistence and IPC; SoundInput recording with live audio visualization and 15s timer; main process tracks aiChange and propagates as directReturn in tool responses; adds i18n keys.
CapsLock simulation (IPC)
src/main/presenter/mcpPresenter/toolManager.ts, src/renderer/src/components/ChatInput.vue
Adds simulate-capslock IPC via nut-js; ChatInput sends press/release around recording.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant UI as Renderer UI
  participant Chat as chat store
  participant TP as threadPresenter (main)
  participant LLM as llmProviderPresenter (main)
  participant TM as toolManager (main)

  UI->>Chat: send message
  Chat->>TP: start stream
  TP->>LLM: start agent loop
  LLM->>TM: callTool(toolName, args)
  TM-->>LLM: MCPToolResponse { content, directReturn: aiChange }
  alt directReturn == true
    LLM-->>TP: event { tool_call: 'end', direct_return: true, ... }
    LLM-->>TP: event { type: 'end' }
  else
    LLM-->>TP: normal tool/assistant events
  end
  TP-->>Chat: tool_call 'end' (with direct_return if present)
  Chat->>UI: update blocks (expand if direct_return)
Loading
sequenceDiagram
  autonumber
  participant UI as ChatInput.vue
  participant IPC as Electron IPC
  participant TM as toolManager (main)
  participant KB as nut-js keyboard

  UI->>IPC: aiChangeEvent { aiChange }
  IPC->>TM: set aiChange (module state)

  UI->>IPC: simulate-capslock 'press' (on record start)
  IPC->>KB: Key.CapsLock
  UI->>UI: start audio meter + countdown
  UI->>IPC: simulate-capslock 'release' (on stop/timeout)
  IPC->>KB: Key.CapsLock
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • deepinfect
  • zerob13

Poem

I tuned my whiskers to a brighter beat,
Tool calls hop once—then softly complete.
A toggle twitches: AI, your turn!
CapsLock clicks as meters burn.
Upgrades asleep, the carrots fine—
Markdown crumbs in tidy line.
Thump-thump—ship it, right on time! 🥕✨

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (7)
src/shared/presenter.d.ts (1)

982-982: Typo in type: unknowunknown (breaks type checking)

This will fail strict TS type checking and downstream consumers.

-  env: Record<string, unknow>
+  env: Record<string, unknown>
src/renderer/src/stores/chat.ts (3)

192-201: Bug: parent variant lookup compares parentId to parentId (should match parent’s id).

This will fail to attach variants because it searches mergedMessages.find((m) => m.parentId === message.parentId). The parent message has id === message.parentId.

Apply this diff:

-            const parentMsg = mergedMessages.find((m) => m.parentId === message.parentId)
+            const parentMsg = mergedMessages.find((m) => m.id === message.parentId)

626-641: Always-true condition: getActiveThreadId() === getActiveThreadId().

These branches will always execute and mask logic intended to gate updates to the active thread.

Apply this diff:

-          if (getActiveThreadId() === getActiveThreadId()) {
+          if (getActiveThreadId() === cached.threadId) {
             const mainMsgIndex = getMessages().findIndex((m) => m.id === mainMessage.id)
             if (mainMsgIndex !== -1) {
               getMessages()[mainMsgIndex] = enrichedMainMessage as AssistantMessage | UserMessage
             }
           }

And lower down:

-        if (getActiveThreadId() === getActiveThreadId()) {
+        if (getActiveThreadId() === cached.threadId) {
           const msgIndex = getMessages().findIndex((m) => m.id === msg.eventId)
           if (msgIndex !== -1) {
             getMessages()[msgIndex] = enrichedMessage as AssistantMessage | UserMessage
           }
         }

450-458: Renderer can miss a tool_call block if only an 'end' event is sent (no 'start'/'running'). Add fallback creation.

ThreadPresenter.continueStreamCompletion now emits only 'end'. Your end handler looks up a loading tool_call block and updates it; if none exists, nothing renders. Provide a fallback to create the block when receiving 'end' without a prior 'start'.

Apply this diff:

-          } else if (msg.tool_call === 'end' || msg.tool_call === 'error') {
+          } else if (msg.tool_call === 'end' || msg.tool_call === 'error') {
             // 查找对应的工具调用块
             const existingToolCallBlock = curMsg.content.find(
               (block) =>
                 block.type === 'tool_call' &&
                 ((msg.tool_call_id && block.tool_call?.id === msg.tool_call_id) ||
                   block.tool_call?.name === msg.tool_call_name) &&
                 block.status === 'loading'
             )
-            if (existingToolCallBlock && existingToolCallBlock.type === 'tool_call') {
+            // 如果未找到,创建一个占位块以便渲染(兼容只发送'end'事件的路径)
+            const toolCallBlock =
+              (existingToolCallBlock && existingToolCallBlock.type === 'tool_call'
+                ? existingToolCallBlock
+                : (() => {
+                    const block = {
+                      type: 'tool_call' as const,
+                      content: '',
+                      status: 'loading' as const,
+                      timestamp: Date.now(),
+                      tool_call: {
+                        id: msg.tool_call_id,
+                        name: msg.tool_call_name,
+                        params: msg.tool_call_params || '',
+                        server_name: msg.tool_call_server_name,
+                        server_icons: msg.tool_call_server_icons,
+                        server_description: msg.tool_call_server_description
+                      }
+                    }
+                    curMsg.content.push(block)
+                    return block
+                  })())
+            if (toolCallBlock && toolCallBlock.type === 'tool_call') {
               if (msg.tool_call === 'error') {
-                existingToolCallBlock.status = 'error'
-                if (existingToolCallBlock.tool_call) {
-                  existingToolCallBlock.tool_call.response =
+                toolCallBlock.status = 'error'
+                if (toolCallBlock.tool_call) {
+                  toolCallBlock.tool_call.response =
                     msg.tool_call_response || 'tool call failed'
                 }
               } else {
-                existingToolCallBlock.status = 'success'
-                if (msg.tool_call_response && existingToolCallBlock.tool_call) {
-                  existingToolCallBlock.tool_call.response = msg.tool_call_response
+                toolCallBlock.status = 'success'
+                if (msg.tool_call_response && toolCallBlock.tool_call) {
+                  toolCallBlock.tool_call.response = msg.tool_call_response
                   // 如果是直接返回的工具调用结果,添加标记
                   if (msg.direct_return) {
-                    existingToolCallBlock.tool_call.direct_return = true
+                    toolCallBlock.tool_call.direct_return = true
                   }
                 }
               }
             }

Also applies to: 472-476

src/main/presenter/threadPresenter/index.ts (2)

1606-1643: Renderer won’t render a tool_call without a preceding 'start'; re-emit at least one synthetic 'start'.

You removed the synthetic 'start'/'running' emits and now only send 'end'. The renderer’s current logic (chat.ts) expects an existing loading tool_call block to flip to success. Without a prior 'start', nothing updates.

Minimal fix: send a 'start' right before 'end' (no 'running' needed):

-        eventBus.sendToRenderer(STREAM_EVENTS.RESPONSE, SendTarget.ALL_WINDOWS, {
+        // Send a synthetic 'start' so renderer has a loading block to finalize
+        eventBus.sendToRenderer(STREAM_EVENTS.RESPONSE, SendTarget.ALL_WINDOWS, {
+          eventId: state.message.id,
+          content: '',
+          tool_call: 'start',
+          tool_call_id: toolCall.id,
+          tool_call_name: toolCall.name,
+          tool_call_params: toolCall.params,
+          tool_call_server_name: toolCall.server_name,
+          tool_call_server_icons: toolCall.server_icons,
+          tool_call_server_description: toolCall.server_description
+        })
+
+        eventBus.sendToRenderer(STREAM_EVENTS.RESPONSE, SendTarget.ALL_WINDOWS, {
           eventId: state.message.id,
           content: '',
           tool_call: 'end',
           tool_call_id: toolCall.id,
           tool_call_response: toolCallResponse.content,
           tool_call_name: toolCall.name,
           tool_call_params: toolCall.params,
           tool_call_server_name: toolCall.server_name,
           tool_call_server_icons: toolCall.server_icons,
           tool_call_server_description: toolCall.server_description,
           tool_call_response_raw: toolCallResponse.rawData
         })

Optionally add direct_return: true if toolCallResponse carries it.


1003-1009: Data loss risk: clearContext deletes all messages across all conversations.

Calling sqlitePresenter.deleteAllMessages() inside clearContext(conversationId) likely erases every message. Scope the deletion to the provided conversationId.

If available, use the existing manager API:

-    await this.sqlitePresenter.runTransaction(async () => {
-      const conversation = await this.getConversation(conversationId)
-      if (conversation) {
-        await this.sqlitePresenter.deleteAllMessages()
-      }
-    })
+    await this.messageManager.clearAllMessages(conversationId)

If you must use sqlitePresenter directly, call a by-conversation method (e.g., deleteMessagesByConversationId) instead of deleteAllMessages.

src/main/presenter/mcpPresenter/toolManager.ts (1)

425-438: Permission flow shape mismatch: LLM loop expects toolResponse.rawData.requiresPermission.

You return requiresPermission on the top-level, but LLMProviderPresenter reads toolResponse.rawData.requiresPermission. Include a rawData payload to preserve compatibility.

Apply this diff:

-        return {
+        return {
           toolCallId: toolCall.id,
           content: `components.messageBlockPermissionRequest.description.${permissionType}`,
           isError: false,
           requiresPermission: true,
           permissionRequest: {
             toolName: originalName,
             serverName: toolServerName,
             permissionType,
             description: `Allow ${originalName} to perform ${permissionType} operations on ${toolServerName}?`
-          }
+          },
+          rawData: {
+            requiresPermission: true,
+            permissionRequest: {
+              toolName: originalName,
+              serverName: toolServerName,
+              permissionType,
+              description: `Allow ${originalName} to perform ${permissionType} operations on ${toolServerName}?`
+            }
+          }
         }
🧹 Nitpick comments (34)
src/renderer/src/App.vue (5)

4-4: Avoid commented-out imports; remove or gate with a proper feature flag

Leaving the UpdateDialog import commented introduces dead code and drift. If the updater is intentionally disabled across the app, remove the line. If you plan to toggle later, gate via a boolean config/env flag rather than comments.

Apply if you want to remove it entirely:

-// import UpdateDialog from './components/ui/UpdateDialog.vue'

If you prefer a feature flag, I can wire a settings-driven toggle (e.g., updaterEnabled) and guard rendering. Want me to draft that?


312-312: Clean up commented component in the template

Same rationale as the import. Commented JSX/HTML fragments add noise and confuse diffs. Remove or gate with a flag.

Remove entirely:

-    <!-- <UpdateDialog /> -->

39-54: Unify class target: documentElement vs body

You add/remove theme/font classes on document.documentElement in the watcher but add them on document.body in onMounted. This can lead to inconsistent styling and debugging friction. Stick to one (prefer document.documentElement).

Suggested change:

-  document.body.classList.add(themeStore.themeMode)
-  document.body.classList.add(settingsStore.fontSizeClass)
+  document.documentElement.classList.add(themeStore.themeMode)
+  document.documentElement.classList.add(settingsStore.fontSizeClass)

If any CSS currently targets body for these classes, verify selectors still work after unification.

Also applies to: 179-181


31-35: Timer typing and lifecycle cleanup robustness

  • errorDisplayTimer is typed as number | null. In mixed environments, ReturnType is safer and self-documenting. You’re already using window.setTimeout, but aligning the type avoids future regressions if this code is refactored or reused.
  • Cleanup looks correct; thanks for removing IPC listeners in onBeforeUnmount.

Minimal typing tweak:

-const errorDisplayTimer = ref<number | null>(null)
+const errorDisplayTimer = ref<ReturnType<typeof setTimeout> | null>(null)

Also applies to: 55-73, 97-103, 283-298


38-53: Use English for comments/logs per repo guidelines

This file mixes Chinese comments/log messages in TypeScript/Vue. The guidelines require English for logs and comments. Convert comments/logs to English for consistency and easier cross-team maintenance.

Example tweak:

-// 监听主题和字体大小变化,直接更新 body class
+// Watch theme and font size changes; update root classes directly

If you want, I can submit a follow-up commit converting all comments/logs here.

Also applies to: 135-152, 153-171, 175-181, 183-201, 209-221, 243-281

src/shared/chat.d.ts (1)

120-130: Document and clarify tool_call.direct_return

Please add a brief TSDoc comment on the new direct_return field in src/shared/chat.d.ts so downstream consumers understand its purpose and behavior. For example:

   tool_call?: {
     id?: string
     name?: string
     params?: string
     response?: string
     server_name?: string
     server_icons?: string
     server_description?: string
+    /** If true, the renderer should treat this tool call as a direct return and halt normal assistant streaming. */
     direct_return?: boolean
   }

• Note that the chat schema and front-end chat store consistently use the snake_case direct_return field.
• The presenter types already expose a camelCase directReturn alias (e.g. in src/shared/presenter.d.ts), so you can avoid polluting the chat schema with a second alias. If you ever need camelCase access in the renderer, implement that mapping centrally in your store-initialization logic rather than adding a separate property to the interface.
• This keeps the wire format clear (snake_case for JSON) while letting you use camelCase in code where it makes sense.

src/main/presenter/index.ts (2)

96-118: Provider sync handler is good; add defensive logging on provider fetch failure

Looks good and aligns with EventBus usage. Consider wrapping getProviders() with try/catch and logging a WARN to meet the repo’s error-handling guideline, but not blocking.


120-126: setupTray fallback is fine; consider explicit null checks and INFO logs

This is fine; you already log. Optional: add a brief INFO when re-instantiating TrayPresenter so operations teams can correlate tray lifecycle in logs.

src/main/index.ts (2)

1-312: English-only comments/logs in main process files

There are several Chinese comments in this file. Per repo guideline, use English for logs/comments. Not blocking; convert progressively to reduce review noise going forward.


118-129: Disable or Replace the Tray “Check for Updates” Menu Item

The update flow is currently disabled end-to-end (all upgradePresenter.checkUpdate() calls are commented out in both main and renderer), yet the tray menu still shows “检查更新” and dispatches the event—focusing a window without any meaningful action. This will confuse users. You should either:

• Hide/disable the menu item when the updater is unavailable
• Or keep it visible but provide explicit, user-facing feedback when clicked

Pinpointed locations:

  • src/main/presenter/trayPresenter.ts (around lines 49–52): always builds the “检查更新” item and sends TRAY_EVENTS.CHECK_FOR_UPDATES
  • src/main/index.ts (around lines 118–129): listens for that event, shows and focuses a window, then does nothing

Example diff if you choose to show a notice instead of a no-op:

--- a/src/main/index.ts
+++ b/src/main/index.ts
@@ -126,7 +126,13 @@ eventBus.on(TRAY_EVENTS.CHECK_FOR_UPDATES, () => {
     presenter.windowPresenter.show(targetWindow.id)
     targetWindow.focus() // 确保窗口置顶
-
-    // presenter.upgradePresenter.checkUpdate()
+    // Updater is disabled—notify the user instead of silent no-op
+    import { dialog } from 'electron'
+    dialog.showMessageBox({
+      type: 'info',
+      title: '检查更新',
+      message: '此版本已禁用自动更新。',
+      buttons: ['确定']
+    })
 })

Or, to remove the item entirely:

--- a/src/main/presenter/trayPresenter.ts
+++ b/src/main/presenter/trayPresenter.ts
@@ -46,8 +46,10 @@ const menuTemplate = [
     // … other items …
-    {
-      label: labels.checkForUpdates || '检查更新',
-      click: () => eventBus.sendToMain(TRAY_EVENTS.CHECK_FOR_UPDATES)
-    },
+    // Only include “检查更新” if updater is enabled
+    ...(presenter.upgradePresenter
+      ? [{
+          label: labels.checkForUpdates || '检查更新',
+          click: () => eventBus.sendToMain(TRAY_EVENTS.CHECK_FOR_UPDATES)
+        }]
+      : []),
     // … remaining items …
 ]
src/renderer/src/stores/aiStore.ts (3)

6-6: Use English for comments to match repo guidelines

Replace the Chinese inline comment with an English one.

-    aiChange: false // 默认值
+    aiChange: false // Default value

9-14: Prefer arrow functions for actions; keep signatures concise

Coding guidelines for renderer TS recommend arrow functions for methods. Convert action methods to arrows for consistency.

   actions: {
-    toggleAiChange() {
-      this.aiChange = !this.aiChange
-    },
-    setAiChange(value: boolean) {
-      this.aiChange = value
-    }
+    toggleAiChange: () => {
+      // flip boolean flag
+      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+      // @ts-ignore -- pinia binds `this` at runtime
+      this.aiChange = !this.aiChange
+    },
+    setAiChange: (value: boolean) => {
+      // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+      // @ts-ignore -- pinia binds `this` at runtime
+      this.aiChange = value
+    }
   }

5-13: Consider a more descriptive boolean name (optional)

To align with “descriptive variable names with auxiliary verbs,” consider isAiChangeEnabled (or isAiChange) instead of aiChange. If you want this, I can generate a codemod to update references across the renderer.

src/renderer/src/stores/upgrade.ts (2)

19-21: Use English for comments to match repo guidelines

Translate the inline note near updateInfo.

-// 添加在 const updateInfo = ref<any>(null) 附近
+// Add this near: const updateInfo = ref<any>(null)

32-60: Optional: annotate function return types for stricter TS checking

Consider explicitly annotating checkUpdate and handleUpdate to keep type intent clear while the updater is disabled.

-const checkUpdate = async (silent = true) => {
+const checkUpdate = async (silent = true): Promise<void> => {
   ...
 }
-const handleUpdate = async (type: 'github' | 'netdisk' | 'auto') => {
+const handleUpdate = async (type: 'github' | 'netdisk' | 'auto'): Promise<void> => {
   ...
 }
src/shared/presenter.d.ts (2)

1054-1055: De-duplicate the “direct return” type with a shared alias to prevent divergence

directReturn appears in multiple shapes. Define a single alias and reuse it to avoid drift and simplify maintenance.

+// Shared direct-return flag type (either a simple boolean or carries aiChange detail)
+export type DirectReturnFlag = boolean | { aiChange: boolean }
@@
-  /** 是否直接返回不再继续喂回判断 */
-  directReturn?: boolean | { aiChange: boolean }
+  /** Whether to bypass further AI processing and return tool result directly */
+  directReturn?: DirectReturnFlag
@@
-  directReturn?: boolean | { aiChange: boolean }
-  direct_return?: boolean
+  directReturn?: DirectReturnFlag
+  direct_return?: boolean

If you want, I can propagate this alias to other places (e.g., tool manager and renderer store types).

Also applies to: 1261-1263


1268-1274: Minor stylistic fix: consistent semicolons in the agent event definition

In src/shared/presenter.d.ts, update the permission_request block so its fields end with semicolons:

   permission_request?: {
     toolName: string
     serverName: string
     permissionType: 'read' | 'write' | 'all'
-    description: string,
-    direct_return?: boolean
+    description: string;
+    direct_return?: boolean;
   }

No change needed in MCPToolResponse.permissionRequest

The MCPToolResponse interface already exposes its own directReturn flag at the top level (e.g.,
directReturn?: boolean | { aiChange: boolean }), and the nested permissionRequest block is solely for request metadata. Adding direct_return inside that block isn’t necessary and would duplicate the existing top-level flag.

src/renderer/src/stores/chat.ts (1)

100-121: Logs/comments should be in English per guidelines.

Multiple console.* and comments are Chinese. Please switch logs/comments to English as per the repo rules for .ts files.

Example:

- console.error('创建会话失败:', error)
+ console.error('Failed to create conversation:', error)

Apply similarly across this store.

Also applies to: 178-226, 228-253, 268-273, 298-302, 322-335, 645-715, 867-891, 1034-1047

src/renderer/src/stores/mcp.ts (1)

27-31: Align directReturn type with shared contract.

You declared directReturn?: boolean. In shared types this may be boolean | { aiChange: boolean }. To avoid narrowing issues, mirror the upstream union.

Apply this diff:

-interface MCPToolCallResult {
+interface MCPToolCallResult {
   function_name?: string
   content: string | { type: string; text: string }[]
-  directReturn?: boolean
+  directReturn?: boolean | { aiChange: boolean }
 }
src/main/presenter/mcpPresenter/toolManager.ts (1)

21-26: aiChange wiring: OK, but log in English and validate payload type.

The ipcMain.on('aiChangeEvent') handler should validate arg is boolean and use English logs per guidelines.

Apply this diff:

-ipcMain.on('aiChangeEvent', (_event, arg) => {
-  console.log('收到渲染进程消息aiChangeEvent:', arg)
-  // 处理逻辑...
-  aiChange = arg
-})
+ipcMain.on('aiChangeEvent', (_event, arg) => {
+  console.log('[MCP] Received aiChangeEvent from renderer:', arg)
+  if (typeof arg === 'boolean') {
+    aiChange = arg
+  } else {
+    console.warn('[MCP] Ignoring aiChangeEvent: expected boolean, got', typeof arg)
+  }
+})
src/main/presenter/llmProviderPresenter/index.ts (2)

958-969: Duplicate direct-return checks: keep behavior but use the same robust condition.

Unify the condition to avoid future drift, and keep emitting the final END event once.

Apply this diff in both locations:

-                  if (toolResponse.rawData && toolResponse.rawData.directReturn === true) {
+                  if (
+                    (toolResponse as any).directReturn === true ||
+                    toolResponse.rawData?.directReturn === true ||
+                    toolResponse.rawData?.directReturn?.aiChange === true
+                  ) {

Also applies to: 1033-1044


939-956: Consider adding direct_return: true to the renderer payload when short-circuiting.

When you short-circuit due to directReturn in the native and non-native paths, also include direct_return: true in the tool_call 'end' payload so the UI can mark blocks accordingly. You already do this in the early-return branch; mirror it here for consistency.

Example:

           yield {
             type: 'response',
             data: {
               eventId,
               tool_call: 'end',
               tool_call_id: toolCall.id,
               tool_call_response: /* ... */,
               tool_call_name: toolCall.name,
               tool_call_params: toolCall.arguments,
               tool_call_server_name: toolDef.server.name,
               tool_call_server_icons: toolDef.server.icons,
               tool_call_server_description: toolDef.server.description,
-              tool_call_response_raw: toolResponse.rawData
+              tool_call_response_raw: toolResponse.rawData,
+              direct_return:
+                (toolResponse as any).directReturn === true ||
+                toolResponse.rawData?.directReturn === true ||
+                toolResponse.rawData?.directReturn?.aiChange === true
             }
           }

Also applies to: 1017-1031

electron.vite.config.1755071894873.mjs (5)

1-10: File header indicates TypeScript source but this is a JavaScript file

The comment on line 1 says // electron.vite.config.ts but this is actually a .mjs file. This inconsistency could cause confusion for developers.

-// electron.vite.config.ts
+// electron.vite.config.1755071894873.mjs

2-10: Duplicate path imports can be consolidated

Both path from "path" (line 2) and path from "node:path" (line 10) are imported. Use only one consistent import style.

-import { resolve } from "path";
+import { resolve } from "node:path";
 import { defineConfig, externalizeDepsPlugin } from "electron-vite";
 import vue from "@vitejs/plugin-vue";
 import autoprefixer from "autoprefixer";
 import tailwind from "tailwindcss";
 import vueDevTools from "vite-plugin-vue-devtools";
 import svgLoader from "vite-svg-loader";
 import monacoEditorPlugin from "vite-plugin-monaco-editor-esm";
-import path from "node:path";

29-29: Using void 0 instead of undefined is unconventional

While functionally equivalent, using void 0 instead of undefined is less readable and not a common pattern in modern JavaScript/TypeScript.

-          manualChunks: void 0
+          manualChunks: undefined

68-69: Remove TypeScript-specific comments from JavaScript file

The @ts-ignore comment is not needed in a JavaScript file as TypeScript doesn't process .mjs files.

     css: {
       postcss: {
-        // @ts-ignore
         plugins: [tailwind(), autoprefixer()]
       }
     },

73-74: Consider using English for comments to maintain consistency

The comment on line 74 is in Chinese while the coding guidelines specify using English for logs and comments in TypeScript/JavaScript files.

       host: "0.0.0.0"
-      // 防止代理干扰,导致vite-electron之间ws://localhost:5713和http://localhost:5713通信失败、页面组件无法加载
+      // Prevent proxy interference that causes communication failure between vite-electron ws://localhost:5713 and http://localhost:5713, preventing component loading
src/renderer/src/components/message/MessageBlockToolCall.vue (5)

86-95: Commented-out code should be removed

Large blocks of commented code make the codebase harder to maintain. If this functionality is no longer needed, it should be removed. If it might be needed later, consider using version control to track the changes instead.

Remove the entire commented-out parameters section (lines 86-95) since it's no longer being used.


106-108: Redundant commented code for MarkdownRenderer

The commented lines for MarkdownRenderer and JsonObject are redundant since MarkdownRenderer is already being used.

             <div class="text-sm rounded-md p-3">
-              <!-- <MarkdownRenderer v-if="isMarkdownResponse(block.tool_call.response)" :content="getMarkdownContent(block.tool_call.response)" /> -->
-              <!-- <JsonObject v-else :data="parseJson(block.tool_call.response)" /> -->
               <MarkdownRenderer  :content="getMarkdownContent(block.tool_call.response)" />
             </div>

199-213: Remove entire commented-out parseJson function

The parseJson function is no longer used and should be removed entirely rather than being commented out.

Remove lines 199-213 completely as the function is no longer needed with the switch to Markdown rendering.


215-243: Consider edge cases in CSV to Markdown conversion

The csvToMarkdownTable function might not handle all CSV edge cases correctly:

  1. Cells containing commas will break the parsing
  2. Quoted values are not handled
  3. Empty cells might not render correctly

Consider using a proper CSV parsing library or adding more robust handling:

 function csvToMarkdownTable(csvString: string): string {
+  // Handle empty input
+  if (!csvString || typeof csvString !== 'string') return ''
+  
   // 按行分割,并去掉空行
   const lines = csvString
     .trim()
     .split(/\r?\n/)
     .filter(line => line.trim())

   if (lines.length === 0) return ''
+  
+  // Basic CSV parsing - this won't handle quoted values with commas
+  // Consider using a CSV parsing library for production use

   // 解析每行
   const rows = lines.map(line =>
     line
       .split(',')
       .map(cell => cell.trim()) // 去掉首尾空格
   )

126-145: Consider moving fallback translations to a proper i18n configuration

The fallback translation logic in the t function should ideally be handled by the i18n configuration rather than hardcoded in the component.

Consider extracting the fallback translations to a separate configuration file or ensuring i18n is properly initialized before component mounting.

src/renderer/src/components/ChatInput.vue (2)

793-793: Incorrect initial bar heights value

The bar heights are reset to 100 instead of a smaller value like the initial 5.

-  barHeights.value = Array.from({ length: BARS }, () => 100)
+  barHeights.value = Array.from({ length: BARS }, () => 5)

714-714: Check for browser compatibility with AudioContext

The code uses a fallback for webkit but should handle cases where neither is available.

-    audioContext = new (window.AudioContext || (window as any).webkitAudioContext)()
+    const AudioContextClass = window.AudioContext || (window as any).webkitAudioContext
+    if (!AudioContextClass) {
+      throw new Error('Web Audio API is not supported in this browser')
+    }
+    audioContext = new AudioContextClass()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 93d9095 and 54f90f9.

📒 Files selected for processing (19)
  • electron.vite.config.1755071894873.mjs (1 hunks)
  • electron.vite.config.1755572548960.mjs (1 hunks)
  • package.json (3 hunks)
  • src/main/index.ts (1 hunks)
  • src/main/presenter/index.ts (3 hunks)
  • src/main/presenter/llmProviderPresenter/index.ts (3 hunks)
  • src/main/presenter/mcpPresenter/toolManager.ts (3 hunks)
  • src/main/presenter/threadPresenter/index.ts (1 hunks)
  • src/main/presenter/upgradePresenter/index.ts (1 hunks)
  • src/renderer/src/App.vue (2 hunks)
  • src/renderer/src/components/ChatInput.vue (7 hunks)
  • src/renderer/src/components/message/MessageBlockToolCall.vue (5 hunks)
  • src/renderer/src/i18n/zh-CN/chat.json (1 hunks)
  • src/renderer/src/stores/aiStore.ts (1 hunks)
  • src/renderer/src/stores/chat.ts (2 hunks)
  • src/renderer/src/stores/mcp.ts (2 hunks)
  • src/renderer/src/stores/upgrade.ts (5 hunks)
  • src/shared/chat.d.ts (1 hunks)
  • src/shared/presenter.d.ts (5 hunks)
🧰 Additional context used
📓 Path-based instructions (21)
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for logs and comments

Files:

  • src/renderer/src/stores/mcp.ts
  • src/main/index.ts
  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/renderer/src/App.vue
  • src/main/presenter/index.ts
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/shared/presenter.d.ts
  • src/shared/chat.d.ts
  • src/renderer/src/components/ChatInput.vue
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
  • src/main/presenter/upgradePresenter/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Strict type checking enabled for TypeScript

**/*.{ts,tsx}: 始终使用 try-catch 处理可能的错误
提供有意义的错误信息
记录详细的错误日志
优雅降级处理
日志应包含时间戳、日志级别、错误代码、错误描述、堆栈跟踪(如适用)、相关上下文信息
日志级别应包括 ERROR、WARN、INFO、DEBUG
不要吞掉错误
提供用户友好的错误信息
实现错误重试机制
避免记录敏感信息
使用结构化日志
设置适当的日志级别

Files:

  • src/renderer/src/stores/mcp.ts
  • src/main/index.ts
  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/renderer/src/stores/aiStore.ts
  • src/shared/presenter.d.ts
  • src/shared/chat.d.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
  • src/main/presenter/upgradePresenter/index.ts
src/renderer/src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/src/**/*.{ts,tsx,vue}: Use Pinia for frontend state management
Renderer to Main: Use usePresenter.ts composable for direct presenter method calls

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
**/*.{js,jsx,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/development-setup.mdc)

**/*.{js,jsx,ts,tsx}: 使用 OxLint 进行代码检查
Log和注释使用英文书写

Files:

  • src/renderer/src/stores/mcp.ts
  • src/main/index.ts
  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/renderer/src/stores/aiStore.ts
  • src/shared/presenter.d.ts
  • src/shared/chat.d.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
  • src/main/presenter/upgradePresenter/index.ts
src/{main,renderer}/**/*.ts

📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)

src/{main,renderer}/**/*.ts: Use context isolation for improved security
Implement proper inter-process communication (IPC) patterns
Optimize application startup time with lazy loading
Implement proper error handling and logging for debugging

Files:

  • src/renderer/src/stores/mcp.ts
  • src/main/index.ts
  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/renderer/src/stores/aiStore.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
  • src/main/presenter/upgradePresenter/index.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/stores/mcp.ts
  • src/renderer/src/i18n/zh-CN/chat.json
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/pinia-best-practices.mdc)

src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx}: Use modules to organize related state and actions
Implement proper state persistence for maintaining data across sessions
Use getters for computed state properties
Utilize actions for side effects and asynchronous operations
Keep the store focused on global state, not component-specific data

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

📄 CodeRabbit inference engine (.cursor/rules/vue-best-practices.mdc)

src/renderer/src/**/*.{vue,ts,tsx,js,jsx}: Use the Composition API for better code organization and reusability
Implement proper state management with Pinia
Utilize Vue Router for navigation and route management
Leverage Vue's built-in reactivity system for efficient data handling

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/renderer/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

src/renderer/**/*.{ts,tsx,vue}: Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).
Use TypeScript for all code; prefer types over interfaces.
Avoid enums; use const objects instead.
Use arrow functions for methods and computed properties.
Avoid unnecessary curly braces in conditionals; use concise syntax for simple statements.

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/renderer/**/*.{vue,ts}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/renderer/**/*.{ts,vue}

📄 CodeRabbit inference engine (.cursor/rules/vue-shadcn.mdc)

src/renderer/**/*.{ts,vue}: Use useFetch and useAsyncData for data fetching.
Implement SEO best practices using Nuxt's useHead and useSeoMeta.

Files:

  • src/renderer/src/stores/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/aiStore.ts
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/stores/upgrade.ts
src/main/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Main to Renderer: Use EventBus to broadcast events via mainWindow.webContents.send()

Use Electron's built-in APIs for file system and native dialogs

Files:

  • src/main/index.ts
  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/main/presenter/upgradePresenter/index.ts
src/main/**/*.{ts,js,tsx,jsx}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

主进程代码放在 src/main

Files:

  • src/main/index.ts
  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/main/presenter/upgradePresenter/index.ts
src/main/presenter/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

One presenter per functional domain

Files:

  • src/main/presenter/threadPresenter/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/main/presenter/upgradePresenter/index.ts
src/main/presenter/llmProviderPresenter/index.ts

📄 CodeRabbit inference engine (.cursor/rules/llm-agent-loop.mdc)

src/main/presenter/llmProviderPresenter/index.ts: src/main/presenter/llmProviderPresenter/index.ts should manage the overall Agent loop, conversation history, tool execution via McpPresenter, and frontend communication via eventBus.
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.
The main Agent loop should send standardized STREAM_EVENTS (RESPONSE, END, ERROR) to the frontend via eventBus.
The main Agent loop should buffer text content, handle tool call events, format tool results for the next LLM call, and manage conversation continuation logic.

Files:

  • src/main/presenter/llmProviderPresenter/index.ts
src/renderer/src/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/src/**/*.vue: Use Composition API for all Vue 3 components
Use Tailwind CSS with scoped styles for styling
Organize components by feature in src/renderer/src/
Follow existing component patterns in src/renderer/src/ when creating new UI components
Use Composition API with proper TypeScript typing for new UI components
Implement responsive design with Tailwind CSS for new UI components
Add proper error handling and loading states for new UI components

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
src/main/presenter/index.ts

📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)

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

Files:

  • src/main/presenter/index.ts
src/shared/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Shared types in src/shared/

Files:

  • src/shared/presenter.d.ts
  • src/shared/chat.d.ts
src/shared/*.d.ts

📄 CodeRabbit inference engine (.cursor/rules/electron-best-practices.mdc)

The shared/*.d.ts files are used to define the types of objects exposed by the main process to the renderer process

Files:

  • src/shared/presenter.d.ts
  • src/shared/chat.d.ts
src/shared/**/*.{ts,tsx,d.ts}

📄 CodeRabbit inference engine (.cursor/rules/project-structure.mdc)

共享类型定义放在 shared 目录

Files:

  • src/shared/presenter.d.ts
  • src/shared/chat.d.ts
🧠 Learnings (34)
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tool in mcpPresenter/index.ts

Applied to files:

  • src/renderer/src/stores/mcp.ts
  • src/main/presenter/index.ts
  • src/shared/presenter.d.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield tool call events (`tool_call_start`, `tool_call_chunk`, `tool_call_end`) in the standardized format.

Applied to files:

  • src/main/presenter/threadPresenter/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/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/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/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/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/shared/presenter.d.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/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/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/shared/presenter.d.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/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/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/main/presenter/index.ts
  • src/shared/presenter.d.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : 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/index.ts
  • src/main/presenter/llmProviderPresenter/index.ts
  • src/shared/presenter.d.ts
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Implement coreStream method following standardized event interface in LLM provider files

Applied to files:

  • src/main/presenter/threadPresenter/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : 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/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : All provider implementations must parse provider-specific data chunks and yield standardized events for text, reasoning, tool calls, usage, errors, stop reasons, and image data.

Applied to files:

  • src/main/presenter/threadPresenter/index.ts
📚 Learning: 2025-07-21T01:46:52.880Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/llm-agent-loop.mdc:0-0
Timestamp: 2025-07-21T01:46:52.880Z
Learning: Applies to src/main/presenter/llmProviderPresenter/providers/*.ts : Provider implementations should yield stop events with appropriate `stop_reason` in the standardized format.

Applied to files:

  • src/main/presenter/threadPresenter/index.ts
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Use Shadcn Vue, Radix Vue, and Tailwind for components and styling.

Applied to files:

  • package.json
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Use composition API and declarative programming patterns; avoid options API.

Applied to files:

  • src/renderer/src/App.vue
📚 Learning: 2025-07-21T01:47:28.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:47:28.817Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx,js,jsx} : Use the Composition API for better code organization and reusability

Applied to files:

  • src/renderer/src/App.vue
📚 Learning: 2025-07-21T01:47:28.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:47:28.817Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx,js,jsx} : Utilize Vue Router for navigation and route management

Applied to files:

  • src/renderer/src/App.vue
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Use <script setup> syntax for concise component definitions.

Applied to files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Renderer to Main: Use usePresenter.ts composable for direct presenter method calls

Applied to files:

  • src/renderer/src/App.vue
  • src/main/presenter/index.ts
  • src/renderer/src/stores/upgrade.ts
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/{composables,utils}/**/*.ts : Use VueUse for common composables and utility functions.

Applied to files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Leverage ref, reactive, and computed for reactive state management.

Applied to files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/renderer/src/**/*.vue : Use Composition API with proper TypeScript typing for new UI components

Applied to files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Use Vue 3 with TypeScript, leveraging defineComponent and PropType.

Applied to files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/main/presenter/configPresenter/**/*.ts : Centralize configuration in configPresenter/

Applied to files:

  • src/main/presenter/index.ts
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/main/presenter/**/*.ts : One presenter per functional domain

Applied to files:

  • src/main/presenter/index.ts
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/electron-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:45:54.229Z
Learning: Applies to src/renderer/src/composables/usePresenter.ts : The IPC in the renderer process is implemented in usePresenter.ts, allowing direct calls to the presenter-related interfaces exposed by the main process

Applied to files:

  • src/main/presenter/index.ts
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/stores/**/*.ts : Use Pinia for state management.

Applied to files:

  • src/renderer/src/stores/aiStore.ts
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Use Pinia for frontend state management

Applied to files:

  • src/renderer/src/stores/aiStore.ts
📚 Learning: 2025-07-21T01:47:03.479Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/pinia-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:47:03.479Z
Learning: Applies to src/renderer/src/stores/**/*.{vue,ts,tsx,js,jsx} : Use modules to organize related state and actions

Applied to files:

  • src/renderer/src/stores/aiStore.ts
📚 Learning: 2025-07-21T01:47:28.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-best-practices.mdc:0-0
Timestamp: 2025-07-21T01:47:28.817Z
Learning: Applies to src/renderer/src/**/*.{vue,ts,tsx,js,jsx} : Implement proper state management with Pinia

Applied to files:

  • src/renderer/src/stores/aiStore.ts
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Import Icon component from Iconify/Vue.

Applied to files:

  • src/renderer/src/components/message/MessageBlockToolCall.vue
  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-23T00:45:57.322Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/vue-shadcn.mdc:0-0
Timestamp: 2025-07-23T00:45:57.322Z
Learning: Applies to src/renderer/**/*.{vue} : Use Iconify/Vue for icon implementation.

Applied to files:

  • src/renderer/src/components/message/MessageBlockToolCall.vue
📚 Learning: 2025-07-21T01:46:30.354Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: .cursor/rules/i18n.mdc:0-0
Timestamp: 2025-07-21T01:46:30.354Z
Learning: Applies to src/renderer/src/**/* : Use the 'vue-i18n' framework for all internationalization in the renderer

Applied to files:

  • src/renderer/src/components/ChatInput.vue
📚 Learning: 2025-07-21T01:45:54.229Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#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/mcpPresenter/toolManager.ts
📚 Learning: 2025-07-21T01:45:33.790Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-21T01:45:33.790Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tool in src/main/presenter/mcpPresenter/inMemoryServers/ when adding a new MCP tool

Applied to files:

  • src/main/presenter/mcpPresenter/toolManager.ts
📚 Learning: 2025-06-21T15:49:17.044Z
Learnt from: neoragex2002
PR: ThinkInAIXYZ/deepchat#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/renderer/src/stores/chat.ts
🪛 Biome (2.1.2)
src/renderer/src/stores/upgrade.ts

[error] 63-64: This code is unreachable

(lint/correctness/noUnreachable)


[error] 76-77: This code is unreachable

(lint/correctness/noUnreachable)

🔇 Additional comments (6)
src/main/presenter/upgradePresenter/index.ts (1)

1-441: Add explicit ES module no-op export in upgradePresenter

To make it clear that this module intentionally exports nothing—and to prevent it from being treated as a script module—please add at the top (or bottom) of src/main/presenter/upgradePresenter/index.ts:

+// Explicitly mark this module as an ES module with no exports
+export {}

I’ve searched the codebase for any live references to upgradePresenter and found only commented-out occurrences in:

  • src/shared/presenter.d.ts (line 322)
  • src/renderer/src/stores/upgrade.ts (lines 7–8)
  • src/main/index.ts (line 128)
  • src/main/presenter/index.ts (lines 14, 48, 80)

No active imports or usages remain, so adding this no-op export is safe.

package.json (1)

67-67: The next step is to confirm that your existing asarUnpack patterns actually cover the native .node binaries introduced by @nut-tree/nut-js. Please run the script above to dump the surrounding lines. Once we can see whether there’s a glob like **/*.node (or specifically targeting node_modules/@nut-tree/nut-js/**/*.node), we can:

  • If present: mark this as ✅ resolved—your current config already unpacks the native modules correctly.
  • If absent or too narrow: I’ll recommend adding something like:
    asarUnpack:
      - '**/*.node'
      - 'node_modules/@nut-tree/nut-js/**/*.node'

to ensure all native binaries are unpacked.

Let me know the output of the snippet above, and I’ll update the review accordingly.

src/renderer/src/stores/chat.ts (2)

334-335: Type shape for direct_return looks fine; verify upstream emits the same key.

You added msg.direct_return?: boolean here. Ensure the upstream emitter (LLMProviderPresenter) uses the exact snake_case key direct_return in its STREAM_EVENTS.RESPONSE payload; otherwise this flag will never be observed.

Run-time check suggestion: set a breakpoint or add a temporary console.info('direct_return seen', msg.direct_return) to confirm it flips when aiChange/directReturn is active.


470-474: Good: persist direct-return semantics into tool_call block.

Setting existingToolCallBlock.tool_call.direct_return = true enables specialized rendering later. No changes needed here.

src/renderer/src/stores/mcp.ts (1)

498-509: Event handler no longer updates toolResults; confirm this is intentional.

You now only log the result. If any UI depends on toolResults when tools are invoked via UI (not the agent loop), this removal regresses behavior.

If this was accidental, restore assignment:

-        console.log(`MCP tool call result:`, result)
+        console.log(`MCP tool call result:`, result)
+        if (result && result.function_name) {
+          toolResults.value[result.function_name] = result.content
+        }
electron.vite.config.1755071894873.mjs (1)

79-81: Unused function parameters should follow naming convention

The unused parameters in the customDistPath function should be prefixed with underscore, which is already done for _root and _base, but the pattern could be more consistent.

The naming convention for unused parameters is correctly applied.

Comment on lines +1 to +104
// electron.vite.config.ts
import { resolve } from "path";
import { defineConfig, externalizeDepsPlugin } from "electron-vite";
import vue from "@vitejs/plugin-vue";
import autoprefixer from "autoprefixer";
import tailwind from "tailwindcss";
import vueDevTools from "vite-plugin-vue-devtools";
import svgLoader from "vite-svg-loader";
import monacoEditorPlugin from "vite-plugin-monaco-editor-esm";
import path from "node:path";
var electron_vite_config_default = defineConfig({
main: {
plugins: [
externalizeDepsPlugin({
exclude: ["mermaid", "dompurify"]
})
],
resolve: {
alias: {
"@": resolve("src/main/"),
"@shared": resolve("src/shared")
}
},
build: {
rollupOptions: {
external: ["sharp", "@duckdb/node-api"],
output: {
inlineDynamicImports: true,
manualChunks: void 0
// Disable automatic chunk splitting
}
}
}
},
preload: {
plugins: [externalizeDepsPlugin()],
resolve: {
alias: {
"@shared": resolve("src/shared")
}
},
build: {
rollupOptions: {
input: {
index: resolve("src/preload/index.ts"),
floating: resolve("src/preload/floating-preload.ts")
}
}
}
},
renderer: {
optimizeDeps: {
include: [
"monaco-editor",
"axios"
]
},
resolve: {
alias: {
"@": resolve("src/renderer/src"),
"@shell": resolve("src/renderer/shell"),
"@shared": resolve("src/shared"),
vue: "vue/dist/vue.esm-bundler.js"
}
},
css: {
postcss: {
// @ts-ignore
plugins: [tailwind(), autoprefixer()]
}
},
server: {
host: "0.0.0.0"
// 防止代理干扰,导致vite-electron之间ws://localhost:5713和http://localhost:5713通信失败、页面组件无法加载
},
plugins: [
monacoEditorPlugin({
languageWorkers: ["editorWorkerService", "typescript", "css", "html", "json"],
customDistPath(_root, buildOutDir, _base) {
return path.resolve(buildOutDir, "monacoeditorwork");
}
}),
vue(),
svgLoader(),
vueDevTools({
// use export LAUNCH_EDITOR=cursor instead
// launchEditor: 'cursor'
})
],
build: {
minify: "esbuild",
rollupOptions: {
input: {
shell: resolve("src/renderer/shell/index.html"),
index: resolve("src/renderer/index.html"),
floating: resolve("src/renderer/floating/index.html")
}
}
}
}
});
export {
electron_vite_config_default as default
};
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Duplicate configuration file with identical content

This file appears to be an exact duplicate of electron.vite.config.1755071894873.mjs. Having multiple identical configuration files can lead to confusion and maintenance issues.

Consider removing the duplicate file and keeping only one configuration file to avoid confusion.


🏁 Script executed:

#!/bin/bash
# Check if both files are identical
if cmp -s "electron.vite.config.1755071894873.mjs" "electron.vite.config.1755572548960.mjs"; then
    echo "Files are identical"
else
    echo "Files differ"
    diff -u "electron.vite.config.1755071894873.mjs" "electron.vite.config.1755572548960.mjs" | head -20
fi

# Check if there's a primary config file
if [ -f "electron.vite.config.ts" ]; then
    echo "Found primary TypeScript config: electron.vite.config.ts"
fi

# Check references to these config files
echo -e "\nReferences to config files:"
rg -n "electron\.vite\.config\.(1755071894873|1755572548960|ts)" --type json --type js --type ts

Length of output: 644


🏁 Script executed:

#!/bin/bash
# Verify both config files exist
if [ ! -f electron.vite.config.1755071894873.mjs ] || [ ! -f electron.vite.config.1755572548960.mjs ]; then
  echo "ERROR: One or both config files not found."
  exit 1
fi

# Compare checksums to determine if files are truly identical
if command -v md5sum >/dev/null 2>&1; then
  echo "Using md5sum to compare files:"
  md5sum electron.vite.config.1755071894873.mjs electron.vite.config.1755572548960.mjs
elif command -v shasum >/dev/null 2>&1; then
  echo "Using shasum to compare files:"
  shasum -a 256 electron.vite.config.1755071894873.mjs electron.vite.config.1755572548960.mjs
else
  echo "No suitable hashing tool (md5sum/shasum) available."
  exit 1
fi

# Check for a single canonical TypeScript config
if [ -f electron.vite.config.ts ]; then
  echo "Found primary TypeScript config: electron.vite.config.ts"
else
  echo "No primary TypeScript config (electron.vite.config.ts) found."
fi

# Search codebase for any references to these timestamped config files
echo
echo "References to timestamped config files in repository:"
grep -R --include='*.mjs' --include='*.ts' "electron.vite.config.1755071894873" -n . || echo "  (none found)"
grep -R --include='*.mjs' --include='*.ts' "electron.vite.config.1755572548960" -n . || echo "  (none found)"

Length of output: 968


Remove duplicate timestamped Vite config files

Both electron.vite.config.1755071894873.mjs and electron.vite.config.1755572548960.mjs are bit-for-bit identical (same SHA-256 checksum) and aren’t referenced anywhere in the codebase. Keeping both can cause confusion and accidental drift.

• Delete one (or both) of the timestamped .mjs files – e.g.:

  • Remove electron.vite.config.1755071894873.mjs
  • Remove electron.vite.config.1755572548960.mjs

• Consolidate on the single canonical config:

  • Use electron.vite.config.ts as your primary Vite/Electron configuration.
  • Update any build or start scripts to reference the .ts file directly, if they currently point to a timestamped .mjs.

This cleanup will reduce maintenance overhead and eliminate ambiguity about which config is “authoritative.”

🤖 Prompt for AI Agents
In electron.vite.config.1755572548960.mjs lines 1-104: these timestamped .mjs
Vite config files are duplicates and unreferenced; delete one or both duplicate
files (e.g., remove electron.vite.config.1755071894873.mjs and
electron.vite.config.1755572548960.mjs), consolidate on the canonical
electron.vite.config.ts, and update any build/start scripts or config references
to point to electron.vite.config.ts instead of the timestamped .mjs filenames.

Comment on lines +84 to 85
"marked": "^16.1.2",
"mime-types": "^2.1.35",
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Sanitize Markdown rendering to prevent XSS in the renderer

Adding marked is fine, but never inject its output without sanitization. Ensure DOMPurify (or equivalent) is applied, and avoid v-html with untrusted content.

If you’re using marked directly, wrap its output like:

import DOMPurify from 'dompurify'
const html = DOMPurify.sanitize(marked(markdown))

Quick check for sanitization paths:


🏁 Script executed:

#!/bin/bash
rg -nP -C2 '\bmarked\(|MarkdownRenderer|v-html' src/renderer | sed -n '1,120p'
rg -nP -C2 'DOMPurify|sanitize' src/renderer | sed -n '1,120p'

Length of output: 10324


🏁 Script executed:

#!/bin/bash
# Locate renderMarkdown imports and definitions
rg -nP 'import\s+.*renderMarkdown' -n src/renderer
rg -nP 'export\s+function\s+renderMarkdown' -C4 -n src/renderer
# Check if MarkdownRenderer.vue uses v-html without sanitization
rg -nP 'v-html' -C3 src/renderer/src/components/markdown/MarkdownRenderer.vue

Length of output: 743


Enforce sanitization on all v-html renderings

We’ve identified several places where untrusted HTML is rendered via v-html without any sanitization, which poses an XSS risk. Please apply DOMPurify.sanitize (or a comparable HTML sanitizer) to every such output:

• src/renderer/src/components/settings/AboutUsSettings.vue (line 126)

- <div class="… overflow-y-auto" v-html="disclaimerContent"></div>
+ <div class="… overflow-y-auto"
+      v-html="DOMPurify.sanitize(disclaimerContent)"></div>

Add at top:

import DOMPurify from 'dompurify'

• src/renderer/src/components/ui/UpdateDialog.vue (line 13)

- v-html="renderMarkdown(getCommonMarkdown(), upgrade.updateInfo?.releaseNotes || '')"
+ v-html="DOMPurify.sanitize(
+     renderMarkdown(getCommonMarkdown(), upgrade.updateInfo?.releaseNotes || '')
+   )"

Ensure import DOMPurify from 'dompurify' is present.

• src/renderer/src/components/message/MessageBlockThink.vue (line 24)

- <div … v-html="renderedContent"></div>
+ <div … v-html="DOMPurify.sanitize(renderedContent)"></div>

• src/renderer/src/components/artifacts/SvgArtifact.vue (line 2)

- const sanitizedContent = computed(() => props.block.content || '')
+ const sanitizedContent = computed(() =>
+   DOMPurify.sanitize(props.block.content || '', { SAFE_FOR_SVG: true })
+ )

• src/renderer/src/components/artifacts/HTMLArtifact.vue
Re-enable and adjust the commented‐out sanitizer code:

- // const sanitizedContent = computed(() => {
- //   if (!props.block.content) return ''
- //   return DOMPurify.sanitize(props.block.content, {
- //     WHOLE_DOCUMENT: true,
- //     ADD_TAGS: ['script', 'style'],
- //   })
- // })
+ const sanitizedContent = computed(() =>
+   DOMPurify.sanitize(props.block.content || '', {
+     WHOLE_DOCUMENT: true,
+     ADD_TAGS: ['script', 'style'],
+   })
+ )

Optional cleanup: remove the <!-- eslint-disable vue/no-v-html --> comments in MarkdownRenderer.vue, since it doesn’t actually use v-html and you should restrict disabling this rule only where truly necessary.

🤖 Prompt for AI Agents
In package.json lines 84-85 and across the renderer files:
src/renderer/src/components/settings/AboutUsSettings.vue (around line 126),
src/renderer/src/components/ui/UpdateDialog.vue (around line 13),
src/renderer/src/components/message/MessageBlockThink.vue (around line 24),
src/renderer/src/components/artifacts/SvgArtifact.vue (near top), and
src/renderer/src/components/artifacts/HTMLArtifact.vue, the review flags
unsanitized v-html usages; import DOMPurify from 'dompurify' at the top of each
listed component (or ensure the import already exists) and replace direct v-html
bindings with sanitized content by passing the HTML through
DOMPurify.sanitize(...) before rendering; in HTMLArtifact.vue re-enable and
adapt the previously commented sanitizer code to sanitize artifact HTML output;
optionally remove unnecessary <!-- eslint-disable vue/no-v-html --> in
MarkdownRenderer.vue and only keep the rule disabled where v-html is truly
required.

import { ThreadPresenter } from './threadPresenter'
import { DevicePresenter } from './devicePresenter'
import { UpgradePresenter } from './upgradePresenter'
// import { UpgradePresenter } from './upgradePresenter'
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Remove updater references rather than commenting them out; verify no remaining usages

If the updater is intentionally disabled, delete the import, property, and instantiation to avoid drift and accidental reintroduction. Commented-out members on a central class invite merge conflicts later.

Apply removals in these spots:

-// import { UpgradePresenter } from './upgradePresenter'
-  // upgradePresenter: UpgradePresenter
-    // this.upgradePresenter = new UpgradePresenter()

And confirm there are no lingering references:

Also applies to: 48-48, 80-81


🏁 Script executed:

#!/bin/bash
rg -n -C2 '\bupgradePresenter\b|UpgradePresenter' --glob '!**/node_modules/**'

Length of output: 3848


Remove all commented-out UpgradePresenter references and related artifacts

The upgrade functionality appears to be fully disabled, yet there are numerous commented-out references, type declarations, store hooks, and documentation entries that should be cleaned up to prevent code drift and merge conflicts. Please apply the following removals and refactorings:

• In src/main/presenter/index.ts
– Remove the import on line 14
– Remove the commented-out property on line 48
– Remove the commented-out instantiation on line 80

• Delete the entire src/main/presenter/upgradePresenter/ folder (no active code is used)

• In src/shared/presenter.d.ts
– Remove the commented-out upgradePresenter: IUpgradePresenter declaration (around line 322)
– Remove the commented-out IUpgradePresenter interface (around lines 865–867)

• In src/renderer/src/stores/upgrade.ts
– Remove the commented-out usePresenter('upgradePresenter') hook on line 7

• In documentation files:
– Remove the UpgradePresenter entry in docs/event-system-design.md (line 58)
– Remove the UpgradePresenter box in docs/deepchat-architecture-overview.md (line 22)

After applying these changes, run:

rg -n '\bupgradePresenter\b|UpgradePresenter\b' --glob '!**/node_modules/**'

to confirm no residual references remain.

🤖 Prompt for AI Agents
In src/main/presenter/index.ts around lines 14, 48 and 80 remove the
commented-out import on line 14, the commented-out property on line 48, and the
commented-out instantiation on line 80; delete the entire
src/main/presenter/upgradePresenter/ folder; in src/shared/presenter.d.ts remove
the commented-out upgradePresenter: IUpgradePresenter declaration (around line
322) and the commented-out IUpgradePresenter interface (around lines 865–867);
in src/renderer/src/stores/upgrade.ts remove the commented-out
usePresenter('upgradePresenter') hook on line 7; in docs/event-system-design.md
remove the UpgradePresenter entry (line 58) and in
docs/deepchat-architecture-overview.md remove the UpgradePresenter box (line
22); after making these deletions run rg -n
'\bupgradePresenter\b|UpgradePresenter\b' --glob '!**/node_modules/**' to
confirm no residual references remain.

Comment on lines +825 to +832
const directReturnValue =
typeof toolResponse.rawData.directReturn === 'boolean'
? toolResponse.rawData.directReturn
: toolResponse.rawData.directReturn?.aiChange
console.log('index-toolResponse.rawData.directReturn', directReturnValue)
if (directReturnValue) {
console.log(
`[Agent Loop] Direct return tool result for ${toolCall.name}, skipping AI processing`
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

Direct-return detection reads rawData only; also check top-level 'directReturn'.

ToolManager now sets directReturn at top-level and (after the fix) inside rawData. Make detection robust by checking both.

Apply this diff:

-                const directReturnValue =
-                  typeof toolResponse.rawData.directReturn === 'boolean'
-                    ? toolResponse.rawData.directReturn
-                    : toolResponse.rawData.directReturn?.aiChange
+                const directReturnValue =
+                  (typeof (toolResponse as any).directReturn === 'boolean'
+                    ? (toolResponse as any).directReturn
+                    : undefined) ??
+                  (typeof toolResponse.rawData?.directReturn === 'boolean'
+                    ? toolResponse.rawData.directReturn
+                    : toolResponse.rawData?.directReturn?.aiChange)

Also applies to: 835-857

🤖 Prompt for AI Agents
In src/main/presenter/llmProviderPresenter/index.ts around lines 825-832 (and
also apply same change to 835-857), the direct-return detection only inspects
toolResponse.rawData.directReturn; update the logic to first check the top-level
toolResponse.directReturn (which may be boolean) and then fall back to
rawData.directReturn (handling both boolean and object with aiChange) so the
code respects directReturn set at either location; replace the current
conditional computation with one that checks toolResponse.directReturn ||
(typeof rawData.directReturn === 'boolean' ? rawData.directReturn :
rawData.directReturn?.aiChange) and use that combined value where
directReturnValue is used.

Comment on lines +36 to +46
if (!ipcMain.listenerCount('simulate-capslock')) {
ipcMain.on('simulate-capslock', async (_event, action) => {
if (action === 'press') {
await keyboard.type(Key.CapsLock);
console.log('主进程: 模拟按下 CapsLock-press');
} else if (action === 'release') {
await keyboard.type(Key.CapsLock);
console.log('主进程: 模拟释放 CapsLock-release');
}
});
}
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

CapsLock simulation toggles twice; use press/release APIs instead of type().

Calling keyboard.type(Key.CapsLock) on both press and release will toggle twice. Use keyboard.pressKey / keyboard.releaseKey for correctness; also use English logs.

Apply this diff:

-  ipcMain.on('simulate-capslock', async (_event, action) => {
-    if (action === 'press') {
-      await keyboard.type(Key.CapsLock);
-      console.log('主进程: 模拟按下 CapsLock-press');
-    } else if (action === 'release') {
-      await keyboard.type(Key.CapsLock);
-      console.log('主进程: 模拟释放 CapsLock-release');
-    }
-  });
+  ipcMain.on('simulate-capslock', async (_event, action) => {
+    if (action === 'press') {
+      await keyboard.pressKey(Key.CapsLock)
+      console.log('[MCP] Simulate CapsLock press')
+    } else if (action === 'release') {
+      await keyboard.releaseKey(Key.CapsLock)
+      console.log('[MCP] Simulate CapsLock release')
+    } else {
+      console.warn('[MCP] Unknown simulate-capslock action:', action)
+    }
+  })
📝 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
if (!ipcMain.listenerCount('simulate-capslock')) {
ipcMain.on('simulate-capslock', async (_event, action) => {
if (action === 'press') {
await keyboard.type(Key.CapsLock);
console.log('主进程: 模拟按下 CapsLock-press');
} else if (action === 'release') {
await keyboard.type(Key.CapsLock);
console.log('主进程: 模拟释放 CapsLock-release');
}
});
}
if (!ipcMain.listenerCount('simulate-capslock')) {
ipcMain.on('simulate-capslock', async (_event, action) => {
if (action === 'press') {
await keyboard.pressKey(Key.CapsLock)
console.log('[MCP] Simulate CapsLock press')
} else if (action === 'release') {
await keyboard.releaseKey(Key.CapsLock)
console.log('[MCP] Simulate CapsLock release')
} else {
console.warn('[MCP] Unknown simulate-capslock action:', action)
}
})
}
🤖 Prompt for AI Agents
In src/main/presenter/mcpPresenter/toolManager.ts around lines 36 to 46, the
handler calls keyboard.type(Key.CapsLock) for both 'press' and 'release' which
toggles CapsLock twice; replace those calls with the appropriate press and
release APIs (keyboard.pressKey(Key.CapsLock) for action === 'press' and
keyboard.releaseKey(Key.CapsLock) for action === 'release'), update the
console.log messages to English (e.g., "Main: simulate CapsLock press" and
"Main: simulate CapsLock release"), and keep the existing ipcMain.listenerCount
guard unchanged.

Comment on lines +1329 to +1344
const aiChangeIsActiveState = localStorage.getItem('aiChangeIsActiveState')
if (aiChangeIsActiveState == 'true') {
aiChangeIsActive.value = true
window.electron.ipcRenderer.send('aiChangeEvent', {
aiChange: false
})
aiChangeState.value = JSON.stringify(false)
} else if (aiChangeIsActiveState == 'false') {
aiChangeIsActive.value = false
window.electron.ipcRenderer.send('aiChangeEvent', {
aiChange: true
})
aiChangeState.value = JSON.stringify(true)
} else {
return
}
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

Complex and confusing AI change initialization logic

The initialization logic for AI change state is overly complex with string comparisons and multiple negations.

-  const aiChangeIsActiveState = localStorage.getItem('aiChangeIsActiveState')
-  if (aiChangeIsActiveState == 'true') {
-    aiChangeIsActive.value = true
-    window.electron.ipcRenderer.send('aiChangeEvent', {
-      aiChange: false
-    })
-    aiChangeState.value = JSON.stringify(false)
-  } else if (aiChangeIsActiveState == 'false') {
-    aiChangeIsActive.value = false
-    window.electron.ipcRenderer.send('aiChangeEvent', {
-      aiChange: true
-    })
-    aiChangeState.value = JSON.stringify(true)
-  } else {
-    return
-  }
+  // Initialize AI change state from localStorage
+  const savedState = localStorage.getItem('isAiChangeEnabled')
+  if (savedState !== null) {
+    isAiChangeEnabled.value = savedState === 'true'
+    window.electron.ipcRenderer.send('aiChangeEvent', {
+      aiChange: !isAiChangeEnabled.value
+    })
+  }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/renderer/src/components/ChatInput.vue around lines 1329 to 1344, the
localStorage-based AI change initialization uses verbose string comparisons and
double-negation; replace it by reading the stored value once, return early if
null/undefined, parse it to a boolean (e.g. JSON.parse or value === 'true'), set
aiChangeIsActive.value to that boolean, compute const opposite = !thatBoolean,
send window.electron.ipcRenderer.send('aiChangeEvent', { aiChange: opposite }),
and set aiChangeState.value = JSON.stringify(opposite) — this removes duplicated
branches and clarifies intent.

Comment on lines +156 to +161
onMounted(() => {
console.log("pMessageBlockToolCall-block.tool_call",props.block.tool_call?.direct_return)
if (props.block.tool_call?.direct_return === true) {
isExpanded.value = true
}
})
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

Remove debug console.log statement

Debug logging should be removed from production code.

 // 在组件挂载时检查direct_return属性
 onMounted(() => {
-  console.log("pMessageBlockToolCall-block.tool_call",props.block.tool_call?.direct_return)
   if (props.block.tool_call?.direct_return === true) {
     isExpanded.value = true
   }
 })
📝 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
onMounted(() => {
console.log("pMessageBlockToolCall-block.tool_call",props.block.tool_call?.direct_return)
if (props.block.tool_call?.direct_return === true) {
isExpanded.value = true
}
})
// 在组件挂载时检查direct_return属性
onMounted(() => {
if (props.block.tool_call?.direct_return === true) {
isExpanded.value = true
}
})
🤖 Prompt for AI Agents
In src/renderer/src/components/message/MessageBlockToolCall.vue around lines 156
to 161, remove the debug console.log call left in onMounted; simply delete the
console.log statement and leave the existing logic that checks
props.block.tool_call?.direct_return and sets isExpanded.value to true, ensuring
no other behavior is changed.

Comment on lines 248 to +250
try {
const parsed = JSON.parse(jsonStr)
if (parsed) {
if (typeof parsed === 'object' || Array.isArray(parsed)) {
return parsed
} else {
return { raw: parsed }
}
}
return parsed
console.log("getMarkdownContent-content",content)
const markdownContent = csvToMarkdownTable(content);
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

Remove debug console.log in production code

Debug logging in the getMarkdownContent function should be removed.

   try {
-    console.log("getMarkdownContent-content",content)
     const markdownContent = csvToMarkdownTable(content);
     return markdownContent
📝 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
try {
const parsed = JSON.parse(jsonStr)
if (parsed) {
if (typeof parsed === 'object' || Array.isArray(parsed)) {
return parsed
} else {
return { raw: parsed }
}
}
return parsed
console.log("getMarkdownContent-content",content)
const markdownContent = csvToMarkdownTable(content);
try {
const markdownContent = csvToMarkdownTable(content);
return markdownContent
🤖 Prompt for AI Agents
In src/renderer/src/components/message/MessageBlockToolCall.vue around lines 248
to 250, remove the debug console.log("getMarkdownContent-content", content) call
from the getMarkdownContent try block; simply delete that line so production
code no longer emits debug logs and keep the subsequent logic (assigning
markdownContent via csvToMarkdownTable(content)) intact.

Comment on lines +8 to +9
"aiChange":"AI处理结果",
"SoundInput":"语音输入",
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Key naming consistency: prefer lower camelCase for i18n keys

Most keys under input use lower camelCase (e.g., fileArea, inputArea). SoundInput deviates. Recommend renaming to soundInput for consistency. Also ensure en/other locales add matching keys.

Rename here:

-    "aiChange":"AI处理结果",
-    "SoundInput":"语音输入",
+    "aiChange": "AI处理结果",
+    "soundInput": "语音输入",

Please verify:


🏁 Script executed:

#!/bin/bash
# Check other locales and call sites
fd 'chat\.json' src/renderer/src/i18n | xargs -I{} rg -n 'soundInput|SoundInput' {}
rg -n --type ts --type vue -C2 '\$t\(.+SoundInput.+\)|i18n\.t\(.+SoundInput.+\)'

Length of output: 227


🏁 Script executed:

#!/bin/bash
# List all chat.json locale files
fd 'chat\.json' src/renderer/src/i18n

# For each locale file, check for the existing and proposed key variants
for file in $(fd 'chat\.json' src/renderer/src/i18n); do
  echo "=== $file ==="
  rg -n '"SoundInput"' "$file" || echo "  ✗ no \"SoundInput\""
  rg -n '"soundInput"' "$file" || echo "  ✗ no \"soundInput\""
done

# Search for references to the key in translation calls
rg -n "\$t\(.+SoundInput.+\)" -C2 src/renderer/src || echo "  ✗ no $t('…SoundInput…') patterns"
rg -n "i18n\.t\(.+SoundInput.+\)" -C2 src/renderer/src || echo "  ✗ no i18n.t('…SoundInput…') patterns"

# Broad search for any leftover usages of SoundInput in code
rg -n SoundInput -g "*.{ts,vue}" -C2 src/renderer/src || echo "  ✗ no SoundInput references in TS/Vue files"

Length of output: 5368


Action Required: Rename and Propagate SoundInputsoundInput

To maintain lower-camelCase consistency for i18n keys under chat.input and ensure all locales and call sites stay in sync, please:

• In every src/renderer/src/i18n/<locale>/chat.json file:

  • Rename the existing key in zh-CN and add the new key to all other locales.
  • Example diff for zh-CN:
     "input": {
    -  "aiChange": "AI处理结果",
    -  "SoundInput": "语音输入",
    +  "aiChange": "AI处理结果",
    +  "soundInput": "语音输入",
       …
     }
  • For en-US, fa-IR, fr-FR, ja-JP, ko-KR, ru-RU, zh-HK, zh-TW, insert under "input":
    "soundInput": "<appropriate translation>",
    (Use an empty string or fallback copy until translations are available.)

• In src/renderer/src/components/ChatInput.vue, update the translation lookup:

- <TooltipContent>{{ t('chat.input.SoundInput') }}</TooltipContent>
+ <TooltipContent>{{ t('chat.input.soundInput') }}</TooltipContent>

No other call sites or code references to the translation key were found; the SoundInput function and its @click handler remain unchanged.

🤖 Prompt for AI Agents
In src/renderer/src/i18n/zh-CN/chat.json around lines 8–9, the i18n key
"SoundInput" must be renamed to lower-camelCase "soundInput"; update zh-CN by
replacing "SoundInput":"语音输入" with "soundInput":"语音输入". Then add the new
"soundInput" key under the "input" object in every other locale file at
src/renderer/src/i18n/<locale>/chat.json (en-US, fa-IR, fr-FR, ja-JP, ko-KR,
ru-RU, zh-HK, zh-TW) with appropriate translations or an empty string as a
placeholder. Finally, update the translation lookup in
src/renderer/src/components/ChatInput.vue to use "input.soundInput"
(lower-camelCase) instead of "input.SoundInput" so the component resolves the
new key.

Comment on lines +64 to 71
const startUpdate = async () => {
try {
return await upgradeP.goDownloadUpgrade(type)
return
// return await upgradeP.goDownloadUpgrade(type)
} catch (error) {
console.error('Failed to start update:', error)
return false
}
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

Fix unreachable/early return and make return type explicit

Static analysis flagged unreachable code; the immediate return inside startUpdate also makes intent unclear. Since the updater is disabled, return a boolean consistently.

-// const startUpdate = async (type: 'github' | 'netdisk') => {
-const startUpdate = async () => {
-  try {
-    return
-    // return await upgradeP.goDownloadUpgrade(type)
-  } catch (error) {
-    console.error('Failed to start update:', error)
-    return false
-  }
-}
+// const startUpdate = async (type: 'github' | 'netdisk') => {
+const startUpdate = async (): Promise<boolean> => {
+  try {
+    // Updater disabled; always return false
+    return false
+  } catch (error) {
+    console.error('Failed to start update:', error)
+    return false
+  }
+}
📝 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
const startUpdate = async () => {
try {
return await upgradeP.goDownloadUpgrade(type)
return
// return await upgradeP.goDownloadUpgrade(type)
} catch (error) {
console.error('Failed to start update:', error)
return false
}
// const startUpdate = async (type: 'github' | 'netdisk') => {
const startUpdate = async (): Promise<boolean> => {
try {
// Updater disabled; always return false
return false
} catch (error) {
console.error('Failed to start update:', error)
return false
}
}
🤖 Prompt for AI Agents
In src/renderer/src/stores/upgrade.ts around lines 64 to 71, remove the
immediate unreachable `return` so the function consistently returns a boolean;
inside the try block return the awaited result of the updater call (e.g.,
`return await upgradeP.goDownloadUpgrade(type)`) or, if the updater is
intentionally disabled, explicitly return false there, and keep the catch
returning false; also make the function's return type explicit as
Promise<boolean> so callers get a consistent boolean result.

@zerob13
Copy link
Collaborator

zerob13 commented Aug 21, 2025

This PR does not appear to be closely related to this project, and neither the commits nor the code style meet the requirements for merging. Therefore, it will be closed.

@zerob13 zerob13 closed this Aug 21, 2025
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