fix(ui): preserve Talk transcript surrogate bounds

This commit is contained in:
Vincent Koc
2026-08-02 03:19:48 +08:00
parent 35799b63f9
commit 07822aaefd
2 changed files with 27 additions and 3 deletions
@@ -217,6 +217,29 @@ describe("realtime Talk conversation", () => {
expect(state.entries[0]?.text.endsWith("NEWEST")).toBe(true);
});
it.each([255, 256])(
"does not retain a lone high surrogate before a natural marker at offset %i",
(markerOffset) => {
let state = createRealtimeTalkConversationState();
const retainedText = "a".repeat(markerOffset - 1);
state = updateRealtimeTalkConversation(state, {
role: "assistant",
text: `${retainedText}\uD800\n…\n${"b".repeat(8_000)}NEWEST`,
final: true,
nowMs: 1,
});
const text = state.entries[0]?.text ?? "";
expect(text.length).toBeLessThanOrEqual(8_000);
expect(text.startsWith(`${retainedText}\n…\n`)).toBe(true);
expect(text.endsWith("NEWEST")).toBe(true);
expect(text).not.toMatch(
/(?:[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?<![\uD800-\uDBFF])[\uDC00-\uDFFF])/,
);
},
);
it.each(["user", "assistant"] as const)(
"bounds oversized final %s entries while retaining the newest text",
(role) => {
@@ -285,9 +285,10 @@ function boundRealtimeConversationText(text: string): string {
const hasBoundedPrefix =
markerIndex >= CONVERSATION_ENTRY_PREFIX_CHARS - 1 &&
markerIndex <= CONVERSATION_ENTRY_PREFIX_CHARS;
const prefix = hasBoundedPrefix
? text.slice(0, markerIndex)
: sliceUtf16Safe(text, 0, CONVERSATION_ENTRY_PREFIX_CHARS);
const prefixEnd = hasBoundedPrefix ? markerIndex : CONVERSATION_ENTRY_PREFIX_CHARS;
// A natural marker can follow malformed provider text ending in a lone high
// surrogate. Keep that code unit out of the retained truncation boundary.
const prefix = sliceUtf16Safe(text, 0, prefixEnd).replace(/[\uD800-\uDBFF]$/, "");
const tailChars =
MAX_CONVERSATION_ENTRY_CHARS - prefix.length - CONVERSATION_ENTRY_TRUNCATION_MARKER.length;
const tail = sliceUtf16Safe(text, -tailChars);