Skip to content

fix(tui): arm streaming watchdog on every delta, not only visible ones#69338

Merged
amknight merged 1 commit intoopenclaw:mainfrom
CCcassiusdjs:fix/tui-delta-watchdog-arm
Apr 21, 2026
Merged

fix(tui): arm streaming watchdog on every delta, not only visible ones#69338
amknight merged 1 commit intoopenclaw:mainfrom
CCcassiusdjs:fix/tui-delta-watchdog-arm

Conversation

@CCcassiusdjs
Copy link
Copy Markdown
Contributor

Summary

  • When ingestDelta returns null (no visible change yet — first commentary-only delta, tool-call delta, or unchanged content), the handler returned early, skipping setActivityStatus("streaming") and armStreamingWatchdog
  • If every delta during a run returned null (common when phase filtering drops all content), the streaming watchdog was never armed and the status bar stayed stuck on "idle" while the run was active
  • Move setActivityStatus and armStreamingWatchdog before the null check so both fire on every received delta, regardless of visible output

Root cause

// before
if (!displayText) {
  return;  // ← skipped setActivityStatus + armStreamingWatchdog
}
chatLog.updateAssistant(displayText, evt.runId);
setActivityStatus("streaming");  // ← never reached on null delta
armStreamingWatchdog(evt.runId); // ← never reached on null delta

The tui.requestRender() at the end of handleChatEvent is intentionally still skipped on null deltas (no visual change), so render pressure is unchanged.

Affected issues

Fixes #34513, #40824

Test plan

  • Status bar shows streaming immediately when a run starts, even if first visible text arrives after a delay
  • 30s watchdog fires and resets status when backend drops a run silently mid-stream
  • pnpm test src/tui/ green

🤖 Generated with Claude Code

When ingestDelta returns null (first empty/commentary delta or unchanged
content), the handler returned early, skipping setActivityStatus and
armStreamingWatchdog. If all subsequent deltas were also null (e.g.
due to phase filtering), the watchdog was never armed and the status bar
stayed stale as "idle" while a run was live.

Move setActivityStatus("streaming") and armStreamingWatchdog before
the null-displayText guard so they fire on every received delta event.

Fixes openclaw#34513, openclaw#40824

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 20, 2026

Greptile Summary

This PR fixes a bug where the streaming watchdog and activity status were never set when all received deltas produced no visible output (e.g. commentary-only or tool-call deltas). The fix moves setActivityStatus("streaming") and armStreamingWatchdog before the ingestDelta null-check, so both fire on every delta. The tui.requestRender() call is intentionally still skipped on null deltas, keeping render pressure unchanged.

Confidence Score: 5/5

Safe to merge — minimal, targeted fix with no regressions introduced.

The change is a two-line reorder within a single conditional block. The watchdog guard (activeChatRunId === evt.runId) is preserved, render pressure is unchanged, and finalized-run filtering upstream prevents stale events from reaching this path.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(tui): arm streaming watchdog on ever..." | Re-trigger Greptile

@amknight
Copy link
Copy Markdown
Member

LGTM 👍 merging

@amknight amknight merged commit 89b6d02 into openclaw:main Apr 21, 2026
49 checks passed
zhongmairen pushed a commit to agencyos-cn/openclaw-bad that referenced this pull request Apr 21, 2026
* 'main' of https://github.com/openclaw/openclaw:
  fix(agents): enforce subagent envelope inheritance on ACP child sessions [AI-assisted] (openclaw#69383)
  fix(tui): arm streaming watchdog on every delta, not only visible ones (openclaw#69338)
  fix(codex): exclude codex-app-server synthetic apiKey from secrets audit (openclaw#69581)
steipete pushed a commit that referenced this pull request Apr 21, 2026
#69338)

When ingestDelta returns null (first empty/commentary delta or unchanged
content), the handler returned early, skipping setActivityStatus and
armStreamingWatchdog. If all subsequent deltas were also null (e.g.
due to phase filtering), the watchdog was never armed and the status bar
stayed stale as "idle" while a run was live.

Move setActivityStatus("streaming") and armStreamingWatchdog before
the null-displayText guard so they fire on every received delta event.

Fixes #34513, #40824

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
(cherry picked from commit 89b6d02)
gdibble pushed a commit to gdibble/openclaw that referenced this pull request Apr 21, 2026
openclaw#69338)

When ingestDelta returns null (first empty/commentary delta or unchanged
content), the handler returned early, skipping setActivityStatus and
armStreamingWatchdog. If all subsequent deltas were also null (e.g.
due to phase filtering), the watchdog was never armed and the status bar
stayed stale as "idle" while a run was live.

Move setActivityStatus("streaming") and armStreamingWatchdog before
the null-displayText guard so they fire on every received delta event.

Fixes openclaw#34513, openclaw#40824

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
openclaw#69338)

When ingestDelta returns null (first empty/commentary delta or unchanged
content), the handler returned early, skipping setActivityStatus and
armStreamingWatchdog. If all subsequent deltas were also null (e.g.
due to phase filtering), the watchdog was never armed and the status bar
stayed stale as "idle" while a run was live.

Move setActivityStatus("streaming") and armStreamingWatchdog before
the null-displayText guard so they fire on every received delta event.

Fixes openclaw#34513, openclaw#40824

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
zhonghe0615 pushed a commit to zhonghe0615/openclaw that referenced this pull request May 7, 2026
openclaw#69338)

When ingestDelta returns null (first empty/commentary delta or unchanged
content), the handler returned early, skipping setActivityStatus and
armStreamingWatchdog. If all subsequent deltas were also null (e.g.
due to phase filtering), the watchdog was never armed and the status bar
stayed stale as "idle" while a run was live.

Move setActivityStatus("streaming") and armStreamingWatchdog before
the null-displayText guard so they fire on every received delta event.

Fixes openclaw#34513, openclaw#40824

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
openclaw#69338)

When ingestDelta returns null (first empty/commentary delta or unchanged
content), the handler returned early, skipping setActivityStatus and
armStreamingWatchdog. If all subsequent deltas were also null (e.g.
due to phase filtering), the watchdog was never armed and the status bar
stayed stale as "idle" while a run was live.

Move setActivityStatus("streaming") and armStreamingWatchdog before
the null-displayText guard so they fire on every received delta event.

Fixes openclaw#34513, openclaw#40824

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: TUI stops rendering messages after 1-2 messages, have to restart to see them

2 participants