Skip to content

Fix TUI Esc abort stale busy state#86200

Closed
RomneyDa wants to merge 2 commits into
mainfrom
tui-contradicting-esc-pattern
Closed

Fix TUI Esc abort stale busy state#86200
RomneyDa wants to merge 2 commits into
mainfrom
tui-contradicting-esc-pattern

Conversation

@RomneyDa

@RomneyDa RomneyDa commented May 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Clear pendingOptimisticUserMessage after a successful TUI abort of a pending submit, alongside pendingChatRunId.
  • Track submitted prompts as TUI pending drafts keyed by the generated run id so early Esc abort can redact the pending transcript row and restore the text into the editor before gateway registration.
  • Share pending draft/pending row cleanup through abortActive() so Esc, /stop, and stop-text abort paths handle pending submits consistently.
  • Preserve/reconcile pending user rows across history reloads, and clear the draft-restore candidate as soon as chat/lifecycle/history proves the run is registered or durable.

Fixes #86199

Verification

  • node scripts/run-vitest.mjs src/tui/tui-command-handlers.test.ts src/tui/tui-session-actions.test.ts src/tui/tui-event-handlers.test.ts src/tui/components/chat-log.test.ts src/tui/tui.test.ts
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfo
  • git diff --check

Real behavior proof

Behavior addressed: TUI Esc abort could clear the pending run id while leaving pendingOptimisticUserMessage set, causing the next prompt to be blocked as busy even though a second Esc reported no active run. During the earliest submit window, a same-session history reload could also erase the just-submitted prompt before the run id was fully bound. Early Esc abort now restores the still-unregistered prompt to the editor instead of leaving it as a lost transcript row, and command-driven aborts share the same pending draft cleanup.

Real environment tested: macOS arm64, Node v22.22.0, OpenClaw worktree tui-contradicting-esc-pattern, commit 4504b2c.

Exact steps or command run after this patch:

node scripts/run-vitest.mjs src/tui/tui-command-handlers.test.ts src/tui/tui-session-actions.test.ts src/tui/tui-event-handlers.test.ts src/tui/components/chat-log.test.ts src/tui/tui.test.ts
node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfo
git diff --check

Evidence after fix:

Test Files  5 passed (5)
     Tests  230 passed (230)

Observed result after fix: the regression coverage verifies that aborting a pending run clears both local busy-state fields, pending user prompts survive same-session history reloads when history has not committed them yet, pending prompts reconcile to a single history-backed row once the submitted prompt appears in history, chat/lifecycle registration clears the local draft-restore candidate, and command aborts of a pending run drop the pending row and restore the draft through shared abortActive() cleanup.

What was not tested: no live interactive TUI PTY run was executed; coverage is focused unit coverage for the state transitions behind the stale busy lock, early prompt disappearance, and early-abort draft restoration.

@openclaw-barnacle openclaw-barnacle Bot added size: XS maintainer Maintainer-authored PR labels May 24, 2026
@clawsweeper

clawsweeper Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs changes before merge. Reviewed June 3, 2026, 2:38 PM ET / 18:38 UTC.

Summary
The PR changes TUI pending-submit abort and history reconciliation so pending user drafts can be tracked, reconciled, dropped, or restored across Esc, /stop, stop-text aborts, and history reloads.

PR surface: Source +94, Tests +47. Total +141 across 8 files.

Reproducibility: yes. for the patch defect by source inspection: Esc starts abortActive asynchronously, abortActive returns restoredDraftText only after awaiting abortChat, and the later editor.setText can overwrite text typed during that gap. I did not run an interactive PTY repro in this read-only review.

Review metrics: 1 noteworthy metric.

  • Internal abort contract changed: 1 return surface changed. abortActive now returns TuiAbortActiveResult and only the Esc caller consumes restoredDraftText, so caller safety matters before merge.

Merge readiness
Overall: 🦐 gold shrimp
Proof: 🌊 off-meta tidepool
Patch quality: 🦐 gold shrimp
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Guard restored draft application against editor changes made while abortChat is pending.
  • [P2] Add focused regression coverage for pressing Esc, typing before abortActive resolves, and preserving the new editor text.

Risk before merge

  • [P1] Merging as-is can lose or replace newly typed TUI editor input if the user presses Esc to abort and starts typing before abortChat resolves.
  • [P1] The PR expands the original stale-busy fix into broader pending-draft and history-reconciliation semantics while related TUI pending-message PRs remain open, so maintainers should choose the canonical branch before landing overlapping state-machine changes.
  • [P1] The PR body reports focused unit/typecheck proof but no live interactive TUI or PTY proof for the visible Esc workflow.

Maintainer options:

  1. Guard draft restoration before merge (recommended)
    Only restore the aborted draft if the editor is still in the same empty or unchanged state captured when Esc was pressed, and add a regression test for typing before abortActive resolves.
  2. Choose the canonical pending-submit branch
    Before landing, maintainers should decide whether this branch or a sibling TUI pending-message PR owns the combined abort/history behavior.
Copy recommended automerge instruction
@clawsweeper automerge

