vtcode_core/tools/tool_intent/
actions.rs1use serde_json::Value;
2
3use crate::config::constants::tools;
4
5pub fn file_operation_action(args: &Value) -> Option<&str> {
8 args.get("action").and_then(|v| v.as_str()).or_else(|| {
9 let has_read_path = args.get("path").is_some()
10 || args.get("file_path").is_some()
11 || args.get("filepath").is_some()
12 || args.get("target_path").is_some()
13 || args.get("file").is_some()
14 || args.get("p").is_some();
15
16 if args.get("old_str").is_some() {
17 Some("edit")
18 } else if args.get("content").is_some() {
19 Some("write")
20 } else if args.get("destination").is_some() {
21 Some("move")
22 } else if has_read_path {
23 Some("read")
24 } else {
25 None
26 }
27 })
28}
29
30pub fn command_session_action(args: &Value) -> Option<&str> {
33 args.get("action").and_then(|v| v.as_str()).or_else(|| {
34 if args.get("command").is_some()
36 || args.get("cmd").is_some()
37 || args.get("raw_command").is_some()
38 || crate::tools::command_args::has_indexed_command_parts(args)
39 {
40 Some("run")
41 } else if args.get("code").is_some() {
42 Some("code")
43 } else if args.get("input").is_some() || args.get("chars").is_some() || args.get("text").is_some() {
44 Some("write")
45 } else if args.get("spool_path").is_some()
46 || args.get("query").is_some()
47 || args.get("head_lines").is_some()
48 || args.get("tail_lines").is_some()
49 || args.get("max_matches").is_some()
50 || args.get("literal").is_some()
51 {
52 Some("inspect")
53 } else if args.get("session_id").is_some() || args.get("s").is_some() {
54 Some("poll")
55 } else {
56 None
57 }
58 })
59}
60
61fn action_matches(action: Option<&str>, expected: &str) -> bool {
62 action.is_some_and(|candidate| candidate.eq_ignore_ascii_case(expected))
63}
64
65pub fn action_matches_any(action: Option<&str>, expected: &[&str]) -> bool {
66 action.is_some_and(|candidate| {
67 expected
68 .iter()
69 .any(|expected_action| candidate.eq_ignore_ascii_case(expected_action))
70 })
71}
72
73pub fn file_operation_action_is(args: &Value, expected: &str) -> bool {
74 action_matches(file_operation_action(args), expected)
75}
76
77pub fn file_operation_action_in(args: &Value, expected: &[&str]) -> bool {
78 action_matches_any(file_operation_action(args), expected)
79}
80
81pub fn command_session_action_is(args: &Value, expected: &str) -> bool {
82 action_matches(command_session_action(args), expected)
83}
84
85pub fn command_session_action_in(args: &Value, expected: &[&str]) -> bool {
86 action_matches_any(command_session_action(args), expected)
87}
88
89pub fn mcp_action(args: &Value) -> Option<&str> {
91 args.get("action").and_then(Value::as_str)
92}
93
94pub fn mcp_action_is(args: &Value, expected: &str) -> bool {
95 action_matches(mcp_action(args), expected)
96}
97
98pub fn action_qualified_policy_name(tool_name: &str, args: Option<&Value>) -> Option<&'static str> {
101 if tool_name == tools::MCP_CONNECT_SERVER
102 || (tool_name == tools::MCP && args.is_some_and(|args| mcp_action_is(args, "connect")))
103 {
104 return Some("mcp:connect");
105 }
106
107 if tool_name == tools::MCP_DISCONNECT_SERVER
108 || (tool_name == tools::MCP && args.is_some_and(|args| mcp_action_is(args, "disconnect")))
109 {
110 return Some("mcp:disconnect");
111 }
112
113 None
114}