11import { describe , expect , test } from "bun:test" ;
2+ import { z } from "zod" ;
3+
4+ import type { AssistantMessage } from "@/foundation" ;
5+ import { Model } from "@/foundation/models/model" ;
6+ import type { ModelProvider , ModelProviderInvokeParams } from "@/foundation/models/model-provider" ;
7+
28import { Agent } from "../agent" ;
39import type { AgentProgressThinkingEvent } from "../agent-event" ;
4- import { Model } from "@/foundation/models/model" ;
5- import type {
6- ModelProvider ,
7- ModelProviderInvokeParams ,
8- } from "@/foundation/models/model-provider" ;
9- import type { AssistantMessage } from "@/foundation" ;
10- import { z } from "zod" ;
1110
1211function createTextStreamingProvider ( ) : ModelProvider {
1312 const finalMessage : AssistantMessage = {
@@ -16,7 +15,9 @@ function createTextStreamingProvider(): ModelProvider {
1615 } ;
1716
1817 return {
18+ // eslint-disable-next-line no-unused-vars
1919 invoke : async ( _params : ModelProviderInvokeParams ) => finalMessage ,
20+ // eslint-disable-next-line no-unused-vars
2021 async * stream ( _params : ModelProviderInvokeParams ) {
2122 const snapshots : AssistantMessage [ ] = [
2223 {
@@ -63,7 +64,9 @@ function createToolStreamingProvider(): ModelProvider {
6364 } ;
6465
6566 return {
67+ // eslint-disable-next-line no-unused-vars
6668 invoke : async ( _params : ModelProviderInvokeParams ) => toolMessage ,
69+ // eslint-disable-next-line no-unused-vars
6770 async * stream ( _params : ModelProviderInvokeParams ) {
6871 callCount ++ ;
6972 if ( callCount === 1 ) {
@@ -82,7 +85,6 @@ function createToolStreamingProvider(): ModelProvider {
8285 } ;
8386 yield toolMessage ;
8487 } else {
85- // Second call: return a text-only message to end the loop
8688 yield doneMessage ;
8789 }
8890 } ,
@@ -95,28 +97,26 @@ describe("Agent streaming progress events", () => {
9597 const model = new Model ( "test-model" , provider ) ;
9698 const agent = new Agent ( { model, prompt : "You are a test assistant." , tools : [ ] } ) ;
9799
98- const events : any [ ] = [ ] ;
100+ const events : AgentProgressThinkingEvent [ ] = [ ] ;
99101 for await ( const event of agent . stream ( {
100102 role : "user" ,
101103 content : [ { type : "text" , text : "Hi" } ] ,
102104 } ) ) {
103- events . push ( event ) ;
105+ if ( event . type === "progress" && event . subtype === "thinking" ) {
106+ events . push ( event ) ;
107+ }
104108 }
105109
106- const thinkingEvents = events . filter (
107- ( e ) => e . type === "progress" && e . subtype === "thinking" ,
108- ) as AgentProgressThinkingEvent [ ] ;
110+ expect ( events . length ) . toBe ( 2 ) ;
109111
110- expect ( thinkingEvents . length ) . toBe ( 2 ) ;
111-
112- expect ( thinkingEvents [ 0 ] ) . toMatchObject ( {
112+ expect ( events [ 0 ] ) . toMatchObject ( {
113113 type : "progress" ,
114114 subtype : "thinking" ,
115115 text : "Hello" ,
116116 delta : "Hello" ,
117117 } ) ;
118118
119- expect ( thinkingEvents [ 1 ] ) . toMatchObject ( {
119+ expect ( events [ 1 ] ) . toMatchObject ( {
120120 type : "progress" ,
121121 subtype : "thinking" ,
122122 text : "Hello, world" ,
@@ -129,23 +129,24 @@ describe("Agent streaming progress events", () => {
129129 const model = new Model ( "test-model" , provider ) ;
130130 const agent = new Agent ( { model, prompt : "You are a test assistant." , tools : [ ] } ) ;
131131
132- const events : any [ ] = [ ] ;
132+ let finalMessage : AssistantMessage | null = null ;
133133 for await ( const event of agent . stream ( {
134134 role : "user" ,
135135 content : [ { type : "text" , text : "Hi" } ] ,
136136 } ) ) {
137- events . push ( event ) ;
137+ if ( event . type === "message" && event . message . role === "assistant" ) {
138+ finalMessage = event . message as AssistantMessage ;
139+ }
138140 }
139141
140- const messageEvent = events . find ( ( e ) => e . type === "message" ) ;
141- expect ( messageEvent ) . toBeDefined ( ) ;
142- expect ( messageEvent . message . role ) . toBe ( "assistant" ) ;
142+ expect ( finalMessage ) . toBeDefined ( ) ;
143+ expect ( finalMessage ! . role ) . toBe ( "assistant" ) ;
143144
144- const textBlock = messageEvent . message . content . find (
145- ( block : any ) => block . type === "text" ,
145+ const textBlock = finalMessage ! . content . find (
146+ ( block ) => block . type === "text" ,
146147 ) ;
147148 expect ( textBlock ) . toBeDefined ( ) ;
148- expect ( textBlock . text ) . toBe ( "Hello, world!" ) ;
149+ expect ( ( textBlock as { text : string } ) . text ) . toBe ( "Hello, world!" ) ;
149150 } ) ;
150151
151152 test ( "yields tool progress events without text fields" , async ( ) => {
@@ -161,18 +162,16 @@ describe("Agent streaming progress events", () => {
161162
162163 const agent = new Agent ( { model, prompt : "You are a test assistant." , tools : [ bashTool ] } ) ;
163164
164- const events : any [ ] = [ ] ;
165+ const toolProgressEvents : { name ?: string ; text ?: string ; delta ?: string } [ ] = [ ] ;
165166 for await ( const event of agent . stream ( {
166167 role : "user" ,
167168 content : [ { type : "text" , text : "Hi" } ] ,
168169 } ) ) {
169- events . push ( event ) ;
170+ if ( event . type === "progress" && event . subtype === "tool" ) {
171+ toolProgressEvents . push ( event as unknown as { name ?: string ; text ?: string ; delta ?: string } ) ;
172+ }
170173 }
171174
172- const toolProgressEvents = events . filter (
173- ( e ) => e . type === "progress" && e . subtype === "tool" ,
174- ) ;
175-
176175 expect ( toolProgressEvents . length ) . toBeGreaterThanOrEqual ( 1 ) ;
177176
178177 for ( const toolEvent of toolProgressEvents ) {
0 commit comments