feat: auto-open generated images and videos in OS viewer (#244)
* feat: add inline image and video rendering in terminal UI Use sharp to render images as half-block character grids directly in the terminal when media tool results are displayed, with ffmpeg fallback for video thumbnail extraction. * feat: auto-open generated media in OS viewer instead of inline rendering Replace pixelated half-block terminal image rendering with native OS viewer (`open` on macOS, `xdg-open` on Linux). Generated images and videos now open automatically in full quality. Remove sharp dependency and inline rendering utilities. * bump version * fix: use execFile instead of exec to prevent shell injection * fix: remove auto-open from MediaToolResultView, keep only in MediaAutoOpenView
This commit is contained in:
1 parent
a9a78a3a5b
commit
2b7a0396bc
2 files changed
+33
-1
No files matched your search
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "grok-dev",
|
||||
"version": "1.1.4-rc5",
|
||||
"version": "1.1.4",
|
||||
"description": "An open-source AI coding agent powered by Grok, built with Bun and OpenTUI.",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
||||
@@ -3941,6 +3941,9 @@ function MessageView({
|
||||
}
|
||||
|
||||
if ((entry.toolResult?.media?.length ?? 0) > 0) {
|
||||
if (name === "generate_image" || name === "generate_video") {
|
||||
return <MediaAutoOpenView t={t} label={toolLabel(entry.toolCall!)} toolResult={entry.toolResult!} />;
|
||||
}
|
||||
return <MediaToolResultView t={t} label={toolLabel(entry.toolCall!)} toolResult={entry.toolResult!} />;
|
||||
}
|
||||
|
||||
@@ -4378,6 +4381,35 @@ function ToolTextOutputView({ t, label, content }: { t: Theme; label: string; co
|
||||
);
|
||||
}
|
||||
|
||||
function openMediaFile(filePath: string): void {
|
||||
try {
|
||||
const cmd = process.platform === "darwin" ? "open" : "xdg-open";
|
||||
require("child_process").execFile(cmd, [filePath]);
|
||||
} catch {}
|
||||
}
|
||||
|
||||
function MediaAutoOpenView({ t, label, toolResult }: { t: Theme; label: string; toolResult: ToolResult }) {
|
||||
const media = toolResult.media ?? [];
|
||||
const openedRef = useRef<Set<string>>(new Set());
|
||||
|
||||
useEffect(() => {
|
||||
for (const asset of media) {
|
||||
if (!openedRef.current.has(asset.path)) {
|
||||
openedRef.current.add(asset.path);
|
||||
openMediaFile(asset.path);
|
||||
}
|
||||
}
|
||||
}, [media]);
|
||||
|
||||
return (
|
||||
<box gap={0}>
|
||||
<InlineTool t={t} pending={false}>
|
||||
{label}
|
||||
</InlineTool>
|
||||
</box>
|
||||
);
|
||||
}
|
||||
|
||||
function MediaToolResultView({ t, label, toolResult }: { t: Theme; label: string; toolResult: ToolResult }) {
|
||||
const media = toolResult.media ?? [];
|
||||
|
||||
|
||||
Reference in new issue
Block a user