Skip to content

fix: handle terminal chat send acknowledgements#91049

Merged
openclaw-clownfish[bot] merged 37 commits into
openclaw:mainfrom
nxmxbbd:repair/post84306-terminal-ack-clients-20260607T222010
Jun 22, 2026
Merged

fix: handle terminal chat send acknowledgements#91049
openclaw-clownfish[bot] merged 37 commits into
openclaw:mainfrom
nxmxbbd:repair/post84306-terminal-ack-clients-20260607T222010

Conversation

@nxmxbbd

@nxmxbbd nxmxbbd commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Preserves terminal chat.send ACK status (ok, timeout, error) through clients/helper paths that previously reduced the response to "has a run id".
  • Clears, restores, or fails pending/optimistic state when the gateway has already returned a terminal ACK, so clients do not wait for run events that will not arrive.
  • Covers Web queued/direct sends, detached /btw, queued /steer, /redirect via sessions.steer, Android chat/mic/Talk flows, native Talk flows, TUI, ACP, and the Skill Workshop forwarded schema.
  • Handles the follow-up TUI detached-send ACK case: terminal /btw / /side ACKs now clear local BTW tracking, and detached accepted-runId replacements rekey local tracking instead of being misclassified later.
  • Updates Android chat, mic, Swift chat, and TUI normal-send timeout/error handling so terminal timeout / error ACKs surface failed-send state instead of looking accepted.

Terminal ACKs are part of the chat.send contract. If a client treats one as an accepted active run, a message, mic turn, or queued command can get stuck or disappear without failure copy.

Clients branch on ACK status instead of only checking runId: active statuses keep the existing pending-run flow, while terminal statuses clear pending state, restore retryable queue/draft state where appropriate, or surface failure copy.

  • Redesigning the public SDK Session.send API shape.

  • Standardizing every cross-client terminal-timeout message/toast policy.

  • Broader lifecycle cleanup races not introduced by this PR.

  • Whether each touched consumer preserves runId and status until the final caller branches.

  • Whether terminal ok / timeout / error branches clear or restore pending state without breaking non-terminal started / in_flight behavior.

  • Whether Android chat/mic and Swift chat now surface terminal timeout/error as failed-send state.

Linked context

Closes #91048

Related #84176
Related #84306

No direct maintainer request; this follows the terminal ACK contract through additional consumers and addresses the Android terminal-timeout feedback.

Real behavior proof (required for external PRs)

  • Behavior or issue addressed:
    Terminal chat.send / forwarded ACKs with status: "ok" | "timeout" | "error" should not be treated as accepted active runs. Live proof exercises terminal timeout; current 9cd2b839bbf4a50882564024fbc3f9c003818e89 preserves the Android/Swift/TUI follow-ups and is clean against latest main.

  • Real environment tested:
    Local Linux checkout using repo test runners, Android JVM/Robolectric, and a real local Gateway server + WebSocket RPC harness driving Control UI sendChatMessage against a terminal timeout ACK. Hosted checks on 603380bfc4fbc1604ac16cb6915837191a36ad53 covered macOS Swift, Android build/test, lint, production/test types, and the real-behavior proof checker. Current head adds CI-red triage plus the iOS SwiftFormat and compile-safe logger fixes.

  • Exact steps or command run after this patch:

node scripts/run-vitest.mjs packages/gateway-protocol/src/schema/agents-models-skills.test.ts src/gateway/server-methods/talk.test.ts src/tui/gateway-chat.test.ts src/tui/tui-command-handlers.test.ts src/acp/translator.lifecycle.test.ts ui/src/ui/chat/slash-command-executor.node.test.ts
cd apps/android && ANDROID_HOME=/opt/android-sdk ANDROID_SDK_ROOT=/opt/android-sdk ./gradlew :app:testPlayDebugUnitTest --tests ai.openclaw.app.gateway.ChatSendAckTest --tests ai.openclaw.app.chat.ChatControllerTerminalAckTest --tests ai.openclaw.app.voice.MicCaptureManagerTest
pnpm tsgo:core && pnpm tsgo:test:ui && pnpm tsgo:test:packages
git diff --check

# Current-head conflict-repair validation.
node scripts/run-vitest.mjs src/tui/tui-command-handlers.test.ts
node scripts/run-vitest.mjs run --config test/vitest/vitest.tui-pty.config.ts
node scripts/run-oxlint.mjs src/tui/tui-backend.ts src/tui/gateway-chat.ts src/tui/embedded-backend.ts src/tui/tui-command-handlers.ts src/tui/tui-command-handlers.test.ts
node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo
git diff --check
git merge-tree --write-tree upstream/main HEAD

# Temporary uncommitted live proof harness copied to src/gateway/pr91049-live-terminal-ack-proof.test.ts, then removed.
PR91049_HEAD=c18e743ba4ced535ec5351ba536a542db3d7621f node scripts/run-vitest.mjs run --config test/vitest/vitest.gateway.config.ts src/gateway/pr91049-live-terminal-ack-proof.test.ts

