Skip to content

Conversation

@zerob13
Copy link
Collaborator

@zerob13 zerob13 commented Oct 29, 2025

#568

Summary

  • declare MCP sampling capability during client handshake and handle sampling/createMessage requests
  • surface sampling approvals in the renderer with a dedicated dialog and store
  • add shared sampling types and plumbing for communicating decisions back to MCP servers

Testing

  • pnpm run typecheck

https://chatgpt.com/codex/tasks/task_e_6901ac4d0a44832c976956eba57927d2

Summary by CodeRabbit

  • New Features

    • MCP sampling dialog for reviewing requests, selecting model/provider, and approve/reject flow.
    • Asynchronous sampling workflow with request/decision/cancel events between renderer and main.
  • Improvements

    • End-to-end sampling in message creation with timeout, cancellation, model resolution, and image handling.
    • Model chooser respects vision requirements via new prop.
    • Public sampling types and presenter APIs added.
  • Tests

    • Coverage for sampling payloads, image validation, approval and rejection paths.
  • Chores

    • Added Content-Security-Policy meta tags and extensive localization strings for sampling.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 29, 2025

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds end-to-end MCP sampling: new events and shared types, presenter APIs and pending-request lifecycle, MCP client CreateMessage sampling handler with abort/cancel handling and image sanitization, renderer Pinia store and dialog UI with i18n, tests, ModelChooser prop tweaks, threadPresenter permission metadata, and CSP meta tags across renderer HTML.

Changes

Cohort / File(s) Summary
Event Constants
src/main/events.ts, src/renderer/src/events.ts
Add SAMPLING_REQUEST, SAMPLING_DECISION, SAMPLING_CANCELLED to MCP_EVENTS; minor formatting tweaks.
Shared Sampling Types
src/shared/types/core/mcp.ts, src/shared/types/presenters/legacy.presenters.d.ts
Add sampling types/interfaces and re-exports: McpSamplingMessageType, McpSamplingMessage, McpSamplingModelPreferences, McpSamplingRequestPayload, McpSamplingDecision; extend IMCPPresenter signatures for sampling methods.
Presenter Implementation
src/main/presenter/mcpPresenter/index.ts
Add pendingSamplingRequests map and methods handleSamplingRequest, submitSamplingDecision, cancelSamplingRequest; emit sampling events and manage pending-promise lifecycle.
MCP Client Sampling
src/main/presenter/mcpPresenter/mcpClient.ts
Register sampling CreateMessage handler; implement sampling flow: handleSamplingCreateMessage, prepareSamplingContext, image sanitization/validation, model/server label resolution, normalize model prefs, AbortSignal/timeout/cancel handling, call llmprovider to generate CreateMessageResult; expose sampling capability.
Renderer App Integration
src/renderer/src/App.vue
Mount new <McpSamplingDialog /> component in global template.
Sampling Dialog Component
src/renderer/src/components/mcp/McpSamplingDialog.vue
New Vue SFC dialog rendering system prompt, messages (text/image/audio), model preferences, ModelChooser, and actions (Reject/Approve/Confirm) with i18n labels and loading states.
Sampling Store
src/renderer/src/stores/mcpSampling.ts
New Pinia store useMcpSamplingStore: manages request state, selection flow (provider/model), submit/reject/confirm flows, IPC listeners, vision constraints, lifecycle.
Localization
src/renderer/src/i18n/*/mcp.json
Add sampling localization blocks across locales (en-US, fa-IR, fr-FR, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-HK, zh-TW) covering UI strings, hints, labels, and warnings.
Tests
test/main/presenter/mcpClient.test.ts
Add sampling-related mocks and tests for prepareSamplingContext and handleSamplingCreateMessage (approve/reject flows, MIME/base64 validation).
Thread Presenter Permission Metadata
src/main/presenter/threadPresenter/index.ts
Construct and attach permissionExtra (includes needsUserAction: true and optional legacy fields) to permission/tool_call_permission blocks.
ModelChooser UI/Prop
src/renderer/src/components/ModelChooser.vue
Add requiresVision boolean prop; filter provider models by vision capability when true; remove backdrop styling.
CSP Meta Tags (renderer)
src/renderer/index.html, src/renderer/floating/index.html, src/renderer/settings/index.html, src/renderer/shell/index.html, src/renderer/splash/index.html
Add/enable Content-Security-Policy meta tags across renderer entry HTML files.

Sequence Diagram(s)

sequenceDiagram
    participant S as MCP Server
    participant C as MCP Client
    participant P as Presenter
    participant R as Renderer (Store + UI)

    S->>C: CreateMessageRequest (sampling)
    C->>C: prepareSamplingContext(request)
    C->>P: handleSamplingRequest(payload)
    P->>P: store pending promise (requestId)
    P->>R: emit SAMPLING_REQUEST (IPC)
    R->>R: open dialog & show context
    alt User approves
        R->>P: submitSamplingDecision(approved + provider/model)
    else User rejects
        R->>P: submitSamplingDecision(rejected + reason)
    end
    P->>C: resolve pending decision
    alt Approved
        C->>C: generateCompletion (llmprovider) [with AbortSignal]
        C->>S: return CreateMessageResult
    else Rejected/Cancelled
        C->>S: return error / cancelled response
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Extra attention:
    • src/main/presenter/mcpPresenter/mcpClient.ts — sampling orchestration, AbortSignal/timeout/cancel handling, image sanitization, model/server resolution, error paths.
    • src/main/presenter/mcpPresenter/index.ts — pending request lifecycle, concurrency, event emission and cleanup.
    • Renderer store & dialog (src/renderer/src/stores/mcpSampling.ts, src/renderer/src/components/mcp/McpSamplingDialog.vue) — IPC wiring and UX state transitions.
    • Tests (test/main/presenter/mcpClient.test.ts) — mock wiring and sampling-path coverage.

Possibly related PRs

Poem

🐇 I nudged a sample through the night,

events chimed softly, context in sight,
images and prompts lined up just so,
a choice came back — approve or no,
carrots, code, and a tiny glow.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "feat: support MCP sampling requests" is directly and fully related to the main changes in the changeset. The pull request implements comprehensive MCP sampling request support, including new event constants, sampling workflow handlers in the MCP presenter, a complete sampling request dialog component in the renderer, a new Pinia store for managing sampling state, shared types for sampling payloads and decisions, and corresponding interface extensions. The title accurately captures the primary objective of the PR and clearly conveys the main feature being introduced, using a standard conventional commit format with an appropriate "feat:" prefix. While the changeset also includes supporting changes like localization strings, CSP updates, and model chooser enhancements, these are all subordinate to the core MCP sampling feature that the title appropriately emphasizes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/add-sampling-support-in-mcp-module

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines 196 to 199
const onDialogToggle = (open: boolean) => {
if (!open && !store.isSubmitting) {
store.closeRequest()
}

Choose a reason for hiding this comment

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

P1 Badge Reject sampling request when dialog dismissed

The sampling dialog allows the user to close it (ESC or overlay click) and onDialogToggle simply calls store.closeRequest() without sending any decision back to the main process. handleSamplingRequest in the MCP presenter waits on a promise that is only resolved by submitSamplingDecision or cancelSamplingRequest, so closing the dialog leaves the pending request in pendingSamplingRequests and the MCP server never receives a response until it times out. Consider treating dialog dismissal as an explicit rejection or calling a cancellation method so the server is notified and the pending promise is cleaned up.

Useful? React with 👍 / 👎.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (6)
src/main/presenter/mcpPresenter/index.ts (1)

589-641: Consider adding timeout for pending sampling requests.

The sampling request workflow correctly validates input, manages promise lifecycle, and handles cleanup. However, the pendingSamplingRequests Map has no timeout or size limits, which could lead to memory accumulation if the renderer process crashes or fails to respond.

Consider adding a timeout mechanism to automatically reject and clean up pending requests after a reasonable duration (e.g., 5 minutes):

async handleSamplingRequest(request: McpSamplingRequestPayload): Promise<McpSamplingDecision> {
  if (!request || !request.requestId) {
    throw new Error('Invalid sampling request: missing requestId')
  }

  return new Promise<McpSamplingDecision>((resolve, reject) => {
    try {
      // Set timeout to auto-cancel after 5 minutes
      const timeoutId = setTimeout(() => {
        this.cancelSamplingRequest(
          request.requestId, 
          'Request timed out after 5 minutes'
        ).catch(console.error)
      }, 5 * 60 * 1000)

      this.pendingSamplingRequests.set(request.requestId, { 
        resolve: (decision) => {
          clearTimeout(timeoutId)
          resolve(decision)
        }, 
        reject: (error) => {
          clearTimeout(timeoutId)
          reject(error)
        }
      })
      eventBus.sendToRenderer(MCP_EVENTS.SAMPLING_REQUEST, SendTarget.DEFAULT_TAB, request)
    } catch (error) {
      this.pendingSamplingRequests.delete(request.requestId)
      reject(error instanceof Error ? error : new Error(String(error)))
    }
  })
}
src/renderer/src/stores/mcpSampling.ts (1)

76-89: Consider surfacing submission errors to the user.

Currently, submission errors are only logged to console. Users won't receive feedback if the submission fails, though they can retry since isSubmitting is reset to false.

Consider showing a toast notification on error:

import { useToast } from '@/components/use-toast'

// In store setup:
const { toast } = useToast()

const submitDecision = async (decision: McpSamplingDecision) => {
  if (!request.value) {
    return
  }

  isSubmitting.value = true
  try {
    await mcpPresenter.submitSamplingDecision(decision)
    closeRequest()
  } catch (error) {
    console.error('[MCP Sampling] Failed to submit decision:', error)
    toast({
      title: 'Failed to submit sampling decision',
      description: error instanceof Error ? error.message : 'Unknown error',
      variant: 'destructive'
    })
    isSubmitting.value = false
  }
}
src/renderer/src/components/mcp/McpSamplingDialog.vue (1)

6-10: Consider extracting server name fallback logic.

While functional, the nested ternary in the template interpolation reduces readability. Extract to a computed property for clarity.

const serverDisplayName = computed(() => {
  return store.request?.serverLabel 
    || store.request?.serverName 
    || t('mcp.sampling.unknownServer')
})

Then in template:

{{ t('mcp.sampling.title', { server: serverDisplayName }) }}
src/main/presenter/mcpPresenter/mcpClient.ts (3)

786-869: Sampling flow: good structure; add top-level try/catch and refine abort error code

  • Flow is correct: build payload, await decision, guard with AbortSignal, call provider, return CreateMessageResult.
  • Add a top-level try/catch to normalize unexpected errors into McpError(ErrorCode.InternalError) and include requestId in the log for diagnostics.
  • On abort, if the SDK has a RequestCancelled code, prefer it over RequestTimeout for clarity; otherwise keep as-is.
   private async handleSamplingCreateMessage(
     request: CreateMessageRequest,
     extra: RequestHandlerContext
   ): Promise<CreateMessageResult> {
-    const params = request.params ?? {}
-    const requestId = this.resolveSamplingRequestId(extra)
-    const { payload, chatMessages } = this.prepareSamplingContext(requestId, params)
+    try {
+      const params = request.params ?? {}
+      const requestId = this.resolveSamplingRequestId(extra)
+      const { payload, chatMessages } = this.prepareSamplingContext(requestId, params)
@@
-    return result
+      return result
+    } catch (err) {
+      console.error(`[MCP] Sampling handler failed (${this.serverName}):`, err)
+      if (err instanceof McpError) throw err
+      throw new McpError(ErrorCode.InternalError, (err as Error)?.message ?? 'Unknown error')
+    }
   }

880-954: Content parsing and modelPreferences normalization — add validation and clamping

  • Content parsing looks robust. Optional: filter empty text parts to reduce no-op tokens.
  • Normalize model preference weights by clamping to [0,1] (or your accepted range) to avoid pathological inputs.
   private normalizeModelPreferences(
     preferences: any
   ): McpSamplingRequestPayload['modelPreferences'] {
@@
-    if (typeof preferences.costPriority === 'number') {
-      normalized.costPriority = preferences.costPriority
-    }
-    if (typeof preferences.speedPriority === 'number') {
-      normalized.speedPriority = preferences.speedPriority
-    }
-    if (typeof preferences.intelligencePriority === 'number') {
-      normalized.intelligencePriority = preferences.intelligencePriority
-    }
+    const clamp = (n: number) => Math.max(0, Math.min(1, n))
+    if (typeof preferences.costPriority === 'number') {
+      normalized.costPriority = clamp(preferences.costPriority)
+    }
+    if (typeof preferences.speedPriority === 'number') {
+      normalized.speedPriority = clamp(preferences.speedPriority)
+    }
+    if (typeof preferences.intelligencePriority === 'number') {
+      normalized.intelligencePriority = clamp(preferences.intelligencePriority)
+    }
@@
-      normalized.hints = preferences.hints.map((hint: { name?: unknown }) => ({
+      normalized.hints = preferences.hints.map((hint: { name?: unknown }) => ({
         name: typeof hint?.name === 'string' ? hint.name : undefined
       }))

Also applies to: 956-991


992-1005: Minor: friendlier label fallback and structured logs

  • getServerLabel could fall back to this.serverName if no label is present to keep UI strings non-empty.
  • Prefer a structured logger over console.* to meet the logging guidelines (timestamp, level, context like requestId/serverName).
   private getServerLabel(): string | undefined {
@@
-    return candidates.find((label) => label && label.trim().length > 0)
+    return candidates.find((label) => label && label.trim().length > 0) ?? this.serverName
   }

Also applies to: 1007-1028

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e425fc1 and a83d9cb.

📒 Files selected for processing (10)
  • src/main/events.ts (1 hunks)
  • src/main/presenter/mcpPresenter/index.ts (3 hunks)
  • src/main/presenter/mcpPresenter/mcpClient.ts (5 hunks)
  • src/renderer/src/App.vue (2 hunks)
  • src/renderer/src/components/mcp/McpSamplingDialog.vue (1 hunks)
  • src/renderer/src/events.ts (1 hunks)
  • src/renderer/src/i18n/en-US/mcp.json (1 hunks)
  • src/renderer/src/stores/mcpSampling.ts (1 hunks)
  • src/shared/types/core/mcp.ts (1 hunks)
  • src/shared/types/presenters/legacy.presenters.d.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (28)
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • src/shared/types/core/mcp.ts
  • src/renderer/src/stores/mcpSampling.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

  • src/shared/types/core/mcp.ts
  • src/renderer/src/stores/mcpSampling.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
src/shared/**/*.{ts,tsx,d.ts}

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

