@@ -7,13 +7,21 @@ import {
77import Bedrock from "./Bedrock.js" ;
88
99// Mock AWS SDK
10+ const mockSend = jest . fn ( ) ;
11+ const mockMiddlewareStackAdd = jest . fn ( ) ;
12+
1013jest . mock ( "@aws-sdk/client-bedrock-runtime" , ( ) => ( {
1114 BedrockRuntimeClient : jest . fn ( ) . mockImplementation ( ( ) => ( {
12- send : jest . fn ( ) ,
13- middlewareStack : { add : jest . fn ( ) } ,
15+ send : mockSend ,
16+ middlewareStack : { add : mockMiddlewareStackAdd } ,
1417 } ) ) ,
1518 ConverseStreamCommand : jest . fn ( ) ,
19+ ConverseCommand : jest . fn ( ) ,
1620 InvokeModelCommand : jest . fn ( ) ,
21+ ConversationRole : {
22+ USER : "user" ,
23+ ASSISTANT : "assistant" ,
24+ } ,
1725} ) ) ;
1826
1927// Mock credential provider
@@ -90,6 +98,8 @@ class TestBedrock extends Bedrock {
9098describe ( "Bedrock" , ( ) => {
9199 beforeEach ( ( ) => {
92100 jest . clearAllMocks ( ) ;
101+ mockSend . mockReset ( ) ;
102+ mockMiddlewareStackAdd . mockReset ( ) ;
93103 } ) ;
94104
95105 describe ( "constructor" , ( ) => {
@@ -304,6 +314,119 @@ describe("Bedrock", () => {
304314 } ) ;
305315 } ) ;
306316
317+ describe ( "streaming vs non-streaming behavior" , ( ) => {
318+ class TestableStreamingBedrock extends Bedrock {
319+ public streamingMethodCalled = false ;
320+ public nonStreamingMethodCalled = false ;
321+
322+ protected async * _streamChatStreaming (
323+ messages : ChatMessage [ ] ,
324+ signal : AbortSignal ,
325+ options : CompletionOptions ,
326+ ) : AsyncGenerator < ChatMessage > {
327+ this . streamingMethodCalled = true ;
328+ yield { role : "assistant" , content : "Streaming response" } ;
329+ }
330+
331+ protected async * _streamChatNonStreaming (
332+ messages : ChatMessage [ ] ,
333+ signal : AbortSignal ,
334+ options : CompletionOptions ,
335+ ) : AsyncGenerator < ChatMessage > {
336+ this . nonStreamingMethodCalled = true ;
337+ yield { role : "assistant" , content : "Non-streaming response" } ;
338+ }
339+ }
340+
341+ let bedrock : TestableStreamingBedrock ;
342+ const mockAbortSignal = new AbortController ( ) . signal ;
343+
344+ beforeEach ( ( ) => {
345+ bedrock = new TestableStreamingBedrock ( {
346+ apiKey : "test-key" ,
347+ model : "anthropic.claude-3-sonnet-20240229-v1:0" ,
348+ region : "us-east-1" ,
349+ } ) ;
350+ } ) ;
351+
352+ it ( "should use streaming method when stream is not false" , async ( ) => {
353+ const messages : ChatMessage [ ] = [
354+ { role : "user" , content : "Hello" } as UserChatMessage ,
355+ ] ;
356+
357+ const options : CompletionOptions = {
358+ model : "anthropic.claude-3-sonnet-20240229-v1:0" ,
359+ stream : true , // Explicitly set streaming
360+ } ;
361+
362+ const results = [ ] ;
363+ for await ( const message of bedrock [ "_streamChat" ] (
364+ messages ,
365+ mockAbortSignal ,
366+ options ,
367+ ) ) {
368+ results . push ( message ) ;
369+ }
370+
371+ expect ( bedrock . streamingMethodCalled ) . toBe ( true ) ;
372+ expect ( bedrock . nonStreamingMethodCalled ) . toBe ( false ) ;
373+ expect ( results ) . toEqual ( [
374+ { role : "assistant" , content : "Streaming response" } ,
375+ ] ) ;
376+ } ) ;
377+
378+ it ( "should use non-streaming method when stream is false" , async ( ) => {
379+ const messages : ChatMessage [ ] = [
380+ { role : "user" , content : "Hello" } as UserChatMessage ,
381+ ] ;
382+
383+ const options : CompletionOptions = {
384+ model : "anthropic.claude-3-sonnet-20240229-v1:0" ,
385+ stream : false , // Explicitly set non-streaming
386+ } ;
387+
388+ const results = [ ] ;
389+ for await ( const message of bedrock [ "_streamChat" ] (
390+ messages ,
391+ mockAbortSignal ,
392+ options ,
393+ ) ) {
394+ results . push ( message ) ;
395+ }
396+
397+ expect ( bedrock . streamingMethodCalled ) . toBe ( false ) ;
398+ expect ( bedrock . nonStreamingMethodCalled ) . toBe ( true ) ;
399+ expect ( results ) . toEqual ( [
400+ { role : "assistant" , content : "Non-streaming response" } ,
401+ ] ) ;
402+ } ) ;
403+
404+ it ( "should default to streaming method when stream option is undefined" , async ( ) => {
405+ const messages : ChatMessage [ ] = [
406+ { role : "user" , content : "Hello" } as UserChatMessage ,
407+ ] ;
408+
409+ const options : CompletionOptions = {
410+ model : "anthropic.claude-3-sonnet-20240229-v1:0" ,
411+ // stream option is undefined, should default to streaming
412+ } ;
413+
414+ const results = [ ] ;
415+ for await ( const message of bedrock [ "_streamChat" ] (
416+ messages ,
417+ mockAbortSignal ,
418+ options ,
419+ ) ) {
420+ results . push ( message ) ;
421+ }
422+
423+ expect ( bedrock . streamingMethodCalled ) . toBe ( true ) ;
424+ expect ( bedrock . nonStreamingMethodCalled ) . toBe ( false ) ;
425+ } ) ;
426+ } ) ;
427+
428+
429+
307430 describe ( "message conversion" , ( ) => {
308431 let bedrock : TestBedrock ;
309432
0 commit comments