llmsdk_provider/
skills_model.rs1use async_trait::async_trait;
15use serde::{Deserialize, Serialize};
16
17use crate::error::Result;
18use crate::files_model::UploadFileData;
19use crate::shared::{ProviderMetadata, ProviderOptions, ProviderReference, Warning};
20
21#[async_trait]
25pub trait SkillsModel: Send + Sync + std::fmt::Debug {
26 fn provider(&self) -> &str;
28
29 fn specification_version(&self) -> &'static str {
31 "v4"
32 }
33
34 async fn upload_skill(&self, options: UploadSkillOptions) -> Result<UploadSkillResult>;
41}
42
43#[derive(Debug, Clone, Serialize, Deserialize)]
47pub struct SkillFile {
48 pub path: String,
50 pub data: UploadFileData,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
58pub struct UploadSkillOptions {
59 pub files: Vec<SkillFile>,
61 #[serde(
63 default,
64 rename = "displayTitle",
65 skip_serializing_if = "Option::is_none"
66 )]
67 pub display_title: Option<String>,
68 #[serde(
70 default,
71 rename = "providerOptions",
72 skip_serializing_if = "Option::is_none"
73 )]
74 pub provider_options: Option<ProviderOptions>,
75}
76
77#[derive(Debug, Clone)]
81pub struct UploadSkillResult {
82 pub provider_reference: ProviderReference,
84 pub display_title: Option<String>,
86 pub name: Option<String>,
88 pub description: Option<String>,
90 pub latest_version: Option<String>,
92 pub provider_metadata: Option<ProviderMetadata>,
94 pub warnings: Vec<Warning>,
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::shared::FileBytes;
102
103 #[test]
104 fn options_serde_roundtrip() {
105 let opts = UploadSkillOptions {
106 files: vec![SkillFile {
107 path: "main.py".into(),
108 data: UploadFileData::Text {
109 text: "print(1)".into(),
110 },
111 }],
112 display_title: Some("greeter".into()),
113 provider_options: None,
114 };
115 let json = serde_json::to_value(&opts).unwrap();
116 assert_eq!(json["displayTitle"], "greeter");
117 assert_eq!(json["files"][0]["path"], "main.py");
118 assert_eq!(json["files"][0]["data"]["type"], "text");
119 }
120
121 #[test]
122 fn skill_file_supports_bytes() {
123 let f = SkillFile {
124 path: "asset.bin".into(),
125 data: UploadFileData::Data {
126 data: FileBytes::Bytes(vec![1, 2, 3]),
127 },
128 };
129 let v = serde_json::to_value(&f).unwrap();
130 assert_eq!(v["data"]["type"], "data");
131 }
132}