Skip to content

Conversation

@deepinfect
Copy link
Collaborator

@deepinfect deepinfect commented Oct 14, 2025

Summary by CodeRabbit

  • New Features

    • Added a Cancel button to stop ongoing message generation; Send returns when idle.
    • Introduced a confirmation dialog before clearing all messages in a thread, with clear and cancel actions.
    • Enhanced canceled message display with a subtle notice instead of an error block.
    • Enabled clearing all messages in the active thread from the dialog.
  • Style

    • Updated action layout to stack vertically within the dialog for improved clarity.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 14, 2025

Walkthrough

Adds streaming-aware cancel behavior to PromptInput, introduces a confirmation dialog to clear all messages from MessageList, and adjusts MessageBlockError to render a distinct UI for cancelled blocks versus other errors. New control flows handle canceling generation and confirming thread-wide message clearing.

Changes

Cohort / File(s) Summary of changes
Prompt input streaming cancel
src/renderer/src/components/prompt-input/PromptInput.vue
Adds isStreaming computed; toggles Send/Cancel button. Implements handleCancel to call chatStore.cancelGenerating for the active thread. Template conditionally shows cancel during generation.
Message list clean dialog
src/renderer/src/components/message/MessageList.vue
Adds confirmation dialog (shadcn Dialog). Replaces inline cancel with openCleanDialog. Implements handleThreadCleanMessages to call chatStore.clearAllMessages(threadId); adds dialog open/close state and handlers. Adjusts action layout classes.
Message block cancel UI
src/renderer/src/components/message/MessageBlockError.vue
Conditionally renders a muted “cancelled” row with refresh-off icon when status is 'cancel'; retains red error block for other statuses.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant PromptInput
  participant ChatStore as chatStore
  participant Thread as ActiveThread

  User->>PromptInput: Press Cancel (while streaming)
  PromptInput->>ChatStore: getActiveThreadId()
  alt Active thread exists and is generating
    PromptInput->>ChatStore: cancelGenerating(threadId)
    ChatStore-->>PromptInput: ack/caught error
  else No active thread
    Note over PromptInput: No-op
  end
Loading
sequenceDiagram
  autonumber
  actor User
  participant MessageList
  participant Dialog
  participant ChatStore as chatStore

  User->>MessageList: Click "Clean messages"
  MessageList->>Dialog: Open
  User->>Dialog: Confirm
  Dialog->>MessageList: onConfirm
  MessageList->>ChatStore: getActiveThreadId()
  MessageList->>ChatStore: clearAllMessages(threadId)
  alt Success
    ChatStore-->>MessageList: resolved
    MessageList->>Dialog: Close
  else Error
    ChatStore-->>MessageList: error
    MessageList->>Dialog: Close (after handling)
  end
Loading
sequenceDiagram
  participant UI as MessageBlockError.vue
  participant Block as block

  alt block.status == 'cancel'
    UI->>UI: Render muted cancel row with icon + i18n text
  else Other statuses
    UI->>UI: Render red error block (existing)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • zerob13

Poem

I thump my paws: “Cancel!”—the stream goes still,
A whisper of dialogs asks, “Clean this quill?”
Errors wear grey when chats are curtailed,
Threads sweep neat, no crumbs derailed.
With tidy logs and buttons bright,
This bunny ships the flow just right. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title “Feat/button cancel” is too terse and does not clearly convey the primary updates introduced by this changeset, including a cancel button for streaming generation, a message cleanup confirmation dialog, and updated error block rendering for canceled statuses. It ambiguously refers to a cancel button without specifying where the feature appears or the broader context of the UI improvements. As a result, teammates scanning the PR history may not grasp the full scope of the changes. Please update the PR title to succinctly summarize the main UI enhancements, for example “Add streaming cancel button and message cleanup confirmation dialog,” so that the scope and intent of the changes are immediately clear.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/button-cancel

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

🧹 Nitpick comments (2)
src/renderer/src/components/prompt-input/PromptInput.vue (1)

729-732: Consider providing user feedback when cancellation fails.

The handleCancel function silently returns when there's no active thread. While this prevents errors, it could leave users uncertain about why the cancel action had no effect.

Consider logging or providing user feedback:

 const handleCancel = () => {
-  if (!chatStore.getActiveThreadId()) return
+  const activeThreadId = chatStore.getActiveThreadId()
+  if (!activeThreadId) {
+    console.warn('Cannot cancel: no active thread')
+    return
+  }
-  chatStore.cancelGenerating(chatStore.getActiveThreadId()!)
+  chatStore.cancelGenerating(activeThreadId)
 }
