Skip to content

refactor/simplify-provider-selection-components#2280

Merged
yujonglee merged 11 commits intomainfrom
refactor/simplify-provider-selection-components
Dec 14, 2025
Merged

refactor/simplify-provider-selection-components#2280
yujonglee merged 11 commits intomainfrom
refactor/simplify-provider-selection-components

Conversation

@ComputelessComputer
Copy link
Collaborator

Overview

  • Simplified provider and model selection components
  • Added provider configuration status indicator
  • Restructured AI tab layout and removed header action prop

@netlify
Copy link

netlify bot commented Dec 13, 2025

Deploy Preview for hyprnote ready!

Name Link
🔨 Latest commit 197825d
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote/deploys/693e9ad79bc7c000085d4c4e
😎 Deploy Preview https://deploy-preview-2280--hyprnote.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify
Copy link

netlify bot commented Dec 13, 2025

Deploy Preview for hyprnote-storybook ready!

Name Link
🔨 Latest commit 197825d
🔍 Latest deploy log https://app.netlify.com/projects/hyprnote-storybook/deploys/693e9ad77496c10008db7ef8
😎 Deploy Preview https://deploy-preview-2280--hyprnote-storybook.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 13, 2025

📝 Walkthrough

Walkthrough

Replaces headerAction-driven AI header with an inline Transcription/Intelligence toggle and vertical layout; moves NonHyprProviderCard into shared module with provider-type props; removes HealthCheckForAvailability and headerAction props from STT/LLM/select components; adds missing-file early-return in JSON persister; UI/style tweaks.

Changes

Cohort / File(s) Summary
AI view layout
apps/desktop/src/components/main/body/ai.tsx
Replaces headerAction-based toggle with an inline header row of two buttons and a vertical flex layout: fixed header + scrollable content that renders STT or LLM panes.
LLM: entry & select
apps/desktop/src/components/settings/ai/llm/index.tsx, apps/desktop/src/components/settings/ai/llm/select.tsx
Removes headerAction prop and HealthCheckForAvailability; LLM and SelectProviderAndModel are now parameterless; select shows a red-bordered warning when provider or model is missing and keeps HealthCheckForConnection when configured.
LLM: configure
apps/desktop/src/components/settings/ai/llm/configure.tsx
Removes local NonHyprProviderCard implementation; uses shared NonHyprProviderCard with props (providerType="llm", providers, providerContext); cleans imports and adjusts heading size/styling.
STT: entry & select
apps/desktop/src/components/settings/ai/stt/index.tsx, apps/desktop/src/components/settings/ai/stt/select.tsx
Removes headerAction prop and HealthCheckForAvailability; STT and SelectProviderAndModel are now parameterless; select shows red-bordered warning when provider or model is missing and keeps HealthCheckForConnection when configured.
STT: configure
apps/desktop/src/components/settings/ai/stt/configure.tsx
Replaces local NonHyprProviderCard with shared import; passes providerType="stt", providers, and providerContext; cleans imports and adjusts heading/styling.
Shared provider UI & hooks
apps/desktop/src/components/settings/ai/shared/index.tsx
Adds NonHyprProviderCard component, ProviderType and ProviderConfig types, useIsProviderConfigured, and provider utilities; centralizes provider form, validation, billing gating, and storage handling; makes some previously-exported utilities internal.
Persistence error handling
apps/desktop/src/store/tinybase/jsonPersister.ts
In migrateKeysJsonToSettings catch block, returns false early (without logging) when error indicates missing file (ENOENT / "No such file or directory"); other errors still log and return false.
Sidebar banner styling
apps/desktop/src/components/main/sidebar/banner/component.tsx
Adjusted container padding; refactored dismiss button positioning, sizing, hover/opacity behavior; reduced dismiss icon size.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Verify all call sites removed/updated to stop passing headerAction to LLM/STT/select components.
  • Review shared NonHyprProviderCard and useIsProviderConfigured for correctness across stt and llm flows.
  • Confirm missing-provider/model warning UI and that HealthCheckForConnection still renders when configured.
  • Inspect form auto-submit, validation, and billing gating in shared provider card.
  • Check jsonPersister ENOENT early-return doesn't hide other filesystem errors.

Possibly related PRs

  • settings migration #2275 — modifies AI tab header/toggle behavior and may overlap UI changes in apps/desktop/src/components/main/body/ai.tsx.
  • AI setting custom #1586 — touches provider/shared components and NonHyprProviderCard; overlaps with extraction to shared/index.tsx.
  • AI Setting Final #1580 — adds/changes provider/shared functionality (useProvider/FormField/PROVIDERS) that directly relates to the new shared provider implementations.

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main refactoring work: simplifying provider selection components, which is central to the changeset across multiple files.
Description check ✅ Passed The description is related to the changeset, covering the main aspects: component simplification, status indicator addition, and layout restructuring with header action removal.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/simplify-provider-selection-components

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

