Skip to content

Commit fed716a

Browse files
authored
Clarify compaction test harness (#26777)
1 parent 426d92e commit fed716a

1 file changed

Lines changed: 38 additions & 48 deletions

File tree

packages/opencode/test/session/compaction.test.ts

Lines changed: 38 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -233,16 +233,22 @@ const env = Layer.mergeAll(
233233

234234
const it = testEffect(env)
235235

236-
const processEnv = Layer.mergeAll(SessionNs.defaultLayer, CrossSpawnSpawner.defaultLayer)
237-
const itProcess = testEffect(processEnv)
236+
const compactionEnv = Layer.mergeAll(SessionNs.defaultLayer, CrossSpawnSpawner.defaultLayer)
237+
const itCompaction = testEffect(compactionEnv)
238238

239-
function compactionProcessLayer(options?: {
239+
type CompactionProcessOptions = {
240240
result?: "continue" | "compact"
241241
llm?: Layer.Layer<LLM.Service>
242242
plugin?: Layer.Layer<Plugin.Service>
243243
provider?: ReturnType<typeof ProviderTest.fake>
244244
config?: Layer.Layer<Config.Service>
245-
}) {
245+
}
246+
247+
function withCompaction(options?: CompactionProcessOptions) {
248+
return Effect.provide(compactionProcessLayer(options))
249+
}
250+
251+
function compactionProcessLayer(options?: CompactionProcessOptions) {
246252
const bus = Bus.layer
247253
const status = SessionStatus.layer.pipe(Layer.provide(bus))
248254
const processor = options?.llm
@@ -857,7 +863,7 @@ describe("session.compaction.process", () => {
857863
}),
858864
)
859865

860-
itProcess.instance(
866+
itCompaction.instance(
861867
"marks summary message as errored on compact result",
862868
Effect.gen(function* () {
863869
const ssn = yield* SessionNs.Service
@@ -882,7 +888,7 @@ describe("session.compaction.process", () => {
882888
expect(summary.info.finish).toBe("error")
883889
expect(JSON.stringify(summary.info.error)).toContain("Session too large to compact")
884890
}
885-
}).pipe(Effect.provide(compactionProcessLayer({ result: "compact" }))),
891+
}).pipe(withCompaction({ result: "compact" })),
886892
)
887893

888894
it.instance(
@@ -916,7 +922,7 @@ describe("session.compaction.process", () => {
916922
}),
917923
)
918924

919-
itProcess.instance(
925+
itCompaction.instance(
920926
"persists tail_start_id for retained recent turns",
921927
Effect.gen(function* () {
922928
const ssn = yield* SessionNs.Service
@@ -939,10 +945,10 @@ describe("session.compaction.process", () => {
939945
const part = yield* readCompactionPart(session.id)
940946
expect(part?.type).toBe("compaction")
941947
expect(part?.tail_start_id).toBe(keep.id)
942-
}).pipe(Effect.provide(compactionProcessLayer({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }) }))),
948+
}).pipe(withCompaction({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }) })),
943949
)
944950

945-
itProcess.instance(
951+
itCompaction.instance(
946952
"shrinks retained tail to fit preserve token budget",
947953
Effect.gen(function* () {
948954
const ssn = yield* SessionNs.Service
@@ -965,10 +971,10 @@ describe("session.compaction.process", () => {
965971
const part = yield* readCompactionPart(session.id)
966972
expect(part?.type).toBe("compaction")
967973
expect(part?.tail_start_id).toBe(keep.id)
968-
}).pipe(Effect.provide(compactionProcessLayer({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 100 }) }))),
974+
}).pipe(withCompaction({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 100 }) })),
969975
)
970976

