a2a_protocol_types/
artifact.rs1use serde::{Deserialize, Serialize};
12
13use crate::message::Part;
14
15#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
21pub struct ArtifactId(pub String);
22
23impl ArtifactId {
24 #[must_use]
26 pub fn new(s: impl Into<String>) -> Self {
27 Self(s.into())
28 }
29}
30
31impl std::fmt::Display for ArtifactId {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.write_str(&self.0)
34 }
35}
36
37impl From<String> for ArtifactId {
38 fn from(s: String) -> Self {
39 Self(s)
40 }
41}
42
43impl From<&str> for ArtifactId {
44 fn from(s: &str) -> Self {
45 Self(s.to_owned())
46 }
47}
48
49impl AsRef<str> for ArtifactId {
50 fn as_ref(&self) -> &str {
51 &self.0
52 }
53}
54
55#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
62#[serde(rename_all = "camelCase")]
63pub struct Artifact {
64 #[serde(rename = "artifactId")]
66 pub id: ArtifactId,
67
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub name: Option<String>,
71
72 #[serde(skip_serializing_if = "Option::is_none")]
74 pub description: Option<String>,
75
76 pub parts: Vec<Part>,
81
82 #[serde(skip_serializing_if = "Option::is_none")]
84 pub extensions: Option<Vec<String>>,
85
86 #[serde(skip_serializing_if = "Option::is_none")]
88 pub metadata: Option<serde_json::Value>,
89}
90
91impl Artifact {
92 #[must_use]
94 pub fn new(id: impl Into<ArtifactId>, parts: Vec<Part>) -> Self {
95 Self {
96 id: id.into(),
97 name: None,
98 description: None,
99 parts,
100 extensions: None,
101 metadata: None,
102 }
103 }
104}
105
106#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::message::Part;
112
113 #[test]
114 fn artifact_roundtrip() {
115 let artifact = Artifact::new("art-1", vec![Part::text("result content")]);
116 let json = serde_json::to_string(&artifact).expect("serialize");
117 assert!(json.contains("\"artifactId\":\"art-1\""));
118 assert!(json.contains("\"text\":\"result content\""));
119
120 let back: Artifact = serde_json::from_str(&json).expect("deserialize");
121 assert_eq!(back.id, ArtifactId::new("art-1"));
122 assert_eq!(back.parts.len(), 1);
123 }
124
125 #[test]
126 fn optional_fields_omitted() {
127 let artifact = Artifact::new("art-2", vec![Part::text("x")]);
128 let json = serde_json::to_string(&artifact).expect("serialize");
129 assert!(!json.contains("\"name\""), "name should be omitted");
130 assert!(
131 !json.contains("\"description\""),
132 "description should be omitted"
133 );
134 assert!(!json.contains("\"metadata\""), "metadata should be omitted");
135 }
136
137 #[test]
138 fn artifact_id_display() {
139 let id = ArtifactId::new("my-artifact");
140 assert_eq!(id.to_string(), "my-artifact");
141 }
142}