3030import com .fasterxml .jackson .annotation .JsonProperty ;
3131import com .fasterxml .jackson .annotation .JsonSubTypes ;
3232import com .fasterxml .jackson .annotation .JsonTypeInfo ;
33+ import com .fasterxml .jackson .databind .annotation .JsonDeserialize ;
34+ import com .fasterxml .jackson .databind .annotation .JsonSerialize ;
3335import reactor .core .publisher .Flux ;
3436import reactor .core .publisher .Mono ;
3537
3638import 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 ;
3742import org .springframework .ai .model .ChatModelDescription ;
3843import org .springframework .ai .model .ModelOptionsUtils ;
3944import org .springframework .ai .observation .conventions .AiProvider ;
@@ -717,7 +722,11 @@ public record ContentBlock(
717722
718723 // tool_result response only
719724 @ JsonProperty ("tool_use_id" ) String toolUseId ,
720- @ JsonProperty ("content" ) String content ,
725+
726+ @ JsonSerialize (using = ContentFieldSerializer .class )
727+ @ JsonDeserialize (using = ContentFieldDeserializer .class )
728+ @ JsonProperty ("content" )
729+ Object content ,
721730
722731 // Thinking only
723732 @ JsonProperty ("signature" ) String signature ,
@@ -728,6 +737,15 @@ public record ContentBlock(
728737 ) {
729738 // @formatter:on
730739
740+ @ JsonInclude (Include .NON_NULL )
741+ @ JsonIgnoreProperties (ignoreUnknown = true )
742+ public record WebSearchToolContentBlock (@ JsonProperty ("type" ) String type , @ JsonProperty ("title" ) String title ,
743+ @ JsonProperty ("url" ) String url , @ JsonProperty ("encrypted_content" ) String EncryptedContent ,
744+ @ JsonProperty ("page_age" ) String pageAge ) {
745+
746+ }
747+ // @formatter:on
748+
731749 /**
732750 * Create content block
733751 * @param mediaType The media type of the content.
@@ -813,6 +831,18 @@ public enum Type {
813831 @ JsonProperty ("tool_result" )
814832 TOOL_RESULT ("tool_result" ),
815833
834+ /**
835+ * Server Tool request
836+ */
837+ @ JsonProperty ("server_tool_use" )
838+ SERVER_TOOL_USE ("server_tool_use" ),
839+
840+ /**
841+ * Web search tool result
842+ */
843+ @ JsonProperty ("web_search_tool_result" )
844+ WEB_SEARCH_TOOL_RESULT ("web_search_tool_result" ),
845+
816846 /**
817847 * Text message.
818848 */
@@ -926,22 +956,6 @@ public Source(String url) {
926956 /// CONTENT_BLOCK EVENTS
927957 ///////////////////////////////////////
928958
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-
945959 // CB START EVENT
946960
947961 /**
@@ -987,16 +1001,25 @@ public record ChatCompletionResponse(
9871001 public record Usage (
9881002 // @formatter:off
9891003 @ JsonProperty ("input_tokens" ) Integer inputTokens ,
990- @ JsonProperty ("output_tokens" ) Integer outputTokens ) {
991- // @formatter:off
1004+ @ JsonProperty ("output_tokens" ) Integer outputTokens ,
1005+ @ JsonProperty ("server_tool_use" ) ServerToolUse serverToolUse ) {
1006+ // @formatter:on
1007+ }
1008+
1009+ @ JsonInclude (Include .NON_NULL )
1010+ @ JsonIgnoreProperties (ignoreUnknown = true )
1011+ public record ServerToolUse (
1012+ // @formatter:off
1013+ @ JsonProperty ("web_search_requests" ) Integer webSearchRequests ) {
1014+ // @formatter:on
9921015 }
9931016
994- /// ECB STOP
1017+ /// ECB STOP
9951018
9961019 /**
9971020 * Special event used to aggregate multiple tool use events into a single event with
9981021 * list of aggregated ContentBlockToolUse.
999- */
1022+ */
10001023 public static class ToolUseAggregationEvent implements StreamEvent {
10011024
10021025 private Integer index ;
@@ -1015,17 +1038,17 @@ public EventType type() {
10151038 }
10161039
10171040 /**
1018- * Get tool content blocks.
1019- * @return The tool content blocks.
1020- */
1041+ * Get tool content blocks.
1042+ * @return The tool content blocks.
1043+ */
10211044 public List <ContentBlockStartEvent .ContentBlockToolUse > getToolContentBlocks () {
10221045 return this .toolContentBlocks ;
10231046 }
10241047
10251048 /**
1026- * Check if the event is empty.
1027- * @return True if the event is empty, false otherwise.
1028- */
1049+ * Check if the event is empty.
1050+ * @return True if the event is empty, false otherwise.
1051+ */
10291052 public boolean isEmpty () {
10301053 return (this .index == null || this .id == null || this .name == null
10311054 || !StringUtils .hasText (this .partialJson ));
@@ -1054,7 +1077,8 @@ ToolUseAggregationEvent appendPartialJson(String partialJson) {
10541077 void squashIntoContentBlock () {
10551078 Map <String , Object > map = (StringUtils .hasText (this .partialJson ))
10561079 ? ModelOptionsUtils .jsonToMap (this .partialJson ) : Map .of ();
1057- this .toolContentBlocks .add (new ContentBlockStartEvent .ContentBlockToolUse ("tool_use" , this .id , this .name , map ));
1080+ this .toolContentBlocks
1081+ .add (new ContentBlockStartEvent .ContentBlockToolUse ("tool_use" , this .id , this .name , map ));
10581082 this .index = null ;
10591083 this .id = null ;
10601084 this .name = null ;
@@ -1063,28 +1087,29 @@ void squashIntoContentBlock() {
10631087
10641088 @ Override
10651089 public String toString () {
1066- return "EventToolUseBuilder [index=" + this .index + ", id=" + this .id + ", name=" + this .name + ", partialJson="
1067- + this .partialJson + ", toolUseMap=" + this .toolContentBlocks + "]" ;
1090+ return "EventToolUseBuilder [index=" + this .index + ", id=" + this .id + ", name=" + this .name
1091+ + ", partialJson=" + this .partialJson + ", toolUseMap=" + this .toolContentBlocks + "]" ;
10681092 }
10691093
10701094 }
10711095
1072- ///////////////////////////////////////
1073- /// MESSAGE EVENTS
1074- ///////////////////////////////////////
1096+ ///////////////////////////////////////
1097+ /// MESSAGE EVENTS
1098+ ///////////////////////////////////////
10751099
1076- // MESSAGE START EVENT
1100+ // MESSAGE START EVENT
10771101
10781102 /**
10791103 * Content block start event.
1104+ *
10801105 * @param type The event type.
10811106 * @param index The index of the content block.
10821107 * @param contentBlock The content block body.
1083- */
1108+ */
10841109 @ JsonInclude (Include .NON_NULL )
10851110 @ JsonIgnoreProperties (ignoreUnknown = true )
10861111 public record ContentBlockStartEvent (
1087- // @formatter:off
1112+ // @formatter:off
10881113 @ JsonProperty ("type" ) EventType type ,
10891114 @ JsonProperty ("index" ) Integer index ,
10901115 @ JsonProperty ("content_block" ) ContentBlockBody contentBlock ) implements StreamEvent {
0 commit comments