openclaw - ✅(Solved) Fix [Bug]: [Bug] TUI renders internal command envelopes to operator; async completion events inject verbose agent instructions into session transcript [1 pull requests, 1 comments, 1 participants]

Official PRs (…)
ON THIS PAGE

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…
GitHub stats
openclaw/openclaw#59871Fetched 2026-04-08 02:39:32
View on GitHub
Comments
1
Participants
1
Timeline
5
Reactions
0
Author
Participants
Timeline (top)
labeled ×2commented ×1cross-referenced ×1referenced ×1

Two related but distinct bugs were found by inspecting the compiled TUI bundle (dist/tui-Da-djW_y.js) and the strip-inbound-meta module.

Root Cause

extractTextFromMessage() calls stripLeadingInboundMetadata() only when record.role === "user". Command messages carry no role, so they bypass stripping entirely.

Fix Action

Fixed

PR fix notes

PR #59985: fix(tui): strip inbound metadata from command messages before rendering (#59871)

Description (problem / solution / changelog)

Summary

Command messages (async exec completion notices, gateway system messages) rendered raw internal envelope metadata in the operator TUI because extractTextFromMessage only stripped inbound metadata for role === "user" messages.

Root Cause

In src/tui/tui-formatters.ts, extractTextFromMessage() conditionally calls stripLeadingInboundMetadata() only when record.role === "user". Command messages carry command: true without a user role, so they bypass stripping entirely. The raw metadata blocks (conversation info, sender labels, untrusted context) are passed directly to chatLog.addSystem() and rendered to the operator.

Changes

  • src/tui/tui-formatters.ts: extend the strip condition to record.role === "user" || record.command === true
  • src/tui/tui-formatters.test.ts: add regression test verifying command messages have metadata stripped

Test

pnpm test -- src/tui/tui-formatters.test.ts  # 27 passed

Closes #59871

Changed files

  • src/tui/tui-formatters.test.ts (modified, +23/-0)
  • src/tui/tui-formatters.ts (modified, +1/-1)

Code Example

[exec completed: code 0]

### Steps to reproduce

1. Run OpenClaw 2026.4.1 with a gateway on WSL2/Linux and use the TUI client on Windows.
2. Start a session where the agent requests an exec approval.
3. Approve the exec and let it complete asynchronously.
4. Observe the TUI output after completion.
5. Repeat with multiple approvals, including stale/timed-out ones if possible.
6. Check both:
   - what is rendered in the TUI
   - what is injected back into the agent transcript after exec completion

### Expected behavior

1. Internal command/system envelopes should not render raw in the operator TUI.
2. Async exec completions should appear either suppressed or as a short operator-friendly summary, such as:
   [exec completed: code 0]
3. Agent-facing async completion events should be injected into context in a compact format containing only the essentials:
   - short id
   - exit code
   - truncated output
4. Redundant behavioral instructions such as “Do not run the command again” and “Only ask the user for help if you are actually blocked” should not be injected on every async completion event.

### Actual behavior

1. The TUI renders raw internal command/system envelope text, including async completion wrappers.
2. The agent receives verbose async completion messages in its working context, including repeated behavioral instructions.
3. These messages consume unnecessary context tokens and can create focus noise, especially when several async completions arrive in sequence or when stale/timed-out approvals complete later.
4. In practice, the operator sees internal wrapper text in the terminal, and the agent must process the full verbose completion envelope instead of a compact result summary.

### OpenClaw version

2026.4.1

### Operating system

Gateway: WSL2 / Linux Client: Windows

### Install method

_No response_

### Model

Claude Sonnet 4.6

### Provider / routing chain

Claude CLI / Anthropic via OpenClaw gateway Channels used during testing: TUI and Telegram

### Additional provider/model setup details

_No response_

### Logs, screenshots, and evidence
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

Two related but distinct bugs were found by inspecting the compiled TUI bundle (dist/tui-Da-djW_y.js) and the strip-inbound-meta module.

Bug 1 — TUI Display Layer: Command envelopes rendered to operator

Component: src/tui/tui-event-handlers.ts

Describe the bug

When a chat event with message.command === true arrives (e.g. async exec completion notices, gateway system messages), the TUI passes the full text to chatLog.addSystem() without any filtering. This causes internal agent-facing text to render visibly in the operator's terminal.

Root cause

extractTextFromMessage() calls stripLeadingInboundMetadata() only when record.role === "user". Command messages carry no role, so they bypass stripping entirely.

Affected call sites

Approximate compiled bundle locations:

  • handleChatEvent()isCommandMessage branch (~line 2652)
  • loadHistory() → command message branch (~line 3022)

Expected behavior

Command/system messages intended for agent context should not render as raw text in the operator's TUI view. They should either be suppressed or collapsed to a compact operator summary such as:

[exec completed: code 0]

### Steps to reproduce

