Skip to content

Use Workers AI for vector embeddings - #613

Merged
kody-bot merged 4 commits into
mainfrom
cursor/workers-ai-search-embeddings-23c3
Jul 5, 2026
Merged

kody-bot merged 4 commits into
mainfrom
cursor/workers-ai-search-embeddings-23c3

Conversation

@kentcdodds

@kentcdodds kentcdodds commented Jul 5, 2026 •

Copy link
Copy Markdown
Owner

Summary

  • Replace online pseudo-embeddings with batched Workers AI embeddings using @cf/baai/bge-small-en-v1.5 (384 dimensions, cls pooling), with strict response shape/dimension validation.
  • Add production/preview AI bindings and optional AI Gateway routing via AI_GATEWAY_ID; local/test and non-production no-AI paths keep deterministic offline fallback behavior.
  • Expand the existing CAPABILITY_REINDEX_SECRET /__maintenance/reindex-capabilities operation to rebuild built-in capabilities, memories, jobs, and saved packages, preserving userId metadata filters for user-owned vectors.
  • Rebuild saved-package vectors from each package’s full manifest (matching save/publish behavior), skip/log individual bad package manifests, and report skipped package rows as aggregate reindex failures with partial per-kind results.
  • Update contributor docs/workflows for the real embedding model, optional gateway routing, and all-vector operational reindexing.

Operational reindex note

The existing Vectorize indexes remain --dimensions=384 --metric=cosine, matching @cf/baai/bge-small-en-v1.5. After deploy, run (or let the production workflow run) POST /__maintenance/reindex-capabilities with Authorization: Bearer $CAPABILITY_REINDEX_SECRET to rebuild all shared-index vectors: built-in capabilities, memories, jobs, and saved packages. This is required after the fake-to-real embedding switch so old pseudo-vectors are replaced with Workers AI vectors.

Validation

  • npm run test -- --run packages/worker/src/mcp/capabilities/capability-search.workers.test.ts packages/worker/src/capability-maintenance.node.test.ts packages/worker/src/maintenance-handler.node.test.ts packages/worker/src/package-registry/package-reindex.node.test.ts ✅
  • npm run typecheck ✅
  • npm run format:check ✅
  • npm run lint ✅ (existing warnings only)
  • npm run validate ✅ (run before initial push and after each reviewer-fix commit)
System recap — extends existing primitives (medium risk)

Mode: recap · Base: main @ cf8c22e · Head: cffb6da

Classification: extends — changes the embedding implementation and maintenance rebuild behavior for the existing Vectorize search primitive.

Primitives touched

Primitive Group Impact
vectorize-search storage extends — online embeddings now use Workers AI, and the existing reindex endpoint rebuilds every vector kind in the shared index
mcp-server surfaces composes — capability/memory/package search continues through existing MCP search surfaces

System map

flowchart LR
	mcpServer["mcp-server"]:::untouched --> vectorizeSearch["vectorize-search"]:::extended
	vectorizeSearch --> vectorizeIndex["CAPABILITY_VECTOR_INDEX"]:::extended
	vectorizeSearch --> workersAI["Workers AI binding"]:::extended
	classDef touched fill:#1a7f37,color:#fff
	classDef extended fill:#9a6700,color:#fff
	classDef added fill:#cf222e,color:#fff
	classDef untouched fill:#57606a,color:#fff
Loading

Change flow

sequenceDiagram
	participant Search as Search/reindex caller
	participant Embed as embedTextsForVectorize
	participant AI as Workers AI / AI Gateway
	participant V as Vectorize
	Search->>Embed: text batch
	alt local/test or non-prod without AI
		Embed-->>Search: deterministic fallback vectors
	else production/preview AI binding
		Embed->>AI: @cf/baai/bge-small-en-v1.5 batch (gateway when configured)
		AI-->>Embed: 384-dim rows
		Embed-->>Search: validated vectors
	end
	Search->>V: query/upsert with kind + userId metadata filters where user-owned
Loading

Invariants

  • Per-user isolation remains required for user-owned vector paths. Memory, job, and saved-package reindexing writes metadata.userId, and existing search paths continue to filter by userId for user-owned data.
  • Built-in capability vectors remain global (kind: builtin) and are not user content.
Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Added support for optional AI Gateway routing in production and preview environments.
    • Expanded capability search to use Workers AI embeddings when available, with reliable fallback behavior in local/test environments.
    • Added reindexing for saved packages alongside existing capability, memory, and job vectors.
  • Documentation

    • Updated setup and contribution docs to reflect the new embedding, AI Gateway, and reindexing workflow guidance.

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

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces an optional Workers AI binding for capability embeddings with Cloudflare AI Gateway routing and offline fallback, expands capability maintenance reindexing to cover memories, jobs, and saved packages via a new reindexSavedPackageVectors module, generalizes the maintenance response shape, updates env schema and Wrangler config, and revises related workflows and documentation.

