swiftide_agents/tools/
arg_preprocessor.rs1use std::borrow::Cow;
2
3use serde_json::{Map, Value};
4use swiftide_core::chat_completion::ToolCall;
5
6pub struct ArgPreprocessor;
9
10impl ArgPreprocessor {
11 pub fn preprocess_tool_calls(tool_calls: &mut [ToolCall]) {
12 for tool_call in tool_calls.iter_mut() {
13 let args = Self::preprocess(tool_call.args());
14
15 if args.as_ref().is_some_and(|a| match a {
16 Cow::Borrowed(_) => false,
17 Cow::Owned(_) => true,
18 }) {
19 tool_call.with_args(args.map(|a| a.to_string()));
20 }
21 }
22 }
23 pub fn preprocess(value: Option<&str>) -> Option<Cow<'_, str>> {
24 Some(take_first_occurrence_in_object(value?))
25 }
26}
27
28fn take_first_occurrence_in_object(value: &str) -> Cow<'_, str> {
30 let Ok(parsed) = &serde_json::from_str(value) else {
31 return Cow::Borrowed(value);
32 };
33 if let Value::Object(obj) = parsed {
34 let mut new_map = Map::with_capacity(obj.len());
35 for (k, v) in obj {
36 new_map.entry(k).or_insert(v.clone());
38 }
39 Cow::Owned(Value::Object(new_map).to_string())
40 } else {
41 Cow::Borrowed(value)
44 }
45}
46
47#[cfg(test)]
48mod tests {
49 use super::*;
50 use serde_json::json;
51
52 #[test]
53 fn test_preprocess_regular_json() {
54 let input = json!({
55 "key1": "value1",
56 "key2": "value2"
57 })
58 .to_string();
59 let expected = json!({
60 "key1": "value1",
61 "key2": "value2"
62 });
63 let result = ArgPreprocessor::preprocess(Some(&input));
64 assert_eq!(result.as_deref(), Some(expected.to_string().as_str()));
65 }
66
67 #[test]
68 fn test_preprocess_json_with_duplicate_keys() {
69 let input = json!({
70 "key1": "value1",
71 "key1": "value2"
72 })
73 .to_string();
74 let expected = json!({
75 "key1": "value2"
76 });
77 let result = ArgPreprocessor::preprocess(Some(&input));
78 assert_eq!(result.as_deref(), Some(expected.to_string().as_str()));
79 }
80
81 #[test]
82 fn test_no_preprocess_invalid_json() {
83 let input = "invalid json";
84 let result = ArgPreprocessor::preprocess(Some(input));
85 assert_eq!(result.as_deref(), Some(input));
86 }
87
88 #[test]
89 fn test_no_input() {
90 let result = ArgPreprocessor::preprocess(None);
91 assert_eq!(result, None);
92 }
93}