@@ -251,4 +251,142 @@ describe('sdk-event-handlers', () => {
251251 } )
252252 expect ( getStreamingAgents ( ) . size ) . toBe ( 0 )
253253 } )
254+
255+ test ( 'handles spawn_agents tool results for agents with tool blocks (lastMessage mode)' , ( ) => {
256+ const { ctx, getMessages, getStreamingAgents } = createTestContext ( )
257+
258+ // Create an agent block with an existing tool block (simulating thinker agent's read_files)
259+ ctx . message . updater . updateAiMessageBlocks ( ( ) => [
260+ {
261+ type : 'agent' ,
262+ agentId : 'tool-1-0' ,
263+ agentName : 'Thinker' ,
264+ agentType : 'thinker-with-files-gemini' ,
265+ content : '' ,
266+ status : 'running' ,
267+ blocks : [
268+ {
269+ type : 'tool' ,
270+ toolCallId : 'read-1' ,
271+ toolName : 'read_files' ,
272+ input : { paths : [ 'package.json' ] } ,
273+ output : 'package contents' ,
274+ } ,
275+ ] ,
276+ initialPrompt : 'Think about this' ,
277+ spawnToolCallId : 'tool-1' ,
278+ spawnIndex : 0 ,
279+ } as any ,
280+ ] )
281+ ctx . streaming . setStreamingAgents ( ( ) => new Set ( [ 'tool-1-0' ] ) )
282+
283+ const handleEvent = createEventHandler ( ctx )
284+ const toolResultEvent : ToolResultEvent = {
285+ type : 'tool_result' ,
286+ toolCallId : 'tool-1' ,
287+ toolName : 'spawn_agents' ,
288+ output : [
289+ {
290+ type : 'json' ,
291+ value : [
292+ {
293+ agentName : 'thinker-with-files-gemini' ,
294+ value : {
295+ type : 'lastMessage' ,
296+ value : [
297+ {
298+ role : 'assistant' ,
299+ content : [
300+ { type : 'text' , text : 'Here is the analysis result.' } ,
301+ ] ,
302+ } ,
303+ ] ,
304+ } ,
305+ } ,
306+ ] ,
307+ } ,
308+ ] ,
309+ }
310+ handleEvent ( toolResultEvent )
311+
312+ const agentBlock = ( getMessages ( ) [ 0 ] . blocks ?? [ ] ) [ 0 ] as AgentContentBlock
313+ expect ( agentBlock . status ) . toBe ( 'complete' )
314+ // Should have the tool block AND the final text content
315+ expect ( agentBlock . blocks ) . toHaveLength ( 2 )
316+ expect ( agentBlock . blocks ?. [ 0 ] ) . toMatchObject ( {
317+ type : 'tool' ,
318+ toolName : 'read_files' ,
319+ } )
320+ expect ( agentBlock . blocks ?. [ 1 ] ) . toMatchObject ( {
321+ type : 'text' ,
322+ content : 'Here is the analysis result.' ,
323+ } )
324+ expect ( getStreamingAgents ( ) . size ) . toBe ( 0 )
325+ } )
326+
327+ test ( 'preserves streamed text content and skips duplicate final content' , ( ) => {
328+ const { ctx, getMessages, getStreamingAgents } = createTestContext ( )
329+
330+ // Create an agent block with existing text blocks (simulating streamed output like basher)
331+ ctx . message . updater . updateAiMessageBlocks ( ( ) => [
332+ {
333+ type : 'agent' ,
334+ agentId : 'tool-1-0' ,
335+ agentName : 'Basher' ,
336+ agentType : 'basher' ,
337+ content : '' ,
338+ status : 'running' ,
339+ blocks : [
340+ {
341+ type : 'text' ,
342+ content : 'Streamed output from basher' ,
343+ textType : 'text' ,
344+ } ,
345+ ] ,
346+ initialPrompt : 'Run a command' ,
347+ spawnToolCallId : 'tool-1' ,
348+ spawnIndex : 0 ,
349+ } as any ,
350+ ] )
351+ ctx . streaming . setStreamingAgents ( ( ) => new Set ( [ 'tool-1-0' ] ) )
352+
353+ const handleEvent = createEventHandler ( ctx )
354+ const toolResultEvent : ToolResultEvent = {
355+ type : 'tool_result' ,
356+ toolCallId : 'tool-1' ,
357+ toolName : 'spawn_agents' ,
358+ output : [
359+ {
360+ type : 'json' ,
361+ value : [
362+ {
363+ agentName : 'basher' ,
364+ value : {
365+ type : 'lastMessage' ,
366+ value : [
367+ {
368+ role : 'assistant' ,
369+ content : [
370+ { type : 'text' , text : 'Streamed output from basher' } ,
371+ ] ,
372+ } ,
373+ ] ,
374+ } ,
375+ } ,
376+ ] ,
377+ } ,
378+ ] ,
379+ }
380+ handleEvent ( toolResultEvent )
381+
382+ const agentBlock = ( getMessages ( ) [ 0 ] . blocks ?? [ ] ) [ 0 ] as AgentContentBlock
383+ expect ( agentBlock . status ) . toBe ( 'complete' )
384+ // Should NOT duplicate the streamed text — only the original text block
385+ expect ( agentBlock . blocks ) . toHaveLength ( 1 )
386+ expect ( agentBlock . blocks ?. [ 0 ] ) . toMatchObject ( {
387+ type : 'text' ,
388+ content : 'Streamed output from basher' ,
389+ } )
390+ expect ( getStreamingAgents ( ) . size ) . toBe ( 0 )
391+ } )
254392} )
0 commit comments