@@ -11,6 +11,7 @@ import {
1111 useState ,
1212} from 'react'
1313import { cn } from '@sim/emcn'
14+ import { compactAsyncAgentLaunch } from '@/lib/copilot/chat/async-agent-display'
1415import { PrepareFileEdit , Read as ReadTool } from '@/lib/copilot/generated/tool-catalog-v1'
1516import { isToolHiddenInUi } from '@/lib/copilot/tools/client/hidden-tools'
1617import { resolveToolDisplay } from '@/lib/copilot/tools/client/store-utils'
@@ -181,7 +182,19 @@ function mapToolStatusToClientState(
181182 }
182183}
183184
184- function getOverrideDisplayTitle ( tc : NonNullable < ContentBlock [ 'toolCall' ] > ) : string | undefined {
185+ function getOverrideDisplayTitle (
186+ tc : NonNullable < ContentBlock [ 'toolCall' ] > ,
187+ agentNames : ReadonlyMap < string , string >
188+ ) : string | undefined {
189+ if (
190+ agentNames . size > 0 &&
191+ [ 'wait_agents' , 'tail_agent' , 'steer_agent' , 'interrupt_agent' ] . includes ( tc . name )
192+ ) {
193+ const ids = tc . name === 'wait_agents' ? tc . params ?. agent_ids : [ tc . params ?. agent_id ]
194+ if ( Array . isArray ( ids ) && ids . some ( ( id ) => typeof id === 'string' && agentNames . has ( id ) ) ) {
195+ return getToolDisplayTitle ( tc . name , tc . params , agentNames )
196+ }
197+ }
185198 if ( tc . name === ReadTool . id || tc . name === 'respond' || tc . name . endsWith ( '_respond' ) ) {
186199 return resolveToolDisplay ( tc . name , mapToolStatusToClientState ( tc . status ) , tc . params ) ?. text
187200 }
@@ -199,8 +212,11 @@ function getOverrideDisplayTitle(tc: NonNullable<ContentBlock['toolCall']>): str
199212 return undefined
200213}
201214
202- function toToolData ( tc : NonNullable < ContentBlock [ 'toolCall' ] > ) : ToolCallData {
203- const overrideDisplayTitle = getOverrideDisplayTitle ( tc )
215+ function toToolData (
216+ tc : NonNullable < ContentBlock [ 'toolCall' ] > ,
217+ agentNames : ReadonlyMap < string , string >
218+ ) : ToolCallData {
219+ const overrideDisplayTitle = getOverrideDisplayTitle ( tc , agentNames )
204220 const resolvedTitle =
205221 overrideDisplayTitle || tc . displayTitle || getToolDisplayTitle ( tc . name , tc . params )
206222 const displayTitle = getToolStatusDisplayTitle ( resolvedTitle , tc . status , tc . name )
@@ -253,7 +269,10 @@ function appendTextItem(group: AgentGroupSegment, content: string): void {
253269 * no name/tool-call reverse lookups. Delegation tool_calls are absorbed — the
254270 * subagent span is the canonical representation of the nested agent.
255271 */
256- function parseBlocksWithSpanTree ( blocks : ContentBlock [ ] ) : MessageSegment [ ] {
272+ function parseBlocksWithSpanTree (
273+ blocks : ContentBlock [ ] ,
274+ agentNames : ReadonlyMap < string , string >
275+ ) : MessageSegment [ ] {
257276 const segments : MessageSegment [ ] = [ ]
258277 const groupsBySpanId = new Map < string , AgentGroupSegment > ( )
259278 // Stable per-run counters for React keys. The Nth top-level text run / Nth
@@ -422,7 +441,7 @@ function parseBlocksWithSpanTree(blocks: ContentBlock[]): MessageSegment[] {
422441 if ( tc . name === ReadTool . id && isToolResultRead ( tc . params ) ) continue
423442 // Delegation tools are represented by their subagent span group; absorb.
424443 if ( SUBAGENT_KEYS . has ( tc . name ) ) continue
425- const tool = toToolData ( tc )
444+ const tool = toToolData ( tc , agentNames )
426445 if ( block . spanId ) {
427446 let g = groupsBySpanId . get ( block . spanId )
428447 // Out-of-order safety: a subagent's tool can stream before its
@@ -500,10 +519,19 @@ function parseBlocksWithSpanTree(blocks: ContentBlock[]): MessageSegment[] {
500519 * span identity existed.
501520 */
502521export function parseBlocks ( blocks : ContentBlock [ ] ) : MessageSegment [ ] {
522+ /** Launch results retain display names; their slugified IDs can cut words short. */
523+ const agentNames = new Map < string , string > ( )
524+ for ( const block of blocks ) {
525+ if ( block . type !== 'tool_call' ) continue
526+ const tc = block . toolCall
527+ if ( ! tc ?. result ?. success ) continue
528+ const launch = compactAsyncAgentLaunch ( tc . name , tc . result . output )
529+ if ( launch ) agentNames . set ( launch . agentId , launch . name )
530+ }
503531 if ( blocks . some ( ( block ) => Boolean ( block . spanId ) ) ) {
504- return parseBlocksWithSpanTree ( blocks )
532+ return parseBlocksWithSpanTree ( blocks , agentNames )
505533 }
506- return parseBlocksLegacy ( blocks )
534+ return parseBlocksLegacy ( blocks , agentNames )
507535}
508536
509537function joinRenderableText ( parts : string [ ] ) : string {
@@ -523,7 +551,10 @@ export function getOrchestratorMessageText(
523551 )
524552}
525553
526- function parseBlocksLegacy ( blocks : ContentBlock [ ] ) : MessageSegment [ ] {
554+ function parseBlocksLegacy (
555+ blocks : ContentBlock [ ] ,
556+ agentNames : ReadonlyMap < string , string >
557+ ) : MessageSegment [ ] {
527558 const segments : MessageSegment [ ] = [ ]
528559 const groupsByKey = new Map < string , AgentGroupSegment > ( )
529560 let activeGroupKey : string | null = null
@@ -677,7 +708,7 @@ function parseBlocksLegacy(blocks: ContentBlock[]): MessageSegment[] {
677708 continue
678709 }
679710
680- const tool = toToolData ( tc )
711+ const tool = toToolData ( tc , agentNames )
681712
682713 if ( tc . calledBy ) {
683714 const { group : g , created } = ensureGroup ( tc . calledBy , block . parentToolCallId )
0 commit comments