Files
Anthony Tafoya f7a135ec61 Reconcile V2 executor plugins with cloud catalogs (#55301)
## What changed

- Use V2 discovery inventories for plugin MCP contributions when supplied, including empty or failed inventories; retain legacy discovery when no V2 snapshot is supplied.
- Merge plugins by canonical identity, using cloud metadata and enablement for remote plugins and attaching executor installations only when versions match. Preserve configured executor-local plugins and executor enablement when cloud data is unavailable.
- Keep installation order stable across refreshes and run merged MCP declarations on the first retained executor installation while preserving attribution for the others.
- Carry local and remote identities through selected-plugin snapshots, skill attribution, and active-plugin telemetry. Track disabled plugin IDs alongside disabled roots.
- Preserve a complete cloud catalog when a partial refresh arrives, and cap tool-description plugin attribution at 1,024 bytes while retaining all plugin associations.

## Testing

Add coverage for catalog parsing and reconciliation, enablement and discovery-mode selection, installation refresh ordering, executor-specific MCP normalization, selected-plugin snapshots, and bounded UTF-8 attribution text.

GitOrigin-RevId: a8ad352de6a2b8dc4bfd1ff6a5c62ee8ed1d1664
2026-10-19 15:15:17 +00:00

47 lines
1.7 KiB
Rust

//! Plugin catalog listing interface and source inputs used to request snapshots.
use crate::ExecutorPluginProviderError;
use crate::PluginCatalog;
use codex_exec_server::ExecutorCapabilityDiscoveryV2Snapshot;
use codex_mcp::McpResourceClient;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
use thiserror::Error;
/// Identifiers, MCP client, and executor inventories used to request one catalog snapshot.
#[derive(Clone, Debug)]
pub struct PluginListQuery {
pub thread_id: String,
pub turn_id: String,
pub mcp_resources: Option<Arc<McpResourceClient>>,
/// Already-acquired V2 inventories; empty for cloud listing.
pub snapshots: Vec<ExecutorCapabilityDiscoveryV2Snapshot>,
}
/// Failure to list plugin metadata.
#[derive(Debug, Error)]
pub enum PluginProviderError {
#[error(transparent)]
Executor(#[from] ExecutorPluginProviderError),
#[error("{0}")]
Message(String),
}
pub type PluginProviderResult<T> = Result<T, PluginProviderError>;
pub type PluginProviderFuture<'a, T> =
Pin<Box<dyn Future<Output = PluginProviderResult<T>> + Send + 'a>>;
/// Lists plugin metadata without resolving packages or binding filesystems.
///
/// Cloud providers implement `list`; executor listing is not yet supported.
/// Package access uses [`crate::ExecutorPluginProvider::resolve_bound`] directly.
pub trait PluginProvider: Send + Sync {
/// Returns a snapshot; on error, callers retain the previous snapshot.
/// Providers set `is_partial` when listing omits entries; warnings are diagnostic only.
fn list(&self, _query: PluginListQuery) -> PluginProviderFuture<'_, PluginCatalog> {
Box::pin(async { Ok(PluginCatalog::default()) })
}
}