From 34dedf97d46af55bb307050d81ce80b4ebf96c15 Mon Sep 17 00:00:00 2001 From: James Abbott Date: Sun, 1 Mar 2026 11:26:49 +0000 Subject: [PATCH 1/7] feat: Add support for dimensions in Vertex AI embedding services and tests --- .../VertexAIEmbeddingGeneratorTests.cs | 147 +++++++++++++++++- ...exAITextEmbeddingGenerationServiceTests.cs | 147 +++++++++++++++++- .../Core/VertexAI/VertexAIEmbeddingClient.cs | 15 +- .../Core/VertexAI/VertexAIEmbeddingRequest.cs | 10 +- .../VertexAIKernelBuilderExtensions.cs | 26 +++- ...ollectionExtensions.DependencyInjection.cs | 14 +- .../VertexAIServiceCollectionExtensions.cs | 14 +- .../Services/VertexAIEmbeddingGenerator.cs | 16 +- .../VertexAITextEmbeddingGenerationService.cs | 41 ++++- 9 files changed, 383 insertions(+), 47 deletions(-) diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs index d3304bb3bdd7..e293de580a7a 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs @@ -1,5 +1,9 @@ // Copyright (c) Microsoft. All rights reserved. +using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Microsoft.Extensions.AI; using Microsoft.SemanticKernel.Connectors.Google; @@ -7,27 +11,156 @@ namespace SemanticKernel.Connectors.Google.UnitTests.Services; -public sealed class VertexAIEmbeddingGeneratorTests +public sealed class VertexAIEmbeddingGeneratorTests : IDisposable { + private const string Model = "fake-model"; + private const string BearerKey = "fake-key"; + private const int Dimensions = 512; + private readonly HttpMessageHandlerStub _messageHandlerStub; + private readonly HttpClient _httpClient; + + public VertexAIEmbeddingGeneratorTests() + { + this._messageHandlerStub = new HttpMessageHandlerStub + { + ResponseToReturn = new HttpResponseMessage(System.Net.HttpStatusCode.OK) + { + Content = new StringContent( + """ + { + "predictions": [ + { + "embeddings": { + "values": [0.1, 0.2, 0.3, 0.4, 0.5] + } + } + ] + } + """, + Encoding.UTF8, + "application/json" + ) + } + }; + + this._httpClient = new HttpClient(this._messageHandlerStub, disposeHandler: false); + } + [Fact] public void AttributesShouldContainModelIdBearerAsString() { // Arrange & Act - string model = "fake-model"; - using var service = new VertexAIEmbeddingGenerator(model, "key", "location", "project"); + using var service = new VertexAIEmbeddingGenerator(Model, BearerKey, "location", "project"); // Assert - Assert.Equal(model, service.GetService()!.DefaultModelId); + Assert.Equal(Model, service.GetService()!.DefaultModelId); } [Fact] public void AttributesShouldContainModelIdBearerAsFunc() { // Arrange & Act - string model = "fake-model"; - using var service = new VertexAIEmbeddingGenerator(model, () => ValueTask.FromResult("key"), "location", "project"); + using var service = new VertexAIEmbeddingGenerator(Model, () => ValueTask.FromResult(BearerKey), "location", "project"); // Assert - Assert.Equal(model, service.GetService()!.DefaultModelId); + Assert.Equal(Model, service.GetService()!.DefaultModelId); + } + + [Fact] + public void AttributesShouldNotContainDimensionsWhenNotProvided() + { + // Arrange & Act + using var service = new VertexAIEmbeddingGenerator(Model, BearerKey, "location", "project"); + + // Assert + Assert.Null(service.GetService()!.DefaultModelDimensions); + } + + [Fact] + public void AttributesShouldContainDimensionsWhenProvided() + { + // Arrange & Act + using var service = new VertexAIEmbeddingGenerator(Model, BearerKey, "location", "project", dimensions: Dimensions); + + // Assert + Assert.Equal(Dimensions, service.GetService()!.DefaultModelDimensions); + } + + [Fact] + public void GetDimensionsReturnsCorrectValue() + { + // Arrange + using var service = new VertexAIEmbeddingGenerator(Model, BearerKey, "location", "project", dimensions: Dimensions); + + // Act + var result = service.GetService()!.DefaultModelDimensions; + + // Assert + Assert.Equal(Dimensions, result); + } + + [Fact] + public void GetDimensionsReturnsNullWhenNotProvided() + { + // Arrange + using var service = new VertexAIEmbeddingGenerator(Model, BearerKey, "location", "project"); + + // Act + var result = service.GetService()!.DefaultModelDimensions; + + // Assert + Assert.Null(result); + } + + [Fact] + public async Task ShouldNotIncludeDimensionsInRequestWhenNotProvidedAsync() + { + // Arrange + using var service = new VertexAIEmbeddingGenerator( + modelId: Model, + bearerKey: BearerKey, + location: "location", + projectId: "project", + dimensions: null, + httpClient: this._httpClient); + var dataToEmbed = new List { "Text to embed" }; + + // Act + await service.GenerateAsync(dataToEmbed); + + // Assert + Assert.NotNull(this._messageHandlerStub.RequestContent); + var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); + Assert.DoesNotContain("outputDimensionality", requestBody); + } + + [Theory] + [InlineData(Dimensions)] + [InlineData(Dimensions * 2)] + public async Task ShouldIncludeDimensionsInRequestWhenProvidedAsync(int? dimensions) + { + // Arrange + using var service = new VertexAIEmbeddingGenerator( + modelId: Model, + bearerKey: BearerKey, + location: "location", + projectId: "project", + dimensions: dimensions, + httpClient: this._httpClient); + var dataToEmbed = new List { "Text to embed" }; + + // Act + await service.GenerateAsync(dataToEmbed); + + // Assert + Assert.NotNull(this._messageHandlerStub.RequestContent); + var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); + Assert.Contains($"\"outputDimensionality\":{dimensions}", requestBody); + } + + public void Dispose() + { + this._messageHandlerStub.Dispose(); + this._httpClient.Dispose(); } } diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs index fbc3579fbfe7..3a076c32e001 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs @@ -1,35 +1,168 @@ // Copyright (c) Microsoft. All rights reserved. using System; +using System.Collections.Generic; +using System.Net.Http; +using System.Text; using System.Threading.Tasks; using Microsoft.SemanticKernel.Connectors.Google; +using Microsoft.SemanticKernel.Embeddings; using Microsoft.SemanticKernel.Services; using Xunit; namespace SemanticKernel.Connectors.Google.UnitTests.Services; [Obsolete("Temporary test for Obsolete ITextEmbeddingGenerationService")] -public sealed class VertexAITextEmbeddingGenerationServiceTests +public sealed class VertexAITextEmbeddingGenerationServiceTests : IDisposable { + private const string Model = "fake-model"; + private const string BearerKey = "fake-key"; + private const int Dimensions = 512; + private readonly HttpMessageHandlerStub _messageHandlerStub; + private readonly HttpClient _httpClient; + + public VertexAITextEmbeddingGenerationServiceTests() + { + this._messageHandlerStub = new HttpMessageHandlerStub + { + ResponseToReturn = new HttpResponseMessage(System.Net.HttpStatusCode.OK) + { + Content = new StringContent( + """ + { + "predictions": [ + { + "embeddings": { + "values": [0.1, 0.2, 0.3, 0.4, 0.5] + } + } + ] + } + """, + Encoding.UTF8, + "application/json" + ) + } + }; + + this._httpClient = new HttpClient(this._messageHandlerStub, disposeHandler: false); + } + [Fact] public void AttributesShouldContainModelIdBearerAsString() { // Arrange & Act - string model = "fake-model"; - var service = new VertexAITextEmbeddingGenerationService(model, "key", "location", "project"); + var service = new VertexAITextEmbeddingGenerationService(Model, BearerKey, "location", "project"); // Assert - Assert.Equal(model, service.Attributes[AIServiceExtensions.ModelIdKey]); + Assert.Equal(Model, service.Attributes[AIServiceExtensions.ModelIdKey]); } [Fact] public void AttributesShouldContainModelIdBearerAsFunc() { // Arrange & Act - string model = "fake-model"; - var service = new VertexAITextEmbeddingGenerationService(model, () => ValueTask.FromResult("key"), "location", "project"); + var service = new VertexAITextEmbeddingGenerationService(Model, () => ValueTask.FromResult(BearerKey), "location", "project"); // Assert - Assert.Equal(model, service.Attributes[AIServiceExtensions.ModelIdKey]); + Assert.Equal(Model, service.Attributes[AIServiceExtensions.ModelIdKey]); + } + + [Fact] + public void AttributesShouldNotContainDimensionsWhenNotProvided() + { + // Arrange & Act + var service = new VertexAITextEmbeddingGenerationService(Model, BearerKey, "location", "project"); + + // Assert + Assert.False(service.Attributes.ContainsKey(EmbeddingGenerationExtensions.DimensionsKey)); + } + + [Fact] + public void AttributesShouldContainDimensionsWhenProvided() + { + // Arrange & Act + var service = new VertexAITextEmbeddingGenerationService(Model, BearerKey, "location", "project", dimensions: Dimensions); + + // Assert + Assert.Equal(Dimensions, service.Attributes[EmbeddingGenerationExtensions.DimensionsKey]); + } + + [Fact] + public void GetDimensionsReturnsCorrectValue() + { + // Arrange + var service = new VertexAITextEmbeddingGenerationService(Model, BearerKey, "location", "project", dimensions: Dimensions); + + // Act + var result = service.GetDimensions(); + + // Assert + Assert.Equal(Dimensions, result); + } + + [Fact] + public void GetDimensionsReturnsNullWhenNotProvided() + { + // Arrange + var service = new VertexAITextEmbeddingGenerationService(Model, BearerKey, "location", "project"); + + // Act + var result = service.GetDimensions(); + + // Assert + Assert.Null(result); + } + + [Fact] + public async Task ShouldNotIncludeDimensionsInRequestWhenNotProvidedAsync() + { + // Arrange + var service = new VertexAITextEmbeddingGenerationService( + modelId: Model, + bearerKey: BearerKey, + location: "location", + projectId: "project", + dimensions: null, + httpClient: this._httpClient); + var dataToEmbed = new List { "Text to embed" }; + + // Act + await service.GenerateEmbeddingsAsync(dataToEmbed); + + // Assert + Assert.NotNull(this._messageHandlerStub.RequestContent); + var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); + Assert.DoesNotContain("outputDimensionality", requestBody); + } + + [Theory] + [InlineData(Dimensions)] + [InlineData(Dimensions * 2)] + public async Task ShouldIncludeDimensionsInRequestWhenProvidedAsync(int? dimensions) + { + // Arrange + var service = new VertexAITextEmbeddingGenerationService( + modelId: Model, + bearerKey: BearerKey, + location: "location", + projectId: "project", + dimensions: dimensions, + httpClient: this._httpClient); + var dataToEmbed = new List { "Text to embed" }; + + // Act + await service.GenerateEmbeddingsAsync(dataToEmbed); + + // Assert + Assert.NotNull(this._messageHandlerStub.RequestContent); + var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); + Assert.Contains($"\"outputDimensionality\":{dimensions}", requestBody); + } + + public void Dispose() + { + this._messageHandlerStub.Dispose(); + this._httpClient.Dispose(); } } diff --git a/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingClient.cs b/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingClient.cs index 0791de9d6262..e7b1c5343b61 100644 --- a/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingClient.cs +++ b/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingClient.cs @@ -6,6 +6,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.AI; using Microsoft.Extensions.Logging; namespace Microsoft.SemanticKernel.Connectors.Google.Core; @@ -17,6 +18,7 @@ internal sealed class VertexAIEmbeddingClient : ClientBase { private readonly string _embeddingModelId; private readonly Uri _embeddingEndpoint; + private readonly int? _dimensions; /// /// Represents a client for interacting with the embeddings models by Vertex AI. @@ -28,6 +30,7 @@ internal sealed class VertexAIEmbeddingClient : ClientBase /// Project ID from google cloud /// Version of the Vertex API /// Logger instance used for logging (optional) + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. public VertexAIEmbeddingClient( HttpClient httpClient, string modelId, @@ -35,7 +38,8 @@ public VertexAIEmbeddingClient( string location, string projectId, VertexAIVersion apiVersion, - ILogger? logger = null) + ILogger? logger = null, + int? dimensions = null) : base( httpClient: httpClient, logger: logger, @@ -50,21 +54,24 @@ public VertexAIEmbeddingClient( this._embeddingModelId = modelId; this._embeddingEndpoint = new Uri($"https://{location}-aiplatform.googleapis.com/{versionSubLink}/projects/{projectId}/locations/{location}/publishers/google/models/{this._embeddingModelId}:predict"); + this._dimensions = dimensions; } /// /// Generates embeddings for the given data asynchronously. /// /// The list of strings to generate embeddings for. + /// The embedding generation options. /// The cancellation token to cancel the operation. /// Result contains a list of read-only memories of floats representing the generated embeddings. public async Task>> GenerateEmbeddingsAsync( IList data, + EmbeddingGenerationOptions? options = null, CancellationToken cancellationToken = default) { Verify.NotNullOrEmpty(data); - var geminiRequest = GetEmbeddingRequest(data); + var geminiRequest = this.GetEmbeddingRequest(data, options); using var httpRequestMessage = await this.CreateHttpRequestAsync(geminiRequest, this._embeddingEndpoint).ConfigureAwait(false); string body = await this.SendRequestAndGetStringBodyAsync(httpRequestMessage, cancellationToken) @@ -73,8 +80,8 @@ public async Task>> GenerateEmbeddingsAsync( return DeserializeAndProcessEmbeddingsResponse(body); } - private static VertexAIEmbeddingRequest GetEmbeddingRequest(IEnumerable data) - => VertexAIEmbeddingRequest.FromData(data); + private VertexAIEmbeddingRequest GetEmbeddingRequest(IEnumerable data, EmbeddingGenerationOptions? options = null) + => VertexAIEmbeddingRequest.FromData(data, options?.Dimensions ?? this._dimensions); private static List> DeserializeAndProcessEmbeddingsResponse(string body) => ProcessEmbeddingsResponse(DeserializeResponse(body)); diff --git a/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingRequest.cs b/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingRequest.cs index b93f95cc9d2c..b9a42c9b0bd5 100644 --- a/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingRequest.cs +++ b/dotnet/src/Connectors/Connectors.Google/Core/VertexAI/VertexAIEmbeddingRequest.cs @@ -15,7 +15,7 @@ internal sealed class VertexAIEmbeddingRequest [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] public RequestParameters? Parameters { get; set; } - public static VertexAIEmbeddingRequest FromData(IEnumerable data) => new() + public static VertexAIEmbeddingRequest FromData(IEnumerable data, int? dimensions = null) => new() { Requests = data.Select(text => new RequestContent { @@ -23,8 +23,8 @@ internal sealed class VertexAIEmbeddingRequest }).ToList(), Parameters = new RequestParameters { - // todo make configurable when ITextEmbeddingGenerationService will support parameters - AutoTruncate = false + AutoTruncate = false, + OutputDimensionality = dimensions } }; @@ -46,5 +46,9 @@ internal sealed class RequestParameters { [JsonPropertyName("autoTruncate")] public bool AutoTruncate { get; set; } + + [JsonPropertyName("outputDimensionality")] + [JsonIgnore(Condition = JsonIgnoreCondition.WhenWritingNull)] + public int? OutputDimensionality { get; set; } } } diff --git a/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIKernelBuilderExtensions.cs index 109f145569fb..e727d339a44d 100644 --- a/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIKernelBuilderExtensions.cs @@ -114,6 +114,7 @@ public static IKernelBuilder AddVertexAIGeminiChatCompletion( /// The version of the Vertex API. /// The optional service ID. /// The optional custom HttpClient. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated kernel builder. /// /// This will be called on every request, @@ -129,7 +130,8 @@ public static IKernelBuilder AddVertexAIEmbeddingGeneration( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, string? serviceId = null, - HttpClient? httpClient = null) + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(builder); Verify.NotNull(modelId); @@ -145,7 +147,8 @@ public static IKernelBuilder AddVertexAIEmbeddingGeneration( projectId: projectId, apiVersion: apiVersion, httpClient: HttpClientProvider.GetHttpClient(httpClient, serviceProvider), - loggerFactory: serviceProvider.GetService())); + loggerFactory: serviceProvider.GetService(), + dimensions: dimensions)); return builder; } @@ -160,6 +163,7 @@ public static IKernelBuilder AddVertexAIEmbeddingGeneration( /// The version of the Vertex API. /// The optional service ID. /// The optional custom HttpClient. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated kernel builder. [Obsolete("Use AddVertexAIEmbeddingGenerator instead.")] public static IKernelBuilder AddVertexAIEmbeddingGeneration( @@ -170,7 +174,8 @@ public static IKernelBuilder AddVertexAIEmbeddingGeneration( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, string? serviceId = null, - HttpClient? httpClient = null) + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(builder); Verify.NotNull(modelId); @@ -186,7 +191,8 @@ public static IKernelBuilder AddVertexAIEmbeddingGeneration( projectId: projectId, apiVersion: apiVersion, httpClient: HttpClientProvider.GetHttpClient(httpClient, serviceProvider), - loggerFactory: serviceProvider.GetService())); + loggerFactory: serviceProvider.GetService(), + dimensions: dimensions)); return builder; } @@ -201,6 +207,7 @@ public static IKernelBuilder AddVertexAIEmbeddingGeneration( /// The version of the Vertex API. /// The optional service ID. /// The optional custom HttpClient. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated kernel builder. /// /// This will be called on every request, @@ -215,7 +222,8 @@ public static IKernelBuilder AddVertexAIEmbeddingGenerator( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, string? serviceId = null, - HttpClient? httpClient = null) + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(builder); Verify.NotNull(modelId); @@ -223,7 +231,7 @@ public static IKernelBuilder AddVertexAIEmbeddingGenerator( Verify.NotNull(location); Verify.NotNull(projectId); - builder.Services.AddVertexAIEmbeddingGenerator(modelId, bearerTokenProvider, location, projectId, apiVersion, serviceId, httpClient); + builder.Services.AddVertexAIEmbeddingGenerator(modelId, bearerTokenProvider, location, projectId, apiVersion, serviceId, httpClient, dimensions); return builder; } @@ -239,6 +247,7 @@ public static IKernelBuilder AddVertexAIEmbeddingGenerator( /// The version of the Vertex API. /// The optional service ID. /// The optional custom HttpClient. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated kernel builder. public static IKernelBuilder AddVertexAIEmbeddingGenerator( this IKernelBuilder builder, @@ -248,7 +257,8 @@ public static IKernelBuilder AddVertexAIEmbeddingGenerator( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, string? serviceId = null, - HttpClient? httpClient = null) + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(builder); Verify.NotNull(modelId); @@ -256,7 +266,7 @@ public static IKernelBuilder AddVertexAIEmbeddingGenerator( Verify.NotNull(location); Verify.NotNull(projectId); - builder.Services.AddVertexAIEmbeddingGenerator(modelId, bearerKey, location, projectId, apiVersion, serviceId, httpClient); + builder.Services.AddVertexAIEmbeddingGenerator(modelId, bearerKey, location, projectId, apiVersion, serviceId, httpClient, dimensions); return builder; } diff --git a/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.DependencyInjection.cs b/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.DependencyInjection.cs index fff117e0a76c..d94896056cfa 100644 --- a/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.DependencyInjection.cs +++ b/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.DependencyInjection.cs @@ -27,6 +27,7 @@ public static class VertexAIServiceCollectionExtensions /// The version of the Vertex API. /// Optional service ID. /// The optional custom HttpClient. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated service collection. /// /// This will be called on every request, @@ -41,7 +42,8 @@ public static IServiceCollection AddVertexAIEmbeddingGenerator( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, string? serviceId = null, - HttpClient? httpClient = null) + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(services); Verify.NotNull(modelId); @@ -57,7 +59,8 @@ public static IServiceCollection AddVertexAIEmbeddingGenerator( projectId: projectId, apiVersion: apiVersion, httpClient: HttpClientProvider.GetHttpClient(httpClient, serviceProvider), - loggerFactory: serviceProvider.GetService())); + loggerFactory: serviceProvider.GetService(), + dimensions: dimensions)); } /// @@ -71,6 +74,7 @@ public static IServiceCollection AddVertexAIEmbeddingGenerator( /// The version of the Vertex API. /// Optional service ID. /// The optional custom HttpClient. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated service collection. public static IServiceCollection AddVertexAIEmbeddingGenerator( this IServiceCollection services, @@ -80,7 +84,8 @@ public static IServiceCollection AddVertexAIEmbeddingGenerator( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, string? serviceId = null, - HttpClient? httpClient = null) + HttpClient? httpClient = null, + int? dimensions = null) { Verify.NotNull(services); Verify.NotNull(modelId); @@ -96,6 +101,7 @@ public static IServiceCollection AddVertexAIEmbeddingGenerator( projectId: projectId, apiVersion: apiVersion, httpClient: HttpClientProvider.GetHttpClient(httpClient, serviceProvider), - loggerFactory: serviceProvider.GetService())); + loggerFactory: serviceProvider.GetService(), + dimensions: dimensions)); } } diff --git a/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.cs index 34457730aca5..b9a435119de3 100644 --- a/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Google/Extensions/VertexAIServiceCollectionExtensions.cs @@ -107,6 +107,7 @@ public static IServiceCollection AddVertexAIGeminiChatCompletion( /// Your project ID /// The version of the Vertex API. /// Optional service ID. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated service collection. /// /// This will be called on every request, @@ -121,7 +122,8 @@ public static IServiceCollection AddVertexAIEmbeddingGeneration( string location, string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, - string? serviceId = null) + string? serviceId = null, + int? dimensions = null) { Verify.NotNull(services); Verify.NotNull(modelId); @@ -137,7 +139,8 @@ public static IServiceCollection AddVertexAIEmbeddingGeneration( projectId: projectId, apiVersion: apiVersion, httpClient: HttpClientProvider.GetHttpClient(serviceProvider), - loggerFactory: serviceProvider.GetService())); + loggerFactory: serviceProvider.GetService(), + dimensions: dimensions)); } /// @@ -150,6 +153,7 @@ public static IServiceCollection AddVertexAIEmbeddingGeneration( /// Your project ID /// The version of the Vertex API. /// Optional service ID. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// The updated service collection. [Obsolete("Use AddVertexAIEmbeddingGenerator instead.")] public static IServiceCollection AddVertexAIEmbeddingGeneration( @@ -159,7 +163,8 @@ public static IServiceCollection AddVertexAIEmbeddingGeneration( string location, string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, - string? serviceId = null) + string? serviceId = null, + int? dimensions = null) { Verify.NotNull(services); Verify.NotNull(modelId); @@ -175,6 +180,7 @@ public static IServiceCollection AddVertexAIEmbeddingGeneration( projectId: projectId, apiVersion: apiVersion, httpClient: HttpClientProvider.GetHttpClient(serviceProvider), - loggerFactory: serviceProvider.GetService())); + loggerFactory: serviceProvider.GetService(), + dimensions: dimensions)); } } diff --git a/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs b/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs index 46b1e4edae7f..86b04311e36d 100644 --- a/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs +++ b/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs @@ -28,6 +28,7 @@ public sealed class VertexAIEmbeddingGenerator : IEmbeddingGeneratorVersion of the Vertex API /// The optional HTTP client. /// Optional logger factory to be used for logging. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. public VertexAIEmbeddingGenerator( string modelId, string bearerKey, @@ -35,8 +36,9 @@ public VertexAIEmbeddingGenerator( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, HttpClient? httpClient = null, - ILoggerFactory? loggerFactory = null) - : this(modelId, () => new ValueTask(bearerKey), location, projectId, apiVersion, httpClient, loggerFactory) + ILoggerFactory? loggerFactory = null, + int? dimensions = null) + : this(modelId, () => new ValueTask(bearerKey), location, projectId, apiVersion, httpClient, loggerFactory, dimensions) { #pragma warning disable CS0618 // Type or member is obsolete this._generator = new VertexAITextEmbeddingGenerationService( @@ -46,7 +48,8 @@ public VertexAIEmbeddingGenerator( projectId: projectId, apiVersion: apiVersion, httpClient: httpClient, - loggerFactory: loggerFactory) + loggerFactory: loggerFactory, + dimensions: dimensions) .AsEmbeddingGenerator(); #pragma warning restore CS0618 // Type or member is obsolete } @@ -61,6 +64,7 @@ public VertexAIEmbeddingGenerator( /// Version of the Vertex API /// The optional HTTP client. /// Optional logger factory to be used for logging. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// /// This will be called on every request, /// when providing the token consider using caching strategy and refresh token logic @@ -73,7 +77,8 @@ public VertexAIEmbeddingGenerator( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, HttpClient? httpClient = null, - ILoggerFactory? loggerFactory = null) + ILoggerFactory? loggerFactory = null, + int? dimensions = null) { #pragma warning disable CS0618 // Type or member is obsolete this._generator = new VertexAITextEmbeddingGenerationService( @@ -83,7 +88,8 @@ public VertexAIEmbeddingGenerator( projectId: projectId, apiVersion: apiVersion, httpClient: httpClient, - loggerFactory: loggerFactory) + loggerFactory: loggerFactory, + dimensions: dimensions) .AsEmbeddingGenerator(); #pragma warning restore CS0618 // Type or member is obsolete } diff --git a/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs b/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs index 0f14fd2a22bf..3fab8a4cfb4e 100644 --- a/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs +++ b/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs @@ -5,6 +5,7 @@ using System.Net.Http; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.AI; using Microsoft.Extensions.Logging; using Microsoft.SemanticKernel.Connectors.Google.Core; using Microsoft.SemanticKernel.Embeddings; @@ -32,6 +33,7 @@ public sealed class VertexAITextEmbeddingGenerationService : ITextEmbeddingGener /// Version of the Vertex API /// The optional HTTP client. /// Optional logger factory to be used for logging. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. public VertexAITextEmbeddingGenerationService( string modelId, string bearerKey, @@ -39,8 +41,9 @@ public VertexAITextEmbeddingGenerationService( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, HttpClient? httpClient = null, - ILoggerFactory? loggerFactory = null) - : this(modelId, () => new ValueTask(bearerKey), location, projectId, apiVersion, httpClient, loggerFactory) + ILoggerFactory? loggerFactory = null, + int? dimensions = null) + : this(modelId, () => new ValueTask(bearerKey), location, projectId, apiVersion, httpClient, loggerFactory, dimensions) { Verify.NotNullOrWhiteSpace(bearerKey); } @@ -55,6 +58,7 @@ public VertexAITextEmbeddingGenerationService( /// Version of the Vertex API /// The optional HTTP client. /// Optional logger factory to be used for logging. + /// The number of dimensions that the model should use. If not specified, the default number of dimensions will be used. /// /// This will be called on every request, /// when providing the token consider using caching strategy and refresh token logic @@ -67,7 +71,8 @@ public VertexAITextEmbeddingGenerationService( string projectId, VertexAIVersion apiVersion = VertexAIVersion.V1, HttpClient? httpClient = null, - ILoggerFactory? loggerFactory = null) + ILoggerFactory? loggerFactory = null, + int? dimensions = null) { Verify.NotNullOrWhiteSpace(modelId); Verify.NotNull(bearerTokenProvider); @@ -83,8 +88,14 @@ public VertexAITextEmbeddingGenerationService( location: location, projectId: projectId, apiVersion: apiVersion, - logger: loggerFactory?.CreateLogger(typeof(VertexAITextEmbeddingGenerationService))); + logger: loggerFactory?.CreateLogger(typeof(VertexAITextEmbeddingGenerationService)), + dimensions: dimensions); this._attributesInternal.Add(AIServiceExtensions.ModelIdKey, modelId); + + if (dimensions.HasValue) + { + this._attributesInternal.Add(EmbeddingGenerationExtensions.DimensionsKey, dimensions); + } } /// @@ -96,6 +107,26 @@ public Task>> GenerateEmbeddingsAsync( Kernel? kernel = null, CancellationToken cancellationToken = default) { - return this._embeddingClient.GenerateEmbeddingsAsync(data, cancellationToken); + return this._embeddingClient.GenerateEmbeddingsAsync(data, null, cancellationToken); + } + + /// + /// Generates an embedding from the given . + /// + /// List of strings to generate embeddings for + /// Additional options for embedding generation + /// The containing services, plugins, and other state for use throughout the operation. + /// The to monitor for cancellation requests. The default is . + /// List of embeddings + /// + /// The parameter can be used to override default settings such as and + /// + public Task>> GenerateEmbeddingsAsync( + IList data, + EmbeddingGenerationOptions? options, + Kernel? kernel = null, + CancellationToken cancellationToken = default) + { + return this._embeddingClient.GenerateEmbeddingsAsync(data, options, cancellationToken); } } From bafdb29d1ffc9da6cc78ff4e60e52289ee4c2385 Mon Sep 17 00:00:00 2001 From: James Abbott Date: Fri, 20 Mar 2026 11:06:37 +0000 Subject: [PATCH 2/7] fix: Improve JSON assertions for Vertex AI tests. Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- ...texAITextEmbeddingGenerationServiceTests.cs | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs index 3a076c32e001..b497ae555338 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs @@ -5,6 +5,7 @@ using System.Net.Http; using System.Text; using System.Threading.Tasks; +using System.Text.Json; using Microsoft.SemanticKernel.Connectors.Google; using Microsoft.SemanticKernel.Embeddings; using Microsoft.SemanticKernel.Services; @@ -133,7 +134,14 @@ public async Task ShouldNotIncludeDimensionsInRequestWhenNotProvidedAsync() // Assert Assert.NotNull(this._messageHandlerStub.RequestContent); var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); - Assert.DoesNotContain("outputDimensionality", requestBody); + using (var document = JsonDocument.Parse(requestBody)) + { + var root = document.RootElement; + if (root.TryGetProperty("parameters", out var parametersElement)) + { + Assert.False(parametersElement.TryGetProperty("outputDimensionality", out _)); + } + } } [Theory] @@ -157,7 +165,13 @@ public async Task ShouldIncludeDimensionsInRequestWhenProvidedAsync(int? dimensi // Assert Assert.NotNull(this._messageHandlerStub.RequestContent); var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); - Assert.Contains($"\"outputDimensionality\":{dimensions}", requestBody); + using (var document = JsonDocument.Parse(requestBody)) + { + var root = document.RootElement; + Assert.True(root.TryGetProperty("parameters", out var parametersElement)); + Assert.True(parametersElement.TryGetProperty("outputDimensionality", out var outputDimensionalityElement)); + Assert.Equal(dimensions!.Value, outputDimensionalityElement.GetInt32()); + } } public void Dispose() From 0fa0efd0eada74d7694ac2fb0d4a33de3289b753 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:08:54 +0000 Subject: [PATCH 3/7] Initial plan From 637ff9f687424aab9fbf573474e6ccd22db31d8b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:20:57 +0000 Subject: [PATCH 4/7] Add missing namespace and precedence tests for Vertex AI dimensions Co-authored-by: abbottdev <3226335+abbottdev@users.noreply.github.com> --- .../VertexAIEmbeddingGeneratorTests.cs | 24 +++++++++++ ...exAITextEmbeddingGenerationServiceTests.cs | 29 +++++++++++++ .../Services/VertexAIEmbeddingGenerator.cs | 42 +++++++++++++------ 3 files changed, 82 insertions(+), 13 deletions(-) diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs index e293de580a7a..efdbf680e948 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAIEmbeddingGeneratorTests.cs @@ -158,6 +158,30 @@ public async Task ShouldIncludeDimensionsInRequestWhenProvidedAsync(int? dimensi Assert.Contains($"\"outputDimensionality\":{dimensions}", requestBody); } + [Fact] + public async Task OptionsDimensionsShouldOverrideConstructorDefaultAsync() + { + // Arrange + const int OptionsDimensions = Dimensions * 2; + using var service = new VertexAIEmbeddingGenerator( + modelId: Model, + bearerKey: BearerKey, + location: "location", + projectId: "project", + dimensions: Dimensions, + httpClient: this._httpClient); + var dataToEmbed = new List { "Text to embed" }; + var options = new EmbeddingGenerationOptions { Dimensions = OptionsDimensions }; + + // Act + await service.GenerateAsync(dataToEmbed, options); + + // Assert + Assert.NotNull(this._messageHandlerStub.RequestContent); + var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); + Assert.Contains($"\"outputDimensionality\":{OptionsDimensions}", requestBody); + } + public void Dispose() { this._messageHandlerStub.Dispose(); diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs index b497ae555338..8416882fa2e8 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs @@ -6,6 +6,7 @@ using System.Text; using System.Threading.Tasks; using System.Text.Json; +using Microsoft.Extensions.AI; using Microsoft.SemanticKernel.Connectors.Google; using Microsoft.SemanticKernel.Embeddings; using Microsoft.SemanticKernel.Services; @@ -174,6 +175,34 @@ public async Task ShouldIncludeDimensionsInRequestWhenProvidedAsync(int? dimensi } } + [Fact] + public async Task OptionsDimensionsShouldOverrideConstructorDefaultAsync() + { + // Arrange + const int OptionsDimensions = Dimensions * 2; + var service = new VertexAITextEmbeddingGenerationService( + modelId: Model, + bearerKey: BearerKey, + location: "location", + projectId: "project", + dimensions: Dimensions, + httpClient: this._httpClient); + var dataToEmbed = new List { "Text to embed" }; + var options = new EmbeddingGenerationOptions { Dimensions = OptionsDimensions }; + + // Act + await service.GenerateEmbeddingsAsync(dataToEmbed, options); + + // Assert + Assert.NotNull(this._messageHandlerStub.RequestContent); + var requestBody = Encoding.UTF8.GetString(this._messageHandlerStub.RequestContent); + using var document = JsonDocument.Parse(requestBody); + var root = document.RootElement; + Assert.True(root.TryGetProperty("parameters", out var parametersElement)); + Assert.True(parametersElement.TryGetProperty("outputDimensionality", out var outputDimensionalityElement)); + Assert.Equal(OptionsDimensions, outputDimensionalityElement.GetInt32()); + } + public void Dispose() { this._messageHandlerStub.Dispose(); diff --git a/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs b/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs index 86b04311e36d..d08afae2e8e3 100644 --- a/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs +++ b/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs @@ -2,12 +2,12 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.AI; using Microsoft.Extensions.Logging; -using Microsoft.SemanticKernel.Embeddings; namespace Microsoft.SemanticKernel.Connectors.Google; @@ -16,7 +16,11 @@ namespace Microsoft.SemanticKernel.Connectors.Google; /// public sealed class VertexAIEmbeddingGenerator : IEmbeddingGenerator> { - private readonly IEmbeddingGenerator> _generator; + private readonly EmbeddingGeneratorMetadata _metadata; + +#pragma warning disable CS0618 // Type or member is obsolete + private readonly VertexAITextEmbeddingGenerationService _service; +#pragma warning restore CS0618 // Type or member is obsolete /// /// Initializes a new instance of the class. @@ -38,10 +42,9 @@ public VertexAIEmbeddingGenerator( HttpClient? httpClient = null, ILoggerFactory? loggerFactory = null, int? dimensions = null) - : this(modelId, () => new ValueTask(bearerKey), location, projectId, apiVersion, httpClient, loggerFactory, dimensions) { #pragma warning disable CS0618 // Type or member is obsolete - this._generator = new VertexAITextEmbeddingGenerationService( + this._service = new VertexAITextEmbeddingGenerationService( modelId: modelId, bearerKey: bearerKey, location: location, @@ -49,9 +52,9 @@ public VertexAIEmbeddingGenerator( apiVersion: apiVersion, httpClient: httpClient, loggerFactory: loggerFactory, - dimensions: dimensions) - .AsEmbeddingGenerator(); + dimensions: dimensions); #pragma warning restore CS0618 // Type or member is obsolete + this._metadata = new EmbeddingGeneratorMetadata(nameof(VertexAIEmbeddingGenerator), providerUri: null, modelId, dimensions); } /// @@ -81,7 +84,7 @@ public VertexAIEmbeddingGenerator( int? dimensions = null) { #pragma warning disable CS0618 // Type or member is obsolete - this._generator = new VertexAITextEmbeddingGenerationService( + this._service = new VertexAITextEmbeddingGenerationService( modelId: modelId, bearerTokenProvider: bearerTokenProvider, location: location, @@ -89,20 +92,33 @@ public VertexAIEmbeddingGenerator( apiVersion: apiVersion, httpClient: httpClient, loggerFactory: loggerFactory, - dimensions: dimensions) - .AsEmbeddingGenerator(); + dimensions: dimensions); #pragma warning restore CS0618 // Type or member is obsolete + this._metadata = new EmbeddingGeneratorMetadata(nameof(VertexAIEmbeddingGenerator), providerUri: null, modelId, dimensions); } /// public void Dispose() - => this._generator.Dispose(); + { + } /// - public Task>> GenerateAsync(IEnumerable values, EmbeddingGenerationOptions? options = null, CancellationToken cancellationToken = default) - => this._generator.GenerateAsync(values, options, cancellationToken); + public async Task>> GenerateAsync(IEnumerable values, EmbeddingGenerationOptions? options = null, CancellationToken cancellationToken = default) + { + var result = await this._service.GenerateEmbeddingsAsync(values.ToList(), options, cancellationToken: cancellationToken).ConfigureAwait(false); + return new(result.Select(e => new Embedding(e))); + } /// public object? GetService(Type serviceType, object? serviceKey = null) - => this._generator.GetService(serviceType, serviceKey); + { + Verify.NotNull(serviceType); + + return + serviceKey is not null ? null : + serviceType.IsInstanceOfType(this) ? this : + serviceType.IsInstanceOfType(this._service) ? this._service : + serviceType.IsInstanceOfType(this._metadata) ? this._metadata : + null; + } } From 0969e6c99930529a3743e7dcc02f73b6b6dc23d4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:36:58 +0000 Subject: [PATCH 5/7] Initial plan From a6132bc20eb27222c88bc8b35d9f26ed0a66239c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 20 Mar 2026 11:41:10 +0000 Subject: [PATCH 6/7] Apply review comments: delegate Dispose to underlying service, fix XML doc remark Co-authored-by: abbottdev <3226335+abbottdev@users.noreply.github.com> --- .../Connectors.Google/Services/VertexAIEmbeddingGenerator.cs | 1 + .../Services/VertexAITextEmbeddingGenerationService.cs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs b/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs index d08afae2e8e3..2eedbff208d2 100644 --- a/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs +++ b/dotnet/src/Connectors/Connectors.Google/Services/VertexAIEmbeddingGenerator.cs @@ -100,6 +100,7 @@ public VertexAIEmbeddingGenerator( /// public void Dispose() { + ((object)this._service as IDisposable)?.Dispose(); } /// diff --git a/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs b/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs index 3fab8a4cfb4e..e35c9200acd9 100644 --- a/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs +++ b/dotnet/src/Connectors/Connectors.Google/Services/VertexAITextEmbeddingGenerationService.cs @@ -119,7 +119,7 @@ public Task>> GenerateEmbeddingsAsync( /// The to monitor for cancellation requests. The default is . /// List of embeddings /// - /// The parameter can be used to override default settings such as and + /// The parameter can be used to override default settings such as . /// public Task>> GenerateEmbeddingsAsync( IList data, From 5b9c39e91901e231893fa9fc59fd036a159ed6f4 Mon Sep 17 00:00:00 2001 From: James Abbott Date: Fri, 20 Mar 2026 14:01:25 +0000 Subject: [PATCH 7/7] format: fix namespace ordering format --- .../Services/VertexAITextEmbeddingGenerationServiceTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs index 8416882fa2e8..002b5bd4fcab 100644 --- a/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs +++ b/dotnet/src/Connectors/Connectors.Google.UnitTests/Services/VertexAITextEmbeddingGenerationServiceTests.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using System.Net.Http; using System.Text; -using System.Threading.Tasks; using System.Text.Json; +using System.Threading.Tasks; using Microsoft.Extensions.AI; using Microsoft.SemanticKernel.Connectors.Google; using Microsoft.SemanticKernel.Embeddings;