narcolepticchicken commited on
Commit
edbfb20
·
verified ·
1 Parent(s): 032c73c

Delete eval/benchmark_v9_results.json, eval/bert_vs_xgboost_results.json/*, eval/e2e_standalone_results.json, training/e2e_*.py

Browse files
training/e2e_benchmark.py DELETED
@@ -1,429 +0,0 @@
1
- """End-to-End ACO Evaluation on SWE-bench Agent Traces.
2
-
3
- Simulates a coding agent running on SWE-bench tasks, with the ACO optimizer
4
- intercepting every decision point. Uses SWE-Router execution data for
5
- ground-truth model costs and outcomes.
6
-
7
- Measures:
8
- - Total cost with optimizer vs without
9
- - Per-module cost impact (ablation study)
10
- - Which optimizer decisions actually saved money
11
- - Which optimizer decisions wasted money
12
-
13
- Architecture:
14
- For each SWE-bench task:
15
- 1. ACO predicts task type, difficulty, optimal tier
16
- 2. ACO routes to a model (cascade)
17
- 3. Agent "runs" using SWE-Router ground truth (did it resolve? how much did it cost?)
18
- 4. ACO decides: verify? retry? escalate? stop?
19
- 5. Measure: actual cost path vs baseline
20
-
21
- The "agent" is simulated: we use SWE-Router traces to know what each model
22
- actually did (cost, api_calls, success). ACO makes the decisions, we look up
23
- the real outcomes, ACO reacts, etc.
24
- """
25
- import json, sys, os, copy, random, hashlib
26
- from collections import defaultdict
27
- from typing import Dict, List, Optional, Tuple
28
- import numpy as np
29
-
30
- # ── Load ACO package ────────────────────────────────────────────
31
- sys.path.insert(0, "/app")
32
- from aco.optimizer import ACOOptimizer
33
- from aco.config import ACOConfig, RoutingPolicy
34
- from aco.router import RoutingDecision
35
- from aco.router_v10 import V10Router
36
- from datasets import load_dataset
37
-
38
- REPO = "narcolepticchicken/agent-cost-optimizer"
39
-
40
- print("=" * 70)
41
- print("ACO END-TO-END BENCHMARK ON SWE-BENCH AGENT TRACES")
42
- print("=" * 70)
43
-
44
- # ── 1. Load SWE-Router ground truth ─────────────────────────────
45
- print("\n[1] Loading SWE-Router execution data (8 models × 500 tasks)...")
46
-
47
- MODELS = [
48
- "deepseek-v4-flash", "gpt-5-nano", "gpt-5-mini", "deepseek-v3.2",
49
- "gemini-2.5-pro", "claude-opus-4.7", "gpt-5.2", "gemini-3-pro",
50
- ]
51
-
52
- TIER = {
53
- "deepseek-v4-flash": 1, "gpt-5-nano": 1,
54
- "gpt-5-mini": 2, "deepseek-v3.2": 2,
55
- "gemini-2.5-pro": 3,
56
- "claude-opus-4.7": 4, "gpt-5.2": 4,
57
- "gemini-3-pro": 5,
58
- }
59
-
60
- TIER_MODEL_MAP = {
61
- 1: "deepseek-v4-flash", 2: "gpt-5-mini",
62
- 3: "gemini-2.5-pro", 4: "claude-opus-4.7", 5: "gemini-3-pro",
63
- }
64
-
65
- # Load all SWE-Router traces
66
- traces = defaultdict(dict)
67
- for model_name in MODELS:
68
- ds = load_dataset(f"SWE-Router/swebench-verified-{model_name}", split="test")
69
- for row in ds:
70
- iid = row["instance_id"]
71
- traces[iid][model_name] = {
72
- "resolved": row["resolved"],
73
- "cost": float(row["instance_cost"]),
74
- "api_calls": int(row["api_calls"]),
75
- "problem": row.get("problem_statement", row.get("problem", "")),
76
- }
77
- print(f" Loaded {len(traces)} tasks × {len(MODELS)} models = {len(traces) * len(MODELS)} outcomes")
78
-
79
- # ── 2. Set up ACO optimizer ─────────────────────────────────────
80
- print("\n[2] Setting up ACO optimizer...")
81
-
82
- config = ACOConfig()
83
- config.routing_policy = RoutingPolicy(
84
- routing_mode="cascade",
85
- feedback_escalation=True,
86
- max_retries=2,
87
- max_cost_per_task=1.0,
88
- safety_threshold=0.5,
89
- )
90
- config.enable_meta_tools = False # no trace data to mine yet
91
- config.enable_doom_detector = True
92
- config.router_model_path = "/tmp/router_models/router_bundle_v10_fixed.pkl"
93
-
94
- # Download the router bundle
95
- from huggingface_hub import hf_hub_download
96
- try:
97
- bundle_path = hf_hub_download(
98
- repo_id=REPO,
99
- filename="router_models/router_bundle_v10_fixed.pkl",
100
- cache_dir="/tmp/router_models"
101
- )
102
- config.router_model_path = bundle_path
103
- print(f" Router model: {bundle_path}")
104
- except Exception as e:
105
- print(f" Router bundle download failed: {e}")
106
- config.router_model_path = None
107
-
108
- optimizer = ACOOptimizer(config)
109
-
110
- # ── 3. Simulate agent runs ──────────────────────────────────────
111
- print("\n[3] Running end-to-end simulation...")
112
-
113
- def simulate_agent_run(task_id: str, task_problem: str, model_name: str,
114
- optimizer: ACOOptimizer) -> Dict:
115
- """Simulate one agent run with ACO intercepting decisions."""
116
- result = {
117
- "task_id": task_id,
118
- "problem": task_problem[:200],
119
- "steps": [],
120
- "total_cost": 0.0,
121
- "total_api_calls": 0,
122
- "success": False,
123
- "routed_model": model_name,
124
- "routed_tier": TIER.get(model_name, 4),
125
- "escalated": False,
126
- "terminated_early": False,
127
- "verifier_calls": 0,
128
- "tool_gate_skips": 0,
129
- "doom_stops": 0,
130
- }
131
-
132
- # Step 1: ACO routes to a model
133
- start = optimizer.start_run(task_problem)
134
- routed_model = start["routing"]["model_id"]
135
- routed_tier = start["routing"]["tier"]
136
-
137
- result["routed_model"] = routed_model
138
- result["routed_tier"] = routed_tier
139
- result["aco_start"] = start
140
-
141
- # Step 2: Simulate agent execution with this model
142
- model_trace = traces[task_id].get(routed_model, {})
143
- resolved = model_trace.get("resolved", False)
144
- cost = model_trace.get("cost", 0.30)
145
- api_calls = model_trace.get("api_calls", 10)
146
-
147
- # Simulate 3 agent steps (model call + tool calls per step)
148
- step_names = ["analyze_problem", "generate_patch", "verify_patch"]
149
- for i, step_name in enumerate(step_names):
150
- step_cost = cost / len(step_names)
151
- step_api = max(1, api_calls // len(step_names))
152
-
153
- # ACO: gate tools (simulate 2-3 tool calls per step)
154
- tool_decisions = []
155
- for tool_idx in range(random.randint(2, 4)):
156
- td = optimizer.gate_tool(f"tool_{tool_idx}", {"step": step_name})
157
- tool_decisions.append(td)
158
- if td.action == "skip":
159
- result["tool_gate_skips"] += 1
160
-
161
- # ACO: should we verify?
162
- is_final = (i == len(step_names) - 1)
163
- vd = optimizer.should_verify(
164
- is_irreversible=is_final,
165
- has_prior_failures=(not resolved and i > 0),
166
- )
167
- if vd.should_verify:
168
- result["verifier_calls"] += 1
169
- # Verifier adds ~20% to cost
170
- step_cost *= 1.2
171
-
172
- # ACO: check for doom
173
- total_so_far = result["total_cost"] + step_cost
174
- doom = optimizer.check_doom(current_cost=total_so_far)
175
-
176
- if doom.doomed:
177
- result["terminated_early"] = True
178
- result["doom_stops"] += 1
179
- result["doom_reason"] = doom.reasoning
180
- break
181
-
182
- # Record step
183
- optimizer.record_step(
184
- model_call={
185
- "model_id": routed_model,
186
- "input_tokens": 5000 // len(step_names),
187
- "output_tokens": 500,
188
- "cost": step_cost,
189
- "latency_ms": 2000,
190
- },
191
- tool_calls=[{
192
- "tool_name": td.tool_name,
193
- "args": td.args,
194
- "success": td.action != "skip",
195
- "cost": td.estimated_cost,
196
- "latency_ms": td.estimated_latency,
197
- } for td in tool_decisions],
198
- context_size=5000 + (i * 1000),
199
- retry_num=0,
200
- )
201
-
202
- result["total_cost"] += step_cost
203
- result["total_api_calls"] += step_api
204
- result["steps"].append(step_name)
205
-
206
- # If escalated, try next tier
207
- if not resolved and not result["terminated_early"]:
208
- for escalate_tier in range(routed_tier + 1, 6):
209
- escalate_model = TIER_MODEL_MAP[escalate_tier]
210
- esc_trace = traces[task_id].get(escalate_model, {})
211
- if esc_trace.get("resolved", False):
212
- result["total_cost"] += esc_trace.get("cost", 0.30)
213
- result["escalated"] = True
214
- result["final_model_used"] = escalate_model
215
- resolved = True
216
- break
217
- else:
218
- # Escalation failed, add cost and continue
219
- result["total_cost"] += esc_trace.get("cost", 0.30)
220
-
221
- result["success"] = resolved
222
-
223
- # End run
224
- outcome = "completed" if resolved else ("terminated" if result["terminated_early"] else "abandoned")
225
- trace = optimizer.end_run(
226
- success=resolved,
227
- outcome=outcome,
228
- artifacts=["patch.diff"] if resolved else [],
229
- failure_tags=[] if resolved else ["not_resolved"],
230
- )
231
-
232
- return result
233
-
234
-
235
- def compute_baseline_cost(task_id: str) -> Dict:
236
- """Get baseline metrics for a task."""
237
- best = None
238
- for model_name, mt in traces[task_id].items():
239
- # Frontier: claude-opus-4.7
240
- if model_name == "claude-opus-4.7":
241
- frontier = mt
242
- # Cheapest that solves it
243
- if mt["resolved"]:
244
- if best is None or mt["cost"] < best["cost"]:
245
- best = mt
246
-
247
- return {
248
- "frontier_cost": traces[task_id].get("claude-opus-4.7", {}).get("cost", 0.317),
249
- "frontier_resolved": traces[task_id].get("claude-opus-4.7", {}).get("resolved", False),
250
- "cheapest_success_cost": best["cost"] if best else None,
251
- "cheapest_resolved": best is not None,
252
- "always_cheap_cost": traces[task_id].get("deepseek-v4-flash", {}).get("cost", 0.014),
253
- "always_cheap_resolved": traces[task_id].get("deepseek-v4-flash", {}).get("resolved", False),
254
- }
255
-
256
- # Run on all 500 tasks
257
- all_results = []
258
- for idx, (task_id, task_traces) in enumerate(traces.items()):
259
- problem = next(iter(task_traces.values()))["problem"]
260
- result = simulate_agent_run(task_id, problem, "deepseek-v4-flash", optimizer)
261
- baseline = compute_baseline_cost(task_id)
262
- result["baseline"] = baseline
263
- all_results.append(result)
264
-
265
- if (idx + 1) % 100 == 0:
266
- n = idx + 1
267
- resolved = sum(1 for r in all_results if r["success"])
268
- total_cost = sum(r["total_cost"] for r in all_results)
269
- print(f" [{n}/500] resolved={resolved} ({resolved/n*100:.1f}%), "
270
- f"avg_cost=${total_cost/n:.4f}")
271
-
272
- # ── 4. Compute metrics ──────────────────────────────────────────
273
- print(f"\n[4] Computing metrics...")
274
-
275
- n = len(all_results)
276
- resolved = sum(1 for r in all_results if r["success"])
277
- total_cost = sum(r["total_cost"] for r in all_results)
278
- baseline_frontier_cost = sum(r["baseline"]["frontier_cost"] for r in all_results)
279
- baseline_cheap_cost = sum(r["baseline"]["always_cheap_cost"] for r in all_results)
280
- escalated = sum(1 for r in all_results if r["escalated"])
281
- terminated = sum(1 for r in all_results if r["terminated_early"])
282
- verifier_calls = sum(r["verifier_calls"] for r in all_results)
283
- tool_skips = sum(r["tool_gate_skips"] for r in all_results)
284
-
285
- # Baseline metrics
286
- frontier_resolved = sum(1 for r in all_results if r["baseline"]["frontier_resolved"])
287
- cheap_resolved = sum(1 for r in all_results if r["baseline"]["always_cheap_resolved"])
288
-
289
- print(f"""
290
- {'='*70}
291
- ACO END-TO-END RESULTS (500 SWE-bench tasks)
292
- {'='*70}
293
-
294
- TASKS: {n}
295
-
296
- {'Policy':<25} {'Resolved':>10} {'Rate':>10} {'TotalCost':>12} {'AvgCost':>10} {'CostRed':>10}
297
- {'-'*77}
298
- {'ACO Optimized':<25} {resolved:>10} {resolved/n*100:>9.1f}% ${total_cost:>10.2f} ${total_cost/n:>9.4f} {(1-total_cost/baseline_frontier_cost)*100:>9.1f}%
299
- {'Frontier (always)':<25} {frontier_resolved:>10} {frontier_resolved/n*100:>9.1f}% ${baseline_frontier_cost:>10.2f} ${baseline_frontier_cost/n:>9.4f} {'--':>10}
300
- {'Always Cheap':<25} {cheap_resolved:>10} {cheap_resolved/n*100:>9.1f}% ${baseline_cheap_cost:>10.2f} ${baseline_cheap_cost/n:>9.4f} {(1-baseline_cheap_cost/baseline_frontier_cost)*100:>9.1f}%
301
-
302
- PER-MODULE IMPACT:
303
- Escalations triggered: {escalated} ({escalated/n*100:.1f}%)
304
- Early terminations: {terminated} ({terminated/n*100:.1f}%)
305
- Verifier calls: {verifier_calls} ({verifier_calls/n*100:.1f} avg/task)
306
- Tool gate skips: {tool_skips} ({tool_skips/n*100:.1f} avg/task)
307
-
308
- COST BREAKDOWN:
309
- Avg cost per run: ${total_cost/n:.4f}
310
- Avg cost per resolved: ${total_cost/max(resolved,1):.4f}
311
- Waste on failed runs: ${sum(r['total_cost'] for r in all_results if not r['success']):.2f}
312
- """)
313
-
314
- # ── 5. Ablation study ───────────────────────────────────────────
315
- print(f"[5] Running ablation study...")
316
-
317
- def run_ablation(disable_modules: List[str]) -> Dict:
318
- """Run with specific modules disabled."""
319
- ab_config = ACOConfig()
320
- ab_config.routing_policy = RoutingPolicy(
321
- routing_mode="cascade" if "router" not in disable_modules else "frontier",
322
- feedback_escalation="feedback_escalation" not in disable_modules,
323
- max_retries=2,
324
- max_cost_per_task=1.0,
325
- safety_threshold=0.5,
326
- )
327
- ab_config.enable_meta_tools = "meta_tools" not in disable_modules
328
- ab_config.enable_doom_detector = "doom_detector" not in disable_modules
329
- ab_config.router_model_path = config.router_model_path
330
-
331
- ab_opt = ACOOptimizer(ab_config)
332
-
333
- results = []
334
- for task_id, task_traces in list(traces.items())[:100]: # Use 100 for ablation
335
- problem = next(iter(task_traces.values()))["problem"]
336
- result = simulate_agent_run(task_id, problem, "deepseek-v4-flash", ab_opt)
337
- # Override with ablation behavior
338
- if "verifier" in disable_modules:
339
- result["verifier_calls"] = 0
340
- if "tool_gate" in disable_modules:
341
- result["tool_gate_skips"] = 0
342
- if "context" in disable_modules:
343
- pass # mock agent doesn't use context
344
- results.append(result)
345
-
346
- return {
347
- "modules_disabled": disable_modules,
348
- "n": len(results),
349
- "resolved": sum(1 for r in results if r["success"]),
350
- "total_cost": sum(r["total_cost"] for r in results),
351
- "avg_cost": sum(r["total_cost"] for r in results) / max(len(results), 1),
352
- "verifier_calls": sum(r["verifier_calls"] for r in results),
353
- "escalated": sum(1 for r in results if r["escalated"]),
354
- "terminated": sum(1 for r in results if r["terminated_early"]),
355
- }
356
-
357
- ablations = {
358
- "full_aco": run_ablation([]),
359
- "no_router": run_ablation(["router", "feedback_escalation"]),
360
- "no_feedback": run_ablation(["feedback_escalation"]),
361
- "no_verifier": run_ablation(["verifier"]),
362
- "no_doom_detector": run_ablation(["doom_detector"]),
363
- "no_tool_gate": run_ablation(["tool_gate"]),
364
- "frontier_only": run_ablation(["router", "feedback_escalation", "verifier", "doom_detector", "tool_gate"]),
365
- }
366
-
367
- print(f"\n{'='*70}")
368
- print("ABLATION STUDY (100 tasks)")
369
- print(f"{'='*70}")
370
- print(f"\n{'Configuration':<25} {'Resolved':>10} {'Rate':>8} {'AvgCost':>10} {'vsFull':>10}")
371
- print("-" * 63)
372
-
373
- full_cost = ablations["full_aco"]["avg_cost"]
374
- full_resolved = ablations["full_aco"]["resolved"]
375
-
376
- for name, ab in sorted(ablations.items(), key=lambda x: x[1]["avg_cost"]):
377
- delta_cost = (ab["avg_cost"] - full_cost) / max(full_cost, 0.0001) * 100
378
- delta_resolved = ab["resolved"] - full_resolved
379
- flag = ""
380
- if delta_cost > 0 and ab["resolved"] < full_resolved:
381
- flag = " ← REGRESSION"
382
- elif delta_cost < 0 and ab["resolved"] >= full_resolved:
383
- flag = " ← IMPROVEMENT"
384
- print(f" {name:<23} {ab['resolved']:>10} {ab['resolved']/10:>7.1f}% ${ab['avg_cost']:>9.4f} {delta_cost:>+9.1f}%{flag}")
385
-
386
- # ── 6. Save results ─────────────────────────────────────────────
387
- output = {
388
- "end_to_end": {
389
- "n": n,
390
- "resolved": resolved,
391
- "success_rate": round(resolved / n, 4),
392
- "total_cost": round(total_cost, 2),
393
- "avg_cost": round(total_cost / n, 4),
394
- "avg_cost_per_resolved": round(total_cost / max(resolved, 1), 4),
395
- "cost_reduction_vs_frontier": round((1 - total_cost / baseline_frontier_cost) * 100, 1),
396
- "frontier_cost": round(baseline_frontier_cost, 2),
397
- "frontier_resolved": frontier_resolved,
398
- "escalations": escalated,
399
- "early_terminations": terminated,
400
- "verifier_calls": verifier_calls,
401
- "tool_gate_skips": tool_skips,
402
- },
403
- "ablations": {
404
- name: {
405
- "resolved": a["resolved"],
406
- "avg_cost": round(a["avg_cost"], 4),
407
- "cost_delta_vs_full": round((a["avg_cost"] - full_cost) / max(full_cost, 0.0001) * 100, 1),
408
- }
409
- for name, a in ablations.items()
410
- },
411
- }
412
-
413
- with open("/tmp/aco_e2e_results.json", "w") as f:
414
- json.dump(output, f, indent=2)
415
-
416
- # Upload
417
- from huggingface_hub import HfApi
418
- api = HfApi()
419
- api.upload_file(
420
- path_or_fileobj="/tmp/aco_e2e_results.json",
421
- path_in_repo="eval/e2e_benchmark_results.json",
422
- repo_id=REPO,
423
- repo_type="model",
424
- )
425
-
426
- print(f"\n ✓ Results uploaded to eval/e2e_benchmark_results.json")
427
- print(f"\n{'='*70}")
428
- print("E2E BENCHMARK COMPLETE")
429
- print("=" * 70)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/e2e_benchmark_v2.py DELETED
@@ -1,355 +0,0 @@
1
- """End-to-End ACO Evaluation on SWE-bench Agent Traces.
2
-
3
- FIXED: Clones the ACO repo first for imports.
4
- """
5
- import json, sys, os, copy, random, subprocess
6
- from collections import defaultdict
7
- from typing import Dict, List, Optional, Tuple
8
- import numpy as np
9
-
10
- # Clone repo for ACO imports
11
- repo_url = "https://huggingface.co/narcolepticchicken/agent-cost-optimizer"
12
- if not os.path.exists("/tmp/aco_repo"):
13
- print(f"Cloning {repo_url}...")
14
- subprocess.run(["git", "clone", repo_url, "/tmp/aco_repo"], check=True)
15
- subprocess.run(["pip", "install", "pyyaml"], check=True, capture_output=True)
16
-
17
- sys.path.insert(0, "/tmp/aco_repo")
18
- from aco.optimizer import ACOOptimizer
19
- from aco.config import ACOConfig, RoutingPolicy
20
- from datasets import load_dataset
21
-
22
- REPO = "narcolepticchicken/agent-cost-optimizer"
23
-
24
- print("=" * 70)
25
- print("ACO END-TO-END BENCHMARK ON SWE-BENCH AGENT TRACES (V2)")
26
- print("=" * 70)
27
-
28
- # ── 1. Load SWE-Router ground truth ─────────────────────────────
29
- print("\n[1] Loading SWE-Router execution data...")
30
-
31
- MODELS = [
32
- "deepseek-v4-flash", "gpt-5-nano", "gpt-5-mini", "deepseek-v3.2",
33
- "gemini-2.5-pro", "claude-opus-4.7", "gpt-5.2", "gemini-3-pro",
34
- ]
35
-
36
- TIER = {
37
- "deepseek-v4-flash": 1, "gpt-5-nano": 1,
38
- "gpt-5-mini": 2, "deepseek-v3.2": 2,
39
- "gemini-2.5-pro": 3,
40
- "claude-opus-4.7": 4, "gpt-5.2": 4,
41
- "gemini-3-pro": 5,
42
- }
43
-
44
- TIER_MODEL_MAP = {
45
- 1: "deepseek-v4-flash", 2: "gpt-5-mini",
46
- 3: "gemini-2.5-pro", 4: "claude-opus-4.7", 5: "gemini-3-pro",
47
- }
48
-
49
- # Load all SWE-Router traces
50
- traces = defaultdict(dict)
51
- for model_name in MODELS:
52
- ds = load_dataset(f"SWE-Router/swebench-verified-{model_name}", split="test")
53
- for row in ds:
54
- iid = row["instance_id"]
55
- traces[iid][model_name] = {
56
- "resolved": row["resolved"],
57
- "cost": float(row["instance_cost"]),
58
- "api_calls": int(row["api_calls"]),
59
- "problem": row.get("problem_statement", row.get("problem", "")),
60
- }
61
- print(f" Loaded {len(traces)} tasks × {len(MODELS)} models")
62
-
63
- # ── 2. Set up ACO optimizer ─────────────────────────────────────
64
- print("\n[2] Setting up ACO optimizer...")
65
-
66
- config = ACOConfig()
67
- config.routing_policy = RoutingPolicy(
68
- routing_mode="cascade",
69
- feedback_escalation=True,
70
- max_retries=2,
71
- max_cost_per_task=1.0,
72
- safety_threshold=0.5,
73
- )
74
- config.enable_meta_tools = False
75
- config.enable_doom_detector = True
76
-
77
- # Download router bundle
78
- from huggingface_hub import hf_hub_download
79
- try:
80
- bundle_path = hf_hub_download(
81
- repo_id=REPO,
82
- filename="router_models/router_bundle_v10_fixed.pkl",
83
- )
84
- config.router_model_path = bundle_path
85
- print(f" Router model loaded")
86
- except Exception as e:
87
- print(f" Router not available: {e}")
88
- config.router_model_path = None
89
-
90
- optimizer = ACOOptimizer(config)
91
-
92
- # ── 3. Simulate agent runs ──────────────────────────────────────
93
- print("\n[3] Running end-to-end simulation...")
94
-
95
- def simulate_agent_run(task_id: str, task_problem: str,
96
- optimizer: ACOOptimizer) -> Dict:
97
- """Simulate one agent run with ACO intercepting decisions."""
98
- result = {
99
- "task_id": task_id,
100
- "total_cost": 0.0,
101
- "success": False,
102
- "escalated": False,
103
- "terminated_early": False,
104
- "verifier_calls": 0,
105
- "tool_gate_skips": 0,
106
- "doom_stops": 0,
107
- }
108
-
109
- # Step 1: ACO routes to a model
110
- start = optimizer.start_run(task_problem)
111
- routed_model = start["routing"]["model_id"]
112
- routed_tier = start["routing"]["tier"]
113
-
114
- result["routed_model"] = routed_model
115
- result["routed_tier"] = routed_tier
116
-
117
- # Step 2: Simulate agent execution
118
- model_trace = traces[task_id].get(routed_model, {})
119
- resolved = model_trace.get("resolved", False)
120
- cost = model_trace.get("cost", 0.30)
121
- api_calls = model_trace.get("api_calls", 10)
122
-
123
- step_names = ["analyze", "generate", "verify"]
124
- n_steps = min(len(step_names), api_calls)
125
-
126
- for i, step_name in enumerate(step_names[:n_steps]):
127
- step_cost = cost / max(n_steps, 1)
128
-
129
- # Gate tools
130
- for tool_idx in range(random.randint(1, 3)):
131
- td = optimizer.gate_tool(f"tool_{tool_idx}", {"step": step_name})
132
- if td.action == "skip":
133
- result["tool_gate_skips"] += 1
134
-
135
- # Should we verify?
136
- is_final = (i == n_steps - 1)
137
- vd = optimizer.should_verify(
138
- is_irreversible=is_final,
139
- has_prior_failures=(not resolved and i > 0),
140
- )
141
- if vd.should_verify:
142
- result["verifier_calls"] += 1
143
- step_cost *= 1.2
144
-
145
- # Doom check
146
- total_so_far = result["total_cost"] + step_cost
147
- doom = optimizer.check_doom(current_cost=total_so_far)
148
- if doom.doomed:
149
- result["terminated_early"] = True
150
- result["doom_stops"] += 1
151
- break
152
-
153
- # Record step
154
- optimizer.record_step(
155
- model_call={
156
- "model_id": routed_model,
157
- "input_tokens": 5000 // max(n_steps, 1),
158
- "output_tokens": 500,
159
- "cost": step_cost,
160
- "latency_ms": 2000,
161
- },
162
- context_size=5000 + (i * 1000),
163
- retry_num=0,
164
- )
165
-
166
- result["total_cost"] += step_cost
167
-
168
- # Escalate if needed
169
- if not resolved and not result["terminated_early"]:
170
- for escalate_tier in range(routed_tier + 1, 6):
171
- escalate_model = TIER_MODEL_MAP[escalate_tier]
172
- esc_trace = traces[task_id].get(escalate_model, {})
173
- if esc_trace.get("resolved", False):
174
- result["total_cost"] += esc_trace.get("cost", 0.30)
175
- result["escalated"] = True
176
- resolved = True
177
- break
178
- else:
179
- result["total_cost"] += esc_trace.get("cost", 0.30)
180
-
181
- result["success"] = resolved
182
-
183
- optimizer.end_run(
184
- success=resolved,
185
- outcome="completed" if resolved else "abandoned",
186
- artifacts=["fix"] if resolved else [],
187
- failure_tags=[] if resolved else ["not_resolved"],
188
- )
189
-
190
- return result
191
-
192
- def compute_baseline(task_id: str) -> Dict:
193
- ft = traces[task_id].get("claude-opus-4.7", {})
194
- ch = traces[task_id].get("deepseek-v4-flash", {})
195
- best = None
196
- for m, mt in traces[task_id].items():
197
- if mt["resolved"] and (best is None or mt["cost"] < best["cost"]):
198
- best = mt
199
- return {
200
- "frontier_cost": ft.get("cost", 0.317),
201
- "frontier_resolved": ft.get("resolved", False),
202
- "always_cheap_cost": ch.get("cost", 0.014),
203
- "always_cheap_resolved": ch.get("resolved", False),
204
- "oracle_cost": best["cost"] if best else ft.get("cost", 0.317),
205
- "oracle_resolved": best is not None,
206
- }
207
-
208
- # Run on all 500 tasks
209
- all_results = []
210
- for idx, (task_id, task_traces) in enumerate(traces.items()):
211
- problem = next(iter(task_traces.values()))["problem"]
212
- result = simulate_agent_run(task_id, problem, optimizer)
213
- baseline = compute_baseline(task_id)
214
- result["baseline"] = baseline
215
- all_results.append(result)
216
-
217
- if (idx + 1) % 100 == 0:
218
- n = idx + 1
219
- resolved = sum(1 for r in all_results if r["success"])
220
- total_cost = sum(r["total_cost"] for r in all_results)
221
- print(f" [{n}/500] resolved={resolved} ({resolved/n*100:.1f}%), "
222
- f"avg_cost=${total_cost/n:.4f}")
223
-
224
- # ── 4. Compute metrics ──────────────────────────────────────────
225
- print(f"\n[4] Computing metrics...")
226
-
227
- n = len(all_results)
228
- resolved = sum(1 for r in all_results if r["success"])
229
- total_cost = sum(r["total_cost"] for r in all_results)
230
- baseline_frontier_cost = sum(r["baseline"]["frontier_cost"] for r in all_results)
231
- baseline_cheap_cost = sum(r["baseline"]["always_cheap_cost"] for r in all_results)
232
- baseline_oracle_cost = sum(r["baseline"]["oracle_cost"] for r in all_results)
233
- frontier_resolved = sum(1 for r in all_results if r["baseline"]["frontier_resolved"])
234
- cheap_resolved = sum(1 for r in all_results if r["baseline"]["always_cheap_resolved"])
235
- oracle_resolved = sum(1 for r in all_results if r["baseline"]["oracle_resolved"])
236
- escalated = sum(1 for r in all_results if r["escalated"])
237
- terminated = sum(1 for r in all_results if r["terminated_early"])
238
- verifier_calls = sum(r["verifier_calls"] for r in all_results)
239
-
240
- print(f"""
241
- {'='*70}
242
- ACO END-TO-END RESULTS ({n} SWE-bench tasks)
243
- {'='*70}
244
-
245
- {'Policy':<25} {'Resolved':>10} {'Rate':>10} {'TotalCost':>12} {'AvgCost':>10} {'vsFront':>10}
246
- {'-'*77}
247
- {'ACO Optimized':<25} {resolved:>10} {resolved/n*100:>9.1f}% ${total_cost:>10.2f} ${total_cost/n:>9.4f} {(1-total_cost/baseline_frontier_cost)*100:>9.1f}%
248
- {'Frontier (always)':<25} {frontier_resolved:>10} {frontier_resolved/n*100:>9.1f}% ${baseline_frontier_cost:>10.2f} ${baseline_frontier_cost/n:>9.4f} {'--':>10}
249
- {'Always Cheap':<25} {cheap_resolved:>10} {cheap_resolved/n*100:>9.1f}% ${baseline_cheap_cost:>10.2f} ${baseline_cheap_cost/n:>9.4f} {(1-baseline_cheap_cost/baseline_frontier_cost)*100:>9.1f}%
250
- {'Oracle':<25} {oracle_resolved:>10} {oracle_resolved/n*100:>9.1f}% ${baseline_oracle_cost:>10.2f} ${baseline_oracle_cost/n:>9.4f} {(1-baseline_oracle_cost/baseline_frontier_cost)*100:>9.1f}%
251
-
252
- MODULE IMPACT:
253
- Escalations: {escalated} ({escalated/n*100:.1f}%)
254
- Early stops: {terminated} ({terminated/n*100:.1f}%)
255
- Verifier calls: {verifier_calls} ({verifier_calls/max(n,1):.2f}/task)
256
- Avg cost/resolved: ${total_cost/max(resolved,1):.4f}
257
- Waste on failures: ${sum(r['total_cost'] for r in all_results if not r['success']):.2f}
258
- """)
259
-
260
- # ── 5. Ablation study (100 tasks) ───────────────────────────────
261
- print(f"\n[5] Ablation study (100 tasks)...")
262
-
263
- def run_ablation(disable_modules: List[str], n_tasks: int = 100) -> Dict:
264
- ab_config = ACOConfig()
265
- ab_config.routing_policy = RoutingPolicy(
266
- routing_mode="cascade" if "router" not in disable_modules else "frontier",
267
- feedback_escalation="feedback" not in disable_modules,
268
- max_retries=2, max_cost_per_task=1.0, safety_threshold=0.5,
269
- )
270
- ab_config.enable_doom_detector = "doom" not in disable_modules
271
- ab_config.router_model_path = config.router_model_path
272
-
273
- ab_opt = ACOOptimizer(ab_config)
274
- results = []
275
- task_items = list(traces.items())[:n_tasks]
276
-
277
- for task_id, task_traces in task_items:
278
- problem = next(iter(task_traces.values()))["problem"]
279
- result = simulate_agent_run(task_id, problem, ab_opt)
280
- if "verifier" in disable_modules:
281
- result["verifier_calls"] = 0
282
- if "tool_gate" in disable_modules:
283
- result["tool_gate_skips"] = 0
284
- results.append(result)
285
-
286
- return {
287
- "n": len(results),
288
- "resolved": sum(1 for r in results if r["success"]),
289
- "total_cost": sum(r["total_cost"] for r in results),
290
- "avg_cost": sum(r["total_cost"] for r in results) / max(len(results), 1),
291
- }
292
-
293
- ablations = {
294
- "full_aco": run_ablation([]),
295
- "no_router": run_ablation(["router", "feedback"]),
296
- "no_feedback": run_ablation(["feedback"]),
297
- "no_verifier": run_ablation(["verifier"]),
298
- "no_doom": run_ablation(["doom"]),
299
- "no_tool_gate": run_ablation(["tool_gate"]),
300
- "frontier_only": run_ablation(["router", "feedback", "verifier", "doom", "tool_gate"]),
301
- }
302
-
303
- full_cost = ablations["full_aco"]["avg_cost"]
304
- full_resolved = ablations["full_aco"]["resolved"]
305
-
306
- print(f"\n{'Configuration':<25} {'Resolved':>10} {'Rate':>8} {'AvgCost':>10} {'vsFull':>10}")
307
- print("-" * 63)
308
-
309
- for name in ["full_aco", "no_feedback", "no_doom", "no_tool_gate", "no_verifier", "no_router", "frontier_only"]:
310
- ab = ablations[name]
311
- dc = (ab["avg_cost"] - full_cost) / max(full_cost, 0.0001) * 100
312
- dr = ab["resolved"] - full_resolved
313
- flag = ""
314
- if dc > 0 and dr < 0: flag = " ← REGRESSION"
315
- elif dc < 0 and dr >= 0: flag = " ← BETTER"
316
- print(f" {name:<23} {ab['resolved']:>10} {ab['resolved']/ab['n']*100:>7.1f}% ${ab['avg_cost']:>9.4f} {dc:>+9.1f}%{flag}")
317
-
318
- # ── 6. Save ─────────────────────────────────────────────────────
319
- output = {
320
- "end_to_end": {
321
- "n": n, "resolved": resolved,
322
- "success_rate": round(resolved/n, 4),
323
- "total_cost": round(total_cost, 2),
324
- "avg_cost": round(total_cost/n, 4),
325
- "cost_reduction_vs_frontier": round((1 - total_cost/baseline_frontier_cost) * 100, 1),
326
- "frontier_cost": round(baseline_frontier_cost, 2),
327
- "frontier_resolved": frontier_resolved,
328
- "oracle_cost": round(baseline_oracle_cost, 2),
329
- "oracle_resolved": oracle_resolved,
330
- "escalations": escalated,
331
- "early_terminations": terminated,
332
- "verifier_calls": verifier_calls,
333
- },
334
- "ablations": {
335
- name: {"resolved": a["resolved"], "avg_cost": round(a["avg_cost"], 4),
336
- "cost_delta_vs_full": round((a["avg_cost"] - full_cost) / max(full_cost, 0.0001) * 100, 1)}
337
- for name, a in ablations.items()
338
- },
339
- }
340
-
341
- with open("/tmp/aco_e2e_v2.json", "w") as f:
342
- json.dump(output, f, indent=2)
343
-
344
- from huggingface_hub import HfApi
345
- api = HfApi()
346
- api.upload_file(
347
- path_or_fileobj="/tmp/aco_e2e_v2.json",
348
- path_in_repo="eval/e2e_benchmark_v2.json",
349
- repo_id=REPO, repo_type="model",
350
- )
351
-
352
- print(f"\n✓ Results uploaded: eval/e2e_benchmark_v2.json")
353
- print(f"\n{'='*70}")
354
- print("E2E BENCHMARK V2 COMPLETE")
355
- print("=" * 70)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/e2e_standalone.py DELETED
@@ -1,397 +0,0 @@
1
- """Standalone ACO E2E Benchmark — no external aco/ imports.
2
-
3
- Evaluates the Agent Cost Optimizer's model cascade routing against simulated
4
- SWE-bench agent runs using SWE-Router execution traces as ground truth.
5
-
6
- Measures per-module impact through ablation: disable each module one at a time.
7
- """
8
- import json, sys, os, random, pickle
9
- from collections import defaultdict
10
- from typing import Dict, List, Optional
11
- import numpy as np
12
-
13
- # ── Core Router (inlined from aco/router_v10.py) ─────────────────
14
- CODE_KW = ["python","javascript","code","function","bug","debug","refactor",
15
- "implement","test","compile","runtime","segfault","thread","async","class",
16
- "module","import","error","traceback"]
17
- CRITICAL_KW = ["critical","production","urgent","emergency","live","deployed","safety","security"]
18
- SIMPLE_KW = ["typo","simple","quick","brief","minor","small","easy","trivial","just"]
19
- RESEARCH_KW = ["research","investigate","compare","analyze","survey","paper"]
20
- TOOL_KW = ["search","fetch","retrieve","query","api","database","scrape","aggregate"]
21
- LONG_KW = ["plan","project","roadmap","orchestrate","migrate","pipeline","deploy","architecture"]
22
-
23
- FEAT_KEYS = sorted([
24
- 'req_len','num_words','has_code','n_code','has_legal','has_research',
25
- 'has_tool','has_critical','has_simple','has_long','has_math',
26
- 'has_error_msg','has_file_path','n_lines','has_version','has_add',
27
- 'has_fix','has_change','has_remove','has_test','has_doc',
28
- 'has_see_also','has_steps_to_reproduce',
29
- ])
30
-
31
- TIER_TO_MODEL = {
32
- 1: 'deepseek-v4-flash', 2: 'gpt-5-mini',
33
- 3: 'gemini-2.5-pro', 4: 'claude-opus-4.7', 5: 'gemini-3-pro',
34
- }
35
-
36
- TIER_COST = {1:0.01, 2:0.05, 3:0.15, 4:0.30, 5:0.50}
37
-
38
- MODELS = ["deepseek-v4-flash","gpt-5-nano","gpt-5-mini","deepseek-v3.2",
39
- "gemini-2.5-pro","claude-opus-4.7","gpt-5.2","gemini-3-pro"]
40
- MODEL_TIER = {"deepseek-v4-flash":1,"gpt-5-nano":1,"gpt-5-mini":2,"deepseek-v3.2":2,
41
- "gemini-2.5-pro":3,"claude-opus-4.7":4,"gpt-5.2":4,"gemini-3-pro":5}
42
-
43
- def extract_features(text: str) -> np.ndarray:
44
- r = text.lower()
45
- feats = {
46
- 'req_len': len(text), 'num_words': len(text.split()),
47
- 'has_code': int(any(k in r for k in CODE_KW)),
48
- 'n_code': sum(1 for k in CODE_KW if k in r),
49
- 'has_legal': int(any(k in r for k in ["contract","legal","compliance"])),
50
- 'has_research': int(any(k in r for k in RESEARCH_KW)),
51
- 'has_tool': int(any(k in r for k in TOOL_KW)),
52
- 'has_critical': int(any(k in r for k in CRITICAL_KW)),
53
- 'has_simple': int(any(k in r for k in SIMPLE_KW)),
54
- 'has_long': int(any(k in r for k in LONG_KW)),
55
- 'has_math': int(any(k in r for k in ["calculate","compute","solve","equation"])),
56
- 'has_error_msg': int('error' in r or 'traceback' in r or 'exception' in r),
57
- 'has_file_path': int('/' in r),
58
- 'n_lines': text.count('\n') + 1,
59
- 'has_version': int('version' in r or 'update' in r),
60
- 'has_add': int('add' in r or 'new' in r or 'create' in r),
61
- 'has_fix': int('fix' in r or 'bug' in r or 'issue' in r),
62
- 'has_change': int('change' in r or 'modify' in r),
63
- 'has_remove': int('remove' in r or 'delete' in r),
64
- 'has_test': int('test' in r or 'spec' in r),
65
- 'has_doc': int('doc' in r or 'readme' in r),
66
- 'has_see_also': int('see also' in r or 'related' in r),
67
- 'has_steps_to_reproduce': int('reproduce' in r or 'steps' in r),
68
- }
69
- return np.array([float(feats.get(k,0.0)) for k in FEAT_KEYS], dtype=np.float32)
70
-
71
-
72
- # ── Load Router Bundle ──────────────────────────────────────────
73
- from huggingface_hub import hf_hub_download
74
- from sklearn.isotonic import IsotonicRegression
75
-
76
- print("Loading router model...")
77
- try:
78
- bundle_path = hf_hub_download(
79
- repo_id="narcolepticchicken/agent-cost-optimizer",
80
- filename="router_models/router_bundle_v10_fixed.pkl",
81
- )
82
- bundle = pickle.load(open(bundle_path, 'rb'))
83
- tier_clfs = {int(k):v for k,v in bundle.get('tier_clfs',{}).items()}
84
- tier_calibs = {int(k):v for k,v in bundle.get('tier_calibrators',{}).items()}
85
- print(f" Loaded v10 router: {len(tier_clfs)} tier classifiers")
86
- except Exception as e:
87
- print(f" WARNING: v10 bundle failed ({e}), using fallback routing")
88
- tier_clfs = {}
89
- tier_calibs = {}
90
-
91
-
92
- def route_cascade(text: str, threshold: float = 0.5) -> int:
93
- """Route to cheapest tier with P(success) >= threshold."""
94
- if not tier_clfs:
95
- # Fallback: use hardcoded tier success rates
96
- return 1 # always try cheapest
97
-
98
- x = extract_features(text).reshape(1, -1)
99
-
100
- for t in range(1, 6):
101
- if t in tier_clfs:
102
- try:
103
- p_raw = tier_clfs[t].predict_proba(x)[0, 1]
104
- p_cal = float(tier_calibs[t].transform([p_raw])[0])
105
- if p_cal >= threshold:
106
- return t
107
- except:
108
- pass
109
-
110
- return 5 # escalate to strongest
111
-
112
-
113
- # ── 1. Load SWE-Router Data ─────────────────────────────────────
114
- from datasets import load_dataset
115
-
116
- print("\n[1] Loading SWE-Router execution data...")
117
- traces = defaultdict(dict)
118
- for model_name in MODELS:
119
- ds = load_dataset(f"SWE-Router/swebench-verified-{model_name}", split="test")
120
- for row in ds:
121
- iid = row["instance_id"]
122
- traces[iid][model_name] = {
123
- "resolved": row["resolved"],
124
- "cost": float(row["instance_cost"]),
125
- "api_calls": int(row["api_calls"]),
126
- "problem": row.get("problem_statement", row.get("problem", "")),
127
- }
128
- print(f" Loaded {len(traces)} tasks × {len(MODELS)} models = {sum(len(v) for v in traces.values())} outcomes")
129
-
130
-
131
- # ── 2. Simulate ACO Agent Run ────────────────────────────────────
132
- print("\n[2] Simulating ACO-optimized agent runs...")
133
-
134
- def simulate_acorun(task_id: str, problem: str,
135
- use_router: bool = True,
136
- use_feedback: bool = True,
137
- use_verifier: bool = True,
138
- use_doom: bool = True,
139
- use_tool_gate: bool = True,
140
- max_doom_cost: float = 1.0,
141
- verifier_max_per_run: int = 3) -> Dict:
142
- """Simulate one ACO-optimized agent run."""
143
- result = {
144
- "task_id": task_id,
145
- "total_cost": 0.0,
146
- "success": False, "escalated": False,
147
- "terminated_early": False,
148
- "verifier_calls": 0, "tool_skips": 0,
149
- "routed_tier": 1,
150
- }
151
-
152
- # Step 1: Route
153
- routed_tier = route_cascade(problem) if use_router else 4
154
- routed_model = TIER_TO_MODEL.get(routed_tier, "claude-opus-4.7")
155
- result["routed_tier"] = routed_tier
156
-
157
- # Step 2: Execute tier 1
158
- model_trace = traces[task_id].get(routed_model, {})
159
- resolved = model_trace.get("resolved", False)
160
- cost = model_trace.get("cost", 0.30)
161
- api_calls = model_trace.get("api_calls", 10)
162
-
163
- # Simulate 3 agent steps
164
- n_steps = min(3, api_calls)
165
- verifier_count = 0
166
-
167
- for i in range(n_steps):
168
- step_cost = cost / max(n_steps, 1)
169
-
170
- # Tool gate
171
- if use_tool_gate and random.random() < 0.3:
172
- result["tool_skips"] += 1
173
- step_cost *= 0.9 # save 10% on skipped tools
174
-
175
- # Verifier
176
- should_verify = False
177
- if use_verifier:
178
- is_final = (i == n_steps - 1)
179
- is_high_risk = routed_tier <= 2
180
- has_failures = not resolved and i > 0
181
-
182
- if verifier_count < verifier_max_per_run and (is_final or is_high_risk or has_failures):
183
- should_verify = True
184
- verifier_count += 1
185
- result["verifier_calls"] += 1
186
- step_cost *= 1.15 # verifier adds 15%
187
-
188
- # Doom check (only after step 1)
189
- if use_doom and i > 0:
190
- total_so_far = result["total_cost"] + step_cost
191
- failed = not resolved
192
- if total_so_far > max_doom_cost * 0.7 and failed:
193
- result["terminated_early"] = True
194
- result["total_cost"] += step_cost * 0.5
195
- return result
196
-
197
- result["total_cost"] += step_cost
198
-
199
- # If not resolved and feedback is on, escalate
200
- if not resolved and use_feedback:
201
- result["escalated"] = True
202
- for escalate_tier in range(routed_tier + 1, 6):
203
- esc_model = TIER_TO_MODEL[escalate_tier]
204
- esc_trace = traces[task_id].get(esc_model, {})
205
- esc_cost = esc_trace.get("cost", 0.30)
206
- result["total_cost"] += esc_cost
207
-
208
- if esc_trace.get("resolved", False):
209
- resolved = True
210
- break
211
-
212
- # Doom check during escalation
213
- if use_doom and result["total_cost"] > max_doom_cost * 0.8:
214
- result["terminated_early"] = True
215
- break
216
-
217
- result["success"] = resolved
218
- return result
219
-
220
-
221
- # ── 3. Run Full Evaluation ──────────────────────────────────────
222
- N_TASKS = len(traces)
223
- eval_results = []
224
- configs = {
225
- "full_aco": (True, True, True, True, True),
226
- "no_router": (False, False, True, True, True),
227
- "no_feedback": (True, False, True, True, True),
228
- "no_verifier": (True, True, False, True, True),
229
- "no_doom": (True, True, True, False, True),
230
- "no_tool_gate": (True, True, True, True, False),
231
- "frontier_only": (False, False, False, False, False),
232
- }
233
-
234
- for config_name, (router, feedback, verifier, doom, tool_gate) in configs.items():
235
- results = []
236
- for task_id, task_traces in traces.items():
237
- problem = next(iter(task_traces.values()))["problem"]
238
- result = simulate_acorun(
239
- task_id, problem,
240
- use_router=router, use_feedback=feedback,
241
- use_verifier=verifier, use_doom=doom,
242
- use_tool_gate=tool_gate,
243
- )
244
- results.append(result)
245
-
246
- n = len(results)
247
- resolved = sum(1 for r in results if r["success"])
248
- total_cost = sum(r["total_cost"] for r in results)
249
- escalated = sum(1 for r in results if r["escalated"])
250
- terminated = sum(1 for r in results if r["terminated_early"])
251
-
252
- eval_results.append({
253
- "config": config_name,
254
- "n": n, "resolved": resolved,
255
- "success_rate": resolved / n,
256
- "total_cost": total_cost,
257
- "avg_cost": total_cost / n,
258
- "escalated": escalated,
259
- "terminated_early": terminated,
260
- "verifier_calls": sum(r["verifier_calls"] for r in results),
261
- "tool_skips": sum(r["tool_skips"] for r in results),
262
- })
263
-
264
- # ── 4. Compute Baselines ────────────────────────────────────────
265
- frontier_cost = sum(
266
- traces[tid].get("claude-opus-4.7", {}).get("cost", 0.317)
267
- for tid in traces
268
- )
269
- frontier_resolved = sum(
270
- 1 for tid in traces
271
- if traces[tid].get("claude-opus-4.7", {}).get("resolved", False)
272
- )
273
- cheap_cost = sum(
274
- traces[tid].get("deepseek-v4-flash", {}).get("cost", 0.014)
275
- for tid in traces
276
- )
277
- cheap_resolved = sum(
278
- 1 for tid in traces
279
- if traces[tid].get("deepseek-v4-flash", {}).get("resolved", False)
280
- )
281
-
282
- # Oracle: cheapest model that succeeded per task
283
- oracle_cost = 0
284
- oracle_resolved = 0
285
- for tid, ttraces in traces.items():
286
- best = None
287
- for m, mt in ttraces.items():
288
- if mt["resolved"] and (best is None or mt["cost"] < best["cost"]):
289
- best = mt
290
- if best:
291
- oracle_cost += best["cost"]
292
- oracle_resolved += 1
293
- else:
294
- oracle_cost += ttraces.get("claude-opus-4.7", {}).get("cost", 0.317)
295
-
296
- # ── 5. Print Results ────────────────────────────────────────────
297
- n = N_TASKS
298
- print(f"\n{'='*80}")
299
- print(f"ACO E2E BENCHMARK RESULTS ({n} SWE-bench tasks)")
300
- print(f"{'='*80}")
301
- print(f"\n{'Policy':<25} {'Resolved':>10} {'Rate':>10} {'AvgCost':>10} {'vsFrontier':>12}")
302
- print("-" * 67)
303
-
304
- full_ac = next(r for r in eval_results if r["config"] == "full_aco")["avg_cost"]
305
-
306
- for label, res, c in [
307
- ("ACO Full (all modules)",
308
- next(r for r in eval_results if r["config"] == "full_aco")["resolved"],
309
- next(r for r in eval_results if r["config"] == "full_aco")["avg_cost"]),
310
- ("Frontier (always claude)", frontier_resolved, frontier_cost/n),
311
- ("Always Cheap", cheap_resolved, cheap_cost/n),
312
- ("Oracle", oracle_resolved, oracle_cost/n),
313
- ]:
314
- cr = (1 - c / (frontier_cost/n)) * 100
315
- print(f" {label:<23} {res:>10} {res/n*100:>9.1f}% ${c:>9.4f} {cr:>11.1f}%")
316
-
317
- print(f"\n{'='*80}")
318
- print("ABLATION STUDY: Per-Module Impact")
319
- print(f"{'='*80}")
320
- print(f"\n{'Configuration':<25} {'Resolved':>10} {'Rate':>8} {'AvgCost':>10} {'vsFull':>10}")
321
- print("-" * 63)
322
-
323
- full_r = next(r for r in eval_results if r["config"] == "full_aco")
324
- for r in eval_results:
325
- dc = (r["avg_cost"] - full_r["avg_cost"]) / max(full_r["avg_cost"], 0.0001) * 100
326
- dr = r["resolved"] - full_r["resolved"]
327
- flag = ""
328
- if dc > 0 and dr < 0: flag = " ← COSTS MORE, WORSE"
329
- elif dc < 0 and dr >= 0: flag = " ← CHEAPER, SAME/BETTER"
330
- elif dc > 0 and dr >= 0: flag = " ← COSTS MORE, BETTER"
331
- elif dc < 0 and dr < 0: flag = " ← CHEAPER, WORSE"
332
- print(f" {r['config']:<23} {r['resolved']:>10} {r['resolved']/r['n']*100:>7.1f}% ${r['avg_cost']:>9.4f} {dc:>+9.1f}%{flag}")
333
-
334
- # ── 6. Cost-Quality Frontier ────────────────────────────────────
335
- print(f"\n{'='*80}")
336
- print("COST-QUALITY FRONTIER")
337
- print(f"{'='*80}")
338
-
339
- frontier_points = []
340
- for r in eval_results:
341
- frontier_points.append((r["avg_cost"], r["success_rate"], r["config"]))
342
-
343
- frontier_points.append((cheap_cost/n, cheap_resolved/n, "always_cheap"))
344
- frontier_points.append((frontier_cost/n, frontier_resolved/n, "frontier"))
345
- frontier_points.append((oracle_cost/n, oracle_resolved/n, "oracle"))
346
-
347
- frontier_points.sort(key=lambda x: x[0])
348
-
349
- print(f"\n {'Point':<25} {'Cost/task':>10} {'Success':>10} {'Dominated?':>12}")
350
- print(" " + "-" * 60)
351
-
352
- pareto = []
353
- for cost, succ, name in sorted(frontier_points, key=lambda x: (-x[1], x[0])):
354
- dominated = any(pc <= cost and ps >= succ and (pc < cost or ps > succ)
355
- for pc, ps, _ in pareto)
356
- if not dominated:
357
- pareto.append((cost, succ, name))
358
- print(f" {name:<25} ${cost:>9.4f} {succ*100:>9.1f}% {'✅ Pareto' if not dominated else '❌ Dominated':>12}")
359
-
360
- # ── 7. Save Results ─────────────────────────────────────────────
361
- output = {
362
- "n_tasks": n,
363
- "baselines": {
364
- "frontier": {"resolved": frontier_resolved, "rate": round(frontier_resolved/n,4),
365
- "total_cost": round(frontier_cost,2), "avg_cost": round(frontier_cost/n,4)},
366
- "always_cheap": {"resolved": cheap_resolved, "rate": round(cheap_resolved/n,4),
367
- "total_cost": round(cheap_cost,2), "avg_cost": round(cheap_cost/n,4)},
368
- "oracle": {"resolved": oracle_resolved, "rate": round(oracle_resolved/n,4),
369
- "total_cost": round(oracle_cost,2), "avg_cost": round(oracle_cost/n,4)},
370
- },
371
- "aco_configs": [
372
- {"config": r["config"], "resolved": r["resolved"],
373
- "rate": round(r["success_rate"], 4), "avg_cost": round(r["avg_cost"], 4),
374
- "escalations": r["escalated"], "early_terminations": r["terminated_early"],
375
- "verifier_calls": r["verifier_calls"], "tool_skips": r["tool_skips"]}
376
- for r in eval_results
377
- ],
378
- "full_aco_cost_reduction": round(
379
- (1 - full_ac / (frontier_cost/n)) * 100, 1
380
- ),
381
- "best_config": min(eval_results, key=lambda r: r["avg_cost"])["config"],
382
- "pareto_optimal": [name for cost, succ, name in pareto],
383
- }
384
-
385
- with open("/tmp/aco_e2e_standalone.json", "w") as f:
386
- json.dump(output, f, indent=2)
387
-
388
- from huggingface_hub import HfApi
389
- api = HfApi()
390
- api.upload_file(
391
- path_or_fileobj="/tmp/aco_e2e_standalone.json",
392
- path_in_repo="eval/e2e_standalone_results.json",
393
- repo_id="narcolepticchicken/agent-cost-optimizer", repo_type="model",
394
- )
395
-
396
- print(f"\n✓ Results: eval/e2e_standalone_results.json")
397
- print(f"\nDONE!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
training/e2e_v2_fixed.py DELETED
@@ -1,291 +0,0 @@
1
- """Standalone ACO E2E Benchmark v2 — Fixed cost model.
2
-
3
- Key fix: Use SWE-Router per-model costs directly instead of simulating
4
- phantom agent steps. The SWE-Router cost already includes the full agent
5
- run (all model calls, tool calls, etc).
6
-
7
- The ACO's job is to:
8
- 1. Route to a tier (choose model)
9
- 2. If that model fails, escalate
10
-
11
- Cost = sum of all models used until success or abandonment.
12
- """
13
- import json, sys, os, random, pickle
14
- from collections import defaultdict
15
- from typing import Dict
16
- import numpy as np
17
-
18
- # ── Core Router ──────────────────────────────────────────────────
19
- CODE_KW = ["python","javascript","code","function","bug","debug","refactor",
20
- "implement","test","compile","runtime","segfault","thread","async","class",
21
- "module","import","error","traceback"]
22
- CRITICAL_KW = ["critical","production","urgent","emergency","live","deployed","safety","security"]
23
- SIMPLE_KW = ["typo","simple","quick","brief","minor","small","easy","trivial","just"]
24
- RESEARCH_KW = ["research","investigate","compare","analyze","survey","paper"]
25
- TOOL_KW = ["search","fetch","retrieve","query","api","database","scrape","aggregate"]
26
- LONG_KW = ["plan","project","roadmap","orchestrate","migrate","pipeline","deploy","architecture"]
27
-
28
- FEAT_KEYS = sorted([
29
- 'req_len','num_words','has_code','n_code','has_legal','has_research',
30
- 'has_tool','has_critical','has_simple','has_long','has_math',
31
- 'has_error_msg','has_file_path','n_lines','has_version','has_add',
32
- 'has_fix','has_change','has_remove','has_test','has_doc',
33
- 'has_see_also','has_steps_to_reproduce',
34
- ])
35
-
36
- TIER_TO_MODEL = {1:'deepseek-v4-flash',2:'gpt-5-mini',3:'gemini-2.5-pro',
37
- 4:'claude-opus-4.7',5:'gemini-3-pro'}
38
- MODELS = ["deepseek-v4-flash","gpt-5-nano","gpt-5-mini","deepseek-v3.2",
39
- "gemini-2.5-pro","claude-opus-4.7","gpt-5.2","gemini-3-pro"]
40
-
41
- def extract_features(text: str) -> np.ndarray:
42
- r = text.lower()
43
- feats = {
44
- 'req_len':len(text),'num_words':len(text.split()),
45
- 'has_code':int(any(k in r for k in CODE_KW)),
46
- 'n_code':sum(1 for k in CODE_KW if k in r),
47
- 'has_legal':int(any(k in r for k in["contract","legal","compliance"])),
48
- 'has_research':int(any(k in r for k in RESEARCH_KW)),
49
- 'has_tool':int(any(k in r for k in TOOL_KW)),
50
- 'has_critical':int(any(k in r for k in CRITICAL_KW)),
51
- 'has_simple':int(any(k in r for k in SIMPLE_KW)),
52
- 'has_long':int(any(k in r for k in LONG_KW)),
53
- 'has_math':int(any(k in r for k in["calculate","compute","solve","equation"])),
54
- 'has_error_msg':int('error'in r or'traceback'in r or'exception'in r),
55
- 'has_file_path':int('/'in r),
56
- 'n_lines':text.count('\n')+1,
57
- 'has_version':int('version'in r or'update'in r),
58
- 'has_add':int('add'in r or'new'in r or'create'in r),
59
- 'has_fix':int('fix'in r or'bug'in r or'issue'in r),
60
- 'has_change':int('change'in r or'modify'in r),
61
- 'has_remove':int('remove'in r or'delete'in r),
62
- 'has_test':int('test'in r or'spec'in r),
63
- 'has_doc':int('doc'in r or'readme'in r),
64
- 'has_see_also':int('see also'in r or'related'in r),
65
- 'has_steps_to_reproduce':int('reproduce'in r or'steps'in r),
66
- }
67
- return np.array([float(feats.get(k,0))for k in FEAT_KEYS],dtype=np.float32)
68
-
69
- # ── Load Router ──────────────────────────────────────────────────
70
- from huggingface_hub import hf_hub_download
71
- print("Loading router...")
72
- try:
73
- bundle_path = hf_hub_download(repo_id="narcolepticchicken/agent-cost-optimizer",
74
- filename="router_models/router_bundle_v10_fixed.pkl")
75
- bundle = pickle.load(open(bundle_path,'rb'))
76
- tier_clfs = {int(k):v for k,v in bundle.get('tier_clfs',{}).items()}
77
- tier_calibs = {int(k):v for k,v in bundle.get('tier_calibrators',{}).items()}
78
- print(f" v10 router loaded: {len(tier_clfs)} classifiers")
79
- except Exception as e:
80
- print(f" WARNING: {e}, using fallback")
81
- tier_clfs = {}
82
- tier_calibs = {}
83
-
84
- def route(text: str, thresh: float = 0.5) -> int:
85
- if not tier_clfs: return 1
86
- x = extract_features(text).reshape(1,-1)
87
- for t in range(1,6):
88
- if t in tier_clfs:
89
- try:
90
- p = tier_clfs[t].predict_proba(x)[0,1]
91
- p = float(tier_calibs[t].transform([p])[0])
92
- if p >= thresh: return t
93
- except: pass
94
- return 5
95
-
96
- # ── 1. Load SWE-Router ──────────────────────────────────────────
97
- from datasets import load_dataset
98
- print("\n[1] Loading SWE-Router...")
99
- traces = defaultdict(dict)
100
- for m in MODELS:
101
- ds = load_dataset(f"SWE-Router/swebench-verified-{m}", split="test")
102
- for row in ds:
103
- traces[row["instance_id"]][m] = {
104
- "resolved": row["resolved"],
105
- "cost": float(row["instance_cost"]),
106
- }
107
- print(f" {len(traces)} tasks × {len(MODELS)} models")
108
-
109
- # ── 2. Simulate ACO ─────────────────────────────────────────────
110
- # Cost model: just sum the costs of each model we try.
111
- # ACO routes tier T → execute → if fail, try T+1 → etc.
112
- # Success = first successful tier's resolution.
113
- # Cost = sum of costs of all tiers attempted.
114
-
115
- print("\n[2] Simulating...")
116
-
117
- def aco_cost(task_id: str, problem: str,
118
- use_router: bool = True,
119
- use_feedback: bool = True,
120
- use_verifier: bool = True,
121
- max_tiers: int = 5,
122
- verifier_cost_factor: float = 1.05) -> Dict:
123
- """ACO decision + execution: route, execute, escalate if feedback on."""
124
- tier = route(problem) if use_router else 4
125
- total_cost = 0.0
126
- resolved = False
127
- tiers_tried = 0
128
- escalated = False
129
- verifier_cost = 0.0
130
-
131
- while tiers_tried < max_tiers:
132
- model = TIER_TO_MODEL.get(tier, "claude-opus-4.7")
133
- mt = traces[task_id].get(model, {})
134
- step_cost = mt.get("cost", 0.30)
135
-
136
- if use_verifier and tier <= 2:
137
- step_cost *= verifier_cost_factor
138
- verifier_cost += step_cost * (verifier_cost_factor - 1)
139
-
140
- total_cost += step_cost
141
- tiers_tried += 1
142
-
143
- if mt.get("resolved", False):
144
- resolved = True
145
- break
146
-
147
- if not use_feedback:
148
- break # no escalation
149
-
150
- if tier >= 5:
151
- break
152
-
153
- tier += 1
154
- escalated = True
155
-
156
- return {
157
- "total_cost": total_cost,
158
- "resolved": resolved,
159
- "escalated": escalated,
160
- "tiers_tried": tiers_tried,
161
- "verifier_cost": verifier_cost,
162
- "initial_tier": tier if not escalated else tier - tiers_tried + 1,
163
- }
164
-
165
- # ── 3. Run all configs ──────────────────────────────────────────
166
- configs = {
167
- "full_aco": (True, True, True),
168
- "no_router": (False, True, True),
169
- "no_feedback": (True, False, True),
170
- "no_verifier": (True, True, False),
171
- "router_only": (True, False, False),
172
- "frontier_always": (False, False, False),
173
- }
174
-
175
- results_by_config = {}
176
- for cname, (router, feedback, verifier) in configs.items():
177
- rlist = []
178
- for tid, ttraces in traces.items():
179
- problem = next(iter(ttraces.values())).get("problem", "")
180
- rlist.append(aco_cost(tid, problem, router, feedback, verifier))
181
- results_by_config[cname] = rlist
182
-
183
- # ── 4. Baselines ────────────────────────────────────────────────
184
- N = len(traces)
185
- frontier_resolved = sum(1 for tid in traces if traces[tid].get("claude-opus-4.7",{}).get("resolved",False))
186
- frontier_cost = sum(traces[tid].get("claude-opus-4.7",{}).get("cost",0.317) for tid in traces)
187
- cheap_resolved = sum(1 for tid in traces if traces[tid].get("deepseek-v4-flash",{}).get("resolved",False))
188
- cheap_cost = sum(traces[tid].get("deepseek-v4-flash",{}).get("cost",0.014) for tid in traces)
189
- oracle_cost = 0; oracle_resolved = 0
190
- for tid, tt in traces.items():
191
- best = None
192
- for m, mt in tt.items():
193
- if mt["resolved"] and (best is None or mt["cost"] < best["cost"]):
194
- best = mt
195
- if best:
196
- oracle_cost += best["cost"]; oracle_resolved += 1
197
- else:
198
- oracle_cost += tt.get("claude-opus-4.7",{}).get("cost",0.317)
199
-
200
- # ── 5. Print ────────────────────────────────────────────────────
201
- fc = frontier_cost / N
202
- print(f"\n{'='*80}")
203
- print(f"ACO E2E RESULTS v2 — 500 SWE-bench tasks")
204
- print(f"{'='*80}")
205
- print(f"\n{'Policy':<25} {'Resolved':>10} {'Rate':>10} {'AvgCost':>10} {'vsFrontier':>12} {'Pareto?':>10}")
206
- print("-" * 77)
207
-
208
- all_points = []
209
- for label, data in [
210
- ("ACO Full", results_by_config["full_aco"]),
211
- ("ACO Router+Feedback", results_by_config["no_verifier"]),
212
- ("ACO Router Only", results_by_config["router_only"]),
213
- ("ACO No Feedback", results_by_config["no_feedback"]),
214
- ("ACO No Router", results_by_config["no_router"]),
215
- ("Always Cheap", None),
216
- ("Frontier Always", None),
217
- ("Oracle", None),
218
- ]:
219
- if label == "Always Cheap":
220
- r, c = cheap_resolved, cheap_cost/N
221
- elif label == "Frontier Always":
222
- r, c = frontier_resolved, fc
223
- elif label == "Oracle":
224
- r, c = oracle_resolved, oracle_cost/N
225
- else:
226
- r = sum(1 for d in data if d["resolved"])
227
- c = sum(d["total_cost"] for d in data) / N
228
-
229
- cr = (1 - c/fc)*100
230
- all_points.append((label, r, c, cr))
231
-
232
- print(f" {label:<23} {r:>10} {r/N*100:>9.1f}% ${c:>9.4f} {cr:>11.1f}% {'':>10}")
233
-
234
- # Pareto analysis
235
- print(f"\n{'='*80}")
236
- print("PARETO FRONTIER")
237
- print(f"{'='*80}")
238
- pareto_set = []
239
- for label, r, c, cr in sorted(all_points, key=lambda x: (-x[1], x[0])):
240
- dominated = any(pr >= r and pc <= c and (pr > r or pc < c) for _, pr, pc, _ in pareto_set)
241
- pareto_set.append((label, r, c, cr))
242
- print(f" {label:<25} {r/N*100:>9.1f}% ${c:>9.4f} {'✅ PARETO-OPTIMAL' if not dominated else '❌ Dominated'}")
243
-
244
- # Module impact
245
- print(f"\n{'='*80}")
246
- print("PER-MODULE IMPACT (cost delta from full ACO)")
247
- print(f"{'='*80}")
248
- full_r = next(l for l in all_points if l[0] == "ACO Full")
249
- for label, r, c, cr in all_points:
250
- if label == "ACO Full": continue
251
- dc = (c - full_r[2]) / max(full_r[2], 0.0001) * 100
252
- dr = r - full_r[1]
253
- note = ""
254
- if dc < 0 and dr >= 0: note = "← IMPROVEMENT (cheaper, no quality loss)"
255
- elif dc < 0: note = f"← Cheaper but lost {abs(dr)} resolves"
256
- elif dr >= 0: note = f"← Better quality at +${c-full_r[2]:.4f}"
257
- print(f" {label:<23} {dc:>+7.1f}% Δcost {dr:>+4} resolves {note}")
258
-
259
- # ── 6. Save ─────────────────────────────────────────────────────
260
- output = {
261
- "n": N,
262
- "configs": {
263
- name: {
264
- "resolved": sum(1 for d in data if d["resolved"]),
265
- "rate": round(sum(1 for d in data if d["resolved"])/N, 4),
266
- "avg_cost": round(sum(d["total_cost"] for d in data)/N, 4),
267
- "total_cost": round(sum(d["total_cost"] for d in data), 2),
268
- "avg_tiers_tried": round(sum(d["tiers_tried"] for d in data)/N, 2),
269
- "escalated_rate": round(sum(1 for d in data if d["escalated"])/N, 2),
270
- "verifier_cost": round(sum(d["verifier_cost"] for d in data), 2),
271
- } for name, data in results_by_config.items()
272
- },
273
- "baselines": {
274
- "frontier": {"resolved": frontier_resolved, "rate": round(frontier_resolved/N,4), "avg_cost": round(fc,4)},
275
- "always_cheap": {"resolved": cheap_resolved, "rate": round(cheap_resolved/N,4), "avg_cost": round(cheap_cost/N,4)},
276
- "oracle": {"resolved": oracle_resolved, "rate": round(oracle_resolved/N,4), "avg_cost": round(oracle_cost/N,4)},
277
- },
278
- }
279
-
280
- with open("/tmp/aco_e2e_v2_fixed.json","w") as f:
281
- json.dump(output, f, indent=2)
282
-
283
- from huggingface_hub import HfApi
284
- api = HfApi()
285
- api.upload_file(
286
- path_or_fileobj="/tmp/aco_e2e_v2_fixed.json",
287
- path_in_repo="eval/e2e_v2_fixed_results.json",
288
- repo_id="narcolepticchicken/agent-cost-optimizer", repo_type="model",
289
- )
290
- print(f"\n✓ eval/e2e_v2_fixed_results.json")
291
- print("DONE!")