From f13f6b531d1106ee0fc4114e0d7b55a1c30e8d4e Mon Sep 17 00:00:00 2001 From: Guoguo Date: Wed, 29 Apr 2026 19:13:17 -0700 Subject: [PATCH] fix(media): prepend path tags for JSON content, narrow looksLikeJSON Two fixes from code review: 1. looksLikeJSON now only checks for '{' prefix (not '['), avoiding false positives on regular text like "[update] see attached". 2. For JSON content (Feishu cards/posts), path tags are prepended before the JSON instead of being silently dropped. This ensures the LLM can discover attached images via the path tag while the JSON payload stays valid for downstream parsing. Co-Authored-By: Claude Opus 4.7 (1M context) --- pkg/agent/agent_media.go | 3 ++- pkg/agent/agent_test.go | 25 ++++++++++++++----------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/pkg/agent/agent_media.go b/pkg/agent/agent_media.go index 9ec3ec585..c02c7392c 100644 --- a/pkg/agent/agent_media.go +++ b/pkg/agent/agent_media.go @@ -269,6 +269,7 @@ func injectPathTags(content string, tags []string) string { } if isStructured { + content = tag + "\n" + content continue } @@ -283,5 +284,5 @@ func injectPathTags(content string, tags []string) string { func looksLikeJSON(s string) bool { s = strings.TrimSpace(s) - return len(s) > 1 && (s[0] == '{' || s[0] == '[') + return len(s) > 1 && s[0] == '{' } diff --git a/pkg/agent/agent_test.go b/pkg/agent/agent_test.go index e1ee0fafb..f326e2acb 100644 --- a/pkg/agent/agent_test.go +++ b/pkg/agent/agent_test.go @@ -5040,23 +5040,25 @@ func TestInjectPathTags_DoesNotReplacePathTag(t *testing.T) { } } -func TestInjectPathTags_SkipsAppendForJSONContent(t *testing.T) { +func TestInjectPathTags_PrependsForJSONContent(t *testing.T) { jsonContent := `{"schema":"2.0","body":{"elements":[{"tag":"img","img_key":"img_123"}]}}` got := injectPathTags(jsonContent, []string{"[image:/tmp/photo.png]"}) - if got != jsonContent { - t.Fatalf("expected JSON content unchanged, got %q", got) + want := "[image:/tmp/photo.png]\n" + jsonContent + if got != want { + t.Fatalf("expected tag prepended to JSON, got %q", got) } } -func TestInjectPathTags_JSONArrayContent(t *testing.T) { - jsonContent := `[{"tag":"text","text":"hello"}]` - got := injectPathTags(jsonContent, []string{"[file:/tmp/doc.pdf]"}) - if got != jsonContent { - t.Fatalf("expected JSON array content unchanged, got %q", got) +func TestInjectPathTags_BracketTextNotTreatedAsJSON(t *testing.T) { + content := "[update] see attached report" + got := injectPathTags(content, []string{"[file:/tmp/report.pdf]"}) + want := "[update] see attached report [file:/tmp/report.pdf]" + if got != want { + t.Fatalf("expected tag appended to bracket text, got %q", got) } } -func TestResolveMediaRefs_JSONContentPreservesStructure(t *testing.T) { +func TestResolveMediaRefs_JSONContentPrependsPathTag(t *testing.T) { store := media.NewFileMediaStore() dir := t.TempDir() @@ -5076,8 +5078,9 @@ func TestResolveMediaRefs_JSONContentPreservesStructure(t *testing.T) { } result := resolveMediaRefs(messages, store, config.DefaultMaxMediaSize) - if result[0].Content != jsonContent { - t.Fatalf("expected JSON content preserved, got %q", result[0].Content) + want := "[image:" + pngPath + "]\n" + jsonContent + if result[0].Content != want { + t.Fatalf("expected path tag prepended to JSON content, got %q", result[0].Content) } }