Skip to content

fix(ui): strip injected inbound metadata from user messages in history#22142

Merged
vincentkoc merged 10 commits intoopenclaw:mainfrom
Mellowambience:fix/strip-inbound-metadata-v2
Feb 21, 2026
Merged

fix(ui): strip injected inbound metadata from user messages in history#22142
vincentkoc merged 10 commits intoopenclaw:mainfrom
Mellowambience:fix/strip-inbound-metadata-v2

Conversation

@Mellowambience
Copy link
Copy Markdown
Contributor

@Mellowambience Mellowambience commented Feb 20, 2026

Summary

Fixes #21106, #21109, #22116

OpenClaw prepends structured metadata blocks (Conversation info, Sender:, reply-context) to user messages before sending them to the LLM. These blocks are intentionally AI-context-only and must never reach the chat history that users see.

Root Cause

buildInboundUserContextPrefix in inbound-meta.ts prepends the blocks directly to the stored user message content string, so they are persisted verbatim and later shown in webchat, TUI, and every other rendering surface.

Fix

src/auto-reply/reply/strip-inbound-meta.ts — new utility with a 6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.

src/tui/tui-session-actions.ts — wraps chatLog.addUser(...) with stripInboundMetadata() so the TUI never stores the prefix.

ui/src/ui/chat/message-normalizer.ts — strips user-role text content items during normalisation so webchat renders clean messages.

Change Type

  • Bug fix

Scope

  • UI/UX
  • TUI

Linked Issues

Fixes #21106
Fixes #21109
Fixes #22116

🤖 AI-Assisted: Yes (via OpenClaw / MIST)

Note: This is a clean resubmission of the previously closed PR #21138. The original branch had accumulated unrelated commits from the fork — this branch contains only the 4 relevant files.

Greptile Summary

Implements metadata stripping across all UI surfaces (TUI, webchat, Swift) to prevent AI-context-only metadata blocks from appearing in user-visible chat history.

Key Changes:

  • Created stripInboundMetadata() utility with fast-path optimization (zero-alloc when no metadata present) and comprehensive test suite
  • Applied stripping in 4 locations: TUI session actions, webchat message normalizer, webchat message extractor, and Swift ChatViewModel
  • Swift and TypeScript implementations use identical line-by-line state machine parsers
  • Strips 6 sentinel types: Conversation info, Sender, Thread starter, Replied message, Forwarded message, Chat history

Observations:

  • TypeScript version splits on \n only, while Swift normalizes \r\n to \n first - potential inconsistency if messages contain CRLF line endings
  • All 6 sentinels match those defined in buildInboundUserContextPrefix() in inbound-meta.ts:103-189
  • Fast-path regex prevents unnecessary parsing when no sentinels are present

Confidence Score: 4/5

  • This PR is safe to merge with minor concerns around line ending handling
  • The implementation correctly strips metadata from user messages across all platforms (TypeScript, Swift, TUI, webchat). The core logic is sound with comprehensive test coverage (9 tests for TS, 3 tests for Swift). However, the TypeScript implementation lacks CRLF normalization that the Swift version includes, which could cause issues if messages contain Windows-style line endings.
  • Pay attention to src/auto-reply/reply/strip-inbound-meta.ts for potential line ending edge case

Last reviewed commit: deb3674

@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@vincentkoc
Copy link
Copy Markdown
Member

Implemented on this PR:

  • Normalized message extraction for user messages to apply inbound metadata stripping in UI chat extraction path (ui/src/ui/chat/message-extract.ts).
  • Preserved indentation semantics in metadata trimming (src/auto-reply/reply/strip-inbound-meta.ts) and added regression coverage.
  • Kept PR formatting-clean via oxfmt@0.33.0 and added follow-up visibility in canonical issue.

Closed duplicate cluster items remain tracked at canonical issue #21109:

  • 21106, 22116, 22156, 22202, 21030, 19718, 20297, and PR 21121.

Open/scope-overlap relateds remain on hold: #20903, #20807.

Post-merge follow-up surfaces (still monitored): #21643, #21548, #22147.

@vincentkoc vincentkoc force-pushed the fix/strip-inbound-metadata-v2 branch from 961f631 to 3b62f4e Compare February 21, 2026 00:18
@openclaw-barnacle openclaw-barnacle Bot added the channel: discord Channel integration: discord label Feb 21, 2026
@vincentkoc vincentkoc self-assigned this Feb 21, 2026
Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

8 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread src/discord/send.components.test.ts Outdated
@vincentkoc
Copy link
Copy Markdown
Member

@greptileai review

Copy link
Copy Markdown
Contributor

@greptile-apps greptile-apps Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

