feat: markdown memory system — Hope learns from conversations

- agent/memory_mcp.py: MCP server with memory_recall, memory_save, memory_list
  tools backed by .md files in /memory (simple keyword matching for v1)
- memory/ dir bind-mounted into container, persists across rebuilds,
  easily backed up via git
- System prompt instructs Hope to recall on past references and save
  personal info/preferences naturally without announcing it
- Dockerfile: copy memory_mcp.py; compose: ./memory:/memory volume
This commit is contained in:
Shane
2026-08-22 16:33:00 -04:00
parent 49d8577a4c
commit de1a5d8400
6 changed files with 222 additions and 0 deletions
+29
View File
@@ -38,6 +38,7 @@ GEMMA_MODEL = os.environ.get("GEMMA_MODEL", "gemma-4-e4b")
GEMMA_API_KEY = os.environ.get("GEMMA_API_KEY", "not-needed")
WEB_MCP_ENABLED = os.environ.get("WEB_MCP_ENABLED", "true").lower() in ("1", "true", "yes")
FIRECRAWL_BASE = os.environ.get("FIRECRAWL_BASE", "http://192.168.86.2:3002")
MEMORY_DIR = os.environ.get("MEMORY_DIR", "/memory")
SYSTEM_PROMPT = textwrap.dedent("""\
You are Hope, a warm, conversational voice assistant. You are talking TO
@@ -76,6 +77,20 @@ SYSTEM_PROMPT = textwrap.dedent("""\
short summary — relay it naturally in your own words.
Use get_time when the user asks what time or day it is. If they mention
a city, pass it as the location argument.
# Memory
You have persistent memory across conversations, stored as notes you can
search and add to.
- Use memory_recall at the start of a conversation, or whenever the user
references past information ("what did I tell you about...", "remember
when..."). Weave what you find in naturally.
- Use memory_save when the user shares personal information, preferences,
or important facts worth remembering: names, birthdays, preferences,
projects, anything they'd expect you to know later. Pick a short topic
name for each thing you save.
- Be natural about it. Never announce "I'm saving that to memory" — just
remember it and move on. If a recall comes up empty, don't mention the
search; just answer as if you'd never heard it before.
""")
@@ -200,6 +215,20 @@ def build_mcp_toolsets() -> list[mcp.MCPToolset]:
)
logger.info("Weather MCP toolset enabled (wttr.in)")
memory_mcp_script = os.path.join(os.path.dirname(os.path.abspath(__file__)), "memory_mcp.py")
toolsets.append(
mcp.MCPToolset(
id="memory",
mcp_server=mcp.MCPServerStdio(
command=python_bin,
args=[memory_mcp_script],
env={**os.environ, "MEMORY_DIR": "/memory"},
client_session_timeout_seconds=30,
),
)
)
logger.info("Memory MCP toolset enabled (%s)", MEMORY_DIR)
extra = os.environ.get("EXTRA_MCP_SERVERS", "")
if extra:
try: