Repository navigation
fix(flows): keep seeded build turn propose-only (#4596) - #4607
Conversation
📝 WalkthroughWalkthroughThis PR updates frontend comments, agent policy text, server prompt directives, schema wording, and tests to state that ChangesPropose-only build persistence contract
Estimated code review effort: 2 (Simple) | ~15 minutes Possibly related issues
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 94aacd4aaa
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| dry_run_workflow, then return the proposal for me to review. Do NOT save_workflow in this turn: I will \ | ||
| Accept the proposal explicitly and the canvas's Save persists it. Do not enable, disable, or run_flow \ |
There was a problem hiding this comment.
Remove the remaining auto-save tool instruction
This turn-level prohibition is undermined because the workflow builder system prompt still appends the model-visible tool list, and SaveWorkflowTool::description() still tells the agent to use save_workflow after the user asked it to “build/update a workflow” (src/openhuman/flows/builder_tools.rs:1243-1247). In the prompt-bar build path that exact condition is true and a flow_id is present, so the agent still receives a conflicting instruction that can persist the graph before Accept/Reject; please update the actual tool description (or hide the tool for seeded build turns), not just the registry comment.
Useful? React with 👍 / 👎.
The Flows prompt bar's instant-create path routed through WorkflowCopilotPanel with `mode: 'build'`, whose server directive told the workflow_builder agent to `save_workflow` onto the freshly-created flow before Accept/Reject rendered. Reject then only cleared the local overlay — the persisted graph stayed on disk (and a schedule/app_event trigger would arm if the user later enabled the flow), violating the copilot's stated "propose only" invariant. Restore the invariant by making `build` mode propose-only, matching the existing `create`/`revise`/`repair` contract: - Rewrite DIRECTIVE_BUILD_AND_SAVE -> DIRECTIVE_BUILD_PROPOSE_ONLY and forbid `save_workflow` on the seeded turn explicitly. - Keep the flow_id injected as future-turn context (the user may later ask the agent to save/test it). - Realign the workflow_builder system prompt (`prompt.md`), the router descriptor (`agent.toml`), the `flows.build` RPC schema description, and the `save_workflow` tool comment so every doc surface says the same thing: `save_workflow` runs only on the user's explicit ask. - Frontend `WorkflowCopilotPanel` needs no behavior change — `mode: 'build'` still fires (naming preserved) but the server no longer asks the agent to persist. Comments updated to match. Regression test `build_is_propose_only_and_injects_flow_id_as_context` asserts the new directive forbids `save_workflow` and that none of the four historical auto-save phrasings survive. Closes tinyhumansai#4596
Landed unformatted on origin/main via tinyhumansai#4604 ("Fix/conversation timeline anchoring and dedup"). Blocking `pnpm --filter openhuman-app format:check` in `pr-quality.yml` on this PR. Two mechanical wraps — no code change: - Inline an `expect.objectContaining` literal. - Wrap a long `expect(...).toBe('')` chain across three lines. Not part of the tinyhumansai#4596 fix; included here purely to unblock CI.
94aacd4 to
44f4590
Compare
Summary
workflow_builderbuild directive to explicitly forbidsave_workflowon the seeded turn; realigns the system prompt, agent descriptor, RPC schema description, andsave_workflowtool comment so every doc surface says the same thing.mode: 'build'still fires; the server just no longer asks the agent to persist.build_is_propose_only_and_injects_flow_id_as_context) that guards against every historical auto-save phrasing coming back.Problem
Flagged as P1 by
chatgpt-codex-connectoron PR #4578 and filed as #4596.The Flows prompt bar's instant-create path did two real writes:
WorkflowPromptBar.tsxcallscreateFlow(...)(persists a blank flow), then navigates to/flows/:idwithstate.copilotBuild.WorkflowCopilotPanel.tsx:161-169seesbuildSeedand sendsmode: 'build'.builder_prompt.rs's oldDIRECTIVE_BUILD_AND_SAVEexplicitly told the agent tosave_workflowonto that flow id after dry-run.save_workflow→flows_update→ the graph is persisted before Accept/Reject ever renders.Reject (
WorkflowCopilotPanel.tsx:214-218) only didonReject()+clearProposal()— pure local overlay state; no RPC. So a user who rejected or closed the panel was left with a persisted flow they never approved. If the graph carried a schedule / app_event trigger and the user later enabled the flow, that trigger would arm.The invariant on
WorkflowCopilotPanel.tsx:19-20— "the copilot only PROPOSES. Accept applies to the UNSAVED local draft (noflows_update); persistence stays behind the canvas's own Save" — had already been silently violated by thebuildmode addition.Solution
Bring
buildmode back inside the propose-only invariant. Persistence stays a user-explicit action (Accept in the review card, then the canvas's own Save). Two options were considered:buildpropose-only (chosen) — small footprint, restores the stated invariant, matches every other authoring turn.Chose A.
Changes
src/openhuman/flows/agents/workflow_builder/builder_prompt.rsDIRECTIVE_BUILD_AND_SAVE→DIRECTIVE_BUILD_PROPOSE_ONLY. New directive explicitly says "Do NOT save_workflow in this turn: I will Accept the proposal explicitly and the canvas's Save persists it."BuildMode::Buildbranch ofrender_promptstill injectsflow_idas future-turn context (user may later ask "save it" / "run it"), but the injection line now labels it: "kept for future turns — do not save_workflow it here".BuildMode::Buildvariant doc to reference Rejecting a seeded flow build leaves the graph persisted #4596 and the propose-only contract.build_asks_to_save_onto_flow_id→build_is_propose_only_and_injects_flow_id_as_context. Asserts (a)Do NOT save_workflowappears; (b) none of the four historical auto-save phrasings (then SAVE,with save_workflow,SAVE it onto,save_workflow onto) survive; (c)flow_9+END-TO-ENDstill land.src/openhuman/flows/agents/workflow_builder/prompt.mdsave_workflowruns only when the user explicitly asks ("save this"); explains why auto-saving on a flow_id would leave the graph persisted even on Reject.src/openhuman/flows/agents/workflow_builder/agent.tomlwhen_to_useno longer tells the router the agent "may also SAVE the built graph" on flow-id delegation. Persistence stays with the user's Accept + Save;save_workflow/run_floware on explicit user ask only.src/openhuman/flows/schemas.rsflows.buildRPC controller description: "build (instant-create: build + dry-run + propose againstflow_id; propose-only, see Rejecting a seeded flow build leaves the graph persisted #4596)" instead of "…save_workflow onto flow_id". Adds "No mode auto-persists a graph."src/openhuman/tools/ops.rsSaveWorkflowToolregistration was defending an auto-save carve-out for the prompt bar. Rewrote to reflect explicit-ask usage.app/src/components/flows/WorkflowCopilotPanel.tsxsendforbuildSeed(~line 154) now describes a "build → dry-run → PROPOSE" arc and points at Rejecting a seeded flow build leaves the graph persisted #4596.mode: 'build'still fires (naming preserved) so the server can still distinguish "seeded from prompt bar" from a plain revise and inject the flow_id as context. No API break.app/src/components/flows/WorkflowCopilotPanel.test.tsxarg.request.mode === 'build'assertion still holds.What was deliberately not changed
save_workflowremains in the agent'snamedtools list — revise mode legitimately uses it on user ask.Submission Checklist
build_is_propose_only_and_injects_flow_id_as_contextcovers both the happy path (directive still injects flow_id and END-TO-END framing) and the failure path (four historical auto-save phrasings are asserted absent).BuildMode::Build, fully covered by the new + existingbuilder_prompttests.cargo test --lib openhuman::flows::agents::workflow_builder— 9 passed. Frontend edits are comment-only.N/A: behavior-only change restoring a documented invariant; no new feature row.## Related—N/A: behavior-only change, no matrix rows added/removed/renamed.N/A: bug fix restoring propose-only; the Flows seeded-build path smoke step is unchanged from the reviewer's perspective (Accept still applies, Save still persists).Closes #4596in## Related.Impact
mode: 'build'still accepted; only its rendered directive changes.Related
app/src/providers/__tests__/ChatRuntimeProvider.test.tsx(2 mechanical wraps, no code change) that landed unformatted via Fix/conversation timeline anchoring and dedup #4604 and was blockingpr-quality.yml'sformat:checkjob on this PR. Called out separately in the commit history so it's easy to review. The blank flow created by the prompt bar remains listed if the user Rejects; that's a first-class saved-but-empty flow they can delete or build up manually, which matches "Start from scratch" today.AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/4596-seeded-build-propose-only44f459007(rebased onto latestorigin/mainand includes one incidental Prettier autofix — see Follow-up TODOs below).Validation Run
pnpm --filter openhuman-app format:check— Prettier clean on touched frontend files (WorkflowCopilotPanel.tsx,WorkflowCopilotPanel.test.tsx).pnpm typecheck—N/A: no TS surface changed (only comments); frontend tests compile + pass via vitest run.cargo test --lib openhuman::flows::agents::workflow_builder→ 9 passed.cargo test --lib openhuman::flows::schemas→ 19 passed (no cascade from schema description edit).app/src/components/flows/*pass (WorkflowCopilotPanel.test.tsx,WorkflowPromptBar.test.tsx, and 14 more).cargo fmt --checkclean;cargo checkclean (no new warnings introduced).N/A: no Tauri host code changed.Validation Blocked
command:N/Aerror:N/Aimpact:N/ABehavior Changes
save_workflows onto the prompt-bar-seeded flow.mode: 'build'becomes propose-only, matchingcreate/revise/repair.Parity Contract
mode: 'build'still accepted at the RPC surface with the same request shape ({ mode, instruction, graph, flow_id }) andvalidate()still rejects a missing/blankflow_id.save_workflowtool is still registered and still callable when the user explicitly asks the agent to save.mode: 'revise'fallback inWorkflowCopilotPanel.tsx:168(used whenflowIdis somehow missing) is unchanged.Duplicate / Superseded PR Handling
Summary by CodeRabbit
New Features
Bug Fixes
Tests