claude_agent/types/
search.rs1use serde::{Deserialize, Serialize};
4
5use super::citations::CitationsConfig;
6use super::message::CacheControl;
7
8#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
9#[serde(tag = "type", rename_all = "snake_case")]
10pub enum SearchResultContentBlock {
11 Text { text: String },
12}
13
14impl SearchResultContentBlock {
15 pub fn text(content: impl Into<String>) -> Self {
16 Self::Text {
17 text: content.into(),
18 }
19 }
20}
21
22#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
23pub struct SearchResultBlock {
24 pub source: String,
25 pub title: String,
26 pub content: Vec<SearchResultContentBlock>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub citations: Option<CitationsConfig>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub cache_control: Option<CacheControl>,
31}
32
33impl SearchResultBlock {
34 pub fn new(
35 source: impl Into<String>,
36 title: impl Into<String>,
37 content: impl Into<String>,
38 ) -> Self {
39 Self {
40 source: source.into(),
41 title: title.into(),
42 content: vec![SearchResultContentBlock::Text {
43 text: content.into(),
44 }],
45 citations: None,
46 cache_control: None,
47 }
48 }
49
50 pub fn with_blocks(
51 source: impl Into<String>,
52 title: impl Into<String>,
53 blocks: Vec<SearchResultContentBlock>,
54 ) -> Self {
55 Self {
56 source: source.into(),
57 title: title.into(),
58 content: blocks,
59 citations: None,
60 cache_control: None,
61 }
62 }
63
64 pub fn add_text(mut self, text: impl Into<String>) -> Self {
65 self.content
66 .push(SearchResultContentBlock::Text { text: text.into() });
67 self
68 }
69
70 pub fn with_citations(mut self, enabled: bool) -> Self {
71 self.citations = Some(if enabled {
72 CitationsConfig::enabled()
73 } else {
74 CitationsConfig::disabled()
75 });
76 self
77 }
78
79 pub fn without_citations(mut self) -> Self {
80 self.citations = Some(CitationsConfig::disabled());
81 self
82 }
83
84 pub fn with_cache_control(mut self, cache_control: CacheControl) -> Self {
85 self.cache_control = Some(cache_control);
86 self
87 }
88
89 pub fn cached(mut self) -> Self {
90 self.cache_control = Some(CacheControl::ephemeral());
91 self
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn test_search_result_new() {
101 let result = SearchResultBlock::new("https://example.com", "Example Page", "Some content");
102
103 assert_eq!(result.source, "https://example.com");
104 assert_eq!(result.title, "Example Page");
105 assert_eq!(result.content.len(), 1);
106 assert!(result.citations.is_none());
107 }
108
109 #[test]
110 fn test_search_result_with_citations() {
111 let result = SearchResultBlock::new("https://example.com", "Example Page", "Content")
112 .with_citations(true);
113
114 assert!(result.citations.is_some());
115 assert!(result.citations.unwrap().enabled);
116 }
117
118 #[test]
119 fn test_search_result_multiple_blocks() {
120 let result = SearchResultBlock::new("https://example.com", "Title", "First block")
121 .add_text("Second block")
122 .add_text("Third block");
123
124 assert_eq!(result.content.len(), 3);
125 }
126
127 #[test]
128 fn test_search_result_serialization() {
129 let result = SearchResultBlock::new("https://example.com", "Title", "content");
130
131 let json = serde_json::to_string(&result).unwrap();
132 assert!(json.contains("https://example.com"));
133 assert!(json.contains("content"));
134 assert!(json.contains("\"title\":\"Title\""));
135 }
136}