-
Notifications
You must be signed in to change notification settings - Fork 136
Expand file tree
/
Copy pathplan-refinement.test.ts
More file actions
163 lines (132 loc) · 6.97 KB
/
Copy pathplan-refinement.test.ts
File metadata and controls
163 lines (132 loc) · 6.97 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
/**
* Plan Refinement UX Tests
*
* Validates the plan refinement flow:
* 1. Plan agent system prompt includes two-step approach instructions
* 2. Plan revision counter increments correctly
* 3. Revision cap at 5
* 4. `plan_revision` telemetry emission with correct fields
* 5. Non-plan sessions are unaffected
*/
import { describe, expect, test, mock, afterEach, beforeEach, spyOn } from "bun:test"
import fs from "fs/promises"
import path from "path"
// ---------------------------------------------------------------------------
// 1. Plan agent system prompt includes two-step approach
// ---------------------------------------------------------------------------
describe("Plan agent system prompt", () => {
test("plan.txt includes two-step approach instructions", async () => {
const planPromptPath = path.join(__dirname, "../../src/session/prompt/plan.txt")
const content = await fs.readFile(planPromptPath, "utf-8")
// Use semantic regex patterns to avoid breaking on wording tweaks
expect(content).toMatch(/two-?step/i)
expect(content).toMatch(/outline|bullet\s*point/i)
expect(content).toMatch(/confirm|direction.*right|looks.*right/i)
expect(content).toMatch(/refine|change/i)
expect(content).toMatch(/full.*plan|detailed.*plan/i)
})
test("plan.txt includes feedback/refinement instructions", async () => {
const planPromptPath = path.join(__dirname, "../../src/session/prompt/plan.txt")
const content = await fs.readFile(planPromptPath, "utf-8")
expect(content).toMatch(/feedback/i)
expect(content).toMatch(/read.*existing.*plan|read.*plan.*file/i)
expect(content).toMatch(/incorporate|apply.*feedback/i)
expect(content).toMatch(/update.*plan/i)
expect(content).toMatch(/summarize|describe.*change/i)
})
test("experimental plan mode inline prompt includes two-step approach", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// The inline prompt in prompt.ts (experimental plan mode) should also have the two-step approach
expect(content).toMatch(/two-?step/i)
expect(content).toMatch(/outline|bullet\s*point/i)
})
})
// ---------------------------------------------------------------------------
// 2 & 3. Plan revision counter and cap
// ---------------------------------------------------------------------------
describe("Plan revision tracking", () => {
test("planRevisionCount variable is declared in the session loop", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
expect(content).toContain("let planRevisionCount = 0")
expect(content).toContain("let planHasWritten = false")
})
test("revision cap is enforced at 5", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// The condition should cap at 5 revisions (>= 5 check with user communication)
expect(content).toMatch(/planRevisionCount\s*>=\s*5/)
})
test("revision counter increments on each plan refinement", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
expect(content).toContain("planRevisionCount++")
})
})
// ---------------------------------------------------------------------------
// 4. plan_revision telemetry event type
// ---------------------------------------------------------------------------
describe("plan_revision telemetry", () => {
test("plan_revision event type exists in telemetry Event union", async () => {
const telemetryPath = path.join(__dirname, "../../src/altimate/telemetry/index.ts")
const content = await fs.readFile(telemetryPath, "utf-8")
expect(content).toContain('type: "plan_revision"')
expect(content).toContain("revision_number: number")
expect(content).toContain('action: "refine" | "approve" | "reject"')
})
test("plan_revision telemetry is emitted in the session loop", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// Verify Telemetry.track is called with plan_revision type
expect(content).toContain('type: "plan_revision"')
expect(content).toContain("revision_number: planRevisionCount")
})
test("approval detection uses appropriate phrases", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// Verify approval phrase detection
expect(content).toContain("looks good")
expect(content).toContain("proceed")
expect(content).toContain("approved")
expect(content).toContain("lgtm")
expect(content).toMatch(/action.*approve.*refine|action.*reject.*approve.*refine/)
})
test("plan_revision telemetry includes required fields", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// Find the Telemetry.track({ ... }) block containing plan_revision
const trackMatch = content.match(/Telemetry\.track\(\{[^}]*type:\s*"plan_revision"[^}]*\}\)/s)
expect(trackMatch).not.toBeNull()
const trackBlock = trackMatch![0]
expect(trackBlock).toContain("timestamp:")
expect(trackBlock).toContain("session_id:")
expect(trackBlock).toContain("revision_number:")
expect(trackBlock).toContain("action")
})
})
// ---------------------------------------------------------------------------
// 5. Non-plan sessions are unaffected
// ---------------------------------------------------------------------------
describe("Non-plan sessions unaffected", () => {
test("plan revision tracking is guarded by agent name check", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// The revision tracking should only trigger for plan agent
expect(content).toContain('if (agent.name === "plan"')
})
test("plan file detection only runs for plan agent", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// The plan file existence check after tool calls should be guarded
expect(content).toContain('if (agent.name === "plan" && !planHasWritten)')
})
test("planRevisionCount is initialized to 0 and only modified in plan context", async () => {
const promptTsPath = path.join(__dirname, "../../src/session/prompt.ts")
const content = await fs.readFile(promptTsPath, "utf-8")
// Count occurrences of planRevisionCount++ — should only appear once, inside plan guard
const incrementMatches = content.match(/planRevisionCount\+\+/g)
expect(incrementMatches).toBeTruthy()
expect(incrementMatches!.length).toBe(1)
})
})