Files
pepa-pi-bot/dev/v0.3.0/PLAN.md
T
mayatnikovandClaude Opus 4.7 fcfa2277ba v0.3.0-rc.1: live skill registry + fast advisor scaffold
Roots out the v0.2.x failure mode: Pi-extracted lessons routinely named
hallucinated skill ids (relocate.surface, choose.safe.surface,
survive.shelter, gather.visible_log, …). All 47 Pi-lessons in the live DB
had applied_count=0 because normalisePreferSkill couldn't find them.

Fix:
1. runtime/skill-registry.js — single source of truth derived from
   skills/index.js. Exports listSkillIds, isRegistered, and a
   prompt-ready block (skillRegistryPrompt) grouped by namespace.
2. Pi prompts (coach/postmortem, coach/reflect) embed the live registry
   with a "USE ONLY THESE, never invent" instruction. Lessons are
   filtered at write-time too — anything not in the registry and not a
   known mode name gets dropped.
3. coach/advice.js — normalisePreferSkill now returns null for unknown
   ids, hardening consult() against any hallucinations that slip
   through. Warn-logged for visibility.

Also lays the LLM substrate for the rest of v0.3.0:

- runtime/llm/provider.js — OpenAI-compatible chat client. Configured
  via PEPA_FAST_LLM_{BASE_URL,API_KEY,MODEL,TIMEOUT_MS}. Safe no-op
  unless API_KEY is set. Supports JSON-mode.
- runtime/coach/fast-advisor.js — tactical advisor tier (scaffold).
  Exposes advise() that asks the fast LLM what to do RIGHT NOW when
  the reflex is wedged/stuck. Rejects hallucinated skill ids using the
  registry. Rate-limited 6/h, 30s cooldown. Not auto-triggered yet —
  wired into reflex in rc.3 (awareness layer).

Tests: 279 green (+24 vs rc.3): 5 registry, 9 provider, 10 advisor.

See dev/v0.3.0/PLAN.md for the full iteration design (manifesto needs
ladder, event-driven awareness, skill pre-emption) and STATUS.md for
shipped/pending tracking.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 17:39:43 +03:00

