Skip to content

Local Waifu 0.1.19

Choose a tag to compare

@lumizone lumizone released this 22 May 19:35
· 4 commits to main since this release

The prior release was about how the character learns about YOU. This
one is about her interior life — modes she can be in, things she
likes, things she's afraid of, who she is when she's with you. Three
layers landed together.

New (named behaviour modes)

  • Mode catalog. 13 named modes the character can be in for a
    turn: neutral, playful, naughty, tender, comforting,
    excited, sleepy, focused, melancholic, grumpy,
    protective, curious, quiet. Each ships with a one-line
    behavioural cue so the LLM has a discrete posture to organise the
    reply around (instead of trying to translate 6 analog mood
    numbers into tone).
  • Mode selector. Each turn picks a mode from mood + user-message
    signals (sad-keyword lexicon, threat keywords, new-topic openers)
    • stage + time-of-day. Strong overrides (distress → comforting,
      threat → protective) bypass mood entirely. naughty is gated by
      relationship stage (≥ Close) AND the absence of an NSFW
      hard-boundary.
  • Sticky modes. Modes hold for at least 3 turns once chosen so
    the character doesn't whiplash between postures when mood values
    jiggle by 0.05. Strong overrides break stickiness instantly.
  • LLM-driven shifts. New [[MODE shift <name> | <reason>]]
    marker lets the LLM consciously override the heuristic when it
    senses something the lexicon missed.
  • Mode telemetry. Last 50 transitions persisted per character
    in app_meta, ready for future Growth Dashboard surfacing.

New (character self-content blocks)

Four new Letta-style working-memory blocks every character now
ships with, alongside the existing persona / user / session
/ scratch:

  • likes — things SHE enjoys, discovered through your
    conversations.
  • dislikes — things that bother her.
  • quirks — verbal tics and mannerisms she's noticed in
    herself.
  • fears — soft worries she carries, even with you.

All four start mostly empty and grow organically — from in-chat
[[BLOCK append <label>]] markers the LLM emits AND from the new
weekly self-reflection pass.

New (weekly self-reflection sub-agent)

  • character/self_reflection.rs — runs once per 7 days per
    character from the daily background pass. Reads the last 50
    chat turns plus the current self-content blocks, asks the LLM
    to reflect in FIRST person ("I notice I enjoy…"), and appends
    up to 3 entries to each block. Also produces:
    • Mode preference weightsmode → weight map blended into
      the existing weights (smoothing 0.7 × existing + 0.3 × new) so
      "she has learned that playful works with you" emerges over
      months without a single week's outlier flipping it.
    • Insight of the week — 1-2 sentence honest self-observation
      stored as a self_insight memory, ready for the Growth
      Dashboard.
  • License-gated like the other background loops.

Removed / cleaned up

  • The pre-v0.1.19 mood-only prompt line ("Current mood: warm
    (happiness=…)") is now LABELLED as "Underlying mood" because
    the discrete mode + cue sits above it. The mood numbers still
    feed the model — they just no longer carry the whole tonal
    responsibility alone.

Fixed (caught by new gemma4:e4b integration test)

  • System-prompt block dump no longer leaks into the chat.
    Reasoning models (gemma4:e4b especially) sometimes echoed the
    rendered working-memory block dump — --- persona (188/500 — Your self-image) --- … --- end blocks --- — verbatim into the
    visible reply, exposing internal state. The pipeline now strips
    any block-dump-shaped region from the assistant text right
    before persisting and surfacing it, so even when the model
    mimics the system-prompt format, only her actual words reach
    you. (character::blocks::strip_leaked_block_dump, wired in
    chat_pipeline.rs after marker parsing; 5 unit tests covering
    with/without terminator, markdown horizontal rules, unknown
    labels, and clean text.)
  • Polish distress lexicon now catches reversed word order.
    The distress cue list only had "fatalnie się czuję" but
    Polish lets you reorder freely — "Czuję się fatalnie." was
    slipping through and Comforting mode wasn't firing. Added 12
    new cues: both word orders for czuję się fatalnie /
    fatalnie się czuję / źle się czuję / kiepsko się czuję,
    plus kiepsko mi, ciężko mi, rozpadam się,
    przejebany dzień/tydzień, and ASCII-fold variants for users
    who skip Polish diacritics. Threat-mode (boję się) still
    takes precedence when both signals fire, by design.
  • Multi-turn self-learning integration test.
    Added tests/v019_self_learning_demo.rs — drives a 6-turn
    Polish conversation against gemma4:e4b, parses every marker
    the character emits ([[MEM]] / [[BLOCK]] / [[THREAD]] /
    [[MODE shift]] / [[MILESTONE]] / <thought>), folds the
    resulting state back into the next prompt, and asserts the