|
| 1 | +""" |
| 2 | +LHAW Constants |
| 3 | +============== |
| 4 | +
|
| 5 | +Centralized defaults for all scripts. Import these instead of hardcoding values. |
| 6 | +
|
| 7 | +Usage: |
| 8 | + from constants import DEFAULTS, MODELS |
| 9 | +
|
| 10 | + parser.add_argument("--num_trials", type=int, default=DEFAULTS["num_trials"]) |
| 11 | +""" |
| 12 | + |
| 13 | +import os |
| 14 | + |
| 15 | +# ============================================================================= |
| 16 | +# DEFAULT CONFIGURATION |
| 17 | +# ============================================================================= |
| 18 | +# Canonical values used across all entrypoints. Change here to affect everything. |
| 19 | + |
| 20 | +DEFAULTS = { |
| 21 | + # Trials |
| 22 | + "num_trials": 3, # Number of rollouts per task/variant (for pass@k) |
| 23 | + # Parallelism |
| 24 | + "parallel_variants": 1, # Sequential by default to avoid OOM; override with PARALLEL_VARIANTS=N |
| 25 | + # Agent limits |
| 26 | + "max_iterations": 100, # Max agent steps per task |
| 27 | + # Underspec generation |
| 28 | + "max_level": 2, # Segments to remove together (1=single, 2=pairs) |
| 29 | + "max_variants": None, # None = no limit (use top_k_per_level in pipeline) |
| 30 | + "severity": "delete", # Removal strategy: delete, vaguify, genericize |
| 31 | + # Default model for agent evaluation |
| 32 | + "model": "opus_4_5", |
| 33 | + # Docker cleanup |
| 34 | + "cleanup_interval": 10, # Prune containers every N completed variants |
| 35 | + # Benchmark filtering |
| 36 | + "max_total": 100, # Max total samples in filtered benchmark |
| 37 | + "max_per_task_tac": 10, # Max samples per original task (TAC) |
| 38 | + "max_per_task_swebench": 8, # Max samples per original instance (SWE-bench) |
| 39 | + "seed": 42, # Random seed for reproducibility |
| 40 | + # Container timeouts (SWE-bench) |
| 41 | + "startup_timeout": 600, # Container startup timeout in seconds |
| 42 | + "runtime_timeout": 900, # Container runtime timeout in seconds |
| 43 | + # Parallelism |
| 44 | + "concurrency": 10, # Parallel completions (MCP-Atlas, SWE-bench) |
| 45 | +} |
| 46 | + |
| 47 | +# ============================================================================= |
| 48 | +# MODEL SHORTCUTS |
| 49 | +# ============================================================================= |
| 50 | +# Short names → full model identifiers for LiteLLM/OpenAI API |
| 51 | + |
| 52 | +MODELS = { |
| 53 | + # Standard LiteLLM model identifiers (provider/model-name). |
| 54 | + # When LLM_BASE_URL is set (proxy mode), "litellm_proxy/" is auto-prepended |
| 55 | + # at runtime so LiteLLM routes through the proxy. For direct provider access, |
| 56 | + # leave LLM_BASE_URL unset and set provider-specific API keys instead |
| 57 | + # (e.g. ANTHROPIC_API_KEY, OPENAI_API_KEY, GEMINI_API_KEY). |
| 58 | + # |
| 59 | + # Anthropic |
| 60 | + "opus_4_5": "anthropic/claude-opus-4-5-20251101", |
| 61 | + "sonnet_4_5": "anthropic/claude-sonnet-4-5-20250929", |
| 62 | + "opus_4_6": "anthropic/claude-opus-4-6-20260205", |
| 63 | + "sonnet_4_6": "anthropic/claude-sonnet-4-6", |
| 64 | + "sonnet_4": "anthropic/claude-sonnet-4-20250514", |
| 65 | + "haiku_4_5": "anthropic/claude-haiku-4-5-20251001", |
| 66 | + # OpenAI |
| 67 | + "gpt_5_2": "openai/gpt-5.2-2025-12-11", |
| 68 | + "gpt_5_1": "openai/gpt-5.1-2025-11-13", |
| 69 | + "gpt_5": "openai/gpt-5-2025-08-07", |
| 70 | + "o3_pro": "openai/o3-pro-2025-06-10", |
| 71 | + "o3": "openai/o3-2025-04-16", |
| 72 | + "gpt_4_1_mini": "openai/gpt-4.1-mini", |
| 73 | + # Google |
| 74 | + "gemini_3_pro": "gemini/gemini-3-pro-preview", |
| 75 | + "gemini_3_flash": "gemini/gemini-3-flash-preview", |
| 76 | + "gemini_3_1_pro": "gemini/gemini-3.1-pro-preview", |
| 77 | + "gemini_3_1_flash_lite": "gemini/gemini-3.1-flash-lite-preview", |
| 78 | + # Other |
| 79 | + "kimi_k2": "fireworks_ai/kimi-k2-instruct-0905", |
| 80 | + "qwen3_235b": "fireworks_ai/qwen3-235b-a22b", |
| 81 | + "llama4_maverick": "fireworks_ai/llama4-maverick-instruct-basic", |
| 82 | + "glm_4p5_air": "fireworks_ai/glm-4p5-air", |
| 83 | + "nova_2_lite": "bedrock/global.amazon.nova-2-lite-v1:0", |
| 84 | +} |
| 85 | + |
| 86 | +# ============================================================================= |
| 87 | +# PATH CONSTANTS |
| 88 | +# ============================================================================= |
| 89 | +# Relative to REPO_ROOT (computed at import time by each script) |
| 90 | + |
| 91 | +PATHS = { |
| 92 | + "synthetic_outputs": "synthetic/outputs", |
| 93 | + "tac_tasks": "task_pairs_agentcompany", |
| 94 | + "runs_dir": "experiments/agentcompany/runs", |
| 95 | + "tac_golden_trajectories": "experiments/agentcompany/golden_trajectories", |
| 96 | +} |
| 97 | + |
| 98 | +# ============================================================================= |
| 99 | +# LHAW BENCHMARK TASKS |
| 100 | +# ============================================================================= |
| 101 | +# 13 TAC tasks selected for LHAW (avg_ckpt_acc >= 0.5 across reference models) |
| 102 | + |
| 103 | +SELECTED_TASKS = [ |
| 104 | + "ds_answer_numerical_data_question", |
| 105 | + "ds_fix_table_values_and_missing_answers", |
| 106 | + "ds_format_excel_sheets", |
| 107 | + "ds_predictive_modeling", |
| 108 | + "ds_visualize_data_in_pie_and_bar_chart", |
| 109 | + "finance_budget_variance", |
| 110 | + "finance_check_attendance_payroll", |
| 111 | + "finance_expense_validation", |
| 112 | + "hr_check_attendance_multiple_days", |
| 113 | + "hr_check_attendance_one_day", |
| 114 | + "hr_create_employee_manual", |
| 115 | + "hr_new_grad_job_description", |
| 116 | + "sde_create_sqlite_database", |
| 117 | +] |
| 118 | + |
| 119 | + |
| 120 | +VARIANT_DELIMITER = "__V_" |
| 121 | + |
| 122 | + |
| 123 | +def parse_variant_id(instance_id: str) -> tuple: |
| 124 | + """Parse a SWE-bench variant instance ID into (original_id, variant_suffix). |
| 125 | +
|
| 126 | + Returns (original_id, variant_suffix) where variant_suffix is "" for originals. |
| 127 | + Example: "inst_foo__V_S1_delete" → ("inst_foo", "S1_delete") |
| 128 | + "inst_foo" → ("inst_foo", "") |
| 129 | + """ |
| 130 | + if VARIANT_DELIMITER in instance_id: |
| 131 | + original_id, variant_suffix = instance_id.split(VARIANT_DELIMITER, 1) |
| 132 | + return original_id, variant_suffix |
| 133 | + return instance_id, "" |
| 134 | + |
| 135 | + |
| 136 | +def print_bash_models() -> None: |
| 137 | + """Print MODELS as a bash associative array declaration. |
| 138 | +
|
| 139 | + Shell scripts source this via: |
| 140 | + eval "$(python3 constants.py bash_models)" |
| 141 | + """ |
| 142 | + pairs = " ".join(f'["{k}"]="{v}"' for k, v in MODELS.items()) |
| 143 | + print(f"declare -A MODELS=({pairs})") |
| 144 | + |
| 145 | + |
| 146 | +def get_model(key: str) -> str: |
| 147 | + """Get full model identifier from shortcut, or return as-is if not found.""" |
| 148 | + return MODELS.get(key, key) |
| 149 | + |
| 150 | + |
| 151 | +def uses_litellm_proxy() -> bool: |
| 152 | + """Check if LLM_BASE_URL points to a LiteLLM proxy. |
| 153 | +
|
| 154 | + Returns True when LLM_BASE_URL contains "litellm" (e.g. |
| 155 | + ``https://litellm-proxy.{DOMAIN}.com/v1``). The ``litellm_proxy/`` |
| 156 | + model prefix is only needed when OpenHands routes through such a proxy. |
| 157 | + """ |
| 158 | + base_url = os.environ.get("LLM_BASE_URL", "").lower() |
| 159 | + return "litellm-proxy" in base_url |
| 160 | + |
| 161 | + |
| 162 | +def resolve_model(key: str) -> str: |
| 163 | + """Get model identifier with litellm_proxy/ prefix when using a LiteLLM proxy. |
| 164 | +
|
| 165 | + When LLM_BASE_URL points to a LiteLLM proxy, the model needs the |
| 166 | + ``litellm_proxy/`` prefix so the LiteLLM SDK routes through the proxy. |
| 167 | + Otherwise, returns the standard LiteLLM identifier for direct provider |
| 168 | + access (e.g. ``anthropic/claude-sonnet-4-6``). |
| 169 | + """ |
| 170 | + model = get_model(key) |
| 171 | + if uses_litellm_proxy() and not model.startswith("litellm_proxy/"): |
| 172 | + return f"litellm_proxy/{model}" |
| 173 | + return model |
| 174 | + |
| 175 | + |
| 176 | +if __name__ == "__main__": |
| 177 | + import sys |
| 178 | + |
| 179 | + if len(sys.argv) > 1 and sys.argv[1] == "bash_models": |
| 180 | + print_bash_models() |
| 181 | + else: |
| 182 | + print(f"Usage: {sys.argv[0]} bash_models", file=sys.stderr) |
| 183 | + sys.exit(1) |
0 commit comments