src/renderer/src/components/message/MessageBlockError.vue (1)

2-8: Avoid empty translation lookups: t(block.content || '') will call t('') when block.content is falsy—either wrap the <span> in v-if="block.content" or supply a default key (e.g. 'common.cancelled') to prevent empty lookups.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c126214 and c6de5e8.

📒 Files selected for processing (3)
  • src/renderer/src/components/message/MessageBlockError.vue (1 hunks)
  • src/renderer/src/components/message/MessageList.vue (6 hunks)
  • src/renderer/src/components/prompt-input/PromptInput.vue (3 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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.vue
src/renderer/**/*.{vue,ts,js,tsx,jsx}

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

渲染进程代码放在 src/renderer

Files:

  • src/renderer/src/components/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.vue
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for all logs and comments

Files:

  • src/renderer/src/components/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.vue
src/renderer/src/components/**/*

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • src/renderer/src/components/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.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/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

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

Files:

  • src/renderer/src/components/prompt-input/PromptInput.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageBlockError.vue
⏰ 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/components/prompt-input/PromptInput.vue (2)

1073-1079: LGTM: isStreaming implementation is clean.

The computed property correctly checks if the active thread is in the generating state by looking up the thread ID in generatingThreadIds.


196-214: Verify conditional rendering with v-if and keys.

The Send and Cancel buttons use v-if without explicit key attributes (except Cancel has key="cancel"). While Vue 3 generally handles this well, consider adding a key to the Send button for explicit control during transitions.

             <Button
+              key="send"
               variant="default"
               size="icon"
               class="w-7 h-7 text-xs rounded-lg"

This ensures Vue properly distinguishes between the two buttons during the transition when isStreaming changes.

src/renderer/src/components/message/MessageList.vue (4)

93-110: LGTM: Dialog implementation follows best practices.

The dialog component correctly uses:

  • i18n keys for all user-facing text
  • Destructive variant for the confirm button
  • Proper state management with cleanMessagesDialog ref
  • Standard dialog composition with header, description, and footer

As per coding guidelines.


188-206: Verify error handling in chatStore.clearAllMessages.

The handleThreadCleanMessages function includes a try-catch block, but only logs the error without providing user feedback (e.g., a toast notification).

Consider whether users should be notified of failure:

const handleThreadCleanMessages = async () => {
  try {
    const threadId = chatStore.getActiveThreadId()
    if (!threadId) {
      return
    }
    await chatStore.clearAllMessages(threadId)
    cleanMessagesDialog.value = false
  } catch (error) {
    console.error(t('common.error.cleanMessagesFailed'), error)
    // Consider adding user-facing error notification:
    // toast({ title: t('common.error.cleanMessagesFailed'), variant: 'destructive' })
  }
}

Note: The dialog is closed outside the try-catch, so it closes even on error. Consider moving it inside the try block if you want it to stay open on failure.


40-40: Approve flex direction change for vertical button stacking.

Changing from horizontal to vertical layout (flex flex-col) appropriately accommodates the new dialog-triggered clean action alongside the scroll-to-bottom button.


130-139: LGTM: Dialog imports and state initialization.

The dialog components are properly imported from the shadcn UI library, and the cleanMessagesDialog ref is correctly initialized as a boolean.

>
<Icon icon="lucide:arrow-up" class="w-4 h-4" />
</Button>
<!-- 取消按钮 -->
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Replace Chinese comment with English.

The comment on line 201 is in Chinese. Per coding guidelines, all comments must be in English.

As per coding guidelines.

Apply this diff:

-            <!-- 取消按钮 -->
+            <!-- Cancel button -->
📝 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
<!-- 取消按钮 -->
<!-- Cancel button -->
🤖 Prompt for AI Agents
In src/renderer/src/components/prompt-input/PromptInput.vue around line 201, the
inline comment "取消按钮" is in Chinese; update that comment to English (e.g.,
"Cancel button") by replacing the Chinese text with an equivalent English
comment, preserving comment style/placement and whitespace.

@zerob13
Copy link
Collaborator

zerob13 commented Oct 14, 2025

@codex review

@chatgpt-codex-connector
Copy link

Codex Review: Didn't find any major issues. Already looking forward to the next diff.

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

@zerob13 zerob13 merged commit 84ecc97 into dev Oct 14, 2025
2 checks passed
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.

3 participants