From 6ba7cfded184e0bbd7a7056ffd72487ee9197831 Mon Sep 17 00:00:00 2001 From: kjgbot Date: Sat, 19 Sep 2026 13:53:38 -0700 Subject: [PATCH] fix(flows): pin the local kit to relayflows 2.0.22 The downloadable local kit installed relayflows 2.0.15, so local users missed every fix since, including AgentWorkforce/flows#484: a Claude agent step now completes on Claude's result rather than on process exit, so a background task the agent started no longer holds the run open until the wall-clock limit. Hosted runs already use 2.0.21. 2.0.22 publishes the same shape (a flows bin, nothing to import), and `flows check` passes the generated local flow for every preset. It also lowers `declined` (flows#438/#439); the ticket guards deliberately stay on done("needs_human") until Agent Relay Cloud renders a declined run, and the pin rationale and tripwire now say so. Co-Authored-By: Claude Opus 5 (1M context) --- web/lib/flow-local.ts | 19 +++++++++++++------ web/lib/flow-workflows.ts | 4 ++-- web/lib/test/flow-local.test.ts | 16 ++++++++++------ web/lib/test/flow-onboarding.test.ts | 2 +- web/lib/test/flow-workflows.test.ts | 2 +- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/web/lib/flow-local.ts b/web/lib/flow-local.ts index aff1fb8..6f265be 100644 --- a/web/lib/flow-local.ts +++ b/web/lib/flow-local.ts @@ -44,13 +44,20 @@ import { workflowAgents } from './flow-workflows'; * * So the guards that turn a ticket away still park with `f.done("needs_human")` * (see flow-onboarding.ts). The reason they actually want is a deliberate - * declination, proposed as `declined` in AgentWorkforce/flows#438 and - * implemented in PR #439 — open, unmerged, and not in any published release. - * Do not generate `declined` until a pin here contains it. The test that - * asserts this exact version is the tripwire for that: it fails on the next - * bump and names what to revisit. + * declination, `declined` (AgentWorkforce/flows#438, merged as #439). It first + * shipped in 2.0.16, and the 2.0.22 executor lowers it: its + * `LOWERED_COMPLETIONS` is `['success', 'needs_human', 'step_failed', + * 'declined']`. This pin now contains it, but the guards stay on + * `needs_human` on purpose: the same generated source runs on Agent Relay + * Cloud, which must render a `declined` run before any flow emits one. Switch + * the two guards together with that Cloud change, not as part of a pin bump. + * + * 2.0.22 is the current release. Beyond the above it carries + * AgentWorkforce/flows#484: a Claude agent step completes on Claude's own + * result rather than on process exit, so an agent that started a background + * task no longer holds the run open until its wall-clock limit. */ -export const RELAYFLOWS_VERSION = '2.0.15'; +export const RELAYFLOWS_VERSION = '2.0.22'; export const LOCAL_PREFLIGHT = 'relay-preflight.mjs'; export const LOCAL_INSTALL = `npm install --save-dev relayflows@${RELAYFLOWS_VERSION} @relayflows/surface@${RELAYFLOWS_VERSION}`; diff --git a/web/lib/flow-workflows.ts b/web/lib/flow-workflows.ts index 1bcba7b..76b9ad3 100644 --- a/web/lib/flow-workflows.ts +++ b/web/lib/flow-workflows.ts @@ -370,7 +370,7 @@ const REVIEW_BLOCKED_HEADING ='**Relayflow: the adversarial review did not pass. * Puts the failed review where an operator acts on it: on the pull request. * * `done("step_failed")` is the honest end for a review that found problems, and - * as of the 2.0.15 pin the runtime lowers it (AgentWorkforce/flows#436), so the + * since the 2.0.15 pin the runtime lowers it (AgentWorkforce/flows#436), so the * flow reports it. Up to 2.0.14 it did not: the authored executor lowered only * `success` and `needs_human` and threw `the initial authored executor cannot * lower done("step_failed")`, and a real run paid for it — 15 agent steps, a @@ -553,7 +553,7 @@ export function workflowCode(workflow: WorkflowId, agents: ReturnType { // `run.cancel`, budget from the enforced budget) that a flow body cannot // declare. flows#401, which promised `canceled`, is closed and superseded // by #436. The guards in flow-onboarding.ts want a deliberate declination - // instead — `declined`, proposed in AgentWorkforce/flows#438 and - // implemented in PR #439, which is open and unmerged. When a pinned release - // contains it, turn those two f.done("needs_human") calls into - // f.done("declined"), and not before. + // instead — `declined` (AgentWorkforce/flows#438, merged as #439), which + // every release from 2.0.16 lowers. 2.0.22 contains it, yet the guards + // deliberately stay on f.done("needs_human"): the same source runs on Agent + // Relay Cloud, which has to render a declined run first. Switch the two + // guards in the same change that teaches Cloud `declined`. + // 2.0.22 also carries AgentWorkforce/flows#484: a Claude agent step ends on + // Claude's result, not on process exit, so a background task the agent + // started can no longer hold the run open until its wall-clock limit. expect(LOCAL_INSTALL).toContain(`relayflows@${RELAYFLOWS_VERSION}`); expect(LOCAL_INSTALL).toContain(`@relayflows/surface@${RELAYFLOWS_VERSION}`); - expect(RELAYFLOWS_VERSION).toBe('2.0.15'); + expect(RELAYFLOWS_VERSION).toBe('2.0.22'); for (const workflow of ['traditional', 'prototype', 'simple'] as const) { const source = factorySource({ ...draft, workflow }, 'local'); const code = withoutComments(source); @@ -518,7 +522,7 @@ describe('relocating a kit that was extracted outside a repository', () => { if (options.dependency) { const pkg = join(target, 'node_modules', 'relayflows'); mkdirSync(pkg, { recursive: true }); - // The shape relayflows@2.0.15 really publishes: a bin and nothing to + // The shape relayflows really publishes (still true of 2.0.22): a bin and nothing to // import. A fake with a "main" let a bare resolve("relayflows") pass here // while it failed against every real install. mkdirSync(join(pkg, 'bin'), { recursive: true }); diff --git a/web/lib/test/flow-onboarding.test.ts b/web/lib/test/flow-onboarding.test.ts index 6e15a2b..6a8be58 100644 --- a/web/lib/test/flow-onboarding.test.ts +++ b/web/lib/test/flow-onboarding.test.ts @@ -357,7 +357,7 @@ describe('software factory onboarding', () => { const { calls, finish } = await runFactory([false, false, false]); expect(calls.filter(call => call.startsWith('adversary-'))).toHaveLength(2); expect(calls).not.toContain('human'); - // done("step_failed") is the honest reason, and as of the 2.0.15 pin the + // done("step_failed") is the honest reason, and since the 2.0.15 pin the // runtime lowers it (AgentWorkforce/flows#436). Before that it did not: a // real run did all 15 steps, opened AgentWorkforce/cloud-e2e-sandbox#25, // and then died as FAILED [protocol_error] unsupported_completion — the one diff --git a/web/lib/test/flow-workflows.test.ts b/web/lib/test/flow-workflows.test.ts index 82fd9aa..ad28cb4 100644 --- a/web/lib/test/flow-workflows.test.ts +++ b/web/lib/test/flow-workflows.test.ts @@ -217,7 +217,7 @@ describe('FLOW_CHECK_RUN_COMMAND', () => { /** * The step that runs when an adversarial review does not pass. The run itself - * reports `f.done("step_failed")` again: the 2.0.15 pin lowers that reason + * reports `f.done("step_failed")` again: every pin since 2.0.15 lowers that reason * (AgentWorkforce/flows#436), where 2.0.14 failed the whole run with * `unsupported_completion` after every agent had finished. An exit code still * cannot carry what the reviewer found, so this step puts the verdict where an