Skip to content

fix(ui): strip reply directive tags from assistant messages in WebChat (#23053)#23144

Closed
echoVic wants to merge 2 commits into
openclaw:mainfrom
echoVic:fix/webchat-reply-tag-strip
Closed

fix(ui): strip reply directive tags from assistant messages in WebChat (#23053)#23144
echoVic wants to merge 2 commits into
openclaw:mainfrom
echoVic:fix/webchat-reply-tag-strip

Conversation

@echoVic

@echoVic echoVic commented Feb 22, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #23053[[reply_to_current]] (and [[reply_to:<id>]], [[audio_as_voice]]) tags appear as raw text in WebChat after a message finishes streaming.

Root Cause

Two code paths render assistant messages in WebChat:

  1. Streaming path (src/gateway/server-chat.ts): emitChatDelta and emitChatFinal both call stripInlineDirectiveTagsForDisplay() before broadcasting — tags are stripped ✅
  2. History/render path (ui/src/ui/chat/message-extract.ts): extractText() only calls stripThinkingTags() for assistant messages — tags are not stripped ❌

When streaming completes, WebChat reloads history from the session store. The raw messages (with reply tags) pass through extractText()extractTextCached()grouped-render.ts without stripping, so [[reply_to_current]] becomes visible.

Fix

Apply stripInlineDirectiveTagsForDisplay() alongside stripThinkingTags() for assistant messages in extractText(). This reuses the same utility already used by the gateway streaming path.

function stripAssistantDirectives(text: string): string {
  return stripInlineDirectiveTagsForDisplay(stripThinkingTags(text)).text;
}

Changes

  • ui/src/ui/chat/message-extract.ts — import stripInlineDirectiveTagsForDisplay, apply to all three assistant text extraction branches
  • ui/src/ui/chat/message-extract.test.ts — 6 new test cases covering string content, content array, explicit reply ID, audio tag, .text field, and user messages (no-op)

Testing

  • [[reply_to_current]] Hello → assistant renders Hello
  • [[reply_to: msg_123]] Hello → assistant renders Hello
  • [[audio_as_voice]] Hello → assistant renders Hello
  • User messages are unaffected (tags preserved as-is)

Greptile Summary

Fixes [[reply_to_current]] and related directive tags appearing as raw text in WebChat after message streaming completes.

Root Cause: The streaming path (server-chat.ts) strips directive tags before broadcasting, but the history/render path (message-extract.ts) only stripped thinking tags. When WebChat reloads history from session store after streaming, raw directive tags become visible.

Solution: Applied stripInlineDirectiveTagsForDisplay() alongside stripThinkingTags() for all assistant message extraction paths (string content, content array, and .text field), reusing the same utility as the gateway streaming path.

Test Coverage: Added 6 test cases covering string content, content arrays, explicit reply IDs, audio tags, .text field, and verification that user messages are unaffected.

Minor Note: One style suggestion regarding whitespace normalization consistency with the gateway code pattern.

Confidence Score: 4/5

  • This PR is safe to merge with low risk
  • The fix correctly addresses the root cause by applying the same directive tag stripping utility to both code paths (streaming and history rendering). The implementation reuses existing, well-tested functions and adds comprehensive test coverage. Score is 4/5 rather than 5/5 due to one minor style suggestion about whitespace normalization consistency with the gateway pattern, though this likely has minimal practical impact given markdown rendering behavior.
  • No files require special attention - the changes are straightforward and well-tested

Last reviewed commit: aa76e1e

When WebChat loads chat history, assistant messages containing
[[reply_to_current]] or [[reply_to:<id>]] tags were rendered with the
raw tag text visible. This happened because extractText() only stripped
thinking tags for assistant messages but not inline directive tags.

During streaming, server-chat.ts correctly strips these tags via
stripInlineDirectiveTagsForDisplay(). However, when the message
finalizes and history is reloaded from the session store, the UI's
extractText() path did not apply the same stripping.

Fix: apply stripInlineDirectiveTagsForDisplay() alongside
stripThinkingTags() for assistant messages in extractText().

Closes openclaw#23053

@whynice724-cell whynice724-cell left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review ✅

PR #23144 - Fix for reply directive tags leaking in WebChat

Summary

The fix correctly addresses the issue where tags appear as raw text in WebChat after message streaming completes.

Analysis

  • Root cause correctly identified - extractText() only calls stripThinkingTags() but not stripInlineDirectiveTagsForDisplay()
  • Solution cleanly reuses the existing utility already used in the gateway streaming path
  • Testing: Added 6 new test cases covering various scenarios

Changes Review

  • message-extract.ts - Import and apply stripInlineDirectiveTagsForDisplay() ✅
  • message-extract.test.ts - Comprehensive test coverage ✅

Verdict

Approve - The fix is minimal, targeted, and reuses existing utilities correctly. No security concerns. Mergeable.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

2 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines +6 to +8
function stripAssistantDirectives(text: string): string {
return stripInlineDirectiveTagsForDisplay(stripThinkingTags(text)).text;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Potential whitespace issue: stripInlineDirectiveTagsForDisplay removes tags but doesn't trim the result. For input like "[[reply_to_current]] Hello", this produces " Hello" with a leading space. The gateway code (server-chat.ts:329) explicitly calls .trim() after stripping. Consider adding .trimStart() here to match the trim: "start" behavior of stripThinkingTags and ensure consistency:

Suggested change
function stripAssistantDirectives(text: string): string {
return stripInlineDirectiveTagsForDisplay(stripThinkingTags(text)).text;
}
function stripAssistantDirectives(text: string): string {
return stripInlineDirectiveTagsForDisplay(stripThinkingTags(text)).text.trimStart();
}

(Markdown renderers may normalize this, but direct consumers of extractText() could see the leading space)

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/chat/message-extract.ts
Line: 6-8

Comment:
Potential whitespace issue: `stripInlineDirectiveTagsForDisplay` removes tags but doesn't trim the result. For input like `"[[reply_to_current]] Hello"`, this produces `" Hello"` with a leading space. The gateway code (`server-chat.ts:329`) explicitly calls `.trim()` after stripping. Consider adding `.trimStart()` here to match the `trim: "start"` behavior of `stripThinkingTags` and ensure consistency:

```suggestion
function stripAssistantDirectives(text: string): string {
  return stripInlineDirectiveTagsForDisplay(stripThinkingTags(text)).text.trimStart();
}
```

(Markdown renderers may normalize this, but direct consumers of `extractText()` could see the leading space)

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@echoVic

echoVic commented Feb 22, 2026

Copy link
Copy Markdown
Contributor Author

Addressed greptile's review — added .trimStart() after stripping directive tags (ec2ba2e) to avoid leading whitespace, matching the gateway's trim behavior.

@echoVic

echoVic commented Feb 23, 2026

Copy link
Copy Markdown
Contributor Author

Closing — issue #23053 has been resolved in main.

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]: WebChat shows [[reply_to_current]] tag after message completes (not during streaming)

2 participants