feat: add gesture sequences and calibrated pixel drags

This commit is contained in:
chenmingxuan committed 2026-11-02 11:53:27 +08:00
1 parent 2a3bbaa3fb
commit 479a185192
31 files changed
+2440 -44

No files matched your search

+35 -2
View File
@@ -85,7 +85,17 @@ AGENT_TOOL_NAMES: frozenset[str] = (
#: Actions whose ``target`` is a single point: an element index or an [x, y] pair.
_POINT_TARGET_ACTIONS: frozenset[str] = frozenset({"click", "long_press", "input_text"})
_SCREEN_CHANGING_ACTIONS: frozenset[str] = frozenset(
{"click", "click_sequence", "long_press", "input_text", "press_key", "swipe", "manage_app"}
{
"click",
"click_sequence",
"action_sequence",
"drag",
"long_press",
"input_text",
"press_key",
"swipe",
"manage_app",
}
)
@@ -337,7 +347,7 @@ class McpActionExecutor:
)
else:
res = await session.call(wire_name, wire_args)
message = finalize(res) if finalize else res.message
message = finalize(res) if finalize else res.agent_message
if res.ok or self._observe_despite_failure(raw_name, res):
obs, observation_settled = await self._observe_after_action(
@@ -393,6 +403,7 @@ class McpActionExecutor:
"post_image_name": post_image_name,
"has_xml": bool(xml_list),
"status": status,
**({"gesture_result": res.metadata} if res.metadata else {}),
**({"source": source} if source and dispatched else {}),
}
if status == "error":
@@ -423,6 +434,7 @@ class McpActionExecutor:
if res.code
in {ActionCode.INVALID_ARGS, ActionCode.UNSUPPORTED, ActionCode.PACKAGE_NOT_FOUND}
else "possible",
**res.metadata,
},
)
@@ -436,6 +448,8 @@ class McpActionExecutor:
return res.code not in (ActionCode.PACKAGE_NOT_FOUND, ActionCode.INVALID_ARGS)
if raw_name == "wait_for_text":
return res.code is ActionCode.TIMEOUT
if raw_name in {"drag", "action_sequence"}:
return res.code not in {ActionCode.INVALID_ARGS, ActionCode.UNSUPPORTED}
return False
# --- Argument translation --------------------------------------------------------
@@ -458,6 +472,25 @@ class McpActionExecutor:
``index_elements`` overrides the list index targets resolve against
(see :meth:`execute`).
"""
if raw_name in {"drag", "action_sequence"}:
from artemis.config.agent import load_agent_config
from artemis.mcp.gestures import DragRequest, SequenceRequest, plan_drag, plan_sequence
try:
if raw_name == "drag":
request = DragRequest.model_validate(args)
planned = plan_drag(request, *self._screen_size())
return "drag", request.model_dump(mode="json"), None, planned
sequence_request = SequenceRequest.model_validate(args)
plan_sequence(
sequence_request,
*self._screen_size(),
limit=load_agent_config().pro.execution.max_burst_actions,
)
return "action_sequence", sequence_request.model_dump(mode="json"), None, {}
except ValueError as exc:
raise _ArgError(f"Error during {raw_name}: {exc}") from exc
if raw_name == "click":
target, recorded = self._resolve_target(
args.get("target") or args.get("coordinates"),