Tools: delete_file + execute (bash via stdin)

This commit is contained in:
Meleki committed 2026-02-26 14:41:56 +01:00
1 parent 6ccd8cdb06
commit fde6b51b1b
1 file changed
+85 -2
+85 -2
View File
@@ -87,6 +87,34 @@ var toolDefs = new[]
},
required = System.Array.Empty<string>()
}
},
new
{
name = "delete_file",
description = "Löscht eine Datei oder ein leeres Verzeichnis.",
input_schema = new
{
type = "object",
properties = new Dictionary<string, object>
{
["path"] = new { type = "string", description = "Relativer Pfad zur Datei oder zum Verzeichnis" }
},
required = new[] { "path" }
}
},
new
{
name = "execute",
description = "Führt einen Shell-Befehl im Workspace-Verzeichnis aus. Gibt stdout und stderr zurück. Timeout: 30 Sekunden.",
input_schema = new
{
type = "object",
properties = new Dictionary<string, object>
{
["command"] = new { type = "string", description = "Shell-Befehl zum Ausführen" }
},
required = new[] { "command" }
}
}
};
@@ -100,7 +128,7 @@ string ResolvePath(string relativePath)
return full;
}
string ExecuteTool(string name, JsonElement input)
async Task<string> ExecuteTool(string name, JsonElement input)
{
switch (name)
{
@@ -146,6 +174,61 @@ string ExecuteTool(string name, JsonElement input)
entries.Add(Path.GetRelativePath(workspaceRoot, file));
return entries.Count == 0 ? "(leer)" : string.Join("\n", entries);
}
case "delete_file":
{
var path = ResolvePath(input.GetProperty("path").GetString() ?? "");
if (File.Exists(path))
{
File.Delete(path);
return $"Datei gelöscht: {Path.GetRelativePath(workspaceRoot, path)}";
}
if (Directory.Exists(path))
{
Directory.Delete(path, recursive: false);
return $"Verzeichnis gelöscht: {Path.GetRelativePath(workspaceRoot, path)}";
}
return $"Fehler: Nicht gefunden: {Path.GetRelativePath(workspaceRoot, path)}";
}
case "execute":
{
var command = input.GetProperty("command").GetString() ?? "";
var psi = new System.Diagnostics.ProcessStartInfo
{
FileName = "/bin/bash",
WorkingDirectory = workspaceRoot,
RedirectStandardInput = true,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true
};
using var proc = System.Diagnostics.Process.Start(psi);
if (proc == null) return "Fehler: Prozess konnte nicht gestartet werden";
await proc.StandardInput.WriteAsync(command);
proc.StandardInput.Close();
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
await proc.WaitForExitAsync(cts.Token);
}
catch (OperationCanceledException)
{
proc.Kill(entireProcessTree: true);
return "Fehler: Timeout nach 30 Sekunden - Prozess abgebrochen";
}
var stdout = await proc.StandardOutput.ReadToEndAsync();
var stderr = await proc.StandardError.ReadToEndAsync();
var result = new StringBuilder();
if (!string.IsNullOrEmpty(stdout)) result.Append(stdout);
if (!string.IsNullOrEmpty(stderr))
{
if (result.Length > 0) result.Append("\n--- stderr ---\n");
result.Append(stderr);
}
if (result.Length == 0) result.Append($"(exit code {proc.ExitCode})");
else if (proc.ExitCode != 0) result.Append($"\n(exit code {proc.ExitCode})");
return result.ToString();
}
default:
return $"Fehler: Unbekanntes Tool: {name}";
}
@@ -374,7 +457,7 @@ app.MapPost("/api/chat", async (HttpRequest req, HttpResponse res, IHttpClientFa
// Tool sofort ausführen und streamen
string toolResult;
bool isError = false;
try { toolResult = ExecuteTool(currentToolName, inputEl); }
try { toolResult = await ExecuteTool(currentToolName, inputEl); }
catch (Exception ex) { toolResult = $"Fehler: {ex.Message}"; isError = true; }
executedTools.Add((currentToolId, toolResult, isError));