Special instructions:
Guard restored draft application so Esc only restores when the editor is still empty or unchanged from the abort request, and add focused coverage for typing after Esc before abortActive resolves.

Next step before merge

  • [P2] A narrow automated repair can guard the async editor restore and add regression coverage, while maintainers still own the final canonical-branch decision for overlapping TUI pending-submit work.

Security
Cleared: The diff is limited to TUI TypeScript and tests; it does not touch workflows, dependencies, lockfiles, credentials, permissions, or code-download surfaces.

Review findings

  • [P2] Avoid overwriting editor input after async abort — src/tui/tui.ts:1410
Review details

Best possible solution:

Land a canonical TUI pending-submit fix that preserves current main's stale-busy clearing, guards draft restoration against editor races, and then closes or supersedes overlapping pending-message PRs.

Do we have a high-confidence way to reproduce the issue?

Yes for the patch defect by source inspection: Esc starts abortActive asynchronously, abortActive returns restoredDraftText only after awaiting abortChat, and the later editor.setText can overwrite text typed during that gap. I did not run an interactive PTY repro in this read-only review.

Is this the best way to solve the issue?

No, not yet. Restoring a still-unregistered aborted draft is a reasonable fix direction, but the best version must make the restore conditional on the editor not having changed and should include focused regression coverage for that ordering case.

Full review comments:

  • [P2] Avoid overwriting editor input after async abort — src/tui/tui.ts:1410
    When Esc aborts a pending draft, abortActive() waits for client.abortChat() before resolving restoredDraftText. During that await the editor is still active, so if the user starts typing a replacement prompt, this setText() overwrites it with the aborted draft. Capture the editor text/state at Esc time and only restore when it is still safe, with coverage for typing before the abort resolves.
    Confidence: 0.91

Overall correctness: patch is incorrect
Overall confidence: 0.86

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 892602eaba07.

Label changes

Label changes:

  • add rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • remove rating: 🦪 silver shellfish: Current PR rating is rating: 🦐 gold shrimp, so this older rating label is no longer current.

Label justifications:

  • P2: This is a normal-priority TUI state-machine bugfix with limited blast radius but real user-visible editor/message impact.
  • merge-risk: 🚨 compatibility: The PR changes existing Esc abort behavior by restoring aborted prompt text into the editor, which can affect current TUI workflows.
  • merge-risk: 🚨 message-delivery: The patch can overwrite newly typed replacement text after abort, causing user input to be lost or sent differently than intended.
  • merge-risk: 🚨 session-state: The diff changes pending run, optimistic message, pending draft, and history reconciliation state across TUI abort and reload paths.
  • rating: 🦐 gold shrimp: Overall readiness is 🦐 gold shrimp; proof is 🌊 off-meta tidepool and patch quality is 🦐 gold shrimp.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Not applicable: The external contributor proof gate is not applied because this PR is maintainer-authored/labeled; the PR body supplies focused unit/typecheck proof but no live interactive TUI proof.
Evidence reviewed

PR surface:

Source +94, Tests +47. Total +141 across 8 files.

View PR surface stats
Area Files Added Removed Net
Source 5 105 11 +94
Tests 3 116 69 +47
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 8 221 80 +141

Acceptance criteria:

  • [P1] node scripts/run-vitest.mjs src/tui/tui-command-handlers.test.ts src/tui/tui-session-actions.test.ts src/tui/tui-event-handlers.test.ts src/tui/components/chat-log.test.ts src/tui/tui.test.ts.
  • [P1] node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfo.
  • [P1] git diff --check.

What I checked:

  • Repository policy read: Root AGENTS.md and scoped src/tui/AGENTS.md were read; the TUI guide says fake-backend PTY tests do not prove Gateway transport, embedded runtime, providers, session persistence, or live streaming. (AGENTS.md:1, 892602eaba07)
  • Patch restores draft after async abort: The PR head wires Esc to wait for abortActive() and then unconditionally writes restoredDraftText into the editor, which creates a race with user input typed while abortChat is still pending. (src/tui/tui.ts:1410, c1793c64ebb7)
  • Abort result is delayed by backend RPC: abortActive awaits client.abortChat before returning restoredDraftText, so the editor remains usable during the interval that the later setText can overwrite. (src/tui/tui-session-actions.ts:647, c1793c64ebb7)
  • Current main already clears stale busy state on abort and session switch: Current main clears pendingOptimisticUserMessage in abortActive and session-switch paths, so the PR's remaining value is broader pending-draft restoration and history reconciliation rather than only the original stale-busy flag clear. (src/tui/tui-session-actions.ts:529, 892602eaba07)
  • Latest release partially covers the stale busy fix: v2026.5.28 already clears pendingOptimisticUserMessage after aborting a pending run, but its setSession path did not clear that flag; current main is ahead of the release on the session-switch portion. (src/tui/tui-session-actions.ts:378, e93216080aa1)
  • Whitespace check: The PR diff has no whitespace errors under git diff --check. (c1793c64ebb7)

