Skip to main content

claudius/types/
document_block.rs

1use serde::{Deserialize, Serialize};
2
3use crate::types::{
4    Base64PdfSource, CacheControlEphemeral, CitationsConfig, ContentBlockSourceParam,
5    PlainTextSource, UrlPdfSource,
6};
7
8/// The source type for a document block, which can be one of several types.
9#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
10#[serde(tag = "type")]
11pub enum DocumentSource {
12    /// A Base64 encoded PDF source.
13    #[serde(rename = "base64")]
14    Base64Pdf(Base64PdfSource),
15
16    /// A plain text source.
17    #[serde(rename = "text")]
18    PlainText(PlainTextSource),
19
20    /// A content block source.
21    #[serde(rename = "content")]
22    ContentBlock(ContentBlockSourceParam),
23
24    /// A URL PDF source.
25    #[serde(rename = "url")]
26    UrlPdf(UrlPdfSource),
27}
28
29impl From<Base64PdfSource> for DocumentSource {
30    fn from(source: Base64PdfSource) -> Self {
31        DocumentSource::Base64Pdf(source)
32    }
33}
34
35impl From<PlainTextSource> for DocumentSource {
36    fn from(source: PlainTextSource) -> Self {
37        DocumentSource::PlainText(source)
38    }
39}
40
41impl From<ContentBlockSourceParam> for DocumentSource {
42    fn from(source: ContentBlockSourceParam) -> Self {
43        DocumentSource::ContentBlock(source)
44    }
45}
46
47impl From<UrlPdfSource> for DocumentSource {
48    fn from(source: UrlPdfSource) -> Self {
49        DocumentSource::UrlPdf(source)
50    }
51}
52
53/// Parameters for a document block.
54#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
55pub struct DocumentBlock {
56    /// The source of the document.
57    pub source: DocumentSource,
58
59    /// Create a cache control breakpoint at this content block.
60    #[serde(skip_serializing_if = "Option::is_none")]
61    pub cache_control: Option<CacheControlEphemeral>,
62
63    /// Configuration for citations in this document.
64    #[serde(skip_serializing_if = "Option::is_none")]
65    pub citations: Option<CitationsConfig>,
66
67    /// Optional context for the document.
68    #[serde(skip_serializing_if = "Option::is_none")]
69    pub context: Option<String>,
70
71    /// Optional title for the document.
72    #[serde(skip_serializing_if = "Option::is_none")]
73    pub title: Option<String>,
74}
75
76impl DocumentBlock {
77    /// Create a new `DocumentBlock` with the given source.
78    pub fn new(source: DocumentSource) -> Self {
79        Self {
80            source,
81            cache_control: None,
82            citations: None,
83            context: None,
84            title: None,
85        }
86    }
87
88    /// Create a new `DocumentBlock` with a Base64 PDF source.
89    pub fn new_with_base64_pdf(source: Base64PdfSource) -> Self {
90        Self::new(DocumentSource::Base64Pdf(source))
91    }
92
93    /// Create a new `DocumentBlock` with a plain text source.
94    pub fn new_with_plain_text(source: PlainTextSource) -> Self {
95        Self::new(DocumentSource::PlainText(source))
96    }
97
98    /// Create a new `DocumentBlock` with a content block source.
99    pub fn new_with_content_block(source: ContentBlockSourceParam) -> Self {
100        Self::new(DocumentSource::ContentBlock(source))
101    }
102
103    /// Create a new `DocumentBlock` with a URL PDF source.
104    pub fn new_with_url_pdf(source: UrlPdfSource) -> Self {
105        Self::new(DocumentSource::UrlPdf(source))
106    }
107
108    /// Add a cache control to this document block.
109    pub fn with_cache_control(mut self, cache_control: CacheControlEphemeral) -> Self {
110        self.cache_control = Some(cache_control);
111        self
112    }
113
114    /// Add citations configuration to this document block.
115    pub fn with_citations(mut self, citations: CitationsConfig) -> Self {
116        self.citations = Some(citations);
117        self
118    }
119
120    /// Add context to this document block.
121    pub fn with_context(mut self, context: String) -> Self {
122        self.context = Some(context);
123        self
124    }
125
126    /// Add a title to this document block.
127    pub fn with_title(mut self, title: String) -> Self {
128        self.title = Some(title);
129        self
130    }
131}
132
133#[cfg(test)]
134mod tests {
135    use super::*;
136    use serde_json::{json, to_value};
137
138    #[test]
139    fn document_block_with_base64_pdf() {
140        let base64_source =
141            Base64PdfSource::new("data:application/pdf;base64,JVBERi0xLjcKJeLjz9MKN".to_string());
142
143        let document_block = DocumentBlock::new_with_base64_pdf(base64_source);
144        let json = to_value(&document_block).unwrap();
145
146        assert_eq!(
147            json,
148            json!({
149                "source": {
150                    "type": "base64",
151                    "data": "data:application/pdf;base64,JVBERi0xLjcKJeLjz9MKN",
152                    "media_type": "application/pdf"
153                }
154            })
155        );
156    }
157
158    #[test]
159    fn document_block_with_plain_text() {
160        let text_source = PlainTextSource::new("Sample text content".to_string());
161
162        let document_block = DocumentBlock::new_with_plain_text(text_source);
163        let json = to_value(&document_block).unwrap();
164
165        assert_eq!(
166            json,
167            json!({
168                "source": {
169                    "type": "text",
170                    "data": "Sample text content",
171                    "media_type": "text/plain"
172                }
173            })
174        );
175    }
176
177    #[test]
178    fn document_block_with_content_block() {
179        let content_source = ContentBlockSourceParam::from_string_ref("Sample content");
180
181        let document_block = DocumentBlock::new_with_content_block(content_source);
182        let json = to_value(&document_block).unwrap();
183
184        assert_eq!(
185            json,
186            json!({
187                "source": {
188                    "type": "content",
189                    "content": "Sample content"
190                }
191            })
192        );
193    }
194
195    #[test]
196    fn document_block_with_url_pdf() {
197        let url_source = UrlPdfSource::new("https://example.com/document.pdf".to_string());
198
199        let document_block = DocumentBlock::new_with_url_pdf(url_source);
200        let json = to_value(&document_block).unwrap();
201
202        assert_eq!(
203            json,
204            json!({
205                "source": {
206                    "type": "url",
207                    "url": "https://example.com/document.pdf"
208                }
209            })
210        );
211    }
212
213    #[test]
214    fn document_block_with_all_fields() {
215        let url_source = UrlPdfSource::new("https://example.com/document.pdf".to_string());
216        let cache_control = CacheControlEphemeral::new();
217        let citations = CitationsConfig::enabled();
218
219        let document_block = DocumentBlock::new_with_url_pdf(url_source)
220            .with_cache_control(cache_control)
221            .with_citations(citations)
222            .with_context("Document context".to_string())
223            .with_title("Document Title".to_string());
224
225        let json = to_value(&document_block).unwrap();
226
227        assert_eq!(
228            json,
229            json!({
230                "source": {
231                    "type": "url",
232                    "url": "https://example.com/document.pdf"
233                },
234                "cache_control": {
235                    "type": "ephemeral"
236                },
237                "citations": {
238                    "enabled": true
239                },
240                "context": "Document context",
241                "title": "Document Title"
242            })
243        );
244    }
245}