Files
2026-09-04 14:58:42 +08:00

196 lines
7.6 KiB
Python

"""完整静态、Fast 与 Deep 技能编译流水线。"""
from __future__ import annotations
from pathlib import Path
import shutil
import sys
from typing import Any
from scripts.dynamic_compile.deep.pipeline import DeepLoop
from scripts.dynamic_compile.fast.pipeline import run_pipeline as run_fast_pipeline
from scripts.static_compile.compiler.compiler import compile_input
from scripts.static_compile.profile_generation.pipeline import ensure_profile
from .evaluation import (
MAX_PARALLEL,
complete_deep_skill,
deep_final_rollouts,
evaluate,
)
from .manifest import RunManifest, read_json_object
from .paths import requested_run_root, single_skill_source, task_directory
ORIGINAL_ROLLOUTS = 6
STATIC_ROLLOUTS = 6
FAST_ROLLOUTS = 3
FINAL_ROLLOUTS = 3
def _complete_static_skill(output: Path) -> tuple[Path, str] | None:
complete: list[tuple[Path, str]] = []
if not output.is_dir():
return None
for report_path in output.rglob("rewrite-report.json"):
skill = report_path.parent
report = read_json_object(report_path)
if report is None or not (skill / "SKILL.md").is_file():
continue
status = str(report.get("status", "failed"))
if status not in {"failed", "rolled_back"}:
complete.append((skill, status))
return complete[0] if len(complete) == 1 else None
def run_pipeline(
*,
harness: str,
model: str,
external_model: str,
task: str,
run_dir: str | Path | None = None,
) -> Path:
task_dir = task_directory(task)
source_skills = single_skill_source(task_dir)
task_name = task_dir.name
run_root = requested_run_root(run_dir)
if (
run_root.is_dir()
and any(run_root.iterdir())
and not (run_root / "manifest.json").is_file()
):
raise ValueError(
f"non-empty run directory has no manifest and cannot be resumed: {run_root}"
)
run_root.mkdir(parents=True, exist_ok=True)
manifest = RunManifest(
run_root / "manifest.json",
harness=harness,
model=model,
external_model=external_model,
task_dir=task_dir,
)
artifacts = run_root / "artifacts"
trace_task_root = run_root / "traces" / task_name
original_traces = trace_task_root / "ori_skill"
static_root = artifacts / "static"
static_traces = trace_task_root / "model_skill"
fast_score = artifacts / "fast" / "score"
fast_output = artifacts / "fast" / "optimization"
fast_traces = trace_task_root / "fast_skill"
deep_output = artifacts / "deep"
final_traces = trace_task_root / "final_skill"
print(f"[compile-pipeline] run directory: {run_root}", file=sys.stderr, flush=True)
try:
manifest.stage("original_evaluation", "running", output=str(original_traces))
evaluate(
harness=harness, model=model, task_dir=task_dir, skill_source=source_skills,
output=original_traces, repeat=ORIGINAL_ROLLOUTS,
)
manifest.stage(
"original_evaluation", "complete", output=str(original_traces),
rollouts=ORIGINAL_ROLLOUTS, max_parallel=MAX_PARALLEL,
)
manifest.stage("profile", "running")
profile_path, generated = ensure_profile(model)
manifest.stage("profile", "complete", path=str(profile_path), generated=generated)
cached_static = _complete_static_skill(static_root)
if cached_static is not None:
static_skill, static_status = cached_static
print(
f"[compile-pipeline] static compilation complete: {static_skill}; skipping",
file=sys.stderr, flush=True,
)
else:
manifest.stage("static_compile", "running")
static_results = compile_input(
source_skills, profile_path, static_root, mode="hybrid",
annotator_model=external_model, force=static_root.exists(),
)
if len(static_results) != 1 or static_results[0].output_dir is None:
raise RuntimeError("static compilation did not produce exactly one Skill package")
static_status = str(static_results[0].report.get("status", "failed"))
if static_status in {"failed", "rolled_back"}:
raise RuntimeError(f"static compilation ended with status {static_status}")
static_skill = static_results[0].output_dir
manifest.stage(
"static_compile", "complete", skill=str(static_skill), compile_status=static_status,
)
manifest.stage("static_evaluation", "running", output=str(static_traces))
evaluate(
harness=harness, model=model, task_dir=task_dir, skill_source=static_skill,
output=static_traces, repeat=STATIC_ROLLOUTS,
)
manifest.stage(
"static_evaluation", "complete", output=str(static_traces),
rollouts=STATIC_ROLLOUTS, max_parallel=MAX_PARALLEL,
)
manifest.stage("fast_compile", "running")
fast_skill = run_fast_pipeline(
static_traces, static_skill, score_output=fast_score, output=fast_output,
model=external_model, max_parallel=MAX_PARALLEL,
)
manifest.stage("fast_compile", "complete", skill=str(fast_skill))
manifest.stage("fast_evaluation", "running", output=str(fast_traces))
evaluate(
harness=harness, model=model, task_dir=task_dir, skill_source=fast_skill,
output=fast_traces, repeat=FAST_ROLLOUTS,
)
manifest.stage(
"fast_evaluation", "complete", output=str(fast_traces),
rollouts=FAST_ROLLOUTS, max_parallel=MAX_PARALLEL,
)
final_skill = complete_deep_skill(deep_output)
if final_skill is not None:
print(
f"[compile-pipeline] deep compilation complete: {final_skill}; skipping",
file=sys.stderr, flush=True,
)
else:
manifest.stage("deep_compile", "running", output=str(deep_output))
deep_loop = (
DeepLoop(deep_output)
if (deep_output / "run.json").is_file()
else DeepLoop.create(fast_skill, fast_traces, deep_output, model=external_model)
)
final_skill = deep_loop.drive()
if complete_deep_skill(deep_output) is None:
raise RuntimeError(
f"deep compilation did not produce complete artifacts under {deep_output}"
)
manifest.stage("deep_compile", "complete", skill=str(final_skill))
reusable_rollouts = deep_final_rollouts(
deep_output, final_skill, FINAL_ROLLOUTS,
)
if reusable_rollouts is not None:
print(
f"[compile-pipeline] copying Deep final rollouts to: {final_traces}",
file=sys.stderr, flush=True,
)
shutil.copytree(reusable_rollouts, final_traces, dirs_exist_ok=True)
final_evaluation_output = final_traces
manifest.stage("final_evaluation", "running", output=str(final_evaluation_output))
evaluate(
harness=harness, model=model, task_dir=task_dir, skill_source=final_skill,
output=final_evaluation_output, repeat=FINAL_ROLLOUTS,
)
manifest.stage(
"final_evaluation", "complete", output=str(final_evaluation_output),
rollouts=FINAL_ROLLOUTS, max_parallel=MAX_PARALLEL,
reused_deep_rollouts=reusable_rollouts is not None,
)
manifest.complete(final_skill)
return final_skill
except Exception as exc:
manifest.fail(exc)
raise