174 lines
4.9 KiB
Go
174 lines
4.9 KiB
Go
package boot
|
|
|
|
import (
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"reasonix/internal/agent"
|
|
"reasonix/internal/config"
|
|
"reasonix/internal/skill"
|
|
"reasonix/internal/tool"
|
|
)
|
|
|
|
func TestSubagentModelRefUsesConfiguredDefault(t *testing.T) {
|
|
cfg := config.Default()
|
|
cfg.Agent.SubagentModel = "deepseek-pro"
|
|
|
|
got := subagentModelRef(cfg, skill.Skill{Name: "explore", RunAs: skill.RunSubagent})
|
|
if got != "deepseek-pro" {
|
|
t.Fatalf("subagent model = %q, want deepseek-pro", got)
|
|
}
|
|
}
|
|
|
|
func TestSubagentModelRefHonorsPrecedence(t *testing.T) {
|
|
cfg := config.Default()
|
|
cfg.Agent.SubagentModel = "mimo-pro"
|
|
cfg.Agent.SubagentModels = map[string]string{"review": "deepseek-pro"}
|
|
|
|
got := subagentModelRef(cfg, skill.Skill{
|
|
Name: "review",
|
|
RunAs: skill.RunSubagent,
|
|
Model: "mimo-flash",
|
|
})
|
|
if got != "deepseek-pro" {
|
|
t.Fatalf("per-skill config should override skill frontmatter and default, got %q", got)
|
|
}
|
|
|
|
got = subagentModelRef(cfg, skill.Skill{
|
|
Name: "custom",
|
|
RunAs: skill.RunSubagent,
|
|
Model: "mimo-flash",
|
|
})
|
|
if got != "mimo-flash" {
|
|
t.Fatalf("skill frontmatter should override default config, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSubagentModelRefAcceptsToolNameAliases(t *testing.T) {
|
|
cfg := config.Default()
|
|
cfg.Agent.SubagentModels = map[string]string{"security_review": "deepseek-pro"}
|
|
|
|
got := subagentModelRef(cfg, skill.Skill{Name: "security-review", RunAs: skill.RunSubagent})
|
|
if got != "deepseek-pro" {
|
|
t.Fatalf("security_review alias should configure security-review, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSubagentEffortRefHonorsPrecedence(t *testing.T) {
|
|
cfg := config.Default()
|
|
cfg.Agent.SubagentEffort = "high"
|
|
cfg.Agent.SubagentEfforts = map[string]string{"review": "max"}
|
|
|
|
got := subagentEffortRef(cfg, skill.Skill{
|
|
Name: "review",
|
|
RunAs: skill.RunSubagent,
|
|
Effort: "low",
|
|
})
|
|
if got != "max" {
|
|
t.Fatalf("per-skill effort config should override skill frontmatter and default, got %q", got)
|
|
}
|
|
|
|
got = subagentEffortRef(cfg, skill.Skill{
|
|
Name: "custom",
|
|
RunAs: skill.RunSubagent,
|
|
Effort: "medium",
|
|
})
|
|
if got != "medium" {
|
|
t.Fatalf("skill frontmatter effort should override default config, got %q", got)
|
|
}
|
|
|
|
got = subagentEffortRef(cfg, skill.Skill{Name: "other", RunAs: skill.RunSubagent})
|
|
if got != "high" {
|
|
t.Fatalf("default subagent effort = %q, want high", got)
|
|
}
|
|
}
|
|
|
|
func TestSubagentEffortRefAcceptsToolNameAliases(t *testing.T) {
|
|
cfg := config.Default()
|
|
cfg.Agent.SubagentEfforts = map[string]string{"security_review": "max"}
|
|
|
|
got := subagentEffortRef(cfg, skill.Skill{Name: "security-review", RunAs: skill.RunSubagent})
|
|
if got != "max" {
|
|
t.Fatalf("security_review alias should configure security-review effort, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSubagentEffectiveIdentityUsesResolvedModelAndEffort(t *testing.T) {
|
|
cfg := config.Default()
|
|
cfg.Providers = []config.ProviderEntry{{
|
|
Name: "custom",
|
|
Kind: "openai",
|
|
Models: []string{"alpha", "beta"},
|
|
Default: "beta",
|
|
SupportedEfforts: []string{"low", "high"},
|
|
DefaultEffort: "high",
|
|
}}
|
|
base, ok := cfg.ResolveModel("custom")
|
|
if !ok {
|
|
t.Fatal("custom provider should resolve")
|
|
}
|
|
|
|
model, effort := subagentEffectiveIdentity(cfg, "custom", base, "", "")
|
|
if model != "custom/beta" || effort != "high" {
|
|
t.Fatalf("identity = %q/%q, want custom/beta/high", model, effort)
|
|
}
|
|
|
|
model, effort = subagentEffectiveIdentity(cfg, "custom", base, "alpha", "low")
|
|
if model != "custom/alpha" || effort != "low" {
|
|
t.Fatalf("override identity = %q/%q, want custom/alpha/low", model, effort)
|
|
}
|
|
}
|
|
|
|
func TestNewSubagentStoreRequiresSessionDir(t *testing.T) {
|
|
if got, err := newSubagentStore(""); err != nil || got != nil {
|
|
if err != nil {
|
|
t.Fatalf("empty session dir error = %v", err)
|
|
}
|
|
t.Fatalf("empty session dir should disable subagent store, got %#v", got)
|
|
}
|
|
if got, err := newSubagentStore(t.TempDir()); err != nil || got == nil {
|
|
if err != nil {
|
|
t.Fatalf("non-empty session dir error = %v", err)
|
|
}
|
|
t.Fatal("non-empty session dir should create subagent store")
|
|
}
|
|
}
|
|
|
|
func TestNewSubagentStoreCleansStaleRunningRefs(t *testing.T) {
|
|
sessionDir := t.TempDir()
|
|
store := agent.NewSubagentStore(filepath.Join(sessionDir, "subagents"))
|
|
spec := agent.SubagentSpec{
|
|
Kind: "task",
|
|
Name: "task",
|
|
WorkspaceRoot: t.TempDir(),
|
|
ParentSession: "parent-session",
|
|
SystemPrompt: "sys",
|
|
Registry: tool.NewRegistry(),
|
|
Model: "base-model",
|
|
}
|
|
run, err := store.PrepareFresh(spec)
|
|
if err != nil {
|
|
t.Fatalf("PrepareFresh: %v", err)
|
|
}
|
|
if err := store.MarkRunning(run); err != nil {
|
|
t.Fatalf("MarkRunning: %v", err)
|
|
}
|
|
ref := run.Ref
|
|
run.Release()
|
|
|
|
got, err := newSubagentStore(sessionDir)
|
|
if err != nil {
|
|
t.Fatalf("newSubagentStore: %v", err)
|
|
}
|
|
if got == nil {
|
|
t.Fatal("newSubagentStore returned nil")
|
|
}
|
|
meta, err := got.LoadMeta(ref)
|
|
if err != nil {
|
|
t.Fatalf("LoadMeta: %v", err)
|
|
}
|
|
if meta.Status != agent.SubagentInterrupted {
|
|
t.Fatalf("status = %q, want interrupted", meta.Status)
|
|
}
|
|
}
|