viva_emotion

CI Package Version Hex Docs

Type-safe emotional core for digital consciousness. PAD model, Ornstein-Uhlenbeck dynamics, and Cusp catastrophe - all with exhaustive pattern matching.

Installation

gleam add viva_emotion@1

Quick Start

import viva_emotion
import viva_emotion/stimulus
import viva_emotion/emotion

pub fn main() {
  // Create emotional state
  let state = viva_emotion.new()

  // Feel success
  let state = viva_emotion.feel(state, stimulus.Success, 1.0)

  // Evolve over time
  let #(state, jumped) = viva_emotion.tick(state, 0.1)

  // Classify current emotion
  let classified = viva_emotion.classify(state)
  // classified.emotion == emotion.Joy
}

Features

Platform Support

This library targets the Erlang platform and is compatible with:

Personality Configuration

import viva_emotion
import viva_emotion/dynamics
import viva_emotion/emotion
import viva_emotion/stimulus
import viva_emotion/pad

// Anxious personality: lower threshold for existential states
let anxious_classification = emotion.ClassificationConfig(
  high_threshold: 0.2,
  low_threshold: -0.2,
  existential_arousal: 0.5,  // Triggers easier
  existential_pleasure: -0.2,
)

// Stoic personality: rejection hurts less
let stoic_weights = stimulus.default_weights()
  |> stimulus.weight(stimulus.Rejection, pad.new(-0.1, 0.1, 0.0))

// Volatile personality: easier cusp triggers
let volatile_dynamics = dynamics.DynamicsConfig(
  ..dynamics.default_config(),
  cusp_dominance_trigger: -0.1,
  cusp_flip_pleasure_damp: 0.95,
)

// Combine into full personality
let anxious_viva = viva_emotion.with_full_config(
  pad.new(-0.1, 0.2, -0.1),  // baseline
  volatile_dynamics,
  anxious_classification,
  stoic_weights,
)

Emotion Fusion

Combine multiple emotional sources with adaptive weighting:

import viva_emotion
import viva_emotion/fusion
import viva_emotion/pad

// Need-based emotion (from interoception/hardware)
let need = pad.new(-0.3, 0.4, -0.2)

// Past-based emotion (from memory retrieval)
let past = pad.new(0.2, 0.1, 0.3)

// Context for adaptive weights
let context = fusion.FusionContext(
  arousal: 0.4,     // Current arousal → affects need weight
  confidence: 0.7,  // Memory confidence → affects past weight
  novelty: 0.3,     // Situation novelty → affects personality weight
)

// Fuse sources
let state = viva_emotion.new()
let state = viva_emotion.fuse(state, need, past, context)

// Check for emotional conflict
let has_conflict = viva_emotion.has_emotional_conflict(state, need, past)
let coherence = viva_emotion.emotional_coherence(state, need, past)

Long-term Mood

Track mood over time with Exponential Moving Average:

import viva_emotion
import viva_emotion/mood
import viva_emotion/stimulus

// Create state with mood tracking
let state = viva_emotion.new_with_mood()

// Feel emotions and update mood
let state = viva_emotion.EmotionalStateWithMood(
  ..state,
  emotion: viva_emotion.feel(state.emotion, stimulus.Success, 1.0),
)
let state = viva_emotion.update_mood(state)

// Check mood
let is_happy = viva_emotion.mood_is_positive(state)
let valence = viva_emotion.mood_valence(state)

// Big Bounce: carry mood across death (80% decay)
let reborn = viva_emotion.bounce_mood(state, 0.8)

Stochastic Mode

Inject external entropy for organic emotional evolution:

// Get noise from Rust/hardware
let noise = pad.new(random_p, random_a, random_d)

// Stochastic tick
let #(state, jumped) = viva_emotion.tick_with_noise(state, 0.1, noise)

// Deterministic mode (for testing/replay)
let #(state, jumped) = viva_emotion.tick_with_noise(state, 0.1, pad.neutral())

Development

gleam test        # Run tests
gleam format src test  # Format code
gleam build       # Build

Community

For questions and discussions, check:

License

MIT - see LICENSE for details.

Search Document