regy 0.1.0

Private-by-default desktop agent for the Regy web interface
use async_trait::async_trait;

use super::{errors::AgentResult, protocol::SkillSearchItem};

pub const MAX_SEARCH_LIMIT: u16 = 100;
pub const MAX_RESPONSE_BYTES: usize = 2 * 1024 * 1024;

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CatalogSearch {
    pub items: Vec<SkillSearchItem>,
    pub next_offset: Option<u32>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SkillFile {
    pub path: String,
    pub bytes: Vec<u8>,
    pub executable: bool,
}

impl SkillFile {
    pub fn text(path: impl Into<String>, contents: impl AsRef<str>) -> Self {
        Self {
            path: path.into(),
            bytes: contents.as_ref().as_bytes().to_vec(),
            executable: false,
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct SkillSource {
    pub repository: String,
    pub revision: String,
    pub directory: String,
    pub files: Option<Vec<SkillFile>>,
    pub content_hash: Option<String>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct CatalogSkill {
    pub item: SkillSearchItem,
    pub source: SkillSource,
}

#[async_trait]
pub trait SkillCatalog: Send + Sync {
    fn id(&self) -> &'static str;
    async fn search(&self, query: &str, limit: u16, offset: u32) -> AgentResult<CatalogSearch>;
    async fn get(&self, skill_id: &str) -> AgentResult<CatalogSkill>;
}