Skip to main content

ferrin_spec/
skills.rs

1//! Provider skill upload interface.
2
3use std::future::Future;
4
5use bytes::Bytes;
6use serde::Deserialize;
7use serde::Serialize;
8use tokio_util::sync::CancellationToken;
9
10use crate::error::ProviderError;
11use crate::shared::Headers;
12use crate::shared::ProviderId;
13use crate::shared::ProviderMetadata;
14use crate::shared::ProviderOptions;
15use crate::shared::ProviderReference;
16use crate::shared::Warning;
17use crate::shared::base64_bytes;
18
19/// Upload skills (bundles of files) to the provider.
20pub trait Skills: Send + Sync + 'static {
21    /// Provider identifier.
22    fn provider(&self) -> &ProviderId;
23
24    /// Uploads a skill and returns its provider reference.
25    fn upload_skill(
26        &self,
27        options: UploadSkillOptions,
28    ) -> impl Future<Output = Result<UploadSkillResult, ProviderError>> + Send;
29}
30
31/// Content of a skill file.
32#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
33#[serde(tag = "type", rename_all = "lowercase")]
34#[non_exhaustive]
35pub enum SkillFileData {
36    /// Binary data.
37    Data {
38        /// The bytes.
39        #[serde(with = "base64_bytes")]
40        data: Bytes,
41    },
42    /// UTF-8 text.
43    Text {
44        /// The text.
45        text: String,
46    },
47}
48
49/// A file inside a skill bundle.
50#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
51pub struct SkillFile {
52    /// Path inside the bundle.
53    pub path: String,
54    /// Content.
55    pub data: SkillFileData,
56}
57
58/// Options for uploading a skill.
59#[derive(Debug, Clone)]
60pub struct UploadSkillOptions {
61    /// Files of the bundle.
62    pub files: Vec<SkillFile>,
63    /// Display title.
64    pub display_title: Option<String>,
65    /// Additional request headers.
66    pub headers: Headers,
67    /// Provider-specific options keyed by provider name.
68    pub provider_options: ProviderOptions,
69    /// Cancellation token.
70    pub cancellation: CancellationToken,
71}
72
73impl UploadSkillOptions {
74    /// Creates options for `files`.
75    #[must_use]
76    pub fn new(files: Vec<SkillFile>) -> Self {
77        Self {
78            files,
79            display_title: None,
80            headers: Headers::new(),
81            provider_options: ProviderOptions::new(),
82            cancellation: CancellationToken::new(),
83        }
84    }
85}
86
87/// Result of a skill upload.
88#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
89pub struct UploadSkillResult {
90    /// Reference to the stored skill.
91    pub provider_reference: ProviderReference,
92    /// Display title.
93    #[serde(default, skip_serializing_if = "Option::is_none")]
94    pub display_title: Option<String>,
95    /// Skill name.
96    #[serde(default, skip_serializing_if = "Option::is_none")]
97    pub name: Option<String>,
98    /// Skill description.
99    #[serde(default, skip_serializing_if = "Option::is_none")]
100    pub description: Option<String>,
101    /// Latest version identifier.
102    #[serde(default, skip_serializing_if = "Option::is_none")]
103    pub latest_version: Option<String>,
104    /// Provider-specific metadata.
105    #[serde(default, skip_serializing_if = "Option::is_none")]
106    pub provider_metadata: Option<ProviderMetadata>,
107    /// Warnings.
108    #[serde(default)]
109    pub warnings: Vec<Warning>,
110}