gglib_core/domain/agent/
messages_serde.rs1use serde::ser::SerializeMap;
8use serde::{Deserialize, Serialize};
9
10use super::messages::AssistantContent;
11use super::tool_types::ToolCall;
12
13impl Serialize for AssistantContent {
18 fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
19 let has_text = self.text.is_some();
20 let has_calls = !self.tool_calls.is_empty();
21 let count = usize::from(has_text) + usize::from(has_calls);
22 let mut m = serializer.serialize_map(Some(count))?;
23 if let Some(text) = &self.text {
24 m.serialize_entry("content", text)?;
25 }
26 if has_calls {
27 m.serialize_entry("tool_calls", &self.tool_calls)?;
28 }
29 m.end()
30 }
31}
32
33impl<'de> Deserialize<'de> for AssistantContent {
38 fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
39 deserializer.deserialize_map(AssistantContentVisitor)
40 }
41}
42
43struct AssistantContentVisitor;
49
50impl<'de> serde::de::Visitor<'de> for AssistantContentVisitor {
51 type Value = AssistantContent;
52
53 fn expecting(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
54 f.write_str("assistant message with `content` and/or `tool_calls`")
55 }
56
57 fn visit_map<A: serde::de::MapAccess<'de>>(self, mut map: A) -> Result<Self::Value, A::Error> {
58 let mut content: Option<String> = None;
59 let mut tool_calls: Option<Vec<ToolCall>> = None;
60 while let Some(key) = map.next_key::<String>()? {
61 match key.as_str() {
62 "content" => content = map.next_value()?,
63 "tool_calls" => tool_calls = map.next_value()?,
64 _ => {
65 map.next_value::<serde::de::IgnoredAny>()?;
66 }
67 }
68 }
69 let tool_calls = tool_calls.unwrap_or_default();
70 if content.is_none() && tool_calls.is_empty() {
71 return Err(serde::de::Error::custom(
72 "assistant message must have `content` or `tool_calls`",
73 ));
74 }
75 Ok(AssistantContent {
76 text: content,
77 tool_calls,
78 })
79 }
80}