🧹 Nitpick comments (1)
apps/desktop/src/components/settings/ai/stt/configure.tsx (1)

54-66: Consider edge cases in configuration detection.

The useIsProviderConfigured hook assumes all providers require an API key (line 61-62), but some providers (like "hyprnote" or custom endpoints) might not require one. This could lead to false negatives where properly configured providers appear as unconfigured.

Consider checking provider requirements before validating api_key:

 function useIsProviderConfigured(providerId: string) {
   const configuredProviders = keys.UI.useResultTable(
     keys.QUERIES.sttProviders,
     keys.STORE_ID,
   );
+  const providerDef = PROVIDERS.find((p) => p.id === providerId);
   const config = configuredProviders[providerId];
 
   if (!config || !config.api_key) {
     return false;
   }
+
+  // Some providers may not require an API key
+  if (providerDef?.apiKey && !config.api_key) {
+    return false;
+  }
 
   return true;
 }
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2545475 and 175e8fe.

📒 Files selected for processing (7)
  • apps/desktop/src/components/main/body/ai.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/configure.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/llm/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/select.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/stt/configure.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/stt/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/stt/select.tsx (3 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/main/body/ai.tsx
  • apps/desktop/src/components/settings/ai/llm/select.tsx
  • apps/desktop/src/components/settings/ai/llm/index.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/select.tsx
  • apps/desktop/src/components/settings/ai/stt/index.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:32:23.055Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:23.055Z
Learning: Applies to **/*.{ts,tsx} : If there are many classNames with conditional logic, use `cn` (import from `hypr/utils`). It is similar to `clsx`. Always pass an array and split by logical grouping.

Applied to files:

  • apps/desktop/src/components/settings/ai/stt/configure.tsx
📚 Learning: 2025-11-24T16:32:19.706Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:19.706Z
Learning: Applies to **/*.{ts,tsx} : If there are many classNames with conditional logic, use `cn` (import from `hypr/utils`), similar to `clsx`. Always pass an array and split by logical grouping.

Applied to files:

  • apps/desktop/src/components/settings/ai/stt/configure.tsx
🧬 Code graph analysis (7)
apps/desktop/src/components/main/body/ai.tsx (4)
extensions/shared/types/hypr-extension.d.ts (1)
  • Button (159-159)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/stt/index.tsx (1)
  • STT (4-11)
apps/desktop/src/components/settings/ai/llm/index.tsx (1)
  • LLM (4-11)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
  • SelectProviderAndModel (28-219)
apps/desktop/src/components/settings/ai/llm/index.tsx (2)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (32-188)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
  • SelectProviderAndModel (28-219)
apps/desktop/src/components/settings/ai/llm/configure.tsx (4)
apps/desktop/src/components/settings/ai/stt/configure.tsx (1)
  • ConfigureProviders (31-52)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
apps/desktop/src/components/settings/ai/stt/shared.tsx (1)
  • PROVIDERS (189-197)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/stt/configure.tsx (2)
apps/desktop/src/components/settings/ai/llm/configure.tsx (1)
  • ConfigureProviders (19-39)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (32-188)
apps/desktop/src/components/settings/ai/stt/index.tsx (2)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (32-188)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
  • SelectProviderAndModel (28-219)
⏰ 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). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
🔇 Additional comments (10)
apps/desktop/src/components/main/body/ai.tsx (1)

57-87: LGTM! Clean refactor to inline toggle buttons.

The new layout successfully removes the headerAction prop pattern and uses inline toggle buttons with proper conditional styling. The cn usage follows the coding guidelines by passing arrays and splitting by logical grouping.

apps/desktop/src/components/settings/ai/llm/index.tsx (1)

4-11: LGTM! Clean simplification.

The component is now properly simplified by removing the headerAction prop and HealthCheckForAvailability dependency, resulting in a cleaner composition pattern.

apps/desktop/src/components/settings/ai/stt/select.tsx (2)

28-28: LGTM! Signature simplified.

The removal of the headerAction prop aligns with the PR's objective to simplify provider selection components.


208-215: LGTM! Clear user feedback for missing configuration.

The warning UI provides clear feedback when transcription model configuration is incomplete. This pattern is consistent with the LLM select component.

apps/desktop/src/components/settings/ai/stt/index.tsx (1)

4-11: LGTM! Consistent simplification.

The component now mirrors the LLM component structure by removing headerAction and health check dependencies, maintaining consistency across the codebase.

apps/desktop/src/components/settings/ai/stt/configure.tsx (1)

108-111: LGTM! Clear visual distinction for configuration state.

The conditional border styling provides clear visual feedback about whether a provider is configured. The use of cn with arrays follows the coding guidelines.

apps/desktop/src/components/settings/ai/llm/configure.tsx (2)

41-58: Good implementation of configuration detection.