Gateway/Control UI live proof still applies because later heads changed Android/Swift/TUI clients only. Current head 9cd2b839bbf4a50882564024fbc3f9c003818e89 is the current conflict-repair head and remains clean against latest main; it preserves the normal TUI timeout/error failure copy after loadHistory().

  • Evidence after fix (screenshot, recording, terminal capture, console output, redacted runtime log, linked artifact, or copied live output):

Focused suite output from this branch:

Test Files 9 passed (9)
Tests 237 passed (237)
Android JVM focused ACK suites: BUILD SUCCESSFUL
Type checks: pnpm tsgo:core, tsgo:test:ui, tsgo:test:packages passed
Touched TypeScript oxlint: Found 0 warnings and 0 errors

Current-head local validation on 9cd2b839bbf4a50882564024fbc3f9c003818e89:

TUI ACK 66/66; TUI PTY 13/13; focused TUI oxlint 0/0; core-test typecheck exit 0; merge-tree clean.
CI-red stale-base replays: prompt snapshots current; session-snapshot 8/8; preview-warnings 42/42; doctor-config-flow 39/39.
Latest-base replays: tooling helper route test passed; extensions test typecheck passed.
Swift targets: line 1045 uses self.waitForChatCompletion; logger status messages avoid OSLogMessage concatenation.

Live Gateway + Control UI terminal-ACK proof from head c18e743ba4ced535ec5351ba536a542db3d7621f for the unchanged Gateway/Control UI path:

✓ gateway-core ../../src/gateway/pr91049-live-terminal-ack-proof.test.ts (1 test)
✓ gateway-server ../../src/gateway/pr91049-live-terminal-ack-proof.test.ts (1 test)
✓ gateway-client ../../src/gateway/pr91049-live-terminal-ack-proof.test.ts (1 test)
Test Files 3 passed (3)
Tests 3 passed (3)

Copied proof artifact from that run:

{"terminalStatus":"timeout","gatewayTerminalAck":{"runId":"00000000-0000-4000-8000-000000091049","status":"timeout"},"uiResult":null,"uiStateAfter":{"chatSending":false,"chatRunId":null,"chatStream":null,"lastError":"The run ended before the message was accepted."}}

