Skip to content

feat(flows): add a Stop button to the Workflow Copilot composer - #5223

Merged
graycyrus merged 8 commits into
tinyhumansai:mainfrom
graycyrus:feat/copilot-stop-button
Jul 28, 2026
Merged

feat(flows): add a Stop button to the Workflow Copilot composer#5223
graycyrus merged 8 commits into
tinyhumansai:mainfrom
graycyrus:feat/copilot-stop-button

Conversation

@graycyrus

@graycyrus graycyrus commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a Stop button to the Workflow Copilot composer, matching the main chat: while a builder turn is in flight, the Send button morphs into a Stop button that cancels the turn.
  • Expose stop() from useWorkflowBuilderChat and pass it as onStopGeneration to the copilot's ChatComposer (which already had the send↔stop morph logic).

Problem

The main chat's ChatComposer shows a Stop button while isSending is true and an onStopGeneration handler is wired (showStopButton), letting the user cancel an in-flight generation. The Workflow Copilot already renders the same ChatComposer, but never passed onStopGeneration — so the Stop button never appeared and there was no way to cancel an in-flight builder turn (which can run for a while, e.g. a 70s+ grounding+build turn).

Solution

  • useWorkflowBuilderChat now returns stop(). It cancels the current thread's turn via chatCancel(threadId) — the same primitive the main chat's handleStopGeneration uses (openhuman.channel_web_cancel). The flows_build turn streams over the same web-channel surface (confirmed: it emits external_transfer_pending service=chat-v1 on the copilot thread), so the thread-scoped cancel applies. stop() is a no-op when nothing is in flight or no thread is bound, and flips sending off on a confirmed cancel for immediate button feedback (the in-flight send promise also clears it in its finally).
  • WorkflowCopilotPanel passes onStopGeneration={stop} to ChatComposer. No changes to ChatComposer itself — it already renders the Stop button when isSending && onStopGeneration && !hasTypedContent.

Submission Checklist

  • Tests added or updated (happy path + edge) — stop cancels the in-flight builder turn via chatCancel and clears sending and stop is a no-op when nothing is in flight in useWorkflowBuilderChat.test.ts; existing WorkflowCopilotPanel (36) and hook (32) tests still pass.
  • Diff coverage ≥ 80% — the new stop path is covered by the two new hook tests; the one-line panel prop is exercised by the existing panel render tests. CI coverage gate authoritative.
  • N/A: behaviour-additive UX change — no matrix feature row added/removed/renamed.
  • N/A: no matrix feature IDs affected.
  • No new external network dependencies introduced — reuses the existing chatCancel service.
  • N/A: does not change a release-cut smoke flow (additive composer control; existing chat Stop is already covered).
  • N/A: no separate tracked GitHub issue — user-requested parity with the main chat Stop button.

Impact

  • Frontend only (two app/src files + a test). No Rust/Tauri change, no new RPC — openhuman.channel_web_cancel already exists and backs the main chat Stop. No effect on the main chat or any non-copilot surface.

Related

  • Closes: N/A (parity feature request)
  • Follow-up PR(s)/TODOs: optionally persist the copilot's partial reply as a "stopped" message on cancel (the main chat does this); omitted here to keep the change minimal.

AI Authored PR Metadata

Linear Issue

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

Commit & Branch

  • Branch: feat/copilot-stop-button
  • Commit SHA: df1b66c253af5aefe497a0a640f4ccf488db1df8

Validation Run

  • pnpm --filter openhuman-app format:check — prettier clean on changed files
  • pnpm typecheck — exit 0, no TS errors
  • Focused tests: useWorkflowBuilderChat.test.ts (32 passed) + WorkflowCopilotPanel.test.tsx (36 passed)
  • Rust fmt/check: N/A — no Rust changes
  • Tauri fmt/check: N/A — no Tauri changes

Validation Blocked

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

Behavior Changes

  • Intended: the Workflow Copilot composer shows a Stop button while a builder turn is in flight; clicking it cancels the turn.
  • User-visible effect: parity with the main chat — an in-flight copilot turn can be stopped instead of only being able to wait for it.

Parity Contract

  • Legacy behavior preserved: yes — ChatComposer unchanged; when no onStopGeneration is passed (every other caller) behavior is identical to before. Main chat Stop untouched.
  • Guard/fallback/dispatch parity: stop() no-ops without a bound thread or in-flight turn.

