Repository navigation
Run Workflow nodes as ephemeral Bots with a queue, loops and conditions - #1412
Conversation
A second assign replaced the run, and the demo timer marked nodes done without a reply. Keep the live run, enqueue the next task, and leave a refused dispatch unhanded so the next hand-off can send it again. Co-authored-by: Danyang Chen <birfychen@gmail.com>
|
Verdict: REQUEST_CHANGES at 5aca831 Ran:
Not run:
Findings:
Same pass, not a separate refusal: plugins/workflow/index.js treats any reply matching /\b429\b|rate limit/i as a node failure. The host failure sentence already matches "could not answer your message" and "model call failed", and a 429 status is inside that sentence. A successful step whose text mentions a rate limit fails the node and does not start its successor. Match the host failure sentence only. What held at this tip: per-workflow FIFO at maxConcurrent (default 2) keeps the live run and its Bots; demo-step refuses while that workflow has a running lane; a refused dispatch is not marked handed and is named in the chat; a Bot reply advances the node and is the chat line; a reply the caller marks failed fails the node and does not start the successor; a required input with no upstream provider refuses the start; outputs move along edges; assign { botId } does not start a run. docs/subsystems/workflow.md and changelog.d/1402.changed.md are in the diff. risk-tier: T3. This conclusion does not enqueue the pull request. The enqueue guard on this head also reports missing label agent-pr; add that label when the tip is ready again. |
A pre-lane running script was treated as a live run, so replay never moved. A task parked at the host cap stayed queued when a different workflow finished, and the next assign could start ahead of it. Drain every workflow after a release, and fail a node only on the host's model-failure sentence. Co-authored-by: Danyang Chen <birfychen@gmail.com>
|
Owner: add loops + 条件判断 to this PR scope (with #1402). |
|
Verdict: REQUEST_CHANGES at a4034ad Ran:
Not run:
Findings:
What held at this tip:
This conclusion does not enqueue the pull request. |
A workflow node is an ephemeral Bot for that run. Its tools grant GitHub or a shell, and the host answers the hidden approval, so the step is not a permissionless shell and a seated botId is optional. A loop edge may cycle until its until output matches or it hits max. A when edge chooses one branch and skips the other. Replay can show the demo again after a live run finishes. Co-authored-by: Danyang Chen <birfychen@gmail.com>
Bring in the restart reap (#1388) so a running lane is abandoned on load. Co-authored-by: Danyang Chen <birfychen@gmail.com> # Conflicts: # docs/subsystems/workflow.md # plugins/workflow/src/service.js
A finished lane stayed on stage while demo-step only appended canned lines. Replay now keeps that lane until the first demo step, then the presented node status follows the script, including a migrated weekly run that had been left done. Co-authored-by: Danyang Chen <birfychen@gmail.com>
|
Verdict: REQUEST_CHANGES at 6e969c6 Ran:
Not run:
Prior blockers at this tip hold. migrateRuns keeps a running ephemeral run live and leaves every other old run as a demo (finished ones also copied to lane.last). The host cap drains the oldest enqueuedAt across workflows, and a newer assign waits behind it. A reply fails only on
Repro at this tip: choose outputs path; edges choose→left when eq left, choose→right when eq right, left→choose and right→choose loop max 4.
Fix in plugins/workflow/src/graph.js completeNode, looping branch: delete fired keys for every edge whose from is in the reset set, and set back to queued every skipped node that has a forward incoming edge from that set. Leave the loop target as the only running node. Add a test in plugins/workflow/test/branch.test.js: iteration 1 path=left skips right; iteration 2 path=right leaves right running and left skipped, with fired only choose>right.
Not enqueued. Security fence is not in this diff. The step-tool grant matches the owner model and fails closed when the step did not name the connector. |
A restart kept the previous when-edge and left the skipped sibling skipped, so the next pass opened the first branch again. Drop those decisions and queue the sibling. The permission cleanup also reports a delete that fails instead of swallowing it. Co-authored-by: Danyang Chen <birfychen@gmail.com>
|
Verdict: PASS at 4b5b7a3 Ran / reviewed:
Ready for merge queue. |
Written-by: Dev
Owner: Dev
Reviewer: Reviewer
Fixes #1402
What changed
A live Workflow run is no longer replaced by the next assign, and the demo timer no longer marks its nodes done. A second task waits in a FIFO queue (per-workflow
maxConcurrent, default 2, host cap 6). A node stays running until its ephemeral Bot replies, and that reply is the line in the Workflow chat.Each node is a real ephemeral Bot for that run, then it is removed. A seated sidebar Bot (
botId) is optional and is not required for the step. The node'stoolsequip that Bot:githubgrantsmcp__github__*so it can open pull requests, comment and review;bashorshellsetsdanger-full-access; any other step getsworkspace-write. The host stores this asstepToolsandpermission. A hidden run Bot cannot show an approval card, so a granted tool is allowed once and a connector the step did not name is refused.A loop edge is the only cycle (
max1–8, default 3, optionaluntil). Awhenedge chooses a branch and the other is skipped. Restarting the body drops the branch choice made inside it and queues a sibling the previous pass skipped, so the next pass can take the other side. Settings can add a link, a condition or a loop.After a live run finishes, the stage keeps that run until Replay steps the script. From that step on, the presented run is the demo, and its
nodeStatusmoves with each demo step, ahead of the finishedlane.last. A migrated finished weekly script does the same. A running live lane still wins.Each node can name inputs and outputs. A required input with no upstream provider refuses the start. A dispatch that does not land stays unhanded. A reply fails the node only when it says
could not answer your messageormodel call failed. A run still markedrunningat load is abandoned and its Bots are released (#1388, on the lane store). A permission preset that fails to apply deletes the new Bot and warns if that delete fails.Verification at the tip
Tip SHA: 4b5b7a3
Ran:
node --test plugins/workflow/test/*.test.js— 52 pass, 0 fail (includes the loop that takes the other branch on the next pass).Ran:
node .github/scripts/check-empty-catch.mjs— exit 0.node core/scripts/check-arch-docs.mjs— OK (29 changed files).node scripts/ds-bot-patches.mjs check— core matches the patches.Ran at
ad9b06bad9ed048a58ca05680364a692fe44e53d, whose grant behavior later commits kept:node --import ./test/harness-resolve.mjs --test test/flybot.test.js test/connector-access.test.js— 67 pass, 0 fail.Not run (and why): full
npm run verify— the other core and plugin suites were not run. No smoke test and no desktop run.Checkpoint
{ "pr": 1412, "claim": "Dev", "issue": 1402, "summary": "Each workflow node is an ephemeral Bot for that run, removed when the run ends. Its tools grant GitHub or a shell, and the host answers the hidden approval, so a seated Bot is optional. A loop edge cycles until its break output matches or it hits max, and the next pass can take the other branch. A when edge chooses one branch and skips the other. After a live run finishes, Replay keeps that run until the first demo step, then the stage's node status follows the script.", "files": ["plugins/workflow/src/graph.js", "plugins/workflow/src/service.js", "plugins/workflow/test/branch.test.js", "core/src/host/hooks.js", "core/src/host/approvals.js", "core/src/host/connector-access.js", "docs/subsystems/workflow.md", "plugins/workflow/README.md", "changelog.d/1402.changed.md"], "checks": { "ran": "node --test plugins/workflow/test/*.test.js", "result": "green", "at": "4b5b7a39b86b2f78a773708b52a99f1a8404cb51" }, "next": "none — ready for review" }