@@ -1056,6 +1056,92 @@ Use pandas and summarize findings.`.split("\n"),
10561056 expect ( emittedTypes ) . toContain ( "text-delta" ) ;
10571057 expect ( emittedTypes ) . toContain ( "finish" ) ;
10581058 } ) ;
1059+
1060+ it ( "does not lock getter-based teeing fullStream after probe" , async ( ) => {
1061+ const agent = new Agent ( {
1062+ name : "TestAgent" ,
1063+ instructions : "You are a helpful assistant" ,
1064+ model : mockModel as any ,
1065+ } ) ;
1066+
1067+ const streamParts = [
1068+ { type : "start" as const } ,
1069+ { type : "text-start" as const , id : "text-1" } ,
1070+ { type : "text-delta" as const , id : "text-1" , delta : "Hello " } ,
1071+ { type : "text-delta" as const , id : "text-1" , delta : "world" } ,
1072+ { type : "text-end" as const , id : "text-1" } ,
1073+ { type : "finish" as const , finishReason : "stop" , totalUsage : { } } ,
1074+ ] ;
1075+
1076+ class TeeingStreamResult {
1077+ private baseStream : ReadableStream < any > ;
1078+ private readonly cachedText : Promise < string > ;
1079+
1080+ constructor ( parts : ReadonlyArray < any > ) {
1081+ this . baseStream = convertArrayToReadableStream ( [ ...parts ] ) ;
1082+ this . cachedText = this . consumeText ( ) ;
1083+ }
1084+
1085+ private teeStream ( ) : ai . AsyncIterableStream < any > {
1086+ const [ probeStream , passthroughStream ] = this . baseStream . tee ( ) ;
1087+ this . baseStream = passthroughStream ;
1088+ return toAsyncIterableStream ( probeStream ) ;
1089+ }
1090+
1091+ get fullStream ( ) : ai . AsyncIterableStream < any > {
1092+ return this . teeStream ( ) ;
1093+ }
1094+
1095+ get text ( ) : Promise < string > {
1096+ return this . cachedText ;
1097+ }
1098+
1099+ get textStream ( ) : AsyncIterable < string > {
1100+ return ( async function * ( ) {
1101+ yield "Hello world" ;
1102+ } ) ( ) ;
1103+ }
1104+
1105+ readonly usage = Promise . resolve ( {
1106+ inputTokens : 10 ,
1107+ outputTokens : 2 ,
1108+ totalTokens : 12 ,
1109+ } ) ;
1110+ readonly finishReason = Promise . resolve ( "stop" ) ;
1111+ readonly warnings : never [ ] = [ ] ;
1112+ readonly toUIMessageStream = vi . fn ( ) ;
1113+ readonly toUIMessageStreamResponse = vi . fn ( ) ;
1114+ readonly pipeUIMessageStreamToResponse = vi . fn ( ) ;
1115+ readonly pipeTextStreamToResponse = vi . fn ( ) ;
1116+ readonly toTextStreamResponse = vi . fn ( ) ;
1117+ readonly partialOutputStream = undefined ;
1118+
1119+ private async consumeText ( ) : Promise < string > {
1120+ let text = "" ;
1121+ for await ( const part of this . fullStream ) {
1122+ if ( part . type === "text-delta" && typeof part . delta === "string" ) {
1123+ text += part . delta ;
1124+ }
1125+ }
1126+ return text ;
1127+ }
1128+ }
1129+
1130+ const mockStream = new TeeingStreamResult ( streamParts ) ;
1131+ vi . mocked ( ai . streamText ) . mockReturnValue ( mockStream as any ) ;
1132+
1133+ const result = await agent . streamText ( "answer me" ) ;
1134+ const emittedTypes : string [ ] = [ ] ;
1135+
1136+ for await ( const part of result . fullStream as AsyncIterable < { type : string } > ) {
1137+ emittedTypes . push ( part . type ) ;
1138+ }
1139+
1140+ expect ( emittedTypes ) . toContain ( "start" ) ;
1141+ expect ( emittedTypes ) . toContain ( "text-delta" ) ;
1142+ expect ( emittedTypes ) . toContain ( "finish" ) ;
1143+ await expect ( result . text ) . resolves . toBe ( "Hello world" ) ;
1144+ } ) ;
10591145 } ) ;
10601146
10611147 describe ( "Tool Management" , ( ) => {
0 commit comments