10 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment thread src/auto-reply/reply/strip-inbound-meta.ts
@vincentkoc vincentkoc force-pushed the fix/strip-inbound-metadata-v2 branch from b9cc688 to 828aa83 Compare February 21, 2026 01:22
Mellowambience and others added 6 commits February 20, 2026 17:32
Fixes openclaw#21106
Fixes openclaw#21109
Fixes openclaw#22116

OpenClaw prepends structured metadata blocks ("Conversation info",
"Sender:", reply-context) to user messages before sending them to the
LLM. These blocks are intentionally AI-context-only and must never reach
the chat history that users see.

Root cause:
`buildInboundUserContextPrefix` in `inbound-meta.ts` prepends the
blocks directly to the stored user message content string, so they are
persisted verbatim and later shown in webchat, TUI, and every other
rendering surface.

Fix:
• `src/auto-reply/reply/strip-inbound-meta.ts` — new utility with a
  6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.
• `src/tui/tui-session-actions.ts` — wraps `chatLog.addUser(...)` with
  `stripInboundMetadata()` so the TUI never stores the prefix.
• `ui/src/ui/chat/message-normalizer.ts` — strips user-role text content
  items during normalisation so webchat renders clean messages.
@vincentkoc vincentkoc force-pushed the fix/strip-inbound-metadata-v2 branch from 828aa83 to 046d926 Compare February 21, 2026 01:33
@vincentkoc vincentkoc merged commit a4e7e95 into openclaw:main Feb 21, 2026
6 checks passed
mmyyfirstb pushed a commit to mmyyfirstb/openclaw that referenced this pull request Feb 21, 2026
openclaw#22142)

* fix(ui): strip injected inbound metadata from user messages in history

Fixes openclaw#21106
Fixes openclaw#21109
Fixes openclaw#22116

OpenClaw prepends structured metadata blocks ("Conversation info",
"Sender:", reply-context) to user messages before sending them to the
LLM. These blocks are intentionally AI-context-only and must never reach
the chat history that users see.

Root cause:
`buildInboundUserContextPrefix` in `inbound-meta.ts` prepends the
blocks directly to the stored user message content string, so they are
persisted verbatim and later shown in webchat, TUI, and every other
rendering surface.

Fix:
• `src/auto-reply/reply/strip-inbound-meta.ts` — new utility with a
  6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.
• `src/tui/tui-session-actions.ts` — wraps `chatLog.addUser(...)` with
  `stripInboundMetadata()` so the TUI never stores the prefix.
• `ui/src/ui/chat/message-normalizer.ts` — strips user-role text content
  items during normalisation so webchat renders clean messages.

* fix(ui): strip inbound metadata for user messages in display path

* test: fix discord component send test spread typing

* fix: strip inbound metadata from mac chat history decode

* fix: align Swift metadata stripping parser with TS implementation

* fix: normalize line endings in inbound metadata stripper

* chore: document Swift/TS metadata-sentinel ownership

* chore: update changelog for inbound metadata strip fix

* changelog: credit Mellowambience for 22142

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
mreedr pushed a commit to mreedr/openclaw-custom that referenced this pull request Feb 24, 2026
openclaw#22142)

* fix(ui): strip injected inbound metadata from user messages in history

Fixes openclaw#21106
Fixes openclaw#21109
Fixes openclaw#22116

OpenClaw prepends structured metadata blocks ("Conversation info",
"Sender:", reply-context) to user messages before sending them to the
LLM. These blocks are intentionally AI-context-only and must never reach
the chat history that users see.

Root cause:
`buildInboundUserContextPrefix` in `inbound-meta.ts` prepends the
blocks directly to the stored user message content string, so they are
persisted verbatim and later shown in webchat, TUI, and every other
rendering surface.

Fix:
• `src/auto-reply/reply/strip-inbound-meta.ts` — new utility with a
  6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.
• `src/tui/tui-session-actions.ts` — wraps `chatLog.addUser(...)` with
  `stripInboundMetadata()` so the TUI never stores the prefix.
• `ui/src/ui/chat/message-normalizer.ts` — strips user-role text content
  items during normalisation so webchat renders clean messages.

* fix(ui): strip inbound metadata for user messages in display path

* test: fix discord component send test spread typing

* fix: strip inbound metadata from mac chat history decode

* fix: align Swift metadata stripping parser with TS implementation

* fix: normalize line endings in inbound metadata stripper

* chore: document Swift/TS metadata-sentinel ownership

* chore: update changelog for inbound metadata strip fix

* changelog: credit Mellowambience for 22142

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
zooqueen pushed a commit to hanzoai/bot that referenced this pull request Mar 6, 2026
openclaw#22142)

