feat: load from plugins (#12864)

Support loading plugins.

Plugins can now be enabled via [plugins.<name>] in config.toml. They are
loaded as first-class entities through PluginsManager, and their default
skills/ and .mcp.json contributions are integrated into the existing
skills and MCP flows.
This commit is contained in:
xl-openai
2026-03-01 10:50:56 -08:00
committed by GitHub
parent 6a673e7339
commit 752402c4fe
24 changed files with 1389 additions and 113 deletions

View File

@@ -173,8 +173,8 @@ use crate::file_watcher::FileWatcherEvent;
use crate::git_info::get_git_repo_root;
use crate::instructions::UserInstructions;
use crate::mcp::CODEX_APPS_MCP_SERVER_NAME;
use crate::mcp::McpManager;
use crate::mcp::auth::compute_auth_statuses;
use crate::mcp::effective_mcp_servers;
use crate::mcp::maybe_prompt_and_install_mcp_dependencies;
use crate::mcp::with_codex_apps_mcp;
use crate::mcp_connection_manager::McpConnectionManager;
@@ -188,6 +188,7 @@ use crate::mentions::build_skill_name_counts;
use crate::mentions::collect_explicit_app_ids;
use crate::mentions::collect_tool_mentions_from_messages;
use crate::network_policy_decision::execpolicy_network_rule_amendment;
use crate::plugins::PluginsManager;
use crate::project_doc::get_user_instructions;
use crate::protocol::AgentMessageContentDeltaEvent;
use crate::protocol::AgentReasoningSectionBreakEvent;
@@ -322,6 +323,8 @@ impl Codex {
auth_manager: Arc<AuthManager>,
models_manager: Arc<ModelsManager>,
skills_manager: Arc<SkillsManager>,
plugins_manager: Arc<PluginsManager>,
mcp_manager: Arc<McpManager>,
file_watcher: Arc<FileWatcher>,
conversation_history: InitialHistory,
session_source: SessionSource,
@@ -333,6 +336,7 @@ impl Codex {
let (tx_sub, rx_sub) = async_channel::bounded(SUBMISSION_CHANNEL_CAPACITY);
let (tx_event, rx_event) = async_channel::unbounded();
plugins_manager.plugins_for_config(&config);
let loaded_skills = skills_manager.skills_for_config(&config);
for err in &loaded_skills.errors {
@@ -476,6 +480,8 @@ impl Codex {
conversation_history,
session_source_clone,
skills_manager,
plugins_manager,
mcp_manager,
file_watcher,
agent_control,
)
@@ -1118,6 +1124,8 @@ impl Session {
initial_history: InitialHistory,
session_source: SessionSource,
skills_manager: Arc<SkillsManager>,
plugins_manager: Arc<PluginsManager>,
mcp_manager: Arc<McpManager>,
file_watcher: Arc<FileWatcher>,
agent_control: AgentControl,
) -> anyhow::Result<Arc<Self>> {
@@ -1209,9 +1217,10 @@ impl Session {
};
let auth_manager_clone = Arc::clone(&auth_manager);
let config_for_mcp = Arc::clone(&config);
let mcp_manager_for_mcp = Arc::clone(&mcp_manager);
let auth_and_mcp_fut = async move {
let auth = auth_manager_clone.auth().await;
let mcp_servers = effective_mcp_servers(&config_for_mcp, auth.as_ref());
let mcp_servers = mcp_manager_for_mcp.effective_servers(&config_for_mcp, auth.as_ref());
let auth_statuses = compute_auth_statuses(
mcp_servers.iter(),
config_for_mcp.mcp_oauth_credentials_store_mode,
@@ -1461,6 +1470,8 @@ impl Session {
tool_approvals: Mutex::new(ApprovalStore::default()),
execve_session_approvals: RwLock::new(HashMap::new()),
skills_manager,
plugins_manager,
mcp_manager,
file_watcher,
agent_control,
network_proxy,
@@ -2235,6 +2246,8 @@ impl Session {
.config_layer_stack
.with_user_config(&config_toml_path, user_config);
state.session_configuration.original_config_do_not_use = Arc::new(config);
self.services.skills_manager.clear_cache();
self.services.plugins_manager.clear_cache();
}
pub(crate) async fn new_default_turn_with_sub_id(&self, sub_id: String) -> Arc<TurnContext> {
@@ -3728,7 +3741,6 @@ mod handlers {
use crate::mcp::auth::compute_auth_statuses;
use crate::mcp::collect_mcp_snapshot_from_manager;
use crate::mcp::effective_mcp_servers;
use crate::review_prompts::resolve_review_request;
use crate::rollout::session_index;
use crate::tasks::CompactTask;
@@ -4058,7 +4070,10 @@ mod handlers {
pub async fn list_mcp_tools(sess: &Session, config: &Arc<Config>, sub_id: String) {
let mcp_connection_manager = sess.services.mcp_connection_manager.read().await;
let auth = sess.services.auth_manager.auth().await;
let mcp_servers = effective_mcp_servers(config, auth.as_ref());
let mcp_servers = sess
.services
.mcp_manager
.effective_servers(config, auth.as_ref());
let snapshot = collect_mcp_snapshot_from_manager(
&mcp_connection_manager,
compute_auth_statuses(mcp_servers.iter(), config.mcp_oauth_credentials_store_mode)
@@ -8057,6 +8072,12 @@ mod tests {
let (tx_event, _rx_event) = async_channel::unbounded();
let (agent_status_tx, _agent_status_rx) = watch::channel(AgentStatus::PendingInit);
let plugins_manager = Arc::new(PluginsManager::new(config.codex_home.clone()));
let mcp_manager = Arc::new(McpManager::new(Arc::clone(&plugins_manager)));
let skills_manager = Arc::new(SkillsManager::new(
config.codex_home.clone(),
Arc::clone(&plugins_manager),
));
let result = Session::new(
session_configuration,
Arc::clone(&config),
@@ -8067,7 +8088,9 @@ mod tests {
agent_status_tx,
InitialHistory::New,
SessionSource::Exec,
Arc::new(SkillsManager::new(config.codex_home.clone())),
skills_manager,
plugins_manager,
mcp_manager,
Arc::new(FileWatcher::noop()),
AgentControl::default(),
)
@@ -8149,7 +8172,12 @@ mod tests {
);
let state = SessionState::new(session_configuration.clone());
let skills_manager = Arc::new(SkillsManager::new(config.codex_home.clone()));
let plugins_manager = Arc::new(PluginsManager::new(config.codex_home.clone()));
let mcp_manager = Arc::new(McpManager::new(Arc::clone(&plugins_manager)));
let skills_manager = Arc::new(SkillsManager::new(
config.codex_home.clone(),
Arc::clone(&plugins_manager),
));
let network_approval = Arc::new(NetworkApprovalService::default());
let file_watcher = Arc::new(FileWatcher::noop());
@@ -8183,6 +8211,8 @@ mod tests {
tool_approvals: Mutex::new(ApprovalStore::default()),
execve_session_approvals: RwLock::new(HashMap::new()),
skills_manager,
plugins_manager,
mcp_manager,
file_watcher,
agent_control,
network_proxy: None,
@@ -8309,7 +8339,12 @@ mod tests {
);
let state = SessionState::new(session_configuration.clone());
let skills_manager = Arc::new(SkillsManager::new(config.codex_home.clone()));
let plugins_manager = Arc::new(PluginsManager::new(config.codex_home.clone()));
let mcp_manager = Arc::new(McpManager::new(Arc::clone(&plugins_manager)));
let skills_manager = Arc::new(SkillsManager::new(
config.codex_home.clone(),
Arc::clone(&plugins_manager),
));
let network_approval = Arc::new(NetworkApprovalService::default());
let file_watcher = Arc::new(FileWatcher::noop());
@@ -8343,6 +8378,8 @@ mod tests {
tool_approvals: Mutex::new(ApprovalStore::default()),
execve_session_approvals: RwLock::new(HashMap::new()),
skills_manager,
plugins_manager,
mcp_manager,
file_watcher,
agent_control,
network_proxy: None,