feat: add favorite task templates and optimize evidence exports
This commit is contained in:
1 parent
e1ea099592
commit
a4a5430922
46 files changed
+1714
-188
No files matched your search
@@ -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[
|
||||
|
||||
Reference in new issue
Block a user