mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## What changed - Define `capabilities/discoverV2` request and inventory types and advertise `capabilityDiscoveryV2` in executor metadata. - Prewarm installed plugin and global skill locations at server startup, with nonfatal scan failures. - Add sandbox-scoped discovery caching with file watcher invalidation and request-time reloads when watching is unavailable. - Batch metadata reads through the filesystem sandbox helper and bound discovery responses to 4 MiB and 2,048 capabilities. - Share plugin identity and installed-version selection in `codex-core-plugin-common`, and fall back to `.app.json` when a plugin does not declare an apps configuration. The V2 discovery manager is not yet wired into RPC request dispatch. ## Testing Add coverage for inventory metadata, sandbox cache isolation, watcher invalidation, startup scan failures, response limits, and compatibility with older executor metadata. GitOrigin-RevId: a223a5bc15fdf251023c0c71f468fd92c3b2d847
103 lines
3.2 KiB
Rust
103 lines
3.2 KiB
Rust
//! Executor capability inventory; callers apply identity and enablement.
|
|
|
|
use codex_file_system::FileSystemSandboxContext;
|
|
use codex_utils_path_uri::PathUri;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::fmt;
|
|
|
|
use crate::CapabilityTextFile;
|
|
use crate::DiscoveredPluginFiles;
|
|
|
|
pub const CAPABILITIES_DISCOVER_V2_METHOD: &str = "capabilities/discoverV2";
|
|
|
|
/// Discovers installed capabilities on the executor.
|
|
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct DiscoverV2CapabilitiesRequest {
|
|
pub cwd: PathUri,
|
|
#[serde(default)]
|
|
pub sandbox: Option<FileSystemSandboxContext>,
|
|
}
|
|
|
|
/// Discovered metadata before caller policy is applied.
|
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct DiscoverV2CapabilitiesResponse {
|
|
pub plugins: Vec<ExecutorPlugin>,
|
|
/// Skills outside installed packages.
|
|
pub skills: Vec<ExecutorSkill>,
|
|
#[serde(default)]
|
|
pub warnings: Vec<String>,
|
|
}
|
|
|
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecutorPlugin {
|
|
/// Environment-local ID: `<name>@<marketplace>`.
|
|
pub id: String,
|
|
pub remote_plugin_id: Option<String>,
|
|
pub version: String,
|
|
pub root: PathUri,
|
|
pub files: DiscoveredPluginFiles,
|
|
pub skills: Vec<ExecutorSkill>,
|
|
}
|
|
|
|
/// Skill metadata, excluding instructions and resources.
|
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecutorSkill {
|
|
pub name: String,
|
|
/// Nearest enclosing legacy plugin's name, following V1 precedence.
|
|
#[serde(default)]
|
|
pub namespace: Option<String>,
|
|
pub description: String,
|
|
#[serde(default)]
|
|
pub short_description: Option<String>,
|
|
/// Path to SKILL.md, not its containing directory.
|
|
pub path: PathUri,
|
|
pub metadata: Option<CapabilityTextFile>,
|
|
}
|
|
|
|
impl fmt::Debug for ExecutorPlugin {
|
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
formatter
|
|
.debug_struct("ExecutorPlugin")
|
|
.field("id", &self.id)
|
|
.field("remote_plugin_id", &self.remote_plugin_id)
|
|
.field("version", &self.version)
|
|
.field("root", &self.root)
|
|
.field("manifest_path", &self.files.manifest.path)
|
|
.field(
|
|
"mcp_config_path",
|
|
&self.files.mcp_config.as_ref().map(|file| &file.path),
|
|
)
|
|
.field(
|
|
"apps_config_path",
|
|
&self.files.apps_config.as_ref().map(|file| &file.path),
|
|
)
|
|
.field("skills", &self.skills)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl fmt::Debug for ExecutorSkill {
|
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
// Omit potentially sensitive descriptions and file contents.
|
|
formatter
|
|
.debug_struct("ExecutorSkill")
|
|
.field("name", &self.name)
|
|
.field("namespace", &self.namespace)
|
|
.field("path", &self.path)
|
|
.field(
|
|
"metadata_path",
|
|
&self.metadata.as_ref().map(|file| &file.path),
|
|
)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "capabilities_tests.rs"]
|
|
mod tests;
|