@@ -823,6 +823,88 @@ void describe('Bedrock converse adapter', () => {
823
823
} ) ;
824
824
} ) ;
825
825
826
+ void it ( 'handles tool use with empty input when streaming' , async ( ) => {
827
+ const toolOutput : ToolResultContentBlock = {
828
+ text : 'additionalToolOutput' ,
829
+ } ;
830
+ const toolExecuteMock = mock . fn <
831
+ ( input : unknown ) => Promise < ToolResultContentBlock >
832
+ > ( ( ) => Promise . resolve ( toolOutput ) ) ;
833
+ const tool : ExecutableTool = {
834
+ name : 'toolId' ,
835
+ description : 'tool description' ,
836
+ inputSchema : {
837
+ json : { } ,
838
+ } ,
839
+ execute : toolExecuteMock ,
840
+ } ;
841
+
842
+ const event : ConversationTurnEvent = {
843
+ ...commonEvent ,
844
+ } ;
845
+
846
+ const bedrockClient = new BedrockRuntimeClient ( ) ;
847
+ const bedrockResponseQueue : Array <
848
+ ConverseCommandOutput | ConverseStreamCommandOutput
849
+ > = [ ] ;
850
+ const toolUse1 = {
851
+ toolUseId : randomUUID ( ) . toString ( ) ,
852
+ name : tool . name ,
853
+ input : undefined ,
854
+ } ;
855
+ const toolUse2 = {
856
+ toolUseId : randomUUID ( ) . toString ( ) ,
857
+ name : tool . name ,
858
+ input : '' ,
859
+ } ;
860
+ const toolUseBedrockResponse = mockBedrockResponse (
861
+ [
862
+ {
863
+ toolUse : toolUse1 ,
864
+ } ,
865
+ {
866
+ toolUse : toolUse2 ,
867
+ } ,
868
+ ] ,
869
+ true
870
+ ) ;
871
+ bedrockResponseQueue . push ( toolUseBedrockResponse ) ;
872
+ const content = [
873
+ {
874
+ text : 'finalResponse' ,
875
+ } ,
876
+ ] ;
877
+ const finalBedrockResponse = mockBedrockResponse ( content , true ) ;
878
+ bedrockResponseQueue . push ( finalBedrockResponse ) ;
879
+
880
+ mock . method ( bedrockClient , 'send' , ( ) =>
881
+ Promise . resolve ( bedrockResponseQueue . shift ( ) )
882
+ ) ;
883
+
884
+ const adapter = new BedrockConverseAdapter (
885
+ event ,
886
+ [ tool ] ,
887
+ bedrockClient ,
888
+ undefined ,
889
+ messageHistoryRetriever
890
+ ) ;
891
+
892
+ const chunks : Array < StreamingResponseChunk > = await askBedrockWithStreaming (
893
+ adapter
894
+ ) ;
895
+ const responseText = chunks . reduce ( ( acc , next ) => {
896
+ if ( next . contentBlockText ) {
897
+ acc += next . contentBlockText ;
898
+ }
899
+ return acc ;
900
+ } , '' ) ;
901
+ assert . strictEqual ( responseText , 'finalResponse' ) ;
902
+
903
+ assert . strictEqual ( toolExecuteMock . mock . calls . length , 2 ) ;
904
+ assert . strictEqual ( toolExecuteMock . mock . calls [ 0 ] . arguments [ 0 ] , undefined ) ;
905
+ assert . strictEqual ( toolExecuteMock . mock . calls [ 1 ] . arguments [ 0 ] , undefined ) ;
906
+ } ) ;
907
+
826
908
void it ( 'throws if tool is duplicated' , ( ) => {
827
909
assert . throws (
828
910
( ) =>
@@ -1007,19 +1089,21 @@ const mockConverseStreamCommandOutput = (
1007
1089
} ,
1008
1090
} ,
1009
1091
} ) ;
1010
- const input = JSON . stringify ( block . toolUse . input ) ;
1092
+ const input = block . toolUse . input
1093
+ ? JSON . stringify ( block . toolUse . input )
1094
+ : undefined ;
1011
1095
streamItems . push ( {
1012
1096
contentBlockDelta : {
1013
1097
contentBlockIndex : i ,
1014
1098
delta : {
1015
1099
toolUse : {
1016
1100
// simulate chunked input
1017
- input : input . substring ( 0 , 1 ) ,
1101
+ input : input ? .substring ( 0 , 1 ) ,
1018
1102
} ,
1019
1103
} ,
1020
1104
} ,
1021
1105
} ) ;
1022
- if ( input . length > 1 ) {
1106
+ if ( input && input . length > 1 ) {
1023
1107
streamItems . push ( {
1024
1108
contentBlockDelta : {
1025
1109
contentBlockIndex : i ,
0 commit comments