# src/memory/core.py """Core memory helpers. Core memory is the always-in-prompt tier of MemGPT-lite's three-tier memory. Backed by ADK session state under keys `user:core:persona` and `user:core:human`. The `user:` prefix triggers ADK's user-scoped persistence. Helpers accept any dict-like state object — `session.state` outside a tool call, or `tool_context.state` inside one. """ from typing import Literal Section = Literal["persona", "human"] PERSONA_KEY = "user:core:persona" HUMAN_KEY = "user:core:human" _SECTION_TO_KEY = {"persona": PERSONA_KEY, "human": HUMAN_KEY} def _key_for(section: str) -> str: """Resolve a section name to its state key. Raises ValueError on bad input.""" if section not in _SECTION_TO_KEY: raise ValueError(f"section must be 'persona' or 'human', got {section!r}") return _SECTION_TO_KEY[section] def get_block(state, section: str) -> str: """Return the contents of a core memory block. Empty string if unset.""" return state.get(_key_for(section), "") def append(state, section: str, content: str) -> None: """Append a fact to a core memory block as a new bullet line.""" key = _key_for(section) current = state.get(key, "") state[key] = f"{current}\n- {content}" if current else f"- {content}" def replace(state, section: str, old: str, new: str) -> bool: """Replace `old` with `new` in the given block. Returns True if the replacement happened, False if `old` was not found. Callers surface the miss as a tool error. """ key = _key_for(section) current = state.get(key, "") if old not in current: return False state[key] = current.replace(old, new) return True