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 ;
@@ -632,7 +637,12 @@ public ChatCompletionRequestBuilder topK(Integer topK) {
632637		}
633638
634639		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+ 			}
636646			return  this ;
637647		}
638648
@@ -717,7 +727,11 @@ public record ContentBlock(
717727
718728		// tool_result response only 
719729		@ 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 ,
721735
722736		// Thinking only 
723737		@ JsonProperty ("signature" ) String  signature ,
@@ -728,6 +742,15 @@ public record ContentBlock(
728742		) {
729743		// @formatter:on 
730744
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+ 
731754		/** 
732755		 * Create content block 
733756		 * @param mediaType The media type of the content. 
@@ -813,6 +836,18 @@ public enum Type {
813836			@ JsonProperty ("tool_result" )
814837			TOOL_RESULT ("tool_result" ),
815838
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+ 
816851			/** 
817852			 * Text message. 
818853			 */ 
@@ -926,22 +961,6 @@ public Source(String url) {
926961	/// CONTENT_BLOCK EVENTS 
927962	/////////////////////////////////////// 
928963
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- 
945964	// CB START EVENT 
946965
947966	/** 
@@ -987,16 +1006,25 @@ public record ChatCompletionResponse(
9871006	public  record  Usage (
9881007	// @formatter:off 
9891008		@ 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 
9921020	}
9931021
994- 	  /// ECB STOP 
1022+ 	/// ECB STOP 
9951023
9961024	/** 
9971025	 * Special event used to aggregate multiple tool use events into a single event with 
9981026	 * list of aggregated ContentBlockToolUse. 
999- 	*/ 
1027+ 	  */ 
10001028	public  static  class  ToolUseAggregationEvent  implements  StreamEvent  {
10011029
10021030		private  Integer  index ;
@@ -1015,17 +1043,17 @@ public EventType type() {
10151043		}
10161044
10171045		/** 
1018- 		   * Get tool content blocks. 
1019- 		   * @return The tool content blocks. 
1020- 		*/ 
1046+ 		 * Get tool content blocks. 
1047+ 		 * @return The tool content blocks. 
1048+ 		  */ 
10211049		public  List <ContentBlockStartEvent .ContentBlockToolUse > getToolContentBlocks () {
10221050			return  this .toolContentBlocks ;
10231051		}
10241052
10251053		/** 
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+ 		  */ 
10291057		public  boolean  isEmpty () {
10301058			return  (this .index  == null  || this .id  == null  || this .name  == null 
10311059					|| !StringUtils .hasText (this .partialJson ));
@@ -1054,7 +1082,8 @@ ToolUseAggregationEvent appendPartialJson(String partialJson) {
10541082		void  squashIntoContentBlock () {
10551083			Map <String , Object > map  = (StringUtils .hasText (this .partialJson ))
10561084					? 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 ));
10581087			this .index  = null ;
10591088			this .id  = null ;
10601089			this .name  = null ;
@@ -1063,28 +1092,29 @@ void squashIntoContentBlock() {
10631092
10641093		@ Override 
10651094		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  + "]" ;
10681097		}
10691098
10701099	}
10711100
1072- 	  /////////////////////////////////////// 
1073- 	  /// MESSAGE EVENTS 
1074- 	  /////////////////////////////////////// 
1101+ 	/////////////////////////////////////// 
1102+ 	/// MESSAGE EVENTS 
1103+ 	/////////////////////////////////////// 
10751104
1076- 	  // MESSAGE START EVENT 
1105+ 	// MESSAGE START EVENT 
10771106
10781107	/** 
10791108	 * Content block start event. 
1109+ 	 * 
10801110	 * @param type The event type. 
10811111	 * @param index The index of the content block. 
10821112	 * @param contentBlock The content block body. 
1083- 	*/ 
1113+ 	  */ 
10841114	@ JsonInclude (Include .NON_NULL )
10851115	@ JsonIgnoreProperties (ignoreUnknown  = true )
10861116	public  record  ContentBlockStartEvent (
1087- 			 // @formatter:off 
1117+ 	// @formatter:off 
10881118		@ JsonProperty ("type" ) EventType  type ,
10891119		@ JsonProperty ("index" ) Integer  index ,
10901120		@ JsonProperty ("content_block" ) ContentBlockBody  contentBlock ) implements  StreamEvent  {
0 commit comments