starweaver_model/message/
tool.rs1use serde::{Deserialize, Serialize};
4use serde_json::{Map, Value};
5
6use super::Metadata;
7
8pub const TOOL_RETURN_APPROVAL_ARGUMENTS_METADATA_KEY: &str = "starweaver.approval_tool_arguments";
10
11#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
13pub struct ToolCallPart {
14 pub id: String,
16 pub name: String,
18 #[serde(default)]
20 pub arguments: ToolArguments,
21}
22
23#[derive(Clone, Debug, Eq, PartialEq)]
25pub enum ToolArguments {
26 Parsed(Value),
28 RawJsonString(String),
30 Invalid {
32 raw: String,
34 error: String,
36 },
37}
38
39impl Default for ToolArguments {
40 fn default() -> Self {
41 Self::Parsed(Value::Null)
42 }
43}
44
45impl ToolArguments {
46 const INVALID_KIND: &'static str = "starweaver_invalid_tool_arguments";
47
48 #[must_use]
50 pub const fn parsed(value: Value) -> Self {
51 Self::Parsed(value)
52 }
53
54 #[must_use]
56 pub fn raw_json_string(raw: impl Into<String>) -> Self {
57 Self::RawJsonString(raw.into())
58 }
59
60 #[must_use]
62 pub fn invalid(raw: impl Into<String>, error: impl Into<String>) -> Self {
63 Self::Invalid {
64 raw: raw.into(),
65 error: error.into(),
66 }
67 }
68
69 #[must_use]
71 pub fn from_provider_value(value: &Value) -> Self {
72 match value {
73 Value::String(raw) => match serde_json::from_str::<Value>(raw) {
74 Ok(parsed) => Self::Parsed(parsed),
75 Err(error) => Self::Invalid {
76 raw: raw.clone(),
77 error: error.to_string(),
78 },
79 },
80 other => Self::Parsed(other.clone()),
81 }
82 }
83
84 #[must_use]
86 pub fn execution_value(&self) -> Value {
87 match self {
88 Self::Parsed(value) => value.clone(),
89 Self::RawJsonString(raw) => {
90 serde_json::from_str(raw).unwrap_or_else(|_| Value::String(raw.clone()))
91 }
92 Self::Invalid { raw, .. } => Value::String(raw.clone()),
93 }
94 }
95
96 #[must_use]
98 pub fn wire_json_string(&self) -> String {
99 match self {
100 Self::Parsed(value) => value.to_string(),
101 Self::RawJsonString(raw) | Self::Invalid { raw, .. } => raw.clone(),
102 }
103 }
104
105 #[must_use]
107 pub fn replay_value(&self) -> Value {
108 match self {
109 Self::Parsed(value) => value.clone(),
110 Self::RawJsonString(raw) => Value::String(raw.clone()),
111 Self::Invalid { raw, error } => {
112 let mut object = Map::new();
113 object.insert(
114 "kind".to_string(),
115 Value::String(Self::INVALID_KIND.to_string()),
116 );
117 object.insert("raw".to_string(), Value::String(raw.clone()));
118 object.insert("error".to_string(), Value::String(error.clone()));
119 Value::Object(object)
120 }
121 }
122 }
123
124 #[must_use]
126 pub const fn invalid_error(&self) -> Option<&str> {
127 match self {
128 Self::Invalid { error, .. } => Some(error.as_str()),
129 Self::Parsed(_) | Self::RawJsonString(_) => None,
130 }
131 }
132}
133
134impl From<Value> for ToolArguments {
135 fn from(value: Value) -> Self {
136 Self::Parsed(value)
137 }
138}
139
140impl From<Map<String, Value>> for ToolArguments {
141 fn from(value: Map<String, Value>) -> Self {
142 Self::Parsed(Value::Object(value))
143 }
144}
145
146impl From<&str> for ToolArguments {
147 fn from(value: &str) -> Self {
148 Self::RawJsonString(value.to_string())
149 }
150}
151
152impl From<String> for ToolArguments {
153 fn from(value: String) -> Self {
154 Self::RawJsonString(value)
155 }
156}
157
158impl PartialEq<Value> for ToolArguments {
159 fn eq(&self, other: &Value) -> bool {
160 &self.execution_value() == other
161 }
162}
163
164impl PartialEq<ToolArguments> for Value {
165 fn eq(&self, other: &ToolArguments) -> bool {
166 self == &other.execution_value()
167 }
168}
169
170impl Serialize for ToolArguments {
171 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
172 where
173 S: serde::Serializer,
174 {
175 self.replay_value().serialize(serializer)
176 }
177}
178
179impl<'de> Deserialize<'de> for ToolArguments {
180 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
181 where
182 D: serde::Deserializer<'de>,
183 {
184 let value = Value::deserialize(deserializer)?;
185 if let Value::Object(object) = &value
186 && object
187 .get("kind")
188 .and_then(Value::as_str)
189 .is_some_and(|kind| kind == Self::INVALID_KIND)
190 {
191 return Ok(Self::Invalid {
192 raw: object
193 .get("raw")
194 .and_then(Value::as_str)
195 .unwrap_or_default()
196 .to_string(),
197 error: object
198 .get("error")
199 .and_then(Value::as_str)
200 .unwrap_or_default()
201 .to_string(),
202 });
203 }
204 Ok(Self::Parsed(value))
205 }
206}
207
208#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
210pub struct ToolReturnPart {
211 pub tool_call_id: String,
213 pub name: String,
215 pub content: Value,
217 #[serde(default)]
219 pub is_error: bool,
220 #[serde(default, skip_serializing_if = "Map::is_empty")]
222 pub metadata: Metadata,
223 #[serde(default, skip_serializing_if = "Option::is_none")]
225 pub app_value: Option<Value>,
226 #[serde(default, skip_serializing_if = "Option::is_none")]
228 pub user_content: Option<Value>,
229 #[serde(default, skip_serializing_if = "Map::is_empty")]
231 pub private_metadata: Metadata,
232}
233
234impl ToolReturnPart {
235 #[must_use]
237 pub fn new(tool_call_id: impl Into<String>, name: impl Into<String>, content: Value) -> Self {
238 Self {
239 tool_call_id: tool_call_id.into(),
240 name: name.into(),
241 content,
242 is_error: false,
243 metadata: Metadata::default(),
244 app_value: None,
245 user_content: None,
246 private_metadata: Metadata::default(),
247 }
248 }
249
250 #[must_use]
252 pub const fn with_error(mut self, is_error: bool) -> Self {
253 self.is_error = is_error;
254 self
255 }
256
257 #[must_use]
259 pub fn with_metadata(mut self, metadata: Metadata) -> Self {
260 self.metadata = metadata;
261 self
262 }
263
264 #[must_use]
266 pub fn with_app_value(mut self, app_value: Value) -> Self {
267 self.app_value = Some(app_value);
268 self
269 }
270
271 #[must_use]
273 pub fn with_user_content(mut self, user_content: Value) -> Self {
274 self.user_content = Some(user_content);
275 self
276 }
277
278 #[must_use]
280 pub fn with_private_metadata(mut self, private_metadata: Metadata) -> Self {
281 self.private_metadata = private_metadata;
282 self
283 }
284}