Skip to main content

IMO-AnswerBench

IMO-AnswerBench evaluates mathematical-answer extraction and scoring on Hwilner/imo-answerbench.

Prerequisites

Run from the repository root:

source scripts/activate.sh
export PYTHONPATH=$PWD

export OPENAI_BASE_URL=https://models.sjtu.edu.cn/api/v1/
export OPENAI_API_KEY=sk-...
export OPENAI_MODEL_NAME=minimax-m2.5

The benchmark loads from HuggingFace. If the default mirror is slow, set HF_ENDPOINT before running.

If the host cannot reach huggingface.co directly, set:

export HF_ENDPOINT=https://hf-mirror.com

The April 22, 2026 local-vLLM Qwen follow-up on this repo required that override before imo_answerbench could load at all.

Supported Modes

ModeStatusConfig
direct_llmsmoke config availableconfigs/examples/directllm_minimax_imo_answerbench.yaml
opencodesmoke config availableconfigs/examples/opencode_minimax_imo_answerbench.yaml
openclawsmoke config availableconfigs/examples/openclaw_minimax_imo_answerbench.yaml
zeroclawsmoke config availableconfigs/examples/zeroclaw_imo_answerbench.yaml

The DirectLLM, OpenCode, and OpenClaw configs pin dataset_index: 367. The ZeroClaw config uses only max_tasks: 1, so it selects the first eligible row.

Additional April 18/19, 2026 pilot configs are also checked in:

  • configs/examples/directllm_qwen35_27b_imo_answerbench_pilot.yaml
  • configs/examples/openclaw_qwen35_27b_imo_answerbench_pilot.yaml
  • configs/examples/opencode_qwen35_27b_imo_answerbench_pilot.yaml

These pilot configs use max_tasks: 3 and the OpenRouter slug qwen/qwen3.5-27b for the logical model target Qwen/Qwen3.5-27B. The dedicated opencode pilot config intentionally omits the smoke dataset_index: 367 pin so it can load three distinct tasks.

Full Runs

This checkout does not ship IMO-AnswerBench full-run configs. Start from the appropriate checked-in smoke or Qwen pilot config, remove the bounded task selector, and review the model, output, timeout, and concurrency contract before a full evaluation. Keep scorer.name: imo_verify.

Current OpenRouter free-text follow-up on April 22, 2026 uses nvidia/nemotron-3-nano-30b-a3b:free. Early full-run evidence:

  • full_20260422_openrouter_nemotron_3_nano_30b_a3b_imo_answerbench_directllm_r1 writes normal task JSONs, but many early answers collapse to short scalar outputs even on symbolic-ground-truth items
  • ..._opencode_r1 is the healthiest current path and already wrote normal score=1 and score=0 task records
  • ..._openclaw_r1 still preserves predicted=null with metadata.partial_reasoning_only=true
  • ..._zeroclaw_r1 still fails the first task with score_status=runtime_error and metadata.failure_reason=empty_response

DirectLLM

DirectLLM calls the OpenAI-compatible endpoint directly and scores the returned answer with imo_verify. Checked-in IMO configs now enforce scorer.name: imo_verify, and config validation rejects benchmark.name: imo_answerbench with any other scorer. Historical IMO runs scored with math_verify should be treated as non-canonical audit artifacts, not current support evidence. imo_verify is still a repo-local heuristic scorer, not an external official verifier. The current implementation is intentionally conservative: it blocks the old symbolic-to-numeric false positives, but it can still over-split some comma-heavy answer forms and therefore still carries false-negative risk. For short OpenRouter canaries on Qwen/Qwen3.5-27B, set agent.config.extra_body.reasoning.enabled=false when you want terse outputs. The provider otherwise emits hidden reasoning tokens even for tiny prompts, which can dominate latency without changing the visible boxed answer. This is a canary-only override; benchmark defaults still keep reasoning enabled unless you explicitly change them.

python -m alphadiana.cli run configs/examples/directllm_minimax_imo_answerbench.yaml \
-o run_id=imo_directllm_smoke

Local-vLLM Qwen example with the rollout-plan temperature=0.0 semantics:

source scripts/activate.sh
export PYTHONPATH=$PWD
export HF_ENDPOINT=https://hf-mirror.com
export QWEN_VLLM_API_BASE=http://127.0.0.1:8011/v1
export QWEN_VLLM_API_KEY=EMPTY

python -m alphadiana.cli run configs/examples/directllm_minimax_imo_answerbench.yaml \
-o run_id=full_20260422_imo_answerbench_direct_llm_qwen35_27b_localvllm_mc20_r1 \
-o output_dir=./results/full_20260422_imo_answerbench_direct_llm_qwen35_27b_localvllm_mc20_r1 \
-o max_concurrent=20 \
-o agent.config.model='Qwen/Qwen3.5-27B' \
-o agent.config.api_base="$QWEN_VLLM_API_BASE" \
-o agent.config.api_key="$QWEN_VLLM_API_KEY" \
-o agent.config.temperature=0.0 \
-o agent.config.top_p=0.95 \
-o agent.config.max_tokens=32768 \
-o agent.config.stream=true

