From e4b3bbd3a2d2b327ba84f528706cf12fd5ddc832 Mon Sep 17 00:00:00 2001 From: spoukyii <61633921+spoukyii@users.noreply.github.com> Date: Tue, 3 Nov 2026 12:17:47 -0800 Subject: [PATCH 1/2] test(mobile): cover a long untitled subagent prompt that ends on an emoji --- .../src/features/threads/threadAgentsPresentation.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/mobile/src/features/threads/threadAgentsPresentation.test.ts b/apps/mobile/src/features/threads/threadAgentsPresentation.test.ts index 171d73a148597..e0771be61c5eb 100644 --- a/apps/mobile/src/features/threads/threadAgentsPresentation.test.ts +++ b/apps/mobile/src/features/threads/threadAgentsPresentation.test.ts @@ -64,10 +64,15 @@ describe("resolveSubagentRowPresentation", () => { it("falls back to a trimmed prompt when the agent has no title", () => { const long = resolveSubagentRowPresentation({ ...base, prompt: "x".repeat(200) }); + const emoji = resolveSubagentRowPresentation({ + ...base, + prompt: `${"x".repeat(76)}😀 and more`, + }); const titled = resolveSubagentRowPresentation({ ...base, title: "Subagent: /root/my_worker" }); expect(long.title).toHaveLength(80); expect(long.title.endsWith("...")).toBe(true); + expect(emoji.title).toBe(`${"x".repeat(76)}...`); expect(titled.title).toBe("My Worker"); }); From 5a89ae6ceb6e60f76df96da8e965373bb1e316f7 Mon Sep 17 00:00:00 2001 From: spoukyii <61633921+spoukyii@users.noreply.github.com> Date: Tue, 3 Nov 2026 12:17:56 -0800 Subject: [PATCH 2/2] fix(mobile): untitled subagent rows no longer end in a broken character The Agents sheet titles a subagent that has no title of its own from its prompt, cut at 77 UTF-16 code units with "..." added. When an emoji straddled the cut, the title kept only its high surrogate and ended in a replacement character before the "...". The row itself is one line and cuts the title off well before that point, but the Stop confirmation dialog ("Stop ?") and the Stop button's VoiceOver label show the whole title. The cut now steps back one unit when it would land between a high and a low surrogate, the same check #29163 and #29563 added to thread titles. Bug: an untitled subagent row on mobile ends in a broken character when an emoji sits at the cut --- .../src/features/threads/threadAgentsPresentation.ts | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/apps/mobile/src/features/threads/threadAgentsPresentation.ts b/apps/mobile/src/features/threads/threadAgentsPresentation.ts index 7f560497da254..1e0f0c7960592 100644 --- a/apps/mobile/src/features/threads/threadAgentsPresentation.ts +++ b/apps/mobile/src/features/threads/threadAgentsPresentation.ts @@ -58,9 +58,14 @@ function rowTitle(subagent: Pick<OrchestrationV2Subagent, "title" | "prompt">): if (title) return formatSubagentDisplayTitle(title); const prompt = subagent.prompt.trim(); if (prompt.length === 0) return "Subagent"; - return prompt.length > PROMPT_TITLE_LIMIT - ? `${prompt.slice(0, PROMPT_TITLE_LIMIT - 3)}...` - : prompt; + if (prompt.length <= PROMPT_TITLE_LIMIT) return prompt; + let end = PROMPT_TITLE_LIMIT - 3; + const previous = prompt.charCodeAt(end - 1); + const next = prompt.charCodeAt(end); + if (previous >= 0xd800 && previous <= 0xdbff && next >= 0xdc00 && next <= 0xdfff) { + end -= 1; + } + return `${prompt.slice(0, end)}...`; } function rowTone(status: OrchestrationV2Subagent["status"]): SubagentRowTone {