Skip to content

feat: migrate frontend to dedicated provider keys API#2161

Merged
Pratham-Mishra04 merged 1 commit intov1.5.0from
feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api
Mar 25, 2026
Merged

feat: migrate frontend to dedicated provider keys API#2161
Pratham-Mishra04 merged 1 commit intov1.5.0from
feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api

Conversation

@danpiths
Copy link
Copy Markdown
Collaborator

@danpiths danpiths commented Mar 18, 2026

Summary

Migrates the frontend from reading provider keys via provider.keys (removed
from provider API response in PR #2160) to the dedicated getProviderKeys
query and /api/keys endpoint. Removes keys from all provider TypeScript
types. Key mutations patch caches from authoritative server responses; provider
updates invalidate the ProviderKeys tag to refresh key statuses after model
discovery. Also adds a read-only routing rule info sheet.

Changes

Types (config.ts, schemas.ts)

  • Removed keys field from ModelProviderConfig, AddProviderRequest, and
    UpdateProviderRequest
  • Added CreateProviderKeyRequest, UpdateProviderKeyRequest,
    ListProviderKeysResponse types

Store (providersApi.ts, baseApi.ts)

  • Added ProviderKeys tag type to baseApi
  • Changed getProviderKeys/getProviderKey from Providers tag to
    ProviderKeys tag (avoids invalidating provider cache on key changes)
  • Added invalidatesTags: [ProviderKeys, DBKeys] on updateProvider mutation
    (refreshes key statuses after model discovery)
  • Removed getProvider/getProviders cache patches from createProviderKey,
    updateProviderKey, deleteProviderKey (providers no longer carry keys)
  • Added duplicate-check guards on createProviderKey cache patches to prevent
    ghost keys
  • Each key mutation patches getProviderKeys and getAllKeys caches from
    authoritative server response

Components

  • modelProviderKeysTableView.tsx: Already uses useGetProviderKeysQuery;
    formatting/indentation fixes
  • page.tsx: Removed keys: [] from fallback provider object and
    createProvider call; simplified KeyDiscoveryFailedBadge to only check
    provider-level status (removed per-key status check since keys are no longer
    on provider)
  • routingRuleSheet.tsx: TargetRow now receives allKeys prop (from
    useGetAllKeysQuery) instead of providersData with .keys; filters keys
    by target provider
  • routingRuleInfoSheet.tsx: New read-only sheet component that displays
    routing rule details (conditions, targets with provider icons and weight bars,
    fallback chain, scope, priority, timestamps)
  • settingsPanel.tsx: Uses useGetAllKeysQuery to determine configured
    providers (replaces p.keys.length > 0 check) and derive
    providerKeyConfigs per provider

Other frontend changes (from prior commit, unchanged)

  • Added getProviderKeys, getProviderKey RTK Query endpoints
  • Added createProviderKey, updateProviderKey, deleteProviderKey mutations
  • Added buildProviderUpdatePayload utility for key-free provider updates
  • Migrated providerKeyForm.tsx to separate create/update mutations
  • Updated addNewKeySheet.tsx props from keyIndex to keyId
  • Updated all 6 provider form fragments to use buildProviderUpdatePayload
  • Removed dead selectedProvider.keys sync matchers from providerSlice.ts

Type of change

  • Feature
  • Refactor
  • Bug fix
  • Documentation
  • Chore/CI

Affected areas

  • Core (Go)
  • Transports (HTTP)
  • Providers/Integrations
  • Plugins
  • UI (Next.js)
  • Docs

How to test

cd ui
npm run build
npm run lint

Manual testing:

  1. Navigate to Providers page, select a provider with keys
  2. Verify keys table loads correctly from dedicated API
  3. Create a new key — verify it appears immediately (no ghost/duplicate)
  4. Toggle enable/disable — verify switch updates immediately
  5. Edit a key — verify form pre-populates, save works
  6. Delete a key — verify it disappears immediately
  7. Update provider settings — verify key statuses refresh after save
  8. Check sidebar badge shows provider-level discovery failures
  9. Open Playground settings — verify provider/key dropdowns work
  10. Open Routing Rules — verify target key selector works
  11. Click a routing rule row — verify info sheet opens with correct details
    (conditions, targets, fallbacks, scope, priority)

Screenshots/Recordings

N/A — no visual changes to existing features; routing rule info sheet is new.

Breaking changes

  • Yes
  • No

Frontend-only changes consuming the new API shape from PR #2160.

Related issues

N/A

Security considerations

No new security considerations. Key values continue to be handled through
existing redaction on the backend.

Checklist

  • I read docs/contributing/README.md and followed the guidelines
  • I added/updated tests where appropriate
  • I updated documentation where needed
  • I verified builds succeed (Go and UI)
  • I verified the CI pipeline passes locally if applicable

@danpiths danpiths requested a review from akshaydeo March 18, 2026 11:57
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Copy Markdown
Collaborator Author

danpiths commented Mar 18, 2026

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 6a8d3f38-3818-4524-9855-a6f8b07d8dfa

📥 Commits

Reviewing files that changed from the base of the PR and between 39a0808 and 9e7ee50.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (20)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
  • ui/app/workspace/routing-rules/views/routingRuleSheet.tsx
  • ui/components/prompts/fragments/settingsPanel.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
✅ Files skipped from review due to trivial changes (3)
  • ui/lib/store/apis/baseApi.ts
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/views/utils.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/schemas.ts
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/lib/types/config.ts
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Independent provider key management with per-key create/update/delete and enable/disable controls
    • Detailed routing rule info sheet showing metadata, conditions, targets, fallbacks, and timestamps
  • Bug Fixes

    • Simplified provider discovery error display and messaging
  • Other

    • Provider create/update flows no longer send empty embedded key arrays; key schema now supports an optional enabled flag
    • Settings now load keys centrally and show a loading skeleton while providers load

Walkthrough

Provider keys were extracted into first-class resources with dedicated RTK endpoints and per-key mutations; provider update payload assembly was centralized via buildProviderUpdatePayload; request/response types and UI flows were updated to use key IDs and global key queries; create/update payloads no longer include a top-level keys: [].

Changes

Cohort / File(s) Summary
Provider-key API & Cache
ui/lib/store/apis/providersApi.ts, ui/lib/store/apis/baseApi.ts
Added ProviderKeys tag; new endpoints/hooks: getProviderKeys, getProviderKey, createProviderKey, updateProviderKey, deleteProviderKey; adjusted updateProvider arg type and cache invalidation; extended tagTypes.
Types & Validation
ui/lib/types/config.ts, ui/lib/types/schemas.ts
Removed keys from provider request/config interfaces; added CreateProviderKeyRequest, UpdateProviderKeyRequest, ListProviderKeysResponse; added optional enabled to modelProviderKeySchema.
Provider update payload helper
ui/app/workspace/providers/views/utils.ts
Added buildProviderUpdatePayload(provider, updates) to centralize payload assembly and apply defaults/merging for network/performance fields.
Provider form fragments
ui/app/workspace/providers/fragments/...
apiStructureFormFragment.tsx, debuggingFormFragment.tsx, networkFormFragment.tsx, performanceFormFragment.tsx, pricingOverridesFormFragment.tsx, proxyFormFragment.tsx
Replaced inline spread-based payload construction with buildProviderUpdatePayload(provider, updates) across fragments; submit flows, toasts, and validation unchanged.
Key UI (dialogs/forms/table)
ui/app/workspace/providers/dialogs/addNewKeySheet.tsx, ui/app/workspace/providers/views/providerKeyForm.tsx, ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
Switched from index-based keys to `keyId: string
Provider creation & discovery UI
ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx, ui/app/workspace/providers/page.tsx
Stopped including top-level keys: [] in createProvider payloads and removed empty keys init on provider fetch 404; simplified discovery badge/tooltip to depend on provider status only.
Global keys consumers
ui/components/prompts/fragments/settingsPanel.tsx, ui/app/workspace/routing-rules/views/routingRuleSheet.tsx, ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
Consumers switched to using global allKeys (useGetAllKeysQuery) and adapted lookups/props to unified key records instead of provider-embedded keys.
Provider slice
ui/lib/store/slices/providerSlice.ts
Moved updateProvider.matchFulfilled matcher registration inside extraReducers(builder) block; handler logic unchanged.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as Providers UI
    participant RTK as providersApi (RTK Query)
    participant Cache as Client Cache
    participant Server

    User->>UI: open key sheet / toggle key / delete key
    UI->>RTK: call createProviderKey / updateProviderKey / deleteProviderKey
    RTK->>Server: HTTP request for key create/update/delete
    Server-->>RTK: response (key object or success)
    RTK->>Cache: update getProviderKeys / getProviderKey / getAllKeys caches
    RTK-->>UI: mutation result (success/error)
    UI-->>User: show toast and refreshed UI from cache
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Poem

🐇 I hopped through branches, keys in tow,
Old nests unbundled, new pathways show.
Endpoints hum, payloads neat and trim,
Cache refreshed with every tiny limb.
A joyful hop — the code feels prim.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 4.17% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: migrating the frontend to use a dedicated provider keys API instead of embedded provider.keys.
Description check ✅ Passed The description comprehensively explains the changes across types, store, components, and utilities, providing clear context for the provider keys API migration with testing instructions.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api
📝 Coding Plan
  • Generate coding plan for human review comments

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

Copy link
Copy Markdown
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.

Caution

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

⚠️ Outside diff range comments (1)
ui/app/workspace/providers/views/providerKeyForm.tsx (1)

36-50: ⚠️ Potential issue | 🟠 Major

Form may not update when currentKey becomes available after initial render.

When editing an existing key, useGetProviderKeysQuery may still be loading on first render, causing currentKey to be undefined. The form initializes with default values, but there's no useEffect to reset the form when currentKey becomes available. This could result in the edit form showing empty/new key values instead of the existing key data.

🔧 Proposed fix to reset form when currentKey loads
+	// Reset form when currentKey becomes available (e.g., after keys query loads)
+	useEffect(() => {
+		if (currentKey) {
+			form.reset({
+				key: currentKey as ProviderKeyFormValues,
+			});
+		}
+	}, [currentKey, form]);
+
 	// Trigger validation on mount when editing existing data
 	useEffect(() => {
 		if (isEditing) {
 			form.trigger();
 		}
 	}, [isEditing, form]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/providers/views/providerKeyForm.tsx` around lines 36 - 50,
The form initializes with defaultValues and never updates when currentKey
becomes available, so add a useEffect that watches currentKey and calls
form.reset({ key: currentKey as ProviderKeyFormValues }) when currentKey is
defined (ensuring the uuid/new-key default remains only for creation); reference
the existing form from useForm, the currentKey variable, and the
providerKeyFormSchema to perform the reset so the edit form reflects the loaded
key data.
🧹 Nitpick comments (2)
ui/app/workspace/providers/views/utils.ts (1)

6-20: Consider adding an explicit return type for better type safety.

The function works correctly and centralizes payload construction, but an explicit return type would improve maintainability and catch type mismatches at compile time.

💡 Optional: Add explicit return type
-export const buildProviderUpdatePayload = (provider: ModelProvider, updates: Partial<UpdateProviderRequest>) => {
+export const buildProviderUpdatePayload = (provider: ModelProvider, updates: Partial<UpdateProviderRequest>): UpdateProviderRequest & { name: ModelProviderName } => {
 	const { name } = provider;

This would require importing ModelProviderName from @/lib/types/config.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/providers/views/utils.ts` around lines 6 - 20, Add an
explicit return type to buildProviderUpdatePayload to improve type safety:
change its signature to return UpdateProviderRequest (or the exact type used for
provider update payloads) and import that type if not already imported; ensure
the constructed object fields (network_config, concurrency_and_buffer_size,
etc.) match the UpdateProviderRequest shape and the
DefaultNetworkConfig/DefaultPerformanceConfig types to avoid type mismatches.
ui/lib/store/apis/providersApi.ts (1)

305-309: Consider using a cleaner array-clearing approach.

The current splice(0, draft.length) works but is unconventional for clearing an array in Immer drafts.

💡 Optional: Simplify array clearing
 				dispatch(
 					providersApi.util.updateQueryData("getProviderKeys", providerName, (draft) => {
-						draft.splice(0, draft.length);
+						return [];
 					}),
 				);

Returning an empty array is more idiomatic for Immer when replacing the entire state.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/lib/store/apis/providersApi.ts` around lines 305 - 309, The update to the
cached query in providersApi.util.updateQueryData currently clears the Immer
draft with draft.splice(0, draft.length), which is unconventional; instead
replace the entire draft by returning an empty array. In the provider cache
update for "getProviderKeys" (call using providersApi.util.updateQueryData and
the providerName key), change the updater callback to return [] so Immer
replaces the array cleanly rather than mutating it with splice.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@ui/app/workspace/providers/views/providerKeyForm.tsx`:
- Around line 36-50: The form initializes with defaultValues and never updates
when currentKey becomes available, so add a useEffect that watches currentKey
and calls form.reset({ key: currentKey as ProviderKeyFormValues }) when
currentKey is defined (ensuring the uuid/new-key default remains only for
creation); reference the existing form from useForm, the currentKey variable,
and the providerKeyFormSchema to perform the reset so the edit form reflects the
loaded key data.

---

Nitpick comments:
In `@ui/app/workspace/providers/views/utils.ts`:
- Around line 6-20: Add an explicit return type to buildProviderUpdatePayload to
improve type safety: change its signature to return UpdateProviderRequest (or
the exact type used for provider update payloads) and import that type if not
already imported; ensure the constructed object fields (network_config,
concurrency_and_buffer_size, etc.) match the UpdateProviderRequest shape and the
DefaultNetworkConfig/DefaultPerformanceConfig types to avoid type mismatches.

In `@ui/lib/store/apis/providersApi.ts`:
- Around line 305-309: The update to the cached query in
providersApi.util.updateQueryData currently clears the Immer draft with
draft.splice(0, draft.length), which is unconventional; instead replace the
entire draft by returning an empty array. In the provider cache update for
"getProviderKeys" (call using providersApi.util.updateQueryData and the
providerName key), change the updater callback to return [] so Immer replaces
the array cleanly rather than mutating it with splice.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a74b86c1-1249-435d-82bb-8ffc34c82763

📥 Commits

Reviewing files that changed from the base of the PR and between b3aefcd and 6326b73.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx

@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 6326b73 to ff4302e Compare March 18, 2026 13:10
Copy link
Copy Markdown
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: 3

Caution

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

⚠️ Outside diff range comments (1)
ui/lib/types/config.ts (1)

334-350: ⚠️ Potential issue | 🟠 Major

Keep the runtime request schemas in sync with these optional fields.

AddProviderRequest.keys and UpdateProviderRequest.keys / proxy_config are optional here now, but addProviderRequestSchema and updateProviderRequestSchema in ui/lib/types/schemas.ts still require a non-empty keys array and a required proxy_config (ui/lib/types/schemas.ts lines 559-577). Any path that parses these payloads will still reject the new key-less/provider-key flows even though the types now allow them.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/lib/types/config.ts` around lines 334 - 350, The runtime JSON schemas in
addProviderRequestSchema and updateProviderRequestSchema still require a
non-empty keys array and a required proxy_config while the TypeScript interfaces
(AddProviderRequest.keys, UpdateProviderRequest.keys, and proxy_config) make
them optional; update those schemas in ui/lib/types/schemas.ts to match the
types: make proxy_config optional and allow keys to be absent (or present as an
optional array), and only enforce non-empty keys when the keys property exists
(e.g., validate non-empty arrays conditionally), so the parser accepts
key-less/provider-key flows consistent with the interfaces.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui/app/workspace/providers/views/modelProviderKeysTableView.tsx`:
- Around line 66-71: The delete/edit actions use the unstable key.name and lack
test hooks; update the row selector and dialog/menu action attributes to use the
stable key.id instead of key.name and add data-testid attributes for the
interactive elements following the pattern
data-testid="<entity>-<element>-<qualifier>". Specifically, change any usages
that build test hooks from key.name to key.id (references:
setShowDeleteKeyDialog call, isMutatingProviderKey gating,
hasDeleteProviderAccess check, and places rendering
AlertDialogAction/AlertDialogCancel) and add data-testid values like
data-testid="provider-key-delete-<key.id>" and
data-testid="provider-key-cancel-<key.id>" (and similar for edit/menu items) for
all affected controls (also update the other occurrences noted around the other
ranges).

In `@ui/app/workspace/providers/views/providerKeyForm.tsx`:
- Around line 34-43: The form is initialized with defaultValues from useForm
before useGetProviderKeysQuery resolves, so currentKey can arrive later and must
populate the form; add a useEffect that watches currentKey and calls
form.reset({ key: currentKey as ProviderKeyFormValues }) when currentKey becomes
defined (and when keyId changes), and in the submit handler (where
currentKey!.id is used) guard submission by returning or disabling submit if
isEditing && !currentKey to avoid dereferencing undefined; update references to
currentKey and useGetProviderKeysQuery accordingly.

In `@ui/lib/store/apis/providersApi.ts`:
- Around line 123-132: The getProviderKeys/getProviderKey/getAllKeys cache sync
is incomplete: stop relying on invalidatesTags: ["DBKeys"] and instead patch the
remaining queries in the mutations' onQueryStarted handlers; specifically, in
the mutation handlers that currently patch getProviderKeys, getProvider, and
getProviders add api.util.updateQueryData calls to also update getAllKeys (the
global list) and getProviderKey (detail) so updates/deletes keep consumers
fresh, and remove invalidatesTags: ["DBKeys"] from those mutations; locate uses
of getProviderKeys, getProviderKey, getAllKeys and the mutation onQueryStarted
handlers and apply updateQueryData to add/replace/remove items accordingly (use
provider and keyId from args/response to target entries).

---

Outside diff comments:
In `@ui/lib/types/config.ts`:
- Around line 334-350: The runtime JSON schemas in addProviderRequestSchema and
updateProviderRequestSchema still require a non-empty keys array and a required
proxy_config while the TypeScript interfaces (AddProviderRequest.keys,
UpdateProviderRequest.keys, and proxy_config) make them optional; update those
schemas in ui/lib/types/schemas.ts to match the types: make proxy_config
optional and allow keys to be absent (or present as an optional array), and only
enforce non-empty keys when the keys property exists (e.g., validate non-empty
arrays conditionally), so the parser accepts key-less/provider-key flows
consistent with the interfaces.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4d6863f6-19ae-4c26-bd46-5001fc5c6707

📥 Commits

Reviewing files that changed from the base of the PR and between 6326b73 and ff4302e.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
🚧 Files skipped from review as they are similar to previous changes (8)
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/lib/store/slices/providerSlice.ts
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx

Comment thread ui/app/workspace/providers/views/modelProviderKeysTableView.tsx Outdated
Comment thread ui/app/workspace/providers/views/providerKeyForm.tsx
Comment thread ui/lib/store/apis/providersApi.ts
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from ff4302e to 4c6edab Compare March 18, 2026 13:54
Copy link
Copy Markdown
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: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui/app/workspace/providers/views/modelProviderKeysTableView.tsx`:
- Around line 47-50: The component currently uses a single togglingKeyId state
(togglingKeyId / setTogglingKeyId) which allows a second toggle to overwrite the
first and permits overlapping requests to race; change this to track pending
toggles per-key (e.g., togglingKeyIds as a Set<string> or
Record<string,boolean>) and update all places that read or mutate togglingKeyId
to add/remove the specific keyId instead of replacing a single value.
Specifically, replace togglingKeyId/setTogglingKeyId with
togglingKeyIds/setTogglingKeyIds, adjust the toggle handler(s) to add the keyId
before the async PUT and remove it in finally, and update UI disables/conditions
(where you currently check togglingKeyId === key.id) to use
togglingKeyIds.has(key.id); also apply the same per-key pending-tracking pattern
to the related update/delete flows that reference isUpdatingProviderKey /
isDeletingProviderKey so each row is disabled only while its own request is in
flight.

In `@ui/lib/store/apis/providersApi.ts`:
- Around line 337-341: The deleteProvider flow clears the per-provider cache
("getProviderKeys") but does not purge the governance-wide cache ("getAllKeys"),
leaving deleted provider keys selectable; update the same dispatch in the
deleteProvider handler to also call
providersApi.util.updateQueryData("getAllKeys", undefined, draft => { remove any
keys belonging to providerName or clear as appropriate }) so the global cache
reflects the deletion—refer to the existing providersApi.util.updateQueryData
usage around deleteProvider/getProviderKeys and mirror that logic for
"getAllKeys".
- Around line 289-293: The current use of
providersApi.util.updateQueryData("getProviderKey", { provider, keyId }, ...)
trying to return undefined won't evict the cache because Immer treats undefined
as no-op; instead, change the delete mutation to use RTK Query tag invalidation
(e.g., set invalidatesTags: [{ type: 'ProviderKey', id: keyId }]) so that
deleting a key invalidates the cached getProviderKey entry and triggers
refetch/removal; update the mutation definition that performs the deletion to
include the invalidatesTags for the ProviderKey id.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4838b83f-92d9-4d02-b93c-eedb9e852148

📥 Commits

Reviewing files that changed from the base of the PR and between ff4302e and 4c6edab.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
✅ Files skipped from review due to trivial changes (1)
  • ui/lib/store/slices/providerSlice.ts
🚧 Files skipped from review as they are similar to previous changes (6)
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/lib/types/schemas.ts
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx

Comment thread ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
Comment thread ui/lib/store/apis/providersApi.ts Outdated
Comment thread ui/lib/store/apis/providersApi.ts
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 4c6edab to a4ce926 Compare March 18, 2026 14:26
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui/app/workspace/providers/views/modelProviderKeysTableView.tsx`:
- Around line 191-194: The toggle mutation is mistakenly sending the entire
server response object by spreading key into updateProviderKey, which can write
back server-only metadata; change the call to pass only the editable fields
(e.g., enabled and any user-editable properties like name/value) instead of
...key — for example call updateProviderKey({ provider: provider.name, keyId:
key.id, key: { enabled: checked } }) or include any other explicit editable
fields, ensuring you remove the spread of key in the payload.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fda11345-923e-4fba-8a48-13ea543416ad

📥 Commits

Reviewing files that changed from the base of the PR and between 4c6edab and a4ce926.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (16)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
✅ Files skipped from review due to trivial changes (1)
  • ui/lib/store/slices/providerSlice.ts
🚧 Files skipped from review as they are similar to previous changes (9)
  • ui/app/workspace/providers/page.tsx
  • ui/lib/types/schemas.ts
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/lib/store/apis/providersApi.ts
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx

Comment thread ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch from b3aefcd to 86de542 Compare March 19, 2026 10:17
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch 2 times, most recently from 4b7ba64 to fbe5ad0 Compare March 19, 2026 10:18
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch from 86de542 to 9ff1b4f Compare March 19, 2026 10:18
Copy link
Copy Markdown
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 (1)
ui/app/workspace/providers/fragments/proxyFormFragment.tsx (1)

43-45: Pre-existing: Missing dispatch in useEffect dependency array.

The dispatch function is used inside the effect but not listed in the dependency array. While dispatch from Redux is typically stable, React's exhaustive-deps rule recommends including it.

Suggested fix
 	useEffect(() => {
 		dispatch(setProviderFormDirtyState(form.formState.isDirty));
-	}, [form.formState.isDirty]);
+	}, [form.formState.isDirty, dispatch]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/app/workspace/providers/fragments/proxyFormFragment.tsx` around lines 43 -
45, The effect in proxyFormFragment.tsx uses dispatch and
setProviderFormDirtyState but only lists form.formState.isDirty in the
dependency array; update the useEffect so it includes dispatch (and optionally
setProviderFormDirtyState) in the dependency array: e.g. useEffect(() => {
dispatch(setProviderFormDirtyState(form.formState.isDirty)); }, [dispatch,
form.formState.isDirty]); or destructure isDirty into a local variable and
include dispatch and that variable in the deps to satisfy exhaustive-deps and
keep behavior stable.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx`:
- Around line 160-167: The early return in RoutingRuleInfoSheet skips the
useScopeName hook and violates React hooks rules; move the hook call so hooks
run unconditionally (call useScopeName at the top of RoutingRuleInfoSheet before
any returns) and pass safe values (e.g., rule?.scope and rule?.scope_id or
undefined) so it can execute even when rule is null/undefined, then keep the
conditional render (if (!rule) return null) after the hook call.

---

Nitpick comments:
In `@ui/app/workspace/providers/fragments/proxyFormFragment.tsx`:
- Around line 43-45: The effect in proxyFormFragment.tsx uses dispatch and
setProviderFormDirtyState but only lists form.formState.isDirty in the
dependency array; update the useEffect so it includes dispatch (and optionally
setProviderFormDirtyState) in the dependency array: e.g. useEffect(() => {
dispatch(setProviderFormDirtyState(form.formState.isDirty)); }, [dispatch,
form.formState.isDirty]); or destructure isDirty into a local variable and
include dispatch and that variable in the deps to satisfy exhaustive-deps and
keep behavior stable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: f965c079-864e-4553-a807-1d207250df9f

📥 Commits

Reviewing files that changed from the base of the PR and between a4ce926 and fbe5ad0.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (20)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
  • ui/app/workspace/routing-rules/views/routingRuleSheet.tsx
  • ui/components/prompts/fragments/settingsPanel.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
✅ Files skipped from review due to trivial changes (3)
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
🚧 Files skipped from review as they are similar to previous changes (7)
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/lib/types/schemas.ts
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx

Comment thread ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch from 9ff1b4f to c00677a Compare March 19, 2026 11:03
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from fbe5ad0 to d022fb5 Compare March 19, 2026 11:03
Copy link
Copy Markdown
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

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui/components/prompts/fragments/settingsPanel.tsx`:
- Around line 49-61: The provider filtering currently treats a
missing/unresolved allKeys as an empty array because of (allKeys ?? []), causing
providers to be excluded during loading/error; adjust configuredProviders to use
the query's load state (e.g., the flags returned by useGetAllKeysQuery such as
isLoading/isSuccess/isError or isFetching) instead of null-coalescing to [] so
you only treat a provider as having zero keys when the keys query has
successfully loaded and returned an empty array; update the logic in
configuredProviders (and any downstream checks that use providerKeyConfigs to
mean “unrestricted”) to check the allKeys-loaded flag (isSuccess) before
deciding that no keys exist so that loading/error keeps providers available and
preserves model-restriction behavior until keys are known.

In `@ui/lib/store/apis/providersApi.ts`:
- Around line 155-160: The PUT currently sends the whole provider object
(builder.mutation updateProvider using UpdateProviderMutationArg /
ModelProvider) including provider.name, but the backend expects
UpdateProviderRequest without name; change the query body to exclude the name
(use the encoded provider.name only in the URL via
encodeURIComponent(provider.name)) and send a payload shaped like
UpdateProviderRequest (e.g., spread provider minus name or construct an explicit
object), so the request body matches the new types and backend validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b2c1fabe-7177-403a-be51-2e7315e1e99c

📥 Commits

Reviewing files that changed from the base of the PR and between fbe5ad0 and d022fb5.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (20)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
  • ui/app/workspace/routing-rules/views/routingRuleSheet.tsx
  • ui/components/prompts/fragments/settingsPanel.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
✅ Files skipped from review due to trivial changes (2)
  • ui/lib/store/apis/baseApi.ts
  • ui/app/workspace/routing-rules/views/routingRuleSheet.tsx
🚧 Files skipped from review as they are similar to previous changes (14)
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/lib/store/slices/providerSlice.ts
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/lib/types/schemas.ts
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/lib/types/config.ts
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/page.tsx

Comment thread ui/components/prompts/fragments/settingsPanel.tsx Outdated
Comment thread ui/lib/store/apis/providersApi.ts
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from d022fb5 to 39a0808 Compare March 19, 2026 12:52
Copy link
Copy Markdown
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: 3

♻️ Duplicate comments (1)
ui/components/prompts/fragments/settingsPanel.tsx (1)

48-68: ⚠️ Potential issue | 🟠 Major

Don’t let a pending /keys query look like “no restrictions”.

configuredProviders now respects hasLoadedAllKeys, but providerKeys/providerKeyConfigs still collapse unresolved allKeys to []. On a cold load, Lines 117-119 therefore fall back to allProviderModels and the key selector stays hidden before provider-key restrictions are actually known. Keep the same loaded flag through this path and only treat an empty key set as unrestricted after useGetAllKeysQuery() succeeds.

Also applies to: 79-80, 104-119

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ui/components/prompts/fragments/settingsPanel.tsx` around lines 48 - 68, The
provider key resolution is incorrectly treating an unresolved allKeys result as
an empty set; update the code paths that build providerKeys and
providerKeyConfigs to check the same hasLoadedAllKeys flag returned by
useGetAllKeysQuery() (same as configuredProviders) and only collapse to [] or
apply "no restrictions" logic after hasLoadedAllKeys is true. Concretely, change
any usage of (allKeys ?? []) in the providerKeys/providerKeyConfigs logic to
gate on hasLoadedAllKeys (e.g., if !hasLoadedAllKeys return the
pre-loaded/placeholder state or hide the selector) and use allKeys only when
hasLoadedAllKeys is true, referencing the functions/variables
useGetAllKeysQuery, hasLoadedAllKeys, allKeys, providerKeys, providerKeyConfigs
and allProviderModels to locate where to add the guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx`:
- Around line 150-151: The current JSX renders the provider icon via
RenderProviderIcon and then shows model || fb, which hides the provider fallback
text when model is present but RenderProviderIcon returns null for unknown
providers; update the rendering in routingRuleInfoSheet.tsx so that when
RenderProviderIcon returns null (i.e., provider is unknown) you append or
display the fallback provider label (fb) alongside model (e.g., "model (fb)") or
otherwise render fb when provider is not recognized; use the existing symbols
RenderProviderIcon, provider, model, and fb to detect the missing icon and
include the fallback provider text in the UI.
- Around line 123-131: The TooltipTrigger currently uses asChild to wrap a
non-focusable <div>, making the tooltip inaccessible by keyboard and missing the
required test id; replace the wrapped element with a keyboard-focusable element
(e.g., a <button type="button">) or add tabIndex={0} and appropriate keyboard
handlers so the trigger is focusable and operable, preserve the existing
classes/structure for the progress bar and percentage span, and add a compliant
data-testid attribute (for example
data-testid="routing-rule-weight-tooltip-trigger") to the trigger element so
tests can target it; update TooltipContent usage remains unchanged.

In `@ui/lib/store/apis/providersApi.ts`:
- Around line 123-126: getProviderKeys currently provides both { type:
"ProviderKeys", id: provider } and the global "DBKeys" tag which causes
updateProvider to unnecessarily refetch provider-scoped key lists; remove the
"DBKeys" tag from getProviderKeys's providesTags so it only returns the
provider-scoped tag, and also remove "DBKeys" from updateProvider's
invalidatesTags so that updating provider configuration does not invalidate key
caches—leave "DBKeys" only on the global getAllKeys and let key mutations
(createProviderKey, updateProviderKey, deleteProviderKey) continue to target the
provider-scoped tag and the global "DBKeys" as appropriate.

---

Duplicate comments:
In `@ui/components/prompts/fragments/settingsPanel.tsx`:
- Around line 48-68: The provider key resolution is incorrectly treating an
unresolved allKeys result as an empty set; update the code paths that build
providerKeys and providerKeyConfigs to check the same hasLoadedAllKeys flag
returned by useGetAllKeysQuery() (same as configuredProviders) and only collapse
to [] or apply "no restrictions" logic after hasLoadedAllKeys is true.
Concretely, change any usage of (allKeys ?? []) in the
providerKeys/providerKeyConfigs logic to gate on hasLoadedAllKeys (e.g., if
!hasLoadedAllKeys return the pre-loaded/placeholder state or hide the selector)
and use allKeys only when hasLoadedAllKeys is true, referencing the
functions/variables useGetAllKeysQuery, hasLoadedAllKeys, allKeys, providerKeys,
providerKeyConfigs and allProviderModels to locate where to add the guard.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ff059b44-c989-4425-b241-0f540e8888b9

📥 Commits

Reviewing files that changed from the base of the PR and between d022fb5 and 39a0808.

⛔ Files ignored due to path filters (1)
  • ui/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (20)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/fragments/debuggingFormFragment.tsx
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/app/workspace/providers/fragments/performanceFormFragment.tsx
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
  • ui/app/workspace/providers/views/providerKeyForm.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
  • ui/app/workspace/routing-rules/views/routingRuleSheet.tsx
  • ui/components/prompts/fragments/settingsPanel.tsx
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/store/apis/providersApi.ts
  • ui/lib/store/slices/providerSlice.ts
  • ui/lib/types/config.ts
  • ui/lib/types/schemas.ts
💤 Files with no reviewable changes (1)
  • ui/app/workspace/providers/dialogs/addNewCustomProviderSheet.tsx
✅ Files skipped from review due to trivial changes (2)
  • ui/lib/store/apis/baseApi.ts
  • ui/lib/types/config.ts
🚧 Files skipped from review as they are similar to previous changes (10)
  • ui/app/workspace/providers/fragments/networkFormFragment.tsx
  • ui/lib/types/schemas.ts
  • ui/app/workspace/providers/fragments/proxyFormFragment.tsx
  • ui/lib/store/slices/providerSlice.ts
  • ui/app/workspace/providers/fragments/pricingOverridesFormFragment.tsx
  • ui/app/workspace/providers/page.tsx
  • ui/app/workspace/providers/fragments/apiStructureFormFragment.tsx
  • ui/app/workspace/providers/dialogs/addNewKeySheet.tsx
  • ui/app/workspace/providers/views/utils.ts
  • ui/app/workspace/providers/views/modelProviderKeysTableView.tsx

Comment thread ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
Comment thread ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx Outdated
Comment thread ui/lib/store/apis/providersApi.ts Outdated
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 39a0808 to 9e7ee50 Compare March 19, 2026 13:38
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch from c00677a to b69f412 Compare March 25, 2026 07:40
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 9e7ee50 to 5301508 Compare March 25, 2026 07:40
@danpiths danpiths mentioned this pull request Mar 25, 2026
18 tasks
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from e9258e5 to 8f86b88 Compare March 25, 2026 09:48
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch from 78f84df to cdd753f Compare March 25, 2026 09:48
Comment thread ui/app/workspace/providers/views/utils.ts Outdated
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 8f86b88 to 0040019 Compare March 25, 2026 10:06
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch 2 times, most recently from 43e0a19 to dbd12f5 Compare March 25, 2026 10:39
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 0040019 to 6997f13 Compare March 25, 2026 10:39
Comment thread ui/components/prompts/fragments/settingsPanel.tsx
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 6997f13 to b8d1591 Compare March 25, 2026 10:53
@danpiths danpiths force-pushed the feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys branch from dbd12f5 to 9b84e1e Compare March 25, 2026 10:53
Comment thread ui/app/workspace/providers/views/utils.ts Outdated
Comment thread ui/lib/types/config.ts
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from b8d1591 to 547d180 Compare March 25, 2026 11:06
Comment thread ui/app/workspace/providers/views/providerKeyForm.tsx
@danpiths danpiths force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from 547d180 to e37b59b Compare March 25, 2026 12:52
Copy link
Copy Markdown
Collaborator

Pratham-Mishra04 commented Mar 25, 2026

Merge activity

  • Mar 25, 12:57 PM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Mar 25, 1:03 PM UTC: Graphite rebased this pull request as part of a merge.
  • Mar 25, 1:04 PM UTC: @Pratham-Mishra04 merged this pull request with Graphite.

@Pratham-Mishra04 Pratham-Mishra04 changed the base branch from feature/03-18-feat_add_provider_keys_http_handlers_and_refactor_optional_keys to graphite-base/2161 March 25, 2026 12:59
Comment thread ui/app/workspace/providers/views/modelProviderKeysTableView.tsx
Comment thread ui/app/workspace/routing-rules/views/routingRuleInfoSheet.tsx
@Pratham-Mishra04 Pratham-Mishra04 changed the base branch from graphite-base/2161 to v1.5.0 March 25, 2026 13:01
@Pratham-Mishra04 Pratham-Mishra04 force-pushed the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch from e37b59b to 3d2b166 Compare March 25, 2026 13:02
@Pratham-Mishra04 Pratham-Mishra04 merged commit 72f4ba2 into v1.5.0 Mar 25, 2026
4 of 5 checks passed
@Pratham-Mishra04 Pratham-Mishra04 deleted the feature/03-18-feat_migrate_frontend_to_dedicated_provider_keys_api branch March 25, 2026 13:04
Comment on lines +160 to +163
export function RoutingRuleInfoSheet({ rule, open, onOpenChange }: Props) {
const targets = rule?.targets ?? [];
const fallbacks = rule?.fallbacks ?? [];
const hasQuery = rule?.query && (rule.query.rules?.length ?? 0) > 0;
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.

P2 Sheet close animation dropped when rule is cleared

When the parent sets open = false and rule = null in the same render cycle (the typical close pattern), the {rule && <SheetContent>} guard causes SheetContent to unmount immediately — the Sheet never receives open={false} with content present, so the slide-out animation never plays and the panel snaps closed.

Move the null-guard inside the already-rendered SheetContent so the outer Sheet always stays mounted and can animate:

export function RoutingRuleInfoSheet({ rule, open, onOpenChange }: Props) {
	const targets = rule?.targets ?? [];
	const fallbacks = rule?.fallbacks ?? [];
	const hasQuery = rule?.query && (rule.query.rules?.length ?? 0) > 0;
	const scopeName = useScopeName(rule?.scope ?? "global", rule?.scope_id);

	return (
		<Sheet open={open} onOpenChange={onOpenChange}>
			<SheetContent className="custom-scrollbar p-8" data-testid="routing-rule-info">
				{rule && (
					<>
						<SheetHeader className="flex flex-col items-start">
							<SheetTitle>Rule details</SheetTitle>
						</SheetHeader>
						{/* ... rest of content */}
					</>
				)}
			</SheetContent>
		</Sheet>
	);
}

Comment on lines +241 to +247
} catch {}
},
}),

