This release is a pre-release and may not be stable for production use.
GLLM Memory
Description
Memory layer for AI agents. The public API is MemoryManager. You can use it in two ways:
- HTTP mode: use
api_keyand optionalhost - SDK mode: use
MemoryManagerConfigand passconfig=...
In SDK mode, you can register your own LLM, embedding model, memory store, and optional reranker without exposing backend-specific config to application code.
TL;DR / 30-Second Example
Fastest HTTP mode example:
from gllm_inference.schema.message import Message
from gllm_memory import MemoryManager
from gllm_memory.enums import MemoryScope
memory_manager = MemoryManager(api_key="your_mem0_api_key")
await memory_manager.add(
user_id="user_123",
agent_id="agent_456",
messages=[Message.user("I love pizza")],
scopes={MemoryScope.USER},
)
results = await memory_manager.search(
query="What does the user like?",
user_id="user_123",
scopes={MemoryScope.USER},
)
For the recommended SDK mode setup with MemoryManagerConfig, see SDK Mode.
Installation & Setup
Requirements
- Python 3.11+ — Install here
- pip or uv — pip, uv
- gcloud CLI — Install here
- Git — only needed for local development from a cloned repository
Authentication
Use this once when you need internal packages or local development setup:
gcloud auth login
export UV_INDEX_GEN_AI_INTERNAL_USERNAME=oauth2accesstoken
export UV_INDEX_GEN_AI_INTERNAL_PASSWORD="$(gcloud auth print-access-token)"
export UV_INDEX_GEN_AI_USERNAME=oauth2accesstoken
export UV_INDEX_GEN_AI_PASSWORD="$(gcloud auth print-access-token)"
Install from Artifact Registry
uv pip install \
--extra-index-url "https://oauth2accesstoken:$(gcloud auth print-access-token)@glsdk.gdplabs.id/gen-ai-internal/simple/" \
gllm-memory
Install from Local Clone
git clone git@github.com:GDP-ADMIN/gl-sdk.git
cd gl-sdk/libs/gllm-memory
pip install -e .
For the full local development setup with project tooling:
make setup
source .venv/bin/activate
Runtime Notes
- HTTP mode uses
MEM0_API_KEYand optionalMEM0_HOST. - SDK mode uses
MemoryManagerConfig(...)and lets your app register LM, embedding, memory store, and optional retrieval reranker.
Optional Dependencies
- OpenAI-based SDK examples require OpenAI support from
gllm-inference, for examplegllm-inference[openai]. - Knowledge graph examples require the KG dependencies used by this repository setup.
Typical environment variables:
| Variable | Role |
|---|---|
MEM0_API_KEY |
Required for the HTTP client when not passed in code. |
MEM0_HOST |
Optional; base URL for self-hosted Mem0 API. |
MEMORY_PROVIDER |
Optional; default is Mem0 (mem0). |
MEMORY_DEDUP_ENABLED |
Optional; enables the internal semantic memory dedupe weekend job (default false). |
MEMORY_DEDUP_SIMILARITY_THRESHOLD |
Optional; embedding similarity threshold for dedupe (default 0.65). |
MEMORY_DEDUP_CRON_DAY |
Optional; dedupe schedule day (default sat). |
MEMORY_DEDUP_CRON_HOUR |
Optional; dedupe schedule hour in server-local time (default 1). |
MEMORY_DEDUP_CRON_MINUTE |
Optional; dedupe schedule minute in server-local time (default 0). |
MEMORY_DEDUP_LOOKBACK_DAYS |
Optional; recent-window scan using created_at OR updated_at (default 7). |
MEMORY_DEDUP_MAX_CANDIDATES_PER_ANCHOR |
Optional; per-anchor semantic search cap (default 100). |
MEMORY_DEDUP_MAX_TARGET_MEMORIES |
Optional; per-partition safeguard before the job skips a large target (default 5000). |
TIMEOUT_SEC |
Optional; request timeout in seconds (default 30). Used when building clients from env. |
Do not commit secrets to git.
Semantic Memory Dedupe
gllm-memory includes one internal background job to reduce semantic duplicate memories in the vector store.
You do not call this job directly from MemoryManager. When semantic dedupe is enabled, the scheduler is registered automatically during MemoryManager initialization.
What it does:
- scans recent memories from the configured vector store
- groups candidates inside one partition:
scope + user_id + agent_id + source + target - finds semantically similar memories using embedding similarity
- keeps one canonical memory and removes duplicate rows when it is safe
Safety rules in the current implementation:
is_important=Truememories are never deleted- canonical priority is:
important > newer > richer content > older - if compatible memories are in the same context, the canonical memory can be updated with merged content before duplicate rows are deleted
- if custom metadata conflicts, that duplicate group is skipped
- deletion is hard delete from the vector store
Current behavior:
- the first version uses embedding-only comparison
- if
MEMORY_DEDUP_*variables are not set, semantic dedupe stays disabled by default - the default schedule is Saturday at
01:00 - the timezone follows the server-local timezone where
gllm-memoryruns - the default lookback window is the last
7days usingcreated_at OR updated_at - the default large-partition safeguard is
MEMORY_DEDUP_MAX_TARGET_MEMORIES=5000 - the job is process-local, so one process keeps one scheduler per vector-store target
- the current full-store scanner implementation is available for Elasticsearch-backed vector stores
Architecture
The system follows a layered architecture below:
┌──────────────────────────────────────────────────────────────┐
│ Application Layer │
├──────────────────────────────────────────────────────────────┤
│ Memory Manager │
├──────────────────────────────────────────────────────────────┤
│ Memory Client (Base) │
├──────────────────────────────────────────────────────────────┤
│ Provider Layer (Mem0) │
├──────────────────────────────────────────────────────────────┤
│ Mem0 Platform (HTTP client or Python SDK) │
└──────────────────────────────────────────────────────────────┘
🧩 SDK Mode With MemoryManagerConfig
Use this mode if you want to:
- register memory LLM and embedding invoker runtimes
- configure an optional reranker
- keep application code independent from backend-specific config shape
gllm-memory does not create provider-specific LM or embedding invokers for you in normal SDK usage. Your application builds the LM invoker, optional fallback invokers, one embedding invoker, and then wraps the memory LLM path with the library-owned MemoryLMComponent.
SDK Mode Example
Recommended LLM registration:
from gllm_inference.lm_invoker.lm_invoker import BaseLMInvoker
from gllm_inference.lm_invoker.openai_lm_invoker import OpenAILMInvoker
from gllm_memory import MemoryLMComponent, MemoryManagerConfig
def build_openai_lm_invoker(model_name: str) -> OpenAILMInvoker:
return OpenAILMInvoker(
model_name=model_name,
api_key="your_openai_api_key",
)
def build_fallback_lm_invokers() -> list[BaseLMInvoker]:
return [
build_openai_lm_invoker("gpt-4o-mini"),
]
def build_lm_component() -> MemoryLMComponent:
return MemoryLMComponent(
lm_invoker=build_openai_lm_invoker("gpt-5-nano"),
fallback_lms=build_fallback_lm_invokers() or None,
)
def build_em_invoker():
from gllm_inference.em_invoker.openai_em_invoker import OpenAIEMInvoker
return OpenAIEMInvoker(
model_name="text-embedding-3-small",
api_key="your_openai_api_key",
)
lm_component = build_lm_component()
em_invoker = build_em_invoker()
config = (
MemoryManagerConfig.builder()
.memory_store.elasticsearch(
host="localhost",
port=9200,
collection_name="memories",
embedding_model_dims=1536,
)
.embedding.register(
em_invoker,
embedding_dims=1536,
)
.llm.register_component(lm_component)
.reranker.similarity_based(
em_invoker,
top_k=5,
)
.build()
)
In this path, em_invoker and the underlying LM invokers are created by your application, while MemoryLMComponent is owned by gllm-memory. MemoryManager.instruction remains the source of truth for memory extraction instructions, and lm_component can route from one primary LM to fallback_lms when the primary LM fails.
The reranker is optional. If you do not need retrieval reranking, omit .reranker.similarity_based(...) from the builder. When configured with similarity_based(...), reranking runs in the external retrieval layer after provider retrieval returns chunks. The provider keeps native backend rerank disabled for this path so the request does not run double reranking. If your installed gllm_inference version still has a circular import on OpenAIEMInvoker, instantiate the EM invoker with a local lazy import like the example above.
SDK Mode With Default Config
If you want to use the default SDK setup, you can build an empty config:
from gllm_memory import MemoryManager, MemoryManagerConfig
config = MemoryManagerConfig.builder().build()
memory_manager = MemoryManager(config=config)
Default SDK behavior:
- memory store uses Elasticsearch
- embedding uses
gllm-inference: EM Invokerwith OpenAI defaults - llm uses
gllm-inferenceOpenAI defaults - reranker is omitted unless configured explicitly
Required environment variables for the default SDK config:
ELASTICSEARCH_HOSTELASTICSEARCH_PORTELASTICSEARCH_COLLECTION_NAMEELASTICSEARCH_EMBEDDING_MODEL_DIMSOPENAI_API_KEY
Optional environment variables:
ELASTICSEARCH_USERELASTICSEARCH_PASSWORDOPENAI_BASE_URLOPENAI_MODEL_NAME(default SDK LLM model override)OPENAI_EMBEDDING_MODEL(used byexamples/example_mem0_sdk_client.py)MEMORY_DEDUP_ENABLED(defaultfalse)MEMORY_DEDUP_SIMILARITY_THRESHOLD(default0.65)MEMORY_DEDUP_CRON_DAY(defaultsat)MEMORY_DEDUP_CRON_HOUR(default1)MEMORY_DEDUP_CRON_MINUTE(default0)
🌐 HTTP Mode
Use this mode if you want to connect to the HTTP API directly. Point the client at your own server:
from gllm_memory import MemoryManager
manager = MemoryManager(
api_key="your-api-key",
host="https://your-mem0-server.com",
)
If you want local SDK mode, use MemoryManager(config=...) instead of api_key and host.
HTTP Mode Example
from gllm_inference.schema.message import Message
from gllm_memory import MemoryManager
from gllm_memory.enums import MemoryScope
memory_manager = MemoryManager(api_key="...", host="...") # host optional
messages = [
Message.user("I love pizza"),
Message.assistant("Noted."),
]
await memory_manager.add(
user_id="user_123",
agent_id="agent_456",
messages=messages,
scopes={MemoryScope.USER},
metadata={"conversation_id": "chat_001"}, # Optional
infer=True, # Optional, defaults to True
is_important=False, # Optional, defaults to False
)
memories = await memory_manager.search(
query="What does the user like?",
user_id="user_123",
scopes={MemoryScope.USER},
metadata=None, # Optional
threshold=0.3, # Optional, defaults to 0.3
top_k=10, # Optional, defaults to 10
include_important=False, # Optional, defaults to False
rerank=False, # Optional, defaults to False; if True, applies re-ranking to results
)
🕸️ Knowledge Graph in GLLM Memory
gllm-memory can optionally use a Knowledge Graph (KG) so one search flow can combine:
- normal memory retrieval
- graph-based facts such as people, companies, places, and relationships
Enable it with the same public API:
memory_manager = MemoryManager(config=config)
Recommended setup:
from gllm_inference.lm_invoker.openai_lm_invoker import OpenAILMInvoker
from gllm_memory import MemoryManager, MemoryManagerConfig, Neo4jGraphStoreConfig
memory_lm_component = build_lm_component()
em_invoker = build_em_invoker()
kg_lm_invoker = OpenAILMInvoker(
model_name="gpt-4o-mini",
api_key="your_openai_api_key",
)
config = (
MemoryManagerConfig.builder()
.memory_store.elasticsearch(
host="localhost",
port=9200,
collection_name="memories",
embedding_model_dims=1536,
)
.embedding.register(
em_invoker,
embedding_dims=1536,
)
.llm.register_component(memory_lm_component)
.knowledge_graph.enable(
lm_invoker=kg_lm_invoker,
graph_store=Neo4jGraphStoreConfig(
uri="bolt://localhost:7687",
user="neo4j",
password="password",
),
)
.build()
)
memory_manager = MemoryManager(config=config)
MemoryManager enables KG automatically when the config contains a knowledge_graph section.
Detailed KG flows, storage isolation, update behavior, and delete behavior are documented in docs/knowledge-graph.md.
Core API methods
MemoryManager exposes async methods; query is required where noted.
Usage examples:
- SDK mode example: see SDK Mode With
MemoryManagerConfig - HTTP mode example: see 🌐 HTTP Mode
Methods
add(user_id, agent_id, messages, scopes, metadata, infer, is_important) -> list[Chunk]- Add new memories from message objects.search(query, user_id, agent_id, scopes, metadata, threshold, top_k, include_important, rerank) -> list[Chunk]- Search and retrieve memories by query.list_memories(user_id, agent_id, scopes, metadata, keywords, page, page_size) -> list[Chunk]- Get memories with pagination and optional keyword filtering.update(memory_id, new_content, metadata, user_id, agent_id, scopes, is_important) -> Chunk | None- Update one existing memory by ID.delete(memory_ids, user_id, agent_id, scopes, metadata) -> list[Chunk]- Delete memories by IDs or by user or agent identifiers. When KG is enabled, the related KG contribution is also cleaned up.delete_by_user_query(query, user_id, agent_id, scopes, metadata, threshold, top_k) -> list[Chunk]- Delete memories by query. When KG is enabled, the related KG contribution is also cleaned up.
🔧 Code Quality
# Format code with ruff
ruff format gllm_memory/ tests/
# Check code quality
ruff check gllm_memory/ tests/
# Fix auto-fixable issues
ruff check gllm_memory/ tests/ --fix
Local Development Utilities
The following Makefile commands are available for quick operations:
Install uv
make install-uv
Install Pre-Commit
make install-pre-commit
Install Dependencies
make install
Update Dependencies
make update
Run Tests
make test
Contributing
Please refer to the Python Style Guide for information about code style, documentation standards, and SCA requirements.
Contributing Steps
-
Fork and clone the repository
-
Set up development environment:
# Complete setup: installs uv, configures auth, installs packages, sets up pre-commit make setup
-
Activate virtual environment:
source .venv/bin/activate
-
Run tests to ensure everything works:
make test
-
Make your changes and ensure tests pass:
# Make your changes # Ensure tests pass make test
-
Submit a pull request:
# Submit a pull request git push origin your-branch
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
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 gllm_memory_binary-0.3.1b1-cp312-cp312-manylinux_2_31_x86_64.whl.
File metadata
- Download URL: gllm_memory_binary-0.3.1b1-cp312-cp312-manylinux_2_31_x86_64.whl
- Upload date:
- Size: 2.3 MB
- Tags: CPython 3.12, manylinux: glibc 2.31+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.8.24
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84c1c67254d19ce558c2d930a8860350de6adbaf9342fe9845547ef9a07e2da3
|
|
| MD5 |
c483b5f426efe00568f9007f71ed6ce8
|
|
| BLAKE2b-256 |
cfea48d056011dc3fc53a90b84522c9203ec2edaf18b185398f2ed7435d664a9
|
File details
Details for the file gllm_memory_binary-0.3.1b1-cp311-cp311-manylinux_2_31_x86_64.whl.
File metadata
- Download URL: gllm_memory_binary-0.3.1b1-cp311-cp311-manylinux_2_31_x86_64.whl
- Upload date:
- Size: 2.1 MB
- Tags: CPython 3.11, manylinux: glibc 2.31+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
uv/0.8.24
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
52e21ad8e34f3ebf7dbe13b3abdb94ea49c144769e6e7b2925c4f0cd11ef6846
|
|
| MD5 |
1a47b737166c16bf89e740b7a0d12048
|
|
| BLAKE2b-256 |
220dc7ef8640465a69feb888882dcae1131b585c3646feec5f8c4d99b984638e
|