@@ -14,6 +14,14 @@ import {
14
14
AIMessageFields ,
15
15
AIMessageChunkFields ,
16
16
AIMessage ,
17
+ StandardContentBlockConverter ,
18
+ StandardImageBlock ,
19
+ StandardTextBlock ,
20
+ StandardFileBlock ,
21
+ DataContentBlock ,
22
+ isDataContentBlock ,
23
+ convertToProviderContentBlock ,
24
+ parseBase64DataUrl ,
17
25
} from "@langchain/core/messages" ;
18
26
import {
19
27
ToolCall ,
@@ -22,13 +30,15 @@ import {
22
30
} from "@langchain/core/messages/tool" ;
23
31
import {
24
32
AnthropicAPIConfig ,
33
+ AnthropicCacheControl ,
25
34
AnthropicContent ,
26
35
AnthropicContentRedactedThinking ,
27
36
AnthropicContentText ,
28
37
AnthropicContentThinking ,
29
38
AnthropicContentToolUse ,
30
39
AnthropicMessage ,
31
40
AnthropicMessageContent ,
41
+ AnthropicMessageContentDocument ,
32
42
AnthropicMessageContentImage ,
33
43
AnthropicMessageContentRedactedThinking ,
34
44
AnthropicMessageContentText ,
@@ -528,21 +538,248 @@ export function getAnthropicAPI(config?: AnthropicAPIConfig): GoogleAIAPI {
528
538
}
529
539
}
530
540
541
+ const anthropicContentConverter : StandardContentBlockConverter < {
542
+ text : AnthropicMessageContentText ;
543
+ image : AnthropicMessageContentImage ;
544
+ file : AnthropicMessageContentDocument ;
545
+ } > = {
546
+ providerName : "anthropic" ,
547
+
548
+ fromStandardTextBlock (
549
+ block : StandardTextBlock
550
+ ) : AnthropicMessageContentText {
551
+ return {
552
+ type : "text" ,
553
+ text : block . text ,
554
+ ...( "cache_control" in ( block . metadata ?? { } )
555
+ ? {
556
+ cache_control : block . metadata !
557
+ . cache_control as AnthropicCacheControl ,
558
+ }
559
+ : { } ) ,
560
+ } ;
561
+ } ,
562
+
563
+ fromStandardImageBlock (
564
+ block : StandardImageBlock
565
+ ) : AnthropicMessageContentImage {
566
+ if ( block . source_type === "url" ) {
567
+ const data = parseBase64DataUrl ( {
568
+ dataUrl : block . url ,
569
+ asTypedArray : false ,
570
+ } ) ;
571
+ if ( data ) {
572
+ return {
573
+ type : "image" ,
574
+ source : {
575
+ type : "base64" ,
576
+ data : data . data ,
577
+ media_type : data . mime_type ,
578
+ } ,
579
+ ...( "cache_control" in ( block . metadata ?? { } )
580
+ ? { cache_control : block . metadata ! . cache_control }
581
+ : { } ) ,
582
+ } as AnthropicMessageContentImage ;
583
+ } else {
584
+ return {
585
+ type : "image" ,
586
+ source : {
587
+ type : "url" ,
588
+ url : block . url ,
589
+ media_type : block . mime_type ?? "" ,
590
+ } ,
591
+ ...( "cache_control" in ( block . metadata ?? { } )
592
+ ? { cache_control : block . metadata ! . cache_control }
593
+ : { } ) ,
594
+ } as AnthropicMessageContentImage ;
595
+ }
596
+ } else {
597
+ if ( block . source_type === "base64" ) {
598
+ return {
599
+ type : "image" ,
600
+ source : {
601
+ type : "base64" ,
602
+ data : block . data ,
603
+ media_type : block . mime_type ?? "" ,
604
+ } ,
605
+ ...( "cache_control" in ( block . metadata ?? { } )
606
+ ? { cache_control : block . metadata ! . cache_control }
607
+ : { } ) ,
608
+ } as AnthropicMessageContentImage ;
609
+ } else {
610
+ throw new Error (
611
+ `Unsupported image source type: ${ block . source_type } `
612
+ ) ;
613
+ }
614
+ }
615
+ } ,
616
+
617
+ fromStandardFileBlock (
618
+ block : StandardFileBlock
619
+ ) : AnthropicMessageContentDocument {
620
+ const mime_type = ( block . mime_type ?? "" ) . split ( ";" ) [ 0 ] ;
621
+
622
+ if ( block . source_type === "url" ) {
623
+ if ( mime_type === "application/pdf" || mime_type === "" ) {
624
+ return {
625
+ type : "document" ,
626
+ source : {
627
+ type : "url" ,
628
+ url : block . url ,
629
+ media_type : block . mime_type ?? "" ,
630
+ } ,
631
+ ...( "cache_control" in ( block . metadata ?? { } )
632
+ ? {
633
+ cache_control : block . metadata !
634
+ . cache_control as AnthropicCacheControl ,
635
+ }
636
+ : { } ) ,
637
+ ...( "citations" in ( block . metadata ?? { } )
638
+ ? {
639
+ citations : block . metadata ! . citations as { enabled ?: boolean } ,
640
+ }
641
+ : { } ) ,
642
+ ...( "context" in ( block . metadata ?? { } )
643
+ ? { context : block . metadata ! . context as string }
644
+ : { } ) ,
645
+ ...( block . metadata ?. title ||
646
+ block . metadata ?. filename ||
647
+ block . metadata ?. name
648
+ ? {
649
+ title : ( block . metadata ?. title ||
650
+ block . metadata ?. filename ||
651
+ block . metadata ?. name ) as string ,
652
+ }
653
+ : { } ) ,
654
+ } ;
655
+ }
656
+ throw new Error (
657
+ `Unsupported file mime type for file url source: ${ block . mime_type } `
658
+ ) ;
659
+ } else if ( block . source_type === "text" ) {
660
+ if ( mime_type === "text/plain" || mime_type === "" ) {
661
+ return {
662
+ type : "document" ,
663
+ source : {
664
+ type : "text" ,
665
+ data : block . text ,
666
+ media_type : block . mime_type ?? "" ,
667
+ } ,
668
+ ...( "cache_control" in ( block . metadata ?? { } )
669
+ ? {
670
+ cache_control : block . metadata !
671
+ . cache_control as AnthropicCacheControl ,
672
+ }
673
+ : { } ) ,
674
+ ...( "citations" in ( block . metadata ?? { } )
675
+ ? {
676
+ citations : block . metadata ! . citations as { enabled ?: boolean } ,
677
+ }
678
+ : { } ) ,
679
+ ...( "context" in ( block . metadata ?? { } )
680
+ ? { context : block . metadata ! . context as string }
681
+ : { } ) ,
682
+ ...( "title" in ( block . metadata ?? { } )
683
+ ? { title : block . metadata ! . title as string }
684
+ : { } ) ,
685
+ } ;
686
+ } else {
687
+ throw new Error (
688
+ `Unsupported file mime type for file text source: ${ block . mime_type } `
689
+ ) ;
690
+ }
691
+ } else if ( block . source_type === "base64" ) {
692
+ if ( mime_type === "application/pdf" || mime_type === "" ) {
693
+ return {
694
+ type : "document" ,
695
+ source : {
696
+ type : "base64" ,
697
+ data : block . data ,
698
+ media_type : "application/pdf" ,
699
+ } ,
700
+ ...( "cache_control" in ( block . metadata ?? { } )
701
+ ? {
702
+ cache_control : block . metadata !
703
+ . cache_control as AnthropicCacheControl ,
704
+ }
705
+ : { } ) ,
706
+ ...( "citations" in ( block . metadata ?? { } )
707
+ ? {
708
+ citations : block . metadata ! . citations as { enabled ?: boolean } ,
709
+ }
710
+ : { } ) ,
711
+ ...( "context" in ( block . metadata ?? { } )
712
+ ? { context : block . metadata ! . context as string }
713
+ : { } ) ,
714
+ ...( "title" in ( block . metadata ?? { } )
715
+ ? { title : block . metadata ! . title as string }
716
+ : { } ) ,
717
+ } ;
718
+ } else if (
719
+ [ "image/jpeg" , "image/png" , "image/gif" , "image/webp" ] . includes (
720
+ mime_type
721
+ )
722
+ ) {
723
+ return {
724
+ type : "document" ,
725
+ source : {
726
+ type : "content" ,
727
+ content : [
728
+ {
729
+ type : "image" ,
730
+ source : {
731
+ type : "base64" ,
732
+ data : block . data ,
733
+ media_type : mime_type as
734
+ | "image/jpeg"
735
+ | "image/png"
736
+ | "image/gif"
737
+ | "image/webp" ,
738
+ } ,
739
+ } ,
740
+ ] ,
741
+ } ,
742
+ ...( "cache_control" in ( block . metadata ?? { } )
743
+ ? {
744
+ cache_control : block . metadata !
745
+ . cache_control as AnthropicCacheControl ,
746
+ }
747
+ : { } ) ,
748
+ ...( "citations" in ( block . metadata ?? { } )
749
+ ? {
750
+ citations : block . metadata ! . citations as { enabled ?: boolean } ,
751
+ }
752
+ : { } ) ,
753
+ ...( "context" in ( block . metadata ?? { } )
754
+ ? { context : block . metadata ! . context as string }
755
+ : { } ) ,
756
+ ...( "title" in ( block . metadata ?? { } )
757
+ ? { title : block . metadata ! . title as string }
758
+ : { } ) ,
759
+ } ;
760
+ } else {
761
+ throw new Error (
762
+ `Unsupported file mime type for file base64 source: ${ block . mime_type } `
763
+ ) ;
764
+ }
765
+ } else {
766
+ throw new Error ( `Unsupported file source type: ${ block . source_type } ` ) ;
767
+ }
768
+ } ,
769
+ } ;
770
+
531
771
function contentToAnthropicContent (
532
- content : MessageContent
772
+ content : MessageContent | DataContentBlock [ ]
533
773
) : AnthropicMessageContent [ ] {
534
- const ret : AnthropicMessageContent [ ] = [ ] ;
535
-
536
774
const ca =
537
775
typeof content === "string" ? [ { type : "text" , text : content } ] : content ;
538
- ca . forEach ( ( complex ) => {
539
- const ac = contentComplexToAnthropicContent ( complex ) ;
540
- if ( ac ) {
541
- ret . push ( ac ) ;
542
- }
543
- } ) ;
544
-
545
- return ret ;
776
+ return ca
777
+ . map ( ( complex ) =>
778
+ isDataContentBlock ( complex )
779
+ ? convertToProviderContentBlock ( complex , anthropicContentConverter )
780
+ : contentComplexToAnthropicContent ( complex )
781
+ )
782
+ . filter ( Boolean ) as AnthropicMessageContent [ ] ;
546
783
}
547
784
548
785
function toolCallToAnthropicContent (
0 commit comments