Commit Graph
4 Commits
Author SHA1 Message Date
mayatnikovandClaude Opus 4.7 ecbdd05058 chore(v0.3.0): rename fast-LLM env vars to TIMEWEB_* (match other projects)
Aligns with the user's other repos (proso) which use TIMEWEB_API_GROK /
TIMEWEB_URL_GROK. Single naming convention across projects avoids the
'which env var was it for this repo' mental tax.

  PEPA_FAST_LLM_BASE_URL → TIMEWEB_BASE_URL
  PEPA_FAST_LLM_API_KEY  → TIMEWEB_API_KEY
  PEPA_FAST_LLM_MODEL    → TIMEWEB_MODEL
  PEPA_FAST_LLM_TIMEOUT_MS → TIMEWEB_TIMEOUT_MS

Provider still works with any OpenAI-compatible endpoint — TimeWeb is
the default but the variable name doesn't lock us in. Tests + docs +
.env / .env.example updated.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 18:09:04 +03:00
mayatnikovandClaude Opus 4.7 8473ba6519 v0.3.0-rc.3: event-driven awareness + skill pre-emption
Adds a reactive layer on top of the polling reflex. The bot now
notices environmental shocks (forced moves, HP plunges, hostile
spawns) within ~100ms instead of waiting for the next DISPATCH tick,
and the in-flight skill is preempted so the next reflex cycle can
re-plan against the current world state.

This is the rc that wires the "rc.1 plumbing + rc.2 manifesto" into
a feedback loop:
  - awareness fires preempt → dispatch aborts
  - reflex tick re-evaluates → manifesto walks the ladder
  - new dispatch picks the right skill for the new world state

Pieces:

- runtime/awareness/events.js (new) — bot.on listeners:
  - move: single-tick Δposition ≥ 5 blocks → forced_move flag + preempt
  - health: HP drop ≥ 2 → health_plunge flag + preempt
  - entitySpawn: hostile mob within 12 blocks → hostile_added + preempt
  - blockUpdate: nearby block change → env_changed flag (no preempt,
    throttled 800ms; otherwise gather skills would self-preempt
    every dig)

- runtime/skills/index.js — RUNNER_CODES.PREEMPTED + raceWithAbort()
  wraps every execute() against ctx.abortSignal. Existing skills get
  preemption for free; they don't have to check the signal manually.

- runtime/bot.js:
  - dispatchAction creates a fresh AbortController per dispatch and
    stores it on reflexCtx.currentAbort
  - attachAwareness fires controller.abort() when something disrupts
    the active skill; runSkill returns code: "preempted" and the
    reflex moves on
  - reflexCtx.lastPreempt records the most recent shock

Tests: 332 green (was 315 on rc.2, +17 new):
- runtime/awareness/events.test.js — 12 tests (each event type +
  thresholds + throttling + passive-mob filter)
- runtime/skills/contract.test.js — 3 abortSignal tests
  (mid-flight, pre-armed, clean signal)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 17:56:33 +03:00
mayatnikovandClaude Opus 4.7 ddc67a5031 v0.3.0-rc.2: manifesto / needs ladder L0-L10
Adds an explicit hierarchical needs catalogue that the reflex consults
on every tick. The bot now pursues tangible intermediate goals (food,
wood tools, shelter, stone tools, ...) instead of inheriting whatever
the curriculum thought was "next".

Ladder:
  L0  alive          HP>5, food>0, not in lava, not panic-near hostile
  L1  food           ≥6 food items in inventory (or sated + any food)
  L2  tools_wood     wooden_pickaxe + wooden_axe + wooden_sword
  L3  shelter_basic  bed placed nearby or in inventory
  L4  tools_stone    stone-tier triplet
  L5  armor_basic    any chestplate (pursue=null until craft.leather-*
                     lands; ladder gracefully skips)
  L6  food_security  ≥16 food items
  L7  tools_iron     iron-tier triplet (pursue=gather.stone for now)
  L8  armor_iron     iron chestplate (pursue=null for now)
  L9  village_seed   bed + chest in nearby blocks
  L10 village_full   never detected, falls through to curriculum

Each need has detect(snapshot) → bool and pursue(snapshot) →
{skillId, args} | null. The ladder picks the LOWEST unsatisfied
pursuable need. Needs whose pursue is null get recorded as
blockedNeeds and the walk continues — no stalling on missing skills.

Wired into curriculumReflex: manifesto takes precedence over
curriculum.plan when it has a concrete suggestion. Tests can pass
ctx.disableManifesto=true to exercise the curriculum branch
in isolation (existing reflex tests keep passing this way).

Pi self-reflection prompt now includes
"activeNeed (Maslow ladder L0-L10): L2 tools_wood → gather.logs"
so Pi advises at the right level instead of giving generic guidance.

skillId returned by pursue() is validated against the live registry
(rc.1 plumbing) — manifesto cannot accidentally dispatch a
hallucinated skill name.

Tests: 315 green (was 279 on rc.1, +36 new):
- runtime/manifesto/needs.test.js — 24 tests (per-need detect/pursue,
  helper sums)
- runtime/manifesto/state.test.js — 10 tests (ladder walk, hostile
  takeover at L0, armor skipping, caching)
- runtime/reflex.test.js — 2 integration tests (manifesto overrides
  curriculum plan; well-fed bot pursues tools_stone)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-27 17:50:05 +03:00
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