Likely related people:

  • vincentkoc: Recent current-main blame and history show Vincent Koc touching TUI pending-send, busy-state visibility, and pending-history reconciliation around the affected files. (role: recent area contributor; confidence: high; commits: eddf1c776dd2, 51d6d7013f07, f0a44232716d; files: src/tui/tui-session-actions.ts, src/tui/tui-command-handlers.ts, src/tui/tui.ts)
  • vignesh07: History shows Vignesh Natarajan introduced and maintained TUI optimistic user-message and active-run behavior adjacent to this pending-submit state machine. (role: feature-history owner; confidence: medium; commits: 61a0b0293104, 68cb4fc8a163, b4cdffc7a429; files: src/tui/tui.ts, src/tui/tui-event-handlers.ts, src/tui/tui-command-handlers.ts)
  • steipete: History shows Peter Steinberger as a frequent TUI refactor/fix contributor, including the handler split and deferred history sync paths that frame this owner boundary. (role: adjacent owner; confidence: medium; commits: 32cfc4900273, ff2e9a52ff10, 38752338dcbc; files: src/tui/tui.ts, src/tui/tui-session-actions.ts, src/tui/tui-event-handlers.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels May 24, 2026
@clawsweeper

clawsweeper Bot commented May 24, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

🔥 Warming up: real-behavior proof passed; findings, security review, or rank-up moves are still in progress.

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.
What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@RomneyDa RomneyDa force-pushed the tui-contradicting-esc-pattern branch from 04dcad1 to 6cbefa6 Compare May 24, 2026 21:09
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 24, 2026
@RomneyDa RomneyDa force-pushed the tui-contradicting-esc-pattern branch from 6cbefa6 to 21f2ff2 Compare May 24, 2026 21:30
@RomneyDa

Copy link
Copy Markdown
Member Author

Future hardening note: this PR keeps the fix TUI-local and intentionally conservative. The TUI now treats the submitted prompt as a restore candidate only until a chat/lifecycle event or history reconciliation proves the run is registered/durable; early Esc abort can then redact the pending row and restore the text into the editor.

A more deterministic gateway-level version would add an explicit user-prompt durability signal, for example a user_prompt_committed / chat.user_committed event or equivalent sendChat acknowledgement. That would let clients distinguish "accepted but not durable yet" from "prompt is persisted and should stay in transcript" without relying on first run event/history reconciliation as the boundary.

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels May 24, 2026
@RomneyDa RomneyDa marked this pull request as draft May 27, 2026 20:02
@clawsweeper clawsweeper Bot added status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed status: 🛠️ actively grinding The PR author has acted after the latest ClawSweeper review and work remains. labels May 27, 2026
@BingqingLyu

This comment was marked as spam.

@RomneyDa RomneyDa force-pushed the tui-contradicting-esc-pattern branch from 21f2ff2 to 4504b2c Compare June 1, 2026 17:33
@RomneyDa

RomneyDa commented Jun 1, 2026

Copy link
Copy Markdown
Member Author

Addressed ClawSweeper feedback:

  • rebased onto current origin/main
  • preserved main's active-plus-pending abort ordering in abortActive({ preferActive: true })
  • moved pending draft/pending transcript row cleanup into shared abortActive() so Esc, /stop, and stop-text aborts use the same pending-run cleanup
  • added focused command-abort coverage for a pending submitted draft

Verification:

node scripts/run-vitest.mjs src/tui/tui-command-handlers.test.ts src/tui/tui-session-actions.test.ts src/tui/tui-event-handlers.test.ts src/tui/components/chat-log.test.ts src/tui/tui.test.ts
node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.test.ui.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/test-ui.tsbuildinfo
git diff --check

node scripts/run-vitest.mjs ... passed with 5 files / 230 tests.

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 1, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 1, 2026
@RomneyDa RomneyDa marked this pull request as ready for review June 1, 2026 19:44
@RomneyDa RomneyDa force-pushed the tui-contradicting-esc-pattern branch 2 times, most recently from 792880e to a17209c Compare June 3, 2026 07:13
@openclaw-barnacle openclaw-barnacle Bot added the channel: discord Channel integration: discord label Jun 3, 2026
@clawsweeper clawsweeper Bot added rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 3, 2026
@RomneyDa RomneyDa force-pushed the tui-contradicting-esc-pattern branch from a17209c to c1793c6 Compare June 3, 2026 18:30
@openclaw-barnacle openclaw-barnacle Bot removed the channel: discord Channel integration: discord label Jun 3, 2026
@clawsweeper clawsweeper Bot added rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. and removed rating: 🦪 silver shellfish Thin PR readiness signal; proof, validation, or implementation needs work. labels Jun 3, 2026
@RomneyDa

RomneyDa commented Jun 5, 2026

Copy link
Copy Markdown
Member Author

Issue already fixed

@RomneyDa RomneyDa closed this Jun 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

maintainer Maintainer-authored PR merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. merge-risk: 🚨 session-state 🚨 May lose, corrupt, stale, or mis-associate session, agent, or context state. P2 Normal backlog priority with limited blast radius. rating: 🦐 gold shrimp Decent PR readiness signal, but merge confidence is limited. size: M status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TUI Esc abort can leave stale optimistic busy state

2 participants