返回 DeepSeek-Reasonix
context_capsule_test.go
根目录 / internal / agent / context_capsule_test.go
1 package agent
2
3 import (
4 "strings"
5 "testing"
6 "time"
7
8 "reasonix/internal/tool"
9 )
10
11 func capsuleForSpec(t *testing.T, spec SubagentSpec) ContextCapsule {
12 t.Helper()
13 now := time.Unix(0, 0)
14 return metaFromSpec("sa_test", SubagentRunning, now, now, spec).Capsule
15 }
16
17 // Children are isolated by construction. This test states that as a fact so a
18 // future change that starts inheriting something has to come here, flip the
19 // flag, and update the SPEC table in the same commit.
20 func TestContextCapsuleRecordsWhatIsNotInherited(t *testing.T) {
21 capsule := capsuleForSpec(t, SubagentSpec{
22 Kind: "task", Name: "task", SystemPrompt: DefaultTaskSystemPrompt,
23 })
24 if capsule.Inherited != (InheritedContext{}) {
25 t.Fatalf("Inherited = %+v, want every field false: a child receives no standing instructions, memory, parent conversation, goal, or planner output", capsule.Inherited)
26 }
27 }
28
29 func TestContextCapsuleNamesTheSystemPromptSource(t *testing.T) {
30 for _, tc := range []struct {
31 name string
32 spec SubagentSpec
33 want string
34 }{
35 {"writer default", SubagentSpec{Kind: "task", Name: "task", SystemPrompt: DefaultTaskSystemPrompt}, SystemPromptTaskDefault},
36 {"read-only default", SubagentSpec{Kind: "task", Name: "task", SystemPrompt: DefaultReadOnlyTaskSystemPrompt}, SystemPromptReadOnlyDefault},
37 {"profile body", SubagentSpec{Kind: "skill", Name: "reviewer", SystemPrompt: "you review code"}, "profile:reviewer"},
38 } {
39 if got := capsuleForSpec(t, tc.spec).SystemPromptSource; got != tc.want {
40 t.Errorf("%s: SystemPromptSource = %q, want %q", tc.name, got, tc.want)
41 }
42 }
43 // The capsule identifies the prompt without carrying it.
44 capsule := capsuleForSpec(t, SubagentSpec{Kind: "skill", Name: "reviewer", SystemPrompt: "secret review playbook"})
45 if capsule.SystemPromptHash == "" {
46 t.Fatal("capsule must hash the system prompt")
47 }
48 if strings.Contains(capsule.Hash(), "secret") {
49 t.Fatal("capsule must reference the prompt, never embed it")
50 }
51 }
52
53 func TestContextCapsuleHashDiscriminatesRealDifferences(t *testing.T) {
54 base := SubagentSpec{Kind: "task", Name: "task", SystemPrompt: DefaultTaskSystemPrompt, WorkspaceRoot: "/w", Model: "m"}
55 first := capsuleForSpec(t, base).Hash()
56 if first == "" {
57 t.Fatal("capsule hash must be computable")
58 }
59 if second := capsuleForSpec(t, base).Hash(); second != first {
60 t.Fatalf("same context produced different hashes: %s vs %s", first, second)
61 }
62
63 for name, mutate := range map[string]func(*SubagentSpec){
64 "different prompt": func(s *SubagentSpec) { s.SystemPrompt = "other" },
65 "different model": func(s *SubagentSpec) { s.Model = "other" },
66 "different workspace": func(s *SubagentSpec) { s.WorkspaceRoot = "/other" },
67 "resumed transcript": func(s *SubagentSpec) { s.ResumedFrom = "sa_prior" },
68 } {
69 changed := base
70 mutate(&changed)
71 if got := capsuleForSpec(t, changed).Hash(); got == first {
72 t.Errorf("%s: hash did not change, so the record cannot explain a behaviour difference", name)
73 }
74 }
75 }
76
77 // The tool surface is part of what a child saw, so it must move the hash.
78 func TestContextCapsuleHashCoversToolScope(t *testing.T) {
79 reg := tool.NewRegistry()
80 reg.Add(&recordingWriter{name: "write_file"})
81 base := SubagentSpec{Kind: "task", Name: "task", SystemPrompt: DefaultTaskSystemPrompt}
82 withTools := base
83 withTools.Registry = reg
84 if capsuleForSpec(t, base).Hash() == capsuleForSpec(t, withTools).Hash() {
85 t.Fatal("a different tool surface must produce a different capsule hash")
86 }
87 if scope := capsuleForSpec(t, withTools).ToolScope; len(scope) == 0 {
88 t.Fatal("capsule must record the resolved tool scope")
89 }
90 }
91
91 lines GO