harness2: upstream gap fill — trivial selection fix, session budget, run_tag validation, preflight check
- select_final trivial condition now k==1 and single-candidate pool, regardless of whether a selector is provided (previously gated on selector is None, so wired runs always paid for a useless selector task at k=1) - Budget gains max_sessions gate (probe + stage-attempt sessions; fmt2 corrections and selector/reflector sessions exempt), the backstop for unpriced models where the USD gate never binds - validate_run_tag (charset, no leading '-', no s<N> seed prefix) enforced at run_improvement_via_tasks and the CLI - CLI --check preflight (base harness, source dir, prompt, tag, control-plane /health probe) without creating tasks - ModeResult.to_dict now includes rollout summaries so a lost probe is visible in full_result instead of only on the server - CLI plan counts the selector only when k>1
This commit is contained in:
1 parent
3d60f32bd3
commit
4ed1479d7a
5 files changed
+247
-26
No files matched your search
@@ -33,7 +33,8 @@ sys.path.insert(0, str(Path(__file__).resolve().parents[1]))
|
||||
|
||||
from cloud.harness2 import read_tree # noqa: E402
|
||||
from cloud.harness2_tasks import ( # noqa: E402
|
||||
HttpTaskClient, run_improvement_via_tasks,
|
||||
HttpTaskClient, preflight_checks, run_improvement_via_tasks,
|
||||
validate_run_tag,
|
||||
)
|
||||
|
||||
|
||||
@@ -60,6 +61,10 @@ def main():
|
||||
ap.add_argument("--mode", default="parallel", choices=["parallel", "sequential"])
|
||||
ap.add_argument("--k", type=int, default=1)
|
||||
ap.add_argument("--budget", type=float, default=None)
|
||||
ap.add_argument("--max-sessions", type=int, default=None,
|
||||
help="会话数上限(探针 + 阶段尝试;unpriced 模型上美元门不触发时的兜底)")
|
||||
ap.add_argument("--check", action="store_true",
|
||||
help="只做建任务前预检(本地目录/提示/tag + 控制面 health 探针),不建任务")
|
||||
ap.add_argument("--run-tag", default="")
|
||||
ap.add_argument("--output", default="")
|
||||
ap.add_argument("--library-root", default="")
|
||||
@@ -73,6 +78,34 @@ def main():
|
||||
ap.add_argument("--yes", action="store_true", help="确认创建真实任务并消费配额")
|
||||
args = ap.parse_args()
|
||||
|
||||
if args.check:
|
||||
prompt = args.prompt
|
||||
if args.prompt_file:
|
||||
try:
|
||||
prompt = Path(args.prompt_file).read_text(encoding="utf-8")
|
||||
except OSError as exc:
|
||||
print(f"FAIL: prompt-file 读不到:{exc}", file=sys.stderr)
|
||||
return 2
|
||||
errors, warnings = preflight_checks(
|
||||
base_harness_dir=args.base_harness_dir,
|
||||
source_dir=args.source_dir or None, prompt=prompt,
|
||||
run_tag=args.run_tag, base_url=args.base_url)
|
||||
for e in errors:
|
||||
print(f"FAIL: {e}", file=sys.stderr)
|
||||
for w in warnings:
|
||||
print(f"WARN: {w}")
|
||||
if not os.environ.get("CODEX_API_KEY"):
|
||||
print("WARN: 未设置 CODEX_API_KEY(建任务时需要)")
|
||||
if errors:
|
||||
return 2
|
||||
print("preflight: 通过" + ("(有告警)" if warnings else ""))
|
||||
return 0
|
||||
|
||||
try:
|
||||
validate_run_tag(args.run_tag)
|
||||
except ValueError as exc:
|
||||
print(f"run-tag 非法:{exc}", file=sys.stderr)
|
||||
return 2
|
||||
api_key = os.environ.get("CODEX_API_KEY")
|
||||
if not api_key:
|
||||
print("缺少 CODEX_API_KEY 环境变量(密钥不接受命令行参数)", file=sys.stderr)
|
||||
@@ -90,15 +123,18 @@ def main():
|
||||
return 2
|
||||
run_tag = args.run_tag or time.strftime("h2-%Y%m%d-%H%M%S")
|
||||
# 任务数(k=1 parallel):1 base + 2 候选 + 1 终版探针 + 3 编辑
|
||||
# + 1 选择 + 1 反思 = 9;sequential 同为 9;k 越大按 3k+? 线性涨,
|
||||
# 上限 k=3 时 parallel 为 1 + 6 + 3 探针 + 9 编辑 + 1 选择 + 1 反思 = 21。
|
||||
# + 1 反思 = 8(k=1 时选择 trivial,不建选择任务);sequential
|
||||
# 同为 8;k 越大线性涨,上限 k=3 时 parallel 为 1 + 6 + 3 探针
|
||||
# + 9 编辑 + 1 选择 + 1 反思 = 21。
|
||||
n_probes = 1 + 3 * args.k # 两种模式同款:1 base + 每轮 2 候选 + 1 终版
|
||||
n_edits = 3 * args.k
|
||||
n_select = 0 if args.k == 1 else 1 # k=1 trivial,不建选择任务
|
||||
plan = (f"计划:项目 {args.project_id},任务 {args.task_id},"
|
||||
f"mode={args.mode} k={args.k},run_tag={run_tag},"
|
||||
f"约 {n_probes} 个探针 + {n_edits} 个编辑 + 1 选择 + 1 反思 = "
|
||||
f"{n_probes + n_edits + 2} 个真实任务,"
|
||||
f"budget_usd={args.budget},base 文件 {len(base)} 个。")
|
||||
f"约 {n_probes} 个探针 + {n_edits} 个编辑 + {n_select} 选择 + 1 反思 = "
|
||||
f"{n_probes + n_edits + n_select + 1} 个真实任务,"
|
||||
f"budget_usd={args.budget},max_sessions={args.max_sessions},"
|
||||
f"base 文件 {len(base)} 个。")
|
||||
print(plan)
|
||||
if not args.yes:
|
||||
print("未带 --yes:只打印计划,不创建任何任务。确认无误后加 --yes 重跑。")
|
||||
@@ -111,7 +147,8 @@ def main():
|
||||
source_files=_flatten(Path(args.source_dir)) if args.source_dir else None,
|
||||
k=args.k, mode=args.mode,
|
||||
library_root=Path(args.library_root) if args.library_root else None,
|
||||
budget_usd=args.budget, model=args.model, effort=args.effort,
|
||||
budget_usd=args.budget, max_sessions=args.max_sessions,
|
||||
model=args.model, effort=args.effort,
|
||||
approval=args.approval, environment_id=args.environment_id,
|
||||
executor=args.executor, no_time_limit=args.no_time_limit,
|
||||
timeout_seconds=args.timeout)
|
||||
|
||||
Reference in new issue
Block a user