1. Run OpenClaw 2026.4.1 with a gateway on WSL2/Linux and use the TUI client on Windows.
2. Start a session where the agent requests an exec approval.
3. Approve the exec and let it complete asynchronously.
4. Observe the TUI output after completion.
5. Repeat with multiple approvals, including stale/timed-out ones if possible.
6. Check both:
   - what is rendered in the TUI
   - what is injected back into the agent transcript after exec completion

### Expected behavior

1. Internal command/system envelopes should not render raw in the operator TUI.
2. Async exec completions should appear either suppressed or as a short operator-friendly summary, such as:
   [exec completed: code 0]
3. Agent-facing async completion events should be injected into context in a compact format containing only the essentials:
   - short id
   - exit code
   - truncated output
4. Redundant behavioral instructions such as “Do not run the command again” and “Only ask the user for help if you are actually blocked” should not be injected on every async completion event.

### Actual behavior

1. The TUI renders raw internal command/system envelope text, including async completion wrappers.
2. The agent receives verbose async completion messages in its working context, including repeated behavioral instructions.
3. These messages consume unnecessary context tokens and can create focus noise, especially when several async completions arrive in sequence or when stale/timed-out approvals complete later.
4. In practice, the operator sees internal wrapper text in the terminal, and the agent must process the full verbose completion envelope instead of a compact result summary.

### OpenClaw version

2026.4.1

### Operating system

Gateway: WSL2 / Linux Client: Windows

### Install method

_No response_

### Model

Claude Sonnet 4.6

### Provider / routing chain

Claude CLI / Anthropic via OpenClaw gateway Channels used during testing: TUI and Telegram

### Additional provider/model setup details

_No response_

### Logs, screenshots, and evidence

```shell

Impact and severity

Severity: Medium for TUI display bug, High for gateway/session transcript injection bug.

Impact:

  1. TUI display-layer issue — Medium
  • Internal command/system envelopes are rendered directly to the operator.
  • This creates noisy, confusing terminal output and exposes agent-facing internal wrapper text that should not be shown raw.
  • It is primarily a UX/operator-clarity problem.
  1. Gateway/session transcript injection issue — High
  • Every async exec completion injects a verbose human-readable wrapper into the agent’s working context.
  • This adds roughly 150–300 unnecessary tokens per completion event.
  • Repeated or stale async completions can accumulate quickly and dilute working context.
  • The injected text includes redundant behavioral instructions that overlap with the system prompt.
  • This can reduce model focus, waste context budget, and increase the chance of off-track responses or unnecessary acknowledgments.

Overall:

  • The display bug is cosmetic but disruptive.
  • The transcript injection bug affects model quality and context efficiency and is the more serious issue.

Additional information

This appears to involve two related issues:

  1. TUI display-layer bug: command-type messages bypass metadata stripping and render raw to the operator.

  2. Gateway/session transcript formatting bug: async exec completion events are injected into agent context as verbose human-readable envelopes instead of compact structured summaries.

The TUI issue is cosmetic/UX-facing. The transcript injection issue affects model focus and token usage.

extent analysis

TL;DR

Modify the extractTextFromMessage() function to strip metadata from command messages by calling stripLeadingInboundMetadata() regardless of the message role.

Guidance

  • Review the extractTextFromMessage() function in src/tui/tui-event-handlers.ts to ensure it correctly handles command messages by stripping leading inbound metadata.
  • Update the handleChatEvent() and loadHistory() functions to use the modified extractTextFromMessage() function for command messages.
  • Verify that command messages are no longer rendered raw in the operator's TUI view and that async exec completions are injected into the agent's context in a compact format.
  • Test the changes with multiple approvals, including stale/timed-out ones, to ensure the fix works as expected.

Example

// Modified extractTextFromMessage() function
function extractTextFromMessage(message) {
  if (message.command === true) {
    return stripLeadingInboundMetadata(message.text);
  } else if (message.role === "user") {
    return stripLeadingInboundMetadata(message.text);
  } else {
    return message.text;
  }
}

Notes

The provided solution assumes that the stripLeadingInboundMetadata() function correctly removes the necessary metadata from command messages. Additional testing may be required to ensure the fix works as expected in all scenarios.

Recommendation

Apply the workaround by modifying the extractTextFromMessage() function to strip metadata from command messages, as this should resolve both the TUI display-layer bug and the gateway/session transcript formatting bug.

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

  1. Internal command/system envelopes should not render raw in the operator TUI.
  2. Async exec completions should appear either suppressed or as a short operator-friendly summary, such as: [exec completed: code 0]
  3. Agent-facing async completion events should be injected into context in a compact format containing only the essentials:
    • short id
    • exit code
    • truncated output
  4. Redundant behavioral instructions such as “Do not run the command again” and “Only ask the user for help if you are actually blocked” should not be injected on every async completion event.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING