Skip to content

Conversation

@zhangmo8
Copy link
Collaborator

@zhangmo8 zhangmo8 commented Jan 12, 2026

Summary by CodeRabbit

  • Bug Fixes

    • Improved variant navigation reliability with enhanced boundary checking.
    • Enhanced retry functionality with better error handling and validation.
  • Refactor

    • Optimized message query performance for assistant responses.
    • Streamlined variant selection and navigation logic for increased stability.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 12, 2026

📝 Walkthrough

Walkthrough

This PR refactors variant and message retry handling to use message IDs instead of array indices throughout the codebase. Key changes include converting selectedVariantsMap from a Map to a plain object record, updating the retry composable and store to accept messageId parameters, and modifying the main message query to enforce assistant role filtering and descending timestamp ordering.

Changes

Cohort / File(s) Summary
Database Query Enhancement
src/main/presenter/sqlitePresenter/tables/messages.ts
Modified getMainMessageByParentId to filter main messages by assistant role and order by creation time descending, ensuring only the most recently created assistant message is selected.
Variant Selection & Navigation
src/renderer/src/components/message/MessageItemAssistant.vue, src/renderer/src/components/message/MessageToolbar.vue
Refactored variant indexing and navigation to use direct map lookups instead of store getters; simplified prev/next boundary checking logic and updated disabled button conditions.
Message Retry & Variant Tracking
src/renderer/src/components/message/MessageList.vue, src/renderer/src/composables/message/useMessageRetry.ts, src/renderer/src/stores/chat.ts
Converted retry mechanisms and variant storage from index-based to message ID-based; changed selectedVariantsMap from Map<string, string> to Record<string, string>; added retryFromUserMessage(userMessageId: string) store method; removed per-item assistant ref setup and integrated centralized retry logic.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 From indices we leap, to IDs we bound,
No more array chaos, just strings all around,
Variants now dance with their message in tow,
Retries flow smoother, much cleaner you know!

🚥 Pre-merge checks | ✅ 1 | ❌ 2
❌ Failed checks (1 warning, 1 inconclusive)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title is vague and generic. While it mentions 'retry message', it doesn't specify what aspect of the retry functionality is being fixed or what the main changes accomplish. Consider a more descriptive title such as 'refactor: use message IDs instead of indices for retry handling' or 'fix: convert selectedVariantsMap from Map to object and refactor retry logic'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

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

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/message/MessageToolbar.vue (1)

59-59: Inconsistent handling of undefined currentVariantIndex.

Line 59 uses strict equality currentVariantIndex === 0, but when currentVariantIndex is undefined, this evaluates to false, leaving the "prev" button enabled incorrectly. Lines 71 and 77 correctly use nullish coalescing. Apply the same pattern here for consistency.

🐛 Proposed fix
-                  :disabled="currentVariantIndex === 0"
+                  :disabled="(currentVariantIndex ?? 0) === 0"
🧹 Nitpick comments (2)
src/renderer/src/stores/chat.ts (2)

691-735: Potential duplicate updateSelectedVariant calls.

The function calls updateSelectedVariant twice:

  1. Line 715: await updateSelectedVariant(parentMsg.id, aiResponseMessage.id)
  2. Lines 725-726: await updateSelectedVariant(mainMessage.id, aiResponseMessage.id)

If parentMsg.id equals mainMessage.id (which it should for the same parent), this results in redundant persistence operations. Consider consolidating these calls or adding a guard to avoid the second call when the first already succeeded.

♻️ Suggested fix
       await loadMessages()
-      if (aiResponseMessage.parentId) {
-        const mainMessage = await threadP.getMainMessageByParentId(
-          getActiveThreadId()!,
-          aiResponseMessage.parentId
-        )
-        if (mainMessage) {
-          await updateSelectedVariant(mainMessage.id, aiResponseMessage.id)
-        }
-      }
       generatingThreadIds.value.add(getActiveThreadId()!)

The first updateSelectedVariant call at line 715 should be sufficient since parentMsg.id is the main message ID.


1556-1581: Consider the timing implications of the 100ms delay.

The setTimeout with 100ms delay for resetting isUpdatingVariant is a simple debounce approach, but it has potential edge cases:

  1. If the user rapidly switches variants, multiple calls could overlap and the flag might be reset prematurely by an earlier call's timeout
  2. The 100ms is arbitrary and may not align with actual IPC round-trip times

For robustness, consider tracking the update with a counter or promise instead:

