a3s-code-core 9.0.0

A3S Code Core - Embeddable AI agent library with tool execution
Documentation
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};

/// Closed runtime value categories accepted by the Code projection kernel.
///
/// Implementations inside trait-backed categories remain open, but callers
/// cannot insert `Any` or invent a new product category. UI values carry only
/// renderer-neutral path-free content; embedding-host authority stays outside
/// this enum.
#[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"));
    }
}