Skip to main content

deepseek_rust_cli/tools/
schemas.rs

1use serde_json::json;
2
3use crate::api::types::Tool;
4
5/// Full unfiltered tool list (used when context detection isn't available).
6pub fn get_tools_schemas() -> Vec<Tool> {
7    get_filtered_tools_schemas(true, true)
8}
9
10/// Return tool schemas filtered by context:
11/// - `is_git_repo`: include local git tools (status, diff, commit, push, etc.)
12/// - `has_github_token`: include GitHub API tools
13///
14/// Core tools (shell, file I/O, code/web) are always included.
15pub fn get_filtered_tools_schemas(is_git_repo: bool, has_github_token: bool) -> Vec<Tool> {
16    let mut tools = Vec::with_capacity(40);
17
18    // ─── Shell & System (always) ────────────────────────────
19    tools.push(create_tool(
20        "execute_shell_command",
21        "Execute a shell command.",
22        json!({
23            "command": { "type": "string" },
24            "is_background": { "type": "boolean" }
25        }),
26        vec!["command"],
27    ));
28    tools.push(create_tool(
29        "get_system_info",
30        "Get system information.",
31        json!({}),
32        vec![],
33    ));
34    tools.push(create_tool(
35        "start_background_process",
36        "Start a command in the background, allowing the agent to continuously monitor its logs \
37         and terminate it when needed. Ideal for dev servers.",
38        json!({
39            "command": { "type": "string", "description": "The command to run" },
40            "cwd": { "type": "string", "description": "Optional: working directory" },
41            "env": {
42                "type": "object",
43                "description": "Optional: environment variables as key-value pairs"
44            }
45        }),
46        vec!["command"],
47    ));
48    tools.push(create_tool(
49        "read_background_process_logs",
50        "Read accumulated stdout/stderr logs from a running background process.",
51        json!({
52            "pid": { "type": "integer", "description": "The process ID (PID) of the background process" }
53        }),
54        vec!["pid"],
55    ));
56    tools.push(create_tool(
57        "kill_background_process",
58        "Kill a background process started by the agent.",
59        json!({
60            "pid": { "type": "integer", "description": "The process ID (PID) to terminate" }
61        }),
62        vec!["pid"],
63    ));
64    tools.push(create_tool(
65        "list_background_processes",
66        "List all active background processes started by the agent.",
67        json!({}),
68        vec![],
69    ));
70    tools.push(create_tool(
71        "check_port_status",
72        "Check if a local port is occupied, free, or blocked.",
73        json!({
74            "port": { "type": "integer", "description": "Port number to check" },
75            "host": { "type": "string", "description": "Optional: host (defaults to '127.0.0.1')" }
76        }),
77        vec!["port"],
78    ));
79
80    // ─── File I/O (always) ──────────────────────────────────
81    tools.push(create_tool(
82        "read_local_file",
83        "Read a local file.",
84        json!({
85            "file_path": { "type": "string" },
86            "start_line": { "type": "integer" },
87            "end_line": { "type": "integer" }
88        }),
89        vec!["file_path"],
90    ));
91    tools.push(create_tool(
92        "write_local_file",
93        "Write to a local file.",
94        json!({
95            "file_path": { "type": "string" },
96            "content": { "type": "string" }
97        }),
98        vec!["file_path", "content"],
99    ));
100    tools.push(create_tool(
101        "replace_text_in_file",
102        "Replace text in a file.",
103        json!({
104            "file_path": { "type": "string" },
105            "old_text": { "type": "string" },
106            "new_text": { "type": "string" }
107        }),
108        vec!["file_path", "old_text", "new_text"],
109    ));
110    tools.push(create_tool(
111        "list_directory",
112        "List directory contents.",
113        json!({
114            "path": { "type": "string" }
115        }),
116        vec![],
117    ));
118    tools.push(create_tool(
119        "tree_view",
120        "Show directory tree.",
121        json!({
122            "path": { "type": "string" },
123            "max_depth": { "type": "integer" }
124        }),
125        vec![],
126    ));
127    tools.push(create_tool(
128        "delete_file",
129        "Delete a file or directory.",
130        json!({
131            "file_path": { "type": "string" }
132        }),
133        vec!["file_path"],
134    ));
135    tools.push(create_tool(
136        "rename_file",
137        "Rename or move a file.",
138        json!({
139            "source_path": { "type": "string" },
140            "destination_path": { "type": "string" }
141        }),
142        vec!["source_path", "destination_path"],
143    ));
144    tools.push(create_tool(
145        "diff_files",
146        "Compare two files.",
147        json!({
148            "file1": { "type": "string" },
149            "file2": { "type": "string" }
150        }),
151        vec!["file1", "file2"],
152    ));
153    tools.push(create_tool(
154        "hash_file",
155        "Calculate file hash.",
156        json!({
157            "path": { "type": "string" },
158            "algorithm": { "type": "string", "enum": ["sha256", "md5"] }
159        }),
160        vec!["path"],
161    ));
162    tools.push(create_tool(
163        "count_lines",
164        "Count lines, words and characters in a file.",
165        json!({
166            "path": { "type": "string" }
167        }),
168        vec!["path"],
169    ));
170    tools.push(create_tool(
171        "search_files",
172        "Search files for a text pattern using native Rust (no shell process needed). Fast \
173         parallel search with regex support.",
174        json!({
175            "query": { "type": "string" },
176            "path": { "type": "string" },
177            "glob": { "type": "string" },
178            "max_results": { "type": "integer" }
179        }),
180        vec!["query"],
181    ));
182    tools.push(create_tool(
183        "bulk_rename",
184        "Rename multiple files in a directory using a regex pattern.",
185        json!({
186            "path": { "type": "string" },
187            "pattern": { "type": "string" },
188            "replacement": { "type": "string" }
189        }),
190        vec!["path", "pattern", "replacement"],
191    ));
192
193    tools.push(create_tool(
194        "copy_file",
195        "Copy a file from source_path to destination_path natively.",
196        json!({
197            "source_path": { "type": "string" },
198            "destination_path": { "type": "string" }
199        }),
200        vec!["source_path", "destination_path"],
201    ));
202    tools.push(create_tool(
203        "copy_directory",
204        "Recursively copy a directory from source_path to destination_path natively.",
205        json!({
206            "source_path": { "type": "string" },
207            "destination_path": { "type": "string" }
208        }),
209        vec!["source_path", "destination_path"],
210    ));
211    tools.push(create_tool(
212        "create_directory",
213        "Create a directory (and any necessary parent directories) natively.",
214        json!({
215            "directory_path": { "type": "string" }
216        }),
217        vec!["directory_path"],
218    ));
219    tools.push(create_tool(
220        "file_exists",
221        "Check if a file or directory exists at the given path.",
222        json!({
223            "file_path": { "type": "string" }
224        }),
225        vec!["file_path"],
226    ));
227    tools.push(create_tool(
228        "get_file_info",
229        "Get metadata for a file (type, size, timestamps, permissions) natively.",
230        json!({
231            "file_path": { "type": "string" }
232        }),
233        vec!["file_path"],
234    ));
235
236    // ─── Code & Web (always) ───────────────────────────────
237    tools.push(create_tool(
238        "run_python_code",
239        "Execute Python code snippet.",
240        json!({
241            "code": { "type": "string" }
242        }),
243        vec!["code"],
244    ));
245    tools.push(create_tool(
246        "fetch_url",
247        "Fetch and clean content from a URL.",
248        json!({
249            "url": { "type": "string" }
250        }),
251        vec!["url"],
252    ));
253    tools.push(create_tool(
254        "get_env_var",
255        "Read an environment variable.",
256        json!({
257            "name": { "type": "string" }
258        }),
259        vec!["name"],
260    ));
261
262    // ─── New Advanced Tools ─────────────────────────────────
263    tools.push(create_tool(
264        "regex_replace_in_file",
265        "Replace text in a file using a regular expression.",
266        json!({
267            "file_path": { "type": "string" },
268            "regex": { "type": "string" },
269            "replacement": { "type": "string" }
270        }),
271        vec!["file_path", "regex", "replacement"],
272    ));
273    tools.push(create_tool(
274        "json_update_value",
275        "Read a JSON file, update a value at a specified key path (e.g. \
276         'dependencies.tokio.version'), and save it.",
277        json!({
278            "file_path": { "type": "string" },
279            "key_path": { "type": "string" },
280            "new_value": { "type": "string" }
281        }),
282        vec!["file_path", "key_path", "new_value"],
283    ));
284    tools.push(create_tool(
285        "edit_file_by_lines",
286        "Edit a file by specifying one or more non-overlapping line ranges. This is highly \
287         efficient for modifying code without rewriting the whole file.",
288        json!({
289            "file_path": {
290                "type": "string",
291                "description": "Path to the file to edit"
292            },
293            "edits": {
294                "type": "array",
295                "description": "List of line-based replacement edits",
296                "items": {
297                    "type": "object",
298                    "properties": {
299                        "start_line": {
300                            "type": "integer",
301                            "description": "The 1-indexed start line number of the range to replace (inclusive)"
302                        },
303                        "end_line": {
304                            "type": "integer",
305                            "description": "The 1-indexed end line number of the range to replace (inclusive)"
306                        },
307                        "replacement_content": {
308                            "type": "string",
309                            "description": "The new content to insert in place of the target line range"
310                        },
311                        "target_content": {
312                            "type": "string",
313                            "description": "Optional: The exact content of the lines being replaced. If provided, it will be verified against the file contents to ensure correctness before applying the edit."
314                        }
315                    },
316                    "required": ["start_line", "end_line", "replacement_content"]
317                }
318            }
319        }),
320        vec!["file_path", "edits"],
321    ));
322    tools.push(create_tool(
323        "apply_diff_patch",
324        "Apply a unified diff patch to a local file. Ideal for complex or multi-hunk code modifications.",
325        json!({
326            "file_path": { "type": "string", "description": "Path to the file to patch" },
327            "patch_content": { "type": "string", "description": "The unified diff content (including hunk headers @@)" }
328        }),
329        vec!["file_path", "patch_content"],
330    ));
331    tools.push(create_tool(
332        "list_symbols",
333        "Parse code symbols (functions, structs, classes, etc.) from a file using lightweight \
334         regex.",
335        json!({
336            "file_path": { "type": "string" }
337        }),
338        vec!["file_path"],
339    ));
340    tools.push(create_tool(
341        "view_symbol_contents",
342        "View the full implementation code of a specific symbol (function, class, struct, enum, or impl) from a file.",
343        json!({
344            "file_path": { "type": "string", "description": "Path to the file to inspect" },
345            "symbol_name": { "type": "string", "description": "The name of the symbol/definition to view" }
346        }),
347        vec!["file_path", "symbol_name"],
348    ));
349    tools.push(create_tool(
350        "screenshot_webapp",
351        "Take a screenshot of a local web app or website using Microsoft Edge or Google Chrome in \
352         headless mode.",
353        json!({
354            "url": { "type": "string" },
355            "output_path": { "type": "string" }
356        }),
357        vec!["url", "output_path"],
358    ));
359    tools.push(create_tool(
360        "web_search_duckduckgo",
361        "Perform an internet search query via DuckDuckGo and return top results.",
362        json!({
363            "query": { "type": "string" }
364        }),
365        vec!["query"],
366    ));
367
368    // ─── Refactoring & Advanced Ops ────────────────────────
369    tools.push(create_tool(
370        "move_code_block",
371        "Move a code block (function, struct, etc.) from one file to another using regex.",
372        json!({
373            "source_path": { "type": "string" },
374            "destination_path": { "type": "string" },
375            "block_pattern": { "type": "string" }
376        }),
377        vec!["source_path", "destination_path", "block_pattern"],
378    ));
379    tools.push(create_tool(
380        "split_file",
381        "Split a file into multiple parts based on a regex pattern.",
382        json!({
383            "file_path": { "type": "string" },
384            "split_pattern": { "type": "string" },
385            "output_prefix": { "type": "string" }
386        }),
387        vec!["file_path", "split_pattern", "output_prefix"],
388    ));
389    tools.push(create_tool(
390        "cleanup_file",
391        "Clean up a file by removing trailing spaces and normalizing line endings.",
392        json!({
393            "file_path": { "type": "string" }
394        }),
395        vec!["file_path"],
396    ));
397    tools.push(create_tool(
398        "summarize_project",
399        "Analyze the current project and provide a high-level summary of files, languages, and \
400         structure.",
401        json!({}),
402        vec![],
403    ));
404    tools.push(create_tool(
405        "list_todo_tasks",
406        "Search the project for TODO, FIXME, HACK, and BUG comments and list them with file and \
407         line info.",
408        json!({}),
409        vec![],
410    ));
411    tools.push(create_tool(
412        "project_checkpoint",
413        "Create a project-wide backup archive of the source code and configuration.",
414        json!({
415            "name": { "type": "string", "description": "Short mnemonic name for the checkpoint" }
416        }),
417        vec!["name"],
418    ));
419    tools.push(create_tool(
420        "restore_checkpoint",
421        "Restore the project from a previously created checkpoint archive.",
422        json!({
423            "checkpoint_file": { "type": "string", "description": "Filename of the .tar.gz checkpoint" }
424        }),
425        vec!["checkpoint_file"],
426    ));
427    tools.push(create_tool(
428        "project_wide_replace",
429        "Perform a global search and replace across the entire project (filtering target files by \
430         glob).",
431        json!({
432            "old_text": { "type": "string" },
433            "new_text": { "type": "string" },
434            "glob": { "type": "string", "description": "Glob pattern for files, e.g. '**/*.rs'" }
435        }),
436        vec!["old_text", "new_text"],
437    ));
438
439    // ─── Local Git Operations (only if in a git repo) ──────
440    if is_git_repo {
441        tools.push(create_tool(
442            "git_status",
443            "Show git status.",
444            json!({
445                "path": { "type": "string" }
446            }),
447            vec![],
448        ));
449        tools.push(create_tool(
450            "git_diff",
451            "Show git diff.",
452            json!({
453                "path": { "type": "string" },
454                "staged": { "type": "boolean" }
455            }),
456            vec![],
457        ));
458        tools.push(create_tool(
459            "git_log",
460            "Show git commit history.",
461            json!({
462                "path": { "type": "string" },
463                "count": { "type": "integer" }
464            }),
465            vec![],
466        ));
467        tools.push(create_tool(
468            "git_branch",
469            "List, create, delete, or switch git branches.",
470            json!({
471                "path": { "type": "string" },
472                "action": { "type": "string", "enum": ["list", "create", "delete", "switch"] },
473                "name": { "type": "string" }
474            }),
475            vec![],
476        ));
477        tools.push(create_tool(
478            "git_add",
479            "Stage files for commit.",
480            json!({
481                "path": { "type": "string" },
482                "files": { "type": "string" }
483            }),
484            vec![],
485        ));
486        tools.push(create_tool(
487            "git_commit",
488            "Commit staged changes.",
489            json!({
490                "path": { "type": "string" },
491                "message": { "type": "string" }
492            }),
493            vec!["message"],
494        ));
495        tools.push(create_tool(
496            "git_push",
497            "Push commits to remote.",
498            json!({
499                "path": { "type": "string" },
500                "remote": { "type": "string" },
501                "branch": { "type": "string" }
502            }),
503            vec![],
504        ));
505        tools.push(create_tool(
506            "git_pull",
507            "Pull changes from remote.",
508            json!({
509                "path": { "type": "string" },
510                "remote": { "type": "string" },
511                "branch": { "type": "string" }
512            }),
513            vec![],
514        ));
515        tools.push(create_tool(
516            "git_checkout",
517            "Checkout branch or file.",
518            json!({
519                "path": { "type": "string" },
520                "target": { "type": "string" }
521            }),
522            vec!["target"],
523        ));
524        tools.push(create_tool(
525            "git_clone",
526            "Clone a git repository.",
527            json!({
528                "url": { "type": "string" },
529                "dest": { "type": "string" }
530            }),
531            vec!["url"],
532        ));
533        tools.push(create_tool(
534            "git_remote_list",
535            "List git remotes.",
536            json!({
537                "path": { "type": "string" }
538            }),
539            vec![],
540        ));
541        tools.push(create_tool(
542            "git_stash",
543            "Stash, pop, or list git stashes.",
544            json!({
545                "path": { "type": "string" },
546                "action": { "type": "string", "enum": ["save", "pop", "list"] }
547            }),
548            vec![],
549        ));
550    }
551
552    // ─── GitHub API Operations (only if GITHUB_TOKEN is set)
553    if has_github_token {
554        tools.push(create_tool(
555            "github_repo_info",
556            "Get GitHub repository information. Requires GITHUB_TOKEN.",
557            json!({
558                "repo": { "type": "string" }
559            }),
560            vec!["repo"],
561        ));
562        tools.push(create_tool(
563            "github_repo_list_issues",
564            "List GitHub issues for a repository.",
565            json!({
566                "repo": { "type": "string" },
567                "state": { "type": "string", "enum": ["open", "closed", "all"] },
568                "limit": { "type": "integer" }
569            }),
570            vec!["repo"],
571        ));
572        tools.push(create_tool(
573            "github_issue_create",
574            "Create a GitHub issue. Requires GITHUB_TOKEN.",
575            json!({
576                "repo": { "type": "string" },
577                "title": { "type": "string" },
578                "body": { "type": "string" },
579                "labels": { "type": "string" }
580            }),
581            vec!["repo", "title"],
582        ));
583        tools.push(create_tool(
584            "github_issue_update",
585            "Update a GitHub issue. Requires GITHUB_TOKEN.",
586            json!({
587                "repo": { "type": "string" },
588                "issue_number": { "type": "integer" },
589                "title": { "type": "string" },
590                "body": { "type": "string" },
591                "state": { "type": "string", "enum": ["open", "closed"] }
592            }),
593            vec!["repo", "issue_number"],
594        ));
595        tools.push(create_tool(
596            "github_pr_list",
597            "List GitHub pull requests.",
598            json!({
599                "repo": { "type": "string" },
600                "state": { "type": "string", "enum": ["open", "closed", "all"] },
601                "limit": { "type": "integer" }
602            }),
603            vec!["repo"],
604        ));
605        tools.push(create_tool(
606            "github_pr_create",
607            "Create a GitHub pull request. Requires GITHUB_TOKEN.",
608            json!({
609                "repo": { "type": "string" },
610                "title": { "type": "string" },
611                "head": { "type": "string" },
612                "base": { "type": "string" },
613                "body": { "type": "string" },
614                "draft": { "type": "boolean" }
615            }),
616            vec!["repo", "title", "head", "base"],
617        ));
618        tools.push(create_tool(
619            "github_pr_info",
620            "Get detailed information about a pull request.",
621            json!({
622                "repo": { "type": "string" },
623                "pr_number": { "type": "integer" }
624            }),
625            vec!["repo", "pr_number"],
626        ));
627        tools.push(create_tool(
628            "github_pr_merge",
629            "Merge a GitHub pull request. Requires GITHUB_TOKEN.",
630            json!({
631                "repo": { "type": "string" },
632                "pr_number": { "type": "integer" },
633                "method": { "type": "string", "enum": ["merge", "squash", "rebase"] }
634            }),
635            vec!["repo", "pr_number"],
636        ));
637        tools.push(create_tool(
638            "github_search_code",
639            "Search code on GitHub. Requires GITHUB_TOKEN.",
640            json!({
641                "query": { "type": "string" },
642                "repo": { "type": "string" },
643                "limit": { "type": "integer" }
644            }),
645            vec!["query"],
646        ));
647        tools.push(create_tool(
648            "github_search_repos",
649            "Search GitHub repositories. Requires GITHUB_TOKEN.",
650            json!({
651                "query": { "type": "string" },
652                "limit": { "type": "integer" }
653            }),
654            vec!["query"],
655        ));
656        tools.push(create_tool(
657            "github_get_file",
658            "Get file content from a GitHub repository.",
659            json!({
660                "repo": { "type": "string" },
661                "path": { "type": "string" },
662                "ref": { "type": "string" }
663            }),
664            vec!["repo", "path"],
665        ));
666        tools.push(create_tool(
667            "github_workflow_list",
668            "List GitHub Actions workflows.",
669            json!({
670                "repo": { "type": "string" }
671            }),
672            vec!["repo"],
673        ));
674        tools.push(create_tool(
675            "github_workflow_runs",
676            "List GitHub Actions workflow runs.",
677            json!({
678                "repo": { "type": "string" },
679                "workflow_id": { "type": "string" },
680                "limit": { "type": "integer" }
681            }),
682            vec!["repo"],
683        ));
684    }
685
686    tools
687}
688
689fn create_tool(name: &str, desc: &str, props: serde_json::Value, required: Vec<&str>) -> Tool {
690    Tool {
691        r#type: "function".to_string(),
692        function: crate::api::types::FunctionDefinition {
693            name: name.to_string(),
694            description: desc.to_string(),
695            parameters: json!({
696                "type": "object",
697                "properties": props,
698                "required": required
699            }),
700        },
701    }
702}