feat: release 2.2.0 with PC-only tests and execution reliability fixes
Unify task scheduling and queue state, fix Android input and observation recovery, preserve screenshot paths, and match final review criteria accurately. Add collapsible copyable results and publish the complete 2.1.0 upgrade notes. Validation: 3189 backend tests, 326 frontend tests, 24 client tests, production build and quality gates.
This commit is contained in:
1 parent
fac4ccb760
commit
be6e8c2abd
79 files changed
+2263
-277
No files matched your search
@@ -274,6 +274,8 @@ def mobile_run_task(
|
||||
Delegates a mobile workflow to a background agent. Non-blocking: returns
|
||||
immediately with `trace_id` (for `mobile_manage_task` / `mobile_inspect_trace`),
|
||||
`device_serial`, `stdout_log`/`stderr_log` paths, and `notes_dir` (Pro only).
|
||||
Admission normally returns `status="pending"`; it does not mean the worker
|
||||
is running. A newer worker state is returned when already available.
|
||||
Completion notifications depend on the caller's configured notification backend;
|
||||
conversation_id alone does not guarantee the agent client receives a wakeup.
|
||||
|
||||
@@ -323,7 +325,7 @@ def mobile_run_task(
|
||||
expected_output_desc: Optional, Pro only. If set, a summarization agent
|
||||
writes a report to `output.md` in `notes_dir`. Ignored for Flash.
|
||||
device_serial: Optional device serial (e.g. "emulator-5554") to bind
|
||||
execution to a specific device; distinct devices run concurrently.
|
||||
execution to a specific device; tasks share the global serial queue.
|
||||
If omitted, an available device is selected automatically. When
|
||||
several devices are attached, confirm the target with the user first
|
||||
(`adb devices -l` lists serials and authorization states).
|
||||
@@ -342,7 +344,9 @@ def mobile_run_task(
|
||||
([{id, profile}] references to saved authorized configurations; never secrets).
|
||||
Omitted plugins selects matching enabled defaults; [] disables plugins.
|
||||
Default Android tasks can use mixed extensions on demand without changing targets.
|
||||
Computer tasks require an observation plugin, not an Android device.
|
||||
PC-only tasks use {"execution_target": "computer"}; no Android device or
|
||||
emulator needs to be online. Computer tasks require an observation plugin.
|
||||
This matches the web launcher's PC-only checkbox and batch task_config JSON.
|
||||
Query mobile_workspace first; installation/authorization is in the plugin page.
|
||||
timeout_seconds (total execution, default 1800; excludes queue/pause),
|
||||
observation_timeout_seconds (60), observation_max_attempts (3),
|
||||
@@ -373,6 +377,14 @@ def mobile_run_task(
|
||||
return _run_task(trace_id=str(uuid.uuid4()), **parameters)
|
||||
|
||||
|
||||
def _daemon_task_status(trace_id: str, task: dict[str, Any]) -> str:
|
||||
"""Prefer a worker's newer state without writing back an admission snapshot."""
|
||||
current = (trace_store.read_status(trace_id) or {}).get("status")
|
||||
if current and current != "pending":
|
||||
return current
|
||||
return task.get("status") or "pending"
|
||||
|
||||
|
||||
def _run_task(
|
||||
*,
|
||||
trace_id: str,
|
||||
@@ -406,6 +418,10 @@ def _run_task(
|
||||
# plain tool error rather than a failed trace on disk.
|
||||
verification_level, explorer_mode = _normalize_pro_tuning(verification_level, explorer_mode)
|
||||
|
||||
execution_target = (runtime_overrides or {}).get("execution_target", "android")
|
||||
if execution_target == "computer":
|
||||
device_serial = "computer:local"
|
||||
|
||||
# 2. Initialize the trace store directory and status.json
|
||||
trace_store.init_trace(
|
||||
trace_id=trace_id,
|
||||
@@ -419,7 +435,6 @@ def _run_task(
|
||||
# authorized. Rejecting here prevents the task from silently running on a
|
||||
# different device than the caller asked for. Runs after init_trace so the
|
||||
# rejection carries a trace_id like every other response of this tool.
|
||||
execution_target = (runtime_overrides or {}).get("execution_target", "android")
|
||||
if device_serial and execution_target != "computer":
|
||||
rejection = _validate_device_serial(device_serial)
|
||||
if rejection:
|
||||
@@ -431,6 +446,8 @@ def _run_task(
|
||||
try:
|
||||
is_running, base_url = ensure_daemon_running(timeout=2.0, wait_ready=True)
|
||||
if is_running:
|
||||
# Set admission state before dispatch; after this the daemon owns it.
|
||||
trace_store.update_trace_status(trace_id, "pending", device_serial=device_serial)
|
||||
resp = submit_task_to_daemon(
|
||||
goal=task_desc,
|
||||
profile=canonical_model.lower(),
|
||||
@@ -460,16 +477,14 @@ def _run_task(
|
||||
"message": f"Task rejected by Artemis Daemon: {rejection_error}",
|
||||
}
|
||||
if resp and resp.get("tasks"):
|
||||
assigned_sid = resp["tasks"][0].get("session_id", trace_id)
|
||||
trace_store.update_trace_status(
|
||||
assigned_sid, "running", device_serial=device_serial
|
||||
)
|
||||
task = resp["tasks"][0]
|
||||
assigned_sid = task.get("session_id", trace_id)
|
||||
notes_dir = str(trace_store.get_trace_notes_dir(assigned_sid))
|
||||
stdout_log = str(trace_store.get_trace_stdout_log_path(assigned_sid))
|
||||
stderr_log = str(trace_store.get_trace_stderr_log_path(assigned_sid))
|
||||
return {
|
||||
"trace_id": assigned_sid,
|
||||
"status": "running",
|
||||
"status": _daemon_task_status(assigned_sid, task),
|
||||
"message": (
|
||||
f"Autonomous task '{task_desc}' enqueued via unified Artemis Daemon.\n"
|
||||
f"Trace ID: {assigned_sid}\n"
|
||||
@@ -501,12 +516,9 @@ def _run_task(
|
||||
break
|
||||
for q in queued_tasks:
|
||||
if str(q.get("session_id")) == str(trace_id):
|
||||
trace_store.update_trace_status(
|
||||
trace_id, "running", device_serial=device_serial
|
||||
)
|
||||
return {
|
||||
"trace_id": trace_id,
|
||||
"status": "running",
|
||||
"status": _daemon_task_status(trace_id, q),
|
||||
"message": (
|
||||
f"Autonomous task '{task_desc}' enqueued via unified Artemis Daemon.\n"
|
||||
f"Trace ID: {trace_id}\n"
|
||||
|
||||
Reference in new issue
Block a user