1package agent
2
3import (
4 "strings"
5 "testing"
6 "time"
7)
8
9func TestBuildSystemPromptAlwaysPrefersDedicatedTools(t *testing.T) {
10 for _, custom := range []string{"", "Custom identity"} {
11 prompt := BuildSystemPrompt(SystemPromptOpts{Custom: custom})
12 if count := strings.Count(prompt, toolSelectionGuidance); count != 1 {
13 t.Fatalf("dedicated tool guidance count = %d, want 1:\n%s", count, prompt)
14 }
15 }
16}
17
18func TestBuildSystemPromptAlwaysIncludesFinalWritingGuidance(t *testing.T) {
19 for _, tt := range []struct {
20 name string
21 custom string
22 }{
23 {name: "default"},
24 {name: "custom", custom: "custom identity"},
25 } {
26 t.Run(tt.name, func(t *testing.T) {
27 const conflictingAddendum = "Always use ceremonial language."
28 prompt := BuildSystemPrompt(SystemPromptOpts{
29 Custom: tt.custom,
30 Append: []string{conflictingAddendum},
31 })
32
33 if count := strings.Count(prompt, writingGuidance); count != 1 {
34 t.Fatalf("writing guidance count = %d, want 1:\n%s", count, prompt)
35 }
36 if strings.Index(prompt, writingGuidance) < strings.Index(prompt, conflictingAddendum) {
37 t.Fatalf("writing guidance must follow appended context:\n%s", prompt)
38 }
39 for _, want := range []string{
40 "medium, audience, and reader's immediate need",
41 "plain, precise language",
42 "Default to concise paragraphs",
43 "Use lists when items are genuinely parallel, sequential, or easier to compare",
44 "canned transitions",
45 "verified facts",
46 "descriptive links, and accessibility",
47 "Do not manufacture slang, errors, hesitation",
48 "Revise silently",
49 } {
50 if !strings.Contains(prompt, want) {
51 t.Errorf("writing guidance missing %q:\n%s", want, prompt)
52 }
53 }
54 })
55 }
56}
57
58func TestBuildSystemPromptAlwaysIncludesTaskAndSkillGuidance(t *testing.T) {
59 for _, custom := range []string{"", "Custom identity"} {
60 t.Run(custom, func(t *testing.T) {
61 prompt := BuildSystemPrompt(SystemPromptOpts{
62 Custom: custom,
63 Append: []string{"Workspace context", "Available skills"},
64 })
65 previous := strings.Index(prompt, "Available skills")
66 for _, guidance := range []string{taskExecutionGuidance, skillPriorityGuidance, writingGuidance} {
67 index := strings.Index(prompt, guidance)
68 if index <= previous {
69 t.Fatalf("shared guidance must follow appended context in task/skill/writing order")
70 }
71 previous = index
72 }
73 for _, want := range []string{
74 "Treat requests such as \"can you\" as instructions to do the requested work",
75 "do not stop at a plan or an offer to continue",
76 "Follow each progress statement with the action it describes",
77 "Final answers contain the result of the work or a concrete blocker",
78 "Respect requests for explanation, planning, or review without making unsolicited changes",
79 "Ask only when a necessary decision blocks safe, correct progress",
80 "Preserve tool permissions, required confirmations, and explicit approval requirements",
81 "Explicit user instructions take precedence over skill guidelines",
82 "Skills do not grant permissions or override system or developer constraints",
83 "identify its source and the relevant instruction",
84 } {
85 if count := strings.Count(prompt, want); count != 1 {
86 t.Errorf("guidance %q count = %d, want 1", want, count)
87 }
88 }
89 })
90 }
91}
92
93func TestBuildSystemPromptAddsCompactionHandoffToCustomPrompt(t *testing.T) {
94 prompt := BuildSystemPrompt(SystemPromptOpts{Custom: "custom identity"})
95 if !strings.Contains(prompt, "custom identity") {
96 t.Fatalf("custom prompt missing:\n%s", prompt)
97 }
98 if !strings.Contains(prompt, compactedSummaryHandoffInstruction) {
99 t.Fatalf("custom prompt missing compaction handoff:\n%s", prompt)
100 }
101 if count := strings.Count(prompt, compactedSummaryHandoffInstruction); count != 1 {
102 t.Fatalf("compaction handoff count = %d, want 1:\n%s", count, prompt)
103 }
104 for _, want := range []string{"most recent unresolved user request", "newer user request", "without waiting for the user to type \"continue\""} {
105 if !strings.Contains(prompt, want) {
106 t.Fatalf("compaction handoff missing %q:\n%s", want, prompt)
107 }
108 }
109}
110
111func TestBuildSystemPromptCustomOmitsBuiltInDocs(t *testing.T) {
112 got := BuildSystemPrompt(SystemPromptOpts{
113 CWD: "/workspace",
114 Custom: "Custom instructions",
115 Append: []string{"Additional context"},
116 Now: time.Date(2026, time.August, 6, 0, 0, 0, 0, time.UTC),
117 ZutDocsDir: "/zut/docs",
118 })
119
120 if strings.Contains(got, "Zut's own docs") || strings.Contains(got, "/zut/docs") {
121 t.Fatalf("custom prompt includes built-in docs guidance:\n%s", got)
122 }
123 for _, want := range []string{
124 "Custom instructions",
125 "Additional context",
126 "Current date: 2026-08-06",
127 "Current working directory: /workspace",
128 } {
129 if !strings.Contains(got, want) {
130 t.Errorf("custom prompt missing %q:\n%s", want, got)
131 }
132 }
133}
134
135func TestBuildSystemPromptDefaultIncludesBuiltInDocs(t *testing.T) {
136 got := BuildSystemPrompt(SystemPromptOpts{
137 CWD: "/workspace",
138 Now: time.Date(2026, time.August, 6, 0, 0, 0, 0, time.UTC),
139 ZutDocsDir: "/zut/docs",
140 })
141
142 if !strings.Contains(got, "Zut's own docs are installed under /zut/docs") {
143 t.Fatalf("default prompt missing built-in docs guidance:\n%s", got)
144 }
145}