Skip to main content

Hierarchical memory management for AI agents with vector search and graph relationships

Project description

Agent Mem

A standalone Python package for hierarchical memory management in AI agents. Provides a stateless interface to manage active, short-term, and long-term memories with vector search, graph relationships, and intelligent consolidation.

๐Ÿš€ Quick Links

โœ… Current Status

Overall Progress: 89% complete (98/110 major tasks completed)

Completed Phases:

  • โœ… Phase 1: Core infrastructure (PostgreSQL + Neo4j, embedding service)
  • โœ… Phase 2: Memory tiers (Active, Shortterm, Longterm repositories)
  • โœ… Phase 3: Memory Manager (consolidation, promotion, retrieval)
  • โœ… Phase 4: AI Agents (ER Extractor, Memory Retrieve, Memory Update)
  • โœ… Phase 5: Testing (27 test suites - needs rewrite to match implementation)
  • โœ… Phase 9: Streamlit UI (100% - Web UI fully functional)
  • โœ… Phase 10: MCP Server (100% - Claude Desktop integration ready)

In Progress:

  • ๐Ÿ“– Phase 6: Examples and demonstrations (20% complete)
  • ๐Ÿ“š Phase 7: Complete API documentation (50% complete)
  • ๐Ÿš€ Phase 8: Production deployment (not started)

See docs/IMPLEMENTATION_STATUS.md for detailed progress

๐ŸŽจ Streamlit Web UI

NEW: AgentMem now includes a web-based UI for managing memories without writing code!

Features

  • ๐Ÿ“š Browse Templates - Explore 60+ pre-built BMAD templates
  • โž• Create Memories - Create memories using templates or custom YAML
  • ๐Ÿ“‹ View Memories - Browse all memories for an agent
  • โœ๏ธ Update Sections - Edit memory sections with live Markdown preview
  • ๐Ÿ—‘๏ธ Delete Memories - Safely delete with type-to-confirm protection

Starting the UI

cd streamlit_app
streamlit run app.py

The UI will open at http://localhost:8501

User Guide

See docs/STREAMLIT_UI_USER_GUIDE.md for complete usage instructions.


๐Ÿ”Œ MCP Server for Claude Desktop

NEW: AgentMem now includes a Model Context Protocol (MCP) server for integration with Claude Desktop and other MCP clients!

Features

  • ๐Ÿ” get_active_memories - Retrieve all active memories for an agent
  • โž• create_active_memory - Create new active memory with template
  • ๐Ÿ“ update_memory_sections - Batch upsert multiple sections (insert/update/replace)
  • ๐Ÿ—‘๏ธ delete_active_memory - Delete an active memory
  • ๐Ÿ”Ž search_memories - Search across memory tiers with AI-synthesized responses

Quick Start

# Run the MCP server (recommended: using uv)
uv run agent_reminiscence_mcp\run.py

# Alternative: using Python directly
py agent_reminiscence_mcp\run.py

# Add sample data for testing
uv run agent_reminiscence_mcp\tests\add_sample_data.py

# Test with Python client
uv run agent_reminiscence_mcp\tests\test_mcp_client.py

Claude Desktop Integration

Add to your Claude Desktop config (%APPDATA%\Claude\claude_desktop_config.json):

{
  "mcpServers": {
    "agent-reminiscence": {
      "command": "uv",
      "args": [
        "run",
        "path_to_agent_reminiscence_mcp\\run.py"
      ],
      "env": {
        "POSTGRES_HOST": "localhost",
        "POSTGRES_PORT": "5432",
        "POSTGRES_USER": "postgres",
        "POSTGRES_PASSWORD": "postgres",
        "POSTGRES_DB": "agent_reminiscence",
        "NEO4J_URI": "bolt://localhost:7687",
        "NEO4J_USER": "neo4j",
        "NEO4J_PASSWORD": "neo4jpassword",
        "OLLAMA_BASE_URL": "http://localhost:11434"
      }
    }
  }
}

Important:

  • Use uv command for better dependency management
  • Use absolute path (adjust to your installation directory)
  • Ensure environment variables match your .env file
  • Double backslashes required in JSON on Windows