The useIsProviderConfigured hook properly checks provider requirements before validating the API key (lines 53-55), which handles providers that don't require API keys correctly. This is more robust than the STT version.


109-112: LGTM! Consistent configuration state visualization.

The conditional border styling matches the pattern in the STT configure component, maintaining consistency across the codebase. The use of cn with arrays follows the coding guidelines.

apps/desktop/src/components/settings/ai/llm/select.tsx (2)

32-32: LGTM! Signature simplified.

The removal of the headerAction prop is consistent with the refactoring pattern applied across both LLM and STT components.


177-184: LGTM! Clear user feedback for missing configuration.

The warning UI provides clear, context-specific feedback when language model configuration is incomplete. This mirrors the pattern in the STT select component, maintaining consistency.

@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch 2 times, most recently from b7011bf to e7756e6 Compare December 14, 2025 01:37
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 (3)
apps/desktop/src/components/main/body/ai.tsx (1)

59-82: Consider extracting toggle button logic to reduce duplication.

The two toggle buttons share nearly identical structure and styling, differing only in their tab key, icon, and label. This could be refactored into a mapped structure for better maintainability.

Example refactor:

+      const tabs = [
+        { key: "transcription" as const, icon: AudioLinesIcon, label: "Transcription" },
+        { key: "intelligence" as const, icon: SparklesIcon, label: "Intelligence" },
+      ];
+
       <div className="flex gap-1 px-6 pt-6 pb-2">
-        <Button
-          variant="ghost"
-          size="sm"
-          onClick={() => setActiveTab("transcription")}
-          className={cn([
-            "gap-1.5 h-7 px-2 border border-transparent",
-            activeTab === "transcription" && "bg-neutral-100 border-neutral-200",
-          ])}
-        >
-          <AudioLinesIcon size={14} />
-          <span className="text-xs">Transcription</span>
-        </Button>
-        <Button
-          variant="ghost"
-          size="sm"
-          onClick={() => setActiveTab("intelligence")}
-          className={cn([
-            "gap-1.5 h-7 px-2 border border-transparent",
-            activeTab === "intelligence" && "bg-neutral-100 border-neutral-200",
-          ])}
-        >
-          <SparklesIcon size={14} />
-          <span className="text-xs">Intelligence</span>
-        </Button>
+        {tabs.map(({ key, icon: Icon, label }) => (
+          <Button
+            key={key}
+            variant="ghost"
+            size="sm"
+            onClick={() => setActiveTab(key)}
+            className={cn([
+              "gap-1.5 h-7 px-2 border border-transparent",
+              activeTab === key && "bg-neutral-100 border-neutral-200",
+            ])}
+          >
+            <Icon size={14} />
+            <span className="text-xs">{label}</span>
+          </Button>
+        ))}
       </div>
apps/desktop/src/components/settings/ai/stt/select.tsx (1)

28-218: Consider extracting shared logic between STT and LLM select components.

Based on the relevant code snippets, both apps/desktop/src/components/settings/ai/stt/select.tsx and apps/desktop/src/components/settings/ai/llm/select.tsx share nearly identical structure:

  • Same function signature (no props)
  • Same heading "Model being used"
  • Same conditional background color logic
  • Same warning UI pattern when provider/model are missing
  • Similar form handling and rendering logic

The only differences are the config keys (current_stt_* vs current_llm_*), warning text, and provider-specific queries. This could be refactored into a shared component that accepts a type parameter or configuration object.

Note: This is a broader architectural improvement that could be addressed in a follow-up PR.

apps/desktop/src/components/settings/ai/llm/configure.tsx (1)

189-191: Consider applying consistent configuration status indicator to HyprProviderCard.

NonHyprProviderCard uses isConfigured to show visual status (dashed vs. solid border), but HyprProviderCard always shows a dashed border regardless of configuration state. If the Hyprnote provider can also be configured/unconfigured, consider applying the same visual treatment for consistency.

If this distinction is intentional (e.g., Hyprnote is always available or has different semantics), this can be safely ignored.

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 175e8fe and b7011bf.

📒 Files selected for processing (7)
  • apps/desktop/src/components/main/body/ai.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/configure.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/llm/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/select.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/stt/configure.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/stt/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/stt/select.tsx (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/components/settings/ai/stt/index.tsx
  • apps/desktop/src/components/settings/ai/llm/select.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/settings/ai/llm/index.tsx
  • apps/desktop/src/components/settings/ai/stt/select.tsx
  • apps/desktop/src/components/main/body/ai.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
🧬 Code graph analysis (2)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (32-188)
apps/desktop/src/components/main/body/ai.tsx (4)
extensions/shared/types/hypr-extension.d.ts (1)
  • Button (159-159)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/stt/index.tsx (1)
  • STT (4-11)
apps/desktop/src/components/settings/ai/llm/index.tsx (1)
  • LLM (4-11)
⏰ 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). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: fmt
🔇 Additional comments (7)
apps/desktop/src/components/main/body/ai.tsx (1)