Duplicate / Superseded PR Handling

  • Duplicate PR(s): none
  • Canonical PR: this
  • Resolution: N/A

Summary by CodeRabbit

  • New Features

    • Added a stop control for workflow copilot responses, allowing in-progress generations to be interrupted.
    • Stop/cancel is now supported end-to-end for active workflow builder turns, with optional request scoping.
  • Bug Fixes

    • Stop actions are safely ignored when nothing is currently generating.
    • Fixed a race condition so overlapping generations won’t cause the UI to stop/cancel the wrong attempt.
  • Tests

    • Added/updated coverage for stop/cancel behavior, including no-op cases and overlapping re-send scenarios.

The main chat's Send button morphs into a Stop button while a turn is
in flight (ChatComposer's showStopButton, wired to handleStopGeneration ->
chatCancel). The Workflow Copilot already renders ChatComposer but never
passed onStopGeneration, so the Stop button never appeared and an in-flight
builder turn could not be cancelled.

Expose a stop() from useWorkflowBuilderChat that cancels the current
thread's turn via the same chatCancel (openhuman.channel_web_cancel)
primitive the main chat uses -- the flows_build turn streams over the same
web-channel surface, so the thread-scoped cancel applies -- and pass it as
onStopGeneration to the copilot's ChatComposer. No-op when nothing is in
flight or no thread is bound.
@graycyrus
graycyrus requested a review from a team July 27, 2026 16:10
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 37090256-f46b-4277-88d4-71f57d366541

📥 Commits

Reviewing files that changed from the base of the PR and between 07f1f19 and fdbc14d.

📒 Files selected for processing (3)
  • app/src/hooks/useWorkflowBuilderChat.test.ts
  • app/src/hooks/useWorkflowBuilderChat.ts
  • app/src/services/api/flowsApi.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • app/src/hooks/useWorkflowBuilderChat.ts

📝 Walkthrough

Walkthrough

Workflow builder generation can now be stopped through ChatComposer. Cancellation travels through a frontend RPC wrapper and flows controller to a thread-scoped cancellation registry, while tests cover idle cancellation, settlement, and resend races.

Changes

Workflow build cancellation

Layer / File(s) Summary
Cancellation registry and build runtime
src/openhuman/flows/build_registry.rs, src/openhuman/flows/ops.rs, src/openhuman/flows/mod.rs
Active builder turns are registered by thread, cancelled through tokens, safely unregistered, and returned with partial results when cancelled.
Cancellation RPC contract
src/openhuman/flows/schemas.rs, src/openhuman/flows/ops.rs
Adds the build_cancel controller with required thread_id, optional request_id, and a cancelled result.
Frontend stop runtime and validation
app/src/hooks/useWorkflowBuilderChat.ts, app/src/services/api/flowsApi.ts, app/src/hooks/useWorkflowBuilderChat.test.ts, app/src/services/api/flowsApi.test.ts
Adds stop(), invokes flowsBuildCancel, guards sending cleanup for overlapping attempts, and tests cancellation behavior and RPC responses.
Copilot composer stop wiring
app/src/components/flows/WorkflowCopilotPanel.tsx
Passes the hook’s stop callback to ChatComposer through onStopGeneration.

Estimated code review effort: 4 (Complex) | ~45 minutes

Possibly related PRs

Suggested labels: feature, rust-core

Suggested reviewers: m3ga-mind

Sequence Diagram(s)

sequenceDiagram
  participant ChatComposer
  participant WorkflowCopilotPanel
  participant useWorkflowBuilderChat
  participant flows_build_cancel
  participant flows_build
  ChatComposer->>WorkflowCopilotPanel: onStopGeneration()
  WorkflowCopilotPanel->>useWorkflowBuilderChat: stop()
  useWorkflowBuilderChat->>flows_build_cancel: cancel(thread_id)
  flows_build_cancel->>flows_build: signal registered cancellation token
  flows_build-->>useWorkflowBuilderChat: partial result with cancelled state
Loading

Poem

I’m a rabbit with a stop button bright,
Pausing workflow streams mid-flight.
Tokens hush and threads unwind,
Fresh sends keep their state aligned.
Hop, hop—cancellation done!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main user-facing change: adding a Stop button to the Workflow Copilot composer.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
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.

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