Documentation


Key Features

  • Stateless Design: One AgentMem instance can serve multiple agents/workers
  • Template-Driven Memory: Active memories use YAML templates with structured sections
  • Section-Level Tracking: Each section tracks its own update_count for consolidation
  • Three-Tier Memory: Active (template+sections) โ†’ Shortterm (chunks+entities) โ†’ Longterm (temporal)
  • Simple API: Just 4 methods to manage all your agent's memories
  • Vector Search: Semantic search using embeddings via Ollama
  • Graph Relationships: Entity and relationship tracking with Neo4j
  • Smart Consolidation: Automatic section-level consolidation with conflict resolution
  • Generic ID Support: Use any external ID (UUID, string, int) for your agents

Quick Start

Installation

Linux/Mac:

cd libs/agent_reminiscence
pip install -e .

Windows:

cd libs\agent_reminiscence
py -m pip install -e .

Or add to your project's requirements:

echo "agent-reminiscence @ file:///${PWD}/libs/agent_reminiscence" >> requirements.txt

Prerequisites

Using Docker Compose (Recommended):

The easiest way is to use the provided Docker Compose configuration:

# Start all services (PostgreSQL, Neo4j, Ollama)
docker compose up -d

# Check services are running
docker compose ps

Manual Setup:

  1. PostgreSQL with extensions:

    • pgvector for vector storage
    • pg_tokenizer for text tokenization
    • vchord_bm25 for BM25 search
  2. Neo4j for graph storage

  3. Ollama for embeddings:

    ollama pull nomic-embed-text
    

Configuration

AgentMem supports three configuration methods:

Pattern 1: Direct Python (Recommended for PyPI users)

from agent_reminiscence import AgentMem, Config

config = Config(
    postgres_host="localhost",
    postgres_password="secure_password",
    neo4j_uri="bolt://localhost:7687",
    neo4j_password="neo4j_password",
    ollama_base_url="http://localhost:11434"
)

agent_reminiscence = AgentMem(config=config)

Pattern 2: Environment Variables (Recommended for Docker/K8s)

export POSTGRES_HOST=postgres
export POSTGRES_PASSWORD=secure_pass
export NEO4J_URI=bolt://neo4j:7687
export NEO4J_PASSWORD=neo4j_pass
export OLLAMA_BASE_URL=http://ollama:11434
python your_app.py
from agent_reminiscence import AgentMem

agent_reminiscence = AgentMem()  # Uses environment variables

Pattern 3: .env File (Convenient for local development)

Create a .env file:

# PostgreSQL
POSTGRES_HOST=localhost
POSTGRES_PORT=5432
POSTGRES_USER=postgres
POSTGRES_PASSWORD=your_password
POSTGRES_DB=agent_reminiscence

# Neo4j
NEO4J_URI=bolt://localhost:7687
NEO4J_USER=neo4j
NEO4J_PASSWORD=your_password
NEO4J_DATABASE=neo4j

# Ollama
OLLAMA_BASE_URL=http://localhost:11434

# Model Configuration
EMBEDDING_MODEL=nomic-embed-text
VECTOR_DIMENSION=768

# Agent Models (Optional - defaults to Gemini)
MEMORY_UPDATE_AGENT_MODEL=google:gemini-2.0-flash
MEMORIZER_AGENT_MODEL=google:gemini-2.0-flash
MEMORY_RETRIEVE_AGENT_MODEL=google:gemini-2.0-flash
# Automatically loaded if python-dotenv is available
from agent_reminiscence import AgentMem

agent_reminiscence = AgentMem()  # Uses .env file

Note: python-dotenv is optional. Install with pip install agent-reminiscence[dev] for .env file support.

Basic Usage

from agent_reminiscence import AgentMem
import asyncio

# Template defining memory structure
TASK_TEMPLATE = """
template:
  id: "task_memory_v1"
  name: "Task Memory"
sections:
  - id: "current_task"
    title: "Current Task"
  - id: "progress"
    title: "Progress"
"""

