{"data":{"kind":"file","path":"README.md","version_id":"xbsq0wrzy0s8qfm2lvxptlbz","entry":{"name":"README.md","path":"README.md","is_directory":false,"size":6649,"modified_at":"2026-08-07T06:30:03.664000","content_hash":"bf4b0c8b2ec399d1c1652db41c1b05f281f8642a2894f577218d509c37d073d5"},"entries":[],"content":"# aima-env\r\n\r\nRL environment for **classical AI** on the topics of *Artificial Intelligence: A Modern\r\nApproach* (Russell & Norvig): uninformed and informed search, adversarial search with\r\nalpha-beta pruning, constraint satisfaction, exact probability and Markov decision processes.\r\n\r\n- **Tasks:** 30 across 5 categories (search 8, adversarial 6, csp 6, probability 5, mdp 5)\r\n- **Dataset:** [`aima-tasks-v1`](https://huggingface.co/datasets/eltociear/aima-tasks-v1)\r\n- **Reward:** binary, from an exact comparison. No LLM judge, no network, no clock.\r\n- **Dependencies in the sandbox:** none.\r\n\r\n```bash\r\nprime env install eltociear/aima-env\r\n```\r\n\r\n## Original problems, not the book's exercises\r\n\r\nNothing is copied. The four worlds the tasks run against — a weighted graph, a game tree, a\r\nmap-colouring CSP and a small MDP — are invented here, so a model cannot recall an answer\r\ninstead of deriving it.\r\n\r\n\r\n30 classical-AI tasks for the\r\n[`aima-env`](https://app.primeintellect.ai/dashboard/environments/eltociear/aima-env) RL\r\nenvironment, on the topics of *Artificial Intelligence: A Modern Approach* (Russell & Norvig):\r\nuninformed and informed search, adversarial search with alpha-beta pruning, constraint\r\nsatisfaction, exact probability, and Markov decision processes.\r\n\r\n| field | meaning |\r\n|---|---|\r\n| `task_id` | `ai-000` … `ai-029` |\r\n| `category` | search / adversarial / csp / probability / mdp |\r\n| `prompt` | the question, the tie-breaking rule, and the exact shape of the answer |\r\n| `api_description` | the four fixed worlds — graph, game tree, CSP, MDP — plus the ordering rules |\r\n| `expected_output` | JSON `{\"rows\": [...]}`, **computed by executing a reference solution** |\r\n\r\nCategories: search 8, adversarial 6, csp 6, probability 5, mdp 5.\r\nNo dependencies — `heapq`, `itertools`, `math` and `fractions` are all standard library.\r\n\r\n## The trap this dataset is built around: tie-breaking\r\n\r\nSearch algorithms are only deterministic once ties are resolved, and textbooks leave that to\r\nthe implementation. Two correct A* implementations disagree on which node they expand when two\r\nf-values tie; two correct alpha-beta implementations prune different subtrees when children are\r\nvisited in a different order; a backtracking CSP solver's *first* solution depends entirely on\r\nvalue ordering.\r\n\r\nSo every rule is stated in the prompt — frontier ties break alphabetically, neighbours are\r\nconsidered alphabetically, game-tree children go left to right, CSP variables and values are\r\ntried in a named order. And the builder **proves the rules are load-bearing** by recomputing\r\nevery order-sensitive answer against a scrambled internal edge list: 9 of the 30 tasks are\r\nre-checked that way, which is what distinguishes a genuinely pinned answer from one that\r\nhappened to match Python's dict ordering.\r\n\r\n## Two defects caught before publishing\r\n\r\n- **Alpha-beta pruned nothing.** Each MIN node had only two children, so the first draft's\r\n  \"how many leaves were pruned\" answer was `0` — a pruning task that does not exercise pruning.\r\n  The tree now has nine leaves ordered so left-to-right evaluates 5 and prunes 4, while\r\n  right-to-left evaluates all 9 for the same root value. The builder asserts that something is\r\n  always pruned.\r\n- **Greedy best-first found the optimal path**, making the \"compare greedy with UCS\" task\r\n  vacuous. One edge weight was raised so greedy is genuinely misled (cost 25 against the\r\n  optimum of 18) — and because that change could have broken admissibility, the builder now\r\n  *proves* the heuristic never overestimates before any task runs.\r\n\r\n## Grading\r\n\r\nExact, no tolerance. Probabilities and MDP values are exact rationals returned as\r\n`[numerator, denominator]`. Strings and numbers are strictly separated, since rows mix them\r\n(`[\"A\",\"C\",\"E\",\"D\",\"G\",\"H\",18]`), and a float never passes for an integer even when equal in\r\nvalue — `18.0` is evidence of float division where an exact answer was required.\r\n\r\n## Verify it yourself\r\n\r\n```bash\r\npython environments/aima_env/build_tasks.py --verify   # 30/30, plus 9 order-sensitive\r\n                                                       # tasks re-run on a scrambled world\r\n```\r\nSource: <https://github.com/eltociear/my-molt-agent/tree/main/environments/aima_env>\r\n\r\n## Environment arguments\r\n\r\n`load_environment()` deliberately exposes very little: the program's guidance is that an\r\nenvironment should have one correct way to be run, so nothing about the prompts, the parsing or\r\nthe grading is configurable.\r\n\r\n| Argument | Default | Meaning |\r\n|---|---|---|\r\n| `split` | `'train'` | Dataset split to load. |\r\n| `dataset_name` | `'eltociear/aima-tasks-v1'` | Hugging Face dataset of tasks. Change only to point at a fork. |\r\n| `max_turns` | `5` | Tool-use turns the model gets before the rollout ends. |\r\n| `**kwargs` | — | Passed through to the underlying `SandboxEnv`. |\r\n\r\n## Reward rubric\r\n\r\n| Reward function | Weight | What it returns |\r\n|---|---|---|\r\n| `correctness` | 1.0 | Binary: 1.0 when the answer matches the reference, else 0.0. |\r\n\r\nThere is no LLM judge and no partial credit. The score is computed on the host in\r\n`post_rollout` and read back by the rubric, so the reward is a deterministic function of the\r\nvalues the model left in `result`. A **harness** failure (dead sandbox, unreadable read-back)\r\nalso scores 0.0 but additionally sets `state[\"scoring_error\"]`, so an eval run can tell a\r\nbroken harness from a wrong answer instead of blaming the model.\r\n\r\n## Dependencies\r\n\r\n`datasets>=4.1.0`, `verifiers>=0.1.8`\r\n\r\n## Sample `vf-eval` usage\r\n\r\n```bash\r\nuv run vf-install aima-env\r\nuv run vf-eval -s aima-env -m gpt-4.1 -n 5 -r 3\r\nuv run vf-tui                      # inspect the outputs/ folder it writes\r\n```\r\n\r\n## Known limitation\r\n\r\nThe Docker **sandbox transport** has not been executed — `docker run`, `pip install`, and the\r\nmodel's code running inside the container — because that needs a Docker runtime and an\r\ninference provider key, neither available where this was authored.\r\n\r\nEverything else is exercised. `environments/test_scoring_path.py` runs this environment's\r\n`post_rollout` and `Rubric` with the sandbox mocked out, asserting that a correct answer scores\r\n1.0, a well-formed wrong answer scores 0.0, and a dead sandbox scores 0.0 *and* sets\r\n`scoring_error` so a harness failure is never mistaken for a bad model. It also checks that\r\nwhat `build_tasks.py` emits is exactly what the scorer expects. The environment mirrors the\r\nstructure of `polars_env` (already accepted into the Environments Program) and imports cleanly\r\nagainst `verifiers` 0.2.1.\r\n","encoding":"utf-8","truncated":false,"total_bytes":6649},"status":null}