(tool: SearchableTool, query: string)
| 573 | }; |
| 574 | |
| 575 | const scoreToolMatch = (tool: SearchableTool, query: string): ToolDiscoveryResult | null => { |
| 576 | const normalizedQuery = normalizeSearchText(query); |
| 577 | const queryTokens = tokenizeSearchText(query); |
| 578 | |
| 579 | if (normalizedQuery.length === 0 || queryTokens.length === 0) { |
| 580 | return null; |
| 581 | } |
| 582 | |
| 583 | const path = prepareField(tool.path); |
| 584 | const integration = prepareField(tool.integration); |
| 585 | const name = prepareField(tool.name); |
| 586 | const description = prepareField(tool.description); |
| 587 | |
| 588 | const fieldScores = [ |
| 589 | scorePreparedField(normalizedQuery, queryTokens, path, SEARCH_FIELD_WEIGHTS.path), |
| 590 | scorePreparedField(normalizedQuery, queryTokens, integration, SEARCH_FIELD_WEIGHTS.integration), |
| 591 | scorePreparedField(normalizedQuery, queryTokens, name, SEARCH_FIELD_WEIGHTS.name), |
| 592 | scorePreparedField(normalizedQuery, queryTokens, description, SEARCH_FIELD_WEIGHTS.description), |
| 593 | ]; |
| 594 | |
| 595 | const matchedTokens = new Set<string>(); |
| 596 | let score = 0; |
| 597 | let exactPhraseMatch = false; |
| 598 | |
| 599 | for (const fieldScore of fieldScores) { |
| 600 | score += fieldScore.score; |
| 601 | exactPhraseMatch ||= fieldScore.exactPhraseMatch; |
| 602 | for (const token of fieldScore.matchedTokens) { |
| 603 | matchedTokens.add(token); |
| 604 | } |
| 605 | } |
| 606 | |
| 607 | if (matchedTokens.size === 0) { |
| 608 | return null; |
| 609 | } |
| 610 | |
| 611 | const coverage = matchedTokens.size / queryTokens.length; |
| 612 | const minimumCoverage = queryTokens.length <= 2 ? 1 : 0.6; |
| 613 | |
| 614 | if (coverage < minimumCoverage && !exactPhraseMatch) { |
| 615 | return null; |
| 616 | } |
| 617 | |
| 618 | if (coverage === 1) { |
| 619 | score += 25; |
| 620 | } else { |
| 621 | score += Math.round(coverage * 10); |
| 622 | } |
| 623 | |
| 624 | if (path.tokens[0] === queryTokens[0] || name.tokens[0] === queryTokens[0]) { |
| 625 | score += 8; |
| 626 | } |
| 627 | |
| 628 | if ( |
| 629 | normalizeSearchText(tool.path) === normalizedQuery || |
| 630 | normalizeSearchText(tool.name) === normalizedQuery |
| 631 | ) { |
| 632 | score += 20; |
no test coverage detected