diff --git a/README.md b/README.md
index 46228b0ca8b..b70d46c1b3f 100644
--- a/README.md
+++ b/README.md
@@ -94,6 +94,12 @@ To check javadocs using the [javadoc:javadoc](https://maven.apache.org/plugins/m
 ./mvnw javadoc:javadoc -Pjavadoc
 ```
 
+To build with checkstyles enabled.
+Checkstyles are currently disabled, but you can enable them by doing the following:
+```shell
+./mvnw clean package -DskipTests -Ddisable.checks=false
+```
+
 ## Project Links
 
 * [Documentation](https://docs.spring.io/spring-ai/reference/)
diff --git a/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/MarkdownDocumentReader.java b/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/MarkdownDocumentReader.java
index 19ebed9cad6..33c3709eb02 100644
--- a/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/MarkdownDocumentReader.java
+++ b/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/MarkdownDocumentReader.java
@@ -111,7 +111,7 @@ static class DocumentVisitor extends AbstractVisitor {
 
 		private Document.Builder currentDocumentBuilder;
 
-		public DocumentVisitor(MarkdownDocumentReaderConfig config) {
+		DocumentVisitor(MarkdownDocumentReaderConfig config) {
 			this.config = config;
 		}
 
diff --git a/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/config/MarkdownDocumentReaderConfig.java b/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/config/MarkdownDocumentReaderConfig.java
index c22c573f0e8..a622f2531ba 100644
--- a/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/config/MarkdownDocumentReaderConfig.java
+++ b/document-readers/markdown-reader/src/main/java/org/springframework/ai/reader/markdown/config/MarkdownDocumentReaderConfig.java
@@ -56,7 +56,7 @@ public static Builder builder() {
 		return new Builder();
 	}
 
-	public static class Builder {
+	public static final class Builder {
 
 		private boolean horizontalRuleCreateDocument = false;
 
diff --git a/document-readers/pdf-reader/pom.xml b/document-readers/pdf-reader/pom.xml
index 1a44d4ef382..94d106a7517 100644
--- a/document-readers/pdf-reader/pom.xml
+++ b/document-readers/pdf-reader/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-anthropic/pom.xml b/models/spring-ai-anthropic/pom.xml
index 74663049a06..7cb9a41d8e3 100644
--- a/models/spring-ai-anthropic/pom.xml
+++ b/models/spring-ai-anthropic/pom.xml
@@ -38,7 +38,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-azure-openai/pom.xml b/models/spring-ai-azure-openai/pom.xml
index 35f8511d226..6e312cfca8a 100644
--- a/models/spring-ai-azure-openai/pom.xml
+++ b/models/spring-ai-azure-openai/pom.xml
@@ -36,7 +36,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-bedrock-converse/pom.xml b/models/spring-ai-bedrock-converse/pom.xml
index e684d6bf133..79c9364b203 100644
--- a/models/spring-ai-bedrock-converse/pom.xml
+++ b/models/spring-ai-bedrock-converse/pom.xml
@@ -1,4 +1,20 @@
 
+
+
 
@@ -81,4 +97,4 @@
 
 	
 
-
\ No newline at end of file
+
diff --git a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java
index 013cba9be4b..4687504e075 100644
--- a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java
+++ b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModel.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2024 - 2024 the original author or authors.
+ * Copyright 2023-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * https://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.springframework.ai.bedrock.converse;
 
 import java.io.IOException;
@@ -26,44 +27,11 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.ai.bedrock.converse.api.ConverseApiUtils;
-import org.springframework.ai.bedrock.converse.api.URLValidator;
-import org.springframework.ai.chat.messages.AssistantMessage;
-import org.springframework.ai.chat.messages.MessageType;
-import org.springframework.ai.chat.messages.ToolResponseMessage;
-import org.springframework.ai.chat.messages.UserMessage;
-import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
-import org.springframework.ai.chat.metadata.ChatResponseMetadata;
-import org.springframework.ai.chat.metadata.DefaultUsage;
-import org.springframework.ai.chat.model.AbstractToolCallSupport;
-import org.springframework.ai.chat.model.ChatModel;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.model.Generation;
-import org.springframework.ai.chat.model.MessageAggregator;
-import org.springframework.ai.chat.observation.ChatModelObservationContext;
-import org.springframework.ai.chat.observation.ChatModelObservationConvention;
-import org.springframework.ai.chat.observation.ChatModelObservationDocumentation;
-import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
-import org.springframework.ai.chat.prompt.ChatOptions;
-import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
-import org.springframework.ai.chat.prompt.Prompt;
-import org.springframework.ai.model.ModelOptionsUtils;
-import org.springframework.ai.model.function.FunctionCallback;
-import org.springframework.ai.model.function.FunctionCallbackContext;
-import org.springframework.ai.model.function.FunctionCallingOptions;
-import org.springframework.ai.model.function.FunctionCallingOptionsBuilder;
-import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
-import org.springframework.ai.observation.conventions.AiProvider;
-import org.springframework.util.Assert;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StreamUtils;
-import org.springframework.util.StringUtils;
-
 import io.micrometer.observation.Observation;
 import io.micrometer.observation.ObservationRegistry;
 import io.micrometer.observation.contextpropagation.ObservationThreadLocalAccessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import reactor.core.publisher.Sinks;
@@ -97,6 +65,39 @@
 import software.amazon.awssdk.services.bedrockruntime.model.ToolSpecification;
 import software.amazon.awssdk.services.bedrockruntime.model.ToolUseBlock;
 
+import org.springframework.ai.bedrock.converse.api.ConverseApiUtils;
+import org.springframework.ai.bedrock.converse.api.URLValidator;
+import org.springframework.ai.chat.messages.AssistantMessage;
+import org.springframework.ai.chat.messages.MessageType;
+import org.springframework.ai.chat.messages.ToolResponseMessage;
+import org.springframework.ai.chat.messages.UserMessage;
+import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
+import org.springframework.ai.chat.metadata.ChatResponseMetadata;
+import org.springframework.ai.chat.metadata.DefaultUsage;
+import org.springframework.ai.chat.model.AbstractToolCallSupport;
+import org.springframework.ai.chat.model.ChatModel;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.model.Generation;
+import org.springframework.ai.chat.model.MessageAggregator;
+import org.springframework.ai.chat.observation.ChatModelObservationContext;
+import org.springframework.ai.chat.observation.ChatModelObservationConvention;
+import org.springframework.ai.chat.observation.ChatModelObservationDocumentation;
+import org.springframework.ai.chat.observation.DefaultChatModelObservationConvention;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
+import org.springframework.ai.chat.prompt.Prompt;
+import org.springframework.ai.model.ModelOptionsUtils;
+import org.springframework.ai.model.function.FunctionCallback;
+import org.springframework.ai.model.function.FunctionCallbackContext;
+import org.springframework.ai.model.function.FunctionCallingOptions;
+import org.springframework.ai.model.function.FunctionCallingOptionsBuilder;
+import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
+import org.springframework.ai.observation.conventions.AiProvider;
+import org.springframework.util.Assert;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StreamUtils;
+import org.springframework.util.StringUtils;
+
 /**
  * A {@link ChatModel} implementation that uses the Amazon Bedrock Converse API to
  * interact with the  generations = message.content()
 			.stream()
 			.filter(content -> content.type() != ContentBlock.Type.TOOL_USE)
-			.map(content -> {
-				return new Generation(new AssistantMessage(content.text(), Map.of()),
-						ChatGenerationMetadata.from(response.stopReasonAsString(), null));
-			})
+			.map(content -> new Generation(new AssistantMessage(content.text(), Map.of()),
+					ChatGenerationMetadata.from(response.stopReasonAsString(), null)))
 			.toList();
 
 		List allGenerations = new ArrayList<>(generations);
@@ -508,7 +507,7 @@ public Flux stream(Prompt prompt) {
 			// @formatter:off
 			Flux chatResponses = ConverseApiUtils.toChatResponse(response);
 
-			Flux chatResponseFlux = chatResponses.switchMap(chatResponse -> {							
+			Flux chatResponseFlux = chatResponses.switchMap(chatResponse -> {
 				if (!this.isProxyToolCalls(prompt, this.defaultOptions) && chatResponse != null
 						&& this.isToolCall(chatResponse, Set.of("tool_use"))) {
 					var toolCallConversation = this.handleToolCalls(prompt, chatResponse);
@@ -540,14 +539,14 @@ public Flux converseStream(ConverseStreamRequest converseS
 		Sinks.Many eventSink = Sinks.many().multicast().onBackpressureBuffer();
 
 		ConverseStreamResponseHandler.Visitor visitor = ConverseStreamResponseHandler.Visitor.builder()
-			.onDefault((output) -> {
+			.onDefault(output -> {
 				logger.debug("Received converse stream output:{}", output);
 				eventSink.tryEmitNext(output);
 			})
 			.build();
 
 		ConverseStreamResponseHandler responseHandler = ConverseStreamResponseHandler.builder()
-			.onEventStream(stream -> stream.subscribe((e) -> e.accept(visitor)))
+			.onEventStream(stream -> stream.subscribe(e -> e.accept(visitor)))
 			.onComplete(() -> {
 				EmitResult emitResult = eventSink.tryEmitComplete();
 
@@ -559,7 +558,7 @@ public Flux converseStream(ConverseStreamRequest converseS
 				eventSink.emitComplete(EmitFailureHandler.busyLooping(Duration.ofSeconds(3)));
 				logger.info("Completed streaming response.");
 			})
-			.onError((error) -> {
+			.onError(error -> {
 				logger.error("Error handling Bedrock converse stream response", error);
 				eventSink.tryEmitError(error);
 			})
@@ -571,11 +570,20 @@ public Flux converseStream(ConverseStreamRequest converseS
 
 	}
 
+	/**
+	 * Use the provided convention for reporting observation data
+	 * @param observationConvention The provided convention
+	 */
+	public void setObservationConvention(ChatModelObservationConvention observationConvention) {
+		Assert.notNull(observationConvention, "observationConvention cannot be null");
+		this.observationConvention = observationConvention;
+	}
+
 	public static Builder builder() {
 		return new Builder();
 	}
 
-	public static class Builder {
+	public static final class Builder {
 
 		private AwsCredentialsProvider credentialsProvider;
 
@@ -696,13 +704,4 @@ public BedrockProxyChatModel build() {
 
 	}
 
-	/**
-	 * Use the provided convention for reporting observation data
-	 * @param observationConvention The provided convention
-	 */
-	public void setObservationConvention(ChatModelObservationConvention observationConvention) {
-		Assert.notNull(observationConvention, "observationConvention cannot be null");
-		this.observationConvention = observationConvention;
-	}
-
 }
diff --git a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/BedrockUsage.java b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/BedrockUsage.java
index 96186b9b782..ac58a7ca502 100644
--- a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/BedrockUsage.java
+++ b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/BedrockUsage.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2024 - 2024 the original author or authors.
+ * Copyright 2023-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * https://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,13 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.springframework.ai.bedrock.converse.api;
 
+import software.amazon.awssdk.services.bedrockruntime.model.TokenUsage;
+
 import org.springframework.ai.chat.metadata.Usage;
 import org.springframework.util.Assert;
 
-import software.amazon.awssdk.services.bedrockruntime.model.TokenUsage;
-
 /**
  * {@link Usage} implementation for Bedrock Converse API.
  *
@@ -46,17 +47,17 @@ protected BedrockUsage(Long inputTokens, Long outputTokens) {
 
 	@Override
 	public Long getPromptTokens() {
-		return inputTokens;
+		return this.inputTokens;
 	}
 
 	@Override
 	public Long getGenerationTokens() {
-		return outputTokens;
+		return this.outputTokens;
 	}
 
 	@Override
 	public String toString() {
-		return "BedrockUsage [inputTokens=" + inputTokens + ", outputTokens=" + outputTokens + "]";
+		return "BedrockUsage [inputTokens=" + this.inputTokens + ", outputTokens=" + this.outputTokens + "]";
 	}
 
-}
\ No newline at end of file
+}
diff --git a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java
index a5203c39d95..29038d972f4 100644
--- a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java
+++ b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/ConverseApiUtils.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2024 - 2024 the original author or authors.
+ * Copyright 2023-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * https://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.springframework.ai.bedrock.converse.api;
 
 import java.math.BigDecimal;
@@ -24,18 +25,6 @@
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 
-import org.springframework.ai.chat.messages.AssistantMessage;
-import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
-import org.springframework.ai.chat.metadata.ChatResponseMetadata;
-import org.springframework.ai.chat.metadata.DefaultUsage;
-import org.springframework.ai.chat.model.ChatResponse;
-import org.springframework.ai.chat.model.Generation;
-import org.springframework.ai.chat.prompt.ChatOptions;
-import org.springframework.ai.model.ModelOptions;
-import org.springframework.ai.model.ModelOptionsUtils;
-import org.springframework.util.CollectionUtils;
-import org.springframework.util.StringUtils;
-
 import reactor.core.publisher.Flux;
 import reactor.core.publisher.Mono;
 import software.amazon.awssdk.core.SdkField;
@@ -56,6 +45,18 @@
 import software.amazon.awssdk.services.bedrockruntime.model.TokenUsage;
 import software.amazon.awssdk.services.bedrockruntime.model.ToolUseBlockStart;
 
+import org.springframework.ai.chat.messages.AssistantMessage;
+import org.springframework.ai.chat.metadata.ChatGenerationMetadata;
+import org.springframework.ai.chat.metadata.ChatResponseMetadata;
+import org.springframework.ai.chat.metadata.DefaultUsage;
+import org.springframework.ai.chat.model.ChatResponse;
+import org.springframework.ai.chat.model.Generation;
+import org.springframework.ai.chat.prompt.ChatOptions;
+import org.springframework.ai.model.ModelOptions;
+import org.springframework.ai.model.ModelOptionsUtils;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
 /**
  * Amazon Bedrock Converse API utils.
  *
@@ -63,7 +64,16 @@
  * @author Christian Tzolov
  * @since 1.0.0
  */
-public class ConverseApiUtils {
+public final class ConverseApiUtils {
+
+	public static final ChatResponse EMPTY_CHAT_RESPONSE = ChatResponse.builder()
+		.withGenerations(List.of())
+		.withMetadata("empty", true)
+		.build();
+
+	private ConverseApiUtils() {
+
+	}
 
 	public static boolean isToolUseStart(ConverseStreamOutput event) {
 		if (event == null || event.sdkEventType() == null || event.sdkEventType() != EventType.CONTENT_BLOCK_START) {
@@ -80,139 +90,6 @@ public static boolean isToolUseFinish(ConverseStreamOutput event) {
 		return true;
 	}
 
-	public record Aggregation(MetadataAggregation metadataAggregation, ChatResponse chatResponse) {
-		public Aggregation() {
-			this(MetadataAggregation.builder().build(), EMPTY_CHAT_RESPONSE);
-		}
-	}
-
-	/**
-	 * Special event used to aggregate multiple tool use events into a single event with
-	 * list of aggregated ContentBlockToolUse.
-	 */
-	public static class ToolUseAggregationEvent implements ConverseStreamOutput {
-
-		public record ToolUseEntry(Integer index, String id, String name, String input) {
-		}
-
-		private Integer index;
-
-		private String id;
-
-		private String name;
-
-		private String partialJson = "";
-
-		private List toolUseEntries = new ArrayList<>();
-
-		private DefaultUsage usage;
-
-		public List toolUseEntries() {
-			return this.toolUseEntries;
-		}
-
-		public boolean isEmpty() {
-			return (this.index == null || this.id == null || this.name == null
-					|| !StringUtils.hasText(this.partialJson));
-		}
-
-		ToolUseAggregationEvent withIndex(Integer index) {
-			this.index = index;
-			return this;
-		}
-
-		ToolUseAggregationEvent withId(String id) {
-			this.id = id;
-			return this;
-		}
-
-		ToolUseAggregationEvent withName(String name) {
-			this.name = name;
-			return this;
-		}
-
-		ToolUseAggregationEvent withUsage(DefaultUsage usage) {
-			this.usage = usage;
-			return this;
-		}
-
-		ToolUseAggregationEvent appendPartialJson(String partialJson) {
-			this.partialJson = this.partialJson + partialJson;
-			return this;
-		}
-
-		void squashIntoContentBlock() {
-			this.toolUseEntries.add(new ToolUseEntry(this.index, this.id, this.name, this.partialJson));
-			this.index = null;
-			this.id = null;
-			this.name = null;
-			this.partialJson = "";
-			this.usage = null;
-		}
-
-		@Override
-		public String toString() {
-			return "EventToolUseBuilder [index=" + this.index + ", id=" + this.id + ", name=" + this.name
-					+ ", partialJson=" + this.partialJson + ", toolUseMap=" + "]";
-		}
-
-		@Override
-		public List> sdkFields() {
-			return List.of();
-		}
-
-		@Override
-		public void accept(Visitor visitor) {
-			throw new UnsupportedOperationException();
-		}
-
-	}
-
-	public static ConverseStreamOutput mergeToolUseEvents(ConverseStreamOutput previousEvent,
-			ConverseStreamOutput event) {
-
-		ToolUseAggregationEvent toolUseEventAggregator = (ToolUseAggregationEvent) previousEvent;
-
-		if (event.sdkEventType() == EventType.CONTENT_BLOCK_START) {
-
-			ContentBlockStartEvent contentBlockStart = (ContentBlockStartEvent) event;
-
-			if (ContentBlockStart.Type.TOOL_USE.equals(contentBlockStart.start().type())) {
-				ToolUseBlockStart cbToolUse = contentBlockStart.start().toolUse();
-
-				return toolUseEventAggregator.withIndex(contentBlockStart.contentBlockIndex())
-					.withId(cbToolUse.toolUseId())
-					.withName(cbToolUse.name())
-					.appendPartialJson(""); // CB START always has empty JSON.
-			}
-		}
-		else if (event.sdkEventType() == EventType.CONTENT_BLOCK_DELTA) {
-			ContentBlockDeltaEvent contentBlockDelta = (ContentBlockDeltaEvent) event;
-			if (ContentBlockDelta.Type.TOOL_USE == contentBlockDelta.delta().type()) {
-				return toolUseEventAggregator.appendPartialJson(contentBlockDelta.delta().toolUse().input());
-			}
-		}
-		else if (event.sdkEventType() == EventType.CONTENT_BLOCK_STOP) {
-			return toolUseEventAggregator;
-		}
-		else if (event.sdkEventType() == EventType.MESSAGE_STOP) {
-			return toolUseEventAggregator;
-		}
-		else if (event.sdkEventType() == EventType.METADATA) {
-			ConverseStreamMetadataEvent metadataEvent = (ConverseStreamMetadataEvent) event;
-			DefaultUsage usage = new DefaultUsage(metadataEvent.usage().inputTokens().longValue(),
-					metadataEvent.usage().outputTokens().longValue(), metadataEvent.usage().totalTokens().longValue());
-			toolUseEventAggregator.withUsage(usage);
-			// TODO
-			if (!toolUseEventAggregator.isEmpty()) {
-				toolUseEventAggregator.squashIntoContentBlock();
-				return toolUseEventAggregator;
-			}
-		}
-
-		return event;
-	}
-
 	public static Flux toChatResponse(Flux responses) {
 
 		AtomicBoolean isInsideTool = new AtomicBoolean(false);
@@ -228,7 +105,7 @@ public static Flux toChatResponse(Flux respo
 				return true;
 			}
 			return !isInsideTool.get();
-		}).concatMapIterable(window -> {// Merging the window chunks into a single chunk.
+		}).concatMapIterable(window -> { // Merging the window chunks into a single chunk.
 			Mono monoChunk = window.reduce(new ToolUseAggregationEvent(),
 					ConverseApiUtils::mergeToolUseEvents);
 			return List.of(monoChunk);
@@ -333,81 +210,49 @@ else if (nextEvent instanceof ConverseStreamMetadataEvent metadataEvent) {
 			.filter(chatResponse -> chatResponse != ConverseApiUtils.EMPTY_CHAT_RESPONSE);
 	}
 
-	public static final ChatResponse EMPTY_CHAT_RESPONSE = ChatResponse.builder()
-		.withGenerations(List.of())
-		.withMetadata("empty", true)
-		.build();
-
-	public record MetadataAggregation(String role, String stopReason, Document additionalModelResponseFields,
-			TokenUsage tokenUsage, ConverseStreamMetrics metrics, ConverseStreamTrace trace) {
-
-		public static Builder builder() {
-			return new Builder();
-		}
-
-		public final static class Builder {
-
-			private String role;
-
-			private String stopReason;
-
-			private Document additionalModelResponseFields;
-
-			private TokenUsage tokenUsage;
-
-			private ConverseStreamMetrics metrics;
-
-			private ConverseStreamTrace trace;
-
-			private Builder() {
-			}
-
-			public Builder copy(MetadataAggregation metadataAggregation) {
-				this.role = metadataAggregation.role;
-				this.stopReason = metadataAggregation.stopReason;
-				this.additionalModelResponseFields = metadataAggregation.additionalModelResponseFields;
-				this.tokenUsage = metadataAggregation.tokenUsage;
-				this.metrics = metadataAggregation.metrics;
-				this.trace = metadataAggregation.trace;
-				return this;
-			}
+	public static ConverseStreamOutput mergeToolUseEvents(ConverseStreamOutput previousEvent,
+			ConverseStreamOutput event) {
 
-			public Builder withRole(String role) {
-				this.role = role;
-				return this;
-			}
+		ToolUseAggregationEvent toolUseEventAggregator = (ToolUseAggregationEvent) previousEvent;
 
-			public Builder withStopReason(String stopReason) {
-				this.stopReason = stopReason;
-				return this;
-			}
+		if (event.sdkEventType() == EventType.CONTENT_BLOCK_START) {
 
-			public Builder withAdditionalModelResponseFields(Document additionalModelResponseFields) {
-				this.additionalModelResponseFields = additionalModelResponseFields;
-				return this;
-			}
+			ContentBlockStartEvent contentBlockStart = (ContentBlockStartEvent) event;
 
-			public Builder withTokenUsage(TokenUsage tokenUsage) {
-				this.tokenUsage = tokenUsage;
-				return this;
-			}
+			if (ContentBlockStart.Type.TOOL_USE.equals(contentBlockStart.start().type())) {
+				ToolUseBlockStart cbToolUse = contentBlockStart.start().toolUse();
 
-			public Builder withMetrics(ConverseStreamMetrics metrics) {
-				this.metrics = metrics;
-				return this;
+				return toolUseEventAggregator.withIndex(contentBlockStart.contentBlockIndex())
+					.withId(cbToolUse.toolUseId())
+					.withName(cbToolUse.name())
+					.appendPartialJson(""); // CB START always has empty JSON.
 			}
-
-			public Builder withTrace(ConverseStreamTrace trace) {
-				this.trace = trace;
-				return this;
+		}
+		else if (event.sdkEventType() == EventType.CONTENT_BLOCK_DELTA) {
+			ContentBlockDeltaEvent contentBlockDelta = (ContentBlockDeltaEvent) event;
+			if (ContentBlockDelta.Type.TOOL_USE == contentBlockDelta.delta().type()) {
+				return toolUseEventAggregator.appendPartialJson(contentBlockDelta.delta().toolUse().input());
 			}
-
-			public MetadataAggregation build() {
-				return new MetadataAggregation(role, stopReason, additionalModelResponseFields, tokenUsage, metrics,
-						trace);
+		}
+		else if (event.sdkEventType() == EventType.CONTENT_BLOCK_STOP) {
+			return toolUseEventAggregator;
+		}
+		else if (event.sdkEventType() == EventType.MESSAGE_STOP) {
+			return toolUseEventAggregator;
+		}
+		else if (event.sdkEventType() == EventType.METADATA) {
+			ConverseStreamMetadataEvent metadataEvent = (ConverseStreamMetadataEvent) event;
+			DefaultUsage usage = new DefaultUsage(metadataEvent.usage().inputTokens().longValue(),
+					metadataEvent.usage().outputTokens().longValue(), metadataEvent.usage().totalTokens().longValue());
+			toolUseEventAggregator.withUsage(usage);
+			// TODO
+			if (!toolUseEventAggregator.isEmpty()) {
+				toolUseEventAggregator.squashIntoContentBlock();
+				return toolUseEventAggregator;
 			}
-
 		}
+
+		return event;
 	}
 
 	@SuppressWarnings("unchecked")
@@ -496,4 +341,164 @@ private static Document convertMapToDocument(Map value) {
 		return Document.fromMap(attr);
 	}
 
+	public record Aggregation(MetadataAggregation metadataAggregation, ChatResponse chatResponse) {
+		public Aggregation() {
+			this(MetadataAggregation.builder().build(), EMPTY_CHAT_RESPONSE);
+		}
+	}
+
+	/**
+	 * Special event used to aggregate multiple tool use events into a single event with
+	 * list of aggregated ContentBlockToolUse.
+	 */
+	public static class ToolUseAggregationEvent implements ConverseStreamOutput {
+
+		private Integer index;
+
+		private String id;
+
+		private String name;
+
+		private String partialJson = "";
+
+		private List toolUseEntries = new ArrayList<>();
+
+		private DefaultUsage usage;
+
+		public List toolUseEntries() {
+			return this.toolUseEntries;
+		}
+
+		public boolean isEmpty() {
+			return (this.index == null || this.id == null || this.name == null
+					|| !StringUtils.hasText(this.partialJson));
+		}
+
+		ToolUseAggregationEvent withIndex(Integer index) {
+			this.index = index;
+			return this;
+		}
+
+		ToolUseAggregationEvent withId(String id) {
+			this.id = id;
+			return this;
+		}
+
+		ToolUseAggregationEvent withName(String name) {
+			this.name = name;
+			return this;
+		}
+
+		ToolUseAggregationEvent withUsage(DefaultUsage usage) {
+			this.usage = usage;
+			return this;
+		}
+
+		ToolUseAggregationEvent appendPartialJson(String partialJson) {
+			this.partialJson = this.partialJson + partialJson;
+			return this;
+		}
+
+		void squashIntoContentBlock() {
+			this.toolUseEntries.add(new ToolUseEntry(this.index, this.id, this.name, this.partialJson));
+			this.index = null;
+			this.id = null;
+			this.name = null;
+			this.partialJson = "";
+			this.usage = null;
+		}
+
+		@Override
+		public String toString() {
+			return "EventToolUseBuilder [index=" + this.index + ", id=" + this.id + ", name=" + this.name
+					+ ", partialJson=" + this.partialJson + ", toolUseMap=" + "]";
+		}
+
+		@Override
+		public List> sdkFields() {
+			return List.of();
+		}
+
+		@Override
+		public void accept(Visitor visitor) {
+			throw new UnsupportedOperationException();
+		}
+
+		public record ToolUseEntry(Integer index, String id, String name, String input) {
+		}
+
+	}
+
+	public record MetadataAggregation(String role, String stopReason, Document additionalModelResponseFields,
+			TokenUsage tokenUsage, ConverseStreamMetrics metrics, ConverseStreamTrace trace) {
+
+		public static Builder builder() {
+			return new Builder();
+		}
+
+		public final static class Builder {
+
+			private String role;
+
+			private String stopReason;
+
+			private Document additionalModelResponseFields;
+
+			private TokenUsage tokenUsage;
+
+			private ConverseStreamMetrics metrics;
+
+			private ConverseStreamTrace trace;
+
+			private Builder() {
+			}
+
+			public Builder copy(MetadataAggregation metadataAggregation) {
+				this.role = metadataAggregation.role;
+				this.stopReason = metadataAggregation.stopReason;
+				this.additionalModelResponseFields = metadataAggregation.additionalModelResponseFields;
+				this.tokenUsage = metadataAggregation.tokenUsage;
+				this.metrics = metadataAggregation.metrics;
+				this.trace = metadataAggregation.trace;
+				return this;
+			}
+
+			public Builder withRole(String role) {
+				this.role = role;
+				return this;
+			}
+
+			public Builder withStopReason(String stopReason) {
+				this.stopReason = stopReason;
+				return this;
+			}
+
+			public Builder withAdditionalModelResponseFields(Document additionalModelResponseFields) {
+				this.additionalModelResponseFields = additionalModelResponseFields;
+				return this;
+			}
+
+			public Builder withTokenUsage(TokenUsage tokenUsage) {
+				this.tokenUsage = tokenUsage;
+				return this;
+			}
+
+			public Builder withMetrics(ConverseStreamMetrics metrics) {
+				this.metrics = metrics;
+				return this;
+			}
+
+			public Builder withTrace(ConverseStreamTrace trace) {
+				this.trace = trace;
+				return this;
+			}
+
+			public MetadataAggregation build() {
+				return new MetadataAggregation(this.role, this.stopReason, this.additionalModelResponseFields,
+						this.tokenUsage, this.metrics, this.trace);
+			}
+
+		}
+	}
+
 }
diff --git a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/URLValidator.java b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/URLValidator.java
index 342ce5ba545..121fe74877b 100644
--- a/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/URLValidator.java
+++ b/models/spring-ai-bedrock-converse/src/main/java/org/springframework/ai/bedrock/converse/api/URLValidator.java
@@ -1,18 +1,19 @@
 /*
-* Copyright 2024 - 2024 the original author or authors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2023-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.springframework.ai.bedrock.converse.api;
 
 import java.net.MalformedURLException;
@@ -27,7 +28,7 @@
  * @author Christian Tzolov
  * @since 1.0.0
  */
-public class URLValidator {
+public final class URLValidator {
 
 	// Basic URL regex pattern
 	// Protocol (http:// or https://)
@@ -41,6 +42,10 @@ public class URLValidator {
 			"(#[\\w-]*)?" + // Optional fragment
 			"$");
 
+	private URLValidator() {
+
+	}
+
 	/**
 	 * Quick validation using regex pattern Good for basic checks but may not catch all
 	 * edge cases
@@ -121,4 +126,4 @@ public static String normalizeURL(String urlString) {
 		return normalized;
 	}
 
-}
\ No newline at end of file
+}
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java
index 3486abd9d50..2719569dcce 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseChatClientIT.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024-2024 the original author or authors.
+ * Copyright 2023-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,8 +16,6 @@
 
 package org.springframework.ai.bedrock.converse;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 import java.io.IOException;
 import java.net.URL;
 import java.util.Arrays;
@@ -31,6 +29,8 @@
 import org.junit.jupiter.params.provider.ValueSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Flux;
+
 import org.springframework.ai.chat.client.ChatClient;
 import org.springframework.ai.chat.client.advisor.SimpleLoggerAdvisor;
 import org.springframework.ai.chat.model.ChatModel;
@@ -47,7 +47,7 @@
 import org.springframework.core.io.Resource;
 import org.springframework.util.MimeTypeUtils;
 
-import reactor.core.publisher.Flux;
+import static org.assertj.core.api.Assertions.assertThat;
 
 @SpringBootTest(classes = BedrockConverseTestConfiguration.class)
 @EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
@@ -88,7 +88,7 @@ void listOutputConverterString() {
 				.user(u -> u.text("List five {subject}")
 						.param("subject", "ice cream flavors"))
 				.call()
-				.entity(new ParameterizedTypeReference>() {});
+				.entity(new ParameterizedTypeReference>() { });
 		// @formatter:on
 
 		logger.info(collection.toString());
@@ -211,7 +211,7 @@ void functionCallTest() {
 
 		// @formatter:off
 		String response = ChatClient.create(this.chatModel)
-				.prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.")				
+				.prompt("What's the weather like in San Francisco, Tokyo, and Paris? Return the temperature in Celsius.")
 				.function("getCurrentWeather", "Get the weather in location", new MockWeatherService())
 				.call()
 				.content();
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseTestConfiguration.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseTestConfiguration.java
index 4275e9fc75b..eaf220fb284 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseTestConfiguration.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockConverseTestConfiguration.java
@@ -18,13 +18,13 @@
 
 import java.time.Duration;
 
+import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+
 import org.springframework.ai.model.function.FunctionCallingOptions;
 import org.springframework.boot.SpringBootConfiguration;
 import org.springframework.context.annotation.Bean;
 
-import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
-import software.amazon.awssdk.regions.Region;
-
 @SpringBootConfiguration
 public class BedrockConverseTestConfiguration {
 
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java
index e02965f6768..f2f5c19f29a 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelIT.java
@@ -16,8 +16,6 @@
 
 package org.springframework.ai.bedrock.converse;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -32,6 +30,8 @@
 import org.junit.jupiter.params.provider.ValueSource;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import reactor.core.publisher.Flux;
+
 import org.springframework.ai.chat.client.ChatClient;
 import org.springframework.ai.chat.messages.AssistantMessage;
 import org.springframework.ai.chat.messages.Message;
@@ -57,7 +57,7 @@
 import org.springframework.core.io.Resource;
 import org.springframework.util.MimeTypeUtils;
 
-import reactor.core.publisher.Flux;
+import static org.assertj.core.api.Assertions.assertThat;
 
 @SpringBootTest(classes = BedrockConverseTestConfiguration.class, properties = "spring.ai.retry.on-http-codes=429")
 @EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelObservationIT.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelObservationIT.java
index 70c130bb2e6..1b2be8a2724 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelObservationIT.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/BedrockProxyChatModelObservationIT.java
@@ -16,8 +16,6 @@
 
 package org.springframework.ai.bedrock.converse;
 
-import static org.assertj.core.api.Assertions.assertThat;
-
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -45,6 +43,8 @@
 import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.context.annotation.Bean;
 
+import static org.assertj.core.api.Assertions.assertThat;
+
 /**
  * Integration tests for observation instrumentation in {@link BedrockProxyChatModel}.
  *
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/MockWeatherService.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/MockWeatherService.java
index af62aaf85a0..8579aa44329 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/MockWeatherService.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/MockWeatherService.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2024-2024 the original author or authors.
+ * Copyright 2023-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -65,7 +65,7 @@ public enum Unit {
 		 */
 		public final String unitName;
 
-		private Unit(String text) {
+		Unit(String text) {
 			this.unitName = text;
 		}
 
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/RequiresAwsCredentials.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/RequiresAwsCredentials.java
index cc2db3b4914..bf750e1cfd6 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/RequiresAwsCredentials.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/RequiresAwsCredentials.java
@@ -1,11 +1,11 @@
 /*
- * Copyright 2024 - 2024 the original author or authors.
+ * Copyright 2023-2024 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
- * https://www.apache.org/licenses/LICENSE-2.0
+ *      https://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -13,15 +13,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.springframework.ai.bedrock.converse;
 
-import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+package org.springframework.ai.bedrock.converse;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
+import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable;
+
 @Target({ ElementType.TYPE, ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 @EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*")
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain.java
index 51493cf73a9..f7978fa1bb9 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain.java
@@ -1,27 +1,28 @@
 /*
-* Copyright 2024 - 2024 the original author or authors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2023-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.springframework.ai.bedrock.converse.experiements;
 
+import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+
 import org.springframework.ai.bedrock.converse.BedrockProxyChatModel;
 import org.springframework.ai.chat.prompt.ChatOptionsBuilder;
 import org.springframework.ai.chat.prompt.Prompt;
 
-import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
-import software.amazon.awssdk.regions.Region;
-
 /**
  * Used for reverse engineering the protocol.
  *
@@ -29,7 +30,11 @@
  * @since 1.0.0
  */
 
-public class BedrockConverseChatModelMain {
+public final class BedrockConverseChatModelMain {
+
+	private BedrockConverseChatModelMain() {
+
+	}
 
 	public static void main(String[] args) {
 
diff --git a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain2.java b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain2.java
index 569bf021332..e42b60d9a8e 100644
--- a/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain2.java
+++ b/models/spring-ai-bedrock-converse/src/test/java/org/springframework/ai/bedrock/converse/experiements/BedrockConverseChatModelMain2.java
@@ -1,37 +1,42 @@
 /*
-* Copyright 2024 - 2024 the original author or authors.
-*
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* https://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*/
+ * Copyright 2023-2024 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.springframework.ai.bedrock.converse.experiements;
 
 import java.util.List;
 
+import reactor.core.publisher.Flux;
+import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
+import software.amazon.awssdk.regions.Region;
+import software.amazon.awssdk.services.bedrockruntime.model.ConverseStreamOutput;
+
 import org.springframework.ai.bedrock.converse.BedrockProxyChatModel;
 import org.springframework.ai.bedrock.converse.MockWeatherService;
 import org.springframework.ai.chat.prompt.Prompt;
 import org.springframework.ai.model.function.FunctionCallbackWrapper;
 import org.springframework.ai.model.function.FunctionCallingOptionsBuilder.PortableFunctionCallingOptions;
 
-import reactor.core.publisher.Flux;
-import software.amazon.awssdk.auth.credentials.EnvironmentVariableCredentialsProvider;
-import software.amazon.awssdk.regions.Region;
-import software.amazon.awssdk.services.bedrockruntime.model.ConverseStreamOutput;
-
 /**
  * Used for reverse engineering the protocol
  */
-public class BedrockConverseChatModelMain2 {
+public final class BedrockConverseChatModelMain2 {
+
+	private BedrockConverseChatModelMain2() {
+
+	}
 
 	public static void main(String[] args) {
 
diff --git a/models/spring-ai-bedrock/pom.xml b/models/spring-ai-bedrock/pom.xml
index a77188f9dae..25a54b28f05 100644
--- a/models/spring-ai-bedrock/pom.xml
+++ b/models/spring-ai-bedrock/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-huggingface/pom.xml b/models/spring-ai-huggingface/pom.xml
index d0fe5583636..9a1d487dbb4 100644
--- a/models/spring-ai-huggingface/pom.xml
+++ b/models/spring-ai-huggingface/pom.xml
@@ -36,7 +36,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-minimax/pom.xml b/models/spring-ai-minimax/pom.xml
index 198f47112e5..8a592901a91 100644
--- a/models/spring-ai-minimax/pom.xml
+++ b/models/spring-ai-minimax/pom.xml
@@ -37,7 +37,6 @@
     
 
 	
-		false
 	
 
     
diff --git a/models/spring-ai-mistral-ai/pom.xml b/models/spring-ai-mistral-ai/pom.xml
index b95c4a23feb..07e45c48d80 100644
--- a/models/spring-ai-mistral-ai/pom.xml
+++ b/models/spring-ai-mistral-ai/pom.xml
@@ -38,7 +38,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-moonshot/pom.xml b/models/spring-ai-moonshot/pom.xml
index 5d72d858348..40527b8a171 100644
--- a/models/spring-ai-moonshot/pom.xml
+++ b/models/spring-ai-moonshot/pom.xml
@@ -38,7 +38,6 @@
 
 
 	
-		false
 	
 
     
diff --git a/models/spring-ai-oci-genai/pom.xml b/models/spring-ai-oci-genai/pom.xml
index 82c34d0442d..1355d4230cc 100644
--- a/models/spring-ai-oci-genai/pom.xml
+++ b/models/spring-ai-oci-genai/pom.xml
@@ -37,7 +37,6 @@
     
 
 	
-		false
 	
 
     
diff --git a/models/spring-ai-ollama/pom.xml b/models/spring-ai-ollama/pom.xml
index 0e9fb5b942a..9f8e340dd81 100644
--- a/models/spring-ai-ollama/pom.xml
+++ b/models/spring-ai-ollama/pom.xml
@@ -34,7 +34,6 @@
         17
         17
         UTF-8
-		false
     
 
     
diff --git a/models/spring-ai-openai/pom.xml b/models/spring-ai-openai/pom.xml
index aa52d0521fc..a69a0224c08 100644
--- a/models/spring-ai-openai/pom.xml
+++ b/models/spring-ai-openai/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-postgresml/pom.xml b/models/spring-ai-postgresml/pom.xml
index d205720f1fa..ff1d1eed41b 100644
--- a/models/spring-ai-postgresml/pom.xml
+++ b/models/spring-ai-postgresml/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-qianfan/pom.xml b/models/spring-ai-qianfan/pom.xml
index 750fe69fc56..a2483861c68 100644
--- a/models/spring-ai-qianfan/pom.xml
+++ b/models/spring-ai-qianfan/pom.xml
@@ -37,7 +37,6 @@
     
 
 	
-		false
 	
 
     
diff --git a/models/spring-ai-stability-ai/pom.xml b/models/spring-ai-stability-ai/pom.xml
index b1a14b4c93f..0307df28df5 100644
--- a/models/spring-ai-stability-ai/pom.xml
+++ b/models/spring-ai-stability-ai/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-transformers/pom.xml b/models/spring-ai-transformers/pom.xml
index 3351485ed25..2b99d6a9981 100644
--- a/models/spring-ai-transformers/pom.xml
+++ b/models/spring-ai-transformers/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-vertex-ai-embedding/pom.xml b/models/spring-ai-vertex-ai-embedding/pom.xml
index dc61e8dfb7e..5327e48b45e 100644
--- a/models/spring-ai-vertex-ai-embedding/pom.xml
+++ b/models/spring-ai-vertex-ai-embedding/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-vertex-ai-gemini/pom.xml b/models/spring-ai-vertex-ai-gemini/pom.xml
index 0f503e4e781..cc184d54b22 100644
--- a/models/spring-ai-vertex-ai-gemini/pom.xml
+++ b/models/spring-ai-vertex-ai-gemini/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/models/spring-ai-watsonx-ai/pom.xml b/models/spring-ai-watsonx-ai/pom.xml
index ca14a148d5c..3b8d281d033 100644
--- a/models/spring-ai-watsonx-ai/pom.xml
+++ b/models/spring-ai-watsonx-ai/pom.xml
@@ -34,7 +34,6 @@
 		17
 		17
 		UTF-8
-		false
 	
 
 	
diff --git a/models/spring-ai-zhipuai/pom.xml b/models/spring-ai-zhipuai/pom.xml
index 10bb5cbfcf9..f0f6a920fc9 100644
--- a/models/spring-ai-zhipuai/pom.xml
+++ b/models/spring-ai-zhipuai/pom.xml
@@ -36,7 +36,6 @@
         git@github.com:spring-projects/spring-ai.git
     
 	
-		false
 	
 
     
diff --git a/spring-ai-core/pom.xml b/spring-ai-core/pom.xml
index 1a58c4cf869..e278f72cc35 100644
--- a/spring-ai-core/pom.xml
+++ b/spring-ai-core/pom.xml
@@ -38,7 +38,6 @@
 
 	
 		4.13.1
-		false
 	
 
 	
diff --git a/spring-ai-retry/pom.xml b/spring-ai-retry/pom.xml
index e479fa22059..596aef76a9e 100644
--- a/spring-ai-retry/pom.xml
+++ b/spring-ai-retry/pom.xml
@@ -36,7 +36,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/spring-ai-spring-boot-autoconfigure/pom.xml b/spring-ai-spring-boot-autoconfigure/pom.xml
index 2f6179bee67..425674e77f8 100644
--- a/spring-ai-spring-boot-autoconfigure/pom.xml
+++ b/spring-ai-spring-boot-autoconfigure/pom.xml
@@ -21,7 +21,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/spring-ai-spring-boot-docker-compose/pom.xml b/spring-ai-spring-boot-docker-compose/pom.xml
index 70115f2a57b..62d0d0de820 100644
--- a/spring-ai-spring-boot-docker-compose/pom.xml
+++ b/spring-ai-spring-boot-docker-compose/pom.xml
@@ -36,7 +36,6 @@
     
 
 	
-		false
 	
 
     
diff --git a/spring-ai-spring-boot-testcontainers/pom.xml b/spring-ai-spring-boot-testcontainers/pom.xml
index 13acbba6858..f60e6b34da7 100644
--- a/spring-ai-spring-boot-testcontainers/pom.xml
+++ b/spring-ai-spring-boot-testcontainers/pom.xml
@@ -37,7 +37,6 @@
 	
 
 	
-		false
 	
 
 	
diff --git a/spring-ai-spring-cloud-bindings/pom.xml b/spring-ai-spring-cloud-bindings/pom.xml
index 60de4a9514e..576e4bb337c 100644
--- a/spring-ai-spring-cloud-bindings/pom.xml
+++ b/spring-ai-spring-cloud-bindings/pom.xml
@@ -36,7 +36,6 @@
     
 
 	
-		false
 	
 
     
diff --git a/spring-ai-test/pom.xml b/spring-ai-test/pom.xml
index 81a928a263a..3397a92ae7b 100644
--- a/spring-ai-test/pom.xml
+++ b/spring-ai-test/pom.xml
@@ -37,7 +37,6 @@
 	
 		17
         17
-		false
 	
 
 	
diff --git a/src/checkstyle/checkstyle.xml b/src/checkstyle/checkstyle.xml
index b19befaaab4..c95fea1a117 100644
--- a/src/checkstyle/checkstyle.xml
+++ b/src/checkstyle/checkstyle.xml
@@ -100,7 +100,7 @@
 		
 		
 			
+					  value="org.springframework.ai.autoconfigure.vectorstore.observation.ObservationTestUtil.*, org.awaitility.Awaitility.*, org.springframework.ai.aot.AiRuntimeHints.*, org.springframework.ai.openai.metadata.support.OpenAiApiResponseHeaders.*, org.springframework.ai.image.observation.ImageModelObservationDocumentation.*, org.springframework.ai.embedding.observation.EmbeddingModelObservationDocumentation.*, org.springframework.aot.hint.predicate.RuntimeHintsPredicates.*, org.springframework.ai.vectorstore.filter.Filter.ExpressionType.*, org.springframework.ai.chat.observation.ChatModelObservationDocumentation.*, org.assertj.core.groups.Tuple.*, org.assertj.core.api.AssertionsForClassTypes.*, org.junit.jupiter.api.Assertions.*, org.assertj.core.api.Assertions.*, org.junit.Assert.*, org.junit.Assume.*, org.junit.internal.matchers.ThrowableMessageMatcher.*, org.hamcrest.CoreMatchers.*, org.hamcrest.Matchers.*, org.springframework.boot.configurationprocessor.ConfigurationMetadataMatchers.*, org.springframework.boot.configurationprocessor.TestCompiler.*, org.springframework.boot.test.autoconfigure.AutoConfigurationImportedCondition.*, org.mockito.Mockito.*, org.mockito.BDDMockito.*, org.mockito.Matchers.*, org.mockito.ArgumentMatchers.*, org.springframework.restdocs.mockmvc.MockMvcRestDocumentation.*, org.springframework.restdocs.hypermedia.HypermediaDocumentation.*, org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*, org.springframework.test.web.servlet.result.MockMvcResultMatchers.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestBuilders.*, org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.*, org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.*, org.springframework.hateoas.mvc.ControllerLinkBuilder.linkTo, org.springframework.test.web.client.match.MockRestRequestMatchers.*, org.springframework.test.web.client.response.MockRestResponseCreators.*, org.springframework.web.reactive.function.server.RequestPredicates.*, org.springframework.web.reactive.function.server.RouterFunctions.*, org.springframework.test.web.servlet.setup.MockMvcBuilders.*"/>
 		
 		
 		
diff --git a/vector-stores/spring-ai-azure-cosmos-db-store/pom.xml b/vector-stores/spring-ai-azure-cosmos-db-store/pom.xml
index 4dc1ca30dce..ca93a9ece8b 100644
--- a/vector-stores/spring-ai-azure-cosmos-db-store/pom.xml
+++ b/vector-stores/spring-ai-azure-cosmos-db-store/pom.xml
@@ -39,7 +39,6 @@
 	
         17
         17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-azure-store/pom.xml b/vector-stores/spring-ai-azure-store/pom.xml
index 015199de527..25bf7e5f11e 100644
--- a/vector-stores/spring-ai-azure-store/pom.xml
+++ b/vector-stores/spring-ai-azure-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-cassandra-store/pom.xml b/vector-stores/spring-ai-cassandra-store/pom.xml
index ea9892b3810..1032f363547 100644
--- a/vector-stores/spring-ai-cassandra-store/pom.xml
+++ b/vector-stores/spring-ai-cassandra-store/pom.xml
@@ -39,7 +39,6 @@
 	
         17
         17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-elasticsearch-store/pom.xml b/vector-stores/spring-ai-elasticsearch-store/pom.xml
index 824842bd002..440dc99b7a6 100644
--- a/vector-stores/spring-ai-elasticsearch-store/pom.xml
+++ b/vector-stores/spring-ai-elasticsearch-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 		
 		4.0.3
 	
diff --git a/vector-stores/spring-ai-gemfire-store/pom.xml b/vector-stores/spring-ai-gemfire-store/pom.xml
index 2d1f84a66c1..37d859f701a 100644
--- a/vector-stores/spring-ai-gemfire-store/pom.xml
+++ b/vector-stores/spring-ai-gemfire-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 	
 
     
diff --git a/vector-stores/spring-ai-hanadb-store/pom.xml b/vector-stores/spring-ai-hanadb-store/pom.xml
index 0e72805977f..430297bb718 100644
--- a/vector-stores/spring-ai-hanadb-store/pom.xml
+++ b/vector-stores/spring-ai-hanadb-store/pom.xml
@@ -40,7 +40,6 @@
 	
 		17
 		17
-		false
 	
 
     
diff --git a/vector-stores/spring-ai-milvus-store/pom.xml b/vector-stores/spring-ai-milvus-store/pom.xml
index c671083d436..fddad05b654 100644
--- a/vector-stores/spring-ai-milvus-store/pom.xml
+++ b/vector-stores/spring-ai-milvus-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-mongodb-atlas-store/pom.xml b/vector-stores/spring-ai-mongodb-atlas-store/pom.xml
index 753b5f9c8e5..b1b80300531 100644
--- a/vector-stores/spring-ai-mongodb-atlas-store/pom.xml
+++ b/vector-stores/spring-ai-mongodb-atlas-store/pom.xml
@@ -38,7 +38,6 @@
 	
 		17
 		17
-		false
 	
 
     
diff --git a/vector-stores/spring-ai-neo4j-store/pom.xml b/vector-stores/spring-ai-neo4j-store/pom.xml
index 29697aaeb3b..a8acbfc8f2c 100644
--- a/vector-stores/spring-ai-neo4j-store/pom.xml
+++ b/vector-stores/spring-ai-neo4j-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-opensearch-store/pom.xml b/vector-stores/spring-ai-opensearch-store/pom.xml
index e8c5972f268..aa3ddfbbd09 100644
--- a/vector-stores/spring-ai-opensearch-store/pom.xml
+++ b/vector-stores/spring-ai-opensearch-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		
 		4.0.3
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-oracle-store/pom.xml b/vector-stores/spring-ai-oracle-store/pom.xml
index 3e56973eb57..0f795fa89e7 100644
--- a/vector-stores/spring-ai-oracle-store/pom.xml
+++ b/vector-stores/spring-ai-oracle-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-pgvector-store/pom.xml b/vector-stores/spring-ai-pgvector-store/pom.xml
index c36221d7e49..5b4a7b0df1f 100644
--- a/vector-stores/spring-ai-pgvector-store/pom.xml
+++ b/vector-stores/spring-ai-pgvector-store/pom.xml
@@ -39,7 +39,6 @@
 	
 		17
 		17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-pinecone-store/pom.xml b/vector-stores/spring-ai-pinecone-store/pom.xml
index 8603595fb88..87b2722c561 100644
--- a/vector-stores/spring-ai-pinecone-store/pom.xml
+++ b/vector-stores/spring-ai-pinecone-store/pom.xml
@@ -38,7 +38,6 @@
     
         17
         17
-		false
     
 
     
diff --git a/vector-stores/spring-ai-qdrant-store/pom.xml b/vector-stores/spring-ai-qdrant-store/pom.xml
index d2938dcb53d..2d9c598e529 100644
--- a/vector-stores/spring-ai-qdrant-store/pom.xml
+++ b/vector-stores/spring-ai-qdrant-store/pom.xml
@@ -39,7 +39,6 @@
     
         17
         17
-		false
     
 
     
diff --git a/vector-stores/spring-ai-redis-store/pom.xml b/vector-stores/spring-ai-redis-store/pom.xml
index 394f00aac60..80c7c687476 100644
--- a/vector-stores/spring-ai-redis-store/pom.xml
+++ b/vector-stores/spring-ai-redis-store/pom.xml
@@ -41,7 +41,6 @@
 		5.1.0
         17
         17
-		false
 	
 
 	
diff --git a/vector-stores/spring-ai-typesense-store/pom.xml b/vector-stores/spring-ai-typesense-store/pom.xml
index 860758ec40a..db03d79179b 100644
--- a/vector-stores/spring-ai-typesense-store/pom.xml
+++ b/vector-stores/spring-ai-typesense-store/pom.xml
@@ -39,7 +39,6 @@
     
 
 	
-		false
 	
 
 
diff --git a/vector-stores/spring-ai-weaviate-store/pom.xml b/vector-stores/spring-ai-weaviate-store/pom.xml
index 7a1b19ef585..c1ea5ff95be 100644
--- a/vector-stores/spring-ai-weaviate-store/pom.xml
+++ b/vector-stores/spring-ai-weaviate-store/pom.xml
@@ -38,7 +38,6 @@
     
         17
         17
-		false