57-87: LGTM! Clean refactor with proper utility usage.

The vertical layout with inline toggle buttons effectively replaces the headerAction pattern. The use of cn with array syntax follows the coding guidelines, and the conditional rendering logic is straightforward.

apps/desktop/src/components/settings/ai/llm/index.tsx (1)

4-10: LGTM! Clean simplification of component.

The removal of the headerAction prop and HealthCheckForAvailability aligns with the PR's goal to simplify provider selection components. The component now has a cleaner interface and consistent structure with the STT equivalent.

apps/desktop/src/components/settings/ai/stt/select.tsx (2)

28-75: LGTM! Simplified component signature.

The removal of the headerAction prop and addition of a static heading simplifies the component interface and aligns with the broader refactor to remove headerAction dependencies across AI components.


76-215: Good UX with clear visual feedback.

The conditional background color and warning message provide excellent user feedback when configuration is incomplete. The implementation is clean and the warning text is specific to transcription use case.

apps/desktop/src/components/settings/ai/llm/configure.tsx (3)

15-15: LGTM! Supporting changes for configuration status feature.

The keys import supports the new useIsProviderConfigured hook, and the heading size adjustment improves visual hierarchy.

Also applies to: 22-22


68-68: Good visual indicator for provider configuration status.

The conditional border styling (dashed for unconfigured, solid for configured) effectively communicates provider setup status to users, aligning with the PR's goal to add provider configuration status indicators.

Also applies to: 109-112


41-58: No changes needed. Empty strings are already properly handled by the current logic.

The hook's checks using !config.base_url and !config.api_key already catch empty strings because empty strings are falsy in JavaScript. When either value is an empty string, the negation returns true and the function returns false as intended. Additionally, the aiProviderSchema enforces that base_url is a valid URL with z.url().min(1), preventing empty strings from being stored in the first place.

@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch from e7756e6 to 9870909 Compare December 14, 2025 04:06
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

📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e7756e6 and 9870909.

📒 Files selected for processing (8)
  • apps/desktop/src/components/main/body/ai.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/configure.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/llm/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/select.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/stt/configure.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/stt/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/stt/select.tsx (3 hunks)
  • apps/desktop/src/store/tinybase/jsonPersister.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/store/tinybase/jsonPersister.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/store/tinybase/jsonPersister.ts
  • apps/desktop/src/components/settings/ai/stt/index.tsx
  • apps/desktop/src/components/settings/ai/llm/index.tsx
  • apps/desktop/src/components/settings/ai/stt/select.tsx
  • apps/desktop/src/components/settings/ai/llm/select.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/main/body/ai.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:32:23.055Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:23.055Z
Learning: Applies to **/*.{ts,tsx} : If there are many classNames with conditional logic, use `cn` (import from `hypr/utils`). It is similar to `clsx`. Always pass an array and split by logical grouping.

Applied to files:

  • apps/desktop/src/components/settings/ai/stt/configure.tsx
📚 Learning: 2025-11-24T16:32:19.706Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:19.706Z
Learning: Applies to **/*.{ts,tsx} : If there are many classNames with conditional logic, use `cn` (import from `hypr/utils`), similar to `clsx`. Always pass an array and split by logical grouping.

Applied to files:

  • apps/desktop/src/components/settings/ai/stt/configure.tsx
🧬 Code graph analysis (5)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (31-187)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
  • SelectProviderAndModel (27-218)
apps/desktop/src/components/settings/ai/llm/configure.tsx (3)
apps/desktop/src/components/settings/ai/stt/configure.tsx (1)
  • ConfigureProviders (30-51)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/stt/configure.tsx (1)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/main/body/ai.tsx (4)
extensions/shared/types/hypr-extension.d.ts (1)
  • Button (159-159)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/stt/index.tsx (1)
  • STT (4-11)
apps/desktop/src/components/settings/ai/llm/index.tsx (1)
  • LLM (4-11)
⏰ 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). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: fmt
🔇 Additional comments (13)
apps/desktop/src/store/tinybase/jsonPersister.ts (1)

180-186: LGTM!

The early return for file-not-found errors is appropriate for a migration function. This reduces log noise when the legacy file doesn't exist, which is the expected state for most users.

apps/desktop/src/components/settings/ai/stt/configure.tsx (2)

33-33: LGTM!

The heading size increase improves visual hierarchy and is consistent with the LLM configure screen.


107-110: LGTM!

The conditional border styling effectively communicates configuration status. The use of cn with array grouping follows the coding guidelines.

apps/desktop/src/components/settings/ai/llm/configure.tsx (3)

22-22: LGTM!

The heading size increase improves visual hierarchy.


41-58: LGTM!

The configuration validation logic correctly:

  1. Validates base_url presence for all providers
  2. Conditionally validates api_key only for providers that require it (based on providerDef?.apiKey)

