From 27647c25c6cb7a9eabf6893a95963aedfba5fdc3 Mon Sep 17 00:00:00 2001 From: fzowl Date: Mon, 17 Nov 2025 10:54:22 +0100 Subject: [PATCH 01/37] Adding VoyageAI integration --- PACKAGES.md | 34 + aiservices/voyageai/pom.xml | 89 +++ ...textualizedEmbeddingGenerationService.java | 204 ++++++ .../voyageai/core/VoyageAIClient.java | 132 ++++ .../voyageai/core/VoyageAIModels.java | 606 ++++++++++++++++++ ...IMultimodalEmbeddingGenerationService.java | 227 +++++++ .../VoyageAITextRerankingService.java | 182 ++++++ ...oyageAITextEmbeddingGenerationService.java | 174 +++++ ...ualizedEmbeddingGenerationServiceTest.java | 142 ++++ .../voyageai/VoyageAIIntegrationTest.java | 216 +++++++ ...timodalEmbeddingGenerationServiceTest.java | 181 ++++++ ...eAITextEmbeddingGenerationServiceTest.java | 131 ++++ .../VoyageAITextRerankingServiceTest.java | 116 ++++ pom.xml | 1 + .../services/reranking/RerankResult.java | 55 ++ .../reranking/TextRerankingService.java | 22 + 16 files changed, 2512 insertions(+) create mode 100644 aiservices/voyageai/pom.xml create mode 100644 aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java create mode 100644 aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java create mode 100644 aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java create mode 100644 aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java create mode 100644 aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java create mode 100644 aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java create mode 100644 aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIContextualizedEmbeddingGenerationServiceTest.java create mode 100644 aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIIntegrationTest.java create mode 100644 aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java create mode 100644 aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextEmbeddingGenerationServiceTest.java create mode 100644 aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextRerankingServiceTest.java create mode 100644 semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java create mode 100644 semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/TextRerankingService.java diff --git a/PACKAGES.md b/PACKAGES.md index a6e2dc7a4..eab2cdf08 100644 --- a/PACKAGES.md +++ b/PACKAGES.md @@ -39,6 +39,9 @@ A BOM is provided that can be used to define the versions of all Semantic Kernel `semantickernel-aiservices-openai` : Provides a connector that can be used to interact with the OpenAI API. +`semantickernel-aiservices-voyageai` +: Provides connectors for VoyageAI's embedding and reranking services, including text embeddings, contextualized embeddings, multimodal embeddings, and document reranking. + ## Example Configurations ### Example: OpenAI + SQLite @@ -72,5 +75,36 @@ POM XML for a simple project that uses OpenAI. ``` +### Example: VoyageAI Embeddings and Reranking + +POM XML for a project that uses VoyageAI for embeddings and reranking. + +```xml + + + + + + com.microsoft.semantic-kernel + semantickernel-bom + ${semantickernel.version} + import + pom + + + + + + com.microsoft.semantic-kernel + semantickernel-api + + + com.microsoft.semantic-kernel + semantickernel-aiservices-voyageai + + + +``` + diff --git a/aiservices/voyageai/pom.xml b/aiservices/voyageai/pom.xml new file mode 100644 index 000000000..db0d06a44 --- /dev/null +++ b/aiservices/voyageai/pom.xml @@ -0,0 +1,89 @@ + + + 4.0.0 + + com.microsoft.semantic-kernel + semantickernel-parent + 1.4.4-RC3-SNAPSHOT + ../../pom.xml + + + semantickernel-aiservices-voyageai + Semantic Kernel VoyageAI Services + VoyageAI services for Semantic Kernel + + + + com.microsoft.semantic-kernel + semantickernel-api + + + com.microsoft.semantic-kernel + semantickernel-api-builders + + + com.microsoft.semantic-kernel + semantickernel-api-ai-services + + + com.microsoft.semantic-kernel + semantickernel-api-textembedding-services + + + com.microsoft.semantic-kernel + semantickernel-api-exceptions + + + com.microsoft.semantic-kernel + semantickernel-api-localization + + + + com.fasterxml.jackson.core + jackson-databind + compile + + + com.fasterxml.jackson.core + jackson-core + compile + + + com.fasterxml.jackson.core + jackson-annotations + compile + + + + + com.squareup.okhttp3 + okhttp + 4.12.0 + + + + + io.projectreactor + reactor-core + + + + + org.slf4j + slf4j-api + + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + + diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java new file mode 100644 index 000000000..e04f6794e --- /dev/null +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java @@ -0,0 +1,204 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * VoyageAI contextualized embedding generation service. + * Generates embeddings that capture both local chunk details and global document-level metadata. + * Supports models like voyage-3. + */ +public class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService { + + private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class); + + private final VoyageAIClient client; + private final String modelId; + private final String serviceId; + + /** + * Creates a new instance of VoyageAI contextualized embedding generation service. + * + * @param client VoyageAI client + * @param modelId Model ID (e.g., "voyage-3") + * @param serviceId Optional service ID + */ + public VoyageAIContextualizedEmbeddingGenerationService( + VoyageAIClient client, + String modelId, + @Nullable String serviceId) { + + if (client == null) { + throw new IllegalArgumentException("Client cannot be null"); + } + if (modelId == null || modelId.trim().isEmpty()) { + throw new IllegalArgumentException("Model ID cannot be null or empty"); + } + + this.client = client; + this.modelId = modelId; + this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getModelId() { + return modelId; + } + + /** + * Generates contextualized embeddings for document chunks. + * + * @param inputs List of lists where each inner list contains document chunks + * @return A Mono containing a list of embeddings for all chunks across all documents + */ + public Mono> generateContextualizedEmbeddingsAsync(List> inputs) { + if (inputs == null || inputs.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + LOGGER.debug("Generating contextualized embeddings for {} document groups using model {}", + inputs.size(), modelId); + + VoyageAIModels.ContextualizedEmbeddingRequest request = + new VoyageAIModels.ContextualizedEmbeddingRequest(); + request.setInputs(inputs); + request.setModel(modelId); + + return client.sendRequestAsync( + "contextualizedembeddings", + request, + VoyageAIModels.ContextualizedEmbeddingResponse.class) + .map(response -> { + List embeddings = new ArrayList<>(); + // Parse nested data structure: {"data":[{"data":[{"embedding":[...]}]}]} + for (VoyageAIModels.ContextualizedEmbeddingDataList dataList : response.getData()) { + for (VoyageAIModels.EmbeddingDataItem item : dataList.getData()) { + embeddings.add(new Embedding(item.getEmbedding())); + } + } + + LOGGER.debug("Received {} contextualized embeddings from VoyageAI", embeddings.size()); + return embeddings; + }); + } + + /** + * Generates embeddings for the given text. + * For standard text embedding, wraps the data as a single input. + * + * @param data The text to generate embeddings for + * @return A Mono that completes with the embedding + */ + @Override + public Mono generateEmbeddingAsync(String data) { + return generateEmbeddingsAsync(Arrays.asList(data)) + .flatMap(embeddings -> { + if (embeddings.isEmpty()) { + return Mono.empty(); + } + return Mono.just(embeddings.get(0)); + }); + } + + /** + * Generates embeddings for the given texts. + * Each text is treated as a separate document for contextualized embeddings. + * + * @param data The texts to generate embeddings for + * @return A Mono that completes with the list of embeddings + */ + @Override + public Mono> generateEmbeddingsAsync(List data) { + if (data == null || data.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + // Convert each string to a single-element list for contextualized embeddings + List> inputs = new ArrayList<>(); + for (String text : data) { + inputs.add(Arrays.asList(text)); + } + + return generateContextualizedEmbeddingsAsync(inputs); + } + + /** + * Creates a builder for VoyageAI contextualized embedding generation service. + * + * @return A new builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link VoyageAIContextualizedEmbeddingGenerationService}. + */ + public static class Builder { + private VoyageAIClient client; + private String modelId; + private String serviceId; + + /** + * Sets the VoyageAI client. + * + * @param client VoyageAI client + * @return This builder + */ + public Builder withClient(VoyageAIClient client) { + this.client = client; + return this; + } + + /** + * Sets the model ID. + * + * @param modelId Model ID (e.g., "voyage-3") + * @return This builder + */ + public Builder withModelId(String modelId) { + this.modelId = modelId; + return this; + } + + /** + * Sets the service ID. + * + * @param serviceId Service ID + * @return This builder + */ + public Builder withServiceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + /** + * Builds the VoyageAI contextualized embedding generation service. + * + * @return A new instance of VoyageAIContextualizedEmbeddingGenerationService + */ + public VoyageAIContextualizedEmbeddingGenerationService build() { + return new VoyageAIContextualizedEmbeddingGenerationService(client, modelId, serviceId); + } + } +} diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java new file mode 100644 index 000000000..95188ea5b --- /dev/null +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java @@ -0,0 +1,132 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai.core; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.PropertyNamingStrategies; +import com.microsoft.semantickernel.exceptions.AIException; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import javax.annotation.Nullable; +import java.io.IOException; +import java.util.concurrent.TimeUnit; + +/** + * HTTP client for VoyageAI API. + */ +public class VoyageAIClient { + private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIClient.class); + private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); + private static final String DEFAULT_ENDPOINT = "https://api.voyageai.com/v1"; + + private final OkHttpClient httpClient; + private final String apiKey; + private final String endpoint; + private final ObjectMapper objectMapper; + + /** + * Creates a new VoyageAI client. + * + * @param apiKey VoyageAI API key + * @param endpoint Optional API endpoint (defaults to https://api.voyageai.com/v1) + * @param httpClient Optional HTTP client + */ + public VoyageAIClient( + String apiKey, + @Nullable String endpoint, + @Nullable OkHttpClient httpClient) { + + if (apiKey == null || apiKey.trim().isEmpty()) { + throw new IllegalArgumentException("API key cannot be null or empty"); + } + + this.apiKey = apiKey; + this.endpoint = endpoint != null ? endpoint : DEFAULT_ENDPOINT; + this.httpClient = httpClient != null ? httpClient : createDefaultHttpClient(); + this.objectMapper = createObjectMapper(); + } + + /** + * Creates a new VoyageAI client with default HTTP client and endpoint. + * + * @param apiKey VoyageAI API key + */ + public VoyageAIClient(String apiKey) { + this(apiKey, null, null); + } + + private static OkHttpClient createDefaultHttpClient() { + return new OkHttpClient.Builder() + .connectTimeout(30, TimeUnit.SECONDS) + .readTimeout(60, TimeUnit.SECONDS) + .writeTimeout(30, TimeUnit.SECONDS) + .build(); + } + + private static ObjectMapper createObjectMapper() { + ObjectMapper mapper = new ObjectMapper(); + mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE); + return mapper; + } + + /** + * Sends a request to the VoyageAI API. + * + * @param path API path (e.g., "embeddings", "rerank") + * @param requestBody Request body object + * @param responseType Response type class + * @param Response type + * @return Mono containing the response + */ + public Mono sendRequestAsync( + String path, + Object requestBody, + Class responseType) { + + return Mono.fromCallable(() -> { + String requestUri = endpoint + "/" + path; + + LOGGER.debug("Sending VoyageAI request to {}", requestUri); + + String json = objectMapper.writeValueAsString(requestBody); + LOGGER.trace("Request body: {}", json); + + RequestBody body = RequestBody.create(json, JSON); + + Request request = new Request.Builder() + .url(requestUri) + .addHeader("Authorization", "Bearer " + apiKey) + .addHeader("Accept", "application/json") + .post(body) + .build(); + + try (Response response = httpClient.newCall(request).execute()) { + String responseBody = response.body() != null ? response.body().string() : ""; + + if (!response.isSuccessful()) { + LOGGER.error("VoyageAI API request failed with status {}: {}", + response.code(), responseBody); + throw new AIException(AIException.ErrorCodes.SERVICE_ERROR, + String.format("VoyageAI API request failed with status %d: %s", + response.code(), responseBody)); + } + + LOGGER.trace("Response body: {}", responseBody); + + T result = objectMapper.readValue(responseBody, responseType); + if (result == null) { + throw new AIException(AIException.ErrorCodes.SERVICE_ERROR, + "Failed to deserialize VoyageAI response: " + responseBody); + } + + return result; + } + }); + } +} diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java new file mode 100644 index 000000000..b196d9e00 --- /dev/null +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java @@ -0,0 +1,606 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai.core; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import java.util.List; + +/** + * VoyageAI API request and response models. + */ +public class VoyageAIModels { + + // Embedding Models + + /** + * Request model for text embeddings. + */ + public static class EmbeddingRequest { + @JsonProperty("input") + private List input; + + @JsonProperty("model") + private String model; + + @JsonProperty("input_type") + private String inputType; + + @JsonProperty("truncation") + private Boolean truncation; + + @JsonProperty("output_dimension") + private Integer outputDimension; + + @JsonProperty("output_dtype") + private String outputDtype; + + public List getInput() { + return input; + } + + public void setInput(List input) { + this.input = input; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getInputType() { + return inputType; + } + + public void setInputType(String inputType) { + this.inputType = inputType; + } + + public Boolean getTruncation() { + return truncation; + } + + public void setTruncation(Boolean truncation) { + this.truncation = truncation; + } + + public Integer getOutputDimension() { + return outputDimension; + } + + public void setOutputDimension(Integer outputDimension) { + this.outputDimension = outputDimension; + } + + public String getOutputDtype() { + return outputDtype; + } + + public void setOutputDtype(String outputDtype) { + this.outputDtype = outputDtype; + } + } + + /** + * Response model for embeddings. + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class EmbeddingResponse { + @JsonProperty("data") + private List data; + + @JsonProperty("usage") + private EmbeddingUsage usage; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public EmbeddingUsage getUsage() { + return usage; + } + + public void setUsage(EmbeddingUsage usage) { + this.usage = usage; + } + } + + /** + * Embedding data item. + */ + public static class EmbeddingDataItem { + @JsonProperty("object") + private String object; + + @JsonProperty("embedding") + private float[] embedding; + + @JsonProperty("index") + private int index; + + public String getObject() { + return object; + } + + public void setObject(String object) { + this.object = object; + } + + public float[] getEmbedding() { + return embedding; + } + + public void setEmbedding(float[] embedding) { + this.embedding = embedding; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + } + + /** + * Usage information. + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class EmbeddingUsage { + @JsonProperty("total_tokens") + private int totalTokens; + + public int getTotalTokens() { + return totalTokens; + } + + public void setTotalTokens(int totalTokens) { + this.totalTokens = totalTokens; + } + } + + // Reranking Models + + /** + * Request model for reranking. + */ + public static class RerankRequest { + @JsonProperty("query") + private String query; + + @JsonProperty("documents") + private List documents; + + @JsonProperty("model") + private String model; + + @JsonProperty("top_k") + private Integer topK; + + @JsonProperty("truncation") + private Boolean truncation; + + public String getQuery() { + return query; + } + + public void setQuery(String query) { + this.query = query; + } + + public List getDocuments() { + return documents; + } + + public void setDocuments(List documents) { + this.documents = documents; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public Integer getTopK() { + return topK; + } + + public void setTopK(Integer topK) { + this.topK = topK; + } + + public Boolean getTruncation() { + return truncation; + } + + public void setTruncation(Boolean truncation) { + this.truncation = truncation; + } + } + + /** + * Response model for reranking. + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class RerankResponse { + @JsonProperty("data") + private List data; + + @JsonProperty("usage") + private EmbeddingUsage usage; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public EmbeddingUsage getUsage() { + return usage; + } + + public void setUsage(EmbeddingUsage usage) { + this.usage = usage; + } + } + + /** + * Rerank data item. + */ + public static class RerankDataItem { + @JsonProperty("index") + private int index; + + @JsonProperty("relevance_score") + private double relevanceScore; + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + + public double getRelevanceScore() { + return relevanceScore; + } + + public void setRelevanceScore(double relevanceScore) { + this.relevanceScore = relevanceScore; + } + } + + // Contextualized Embedding Models + + /** + * Request model for contextualized embeddings. + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class ContextualizedEmbeddingRequest { + @JsonProperty("inputs") + private List> inputs; + + @JsonProperty("model") + private String model; + + @JsonProperty("input_type") + private String inputType; + + @JsonProperty("truncation") + private Boolean truncation; + + @JsonProperty("output_dimension") + private Integer outputDimension; + + @JsonProperty("output_dtype") + private String outputDtype; + + public List> getInputs() { + return inputs; + } + + public void setInputs(List> inputs) { + this.inputs = inputs; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getInputType() { + return inputType; + } + + public void setInputType(String inputType) { + this.inputType = inputType; + } + + public Boolean getTruncation() { + return truncation; + } + + public void setTruncation(Boolean truncation) { + this.truncation = truncation; + } + + public Integer getOutputDimension() { + return outputDimension; + } + + public void setOutputDimension(Integer outputDimension) { + this.outputDimension = outputDimension; + } + + public String getOutputDtype() { + return outputDtype; + } + + public void setOutputDtype(String outputDtype) { + this.outputDtype = outputDtype; + } + } + + /** + * Response model for contextualized embeddings. + * VoyageAI returns a nested list structure: {"object":"list","data":[{"object":"list","data":[...]}]} + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ContextualizedEmbeddingResponse { + @JsonProperty("data") + private List data; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + } + + /** + * Nested data list for contextualized embeddings. + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class ContextualizedEmbeddingDataList { + @JsonProperty("data") + private List data; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + } + + /** + * Contextualized embedding result. + */ + public static class ContextualizedEmbeddingResult { + @JsonProperty("embeddings") + private List embeddings; + + public List getEmbeddings() { + return embeddings; + } + + public void setEmbeddings(List embeddings) { + this.embeddings = embeddings; + } + } + + /** + * Embedding item with chunk information. + */ + public static class EmbeddingItem { + @JsonProperty("embedding") + private float[] embedding; + + @JsonProperty("chunk") + private String chunk; + + @JsonProperty("index") + private int index; + + public float[] getEmbedding() { + return embedding; + } + + public void setEmbedding(float[] embedding) { + this.embedding = embedding; + } + + public String getChunk() { + return chunk; + } + + public void setChunk(String chunk) { + this.chunk = chunk; + } + + public int getIndex() { + return index; + } + + public void setIndex(int index) { + this.index = index; + } + } + + // Multimodal Embedding Models + + /** + * Content item for multimodal input (text or image). + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class MultimodalContentItem { + @JsonProperty("type") + private String type; // "text" or "image_url" + + @JsonProperty("text") + private String text; + + @JsonProperty("image_url") + private String imageUrl; + + public MultimodalContentItem() { + // Default constructor for Jackson + } + + public MultimodalContentItem(String type, String value) { + this.type = type; + if ("text".equals(type)) { + this.text = value; + } else if ("image_url".equals(type)) { + this.imageUrl = value; + } + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getText() { + return text; + } + + public void setText(String text) { + this.text = text; + } + + public String getImageUrl() { + return imageUrl; + } + + public void setImageUrl(String imageUrl) { + this.imageUrl = imageUrl; + } + } + + /** + * Input for multimodal embedding (contains a list of content items). + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class MultimodalInput { + @JsonProperty("content") + private List content; + + public MultimodalInput() { + // Default constructor for Jackson + } + + public MultimodalInput(List content) { + this.content = content; + } + + public List getContent() { + return content; + } + + public void setContent(List content) { + this.content = content; + } + } + + /** + * Request model for multimodal embeddings. + */ + @JsonInclude(JsonInclude.Include.NON_NULL) + public static class MultimodalEmbeddingRequest { + @JsonProperty("inputs") + private List inputs; + + @JsonProperty("model") + private String model; + + @JsonProperty("input_type") + private String inputType; + + @JsonProperty("truncation") + private Boolean truncation; + + public List getInputs() { + return inputs; + } + + public void setInputs(List inputs) { + this.inputs = inputs; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + public String getInputType() { + return inputType; + } + + public void setInputType(String inputType) { + this.inputType = inputType; + } + + public Boolean getTruncation() { + return truncation; + } + + public void setTruncation(Boolean truncation) { + this.truncation = truncation; + } + } + + /** + * Response model for multimodal embeddings. + */ + @JsonIgnoreProperties(ignoreUnknown = true) + public static class MultimodalEmbeddingResponse { + @JsonProperty("data") + private List data; + + @JsonProperty("usage") + private EmbeddingUsage usage; + + public List getData() { + return data; + } + + public void setData(List data) { + this.data = data; + } + + public EmbeddingUsage getUsage() { + return usage; + } + + public void setUsage(EmbeddingUsage usage) { + this.usage = usage; + } + } +} diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java new file mode 100644 index 000000000..239d29b5d --- /dev/null +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java @@ -0,0 +1,227 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai.multimodalembedding; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import javax.annotation.Nullable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * VoyageAI multimodal embedding generation service. + * Generates embeddings for text, images, or interleaved text and images. + * Supports the voyage-multimodal-3 model. + *

