okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
6e82811
main
1%% Test-only structural inspection. Never returns inspected actor state. 2- module ( albedo_context_snapshot_probe ). 3- export ([ retention / 0 , actor / 1 , actor_json / 1 ]). 4 5capture ( Inputs ) -> 6Request = 'albedo@openai_api' : request (<< "fixture" >>, Inputs ), 7'albedo@daemon@context_snapshot' : from_request ( 8{ some , 1234 }, << "fixture" >>, << "responses" >>, responses , Request , none ). 9 10payload ( Prefix , Index , Bytes ) -> 11Head = iolist_to_binary ([ Prefix , integer_to_binary ( Index ), << ":" >>]), 12<< Head / binary , ( binary : copy (<< "x" >>, Bytes - byte_size ( Head ))) / binary >>. 13replay ( Index , Bytes ) -> 14Encoded = iolist_to_binary ( json : encode ( # { type =><< "reasoning" >>, 15opaque =>payload (<< "REPLAY_SENTINEL:" >>, Index , Bytes )})), 16{ ok , Item } = 'gleam@json' : parse ( Encoded , 17'albedo@openai_api@types' : replay_decoder ( responses )), 18{ replay , Item }. 19 20inline () -> 21{ ok , Image } = 'albedo@openai_api@types' : image (<< "image/png" >>, 22payload (<< "INLINE_SENTINEL:" >>, 1 , 1048576 ), 10 , 10 , 786432 ), 23Image . 24stored () -> 25Sentinel = payload (<< "READER_SENTINEL:" >>, 1 , 1048576 ), 26{ ok , Image } = 'albedo@openai_api@types' : stored_image (<< "image/png" >>, 27<< "stored-hash" >>, 1048576 , fun () -> { ok , Sentinel } end , 10 , 10 , 786432 ), 28Image . 29 30walk ( Term , Test ) when is_binary ( Term ) -> Test ( Term ); 31walk ( Term , Test ) when is_tuple ( Term ) -> walk ( tuple_to_list ( Term ), Test ); 32walk ([ Head | Tail ], Test ) -> walk ( Head , Test ) orelse walk ( Tail , Test ); 33walk ( Term , Test ) when is_map ( Term ) -> walk ( maps : to_list ( Term ), Test ); 34walk ( Term , Test ) when is_function ( Term ) -> 35{ env , Environment } = erlang : fun_info ( Term , env ), walk ( Environment , Test ); 36walk ( _ , _ ) -> false . 37contains ( Term , Prefix ) -> walk ( Term , fun ( Binary ) -> 38binary : match ( Binary , Prefix ) =/= nomatch end ). 39 40retention () -> 41Parent = self (), 42{ Producer , Monitor } = spawn_monitor ( fun () -> 43Parent ! { snapshot , capture ([{ user , << "VISIBLE_SENTINEL:" , ( binary : copy (<< "v" >>, 256 )) / binary >>}, 44replay ( 1 , 1048576 ), { user_image , << "image" >>, [ inline ()]}, 45{ tool_output , << "call" >>, << "tool" >>, [ stored ()]}])} 46end ), 47Snapshot = receive { snapshot , Value } -> Value end , 48receive { 'DOWN' , Monitor , process , Producer , normal } -> ok end , 49erlang : garbage_collect (), 50{ contains ( Snapshot , << "VISIBLE_SENTINEL:" >>), 51contains ( Snapshot , << "REPLAY_SENTINEL:" >>), 52contains ( Snapshot , << "INLINE_SENTINEL:" >>), 53contains ( Snapshot , << "READER_SENTINEL:" >>)}. 54 55binary_bytes ( Pid ) -> 56{ binary , Entries } = process_info ( Pid , binary ), 57lists : sum ( maps : values ( maps : from_list ([{ Pointer , Bytes } || { Pointer , Bytes , _ } <- Entries ]))). 58actor ( Id ) -> 59{ some , Session } = 'albedo@daemon@session' : live ( Id ), 60{ ok , Pid } = 'gleam@erlang@process' : subject_owner ( Session ), 61Workers = [ Worker || Worker <- processes (), Label <- [ proc_lib : get_label ( Worker )], 62is_tuple ( Label ), element ( 1 , Label ) =:= albedo_worker ], 63lists : foreach ( fun ( Worker ) -> 64Monitor = monitor ( process , Worker ), 65receive { 'DOWN' , Monitor , process , Worker , _ } -> ok after 10000 -> error ( worker_still_alive ) end 66end , Workers ), 67erlang : garbage_collect ( Pid ), 68{ binary , BeforeEntries } = process_info ( Pid , binary ), 69LargePointers = maps : from_list ([{ Pointer , Size } || { Pointer , Size , _ } <- BeforeEntries , 70Size >= 262144 ]), 71{ Evicted , EvictionMetric } = actor_measure ( Pid , history_eviction_collection , fun () -> 72DidEvict = 'albedo@daemon@session' : evict_history ( Session ), 73%% Two synchronous actor barriers pass the self-sent Collect message. 74_ = 'albedo@daemon@session' : report ( Session ), 75_ = 'albedo@daemon@session' : report ( Session ), 76erlang : garbage_collect ( Pid ), 77DidEvict 78end ), 79Check = self (), 80{ Reader , ReaderMonitor } = spawn_monitor ( fun () -> 81State = sys : get_state ( Pid ), 82Check ! { checked , 'albedo@daemon@session_diagnostics' : history_unloaded ( State ), 83contains ( State , << "REPLAY_SENTINEL:" >>)} 84end ), 85{ Unloaded , Reachable } = receive 86{ checked , A , B } -> { A , B }; 87{ 'DOWN' , ReaderMonitor , process , Reader , Reason } -> error ({ state_inspection_failed , Reason }) 88end , 89receive { 'DOWN' , ReaderMonitor , process , Reader , normal } -> ok end , 90erlang : garbage_collect ( Pid ), 91Retained = binary_bytes ( Pid ), 92{ binary , AfterEntries } = process_info ( Pid , binary ), 93Backing = lists : sum ( maps : values ( maps : from_list ([{ Pointer , Size } 94|| { Pointer , Size , _ } <- AfterEntries , maps : is_key ( Pointer , LargePointers )]))), 95{ ok , Snapshot } = 'albedo@daemon@session' : prepared_context ( Session , none ), 96HistoryPage = 'albedo@daemon@context_snapshot' : page ( Snapshot , << "history" >>, 0 ), 97{ _ , IdleMetric } = actor_measure ( Pid , idle_retention , fun () -> 98_ = 'albedo@daemon@session' : report ( Session ), 99erlang : garbage_collect ( Pid ) 100end ), 101{ Released , ClearMetric } = actor_measure ( Pid , context_clear , fun () -> 102DidRelease = 'albedo@daemon@session' : release ( Session ), 103_ = 'albedo@daemon@session' : report ( Session ), 104_ = 'albedo@daemon@session' : report ( Session ), 105erlang : garbage_collect ( Pid ), 106DidRelease 107end ), 108{ ok , Pending } = 'albedo@daemon@session' : prepared_context ( Session , none ), 109{ pending , _ } = Pending , 110SessionMonitor = monitor ( process , Pid ), 111_ = 'albedo@daemon@session' : close ( Session ), 112Stopped = receive { 'DOWN' , SessionMonitor , process , Pid , _ } -> true after 5000 -> false end , 113# { evicted =>Evicted , history_unloaded =>Unloaded , replay_reachable =>Reachable , 114history_readable =>element ( 1 , HistoryPage ) =:= ok , 115actor_binary_bytes =>Retained , replay_backing_binary_bytes =>Backing , 116replay_backing_before_bytes =>lists : sum ( maps : values ( LargePointers )), 117kernel_released =>Released , context_cleared =>element ( 1 , Pending ) =:= pending , 118actor_stopped =>Stopped , workers_terminated =>true , 119phases =>[ EvictionMetric , IdleMetric , ClearMetric ]}. 120actor_json ( Id ) -> iolist_to_binary ( json : encode ( actor ( Id ))). 121 122actor_measure ( Pid , Name , Action ) -> 123{ reductions , Before } = process_info ( Pid , reductions ), 124Start = erlang : monotonic_time ( microsecond ), 125Value = Action (), 126Elapsed = erlang : monotonic_time ( microsecond ) - Start , 127{ reductions , After } = process_info ( Pid , reductions ), 128{ memory , Memory } = process_info ( Pid , memory ), 129{ message_queue_len , Mailbox } = process_info ( Pid , message_queue_len ), 130{ Value , # { phase =>Name , wall_us =>Elapsed , reductions =>After - Before , 131actor_memory_bytes =>Memory , mailbox_messages =>Mailbox , 132actor_binary_bytes =>binary_bytes ( Pid )}}.