@@ -746,302 +746,4 @@ describe("AnthropicHandler", () => {
746746 } )
747747 } )
748748 } )
749-
750- describe ( "extended thinking with signature capture" , ( ) => {
751- const systemPrompt = "You are a helpful assistant."
752- const messages : Anthropic . Messages . MessageParam [ ] = [
753- {
754- role : "user" ,
755- content : [ { type : "text" as const , text : "Think about this carefully" } ] ,
756- } ,
757- ]
758-
759- it ( "should capture signature_delta and make it available via getThoughtSignature()" , async ( ) => {
760- mockCreate . mockImplementationOnce ( async ( ) => ( {
761- async * [ Symbol . asyncIterator ] ( ) {
762- yield {
763- type : "message_start" ,
764- message : {
765- usage : {
766- input_tokens : 100 ,
767- output_tokens : 50 ,
768- } ,
769- } ,
770- }
771- yield {
772- type : "content_block_start" ,
773- index : 0 ,
774- content_block : {
775- type : "thinking" ,
776- thinking : "Let me think..." ,
777- } ,
778- }
779- yield {
780- type : "content_block_delta" ,
781- index : 0 ,
782- delta : {
783- type : "thinking_delta" ,
784- thinking : " about this carefully" ,
785- } ,
786- }
787- yield {
788- type : "content_block_delta" ,
789- index : 0 ,
790- delta : {
791- type : "signature_delta" ,
792- signature : "test_signature_123" ,
793- } ,
794- }
795- yield {
796- type : "content_block_stop" ,
797- index : 0 ,
798- }
799- yield {
800- type : "content_block_start" ,
801- index : 1 ,
802- content_block : {
803- type : "text" ,
804- text : "Here is my response" ,
805- } ,
806- }
807- yield {
808- type : "content_block_stop" ,
809- index : 1 ,
810- }
811- } ,
812- } ) )
813-
814- const stream = handler . createMessage ( systemPrompt , messages , {
815- taskId : "test-task" ,
816- } )
817-
818- const chunks : any [ ] = [ ]
819- for await ( const chunk of stream ) {
820- chunks . push ( chunk )
821- }
822-
823- // Verify reasoning chunks were emitted
824- const reasoningChunks = chunks . filter ( ( chunk ) => chunk . type === "reasoning" )
825- expect ( reasoningChunks ) . toHaveLength ( 2 )
826- expect ( reasoningChunks [ 0 ] . text ) . toBe ( "Let me think..." )
827- expect ( reasoningChunks [ 1 ] . text ) . toBe ( " about this carefully" )
828-
829- // Verify thinking_complete chunk was emitted with signature
830- const thinkingCompleteChunk = chunks . find ( ( chunk ) => chunk . type === "thinking_complete" )
831- expect ( thinkingCompleteChunk ) . toBeDefined ( )
832- expect ( thinkingCompleteChunk . signature ) . toBe ( "test_signature_123" )
833-
834- // Verify getThoughtSignature() returns the captured signature
835- expect ( handler . getThoughtSignature ( ) ) . toBe ( "test_signature_123" )
836- } )
837-
838- it ( "should reset signature for each new request" , async ( ) => {
839- // First request with signature
840- mockCreate . mockImplementationOnce ( async ( ) => ( {
841- async * [ Symbol . asyncIterator ] ( ) {
842- yield {
843- type : "message_start" ,
844- message : { usage : { input_tokens : 100 , output_tokens : 50 } } ,
845- }
846- yield {
847- type : "content_block_start" ,
848- index : 0 ,
849- content_block : { type : "thinking" , thinking : "First thinking" } ,
850- }
851- yield {
852- type : "content_block_delta" ,
853- index : 0 ,
854- delta : { type : "signature_delta" , signature : "first_signature" } ,
855- }
856- yield { type : "content_block_stop" , index : 0 }
857- } ,
858- } ) )
859-
860- const stream1 = handler . createMessage ( systemPrompt , messages , { taskId : "test-task-1" } )
861- for await ( const _chunk of stream1 ) {
862- // consume
863- }
864- expect ( handler . getThoughtSignature ( ) ) . toBe ( "first_signature" )
865-
866- // Second request without signature
867- mockCreate . mockImplementationOnce ( async ( ) => ( {
868- async * [ Symbol . asyncIterator ] ( ) {
869- yield {
870- type : "message_start" ,
871- message : { usage : { input_tokens : 100 , output_tokens : 50 } } ,
872- }
873- yield {
874- type : "content_block_start" ,
875- index : 0 ,
876- content_block : { type : "text" , text : "Just text, no thinking" } ,
877- }
878- yield { type : "content_block_stop" , index : 0 }
879- } ,
880- } ) )
881-
882- const stream2 = handler . createMessage ( systemPrompt , messages , { taskId : "test-task-2" } )
883- for await ( const _chunk of stream2 ) {
884- // consume
885- }
886-
887- // Signature should be reset (undefined) for the new request
888- expect ( handler . getThoughtSignature ( ) ) . toBeUndefined ( )
889- } )
890-
891- it ( "should accumulate signature_delta chunks (incremental signature)" , async ( ) => {
892- mockCreate . mockImplementationOnce ( async ( ) => ( {
893- async * [ Symbol . asyncIterator ] ( ) {
894- yield {
895- type : "message_start" ,
896- message : { usage : { input_tokens : 100 , output_tokens : 50 } } ,
897- }
898- yield {
899- type : "content_block_start" ,
900- index : 0 ,
901- content_block : { type : "thinking" , thinking : "Thinking..." } ,
902- }
903- yield {
904- type : "content_block_delta" ,
905- index : 0 ,
906- delta : { type : "signature_delta" , signature : "sig_part1" } ,
907- }
908- yield {
909- type : "content_block_delta" ,
910- index : 0 ,
911- delta : { type : "signature_delta" , signature : "_part2" } ,
912- }
913- yield {
914- type : "content_block_delta" ,
915- index : 0 ,
916- delta : { type : "signature_delta" , signature : "_part3" } ,
917- }
918- yield { type : "content_block_stop" , index : 0 }
919- } ,
920- } ) )
921-
922- const stream = handler . createMessage ( systemPrompt , messages , { taskId : "test-task" } )
923-
924- const chunks : any [ ] = [ ]
925- for await ( const chunk of stream ) {
926- chunks . push ( chunk )
927- }
928-
929- // Verify the accumulated signature
930- expect ( handler . getThoughtSignature ( ) ) . toBe ( "sig_part1_part2_part3" )
931-
932- // Verify thinking_complete has the accumulated signature
933- const thinkingCompleteChunk = chunks . find ( ( chunk ) => chunk . type === "thinking_complete" )
934- expect ( thinkingCompleteChunk ?. signature ) . toBe ( "sig_part1_part2_part3" )
935- } )
936-
937- it ( "should not emit thinking_complete if no signature is captured" , async ( ) => {
938- mockCreate . mockImplementationOnce ( async ( ) => ( {
939- async * [ Symbol . asyncIterator ] ( ) {
940- yield {
941- type : "message_start" ,
942- message : { usage : { input_tokens : 100 , output_tokens : 50 } } ,
943- }
944- yield {
945- type : "content_block_start" ,
946- index : 0 ,
947- content_block : { type : "thinking" , thinking : "Thinking without signature" } ,
948- }
949- yield {
950- type : "content_block_delta" ,
951- index : 0 ,
952- delta : { type : "thinking_delta" , thinking : "More thinking" } ,
953- }
954- // No signature_delta event
955- yield { type : "content_block_stop" , index : 0 }
956- } ,
957- } ) )
958-
959- const stream = handler . createMessage ( systemPrompt , messages , { taskId : "test-task" } )
960-
961- const chunks : any [ ] = [ ]
962- for await ( const chunk of stream ) {
963- chunks . push ( chunk )
964- }
965-
966- // Verify thinking_complete was NOT emitted (no signature)
967- const thinkingCompleteChunk = chunks . find ( ( chunk ) => chunk . type === "thinking_complete" )
968- expect ( thinkingCompleteChunk ) . toBeUndefined ( )
969-
970- // Verify getThoughtSignature() returns undefined
971- expect ( handler . getThoughtSignature ( ) ) . toBeUndefined ( )
972- } )
973-
974- it ( "should handle interleaved thinking with tool use" , async ( ) => {
975- mockCreate . mockImplementationOnce ( async ( ) => ( {
976- async * [ Symbol . asyncIterator ] ( ) {
977- yield {
978- type : "message_start" ,
979- message : { usage : { input_tokens : 100 , output_tokens : 50 } } ,
980- }
981- // First: thinking block
982- yield {
983- type : "content_block_start" ,
984- index : 0 ,
985- content_block : { type : "thinking" , thinking : "Let me think about what tool to use" } ,
986- }
987- yield {
988- type : "content_block_delta" ,
989- index : 0 ,
990- delta : { type : "signature_delta" , signature : "thinking_signature_abc" } ,
991- }
992- yield { type : "content_block_stop" , index : 0 }
993- // Second: tool use block
994- yield {
995- type : "content_block_start" ,
996- index : 1 ,
997- content_block : {
998- type : "tool_use" ,
999- id : "toolu_456" ,
1000- name : "get_weather" ,
1001- } ,
1002- }
1003- yield {
1004- type : "content_block_delta" ,
1005- index : 1 ,
1006- delta : {
1007- type : "input_json_delta" ,
1008- partial_json : '{"location":"Paris"}' ,
1009- } ,
1010- }
1011- yield { type : "content_block_stop" , index : 1 }
1012- } ,
1013- } ) )
1014-
1015- const stream = handler . createMessage ( systemPrompt , messages , {
1016- taskId : "test-task" ,
1017- tools : [
1018- {
1019- type : "function" as const ,
1020- function : {
1021- name : "get_weather" ,
1022- description : "Get weather" ,
1023- parameters : { type : "object" , properties : { location : { type : "string" } } } ,
1024- } ,
1025- } ,
1026- ] ,
1027- } )
1028-
1029- const chunks : any [ ] = [ ]
1030- for await ( const chunk of stream ) {
1031- chunks . push ( chunk )
1032- }
1033-
1034- // Verify thinking_complete was emitted for the thinking block
1035- const thinkingCompleteChunk = chunks . find ( ( chunk ) => chunk . type === "thinking_complete" )
1036- expect ( thinkingCompleteChunk ) . toBeDefined ( )
1037- expect ( thinkingCompleteChunk . signature ) . toBe ( "thinking_signature_abc" )
1038-
1039- // Verify signature is available for tool use continuation
1040- expect ( handler . getThoughtSignature ( ) ) . toBe ( "thinking_signature_abc" )
1041-
1042- // Verify tool_call_partial was also emitted
1043- const toolChunks = chunks . filter ( ( chunk ) => chunk . type === "tool_call_partial" )
1044- expect ( toolChunks . length ) . toBeGreaterThan ( 0 )
1045- } )
1046- } )
1047749} )
0 commit comments