fix(dashboard): don't let a provider-name query hide the selected provider's models (#65374) (#65413)

Co-authored-by: Simplicio, Wesley (ext) <wesley.simplicio.ext@siemens-energy.com>
This commit is contained in:
Wesley Simplicio 2026-07-19 20:05:44 -03:00 committed by GitHub
parent b1fb3c5285
commit 07ba9e9266
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 79 additions and 2 deletions

View file

@ -11,6 +11,7 @@ import { useEffect, useMemo, useRef, useState } from "react";
import { createPortal } from "react-dom";
import { cn, themedBody } from "@/lib/utils";
import { fuzzyRank } from "@/lib/fuzzy";
import { queryMatchesProviderOnly } from "@/lib/model-picker-filter";
/**
* Two-stage model picker modal.
@ -226,15 +227,30 @@ export function ModelPickerDialog(props: Props) {
[providers, trimmedQuery],
);
// A query that matched the SELECTED provider by name/slug (not its models)
// located that provider — it shouldn't also hide that provider's models
// just because their ids don't share a substring with the provider name
// (e.g. typing "aws" to find "AWS Build" then finding zero of its Claude
// model ids contain "aws"). Fall back to an unfiltered model list in that
// case; a query that also matches a model id keeps filtering normally.
const queryMatchesSelectedProviderOnly = useMemo(
() => queryMatchesProviderOnly(selectedProvider, models, trimmedQuery),
[trimmedQuery, selectedProvider, models],
);
// Fuzzy-ranked models carrying the matched character positions so the model
// list can highlight why each entry matched.
const filteredModels = useMemo(
() =>
fuzzyRank(models, trimmedQuery, (m) => m).map((r) => ({
fuzzyRank(
models,
queryMatchesSelectedProviderOnly ? "" : trimmedQuery,
(m) => m,
).map((r) => ({
model: r.item,
positions: r.positions,
})),
[models, trimmedQuery],
[models, trimmedQuery, queryMatchesSelectedProviderOnly],
);
const canConfirm = !!selectedProvider && !!selectedModel && !applying;

View file

@ -0,0 +1,38 @@
import { describe, it, expect } from "vitest";
import { queryMatchesProviderOnly } from "./model-picker-filter";
describe("queryMatchesProviderOnly", () => {
it("returns true when the query finds the provider but no model id (issue #65374)", () => {
// Reproduces the exact case from the issue: typing "aws" locates the
// "AWS Build" provider, but none of its Claude model ids contain "aws".
const provider = { name: "AWS Build", slug: "aws-build" };
const models = ["claude-sonnet-4.5", "claude-sonnet-4", "claude-haiku-4.5"];
expect(queryMatchesProviderOnly(provider, models, "aws")).toBe(true);
});
it("returns false when the query also matches a model id — keeps normal filtering", () => {
const provider = { name: "AWS Build", slug: "aws-build" };
const models = ["claude-sonnet-4.5", "claude-sonnet-4", "claude-haiku-4.5"];
expect(queryMatchesProviderOnly(provider, models, "sonnet")).toBe(false);
});
it("returns false when the query does not match the provider at all", () => {
const provider = { name: "AWS Build", slug: "aws-build" };
const models = ["claude-sonnet-4.5"];
expect(queryMatchesProviderOnly(provider, models, "openrouter")).toBe(false);
});
it("returns false for an empty query", () => {
const provider = { name: "AWS Build", slug: "aws-build" };
const models = ["claude-sonnet-4.5"];
expect(queryMatchesProviderOnly(provider, models, "")).toBe(false);
});
it("returns false when there is no selected provider", () => {
expect(queryMatchesProviderOnly(null, ["claude-sonnet-4.5"], "aws")).toBe(false);
});
});

View file

@ -0,0 +1,23 @@
import { fuzzyScoreMulti } from "@/lib/fuzzy";
/**
* True when `trimmedQuery` located the selected provider by name/slug but
* matches none of its models by id the case where a single search box
* filtering both the provider and model columns would otherwise leave the
* model pane empty even though the user just successfully found the
* provider they were looking for.
*/
export function queryMatchesProviderOnly(
selectedProvider: { name: string; slug: string } | null,
models: readonly string[],
trimmedQuery: string,
): boolean {
if (!trimmedQuery || !selectedProvider) return false;
const matchesProvider =
fuzzyScoreMulti(`${selectedProvider.name} ${selectedProvider.slug}`, trimmedQuery) !=
null;
const matchesAnyModel = models.some((m) => fuzzyScoreMulti(m, trimmedQuery) != null);
return matchesProvider && !matchesAnyModel;
}