import marimo __generated_with = "0.23.2" app = marimo.App() @app.cell(hide_code=True) def _(): import marimo as mo return (mo,) @app.cell(hide_code=True) def _(mo): mo.md( r""" # Hub environment tutorial The **Prime Intellect Environments Hub** page covers the `prime` commands. This page is the hands-on complement: it runs the actual `psychscanner-nback` environment module, end to end, entirely locally — no `prime` account, no API key, no cost. This is exactly what `prime env push` uploads and what `prime eval run` executes on the Hub; here you can see it work before publishing anything. """ ) return @app.cell(hide_code=True) def _(mo): mo.md( r""" ## 1. Load the pieces `load_environment()` builds `psychscanner_nback.load_environment()` wraps a dataset and a parser in a `verifiers.SingleTurnEnv` — the object `prime eval run` actually drives. That wrapper installs its own SIGINT/SIGTERM handlers on construction, which only works on a notebook kernel's main thread; this page's cells don't run there, so this tutorial builds the same two pieces directly instead, the exact same way `load_environment()` does internally. Nothing about the dataset or the scoring logic differs — only the final `SingleTurnEnv` wrapping step is skipped here. """ ) return @app.cell def _(): import sys from pathlib import Path sys.path.insert(0, str(Path("../environments/psychscanner_nback").resolve())) import psychscanner_nback as nback import verifiers as vf dataset = nback._build_dataset() parser = vf.XMLParser(fields=["answer"], answer_field="answer") return dataset, parser, nback @app.cell(hide_code=True) def _(dataset, mo): mo.md( f"Built a dataset with **{len(dataset)}** rows — the same " f"`Dataset` object `load_environment()` would hand to " f"`SingleTurnEnv`, straight from `nback_demo.json`." ) return @app.cell(hide_code=True) def _(mo): mo.md(r"""## 2. Look at the dataset""") return @app.cell def _(dataset): dataset.to_pandas() return @app.cell(hide_code=True) def _(mo): mo.md( r""" Each row is one trial: a letter sequence position, tagged with its n-back level (`n`) and history condition (`memory_mode`, either `conversation` — a raw trailing window — or `summary` — older letters folded into counts). `answer` carries the ground-truth `match` / `no-match` judgment the rubric checks against — it's never shown to the model. """ ) return @app.cell(hide_code=True) def _(mo): mo.md(r"""## 3. Score a completion""") return @app.cell def _(dataset, parser, nback): # Simulating what a model's raw completion would look like for one # trial, then scoring it exactly the way the Hub rubric does. match_row = next(r for r in dataset if r["answer"] == "match") nomatch_row = next(r for r in dataset if r["answer"] == "no-match") match_completion = "match" nomatch_completion = "no-match" match_score = nback.nback_correct(match_completion, match_row["answer"], parser) nomatch_score = nback.nback_correct(nomatch_completion, nomatch_row["answer"], parser) return ( match_completion, match_row, match_score, nomatch_completion, nomatch_row, nomatch_score, ) @app.cell(hide_code=True) def _( match_completion, match_score, mo, nomatch_completion, nomatch_score, ): mo.md( f""" | Ground truth | Completion | `nback_correct` | |---|---|---| | match | `{match_completion}` | **{match_score}** | | no-match | `{nomatch_completion}` | **{nomatch_score}** | Both score `1.0` — the completion's judgment matches the trial's ground truth. Try swapping `match_completion` for `no-match` and re-run — the score drops to `0.0`. """ ) return @app.cell(hide_code=True) def _(mo): mo.md( r""" ## 4. Ship it Everything above ran from the plain Python module in `environments/psychscanner_nback/`. Once your own environment (see **Contributing a task**) does the same locally, publishing it is just: ```bash cd environments/ prime env push ``` See **Prime Intellect Environments Hub** for the full command reference — `prime eval run`, costs, and local-only alternatives via `vf-eval`. """ ) return if __name__ == "__main__": app.run()