Skip to content

RAG-1300: Add web_search binding kind support#13955

Draft
G4brym wants to merge 5 commits into
cloudflare:mainfrom
G4brym:gmassadas/add-web-search-binding
Draft

RAG-1300: Add web_search binding kind support#13955
G4brym wants to merge 5 commits into
cloudflare:mainfrom
G4brym:gmassadas/add-web-search-binding

Conversation

@G4brym
Copy link
Copy Markdown
Member

@G4brym G4brym commented May 18, 2026

Adds wrangler / miniflare / workers-utils support for the new web_search Workers binding plus a wrangler websearch search command.

includes:

  • binding
  • cli
  • oauth scopes

Binding

Declared as a single object in wrangler.jsonc (one shared corpus, no namespace/instance):

{ "web_search": { "binding": "WEBSEARCH" } }

At runtime the binding exposes a single search() method returning { items, metadata }. Always-remote in local dev: Miniflare proxies to the production service via the remote-bindings transport.

CLI

npx wrangler websearch search "cloudflare workers"
npx wrangler websearch search "cloudflare workers" --limit 5
npx wrangler websearch search "cloudflare workers" --json

--limit and --json are optional. Default output is a pretty table; --json prints the raw response.


  • Tests
    • Tests included/updated
    • Automated tests not possible - manual testing has been completed as follows:
    • Additional testing not necessary because:
  • Public documentation
    • Cloudflare docs PR(s):
    • Documentation not necessary because: we will add docs when we release this to the public

Open in Devin Review

@G4brym G4brym requested a review from workers-devprod as a code owner May 18, 2026 16:04
@changeset-bot
Copy link
Copy Markdown

changeset-bot Bot commented May 18, 2026

🦋 Changeset detected

Latest commit: 9c09fcf

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 7 packages
Name Type
miniflare Minor
wrangler Minor
@cloudflare/workers-utils Minor
@cloudflare/pages-shared Patch
@cloudflare/vite-plugin Patch
@cloudflare/vitest-pool-workers Patch
@cloudflare/cli-shared-helpers Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@github-project-automation github-project-automation Bot moved this to Untriaged in workers-sdk May 18, 2026
@workers-devprod workers-devprod requested review from a team and dario-piotrowicz and removed request for a team May 18, 2026 16:05
@workers-devprod
Copy link
Copy Markdown
Contributor

workers-devprod commented May 18, 2026

Codeowners approval required for this PR:

  • @cloudflare/wrangler
Show detailed file reviewers
  • .changeset/add-web-search-binding.md: [@cloudflare/wrangler]
  • packages/miniflare/src/plugins/index.ts: [@cloudflare/wrangler]
  • packages/miniflare/src/plugins/web-search/index.ts: [@cloudflare/wrangler]
  • packages/workers-utils/src/config/config.ts: [@cloudflare/wrangler]
  • packages/workers-utils/src/config/environment.ts: [@cloudflare/wrangler]
  • packages/workers-utils/src/config/validation.ts: [@cloudflare/wrangler]
  • packages/workers-utils/src/map-worker-metadata-bindings.ts: [@cloudflare/wrangler]
  • packages/workers-utils/src/types.ts: [@cloudflare/wrangler]
  • packages/workers-utils/src/worker.ts: [@cloudflare/wrangler]
  • packages/workers-utils/tests/config/validation/normalize-and-validate-config.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/deploy/core.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/index.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/user.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/tests/whoami.test.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/api/remoteBindings/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/api/startDevWorker/utils.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/core/teams.d.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/deploy/check-remote-secrets-override.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/deploy/config-diffs.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/deployment-bundle/create-worker-upload-form.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/dev/miniflare/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/type-generation/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/user/user.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/utils/add-created-resource-config.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/utils/print-bindings.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/websearch/client.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/websearch/index.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/websearch/search.ts: [@cloudflare/wrangler]
  • packages/wrangler/src/websearch/types.ts: [@cloudflare/wrangler]

