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
@@ -100,3 +100,5 @@ Run `uv run artemis mcp --generate-config codex` to output a configuration templ
|
||||
## 完整 AI 自动化
|
||||
|
||||
工作区工具与网页共用后台服务,覆盖普通与探索任务、批次、历史、诊断、人工复验及报告导出。参见 [接入说明](../docs/ai-automation.md) 和 [Skill](../skills/artemis-use/SKILL.md)。网页启动时同步官方 Skill 与 MCP 接入;已有审批策略及工具白名单保留。更新后重新加载 MCP 才能使用新版工具定义。
|
||||
|
||||
* **`mobile_favorites`**: Save independent task/case/batch templates, list or rename favorites, adjust their defaults, and start a new run with original settings. Per-run overrides are temporary; run retries use the same request_id. Source deletion does not delete favorites. See the [batch and favorite workflow](../skills/artemis-use/references/batches.md).
|
||||
@@ -501,6 +501,102 @@
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mobile_favorites",
|
||||
"description": "Save independent favorite templates and run them on the existing queue.\n\nlist is read-only. create snapshots source_id (task session/batch/exploration),\nincluding original execution settings; exploration_case pins a case version.\nAn exploration task automatically favorites its confirmed case when available.\nchanges accepts name, task_config (TaskOptions), case_configs (zero-based case\nindices to TaskOptions). No credentials or arbitrary snapshot input is accepted.\nupdate saves defaults; run applies changes to this execution only and requires\na stable request_id. After an uncertain reply retry the same payload and ID.\nrun creates a new execution, never continues the source or copies its verdict.\nBatch order/repetitions and per-case settings are preserved. Missing historical\nsettings are explicitly marked inherited_fields. Offline devices are not replaced.\ndelete removes only the favorite, never the source history or previous runs.\n",
|
||||
"inputSchema": {
|
||||
"properties": {
|
||||
"action": {
|
||||
"enum": [
|
||||
"list",
|
||||
"create",
|
||||
"update",
|
||||
"delete",
|
||||
"run"
|
||||
],
|
||||
"title": "Action",
|
||||
"type": "string"
|
||||
},
|
||||
"favorite_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Favorite Id"
|
||||
},
|
||||
"source_kind": {
|
||||
"default": "task",
|
||||
"enum": [
|
||||
"task",
|
||||
"batch",
|
||||
"exploration",
|
||||
"exploration_case"
|
||||
],
|
||||
"title": "Source Kind",
|
||||
"type": "string"
|
||||
},
|
||||
"source_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Source Id"
|
||||
},
|
||||
"version": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "integer"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Version"
|
||||
},
|
||||
"request_id": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Request Id"
|
||||
},
|
||||
"changes": {
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": true,
|
||||
"type": "object"
|
||||
},
|
||||
{
|
||||
"type": "null"
|
||||
}
|
||||
],
|
||||
"default": null,
|
||||
"title": "Changes"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"action"
|
||||
],
|
||||
"title": "mobile_favoritesArguments",
|
||||
"type": "object"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "mobile_batch",
|
||||
"description": "Create, execute and manage durable batches on the unified device queue.\n\ncreate requires a unique request_id and batch={name,device_serial,cases:[{name,goal,\ncase_id?,category?,subcategory?,preconditions?,task_config?:{profile?,model?,\nreasoning_effort?,device_serial?,verification_level?,explorer_mode?,\nlocked_app_package?,record_video?,analyze_video?,request_timeout_seconds?,\nmax_retries?,retry_interval_seconds?,timeout_seconds?}}],profile?:flash|pro,\nformats?:[docx,xlsx],stop_on_failure?:false,timeout_seconds?:1800,repeat_count?:1}.\nrepeat_count is a positive integer: execute all selected cases in order for each\nround, with independent session IDs, statuses and reports. The default total limit\n(cases * repeat_count) is 10000, configurable via ARTEMIS_BATCH_MAX_EXECUTIONS.\nOnly include user-selected cases; get returns iteration/repeat_count per job.\nRequired device\nmust be user-selected. Creation validates and saves a DRAFT; start executes it.\nReuse the same request_id and exact payload after a connection failure; never invent\na new ID for the same submission. lookup(request_id) resolves an uncertain outcome.\nget returns per-case status. pause stops future dispatch, not the active task;\nuse mobile_manage_task(stop) to stop that task. resume never repeats finished cases.\nretry_failed copies each failed execution once into a new draft (repeat_count=1)\nonly after an explicit rerun request; it is not\ntransport-idempotent, so after an uncertain response use list instead of retrying.\ndelete removes a non-active batch and its task sessions, reports and files after\nan explicit user request. Confirm the batch ID with get first; deletion is irreversible.\nRestarted batches remain paused. No automatic failed-case retries or action replay.\n",
|
||||
|
||||
@@ -33,6 +33,7 @@ __all__ = [
|
||||
"mobile_batch",
|
||||
"mobile_search_history",
|
||||
"mobile_export_report",
|
||||
"mobile_favorites",
|
||||
"mobile_exploration",
|
||||
]
|
||||
|
||||
@@ -43,4 +44,5 @@ from mcp_server.tools.automation import (
|
||||
mobile_batch,
|
||||
mobile_search_history,
|
||||
mobile_export_report,
|
||||
mobile_favorites,
|
||||
)
|
||||
@@ -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