vv_agent/types/dict/
messages.rs1use super::common::*;
2use super::*;
3
4impl Message {
5 pub fn to_openai_message(&self, include_reasoning_content: bool) -> Value {
6 let mut payload = serde_json::Map::from_iter([
7 (
8 "role".to_string(),
9 Value::String(message_role_value(self.role).to_string()),
10 ),
11 ("content".to_string(), Value::String(self.content.clone())),
12 ]);
13 insert_non_empty_optional_string(&mut payload, "name", &self.name);
14 insert_non_empty_optional_string(&mut payload, "tool_call_id", &self.tool_call_id);
15 if self.role == MessageRole::Assistant && !self.tool_calls.is_empty() {
16 payload.insert(
17 "tool_calls".to_string(),
18 Value::Array(self.tool_calls.iter().map(tool_call_to_openai).collect()),
19 );
20 if self.content.is_empty() {
21 payload.insert("content".to_string(), Value::Null);
22 }
23 }
24 if include_reasoning_content && self.role == MessageRole::Assistant {
25 insert_non_empty_optional_string(
26 &mut payload,
27 "reasoning_content",
28 &self.reasoning_content,
29 );
30 }
31 if self.role == MessageRole::User {
32 if let Some(image_url) = self.image_url.as_deref().filter(|value| !value.is_empty()) {
33 let mut blocks = Vec::new();
34 if !self.content.is_empty() {
35 blocks.push(serde_json::json!({
36 "type": "text",
37 "text": self.content,
38 }));
39 }
40 blocks.push(serde_json::json!({
41 "type": "image_url",
42 "image_url": {"url": image_url},
43 }));
44 payload.insert("content".to_string(), Value::Array(blocks));
45 }
46 }
47 Value::Object(payload)
48 }
49
50 pub fn to_dict(&self) -> Value {
51 let mut payload = serde_json::Map::from_iter([
52 (
53 "role".to_string(),
54 Value::String(message_role_value(self.role).to_string()),
55 ),
56 ("content".to_string(), Value::String(self.content.clone())),
57 ]);
58 insert_optional_string(&mut payload, "name", &self.name);
59 insert_optional_string(&mut payload, "tool_call_id", &self.tool_call_id);
60 if !self.tool_calls.is_empty() {
61 payload.insert(
62 "tool_calls".to_string(),
63 Value::Array(self.tool_calls.iter().map(tool_call_to_openai).collect()),
64 );
65 }
66 insert_optional_string(&mut payload, "reasoning_content", &self.reasoning_content);
67 insert_optional_string(&mut payload, "image_url", &self.image_url);
68 if !self.metadata.is_empty() {
69 payload.insert("metadata".to_string(), metadata_to_value(&self.metadata));
70 }
71 Value::Object(payload)
72 }
73
74 pub fn from_dict(data: &Value) -> Result<Self, String> {
75 let object = expect_object(data, "Message")?;
76 let role = parse_message_role(read_required_string(object, "role")?)?;
77 let tool_calls = read_array(object, "tool_calls")
78 .unwrap_or(&[])
79 .iter()
80 .map(ToolCall::from_dict)
81 .collect::<Result<Vec<_>, _>>()?;
82 Ok(Self {
83 role,
84 content: read_string(object, "content").unwrap_or_default(),
85 name: read_optional_string(object, "name"),
86 tool_call_id: read_optional_string(object, "tool_call_id"),
87 tool_calls,
88 reasoning_content: read_optional_string(object, "reasoning_content"),
89 image_url: read_optional_string(object, "image_url"),
90 metadata: read_metadata(object, "metadata")?,
91 })
92 }
93}
94
95fn tool_call_to_openai(tool_call: &ToolCall) -> Value {
96 let mut payload = serde_json::json!({
97 "id": tool_call.id,
98 "type": "function",
99 "function": {
100 "name": tool_call.name,
101 "arguments": Value::Object(tool_call.arguments.clone().into_iter().collect()).to_string(),
102 },
103 });
104 if let Some(extra_content) = &tool_call.extra_content {
105 payload["extra_content"] = extra_content.clone();
106 }
107 payload
108}
109
110impl ToolCall {
111 pub fn to_dict(&self) -> Value {
112 let mut payload = serde_json::Map::from_iter([
113 ("id".to_string(), Value::String(self.id.clone())),
114 ("name".to_string(), Value::String(self.name.clone())),
115 (
116 "arguments".to_string(),
117 Value::Object(self.arguments.clone().into_iter().collect()),
118 ),
119 ]);
120 if let Some(extra_content) = &self.extra_content {
121 payload.insert("extra_content".to_string(), extra_content.clone());
122 }
123 Value::Object(payload)
124 }
125
126 pub fn from_dict(data: &Value) -> Result<Self, String> {
127 let object = expect_object(data, "ToolCall")?;
128 if let Some(function) = object.get("function").and_then(Value::as_object) {
129 let id = read_required_string(object, "id")?.to_string();
130 let name = read_required_string(function, "name")?.to_string();
131 let raw_arguments = function
132 .get("arguments")
133 .cloned()
134 .unwrap_or_else(|| Value::String("{}".to_string()));
135 let mut tool_call = ToolCall::from_raw_arguments(id, name, raw_arguments);
136 tool_call.extra_content = object
137 .get("extra_content")
138 .filter(|value| value.is_object())
139 .cloned();
140 return Ok(tool_call);
141 }
142 Ok(Self {
143 id: read_required_string(object, "id")?.to_string(),
144 name: read_required_string(object, "name")?.to_string(),
145 arguments: read_metadata(object, "arguments")?,
146 extra_content: object
147 .get("extra_content")
148 .filter(|value| value.is_object())
149 .cloned(),
150 })
151 }
152}