okami.mom/albedo
git clone https://git.nkp.pet/okami.mom/albedo
cba5ff8
main
1"""Cancellation releases execution workers and long tool turns complete.""" 2 3from concurrent .futures import ThreadPoolExecutor 4import json 5import time 6 7from harness import exclusive 8from stream_support import StreamProbe 9 10from integration_support import IntegrationScenario 11 12 13class ExecutionRecoveryTests (IntegrationScenario ): 14# exclusive: enables the existing native inspection seam 15@exclusive 16def test_interrupt_before_first_token_stops_worker_without_killing_it (self ): 17for protocol in ("responses" ,"chat_completions" ): 18with self .subTest (protocol = protocol ): 19app = self .app_for ( 20protocol ,prepare = lambda app :app .env .update (ALBEDO_INSPECT = "1" ) 21 ) 22session = app .session () 23start = len (self .provider .requests ) 24with app .prompt (session ,"no first token" )as response : 25input_id = json .load (response )["id" ] 26self .wait_for_request (start ) 27captured = self .read (app ,f"/sessions/ { session } ?tail=0" ) 28probe = StreamProbe (app ) 29ready = app .workspace / f"monitor- { protocol } " 30arguments = ( 31"[" 32+ "," .join ( 33"<<" + json .dumps (value )+ ">>" 34for value in [session ,captured ["status" ]["run_id" ],str (ready )] 35 ) 36+ "]" 37 ) 38with ThreadPoolExecutor (max_workers = 1 )as pool : 39exited = pool .submit (probe .call ,"worker_exit_json" ,arguments ) 40deadline = time .monotonic ()+ 30 41while not ready .exists ()and time .monotonic ()< deadline : 42time .sleep (0.01 ) 43self .assertTrue (ready .exists (),"worker monitor was not installed" ) 44app .api ( 45f"/sessions/ { session } /interrupt" , 46 { 47"run_id" :captured ["status" ]["run_id" ], 48"through_input_order" :captured ["input_order" ], 49 }, 50 ).close () 51self .assertEqual (exited .result (timeout = 40 ), {"reason" :"normal" }) 52app .idle (session ) 53receipt = self .read (app ,f"/sessions/ { session } /inputs/ { input_id } " ) 54self .assertEqual (receipt ["turn" ]["state" ],"interrupted" ) 55# The interrupted session takes a new turn and commits it. 56self .send (app ,session ,"continue from branch" ) 57self .assertTrue ( 58any ( 59e ["kind" ]== "assistant" and self .entry_text (e )== "finished" 60for e in self .history (app ,session ) 61 ) 62 ) 63 64def test_more_than_hundred_tool_turns_complete (self ): 65for protocol in ("responses" ,"chat_completions" ): 66with self .subTest (protocol = protocol ): 67app = self .app_for (protocol ) 68session = app .session () 69start = len (self .provider .requests ) 70self .send (app ,session ,"continue for over 100 turns" ) 71self .assertEqual (len (self .records (start )),106 ) 72events = self .history (app ,session ) 73self .assertEqual (sum (e ["kind" ]== "tool_result" for e in events ),105 ) 74self .assertTrue ( 75any ( 76e ["kind" ]== "assistant" and self .entry_text (e )== "finished" 77for e in events 78 ) 79 )