Files
deep_research/scripts/runtime/orchestrator.py
T

92 lines
3.3 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, generate_task_cards_from_research_brief, 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)
research_brief_path = project_root / "phase1" / "research_brief.json"
framework_text = framework.read_text(encoding="utf-8")
if research_brief_path.exists():
research_brief = json.loads(research_brief_path.read_text(encoding="utf-8"))
cards = generate_task_cards_from_research_brief(
project_root.name,
framework_text,
research_brief,
axes=axes,
method=method,
)
else:
cards = generate_task_cards(project_root.name, framework_text, 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