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-shell-command",
|
||||
"codex-shell-escalation",
|
||||
"codex-skills",
|
||||
"codex-state",
|
||||
"codex-terminal-detection",
|
||||
"codex-test-binary-support",
|
||||
@@ -2777,6 +2778,7 @@ dependencies = [
|
||||
"codex-otel",
|
||||
"codex-plugin",
|
||||
"codex-protocol",
|
||||
"codex-skills",
|
||||
"codex-tools",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-path",
|
||||
@@ -3950,7 +3952,9 @@ dependencies = [
|
||||
name = "codex-skills"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"codex-protocol",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-path-uri",
|
||||
"include_dir",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
@@ -3965,6 +3969,7 @@ dependencies = [
|
||||
"codex-mcp",
|
||||
"codex-otel",
|
||||
"codex-protocol",
|
||||
"codex-skills",
|
||||
"codex-tools",
|
||||
"codex-utils-absolute-path",
|
||||
"codex-utils-path-uri",
|
||||
|
||||
@@ -28,6 +28,7 @@ codex-model-provider = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-plugin = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
codex-skills = { workspace = true }
|
||||
codex-tools = { workspace = true }
|
||||
codex-utils-absolute-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_value;
|
||||
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::skill_config_rules_from_stack;
|
||||
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::protocol::Product;
|
||||
use codex_protocol::protocol::SkillScope;
|
||||
use codex_skills::SkillConfigRules;
|
||||
use codex_skills::SkillMetadata;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_plugins::find_plugin_manifest_path;
|
||||
use serde_json::Value as JsonValue;
|
||||
|
||||
@@ -67,8 +67,6 @@ use codex_config::types::PluginConfig;
|
||||
use codex_config::types::ToolSuggestDisabledTool;
|
||||
use codex_config::types::ToolSuggestDiscoverableType;
|
||||
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::loader::MAX_CONCURRENT_ROOT_SCANS;
|
||||
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::protocol::HookEventName;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_skills::SkillConfigRules;
|
||||
use codex_skills::SkillMetadata;
|
||||
use codex_tools::DiscoverablePluginInfo;
|
||||
use codex_tools::DiscoverableTool;
|
||||
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::SkillsLoadInput;
|
||||
use codex_core_skills::SkillsService;
|
||||
use codex_core_skills::config_rules::SkillConfigRules;
|
||||
use codex_login::CodexAuth;
|
||||
use codex_plugin::AppDeclaration;
|
||||
use codex_plugin::PluginId;
|
||||
use codex_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::HookEventName;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_skills::SkillConfigRules;
|
||||
use codex_utils_absolute_path::AbsolutePathBuf;
|
||||
use codex_utils_absolute_path::test_support::PathBufExt;
|
||||
use pretty_assertions::assert_eq;
|
||||
|
||||
@@ -2,7 +2,6 @@ use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use std::sync::RwLock;
|
||||
|
||||
use codex_core_skills::config_rules::SkillConfigRules;
|
||||
use codex_plugin::AppDeclaration;
|
||||
use codex_plugin::PluginCapabilitySummary;
|
||||
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_protocol::auth::AuthMode;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_skills::SkillConfigRules;
|
||||
use tokio::sync::Semaphore;
|
||||
|
||||
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::SkillConfig;
|
||||
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 tracing::warn;
|
||||
|
||||
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 {
|
||||
let mut entries = Vec::new();
|
||||
for layer in config_layer_stack.get_layers(
|
||||
|
||||
@@ -4,6 +4,7 @@ use std::io;
|
||||
use codex_exec_server::CapabilityRootDiscovery;
|
||||
use codex_exec_server::ExecutorFileSystem;
|
||||
use codex_protocol::protocol::Product;
|
||||
pub use codex_skills::EnvironmentSkillMetadata;
|
||||
use codex_utils_path_uri::PathUri;
|
||||
use futures::StreamExt;
|
||||
|
||||
@@ -36,17 +37,6 @@ struct ParsedEnvironmentSkill {
|
||||
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.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub struct EnvironmentSkillSnapshot {
|
||||
@@ -60,27 +50,6 @@ pub struct EnvironmentSkillSnapshotOutcome {
|
||||
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 {
|
||||
async fn load(
|
||||
file_system: &dyn ExecutorFileSystem,
|
||||
|
||||
@@ -7,81 +7,14 @@ use std::sync::Arc;
|
||||
use codex_exec_server::ExecutorFileSystem;
|
||||
use codex_exec_server::LOCAL_FS;
|
||||
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_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)]
|
||||
pub struct SkillError {
|
||||
pub path: AbsolutePathBuf,
|
||||
|
||||
@@ -63,6 +63,7 @@ codex-rollout = { workspace = true }
|
||||
codex-rollout-trace = { workspace = true }
|
||||
codex-rmcp-client = { workspace = true }
|
||||
codex-sandboxing = { workspace = true }
|
||||
codex-skills = { workspace = true }
|
||||
codex-state = { workspace = true }
|
||||
codex-terminal-detection = { 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::SkillLoadOutcome;
|
||||
pub use codex_core_skills::SkillMetadata;
|
||||
pub use codex_core_skills::SkillPolicy;
|
||||
pub use codex_core_skills::SkillRenderReport;
|
||||
pub use codex_core_skills::SkillsLoadInput;
|
||||
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::service;
|
||||
pub use codex_core_skills::system;
|
||||
pub use codex_skills::SkillMetadata;
|
||||
pub use codex_skills::SkillPolicy;
|
||||
|
||||
pub(crate) fn skills_load_input_from_config(
|
||||
config: &Config,
|
||||
|
||||
@@ -19,6 +19,7 @@ codex-extension-api = { workspace = true }
|
||||
codex-mcp = { workspace = true }
|
||||
codex-otel = { workspace = true }
|
||||
codex-protocol = { workspace = true }
|
||||
codex-skills = { workspace = true }
|
||||
codex-tools = { workspace = true }
|
||||
codex-utils-path-uri = { 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 std::sync::Arc;
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
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_root;
|
||||
use codex_exec_server::EnvironmentManager;
|
||||
use codex_protocol::capabilities::CapabilityRootLocation;
|
||||
use codex_protocol::protocol::Product;
|
||||
use codex_skills::EnvironmentSkillMetadata;
|
||||
use codex_utils_path_uri::PathConvention;
|
||||
|
||||
use crate::catalog::SkillAuthority;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use codex_core_skills::SkillLoadOutcome;
|
||||
use codex_core_skills::SkillMetadata;
|
||||
use codex_skills::SkillMetadata;
|
||||
|
||||
use crate::catalog::SkillAuthority;
|
||||
use crate::catalog::SkillCatalog;
|
||||
|
||||
@@ -7,7 +7,6 @@ use std::sync::atomic::Ordering;
|
||||
use codex_core_skills::HostSkillsSnapshot;
|
||||
use codex_core_skills::SKILLS_INTRO_WITH_ABSOLUTE_PATHS;
|
||||
use codex_core_skills::SkillLoadOutcome;
|
||||
use codex_core_skills::SkillMetadata;
|
||||
use codex_core_skills::injection::InjectedHostSkillPrompts;
|
||||
use codex_extension_api::ConversationHistory;
|
||||
use codex_extension_api::ExtensionData;
|
||||
@@ -31,6 +30,7 @@ use codex_protocol::protocol::SkillScope;
|
||||
use codex_protocol::protocol::TruncationPolicy;
|
||||
use codex_protocol::protocol::TurnEnvironmentSelection;
|
||||
use codex_protocol::user_input::UserInput;
|
||||
use codex_skills::SkillMetadata;
|
||||
use codex_skills_extension::SkillProviders;
|
||||
use codex_skills_extension::SkillsExtensionConfig;
|
||||
use codex_skills_extension::catalog::SkillAuthority;
|
||||
|
||||
@@ -14,6 +14,8 @@ path = "src/lib.rs"
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
codex-protocol = { workspace = true }
|
||||
codex-utils-absolute-path = { workspace = true }
|
||||
codex-utils-path-uri = { workspace = true }
|
||||
include_dir = { 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 include_dir::Dir;
|
||||
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