diff --git a/packages/client-runtime/src/state/subagentRuntime.test.ts b/packages/client-runtime/src/state/subagentRuntime.test.ts index 93d15b016d755..7be9639bafedb 100644 --- a/packages/client-runtime/src/state/subagentRuntime.test.ts +++ b/packages/client-runtime/src/state/subagentRuntime.test.ts @@ -158,6 +158,13 @@ describe("projectedSubagentsToRuntime workflow expansion", () => { expect(members?.[0]?.speed).toBeUndefined(); }, ); + + it("titles an untitled subagent from its prompt without splitting an emoji", () => { + const [untitled] = projectedSubagentsToRuntime([ + subagent({ title: null, prompt: `${"a".repeat(76)}😀 and more work.` }), + ]); + expect(untitled?.title).toBe(`${"a".repeat(76)}...`); + }); }); describe("deriveWorkflowGroups over a dynamic workflow", () => { diff --git a/packages/client-runtime/src/state/subagentRuntime.ts b/packages/client-runtime/src/state/subagentRuntime.ts index fac58a029ce62..8205d178e5cd6 100644 --- a/packages/client-runtime/src/state/subagentRuntime.ts +++ b/packages/client-runtime/src/state/subagentRuntime.ts @@ -176,6 +176,17 @@ function workflowMembersToRuntime( }); } +function promptTitle(prompt: string): string { + if (prompt.length <= 80) return prompt; + let end = 77; + 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)}...`; +} + export function workflowMemberModelSelection( member: Pick, instanceId: ModelSelection["instanceId"], @@ -216,9 +227,7 @@ export function projectedSubagentsToRuntime( const coordinator = { id: subagent.id, kind: workflow === undefined ? "subagent" : "workflow", - title: - subagent.title ?? - (subagent.prompt.length > 80 ? `${subagent.prompt.slice(0, 77)}...` : subagent.prompt), + title: subagent.title ?? promptTitle(subagent.prompt), role: null, model: subagent.model, effort: null,