fix: bound task failures and release stalled workers

This commit is contained in:
chenmingxuan committed 2026-10-08 16:10:10 +08:00
1 parent 606ed94160
commit 1fdf7c0d1d
32 files changed
+1121 -93

No files matched your search

+37 -2
View File
@@ -22,9 +22,12 @@ Validator -- which runs its own UI-change polling -- simply never calls it.
import asyncio
import base64
from io import BytesIO
import time
from PIL import Image
from artemis.config import get_temp_dir
from artemis.config.settings import settings
from artemis.context import ArtemisContext
from artemis.controllers.unified_controller import UnifiedMobileController
from artemis.mcp.action_types import ActionCode, ObserveResult
@@ -34,7 +37,29 @@ from artemis.utils.visualization import format_minimal_list_with_elements
logger = get_logger(__name__)
__all__ = ["observe"]
__all__ = ["observe", "require_observation", "DeviceObservationError"]
class DeviceObservationError(RuntimeError):
"""A live device could not be observed after bounded recovery."""
async def require_observation(
ctx: ArtemisContext, controller: UnifiedMobileController, settle_ms: int = 400
) -> tuple[ObserveResult, bytes | None]:
"""Recover observation without spending model calls on unavailable screens."""
last = "设备未返回有效画面"
for attempt in range(settings.ARTEMIS_OBSERVATION_MAX_ATTEMPTS):
observation, image = await observe(ctx, controller, settle_ms=settle_ms)
if observation.ok:
return observation, image
last = observation.message
logger.warning(
f"设备观测恢复 {attempt + 1}/{settings.ARTEMIS_OBSERVATION_MAX_ATTEMPTS}:{last}"
)
raise DeviceObservationError(
f"设备观测失败(已尝试 {settings.ARTEMIS_OBSERVATION_MAX_ATTEMPTS} 次):{last}"
)
async def observe(
@@ -60,9 +85,19 @@ async def observe(
await asyncio.sleep(settle_ms / 1000.0)
else:
logger.info("Retrieving screen data directly (skip settling)...")
device_data = await controller.get_screen_data()
device_data = await asyncio.wait_for(
controller.get_screen_data(), timeout=settings.ARTEMIS_OBSERVATION_TIMEOUT_SECONDS
)
screenshot_bytes = base64.b64decode(device_data.base64)
with Image.open(BytesIO(screenshot_bytes)) as image:
if min(image.size) <= 1:
raise ValueError("设备截图为占位图,当前画面不可用")
image.verify()
except Exception as e:
if isinstance(e, TimeoutError):
e = TimeoutError(
f"设备屏幕观测超时({settings.ARTEMIS_OBSERVATION_TIMEOUT_SECONDS:g} 秒)"
)
logger.error(f"Failed to capture screen state: {e}")
return (
ObserveResult(