game_memory
GameGirl Color – Two-tier game memory system.
Manages per-game memories in Redis with two tiers: - Basic: Important, long-lived (characters, plot, bosses, items) - Channel: Ephemeral, recent context (recent events, minor NPCs)
Includes hot-swap memory bleed logic for carrying context between cartridge swaps. # 🧠💀 CORRUPTED MEMORY BANKS
- class game_memory.GameMemory(label, content, importance=0.5, turn_created=0, turn_last_referenced=0, reference_count=1, category='general', glitched=False, source_game='', created_at=<factory>)[source]
Bases:
objectA single memory entry in a game’s two-tier memory bank.
Represents one remembered fact about an in-progress GameGirl Color game – a character, plot beat, boss, item, or a fleeting scene detail – along with the bookkeeping the tiering logic needs: an
importanceweight that drives trimming and bleed selection,reference_countandturn_last_referencedthat drive channel-to-basic promotion, and theglitched/source_gameflags that mark entries carried across a cartridge hot-swap. Instances are a pure in-memory record with no I/O of their own; they are serialized to and from thegame:mem:basic:{game_id}andgame:mem:channel:{game_id}Redis strings viato_dict()andfrom_dict().Constructed by
store_basic()andstore_channel()when a new fact is recorded, and rebuilt byget_basic_memories()andget_channel_memories()when memories are read back from Redis.- Parameters:
- to_dict()[source]
Serialize this memory entry to a plain JSON-safe dict.
Delegates to
dataclasses.asdict()to flatten every field (label,content,importance,turn_created,turn_last_referenced,reference_count,category,glitched,source_game,created_at) into a dict. The result is appended to the memory list and persisted to thegame:mem:basic:{game_id}orgame:mem:channel:{game_id}Redis string viajson.dumps(). No side effects.Called by
store_basic()andstore_channel()when a new entry is created before the list is written back to Redis.
- classmethod from_dict(d)[source]
Reconstruct a
GameMemoryfrom a stored dict, ignoring extras.Filters d down to the dataclass’s declared fields (via
cls.__dataclass_fields__) before constructing the instance, so any stray or legacy keys read back from Redis are dropped rather than raising aTypeError. Missing optional fields fall back to their dataclass defaults. No side effects.Called by
get_basic_memories()andget_channel_memories()when deserializing each entry of the JSON list loaded from thegame:mem:basic:{game_id}/game:mem:channel:{game_id}keys.
- async game_memory.store_basic(game_id, label, content, importance=0.7, category='general', turn=0, redis=None)[source]
Store or update a basic (important), long-lived game memory.
Basic memories persist for the life of the game and hold the things worth remembering across the whole playthrough – characters, plot points, bosses, key items, and relationships. The function reads the current memory list from the
game:mem:basic:{game_id}Redis string, merges by case-insensitivelabel(updating content, raising importance to the max seen, bumping the reference count, and stamping the last-referenced turn) or appends a freshGameMemory, trims the list down to_MAX_BASICkeeping the highest-importance entries, and writes the JSON list back. All Redis failures are caught and logged rather than raised.Called by
store_channel()to promote a frequently referenced ephemeral memory and bybleed_memories()to inject glitch-tagged entries into a new cartridge; no other in-repo callers were found, so it is otherwise invoked from the game subsystem at runtime.- Parameters:
game_id (
str) – Identifier of the game whose basic memory bank is updated.label (
str) – Short name/key for the memory; matched case-insensitively to decide between update and insert.content (
str) – The remembered text.importance (
float) – Weight in the0.0-1.0range; an existing entry keeps the larger of its current and the supplied value.category (
str) – Memory category such asgeneral,character,plot,boss, oritem.turn (
int) – Current game turn, recorded as the last-referenced turn.redis (
Any) – Async Redis client; whenNonethe call is a no-op.
- Returns:
Trueif the memory list was written,Falsewhen Redis is absent or the write failed.- Return type:
- async game_memory.store_channel(game_id, label, content, turn=0, redis=None)[source]
Store a channel (ephemeral) game memory, auto-promoting hot entries.
Channel memories hold recent, disposable context – scene descriptions, minor NPCs, dialogue snippets – under the
game:mem:channel:{game_id}Redis string and are evicted FIFO once the list exceeds_MAX_CHANNEL. The function reads the current list, merges by case-insensitivelabelor appends a fresh low-importanceGameMemory, and writes the JSON list back. When a matched entry’s reference count reaches_PROMOTION_THRESHOLDit is promoted: this callsstore_basic()to copy it into the durable tier, drops it from the channel list, and logs the promotion. Redis failures are caught and logged rather than raised.No in-repo callers were found; invoked from the game subsystem at runtime as new ephemeral context is observed.
- Parameters:
game_id (
str) – Identifier of the game whose channel memory bank is updated.label (
str) – Short name/key for the memory; matched case-insensitively.content (
str) – The remembered text.turn (
int) – Current game turn, recorded as creation and last-referenced turn.redis (
Any) – Async Redis client; whenNonethe call is a no-op.
- Returns:
Trueif the channel list was written,Falsewhen Redis is absent or the write failed.- Return type:
- async game_memory.get_basic_memories(game_id, redis=None)[source]
Load all durable (basic) memories for a game from Redis.
Reads the JSON list stored under the
game:mem:basic:{game_id}Redis string and rebuilds each element into aGameMemoryviaGameMemory.from_dict(). A missing key or any Redis/JSON failure yields an empty list (the failure is logged), so callers can treat an empty result as “no memories” without special-casing errors.Called by
get_context_summary()andbleed_memories(); no other in-repo callers were found.- Parameters:
- Returns:
The stored basic memories, or an empty list when none exist or a read error occurs.
- Return type:
- async game_memory.get_channel_memories(game_id, redis=None)[source]
Load all ephemeral (channel) memories for a game from Redis.
Reads the JSON list stored under the
game:mem:channel:{game_id}Redis string and rebuilds each element into aGameMemoryviaGameMemory.from_dict(). A missing key or any Redis/JSON failure yields an empty list (the failure is logged), letting callers treat an empty result uniformly.Called by
get_context_summary(); no other in-repo callers were found.- Parameters:
- Returns:
The stored channel memories, or an empty list when none exist or a read error occurs.
- Return type:
- async game_memory.get_context_summary(game_id, redis=None)[source]
Build a formatted memory context block for injection into the LLM prompt.
Loads both memory tiers via
get_basic_memories()andget_channel_memories(), then renders them into a single human-readable text block: core (basic) memories sorted by importance and labeled by category – with a[BLEED-THROUGH]tag on glitched entries – followed by up to the last ten ephemeral channel entries. The result is meant to be spliced into the system/context prompt so the LLM stays grounded in the game’s accumulated state. When neither tier has any entries an explicit “empty” placeholder is returned instead. Read-only with respect to Redis.No in-repo callers were found; invoked from the game subsystem’s prompt assembly at runtime.
- Parameters:
- Returns:
A multi-line memory context block, or an “empty” placeholder string when no memories exist.
- Return type:
- async game_memory.bleed_memories(source_game_id, target_game_id, redis=None, max_bleed=7)[source]
Bleed important memories from one game into another across a cartridge swap.
Implements the hot-swap “memory bleed” effect: the most important durable memories of the source game leak into the target game as corrupted echoes. It loads the source’s basic memories via
get_basic_memories(), puts allboss/antagonistentries first, then fills the remainder by importance up tomax_bleed. Channel memories are intentionally dropped because they are ephemeral by design. Whentarget_game_idisNonethe function runs in preview mode and only describes what would bleed. Otherwise, for each selected memory it callsstore_basic()on the target with a[BLEED]label, glitch-recontextualized content, and slightly boosted importance, then re-reads the target’sgame:mem:basic:{game_id}Redis string to set theglitchedandsource_gameflags on the stored entry. The post-store flag patch swallows its own exceptions so a flag-write hiccup never aborts the bleed.Called by the
hot_swap_gametool’srun()intools/hot_swap_game.py, which imports it lazily and passesNonefor the target so this acts as a bleed preview during the swap.- Parameters:
source_game_id (
str) – Identifier of the game being swapped out.target_game_id (
str|None) – Identifier of the new game to receive the bled memories, orNoneto only preview the selection without writing.redis (
Any) – Async Redis client; whenNonea static placeholder summary is returned and nothing is read or written.max_bleed (
int) – Maximum number of memories to carry across.
- Returns:
A human-readable
[BLEED-THROUGH]summary of what bled (or would bleed), suitable for surfacing in the swap narrative.- Return type:
- async game_memory.clear_game_memories(game_id, redis=None)[source]
Delete both memory tiers for a game from Redis.
Issues a single
DELfor thegame:mem:basic:{game_id}andgame:mem:channel:{game_id}keys, wiping the game’s entire memory bank. Used to reset state when a game ends or is discarded. Any Redis failure is caught and logged rather than raised, and the function returns nothing.No in-repo callers were found; invoked from the game subsystem at runtime when a game’s memories are torn down.