feat: prepare 2.2.0 with UI and execution fixes

Add dark theme, richer Markdown and readable plugin results.
Improve Android input evidence, response integrity and diagnostics.
Unify lifecycle, guidance receipts and evidence sources across clients.
Keep direct action dispatch without an added AI quota approval layer.
Align version metadata at 2.2.0 and bundle Helper 1.2.2.

Validation: 3063 backend tests before the version bump; 44 after.
Frontend: 317 tests and production build passed.
This commit is contained in:
chenmingxuan committed 2026-10-26 00:44:13 +08:00
1 parent 83bcfd54d5
commit fac4ccb760
146 files changed
+5689 -2033

No files matched your search

+88 -1
View File
@@ -14,6 +14,7 @@ from apps.admin_console.services.export_cache import (
reusable,
)
from apps.admin_console.services.request_diagnostics import diagnostics_json
from apps.admin_console.services.task_lifecycle import guidance_details
from docx import Document
from docx.enum.table import WD_CELL_VERTICAL_ALIGNMENT
@@ -166,6 +167,7 @@ def failure_reason(directory: Path, status: str, recorded: str | None) -> str:
def session_report(session_id: str, db_path=None) -> dict:
from apps.admin_console.services.exploration_evidence import exploration_metadata
from artemis.data_engine.evidence_sources import recorded_sources
identifier(session_id)
meta = store.job(session_id) or {}
@@ -213,6 +215,7 @@ def session_report(session_id: str, db_path=None) -> dict:
)
return {
"id": session_id,
**guidance_details(session_id, db_path=repo.db_path),
"exploration": exploration_metadata(session_id),
"name": execution_title(meta) or session.get("initial_goal", session_id)[:120],
"iteration": meta.get("iteration", 1),
@@ -225,6 +228,7 @@ def session_report(session_id: str, db_path=None) -> dict:
"outcome": outcome,
"content": content,
"steps": steps,
"evidence_sources": recorded_sources(steps),
"start": session.get("start_time") or meta.get("started_at"),
"end": session.get("end_time") or meta.get("ended_at"),
"error": error,
@@ -246,6 +250,74 @@ def time_text(value) -> str:
)
def lifecycle_text(value: dict) -> str:
labels = {
"total": "总历时",
"queued": "后台排队",
"resource_wait": "等待设备/资源",
"paused": "暂停与示范",
"execution": "执行与整理",
"final_review": "最终验收",
"report_export": "报告导出",
}
durations = value.get("durations") or {}
return (
"\n".join(
f"{label}:{round(durations[key], 1)} 秒"
if durations.get(key) is not None
else f"{label}:未记录"
for key, label in labels.items()
)
+ "\n执行含初始化与报告整理,不代表模型速度。"
)
def guidance_text(items: list[dict]) -> str:
labels = {
"pending": "已接收,等待读取",
"reading": "执行器正在读取",
"consumed": "执行器已读取",
"unapplied": "任务结束,未记录消费",
"unconfirmed": "任务结束,读取未确认",
}
return (
"\n".join(
f"{item['id']} · {labels.get(item['status'], '状态未知')} · 接收 {time_text(item.get('accepted_at') or item.get('timestamp'))}"
+ (f" · 读取 {time_text(item['consumed_at'])}" if item.get("consumed_at") else "")
for item in items
)
or "无指导记录"
)
def source_text(value: dict) -> str:
labels = {
"android": "安卓界面",
"computer": "电脑界面",
"api": "接口数据",
"terminal": "终端",
"file": "文件",
"other": "其他",
}
lines = []
for item in value.get("sources", []):
references = ", ".join(
" / ".join(
f"{key}={ref[key]}" for key in ("step_id", "call_id", "source_id") if ref.get(key)
)
or "编号未记录"
for ref in item.get("references", [])
)
lines.append(
f"{labels.get(item['kind'], '其他')} · {item['label'] or item['target_id']} · {references}"
)
if value.get("sources_omitted"):
lines.append(f"另 {value['sources_omitted']} 个来源见原始步骤记录。")
lines.append(f"来源未完整记录的步骤:{value.get('unattributed_step_count', '未知')}。")
lines.append(value.get("note") or "来源清单不代表断言已验证。")
return "\n".join(lines)
def metadata(report: dict) -> list[tuple]:
return [
("任务编号", report["id"]),
@@ -272,6 +344,9 @@ def metadata(report: dict) -> list[tuple]:
("任务目标", report["goal"]),
("预期结果", report["expected"] or "未指定"),
("执行状态", STATUS.get(report["status"], report["status"])),
("耗时分项", lifecycle_text(report.get("lifecycle") or {})),
("指导消费", guidance_text(report.get("instructions") or [])),
("证据来源与边界", source_text(report.get("evidence_sources") or {})),
("验证结论", report["verdict"]),
("人工复验时间", time_text((report.get("test_result") or {}).get("reviewed_at"))),
(
@@ -558,7 +633,19 @@ def word_report(report: dict, path: Path):
details = [
(label, value)
for label, value in metadata(report)
if label in {"任务编号", "用例编号", "检测项目", "测试子项", "开始时间", "结束时间", "设备"}
if label
in {
"任务编号",
"用例编号",
"检测项目",
"测试子项",
"开始时间",
"结束时间",
"设备",
"耗时分项",
"指导消费",
"证据来源与边界",
}
]
word_table(doc, details, (3.2, 13.3))
doc.add_heading("任务目标与预期" if not report["expected"] else "任务目标", 2)