@coderabbitai coderabbitai Bot added the feature Net-new user-facing capability or product behavior. label Jul 27, 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: df1b66c253

ℹ️ 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 thread app/src/hooks/useWorkflowBuilderChat.ts Outdated
Comment on lines +513 to +515
void chatCancel(threadId).then(cancelled => {
log('stop: chatCancel thread=%s ok=%s', threadId, cancelled);
if (cancelled) setLocalSending(false);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Wire builder execution into the cancellation path

When Stop is clicked during any flows_build turn, this reports success without cancelling the builder: flows_build invokes Agent::run_single directly and only attaches a progress bridge, while channel_web_cancel in src/openhuman/web_chat/ops.rs can cancel only a registered web-chat turn or task-dispatcher run. Since neither registry contains this builder, the RPC returns cancelled: false; moreover, chatCancel ignores that payload and resolves true, so this callback hides the Stop button while the agent continues running and may still emit or save a proposal. Register the core-side builder run with a cancellation mechanism and propagate the actual cancellation result before clearing localSending.

AGENTS.md reference: AGENTS.md:L29-L30

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Confirmed and fixed — thank you, this was correct. flows_build runs agent.run_single inline and is registered in neither web_chat::IN_FLIGHT nor the task-dispatcher registry, so channel_web_cancel returned cancelled:false while chatCancel reported true. Rather than force flows into the web-chat cancel path, this now has real, domain-scoped cancellation: a new build-turn registry (flows/build_registry.rs, thread_id-keyed CancellationToken, request-scoped stale-cancel guard mirroring task_dispatcher::cancel_session_scoped), flows_build wraps its scoped+timeout run in tokio::select!{ r = run => r, _ = token.cancelled() => Cancelled } (no spawn, so the approval/streaming task-local scopes stay intact), and a new openhuman.flows_build_cancel RPC signals it. The FE stop() now calls flowsBuildCancel and reads the REAL cancelled field (not the unconditional true). A user Stop short-circuits before the trail-off backstop and returns a clean chat_done, so the turn ends without a synthesized "continue?" question. Commits e12c8b7, ed40e0d, 3cc8123, caddbac.

@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds a working Stop button to the Workflow Copilot composer by wiring stop() from useWorkflowBuilderChat through to ChatComposer's existing onStopGeneration prop. The implementation evolved significantly from the PR description: rather than the FE-only approach using chatCancel/openhuman.channel_web_cancel described in the summary, the actual code introduces a dedicated openhuman.flows_build_cancel RPC backed by a new Rust build_registry module, because flows_build runs the agent inline (never spawned) and was therefore never reachable via the shared web-channel cancel primitive.

  • Frontend (useWorkflowBuilderChat.ts, WorkflowCopilotPanel.tsx, flowsApi.ts): stop() fires flowsBuildCancel(threadId) fire-and-forget; a sendAttemptRef counter prevents a Stop-cancelled turn's finally from clearing a newer send's sending flag.
  • Rust backend (build_registry.rs, ops.rs, schemas.rs): new process-local BUILD_TURNS registry keyed by thread_id; flows_build registers a CancellationToken before racing the agent run with tokio::select!, so the token can be signalled from the RPC handler; unregister_build_turn is called unconditionally on every exit path.
  • Tests: comprehensive hook + API tests added including the re-send race regression, swallowed-rejection, and no-op cases.

Confidence Score: 5/5

Safe to merge — purely additive, no changes to existing cancel paths, main chat, or non-copilot surfaces.

The change is well-scoped: the Rust build_registry uses std::sync::Mutex correctly (never held across an await point), tokio::select! races the inline agent run without spawning (preserving all task-local context), and unregister_build_turn is called unconditionally on every exit path. The sendAttemptRef guard on the FE closes the re-send race with a regression test. No existing behaviour is modified — ChatComposer, the main chat stop path, and every other caller of flows_build are all untouched.

Files Needing Attention: No files require special attention. The most complex change is ops.rs (the tokio::select! integration), which is commented thoroughly and mirrors the existing run_registry pattern.

Important Files Changed

Filename Overview
src/openhuman/flows/build_registry.rs New process-local registry for in-flight flows_build turns; uses std::sync::Mutex (correct — never held across await), CancellationToken for signalling, and scoped-cancel matching identical to task_dispatcher::cancel_session_scoped. Comprehensive unit tests cover all guard branches.
src/openhuman/flows/ops.rs flows_build: registers a CancellationToken before racing the inline agent run via tokio::select!, then unregisters unconditionally on every exit path (run, timeout, cancel). Cancelled branch calls finalize_flow_stream so the FE receives chat_done and nothing dangles. flows_build_cancel delegates to the registry.
app/src/hooks/useWorkflowBuilderChat.ts Adds stop() (fire-and-forget flowsBuildCancel, no eager localSending clear) and sendAttemptRef to prevent a cancelled turn's finally from wiping a newer send's in-flight flag. All guard conditions (no thread, not sending) are correctly checked.
app/src/services/api/flowsApi.ts Adds flowsBuildCancel wrapping openhuman.flows_build_cancel; correctly maps undefined requestId to null for unscoped cancel, handles missing cancelled field with ?? false.
app/src/components/flows/WorkflowCopilotPanel.tsx Minimal two-line change: destructures stop from the hook and passes it as onStopGeneration to ChatComposer. No logic changes.
src/openhuman/flows/schemas.rs Registers build_cancel schema and handler; thread_id required, request_id optional (matching the cancel's scoped/unscoped semantics). Controller count assertion updated to 34.
app/src/hooks/useWorkflowBuilderChat.test.ts Adds 5 new tests covering: happy-path cancel, no-op when idle, no-op without thread, swallowed rejected RPC, and the re-send race regression. All scenarios are correctly set up with manual promise control.
app/src/services/api/flowsApi.test.ts Adds 4 tests for flowsBuildCancel covering the scoped/unscoped paths, missing-field default, and RPC rejection propagation.
src/openhuman/flows/mod.rs Single-line addition declaring the new build_registry module as private (pub(crate) visibility handled at the function level).

Sequence Diagram

sequenceDiagram
    participant User
    participant ChatComposer
    participant useWorkflowBuilderChat
    participant flowsApi
    participant Tauri/RPC
    participant BuildRegistry (Rust)
    participant flows_build (Rust)

    User->>ChatComposer: Click Send
    ChatComposer->>useWorkflowBuilderChat: send(params)
    useWorkflowBuilderChat->>useWorkflowBuilderChat: ++sendAttemptRef, setLocalSending(true)
    useWorkflowBuilderChat->>flowsApi: buildWorkflow(threadId, ...)
    flowsApi->>Tauri/RPC: openhuman.flows_build
    Tauri/RPC->>flows_build (Rust): flows_build(req, stream)
    flows_build (Rust)->>BuildRegistry (Rust): register_build_turn(thread_id, request_id, token)
    flows_build (Rust)->>flows_build (Rust): tokio::select!(run vs token.cancelled())

    Note over ChatComposer: isSending=true → Stop button rendered

    User->>ChatComposer: Click Stop
    ChatComposer->>useWorkflowBuilderChat: stop()
    useWorkflowBuilderChat->>flowsApi: flowsBuildCancel(threadId)
    flowsApi->>Tauri/RPC: openhuman.flows_build_cancel
    Tauri/RPC->>BuildRegistry (Rust): cancel_build_turn_scoped(thread_id, None)
    BuildRegistry (Rust)->>flows_build (Rust): token.cancel()

    flows_build (Rust)->>flows_build (Rust): select! → Cancelled branch
    flows_build (Rust)->>flows_build (Rust): finalize_flow_stream (chat_done event)
    flows_build (Rust)->>BuildRegistry (Rust): unregister_build_turn(thread_id, request_id)
    flows_build (Rust)->>Tauri/RPC: RpcOutcome (cancelled=true)
    Tauri/RPC->>flowsApi: resolves buildWorkflow promise
    flowsApi->>useWorkflowBuilderChat: finally block fires
    useWorkflowBuilderChat->>useWorkflowBuilderChat: attempt guard passes → setLocalSending(false)

    Note over ChatComposer: isSending=false → Send button restored
Loading

Reviews (3): Last reviewed commit: "test(flows): cover flowsBuildCancel + st..." | Re-trigger Greptile

Comment thread app/src/hooks/useWorkflowBuilderChat.ts

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@app/src/hooks/useWorkflowBuilderChat.ts`:
- Around line 500-516: The stop flow in useWorkflowBuilderChat must not allow a
cancelled buildWorkflow request to update a newer turn. Keep localSending
blocked until the original request settles, or add an attempt/token guard so
only the active send may run endInferenceTurn, update result/proposal/capped
state, and clear localSending; update stop accordingly and add a regression test
covering stop, immediate second send, and late completion of the first request.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fbe70725-d4a2-4faa-a5f2-e1f735a2d594

📥 Commits

Reviewing files that changed from the base of the PR and between 6b33376 and df1b66c.

📒 Files selected for processing (3)
  • app/src/components/flows/WorkflowCopilotPanel.tsx
  • app/src/hooks/useWorkflowBuilderChat.test.ts
  • app/src/hooks/useWorkflowBuilderChat.ts

Comment thread app/src/hooks/useWorkflowBuilderChat.ts Outdated
flows_build runs the workflow_builder agent turn awaited inline (never
spawned, to keep with_origin/APPROVAL_CHAT_CONTEXT/thread-id task-local
scopes attached), so it can't register in web_chat::IN_FLIGHT or
task_dispatcher::ACTIVE_RUNS the way an interactive chat turn or an
autonomous run does. Add a dedicated thread_id + request_id scoped
registry (mirrors flows::run_registry's register/select shape, and
task_dispatcher::cancel_session_scoped's stale-cancel guard) so a real
cancel path can reach the running turn.
Race the existing scoped+timeout workflow_builder run future against
the new build_registry token via tokio::select! (both the streaming
and headless branches), instead of only awaiting it inline. A user
Stop now actually interrupts the turn:

- register_build_turn before the run, unregister on every settle path
  (ran to completion, errored, timed out, or cancelled) — single call
  after the select covers all of them, no early return in between.
- A cancelled turn is treated as a clean stop, not an error: run_error
  stays None, the copilot stream gets a chat_done (not chat_error) so
  ChatRuntimeProvider ends the inference turn normally, and it returns
  before the trail-off backstop (which would otherwise synthesize a
  "continue?" question for what is actually a deliberate Stop).
- New ops::flows_build_cancel(thread_id, request_id) delegates to
  build_registry::cancel_build_turn_scoped and returns { cancelled }.

The headless (CLI/no-thread) branch keeps its existing behavior
unchanged — there's no thread_id to register a cancellable turn under
in that path.
New flows.build_cancel controller — { thread_id: String, request_id:
Option<String> } -> { cancelled: bool } — delegating to
ops::flows_build_cancel. Registered alongside flows.build in both
all_controller_schemas and all_registered_controllers; updates the two
schema-registry coverage tests to the new 34-controller count.
The Stop button was cosmetic: it called the shared chatCancel
(channel_web_cancel), which only ever tears down a spawned interactive
chat turn and silently no-ops for flows_build (inline-run, never
registered there), while resolving `true` unconditionally.

- flowsApi.flowsBuildCancel(threadId, requestId?) calls the new
  openhuman.flows_build_cancel RPC and returns its real `cancelled`
  field.
- useWorkflowBuilderChat's stop() now calls flowsBuildCancel instead of
  chatCancel, and no longer eagerly clears `sending` on a confirmed
  cancel — with real cancellation the in-flight buildWorkflow call now
  settles promptly on its own, and its own `finally` is the single
  place `sending` clears.
- Attempt-guard (P2/Major re-send race): a useRef counter bumped at the
  start of every send(); a send's `finally` only clears `sending` when
  its captured attempt is still the latest one, so an earlier
  (cancelled/settling) turn can never clear a newer turn's in-flight
  indicator.
Update the two stop() tests to mock/assert flowsBuildCancel instead of
chatCancel, including that stop() no longer eagerly clears `sending`
(it now waits for the in-flight buildWorkflow call's own finally).
Add a regression test for the attempt-guard: two sends dispatched in
the same tick (the stale-closure double-fire the guard exists for)
must not let the earlier one's settle clear the newer one's `sending`
flag.
@greptile-apps

greptile-apps Bot commented Jul 27, 2026

Copy link
Copy Markdown

Want your agent to iterate on Greptile's feedback? Try greploops.

@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.

Actionable comments posted: 1

🧹 Nitpick comments (2)
app/src/hooks/useWorkflowBuilderChat.ts (1)

528-559: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Cancel is unscoped — the backend's request_id guard is unused here.

flowsBuildCancel supports an optional requestId to scope the cancel to the exact in-flight turn (matching cancel_build_turn_scoped's stale-request guard on the server), but stop() never passes one. In practice this means a Stop click always cancels "whatever build turn is currently registered on the thread," not necessarily the specific turn the user is looking at — so the elaborate server-side scoping this PR built is currently moot on the real product path. Threading a client-generated (or server-returned) request_id through send()/buildWorkflow()/stop() would let Stop precisely target the turn it was clicked for.

🤖 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/hooks/useWorkflowBuilderChat.ts` around lines 528 - 559, Thread the
active build turn’s request_id through send() and buildWorkflow() into the hook
state, then pass that identifier to flowsBuildCancel from stop(). Ensure the
request ID is cleared when the turn settles and that Stop targets only the
matching in-flight turn, preserving the existing attempt-guard behavior.
src/openhuman/flows/ops.rs (1)

5666-5676: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Add end-to-end coverage for the flows_build/flows_build_cancel race path in tests/json_rpc_e2e.rs; the current test only exercises the flows_build proposal flow.

🤖 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 `@src/openhuman/flows/ops.rs` around lines 5666 - 5676, Extend the JSON-RPC
end-to-end coverage in tests/json_rpc_e2e.rs to exercise the
flows_build/flows_build_cancel race, including cancellation before the build
completes and validation of the resulting response/outcome. Preserve the
existing flows_build proposal-flow assertions and use the
BuildRunOutcome::Cancelled behavior as the expected streaming result.

Source: Coding guidelines

🤖 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.

Inline comments:
In `@app/src/hooks/useWorkflowBuilderChat.ts`:
- Around line 556-558: Add rejection handling to the fire-and-forget
flowsBuildCancel call in the stop flow, preserving the existing success log
while catching failures and logging the cancellation error with thread context.
Ensure the rejected promise is handled so it does not become an unhandled
rejection.

---

Nitpick comments:
In `@app/src/hooks/useWorkflowBuilderChat.ts`:
- Around line 528-559: Thread the active build turn’s request_id through send()
and buildWorkflow() into the hook state, then pass that identifier to
flowsBuildCancel from stop(). Ensure the request ID is cleared when the turn
settles and that Stop targets only the matching in-flight turn, preserving the
existing attempt-guard behavior.

In `@src/openhuman/flows/ops.rs`:
- Around line 5666-5676: Extend the JSON-RPC end-to-end coverage in
tests/json_rpc_e2e.rs to exercise the flows_build/flows_build_cancel race,
including cancellation before the build completes and validation of the
resulting response/outcome. Preserve the existing flows_build proposal-flow
assertions and use the BuildRunOutcome::Cancelled behavior as the expected
streaming result.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 996584e5-3226-4867-85ed-d0943710bc79

📥 Commits

Reviewing files that changed from the base of the PR and between df1b66c and 07f1f19.

📒 Files selected for processing (7)
  • app/src/hooks/useWorkflowBuilderChat.test.ts
  • app/src/hooks/useWorkflowBuilderChat.ts
  • app/src/services/api/flowsApi.ts
  • src/openhuman/flows/build_registry.rs
  • src/openhuman/flows/mod.rs
  • src/openhuman/flows/ops.rs
  • src/openhuman/flows/schemas.rs

Comment thread app/src/hooks/useWorkflowBuilderChat.ts Outdated
…ion)

flowsBuildCancel is fire-and-forget in stop(); a rejected promise
(network/RPC failure) would become an unhandled rejection. Add a .catch
that logs the failed cancel attempt -- the in-flight turn's own settle
still clears sending.
Restores the diff-coverage gate (was 60%): the copilot Stop FE lines were
uncovered because the hook test mocks flowsApi. Adds a flowsApi.test.ts
flowsBuildCancel suite (RPC method/params, scoped request_id, cancelled
default, rejection) and hook tests for the no-bound-thread guard and the
rejected-cancel .catch.
@coderabbitai coderabbitai Bot added the rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. label Jul 28, 2026
@graycyrus
graycyrus merged commit 5758e4e into tinyhumansai:main Jul 28, 2026
25 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Net-new user-facing capability or product behavior. rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant