Repository navigation
feat(surface): dependency-free hosted completion-signal helper (2.0.54) - #677
Merged
Merged
Conversation
Hosted Cloud runs materialize only the pinned @relayflows/surface next to the flow source, so the SDK's waitForCloudSignal cannot be imported there. - Add @relayflows/surface/signals: waitForSignal(name, opts?) with hosted defaults (RELAYFLOW_V2_CLOUD_RUN_ID, RELAYFLOW_V2_SIGNAL_READ_TOKEN, FLOWS_CLOUD_URL else https://agentrelay.com/cloud). Imports only node:timers/promises and uses global fetch. - Move the held-GET wait (path validation, waitMs <= 25000, fast-204 backoff 250ms->5s with reset, error classification) into the Surface as holdSignalWait; the SDK's waitForCloudSignal now delegates to it with its own credential resolution, hosted-token fallback, and CloudFlowError. - Tests: Surface unit tests mirroring the SDK suite plus hosted defaults; packed-consumer gate imports the subpath from the tarball and asserts it imports only Node built-ins; a replica of Cloud's Bun compatibility envelope shows the subpath needs a companion Cloud change. - Docs: SURFACE.md usage for hosted flows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
miyaontherelay has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
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. Comment |
Flows AGENTS.md: never edit a gate that judges your own work. The surface-package-gate.sh and pack-release.mjs assertions for ./signals move to a follow-up PR that lands after this one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
There was a problem hiding this comment.
miyaontherelay has reached the 50-credit limit for trial accounts. To continue receiving code reviews, upgrade your plan.
miyaontherelay
added a commit
that referenced
this pull request
Oct 19, 2026
Follow-up to #677 (kept separate per AGENTS.md: never edit a gate that judges your own work). pack-release.mjs requires dist/signals.js and dist/signals.d.ts in the Surface tarball, and surface-package-gate.sh checks the subpath resolves from the packed tarball and imports only Node built-ins. Co-Authored-By: Claude Opus 5.5 <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.
Why
Hosted Cloud runs materialize only the hash-pinned
@relayflows/surfacenext to the flow source (cloudpackages/core/src/bootstrap/lib/relayflow-v2-executor.ts,materializeRelayflowV2SurfacePackage).@relayflows/sdk, wherewaitForCloudSignallives, can't be imported there, so a hosted flow has no way to wait on a completion signal.What
@relayflows/surface/signalsexportingwaitForSignal(name, { waitMs?, signal?, runId?, apiUrl?, token?, requestTimeoutMs? }).runId=RELAYFLOW_V2_CLOUD_RUN_ID(Cloud's run ID, not the engine'sRELAYFLOW_RUN_ID);token=RELAYFLOW_V2_SIGNAL_READ_TOKEN;apiUrl=FLOWS_CLOUD_URL(the SDK's cloud-http variable), elsehttps://agentrelay.com/cloud.dist/signals.jsimports onlynode:timers/promisesand calls Cloud through globalfetch.f.runchildren don't.holdSignalWaitin Surface. It covers name and run-ID validation,waitMs <= 25000, the 250 ms → 5 s abort-aware fast-204 backoff with reset after a held 204, and error classification (caller abort passes through, deadline or reset istransient_error, malformed JSON or bad shape isinvalid_response). The SDK'swaitForCloudSignalnow delegates to it. It keeps its public signature, its credential resolution (stored login and refresh, then theFLOWS_CLOUD_TOKEN> hosted read-token fallback),CloudFlowError, and its own timer, so the existing SDK suite runs unchanged.pack-release.mjsnow requiresdist/signals.{js,d.ts}in the surface tarball.SURFACE.mdsection covering hosted completion signals.Required Cloud change (must land before Cloud pins Surface 2.0.54)
Cloud's executor compares the published
exportsmap exactly (JSON.stringifyequality) before applying the Bun envelope. A 2.0.54 manifest that contains./signalstherefore fails withRelayflow v2 authored Surface package has an unsupported export shapefor every hosted TS flow, not only flows that use signals. The envelope also writes a fixedexportsmap, so./signalswould not resolve even if that check passed.tests/signals-envelope.test.tsreplicates both behaviors. Cloud's root currently pins surface 2.0.52, so nothing breaks until Cloud bumps.The changes, in
packages/core/src/bootstrap/lib/relayflow-v2-executor.ts(cloud main5b31e1016):"./signals": { types: "./dist/signals.d.ts", import: "./dist/signals.js", require: "./dist/signals.js" }appended last. Key order matters for the stringify compare."./signals": "./signals.js"to the envelopeexports, but only when the manifest has it. A pre-2.0.54 derived package then stays byte-identical, so resume hashes still match.signals.jsandsignals.d.tscontainingexport * from './dist/signals.js';\n(flag: "wx", mode: 0o600).@relayflows/surfacepin and authority to 2.0.54.FLOWS_CLOUD_URLin the CLIchildEnv(~L859–867) for non-prod stages. Otherwise the helper falls back tohttps://agentrelay.com/cloud.Note
certifiedModuleBody(authored-parallel-eligibility.ts) only certifies modules whose single import isimport { flow } from '@relayflows/surface'. A flow that also imports@relayflows/surface/signalstherefore runs itsPromise.allf.rungroups on the serial scheduler. This is documented in SURFACE.md and left unchanged here.Verification
All commands were run locally (Node 26.11.1, Bun 1.4.2) in a fresh worktree off
origin/main(v2.0.53), with realnpm ciinpackages/surfaceandpackages/sdk.packages/surface:tscbuild OK,tsc --noEmitOK,tsc -p tsconfig.test.jsonOK,npm run typecheck:regressionsOK.vitest rungives 13 files / 80 tests passed: 18 new insignals.test.tsand 6 new insignals-envelope.test.ts, which runs under both node and bun.scripts/surface-package-gate.shpasses end to end:PACKED_RUNTIME_OK,PACKED_RUNTIME_REFUSAL_OK,PACKED_SIGNALS_OK imports=node:timers/promises,PACKED_TYPESCRIPT_OK, the SDK typecheck against the packed tarball, and the SDKauthored-flow.test.ts(38 passed). Locally I added--backend=copyfileto bun install because of a cache issue on this disk; the script in the PR is unchanged in that respect.packages/sdk:npm run typecheckOK,npm run buildOK,npm run typecheck:testsOK.tests/cloud-signal.test.tspasses 17/17, unmodified. The cloud-run, connect, deploy, schedule, sync and signal files pass 320/320 withTMPDIR=/tmp. My machine's TMPDIR contains a space, which breaks vite's loader for those files; that is environmental and unrelated to this change.cloud-signal.test.ts. This shows the SDK really delegates to Surface.RELAYFLOW_RUN_ID: 3 tests fail../signalsexport removed frompackage.json: 3 tests fail in the envelope suite.npm run check:docsreportsAUTHORING.mddrift that already exists on main (thesecrets?fields). This PR doesn't touch it.Not run: the full SDK suite and the Bun-standalone
authored-node-runtime.test.ts, because both need a kernelcargobuild. The envelope test covers the subpath under Node and Bun module resolution on the envelope Cloud writes.Not merged and not published.
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need.Note
Medium Risk
Introduces run-bound signal-read credentials and shared Cloud wait logic used by hosted flows and the SDK; shipping Surface 2.0.54 without the documented Cloud envelope update would break hosted TS flows at manifest check time.
Overview
Adds
@relayflows/surface/signalsso hosted flows canwaitForSignalwithout importing the SDK, using only Node built-ins andfetchwith hosted env defaults (RELAYFLOW_V2_CLOUD_RUN_ID,RELAYFLOW_V2_SIGNAL_READ_TOKEN,FLOWS_CLOUD_URL).The held-GET loop (validation, 25s holds, fast-204 backoff, error codes) lives in Surface as
holdSignalWait;waitForCloudSignalin the SDK now delegates there while keeping its own credential resolution andCloudFlowError.package.jsonexports./signals,docs/SURFACE.mddocuments usage and scheduler implications, and new unit/envelope tests assert wire behavior and Cloud’s Bun materialization shape (./signalsneeds a companion Cloud executor change before pinning this Surface version).Reviewed by Cursor Bugbot for commit da059aa. Bugbot is set up for automated code reviews on this repo. Configure here.
Agent Relay sessions
claudesessiona7fef635· opened viagh pr create· last active 2026-10-19