80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
"""Deterministic orchestration helpers for v0.20."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from datetime import datetime, timezone
|
|
from pathlib import Path
|
|
|
|
from scripts.runtime.artifacts import ensure_phase_dirs, load_manifest, write_manifest
|
|
from scripts.runtime.methods import ResearchMethodRegistry
|
|
from scripts.runtime.tasks import generate_task_cards, write_task_cards
|
|
|
|
|
|
def utc_now_iso() -> str:
|
|
return datetime.now(timezone.utc).replace(microsecond=0).isoformat()
|
|
|
|
|
|
def create_phase2_task_cards(
|
|
project_root: Path,
|
|
*,
|
|
axes: list[str] | None = None,
|
|
dry_run: bool = False,
|
|
) -> list[dict[str, object]]:
|
|
framework = project_root / "phase1" / "framework.md"
|
|
if not framework.exists():
|
|
raise FileNotFoundError(f"framework not found: {framework}")
|
|
method_key = None
|
|
if (project_root / "manifest.json").exists():
|
|
method_key = load_manifest(project_root).get("research_method")
|
|
method = ResearchMethodRegistry().get(method_key)
|
|
cards = generate_task_cards(project_root.name, framework.read_text(encoding="utf-8"), axes=axes, method=method)
|
|
if not dry_run:
|
|
ensure_phase_dirs(project_root)
|
|
write_task_cards(project_root / "phase2" / "task_cards.json", cards)
|
|
manifest = load_manifest(project_root)
|
|
phase2 = manifest.setdefault("phase2", {})
|
|
phase2.update(
|
|
{
|
|
"status": "in_progress",
|
|
"runtime": "python-core-v0.20",
|
|
"research_method": method.key,
|
|
"task_cards_path": "phase2/task_cards.json",
|
|
"task_cards_total": len(cards),
|
|
"updated_at": utc_now_iso(),
|
|
}
|
|
)
|
|
write_manifest(project_root, manifest)
|
|
return [card.to_dict() for card in cards]
|
|
|
|
|
|
def write_placeholder_packets(
|
|
project_root: Path,
|
|
task_cards: list[dict[str, object]],
|
|
*,
|
|
dry_run: bool = False,
|
|
) -> int:
|
|
"""Create packet skeletons for manual/API completion.
|
|
|
|
This keeps the first v0.20 implementation deterministic and resumable; LLM
|
|
calls can later fill the same schema without changing downstream readers.
|
|
"""
|
|
count = 0
|
|
for card in task_cards:
|
|
packet_path = project_root / str(card["output_packet"])
|
|
packet = {
|
|
"task_id": card["task_id"],
|
|
"claims": [],
|
|
"evidence_items": [],
|
|
"counter_evidence": [],
|
|
"source_ids": [],
|
|
"source_quality_notes": [],
|
|
"open_questions": ["待由 Python role worker 调用模型补全。"],
|
|
"raw_quotes_or_notes": [],
|
|
}
|
|
if not dry_run:
|
|
packet_path.parent.mkdir(parents=True, exist_ok=True)
|
|
packet_path.write_text(json.dumps(packet, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|
|
count += 1
|
|
return count
|