共享类型定义放在 shared 目录

Files:

  • src/shared/types/core/mcp.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/shared/types/core/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/shared/types/core/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
src/shared/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Place shared types, utilities, constants, and IPC contract definitions under src/shared/

Files:

  • src/shared/types/core/mcp.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
src/shared/**

📄 CodeRabbit inference engine (AGENTS.md)

Put shared TypeScript types and utilities under src/shared

Files:

  • src/shared/types/core/mcp.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/shared/types/core/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
  • src/renderer/src/i18n/en-US/mcp.json
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/shared/types/core/mcp.ts
  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.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/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
  • src/renderer/src/i18n/en-US/mcp.json
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

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

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

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.vue

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

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,tsx,vue}

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

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

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{vue,ts}

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

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/{src,shell,floating}/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
  • src/renderer/src/i18n/en-US/mcp.json
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue component files in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/App.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
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/mcpSampling.ts
  • src/renderer/src/events.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.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/mcpSampling.ts
src/main/**/*.ts

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

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

Files:

  • src/main/presenter/mcpPresenter/index.ts
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
src/main/**/*.{ts,js,tsx,jsx}

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

主进程代码放在 src/main

Files:

  • src/main/presenter/mcpPresenter/index.ts
  • src/main/events.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
src/main/presenter/mcpPresenter/index.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Register new MCP tools in src/main/presenter/mcpPresenter/index.ts

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)

Files:

  • src/main/presenter/mcpPresenter/index.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/i18n/**/*.{ts,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Store i18n resources under src/renderer/src/i18n

Files:

  • src/renderer/src/i18n/en-US/mcp.json
🧠 Learnings (2)
📚 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/mcpSampling.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts

Applied to files:

  • src/shared/types/presenters/legacy.presenters.d.ts
  • src/main/presenter/mcpPresenter/index.ts
🧬 Code graph analysis (5)
src/shared/types/core/mcp.ts (1)
src/shared/types/presenters/legacy.presenters.d.ts (4)
  • McpSamplingMessage (1209-1209)
  • McpSamplingModelPreferences (1212-1212)
  • McpSamplingRequestPayload (1210-1210)
  • McpSamplingDecision (1211-1211)
src/renderer/src/stores/mcpSampling.ts (7)
src/renderer/src/composables/usePresenter.ts (1)
  • usePresenter (103-105)
src/renderer/src/stores/chat.ts (1)
  • useChatStore (24-1379)
src/renderer/src/stores/settings.ts (1)
  • useSettingsStore (19-1993)
src/shared/types/core/mcp.ts (2)
  • McpSamplingRequestPayload (99-108)
  • McpSamplingDecision (110-116)
src/shared/types/presenters/legacy.presenters.d.ts (3)
  • McpSamplingRequestPayload (1210-1210)
  • RENDERER_MODEL_META (551-565)
  • McpSamplingDecision (1211-1211)
src/main/presenter/mcpPresenter/index.ts (1)
  • handleSamplingRequest (589-603)
src/renderer/src/events.ts (1)
  • MCP_EVENTS (68-77)
src/shared/types/presenters/legacy.presenters.d.ts (1)
src/shared/types/core/mcp.ts (4)
  • McpSamplingMessage (75-90)
  • McpSamplingRequestPayload (99-108)
  • McpSamplingDecision (110-116)
  • McpSamplingModelPreferences (92-97)
src/main/presenter/mcpPresenter/index.ts (3)
src/shared/types/core/mcp.ts (2)
  • McpSamplingDecision (110-116)
  • McpSamplingRequestPayload (99-108)
src/main/eventbus.ts (1)
  • eventBus (151-151)
src/main/events.ts (1)
  • MCP_EVENTS (107-118)
src/main/presenter/mcpPresenter/mcpClient.ts (3)
src/main/presenter/index.ts (1)
  • presenter (223-223)
src/shared/types/core/mcp.ts (2)
  • McpSamplingDecision (110-116)
  • McpSamplingRequestPayload (99-108)
src/shared/types/presenters/legacy.presenters.d.ts (3)
  • McpSamplingDecision (1211-1211)
  • McpSamplingRequestPayload (1210-1210)
  • ChatMessage (1384-1384)
🪛 GitHub Actions: PR Check
src/renderer/src/components/mcp/McpSamplingDialog.vue

[error] 1-1: Prettier formatting check failed in 'pnpm run format:check'. Run 'prettier --write' to fix code style issues.

🔇 Additional comments (16)
src/main/events.ts (1)

114-117: LGTM! Event constants follow naming conventions.

The new MCP sampling event constants are well-formed and consistent with the existing event naming pattern (lowercase, kebab-case, domain-prefixed).

src/renderer/src/App.vue (2)

21-21: LGTM! Component import follows conventions.

The import statement for McpSamplingDialog is correctly placed and follows the existing pattern for global dialog components.


342-342: LGTM! Dialog integration is appropriate.

The McpSamplingDialog is correctly positioned alongside other global dialogs and will manage its own state via the Pinia store, consistent with the existing dialog pattern.

src/renderer/src/i18n/en-US/mcp.json (1)

139-167: LGTM! Comprehensive i18n coverage for sampling workflow.

The new localization keys are well-organized, use appropriate interpolation placeholders, and provide clear, user-friendly strings for all sampling UI elements. The hierarchical structure (contentType, preference) aids maintainability.

src/renderer/src/events.ts (1)

73-76: LGTM! Renderer events mirror main process correctly.

The sampling event constants are correctly defined and consistent with the main process event names, enabling proper IPC communication for the sampling workflow.

src/shared/types/core/mcp.ts (1)

73-116: LGTM! Well-designed type definitions for sampling workflow.

The new sampling types are comprehensive and type-safe:

  • Clear separation of message types (text, image, audio)
  • Appropriate use of optional fields for flexible content representation
  • JSDoc comments clarify the purpose of key fields
  • Request/decision correlation via requestId enables proper async flow tracking
src/main/presenter/mcpPresenter/index.ts (2)

11-13: LGTM! Imports are correct.

The sampling type imports are properly added from the shared presenter module.


90-93: LGTM! Pending request tracking is appropriate.

The Map structure for tracking in-flight sampling requests with their resolve/reject handlers enables the async request/response pattern.

src/renderer/src/stores/mcpSampling.ts (3)

1-23: LGTM! Store setup and state management follows Pinia conventions.

The store structure is clean with appropriate reactive state refs and computed properties. Dependencies on chat and settings stores enable proper model selection defaults.

Based on learnings


28-48: LGTM! Model selection logic handles edge cases gracefully.

The resetSelection function appropriately:

  • Falls back when provider is not found
  • Prefers the active model from chat config
  • Falls back to the first available model
  • Handles undefined/null cases safely

116-145: LGTM! IPC event handling is robust.

The event handlers properly:

  • Validate requestId matches before acting on cancellation/decision events
  • Register and clean up listeners appropriately in lifecycle hooks
  • Follow defensive programming practices
src/renderer/src/components/mcp/McpSamplingDialog.vue (3)

27-64: LGTM! Message rendering and preferences display are well-implemented.

The component appropriately:

  • Renders different message types (text, image, audio/unsupported) with appropriate fallbacks
  • Uses ScrollArea for long message lists
  • Conditionally displays system prompt and model preferences
  • Shows vision capability warnings
  • Handles missing/undefined data gracefully

Also applies to: 66-94


97-120: LGTM! Dialog actions handle the approval flow correctly.

The button states and transitions properly manage:

  • Three-state flow: initial → model selection → submission
  • Disable states during submission
  • Loading indicator during async operations
  • Conditional rendering of Approve vs Confirm buttons

146-182: LGTM! Preferences summary logic is clean and localized.

The computed property correctly:

  • Handles undefined preferences gracefully
  • Formats numeric priorities with appropriate precision
  • Joins hint names with fallback for unnamed hints
  • Uses i18n keys throughout
src/shared/types/presenters/legacy.presenters.d.ts (2)

1209-1213: Re-exported sampling types — import paths verified

The relative paths are correct and consistent. The imports at lines 1209-1213 correctly use ../../core/mcp to resolve from src/shared/types/presenters/legacy.presenters.d.ts to src/shared/types/core/mcp.ts. This matches the existing ../../core/llm-events import pattern used elsewhere in the same file, confirming proper path resolution.


1263-1266: Implementation verified and concurrency pattern confirmed ✓

All three methods are correctly implemented in src/main/presenter/mcpPresenter/index.ts:

  • Concurrent requests are keyed by requestId in a pendingSamplingRequests Map—no cross-talk
  • Each request stores its own resolve/reject functions isolated by key
  • Cancellations properly reject pending promises; submissions properly resolve them
  • All edge cases (missing requestId, missing pending request) are handled gracefully

Comment on lines +11 to +16
LoggingMessageNotificationSchema,
CreateMessageRequestSchema,
ErrorCode,
McpError
} from '@modelcontextprotocol/sdk/types.js'
import type { CreateMessageRequest, CreateMessageResult } from '@modelcontextprotocol/sdk/types.js'
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 | 🔴 Critical

🧩 Analysis chain

Sampling capability and handler registration — solid; verify SDK symbols and keep comments in English

  • Enabling capabilities.sampling and wiring CreateMessageRequest handler is correct.
  • Type-only imports for CreateMessageRequest/Result are good.
  • Minor: the new inline comment at Line 615 is Chinese; guidelines require English logs/comments. Consider “Register sampling request handler”.

Also applies to: 32-36, 606-608, 615-619


🏁 Script executed:

#!/bin/bash
# Ensure the SDK exports these symbols in your installed version
pnpm ls @modelcontextprotocol/sdk
rg -n 'CreateMessageRequestSchema|McpError|ErrorCode' node_modules/@modelcontextprotocol/sdk --no-messages || true

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Locate the mcpClient.ts file
echo "=== Locating mcpClient.ts ==="
fd -t f 'mcpClient\.ts' || echo "File not found"

# Check repository structure
echo -e "\n=== Repository structure ==="
ls -la src/main/presenter/mcpPresenter/ 2>/dev/null || echo "Directory not accessible"

# Check if package.json exists and contains SDK info
echo -e "\n=== Package.json SDK reference ==="
grep -i '@modelcontextprotocol/sdk' package.json 2>/dev/null || echo "SDK not found in package.json"

Length of output: 697


🏁 Script executed:

#!/bin/bash
# If file found, inspect the imports and comments around specified lines
if [ -f src/main/presenter/mcpPresenter/mcpClient.ts ]; then
  echo "=== Lines 11-16 (imports) ==="
  sed -n '11,16p' src/main/presenter/mcpPresenter/mcpClient.ts
  
  echo -e "\n=== Lines 32-36 ==="
  sed -n '32,36p' src/main/presenter/mcpPresenter/mcpClient.ts
  
  echo -e "\n=== Lines 606-619 (sampling handler registration and comment) ==="
  sed -n '606,619p' src/main/presenter/mcpPresenter/mcpClient.ts
  
  echo -e "\n=== Check for non-ASCII/Chinese characters in lines 615-619 ==="
  sed -n '615,619p' src/main/presenter/mcpPresenter/mcpClient.ts | od -c | head -20
fi

Length of output: 889


🏁 Script executed:

#!/bin/bash
# Verify Chinese characters using file inspection without od
echo "=== Lines 614-616 raw content ==="
sed -n '614,616p' src/main/presenter/mcpPresenter/mcpClient.ts | cat -A

echo -e "\n=== Confirm Chinese with grep ==="
grep -n '设置\|注册\|采样' src/main/presenter/mcpPresenter/mcpClient.ts | head -5

Length of output: 234


Convert Chinese comments to English