* fix(ui): strip injected inbound metadata from user messages in history

Fixes openclaw#21106
Fixes openclaw#21109
Fixes openclaw#22116

OpenClaw prepends structured metadata blocks ("Conversation info",
"Sender:", reply-context) to user messages before sending them to the
LLM. These blocks are intentionally AI-context-only and must never reach
the chat history that users see.

Root cause:
`buildInboundUserContextPrefix` in `inbound-meta.ts` prepends the
blocks directly to the stored user message content string, so they are
persisted verbatim and later shown in webchat, TUI, and every other
rendering surface.

Fix:
• `src/auto-reply/reply/strip-inbound-meta.ts` — new utility with a
  6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.
• `src/tui/tui-session-actions.ts` — wraps `chatLog.addUser(...)` with
  `stripInboundMetadata()` so the TUI never stores the prefix.
• `ui/src/ui/chat/message-normalizer.ts` — strips user-role text content
  items during normalisation so webchat renders clean messages.

* fix(ui): strip inbound metadata for user messages in display path

* test: fix discord component send test spread typing

* fix: strip inbound metadata from mac chat history decode

* fix: align Swift metadata stripping parser with TS implementation

* fix: normalize line endings in inbound metadata stripper

* chore: document Swift/TS metadata-sentinel ownership

* chore: update changelog for inbound metadata strip fix

* changelog: credit Mellowambience for 22142

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
lovewanwan pushed a commit to lovewanwan/openclaw that referenced this pull request Apr 28, 2026
openclaw#22142)

* fix(ui): strip injected inbound metadata from user messages in history

Fixes openclaw#21106
Fixes openclaw#21109
Fixes openclaw#22116

OpenClaw prepends structured metadata blocks ("Conversation info",
"Sender:", reply-context) to user messages before sending them to the
LLM. These blocks are intentionally AI-context-only and must never reach
the chat history that users see.

Root cause:
`buildInboundUserContextPrefix` in `inbound-meta.ts` prepends the
blocks directly to the stored user message content string, so they are
persisted verbatim and later shown in webchat, TUI, and every other
rendering surface.

Fix:
• `src/auto-reply/reply/strip-inbound-meta.ts` — new utility with a
  6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.
• `src/tui/tui-session-actions.ts` — wraps `chatLog.addUser(...)` with
  `stripInboundMetadata()` so the TUI never stores the prefix.
• `ui/src/ui/chat/message-normalizer.ts` — strips user-role text content
  items during normalisation so webchat renders clean messages.

* fix(ui): strip inbound metadata for user messages in display path

* test: fix discord component send test spread typing

* fix: strip inbound metadata from mac chat history decode

* fix: align Swift metadata stripping parser with TS implementation

* fix: normalize line endings in inbound metadata stripper

* chore: document Swift/TS metadata-sentinel ownership

* chore: update changelog for inbound metadata strip fix

* changelog: credit Mellowambience for 22142

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
ogt-redknie pushed a commit to ogt-redknie/OPENX that referenced this pull request May 2, 2026
openclaw#22142)

* fix(ui): strip injected inbound metadata from user messages in history

Fixes openclaw#21106
Fixes openclaw#21109
Fixes openclaw#22116

OpenClaw prepends structured metadata blocks ("Conversation info",
"Sender:", reply-context) to user messages before sending them to the
LLM. These blocks are intentionally AI-context-only and must never reach
the chat history that users see.

Root cause:
`buildInboundUserContextPrefix` in `inbound-meta.ts` prepends the
blocks directly to the stored user message content string, so they are
persisted verbatim and later shown in webchat, TUI, and every other
rendering surface.

Fix:
• `src/auto-reply/reply/strip-inbound-meta.ts` — new utility with a
  6-sentinel fast-path strip (zero-alloc on miss) + 9-test suite.
• `src/tui/tui-session-actions.ts` — wraps `chatLog.addUser(...)` with
  `stripInboundMetadata()` so the TUI never stores the prefix.
• `ui/src/ui/chat/message-normalizer.ts` — strips user-role text content
  items during normalisation so webchat renders clean messages.

* fix(ui): strip inbound metadata for user messages in display path

* test: fix discord component send test spread typing

* fix: strip inbound metadata from mac chat history decode

* fix: align Swift metadata stripping parser with TS implementation

* fix: normalize line endings in inbound metadata stripper

* chore: document Swift/TS metadata-sentinel ownership

* chore: update changelog for inbound metadata strip fix

* changelog: credit Mellowambience for 22142

---------

Co-authored-by: Vincent Koc <vincentkoc@ieee.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui channel: discord Channel integration: discord size: M

Projects

None yet

2 participants