返回 DeepSeek-Reasonix
subagent_model_test.go
根目录 / internal / boot / subagent_model_test.go
1 package boot
2
3 import (
4 "path/filepath"
5 "testing"
6
7 "reasonix/internal/agent"
8 "reasonix/internal/config"
9 "reasonix/internal/provider"
10 "reasonix/internal/skill"
11 "reasonix/internal/tool"
12 )
13
14 type staticResolver struct {
15 catalog []provider.Descriptor
16 }
17
18 func (r *staticResolver) Catalog() []provider.Descriptor { return r.catalog }
19 func (r *staticResolver) Resolve(provider.Selection) (provider.Provider, error) {
20 return nil, nil
21 }
22
23 func TestSubagentModelRefUsesConfiguredDefault(t *testing.T) {
24 cfg := config.Default()
25 cfg.Agent.SubagentModel = "deepseek-pro"
26
27 got := subagentModelRef(cfg, skill.Skill{Name: "explore", RunAs: skill.RunSubagent})
28 if got != "deepseek-pro" {
29 t.Fatalf("subagent model = %q, want deepseek-pro", got)
30 }
31 }
32
33 func TestSubagentModelRefHonorsPrecedence(t *testing.T) {
34 cfg := config.Default()
35 cfg.Agent.SubagentModel = "mimo-pro"
36 cfg.Agent.SubagentModels = map[string]string{"review": "deepseek-pro"}
37
38 got := subagentModelRef(cfg, skill.Skill{
39 Name: "review",
40 RunAs: skill.RunSubagent,
41 Model: "mimo-flash",
42 })
43 if got != "deepseek-pro" {
44 t.Fatalf("per-skill config should override skill frontmatter and default, got %q", got)
45 }
46
47 got = subagentModelRef(cfg, skill.Skill{
48 Name: "custom",
49 RunAs: skill.RunSubagent,
50 Model: "mimo-flash",
51 })
52 if got != "mimo-flash" {
53 t.Fatalf("skill frontmatter should override default config, got %q", got)
54 }
55 }
56
57 func TestSubagentModelRefAcceptsToolNameAliases(t *testing.T) {
58 cfg := config.Default()
59 cfg.Agent.SubagentModels = map[string]string{"security_review": "deepseek-pro"}
60
61 got := subagentModelRef(cfg, skill.Skill{Name: "security-review", RunAs: skill.RunSubagent})
62 if got != "deepseek-pro" {
63 t.Fatalf("security_review alias should configure security-review, got %q", got)
64 }
65 }
66
67 func TestSubagentEffortRefHonorsPrecedence(t *testing.T) {
68 cfg := config.Default()
69 cfg.Agent.SubagentEffort = "high"
70 cfg.Agent.SubagentEfforts = map[string]string{"review": "max"}
71
72 got := subagentEffortRef(cfg, skill.Skill{
73 Name: "review",
74 RunAs: skill.RunSubagent,
75 Effort: "low",
76 })
77 if got != "max" {
78 t.Fatalf("per-skill effort config should override skill frontmatter and default, got %q", got)
79 }
80
81 got = subagentEffortRef(cfg, skill.Skill{
82 Name: "custom",
83 RunAs: skill.RunSubagent,
84 Effort: "medium",
85 })
86 if got != "medium" {
87 t.Fatalf("skill frontmatter effort should override default config, got %q", got)
88 }
89
90 got = subagentEffortRef(cfg, skill.Skill{Name: "other", RunAs: skill.RunSubagent})
91 if got != "high" {
92 t.Fatalf("default subagent effort = %q, want high", got)
93 }
94 }
95
96 func TestSubagentEffortRefAcceptsToolNameAliases(t *testing.T) {
97 cfg := config.Default()
98 cfg.Agent.SubagentEfforts = map[string]string{"security_review": "max"}
99
100 got := subagentEffortRef(cfg, skill.Skill{Name: "security-review", RunAs: skill.RunSubagent})
101 if got != "max" {
102 t.Fatalf("security_review alias should configure security-review effort, got %q", got)
103 }
104 }
105
106 func TestSubagentEffectiveIdentityUsesResolvedModelAndEffort(t *testing.T) {
107 cfg := config.Default()
108 cfg.Providers = []config.ProviderEntry{{
109 Name: "custom",
110 Kind: "openai",
111 Models: []string{"alpha", "beta"},
112 Default: "beta",
113 SupportedEfforts: []string{"low", "high"},
114 DefaultEffort: "high",
115 }}
116 base, ok := cfg.ResolveModel("custom")
117 if !ok {
118 t.Fatal("custom provider should resolve")
119 }
120
121 model, effort := subagentEffectiveIdentity(cfg, nil, "custom", base, "", "")
122 if model != "custom/beta" || effort != "high" {
123 t.Fatalf("identity = %q/%q, want custom/beta/high", model, effort)
124 }
125
126 model, effort = subagentEffectiveIdentity(cfg, nil, "custom", base, "alpha", "low")
127 if model != "custom/alpha" || effort != "low" {
128 t.Fatalf("override identity = %q/%q, want custom/alpha/low", model, effort)
129 }
130 }
131
132 func TestSubagentEffectiveIdentityUsesAuthoritativeExternalResolver(t *testing.T) {
133 cfg := config.Default()
134 base := &config.ProviderEntry{Name: "openai", Model: "gpt"}
135 resolver := &staticResolver{catalog: []provider.Descriptor{{
136 Ref: "anthropic/claude-sonnet", DisplayName: "anthropic", Model: "claude-sonnet",
137 Efforts: []string{"low", "high"}, DefaultEffort: "high",
138 }}}
139
140 model, effort := subagentEffectiveIdentity(cfg, resolver, "openai/gpt", base, "anthropic/claude-sonnet", "high")
141 if model != "anthropic/claude-sonnet" || effort != "high" {
142 t.Fatalf("identity = %q/%q, want anthropic/claude-sonnet/high", model, effort)
143 }
144 }
145
146 func TestNewSubagentStoreRequiresSessionDir(t *testing.T) {
147 if got, err := newSubagentStore("", nil); err != nil || got != nil {
148 if err != nil {
149 t.Fatalf("empty session dir error = %v", err)
150 }
151 t.Fatalf("empty session dir should disable subagent store, got %#v", got)
152 }
153 if got, err := newSubagentStore(t.TempDir(), nil); err != nil || got == nil {
154 if err != nil {
155 t.Fatalf("non-empty session dir error = %v", err)
156 }
157 t.Fatal("non-empty session dir should create subagent store")
158 }
159 }
160
161 func TestNewSubagentStoreCleansStaleRunningRefs(t *testing.T) {
162 sessionDir := t.TempDir()
163 store := agent.NewSubagentStore(filepath.Join(sessionDir, "subagents"))
164 spec := agent.SubagentSpec{
165 Kind: "task",
166 Name: "task",
167 WorkspaceRoot: t.TempDir(),
168 ParentSession: "parent-session",
169 SystemPrompt: "sys",
170 Registry: tool.NewRegistry(),
171 Model: "base-model",
172 }
173 run, err := store.PrepareFresh(spec)
174 if err != nil {
175 t.Fatalf("PrepareFresh: %v", err)
176 }
177 if err := store.MarkRunning(run); err != nil {
178 t.Fatalf("MarkRunning: %v", err)
179 }
180 ref := run.Ref
181 run.Release()
182
183 got, err := newSubagentStore(sessionDir, nil)
184 if err != nil {
185 t.Fatalf("newSubagentStore: %v", err)
186 }
187 if got == nil {
188 t.Fatal("newSubagentStore returned nil")
189 }
190 meta, err := got.LoadMeta(ref)
191 if err != nil {
192 t.Fatalf("LoadMeta: %v", err)
193 }
194 if meta.Status != agent.SubagentInterrupted {
195 t.Fatalf("status = %q, want interrupted", meta.Status)
196 }
197 }
198
198 lines GO