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