semif-api-rocm

SemIf HTTP API and rocm flake
Log | Files | Refs | README | LICENSE

AGENTS.md (7429B)


AGENTS.md — where to change things

Guide for agent sessions working on the SemIf self-learning demos (platformer + puzzle room). Repo root: everything below is relative to here. JS tests: node --test "tests/**/*.cjs". Python tests need the venv (see "Running" at bottom). Run the JS tests after any change to semif-api/src/semif_api/web/ — they pin prompt and state-text strings.


1. Planner prompts (what /plan tells the rule-writer)

What Where Notes
Universal planner system prompt (PLAN_SYSTEM) semif-api/src/semif_api/llama.py (~line 32) One prompt for every game — must stay demo-term-free ("key", "door", "exit", "flag", "jump"… are all banned; test_llama.py::test_plan_system_prompt_is_universal_and_committal pins this). Blame-the-previous-rules and reset paragraphs live here too.
Planner sampling params (PLAN_SAMPLING) same file, right below PLAN_SYSTEM Pinned to the model card's thinking-mode recommendation.
Per-game goal statement (PLAN_GOAL) semif-api/src/semif_api/web/self-rules.js:106 (platformer), semif-api/src/semif_api/web/room-self-rules.js:92 (room) The ONLY deliberate goal channel. Never name the objective anywhere else — decision questions, transcript outcomes, and plan triggers must stay goal-free (goal leaks are a bug class here).
Planner user-prompt assembly semif-api/src/semif_api/web/planner.js → Planner.context(goal, trigger, rules) Wraps PLAN_GOAL + trigger note + previous rules (pre-indicted on repeat failures).
Trigger phrasing (what failed) semif-api/src/semif_api/web/self-game.js and semif-api/src/semif_api/web/room-self-game.js, in the replan() functions Mechanical, goal-free strings, e.g. "the actor used up the step budget and the attempt ended".
Trigger policy (when to plan) semif-api/src/semif_api/web/planner.js (triggered, INSUFFICIENT_THRESHOLD); per-game thresholds passed at the call sites Platformer: p ≥ 0.99 on insufficient. Room: 0 — any plurality plans, since a wandering model must be able to ask early.
Transcript shape the planner reads semif-api/src/semif_api/web/planner.js (record, TRANSCRIPT_KEEP = 24); written by the *-game.js loops Transcript records the bare state + chosen action + mechanical outcome. Rules reach the planner once, via context — never re-embedded per turn.
Decision-model system prompt (DIRECT_SYSTEM) NOT in this repo — direct_messages() comes from the semif_phase1 package (nix store) Meta-only ("you are a decision maker…"). Change it upstream, not here.

2. Game rules

Puzzle room (start here — most iteration happens in this demo):

What Where
Shared core: grid gen, physics, sight, state text semif-api/src/semif_api/web/room-rules.js
— Layout generation (makeLayout, FALLBACK, seeds) semif-api/src/semif_api/web/room-rules.js:79
— Step budget semif-api/src/semif_api/web/room-rules.js:12 (MAX_STEPS = 80)
— Physics (forward, turn, pick-up/unlock/win outcomes) semif-api/src/semif_api/web/room-rules.js (forward ~line 140)
— Sight: cast (DDA), occluded/lineClear (3×3 multi-ray), visibleObjects, bearings, Known: line semif-api/src/semif_api/web/room-rules.js (~lines 175–345)
— FPP state text (fppText, adjacentLines), map text (mapText) semif-api/src/semif_api/web/room-rules.js (~lines 355–410)
— Action options (OPTIONS, optionsFor — forward withheld when faced cell is a no-op) semif-api/src/semif_api/web/room-rules.js:409
SL variant: assembly, insufficient option, PLAN_GOAL semif-api/src/semif_api/web/room-self-rules.js
Ruled variant adds: instructions, guided hint semif-api/src/semif_api/web/room.js + fppText(guided) in room-rules.js

Platformer:

What Where
Level gen, physics (advance), prose state text, OPTIONS, MAX_JUMPS semif-api/src/semif_api/web/game-rules.js
SL variant: stateText (prose/runlength/ascii modes), insufficient, PLAN_GOAL semif-api/src/semif_api/web/self-rules.js

Tests (pin nearly every string above — update them in the same commit): tests/test_roomself.cjs (room), tests/test_self.cjs (platformer SL), tests/test_game.cjs (platformer + planner.js). tests/test_llama.py / tests/test_llama_api.py pin the backend prompts (PLAN_SYSTEM etc.).

3. Web UI wiring

semif-api/src/semif_api/web/index.html loads scripts in dependency order (a test pins the order — keep it when adding files): planner.js → *-rules.js → *-game.js.

Piece File Key hooks
Backend endpoints /decide, /plan (llama-only; torch → 422) semif-api/src/semif_api/app.py:203–236 Thin; all prompt logic is in llama.py.
Platformer ruled loop semif-api/src/semif_api/web/game.js requestDecision → /decide; tick physics
Platformer SL loop semif-api/src/semif_api/web/self-game.js + replan/replanAndRetry (trigger strings, transcript writes)
Room ruled loop semif-api/src/semif_api/web/room.js same shape; manual keydown drive
Room SL loop semif-api/src/semif_api/web/room-self-game.js same; state pane, plan triggers, editable rules pane
Shared SL helpers (Planner.context, thresholds, transcript) semif-api/src/semif_api/web/planner.js
Page: tabs, state/rules panes, script order semif-api/src/semif_api/web/index.html rules panes are <textarea class="rules-edit"> — editable, bound live to learnedRules
Styling semif-api/src/semif_api/web/style.css .demo-panel scoped; .rules-edit, .probs.expandable

Data flow to remember: game loop composes state text (stateText()) → POSTs {state, question, options} to /decide → applies argmax → on failure calls /plan with {prompt: Planner.context(PLAN_GOAL, trigger, learnedRules), transcript} → stores payload.rules into learnedRules (shown in the editable pane) → restarts the level with rules leading every observation. Manual play mirrors the same state text into the side pane for debugging.

Conventions that bite

Running