This approach handles both API-based and local providers correctly.


109-112: LGTM!

The conditional border styling effectively communicates configuration status, and the use of cn with array grouping follows the coding guidelines.

apps/desktop/src/components/settings/ai/stt/index.tsx (1)

4-10: LGTM!

The removal of the headerAction prop simplifies the component interface and aligns with the refactored AI tab layout where header actions are now handled inline.

apps/desktop/src/components/main/body/ai.tsx (1)

57-88: LGTM!

The refactored inline header with toggle buttons is a good improvement:

  1. Cleaner component interface without headerAction prop drilling
  2. Clear visual indication of active tab with border styling
  3. Proper use of cn with array grouping per coding guidelines
  4. Appropriate use of Button component with ghost variant for toggle behavior
apps/desktop/src/components/settings/ai/llm/index.tsx (1)

4-10: LGTM!

The removal of the headerAction prop simplifies the component interface and aligns with the refactored AI tab layout.

apps/desktop/src/components/settings/ai/stt/select.tsx (2)

27-27: LGTM!

The removal of the headerAction prop simplifies the component interface and aligns with the inline header approach in the AI tab.


207-214: LGTM!

The missing-model warning is a good UX improvement that clearly communicates to users when configuration is incomplete. The red border styling appropriately conveys urgency while the message clearly explains the impact.

apps/desktop/src/components/settings/ai/llm/select.tsx (2)

31-31: LGTM!

The removal of the headerAction prop simplifies the component interface and aligns with the refactored AI tab layout.


176-183: LGTM!

The missing-model warning effectively communicates the impact of incomplete configuration and provides clear guidance to users.

@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch from 69c7875 to 10a7802 Compare December 14, 2025 05:00
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

Caution

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

⚠️ Outside diff range comments (1)
apps/desktop/src/components/main/sidebar/banner/component.tsx (1)

16-38: Dismiss button is effectively invisible for keyboard users (add focus-visible styles).

Because the button starts at opacity-0 and only becomes visible via group-hover, tabbing to it won’t reveal it. Add focus-visible: (or focus:) opacity/background styles so keyboard users can discover it.

           <Button
             onClick={onDismiss}
             size="icon"
             variant="ghost"
             aria-label="Dismiss banner"
             className={cn([
               "absolute top-1.5 right-1.5 size-6",
               "opacity-0 group-hover:opacity-50 hover:!opacity-100",
               "hover:bg-neutral-200",
+              "focus-visible:opacity-100 focus-visible:bg-neutral-200",
               "transition-all duration-200",
             ])}
           >
             <X className="w-3.5 h-3.5" />
           </Button>
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 10a7802 and 69fe9c9.

📒 Files selected for processing (4)
  • apps/desktop/src/components/main/sidebar/banner/component.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/llm/configure.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/shared/index.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/stt/configure.tsx (2 hunks)
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/main/sidebar/banner/component.tsx
  • apps/desktop/src/components/settings/ai/shared/index.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:32:23.055Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:23.055Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.

Applied to files:

  • apps/desktop/src/components/settings/ai/shared/index.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
📚 Learning: 2025-11-24T16:32:19.706Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:19.706Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) for 99% of cases instead of setError and similar patterns.

Applied to files:

  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
🧬 Code graph analysis (3)
apps/desktop/src/components/main/sidebar/banner/component.tsx (1)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/llm/configure.tsx (2)
apps/desktop/src/components/settings/ai/shared/index.tsx (1)
  • NonHyprProviderCard (79-195)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
apps/desktop/src/components/settings/ai/stt/configure.tsx (4)
apps/desktop/src/components/settings/ai/llm/configure.tsx (1)
  • ConfigureProviders (14-40)
apps/desktop/src/components/settings/ai/shared/index.tsx (1)
  • NonHyprProviderCard (79-195)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
apps/desktop/src/components/settings/ai/stt/shared.tsx (1)
  • PROVIDERS (189-197)
⏰ 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). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: fmt
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
🔇 Additional comments (2)
apps/desktop/src/components/settings/ai/llm/configure.tsx (1)

11-38: Nice simplification: shared NonHyprProviderCard + explicit providerType/providerContext.

apps/desktop/src/components/settings/ai/stt/configure.tsx (1)

25-55: Good alignment with LLM: shared NonHyprProviderCard usage is consistent.

@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch from 69fe9c9 to f3c27cc Compare December 14, 2025 05:46
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)
apps/desktop/src/store/tinybase/jsonPersister.ts (1)

179-186: Consider checking error code instead of string matching.