@G4brym G4brym marked this pull request as draft May 18, 2026 16:11
@G4brym G4brym changed the title Add web_search binding kind support RAG-1300: Add web_search binding kind support May 18, 2026
@G4brym G4brym force-pushed the gmassadas/add-web-search-binding branch from ffac1d2 to 344d2a1 Compare May 21, 2026 10:39
@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 21, 2026

create-cloudflare

npm i https://pkg.pr.new/create-cloudflare@13955

@cloudflare/kv-asset-handler

npm i https://pkg.pr.new/@cloudflare/kv-asset-handler@13955

miniflare

npm i https://pkg.pr.new/miniflare@13955

@cloudflare/pages-shared

npm i https://pkg.pr.new/@cloudflare/pages-shared@13955

@cloudflare/unenv-preset

npm i https://pkg.pr.new/@cloudflare/unenv-preset@13955

@cloudflare/vite-plugin

npm i https://pkg.pr.new/@cloudflare/vite-plugin@13955

@cloudflare/vitest-pool-workers

npm i https://pkg.pr.new/@cloudflare/vitest-pool-workers@13955

@cloudflare/workers-editor-shared

npm i https://pkg.pr.new/@cloudflare/workers-editor-shared@13955

@cloudflare/workers-utils

npm i https://pkg.pr.new/@cloudflare/workers-utils@13955

wrangler

npm i https://pkg.pr.new/wrangler@13955

commit: 9c09fcf

G4brym added 5 commits May 21, 2026 14:52
Cloudflare Web Search is a new zero-config Workers binding. Declared
in wrangler.jsonc as a single object (there is exactly one shared web
corpus, so no namespace/instance/setting is required):

  { "web_search": { "binding": "WEBSEARCH" } }

At runtime the binding exposes a single `search()` method that
returns URLs and catalog metadata. The binding is always-remote --
Miniflare proxies to the production Web Search service via the
remote-bindings transport.

Changes in this PR:

@cloudflare/workers-utils
* environment.ts: `web_search` field (single-object shape)
* config.ts: default value
* validation.ts: `ConfigBindingFieldName` entry, friendly-name maps,
  `notInheritable` registration using `validateNamedSimpleBinding`,
  `safeBindings` entry
* worker.ts: `CfWebSearch` interface
* types.ts: `web_search` entries in `WorkerMetadataBinding` and
  `Binding` discriminated unions
* map-worker-metadata-bindings.ts: `case "web_search":` arm
* tests: validation tests for the new field

wrangler
* deployment-bundle/create-worker-upload-form.ts: extract +
  serialise into the upload metadata
* api/startDevWorker/utils.ts: config-to-bindings + metadata-to-bindings
  switches
* api/remoteBindings/index.ts: marked always-remote
* deploy/config-diffs.ts: `reorderableBindings` and
  `singleBindingFields` entries
* deploy/check-remote-secrets-override.ts: switch case
* dev/miniflare/index.ts: `WorkerOptionsBindings` pick, extract,
  `warnOrError`, pass to miniflare options
* type-generation/index.ts: emit `WebSearch` runtime type in both
  type-generation entry points
* user/user.ts: add `websearch:read` OAuth scope
* utils/print-bindings.ts: extract + render in startup banner

miniflare
* plugins/web-search/index.ts: new always-remote proxy plugin
* plugins/index.ts: register the plugin in PLUGINS, intersect
  WorkerOptions, re-export

Companion changes land in workerd (Web Search type definitions) and
edgeworker-config-service (binding kind + pipeline stage).
* Run oxfmt: fix changeset paragraph wrapping + plugin import order
  (caught by check:format)

* Update inline snapshots in user.test.ts, whoami.test.ts, and
  deploy/core.test.ts to include the new websearch:run OAuth scope in
  the login URL and whoami scope listing (11 snapshots)

* Rename the OAuth scope from 'websearch:read' to 'websearch:run'.
  The scope is already registered backend-side as 'websearch:run', so
  using anything else would break the auth-scopes E2E test that
  validates scope acceptance against the live Cloudflare backend.
Adds a new top-level 'websearch' namespace with a single 'search'
subcommand:

  npx wrangler websearch search <query>
  npx wrangler websearch search <query> --limit 5
  npx wrangler websearch search <query> --json

