Skip to main content

Production-grade long-term memory system for AI conversations

Project description

Eidetic

Production-grade long-term memory system for AI conversations. Extracts semantic facts and episodic bubbles from conversation turns, stores them in a FAISS vector index with SQLite persistence, and surfaces them via a simple Python API or FastAPI HTTP server.

Features

  • Dual Memory Types: Semantic facts (stable, long-term) + Episodic bubbles (time-bound moments)
  • Fast Search: FAISS-powered vector similarity search
  • Smart Updates: LLM-based contradiction detection (ADD / UPDATE / REPLACE / DELETE / NOOP)
  • Memory Connections: Bubbles auto-link to related facts
  • Multi-Provider: OpenAI or OpenRouter (Claude, Gemini, etc.)
  • Flexible Storage: SQLite (default) or PostgreSQL
  • Full async: Python 3.12+, SQLAlchemy 2.0 asyncio

Installation

pip install eidetic-ai

# For the HTTP server (optional):
pip install 'eidetic-ai[server]'

# For PostgreSQL (optional):
pip install 'eidetic-ai[postgres]'

Quick Start (Library)

import asyncio
from eidetic import configure, Memory, create_table

# Configure with your API key
configure(openai_api_key="sk-...")

# Create tables (first time only)
async def main():
    await create_table()

    memory = Memory()

    # Add memories from a conversation turn
    result = await memory.add(
        messages=[
            {"role": "user", "content": "Hi, I'm Alice and I love Python"},
            {"role": "assistant", "content": "Nice to meet you, Alice!"},
        ],
        conversation_id=1,
    )
    print(result)
    # {'semantic': ['User is named Alice', 'User loves Python'], 'bubbles': []}

    # Search stored memories
    results = await memory.search(
        query="What programming language?",
        conversation_id=1,
        limit=5,
    )
    for r in results["results"]:
        print(f"  [{r['type']}] {r['memory']} (score: {r['score']})")

asyncio.run(main())

Environment Variables

export EIDETIC_OPENAI_API_KEY="sk-..."
# Or for OpenRouter:
export EIDETIC_OPENROUTER_API_KEY="sk-or-v1-..."
export EIDETIC_LLM_PROVIDER="openrouter"
export EIDETIC_DATABASE_URL="sqlite+aiosqlite:///path/to/eidetic.db"

Full Example: Chat with Memory

import asyncio
from openai import OpenAI
from eidetic import configure, Memory, create_table

configure(openrouter_api_key="sk-or-v1-...", llm_provider="openrouter")
chat = OpenAI(api_key="sk-or-v1-...", base_url="https://openrouter.ai/api/v1")

async def main():
    await create_table()
    memory = Memory()

    def chat_with_memories(message: str, conv_id: int = 1) -> str:
        # 1. Search relevant memories
        results = asyncio.run(memory.search(query=message, conversation_id=conv_id, limit=5))
        memories_str = "\n".join(
            f"- [{r['type']}] {r['memory']}"
            for r in results["results"]
        )

        # 2. Build prompt with memories
        system = f"You are a helpful AI.\n\nUser Memories:\n{memories_str or 'None yet.'}"

        # 3. Call LLM
        response = chat.chat.completions.create(
            model="anthropic/claude-sonnet-4.5",
            messages=[
                {"role": "system", "content": system},
                {"role": "user", "content": message},
            ],
        )
        reply = response.choices[0].message.content

        # 4. Store new memories
        asyncio.run(memory.add(
            messages=[{"role": "user", "content": message}, {"role": "assistant", "content": reply}],
            conversation_id=conv_id,
        ))
        return reply

    while True:
        msg = input("You: ")
        if msg.lower() == "exit":
            break
        print(f"AI: {chat_with_memories(msg)}")

asyncio.run(main())

HTTP Server

pip install 'eidetic[server]'

# Start the API server
eidetic serve

API Endpoints

Method Path Description
GET /health Health check
POST /conversations Create a conversation
POST /memories Add memories from a conversation turn
GET /memories/search Search memories by similarity
PUT /memories/{id} Update a memory's text
DELETE /memories/{id} Soft-delete a memory
POST /bubbles/expire Run bubble TTL expiry

