mirror of
https://github.com/openai/codex.git
synced 2026-11-09 00:39:32 +00:00
Honor thread-level plugin exclusions across runtime capabilities (#44655)
## What changed - Apply `disabled_plugin_ids` to plugin skills, recommendations, hooks, and MCP servers without modifying shared plugin state. - Activate selection changes when the next task starts, keeping pending settings from changing the active runtime. - Hide app tools contributed only by disabled plugins from model tool catalogs and search. Preserve connectors shared with enabled plugins and existing direct Apps RPC behavior. - Include plugin identity in MCP approval keys and use that identity when persisting plugin tool approvals. ## Testing Add regression coverage for disabling and re-enabling plugin skills and tools, deferred activation of settings, shared connector ownership, selected plugin servers, executor hooks, and plugin-specific approval keys and persistence. GitOrigin-RevId: 1153ff6aa7ab6953d50e838da05203904ecd2956
This commit is contained in:
1 parent
5c94936b56
commit
8570091e14
27 files changed
+565
-171
No files matched your search
@@ -98,11 +98,12 @@ impl Session {
|
||||
config: &Config,
|
||||
) -> (McpConfig, McpRuntimeContext) {
|
||||
let originator = self.originator().await;
|
||||
let (session_source, host_fallback_cwd) = {
|
||||
let (session_source, host_fallback_cwd, disabled_plugin_ids) = {
|
||||
let state = self.state.lock().await;
|
||||
(
|
||||
state.session_configuration.session_source.clone(),
|
||||
state.session_configuration.cwd().clone(),
|
||||
state.active_disabled_plugin_ids.clone(),
|
||||
)
|
||||
};
|
||||
let environments = self.services.turn_environments.snapshot().await;
|
||||
@@ -128,6 +129,7 @@ impl Session {
|
||||
McpThreadIdentity {
|
||||
session_source: &session_source,
|
||||
originator: &originator,
|
||||
disabled_plugin_ids: &disabled_plugin_ids,
|
||||
environments: McpEnvironmentScope::Live(&self.services.turn_environments),
|
||||
},
|
||||
&ready_selected_capability_roots,
|
||||
@@ -233,6 +235,7 @@ impl Session {
|
||||
McpThreadIdentity {
|
||||
session_source: &desired.session_source,
|
||||
originator: &desired.originator,
|
||||
disabled_plugin_ids: &desired.disabled_plugin_ids,
|
||||
environments: McpEnvironmentScope::Live(&self.services.turn_environments),
|
||||
},
|
||||
&ready_selected_capability_roots,
|
||||
@@ -299,6 +302,7 @@ impl Session {
|
||||
McpThreadIdentity {
|
||||
session_source: &desired.session_source,
|
||||
originator: &desired.originator,
|
||||
disabled_plugin_ids: &desired.disabled_plugin_ids,
|
||||
environments: McpEnvironmentScope::Live(&self.services.turn_environments),
|
||||
},
|
||||
&ready_selected_capability_roots,
|
||||
@@ -662,12 +666,13 @@ impl Session {
|
||||
return;
|
||||
};
|
||||
let auth = self.services.auth_manager.auth().await;
|
||||
{
|
||||
let disabled_plugin_ids = {
|
||||
let mut state = self.state.lock().await;
|
||||
let mut config = (*state.session_configuration.original_config_do_not_use).clone();
|
||||
config.mcp_servers = refresh_config.mcp_servers.clone();
|
||||
state.session_configuration.original_config_do_not_use = Arc::new(config);
|
||||
}
|
||||
state.active_disabled_plugin_ids.clone()
|
||||
};
|
||||
let ready_selected_capability_roots = self
|
||||
.services
|
||||
.mcp_runtime
|
||||
@@ -690,6 +695,7 @@ impl Session {
|
||||
McpThreadIdentity {
|
||||
session_source: &turn_context.session_source,
|
||||
originator: &turn_context.originator,
|
||||
disabled_plugin_ids: &disabled_plugin_ids,
|
||||
environments: McpEnvironmentScope::Live(&self.services.turn_environments),
|
||||
},
|
||||
&ready_selected_capability_roots,
|
||||
|
||||
@@ -28,6 +28,7 @@ pub(super) struct McpDesiredState {
|
||||
pub(super) session_source: SessionSource,
|
||||
pub(super) environments: TurnEnvironmentSnapshot,
|
||||
pub(super) local_process_cwd: PathBuf,
|
||||
pub(super) disabled_plugin_ids: Vec<String>,
|
||||
}
|
||||
|
||||
impl Session {
|
||||
@@ -75,9 +76,12 @@ impl Session {
|
||||
&self,
|
||||
auth: Option<CodexAuth>,
|
||||
) -> McpDesiredState {
|
||||
let session_configuration = {
|
||||
let (session_configuration, disabled_plugin_ids) = {
|
||||
let state = self.state.lock().await;
|
||||
state.session_configuration.clone()
|
||||
(
|
||||
state.session_configuration.clone(),
|
||||
state.active_disabled_plugin_ids.clone(),
|
||||
)
|
||||
};
|
||||
let environments = self.services.turn_environments.snapshot().await;
|
||||
let cwd = environments
|
||||
@@ -98,6 +102,7 @@ impl Session {
|
||||
session_source: session_configuration.session_source.clone(),
|
||||
environments,
|
||||
local_process_cwd,
|
||||
disabled_plugin_ids,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,6 +129,7 @@ impl Session {
|
||||
session_source: session_configuration.session_source.clone(),
|
||||
environments: resolved_environments.clone(),
|
||||
local_process_cwd,
|
||||
disabled_plugin_ids: session_configuration.disabled_plugin_ids.clone(),
|
||||
};
|
||||
self.publish_mcp_runtime(
|
||||
&desired,
|
||||
|
||||
@@ -235,6 +235,7 @@ mod mcp_prewarm;
|
||||
mod mcp_refresh;
|
||||
mod mcp_runtime;
|
||||
pub(crate) mod multi_agents;
|
||||
mod plugin_selection;
|
||||
mod realtime_history;
|
||||
mod retained_context;
|
||||
mod review;
|
||||
@@ -2006,11 +2007,13 @@ impl Session {
|
||||
}
|
||||
|
||||
pub(crate) async fn refresh_hooks(&self, config: Arc<Config>) {
|
||||
let disabled_plugin_ids = self.state.lock().await.active_disabled_plugin_ids.clone();
|
||||
let environments = self.services.turn_environments.snapshot().await;
|
||||
let hooks_config = build_hooks_config(
|
||||
config.as_ref(),
|
||||
self.services.plugins_manager.as_ref(),
|
||||
environments.single_local_environment(),
|
||||
&disabled_plugin_ids,
|
||||
)
|
||||
.await;
|
||||
|
||||
@@ -2020,7 +2023,8 @@ impl Session {
|
||||
if Arc::ptr_eq(
|
||||
&state.session_configuration.original_config_do_not_use,
|
||||
&config,
|
||||
) {
|
||||
) && state.active_disabled_plugin_ids == disabled_plugin_ids
|
||||
{
|
||||
let hooks = self.hooks().reconfigured(hooks_config);
|
||||
self.services.hooks.store(Arc::new(hooks));
|
||||
}
|
||||
@@ -4112,7 +4116,8 @@ impl Session {
|
||||
.services
|
||||
.plugins_manager
|
||||
.plugins_for_config(&turn_context.config.plugins_config_input())
|
||||
.await;
|
||||
.await
|
||||
.without_plugins(&turn_context.disabled_plugin_ids);
|
||||
let recommended_plugin_candidates = if turn_context
|
||||
.config
|
||||
.features
|
||||
@@ -4874,6 +4879,7 @@ async fn build_hooks_config(
|
||||
config: &Config,
|
||||
plugins_manager: &PluginsManager,
|
||||
environment: Option<&TurnEnvironment>,
|
||||
disabled_plugin_ids: &[String],
|
||||
) -> HooksConfig {
|
||||
let (hook_shell_program, hook_shell_argv) = environment
|
||||
.and_then(|environment| environment.shell.as_ref())
|
||||
@@ -4885,7 +4891,10 @@ async fn build_hooks_config(
|
||||
})
|
||||
.unwrap_or_default();
|
||||
let plugins_input = config.plugins_config_input();
|
||||
let plugin_outcome = plugins_manager.plugins_for_config(&plugins_input).await;
|
||||
let plugin_outcome = plugins_manager
|
||||
.plugins_for_config(&plugins_input)
|
||||
.await
|
||||
.without_plugins(disabled_plugin_ids);
|
||||
let plugin_hook_sources = plugin_outcome.effective_plugin_hook_sources();
|
||||
let plugin_hook_load_warnings = plugin_outcome.effective_plugin_hook_warnings();
|
||||
HooksConfig {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
//! Activates an admitted task's plugin selection without changing pending settings.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use super::Session;
|
||||
use super::turn_context::TurnContext;
|
||||
|
||||
impl Session {
|
||||
pub(crate) async fn activate_plugin_selection(&self, turn_context: &TurnContext) {
|
||||
let config = {
|
||||
let mut state = self.state.lock().await;
|
||||
if state.active_disabled_plugin_ids != turn_context.disabled_plugin_ids {
|
||||
state.active_disabled_plugin_ids = turn_context.disabled_plugin_ids.clone();
|
||||
self.mark_mcp_runtime_dirty();
|
||||
}
|
||||
Arc::clone(&state.session_configuration.original_config_do_not_use)
|
||||
};
|
||||
let plugin_outcome = self
|
||||
.services
|
||||
.plugins_manager
|
||||
.plugins_for_config(&config.plugins_config_input())
|
||||
.await
|
||||
.without_plugins(&turn_context.disabled_plugin_ids);
|
||||
// Cache changes from another process do not notify this session's hook runtime.
|
||||
if !self.hooks().matches_plugin_hooks(
|
||||
plugin_outcome.iter_effective_plugin_hook_sources(),
|
||||
plugin_outcome.iter_effective_plugin_hook_warnings(),
|
||||
) {
|
||||
self.refresh_hooks(config).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -996,6 +996,7 @@ impl Session {
|
||||
let thread_extension_data_for_mcp = &thread_extension_data;
|
||||
let mcp_originator = session_configuration.originator.clone();
|
||||
let mcp_session_source = session_configuration.session_source.clone();
|
||||
let mcp_disabled_plugin_ids = session_configuration.disabled_plugin_ids.clone();
|
||||
let mcp_runtime_cwd = environment_selections
|
||||
.first()
|
||||
.and_then(|environment| environment.cwd.to_abs_path().ok())
|
||||
@@ -1025,6 +1026,7 @@ impl Session {
|
||||
McpThreadIdentity {
|
||||
session_source: &mcp_session_source,
|
||||
originator: &mcp_originator,
|
||||
disabled_plugin_ids: &mcp_disabled_plugin_ids,
|
||||
environments: McpEnvironmentScope::Initial(environment_selections),
|
||||
},
|
||||
/*ready_selected_capability_roots*/ &[],
|
||||
@@ -1340,6 +1342,7 @@ impl Session {
|
||||
),
|
||||
);
|
||||
state.base_instructions_provenance = base_instructions_provenance.clone();
|
||||
state.active_disabled_plugin_ids = session_configuration.disabled_plugin_ids.clone();
|
||||
let managed_network_requirements_configured = config
|
||||
.config_layer_stack
|
||||
.requirements_toml()
|
||||
@@ -1419,6 +1422,7 @@ impl Session {
|
||||
&config,
|
||||
plugins_manager.as_ref(),
|
||||
resolved_environments.single_local_environment(),
|
||||
&session_configuration.disabled_plugin_ids,
|
||||
)
|
||||
.await;
|
||||
let (hooks, async_hook_results) = Hooks::new(
|
||||
@@ -1672,6 +1676,7 @@ impl Session {
|
||||
McpThreadIdentity {
|
||||
session_source: &session_configuration.session_source,
|
||||
originator: &session_configuration.originator,
|
||||
disabled_plugin_ids: &session_configuration.disabled_plugin_ids,
|
||||
environments: McpEnvironmentScope::Live(
|
||||
&sess.services.turn_environments,
|
||||
),
|
||||
|
||||
@@ -878,7 +878,8 @@ async fn required_mcp_servers_for_input(
|
||||
.services
|
||||
.plugins_manager
|
||||
.plugins_for_config(&turn_context.config.plugins_config_input())
|
||||
.await;
|
||||
.await
|
||||
.without_plugins(&turn_context.disabled_plugin_ids);
|
||||
let current_config = sess.services.mcp_runtime.current_config();
|
||||
let mentioned_plugins =
|
||||
collect_explicit_plugin_mentions(user_input, loaded_plugins.capability_summaries());
|
||||
@@ -1661,7 +1662,8 @@ pub(crate) async fn prepare_tool_recommendations(
|
||||
.plugins_manager
|
||||
.plugins_for_config(&turn_context.config.plugins_config_input())
|
||||
.instrument(trace_span!("built_tools.load_plugins"))
|
||||
.await;
|
||||
.await
|
||||
.without_plugins(&turn_context.disabled_plugin_ids);
|
||||
let tool_suggest_is_enabled = tool_suggest_enabled(turn_context);
|
||||
let auth = if tool_suggest_is_enabled {
|
||||
sess.services.auth_manager.auth().await
|
||||
|
||||
@@ -1039,18 +1039,8 @@ impl Session {
|
||||
.services
|
||||
.plugins_manager
|
||||
.plugins_for_config(&plugins_input)
|
||||
.await;
|
||||
// Cache changes from another process do not notify this session's hook runtime.
|
||||
if !self.hooks().matches_plugin_hooks(
|
||||
plugin_outcome.iter_effective_plugin_hook_sources(),
|
||||
plugin_outcome.iter_effective_plugin_hook_warnings(),
|
||||
) {
|
||||
// Keep the refresh state out of the enclosing turn-construction future.
|
||||
Box::pin(self.refresh_hooks(Arc::clone(
|
||||
&session_configuration.original_config_do_not_use,
|
||||
)))
|
||||
.await;
|
||||
}
|
||||
.await
|
||||
.without_plugins(&session_configuration.disabled_plugin_ids);
|
||||
let trusted_plugin_roots = TrustedPluginRoots::from_plugin_load_outcome(
|
||||
&plugin_outcome,
|
||||
per_turn_config.codex_home.as_path(),
|
||||
|
||||
Reference in new issue
Block a user