openclaw - 💡(How to fix) Fix [Bug]: Gateway and embedded TUI ignore delta-only assistant events for live chat projection [3 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

Gateway chat projection and embedded TUI chat projection ignore assistant stream events that carry an incremental data.delta but no cumulative data.text. When a provider/runtime path emits canonical assistant delta events in that shape, live chat consumers can see the run start and then only receive the final chat event, with no intermediate chat state:"delta" frames. Downstream UIs lose their working/thinking/streaming indication during the run.

Root Cause

Actual: no live chat delta is emitted because both Gateway and embedded TUI require typeof evt.data?.text === "string" before updating chat buffers.

Fix Action

Fixed

Code Example

emitAgentEvent({
  runId,
  stream: "assistant",
  data: { delta: "hello" },
});

---

if (
  !isAborted &&
  evt.stream === "assistant" &&
  typeof evt.data?.text === "string" &&
  !shouldSuppressAssistantEventForLiveChat(evt.data)
) {
  emitChatDelta(sessionKey, clientRunId, evt.runId, evt.seq, evt.data.text, evt.data.delta);
}

---

if (
  evt.stream === "assistant" &&
  !run.isBtw &&
  typeof evt.data?.text === "string" &&
  !shouldSuppressAssistantEventForLiveChat(evt.data)
) {
  // merge/update live chat buffer
}

---

[bridge] Started streaming run=8795fd8b-879f-41a3-a8f3-08b77791b166 messageId=stream-8795fd8b-879f-41a3-a8f3-08b77791b166
[bridge] Chat event: state=final runId=8795fd8b-879f-41a3-a8f3-08b77791b166
[bridge] Finalized streaming run=8795fd8b-879f-41a3-a8f3-08b77791b166

---

const assistantText = typeof evt.data?.text === "string" ? evt.data.text : "";
const assistantDelta = typeof evt.data?.delta === "string" ? evt.data.delta : "";
if (!isAborted && evt.stream === "assistant" && (assistantText || assistantDelta) && !shouldSuppressAssistantEventForLiveChat(evt.data)) {
  emitChatDelta(sessionKey, clientRunId, evt.runId, evt.seq, assistantText, assistantDelta);
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect live streaming state without crash)

Beta release blocker

No

Summary

Gateway chat projection and embedded TUI chat projection ignore assistant stream events that carry an incremental data.delta but no cumulative data.text. When a provider/runtime path emits canonical assistant delta events in that shape, live chat consumers can see the run start and then only receive the final chat event, with no intermediate chat state:"delta" frames. Downstream UIs lose their working/thinking/streaming indication during the run.

Steps to reproduce

Source-level reproduction:

  1. Run a session through the Gateway or embedded TUI path.
  2. Emit an assistant agent event shaped like:
emitAgentEvent({
  runId,
  stream: "assistant",
  data: { delta: "hello" },
});
  1. Keep the run alive, then later emit lifecycle end / final response.
  2. Observe chat projection output.

Expected: the assistant delta should update chat projection/live UI state, using delta as the incremental text when text is absent.

Actual: no live chat delta is emitted because both Gateway and embedded TUI require typeof evt.data?.text === "string" before updating chat buffers.

Expected behavior

The live chat projection should accept canonical assistant delta events with either:

  • data.text + optional data.delta, or
  • data.delta alone, treating the delta as the next incremental chunk.

This keeps TUI/Control UI/SDK/session observers visibly working while the run is active, even when the runtime emits delta-only assistant chunks.

Actual behavior

Current upstream main gates chat projection on cumulative data.text:

if (
  !isAborted &&
  evt.stream === "assistant" &&
  typeof evt.data?.text === "string" &&
  !shouldSuppressAssistantEventForLiveChat(evt.data)
) {
  emitChatDelta(sessionKey, clientRunId, evt.runId, evt.seq, evt.data.text, evt.data.delta);
}

The same shape exists in embedded TUI handling:

if (
  evt.stream === "assistant" &&
  !run.isBtw &&
  typeof evt.data?.text === "string" &&
  !shouldSuppressAssistantEventForLiveChat(evt.data)
) {
  // merge/update live chat buffer
}

Delta-only assistant events are still broadcast as raw agent events, but they are not promoted into live chat projection events. Consumers that depend on chat deltas for visible working/streaming state can sit on an initial placeholder until final.

OpenClaw version

Observed on installed OpenClaw 2026.5.12 (f066dd2) and checked against current upstream main at 635b947e32 after git fetch --all --prune on 2026-05-17.

Operating system

Ubuntu 24.04 / Linux x86_64

Install method

npm global (~/.npm-global/lib/node_modules/openclaw), Gateway via systemd user service.

Model

Observed through a Venice Claude Opus route in an OpenClaw Pi Default session. The source-level bug is not model-specific; it depends on whether the runtime emits assistant chunks with delta only versus cumulative text.

Provider / routing chain

OpenClaw Gateway / TUI session -> agent runtime -> assistant stream events -> Gateway/TUI chat projection -> downstream client (eva-core bridge in the observed deployment).

Additional provider/model setup details

The observed downstream bridge created streaming placeholders and later persisted final replies, but did not receive intermediate chat delta events. Gateway logs showed runs active, and the downstream service logs showed Started streaming followed by repeated Chat event: state=final lines without intermediate state=delta chat events for affected runs.

Logs, screenshots, and evidence

Relevant current-main source evidence:

  • src/gateway/server-chat.ts still requires cumulative evt.data.text before calling emitChatDelta for assistant events. Checked on origin/main 635b947e32 after fetch.
  • src/tui/embedded-backend.ts has the same typeof evt.data?.text === "string" gate before updating run.buffer and emitting embedded chat deltas.
  • src/gateway/live-chat-projector.ts already supports merging with nextDelta when nextText is empty via resolveMergedAssistantText(...), so the projection helper can handle delta-only input if callers pass text: "" and delta.
  • packages/sdk/src/normalize.ts classifies assistant events with string data.delta as assistant.delta, so delta-only assistant events are an accepted SDK/event shape.
  • Existing tests such as src/gateway/openai-http.test.ts emit assistant events with { delta: "he" } / { delta: "llo" }, showing delta-only assistant events are part of the test surface.

Observed local downstream evidence from eva-core logs around 2026-05-17 00:10 PDT:

[bridge] Started streaming run=8795fd8b-879f-41a3-a8f3-08b77791b166 messageId=stream-8795fd8b-879f-41a3-a8f3-08b77791b166
[bridge] Chat event: state=final runId=8795fd8b-879f-41a3-a8f3-08b77791b166
[bridge] Finalized streaming run=8795fd8b-879f-41a3-a8f3-08b77791b166

No intermediate Chat event: state=delta entries were present in the inspected log slice for affected runs, matching the missing working/streaming indicator symptom.

Impact and severity

Affected: live chat surfaces that rely on Gateway/TUI chat deltas to show progress, including Control UI/TUI-like observers and external bridges.

Severity: Medium. Final answers can still arrive, but the live UX regresses: active runs appear quiet/stuck or fail to show the normal working/thinking/streaming indicator until final. This is especially confusing for long-running or sparse-output turns.

Frequency: Depends on runtime/provider event shape. Any path that emits assistant deltas without cumulative text can trigger it.

Consequence: Users may think the run is idle or broken, send duplicate messages, or rely on downstream transcript fallbacks that are suppressed by recent gateway activity.

Additional information

This appears related to but distinct from:

  • #78360: TUI watchdog marks quiet active runs idle. That is about quiet active runs and watchdog state. This report is about chat projection dropping valid delta-only assistant chunks before the watchdog/fallback question.
  • #77537: Render TUI commentary progress events. That is about phase:"commentary" progress events. This report is about ordinary assistant delta events with no cumulative text.
  • #74827: SDK chat-only projection fallback delta normalization. That fixed SDK fallback deltas after chat projection exists. This report is earlier in the pipeline: chat projection itself is not produced for delta-only assistant events.
  • #67052 / #74614 / #82611: Adjacent live/final/session-observer issues, but not this exact event-contract mismatch.

Suggested low-risk fix direction:

Normalize assistant live-chat input before the gate, e.g. allow typeof evt.data?.delta === "string" as a valid assistant text update, then call the existing merge helper with text defaulting to "":

const assistantText = typeof evt.data?.text === "string" ? evt.data.text : "";
const assistantDelta = typeof evt.data?.delta === "string" ? evt.data.delta : "";
if (!isAborted && evt.stream === "assistant" && (assistantText || assistantDelta) && !shouldSuppressAssistantEventForLiveChat(evt.data)) {
  emitChatDelta(sessionKey, clientRunId, evt.runId, evt.seq, assistantText, assistantDelta);
}

Apply the same normalization to src/tui/embedded-backend.ts, with focused regression tests for delta-only assistant events producing chat delta output without duplicating cumulative-text paths.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

The live chat projection should accept canonical assistant delta events with either:

  • data.text + optional data.delta, or
  • data.delta alone, treating the delta as the next incremental chunk.

This keeps TUI/Control UI/SDK/session observers visibly working while the run is active, even when the runtime emits delta-only assistant chunks.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - 💡(How to fix) Fix [Bug]: Gateway and embedded TUI ignore delta-only assistant events for live chat projection [3 pull requests]