This command scales a bounded smoke config with overrides. Review and remove its task-selection limit before treating it as a full evaluation.

On current main, direct_llm captures logprobs by default. For a local-vLLM Qwen pilot, use configs/examples/directllm_qwen35_27b_imo_answerbench_pilot.yaml.

OpenCode

OpenCode runs the opencode CLI. The checked-in minimax smoke config includes OpenCode-specific external agent settings (agent: lean-math and agent_md_path: alphadiana/context/opencode_lean_math.md) in addition to agent.config.system_prompt. When comparing harness prompts or running local Qwen logprob smoke without that external agent layer, override both fields to empty strings.

Build the controller image once before using the checked-in OpenCode configs:

docker build --network host \
-f alphadiana/benchmarks/terminal_bench2/deploy/dockerfiles/Dockerfile.opencode-controller \
-t alphadiana/tb2-opencode-controller:latest .
python -m alphadiana.cli run configs/examples/opencode_minimax_imo_answerbench.yaml \
-o run_id=imo_opencode_smoke

Local-vLLM Qwen logprob smoke with the external agent disabled:

python -m alphadiana.cli run configs/examples/opencode_minimax_imo_answerbench.yaml \
--redo-all \
-o run_id=phase11_opencode_imo_answerbench_qwen35_27b_logprobs_smoke \
-o output_dir=./results \
-o agent.config.model=custom/Qwen/Qwen3.5-27B \
-o agent.config.model_name=Qwen/Qwen3.5-27B \
-o agent.config.api_base=http://127.0.0.1:8011/v1 \
-o agent.config.api_key=EMPTY \
-o agent.config.controller_mode=docker \
-o agent.config.controller_network=host \
-o agent.config.capture_logprobs=true \
-o agent.config.top_logprobs=20 \
-o agent.config.agent= \
-o agent.config.agent_md_path=

