69 lines
3.2 KiB
Python
69 lines
3.2 KiB
Python
"""All terminal worker exits must close Steer and preserve accepted guidance."""
|
|
import pytest
|
|
from api import config
|
|
from tests import test_steer_worker_boundaries as boundaries
|
|
|
|
worker_scene = boundaries.worker_scene
|
|
|
|
|
|
@pytest.mark.parametrize('outcome', ['success', 'returned-error', 'exception'])
|
|
def test_terminal_exit_fences_before_event_and_keeps_guidance(worker_scene, monkeypatch, outcome):
|
|
scene = worker_scene
|
|
observed = []
|
|
put = scene.events.put_nowait
|
|
|
|
def observe(item):
|
|
if item[0] in ('done', 'apperror'):
|
|
observed.append(config.ACTIVE_RUNS.get('run', {}).get('phase'))
|
|
return put(item)
|
|
|
|
monkeypatch.setattr(scene.events, 'put_nowait', observe)
|
|
|
|
def running():
|
|
scene.agent.session_id = 'compressed-child'
|
|
scene.agent.steer('retained guidance')
|
|
if outcome == 'exception':
|
|
raise RuntimeError('terminal worker failure')
|
|
if outcome == 'returned-error':
|
|
scene.result = {'messages': [], 'error': 'terminal worker failure'}
|
|
else:
|
|
# The real Agent consumes this slot into its returned result.
|
|
text = scene.agent._drain_pending_steer()
|
|
scene.result = {'messages': [
|
|
{'role': 'user', 'content': 'Do the task.'},
|
|
{'role': 'assistant', 'content': 'Finished.'},
|
|
], 'pending_steer': text}
|
|
|
|
scene.on_run = running
|
|
scene.run()
|
|
assert observed and all(phase == 'finalizing' for phase in observed)
|
|
events = list(scene.events.queue)
|
|
leftovers = [data['text'] for event, data in events if event == 'pending_steer_leftover']
|
|
assert leftovers == ['retained guidance']
|
|
assert next(i for i, item in enumerate(events) if item[0] == 'pending_steer_leftover') < next(i for i, item in enumerate(events) if item[0] in ('done', 'apperror'))
|
|
assert scene.agent.pending == []
|
|
|
|
|
|
def test_finalizing_response_preserves_browser_live_stream():
|
|
import subprocess
|
|
from pathlib import Path
|
|
source = (Path(__file__).parents[1] / 'static/commands.js').read_text()
|
|
fn = source[source.index('async function _trySteer('):source.index('async function cmdTitle(')]
|
|
predicate = source[source.index('function _steerFallbackIsDeadRun('):source.index('function _steerOwnerStreamIsCurrent(')]
|
|
script = r'''
|
|
const assert=require('node:assert/strict');
|
|
const S={session:{session_id:'s',active_stream_id:'run'},activeStreamId:'run',busy:true,pendingFiles:[]};
|
|
const INFLIGHT={s:{stream_id:'run'}},inp={value:''};
|
|
const $=()=>inp,t=x=>x,showToast=()=>{};
|
|
const _steerTextWithPendingFiles=async x=>x,_steerOwnerIsCurrent=()=>true,_steerRestoreText=x=>x;
|
|
const _steerFailureMessageKey=x=>x,_showSteerRecovery=()=>{};
|
|
const _steerClearCurrentOwnerDeadRun=()=>{S.busy=false;S.activeStreamId=null;delete INFLIGHT.s};
|
|
const api=async()=>({accepted:false,fallback:'not_running',stream_id:'run'});
|
|
(async()=>{
|
|
assert.equal(await _trySteer('guidance',true),false);
|
|
assert.equal(S.busy,true);assert.equal(S.activeStreamId,'run');
|
|
assert.equal(INFLIGHT.s.stream_id,'run');assert.equal(inp.value,'guidance');
|
|
})().catch(e=>{console.error(e);process.exit(1)});
|
|
'''
|
|
subprocess.run(['node','-e',fn+predicate+script],check=True,timeout=15)
|