systemprompt-models 0.1.18

Shared data models and types for systemprompt.io OS
Documentation
use crate::artifacts::metadata::ExecutionMetadata;
use crate::artifacts::traits::Artifact;
use crate::artifacts::types::ArtifactType;
use crate::execution::context::RequestContext;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use serde_json::{Value as JsonValue, json};
use systemprompt_identifiers::SkillId;

fn default_artifact_type() -> String {
    "list".to_string()
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ListItem {
    #[serde(skip_serializing_if = "Option::is_none")]
    pub id: Option<String>,
    pub title: String,
    pub summary: String,
    pub link: String,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub uri: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub slug: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub source_id: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub category: Option<String>,
    #[serde(skip_serializing_if = "Option::is_none")]
    pub description: Option<String>,
}

impl ListItem {
    pub fn new(
        title: impl Into<String>,
        summary: impl Into<String>,
        link: impl Into<String>,
    ) -> Self {
        Self {
            id: None,
            title: title.into(),
            summary: summary.into(),
            link: link.into(),
            uri: None,
            slug: None,
            source_id: None,
            category: None,
            description: None,
        }
    }

    pub fn with_id(mut self, id: impl Into<String>) -> Self {
        self.id = Some(id.into());
        self
    }

    pub fn with_uri(mut self, uri: impl Into<String>) -> Self {
        self.uri = Some(uri.into());
        self
    }

    pub fn with_slug(mut self, slug: impl Into<String>) -> Self {
        self.slug = Some(slug.into());
        self
    }

    pub fn with_source_id(mut self, source_id: impl Into<String>) -> Self {
        self.source_id = Some(source_id.into());
        self
    }

    pub fn with_category(mut self, category: impl Into<String>) -> Self {
        self.category = Some(category.into());
        self
    }

    pub fn with_description(mut self, description: impl Into<String>) -> Self {
        self.description = Some(description.into());
        self
    }
}

#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct ListArtifact {
    #[serde(rename = "x-artifact-type")]
    #[serde(default = "default_artifact_type")]
    pub artifact_type: String,
    pub items: Vec<ListItem>,
    pub count: usize,
    #[serde(skip)]
    #[schemars(skip)]
    metadata: ExecutionMetadata,
}

impl ListArtifact {
    pub const ARTIFACT_TYPE_STR: &'static str = "list";

    pub fn new(ctx: &RequestContext) -> Self {
        Self {
            artifact_type: "list".to_string(),
            items: Vec::new(),
            count: 0,
            metadata: ExecutionMetadata::with_request(ctx),
        }
    }

    pub fn with_items(mut self, items: Vec<ListItem>) -> Self {
        self.count = items.len();
        self.items = items;
        self
    }

    pub fn with_execution_id(mut self, id: impl Into<String>) -> Self {
        self.metadata.execution_id = Some(id.into());
        self
    }

    pub fn with_skill(
        mut self,
        skill_id: impl Into<SkillId>,
        skill_name: impl Into<String>,
    ) -> Self {
        self.metadata.skill_id = Some(skill_id.into());
        self.metadata.skill_name = Some(skill_name.into());
        self
    }
}

impl Artifact for ListArtifact {
    fn artifact_type(&self) -> ArtifactType {
        ArtifactType::List
    }

    fn to_schema(&self) -> JsonValue {
        json!({
            "type": "object",
            "properties": {
                "items": {
                    "type": "array",
                    "description": "Array of list items",
                    "items": {
                        "type": "object",
                        "properties": {
                            "title": {
                                "type": "string",
                                "description": "Item title"
                            },
                            "summary": {
                                "type": "string",
                                "description": "Item summary"
                            },
                            "link": {
                                "type": "string",
                                "description": "Item URL (full HTTPS URL compatible with resource_loading tool's uris parameter)"
                            },
                            "uri": {
                                "type": "string",
                                "description": "Standardized URI format (tyingshoelaces://blog/slug) for use with resource_loading tool"
                            },
                            "slug": {
                                "type": "string",
                                "description": "Content slug - can be used directly with resource_loading tool as tyingshoelaces://blog/{slug}"
                            }
                        },
                        "required": ["title", "summary", "link"]
                    }
                },
                "count": {
                    "type": "integer",
                    "description": "Total number of items"
                },
                "_execution_id": {
                    "type": "string",
                    "description": "Execution ID for tracking"
                }
            },
            "required": ["items"],
            "x-artifact-type": "list"
        })
    }
}