Skip to main content

agent_workspace_contract/environment/
skills.rs

1use super::*;
2
3/// Product path for installing a Skills Hub package into a running Sandbox.
4pub const SANDBOX_SKILLS_PATH: &str = "/internal/v1/workspace/sandboxes/{sandboxId}/skills";
5
6/// Product path for searching published Skills Hub packages.
7pub const SKILLS_SEARCH_PATH: &str = "/internal/v1/workspace/skills:search";
8
9/// Sandbox-root directory that receives unpacked skill packages.
10pub const SANDBOX_SKILL_INSTALL_ROOT: &str = "skills";
11
12/// Default Skills Hub version selector when the caller omits `version`.
13pub const SANDBOX_SKILL_DEFAULT_VERSION: &str = "latest";
14
15/// Default sandbox provider when the caller omits `provider`.
16pub const SANDBOX_SKILL_DEFAULT_PROVIDER: &str = "local";
17
18fn default_sandbox_skill_provider() -> String {
19    SANDBOX_SKILL_DEFAULT_PROVIDER.to_string()
20}
21
22#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
23#[serde(deny_unknown_fields, rename_all = "camelCase")]
24pub struct InstallSandboxSkillRequest {
25    pub group: String,
26    pub name: String,
27    #[serde(default, skip_serializing_if = "Option::is_none")]
28    pub version: Option<String>,
29    /// Sandbox provider to write into: `local`, `e2b`, or `moulin`.
30    #[serde(default = "default_sandbox_skill_provider")]
31    pub provider: String,
32}
33
34#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(deny_unknown_fields, rename_all = "camelCase")]
36pub struct InstallSandboxSkillResource {
37    pub sandbox_id: String,
38    pub provider: String,
39    pub group: String,
40    pub name: String,
41    pub version: String,
42    pub install_path: String,
43    pub files: Vec<String>,
44}
45
46#[derive(Debug, Clone, PartialEq, Eq)]
47pub struct SkillPackageFile {
48    pub path: String,
49    pub content: Vec<u8>,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
53pub struct SkillPackage {
54    pub group: String,
55    pub name: String,
56    pub version: String,
57    pub files: Vec<SkillPackageFile>,
58}
59
60#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
61#[serde(rename_all = "camelCase")]
62pub struct SkillSearchQuery {
63    #[serde(default, skip_serializing_if = "Option::is_none")]
64    pub q: Option<String>,
65    #[serde(default, skip_serializing_if = "Option::is_none")]
66    pub page: Option<u32>,
67    #[serde(default, skip_serializing_if = "Option::is_none")]
68    pub limit: Option<u32>,
69}
70
71#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
72#[serde(rename_all = "camelCase")]
73pub struct SkillSearchItem {
74    pub group: String,
75    pub name: String,
76    pub full_name: String,
77    #[serde(default)]
78    pub description: String,
79    #[serde(default)]
80    pub latest_version: String,
81    #[serde(default, skip_serializing_if = "Option::is_none")]
82    pub skill_type: Option<String>,
83}
84
85#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
86#[serde(rename_all = "camelCase")]
87pub struct SkillSearchPage {
88    pub items: Vec<SkillSearchItem>,
89    #[serde(default)]
90    pub page: u32,
91    #[serde(default)]
92    pub limit: u32,
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub total: Option<u64>,
95    #[serde(default, skip_serializing_if = "Option::is_none")]
96    pub has_more: Option<bool>,
97}
98
99/// Downloads a published skill archive. Implementations live in adapter crates.
100#[async_trait]
101pub trait SkillHubClient: Send + Sync + Debug {
102    async fn download_skill(
103        &self,
104        group: &str,
105        name: &str,
106        version: &str,
107        user_authorization: &str,
108    ) -> Result<SkillPackage>;
109
110    async fn search_skills(
111        &self,
112        query: &SkillSearchQuery,
113        user_authorization: &str,
114    ) -> Result<SkillSearchPage>;
115}