Initial commit
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
"""可恢复运行的原子清单持久化。"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from scripts.dynamic_compile.fast.storage import atomic_write_json
|
||||
|
||||
|
||||
def read_json_object(path: Path) -> dict[str, Any] | None:
|
||||
try:
|
||||
value = json.loads(path.read_text(encoding="utf-8"))
|
||||
except (OSError, json.JSONDecodeError):
|
||||
return None
|
||||
return value if isinstance(value, dict) else None
|
||||
|
||||
|
||||
class RunManifest:
|
||||
def __init__(
|
||||
self,
|
||||
path: Path,
|
||||
*,
|
||||
harness: str,
|
||||
model: str,
|
||||
external_model: str,
|
||||
task_dir: Path,
|
||||
):
|
||||
self.path = path
|
||||
inputs = {
|
||||
"harness": harness,
|
||||
"model": model,
|
||||
"external_model": external_model,
|
||||
"task": str(task_dir),
|
||||
}
|
||||
if path.is_file():
|
||||
existing = read_json_object(path)
|
||||
if existing is None:
|
||||
raise ValueError(f"invalid run manifest: {path}")
|
||||
if existing.get("schema_version") != "1.0":
|
||||
raise ValueError(f"unsupported run manifest schema: {path}")
|
||||
if existing.get("inputs") != inputs:
|
||||
raise ValueError(
|
||||
f"run directory belongs to different pipeline inputs: {path.parent}"
|
||||
)
|
||||
stages = existing.get("stages")
|
||||
if not isinstance(stages, dict):
|
||||
raise ValueError(f"invalid stages in run manifest: {path}")
|
||||
self.value = existing
|
||||
self.value["status"] = "running"
|
||||
self.value.pop("error", None)
|
||||
self.save()
|
||||
return
|
||||
self.value: dict[str, Any] = {
|
||||
"schema_version": "1.0",
|
||||
"status": "running",
|
||||
"inputs": inputs,
|
||||
"stages": {},
|
||||
}
|
||||
self.save()
|
||||
|
||||
def save(self) -> None:
|
||||
atomic_write_json(self.path, self.value)
|
||||
|
||||
def stage(self, name: str, status: str, **details: Any) -> None:
|
||||
self.value["stages"][name] = {"status": status, **details}
|
||||
self.save()
|
||||
|
||||
def complete(self, final_skill: Path) -> None:
|
||||
self.value["status"] = "complete"
|
||||
self.value["final_skill"] = str(final_skill)
|
||||
self.save()
|
||||
|
||||
def fail(self, error: Exception) -> None:
|
||||
self.value["status"] = "failed"
|
||||
self.value["error"] = f"{type(error).__name__}: {error}"
|
||||
self.save()
|
||||
Reference in New Issue
Block a user