Skip to content

feat(sdk): workerd export condition + narrow entry + workers-safety probe#726

Merged
khaliqgant merged 1 commit into
mainfrom
fix/sdk-workers-hardening
Apr 13, 2026
Merged

feat(sdk): workerd export condition + narrow entry + workers-safety probe#726
khaliqgant merged 1 commit into
mainfrom
fix/sdk-workers-hardening

Conversation

@khaliqgant
Copy link
Copy Markdown
Member

@khaliqgant khaliqgant commented Apr 13, 2026

Summary

Architectural hardening of @agent-relay/sdk against the Cloudflare Workers error 10021 class of bugs. Three independent layers, all in this PR:

  1. Narrow workerd entry (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.
  2. Export condition (packages/sdk/package.json) — adds "workerd" and "worker" keys to exports["."] pointing at ./dist/workers.js. Non-breaking: Node consumers still resolve "import"/"default" and get the full root export.
  3. Workers-safety probe (packages/sdk/scripts/check-workers-safe.mjs + .github/workflows/sdk-workers-safe.yml) — bundles a minimal Workers consumer of @agent-relay/sdk via esbuild with conditions [workerd, worker, browser, import], imports the output in Node, invokes default.fetch(), asserts HTTP 200. Runs on every PR touching packages/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 pulls workflows/cli-session-collector and its two collector files — both of which run createRequire(import.meta.url) at module top level. In workerd, import.meta.url is 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

  • Baseline probe (pre-fix): tmp/sdk-before.log reproduces the Workers consumer bundle failure against the current SDK root.
  • After fix: node packages/sdk/scripts/check-workers-safe.mjs exits 0. Bundle builds, module init is clean, default.fetch() returns 200.
  • Existing packages/sdk test suite green (vitest).

Test plan

  • New CI workflow sdk-workers-safe.yml green on this PR
  • Existing SDK tests green
  • Local probe reproduces the pre-fix crash and the post-fix pass

Out of scope

  • Lazy createRequire in workflow collectors (defense in depth). Tracked separately in AgentWorkforce/cloud workflows/fix-sage-workers-upstream.ts.
  • Removing workflows/* from root index.ts entirely. Breaking change — future minor.
  • Package split into @agent-relay/client + @agent-relay/workflows. Future.

Open with Devin

…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>
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: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@khaliqgant khaliqgant merged commit fc9135c into main Apr 13, 2026
39 checks passed
@khaliqgant khaliqgant deleted the fix/sdk-workers-hardening branch April 13, 2026 06:25
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.

1 participant