okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
deef7f4
main
1//// Building a request must not change what the next one builds: every 2//// strategy's projection reads its saved state and writes nothing, even when 3//// the history no longer matches that state. Only a compaction writes. The 4//// E2E harness cannot run a projection apart from the compaction that may 5//// follow it, so it cannot tell a read from a write. 6 7import albedo/daemon/conversation 8import albedo/daemon/store 9import albedo/harness/extension 10import albedo/harness/extensions 11import albedo/harness/extensions/lcm/extension as lcm 12import albedo/harness/extensions/lcm/memory 13import albedo/harness/extensions/rolling/extension as rolling 14import albedo/harness/extensions/snapcompact/extension as snapcompact 15import albedo/harness/runtime 16import albedo/openai_api/types 17import gleam/dynamic/decode 18import gleam/list 19import gleam/option .{ None , Some } 20import gleam/string 21import gleeunit/should 22import harness/session_fixture 23import sqlight 24 25pub fn rolling_projection_writes_nothing_test () -> Nil { 26projections_write_nothing ( 27[ rolling . configured_extension ( rolling . Config ( Some ( 100_000 ), 90 , 25 ))], 28[ "rolling" ], 29) 30} 31 32pub fn lcm_projection_writes_nothing_test () -> Nil { 33projections_write_nothing ( 34[ 35memory . extension (), 36lcm . configured_extension ( lcm . Config ( Some ( 100_000 ), 90 , 25 )), 37], 38[ "lcm-memory" , "lcm" ], 39) 40} 41 42pub fn snapcompact_projection_writes_nothing_test () -> Nil { 43projections_write_nothing ([ snapcompact . memory (), snapcompact . extension ()], [ 44"snapcompact-memory" , 45"snapcompact" , 46]) 47} 48 49/// Compacts once, then prepares requests below the trigger: from the history 50/// the compaction saw, and from a rewritten one its saved state no longer 51/// matches. Neither may write. 52fn projections_write_nothing ( 53installed : List ( extension . Extension ), 54enabled : List ( String ), 55) -> Nil { 56let assert Ok ( host ) = 57runtime . start_with_config ( ":memory:" , extensions . Config ( installed , enabled )) 58session_fixture . initialise ( host ) 59session_fixture . create ( host , "projection" , "/tmp" ) 60let ledger = runtime . ledger ( host ) 61let history = conversation_of ([ "first" , "second" , "third" , "fourth" ]) 62let assert Ok ( _ ) = 63conversation . commit_from ( 64ledger , 65"projection" , 66history , 67conversation . Idle , 68Some ( "provider" ), 69) 70let assert Ok ( session ) = runtime . open_session ( host , "projection" , "/tmp" ) 71let assert Ok ( _ ) = 72runtime . compact_history_scoped ( 73host , 74session , 75"model" , 76"model" , 77None , 78"" , 79fn ( _ ) { Ok ( "summary of earlier work" ) }, 80history , 81) 82let prepare = fn ( history ) { 83let before = changes ( ledger ) 84let assert Ok ( inputs ) = 85runtime . prepare_history_with ( 86host , 87session , 88"model" , 89"" , 90fn ( _ ) { Error ( "a projection must not summarize" ) }, 91history , 92) 93changes ( ledger ) |> should . equal ( before ) 94inputs 95} 96// The saved compaction stands in for the start of the history it covers. 97prepare ( history ) |> should . not_equal ( history ) 98prepare ( conversation_of ([ "rewritten" , "second" , "third" , "fourth" ])) 99runtime . stop ( host ) 100} 101 102fn conversation_of ( topics : List ( String )) -> List ( types . Input ) { 103list . flat_map ( topics , fn ( topic ) { 104[ 105types . User ( topic <> " " <> string . repeat ( "q" , 4000 )), 106types . Assistant ( topic <> " answer " <> string . repeat ( "a" , 4000 )), 107] 108}) 109} 110 111/// Rows the store's one connection has changed since it opened. 112fn changes ( ledger : store . Store ) -> Int { 113let assert Ok ([ count ]) = 114store . query ( ledger , fn ( db ) { 115sqlight . query ( 116"SELECT total_changes()" , 117db , 118[], 119decode . field ( 0 , decode . int , decode . success ), 120) 121}) 122count 123}