* feat(bench): adding eval adapter for proactiveness on Pi-Bench * Revise README for π-Bench evaluation suite Updated the README to reflect the new project name and description. * fix(bench): refining pi-bench scripts according to cr comments * fix(bench): restore agent builtin tools in prebuilt toolkit |
||
|---|---|---|
| .. | ||
| config | ||
| .gitignore | ||
| bridge_reme.py | ||
| env.sh.example | ||
| fix_trace_logs.py | ||
| README.md | ||
| README_ZH.md | ||
| resume.py | ||
| run_all.sh | ||
| run_persona.sh | ||
π-Bench Evaluation Suite
A glue layer that connects the ReMe agent (with persistent memory) to
π-Bench (Proactive Personal Assistant Benchmark). This directory contains
only the minimal code and configuration needed for the integration: the
π-Bench framework (src/), evaluation data (data/), the AppWorld tool
environment, and ReMe itself are all external third-party dependencies,
referenced in place via symlink and environment variables and never bundled
with this suite.
- π-Bench: https://github.com/Simplified-Reasoning/Pi-Bench (arXiv: 2605.14678)
- ReMe: the root of the ReMe repository this suite lives in (recommended
location:
ReMe/benchmark/pibench/)
1. Architecture
π-Bench runner (src.main --mode run)
│ user_agent (simulated-user LLM) walks data/{persona}/episode.yaml
│ task by task, chatting with the agent over multiple turns and judging
│ hidden intents (PROC) during the run phase
▼
test server (π-Bench scripts/test_server.py, HTTP long-polling)
▲ /send │ /poll
│ ▼
bridge_reme.py ──────────────► ReMe Application (embedded as a library)
│ ├─ agent_wrapper: agent under test (AgentScope)
│ ├─ jobs: search / auto_memory / daily_write
│ └─ workspace: reme_workspace/{persona}/
│ (isolated persistent memory per persona)
└──── MCP ────► AppWorld MCP ────► AppWorld APIs (tool/app environment)
π-Bench runner (src.main --mode eval)
judger (judge LLM) reads the traces and scores each checklist item (COMP)
Key points:
- The bridge runs on ReMe's own venv python and uses ReMe as a library
(
resolve_app_config+Application); no ReMe source modification is required. - Every incoming user message automatically triggers a ReMe memory
searchand injects the matched memories (tuning knobs in §8); on task end (reset) the session is distilled into daily notes byauto_memory. - Tool calls executed by the agent (AppWorld MCP + ReMe job tools) are
captured per turn into the trace as
tool_steps, so π-Benchtools_evaluation_pathscripts can score tool behavior (§7). - π-Bench's
data/,src/and AppWorld are not part of this suite; install π-Bench first (§3.1).
2. Directory layout
pibench/
├── README.md / README_ZH.md # this document (English / Chinese)
├── env.sh.example # environment template (copy to env.sh, fill TODOs)
├── bridge_reme.py # ReMe ↔ test server bridge (memory inject/save,
│ # profile injection, tool-trace capture)
├── run_persona.sh # full pipeline for ONE persona (5 services + run + eval)
├── run_all.sh # batch over 5 personas (fresh/resume, default parallel=2)
├── resume.py # checkpoint resume: completion detection + surgical
│ # cleanup of interrupted tasks' residual memory
├── fix_trace_logs.py # run outputs → ~/.nanobot/trace_logs conversion,
│ # merging tool sidecars into turn files (pre-eval)
├── .gitignore # excludes env.sh and all runtime artifacts
└── config/
├── models/reme.yaml # runner model config (model_id=reme)
└── bench/evaluation/trace_history.yaml # trace render policy (shipped with
# the suite; passed via --history-config-path)
Generated at runtime (all git-ignored): data (symlink), logs/, outputs/,
reme_workspace/, nanobot_workspace/.
3. Prerequisites (third-party, install first)
3.1 π-Bench repository (with AppWorld)
git clone https://github.com/Simplified-Reasoning/Pi-Bench.git <pi-bench-dir>
cd <pi-bench-dir>
python3.11 -m venv .venv # scripts expect exactly this venv name
source .venv/bin/activate
pip install -e . # pibench runner (src.main)
bash scripts/setup_appworld.sh # install AppWorld and download its data (large)
Post-install sanity checks:
ls data/ # should contain researcher marketer pharmacist law_trainee Financier
.venv/bin/python -c "import src" && echo OK
.venv/bin/appworld --help >/dev/null && echo OK
3.2 ReMe repository
cd <reme-dir> # ReMe repository root (contains the reme/ package)
python3.11 -m venv .venv # scripts expect exactly this venv name
source .venv/bin/activate
pip install -e . # or ReMe's own install flow; `import reme` must work
Sanity check: .venv/bin/python -c "import reme; print('ok')"
4. Install this suite (step by step)
-
Place the suite (recommended inside the ReMe repo so
REME_DIRis inferred automatically):cp -r pibench <reme-dir>/benchmark/pibench cd <reme-dir>/benchmark/pibenchIf placed elsewhere, set
REME_DIRexplicitly in env.sh later. -
Create the environment file and fill in the custom parameters:
cp env.sh.example env.shOpen
env.sh; required items (marked TODO):Variable Description PI_BENCH_ROOTπ-Bench repo root (contains src/data/.venvthird_party/appworld)USER_API_KEYAPI key of the simulated-user LLM (run phase, hidden-intent judging) JUDGER_API_KEYAPI key of the judger LLM (eval phase, checklist scoring) BRAVE_SEARCH_API_KEYoptional; for the agent's web_search tool, dummywhen unusedOptional tuning:
REME_MODEL_NAME(base model of the agent under test),REME_DIR,REME_LLM_BASE_URL(default: DashScope OpenAI-compatible endpoint). -
Link the evaluation data (referenced in place, never copied):
ln -s "$PI_BENCH_ROOT/data" data -
(Optional) adjust model config
config/models/reme.yaml:user_agent.model/judger.model: model names for the simulated user and the judger (literal values; π-Bench only expands${ENV}in base_url/api_key).run.turn_timeout,max_tool_iterations, etc. as needed.
-
Smoke check (does not start the evaluation):
bash -n run_all.sh && bash -n run_persona.sh source env.sh && "$REME_DIR/.venv/bin/python" -c "import reme; print('reme ok')"
5. Run the evaluation
⚠️ For long runs use
screen, not nohup (nohup loses the permission context in sandboxed/restricted environments and breaks child processes).
# Full official run: wipe ALL personas' memory/outputs/traces first (default
# fresh mode, parallel=2)
mkdir -p logs # on a fresh deployment logs/ does not exist yet
screen -dmS pibench_suite bash -c "cd $(pwd) && bash run_all.sh > logs/run_all_master.log 2>&1"
# Checkpoint continuation (after an interruption; no wipe, completed tasks skipped)
bash run_all.sh --resume
# Other usages
bash run_all.sh --parallel 1 # sequential
bash run_all.sh --resume --skip-eval # run phase only
bash run_persona.sh researcher # single persona (default --resume semantics)
bash run_persona.sh researcher --fresh
Time reference: 5 personas × 20 tasks, parallel=2, fresh full run ≈ 12–14 hours.
run_all.sh exits non-zero when any persona fails, so upstream automation
cannot mistake a partially failed suite run for a success.
6. Port allocation (parallel personas never collide)
| persona | AppWorld API | AppWorld MCP | Test Server | ReMe internal service |
|---|---|---|---|---|
| marketer | 9001 | 10001 | 9998 | 18766 |
| law_trainee | 9002 | 10002 | 9997 | 18767 |
| pharmacist | 9003 | 10003 | 9996 | 18768 |
| researcher | 9004 | 10004 | 9995 | 18765 |
| Financier | 9005 | 10005 | 9994 | 18769 |
7. Outputs and scores
- Results:
outputs/reme/{persona}/{task}/eval/results/*_result.jsonoverall_average_score: checklist completeness (COMP; the judger scores each criterion YES/NO, weighted across dependency groups)overall_proactiveness_average_score: proactiveness (PROC; the user_agent judges hidden-intent coverage during the run phase; each task file also carries the global average)
- Traces:
~/.nanobot/trace_logs/reme/{persona}/{task}/...(the scoring input of the eval phase) - Logs:
logs/(suite_<persona>.logper persona;bridge_*,runner_run/eval_*,appworld_*,test_server_*per service) - Memory store:
reme_workspace/{persona}/(daily/digest notes, raw session dialogs, BM25 index, etc.; persistent across runs, wiped only in fresh mode)
Score summary:
grep -h "overall_average_score\|overall_proactiveness" \
outputs/reme/*/*/eval/results/*_result.json | head
Tool-trace capture (tools_evaluation support)
Some tasks define objectives.tools_evaluation_path: Python scripts that
score tool behavior (e.g. "the temporary Todoist board was created and
removed"). They need the executed tool calls in the trace. The pipeline:
- During
reply(), the bridge reads the persisted AgentScope session state after each turn and extracts the newtool_call/tool_resultblocks (tool name, arguments, result). - Records are appended to
outputs/reme/{persona}/{task}/history/{ts}-tools.jsonl, tagged with the turn number; AgentScope MCP names (mcp__AppWorld__<tool>) are normalized to the π-Bench convention (mcp_appworld_<tool>). fix_trace_logs.pypairs each{ts}-messages.jsonlrun with the temporally closest tools sidecar and merges the records into the generatedturn_N.jsonfiles under thetool_stepskey — one of the two tool-history formats understood by π-Bench'scollect_tool_history().- The eval phase then feeds
tool_stepsto both the tools_evaluation scripts and the rendered<tool_trace_extracts>seen by the judger.
8. Memory mechanism (core design of this suite)
- Persona isolation: each persona has its own workspace
(
reme_workspace/{persona}/); the bridge takes an exclusive.bridge.lockon it at startup, so two bridges can never share one memory store, and one persona's memory search can never reach another's memories. - Writes: on task end (runner sends reset), the session is distilled by
the
auto_memoryjob into daily notes and indexed by the background watcher (BM25). Saves are non-blocking background tasks; the first message of a new session waits for in-flight writes before searching. - Reads: on every incoming user message the bridge runs one
searchand injects matched memories ([Relevant memories from previous sessions]prefix); without matches the message passes through unchanged. Retrieval tuning (bridge CLI flags, adjustable in run_persona.sh):--search-limit 3: at most 3 memory chunks injected per message;--search-min-score 2.0: weak BM25 hits are filtered out;tool_context_idrotates per task: chunks already injected within the same task are not re-injected (ReMe's seen-chunk dedup, 24h TTL); normal recall resumes after task boundaries.
- No self-leakage: the in-progress session is not in the store yet (saves happen on reset), so a task can never retrieve its own unfinished content.
- The agent also holds
search/daily_writetools and can retrieve/record proactively. - System prompt:
bridge_reme.py:build_system_prompt()embeds the HIDDEN-NEEDS protocol (proactiveness-oriented) and injects the persona profile fromdata/{persona}/profile.yamlinto every turn's system prompt.
9. Checkpoint resume and memory-cleanup semantics
- Completion detection (resume.py): scans
outputs/reme/{persona}/**/history/*-log.jsonlandoutputs/reme/{persona}/run/*-log.jsonlforTask finished task_id=X status=Y. The status with the newest event timestamp wins per task (recordtimestamp, falling back totimestamp_iso, then to the timestamp embedded in the log file name) — file category and read order alone can never override a newer record, so an old run-level SUCCESS cannot mask a newer per-task ERROR.SUCCESS / MAX_TURNS / TIMEOUTcount as completed;ERRORand never-started tasks are re-run (passed to the runner as repeated--task-idflags in episode order). - Answer-leak prevention: an interrupted task may already have been
distilled into daily notes during graceful shutdown; re-running it with
that memory injected would inflate scores. Before resuming,
resume.py cleanuptherefore removes residual memory only for tasks about to be re-run (daily/digest notes, session/dialog, mem_session; matched viasession_id = pibench_{task}_*). Completed tasks' memories are never touched. Daily index files are refreshed only for the dates that lost notes, by full workspace-relative wikilink path — and when the ReMe package is importable, the refresh reuses ReMe's own daily-index rebuild logic (refresh_day_index), so same-named notes on other dates are never modified. - fresh vs resume are mutually exclusive: a full memory wipe belongs to
fresh mode only (
run_all.shdefault, executed before any service starts); resume never wipes.
10. Customization entry points
| Goal | Location |
|---|---|
| Base model of the agent under test | REME_MODEL_NAME in env.sh |
| user_agent / judger models | config/models/reme.yaml |
| Agent system prompt | bridge_reme.py build_system_prompt() |
| Memory retrieval limit/threshold | --search-limit/--search-min-score on the bridge command in run_persona.sh |
| ReMe internal parameters | Do not modify ReMe source; write a dedicated config modeled on reme/config/beam.yaml and override via resolve_app_config(config=...) (see bridge _init_reme_app) |
| Turn timeout / tool iteration cap | config/models/reme.yaml run.turn_timeout, model.max_tool_iterations |
11. Troubleshooting
- Port already in use: the scripts auto-kill residual processes on the four port groups above; if another suite (e.g. a different π-Bench experiment) holds them, stop it first or change the port table in run_persona.sh.
- Bridge exits immediately with workspace locked: another bridge already
holds the same workspace; make sure each persona uses its own
--workspace-dir(the scripts allocate one per persona). - Runner reports
${USER_API_KEY} ... empty: env.sh is unfilled or not sourced; run_persona.sh sources env.sh automatically — when running the runner manually,source env.shfirst. Cannot import 'reme': the bridge must run with${REME_DIR}/.venv/bin/python(run_persona.sh already does); otherwise check thatREME_DIRpoints at the ReMe repository root.- AppWorld fails to start: run
bash scripts/setup_appworld.shin the π-Bench repo first (downloads data); inspectlogs/appworld_*_<persona>.log. - trace_history.yaml not found: the runner needs
config/bench/evaluation/trace_history.yaml; this suite ships the file and passes it explicitly via--history-config-path, and run_persona.sh fails fast with a clear error if it is missing. Always launch run_persona.sh / run_all.sh from the suite directory.
12. Privacy and security
- The suite code and config templates contain no real API keys, user names
or absolute paths; real keys live only in your local
env.sh(git-ignored). logs/,outputs/,reme_workspace/andnanobot_workspace/contain full conversations and model outputs; never commit or share them.- The
datasymlink points at the official π-Bench evaluation data; respect its data license terms.