async def main():
    # Initialize STATELESS memory manager (serves multiple agents)
    agent_reminiscence = AgentMem()
    
    # Initialize database connections
    await agent_reminiscence.initialize()
    
    try:
        # 1. Create an active memory with template
        memory = await agent_reminiscence.create_active_memory(
            external_id="agent-123",  # Pass agent ID to method
            title="Build Dashboard",
            template_content=TASK_TEMPLATE,  # Can be YAML string or dict
            initial_sections={
                "current_task": {
                    "content": "Implement real-time analytics",
                    "update_count": 0,
                    "awake_update_count": 0,
                    "last_updated": None
                },
                "progress": {
                    "content": "- Designed UI\n- Set up project",
                    "update_count": 0,
                    "awake_update_count": 0,
                    "last_updated": None
                }
            },
            metadata={"priority": "high"}
        )
        print(f"Created memory: {memory.id}")
        
        # 2. Get all active memories for agent
        all_memories = await agent_reminiscence.get_active_memories(
            external_id="agent-123"
        )
        print(f"Total memories: {len(all_memories)}")
        
        # 3. Update multiple sections with upsert (batch operation)
        await agent_reminiscence.update_active_memory_sections(
            external_id="agent-123",
            memory_id=memory.id,
            sections=[
                {
                    "section_id": "progress",
                    "new_content": "- Designed UI\n- Set up project\n- Implemented analytics",
                    "action": "replace"  # Replace entire content
                },
                {
                    "section_id": "blockers",  # New section (upsert)
                    "new_content": "# Blockers\n- None currently",
                    "action": "replace"
                }
            ]
        )
            new_content="- Designed UI\n- Set up project\n- Implemented charts"
        )
        
        # 4. Retrieve memories (searches across all tiers)
        results = await agent_reminiscence.retrieve_memories(
            external_id="agent-123",
            query="What is the current progress on the dashboard?",
            limit=10,
            synthesis=True  # Request AI summary of findings
        )
        
        # Access results
        print(f"Mode: {results.mode}")  # "pointer" or "synthesis"
        print(f"Found {len(results.chunks)} chunks, {len(results.entities)} entities")
        if results.synthesis:
            print(f"AI Summary: {results.synthesis}")
        
    finally:
        # Clean up connections
        await agent_reminiscence.close()

if __name__ == "__main__":
    asyncio.run(main())

Architecture

agent_reminiscence/
โ”œโ”€โ”€ __init__.py              # Public API exports
โ”œโ”€โ”€ core.py                  # AgentMem main class (STATELESS)
โ”œโ”€โ”€ config/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ settings.py          # Configuration management
โ”œโ”€โ”€ database/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ postgres_manager.py  # PostgreSQL connection pool
โ”‚   โ”œโ”€โ”€ neo4j_manager.py     # Neo4j connection manager
โ”‚   โ”œโ”€โ”€ repositories/
โ”‚   โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”‚   โ”œโ”€โ”€ active_memory.py      # Template + section CRUD
โ”‚   โ”‚   โ”œโ”€โ”€ shortterm_memory.py   # Shortterm memory CRUD
โ”‚   โ”‚   โ””โ”€โ”€ longterm_memory.py    # Longterm memory CRUD
โ”‚   โ””โ”€โ”€ models.py            # Pydantic models for data
โ”œโ”€โ”€ services/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ embedding.py         # Ollama embedding service
โ”‚   โ””โ”€โ”€ memory_manager.py    # Core memory operations (stateless)
โ”œโ”€โ”€ agents/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ”œโ”€โ”€ memory_updater.py    # Memory Update Agent
โ”‚   โ”œโ”€โ”€ memorizer.py         # Memory Consolidation Agent
โ”‚   โ””โ”€โ”€ memory_retriever.py  # Memory Retrieve Agent
โ”œโ”€โ”€ utils/
โ”‚   โ”œโ”€โ”€ __init__.py
โ”‚   โ””โ”€โ”€ helpers.py           # Utility functions
โ””โ”€โ”€ sql/
    โ”œโ”€โ”€ schema.sql           # PostgreSQL schema
    โ””โ”€โ”€ migrations/          # Future migrations

API Reference

AgentMem

The main class for memory management (STATELESS - serves multiple agents).

__init__(config: Optional[Config] = None)

Initialize stateless memory manager.

Parameters:

  • config: Optional configuration object (uses environment variables by default)

async initialize() -> None

Initialize database connections and ensure schema exists.

async create_active_memory(external_id: str | UUID | int, title: str, template_content: str | dict, initial_sections: Optional[dict] = None, metadata: Optional[dict] = None) -> ActiveMemory

Create a new active memory with template-driven structure.

Parameters:

  • external_id: Unique identifier for the agent (UUID, string, or int)
  • title: Memory title
  • template_content: Template defining section structure. Can be:
    • Dict (JSON): {"template": {...}, "sections": [{"id": "...", "description": "..."}]}
    • Str (YAML): Parsed to dict automatically (backward compatible)
  • initial_sections: Optional initial sections that override template defaults
    • Format: {"section_id": {"content": "...", "update_count": 0, "awake_update_count": 0, "last_updated": None}}
  • metadata: Optional metadata dictionary

Returns: Created ActiveMemory object with sections

Section Structure: Each section contains:

  • content: Markdown content
  • update_count: Updates since last consolidation (resets to 0 after consolidation)
  • awake_update_count: Total updates (never resets, for future sleep/wake features)
  • last_updated: ISO timestamp of last update

async get_active_memories(external_id: str | UUID | int) -> List[ActiveMemory]

Get all active memories for a specific agent.

Parameters:

  • external_id: Unique identifier for the agent

Returns: List of ActiveMemory objects

async update_active_memory_section(external_id: str | UUID | int, memory_id: int, section_id: str, new_content: str) -> ActiveMemory

Update a specific section in an active memory.

Automatically increments the section's update_count and awake_update_count, and triggers consolidation when threshold is reached.

Parameters:

  • external_id: Unique identifier for the agent
  • memory_id: ID of memory to update
  • section_id: Section ID to update (defined in template)
  • new_content: New content for the section

Returns: Updated ActiveMemory object

async update_active_memory_sections(external_id: str | UUID | int, memory_id: int, sections: List[dict]) -> ActiveMemory

Upsert multiple sections in an active memory (batch operation).

Supports creating new sections, updating existing ones, content replacement with pattern matching, and content insertion/appending.

Parameters:

  • external_id: Unique identifier for the agent
  • memory_id: ID of memory to update
  • sections: List of section updates with structure:
    [
      {
        "section_id": "progress",
        "old_content": "# Old",  # Optional: pattern to find
        "new_content": "# New",
        "action": "replace"  # "replace" or "insert"
      }
    ]
    

Action Behaviors:

  • replace + no old_content: Replace entire section
  • replace + old_content: Replace that substring
  • insert + no old_content: Append at end
  • insert + old_content: Insert after pattern

Returns: Updated ActiveMemory object

async retrieve_memories(external_id: str | UUID | int, query: str, limit: int = 10, synthesis: bool = False) -> RetrievalResult

Search and retrieve relevant memories for a specific agent across all tiers.

Parameters:

  • external_id: Unique identifier for the agent
  • query: Natural language search query describing the context and what information is needed
  • limit: Maximum results per tier (default: 10)
  • synthesis: Force AI to generate a synthesized summary of results (default: False, AI decides)

Returns: RetrievalResult with matched chunks, entities, relationships, and optional AI synthesis

async close() -> None

Close all database connections.

Memory Tiers

Active Memory

  • Purpose: Template-driven working memory with sections
  • Storage: PostgreSQL with JSONB sections
  • Structure: JSON/YAML template + sections
    • Each section: {content, update_count, awake_update_count, last_updated}
  • Lifetime: Short (hours to days)
  • Updates: Frequent (per-section tracking with dual counters)
  • Use Case: Current task context, ongoing work, structured progress tracking
  • Consolidation: Section-level triggers based on update_count threshold

Shortterm Memory

  • Purpose: Searchable recent knowledge
  • Storage: PostgreSQL (vectors + BM25) + Neo4j (entities/relationships)
  • Lifetime: Medium (days to weeks)
  • Updates: Occasional (from active memory consolidation)
  • Use Case: Recent implementations, conversations, research findings

