Fix model selector fuzzy search to match provider and support multi-token queries

This commit is contained in:
Mario Zechner 2025-12-15 18:05:32 +01:00
parent 7272eb9274
commit 3de8e0757d
3 changed files with 36 additions and 7 deletions

View file

@ -2,6 +2,10 @@
## [Unreleased]
### Fixed
- Model selector fuzzy search now matches against provider name (not just model ID) and supports space-separated tokens where all tokens must match
## [0.21.0] - 2025-12-14
### Added

View file

@ -115,7 +115,7 @@ export class ModelSelectorComponent extends Container {
}
private filterModels(query: string): void {
this.filteredModels = fuzzyFilter(this.allModels, query, ({ id }) => id);
this.filteredModels = fuzzyFilter(this.allModels, query, ({ id, provider }) => `${id} ${provider}`);
this.selectedIndex = Math.min(this.selectedIndex, Math.max(0, this.filteredModels.length - 1));
this.updateList();
}

View file

@ -61,23 +61,48 @@ export function fuzzyMatch(query: string, text: string): FuzzyMatch {
}
// Filter and sort items by fuzzy match quality (best matches first)
// Supports space-separated tokens: all tokens must match, sorted by match count then score
export function fuzzyFilter<T>(items: T[], query: string, getText: (item: T) => string): T[] {
if (!query.trim()) {
return items;
}
const results: { item: T; score: number }[] = [];
// Split query into tokens
const tokens = query
.trim()
.split(/\s+/)
.filter((t) => t.length > 0);
if (tokens.length === 0) {
return items;
}
const results: { item: T; totalScore: number }[] = [];
for (const item of items) {
const text = getText(item);
const match = fuzzyMatch(query, text);
if (match.matches) {
results.push({ item, score: match.score });
let totalScore = 0;
let allMatch = true;
// Check each token against the text - ALL must match
for (const token of tokens) {
const match = fuzzyMatch(token, text);
if (match.matches) {
totalScore += match.score;
} else {
allMatch = false;
break;
}
}
// Only include if all tokens match
if (allMatch) {
results.push({ item, totalScore });
}
}
// Sort ascending by score (lower = better match)
results.sort((a, b) => a.score - b.score);
// Sort by score (asc, lower is better)
results.sort((a, b) => a.totalScore - b.totalScore);
return results.map((r) => r.item);
}