DEV Community

chowyu
chowyu

Posted on Fully Autonomous

How AIClaw 3.7.4 Keeps Generated Images Visible After Reopening a Chat

An agent generates a picture, saves it successfully, and answers with a local filename. The tool did its job. The user still has to find the file to see the result.

That was the gap behind AIClaw 3.7.4. The release adds inline previews for generated images, including images restored from older conversations. The interesting part was making the result survive the whole trip through tool execution, storage, and history replay.

AIClaw is an open-source desktop agent with an Electron/Vue interface and a Go kernel. Here is how this change fits into that architecture.

A small UI contract

The display rules are deliberately simple:

  • One image gets a larger preview below the answer.
  • Multiple images appear as a row of thumbnails that wraps when needed.
  • Clicking a preview opens a large image viewer inside the app.
  • Escape, the close button, or a click on the backdrop closes the viewer.
  • The filename remains available as an action for opening the local file.

The images sit outside the collapsed execution steps. A user can inspect the output without expanding the tool log, while the log remains available for understanding how it was produced.

The preview starts with tool metadata

The renderer collects image artifacts from successful tool steps in the current turn. It filters supported image extensions and deduplicates paths within that turn.

The path comes from the tool result's artifact metadata. We do not scan the assistant's answer for anything that resembles a filename. An assistant can mention an example path or describe a file that was never created; that text alone should not become a preview.

The flow is:

Tool execution → artifact paths → saved tool result → restored history item → turn-level image collection → preview

In the Go message structure, the persisted field is small:

// Artifacts are local UI metadata, omitted from model requests.
Artifacts []string `json:"artifacts,omitempty"`
Enter fullscreen mode Exit fullscreen mode

The model request builder omits this field. The UI needs it to restore local outputs; it does not need to add those paths to the model's request payload.

The bug that only appeared in history

A preview working during a live turn is only half the job. Older sessions were saved before artifact paths were included in the stored messages.

Some of those sessions also used Code Mode. The image tool ran inside the exec wrapper, so the outer tool result was a string describing the generated file. That string could be plain text or JSON-encoded text, and it could appear among multiple output lines.

Supporting only the direct image tool missed that case. Reopening the conversation still produced the answer and filename, but no image metadata reached the renderer.

The compatibility path now handles the standard saved-image result emitted by both generate_image and exec. For wrapper output, it attempts to decode each line as a JSON string before matching the known result format.

This is intentionally narrow: it recognizes the tool's standard Chinese or English success prefix and its generated image filename format. It keeps existing structured metadata when present, deduplicates recovered paths, and avoids extracting files from arbitrary assistant prose or unrelated tools.

That gives older conversations a recovery path without making every line of chat text a file-discovery mechanism.

Load images when they become visible

A long history can contain many generated images. Loading all of them immediately would make reopening that history unnecessarily expensive.

The Vue component uses IntersectionObserver to begin reading images when their turn enters the viewport. It then reads each file through the desktop host's media interface.

Read or decode failures stay local to the affected image. The text answer and other previews remain usable. The large viewer uses the browser's native <dialog> element, with explicit controls for closing it.

The component is also keyed by session and turn so that switching conversations does not accidentally reuse another turn's media state.

What we verified

The release includes regression coverage for:

  • Artifact paths surviving save and load.
  • Legacy Code Mode output restoring the image metadata.
  • Plain strings, JSON strings, multiple lines, and duplicate paths.
  • Unrelated tools and failed steps being excluded from previews.
  • Single-image and multiple-image layouts, large-viewer controls, and local image errors.

The release notes record the full local check passing, 34 work-interface smoke checks, and 13 real-model scenarios passing with no failures or skips. The UI checks use fixtures to exercise display behavior; the real-model scenarios separately cover capabilities including image generation. Those are different kinds of evidence.

Try it or read the implementation

Download AIClaw 3.7.4.

The relevant code is small enough to follow directly:

This feature previews local image artifacts produced by tools. Automatically recognizing arbitrary image URLs pasted into a conversation is a separate capability.

For an agent application, the saved conversation includes more than the assistant's words. Its outputs need enough structure to remain useful when the user returns later.

This post was prepared with AI assistance and checked against the AIClaw 3.7.4 implementation and release notes.

Top comments (1)

Collapse
 
baumgaerben profile image
baumgaerben •

Vấn đề persistence của file local giữa các session là một pain point thực tế khi build agent dùng tool calling. Cách AIClaw handle — map filename về một resource ID ổn định thay vì trả path tuyệt đối — nghe khá hợp lý vì nó tách biệt storage layer khỏi presentation layer.

Một số thứ mình hay gặp khi implement pattern này:

  • Collision handling: Nếu user mở 2 tab chat cùng lúc, agent generate ảnh trùng tên → cần namespace theo session_id hoặc hash nội dung
  • Cleanup policy: File orphaned khi user xóa conversation hoặc session expire → cần background job dọn dẹp định kỳ, không để disk đầy
  • Permission boundary: Đảm bảo agent A không đọc được file của agent B nếu chạy multi-tenant

Bài viết chưa nhắc đến việc handle khi storage backend thay đổi (local → S3 → R2). Mình thường wrap một interface ArtifactStore với save(bytes, meta) -> ref và resolve(ref) -> stream, như vậy swap backend sau này không break contract với agent.

Có test case nào cover scenario network partition khi agent đang write file mà process crash giữa chừng không? PS: the tool I meant is on labagent .tech