Skip to content

feat(chat): re-enable the stop button via chatAbort (#550)#563

Open
clemenshelm wants to merge 2 commits into
mainfrom
feat/chat-stop-button
Open

feat(chat): re-enable the stop button via chatAbort (#550)#563
clemenshelm wants to merge 2 commits into
mainfrom
feat/chat-stop-button

Conversation

@clemenshelm

Copy link
Copy Markdown
Contributor

Closes #550. Part of the OpenClaw-integration audit (#556).

Why

The chat composer's stop button has been cosmetic since PR #136 rolled it back. The original implementation (PR #23) looked like it worked client-side, but OpenClaw's chat.abort was a no-op on agent-RPC runs — it returned { aborted: false } and never released the session lane, so every subsequent message on that session came back as an empty done. Root-caused as openclaw/openclaw#42172.

That upstream bug is fixed (closed 2026-04-26, commit fd68994c5a registers the AbortController for agent-RPC runs) and shipped in our pinned OpenClaw 2026.6.5. So the button can come back — but only with empirical proof against a real gateway, because last time the client-side flow lied about the server having stopped.

What changed

  • Server (client-router.ts): a new {type:"abort"} WS frame is routed to chatAbort(sessionKey, runId) — runId resolved precisely from the active-run registry (never aborts a newer run that already replaced this one), falling back to a sessionKey-only abort. It emits chat.run_aborted (reserved by feat(chat): server-side run registry + watchdog for stuck runs (#310 Tier 2a) #441's watchdog work, emitted here for the first time) with outcome reflecting the RPC result, so an operator always sees that a user asked to stop. The abort frame goes through the same agent-access check as chat/history.
  • Client (use-ws-runtime.ts): onCancel wired into the assistant-ui external-store runtime — sends the abort frame and optimistically ends the turn so the composer re-enables immediately. The existing ComposerPrimitive.Cancel button now does something; no markup change needed.
  • Docs: chat.run_aborted flipped from reserved to emitted in audit-trail.mdx.

The stream pipe's existing post-abort handling (the synthetic terminal done openclaw-node emits) cleans up the run — no new teardown code.

Test plan

  • Unitclient-router-abort.test.ts (6): routing to chatAbort with the registry runId, the chat.run_aborted audit (actor=user, success), sessionKey-only abort when no run is registered, per-chat chatId targeting (Chats: per-agent session overview + per-task session model (fixes silent history loss from cross-channel /new) #508), outcome: failure on RPC throw (still audits), and access-denied (no abort, no audit). use-ws-runtime.test.ts (+3): the abort frame is sent (with chatId when scoped), and isRunning flips optimistically.
  • Integration E2E19-chat-stop-button.spec.ts against real OpenClaw 2026.6.5: send a genuinely incremental reply, stop it mid-stream, and assert (1) the full reply never lands, (2) a chat.run_aborted audit row appears, and (3) the same session is immediately reusable — a second message gets a real reply. That third assertion is the openclaw#42172 regression guard; it would go red if the upstream fix ever regressed. Verified green locally against the production-image integration stack (run with DB_PASSWORD set, as CI does).
  • Local gates: tsc --noEmit clean, eslint 0 errors, full web unit suite (6203 passed), test:db (115 passed).

Notes

  • chat.run_aborted detail: { agent:{id,name}, sessionKey, runId|null, reason:"user_request" } — no PII; sessionKey embeds the user UUID, not an email.
  • A type error (onCancel must be () => Promise<void> per assistant-ui) was caught by the production-image build's stricter typecheck and fixed — folded into the feature commit.

Clemens Helm added 2 commits June 19, 2026 13:22
The composer's stop button was cosmetic since PR #136 rolled it back —
OpenClaw's chat.abort was a no-op on agent-RPC runs (openclaw#42172,
fixed upstream and shipped in our pinned OC 2026.6.5).

- Add an {type:"abort"} WS frame to BrowserMessage; ClientRouter routes
  it to chatAbort(sessionKey, runId) using the active-run registry for a
  precise runId, then emits the chat.run_aborted audit event (reserved by
  #441, first emitted here) with outcome reflecting the RPC result.
- Wire onCancel into the assistant-ui external-store runtime: send the
  abort frame and optimistically end the turn client-side.
- Unit tests for the server routing/audit contract and the client onCancel
  dispatch + optimistic stop. Integration E2E drives a real stop against
  OpenClaw and guards the session-lane-release regression (a second message
  on the same session must still get a reply).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Re-enable the chat stop button (upstream openclaw#42172 is fixed)

1 participant