s01 唯一真实工具:执行 shell 命令。 本章故意不做权限判断,只保留“模型请求工具 -> Java 执行工具 -> 结果回给模型”的闭环。
| 15 | * 本章故意不做权限判断,只保留“模型请求工具 -> Java 执行工具 -> 结果回给模型”的闭环。 |
| 16 | */ |
| 17 | public class BashTool implements Tool { |
| 18 | |
| 19 | private final File workdir; |
| 20 | |
| 21 | public BashTool(File workdir) { |
| 22 | this.workdir = workdir; |
| 23 | } |
| 24 | |
| 25 | /* |
| 26 | * { |
| 27 | * "name": "bash", |
| 28 | * "description": "Run a shell command. Set run_in_background=true for slow commands.", |
| 29 | * "input_schema": { |
| 30 | * "type": "object", |
| 31 | * "properties": { |
| 32 | * "command": {"type": "string", "description": "Shell command to run"}, |
| 33 | * "run_in_background": {"type": "boolean", "description": "Run in background for slow commands"} |
| 34 | * }, |
| 35 | * "required": ["command"] |
| 36 | * } |
| 37 | * } |
| 38 | */ |
| 39 | @Override |
| 40 | public ToolDefinition getDefinition() { |
| 41 | JSONObject properties = new JSONObject() |
| 42 | .fluentPut("command", new JSONObject() |
| 43 | .fluentPut("type", "string") |
| 44 | .fluentPut("description", "Shell command to run")) |
| 45 | .fluentPut("run_in_background", new JSONObject() |
| 46 | .fluentPut("type", "boolean") |
| 47 | .fluentPut("description", "Run in background for slow commands")); |
| 48 | JSONObject schema = new JSONObject() |
| 49 | .fluentPut("type", "object") |
| 50 | .fluentPut("properties", properties) |
| 51 | .fluentPut("required", new JSONArray().fluentAdd("command")); |
| 52 | return new ToolDefinition("bash", |
| 53 | "Run a shell command. Set run_in_background=true for slow commands.", schema); |
| 54 | } |
| 55 | |
| 56 | @Override |
| 57 | public ToolResult execute(JSONObject input) { |
| 58 | String command = input == null ? "" : input.getString("command"); |
| 59 | if (command == null || command.isBlank()) { |
| 60 | return new ToolResult("No command provided"); |
| 61 | } |
| 62 | |
| 63 | try { |
| 64 | // bash 工具的工作目录和 system prompt 中告诉模型的 workdir 保持一致。 |
| 65 | Process process = new ProcessBuilder("/bin/sh", "-c", command) |
| 66 | .directory(workdir) |
| 67 | .redirectErrorStream(true) |
| 68 | .start(); |
| 69 | String output = readOutput(process); |
| 70 | int exitCode = process.waitFor(); |
| 71 | return new ToolResult("exit_code=" + exitCode + "\n" + output); |
| 72 | } |
| 73 | catch (IOException e) { |
| 74 | return new ToolResult("Command failed to start: " + e.getMessage()); |
nothing calls this directly
no outgoing calls
no test coverage detected