mirror of
https://github.com/openai/codex.git
synced 2026-11-13 14:46:14 +00:00
Move shared skill models into codex-skills (#34429)
## What changed - Define and export skill metadata, policy, dependency, interface, and configuration rule types from `codex-skills`. - Update core, plugin, and extension consumers to use the shared models while retaining compatibility re-exports from `codex-core-skills`. - Share product-restriction handling between host and environment skill metadata. ## Testing - Add unit coverage for default and explicit implicit-invocation and product policies. GitOrigin-RevId: 9093469f8fff8e2d902dc9781235f64709827a87
This commit is contained in:
1 parent
35c2278dd5
commit
56c11cf658
20 files changed
+206
-133
No files matched your search
Generated
+5
@@ -2665,6 +2665,7 @@ dependencies = [
|
|||||||
"codex-sandboxing",
|
"codex-sandboxing",
|
||||||
"codex-shell-command",
|
"codex-shell-command",
|
||||||
"codex-shell-escalation",
|
"codex-shell-escalation",
|
||||||
|
"codex-skills",
|
||||||
"codex-state",
|
"codex-state",
|
||||||
"codex-terminal-detection",
|
"codex-terminal-detection",
|
||||||
"codex-test-binary-support",
|
"codex-test-binary-support",
|
||||||
@@ -2777,6 +2778,7 @@ dependencies = [
|
|||||||
"codex-otel",
|
"codex-otel",
|
||||||
"codex-plugin",
|
"codex-plugin",
|
||||||
"codex-protocol",
|
"codex-protocol",
|
||||||
|
"codex-skills",
|
||||||
"codex-tools",
|
"codex-tools",
|
||||||
"codex-utils-absolute-path",
|
"codex-utils-absolute-path",
|
||||||
"codex-utils-path",
|
"codex-utils-path",
|
||||||
@@ -3950,7 +3952,9 @@ dependencies = [
|
|||||||
name = "codex-skills"
|
name = "codex-skills"
|
||||||
version = "0.0.0"
|
version = "0.0.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"codex-protocol",
|
||||||
"codex-utils-absolute-path",
|
"codex-utils-absolute-path",
|
||||||
|
"codex-utils-path-uri",
|
||||||
"include_dir",
|
"include_dir",
|
||||||
"thiserror 2.0.18",
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
@@ -3965,6 +3969,7 @@ dependencies = [
|
|||||||
"codex-mcp",
|
"codex-mcp",
|
||||||
"codex-otel",
|
"codex-otel",
|
||||||
"codex-protocol",
|
"codex-protocol",
|
||||||
|
"codex-skills",
|
||||||
"codex-tools",
|
"codex-tools",
|
||||||
"codex-utils-absolute-path",
|
"codex-utils-absolute-path",
|
||||||
"codex-utils-path-uri",
|
"codex-utils-path-uri",
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ codex-model-provider = { workspace = true }
|
|||||||
codex-otel = { workspace = true }
|
codex-otel = { workspace = true }
|
||||||
codex-plugin = { workspace = true }
|
codex-plugin = { workspace = true }
|
||||||
codex-protocol = { workspace = true }
|
codex-protocol = { workspace = true }
|
||||||
|
codex-skills = { workspace = true }
|
||||||
codex-tools = { workspace = true }
|
codex-tools = { workspace = true }
|
||||||
codex-utils-absolute-path = { workspace = true }
|
codex-utils-absolute-path = { workspace = true }
|
||||||
codex-utils-path = { workspace = true }
|
codex-utils-path = { workspace = true }
|
||||||
|
|||||||
@@ -26,8 +26,6 @@ use codex_config::types::PluginMcpServerConfig;
|
|||||||
use codex_connectors::parse_plugin_app_config;
|
use codex_connectors::parse_plugin_app_config;
|
||||||
use codex_connectors::parse_plugin_app_config_value;
|
use codex_connectors::parse_plugin_app_config_value;
|
||||||
use codex_core_skills::PluginSkillSnapshots;
|
use codex_core_skills::PluginSkillSnapshots;
|
||||||
use codex_core_skills::SkillMetadata;
|
|
||||||
use codex_core_skills::config_rules::SkillConfigRules;
|
|
||||||
use codex_core_skills::config_rules::resolve_disabled_skill_paths;
|
use codex_core_skills::config_rules::resolve_disabled_skill_paths;
|
||||||
use codex_core_skills::config_rules::skill_config_rules_from_stack;
|
use codex_core_skills::config_rules::skill_config_rules_from_stack;
|
||||||
use codex_core_skills::loader::SkillRoot;
|
use codex_core_skills::loader::SkillRoot;
|
||||||
@@ -44,6 +42,8 @@ use codex_plugin::app_connector_ids_from_declarations;
|
|||||||
use codex_protocol::auth::AuthMode;
|
use codex_protocol::auth::AuthMode;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
use codex_protocol::protocol::SkillScope;
|
use codex_protocol::protocol::SkillScope;
|
||||||
|
use codex_skills::SkillConfigRules;
|
||||||
|
use codex_skills::SkillMetadata;
|
||||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
use codex_utils_plugins::find_plugin_manifest_path;
|
use codex_utils_plugins::find_plugin_manifest_path;
|
||||||
use serde_json::Value as JsonValue;
|
use serde_json::Value as JsonValue;
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ use codex_config::types::PluginConfig;
|
|||||||
use codex_config::types::ToolSuggestDisabledTool;
|
use codex_config::types::ToolSuggestDisabledTool;
|
||||||
use codex_config::types::ToolSuggestDiscoverableType;
|
use codex_config::types::ToolSuggestDiscoverableType;
|
||||||
use codex_core_skills::PluginSkillSnapshots;
|
use codex_core_skills::PluginSkillSnapshots;
|
||||||
use codex_core_skills::SkillMetadata;
|
|
||||||
use codex_core_skills::config_rules::SkillConfigRules;
|
|
||||||
use codex_core_skills::config_rules::skill_config_rules_from_stack;
|
use codex_core_skills::config_rules::skill_config_rules_from_stack;
|
||||||
use codex_core_skills::loader::MAX_CONCURRENT_ROOT_SCANS;
|
use codex_core_skills::loader::MAX_CONCURRENT_ROOT_SCANS;
|
||||||
use codex_hooks::plugin_hook_declarations;
|
use codex_hooks::plugin_hook_declarations;
|
||||||
@@ -84,6 +82,8 @@ use codex_plugin::prompt_safe_plugin_description;
|
|||||||
use codex_protocol::auth::AuthMode;
|
use codex_protocol::auth::AuthMode;
|
||||||
use codex_protocol::protocol::HookEventName;
|
use codex_protocol::protocol::HookEventName;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
|
use codex_skills::SkillConfigRules;
|
||||||
|
use codex_skills::SkillMetadata;
|
||||||
use codex_tools::DiscoverablePluginInfo;
|
use codex_tools::DiscoverablePluginInfo;
|
||||||
use codex_tools::DiscoverableTool;
|
use codex_tools::DiscoverableTool;
|
||||||
use codex_tools::filter_request_plugin_install_discoverable_tools_for_client;
|
use codex_tools::filter_request_plugin_install_discoverable_tools_for_client;
|
||||||
|
|||||||
@@ -42,13 +42,13 @@ use codex_config::types::McpServerTransportConfig;
|
|||||||
use codex_core_skills::PluginSkillSnapshots;
|
use codex_core_skills::PluginSkillSnapshots;
|
||||||
use codex_core_skills::SkillsLoadInput;
|
use codex_core_skills::SkillsLoadInput;
|
||||||
use codex_core_skills::SkillsService;
|
use codex_core_skills::SkillsService;
|
||||||
use codex_core_skills::config_rules::SkillConfigRules;
|
|
||||||
use codex_login::CodexAuth;
|
use codex_login::CodexAuth;
|
||||||
use codex_plugin::AppDeclaration;
|
use codex_plugin::AppDeclaration;
|
||||||
use codex_plugin::PluginId;
|
use codex_plugin::PluginId;
|
||||||
use codex_protocol::auth::AuthMode;
|
use codex_protocol::auth::AuthMode;
|
||||||
use codex_protocol::protocol::HookEventName;
|
use codex_protocol::protocol::HookEventName;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
|
use codex_skills::SkillConfigRules;
|
||||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||||
use pretty_assertions::assert_eq;
|
use pretty_assertions::assert_eq;
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ use std::collections::HashMap;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::sync::RwLock;
|
use std::sync::RwLock;
|
||||||
|
|
||||||
use codex_core_skills::config_rules::SkillConfigRules;
|
|
||||||
use codex_plugin::AppDeclaration;
|
use codex_plugin::AppDeclaration;
|
||||||
use codex_plugin::PluginCapabilitySummary;
|
use codex_plugin::PluginCapabilitySummary;
|
||||||
use codex_plugin::PluginId;
|
use codex_plugin::PluginId;
|
||||||
@@ -11,6 +10,7 @@ use codex_plugin::app_connector_ids_from_declarations;
|
|||||||
use codex_plugin::prompt_safe_plugin_description;
|
use codex_plugin::prompt_safe_plugin_description;
|
||||||
use codex_protocol::auth::AuthMode;
|
use codex_protocol::auth::AuthMode;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
|
use codex_skills::SkillConfigRules;
|
||||||
use tokio::sync::Semaphore;
|
use tokio::sync::Semaphore;
|
||||||
|
|
||||||
use crate::app_mcp_routing::apply_app_mcp_routing_policy;
|
use crate::app_mcp_routing::apply_app_mcp_routing_policy;
|
||||||
|
|||||||
@@ -5,28 +5,14 @@ use codex_config::ConfigLayerStack;
|
|||||||
use codex_config::ConfigLayerStackOrdering;
|
use codex_config::ConfigLayerStackOrdering;
|
||||||
use codex_config::SkillConfig;
|
use codex_config::SkillConfig;
|
||||||
use codex_config::SkillsConfig;
|
use codex_config::SkillsConfig;
|
||||||
|
pub use codex_skills::SkillConfigRule;
|
||||||
|
pub use codex_skills::SkillConfigRuleSelector;
|
||||||
|
pub use codex_skills::SkillConfigRules;
|
||||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::SkillMetadata;
|
use crate::SkillMetadata;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
|
||||||
pub enum SkillConfigRuleSelector {
|
|
||||||
Name(String),
|
|
||||||
Path(AbsolutePathBuf),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
||||||
pub struct SkillConfigRule {
|
|
||||||
pub selector: SkillConfigRuleSelector,
|
|
||||||
pub enabled: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
|
|
||||||
pub struct SkillConfigRules {
|
|
||||||
pub entries: Vec<SkillConfigRule>,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn skill_config_rules_from_stack(config_layer_stack: &ConfigLayerStack) -> SkillConfigRules {
|
pub fn skill_config_rules_from_stack(config_layer_stack: &ConfigLayerStack) -> SkillConfigRules {
|
||||||
let mut entries = Vec::new();
|
let mut entries = Vec::new();
|
||||||
for layer in config_layer_stack.get_layers(
|
for layer in config_layer_stack.get_layers(
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use std::io;
|
|||||||
use codex_exec_server::CapabilityRootDiscovery;
|
use codex_exec_server::CapabilityRootDiscovery;
|
||||||
use codex_exec_server::ExecutorFileSystem;
|
use codex_exec_server::ExecutorFileSystem;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
|
pub use codex_skills::EnvironmentSkillMetadata;
|
||||||
use codex_utils_path_uri::PathUri;
|
use codex_utils_path_uri::PathUri;
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
|
|
||||||
@@ -36,17 +37,6 @@ struct ParsedEnvironmentSkill {
|
|||||||
policy: Option<SkillPolicy>,
|
policy: Option<SkillPolicy>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// URI-native metadata for one skill owned by an execution environment.
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
|
||||||
pub struct EnvironmentSkillMetadata {
|
|
||||||
pub path_to_skills_md: PathUri,
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub short_description: Option<String>,
|
|
||||||
pub dependencies: Option<SkillDependencies>,
|
|
||||||
pub policy: Option<SkillPolicy>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parsed executor skill plus the instructions already materialized by capability discovery.
|
/// Parsed executor skill plus the instructions already materialized by capability discovery.
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct EnvironmentSkillSnapshot {
|
pub struct EnvironmentSkillSnapshot {
|
||||||
@@ -60,27 +50,6 @@ pub struct EnvironmentSkillSnapshotOutcome {
|
|||||||
pub warnings: Vec<String>,
|
pub warnings: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EnvironmentSkillMetadata {
|
|
||||||
pub fn allows_implicit_invocation(&self) -> bool {
|
|
||||||
self.policy
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|policy| policy.allow_implicit_invocation)
|
|
||||||
.unwrap_or(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn matches_product_restriction(&self, restriction_product: Option<Product>) -> bool {
|
|
||||||
match &self.policy {
|
|
||||||
Some(policy) => {
|
|
||||||
policy.products.is_empty()
|
|
||||||
|| restriction_product.is_some_and(|product| {
|
|
||||||
product.matches_product_restriction(&policy.products)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ParsedEnvironmentSkill {
|
impl ParsedEnvironmentSkill {
|
||||||
async fn load(
|
async fn load(
|
||||||
file_system: &dyn ExecutorFileSystem,
|
file_system: &dyn ExecutorFileSystem,
|
||||||
|
|||||||
@@ -7,81 +7,14 @@ use std::sync::Arc;
|
|||||||
use codex_exec_server::ExecutorFileSystem;
|
use codex_exec_server::ExecutorFileSystem;
|
||||||
use codex_exec_server::LOCAL_FS;
|
use codex_exec_server::LOCAL_FS;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
use codex_protocol::protocol::SkillScope;
|
pub use codex_skills::SkillDependencies;
|
||||||
|
pub use codex_skills::SkillInterface;
|
||||||
|
pub use codex_skills::SkillMetadata;
|
||||||
|
pub use codex_skills::SkillPolicy;
|
||||||
|
pub use codex_skills::SkillToolDependency;
|
||||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
use codex_utils_path_uri::PathUri;
|
use codex_utils_path_uri::PathUri;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
pub struct SkillMetadata {
|
|
||||||
pub name: String,
|
|
||||||
pub description: String,
|
|
||||||
pub short_description: Option<String>,
|
|
||||||
pub interface: Option<SkillInterface>,
|
|
||||||
pub dependencies: Option<SkillDependencies>,
|
|
||||||
pub policy: Option<SkillPolicy>,
|
|
||||||
/// Path to the SKILLS.md file that declares this skill.
|
|
||||||
pub path_to_skills_md: AbsolutePathBuf,
|
|
||||||
pub scope: SkillScope,
|
|
||||||
pub plugin_id: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SkillMetadata {
|
|
||||||
pub fn allows_implicit_invocation(&self) -> bool {
|
|
||||||
self.policy
|
|
||||||
.as_ref()
|
|
||||||
.and_then(|policy| policy.allow_implicit_invocation)
|
|
||||||
.unwrap_or(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn matches_product_restriction_for_product(
|
|
||||||
&self,
|
|
||||||
restriction_product: Option<Product>,
|
|
||||||
) -> bool {
|
|
||||||
match &self.policy {
|
|
||||||
Some(policy) => {
|
|
||||||
policy.products.is_empty()
|
|
||||||
|| restriction_product.is_some_and(|product| {
|
|
||||||
product.matches_product_restriction(&policy.products)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
None => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
|
||||||
pub struct SkillPolicy {
|
|
||||||
pub allow_implicit_invocation: Option<bool>,
|
|
||||||
// TODO: Enforce product gating in Codex skill selection/injection instead of only parsing and
|
|
||||||
// storing this metadata.
|
|
||||||
pub products: Vec<Product>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct SkillInterface {
|
|
||||||
pub display_name: Option<String>,
|
|
||||||
pub short_description: Option<String>,
|
|
||||||
pub icon_small: Option<AbsolutePathBuf>,
|
|
||||||
pub icon_large: Option<AbsolutePathBuf>,
|
|
||||||
pub brand_color: Option<String>,
|
|
||||||
pub default_prompt: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct SkillDependencies {
|
|
||||||
pub tools: Vec<SkillToolDependency>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub struct SkillToolDependency {
|
|
||||||
pub r#type: String,
|
|
||||||
pub value: String,
|
|
||||||
pub description: Option<String>,
|
|
||||||
pub transport: Option<String>,
|
|
||||||
pub command: Option<String>,
|
|
||||||
pub url: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct SkillError {
|
pub struct SkillError {
|
||||||
pub path: AbsolutePathBuf,
|
pub path: AbsolutePathBuf,
|
||||||
|
|||||||
@@ -63,6 +63,7 @@ codex-rollout = { workspace = true }
|
|||||||
codex-rollout-trace = { workspace = true }
|
codex-rollout-trace = { workspace = true }
|
||||||
codex-rmcp-client = { workspace = true }
|
codex-rmcp-client = { workspace = true }
|
||||||
codex-sandboxing = { workspace = true }
|
codex-sandboxing = { workspace = true }
|
||||||
|
codex-skills = { workspace = true }
|
||||||
codex-state = { workspace = true }
|
codex-state = { workspace = true }
|
||||||
codex-terminal-detection = { workspace = true }
|
codex-terminal-detection = { workspace = true }
|
||||||
codex-thread-store = { workspace = true }
|
codex-thread-store = { workspace = true }
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ use codex_utils_plugins::PluginSkillRoot;
|
|||||||
|
|
||||||
pub use codex_core_skills::SkillError;
|
pub use codex_core_skills::SkillError;
|
||||||
pub use codex_core_skills::SkillLoadOutcome;
|
pub use codex_core_skills::SkillLoadOutcome;
|
||||||
pub use codex_core_skills::SkillMetadata;
|
|
||||||
pub use codex_core_skills::SkillPolicy;
|
|
||||||
pub use codex_core_skills::SkillRenderReport;
|
pub use codex_core_skills::SkillRenderReport;
|
||||||
pub use codex_core_skills::SkillsLoadInput;
|
pub use codex_core_skills::SkillsLoadInput;
|
||||||
pub use codex_core_skills::SkillsService;
|
pub use codex_core_skills::SkillsService;
|
||||||
@@ -34,6 +32,8 @@ pub use codex_core_skills::render;
|
|||||||
pub use codex_core_skills::render::SkillRenderSideEffects;
|
pub use codex_core_skills::render::SkillRenderSideEffects;
|
||||||
pub use codex_core_skills::service;
|
pub use codex_core_skills::service;
|
||||||
pub use codex_core_skills::system;
|
pub use codex_core_skills::system;
|
||||||
|
pub use codex_skills::SkillMetadata;
|
||||||
|
pub use codex_skills::SkillPolicy;
|
||||||
|
|
||||||
pub(crate) fn skills_load_input_from_config(
|
pub(crate) fn skills_load_input_from_config(
|
||||||
config: &Config,
|
config: &Config,
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ codex-extension-api = { workspace = true }
|
|||||||
codex-mcp = { workspace = true }
|
codex-mcp = { workspace = true }
|
||||||
codex-otel = { workspace = true }
|
codex-otel = { workspace = true }
|
||||||
codex-protocol = { workspace = true }
|
codex-protocol = { workspace = true }
|
||||||
|
codex-skills = { workspace = true }
|
||||||
codex-tools = { workspace = true }
|
codex-tools = { workspace = true }
|
||||||
codex-utils-path-uri = { workspace = true }
|
codex-utils-path-uri = { workspace = true }
|
||||||
codex-utils-string = { workspace = true }
|
codex-utils-string = { workspace = true }
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use codex_core_skills::model::SkillDependencies;
|
use codex_skills::SkillDependencies;
|
||||||
use codex_utils_path_uri::PathUri;
|
use codex_utils_path_uri::PathUri;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use codex_core_skills::loader::EnvironmentSkillMetadata;
|
|
||||||
use codex_core_skills::loader::load_environment_skills_from_discovery;
|
use codex_core_skills::loader::load_environment_skills_from_discovery;
|
||||||
use codex_core_skills::loader::load_environment_skills_from_root;
|
use codex_core_skills::loader::load_environment_skills_from_root;
|
||||||
use codex_exec_server::EnvironmentManager;
|
use codex_exec_server::EnvironmentManager;
|
||||||
use codex_protocol::capabilities::CapabilityRootLocation;
|
use codex_protocol::capabilities::CapabilityRootLocation;
|
||||||
use codex_protocol::protocol::Product;
|
use codex_protocol::protocol::Product;
|
||||||
|
use codex_skills::EnvironmentSkillMetadata;
|
||||||
use codex_utils_path_uri::PathConvention;
|
use codex_utils_path_uri::PathConvention;
|
||||||
|
|
||||||
use crate::catalog::SkillAuthority;
|
use crate::catalog::SkillAuthority;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use codex_core_skills::SkillLoadOutcome;
|
use codex_core_skills::SkillLoadOutcome;
|
||||||
use codex_core_skills::SkillMetadata;
|
use codex_skills::SkillMetadata;
|
||||||
|
|
||||||
use crate::catalog::SkillAuthority;
|
use crate::catalog::SkillAuthority;
|
||||||
use crate::catalog::SkillCatalog;
|
use crate::catalog::SkillCatalog;
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ use std::sync::atomic::Ordering;
|
|||||||
use codex_core_skills::HostSkillsSnapshot;
|
use codex_core_skills::HostSkillsSnapshot;
|
||||||
use codex_core_skills::SKILLS_INTRO_WITH_ABSOLUTE_PATHS;
|
use codex_core_skills::SKILLS_INTRO_WITH_ABSOLUTE_PATHS;
|
||||||
use codex_core_skills::SkillLoadOutcome;
|
use codex_core_skills::SkillLoadOutcome;
|
||||||
use codex_core_skills::SkillMetadata;
|
|
||||||
use codex_core_skills::injection::InjectedHostSkillPrompts;
|
use codex_core_skills::injection::InjectedHostSkillPrompts;
|
||||||
use codex_extension_api::ConversationHistory;
|
use codex_extension_api::ConversationHistory;
|
||||||
use codex_extension_api::ExtensionData;
|
use codex_extension_api::ExtensionData;
|
||||||
@@ -31,6 +30,7 @@ use codex_protocol::protocol::SkillScope;
|
|||||||
use codex_protocol::protocol::TruncationPolicy;
|
use codex_protocol::protocol::TruncationPolicy;
|
||||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||||
use codex_protocol::user_input::UserInput;
|
use codex_protocol::user_input::UserInput;
|
||||||
|
use codex_skills::SkillMetadata;
|
||||||
use codex_skills_extension::SkillProviders;
|
use codex_skills_extension::SkillProviders;
|
||||||
use codex_skills_extension::SkillsExtensionConfig;
|
use codex_skills_extension::SkillsExtensionConfig;
|
||||||
use codex_skills_extension::catalog::SkillAuthority;
|
use codex_skills_extension::catalog::SkillAuthority;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ path = "src/lib.rs"
|
|||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
codex-protocol = { workspace = true }
|
||||||
codex-utils-absolute-path = { workspace = true }
|
codex-utils-absolute-path = { workspace = true }
|
||||||
|
codex-utils-path-uri = { workspace = true }
|
||||||
include_dir = { workspace = true }
|
include_dir = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
@@ -1,3 +1,15 @@
|
|||||||
|
mod model;
|
||||||
|
|
||||||
|
pub use model::EnvironmentSkillMetadata;
|
||||||
|
pub use model::SkillConfigRule;
|
||||||
|
pub use model::SkillConfigRuleSelector;
|
||||||
|
pub use model::SkillConfigRules;
|
||||||
|
pub use model::SkillDependencies;
|
||||||
|
pub use model::SkillInterface;
|
||||||
|
pub use model::SkillMetadata;
|
||||||
|
pub use model::SkillPolicy;
|
||||||
|
pub use model::SkillToolDependency;
|
||||||
|
|
||||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
use include_dir::Dir;
|
use include_dir::Dir;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
|
|||||||
@@ -0,0 +1,127 @@
|
|||||||
|
use codex_protocol::protocol::Product;
|
||||||
|
use codex_protocol::protocol::SkillScope;
|
||||||
|
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||||
|
use codex_utils_path_uri::PathUri;
|
||||||
|
|
||||||
|
/// Metadata for one skill materialized on the host filesystem.
|
||||||
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
|
pub struct SkillMetadata {
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub short_description: Option<String>,
|
||||||
|
pub interface: Option<SkillInterface>,
|
||||||
|
pub dependencies: Option<SkillDependencies>,
|
||||||
|
pub policy: Option<SkillPolicy>,
|
||||||
|
/// Path to the SKILL.md file that declares this skill.
|
||||||
|
pub path_to_skills_md: AbsolutePathBuf,
|
||||||
|
pub scope: SkillScope,
|
||||||
|
pub plugin_id: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SkillMetadata {
|
||||||
|
pub fn allows_implicit_invocation(&self) -> bool {
|
||||||
|
self.policy
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|policy| policy.allow_implicit_invocation)
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn matches_product_restriction_for_product(
|
||||||
|
&self,
|
||||||
|
restriction_product: Option<Product>,
|
||||||
|
) -> bool {
|
||||||
|
matches_product_restriction(self.policy.as_ref(), restriction_product)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// URI-native metadata for one skill owned by an execution environment.
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
|
pub struct EnvironmentSkillMetadata {
|
||||||
|
pub path_to_skills_md: PathUri,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub short_description: Option<String>,
|
||||||
|
pub dependencies: Option<SkillDependencies>,
|
||||||
|
pub policy: Option<SkillPolicy>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvironmentSkillMetadata {
|
||||||
|
pub fn allows_implicit_invocation(&self) -> bool {
|
||||||
|
self.policy
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|policy| policy.allow_implicit_invocation)
|
||||||
|
.unwrap_or(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn matches_product_restriction(&self, restriction_product: Option<Product>) -> bool {
|
||||||
|
matches_product_restriction(self.policy.as_ref(), restriction_product)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
|
pub struct SkillPolicy {
|
||||||
|
pub allow_implicit_invocation: Option<bool>,
|
||||||
|
// TODO: Enforce product gating in Codex skill selection/injection instead of only parsing and
|
||||||
|
// storing this metadata.
|
||||||
|
pub products: Vec<Product>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct SkillInterface {
|
||||||
|
pub display_name: Option<String>,
|
||||||
|
pub short_description: Option<String>,
|
||||||
|
pub icon_small: Option<AbsolutePathBuf>,
|
||||||
|
pub icon_large: Option<AbsolutePathBuf>,
|
||||||
|
pub brand_color: Option<String>,
|
||||||
|
pub default_prompt: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct SkillDependencies {
|
||||||
|
pub tools: Vec<SkillToolDependency>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub struct SkillToolDependency {
|
||||||
|
pub r#type: String,
|
||||||
|
pub value: String,
|
||||||
|
pub description: Option<String>,
|
||||||
|
pub transport: Option<String>,
|
||||||
|
pub command: Option<String>,
|
||||||
|
pub url: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||||
|
pub enum SkillConfigRuleSelector {
|
||||||
|
Name(String),
|
||||||
|
Path(AbsolutePathBuf),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SkillConfigRule {
|
||||||
|
pub selector: SkillConfigRuleSelector,
|
||||||
|
pub enabled: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
|
||||||
|
pub struct SkillConfigRules {
|
||||||
|
pub entries: Vec<SkillConfigRule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn matches_product_restriction(
|
||||||
|
policy: Option<&SkillPolicy>,
|
||||||
|
restriction_product: Option<Product>,
|
||||||
|
) -> bool {
|
||||||
|
match policy {
|
||||||
|
Some(policy) => {
|
||||||
|
policy.products.is_empty()
|
||||||
|
|| restriction_product
|
||||||
|
.is_some_and(|product| product.matches_product_restriction(&policy.products))
|
||||||
|
}
|
||||||
|
None => true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
#[path = "model_tests.rs"]
|
||||||
|
mod tests;
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn missing_policy_allows_implicit_invocation_and_all_products() {
|
||||||
|
let skill = EnvironmentSkillMetadata {
|
||||||
|
path_to_skills_md: PathUri::parse("file:///skills/demo/SKILL.md").expect("valid skill URI"),
|
||||||
|
name: "demo".to_string(),
|
||||||
|
description: "Demo skill".to_string(),
|
||||||
|
short_description: None,
|
||||||
|
dependencies: None,
|
||||||
|
policy: None,
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(skill.allows_implicit_invocation());
|
||||||
|
assert!(skill.matches_product_restriction(/*restriction_product*/ None));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn policy_restricts_implicit_invocation_and_products() {
|
||||||
|
let policy = SkillPolicy {
|
||||||
|
allow_implicit_invocation: Some(false),
|
||||||
|
products: vec![Product::Codex],
|
||||||
|
};
|
||||||
|
let skill = EnvironmentSkillMetadata {
|
||||||
|
path_to_skills_md: PathUri::parse("file:///skills/demo/SKILL.md").expect("valid skill URI"),
|
||||||
|
name: "demo".to_string(),
|
||||||
|
description: "Demo skill".to_string(),
|
||||||
|
short_description: None,
|
||||||
|
dependencies: None,
|
||||||
|
policy: Some(policy),
|
||||||
|
};
|
||||||
|
|
||||||
|
assert!(!skill.allows_implicit_invocation());
|
||||||
|
assert!(skill.matches_product_restriction(Some(Product::Codex)));
|
||||||
|
assert!(!skill.matches_product_restriction(/*restriction_product*/ None));
|
||||||
|
}
|
||||||
Reference in new issue
Block a user