agtrace_providers/
normalization.rs1use agtrace_types::ToolCallPayload;
14use serde_json::Value;
15
16#[deprecated(
51 since = "0.3.0",
52 note = "Use ToolMapper::normalize_call instead. See function docs for migration path."
53)]
54pub fn normalize_tool_call(
55 name: String,
56 arguments: Value,
57 provider_call_id: Option<String>,
58) -> ToolCallPayload {
59 match name.as_str() {
61 "Read" | "Glob" => {
62 if let Ok(args) = serde_json::from_value(arguments.clone()) {
63 return ToolCallPayload::FileRead {
64 name,
65 arguments: args,
66 provider_call_id,
67 };
68 }
69 }
70 "Edit" => {
71 if let Ok(args) = serde_json::from_value(arguments.clone()) {
72 return ToolCallPayload::FileEdit {
73 name,
74 arguments: args,
75 provider_call_id,
76 };
77 }
78 }
79 "Write" => {
80 if let Ok(args) = serde_json::from_value(arguments.clone()) {
81 return ToolCallPayload::FileWrite {
82 name,
83 arguments: args,
84 provider_call_id,
85 };
86 }
87 }
88 "Bash" | "KillShell" | "BashOutput" => {
89 if let Ok(args) = serde_json::from_value(arguments.clone()) {
90 return ToolCallPayload::Execute {
91 name,
92 arguments: args,
93 provider_call_id,
94 };
95 }
96 }
97 "Grep" | "WebSearch" | "WebFetch" => {
98 if let Ok(args) = serde_json::from_value(arguments.clone()) {
99 return ToolCallPayload::Search {
100 name,
101 arguments: args,
102 provider_call_id,
103 };
104 }
105 }
106 _ if name.starts_with("mcp__") => {
107 if let Ok(args) = serde_json::from_value(arguments.clone()) {
108 return ToolCallPayload::Mcp {
109 name,
110 arguments: args,
111 provider_call_id,
112 };
113 }
114 }
115 _ => {}
116 }
117
118 ToolCallPayload::Generic {
120 name,
121 arguments,
122 provider_call_id,
123 }
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129 use serde_json::json;
130
131 #[allow(deprecated)]
132 #[test]
133 fn test_normalize_file_read() {
134 let payload = normalize_tool_call(
135 "Read".to_string(),
136 json!({"file_path": "/path/to/file.rs"}),
137 Some("call_123".to_string()),
138 );
139
140 match payload {
141 ToolCallPayload::FileRead {
142 name,
143 arguments,
144 provider_call_id,
145 } => {
146 assert_eq!(name, "Read");
147 assert_eq!(arguments.path(), Some("/path/to/file.rs"));
148 assert_eq!(provider_call_id, Some("call_123".to_string()));
149 }
150 _ => panic!("Expected FileRead variant"),
151 }
152 }
153
154 #[allow(deprecated)]
155 #[test]
156 fn test_normalize_execute() {
157 let payload = normalize_tool_call(
158 "Bash".to_string(),
159 json!({"command": "ls -la"}),
160 Some("call_456".to_string()),
161 );
162
163 match payload {
164 ToolCallPayload::Execute {
165 name,
166 arguments,
167 provider_call_id,
168 } => {
169 assert_eq!(name, "Bash");
170 assert_eq!(arguments.command, Some("ls -la".to_string()));
171 assert_eq!(provider_call_id, Some("call_456".to_string()));
172 }
173 _ => panic!("Expected Execute variant"),
174 }
175 }
176
177 #[allow(deprecated)]
178 #[test]
179 fn test_normalize_mcp_tool() {
180 let payload = normalize_tool_call(
181 "mcp__o3__search".to_string(),
182 json!({"query": "test"}),
183 Some("call_789".to_string()),
184 );
185
186 match payload {
187 ToolCallPayload::Mcp {
188 name,
189 arguments,
190 provider_call_id,
191 } => {
192 assert_eq!(name, "mcp__o3__search");
193 assert_eq!(
195 arguments.inner.get("query").and_then(|v| v.as_str()),
196 Some("test")
197 );
198 assert_eq!(provider_call_id, Some("call_789".to_string()));
199 }
200 _ => panic!("Expected Mcp variant"),
201 }
202 }
203
204 #[allow(deprecated)]
205 #[test]
206 fn test_normalize_unknown_tool_fallback() {
207 let payload = normalize_tool_call(
208 "UnknownTool".to_string(),
209 json!({"foo": "bar"}),
210 Some("call_999".to_string()),
211 );
212
213 match payload {
214 ToolCallPayload::Generic {
215 name,
216 arguments,
217 provider_call_id,
218 } => {
219 assert_eq!(name, "UnknownTool");
220 assert_eq!(arguments, json!({"foo": "bar"}));
221 assert_eq!(provider_call_id, Some("call_999".to_string()));
222 }
223 _ => panic!("Expected Generic variant for unknown tool"),
224 }
225 }
226
227 #[allow(deprecated)]
228 #[test]
229 fn test_normalize_invalid_arguments_fallback() {
230 let payload = normalize_tool_call(
233 "Read".to_string(),
234 json!({"invalid_field": 123}),
235 Some("call_000".to_string()),
236 );
237
238 match payload {
240 ToolCallPayload::FileRead {
241 name, arguments, ..
242 } => {
243 assert_eq!(name, "Read");
244 assert_eq!(arguments.file_path, None);
245 assert_eq!(arguments.path, None);
246 assert_eq!(arguments.pattern, None);
247 assert_eq!(arguments.extra.get("invalid_field"), Some(&json!(123)));
248 }
249 _ => panic!("Expected FileRead variant, got: {:?}", payload.kind()),
250 }
251 }
252}