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"); }); 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): 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 {