@@ -29,12 +29,12 @@ describe("box.agent.run", () => {
2929
3030 it ( "calls onToolUse callback" , async ( ) => {
3131 const { box, fetchMock } = await createTestBox ( ) ;
32- const tools : Array < { name : string ; input : Record < string , unknown > } > = [ ] ;
32+ const tools : Array < { toolCallId : string ; name : string ; input : Record < string , unknown > } > = [ ] ;
3333
3434 fetchMock . mockResolvedValueOnce (
3535 mockSSEResponse ( [
3636 { event : "run_start" , data : { run_id : "r1" } } ,
37- { event : "tool" , data : { name : "Read" , input : { path : "/test" } } } ,
37+ { event : "tool" , data : { id : "tool-1" , name : "Read" , input : { path : "/test" } } } ,
3838 { event : "done" , data : { } } ,
3939 ] ) ,
4040 ) ;
@@ -45,9 +45,30 @@ describe("box.agent.run", () => {
4545 } ) ;
4646
4747 expect ( tools ) . toHaveLength ( 1 ) ;
48+ expect ( tools [ 0 ] ! . toolCallId ) . toBe ( "tool-1" ) ;
4849 expect ( tools [ 0 ] ! . name ) . toBe ( "Read" ) ;
4950 } ) ;
5051
52+ it ( "calls onToolResult callback" , async ( ) => {
53+ const { box, fetchMock } = await createTestBox ( ) ;
54+ const results : Array < { toolCallId : string ; output : unknown } > = [ ] ;
55+
56+ fetchMock . mockResolvedValueOnce (
57+ mockSSEResponse ( [
58+ { event : "run_start" , data : { run_id : "r1" } } ,
59+ { event : "tool_result" , data : { toolCallId : "tool-1" , output : { ok : true } } } ,
60+ { event : "done" , data : { } } ,
61+ ] ) ,
62+ ) ;
63+
64+ await box . agent . run ( {
65+ prompt : "test" ,
66+ onToolResult : ( result ) => results . push ( result ) ,
67+ } ) ;
68+
69+ expect ( results ) . toEqual ( [ { toolCallId : "tool-1" , output : { ok : true } } ] ) ;
70+ } ) ;
71+
5172 it ( "parses structured output with responseSchema" , async ( ) => {
5273 const { box, fetchMock } = await createTestBox ( ) ;
5374
@@ -437,12 +458,12 @@ describe("box.agent.stream", () => {
437458
438459 it ( "yields tool-call chunks and calls onToolUse" , async ( ) => {
439460 const { box, fetchMock } = await createTestBox ( ) ;
440- const tools : Array < { name : string ; input : Record < string , unknown > } > = [ ] ;
461+ const tools : Array < { toolCallId : string ; name : string ; input : Record < string , unknown > } > = [ ] ;
441462
442463 fetchMock . mockResolvedValueOnce (
443464 mockSSEResponse ( [
444465 { event : "run_start" , data : { run_id : "r1" } } ,
445- { event : "tool" , data : { name : "Write" , input : { path : "/x" } } } ,
466+ { event : "tool" , data : { id : "tool-2" , name : "Write" , input : { path : "/x" } } } ,
446467 { event : "text" , data : { text : "done" } } ,
447468 { event : "done" , data : { } } ,
448469 ] ) ,
@@ -458,15 +479,51 @@ describe("box.agent.stream", () => {
458479 }
459480
460481 expect ( tools ) . toHaveLength ( 1 ) ;
482+ expect ( tools [ 0 ] ! . toolCallId ) . toBe ( "tool-2" ) ;
461483 expect ( tools [ 0 ] ! . name ) . toBe ( "Write" ) ;
462484 const toolChunks = chunks . filter ( ( c ) => c . type === "tool-call" ) ;
463485 expect ( toolChunks ) . toHaveLength ( 1 ) ;
486+ expect ( toolChunks [ 0 ] ) . toEqual ( {
487+ type : "tool-call" ,
488+ toolCallId : "tool-2" ,
489+ toolName : "Write" ,
490+ input : { path : "/x" } ,
491+ } ) ;
464492 const textChunks = chunks . filter (
465493 ( c ) : c is Extract < Chunk , { type : "text-delta" } > => c . type === "text-delta" ,
466494 ) ;
467495 expect ( textChunks . map ( ( c ) => c . text ) ) . toEqual ( [ "done" ] ) ;
468496 } ) ;
469497
498+ it ( "yields tool-result chunks and calls onToolResult" , async ( ) => {
499+ const { box, fetchMock } = await createTestBox ( ) ;
500+ const results : Array < { toolCallId : string ; output : unknown } > = [ ] ;
501+
502+ fetchMock . mockResolvedValueOnce (
503+ mockSSEResponse ( [
504+ { event : "run_start" , data : { run_id : "r1" } } ,
505+ { event : "tool_result" , data : { tool_use_id : "tool-3" , output : "ok" } } ,
506+ { event : "done" , data : { } } ,
507+ ] ) ,
508+ ) ;
509+
510+ const run = await box . agent . stream ( {
511+ prompt : "test" ,
512+ onToolResult : ( result ) => results . push ( result ) ,
513+ } ) ;
514+ const chunks : Chunk [ ] = [ ] ;
515+ for await ( const chunk of run ) {
516+ chunks . push ( chunk ) ;
517+ }
518+
519+ expect ( results ) . toEqual ( [ { toolCallId : "tool-3" , output : "ok" } ] ) ;
520+ expect ( chunks ) . toContainEqual ( {
521+ type : "tool-result" ,
522+ toolCallId : "tool-3" ,
523+ output : "ok" ,
524+ } ) ;
525+ } ) ;
526+
470527 it ( "yields all chunk types in order" , async ( ) => {
471528 const { box, fetchMock } = await createTestBox ( ) ;
472529
@@ -475,7 +532,8 @@ describe("box.agent.stream", () => {
475532 { event : "run_start" , data : { run_id : "r1" } } ,
476533 { event : "text" , data : { text : "Hello " } } ,
477534 { event : "thinking" , data : { text : "trace" } } ,
478- { event : "tool" , data : { name : "Write" , input : { path : "/x" } } } ,
535+ { event : "tool" , data : { toolCallId : "tool-4" , name : "Write" , input : { path : "/x" } } } ,
536+ { event : "tool_result" , data : { tool_use_id : "tool-4" , output : "done" } } ,
479537 {
480538 event : "done" ,
481539 data : { output : "Hello world" , input_tokens : 7 , output_tokens : 9 , session_id : "s1" } ,
@@ -495,6 +553,7 @@ describe("box.agent.stream", () => {
495553 "text-delta" ,
496554 "reasoning" ,
497555 "tool-call" ,
556+ "tool-result" ,
498557 "finish" ,
499558 "stats" ,
500559 ] ) ;
0 commit comments