feat(runtime): social layer — intent / templates / chat memory (Phase 5) (#16)
Phase 5 of plans/autonomous-survival-bot-prd.md. Make the bot feel
present in chat without ever becoming a command executor.
New: runtime/social/
- intent.js: classifyIntent({text, botName}) returns one of GREETING /
STATUS_QUESTION / ADDRESSED_BANTER / COMMAND_LIKE / UNSAFE_REQUEST /
AMBIENT. Unicode-aware word boundaries so cyrillic + latin both work
("Привет всем" → GREETING, "build me a tower" → AMBIENT unless
addressed).
- reply.js: generateReply({intent, speaker, snapshot, diaryTail}) →
short templated response, or {send: null, escalate: true} for the
caller to decide whether to spend Pi tokens.
- memory.js: createChatMemory() — per-speaker LRU buffer of recent
lines; redacts password / api_key / JWT-shaped tokens at append
time, so the buffer can be safely fed back into any future prompt.
- social.test.js: 12 tests (intent edges, memory eviction, redaction,
reply routing). npm test now 40/40.
state-store.js additions:
- readDiaryTail(n) — reads the last N lines of today's diary; used by
status replies.
- writeEscalation({from, request, whyUnsure, wouldHave}) /
listEscalations() — JSONL log under state/<host>/escalations.jsonl
for UNSAFE_REQUEST classifications and future operator review.
bot.js: handleChat() now routes through social/intent + social/reply
(replacing the Phase-0 inline regexes), records every line into
chatMemory, and writes an escalation when classifyIntent returns
UNSAFE_REQUEST. Command-like notice + dialog-only behaviour from
Phase 0 are preserved.
Co-authored-by: Yuriy Mayatnikov <mayatnikov@me.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit was merged in pull request #16.
This commit is contained in:
@@ -246,6 +246,31 @@ in-process. The package is **not** a default dep — install it explicitly
|
||||
(`npm i prismarine-viewer`) before enabling. If missing, the runtime
|
||||
logs a warning and continues.
|
||||
|
||||
### Social layer (Phase 5)
|
||||
|
||||
Inbound MC chat is classified via `runtime/social/intent.js` into one
|
||||
of `GREETING` / `STATUS_QUESTION` / `ADDRESSED_BANTER` / `COMMAND_LIKE`
|
||||
/ `UNSAFE_REQUEST` / `AMBIENT`. The classifier uses Unicode-aware
|
||||
boundaries so "Привет всем" lands as `GREETING` while
|
||||
"build me a tower" stays `AMBIENT` until the bot is addressed.
|
||||
|
||||
`runtime/social/reply.js` turns an intent into a short reply:
|
||||
- `GREETING` → one of a small picked-randomly set ("yo" / "привет" / …).
|
||||
- `STATUS_QUESTION` → live snapshot summary: active skill, current
|
||||
milestone, hp/food/position, no-progress reason, last diary line.
|
||||
- `COMMAND_LIKE` → dialog-only notice (per Phase 0).
|
||||
- `UNSAFE_REQUEST` → terse "logged for operator review", plus an entry
|
||||
in `state/<host>/escalations.jsonl`.
|
||||
- `ADDRESSED_BANTER` → templates can't reliably answer, so the
|
||||
generator returns `escalate: true`. Today bot.js does NOT spawn Pi
|
||||
from this path (keeps the LLM out of the hot path); a rate-limited
|
||||
escalation lands in Phase 6.
|
||||
|
||||
`runtime/social/memory.js` maintains an LRU per-speaker buffer of
|
||||
recent lines (default 8 per speaker, 16 speakers max) and redacts
|
||||
password / api-key / JWT-shaped tokens before they ever exit the
|
||||
runtime.
|
||||
|
||||
## In-game chat (dialog-only)
|
||||
|
||||
As of the Phase 0 survival-bot pivot, MC chat does **not** drive bot
|
||||
|
||||
Reference in New Issue
Block a user