30
30
import com .fasterxml .jackson .annotation .JsonProperty ;
31
31
import com .fasterxml .jackson .annotation .JsonSubTypes ;
32
32
import com .fasterxml .jackson .annotation .JsonTypeInfo ;
33
+ import com .fasterxml .jackson .databind .annotation .JsonDeserialize ;
34
+ import com .fasterxml .jackson .databind .annotation .JsonSerialize ;
33
35
import reactor .core .publisher .Flux ;
34
36
import reactor .core .publisher .Mono ;
35
37
36
38
import org .springframework .ai .anthropic .api .StreamHelper .ChatCompletionResponseBuilder ;
39
+ import org .springframework .ai .anthropic .api .tool .Tool ;
40
+ import org .springframework .ai .anthropic .util .ContentFieldDeserializer ;
41
+ import org .springframework .ai .anthropic .util .ContentFieldSerializer ;
37
42
import org .springframework .ai .model .ChatModelDescription ;
38
43
import org .springframework .ai .model .ModelOptionsUtils ;
39
44
import org .springframework .ai .observation .conventions .AiProvider ;
@@ -632,7 +637,12 @@ public ChatCompletionRequestBuilder topK(Integer topK) {
632
637
}
633
638
634
639
public ChatCompletionRequestBuilder tools (List <Tool > tools ) {
635
- this .tools = tools ;
640
+ if (this .tools == null ) {
641
+ this .tools = tools ;
642
+ }
643
+ else {
644
+ this .tools .addAll (tools );
645
+ }
636
646
return this ;
637
647
}
638
648
@@ -717,7 +727,11 @@ public record ContentBlock(
717
727
718
728
// tool_result response only
719
729
@ JsonProperty ("tool_use_id" ) String toolUseId ,
720
- @ JsonProperty ("content" ) String content ,
730
+
731
+ @ JsonSerialize (using = ContentFieldSerializer .class )
732
+ @ JsonDeserialize (using = ContentFieldDeserializer .class )
733
+ @ JsonProperty ("content" )
734
+ Object content ,
721
735
722
736
// Thinking only
723
737
@ JsonProperty ("signature" ) String signature ,
@@ -728,6 +742,15 @@ public record ContentBlock(
728
742
) {
729
743
// @formatter:on
730
744
745
+ @ JsonInclude (Include .NON_NULL )
746
+ @ JsonIgnoreProperties (ignoreUnknown = true )
747
+ public record WebSearchToolContentBlock (@ JsonProperty ("type" ) String type , @ JsonProperty ("title" ) String title ,
748
+ @ JsonProperty ("url" ) String url , @ JsonProperty ("encrypted_content" ) String EncryptedContent ,
749
+ @ JsonProperty ("page_age" ) String pageAge ) {
750
+
751
+ }
752
+ // @formatter:on
753
+
731
754
/**
732
755
* Create content block
733
756
* @param mediaType The media type of the content.
@@ -813,6 +836,18 @@ public enum Type {
813
836
@ JsonProperty ("tool_result" )
814
837
TOOL_RESULT ("tool_result" ),
815
838
839
+ /**
840
+ * Server Tool request
841
+ */
842
+ @ JsonProperty ("server_tool_use" )
843
+ SERVER_TOOL_USE ("server_tool_use" ),
844
+
845
+ /**
846
+ * Web search tool result
847
+ */
848
+ @ JsonProperty ("web_search_tool_result" )
849
+ WEB_SEARCH_TOOL_RESULT ("web_search_tool_result" ),
850
+
816
851
/**
817
852
* Text message.
818
853
*/
@@ -926,22 +961,6 @@ public Source(String url) {
926
961
/// CONTENT_BLOCK EVENTS
927
962
///////////////////////////////////////
928
963
929
- /**
930
- * Tool description.
931
- *
932
- * @param name The name of the tool.
933
- * @param description A description of the tool.
934
- * @param inputSchema The input schema of the tool.
935
- */
936
- @ JsonInclude (Include .NON_NULL )
937
- public record Tool (
938
- // @formatter:off
939
- @ JsonProperty ("name" ) String name ,
940
- @ JsonProperty ("description" ) String description ,
941
- @ JsonProperty ("input_schema" ) Map <String , Object > inputSchema ) {
942
- // @formatter:on
943
- }
944
-
945
964
// CB START EVENT
946
965
947
966
/**
@@ -987,16 +1006,25 @@ public record ChatCompletionResponse(
987
1006
public record Usage (
988
1007
// @formatter:off
989
1008
@ JsonProperty ("input_tokens" ) Integer inputTokens ,
990
- @ JsonProperty ("output_tokens" ) Integer outputTokens ) {
991
- // @formatter:off
1009
+ @ JsonProperty ("output_tokens" ) Integer outputTokens ,
1010
+ @ JsonProperty ("server_tool_use" ) ServerToolUse serverToolUse ) {
1011
+ // @formatter:on
1012
+ }
1013
+
1014
+ @ JsonInclude (Include .NON_NULL )
1015
+ @ JsonIgnoreProperties (ignoreUnknown = true )
1016
+ public record ServerToolUse (
1017
+ // @formatter:off
1018
+ @ JsonProperty ("web_search_requests" ) Integer webSearchRequests ) {
1019
+ // @formatter:on
992
1020
}
993
1021
994
- /// ECB STOP
1022
+ /// ECB STOP
995
1023
996
1024
/**
997
1025
* Special event used to aggregate multiple tool use events into a single event with
998
1026
* list of aggregated ContentBlockToolUse.
999
- */
1027
+ */
1000
1028
public static class ToolUseAggregationEvent implements StreamEvent {
1001
1029
1002
1030
private Integer index ;
@@ -1015,17 +1043,17 @@ public EventType type() {
1015
1043
}
1016
1044
1017
1045
/**
1018
- * Get tool content blocks.
1019
- * @return The tool content blocks.
1020
- */
1046
+ * Get tool content blocks.
1047
+ * @return The tool content blocks.
1048
+ */
1021
1049
public List <ContentBlockStartEvent .ContentBlockToolUse > getToolContentBlocks () {
1022
1050
return this .toolContentBlocks ;
1023
1051
}
1024
1052
1025
1053
/**
1026
- * Check if the event is empty.
1027
- * @return True if the event is empty, false otherwise.
1028
- */
1054
+ * Check if the event is empty.
1055
+ * @return True if the event is empty, false otherwise.
1056
+ */
1029
1057
public boolean isEmpty () {
1030
1058
return (this .index == null || this .id == null || this .name == null
1031
1059
|| !StringUtils .hasText (this .partialJson ));
@@ -1054,7 +1082,8 @@ ToolUseAggregationEvent appendPartialJson(String partialJson) {
1054
1082
void squashIntoContentBlock () {
1055
1083
Map <String , Object > map = (StringUtils .hasText (this .partialJson ))
1056
1084
? ModelOptionsUtils .jsonToMap (this .partialJson ) : Map .of ();
1057
- this .toolContentBlocks .add (new ContentBlockStartEvent .ContentBlockToolUse ("tool_use" , this .id , this .name , map ));
1085
+ this .toolContentBlocks
1086
+ .add (new ContentBlockStartEvent .ContentBlockToolUse ("tool_use" , this .id , this .name , map ));
1058
1087
this .index = null ;
1059
1088
this .id = null ;
1060
1089
this .name = null ;
@@ -1063,28 +1092,29 @@ void squashIntoContentBlock() {
1063
1092
1064
1093
@ Override
1065
1094
public String toString () {
1066
- return "EventToolUseBuilder [index=" + this .index + ", id=" + this .id + ", name=" + this .name + ", partialJson="
1067
- + this .partialJson + ", toolUseMap=" + this .toolContentBlocks + "]" ;
1095
+ return "EventToolUseBuilder [index=" + this .index + ", id=" + this .id + ", name=" + this .name
1096
+ + ", partialJson=" + this .partialJson + ", toolUseMap=" + this .toolContentBlocks + "]" ;
1068
1097
}
1069
1098
1070
1099
}
1071
1100
1072
- ///////////////////////////////////////
1073
- /// MESSAGE EVENTS
1074
- ///////////////////////////////////////
1101
+ ///////////////////////////////////////
1102
+ /// MESSAGE EVENTS
1103
+ ///////////////////////////////////////
1075
1104
1076
- // MESSAGE START EVENT
1105
+ // MESSAGE START EVENT
1077
1106
1078
1107
/**
1079
1108
* Content block start event.
1109
+ *
1080
1110
* @param type The event type.
1081
1111
* @param index The index of the content block.
1082
1112
* @param contentBlock The content block body.
1083
- */
1113
+ */
1084
1114
@ JsonInclude (Include .NON_NULL )
1085
1115
@ JsonIgnoreProperties (ignoreUnknown = true )
1086
1116
public record ContentBlockStartEvent (
1087
- // @formatter:off
1117
+ // @formatter:off
1088
1118
@ JsonProperty ("type" ) EventType type ,
1089
1119
@ JsonProperty ("index" ) Integer index ,
1090
1120
@ JsonProperty ("content_block" ) ContentBlockBody contentBlock ) implements StreamEvent {
0 commit comments