From 15772c4e6adcb14e173dd6c7a1e0bf8ab55c3797 Mon Sep 17 00:00:00 2001 From: AmChocolate Date: Sun, 15 Mar 2026 21:57:56 +0800 Subject: [PATCH] feat: wire image_model config to agent loop for vision-capable models - Add media parameter to selectCandidates function - Check for media attachments and route to image_model when present Fixes issue #1578 --- pkg/agent/loop.go | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/pkg/agent/loop.go b/pkg/agent/loop.go index f20a56b9c..d09903b10 100644 --- a/pkg/agent/loop.go +++ b/pkg/agent/loop.go @@ -1004,7 +1004,7 @@ func (al *AgentLoop) runLLMIteration( // selectCandidates evaluates routing once and the decision is sticky for // all tool-follow-up iterations within the same turn so that a multi-step // tool chain doesn't switch models mid-way through. - activeCandidates, activeModel := al.selectCandidates(agent, opts.UserMessage, messages) + activeCandidates, activeModel := al.selectCandidates(agent, opts.UserMessage, messages, opts.Media) for iteration < agent.MaxIterations { iteration++ @@ -1406,6 +1406,9 @@ func (al *AgentLoop) runLLMIteration( // message scores below the complexity threshold, it returns the light model // candidates instead of the primary ones. // +// If the message contains media attachments (images) and an image_model is +// configured, the image model candidates are returned instead. +// // The returned (candidates, model) pair is used for all LLM calls within one // turn — tool follow-up iterations use the same tier as the initial call so // that a multi-step tool chain doesn't switch models mid-way. @@ -1413,7 +1416,19 @@ func (al *AgentLoop) selectCandidates( agent *AgentInstance, userMsg string, history []providers.Message, + media []string, ) (candidates []providers.FallbackCandidate, model string) { + // If image_model is configured and there are media attachments, route to image model + if len(media) > 0 && agent.ImageModel != "" && len(agent.ImageModelCandidates) > 0 { + logger.InfoCF("agent", "Image model routing: media attachments detected", + map[string]any{ + "agent_id": agent.ID, + "image_model": agent.ImageModel, + "media_count": len(media), + }) + return agent.ImageModelCandidates, agent.ImageModel + } + if agent.Router == nil || len(agent.LightCandidates) == 0 { return agent.Candidates, agent.Model }