Skip to main content

Emotional extension for AI companions โ€” memory triggers, relationship states, self-emotion.

Project description

affective-longing ๐Ÿง ๐Ÿ’ซ

Emotional extension for AI companions โ€” beyond timing, into feeling.

Built on revive-companion (Poisson timing + Bayesian inference).

Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚                    AffectiveLonging                         โ”‚
โ”‚                                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”      โ”‚
โ”‚  โ”‚   Memory     โ”‚  โ”‚ Relationship โ”‚  โ”‚   Emotion    โ”‚      โ”‚
โ”‚  โ”‚              โ”‚  โ”‚              โ”‚  โ”‚              โ”‚      โ”‚
โ”‚  โ”‚ ChromaDB     โ”‚  โ”‚ HMM          โ”‚  โ”‚ VAD Model    โ”‚      โ”‚
โ”‚  โ”‚ Embeddings   โ”‚  โ”‚ OU Process   โ”‚  โ”‚ Valence      โ”‚      โ”‚
โ”‚  โ”‚ Similarity   โ”‚  โ”‚ 6 Stages     โ”‚  โ”‚ Arousal      โ”‚      โ”‚
โ”‚  โ”‚              โ”‚  โ”‚              โ”‚  โ”‚ Dominance    โ”‚      โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜      โ”‚
โ”‚         โ”‚                 โ”‚                 โ”‚               โ”‚
โ”‚         โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜               โ”‚
โ”‚                           โ–ผ                                 โ”‚
โ”‚                    tick() โ†’ AffectiveResult                 โ”‚
โ”‚                                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚              revive-companion (base)                  โ”‚  โ”‚
โ”‚  โ”‚  Poisson Process โ†’ InfoGain โ†’ Bayesian โ†’ Decision   โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Three Layers

1. Memory โ€” Past triggers present

Store conversations as embeddings. When current context matches past memories, longing probability gets a boost.

engine.remember("ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ", tags=["weather"])
engine.remember("ๆˆ‘ไปฌ็ฌฌไธ€ๆฌก็œ‹็”ตๅฝฑๆ˜ฏใ€Šๆ˜Ÿ้™…็ฉฟ่ถŠใ€‹", tags=["movie"])

# Later...
result = engine.tick(context="ไปŠๅคฉไธ‹้›จไบ†")
# โ†’ Triggers "ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ" with similarity 0.988
# โ†’ Longing boost: +15%

Theory: Sentence embeddings (all-MiniLM-L6-v2) + cosine similarity. Memory decay via Ebbinghaus forgetting curve.

2. Relationship โ€” 6-stage lifecycle

Models relationship dynamics through discrete state transitions (HMM) + continuous emotional drift (Ornstein-Uhlenbeck process).

่ฟฝๆฑ‚ โ†’ ็”œ่œœ โ†’ ็ƒญๆ‹ โ†’ ๅนณ็จณ
  โ†‘                    โ†“
  โ””โ”€โ”€โ”€โ”€ ไฟฎๅค โ† ๅ†ทๆˆ˜ โ†โ”€โ”€โ”˜
engine.observe("affection")   # intimacy +0.10
engine.observe("fight")       # conflict +0.20, may โ†’ ๅ†ทๆˆ˜
engine.step_time(hours=24)    # OU decay toward baseline

Theory:

  • HMM: Hidden states (relationship stages), observed events (user actions). Transition matrix modulated by intimacy/conflict levels.
  • Ornstein-Uhlenbeck: Mean-reverting stochastic process. dX = ฮธ(ฮผ - X)dt + ฯƒdW. Models how intimacy/conflict drift toward baselines over time.

3. Emotion โ€” VAD model

AI companion's internal emotional state modeled as 3D vector (Valence, Arousal, Dominance). Mapped to 11 discrete emotions.

state = engine.emotion.current_state
# EmotionalState(๐Ÿ˜Š joy, V=+0.65, A=0.58, D=0.55)
Dimension Range Meaning
Valence -1 to +1 Unhappy โ†” Happy
Arousal 0 to 1 Calm โ†” Excited
Dominance 0 to 1 Submissive โ†” Dominant

Theory: Russell's Circumplex Model (1980) + Mehrabian's PAD model (1996). OU process for time decay, event-driven bumps for state changes.

Install

# Base (Poisson + Bayesian from revive-companion)
pip install affective-longing

# With memory support (sentence-transformers + chromadb)
pip install affective-longing[memory]

Quick Start

from affective_longing import AffectiveLonging

engine = AffectiveLonging(seed=42)

# 1. Store memories
engine.remember("ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ", tags=["weather"])
engine.remember("ไฝ ่ฏด่ฟ‡ๆœ€ๅ–œๆฌขๅƒ่‰่Ž“่›‹็ณ•", tags=["food"])

