{"data":{"kind":"file","path":"README.md","version_id":"cebw5nbjokh9kvgmst2m5hxl","entry":{"name":"README.md","path":"README.md","is_directory":false,"size":6320,"modified_at":"2026-08-24T13:15:10.285000","content_hash":"f61a2e945345ad9aed6aa63875b9234377276d7b7e0004e037f90a3153e8c18e"},"entries":[],"content":"# androidworld-dense\n\nDense-reward wrapper around the [AndroidWorld](https://arxiv.org/abs/2405.14573) verifiers\nenvironment ([`primeintellect/androidworld`](https://app.primeintellect.ai/dashboard/environments/primeintellect/androidworld)).\n\nThe base environment returns only AndroidWorld's native `task.is_successful()` signal —\nbinary for most of the 116 tasks. That is the right *final* objective, but it makes every\nfailed rollout look identical: an agent that opened the right app, navigated three screens\ndeep and mistyped one field scores exactly the same 0.0 as an agent that emitted malformed\ntool calls for ten turns. This environment keeps the native signal dominant and adds three\ncheap, generic partial-progress components computed from the rollout itself — no per-task\nhand-written validators, so all 116 tasks are covered.\n\n## Reward\n\n`reward = 0.70 * task_success + 0.15 * app_route + 0.10 * action_validity + 0.05 * efficiency`\n\n| Component | What it measures |\n| --- | --- |\n| `task_success` | AndroidWorld's native `task.is_successful()` (binary, or fractional for composite tasks). Reused verbatim from the base package, including its emulator teardown/release contract. |\n| `app_route` | 1.0 if the rollout's foreground-app trace ever entered one of the task's target apps (resolved from the task class's `app_names` via AndroidWorld's own app→package registry). Tasks with no resolvable target app fall back to \"made ≥1 valid action\". |\n| `action_validity` | Fraction of assistant turns that contained at least one tool call and whose tool calls all executed cleanly. Text-only turns and crashed tool calls count against it. |\n| `efficiency` | Unused fraction of the step budget, awarded **only** when the agent explicitly called `return_task_completion` — never for silent stalls or `max_turns` timeouts. |\n\nWeights are normalised to sum to 1, so the reward is always in [0, 1]. Shaping components\nare capped at 0.30 total, strictly below the 0.70 success weight: no combination of\npartial-progress farming can outrank a genuine success. All progress tracking is stored in\n`state[\"dense_progress\"]` as plain JSON (lists/strings/ints/bools).\n\n## Install\n\nTwo upstream quirks make this a three-line install (both inherited from the base\npackage's dependency set): `android-world`'s 2024-era `setup.py` imports `pkg_resources`\nat build time (gone from setuptools ≥ 81), and uv requires direct-URL dependencies to be\nrestated as top-level requirements. This exact sequence is tested end-to-end:\n\n```bash\nuv pip install 'setuptools<81' wheel\nuv pip install --no-build-isolation androidworld-dense \\\n  \"android-world @ git+https://github.com/google-research/android_world.git@a96012ff326e5e39d15d754ba6e6661d5612a555\" \\\n  \"androidworld @ https://hub.primeintellect.ai/primeintellect/androidworld/@86135ea4/androidworld-0.1.0-py3-none-any.whl\" \\\n  --extra-index-url https://hub.primeintellect.ai/rohiitspace/simple/\n```\n\nPython 3.11 or 3.12 (`<3.13`). The pinned `verifiers<0.1.7` bound is deliberate: the\nbase environment breaks on the 0.1.7+ message-format change.\n\n**Requirements**: Java 11+, ~15 GB disk for the Android SDK, hardware virtualization,\n8 GB+ RAM. macOS (Apple Silicon/Intel) and Linux.\n\nFirst run ever (installs SDK, creates AVD, installs apps on the emulator — slow):\n\n```bash\nuv run vf-eval androidworld-dense -n 1 -a '{\"setup_sdk\": true, \"setup_apps\": true, \"pool_size\": 1}' -c 1\n```\n\nSubsequent runs:\n\n```bash\nuv run vf-eval androidworld-dense -m gpt-4.1-mini -n 20 -r 3 -c 2 \\\n  -a '{\"pool_size\": 2, \"difficulty\": \"easy\", \"seed\": 42, \"max_turns\": 15}'\n```\n\n## Arguments\n\n| Arg | Type | Default | Description |\n| --- | --- | --- | --- |\n| `difficulty` | str | `\"mixed\"` | `easy` (complexity < 2, 75 tasks), `medium` (2–3.9, 29), `hard` (≥ 4, 12), or `mixed` (all 116). |\n| `task_names` | list[str] | `None` | Explicit task subset (AndroidWorld registry names), applied after the difficulty filter. |\n| `seed` | int | `None` | Seed for task-parameter generation. Set for fully reproducible task instances. |\n| `max_turns` | int | `10` | Step budget per rollout (also the denominator of the `efficiency` term). |\n| `n_task_combinations` | int | `1` | Parameter variations per task template. |\n| `pool_size` | int | `1` | Emulators in the pool. Match to `-c`. |\n| `setup_sdk` | bool | `True` | Install Android SDK / create AVD if missing (idempotent). |\n| `setup_apps` | bool | `False` | First-run app install + onboarding. Needed once per machine. |\n| `task_family` | str | `\"android_world\"` | AndroidWorld suite family. |\n| `reward_weights` | dict | `None` | Override `{\"task_success\", \"app_route\", \"action_validity\", \"efficiency\"}`; normalised to sum to 1. |\n\n## Emulator lifecycle\n\nInherited unchanged from the base package: a pool of headless emulators is launched lazily\non the first rollout; each rollout acquires an emulator in `setup_state`, the task is\ninitialised on it, and after scoring the rubric tears the task down and releases the\nemulator back to the pool; all emulators are killed via an `atexit` hook. `pool_size`\nshould match the eval concurrency (`-c`).\n\n## What can break it / known limits\n\n- `app_route` samples the foreground activity once per environment turn; an agent that\n  passes through the target app between samples (or a task whose app cannot be resolved by\n  AndroidWorld's app registry) can be under- or over-credited. It is a shaping term, not a\n  correctness claim.\n- `action_validity` treats a tool's own `success: true` JSON as \"clean\"; a click that lands\n  on the wrong element is still \"valid\". It measures interface competence, not progress.\n- An agent that opens the right app, acts validly and immediately declares completion\n  collects ≈ 0.30 without solving anything. That ceiling is deliberate (< `task_success`),\n  but RL training against this reward should monitor for that plateau.\n- Emulator flakiness (slow boots, gRPC hiccups) is inherited from the base environment.\n\n## References\n\n- AndroidWorld: [paper](https://arxiv.org/abs/2405.14573) · [repo](https://github.com/google-research/android_world)\n- Base environment: [primeintellect/androidworld](https://app.primeintellect.ai/dashboard/environments/primeintellect/androidworld) ([PR 248](https://github.com/PrimeIntellect-ai/prime-environments/pull/248))\n","encoding":"utf-8","truncated":false,"total_bytes":6320},"status":null}