feat(host-agent): renew active assignment leases
This commit is contained in:
@@ -76,3 +76,39 @@ def test_task_runner_executes_loop_and_writes_timeline(tmp_path) -> None:
|
||||
assert len(timeline.read(task.id)) == 2
|
||||
assert metadata.get_task(task.id)["status"] == "completed"
|
||||
|
||||
|
||||
def test_task_runner_stops_before_the_next_planned_action() -> None:
|
||||
scene = Scene(width=10, height=20, elements=[])
|
||||
stop_requested = False
|
||||
actions: list[str] = []
|
||||
|
||||
def record_action(**kwargs):
|
||||
nonlocal stop_requested
|
||||
actions.append("tap")
|
||||
stop_requested = True
|
||||
return {"ok": True}
|
||||
|
||||
runner = TaskRunner(
|
||||
planner=ScriptedPlanner(
|
||||
[
|
||||
PlannedStep(action="tap", description="first", args={}),
|
||||
PlannedStep(action="tap", description="second", args={}),
|
||||
]
|
||||
),
|
||||
executor=Executor(
|
||||
tools={"tap": record_action},
|
||||
config=ExecutorConfig(max_retries=1, backoff_seconds=0),
|
||||
),
|
||||
config=TaskRunnerConfig(max_steps=5),
|
||||
observer=lambda device_id: scene,
|
||||
screenshot_provider=lambda device_id: PNG_10X20,
|
||||
)
|
||||
|
||||
result = runner.run(
|
||||
Task(goal="perform two actions", device_id="phone"),
|
||||
should_stop=lambda: stop_requested,
|
||||
)
|
||||
|
||||
assert result.status == "failed"
|
||||
assert result.failure_reason == "execution interrupted"
|
||||
assert actions == ["tap"]
|
||||
|
||||
@@ -96,6 +96,41 @@ def test_workflow_runner_linear_planned_goal_completes(tmp_path) -> None:
|
||||
assert [result.step_id for result in run.step_results] == ["first", "second"]
|
||||
|
||||
|
||||
def test_workflow_runner_stops_before_the_next_step(tmp_path) -> None:
|
||||
stop_requested = False
|
||||
calls: list[str] = []
|
||||
|
||||
class StoppingTaskRunner:
|
||||
def run(self, task: Task, *, should_stop=None) -> Task:
|
||||
nonlocal stop_requested
|
||||
calls.append(task.goal)
|
||||
stop_requested = True
|
||||
task.status = "completed"
|
||||
return task
|
||||
|
||||
definition = WorkflowDefinition(
|
||||
name="interruptible",
|
||||
entry_step_id="first",
|
||||
steps=[
|
||||
PlannedGoalStep("first", "first", next_step_id="second"),
|
||||
PlannedGoalStep("second", "second"),
|
||||
],
|
||||
)
|
||||
runner = WorkflowRunner(
|
||||
_store(tmp_path),
|
||||
task_runner_factory=lambda: StoppingTaskRunner(), # type: ignore[arg-type]
|
||||
)
|
||||
|
||||
run = runner.run(
|
||||
definition,
|
||||
"phone",
|
||||
should_stop=lambda: stop_requested,
|
||||
)
|
||||
|
||||
assert run.status == "cancelled"
|
||||
assert calls == ["first"]
|
||||
|
||||
|
||||
def test_workflow_runner_failing_planned_goal_marks_run_failed(tmp_path) -> None:
|
||||
definition = WorkflowDefinition(
|
||||
name="fail",
|
||||
|
||||
Reference in New Issue
Block a user