memory_agent¶
Level 3 · Memory — persistent context across turns using DocumentStore.
Documents written to a store persist between agent turns, and a
ContextInjectionNode loads them into the prompt so the model can reason over
them. This example writes facts, verifies they survive across simulated turns
(including a write mid-conversation), then runs an agent backed by that store.
- Lines: ~44
- Prerequisites: none
- Key concepts:
DocumentStore,InMemoryDocumentStore, memory persistence
Run it¶
Installed via pip? Copy this example into your project with the CLI (no checkout needed):
Or, from a source checkout (run from the repo root):
Expected output:
Turn 1 — found 1 doc(s): The project uses DI.
Turn 2 — found 1 doc(s): Phase 5 adds examples.
Agent: Memory recalled.
Full code¶
"""Memory agent -- persistent memory across agent turns using DocumentStore.
Demonstrates ContextInjectionNode loading stored documents into prompt context.
InMemory only, zero external network calls.
Usage: python -m examples.memory_agent
"""
import asyncio
from symfonic.core import AgentGraph, AgentRuntime, BaseAgentDeps, ModelProvider
from symfonic.core.documents.in_memory import InMemoryDocumentStore
from symfonic.core.models import Document
from symfonic.core.protocols import DocumentStore
from symfonic.core.testing import MockModelProvider
async def main() -> None:
# 1. Populate document store (simulates persistent memory)
doc_store = InMemoryDocumentStore()
await doc_store.write(Document(id="fact-1", content="The project uses DI."))
await doc_store.write(Document(id="fact-2", content="All storage is async."))
# 2. Inject all concrete implementations at entry point
deps = BaseAgentDeps()
deps.register(ModelProvider, MockModelProvider(response="Memory recalled."))
deps.register(DocumentStore, doc_store)
# 3. Verify documents persist across reads (simulates turns)
found = await doc_store.search("DI")
print(f"Turn 1 — found {len(found)} doc(s): {found[0].content}")
await doc_store.write(Document(id="fact-3", content="Phase 5 adds examples."))
found2 = await doc_store.search("Phase")
print(f"Turn 2 — found {len(found2)} doc(s): {found2[0].content}")
# 4. Run agent with memory-backed deps
graph = AgentGraph()
runtime = AgentRuntime(graph=graph, deps=deps)
result = await runtime.run("What do you remember?")
print(f"Agent: {result['final_response']}")
if __name__ == "__main__":
asyncio.run(main())
Step by step¶
1. Populate the store¶
doc_store = InMemoryDocumentStore()
await doc_store.write(Document(id="fact-1", content="The project uses DI."))
await doc_store.write(Document(id="fact-2", content="All storage is async."))
Each Document has a stable id and a content body. Writing with the same
id again would update in place. This store stands in for any persistence
backend — swap InMemoryDocumentStore for a Postgres- or Mongo-backed one and
the rest of the code is unchanged.
2. Register the store¶
deps = BaseAgentDeps()
deps.register(ModelProvider, MockModelProvider(response="Memory recalled."))
deps.register(DocumentStore, doc_store)
The store is injected by the DocumentStore protocol. The graph's context nodes
resolve it from deps at run time.
3. Confirm persistence across turns¶
found = await doc_store.search("DI")
print(f"Turn 1 — found {len(found)} doc(s): {found[0].content}")
await doc_store.write(Document(id="fact-3", content="Phase 5 adds examples."))
found2 = await doc_store.search("Phase")
print(f"Turn 2 — found {len(found2)} doc(s): {found2[0].content}")
search(query) returns documents matching the query. The key idea: the write in
"Turn 2" is visible to subsequent reads — state accumulates across turns rather
than resetting. This is what makes the agent remember within a session.
4. Run the agent over its memory¶
graph = AgentGraph()
runtime = AgentRuntime(graph=graph, deps=deps)
result = await runtime.run("What do you remember?")
print(f"Agent: {result['final_response']}")
The runtime's context-injection node reads from the same DocumentStore and
splices matching documents into the prompt before the model runs — so the model's
answer is grounded in what was stored. (With MockModelProvider the reply is
canned; with a real provider the documents shape the response.)
DocumentStore vs the 5-layer HMS¶
This example uses the raw DocumentStore — the simplest persistence primitive.
The high-level SymfonicAgent builds on top of it with the full Hierarchical
Memory System (Semantic, Episodic, Working, Procedural, Prospective layers),
which adds consolidation, spreading activation, and automatic hydration. Start
here to understand the primitive; graduate to the HMS for production memory.
What to try next¶
- Round-trip memory tools (
memory_read/memory_write/memory_search) → seeagent_with_memoryin the Examples Index - The full memory model → Memory (5-Pentad)