@@ -13,14 +13,24 @@ import {
13
13
MessagesResponse ,
14
14
STOP_REASON ,
15
15
} from '../../types/messagesResponse' ;
16
+ import { RawContentBlockDeltaEvent } from '../../types/MessagesStreamResponse' ;
17
+ import {
18
+ ANTHROPIC_CONTENT_BLOCK_START_EVENT ,
19
+ ANTHROPIC_CONTENT_BLOCK_STOP_EVENT ,
20
+ ANTHROPIC_MESSAGE_DELTA_EVENT ,
21
+ ANTHROPIC_MESSAGE_START_EVENT ,
22
+ ANTHROPIC_MESSAGE_STOP_EVENT ,
23
+ } from '../anthropic-base/constants' ;
16
24
import { ErrorResponse , ProviderConfig } from '../types' ;
17
25
import { generateInvalidProviderResponseError } from '../utils' ;
18
26
import { BedrockErrorResponseTransform } from './chatComplete' ;
19
27
import { BedrockErrorResponse } from './embed' ;
20
28
import {
29
+ BedrockChatCompleteStreamChunk ,
21
30
BedrockChatCompletionResponse ,
22
31
BedrockContentItem ,
23
32
BedrockMessagesParams ,
33
+ BedrockStreamState ,
24
34
} from './types' ;
25
35
import {
26
36
transformInferenceConfig ,
@@ -397,3 +407,124 @@ export const BedrockMessagesResponseTransform = (
397
407
398
408
return generateInvalidProviderResponseError ( response , BEDROCK ) ;
399
409
} ;
410
+
411
+ const transformContentBlock = (
412
+ contentBlock : BedrockChatCompleteStreamChunk
413
+ ) : RawContentBlockDeltaEvent | undefined => {
414
+ if ( ! contentBlock . delta || contentBlock . contentBlockIndex === undefined ) {
415
+ return undefined ;
416
+ }
417
+ if ( contentBlock . delta . text ) {
418
+ return {
419
+ type : 'content_block_delta' ,
420
+ index : contentBlock . contentBlockIndex ,
421
+ delta : {
422
+ type : 'text_delta' ,
423
+ text : contentBlock . delta . text ,
424
+ } ,
425
+ } ;
426
+ } else if ( contentBlock . delta . reasoningContent ?. text ) {
427
+ return {
428
+ type : 'content_block_delta' ,
429
+ index : contentBlock . contentBlockIndex ,
430
+ delta : {
431
+ type : 'thinking_delta' ,
432
+ thinking : contentBlock . delta . reasoningContent . text ,
433
+ } ,
434
+ } ;
435
+ } else if ( contentBlock . delta . reasoningContent ?. signature ) {
436
+ return {
437
+ type : 'content_block_delta' ,
438
+ index : contentBlock . contentBlockIndex ,
439
+ delta : {
440
+ type : 'signature_delta' ,
441
+ signature : contentBlock . delta . reasoningContent . signature ,
442
+ } ,
443
+ } ;
444
+ } else if ( contentBlock . delta . toolUse ) {
445
+ return {
446
+ type : 'content_block_delta' ,
447
+ index : contentBlock . contentBlockIndex ,
448
+ delta : {
449
+ type : 'input_json_delta' ,
450
+ partial_json : contentBlock . delta . toolUse . input ,
451
+ } ,
452
+ } ;
453
+ }
454
+ return undefined ;
455
+ } ;
456
+
457
+ export const BedrockConverseMessagesStreamChunkTransform = (
458
+ responseChunk : string ,
459
+ fallbackId : string ,
460
+ streamState : BedrockStreamState ,
461
+ strictOpenAiCompliance : boolean ,
462
+ gatewayRequest : Params
463
+ ) => {
464
+ const parsedChunk : BedrockChatCompleteStreamChunk = JSON . parse ( responseChunk ) ;
465
+ if ( streamState . currentContentBlockIndex === undefined ) {
466
+ streamState . currentContentBlockIndex = - 1 ;
467
+ }
468
+ if ( parsedChunk . stopReason ) {
469
+ streamState . stopReason = parsedChunk . stopReason ;
470
+ }
471
+ // message start event
472
+ if ( parsedChunk . role ) {
473
+ return getMessageStartEvent ( fallbackId , gatewayRequest ) ;
474
+ }
475
+ // content block start and stop events
476
+ if (
477
+ parsedChunk . contentBlockIndex !== undefined &&
478
+ parsedChunk . contentBlockIndex !== streamState . currentContentBlockIndex
479
+ ) {
480
+ let returnChunk = '' ;
481
+ if ( streamState . currentContentBlockIndex !== - 1 ) {
482
+ const previousBlockStopEvent = { ...ANTHROPIC_CONTENT_BLOCK_STOP_EVENT } ;
483
+ previousBlockStopEvent . index = parsedChunk . contentBlockIndex - 1 ;
484
+ returnChunk += `event: content_block_stop\ndata: ${ JSON . stringify ( previousBlockStopEvent ) } \n\n` ;
485
+ }
486
+ streamState . currentContentBlockIndex = parsedChunk . contentBlockIndex ;
487
+ const contentBlockStartEvent = { ...ANTHROPIC_CONTENT_BLOCK_START_EVENT } ;
488
+ contentBlockStartEvent . index = parsedChunk . contentBlockIndex ;
489
+ returnChunk += `event: content_block_start\ndata: ${ JSON . stringify ( contentBlockStartEvent ) } \n\n` ;
490
+ const contentBlockDeltaEvent = transformContentBlock ( parsedChunk ) ;
491
+ if ( contentBlockDeltaEvent ) {
492
+ returnChunk += `event: content_block_delta\ndata: ${ JSON . stringify ( contentBlockDeltaEvent ) } \n\n` ;
493
+ }
494
+ return returnChunk ;
495
+ }
496
+ // content block delta event
497
+ if ( parsedChunk . delta ) {
498
+ const contentBlockDeltaEvent = transformContentBlock ( parsedChunk ) ;
499
+ if ( contentBlockDeltaEvent ) {
500
+ return `event: content_block_delta\ndata: ${ JSON . stringify ( contentBlockDeltaEvent ) } \n\n` ;
501
+ }
502
+ }
503
+ // message delta and message stop events
504
+ if ( parsedChunk . usage ) {
505
+ const messageDeltaEvent = { ...ANTHROPIC_MESSAGE_DELTA_EVENT } ;
506
+ messageDeltaEvent . usage . input_tokens = parsedChunk . usage . inputTokens ;
507
+ messageDeltaEvent . usage . output_tokens = parsedChunk . usage . outputTokens ;
508
+ messageDeltaEvent . usage . cache_read_input_tokens =
509
+ parsedChunk . usage . cacheReadInputTokens ;
510
+ messageDeltaEvent . usage . cache_creation_input_tokens =
511
+ parsedChunk . usage . cacheWriteInputTokens ;
512
+ messageDeltaEvent . delta . stop_reason = streamState . stopReason || '' ;
513
+ const contentBlockStopEvent = { ...ANTHROPIC_CONTENT_BLOCK_STOP_EVENT } ;
514
+ contentBlockStopEvent . index = streamState . currentContentBlockIndex ;
515
+ let returnChunk = `event: content_block_stop\ndata: ${ JSON . stringify ( contentBlockStopEvent ) } \n\n` ;
516
+ returnChunk += `event: message_delta\ndata: ${ JSON . stringify ( messageDeltaEvent ) } \n\n` ;
517
+ returnChunk += `event: message_stop\ndata: ${ JSON . stringify ( ANTHROPIC_MESSAGE_STOP_EVENT ) } \n\n` ;
518
+ return returnChunk ;
519
+ }
520
+ // console.log(JSON.stringify(parsedChunk, null, 2));
521
+ } ;
522
+
523
+ function getMessageStartEvent ( fallbackId : string , gatewayRequest : Params < any > ) {
524
+ const messageStartEvent = { ...ANTHROPIC_MESSAGE_START_EVENT } ;
525
+ messageStartEvent . message . id = fallbackId ;
526
+ messageStartEvent . message . model = gatewayRequest . model as string ;
527
+ // bedrock does not send usage in the beginning of the stream
528
+ delete messageStartEvent . message . usage ;
529
+ return `event: message_start\ndata: ${ JSON . stringify ( messageStartEvent ) } \n\n` ;
530
+ }
0 commit comments