Support custom transports for Amazon Bedrock (#33695)

## What changed

- Allow the built-in `amazon-bedrock` provider to override `base_url`, `auth`,
  and `http_headers` in addition to its AWS profile and region.
- Use command-based bearer authentication and configured endpoints without
  applying AWS request signing, while retaining regional endpoint resolution
  for the default Bedrock configuration.
- Replace the Bedrock account `credentialSource` enum with the
  `usesCodexManagedCredentials` boolean so command-authenticated and other
  externally managed configurations are reported consistently.

## Testing

- Cover configuration merging and validation, command-authenticated proxy
  requests with custom headers, and account reporting for managed and external
  credentials.

GitOrigin-RevId: d1acbe602060470583b5e12f8d304bee5be46f4c
This commit is contained in:
Celia Chen authored and copyberry committed 2026-07-16 21:41:00 +00:00
1 parent 18110b810f
commit 315195492c
20 files changed
+362 -148

No files matched your search

+20 -11
View File
@@ -368,7 +368,10 @@ impl ModelProviderInfo {
) -> ModelProviderInfo {
ModelProviderInfo {
name: AMAZON_BEDROCK_PROVIDER_NAME.into(),
base_url: Some(AMAZON_BEDROCK_DEFAULT_BASE_URL.into()),
// The runtime provider derives the regional Mantle endpoint when
// this is unset. A configured value is therefore unambiguously an
// endpoint override.
base_url: None,
env_key: None,
env_key_instructions: None,
experimental_bearer_token: None,
@@ -459,30 +462,36 @@ pub fn built_in_model_providers(
///
/// Configured providers extend the built-in set. Built-in providers are not
/// generally overridable, but the built-in Amazon Bedrock provider allows the
/// user to set `aws.profile` and `aws.region`.
/// user to customize its endpoint, authentication, headers, and AWS settings.
pub fn merge_configured_model_providers(
mut model_providers: HashMap<String, ModelProviderInfo>,
configured_model_providers: HashMap<String, ModelProviderInfo>,
) -> Result<HashMap<String, ModelProviderInfo>, String> {
for (key, mut provider) in configured_model_providers {
if key == AMAZON_BEDROCK_PROVIDER_ID {
let base_url_override = provider.base_url.take();
let auth_override = provider.auth.take();
let aws_override = provider.aws.take();
let http_headers_override = provider.http_headers.take();
if provider != ModelProviderInfo::default() {
return Err(format!(
"model_providers.{AMAZON_BEDROCK_PROVIDER_ID} only supports changing \
`aws.profile` and `aws.region`; other non-default provider fields are not supported"
`base_url`, `auth`, `http_headers`, `aws.profile`, and `aws.region`; other non-default \
provider fields are not supported"
));
}
if let Some(aws_override) = aws_override
&& let Some(built_in_provider) = model_providers.get_mut(AMAZON_BEDROCK_PROVIDER_ID)
&& let Some(built_in_aws) = built_in_provider.aws.as_mut()
{
if let Some(profile) = aws_override.profile {
built_in_aws.profile = Some(profile);
if let Some(built_in_provider) = model_providers.get_mut(AMAZON_BEDROCK_PROVIDER_ID) {
built_in_provider.base_url = base_url_override;
built_in_provider.auth = auth_override;
if let Some(aws_override) = aws_override {
built_in_provider.aws = Some(aws_override);
}
if let Some(region) = aws_override.region {
built_in_aws.region = Some(region);
if let Some(http_headers_override) = http_headers_override {
built_in_provider
.http_headers
.get_or_insert_default()
.extend(http_headers_override);
}
}
} else {
@@ -288,7 +288,7 @@ fn test_create_amazon_bedrock_provider() {
ModelProviderInfo::create_amazon_bedrock_provider(/*aws*/ None),
ModelProviderInfo {
name: "Amazon Bedrock".to_string(),
base_url: Some("https://bedrock-mantle.us-east-1.api.aws/openai/v1".to_string()),
base_url: None,
env_key: None,
env_key_instructions: None,
experimental_bearer_token: None,
@@ -314,6 +314,19 @@ fn test_create_amazon_bedrock_provider() {
);
}
fn provider_auth_for_test() -> ModelProviderAuthInfo {
ModelProviderAuthInfo {
command: "token-fetcher".to_string(),
args: vec!["fetch".to_string()],
timeout_ms: NonZeroU64::new(5_000).expect("timeout should be non-zero"),
refresh_interval_ms: 300_000,
cwd: std::env::current_dir()
.expect("current directory should be available")
.try_into()
.expect("current directory should be absolute"),
}
}
#[test]
fn test_amazon_bedrock_provider_adds_mantle_client_agent_header() {
let api_provider = ModelProviderInfo::create_amazon_bedrock_provider(/*aws*/ None)
@@ -394,6 +407,49 @@ fn test_merge_configured_model_providers_applies_amazon_bedrock_profile_override
);
}
#[test]
fn test_merge_configured_model_providers_applies_amazon_bedrock_transport_overrides() {
let auth = provider_auth_for_test();
let configured_model_providers = std::collections::HashMap::from([(
AMAZON_BEDROCK_PROVIDER_ID.to_string(),
ModelProviderInfo {
base_url: Some("https://proxy.example.com/v1".to_string()),
auth: Some(auth.clone()),
aws: Some(ModelProviderAwsAuthInfo {
profile: Some("codex-bedrock".to_string()),
region: Some("us-west-2".to_string()),
}),
http_headers: Some(maplit::hashmap! {
"x-example-header".to_string() => "value".to_string(),
}),
..ModelProviderInfo::default()
},
)]);
let mut expected = built_in_model_providers(/*openai_base_url*/ None);
let expected_provider = expected
.get_mut(AMAZON_BEDROCK_PROVIDER_ID)
.expect("Amazon Bedrock provider should be built in");
expected_provider.base_url = Some("https://proxy.example.com/v1".to_string());
expected_provider.auth = Some(auth);
expected_provider.aws = Some(ModelProviderAwsAuthInfo {
profile: Some("codex-bedrock".to_string()),
region: Some("us-west-2".to_string()),
});
expected_provider
.http_headers
.get_or_insert_default()
.insert("x-example-header".to_string(), "value".to_string());
assert_eq!(
merge_configured_model_providers(
built_in_model_providers(/*openai_base_url*/ None),
configured_model_providers,
),
Ok(expected)
);
}
#[test]
fn test_merge_configured_model_providers_rejects_amazon_bedrock_non_default_fields() {
let configured_model_providers = std::collections::HashMap::from([(
@@ -414,7 +470,7 @@ fn test_merge_configured_model_providers_rejects_amazon_bedrock_non_default_fiel
configured_model_providers,
),
Err(
"model_providers.amazon-bedrock only supports changing `aws.profile` and `aws.region`; other non-default provider fields are not supported"
"model_providers.amazon-bedrock only supports changing `base_url`, `auth`, `http_headers`, `aws.profile`, and `aws.region`; other non-default provider fields are not supported"
.to_string()
)
);