Files
agentic-mobile-control/packages/cloud-platform/cloud/repository.py
T

148 lines
3.6 KiB
Python

from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime
from typing import TYPE_CHECKING, Any, Literal, Protocol
if TYPE_CHECKING:
from cloud.plugins import PluginManifest
from cloud.pool import HostRegistration, PooledDevice
from cloud.scheduler import ScheduledTask
AttemptStatus = Literal["assigned", "dispatched", "done", "failed", "expired"]
TerminalTaskStatus = Literal["done", "failed"]
ResultRecordStatus = Literal["recorded", "already_recorded", "conflict"]
@dataclass(frozen=True)
class TaskAttemptRecord:
task_id: str
attempt: int
lease_id: str
host_id: str
device_id: str
status: AttemptStatus
lease_expires_at: datetime
created_at: datetime
completed_at: datetime | None = None
failure_reason: str | None = None
terminal_result: dict[str, Any] | None = None
@dataclass(frozen=True)
class LeasedAssignment:
task_id: str
attempt: int
lease_id: str
lease_expires_at: datetime
host_id: str
device_id: str
goal: str | None
workflow_definition_id: str | None
class CloudRepository(Protocol):
"""Persistence port for cloud state and atomic scheduling operations."""
def upsert_host(
self,
host_id: str,
*,
address: str | None,
last_seen_at: datetime,
) -> None: ...
def replace_host_devices(
self,
host_id: str,
devices: list[PooledDevice],
) -> None: ...
def list_hosts(self) -> list[HostRegistration]: ...
def get_host(self, host_id: str) -> HostRegistration | None: ...
def list_devices(self) -> list[PooledDevice]: ...
def get_device(self, device_id: str) -> PooledDevice | None: ...
def enqueue_task(self, task: ScheduledTask) -> None: ...
def list_queued_tasks(self) -> list[ScheduledTask]: ...
def get_task(self, task_id: str) -> ScheduledTask | None: ...
def update_task(
self,
task_id: str,
*,
status: str | None = None,
assigned_device_id: str | None = None,
assigned_host_id: str | None = None,
) -> None: ...
def count_queued_tasks(self) -> int: ...
def save_plugin(self, manifest: PluginManifest, *, wired: bool) -> None: ...
def list_plugins(self) -> list[tuple[PluginManifest, bool]]: ...
def get_plugin(self, name: str) -> tuple[PluginManifest, bool] | None: ...
def list_reserved_device_ids(self, *, now: datetime) -> set[str]: ...
def assign_task(
self,
*,
task_id: str,
host_id: str,
device_id: str,
lease_id: str,
lease_expires_at: datetime,
now: datetime,
) -> LeasedAssignment | None: ...
def claim_assignment(
self,
*,
host_id: str,
now: datetime,
) -> LeasedAssignment | None: ...
def renew_lease(
self,
*,
task_id: str,
attempt: int,
lease_id: str,
host_id: str,
lease_expires_at: datetime,
now: datetime,
) -> bool: ...
def record_task_result(
self,
*,
task_id: str,
attempt: int,
lease_id: str,
host_id: str,
status: TerminalTaskStatus,
failure_reason: str | None,
completed_at: datetime,
) -> ResultRecordStatus: ...
def reap_expired_leases(
self,
*,
now: datetime,
max_attempts: int,
) -> list[str]: ...
def list_task_attempts(self, task_id: str) -> list[TaskAttemptRecord]: ...
def health_check(self) -> None: ...
def close(self) -> None: ...