Skip to content

Commit a16e624

Browse files
afmire877ahmed-mireclaudevercel[bot]
authored
fix: relax search token matching to require at least one match (#27)
* fix: relax search token matching to require at least one match The search was requiring ALL query tokens to exist in the skill's displayName, slug, or summary. This was too strict and caused valid results to be filtered out. For example, searching "HTTP API client" would fail to match skills about "HTTP API" that didn't mention "client". Changed from `.every()` to `.some()` so at least one token must match, allowing the vector similarity to determine relevance for the rest. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix: update matchesExactTokens to require prefix matching for query tokens * more inclusive token check * Update convex/lib/searchText.ts Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com> --------- Co-authored-by: Ahmed <ahmed.mire@kaluza.com> Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com> Co-authored-by: vercel[bot] <35613825+vercel[bot]@users.noreply.github.com>
1 parent decce1d commit a16e624

File tree

2 files changed

+20
-4
lines changed

2 files changed

+20
-4
lines changed

convex/lib/searchText.test.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,26 @@ describe('searchText', () => {
1313
])
1414
})
1515

16-
it('matchesExactTokens requires all query tokens', () => {
16+
it('matchesExactTokens requires at least one query token to prefix-match', () => {
1717
const queryTokens = tokenize('Remind Me')
1818
expect(matchesExactTokens(queryTokens, ['Remind Me', '/remind-me', 'Short summary'])).toBe(true)
19+
// "Reminder" starts with "remind", so it matches with prefix matching
1920
expect(matchesExactTokens(queryTokens, ['Reminder tool', '/reminder', 'Short summary'])).toBe(
20-
false,
21+
true,
2122
)
23+
// Matches because "remind" token is present
24+
expect(matchesExactTokens(queryTokens, ['Remind tool', '/remind', 'Short summary'])).toBe(true)
25+
// No matching tokens at all
26+
expect(matchesExactTokens(queryTokens, ['Other tool', '/other', 'Short summary'])).toBe(false)
27+
})
28+
29+
it('matchesExactTokens supports prefix matching for partial queries', () => {
30+
// "go" should match "gohome" because "gohome" starts with "go"
31+
expect(matchesExactTokens(['go'], ['GoHome', '/gohome', 'Navigate home'])).toBe(true)
32+
// "pad" should match "padel"
33+
expect(matchesExactTokens(['pad'], ['Padel', '/padel', 'Tennis-like sport'])).toBe(true)
34+
// "xyz" should not match anything
35+
expect(matchesExactTokens(['xyz'], ['GoHome', '/gohome', 'Navigate home'])).toBe(false)
2236
})
2337

2438
it('matchesExactTokens ignores empty inputs', () => {

convex/lib/searchText.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,10 @@ export function matchesExactTokens(
1818
if (!text) return false
1919
const textTokens = tokenize(text)
2020
if (textTokens.length === 0) return false
21-
const textSet = new Set(textTokens)
22-
return queryTokens.every((token) => textSet.has(token))
21+
// Require at least one token to prefix-match, allowing vector similarity to determine relevance
22+
return queryTokens.some((queryToken) =>
23+
textTokens.some((textToken) => textToken.includes(queryToken)),
24+
)
2325
}
2426

2527
export const __test = { normalize, tokenize, matchesExactTokens }

0 commit comments

Comments
 (0)