Changes

Workers AI embeddings and multi-vector reindex

Layer / File(s) Summary
Env schema and Wrangler/binding wiring
packages/worker/src/env-schema.ts, packages/worker/worker-configuration.d.ts, packages/worker/wrangler.jsonc
Adds optional AI and AI_GATEWAY_ID fields to EnvSchema/AppEnv, adds AI: Ai to Cloudflare.Env, and wires an ai binding block into production and preview Wrangler environments.
Workers AI embedding implementation
packages/worker/src/mcp/capabilities/capability-search.ts, capability-search.workers.test.ts
Extends CapabilityVectorizeEnv, adds CAPABILITY_EMBEDDING_MODEL, and reworks embedTextsForVectorize to call Workers AI (optionally via AI Gateway) with response validation, falling back to deterministic offline embeddings outside production; adds unit tests for empty input, batching, fallback, and invalid-response rejection.
Saved package reindex module
packages/worker/src/package-registry/package-reindex.ts, package-reindex.node.test.ts
Adds reindexSavedPackageVectors, which loads saved packages in batches of 16, embeds manifest text, and upserts vectors with user-scoped metadata; skips when offline or empty; adds a unit test.
Multi-vector reindex orchestration
packages/worker/src/capability-maintenance.ts, capability-maintenance.node.test.ts, packages/worker/src/maintenance-handler.ts
Adds reindexAllCapabilitySearchVectors to aggregate capability, memory, job, and package reindex results with per-step error capture; updates handleCapabilityReindexRequest to report combined failures; generalizes MaintenanceResult to Record<string, unknown> and spreads run() output into responses; adds success/partial-failure tests.
Deploy workflows, env example, and docs
.github/workflows/deploy.yml, .github/workflows/preview.yml, packages/worker/.env.example, docs/contributing/*
Marks AI_GATEWAY_ID as optional in secret-sync steps, updates .env.example comments for the embedding gateway and multi-vector reindex, and revises contributing docs to describe Workers AI embeddings, AI Gateway routing, and the reindex-capabilities maintenance endpoint.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant handleCapabilityReindexRequest
  participant reindexAllCapabilitySearchVectors
  participant embedTextsForVectorize
  participant WorkersAI as "runtime.AI"

  Client->>handleCapabilityReindexRequest: POST /__maintenance/reindex-capabilities
  handleCapabilityReindexRequest->>reindexAllCapabilitySearchVectors: run()
  reindexAllCapabilitySearchVectors->>embedTextsForVectorize: embed capability/memory/job/package text
  alt AI binding available
    embedTextsForVectorize->>WorkersAI: run(CAPABILITY_EMBEDDING_MODEL)
    WorkersAI-->>embedTextsForVectorize: embedding rows
  else offline/non-production
    embedTextsForVectorize->>embedTextsForVectorize: deterministicEmbedding fallback
  end
  embedTextsForVectorize-->>reindexAllCapabilitySearchVectors: embeddings
  reindexAllCapabilitySearchVectors-->>handleCapabilityReindexRequest: aggregated {upserted, error?} per kind
  handleCapabilityReindexRequest-->>Client: 200 {ok:true, ...results} or 500 with error summary
Loading

Related PRs: None identified.

Suggested labels: enhancement, documentation, worker

Suggested reviewers: kentcdodds

🐰 A carrot-sized model now hums,
Fetching vectors as reindex comes,
Packages, jobs, and memories too,
All stitched into embeddings new,
Optional AI, gateway aglow —
Hop, hop, watch the vectors grow!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly matches the main change: switching vector embeddings to Workers AI.
✨ 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/workers-ai-search-embeddings-23c3

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.

@kentcdodds
kentcdodds marked this pull request as ready for review July 5, 2026 16:07
Comment thread packages/worker/src/package-registry/package-reindex.ts Outdated
Comment thread packages/worker/src/capability-maintenance.ts Outdated
@github-actions

github-actions Bot commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

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

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

Mocks:

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

@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: 1

🧹 Nitpick comments (5)
packages/worker/src/package-registry/package-reindex.ts (1)

30-41: 🧹 Nitpick | 🔵 Trivial

Possible subrequest-limit exposure on large batches.

Each package in a batch triggers a manifest fetch via loadPackageManifestBySourceId, likely a fetch() against baseUrl. With enough saved packages, cumulative subrequests across all batches (plus the other reindex steps run in the same request) could approach the free-plan external subrequest ceiling. Worth confirming the deployment's Workers plan tier and expected saved-package volume.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/package-registry/package-reindex.ts` around lines 30 -
41, The reindex flow in package-reindex.ts may create too many external
subrequests because each batch calls loadPackageManifestBySourceId in parallel
and the overall request also performs other reindex work. Review the batch size
and the PackageReindex path around the loop using upsertBatchSize and
Promise.all, then add a safeguard by reducing concurrency, lowering batch size,
or splitting work so the total fetch volume stays within the Workers plan’s
subrequest limits.
packages/worker/src/capability-maintenance.ts (2)

27-45: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider running independent reindex steps concurrently.

runReindexStep already isolates failures per step (it never rejects), so the four await calls don't need to be sequential. Since this endpoint is invoked from deploy/preview automation per the PR description, reducing total wall-clock latency is worthwhile.

-	const capabilities = await runReindexStep(() =>
-		reindexCapabilityVectors(env, capabilitySpecs),
-	)
-	const memories = await runReindexStep(() => reindexMemoryVectors(env))
-	const jobs = await runReindexStep(() => reindexJobVectors(env))
-	const packages = await runReindexStep(() =>
-		reindexSavedPackageVectors(env, { baseUrl: input.baseUrl }),
-	)
-	return {
-		capabilities,
-		memories,
-		jobs,
-		packages,
-	}
+	const [capabilities, memories, jobs, packages] = await Promise.all([
+		runReindexStep(() => reindexCapabilityVectors(env, capabilitySpecs)),
+		runReindexStep(() => reindexMemoryVectors(env)),
+		runReindexStep(() => reindexJobVectors(env)),
+		runReindexStep(() =>
+			reindexSavedPackageVectors(env, { baseUrl: input.baseUrl }),
+		),
+	])
+	return { capabilities, memories, jobs, packages }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/capability-maintenance.ts` around lines 27 - 45,
`reindexAllCapabilitySearchVectors` is running four independent `runReindexStep`
calls sequentially even though each step is failure-isolated and never rejects.
Update the function to start the `reindexCapabilityVectors`,
`reindexMemoryVectors`, `reindexJobVectors`, and `reindexSavedPackageVectors`
steps concurrently (while still passing `env` and `input.baseUrl` as needed),
then wait for all of them before returning the `{ capabilities, memories, jobs,
packages }` result.

55-73: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Partial success detail is discarded on failure.

When any step fails, the response body only contains { ok: false, error } — the counts from steps that did succeed (e.g., capabilities: {upserted: 3}) are lost. For an endpoint invoked from deploy automation, surfacing partial progress alongside the error would ease triage.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/capability-maintenance.ts` around lines 55 - 73, The
`run` handler in `capability-maintenance.ts` throws away successful step results
when any reindex step fails. Update the `run` logic so it preserves and returns
the partial `result` alongside the failure information instead of only surfacing
an error string; keep using `reindexAllCapabilitySearchVectors` and the `failed`
detection, but have the response include both the error and the successful step
payloads (for example, the `capabilities` counts) so deploy automation can see
partial progress.
packages/worker/src/package-registry/package-reindex.node.test.ts (1)

39-101: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Missing coverage for batching and manifest-load failures.

Only a single-row, single-batch success case is tested. Consider adding cases for: multiple batches (>16 rows), the offline/missing-index early returns, and a rejected loadPackageManifestBySourceId call — the last would have caught the failure-propagation issue flagged in package-reindex.ts.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/package-registry/package-reindex.node.test.ts` around
lines 39 - 101, Add tests in reindexSavedPackageVectors to cover the missing
control-flow paths: verify the early return cases when
isCapabilitySearchOffline() is true and when getCapabilityVectorIndex() yields
no index, then add a multi-row fixture that forces batching beyond 16 items and
asserts multiple upsert calls. Also add a failure case where
loadPackageManifestBySourceId rejects so the test confirms the error is
propagated rather than swallowed, using the existing reindexSavedPackageVectors
and mockModule helpers to locate the behavior.
packages/worker/src/maintenance-handler.ts (1)

3-3: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Guard against a future run() result overriding the ok field.

MaintenanceResult is now Record<string, unknown>, and { ok: true, ...result } lets any ok key in result silently override the success flag. Not an issue with today's only caller, but nothing prevents a future maintenance handler from returning ok and corrupting the response contract shared across all handleSecretMaintenanceRequest consumers.

-type MaintenanceResult = Record<string, unknown>
+type MaintenanceResult = Record<string, unknown> & { ok?: never }

Also applies to: 36-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/worker/src/maintenance-handler.ts` at line 3, The maintenance
response shape in MaintenanceResult can be corrupted because
handleSecretMaintenanceRequest spreads the run() result after setting ok: true,
allowing a future result.ok to override the success flag. Update the response
assembly in handleSecretMaintenanceRequest so the contract-owned ok field cannot
be overwritten, and keep the safeguard local to the code path that merges the
maintenance handler result.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/worker/src/package-registry/package-reindex.ts`:
- Around line 32-56: The saved-package reindex flow in packageReindex currently
uses Promise.all over loadPackageManifestBySourceId, so one failed manifest load
aborts the whole batch and stops later packages from being indexed. Update the
manifest-loading step to handle failures per row inside the batch loop, using
loadPackageManifestBySourceId and the subsequent
buildSavedPackageEmbedText/embedTextsForVectorize flow only for successfully
loaded manifests, while skipping and continuing past failed rows so the rest of
the batch and later batches still run.

---

Nitpick comments:
In `@packages/worker/src/capability-maintenance.ts`:
- Around line 27-45: `reindexAllCapabilitySearchVectors` is running four
independent `runReindexStep` calls sequentially even though each step is
failure-isolated and never rejects. Update the function to start the
`reindexCapabilityVectors`, `reindexMemoryVectors`, `reindexJobVectors`, and
`reindexSavedPackageVectors` steps concurrently (while still passing `env` and
`input.baseUrl` as needed), then wait for all of them before returning the `{
capabilities, memories, jobs, packages }` result.
- Around line 55-73: The `run` handler in `capability-maintenance.ts` throws
away successful step results when any reindex step fails. Update the `run` logic
so it preserves and returns the partial `result` alongside the failure
information instead of only surfacing an error string; keep using
`reindexAllCapabilitySearchVectors` and the `failed` detection, but have the
response include both the error and the successful step payloads (for example,
the `capabilities` counts) so deploy automation can see partial progress.

In `@packages/worker/src/maintenance-handler.ts`:
- Line 3: The maintenance response shape in MaintenanceResult can be corrupted
because handleSecretMaintenanceRequest spreads the run() result after setting
ok: true, allowing a future result.ok to override the success flag. Update the
response assembly in handleSecretMaintenanceRequest so the contract-owned ok
field cannot be overwritten, and keep the safeguard local to the code path that
merges the maintenance handler result.

In `@packages/worker/src/package-registry/package-reindex.node.test.ts`:
- Around line 39-101: Add tests in reindexSavedPackageVectors to cover the
missing control-flow paths: verify the early return cases when
isCapabilitySearchOffline() is true and when getCapabilityVectorIndex() yields
no index, then add a multi-row fixture that forces batching beyond 16 items and
asserts multiple upsert calls. Also add a failure case where
loadPackageManifestBySourceId rejects so the test confirms the error is
propagated rather than swallowed, using the existing reindexSavedPackageVectors
and mockModule helpers to locate the behavior.

In `@packages/worker/src/package-registry/package-reindex.ts`:
- Around line 30-41: The reindex flow in package-reindex.ts may create too many
external subrequests because each batch calls loadPackageManifestBySourceId in
parallel and the overall request also performs other reindex work. Review the
batch size and the PackageReindex path around the loop using upsertBatchSize and
Promise.all, then add a safeguard by reducing concurrency, lowering batch size,
or splitting work so the total fetch volume stays within the Workers plan’s
subrequest limits.
🪄 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: e2886509-a461-4aab-a5db-ab0e218c8620

📥 Commits

Reviewing files that changed from the base of the PR and between cf8c22e and 43464d0.

📒 Files selected for processing (17)
  • .github/workflows/deploy.yml
  • .github/workflows/preview.yml
  • docs/contributing/adding-capabilities.md
  • docs/contributing/environment-variables.md
  • docs/contributing/setup-manifest.md
  • docs/contributing/setup.md
  • packages/worker/.env.example
  • packages/worker/src/capability-maintenance.node.test.ts
  • packages/worker/src/capability-maintenance.ts
  • packages/worker/src/env-schema.ts
  • packages/worker/src/maintenance-handler.ts
  • packages/worker/src/mcp/capabilities/capability-search.ts
  • packages/worker/src/mcp/capabilities/capability-search.workers.test.ts
  • packages/worker/src/package-registry/package-reindex.node.test.ts
  • packages/worker/src/package-registry/package-reindex.ts
  • packages/worker/worker-configuration.d.ts
  • packages/worker/wrangler.jsonc

Comment thread packages/worker/src/package-registry/package-reindex.ts Outdated
Co-authored-by: Kent C. Dodds <me+github@kentcdodds.com>
Comment thread packages/worker/src/capability-maintenance.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 cffb6da. Configure here.

upserted: 0,
error: getErrorMessage(error),
}
}

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.

Reindex errors hide partial upserts

Medium Severity

When a reindex step throws after earlier batches succeeded, runReindexStep always reports upserted: 0 for that kind. Vectorize may already contain those vectors, but the maintenance JSON and failure payload imply nothing was written for that step.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit cffb6da. Configure here.

@kody-bot
kody-bot merged commit dccf215 into main Jul 5, 2026
5 checks passed
@kody-bot
kody-bot deleted the cursor/workers-ai-search-embeddings-23c3 branch July 5, 2026 17:00
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.

3 participants