String matching error messages can be fragile and locale-dependent. If the error object has a code property, check it directly.

   } catch (error) {
-    const errorStr = String(error);
-    if (
-      errorStr.includes("No such file or directory") ||
-      errorStr.includes("ENOENT")
-    ) {
+    if (
+      error &&
+      typeof error === "object" &&
+      "code" in error &&
+      error.code === "ENOENT"
+    ) {
       return false;
     }
     console.error("[migrateKeysJsonToSettings] error:", error);
     return false;
   }
apps/desktop/src/components/settings/ai/shared/index.tsx (1)

104-104: Consider making API key field conditional for STT providers.

Line 104 always shows the API key field for STT providers (providerType === "stt"), but this should respect the config.apiKey flag like LLM providers do. Local providers (lmstudio, ollama) don't need API keys.

-  const showApiKey = providerType === "stt" || config.apiKey;
+  const showApiKey = config.apiKey;
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 69fe9c9 and f3c27cc.

📒 Files selected for processing (10)
  • apps/desktop/src/components/main/body/ai.tsx (1 hunks)
  • apps/desktop/src/components/main/sidebar/banner/component.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/llm/configure.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/llm/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/select.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/shared/index.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/stt/configure.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/stt/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/stt/select.tsx (3 hunks)
  • apps/desktop/src/store/tinybase/jsonPersister.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/desktop/src/components/settings/ai/llm/index.tsx
  • apps/desktop/src/components/settings/ai/stt/index.tsx
  • apps/desktop/src/components/main/sidebar/banner/component.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/store/tinybase/jsonPersister.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/store/tinybase/jsonPersister.ts
  • apps/desktop/src/components/settings/ai/stt/select.tsx
  • apps/desktop/src/components/main/body/ai.tsx
  • apps/desktop/src/components/settings/ai/llm/select.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/settings/ai/shared/index.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:32:23.055Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:23.055Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.

Applied to files:

  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/settings/ai/shared/index.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
📚 Learning: 2025-11-24T16:32:19.706Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:19.706Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) for 99% of cases instead of setError and similar patterns.

Applied to files:

  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
🧬 Code graph analysis (5)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (31-187)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
  • SelectProviderAndModel (27-218)
apps/desktop/src/components/settings/ai/stt/configure.tsx (4)
apps/desktop/src/components/settings/ai/llm/configure.tsx (1)
  • ConfigureProviders (14-40)
apps/desktop/src/components/settings/ai/shared/index.tsx (1)
  • NonHyprProviderCard (84-200)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
apps/desktop/src/components/settings/ai/stt/shared.tsx (1)
  • PROVIDERS (189-197)
apps/desktop/src/components/settings/ai/shared/index.tsx (3)
apps/desktop/src/billing.tsx (1)
  • useBillingAccess (66-74)
packages/store/src/schema-internal.ts (2)
  • AIProvider (43-43)
  • aiProviderSchema (29-41)
extensions/shared/types/hypr-extension.d.ts (3)
  • AccordionItem (120-120)
  • AccordionTrigger (121-121)
  • AccordionContent (119-119)
apps/desktop/src/components/settings/ai/llm/configure.tsx (2)
apps/desktop/src/components/settings/ai/shared/index.tsx (1)
  • NonHyprProviderCard (84-200)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
⏰ 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). (7)
  • GitHub Check: Redirect rules - hyprnote-storybook
  • GitHub Check: Header rules - hyprnote-storybook
  • GitHub Check: Pages changed - hyprnote-storybook
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: fmt
🔇 Additional comments (10)
apps/desktop/src/components/main/body/ai.tsx (1)

57-88: LGTM!

The refactored tab layout with inline buttons and content pane is clean and follows the coding guidelines. The use of cn with arrays for conditional styling is appropriate.

apps/desktop/src/components/settings/ai/stt/select.tsx (2)

27-27: LGTM!

The removal of the headerAction prop aligns with the PR's goal to simplify the component interface and centralize provider UI logic.


207-214: LGTM!

The missing-model warning provides clear user feedback and is consistent with the LLM implementation pattern.

apps/desktop/src/components/settings/ai/stt/configure.tsx (1)

25-25: LGTM!

The migration to the shared NonHyprProviderCard component successfully centralizes provider configuration UI and eliminates code duplication. The props passed (config, providerType, providers, providerContext) match the expected signature.

Also applies to: 43-49

apps/desktop/src/components/settings/ai/llm/select.tsx (2)

31-31: LGTM!

Removing the headerAction prop simplifies the component interface and aligns with the broader refactoring to centralize provider UI.


176-183: LGTM!

The missing-model warning provides clear, contextual feedback to users and maintains consistency with the STT implementation.

apps/desktop/src/components/settings/ai/llm/configure.tsx (1)

11-11: LGTM!

Successfully migrated to the shared NonHyprProviderCard, eliminating code duplication and centralizing provider configuration logic. The component usage is consistent with the STT implementation.

Also applies to: 28-34

apps/desktop/src/components/settings/ai/shared/index.tsx (3)

26-30: LGTM!

The composite key approach (type:id) effectively prevents configuration collisions between STT and LLM providers with the same id. This addresses the major issue flagged in previous reviews.


106-123: LGTM!

