mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-19 04:16:03 +00:00
fix(agent): enrich <media:image> tags with persisted media IDs for Discord image attachments (#179)
* fix(agent): enrich <media:image> tags with persisted media IDs for Discord image attachments Discord image attachments were downloaded and persisted correctly, but <media:image> tags in the message content remained bare (no ID attribute), unlike <media:audio> and <media:video> tags which get enriched with media IDs. This made it harder for the LLM to confirm image receipt and reference specific images. Add enrichImageIDs() that embeds persisted media IDs into <media:image> tags, matching the existing enrichAudioIDs()/enrichVideoIDs() pattern. Iterates refs in reverse order to correctly map multiple image refs to their positional tags when users attach several images at once. Closes #178 https://claude.ai/code/session_01KkE9UxcNB8eXpqRiJHRqeB * style(agent): add missing continue in enrichImageIDs for consistency with enrichVideoIDs https://claude.ai/code/session_01KkE9UxcNB8eXpqRiJHRqeB --------- Co-authored-by: Claude <noreply@anthropic.com> Co-authored-by: Viet Tran <viettranx@gmail.com>
This commit is contained in:
2 files changed
+45
-2
No files matched your search
@@ -297,8 +297,12 @@ func (l *Loop) runLoop(ctx context.Context, req RunRequest) (*RunResult, error)
|
||||
l.enrichVideoIDs(messages, mediaRefs)
|
||||
}
|
||||
|
||||
// 2e. Cross-session recovery: recover stale locked tasks and notify team leads
|
||||
// about orphaned pending tasks and in-progress tasks being handled by delegates.
|
||||
// 2e. Enrich <media:image> tags with persisted media IDs so the LLM
|
||||
// knows images were received and stored (consistent with audio/video enrichment).
|
||||
l.enrichImageIDs(messages, mediaRefs)
|
||||
|
||||
// 2f. Cross-session recovery: notify team leads about orphaned pending tasks
|
||||
// and in-progress tasks being handled by delegates.
|
||||
// Safe because Bước 1 (early ClaimTask) ensures running tasks are in_progress,
|
||||
// so only truly un-spawned tasks remain pending.
|
||||
if l.teamStore != nil && l.agentUUID != uuid.Nil {
|
||||
|
||||
@@ -244,6 +244,45 @@ func (l *Loop) enrichVideoIDs(messages []providers.Message, refs []providers.Med
|
||||
messages[lastIdx].Content = content
|
||||
}
|
||||
|
||||
// enrichImageIDs updates the last user message to embed persisted media IDs
|
||||
// in <media:image> tags so the LLM knows images were received and stored.
|
||||
// Without this, the LLM sees plain <media:image> and cannot confirm image availability.
|
||||
// Iterates refs in reverse order so that when multiple images are present,
|
||||
// each ref maps to the correct positional tag (last ref → last tag, etc.).
|
||||
func (l *Loop) enrichImageIDs(messages []providers.Message, refs []providers.MediaRef) {
|
||||
if len(messages) == 0 {
|
||||
return
|
||||
}
|
||||
lastIdx := -1
|
||||
for i := len(messages) - 1; i >= 0; i-- {
|
||||
if messages[i].Role == "user" {
|
||||
lastIdx = i
|
||||
break
|
||||
}
|
||||
}
|
||||
if lastIdx < 0 {
|
||||
return
|
||||
}
|
||||
|
||||
content := messages[lastIdx].Content
|
||||
// Iterate in reverse so first ref matches first tag when using LastIndex replacements.
|
||||
for i := len(refs) - 1; i >= 0; i-- {
|
||||
ref := refs[i]
|
||||
if ref.Kind != "image" {
|
||||
continue
|
||||
}
|
||||
idAttr := fmt.Sprintf(" id=%q", ref.ID)
|
||||
|
||||
// Replace the LAST bare <media:image> with <media:image id="uuid">
|
||||
bare := "<media:image>"
|
||||
if idx := strings.LastIndex(content, bare); idx >= 0 {
|
||||
content = content[:idx] + "<media:image" + idAttr + ">" + content[idx+len(bare):]
|
||||
continue
|
||||
}
|
||||
}
|
||||
messages[lastIdx].Content = content
|
||||
}
|
||||
|
||||
// mediaKindFromMime returns the media kind ("image", "video", "audio", "document")
|
||||
// based on MIME type prefix.
|
||||
func mediaKindFromMime(mime string) string {
|
||||
|
||||
Reference in new issue
Block a user