Observed on April 24, 2026: this command wrote results/phase11_opencode_imo_answerbench_qwen35_27b_logprobs_smoke/tasks/imo-bench-number_theory-068.json with score=1.0, metadata.logprobs_capture_status="captured", and token_entropy_stats.n_tokens=11949. The preserved OpenCode config/listing showed no external agent/*.md file.

The checked-in OpenCode benchmark configs now use Docker controller isolation by default. If you need the old host-process path for debugging, override -o agent.config.controller_mode=host.

The smoke config uses timeout: 1800 because shorter bounds can kill valid slow model output before it reaches scoring. The full Docker setup and reproduction guidance is in the OpenCode harness guide.

OpenClaw

OpenClaw uses ROCK auto-deploy and the gateway config in alphadiana/harness/openclaw/deploy/. Benchmark fairness now requires a fresh ROCK sandbox session per task for openclaw; do not treat older sequential runs that reused one shared session across tasks as comparable evidence. Current main also skips the OpenClaw chat-completions warmup by default on benchmark runs because that warmup could pollute the first task with a leftover READY/bootstrap response.

python -m alphadiana.cli run configs/examples/openclaw_minimax_imo_answerbench.yaml \
-o run_id=imo_openclaw_smoke

ROCK services must be healthy before this run. scripts/activate.sh loads the local ROCK port configuration.

Current OpenRouter free-text full-run evidence on April 22, 2026: full_20260422_openrouter_nemotron_3_nano_30b_a3b_imo_answerbench_openclaw_r1 continues to reproduce the same failure shape from smoke scale-up: normal task JSONs are written, but early tasks preserve predicted=null with metadata.partial_reasoning_only=true.

ZeroClaw

ZeroClaw uses the same ROCK auto-deploy path as the PR23 AIME integration.

Unlike the AIME quickstart in the main README.md, the formal benchmark smoke here is counted only when the task executes inside a ROCK sandbox. Do not clear agent.config.rock_image for the benchmark smoke.

Start ROCK first:

bash scripts/start_zeroclaw.sh
source scripts/rock_env.sh

If another branch is already using ROCK, edit scripts/.rock_ports.env before startup so this worktree gets isolated admin/proxy/redis/ray ports.

python -m alphadiana.cli run configs/examples/zeroclaw_imo_answerbench.yaml \
-o run_id=imo_zeroclaw_smoke

Current OpenRouter free-text full-run evidence on April 22, 2026: full_20260422_openrouter_nemotron_3_nano_30b_a3b_imo_answerbench_zeroclaw_r1 still fails its first task as score_status=runtime_error with metadata.failure_reason=empty_response, even though current main preserves the failure record cleanly.

Reproduce The 2026-04-17 Formal Sandbox Smoke

This is the exact smoke style used for local validation of the ZeroClaw sandbox path. It intentionally forces a fast wrong answer so the run terminates quickly with dashboard X, which is enough for the execution-path smoke criterion.

export OPENAI_BASE_URL=https://models.sjtu.edu.cn/api/v1/
export OPENAI_API_KEY=sk-...
export OPENAI_MODEL_NAME=minimax

python -m alphadiana.cli run configs/examples/zeroclaw_imo_answerbench.yaml \
-o run_id=pr26_formal_smoke_zeroclaw_imo_minimax_rock_cli_box0_20260417_v2 \
-o benchmark.config.dataset_index=0 \
-o agent.config.system_prompt='Smoke test mode: ignore the math problem. Do not use tools. Output exactly $$\\boxed{0}$$ and nothing else.'

Expected result:

  • dashboard: X
  • task file exists under results/zeroclaw_imo_answerbench_smoke/<run_id>/tasks/
  • data[0] in the single-sample task JSON list has no error
  • the recorded task uses the dataset row's Problem ID (for example, imo-bench-number_theory-068); if that field is missing, the loader falls back to imo_0

Observed local verification on 2026-04-17:

  • run_id: pr26_formal_smoke_zeroclaw_imo_minimax_rock_cli_box0_20260417_v2
  • result: dashboard X, predicted=0, ground_truth=3, no error
  • execution mode: ROCK sandbox + in-sandbox ZeroClaw CLI

Smoke Selection

The DirectLLM, OpenCode, and OpenClaw minimax configs pin row 367; the ZeroClaw config is bounded to one task with max_tasks: 1 but does not pin that row.

No IMO-AnswerBench full-run file is checked in; create and validate one before scaling.

Qwen/OpenRouter 3-Task Pilot

Environment:

source scripts/activate.sh
export PYTHONPATH=$PWD
export HF_ENDPOINT=https://hf-mirror.com
export OPENAI_BASE_URL=https://openrouter.ai/api/v1
export OPENAI_MODEL_NAME=qwen/qwen3.5-27b
export OPENAI_API_KEY=sk-...

Commands:

python -m alphadiana.cli run configs/examples/directllm_qwen35_27b_imo_answerbench_pilot.yaml
python -m alphadiana.cli run configs/examples/openclaw_qwen35_27b_imo_answerbench_pilot.yaml
python -m alphadiana.cli run configs/examples/opencode_qwen35_27b_imo_answerbench_pilot.yaml

Observed on April 18/19/20, 2026:

  • direct_llm: 3/3 task records written, all score=1
  • openclaw: not rollout-ready yet
    • the first selected dataset Problem ID: score=1
    • the second selected dataset Problem ID: task completed on the April 19 checkpoint rerun, but the current scorer marked a symbolic mismatch as score=1
    • the third selected dataset Problem ID: score=0 with partial_reasoning_only=true; the partial reasoning trace was preserved and is treated as a normal sample
    • the path remains blocked on scorer correctness, not on benchmark completion
  • opencode:
    • April 19 uploaded quality pilot: pilot_20260419_qwen35_27b_imo_answerbench_opencode_t3 wrote 3/3 task records, all score=1
    • April 20 default-Docker confirmation rerun: pilot_20260420_qwen35_27b_imo_answerbench_opencode_t3_docker_default wrote 3/3 normal task records with scores 1/0/0

Local follow-up on April 19, 2026:

  • rerun_20260419_qwen35_27b_imo_answerbench_openclaw_idx2_r2 completed with score=1; the task JSON kept a non-empty top-level reasoning_trajectory plus metadata.raw_reasoning
  • rerun_20260419_qwen35_27b_imo_answerbench_zeroclaw_idx0_r3 failed cleanly with provider transport errors and predicted=None; the previous startup-log pollution no longer leaked into a fake parsed answer

Local follow-up on April 20, 2026:

  • root cause for the ZeroClaw/OpenRouter failure was a config gap, not the benchmark itself: AlphaDiana was not writing ZeroClaw provider_timeout_secs, so the CLI fell back to its internal 120s provider timeout and aborted long streamed math responses
  • the fix keeps stream=true and writes provider_timeout_secs = request_timeout by default unless explicitly overridden
  • validation smoke: debug_20260420_qwen35_27b_imo_answerbench_zeroclaw_idx0_provider_timeout_r1 completed 1/1 on the previously failing first task
  • repaired 3-task pilot: pilot_20260420_qwen35_27b_imo_answerbench_zeroclaw_t3_repair_r3 completed 3/3, all task JSONs now have non-null predictions and no task-level error, and the archive was uploaded to pilot_run/pilot_20260420_qwen35_27b_imo_answerbench_zeroclaw_t3_repair_r3/

Reviewer-facing evidence for this pilot lives in the recorded run IDs above.