FileRW: Dateiaktion ohne path abweisen, Hostpfad nicht in Fehlermeldungen

Testinstanz 2026-10-02: write mit destinationPath statt path loeste auf die
Wurzel des Arbeitsbereichs auf; die Ausnahme nannte den absoluten Ordner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard
2026-10-02 09:18:05 +02:00
co-authored by Claude Opus 5.5
parent 0a75afa51b
commit 2699b98781
2 changed files with 81 additions and 1 deletions
+23 -1
View File
@@ -149,6 +149,9 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
return ToolResult.Fail($"Access denied: Action '{action}' is not allowed in workspace '{area.Name}' for this agent.");
}
if (MissingPath(action, input) is { } missing)
return ToolResult.Fail(missing);
// A workspace with a member list comes into being when it is first used.
if (!area.IsPersonal && area.Name != WorkspaceLayout.Shared)
Directory.CreateDirectory(rootPath);
@@ -177,10 +180,26 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
catch (Exception ex)
{
context.Logger.LogError(ex, "Error during FileRW action {Action}", action);
return ToolResult.Fail($"Error: {ex.Message}");
// The host's folder layout is none of the model's business — the workspace name says enough.
return ToolResult.Fail($"Error: {ex.Message.Replace(rootPath, $"<{area.Name}>", StringComparison.Ordinal)}");
}
}
/// <summary>
/// Actions on one file need its path. Without one, the path resolved to the workspace root:
/// a write then tried to move its temp file onto the folder itself (test instance, 2026-10-02,
/// a model that sent <c>destinationPath</c> instead of <c>path</c>).
/// </summary>
internal static string? MissingPath(string action, JsonElement input)
{
if (action is not ("read" or "write" or "append" or "delete" or "copy") || !string.IsNullOrWhiteSpace(RelativerPfad(input)))
return null;
var hint = action != "copy" && input.ValueKind == JsonValueKind.Object && input.TryGetProperty("destinationPath", out _)
? " 'destinationPath' belongs to copy only — name the file in 'path'."
: "";
return $"'path' is required for {action}.{hint}";
}
/// <summary>
/// #579: Rechte und Pfad pruefen, bevor ein Aufruf in die Freigabeliste kommt. Dieselben
/// Pruefungen wie in <see cref="ExecuteAsync"/>, ohne etwas anzufassen.
@@ -203,6 +222,9 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
if (!IsActionAllowed(action, area))
return $"Access denied: Action '{action}' is not allowed in workspace '{area.Name}' for this agent.";
if (MissingPath(action, input) is { } missing)
return missing;
if (action != "delete" || string.IsNullOrWhiteSpace(area.Root))
return null;