Hosted PR checks on broad-validation head 603380bfc4fbc1604ac16cb6915837191a36ad53: macos-swift, android-build-play, android-test-play, android-test-third-party, check-lint, Real behavior proof, and Auto response were SUCCESS (runs: https://github.com/openclaw/openclaw/actions/runs/27089311492, https://github.com/openclaw/openclaw/actions/runs/27089323348, https://github.com/openclaw/openclaw/actions/runs/27089323350).

  • Observed result after fix:
    Focused suites cover protocol schema, gateway Talk, TUI, ACP, slash commands, Android chat, and Android mic. Live Gateway proof shows terminal timeout over WebSocket to Control UI sendChatMessage; after ACK, pending state is cleared and failure copy is set. TUI tests cover detached /btw / /side, accepted-runId rekeying, and normal-send timeout/error failure copy after loadHistory(). Current-head validation adds latest-base stale-failure replays, clean merge-tree, diff check, focused TUI checks, TUI oxlint, core-test typecheck, and the iOS SwiftFormat/logger fixes.

  • What was not tested:
    Full browser/device manual UI testing was not performed. The live proof exercises the Control UI controller source and Gateway WebSocket transport, not a screenshot-driven browser session.

  • Proof limitations or environment constraints:
    The live proof controls the agent reply boundary through the repository Gateway test seam so chat.abort can deterministically produce a terminal timeout ACK. Gateway transport, idempotency caching, terminal ACK payload, and the Control UI controller cleanup path are real source code. The temporary proof harness was not committed to the feature branch. Swift execution was validated by hosted macos-swift, not by the local Linux checkout.

  • Before evidence (optional but encouraged):
    Focused RED tests were used during development for Web helper callers, Android chat timeout/error acceptance, Android mic terminal timeout, ACP terminal ok, and /redirect terminal ACK handling before the fixes were applied.

Tests and validation

  • Focused JS suite listed in the Real behavior proof section.

  • Focused Android JVM/Robolectric ACK suites for ChatSendAckTest, ChatControllerTerminalAckTest, and MicCaptureManagerTest.

  • pnpm tsgo:core

  • pnpm tsgo:test:ui

  • pnpm tsgo:test:packages

  • Touched TypeScript oxlint.

  • git diff --check

  • Hosted PR checks listed above on head 603380bfc4fbc1604ac16cb6915837191a36ad53.

  • Focused TUI ACK suite on 9cd2b839bbf4a50882564024fbc3f9c003818e89: 66 tests passed, covering normal timeout/error/ok, detached /btw / /side, rekeying, and timeout feedback after loadHistory().

  • Current-head gates: previous TUI conflict checks plus latest-base CI-red direct replays; iOS line 1045 now uses self.waitForChatCompletion; logger status messages no longer concatenate OSLogMessage.

  • Web direct send, queued send, detached /btw, queued /steer, and /redirect terminal ACK behavior.

  • Android ACK parsing, chat controller terminal ACK handling, and mic terminal ACK handling.

  • Swift chat terminal timeout feedback.

  • Gateway Talk terminal ACK rejection before realtime subscription.

  • ACP terminal ok parity with terminal timeout/error.

  • TUI terminal ACK send-result handling, including normal-send timeout/error failure copy, detached /btw / /side terminal ACK cleanup, and detached accepted-runId rekeying.

  • Skill Workshop forwarded ACK schema accepting the widened terminal statuses.

RED coverage showed terminal ACK helper callers, Android chat, and Android mic handling could still collapse, accept, or discard terminal statuses after the initial propagation work. /redirect also treated terminal forwarded ACKs as a successful redirect with a tracked run id.

Tests were added or updated for the main status-preserving branches. Swift source changes include test updates; hosted macos-swift passed on the final head.

Risk checklist

Yes. Clients now clear, restore, or fail pending state when the gateway returns a terminal ACK instead of waiting for future run events.

No.

No.

Session/chat lifecycle state: clearing pending or optimistic state too early could hide a message, while not clearing it leaves clients stuck.

The patch preserves non-terminal started / in_flight behavior, keeps runId remapping where needed, restores retryable draft/queue state on terminal failure, and adds regression coverage for the changed branches.

Current review state

Review the status-preserving ACK branches, Android/Swift timeout follow-up, TUI detached ACK cleanup, normal TUI timeout feedback, and current head 9cd2b839bbf4a50882564024fbc3f9c003818e89.

  • Hosted PR checks will report post-push status; no 9cd2b83 hosted run has executed yet.
  • The real-behavior proof gate and platform checks completed successfully on head 603380bfc4fbc1604ac16cb6915837191a36ad53; head e5b96a8c970630618d71b665388c1b924fd07863 adds local focused TUI validation for the detached ACK follow-up.
  • Current head 9cd2b839bbf4a50882564024fbc3f9c003818e89 is merge-tree clean against latest main; latest-base stale-failure replays passed; the iOS SwiftFormat/logger targets are fixed.
  • This PR is waiting on final bot/maintainer review for the current head.

@openclaw-barnacle openclaw-barnacle Bot added app: android App: android app: ios App: ios labels Jun 7, 2026
@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 9, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 13, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. labels Jun 13, 2026
@clawsweeper clawsweeper Bot removed the merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. label Jun 15, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 16, 2026
@clawsweeper clawsweeper Bot 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 16, 2026
@nxmxbbd

nxmxbbd commented Jun 16, 2026

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented Jun 16, 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 proof: sufficient ClawSweeper judged the real behavior proof convincing. 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: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jun 19, 2026
@openclaw-clownfish
openclaw-clownfish Bot merged commit 3ff0c29 into openclaw:main Jun 22, 2026
202 of 212 checks passed
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jun 23, 2026
* test: cover terminal chat send acknowledgements

* test: cover Swift terminal chat send acknowledgement

* fix: handle terminal chat send acknowledgements

* fix: align terminal ack web lifecycle options

* test: fix Android terminal ack style

* fix: tidy Android terminal ack helpers

* fix: clear mic pending run after terminal ack

* fix: handle terminal talk mode chat send acks

* fix: handle terminal tui chat send acks

* fix: handle terminal acp chat send acks

* test: add Swift chat message text helper

* test: cover steer terminal chat send acknowledgements

* fix: handle terminal steer chat send acks

* test: cover terminal realtime consult send acks

* fix: reject terminal realtime consult send acks

* test: cover Swift terminal ok chat send ack

* fix: clear Swift pending run on terminal ok ack

* test: cover terminal ack helper callers

* fix: preserve terminal ack helper semantics

* fix: narrow terminal ack type guard

* test: cover mic terminal ack statuses

* fix: preserve mic terminal ack status

* fix: keep mic ack contract internal

* test: fix mic ack import order

* test: cover acp terminal ok ack

* test: narrow acp ok ack assertion

* test: cover redirect terminal acknowledgements

* fix: handle redirect terminal acknowledgements

* fix: settle terminal ack reconnect prompts

* fix: surface Android terminal ack timeouts

* fix(tui): handle detached terminal chat acknowledgements

* fix(tui): report terminal timeout send failures

* fix: satisfy iOS talk-mode SwiftFormat

* fix: keep iOS talk logs compile-safe
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: android App: android app: ios App: ios app: macos App: macos app: web-ui App: web-ui gateway Gateway runtime 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. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: XL status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Terminal chat.send acknowledgements can leave clients tracking non-running runs

1 participant