mirror of
https://github.com/openai/codex.git
synced 2026-11-13 06:45:07 +00:00
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:
1 parent
18110b810f
commit
315195492c
20 files changed
+362
-148
No files matched your search
@@ -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()
|
||||
)
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user