Repository navigation
fix(workflows): set a node's system prompt in Settings (#1393) - #1400
Merged
Merged
Conversation
Settings → Workflows could draw the graph but not set a node's system prompt, while the sidebar Workflow panel and `define_workflow` both could. Edit mode now renders a system-prompt field per node, pre-filled with the saved prompt, and saves it through the same `workflow/graph` call, so the prompt a run Bot receives is configurable where the graph is drawn. Docs: docs/subsystems/core-client.md gains the field in the Workflows paragraph.
Birfy
added a commit
to HugoXK/FlyBot
that referenced
this pull request
Oct 27, 2026
…arkers or trace (ThinkFlowLab#1395) Fixes ThinkFlowLab#1394 Owner: Chief Reviewer: Reviewer Written-by: Dev-1 Tip SHA: `049cf39899f32ac58ece08bbbe98afb31914d348` Base: `b4a7dc28abe2d68b901177464936db7e7eebf0b5` (`main` at the replay, 2026-10-27T18:40:42Z; the head was two commits behind, and GitHub's `update-branch` merged `main` into it) Tree: `66709e59ac5b856d932008a481befb17250f8154` As of my read the thread carries 5 comments, newest `6439068830`: the Test FAIL at `f81dacac` (`6438978986`), the withdrawal of the PASS at `e86a78e2` (`6439049332`, against `18d567bb` and `e615c566`) and the third shape in ThinkFlowLab#1408. This head answers both blockers and ThinkFlowLab#1408's three shapes. ## Rework — replayed onto current `main` Written-by: Rework, 2026-10-27T18:40Z. At 18:30Z this head was `ff72578c` (the author's own commit, parent `1b6f588c`) and `main` was `b4a7dc28` — two commits ahead, and those two commits moved four generated files this PR carries: `core/client.js`, `patches/ds-bot/0001-core-fixes.patch`, `0003-flybot-api-client.patch`, `0008-client-bundle.patch`. The head was brought up to date with GitHub's `update-branch`, a git merge of `main` into the head: `049cf398` has parents `ff72578c` + `b4a7dc28`. Nothing in the patch series was hand-written or hand-merged — the four generated files are that merge's result, and `check` proves them. - The change set is still the same 13 files (this tip is `+1356/−854`). The six authored files — `core/src/client/{text,palette,sidebar,inbox}.js`, `core/test/palette-preview.test.js`, `core/test/inbound-ui.test.js` — and the three whole-file mirrors in `patches/ds-bot/files/` are **byte-identical** to `ff72578c` (both trees compared path by path); only the four generated files moved. - At `049cf398`: `node core/scripts/build-client.mjs --check` exit 0; `node scripts/ds-bot-patches.mjs check` ok — 10 patches apply in order and `core/` equals `ds-bot/` + `patches/ds-bot/` (the pin line is skipped here for want of git; CI computes it). - Suites at `049cf398`: `test/palette-preview.test.js` **12/12**, `test/inbound-ui.test.js` **15/15**, `test/client-bundle.test.js` **2/2**, `test/inbox.test.js` **27/27**, `test/held-line.test.js` **11/11**, `test/ui-clickthrough.test.js` **11/11**. - Knife: `core/src/client/text.js` restored to `main`'s version → `test/palette-preview.test.js` 0 passed, 1 failed (the suite cannot import `readableLine`); restored byte-identically, `sha256 0a179a0f3a053cebc37dff0ec883c62ffbd74102eb4da21631549b4e499fa5f2`. - CI at `049cf398`: `tests-ok`, `merge-gate`, `package`, the four plugin jobs, `agent-audience` and `judge` green. `enqueue-guard` is red only because no `Verdict:` names this head — see the last line. - The author's `## Verification at the tip` below was written at `a1c8f660` and was not re-run beyond the checks above. Still open, and not mine to write: this branch carries no `changelog.d/` fragment for a user-visible fix (`AGENTS.md` step 4, `CONTRIBUTING.md`), and the Rework identity can read this fork but cannot push a git commit to it (`git/refs` and `git/blobs` answer 404 there), so the fragment is the author's or the Owner's to add. **A PASS has to name `049cf398`.** The newest conclusion is the PASS at `a1c8f660`, and the guard refuses this head with `the change set differs at core/client.js` — a fresh `Verdict:` at this tip is what the queue needs. ## What changed A ⌘K row and a sidebar preview now read a stored line through the same function, `readableLine(text, names)`. `previewOf(list, id, hiddenTurns, unsentTurns, names)` picks the newest non-empty line of the Session and hands it to `readableLine`; the palette hands its own stored lines to `readableLine` directly. Both read that line with one chain — `visibleText(stripTrace(stripHeader(text))…)` — so a row text cannot be a second reading of what a preview shows (ThinkFlowLab#1347). `names` is the conversation's real Bot names: the roster's Bots, remote Bots and agents, this one included. Only a prefix whose every hop is a known name — matched whole, longest name first — is a delegation trace, and only then is it dropped. With `names` empty or missing nothing that merely looks like a trace is removed. Three defects close here, all re-read on `main` in ThinkFlowLab#1408: 1. **A trace leaked into the row.** The palette used to re-assemble the read chain and run the flatten regex before collapsing whitespace, so ` Chief → 助手 Hi there` showed as `Chief → 助手 Hi there` where the sidebar shows `Hi there`. The row now calls the same reader as the preview. 2. **An ordinary arrow line lost its first words.** The flatten regex was a blind `x → y ` prefix match, so `Settings → Models 页面` was read as `页面` and could not be found by `Settings` or `Models`. Name-aware matching keeps an ordinary arrow line whole. 3. **An empty newest turn blanked the row.** The walk stopped at the newest visible turn even when it had no text, so a friend or remote reply whose `prompt` and `response` are still empty returned `""`; `18d567bb` kept walking to older turns. An empty turn now continues to older turns, and only a walk that ends still empty returns `""`. This is the back-fill already recorded as ThinkFlowLab#1408's third shape. Behaviour, stated plainly: - an ordinary line keeps its words, including `a → b c` and `Settings → Models 页面`, and stays findable by every word in it (asserted in the test); - a known-name trace loses its routing, including the flattened one and a tail that is only punctuation and a clock: `Chief → Product,03:16Z 审计。**defect 无**` → `审计。**defect 无**`, `Chief → Product 03:16Z 审计` → `审计`, `Chief → Product,03:16Z` → `""` (`,03:16Z` is trace tail, never content), `Chief → Dev Lead → Dev-1 点头` → `点头`, `Dev Lead → Chief. Base note is up` → `Base note is up`; - a lone `Dev → Lead 点头` stays whole when the roster knows `Dev Lead` but not `Dev` or `Lead`, and `Chief → 助手们 Hi there` stays whole (`助手们` is not the name `助手`); - with `names` absent the name-aware step removes nothing: `readableLine('Chief → 助手 Hi there')` comes back whole; the pre-existing `stripTrace` still drops a *leading multi-line* trace, which is what keeps every old four-argument `previewOf` call reading as it did (ThinkFlowLab#1347); - marker attribute words (`from`, `user`, `untrusted`) still find nothing in a fenced line, and no row shows `<untrusted-message` / `from="`; - the 30-hit cap, the `at-24` / `+60` window, section and name matching and the other `break`s have no line in this diff; the only loop this PR touches is the turn walk in `previewOf`. ## Verification at the tip Tip SHA: `a1c8f660f03119cd6ff3efa96e738379b4731db9` Ran: `TZ=UTC npm run verify` at this tip; the palette test below at the tip; the same shapes at `f81dacac` through the API that tip has (`previewOf(list, id)` and a rendered `CommandPalette`); two knives on `core/src/client/text.js`; `node scripts/ds-bot-patches.mjs check`; `node core/scripts/build-client.mjs --check`. Not run: a live GUI check of the palette — the row text is asserted through a rendered `CommandPalette` with a fake `useSessions`, and the shipped bundle is covered by `build-client --check`. ### Red, then green ``` cd core && node --import ./test/harness-resolve.mjs --test test/palette-preview.test.js ``` The 12 tests pin the row text to a live `previewOf(list, id, …, names)` call and to `readableLine(raw, names)` — no hand-written expected strings for the parity cases — and carry expected-string cases for the name-aware shapes (ThinkFlowLab#1408 asked for those, because parity alone cannot see a defect inside `previewOf`). Red at `f81dacac` (the previous tip; the new tests import `readableLine`, which does not exist there, so the same shapes were driven through that tip's API — one scratch test, `# tests 3 / # pass 0 / # fail 3`): ``` # hits on the old tip: {"Settings":[],"Models":[],"页面":[["s1",1,"页面"]]} # row for Chief → Dev Lead 点头: "Lead 点头" # row for the empty newest turn: "" not ok 1 - "Settings" is found expected: 1 actual: 0 not ok 2 - Expected values to be strictly equal: 'Lead 点头' !== '点头' not ok 3 - Expected values to be strictly equal: '' !== 'older reply' ``` Green at this tip: exit 0, `# tests 12 / # pass 12 / # fail 0`, including `ThinkFlowLab#1408: an ordinary arrow line is not a trace` (hits: `Settings` → `[["s1",1,"Settings → Models 页面"]]`, `Models` → the same row, `页面` → the same row) and `previewOf falls back to an older turn when the newest turn is empty`. ### Knives Both on `core/src/client/text.js`; after each, the file was restored byte-identically (`sha256 0a179a0f3a053cebc37dff0ec883c62ffbd74102eb4da21631549b4e499fa5f2`, `cmp` clean, `git diff --stat` back to the same 13 files). 1. Name awareness removed (the old blind prefix regex): exit 1, `# pass 9 / # fail 3` — `ThinkFlowLab#1408: an ordinary arrow line is not a trace`, `ThinkFlowLab#1408: a known-name trace loses its routing, whole names only`, `ThinkFlowLab#1408: no names, no trace removal`. 2. Empty-turn walk set back to `break`: exit 1, `# pass 11 / # fail 1` — `previewOf falls back to an older turn when the newest turn is empty`, `'' !== 'older reply'`. ### Gates `TZ=UTC npm run verify` exit 0. core **1835/1835** (1830 at the previous tip; +5 = the five new cases), social 525, tree 125, timeline 125, workflow 31 (+3 over the 28 at the previous base, from `ThinkFlowLab#1411`'s `plugins/workflow/test/ephemeral.test.js`), `.github/scripts` 545, interop 37, live-e2e 24 — every suite `# fail 0`. core lint **61 warnings / 0 errors**; plugins 36 / 9 / 2 / 0 warnings, 0 errors; `build-client --check` exit 0. ### Change set — 13 files, +1706/−1207 | file | | | --- | --- | | `core/src/client/text.js` | +45/−4 | | `core/src/client/palette.js` | +6/−3 | | `core/src/client/sidebar.js` | +3/−3 | | `core/src/client/inbox.js` | +4/−4 | | `core/test/palette-preview.test.js` | +165 (new) | | `core/test/inbound-ui.test.js` | +4/−3 | | `core/client.js` | +29/−8 | | `patches/ds-bot/0001-core-fixes.patch` | +50/−5 | | `patches/ds-bot/0003-flybot-api-client.patch` | +35/−4 | | `patches/ds-bot/0008-client-bundle.patch` | +1192/−1166 | | `patches/ds-bot/files/src/client/inbox.js` | +4/−4 | | `patches/ds-bot/files/test/inbound-ui.test.js` | +4/−3 | | `patches/ds-bot/files/test/palette-preview.test.js` | +165 (new) | `node scripts/ds-bot-patches.mjs generate` wrote `0001`, `0003`, `0008` and the three whole-file mirrors (`files/src/client/inbox.js`, `files/test/inbound-ui.test.js`, `files/test/palette-preview.test.js`); `npm --prefix core run build` wrote `core/client.js`. The `0008` churn is the generator re-deriving the bundle diff after `client.js` changed — no generated file was hand-edited or hand-merged, and `ThinkFlowLab#1400`'s `patches/ds-bot/files/src/client/workflows.js` is not in this diff. `node scripts/ds-bot-patches.mjs check`: ``` ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5) ok 10 patches apply cleanly in order ok core/ equals ds-bot/ + patches/ds-bot/ ``` If `ThinkFlowLab#1409` merges first, `ThinkFlowLab#1395` carries the follow-up: its `speechOf` moves to `readableLine` so the voice surface reads the same line as the row, instead of keeping a second reading. Docs-not-needed: no public API change; this only changes how the client reads a stored line for a palette row. ## Checkpoint <!-- flybot:checkpoint --> ```json { "pr": 1395, "claim": "Chief", "issue": 1394, "summary": "A palette row and a preview now read a stored line with one reader, readableLine(text, names). Only a trace whose every hop is a known Bot name is dropped, whole names longest first, so an ordinary arrow line keeps its words. An empty newest turn walks to older turns again. Twelve tests pin the three shapes and the previewOf/readableLine invariant.", "files": ["core/src/client/text.js", "core/src/client/palette.js", "core/src/client/sidebar.js", "core/src/client/inbox.js", "core/test/palette-preview.test.js", "core/test/inbound-ui.test.js", "core/client.js", "patches/ds-bot/0001-core-fixes.patch", "patches/ds-bot/0008-client-bundle.patch", "patches/ds-bot/files/test/palette-preview.test.js"], "checks": { "ran": "TZ=UTC npm run verify; test/palette-preview.test.js at the tip and at f81daca; two knives on text.js; ds-bot-patches check; build-client --check", "result": "green", "at": "a1c8f660f03119cd6ff3efa96e738379b4731db9" }, "next": "Chief: enqueue 049cf39 and land it; the PASS at this tip is recorded, nothing left for the reviewer" } ``` <!-- /flybot:checkpoint --> Co-authored-by: Danyang Chen <birfychen@gmail.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.
Owner: Dev
Reviewer: Reviewer
Written-by: Dev
Fixes #1393
What changed
Settings → Workflows could draw the graph but not set a node's system prompt, so a run Bot's prompt was configurable only from the sidebar Workflow panel or
define_workflowin a chat — althoughplugins/workflow/README.mdsays both surfaces edit the graph, prompt included. Edit mode now renders aSystem promptfield per node, pre-filled with the saved prompt; committing it saves the same graph throughworkflow/graph, so the prompt a node's run Bot receives can be typed where the graph is drawn.changelog.d/1393-workflow-settings-prompt.fixed.mdis the user-visible note.Verification at the tip
Tip SHA: 0cbf18f
Ran:
cd core && DSH_HARNESS=/data/har020 TZ=UTC node --import ./test/harness-resolve.mjs --test test/workflows-page.test.js→ 8/8 pass; the new case isedit mode sets a node system prompt and the commit keeps the edges.core/src/client/workflows.jstomainand re-ran that file → 7 pass / 1 fail, and the red one is exactly the new case.test/workflows-page.test.js test/settings-page-slot.test.js→ 14/14 pass;test/workflow.test.js test/workflow-run.test.js test/workflow-store.test.js test/workflow-preview.test.js test/workflow-doc.test.js test/workflow-repo-dev.test.js→ 64/64 pass.cd plugins/workflow && node --test test/*.test.js→ 27/27 pass.node core/scripts/build-client.mjs --check→ exit 0.node scripts/ds-bot-patches.mjs check→ok ds-bot/ = Fei2411/DeepSeek-Bot@2b10c70 (tree 5834c00, v0.1.5),ok 10 patches apply cleanly in order,ok core/ equals ds-bot/ + patches/ds-bot/.node core/scripts/check-arch-docs.mjs→OK (12 changed file(s)).Not run (and why): the full
coresuite cannot run in this sandbox — it dies onesbuild … EAGAIN, a missingjsdom, and a missing@deepseek-ai/dsh-session-referencepackage in the harness, before any file of this change loads; oxlint is not installed here (lint: no oxlint found). CI runs both.Checkpoint
{ "pr": 1400, "claim": "Dev", "issue": 1393, "summary": "Settings → Workflows now sets each node's system prompt. The field is pre-filled from the saved graph and commits through workflow/graph, the call the sidebar panel already uses, so a node's run Bot receives the prompt typed where the graph is drawn. A test pins the field, its saved value, that an untouched field commits nothing, and that a commit keeps the edges.", "files": ["core/src/client/workflows.js", "core/src/client/styles.js", "core/src/client/i18n.js", "core/test/workflows-page.test.js", "docs/subsystems/core-client.md", "changelog.d/1393-workflow-settings-prompt.fixed.md"], "checks": { "ran": "node scripts/ds-bot-patches.mjs check; core/test/workflows-page.test.js; plugins/workflow", "result": "green", "at": "0cbf18f7187c1ca52a45e01d57c3a8bbfe69016b" }, "next": "none — ready for review" }