♻️ Alternative approach using a counter
-  let isUpdatingVariant = false
+  let variantUpdateCounter = 0

   const updateSelectedVariant = async (mainMessageId: string, selectedVariantId: string | null) => {
     const activeThreadId = getActiveThreadId()
     if (!activeThreadId) return

-    isUpdatingVariant = true
+    const currentUpdate = ++variantUpdateCounter
     // ... rest of function ...
   } finally {
-      setTimeout(() => {
-        isUpdatingVariant = false
-      }, 100)
+      // Only clear if this is the latest update
+      if (variantUpdateCounter === currentUpdate) {
+        variantUpdateCounter = 0
+      }
     }
   }

Then check variantUpdateCounter > 0 instead of isUpdatingVariant.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7d7d7d and 9dd9039.

📒 Files selected for processing (6)
  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/components/message/MessageList.vue
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/stores/chat.ts
🧰 Additional context used
📓 Path-based instructions (19)
**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use English for logs and comments in TypeScript/JavaScript code

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use TypeScript with strict type checking enabled

Use OxLint for linting JavaScript and TypeScript files; ensure lint-staged hooks and typecheck pass before commits

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
src/main/presenter/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/presenter/**/*.ts: Use EventBus to broadcast events from main to renderer via mainWindow.webContents.send()
Implement one presenter per functional domain in the main process

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
src/main/**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

src/main/**/*.ts: Use EventBus from src/main/eventbus.ts for decoupled inter-process communication
Context isolation must be enabled with preload scripts for secure IPC communication

Electron main process code should reside in src/main/, with presenters organized in presenter/ subdirectory (Window, Tab, Thread, Mcp, Config, LLMProvider), and app events managed via eventbus.ts

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
**/*.{js,ts,tsx,jsx,vue,mjs,cjs}

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

All logs and comments must be in English

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/components/message/MessageList.vue
**/*.{js,ts,tsx,jsx,mjs,cjs}

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

Use OxLint as the linter

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
**/*.{js,ts,tsx,jsx,vue,json,mjs,cjs}

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

Use Prettier as the code formatter

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/components/message/MessageList.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use camelCase for variable and function names; use PascalCase for types and classes; use SCREAMING_SNAKE_CASE for constants
Configure Prettier with single quotes, no semicolons, and line width of 100 characters. Run pnpm run format after completing features

Files:

  • src/main/presenter/sqlitePresenter/tables/messages.ts
  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/components/message/MessageList.vue
src/renderer/**/*.vue

📄 CodeRabbit inference engine (CLAUDE.md)

src/renderer/**/*.vue: Use Vue 3 Composition API for all components
Use Tailwind CSS for styling with scoped styles
All user-facing strings must use i18n keys via vue-i18n

Files:

  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/components/message/MessageList.vue
src/renderer/src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use usePresenter.ts composable for renderer-to-main IPC communication via direct presenter method calls

Ensure all code comments are in English and all log messages are in English, with no non-English text in code comments or console statements

Use VueUse composables for common utilities like useLocalStorage, useClipboard, useDebounceFn

Vue 3 renderer app code should be organized in src/renderer/src with subdirectories for components/, stores/, views/, i18n/, and lib/

Files:

  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/components/message/MessageList.vue
src/renderer/src/**/*.{vue,ts,tsx}

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

src/renderer/src/**/*.{vue,ts,tsx}: Use vue-i18n framework for internationalization located at src/renderer/src/i18n/
All user-facing strings must use i18n keys, not hardcoded text

src/renderer/src/**/*.{vue,ts,tsx}: Use ref for primitives and references, reactive for objects in Vue 3 Composition API
Prefer computed properties over methods for derived state in Vue components
Import Shadcn Vue components from @/shadcn/components/ui/ path alias
Use the cn() utility function combining clsx and tailwind-merge for dynamic Tailwind classes
Use defineAsyncComponent() for lazy loading heavy Vue components
Use TypeScript for all Vue components and composables with explicit type annotations
Define TypeScript interfaces for Vue component props and data structures
Use usePresenter composable for main process communication instead of direct IPC calls

Files:

  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/components/message/MessageList.vue
src/renderer/src/**/*.vue

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

Import useI18n from vue-i18n in Vue components to access translation functions t and locale

