Route curated plugins by authentication mode (#35671)

## Why

Curated plugin capabilities need to follow the active authentication mode, including after an account switch and when the configured model provider differs from the authentication source.

## What changed

- Select the ChatGPT, remote, or API curated marketplace from the current authentication mode, with an API marketplace fallback for ambient Amazon Bedrock credentials.
- Apply that selection consistently to plugin loading, hooks, skills, installed-plugin conflict filtering, marketplace listing, and `codex mcp` discovery.
- Start the local curated repository sync when an account change makes the remote catalog unavailable, and refresh existing thread MCP runtimes when the effective plugin cache changes.

## Testing

Added coverage for account switches, ChatGPT-authenticated Bedrock sessions, API-key MCP discovery, curated marketplace filtering, hook and skill routing, and existing-thread MCP refreshes.

GitOrigin-RevId: dbefdba3a3ea7281e7b6013e057a418770ccfc95
This commit is contained in:
felixxia-oai
2026-07-27 21:17:42 +00:00
committed by copyberry
parent fd41e813cb
commit 294d813263
12 changed files with 1258 additions and 88 deletions
@@ -229,19 +229,29 @@ impl AccountRequestProcessor {
Arc::clone(thread_manager),
config_manager.clone(),
);
let plugins_config = config.plugins_config_input();
let refresh_thread_manager = Arc::clone(thread_manager);
let refresh_config_manager = config_manager.clone();
let on_effective_plugins_changed: Arc<
dyn Fn(codex_core_plugins::EffectivePluginsChange) + Send + Sync,
> = Arc::new(move |_change| {
Self::spawn_effective_plugins_changed_task(
Arc::clone(&refresh_thread_manager),
refresh_config_manager.clone(),
);
});
thread_manager
.plugins_manager()
.maybe_start_curated_repo_sync_for_config(
&plugins_config,
Some(Arc::clone(&on_effective_plugins_changed)),
);
thread_manager
.plugins_manager()
.maybe_start_remote_plugin_caches_refresh(
&config.plugins_config_input(),
&plugins_config,
auth,
Some(Arc::new(move |_change| {
Self::spawn_effective_plugins_changed_task(
Arc::clone(&refresh_thread_manager),
refresh_config_manager.clone(),
);
})),
Some(on_effective_plugins_changed),
);
}
Err(err) => {
@@ -188,10 +188,15 @@ fn convert_configured_marketplace_plugin_to_plugin_summary(
}
}
fn remote_installed_plugin_visible_marketplaces(config: &Config) -> Vec<&'static str> {
fn remote_installed_plugin_visible_marketplaces(
config: &Config,
use_remote_global_catalog: bool,
) -> Vec<&'static str> {
let mut marketplaces = Vec::new();
if config.features.enabled(Feature::RemotePlugin) {
if use_remote_global_catalog {
marketplaces.push(REMOTE_GLOBAL_MARKETPLACE_NAME);
}
if config.features.enabled(Feature::RemotePlugin) {
marketplaces.push(REMOTE_CREATED_BY_ME_MARKETPLACE_NAME);
}
marketplaces.push(REMOTE_WORKSPACE_MARKETPLACE_NAME);
@@ -831,11 +836,14 @@ impl PluginRequestProcessor {
{
return Ok(empty_response());
}
plugins_manager.set_auth_mode(auth.as_ref().map(CodexAuth::api_auth_mode));
let auth_mode = auth.as_ref().map(CodexAuth::api_auth_mode);
plugins_manager.set_auth_mode(auth_mode);
let plugins_input = config.plugins_config_input();
let use_remote_global_catalog = config.features.enabled(Feature::RemotePlugin)
&& auth_mode.is_some_and(DomainAuthMode::uses_codex_backend);
let remote_installed_plugin_visible_marketplaces =
remote_installed_plugin_visible_marketplaces(&config);
remote_installed_plugin_visible_marketplaces(&config, use_remote_global_catalog);
plugins_manager.maybe_start_remote_installed_plugin_bundle_sync(
&plugins_input,
auth.clone(),
@@ -861,10 +869,7 @@ impl PluginRequestProcessor {
)
.await,
);
filter_openai_curated_installed_conflicts(
&mut data,
config.features.enabled(Feature::RemotePlugin),
);
filter_openai_curated_installed_conflicts(&mut data, use_remote_global_catalog);
Ok(PluginInstalledResponse {
marketplaces: data,