Use the API plugin marketplace for Amazon Bedrock (#34931)

## Why

Amazon Bedrock configurations can operate without Codex auth, so auth mode alone
cannot determine which curated plugin marketplace to expose.

## What changed

- Pass the resolved model provider into plugin configuration.
- Select `openai-api-curated` when the resolved provider is `amazon-bedrock`,
  while retaining API-key auth as a selection signal.
- Cover provider overrides and app-server plugin listing without an `auth.json`
  file.

GitOrigin-RevId: 972a22e19c41490d8b19d989da052302dc30e8f2
This commit is contained in:
felixxia-oai
2026-07-23 11:32:47 +00:00
committed by copyberry
parent e497325a6a
commit 48ebbf5334
5 changed files with 121 additions and 4 deletions
+10 -4
View File
@@ -74,6 +74,7 @@ use codex_hooks::plugin_hook_declarations;
use codex_http_client::HttpClientFactory;
use codex_login::AuthManager;
use codex_login::CodexAuth;
use codex_model_provider::AMAZON_BEDROCK_PROVIDER_ID;
use codex_plugin::AppConnectorId;
use codex_plugin::PluginCapabilitySummary;
use codex_plugin::PluginId;
@@ -117,6 +118,7 @@ type EffectivePluginsChangedCallback = Arc<dyn Fn(EffectivePluginsChange) + Send
#[derive(Debug, Clone)]
pub struct PluginsConfigInput {
pub config_layer_stack: ConfigLayerStack,
pub model_provider_id: String,
pub plugins_enabled: bool,
pub remote_plugin_enabled: bool,
pub chatgpt_base_url: String,
@@ -126,6 +128,7 @@ pub struct PluginsConfigInput {
impl PluginsConfigInput {
pub fn new(
config_layer_stack: ConfigLayerStack,
model_provider_id: String,
plugins_enabled: bool,
remote_plugin_enabled: bool,
chatgpt_base_url: String,
@@ -133,6 +136,7 @@ impl PluginsConfigInput {
) -> Self {
Self {
config_layer_stack,
model_provider_id,
plugins_enabled,
remote_plugin_enabled,
chatgpt_base_url,
@@ -2786,10 +2790,12 @@ impl PluginsManager {
self.codex_home.as_path(),
));
let curated_marketplace_path = if include_openai_curated {
if matches!(
self.auth_mode(),
Some(AuthMode::ApiKey | AuthMode::BedrockApiKey)
) {
if config.model_provider_id == AMAZON_BEDROCK_PROVIDER_ID
|| matches!(
self.auth_mode(),
Some(AuthMode::ApiKey | AuthMode::BedrockApiKey)
)
{
let api_marketplace_path =
curated_plugins_api_marketplace_path(self.codex_home.as_path());
api_marketplace_path
@@ -108,6 +108,7 @@ fn plugins_config_input_with_requirements(
) -> PluginsConfigInput {
PluginsConfigInput::new(
config_layer_stack_with_requirements(codex_home, user_config, requirements),
String::new(),
/*plugins_enabled*/ true,
/*remote_plugin_enabled*/ false,
String::new(),
@@ -2625,6 +2626,7 @@ async fn plugin_cache_ignores_unrelated_session_overrides() {
let config = |session_config| {
PluginsConfigInput::new(
stack(session_config),
String::new(),
/*plugins_enabled*/ true,
/*remote_plugin_enabled*/ false,
"https://chatgpt.com".to_string(),
@@ -4410,6 +4412,52 @@ plugins = true
);
}
#[tokio::test]
async fn list_marketplaces_uses_resolved_provider_instead_of_configured_default() {
for (configured_provider, resolved_provider, expected_marketplace) in [
(
"openai",
AMAZON_BEDROCK_PROVIDER_ID,
OPENAI_API_CURATED_MARKETPLACE_NAME,
),
(
AMAZON_BEDROCK_PROVIDER_ID,
"openai",
OPENAI_CURATED_MARKETPLACE_NAME,
),
] {
let tmp = tempfile::tempdir().unwrap();
let curated_root = curated_plugins_repo_path(tmp.path());
write_file(
&tmp.path().join(CONFIG_TOML_FILE),
&format!(
r#"model_provider = "{configured_provider}"
[features]
plugins = true
"#
),
);
write_openai_curated_marketplace(&curated_root, &["chatgpt-plugin"]);
write_openai_api_curated_marketplace(&curated_root, &["api-plugin"]);
let mut config = load_config(tmp.path(), tmp.path()).await;
config.model_provider_id = resolved_provider.to_string();
let marketplaces = PluginsManager::new(tmp.path().to_path_buf())
.list_marketplaces_for_config(&config, &[], /*include_openai_curated*/ true)
.unwrap()
.marketplaces;
assert!(
marketplaces
.iter()
.any(|marketplace| marketplace.name == expected_marketplace),
"expected `{expected_marketplace}` for resolved provider `{resolved_provider}`"
);
}
}
#[tokio::test]
async fn list_marketplaces_skips_missing_api_curated_manifest() {
let tmp = tempfile::tempdir().unwrap();
@@ -213,8 +213,14 @@ pub(crate) async fn load_plugins_config(codex_home: &Path, cwd: &Path) -> Plugin
.await
.expect("config should load");
let effective_config = config_layer_stack.effective_config();
let model_provider_id = effective_config
.get("model_provider")
.and_then(toml::Value::as_str)
.unwrap_or_default()
.to_string();
PluginsConfigInput::new(
config_layer_stack,
model_provider_id,
feature_enabled(&effective_config, "plugins", /*default_enabled*/ true),
feature_enabled(
&effective_config,