Skip to main content

systemprompt_models/artifacts/cli/
conversion.rs

1use serde_json::Value as JsonValue;
2
3use super::{CliArtifact, CliArtifactType, CommandResultRaw, ConversionError};
4use crate::artifacts::list::ListItem;
5use crate::artifacts::table::Column;
6use crate::artifacts::types::ColumnType;
7use crate::artifacts::{
8    CopyPasteTextArtifact, ListArtifact, PresentationCardArtifact, TableArtifact, TextArtifact,
9};
10use crate::execution::context::RequestContext;
11
12impl CommandResultRaw {
13    pub fn from_json(json: &str) -> Result<Self, serde_json::Error> {
14        serde_json::from_str(json)
15    }
16
17    pub fn from_value(value: JsonValue) -> Result<Self, serde_json::Error> {
18        serde_json::from_value(value)
19    }
20
21    pub fn to_cli_artifact(&self, ctx: &RequestContext) -> Result<CliArtifact, ConversionError> {
22        match self.artifact_type {
23            CliArtifactType::Table => self.convert_table(ctx),
24            CliArtifactType::List => self.convert_list(ctx),
25            CliArtifactType::CopyPasteText => Ok(self.convert_copy_paste_text(ctx)),
26            CliArtifactType::PresentationCard => self.convert_presentation_card(ctx),
27            CliArtifactType::Text
28            | CliArtifactType::Dashboard
29            | CliArtifactType::Chart
30            | CliArtifactType::Form => Ok(self.convert_text(ctx)),
31        }
32    }
33
34    fn convert_table(&self, ctx: &RequestContext) -> Result<CliArtifact, ConversionError> {
35        let column_names = self
36            .hints
37            .as_ref()
38            .and_then(|h| h.columns.as_ref())
39            .ok_or(ConversionError::MissingColumns)?;
40
41        let items = extract_array_from_value(&self.data)?;
42
43        let columns: Vec<Column> = column_names
44            .iter()
45            .map(|name| Column::new(name, ColumnType::String))
46            .collect();
47
48        let artifact = TableArtifact::new(columns, ctx).with_rows(items);
49
50        Ok(CliArtifact::Table { artifact })
51    }
52
53    fn convert_list(&self, ctx: &RequestContext) -> Result<CliArtifact, ConversionError> {
54        let items = extract_array_from_value(&self.data)?;
55
56        let list_items: Vec<ListItem> = items
57            .iter()
58            .filter_map(|item| {
59                let title = item
60                    .get("title")
61                    .or_else(|| item.get("name"))
62                    .and_then(|v| v.as_str())?;
63
64                let summary = item
65                    .get("summary")
66                    .or_else(|| item.get("description"))
67                    .and_then(|v| v.as_str())
68                    .unwrap_or("");
69
70                let link = item
71                    .get("link")
72                    .or_else(|| item.get("url"))
73                    .or_else(|| item.get("id"))
74                    .and_then(|v| v.as_str())
75                    .unwrap_or("");
76
77                Some(ListItem::new(title, summary, link))
78            })
79            .collect();
80
81        let artifact = ListArtifact::new(ctx).with_items(list_items);
82
83        Ok(CliArtifact::List { artifact })
84    }
85
86    fn convert_text(&self, ctx: &RequestContext) -> CliArtifact {
87        let content = self
88            .data
89            .get("message")
90            .and_then(|v| v.as_str())
91            .map_or_else(
92                || {
93                    serde_json::to_string_pretty(&self.data)
94                        .unwrap_or_else(|_| self.data.to_string())
95                },
96                String::from,
97            );
98
99        let mut artifact = TextArtifact::new(&content, ctx);
100
101        if let Some(title) = &self.title {
102            artifact = artifact.with_title(title);
103        }
104
105        CliArtifact::Text { artifact }
106    }
107
108    fn convert_copy_paste_text(&self, ctx: &RequestContext) -> CliArtifact {
109        let content = self
110            .data
111            .get("content")
112            .or_else(|| self.data.get("message"))
113            .and_then(|v| v.as_str())
114            .map_or_else(
115                || {
116                    serde_json::to_string_pretty(&self.data)
117                        .unwrap_or_else(|_| self.data.to_string())
118                },
119                String::from,
120            );
121
122        let mut artifact = CopyPasteTextArtifact::new(&content, ctx);
123
124        if let Some(title) = &self.title {
125            artifact = artifact.with_title(title);
126        }
127
128        CliArtifact::CopyPasteText { artifact }
129    }
130
131    fn convert_presentation_card(
132        &self,
133        _ctx: &RequestContext,
134    ) -> Result<CliArtifact, ConversionError> {
135        let artifact: PresentationCardArtifact =
136            serde_json::from_value(self.data.clone()).map_err(ConversionError::Json)?;
137        Ok(CliArtifact::PresentationCard { artifact })
138    }
139}
140
141fn extract_array_from_value(value: &JsonValue) -> Result<Vec<JsonValue>, ConversionError> {
142    if let Some(arr) = value.as_array() {
143        return Ok(arr.clone());
144    }
145
146    if let Some(obj) = value.as_object() {
147        for v in obj.values() {
148            if let Some(arr) = v.as_array() {
149                return Ok(arr.clone());
150            }
151        }
152    }
153
154    Err(ConversionError::NoArrayFound)
155}