feat(memory): temporal memory horizon for episodic classification#47
Merged
Conversation
Add MemoryHorizon enum (short_term, long_term) to Episode model. New episodes default to short_term. EpisodeStore gains promote_to_long_term(age_days) for age-based auto-promotion and query_by_horizon() for filtered retrieval per temporal class. Schema migration adds memory_horizon column to existing DBs via ALTER TABLE with contextlib.suppress for idempotency. Migration runs before CREATE INDEX to handle legacy databases. Add short_term_days config field to EpisodicConfig (default 30).
15 tests across 7 classes: model enum values and defaults (3), store persistence roundtrip (2), promote_to_long_term with age threshold (4), query_by_horizon filtering (4), EpisodicConfig short_term_days (1), and legacy DB migration without memory_horizon column (1).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add temporal memory horizon classification to episodic memory, inspired by memora-lab/memory-service-public's four-category observation taxonomy (long-term people, long-term preferences, short-term preferences, short-term content). Episodes are now classified as
short_termorlong_termwith age-based auto-promotion, enabling time-stratified retrieval and different handling per temporal class.How It Works
Promotion is explicit (called from scheduler or CLI), not implicit on read — avoids surprise side effects during queries.
Memory Horizon Enum
Changes
Modified Files
src/vaultmind/memory/models.py— AddedMemoryHorizonStrEnum andmemory_horizon: MemoryHorizon = MemoryHorizon.SHORT_TERMfield toEpisodedataclasssrc/vaultmind/memory/store.py— Schema addsmemory_horizon TEXT NOT NULL DEFAULT 'short_term'column with index. Migration viaALTER TABLEwithcontextlib.suppressfor idempotency (migration runs beforeCREATE INDEXto handle legacy DBs)._row_to_episode()reads horizon from row dict with fallback.create()persistsmemory_horizon. New methods:promote_to_long_term(age_days=30)— UPDATE episodes older than threshold from short_term to long_term, returns count promotedquery_by_horizon(horizon, limit=50)— filtered retrieval by temporal classsrc/vaultmind/config.py— Addedshort_term_days: int = 30toEpisodicConfigconfig/default.toml— Addedshort_term_days = 30to[episodic]sectionNew Files
tests/test_memory_horizon.py(202 lines) — 15 tests across 7 classesBackward Compatibility
memory_horizondefaults toSHORT_TERM— existing episodes treated as short-termEpisodeStore.__init__()_row_to_episode()handles rows withoutmemory_horizoncolumn (fallback to "short_term")memory_horizonis auto-assignedSchema Migration Strategy
Migration runs before schema creation to ensure the column exists before the index is created.
contextlib.suppress(OperationalError)makes it idempotent for both fresh and existing databases.Test plan
test_memory_horizon.pyacross 7 classes:ruff check— cleanmypy --ignore-missing-imports— clean