Skip to content

Refactor provider settings to declarative metadata#2452

Merged
juliusmarminge merged 6 commits into
mainfrom
t3code/declarative-provider-settings
May 2, 2026
Merged

Refactor provider settings to declarative metadata#2452
juliusmarminge merged 6 commits into
mainfrom
t3code/declarative-provider-settings

Conversation

@juliusmarminge
Copy link
Copy Markdown
Member

@juliusmarminge juliusmarminge commented May 2, 2026

Summary

  • Replaced per-surface hardcoded provider setting fields with shared declarative provider definitions.
  • Added a generic ProviderSettingsForm that renders text, password, textarea, and switch controls for both the add-instance dialog and provider cards.
  • Preserved opaque provider config keys while tightening field read/write helpers and adding unit coverage for field derivation and config normalization.

Testing

  • Not run

Note

Medium Risk
Refactors how provider instance configs are rendered and normalized, and changes contract schemas/annotations that multiple surfaces may rely on. Risk is mainly UI/config persistence regressions (fields hidden/ordered differently, empty values omitted) rather than security.

Overview
Provider instance configuration is now rendered from declarative, schema-annotated metadata instead of hardcoded per-surface field arrays, via a new reusable ProviderSettingsForm used in both the add-instance dialog and instance cards.

Driver metadata in providerDriverMeta.ts is updated to reference typed Effect Schemas (CodexSettings, ClaudeSettings, CursorSettings, OpenCodeSettings) and the contracts add schema annotations for field labels/descriptions/placeholders, ordering, hidden fields, and empty-value persistence rules. The add-instance flow switches to per-driver config drafts, and save/update logic now round-trips unknown config keys while omitting empty fields according to clearWhenEmpty, with unit tests covering derivation and normalization helpers.

Reviewed by Cursor Bugbot for commit a4ac493. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Refactor provider settings to use schema-driven declarative metadata

  • Replaces hand-coded fields arrays on driver definitions with settingsSchema annotations in packages/contracts/src/settings.ts, covering titles, descriptions, placeholders, control types (text, password, textarea, switch), and clearWhenEmpty policies.
  • Introduces a new ProviderSettingsForm.tsx component that derives and renders form fields from the schema annotations, supporting card and dialog visual variants.
  • Updates both AddProviderInstanceDialog and ProviderInstanceCard to use ProviderSettingsForm instead of manual field rendering; per-driver config drafts are preserved when switching tabs in the dialog.
  • SettingsPanels now derives its provider list from DRIVER_OPTIONS rather than a separate hard-coded array.
  • Behavioral Change: empty field values are now omitted from saved configs according to per-field clearWhenEmpty policy rather than being stored as empty strings.

Macroscope summarized a4ac493.

- Centralize provider field metadata and rendering
- Reuse the same form in add-instance and instance cards
- Add coverage for schema-driven field derivation and config merging
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 2, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3ae4d89a-cd4d-487a-8d17-1f6208f4cab3

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch t3code/declarative-provider-settings

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

@github-actions github-actions Bot added size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. labels May 2, 2026
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes May 2, 2026
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp Bot commented May 2, 2026

Approvability

Verdict: Approved

Mechanical refactor moving provider settings field definitions from hardcoded UI arrays to declarative schema annotations. No runtime behavior changes - same fields render with same values. The unresolved comments identify minor UI polish issues, not correctness or security concerns.

You can customize Macroscope's approvability policy. Learn more.

- Derive form labels and descriptions from contract annotations
- Simplify provider metadata and reuse shared empty config draft
- Cover annotated field metadata in settings form tests
@macroscopeapp macroscopeapp Bot dismissed their stale review May 2, 2026 01:55

Dismissing prior approval to re-evaluate cc102a0

{description}
</label>
</FieldFrame>
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Textarea in card variant bypasses DraftInput buffering pattern

Low Severity

The textarea control type in the card variant uses a standard Textarea with onChange (firing on every keystroke), while the text and password controls correctly use DraftInput which buffers keystrokes and commits only on blur. DraftInput was specifically designed to prevent per-keystroke settings saves and server round-trips. If a textarea field is added to a provider's card settings, each keystroke will trigger updateConfigonUpdate → full settings propagation, causing exactly the lag DraftInput was built to avoid. The card variant's textarea path needs an equivalent buffered input component to be consistent with the other controls.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit cc102a0. Configure here.

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes May 2, 2026
- Derive provider settings UI from schema annotations
- Remove separate provider UI metadata and hide internal fields in contracts
@macroscopeapp macroscopeapp Bot dismissed their stale review May 2, 2026 02:04

