Skip to content

Affective State

emotional_memory.state.AffectiveState

Bases: BaseModel

Snapshot of the system's complete affective state at a point in time.

Immutable: the model fields are frozen (update() returns a new instance). The private _history list is still assignable during construction (frozen blocks field mutation, not private-attribute setup).

initial() -> AffectiveState classmethod

Neutral starting state.

Source code in src/emotional_memory/state.py
@classmethod
def initial(cls) -> AffectiveState:
    """Neutral starting state."""
    return cls(
        core_affect=CoreAffect.neutral(),
        momentum=AffectiveMomentum.zero(),
        mood=MoodField.neutral(),
    )

restore(data: dict[str, Any]) -> AffectiveState classmethod

Reconstruct an AffectiveState from a snapshot dict.

Restores the private momentum history that Pydantic excludes from normal serialisation, so that the next update() call produces correct momentum derivatives.

Source code in src/emotional_memory/state.py
@classmethod
def restore(cls, data: dict[str, Any]) -> AffectiveState:
    """Reconstruct an AffectiveState from a snapshot dict.

    Restores the private momentum history that Pydantic excludes from
    normal serialisation, so that the next ``update()`` call produces
    correct momentum derivatives.
    """
    raw_history = data.get("_history", [])
    filtered = {k: v for k, v in data.items() if k != "_history"}
    state = cls.model_validate(filtered)
    state._history = [
        (str(entry[0]), float(entry[1]), float(entry[2]), float(entry[3]))
        for entry in raw_history
        if len(entry) >= 4
    ]
    return state

snapshot() -> dict[str, Any]

Serialise to a dict including the private momentum history.

Suitable for JSON persistence and later restoration via AffectiveState.restore(). Pydantic's normal serialisation excludes _history; this method adds it back.

Source code in src/emotional_memory/state.py
def snapshot(self) -> dict[str, Any]:
    """Serialise to a dict including the private momentum history.

    Suitable for JSON persistence and later restoration via
    ``AffectiveState.restore()``.  Pydantic's normal serialisation
    excludes ``_history``; this method adds it back.
    """
    data: dict[str, Any] = self.model_dump(mode="json")
    data["_history"] = list(self._history)
    return data

update(new_affect: CoreAffect, now: datetime | None = None, mood_alpha: float = 0.1, mood_decay: MoodDecayConfig | None = None) -> AffectiveState

Return a new AffectiveState reflecting the updated affect.

Momentum is computed from finite differences over the last 3 history points (velocity = Δaffect, acceleration = Δvelocity).

Source code in src/emotional_memory/state.py
def update(
    self,
    new_affect: CoreAffect,
    now: datetime | None = None,
    mood_alpha: float = 0.1,
    mood_decay: MoodDecayConfig | None = None,
) -> AffectiveState:
    """Return a new AffectiveState reflecting the updated affect.

    Momentum is computed from finite differences over the last 3 history
    points (velocity = Δaffect, acceleration = Δvelocity).
    """
    if now is None:
        now = datetime.now(tz=UTC)

    history = [
        *self._history,
        (now.isoformat(), new_affect.valence, new_affect.arousal, new_affect.dominance),
    ]
    history = history[-3:]

    momentum = _compute_momentum(history)
    new_mood = self.mood.update(new_affect, alpha=mood_alpha, now=now, decay_config=mood_decay)

    next_state = AffectiveState(
        core_affect=new_affect,
        momentum=momentum,
        mood=new_mood,
    )
    next_state._history = history
    return next_state