Skip to main content

systemprompt_models/artifacts/image/
mod.rs

1//! Image artifact.
2//!
3//! An [`ImageArtifact`] carries an image source URI with optional alt text,
4//! caption, and pixel dimensions. It implements [`Artifact`] and emits its own
5//! JSON schema for tool output.
6//!
7//! Copyright (c) systemprompt.io — Business Source License 1.1.
8//! See <https://systemprompt.io> for licensing details.
9
10use crate::artifacts::metadata::ArtifactProvenance;
11use crate::artifacts::traits::Artifact;
12use crate::artifacts::types::ArtifactType;
13use crate::execution::context::RequestContext;
14use schemars::JsonSchema;
15use serde::{Deserialize, Serialize};
16use serde_json::{Value as JsonValue, json};
17use systemprompt_identifiers::{McpExecutionId, SkillId, SkillName};
18
19fn default_artifact_type() -> String {
20    "image".to_owned()
21}
22
23#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
24pub struct ImageArtifact {
25    #[serde(rename = "x-artifact-type")]
26    #[serde(default = "default_artifact_type")]
27    pub artifact_type: String,
28    pub src: String,
29    #[serde(skip_serializing_if = "Option::is_none")]
30    pub alt: Option<String>,
31    #[serde(skip_serializing_if = "Option::is_none")]
32    pub caption: Option<String>,
33    #[serde(skip_serializing_if = "Option::is_none")]
34    pub width: Option<u32>,
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub height: Option<u32>,
37    #[serde(skip)]
38    #[schemars(skip)]
39    metadata: ArtifactProvenance,
40}
41
42impl ImageArtifact {
43    pub const ARTIFACT_TYPE_STR: &'static str = "image";
44
45    pub fn new(src: impl Into<String>) -> Self {
46        Self {
47            artifact_type: "image".to_owned(),
48            src: src.into(),
49            alt: None,
50            caption: None,
51            width: None,
52            height: None,
53            metadata: ArtifactProvenance::default(),
54        }
55    }
56
57    pub fn with_request(mut self, ctx: &RequestContext) -> Self {
58        self.metadata.set_request(ctx);
59        self
60    }
61
62    pub fn with_alt(mut self, alt: impl Into<String>) -> Self {
63        self.alt = Some(alt.into());
64        self
65    }
66
67    pub fn with_caption(mut self, caption: impl Into<String>) -> Self {
68        self.caption = Some(caption.into());
69        self
70    }
71
72    pub const fn with_dimensions(mut self, width: u32, height: u32) -> Self {
73        self.width = Some(width);
74        self.height = Some(height);
75        self
76    }
77
78    pub fn with_execution_id(mut self, id: McpExecutionId) -> Self {
79        self.metadata.set_execution_id(id);
80        self
81    }
82
83    pub fn with_skill(mut self, skill_id: SkillId, skill_name: SkillName) -> Self {
84        self.metadata.set_skill(skill_id, skill_name);
85        self
86    }
87}
88
89impl Artifact for ImageArtifact {
90    fn artifact_type(&self) -> ArtifactType {
91        ArtifactType::Image
92    }
93
94    // JSON: JSON Schema document describing the artifact for the model.
95    fn to_schema(&self) -> JsonValue {
96        json!({
97            "type": "object",
98            "properties": {
99                "src": {
100                    "type": "string",
101                    "description": "Image source URL or base64 data URI"
102                },
103                "alt": {
104                    "type": "string",
105                    "description": "Alt text for accessibility"
106                },
107                "caption": {
108                    "type": "string",
109                    "description": "Caption displayed below the image"
110                },
111                "width": {
112                    "type": "integer",
113                    "description": "Image width in pixels"
114                },
115                "height": {
116                    "type": "integer",
117                    "description": "Image height in pixels"
118                }
119            },
120            "required": ["src"],
121            "x-artifact-type": "image"
122        })
123    }
124}