deleteProviderKey: builder.mutation<ModelProviderKey, { provider: string; keyId: string }>({
query: ({ provider, keyId }) => ({
url: `/providers/${encodeURIComponent(provider)}/keys/${encodeURIComponent(keyId)}`,
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.

P2 deleteProviderKey return type may not match backend

The mutation is declared as builder.mutation<ModelProviderKey, ...>, implying the DELETE endpoint returns the deleted record as JSON. If the backend returns 204 No Content (a common REST convention for DELETE), RTK Query's default baseQuery will attempt to parse an empty body as JSON and emit a parse error in the console — even though the onQueryStarted handler does not use the returned data.

If the endpoint returns 204, the response type generic should be updated to void to match the actual server contract. This prevents the spurious parse error from appearing in production logs.

@danpiths danpiths linked an issue Mar 25, 2026 that may be closed by this pull request
1 task
@danpiths danpiths self-assigned this Mar 25, 2026
@Pratham-Mishra04 Pratham-Mishra04 linked an issue Mar 27, 2026 that may be closed by this pull request
1 task
akshaydeo added a commit that referenced this pull request Apr 18, 2026
* refactor: standardize empty array conventions for VK Provider & MCP Configs, and makes Provider Config weight optional for routing (#1932)

## Summary

Changes Virtual Key provider and MCP configurations from "allow-all by default" to "deny-by-default" security model. Virtual Keys now require explicit provider and MCP client configurations to allow access, improving security posture.

## Changes

- **Provider Configs**: Empty `provider_configs` now blocks all providers instead of allowing all
- **MCP Configs**: Empty `mcp_configs` now blocks all MCP tools instead of allowing all  
- **Weight Field**: Changed provider `weight` from required `float64` to optional `*float64` - null weight excludes provider from weighted routing
- **Migration**: Added automatic backfill migration to preserve existing Virtual Key behavior by adding all available providers/MCP clients to VKs with empty configs
- **Documentation**: Updated all references to reflect new deny-by-default behavior
- **UI Updates**: Modified Virtual Key creation/editing interface to reflect new behavior and weight handling

## Type of change

- [x] Feature
- [x] Refactor
- [x] Documentation

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Plugins
- [x] UI (Next.js)
- [x] Docs

## How to test

Test Virtual Key creation and provider/MCP access:

```sh
# Core/Transports
go version
go test ./...

# Test Virtual Key with no provider configs blocks requests
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer sk-bf-empty-vk" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4", "messages": [{"role": "user", "content": "test"}]}'
# Should return error about no providers configured

# Test Virtual Key with provider configs allows requests  
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer sk-bf-configured-vk" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4", "messages": [{"role": "user", "content": "test"}]}'
# Should work normally

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

## Breaking changes

- [x] Yes

**Impact**: Existing Virtual Keys with empty `provider_configs` or `mcp_configs` would be blocked after this change.

**Migration**: Automatic migration `migrationBackfillEmptyVirtualKeyConfigs` runs on startup to backfill existing Virtual Keys with all available providers/MCP clients, preserving current behavior. New Virtual Keys created after this change will use deny-by-default.

## Security considerations

This change significantly improves security posture by requiring explicit configuration of allowed providers and MCP tools for Virtual Keys. The automatic migration ensures no disruption to existing deployments while new Virtual Keys benefit from the more secure default behavior.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: add MCP auto tool injection toggle (#1933)

## Summary

Adds a new configuration option `DisableAutoToolInject` to the MCP (Model Context Protocol) system that allows disabling automatic tool injection into requests. When enabled, MCP tools are only included when explicitly requested via context headers or filters, providing more granular control over tool availability.

## Changes

- Added `DisableAutoToolInject` field to `MCPToolManagerConfig` schema with runtime update support
- Implemented atomic boolean storage in `ToolsManager` to safely handle concurrent access
- Added logic in `ParseAndAddToolsToRequest` to respect the disable flag and only inject tools when explicit context filters are present
- Extended configuration management with database migration, UI controls, and API endpoints
- Added hot-reload capability through `UpdateMCPDisableAutoToolInject` methods across the stack
- Updated UI with a toggle switch and clear documentation about the feature's behavior

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (Next.js)
- [ ] Docs

## How to test

Validate the new MCP auto tool injection toggle:

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

Test the feature:
1. Configure MCP clients and tools
2. Enable "Disable Auto Tool Injection" in the MCP configuration UI
3. Make requests without explicit tool headers - tools should not be injected
4. Make requests with `x-bf-mcp-include-tools` header - tools should be injected
5. Verify hot-reload works by toggling the setting without server restart

## Screenshots/Recordings

UI changes include a new toggle switch in the MCP configuration view with descriptive text explaining when tools are injected based on explicit headers.

## Breaking changes

- [ ] Yes
- [x] No

This is a backward-compatible addition with a default value of `false` (auto injection enabled).

## Related issues

This addresses the need for more granular control over MCP tool injection behavior in request processing.

## Security considerations

The feature provides better control over tool exposure by allowing administrators to require explicit opt-in for tool injection, potentially reducing unintended tool access.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: VK MCP config now works as an AllowList (#1940)

## Summary

This PR implements MCP tool governance by enforcing virtual key MCP configurations as an execution-time allow-list. When virtual keys have empty MCPConfigs, all MCP tools are denied. When non-empty, each tool is validated against the configured allow-list at both inference time and MCP tool execution.

## Changes

- **Context parameter updates**: Changed MCP-related functions to use `*schemas.BifrostContext` instead of `context.Context` to enable tool tracking
- **Tool tracking**: Added `BifrostContextKeyMCPAddedTools` context key to track which MCP tools are added to requests
- **Governance enforcement**: Virtual key MCP configurations now act as execution-time allow-lists with validation in both `PreMCPHook` and `evaluateGovernanceRequest`
- **Auto-injection control**: Added `DisableAutoToolInject` configuration option that respects the toggle and skips auto-injection when headers are already set by callers
- **Decision type**: Added `DecisionMCPToolBlocked` for MCP tool governance violations
- **UI improvements**: Updated MCP view description and sidebar item naming for better clarity

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [x] UI (Next.js)
- [ ] Docs

## How to test

Test MCP tool governance with virtual keys:

```sh
# Core/Transports
go version
go test ./...

# Test with virtual key having empty MCPConfigs (should deny all MCP tools)
curl -X POST /v1/chat/completions \
  -H "x-bf-virtual-key: test-vk-empty-mcp" \
  -d '{"model": "gpt-4", "messages": [{"role": "user", "content": "test"}]}'

# Test with virtual key having specific MCP tool allowlist
curl -X POST /v1/chat/completions \
  -H "x-bf-virtual-key: test-vk-with-mcp" \
  -d '{"model": "gpt-4", "messages": [{"role": "user", "content": "test"}]}'

# Test disable auto tool inject configuration
curl -X PUT /v1/config/mcp/disable-auto-tool-inject \
  -d '{"disable": true}'

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

New configuration options:
- `disable_auto_tool_inject`: Boolean flag to disable automatic MCP tool injection
- Virtual key `MCPConfigs`: Array of MCP client configurations that act as allow-lists

## Screenshots/Recordings

UI changes include updated MCP configuration view with clearer descriptions for the disable auto tool injection toggle and improved sidebar navigation labels.

## Breaking changes

- [x] Yes
- [ ] No

**Impact**: MCP-related function signatures now require `*schemas.BifrostContext` instead of `context.Context`. Virtual keys with empty MCPConfigs will now deny all MCP tools by default.

**Migration**: Update any custom MCP integrations to use the new context parameter type. Configure MCPConfigs on virtual keys that need MCP tool access.

## Related issues

Implements MCP tool governance and execution-time validation for virtual key configurations.

## Security considerations

- **Access control**: Virtual key MCP configurations now enforce strict allow-lists for tool execution
- **Context isolation**: Tool tracking is isolated per request context to prevent cross-request leakage
- **Validation**: Both pre-execution and execution-time validation prevent unauthorized tool access

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* refactor: standardize empty array conventions for VK Provider Config Allowed Keys (#2006)

## Summary

Migrates VK provider config allowed keys from implicit allow-all semantics to explicit deny-by-default behavior. Adds `AllowAllKeys` boolean field to enable granular key access control while maintaining backward compatibility.

## Changes

- Added `AllowAllKeys` boolean field to `TableVirtualKeyProviderConfig` with database migration
- Backfilled existing configs with `allow_all_keys=true` to preserve current behavior
- Updated key resolution logic: empty keys now denies all access, `["*"]` wildcard allows all keys
- Modified governance resolver to set empty `includeOnlyKeys` slice when no keys are configured
- Enhanced HTTP handlers to recognize `["*"]` wildcard and set `AllowAllKeys` flag appropriately
- Updated UI to display "Allow All Keys" option and show deny-by-default messaging
- Added JSON unmarshaling support for `["*"]` wildcard in config files

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [x] UI (Next.js)
- [ ] Docs

## How to test

Validate the migration and new key access control behavior:

```sh
# Core/Transports
go version
go test ./...

# Test migration runs successfully
go run main.go migrate

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

Test scenarios:
1. Create VK with empty `key_ids` - should deny all keys
2. Create VK with `key_ids: ["*"]` - should allow all keys  
3. Create VK with specific key IDs - should allow only those keys
4. Verify existing VKs maintain their current behavior after migration

## Screenshots/Recordings

UI now shows:
- "Allow All Keys" option in key selection dropdown
- "No keys allowed" vs "All keys allowed" status indicators
- "No providers configured (deny-by-default)" messaging

## Breaking changes

- [ ] Yes
- [x] No

The migration preserves existing behavior by setting `allow_all_keys=true` for configs that previously had no keys specified.

## Related issues

Part of VK access control enhancement initiative.

## Security considerations

Improves security posture by implementing deny-by-default semantics for key access. Existing deployments maintain current access patterns through automatic backfill migration.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* refactor: standardize empty array conventions for allowed models (#2113)

## Summary

Standardizes empty array conventions across Bifrost to implement deny-by-default security semantics. Previously, empty arrays for `allowed_models` and `Models` fields meant "allow all", creating potential security gaps. Now `["*"]` explicitly means "allow all" while empty arrays mean "deny all".

## Changes

- **Core Logic**: Updated model filtering in `bifrost.go` and `selectKeyFromProviderForModel` to treat empty `Models` arrays as deny-all and `["*"]` as allow-all
- **Database Migration**: Added `migrationBackfillAllowedModelsWildcard` to convert existing empty arrays to `["*"]` preserving current behavior for existing records
- **Model Catalog**: Updated `IsModelAllowedForProvider` to use wildcard semantics with deny-by-default fallback
- **Schema Defaults**: Changed default `Models` value from `[]` to `["*"]` in table definitions and form schemas
- **UI Components**: Enhanced `ModelMultiselect` with `allowAllOption` prop and updated virtual key forms to handle wildcard selection
- **Documentation**: Updated JSON schemas, comments, and tooltips to reflect new conventions
- **Governance**: Updated provider config filtering logic to use new wildcard semantics
- **Server Bootstrap**: Added wildcard filtering when loading models to prevent literal "*" from appearing as a model name

## Type of change

- [x] Refactor
- [ ] Bug fix
- [ ] Feature
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [x] Plugins
- [x] UI (Next.js)
- [x] Docs

## How to test

Validate the migration and new semantics:

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

Test scenarios:
1. Create new virtual keys - should default to `["*"]` for allowed models
2. Create new provider keys - should default to `["*"]` for models
3. Verify existing keys with empty arrays are migrated to `["*"]`
4. Test that empty arrays now deny all models/keys as expected
5. Verify UI shows "All models allowed" for wildcard and "No models (deny all)" for empty arrays

## Screenshots/Recordings

UI changes include:
- Model multiselect now shows "Allow All Models" option
- Virtual key details display "All Models" badge for wildcard vs "No models (deny all)" for empty
- Form placeholders updated to reflect new semantics

## Breaking changes

- [x] Yes
- [ ] No

**Migration Impact**: The database migration automatically converts existing empty `allowed_models` and `models_json` arrays to `["*"]`, preserving current behavior. However, any new configurations with empty arrays will now deny access instead of allowing all. Applications relying on "empty = allow all" semantics must be updated to use `["*"]` explicitly.

## Related issues

Part of security hardening initiative to implement explicit allow-lists and deny-by-default semantics across Bifrost configuration.

## Security considerations

This change significantly improves security posture by:
- Eliminating ambiguous "empty means allow all" semantics
- Implementing explicit deny-by-default for new configurations
- Requiring intentional wildcard usage via `["*"]` for broad access
- Maintaining backward compatibility through automatic migration

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* refactor: replace string slices with WhiteList for allowlist fields (#2125)

## Summary

Introduces a new `WhiteList` type to standardize whitelist behavior across the codebase, replacing manual slice operations and string comparisons with semantic methods for handling allow/deny lists.

## Changes

- Added `WhiteList` type with methods `IsAllowed()`, `IsUnrestricted()`, `IsEmpty()`, `Contains()`, and `Validate()`
- Replaced `[]string` fields with `WhiteList` for model restrictions, tool filtering, and key access controls
- Updated all whitelist logic to use semantic methods instead of manual `slices.Contains()` checks
- Added validation to ensure wildcards ("*") aren't mixed with specific values and prevent duplicates
- Improved case-insensitive matching for whitelist comparisons

## Type of change

- [x] Refactor

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Plugins

## How to test

Verify that whitelist behavior remains consistent across all affected components:

```sh
# Core/Transports
go version
go test ./...

# Test specific whitelist scenarios:
# - Empty lists deny all access
# - ["*"] allows all access  
# - Specific lists only allow listed items
# - Mixed wildcards and specific items are rejected
# - Duplicate entries are rejected
```

Test key model filtering, MCP tool execution, and virtual key configurations to ensure whitelist logic works correctly.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

The `WhiteList` type maintains the same JSON serialization format as `[]string`, so existing configurations remain compatible.

## Related issues

N/A

## Security considerations

Improves security by standardizing deny-by-default behavior and adding validation to prevent misconfigured whitelists that could inadvertently grant excessive permissions.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: add request-level extra headers support for MCP tool execution (#2126)

## Summary

This PR adds support for request-level extra headers in MCP tool execution, allowing callers to forward specific headers to MCP servers at runtime based on a per-client allowlist configuration.

## Changes

- Added `AllowedExtraHeaders` field to MCP client configuration with allowlist semantics (empty array = deny all, `["*"]` = allow all)
- Introduced `BifrostContextKeyMCPExtraHeaders` context key to track headers forwarded to MCP tools
- Created `core/mcp/utils` package with `GetHeadersForToolExecution` function to merge static and dynamic headers
- Updated MCP tool execution in both regular tool manager and Starlark code mode to use the new header forwarding system
- Added database migration for `allowed_extra_headers_json` column in MCP client table
- Updated UI to include allowed extra headers configuration in MCP client management
- Enhanced auth demo server example to demonstrate tool-execution level authentication patterns

## Type of change

- [x] Feature

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] UI (Next.js)

## How to test

1. Configure an MCP client with allowed extra headers:
```json
{
  "name": "test-client",
  "connection_string": "http://localhost:3002/",
  "auth_type": "headers",
  "headers": {
    "X-API-Key": "connection-secret"
  },
  "allowed_extra_headers": ["X-Tool-Token"],
  "tools_to_execute": ["*"]
}
```

2. Make requests with extra headers that should be forwarded:
```bash
curl -X POST http://localhost:8080/v1/chat/completions \
  -H "Authorization: Bearer your-key" \
  -H "X-Tool-Token: tool-execution-secret" \
  -d '{
    "model": "gpt-4",
    "messages": [{"role": "user", "content": "Use the secret_data tool"}],
    "tools": [{"type": "function", "function": {"name": "secret_data"}}]
  }'
```

3. Test the auth demo server:
```bash
cd examples/mcps/auth-demo-server
go run main.go
# Server demonstrates two-tier auth: connection-level (X-API-Key) and tool-level (X-Tool-Token)
```

4. Run tests:
```sh
go test ./core/mcp/...
go test ./transports/bifrost-http/...

cd ui
pnpm test
pnpm build
```

## Breaking changes

- [ ] Yes
- [x] No

This is a backward-compatible addition. Existing MCP clients will have empty `allowed_extra_headers` (deny all extra headers) which maintains current behavior.

## Security considerations

- Extra headers are filtered through a strict allowlist per MCP client
- Security denylist prevents auth header overrides via extra headers
- Two-tier authentication pattern demonstrated: connection-level + tool-execution level
- Headers are only forwarded to MCP servers that explicitly allow them

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* fix: apply MCP tool filtering headers to tools/list response when using bifrost as MCP gateway (#2127)

## Summary

Adds support for `x-bf-mcp-include-clients` and `x-bf-mcp-include-tools` request headers to filter MCP tools/list response when using Bifrost as an MCP gateway. This ensures that tool filtering is respected at the MCP protocol level, not just during inference.

## Changes

- Implemented dynamic tool filtering in MCP server handlers that respects per-request include headers
- Added `makeIncludeClientsFilter()` function that filters tools based on request context values
- Registered the tool filter on both global and virtual key MCP servers during initialization
- Updated documentation to clarify that `mcp-include-tools` requires `clientName-toolName` format
- Enhanced examples in documentation to show proper tool naming format

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [x] Docs

## How to test

Test MCP gateway functionality with tool filtering:

```sh
# Test tools/list filtering with include-tools header
curl --location 'http://localhost:8080/mcp/tools/list' \
--header 'x-bf-mcp-include-tools: gmail-send_email,filesystem-read_file' \
--header 'Authorization: Bearer your-vk-here'

# Test tools/list filtering with include-clients header  
curl --location 'http://localhost:8080/mcp/tools/list' \
--header 'x-bf-mcp-include-clients: gmail,filesystem' \
--header 'Authorization: Bearer your-vk-here'

# Verify chat completions still respect the same headers
curl --location 'http://localhost:8080/v1/chat/completions' \
--header 'x-bf-mcp-include-tools: gmail-send_email' \
--header 'Content-Type: application/json' \
--data '{
    "model": "openai/gpt-4o-mini",
    "messages": [{"role": "user", "content": "What tools are available?"}]
}'
```

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

The tool filtering mechanism ensures that virtual key restrictions are properly enforced at the MCP protocol level, preventing unauthorized access to tools that should be filtered out based on request headers.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* refactor: parallelize model listing for providers to speed up startup time (#2151)

## Summary

Parallelizes model listing operations for providers during server startup and provider reloading to significantly reduce initialization time. Previously, model listing was performed sequentially for each provider, causing slower startup times especially when multiple providers were configured.

## Changes

- Added concurrent execution using goroutines and sync.WaitGroup for model listing operations in three key functions: `ReloadProvider`, `ForceReloadPricing`, and `Bootstrap`
- In `ReloadProvider`, both filtered and unfiltered model listing requests now run concurrently for the same provider
- In `ForceReloadPricing` and `Bootstrap`, model listing for different providers now runs in parallel instead of sequentially
- Moved provider key retrieval earlier in `ReloadProvider` to ensure it happens before concurrent model listing
- Added proper context cancellation with defer statements for bifrost contexts

## Type of change

- [x] Refactor

## Affected areas

- [x] Transports (HTTP)

## How to test

Test server startup time with multiple providers configured to verify the performance improvement:

```sh
# Core/Transports
go version
go test ./...

# Test with multiple providers configured
# Measure startup time before and after the change
time go run main.go
```

Configure multiple providers in your bifrost configuration and observe faster startup times, especially noticeable when providers have high latency or many models.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

No security implications. The change maintains the same authentication and authorization patterns while improving performance through parallelization.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* fix: reorder migrations and set AllowAllKeys to true for virtual key provider configs (#2158)

## Summary

Fixes database migration ordering issue and ensures virtual key configurations are properly initialized with the AllowAllKeys field set to true.

## Changes

- Reordered database migrations to execute `migrationAddAllowAllKeysToProviderConfig` before `migrationBackfillEmptyVirtualKeyConfigs` to ensure the AllowAllKeys column exists before backfilling
- Added `AllowAllKeys: true` to provider configurations created during virtual key backfill migration to enable unrestricted key access by default

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Verify that database migrations run successfully and virtual key configurations are created with proper defaults:

```sh
# Core/Transports
go version
go test ./...
```

Test migration ordering by running against a fresh database to ensure no column reference errors occur.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

This change enables unrestricted key access by default for virtual key configurations, which may have security implications depending on the intended access control model.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* feat: implement scoped pricing override

* refactor: custom pricing refactor

* fix: resolve merge conflicts in config loading and governance functions (#2230)

## Summary

Resolves Git merge conflicts in the bifrost-http configuration loading code by cleaning up duplicate function definitions and consolidating the configuration initialization flow.

## Changes

- Removed Git merge conflict markers and duplicate code blocks from `LoadConfig` function
- Consolidated governance configuration loading by keeping both `loadGovernanceConfigFromFile` and `loadGovernanceConfig` functions with distinct purposes
- Removed duplicate `convertSchemasMCPClientConfigToTable` function definition
- Moved pricing overrides initialization logic to `initFrameworkConfig` function for better organization
- Cleaned up extensive duplicate default configuration loading code that was causing merge conflicts
- Changed error handling for pricing overrides from returning error to logging warning

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Verify that configuration loading works correctly without merge conflicts:

```sh
# Core/Transports
go version
go test ./...
go build ./transports/bifrost-http/...
```

Test configuration loading with various scenarios:
- Config file present
- Config file absent (default loading)
- Store-based configuration
- Governance and MCP configuration loading

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

No security implications - this is a merge conflict resolution that maintains existing functionality.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: add Stability AI model support for Bedrock image generation (#2180)

## Summary

Adds support for Stability AI image generation models (stability.stable-image-*) to the Bedrock provider, enabling text-to-image generation with models like stability.stable-image-core-v1:1 and stability.stable-image-ultra-v1:1.

## Changes

- Added `isStabilityAIModel()` function to detect Stability AI models by "stability." prefix
- Created `ToStabilityAIImageGenerationRequest()` to convert Bifrost requests to Stability AI's flat request format
- Implemented `StabilityAIImageGenerationRequest` type with support for prompt, mode, aspect_ratio, output_format, seed, and negative_prompt parameters
- Added conditional routing in `ImageGeneration()` to use Stability AI request format when appropriate
- Extended known fields for image generation parameters to include "aspect_ratio" and "input_images"
- Updated documentation comment to reflect Stability AI model support

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Test Stability AI image generation through the Bedrock provider:

```sh
# Core/Transports
go version
go test ./...

# Test with a Stability AI model
curl -X POST http://localhost:8080/v1/images/generations \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer your-key" \
  -d '{
    "model": "stability.stable-image-core-v1:1",
    "prompt": "A beautiful sunset over mountains",
    "aspect_ratio": "16:9",
    "output_format": "PNG"
  }'
```

Ensure AWS credentials are configured for Bedrock access and the Stability AI models are available in your region.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

No additional security implications beyond existing Bedrock provider authentication and AWS credential handling.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: add Stability AI image edit models support to Bedrock provider (#2225)

## Summary

Adds support for Stability AI image editing models in the Bedrock provider, expanding image editing capabilities beyond the existing Titan and Nova Canvas models.

## Changes

- Added `getStabilityAIEditTaskType()` function to infer edit task types from Stability AI model names (inpaint, outpaint, recolor, search-replace, erase-object, remove-bg, control-sketch, control-structure, style-guide, style-transfer, upscale-creative, upscale-conservative, upscale-fast)
- Created `ToStabilityAIImageEditRequest()` function to convert Bifrost requests to Stability AI's flat JSON format, with task-specific field validation
- Added `StabilityAIImageEditRequest` struct with comprehensive field support for all Stability AI edit operations
- Enhanced `BedrockImageGenerationResponse` with Seeds and FinishReasons fields for Stability AI compatibility
- Modified `ImageEdit()` method to route requests to appropriate conversion function based on model type
- Updated documentation to reflect expanded model support

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Test with various Stability AI edit models through the Bedrock provider:

```sh
# Core/Transports
go version
go test ./...

# Test image editing with Stability AI models
# Example: stable-image-inpaint, stable-outpaint, stable-creative-upscale, etc.
```

Verify that task-specific parameters are correctly mapped and invalid fields are filtered out based on the detected task type.

## Screenshots/Recordings

N/A - Backend functionality only

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

Image data is handled as base64-encoded strings. Mask and image parameters are properly validated before processing.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* fix: send back accumulated usage in MCP agent mode (#2246)

## Summary

This PR fixes token usage tracking in MCP agent mode by accumulating usage across all LLM calls in the agent loop and returning the total usage in the final response.

## Changes

- Added usage accumulation logic in the MCP agent execution loop to track token consumption across multiple LLM calls
- Implemented `mergeUsage` function to combine token counts and costs from multiple `BifrostLLMUsage` values, handling all detail sub-fields including prompt tokens, completion tokens, and cost breakdowns
- Extended agent API adapters with `extractUsage` and `applyUsage` methods to handle usage extraction and application for both Chat API and Responses API
- Applied accumulated usage to the final response before returning it to the client

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Test MCP agent mode with multiple tool calls to verify usage accumulation:

```sh
# Core/Transports
go version
go test ./...

# Test MCP agent mode with multiple LLM calls
# Verify that the returned usage reflects the sum of all calls in the agent loop
# Check that both token counts and cost details are properly accumulated
```

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

No security implications - this change only affects usage tracking and reporting.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* [codemode]: fixing string escape corruption, enable top-level control flow in starlark, refining the prompt of executecode tool (#2206)

## Changes

- **Enhanced Starlark dialect configuration**: Enabled top-level control flow statements (if/for/while), while loops, set() builtin, global variable reassignment, and recursive functions for a more Python-like experience
- **Improved string escape handling**: Removed automatic `\n` to newline conversion, allowing Starlark's native string escape processing to handle `\n`, `\t`, and other escape sequences correctly
- **Updated tool description**: Streamlined the executeToolCode tool description with clearer syntax notes, explicit documentation of Starlark differences from Python (no try/except, no classes, no imports, no f-strings), and emphasis on fresh isolated scope per execution
- **Enhanced error hints**: Added specific error messages for unsupported Python features like try/except/finally/raise, with guidance on alternative approaches and scope persistence warnings
- **Comprehensive test coverage**: Added tests for dialect options, string escape preservation, unsupported feature detection, and end-to-end JSON deserialization scenarios

## Type of change

- [ ] Feature
- [ ] Bug fix
- [x] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go) - Starlark CodeMode improvements
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Test the enhanced Starlark features with MCP CodeMode:

```sh
# Test dialect options (top-level control flow, while loops, etc.)
make test-mcp TESTCASE=TestStarlarkDialectOptions

# Test string escape handling
make test-mcp PATTERN=TestStarlarkStringEscape

# Test unsupported feature detection
make test-mcp PATTERN=TestStarlarkUnsupportedFeatures
```

## Breaking changes

- [ ] Yes
- [x] No

The Starlark changes are additive and maintain backward compatibility while enabling more Python-like syntax.

## Security considerations

Starlark CodeMode maintains its existing sandboxing with no additional network or filesystem access. The dialect enhancements only affect language features within the existing security boundary.

* logging in plugins (#2215)

## Summary

Reorders middleware initialization in the Bifrost HTTP server to ensure tracing middleware is added before transport interceptor middleware in the inference pipeline.

## Changes

- Moved tracing middleware initialization and setup earlier in the bootstrap process
- Reordered middleware registration so tracing middleware is prepended before transport interceptor middleware
- Updated comments to clarify the middleware ordering logic and rationale

The change ensures that tracing context and trace IDs are properly established before other middleware components process requests.

## Type of change

- [x] Bug fix
- [ ] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Verify that tracing middleware executes before transport interceptor middleware by checking trace logs and middleware execution order.

```sh
# Core/Transports
go version
go test ./...
```

Test with tracing enabled to ensure trace IDs are properly set in context before subsequent middleware processing.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

No security implications - this is a middleware ordering change that affects observability components.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* fix: handling text, vtt, srt response format for transcriptions (#2102)

* feat: add virtual key access management for MCP clients (#2255)

## Summary

Adds virtual key access management to MCP client configuration, allowing administrators to control which virtual keys can access specific MCP servers and which tools they can execute on a per-VK basis.

## Changes

- Added `vk_configs` field to MCP client update API that accepts an array of virtual key configurations
- Each VK config specifies a virtual key ID and the tools it's allowed to execute on that MCP server
- When `vk_configs` is provided, it atomically replaces all existing VK assignments for the MCP client
- Added database method `GetVirtualKeyMCPConfigsByMCPClientID` to retrieve VK configs by MCP client
- Updated OpenAPI documentation to describe the new VK configuration functionality
- Enhanced UI with virtual key access management section in the MCP client sheet
- Added Go SDK context keys for MCP tool filtering: `MCPContextKeyIncludeClients`, `MCPContextKeyIncludeTools`, and `BifrostContextKeyMCPExtraHeaders`
- Updated context keys documentation with comprehensive MCP configuration examples

## Type of change

- [x] Feature

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] UI (Next.js)
- [x] Docs

## How to test

1. Create an MCP client with tools available
2. Create virtual keys in the system
3. Update the MCP client with VK configurations:

```sh
curl -X PUT /api/mcp/client/{id} \
  -H "Content-Type: application/json" \
  -d '{
    "name": "test-client",
    "vk_configs": [
      {
        "virtual_key_id": "vk-123",
        "tools_to_execute": ["*"]
      },
      {
        "virtual_key_id": "vk-456", 
        "tools_to_execute": ["read_file", "write_file"]
      }
    ]
  }'
```

4. Verify VK assignments are created/updated in the database
5. Test the UI by opening an MCP client sheet and managing virtual key access

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

## Screenshots/Recordings

The UI now includes a "Virtual Key Access" section in the MCP client configuration sheet where administrators can:
- Add virtual keys to grant access to the MCP server
- Configure which specific tools each virtual key can execute
- Remove virtual key access entirely

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

This enables fine-grained access control for MCP servers at the virtual key level, complementing the existing governance and budgeting features.

## Security considerations

- VK access controls are enforced through the governance plugin during MCP tool execution
- The atomic replacement of VK assignments prevents partial updates that could leave the system in an inconsistent state
- Tool-level restrictions allow principle of least privilege by limiting which MCP tools each virtual key can access

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: adds option to allow MCP clients to run on all virtual keys (#2258)

## Summary

Adds a new `AllowOnAllVirtualKeys` configuration option for MCP clients that enables them to be accessible to all virtual keys without requiring explicit per-key assignment. When enabled, all tools from the MCP client are available to every virtual key.

## Changes

- Added `AllowOnAllVirtualKeys` boolean field to `MCPClientConfig` schema and database table
- Updated MCP client manager to handle the new field during client updates
- Modified governance plugin to check for clients with `AllowOnAllVirtualKeys` enabled and automatically include their tools for all virtual keys
- Added database migration to add the new column to `TableMCPClient`
- Updated UI to include a toggle for the new setting with tooltip explanation
- Added OpenAPI documentation for the new field
- Updated configuration store methods to persist and retrieve the new field

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [x] UI (Next.js)
- [x] Docs

## How to test

1. Create or update an MCP client with `allow_on_all_virtual_keys: true`
2. Verify that the client's tools are available to all virtual keys without explicit assignment
3. Test that the governance plugin correctly allows tools from such clients
4. Verify the UI toggle works correctly in the MCP client edit sheet

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

The new configuration field `allow_on_all_virtual_keys` defaults to `false` to maintain backward compatibility.

## Screenshots/Recordings

If UI changes, add before/after screenshots or short clips.

## Breaking changes

- [ ] Yes
- [x] No

This is a backward-compatible addition with the new field defaulting to `false`.

## Related issues

Link related issues and discussions. Example: Closes #123

## Security considerations

This feature reduces access control granularity by allowing MCP clients to bypass virtual key restrictions when enabled. Administrators should carefully consider which MCP clients should have this permission as it grants broad access across all virtual keys.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* feat: add provider keys CRUD to configstore and in-memory store (#2159)

## Summary

Adds dedicated CRUD operations for individual provider keys at the data layer
(configstore interface + RDB implementation) and in-memory store. This enables
key-level operations without replacing the entire provider key set, which is
required for the new `/api/providers/{provider}/keys/*` endpoints.

## Changes

- Added `GetProviderKeys`, `GetProviderKey`, `CreateProviderKey`,
  `UpdateProviderKey`, `DeleteProviderKey` to `ConfigStore` interface
- Implemented all five methods in `RDBConfigStore` with proper GORM queries,
  error handling, and `ErrNotFound` propagation
- Extracted `schemaKeyFromTableKey` and `tableKeyFromSchemaKey` helpers to
  deduplicate key conversion logic (previously inlined in `GetProvidersConfig`
  and `GetProviderConfig`)
- Added `AddProviderKey`, `UpdateProviderKey`, `RemoveProviderKey` to in-memory
  `Config` with mutex locking, DB persistence, and rollback on client update
  failure
- Added `GetProviderKeysRaw`, `GetProviderKeysRedacted`, `GetProviderKeyRaw`,
  `GetProviderKeyRedacted` read methods
- Added `TestProviderKeyCRUD` and `TestProviderKeyCRUD_ProviderMustExist`
  integration tests
- Updated `MockConfigStore` with all five new interface methods

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

```sh
# Run configstore tests
go test ./framework/configstore/... -v -run TestProviderKeyCRUD

# Run config tests (mock store)
go test ./transports/bifrost-http/lib/... -v
```

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

Key values are handled through existing redaction infrastructure. No new secret
exposure paths introduced.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* feat: add provider keys HTTP handlers and refactor optional keys (#2160)

## Summary

Adds HTTP handlers for the dedicated provider keys CRUD endpoints and removes
`keys` from provider API responses and payloads. Keys are now exclusively
managed via `/api/providers/{provider}/keys/*`. Also fixes a context timeout bug
in `ReloadProvider` where model discovery could exhaust the shared context
budget, causing subsequent DB calls to fail.

## Changes

### Provider keys handlers (`provider_keys.go`)
- New file with five handlers: `listProviderKeys`, `getProviderKey`,
  `createProviderKey`, `updateProviderKey`, `deleteProviderKey`
- Includes `mergeUpdatedKey` (redacted value preservation logic used by
  `updateProviderKey`)
- Key handlers enforce keyless provider validation and trigger model discovery
  after mutations

### Provider handlers cleanup (`providers.go`)
- Registered new key routes: `GET/POST /api/providers/{provider}/keys`,
  `GET/PUT/DELETE /api/providers/{provider}/keys/{key_id}`
- Extracted inline anonymous structs into named `providerCreatePayload` and
  `providerUpdatePayload` types (without `Keys` field)
- Removed `Keys` field from `ProviderResponse`
- Switched `addProvider` from `json.Unmarshal` to `sonic.Unmarshal`
- Removed `oldConfigRedacted` fetch and the entire key merge block
  (`mergeKeys`, `hasKeys`, `slices` usage) from `updateProvider`
- Removed `Keys` from `getProviderResponseFromConfig` response builder
- Removed unused `encoding/json` import

### Context timeout fix (`server.go`)
- Split shared `bfCtx` in `ReloadProvider` into separate contexts:
  `filteredBfCtx` (15s) for filtered `ListModelsRequest` and `unfilteredBfCtx`
  (fresh 15s) for unfiltered `ListModelsRequest`, each cancelled after use
- Changed `GetKeysByProvider` to use `context.Background()` since it's a local
  DB call that shouldn't be gated by model discovery timeouts
- Added `hasNoKeys` check to emit warn-level logs instead of errors when model
  discovery fails because no keys are configured
- Read in-memory key count via `GetProviderKeysRaw` for the `hasNoKeys` check

### Tests (`providers_test.go`)
- Cleared file (contained only tests for removed inline struct decoding)

## Type of change

- [x] Feature
- [x] Bug fix
- [x] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

```sh
# Build
go build ./transports/bifrost-http/...

# Manual: start Bifrost, then test key CRUD
curl -X POST localhost:8080/api/providers/openai/keys -d '{"name":"test-key","value":"sk-test"}'
curl localhost:8080/api/providers/openai/keys
curl -X PUT localhost:8080/api/providers/openai/keys/{key_id} -d '{"name":"updated","value":"sk-new"}'
curl -X DELETE localhost:8080/api/providers/openai/keys/{key_id}

# Verify provider endpoints no longer return keys
curl localhost:8080/api/providers/openai | jq 'has("keys")'  # should be false
```

## Screenshots/Recordings

N/A

## Breaking changes

- [x] Yes
- [ ] No

Provider API responses no longer include `keys` field. Provider create/update
payloads no longer accept `keys`. Clients must use the dedicated
`/api/providers/{provider}/keys/*` endpoints for key management.

## Related issues

N/A

## Security considerations

- Key handlers use existing redaction infrastructure (`GetProviderKeyRedacted`)
  before returning responses
- Keyless provider validation prevents key creation on providers that don't
  support keys

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* feat: migrate frontend to dedicated provider keys API (#2161)

## Summary

Migrates the frontend from reading provider keys via `provider.keys` (removed
from provider API response in PR #2160) to the dedicated `getProviderKeys`
query and `/api/keys` endpoint. Removes `keys` from all provider TypeScript
types. Key mutations patch caches from authoritative server responses; provider
updates invalidate the `ProviderKeys` tag to refresh key statuses after model
discovery. Also adds a read-only routing rule info sheet.

## Changes

### Types (`config.ts`, `schemas.ts`)
- Removed `keys` field from `ModelProviderConfig`, `AddProviderRequest`, and
  `UpdateProviderRequest`
- Added `CreateProviderKeyRequest`, `UpdateProviderKeyRequest`,
  `ListProviderKeysResponse` types

### Store (`providersApi.ts`, `baseApi.ts`)
- Added `ProviderKeys` tag type to `baseApi`
- Changed `getProviderKeys`/`getProviderKey` from `Providers` tag to
  `ProviderKeys` tag (avoids invalidating provider cache on key changes)
- Added `invalidatesTags: [ProviderKeys, DBKeys]` on `updateProvider` mutation
  (refreshes key statuses after model discovery)
- Removed `getProvider`/`getProviders` cache patches from `createProviderKey`,
  `updateProviderKey`, `deleteProviderKey` (providers no longer carry keys)
- Added duplicate-check guards on `createProviderKey` cache patches to prevent
  ghost keys
- Each key mutation patches `getProviderKeys` and `getAllKeys` caches from
  authoritative server response

### Components
- **`modelProviderKeysTableView.tsx`**: Already uses `useGetProviderKeysQuery`;
  formatting/indentation fixes
- **`page.tsx`**: Removed `keys: []` from fallback provider object and
  `createProvider` call; simplified `KeyDiscoveryFailedBadge` to only check
  provider-level status (removed per-key status check since keys are no longer
  on provider)
- **`routingRuleSheet.tsx`**: `TargetRow` now receives `allKeys` prop (from
  `useGetAllKeysQuery`) instead of `providersData` with `.keys`; filters keys
  by target provider
- **`routingRuleInfoSheet.tsx`**: New read-only sheet component that displays
  routing rule details (conditions, targets with provider icons and weight bars,
  fallback chain, scope, priority, timestamps)
- **`settingsPanel.tsx`**: Uses `useGetAllKeysQuery` to determine configured
  providers (replaces `p.keys.length > 0` check) and derive
  `providerKeyConfigs` per provider

### Other frontend changes (from prior commit, unchanged)
- Added `getProviderKeys`, `getProviderKey` RTK Query endpoints
- Added `createProviderKey`, `updateProviderKey`, `deleteProviderKey` mutations
- Added `buildProviderUpdatePayload` utility for key-free provider updates
- Migrated `providerKeyForm.tsx` to separate create/update mutations
- Updated `addNewKeySheet.tsx` props from `keyIndex` to `keyId`
- Updated all 6 provider form fragments to use `buildProviderUpdatePayload`
- Removed dead `selectedProvider.keys` sync matchers from `providerSlice.ts`

## Type of change

- [x] Feature
- [x] Refactor
- [ ] Bug fix
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (Next.js)
- [ ] Docs

## How to test

```sh
cd ui
npm run build
npm run lint
```

Manual testing:

1. Navigate to Providers page, select a provider with keys
2. Verify keys table loads correctly from dedicated API
3. Create a new key — verify it appears immediately (no ghost/duplicate)
4. Toggle enable/disable — verify switch updates immediately
5. Edit a key — verify form pre-populates, save works
6. Delete a key — verify it disappears immediately
7. Update provider settings — verify key statuses refresh after save
8. Check sidebar badge shows provider-level discovery failures
9. Open Playground settings — verify provider/key dropdowns work
10. Open Routing Rules — verify target key selector works
11. Click a routing rule row — verify info sheet opens with correct details
    (conditions, targets, fallbacks, scope, priority)

## Screenshots/Recordings

N/A — no visual changes to existing features; routing rule info sheet is new.

## Breaking changes

- [ ] Yes
- [x] No

Frontend-only changes consuming the new API shape from PR #2160.

## Related issues

N/A

## Security considerations

No new security considerations. Key values continue to be handled through
existing redaction on the backend.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* refactor: replace string slice with WhiteList type for model restrictions (#2282)

## Summary

Refactored model access control logic by replacing string slice with a dedicated `WhiteList` type for the `Models` field in `TableKey`. This change introduces a more structured approach to handling wildcard permissions and improves code readability.

## Changes

- Changed `Models` field type from `[]string` to `schemas.WhiteList` in `TableKey` struct
- Replaced manual wildcard checking (`model == "*"`) with `IsUnrestricted()` method calls across multiple functions
- Added missing mock method `GetVirtualKeyMCPConfigsByMCPClientIDs` to test configuration store
- Applied the refactoring consistently in `ReloadProvider`, `ForceReloadPricing`, and `Bootstrap` methods

## Type of change

- [x] Refactor
- [ ] Bug fix
- [ ] Feature
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Verify that model access control continues to work correctly with both wildcard and specific model permissions:

```sh
# Core/Transports
go version
go test ./...

# Test specific areas affected by the changes
go test ./framework/configstore/tables/...
go test ./transports/bifrost-http/...
```

Test scenarios should include:
- Keys with wildcard permissions (`["*"]`)
- Keys with specific model restrictions
- Keys with empty model lists (deny-by-default behavior)

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

This refactoring maintains the existing security model for API key permissions. The deny-by-default behavior and wildcard functionality remain unchanged, just implemented through a more structured type system.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* feat: add Plus icon and responsive text to pricing override create button (#2285)

## Summary

Improves the visual design and mobile responsiveness of the pricing overrides section by adding a Plus icon to the create button and optimizing the button text for different screen sizes.

## Changes

- Added Plus icon import from lucide-react
- Enhanced the "Create Override" button with a Plus icon and responsive text that shows "New Override" on larger screens and hides text on mobile
- Adjusted container spacing by removing top margin and changing flex alignment from `items-start` to `items-center` for better visual balance

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [ ] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [x] UI (Next.js)
- [ ] Docs

## How to test

Navigate to the custom pricing overrides page and verify:
1. The "New Override" button displays with a Plus icon
2. On mobile screens, only the Plus icon is visible
3. On larger screens (sm and above), both icon and "New Override" text are visible
4. The button functionality remains unchanged when clicked

```sh
# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

## Screenshots/Recordings

Before/after screenshots showing the button design changes and responsive behavior would be helpful.

## Breaking changes

- [x] Yes
- [ ] No

## Related issues

## Security considerations

No security implications - this is a purely visual enhancement.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* refactor: blacklist models on new convention (#2305)

## Summary

Implements comprehensive blacklist support for model filtering across all providers. This adds the ability to explicitly deny access to specific models at the key level, with blacklist rules taking precedence over allowlist rules.

## Changes

- Added `BlackList` type with semantic validation (supports wildcard "*" for block-all)
- Updated key selection logic to check both allowlist and blacklist constraints
- Modified all provider model listing functions to filter out blacklisted models
- Enhanced UI to support blacklist configuration with improved UX for wildcard selection
- Added blacklist filtering to model catalog and provider handlers
- Updated test cases to verify blacklist functionality

Key design decisions:
- Blacklist always wins over allowlist when conflicts occur
- Wildcard "*" in blacklist blocks all models for that key
- Empty blacklist blocks nothing (permissive default)
- Consistent filtering logic across all providers (Anthropic, Azure, Bedrock, Cohere, etc.)

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [x] Transports (HTTP)
- [x] Providers/Integrations
- [ ] Plugins
- [x] UI (Next.js)
- [x] Docs

## How to test

Test blacklist functionality with provider keys:

```sh
# Core/Transports
go version
go test ./...

# UI
cd ui
pnpm i || npm i
pnpm test || npm test
pnpm build || npm run build
```

Example configuration to test:
```json
{
  "keys": [{
    "id": "test-key",
    "models": ["*"],
    "blacklisted_models": ["gpt-4", "claude-3"]
  }]
}
```

Verify that blacklisted models are excluded from model listings and key selection.

## Screenshots/Recordings

UI now shows "Blocked Models" field with improved tooltips and wildcard handling for denying access to specific models.

## Breaking changes

- [ ] Yes
- [x] No

The `blacklisted_models` field was already present in the schema but not fully implemented. This change makes it functional without breaking existing configurations.

## Related issues

Enhances model access control capabilities for fine-grained permission management.

## Security considerations

Improves security by allowing explicit denial of access to sensitive or expensive models at the key level. Blacklist rules cannot be bypassed by allowlist configurations.

## Checklist

- [x] I read `docs/contributing/README.md` and followed the guidelines
- [x] I added/updated tests where appropriate
- [x] I updated documentation where needed
- [x] I verified builds succeed (Go and UI)
- [x] I verified the CI pipeline passes locally if applicable

* minor fix add blacklisted model field in tableKeyFromSchemaKey (#2324)

## Summary

This PR adds support for the `BlacklistedModels` field when converting schema keys to table keys in the configuration store's RDB implementation.

## Changes

- Added `BlacklistedModels: key.BlacklistedModels` field mapping in the `tableKeyFromSchemaKey` function
- Ensures that blacklisted model information is properly preserved when converting between schema and table representations

## Type of change

- [ ] Bug fix
- [x] Feature
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [ ] Plugins
- [ ] UI (Next.js)
- [ ] Docs

## How to test

Verify that configuration keys with blacklisted models are properly stored and retrieved from the RDB configstore.

```sh
# Core/Transports
go version
go test ./...
```

Test creating configuration entries with `BlacklistedModels` specified and ensure they persist correctly through the RDB layer.

## Screenshots/Recordings

N/A

## Breaking changes

- [ ] Yes
- [x] No

## Related issues

N/A

## Security considerations

None - this change only adds field mapping for existing blacklisted models functionality.

## Checklist

- [ ] I read `docs/contributing/README.md` and followed the guidelines
- [ ] I added/updated tests where appropriate
- [ ] I updated documentation where needed
- [ ] I verified builds succeed (Go and UI)
- [ ] I verified the CI pipeline passes locally if applicable

* feat: add image edit input view on logs (#2321)

## Summary

Adds support for logging image edit and image variation requests by introducing new database columns and UI components to track and display these image manipulation operations alongside existing image generation functionality.

## Changes

- Added `image_edit_input` and `image_variation_input` columns to the logs table with corresponding database migrations
- Extended the Log struct with new fields for storing and parsing image edit/variation input data
- Updated logging plugin to capture image edit and variation request data with large payload threshold handling
- Enhanced UI to display input images and prompts for image edit operations and input images for variation operations
- Added image MIME type detection for proper display of base64-encoded images in the UI

## Type of change

- [x] Feature
- [ ] Bug fix
- [ ] Refactor
- [ ] Documentation
- [ ] Chore/CI

## Affected areas

- [x] Core (Go)
- [ ] Transports (HTTP)
- [ ] Providers/Integrations
- [x] Plugins
- [x] UI (Next.js)
- [ ] Do…
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.

[Feature]: click-to-copy model name

3 participants