isb_server/server/
aliases.rs1use serde_json::{Value, json};
7
8use super::Tool;
9
10pub fn alias_args(tool: &Tool, mut args: Value) -> Value {
14 let props = tool.input_schema.get("properties");
15 let has = |k: &str| props.is_some_and(|p| p.get(k).is_some());
16 let Some(m) = args.as_object_mut() else {
17 return args;
18 };
19 if tool.name.starts_with("app_") && has("name") && !has("app") && !m.contains_key("name") {
20 if let Some(v) = m.remove("app") {
21 m.insert("name".into(), v);
22 }
23 }
24 if has("argv") && !has("command") && !m.contains_key("argv") {
25 if let Some(v) = m.remove("command") {
26 let v = match v {
27 Value::String(s) => json!(["sh", "-c", s]),
28 other => other,
29 };
30 m.insert("argv".into(), v);
31 }
32 }
33 args
34}
35
36#[cfg(test)]
37mod tests {
38 use super::*;
39
40 fn tool(name: &str) -> Tool {
41 let schema = json!({"type": "object", "properties": {"name": {}, "argv": {}}});
42 Tool::new(name, "x", schema, |a, _| Ok(a))
43 }
44
45 #[test]
46 fn newcomer_names_map_to_the_canonical_ones() {
47 let a = alias_args(&tool("app_exec"), json!({"app": "web", "command": "ls -l"}));
48 assert_eq!(a, json!({"name": "web", "argv": ["sh", "-c", "ls -l"]}));
49 let a = alias_args(
50 &tool("app_exec"),
51 json!({"app": "web", "command": ["ls", "-l"]}),
52 );
53 assert_eq!(a, json!({"name": "web", "argv": ["ls", "-l"]}));
54 }
55
56 #[test]
57 fn the_canonical_name_wins_and_app_means_name_only_on_app_tools() {
58 let a = alias_args(&tool("app_logs"), json!({"app": "x", "name": "web"}));
59 assert_eq!(a, json!({"app": "x", "name": "web"}));
60 let a = alias_args(
61 &tool("instance_exec"),
62 json!({"app": "web", "command": ["id"]}),
63 );
64 assert_eq!(a, json!({"app": "web", "argv": ["id"]}));
65 let a = alias_args(&tool("app_top"), json!("not an object"));
66 assert_eq!(a, json!("not an object"));
67 }
68}