Full OpenAPI docs at /docs when the server is running.

Docker

docker compose up --build

Set API keys via environment variables (see .env.example).

CLI

eidetic create-conversation           create a new conversation
eidetic add <conv_id> <user> <asst>   add memories from one turn
eidetic search <conv_id> <query>      search stored memories
eidetic expire-bubbles [conv_id]      run bubble TTL expiry

Architecture

┌─────────────┐    ┌──────────────┐    ┌──────────────┐
│  FastAPI    │───▶│ MemoryService │───▶│  Extractor   │
│  (HTTP)     │    │  (orchestr.) │    │  (LLM)       │
└─────────────┘    └──────┬───────┘    └──────────────┘
                          │
             ┌────────────┼────────────┐
             ▼            ▼            ▼
      ┌──────────┐ ┌──────────┐ ┌──────────┐
      │Classifier│ │  Bubble  │ │ Summary  │
      │ (LLM)    │ │  Creator │ │ Service  │
      └──────────┘ └──────────┘ └──────────┘
                          │
             ┌────────────┼────────────┐
             ▼            ▼            ▼
      ┌──────────┐ ┌──────────┐ ┌──────────┐
      │  FAISS   │ │ SQLite   │ │  LLM /   │
      │  Index   │ │   DB     │ │ Embedding │
      └──────────┘ └──────────┘ └──────────┘

Memory types:

  • Semantic — stable long-term facts about the user (name, preferences, skills). Deduplicated and updated via an LLM classifier (ADD / UPDATE / REPLACE / DELETE / NOOP).
  • Bubbles (episodic) — time-bound significant moments. Linked bidirectionally to related memories via FAISS similarity. Automatically expired after a configurable TTL.

Config

All configuration via environment variables with prefix EIDETIC_ or via the configure() function:

Variable / kwarg Default Description
EIDETIC_OPENAI_API_KEY OpenAI API key
EIDETIC_OPENROUTER_API_KEY OpenRouter API key
EIDETIC_LLM_PROVIDER openai openai or openrouter
EIDETIC_LLM_MODEL gpt-4o-mini LLM model name
EIDETIC_EMBEDDING_MODEL text-embedding-3-small Embedding model name
EIDETIC_DATABASE_URL ~/.eidetic/eidetic.db SQLAlchemy async DB URL
EIDETIC_DEBUG false Enable debug logging
EIDETIC_BUBBLE_TTL_DAYS 30 Bubble expiry in days (0 = never)
EIDETIC_CONNECTION_THRESHOLD 0.6 Min similarity for bubble links
EIDETIC_MAX_CONNECTIONS_PER_BUBBLE 5 Max bidirectional links per bubble

Development

uv sync --extra dev --extra server
uv run ruff check src/ tests/
uv run mypy src/
uv run pytest -v

License

MIT

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

eidetic_ai-0.2.0.tar.gz (50.0 kB view details)

Uploaded Source

Built Distribution

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

eidetic_ai-0.2.0-py3-none-any.whl (64.3 kB view details)

Uploaded Python 3

File details

Details for the file eidetic_ai-0.2.0.tar.gz.

File metadata

  • Download URL: eidetic_ai-0.2.0.tar.gz
  • Upload date:
  • Size: 50.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for eidetic_ai-0.2.0.tar.gz
Algorithm Hash digest
SHA256 15031a209384e1d90e19c322322ba2c027a4f973af2b0ece505b2e7e441198e8
MD5 800e4d8c84d3bdbab4468f390d0c5b9e
BLAKE2b-256 7ddff7978925468d3de5f8541a6447cd6deb6ee05c3673b25c70b3204e020d2c

See more details on using hashes here.

File details

Details for the file eidetic_ai-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: eidetic_ai-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 64.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.30 {"installer":{"name":"uv","version":"0.11.30","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for eidetic_ai-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 e7a632894d459583c0fc16479cfee9e8a2821ba0cc8f30ce13387fefbae6a321
MD5 3acc598fa3f2ed3fa0e69f9ea951e88a
BLAKE2b-256 460753139520d4526174299d5b8bcedd53116af7c9eac6b4c31dc69a4675e0ab

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