156 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# pepa v0.3.0 — Maslow + Awareness
Concept: needs-based hierarchical agent with real-time event awareness and a
fast LLM tactical advisor. Pi (CLI) stays for slow deep analytics
(postmortem, reflection). A second, fast LLM tier (TimeWeb / OpenAI-
compatible) handles "what to do right now" decisions when the reflex
detects wedged/stuck/changed environment.
This is a major behavioural rewrite over v0.2.x:
- v0.2.x had a flat reflex chain (modes → defend → eat → sleep →
curriculum → idle) — curriculum was just "next mode". The bot had no
internal concept of "do I have a pickaxe?" let alone "do I have a
shelter?" Lessons from Pi were hallucinated skill names (47/47
Pi-extracted lessons applied_count=0 as of v0.2.0-rc.3).
- v0.3.0 introduces a **needs ladder** (Maslow-like) that drives the
bot's intent end-to-end, an **awareness layer** that reacts to env
changes within ~100ms instead of waiting for the next tick boundary,
and a **fast LLM** tier that closes the loop when the bot is stuck.
## Concept terms
This pattern is called variously in the AI literature:
- **Hierarchical Task Network (HTN)** planning — Voyager uses this
- **Needs-based / utility AI** — game-AI mainstream
- **BDI agent** (Beliefs-Desires-Intentions) — academic AI
- **Subsumption architecture** (Brooks) — reactive layers preempt
deliberative layers when conditions trigger
Pepa v0.3.0 is essentially **Maslow-stack curriculum + Brooks-style
preemption + dual-tier LLM (fast tactical + slow analytical)**.
## Manifesto / Needs ladder
```
L0 alive HP>5, не тонет, не горит, не падает с фатальной высоты
L1 food ≥6 насыщения (готов кушать на месте)
L2 tools_wood wooden_pickaxe + wooden_axe + wooden_sword
L3 shelter_basic 4 стены + крыша + кровать в радиусе 8 от спавн-base
L4 tools_stone stone_pickaxe + stone_axe + stone_sword
L5 armor_basic хотя бы один кусок (predпочтительно нагрудник)
L6 food_security ≥16 еды + источник (ферма / стая коров рядом)
L7 tools_iron iron_pickaxe + iron_axe + iron_sword
L8 armor_iron полный iron set
L9 village_seed 2+ постройки, забор/оградка, базовая ферма
L10 village_full глобальная цель (ферма + дом + сосед-NPC мечта)
```
На каждом тике reflex выбирает **самую нижнюю неудовлетворённую** нужду.
Эта нужда становится **активной**. Curriculum.next() и Pi-coach подсказки
дальше выбираются **внутри** активной нужды. Если нужда сменилась
(например, HP упало → L0 проснулся), текущий skill прерывается.
## v0.3.0 release plan (3 rc)
### rc.1 — Skill registry hardening + Fast advisor scaffold
**Цель**: убрать главную проблему v0.2.x — Pi инвентит skill names.
Не вводим манифест ещё, но строим инфраструктуру для него.
- `runtime/skill-registry.js` — exported `listSkillIds()`, `isRegistered(id)`,
`skillRegistryPrompt()` (готовый блок текста для LLM-промпта со списком
валидных id, по группам)
- Все Pi-промпты (`coach/postmortem.js`, `coach/reflect.js`) передают
реестр в system prompt
- `runtime/coach/advice.js`: `normalisePreferSkill` строго отбрасывает
всё, что не в реестре (raise log, не дрейфит на fuzzy)
- `runtime/llm/provider.js` — OpenAI-совместимый клиент, конфигурируется
через env (`PEPA_FAST_LLM_BASE_URL`, `_API_KEY`, `_MODEL`); graceful
fallback "no-op" если env не задан (бот не падает)
- `runtime/coach/fast-advisor.js` — функция `advise({snapshot, reason})`
с rate-limit (макс. 6 вызовов/час), таймаут 8с, JSON-парсинг ответа
через тот же `extractJson()` что у Pi. **Пока не подключаем к reflex**
scaffold + тесты
- Тесты для каждого нового модуля + регрессионный тест:
`advice.test.js` проверяет что hallucinated `relocate.surface` falls
through (никакой override)
- Минимум 270+ зелёных тестов
### rc.2 — Manifesto / Needs ladder + curriculum integration
**Цель**: bot acts toward concrete needs, not toward "explore further".
- `runtime/manifesto/needs.js` — каталог 11 нужд, каждая со схемой:
```
{ id, level, detect(snapshot) → boolean satisfied, prefer_skill_for_pursuit, ... }
```
- `runtime/manifesto/state.js` — `pickActiveNeed(snapshot)` возвращает
самую нижнюю неудовлетворённую. Кеширует на 5с.
- `runtime/reflex.js`:
- В `curriculumReflex` сначала `activeNeed = pickActiveNeed(...)`
- Skill подбирается в первую очередь по `activeNeed.prefer_skill_for_pursuit`
- Fallback на curriculum.next() только если нужда не дала однозначного skill
- `runtime/coach/advice.js`: `consult()` теперь принимает `activeNeed` и
отбрасывает lessons чьи trigger_situation противоречит текущей нужде
(например, "избегай ночью гулять" не применяется когда L0=alive в опасности)
- Pi-промпты (postmortem, reflect) получают `currentNeed: "L2 tools_wood"`
и просят Pi дать совет именно для этого уровня
- Новый персонаж reflex hook: при смене activeNeed бот произносит в чате
"пора заняться X" (Russian narration tying into chatter.js)
- Тесты: каждая нужда имеет 2-3 теста (detect satisfied/unsatisfied,
правильный prefer_skill)
### rc.3 — Event-driven awareness + skill pre-emption
**Цель**: bot reacts within ~100ms to env changes (fall, teleport,
damage, hostile spawn near).
- `runtime/awareness/events.js` — установка listeners:
- `bot.on('move')` — детект position-jump >5 блоков за тик → событие
`forced-move` → инвалидация current dispatch context
- `bot.on('health')` — снижение HP > 2 за тик → reflex.preempt()
- `bot.on('entitySpawn')` — враждебный <12 блоков → reflex.preempt()
- `bot.on('blockUpdate')` около бота (manhattan <4) → пометка
`environment_changed=true`
- `runtime/awareness/state.js` — храним flags `(forcedMove, lastDamage,
hostileAdded, envChanged)`, expose `consumeFlags()` для reflex
- Skill protocol extended: `execute(ctx, args)` теперь получает
`ctx.abortSignal` (AbortSignal). Длинные операции (pathfinder.goto,
collectBlock loops) проверяют `signal.aborted` между шагами и сразу
возвращают `{ok: false, code: 'preempted'}`
- `runtime/reflex.js`: при срабатывании preempt-флагов вызывается
`currentDispatch?.abort()`, и reflex запускает следующий тик
немедленно (не ждёт `DISPATCH_INTERVAL_MS`)
- `recovery.tunnel-out`, `survive.pillar-up`, `gather.logs`, `explore.far`
адаптируются под AbortSignal (минимальное — `if (signal.aborted)
return { ok:false, code:'preempted' }` после каждого `await`)
- **Связка с fast advisor**: когда preempt сработал из-за `forcedMove`
или environment_changed, и reflex не находит очевидный skill, вызывает
`fastAdvisor.advise(...)` чтобы получить тактический совет (rc.1
scaffolding активируется здесь)
### Acceptance signals (после rc.3)
- В живой БД: `lessons WHERE applied_count > 0` растёт (сейчас 3,
должно стать 20+ за сутки)
- Bot движется к конкретным целям: видимый прогресс инвентаря (wood →
pickaxe → stone → axe), а не "блуждание в одном квадранте"
- При forcedMove бот меняет план в течение секунды, не продолжает
старый skill
- Fast advisor пакетно срабатывает <10 раз/час, каждый раз приводит к
смене skill (логируется)
## Что отложено в v0.3.1
- **Vision** (multimodal LLM на скриншотах) — требует prismarine-viewer
pipeline + multimodal model в провайдере; не в первом релизе
- **Vector memory of scenarios** — embeddings от похожих ситуаций
- **Auto-curriculum from wiki** — фоновый паук minecraft.wiki
## Workflow notes
- Каждый rc — отдельный PR, мержим после approve
- main защищён, auto-patch открывает PR с тегом `auto-patch`
- Если что-то ломается в проде (живой бот в петле >30 мин), откатываем
на v0.2.0-rc.3 commit `865aae1` через `git checkout <commit>` на
ветке `revert/v0.3.0-stability`
- Тестовые данные строго в `/tmp/pepa-test-state-*` (исправлено в v0.2.0-rc.2)