fix(webchat): suppress NO_REPLY token in chat transcript rendering (#32183)

* fix(types): resolve pre-existing TS errors in agent-components and pairing-store

- agent-components.ts: normalizeDiscordAllowList returns {allowAll, ids, names},
  not an array — use ids.values().next().value instead of [0] indexing
- pairing-store.ts: add non-null assertions for stat after cache-miss guard
  (resolveAllowFromReadCacheOrMissing returns early when stat is null)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(webchat): suppress NO_REPLY token in chat transcript rendering

Filter assistant NO_REPLY-only entries from chat.history responses at
the gateway API boundary and add client-side defense-in-depth guards in
the UI chat controller so internal silent tokens never render as visible
chat bubbles.

Two-layer fix:
1. Gateway: extractAssistantTextForSilentCheck + isSilentReplyText
   filter in sanitizeChatHistoryMessages (entry.text takes precedence
   over entry.content to avoid dropping messages with real text)
2. UI: isAssistantSilentReply + isSilentReplyStream guards on all 5
   message insertion points in handleChatEvent and loadChatHistory

Fixes #32015

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(webchat): align isAssistantSilentReply text/content precedence with gateway

* webchat: tighten NO_REPLY transcript and delta filtering

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Tak Hoffman <781889+Takhoffman@users.noreply.github.com>
This commit is contained in:
ademczuk
2026-03-02 23:39:08 +01:00
committed by GitHub
parent 48155729fc
commit 0743463b88
7 changed files with 492 additions and 19 deletions

View File

@@ -871,7 +871,7 @@ async function dispatchDiscordComponentEvent(params: {
normalizeEntry: (entry) => {
const normalized = normalizeDiscordAllowList([entry], ["discord:", "user:", "pk:"]);
const candidate = normalized?.ids.values().next().value;
return candidate && /^\d+$/.test(candidate) ? candidate : undefined;
return typeof candidate === "string" && /^\d+$/.test(candidate) ? candidate : undefined;
},
})
: null;