use codex_aws_auth::AwsAuthConfig; use codex_login::CodexAuth; use codex_model_provider_info::ModelProviderAwsAuthInfo; use codex_protocol::error::CodexErr; use codex_protocol::error::Result; use super::BedrockEndpoint; use super::auth::BedrockAuthSource; use super::auth::resolve_region; const BEDROCK_MANTLE_SERVICE_NAME: &str = "bedrock-mantle"; const BEDROCK_MANTLE_SUPPORTED_REGIONS: [&str; 12] = [ "us-east-2", "us-east-1", "us-west-2", "ap-southeast-3", "ap-south-1", "ap-northeast-1", "eu-central-1", "eu-west-1", "eu-west-2", "eu-south-1", "eu-north-1", "sa-east-1", ]; const BEDROCK_GOV_CLOUD_SUPPORTED_REGIONS: [&str; 2] = ["us-gov-east-1", "us-gov-west-1"]; pub(super) fn aws_auth_config(aws: &ModelProviderAwsAuthInfo) -> AwsAuthConfig { AwsAuthConfig { profile: aws.profile.clone(), region: region_from_config(aws), service: BEDROCK_MANTLE_SERVICE_NAME.to_string(), } } pub(super) fn region_from_config(aws: &ModelProviderAwsAuthInfo) -> Option { aws.region .as_deref() .map(str::trim) .filter(|region| !region.is_empty()) .map(str::to_string) } /// Returns whether Amazon Bedrock Mantle is available in `region`. pub fn is_supported_amazon_bedrock_region(region: &str) -> bool { BEDROCK_MANTLE_SUPPORTED_REGIONS.contains(®ion) || is_amazon_bedrock_gov_cloud_region(region) } /// Returns whether `region` is a supported Amazon Bedrock GovCloud region. pub fn is_amazon_bedrock_gov_cloud_region(region: &str) -> bool { BEDROCK_GOV_CLOUD_SUPPORTED_REGIONS.contains(®ion) } pub(super) fn base_url(region: &str) -> Result { if is_supported_amazon_bedrock_region(region) { Ok(format!("https://bedrock-mantle.{region}.api.aws/openai/v1")) } else { Err(CodexErr::Fatal(format!( "Amazon Bedrock does not support region `{region}`" ))) } } pub(super) async fn bedrock_mantle_runtime_base_url( source: BedrockAuthSource, managed_auth: Option<&CodexAuth>, aws: &ModelProviderAwsAuthInfo, http_client_factory: &codex_http_client::HttpClientFactory, ) -> Result { let region = resolve_region( source, managed_auth, aws, BedrockEndpoint::Mantle, http_client_factory, ) .await?; base_url(®ion) } #[cfg(test)] mod tests { use pretty_assertions::assert_eq; use super::*; #[test] fn base_url_uses_region_endpoint() { for (region, expected) in [ ( "ap-northeast-1", "https://bedrock-mantle.ap-northeast-1.api.aws/openai/v1", ), ( "us-gov-east-1", "https://bedrock-mantle.us-gov-east-1.api.aws/openai/v1", ), ( "us-gov-west-1", "https://bedrock-mantle.us-gov-west-1.api.aws/openai/v1", ), ] { assert_eq!(base_url(region).expect("supported region"), expected); } } #[test] fn base_url_rejects_unsupported_region() { let err = base_url("us-west-1").expect_err("unsupported region"); assert_eq!( err.to_string(), "Fatal error: Amazon Bedrock does not support region `us-west-1`" ); } #[test] fn aws_auth_config_uses_profile_and_mantle_service() { assert_eq!( aws_auth_config(&ModelProviderAwsAuthInfo { profile: Some("codex-bedrock".to_string()), region: None, credential_export: None, auth_refresh: None, }), AwsAuthConfig { profile: Some("codex-bedrock".to_string()), region: None, service: "bedrock-mantle".to_string(), } ); } #[test] fn aws_auth_config_uses_configured_region() { assert_eq!( aws_auth_config(&ModelProviderAwsAuthInfo { profile: None, region: Some(" us-west-2 ".to_string()), credential_export: None, auth_refresh: None, }), AwsAuthConfig { profile: None, region: Some("us-west-2".to_string()), service: "bedrock-mantle".to_string(), } ); } }