Gateway: hide NO_REPLY-only entries from chat.history#32082
Gateway: hide NO_REPLY-only entries from chat.history#32082liuxiaopai-ai wants to merge 3 commits intoopenclaw:mainfrom
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8b9d06a68c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| if (typed.type !== "text" || typeof typed.text !== "string") { | ||
| return undefined; |
There was a problem hiding this comment.
Handle output_text blocks in silent history filtering
isSilentAssistantHistoryMessage only treats content blocks with type === "text" as candidates, so assistant entries like content: [{ type: "output_text", text: "NO_REPLY" }] are not filtered and still leak into chat.history. This matters because the gateway/OpenAI paths already use output_text blocks, and downstream history rendering reads .text without requiring type: "text", so users can still see visible NO_REPLY bubbles in those sessions.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR filters out assistant messages whose content is exactly the internal Key findings:
Confidence Score: 3/5
Last reviewed commit: 8b9d06a |
src/gateway/server-methods/chat.ts
Outdated
| if (typeof entry.text === "string" && isSilentReplyText(entry.text, SILENT_REPLY_TOKEN)) { | ||
| return true; | ||
| } | ||
| if (typeof entry.content === "string") { | ||
| return isSilentReplyText(entry.content, SILENT_REPLY_TOKEN); | ||
| } |
There was a problem hiding this comment.
Non-silent text field falls through to content check
When entry.text is a non-empty string that is not the silent token (e.g., "Hello"), the first if block evaluates to false and execution falls through to the entry.content check. If entry.content happens to be the string "NO_REPLY", the function returns true and the message is incorrectly dropped — even though the message carries real text in its text field.
The guard on entry.text should be a complete short-circuit: if a text field is present, its value alone should determine whether the message is silent, and the content field should not be consulted at all.
| if (typeof entry.text === "string" && isSilentReplyText(entry.text, SILENT_REPLY_TOKEN)) { | |
| return true; | |
| } | |
| if (typeof entry.content === "string") { | |
| return isSilentReplyText(entry.content, SILENT_REPLY_TOKEN); | |
| } | |
| if (typeof entry.text === "string") { | |
| return isSilentReplyText(entry.text, SILENT_REPLY_TOKEN); | |
| } | |
| if (typeof entry.content === "string") { | |
| return isSilentReplyText(entry.content, SILENT_REPLY_TOKEN); | |
| } |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/gateway/server-methods/chat.ts
Line: 211-216
Comment:
**Non-silent `text` field falls through to `content` check**
When `entry.text` is a non-empty string that is *not* the silent token (e.g., `"Hello"`), the first `if` block evaluates to `false` and execution falls through to the `entry.content` check. If `entry.content` happens to be the string `"NO_REPLY"`, the function returns `true` and the message is incorrectly dropped — even though the message carries real text in its `text` field.
The guard on `entry.text` should be a complete short-circuit: if a `text` field is present, its value alone should determine whether the message is silent, and the `content` field should not be consulted at all.
```suggestion
if (typeof entry.text === "string") {
return isSilentReplyText(entry.text, SILENT_REPLY_TOKEN);
}
if (typeof entry.content === "string") {
return isSilentReplyText(entry.content, SILENT_REPLY_TOKEN);
}
```
How can I resolve this? If you propose a fix, please make it concise.|
Addressed, thanks for the catch. I pushed a follow-up commit (
Also added a regression case in
|
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d14048b7ce
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| return undefined; | ||
| } | ||
| const typed = block as { type?: unknown; text?: unknown }; | ||
| if (typed.type !== "text" || typeof typed.text !== "string") { |
There was a problem hiding this comment.
Treat output_text blocks as silent in chat.history
isSilentAssistantHistoryMessage only keeps blocks with type === "text", so assistant entries like content: [{ type: "output_text", text: "NO_REPLY" }] are not filtered and still appear in chat.history. This is a regression for gateway/OpenAI-style transcripts because we already treat output_text as normal textual content elsewhere (see src/gateway/session-utils.fs.ts:379), so users can still get visible NO_REPLY bubbles in sessions that use those block types.
Useful? React with 👍 / 👎.
|
Closing as superseded by #32183, which is now merged and covers the NO_REPLY history/UI guardrails with regression tests. |
Summary
chat.historyresponses to drop assistant transcript entries that are exactly the silent token (NO_REPLY)chat.historyto ensureNO_REPLYentries do not appear in returned historyFixes #32015.
Security Impact
Repro + Verification
Repro (before)
NO_REPLY.chat.history.NO_REPLY, which can render as visible bubble in Webchat.Verification (after)
pnpm exec vitest run src/gateway/server.chat.gateway-server-chat.test.tspnpm lint src/gateway/server-methods/chat.ts src/gateway/server.chat.gateway-server-chat.test.ts CHANGELOG.mdpnpm tsgoHuman Verification
chat.historyexcludes assistantNO_REPLY-only messages