Both --limit and --json are optional. limit defaults to 10 server-side
and is capped at 20. Without --json the results render as a pretty
table (#, title, url, description, lastModified); with --json the raw
response body is printed verbatim.

The command POSTs to /accounts/{accountId}/websearch/search with body
{ query, limit? } and uses requireAuth(config) for credentials, same
pattern as 'wrangler ai-search search'.

* src/websearch/types.ts: response shape (items + metadata)
* src/websearch/client.ts: fetchResult wrapper
* src/websearch/index.ts: namespace metadata
* src/websearch/search.ts: command definition
* src/index.ts: registry.define + registerNamespace
* src/core/teams.d.ts: add 'Product: Web Search' to the Teams enum
* src/utils/add-created-resource-config.ts: exclude 'web_search' from
  ValidKeys (singleton bindings can't go through the createdResource
  config helper; same exclusion as 'ai' and 'browser')
* src/__tests__/index.test.ts: update top-level help snapshot to
  include the new namespace
* .changeset: document the new command
The normalize-and-validate-config test asserts the default Config
object satisfies the Config type. Adding web_search as a required
Environment field (alongside ai/browser) means the expected defaults
literal must include 'web_search: undefined' as well.
The scope registered in production is literally 'websearch.run'
(with a dot, not a colon), differing from the more common
'<resource>:<verb>' pattern used by most other scopes. Switching to
the registered name lets the auth-scopes E2E test pass against the
live Cloudflare backend.

Updates the scope key in user.ts, the inline snapshots in
user.test.ts / whoami.test.ts / deploy/core.test.ts, and the changeset.
@G4brym G4brym force-pushed the gmassadas/add-web-search-binding branch from d17a336 to 9c09fcf Compare May 21, 2026 13:52
@G4brym G4brym marked this pull request as ready for review May 21, 2026 13:52
Copy link
Copy Markdown
Contributor

@devin-ai-integration devin-ai-integration Bot left a comment

Choose a reason for hiding this comment

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

Devin Review found 1 potential issue.

View 5 additional findings in Devin Review.

Open in Devin Review

Comment on lines +357 to +368
if (web_search.length > 0) {
output.push(
...web_search.map(({ binding, remote }) => ({
name: binding,
type: getBindingTypeFriendlyName("web_search"),
value: undefined,
mode: getMode({
isSimulatedLocally: context.remoteBindingsDisabled || !remote,
}),
}))
);
}
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.

🟡 web_search print-bindings mode incorrectly shows as local instead of always-remote

The web_search binding is always remote — confirmed by pickRemoteBindings (packages/wrangler/src/api/remoteBindings/index.ts:51-54) which unconditionally returns true for web_search, and the warnOrError("web_search", ws.remote, "always-remote") call in packages/wrangler/src/dev/miniflare/index.ts:636-638. However, print-bindings.ts:364 computes the mode as isSimulatedLocally: context.remoteBindingsDisabled || !remote. Since remote is an optional field on CfWebSearch (packages/workers-utils/src/worker.ts:247) and users won't set it (it's always remote), !remote evaluates to !undefined === true, causing the binding to display as "simulated locally" rather than "remote". The other always-remote bindings (ai_search_namespaces at line 341 and ai_search at line 352) correctly use isSimulatedLocally: false unconditionally.

Suggested change
if (web_search.length > 0) {
output.push(
...web_search.map(({ binding, remote }) => ({
name: binding,
type: getBindingTypeFriendlyName("web_search"),
value: undefined,
mode: getMode({
isSimulatedLocally: context.remoteBindingsDisabled || !remote,
}),
}))
);
}
if (web_search.length > 0) {
output.push(
...web_search.map(({ binding }) => ({
name: binding,
type: getBindingTypeFriendlyName("web_search"),
value: undefined,
mode: getMode({ isSimulatedLocally: false }),
}))
);
}
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@G4brym G4brym marked this pull request as draft May 21, 2026 14:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Untriaged

Development

Successfully merging this pull request may close these issues.

2 participants