fix(agent): resolve primary provider from frontmatter model

This commit is contained in:
afjcjsbx
2026-05-08 13:43:21 +02:00
parent 871892ff15
commit ffa184d183
2 changed files with 93 additions and 0 deletions
+42
View File
@@ -150,6 +150,7 @@ func NewAgentInstance(
subagents = agentCfg.Subagents
skillsFilter = resolveAgentSkillsFilter(agentCfg, definition)
}
provider = resolvePrimaryProviderForAgent(cfg, workspace, agentID, model, provider)
warnOnUnknownAgentMCPServerDeclarations(agentID, workspace, cfg, definition)
maxIter := defaults.MaxToolIterations
@@ -305,6 +306,47 @@ func populateCandidateProvidersFromNames(
}
}
// resolvePrimaryProviderForAgent resolves a dedicated provider for the active
// primary model when the model points at a model_list entry. This keeps the
// agent's single-candidate path aligned with the selected model's own
// provider/api_base/api_key instead of inheriting the process default provider.
func resolvePrimaryProviderForAgent(
cfg *config.Config,
workspace string,
agentID string,
model string,
fallback providers.LLMProvider,
) providers.LLMProvider {
model = strings.TrimSpace(model)
if cfg == nil || model == "" {
return fallback
}
modelCfg := lookupModelConfigByRef(cfg, model)
if modelCfg == nil {
return fallback
}
clone := *modelCfg
if clone.Workspace == "" {
clone.Workspace = workspace
}
resolvedProvider, _, err := providers.CreateProviderFromConfig(&clone)
if err != nil {
logger.WarnCF("agent", "Primary model provider init failed; using injected provider",
map[string]any{
"agent_id": agentID,
"model": model,
"error": err.Error(),
})
return fallback
}
if resolvedProvider == nil {
return fallback
}
return resolvedProvider
}
// resolveAgentWorkspace determines the workspace directory for an agent.
func resolveAgentWorkspace(agentCfg *config.AgentConfig, defaults *config.AgentDefaults) string {
if agentCfg != nil && strings.TrimSpace(agentCfg.Workspace) != "" {
+51
View File
@@ -666,6 +666,57 @@ Use frontmatter identity.
}
}
func TestNewAgentInstance_UsesResolvedProviderForFrontmatterPrimaryModel(t *testing.T) {
workspace := setupWorkspace(t, map[string]string{
"AGENT.md": `---
model: claude-frontmatter
---
# Agent
`,
})
defer cleanupWorkspace(t, workspace)
cfg := &config.Config{
Agents: config.AgentsConfig{
Defaults: config.AgentDefaults{
Workspace: workspace,
Provider: "openai",
ModelName: "default-model",
},
},
ModelList: []*config.ModelConfig{
{
ModelName: "claude-frontmatter",
Model: "anthropic/claude-3-7-sonnet",
APIKeys: config.SimpleSecureStrings("test-anthropic-key"),
Workspace: workspace,
},
},
}
defaultProvider := &mockProvider{}
agent := NewAgentInstance(&config.AgentConfig{
ID: "research",
Workspace: workspace,
}, &cfg.Agents.Defaults, cfg, defaultProvider)
if agent.Model != "claude-frontmatter" {
t.Fatalf("agent.Model = %q, want %q", agent.Model, "claude-frontmatter")
}
if len(agent.Candidates) != 1 {
t.Fatalf("len(agent.Candidates) = %d, want 1", len(agent.Candidates))
}
if got := agent.Candidates[0].Provider; got != "anthropic" {
t.Fatalf("primary candidate provider = %q, want %q", got, "anthropic")
}
if got := agent.Candidates[0].Model; got != "claude-3-7-sonnet" {
t.Fatalf("primary candidate model = %q, want %q", got, "claude-3-7-sonnet")
}
if agent.Provider == defaultProvider {
t.Fatal("expected primary provider to be resolved from model_list instead of using injected default provider")
}
}
func TestNewAgentInstance_InvalidFrontmatterFailsClosedForToolsAndMCPServers(t *testing.T) {
workspace := setupWorkspace(t, map[string]string{
"AGENT.md": `---