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.1.tar.gz (47.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.1-py3-none-any.whl (60.4 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: eidetic_ai-0.2.1.tar.gz
  • Upload date:
  • Size: 47.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.1.tar.gz
Algorithm Hash digest
SHA256 60366b2bffca0923a19d543f3fa1833f550fbcd84ee607356ab9b43d51c53d6e
MD5 49fdf99c5e2c7cf4692a686302c34881
BLAKE2b-256 16a50033ee721f690c0679f2c70b5b9265452874d6f11402666fc7b318dc8587

See more details on using hashes here.

File details

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

File metadata

  • Download URL: eidetic_ai-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 60.4 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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e284ae917f7ee118960517aeb2a5da95ef225cee729e0e1aa88ce621b360f827
MD5 ee02e3c6d09ac5cf607f01940a934f7a
BLAKE2b-256 adb681568d6bad3571e4959c5d3a5347f2d45f92c29541a361d73f241c9ec66c

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