use std::fmt;
use std::sync::Arc;
use crate::cognitive_context::CognitiveContextSession;
use crate::commands::SlashCommand;
use crate::context::ContextProvider;
use crate::hooks::HookBinding;
use crate::mcp::McpBinding;
use crate::skills::Skill;
use crate::subagent::AgentDefinition;
use crate::tools::Tool;
#[cfg(feature = "dynamic-workflow")]
use super::FlowBinding;
use super::{CapabilityKind, KnowledgeSurfaceBinding, UiBinding};
#[derive(Clone)]
pub enum CapabilityValue {
Tool(Arc<dyn Tool>),
Skill(Arc<Skill>),
Agent(Arc<AgentDefinition>),
Command(Arc<dyn SlashCommand>),
Hook(Arc<HookBinding>),
Mcp(Arc<McpBinding>),
#[cfg(feature = "dynamic-workflow")]
Flow(Arc<FlowBinding>),
KnowledgeSurface(Arc<KnowledgeSurfaceBinding>),
Knowledge(Arc<CognitiveContextSession>),
Ui(Arc<UiBinding>),
Context(Arc<dyn ContextProvider>),
}
impl CapabilityValue {
pub const fn kind(&self) -> CapabilityKind {
match self {
Self::Tool(_) => CapabilityKind::Tool,
Self::Skill(_) => CapabilityKind::Skill,
Self::Agent(_) => CapabilityKind::Agent,
Self::Command(_) => CapabilityKind::Command,
Self::Hook(_) => CapabilityKind::Hook,
Self::Mcp(_) => CapabilityKind::Mcp,
#[cfg(feature = "dynamic-workflow")]
Self::Flow(_) => CapabilityKind::Flow,
Self::KnowledgeSurface(_) => CapabilityKind::KnowledgeSurface,
Self::Knowledge(_) => CapabilityKind::Knowledge,
Self::Ui(_) => CapabilityKind::Ui,
Self::Context(_) => CapabilityKind::Context,
}
}
pub(crate) fn public_name(&self) -> Option<&str> {
match self {
Self::Tool(value) => Some(value.name()),
Self::Skill(value) => Some(&value.name),
Self::Agent(value) => Some(&value.name),
Self::Command(value) => Some(value.name()),
Self::Hook(value) => Some(&value.hook().id),
#[cfg(feature = "dynamic-workflow")]
Self::Flow(value) => Some(value.public_name()),
Self::Mcp(value) => Some(value.server_name()),
Self::KnowledgeSurface(value) => Some(value.public_name()),
Self::Knowledge(value) => Some(value.provider_name()),
Self::Ui(value) => Some(value.public_name()),
Self::Context(value) => Some(value.name()),
}
}
}
impl fmt::Debug for CapabilityValue {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut debug = formatter.debug_struct("CapabilityValue");
debug.field("kind", &self.kind());
if let Some(public_name) = self.public_name() {
debug.field("public_name", &public_name);
}
debug.finish_non_exhaustive()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::skills::{Skill, SkillKind};
fn sample_skill(name: &str) -> CapabilityValue {
CapabilityValue::Skill(Arc::new(Skill {
name: name.to_owned(),
description: "coverage".to_owned(),
allowed_tools: None,
disable_model_invocation: false,
kind: SkillKind::Instruction,
content: "body".to_owned(),
tags: vec![],
version: None,
}))
}
#[test]
fn debug_emits_kind_and_public_name_without_body() {
let value = sample_skill("coverage-skill");
let rendered = format!("{value:?}");
assert!(rendered.contains("CapabilityValue"));
assert!(rendered.contains("Skill"));
assert!(rendered.contains("coverage-skill"));
assert!(!rendered.contains("body"));
assert_eq!(value.kind(), CapabilityKind::Skill);
assert_eq!(value.public_name(), Some("coverage-skill"));
}
}