Conversation
📝 WalkthroughWalkthroughThis update introduces a comprehensive, multi-step onboarding flow to the desktop application, adding new React components for audio permissions, calendar permissions, language selection, and model download progress. The onboarding sequence and UI are restructured, with new logic for permission handling, model downloads, microphone muting during onboarding, and improved user feedback. Supporting localization, documentation, and styling updates are included. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant WelcomeModal
participant ModelSelectionView
participant DownloadProgressView
participant AudioPermissionsView
participant LanguageSelectionView
participant CalendarPermissionsView
participant App
User->>WelcomeModal: Open onboarding modal
WelcomeModal->>User: Show welcome view
User->>WelcomeModal: Continue
WelcomeModal->>ModelSelectionView: Show model selection
User->>ModelSelectionView: Select model, continue
WelcomeModal->>DownloadProgressView: Show download progress
DownloadProgressView->>WelcomeModal: Notify on download complete
User->>WelcomeModal: Continue
WelcomeModal->>AudioPermissionsView: Show audio permissions
AudioPermissionsView->>WelcomeModal: Notify on permissions granted
User->>WelcomeModal: Continue
WelcomeModal->>LanguageSelectionView: Show language selection
User->>LanguageSelectionView: Select languages, continue
WelcomeModal->>CalendarPermissionsView: Show calendar permissions
CalendarPermissionsView->>WelcomeModal: Notify on permissions granted or skipped
User->>WelcomeModal: Finish onboarding
WelcomeModal->>App: Close modal, start servers, navigate if onboardingSessionId exists
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: .coderabbit.yaml 📒 Files selected for processing (10)
✅ Files skipped from review due to trivial changes (4)
🚧 Files skipped from review as they are similar to previous changes (6)
⏰ 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). (3)
✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
Documentation and Community
|
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (5)
apps/desktop/src/components/welcome-modal/language-selection-view.tsx (2)
122-126: Remove unreachable code condition.The condition checking
selectedLanguages.length === 0is unreachable because English is always present and cannot be removed (enforced inhandleRemoveLanguage). This creates dead code.- {selectedLanguages.length === 0 && ( - <p className="text-sm text-muted-foreground"> - <Trans>Select at least one language</Trans> - </p> - )}
178-178: Remove redundant disabled condition.The
disabled={selectedLanguages.length === 0}condition is redundant sinceselectedLanguageswill always contain at least English (which cannot be removed).- disabled={selectedLanguages.length === 0}apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx (2)
86-87: Consider reducing polling frequency for permission status.Polling every 500ms for permission status may be unnecessarily aggressive and could impact performance. Consider increasing the interval to 1-2 seconds since permission changes are user-initiated actions that don't require sub-second responsiveness.
- refetchInterval: 500, + refetchInterval: 1000,
12-26: Consider adding loading state to PermissionItem interface.The PermissionItem component could benefit from a loading state to provide visual feedback during permission requests, similar to the pattern used in the AudioPermissionsView component.
interface PermissionItemProps { icon: React.ReactNode; title: string; description: string; done: boolean | undefined; + isLoading?: boolean; onRequest: () => void; }apps/desktop/src/components/welcome-modal/audio-permissions-view.tsx (1)
101-102: Consider reducing polling frequency for permission status.Similar to the calendar permissions component, polling every 500ms may be unnecessarily aggressive. Consider increasing to 1-2 seconds for better performance.
refetchInterval: 500, + refetchInterval: 1000,Apply this change to both permission queries.
Also applies to: 107-108
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (17)
apps/desktop/src/components/editor-area/note-header/listen-button.tsx(4 hunks)apps/desktop/src/components/settings/components/ai/stt-view.tsx(1 hunks)apps/desktop/src/components/welcome-modal/audio-permissions-view.tsx(1 hunks)apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx(1 hunks)apps/desktop/src/components/welcome-modal/download-progress-view.tsx(1 hunks)apps/desktop/src/components/welcome-modal/index.tsx(4 hunks)apps/desktop/src/components/welcome-modal/language-selection-view.tsx(1 hunks)apps/desktop/src/components/welcome-modal/model-selection-view.tsx(6 hunks)apps/desktop/src/components/welcome-modal/rating-display.tsx(1 hunks)apps/desktop/src/components/welcome-modal/welcome-view.tsx(1 hunks)apps/desktop/src/locales/en/messages.po(28 hunks)apps/desktop/src/locales/ko/messages.po(28 hunks)apps/desktop/src/routes/app.tsx(3 hunks)apps/desktop/src/styles/globals.css(1 hunks)crates/db-user/assets/onboarding-raw.html(1 hunks)crates/db-user/assets/thank-you.md(1 hunks)plugins/local-llm/assets/onboarding-enhanced.md(1 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{js,ts,tsx,rs}
⚙️ CodeRabbit Configuration File
**/*.{js,ts,tsx,rs}: 1. No error handling.
2. No unused imports, variables, or functions.
3. For comments, keep it minimal. It should be about "Why", not "What".
Files:
apps/desktop/src/components/welcome-modal/welcome-view.tsxapps/desktop/src/components/settings/components/ai/stt-view.tsxapps/desktop/src/components/welcome-modal/index.tsxapps/desktop/src/routes/app.tsxapps/desktop/src/components/welcome-modal/calendar-permissions-view.tsxapps/desktop/src/components/welcome-modal/rating-display.tsxapps/desktop/src/components/welcome-modal/language-selection-view.tsxapps/desktop/src/components/welcome-modal/audio-permissions-view.tsxapps/desktop/src/components/editor-area/note-header/listen-button.tsxapps/desktop/src/components/welcome-modal/model-selection-view.tsxapps/desktop/src/components/welcome-modal/download-progress-view.tsx
⏰ 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). (3)
- GitHub Check: ci
- GitHub Check: ci (macos, macos-latest)
- GitHub Check: ci (windows, windows-latest)
🔇 Additional comments (33)
apps/desktop/src/styles/globals.css (1)
117-135: LGTM! Clean fade-in-out animation implementation.The keyframe animation is well-structured with smooth opacity and position transitions. The timing progression (0% → 20% → 80% → 100%) provides good visual feedback for UI elements.
apps/desktop/src/components/welcome-modal/rating-display.tsx (1)
13-17: LGTM! Good responsive design improvements.The responsive styling updates are well-implemented, providing better mobile experience with smaller fonts, spacing, and icons while maintaining good desktop visuals.
Also applies to: 22-22
apps/desktop/src/components/welcome-modal/language-selection-view.tsx (1)
63-84: LGTM! Well-implemented language selection logic.The component correctly handles language selection with proper validation, prevents duplicate selections, and enforces English as a required language. The state management and event handlers are implemented correctly.
apps/desktop/src/components/welcome-modal/welcome-view.tsx (1)
28-28: LGTM! Clean branding update.The text content change aligns with the updated messaging for the onboarding flow.
apps/desktop/src/components/settings/components/ai/stt-view.tsx (1)
94-94: LGTM! Improved model description clarity.The simplified description is more accurate and removes potentially misleading speed comparisons while focusing on the key characteristics.
crates/db-user/assets/onboarding-raw.html (4)
1-2: LGTM: Clear user guidance during model download phase.The warning messages effectively communicate the wait time during STT&LLM model downloads and set appropriate expectations for users during the onboarding process.
4-4: LGTM: Concise workflow explanation.The brief explanation "new meeting -> new note and record" effectively communicates the core workflow in simple terms.
9-9: LGTM: Updated feature list aligns with current capabilities.The change from "extensions => realtime transcript, CRM integrations" to "chat, templates" better reflects the current feature set mentioned in the broader onboarding enhancements.
17-20: LGTM: Documentation link addition improves user resources.Adding the official documentation link provides users with better access to comprehensive guidance, complementing the existing Discord community link.
apps/desktop/src/routes/app.tsx (3)
21-21: LGTM: Clean import addition for onboarding integration.The useHypr hook import is appropriately added to support the onboarding completion flow.
42-42: LGTM: Proper hook usage for accessing onboarding session.The extraction of onboardingSessionId from useHypr follows React best practices and integrates cleanly with the existing component structure.
94-96: LGTM: Well-structured conditional navigation logic.The conditional navigation to the thank-you session page is properly implemented with appropriate null checking and follows the expected flow after onboarding completion.
crates/db-user/assets/thank-you.md (3)
1-2: LGTM: Improved formatting enhances readability.The bold formatting for "STT&LLM models" draws appropriate attention to the key concept, and the line break improves visual structure.
4-5: LGTM: Clear explanation of feature availability timeline.The detailed explanation about when transcription and summarization features become available, including the visual cue about the recording button turning red, provides excellent user guidance during the model download process.
7-7: LGTM: Updated links provide better user resources.The replacement of previous links with official documentation and blog links offers users more comprehensive and up-to-date resources, while maintaining the onboarding video reference.
apps/desktop/src/components/welcome-modal/model-selection-view.tsx (3)
27-42: LGTM: Well-implemented responsive design for rating display.The responsive classes with appropriate breakpoints (sm:) provide good mobile and desktop experiences. The sizing and spacing adjustments are properly implemented.
66-68: LGTM: Simplified and focused continue handler.The streamlined handleContinue function correctly delegates download progress and notifications to subsequent onboarding steps, maintaining good separation of concerns in the modular onboarding flow.
76-129: LGTM: Improved layout with responsive flexbox design.The replacement of carousel with flexbox provides better usability and the responsive design handles both mobile and desktop well. The model filtering for specific models ("QuantizedTiny", "QuantizedSmall", "QuantizedLargeTurbo") is appropriate for the onboarding experience.
plugins/local-llm/assets/onboarding-enhanced.md (5)
3-4: LGTM: Clear and focused onboarding objectives.The updated objectives effectively communicate the key value propositions of enhanced summaries and offline functionality, aligning well with the broader onboarding experience.
6-10: LGTM: Excellent step-by-step workflow guidance.The new Core Workflow section provides clear, actionable steps that guide users through the essential meeting recording and note enhancement process. This complements the UI-driven onboarding flow well.
13-15: LGTM: Strong privacy messaging with technical details.The enhanced Privacy and Performance section effectively communicates the offline-first architecture and privacy benefits, providing users with confidence in the platform's data handling approach.
17-20: LGTM: Comprehensive feature overview.The new Features section clearly presents the key capabilities users will encounter, helping set appropriate expectations for the onboarding experience.
23-24: LGTM: Updated community and documentation links.The simplified Stay Connected section with official documentation and Discord links provides users with the most relevant resources for ongoing support and learning.
apps/desktop/src/locales/en/messages.po (1)
1-1467: LGTM! Comprehensive localization updates for onboarding flow.The localization file updates properly support the new multi-step onboarding flow with appropriate translation entries for audio permissions, calendar permissions, language selection, and download progress views. The file follows correct gettext .po format conventions and maintains consistency in translation patterns.
apps/desktop/src/components/welcome-modal/audio-permissions-view.tsx (3)
113-114: Good error handling with mutations.The mutation error handling using
onError: console.erroris appropriate for debugging, but consider whether user-facing error messages would improve the user experience for permission request failures.Also applies to: 118-120
122-122: Excellent continue button logic.The
allPermissionsGrantedlogic properly ensures both permissions are granted before allowing the user to continue, which provides a good user experience and prevents incomplete onboarding.
16-16: Good inclusion of loading state in permission item.The
isPendingprop and its usage in the PermissionItem component provides proper visual feedback during permission requests, which is an improvement over the calendar permissions implementation.Also applies to: 67-67
apps/desktop/src/components/editor-area/note-header/listen-button.tsx (4)
65-76: Well-implemented STT model availability check.The
anySttModelExistsquery is properly implemented with appropriate polling interval (3 seconds) and conditional enabling for onboarding sessions. The logic to check any available STT model rather than a specific one makes sense for the onboarding flow.
105-108: Good microphone muting logic for onboarding.Moving the microphone muting logic to the session start handler is a clean approach that ensures the microphone is muted immediately after starting an onboarding session.
142-144: Proper disabled state logic for onboarding.The updated disabled state logic correctly uses
anySttModelExistsfor onboarding sessions while maintaining the existing logic for regular sessions. This allows onboarding to proceed when any STT model is available.
222-224: Consistent UI feedback improvements.The updates to show "Wait..." when disabled and the cursor/opacity changes provide consistent visual feedback across onboarding buttons, improving the user experience during model downloads.
Also applies to: 231-231
apps/desktop/src/locales/ko/messages.po (1)
1-1467: LGTM!The localization file updates are consistent with the new onboarding flow. Only message IDs and source references were updated, with no changes to actual Korean translations.
apps/desktop/src/components/welcome-modal/download-progress-view.tsx (1)
91-137: Fix channel initialization and cleanup issuesThe current implementation has several issues:
- Channel instances are created in state initialization but used as dependencies in useEffect, causing unnecessary re-renders
- No cleanup for channel message handlers
- The channels being dependencies will cause the effect to re-run on every state update
export const DownloadProgressView = ({ selectedSttModel, onContinue, }: DownloadProgressViewProps) => { - const [sttDownload, setSttDownload] = useState<ModelDownloadProgress>({ - channel: new Channel(), - progress: 0, - error: false, - completed: false, - }); - - const [llmDownload, setLlmDownload] = useState<ModelDownloadProgress>({ - channel: new Channel(), - progress: 0, - error: false, - completed: false, - }); + const [sttDownload, setSttDownload] = useState<ModelDownloadProgress>(() => ({ + channel: new Channel(), + progress: 0, + error: false, + completed: false, + })); + + const [llmDownload, setLlmDownload] = useState<ModelDownloadProgress>(() => ({ + channel: new Channel(), + progress: 0, + error: false, + completed: false, + })); const [currentMessageIndex, setCurrentMessageIndex] = useState(0); useEffect(() => { + const sttChannel = sttDownload.channel; + const llmChannel = llmDownload.channel; + localSttCommands.downloadModel(selectedSttModel, sttChannel); + localLlmCommands.downloadModel("HyprLLM", llmChannel); - localLlmCommands.downloadModel("HyprLLM", llmDownload.channel); - - sttDownload.channel.onmessage = (progress) => { + sttChannel.onmessage = (progress) => { if (progress < 0) { setSttDownload(prev => ({ ...prev, error: true })); return; } setSttDownload(prev => ({ ...prev, progress: Math.max(prev.progress, progress), completed: progress >= 100, })); }; - llmDownload.channel.onmessage = (progress) => { + llmChannel.onmessage = (progress) => { if (progress < 0) { setLlmDownload(prev => ({ ...prev, error: true })); return; } setLlmDownload(prev => ({ ...prev, progress: Math.max(prev.progress, progress), completed: progress >= 100, })); }; - }, [selectedSttModel, sttDownload.channel, llmDownload.channel]); + + return () => { + // Clean up message handlers + sttChannel.onmessage = null; + llmChannel.onmessage = null; + }; + }, [selectedSttModel]);Likely an incorrect or invalid review comment.
| if (getOsType() === "macos") { | ||
| appleCalendarCommands | ||
| .requestCalendarAccess() | ||
| .then(() => { | ||
| calendarAccess.refetch(); | ||
| }) | ||
| .catch((error) => { | ||
| console.error(error); | ||
| }); | ||
| } | ||
| }, [calendarAccess]); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Optimize OS type check and improve error handling.
The OS type check is performed on every permission request. Consider moving this check outside the callback and providing user feedback for errors instead of only console logging.
+const isOnMacOS = getOsType() === "macos";
+
const handleRequestCalendarAccess = useCallback(() => {
- if (getOsType() === "macos") {
+ if (isOnMacOS) {
appleCalendarCommands
.requestCalendarAccess()
.then(() => {
calendarAccess.refetch();
})
.catch((error) => {
- console.error(error);
+ console.error(error);
+ // Consider showing a toast or user-facing error message
});
}
}, [calendarAccess]);📝 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.
| if (getOsType() === "macos") { | |
| appleCalendarCommands | |
| .requestCalendarAccess() | |
| .then(() => { | |
| calendarAccess.refetch(); | |
| }) | |
| .catch((error) => { | |
| console.error(error); | |
| }); | |
| } | |
| }, [calendarAccess]); | |
| const isOnMacOS = getOsType() === "macos"; | |
| const handleRequestCalendarAccess = useCallback(() => { | |
| if (isOnMacOS) { | |
| appleCalendarCommands | |
| .requestCalendarAccess() | |
| .then(() => { | |
| calendarAccess.refetch(); | |
| }) | |
| .catch((error) => { | |
| console.error(error); | |
| // Consider showing a toast or user‐facing error message | |
| }); | |
| } | |
| }, [calendarAccess]); |
🤖 Prompt for AI Agents
In apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx
around lines 96 to 106, the OS type check is done inside the permission request
callback causing repeated checks, and errors are only logged to the console
without user feedback. Move the getOsType() check outside the callback to avoid
redundant calls, and replace console.error with a user-facing error notification
or message to inform the user of any issues during calendar access requests.
| const handleRequestContactsAccess = useCallback(() => { | ||
| if (getOsType() === "macos") { | ||
| appleCalendarCommands | ||
| .requestContactsAccess() | ||
| .then(() => { | ||
| contactsAccess.refetch(); | ||
| }) | ||
| .catch((error) => { | ||
| console.error(error); | ||
| }); | ||
| } | ||
| }, [contactsAccess]); |
There was a problem hiding this comment.
🛠️ Refactor suggestion
Apply the same optimization to contacts access handler.
Similar to the calendar access handler, optimize the OS check and consider improving error handling.
const handleRequestContactsAccess = useCallback(() => {
- if (getOsType() === "macos") {
+ if (isOnMacOS) {
appleCalendarCommands
.requestContactsAccess()
.then(() => {
contactsAccess.refetch();
})
.catch((error) => {
- console.error(error);
+ console.error(error);
+ // Consider showing a toast or user-facing error message
});
}
}, [contactsAccess]);🤖 Prompt for AI Agents
In apps/desktop/src/components/welcome-modal/calendar-permissions-view.tsx
around lines 108 to 119, optimize the OS check in handleRequestContactsAccess by
moving the getOsType() call outside the callback or caching its result to avoid
repeated calls. Also, improve error handling by replacing console.error with a
more user-friendly notification or logging mechanism consistent with the
calendar access handler. Ensure the refetch logic remains intact after
successful access request.
| useEffect(() => { | ||
| if (!isOpen && wentThroughDownloads) { | ||
| // start servers for mockup & tutorial | ||
| localSttCommands.startServer(); | ||
| localLlmCommands.startServer(); | ||
|
|
||
| const checkAndShowToasts = async () => { | ||
| try { | ||
| const sttModelExists = await localSttCommands.isModelDownloaded(selectedSttModel as SupportedModel); | ||
| const llmModelExists = await localLlmCommands.isModelDownloaded("HyprLLM"); | ||
|
|
||
| if (!sttModelExists) { | ||
| showSttModelDownloadToast(selectedSttModel, undefined, queryClient); | ||
| } | ||
|
|
||
| if (!llmModelExists) { | ||
| showLlmModelDownloadToast("HyprLLM", undefined, queryClient); | ||
| } | ||
| } catch (error) { | ||
| console.error("Error checking model download status:", error); | ||
| } | ||
| }; | ||
|
|
||
| checkAndShowToasts(); | ||
| } | ||
| }, [isOpen, wentThroughDownloads, selectedSttModel, queryClient]); | ||
|
|
There was a problem hiding this comment.
Add error handling and prevent potential race condition
The current implementation starts servers immediately but checks download status asynchronously, which could cause issues. Also missing error handling for server startup.
useEffect(() => {
if (!isOpen && wentThroughDownloads) {
- // start servers for mockup & tutorial
- localSttCommands.startServer();
- localLlmCommands.startServer();
-
const checkAndShowToasts = async () => {
try {
const sttModelExists = await localSttCommands.isModelDownloaded(selectedSttModel as SupportedModel);
const llmModelExists = await localLlmCommands.isModelDownloaded("HyprLLM");
+ // Start servers only if models exist
+ if (sttModelExists) {
+ await localSttCommands.startServer();
+ } else {
+ showSttModelDownloadToast(selectedSttModel, undefined, queryClient);
+ }
+
+ if (llmModelExists) {
+ await localLlmCommands.startServer();
+ } else {
+ showLlmModelDownloadToast("HyprLLM", undefined, queryClient);
+ }
- if (!sttModelExists) {
- showSttModelDownloadToast(selectedSttModel, undefined, queryClient);
- }
-
- if (!llmModelExists) {
- showLlmModelDownloadToast("HyprLLM", undefined, queryClient);
- }
} catch (error) {
console.error("Error checking model download status:", error);
+ // Consider showing a user-facing error notification here
}
};
checkAndShowToasts();
}
}, [isOpen, wentThroughDownloads, selectedSttModel, queryClient]);📝 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.
| useEffect(() => { | |
| if (!isOpen && wentThroughDownloads) { | |
| // start servers for mockup & tutorial | |
| localSttCommands.startServer(); | |
| localLlmCommands.startServer(); | |
| const checkAndShowToasts = async () => { | |
| try { | |
| const sttModelExists = await localSttCommands.isModelDownloaded(selectedSttModel as SupportedModel); | |
| const llmModelExists = await localLlmCommands.isModelDownloaded("HyprLLM"); | |
| if (!sttModelExists) { | |
| showSttModelDownloadToast(selectedSttModel, undefined, queryClient); | |
| } | |
| if (!llmModelExists) { | |
| showLlmModelDownloadToast("HyprLLM", undefined, queryClient); | |
| } | |
| } catch (error) { | |
| console.error("Error checking model download status:", error); | |
| } | |
| }; | |
| checkAndShowToasts(); | |
| } | |
| }, [isOpen, wentThroughDownloads, selectedSttModel, queryClient]); | |
| useEffect(() => { | |
| if (!isOpen && wentThroughDownloads) { | |
| const checkAndShowToasts = async () => { | |
| try { | |
| const sttModelExists = await localSttCommands.isModelDownloaded( | |
| selectedSttModel as SupportedModel | |
| ); | |
| const llmModelExists = await localLlmCommands.isModelDownloaded( | |
| "HyprLLM" | |
| ); | |
| // Start servers only if models exist | |
| if (sttModelExists) { | |
| await localSttCommands.startServer(); | |
| } else { | |
| showSttModelDownloadToast(selectedSttModel, undefined, queryClient); | |
| } | |
| if (llmModelExists) { | |
| await localLlmCommands.startServer(); | |
| } else { | |
| showLlmModelDownloadToast("HyprLLM", undefined, queryClient); | |
| } | |
| } catch (error) { | |
| console.error("Error checking model download status:", error); | |
| // Consider showing a user-facing error notification here | |
| } | |
| }; | |
| checkAndShowToasts(); | |
| } | |
| }, [isOpen, wentThroughDownloads, selectedSttModel, queryClient]); |
🤖 Prompt for AI Agents
In apps/desktop/src/components/welcome-modal/index.tsx around lines 134 to 160,
add error handling for the localSttCommands.startServer() and
localLlmCommands.startServer() calls by wrapping them in try-catch blocks. Also,
ensure the asynchronous checkAndShowToasts function is awaited or properly
handled to prevent race conditions by making the useEffect callback async or
restructuring the logic to await server startup before checking model downloads.
No description provided.