src/renderer/src/**/*.vue: Use <script setup> syntax for concise Vue 3 component definitions with Composition API
Define props and emits explicitly in Vue components using defineProps and defineEmits with TypeScript interfaces
Use provide/inject for dependency injection in Vue components instead of prop drilling
Use Tailwind CSS for all styling instead of writing scoped CSS files
Use mobile-first responsive design approach with Tailwind breakpoints
Use Iconify Vue with lucide icons as primary choice, following pattern lucide:{icon-name}
Use v-memo directive for memoizing expensive computations in templates
Use v-once directive for rendering static content without reactivity updates
Use virtual scrolling with RecycleScroller component for rendering long lists
Subscribe to events using rendererEvents.on() and unsubscribe in onUnmounted lifecycle hook

Files:

  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/components/message/MessageList.vue
src/renderer/src/components/**/*.vue

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

Name Vue components using PascalCase (e.g., ChatInput.vue, MessageItemUser.vue)

Files:

  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/components/message/MessageList.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

Vue components must be named in PascalCase (e.g., ChatInput.vue) and use Vue 3 Composition API with Pinia for state management and Tailwind for styling

Files:

  • src/renderer/src/components/message/MessageToolbar.vue
  • src/renderer/src/components/message/MessageItemAssistant.vue
  • src/renderer/src/components/message/MessageList.vue
src/renderer/src/**/stores/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

Use Pinia for frontend state management

Files:

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

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

src/renderer/src/stores/**/*.ts: Use Setup Store syntax with defineStore function pattern in Pinia stores
Use getters (computed properties) for derived state in Pinia stores
Keep Pinia store actions focused on state mutations and async operations

Files:

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

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

Use class-variance-authority (CVA) for defining component variants with Tailwind classes

Files:

  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
src/renderer/src/**/*.{ts,tsx}

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

src/renderer/src/**/*.{ts,tsx}: Use shallowRef and shallowReactive for optimizing reactivity with large objects
Prefer type over interface in TypeScript unless using inheritance with extends

Files:

  • src/renderer/src/stores/chat.ts
  • src/renderer/src/composables/message/useMessageRetry.ts
src/renderer/src/composables/**/*.ts

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

Name composables using camelCase with use prefix (e.g., useChatState.ts, useMessageList.ts)

Files:

  • src/renderer/src/composables/message/useMessageRetry.ts
🧠 Learnings (6)
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,js,jsx} : Use class-variance-authority (CVA) for defining component variants with Tailwind classes

Applied to files:

  • src/renderer/src/components/message/MessageToolbar.vue
📚 Learning: 2025-06-21T15:49:17.044Z
Learnt from: neoragex2002
Repo: ThinkInAIXYZ/deepchat PR: 550
File: src/renderer/src/stores/chat.ts:1011-1035
Timestamp: 2025-06-21T15:49:17.044Z
Learning: In src/renderer/src/stores/chat.ts, the user prefers to keep both `text` and `content` properties in the `handleMeetingInstruction` function's `sendMessage` call, even though they are redundant, rather than removing the `content` property.

Applied to files:

  • src/renderer/src/stores/chat.ts
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/stores/**/*.ts : Keep Pinia store actions focused on state mutations and async operations

Applied to files:

  • src/renderer/src/stores/chat.ts
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/composables/**/*.ts : Name composables using camelCase with `use` prefix (e.g., `useChatState.ts`, `useMessageList.ts`)

Applied to files:

  • src/renderer/src/composables/message/useMessageRetry.ts
  • src/renderer/src/components/message/MessageList.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.{ts,tsx,vue} : Use VueUse composables for common utilities like `useLocalStorage`, `useClipboard`, `useDebounceFn`

Applied to files:

  • src/renderer/src/components/message/MessageList.vue
📚 Learning: 2026-01-05T02:41:31.661Z
Learnt from: CR
Repo: ThinkInAIXYZ/deepchat PR: 0
File: .cursor/rules/vue-stack-guide.mdc:0-0
Timestamp: 2026-01-05T02:41:31.661Z
Learning: Applies to src/renderer/src/**/*.vue : Use virtual scrolling with `RecycleScroller` component for rendering long lists

Applied to files:

  • src/renderer/src/components/message/MessageList.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 (24)
src/main/presenter/sqlitePresenter/tables/messages.ts (1)

273-334: LGTM! The query refinements correctly enforce assistant role and recency.

The addition of role = 'assistant' filter and ORDER BY created_at DESC ensures deterministic selection of the most recent assistant message as the main message. This aligns well with the ID-based retry flow changes across the PR.

src/renderer/src/components/message/MessageToolbar.vue (1)

71-77: LGTM! Boundary checks are now more robust.

The updated display and disabled logic correctly handle undefined values with nullish coalescing. The >= comparison provides additional safety against out-of-bounds indices.

