@@ -233,16 +233,22 @@ const env = Layer.mergeAll(
233233
234234const 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 ( / s u m m a r y o n e / 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