Skip to content

fix(agents): keep webhook paths service-agnostic#4366

Open
icehaunter wants to merge 3 commits into
mainfrom
codex/fix-agents-webhook-stream-paths
Open

fix(agents): keep webhook paths service-agnostic#4366
icehaunter wants to merge 3 commits into
mainfrom
codex/fix-agents-webhook-stream-paths

Conversation

@icehaunter
Copy link
Copy Markdown
Contributor

@icehaunter icehaunter commented May 19, 2026

Motivation

Webhook registration and dispatch were still carrying an old assumption from the closed tenanted cloud implementation: service ids could be prepended to Durable Streams paths and then stripped before runtime delivery. In the OSS agents-server that is the wrong boundary. The service or tenant route belongs in the configured Durable Streams base URL, while subscription patterns, explicit streams, wake streams, webhook wake payloads, and callback acks should all refer to logical stream paths only.

This avoids leaking cloud tenancy details into OSS paths and fixes webhook subscriptions created through agents-server/runtimes without reintroducing service-prefixed stream names.

The end-to-end cloud path also exposed a second boundary issue: Durable Streams calls the agents-server webhook forward endpoint without the cloud bearer token, because DS authenticates the delivery with a webhook signature instead. The OSS server therefore needs to persist the DS signing secret and validate signed deliveries before forwarding them to a runtime.

What changed

  • Normalize subscription pattern, streams, wake_stream, and ack stream fields by stripping only leading slashes at the Durable Streams boundary.
  • Stop using service-id path transforms for subscription request bodies, subscription responses, webhook wake payload adaptation, and callback forwarding.
  • Keep runtime-facing/entity paths root-relative so entity lookup and agents-runtime webhook payloads still use paths like /chat/one/main.
  • Treat old service-prefixed subscription streams as distinct wrong paths instead of accepting them as equivalent to the logical stream path.
  • Preserve custom Durable Streams routing adapters for URL routing, including a serviceId input for cloud wrappers, while deprecating path conversion hooks so existing adapters can still typecheck.
  • Persist the webhook_secret returned by Durable Streams subscription creation and verify Webhook-Signature before forwarding webhook deliveries to runtimes.
  • Store DS subscription callbacks as subscription ids and ack them through the stream client with the DS callback token, instead of replaying the cloud Authorization header to Durable Streams.
  • Have agents-runtime send callback claim tokens using electric-claim-token when server auth headers are configured, preserving the configured cloud Authorization header.
  • Add regression coverage for StreamClient subscriptions, dispatch policy linking, signed webhook forwarding, callback forwarding, host/router flows, and service-scoped Durable Streams base URLs.
  • Add patch changesets for @electric-ax/agents-server and @electric-ax/agents-runtime.

Cloud compatibility

Stratovolt already builds each tenant Durable Streams URL as .../v1/stream/{serviceId}, which matches this boundary: service id in the base URL, logical paths in the subscription body. The cloud wrapper can keep using its routing adapter for URL routing because the adapter still receives serviceId; the deprecated path conversion hooks are simply no longer used by agents-server subscription rewriting.

This does need to be paired with a cloud-side auth relaxation for POST /_electric/webhook-forward/*: that endpoint must be routable to the tenant using the service routing hint without requiring the normal bearer token. The security check moves to the OSS agents-server, which validates the Durable Streams Webhook-Signature against the persisted subscription secret before forwarding anything to the runtime. Other cloud agents endpoints should keep the existing bearer auth.

@codecov
Copy link
Copy Markdown

codecov Bot commented May 19, 2026

Codecov Report

❌ Patch coverage is 85.41667% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 55.97%. Comparing base (99ac6fd) to head (30f9c75).
⚠️ Report is 1 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
...gents-server/src/routing/durable-streams-router.ts 67.74% 10 Missing ⚠️
...kages/agents-server/src/routing/internal-router.ts 94.59% 2 Missing ⚠️
...kages/agents-server/src/routing/dispatch-policy.ts 90.00% 1 Missing ⚠️
...ver/src/routing/durable-streams-routing-adapter.ts 91.66% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #4366      +/-   ##
==========================================
- Coverage   59.73%   55.97%   -3.76%     
==========================================
  Files         290      245      -45     
  Lines       28579    24870    -3709     
  Branches     7768     6890     -878     
==========================================
- Hits        17072    13922    -3150     
+ Misses      11490    10934     -556     
+ Partials       17       14       -3     
Flag Coverage Δ
packages/agents 70.92% <ø> (ø)
packages/agents-mcp ?
packages/agents-runtime 81.25% <100.00%> (-0.03%) ⬇️
packages/agents-server 74.49% <84.44%> (+0.59%) ⬆️
packages/agents-server-ui 6.66% <ø> (ø)
packages/electric-ax 42.61% <ø> (ø)
packages/experimental ?
packages/react-hooks ?
packages/start ?
packages/typescript-client ?
packages/y-electric ?
typescript 55.97% <85.41%> (-3.76%) ⬇️
unit-tests 55.97% <85.41%> (-3.76%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@balegas balegas left a comment

Choose a reason for hiding this comment

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

Looks easy!

@icehaunter icehaunter changed the title fix(agents-server): keep webhook stream paths service-agnostic fix(agents): keep webhook paths service-agnostic May 19, 2026
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