1use std::future::IntoFuture;
6
7use ferrin_spec::BoxFuture;
8use ferrin_spec::SkillsRef;
9pub use ferrin_spec::skills::SkillFile;
10pub use ferrin_spec::skills::SkillFileData;
11use ferrin_spec::skills::UploadSkillOptions;
12pub use ferrin_spec::skills::UploadSkillResult;
13use tracing::Instrument;
14
15use crate::error::Error;
16use crate::modality::ModalityOptions;
17use crate::modality::impl_modality_builder;
18use crate::telemetry::ModelIdentity;
19use crate::telemetry::spans;
20
21#[must_use]
23pub fn upload_skill(skills: impl Into<SkillsRef>, files: Vec<SkillFile>) -> UploadSkill {
24 UploadSkill {
25 skills: skills.into(),
26 files,
27 display_title: None,
28 base: ModalityOptions::default(),
29 }
30}
31
32#[derive(Debug)]
34pub struct UploadSkill {
35 skills: SkillsRef,
36 files: Vec<SkillFile>,
37 display_title: Option<String>,
38 base: ModalityOptions,
39}
40
41impl UploadSkill {
42 #[must_use]
44 pub fn display_title(mut self, display_title: impl Into<String>) -> Self {
45 self.display_title = Some(display_title.into());
46 self
47 }
48}
49
50impl_modality_builder!(@no_retry UploadSkill);
51
52impl IntoFuture for UploadSkill {
53 type Output = Result<UploadSkillResult, Error>;
54 type IntoFuture = BoxFuture<'static, Self::Output>;
55
56 fn into_future(self) -> Self::IntoFuture {
57 Box::pin(async move {
58 let identity = ModelIdentity::new(self.skills.provider().clone(), "skills");
59 let span = spans::modality_span("upload_skill", &identity);
60 let skills = self.skills.clone();
61 let base = self.base.clone();
62 let files = self.files;
63 let display_title = self.display_title;
64 base.run(|base, token| {
65 async move {
66 let result = skills
67 .upload_skill(UploadSkillOptions {
68 files,
69 display_title,
70 headers: base.request_headers(),
71 provider_options: base.provider_options.clone(),
72 cancellation: token,
73 })
74 .await
75 .map_err(Error::from)?;
76 spans::log_warnings(&result.warnings, &identity);
77 Ok(result)
78 }
79 .instrument(span)
80 })
81 .await
82 })
83 }
84}