Dismissing prior approval to re-evaluate f6731f0

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Autofix Details

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Boolean fields ignore clearWhenEmpty semantics
    • Added a check in the boolean path of nextProviderConfigWithFieldValue to delete the key when clearWhenEmpty is "omit" and the value is false (the default), mirroring the existing string field behavior.

Create PR

Or push these changes by commenting:

@cursor push 944381290b
Preview (944381290b)
diff --git a/apps/web/src/components/settings/ProviderSettingsForm.tsx b/apps/web/src/components/settings/ProviderSettingsForm.tsx
--- a/apps/web/src/components/settings/ProviderSettingsForm.tsx
+++ b/apps/web/src/components/settings/ProviderSettingsForm.tsx
@@ -109,7 +109,11 @@
     config !== null && typeof config === "object" ? { ...(config as Record<string, unknown>) } : {};
 
   if (typeof value === "boolean") {
-    base[field.key] = value;
+    if (field.clearWhenEmpty === "omit" && value === false) {
+      delete base[field.key];
+    } else {
+      base[field.key] = value;
+    }
     return Object.keys(base).length > 0 ? base : undefined;
   }

You can send follow-ups to the cloud agent here.

Comment thread apps/web/src/components/settings/ProviderSettingsForm.tsx
macroscopeapp[bot]
macroscopeapp Bot previously approved these changes May 2, 2026
- Add schema-level ordering metadata for provider settings
- Derive field order declaratively in the web form
- Remove per-field order annotations from settings definitions
@macroscopeapp macroscopeapp Bot dismissed their stale review May 2, 2026 05:00

Dismissing prior approval to re-evaluate e5b9956

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes May 2, 2026
- drop false switch values when settings declare `clearWhenEmpty: omit`
- add coverage for boolean field read/write behavior
@macroscopeapp macroscopeapp Bot dismissed their stale review May 2, 2026 20:01

Dismissing prior approval to re-evaluate 77e6873

Copy link
Copy Markdown
Contributor

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

There are 2 total unresolved issues (including 1 from previous review).

Fix All in Cursor

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Dialog variant loses spacing between label, input, description
    • Moved 'grid gap-1.5' from the FieldFrame wrapper div to the element itself for the dialog variant, so the CSS grid gap correctly spaces the label text, input, and description children.

Create PR

Or push these changes by commenting:

@cursor push ef8ded46ad
Preview (ef8ded46ad)
diff --git a/apps/web/src/components/settings/ProviderSettingsForm.tsx b/apps/web/src/components/settings/ProviderSettingsForm.tsx
--- a/apps/web/src/components/settings/ProviderSettingsForm.tsx
+++ b/apps/web/src/components/settings/ProviderSettingsForm.tsx
@@ -202,7 +202,7 @@
   if (field.control === "textarea") {
     return (
       <FieldFrame variant={variant}>
-        <label htmlFor={inputId} className={cn(variant === "card" && "block")}>
+        <label htmlFor={inputId} className={cn(variant === "card" ? "block" : "grid gap-1.5")}>
           {label}
           <Textarea
             id={inputId}
@@ -223,7 +223,7 @@
   const type = field.control === "password" ? "password" : undefined;
   return (
     <FieldFrame variant={variant}>
-      <label htmlFor={inputId} className={cn(variant === "card" && "block")}>
+      <label htmlFor={inputId} className={cn(variant === "card" ? "block" : "grid gap-1.5")}>
         {label}
         {variant === "card" ? (
           <DraftInput

You can send follow-ups to the cloud agent here.

Reviewed by Cursor Bugbot for commit 77e6873. Configure here.

return <div className="border-t border-border/60 px-4 py-3 sm:px-5">{props.children}</div>;
}
return <div className="grid gap-1.5">{props.children}</div>;
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Dialog variant loses spacing between label, input, description

Medium Severity

FieldFrame for the dialog variant applies grid gap-1.5 on a wrapper div, but its only child is the <label> element. The gap has no effect because there's only one grid item. The label text, Input, and description are all inside the label with no layout class, so they lose the vertical spacing the old code provided (which had grid gap-1.5 directly on the <label> itself). This causes a visual regression where form fields in the add-provider dialog appear cramped with no gap between label, input, and description.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 77e6873. Configure here.

- preserve schema-defined boolean defaults in provider settings
- omit default-valued switch fields when clearWhenEmpty is omit
- add coverage for boolean read/write defaults
@juliusmarminge juliusmarminge merged commit 460d9c3 into main May 2, 2026
12 checks passed
@juliusmarminge juliusmarminge deleted the t3code/declarative-provider-settings branch May 2, 2026 21:14
Morphexe pushed a commit to Morphexe/t3code that referenced this pull request May 4, 2026
Co-authored-by: Julius Marminge <julius@macmini.local>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant