Skip to content

fix(flows): canvas re-sync after save + Fix with agent on failed runs (B21/B22) - #4823

Merged
graycyrus merged 1 commit into
tinyhumansai:mainfrom
graycyrus:fix/flows-canvas-render-and-repair
Jul 13, 2026
Merged

graycyrus merged 1 commit into
tinyhumansai:mainfrom
graycyrus:fix/flows-canvas-render-and-repair

Conversation

@graycyrus

@graycyrus graycyrus commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • B21: FlowCanvasPage's Save handler now re-syncs the canvas draft from the flows_update response (instead of discarding it) and bumps the canvas key, so the canvas reflects the server's canonical persisted graph immediately — no more navigate-away-and-back to see it.
  • B22: wired the existing "Fix with agent" repair action (already fully built for FlowsPage's run-history drawer) into two failed-run surfaces that were missing it: FlowRunsSidebar (the canvas's own projected run history) and FlowApprovalCard (the pending-approval notification card).
  • Both new call sites reuse the existing location.state.copilotRepair navigation contract; FlowRunsSidebar's case required extra handling since it triggers from the same /flows/:id page (no page remount), detailed in Solution below.

Problem

Tracked live in my_docs/flows_workflow_bugs.md (bugs B21/B22), found while testing a real Gmail-summary workflow:

  • B21: after clicking Save, the canvas showed blank/stale content — the backend persisted correctly (save_workflow: persisted node_count=N), but the canvas didn't refetch/re-render on save success. Root cause: flows_update re-validates/normalizes the graph server-side before persisting (schema migration, id defaults, etc.), so the canonical response can differ from the client's just-sent graph — but FlowCanvasPage.handleSave discarded the updateFlow(...) response and re-baselined against its own pre-save nodes/edges, so the canonical shape only ever surfaced after a full navigate-away-and-back remount refetched it via flows_get.
  • B22: a run that failed with a clear provider error offered no one-click repair from two failed-run surfaces — the user had to manually re-prompt the copilot. The "Fix with agent" action itself (button, FlowRepairRequest, repair-mode builder turn) was already fully built and tested for FlowsPage's run-history drawer (Phase 5c), but FlowRunInspectorDrawer's onFixWithAgent prop is optional and two other call sites never passed it: FlowRunsSidebar (FlowCanvasPage's own projected sidebar — the single place fixing in-place is most natural) and FlowApprovalCard (a CoreNotification surface that can render from anywhere in the app).

Solution

  • B21: FlowCanvasPage.handleSave now captures updateFlow's response, casts its graph to WorkflowGraph, sets it as the new persistedGraphRef/draftGraph, and bumps canvasVersion — reusing the same force-remount idiom this file already uses for copilot-proposal accept/reject, so the editable canvas re-seeds from the canonical persisted graph without any navigation.
  • B22: both FlowRunsSidebar and FlowApprovalCard now build a handleFixWithAgent that navigates to /flows/:flowId with location.state.copilotRepair — the same contract FlowsPage's drawer already uses.
    • FlowApprovalCard can render from anywhere, so this is a plain navigation (mirrors FlowsPage's existing handler exactly).
    • FlowRunsSidebar is only ever mounted on the SAME flow's canvas page, so this navigation does not remount FlowCanvasPage/FlowEditor (same route, only location.state/location.key change). That breaks two mount-once assumptions: the copilot-open useState initializer, and WorkflowCopilotPanel's once-per-mount repair auto-fire guard (repairSentRef). Fixed by (a) re-asserting copilotOpen during render when a new repair seed prop arrives (React's "adjust state during render" pattern — avoids an extra useEffect render pass and the react-hooks/set-state-in-effect lint warning), and (b) folding location.key (react-router mints a fresh one per navigation, including same-path repeats) into the copilot panel's key so a same-route repair request still forces a fresh panel mount. Build-seed/manual-open behavor is untouched — those already get a fresh FlowEditor mount today, so their panel key stays the stable 'copilot' string.

Testing

  • Added a FlowCanvasPage.test.tsx case: mocks updateFlow to resolve with a graph that differs from what the client sent (renamed node + an extra "server-added" node) and asserts the canvas shows all three response nodes immediately, with no extra flows_get call and no remount.
  • Added FlowRunsSidebar.test.tsx (new file): run list renders, opens the inspector drawer, forwards onFixWithAgent, and — invoking that callback — asserts the sidebar's own drawer closes and the app navigates to the same flow with the right copilotRepair state.
  • Extended FlowApprovalCard.test.tsx with the equivalent onFixWithAgent-wiring and navigation assertions (also switched its render helper to a MemoryRouter, now required since the card calls useNavigate).
  • pnpm typecheck, pnpm lint, pnpm i18n:check all pass; no new user-facing strings were introduced (no i18n key changes needed).
  • Full local run of src/components/flows, src/components/notifications, and src/pages/__tests__/FlowCanvasPage.test.tsx: 23 files / 217 tests passing.

Impact

  • Frontend-only (app/src/); no Rust/RPC changes. No new external network dependencies.
  • No migration/compatibility concerns — reuses existing RPCs (flows_update, flows_build mode=repair) and the existing copilotRepair navigation contract.

Related

  • Closes: N/A (tracked in my_docs/flows_workflow_bugs.md as B21/B22, not a GitHub issue)
  • Follow-up PR(s)/TODOs: FlowListRow.tsx's last_status text and FlowRunsDrawer's per-row status badges still require opening the inspector drawer before "Fix with agent" is reachable (one extra click, not a missing wire) — left out of scope here.

AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/flows-canvas-render-and-repair
  • Commit SHA: 3897e04

Validation Run

  • pnpm --filter openhuman-app format:check
  • pnpm typecheck
  • Focused tests: src/components/flows, src/components/notifications, src/pages/__tests__/FlowCanvasPage.test.tsx (217 passing)
  • Rust fmt/check (if changed): N/A, no Rust changes
  • Tauri fmt/check (if changed): N/A, no Tauri shell changes

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended behavior change: canvas reflects the server's canonical saved graph immediately after Save; "Fix with agent" is now reachable from the canvas's own run sidebar and from the approval notification card, not just the Flows list's run-history drawer.
  • User-visible effect: no more blank/stale canvas after Save; one-click repair available from more failed-run surfaces.

Parity Contract

  • Legacy behavior preserved: manual copilot open/close and the prompt-bar build-seed flow are unaffected (unchanged panel key, unchanged mount timing).
  • Guard/fallback/dispatch parity checks: WorkflowCopilotPanel's repair/build auto-fire guards (repairSentRef/buildSentRef) are untouched; only the panel's remount key changed for the new same-route repair case.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none known
  • Canonical PR: this one
  • Resolution (closed/superseded/updated): N/A

Summary by CodeRabbit

  • New Features

    • Added a “Fix with agent” option for flow runs and pending approval notifications.
    • Selecting it opens the relevant flow with repair context preloaded in the assistant.
  • Bug Fixes

    • Flow run details now close correctly when starting an agent-assisted repair.
    • Saving a flow immediately reflects server-applied updates and validations.
    • Repair prompts reliably reopen when switching between flow runs.

… sidebar/approval card (B21/B22)

B21: `flows_update` re-validates/normalizes the saved graph server-side, so
the canonical response can differ from what the client sent — but the
canvas re-baselined against its own pre-save nodes/edges and ignored the
response, so the canonical graph only ever appeared after a navigate-away-
and-back remount refetched it. `FlowCanvasPage`'s `handleSave` now re-syncs
`draftGraph`/`persistedGraphRef` from the `flows_update` response and bumps
`canvasVersion` to re-seed the editable canvas immediately.

B22: the failed-run "Fix with agent" repair action (already fully wired from
`FlowsPage`'s run-history drawer, Phase 5c) was missing from two other
failed-run surfaces that mount `FlowRunInspectorDrawer` without the
`onFixWithAgent` prop: `FlowRunsSidebar` (the canvas's own projected run
history — the single place fixing in-place is most natural) and
`FlowApprovalCard` (the pending-approval notification card, which can render
from anywhere in the app). Both now navigate to the flow's canvas seeded with
`location.state.copilotRepair`, same mechanism as the existing path.

Since `FlowRunsSidebar` is only ever mounted on the SAME flow's canvas page,
its repair navigation doesn't remount `FlowCanvasPage`/`FlowEditor` — so the
one-time `useState` copilot-open initializer and the copilot panel's
once-per-mount repair auto-fire guard wouldn't otherwise re-trigger. Fixed by
reacting to a changed repair seed during render (no extra render pass) and
folding `location.key` into the copilot panel's key so a same-route repair
request still forces a fresh panel mount.
@graycyrus
graycyrus requested a review from a team July 13, 2026 14:19
@coderabbitai

coderabbitai Bot commented Jul 13, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Flow run surfaces now expose agent repair navigation with failing-run metadata. The flow canvas reopens copilot repair seeds across route updates and synchronizes persisted drafts with canonical server responses after saving.

Changes

Agent repair flow

Layer / File(s) Summary
Repair callbacks from run surfaces
app/src/components/flows/FlowRunsSidebar.tsx, app/src/components/flows/FlowRunsSidebar.test.tsx, app/src/components/notifications/FlowApprovalCard.tsx, app/src/components/notifications/FlowApprovalCard.test.tsx
Run sidebar and approval cards pass onFixWithAgent to the inspector drawer, navigate to the flow route, close the drawer, and write the failing run metadata into location.state.copilotRepair; tests cover wiring, navigation, and empty states.
Repair seed handling in the canvas
app/src/pages/FlowCanvasPage.tsx
FlowEditor tracks repair seeds, uses location.key to remount the copilot panel when needed, and receives the key from both canvas page variants.

Canonical canvas save synchronization

Layer / File(s) Summary
Server-canonical save state
app/src/pages/FlowCanvasPage.tsx
Persisted saves update the draft and persisted baseline from updated.graph, then increment canvasVersion.
Canonical save regression coverage
app/src/pages/__tests__/FlowCanvasPage.test.tsx
The save test verifies server-normalized nodes render immediately without an additional flow fetch or page remount.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested labels: bug, agent

Poem

I’m a rabbit with a repair request,
Hopping through routes with failing runs in tow.
Copilot wakes when seeds arrive,
Saved graphs bloom as servers know.
Thump, thump—fresh canvas glow!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the two main changes: canvas re-sync after save and adding Fix with agent for failed runs.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. bug labels Jul 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3897e04408

ℹ️ About Codex in GitHub

Codex has been enabled to automatically 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 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +376 to +377
setDraftGraph(persisted);
setCanvasVersion(v => v + 1);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid overwriting edits made while a save is in flight

When a save is slow and the user keeps editing after clicking Save, EditableFlowCanvas still accepts palette/node/config edits while only Save/Discard are disabled. Those edits update the host draft via onGraphChange, but this response handler later unconditionally replaces the draft with the graph for the older save request and bumps canvasVersion, remounting the canvas and dropping the post-click edits. Please either disable editing during saving or only re-sync from the response if the current draft still matches the saved snapshot.

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
app/src/pages/FlowCanvasPage.tsx (1)

220-232: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a diagnostic log for the repair-seed reopen transition.

This state transition (a new repair seed reopening the copilot panel without a FlowEditor remount) has no log line, unlike the other new B22/B21 flows in this file (handleFixWithAgent, handleSave) which all log their transitions.

As per path instructions: "New or changed flows must include verbose, grep-friendly diagnostics for entry/exit, branches, external calls, retries/timeouts, state transitions, and errors."

🔍 Proposed diagnostic addition
   const [seenCopilotSeed, setSeenCopilotSeed] = useState(initialCopilotSeed);
   if (initialCopilotSeed !== seenCopilotSeed) {
     setSeenCopilotSeed(initialCopilotSeed);
-    if (initialCopilotSeed) setCopilotOpen(true);
+    if (initialCopilotSeed) {
+      log('repair seed changed — reopening copilot panel run=%s', initialCopilotSeed.runId);
+      setCopilotOpen(true);
+    }
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@app/src/pages/FlowCanvasPage.tsx` around lines 220 - 232, In the render-time
transition guarded by initialCopilotSeed !== seenCopilotSeed, add a verbose,
grep-friendly diagnostic log when a new repair seed is detected and the copilot
panel is reopened. Include the seed transition context and retain the existing
setSeenCopilotSeed and setCopilotOpen behavior unchanged.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@app/src/pages/FlowCanvasPage.tsx`:
- Around line 220-232: In the render-time transition guarded by
initialCopilotSeed !== seenCopilotSeed, add a verbose, grep-friendly diagnostic
log when a new repair seed is detected and the copilot panel is reopened.
Include the seed transition context and retain the existing setSeenCopilotSeed
and setCopilotOpen behavior unchanged.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4a049700-f54e-4021-be31-827f01f17718

📥 Commits

Reviewing files that changed from the base of the PR and between 407fd8e and 3897e04.

📒 Files selected for processing (6)
  • app/src/components/flows/FlowRunsSidebar.test.tsx
  • app/src/components/flows/FlowRunsSidebar.tsx
  • app/src/components/notifications/FlowApprovalCard.test.tsx
  • app/src/components/notifications/FlowApprovalCard.tsx
  • app/src/pages/FlowCanvasPage.tsx
  • app/src/pages/__tests__/FlowCanvasPage.test.tsx

@graycyrus
graycyrus merged commit f517ff8 into tinyhumansai:main Jul 13, 2026
21 of 24 checks passed
@github-project-automation github-project-automation Bot moved this from Todo to Done in Team Openhuman Jul 13, 2026
senamakel pushed a commit to nocstah/openhuman that referenced this pull request Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent Built-in agents, prompts, orchestration, and agent runtime in src/openhuman/agent/. bug

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

1 participant