Skip to main content

systemprompt_models/api/responses/
markdown.rs

1//! Markdown response with structured YAML frontmatter for rendering
2//! authored content over the API.
3//!
4//! Copyright (c) systemprompt.io — Business Source License 1.1.
5//! See <https://systemprompt.io> for licensing details.
6
7use serde::{Deserialize, Serialize};
8
9#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct MarkdownFrontmatter {
11    pub title: String,
12    pub slug: String,
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub description: Option<String>,
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub author: Option<String>,
17    #[serde(skip_serializing_if = "Option::is_none")]
18    pub published_at: Option<String>,
19    #[serde(default, skip_serializing_if = "Vec::is_empty")]
20    pub tags: Vec<String>,
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub url: Option<String>,
23}
24
25impl MarkdownFrontmatter {
26    pub fn new(title: impl Into<String>, slug: impl Into<String>) -> Self {
27        Self {
28            title: title.into(),
29            slug: slug.into(),
30            description: None,
31            author: None,
32            published_at: None,
33            tags: Vec::new(),
34            url: None,
35        }
36    }
37
38    #[must_use]
39    pub fn with_description(mut self, description: impl Into<String>) -> Self {
40        self.description = Some(description.into());
41        self
42    }
43
44    #[must_use]
45    pub fn with_author(mut self, author: impl Into<String>) -> Self {
46        self.author = Some(author.into());
47        self
48    }
49
50    #[must_use]
51    pub fn with_published_at(mut self, published_at: impl Into<String>) -> Self {
52        self.published_at = Some(published_at.into());
53        self
54    }
55
56    #[must_use]
57    pub fn with_tags(mut self, tags: Vec<String>) -> Self {
58        self.tags = tags;
59        self
60    }
61
62    #[must_use]
63    pub fn with_url(mut self, url: impl Into<String>) -> Self {
64        self.url = Some(url.into());
65        self
66    }
67
68    pub fn to_yaml(&self) -> Result<String, serde_yaml::Error> {
69        serde_yaml::to_string(self)
70    }
71}
72
73#[derive(Debug, Clone)]
74pub struct MarkdownResponse {
75    pub frontmatter: MarkdownFrontmatter,
76    pub body: String,
77}
78
79impl MarkdownResponse {
80    pub fn new(frontmatter: MarkdownFrontmatter, body: impl Into<String>) -> Self {
81        Self {
82            frontmatter,
83            body: body.into(),
84        }
85    }
86
87    pub fn to_markdown(&self) -> Result<String, serde_yaml::Error> {
88        let yaml = self.frontmatter.to_yaml()?;
89        Ok(format!("---\n{}---\n\n{}", yaml, self.body))
90    }
91}