The sampling capability and handler registration are solid, and SDK symbols are correctly imported. However, two Chinese comments violate the guideline requiring English for all logs and comments:

  • Line 614: Change // 设置通知处理器 to // Register notification handlers
  • Line 616: Change // 注册采样请求处理器 to // Register sampling request handler
🤖 Prompt for AI Agents
In src/main/presenter/mcpPresenter/mcpClient.ts around lines 614 to 616, replace
the Chinese comments with English equivalents: change "// 设置通知处理器" to "//
Register notification handlers" and change "// 注册采样请求处理器" to "// Register
sampling request handler"; ensure the replacements are exact and preserve
surrounding whitespace and indentation.

Comment on lines 184 to 186
const onModelUpdate = (model, providerId: string) => {
store.selectModel(model, providerId)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add explicit type annotation for model parameter.

The model parameter lacks a type annotation, which reduces type safety. Specify RENDERER_MODEL_META to match the expected type.

-const onModelUpdate = (model, providerId: string) => {
+const onModelUpdate = (model: RENDERER_MODEL_META, providerId: string) => {
   store.selectModel(model, providerId)
 }

As per coding guidelines

📝 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 onModelUpdate = (model, providerId: string) => {
store.selectModel(model, providerId)
}
const onModelUpdate = (model: RENDERER_MODEL_META, providerId: string) => {
store.selectModel(model, providerId)
}
🤖 Prompt for AI Agents
In src/renderer/src/components/mcp/McpSamplingDialog.vue around lines 184 to
186, the onModelUpdate function's model parameter is missing an explicit type;
change the function signature to annotate model as RENDERER_MODEL_META (e.g.
onModelUpdate = (model: RENDERER_MODEL_META, providerId: string) => { ... }),
ensure RENDERER_MODEL_META is imported or available in the file, and run
typecheck to fix any resulting type errors.

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

🧹 Nitpick comments (1)
test/main/presenter/mcpClient.test.ts (1)

424-566: Consider adding tests for additional error paths.

The current test suite covers the basic happy path and user rejection, but several error scenarios from the implementation remain untested:

  1. Abort/cancellation flow: When extra.signal (AbortSignal) is provided and triggers cancellation
  2. Missing model validation: When decision lacks providerId or modelId (should throw ErrorCode.InvalidParams)
  3. Unsupported content types: Audio content (should throw ErrorCode.InvalidParams with message about audio not supported) and other unsupported types
  4. Generation failure: When generateCompletionStandalone fails (should throw ErrorCode.InternalError)

Adding tests for these paths would improve coverage and confidence in error handling.

Would you like me to generate test cases for these additional error scenarios?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a83d9cb and 2a52729.

📒 Files selected for processing (1)
  • test/main/presenter/mcpClient.test.ts (4 hunks)
🧰 Additional context used
📓 Path-based instructions (9)
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • test/main/presenter/mcpClient.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

  • test/main/presenter/mcpClient.test.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • test/main/presenter/mcpClient.test.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • test/main/presenter/mcpClient.test.ts
test/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Place unit and integration tests under the test/ directory mirroring project structure

Files:

  • test/main/presenter/mcpClient.test.ts
test/{main,renderer}/**/*

📄 CodeRabbit inference engine (AGENTS.md)

Mirror source structure for tests under test/main/** and test/renderer/**

Files:

  • test/main/presenter/mcpClient.test.ts
test/{main,renderer}/**/*.{test,spec}.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name test files with .test.ts or .spec.ts

Files:

  • test/main/presenter/mcpClient.test.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • test/main/presenter/mcpClient.test.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • test/main/presenter/mcpClient.test.ts
🔇 Additional comments (6)
test/main/presenter/mcpClient.test.ts (6)

5-5: LGTM!

The ErrorCode import is correctly added to support error assertions in the new sampling tests.


37-66: LGTM!

The hoisted mock structure correctly ensures mocks are available before module imports, properly wires them into the presenter hierarchy, and provides convenient references for test assertions.


117-121: LGTM!

Properly resets all new mocks in beforeEach to ensure test isolation.


425-484: LGTM!

This test thoroughly validates the payload construction and chatMessages transformation, including edge cases like null hint values and multiple content types (text and image). The assertions comprehensively verify both the payload structure and the chat message format.


486-537: LGTM!

The test comprehensively validates the approval flow, verifying that all expected presenter methods are called with correct arguments and that the final result structure matches the expected CreateMessageResult format.


539-565: LGTM!

The test correctly validates the rejection path, verifying the error code, message, and that downstream generation is not invoked.

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

🧹 Nitpick comments (1)
src/renderer/src/components/ModelChooser.vue (1)

2-2: CSS simplification looks good.

The Card wrapper classes have been streamlined by removing backdrop blur, low-contrast borders, and responsive backdrop variants. The new class set (w-full border-border bg-card shadow-sm) is clean, uses design system tokens, and maintains the necessary styling.

Consider verifying the visual appearance in the MCP sampling dialog to ensure the simplified styling meets design expectations.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2a52729 and d3df627.

📒 Files selected for processing (3)
  • src/main/presenter/threadPresenter/index.ts (3 hunks)
  • src/renderer/src/components/ModelChooser.vue (1 hunks)
  • src/renderer/src/components/mcp/McpSamplingDialog.vue (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
🧰 Additional context used
📓 Path-based instructions (22)
src/renderer/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)

src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

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

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

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/src/**/*.vue

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

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/**/*.{ts,tsx,vue}

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

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

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/**/*.{vue,ts}

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

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/components/ModelChooser.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/main/presenter/threadPresenter/index.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/main/presenter/threadPresenter/index.ts
src/renderer/{src,shell,floating}/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/components/ModelChooser.vue
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/components/ModelChooser.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/main/presenter/threadPresenter/index.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/main/presenter/threadPresenter/index.ts
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue component files in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/components/ModelChooser.vue
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • src/main/presenter/threadPresenter/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/main/presenter/threadPresenter/index.ts
src/main/**/*.ts

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

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

Files:

  • src/main/presenter/threadPresenter/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

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

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

主进程代码放在 src/main

Files:

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

📄 CodeRabbit inference engine (AGENTS.md)

Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)

Files:

  • src/main/presenter/threadPresenter/index.ts
🧠 Learnings (1)
📚 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/components/ModelChooser.vue
🔇 Additional comments (5)
src/main/presenter/threadPresenter/index.ts (5)

392-414: Strongly type permissionExtra and avoid JSON‑stringifying permission_request

Use a concrete type for extra to keep renderer/main in sync and store permission_request as an object (not a JSON string) to preserve structure and reduce parsing/mismatch risks. Also consider redacting any sensitive fields before persisting.
[ suggest_recommended_refactor ][ raise_minor_issue ]

Apply within this hunk:

-        const permissionExtra: Record<string, string | boolean> = {
-          needsUserAction: true
-        }
+        const permissionExtra: ToolCallPermissionExtra = {
+          needsUserAction: true
+        }

-        if (permission_request) {
-          permissionExtra.permissionRequest = JSON.stringify(permission_request)
+        if (permission_request) {
+          permissionExtra.permissionRequest = permission_request
           if (permission_request.toolName) {
             permissionExtra.toolName = permission_request.toolName
           }
           if (permission_request.serverName) {
             permissionExtra.serverName = permission_request.serverName
           }
         }

Add (near imports or in a shared types module used by both main/renderer):

type PermissionType = 'read' | 'write' | 'all'

interface ToolCallPermissionExtra {
  needsUserAction: boolean
  permissionType?: PermissionType
  permissionRequest?: unknown // replace with a precise MCP permission request type if available
  toolName?: string
  serverName?: string
  grantedPermissions?: PermissionType
}

Also applies to: 416-431


433-435: Don’t reuse “search” flags for permission gating

Using searchingMessages/isSearching for permission flow can trigger unintended behavior (e.g., stopMessageGeneration calling searchManager.stopSearch). Prefer a dedicated flag like isAwaitingPermission (and a corresponding Set if needed).
[ suggest_recommended_refactor ]


282-283: Logs/comments should be English per guidelines

Several logs are in Chinese; please standardize to English to comply with repo guidelines.
[ suggest_recommended_refactor ]
Example edits:

- console.error('解析搜索结果失败:', e)
+ console.error('Failed to parse search result:', e)

- console.error('处理搜索结果时出错:', error)
+ console.error('Error processing search results:', error)

- console.error('设置搜索引擎失败:', error)
+ console.error('Failed to set search engine:', error)

As per coding guidelines

Also applies to: 338-339, 846-848


2786-2793: Type support is already correct—no action needed

The AssistantMessageBlock type already includes 'granted' and 'denied' in its status field union. The assignment permissionBlock.status = granted ? 'granted' : 'denied' is fully type-safe and will not cause strict typing errors.

Likely an incorrect or invalid review comment.


174-193: Translation required: Chinese comments violate guideline; refactor permissionExtra typing

Lines 2974 & 2977 contain Chinese comments that must be translated to English per coding guidelines. Additionally, avoid JSON-stringifying the permission_request object (line 400)—pass it directly in the extra field. Define a dedicated TypeScript type for permissionExtra instead of using Record<string, string | boolean>.

Likely an incorrect or invalid review comment.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (2)
src/renderer/src/components/mcp/McpSamplingDialog.vue (2)

199-201: Add type annotation for model parameter.

The model parameter lacks an explicit type annotation, violating the strict TypeScript typing guideline. Based on the context and past review, this should be typed as RENDERER_MODEL_META.

As per coding guidelines

Apply this diff:

-const onModelUpdate = (model, providerId: string) => {
+const onModelUpdate = (model: RENDERER_MODEL_META, providerId: string) => {
   store.selectModel(model, providerId)
 }

Ensure RENDERER_MODEL_META is imported from the appropriate location (likely from shared types or model-related type definitions).


211-215: Dialog dismissal does not notify the MCP server.

When the user dismisses the dialog (via ESC or clicking the overlay), onDialogToggle receives open = false and calls store.closeRequest(). According to the past review and the MCP sampling workflow, this does not send a rejection or cancellation back to the main process, leaving the MCP server waiting until timeout. The pending promise in handleSamplingRequest remains unresolved, and resources are not cleaned up properly.

Consider one of these approaches:

Option 1: Treat dismissal as rejection

 const onDialogToggle = (open: boolean) => {
   if (!open && !store.isSubmitting) {
-    store.closeRequest()
+    void store.rejectRequest()
   }
 }

Option 2: Add explicit cancel method

 const onDialogToggle = (open: boolean) => {
   if (!open && !store.isSubmitting) {
-    store.closeRequest()
+    void store.cancelRequest()
   }
 }

Verify that the chosen approach properly notifies the MCP server and cleans up the pending request state.

🧹 Nitpick comments (1)
src/renderer/src/components/mcp/McpSamplingDialog.vue (1)

164-164: Optional: Redundant type annotation.

The explicit type annotation as Array<{ key: string; label: string; value: string }> is redundant since TypeScript can infer the return type from the function signature and the array type from the entries variable below.

Consider simplifying to:

-    return [] as Array<{ key: string; label: string; value: string }>
+    return []
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d3df627 and 599bc5f.

📒 Files selected for processing (1)
  • src/renderer/src/components/mcp/McpSamplingDialog.vue (1 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
src/renderer/src/**/*

📄 CodeRabbit inference engine (.cursor/rules/i18n.mdc)

src/renderer/src/**/*: All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Use the 'vue-i18n' framework for all internationalization in the renderer
Ensure all user-visible text in the renderer uses the translation system

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

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

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

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.vue

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

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,tsx,vue}

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

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

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{vue,ts}

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

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/{src,shell,floating}/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue component files in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
🪛 GitHub Actions: PR Check
src/renderer/src/components/mcp/McpSamplingDialog.vue

[error] 1-1: Prettier formatting check failed. Run 'prettier --write' to fix code style issues in this file.

🔇 Additional comments (1)
src/renderer/src/components/mcp/McpSamplingDialog.vue (1)

161-197: LGTM: Well-structured preference summary.

The computed property correctly handles all edge cases with proper null checks and fallbacks. The formatting and i18n usage are appropriate.

Comment on lines +55 to +60
<img
v-if="message.dataUrl"
:src="message.dataUrl"
class="max-h-40 rounded-md border object-contain"
:alt="t('mcp.sampling.imageAlt', { index: index + 1 })"
/>
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 | 🔴 Critical

🧩 Analysis chain

Verify dataUrl validation in the main process.

The image source uses message.dataUrl directly. If data URLs are not validated or sanitized before reaching the renderer, this could potentially introduce security risks. Ensure the main process validates and sanitizes data URLs from MCP servers before passing them to the renderer.

Run the following script to check how dataUrl is handled in the MCP client and presenter:


🏁 Script executed:

#!/bin/bash
# Search for dataUrl handling and validation in MCP-related code
rg -n -C3 --type=ts 'dataUrl' -g '!node_modules' -g '!dist' -g '!*.vue'

Length of output: 5415



---

🏁 Script executed:

```shell
#!/bin/bash
# Check for CSP configuration in preload, main process, and BrowserWindow setup
rg -n -C2 --type=ts 'Content-Security-Policy|CSP|contentSecurityPolicy' -g '!node_modules' -g '!dist'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Check for BrowserWindow preload and webPreferences security settings
rg -n -C3 --type=ts 'webPreferences|preload|sandbox' -g '!node_modules' -g '!dist' | head -100

Length of output: 6975


🏁 Script executed:

#!/bin/bash
# Check if there's any mimeType validation/whitelist logic
rg -n -C2 --type=ts 'mimeType.*==' -g '!node_modules' -g '!dist'

Length of output: 1498


🏁 Script executed:

#!/bin/bash
# Check MCP server connection initialization and validation
rg -n -C3 --type=ts 'class.*McpClient|new.*McpClient' -g '!node_modules' -g '!dist'

Length of output: 12707



---

🏁 Script executed:

```shell
#!/bin/bash
# Check for DOMPurify or other sanitization library usage
rg -n --type=ts --type=vue 'DOMPurify|sanitize|escapeHtml' -g '!node_modules' -g '!dist'

Length of output: 27


🏁 Script executed:

#!/bin/bash
# Check the McpSamplingDialog component to see if dataUrl is sanitized
cat src/renderer/src/components/mcp/McpSamplingDialog.vue | head -100

Length of output: 4292


🏁 Script executed:

#!/bin/bash
# Check if there's any validation of MCP server responses or trust model
rg -n -C3 --type=ts 'MCP.*server.*trust|validate.*mcp|mcp.*security' -g '!node_modules' -g '!dist'

Length of output: 0


🏁 Script executed:

#!/bin/bash
# Search for any v-html or innerHTML usage that might sanitize dataUrl
rg -n --type=vue 'v-html|innerHTML' -g '!node_modules' -g '!dist'

Length of output: 27


Add MIME type validation and whitelist for MCP server image responses.

The dataUrl is constructed using untrusted mimeType from the MCP server without any validation. While img src is relatively safer than innerHTML, this creates a security risk if the mimeType is manipulated or if the dataUrl is reused in other contexts.

Update line 920 in src/main/presenter/mcpPresenter/mcpClient.ts:

  • Add a whitelist of allowed MIME types (e.g., image/jpeg, image/png, image/gif, image/webp)
  • Validate the mimeType against the whitelist, defaulting to image/png only if the type is missing—not for invalid types
  • Consider adding base64 format validation for the data field

Example fix:

const ALLOWED_IMAGE_TYPES = new Set(['image/jpeg', 'image/png', 'image/gif', 'image/webp'])
const mimeType = ALLOWED_IMAGE_TYPES.has(content.mimeType) ? content.mimeType : 'image/png'

Additionally, configure Content-Security-Policy in the renderer to restrict data URL usage and prevent potential XSS escalation if the protection is bypassed.

🤖 Prompt for AI Agents
In src/renderer/src/components/mcp/McpSamplingDialog.vue around lines 55-60, the
img tag uses a dataUrl built from an untrusted mimeType; fix this by updating
src/main/presenter/mcpPresenter/mcpClient.ts (around line 920) to enforce a
strict whitelist of allowed image MIME types (e.g., image/jpeg, image/png,
image/gif, image/webp), validate the incoming content.mimeType against that
whitelist and only default to image/png when mimeType is missing (do NOT
silently accept or fallback for invalid types), and add validation to ensure the
data payload is valid base64 image data before constructing the data: URL;
additionally update the renderer Content-Security-Policy to restrict data: URL
usage for images to mitigate XSS escalation.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/renderer/src/components/ModelChooser.vue (1)

33-37: Rename ModelIcon's modelId prop to providerId for semantic clarity, or fix callers passing model.id.

The prop is correctly identified as problematic. ModelIcon's modelId prop actually stores and looks up provider IDs (line 159 of ModelIcon.vue: settingsStore.providers.find((item) => item.id === props.modelId)), not model IDs. The name is misleading.

Usage audit found:

  • Correct: 8 callsites pass provider IDs (ModelProviderSettings, ModelSelect, ModelChooser, NewThread, ChatInput, WelcomeView, MessageNavigationSidebar, MessageItemAssistant)
  • Incorrect: 3 callsites pass model.id instead of provider.id (BuiltinKnowledgeSettings lines 187/227, SearchAssistantModelSection line 16, mcpServerForm line 884)

Recommendation: Either rename the prop to providerId and update all 11 usages for clarity, or fix the 3 callers passing model IDs to pass the correct provider ID instead.

♻️ Duplicate comments (2)
src/renderer/src/components/mcp/McpSamplingDialog.vue (2)

221-224: Critical: dismissing the dialog should reject/cancel the sampling request, not just close UI.

Currently calls store.closeRequest(); the MCP presenter promise remains unresolved, leaving the server hanging until timeout. Call a dismissal that notifies the main process.

If you adopt the store.dismiss() helper:

-const onDialogToggle = (open: boolean) => {
-  if (!open && !store.isSubmitting) {
-    store.closeRequest()
-  }
-}
+const onDialogToggle = (open: boolean) => {
+  if (!open && !store.isSubmitting) {
+    void store.dismiss()
+  }
+}

Temporary minimal alternative (without new helper):

-    store.closeRequest()
+    void store.rejectRequest()
#!/bin/bash
# Ensure onDialogToggle is the only place closing the dialog so dismissal is consistently notified
rg -n -C2 --type=vue '@update:open="onDialogToggle"|closeRequest\(\)|rejectRequest\(\)' src/renderer/src/components | sed -n '1,200p'

209-211: Add explicit type for model parameter.

Annotate model as RENDERER_MODEL_META to keep strict typing.

-const onModelUpdate = (model, providerId: string) => {
+const onModelUpdate = (model: RENDERER_MODEL_META, providerId: string) => {
   store.selectModel(model, providerId)
 }
🧹 Nitpick comments (3)
src/renderer/src/components/ModelChooser.vue (1)

133-144: Optional: avoid repeated toLowerCase calls in filter.

Precompute the lowercase search term once for a small perf/readability win.

 const filteredProviders = computed(() => {
-  if (!keyword.value) return providers.value
-
-  return providers.value
+  if (!keyword.value) return providers.value
+  const q = keyword.value.toLowerCase()
+  return providers.value
     .map((provider) => ({
       ...provider,
       models: provider.models.filter((model) =>
-        model.name.toLowerCase().includes(keyword.value.toLowerCase())
+        model.name.toLowerCase().includes(q)
       )
     }))
     .filter((provider) => provider.models.length > 0)
 })
src/renderer/src/stores/mcpSampling.ts (2)

150-158: Use structured logging per guidelines; avoid bare console.error.

Replace console.error with a centralized logger (levelled, timestamped, structured context).

-    } catch (error) {
-      console.error('[MCP Sampling] Failed to submit decision:', error)
+    } catch (error) {
+      logger.error({
+        msg: 'MCP sampling decision submission failed',
+        module: 'mcpSamplingStore',
+        err: error instanceof Error ? { message: error.message, stack: error.stack } : { message: String(error) },
+        context: { requestId: decision.requestId }
+      })
       isSubmitting.value = false
     }

If no logger exists, I can add a minimal wrapper (INFO/WARN/ERROR) under src/renderer/src/lib/logger.ts. Based on learnings.


145-149: Surface a warning when called without an active request.

Silent return makes debugging harder.

-  const submitDecision = async (decision: McpSamplingDecision) => {
-    if (!request.value) {
-      return
-    }
+  const submitDecision = async (decision: McpSamplingDecision) => {
+    if (!request.value) {
+      console.warn('[MCP Sampling] Ignored decision without active request', { decision })
+      return
+    }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 599bc5f and b6d8ef2.

📒 Files selected for processing (4)
  • src/renderer/src/components/ModelChooser.vue (3 hunks)
  • src/renderer/src/components/mcp/McpSamplingDialog.vue (1 hunks)
  • src/renderer/src/i18n/en-US/mcp.json (1 hunks)
  • src/renderer/src/stores/mcpSampling.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/i18n/en-US/mcp.json
🧰 Additional context used
📓 Path-based instructions (20)
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
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/mcpSampling.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,tsx,vue}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{vue,ts}

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

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.vue

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

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/{src,shell,floating}/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue component files in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/components/ModelChooser.vue
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
🧠 Learnings (1)
📚 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/mcpSampling.ts
🧬 Code graph analysis (1)
src/renderer/src/stores/mcpSampling.ts (5)
src/renderer/src/composables/usePresenter.ts (1)
  • usePresenter (103-105)
src/shared/types/core/mcp.ts (2)
  • McpSamplingRequestPayload (99-108)
  • McpSamplingDecision (110-116)
src/shared/types/presenters/legacy.presenters.d.ts (3)
  • McpSamplingRequestPayload (1210-1210)
  • RENDERER_MODEL_META (551-565)
  • McpSamplingDecision (1211-1211)
src/main/presenter/mcpPresenter/index.ts (1)
  • handleSamplingRequest (589-603)
src/renderer/src/events.ts (1)
  • MCP_EVENTS (68-77)
🔇 Additional comments (2)
src/renderer/src/components/ModelChooser.vue (1)

90-93: Vision-aware filtering logic looks solid.

Prop wiring and eligibleModels filtering correctly constrain choices when requiresVision is true; early-return null prevents empty providers from rendering. Nice and readable.

Also applies to: 115-123

src/renderer/src/components/mcp/McpSamplingDialog.vue (1)

6-19: Good i18n coverage in header and description.

All user-visible strings use vue-i18n keys with sensible fallbacks.

Comment on lines 123 to 131
const closeRequest = () => {
isOpen.value = false
isChoosingModel.value = false
isSubmitting.value = false
request.value = null
selectedProviderId.value = null
selectedModel.value = null
}

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

🧩 Analysis chain

Blocker: dialog dismissal must notify presenter to resolve pending request.

closeRequest() only flips UI state; the main presenter waits on a promise and will hang until timeout. Treat dismiss as an explicit rejection (or call a cancel API) before clearing request.

Minimal, additive fix: add a dismiss() helper and export it; call it from the dialog instead of closeRequest.

@@
   const closeRequest = () => {
     isOpen.value = false
     isChoosingModel.value = false
     isSubmitting.value = false
     request.value = null
     selectedProviderId.value = null
     selectedModel.value = null
   }
+
+  // Notify main/presenter when the dialog is dismissed without explicit approval/rejection
+  const dismiss = async () => {
+    if (!request.value || isSubmitting.value) {
+      // Nothing to notify or a submit is in-flight; just close locally
+      closeRequest()
+      return
+    }
+    const current = request.value
+    isSubmitting.value = true
+    try {
+      await mcpPresenter.submitSamplingDecision({
+        requestId: current.requestId,
+        approved: false,
+        reason: 'Dialog dismissed by user'
+      })
+    } catch (error) {
+      console.warn('[MCP Sampling] Failed to notify dismissal', error)
+    } finally {
+      isSubmitting.value = false
+      closeRequest()
+    }
+  }
@@
   return {
@@
-    closeRequest
+    closeRequest,
+    dismiss
   }

Then update the dialog’s onDialogToggle to call store.dismiss() (see comment in McpSamplingDialog.vue).

If a dedicated cancel API exists, prefer it. Check:


🏁 Script executed:

#!/bin/bash
rg -nP 'cancelSamplingRequest\s*\(' src | sed -n '1,200p'

Length of output: 384


Now I need to inspect the actual store file to understand the implementation context:


---

🏁 Script executed:

```shell
#!/bin/bash
# Examine mcpSampling.ts to understand imports, submitSamplingDecision usage, and request structure
cat src/renderer/src/stores/mcpSampling.ts | head -200

Length of output: 5848



---

🏁 Script executed:

```shell
#!/bin/bash
# Check presenter interface to see if cancelSamplingRequest is available
rg -nP 'interface.*Presenter|cancelSamplingRequest|submitSamplingDecision' src/shared/types/presenters/legacy.presenters.d.ts | head -40

Length of output: 1064



---

🏁 Script executed:

```shell
#!/bin/bash
# Find McpSamplingDialog.vue and check how closeRequest is used
fd -t f 'McpSamplingDialog.*' src && rg -nP 'closeRequest|onDialogToggle|close' src/renderer/src/components/McpSamplingDialog.vue -A2 -B2 | head -80

Length of output: 143



---

🏁 Script executed:

```shell
#!/bin/bash
# Examine McpSamplingDialog.vue with correct path
rg -nP 'closeRequest|onDialogToggle|@close|@update:open' src/renderer/src/components/mcp/McpSamplingDialog.vue -A2 -B2 | head -100

Length of output: 336


Blocker: dialog dismissal must notify presenter to resolve pending request.

The issue is confirmed. When onDialogToggle calls store.closeRequest() (McpSamplingDialog.vue:223), the presenter is never notified of a dismissal decision. The presenter waits indefinitely for a response, causing a hang until timeout.

Recommended fix: Create and export a dismiss() helper that calls submitSamplingDecision({approved: false}) before clearing state (as suggested), then update the dialog to call store.dismiss() instead of store.closeRequest() on dismissal. This approach aligns with the existing rejectRequest() pattern and properly notifies the presenter.

Alternatively, use cancelSamplingRequest() if semantically distinct cancellation is preferred, but submitSamplingDecision is already established in the codebase for this purpose.

🤖 Prompt for AI Agents
In src/renderer/src/stores/mcpSampling.ts around lines 123-131, the
closeRequest() function clears state but does not notify the presenter of a
dismissal causing the presenter to wait indefinitely; add and export a dismiss()
helper that calls submitSamplingDecision({ approved: false }) (or
cancelSamplingRequest() if you prefer a distinct semantic) before performing the
same state-clearing steps as closeRequest(), and update the dialog to call
store.dismiss() instead of store.closeRequest() so the presenter is properly
notified prior to clearing the store.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/renderer/src/stores/mcpSampling.ts (1)

39-102: Consider extracting the helper function for improved readability.

The resetSelection function is 63 lines with nested logic and an inner helper. While functionally correct, extracting pickEligibleModel as a top-level function would reduce cognitive load and improve testability.

Example refactor:

// Extract as a module-scoped helper above the store definition
function pickEligibleModel(
  providerEntry: { providerId: string; models: RENDERER_MODEL_META[] } | undefined,
  requiresVision: boolean,
  preferredModelId?: string | null
): { providerId: string | null; model: RENDERER_MODEL_META | null } {
  if (!providerEntry) {
    return { providerId: null, model: null }
  }

  const models = requiresVision
    ? providerEntry.models.filter((model) => model.vision)
    : providerEntry.models

  if (models.length === 0) {
    return { providerId: null, model: null }
  }

  if (preferredModelId) {
    const preferredModel = models.find((model) => model.id === preferredModelId)
    if (preferredModel) {
      return { providerId: providerEntry.providerId, model: preferredModel }
    }
  }

  return { providerId: providerEntry.providerId, model: models[0] }
}

// Then in resetSelection:
const resetSelection = () => {
  const requiresVisionValue = requiresVision.value
  // ... rest of logic using pickEligibleModel(entry, requiresVisionValue, modelId)
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2b27dc1 and 53544ea.

📒 Files selected for processing (1)
  • src/renderer/src/stores/mcpSampling.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.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/mcpSampling.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.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/mcpSampling.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/mcpSampling.ts
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/stores/mcpSampling.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/stores/mcpSampling.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/renderer/src/stores/mcpSampling.ts
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/stores/mcpSampling.ts
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/stores/mcpSampling.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/stores/mcpSampling.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/renderer/src/stores/mcpSampling.ts
🧬 Code graph analysis (1)
src/renderer/src/stores/mcpSampling.ts (5)
src/renderer/src/composables/usePresenter.ts (1)
  • usePresenter (103-105)
src/shared/types/core/mcp.ts (2)
  • McpSamplingRequestPayload (99-108)
  • McpSamplingDecision (110-116)
src/shared/types/presenters/legacy.presenters.d.ts (3)
  • McpSamplingRequestPayload (1210-1210)
  • RENDERER_MODEL_META (551-565)
  • McpSamplingDecision (1211-1211)
src/main/presenter/mcpPresenter/index.ts (1)
  • handleSamplingRequest (589-603)
src/renderer/src/events.ts (1)
  • MCP_EVENTS (68-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (1)
src/renderer/src/stores/mcpSampling.ts (1)

1-258: Store correctly implements MCP sampling workflow and resolves the previous critical dismissal issue.

The implementation properly addresses the prior blocker: the dismiss() function (lines 197-208) now calls submitDecision to notify the presenter before clearing state, preventing the presenter from hanging indefinitely.

Positive aspects:

  • Robust error handling in submitDecision with cancellation fallback (lines 159-166)
  • Proper vision validation throughout selection and submission flows
  • Correct IPC lifecycle management with cleanup in onUnmounted
  • clearRequest is internal-only; only dismiss, rejectRequest, and confirmApproval are exported
  • TypeScript types properly leveraged from shared definitions

Comment on lines 197 to 208
const dismiss = async () => {
if (!request.value) {
clearRequest()
return
}

await submitDecision({
requestId: request.value.requestId,
approved: false,
reason: 'User dismissed sampling request'
})
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard against dismissal during in-flight submission.

The dismiss() function correctly addresses the previous critical issue by notifying the presenter before clearing state. However, it doesn't check isSubmitting, which creates a race condition: if the user dismisses while another decision is being submitted, a second submitDecision call will fire. The presenter expects exactly one decision per request.

Apply this diff to guard against concurrent submissions:

 const dismiss = async () => {
-  if (!request.value) {
+  if (!request.value || isSubmitting.value) {
     clearRequest()
     return
   }
📝 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 dismiss = async () => {
if (!request.value) {
clearRequest()
return
}
await submitDecision({
requestId: request.value.requestId,
approved: false,
reason: 'User dismissed sampling request'
})
}
const dismiss = async () => {
if (!request.value || isSubmitting.value) {
clearRequest()
return
}
await submitDecision({
requestId: request.value.requestId,
approved: false,
reason: 'User dismissed sampling request'
})
}
🤖 Prompt for AI Agents
In src/renderer/src/stores/mcpSampling.ts around lines 197 to 208, the dismiss()
function can trigger a second submitDecision if a submission is already
in-flight; add a guard that checks the isSubmitting reactive flag and returns
early when true (e.g. if (isSubmitting.value) return) before calling
submitDecision so only one submission per request can occur.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

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

⚠️ Outside diff range comments (1)
src/main/presenter/threadPresenter/index.ts (1)

415-432: Remove unused code block.

This extra object is constructed but never used. The permissionExtra object constructed later (lines 439-461) is what actually gets assigned to the action block at line 477. This dead code should be removed.

Apply this diff to remove the unused code:

-    const extra: Record<string, string | number | object[] | boolean> = {
-      needsUserAction: true,
-      permissionType
-    }
-
-    const serverName = permission_request?.serverName || tool_call_server_name
-    if (serverName) {
-      extra.serverName = serverName
-    }
-
-    const toolName = permission_request?.toolName || tool_call_name
-    if (toolName) {
-      extra.toolName = toolName
-    }
-
-    if (permission_request) {
-      extra.permissionRequest = JSON.stringify(permission_request)
-    }
-
     if (lastBlock && lastBlock.type === 'tool_call' && lastBlock.tool_call) {
       lastBlock.status = 'success'
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 53544ea and 84b7e7c.

📒 Files selected for processing (4)
  • src/main/events.ts (1 hunks)
  • src/main/presenter/threadPresenter/index.ts (2 hunks)
  • src/renderer/src/events.ts (1 hunks)
  • src/renderer/src/i18n/en-US/mcp.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/i18n/en-US/mcp.json
🧰 Additional context used
📓 Path-based instructions (18)
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • src/renderer/src/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/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/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

  • src/renderer/src/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/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/events.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/events.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/events.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/events.ts
src/renderer/**/*.{vue,ts}

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

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/events.ts
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/events.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/renderer/src/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/events.ts
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/events.ts
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/renderer/src/events.ts
  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
src/main/**/*.ts

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

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

Files:

  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
src/main/**/*.{ts,js,tsx,jsx}

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

主进程代码放在 src/main

Files:

  • src/main/events.ts
  • src/main/presenter/threadPresenter/index.ts
src/main/presenter/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Place Electron main-process presenters under src/main/presenter/ (Window, Tab, Thread, Mcp, Config, LLMProvider)

Files:

  • src/main/presenter/threadPresenter/index.ts
🧠 Learnings (3)
📓 Common learnings
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/

Applied to files:

  • src/renderer/src/events.ts
  • src/main/events.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts

Applied to files:

  • src/main/events.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (2)
src/main/events.ts (1)

115-118: LGTM! MCP sampling events properly defined.

The three new sampling event constants establish clear IPC channels for the sampling workflow: request initiation, decision handling, and cancellation. The naming follows existing conventions and mirrors the renderer events for bidirectional communication.

src/renderer/src/events.ts (1)

74-77: LGTM! Renderer sampling events match main process.

The sampling event constants correctly mirror the main process definitions, enabling proper IPC communication for the sampling workflow. These events will integrate with the new sampling dialog and store components mentioned in the PR.

Comment on lines +439 to +461
const permissionExtra: Record<string, string | boolean> = {
needsUserAction: true
}

if (permission_request?.permissionType) {
permissionExtra.permissionType = permission_request.permissionType
}
if (permission_request) {
permissionExtra.permissionRequest = JSON.stringify(permission_request)
if (permission_request.toolName) {
permissionExtra.toolName = permission_request.toolName
}
if (permission_request.serverName) {
permissionExtra.serverName = permission_request.serverName
}
} else {
if (tool_call_name) {
permissionExtra.toolName = tool_call_name
}
if (tool_call_server_name) {
permissionExtra.serverName = tool_call_server_name
}
}
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 | 🔴 Critical

Critical: Use validated permission type instead of raw value.

The permission type validation logic (lines 392-413) establishes allowed types and defaults to 'read' for safety, but this validated permissionType variable is not used in the permissionExtra object. Instead, line 443-445 directly assigns the raw permission_request.permissionType value without validation, completely bypassing the security checks.

Apply this diff to use the validated permission type:

     const permissionExtra: Record<string, string | boolean> = {
       needsUserAction: true
     }
 
-    if (permission_request?.permissionType) {
-      permissionExtra.permissionType = permission_request.permissionType
-    }
+    // Use the validated permissionType from lines 392-413
+    permissionExtra.permissionType = permissionType
+    
     if (permission_request) {
       permissionExtra.permissionRequest = JSON.stringify(permission_request)
       if (permission_request.toolName) {
         permissionExtra.toolName = permission_request.toolName
       }
       if (permission_request.serverName) {
         permissionExtra.serverName = permission_request.serverName
       }
     } else {
       if (tool_call_name) {
         permissionExtra.toolName = tool_call_name
       }
       if (tool_call_server_name) {
         permissionExtra.serverName = tool_call_server_name
       }
     }

Also applies to: 477-477

🤖 Prompt for AI Agents
In src/main/presenter/threadPresenter/index.ts around lines 439 to 461 (and also
at line ~477), the code assigns permission_request.permissionType directly into
permissionExtra, bypassing the earlier validation that defaulted to a safe
'read' value; replace any direct uses of permission_request.permissionType with
the previously computed/validated permissionType variable so
permissionExtra.permissionType = permissionType, and ensure any other assignment
at line ~477 similarly uses the validated permissionType instead of the raw
request value.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🧹 Nitpick comments (1)
src/renderer/src/i18n/pt-BR/mcp.json (1)

275-305: Inconsistent terminology for image content type: "foto" vs "Imagem".

Line 281 uses "image": "foto" (photo) but line 285 uses "imageAlt": "Imagem {índice}" (image). For consistency, both references to the same UI concept should use the same Portuguese term. Consider standardizing on "Imagem" since it's more formal and matches the imageAlt field.

Apply this diff to standardize terminology:

-    "contentType": {
-      "audio": "Áudio",
-      "image": "foto",
-      "text": "texto"
-    },
+    "contentType": {
+      "audio": "Áudio",
+      "image": "Imagem",
+      "text": "texto"
+    },
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 84b7e7c and 1382c3f.

📒 Files selected for processing (10)
  • src/renderer/src/i18n/en-US/mcp.json (1 hunks)
  • src/renderer/src/i18n/fa-IR/mcp.json (1 hunks)
  • src/renderer/src/i18n/fr-FR/mcp.json (1 hunks)
  • src/renderer/src/i18n/ja-JP/mcp.json (1 hunks)
  • src/renderer/src/i18n/ko-KR/mcp.json (1 hunks)
  • src/renderer/src/i18n/pt-BR/mcp.json (1 hunks)
  • src/renderer/src/i18n/ru-RU/mcp.json (1 hunks)
  • src/renderer/src/i18n/zh-CN/mcp.json (1 hunks)
  • src/renderer/src/i18n/zh-HK/mcp.json (1 hunks)
  • src/renderer/src/i18n/zh-TW/mcp.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/i18n/en-US/mcp.json
🧰 Additional context used
📓 Path-based instructions (4)
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/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/ru-RU/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
  • src/renderer/src/i18n/fa-IR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/ru-RU/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
  • src/renderer/src/i18n/fa-IR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
src/renderer/src/i18n/**/*.{ts,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Store i18n resources under src/renderer/src/i18n

Files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/ru-RU/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
  • src/renderer/src/i18n/fa-IR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/ru-RU/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
  • src/renderer/src/i18n/fa-IR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
🧠 Learnings (4)
📓 Common learnings
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
📚 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/i18n/*.json : Maintain consistent structure across all translation files

Applied to files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/ru-RU/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
  • src/renderer/src/i18n/fa-IR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
📚 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/i18n/common.json : Shared translation keys must be placed in 'src/renderer/src/i18n/common.json'

Applied to files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
  • src/renderer/src/i18n/fa-IR/mcp.json
📚 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/i18n/*.json : When adding new translations, add shared keys to 'common.json' and language-specific keys to the respective language file; keep all language files' keys consistent

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-CN/mcp.json
🪛 GitHub Actions: PR Check
src/renderer/src/i18n/fa-IR/mcp.json

[error] 1-1: Missing translation keys for i18n fa-IR: sampling.noVisionModels, sampling.preference.cost, sampling.preference.hints, sampling.preference.intelligence, sampling.preference.speed, sampling.preferencesTitle, sampling.reject, sampling.selectedModelLabel, sampling.systemPrompt, sampling.title, sampling.unknownHint, sampling.unknownMime, sampling.unknownServer, sampling.unsupportedMessage, sampling.visionWarning.

src/renderer/src/i18n/fr-FR/mcp.json

[error] 1-1: Missing translation keys for i18n fr-FR: sampling.noVisionModels, sampling.preference.cost, sampling.preference.hints, sampling.preference.intelligence, sampling.preference.speed, sampling.preferencesTitle, sampling.reject, sampling.selectedModelLabel, sampling.systemPrompt, sampling.title, sampling.unknownHint, sampling.unknownMime, sampling.unknownServer, sampling.unsupportedMessage, sampling.visionWarning.

🔇 Additional comments (6)
src/renderer/src/i18n/ja-JP/mcp.json (1)

275-304: Sampling localization complete and well-structured.

The ja-JP sampling section includes all required keys with proper nesting for contentType and preference objects. Structure and translations are consistent with the feature requirements.

src/renderer/src/i18n/zh-CN/mcp.json (1)

275-304: Sampling localization complete and well-structured.

The zh-CN sampling section includes all required keys with proper structure. Translations align with the feature requirements for model preferences, vision warnings, and system prompts.

src/renderer/src/i18n/ru-RU/mcp.json (1)

275-304: Sampling localization complete and well-structured.

The ru-RU sampling section includes all required keys with proper nesting. Translations cover model preferences, vision capabilities, and system prompts as required by the feature.

src/renderer/src/i18n/ko-KR/mcp.json (1)

275-305: Sampling localization complete and well-structured.

The ko-KR sampling section includes all required keys with complete nesting for content types and model preferences. Translations align with the MCP sampling workflow requirements.

src/renderer/src/i18n/zh-HK/mcp.json (1)

275-305: ✓ i18n structure verified and correctly implemented.

The new "sampling" section in src/renderer/src/i18n/zh-HK/mcp.json is correctly structured and fully utilized. All 22+ keys are actively referenced in McpSamplingDialog.vue with proper interpolation placeholders ({server}, {model}, {provider}, {索引}). Translations are appropriate Hong Kong Cantonese using traditional characters. No hardcoded strings found in renderer components or stores.

src/renderer/src/i18n/zh-TW/mcp.json (1)

289-294: Verify nested preference object structure.

The preference object (lines 289-294) contains four keys (cost, hints, intelligence, speed). Confirm this nested structure aligns with how the sampling dialog component accesses and renders model preferences in the UI, particularly in McpSamplingDialog.vue or related store logic.

Comment on lines 275 to 305
"sampling": {
"approve": "concordar",
"confirming": "Confirmando...",
"confirm": "Enviar resposta do modelo",
"contentType": {
"audio": "Áudio",
"image": "foto",
"text": "texto"
},
"description": "Verifique o contexto compartilhado pelo servidor MCP e decida se gera uma resposta.",
"imageAlt": "Imagem {índice}",
"messagesTitle": "Contexto do Diálogo",
"noModels": "Nenhum modelo qualificado foi ativado.\nAtive um modelo aplicável nas \"Configurações\" para continuar.",
"noVisionModels": "Nenhum modelo com recursos visuais está ativado.\nAtive um modelo visual nas \"Configurações\" para continuar.",
"preference": {
"cost": "Prioridade de custo",
"hints": "Prompt do modelo",
"intelligence": "Prioridade de Inteligência",
"speed": "Velocidade prioritária"
},
"preferencesTitle": "Preferência do modelo",
"reject": "Recusar",
"selectedModelLabel": "Responder usando {model} ({provider})",
"systemPrompt": "Prompt do sistema",
"title": "Solicitação de amostra de {server}",
"unknownHint": "Prompt sem nome",
"unknownMime": "Tipo MIME desconhecido",
"unknownServer": "Servidor desconhecido",
"unsupportedMessage": "Não é suportado este tipo de conteúdo.",
"visionWarning": "O modelo selecionado não suporta entrada visual.\nPor favor, selecione primeiro um modelo com funcionalidade visual antes de continuar."
}
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 | 🔴 Critical

🧩 Analysis chain

Verify sampling keys exist consistently across all language locale files.

The PR adds sampling UI strings to pt-BR. Per the learnings, maintain consistent structure across all translation files. Confirm that all sampling keys (approve, confirm, contentType, description, imageAlt, messagesTitle, noModels, noVisionModels, preference, preferencesTitle, reject, selectedModelLabel, systemPrompt, title, unknownHint, unknownMime, unknownServer, unsupportedMessage, visionWarning) exist in all other language files (en-US, fr-FR, ru-RU, zh-CN, zh-TW, ja-JP, ko-KR, fa-IR, zh-HK, etc.) to maintain key consistency across locales.


🏁 Script executed:

#!/bin/bash
# Description: Verify that the sampling section keys are present in all i18n language files

# Find all mcp.json files in the i18n directory
echo "Checking for sampling keys across all language files..."
mcp_files=$(fd -e json 'mcp\.json$' src/renderer/src/i18n)

# Extract sampling keys from pt-BR for comparison
pt_br_keys=$(cat src/renderer/src/i18n/pt-BR/mcp.json | jq -r '.sampling | keys[]' 2>/dev/null | sort)
echo "Expected sampling keys from pt-BR:"
echo "$pt_br_keys"
echo ""

# Check each language file
for file in $mcp_files; do
  if [[ "$file" != *"pt-BR"* ]]; then
    echo "Checking: $file"
    file_keys=$(cat "$file" | jq -r '.sampling | keys[]' 2>/dev/null | sort)
    
    if [ -z "$file_keys" ]; then
      echo "  ⚠️  No sampling section found"
    else
      # Compare keys
      diff <(echo "$pt_br_keys") <(echo "$file_keys") || echo "  ⚠️  Key mismatch detected"
    fi
    echo ""
  fi
done

Length of output: 1809


The previous script encountered a shell compatibility issue with process substitution. Let me rerun the verification with a corrected approach:


🏁 Script executed:

#!/bin/bash
# Description: Verify sampling section keys across all i18n language files (without process substitution)

echo "Checking for sampling keys across all language files..."
mcp_files=$(fd -e json 'mcp\.json$' src/renderer/src/i18n)

# Extract sampling keys from pt-BR
pt_br_keys=$(cat src/renderer/src/i18n/pt-BR/mcp.json | jq -r '.sampling | keys | sort[]' 2>/dev/null)
echo "Expected sampling keys from pt-BR:"
echo "$pt_br_keys"
echo "Total keys: $(echo "$pt_br_keys" | wc -l)"
echo ""

# Check each language file
for file in $mcp_files; do
  lang=$(basename $(dirname "$file"))
  if [[ "$lang" != "pt-BR" ]]; then
    echo "=== Checking: $lang ==="
    
    # Check if sampling section exists
    sampling_exists=$(cat "$file" | jq 'has("sampling")' 2>/dev/null)
    
    if [[ "$sampling_exists" == "true" ]]; then
      file_keys=$(cat "$file" | jq -r '.sampling | keys | sort[]' 2>/dev/null)
      file_key_count=$(echo "$file_keys" | wc -l)
      echo "Sampling section found with $file_key_count keys"
      
      # Find missing keys
      missing=$(comm -23 <(echo "$pt_br_keys") <(echo "$file_keys"))
      if [ -n "$missing" ]; then
        echo "Missing keys:"
        echo "$missing"
      else
        echo "✓ All keys present"
      fi
      
      # Find extra keys
      extra=$(comm -13 <(echo "$pt_br_keys") <(echo "$file_keys"))
      if [ -n "$extra" ]; then
        echo "Extra keys not in pt-BR:"
        echo "$extra"
      fi
    else
      echo "⚠️  No sampling section found"
    fi
    echo ""
  fi
done

Length of output: 1858


The output shows a clear inconsistency. Let me identify exactly which keys are missing from the files with fewer keys:


🏁 Script executed:

#!/bin/bash
# Compare sampling keys more directly

echo "=== Detailed Key Comparison ==="
echo ""

# Get pt-BR keys as reference
pt_br_file="src/renderer/src/i18n/pt-BR/mcp.json"
pt_br_keys=$(cat "$pt_br_file" | jq -r '.sampling | keys[]' 2>/dev/null | sort)

# Check fa-IR
echo "=== fa-IR sampling keys ==="
fa_ir_file="src/renderer/src/i18n/fa-IR/mcp.json"
fa_ir_keys=$(cat "$fa_ir_file" | jq -r '.sampling | keys[]' 2>/dev/null | sort)
echo "$fa_ir_keys"
echo ""
echo "Keys in pt-BR but missing in fa-IR:"
for key in $pt_br_keys; do
  if ! echo "$fa_ir_keys" | grep -q "^${key}$"; then
    echo "  - $key"
  fi
done
echo ""

# Check fr-FR
echo "=== fr-FR sampling keys ==="
fr_fr_file="src/renderer/src/i18n/fr-FR/mcp.json"
fr_fr_keys=$(cat "$fr_fr_file" | jq -r '.sampling | keys[]' 2>/dev/null | sort)
echo "$fr_fr_keys"
echo ""
echo "Keys in pt-BR but missing in fr-FR:"
for key in $pt_br_keys; do
  if ! echo "$fr_fr_keys" | grep -q "^${key}$"; then
    echo "  - $key"
  fi
done

Length of output: 743


Add missing sampling keys to fa-IR and fr-FR language files.

Verification confirms that fa-IR/mcp.json and fr-FR/mcp.json are missing 12 sampling keys that exist in all other language files (en-US, ja-JP, ko-KR, ru-RU, zh-CN, zh-HK, zh-TW, and pt-BR). This breaks translation consistency across locales.

Missing keys in both fa-IR and fr-FR:

  • noVisionModels
  • preference
  • preferencesTitle
  • reject
  • selectedModelLabel
  • systemPrompt
  • title
  • unknownHint
  • unknownMime
  • unknownServer
  • unsupportedMessage
  • visionWarning

Add these keys to src/renderer/src/i18n/fa-IR/mcp.json and src/renderer/src/i18n/fr-FR/mcp.json with appropriate translations to match the other language files.

Comment on lines 275 to 305
"sampling": {
"approve": "同意",
"confirming": "確認中...",
"confirm": "發送模型響應",
"contentType": {
"audio": "音頻",
"image": "圖片",
"text": "文字"
},
"description": "查看 MCP 伺服器共享的上下文並選擇是否產生回應。",
"imageAlt": "圖片{索引}",
"messagesTitle": "對話上下文",
"noModels": "沒有啟用符合條件的模型。\n在「設定」中啟用適用的模型以繼續。",
"noVisionModels": "未啟用任何具有視覺功能的模型。\n在「設定」中啟用視覺模型以繼續。",
"preference": {
"cost": "成本優先",
"hints": "模型提示",
"intelligence": "情報優先",
"speed": "速度優先"
},
"preferencesTitle": "模型偏好",
"reject": "拒絕",
"selectedModelLabel": "使用 {model} ({provider}) 進行回應",
"systemPrompt": "系統提示",
"title": "來自 {server} 的取樣請求",
"unknownHint": "未命名提示",
"unknownMime": "未知的 MIME 類型",
"unknownServer": "未知伺服器",
"unsupportedMessage": "不支援此內容類型。",
"visionWarning": "所選模型不支援視覺輸入。 \n請先選擇一個具有視覺功能的模型,然後再繼續。"
}
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 | 🔴 Critical

🧩 Analysis chain

Verify consistency of sampling translation keys across all locale files.

The new sampling section appears comprehensive and correctly placed in the zh-TW locale file. However, to ensure consistency with the feature rollout across all supported languages, please verify that the key structure and content mirror those added in other locales mentioned in the PR summary (en-US, fr-FR, ja-JP, ko-KR, zh-CN, zh-HK, ru-RU, fa-IR).


🏁 Script executed:

#!/bin/bash
# Description: Verify sampling keys exist consistently across locale files
# Expected: All locale files referenced should have parallel "sampling" section with same key structure

# Find all mcp.json locale files
echo "=== Searching for mcp.json locale files ==="
fd 'mcp\.json$' src/renderer/src/i18n

# Extract and compare "sampling" section structure across locales
echo -e "\n=== Checking 'sampling' section presence in each locale ==="
for file in $(fd 'mcp\.json$' src/renderer/src/i18n); do
  if grep -q '"sampling"' "$file"; then
    echo "$file has 'sampling' section"
    # Extract sampling keys
    echo "  Keys: $(jq '.sampling | keys[]' "$file" 2>/dev/null | head -5)..."
  else
    echo "$file missing 'sampling' section"
  fi
done

# Verify key count is consistent
echo -e "\n=== Sampling key counts by locale ==="
for file in $(fd 'mcp\.json$' src/renderer/src/i18n); do
  count=$(jq '.sampling | keys | length' "$file" 2>/dev/null || echo "0")
  echo "$file: $count keys"
done

Length of output: 2311


🏁 Script executed:

#!/bin/bash
# Description: Identify which keys are missing from fa-IR and fr-FR
# Goal: Compare key structures between full locale (zh-TW) and incomplete locales

echo "=== Keys in zh-TW (reference - 20 keys) ==="
jq '.sampling | keys | sort[]' src/renderer/src/i18n/zh-TW/mcp.json 2>/dev/null

echo -e "\n=== Keys in fa-IR (8 keys) ==="
jq '.sampling | keys | sort[]' src/renderer/src/i18n/fa-IR/mcp.json 2>/dev/null

echo -e "\n=== Keys in fr-FR (8 keys) ==="
jq '.sampling | keys | sort[]' src/renderer/src/i18n/fr-FR/mcp.json 2>/dev/null

echo -e "\n=== Missing keys comparison ==="
echo "fa-IR missing keys:"
comm -23 \
  <(jq '.sampling | keys | sort[]' src/renderer/src/i18n/zh-TW/mcp.json 2>/dev/null | tr -d '"') \
  <(jq '.sampling | keys | sort[]' src/renderer/src/i18n/fa-IR/mcp.json 2>/dev/null | tr -d '"') \
  | sed 's/^/  - /'

echo -e "\nfr-FR missing keys:"
comm -23 \
  <(jq '.sampling | keys | sort[]' src/renderer/src/i18n/zh-TW/mcp.json 2>/dev/null | tr -d '"') \
  <(jq '.sampling | keys | sort[]' src/renderer/src/i18n/fr-FR/mcp.json 2>/dev/null | tr -d '"') \
  | sed 's/^/  - /'

Length of output: 749


Critical: fa-IR and fr-FR locales are missing 12 sampling keys each.

The zh-TW sampling section is correctly implemented with all 20 required keys. However, verification revealed that fa-IR and fr-FR translations are incomplete, containing only 8 of the 20 keys:

Missing from fa-IR and fr-FR:
noVisionModels, preference, preferencesTitle, reject, selectedModelLabel, systemPrompt, title, unknownHint, unknownMime, unknownServer, unsupportedMessage, visionWarning

Please add these missing keys to src/renderer/src/i18n/fa-IR/mcp.json and src/renderer/src/i18n/fr-FR/mcp.json to ensure complete translations for the sampling feature across all supported locales.

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

♻️ Duplicate comments (4)
src/renderer/src/components/mcp/McpSamplingDialog.vue (2)

70-76: Verify MIME type validation in main process.

The image src attribute uses message.dataUrl directly. Past review comments identified that MIME type validation should occur in the main process before constructing data URLs. Ensure src/main/presenter/mcpPresenter/mcpClient.ts validates MIME types against a whitelist before passing to renderer.

Based on learnings


283-286: Add explicit type annotation for model parameter.

The model parameter lacks a type annotation, reducing type safety. Specify RENDERER_MODEL_META to match the expected type from ModelChooser.

-const onModelUpdate = (model, providerId: string) => {
+const onModelUpdate = (model: RENDERER_MODEL_META, providerId: string) => {
   store.selectModel(model, providerId)
   modelSelectOpen.value = false
 }

Ensure RENDERER_MODEL_META is imported:

 import { useMcpSamplingStore } from '@/stores/mcpSampling'
+import type { RENDERER_MODEL_META } from '@shared/presenter'

As per coding guidelines

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

316-327: Guard against dismissal during in-flight submission.

The dismissRequest function can trigger a second submitDecision if called while a submission is already in flight. The presenter expects exactly one decision per request, so concurrent submissions create a race condition.

Apply this diff to guard against concurrent submissions:

 const dismissRequest = async () => {
-  if (!request.value) {
+  if (!request.value || isSubmitting.value) {
     clearRequest()
     return
   }

329-331: Prevent concurrent sampling requests from orphaning pending decisions.

If a new sampling request arrives while the user is reviewing a previous request, openRequest overwrites request.value without notifying the presenter about the abandoned request. The presenter for the first request will wait indefinitely until timeout.

Consider rejecting new requests when busy (simplest approach):

 const handleSamplingRequest = (_event: unknown, payload: McpSamplingRequestPayload) => {
+  if (request.value || isSubmitting.value) {
+    console.warn('[MCP Sampling] Rejecting new request; another is pending', payload.requestId)
+    mcpPresenter.submitSamplingDecision({
+      requestId: payload.requestId,
+      approved: false,
+      reason: 'Another sampling request is already pending'
+    }).catch(err => console.error('[MCP Sampling] Failed to reject concurrent request', err))
+    return
+  }
   openRequest(payload)
 }
🧹 Nitpick comments (2)
src/renderer/src/stores/mcpSampling.ts (2)

261-286: Consider user-facing error feedback for submission failures.

When submitDecision fails, it logs to console and attempts cancellation, but provides no user-facing feedback. Users may not realize their decision wasn't submitted.

Consider adding toast/notification for submission errors:

   } catch (error) {
     console.error('[MCP Sampling] Failed to submit decision:', error)
+    // TODO: Show user-facing error notification
+    // Example: useToast().error(t('mcp.errors.submitSamplingFailed'))

50-113: Consider extracting pickEligibleModel for testability.

The resetSelection function is quite large (60+ lines) with a nested helper function. While the logic is correct, extracting pickEligibleModel to module scope would improve testability and reduce cognitive complexity.

Example refactor:

const pickEligibleModel = (
  providerEntry: { providerId: string; models: RENDERER_MODEL_META[] } | undefined,
  requiresVision: boolean,
  preferredModelId?: string | null
): { providerId: string | null; model: RENDERER_MODEL_META | null } => {
  if (!providerEntry) {
    return { providerId: null, model: null }
  }
  
  const models = requiresVision
    ? providerEntry.models.filter((model) => model.vision)
    : providerEntry.models
  // ... rest of logic
}

// Then in resetSelection:
const resetSelection = () => {
  const requiresVisionValue = requiresVision.value
  const selection = pickEligibleModel(providerEntry, requiresVisionValue, activeModelId)
  // ...
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1382c3f and 12b4e9a.

📒 Files selected for processing (5)
  • src/renderer/index.html (0 hunks)
  • src/renderer/src/components/mcp/McpSamplingDialog.vue (1 hunks)
  • src/renderer/src/i18n/en-US/mcp.json (1 hunks)
  • src/renderer/src/i18n/zh-CN/mcp.json (1 hunks)
  • src/renderer/src/stores/mcpSampling.ts (1 hunks)
💤 Files with no reviewable changes (1)
  • src/renderer/index.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/renderer/src/i18n/zh-CN/mcp.json
🧰 Additional context used
📓 Path-based instructions (21)
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/i18n/en-US/mcp.json
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/i18n/en-US/mcp.json
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/i18n/**/*.{ts,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Store i18n resources under src/renderer/src/i18n

Files:

  • src/renderer/src/i18n/en-US/mcp.json
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/i18n/en-US/mcp.json
  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{js,jsx,ts,tsx}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/error-logging.mdc)

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

Files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.ts
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts,tsx,js,jsx}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,tsx,vue}

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

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

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{vue,ts}

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

Implement lazy loading for routes and components.

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.{ts,vue}

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

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

Use Pinia for frontend state management (do not introduce alternative state libraries)

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Enable and adhere to strict TypeScript typing (avoid implicit any, prefer precise types)

Use PascalCase for TypeScript types and classes

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.{vue,ts}

📄 CodeRabbit inference engine (AGENTS.md)

All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,js,jsx,vue}: Use OxLint for JS/TS code; keep lint clean
Use camelCase for variables and functions
Use SCREAMING_SNAKE_CASE for constants

Files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/**/*.vue

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

Use scoped styles to prevent CSS conflicts between components

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/{src,shell,floating}/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/{src,shell,floating}/**/*.vue: Use Vue 3 Composition API for all components
All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
Use Tailwind CSS utilities and ensure styles are scoped in Vue components

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

Organize UI components by feature within src/renderer/src/

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Name Vue component files in PascalCase (e.g., ChatInput.vue)

Files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
🧠 Learnings (11)
📓 Common learnings
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
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`.
📚 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/mcpSampling.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/

Applied to files:

  • src/renderer/src/stores/mcpSampling.ts
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts

Applied to files:

  • src/renderer/src/stores/mcpSampling.ts
  • src/renderer/src/components/mcp/McpSamplingDialog.vue
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/renderer/**/*.{ts,vue} : Use Pinia for frontend state management (do not introduce alternative state libraries)

Applied to files:

  • src/renderer/src/stores/mcpSampling.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} : Implement proper state persistence for maintaining data across sessions

Applied to files:

  • src/renderer/src/stores/mcpSampling.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/mcpSampling.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/renderer/src/stores/mcpSampling.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/renderer/src/stores/mcpSampling.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/**/*.{ts,tsx,vue} : Use descriptive variable names with auxiliary verbs (e.g., isLoading, hasError).

Applied to files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/preload/**/*.ts : Implement the secure IPC bridge in src/preload/** with contextIsolation enabled and no unsafe APIs exposed

Applied to files:

  • src/renderer/src/components/mcp/McpSamplingDialog.vue
🧬 Code graph analysis (1)
src/renderer/src/stores/mcpSampling.ts (6)
src/renderer/src/composables/usePresenter.ts (1)
  • usePresenter (103-105)
src/shared/types/core/mcp.ts (2)
  • McpSamplingRequestPayload (99-108)
  • McpSamplingDecision (110-116)
src/shared/types/presenters/legacy.presenters.d.ts (3)
  • McpSamplingRequestPayload (1210-1210)
  • RENDERER_MODEL_META (551-565)
  • McpSamplingDecision (1211-1211)
src/main/presenter/mcpPresenter/index.ts (1)
  • handleSamplingRequest (589-603)
src/main/events.ts (1)
  • MCP_EVENTS (108-119)
src/renderer/src/events.ts (1)
  • MCP_EVENTS (69-78)
🔇 Additional comments (4)
src/renderer/src/stores/mcpSampling.ts (1)

127-223: Well-structured session management.

The session tracking implementation properly handles expiration, validation, and cleanup. The logic correctly:

  • Validates session freshness against SESSION_TIMEOUT
  • Removes expired sessions before operations
  • Validates that session models still exist and meet requirements (e.g., vision support)
  • Records approvals before auto-submitting
src/renderer/src/i18n/en-US/mcp.json (1)

139-177: LGTM! Comprehensive i18n coverage for sampling feature.

The new sampling section provides complete localization coverage for the MCP sampling dialog. All keys are well-structured and align with the usage in McpSamplingDialog.vue.

As per coding guidelines

src/renderer/src/components/mcp/McpSamplingDialog.vue (2)

296-300: Dialog dismissal properly integrated with store.

The onDialogToggle handler correctly calls store.dismissRequest() when the dialog is closed, ensuring the presenter is notified. The implementation properly guards against dismissal during submission.


245-281: Well-structured preference summary.

The preferenceSummary computed property properly:

  • Formats numeric preferences to two decimal places
  • Handles missing/undefined values gracefully
  • Maps hints array with fallback for unnamed hints
  • Uses i18n keys for all labels

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
src/renderer/src/i18n/pt-BR/mcp.json (1)

276-276: Refine translation accuracy and UI terminology.

  • Line 276: "concordar" (informally: "agree") is less precise for a UI approve action. Use "Aprovar" instead.
  • Line 281: "foto" (photo) is inaccurate for the generic content type. Use "Imagem" (image) for consistency.

Apply this diff:

-    "approve": "concordar",
+    "approve": "Aprovar",
     "confirming": "Confirmando...",
     "confirm": "Enviar resposta do modelo",
     "contentType": {
       "audio": "Áudio",
-      "image": "foto",
+      "image": "Imagem",
       "text": "texto"
     },

Also applies to: 281-281

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12b4e9a and 35588ab.

📒 Files selected for processing (8)
  • src/renderer/src/i18n/fa-IR/mcp.json (1 hunks)
  • src/renderer/src/i18n/fr-FR/mcp.json (1 hunks)
  • src/renderer/src/i18n/ja-JP/mcp.json (1 hunks)
  • src/renderer/src/i18n/ko-KR/mcp.json (1 hunks)
  • src/renderer/src/i18n/pt-BR/mcp.json (1 hunks)
  • src/renderer/src/i18n/ru-RU/mcp.json (1 hunks)
  • src/renderer/src/i18n/zh-HK/mcp.json (1 hunks)
  • src/renderer/src/i18n/zh-TW/mcp.json (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/renderer/src/i18n/fa-IR/mcp.json
  • src/renderer/src/i18n/ru-RU/mcp.json
🧰 Additional context used
📓 Path-based instructions (4)
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/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
src/renderer/src/**

📄 CodeRabbit inference engine (AGENTS.md)

Place Vue 3 app source under src/renderer/src (components, stores, views, i18n, lib)

Files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
src/renderer/src/i18n/**/*.{ts,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Store i18n resources under src/renderer/src/i18n

Files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
**/*.{ts,tsx,js,jsx,vue,css,scss,md,json,yml,yaml}

📄 CodeRabbit inference engine (AGENTS.md)

Prettier style: single quotes, no semicolons, print width 100; run pnpm run format

Files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
🧠 Learnings (10)
📓 Common learnings
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/index.ts : Register new MCP tools in src/main/presenter/mcpPresenter/index.ts
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/main/presenter/mcpPresenter/inMemoryServers/*.ts : Implement new MCP tools under src/main/presenter/mcpPresenter/inMemoryServers/
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`.
📚 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/i18n/*.json : Maintain consistent structure across all translation files

Applied to files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 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/i18n/common.json : Shared translation keys must be placed in 'src/renderer/src/i18n/common.json'

Applied to files:

  • src/renderer/src/i18n/zh-HK/mcp.json
  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/ja-JP/mcp.json
  • src/renderer/src/i18n/ko-KR/mcp.json
  • src/renderer/src/i18n/fr-FR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 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/i18n/*.json : When adding new translations, add shared keys to 'common.json' and language-specific keys to the respective language file; keep all language files' keys consistent

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 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/i18n/*.json : Regularly check for unused translation keys in i18n files

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 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/**/* : All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 Learning: 2025-09-06T03:07:23.817Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/renderer/{src,shell,floating}/**/*.vue : All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 Learning: 2025-10-14T08:02:59.495Z
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/renderer/src/**/*.{vue,ts} : All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 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/**/* : Ensure all user-visible text in the renderer uses the translation system

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
📚 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/i18n/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')

Applied to files:

  • src/renderer/src/i18n/pt-BR/mcp.json
  • src/renderer/src/i18n/zh-TW/mcp.json
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-check (x64)
🔇 Additional comments (6)
src/renderer/src/i18n/zh-HK/mcp.json (1)

275-312: Sampling section looks good.

The new sampling section is properly structured with consistent placeholder usage ({server}, {model}, {seconds}, {maxTokens}) and complete translation coverage. All required keys are present and correctly nested.

src/renderer/src/i18n/zh-TW/mcp.json (1)

275-312: Sampling section looks good.

The new sampling section is properly structured with all required keys, consistent placeholder usage, and appropriate Traditional Chinese (Taiwan) localization. Structure mirrors zh-HK and other locales as expected.

src/renderer/src/i18n/ko-KR/mcp.json (1)

275-313: Sampling section looks good.

The new sampling section is complete with all required keys and consistent placeholder usage across all localization strings.

src/renderer/src/i18n/ja-JP/mcp.json (3)

287-288: Double-check multiline string formatting for UI rendering.

Lines 287-288 include \n escape sequences in translations (e.g., "一致するモデルが有効になっていません。\n続行するには..." and "視覚的に有効なモデルは有効になりません。\n続行するには..."). Confirm the dialog component correctly renders these newlines and preserves formatting.


275-313: Sampling section verified across all supported locales with consistent structure.

The sampling section has been successfully added to all 10 locale files (en-US, fa-IR, fr-FR, ko-KR, pt-BR, ru-RU, zh-CN, zh-HK, zh-TW, ja-JP) with identical key structures. All nested objects (contentType and preference) are present and consistent across all locales.


275-313: Fix ja-JP placeholder mismatch and remove hardcoded UI string.

Two issues found:

  1. Line 285: "imageAlt": "写真{インデックス}" uses non-matching placeholder {インデックス}. The component passes { index: index + 1 } (English key). Change to "imageAlt": "写真{index}" to match component interpolation.

  2. McpSamplingDialog.vue line 84: Hardcoded <span>Audio content</span> violates i18n guidelines. Replace with {{ t('mcp.sampling.contentType.audio') }}.

Additionally, three translation keys (autoApproveIn, autoApproving, selectedModelLabel) exist across all locale files but have no corresponding $t() calls in the component—these may be dead code pending feature implementation.

⛔ Skipped due to learnings
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/i18n/*.json : Maintain consistent structure across all translation files
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/i18n/common.json : Shared translation keys must be placed in 'src/renderer/src/i18n/common.json'
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/i18n/*.json : Regularly check for unused translation keys in i18n files
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/**/* : All user-facing strings must use i18n keys (avoid hardcoded user-visible text in code)
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: AGENTS.md:0-0
Timestamp: 2025-10-14T08:02:59.495Z
Learning: Applies to src/renderer/src/**/*.{vue,ts} : All user-facing strings must use vue-i18n ($t/keys) rather than hardcoded literals
Learnt from: CR
PR: ThinkInAIXYZ/deepchat#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T03:07:23.817Z
Learning: Applies to src/renderer/{src,shell,floating}/**/*.vue : All user-facing strings must use i18n keys via vue-i18n (no hard-coded UI strings)
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/i18n/*.json : When adding new translations, add shared keys to 'common.json' and language-specific keys to the respective language file; keep all language files' keys consistent
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/i18n/*.json : Translation key naming must use dot-separated hierarchy, lowercase letters, and meaningful descriptive names (e.g., 'common.button.submit')
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/**/* : Ensure all user-visible text in the renderer uses the translation system

Comment on lines +275 to 313
"sampling": {
"approve": "accepter",
"confirming": "Confirmation...",
"confirm": "Envoyer la réponse du modèle",
"contentType": {
"audio": "Audio",
"image": "image",
"text": "texte"
},
"description": "Consulter le contexte partagé par le serveur MCP et choisir de générer ou non une réponse.",
"imageAlt": "Image {index}",
"messagesTitle": "Contexte de la conversation",
"noModels": "Aucun modèle éligible n'est activé.\nActivez un modèle applicable dans les \"Paramètres\" pour continuer.",
"autoApproveIn": "Approuver automatiquement à l'aide de {model} après {seconds} secondes",
"autoApproving": "Exemple de requête MCP de {serveur}",
"maxTokensInfo": "Longueur de réponse maximale : {maxTokens} jetons",
"noVisionModels": "Aucun modèle visuellement activé n’est activé.\nActivez le modèle visuel dans Paramètres pour continuer.",
"preference": {
"cost": "Priorité aux coûts",
"hints": "Conseils pour les modèles",
"intelligence": "Le renseignement d’abord",
"speed": "Priorité vitesse"
},
"preferencesTitle": "Préférence de modèle",
"reject": "rejeter",
"respondWith": "Modèle de réponse :",
"reviewRequest": "vérifier les détails",
"selectModel": "Sélectionnez le modèle",
"selectedModelLabel": "Répondez en utilisant {model} ({provider})",
"sendResponse": "Envoyer la réponse",
"sessionActive": "Session active - la demande sera automatiquement approuvée",
"systemPrompt": "Invite système",
"title": "Demande d'échantillonnage de {serveur}",
"unknownHint": "invite sans nom",
"unknownMime": "Type MIME inconnu",
"unknownServer": "serveur inconnu",
"unsupportedMessage": "Ce type de contenu n'est pas pris en charge.",
"visionWarning": "Le modèle sélectionné ne prend pas en charge la saisie visuelle.\nVeuillez sélectionner un modèle visuellement capable avant de continuer."
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Fix placeholder inconsistencies in sampling section.

Lines 289 and 307 use {serveur} instead of {server} as placeholders, which is inconsistent with the rest of the file (e.g., line 54 uses {name}, line 235 uses {serverName}). Placeholders should use English identifiers to match the component code.

Additionally, line 289's translation for "autoApproving" ("Exemple de requête MCP de {serveur}") differs semantically from other locales (zh-HK, zh-TW, ko-KR all use "request from {server}"), suggesting a possible translation error.

Apply this diff to fix the placeholder inconsistency and align the translation:

-    "autoApproving": "Exemple de requête MCP de {serveur}",
+    "autoApproving": "Demande d'échantillonnage MCP de {server}",
-    "title": "Demande d'échantillonnage de {serveur}",
+    "title": "Demande d'échantillonnage de {server}",
📝 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
"sampling": {
"approve": "accepter",
"confirming": "Confirmation...",
"confirm": "Envoyer la réponse du modèle",
"contentType": {
"audio": "Audio",
"image": "image",
"text": "texte"
},
"description": "Consulter le contexte partagé par le serveur MCP et choisir de générer ou non une réponse.",
"imageAlt": "Image {index}",
"messagesTitle": "Contexte de la conversation",
"noModels": "Aucun modèle éligible n'est activé.\nActivez un modèle applicable dans les \"Paramètres\" pour continuer.",
"autoApproveIn": "Approuver automatiquement à l'aide de {model} après {seconds} secondes",
"autoApproving": "Exemple de requête MCP de {serveur}",
"maxTokensInfo": "Longueur de réponse maximale : {maxTokens} jetons",
"noVisionModels": "Aucun modèle visuellement activé nest activé.\nActivez le modèle visuel dans Paramètres pour continuer.",
"preference": {
"cost": "Priorité aux coûts",
"hints": "Conseils pour les modèles",
"intelligence": "Le renseignement dabord",
"speed": "Priorité vitesse"
},
"preferencesTitle": "Préférence de modèle",
"reject": "rejeter",
"respondWith": "Modèle de réponse :",
"reviewRequest": "vérifier les détails",
"selectModel": "Sélectionnez le modèle",
"selectedModelLabel": "Répondez en utilisant {model} ({provider})",
"sendResponse": "Envoyer la réponse",
"sessionActive": "Session active - la demande sera automatiquement approuvée",
"systemPrompt": "Invite système",
"title": "Demande d'échantillonnage de {serveur}",
"unknownHint": "invite sans nom",
"unknownMime": "Type MIME inconnu",
"unknownServer": "serveur inconnu",
"unsupportedMessage": "Ce type de contenu n'est pas pris en charge.",
"visionWarning": "Le modèle sélectionné ne prend pas en charge la saisie visuelle.\nVeuillez sélectionner un modèle visuellement capable avant de continuer."
}
"sampling": {
"approve": "accepter",
"confirming": "Confirmation...",
"confirm": "Envoyer la réponse du modèle",
"contentType": {
"audio": "Audio",
"image": "image",
"text": "texte"
},
"description": "Consulter le contexte partagé par le serveur MCP et choisir de générer ou non une réponse.",
"imageAlt": "Image {index}",
"messagesTitle": "Contexte de la conversation",
"noModels": "Aucun modèle éligible n'est activé.\nActivez un modèle applicable dans les \"Paramètres\" pour continuer.",
"autoApproveIn": "Approuver automatiquement à l'aide de {model} après {seconds} secondes",
"autoApproving": "Demande d'échantillonnage MCP de {server}",
"maxTokensInfo": "Longueur de réponse maximale : {maxTokens} jetons",
"noVisionModels": "Aucun modèle visuellement activé n'est activé.\nActivez le modèle visuel dans Paramètres pour continuer.",
"preference": {
"cost": "Priorité aux coûts",
"hints": "Conseils pour les modèles",
"intelligence": "Le renseignement d'abord",
"speed": "Priorité vitesse"
},
"preferencesTitle": "Préférence de modèle",
"reject": "rejeter",
"respondWith": "Modèle de réponse :",
"reviewRequest": "vérifier les détails",
"selectModel": "Sélectionnez le modèle",
"selectedModelLabel": "Répondez en utilisant {model} ({provider})",
"sendResponse": "Envoyer la réponse",
"sessionActive": "Session active - la demande sera automatiquement approuvée",
"systemPrompt": "Invite système",
"title": "Demande d'échantillonnage de {server}",
"unknownHint": "invite sans nom",
"unknownMime": "Type MIME inconnu",
"unknownServer": "serveur inconnu",
"unsupportedMessage": "Ce type de contenu n'est pas pris en charge.",
"visionWarning": "Le modèle sélectionné ne prend pas en charge la saisie visuelle.\nVeuillez sélectionner un modèle visuellement capable avant de continuer."
}
🤖 Prompt for AI Agents
In src/renderer/src/i18n/fr-FR/mcp.json around lines 275 to 313, two entries use
the French placeholder "{serveur}" instead of the English "{server}" and one
translation also deviates semantically; replace "{serveur}" with "{server}" in
the "autoApproving" and "title" values and update the "autoApproving" text to
match the intent of other locales (e.g., use a phrasing like "Exemple de requête
MCP du serveur {server}" or "Requête MCP du serveur {server}") so the
placeholder matches the component code and the meaning aligns with other
locales.

"text": "texto"
},
"description": "Verifique o contexto compartilhado pelo servidor MCP e decida se gera uma resposta.",
"imageAlt": "Imagem {índice}",
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 | 🔴 Critical

Placeholder variable name must not be translated.

The i18n placeholder on line 285 uses {índice} instead of {index}. Placeholder variable names must remain in English to match what the code passes to the translation function (e.g., $t('mcp.sampling.imageAlt', { index: 1 })). Translating the variable name breaks runtime placeholder replacement.

Apply this diff:

-    "imageAlt": "Imagem {índice}",
+    "imageAlt": "Imagem {index}",
📝 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
"imageAlt": "Imagem {índice}",
"imageAlt": "Imagem {index}",
🤖 Prompt for AI Agents
In src/renderer/src/i18n/pt-BR/mcp.json around line 285, the placeholder
variable in the translation string is translated as "{índice}" which prevents
runtime replacement; change the placeholder to use the original English variable
name "{index}" so calls like $t('mcp.sampling.imageAlt', { index: 1 }) correctly
replace it, and keep the rest of the translation text intact.

@zerob13 zerob13 merged commit df534b8 into dev Oct 30, 2025
2 checks passed
@zerob13 zerob13 deleted the codex/add-sampling-support-in-mcp-module branch November 6, 2025 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants