Skip to content

Improve search discovery signals - #252

Merged
kentcdodds merged 11 commits into
mainfrom
cursor/improve-search-discovery-3c36
Apr 22, 2026
Merged

kentcdodds merged 11 commits into
mainfrom
cursor/improve-search-discovery-3c36

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Apr 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • merge the branch onto the latest main and resolve the packages/worker/src/package-registry/source.ts conflict by rebasing the search/manifest-only improvements onto main's new published-source architecture
  • enrich saved package search rows with manifest-derived exports, jobs, and app entry data across MCP search and agent-turn search
  • improve action-oriented discovery with richer package/connector search documents and recommended next-step guidance in search results, while keeping the logic connector-agnostic instead of baking production-only connector aliases into code
  • address valid review feedback by surfacing fallback package-search warnings, reusing connector query embeddings, tightening combined package+connector guidance to related matches only, correctly propagating per-package fallback warnings through search loaders, restoring a true manifest-only published-source path for the search hot path, and consolidating duplicate source-loader lifecycle logic where appropriate
  • stabilize the failing Cloudflare artifacts mock unit test by aligning its test timeout with the mock startup budget
  • extend focused tests to cover richer package projections, Spotify-style discovery behavior, fallback warning behavior, warning propagation, published manifest-only loading, and the merged package-source loader behavior

Testing

  • npm exec vitest run --project node-unit packages/worker/src/repo/artifacts-mock-cloudflare.node.test.ts
  • npm run test -- --run packages/worker/src/repo/published-source.node.test.ts packages/worker/src/package-registry/source.node.test.ts packages/worker/src/mcp/tools/search.node.test.ts packages/worker/src/mcp/tools/search-format.node.test.ts
  • npm run typecheck
  • npx oxlint packages/worker/src/repo/published-source.ts packages/worker/src/repo/published-source.node.test.ts packages/worker/src/package-registry/source.ts packages/worker/src/package-registry/source.node.test.ts packages/worker/src/mcp/tools/search.ts packages/worker/src/mcp/tools/search.node.test.ts packages/worker/src/mcp/tools/search-format.node.test.ts packages/worker/src/mcp/tools/search-format.ts packages/worker/src/agent-turn/tools.ts packages/worker/src/package-registry/manifest.ts packages/worker/src/package-registry/embed.ts packages/worker/src/repo/artifacts-mock-cloudflare.node.test.ts
Open in Web Open in Cursor 

Summary by CodeRabbit

Release Notes

  • New Features

    • Search results now display guidance with "Recommended next step" actions for packages and connectors
    • Enhanced connector search with improved keyword matching and relevance scoring
  • Improvements

    • Better package search accuracy with improved app entry detection
    • More robust handling of package metadata in search results

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@coderabbitai

coderabbitai Bot commented Apr 22, 2026 •

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

The changes introduce guidance generation and recommended next steps for search results. A new buildSavedPackageSearchRows helper processes saved packages with fallback error handling. Search formatting extended with optional guidance and nextStep fields, and a new PackageSearchProjection type consolidates package metadata and document building logic.

Changes

Cohort / File(s) Summary
Search Tool Core
packages/worker/src/agent-turn/tools.ts, packages/worker/src/mcp/tools/search.ts
Updated search tool preprocessing to use new buildSavedPackageSearchRows helper for saved packages. Extended search result payload with optional guidance field computed by buildRecommendedNextStep. Added vector similarity scoring for connectors and expanded connector aliases with well-known names and API base URL tokens.
Search Format & Types
packages/worker/src/mcp/tools/search-format.ts, packages/worker/src/package-registry/manifest.ts
Added guidance?: string to search result types. Introduced nextStep?: string for package and connector matches. Added new PackageSearchProjection type and buildPackageSearchDocument function. Updated formatSearchMarkdown to render "## Recommended next step" section when guidance is present.
Package Registry
packages/worker/src/package-registry/embed.ts
Refactored buildSavedPackageEmbedText to delegate to buildPackageSearchProjection and buildPackageSearchDocument builders instead of inline formatting logic.
Tests
packages/worker/src/mcp/tools/search-format.node.test.ts, packages/worker/src/mcp/tools/search.node.test.ts
Updated format tests to validate guidance and recommended next step section in markdown output. Added test fixtures with appEntry field. Added integration test verifying searchUnified returns guidance for matched saved packages and connectors. Added test for buildSavedPackageSearchRows error handling with fallback projections.

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant Tool as Search Tool
    participant Handler as searchUnified
    participant Registry as Package Registry
    participant Formatter as Search Formatter
    
    Client->>Tool: search(query)
    Tool->>Handler: searchUnified(query, savedPackages)
    Handler->>Registry: buildSavedPackageSearchRows(records)
    Registry->>Registry: buildPackageSearchProjection(manifest)
    Registry-->>Handler: PackageSearchRow[]
    Handler->>Handler: Match packages & connectors
    Handler->>Handler: buildRecommendedNextStep(matches)
    Handler-->>Tool: SearchUnifiedResult {matches, guidance}
    Tool->>Formatter: formatSearchMarkdown({matches, guidance})
    Formatter->>Formatter: toSlimStructuredMatches(matches)
    Formatter->>Formatter: Render "## Recommended next step"
    Formatter-->>Tool: Markdown output
    Tool-->>Client: Formatted search results
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Poem

🐰 Hoppy searches now guide the way,
With nextStep hints to help you play,
Saved packages project with care,
Guidance glows when matches are there! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Improve search discovery signals' directly relates to the main objective of the PR, which enriches search with better discovery signals including manifest data, aliases, guidance, and next-step recommendations.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch cursor/improve-search-discovery-3c36

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
@kentcdodds
kentcdodds marked this pull request as ready for review April 22, 2026 00:45
@github-actions

github-actions Bot commented Apr 22, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Preview deployed: https://kody-pr-252.kentcdodds.workers.dev

Worker: kody-pr-252
D1: kody-pr-252-db
KV: kody-pr-252-oauth-kv

Mocks:

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
packages/worker/src/mcp/tools/search.ts (2)

198-218: Hardcoded alias map won't scale beyond the three seeded connectors.

wellKnownConnectorAliases is a closed, in-code record with only spotify, github, tesla. Any new saved connector (slack, notion, linear, etc.) gets zero discovery boost from aliases until this map is manually extended — easy to forget, and the data belongs with connector definitions rather than search internals. Consider sourcing aliases from the connector config itself (e.g., an optional aliases: string[] field on ConnectorConfig) or a separate module co-located with connector-shared types so adding a connector is one-touch.

Not blocking for this PR, but worth a follow-up issue.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/worker/src/mcp/tools/search.ts` around lines 198 - 218, The
hardcoded wellKnownConnectorAliases map and getConnectorAliases function make
alias data non-extensible; instead update search logic to read aliases from
connector configs (e.g., add an optional aliases: string[] to ConnectorConfig or
a connector metadata module) and fall back to the existing
wellKnownConnectorAliases only if no config-provided aliases exist.
Specifically, modify getConnectorAliases to accept or look up the
ConnectorConfig for the given connectorName (or load connector metadata) and
return config.aliases when present, otherwise return
wellKnownConnectorAliases[connectorName.toLowerCase()] ?? []; ensure any
consumers of getConnectorAliases (search-related code) still receive an array
and add unit tests for a connector with and without aliases.

705-763: Recompute of deterministicEmbedding(input.query) per connector row.

Unlike buildCapabilityCandidates and buildPackageCandidates, which accept a precomputed queryEmbedding, buildConnectorCandidates recomputes deterministicEmbedding(input.query) inside the flatMap for every value row — even for rows that ultimately return [] because parseConnectorValueName/parseConnectorConfig reject them. For users with many saved values this is unnecessary work on a hot path. Accept queryEmbedding like the other builders for consistency and cost savings.

♻️ Proposed refactor
 function buildConnectorCandidates(input: {
 	query: string
 	rows: Array<ValueMetadata>
+	queryEmbedding: ReadonlyArray<number>
 }): Array<SearchCandidate> {
 	return input.rows
 		.flatMap((row) => {
 			...
 			const lexical = lexicalScore(input.query, document)
 			const vector = cosineSimilarity(
-				deterministicEmbedding(input.query),
+				input.queryEmbedding,
 				deterministicEmbedding(document),
 			)

And in searchUnified:

 		...buildConnectorCandidates({
 			query: intent.normalizedQuery,
 			rows: input.optionalRows.userValueRows,
+			queryEmbedding,
 		}),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/worker/src/mcp/tools/search.ts` around lines 705 - 763,
buildConnectorCandidates recomputes deterministicEmbedding(input.query) per row
which is wasteful; change buildConnectorCandidates to accept a precomputed
queryEmbedding (like buildCapabilityCandidates/buildPackageCandidates) and use
that for cosineSimilarity instead of calling deterministicEmbedding inside the
flatMap, update the call sites (e.g., searchUnified) to compute const
queryEmbedding = deterministicEmbedding(query) once and pass it into
buildConnectorCandidates, and ensure the new signature (e.g.,
buildConnectorCandidates(input: {query: string; rows: Array<ValueMetadata>;
queryEmbedding: number[]}) or similar) is used everywhere so the embedding is
not recomputed for rows that are filtered out by
parseConnectorValueName/parseConnectorConfig.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/worker/src/mcp/tools/search.ts`:
- Around line 153-167: The fallback projection breaks the invariant that hasApp
=== (appEntry !== null); in buildFallbackPackageSearchProjection you should
derive hasApp from the same signal as the regular projection (i.e., from
appEntry) — since this fallback forces appEntry: null, set hasApp: false to
preserve the invariant and avoid downstream mismatch with buildPackageCandidates
and buildPackageSearchDocument; if you intentionally want to keep record.hasApp
despite a null appEntry, add a clear comment explaining the divergence and
update buildPackageSearchDocument/buildPackageCandidates to handle hasApp &&
!appEntry consistently.
- Around line 169-196: buildSavedPackageSearchRows currently swallows all errors
from loadPackageSourceBySourceId; change the catch to capture and surface the
failure: in the catch block call your observability utility (e.g.
Sentry.captureException(error) or logMcpEvent with a warning outcome) and attach
a warning string for that record to the returned result instead of silently
returning only the fallback projection; update the function return shape (or
wrap results in OptionalSearchRowsResult) so callers receive both the projection
(built via buildFallbackPackageSearchProjection) and a warnings array containing
a concise message referencing the record.sourceId and error context.
- Around line 238-258: buildRecommendedNextStep currently pairs topPackage and
topConnector regardless of relation, causing misleading guidance when they are
unrelated; update the logic in buildRecommendedNextStep to only return the
combined "Found saved package ... and connector ..." guidance when the package
and connector are meaningfully related — e.g., require topPackage.kodyId or a
normalized name/alias to match topConnector.connectorName (or require
topConnector to also appear within the top N overall matches or above a
configurable score threshold on the same input) and otherwise fall back to the
single-match branches. Target the variables topPackage, topConnector and the
intent check input.intent.task.name === 'operate' when making this change.

---

Nitpick comments:
In `@packages/worker/src/mcp/tools/search.ts`:
- Around line 198-218: The hardcoded wellKnownConnectorAliases map and
getConnectorAliases function make alias data non-extensible; instead update
search logic to read aliases from connector configs (e.g., add an optional
aliases: string[] to ConnectorConfig or a connector metadata module) and fall
back to the existing wellKnownConnectorAliases only if no config-provided
aliases exist. Specifically, modify getConnectorAliases to accept or look up the
ConnectorConfig for the given connectorName (or load connector metadata) and
return config.aliases when present, otherwise return
wellKnownConnectorAliases[connectorName.toLowerCase()] ?? []; ensure any
consumers of getConnectorAliases (search-related code) still receive an array
and add unit tests for a connector with and without aliases.
- Around line 705-763: buildConnectorCandidates recomputes
deterministicEmbedding(input.query) per row which is wasteful; change
buildConnectorCandidates to accept a precomputed queryEmbedding (like
buildCapabilityCandidates/buildPackageCandidates) and use that for
cosineSimilarity instead of calling deterministicEmbedding inside the flatMap,
update the call sites (e.g., searchUnified) to compute const queryEmbedding =
deterministicEmbedding(query) once and pass it into buildConnectorCandidates,
and ensure the new signature (e.g., buildConnectorCandidates(input: {query:
string; rows: Array<ValueMetadata>; queryEmbedding: number[]}) or similar) is
used everywhere so the embedding is not recomputed for rows that are filtered
out by parseConnectorValueName/parseConnectorConfig.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5b4b138f-efb0-4540-ae3b-b27ff7abe935

📥 Commits

Reviewing files that changed from the base of the PR and between 2cce6c1 and 1ad9f75.

📒 Files selected for processing (7)
  • packages/worker/src/agent-turn/tools.ts
  • packages/worker/src/mcp/tools/search-format.node.test.ts
  • packages/worker/src/mcp/tools/search-format.ts
  • packages/worker/src/mcp/tools/search.node.test.ts
  • packages/worker/src/mcp/tools/search.ts
  • packages/worker/src/package-registry/embed.ts
  • packages/worker/src/package-registry/manifest.ts

Comment thread packages/worker/src/mcp/tools/search.ts
Comment thread packages/worker/src/mcp/tools/search.ts
Comment thread packages/worker/src/mcp/tools/search.ts
Comment thread packages/worker/src/mcp/tools/search.ts
cursoragent and others added 3 commits April 22, 2026 00:56
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/worker/src/mcp/tools/search.ts Outdated
cursoragent and others added 2 commits April 22, 2026 01:09
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/worker/src/mcp/tools/search.ts
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/worker/src/package-registry/source.ts
cursoragent and others added 2 commits April 22, 2026 01:43
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/worker/src/package-registry/source.ts
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>

@cursor cursor Bot left a comment

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.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 357a318. Configure here.

source,
content: published.content,
}),
}) as LoadedPackageManifest

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.

Manifest parsed twice, ignoring already-parsed result

Medium Severity

loadPackageManifestBySourceId calls loadPublishedEntityManifest, which already parses the manifest and returns it as published.manifest. However, the caller ignores published.manifest and re-parses from published.content via parsePackageManifest. This performs redundant JSON parsing and Zod schema validation on every uncached call in the search hot path. The parsePackageManifest function in source.ts is also an exact duplicate of parsePublishedManifest in published-source.ts.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 357a318. Configure here.

@kentcdodds
kentcdodds merged commit 1cc621b into main Apr 22, 2026
9 checks passed
@kentcdodds
kentcdodds deleted the cursor/improve-search-discovery-3c36 branch April 22, 2026 03:54
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