+ * Constraints: + * - Maximum 1,000 inputs per request + * - Images: ≤16 million pixels, ≤20 MB + * - Total tokens per input: ≤32,000 (560 pixels = 1 token) + * - Aggregate tokens across inputs: ≤320,000 + */ +public class VoyageAIMultimodalEmbeddingGenerationService implements TextEmbeddingGenerationService { + + private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIMultimodalEmbeddingGenerationService.class); + + private final VoyageAIClient client; + private final String modelId; + private final String serviceId; + + /** + * Creates a new instance of VoyageAI multimodal embedding generation service. + * + * @param client VoyageAI client + * @param modelId Model ID (e.g., "voyage-multimodal-3") + * @param serviceId Optional service ID + */ + public VoyageAIMultimodalEmbeddingGenerationService( + VoyageAIClient client, + String modelId, + @Nullable String serviceId) { + + if (client == null) { + throw new IllegalArgumentException("Client cannot be null"); + } + if (modelId == null || modelId.trim().isEmpty()) { + throw new IllegalArgumentException("Model ID cannot be null or empty"); + } + + this.client = client; + this.modelId = modelId; + this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getModelId() { + return modelId; + } + + /** + * Generates multimodal embeddings for text and/or images. + * + * @param inputs List of multimodal inputs + * @return A Mono containing a list of multimodal embeddings + */ + public Mono> generateMultimodalEmbeddingsAsync(List inputs) { + if (inputs == null || inputs.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + LOGGER.debug("Generating multimodal embeddings for {} inputs using model {}", inputs.size(), modelId); + + VoyageAIModels.MultimodalEmbeddingRequest request = new VoyageAIModels.MultimodalEmbeddingRequest(); + request.setInputs(inputs); + request.setModel(modelId); + + return client.sendRequestAsync("multimodalembeddings", request, VoyageAIModels.MultimodalEmbeddingResponse.class) + .map(response -> { + LOGGER.debug("Received {} multimodal embeddings from VoyageAI", response.getData().size()); + + List embeddings = response.getData().stream() + .sorted(Comparator.comparingInt(VoyageAIModels.EmbeddingDataItem::getIndex)) + .map(item -> new Embedding(item.getEmbedding())) + .collect(Collectors.toList()); + + return embeddings; + }); + } + + /** + * Generates embeddings for the given text. + * For text-only input, converts to multimodal format. + * + * @param data The text to generate embeddings for + * @return A Mono that completes with the embedding + */ + @Override + public Mono generateEmbeddingAsync(String data) { + return generateEmbeddingsAsync(Arrays.asList(data)) + .flatMap(embeddings -> { + if (embeddings.isEmpty()) { + return Mono.empty(); + } + return Mono.just(embeddings.get(0)); + }); + } + + /** + * Generates embeddings for the given texts. + * Converts text-only inputs to multimodal format. + * + * @param data The texts to generate embeddings for + * @return A Mono that completes with the list of embeddings + */ + @Override + public Mono> generateEmbeddingsAsync(List data) { + if (data == null || data.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + // Convert each text to multimodal input format + List inputs = new ArrayList<>(); + for (String text : data) { + VoyageAIModels.MultimodalContentItem contentItem = + new VoyageAIModels.MultimodalContentItem("text", text); + VoyageAIModels.MultimodalInput input = + new VoyageAIModels.MultimodalInput(Arrays.asList(contentItem)); + inputs.add(input); + } + + if (inputs.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + LOGGER.debug("Generating multimodal embeddings for {} inputs using model {}", inputs.size(), modelId); + + VoyageAIModels.MultimodalEmbeddingRequest request = new VoyageAIModels.MultimodalEmbeddingRequest(); + request.setInputs(inputs); + request.setModel(modelId); + + return client.sendRequestAsync("multimodalembeddings", request, VoyageAIModels.MultimodalEmbeddingResponse.class) + .map(response -> { + LOGGER.debug("Received {} multimodal embeddings from VoyageAI", response.getData().size()); + + List embeddings = response.getData().stream() + .sorted(Comparator.comparingInt(VoyageAIModels.EmbeddingDataItem::getIndex)) + .map(item -> new Embedding(item.getEmbedding())) + .collect(Collectors.toList()); + + return embeddings; + }); + } + + /** + * Creates a builder for VoyageAI multimodal embedding generation service. + * + * @return A new builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link VoyageAIMultimodalEmbeddingGenerationService}. + */ + public static class Builder { + private VoyageAIClient client; + private String modelId; + private String serviceId; + + /** + * Sets the VoyageAI client. + * + * @param client VoyageAI client + * @return This builder + */ + public Builder withClient(VoyageAIClient client) { + this.client = client; + return this; + } + + /** + * Sets the model ID. + * + * @param modelId Model ID (e.g., "voyage-multimodal-3") + * @return This builder + */ + public Builder withModelId(String modelId) { + this.modelId = modelId; + return this; + } + + /** + * Sets the service ID. + * + * @param serviceId Service ID + * @return This builder + */ + public Builder withServiceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + /** + * Builds the VoyageAI multimodal embedding generation service. + * + * @return A new instance of VoyageAIMultimodalEmbeddingGenerationService + */ + public VoyageAIMultimodalEmbeddingGenerationService build() { + return new VoyageAIMultimodalEmbeddingGenerationService(client, modelId, serviceId); + } + } +} diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java new file mode 100644 index 000000000..6b0f59fa6 --- /dev/null +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java @@ -0,0 +1,182 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai.reranking; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; +import com.microsoft.semantickernel.services.reranking.RerankResult; +import com.microsoft.semantickernel.services.reranking.TextRerankingService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import javax.annotation.Nullable; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * VoyageAI implementation of {@link TextRerankingService}. + * Supports models like rerank-2, rerank-2-lite. + */ +public class VoyageAITextRerankingService implements TextRerankingService { + + private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAITextRerankingService.class); + + private final VoyageAIClient client; + private final String modelId; + private final String serviceId; + private final Integer topK; + + /** + * Creates a new instance of VoyageAI text reranking service. + * + * @param client VoyageAI client + * @param modelId Model ID (e.g., "rerank-2") + * @param serviceId Optional service ID + * @param topK Optional top K results to return + */ + public VoyageAITextRerankingService( + VoyageAIClient client, + String modelId, + @Nullable String serviceId, + @Nullable Integer topK) { + + if (client == null) { + throw new IllegalArgumentException("Client cannot be null"); + } + if (modelId == null || modelId.trim().isEmpty()) { + throw new IllegalArgumentException("Model ID cannot be null or empty"); + } + + this.client = client; + this.modelId = modelId; + this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID; + this.topK = topK; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getModelId() { + return modelId; + } + + /** + * Reranks documents based on their relevance to the query. + * + * @param query The query to rank documents against + * @param documents The list of documents to rerank + * @return A Mono containing a list of {@link RerankResult} sorted by relevance score in descending order + */ + @Override + public Mono> rerankAsync(String query, List documents) { + if (query == null || query.trim().isEmpty()) { + throw new IllegalArgumentException("Query cannot be null or empty"); + } + if (documents == null || documents.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + LOGGER.debug("Reranking {} documents using model {}", documents.size(), modelId); + + VoyageAIModels.RerankRequest request = new VoyageAIModels.RerankRequest(); + request.setQuery(query); + request.setDocuments(documents); + request.setModel(modelId); + request.setTopK(topK); + request.setTruncation(true); + + return client.sendRequestAsync("rerank", request, VoyageAIModels.RerankResponse.class) + .map(response -> { + LOGGER.debug("Received {} reranked results from VoyageAI", response.getData().size()); + + List results = response.getData().stream() + .sorted(Comparator.comparingDouble(VoyageAIModels.RerankDataItem::getRelevanceScore).reversed()) + .map(item -> new RerankResult( + item.getIndex(), + documents.get(item.getIndex()), + item.getRelevanceScore() + )) + .collect(Collectors.toList()); + + return results; + }); + } + + /** + * Creates a builder for VoyageAI text reranking service. + * + * @return A new builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link VoyageAITextRerankingService}. + */ + public static class Builder { + private VoyageAIClient client; + private String modelId; + private String serviceId; + private Integer topK; + + /** + * Sets the VoyageAI client. + * + * @param client VoyageAI client + * @return This builder + */ + public Builder withClient(VoyageAIClient client) { + this.client = client; + return this; + } + + /** + * Sets the model ID. + * + * @param modelId Model ID (e.g., "rerank-2") + * @return This builder + */ + public Builder withModelId(String modelId) { + this.modelId = modelId; + return this; + } + + /** + * Sets the service ID. + * + * @param serviceId Service ID + * @return This builder + */ + public Builder withServiceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + /** + * Sets the top K results to return. + * + * @param topK Top K results + * @return This builder + */ + public Builder withTopK(Integer topK) { + this.topK = topK; + return this; + } + + /** + * Builds the VoyageAI text reranking service. + * + * @return A new instance of VoyageAITextRerankingService + */ + public VoyageAITextRerankingService build() { + return new VoyageAITextRerankingService(client, modelId, serviceId, topK); + } + } +} diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java new file mode 100644 index 000000000..22a393532 --- /dev/null +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java @@ -0,0 +1,174 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai.textembedding; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.orchestration.PromptExecutionSettings; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import com.microsoft.semantickernel.services.textembedding.TextEmbeddingGenerationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import reactor.core.publisher.Mono; + +import javax.annotation.Nullable; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * VoyageAI implementation of {@link TextEmbeddingGenerationService}. + * Supports models like voyage-3-large, voyage-3.5, voyage-code-3, voyage-finance-2, voyage-law-2. + */ +public class VoyageAITextEmbeddingGenerationService implements TextEmbeddingGenerationService { + + private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAITextEmbeddingGenerationService.class); + + private final VoyageAIClient client; + private final String modelId; + private final String serviceId; + + /** + * Creates a new instance of VoyageAI text embedding generation service. + * + * @param client VoyageAI client + * @param modelId Model ID (e.g., "voyage-3-large") + * @param serviceId Optional service ID + */ + public VoyageAITextEmbeddingGenerationService( + VoyageAIClient client, + String modelId, + @Nullable String serviceId) { + + if (client == null) { + throw new IllegalArgumentException("Client cannot be null"); + } + if (modelId == null || modelId.trim().isEmpty()) { + throw new IllegalArgumentException("Model ID cannot be null or empty"); + } + + this.client = client; + this.modelId = modelId; + this.serviceId = serviceId != null ? serviceId : PromptExecutionSettings.DEFAULT_SERVICE_ID; + } + + @Override + public String getServiceId() { + return serviceId; + } + + @Override + public String getModelId() { + return modelId; + } + + /** + * Generates embeddings for the given text. + * + * @param data The text to generate embeddings for + * @return A Mono that completes with the embedding + */ + @Override + public Mono generateEmbeddingAsync(String data) { + return generateEmbeddingsAsync(Arrays.asList(data)) + .flatMap(embeddings -> { + if (embeddings.isEmpty()) { + return Mono.empty(); + } + return Mono.just(embeddings.get(0)); + }); + } + + /** + * Generates embeddings for the given texts. + * + * @param data The texts to generate embeddings for + * @return A Mono that completes with the list of embeddings + */ + @Override + public Mono> generateEmbeddingsAsync(List data) { + if (data == null || data.isEmpty()) { + return Mono.just(Collections.emptyList()); + } + + LOGGER.debug("Generating embeddings for {} texts using model {}", data.size(), modelId); + + VoyageAIModels.EmbeddingRequest request = new VoyageAIModels.EmbeddingRequest(); + request.setInput(data); + request.setModel(modelId); + request.setTruncation(true); + + return client.sendRequestAsync("embeddings", request, VoyageAIModels.EmbeddingResponse.class) + .map(response -> { + LOGGER.debug("Received {} embeddings from VoyageAI", response.getData().size()); + + List embeddings = response.getData().stream() + .sorted(Comparator.comparingInt(VoyageAIModels.EmbeddingDataItem::getIndex)) + .map(item -> new Embedding(item.getEmbedding())) + .collect(Collectors.toList()); + + return embeddings; + }); + } + + /** + * Creates a builder for VoyageAI text embedding generation service. + * + * @return A new builder instance + */ + public static Builder builder() { + return new Builder(); + } + + /** + * Builder for {@link VoyageAITextEmbeddingGenerationService}. + */ + public static class Builder { + private VoyageAIClient client; + private String modelId; + private String serviceId; + + /** + * Sets the VoyageAI client. + * + * @param client VoyageAI client + * @return This builder + */ + public Builder withClient(VoyageAIClient client) { + this.client = client; + return this; + } + + /** + * Sets the model ID. + * + * @param modelId Model ID (e.g., "voyage-3-large") + * @return This builder + */ + public Builder withModelId(String modelId) { + this.modelId = modelId; + return this; + } + + /** + * Sets the service ID. + * + * @param serviceId Service ID + * @return This builder + */ + public Builder withServiceId(String serviceId) { + this.serviceId = serviceId; + return this; + } + + /** + * Builds the VoyageAI text embedding generation service. + * + * @return A new instance of VoyageAITextEmbeddingGenerationService + */ + public VoyageAITextEmbeddingGenerationService build() { + return new VoyageAITextEmbeddingGenerationService(client, modelId, serviceId); + } + } +} diff --git a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIContextualizedEmbeddingGenerationServiceTest.java b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIContextualizedEmbeddingGenerationServiceTest.java new file mode 100644 index 000000000..8b4d22609 --- /dev/null +++ b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIContextualizedEmbeddingGenerationServiceTest.java @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai; + +import com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding.VoyageAIContextualizedEmbeddingGenerationService; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +public class VoyageAIContextualizedEmbeddingGenerationServiceTest { + + @Test + public void testGenerateContextualizedEmbeddings() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.ContextualizedEmbeddingResponse mockResponse = + new VoyageAIModels.ContextualizedEmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item1 = new VoyageAIModels.EmbeddingDataItem(); + item1.setEmbedding(new float[]{0.1f, 0.2f}); + item1.setIndex(0); + + VoyageAIModels.EmbeddingDataItem item2 = new VoyageAIModels.EmbeddingDataItem(); + item2.setEmbedding(new float[]{0.3f, 0.4f}); + item2.setIndex(0); + + VoyageAIModels.ContextualizedEmbeddingDataList dataList1 = + new VoyageAIModels.ContextualizedEmbeddingDataList(); + dataList1.setData(Arrays.asList(item1)); + + VoyageAIModels.ContextualizedEmbeddingDataList dataList2 = + new VoyageAIModels.ContextualizedEmbeddingDataList(); + dataList2.setData(Arrays.asList(item2)); + + mockResponse.setData(Arrays.asList(dataList1, dataList2)); + + when(mockClient.sendRequestAsync( + eq("contextualizedembeddings"), + any(), + eq(VoyageAIModels.ContextualizedEmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAIContextualizedEmbeddingGenerationService service = + new VoyageAIContextualizedEmbeddingGenerationService(mockClient, "voyage-3", null); + + List> inputs = Arrays.asList( + Arrays.asList("chunk1"), + Arrays.asList("chunk2") + ); + + List results = service.generateContextualizedEmbeddingsAsync(inputs).block(); + + assertNotNull(results); + assertEquals(2, results.size()); + List expected1 = Arrays.asList(0.1f, 0.2f); + List expected2 = Arrays.asList(0.3f, 0.4f); + assertEquals(expected1, results.get(0).getVector()); + assertEquals(expected2, results.get(1).getVector()); + } + + @Test + public void testGenerateEmbedding() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.ContextualizedEmbeddingResponse mockResponse = + new VoyageAIModels.ContextualizedEmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item = new VoyageAIModels.EmbeddingDataItem(); + item.setEmbedding(new float[]{0.1f, 0.2f, 0.3f}); + item.setIndex(0); + + VoyageAIModels.ContextualizedEmbeddingDataList dataList = + new VoyageAIModels.ContextualizedEmbeddingDataList(); + dataList.setData(Arrays.asList(item)); + + mockResponse.setData(Arrays.asList(dataList)); + + when(mockClient.sendRequestAsync( + eq("contextualizedembeddings"), + any(), + eq(VoyageAIModels.ContextualizedEmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAIContextualizedEmbeddingGenerationService service = + new VoyageAIContextualizedEmbeddingGenerationService(mockClient, "voyage-3", null); + + Embedding result2 = service.generateEmbeddingAsync("test text").block(); + + assertNotNull(result2); + List expected = Arrays.asList(0.1f, 0.2f, 0.3f); + assertEquals(expected, result2.getVector()); + } + + @Test + public void testServiceIdAndModelId() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIContextualizedEmbeddingGenerationService service = + new VoyageAIContextualizedEmbeddingGenerationService(mockClient, "voyage-3", "test-service"); + + assertEquals("test-service", service.getServiceId()); + assertEquals("voyage-3", service.getModelId()); + } + + @Test + public void testBuilderPattern() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIContextualizedEmbeddingGenerationService service = + VoyageAIContextualizedEmbeddingGenerationService.builder() + .withClient(mockClient) + .withModelId("voyage-3") + .withServiceId("test-service") + .build(); + + assertNotNull(service); + assertEquals("test-service", service.getServiceId()); + assertEquals("voyage-3", service.getModelId()); + } + + @Test + public void testNullClientThrowsException() { + assertThrows(IllegalArgumentException.class, () -> + new VoyageAIContextualizedEmbeddingGenerationService(null, "voyage-3", null)); + } + + @Test + public void testNullModelIdThrowsException() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + assertThrows(IllegalArgumentException.class, () -> + new VoyageAIContextualizedEmbeddingGenerationService(mockClient, null, null)); + } +} diff --git a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIIntegrationTest.java b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIIntegrationTest.java new file mode 100644 index 000000000..b9631d644 --- /dev/null +++ b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIIntegrationTest.java @@ -0,0 +1,216 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai; + +import com.microsoft.semantickernel.aiservices.voyageai.contextualizedembedding.VoyageAIContextualizedEmbeddingGenerationService; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.multimodalembedding.VoyageAIMultimodalEmbeddingGenerationService; +import com.microsoft.semantickernel.aiservices.voyageai.reranking.VoyageAITextRerankingService; +import com.microsoft.semantickernel.aiservices.voyageai.textembedding.VoyageAITextEmbeddingGenerationService; +import com.microsoft.semantickernel.services.reranking.RerankResult; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +/** + * Integration tests for VoyageAI services. + * Requires VOYAGE_API_KEY environment variable to be set. + */ +public class VoyageAIIntegrationTest { + + private static final String API_KEY_ENV_VAR = "VOYAGE_API_KEY"; + private static final String DEFAULT_EMBEDDING_MODEL = "voyage-3-large"; + private static final String DEFAULT_CONTEXTUALIZED_MODEL = "voyage-context-3"; + private static final String DEFAULT_MULTIMODAL_MODEL = "voyage-multimodal-3"; + private static final String DEFAULT_RERANK_MODEL = "rerank-2"; + + private String apiKey; + + @BeforeEach + public void setUp() { + apiKey = System.getenv(API_KEY_ENV_VAR); + Assumptions.assumeTrue( + apiKey != null && !apiKey.isEmpty(), + "Skipping integration test: " + API_KEY_ENV_VAR + " environment variable not set" + ); + } + + @Test + public void testTextEmbeddingGeneration() { + VoyageAIClient client = new VoyageAIClient(apiKey); + VoyageAITextEmbeddingGenerationService service = + VoyageAITextEmbeddingGenerationService.builder() + .withClient(client) + .withModelId(DEFAULT_EMBEDDING_MODEL) + .build(); + + Embedding embedding = service.generateEmbeddingAsync("Hello, world!").block(); + + assertNotNull(embedding, "Embedding should not be null"); + assertNotNull(embedding.getVector(), "Embedding vector should not be null"); + assertTrue(embedding.getVector().size() > 0, "Embedding vector should not be empty"); + + System.out.println("Generated embedding with dimension: " + embedding.getVector().size()); + } + + @Test + public void testMultipleTextEmbeddings() { + VoyageAIClient client = new VoyageAIClient(apiKey); + VoyageAITextEmbeddingGenerationService service = + VoyageAITextEmbeddingGenerationService.builder() + .withClient(client) + .withModelId(DEFAULT_EMBEDDING_MODEL) + .build(); + + List texts = Arrays.asList( + "Hello, world!", + "Semantic Kernel is awesome", + "VoyageAI provides great embeddings" + ); + + List embeddings = service.generateEmbeddingsAsync(texts).block(); + + assertNotNull(embeddings, "Embeddings should not be null"); + assertEquals(3, embeddings.size(), "Should generate 3 embeddings"); + + for (Embedding embedding : embeddings) { + assertNotNull(embedding.getVector(), "Each embedding vector should not be null"); + assertTrue(embedding.getVector().size() > 0, "Each embedding vector should not be empty"); + } + + System.out.println("Generated " + embeddings.size() + " embeddings"); + } + + @Test + public void testTextReranking() { + VoyageAIClient client = new VoyageAIClient(apiKey); + VoyageAITextRerankingService service = + VoyageAITextRerankingService.builder() + .withClient(client) + .withModelId(DEFAULT_RERANK_MODEL) + .build(); + + String query = "What is the capital of France?"; + List documents = Arrays.asList( + "Paris is the capital and most populous city of France.", + "Berlin is the capital of Germany.", + "The Eiffel Tower is located in Paris.", + "London is the capital of the United Kingdom." + ); + + List results = service.rerankAsync(query, documents).block(); + + assertNotNull(results, "Rerank results should not be null"); + assertEquals(4, results.size(), "Should have 4 reranked results"); + + // The first result should have the highest relevance score + assertTrue(results.get(0).getRelevanceScore() >= results.get(1).getRelevanceScore(), + "Results should be sorted by relevance score descending"); + + System.out.println("Reranking results:"); + for (int i = 0; i < results.size(); i++) { + RerankResult result = results.get(i); + System.out.printf("%d. [Index: %d, Score: %.4f] %s%n", + i + 1, result.getIndex(), result.getRelevanceScore(), result.getText()); + } + + // The most relevant document should be about Paris being the capital + assertEquals(0, results.get(0).getIndex(), + "Most relevant document should be the one about Paris being the capital"); + } + + @Test + public void testRerankingWithTopK() { + VoyageAIClient client = new VoyageAIClient(apiKey); + VoyageAITextRerankingService service = + VoyageAITextRerankingService.builder() + .withClient(client) + .withModelId(DEFAULT_RERANK_MODEL) + .withTopK(2) + .build(); + + String query = "Machine learning"; + List documents = Arrays.asList( + "Machine learning is a subset of artificial intelligence.", + "Cooking is an art form.", + "Deep learning uses neural networks.", + "The weather is nice today." + ); + + List results = service.rerankAsync(query, documents).block(); + + assertNotNull(results, "Rerank results should not be null"); + // VoyageAI might return all results sorted, or just top K + assertTrue(results.size() >= 2, "Should have at least 2 results"); + + System.out.println("Top K reranking results:"); + for (RerankResult result : results) { + System.out.printf("[Index: %d, Score: %.4f] %s%n", + result.getIndex(), result.getRelevanceScore(), result.getText()); + } + } + + @Test + public void testContextualizedEmbeddings() { + VoyageAIClient client = new VoyageAIClient(apiKey); + VoyageAIContextualizedEmbeddingGenerationService service = + VoyageAIContextualizedEmbeddingGenerationService.builder() + .withClient(client) + .withModelId(DEFAULT_CONTEXTUALIZED_MODEL) + .build(); + + // Create document chunks with context + List> inputs = Arrays.asList( + Arrays.asList("Introduction to semantic kernel", "Semantic kernel is a framework"), + Arrays.asList("VoyageAI provides embeddings", "VoyageAI is an AI company") + ); + + List embeddings = service.generateContextualizedEmbeddingsAsync(inputs).block(); + + assertNotNull(embeddings, "Contextualized embeddings should not be null"); + // Each input document has 2 chunks, so we expect 4 embeddings total (2 documents * 2 chunks each) + assertEquals(4, embeddings.size(), "Should generate 4 embeddings (2 per document)"); + + for (Embedding embedding : embeddings) { + assertNotNull(embedding.getVector(), "Each embedding vector should not be null"); + assertTrue(embedding.getVector().size() > 0, "Each embedding vector should not be empty"); + } + + System.out.println("Generated " + embeddings.size() + " contextualized embeddings"); + } + + @Test + public void testMultimodalEmbeddings() { + VoyageAIClient client = new VoyageAIClient(apiKey); + VoyageAIMultimodalEmbeddingGenerationService service = + VoyageAIMultimodalEmbeddingGenerationService.builder() + .withClient(client) + .withModelId(DEFAULT_MULTIMODAL_MODEL) + .build(); + + // Test using generateEmbeddingsAsync which handles text conversion + List texts = Arrays.asList( + "This is a text description", + "Another text example" + ); + + List embeddings = service.generateEmbeddingsAsync(texts).block(); + + assertNotNull(embeddings, "Multimodal embeddings should not be null"); + assertEquals(2, embeddings.size(), "Should generate 2 embeddings"); + + for (Embedding embedding : embeddings) { + assertNotNull(embedding.getVector(), "Each embedding vector should not be null"); + assertTrue(embedding.getVector().size() > 0, "Each embedding vector should not be empty"); + } + + System.out.println("Generated " + embeddings.size() + " multimodal embeddings"); + System.out.println("Embedding dimension: " + embeddings.get(0).getVector().size()); + } +} diff --git a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java new file mode 100644 index 000000000..537958d2b --- /dev/null +++ b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java @@ -0,0 +1,181 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.aiservices.voyageai.multimodalembedding.VoyageAIMultimodalEmbeddingGenerationService; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +public class VoyageAIMultimodalEmbeddingGenerationServiceTest { + + @Test + public void testGenerateMultimodalEmbeddings() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.MultimodalEmbeddingResponse mockResponse = + new VoyageAIModels.MultimodalEmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item1 = new VoyageAIModels.EmbeddingDataItem(); + item1.setEmbedding(new float[]{0.1f, 0.2f}); + item1.setIndex(0); + + VoyageAIModels.EmbeddingDataItem item2 = new VoyageAIModels.EmbeddingDataItem(); + item2.setEmbedding(new float[]{0.3f, 0.4f}); + item2.setIndex(1); + + mockResponse.setData(Arrays.asList(item1, item2)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(20); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("multimodalembeddings"), + any(), + eq(VoyageAIModels.MultimodalEmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAIMultimodalEmbeddingGenerationService service = + new VoyageAIMultimodalEmbeddingGenerationService(mockClient, "voyage-multimodal-3", null); + + // Create properly structured multimodal inputs + VoyageAIModels.MultimodalContentItem content1 = new VoyageAIModels.MultimodalContentItem("text", "text1"); + VoyageAIModels.MultimodalContentItem content2 = new VoyageAIModels.MultimodalContentItem("text", "text2"); + VoyageAIModels.MultimodalInput input1 = new VoyageAIModels.MultimodalInput(Arrays.asList(content1)); + VoyageAIModels.MultimodalInput input2 = new VoyageAIModels.MultimodalInput(Arrays.asList(content2)); + List inputs = Arrays.asList(input1, input2); + + List results = service.generateMultimodalEmbeddingsAsync(inputs).block(); + + assertNotNull(results); + assertEquals(2, results.size()); + List expected1 = Arrays.asList(0.1f, 0.2f); + List expected2 = Arrays.asList(0.3f, 0.4f); + assertEquals(expected1, results.get(0).getVector()); + assertEquals(expected2, results.get(1).getVector()); + } + + @Test + public void testGenerateEmbedding() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.MultimodalEmbeddingResponse mockResponse = + new VoyageAIModels.MultimodalEmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item = new VoyageAIModels.EmbeddingDataItem(); + item.setEmbedding(new float[]{0.1f, 0.2f, 0.3f}); + item.setIndex(0); + + mockResponse.setData(Arrays.asList(item)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(10); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("multimodalembeddings"), + any(), + eq(VoyageAIModels.MultimodalEmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAIMultimodalEmbeddingGenerationService service = + new VoyageAIMultimodalEmbeddingGenerationService(mockClient, "voyage-multimodal-3", null); + + Embedding result = service.generateEmbeddingAsync("test text").block(); + + assertNotNull(result); + List expected = Arrays.asList(0.1f, 0.2f, 0.3f); + assertEquals(expected, result.getVector()); + } + + @Test + public void testGenerateEmbeddingsFromTextList() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.MultimodalEmbeddingResponse mockResponse = + new VoyageAIModels.MultimodalEmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item1 = new VoyageAIModels.EmbeddingDataItem(); + item1.setEmbedding(new float[]{0.1f, 0.2f}); + item1.setIndex(0); + + VoyageAIModels.EmbeddingDataItem item2 = new VoyageAIModels.EmbeddingDataItem(); + item2.setEmbedding(new float[]{0.3f, 0.4f}); + item2.setIndex(1); + + mockResponse.setData(Arrays.asList(item1, item2)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(20); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("multimodalembeddings"), + any(), + eq(VoyageAIModels.MultimodalEmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAIMultimodalEmbeddingGenerationService service = + new VoyageAIMultimodalEmbeddingGenerationService(mockClient, "voyage-multimodal-3", null); + + List results = service.generateEmbeddingsAsync( + Arrays.asList("text1", "text2")).block(); + + assertNotNull(results); + assertEquals(2, results.size()); + List expected1 = Arrays.asList(0.1f, 0.2f); + List expected2 = Arrays.asList(0.3f, 0.4f); + assertEquals(expected1, results.get(0).getVector()); + assertEquals(expected2, results.get(1).getVector()); + } + + @Test + public void testServiceIdAndModelId() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIMultimodalEmbeddingGenerationService service = + new VoyageAIMultimodalEmbeddingGenerationService(mockClient, "voyage-multimodal-3", "test-service"); + + assertEquals("test-service", service.getServiceId()); + assertEquals("voyage-multimodal-3", service.getModelId()); + } + + @Test + public void testBuilderPattern() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIMultimodalEmbeddingGenerationService service = + VoyageAIMultimodalEmbeddingGenerationService.builder() + .withClient(mockClient) + .withModelId("voyage-multimodal-3") + .withServiceId("test-service") + .build(); + + assertNotNull(service); + assertEquals("test-service", service.getServiceId()); + assertEquals("voyage-multimodal-3", service.getModelId()); + } + + @Test + public void testNullClientThrowsException() { + assertThrows(IllegalArgumentException.class, () -> + new VoyageAIMultimodalEmbeddingGenerationService(null, "voyage-multimodal-3", null)); + } + + @Test + public void testNullModelIdThrowsException() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + assertThrows(IllegalArgumentException.class, () -> + new VoyageAIMultimodalEmbeddingGenerationService(mockClient, null, null)); + } +} diff --git a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextEmbeddingGenerationServiceTest.java b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextEmbeddingGenerationServiceTest.java new file mode 100644 index 000000000..962a340b2 --- /dev/null +++ b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextEmbeddingGenerationServiceTest.java @@ -0,0 +1,131 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.aiservices.voyageai.textembedding.VoyageAITextEmbeddingGenerationService; +import com.microsoft.semantickernel.services.textembedding.Embedding; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +public class VoyageAITextEmbeddingGenerationServiceTest { + + @Test + public void testGenerateEmbedding() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.EmbeddingResponse mockResponse = new VoyageAIModels.EmbeddingResponse(); + VoyageAIModels.EmbeddingDataItem item = new VoyageAIModels.EmbeddingDataItem(); + item.setEmbedding(new float[]{0.1f, 0.2f, 0.3f}); + item.setIndex(0); + mockResponse.setData(Arrays.asList(item)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(10); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("embeddings"), + any(), + eq(VoyageAIModels.EmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAITextEmbeddingGenerationService service = + new VoyageAITextEmbeddingGenerationService(mockClient, "voyage-3-large", null); + + Embedding result = service.generateEmbeddingAsync("test text").block(); + + assertNotNull(result); + List expected = Arrays.asList(0.1f, 0.2f, 0.3f); + assertEquals(expected, result.getVector()); + } + + @Test + public void testGenerateMultipleEmbeddings() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.EmbeddingResponse mockResponse = new VoyageAIModels.EmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item1 = new VoyageAIModels.EmbeddingDataItem(); + item1.setEmbedding(new float[]{0.1f, 0.2f}); + item1.setIndex(0); + + VoyageAIModels.EmbeddingDataItem item2 = new VoyageAIModels.EmbeddingDataItem(); + item2.setEmbedding(new float[]{0.3f, 0.4f}); + item2.setIndex(1); + + mockResponse.setData(Arrays.asList(item1, item2)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(20); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("embeddings"), + any(), + eq(VoyageAIModels.EmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAITextEmbeddingGenerationService service = + new VoyageAITextEmbeddingGenerationService(mockClient, "voyage-3-large", null); + + List results = service.generateEmbeddingsAsync( + Arrays.asList("text1", "text2")).block(); + + assertNotNull(results); + assertEquals(2, results.size()); + List expected1 = Arrays.asList(0.1f, 0.2f); + List expected2 = Arrays.asList(0.3f, 0.4f); + assertEquals(expected1, results.get(0).getVector()); + assertEquals(expected2, results.get(1).getVector()); + } + + @Test + public void testServiceIdAndModelId() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAITextEmbeddingGenerationService service = + new VoyageAITextEmbeddingGenerationService(mockClient, "voyage-3-large", "test-service"); + + assertEquals("test-service", service.getServiceId()); + assertEquals("voyage-3-large", service.getModelId()); + } + + @Test + public void testBuilderPattern() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAITextEmbeddingGenerationService service = + VoyageAITextEmbeddingGenerationService.builder() + .withClient(mockClient) + .withModelId("voyage-3-large") + .withServiceId("test-service") + .build(); + + assertNotNull(service); + assertEquals("test-service", service.getServiceId()); + assertEquals("voyage-3-large", service.getModelId()); + } + + @Test + public void testNullClientThrowsException() { + assertThrows(IllegalArgumentException.class, () -> + new VoyageAITextEmbeddingGenerationService(null, "voyage-3-large", null)); + } + + @Test + public void testNullModelIdThrowsException() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + assertThrows(IllegalArgumentException.class, () -> + new VoyageAITextEmbeddingGenerationService(mockClient, null, null)); + } +} diff --git a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextRerankingServiceTest.java b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextRerankingServiceTest.java new file mode 100644 index 000000000..9feddd271 --- /dev/null +++ b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAITextRerankingServiceTest.java @@ -0,0 +1,116 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.aiservices.voyageai; + +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIClient; +import com.microsoft.semantickernel.aiservices.voyageai.core.VoyageAIModels; +import com.microsoft.semantickernel.aiservices.voyageai.reranking.VoyageAITextRerankingService; +import com.microsoft.semantickernel.services.reranking.RerankResult; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import reactor.core.publisher.Mono; + +import java.util.Arrays; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.*; +import static org.mockito.Mockito.when; + +public class VoyageAITextRerankingServiceTest { + + @Test + public void testRerank() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.RerankResponse mockResponse = new VoyageAIModels.RerankResponse(); + + VoyageAIModels.RerankDataItem item1 = new VoyageAIModels.RerankDataItem(); + item1.setIndex(1); + item1.setRelevanceScore(0.9); + + VoyageAIModels.RerankDataItem item2 = new VoyageAIModels.RerankDataItem(); + item2.setIndex(0); + item2.setRelevanceScore(0.5); + + mockResponse.setData(Arrays.asList(item1, item2)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(20); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("rerank"), + any(), + eq(VoyageAIModels.RerankResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAITextRerankingService service = + new VoyageAITextRerankingService(mockClient, "rerank-2", null, null); + + List documents = Arrays.asList("Document A", "Document B"); + List results = service.rerankAsync("test query", documents).block(); + + assertNotNull(results); + assertEquals(2, results.size()); + + // Results should be sorted by relevance score descending + assertEquals(1, results.get(0).getIndex()); + assertEquals("Document B", results.get(0).getText()); + assertEquals(0.9, results.get(0).getRelevanceScore(), 0.001); + + assertEquals(0, results.get(1).getIndex()); + assertEquals("Document A", results.get(1).getText()); + assertEquals(0.5, results.get(1).getRelevanceScore(), 0.001); + } + + @Test + public void testServiceIdAndModelId() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAITextRerankingService service = + new VoyageAITextRerankingService(mockClient, "rerank-2", "test-service", null); + + assertEquals("test-service", service.getServiceId()); + assertEquals("rerank-2", service.getModelId()); + } + + @Test + public void testBuilderPattern() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAITextRerankingService service = + VoyageAITextRerankingService.builder() + .withClient(mockClient) + .withModelId("rerank-2") + .withServiceId("test-service") + .withTopK(5) + .build(); + + assertNotNull(service); + assertEquals("test-service", service.getServiceId()); + assertEquals("rerank-2", service.getModelId()); + } + + @Test + public void testNullClientThrowsException() { + assertThrows(IllegalArgumentException.class, () -> + new VoyageAITextRerankingService(null, "rerank-2", null, null)); + } + + @Test + public void testNullModelIdThrowsException() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + assertThrows(IllegalArgumentException.class, () -> + new VoyageAITextRerankingService(mockClient, null, null, null)); + } + + @Test + public void testNullQueryThrowsException() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + VoyageAITextRerankingService service = + new VoyageAITextRerankingService(mockClient, "rerank-2", null, null); + + assertThrows(IllegalArgumentException.class, () -> + service.rerankAsync(null, Arrays.asList("doc")).block()); + } +} diff --git a/pom.xml b/pom.xml index 8399f1c79..b54d9e0eb 100644 --- a/pom.xml +++ b/pom.xml @@ -74,6 +74,7 @@ aiservices/openai aiservices/google aiservices/huggingface + aiservices/voyageai data/semantickernel-data-azureaisearch data/semantickernel-data-jdbc data/semantickernel-data-redis diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java new file mode 100644 index 000000000..9d365b765 --- /dev/null +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java @@ -0,0 +1,55 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.services.reranking; + +/** + * Represents a single reranking result containing a document and its relevance score. + */ +public class RerankResult { + private final int index; + private final String text; + private final double relevanceScore; + + /** + * Initializes a new instance of the {@link RerankResult} class. + * + * @param index The index of the document in the original input list + * @param text The document text + * @param relevanceScore The relevance score (higher scores indicate greater relevance) + */ + public RerankResult(int index, String text, double relevanceScore) { + if (text == null) { + throw new IllegalArgumentException("Text cannot be null"); + } + this.index = index; + this.text = text; + this.relevanceScore = relevanceScore; + } + + /** + * Gets the index of the document in the original input list. + * + * @return The index + */ + public int getIndex() { + return index; + } + + /** + * Gets the document text. + * + * @return The text + */ + public String getText() { + return text; + } + + /** + * Gets the relevance score assigned by the reranker. + * Higher scores indicate greater relevance to the query. + * + * @return The relevance score + */ + public double getRelevanceScore() { + return relevanceScore; + } +} diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/TextRerankingService.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/TextRerankingService.java new file mode 100644 index 000000000..84fe66c08 --- /dev/null +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/TextRerankingService.java @@ -0,0 +1,22 @@ +// Copyright (c) Microsoft. All rights reserved. +package com.microsoft.semantickernel.services.reranking; + +import com.microsoft.semantickernel.services.AIService; +import reactor.core.publisher.Mono; + +import java.util.List; + +/** + * Interface for text reranking services that can reorder documents based on relevance to a query. + */ +public interface TextRerankingService extends AIService { + + /** + * Reranks a list of documents based on their relevance to a query. + * + * @param query The query to rank documents against + * @param documents The list of documents to rerank + * @return A Mono containing a list of {@link RerankResult} sorted by relevance score in descending order + */ + Mono> rerankAsync(String query, List documents); +} From 3904ce365f2a68a0e8ffa9dbb64e9d006d68cbcc Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Nov 2025 07:10:26 +0000 Subject: [PATCH 02/37] Bump actions/checkout from 5 to 6 Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/java-build.yml | 2 +- .github/workflows/java-integration-tests.yml | 2 +- .github/workflows/java-publish-package.yml | 2 +- .github/workflows/markdown-link-check.yml | 2 +- .github/workflows/typos.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 9a2bc55e6..dee4d1c46 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v5 + uses: actions/checkout@v6 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/java-build.yml b/.github/workflows/java-build.yml index 08e039a08..ae14c035e 100644 --- a/.github/workflows/java-build.yml +++ b/.github/workflows/java-build.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 # Need to use JDK 11 to build for JDK 8 - name: Set JDK diff --git a/.github/workflows/java-integration-tests.yml b/.github/workflows/java-integration-tests.yml index f8d25c333..17edd75ed 100644 --- a/.github/workflows/java-integration-tests.yml +++ b/.github/workflows/java-integration-tests.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 # Need to use JDK 11 to build for JDK 8 - name: Set JDK diff --git a/.github/workflows/java-publish-package.yml b/.github/workflows/java-publish-package.yml index f2631c25c..93a136f49 100644 --- a/.github/workflows/java-publish-package.yml +++ b/.github/workflows/java-publish-package.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 # Sets up the specified JDK version from the matrix - uses: actions/setup-java@v5 diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index 4145df277..bc1a1fa72 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest # check out the latest version of the code steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@v6 # Checks the status of hyperlinks in .md files in verbose mode - name: Check links diff --git a/.github/workflows/typos.yaml b/.github/workflows/typos.yaml index 6452831b8..532f4d5dc 100644 --- a/.github/workflows/typos.yaml +++ b/.github/workflows/typos.yaml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v5 + uses: actions/checkout@v6 - name: Use custom config file uses: crate-ci/typos@master From 07f20c327f98a27495116545b280009e4a0143ad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 15 Dec 2025 07:09:34 +0000 Subject: [PATCH 03/37] Bump actions/upload-artifact from 5 to 6 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v5...v6) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/java-build.yml | 2 +- .github/workflows/java-publish-package.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/java-build.yml b/.github/workflows/java-build.yml index ae14c035e..32b71f757 100644 --- a/.github/workflows/java-build.yml +++ b/.github/workflows/java-build.yml @@ -56,7 +56,7 @@ jobs: run: ./mvnw -B -Pbug-check -Pcompile-jdk${{ matrix.java-versions }} test --file pom.xml # Uploads test artifacts for each JDK version - - uses: actions/upload-artifact@v5 + - uses: actions/upload-artifact@v6 if: always() with: name: test_output_sk_jdk${{ matrix.java-versions }}u diff --git a/.github/workflows/java-publish-package.yml b/.github/workflows/java-publish-package.yml index 93a136f49..8cc4e00c0 100644 --- a/.github/workflows/java-publish-package.yml +++ b/.github/workflows/java-publish-package.yml @@ -30,7 +30,7 @@ jobs: run: ./mvnw -B -DskipTests -Pcompile-jdk8 -P-compile-jdk17 clean deploy --file pom.xml -DaltDeploymentRepository=local::file:///tmp/target/staging-deploy - name: Upload Artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@v6 with: name: Artifacts path: /tmp/target/staging-deploy From eb9a8cc036754da15c4718d6a697ad404947a878 Mon Sep 17 00:00:00 2001 From: fzowl Date: Fri, 19 Dec 2025 18:16:29 +0100 Subject: [PATCH 04/37] Adding voyage-multimodal-3.5 tests --- ...timodalEmbeddingGenerationServiceTest.java | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java index 537958d2b..e97d19703 100644 --- a/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java +++ b/aiservices/voyageai/src/test/java/com/microsoft/semantickernel/aiservices/voyageai/VoyageAIMultimodalEmbeddingGenerationServiceTest.java @@ -178,4 +178,53 @@ public void testNullModelIdThrowsException() { assertThrows(IllegalArgumentException.class, () -> new VoyageAIMultimodalEmbeddingGenerationService(mockClient, null, null)); } + + @Test + public void testVoyageMultimodal35ModelId() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIMultimodalEmbeddingGenerationService service = + VoyageAIMultimodalEmbeddingGenerationService.builder() + .withClient(mockClient) + .withModelId("voyage-multimodal-3.5") + .withServiceId("multimodal-3.5-service") + .build(); + + assertNotNull(service); + assertEquals("voyage-multimodal-3.5", service.getModelId()); + assertEquals("multimodal-3.5-service", service.getServiceId()); + } + + @Test + public void testVoyageMultimodal35GenerateEmbeddings() { + VoyageAIClient mockClient = Mockito.mock(VoyageAIClient.class); + + VoyageAIModels.MultimodalEmbeddingResponse mockResponse = + new VoyageAIModels.MultimodalEmbeddingResponse(); + + VoyageAIModels.EmbeddingDataItem item = new VoyageAIModels.EmbeddingDataItem(); + item.setEmbedding(new float[]{0.5f, 0.6f, 0.7f, 0.8f}); + item.setIndex(0); + + mockResponse.setData(Arrays.asList(item)); + + VoyageAIModels.EmbeddingUsage usage = new VoyageAIModels.EmbeddingUsage(); + usage.setTotalTokens(15); + mockResponse.setUsage(usage); + + when(mockClient.sendRequestAsync( + eq("multimodalembeddings"), + any(), + eq(VoyageAIModels.MultimodalEmbeddingResponse.class))) + .thenReturn(Mono.just(mockResponse)); + + VoyageAIMultimodalEmbeddingGenerationService service = + new VoyageAIMultimodalEmbeddingGenerationService(mockClient, "voyage-multimodal-3.5", null); + + Embedding result = service.generateEmbeddingAsync("test with voyage-multimodal-3.5").block(); + + assertNotNull(result); + List expected = Arrays.asList(0.5f, 0.6f, 0.7f, 0.8f); + assertEquals(expected, result.getVector()); + } } From 90457050cb93494675aac827f1e535cd86307f4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 19 Dec 2025 23:50:26 +0000 Subject: [PATCH 05/37] Bump org.apache.logging.log4j:log4j-core from 2.24.1 to 2.25.3 Bumps org.apache.logging.log4j:log4j-core from 2.24.1 to 2.25.3. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-version: 2.25.3 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8399f1c79..b096c4a4b 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 1.17.0 1.6.0 5.11.3 - 2.24.1 + 2.25.3 3.1.0 2.12.1 3.5.0 From 62684bd2736f1ea1e9df4153e56cd86ec28437c1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 21:53:13 +0000 Subject: [PATCH 06/37] Bump org.assertj:assertj-core Bumps [org.assertj:assertj-core](https://github.com/assertj/assertj) from 3.26.3 to 3.27.7. - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.26.3...assertj-build-3.27.7) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.7 dependency-type: direct:development ... Signed-off-by: dependabot[bot] --- .../semantickernel-demos/semantickernel-spring-starter/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml index d7755a11c..8db11dcd1 100644 --- a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml +++ b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml @@ -37,7 +37,7 @@ org.assertj assertj-core - 3.26.3 + 3.27.7 test From c222fb37580f0e483e560e898ef7795ea4813834 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:31:06 +0000 Subject: [PATCH 07/37] Bump testcontainers version --- data/semantickernel-data-oracle/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml index 9971679be..e2c934439 100644 --- a/data/semantickernel-data-oracle/pom.xml +++ b/data/semantickernel-data-oracle/pom.xml @@ -13,7 +13,7 @@ Provides a Oracle connector for the Semantic Kernel - 1.20.4 + 1.21.4 From 65fbb3b8f3b731d7c356077ac29ef6ab4e46c69c Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Tue, 3 Feb 2026 16:37:08 +0000 Subject: [PATCH 08/37] Fix typo --- .../plugin/Example13_ConversationSummaryPlugin.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java index 63412b600..47f0e5a46 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/plugin/Example13_ConversationSummaryPlugin.java @@ -107,7 +107,7 @@ public class Example13_ConversationSummaryPlugin { Jane: Darn, it's just repeating stuff now. John: I think we're done. Jane: We're not though! We need like 1500 more characters. - John: Oh Cananda, our home and native land. + John: Oh Canada, our home and native land. Jane: True patriot love in all thy sons command. John: With glowing hearts we see thee rise. Jane: The True North strong and free. From 1db294c09b82179fa74648c50cd22dc595ee2dee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 03:19:04 +0000 Subject: [PATCH 09/37] Bump com.fasterxml.jackson.core:jackson-core in /semantickernel-bom Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.18.0 to 2.18.6. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.18.0...jackson-core-2.18.6) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.18.6 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- semantickernel-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 372e04c1f..303e08b72 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -13,7 +13,7 @@ https://www.github.com/microsoft/semantic-kernel - 2.18.0 + 2.18.6 From 58fbd5082732f0c99a21e053e4e2aec624fec475 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 03:33:41 +0000 Subject: [PATCH 10/37] Bump net.sourceforge.pmd:pmd-core from 7.10.0 to 7.22.0 Bumps [net.sourceforge.pmd:pmd-core](https://github.com/pmd/pmd) from 7.10.0 to 7.22.0. - [Release notes](https://github.com/pmd/pmd/releases) - [Commits](https://github.com/pmd/pmd/compare/pmd_releases/7.10.0...pmd_releases/7.22.0) --- updated-dependencies: - dependency-name: net.sourceforge.pmd:pmd-core dependency-version: 7.22.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b096c4a4b..9a52016ca 100644 --- a/pom.xml +++ b/pom.xml @@ -60,7 +60,7 @@ 5.14.2 0.9.1 - 7.10.0 + 7.22.0 UTF-8 microsoft/semantic-kernel git@github.com:${project.github.repository}.git From 21b15c11fd8c969235c75babcfefc5883afdfaa8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 2 Mar 2026 07:54:17 +0000 Subject: [PATCH 11/37] Bump actions/upload-artifact from 6 to 7 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 6 to 7. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/java-build.yml | 2 +- .github/workflows/java-publish-package.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/java-build.yml b/.github/workflows/java-build.yml index 32b71f757..d63a0d44d 100644 --- a/.github/workflows/java-build.yml +++ b/.github/workflows/java-build.yml @@ -56,7 +56,7 @@ jobs: run: ./mvnw -B -Pbug-check -Pcompile-jdk${{ matrix.java-versions }} test --file pom.xml # Uploads test artifacts for each JDK version - - uses: actions/upload-artifact@v6 + - uses: actions/upload-artifact@v7 if: always() with: name: test_output_sk_jdk${{ matrix.java-versions }}u diff --git a/.github/workflows/java-publish-package.yml b/.github/workflows/java-publish-package.yml index 8cc4e00c0..1f73e6885 100644 --- a/.github/workflows/java-publish-package.yml +++ b/.github/workflows/java-publish-package.yml @@ -30,7 +30,7 @@ jobs: run: ./mvnw -B -DskipTests -Pcompile-jdk8 -P-compile-jdk17 clean deploy --file pom.xml -DaltDeploymentRepository=local::file:///tmp/target/staging-deploy - name: Upload Artifacts - uses: actions/upload-artifact@v6 + uses: actions/upload-artifact@v7 with: name: Artifacts path: /tmp/target/staging-deploy From 33e1a5d334fb6862dd457913f095a2fe5f232d9a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Apr 2026 23:47:20 +0000 Subject: [PATCH 12/37] Bump org.apache.logging.log4j:log4j-core from 2.25.3 to 2.25.4 Bumps org.apache.logging.log4j:log4j-core from 2.25.3 to 2.25.4. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-version: 2.25.4 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9a52016ca..0a6838bef 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ 1.17.0 1.6.0 5.11.3 - 2.25.3 + 2.25.4 3.1.0 2.12.1 3.5.0 From 7177b90264138d4b730fd328c993662a997262cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 13 Apr 2026 08:01:09 +0000 Subject: [PATCH 13/37] Bump actions/github-script from 8 to 9 Bumps [actions/github-script](https://github.com/actions/github-script) from 8 to 9. - [Release notes](https://github.com/actions/github-script/releases) - [Commits](https://github.com/actions/github-script/compare/v8...v9) --- updated-dependencies: - dependency-name: actions/github-script dependency-version: '9' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/label-issues.yml | 2 +- .github/workflows/label-title-prefix.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/label-issues.yml b/.github/workflows/label-issues.yml index cf901ade0..d5a48785b 100644 --- a/.github/workflows/label-issues.yml +++ b/.github/workflows/label-issues.yml @@ -13,7 +13,7 @@ jobs: permissions: issues: write steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 with: github-token: ${{ secrets.GH_ACTIONS_PR_WRITE }} script: | diff --git a/.github/workflows/label-title-prefix.yml b/.github/workflows/label-title-prefix.yml index 81369deed..e84551dda 100644 --- a/.github/workflows/label-title-prefix.yml +++ b/.github/workflows/label-title-prefix.yml @@ -15,7 +15,7 @@ jobs: pull-requests: write steps: - - uses: actions/github-script@v8 + - uses: actions/github-script@v9 name: "Issue/PR: update title" with: github-token: ${{ secrets.GITHUB_TOKEN }} From c3230235a2dc5b134694c4a83fbc24f86d3c7277 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Thu, 16 Apr 2026 12:28:37 +0000 Subject: [PATCH 14/37] Fix storage filter issues Update testcontainers and fix testing Remove unsused test --- api-test/integration-tests/pom.xml | 9 +- .../tests/data/redis/Hotel.java | 4 +- ...ashSetVectorStoreRecordCollectionTest.java | 138 +++++++++--------- ...isJsonVectorStoreRecordCollectionTest.java | 124 ++++++++-------- .../semantickernel-data-azureaisearch/pom.xml | 20 ++- ...rchVectorStoreCollectionSearchMapping.java | 19 ++- data/semantickernel-data-redis/pom.xml | 7 + ...disVectorStoreCollectionSearchMapping.java | 19 ++- 8 files changed, 197 insertions(+), 143 deletions(-) diff --git a/api-test/integration-tests/pom.xml b/api-test/integration-tests/pom.xml index 862cc5184..256e4cb74 100644 --- a/api-test/integration-tests/pom.xml +++ b/api-test/integration-tests/pom.xml @@ -122,7 +122,7 @@ com.redis testcontainers-redis - 2.2.2 + 2.2.4 test @@ -150,6 +150,11 @@ 2.7.3 test + + com.microsoft.semantic-kernel + semantickernel-api-data + test + @@ -157,7 +162,7 @@ org.testcontainers testcontainers-bom - 1.18.3 + 1.21.4 pom import diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java index 416e06b66..46083425a 100644 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java +++ b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/Hotel.java @@ -18,11 +18,11 @@ public class Hotel { @VectorStoreRecordData(isFilterable = true) private final String name; - @VectorStoreRecordData + @VectorStoreRecordData(isFilterable = true) private final int code; @JsonProperty("summary") - @VectorStoreRecordData() + @VectorStoreRecordData(isFilterable = true) private final String description; @JsonProperty("summaryEmbedding1") diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java index c5b6a186f..6bfebb8d7 100644 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java +++ b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisHashSetVectorStoreRecordCollectionTest.java @@ -53,56 +53,56 @@ public enum RecordCollectionOptions { @BeforeAll static void setup() { optionsMap.put(RecordCollectionOptions.DEFAULT, RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); + .withRecordClass(Hotel.class) + .build()); List fields = new ArrayList<>(); fields.add(VectorStoreRecordKeyField.builder() - .withName("id") - .withFieldType(String.class) - .build()); + .withName("id") + .withFieldType(String.class) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("name") - .withFieldType(String.class) - .build()); + .withName("name") + .withFieldType(String.class) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("code") - .withFieldType(Integer.class) - .build()); + .withName("code") + .withFieldType(Integer.class) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("description") - .withStorageName("summary") - .withFieldType(String.class) - .build()); + .withName("description") + .withStorageName("summary") + .withFieldType(String.class) + .build()); fields.add(VectorStoreRecordVectorField.builder() - .withName("euclidean") - .withStorageName("summaryEmbedding1") - .withFieldType(List.class) - .withDimensions(8) - .build()); + .withName("euclidean") + .withStorageName("summaryEmbedding1") + .withFieldType(List.class) + .withDimensions(8) + .build()); fields.add(VectorStoreRecordVectorField.builder() - .withName("cosineDistance") - .withStorageName("summaryEmbedding2") - .withFieldType(List.class) - .withDimensions(8) - .build()); + .withName("cosineDistance") + .withStorageName("summaryEmbedding2") + .withFieldType(List.class) + .withDimensions(8) + .build()); fields.add(VectorStoreRecordVectorField.builder() - .withName("dotProduct") - .withStorageName("summaryEmbedding3") - .withFieldType(List.class) - .withDimensions(8) - .build()); + .withName("dotProduct") + .withStorageName("summaryEmbedding3") + .withFieldType(List.class) + .withDimensions(8) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("rating") - .withFieldType(Double.class) - .isFilterable(true) - .build()); + .withName("rating") + .withFieldType(Double.class) + .isFilterable(true) + .build()); VectorStoreRecordDefinition recordDefinition = VectorStoreRecordDefinition.fromFields(fields); optionsMap.put(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .withRecordDefinition(recordDefinition) - .build()); + .withRecordClass(Hotel.class) + .withRecordDefinition(recordDefinition) + .build()); // Search configuration List hotels = getHotels(); @@ -127,20 +127,20 @@ static void setup() { private static RedisHashSetVectorStoreRecordCollection createCollection(@Nonnull RedisHashSetVectorStoreRecordCollectionOptions options, @Nonnull String collectionName) { return new RedisHashSetVectorStoreRecordCollection<>(new JedisPooled(redisContainer.getRedisURI()), collectionName, RedisHashSetVectorStoreRecordCollectionOptions.builder() - .withRecordClass(options.getRecordClass()) - .withVectorStoreRecordMapper(options.getVectorStoreRecordMapper()) - .withRecordDefinition(options.getRecordDefinition()) - .withPrefixCollectionName(options.isPrefixCollectionName()) - .build()); + .withRecordClass(options.getRecordClass()) + .withVectorStoreRecordMapper(options.getVectorStoreRecordMapper()) + .withRecordDefinition(options.getRecordDefinition()) + .withPrefixCollectionName(options.isPrefixCollectionName()) + .build()); } private static List getHotels() { return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f),null, null, 4.0), - new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f),null, null, 4.0), - new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f),null, null, 5.0), - new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f),null, null, 4.0), - new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f),null, null, 4.0) + new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f),null, null, 4.0), + new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f),null, null, 4.0), + new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f),null, null, 5.0), + new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f),null, null, 4.0), + new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f),null, null, 4.0) ); } @@ -362,12 +362,12 @@ public void getBatchAsyncWithNoVectors(RecordCollectionOptions options) { private static Stream provideSearchParameters() { return Stream.of( - Arguments.of(RecordCollectionOptions.DEFAULT, "euclidean"), - Arguments.of(RecordCollectionOptions.DEFAULT, "cosineDistance"), - Arguments.of(RecordCollectionOptions.DEFAULT, "dotProduct"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "euclidean"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "cosineDistance"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "dotProduct") + Arguments.of(RecordCollectionOptions.DEFAULT, "euclidean"), + Arguments.of(RecordCollectionOptions.DEFAULT, "cosineDistance"), + Arguments.of(RecordCollectionOptions.DEFAULT, "dotProduct"), + Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "euclidean"), + Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "cosineDistance"), + Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "dotProduct") ); } @@ -383,8 +383,8 @@ public void search(RecordCollectionOptions options, String embeddingName) { recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .build(); + .withVectorFieldName(embeddingName) + .build(); // Embeddings similar to the third hotel List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); @@ -407,9 +407,9 @@ public void searchWithVectors(RecordCollectionOptions options, String embeddingN recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withIncludeVectors(true) - .build(); + .withVectorFieldName(embeddingName) + .withIncludeVectors(true) + .build(); // Embeddings similar to the third hotel List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); @@ -430,10 +430,10 @@ public void searchWithOffSet(RecordCollectionOptions options, String embeddingNa recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withSkip(1) - .withTop(4) - .build(); + .withVectorFieldName(embeddingName) + .withSkip(1) + .withTop(4) + .build(); // Embeddings similar to the third hotel List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); @@ -453,16 +453,16 @@ public void searchWithFilterEqualToFilter(RecordCollectionOptions recordCollecti recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions options = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withTop(3) - .withVectorSearchFilter( - VectorSearchFilter.builder() - .equalTo("rating", 4.0).build()) - .build(); + .withVectorFieldName(embeddingName) + .withTop(3) + .withVectorSearchFilter( + VectorSearchFilter.builder() + .equalTo("rating", 4.0).build()) + .build(); // Embeddings similar to the third hotel, but as the filter is set to 4.0, the third hotel should not be returned List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, - options).block().getResults(); + options).block().getResults(); assertNotNull(results); assertEquals(3, results.size()); // The first hotel should be the most similar diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java index 1b4c30e82..1190e4377 100644 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java +++ b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/data/redis/RedisJsonVectorStoreRecordCollectionTest.java @@ -53,56 +53,56 @@ public enum RecordCollectionOptions { @BeforeAll static void setup() { optionsMap.put(RecordCollectionOptions.DEFAULT, RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .build()); + .withRecordClass(Hotel.class) + .build()); List fields = new ArrayList<>(); fields.add(VectorStoreRecordKeyField.builder() - .withName("id") - .withFieldType(String.class) - .build()); + .withName("id") + .withFieldType(String.class) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("name") - .withFieldType(String.class) - .build()); + .withName("name") + .withFieldType(String.class) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("code") - .withFieldType(Integer.class) - .build()); + .withName("code") + .withFieldType(Integer.class) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("description") - .withStorageName("summary") - .withFieldType(String.class) - .build()); + .withName("description") + .withStorageName("summary") + .withFieldType(String.class) + .build()); fields.add(VectorStoreRecordVectorField.builder() - .withName("euclidean") - .withStorageName("summaryEmbedding1") - .withFieldType(List.class) - .withDimensions(8) - .build()); + .withName("euclidean") + .withStorageName("summaryEmbedding1") + .withFieldType(List.class) + .withDimensions(8) + .build()); fields.add(VectorStoreRecordVectorField.builder() - .withName("cosineDistance") - .withStorageName("summaryEmbedding2") - .withFieldType(List.class) - .withDimensions(8) - .build()); + .withName("cosineDistance") + .withStorageName("summaryEmbedding2") + .withFieldType(List.class) + .withDimensions(8) + .build()); fields.add(VectorStoreRecordVectorField.builder() - .withName("dotProduct") - .withStorageName("summaryEmbedding3") - .withFieldType(List.class) - .withDimensions(8) - .build()); + .withName("dotProduct") + .withStorageName("summaryEmbedding3") + .withFieldType(List.class) + .withDimensions(8) + .build()); fields.add(VectorStoreRecordDataField.builder() - .withName("rating") - .withFieldType(Double.class) - .isFilterable(true) - .build()); + .withName("rating") + .withFieldType(Double.class) + .isFilterable(true) + .build()); VectorStoreRecordDefinition recordDefinition = VectorStoreRecordDefinition.fromFields(fields); optionsMap.put(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(Hotel.class) - .withRecordDefinition(recordDefinition) - .build()); + .withRecordClass(Hotel.class) + .withRecordDefinition(recordDefinition) + .build()); // Search configuration List hotels = getHotels(); @@ -127,20 +127,20 @@ static void setup() { private static RedisJsonVectorStoreRecordCollection createCollection(@Nonnull RedisJsonVectorStoreRecordCollectionOptions options, @Nonnull String collectionName) { return new RedisJsonVectorStoreRecordCollection<>(new JedisPooled(redisContainer.getRedisURI()), collectionName, RedisJsonVectorStoreRecordCollectionOptions.builder() - .withRecordClass(options.getRecordClass()) - .withVectorStoreRecordMapper(options.getVectorStoreRecordMapper()) - .withRecordDefinition(options.getRecordDefinition()) - .withPrefixCollectionName(options.isPrefixCollectionName()) - .build()); + .withRecordClass(options.getRecordClass()) + .withVectorStoreRecordMapper(options.getVectorStoreRecordMapper()) + .withRecordDefinition(options.getRecordDefinition()) + .withPrefixCollectionName(options.isPrefixCollectionName()) + .build()); } private static List getHotels() { return Arrays.asList( - new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f),null, null, 4.0), - new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f),null, null, 4.0), - new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f),null, null, 5.0), - new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f),null, null, 4.0), - new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f),null, null, 4.0) + new Hotel("id_1", "Hotel 1", 1, "Hotel 1 description", Arrays.asList(0.5f, 3.2f, 7.1f, -4.0f, 2.8f, 10.0f, -1.3f, 5.5f),null, null, 4.0), + new Hotel("id_2", "Hotel 2", 2, "Hotel 2 description", Arrays.asList(-2.0f, 8.1f, 0.9f, 5.4f, -3.3f, 2.2f, 9.9f, -4.5f),null, null, 4.0), + new Hotel("id_3", "Hotel 3", 3, "Hotel 3 description", Arrays.asList(4.5f, -6.2f, 3.1f, 7.7f, -0.8f, 1.1f, -2.2f, 8.3f),null, null, 5.0), + new Hotel("id_4", "Hotel 4", 4, "Hotel 4 description", Arrays.asList(7.0f, 1.2f, -5.3f, 2.5f, 6.6f, -7.8f, 3.9f, -0.1f),null, null, 4.0), + new Hotel("id_5", "Hotel 5", 5, "Hotel 5 description", Arrays.asList(-3.5f, 4.4f, -1.2f, 9.9f, 5.7f, -6.1f, 7.8f, -2.0f),null, null, 4.0) ); } @@ -362,12 +362,12 @@ public void getBatchAsyncWithNoVectors(RecordCollectionOptions options) { private static Stream provideSearchParameters() { return Stream.of( - Arguments.of(RecordCollectionOptions.DEFAULT, "euclidean"), - Arguments.of(RecordCollectionOptions.DEFAULT, "cosineDistance"), - Arguments.of(RecordCollectionOptions.DEFAULT, "dotProduct"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "euclidean"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "cosineDistance"), - Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "dotProduct") + Arguments.of(RecordCollectionOptions.DEFAULT, "euclidean"), + Arguments.of(RecordCollectionOptions.DEFAULT, "cosineDistance"), + Arguments.of(RecordCollectionOptions.DEFAULT, "dotProduct"), + Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "euclidean"), + Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "cosineDistance"), + Arguments.of(RecordCollectionOptions.WITH_CUSTOM_DEFINITION, "dotProduct") ); } @@ -383,8 +383,8 @@ public void search(RecordCollectionOptions options, String embeddingName) { recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .build(); + .withVectorFieldName(embeddingName) + .build(); // Embeddings similar to the third hotel List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); @@ -407,9 +407,9 @@ public void searchWithVectors(RecordCollectionOptions options, String embeddingN recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withIncludeVectors(true) - .build(); + .withVectorFieldName(embeddingName) + .withIncludeVectors(true) + .build(); // Embeddings similar to the third hotel List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); @@ -430,10 +430,10 @@ public void searchWithOffSet(RecordCollectionOptions options, String embeddingNa recordCollection.upsertBatchAsync(hotels, null).block(); VectorSearchOptions searchOptions = VectorSearchOptions.builder() - .withVectorFieldName(embeddingName) - .withSkip(1) - .withTop(4) - .build(); + .withVectorFieldName(embeddingName) + .withSkip(1) + .withTop(4) + .build(); // Embeddings similar to the third hotel List> results = recordCollection.searchAsync(SEARCH_EMBEDDINGS, searchOptions).block().getResults(); diff --git a/data/semantickernel-data-azureaisearch/pom.xml b/data/semantickernel-data-azureaisearch/pom.xml index e9db7daae..c0f0a8c6a 100644 --- a/data/semantickernel-data-azureaisearch/pom.xml +++ b/data/semantickernel-data-azureaisearch/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 com.microsoft.semantic-kernel @@ -40,6 +41,23 @@ + + + + org.junit.jupiter + junit-jupiter + test + + + org.mockito + mockito-core + test + + + com.microsoft.semantic-kernel + semantickernel-api-builders + test + \ No newline at end of file diff --git a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java index c31af301d..5d61f9817 100644 --- a/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java +++ b/data/semantickernel-data-azureaisearch/src/main/java/com/microsoft/semantickernel/data/azureaisearch/AzureAISearchVectorStoreCollectionSearchMapping.java @@ -57,11 +57,11 @@ public String getFilter(VectorSearchFilter vectorSearchFilter, @Override public String getEqualToFilter(EqualToFilterClause filterClause) { - String fieldName = filterClause.getFieldName(); + String fieldName = validateFieldName(filterClause.getFieldName()); Object value = filterClause.getValue(); if (value instanceof String) { - return String.format("%s eq '%s'", fieldName, value); + return String.format("%s eq '%s'", fieldName, escapeSingleQuotes((String) value)); } else if (value instanceof Boolean) { return String.format("%s eq %s", fieldName, value.toString().toLowerCase()); @@ -86,7 +86,18 @@ public String getEqualToFilter(EqualToFilterClause filterClause) { @Override public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - return String.format("%s/any(t: t eq '%s')", filterClause.getFieldName(), - filterClause.getValue()); + return String.format("%s/any(t: t eq '%s')", validateFieldName(filterClause.getFieldName()), + escapeSingleQuotes(filterClause.getValue().toString())); + } + + private String validateFieldName(String fieldName) { + if (fieldName.matches("[a-zA-Z_][a-zA-Z0-9_]*")) { + return fieldName; + } + throw new SKException("Invalid field name: " + fieldName); + } + + private String escapeSingleQuotes(String value) { + return value.replaceAll("'", "''"); } } diff --git a/data/semantickernel-data-redis/pom.xml b/data/semantickernel-data-redis/pom.xml index de2f60ee5..885084d3b 100644 --- a/data/semantickernel-data-redis/pom.xml +++ b/data/semantickernel-data-redis/pom.xml @@ -70,6 +70,13 @@ redis.clients jedis + + + + org.junit.jupiter + junit-jupiter + test + \ No newline at end of file diff --git a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java index f029f6787..7f7d31bcf 100644 --- a/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java +++ b/data/semantickernel-data-redis/src/main/java/com/microsoft/semantickernel/data/redis/RedisVectorStoreCollectionSearchMapping.java @@ -154,12 +154,12 @@ public String getFilter(VectorSearchFilter filter, */ @Override public String getEqualToFilter(EqualToFilterClause filterClause) { - String fieldName = filterClause.getFieldName(); + String fieldName = validateFieldName(filterClause.getFieldName()); Object value = filterClause.getValue(); String formattedValue; if (value instanceof String) { - formattedValue = String.format("\"%s\"", value); + formattedValue = String.format("\"%s\"", escapeRedisString((String) value)); } else if (value instanceof Number) { formattedValue = String.format("[%s %s]", value, value); } else { @@ -178,6 +178,19 @@ public String getEqualToFilter(EqualToFilterClause filterClause) { */ @Override public String getAnyTagEqualToFilter(AnyTagEqualToFilterClause filterClause) { - return String.format("@%s:\"%s\"", filterClause.getFieldName(), filterClause.getValue()); + return String.format("@%s:\"%s\"", + validateFieldName(filterClause.getFieldName()), + escapeRedisString(filterClause.getValue().toString())); + } + + private String validateFieldName(String fieldName) { + if (fieldName.matches("[a-zA-Z_][a-zA-Z0-9_]*")) { + return fieldName; + } + throw new SKException("Invalid field name: " + fieldName); + } + + private String escapeRedisString(String searchString) { + return searchString.replaceAll("([,.<>{}\\[\\]\"':;!@#$%^&*()\\-+=~|\\\\/?\\s])", "\\\\$1"); } } From a6809be8be3e001e4845251332e36bf24b4419a7 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:25:03 +0000 Subject: [PATCH 15/37] Fix prompt parsing issues --- .../chatcompletion/ChatXMLPromptParser.java | 28 +++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java index 8cc1cc972..975f5e533 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/implementation/chatcompletion/ChatXMLPromptParser.java @@ -18,6 +18,7 @@ import java.util.Locale; import java.util.Map; import javax.annotation.Nullable; +import javax.xml.XMLConstants; import javax.xml.namespace.QName; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLInputFactory; @@ -32,6 +33,29 @@ public class ChatXMLPromptParser { private static final Logger LOGGER = LoggerFactory.getLogger(ChatXMLPromptParser.class); + private static XMLInputFactory createXMLInputFactory() { + XMLInputFactory factory = XMLInputFactory.newInstance(); + + trySetProperty(factory, XMLConstants.FEATURE_SECURE_PROCESSING, true); + trySetProperty(factory, XMLConstants.ACCESS_EXTERNAL_DTD, ""); + trySetProperty(factory, XMLConstants.ACCESS_EXTERNAL_SCHEMA, ""); + + factory.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, false); + factory.setProperty(XMLInputFactory.SUPPORT_DTD, false); + factory.setProperty(XMLInputFactory.IS_REPLACING_ENTITY_REFERENCES, false); + + return factory; + } + + private static void trySetProperty(XMLInputFactory factory, String property, Object value) { + try { + factory.setProperty(property, value); + } catch (IllegalArgumentException e) { + // Property not supported by this XMLInputFactory implementation + LOGGER.trace("XMLInputFactory property '{}' not supported", property); + } + } + public static ChatPromptParseVisitor parse( String rawPrompt, ChatPromptParseVisitor chatPromptParseVisitor) { @@ -64,7 +88,7 @@ private static ChatPromptParseVisitor getChatRequestMessages(String promp // In this way, we can avoid parsing the whole prompt twice and easily extend the parsing logic. try (InputStream is = new ByteArrayInputStream(prompt.getBytes(StandardCharsets.UTF_8))) { - XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLInputFactory factory = createXMLInputFactory(); XMLEventReader reader = factory.createXMLEventReader(is); while (reader.hasNext()) { XMLEvent event = reader.nextEvent(); @@ -109,7 +133,7 @@ private static ChatPromptParseVisitor getFunctionDefinitions(String promp // try (InputStream is = new ByteArrayInputStream(prompt.getBytes(StandardCharsets.UTF_8))) { - XMLInputFactory factory = XMLInputFactory.newInstance(); + XMLInputFactory factory = createXMLInputFactory(); XMLEventReader reader = factory.createXMLEventReader(is); FunctionDefinition functionDefinition = null; Map parameters = new HashMap<>(); From 55f5d714e528c9098a6fdc55af9586a754a86cb1 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:21:06 +0000 Subject: [PATCH 16/37] Fix classloading --- .../aiservices/openai/chatcompletion/OpenAIFunction.java | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java index cf126d095..a5c5c6629 100644 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java +++ b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java @@ -229,14 +229,9 @@ private static String getJavaTypeToOpenAiFunctionType(String javaType) { } private static String getObjectSchema(String type, String description) { - String schema = "{ \"type\" : \"object\" }"; - try { - Class clazz = Class.forName(type); - schema = ResponseSchemaGenerator.jacksonGenerator().generateSchema(clazz); - - } catch (ClassNotFoundException | SKException ignored) { + Class clazz = KernelPluginFactory.getTypeForName(type); + String schema = ResponseSchemaGenerator.jacksonGenerator().generateSchema(clazz); - } Map properties = BinaryData.fromString(schema).toObject(Map.class); if (StringUtils.isNotBlank(description)) { properties.put("description", description); From 3128efc1976b6b5ac99210772f81b995818c2d54 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:23:52 +0000 Subject: [PATCH 17/37] Support max_completion_tokens and bump maven versions --- aiservices/google/pom.xml | 2 +- .../HuggingFacePromptExecutionSettings.java | 9 ++- .../chatcompletion/OpenAIChatCompletion.java | 72 ++++++++++--------- api-test/integration-tests/pom.xml | 10 +-- .../tests/ImportingMultiplePluginsTest.java | 1 - data/semantickernel-data-jdbc/pom.xml | 6 +- data/semantickernel-data-oracle/pom.xml | 4 +- .../data/jdbc/oracle/Hotel.java | 13 +--- data/semantickernel-data-postgres/pom.xml | 2 +- data/semantickernel-data-sqlite/pom.xml | 2 +- pom.xml | 33 ++++++--- .../semantickernel-syntax-examples/pom.xml | 8 +-- .../Example62_CustomAIServiceSelector.java | 2 +- .../Example_ChatWithResponseFormat.java | 1 + ...xample_ChatWithResponseFormatToolCall.java | 1 + .../Example59_OpenAIFunctionCalling.java | 2 +- .../booking-agent-m365/pom.xml | 2 +- .../semantickernel-spring-starter/pom.xml | 14 ++-- .../semantickernel-learn-resources/pom.xml | 2 +- .../semantickernel-openapi-plugin/pom.xml | 2 +- semantickernel-api/pom.xml | 2 +- .../semantickernel/hooks/KernelHook.java | 1 + .../PromptExecutionSettings.java | 63 ++++++++++++++-- semantickernel-bom/pom.xml | 30 ++++---- semantickernel-experimental/pom.xml | 4 +- 25 files changed, 178 insertions(+), 110 deletions(-) diff --git a/aiservices/google/pom.xml b/aiservices/google/pom.xml index 145ee5494..f56bcab75 100644 --- a/aiservices/google/pom.xml +++ b/aiservices/google/pom.xml @@ -17,7 +17,7 @@ com.google.cloud libraries-bom - 26.49.0 + 26.80.0 pom import diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java index adcabe7c4..4ee23f26d 100644 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java +++ b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java @@ -47,7 +47,8 @@ public HuggingFacePromptExecutionSettings(PromptExecutionSettings copy) { copy.getUser(), copy.getStopSequences(), copy.getTokenSelectionBiases(), - copy.getResponseFormat() == null ? null : copy.getResponseFormat()); + copy.getResponseFormat() == null ? null : copy.getResponseFormat(), + copy.getMaxCompletionTokens() == null ? null : copy.getMaxCompletionTokens().toString()); this.topK = null; this.repetitionPenalty = null; this.maxTime = null; @@ -101,10 +102,11 @@ public HuggingFacePromptExecutionSettings( @Nullable Boolean details, @Nullable Boolean logProbs, @Nullable Integer topLogProbs, - @Nullable Long seed) { + @Nullable Long seed, + @Nullable Boolean maxCompletionTokens) { super( serviceId, modelId, temperature, topP, presencePenalty, frequencyPenalty, maxTokens, - resultsPerPrompt, bestOf, user, stopSequences, tokenSelectionBiases, responseFormat); + resultsPerPrompt, bestOf, user, stopSequences, tokenSelectionBiases, responseFormat, Boolean.toString(maxCompletionTokens)); this.topK = topK; this.repetitionPenalty = repetitionPenalty; @@ -151,6 +153,7 @@ public static HuggingFacePromptExecutionSettings fromExecutionSettings( null, null, null, + null, null); } diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java index 8256bb002..8f0ebaf20 100644 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java +++ b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIChatCompletion.java @@ -65,8 +65,8 @@ import com.microsoft.semantickernel.orchestration.ToolCallBehavior; import com.microsoft.semantickernel.orchestration.responseformat.JsonResponseSchema; import com.microsoft.semantickernel.orchestration.responseformat.JsonSchemaResponseFormat; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.KernelArguments; +import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.services.chatcompletion.AuthorRole; import com.microsoft.semantickernel.services.chatcompletion.ChatCompletionService; import com.microsoft.semantickernel.services.chatcompletion.ChatHistory; @@ -149,7 +149,7 @@ public Mono>> getChatMessageContentsAsync( if (invocationContext != null && invocationContext - .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { + .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { chatHistoryResult = new ChatHistory( Collections.singletonList( CollectionUtil.getLastOrNull(chatHistoryResult.getMessages()))); @@ -183,7 +183,7 @@ public Mono>> getChatMessageContentsAsync( if (invocationContext != null && invocationContext - .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { + .returnMode() == InvocationReturnMode.LAST_MESSAGE_ONLY) { result = new ChatHistory( Collections.singletonList( CollectionUtil.getLastOrNull(result.getMessages()))); @@ -443,31 +443,31 @@ private Mono internalChatMessageContentsAsync( .getOptions(); return Mono.deferContextual(contextView -> { - ChatCompletionSpan span = ChatCompletionSpan.startChatCompletionSpan( - SemanticKernelTelemetry.getTelemetry(invocationContext), - contextView, - getModelId(), - SemanticKernelTelemetry.OPEN_AI_PROVIDER, - options.getMaxTokens(), - options.getTemperature(), - options.getTopP()); - - return getClient() - .getChatCompletionsWithResponse(getDeploymentName(), options, - OpenAIRequestSettings.getRequestOptions()) - .contextWrite(span.getReactorContextModifier()) - .flatMap(completionsResult -> { - if (completionsResult.getStatusCode() >= 400) { - return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR, - "Request failed: " + completionsResult.getStatusCode())); - } + ChatCompletionSpan span = ChatCompletionSpan.startChatCompletionSpan( + SemanticKernelTelemetry.getTelemetry(invocationContext), + contextView, + getModelId(), + SemanticKernelTelemetry.OPEN_AI_PROVIDER, + options.getMaxTokens(), + options.getTemperature(), + options.getTopP()); + + return getClient() + .getChatCompletionsWithResponse(getDeploymentName(), options, + OpenAIRequestSettings.getRequestOptions()) + .contextWrite(span.getReactorContextModifier()) + .flatMap(completionsResult -> { + if (completionsResult.getStatusCode() >= 400) { + return Mono.error(new AIException(ErrorCodes.SERVICE_ERROR, + "Request failed: " + completionsResult.getStatusCode())); + } - return Mono.just(completionsResult.getValue()); - }) - .doOnError(span::endSpanWithError) - .doOnSuccess(span::endSpanWithUsage) - .doOnTerminate(span::close); - }) + return Mono.just(completionsResult.getValue()); + }) + .doOnError(span::endSpanWithError) + .doOnSuccess(span::endSpanWithUsage) + .doOnTerminate(span::close); + }) .flatMap(completions -> { List responseMessages = completions .getChoices() @@ -920,7 +920,8 @@ private static ChatCompletionsOptions getCompletionsOptions( } Map logit = null; - if (promptExecutionSettings.getTokenSelectionBiases() != null) { + if (promptExecutionSettings.getTokenSelectionBiases() != null + && !promptExecutionSettings.getTokenSelectionBiases().isEmpty()) { logit = promptExecutionSettings .getTokenSelectionBiases() .entrySet() @@ -937,12 +938,13 @@ private static ChatCompletionsOptions getCompletionsOptions( .setFrequencyPenalty(promptExecutionSettings.getFrequencyPenalty()) .setPresencePenalty(promptExecutionSettings.getPresencePenalty()) .setMaxTokens(promptExecutionSettings.getMaxTokens()) + .setMaxCompletionTokens(promptExecutionSettings.getMaxCompletionTokens()) .setN(promptExecutionSettings.getResultsPerPrompt()) // Azure OpenAI WithData API does not allow to send empty array of stop sequences // Gives back "Validation error at #/stop/str: Input should be a valid string\nValidation error at #/stop/list[str]: List should have at least 1 item after validation, not 0" .setStop(promptExecutionSettings.getStopSequences() == null || promptExecutionSettings.getStopSequences().isEmpty() ? null - : promptExecutionSettings.getStopSequences()) + : promptExecutionSettings.getStopSequences()) .setUser(promptExecutionSettings.getUser()) .setLogitBias(logit); @@ -1147,7 +1149,7 @@ private static OpenAIToolCallConfig getToolCallBehaviorConfig( toolChoice, toolCallBehavior.isAutoInvokeAllowed() && requestIndex < Math.min(MAXIMUM_INFLIGHT_AUTO_INVOKES, - toolCallBehavior.getMaximumAutoInvokeAttempts()), + toolCallBehavior.getMaximumAutoInvokeAttempts()), null); } @@ -1262,11 +1264,11 @@ private static ChatRequestAssistantMessage formAssistantMessage( String args = arguments != null && !arguments.isEmpty() ? arguments.entrySet().stream() - .map(entry -> String.format("\"%s\": \"%s\"", - StringEscapeUtils.escapeJson(entry.getKey()), - StringEscapeUtils.escapeJson( - entry.getValue().toPromptString()))) - .collect(Collectors.joining(",", "{", "}")) + .map(entry -> String.format("\"%s\": \"%s\"", + StringEscapeUtils.escapeJson(entry.getKey()), + StringEscapeUtils.escapeJson( + entry.getValue().toPromptString()))) + .collect(Collectors.joining(",", "{", "}")) : "{}"; String prefix = ""; diff --git a/api-test/integration-tests/pom.xml b/api-test/integration-tests/pom.xml index 256e4cb74..f62567679 100644 --- a/api-test/integration-tests/pom.xml +++ b/api-test/integration-tests/pom.xml @@ -90,18 +90,18 @@ com.mysql mysql-connector-j - 9.0.0 + 9.6.0 test org.postgresql postgresql - 42.7.3 + 42.7.10 org.xerial sqlite-jdbc - 3.46.1.0 + 3.53.0.0 @@ -147,7 +147,7 @@ org.hsqldb hsqldb - 2.7.3 + 2.7.4 test @@ -162,7 +162,7 @@ org.testcontainers testcontainers-bom - 1.21.4 + 2.0.4 pom import diff --git a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java index a555937ed..e9e5c6d4a 100644 --- a/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java +++ b/api-test/integration-tests/src/test/java/com/microsoft/semantickernel/tests/ImportingMultiplePluginsTest.java @@ -4,7 +4,6 @@ import com.microsoft.semantickernel.Kernel; import com.microsoft.semantickernel.plugin.KernelPlugin; import com.microsoft.semantickernel.plugin.KernelPluginFactory; -import org.junit.Ignore; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; diff --git a/data/semantickernel-data-jdbc/pom.xml b/data/semantickernel-data-jdbc/pom.xml index 077d4da6c..883d06432 100644 --- a/data/semantickernel-data-jdbc/pom.xml +++ b/data/semantickernel-data-jdbc/pom.xml @@ -66,17 +66,17 @@ org.postgresql postgresql - 42.7.7 + 42.7.10 org.xerial sqlite-jdbc - 3.47.0.0 + 3.53.0.0 com.oracle.database.jdbc ojdbc11 - 23.7.0.25.01 + 23.26.1.0.0 \ No newline at end of file diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml index e2c934439..98644f9a9 100644 --- a/data/semantickernel-data-oracle/pom.xml +++ b/data/semantickernel-data-oracle/pom.xml @@ -61,12 +61,12 @@ com.oracle.database.jdbc ojdbc11 - 23.7.0.25.01 + 23.26.1.0.0 com.oracle.database.jdbc ojdbc-provider-jackson-oson - 1.0.4 + 1.0.6 org.junit.jupiter diff --git a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java index 0f93ff7f5..ef6ac824f 100644 --- a/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java +++ b/data/semantickernel-data-oracle/src/test/java/com/microsoft/semantickernel/data/jdbc/oracle/Hotel.java @@ -8,12 +8,8 @@ import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector; import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction; import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind; - import java.util.List; -import static com.fasterxml.jackson.annotation.JsonCreator.Mode.DELEGATING; -import static com.fasterxml.jackson.annotation.JsonCreator.Mode.PROPERTIES; - public class Hotel { @VectorStoreRecordKey private final String id; @@ -52,13 +48,8 @@ public class Hotel { @VectorStoreRecordData private double rating; - @JsonCreator(mode = DELEGATING) - public Hotel() { - this(null, null, 0, 0d, null, null, null, null, null, null, 0.0); - } - - @JsonCreator(mode = PROPERTIES) - protected Hotel( + @JsonCreator + public Hotel( @JsonProperty("id") String id, @JsonProperty("name") String name, @JsonProperty("code") int code, diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml index 8f22241dc..ee56c3f2e 100644 --- a/data/semantickernel-data-postgres/pom.xml +++ b/data/semantickernel-data-postgres/pom.xml @@ -51,7 +51,7 @@ org.postgresql postgresql - 42.7.7 + 42.7.10 \ No newline at end of file diff --git a/data/semantickernel-data-sqlite/pom.xml b/data/semantickernel-data-sqlite/pom.xml index fc4d80186..f490c247d 100644 --- a/data/semantickernel-data-sqlite/pom.xml +++ b/data/semantickernel-data-sqlite/pom.xml @@ -52,7 +52,7 @@ org.xerial sqlite-jdbc - 3.47.0.0 + 3.53.0.0 \ No newline at end of file diff --git a/pom.xml b/pom.xml index 9a52016ca..52630ac77 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ 1.0.0-beta.16 - 10.18.2 + 13.4.2 0.10.21 false 2.19.1 @@ -42,8 +42,7 @@ 3.10.1 3.5.0 2.4.0 - - 3.27.0 + 3.28.0 3.8.0 0.16.1 3.1.1 @@ -59,12 +58,11 @@ 2.17.1 5.14.2 0.9.1 - - 7.22.0 + 7.23.0 UTF-8 microsoft/semantic-kernel git@github.com:${project.github.repository}.git - 4.8.6 + 4.9.8 @@ -203,13 +201,32 @@ org.wiremock wiremock - 3.9.2 + 3.13.2 test org.mockito mockito-junit-jupiter - 5.14.2 + 5.23.0 + test + + + + org.testcontainers + junit-jupiter + 1.21.4 + test + + + org.testcontainers + postgresql + 1.21.4 + test + + + org.testcontainers + mysql + 1.21.4 test diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml index bd5b298ce..60d46fe7c 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml @@ -29,7 +29,7 @@ io.opentelemetry.instrumentation opentelemetry-reactor-3.1 - 2.9.0-alpha + 2.26.1-alpha com.microsoft.semantic-kernel @@ -140,20 +140,20 @@ org.apache.pdfbox pdfbox - 3.0.3 + 3.0.7 com.google.cloud google-cloud-vertexai - 1.6.0 + 1.52.0 compile com.mysql mysql-connector-j - 9.0.0 + 9.6.0 com.github.victools diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java index 5e01d13a2..c3ebd6a0f 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example62_CustomAIServiceSelector.java @@ -50,7 +50,7 @@ public static void main(String[] args) { var openAIChatCompletion = OpenAIChatCompletion.builder() .withOpenAIAsyncClient(client) .withServiceId("AzureOpenAIChat") - .withModelId("gpt-35-turbo-2") + .withModelId("gpt-35-turbo") .build(); var textGenerationService = TextGenerationService.builder() diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java index 5d0aad36e..8a5d02334 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormat.java @@ -55,6 +55,7 @@ public static void main(String[] args) throws InterruptedException, JsonProcessi .setResponseFormat(Pet.class) .setName("Pet") .build()) + .withMaxCompletionTokensEnable(true) .build(); FunctionResult response = kernel diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java index cd227ebd5..a3126eff5 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/chatcompletion/responseschema/Example_ChatWithResponseFormatToolCall.java @@ -58,6 +58,7 @@ public static void main(String[] args) throws InterruptedException, JsonProcessi PromptExecutionSettings promptExecutionSettings = PromptExecutionSettings.builder() .withJsonSchemaResponseFormat(Pet.class) + .withMaxCompletionTokensEnable(true) .build(); FunctionResult response = kernel.invokePromptAsync("Get pet with id 1234") diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java index e921bb784..d021caf88 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/functions/Example59_OpenAIFunctionCalling.java @@ -39,7 +39,7 @@ public class Example59_OpenAIFunctionCalling { // Only required if AZURE_CLIENT_KEY is set private static final String CLIENT_ENDPOINT = System.getenv("CLIENT_ENDPOINT"); private static final String MODEL_ID = System.getenv() - .getOrDefault("MODEL_ID", "gpt-4o"); + .getOrDefault("MODEL_ID", "gpt-35-turbo"); // Define functions that can be called by the model public static class HelperFunctions { diff --git a/samples/semantickernel-demos/booking-agent-m365/pom.xml b/samples/semantickernel-demos/booking-agent-m365/pom.xml index 60bc7ffbc..05c970484 100644 --- a/samples/semantickernel-demos/booking-agent-m365/pom.xml +++ b/samples/semantickernel-demos/booking-agent-m365/pom.xml @@ -43,7 +43,7 @@ com.microsoft.graph microsoft-graph - 6.13.0 + 6.62.0 diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml index 8db11dcd1..0d3ba1784 100644 --- a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml +++ b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml @@ -31,40 +31,40 @@ org.springframework.boot spring-boot-test - 3.3.2 + 4.1.0-M4 test org.assertj assertj-core - 3.27.7 + 4.0.0-M1 test org.springframework.boot spring-boot-autoconfigure - 3.3.2 + 4.1.0-M4 org.springframework.boot spring-boot - 3.3.11 + 4.1.0-M4 org.springframework spring-test - 6.1.10 + 7.0.6 test com.azure azure-identity - 1.12.2 + 1.18.2 org.junit.jupiter junit-jupiter-api - 5.10.3 + 6.1.0-M1 test diff --git a/samples/semantickernel-learn-resources/pom.xml b/samples/semantickernel-learn-resources/pom.xml index 8d5130b22..22b76e1b7 100644 --- a/samples/semantickernel-learn-resources/pom.xml +++ b/samples/semantickernel-learn-resources/pom.xml @@ -89,7 +89,7 @@ com.mysql mysql-connector-j - 9.0.0 + 9.6.0 compile diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml index f0b576424..7f763a06a 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml @@ -62,7 +62,7 @@ io.swagger.parser.v3 swagger-parser - 2.1.22 + 2.1.40 com.microsoft.semantic-kernel diff --git a/semantickernel-api/pom.xml b/semantickernel-api/pom.xml index ace57557c..2b912eb9a 100644 --- a/semantickernel-api/pom.xml +++ b/semantickernel-api/pom.xml @@ -42,7 +42,7 @@ io.opentelemetry.instrumentation opentelemetry-reactor-3.1 - 2.9.0-alpha + 2.26.1-alpha com.azure diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java index e4d3f5300..586c93c5d 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/KernelHook.java @@ -104,6 +104,7 @@ static ChatCompletionsOptions cloneOptionsWithMessages( .setFrequencyPenalty(options.getFrequencyPenalty()) .setLogitBias(options.getLogitBias()) .setMaxTokens(options.getMaxTokens()) + .setMaxCompletionTokens(options.getMaxCompletionTokens()) .setModel(options.getModel()) .setStop(options.getStop()) .setTemperature(options.getTemperature()) diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java index 19dfbd0dd..9209123cc 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java @@ -82,6 +82,7 @@ public class PromptExecutionSettings { private static final String PRESENCE_PENALTY = "presence_penalty"; private static final String FREQUENCY_PENALTY = "frequency_penalty"; private static final String MAX_TOKENS = "max_tokens"; + private static final String MAX_COMPLETION_TOKENS = "max_completion_tokens"; private static final String BEST_OF = "best_of"; private static final String USER = "user"; private static final String STOP_SEQUENCES = "stop_sequences"; @@ -89,13 +90,19 @@ public class PromptExecutionSettings { private static final String TOKEN_SELECTION_BIASES = "token_selection_biases"; private static final String RESPONSE_FORMAT = "response_format"; + private static final String MAX_COMPLETION_TOKENS_ENABLE = "MAX_COMPLETION_TOKENS_ENABLE"; + private static final String DEFAULT_MAX_COMPLETION_TOKENS_ENABLE = System.getenv( + MAX_COMPLETION_TOKENS_ENABLE); + private final String serviceId; private final String modelId; private final double temperature; private final double topP; private final double presencePenalty; private final double frequencyPenalty; - private final int maxTokens; + private final boolean maxCompletionTokensEnable; + private final Integer maxCompletionTokens; + private final Integer maxTokens; private final int bestOf; private final int resultsPerPrompt; private final String user; @@ -135,14 +142,24 @@ public PromptExecutionSettings( @JsonProperty(USER) String user, @Nullable @JsonProperty(STOP_SEQUENCES) List stopSequences, @Nullable @JsonProperty(TOKEN_SELECTION_BIASES) Map tokenSelectionBiases, - @Nullable @JsonProperty(RESPONSE_FORMAT) ResponseFormat responseFormat) { + @Nullable @JsonProperty(RESPONSE_FORMAT) ResponseFormat responseFormat, + @JsonProperty(value = MAX_COMPLETION_TOKENS_ENABLE, defaultValue = "false") String maxCompletionTokensEnable) { this.serviceId = serviceId != null ? serviceId : DEFAULT_SERVICE_ID; this.modelId = modelId != null ? modelId : ""; this.temperature = clamp(temperature, 0d, 2d, DEFAULT_TEMPERATURE); this.topP = clamp(topP, 0d, 1d, DEFAULT_TOP_P); this.presencePenalty = clamp(presencePenalty, -2d, 2d, DEFAULT_PRESENCE_PENALTY); this.frequencyPenalty = clamp(frequencyPenalty, -2d, 2d, DEFAULT_FREQUENCY_PENALTY); - this.maxTokens = clamp(maxTokens, 1, Integer.MAX_VALUE, DEFAULT_MAX_TOKENS); + + this.maxCompletionTokensEnable = isMaxCompletionTokensEnable(maxCompletionTokensEnable); + + if (this.maxCompletionTokensEnable) { + this.maxCompletionTokens = clamp(maxTokens, 1, Integer.MAX_VALUE, DEFAULT_MAX_TOKENS); + this.maxTokens = null; + } else { + this.maxTokens = clamp(maxTokens, 1, Integer.MAX_VALUE, DEFAULT_MAX_TOKENS); + this.maxCompletionTokens = null; + } this.resultsPerPrompt = clamp(resultsPerPrompt, 1, Integer.MAX_VALUE, DEFAULT_RESULTS_PER_PROMPT); this.bestOf = clamp(bestOf, 1, Integer.MAX_VALUE, DEFAULT_BEST_OF); @@ -161,6 +178,22 @@ public PromptExecutionSettings( } } + private boolean isMaxCompletionTokensEnable(String maxCompletionTokensEnable) { + final boolean maxCompletionTokensEnabled; + if (maxCompletionTokensEnable != null && !maxCompletionTokensEnable.isEmpty()) { + maxCompletionTokensEnabled = Boolean.parseBoolean(maxCompletionTokensEnable); + } else { + if (DEFAULT_MAX_COMPLETION_TOKENS_ENABLE != null + && DEFAULT_MAX_COMPLETION_TOKENS_ENABLE.isEmpty()) { + maxCompletionTokensEnabled = Boolean.parseBoolean( + DEFAULT_MAX_COMPLETION_TOKENS_ENABLE); + } else { + maxCompletionTokensEnabled = false; + } + } + return maxCompletionTokensEnabled; + } + /** * Create a new builder for PromptExecutionSettings. * @@ -257,7 +290,7 @@ public double getFrequencyPenalty() { * @return The maximum number of tokens to generate in the output. */ @JsonProperty(MAX_TOKENS) - public int getMaxTokens() { + public Integer getMaxTokens() { return maxTokens; } @@ -383,6 +416,12 @@ public ResponseFormat getResponseFormat() { return responseFormat; } + + @JsonProperty(MAX_COMPLETION_TOKENS) + public Integer getMaxCompletionTokens() { + return maxCompletionTokens; + } + /** * Builder for PromptExecutionSettings. */ @@ -480,6 +519,18 @@ public Builder withMaxTokens(int maxTokens) { return this; } + /** + * Enables the use of max_completion_tokens config parameter rather than the older + * max_completion + * + * @param enable Whether to enable + * @return This builder + */ + public Builder withMaxCompletionTokensEnable(boolean enable) { + settings.put(MAX_COMPLETION_TOKENS_ENABLE, Boolean.toString(enable)); + return this; + } + /** * Set the number of results to generate for each prompt. The value is clamped to the range * [1, Integer.MAX_VALUE], and the default is 1. @@ -620,7 +671,9 @@ public PromptExecutionSettings build() { (List) settings.getOrDefault(STOP_SEQUENCES, Collections.emptyList()), (Map) settings.getOrDefault(TOKEN_SELECTION_BIASES, Collections.emptyMap()), - (ResponseFormat) settings.getOrDefault(RESPONSE_FORMAT, new TextResponseFormat())); + (ResponseFormat) settings.getOrDefault(RESPONSE_FORMAT, new TextResponseFormat()), + (String) settings.getOrDefault(MAX_COMPLETION_TOKENS_ENABLE, + DEFAULT_MAX_COMPLETION_TOKENS_ENABLE)); } } } diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 303e08b72..47b0a1c0b 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -13,7 +13,7 @@ https://www.github.com/microsoft/semantic-kernel - 2.18.6 + 2.21.2 @@ -52,7 +52,7 @@ io.opentelemetry opentelemetry-bom - 1.43.0 + 1.61.0 pom import @@ -150,17 +150,17 @@ com.azure azure-identity - 1.14.0 + 1.18.2 com.azure azure-core - 1.53.0 + 1.57.1 com.azure azure-search-documents - 11.8.0-beta.1 + 11.8.1 com.azure @@ -171,13 +171,13 @@ redis.clients jedis - 5.2.0 + 7.4.1 com.fasterxml.jackson.core jackson-annotations - ${com.fasterxml.jackson.core.version} + 2.21 com.fasterxml.jackson.core @@ -201,7 +201,7 @@ com.github.jknack handlebars - 4.3.1 + 4.5.0 jakarta.inject @@ -211,7 +211,7 @@ org.slf4j slf4j-api - 2.0.16 + 2.0.17 com.google.code.findbugs @@ -230,36 +230,36 @@ com.github.spotbugs spotbugs-annotations - 4.8.6 + 4.9.8 org.apache.commons commons-text - 1.14.0 + 1.15.0 com.google.cloud google-cloud-vertexai - 1.12.0 + 1.52.0 com.github.victools jsonschema-generator - 4.36.0 + 4.38.0 true com.github.victools jsonschema-module-jackson - 4.36.0 + 4.38.0 true io.projectreactor reactor-core - 3.7.8 + 3.8.5 diff --git a/semantickernel-experimental/pom.xml b/semantickernel-experimental/pom.xml index 5cdbd5349..86c0aee78 100644 --- a/semantickernel-experimental/pom.xml +++ b/semantickernel-experimental/pom.xml @@ -115,12 +115,12 @@ org.postgresql postgresql - 42.7.7 + 42.7.10 org.xerial sqlite-jdbc - 3.47.0.0 + 3.53.0.0 From bd492a6e880aa07257f6fbc2f5d2d22e96595424 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Thu, 16 Apr 2026 17:26:38 +0000 Subject: [PATCH 18/37] Bump versions --- agents/semantickernel-agents-core/pom.xml | 2 +- aiservices/google/pom.xml | 2 +- aiservices/huggingface/pom.xml | 2 +- aiservices/openai/pom.xml | 2 +- api-test/integration-tests/pom.xml | 2 +- api-test/pom.xml | 2 +- data/semantickernel-data-azureaisearch/pom.xml | 2 +- data/semantickernel-data-hsqldb/pom.xml | 2 +- data/semantickernel-data-jdbc/pom.xml | 2 +- data/semantickernel-data-mysql/pom.xml | 2 +- data/semantickernel-data-oracle/pom.xml | 2 +- data/semantickernel-data-postgres/pom.xml | 2 +- data/semantickernel-data-redis/pom.xml | 2 +- data/semantickernel-data-sqlite/pom.xml | 2 +- pom.xml | 2 +- samples/pom.xml | 2 +- samples/semantickernel-concepts/pom.xml | 2 +- .../semantickernel-syntax-examples/pom.xml | 2 +- samples/semantickernel-demos/booking-agent-m365/pom.xml | 2 +- samples/semantickernel-demos/pom.xml | 2 +- .../semantickernel-demos/semantickernel-spring-starter/pom.xml | 2 +- samples/semantickernel-demos/sk-presidio-sample/pom.xml | 2 +- samples/semantickernel-learn-resources/pom.xml | 2 +- samples/semantickernel-sample-plugins/pom.xml | 2 +- .../semantickernel-openapi-plugin/pom.xml | 2 +- .../semantickernel-presidio-plugin/pom.xml | 2 +- .../semantickernel-text-splitter-plugin/pom.xml | 2 +- semantickernel-api-ai-services/pom.xml | 2 +- semantickernel-api-builders/pom.xml | 2 +- semantickernel-api-data/pom.xml | 2 +- semantickernel-api-exceptions/pom.xml | 2 +- semantickernel-api-localization/pom.xml | 2 +- semantickernel-api-textembedding-services/pom.xml | 2 +- semantickernel-api/pom.xml | 2 +- semantickernel-bom/pom.xml | 2 +- semantickernel-experimental/pom.xml | 2 +- 36 files changed, 36 insertions(+), 36 deletions(-) diff --git a/agents/semantickernel-agents-core/pom.xml b/agents/semantickernel-agents-core/pom.xml index 1270d00d0..e237c85a8 100644 --- a/agents/semantickernel-agents-core/pom.xml +++ b/agents/semantickernel-agents-core/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/aiservices/google/pom.xml b/aiservices/google/pom.xml index f56bcab75..abe67c86f 100644 --- a/aiservices/google/pom.xml +++ b/aiservices/google/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/aiservices/huggingface/pom.xml b/aiservices/huggingface/pom.xml index 152aba546..139c98a9d 100644 --- a/aiservices/huggingface/pom.xml +++ b/aiservices/huggingface/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/aiservices/openai/pom.xml b/aiservices/openai/pom.xml index 992629a43..96e01cd19 100644 --- a/aiservices/openai/pom.xml +++ b/aiservices/openai/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/api-test/integration-tests/pom.xml b/api-test/integration-tests/pom.xml index f62567679..c919de195 100644 --- a/api-test/integration-tests/pom.xml +++ b/api-test/integration-tests/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel api-test - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/api-test/pom.xml b/api-test/pom.xml index 587dfe5b1..6b6e2ff60 100644 --- a/api-test/pom.xml +++ b/api-test/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/data/semantickernel-data-azureaisearch/pom.xml b/data/semantickernel-data-azureaisearch/pom.xml index c0f0a8c6a..b7b30067d 100644 --- a/data/semantickernel-data-azureaisearch/pom.xml +++ b/data/semantickernel-data-azureaisearch/pom.xml @@ -5,7 +5,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-hsqldb/pom.xml b/data/semantickernel-data-hsqldb/pom.xml index 1cd331795..5296d116c 100644 --- a/data/semantickernel-data-hsqldb/pom.xml +++ b/data/semantickernel-data-hsqldb/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-jdbc/pom.xml b/data/semantickernel-data-jdbc/pom.xml index 883d06432..68452053c 100644 --- a/data/semantickernel-data-jdbc/pom.xml +++ b/data/semantickernel-data-jdbc/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-mysql/pom.xml b/data/semantickernel-data-mysql/pom.xml index 3d6d40e6b..7826fd50c 100644 --- a/data/semantickernel-data-mysql/pom.xml +++ b/data/semantickernel-data-mysql/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml index 98644f9a9..f8376c9c0 100644 --- a/data/semantickernel-data-oracle/pom.xml +++ b/data/semantickernel-data-oracle/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml index ee56c3f2e..5ed076d3a 100644 --- a/data/semantickernel-data-postgres/pom.xml +++ b/data/semantickernel-data-postgres/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-redis/pom.xml b/data/semantickernel-data-redis/pom.xml index 885084d3b..8dffac895 100644 --- a/data/semantickernel-data-redis/pom.xml +++ b/data/semantickernel-data-redis/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-sqlite/pom.xml b/data/semantickernel-data-sqlite/pom.xml index f490c247d..79a8b15a7 100644 --- a/data/semantickernel-data-sqlite/pom.xml +++ b/data/semantickernel-data-sqlite/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index 52630ac77..cb089c6c9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT pom https://www.github.com/microsoft/semantic-kernel diff --git a/samples/pom.xml b/samples/pom.xml index d2bea638a..5dac1dfb8 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-concepts/pom.xml b/samples/semantickernel-concepts/pom.xml index 0b51d1255..bd7e73580 100644 --- a/samples/semantickernel-concepts/pom.xml +++ b/samples/semantickernel-concepts/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml index 60d46fe7c..55b6a06ee 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-concepts - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/booking-agent-m365/pom.xml b/samples/semantickernel-demos/booking-agent-m365/pom.xml index 05c970484..08b39c255 100644 --- a/samples/semantickernel-demos/booking-agent-m365/pom.xml +++ b/samples/semantickernel-demos/booking-agent-m365/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/pom.xml b/samples/semantickernel-demos/pom.xml index c19477a7c..a37b5822a 100644 --- a/samples/semantickernel-demos/pom.xml +++ b/samples/semantickernel-demos/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml index 0d3ba1784..b8656b4f6 100644 --- a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml +++ b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/sk-presidio-sample/pom.xml b/samples/semantickernel-demos/sk-presidio-sample/pom.xml index 079b5af0f..974f4b5b3 100644 --- a/samples/semantickernel-demos/sk-presidio-sample/pom.xml +++ b/samples/semantickernel-demos/sk-presidio-sample/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-learn-resources/pom.xml b/samples/semantickernel-learn-resources/pom.xml index 22b76e1b7..f7ffcb6ac 100644 --- a/samples/semantickernel-learn-resources/pom.xml +++ b/samples/semantickernel-learn-resources/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/pom.xml b/samples/semantickernel-sample-plugins/pom.xml index 0abacea7f..893e5a0d4 100644 --- a/samples/semantickernel-sample-plugins/pom.xml +++ b/samples/semantickernel-sample-plugins/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml index 7f763a06a..8785c2387 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml index 10326e6ea..30e912bb1 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml index 1bf80430f..32eab45e6 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-ai-services/pom.xml b/semantickernel-api-ai-services/pom.xml index 6187b56b4..3f3d7f611 100644 --- a/semantickernel-api-ai-services/pom.xml +++ b/semantickernel-api-ai-services/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-builders/pom.xml b/semantickernel-api-builders/pom.xml index be51b46f7..41bcd8d16 100644 --- a/semantickernel-api-builders/pom.xml +++ b/semantickernel-api-builders/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT com.microsoft.semantic-kernel diff --git a/semantickernel-api-data/pom.xml b/semantickernel-api-data/pom.xml index 13bd19931..972317a14 100644 --- a/semantickernel-api-data/pom.xml +++ b/semantickernel-api-data/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-exceptions/pom.xml b/semantickernel-api-exceptions/pom.xml index b07b001c0..a64467eca 100644 --- a/semantickernel-api-exceptions/pom.xml +++ b/semantickernel-api-exceptions/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-localization/pom.xml b/semantickernel-api-localization/pom.xml index f1c3c2467..3ea4a60bd 100644 --- a/semantickernel-api-localization/pom.xml +++ b/semantickernel-api-localization/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-textembedding-services/pom.xml b/semantickernel-api-textembedding-services/pom.xml index eb8391355..5b2e5181f 100644 --- a/semantickernel-api-textembedding-services/pom.xml +++ b/semantickernel-api-textembedding-services/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-api/pom.xml b/semantickernel-api/pom.xml index 2b912eb9a..ad0290493 100644 --- a/semantickernel-api/pom.xml +++ b/semantickernel-api/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT ../pom.xml diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 47b0a1c0b..cee100ed3 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -5,7 +5,7 @@ com.microsoft.semantic-kernel semantickernel-bom - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT pom Semantic Kernel Java BOM diff --git a/semantickernel-experimental/pom.xml b/semantickernel-experimental/pom.xml index 86c0aee78..61e60f645 100644 --- a/semantickernel-experimental/pom.xml +++ b/semantickernel-experimental/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.4.5-SNAPSHOT semantickernel-experimental From 5377046b34c50fa214d7a3dc6c7743696a92cd47 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Thu, 16 Apr 2026 18:28:52 +0000 Subject: [PATCH 19/37] Debump handlebars --- semantickernel-bom/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index cee100ed3..9b4361751 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -197,11 +197,11 @@ ${com.fasterxml.jackson.core.version} runtime - + com.github.jknack handlebars - 4.5.0 + 4.3.1 jakarta.inject From ca6445440dc24eb4e26eacf1a651c8c9cd672447 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Mon, 20 Apr 2026 16:19:04 +0000 Subject: [PATCH 20/37] Add allow/block list Fix typo Tidy up code Further cleanup --- .../openai/chatcompletion/OpenAIFunction.java | 6 +- .../plugin/KernelPluginFactory.java | 131 ++++++++++++++++-- 2 files changed, 124 insertions(+), 13 deletions(-) diff --git a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java index a5c5c6629..4ef550c23 100644 --- a/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java +++ b/aiservices/openai/src/main/java/com/microsoft/semantickernel/aiservices/openai/chatcompletion/OpenAIFunction.java @@ -7,22 +7,20 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.exceptions.SKException; import com.microsoft.semantickernel.orchestration.responseformat.ResponseSchemaGenerator; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; import com.microsoft.semantickernel.semanticfunctions.InputVariable; import com.microsoft.semantickernel.semanticfunctions.KernelFunctionMetadata; -import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; +import org.apache.commons.lang3.StringUtils; class OpenAIFunction { diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java index afa31cb00..e0bc517b5 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java @@ -27,10 +27,14 @@ import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.Map; +import java.util.Set; +import java.util.function.Predicate; import java.util.stream.Collectors; import javax.annotation.Nullable; import org.reactivestreams.Publisher; @@ -67,6 +71,12 @@ public class KernelPluginFactory { COMMON_CLASS_NAMES.put("map", HashMap.class); COMMON_CLASS_NAMES.put("set", HashSet.class); + COMMON_CLASS_NAMES.put(Integer.class.getName(), int.class); + COMMON_CLASS_NAMES.put(String.class.getName(), String.class); + COMMON_CLASS_NAMES.put(List.class.getName(), ArrayList.class); + COMMON_CLASS_NAMES.put(Map.class.getName(), HashMap.class); + COMMON_CLASS_NAMES.put(Set.class.getName(), HashSet.class); + BOXED_FROM_PRIMITIVE.put(void.class, Void.class); BOXED_FROM_PRIMITIVE.put(int.class, Integer.class); BOXED_FROM_PRIMITIVE.put(double.class, Double.class); @@ -240,21 +250,16 @@ public static Class getTypeForName(String className) { return clazz; } + if (!checkClassName(className)) { + throw new SKException("Requested type is not allowed: " + className); + } + try { clazz = Thread.currentThread().getContextClassLoader().loadClass(className); } catch (ClassNotFoundException e) { // ignore } - if (clazz == null) { - try { - // Seems that in tests specifically we need to use the class loader of the class itself - clazz = KernelPluginFactory.class.getClassLoader().loadClass(className); - } catch (ClassNotFoundException e) { - // ignore - } - } - if (clazz == null) { throw new SKException("Requested type could not be found: " + className + ". This needs to be a fully qualified class name, e.g. 'java.lang.String'."); @@ -262,6 +267,10 @@ public static Class getTypeForName(String className) { return clazz; } + public static boolean checkClassName(String className) { + return ClassFilter.CLASS_CHECKER.test(className); + } + /** * Creates a plugin from the provided name and function collection. * @@ -429,6 +438,7 @@ private static KernelFunction getKernelFunction( /** * Imports a plugin from a resource directory on the filesystem. + * * @param parentDirectory The parent directory containing the plugin directories. * @param pluginDirectoryName The name of the plugin directory. * @param functionName The name of the function to import. @@ -552,4 +562,107 @@ private static PromptTemplateConfig getPromptTemplateConfig( return null; } } + + // Filters allowed classes that can be used as types in plugins + public static class ClassFilter { + + // Selects which filter type to use, allow list or ban list + public static final String CLASS_BLOCK_TYPE_PROPERTY_NAME = "semantic-kernel.class-block-type"; + public static final String CLASS_BLOCK_LIST_PROPERTY_NAME = "semantic-kernel.class-block-list"; + public static final String CLASS_ALLOW_LIST_PROPERTY_NAME = "semantic-kernel.class-allow-list"; + + // allow nothing by default (other than java primitives and collections) + private static final List CLASS_ALLOW_LIST; + private static final List CLASS_ALLOW_LIST_DEFAULT = Collections.emptyList(); + + // block Java classes by default (other than java primitives and collections) + private static final List CLASS_BLOCK_LIST; + private static final List CLASS_BLOCK_LIST_DEFAULT = Arrays.asList( + "java\\..*", + "com\\.sun\\..*", + "javax\\..*", + "jdk\\..*", + "org\\.xml\\..*", + "org\\.w3c\\..*" + ); + + static Predicate CLASS_CHECKER; + + private enum BlockType { + BLOCK, + ALLOW + } + + static { + // Default to blocking type + String classFilterType = System.getProperty(CLASS_BLOCK_TYPE_PROPERTY_NAME, + BlockType.BLOCK.name()); + CLASS_BLOCK_LIST = getList(CLASS_BLOCK_LIST_PROPERTY_NAME, CLASS_BLOCK_LIST_DEFAULT); + CLASS_ALLOW_LIST = getList(CLASS_ALLOW_LIST_PROPERTY_NAME, CLASS_ALLOW_LIST_DEFAULT); + + BlockType type; + + try { + type = BlockType.valueOf(classFilterType.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException e) { + type = BlockType.BLOCK; + } + + switch (type) { + case ALLOW: + CLASS_CHECKER = ClassFilter::evaluateAllow; + break; + case BLOCK: + default: + CLASS_CHECKER = ClassFilter::evaluateBlock; + break; + } + } + + private static List getList(String propertyName, List defaultList) { + String blockList = System.getProperty(propertyName); + + if (blockList != null) { + return Arrays.asList(blockList.split(",")); + } else { + return defaultList; + } + } + + // Block classes/packages classes (other than common Java primitives and collections) + private static boolean evaluateBlock(String className) { + if (className == null || className.isEmpty()) { + return false; + } + + for (String ban : CLASS_BLOCK_LIST) { + if (className.matches(ban)) { + LOGGER.warn( + "Skipping class not allowed by class block list {}, if you wish to unblock this class update the property: {}", + className, CLASS_BLOCK_LIST_PROPERTY_NAME); + return false; + } + } + + return true; + } + + // Only allow explicitly allowed classes/packages (other than common Java primitives and collections) + private static boolean evaluateAllow(String className) { + if (className == null || className.isEmpty()) { + return false; + } + + for (String allow : CLASS_ALLOW_LIST) { + if (className.matches(allow)) { + return true; + } + } + + LOGGER.warn( + "Skipping class not allowed by class allow list {}, if you wish to allow this class update the property: {}", + className, CLASS_ALLOW_LIST_DEFAULT); + return false; + } + } } From f879a77131d0c3df48703c3ab71ae0587e7b5349 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Wed, 22 Apr 2026 16:53:55 +0000 Subject: [PATCH 21/37] Fix null check --- .../orchestration/PromptExecutionSettings.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java index 9209123cc..bfa2bb667 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/PromptExecutionSettings.java @@ -384,7 +384,10 @@ public boolean equals(Object obj) { if (Double.compare(frequencyPenalty, other.frequencyPenalty) != 0) { return false; } - if (maxTokens != other.maxTokens) { + if (!Objects.equals(maxTokens, other.maxTokens)) { + return false; + } + if (!Objects.equals(maxCompletionTokens, other.maxCompletionTokens)) { return false; } if (bestOf != other.bestOf) { From 021faabd01f36887a6a9c11e0cdb8089849b6743 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Wed, 22 Apr 2026 17:21:22 +0000 Subject: [PATCH 22/37] Fix spotbugs issues --- .../services/HuggingFacePromptExecutionSettings.java | 5 +++-- .../jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java | 2 -- .../data/jdbc/JDBCVectorStoreQueryProvider.java | 6 ++---- .../data/jdbc/JDBCVectorStoreRecordCollection.java | 1 - .../data/jdbc/mysql/MySQLVectorStoreQueryProvider.java | 6 ++---- .../postgres/PostgreSQLVectorStoreQueryProvider.java | 10 ++++------ .../jdbc/sqlite/SQLiteVectorStoreQueryProvider.java | 6 ++---- .../contextvariables/ContextVariableTypeConverter.java | 2 -- ...CollectionVariableContextVariableTypeConverter.java | 3 --- .../semantickernel/hooks/FunctionInvokedEvent.java | 3 +-- .../semantickernel/hooks/PreToolCallEvent.java | 3 +-- .../semantickernel/hooks/PromptRenderedEvent.java | 1 - .../orchestration/FunctionInvocation.java | 5 +---- .../handlebars/HandlebarsPromptTemplate.java | 4 +--- 14 files changed, 17 insertions(+), 40 deletions(-) diff --git a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java index 4ee23f26d..ac4f4c093 100644 --- a/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java +++ b/aiservices/huggingface/src/main/java/com/microsoft/semantickernel/aiservices/huggingface/services/HuggingFacePromptExecutionSettings.java @@ -103,10 +103,11 @@ public HuggingFacePromptExecutionSettings( @Nullable Boolean logProbs, @Nullable Integer topLogProbs, @Nullable Long seed, - @Nullable Boolean maxCompletionTokens) { + @Nullable Boolean maxCompletionTokensEnable) { super( serviceId, modelId, temperature, topP, presencePenalty, frequencyPenalty, maxTokens, - resultsPerPrompt, bestOf, user, stopSequences, tokenSelectionBiases, responseFormat, Boolean.toString(maxCompletionTokens)); + resultsPerPrompt, bestOf, user, stopSequences, tokenSelectionBiases, responseFormat, + Boolean.toString(Boolean.TRUE.equals(maxCompletionTokensEnable))); this.topK = topK; this.repetitionPenalty = repetitionPenalty; diff --git a/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java b/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java index 484313168..e105a20db 100644 --- a/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java +++ b/data/semantickernel-data-hsqldb/src/main/java/com/microsoft/semantickernel/data/jdbc/hsqldb/HSQLDBVectorStoreQueryProvider.java @@ -12,7 +12,6 @@ import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; import com.microsoft.semantickernel.exceptions.SKException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -32,7 +31,6 @@ public class HSQLDBVectorStoreQueryProvider extends JDBCVectorStoreQueryProvider private final ObjectMapper objectMapper; - @SuppressFBWarnings("EI_EXPOSE_REP2") private HSQLDBVectorStoreQueryProvider( DataSource dataSource, String collectionsTable, diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java index 2fcc2d5b7..3441ccfed 100644 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java +++ b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreQueryProvider.java @@ -29,8 +29,6 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; import java.util.stream.Stream; import javax.annotation.Nonnull; @@ -59,7 +57,6 @@ public class JDBCVectorStoreQueryProvider private final Object dbCreationLock = new Object(); - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed protected JDBCVectorStoreQueryProvider( @Nonnull DataSource dataSource, @Nonnull String collectionsTable, @@ -102,8 +99,9 @@ protected JDBCVectorStoreQueryProvider( * @param supportedDataTypes the supported data types * @param supportedVectorTypes the supported vector types */ + @SuppressFBWarnings("EI_EXPOSE_REP2") public JDBCVectorStoreQueryProvider( - @SuppressFBWarnings("EI_EXPOSE_REP2") @Nonnull DataSource dataSource, + @Nonnull DataSource dataSource, @Nonnull String collectionsTable, @Nonnull String prefixForCollectionTables, @Nonnull Map, String> supportedKeyTypes, diff --git a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java index 1d6b3e09b..fc421c2b0 100644 --- a/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java +++ b/data/semantickernel-data-jdbc/src/main/java/com/microsoft/semantickernel/data/jdbc/JDBCVectorStoreRecordCollection.java @@ -46,7 +46,6 @@ public class JDBCVectorStoreRecordCollection * @param collectionName the name of the collection * @param options the options */ - @SuppressFBWarnings("EI_EXPOSE_REP2") // DataSource is not exposed public JDBCVectorStoreRecordCollection( @Nonnull DataSource dataSource, @Nonnull String collectionName, diff --git a/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java b/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java index feb6dc4f3..1ff0f7068 100644 --- a/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java +++ b/data/semantickernel-data-mysql/src/main/java/com/microsoft/semantickernel/data/jdbc/mysql/MySQLVectorStoreQueryProvider.java @@ -13,14 +13,13 @@ import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; import com.microsoft.semantickernel.exceptions.SKException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List; import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.sql.DataSource; /** * The MySQL vector store query provider. @@ -32,7 +31,6 @@ public class MySQLVectorStoreQueryProvider extends private final ObjectMapper objectMapper; - @SuppressFBWarnings("EI_EXPOSE_REP2") private MySQLVectorStoreQueryProvider( @Nonnull DataSource dataSource, @Nonnull String collectionsTable, diff --git a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java b/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java index 1f3273eb3..e65bb9eb1 100644 --- a/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java +++ b/data/semantickernel-data-postgres/src/main/java/com/microsoft/semantickernel/data/jdbc/postgres/PostgreSQLVectorStoreQueryProvider.java @@ -4,10 +4,10 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; -import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; import com.microsoft.semantickernel.data.filter.AnyTagEqualToFilterClause; import com.microsoft.semantickernel.data.filter.EqualToFilterClause; +import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreQueryProvider; +import com.microsoft.semantickernel.data.jdbc.SQLVectorStoreQueryProvider; import com.microsoft.semantickernel.data.vectorsearch.VectorSearchFilter; import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResult; import com.microsoft.semantickernel.data.vectorsearch.VectorSearchResults; @@ -22,9 +22,6 @@ import com.microsoft.semantickernel.data.vectorstorage.options.VectorSearchOptions; import com.microsoft.semantickernel.exceptions.SKException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -38,6 +35,8 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; +import javax.annotation.Nonnull; +import javax.sql.DataSource; /** * The MySQL vector store query provider. @@ -50,7 +49,6 @@ public class PostgreSQLVectorStoreQueryProvider extends private final String prefixForCollectionTables; private final ObjectMapper objectMapper; - @SuppressFBWarnings("EI_EXPOSE_REP2") private PostgreSQLVectorStoreQueryProvider( @Nonnull DataSource dataSource, @Nonnull String collectionsTable, diff --git a/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java b/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java index 57de12257..2d88702ee 100644 --- a/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java +++ b/data/semantickernel-data-sqlite/src/main/java/com/microsoft/semantickernel/data/jdbc/sqlite/SQLiteVectorStoreQueryProvider.java @@ -13,13 +13,12 @@ import com.microsoft.semantickernel.data.vectorstorage.options.UpsertRecordOptions; import com.microsoft.semantickernel.exceptions.SKException; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; - -import javax.annotation.Nonnull; -import javax.sql.DataSource; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List; +import javax.annotation.Nonnull; +import javax.sql.DataSource; /** * A query provider for a vector store in SQLite. @@ -30,7 +29,6 @@ public class SQLiteVectorStoreQueryProvider extends private final DataSource dataSource; private final ObjectMapper objectMapper; - @SuppressFBWarnings("EI_EXPOSE_REP2") private SQLiteVectorStoreQueryProvider( @Nonnull DataSource dataSource, @Nonnull String collectionsTable, diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java index 22d53ec06..3082ecf8a 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/ContextVariableTypeConverter.java @@ -3,7 +3,6 @@ import com.microsoft.semantickernel.exceptions.SKException; import com.microsoft.semantickernel.localization.SemanticKernelResources; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -341,7 +340,6 @@ public static class Builder { * * @param clazz the class of the type */ - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") public Builder(Class clazz) { this.clazz = clazz; fromObject = x -> ContextVariableTypes.convert(x, clazz); diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java index d7bf72e00..5b2661971 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/contextvariables/converters/CollectionVariableContextVariableTypeConverter.java @@ -7,7 +7,6 @@ import com.microsoft.semantickernel.contextvariables.ContextVariableType; import com.microsoft.semantickernel.contextvariables.ContextVariableTypeConverter; import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.Collection; import java.util.stream.Collectors; @@ -24,7 +23,6 @@ public class CollectionVariableContextVariableTypeConverter extends * Creates a new instance of the {@link CollectionVariableContextVariableTypeConverter} class. * @param delimiter The delimiter to use joining elements of the collection. */ - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") public CollectionVariableContextVariableTypeConverter(String delimiter) { super( Collection.class, @@ -38,7 +36,6 @@ public CollectionVariableContextVariableTypeConverter(String delimiter) { /** * Creates a new instance of the {@link CollectionVariableContextVariableTypeConverter} class. */ - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") public CollectionVariableContextVariableTypeConverter() { this(","); } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java index 7a39cdfe8..715e71185 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/FunctionInvokedEvent.java @@ -2,8 +2,8 @@ package com.microsoft.semantickernel.hooks; import com.microsoft.semantickernel.orchestration.FunctionResult; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.KernelArguments; +import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import javax.annotation.Nullable; @@ -60,7 +60,6 @@ public KernelArguments getArguments() { * * @return the result */ - @SuppressFBWarnings("EI_EXPOSE_REP") public FunctionResult getResult() { return result; } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java index 42430f085..e5850228c 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PreToolCallEvent.java @@ -2,8 +2,8 @@ package com.microsoft.semantickernel.hooks; import com.microsoft.semantickernel.contextvariables.ContextVariableTypes; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.KernelArguments; +import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import javax.annotation.Nullable; @@ -52,7 +52,6 @@ public KernelArguments getArguments() { * Get the tool call function. * @return The tool call function. */ - @SuppressFBWarnings("EI_EXPOSE_REP2") public KernelFunction getFunction() { return function; } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java index 348d3bf12..fbd8cb801 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/hooks/PromptRenderedEvent.java @@ -55,7 +55,6 @@ public KernelArguments getArguments() { * * @return the prompt */ - @SuppressFBWarnings("EI_EXPOSE_REP") public String getPrompt() { return prompt; } diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java index 9b8a518c3..8641f201c 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/orchestration/FunctionInvocation.java @@ -14,9 +14,8 @@ import com.microsoft.semantickernel.hooks.KernelHooks.UnmodifiableKernelHooks; import com.microsoft.semantickernel.implementation.telemetry.SemanticKernelTelemetry; import com.microsoft.semantickernel.localization.SemanticKernelResources; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.KernelArguments; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import java.util.NoSuchElementException; import java.util.function.BiConsumer; import javax.annotation.Nullable; @@ -63,7 +62,6 @@ public class FunctionInvocation extends Mono> { * @param kernel The kernel to invoke the function on. * @param function The function to invoke. */ - @SuppressFBWarnings("EI_EXPOSE_REP2") public FunctionInvocation( Kernel kernel, KernelFunction function) { @@ -80,7 +78,6 @@ public FunctionInvocation( * @param function The function to invoke. * @param resultType The type of the result of the function invocation. */ - @SuppressFBWarnings("EI_EXPOSE_REP2") public FunctionInvocation( Kernel kernel, KernelFunction function, diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java index 460e48159..bd8df1383 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/templateengine/handlebars/HandlebarsPromptTemplate.java @@ -18,13 +18,12 @@ import com.microsoft.semantickernel.orchestration.InvocationContext; import com.microsoft.semantickernel.orchestration.ToolCallBehavior; import com.microsoft.semantickernel.plugin.KernelPlugin; -import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.KernelArguments; +import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.PromptTemplate; import com.microsoft.semantickernel.semanticfunctions.PromptTemplateConfig; import com.microsoft.semantickernel.semanticfunctions.PromptTemplateOption; import com.microsoft.semantickernel.services.chatcompletion.ChatMessageContent; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; @@ -192,7 +191,6 @@ private class HandleBarsPromptTemplateHandler { private final String template; private final Handlebars handlebars; - @SuppressFBWarnings("CT_CONSTRUCTOR_THROW") // Think this is a false positive public HandleBarsPromptTemplateHandler( Kernel kernel, String template, From 70a199818a60713cc834e451e4f80f6e1b9297d4 Mon Sep 17 00:00:00 2001 From: John Oliver <1615532+johnoliver@users.noreply.github.com> Date: Wed, 22 Apr 2026 18:51:08 +0000 Subject: [PATCH 23/37] Allow disabling filter --- .../Example69_MutableKernelPlugin.java | 2 ++ .../plugin/KernelPluginFactory.java | 25 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java index 23bd37787..591bab7eb 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/src/main/java/com/microsoft/semantickernel/samples/syntaxexamples/Example69_MutableKernelPlugin.java @@ -3,6 +3,7 @@ import com.microsoft.semantickernel.Kernel; import com.microsoft.semantickernel.plugin.KernelPlugin; +import com.microsoft.semantickernel.plugin.KernelPluginFactory; import com.microsoft.semantickernel.semanticfunctions.KernelFunction; import com.microsoft.semantickernel.semanticfunctions.annotations.DefineKernelFunction; @@ -16,6 +17,7 @@ public class Example69_MutableKernelPlugin { */ public static void main(String[] args) throws NoSuchMethodException { System.out.println("======== Example69_MutableKernelPlugin ========"); + KernelPluginFactory.setTypeFilterEnable(false); KernelPlugin plugin = new KernelPlugin("Plugin", "Mutable plugin", null); plugin.addFunction(KernelFunction.createFromMethod( diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java index e0bc517b5..fa31819f2 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/plugin/KernelPluginFactory.java @@ -25,6 +25,7 @@ import java.nio.charset.Charset; import java.nio.file.Files; import java.nio.file.Path; +import java.time.temporal.Temporal; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -54,7 +55,13 @@ public class KernelPluginFactory { private static final CaseInsensitiveMap> COMMON_CLASS_NAMES = new CaseInsensitiveMap<>(); private static final Map, Class> BOXED_FROM_PRIMITIVE = new HashMap<>(); + public static final String CLASS_FILTER_ENABLE_PROPERTY = "semantic-kernel.class-filter-enable"; + private static Boolean CLASS_FILTER_ENABLE; + static { + CLASS_FILTER_ENABLE = Boolean.parseBoolean( + System.getProperty(CLASS_FILTER_ENABLE_PROPERTY, "true")); + PRIMITIVE_CLASS_NAMES.put("void", void.class); PRIMITIVE_CLASS_NAMES.put("int", int.class); PRIMITIVE_CLASS_NAMES.put("double", double.class); @@ -76,6 +83,9 @@ public class KernelPluginFactory { COMMON_CLASS_NAMES.put(List.class.getName(), ArrayList.class); COMMON_CLASS_NAMES.put(Map.class.getName(), HashMap.class); COMMON_CLASS_NAMES.put(Set.class.getName(), HashSet.class); + COMMON_CLASS_NAMES.put(Temporal.class.getName(), Temporal.class); + COMMON_CLASS_NAMES.put(java.time.OffsetDateTime.class.getName(), java.time.OffsetDateTime.class); + COMMON_CLASS_NAMES.put(java.time.ZonedDateTime.class.getName(), java.time.ZonedDateTime.class); BOXED_FROM_PRIMITIVE.put(void.class, Void.class); BOXED_FROM_PRIMITIVE.put(int.class, Integer.class); @@ -89,6 +99,10 @@ public class KernelPluginFactory { } + public static void setTypeFilterEnable(boolean enable) { + KernelPluginFactory.CLASS_FILTER_ENABLE = enable; + } + /** * Creates a plugin that wraps the specified target object. Methods decorated with * {@code {@literal @}DefineSKFunction} will be included in the plugin. @@ -268,6 +282,9 @@ public static Class getTypeForName(String className) { } public static boolean checkClassName(String className) { + if (CLASS_FILTER_ENABLE == false) { + return true; + } return ClassFilter.CLASS_CHECKER.test(className); } @@ -638,8 +655,8 @@ private static boolean evaluateBlock(String className) { for (String ban : CLASS_BLOCK_LIST) { if (className.matches(ban)) { LOGGER.warn( - "Skipping class not allowed by class block list {}, if you wish to unblock this class update the property: {}", - className, CLASS_BLOCK_LIST_PROPERTY_NAME); + "Skipping class not allowed by class block list {}, if you wish to unblock this class update the property: {}. Filtering can also be controlled with {} and KernelPluginFactory.setTypeFilterEnable", + className, CLASS_BLOCK_LIST_PROPERTY_NAME, CLASS_FILTER_ENABLE_PROPERTY); return false; } } @@ -660,8 +677,8 @@ private static boolean evaluateAllow(String className) { } LOGGER.warn( - "Skipping class not allowed by class allow list {}, if you wish to allow this class update the property: {}", - className, CLASS_ALLOW_LIST_DEFAULT); + "Skipping class not allowed by class allow list {}, if you wish to allow this class update the property: {}. Filtering can also be controlled with {} and KernelPluginFactory.setTypeFilterEnable", + className, CLASS_ALLOW_LIST_DEFAULT, CLASS_FILTER_ENABLE_PROPERTY); return false; } } From cec7e78f495060011e57a4b739c7d9bcadf50470 Mon Sep 17 00:00:00 2001 From: GitHub Date: Wed, 22 Apr 2026 20:40:14 +0000 Subject: [PATCH 24/37] [maven-release-plugin] prepare release java-1.5.0 --- agents/semantickernel-agents-core/pom.xml | 2 +- aiservices/google/pom.xml | 2 +- aiservices/huggingface/pom.xml | 2 +- aiservices/openai/pom.xml | 2 +- api-test/integration-tests/pom.xml | 2 +- api-test/pom.xml | 2 +- data/semantickernel-data-azureaisearch/pom.xml | 5 ++--- data/semantickernel-data-hsqldb/pom.xml | 2 +- data/semantickernel-data-jdbc/pom.xml | 2 +- data/semantickernel-data-mysql/pom.xml | 2 +- data/semantickernel-data-oracle/pom.xml | 2 +- data/semantickernel-data-postgres/pom.xml | 2 +- data/semantickernel-data-redis/pom.xml | 2 +- data/semantickernel-data-sqlite/pom.xml | 2 +- pom.xml | 4 ++-- samples/pom.xml | 2 +- samples/semantickernel-concepts/pom.xml | 2 +- .../semantickernel-syntax-examples/pom.xml | 2 +- samples/semantickernel-demos/booking-agent-m365/pom.xml | 2 +- samples/semantickernel-demos/pom.xml | 2 +- .../semantickernel-spring-starter/pom.xml | 2 +- samples/semantickernel-demos/sk-presidio-sample/pom.xml | 2 +- samples/semantickernel-learn-resources/pom.xml | 2 +- samples/semantickernel-sample-plugins/pom.xml | 2 +- .../semantickernel-openapi-plugin/pom.xml | 2 +- .../semantickernel-presidio-plugin/pom.xml | 2 +- .../semantickernel-text-splitter-plugin/pom.xml | 2 +- semantickernel-api-ai-services/pom.xml | 2 +- semantickernel-api-builders/pom.xml | 2 +- semantickernel-api-data/pom.xml | 2 +- semantickernel-api-exceptions/pom.xml | 2 +- semantickernel-api-localization/pom.xml | 2 +- semantickernel-api-textembedding-services/pom.xml | 2 +- semantickernel-api/pom.xml | 2 +- semantickernel-bom/pom.xml | 4 ++-- semantickernel-experimental/pom.xml | 2 +- 36 files changed, 39 insertions(+), 40 deletions(-) diff --git a/agents/semantickernel-agents-core/pom.xml b/agents/semantickernel-agents-core/pom.xml index e237c85a8..d23bd4065 100644 --- a/agents/semantickernel-agents-core/pom.xml +++ b/agents/semantickernel-agents-core/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/aiservices/google/pom.xml b/aiservices/google/pom.xml index abe67c86f..59521e779 100644 --- a/aiservices/google/pom.xml +++ b/aiservices/google/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/aiservices/huggingface/pom.xml b/aiservices/huggingface/pom.xml index 139c98a9d..bcfd47ad7 100644 --- a/aiservices/huggingface/pom.xml +++ b/aiservices/huggingface/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/aiservices/openai/pom.xml b/aiservices/openai/pom.xml index 96e01cd19..51a0a4e6a 100644 --- a/aiservices/openai/pom.xml +++ b/aiservices/openai/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/api-test/integration-tests/pom.xml b/api-test/integration-tests/pom.xml index c919de195..4542a0750 100644 --- a/api-test/integration-tests/pom.xml +++ b/api-test/integration-tests/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel api-test - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/api-test/pom.xml b/api-test/pom.xml index 6b6e2ff60..9bbf5c593 100644 --- a/api-test/pom.xml +++ b/api-test/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/data/semantickernel-data-azureaisearch/pom.xml b/data/semantickernel-data-azureaisearch/pom.xml index b7b30067d..e3a48b252 100644 --- a/data/semantickernel-data-azureaisearch/pom.xml +++ b/data/semantickernel-data-azureaisearch/pom.xml @@ -1,11 +1,10 @@ - + 4.0.0 com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-hsqldb/pom.xml b/data/semantickernel-data-hsqldb/pom.xml index 5296d116c..da17a5c00 100644 --- a/data/semantickernel-data-hsqldb/pom.xml +++ b/data/semantickernel-data-hsqldb/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-jdbc/pom.xml b/data/semantickernel-data-jdbc/pom.xml index 68452053c..098cc08ca 100644 --- a/data/semantickernel-data-jdbc/pom.xml +++ b/data/semantickernel-data-jdbc/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-mysql/pom.xml b/data/semantickernel-data-mysql/pom.xml index 7826fd50c..adbd51b1c 100644 --- a/data/semantickernel-data-mysql/pom.xml +++ b/data/semantickernel-data-mysql/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml index f8376c9c0..40a760abb 100644 --- a/data/semantickernel-data-oracle/pom.xml +++ b/data/semantickernel-data-oracle/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml index 5ed076d3a..5e6ca4dc5 100644 --- a/data/semantickernel-data-postgres/pom.xml +++ b/data/semantickernel-data-postgres/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-redis/pom.xml b/data/semantickernel-data-redis/pom.xml index 8dffac895..5c8a79db7 100644 --- a/data/semantickernel-data-redis/pom.xml +++ b/data/semantickernel-data-redis/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/data/semantickernel-data-sqlite/pom.xml b/data/semantickernel-data-sqlite/pom.xml index 79a8b15a7..12d6c0083 100644 --- a/data/semantickernel-data-sqlite/pom.xml +++ b/data/semantickernel-data-sqlite/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../../pom.xml diff --git a/pom.xml b/pom.xml index 27018142b..a7c3832e9 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 pom https://www.github.com/microsoft/semantic-kernel @@ -947,6 +947,6 @@ https://github.com/microsoft/semantic-kernel scm:git:https://github.com/microsoft/semantic-kernel.git scm:git:https://github.com/microsoft/semantic-kernel.git - HEAD + java-1.5.0 diff --git a/samples/pom.xml b/samples/pom.xml index 5dac1dfb8..f4122eec5 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-concepts/pom.xml b/samples/semantickernel-concepts/pom.xml index bd7e73580..ff5b86e6e 100644 --- a/samples/semantickernel-concepts/pom.xml +++ b/samples/semantickernel-concepts/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml index 55b6a06ee..c62276fe7 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-concepts - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-demos/booking-agent-m365/pom.xml b/samples/semantickernel-demos/booking-agent-m365/pom.xml index 08b39c255..b219fa331 100644 --- a/samples/semantickernel-demos/booking-agent-m365/pom.xml +++ b/samples/semantickernel-demos/booking-agent-m365/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-demos/pom.xml b/samples/semantickernel-demos/pom.xml index a37b5822a..86ccc67d6 100644 --- a/samples/semantickernel-demos/pom.xml +++ b/samples/semantickernel-demos/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml index b8656b4f6..37026b278 100644 --- a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml +++ b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-demos/sk-presidio-sample/pom.xml b/samples/semantickernel-demos/sk-presidio-sample/pom.xml index 974f4b5b3..ead8e7920 100644 --- a/samples/semantickernel-demos/sk-presidio-sample/pom.xml +++ b/samples/semantickernel-demos/sk-presidio-sample/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-learn-resources/pom.xml b/samples/semantickernel-learn-resources/pom.xml index f7ffcb6ac..ecc8138ec 100644 --- a/samples/semantickernel-learn-resources/pom.xml +++ b/samples/semantickernel-learn-resources/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-sample-plugins/pom.xml b/samples/semantickernel-sample-plugins/pom.xml index 893e5a0d4..3cfedcb70 100644 --- a/samples/semantickernel-sample-plugins/pom.xml +++ b/samples/semantickernel-sample-plugins/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml index 8785c2387..b3664ab6a 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml index 30e912bb1..6edcde9f3 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml index 32eab45e6..ba34af35d 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-api-ai-services/pom.xml b/semantickernel-api-ai-services/pom.xml index 3f3d7f611..1412e3cb9 100644 --- a/semantickernel-api-ai-services/pom.xml +++ b/semantickernel-api-ai-services/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-api-builders/pom.xml b/semantickernel-api-builders/pom.xml index 41bcd8d16..ffd6774d3 100644 --- a/semantickernel-api-builders/pom.xml +++ b/semantickernel-api-builders/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 com.microsoft.semantic-kernel diff --git a/semantickernel-api-data/pom.xml b/semantickernel-api-data/pom.xml index 972317a14..15dc82103 100644 --- a/semantickernel-api-data/pom.xml +++ b/semantickernel-api-data/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-api-exceptions/pom.xml b/semantickernel-api-exceptions/pom.xml index a64467eca..a5ee92a06 100644 --- a/semantickernel-api-exceptions/pom.xml +++ b/semantickernel-api-exceptions/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-api-localization/pom.xml b/semantickernel-api-localization/pom.xml index 3ea4a60bd..82becc44b 100644 --- a/semantickernel-api-localization/pom.xml +++ b/semantickernel-api-localization/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-api-textembedding-services/pom.xml b/semantickernel-api-textembedding-services/pom.xml index 5b2e5181f..dfed9b1e6 100644 --- a/semantickernel-api-textembedding-services/pom.xml +++ b/semantickernel-api-textembedding-services/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-api/pom.xml b/semantickernel-api/pom.xml index ad0290493..7f25cdc0e 100644 --- a/semantickernel-api/pom.xml +++ b/semantickernel-api/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 ../pom.xml diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 9b4361751..ed3c8707a 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -5,7 +5,7 @@ com.microsoft.semantic-kernel semantickernel-bom - 1.4.5-SNAPSHOT + 1.5.0 pom Semantic Kernel Java BOM @@ -326,6 +326,6 @@ https://github.com/microsoft/semantic-kernel scm:git:https://github.com/microsoft/semantic-kernel.git scm:git:https://github.com/microsoft/semantic-kernel.git - HEAD + java-1.5.0 diff --git a/semantickernel-experimental/pom.xml b/semantickernel-experimental/pom.xml index 61e60f645..7dbcca0f3 100644 --- a/semantickernel-experimental/pom.xml +++ b/semantickernel-experimental/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.5-SNAPSHOT + 1.5.0 semantickernel-experimental From c62ca9ef6b1e048326cb858577fd94ed6445dba6 Mon Sep 17 00:00:00 2001 From: GitHub Date: Wed, 22 Apr 2026 20:40:15 +0000 Subject: [PATCH 25/37] [maven-release-plugin] prepare for next development iteration --- agents/semantickernel-agents-core/pom.xml | 2 +- aiservices/google/pom.xml | 2 +- aiservices/huggingface/pom.xml | 2 +- aiservices/openai/pom.xml | 2 +- api-test/integration-tests/pom.xml | 2 +- api-test/pom.xml | 2 +- data/semantickernel-data-azureaisearch/pom.xml | 2 +- data/semantickernel-data-hsqldb/pom.xml | 2 +- data/semantickernel-data-jdbc/pom.xml | 2 +- data/semantickernel-data-mysql/pom.xml | 2 +- data/semantickernel-data-oracle/pom.xml | 2 +- data/semantickernel-data-postgres/pom.xml | 2 +- data/semantickernel-data-redis/pom.xml | 2 +- data/semantickernel-data-sqlite/pom.xml | 2 +- pom.xml | 4 ++-- samples/pom.xml | 2 +- samples/semantickernel-concepts/pom.xml | 2 +- .../semantickernel-syntax-examples/pom.xml | 2 +- samples/semantickernel-demos/booking-agent-m365/pom.xml | 2 +- samples/semantickernel-demos/pom.xml | 2 +- .../semantickernel-spring-starter/pom.xml | 2 +- samples/semantickernel-demos/sk-presidio-sample/pom.xml | 2 +- samples/semantickernel-learn-resources/pom.xml | 2 +- samples/semantickernel-sample-plugins/pom.xml | 2 +- .../semantickernel-openapi-plugin/pom.xml | 2 +- .../semantickernel-presidio-plugin/pom.xml | 2 +- .../semantickernel-text-splitter-plugin/pom.xml | 2 +- semantickernel-api-ai-services/pom.xml | 2 +- semantickernel-api-builders/pom.xml | 2 +- semantickernel-api-data/pom.xml | 2 +- semantickernel-api-exceptions/pom.xml | 2 +- semantickernel-api-localization/pom.xml | 2 +- semantickernel-api-textembedding-services/pom.xml | 2 +- semantickernel-api/pom.xml | 2 +- semantickernel-bom/pom.xml | 4 ++-- semantickernel-experimental/pom.xml | 2 +- 36 files changed, 38 insertions(+), 38 deletions(-) diff --git a/agents/semantickernel-agents-core/pom.xml b/agents/semantickernel-agents-core/pom.xml index d23bd4065..d5376209b 100644 --- a/agents/semantickernel-agents-core/pom.xml +++ b/agents/semantickernel-agents-core/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/aiservices/google/pom.xml b/aiservices/google/pom.xml index 59521e779..e136a3eb3 100644 --- a/aiservices/google/pom.xml +++ b/aiservices/google/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/aiservices/huggingface/pom.xml b/aiservices/huggingface/pom.xml index bcfd47ad7..82f5cd52d 100644 --- a/aiservices/huggingface/pom.xml +++ b/aiservices/huggingface/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/aiservices/openai/pom.xml b/aiservices/openai/pom.xml index 51a0a4e6a..4b46bdd4a 100644 --- a/aiservices/openai/pom.xml +++ b/aiservices/openai/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/api-test/integration-tests/pom.xml b/api-test/integration-tests/pom.xml index 4542a0750..9b5c3883d 100644 --- a/api-test/integration-tests/pom.xml +++ b/api-test/integration-tests/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel api-test - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/api-test/pom.xml b/api-test/pom.xml index 9bbf5c593..7b023c30a 100644 --- a/api-test/pom.xml +++ b/api-test/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/data/semantickernel-data-azureaisearch/pom.xml b/data/semantickernel-data-azureaisearch/pom.xml index e3a48b252..714c99484 100644 --- a/data/semantickernel-data-azureaisearch/pom.xml +++ b/data/semantickernel-data-azureaisearch/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-hsqldb/pom.xml b/data/semantickernel-data-hsqldb/pom.xml index da17a5c00..bb06dfe4a 100644 --- a/data/semantickernel-data-hsqldb/pom.xml +++ b/data/semantickernel-data-hsqldb/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-jdbc/pom.xml b/data/semantickernel-data-jdbc/pom.xml index 098cc08ca..74de0e2c9 100644 --- a/data/semantickernel-data-jdbc/pom.xml +++ b/data/semantickernel-data-jdbc/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-mysql/pom.xml b/data/semantickernel-data-mysql/pom.xml index adbd51b1c..2ad3ec2de 100644 --- a/data/semantickernel-data-mysql/pom.xml +++ b/data/semantickernel-data-mysql/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml index 40a760abb..de631318e 100644 --- a/data/semantickernel-data-oracle/pom.xml +++ b/data/semantickernel-data-oracle/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml index 5e6ca4dc5..9949118d9 100644 --- a/data/semantickernel-data-postgres/pom.xml +++ b/data/semantickernel-data-postgres/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-redis/pom.xml b/data/semantickernel-data-redis/pom.xml index 5c8a79db7..db151484b 100644 --- a/data/semantickernel-data-redis/pom.xml +++ b/data/semantickernel-data-redis/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/data/semantickernel-data-sqlite/pom.xml b/data/semantickernel-data-sqlite/pom.xml index 12d6c0083..7b4faa3de 100644 --- a/data/semantickernel-data-sqlite/pom.xml +++ b/data/semantickernel-data-sqlite/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../../pom.xml diff --git a/pom.xml b/pom.xml index a7c3832e9..611f44723 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT pom https://www.github.com/microsoft/semantic-kernel @@ -947,6 +947,6 @@ https://github.com/microsoft/semantic-kernel scm:git:https://github.com/microsoft/semantic-kernel.git scm:git:https://github.com/microsoft/semantic-kernel.git - java-1.5.0 + HEAD diff --git a/samples/pom.xml b/samples/pom.xml index f4122eec5..6ddaea22d 100644 --- a/samples/pom.xml +++ b/samples/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-concepts/pom.xml b/samples/semantickernel-concepts/pom.xml index ff5b86e6e..99d85497c 100644 --- a/samples/semantickernel-concepts/pom.xml +++ b/samples/semantickernel-concepts/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml index c62276fe7..8d42b664b 100644 --- a/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml +++ b/samples/semantickernel-concepts/semantickernel-syntax-examples/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-concepts - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/booking-agent-m365/pom.xml b/samples/semantickernel-demos/booking-agent-m365/pom.xml index b219fa331..ad08549e4 100644 --- a/samples/semantickernel-demos/booking-agent-m365/pom.xml +++ b/samples/semantickernel-demos/booking-agent-m365/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/pom.xml b/samples/semantickernel-demos/pom.xml index 86ccc67d6..ba42e0dbd 100644 --- a/samples/semantickernel-demos/pom.xml +++ b/samples/semantickernel-demos/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml index 37026b278..29454883a 100644 --- a/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml +++ b/samples/semantickernel-demos/semantickernel-spring-starter/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-demos/sk-presidio-sample/pom.xml b/samples/semantickernel-demos/sk-presidio-sample/pom.xml index ead8e7920..2684a88ca 100644 --- a/samples/semantickernel-demos/sk-presidio-sample/pom.xml +++ b/samples/semantickernel-demos/sk-presidio-sample/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-demos - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-learn-resources/pom.xml b/samples/semantickernel-learn-resources/pom.xml index ecc8138ec..420b98e30 100644 --- a/samples/semantickernel-learn-resources/pom.xml +++ b/samples/semantickernel-learn-resources/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/pom.xml b/samples/semantickernel-sample-plugins/pom.xml index 3cfedcb70..c09c6ea8b 100644 --- a/samples/semantickernel-sample-plugins/pom.xml +++ b/samples/semantickernel-sample-plugins/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-samples-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml index b3664ab6a..4016488ab 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-openapi-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml index 6edcde9f3..af97964db 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-presidio-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml index ba34af35d..5236bcff4 100644 --- a/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml +++ b/samples/semantickernel-sample-plugins/semantickernel-text-splitter-plugin/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-sample-plugins - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-ai-services/pom.xml b/semantickernel-api-ai-services/pom.xml index 1412e3cb9..e1fd17ef3 100644 --- a/semantickernel-api-ai-services/pom.xml +++ b/semantickernel-api-ai-services/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-builders/pom.xml b/semantickernel-api-builders/pom.xml index ffd6774d3..cbd35cb81 100644 --- a/semantickernel-api-builders/pom.xml +++ b/semantickernel-api-builders/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT com.microsoft.semantic-kernel diff --git a/semantickernel-api-data/pom.xml b/semantickernel-api-data/pom.xml index 15dc82103..9e055c1e8 100644 --- a/semantickernel-api-data/pom.xml +++ b/semantickernel-api-data/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-exceptions/pom.xml b/semantickernel-api-exceptions/pom.xml index a5ee92a06..bb60deadb 100644 --- a/semantickernel-api-exceptions/pom.xml +++ b/semantickernel-api-exceptions/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-localization/pom.xml b/semantickernel-api-localization/pom.xml index 82becc44b..b57ad77f1 100644 --- a/semantickernel-api-localization/pom.xml +++ b/semantickernel-api-localization/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-api-textembedding-services/pom.xml b/semantickernel-api-textembedding-services/pom.xml index dfed9b1e6..3cba6dd41 100644 --- a/semantickernel-api-textembedding-services/pom.xml +++ b/semantickernel-api-textembedding-services/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-api/pom.xml b/semantickernel-api/pom.xml index 7f25cdc0e..dcebfbc60 100644 --- a/semantickernel-api/pom.xml +++ b/semantickernel-api/pom.xml @@ -6,7 +6,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT ../pom.xml diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index ed3c8707a..424a84faa 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -5,7 +5,7 @@ com.microsoft.semantic-kernel semantickernel-bom - 1.5.0 + 1.5.1-SNAPSHOT pom Semantic Kernel Java BOM @@ -326,6 +326,6 @@ https://github.com/microsoft/semantic-kernel scm:git:https://github.com/microsoft/semantic-kernel.git scm:git:https://github.com/microsoft/semantic-kernel.git - java-1.5.0 + HEAD diff --git a/semantickernel-experimental/pom.xml b/semantickernel-experimental/pom.xml index 7dbcca0f3..63031771a 100644 --- a/semantickernel-experimental/pom.xml +++ b/semantickernel-experimental/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.5.0 + 1.5.1-SNAPSHOT semantickernel-experimental From 8213b74a99e9e6cd0ba3144647669c3e742ef7c5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 6 May 2026 15:15:32 +0000 Subject: [PATCH 26/37] Bump org.postgresql:postgresql in /data/semantickernel-data-postgres Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.10 to 42.7.11. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.10...REL42.7.11) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-version: 42.7.11 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- data/semantickernel-data-postgres/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml index 9949118d9..810a9f535 100644 --- a/data/semantickernel-data-postgres/pom.xml +++ b/data/semantickernel-data-postgres/pom.xml @@ -51,7 +51,7 @@ org.postgresql postgresql - 42.7.10 + 42.7.11 \ No newline at end of file From d042f6a02241fd50c525f6e52c3e9bc03d7c82f1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jun 2026 07:52:58 +0000 Subject: [PATCH 27/37] Bump actions/checkout from 6 to 7 Bumps [actions/checkout](https://github.com/actions/checkout) from 6 to 7. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6...v7) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: '7' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/codeql-analysis.yml | 2 +- .github/workflows/java-build.yml | 2 +- .github/workflows/java-integration-tests.yml | 2 +- .github/workflows/java-publish-package.yml | 2 +- .github/workflows/markdown-link-check.yml | 2 +- .github/workflows/typos.yaml | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index dee4d1c46..5fe9e853c 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v6 + uses: actions/checkout@v7 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL diff --git a/.github/workflows/java-build.yml b/.github/workflows/java-build.yml index d63a0d44d..bf35695ae 100644 --- a/.github/workflows/java-build.yml +++ b/.github/workflows/java-build.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 # Need to use JDK 11 to build for JDK 8 - name: Set JDK diff --git a/.github/workflows/java-integration-tests.yml b/.github/workflows/java-integration-tests.yml index 17edd75ed..45afb219e 100644 --- a/.github/workflows/java-integration-tests.yml +++ b/.github/workflows/java-integration-tests.yml @@ -22,7 +22,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 # Need to use JDK 11 to build for JDK 8 - name: Set JDK diff --git a/.github/workflows/java-publish-package.yml b/.github/workflows/java-publish-package.yml index 1f73e6885..38512904f 100644 --- a/.github/workflows/java-publish-package.yml +++ b/.github/workflows/java-publish-package.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v6 + uses: actions/checkout@v7 # Sets up the specified JDK version from the matrix - uses: actions/setup-java@v5 diff --git a/.github/workflows/markdown-link-check.yml b/.github/workflows/markdown-link-check.yml index bc1a1fa72..530cb5f48 100644 --- a/.github/workflows/markdown-link-check.yml +++ b/.github/workflows/markdown-link-check.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest # check out the latest version of the code steps: - - uses: actions/checkout@v6 + - uses: actions/checkout@v7 # Checks the status of hyperlinks in .md files in verbose mode - name: Check links diff --git a/.github/workflows/typos.yaml b/.github/workflows/typos.yaml index 532f4d5dc..c6845f2ab 100644 --- a/.github/workflows/typos.yaml +++ b/.github/workflows/typos.yaml @@ -20,7 +20,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v6 + uses: actions/checkout@v7 - name: Use custom config file uses: crate-ci/typos@master From 82ddc409b6b0e44d79a90925c8392ffaf5b98a7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 30 Jun 2026 03:28:00 +0000 Subject: [PATCH 28/37] Bump com.fasterxml.jackson.core:jackson-databind in /semantickernel-bom Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.21.2 to 2.22.0. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.22.0 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- semantickernel-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 424a84faa..1d4947b3a 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -13,7 +13,7 @@ https://www.github.com/microsoft/semantic-kernel - 2.21.2 + 2.22.0 From 7b6ff97bf7d58a80f991dcc08a52dbbe62241494 Mon Sep 17 00:00:00 2001 From: John <1615532+johnoliver@users.noreply.github.com> Date: Thu, 9 Jul 2026 21:50:54 +0100 Subject: [PATCH 29/37] Add profile that allows skiping container tests for when running in environments that cannot pull docker images (#365) --- data/semantickernel-data-oracle/pom.xml | 7 +++++++ pom.xml | 9 +++++++++ 2 files changed, 16 insertions(+) diff --git a/data/semantickernel-data-oracle/pom.xml b/data/semantickernel-data-oracle/pom.xml index de631318e..42ec5b2cd 100644 --- a/data/semantickernel-data-oracle/pom.xml +++ b/data/semantickernel-data-oracle/pom.xml @@ -119,6 +119,13 @@ true + + org.apache.maven.plugins + maven-surefire-plugin + + ${skipTests.oracle} + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 611f44723..fd834bd30 100644 --- a/pom.xml +++ b/pom.xml @@ -837,6 +837,15 @@ api-test + + skip-container-tests + + false + + + true + + release From a7c6a33472d868b428250be02054cf37dee7d725 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 14:16:09 +0000 Subject: [PATCH 30/37] Bump org.postgresql:postgresql in /data/semantickernel-data-jdbc Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.10 to 42.7.12. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.10...REL42.7.12) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-version: 42.7.12 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- data/semantickernel-data-jdbc/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/semantickernel-data-jdbc/pom.xml b/data/semantickernel-data-jdbc/pom.xml index 74de0e2c9..cf8069ec0 100644 --- a/data/semantickernel-data-jdbc/pom.xml +++ b/data/semantickernel-data-jdbc/pom.xml @@ -66,7 +66,7 @@ org.postgresql postgresql - 42.7.10 + 42.7.12 org.xerial From 1e7b081ec2706f26029e7c736cb4836e3b2d6d9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 14:18:40 +0000 Subject: [PATCH 31/37] Bump org.postgresql:postgresql in /data/semantickernel-data-postgres Bumps [org.postgresql:postgresql](https://github.com/pgjdbc/pgjdbc) from 42.7.11 to 42.7.12. - [Release notes](https://github.com/pgjdbc/pgjdbc/releases) - [Changelog](https://github.com/pgjdbc/pgjdbc/blob/master/CHANGELOG.md) - [Commits](https://github.com/pgjdbc/pgjdbc/compare/REL42.7.11...REL42.7.12) --- updated-dependencies: - dependency-name: org.postgresql:postgresql dependency-version: 42.7.12 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- data/semantickernel-data-postgres/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/semantickernel-data-postgres/pom.xml b/data/semantickernel-data-postgres/pom.xml index 810a9f535..cfc838f72 100644 --- a/data/semantickernel-data-postgres/pom.xml +++ b/data/semantickernel-data-postgres/pom.xml @@ -51,7 +51,7 @@ org.postgresql postgresql - 42.7.11 + 42.7.12 \ No newline at end of file From 1f5f2d5f65cff85530cffdd44b4110130e7cca0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 22:57:19 +0000 Subject: [PATCH 32/37] Bump com.fasterxml.jackson.core:jackson-core in /semantickernel-bom Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.22.0 to 2.22.1. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.22.0...jackson-core-2.22.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-version: 2.22.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- semantickernel-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 1d4947b3a..d0eb376b7 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -13,7 +13,7 @@ https://www.github.com/microsoft/semantic-kernel - 2.22.0 + 2.22.1 From 11f19e41603b63b14f9f67bc0a43a16744d76179 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Jul 2026 22:57:21 +0000 Subject: [PATCH 33/37] Bump com.fasterxml.jackson.core:jackson-databind in /semantickernel-bom Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.22.0 to 2.22.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-version: 2.22.1 dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- semantickernel-bom/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/semantickernel-bom/pom.xml b/semantickernel-bom/pom.xml index 1d4947b3a..d0eb376b7 100644 --- a/semantickernel-bom/pom.xml +++ b/semantickernel-bom/pom.xml @@ -13,7 +13,7 @@ https://www.github.com/microsoft/semantic-kernel - 2.22.0 + 2.22.1 From 7b607f7f860fe7b55380f3c0cb4068fc8697e736 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 3 Aug 2026 08:01:03 +0000 Subject: [PATCH 34/37] Bump actions/stale from 10 to 11 Bumps [actions/stale](https://github.com/actions/stale) from 10 to 11. - [Release notes](https://github.com/actions/stale/releases) - [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/stale/compare/v10...v11) --- updated-dependencies: - dependency-name: actions/stale dependency-version: '11' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/close-inactive-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/close-inactive-issues.yml b/.github/workflows/close-inactive-issues.yml index 4e6ebccef..bbd6a87c2 100644 --- a/.github/workflows/close-inactive-issues.yml +++ b/.github/workflows/close-inactive-issues.yml @@ -10,7 +10,7 @@ jobs: issues: write pull-requests: write steps: - - uses: actions/stale@v10 + - uses: actions/stale@v11 with: days-before-issue-stale: 90 days-before-issue-close: 14 From 1e0a854361b90eff422a7d432fd55633094498b0 Mon Sep 17 00:00:00 2001 From: fzowl Date: Sun, 16 Aug 2026 19:03:25 +0200 Subject: [PATCH 35/37] Make VoyageAI services and RerankResult final to satisfy SpotBugs CT_CONSTRUCTOR_THROW SpotBugs (bug-check profile) flagged CT_CONSTRUCTOR_THROW on classes whose constructors throw validation exceptions while being non-final, which the Java CI build treats as an error and fails merge-gatekeeper. Marking these value/service classes final removes the finalizer-attack vector SpotBugs warns about while preserving the existing constructor validation. --- .../VoyageAIContextualizedEmbeddingGenerationService.java | 2 +- .../semantickernel/aiservices/voyageai/core/VoyageAIClient.java | 2 +- .../VoyageAIMultimodalEmbeddingGenerationService.java | 2 +- .../voyageai/reranking/VoyageAITextRerankingService.java | 2 +- .../textembedding/VoyageAITextEmbeddingGenerationService.java | 2 +- .../semantickernel/services/reranking/RerankResult.java | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java index e04f6794e..2ccb39909 100644 --- a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/contextualizedembedding/VoyageAIContextualizedEmbeddingGenerationService.java @@ -23,7 +23,7 @@ * Generates embeddings that capture both local chunk details and global document-level metadata. * Supports models like voyage-3. */ -public class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService { +public final class VoyageAIContextualizedEmbeddingGenerationService implements TextEmbeddingGenerationService { private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIContextualizedEmbeddingGenerationService.class); diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java index 95188ea5b..856a33976 100644 --- a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIClient.java @@ -20,7 +20,7 @@ /** * HTTP client for VoyageAI API. */ -public class VoyageAIClient { +public final class VoyageAIClient { private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIClient.class); private static final MediaType JSON = MediaType.get("application/json; charset=utf-8"); private static final String DEFAULT_ENDPOINT = "https://api.voyageai.com/v1"; diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java index 239d29b5d..89304d37d 100644 --- a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/multimodalembedding/VoyageAIMultimodalEmbeddingGenerationService.java @@ -29,7 +29,7 @@ * - Total tokens per input: ≤32,000 (560 pixels = 1 token) * - Aggregate tokens across inputs: ≤320,000 */ -public class VoyageAIMultimodalEmbeddingGenerationService implements TextEmbeddingGenerationService { +public final class VoyageAIMultimodalEmbeddingGenerationService implements TextEmbeddingGenerationService { private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAIMultimodalEmbeddingGenerationService.class); diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java index 6b0f59fa6..cda093d7e 100644 --- a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/reranking/VoyageAITextRerankingService.java @@ -20,7 +20,7 @@ * VoyageAI implementation of {@link TextRerankingService}. * Supports models like rerank-2, rerank-2-lite. */ -public class VoyageAITextRerankingService implements TextRerankingService { +public final class VoyageAITextRerankingService implements TextRerankingService { private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAITextRerankingService.class); diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java index 22a393532..4345aca58 100644 --- a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/textembedding/VoyageAITextEmbeddingGenerationService.java @@ -21,7 +21,7 @@ * VoyageAI implementation of {@link TextEmbeddingGenerationService}. * Supports models like voyage-3-large, voyage-3.5, voyage-code-3, voyage-finance-2, voyage-law-2. */ -public class VoyageAITextEmbeddingGenerationService implements TextEmbeddingGenerationService { +public final class VoyageAITextEmbeddingGenerationService implements TextEmbeddingGenerationService { private static final Logger LOGGER = LoggerFactory.getLogger(VoyageAITextEmbeddingGenerationService.class); diff --git a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java index 9d365b765..d7d8b5c8a 100644 --- a/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java +++ b/semantickernel-api/src/main/java/com/microsoft/semantickernel/services/reranking/RerankResult.java @@ -4,7 +4,7 @@ /** * Represents a single reranking result containing a document and its relevance score. */ -public class RerankResult { +public final class RerankResult { private final int index; private final String text; private final double relevanceScore; From 8287d7a577eefa9ea862bd979f5bcaa74642e57f Mon Sep 17 00:00:00 2001 From: fzowl Date: Sun, 16 Aug 2026 19:10:03 +0200 Subject: [PATCH 36/37] Align VoyageAI module parent version with current main (1.5.1-SNAPSHOT) After merging upstream/main, the repository version advanced to 1.5.1-SNAPSHOT while the VoyageAI module still pinned the old 1.4.4-RC3-SNAPSHOT parent, which made the semantickernel-bom import unresolvable and broke the reactor build. --- aiservices/voyageai/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aiservices/voyageai/pom.xml b/aiservices/voyageai/pom.xml index db0d06a44..b359128df 100644 --- a/aiservices/voyageai/pom.xml +++ b/aiservices/voyageai/pom.xml @@ -4,7 +4,7 @@ com.microsoft.semantic-kernel semantickernel-parent - 1.4.4-RC3-SNAPSHOT + 1.5.1-SNAPSHOT ../../pom.xml From 5139ecb128beacf79dff9093db1c19322a14a100 Mon Sep 17 00:00:00 2001 From: fzowl Date: Sun, 16 Aug 2026 19:21:36 +0200 Subject: [PATCH 37/37] Suppress SpotBugs EI_EXPOSE_REP findings on VoyageAI DTO accessors The VoyageAIModels request/response DTOs expose their mutable list and array fields directly through getters, setters and one constructor, which SpotBugs (bug-check profile) flags as EI_EXPOSE_REP/EI_EXPOSE_REP2. These are plain Jackson-mapped data holders, so annotate the individual accessors with @SuppressFBWarnings, matching the pattern already used by the other aiservices DTOs (e.g. HuggingFace, OpenAI, Google). --- .../voyageai/core/VoyageAIModels.java | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java index b196d9e00..c1e853878 100644 --- a/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java +++ b/aiservices/voyageai/src/main/java/com/microsoft/semantickernel/aiservices/voyageai/core/VoyageAIModels.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonProperty; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.util.List; /** @@ -35,10 +36,12 @@ public static class EmbeddingRequest { @JsonProperty("output_dtype") private String outputDtype; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getInput() { return input; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setInput(List input) { this.input = input; } @@ -95,18 +98,22 @@ public static class EmbeddingResponse { @JsonProperty("usage") private EmbeddingUsage usage; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getData() { return data; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setData(List data) { this.data = data; } + @SuppressFBWarnings("EI_EXPOSE_REP") public EmbeddingUsage getUsage() { return usage; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setUsage(EmbeddingUsage usage) { this.usage = usage; } @@ -133,10 +140,12 @@ public void setObject(String object) { this.object = object; } + @SuppressFBWarnings("EI_EXPOSE_REP") public float[] getEmbedding() { return embedding; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setEmbedding(float[] embedding) { this.embedding = embedding; } @@ -196,10 +205,12 @@ public void setQuery(String query) { this.query = query; } + @SuppressFBWarnings("EI_EXPOSE_REP") public List getDocuments() { return documents; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setDocuments(List documents) { this.documents = documents; } @@ -240,18 +251,22 @@ public static class RerankResponse { @JsonProperty("usage") private EmbeddingUsage usage; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getData() { return data; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setData(List data) { this.data = data; } + @SuppressFBWarnings("EI_EXPOSE_REP") public EmbeddingUsage getUsage() { return usage; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setUsage(EmbeddingUsage usage) { this.usage = usage; } @@ -309,10 +324,12 @@ public static class ContextualizedEmbeddingRequest { @JsonProperty("output_dtype") private String outputDtype; + @SuppressFBWarnings("EI_EXPOSE_REP") public List> getInputs() { return inputs; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setInputs(List> inputs) { this.inputs = inputs; } @@ -367,10 +384,12 @@ public static class ContextualizedEmbeddingResponse { @JsonProperty("data") private List data; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getData() { return data; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setData(List data) { this.data = data; } @@ -384,10 +403,12 @@ public static class ContextualizedEmbeddingDataList { @JsonProperty("data") private List data; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getData() { return data; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setData(List data) { this.data = data; } @@ -400,10 +421,12 @@ public static class ContextualizedEmbeddingResult { @JsonProperty("embeddings") private List embeddings; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getEmbeddings() { return embeddings; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setEmbeddings(List embeddings) { this.embeddings = embeddings; } @@ -422,10 +445,12 @@ public static class EmbeddingItem { @JsonProperty("index") private int index; + @SuppressFBWarnings("EI_EXPOSE_REP") public float[] getEmbedding() { return embedding; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setEmbedding(float[] embedding) { this.embedding = embedding; } @@ -455,7 +480,7 @@ public void setIndex(int index) { @JsonInclude(JsonInclude.Include.NON_NULL) public static class MultimodalContentItem { @JsonProperty("type") - private String type; // "text" or "image_url" + private String type; // "text" or "image_url" @JsonProperty("text") private String text; @@ -513,14 +538,17 @@ public MultimodalInput() { // Default constructor for Jackson } + @SuppressFBWarnings("EI_EXPOSE_REP2") public MultimodalInput(List content) { this.content = content; } + @SuppressFBWarnings("EI_EXPOSE_REP") public List getContent() { return content; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setContent(List content) { this.content = content; } @@ -543,10 +571,12 @@ public static class MultimodalEmbeddingRequest { @JsonProperty("truncation") private Boolean truncation; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getInputs() { return inputs; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setInputs(List inputs) { this.inputs = inputs; } @@ -587,18 +617,22 @@ public static class MultimodalEmbeddingResponse { @JsonProperty("usage") private EmbeddingUsage usage; + @SuppressFBWarnings("EI_EXPOSE_REP") public List getData() { return data; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setData(List data) { this.data = data; } + @SuppressFBWarnings("EI_EXPOSE_REP") public EmbeddingUsage getUsage() { return usage; } + @SuppressFBWarnings("EI_EXPOSE_REP2") public void setUsage(EmbeddingUsage usage) { this.usage = usage; }