971-
itProcess.instance(
977+
itCompaction.instance(
972978
"falls back to full summary when even one recent turn exceeds preserve token budget",
973979
() => {
974980
const stub = llm()
@@ -990,16 +996,12 @@ describe("session.compaction.process", () => {
990996
expect(part?.type).toBe("compaction")
991997
expect(part?.tail_start_id).toBeUndefined()
992998
expect(captured).toContain("yyyy")
993-
}).pipe(
994-
Effect.provide(
995-
compactionProcessLayer({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 20 }) }),
996-
),
997-
)
999+
}).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 20 }) }))
9981000
},
9991001
{ git: true },
10001002
)
10011003

1002-
itProcess.instance(
1004+
itCompaction.instance(
10031005
"falls back to full summary when retained tail media exceeds preserve token budget",
10041006
() => {
10051007
const stub = llm()
@@ -1031,16 +1033,12 @@ describe("session.compaction.process", () => {
10311033
expect(part?.tail_start_id).toBeUndefined()
10321034
expect(captured).toContain("recent image turn")
10331035
expect(captured).toContain("Attached image/png: big.png")
1034-
}).pipe(
1035-
Effect.provide(
1036-
compactionProcessLayer({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 100 }) }),
1037-
),
1038-
)
1036+
}).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 100 }) }))
10391037
},
10401038
{ git: true },
10411039
)
10421040

1043-
itProcess.instance(
1041+
itCompaction.instance(
10441042
"retains a split turn suffix when a later message fits the preserve token budget",
10451043
() => {
10461044
const stub = llm()
@@ -1086,16 +1084,12 @@ describe("session.compaction.process", () => {
10861084
expect(filtered[1]?.info.role).toBe("assistant")
10871085
expect(filtered[1]?.info.role === "assistant" ? filtered[1].info.summary : false).toBe(true)
10881086
expect(filtered.map((msg) => msg.info.id)).not.toContain(large.id)
1089-
}).pipe(
1090-
Effect.provide(
1091-
compactionProcessLayer({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 100 }) }),
1092-
),
1093-
)
1087+
}).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 1, preserve_recent_tokens: 100 }) }))
10941088
},
10951089
{ git: true },
10961090
)
10971091

1098-
itProcess.instance(
1092+
itCompaction.instance(
10991093
"allows plugins to disable synthetic continue prompt",
11001094
Effect.gen(function* () {
11011095
const ssn = yield* SessionNs.Service
@@ -1124,7 +1118,7 @@ describe("session.compaction.process", () => {
11241118
),
11251119
),
11261120
).toBe(false)
1127-
}).pipe(Effect.provide(compactionProcessLayer({ plugin: autocontinue(false) }))),
1121+
}).pipe(withCompaction({ plugin: autocontinue(false) })),
11281122
)
11291123

11301124
it.instance(
@@ -1192,7 +1186,7 @@ describe("session.compaction.process", () => {
11921186
}),
11931187
)
11941188

1195-
itProcess.instance(
1189+
itCompaction.instance(
11961190
"stops quickly when aborted during retry backoff",
11971191
() => {
11981192
const stub = llm()
@@ -1249,12 +1243,12 @@ describe("session.compaction.process", () => {
12491243
expect(Cause.hasInterrupts(exit.cause)).toBe(true)
12501244
expect(Date.now() - start).toBeLessThan(250)
12511245
}
1252-
}).pipe(Effect.provide(compactionProcessLayer({ llm: stub.layer })))
1246+
}).pipe(withCompaction({ llm: stub.layer }))
12531247
},
12541248
{ git: true },
12551249
)
12561250

1257-
itProcess.instance(
1251+
itCompaction.instance(
12581252
"does not leave a summary assistant when aborted before processor setup",
12591253
() =>
12601254
Effect.gen(function* () {
@@ -1281,12 +1275,12 @@ describe("session.compaction.process", () => {
12811275
expect(Exit.isFailure(exit)).toBe(true)
12821276
if (Exit.isFailure(exit)) expect(Cause.hasInterrupts(exit.cause)).toBe(true)
12831277
expect(all.some((msg) => msg.info.role === "assistant" && msg.info.summary)).toBe(false)
1284-
}).pipe(Effect.provide(compactionProcessLayer({ plugin: plugin(ready) })))
1278+
}).pipe(withCompaction({ plugin: plugin(ready) }))
12851279
}),
12861280
{ git: true },
12871281
)
12881282

