Appraisal¶
See also: Appraisal Schema — plug in custom theories (OCC, GRID, domain-specific).
Protocols and Data Types¶
emotional_memory.appraisal.AppraisalVector
¶
Bases: BaseModel
Multi-component appraisal of an event (Scherer CPM).
to_core_affect() -> CoreAffect
¶
Map appraisal dimensions to valence-arousal space.
Delegates to the Scherer CPM schema's projection
(SCHERER_CPM_SCHEMA.project_to_core_affect) so the recalibrated mapping
weights live in a single place (Addendum O). See
appraisal_schema._scherer_project for the formula and provenance.
Source code in src/emotional_memory/appraisal.py
emotional_memory.appraisal.AppraisalEngine
¶
Bases: Protocol
Protocol for computing an appraisal vector from an event description.
Implementations may call an LLM, use rule-based heuristics, or any
other strategy. The library ships LLMAppraisalEngine (LLM-backed),
KeywordAppraisalEngine (rule-based), and StaticAppraisalEngine
(fixed vector, for testing).
Return type is AppraisalVector | GenericAppraisalVector:
AppraisalVector for the default Scherer CPM schema,
GenericAppraisalVector when a custom AppraisalSchema is used.
emotional_memory.appraisal.StaticAppraisalEngine(vector: AppraisalVector | None = None)
¶
emotional_memory.appraisal.consolidation_strength(arousal: float, mood_arousal: float) -> float
¶
Arousal-modulated consolidation strength (Yerkes-Dodson inverted-U).
Effective arousal blends encoding arousal (70%) with background mood arousal (30%). Peak consolidation near effective_arousal=0.7.
A floor of 0.1 ensures even calm, mundane memories have a minimum consolidation chance — otherwise events with effective_arousal < 0.2 would get zero strength and be immediately prunable.
Returns a value in [0.1, 1.0].
Source code in src/emotional_memory/appraisal.py
LLM-backed Engine¶
emotional_memory.appraisal_llm.LLMAppraisalEngine(llm: LLMCallable, config: LLMAppraisalConfig | None = None, fallback: AppraisalVector | None = None)
¶
AppraisalEngine backed by any LLM via a provider-agnostic callable.
Thread-safety: the LRU cache is protected by a threading.Lock.
Concurrent appraise() calls with the same key will each call the LLM
independently (no stampede protection), but the cache dict is always
mutated under the lock.
Source code in src/emotional_memory/appraisal_llm.py
fallback_count: int
property
¶
Number of appraisals that returned the neutral fallback (LLM/parse error).
A non-zero value after a measurement run signals silent degradation:
some results are neutral fallbacks, not genuine appraisals. Reset with
reset_fallback_count().
appraise(event_text: str, context: dict[str, Any] | None = None) -> AppraisalVector | GenericAppraisalVector
¶
Appraise event_text via the LLM.
Returns an AppraisalVector for the default Scherer CPM schema or a
GenericAppraisalVector when a custom AppraisalSchema is configured.
Results are cached by (schema, event_text, context) key. On error, if
fallback_on_error is True, returns the neutral fallback vector
instead of propagating the exception.
Source code in src/emotional_memory/appraisal_llm.py
clear_cache() -> None
¶
close() -> None
¶
Release resources held by the LLM callable, if supported.
Delegates to llm.close() when the callable exposes it (e.g. the
httpx-backed client from make_httpx_llm). Safe on callables
without cleanup.
Source code in src/emotional_memory/appraisal_llm.py
emotional_memory.appraisal_llm.LLMAppraisalConfig
¶
Bases: BaseModel
Configuration for LLMAppraisalEngine.
appraisal_schema: AppraisalSchema | None = None
class-attribute
instance-attribute
¶
Appraisal schema to use. None defaults to SCHERER_CPM_SCHEMA.
cache_size: int = 128
class-attribute
instance-attribute
¶
Number of (text, context) pairs to cache. 0 disables the cache.
fallback_on_error: bool = True
class-attribute
instance-attribute
¶
Return a neutral AppraisalVector instead of raising on LLM/parse errors.
Set to False in measurement/benchmark code that must not silently ingest a
neutral fallback as if it were a genuine appraisal (the failure would be
indistinguishable from a real neutral result). When True (default), the
engine still records every fallback in LLMAppraisalEngine.fallback_count so
aggregators can detect and exclude degraded runs without aborting mid-batch.
system_prompt: str = SCHERER_CPM_SCHEMA.system_prompt
class-attribute
instance-attribute
¶
System prompt describing the appraisal task.
Defaults to the Scherer CPM schema prompt (single source of truth). When
appraisal_schema is set and this field is left at its default, the engine
uses appraisal_schema.system_prompt instead. Explicitly setting this field
always takes precedence.
emotional_memory.appraisal_llm.LLMCallable
¶
Bases: Protocol
Provider-agnostic LLM interface.
The user wraps their SDK of choice (openai, anthropic, local GGUF, …) in
a callable matching this signature. The json_schema parameter is
passed for informational purposes — structured-output enforcement is the
caller's responsibility if the backend supports it.
__call__(prompt: str, json_schema: dict[str, Any]) -> str
¶
Keyword-based Engine¶
emotional_memory.appraisal_llm.KeywordAppraisalEngine(rules: list[KeywordRule] | None = None)
¶
Rule-based AppraisalEngine using keyword pattern matching.
Each rule contributes deltas from neutral baselines. After accumulation the results are averaged (when multiple rules fire) and the coping_potential baseline of 0.5 is re-applied. AppraisalVector validators clamp to range.
Scherer-5 specific: always returns an AppraisalVector and therefore does
not honor a custom AppraisalSchema (e.g. DIRECT_VAD_SCHEMA).
Source code in src/emotional_memory/appraisal_llm.py
make_multilingual() -> KeywordAppraisalEngine
classmethod
¶
Return an engine with EN + IT keyword rules.
FR/ES rely on me5 embeddings; no language-specific keywords.
Source code in src/emotional_memory/appraisal_llm.py
emotional_memory.appraisal_llm.KeywordRule(pattern: str, novelty: float = 0.0, goal_relevance: float = 0.0, coping_potential: float = 0.0, norm_congruence: float = 0.0, self_relevance: float = 0.0)
¶
A single keyword pattern contributing dimension score deltas.
All scores are deltas from the neutral baseline (0.0 for signed dims, 0.0 for coping_potential/self_relevance — the engine adds the baseline 0.5 for coping_potential after accumulation).