Skip to main content

systemprompt_models/artifacts/cli/
mod.rs

1//! CLI artifact envelope.
2//!
3//! [`CliArtifact`] is the tagged union of every renderable artifact a CLI
4//! command can emit (table, list, text, dashboard, chart, media, card). The CLI
5//! builds it, the wire carries it, and the MCP server deserializes it verbatim
6//! — the `artifact_type` tag is intrinsic to the serde representation.
7
8use schemars::JsonSchema;
9use serde::{Deserialize, Serialize};
10
11use super::{
12    AudioArtifact, ChartArtifact, CopyPasteTextArtifact, DashboardArtifact, ImageArtifact,
13    ListArtifact, MessageArtifact, PresentationCardArtifact, TableArtifact, TextArtifact,
14    VideoArtifact,
15};
16
17#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
18#[serde(tag = "artifact_type", rename_all = "snake_case")]
19pub enum CliArtifact {
20    Table {
21        #[serde(flatten)]
22        artifact: TableArtifact,
23    },
24    List {
25        #[serde(flatten)]
26        artifact: ListArtifact,
27    },
28    Text {
29        #[serde(flatten)]
30        artifact: TextArtifact,
31    },
32    #[serde(rename = "copy_paste_text")]
33    CopyPasteText {
34        #[serde(flatten)]
35        artifact: CopyPasteTextArtifact,
36    },
37    Dashboard {
38        #[serde(flatten)]
39        artifact: DashboardArtifact,
40    },
41    Chart {
42        #[serde(flatten)]
43        artifact: ChartArtifact,
44    },
45    Audio {
46        #[serde(flatten)]
47        artifact: AudioArtifact,
48    },
49    Image {
50        #[serde(flatten)]
51        artifact: ImageArtifact,
52    },
53    Video {
54        #[serde(flatten)]
55        artifact: VideoArtifact,
56    },
57    #[serde(rename = "presentation_card")]
58    PresentationCard {
59        #[serde(flatten)]
60        artifact: PresentationCardArtifact,
61    },
62    Message {
63        #[serde(flatten)]
64        artifact: MessageArtifact,
65    },
66}
67
68impl CliArtifact {
69    #[must_use]
70    pub const fn artifact_type_str(&self) -> &'static str {
71        match self {
72            Self::Table { .. } => TableArtifact::ARTIFACT_TYPE_STR,
73            Self::List { .. } => ListArtifact::ARTIFACT_TYPE_STR,
74            Self::Text { .. } => TextArtifact::ARTIFACT_TYPE_STR,
75            Self::CopyPasteText { .. } => CopyPasteTextArtifact::ARTIFACT_TYPE_STR,
76            Self::Dashboard { .. } => DashboardArtifact::ARTIFACT_TYPE_STR,
77            Self::Chart { .. } => ChartArtifact::ARTIFACT_TYPE_STR,
78            Self::Audio { .. } => AudioArtifact::ARTIFACT_TYPE_STR,
79            Self::Image { .. } => ImageArtifact::ARTIFACT_TYPE_STR,
80            Self::Video { .. } => VideoArtifact::ARTIFACT_TYPE_STR,
81            Self::PresentationCard { .. } => PresentationCardArtifact::ARTIFACT_TYPE_STR,
82            Self::Message { .. } => MessageArtifact::ARTIFACT_TYPE_STR,
83        }
84    }
85
86    #[must_use]
87    pub fn title(&self) -> Option<String> {
88        match self {
89            Self::Text { artifact } => artifact.title.clone(),
90            Self::CopyPasteText { artifact } => artifact.title.clone(),
91            Self::Dashboard { artifact } => Some(artifact.title.clone()),
92            Self::Audio { artifact } => artifact.title.clone(),
93            Self::PresentationCard { artifact } => Some(artifact.title.clone()),
94            Self::Table { .. }
95            | Self::List { .. }
96            | Self::Chart { .. }
97            | Self::Image { .. }
98            | Self::Video { .. }
99            | Self::Message { .. } => None,
100        }
101    }
102
103    #[must_use]
104    pub const fn table(artifact: TableArtifact) -> Self {
105        Self::Table { artifact }
106    }
107
108    #[must_use]
109    pub const fn list(artifact: ListArtifact) -> Self {
110        Self::List { artifact }
111    }
112
113    #[must_use]
114    pub const fn text(artifact: TextArtifact) -> Self {
115        Self::Text { artifact }
116    }
117
118    #[must_use]
119    pub const fn copy_paste_text(artifact: CopyPasteTextArtifact) -> Self {
120        Self::CopyPasteText { artifact }
121    }
122
123    #[must_use]
124    pub const fn dashboard(artifact: DashboardArtifact) -> Self {
125        Self::Dashboard { artifact }
126    }
127
128    #[must_use]
129    pub const fn chart(artifact: ChartArtifact) -> Self {
130        Self::Chart { artifact }
131    }
132
133    #[must_use]
134    pub const fn audio(artifact: AudioArtifact) -> Self {
135        Self::Audio { artifact }
136    }
137
138    #[must_use]
139    pub const fn image(artifact: ImageArtifact) -> Self {
140        Self::Image { artifact }
141    }
142
143    #[must_use]
144    pub const fn video(artifact: VideoArtifact) -> Self {
145        Self::Video { artifact }
146    }
147
148    #[must_use]
149    pub const fn presentation_card(artifact: PresentationCardArtifact) -> Self {
150        Self::PresentationCard { artifact }
151    }
152
153    #[must_use]
154    pub const fn message(artifact: MessageArtifact) -> Self {
155        Self::Message { artifact }
156    }
157}