Emotion state, needs, and user needs

Furoshiki keeps a vector of nine emotions (0–1), derives five Furoshiki needs for behavior, and separately tracks seven user-need dimensions about the human’s inferred state. This page orients you; the canonical technical write-up is docs/EMOTION-STATE-AND-NEEDS.md in the repo.

Python vs LLM. Drift, clamps, and persistence are deterministic code. Interpreting what a message means for feelings is done by the same chat model when it chooses to call adjust_emotions (bounded nudges)—not by a keyword table.

Three layers

LayerRoleWhere it lives
Emotions Raw inner state (loneliness, joy, …) heartbeat-state.json, emotion_history
Furoshiki needs Derived from emotions (communication, connection, …) needs in heartbeat, needs_history
User needs Inference about the user (space, conflict, …) with confidence user_needs, user_needs_history

How emotion changes (overview)

flowchart LR
  subgraph drift [Background]
    NL[Natural levels]
    LD[lazy drift on read]
    SE[soul_engine tick]
  end
  subgraph chat [During chat]
    CM[Chat model]
    TC[Tool loop]
    AE[adjust_emotions]
  end
  subgraph store [Persistence]
    HB[(heartbeat)]
    EH[(emotion_history)]
  end
  NL --> LD
  LD --> HB
  SE --> HB
  SE --> EH
  CM --> TC
  TC --> AE
  AE --> HB
  LD -.-> ND[needs / mood]
  HB --> ND
    

Natural levels (drift attractors)

Shipped defaults live in emotion_model.EMOTION_NATURAL_LEVEL. Operators can override per emotion in memory/operator_settings.json under emotion_natural_levels, or use the dashboard Mind & self → Emotion lab (save / revert to code defaults). Drift pulls emotions toward these targets over time when nothing else is firing.

adjust_emotions during chat

When model tools are enabled (default), the Telegram reply model receives tool schemas from model_tools.py. It may call adjust_emotions with small deltas; execution updates the heartbeat and logs a row viewable under Model tools. This is optional per turn—the tool description tells the model not to call it on every message.

Dashboard

Unified contact (gray markers on charts)

The same merged timeline is used for analytics: user conversation_turns (excluding dismiss bookkeeping), user_input system events, and outreach rows triggered by user_message, then deduped within ~90 seconds. One real interaction can still produce more than one raw row—check raw_by_source before assuming “message volume.”