Skip to main content

vtcode_acp/tooling/
schemas.rs

1use std::path::Path;
2
3use serde_json::json;
4
5use vtcode_core::config::constants::tools;
6use vtcode_core::core::interfaces::SessionMode;
7use vtcode_core::llm::provider::ToolDefinition;
8
9pub const TOOL_READ_FILE_DESCRIPTION: &str =
10    "Read the contents of a text file accessible to the IDE workspace";
11pub const TOOL_READ_FILE_URI_ARG: &str = "uri";
12pub const TOOL_READ_FILE_PATH_ARG: &str = "path";
13pub const TOOL_READ_FILE_LINE_ARG: &str = "line";
14pub const TOOL_READ_FILE_LIMIT_ARG: &str = "limit";
15
16pub const TOOL_LIST_FILES_DESCRIPTION: &str = "Explore workspace files in a SUBDIRECTORY (root path is blocked). Requires path like 'src/' or 'vtcode-core/'. For root overview, use shell commands via unified_exec.";
17pub const TOOL_LIST_FILES_PATH_ARG: &str = "path";
18pub const TOOL_LIST_FILES_MODE_ARG: &str = "mode";
19pub const TOOL_LIST_FILES_PAGE_ARG: &str = "page";
20pub const TOOL_LIST_FILES_PER_PAGE_ARG: &str = "per_page";
21pub const TOOL_LIST_FILES_MAX_ITEMS_ARG: &str = "max_items";
22pub const TOOL_LIST_FILES_INCLUDE_HIDDEN_ARG: &str = "include_hidden";
23pub const TOOL_LIST_FILES_RESPONSE_FORMAT_ARG: &str = "response_format";
24pub const TOOL_LIST_FILES_URI_ARG: &str = "uri";
25pub const TOOL_LIST_FILES_NAME_PATTERN_ARG: &str = "name_pattern";
26pub const TOOL_LIST_FILES_CONTENT_PATTERN_ARG: &str = "content_pattern";
27pub const TOOL_LIST_FILES_FILE_EXTENSIONS_ARG: &str = "file_extensions";
28pub const TOOL_LIST_FILES_CASE_SENSITIVE_ARG: &str = "case_sensitive";
29pub const TOOL_LIST_FILES_ITEMS_KEY: &str = "items";
30pub const TOOL_LIST_FILES_MESSAGE_KEY: &str = "message";
31pub const TOOL_LIST_FILES_RESULT_KEY: &str = "result";
32pub const TOOL_LIST_FILES_SUMMARY_MAX_ITEMS: usize = 20;
33
34pub(super) fn build_read_file_definition(workspace_root: &Path) -> ToolDefinition {
35    let workspace_display = workspace_root.display().to_string();
36    let sample_path = workspace_root.join("README.md");
37    let sample_path_string = sample_path.to_string_lossy().into_owned();
38    let sample_uri = format!("file://{}", sample_path_string);
39    let description = format!(
40        "{TOOL_READ_FILE_DESCRIPTION}. Workspace root: {workspace}. Provide {path} or {uri} inside the workspace. Paths must be absolute (see ACP file system spec). Optional {line} and {limit} control slicing.",
41        workspace = workspace_display,
42        path = TOOL_READ_FILE_PATH_ARG,
43        uri = TOOL_READ_FILE_URI_ARG,
44        line = TOOL_READ_FILE_LINE_ARG,
45        limit = TOOL_READ_FILE_LIMIT_ARG,
46    );
47    let examples = vec![
48        json!({
49            TOOL_READ_FILE_PATH_ARG: &sample_path_string,
50        }),
51        json!({
52            TOOL_READ_FILE_PATH_ARG: &sample_path_string,
53            TOOL_READ_FILE_LINE_ARG: 1,
54            TOOL_READ_FILE_LIMIT_ARG: 200,
55        }),
56        json!({
57            TOOL_READ_FILE_URI_ARG: sample_uri,
58        }),
59    ];
60    let schema = json!({
61        "type": "object",
62        "minProperties": 1,
63        "properties": {
64            TOOL_READ_FILE_PATH_ARG: {
65                "type": "string",
66                "description": "Absolute path to the file within the workspace",
67                "minLength": 1,
68            },
69            TOOL_READ_FILE_URI_ARG: {
70                "type": "string",
71                "description": "File URI using file:// or editor-specific schemes",
72                "minLength": 1,
73            },
74            TOOL_READ_FILE_LINE_ARG: {
75                "type": "integer",
76                "minimum": 1,
77                "description": "1-based line number to start reading from",
78            },
79            TOOL_READ_FILE_LIMIT_ARG: {
80                "type": "integer",
81                "minimum": 1,
82                "description": "Maximum number of lines to read",
83            }
84        },
85        "additionalProperties": false,
86        "description": description,
87        "examples": examples,
88    });
89
90    ToolDefinition::function(tools::READ_FILE.to_string(), description, schema)
91}
92
93pub(super) fn build_list_files_definition(workspace_root: &Path) -> ToolDefinition {
94    let description = format!(
95        "{TOOL_LIST_FILES_DESCRIPTION}. Workspace root: {}. Provide {path} (relative) or {uri} inside the workspace. Defaults to '.' when omitted.",
96        workspace_root.display(),
97        path = TOOL_LIST_FILES_PATH_ARG,
98        uri = TOOL_LIST_FILES_URI_ARG,
99    );
100    let workspace_display = workspace_root.display().to_string();
101    let examples = vec![
102        json!({
103            TOOL_LIST_FILES_MODE_ARG: "list",
104        }),
105        json!({
106            TOOL_LIST_FILES_PATH_ARG: "src",
107            TOOL_LIST_FILES_MODE_ARG: "recursive",
108            TOOL_LIST_FILES_PER_PAGE_ARG: 100,
109        }),
110        json!({
111            TOOL_LIST_FILES_URI_ARG: format!("file://{}/src", workspace_display),
112        }),
113    ];
114    let schema = json!({
115        "type": "object",
116        "properties": {
117            TOOL_LIST_FILES_PATH_ARG: {
118                "type": "string",
119                "description": "Directory or file path relative to the workspace root",
120                "default": ".",
121            },
122            TOOL_LIST_FILES_MODE_ARG: {
123                "type": "string",
124                "enum": ["list", "recursive", "find_name", "find_content"],
125                "description": "Listing mode: list (default), recursive, find_name, or find_content",
126            },
127            TOOL_LIST_FILES_PAGE_ARG: {
128                "type": "integer",
129                "minimum": 1,
130                "description": "Page number to return (1-based)",
131            },
132            TOOL_LIST_FILES_PER_PAGE_ARG: {
133                "type": "integer",
134                "minimum": 1,
135                "description": "Items per page (default 50)",
136            },
137            TOOL_LIST_FILES_MAX_ITEMS_ARG: {
138                "type": "integer",
139                "minimum": 1,
140                "description": "Maximum number of items to scan before truncation",
141            },
142            TOOL_LIST_FILES_INCLUDE_HIDDEN_ARG: {
143                "type": "boolean",
144                "description": "Whether to include dotfiles and ignored entries",
145            },
146            TOOL_LIST_FILES_RESPONSE_FORMAT_ARG: {
147                "type": "string",
148                "enum": ["concise", "detailed"],
149                "description": "Choose concise (default) or detailed metadata",
150            },
151            TOOL_LIST_FILES_NAME_PATTERN_ARG: {
152                "type": "string",
153                "description": "Optional filename pattern used by recursive or find_name modes",
154            },
155            TOOL_LIST_FILES_CONTENT_PATTERN_ARG: {
156                "type": "string",
157                "description": "Pattern to search within files when using find_content mode",
158            },
159            TOOL_LIST_FILES_FILE_EXTENSIONS_ARG: {
160                "type": "array",
161                "items": {"type": "string"},
162                "description": "Restrict results to files matching any extension",
163            },
164            TOOL_LIST_FILES_CASE_SENSITIVE_ARG: {
165                "type": "boolean",
166                "description": "Enable case sensitive matching for patterns",
167            },
168        },
169        "additionalProperties": false,
170        "description": description,
171        "examples": examples,
172    });
173
174    ToolDefinition::function(tools::LIST_FILES.to_string(), description, schema)
175}
176
177pub(super) fn build_switch_mode_definition() -> ToolDefinition {
178    let description = format!(
179        "Switch the current session mode. {ask} and {architect} are read-only; {code} enables local implementation tools. Possible modes: {ask}, {architect}, {code}.",
180        ask = SessionMode::Ask.as_str(),
181        architect = SessionMode::Architect.as_str(),
182        code = SessionMode::Code.as_str()
183    );
184    let schema = json!({
185        "type": "object",
186        "required": ["mode_id"],
187        "properties": {
188            "mode_id": {
189                "type": "string",
190                "enum": [
191                    SessionMode::Ask.as_str(),
192                    SessionMode::Architect.as_str(),
193                    SessionMode::Code.as_str()
194                ],
195                "description": "The ID of the mode to switch to"
196            }
197        },
198        "additionalProperties": false,
199        "description": description,
200    });
201
202    ToolDefinition::function("switch_mode".to_string(), description, schema)
203}