Skip to content

Commit 70d0f85

Browse files
author
SidQin-cyber
committed
fix(gateway): filter NO_REPLY messages from chat history endpoint
The streaming path (emitChatDelta/emitChatFinal) already suppresses assistant messages containing NO_REPLY tokens, but the chat.history endpoint returned them unfiltered. When users refresh webchat or open a new connection, historical NO_REPLY messages appeared in the UI. Add extractAssistantText() to pull text from various message formats and filter out matching messages in sanitizeChatHistoryMessages(), bringing the history path in line with the streaming path. Closes #27238
1 parent e35fe78 commit 70d0f85

File tree

1 file changed

+29
-3
lines changed

1 file changed

+29
-3
lines changed

src/gateway/server-methods/chat.ts

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { MsgContext } from "../../auto-reply/templating.js";
1010
import { createReplyPrefixOptions } from "../../channels/reply-prefix.js";
1111
import { resolveSessionFilePath } from "../../config/sessions.js";
1212
import { resolveSendPolicy } from "../../sessions/send-policy.js";
13+
import { isSilentReplyText } from "../../auto-reply/tokens.js";
1314
import {
1415
stripInlineDirectiveTagsForDisplay,
1516
stripInlineDirectiveTagsFromMessageForDisplay,
@@ -185,16 +186,41 @@ function sanitizeChatHistoryMessage(message: unknown): { message: unknown; chang
185186
return { message: changed ? entry : message, changed };
186187
}
187188

189+
function extractAssistantText(message: unknown): string | undefined {
190+
if (!message || typeof message !== "object") return undefined;
191+
const entry = message as Record<string, unknown>;
192+
if (entry.role !== "assistant") return undefined;
193+
if (typeof entry.content === "string") return entry.content;
194+
if (Array.isArray(entry.content)) {
195+
const parts = entry.content
196+
.filter(
197+
(b: unknown): b is Record<string, unknown> =>
198+
!!b && typeof b === "object" && (b as Record<string, unknown>).type === "text",
199+
)
200+
.map((b) => b.text)
201+
.filter((t): t is string => typeof t === "string");
202+
return parts.length > 0 ? parts.join("") : undefined;
203+
}
204+
if (typeof entry.text === "string") return entry.text;
205+
return undefined;
206+
}
207+
188208
function sanitizeChatHistoryMessages(messages: unknown[]): unknown[] {
189209
if (messages.length === 0) {
190210
return messages;
191211
}
192212
let changed = false;
193-
const next = messages.map((message) => {
213+
const next: unknown[] = [];
214+
for (const message of messages) {
194215
const res = sanitizeChatHistoryMessage(message);
195216
changed ||= res.changed;
196-
return res.message;
197-
});
217+
const text = extractAssistantText(res.message);
218+
if (text !== undefined && isSilentReplyText(text)) {
219+
changed = true;
220+
continue;
221+
}
222+
next.push(res.message);
223+
}
198224
return changed ? next : messages;
199225
}
200226

0 commit comments

Comments
 (0)