mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
feat: add a built-in Amazon Bedrock model provider (#18744)
## Why Codex needs a first-class `amazon-bedrock` model provider so users can select Bedrock without copying a full provider definition into `config.toml`. The provider has Codex-owned defaults for the pieces that should stay consistent across users: the display `name`, Bedrock `base_url`, and `wire_api`. At the same time, users still need a way to choose the AWS credential profile used by their local environment. This change makes `amazon-bedrock` a partially modifiable built-in provider: code owns the provider identity and endpoint defaults, while user config can set `model_providers.amazon-bedrock.aws.profile`. For example: ```toml model_provider = "amazon-bedrock" [model_providers.amazon-bedrock.aws] profile = "codex-bedrock" ``` ## What Changed - Added `amazon-bedrock` to the built-in model provider map with: - `name = "Amazon Bedrock"` - `base_url = "https://bedrock-mantle.us-east-1.api.aws/v1"` - `wire_api = "responses"` - Added AWS provider auth config with a profile-only shape: `model_providers.<id>.aws.profile`. - Kept AWS auth config restricted to `amazon-bedrock`; custom providers that set `aws` are rejected. - Allowed `model_providers.amazon-bedrock` through reserved-provider validation so it can act as a partial override. - During config loading, only `aws.profile` is copied from the user-provided `amazon-bedrock` entry onto the built-in provider. Other Bedrock provider fields remain hard-coded by the built-in definition. - Updated the generated config schema for the new provider AWS profile config.
This commit is contained in:
@@ -198,6 +198,7 @@ fn should_use_remote_compact_task_for_azure_provider() {
|
||||
env_key_instructions: None,
|
||||
experimental_bearer_token: None,
|
||||
auth: None,
|
||||
aws: None,
|
||||
wire_api: WireApi::Responses,
|
||||
query_params: None,
|
||||
http_headers: None,
|
||||
|
||||
@@ -369,6 +369,108 @@ command = "print-token"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rejects_provider_aws_for_custom_provider() {
|
||||
let err = toml::from_str::<ConfigToml>(
|
||||
r#"
|
||||
[model_providers.custom]
|
||||
name = "Custom Provider"
|
||||
|
||||
[model_providers.custom.aws]
|
||||
profile = "codex-bedrock"
|
||||
"#,
|
||||
)
|
||||
.unwrap_err();
|
||||
|
||||
assert!(
|
||||
err.to_string().contains(
|
||||
"model_providers.custom: provider aws is only supported for `amazon-bedrock`"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepts_amazon_bedrock_aws_profile_override() {
|
||||
let cfg = toml::from_str::<ConfigToml>(
|
||||
r#"
|
||||
[model_providers.amazon-bedrock.aws]
|
||||
profile = "codex-bedrock"
|
||||
"#,
|
||||
)
|
||||
.expect("Amazon Bedrock AWS profile override should deserialize");
|
||||
|
||||
assert_eq!(
|
||||
cfg.model_providers
|
||||
.get("amazon-bedrock")
|
||||
.and_then(|provider| provider.aws.as_ref())
|
||||
.and_then(|aws| aws.profile.as_deref()),
|
||||
Some("codex-bedrock")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn load_config_applies_amazon_bedrock_aws_profile_override() {
|
||||
let cfg = toml::from_str::<ConfigToml>(
|
||||
r#"
|
||||
model_provider = "amazon-bedrock"
|
||||
|
||||
[model_providers.amazon-bedrock.aws]
|
||||
profile = "codex-bedrock"
|
||||
"#,
|
||||
)
|
||||
.expect("Amazon Bedrock AWS profile override should deserialize");
|
||||
|
||||
let config = Config::load_from_base_config_with_overrides(
|
||||
cfg,
|
||||
ConfigOverrides::default(),
|
||||
tempdir().expect("tempdir").abs(),
|
||||
)
|
||||
.await
|
||||
.expect("load config");
|
||||
|
||||
assert_eq!(config.model_provider_id, "amazon-bedrock");
|
||||
assert_eq!(
|
||||
config
|
||||
.model_provider
|
||||
.aws
|
||||
.as_ref()
|
||||
.and_then(|aws| aws.profile.as_deref()),
|
||||
Some("codex-bedrock")
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn load_config_rejects_unsupported_amazon_bedrock_overrides() {
|
||||
let cfg = toml::from_str::<ConfigToml>(
|
||||
r#"
|
||||
model_provider = "amazon-bedrock"
|
||||
|
||||
[model_providers.amazon-bedrock]
|
||||
name = "Custom Bedrock"
|
||||
base_url = "https://bedrock.example.com/v1"
|
||||
requires_openai_auth = true
|
||||
supports_websockets = true
|
||||
|
||||
[model_providers.amazon-bedrock.aws]
|
||||
profile = "codex-bedrock"
|
||||
"#,
|
||||
)
|
||||
.expect("Amazon Bedrock unsupported overrides should deserialize");
|
||||
|
||||
let err = Config::load_from_base_config_with_overrides(
|
||||
cfg,
|
||||
ConfigOverrides::default(),
|
||||
tempdir().expect("tempdir").abs(),
|
||||
)
|
||||
.await
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(err.kind(), std::io::ErrorKind::InvalidData);
|
||||
assert!(err.to_string().contains(
|
||||
"model_providers.amazon-bedrock only supports changing `aws.profile`; other non-default provider fields are not supported"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn config_toml_deserializes_model_availability_nux() {
|
||||
let toml = r#"
|
||||
@@ -4755,6 +4857,7 @@ model_verbosity = "high"
|
||||
env_key_instructions: None,
|
||||
experimental_bearer_token: None,
|
||||
auth: None,
|
||||
aws: None,
|
||||
query_params: None,
|
||||
http_headers: None,
|
||||
env_http_headers: None,
|
||||
|
||||
@@ -65,6 +65,7 @@ use codex_model_provider_info::LEGACY_OLLAMA_CHAT_PROVIDER_ID;
|
||||
use codex_model_provider_info::ModelProviderInfo;
|
||||
use codex_model_provider_info::OLLAMA_CHAT_PROVIDER_REMOVED_ERROR;
|
||||
use codex_model_provider_info::built_in_model_providers;
|
||||
use codex_model_provider_info::merge_configured_model_providers;
|
||||
use codex_models_manager::ModelsManagerConfig;
|
||||
use codex_protocol::config_types::AltScreenMode;
|
||||
use codex_protocol::config_types::ForcedLoginMethod;
|
||||
@@ -1821,11 +1822,9 @@ impl Config {
|
||||
.clone()
|
||||
.filter(|value| !value.is_empty());
|
||||
|
||||
let mut model_providers = built_in_model_providers(openai_base_url);
|
||||
// Merge user-defined providers into the built-in list.
|
||||
for (key, provider) in cfg.model_providers.into_iter() {
|
||||
model_providers.entry(key).or_insert(provider);
|
||||
}
|
||||
let model_providers =
|
||||
merge_configured_model_providers(built_in_model_providers(openai_base_url), cfg.model_providers)
|
||||
.map_err(|message| std::io::Error::new(std::io::ErrorKind::InvalidData, message))?;
|
||||
|
||||
let model_provider_id = model_provider
|
||||
.or(config_profile.model_provider)
|
||||
|
||||
Reference in New Issue
Block a user