1289-
itProcess.instance(
1283+
itCompaction.instance(
12901284
"does not allow tool calls while generating the summary",
12911285
() => {
12921286
const stub = llm()
@@ -1350,12 +1344,12 @@ describe("session.compaction.process", () => {
13501344

13511345
expect(summary?.info.role).toBe("assistant")
13521346
expect(summary?.parts.some((part) => part.type === "tool")).toBe(false)
1353-
}).pipe(Effect.provide(compactionProcessLayer({ llm: stub.layer })))
1347+
}).pipe(withCompaction({ llm: stub.layer }))
13541348
},
13551349
{ git: true },
13561350
)
13571351

1358-
itProcess.instance(
1352+
itCompaction.instance(
13591353
"summarizes only the head while keeping recent tail out of summary input",
13601354
() => {
13611355
const stub = llm()
@@ -1387,12 +1381,12 @@ describe("session.compaction.process", () => {
13871381
expect(captured).not.toContain("keep this turn")
13881382
expect(captured).not.toContain("and this one too")
13891383
expect(captured).not.toContain("What did we do so far?")
1390-
}).pipe(Effect.provide(compactionProcessLayer({ llm: stub.layer })))
1384+
}).pipe(withCompaction({ llm: stub.layer }))
13911385
},
13921386
{ git: true },
13931387
)
13941388

1395-
itProcess.instance(
1389+
itCompaction.instance(
13961390
"anchors repeated compactions with the previous summary",
13971391
() => {
13981392
const stub = llm()
@@ -1429,12 +1423,12 @@ describe("session.compaction.process", () => {
14291423
expect(captured.match(/summary one/g)?.length).toBe(1)
14301424
expect(captured).toContain("## Constraints & Preferences")
14311425
expect(captured).toContain("## Progress")
1432-
}).pipe(Effect.provide(compactionProcessLayer({ llm: stub.layer })))
1426+
}).pipe(withCompaction({ llm: stub.layer }))
14331427
},
14341428
{ git: true },
14351429
)
14361430

1437-
itProcess.instance("keeps recent pre-compaction turns across repeated compactions", () => {
1431+
itCompaction.instance("keeps recent pre-compaction turns across repeated compactions", () => {
14381432
const stub = llm()
14391433
stub.push(reply("summary one"))
14401434
stub.push(reply("summary two"))
@@ -1471,14 +1465,10 @@ describe("session.compaction.process", () => {
14711465
expect(
14721466
filtered.some((msg) => msg.info.role === "user" && msg.parts.some((part) => part.type === "compaction")),
14731467
).toBe(true)
1474-
}).pipe(
1475-
Effect.provide(
1476-
compactionProcessLayer({ llm: stub.layer, config: cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }) }),
1477-
),
1478-
)
1468+
}).pipe(withCompaction({ llm: stub.layer, config: cfg({ tail_turns: 2, preserve_recent_tokens: 10_000 }) }))
14791469
})
14801470

1481-
itProcess.instance(
1471+
itCompaction.instance(
14821472
"ignores previous summaries when sizing the retained tail",
14831473
Effect.gen(function* () {
14841474
const ssn = yield* SessionNs.Service
@@ -1519,7 +1509,7 @@ describe("session.compaction.process", () => {
15191509
const part = yield* readCompactionPart(session.id)
15201510
expect(part?.type).toBe("compaction")
15211511
expect(part?.tail_start_id).toBe(keep.id)
1522-
}).pipe(Effect.provide(compactionProcessLayer({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 500 }) }))),
1512+
}).pipe(withCompaction({ config: cfg({ tail_turns: 2, preserve_recent_tokens: 500 }) })),
15231513
)
15241514
})
15251515

0 commit comments

Comments
 (0)