feat: add favorite task templates and optimize evidence exports

This commit is contained in:
chenmingxuan committed 2026-10-18 19:44:51 +08:00
1 parent e1ea099592
commit a4a5430922
46 files changed
+1714 -188

No files matched your search

+67
View File
@@ -268,6 +268,73 @@ async def mobile_task_file(
)
@mcp.tool()
async def mobile_favorites(
action: Literal["list", "create", "update", "delete", "run"],
favorite_id: str | None = None,
source_kind: Literal["task", "batch", "exploration", "exploration_case"] = "task",
source_id: str | None = None,
version: int | None = None,
request_id: str | None = None,
changes: dict[str, Any] | None = None,
) -> Any:
"""Save independent favorite templates and run them on the existing queue.
list is read-only. create snapshots source_id (task session/batch/exploration),
including original execution settings; exploration_case pins a case version.
An exploration task automatically favorites its confirmed case when available.
changes accepts name, task_config (TaskOptions), case_configs (zero-based case
indices to TaskOptions). No credentials or arbitrary snapshot input is accepted.
update saves defaults; run applies changes to this execution only and requires
a stable request_id. After an uncertain reply retry the same payload and ID.
run creates a new execution, never continues the source or copies its verdict.
Batch order/repetitions and per-case settings are preserved. Missing historical
settings are explicitly marked inherited_fields. Offline devices are not replaced.
delete removes only the favorite, never the source history or previous runs.
"""
if action == "list":
return await _request("GET", "/api/automation/favorites")
payload = changes or {}
if set(payload) - {"name", "task_config", "case_configs"}:
raise ValueError("收藏只接受名称和非敏感执行配置")
# The HTTP schema applies the complete TaskOptions allowlist. Refuse secret
# fields before making a network request, including nested case overrides.
def check(value):
if isinstance(value, dict):
for key, child in value.items():
if any(
word in str(key).lower()
for word in ("secret", "password", "api_key", "token", "authorization")
):
raise ValueError("收藏不接受密钥或授权配置")
check(child)
elif isinstance(value, list):
for child in value:
check(child)
check(payload)
if action == "create":
if set(payload) - {"name"}:
raise ValueError("创建收藏从源记录读取配置,修改默认配置请使用 update")
return await _request(
"POST",
"/api/automation/favorites",
json={
"source_kind": source_kind,
"source_id": _id(source_id),
"version": version,
**payload,
},
)
route = f"/api/automation/favorites/{_id(favorite_id)}"
if action == "update":
return await _request("PATCH", route, json=payload)
if action == "delete":
return await _request("DELETE", route)
return await _request("POST", route + "/run", json={**payload, "request_id": _id(request_id)})
@mcp.tool()
async def mobile_batch(
action: Literal[