The form setup with auto-submit on change and validation via aiProviderSchema follows the coding guidelines to use useForm from TanStack Form. The microtask queuing for submit prevents race conditions.


243-260: LGTM!

The updated useProvider hook correctly uses composite keys to store and retrieve provider configurations, preventing data collisions between STT and LLM providers.

@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch from f3c27cc to adcf609 Compare December 14, 2025 05:57
@ComputelessComputer ComputelessComputer removed the request for review from yujonglee December 14, 2025 05:58
@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch from adcf609 to 575d78e Compare December 14, 2025 06:10
@ComputelessComputer ComputelessComputer force-pushed the refactor/simplify-provider-selection-components branch from 575d78e to eeb6644 Compare December 14, 2025 06:11
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)
apps/desktop/src/components/settings/ai/shared/index.tsx (2)

238-250: Config collision: ai_providers rows keyed by id alone while queries filter by type.

The useProvider hook persists to ai_providers using only the provider id as the row key (lines 239, 241), but useIsProviderConfigured queries filter by provider type ("stt" vs "llm" at lines 44-47). This means configuring "openai" for STT (storing type: "stt") and then configuring "openai" for LLM (storing type: "llm") will overwrite the same row, silently losing the STT configuration.

The fix requires using a composite key that includes both type and id (e.g., ${providerType}:${id}) in:

  1. useProvider persistence (lines 239-245)
  2. configuredProviders lookups (line 54)
  3. Any other code that references provider rows by id

This ensures STT and LLM configs for the same provider id don't collide.


60-66: STT validation unconditionally requires API key for all providers.

Lines 64-65 always require an api_key for STT providers, but some providers like lmstudio and ollama don't require API keys (they have apiKey: false in their definitions). This prevents users from configuring local STT providers.

Apply this diff to make the API key requirement conditional:

   if (providerType === "stt") {
-    if (!providerDef?.baseUrl && !config.base_url) {
+    if (providerDef?.baseUrl == null && !config.base_url) {
       return false;
     }
-    if (!config.api_key) {
+    if (providerDef?.apiKey && !config.api_key) {
       return false;
     }
   } else {
🧹 Nitpick comments (1)
apps/desktop/src/store/tinybase/jsonPersister.ts (1)

179-186: Consider type-safe error handling instead of string matching.

The current implementation uses String(error) and string matching to detect missing-file errors. This approach is fragile and loses type information.

Apply this diff for more idiomatic TypeScript error handling:

  } catch (error) {
-    const errorStr = String(error);
-    if (
-      errorStr.includes("No such file or directory") ||
-      errorStr.includes("ENOENT")
-    ) {
-      return false;
-    }
+    if (error instanceof Error) {
+      // Check for filesystem "not found" errors
+      if (error.message.includes("ENOENT") || 
+          error.message.includes("No such file or directory")) {
+        return false;
+      }
+    }
     console.error("[migrateKeysJsonToSettings] error:", error);
     return false;
   }

This approach:

  • Preserves type information by checking error instanceof Error
  • Accesses the message property safely
  • Falls through to log unexpected error types
📜 Review details

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f3c27cc and a3aab6b.

📒 Files selected for processing (10)
  • apps/desktop/src/components/main/body/ai.tsx (1 hunks)
  • apps/desktop/src/components/main/sidebar/banner/component.tsx (2 hunks)
  • apps/desktop/src/components/settings/ai/llm/configure.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/llm/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/llm/select.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/shared/index.tsx (4 hunks)
  • apps/desktop/src/components/settings/ai/stt/configure.tsx (3 hunks)
  • apps/desktop/src/components/settings/ai/stt/index.tsx (1 hunks)
  • apps/desktop/src/components/settings/ai/stt/select.tsx (3 hunks)
  • apps/desktop/src/store/tinybase/jsonPersister.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/desktop/src/components/settings/ai/llm/select.tsx
  • apps/desktop/src/components/main/body/ai.tsx
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx}: Avoid creating a bunch of types/interfaces if they are not shared. Especially for function props, just inline them instead.
Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.
If there are many classNames with conditional logic, use cn (import from @hypr/utils). It is similar to clsx. Always pass an array and split by logical grouping.
Use motion/react instead of framer-motion.

Files:

  • apps/desktop/src/components/settings/ai/stt/select.tsx
  • apps/desktop/src/components/settings/ai/stt/index.tsx
  • apps/desktop/src/store/tinybase/jsonPersister.ts
  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/llm/index.tsx
  • apps/desktop/src/components/settings/ai/shared/index.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
  • apps/desktop/src/components/main/sidebar/banner/component.tsx
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Agent implementations should use TypeScript and follow the established architectural patterns defined in the agent framework
Agent communication should use defined message protocols and interfaces

Files:

  • apps/desktop/src/store/tinybase/jsonPersister.ts
🧠 Learnings (2)
📚 Learning: 2025-11-24T16:32:23.055Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:23.055Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) instead for 99% of cases. Avoid patterns like setError.