Longterm Memory

  • Purpose: Consolidated knowledge base
  • Storage: PostgreSQL (vectors + BM25) + Neo4j (entities/relationships)
  • Lifetime: Long (persistent)
  • Updates: Rare (promoted from shortterm with intelligent merging)
  • Use Case: Core knowledge, patterns, historical decisions
  • Promotion: Automatic with type merging, confidence recalculation, and state history tracking

Advanced Usage

Custom Configuration

from agent_reminiscence import AgentMem, Config

config = Config(
    postgres_host="custom-host",
    postgres_port=5433,
    embedding_model="custom-model",
    vector_dimension=1024,
)

agent_reminiscence = AgentMem(external_id="agent-456", config=config)

Automatic Consolidation

Memory consolidation happens automatically based on update thresholds. You can also trigger it manually:

# This is done internally, but exposed for advanced use cases
from agent_reminiscence.services import MemoryManager

manager = MemoryManager(external_id="agent-123")
await manager.consolidate_to_shortterm(active_memory_id=1)
await manager.promote_to_longterm(shortterm_memory_id=5)

Intelligent Promotion to Longterm

When shortterm memories are promoted to longterm, the system performs intelligent merging:

Entity Merging:

  • Matches entities by name (case-insensitive)
  • Merges types from both memories (union operation)
  • Recalculates confidence using weighted average (favors higher confidence)
  • Tracks complete state history in metadata

Relationship Merging:

  • Matches relationships by source and target entity names
  • Merges types from both memories (union operation)
  • Recalculates confidence and strength using weighted averages
  • Tracks complete state history in metadata

State History Example:

# Each entity/relationship tracks its evolution in metadata.state_history:
{
    "state_history": [
        {
            "timestamp": "2025-10-05T10:30:00Z",
            "source": "shortterm_promotion",
            "old_types": ["Person", "Developer"],
            "new_types": ["Person", "Developer", "Team Lead"],
            "old_confidence": 0.75,
            "new_confidence": 0.82
        }
    ]
}

This ensures no information is lost during promotion and provides a complete audit trail.

Working with Entities and Relationships

# Entities and relationships are automatically extracted during consolidation
# You can query them through the retrieval results

result = await agent_reminiscence.retrieve_memories("authentication system")

# Access entities
for entity in result.entities:
    print(f"Entity: {entity.name} (type: {entity.type})")

# Access relationships
for rel in result.relationships:
    print(f"Relationship: {rel.from_entity} -> {rel.type} -> {rel.to_entity}")

Development

Running Tests

# Install dev dependencies
pip install -e ".[dev]"

# Run tests
pytest tests/

# Run with coverage
pytest --cov=agent_reminiscence tests/

Building Documentation

cd docs/
mkdocs serve  # View locally
mkdocs build  # Build static site

Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

License

MIT License - see LICENSE for details.

Support

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

agent_reminiscence-0.1.3.tar.gz (184.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

agent_reminiscence-0.1.3-py3-none-any.whl (111.2 kB view details)

Uploaded Python 3

File details

Details for the file agent_reminiscence-0.1.3.tar.gz.

File metadata

  • Download URL: agent_reminiscence-0.1.3.tar.gz
  • Upload date:
  • Size: 184.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.11

File hashes

Hashes for agent_reminiscence-0.1.3.tar.gz
Algorithm Hash digest
SHA256 9f529df486a6d0ca35997e3c5c2535e1d81a8756ef53c11f2601baa07f78d1d5
MD5 caa57698a3fdca0bac9320e70ec95328
BLAKE2b-256 55556c8d2131ffbf19359ad530b352919eb6b626579047c169fa094502ed45ef

See more details on using hashes here.

File details

Details for the file agent_reminiscence-0.1.3-py3-none-any.whl.

File metadata

File hashes

Hashes for agent_reminiscence-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 6cfdab742fe6e95bbae205bfb11a461e657c5812d0bbb0cc8252bb82b8f78795
MD5 5d70767aa2cd78e6884ecb12a448b6e9
BLAKE2b-256 2bab907981a1988cafb6e2d4e403a3c7e4f6e3132e31626c1c9ca579fbbcaedb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page