Files
tracer-cloud--opensre/tests/benchmarks/cloudopsbench/analyze_floor_sweep.py
T
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

140 lines
4.6 KiB
Python

"""Summarize a MIN_TOOL_CALLS floor sweep into one floor-vs-metric table.
Run after sweeping ``cloudopsbench_floorsweep_openai.yml`` over several
``BENCH_MIN_TOOL_CALLS`` values. Each run wrote a timestamped subdir under the
config's ``output_dir`` with a ``provenance.json`` (the floor lives at
``run_inputs.min_tool_calls``) and a ``cases/`` dir of per-case scores.
The question this answers: does lowering the floor lift the process metrics
opensre is weak on (rel/exact) and cut over-exploration (steps), WITHOUT
dropping the outcome metric (a1)? Each cell is a scenario-clustered mean (seeds
within a scenario averaged first), matching the report's headline statistic.
Usage:
python -m tests.benchmarks.cloudopsbench.analyze_floor_sweep \
.bench-results/cloudopsbench_floorsweep_openai/
Add ``--paper gpt-4o`` to print the paper Table-4 Base row alongside as the
reference target.
"""
from __future__ import annotations
import argparse
import json
import sys
from pathlib import Path
from tests.benchmarks._framework.reporting import (
_PAPER_BASELINE,
_load_cells,
_scenario_means,
)
# Process + outcome metrics the sweep is meant to move. a1 is the guardrail
# (must not drop); rel/exact/steps/cov are the over-exploration signal.
_SWEEP_METRICS = [
"a1",
"a3",
"exact",
"in_order",
"any_order",
"rel",
"cov",
"steps",
"iac",
"mtti",
]
def _floor_for_run(run_dir: Path) -> int | None:
"""Read the resolved MIN_TOOL_CALLS floor from a run's provenance.json."""
prov_path = run_dir / "provenance.json"
if not prov_path.exists():
return None
try:
prov = json.loads(prov_path.read_text(encoding="utf-8"))
except json.JSONDecodeError:
return None
value = prov.get("run_inputs", {}).get("min_tool_calls")
return value if isinstance(value, int) else None
def _run_dirs(sweep_dir: Path) -> list[Path]:
"""Every immediate subdir that looks like a completed run."""
return sorted(d for d in sweep_dir.iterdir() if d.is_dir() and (d / "cases").is_dir())
def _mean(values: list[float]) -> float | None:
return sum(values) / len(values) if values else None
def _fmt(value: float | None) -> str:
return f"{value:.3f}" if value is not None else " - "
def main(argv: list[str] | None = None) -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("sweep_dir", help="Directory holding the per-floor run subdirs.")
parser.add_argument(
"--paper",
default=None,
help="LLM key (e.g. gpt-4o) to print the paper Table-4 Base row as a target.",
)
args = parser.parse_args(argv)
sweep_dir = Path(args.sweep_dir)
if not sweep_dir.is_dir():
print(f" x {sweep_dir} is not a directory", file=sys.stderr)
return 1
rows: list[tuple[int | None, str, dict[str, float | None], int]] = []
for run_dir in _run_dirs(sweep_dir):
cells = _load_cells(run_dir / "cases")
if not cells:
continue
floor = _floor_for_run(run_dir)
means = {m: _mean(_scenario_means(cells, m)) for m in _SWEEP_METRICS}
n_scen = len({c.get("case", {}).get("case_id") for c in cells if "_load_error" not in c})
rows.append((floor, run_dir.name, means, n_scen))
if not rows:
print(f" x no completed runs found under {sweep_dir}", file=sys.stderr)
return 1
rows.sort(key=lambda r: (r[0] is None, r[0]))
header = ["floor", "n", *_SWEEP_METRICS]
widths = [max(7, len(h)) for h in header]
print(" ".join(h.ljust(w) for h, w in zip(header, widths, strict=True)))
print(" ".join("-" * w for w in widths))
for floor, _name, means, n_scen in rows:
cells_str = [
(str(floor) if floor is not None else "?"),
str(n_scen),
*[_fmt(means[m]) for m in _SWEEP_METRICS],
]
print(" ".join(c.ljust(w) for c, w in zip(cells_str, widths, strict=True)))
if args.paper:
paper = _PAPER_BASELINE.get(args.paper.strip().lower())
if paper:
cells_str = [
"paper",
"452",
*[_fmt(paper.get(m)) for m in _SWEEP_METRICS],
]
print(" ".join(c.ljust(w) for c, w in zip(cells_str, widths, strict=True)))
else:
print(f" (no paper Base row for {args.paper!r})", file=sys.stderr)
print()
print("Read: a1 is the guardrail (must NOT drop as floor falls); rel/exact up")
print("and steps down = less over-exploration. Pick the lowest floor that holds a1.")
return 0
if __name__ == "__main__":
sys.exit(main())