From cb3e1c0cd32606a7f53603da502b00ebdabec1cf Mon Sep 17 00:00:00 2001 From: Marius van Niekerk Date: Tue, 24 Mar 2026 11:58:18 -0400 Subject: [PATCH] refactor(agent): unify workflow resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Shared workflow resolution now owns preferred-agent, backup-agent, and model selection precedence across fix, refine, review, daemon, and batch callers. Validation: go fmt ./... && go vet ./... && go test ./... && roborev fix --open --list 🤖 Generated with [OpenAI Codex](https://openai.com/codex) Co-authored-by: OpenAI Codex --- cmd/roborev/analyze.go | 22 +++----- cmd/roborev/fix.go | 31 +++++------ cmd/roborev/refine.go | 34 ++++++------- cmd/roborev/review.go | 13 +++-- internal/agent/model_resolution.go | 68 +++++++++++++++++++++++++ internal/agent/model_resolution_test.go | 31 +++++++++++ internal/daemon/ci_poller.go | 28 ++++------ internal/daemon/server.go | 53 ++++++------------- internal/daemon/worker.go | 13 ++--- internal/review/batch.go | 31 ++++------- 10 files changed, 188 insertions(+), 136 deletions(-) diff --git a/cmd/roborev/analyze.go b/cmd/roborev/analyze.go index 366a8f9f2..74e4e978b 100644 --- a/cmd/roborev/analyze.go +++ b/cmd/roborev/analyze.go @@ -803,25 +803,19 @@ func runFixAgent(cmd *cobra.Command, repoPath, agentName, model, reasoning, prom } // Resolve agent and model via fix workflow config. - agentName = config.ResolveAgentForWorkflow(agentName, repoPath, cfg, "fix", reasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(repoPath, cfg, "fix") + resolution := agent.ResolveWorkflowConfig( + agentName, repoPath, cfg, "fix", reasoning, + ) + agentName = resolution.PreferredAgent - a, err := agent.GetAvailableWithConfig(agentName, cfg, backupAgent) + a, err := agent.GetAvailableWithConfig( + agentName, cfg, resolution.BackupAgent, + ) if err != nil { return fmt.Errorf("get agent: %w", err) } - // Use backup model when the backup agent was selected and no - // explicit model was passed via CLI. - preferredForAnalyze := config.ResolveAgentForWorkflow(agentName, repoPath, cfg, "fix", reasoning) - usingBackup := backupAgent != "" && - agent.CanonicalName(a.Name()) == agent.CanonicalName(backupAgent) && - agent.CanonicalName(a.Name()) != agent.CanonicalName(preferredForAnalyze) - if usingBackup && model == "" { - model = config.ResolveBackupModelForWorkflow(repoPath, cfg, "fix") - } else { - model = resolveFixModel(a.Name(), model, repoPath, cfg, reasoning) - } + model = resolution.ModelForSelectedAgent(a.Name(), model) // Configure agent: agentic mode, with model and reasoning reasoningLevel := agent.ParseReasoningLevel(reasoning) diff --git a/cmd/roborev/fix.go b/cmd/roborev/fix.go index 18e46228a..38a9f60c0 100644 --- a/cmd/roborev/fix.go +++ b/cmd/roborev/fix.go @@ -322,8 +322,11 @@ func resolveFixModel( selectedAgent, cliModel, repoPath string, cfg *config.Config, reasoning string, ) string { - return agent.ResolveWorkflowModelForAgent( - selectedAgent, cliModel, repoPath, cfg, "fix", reasoning, + resolution := agent.ResolveWorkflowConfig( + "", repoPath, cfg, "fix", reasoning, + ) + return resolution.ModelForSelectedAgent( + selectedAgent, cliModel, ) } @@ -339,26 +342,20 @@ func resolveFixAgent(repoPath string, opts fixOptions) (agent.Agent, error) { return nil, fmt.Errorf("resolve fix reasoning: %w", err) } - agentName := config.ResolveAgentForWorkflow(opts.agentName, repoPath, cfg, "fix", reasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(repoPath, cfg, "fix") + resolution := agent.ResolveWorkflowConfig( + opts.agentName, repoPath, cfg, "fix", reasoning, + ) - a, err := agent.GetAvailableWithConfig(agentName, cfg, backupAgent) + a, err := agent.GetAvailableWithConfig( + resolution.PreferredAgent, cfg, resolution.BackupAgent, + ) if err != nil { return nil, fmt.Errorf("get agent: %w", err) } - // Use backup model when the backup agent was selected and no - // explicit model was passed via CLI. - preferredAgent := config.ResolveAgentForWorkflow(opts.agentName, repoPath, cfg, "fix", reasoning) - usingBackup := backupAgent != "" && - agent.CanonicalName(a.Name()) == agent.CanonicalName(backupAgent) && - agent.CanonicalName(a.Name()) != agent.CanonicalName(preferredAgent) - var modelStr string - if usingBackup && opts.model == "" { - modelStr = config.ResolveBackupModelForWorkflow(repoPath, cfg, "fix") - } else { - modelStr = resolveFixModel(a.Name(), opts.model, repoPath, cfg, reasoning) - } + modelStr := resolution.ModelForSelectedAgent( + a.Name(), opts.model, + ) reasoningLevel := agent.ParseReasoningLevel(reasoning) a = a.WithAgentic(true).WithReasoning(reasoningLevel) diff --git a/cmd/roborev/refine.go b/cmd/roborev/refine.go index ae53f8341..4ef1ce174 100644 --- a/cmd/roborev/refine.go +++ b/cmd/roborev/refine.go @@ -355,9 +355,10 @@ func runRefine(ctx RunContext, opts refineOptions) error { } reasoningLevel := agent.ParseReasoningLevel(resolvedReasoning) - // Resolve agent for refine workflow at this reasoning level - resolvedAgent := config.ResolveAgentForWorkflow(opts.agentName, repoPath, cfg, "refine", resolvedReasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(repoPath, cfg, "refine") + // Resolve agent/model preferences for refine at this reasoning level. + resolution := agent.ResolveWorkflowConfig( + opts.agentName, repoPath, cfg, "refine", resolvedReasoning, + ) allowUnsafe := resolveAllowUnsafeAgents(opts.allowUnsafeAgents, opts.unsafeFlagChanged, cfg) agent.SetAllowUnsafeAgents(allowUnsafe) if cfg != nil { @@ -367,12 +368,14 @@ func runRefine(ctx RunContext, opts refineOptions) error { // Get the agent with configured reasoning level (model applied after // backup determination to avoid baking the primary model into a // backup agent). - addressAgent, err := selectRefineAgent(cfg, resolvedAgent, reasoningLevel, backupAgent) + addressAgent, err := selectRefineAgent( + cfg, resolution.PreferredAgent, reasoningLevel, resolution.BackupAgent, + ) if err != nil { return fmt.Errorf("no agent available: %w", err) } addressAgent, _ = applyModelForAgent( - addressAgent, resolvedAgent, backupAgent, + addressAgent, resolution.PreferredAgent, resolution.BackupAgent, opts.model, repoPath, cfg, "refine", resolvedReasoning, ) fmt.Printf("Using agent: %s\n", addressAgent.Name()) @@ -1214,20 +1217,15 @@ func applyModelForAgent( workflow string, reasoning string, ) (agent.Agent, string) { - usingBackup := backupAgentName != "" && - agent.CanonicalName(a.Name()) == agent.CanonicalName(backupAgentName) && - agent.CanonicalName(a.Name()) != agent.CanonicalName(preferredAgent) - - var model string - if usingBackup && cliModel == "" { - model = config.ResolveBackupModelForWorkflow( - repoPath, cfg, workflow, - ) - } else { - model = agent.ResolveWorkflowModelForAgent( - a.Name(), cliModel, repoPath, cfg, workflow, reasoning, - ) + resolution := agent.WorkflowConfig{ + RepoPath: repoPath, + GlobalConfig: cfg, + Workflow: workflow, + Reasoning: reasoning, + PreferredAgent: preferredAgent, + BackupAgent: backupAgentName, } + model := resolution.ModelForSelectedAgent(a.Name(), cliModel) if model != "" { a = a.WithModel(model) diff --git a/cmd/roborev/review.go b/cmd/roborev/review.go index d7e06b150..01bc791ab 100644 --- a/cmd/roborev/review.go +++ b/cmd/roborev/review.go @@ -384,12 +384,15 @@ func runLocalReview(cmd *cobra.Command, repoPath, gitRef, diffContent, agentName workflow = reviewType } - // Resolve agent using workflow-specific resolution (matches daemon behavior) - preferredAgent := config.ResolveAgentForWorkflow(agentName, repoPath, cfg, workflow, reasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(repoPath, cfg, workflow) + // Resolve agent/model preferences (matches daemon behavior). + resolution := agent.ResolveWorkflowConfig( + agentName, repoPath, cfg, workflow, reasoning, + ) // Get the agent (try backup before hardcoded chain) - a, err := agent.GetAvailableWithConfig(preferredAgent, cfg, backupAgent) + a, err := agent.GetAvailableWithConfig( + resolution.PreferredAgent, cfg, resolution.BackupAgent, + ) if err != nil { return fmt.Errorf("get agent: %w", err) } @@ -399,7 +402,7 @@ func runLocalReview(cmd *cobra.Command, repoPath, gitRef, diffContent, agentName reasoningLevel := agent.ParseReasoningLevel(reasoning) a = a.WithReasoning(reasoningLevel) a, model = applyModelForAgent( - a, preferredAgent, backupAgent, + a, resolution.PreferredAgent, resolution.BackupAgent, model, repoPath, cfg, workflow, reasoning, ) diff --git a/internal/agent/model_resolution.go b/internal/agent/model_resolution.go index 908f24e5d..80656fd0a 100644 --- a/internal/agent/model_resolution.go +++ b/internal/agent/model_resolution.go @@ -6,6 +6,74 @@ import ( "github.com/roborev-dev/roborev/internal/config" ) +// WorkflowConfig captures the workflow-specific agent resolution context +// shared by CLI, daemon, and batch review callers. +type WorkflowConfig struct { + RepoPath string + GlobalConfig *config.Config + Workflow string + Reasoning string + PreferredAgent string + BackupAgent string +} + +// ResolveWorkflowConfig resolves the preferred and backup agents for a +// workflow while retaining the workflow and reasoning context needed to +// resolve the final model after an agent has been selected. +func ResolveWorkflowConfig( + cliAgent, repoPath string, + globalCfg *config.Config, + workflow, reasoning string, +) WorkflowConfig { + return WorkflowConfig{ + RepoPath: repoPath, + GlobalConfig: globalCfg, + Workflow: workflow, + Reasoning: reasoning, + PreferredAgent: config.ResolveAgentForWorkflow(cliAgent, repoPath, globalCfg, workflow, reasoning), + BackupAgent: config.ResolveBackupAgentForWorkflow(repoPath, globalCfg, workflow), + } +} + +// AgentMatches reports whether two agent names refer to the same logical +// agent after alias and ACP-name normalization. +func (w WorkflowConfig) AgentMatches(left, right string) bool { + return workflowModelComparableAgentName(left, w.GlobalConfig) == + workflowModelComparableAgentName(right, w.GlobalConfig) +} + +// UsesBackupAgent reports whether the selected agent is the configured +// backup rather than the preferred primary for this workflow. +func (w WorkflowConfig) UsesBackupAgent(selectedAgent string) bool { + return w.BackupAgent != "" && + w.AgentMatches(selectedAgent, w.BackupAgent) && + !w.AgentMatches(selectedAgent, w.PreferredAgent) +} + +// BackupModel returns the workflow backup model override, if any. +func (w WorkflowConfig) BackupModel() string { + return config.ResolveBackupModelForWorkflow( + w.RepoPath, w.GlobalConfig, w.Workflow, + ) +} + +// ModelForSelectedAgent resolves the model for the actual selected +// agent. Backup agents use the workflow backup model when no explicit +// CLI model was provided; otherwise the workflow/default precedence used +// by ResolveWorkflowModelForAgent is preserved. +func (w WorkflowConfig) ModelForSelectedAgent( + selectedAgent, cliModel string, +) string { + if w.UsesBackupAgent(selectedAgent) && + strings.TrimSpace(cliModel) == "" { + return w.BackupModel() + } + return ResolveWorkflowModelForAgent( + selectedAgent, cliModel, w.RepoPath, + w.GlobalConfig, w.Workflow, w.Reasoning, + ) +} + // ResolveWorkflowModelForAgent resolves a workflow model for the actual // agent that will run. If that agent differs from the generic default // agent and no explicit model was provided, generic default_model is diff --git a/internal/agent/model_resolution_test.go b/internal/agent/model_resolution_test.go index 684200dd7..952711909 100644 --- a/internal/agent/model_resolution_test.go +++ b/internal/agent/model_resolution_test.go @@ -272,3 +272,34 @@ agent = "custom-acp" ) require.Equal(t, "gpt-5.4", got, "ResolveWorkflowModelForAgent() = %q, want %q", got, "gpt-5.4") } + +func TestResolveWorkflowConfigModelForSelectedAgent_UsesBackupModelForAliasMatch(t *testing.T) { + t.Parallel() + + cfg := &config.Config{ + ReviewAgent: "gemini", + ReviewBackupAgent: "claude", + ReviewBackupModel: "claude-sonnet", + } + + resolution := ResolveWorkflowConfig("", t.TempDir(), cfg, "review", "standard") + + require.Equal(t, "gemini", resolution.PreferredAgent) + require.Equal(t, "claude", resolution.BackupAgent) + require.Equal(t, "claude-sonnet", resolution.ModelForSelectedAgent("claude-code", "")) +} + +func TestResolveWorkflowConfigModelForSelectedAgent_BackupWithoutModelKeepsDefault(t *testing.T) { + t.Parallel() + + cfg := &config.Config{ + DefaultAgent: "codex", + DefaultModel: "gpt-5.4", + ReviewAgent: "gemini", + ReviewBackupAgent: "claude", + } + + resolution := ResolveWorkflowConfig("", t.TempDir(), cfg, "review", "standard") + + require.Empty(t, resolution.ModelForSelectedAgent("claude-code", "")) +} diff --git a/internal/daemon/ci_poller.go b/internal/daemon/ci_poller.go index e7168d519..3135635e8 100644 --- a/internal/daemon/ci_poller.go +++ b/internal/daemon/ci_poller.go @@ -562,9 +562,11 @@ func (p *CIPoller) processPR(ctx context.Context, ghRepo string, pr ghPR, cfg *c workflow = rt } - // Resolve agent through workflow config when not explicitly set - resolvedAgent := config.ResolveAgentForWorkflow(ag, repo.RootPath, cfg, workflow, reasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(repo.RootPath, cfg, workflow) + // Resolve agent through workflow config when not explicitly set. + resolution := agent.ResolveWorkflowConfig( + ag, repo.RootPath, cfg, workflow, reasoning, + ) + resolvedAgent := resolution.PreferredAgent if p.agentResolverFn != nil { name, err := p.agentResolverFn(resolvedAgent) if err != nil { @@ -572,26 +574,18 @@ func (p *CIPoller) processPR(ctx context.Context, ghRepo string, pr ghPR, cfg *c return fmt.Errorf("no review agent available for type=%s: %w", rt, err) } resolvedAgent = name - } else if resolved, err := agent.GetAvailableWithConfig(resolvedAgent, cfg, backupAgent); err != nil { + } else if resolved, err := agent.GetAvailableWithConfig( + resolvedAgent, cfg, resolution.BackupAgent, + ); err != nil { rollback("No agent available — check agent config or quota") return fmt.Errorf("no review agent available for type=%s: %w", rt, err) } else { resolvedAgent = resolved.Name() } - // Use backup model when the backup agent was selected - preferredForWorkflow := config.ResolveAgentForWorkflow(ag, repo.RootPath, cfg, workflow, reasoning) - usingBackup := backupAgent != "" && - agent.CanonicalName(resolvedAgent) == agent.CanonicalName(backupAgent) && - agent.CanonicalName(resolvedAgent) != agent.CanonicalName(preferredForWorkflow) - var resolvedModel string - if usingBackup && cfg.CI.Model == "" { - resolvedModel = config.ResolveBackupModelForWorkflow(repo.RootPath, cfg, workflow) - } else { - resolvedModel = agent.ResolveWorkflowModelForAgent( - resolvedAgent, cfg.CI.Model, repo.RootPath, cfg, workflow, reasoning, - ) - } + resolvedModel := resolution.ModelForSelectedAgent( + resolvedAgent, cfg.CI.Model, + ) job, err := p.db.EnqueueJob(storage.EnqueueOpts{ RepoID: repo.ID, diff --git a/internal/daemon/server.go b/internal/daemon/server.go index 8de42a353..eaa7f928b 100644 --- a/internal/daemon/server.go +++ b/internal/daemon/server.go @@ -780,13 +780,17 @@ func (s *Server) handleEnqueue(w http.ResponseWriter, r *http.Request) { // Resolve agent for workflow at this reasoning level cfg := s.configWatcher.Config() - agentName := config.ResolveAgentForWorkflow(req.Agent, repoRoot, cfg, workflow, reasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(repoRoot, cfg, workflow) + resolution := agent.ResolveWorkflowConfig( + req.Agent, repoRoot, cfg, workflow, reasoning, + ) + agentName := resolution.PreferredAgent // Resolve to an installed agent: if the configured agent isn't available, // try the backup agent before the hardcoded fallback chain. // Unknown agent names (typos) return 400; no agents at all returns 503. - if resolved, err := agent.GetAvailableWithConfig(agentName, cfg, backupAgent); err != nil { + if resolved, err := agent.GetAvailableWithConfig( + agentName, cfg, resolution.BackupAgent, + ); err != nil { var unknownErr *agent.UnknownAgentError if errors.As(err, &unknownErr) { writeError(w, http.StatusBadRequest, fmt.Sprintf("invalid agent: %v", err)) @@ -798,26 +802,7 @@ func (s *Server) handleEnqueue(w http.ResponseWriter, r *http.Request) { agentName = resolved.Name() } - // Detect whether the resolved agent is the backup (not the preferred). - // When the backup agent is used and no explicit model was requested, - // use the backup model instead of the default model. - preferredAgent := config.ResolveAgentForWorkflow( - req.Agent, repoRoot, cfg, workflow, reasoning, - ) - usingBackup := backupAgent != "" && - agent.CanonicalName(agentName) == agent.CanonicalName(backupAgent) && - agent.CanonicalName(agentName) != agent.CanonicalName(preferredAgent) - - var model string - if usingBackup && req.Model == "" { - model = config.ResolveBackupModelForWorkflow( - repoRoot, cfg, workflow, - ) - } else { - model = agent.ResolveWorkflowModelForAgent( - agentName, req.Model, repoRoot, cfg, workflow, reasoning, - ) - } + model := resolution.ModelForSelectedAgent(agentName, req.Model) if req.JobType == storage.JobTypeInsights { if req.Since == "" { @@ -2325,9 +2310,13 @@ func (s *Server) handleFixJob(w http.ResponseWriter, r *http.Request) { // Resolve agent for fix workflow cfg := s.configWatcher.Config() reasoning := "standard" - agentName := config.ResolveAgentForWorkflow("", parentJob.RepoPath, cfg, "fix", reasoning) - backupAgent := config.ResolveBackupAgentForWorkflow(parentJob.RepoPath, cfg, "fix") - if resolved, err := agent.GetAvailableWithConfig(agentName, cfg, backupAgent); err != nil { + resolution := agent.ResolveWorkflowConfig( + "", parentJob.RepoPath, cfg, "fix", reasoning, + ) + agentName := resolution.PreferredAgent + if resolved, err := agent.GetAvailableWithConfig( + agentName, cfg, resolution.BackupAgent, + ); err != nil { var unknownErr *agent.UnknownAgentError if errors.As(err, &unknownErr) { writeError(w, http.StatusBadRequest, fmt.Sprintf("invalid agent: %v", err)) @@ -2339,17 +2328,7 @@ func (s *Server) handleFixJob(w http.ResponseWriter, r *http.Request) { agentName = resolved.Name() } - // Use backup model when the backup agent was selected - preferredAgent := config.ResolveAgentForWorkflow("", parentJob.RepoPath, cfg, "fix", reasoning) - usingBackup := backupAgent != "" && - agent.CanonicalName(agentName) == agent.CanonicalName(backupAgent) && - agent.CanonicalName(agentName) != agent.CanonicalName(preferredAgent) - var model string - if usingBackup { - model = config.ResolveBackupModelForWorkflow(parentJob.RepoPath, cfg, "fix") - } else { - model = config.ResolveModelForWorkflow("", parentJob.RepoPath, cfg, "fix", reasoning) - } + model := resolution.ModelForSelectedAgent(agentName, "") // Normalize and validate user-provided git ref to prevent option // injection (e.g. " --something") when passed to git worktree add. diff --git a/internal/daemon/worker.go b/internal/daemon/worker.go index d01695d54..508e1a897 100644 --- a/internal/daemon/worker.go +++ b/internal/daemon/worker.go @@ -764,9 +764,10 @@ func failoverWorkflow(job *storage.ReviewJob) string { // available or it's the same as the job's current agent. func (wp *WorkerPool) resolveBackupAgent(job *storage.ReviewJob) string { cfg := wp.cfgGetter.Config() - backup := config.ResolveBackupAgentForWorkflow( - job.RepoPath, cfg, failoverWorkflow(job), + resolution := agent.ResolveWorkflowConfig( + "", job.RepoPath, cfg, failoverWorkflow(job), "", ) + backup := resolution.BackupAgent if backup == "" { return "" } @@ -775,7 +776,7 @@ func (wp *WorkerPool) resolveBackupAgent(job *storage.ReviewJob) string { if err != nil || !agent.IsAvailable(resolved.Name()) { return "" } - if resolved.Name() == agent.CanonicalName(job.Agent) { + if resolution.AgentMatches(resolved.Name(), job.Agent) { return "" } return resolved.Name() @@ -785,9 +786,9 @@ func (wp *WorkerPool) resolveBackupAgent(job *storage.ReviewJob) string { // Returns the configured backup model, or "" if none is set. func (wp *WorkerPool) resolveBackupModel(job *storage.ReviewJob) string { cfg := wp.cfgGetter.Config() - return config.ResolveBackupModelForWorkflow( - job.RepoPath, cfg, failoverWorkflow(job), - ) + return agent.ResolveWorkflowConfig( + "", job.RepoPath, cfg, failoverWorkflow(job), "", + ).BackupModel() } // broadcastFailed sends a review.failed event for a job diff --git a/internal/review/batch.go b/internal/review/batch.go index bdcf8328c..9c5a4d76f 100644 --- a/internal/review/batch.go +++ b/internal/review/batch.go @@ -90,12 +90,13 @@ func runSingle( resolvedName := agentName var model string var backupAgent string + var resolution agent.WorkflowConfig if cfg.GlobalConfig != nil { - resolvedName = config.ResolveAgentForWorkflow( - agentName, cfg.RepoPath, - cfg.GlobalConfig, workflow, cfg.Reasoning) - backupAgent = config.ResolveBackupAgentForWorkflow( - cfg.RepoPath, cfg.GlobalConfig, workflow) + resolution = agent.ResolveWorkflowConfig( + agentName, cfg.RepoPath, cfg.GlobalConfig, workflow, cfg.Reasoning, + ) + resolvedName = resolution.PreferredAgent + backupAgent = resolution.BackupAgent } var resolvedAgent agent.Agent @@ -111,23 +112,9 @@ func runSingle( resolvedName, cfg.GlobalConfig, backupAgent) } - usingBackup := false - // Use backup model when the backup agent was selected - if err == nil && cfg.GlobalConfig != nil && backupAgent != "" { - preferred := config.ResolveAgentForWorkflow( - agentName, cfg.RepoPath, - cfg.GlobalConfig, workflow, cfg.Reasoning) - if agent.CanonicalName(resolvedAgent.Name()) == agent.CanonicalName(backupAgent) && - agent.CanonicalName(resolvedAgent.Name()) != agent.CanonicalName(preferred) { - usingBackup = true - model = config.ResolveBackupModelForWorkflow( - cfg.RepoPath, cfg.GlobalConfig, workflow) - } - } - if err == nil && cfg.GlobalConfig != nil && model == "" && !usingBackup { - model = agent.ResolveWorkflowModelForAgent( - resolvedAgent.Name(), "", cfg.RepoPath, - cfg.GlobalConfig, workflow, cfg.Reasoning, + if err == nil && cfg.GlobalConfig != nil { + model = resolution.ModelForSelectedAgent( + resolvedAgent.Name(), "", ) }