Applied to files:

  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/shared/index.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
📚 Learning: 2025-11-24T16:32:19.706Z
Learnt from: CR
Repo: fastrepl/hyprnote PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T16:32:19.706Z
Learning: Applies to **/*.{ts,tsx} : Never do manual state management for form/mutation. Use useForm (from tanstack-form) and useQuery/useMutation (from tanstack-query) for 99% of cases instead of setError and similar patterns.

Applied to files:

  • apps/desktop/src/components/settings/ai/llm/configure.tsx
  • apps/desktop/src/components/settings/ai/stt/configure.tsx
🧬 Code graph analysis (6)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (31-187)
apps/desktop/src/components/settings/ai/stt/index.tsx (2)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (31-187)
apps/desktop/src/components/settings/ai/stt/select.tsx (1)
  • SelectProviderAndModel (27-218)
apps/desktop/src/components/settings/ai/llm/configure.tsx (4)
apps/desktop/src/components/settings/ai/shared/index.tsx (1)
  • NonHyprProviderCard (79-195)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
apps/desktop/src/components/settings/ai/stt/shared.tsx (1)
  • PROVIDERS (189-197)
packages/utils/src/cn.ts (1)
  • cn (20-22)
apps/desktop/src/components/settings/ai/llm/index.tsx (1)
apps/desktop/src/components/settings/ai/llm/select.tsx (1)
  • SelectProviderAndModel (31-187)
apps/desktop/src/components/settings/ai/stt/configure.tsx (3)
apps/desktop/src/components/settings/ai/shared/index.tsx (1)
  • NonHyprProviderCard (79-195)
apps/desktop/src/components/settings/ai/llm/shared.tsx (1)
  • PROVIDERS (23-96)
apps/desktop/src/components/settings/ai/stt/shared.tsx (1)
  • PROVIDERS (189-197)
apps/desktop/src/components/main/sidebar/banner/component.tsx (1)
packages/utils/src/cn.ts (1)
  • cn (20-22)
🪛 Biome (2.1.2)
apps/desktop/src/components/settings/ai/llm/configure.tsx

[error] 60-60: Unexpected constant condition.

(lint/correctness/noConstantCondition)

apps/desktop/src/components/settings/ai/stt/configure.tsx

[error] 81-81: Unexpected constant condition.

(lint/correctness/noConstantCondition)

⏰ 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). (7)
  • GitHub Check: Redirect rules - hyprnote
  • GitHub Check: Header rules - hyprnote
  • GitHub Check: Pages changed - hyprnote
  • GitHub Check: desktop_ci (macos, depot-macos-14)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-24.04-8)
  • GitHub Check: desktop_ci (linux, depot-ubuntu-22.04-8)
  • GitHub Check: fmt
🔇 Additional comments (8)
apps/desktop/src/components/main/sidebar/banner/component.tsx (3)

16-16: LGTM: Padding refinement.

The uniform padding simplifies the spacing and aligns with the UI polish objectives of this PR.


30-35: LGTM: Well-structured hover behavior.

The dismiss button styling correctly uses cn with arrays and logical grouping per coding guidelines. The opacity cascade (hidden → group-hover semi-transparent → hover fully visible) provides good UX, and the !important ensures direct hover takes precedence.


37-37: LGTM: Icon sizing.

The reduced icon size provides better visual balance within the size-6 button container.

apps/desktop/src/components/settings/ai/stt/select.tsx (1)

27-27: LGTM! Clean refactor removing headerAction prop.

The removal of the headerAction prop and addition of the missing-model warning UI improves the UX by providing clear feedback when configuration is incomplete.

Also applies to: 74-74, 207-214

apps/desktop/src/components/settings/ai/llm/index.tsx (1)

4-10: LGTM! Simplified component signature.

Removing the headerAction prop streamlines the component API and aligns with the new UI layout.

apps/desktop/src/components/settings/ai/stt/index.tsx (1)

4-10: LGTM! Consistent with LLM refactor.

The changes mirror the LLM component updates, maintaining consistency across STT and LLM configuration flows.

apps/desktop/src/components/settings/ai/llm/configure.tsx (1)

28-34: LGTM! Clean integration with shared NonHyprProviderCard.

The updated usage of NonHyprProviderCard with providerType, providers, and providerContext props properly delegates provider configuration to the shared component.

apps/desktop/src/components/settings/ai/stt/configure.tsx (1)

43-49: LGTM! Consistent integration with shared provider card.

The STT configuration now uses the shared NonHyprProviderCard with appropriate providerType="stt", maintaining consistency with the LLM implementation.

@yujonglee yujonglee merged commit e895fbb into main Dec 14, 2025
12 of 15 checks passed
@yujonglee yujonglee deleted the refactor/simplify-provider-selection-components branch December 14, 2025 11:09
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