Skip to content

improve model search matching and highlight hits in selectors#6469

Closed
bernaferrari wants to merge 5 commits intoKilo-Org:mainfrom
bernaferrari:chore/port-pr-5726-model-search-highlight
Closed

improve model search matching and highlight hits in selectors#6469
bernaferrari wants to merge 5 commits intoKilo-Org:mainfrom
bernaferrari:chore/port-pr-5726-model-search-highlight

Conversation

@bernaferrari
Copy link
Copy Markdown
Contributor

Adapted from #5726

I'm having a hard time doing a few specific tasks with the new plugin locally (like choosing the model). Is there anything I need to do besides clicking run into the extension? Is server wired? Maybe it is using local development server on development, so I need another kilo repo to execute it?

Screen.Recording.2026-02-27.at.18.47.45.mov

Before:
image

After:

Screen.Recording.2026-02-06.at.13.09.03.mov


const word = lowerWords[wordIndex]
const token = tokens[wordIndex]
const nextPositions = new Set(currentPositions)
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.

[SUGGESTION]: Eager Set copy before checking for a match

new Set(currentPositions) is allocated on every recursive call, but when matchedInWord ends up being 0 (no prefix match in the current word), the copy is discarded and the function falls through to line 131 using the original currentPositions. Moving the allocation inside the if (matchedInWord > 0) block would avoid unnecessary copies on non-matching branches.

Suggested change
const nextPositions = new Set(currentPositions)
let matchedInWord = 0

Then build nextPositions only after the while loop confirms matchedInWord > 0.

Comment thread packages/kilo-vscode/webview-ui/agent-manager/MultiModelSelector.tsx Outdated
Comment thread packages/kilo-vscode/webview-ui/src/components/shared/ModelSelector.tsx Outdated
@kilo-code-bot
Copy link
Copy Markdown
Contributor

kilo-code-bot Bot commented Feb 27, 2026

Code Review Summary

Status: No New Issues Found | Recommendation: Address existing comments before merge

Overview

This PR replaces the simple includes()-based model search with a custom WordBoundaryFzf fuzzy matcher that supports acronym matching across word boundaries, with match-position highlighting in both the main ModelSelector and MultiModelSelector components. The implementation is clean and well-tested.

All significant issues have already been flagged in existing inline comments (11 active). No additional issues were found in this review pass.

Existing Comments Summary

Severity Count
WARNING 4
SUGGESTION 7

Key items from existing comments to address:

  • Recursive backtracking in matchAcronym without full memoization (only failures are cached)
  • Multi-word matching is order-dependent and greedy
  • WordBoundaryFzf re-instantiation on every call (mitigated by callers passing memoized finder)
  • Eager Set copy before confirming a match in the inner loop
Files Reviewed (6 files)
  • packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts - Core fuzzy matching logic (4 existing warnings/suggestions)
  • packages/kilo-vscode/webview-ui/src/components/shared/ModelSelector.tsx - Main model selector integration (1 existing suggestion)
  • packages/kilo-vscode/webview-ui/agent-manager/MultiModelSelector.tsx - Agent manager integration (1 existing suggestion)
  • packages/kilo-vscode/tests/unit/model-selector-utils.test.ts - Test coverage (1 existing suggestion)
  • packages/kilo-vscode/webview-ui/agent-manager/agent-manager.css - Highlight styles
  • packages/kilo-vscode/webview-ui/src/styles/chat.css - Highlight styles

Comment thread packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts Outdated
Comment thread packages/kilo-vscode/tests/unit/model-selector-utils.test.ts
Comment thread packages/kilo-vscode/webview-ui/src/components/shared/model-selector-utils.ts Outdated
const positions = nameMatchesByKey.get(key)

if (positions) {
result.push({ ...model, matchingPositions: positions })
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.

[WARNING]: Object spread breaks referential identity for SolidJS <For>

Every call to filterModels creates a new object via { ...model, matchingPositions: positions } for name-matched models. SolidJS's <For> uses referential identity to track items — new object identity means the framework treats these as entirely new items, tearing down and recreating DOM nodes on every keystroke rather than updating them in place.

Consider mutating a property on the original object, or using a keyed approach (e.g. <For each={...} fallback={...}> with an explicit key via <Index> or a wrapper), or returning the original model alongside positions in a way that preserves identity (e.g. a parallel Map<model, positions> instead of spreading into a new object).

}

private matchAcronym(tokens: WordToken[], query: string, startWordIndex: number): MatchResult | null {
const lowerWords = tokens.map((token) => token.word.toLowerCase())
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.

[SUGGESTION]: lowerWords is recomputed on every matchAcronym call

tokens.map(token => token.word.toLowerCase()) allocates a new array and lowercases every token word each time matchAcronym is invoked. In the multi-word query path (lines 104-113), this is called once per query word. Consider computing lowerWords once in find() (or caching it alongside the tokens) and passing it in.

const tokens = this.tokenize(text)

if (queryWords.length > 1) {
let startWordIndex = 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.

[WARNING]: Multi-word matching is order-dependent and greedy

startWordIndex only advances forward, so query words must appear in the same order as the model name tokens. For example, searching "sonnet claude" will NOT match "Claude Sonnet". Additionally, the greedy forward advancement means the first query word consumes as many tokens as possible, potentially preventing later query words from matching.

This may be intentional (ordered matching), but it could surprise users who expect word-order-independent search. Worth documenting the behavior or adding a test that explicitly asserts this constraint.

@bernaferrari bernaferrari force-pushed the chore/port-pr-5726-model-search-highlight branch from f85bc0f to f819d7b Compare February 28, 2026 03:02
@bernaferrari bernaferrari marked this pull request as draft March 1, 2026 04:47
@marius-kilocode
Copy link
Copy Markdown
Collaborator

Stale and I think this was solved differently. Thanks though, feel free to reopen if you think I am wrong

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