Zep Memory Agent
A multi-agent conversational memory pipeline that exercises all 5 Zep instrumentor methods -- memory.add, memory.get, memory.search, memory.delete, and graph.search -- through a zep-storer child agent (adds messages to session memory) and a zep-retriever child agent (searches memory, queries the knowledge graph, synthesizes context, and generates a personalized answer with OpenAI). Includes session cleanup via memory.delete.
This example runs in dry-run mode by default (no API key needed). For live mode, set OPENAI_API_KEY, WAXELL_API_KEY, and WAXELL_API_URL.
Architecture
Key Code
Zep memory and graph tool operations
All 5 Zep instrumentor methods are wrapped with @waxell.tool(tool_type="memory").
@waxell.tool(tool_type="memory")
def zep_memory_add(zep, session_id: str, messages: list) -> dict:
return zep.memory.add(session_id=session_id, messages=messages)
@waxell.tool(tool_type="memory")
def zep_memory_search(zep, session_id: str, query: str) -> list:
return zep.memory.search(session_id=session_id, query=query)
@waxell.tool(tool_type="memory")
def zep_memory_get(zep, session_id: str):
return zep.memory.get(session_id=session_id)
@waxell.tool(tool_type="memory")
def zep_graph_search(zep, user_id: str, query: str) -> list:
return zep.graph.search(user_id=user_id, query=query)
@waxell.tool(tool_type="memory")
def zep_memory_delete(zep, session_id: str) -> dict:
return zep.memory.delete(session_id=session_id)
Dual retrieval and context synthesis
Memory search results and knowledge graph results are retrieved separately, then synthesized into a unified context.
@waxell.retrieval(source="zep")
def retrieve_from_memory(query: str, search_results: list) -> list[dict]:
return [
{"text": r.message.content, "score": r.score}
for r in search_results[:3]
]
@waxell.retrieval(source="zep_graph")
def retrieve_from_graph(query: str, graph_results: list) -> list[dict]:
return [
{"text": r.message.content, "score": r.score}
for r in graph_results[:3]
]
@waxell.step_dec(name="synthesize_memory_context")
async def synthesize_memory_context(memory, search_results, graph_results) -> dict:
# Combines session summary, facts, search results, and graph entries
return {"context": context, "context_length": len(context), "sources": {...}}
What this demonstrates
@waxell.tool(tool_type="memory")-- 6 Zep operations covering all 5 instrumentor methods (2 adds, 1 search, 1 get, 1 graph search, 1 delete).@waxell.retrieval(source="zep")-- memory search retrieval with relevance scores.@waxell.retrieval(source="zep_graph")-- knowledge graph retrieval.@waxell.step_dec-- memory context synthesis from multiple sources.waxell.score()-- memory_coverage and context_quality scores.waxell.tag()/waxell.metadata()-- agent role and memory system tags.- Auto-instrumented LLM calls -- OpenAI synthesis with memory context.
- Nested
@waxell.observe-- orchestrator + 2 child agents (zep-storer, zep-retriever). - Full Zep lifecycle -- session creation, message storage, search, graph query, LLM synthesis, and cleanup.
Run it
# Dry-run (no API key needed)
python -m app.demos.zep_memory_agent --dry-run
# Live mode with OpenAI
OPENAI_API_KEY=sk-... python -m app.demos.zep_memory_agent