Spaces:
Runtime error
Runtime error
| #!/usr/bin/env python3 | |
| """ | |
| Baseline Agent — GPT-4o-mini on CodeReviewEnv | |
| Runs the GPT-4o-mini model against all three tasks and records scores. | |
| Requires OPENAI_API_KEY environment variable. | |
| Usage: | |
| OPENAI_API_KEY=sk-... python baseline/run_baseline.py | |
| """ | |
| import json | |
| import os | |
| import sys | |
| import statistics | |
| from datetime import datetime, timezone | |
| # Add parent directory to path | |
| sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) | |
| from env.base import CodeReviewEnv | |
| from env.models import Action | |
| def run_baseline(): | |
| """Run GPT-4o-mini baseline across all tasks via OpenRouter.""" | |
| api_key = os.environ.get("OPENROUTER_API_KEY") or os.environ.get("OPENAI_API_KEY") | |
| if not api_key: | |
| print("ERROR: OPENROUTER_API_KEY or OPENAI_API_KEY not set.") | |
| print("Usage: OPENROUTER_API_KEY=sk-... python baseline/run_baseline.py") | |
| sys.exit(1) | |
| from openai import OpenAI | |
| client = OpenAI( | |
| api_key=api_key, | |
| base_url="https://openrouter.ai/api/v1", | |
| ) | |
| model = "openai/gpt-4o-mini" | |
| seed = 42 | |
| n_episodes = 3 | |
| results = {} | |
| for task in ["easy", "medium", "hard"]: | |
| print(f"\n{'='*40}") | |
| print(f"Running {task} task — {n_episodes} episodes") | |
| print(f"{'='*40}") | |
| episode_scores = [] | |
| for ep in range(n_episodes): | |
| episode_seed = seed + ep | |
| env = CodeReviewEnv(task=task, seed=episode_seed) | |
| obs = env.reset() | |
| system_prompt = env.get_system_prompt() | |
| step_rewards = [] | |
| done = False | |
| max_steps = 50 | |
| while not done and len(step_rewards) < max_steps: | |
| # Build user message from observation | |
| user_msg = json.dumps(obs.model_dump(), indent=2, default=str) | |
| try: | |
| response = client.chat.completions.create( | |
| model=model, | |
| messages=[ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": user_msg}, | |
| ], | |
| temperature=0, | |
| seed=seed, | |
| max_tokens=500, | |
| ) | |
| response_text = response.choices[0].message.content.strip() | |
| # Try to parse JSON — handle common LLM output quirks | |
| # 1. Strip markdown code blocks | |
| if "```" in response_text: | |
| import re | |
| code_match = re.search(r'```(?:json)?\s*\n?(.*?)\n?\s*```', response_text, re.DOTALL) | |
| if code_match: | |
| response_text = code_match.group(1).strip() | |
| # 2. Extract first JSON object (ignore trailing explanation text) | |
| brace_start = response_text.find("{") | |
| if brace_start >= 0: | |
| depth = 0 | |
| for i, ch in enumerate(response_text[brace_start:], start=brace_start): | |
| if ch == "{": | |
| depth += 1 | |
| elif ch == "}": | |
| depth -= 1 | |
| if depth == 0: | |
| response_text = response_text[brace_start:i+1] | |
| break | |
| action_dict = json.loads(response_text) | |
| action = Action(**action_dict) | |
| except Exception as e: | |
| print(f" Parse error at step {len(step_rewards)}: {e}") | |
| # Fallback action | |
| if task == "easy": | |
| action = Action(action_type="label_severity", severity="none") | |
| elif task == "medium": | |
| action = Action( | |
| action_type="prioritize", | |
| priority_order=obs.review_queue, | |
| ) | |
| else: | |
| action = Action(action_type="approve") | |
| obs, reward, done, info = env.step(action) | |
| step_rewards.append(reward.value) | |
| ep_score = sum(step_rewards) / len(step_rewards) if step_rewards else 0.0 | |
| episode_scores.append(round(ep_score, 2)) | |
| print(f" Episode {ep + 1}: score={ep_score:.3f} ({len(step_rewards)} steps)") | |
| mean_score = statistics.mean(episode_scores) | |
| std_score = statistics.stdev(episode_scores) if len(episode_scores) > 1 else 0.0 | |
| results[task] = { | |
| "mean": round(mean_score, 2), | |
| "std": round(std_score, 2), | |
| "episodes": episode_scores, | |
| } | |
| print(f"\n {task}: mean={mean_score:.3f} std={std_score:.3f}") | |
| # Print summary table | |
| print(f"\n{'='*60}") | |
| print(f"{'Task':<10} | {'Episodes':>8} | {'Mean':>6} | {'Std':>6} | {'Min':>6} | {'Max':>6}") | |
| print(f"{'-'*10}-+-{'-'*8}-+-{'-'*6}-+-{'-'*6}-+-{'-'*6}-+-{'-'*6}") | |
| for task in ["easy", "medium", "hard"]: | |
| r = results[task] | |
| eps = r["episodes"] | |
| print( | |
| f"{task:<10} | {len(eps):>8} | {r['mean']:>6.2f} | {r['std']:>6.2f} | " | |
| f"{min(eps):>6.2f} | {max(eps):>6.2f}" | |
| ) | |
| # Save results | |
| output = { | |
| **results, | |
| "model": model, | |
| "seed": seed, | |
| "timestamp": datetime.now(timezone.utc).isoformat(), | |
| } | |
| output_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "results.json") | |
| with open(output_path, "w") as f: | |
| json.dump(output, f, indent=2) | |
| print(f"\nResults saved to {output_path}") | |
| if __name__ == "__main__": | |
| run_baseline() | |