Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using Amazon.BedrockRuntime;
using Amazon.Runtime;
using Microsoft.SemanticKernel.ChatCompletion;
Expand All @@ -18,13 +19,15 @@ public class BedrockKernelBuilderExtensionTests
/// <summary>
/// Checks that AddBedrockTextGenerationService builds a proper kernel with a null bedrockRuntime.
/// </summary>
[Fact]
public void AddBedrockTextGenerationCreatesServiceWithNonNullBedrockRuntime()
[Theory]
[InlineData("amazon.titan-text-premier-v1:0")]
[InlineData("us.amazon.titan-text-premier-v1:0")]
public void AddBedrockTextGenerationCreatesServiceWithNonNullBedrockRuntime(string modelId)
{
// Arrange
var bedrockRuntime = new Mock<IAmazonBedrockRuntime>().Object;
var builder = Kernel.CreateBuilder();
builder.AddBedrockTextGenerationService("amazon.titan-text-premier-v1:0", bedrockRuntime);
builder.AddBedrockTextGenerationService(modelId, bedrockRuntime);

// Act
var kernel = builder.Build();
Expand All @@ -37,13 +40,15 @@ public void AddBedrockTextGenerationCreatesServiceWithNonNullBedrockRuntime()
/// <summary>
/// Checks that AddBedrockChatCompletionService builds a proper kernel with a non-null bedrockRuntime.
/// </summary>
[Fact]
public void AddBedrockChatCompletionCreatesServiceWithNonNullBedrockRuntime()
[Theory]
[InlineData("amazon.titan-text-premier-v1:0")]
[InlineData("us.amazon.titan-text-premier-v1:0")]
public void AddBedrockChatCompletionCreatesServiceWithNonNullBedrockRuntime(string modelId)
{
// Arrange
var bedrockRuntime = new Mock<IAmazonBedrockRuntime>().Object;
var builder = Kernel.CreateBuilder();
builder.AddBedrockChatCompletionService("amazon.titan-text-premier-v1:0", bedrockRuntime);
builder.AddBedrockChatCompletionService(modelId, bedrockRuntime);

// Act
var kernel = builder.Build();
Expand All @@ -65,4 +70,22 @@ public void AwsServiceClientBeforeServiceRequestDoesNothingForNonWebServiceReque
// Assert
// No exceptions should be thrown
}

[Theory]
[InlineData("unknown.titan-text-premier-v1:0")]
[InlineData("us.unknown.titan-text-premier-v1:0")]
public void AwsUnknownBedrockTextCompletionModelShouldThrowException(string modelId)
{
// Arrange
var bedrockRuntime = new Mock<IAmazonBedrockRuntime>().Object;
var builder = Kernel.CreateBuilder();
builder.AddBedrockTextGenerationService(modelId, bedrockRuntime);

// Act & Assert
Assert.Throws<KernelException>(() =>
{
var kernel = builder.Build();
kernel.GetRequiredService<ITextGenerationService>();
});
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// Copyright (c) Microsoft. All rights reserved.

using System;
using System.Linq;

namespace Microsoft.SemanticKernel.Connectors.Amazon.Core;

Expand All @@ -9,6 +10,30 @@ namespace Microsoft.SemanticKernel.Connectors.Amazon.Core;
/// </summary>
internal sealed class BedrockServiceFactory
{
/// <summary>
/// Represents an array of region prefixes used to identify different cross-region configurations
/// for service operations. The prefixes correspond to general geographic areas such as
/// "us" (United States), "eu" (Europe), and "apac" (Asia-Pacific).
/// (sourced from https://docs.aws.amazon.com/bedrock/latest/userguide/inference-profiles-support.html)
/// </summary>
private static readonly string[] s_crossRegionPrefixes = ["us.", "eu.", "apac."];

/// <summary>
/// Removes the cross-region prefix from the provided model identifier if it exists.
/// </summary>
/// <param name="modelId">The model identifier, which may contain a cross-region prefix.</param>
/// <returns>The model identifier without the cross-region prefix.</returns>
private static string ScrubCrossRegionPrefix(string modelId)
{
var prefix = s_crossRegionPrefixes.FirstOrDefault(prefix => modelId.StartsWith(prefix, StringComparison.InvariantCultureIgnoreCase));
if (!string.IsNullOrWhiteSpace(prefix))
{
modelId = modelId.Substring(prefix.Length);
}

return modelId;
}

/// <summary>
/// Gets the model service for body conversion.
/// </summary>
Expand All @@ -17,7 +42,7 @@ internal sealed class BedrockServiceFactory
/// <exception cref="NotSupportedException">Thrown if provider or model is not supported for text generation.</exception>
internal IBedrockTextGenerationService CreateTextGenerationService(string modelId)
{
(string modelProvider, string modelName) = this.GetModelProviderAndName(modelId);
(string modelProvider, string modelName) = this.GetModelProviderAndName(ScrubCrossRegionPrefix(modelId));

switch (modelProvider.ToUpperInvariant())
{
Expand Down Expand Up @@ -79,7 +104,7 @@ internal IBedrockTextGenerationService CreateTextGenerationService(string modelI
/// <exception cref="NotSupportedException">Thrown if provider or model is not supported for chat completion.</exception>
internal IBedrockChatCompletionService CreateChatCompletionService(string modelId)
{
(string modelProvider, string modelName) = this.GetModelProviderAndName(modelId);
(string modelProvider, string modelName) = this.GetModelProviderAndName(ScrubCrossRegionPrefix(modelId));

switch (modelProvider.ToUpperInvariant())
{
Expand Down
Loading