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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15031a209384e1d90e19c322322ba2c027a4f973af2b0ece505b2e7e441198e8
|
|
| MD5 |
800e4d8c84d3bdbab4468f390d0c5b9e
|
|
| BLAKE2b-256 |
7ddff7978925468d3de5f8541a6447cd6deb6ee05c3673b25c70b3204e020d2c
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e7a632894d459583c0fc16479cfee9e8a2821ba0cc8f30ce13387fefbae6a321
|
|
| MD5 |
3acc598fa3f2ed3fa0e69f9ea951e88a
|
|
| BLAKE2b-256 |
460753139520d4526174299d5b8bcedd53116af7c9eac6b4c31dc69a4675e0ab
|