1use serde_json::{Map, Value};
6
7pub fn merge_dicts(left: Value, others: Vec<Value>) -> Result<Value, MergeError> {
40 let mut merged = match left {
41 Value::Object(map) => map,
42 _ => return Err(MergeError::NotAnObject),
43 };
44
45 for right in others {
46 let right_map = match right {
47 Value::Object(map) => map,
48 Value::Null => continue,
49 _ => return Err(MergeError::NotAnObject),
50 };
51
52 for (right_k, right_v) in right_map {
53 if !merged.contains_key(&right_k)
54 || (right_v != Value::Null && merged.get(&right_k) == Some(&Value::Null))
55 {
56 merged.insert(right_k, right_v);
57 } else if right_v == Value::Null {
58 continue;
59 } else {
60 let left_v = merged.get(&right_k).unwrap();
61
62 if !values_same_type(left_v, &right_v) {
63 return Err(MergeError::TypeMismatch {
64 key: right_k.clone(),
65 left_type: type_name(left_v),
66 right_type: type_name(&right_v),
67 });
68 }
69
70 match (left_v.clone(), right_v.clone()) {
71 (Value::String(left_str), Value::String(right_str)) => {
72 if (right_k == "index" && left_str.starts_with("lc_"))
73 || ((right_k == "id"
74 || right_k == "output_version"
75 || right_k == "model_provider")
76 && left_str == right_str)
77 {
78 continue;
79 }
80 merged.insert(right_k, Value::String(left_str + &right_str));
81 }
82 (Value::Object(_), Value::Object(_)) => {
83 let merged_nested =
84 merge_dicts(merged.remove(&right_k).unwrap(), vec![right_v])?;
85 merged.insert(right_k, merged_nested);
86 }
87 (Value::Array(left_arr), Value::Array(right_arr)) => {
88 let merged_list = merge_lists(Some(left_arr), vec![Some(right_arr)])?;
89 merged.insert(right_k, Value::Array(merged_list.unwrap_or_default()));
90 }
91 (Value::Number(left_num), Value::Number(right_num)) => {
92 if left_num == right_num {
93 continue;
94 }
95 if let (Some(left_i), Some(right_i)) =
96 (left_num.as_i64(), right_num.as_i64())
97 {
98 merged.insert(
99 right_k,
100 Value::Number(serde_json::Number::from(left_i + right_i)),
101 );
102 } else if let (Some(left_f), Some(right_f)) =
103 (left_num.as_f64(), right_num.as_f64())
104 && let Some(num) = serde_json::Number::from_f64(left_f + right_f)
105 {
106 merged.insert(right_k, Value::Number(num));
107 }
108 }
109 (left_v, right_v) if left_v == right_v => {
110 continue;
111 }
112 (left_v, _) => {
113 return Err(MergeError::UnsupportedType {
114 key: right_k,
115 value_type: type_name(&left_v),
116 });
117 }
118 }
119 }
120 }
121 }
122
123 Ok(Value::Object(merged))
124}
125
126pub fn merge_lists(
137 left: Option<Vec<Value>>,
138 others: Vec<Option<Vec<Value>>>,
139) -> Result<Option<Vec<Value>>, MergeError> {
140 let mut merged = left.map(|v| v.to_vec());
141
142 for other in others {
143 let Some(other_vec) = other else {
144 continue;
145 };
146
147 if let Some(ref mut merged_vec) = merged {
148 for e in other_vec {
149 if let Value::Object(ref e_map) = e
150 && let Some(index) = e_map.get("index")
151 {
152 let should_merge = match index {
153 Value::Number(n) => n.as_i64().is_some(),
154 Value::String(s) => s.starts_with("lc_"),
155 _ => false,
156 };
157
158 if should_merge {
159 let to_merge: Vec<usize> = merged_vec
160 .iter()
161 .enumerate()
162 .filter_map(|(i, e_left)| {
163 if let Value::Object(left_map) = e_left
164 && left_map.get("index") == Some(index)
165 {
166 return Some(i);
167 }
168 None
169 })
170 .collect();
171
172 if !to_merge.is_empty() {
173 let merge_idx = to_merge[0];
174 let left_elem = &merged_vec[merge_idx];
175
176 let left_type = left_elem
177 .as_object()
178 .and_then(|m| m.get("type"))
179 .and_then(|t| t.as_str());
180
181 let new_e: Value = if left_type.is_some() {
182 let e_type = e_map.get("type").and_then(|t| t.as_str());
183
184 if e_type == Some("non_standard") && e_map.contains_key("value") {
185 if left_type != Some("non_standard") {
186 let mut extras = Map::new();
187 if let Some(Value::Object(value_map)) = e_map.get("value") {
188 for (k, v) in value_map {
189 if k != "type" {
190 extras.insert(k.clone(), v.clone());
191 }
192 }
193 }
194 Value::Object(
195 [("extras".to_string(), Value::Object(extras))]
196 .into_iter()
197 .collect(),
198 )
199 } else {
200 let mut new_map = Map::new();
201 let mut value_map = Map::new();
202 if let Some(Value::Object(orig_value)) = e_map.get("value")
203 {
204 for (k, v) in orig_value {
205 if k != "type" {
206 value_map.insert(k.clone(), v.clone());
207 }
208 }
209 }
210 new_map
211 .insert("value".to_string(), Value::Object(value_map));
212 if let Some(idx) = e_map.get("index") {
213 new_map.insert("index".to_string(), idx.clone());
214 }
215 Value::Object(new_map)
216 }
217 } else {
218 let mut new_map = Map::new();
219 for (k, v) in e_map {
220 if k != "type" {
221 new_map.insert(k.clone(), v.clone());
222 }
223 }
224 Value::Object(new_map)
225 }
226 } else {
227 e.clone()
228 };
229
230 let left_val = merged_vec.remove(merge_idx);
231 let merged_val = merge_dicts(left_val, vec![new_e])?;
232 merged_vec.insert(merge_idx, merged_val);
233 } else {
234 merged_vec.push(e);
235 }
236 continue;
237 }
238 }
239 merged_vec.push(e);
240 }
241 } else {
242 merged = Some(other_vec);
243 }
244 }
245
246 Ok(merged)
247}
248
249pub fn merge_obj(left: Value, right: Value) -> Result<Value, MergeError> {
270 if left == Value::Null || right == Value::Null {
271 return Ok(if left != Value::Null { left } else { right });
272 }
273
274 if !values_same_type(&left, &right) {
275 return Err(MergeError::TypeMismatch {
276 key: String::new(),
277 left_type: type_name(&left),
278 right_type: type_name(&right),
279 });
280 }
281
282 match (&left, &right) {
283 (Value::String(l), Value::String(r)) => Ok(Value::String(l.clone() + r)),
284 (Value::Object(_), Value::Object(_)) => merge_dicts(left, vec![right]),
285 (Value::Array(l), Value::Array(r)) => {
286 let merged = merge_lists(Some(l.clone()), vec![Some(r.clone())])?;
287 Ok(Value::Array(merged.unwrap_or_default()))
288 }
289 (l, r) if l == r => Ok(left),
290 _ => Err(MergeError::UnableToMerge {
291 left_type: type_name(&left),
292 right_type: type_name(&right),
293 }),
294 }
295}
296
297#[derive(Debug, Clone, PartialEq)]
299pub enum MergeError {
300 NotAnObject,
302 TypeMismatch {
304 key: String,
305 left_type: String,
306 right_type: String,
307 },
308 UnsupportedType { key: String, value_type: String },
310 UnableToMerge {
312 left_type: String,
313 right_type: String,
314 },
315}
316
317impl std::fmt::Display for MergeError {
318 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
319 match self {
320 MergeError::NotAnObject => write!(f, "Value is not a JSON object"),
321 MergeError::TypeMismatch {
322 key,
323 left_type,
324 right_type,
325 } => {
326 write!(
327 f,
328 "additional_kwargs[\"{}\"] already exists in this message, but with a different type. Left type: {}, Right type: {}",
329 key, left_type, right_type
330 )
331 }
332 MergeError::UnsupportedType { key, value_type } => {
333 write!(
334 f,
335 "Additional kwargs key {} already exists in left dict and value has unsupported type {}",
336 key, value_type
337 )
338 }
339 MergeError::UnableToMerge {
340 left_type,
341 right_type,
342 } => {
343 write!(
344 f,
345 "Unable to merge {} and {}. Both must be of type str, dict, or list, or else be two equal objects",
346 left_type, right_type
347 )
348 }
349 }
350 }
351}
352
353impl std::error::Error for MergeError {}
354
355fn values_same_type(left: &Value, right: &Value) -> bool {
356 matches!(
357 (left, right),
358 (Value::Null, Value::Null)
359 | (Value::Bool(_), Value::Bool(_))
360 | (Value::Number(_), Value::Number(_))
361 | (Value::String(_), Value::String(_))
362 | (Value::Array(_), Value::Array(_))
363 | (Value::Object(_), Value::Object(_))
364 )
365}
366
367fn type_name(value: &Value) -> String {
368 match value {
369 Value::Null => "null",
370 Value::Bool(_) => "bool",
371 Value::Number(_) => "number",
372 Value::String(_) => "string",
373 Value::Array(_) => "array",
374 Value::Object(_) => "object",
375 }
376 .to_string()
377}
378
379#[cfg(test)]
380mod tests {
381 use super::*;
382 use serde_json::json;
383
384 #[test]
385 fn test_merge_dicts_basic() {
386 let left = json!({"a": 1, "b": 2});
387 let right = json!({"c": 3});
388 let result = merge_dicts(left, vec![right]).unwrap();
389 assert_eq!(result, json!({"a": 1, "b": 2, "c": 3}));
390 }
391
392 #[test]
393 fn test_merge_dicts_null_handling() {
394 let left = json!({"a": null});
395 let right = json!({"a": "value"});
396 let result = merge_dicts(left, vec![right]).unwrap();
397 assert_eq!(result, json!({"a": "value"}));
398 }
399
400 #[test]
401 fn test_merge_dicts_string_concatenation() {
402 let left = json!({"text": "hello "});
403 let right = json!({"text": "world"});
404 let result = merge_dicts(left, vec![right]).unwrap();
405 assert_eq!(result, json!({"text": "hello world"}));
406 }
407
408 #[test]
409 fn test_merge_dicts_nested() {
410 let left = json!({"outer": {"inner": "a"}});
411 let right = json!({"outer": {"inner": "b"}});
412 let result = merge_dicts(left, vec![right]).unwrap();
413 assert_eq!(result, json!({"outer": {"inner": "ab"}}));
414 }
415
416 #[test]
417 fn test_merge_lists_basic() {
418 let left = Some(vec![json!(1), json!(2)]);
419 let right = Some(vec![json!(3), json!(4)]);
420 let result = merge_lists(left, vec![right]).unwrap();
421 assert_eq!(result, Some(vec![json!(1), json!(2), json!(3), json!(4)]));
422 }
423
424 #[test]
425 fn test_merge_lists_with_index() {
426 let left = Some(vec![json!({"index": 0, "value": "a"})]);
427 let right = Some(vec![json!({"index": 0, "value": "b"})]);
428 let result = merge_lists(left, vec![right]).unwrap();
429 assert_eq!(result, Some(vec![json!({"index": 0, "value": "ab"})]));
430 }
431
432 #[test]
433 fn test_merge_obj_strings() {
434 let left = json!("hello ");
435 let right = json!("world");
436 let result = merge_obj(left, right).unwrap();
437 assert_eq!(result, json!("hello world"));
438 }
439
440 #[test]
441 fn test_merge_obj_with_null() {
442 let left = Value::Null;
443 let right = json!("value");
444 let result = merge_obj(left, right).unwrap();
445 assert_eq!(result, json!("value"));
446 }
447}