Werkzeugkasten: Anhaenge lesen - Word, Excel, Text (#692)
- Core/Documents/DocumentText: text of .docx (paragraphs, tables as rows), .xlsx (sheet by sheet, every cell at its column, stored values not formulas) and plain text/CSV. No DTD, no external references, every part bounded against zip bombs. PDF is named as not readable yet. - Mail: read_message lists attachments; read_attachment returns the text; save_attachment keeps the file in the agent's workspace (never over an existing file, never outside). - FileRW read/read_many return Word and Excel files as text; writing them stays refused. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
edf3ff19ea
commit
72d855efcf
@@ -592,7 +592,12 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
|
||||
? je.EnumerateArray().Select(x => x.GetString()?.ToLowerInvariant()).ToList()
|
||||
: new List<string?> { ".txt", ".json", ".md", ".html", ".js", ".css" }; // Default
|
||||
|
||||
if (!allowedExtensions.Contains(extension))
|
||||
// #692: A Word file or a spreadsheet is read as its extracted text, never raw and never
|
||||
// written by this tool — so reading it needs no place on the list.
|
||||
var reading = input.ValueKind == JsonValueKind.Object && input.TryGetProperty("action", out var act)
|
||||
&& act.ValueKind == JsonValueKind.String && act.GetString() is "read" or "read_many";
|
||||
if (!allowedExtensions.Contains(extension)
|
||||
&& !(reading && ClawdDotNet.Core.Documents.DocumentText.IsOfficeDocument(fullPath)))
|
||||
{
|
||||
throw new UnauthorizedAccessException($"File extension '{extension}' is not allowed in workspace '{area.Name}'.");
|
||||
}
|
||||
@@ -668,7 +673,7 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
|
||||
await fileLock.WaitAsync(ct);
|
||||
try
|
||||
{
|
||||
var content = await File.ReadAllTextAsync(path, ct);
|
||||
var content = await ReadContentAsync(path, ct);
|
||||
NoteRead(path, area, context);
|
||||
var relativePath = Path.GetRelativePath(rootPath, path);
|
||||
return ToolResult.Ok($"[{area.Name}:/{relativePath}]\n{content}");
|
||||
@@ -679,6 +684,20 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// #692: A Word file or a spreadsheet is read as its text — a price list saved from a mail is
|
||||
/// a table, not a heap of zip bytes. Everything else as before.
|
||||
/// </summary>
|
||||
private static async Task<string> ReadContentAsync(string path, CancellationToken ct)
|
||||
{
|
||||
if (!ClawdDotNet.Core.Documents.DocumentText.IsOfficeDocument(path))
|
||||
return await File.ReadAllTextAsync(path, ct);
|
||||
var extracted = ClawdDotNet.Core.Documents.DocumentText.Extract(await File.ReadAllBytesAsync(path, ct), path, MaxZeichenJeAufruf);
|
||||
return extracted.Ok
|
||||
? $"(text of a {extracted.Kind}{(extracted.Truncated ? $", first {MaxZeichenJeAufruf} characters" : "")})\n{extracted.Text}"
|
||||
: $"({extracted.Problem})";
|
||||
}
|
||||
|
||||
/// <summary>Hoechstzahl Dateien je <c>read_many</c>.</summary>
|
||||
public const int MaxDateienJeAufruf = 50;
|
||||
|
||||
@@ -730,7 +749,7 @@ public sealed class FileRWTool : IAgentTool, IToolStateProbe
|
||||
string inhalt;
|
||||
try
|
||||
{
|
||||
inhalt = await File.ReadAllTextAsync(pfad, ct);
|
||||
inhalt = await ReadContentAsync(pfad, ct);
|
||||
NoteRead(pfad, area, context);
|
||||
}
|
||||
finally { sperre.Release(); }
|
||||
|
||||
Reference in New Issue
Block a user