# 2. Observe events
engine.observe("reply_fast")
engine.observe("affection")

# 3. Let time pass
engine.step_time(hours=12)

# 4. Tick with context
result = engine.tick(context="ไปŠๅคฉไธ‹้›จไบ†")

print(f"Base probability:    {result.base_probability:.1%}")
print(f"Memory trigger:      {result.memory_trigger}")
print(f"Similarity:          {result.memory_similarity:.3f}")
print(f"Boosted probability: {result.boosted_probability:.1%}")
print(f"Relationship:        {result.relationship_stage.value}")
print(f"Emotion:             {result.emotional_state.emoji} {result.emotional_state.emotion.value}")

if result.should_send:
    send_message(result.prompt)
    engine.record_send()

API Reference

AffectiveLonging

engine = AffectiveLonging(
    memory_persist_dir="./companion_memory_db",  # Where to store embeddings
    relationship_seed=None,                       # For reproducibility
    emotion_seed=None,
    **kwargs                                      # Passed to PoissonLove
)

Methods:

Method Description
remember(text, tags, **metadata) Store a memory. Returns memory ID.
observe(event) Update relationship + emotion. Events: reply_fast, reply_slow, no_reply, long_silence, affection, fight, apology, initiate, reject, long_message
step_time(hours) Advance time โ€” OU decay on all dimensions
tick(now, context) Full pipeline. Returns AffectiveResult.
record_reply(**kwargs) Record user reply (passthrough to base)
record_send() Record that we sent (passthrough to base)
get_state() Snapshot of all 3 layers

AffectiveResult

@dataclass
class AffectiveResult:
    # Decision
    should_send: bool
    base_probability: float

    # Memory
    memory_trigger: str | None
    memory_similarity: float
    longing_boost: float
    boosted_probability: float

    # Relationship
    relationship_stage: Stage
    intimacy: float
    conflict: float

    # Emotion
    emotional_state: EmotionalState

    # Output
    prompt: str
    reason: str

Events

Event Description Intimacy Conflict
reply_fast User replied quickly +0.05 -0.02
reply_slow User replied slowly -0.02 +0.01
no_reply User didn't reply -0.05 +0.03
long_silence No contact >24h -0.10 +0.05
affection User showed warmth +0.10 -0.05
fight Conflict -0.15 +0.20
apology Someone apologized +0.05 -0.15
initiate User initiated contact +0.08 -0.02
reject User rejected us -0.12 +0.10

Examples

Run the quickstarts:

# Memory triggers
python examples/quickstart.py

# Relationship state machine
python examples/quickstart_relationship.py

# VAD emotion engine
python examples/quickstart_emotion.py

# Full integration
python examples/quickstart_integrated.py

Tests

pip install -e ".[memory,test]"
pytest tests/ -v

62 tests covering all modules.

Theoretical Foundations

Module Theory Reference
Memory Sentence embeddings Reimers & Gurevych, 2019
Memory Forgetting curve Ebbinghaus, 1885
Relationship Hidden Markov Model Rabiner, 1989
Relationship Ornstein-Uhlenbeck Uhlenbeck & Ornstein, 1930
Emotion Circumplex Model Russell, 1980
Emotion PAD Model Mehrabian, 1996
Base Poisson Process Poisson, 1837
Base Bayesian Inference Bayes, 1763
Base Information Gain Shannon, 1948

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

affective_longing-0.1.0.tar.gz (25.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

affective_longing-0.1.0-py3-none-any.whl (23.0 kB view details)

Uploaded Python 3

File details

Details for the file affective_longing-0.1.0.tar.gz.

File metadata

  • Download URL: affective_longing-0.1.0.tar.gz
  • Upload date:
  • Size: 25.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.15

File hashes

Hashes for affective_longing-0.1.0.tar.gz
Algorithm Hash digest
SHA256 dc4e133f2397aa6e97dd95448df4d76b7cde86be295576b60c927e183a9d2f20
MD5 f1babe32093f37ca78310f2b2b3fbb2d
BLAKE2b-256 1d72da9f9040fab6aef67df37f4f82e958fef5cf0af5f6af8d36e129ea5b5e6b

See more details on using hashes here.

File details

Details for the file affective_longing-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for affective_longing-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4c7ac9670ea0afa1c8f2597aab62ce1a55a0da0e795af1c6cba2400f6e03c7cb
MD5 1f64b5df57366b9d32fd09aba42a066d
BLAKE2b-256 c0a5b07b17e4cdf43d1b9421488a15d505f1b501aa759088b9553210b09da795

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page