1use serde::{Deserialize, Serialize};
6
7pub const PROTOCOL_VERSION: &str = "2024-11-05";
9
10#[derive(Debug, Clone, Default, Serialize, Deserialize)]
12pub struct ServerCapabilities {
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub tools: Option<ToolsCapability>,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub resources: Option<ResourcesCapability>,
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub prompts: Option<PromptsCapability>,
22 #[serde(skip_serializing_if = "Option::is_none")]
24 pub logging: Option<LoggingCapability>,
25 #[serde(skip_serializing_if = "Option::is_none")]
27 pub tasks: Option<TasksCapability>,
28}
29
30#[derive(Debug, Clone, Default, Serialize, Deserialize)]
32pub struct ToolsCapability {
33 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
35 pub list_changed: bool,
36}
37
38#[derive(Debug, Clone, Default, Serialize, Deserialize)]
40pub struct ResourcesCapability {
41 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
43 pub subscribe: bool,
44 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
46 pub list_changed: bool,
47}
48
49#[derive(Debug, Clone, Default, Serialize, Deserialize)]
51pub struct PromptsCapability {
52 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
54 pub list_changed: bool,
55}
56
57#[derive(Debug, Clone, Default, Serialize, Deserialize)]
59pub struct LoggingCapability {}
60
61#[derive(Debug, Clone, Default, Serialize, Deserialize)]
63pub struct ClientCapabilities {
64 #[serde(skip_serializing_if = "Option::is_none")]
66 pub sampling: Option<SamplingCapability>,
67 #[serde(skip_serializing_if = "Option::is_none")]
69 pub elicitation: Option<ElicitationCapability>,
70 #[serde(skip_serializing_if = "Option::is_none")]
72 pub roots: Option<RootsCapability>,
73}
74
75#[derive(Debug, Clone, Default, Serialize, Deserialize)]
77pub struct SamplingCapability {}
78
79#[derive(Debug, Clone, Default, Serialize, Deserialize)]
81pub struct FormElicitationCapability {}
82
83#[derive(Debug, Clone, Default, Serialize, Deserialize)]
85pub struct UrlElicitationCapability {}
86
87#[derive(Debug, Clone, Default, Serialize, Deserialize)]
91pub struct ElicitationCapability {
92 #[serde(skip_serializing_if = "Option::is_none")]
94 pub form: Option<FormElicitationCapability>,
95 #[serde(skip_serializing_if = "Option::is_none")]
97 pub url: Option<UrlElicitationCapability>,
98}
99
100impl ElicitationCapability {
101 #[must_use]
103 pub fn form() -> Self {
104 Self {
105 form: Some(FormElicitationCapability {}),
106 url: None,
107 }
108 }
109
110 #[must_use]
112 pub fn url() -> Self {
113 Self {
114 form: None,
115 url: Some(UrlElicitationCapability {}),
116 }
117 }
118
119 #[must_use]
121 pub fn both() -> Self {
122 Self {
123 form: Some(FormElicitationCapability {}),
124 url: Some(UrlElicitationCapability {}),
125 }
126 }
127
128 #[must_use]
130 pub fn supports_form(&self) -> bool {
131 self.form.is_some()
132 }
133
134 #[must_use]
136 pub fn supports_url(&self) -> bool {
137 self.url.is_some()
138 }
139}
140
141#[derive(Debug, Clone, Default, Serialize, Deserialize)]
143pub struct RootsCapability {
144 #[serde(
146 rename = "listChanged",
147 default,
148 skip_serializing_if = "std::ops::Not::not"
149 )]
150 pub list_changed: bool,
151}
152
153#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
158pub struct Root {
159 pub uri: String,
161 #[serde(skip_serializing_if = "Option::is_none")]
163 pub name: Option<String>,
164}
165
166impl Root {
167 #[must_use]
169 pub fn new(uri: impl Into<String>) -> Self {
170 Self {
171 uri: uri.into(),
172 name: None,
173 }
174 }
175
176 #[must_use]
178 pub fn with_name(uri: impl Into<String>, name: impl Into<String>) -> Self {
179 Self {
180 uri: uri.into(),
181 name: Some(name.into()),
182 }
183 }
184}
185
186#[derive(Debug, Clone, Serialize, Deserialize)]
188pub struct ServerInfo {
189 pub name: String,
191 pub version: String,
193}
194
195#[derive(Debug, Clone, Serialize, Deserialize)]
197pub struct ClientInfo {
198 pub name: String,
200 pub version: String,
202}
203
204#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
213#[serde(rename_all = "camelCase")]
214pub struct Icon {
215 #[serde(skip_serializing_if = "Option::is_none")]
221 pub src: Option<String>,
222
223 #[serde(skip_serializing_if = "Option::is_none")]
225 pub mime_type: Option<String>,
226
227 #[serde(skip_serializing_if = "Option::is_none")]
229 pub sizes: Option<String>,
230}
231
232impl Icon {
233 #[must_use]
235 pub fn new(src: impl Into<String>) -> Self {
236 Self {
237 src: Some(src.into()),
238 mime_type: None,
239 sizes: None,
240 }
241 }
242
243 #[must_use]
245 pub fn with_mime_type(src: impl Into<String>, mime_type: impl Into<String>) -> Self {
246 Self {
247 src: Some(src.into()),
248 mime_type: Some(mime_type.into()),
249 sizes: None,
250 }
251 }
252
253 #[must_use]
255 pub fn full(
256 src: impl Into<String>,
257 mime_type: impl Into<String>,
258 sizes: impl Into<String>,
259 ) -> Self {
260 Self {
261 src: Some(src.into()),
262 mime_type: Some(mime_type.into()),
263 sizes: Some(sizes.into()),
264 }
265 }
266
267 #[must_use]
269 pub fn has_src(&self) -> bool {
270 self.src.is_some()
271 }
272
273 #[must_use]
275 pub fn is_data_uri(&self) -> bool {
276 self.src.as_ref().is_some_and(|s| s.starts_with("data:"))
277 }
278}
279
280#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
289pub struct ToolAnnotations {
290 #[serde(skip_serializing_if = "Option::is_none")]
293 pub destructive: Option<bool>,
294 #[serde(skip_serializing_if = "Option::is_none")]
297 pub idempotent: Option<bool>,
298 #[serde(rename = "readOnly", skip_serializing_if = "Option::is_none")]
301 pub read_only: Option<bool>,
302 #[serde(rename = "openWorldHint", skip_serializing_if = "Option::is_none")]
305 pub open_world_hint: Option<String>,
306}
307
308impl ToolAnnotations {
309 #[must_use]
311 pub fn new() -> Self {
312 Self::default()
313 }
314
315 #[must_use]
317 pub fn destructive(mut self, value: bool) -> Self {
318 self.destructive = Some(value);
319 self
320 }
321
322 #[must_use]
324 pub fn idempotent(mut self, value: bool) -> Self {
325 self.idempotent = Some(value);
326 self
327 }
328
329 #[must_use]
331 pub fn read_only(mut self, value: bool) -> Self {
332 self.read_only = Some(value);
333 self
334 }
335
336 #[must_use]
338 pub fn open_world_hint(mut self, hint: impl Into<String>) -> Self {
339 self.open_world_hint = Some(hint.into());
340 self
341 }
342
343 #[must_use]
345 pub fn is_empty(&self) -> bool {
346 self.destructive.is_none()
347 && self.idempotent.is_none()
348 && self.read_only.is_none()
349 && self.open_world_hint.is_none()
350 }
351}
352
353#[derive(Debug, Clone, Serialize, Deserialize)]
355pub struct Tool {
356 pub name: String,
358 #[serde(skip_serializing_if = "Option::is_none")]
360 pub description: Option<String>,
361 #[serde(rename = "inputSchema")]
363 pub input_schema: serde_json::Value,
364 #[serde(rename = "outputSchema", skip_serializing_if = "Option::is_none")]
366 pub output_schema: Option<serde_json::Value>,
367 #[serde(skip_serializing_if = "Option::is_none")]
369 pub icon: Option<Icon>,
370 #[serde(skip_serializing_if = "Option::is_none")]
372 pub version: Option<String>,
373 #[serde(default, skip_serializing_if = "Vec::is_empty")]
375 pub tags: Vec<String>,
376 #[serde(skip_serializing_if = "Option::is_none")]
378 pub annotations: Option<ToolAnnotations>,
379}
380
381#[derive(Debug, Clone, Serialize, Deserialize)]
383pub struct Resource {
384 pub uri: String,
386 pub name: String,
388 #[serde(skip_serializing_if = "Option::is_none")]
390 pub description: Option<String>,
391 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
393 pub mime_type: Option<String>,
394 #[serde(skip_serializing_if = "Option::is_none")]
396 pub icon: Option<Icon>,
397 #[serde(skip_serializing_if = "Option::is_none")]
399 pub version: Option<String>,
400 #[serde(default, skip_serializing_if = "Vec::is_empty")]
402 pub tags: Vec<String>,
403}
404
405#[derive(Debug, Clone, Serialize, Deserialize)]
407pub struct ResourceTemplate {
408 #[serde(rename = "uriTemplate")]
410 pub uri_template: String,
411 pub name: String,
413 #[serde(skip_serializing_if = "Option::is_none")]
415 pub description: Option<String>,
416 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
418 pub mime_type: Option<String>,
419 #[serde(skip_serializing_if = "Option::is_none")]
421 pub icon: Option<Icon>,
422 #[serde(skip_serializing_if = "Option::is_none")]
424 pub version: Option<String>,
425 #[serde(default, skip_serializing_if = "Vec::is_empty")]
427 pub tags: Vec<String>,
428}
429
430#[derive(Debug, Clone, Serialize, Deserialize)]
432pub struct Prompt {
433 pub name: String,
435 #[serde(skip_serializing_if = "Option::is_none")]
437 pub description: Option<String>,
438 #[serde(default, skip_serializing_if = "Vec::is_empty")]
440 pub arguments: Vec<PromptArgument>,
441 #[serde(skip_serializing_if = "Option::is_none")]
443 pub icon: Option<Icon>,
444 #[serde(skip_serializing_if = "Option::is_none")]
446 pub version: Option<String>,
447 #[serde(default, skip_serializing_if = "Vec::is_empty")]
449 pub tags: Vec<String>,
450}
451
452#[derive(Debug, Clone, Serialize, Deserialize)]
454pub struct PromptArgument {
455 pub name: String,
457 #[serde(skip_serializing_if = "Option::is_none")]
459 pub description: Option<String>,
460 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
462 pub required: bool,
463}
464
465#[derive(Debug, Clone, Serialize, Deserialize)]
467#[serde(tag = "type", rename_all = "lowercase")]
468pub enum Content {
469 Text {
471 text: String,
473 },
474 Image {
476 data: String,
478 #[serde(rename = "mimeType")]
480 mime_type: String,
481 },
482 Resource {
484 resource: ResourceContent,
486 },
487}
488
489#[derive(Debug, Clone, Serialize, Deserialize)]
491pub struct ResourceContent {
492 pub uri: String,
494 #[serde(rename = "mimeType", skip_serializing_if = "Option::is_none")]
496 pub mime_type: Option<String>,
497 #[serde(skip_serializing_if = "Option::is_none")]
499 pub text: Option<String>,
500 #[serde(skip_serializing_if = "Option::is_none")]
502 pub blob: Option<String>,
503}
504
505#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
507#[serde(rename_all = "lowercase")]
508pub enum Role {
509 User,
511 Assistant,
513}
514
515#[derive(Debug, Clone, Serialize, Deserialize)]
517pub struct PromptMessage {
518 pub role: Role,
520 pub content: Content,
522}
523
524#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
532pub struct TaskId(pub String);
533
534impl TaskId {
535 #[must_use]
537 pub fn new() -> Self {
538 use std::time::{SystemTime, UNIX_EPOCH};
539 let timestamp = SystemTime::now()
540 .duration_since(UNIX_EPOCH)
541 .unwrap_or_default()
542 .as_nanos();
543 Self(format!("task-{timestamp:x}"))
544 }
545
546 #[must_use]
548 pub fn from_string(s: impl Into<String>) -> Self {
549 Self(s.into())
550 }
551
552 #[must_use]
554 pub fn as_str(&self) -> &str {
555 &self.0
556 }
557}
558
559impl Default for TaskId {
560 fn default() -> Self {
561 Self::new()
562 }
563}
564
565impl std::fmt::Display for TaskId {
566 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
567 write!(f, "{}", self.0)
568 }
569}
570
571impl From<String> for TaskId {
572 fn from(s: String) -> Self {
573 Self(s)
574 }
575}
576
577impl From<&str> for TaskId {
578 fn from(s: &str) -> Self {
579 Self(s.to_owned())
580 }
581}
582
583#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
585#[serde(rename_all = "lowercase")]
586pub enum TaskStatus {
587 Pending,
589 Running,
591 Completed,
593 Failed,
595 Cancelled,
597}
598
599impl TaskStatus {
600 #[must_use]
602 pub fn is_terminal(&self) -> bool {
603 matches!(
604 self,
605 TaskStatus::Completed | TaskStatus::Failed | TaskStatus::Cancelled
606 )
607 }
608
609 #[must_use]
611 pub fn is_active(&self) -> bool {
612 matches!(self, TaskStatus::Pending | TaskStatus::Running)
613 }
614}
615
616#[derive(Debug, Clone, Serialize, Deserialize)]
618pub struct TaskInfo {
619 pub id: TaskId,
621 #[serde(rename = "taskType")]
623 pub task_type: String,
624 pub status: TaskStatus,
626 #[serde(skip_serializing_if = "Option::is_none")]
628 pub progress: Option<f64>,
629 #[serde(skip_serializing_if = "Option::is_none")]
631 pub message: Option<String>,
632 #[serde(rename = "createdAt")]
634 pub created_at: String,
635 #[serde(rename = "startedAt", skip_serializing_if = "Option::is_none")]
637 pub started_at: Option<String>,
638 #[serde(rename = "completedAt", skip_serializing_if = "Option::is_none")]
640 pub completed_at: Option<String>,
641 #[serde(skip_serializing_if = "Option::is_none")]
643 pub error: Option<String>,
644}
645
646#[derive(Debug, Clone, Serialize, Deserialize)]
648pub struct TaskResult {
649 pub id: TaskId,
651 pub success: bool,
653 #[serde(skip_serializing_if = "Option::is_none")]
655 pub data: Option<serde_json::Value>,
656 #[serde(skip_serializing_if = "Option::is_none")]
658 pub error: Option<String>,
659}
660
661#[derive(Debug, Clone, Default, Serialize, Deserialize)]
663pub struct TasksCapability {
664 #[serde(
666 default,
667 rename = "listChanged",
668 skip_serializing_if = "std::ops::Not::not"
669 )]
670 pub list_changed: bool,
671}
672
673#[derive(Debug, Clone, Serialize, Deserialize)]
681#[serde(tag = "type", rename_all = "lowercase")]
682pub enum SamplingContent {
683 Text {
685 text: String,
687 },
688 Image {
690 data: String,
692 #[serde(rename = "mimeType")]
694 mime_type: String,
695 },
696}
697
698#[derive(Debug, Clone, Serialize, Deserialize)]
700pub struct SamplingMessage {
701 pub role: Role,
703 pub content: SamplingContent,
705}
706
707impl SamplingMessage {
708 #[must_use]
710 pub fn user(text: impl Into<String>) -> Self {
711 Self {
712 role: Role::User,
713 content: SamplingContent::Text { text: text.into() },
714 }
715 }
716
717 #[must_use]
719 pub fn assistant(text: impl Into<String>) -> Self {
720 Self {
721 role: Role::Assistant,
722 content: SamplingContent::Text { text: text.into() },
723 }
724 }
725}
726
727#[derive(Debug, Clone, Default, Serialize, Deserialize)]
729pub struct ModelPreferences {
730 #[serde(default, skip_serializing_if = "Vec::is_empty")]
732 pub hints: Vec<ModelHint>,
733 #[serde(rename = "costPriority", skip_serializing_if = "Option::is_none")]
735 pub cost_priority: Option<f64>,
736 #[serde(rename = "speedPriority", skip_serializing_if = "Option::is_none")]
738 pub speed_priority: Option<f64>,
739 #[serde(
741 rename = "intelligencePriority",
742 skip_serializing_if = "Option::is_none"
743 )]
744 pub intelligence_priority: Option<f64>,
745}
746
747#[derive(Debug, Clone, Serialize, Deserialize)]
749pub struct ModelHint {
750 #[serde(skip_serializing_if = "Option::is_none")]
752 pub name: Option<String>,
753}
754
755#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
757#[serde(rename_all = "camelCase")]
758pub enum StopReason {
759 #[default]
761 EndTurn,
762 StopSequence,
764 MaxTokens,
766}
767
768#[cfg(test)]
773mod tests {
774 use super::*;
775 use serde_json::json;
776
777 #[test]
782 fn server_capabilities_default_serialization() {
783 let caps = ServerCapabilities::default();
784 let value = serde_json::to_value(&caps).expect("serialize");
785 assert_eq!(value, json!({}));
787 }
788
789 #[test]
790 fn server_capabilities_full_serialization() {
791 let caps = ServerCapabilities {
792 tools: Some(ToolsCapability { list_changed: true }),
793 resources: Some(ResourcesCapability {
794 subscribe: true,
795 list_changed: true,
796 }),
797 prompts: Some(PromptsCapability { list_changed: true }),
798 logging: Some(LoggingCapability {}),
799 tasks: Some(TasksCapability { list_changed: true }),
800 };
801 let value = serde_json::to_value(&caps).expect("serialize");
802 assert_eq!(value["tools"]["list_changed"], true);
803 assert_eq!(value["resources"]["subscribe"], true);
804 assert_eq!(value["resources"]["list_changed"], true);
805 assert_eq!(value["prompts"]["list_changed"], true);
806 assert!(value.get("logging").is_some());
807 assert_eq!(value["tasks"]["listChanged"], true);
808 }
809
810 #[test]
811 fn server_capabilities_partial_serialization() {
812 let caps = ServerCapabilities {
813 tools: Some(ToolsCapability::default()),
814 ..Default::default()
815 };
816 let value = serde_json::to_value(&caps).expect("serialize");
817 assert!(value.get("tools").is_some());
818 assert!(value.get("resources").is_none());
819 assert!(value.get("prompts").is_none());
820 assert!(value.get("logging").is_none());
821 assert!(value.get("tasks").is_none());
822 }
823
824 #[test]
825 fn server_capabilities_round_trip() {
826 let caps = ServerCapabilities {
827 tools: Some(ToolsCapability { list_changed: true }),
828 resources: Some(ResourcesCapability {
829 subscribe: false,
830 list_changed: true,
831 }),
832 prompts: None,
833 logging: Some(LoggingCapability {}),
834 tasks: None,
835 };
836 let json_str = serde_json::to_string(&caps).expect("serialize");
837 let deserialized: ServerCapabilities =
838 serde_json::from_str(&json_str).expect("deserialize");
839 assert!(deserialized.tools.is_some());
840 assert!(deserialized.tools.as_ref().unwrap().list_changed);
841 assert!(deserialized.resources.is_some());
842 assert!(!deserialized.resources.as_ref().unwrap().subscribe);
843 assert!(deserialized.prompts.is_none());
844 assert!(deserialized.logging.is_some());
845 assert!(deserialized.tasks.is_none());
846 }
847
848 #[test]
853 fn tools_capability_default_omits_false() {
854 let cap = ToolsCapability::default();
855 let value = serde_json::to_value(&cap).expect("serialize");
856 assert!(value.get("list_changed").is_none());
858 }
859
860 #[test]
861 fn tools_capability_list_changed() {
862 let cap = ToolsCapability { list_changed: true };
863 let value = serde_json::to_value(&cap).expect("serialize");
864 assert_eq!(value["list_changed"], true);
865 }
866
867 #[test]
872 fn resources_capability_default() {
873 let cap = ResourcesCapability::default();
874 let value = serde_json::to_value(&cap).expect("serialize");
875 assert!(value.get("subscribe").is_none());
876 assert!(value.get("list_changed").is_none());
877 }
878
879 #[test]
880 fn resources_capability_full() {
881 let cap = ResourcesCapability {
882 subscribe: true,
883 list_changed: true,
884 };
885 let value = serde_json::to_value(&cap).expect("serialize");
886 assert_eq!(value["subscribe"], true);
887 assert_eq!(value["list_changed"], true);
888 }
889
890 #[test]
895 fn client_capabilities_default_serialization() {
896 let caps = ClientCapabilities::default();
897 let value = serde_json::to_value(&caps).expect("serialize");
898 assert_eq!(value, json!({}));
899 }
900
901 #[test]
902 fn client_capabilities_full_serialization() {
903 let caps = ClientCapabilities {
904 sampling: Some(SamplingCapability {}),
905 elicitation: Some(ElicitationCapability::both()),
906 roots: Some(RootsCapability { list_changed: true }),
907 };
908 let value = serde_json::to_value(&caps).expect("serialize");
909 assert!(value.get("sampling").is_some());
910 assert!(value.get("elicitation").is_some());
911 assert_eq!(value["roots"]["listChanged"], true);
912 }
913
914 #[test]
915 fn client_capabilities_round_trip() {
916 let caps = ClientCapabilities {
917 sampling: Some(SamplingCapability {}),
918 elicitation: None,
919 roots: Some(RootsCapability {
920 list_changed: false,
921 }),
922 };
923 let json_str = serde_json::to_string(&caps).expect("serialize");
924 let deserialized: ClientCapabilities =
925 serde_json::from_str(&json_str).expect("deserialize");
926 assert!(deserialized.sampling.is_some());
927 assert!(deserialized.elicitation.is_none());
928 assert!(deserialized.roots.is_some());
929 }
930
931 #[test]
936 fn elicitation_capability_form_only() {
937 let cap = ElicitationCapability::form();
938 assert!(cap.supports_form());
939 assert!(!cap.supports_url());
940 let value = serde_json::to_value(&cap).expect("serialize");
941 assert!(value.get("form").is_some());
942 assert!(value.get("url").is_none());
943 }
944
945 #[test]
946 fn elicitation_capability_url_only() {
947 let cap = ElicitationCapability::url();
948 assert!(!cap.supports_form());
949 assert!(cap.supports_url());
950 }
951
952 #[test]
953 fn elicitation_capability_both() {
954 let cap = ElicitationCapability::both();
955 assert!(cap.supports_form());
956 assert!(cap.supports_url());
957 }
958
959 #[test]
964 fn server_info_serialization() {
965 let info = ServerInfo {
966 name: "test-server".to_string(),
967 version: "1.0.0".to_string(),
968 };
969 let value = serde_json::to_value(&info).expect("serialize");
970 assert_eq!(value["name"], "test-server");
971 assert_eq!(value["version"], "1.0.0");
972 }
973
974 #[test]
975 fn client_info_serialization() {
976 let info = ClientInfo {
977 name: "test-client".to_string(),
978 version: "0.1.0".to_string(),
979 };
980 let value = serde_json::to_value(&info).expect("serialize");
981 assert_eq!(value["name"], "test-client");
982 assert_eq!(value["version"], "0.1.0");
983 }
984
985 #[test]
990 fn icon_new() {
991 let icon = Icon::new("https://example.com/icon.png");
992 assert!(icon.has_src());
993 assert!(!icon.is_data_uri());
994 assert!(icon.mime_type.is_none());
995 assert!(icon.sizes.is_none());
996 }
997
998 #[test]
999 fn icon_with_mime_type() {
1000 let icon = Icon::with_mime_type("https://example.com/icon.png", "image/png");
1001 assert!(icon.has_src());
1002 assert_eq!(icon.mime_type, Some("image/png".to_string()));
1003 }
1004
1005 #[test]
1006 fn icon_full() {
1007 let icon = Icon::full("https://example.com/icon.png", "image/png", "32x32");
1008 assert_eq!(icon.src, Some("https://example.com/icon.png".to_string()));
1009 assert_eq!(icon.mime_type, Some("image/png".to_string()));
1010 assert_eq!(icon.sizes, Some("32x32".to_string()));
1011 }
1012
1013 #[test]
1014 fn icon_data_uri() {
1015 let icon = Icon::new("data:image/png;base64,iVBORw0KGgo=");
1016 assert!(icon.is_data_uri());
1017 }
1018
1019 #[test]
1020 fn icon_default_no_src() {
1021 let icon = Icon::default();
1022 assert!(!icon.has_src());
1023 assert!(!icon.is_data_uri());
1024 }
1025
1026 #[test]
1027 fn icon_serialization() {
1028 let icon = Icon::full(
1029 "https://example.com/icon.svg",
1030 "image/svg+xml",
1031 "16x16 32x32",
1032 );
1033 let value = serde_json::to_value(&icon).expect("serialize");
1034 assert_eq!(value["src"], "https://example.com/icon.svg");
1035 assert_eq!(value["mimeType"], "image/svg+xml");
1036 assert_eq!(value["sizes"], "16x16 32x32");
1037 }
1038
1039 #[test]
1040 fn icon_serialization_omits_none_fields() {
1041 let icon = Icon::new("https://example.com/icon.png");
1042 let value = serde_json::to_value(&icon).expect("serialize");
1043 assert!(value.get("src").is_some());
1044 assert!(value.get("mimeType").is_none());
1045 assert!(value.get("sizes").is_none());
1046 }
1047
1048 #[test]
1049 fn icon_equality() {
1050 let a = Icon::new("https://example.com/icon.png");
1051 let b = Icon::new("https://example.com/icon.png");
1052 let c = Icon::new("https://example.com/other.png");
1053 assert_eq!(a, b);
1054 assert_ne!(a, c);
1055 }
1056
1057 #[test]
1062 fn content_text_serialization() {
1063 let content = Content::Text {
1064 text: "Hello, world!".to_string(),
1065 };
1066 let value = serde_json::to_value(&content).expect("serialize");
1067 assert_eq!(value["type"], "text");
1068 assert_eq!(value["text"], "Hello, world!");
1069 }
1070
1071 #[test]
1072 fn content_image_serialization() {
1073 let content = Content::Image {
1074 data: "iVBORw0KGgo=".to_string(),
1075 mime_type: "image/png".to_string(),
1076 };
1077 let value = serde_json::to_value(&content).expect("serialize");
1078 assert_eq!(value["type"], "image");
1079 assert_eq!(value["data"], "iVBORw0KGgo=");
1080 assert_eq!(value["mimeType"], "image/png");
1081 }
1082
1083 #[test]
1084 fn content_resource_serialization() {
1085 let content = Content::Resource {
1086 resource: ResourceContent {
1087 uri: "file://config.json".to_string(),
1088 mime_type: Some("application/json".to_string()),
1089 text: Some("{\"key\": \"value\"}".to_string()),
1090 blob: None,
1091 },
1092 };
1093 let value = serde_json::to_value(&content).expect("serialize");
1094 assert_eq!(value["type"], "resource");
1095 assert_eq!(value["resource"]["uri"], "file://config.json");
1096 assert_eq!(value["resource"]["mimeType"], "application/json");
1097 assert_eq!(value["resource"]["text"], "{\"key\": \"value\"}");
1098 assert!(value["resource"].get("blob").is_none());
1099 }
1100
1101 #[test]
1102 fn content_text_deserialization() {
1103 let json = json!({"type": "text", "text": "Hello!"});
1104 let content: Content = serde_json::from_value(json).expect("deserialize");
1105 match content {
1106 Content::Text { text } => assert_eq!(text, "Hello!"),
1107 _ => panic!("Expected text content"),
1108 }
1109 }
1110
1111 #[test]
1112 fn content_image_deserialization() {
1113 let json = json!({"type": "image", "data": "abc123", "mimeType": "image/jpeg"});
1114 let content: Content = serde_json::from_value(json).expect("deserialize");
1115 match content {
1116 Content::Image { data, mime_type } => {
1117 assert_eq!(data, "abc123");
1118 assert_eq!(mime_type, "image/jpeg");
1119 }
1120 _ => panic!("Expected image content"),
1121 }
1122 }
1123
1124 #[test]
1129 fn resource_content_text_serialization() {
1130 let rc = ResourceContent {
1131 uri: "file://readme.md".to_string(),
1132 mime_type: Some("text/markdown".to_string()),
1133 text: Some("# Hello".to_string()),
1134 blob: None,
1135 };
1136 let value = serde_json::to_value(&rc).expect("serialize");
1137 assert_eq!(value["uri"], "file://readme.md");
1138 assert_eq!(value["mimeType"], "text/markdown");
1139 assert_eq!(value["text"], "# Hello");
1140 assert!(value.get("blob").is_none());
1141 }
1142
1143 #[test]
1144 fn resource_content_blob_serialization() {
1145 let rc = ResourceContent {
1146 uri: "file://image.png".to_string(),
1147 mime_type: Some("image/png".to_string()),
1148 text: None,
1149 blob: Some("base64data".to_string()),
1150 };
1151 let value = serde_json::to_value(&rc).expect("serialize");
1152 assert_eq!(value["uri"], "file://image.png");
1153 assert!(value.get("text").is_none());
1154 assert_eq!(value["blob"], "base64data");
1155 }
1156
1157 #[test]
1158 fn resource_content_minimal() {
1159 let rc = ResourceContent {
1160 uri: "file://test".to_string(),
1161 mime_type: None,
1162 text: None,
1163 blob: None,
1164 };
1165 let value = serde_json::to_value(&rc).expect("serialize");
1166 assert_eq!(value["uri"], "file://test");
1167 assert!(value.get("mimeType").is_none());
1168 assert!(value.get("text").is_none());
1169 assert!(value.get("blob").is_none());
1170 }
1171
1172 #[test]
1177 fn role_serialization() {
1178 assert_eq!(serde_json::to_value(Role::User).unwrap(), "user");
1179 assert_eq!(serde_json::to_value(Role::Assistant).unwrap(), "assistant");
1180 }
1181
1182 #[test]
1183 fn role_deserialization() {
1184 let user: Role = serde_json::from_value(json!("user")).expect("deserialize");
1185 assert_eq!(user, Role::User);
1186 let assistant: Role = serde_json::from_value(json!("assistant")).expect("deserialize");
1187 assert_eq!(assistant, Role::Assistant);
1188 }
1189
1190 #[test]
1195 fn prompt_message_serialization() {
1196 let msg = PromptMessage {
1197 role: Role::User,
1198 content: Content::Text {
1199 text: "Tell me a joke".to_string(),
1200 },
1201 };
1202 let value = serde_json::to_value(&msg).expect("serialize");
1203 assert_eq!(value["role"], "user");
1204 assert_eq!(value["content"]["type"], "text");
1205 assert_eq!(value["content"]["text"], "Tell me a joke");
1206 }
1207
1208 #[test]
1209 fn prompt_message_assistant() {
1210 let msg = PromptMessage {
1211 role: Role::Assistant,
1212 content: Content::Text {
1213 text: "Here's a joke...".to_string(),
1214 },
1215 };
1216 let value = serde_json::to_value(&msg).expect("serialize");
1217 assert_eq!(value["role"], "assistant");
1218 }
1219
1220 #[test]
1225 fn prompt_argument_required() {
1226 let arg = PromptArgument {
1227 name: "language".to_string(),
1228 description: Some("Target language".to_string()),
1229 required: true,
1230 };
1231 let value = serde_json::to_value(&arg).expect("serialize");
1232 assert_eq!(value["name"], "language");
1233 assert_eq!(value["description"], "Target language");
1234 assert_eq!(value["required"], true);
1235 }
1236
1237 #[test]
1238 fn prompt_argument_optional_omits_false() {
1239 let arg = PromptArgument {
1240 name: "style".to_string(),
1241 description: None,
1242 required: false,
1243 };
1244 let value = serde_json::to_value(&arg).expect("serialize");
1245 assert_eq!(value["name"], "style");
1246 assert!(value.get("description").is_none());
1247 assert!(value.get("required").is_none());
1249 }
1250
1251 #[test]
1252 fn prompt_argument_deserialization_defaults() {
1253 let json = json!({"name": "arg1"});
1254 let arg: PromptArgument = serde_json::from_value(json).expect("deserialize");
1255 assert_eq!(arg.name, "arg1");
1256 assert!(arg.description.is_none());
1257 assert!(!arg.required);
1258 }
1259
1260 #[test]
1265 fn tool_minimal_serialization() {
1266 let tool = Tool {
1267 name: "add".to_string(),
1268 description: None,
1269 input_schema: json!({"type": "object"}),
1270 output_schema: None,
1271 icon: None,
1272 version: None,
1273 tags: vec![],
1274 annotations: None,
1275 };
1276 let value = serde_json::to_value(&tool).expect("serialize");
1277 assert_eq!(value["name"], "add");
1278 assert_eq!(value["inputSchema"]["type"], "object");
1279 assert!(value.get("description").is_none());
1280 assert!(value.get("outputSchema").is_none());
1281 assert!(value.get("icon").is_none());
1282 assert!(value.get("version").is_none());
1283 assert!(value.get("tags").is_none());
1284 assert!(value.get("annotations").is_none());
1285 }
1286
1287 #[test]
1288 fn tool_full_serialization() {
1289 let tool = Tool {
1290 name: "compute".to_string(),
1291 description: Some("Runs a computation".to_string()),
1292 input_schema: json!({
1293 "type": "object",
1294 "properties": { "x": { "type": "number" } },
1295 "required": ["x"]
1296 }),
1297 output_schema: Some(json!({"type": "number"})),
1298 icon: Some(Icon::new("https://example.com/icon.png")),
1299 version: Some("2.1.0".to_string()),
1300 tags: vec!["math".to_string(), "compute".to_string()],
1301 annotations: Some(ToolAnnotations::new().read_only(true).idempotent(true)),
1302 };
1303 let value = serde_json::to_value(&tool).expect("serialize");
1304 assert_eq!(value["name"], "compute");
1305 assert_eq!(value["description"], "Runs a computation");
1306 assert!(value["inputSchema"]["properties"]["x"].is_object());
1307 assert_eq!(value["outputSchema"]["type"], "number");
1308 assert_eq!(value["icon"]["src"], "https://example.com/icon.png");
1309 assert_eq!(value["version"], "2.1.0");
1310 assert_eq!(value["tags"], json!(["math", "compute"]));
1311 assert_eq!(value["annotations"]["readOnly"], true);
1312 assert_eq!(value["annotations"]["idempotent"], true);
1313 }
1314
1315 #[test]
1316 fn tool_round_trip() {
1317 let json = json!({
1318 "name": "greet",
1319 "description": "Greets the user",
1320 "inputSchema": {"type": "object", "properties": {"name": {"type": "string"}}},
1321 "outputSchema": {"type": "string"},
1322 "version": "1.0.0",
1323 "tags": ["greeting"],
1324 "annotations": {"readOnly": true}
1325 });
1326 let tool: Tool = serde_json::from_value(json.clone()).expect("deserialize");
1327 assert_eq!(tool.name, "greet");
1328 assert_eq!(tool.version, Some("1.0.0".to_string()));
1329 assert_eq!(tool.tags, vec!["greeting"]);
1330 assert!(tool.annotations.as_ref().unwrap().read_only.unwrap());
1331 let re_serialized = serde_json::to_value(&tool).expect("re-serialize");
1332 assert_eq!(re_serialized["name"], json["name"]);
1333 }
1334
1335 #[test]
1340 fn resource_minimal_serialization() {
1341 let resource = Resource {
1342 uri: "file://test.txt".to_string(),
1343 name: "Test File".to_string(),
1344 description: None,
1345 mime_type: None,
1346 icon: None,
1347 version: None,
1348 tags: vec![],
1349 };
1350 let value = serde_json::to_value(&resource).expect("serialize");
1351 assert_eq!(value["uri"], "file://test.txt");
1352 assert_eq!(value["name"], "Test File");
1353 assert!(value.get("description").is_none());
1354 assert!(value.get("mimeType").is_none());
1355 }
1356
1357 #[test]
1358 fn resource_full_round_trip() {
1359 let json = json!({
1360 "uri": "file://config.json",
1361 "name": "Config",
1362 "description": "Application configuration",
1363 "mimeType": "application/json",
1364 "version": "3.0.0",
1365 "tags": ["config", "json"]
1366 });
1367 let resource: Resource = serde_json::from_value(json).expect("deserialize");
1368 assert_eq!(resource.uri, "file://config.json");
1369 assert_eq!(resource.mime_type, Some("application/json".to_string()));
1370 assert_eq!(resource.tags, vec!["config", "json"]);
1371 }
1372
1373 #[test]
1378 fn resource_template_serialization() {
1379 let template = ResourceTemplate {
1380 uri_template: "file://{path}".to_string(),
1381 name: "File Reader".to_string(),
1382 description: Some("Read any file".to_string()),
1383 mime_type: Some("text/plain".to_string()),
1384 icon: None,
1385 version: None,
1386 tags: vec![],
1387 };
1388 let value = serde_json::to_value(&template).expect("serialize");
1389 assert_eq!(value["uriTemplate"], "file://{path}");
1390 assert_eq!(value["name"], "File Reader");
1391 assert_eq!(value["description"], "Read any file");
1392 assert_eq!(value["mimeType"], "text/plain");
1393 }
1394
1395 #[test]
1400 fn prompt_with_arguments() {
1401 let prompt = Prompt {
1402 name: "translate".to_string(),
1403 description: Some("Translate text".to_string()),
1404 arguments: vec![
1405 PromptArgument {
1406 name: "text".to_string(),
1407 description: Some("Text to translate".to_string()),
1408 required: true,
1409 },
1410 PromptArgument {
1411 name: "language".to_string(),
1412 description: Some("Target language".to_string()),
1413 required: true,
1414 },
1415 PromptArgument {
1416 name: "style".to_string(),
1417 description: None,
1418 required: false,
1419 },
1420 ],
1421 icon: None,
1422 version: None,
1423 tags: vec![],
1424 };
1425 let value = serde_json::to_value(&prompt).expect("serialize");
1426 assert_eq!(value["name"], "translate");
1427 let args = value["arguments"].as_array().expect("arguments array");
1428 assert_eq!(args.len(), 3);
1429 assert_eq!(args[0]["name"], "text");
1430 assert_eq!(args[0]["required"], true);
1431 assert_eq!(args[2]["name"], "style");
1432 assert!(args[2].get("required").is_none());
1434 }
1435
1436 #[test]
1437 fn prompt_empty_arguments_omitted() {
1438 let prompt = Prompt {
1439 name: "simple".to_string(),
1440 description: None,
1441 arguments: vec![],
1442 icon: None,
1443 version: None,
1444 tags: vec![],
1445 };
1446 let value = serde_json::to_value(&prompt).expect("serialize");
1447 assert!(value.get("arguments").is_none());
1448 }
1449
1450 #[test]
1455 fn task_id_new_has_prefix() {
1456 let id = TaskId::new();
1457 assert!(id.as_str().starts_with("task-"));
1458 }
1459
1460 #[test]
1461 fn task_id_from_string() {
1462 let id = TaskId::from_string("task-abc123");
1463 assert_eq!(id.as_str(), "task-abc123");
1464 }
1465
1466 #[test]
1467 fn task_id_display() {
1468 let id = TaskId::from_string("task-xyz");
1469 assert_eq!(format!("{id}"), "task-xyz");
1470 }
1471
1472 #[test]
1473 fn task_id_from_impls() {
1474 let from_string: TaskId = "my-task".to_string().into();
1475 assert_eq!(from_string.as_str(), "my-task");
1476
1477 let from_str: TaskId = "another-task".into();
1478 assert_eq!(from_str.as_str(), "another-task");
1479 }
1480
1481 #[test]
1482 fn task_id_serialization() {
1483 let id = TaskId::from_string("task-1");
1484 let value = serde_json::to_value(&id).expect("serialize");
1485 assert_eq!(value, "task-1");
1486
1487 let deserialized: TaskId = serde_json::from_value(json!("task-2")).expect("deserialize");
1488 assert_eq!(deserialized.as_str(), "task-2");
1489 }
1490
1491 #[test]
1492 fn task_id_equality() {
1493 let a = TaskId::from_string("task-1");
1494 let b = TaskId::from_string("task-1");
1495 let c = TaskId::from_string("task-2");
1496 assert_eq!(a, b);
1497 assert_ne!(a, c);
1498 }
1499
1500 #[test]
1505 fn task_status_is_terminal() {
1506 assert!(TaskStatus::Completed.is_terminal());
1507 assert!(TaskStatus::Failed.is_terminal());
1508 assert!(TaskStatus::Cancelled.is_terminal());
1509 assert!(!TaskStatus::Pending.is_terminal());
1510 assert!(!TaskStatus::Running.is_terminal());
1511 }
1512
1513 #[test]
1514 fn task_status_is_active() {
1515 assert!(TaskStatus::Pending.is_active());
1516 assert!(TaskStatus::Running.is_active());
1517 assert!(!TaskStatus::Completed.is_active());
1518 assert!(!TaskStatus::Failed.is_active());
1519 assert!(!TaskStatus::Cancelled.is_active());
1520 }
1521
1522 #[test]
1523 fn task_status_serialization() {
1524 assert_eq!(
1525 serde_json::to_value(TaskStatus::Pending).unwrap(),
1526 "pending"
1527 );
1528 assert_eq!(
1529 serde_json::to_value(TaskStatus::Running).unwrap(),
1530 "running"
1531 );
1532 assert_eq!(
1533 serde_json::to_value(TaskStatus::Completed).unwrap(),
1534 "completed"
1535 );
1536 assert_eq!(serde_json::to_value(TaskStatus::Failed).unwrap(), "failed");
1537 assert_eq!(
1538 serde_json::to_value(TaskStatus::Cancelled).unwrap(),
1539 "cancelled"
1540 );
1541 }
1542
1543 #[test]
1544 fn task_status_deserialization() {
1545 assert_eq!(
1546 serde_json::from_value::<TaskStatus>(json!("pending")).unwrap(),
1547 TaskStatus::Pending
1548 );
1549 assert_eq!(
1550 serde_json::from_value::<TaskStatus>(json!("running")).unwrap(),
1551 TaskStatus::Running
1552 );
1553 assert_eq!(
1554 serde_json::from_value::<TaskStatus>(json!("completed")).unwrap(),
1555 TaskStatus::Completed
1556 );
1557 assert_eq!(
1558 serde_json::from_value::<TaskStatus>(json!("failed")).unwrap(),
1559 TaskStatus::Failed
1560 );
1561 assert_eq!(
1562 serde_json::from_value::<TaskStatus>(json!("cancelled")).unwrap(),
1563 TaskStatus::Cancelled
1564 );
1565 }
1566
1567 #[test]
1572 fn task_info_serialization() {
1573 let info = TaskInfo {
1574 id: TaskId::from_string("task-1"),
1575 task_type: "compute".to_string(),
1576 status: TaskStatus::Running,
1577 progress: Some(0.5),
1578 message: Some("Processing...".to_string()),
1579 created_at: "2026-01-28T00:00:00Z".to_string(),
1580 started_at: Some("2026-01-28T00:01:00Z".to_string()),
1581 completed_at: None,
1582 error: None,
1583 };
1584 let value = serde_json::to_value(&info).expect("serialize");
1585 assert_eq!(value["id"], "task-1");
1586 assert_eq!(value["taskType"], "compute");
1587 assert_eq!(value["status"], "running");
1588 assert_eq!(value["progress"], 0.5);
1589 assert_eq!(value["message"], "Processing...");
1590 assert_eq!(value["createdAt"], "2026-01-28T00:00:00Z");
1591 assert_eq!(value["startedAt"], "2026-01-28T00:01:00Z");
1592 assert!(value.get("completedAt").is_none());
1593 assert!(value.get("error").is_none());
1594 }
1595
1596 #[test]
1597 fn task_info_minimal() {
1598 let json = json!({
1599 "id": "task-2",
1600 "taskType": "demo",
1601 "status": "pending",
1602 "createdAt": "2026-01-28T00:00:00Z"
1603 });
1604 let info: TaskInfo = serde_json::from_value(json).expect("deserialize");
1605 assert_eq!(info.id.as_str(), "task-2");
1606 assert_eq!(info.status, TaskStatus::Pending);
1607 assert!(info.progress.is_none());
1608 assert!(info.message.is_none());
1609 }
1610
1611 #[test]
1616 fn task_result_success() {
1617 let result = TaskResult {
1618 id: TaskId::from_string("task-1"),
1619 success: true,
1620 data: Some(json!({"value": 42})),
1621 error: None,
1622 };
1623 let value = serde_json::to_value(&result).expect("serialize");
1624 assert_eq!(value["id"], "task-1");
1625 assert_eq!(value["success"], true);
1626 assert_eq!(value["data"]["value"], 42);
1627 assert!(value.get("error").is_none());
1628 }
1629
1630 #[test]
1631 fn task_result_failure() {
1632 let result = TaskResult {
1633 id: TaskId::from_string("task-2"),
1634 success: false,
1635 data: None,
1636 error: Some("computation failed".to_string()),
1637 };
1638 let value = serde_json::to_value(&result).expect("serialize");
1639 assert_eq!(value["success"], false);
1640 assert!(value.get("data").is_none());
1641 assert_eq!(value["error"], "computation failed");
1642 }
1643
1644 #[test]
1649 fn sampling_content_text_serialization() {
1650 let content = SamplingContent::Text {
1651 text: "Hello".to_string(),
1652 };
1653 let value = serde_json::to_value(&content).expect("serialize");
1654 assert_eq!(value["type"], "text");
1655 assert_eq!(value["text"], "Hello");
1656 }
1657
1658 #[test]
1659 fn sampling_content_image_serialization() {
1660 let content = SamplingContent::Image {
1661 data: "base64data".to_string(),
1662 mime_type: "image/png".to_string(),
1663 };
1664 let value = serde_json::to_value(&content).expect("serialize");
1665 assert_eq!(value["type"], "image");
1666 assert_eq!(value["data"], "base64data");
1667 assert_eq!(value["mimeType"], "image/png");
1668 }
1669
1670 #[test]
1675 fn sampling_message_user_constructor() {
1676 let msg = SamplingMessage::user("Hello!");
1677 let value = serde_json::to_value(&msg).expect("serialize");
1678 assert_eq!(value["role"], "user");
1679 assert_eq!(value["content"]["type"], "text");
1680 assert_eq!(value["content"]["text"], "Hello!");
1681 }
1682
1683 #[test]
1684 fn sampling_message_assistant_constructor() {
1685 let msg = SamplingMessage::assistant("Hi there!");
1686 let value = serde_json::to_value(&msg).expect("serialize");
1687 assert_eq!(value["role"], "assistant");
1688 assert_eq!(value["content"]["text"], "Hi there!");
1689 }
1690
1691 #[test]
1696 fn model_preferences_default() {
1697 let prefs = ModelPreferences::default();
1698 let value = serde_json::to_value(&prefs).expect("serialize");
1699 assert!(value.get("hints").is_none());
1701 assert!(value.get("costPriority").is_none());
1702 assert!(value.get("speedPriority").is_none());
1703 assert!(value.get("intelligencePriority").is_none());
1704 }
1705
1706 #[test]
1707 fn model_preferences_full() {
1708 let prefs = ModelPreferences {
1709 hints: vec![ModelHint {
1710 name: Some("claude-3".to_string()),
1711 }],
1712 cost_priority: Some(0.3),
1713 speed_priority: Some(0.5),
1714 intelligence_priority: Some(0.9),
1715 };
1716 let value = serde_json::to_value(&prefs).expect("serialize");
1717 assert_eq!(value["hints"][0]["name"], "claude-3");
1718 assert_eq!(value["costPriority"], 0.3);
1719 assert_eq!(value["speedPriority"], 0.5);
1720 assert_eq!(value["intelligencePriority"], 0.9);
1721 }
1722
1723 #[test]
1728 fn stop_reason_serialization() {
1729 assert_eq!(
1730 serde_json::to_value(StopReason::EndTurn).unwrap(),
1731 "endTurn"
1732 );
1733 assert_eq!(
1734 serde_json::to_value(StopReason::StopSequence).unwrap(),
1735 "stopSequence"
1736 );
1737 assert_eq!(
1738 serde_json::to_value(StopReason::MaxTokens).unwrap(),
1739 "maxTokens"
1740 );
1741 }
1742
1743 #[test]
1744 fn stop_reason_deserialization() {
1745 assert_eq!(
1746 serde_json::from_value::<StopReason>(json!("endTurn")).unwrap(),
1747 StopReason::EndTurn
1748 );
1749 assert_eq!(
1750 serde_json::from_value::<StopReason>(json!("stopSequence")).unwrap(),
1751 StopReason::StopSequence
1752 );
1753 assert_eq!(
1754 serde_json::from_value::<StopReason>(json!("maxTokens")).unwrap(),
1755 StopReason::MaxTokens
1756 );
1757 }
1758
1759 #[test]
1760 fn stop_reason_default() {
1761 assert_eq!(StopReason::default(), StopReason::EndTurn);
1762 }
1763
1764 #[test]
1769 fn protocol_version_value() {
1770 assert_eq!(PROTOCOL_VERSION, "2024-11-05");
1771 }
1772}