src/renderer/src/composables/message/useMessageRetry.ts (2)

13-62: LGTM! ID-based retry logic is well-structured.

The implementation correctly:

  • Guards against undefined/null messageId inputs
  • Uses optional chaining to handle null messages in the array
  • Falls back to store-level regeneration when ref-based retry fails
  • Includes proper error handling with console.error

5-5: No callers of useMessageRetry found in the codebase.

The composable's retryFromUserMessage function is not imported or used anywhere. The type signature does accept Ref<Array<Message | null>>, and the implementation defensively handles null elements with optional chaining (e.g., msg?.id, nextMessage?.role). However, since there are no current callers, the concern about "verifying that callers handle null elements" cannot be evaluated. If this composable is meant to be integrated elsewhere, ensure callers are compatible with the nullable message array.

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

180-187: LGTM! Correct migration to object-based selectedVariantsMap.

The bracket notation access chatStore.selectedVariantsMap[props.message.id] correctly retrieves the selected variant ID from the Record structure, with proper fallback to index 0 when undefined.


199-219: LGTM! Improved variant aggregation with deduplication.

Using a Map keyed by variant ID ensures no duplicates when merging persisted variants with cached generating variants. The is_variant !== 0 filter correctly excludes the main message from the variant list.


240-249: LGTM! Defensive handling of new variant selection.

The ternary lastVariant ? lastVariant.id : null provides a safe fallback, though lastVariant should always exist when newLength > oldLength. The early return when the thread is generating prevents disruptive auto-switching.


322-335: LGTM! Simplified navigation logic.

The prev/next handling is now cleaner with direct index manipulation and proper boundary checks. The null fallback for selectedVariantId when newIndex === 0 correctly returns to the main message.

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

35-36: LGTM! Correctly passing messageId for retry.

The change from index-based to ID-based retry aligns with the PR objective. Using optional chaining item.message?.id safely handles cases where message might be undefined.


219-223: LGTM! Correct access pattern for Record-based selectedVariantsMap.

The bracket notation chatStore.selectedVariantsMap[message.id] correctly accesses the Record structure, with nullish coalescing returning an empty string as fallback.


244-249: LGTM! Clean delegation to store-level retry.

The simplified handleRetry correctly validates the messageId before delegating to chatStore.retryFromUserMessage. This centralizes retry logic in the store rather than managing refs locally.

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

129-132: Appropriate refactor from Map to Record.

Using Record<string, string> simplifies reactivity and serialization compared to Map. The non-reactive isUpdatingVariant flag is appropriate as a synchronization guard to prevent event loops during variant updates.


245-266: LGTM!

The function correctly handles the object-based lookup. The bracket notation access properly returns undefined for missing keys, which is falsy and correctly handled by the conditional.


634-638: Correct filtering of variant messages from main list.

Variant messages should only be accessible through their parent message's variants array, not as standalone entries in the message list. This prevents duplicate rendering.


764-781: LGTM!

Clean implementation that provides a unified entry point for retry logic. The function correctly:

  1. First attempts to find and retry an existing assistant message
  2. Falls back to regenerating from the user message if no assistant response exists
  3. Maintains consistent error handling patterns

1115-1117: Consistent variant filtering during streaming.

This correctly prevents variant messages from being added to the main message list during streaming, maintaining consistency with the filtering in loadMessages.


1340-1342: LGTM!

Correct conversion from Map to object operations for variant cleanup during message deletion.


1584-1589: LGTM!

Correct conversion from Map has() check to object bracket notation.


1725-1736: Good synchronization guard for multi-window scenarios.

The isUpdatingVariant check correctly prevents the LIST_UPDATED event from overwriting variant selections that are currently being persisted. This avoids race conditions when multiple windows are open.


1508-1547: Correct handling of variant message edits.

When a variant message is edited, the function correctly fetches and updates the parent main message instead of adding the variant as a standalone entry. The early return statements properly short-circuit the flow.


1427-1429: LGTM!

Consistent variant filtering when canceling generation.


1300-1304: LGTM!

Correct loading and defaulting of selectedVariantsMap from conversation settings.


425-426: LGTM!

Assigning a new empty object correctly clears the reactive state and triggers reactivity updates.


2017-2017: LGTM!

New retryFromUserMessage correctly exposed in the store's public API.

@zerob13 zerob13 merged commit a7c6bdd into ThinkInAIXYZ:dev Jan 12, 2026
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.

2 participants