Files
Artemis-Eapil/artemis/mcp/action_parameters.py
T
chenmingxuan 4ea7939d9c feat(android): add state conditions and measured gesture feedback
Add optional ensure_state, gesture region and final value feedback shared by Flash and Pro. Preserve completed inputs when verification fails and stop repeated ineffective strategies. Regenerate pinned tool schemas for the new optional arguments.
2026-11-02 23:20:34 +08:00

55 lines
2.1 KiB
Python

"""Strict, shared geometry for device actions; planning never dispatches input."""
from typing import Annotated, Literal
from pydantic import BaseModel, ConfigDict, Field, StrictInt
class GestureModel(BaseModel):
model_config = ConfigDict(
extra="forbid", strict=True, allow_inf_nan=False, str_strip_whitespace=True
)
Point = Annotated[list[StrictInt], Field(min_length=2, max_length=2)]
Region = Annotated[list[StrictInt], Field(min_length=4, max_length=4)]
Duration = Annotated[int, Field(strict=True, ge=1, le=10000)]
CoordinateSpace = Literal["normalized", "pixel"]
def pixel_point(point: list[int], space: CoordinateSpace, width: int, height: int) -> list[int]:
if width <= 0 or height <= 0:
raise ValueError("Screen dimensions must be positive.")
limits = [1001, 1001] if space == "normalized" else [width, height]
if any(p < 0 or p >= limit for p, limit in zip(point, limits, strict=True)):
raise ValueError(f"Point {point} is outside the {space} screen bounds.")
if space == "pixel":
return list(point)
return [min(size - 1, p * size // 1000) for p, size in zip(point, [width, height], strict=True)]
def pixel_region(region: list[int], space: CoordinateSpace, width: int, height: int) -> list[int]:
"""Observed rectangle; right/bottom are exclusive, like Android bounds."""
left, top, right, bottom = region
max_x, max_y = (1000, 1000) if space == "normalized" else (width, height)
if not (0 <= left < right <= max_x and 0 <= top < bottom <= max_y):
raise ValueError(
"region must be a nonempty on-screen [left, top, right, bottom] rectangle."
)
if space == "pixel":
return list(region)
return [
left * width // 1000,
top * height // 1000,
right * width // 1000,
bottom * height // 1000,
]
def require_in_region(points: list[list[int]], region: list[int]) -> None:
left, top, right, bottom = region
if any(not (left <= x < right and top <= y < bottom) for x, y in points):
raise ValueError(
"Gesture leaves the observed region; re-observe the actual gesture surface. No input executed."
)