From 7301ad5eb49c82ab5f354324ef5f67089f38dc9f Mon Sep 17 00:00:00 2001 From: Duy Nguyen Date: Sun, 22 Mar 2026 16:38:15 +0700 Subject: [PATCH] fix(vision): prevent image base64 leak to DB and load historical images for read_image tool Images field on Message had json:"images,omitempty" tag allowing base64 data to be serialized into session JSONB. Changed to json:"-" to match the "runtime only" intent. Also removed deferToReadImageTool gate on loadHistoricalImagesForTool so read_image tool can access historical images in both inline and tool-deferred vision modes. --- internal/agent/loop.go | 7 +++++-- internal/providers/types.go | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/internal/agent/loop.go b/internal/agent/loop.go index b260c459..f05b0e1d 100644 --- a/internal/agent/loop.go +++ b/internal/agent/loop.go @@ -303,9 +303,12 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error) } } - // 2a. Tool mode: also load historical images into context for read_image tool. + // 2a. Load historical images into context for read_image tool. // Without this, read_image can only see current-turn images, not previous turns. - if deferToReadImageTool && l.mediaStore != nil { + // Both inline and tool-deferred modes need this — inline mode attaches images to + // messages for the main LLM, but the read_image tool also needs context access + // to analyze historical images on demand. + if l.mediaStore != nil { ctx = l.loadHistoricalImagesForTool(ctx, mediaRefs, messages) } diff --git a/internal/providers/types.go b/internal/providers/types.go index ee3405ea..a0cb1ff3 100644 --- a/internal/providers/types.go +++ b/internal/providers/types.go @@ -95,7 +95,7 @@ type Message struct { Role string `json:"role"` // "system", "user", "assistant", "tool" Content string `json:"content"` Thinking string `json:"thinking,omitempty"` // reasoning_content for thinking models (Kimi, DeepSeek, etc.) - Images []ImageContent `json:"images,omitempty"` // vision: base64 images (runtime only, not persisted) + Images []ImageContent `json:"-"` // vision: base64 images (runtime only, never persisted to DB) MediaRefs []MediaRef `json:"media_refs,omitempty"` // persistent media file references ToolCalls []ToolCall `json:"tool_calls,omitempty"` ToolCallID string `json:"tool_call_id,omitempty"` // for role="tool" responses