From 8a6af7b25d4edc3418ebab0189745f00b1826a41 Mon Sep 17 00:00:00 2001 From: Alex Southwell <4596216+saphid@users.noreply.github.com> Date: Tue, 3 Nov 2026 07:46:46 +1100 Subject: [PATCH] fix(server): side chat and merge-back context no longer cut an emoji in half Co-Authored-By: Claude Opus 5.5 --- .../src/orchestration-v2/ContextHandoffService.test.ts | 5 +++-- apps/server/src/orchestration-v2/ContextHandoffService.ts | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/apps/server/src/orchestration-v2/ContextHandoffService.test.ts b/apps/server/src/orchestration-v2/ContextHandoffService.test.ts index b5109cb99d930..0282819d81b56 100644 --- a/apps/server/src/orchestration-v2/ContextHandoffService.test.ts +++ b/apps/server/src/orchestration-v2/ContextHandoffService.test.ts @@ -169,12 +169,12 @@ it.effect("caps the side chat context block without summarizing discarded parent ...importedItem({ role: index % 2 === 0 ? "user" : "assistant", id: `parent-${index}`, - text: `item-${index} ${"x".repeat(300)}`, + text: `item-${index} ${"x".repeat(228)}😀${"x".repeat(70)}`, ordinal: index, }), get text() { summarizedItems++; - return `item-${index} ${"x".repeat(300)}`; + return `item-${index} ${"x".repeat(228)}😀${"x".repeat(70)}`; }, })); const service = yield* ContextHandoffService.ContextHandoffServiceV2; @@ -197,6 +197,7 @@ it.effect("caps the side chat context block without summarizing discarded parent assert.notInclude(context, "item-0 "); assert.include(context, "- Assistant: item-59 "); assert.isAtMost(context.length, 8_000); + assert.isTrue(context.isWellFormed()); assert.isTrue( context.endsWith( `Use t3_thread_read on thread ${parentThreadId} to see the main thread's live state.`, diff --git a/apps/server/src/orchestration-v2/ContextHandoffService.ts b/apps/server/src/orchestration-v2/ContextHandoffService.ts index 7eef0afefbc17..dcfffa018c8c0 100644 --- a/apps/server/src/orchestration-v2/ContextHandoffService.ts +++ b/apps/server/src/orchestration-v2/ContextHandoffService.ts @@ -109,7 +109,9 @@ function compactText(text: string, maxLength = 240): string { if (compacted.length <= maxLength) { return compacted; } - return `${compacted.slice(0, maxLength - 3)}...`; + const end = maxLength - 3; + const last = compacted.charCodeAt(end - 1); + return `${compacted.slice(0, last >= 0xd800 && last <= 0xdbff ? end - 1 : end)}...`; } export function visibleDeltaRunOrdinals(