feat: add plan_model config for smarter LLM during interview/review phases
Allow users to specify a separate model for plan phases (interviewing/review) via plan_model and plan_model_fallbacks in defaults or per-agent config. During execution phases, the normal model is used as before. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
2be7c34f71
commit
2759bee2e3
7 changed files with 435 additions and 3 deletions
|
|
@ -6,6 +6,8 @@
|
|||
"provider": "zhipu",
|
||||
"model": "glm-4.7",
|
||||
"model_fallbacks": ["openai/gpt-4o"],
|
||||
"plan_model": "",
|
||||
"plan_model_fallbacks": [],
|
||||
"max_tokens": 8192,
|
||||
"temperature": 0.7,
|
||||
"max_tool_iterations": 20,
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ type AgentInstance struct {
|
|||
Subagents *config.SubagentsConfig
|
||||
SkillsFilter []string
|
||||
Candidates []providers.FallbackCandidate
|
||||
PlanModel string
|
||||
PlanFallbacks []string
|
||||
PlanCandidates []providers.FallbackCandidate
|
||||
|
||||
// Interview staleness tracking: consecutive turns where MEMORY.md was not updated.
|
||||
interviewStaleCount int
|
||||
|
|
@ -108,6 +111,18 @@ func NewAgentInstance(
|
|||
}
|
||||
candidates := providers.ResolveCandidates(modelCfg, defaults.Provider)
|
||||
|
||||
// Resolve plan model (for interviewing/review phases)
|
||||
planModel := resolvePlanModel(agentCfg, defaults)
|
||||
planFallbacks := resolvePlanFallbacks(agentCfg, defaults)
|
||||
var planCandidates []providers.FallbackCandidate
|
||||
if planModel != "" {
|
||||
planModelCfg := providers.ModelConfig{
|
||||
Primary: planModel,
|
||||
Fallbacks: planFallbacks,
|
||||
}
|
||||
planCandidates = providers.ResolveCandidates(planModelCfg, defaults.Provider)
|
||||
}
|
||||
|
||||
return &AgentInstance{
|
||||
ID: agentID,
|
||||
Name: agentName,
|
||||
|
|
@ -126,6 +141,9 @@ func NewAgentInstance(
|
|||
Subagents: subagents,
|
||||
SkillsFilter: skillsFilter,
|
||||
Candidates: candidates,
|
||||
PlanModel: planModel,
|
||||
PlanFallbacks: planFallbacks,
|
||||
PlanCandidates: planCandidates,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -158,6 +176,22 @@ func resolveAgentFallbacks(agentCfg *config.AgentConfig, defaults *config.AgentD
|
|||
return defaults.ModelFallbacks
|
||||
}
|
||||
|
||||
// resolvePlanModel resolves the plan model for an agent (used during interviewing/review phases).
|
||||
func resolvePlanModel(agentCfg *config.AgentConfig, defaults *config.AgentDefaults) string {
|
||||
if agentCfg != nil && agentCfg.PlanModel != nil && strings.TrimSpace(agentCfg.PlanModel.Primary) != "" {
|
||||
return strings.TrimSpace(agentCfg.PlanModel.Primary)
|
||||
}
|
||||
return defaults.PlanModel
|
||||
}
|
||||
|
||||
// resolvePlanFallbacks resolves the plan model fallbacks for an agent.
|
||||
func resolvePlanFallbacks(agentCfg *config.AgentConfig, defaults *config.AgentDefaults) []string {
|
||||
if agentCfg != nil && agentCfg.PlanModel != nil && agentCfg.PlanModel.Fallbacks != nil {
|
||||
return agentCfg.PlanModel.Fallbacks
|
||||
}
|
||||
return defaults.PlanModelFallbacks
|
||||
}
|
||||
|
||||
func expandHome(path string) string {
|
||||
if path == "" {
|
||||
return path
|
||||
|
|
|
|||
|
|
@ -93,3 +93,110 @@ func TestNewAgentInstance_DefaultsTemperatureWhenUnset(t *testing.T) {
|
|||
t.Fatalf("Temperature = %f, want %f", agent.Temperature, 0.7)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAgentInstance_PlanModel_SetFromDefaults(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "agent-instance-test-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cfg := &config.Config{
|
||||
Agents: config.AgentsConfig{
|
||||
Defaults: config.AgentDefaults{
|
||||
Workspace: tmpDir,
|
||||
Provider: "zhipu",
|
||||
Model: "glm-4.7",
|
||||
PlanModel: "anthropic/claude-sonnet-4-6",
|
||||
PlanModelFallbacks: []string{"openai/gpt-4o"},
|
||||
MaxTokens: 8192,
|
||||
MaxToolIterations: 20,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
provider := &mockProvider{}
|
||||
agent := NewAgentInstance(nil, &cfg.Agents.Defaults, cfg, provider)
|
||||
|
||||
if agent.PlanModel != "anthropic/claude-sonnet-4-6" {
|
||||
t.Errorf("PlanModel = %q, want 'anthropic/claude-sonnet-4-6'", agent.PlanModel)
|
||||
}
|
||||
if len(agent.PlanFallbacks) != 1 || agent.PlanFallbacks[0] != "openai/gpt-4o" {
|
||||
t.Errorf("PlanFallbacks = %v, want [openai/gpt-4o]", agent.PlanFallbacks)
|
||||
}
|
||||
if len(agent.PlanCandidates) == 0 {
|
||||
t.Fatal("PlanCandidates should not be empty when plan_model is set")
|
||||
}
|
||||
if agent.PlanCandidates[0].Model != "claude-sonnet-4-6" {
|
||||
t.Errorf("PlanCandidates[0].Model = %q, want 'claude-sonnet-4-6'", agent.PlanCandidates[0].Model)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAgentInstance_PlanModel_NilWhenUnset(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "agent-instance-test-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cfg := &config.Config{
|
||||
Agents: config.AgentsConfig{
|
||||
Defaults: config.AgentDefaults{
|
||||
Workspace: tmpDir,
|
||||
Model: "test-model",
|
||||
MaxTokens: 1234,
|
||||
MaxToolIterations: 5,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
provider := &mockProvider{}
|
||||
agent := NewAgentInstance(nil, &cfg.Agents.Defaults, cfg, provider)
|
||||
|
||||
if agent.PlanModel != "" {
|
||||
t.Errorf("PlanModel = %q, want empty", agent.PlanModel)
|
||||
}
|
||||
if agent.PlanCandidates != nil {
|
||||
t.Errorf("PlanCandidates = %v, want nil", agent.PlanCandidates)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewAgentInstance_PlanModel_AgentOverridesDefaults(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "agent-instance-test-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cfg := &config.Config{
|
||||
Agents: config.AgentsConfig{
|
||||
Defaults: config.AgentDefaults{
|
||||
Workspace: tmpDir,
|
||||
Provider: "zhipu",
|
||||
Model: "glm-4.7",
|
||||
PlanModel: "default-plan-model",
|
||||
PlanModelFallbacks: []string{"default-fallback"},
|
||||
MaxTokens: 8192,
|
||||
MaxToolIterations: 20,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
agentCfg := &config.AgentConfig{
|
||||
ID: "custom",
|
||||
PlanModel: &config.AgentModelConfig{
|
||||
Primary: "agent-plan-model",
|
||||
Fallbacks: []string{"agent-fallback"},
|
||||
},
|
||||
}
|
||||
|
||||
provider := &mockProvider{}
|
||||
agent := NewAgentInstance(agentCfg, &cfg.Agents.Defaults, cfg, provider)
|
||||
|
||||
if agent.PlanModel != "agent-plan-model" {
|
||||
t.Errorf("PlanModel = %q, want 'agent-plan-model'", agent.PlanModel)
|
||||
}
|
||||
if len(agent.PlanFallbacks) != 1 || agent.PlanFallbacks[0] != "agent-fallback" {
|
||||
t.Errorf("PlanFallbacks = %v, want [agent-fallback]", agent.PlanFallbacks)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1623,8 +1623,18 @@ func (al *AgentLoop) runLLMIteration(
|
|||
}
|
||||
|
||||
callLLM := func() (*providers.LLMResponse, error) {
|
||||
if len(agent.Candidates) > 1 && al.fallback != nil {
|
||||
fbResult, fbErr := al.fallback.Execute(ctx, agent.Candidates,
|
||||
// Plan model switching: use plan model during interviewing/review phases
|
||||
candidates := agent.Candidates
|
||||
primaryModel := agent.Model
|
||||
if isPlanPreExecution(planSnapshot) && agent.PlanModel != "" {
|
||||
candidates = agent.PlanCandidates
|
||||
primaryModel = agent.PlanModel
|
||||
logger.InfoCF("agent", "Using plan model",
|
||||
map[string]any{"agent_id": agent.ID, "plan_model": agent.PlanModel})
|
||||
}
|
||||
|
||||
if len(candidates) > 1 && al.fallback != nil {
|
||||
fbResult, fbErr := al.fallback.Execute(ctx, candidates,
|
||||
func(ctx context.Context, provider, model string) (*providers.LLMResponse, error) {
|
||||
p := al.resolveProvider(provider, model, agent.Provider)
|
||||
return doCall(ctx, p, model)
|
||||
|
|
@ -1640,7 +1650,7 @@ func (al *AgentLoop) runLLMIteration(
|
|||
}
|
||||
return fbResult.Response, nil
|
||||
}
|
||||
return doCall(ctx, agent.Provider, agent.Model)
|
||||
return doCall(ctx, agent.Provider, primaryModel)
|
||||
}
|
||||
|
||||
// Retry loop for context/token errors
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
|
|
@ -2348,3 +2349,158 @@ func TestConsumeStream_OnChunkWithRepetitionDetection(t *testing.T) {
|
|||
}
|
||||
_ = ctx
|
||||
}
|
||||
|
||||
// modelCapturingMockProvider records which model was passed to Chat.
|
||||
type modelCapturingMockProvider struct {
|
||||
mu sync.Mutex
|
||||
models []string
|
||||
response string
|
||||
}
|
||||
|
||||
func (m *modelCapturingMockProvider) Chat(
|
||||
ctx context.Context,
|
||||
messages []providers.Message,
|
||||
tools_ []providers.ToolDefinition,
|
||||
model string,
|
||||
opts map[string]any,
|
||||
) (*providers.LLMResponse, error) {
|
||||
m.mu.Lock()
|
||||
m.models = append(m.models, model)
|
||||
m.mu.Unlock()
|
||||
return &providers.LLMResponse{
|
||||
Content: m.response,
|
||||
ToolCalls: []providers.ToolCall{},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *modelCapturingMockProvider) GetDefaultModel() string {
|
||||
return "mock-capture-model"
|
||||
}
|
||||
|
||||
func TestAgentLoop_PlanModel_UsedDuringInterviewing(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "agent-test-planmodel-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cfg := &config.Config{
|
||||
Agents: config.AgentsConfig{
|
||||
Defaults: config.AgentDefaults{
|
||||
Workspace: tmpDir,
|
||||
Model: "normal-model",
|
||||
PlanModel: "plan-model",
|
||||
MaxTokens: 4096,
|
||||
MaxToolIterations: 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
msgBus := bus.NewMessageBus()
|
||||
provider := &modelCapturingMockProvider{response: "Plan interview response"}
|
||||
al := NewAgentLoop(cfg, msgBus, provider)
|
||||
|
||||
defaultAgent := al.registry.GetDefaultAgent()
|
||||
if defaultAgent == nil {
|
||||
t.Fatal("No default agent found")
|
||||
}
|
||||
|
||||
// Write MEMORY.md with interviewing status to activate plan model
|
||||
memoryDir := filepath.Join(tmpDir, "memory")
|
||||
os.MkdirAll(memoryDir, 0o755)
|
||||
memoryPath := filepath.Join(memoryDir, "MEMORY.md")
|
||||
memoryContent := "# Active Plan\n\n> Task: Test plan model\n> Status: interviewing\n> Phase: 1\n"
|
||||
if err := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); err != nil {
|
||||
t.Fatalf("Failed to write MEMORY.md: %v", err)
|
||||
}
|
||||
|
||||
_, err = al.ProcessDirectWithChannel(
|
||||
context.Background(),
|
||||
"Hello, plan model test",
|
||||
"test-plan-session",
|
||||
"test",
|
||||
"test-chat",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessDirectWithChannel failed: %v", err)
|
||||
}
|
||||
|
||||
provider.mu.Lock()
|
||||
defer provider.mu.Unlock()
|
||||
|
||||
if len(provider.models) == 0 {
|
||||
t.Fatal("Expected at least one Chat call")
|
||||
}
|
||||
// The first call should use the plan model since we're in interviewing state
|
||||
if provider.models[0] != "plan-model" {
|
||||
t.Errorf("Expected plan model 'plan-model' during interviewing, got %q", provider.models[0])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentLoop_PlanModel_NotUsedDuringExecuting(t *testing.T) {
|
||||
tmpDir, err := os.MkdirTemp("", "agent-test-planmodel-exec-*")
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to create temp dir: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
cfg := &config.Config{
|
||||
Agents: config.AgentsConfig{
|
||||
Defaults: config.AgentDefaults{
|
||||
Workspace: tmpDir,
|
||||
Model: "normal-model",
|
||||
PlanModel: "plan-model",
|
||||
MaxTokens: 4096,
|
||||
MaxToolIterations: 2,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
msgBus := bus.NewMessageBus()
|
||||
provider := &modelCapturingMockProvider{response: "Executing response"}
|
||||
al := NewAgentLoop(cfg, msgBus, provider)
|
||||
|
||||
defaultAgent := al.registry.GetDefaultAgent()
|
||||
if defaultAgent == nil {
|
||||
t.Fatal("No default agent found")
|
||||
}
|
||||
|
||||
// Write MEMORY.md with executing status - should use normal model
|
||||
memoryDir := filepath.Join(tmpDir, "memory")
|
||||
os.MkdirAll(memoryDir, 0o755)
|
||||
memoryPath := filepath.Join(memoryDir, "MEMORY.md")
|
||||
memoryContent := `# Active Plan
|
||||
|
||||
> Task: Test plan model
|
||||
> Status: executing
|
||||
> Phase: 1
|
||||
|
||||
## Phase 1: Build
|
||||
- [ ] Run build
|
||||
`
|
||||
if err := os.WriteFile(memoryPath, []byte(memoryContent), 0o644); err != nil {
|
||||
t.Fatalf("Failed to write MEMORY.md: %v", err)
|
||||
}
|
||||
|
||||
_, err = al.ProcessDirectWithChannel(
|
||||
context.Background(),
|
||||
"Hello, executing test",
|
||||
"test-exec-session",
|
||||
"test",
|
||||
"test-chat",
|
||||
)
|
||||
if err != nil {
|
||||
t.Fatalf("ProcessDirectWithChannel failed: %v", err)
|
||||
}
|
||||
|
||||
provider.mu.Lock()
|
||||
defer provider.mu.Unlock()
|
||||
|
||||
if len(provider.models) == 0 {
|
||||
t.Fatal("Expected at least one Chat call")
|
||||
}
|
||||
// During executing phase, should use normal model, not plan model
|
||||
if provider.models[0] != "normal-model" {
|
||||
t.Errorf("Expected normal model 'normal-model' during executing, got %q", provider.models[0])
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -135,6 +135,7 @@ type AgentConfig struct {
|
|||
Name string `json:"name,omitempty"`
|
||||
Workspace string `json:"workspace,omitempty"`
|
||||
Model *AgentModelConfig `json:"model,omitempty"`
|
||||
PlanModel *AgentModelConfig `json:"plan_model,omitempty"`
|
||||
Skills []string `json:"skills,omitempty"`
|
||||
Subagents *SubagentsConfig `json:"subagents,omitempty"`
|
||||
}
|
||||
|
|
@ -175,6 +176,8 @@ type AgentDefaults struct {
|
|||
ModelFallbacks []string `json:"model_fallbacks,omitempty"`
|
||||
ImageModel string `json:"image_model,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_IMAGE_MODEL"`
|
||||
ImageModelFallbacks []string `json:"image_model_fallbacks,omitempty"`
|
||||
PlanModel string `json:"plan_model,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_PLAN_MODEL"`
|
||||
PlanModelFallbacks []string `json:"plan_model_fallbacks,omitempty"`
|
||||
MaxTokens int `json:"max_tokens" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOKENS"`
|
||||
Temperature *float64 `json:"temperature,omitempty" env:"PICOCLAW_AGENTS_DEFAULTS_TEMPERATURE"`
|
||||
MaxToolIterations int `json:"max_tool_iterations" env:"PICOCLAW_AGENTS_DEFAULTS_MAX_TOOL_ITERATIONS"`
|
||||
|
|
|
|||
|
|
@ -392,3 +392,123 @@ func TestLoadConfig_OpenAIWebSearchCanBeDisabled(t *testing.T) {
|
|||
t.Fatal("OpenAI codex web search should be false when disabled in config file")
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentDefaults_PlanModel_StringParse(t *testing.T) {
|
||||
jsonData := `{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"workspace": "~/.picoclaw/workspace",
|
||||
"model": "glm-4.7",
|
||||
"plan_model": "anthropic/claude-sonnet-4-6",
|
||||
"plan_model_fallbacks": ["openai/gpt-4o"],
|
||||
"max_tokens": 8192,
|
||||
"max_tool_iterations": 20
|
||||
}
|
||||
}
|
||||
}`
|
||||
|
||||
cfg := DefaultConfig()
|
||||
if err := json.Unmarshal([]byte(jsonData), cfg); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if cfg.Agents.Defaults.PlanModel != "anthropic/claude-sonnet-4-6" {
|
||||
t.Errorf("PlanModel = %q, want 'anthropic/claude-sonnet-4-6'", cfg.Agents.Defaults.PlanModel)
|
||||
}
|
||||
if len(cfg.Agents.Defaults.PlanModelFallbacks) != 1 || cfg.Agents.Defaults.PlanModelFallbacks[0] != "openai/gpt-4o" {
|
||||
t.Errorf("PlanModelFallbacks = %v, want [openai/gpt-4o]", cfg.Agents.Defaults.PlanModelFallbacks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentConfig_PlanModel_ObjectParse(t *testing.T) {
|
||||
jsonData := `{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"workspace": "~/.picoclaw/workspace",
|
||||
"model": "glm-4.7",
|
||||
"max_tokens": 8192,
|
||||
"max_tool_iterations": 20
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"id": "main",
|
||||
"plan_model": "anthropic/claude-sonnet-4-6"
|
||||
},
|
||||
{
|
||||
"id": "advanced",
|
||||
"plan_model": {
|
||||
"primary": "anthropic/claude-opus-4",
|
||||
"fallbacks": ["anthropic/claude-sonnet-4-6"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
|
||||
cfg := DefaultConfig()
|
||||
if err := json.Unmarshal([]byte(jsonData), cfg); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
|
||||
if len(cfg.Agents.List) != 2 {
|
||||
t.Fatalf("agents.list len = %d, want 2", len(cfg.Agents.List))
|
||||
}
|
||||
|
||||
// String form
|
||||
main := cfg.Agents.List[0]
|
||||
if main.PlanModel == nil || main.PlanModel.Primary != "anthropic/claude-sonnet-4-6" {
|
||||
t.Errorf("main.PlanModel = %+v, want primary 'anthropic/claude-sonnet-4-6'", main.PlanModel)
|
||||
}
|
||||
|
||||
// Object form with fallbacks
|
||||
adv := cfg.Agents.List[1]
|
||||
if adv.PlanModel == nil || adv.PlanModel.Primary != "anthropic/claude-opus-4" {
|
||||
t.Errorf("advanced.PlanModel = %+v, want primary 'anthropic/claude-opus-4'", adv.PlanModel)
|
||||
}
|
||||
if len(adv.PlanModel.Fallbacks) != 1 || adv.PlanModel.Fallbacks[0] != "anthropic/claude-sonnet-4-6" {
|
||||
t.Errorf("advanced.PlanModel.Fallbacks = %v", adv.PlanModel.Fallbacks)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAgentConfig_PlanModel_OverridesDefaults(t *testing.T) {
|
||||
jsonData := `{
|
||||
"agents": {
|
||||
"defaults": {
|
||||
"workspace": "~/.picoclaw/workspace",
|
||||
"model": "glm-4.7",
|
||||
"plan_model": "default-plan-model",
|
||||
"plan_model_fallbacks": ["default-fallback"],
|
||||
"max_tokens": 8192,
|
||||
"max_tool_iterations": 20
|
||||
},
|
||||
"list": [
|
||||
{
|
||||
"id": "custom",
|
||||
"plan_model": {
|
||||
"primary": "custom-plan-model",
|
||||
"fallbacks": ["custom-fallback"]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}`
|
||||
|
||||
cfg := DefaultConfig()
|
||||
if err := json.Unmarshal([]byte(jsonData), cfg); err != nil {
|
||||
t.Fatalf("unmarshal: %v", err)
|
||||
}
|
||||
|
||||
// Agent-level plan_model should override defaults
|
||||
custom := cfg.Agents.List[0]
|
||||
if custom.PlanModel == nil || custom.PlanModel.Primary != "custom-plan-model" {
|
||||
t.Errorf("custom.PlanModel.Primary = %v, want 'custom-plan-model'", custom.PlanModel)
|
||||
}
|
||||
if len(custom.PlanModel.Fallbacks) != 1 || custom.PlanModel.Fallbacks[0] != "custom-fallback" {
|
||||
t.Errorf("custom.PlanModel.Fallbacks = %v, want [custom-fallback]", custom.PlanModel.Fallbacks)
|
||||
}
|
||||
|
||||
// Defaults should still be intact
|
||||
if cfg.Agents.Defaults.PlanModel != "default-plan-model" {
|
||||
t.Errorf("defaults.PlanModel = %q, want 'default-plan-model'", cfg.Agents.Defaults.PlanModel)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue