Files
Artemis-Eapil/artemis/agents/checker/flash.py
T
chenmingxuan 83bcfd54d5 feat: release 2.1.0 with optional Flash final AI review
Default Flash final review to off and persist the setting across the UI,
MCP, SDK and queued tasks. Keep execution separate from test verdicts.

Bundle UI fonts and licenses to remove Google Fonts from startup builds.
Align backend/frontend versions and document installation and upgrades.
2026-10-23 12:36:56 +08:00

149 lines
5.8 KiB
Python

"""Flash's exit-only acceptance check uses the same read-only Checker as Pro."""
from pathlib import Path
from artemis.agents.checker.checker import run_final_check
from artemis.context import ArtemisContext
from artemis.llm.diagnostics import final_review_error_text
from artemis.graph.checkpoints import (
RunOutcome,
TestSummary,
final_check_enabled,
publish_checker_event,
verdict_payloads,
write_run_outcome,
)
from artemis.runtime.case_result import CaseTestResult, resolve_case_result
from artemis.services.llm import final_review_budget
from artemis.utils.logger import get_logger
from artemis.utils.notes import save_verified_note
logger = get_logger(__name__)
async def settle_flash_outcome(
ctx: ArtemisContext,
goal: str,
execution_report: dict,
*,
final_report_received: bool = False,
) -> dict:
"""Check once at exit, without operating the device or rerunning the task."""
stop_capture = getattr(ctx, "on_execution_review", None)
if stop_capture:
await stop_capture()
status = str(execution_report.get("status") or "failed")
result = None
delivery = None
report_review = None
if status == "completed" or final_report_received:
body = execution_report.get("explanation")
directory = getattr(getattr(ctx, "data_engine", None), "base_dir", None)
if isinstance(body, str) and body.strip() and isinstance(directory, (str, Path)):
try:
receipt = save_verified_note(directory, "output", body)
delivery = {
**receipt,
"report_path": receipt["path"],
"allow_report_corrections": True,
}
except (OSError, ValueError) as exc:
logger.warning(f"Flash 最终答复保存失败:{exc}")
delivery = {"ok": False, "verified": False, "error": str(exc)}
if final_check_enabled(ctx):
publish_checker_event(
ctx,
{
"event": "attempt_started",
"phase": "final",
"attempt_id": "final#1",
"checkpoint_id": "final",
"check_items": [],
"status": "running",
},
)
try:
report = await final_review_budget(ctx, attempt_id="final#1").run(
lambda: run_final_check(
ctx,
goal=goal,
plan_text="",
ledger=[],
check_items=[],
attempt_id="final#1",
execution_report=execution_report,
report_delivery=delivery,
),
)
result = report.test_result
if report.report_corrections and directory:
from artemis.agents.checker.report_review import apply_report_review
try:
report_review = apply_report_review(
directory, execution_report, report.report_corrections
)
except (OSError, ValueError) as exc:
report_review = {"applied": False, "reason": str(exc)}
logger.warning(f"报告复核修改未保存:{exc}")
publish_checker_event(
ctx,
{
"event": "attempt_finished",
"phase": "final",
"attempt_id": "final#1",
"checkpoint_id": "final",
"status": "done",
"verdicts": verdict_payloads(report.verdicts),
"test_result": result.model_dump() if result else None,
"route": "end",
},
)
except Exception as exc:
detail = final_review_error_text(exc)
logger.warning(f"Flash 测试验收未完成:{detail}")
result = CaseTestResult(
status="inconclusive", reason=f"操作已结束,但测试验收未完成:{detail}。"
)
publish_checker_event(
ctx,
{
"event": "attempt_finished",
"phase": "final",
"attempt_id": "final#1",
"checkpoint_id": "final",
"status": "error",
"error": result.reason,
"route": "end",
},
)
else:
result = CaseTestResult(
status="inconclusive",
reason="执行完成 · 未做 AI 判定。已关闭 Flash 最终 AI 分析与判定,执行记录和报告仍保留。",
verification_skipped=True,
)
outcome = RunOutcome(
task_status="completed" if status == "completed" else "blocked", tests=TestSummary()
)
payload = outcome.model_dump()
if report_review:
payload["report_review"] = report_review
if result:
payload["test_result"] = result.model_dump()
resolved = resolve_case_result(payload, status, str(execution_report.get("explanation") or ""))
payload["test_result"] = resolved.model_dump() if resolved else None
if ctx.data_engine:
write_run_outcome(
ctx.data_engine.base_dir,
outcome,
{
"test_result": payload["test_result"],
**({"report_review": report_review} if report_review else {}),
},
)
publish_checker_event(ctx, {"event": "run_outcome", "phase": "outcome", **payload})
ctx.run_outcome = payload
return payload