Skip to content

chore: enhanced model selector and improved filter UI - #2304

Merged
smakosh merged 3 commits into
theopenco:mainfrom
amelitoalcuitas:feat/model-selector-enhancement
May 16, 2026
Merged

smakosh merged 3 commits into
theopenco:mainfrom
amelitoalcuitas:feat/model-selector-enhancement

Conversation

@amelitoalcuitas

@amelitoalcuitas amelitoalcuitas commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features

    • Filter models by active provider keys in the model selector.
    • Selected models are now remembered for chat, image, and video pages.
    • Added an endpoint to list active provider keys for provider-aware features.
  • Improvements

    • Better handling and display for the special "auto" model in the selector and previews.
    • Improved provider key validation to favor models that support image/video/embed workflows.

Review Change Stack

@coderabbitai

coderabbitai Bot commented May 16, 2026 •

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b20fa70d-5fcb-457c-aa52-d1ee10c36097

📥 Commits

Reviewing files that changed from the base of the PR and between 0759594 and 770e3d2.

📒 Files selected for processing (5)
  • apps/api/src/routes/keys-provider.ts
  • apps/playground/src/components/model-selector.tsx
  • apps/playground/src/components/playground/chat-page-client.tsx
  • apps/playground/src/components/playground/image-page-client.tsx
  • apps/playground/src/components/playground/video-page-client.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • apps/playground/src/components/playground/image-page-client.tsx
  • apps/api/src/routes/keys-provider.ts
  • apps/playground/src/components/model-selector.tsx

Walkthrough

This PR adds provider-key-aware model filtering to the playground's model selector, persists selected models in localStorage across chat/image/video pages, exposes an API endpoint to list active provider keys, and refines validation to exclude embedding-capable models.

Changes

Provider-Key-Aware Model Selection

Layer / File(s) Summary
Backend API endpoint for active provider keys
apps/api/src/routes/keys-provider.ts
New GET /provider/active route returns provider keys with provider and nullable status, authenticated via user context and filtered by the user's active organizations.
Filter state and provider keys data fetching
apps/playground/src/components/model-selector.tsx
Adds showOnlyWithKeys to FilterState, imports useIsMobile and useApi, and fetches active provider keys producing a memoized providersWithKeys set used for filtering.
Model entry construction with auto model handling
apps/playground/src/components/model-selector.tsx
Ensures auto is inserted first as a root entry with normalized search text and avoids creating provider/mapping entries for auto.
Filter application and management
apps/playground/src/components/model-selector.tsx
Applies showOnlyWithKeys to root and non-root entries (excluding deactivated mappings), and wires the flag into clearFilters and hasActiveFilters.
Filter UI and mobile-responsive popover
apps/playground/src/components/model-selector.tsx
Makes popover positioning mobile-aware and adds a conditional "Show only providers with keys" switch when providers with keys exist.
Row layout and section spacing adjustments
apps/playground/src/components/model-selector.tsx
Switches root/provider headers to flex-based layout; updates command input, Capabilities, and Price Range spacing/classes.
Preview panel rendering for auto model
apps/playground/src/components/model-selector.tsx
Desktop preview shows "-" for auto family label and hides the capabilities block when auto is previewed.

Model Selection Persistence Across Pages

Layer / File(s) Summary
Chat page model persistence
apps/playground/src/components/playground/chat-page-client.tsx
Adds CHAT_MODEL_KEY, lazily initializes selected model from URL or localStorage (fallback auto), and persists selection to localStorage on changes.
Image page model persistence
apps/playground/src/components/playground/image-page-client.tsx
Adds IMAGE_MODEL_KEY, reads comma-separated models from localStorage when URL params absent, and persists non-empty selections back to localStorage.
Video page model persistence
apps/playground/src/components/playground/video-page-client.tsx
Adds VIDEO_MODEL_KEY, initializes selectedModels from URL or localStorage fallback, and persists non-empty selections to localStorage on change.

Validation Model Selection

Layer / File(s) Summary
Exclude embedding models from validation
packages/actions/src/validate-provider-key.ts
getValidationModel now disqualifies provider mappings that support embeddings in addition to other capability checks, narrowing the set of models usable for provider key validation.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • theopenco/llmgateway#2267: Related changes to apps/playground/src/components/playground/chat-page-client.tsx around selected model initialization and persistence.
  • theopenco/llmgateway#2111: Related to preserving the user's selected model in chat page flows and request building.

Suggested reviewers

  • steebchen
  • smakosh
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'enhanced model selector and improved filter UI' partially captures the changes, but the PR includes significant backend work (new API route, provider key validation changes) and localStorage persistence across multiple pages that go beyond just model selector enhancement. Consider a more comprehensive title that reflects both the model selector UI enhancements and the backend API additions, such as 'feat: add provider keys API endpoint and enhance model selector with filtering and persistence'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 4

Caution

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

⚠️ Outside diff range comments (1)
apps/playground/src/components/playground/chat-page-client.tsx (1)

276-290: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Use lazy initialization and add error handling for localStorage access.

useState(getInitialModel()) executes getInitialModel on every render; use a function initializer instead. Also, both localStorage.getItem and localStorage.setItem calls lack error handling and can throw in restricted browser contexts (e.g., private browsing mode).

