distri-types 0.3.8

Shared message, tool, and config types for Distri
Documentation
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use crate::agent::StandardDefinition;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Skill {
    pub id: String,
    pub name: String,
    pub description: String,
    pub agent_definition: StandardDefinition,
    pub files: Vec<SkillFile>,
    pub metadata: SkillMetadata,
    pub created_at: DateTime<Utc>,
    pub updated_at: DateTime<Utc>,
}

impl Skill {
    #[allow(clippy::too_many_arguments)]
    pub fn new(
        id: String,
        name: String,
        description: String,
        agent_definition: StandardDefinition,
        files: Vec<SkillFile>,
        metadata: SkillMetadata,
        created_at: DateTime<Utc>,
        updated_at: DateTime<Utc>,
    ) -> Self {
        Self {
            id,
            name,
            description,
            agent_definition,
            files,
            metadata,
            created_at,
            updated_at,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillMetadata {
    #[serde(default = "default_skill_version")]
    pub version: String,
    #[serde(default, skip_serializing_if = "Vec::is_empty")]
    pub tags: Vec<String>,
}

impl Default for SkillMetadata {
    fn default() -> Self {
        Self {
            version: default_skill_version(),
            tags: Vec::new(),
        }
    }
}

fn default_skill_version() -> String {
    "0.1.0".to_string()
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SkillFile {
    pub path: String,
    pub content: String,
    pub kind: SkillFileKind,
    #[serde(default, skip_serializing_if = "Option::is_none")]
    pub export: Option<SkillExport>,
}

#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
#[serde(rename_all = "snake_case")]
pub enum SkillFileKind {
    Script,
    Markdown,
    Asset,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum SkillExport {
    Tool {
        name: String,
        description: Option<String>,
    },
}

pub fn slugify_id(name: &str) -> String {
    let mut slug = name
        .to_lowercase()
        .chars()
        .map(|ch| if ch.is_ascii_alphanumeric() { ch } else { '_' })
        .collect::<String>();
    while slug.contains("__") {
        slug = slug.replace("__", "_");
    }
    slug.trim_matches('_').to_string()
}