mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
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:
1 parent
e497325a6a
commit
48ebbf5334
5 files changed
+121
-4
No files matched your search
@@ -2886,6 +2886,62 @@ async fn plugin_list_includes_api_curated_marketplace_for_api_auth_when_remote_p
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn plugin_list_includes_api_curated_marketplace_for_bedrock_without_codex_auth() -> Result<()>
|
||||||
|
{
|
||||||
|
let codex_home = TempDir::new()?;
|
||||||
|
std::fs::write(
|
||||||
|
codex_home.path().join("config.toml"),
|
||||||
|
r#"model_provider = "amazon-bedrock"
|
||||||
|
|
||||||
|
[model_providers.amazon-bedrock.aws]
|
||||||
|
region = "us-east-2"
|
||||||
|
profile = "default"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
plugins = true
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
write_openai_curated_marketplace(codex_home.path(), &["chatgpt-plugin"])?;
|
||||||
|
write_openai_api_curated_marketplace(codex_home.path(), &["api-plugin"])?;
|
||||||
|
|
||||||
|
let mut mcp = TestAppServer::builder()
|
||||||
|
.with_codex_home(codex_home.path())
|
||||||
|
.without_auto_env()
|
||||||
|
.build_initialized_with_timeout(DEFAULT_TIMEOUT)
|
||||||
|
.await?;
|
||||||
|
|
||||||
|
let request_id = mcp
|
||||||
|
.send_plugin_list_request(PluginListParams {
|
||||||
|
cwds: None,
|
||||||
|
marketplace_kinds: None,
|
||||||
|
force_refetch: false,
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
let response: PluginListResponse =
|
||||||
|
timeout(DEFAULT_TIMEOUT, mcp.read_response(request_id)).await??;
|
||||||
|
|
||||||
|
assert!(!codex_home.path().join("auth.json").exists());
|
||||||
|
let api_curated_marketplace = response
|
||||||
|
.marketplaces
|
||||||
|
.iter()
|
||||||
|
.find(|marketplace| marketplace.name == "openai-api-curated")
|
||||||
|
.expect("expected API curated marketplace");
|
||||||
|
assert_eq!(api_curated_marketplace.plugins.len(), 1);
|
||||||
|
assert_eq!(
|
||||||
|
api_curated_marketplace.plugins[0].id,
|
||||||
|
"api-plugin@openai-api-curated"
|
||||||
|
);
|
||||||
|
assert!(
|
||||||
|
response
|
||||||
|
.marketplaces
|
||||||
|
.iter()
|
||||||
|
.all(|marketplace| marketplace.name != "openai-curated")
|
||||||
|
);
|
||||||
|
assert!(response.marketplace_load_errors.is_empty());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test]
|
#[tokio::test]
|
||||||
async fn plugin_list_does_not_query_openai_curated_remote_collection_by_default() -> Result<()> {
|
async fn plugin_list_does_not_query_openai_curated_remote_collection_by_default() -> Result<()> {
|
||||||
let codex_home = TempDir::new()?;
|
let codex_home = TempDir::new()?;
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ use codex_hooks::plugin_hook_declarations;
|
|||||||
use codex_http_client::HttpClientFactory;
|
use codex_http_client::HttpClientFactory;
|
||||||
use codex_login::AuthManager;
|
use codex_login::AuthManager;
|
||||||
use codex_login::CodexAuth;
|
use codex_login::CodexAuth;
|
||||||
|
use codex_model_provider::AMAZON_BEDROCK_PROVIDER_ID;
|
||||||
use codex_plugin::AppConnectorId;
|
use codex_plugin::AppConnectorId;
|
||||||
use codex_plugin::PluginCapabilitySummary;
|
use codex_plugin::PluginCapabilitySummary;
|
||||||
use codex_plugin::PluginId;
|
use codex_plugin::PluginId;
|
||||||
@@ -117,6 +118,7 @@ type EffectivePluginsChangedCallback = Arc<dyn Fn(EffectivePluginsChange) + Send
|
|||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct PluginsConfigInput {
|
pub struct PluginsConfigInput {
|
||||||
pub config_layer_stack: ConfigLayerStack,
|
pub config_layer_stack: ConfigLayerStack,
|
||||||
|
pub model_provider_id: String,
|
||||||
pub plugins_enabled: bool,
|
pub plugins_enabled: bool,
|
||||||
pub remote_plugin_enabled: bool,
|
pub remote_plugin_enabled: bool,
|
||||||
pub chatgpt_base_url: String,
|
pub chatgpt_base_url: String,
|
||||||
@@ -126,6 +128,7 @@ pub struct PluginsConfigInput {
|
|||||||
impl PluginsConfigInput {
|
impl PluginsConfigInput {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
config_layer_stack: ConfigLayerStack,
|
config_layer_stack: ConfigLayerStack,
|
||||||
|
model_provider_id: String,
|
||||||
plugins_enabled: bool,
|
plugins_enabled: bool,
|
||||||
remote_plugin_enabled: bool,
|
remote_plugin_enabled: bool,
|
||||||
chatgpt_base_url: String,
|
chatgpt_base_url: String,
|
||||||
@@ -133,6 +136,7 @@ impl PluginsConfigInput {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
config_layer_stack,
|
config_layer_stack,
|
||||||
|
model_provider_id,
|
||||||
plugins_enabled,
|
plugins_enabled,
|
||||||
remote_plugin_enabled,
|
remote_plugin_enabled,
|
||||||
chatgpt_base_url,
|
chatgpt_base_url,
|
||||||
@@ -2786,10 +2790,12 @@ impl PluginsManager {
|
|||||||
self.codex_home.as_path(),
|
self.codex_home.as_path(),
|
||||||
));
|
));
|
||||||
let curated_marketplace_path = if include_openai_curated {
|
let curated_marketplace_path = if include_openai_curated {
|
||||||
if matches!(
|
if config.model_provider_id == AMAZON_BEDROCK_PROVIDER_ID
|
||||||
self.auth_mode(),
|
|| matches!(
|
||||||
Some(AuthMode::ApiKey | AuthMode::BedrockApiKey)
|
self.auth_mode(),
|
||||||
) {
|
Some(AuthMode::ApiKey | AuthMode::BedrockApiKey)
|
||||||
|
)
|
||||||
|
{
|
||||||
let api_marketplace_path =
|
let api_marketplace_path =
|
||||||
curated_plugins_api_marketplace_path(self.codex_home.as_path());
|
curated_plugins_api_marketplace_path(self.codex_home.as_path());
|
||||||
api_marketplace_path
|
api_marketplace_path
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ fn plugins_config_input_with_requirements(
|
|||||||
) -> PluginsConfigInput {
|
) -> PluginsConfigInput {
|
||||||
PluginsConfigInput::new(
|
PluginsConfigInput::new(
|
||||||
config_layer_stack_with_requirements(codex_home, user_config, requirements),
|
config_layer_stack_with_requirements(codex_home, user_config, requirements),
|
||||||
|
String::new(),
|
||||||
/*plugins_enabled*/ true,
|
/*plugins_enabled*/ true,
|
||||||
/*remote_plugin_enabled*/ false,
|
/*remote_plugin_enabled*/ false,
|
||||||
String::new(),
|
String::new(),
|
||||||
@@ -2625,6 +2626,7 @@ async fn plugin_cache_ignores_unrelated_session_overrides() {
|
|||||||
let config = |session_config| {
|
let config = |session_config| {
|
||||||
PluginsConfigInput::new(
|
PluginsConfigInput::new(
|
||||||
stack(session_config),
|
stack(session_config),
|
||||||
|
String::new(),
|
||||||
/*plugins_enabled*/ true,
|
/*plugins_enabled*/ true,
|
||||||
/*remote_plugin_enabled*/ false,
|
/*remote_plugin_enabled*/ false,
|
||||||
"https://chatgpt.com".to_string(),
|
"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]
|
#[tokio::test]
|
||||||
async fn list_marketplaces_skips_missing_api_curated_manifest() {
|
async fn list_marketplaces_skips_missing_api_curated_manifest() {
|
||||||
let tmp = tempfile::tempdir().unwrap();
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
|||||||
@@ -213,8 +213,14 @@ pub(crate) async fn load_plugins_config(codex_home: &Path, cwd: &Path) -> Plugin
|
|||||||
.await
|
.await
|
||||||
.expect("config should load");
|
.expect("config should load");
|
||||||
let effective_config = config_layer_stack.effective_config();
|
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(
|
PluginsConfigInput::new(
|
||||||
config_layer_stack,
|
config_layer_stack,
|
||||||
|
model_provider_id,
|
||||||
feature_enabled(&effective_config, "plugins", /*default_enabled*/ true),
|
feature_enabled(&effective_config, "plugins", /*default_enabled*/ true),
|
||||||
feature_enabled(
|
feature_enabled(
|
||||||
&effective_config,
|
&effective_config,
|
||||||
|
|||||||
@@ -1535,6 +1535,7 @@ impl Config {
|
|||||||
pub fn plugins_config_input(&self) -> PluginsConfigInput {
|
pub fn plugins_config_input(&self) -> PluginsConfigInput {
|
||||||
PluginsConfigInput::new(
|
PluginsConfigInput::new(
|
||||||
self.config_layer_stack.clone(),
|
self.config_layer_stack.clone(),
|
||||||
|
self.model_provider_id.clone(),
|
||||||
self.features.enabled(Feature::Plugins),
|
self.features.enabled(Feature::Plugins),
|
||||||
self.features.enabled(Feature::RemotePlugin),
|
self.features.enabled(Feature::RemotePlugin),
|
||||||
self.chatgpt_base_url.clone(),
|
self.chatgpt_base_url.clone(),
|
||||||
|
|||||||
Reference in new issue
Block a user