Proposed fix
-	const [selectedModel, setSelectedModel] = useState(getInitialModel());
+	const [selectedModel, setSelectedModel] = useState(() => getInitialModel());
 	const getInitialModel = () => {
 		const modelFromUrl = searchParams.get("model");
 		if (modelFromUrl) {
 			return modelFromUrl;
 		}
-		if (typeof window !== "undefined") {
-			const stored = localStorage.getItem(CHAT_MODEL_KEY);
-			if (stored) {
-				return stored;
-			}
+		if (typeof window !== "undefined") {
+			try {
+				const stored = localStorage.getItem(CHAT_MODEL_KEY);
+				if (stored) {
+					return stored;
+				}
+			} catch {
+				// ignore storage access failures
+			}
 		}
 		return "auto";
 	};
 	useEffect(() => {
-		if (selectedModel) {
-			localStorage.setItem(CHAT_MODEL_KEY, selectedModel);
-		}
+		if (!selectedModel) {
+			return;
+		}
+		try {
+			localStorage.setItem(CHAT_MODEL_KEY, selectedModel);
+		} catch {
+			// ignore storage access failures
+		}
 	}, [selectedModel]);

Also applies to: 1345–1349

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/playground/src/components/playground/chat-page-client.tsx` around lines
276 - 290, Replace the eager call to getInitialModel in useState with a lazy
initializer and wrap all localStorage accesses in try/catch (and guard with
typeof window !== "undefined" and window.localStorage) to avoid exceptions in
restricted browsers; specifically update the useState(initializer) for
selectedModel to use a function that calls getInitialModel lazily, and modify
getInitialModel (and any localStorage.setItem/getItem usages such as those
referencing CHAT_MODEL_KEY) to catch/storage errors and fall back to "auto" (or
silently ignore writes) while returning a safe default; apply the same pattern
to the other occurrence referenced in the comment.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/api/src/routes/keys-provider.ts`:
- Around line 391-400: The DB query that populates providerKeys via
db.query.providerKey.findMany is missing a filter on the status field, so
inactive/deleted keys are returned; update the where clause to include a status
equality filter (e.g., status: 'ACTIVE' or the project's active enum value) so
only active provider keys are fetched, keeping provider and status in columns as
before.

In `@apps/playground/src/components/model-selector.tsx`:
- Around line 1077-1085: The root-entry filtering for filters.showOnlyWithKeys
currently checks all e.model.mappings when deciding visibility, which can
include deactivated mappings; update the filter to only consider active/usable
mappings the same way non-root entries do: inside the list.filter callback for
entries where e.isRoot, change the predicate to check e.model.mappings for an
active mapping (e.g., a mapping property like isActive/active flag or the same
presence test used for e.mapping) and then confirm
providersWithKeys.has(mapping.providerId) for that active mapping; keep the
existing non-root branch that uses e.mapping and providersWithKeys unchanged so
both root and non-root use consistent active-mapping logic (reference:
filters.showOnlyWithKeys, e.isRoot, e.model.mappings, providersWithKeys,
e.mapping).

In `@apps/playground/src/components/playground/image-page-client.tsx`:
- Around line 90-98: Wrap all localStorage accesses in a try-catch to avoid
throwing in privacy/restricted contexts: around the block that reads
IMAGE_MODEL_KEY (the current if (typeof window !== "undefined") { const stored =
localStorage.getItem(IMAGE_MODEL_KEY); ... } ) and the other read/write spots
referenced (lines ~219-223), catch any errors and fall back to a safe default
(e.g., return [] or ignore the write). Ensure you still check typeof window !==
"undefined" but perform getItem/setItem inside try-catch so failures in
private/iframe contexts degrade gracefully.

In `@apps/playground/src/components/playground/video-page-client.tsx`:
- Around line 101-109: The new localStorage access for VIDEO_MODEL_KEY needs the
same defensive try/catch used for VIDEO_GALLERY_KEY: wrap the retrieval (the
getItem + split/filter logic that builds `models`) and any saves (setItem where
models are written back) in try/catch blocks, returning a safe default (empty
array) on error and logging or silently ignoring quota/private-mode errors;
update the code paths that read VIDEO_MODEL_KEY and that persist it (the
model-loading logic that returns `models` and the model-saving code) to use
these guarded storage operations.

---

Outside diff comments:
In `@apps/playground/src/components/playground/chat-page-client.tsx`:
- Around line 276-290: Replace the eager call to getInitialModel in useState
with a lazy initializer and wrap all localStorage accesses in try/catch (and
guard with typeof window !== "undefined" and window.localStorage) to avoid
exceptions in restricted browsers; specifically update the useState(initializer)
for selectedModel to use a function that calls getInitialModel lazily, and
modify getInitialModel (and any localStorage.setItem/getItem usages such as
those referencing CHAT_MODEL_KEY) to catch/storage errors and fall back to
"auto" (or silently ignore writes) while returning a safe default; apply the
same pattern to the other occurrence referenced in the comment.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 40b22295-d171-43ef-ad00-eda4923db6cc

📥 Commits

Reviewing files that changed from the base of the PR and between 0157762 and 0759594.

⛔ Files ignored due to path filters (4)
  • apps/code/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/playground/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • apps/ui/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
  • ee/admin/src/lib/api/v1.d.ts is excluded by !**/v1.d.ts
📒 Files selected for processing (6)
  • apps/api/src/routes/keys-provider.ts
  • apps/playground/src/components/model-selector.tsx
  • apps/playground/src/components/playground/chat-page-client.tsx
  • apps/playground/src/components/playground/image-page-client.tsx
  • apps/playground/src/components/playground/video-page-client.tsx
  • packages/actions/src/validate-provider-key.ts

Comment thread apps/api/src/routes/keys-provider.ts
Comment thread apps/playground/src/components/model-selector.tsx
Comment thread apps/playground/src/components/playground/image-page-client.tsx Outdated
Comment thread apps/playground/src/components/playground/video-page-client.tsx Outdated
@smakosh
smakosh enabled auto-merge May 16, 2026 16:17
@smakosh
smakosh added this pull request to the merge queue May 16, 2026
Merged via the queue into theopenco:main with commit ed8d55f May 16, 2026
10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants