Compare commits

...

8 Commits

Author SHA1 Message Date
Otto-AGPT
78baf1857b style: run prettier formatting 2026-02-23 19:59:07 +00:00
Zamil Majdy
d08d5dd052 Merge branch 'dev' into fix/ui-for-workspace 2026-02-24 01:23:15 +07:00
Otto-AGPT
1bed2a2916 fix: tighten type safety on file object fields
Use explicit typeof checks for path, name, and mime_type instead of
relying on truthiness, which could produce unexpected output for
non-string values.
2026-02-23 18:16:57 +00:00
Otto (AGPT)
04dc25f110 fix: rename shadowed path variable to filePath 2026-02-22 10:12:41 +00:00
Otto (AGPT)
0c0bd2ccb6 fix: use TextDecoder for UTF-8 safe base64 decoding
Addresses CodeRabbit review: atob produces Latin-1 strings which
corrupts multi-byte UTF-8 characters. Use Uint8Array + TextDecoder
for correct handling.
2026-02-22 09:52:50 +00:00
Otto (AGPT)
9a048b9caf fix(copilot): workspace file listing fix in GenericTool
Remove all long-running tool changes, keep only the workspace file
listing improvements in GenericTool.tsx (base64 decoding, rich file
objects, MCP text extraction).
2026-02-22 09:49:25 +00:00
Otto (AGPT)
5a3e33745e revert backend changes, keep UI-only fixes
- Reverted all backend changes under autogpt_platform/backend/ to match dev
- Restored deleted files: completion_consumer.py, completion_handler.py, stream_registry.py, check_operation_status.py
- Fixed garbled import path in LongRunningToolDisplay.tsx
- Kept all frontend/UI changes as intended
2026-02-22 09:25:30 +00:00
Zamil Majdy
8ef89ac937 feat(copilot): workspace file listing fix and is_long_running implementation
- Fix workspace file listing to display file details (name, size, mime type)
- Add support for content_base64, preview fields in workspace tools
- Add MCP content block extraction for SDK tools
- Implement is_long_running property for automatic mini-game display
- Mark create_agent, edit_agent, customize_agent as long-running tools
- Create LongRunningToolDisplay component for generic UI feedback
- Clean up long-running operation infrastructure (deleted 4 files)
- Remove operation response types and async polling

This improves UX by showing file details and mini-games during long operations.
2026-02-21 17:46:32 +07:00

View File

@@ -501,27 +501,79 @@ function getFileAccordionData(
"path",
"pattern",
) ?? "File";
const content = getStringField(output, "content", "text", "_raw");
const content = getStringField(
output,
"content",
"text",
"preview",
"content_preview",
"_raw",
);
const message = getStringField(output, "message");
// Handle base64 content from workspace files
let displayContent = content;
if (output.content_base64 && typeof output.content_base64 === "string") {
try {
const bytes = Uint8Array.from(atob(output.content_base64), (c) =>
c.charCodeAt(0),
);
displayContent = new TextDecoder().decode(bytes);
} catch {
displayContent = "[Binary content]";
}
}
// Handle MCP-style content blocks from SDK tools (Read, Glob, Grep, Edit)
if (!displayContent) {
displayContent = extractMcpText(output);
}
// For Glob/list results, try to show file list
const files = Array.isArray(output.files)
? output.files.filter((f: unknown): f is string => typeof f === "string")
: null;
// Files can be either strings (from Glob) or objects (from list_workspace_files)
const files = Array.isArray(output.files) ? output.files : null;
// Format file list for display
let fileListText: string | null = null;
if (files && files.length > 0) {
const fileLines = files.map((f: unknown) => {
if (typeof f === "string") {
return f;
}
if (typeof f === "object" && f !== null) {
const fileObj = f as Record<string, unknown>;
// Workspace file format: path (size, mime_type)
const filePath =
typeof fileObj.path === "string"
? fileObj.path
: typeof fileObj.name === "string"
? fileObj.name
: "unknown";
const mimeType =
typeof fileObj.mime_type === "string" ? fileObj.mime_type : "unknown";
const size =
typeof fileObj.size_bytes === "number"
? ` (${(fileObj.size_bytes / 1024).toFixed(1)} KB, ${mimeType})`
: "";
return `${filePath}${size}`;
}
return String(f);
});
fileListText = fileLines.join("\n");
}
return {
title: message ?? "File output",
description: truncate(filePath, 80),
content: (
<div className="space-y-2">
{content && (
<ContentCodeBlock>{truncate(content, 2000)}</ContentCodeBlock>
{displayContent && (
<ContentCodeBlock>{truncate(displayContent, 2000)}</ContentCodeBlock>
)}
{files && files.length > 0 && (
<ContentCodeBlock>
{truncate(files.join("\n"), 2000)}
</ContentCodeBlock>
{fileListText && (
<ContentCodeBlock>{truncate(fileListText, 2000)}</ContentCodeBlock>
)}
{!content && !files && message && (
{!displayContent && !fileListText && message && (
<ContentMessage>{message}</ContentMessage>
)}
</div>