feat(sdk): workerd export condition + narrow entry + workers-safety probe#726
Merged
Conversation
…robe
Adds architectural hardening against the Cloudflare Workers error 10021
class of bugs, where a transitive static import inside @agent-relay/sdk
executes Node-only code (e.g. top-level createRequire(import.meta.url))
and crashes the Worker's bundle during upload validation.
Background:
The AgentWorkforce cloud Sage worker deploy broke after a routine SDK
bump because the SDK root index.ts does
export * from "./workflows/index.js";
which transitively pulls workflows/cli-session-collector and its two
collector files, both of which run createRequire at module top level.
In workerd, import.meta.url is undefined, so the bundle crashed at
module init.
Three independent layers, all in this PR:
1. packages/sdk/src/workers.ts — new narrow workerd entry that
re-exports only the Workers-safe surface: AgentRelayClient (connect-
mode), BrokerTransport, AgentRelayProtocolError, protocol types,
runtime types, model constants. Does NOT touch workflows, logs,
pty, relay-adapter.
2. packages/sdk/package.json — adds "workerd" and "worker" conditions
to exports["."] pointing at ./dist/workers.js. When esbuild/wrangler
bundle for Cloudflare, they resolve the workerd condition first and
pick the narrow entry. Node consumers still resolve "import"/
"default" and get the full root export — no breaking change.
3. packages/sdk/scripts/check-workers-safe.mjs — bundles a minimal
Workers consumer of @agent-relay/sdk via esbuild with conditions
[workerd, worker, browser, import], imports the output in Node, and
asserts it works. Wired into .github/workflows/sdk-workers-safe.yml
to run on every PR touching packages/sdk/**. This is a structural
regression guard — it is IMPOSSIBLE to merge a change to the SDK
root (or its workerd entry) that breaks Workers consumers, because
this probe catches it at PR time.
Out of scope (tracked separately):
- Lazy createRequire in workflows/collectors/{opencode,codex}.ts. Still
worth shipping as defense in depth; tracked in AgentWorkforce/cloud
workflows/fix-sage-workers-upstream.ts.
- Removing workflows/* from root index.ts entirely. Breaking change;
future minor-version PR.
- Package split into @agent-relay/client + @agent-relay/workflows.
Revisit if/when a second Workers consumer appears.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Architectural hardening of
@agent-relay/sdkagainst the Cloudflare Workers error 10021 class of bugs. Three independent layers, all in this PR:packages/sdk/src/workers.ts) — re-exports only the Workers-safe surface (AgentRelayClient, transport, protocol, types, models). Does not touch workflows, logs, pty, relay-adapter.packages/sdk/package.json) — adds"workerd"and"worker"keys toexports["."]pointing at./dist/workers.js. Non-breaking: Node consumers still resolve"import"/"default"and get the full root export.packages/sdk/scripts/check-workers-safe.mjs+.github/workflows/sdk-workers-safe.yml) — bundles a minimal Workers consumer of@agent-relay/sdkvia esbuild with conditions[workerd, worker, browser, import], imports the output in Node, invokesdefault.fetch(), asserts HTTP 200. Runs on every PR touchingpackages/sdk/**. Structural guarantee that it is impossible to merge a regression of the 10021 class of bug.Why
The AgentWorkforce cloud Sage worker deploy broke after a routine SDK bump because the SDK root does
export * from "./workflows/index.js", which transitively pullsworkflows/cli-session-collectorand its two collector files — both of which runcreateRequire(import.meta.url)at module top level. Inworkerd,import.meta.urlis undefined, so the bundle crashes at module init and Cloudflare rejects the upload with error 10021.The downstream workaround (dynamic import in Sage v1.0.3) is shipped, but that only protects Sage. Any other Workers consumer that imports from the SDK root hits the same cliff. This PR structurally prevents that.
Validation
tmp/sdk-before.logreproduces the Workers consumer bundle failure against the current SDK root.node packages/sdk/scripts/check-workers-safe.mjsexits 0. Bundle builds, module init is clean,default.fetch()returns 200.packages/sdktest suite green (vitest).Test plan
sdk-workers-safe.ymlgreen on this PROut of scope
createRequirein workflow collectors (defense in depth). Tracked separately in AgentWorkforce/cloudworkflows/fix-sage-workers-upstream.ts.workflows/*from rootindex.tsentirely. Breaking change — future minor.@agent-relay/client+@agent-relay/workflows. Future.