fix(ui): reset sawAssistantReply for assistant groups without reply text to prevent cross-turn tool-error banner suppression#97873
Conversation
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. This PR should close because the same Web UI chat-turn bug is now covered by a narrower, open, proof-positive replacement PR, while this branch has grown into a broad 21-file diff that reverts unrelated current-main UI fixes. Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Canonical path: Close this branch and let #98888 carry the linked chat projection fix, while preserving current-main cron, pairing QR, and workspace rail behavior. So I’m closing this here and keeping the remaining discussion on #98888. Review detailsBest possible solution: Close this branch and let #98888 carry the linked chat projection fix, while preserving current-main cron, pairing QR, and workspace rail behavior. Do we have a high-confidence way to reproduce the issue? Yes. The linked issue and current source show the backward annotation pass resets only at user groups, so adjacent agent-initiated turns can inherit a later assistant reply's success flag. Is this the best way to solve the issue? No. The shared chat projection layer is the right place to fix the bug, but this branch is no longer the best fix because the narrow open replacement covers the same behavior without unrelated UI regressions. Security review: Security review cleared: No dependency, workflow, secret, package, or supply-chain surface was introduced; the blocking concerns are functional/UI regressions. AGENTS.md: found and applied where relevant. What I checked:
Likely related people:
Codex review notes: model internal, reasoning high; reviewed against 76ccd17ac3c2. |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. |
Dependency graph guard clearedThis PR no longer has blocked dependency graph changes. A future dependency graph change requires a fresh
|
|
@steipete We spent some time tonight cleaning up this branch and also reviewed the competing PR. Here's a summary: What we did on #97873 tonight:
However: we also reviewed #98888 (qingminglong, same issue #97849). It takes the senderLabel boundary approach instead of runId + stopReason classification. ClawSweeper gave it 🐚 platinum hermit with no findings, while ours is 🦐 gold shrimp with a [P2] about missing stop-reason aliases. It also changes only 2 files vs our 21. Our take: #98888's approach is simpler and more precise. We lean toward closing #97873 in favor of #98888, but we wanted your call as the maintainer who added the supplementary refactoring here. The grouped-render and controller changes you attached could also be submitted as an independent follow-up PR. What do you think? |
In openclaw#90122, annotateToolTurnOutcome was added to collapse non-terminal failed tool errors when the turn produced a reply. The backward pass resets sawAssistantReply only at user groups, assuming every turn starts with a user message. Agent-initiated turns (cron/scheduled/autonomous) have no user group between them, so a later turn reply leaks backward and stamps an earlier genuinely-failed turn as turnSucceeded=true, hiding its error banner. Fix: add assistantMessageTurnSucceeded with stop-reason classification and runId-scoped outcome tracking for accurate cross-turn boundary detection. Related to openclaw#97849 Co-authored-by: SunnyShu0925 <[email protected]> Co-authored-by: Peter Steinberger <[email protected]>
|
Closing in favor of #98888 which uses a simpler senderLabel boundary approach (2 files, 🐚 platinum hermit from ClawSweeper). Our rebased branch is preserved at Co-authored-by: SunnyShu0925 [email protected] |
Related to #97849.
What Problem This Solves
Failed cron/scheduled/autonomous agent turns are silently rendered as successful in the Control UI and WebChat. When two agent-initiated turns run back-to-back with no user message between them, a later turn's clean assistant reply leaks backward through
annotateToolTurnOutcomeand stamps an earlier genuinely-failed turn asturnSucceeded=true, collapsing itsTool errorbanner.Why This Change Was Made
annotateToolTurnOutcomeresets itssawAssistantReplyflag only atrole === "user"groups, but agent-initiated turns have no user group separating them. The fix adds a second reset point: an assistant group without reply text marks a turn boundary where the agent tried and failed to produce a visible reply.This approach is the smallest safe change:
sawAssistantReply = true→ the original fix(ui): collapse non-terminal internal tool errors #90122 within-turn suppression is unchanged.sawAssistantReply = false→ a failed turn's tool errors are no longer stampedturnSucceededby a later turn's reply.Alternative approaches (parsing
runId/turnIdmetadata) would require ~50+ line diffs across the grouping layer. The display-projection heuristic used here is already part of the existing annotation contract and is simpler to audit.Root Cause
annotateToolTurnOutcomeinui/src/ui/chat/build-chat-items.ts(introduced by355c43fe0c/ PR #90122): the backward pass only resetssawAssistantReplyat user boundaries, so a later agent-initiated turn's reply propagates backward across an unmarked turn boundary and stamps an earlier genuinely-failed turn as succeeded. Confidence: clear.User Impact
Failed autonomous turns (cron jobs, scheduled tasks) now correctly show their
Tool errorbanner instead of silently collapsing it. The prior behavior for a failed internal tool followed by a same-turn assistant reply is preserved (regression-tested).Evidence
Behavior addressed: A genuinely-failed agent-initiated turn was marked
turnSucceeded=truewhen a later adjacent agent turn produced an assistant reply with no user message separating the two turns.Real environment tested: Local OpenClaw source checkout on current
upstream/mainat6de357ad47.Exact steps or command run after this patch:
The proof script drives the exported
buildChatItemswith realistic agent-initiated turn messages — a failedtoolResult(exitCode=1) followed by an empty assistant group (turn 1, no reply), then another failed tool result followed by an assistant with reply text (turn 2, succeeded). The function correctly stamps turn 1 asturnSucceeded=falseand turn 2 asturnSucceeded=true.Observed result after fix: The earlier failed agent-initiated turn keeps
turnSucceeded=false(red error banner stays visible ✅), while the later turn's tool group getsturnSucceeded=true(collapsed because the turn produced a clean reply ✅). All 4 existing #90122 regression tests pass unchanged.What was not tested: Live scheduled cron job with browser screenshot. The proof script and unit tests cover the
buildChatItemsprojection function that both Control UI and WebChat consume — this is the shared entry point and the exact function modified.Regression Test Plan
Changes
ui/src/ui/chat/build-chat-items.ts: +6 lines — resetsawAssistantReplyfor assistant groups without reply textui/src/ui/chat/build-chat-items.test.ts: +15 lines — add cross-turn agent-initiated scenario