Add Persistent Memory to OpenAI Agents

Give OpenAI Agents SDK agents the ability to store and retrieve memories that persist across sessions.

Table of contents
  1. Prerequisites
  2. Install
  3. How it works
  4. Define the memory tools
  5. Create an agent with memory
  6. Full working example
  7. Per-customer agents
  8. Using assemble_context for richer prompts
  9. Tips
  10. Next steps

Prerequisites

Install

pip install hippodid openai-agents

How it works

The OpenAI Agents SDK lets you define function tools that agents can call during execution. You register search_memories and add_memory as tools, and the agent decides when to store or retrieve information based on the conversation.


Define the memory tools

Create two function tools that wrap HippoDid’s API.

from agents import function_tool
from hippodid import HippoDid

client = HippoDid(api_key="hd_key_...")
CHARACTER_ID = "YOUR_CHARACTER_ID"


@function_tool
def search_memories(query: str, limit: int = 5) -> str:
    """Search long-term memory for relevant facts, preferences, and past decisions.
    Call this at the start of a conversation or when the user references something
    from a previous session."""
    results = client.search_memories(
        character_id=CHARACTER_ID,
        query=query,
        limit=limit,
    )
    if not results["memories"]:
        return "No relevant memories found."
    lines = []
    for mem in results["memories"]:
        lines.append(f"[{mem['category']}] {mem['content']}")
    return "\n".join(lines)


@function_tool
def add_memory(content: str) -> str:
    """Store an important fact, decision, or preference in long-term memory.
    Call this when the user shares something worth remembering for future sessions,
    such as preferences, project decisions, or personal details."""
    result = client.add_memory(
        character_id=CHARACTER_ID,
        content=content,
    )
    return f"Stored: {result['id']} [{result.get('category', 'auto')}]"

Create an agent with memory

Wire the tools into an OpenAI agent.

from agents import Agent, Runner

agent = Agent(
    name="Memory Assistant",
    instructions=(
        "You are a helpful assistant with long-term memory. "
        "At the start of each conversation, search your memory for relevant context. "
        "When the user shares preferences, decisions, or important facts, store them "
        "in memory so you remember next time. "
        "Always acknowledge when you recall something from a previous session."
    ),
    tools=[search_memories, add_memory],
)

# Run the agent
result = Runner.run_sync(agent, "I just switched to a standing desk. Remember that.")
print(result.final_output)

The agent will call add_memory to store the standing desk preference. In a future session:

result = Runner.run_sync(agent, "What do you know about my workspace setup?")
print(result.final_output)
# The agent calls search_memories and recalls the standing desk.

Full working example

A complete script showing a multi-turn agent with persistent memory.

from agents import Agent, Runner
from hippodid import HippoDid

client = HippoDid(api_key="hd_key_...")
CHARACTER_ID = "YOUR_CHARACTER_ID"


@function_tool
def search_memories(query: str, limit: int = 5) -> str:
    """Search long-term memory for facts, preferences, and decisions from past sessions."""
    results = client.search_memories(
        character_id=CHARACTER_ID, query=query, limit=limit,
    )
    if not results["memories"]:
        return "No relevant memories found."
    return "\n".join(
        f"[{m['category']}] {m['content']}" for m in results["memories"]
    )


@function_tool
def add_memory(content: str) -> str:
    """Store a fact or preference in long-term memory for future sessions."""
    result = client.add_memory(character_id=CHARACTER_ID, content=content)
    return f"Stored: {result['id']}"


agent = Agent(
    name="Personal Assistant",
    instructions=(
        "You are a personal assistant with persistent memory. "
        "Search memory at the start of conversations for context. "
        "Store new preferences and decisions when the user shares them. "
        "Reference past memories naturally — do not list them mechanically."
    ),
    tools=[search_memories, add_memory],
)


def chat(message: str) -> str:
    result = Runner.run_sync(agent, message)
    return result.final_output


# Session 1
print(chat("My favorite programming language is Rust. I'm working on a CLI tool."))

# Session 2 (could be days later)
print(chat("Can you suggest a good library for my project?"))
# Agent recalls Rust + CLI tool and suggests clap, serde, etc.

Per-customer agents

For multi-tenant applications, resolve the character ID dynamically based on the customer.

def get_agent_for_customer(customer_email: str) -> Agent:
    # Resolve character by alias
    character = client.resolve_character(alias=f"client:{customer_email}")
    char_id = character["id"]

    @function_tool
    def search_memories(query: str, limit: int = 5) -> str:
        """Search this customer's memory."""
        results = client.search_memories(character_id=char_id, query=query, limit=limit)
        if not results["memories"]:
            return "No relevant memories found."
        return "\n".join(f"[{m['category']}] {m['content']}" for m in results["memories"])

    @function_tool
    def add_memory(content: str) -> str:
        """Store a fact about this customer."""
        result = client.add_memory(character_id=char_id, content=content)
        return f"Stored: {result['id']}"

    return Agent(
        name="Support Agent",
        instructions="You are a support agent. Search memory for customer context before responding.",
        tools=[search_memories, add_memory],
    )

# Usage
agent = get_agent_for_customer("alice@example.com")
result = Runner.run_sync(agent, "I need help with my subscription.")

Using assemble_context for richer prompts

Instead of having the agent search during execution, you can pre-load context into the system prompt using assemble_context().

context = client.assemble_context(
    character_id=CHARACTER_ID,
    query="user asking about their project",
    strategy="task_focused",
    max_tokens=2000,
)

agent = Agent(
    name="Project Assistant",
    instructions=(
        f"You are a project assistant. Here is what you know about the user:\n\n"
        f"{context}\n\n"
        f"Use this context to give informed, personalized responses."
    ),
    tools=[add_memory],  # still allow storing new facts
)

This approach is useful when you want the agent to have full context immediately without spending a tool call on search.


Tips

  • Always include search_memories in the tools list. The agent will learn to call it at the start of conversations when the instructions tell it to.
  • Write clear tool descriptions. The agent decides when to call tools based on the description string. Be specific about when each tool should be used.
  • Use EXTRACTED mode (the default) so HippoDid’s AI categorizes and structures the memories automatically.
  • Combine with assemble_context for the best of both worlds: pre-loaded context in the system prompt plus the ability to search for more during execution.

Next steps


Copyright © 2026 SameThoughts. HippoDid is proprietary software. Open-source components (Spring Boot Starter, MCP Server) are Apache 2.0.

This site uses Just the Docs, a documentation theme for Jekyll.