Log in
scripts/agent_campaign.py 61 lines · 3.1 KB · blame Source
e9b767a51662 Preserve measured agent failures and validate ca 9 days ago
1
#!/usr/bin/env python3
2
"""Plan, execute and resume bounded local coding-agent campaigns."""
3
from __future__ import annotations
4
5
import argparse
6
import json
7
from pathlib import Path
8
import sys
9
10
from oakbench.agent_campaign import (CampaignError, create_plan, load_plan, load_events,
11
                                    campaign_status, run_campaign)
12
13
14
def main(argv=None) -> int:
15
    parser = argparse.ArgumentParser(description=__doc__)
16
    sub = parser.add_subparsers(dest="command", required=True)
17
    plan = sub.add_parser("plan", help="freeze a manifest, schedule and provenance; invokes no agent task")
18
    plan.add_argument("--manifest", type=Path, required=True)
19
    plan.add_argument("--campaign-dir", type=Path, required=True)
20
    for name in ("run", "resume", "status", "report"):
21
        child = sub.add_parser(name)
22
        child.add_argument("--campaign-dir", type=Path, required=True)
23
        if name in ("run", "resume"):
24
            child.add_argument("--enable-real", action="store_true")
25
            child.add_argument("--limit", type=int, help="maximum new trials this invocation")
26
        if name == "resume":
27
            child.add_argument("--acknowledge-torn-journal", action="store_true", help="archive torn journal, reserve uncertain trial, and resume without retrying it")
28
        if name == "report":
29
            child.add_argument("--format", choices=("json", "markdown"), default="json")
30
    args = parser.parse_args(argv)
31
    try:
32
        if args.command == "plan":
33
            frozen = create_plan(args.manifest, args.campaign_dir)
34
            print(json.dumps({"campaign_id": frozen["campaign_id"], "plan_sha256": frozen["plan_sha256"],
35
                              "scheduled": len(frozen["schedule"]), "plan": str(args.campaign_dir / "plan.json")}, indent=2))
36
            return 0
37
        if args.command in ("run", "resume"):
38
            state = run_campaign(args.campaign_dir, resume=args.command == "resume", enable_real=args.enable_real, limit=args.limit, acknowledge_torn=getattr(args, "acknowledge_torn_journal", False))
39
        else:
40
            frozen = load_plan(args.campaign_dir)
41
            events = load_events(args.campaign_dir, frozen, tolerate_torn=True)
42
            if args.command == "report":
43
                from oakbench.campaign_report import report_campaign, render_markdown
44
                report = report_campaign(frozen, events)
45
                print(json.dumps(report, indent=2) if args.format == "json" else render_markdown(report))
46
                return 0
47
            state = campaign_status(frozen, events)
48
        print(json.dumps(state, indent=2))
49
        if args.command in ("run", "resume"):
50
            if state["pending_trial_ids"] or state["interrupted_trial_ids"]:
51
                return 3
52
            events = load_events(args.campaign_dir, load_plan(args.campaign_dir))
53
            return 1 if any(event.get("outcome") in {"error", "fail", "timeout"} for event in events) else 0
54
        return 0
55
    except (ValueError, OSError) as exc:
56
        print("campaign error: " + str(exc), file=sys.stderr)
57
        return 2
58
59
60
if __name__ == "__main__":
61
    raise SystemExit(main())