mirror of
https://github.com/openai/codex.git
synced 2026-10-20 17:38:45 +00:00
## What changed - Return qualified skill names such as `team:deploy` and parsed `dependencies` and `policy` instead of a separate namespace and raw metadata file. Share `agents/openai.yaml` parsing and validation between skill loaders and executor discovery. - Include each standalone skill's search-root ID and path in `discoveryRoot`, while accepting responses from older executors that omit it. - Add plugin `displayName`, falling back to the manifest name or installation directory. - Materialize inline MCP declarations in `mcpConfig` with the manifest as their source path, and report incomplete discovery when declared MCP or Apps configuration files have no returned contents. ## Testing Add coverage for JSON round trips, omitted `discoveryRoot`, optional and invalid skill metadata, qualified names, display-name fallbacks, and inline MCP configuration. Verify standalone search roots survive cached discovery and sandboxed RPC responses. GitOrigin-RevId: 4124972444ad7c2fb8c6418acbf9a589d797fad2
119 lines
3.9 KiB
Rust
119 lines
3.9 KiB
Rust
//! Executor capability inventory; callers apply identity and enablement.
|
|
|
|
use codex_file_system::FileSystemSandboxContext;
|
|
use codex_skills::SkillDependencies;
|
|
use codex_skills::SkillPolicy;
|
|
use codex_utils_path_uri::PathUri;
|
|
use serde::Deserialize;
|
|
use serde::Serialize;
|
|
use std::fmt;
|
|
use std::sync::Arc;
|
|
|
|
use crate::DiscoveredPluginFiles;
|
|
|
|
pub const CAPABILITIES_DISCOVER_V2_METHOD: &str = "capabilities/discoverV2";
|
|
|
|
/// Caller-bound discovery result shared by capability consumers within a model step.
|
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
pub struct ExecutorCapabilityDiscoveryV2Snapshot {
|
|
pub environment_id: String,
|
|
pub result: Result<Arc<DiscoverV2CapabilitiesResponse>, String>,
|
|
}
|
|
|
|
/// Discover installed capabilities for a thread, without client-supplied installation paths.
|
|
#[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,
|
|
/// Manifest display name, falling back to its name or the installation directory.
|
|
pub display_name: String,
|
|
pub remote_plugin_id: Option<String>,
|
|
pub version: String,
|
|
pub root: PathUri,
|
|
pub files: DiscoveredPluginFiles,
|
|
pub skills: Vec<ExecutorSkill>,
|
|
}
|
|
|
|
/// Executor-owned search root for a standalone skill.
|
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct SkillDiscoveryRoot {
|
|
pub id: String,
|
|
pub path: PathUri,
|
|
}
|
|
|
|
/// Skill metadata, excluding instructions and resources.
|
|
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
|
#[serde(rename_all = "camelCase")]
|
|
pub struct ExecutorSkill {
|
|
/// Final skill name, qualified by the nearest enclosing plugin namespace when present.
|
|
pub name: String,
|
|
pub description: String,
|
|
#[serde(default)]
|
|
pub short_description: Option<String>,
|
|
/// Path to SKILL.md, not its containing directory.
|
|
pub path: PathUri,
|
|
/// Absent for plugin skills and responses from older executors.
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
pub discovery_root: Option<SkillDiscoveryRoot>,
|
|
pub dependencies: Option<SkillDependencies>,
|
|
pub policy: Option<SkillPolicy>,
|
|
}
|
|
|
|
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("path", &self.path)
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
#[path = "capabilities_tests.rs"]
|
|
mod tests;
|