(tool: SearchableTool, query: string)
| 602 | }; |
| 603 | |
| 604 | const scoreToolMatch = (tool: SearchableTool, query: string): ToolDiscoveryResult | null => { |
| 605 | const normalizedQuery = normalizeSearchText(query); |
| 606 | const queryTokens = tokenizeSearchText(query); |
| 607 | |
| 608 | if (normalizedQuery.length === 0 || queryTokens.length === 0) { |
| 609 | return null; |
| 610 | } |
| 611 | |
| 612 | const path = prepareField(tool.path); |
| 613 | const integration = prepareField(tool.integration); |
| 614 | const name = prepareField(tool.name); |
| 615 | const description = prepareField(tool.description); |
| 616 | |
| 617 | const fieldScores = [ |
| 618 | scorePreparedField(normalizedQuery, queryTokens, path, SEARCH_FIELD_WEIGHTS.path), |
| 619 | scorePreparedField(normalizedQuery, queryTokens, integration, SEARCH_FIELD_WEIGHTS.integration), |
| 620 | scorePreparedField(normalizedQuery, queryTokens, name, SEARCH_FIELD_WEIGHTS.name), |
| 621 | scorePreparedField(normalizedQuery, queryTokens, description, SEARCH_FIELD_WEIGHTS.description), |
| 622 | ]; |
| 623 | |
| 624 | const matchedTokens = new Set<string>(); |
| 625 | let score = 0; |
| 626 | let exactPhraseMatch = false; |
| 627 | |
| 628 | for (const fieldScore of fieldScores) { |
| 629 | score += fieldScore.score; |
| 630 | exactPhraseMatch ||= fieldScore.exactPhraseMatch; |
| 631 | for (const token of fieldScore.matchedTokens) { |
| 632 | matchedTokens.add(token); |
| 633 | } |
| 634 | } |
| 635 | |
| 636 | if (matchedTokens.size === 0) { |
| 637 | return null; |
| 638 | } |
| 639 | |
| 640 | const coverage = matchedTokens.size / queryTokens.length; |
| 641 | const minimumCoverage = queryTokens.length <= 2 ? 1 : 0.6; |
| 642 | |
| 643 | if (coverage < minimumCoverage && !exactPhraseMatch) { |
| 644 | return null; |
| 645 | } |
| 646 | |
| 647 | if (coverage === 1) { |
| 648 | score += 25; |
| 649 | } else { |
| 650 | score += Math.round(coverage * 10); |
| 651 | } |
| 652 | |
| 653 | if (path.tokens[0] === queryTokens[0] || name.tokens[0] === queryTokens[0]) { |
| 654 | score += 8; |
| 655 | } |
| 656 | |
| 657 | if ( |
| 658 | normalizeSearchText(tool.path) === normalizedQuery || |
| 659 | normalizeSearchText(tool.name) === normalizedQuery |
| 660 | ) { |
| 661 | score += 20; |
no test coverage detected