diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java index 2437b35eebb..55a2d80af50 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/api/AnthropicChatBedrockApi.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.publisher.Flux; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatRequest; import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi.AnthropicChatResponse; @@ -32,6 +33,7 @@ /** * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ // @formatter:off @@ -92,6 +94,20 @@ public AnthropicChatBedrockApi(String modelId, AwsCredentialsProvider credential super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. + * + * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public AnthropicChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + // https://github.com/build-on-aws/amazon-bedrock-java-examples/blob/main/example_code/bedrock-runtime/src/main/java/aws/community/examples/InvokeBedrockStreamingAsync.java // https://docs.anthropic.com/claude/reference/complete_post diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java index 983894267ff..0148b498373 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic3/api/Anthropic3ChatBedrockApi.java @@ -26,6 +26,7 @@ import org.springframework.util.Assert; import reactor.core.publisher.Flux; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import java.time.Duration; import java.util.List; @@ -39,6 +40,7 @@ * * @author Ben Middleton * @author Christian Tzolov + * @author Wei Jiang * @since 1.0.0 */ // @formatter:off @@ -96,6 +98,20 @@ public Anthropic3ChatBedrockApi(String modelId, AwsCredentialsProvider credentia super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new AnthropicChatBedrockApi instance using the provided credentials provider, region and object mapper. + * + * @param modelId The model id to use. See the {@link AnthropicChatModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public Anthropic3ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + // https://github.com/build-on-aws/amazon-bedrock-java-examples/blob/main/example_code/bedrock-runtime/src/main/java/aws/community/examples/InvokeBedrockStreamingAsync.java // https://docs.anthropic.com/claude/reference/complete_post diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java index 74f4249f04f..17e0eed79b7 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/api/AbstractBedrockApi.java @@ -61,6 +61,7 @@ * @see Model Parameters * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ public abstract class AbstractBedrockApi { @@ -69,7 +70,7 @@ public abstract class AbstractBedrockApi { private final String modelId; private final ObjectMapper objectMapper; - private final String region; + private final Region region; private final BedrockRuntimeClient client; private final BedrockRuntimeAsyncClient clientStreaming; @@ -93,7 +94,7 @@ public AbstractBedrockApi(String modelId, String region, Duration timeout) { this(modelId, ProfileCredentialsProvider.builder().build(), region, ModelOptionsUtils.OBJECT_MAPPER, timeout); } - /** + /** * Create a new AbstractBedrockApi instance using the provided credentials provider, region and object mapper. * * @param modelId The model id to use. @@ -105,6 +106,7 @@ public AbstractBedrockApi(String modelId, AwsCredentialsProvider credentialsProv ObjectMapper objectMapper) { this(modelId, credentialsProvider, region, objectMapper, Duration.ofMinutes(5)); } + /** * Create a new AbstractBedrockApi instance using the provided credentials provider, region and object mapper. * @@ -118,10 +120,26 @@ public AbstractBedrockApi(String modelId, AwsCredentialsProvider credentialsProv */ public AbstractBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, String region, ObjectMapper objectMapper, Duration timeout) { + this(modelId, credentialsProvider, Region.of(region), objectMapper, timeout); + } + + /** + * Create a new AbstractBedrockApi instance using the provided credentials provider, region and object mapper. + * + * @param modelId The model id to use. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout Configure the amount of time to allow the client to complete the execution of an API call. + * This timeout covers the entire client execution except for marshalling. This includes request handler execution, + * all HTTP requests including retries, unmarshalling, etc. This value should always be positive, if present. + */ + public AbstractBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { Assert.hasText(modelId, "Model id must not be empty"); Assert.notNull(credentialsProvider, "Credentials provider must not be null"); - Assert.hasText(region, "Region must not be empty"); + Assert.notNull(region, "Region must not be empty"); Assert.notNull(objectMapper, "Object mapper must not be null"); Assert.notNull(timeout, "Timeout must not be null"); @@ -131,13 +149,13 @@ public AbstractBedrockApi(String modelId, AwsCredentialsProvider credentialsProv this.client = BedrockRuntimeClient.builder() - .region(Region.of(this.region)) + .region(this.region) .credentialsProvider(credentialsProvider) .overrideConfiguration(c -> c.apiCallTimeout(timeout)) .build(); this.clientStreaming = BedrockRuntimeAsyncClient.builder() - .region(Region.of(this.region)) + .region(this.region) .credentialsProvider(credentialsProvider) .overrideConfiguration(c -> c.apiCallTimeout(timeout)) .build(); @@ -153,7 +171,7 @@ public String getModelId() { /** * @return The AWS region. */ - public String getRegion() { + public Region getRegion() { return this.region; } diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java index b3b02b6993f..5b133a9976c 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereChatBedrockApi.java @@ -25,6 +25,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.publisher.Flux; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import org.springframework.ai.bedrock.api.AbstractBedrockApi; import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi.CohereChatRequest; @@ -36,6 +37,7 @@ * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-cohere.html * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ public class CohereChatBedrockApi extends @@ -91,6 +93,20 @@ public CohereChatBedrockApi(String modelId, AwsCredentialsProvider credentialsPr super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new CohereChatBedrockApi instance using the provided credentials provider, region and object mapper. + * + * @param modelId The model id to use. See the {@link CohereChatModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public CohereChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + /** * CohereChatRequest encapsulates the request parameters for the Cohere command model. * diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereEmbeddingBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereEmbeddingBedrockApi.java index 7d0fa442cde..13752cc4486 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereEmbeddingBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/cohere/api/CohereEmbeddingBedrockApi.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import org.springframework.ai.bedrock.api.AbstractBedrockApi; import org.springframework.ai.bedrock.cohere.api.CohereEmbeddingBedrockApi.CohereEmbeddingRequest; @@ -34,6 +35,7 @@ * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-cohere.html#model-parameters-embed * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ public class CohereEmbeddingBedrockApi extends @@ -91,6 +93,21 @@ public CohereEmbeddingBedrockApi(String modelId, AwsCredentialsProvider credenti super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new CohereEmbeddingBedrockApi instance using the provided credentials provider, region and object + * mapper. + * + * @param modelId The model id to use. See the {@link CohereEmbeddingModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public CohereEmbeddingBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + /** * The Cohere Embed model request. * diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java index fa505176350..0ec58c8bd2c 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/jurassic2/api/Ai21Jurassic2ChatBedrockApi.java @@ -29,12 +29,14 @@ import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatResponse; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; /** * Java client for the Bedrock Jurassic2 chat model. * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-jurassic2.html * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ public class Ai21Jurassic2ChatBedrockApi extends @@ -92,6 +94,20 @@ public Ai21Jurassic2ChatBedrockApi(String modelId, AwsCredentialsProvider creden super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new Ai21Jurassic2ChatBedrockApi instance. + * + * @param modelId The model id to use. See the {@link Ai21Jurassic2ChatBedrockApi.Ai21Jurassic2ChatModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public Ai21Jurassic2ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + /** * AI21 Jurassic2 chat request parameters. * diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama2/api/Llama2ChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama2/api/Llama2ChatBedrockApi.java index af10d69bdfb..390ad28fffe 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama2/api/Llama2ChatBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/llama2/api/Llama2ChatBedrockApi.java @@ -21,6 +21,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.publisher.Flux; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import org.springframework.ai.bedrock.api.AbstractBedrockApi; import org.springframework.ai.bedrock.llama2.api.Llama2ChatBedrockApi.Llama2ChatRequest; @@ -34,6 +35,7 @@ * https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-meta.html * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ public class Llama2ChatBedrockApi extends @@ -89,6 +91,20 @@ public Llama2ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsPr super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new Llama2ChatBedrockApi instance using the provided credentials provider, region and object mapper. + * + * @param modelId The model id to use. See the {@link Llama2ChatModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public Llama2ChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + /** * Llama2ChatRequest encapsulates the request parameters for the Meta Llama2 chat model. * diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java index 498b34bf3d8..f4a219a8d99 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanChatBedrockApi.java @@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import reactor.core.publisher.Flux; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import org.springframework.ai.bedrock.api.AbstractBedrockApi; import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi.TitanChatRequest; @@ -38,6 +39,7 @@ * https://docs.aws.amazon.com/bedrock/latest/userguide/titan-text-models.html * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ // @formatter:off @@ -92,6 +94,20 @@ public TitanChatBedrockApi(String modelId, AwsCredentialsProvider credentialsPro super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new TitanChatBedrockApi instance using the provided credentials provider, region and object mapper. + * + * @param modelId The model id to use. See the {@link TitanChatModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public TitanChatBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + /** * TitanChatRequest encapsulates the request parameters for the Titan chat model. * diff --git a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanEmbeddingBedrockApi.java b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanEmbeddingBedrockApi.java index 9c1dcb3b267..5901799c32f 100644 --- a/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanEmbeddingBedrockApi.java +++ b/models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/titan/api/TitanEmbeddingBedrockApi.java @@ -23,6 +23,7 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; import org.springframework.ai.bedrock.api.AbstractBedrockApi; import org.springframework.ai.bedrock.titan.api.TitanEmbeddingBedrockApi.TitanEmbeddingRequest; @@ -34,6 +35,7 @@ * https://docs.aws.amazon.com/bedrock/latest/userguide/titan-multiemb-models.html * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ // @formatter:off @@ -65,6 +67,20 @@ public TitanEmbeddingBedrockApi(String modelId, AwsCredentialsProvider credentia super(modelId, credentialsProvider, region, objectMapper, timeout); } + /** + * Create a new TitanEmbeddingBedrockApi instance. + * + * @param modelId The model id to use. See the {@link TitanEmbeddingModel} for the supported models. + * @param credentialsProvider The credentials provider to connect to AWS. + * @param region The AWS region to use. + * @param objectMapper The object mapper to use for JSON serialization and deserialization. + * @param timeout The timeout to use. + */ + public TitanEmbeddingBedrockApi(String modelId, AwsCredentialsProvider credentialsProvider, Region region, + ObjectMapper objectMapper, Duration timeout) { + super(modelId, credentialsProvider, region, objectMapper, timeout); + } + /** * Titan Embedding request parameters. * diff --git a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc index 4da2b06f7d0..89e3190b091 100644 --- a/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc +++ b/spring-ai-docs/src/main/antora/modules/ROOT/pages/api/bedrock.adoc @@ -63,6 +63,18 @@ AWS credentials are resolved in the following order: 6. Credentials delivered through the Amazon EC2 container service if the `AWS_CONTAINER_CREDENTIALS_RELATIVE_URI` environment variable is set and the security manager has permission to access the variable. 7. Instance profile credentials delivered through the Amazon EC2 metadata service or set the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables. +AWS region is resolved in the following order: + +1. Spring-AI Bedrock `spring.ai.bedrock.aws.region` property. +2. Java System Properties - `aws.region`. +3. Environment Variables - `AWS_REGION`. +4. Credential profiles file at the default location (`~/.aws/credentials`) shared by all AWS SDKs and the AWS CLI. +5. Instance profile region delivered through the Amazon EC2 metadata service. + +In addition to the standard Spring-AI Bedrock credentials and region properties configuration, Spring-AI provides support for custom `AwsCredentialsProvider` and `AwsRegionProvider` beans. + +NOTE: For example, using Spring-AI and https://spring.io/projects/spring-cloud-aws[Spring Cloud for Amazon Web Services] at the same time. Spring-AI is compatible with Spring Cloud for Amazon Web Services credential configuration. + === Enable selected Bedrock model NOTE: By default, all models are disabled. You have to enable the chosen Bedrock models explicitly using the `spring.ai.bedrock...enabled=true` property. diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfiguration.java index 9cfd634d13b..46ee804056d 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfiguration.java @@ -19,6 +19,9 @@ import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider; import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; +import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; @@ -28,6 +31,7 @@ /** * @author Christian Tzolov + * @author Wei Jiang */ @Configuration @EnableConfigurationProperties({ BedrockAwsConnectionProperties.class }) @@ -45,4 +49,38 @@ public AwsCredentialsProvider credentialsProvider(BedrockAwsConnectionProperties return DefaultCredentialsProvider.create(); } + @Bean + @ConditionalOnMissingBean + public AwsRegionProvider regionProvider(BedrockAwsConnectionProperties properties) { + + if (StringUtils.hasText(properties.getRegion())) { + return new StaticRegionProvider(properties.getRegion()); + } + + return DefaultAwsRegionProviderChain.builder().build(); + } + + /** + * @author Wei Jiang + */ + static class StaticRegionProvider implements AwsRegionProvider { + + private final Region region; + + public StaticRegionProvider(String region) { + try { + this.region = Region.of(region); + } + catch (IllegalArgumentException e) { + throw new IllegalArgumentException("The region '" + region + "' is not a valid region!", e); + } + } + + @Override + public Region getRegion() { + return this.region; + } + + } + } diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java index 9a74161b050..7b3d4d2d545 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic/BedrockAnthropicChatAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.ai.bedrock.anthropic.BedrockAnthropicChatClient; import org.springframework.ai.bedrock.anthropic.api.AnthropicChatBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -28,6 +29,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; /** * {@link AutoConfiguration Auto-configuration} for Bedrock Anthropic Chat Client. @@ -35,6 +37,7 @@ * Leverages the Spring Cloud AWS to resolve the {@link AwsCredentialsProvider}. * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ @AutoConfiguration @@ -46,16 +49,18 @@ public class BedrockAnthropicChatAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public AnthropicChatBedrockApi anthropicApi(AwsCredentialsProvider credentialsProvider, - BedrockAnthropicChatProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new AnthropicChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockAnthropicChatProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new AnthropicChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean + @ConditionalOnBean(AnthropicChatBedrockApi.class) public BedrockAnthropicChatClient anthropicChatClient(AnthropicChatBedrockApi anthropicApi, BedrockAnthropicChatProperties properties) { - return new BedrockAnthropicChatClient(anthropicApi, properties.getOptions()); } diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java index 7d04798d033..60e5cdce69c 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/anthropic3/BedrockAnthropic3ChatAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.ai.bedrock.anthropic3.BedrockAnthropic3ChatClient; import org.springframework.ai.bedrock.anthropic3.api.Anthropic3ChatBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -28,6 +29,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; /** * {@link AutoConfiguration Auto-configuration} for Bedrock Anthropic Chat Client. @@ -47,13 +49,16 @@ public class BedrockAnthropic3ChatAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public Anthropic3ChatBedrockApi anthropic3Api(AwsCredentialsProvider credentialsProvider, - BedrockAnthropic3ChatProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new Anthropic3ChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockAnthropic3ChatProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new Anthropic3ChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean + @ConditionalOnBean(Anthropic3ChatBedrockApi.class) public BedrockAnthropic3ChatClient anthropic3ChatClient(Anthropic3ChatBedrockApi anthropicApi, BedrockAnthropic3ChatProperties properties) { return new BedrockAnthropic3ChatClient(anthropicApi, properties.getOptions()); diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java index 3ee34f90fa1..66b6d5e5e77 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereChatAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.ai.bedrock.cohere.BedrockCohereChatClient; import org.springframework.ai.bedrock.cohere.api.CohereChatBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -28,11 +29,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; /** * {@link AutoConfiguration Auto-configuration} for Bedrock Cohere Chat Client. * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ @AutoConfiguration @@ -44,13 +47,16 @@ public class BedrockCohereChatAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public CohereChatBedrockApi cohereChatApi(AwsCredentialsProvider credentialsProvider, - BedrockCohereChatProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new CohereChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockCohereChatProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new CohereChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean + @ConditionalOnBean(CohereChatBedrockApi.class) public BedrockCohereChatClient cohereChatClient(CohereChatBedrockApi cohereChatApi, BedrockCohereChatProperties properties) { diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java index 95ecba88858..76e3ea6033d 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/cohere/BedrockCohereEmbeddingAutoConfiguration.java @@ -17,12 +17,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; import org.springframework.ai.bedrock.cohere.BedrockCohereEmbeddingClient; import org.springframework.ai.bedrock.cohere.api.CohereEmbeddingBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -34,6 +36,7 @@ * {@link AutoConfiguration Auto-configuration} for Bedrock Cohere Embedding Client. * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ @AutoConfiguration @@ -45,14 +48,17 @@ public class BedrockCohereEmbeddingAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public CohereEmbeddingBedrockApi cohereEmbeddingApi(AwsCredentialsProvider credentialsProvider, - BedrockCohereEmbeddingProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new CohereEmbeddingBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockCohereEmbeddingProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new CohereEmbeddingBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean @ConditionalOnMissingBean + @ConditionalOnBean(CohereEmbeddingBedrockApi.class) public BedrockCohereEmbeddingClient cohereEmbeddingClient(CohereEmbeddingBedrockApi cohereEmbeddingApi, BedrockCohereEmbeddingProperties properties) { diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java index f7c50657238..e8266a0e417 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/jurrasic2/BedrockAi21Jurassic2ChatAutoConfiguration.java @@ -22,6 +22,7 @@ import org.springframework.ai.bedrock.jurassic2.BedrockAi21Jurassic2ChatClient; import org.springframework.ai.bedrock.jurassic2.api.Ai21Jurassic2ChatBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -29,11 +30,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; /** * {@link AutoConfiguration Auto-configuration} for Bedrock Jurassic2 Chat Client. * * @author Ahmed Yousri + * @author Wei Jiang * @since 1.0.0 */ @AutoConfiguration @@ -46,13 +49,16 @@ public class BedrockAi21Jurassic2ChatAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public Ai21Jurassic2ChatBedrockApi ai21Jurassic2ChatBedrockApi(AwsCredentialsProvider credentialsProvider, - BedrockAi21Jurassic2ChatProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new Ai21Jurassic2ChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockAi21Jurassic2ChatProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new Ai21Jurassic2ChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean + @ConditionalOnBean(Ai21Jurassic2ChatBedrockApi.class) public BedrockAi21Jurassic2ChatClient jurassic2ChatClient(Ai21Jurassic2ChatBedrockApi ai21Jurassic2ChatBedrockApi, BedrockAi21Jurassic2ChatProperties properties) { diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama2/BedrockLlama2ChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama2/BedrockLlama2ChatAutoConfiguration.java index 314e3671be2..ef3d53e4faa 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama2/BedrockLlama2ChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/llama2/BedrockLlama2ChatAutoConfiguration.java @@ -17,12 +17,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; import org.springframework.ai.bedrock.llama2.BedrockLlama2ChatClient; import org.springframework.ai.bedrock.llama2.api.Llama2ChatBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -36,6 +38,7 @@ * Leverages the Spring Cloud AWS to resolve the {@link AwsCredentialsProvider}. * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ @AutoConfiguration @@ -47,13 +50,15 @@ public class BedrockLlama2ChatAutoConfiguration { @Bean @ConditionalOnMissingBean - public Llama2ChatBedrockApi llama2Api(AwsCredentialsProvider credentialsProvider, + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) + public Llama2ChatBedrockApi llama2Api(AwsCredentialsProvider credentialsProvider, AwsRegionProvider regionProvider, BedrockLlama2ChatProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new Llama2ChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + return new Llama2ChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean + @ConditionalOnBean(Llama2ChatBedrockApi.class) public BedrockLlama2ChatClient llama2ChatClient(Llama2ChatBedrockApi llama2Api, BedrockLlama2ChatProperties properties) { diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java index e24ec3696ab..67995b9e39c 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanChatAutoConfiguration.java @@ -21,6 +21,7 @@ import org.springframework.ai.bedrock.titan.BedrockTitanChatClient; import org.springframework.ai.bedrock.titan.api.TitanChatBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -28,11 +29,13 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Import; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; /** * {@link AutoConfiguration Auto-configuration} for Bedrock Titan Chat Client. * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ @AutoConfiguration @@ -44,14 +47,16 @@ public class BedrockTitanChatAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public TitanChatBedrockApi titanChatBedrockApi(AwsCredentialsProvider credentialsProvider, - BedrockTitanChatProperties properties, BedrockAwsConnectionProperties awsProperties) { - - return new TitanChatBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockTitanChatProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new TitanChatBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean + @ConditionalOnBean(TitanChatBedrockApi.class) public BedrockTitanChatClient titanChatClient(TitanChatBedrockApi titanChatApi, BedrockTitanChatProperties properties) { diff --git a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanEmbeddingAutoConfiguration.java b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanEmbeddingAutoConfiguration.java index f36c6e427fd..5ea79d4513a 100644 --- a/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanEmbeddingAutoConfiguration.java +++ b/spring-ai-spring-boot-autoconfigure/src/main/java/org/springframework/ai/autoconfigure/bedrock/titan/BedrockTitanEmbeddingAutoConfiguration.java @@ -17,12 +17,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionConfiguration; import org.springframework.ai.autoconfigure.bedrock.BedrockAwsConnectionProperties; import org.springframework.ai.bedrock.titan.BedrockTitanEmbeddingClient; import org.springframework.ai.bedrock.titan.api.TitanEmbeddingBedrockApi; import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -34,6 +36,7 @@ * {@link AutoConfiguration Auto-configuration} for Bedrock Titan Embedding Client. * * @author Christian Tzolov + * @author Wei Jiang * @since 0.8.0 */ @AutoConfiguration @@ -45,14 +48,17 @@ public class BedrockTitanEmbeddingAutoConfiguration { @Bean @ConditionalOnMissingBean + @ConditionalOnBean({ AwsCredentialsProvider.class, AwsRegionProvider.class }) public TitanEmbeddingBedrockApi titanEmbeddingBedrockApi(AwsCredentialsProvider credentialsProvider, - BedrockTitanEmbeddingProperties properties, BedrockAwsConnectionProperties awsProperties) { - return new TitanEmbeddingBedrockApi(properties.getModel(), credentialsProvider, awsProperties.getRegion(), + AwsRegionProvider regionProvider, BedrockTitanEmbeddingProperties properties, + BedrockAwsConnectionProperties awsProperties) { + return new TitanEmbeddingBedrockApi(properties.getModel(), credentialsProvider, regionProvider.getRegion(), new ObjectMapper(), awsProperties.getTimeout()); } @Bean @ConditionalOnMissingBean + @ConditionalOnBean(TitanEmbeddingBedrockApi.class) public BedrockTitanEmbeddingClient titanEmbeddingClient(TitanEmbeddingBedrockApi titanEmbeddingApi, BedrockTitanEmbeddingProperties properties) { diff --git a/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfigurationIT.java b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfigurationIT.java new file mode 100644 index 00000000000..bea58ce80e3 --- /dev/null +++ b/spring-ai-spring-boot-autoconfigure/src/test/java/org/springframework/ai/autoconfigure/bedrock/BedrockAwsConnectionConfigurationIT.java @@ -0,0 +1,139 @@ +/* + * Copyright 2023 - 2024 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.springframework.ai.autoconfigure.bedrock; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; + +import software.amazon.awssdk.auth.credentials.AwsCredentials; +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; +import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.regions.providers.AwsRegionProvider; + +/** + * @author Wei Jiang + * @since 0.8.1 + */ +@EnabledIfEnvironmentVariable(named = "AWS_ACCESS_KEY_ID", matches = ".*") +@EnabledIfEnvironmentVariable(named = "AWS_SECRET_ACCESS_KEY", matches = ".*") +public class BedrockAwsConnectionConfigurationIT { + + @Test + public void autoConfigureAWSCredentialAndRegionProvider() { + new ApplicationContextRunner() + .withPropertyValues("spring.ai.bedrock.aws.access-key=" + System.getenv("AWS_ACCESS_KEY_ID"), + "spring.ai.bedrock.aws.secret-key=" + System.getenv("AWS_SECRET_ACCESS_KEY"), + "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id()) + .withConfiguration(AutoConfigurations.of(TestAutoConfiguration.class)) + .run((context) -> { + var awsCredentialsProvider = context.getBean(AwsCredentialsProvider.class); + var awsRegionProvider = context.getBean(AwsRegionProvider.class); + + assertThat(awsCredentialsProvider).isNotNull(); + assertThat(awsRegionProvider).isNotNull(); + + var credentials = awsCredentialsProvider.resolveCredentials(); + assertThat(credentials).isNotNull(); + assertThat(credentials.accessKeyId()).isEqualTo(System.getenv("AWS_ACCESS_KEY_ID")); + assertThat(credentials.secretAccessKey()).isEqualTo(System.getenv("AWS_SECRET_ACCESS_KEY")); + + assertThat(awsRegionProvider.getRegion()).isEqualTo(Region.US_EAST_1); + }); + } + + @Test + public void autoConfigureWithCustomAWSCredentialAndRegionProvider() { + new ApplicationContextRunner() + .withPropertyValues("spring.ai.bedrock.aws.access-key=" + System.getenv("AWS_ACCESS_KEY_ID"), + "spring.ai.bedrock.aws.secret-key=" + System.getenv("AWS_SECRET_ACCESS_KEY"), + "spring.ai.bedrock.aws.region=" + Region.US_EAST_1.id()) + .withConfiguration(AutoConfigurations.of(TestAutoConfiguration.class, + CustomAwsCredentialsProviderAndAwsRegionProviderAutoConfiguration.class)) + .run((context) -> { + var awsCredentialsProvider = context.getBean(AwsCredentialsProvider.class); + var awsRegionProvider = context.getBean(AwsRegionProvider.class); + + assertThat(awsCredentialsProvider).isNotNull(); + assertThat(awsRegionProvider).isNotNull(); + + var credentials = awsCredentialsProvider.resolveCredentials(); + assertThat(credentials).isNotNull(); + assertThat(credentials.accessKeyId()).isEqualTo("CUSTOM_ACCESS_KEY"); + assertThat(credentials.secretAccessKey()).isEqualTo("CUSTOM_SECRET_ACCESS_KEY"); + + assertThat(awsRegionProvider.getRegion()).isEqualTo(Region.AWS_GLOBAL); + }); + } + + @EnableConfigurationProperties({ BedrockAwsConnectionProperties.class }) + @Import(BedrockAwsConnectionConfiguration.class) + static class TestAutoConfiguration { + + } + + @AutoConfiguration + static class CustomAwsCredentialsProviderAndAwsRegionProviderAutoConfiguration { + + @Bean + @ConditionalOnMissingBean + public AwsCredentialsProvider credentialsProvider() { + return new AwsCredentialsProvider() { + + @Override + public AwsCredentials resolveCredentials() { + return new AwsCredentials() { + + @Override + public String accessKeyId() { + return "CUSTOM_ACCESS_KEY"; + } + + @Override + public String secretAccessKey() { + return "CUSTOM_SECRET_ACCESS_KEY"; + } + + }; + } + + }; + } + + @Bean + @ConditionalOnMissingBean + public AwsRegionProvider regionProvider() { + return new AwsRegionProvider() { + + @Override + public Region getRegion() { + return Region.AWS_GLOBAL; + } + + }; + } + + } + +}