(tool: SearchableTool, query: string)
| 535 | }; |
| 536 | |
| 537 | const scoreToolMatch = (tool: SearchableTool, query: string): ToolDiscoveryResult | null => { |
| 538 | const normalizedQuery = normalizeSearchText(query); |
| 539 | const queryTokens = tokenizeSearchText(query); |
| 540 | |
| 541 | if (normalizedQuery.length === 0 || queryTokens.length === 0) { |
| 542 | return null; |
| 543 | } |
| 544 | |
| 545 | const path = prepareField(tool.path); |
| 546 | const integration = prepareField(tool.integration); |
| 547 | const name = prepareField(tool.name); |
| 548 | const description = prepareField(tool.description); |
| 549 | |
| 550 | const fieldScores = [ |
| 551 | scorePreparedField(normalizedQuery, queryTokens, path, SEARCH_FIELD_WEIGHTS.path), |
| 552 | scorePreparedField(normalizedQuery, queryTokens, integration, SEARCH_FIELD_WEIGHTS.integration), |
| 553 | scorePreparedField(normalizedQuery, queryTokens, name, SEARCH_FIELD_WEIGHTS.name), |
| 554 | scorePreparedField(normalizedQuery, queryTokens, description, SEARCH_FIELD_WEIGHTS.description), |
| 555 | ]; |
| 556 | |
| 557 | const matchedTokens = new Set<string>(); |
| 558 | let score = 0; |
| 559 | let exactPhraseMatch = false; |
| 560 | |
| 561 | for (const fieldScore of fieldScores) { |
| 562 | score += fieldScore.score; |
| 563 | exactPhraseMatch ||= fieldScore.exactPhraseMatch; |
| 564 | for (const token of fieldScore.matchedTokens) { |
| 565 | matchedTokens.add(token); |
| 566 | } |
| 567 | } |
| 568 | |
| 569 | if (matchedTokens.size === 0) { |
| 570 | return null; |
| 571 | } |
| 572 | |
| 573 | const coverage = matchedTokens.size / queryTokens.length; |
| 574 | const minimumCoverage = queryTokens.length <= 2 ? 1 : 0.6; |
| 575 | |
| 576 | if (coverage < minimumCoverage && !exactPhraseMatch) { |
| 577 | return null; |
| 578 | } |
| 579 | |
| 580 | if (coverage === 1) { |
| 581 | score += 25; |
| 582 | } else { |
| 583 | score += Math.round(coverage * 10); |
| 584 | } |
| 585 | |
| 586 | if (path.tokens[0] === queryTokens[0] || name.tokens[0] === queryTokens[0]) { |
| 587 | score += 8; |
| 588 | } |
| 589 | |
| 590 | if ( |
| 591 | normalizeSearchText(tool.path) === normalizedQuery || |
| 592 | normalizeSearchText(tool.name) === normalizedQuery |
| 593 | ) { |
| 594 | score += 20; |
no test coverage detected