Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8f7e1dc6e | ||
|
|
2ef6291307 |
@@ -1,69 +1,68 @@
|
||||
---
|
||||
title: Memory Types
|
||||
description: "What memory_type actually does in Mem0: procedural memory is implemented, semantic and episodic are not."
|
||||
description: "See how Mem0 layers conversation, session, and user memories to keep agents contextual."
|
||||
icon: "tag"
|
||||
iconType: "solid"
|
||||
---
|
||||
|
||||
# Memory Types
|
||||
# How Mem0 Organizes Memory
|
||||
|
||||
Mem0's Python SDK exposes a `memory_type` parameter on `add()`. The underlying `MemoryType` enum defines three values, but only one of them is wired up. This page states plainly which is which so you don't build against a type that doesn't exist yet.
|
||||
Mem0 separates memory into layers so agents remember the right detail at the right time. Think of it like a notebook: a sticky note for the current task, a daily journal for the session, and an archive for everything a user has shared.
|
||||
|
||||
## Status
|
||||
## Key terms
|
||||
|
||||
| Type | Enum value | Status | Notes |
|
||||
| --- | --- | --- | --- |
|
||||
| Procedural memory | `procedural_memory` | **Implemented** | Python OSS only (`Memory`/`AsyncMemory`). Pass `memory_type="procedural_memory"` and `agent_id` to `add()`. Not available on the Platform `MemoryClient`, and not available in the TypeScript SDK (OSS or Platform). |
|
||||
| Semantic memory | `semantic_memory` | **Not implemented** | Defined in the `MemoryType` enum but never read anywhere else in the codebase. Passing it to `add()` raises a validation error. There is no evidence in this repo of a roadmap date for this. |
|
||||
| Episodic memory | `episodic_memory` | **Not implemented** | Same as above: defined, never wired into the extraction pipeline, rejected by validation, no documented roadmap. |
|
||||
- **Conversation memory**: In-flight messages inside a single turn (what was just said).
|
||||
- **Session memory**: Short-lived facts that apply for the current task or channel.
|
||||
- **User memory**: Long-lived knowledge tied to a person, account, or workspace.
|
||||
- **Organizational memory**: Shared context available to multiple agents or teams.
|
||||
|
||||
<Warning>
|
||||
Only `procedural_memory` is a real, working value. Calling `memory.add(messages, memory_type="semantic_memory")` (or `episodic_memory`) is rejected and tells you to pass `procedural_memory` instead. Sync `Memory.add()` raises `Mem0ValidationError`; `AsyncMemory.add()` raises a plain `ValueError`.
|
||||
</Warning>
|
||||
|
||||
## Procedural memory
|
||||
|
||||
Procedural memory stores step-by-step task knowledge (how an agent performs a workflow) rather than facts about a user. It requires `agent_id`:
|
||||
|
||||
```python
|
||||
from mem0 import Memory
|
||||
|
||||
memory = Memory()
|
||||
|
||||
memory.add(
|
||||
[
|
||||
{"role": "user", "content": "Book a flight from SFO to NYC"},
|
||||
{"role": "assistant", "content": "1. Search flights. 2. Filter by price. 3. Confirm booking."},
|
||||
],
|
||||
agent_id="travel-agent",
|
||||
memory_type="procedural_memory",
|
||||
)
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Conversation turn] --> B[Session memory]
|
||||
B --> C[User memory]
|
||||
C --> D[Org memory]
|
||||
C --> E[Mem0 retrieval layer]
|
||||
```
|
||||
|
||||
Omit `memory_type` entirely and Mem0 stores the messages as an ordinary memory: there is no semantic/episodic pathway for it to fall into. Any other explicit value is rejected by validation rather than quietly falling back to an ordinary memory.
|
||||
## Short-term vs long-term memory
|
||||
|
||||
## How every other memory is scoped
|
||||
Short-term memory keeps the current conversation coherent. It includes:
|
||||
|
||||
Outside of the `procedural_memory` special case, Mem0 does not sort memories into named types. Every memory is scoped by the identifiers you pass in, and the same identifiers are used to retrieve it later:
|
||||
- **Conversation history**: recent turns in order so the agent remembers what was just said.
|
||||
- **Working memory**: temporary state such as tool outputs or intermediate calculations.
|
||||
- **Attention context**: the immediate focus of the assistant, similar to what a person holds in mind mid-sentence.
|
||||
|
||||
- **`user_id`**: ties a memory to a specific person or account.
|
||||
- **`agent_id`**: ties a memory to a specific agent or assistant persona.
|
||||
- **`run_id`**: ties a memory to a specific session, task, or conversation thread.
|
||||
- **`app_id`** (Platform only): ties a memory to a specific application or tenant, in addition to the three above. See <Link href="/platform/features/entity-scoped-memory">Entity-Scoped Memory</Link>.
|
||||
Long-term memory preserves knowledge across sessions. It captures:
|
||||
|
||||
At least one identifier is required on `add()`. Passing more than one narrows the scope further (for example, `user_id` + `run_id` together).
|
||||
- **Factual memory**: user preferences, account details, and domain facts.
|
||||
- **Episodic memory**: summaries of past interactions or completed tasks.
|
||||
- **Semantic memory**: relationships between concepts so agents can reason about them later.
|
||||
|
||||
Mem0 maps these classic categories onto its layered storage so you can decide what should fade quickly versus what should last for months.
|
||||
|
||||
## How does it work?
|
||||
|
||||
Mem0 stores each layer separately and merges them when you query:
|
||||
|
||||
1. **Capture**: Messages enter the conversation layer while the turn is active.
|
||||
2. **Promote**: Relevant details persist to session or user memory based on your `user_id`, `run_id`, and metadata.
|
||||
3. **Retrieve**: The search pipeline pulls from all layers, ranking user memories first, then session notes, then raw history.
|
||||
|
||||
```python
|
||||
import os
|
||||
|
||||
from mem0 import Memory
|
||||
|
||||
memory = Memory()
|
||||
|
||||
# Sticky note: conversation memory
|
||||
memory.add(
|
||||
"I'm Alex and I prefer boutique hotels.",
|
||||
["I'm Alex and I prefer boutique hotels."],
|
||||
user_id="alex",
|
||||
run_id="trip-planning-2025",
|
||||
)
|
||||
|
||||
# Later in the session, pull long-term + session context
|
||||
results = memory.search(
|
||||
"Any hotel preferences?",
|
||||
filters={"user_id": "alex", "run_id": "trip-planning-2025"},
|
||||
@@ -71,48 +70,52 @@ results = memory.search(
|
||||
```
|
||||
|
||||
<Tip>
|
||||
Use `run_id` when you want a set of memories to stay tied to one session or task; use `user_id` alone for anything that should persist across every session for that person.
|
||||
Use `run_id` when you want short-term context to expire automatically; rely on `user_id` for lasting personalization.
|
||||
</Tip>
|
||||
|
||||
## How memories are extracted and updated
|
||||
## When should you use each layer?
|
||||
|
||||
When `infer=True` (the default) on `add()`, Mem0 runs a single pipeline rather than routing through separate type-specific paths:
|
||||
- **Conversation memory**: Tool calls or chain-of-thought that only matter within the current turn.
|
||||
- **Session memory**: Multi-step tasks (onboarding flows, debugging sessions) that should reset once complete.
|
||||
- **User memory**: Personal preferences, account state, or compliance details that must persist across interactions.
|
||||
- **Organizational memory**: Shared FAQs, product catalogs, or policies that every agent should recall.
|
||||
|
||||
1. **Context gathering**: pulls the most recent messages already stored for the same `user_id`/`agent_id`/`run_id` scope.
|
||||
2. **Existing memory retrieval**: embeds the new messages and runs a vector search against memories already in that same scope, to find candidates that might need to change.
|
||||
3. **Extraction**: a single LLM call compares the new messages against the retrieved candidates and decides, per fact, whether to `ADD`, `UPDATE`, `DELETE`, or leave a memory alone.
|
||||
## How it compares
|
||||
|
||||
Alongside this, both OSS and Platform extract named entities (people, places, organizations) from memory text and use shared entities between memories to boost related results at search time. On Platform, that entity graph is also queryable directly; see <Link href="/platform/features/graph-memory">Graph Memory</Link>. In OSS, entities only affect ranking, there is no separate graph to query.
|
||||
| Layer | Lifetime | Short or long term | Best for | Trade-offs |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| Conversation | Single response | Short-term | Tool execution detail | Lost after the turn finishes |
|
||||
| Session | Minutes to hours | Short-term | Multi-step flows | Clear it manually when done |
|
||||
| User | Weeks to forever | Long-term | Personalization | Requires consent/governance |
|
||||
| Org | Configured globally | Long-term | Shared knowledge | Needs owner to keep current |
|
||||
|
||||
<Warning>
|
||||
Avoid storing secrets or unredacted PII in memories: they are retrievable by design. Encrypt or hash sensitive values before calling `add()`.
|
||||
Avoid storing secrets or unredacted PII in user or org memories: Mem0 is retrievable by design. Encrypt or hash sensitive values first.
|
||||
</Warning>
|
||||
|
||||
## Put it into practice
|
||||
|
||||
- Use the <Link href="/core-concepts/memory-operations/add">Add Memory</Link> guide to persist user preferences.
|
||||
- Follow <Link href="/platform/advanced-memory-operations">Advanced Memory Operations</Link> to tune metadata and retrieval.
|
||||
|
||||
## See it live
|
||||
|
||||
- <Link href="/cookbooks/companions/ai-tutor">AI Tutor with Mem0</Link> shows session vs user memories in action.
|
||||
- <Link href="/cookbooks/operations/support-inbox">Support Inbox with Mem0</Link> demonstrates shared org memory.
|
||||
|
||||
{/* DEBUG: verify CTA targets */}
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
title="Explore Memory Operations"
|
||||
description="Dive into the add/search/update/delete operations next."
|
||||
description="Dive into the add/search/update/delete concepts next."
|
||||
icon="circle-check"
|
||||
href="/core-concepts/memory-operations/add"
|
||||
/>
|
||||
<Card
|
||||
title="Advanced Memory Operations"
|
||||
description="Tune metadata, filters, and retrieval on Platform."
|
||||
icon="sliders"
|
||||
href="/platform/advanced-memory-operations"
|
||||
/>
|
||||
<Card
|
||||
title="AI Tutor Cookbook"
|
||||
description="See user_id-scoped memory used in a real tutoring agent."
|
||||
title="See a Cookbook"
|
||||
description="Apply layered memories inside a customer support agent."
|
||||
icon="rocket"
|
||||
href="/cookbooks/companions/ai-tutor"
|
||||
/>
|
||||
<Card
|
||||
title="Support Inbox Cookbook"
|
||||
description="See user_id-scoped memory used in a support workflow."
|
||||
icon="inbox"
|
||||
href="/cookbooks/operations/support-inbox"
|
||||
/>
|
||||
</CardGroup>
|
||||
|
||||
+1
-1
@@ -185,7 +185,7 @@ If the user is on a pre-current major (Python < 2, TS < 3, or a Platform call st
|
||||
## Core Concepts
|
||||
|
||||
- [How Mem0 Works](https://docs.mem0.ai/core-concepts/how-it-works) [Both]: Use when explaining the end-to-end pipeline: extraction (ADD-only distillation), storage across vector/entity/history stores, and multi-signal retrieval.
|
||||
- [Memory Types](https://docs.mem0.ai/core-concepts/memory-types) [Both]: Use when checking which `memory_type` values actually work: `procedural_memory` is implemented, `semantic_memory` and `episodic_memory` are defined in the enum but rejected by validation.
|
||||
- [Memory Types](https://docs.mem0.ai/core-concepts/memory-types) [Both]: Use when explaining working, factual, episodic, and semantic memory distinctions.
|
||||
- [Memory Operations - Add](https://docs.mem0.ai/core-concepts/memory-operations/add) [Both]: Use when explaining how `add()` extracts facts, resolves conflicts, and writes to both stores.
|
||||
- [Memory Operations - Search](https://docs.mem0.ai/core-concepts/memory-operations/search) [Both]: Use when explaining how queries are processed and ranked.
|
||||
- [Memory Operations - Update](https://docs.mem0.ai/core-concepts/memory-operations/update) [Both]: Use when memories need to be edited in place or reconciled against new info.
|
||||
|
||||
@@ -42,15 +42,14 @@ Filters use a nested JSON structure with logical operators at the root:
|
||||
### Time fields
|
||||
| Field | Operators | Example |
|
||||
|-------|-----------|---------|
|
||||
| `created_at` | `gt`, `gte`, `lt`, `lte`, `ne`, `in`. Explicit `eq` is rejected, pass a bare value instead | `{"created_at": {"gte": "2024-01-01"}}` |
|
||||
| `updated_at` | `gt`, `gte`, `lt`, `lte`, `ne`, `in`. Explicit `eq` is rejected, pass a bare value instead | `{"updated_at": {"lt": "2024-12-31"}}` |
|
||||
| `timestamp` | `gt`, `gte`, `lt`, `lte`, `ne`, `in`. Explicit `eq` is rejected, pass a bare value instead | `{"timestamp": {"gt": "2024-01-01"}}` |
|
||||
| `expiration_date` | `gt`, `gte`, `lt`, `lte`, `ne`, `in`. Explicit `eq` is rejected, pass a bare value instead | `{"expiration_date": {"lte": "2026-12-31"}}` |
|
||||
| `created_at` | `gt`, `gte`, `lt`, `lte`, `eq`, `ne` | `{"created_at": {"gte": "2024-01-01"}}` |
|
||||
| `updated_at` | `gt`, `gte`, `lt`, `lte`, `eq`, `ne` | `{"updated_at": {"lt": "2024-12-31"}}` |
|
||||
| `timestamp` | `gt`, `gte`, `lt`, `lte`, `eq`, `ne` | `{"timestamp": {"gt": "2024-01-01"}}` |
|
||||
|
||||
### Content fields
|
||||
| Field | Operators | Example |
|
||||
|-------|-----------|---------|
|
||||
| `categories` | `in` (takes a list, matches any category in it), `contains` (case-insensitive). `eq` and `ne` are rejected | `{"categories": {"in": ["finance"]}}` |
|
||||
| `categories` | `eq`, `ne`, `in` (matches any category in the list), `contains` (case-insensitive) | `{"categories": {"in": ["finance"]}}` |
|
||||
| `metadata` | `eq`, `ne`, `contains` | `{"metadata": {"key": "value"}}` |
|
||||
| `keywords` | `contains` (case-sensitive), `icontains` (case-insensitive) | `{"keywords": {"icontains": "invoice"}}` |
|
||||
|
||||
@@ -329,7 +328,7 @@ Level up foundational patterns with compound filters that coordinate entity scop
|
||||
## Best practices
|
||||
|
||||
<Callout type="tip" icon="lightbulb" color="#26A17B">
|
||||
The root does not have to be `AND`, `OR`, or `NOT`. A bare filter like `{"user_id": "alice"}` works on its own, and several top-level keys in one flat filter are implicitly ANDed. Wrap conditions in a logical operator when you need OR/NOT semantics or nested grouping.
|
||||
The root does not have to be `AND`, `OR`, or `NOT`. A bare filter like `{"user_id": "alice"}` works on its own; wrap conditions in a logical operator only when you need to combine more than one.
|
||||
</Callout>
|
||||
|
||||
<Callout type="tip" icon="lightbulb" color="#26A17B">
|
||||
@@ -393,7 +392,7 @@ A filter object with both an `AND` key and a sibling `OR` key at the same level
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Do I need AND/OR/NOT?">
|
||||
No. A bare filter like `{"user_id": "u1"}` works on its own, and several top-level keys in one flat filter like `{"user_id": "u1", "agent_id": "a1"}` are implicitly ANDed. Reach for `AND`, `OR`, or `NOT` when you need OR/NOT semantics or nested grouping, not merely to combine conditions.
|
||||
No. A bare filter like `{"user_id": "u1"}` works on its own. Add `AND`, `OR`, or `NOT` only when you need to combine more than one condition.
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="What does * match?">
|
||||
@@ -422,8 +421,8 @@ A filter object with both an `AND` key and a sibling `OR` key at the same level
|
||||
"AND": [
|
||||
{"user_id": "user_123"},
|
||||
{"OR": [
|
||||
{"categories": {"in": ["finance"]}},
|
||||
{"categories": {"in": ["health"]}}
|
||||
{"categories": "finance"},
|
||||
{"categories": "health"}
|
||||
]}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ icon: "code-compare"
|
||||
|
||||
## Which Mem0 is right for you?
|
||||
|
||||
Mem0 offers two ways to add memory to your AI applications. Both run the same core extraction and retrieval logic; the Platform adds hosting, a small set of v3-only capabilities, and management surfaces that OSS does not have.
|
||||
Mem0 offers two powerful ways to add memory to your AI applications. Choose based on your priorities:
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card
|
||||
@@ -16,7 +16,7 @@ Mem0 offers two ways to add memory to your AI applications. Both run the same co
|
||||
>
|
||||
**Managed, hassle-free**
|
||||
|
||||
Get started in 5 minutes with our hosted solution. No vector store, LLM, or embedder to configure.
|
||||
Get started in 5 minutes with our hosted solution. Perfect for fast iteration and production apps.
|
||||
</Card>
|
||||
|
||||
<Card
|
||||
@@ -32,85 +32,89 @@ Mem0 offers two ways to add memory to your AI applications. Both run the same co
|
||||
|
||||
---
|
||||
|
||||
## What's the same
|
||||
|
||||
The core memory loop is identical on both: `add`, `search`, `get`, `get_all`, `update`, `delete`, `delete_all`, and per-memory `history` all exist on the self-hosted `Memory`/`AsyncMemory` classes and on the hosted `MemoryClient`/`AsyncMemoryClient`. Both support:
|
||||
|
||||
- **Entity scoping** by `user_id`, `agent_id`, and `run_id`
|
||||
- **Filter grouping**: both accept `AND`/`OR`/`NOT` wrappers, both implicitly AND a flat multi-key filter like `{"user_id": "alice", "agent_id": "a1"}`, and both accept `*` as a wildcard value. Which fields you may filter on, and which operators each field accepts, differ (see below)
|
||||
- **Entity-aware ranking**: both extract entities from memory text and use shared entities to boost related results at search time
|
||||
- **Multimodal input**, **memory expiration** (`expiration_date`), **reranking**, **procedural memory** (Python), and **custom extraction instructions** (`custom_instructions`)
|
||||
- Python and JavaScript SDKs, plus a REST API (self-hosted via `server/`, or hosted)
|
||||
|
||||
## What's actually different
|
||||
## Feature Comparison
|
||||
|
||||
<AccordionGroup>
|
||||
<Accordion title="Hosting & infrastructure" icon="server">
|
||||
<Accordion title="Setup & Getting Started" icon="rocket">
|
||||
| Feature | Platform | Open Source |
|
||||
|---------|----------|-------------|
|
||||
| **Vector store, LLM, embedder** | Run and tuned by Mem0 | You provision, configure, and pay for each |
|
||||
| **Scaling & availability** | Managed | Your responsibility |
|
||||
| **Web dashboard** | `app.mem0.ai` | Not included |
|
||||
| **Time to first memory** | Minutes (API key only) | Depends on your vector DB / LLM setup |
|
||||
| **Time to first memory** | 5 minutes | 15-30 minutes |
|
||||
| **Infrastructure needed** | None | Vector DB + Python/Node env |
|
||||
| **API key setup** | One environment variable | Configure LLM + embedder + vector DB |
|
||||
| **Maintenance** | Fully managed by Mem0 | Self-managed |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Entity scoping & workspace structure" icon="layer-group">
|
||||
<Accordion title="Core Memory Features" icon="brain">
|
||||
| Feature | Platform | Open Source |
|
||||
|---------|----------|-------------|
|
||||
| **Scoping identifiers** | `user_id`, `agent_id`, `run_id`, plus `app_id` for app/tenant separation | `user_id`, `agent_id`, `run_id` only, no `app_id` |
|
||||
| **Organizations & projects** | Multi-org, multi-project, with member roles ([API reference](/api-reference/organization/get-org)) | No org/project concept; a single local config |
|
||||
| **Project-wide event feed** | `GET /v1/events/` lists recent add/search/delete events per org and project, usable for dashboards, alerting, or audit trails | Only per-memory `history(memory_id)`, no project-wide event log |
|
||||
|
||||
See [Entity-Scoped Memory](/platform/features/entity-scoped-memory) for the full `app_id` model.
|
||||
| **User & agent memories** | ✅ | ✅ |
|
||||
| **Smart deduplication** | ✅ | ✅ |
|
||||
| **Semantic search** | ✅ | ✅ |
|
||||
| **Memory updates** | ✅ | ✅ |
|
||||
| **Multi-language SDKs** | Python, JavaScript | Python, JavaScript |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Search-time ranking (v3-only)" icon="sparkles">
|
||||
<Accordion title="Advanced Capabilities" icon="sparkles">
|
||||
| Feature | Platform | Open Source |
|
||||
|---------|----------|-------------|
|
||||
| **Graph Memory** | Native, always-on graph over extracted entities; connections feed directly into the ranking `score` ([details](/platform/features/graph-memory)) | Removed. OSS previously connected external graph stores (Neo4j, Memgraph, Kuzu, Apache AGE); that integration was dropped when the v3 pipeline landed. OSS still extracts entities and uses them to boost ranking, but there is no queryable graph and no `relations` field |
|
||||
| **Memory Decay** | Opt-in per project; reinforces recently-used memories and gently dampens stale ones at search time ([details](/platform/features/memory-decay)) | Not supported. Passing `decay` raises `"The decay parameter is not supported by the OSS Memory SDK."` |
|
||||
| **Temporal Reasoning** | Boosts memories whose event dates match the time expressed in a query (`timestamp` / `reference_date`) ([details](/platform/features/temporal-reasoning)) | Not supported. Both parameters raise a "not supported by the OSS Memory SDK" error |
|
||||
| **Dream (background consolidation)** | Continuously synthesizes patterns, supersedes outdated facts, and merges duplicates per user ([details](/platform/features/dream)) | Not available |
|
||||
| **Multimodal support** | ✅ | ✅ |
|
||||
| **Custom categories** | ✅ | Limited |
|
||||
| **Advanced retrieval** | ✅ | ✅ |
|
||||
| **Temporal reasoning** | ✅ (v3) | ❌ |
|
||||
| **Memory decay** | ✅ (v3) | ❌ |
|
||||
| **Graph memory** | ✅ Built-in | ✅ External graph store |
|
||||
| **Memory filters v2** | ✅ | ⚠️ (via metadata) |
|
||||
| **Webhooks** | ✅ | ❌ |
|
||||
| **Memory export** | ✅ | ❌ |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Configuration & data operations" icon="sliders">
|
||||
<Accordion title="Infrastructure & Scaling" icon="server">
|
||||
| Feature | Platform | Open Source |
|
||||
|---------|----------|-------------|
|
||||
| **Custom categories** | Set per project or per `add` call ([details](/platform/features/custom-categories)) | Not supported. `Memory.add()` has no `custom_categories` parameter, and OSS project updates are rejected outright |
|
||||
| **Webhooks** | Project-scoped HTTP callbacks on memory and ingest events ([details](/platform/features/webhooks)) | Not available |
|
||||
| **Memory Export** | Schema-driven structured export jobs over filtered memories ([details](/platform/features/memory-export)) | Not available |
|
||||
| **Batch operations** | `batch_update` and `batch_delete` apply up to 1000 memories per call | Not available. Loop over the single-memory `update`/`delete` calls |
|
||||
| **Feedback** | `feedback(memory_id, ...)` records `POSITIVE`, `NEGATIVE`, or `VERY_NEGATIVE` signals against a retrieved memory ([details](/platform/features/feedback-mechanism)) | Not available |
|
||||
| **Summaries** | `get_summary(filters)` returns a generated summary over the matching memories | Not available |
|
||||
| **Filterable fields** | Top-level filter keys come from a fixed allowlist: `user_id`, `agent_id`, `app_id`, `run_id`, `created_at`, `updated_at`, `timestamp`, `expiration_date`, `categories`, `metadata`, `keywords`, `memory_ids`, plus the `AND`/`OR`/`NOT` operators and a few endpoint-specific extras. Any other key is rejected with a `400` ([details](/platform/features/v2-memory-filters)) | Any metadata key is filterable directly, with no allowlist |
|
||||
| **Comparison operators** | Depends on the field: `metadata` accepts `eq`, `ne`, `contains`; `categories` accepts `contains`, `in`; the date fields accept the range operators | The filter layer accepts the full set on any key: `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin`, `contains`, `icontains`. What actually runs depends on the vector store you configured, so confirm operator coverage for yours ([details](/open-source/features/metadata-filtering)) |
|
||||
| **Hosting** | Managed by Mem0 | Self-hosted |
|
||||
| **Auto-scaling** | ✅ | Manual |
|
||||
| **High availability** | ✅ Built-in | DIY setup |
|
||||
| **Vector DB choice** | Managed | 20+ stores: Qdrant, Pinecone, Chroma, Weaviate, Milvus, pgvector |
|
||||
| **LLM choice** | Managed (optimized) | 15+ providers: OpenAI, Anthropic, Gemini, Groq, Ollama, Together |
|
||||
| **Data residency** | US (expandable) | Your choice |
|
||||
</Accordion>
|
||||
|
||||
<Accordion title="Support" icon="life-ring">
|
||||
| Channel | Platform | Open Source |
|
||||
|---------|----------|-------------|
|
||||
| **Community & maintainers** | Discord, GitHub Discussions, direct calls with the founders | Same: Discord, GitHub Discussions, direct calls with the founders |
|
||||
<Accordion title="Pricing & Cost" icon="dollar-sign">
|
||||
| Aspect | Platform | Open Source |
|
||||
|--------|----------|-------------|
|
||||
| **License** | Usage-based pricing | Apache 2.0 (free) |
|
||||
| **Infrastructure costs** | Included in pricing | You pay for VectorDB + LLM + hosting |
|
||||
| **Support** | Included | Community + GitHub |
|
||||
| **Best for** | Fast iteration, production apps | Cost-sensitive, custom requirements |
|
||||
</Accordion>
|
||||
|
||||
Support channels are currently the same for both. If you need something contractual (a support SLA, for example), ask before assuming it exists: it is not documented as a Platform benefit today.
|
||||
<Accordion title="Development & Integration" icon="code">
|
||||
| Feature | Platform | Open Source |
|
||||
|---------|----------|-------------|
|
||||
| **REST API** | ✅ | ✅ (self-hosted server) |
|
||||
| **Python SDK** | ✅ | ✅ |
|
||||
| **JavaScript SDK** | ✅ | ✅ |
|
||||
| **Framework integrations** | LangChain, CrewAI, LlamaIndex, and 20+ more | Same |
|
||||
| **Dashboard** | ✅ Web-based | ❌ |
|
||||
| **Analytics** | ✅ Built-in | DIY |
|
||||
</Accordion>
|
||||
</AccordionGroup>
|
||||
|
||||
User Profiles are not listed above. The feature is still being finalized internally, so this page does not present it as an available Platform benefit.
|
||||
|
||||
---
|
||||
|
||||
## Decision Guide
|
||||
|
||||
**Choose Platform if you want:**
|
||||
- Zero infrastructure: no vector store, LLM, or embedder to provision or tune.
|
||||
- The v3-only ranking features: Graph Memory, Memory Decay, Temporal Reasoning, and Dream.
|
||||
- App-level and org/project-level scoping, plus webhooks, memory export, and custom categories.
|
||||
- Fast time to market: get your AI app with memory live in hours, not weeks.
|
||||
- Production-ready hosting: auto-scaling, high availability, and managed infrastructure.
|
||||
- Built-in analytics: track memory usage, query patterns, and user engagement through the dashboard.
|
||||
- Advanced features: webhooks, memory export, custom categories, and priority support.
|
||||
|
||||
**Choose Open Source if you need:**
|
||||
- Full data control: host everything on your own infrastructure.
|
||||
- Custom configuration: your own vector DB, LLM provider, and embedder ([25 vector stores](/components/vectordbs/overview), [18 LLM providers](/components/llms/overview), [11 embedders](/components/embedders/overview) at the time of writing).
|
||||
- Extensibility: modify the codebase, add custom providers, and contribute back.
|
||||
- Cost optimization: local LLMs (Ollama), self-hosted vector DBs, no usage-based billing.
|
||||
- Full data control: host everything on your infrastructure with complete data residency.
|
||||
- Custom configuration: choose your own vector DB, LLM provider, embedder, and deployment strategy.
|
||||
- Extensibility: modify the codebase, add custom features, and contribute back to the community.
|
||||
- Cost optimization: use local LLMs (Ollama), self-hosted vector DBs, and optimize for your use case.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -20,6 +20,8 @@ class BaseEmbedderConfig(ABC):
|
||||
ollama_base_url: Optional[str] = None,
|
||||
# Openai specific
|
||||
openai_base_url: Optional[str] = None,
|
||||
# Together specific
|
||||
together_base_url: Optional[str] = None,
|
||||
# Huggingface specific
|
||||
model_kwargs: Optional[dict] = None,
|
||||
huggingface_base_url: Optional[str] = None,
|
||||
@@ -58,6 +60,8 @@ class BaseEmbedderConfig(ABC):
|
||||
:type huggingface_base_url: Optional[str], optional
|
||||
:param openai_base_url: Openai base URL to be use, defaults to "https://api.openai.com/v1"
|
||||
:type openai_base_url: Optional[str], optional
|
||||
:param together_base_url: Together base URL to be use, defaults to None
|
||||
:type together_base_url: Optional[str], optional
|
||||
:param azure_kwargs: key-value arguments for the AzureOpenAI embedding model, defaults a dict inside init
|
||||
:type azure_kwargs: Optional[Dict[str, Any]], defaults a dict inside init
|
||||
:param http_client_proxies: The proxy server settings used to create self.http_client, defaults to None
|
||||
@@ -77,6 +81,7 @@ class BaseEmbedderConfig(ABC):
|
||||
self.model = model
|
||||
self.api_key = api_key
|
||||
self.openai_base_url = openai_base_url
|
||||
self.together_base_url = together_base_url
|
||||
self.embedding_dims = embedding_dims
|
||||
|
||||
# AzureOpenAI specific
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
from typing import Optional
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
|
||||
|
||||
class TogetherConfig(BaseLlmConfig):
|
||||
"""
|
||||
Configuration class for Together-specific parameters.
|
||||
Inherits from BaseLlmConfig and adds Together-specific settings.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
# Base parameters
|
||||
model: Optional[str] = None,
|
||||
temperature: float = 0.1,
|
||||
api_key: Optional[str] = None,
|
||||
max_tokens: int = 2000,
|
||||
top_p: float = 0.1,
|
||||
top_k: int = 1,
|
||||
enable_vision: bool = False,
|
||||
vision_details: Optional[str] = "auto",
|
||||
http_client_proxies: Optional[dict] = None,
|
||||
# Together-specific parameters
|
||||
together_base_url: Optional[str] = None,
|
||||
):
|
||||
"""
|
||||
Initialize Together configuration.
|
||||
|
||||
Args:
|
||||
model: Together model to use, defaults to None
|
||||
temperature: Controls randomness, defaults to 0.1
|
||||
api_key: Together API key, defaults to None
|
||||
max_tokens: Maximum tokens to generate, defaults to 2000
|
||||
top_p: Nucleus sampling parameter, defaults to 0.1
|
||||
top_k: Top-k sampling parameter, defaults to 1
|
||||
enable_vision: Enable vision capabilities, defaults to False
|
||||
vision_details: Vision detail level, defaults to "auto"
|
||||
http_client_proxies: HTTP client proxy settings, defaults to None
|
||||
together_base_url: Together API base URL, defaults to None
|
||||
"""
|
||||
# Initialize base parameters
|
||||
super().__init__(
|
||||
model=model,
|
||||
temperature=temperature,
|
||||
api_key=api_key,
|
||||
max_tokens=max_tokens,
|
||||
top_p=top_p,
|
||||
top_k=top_k,
|
||||
enable_vision=enable_vision,
|
||||
vision_details=vision_details,
|
||||
http_client_proxies=http_client_proxies,
|
||||
)
|
||||
|
||||
# Together-specific parameters
|
||||
self.together_base_url = together_base_url
|
||||
@@ -13,8 +13,9 @@ class TogetherEmbedding(EmbeddingBase):
|
||||
|
||||
self.config.model = self.config.model or "intfloat/multilingual-e5-large-instruct"
|
||||
api_key = self.config.api_key or os.getenv("TOGETHER_API_KEY")
|
||||
base_url = self.config.together_base_url or os.getenv("TOGETHER_API_BASE") or "https://api.together.ai/v1"
|
||||
self.config.embedding_dims = self.config.embedding_dims or 1024
|
||||
self.client = Together(api_key=api_key)
|
||||
self.client = Together(api_key=api_key, base_url=base_url)
|
||||
|
||||
def embed(self, text, memory_action: Optional[Literal["add", "search", "update"]] = None):
|
||||
"""
|
||||
|
||||
+24
-3
@@ -1,6 +1,6 @@
|
||||
import json
|
||||
import os
|
||||
from typing import Dict, List, Optional
|
||||
from typing import Dict, List, Optional, Union
|
||||
|
||||
try:
|
||||
from together import Together
|
||||
@@ -8,19 +8,40 @@ except ImportError:
|
||||
raise ImportError("The 'together' library is required. Please install it using 'pip install together'.")
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
from mem0.configs.llms.together import TogetherConfig
|
||||
from mem0.llms.base import LLMBase
|
||||
from mem0.memory.utils import extract_json
|
||||
|
||||
|
||||
class TogetherLLM(LLMBase):
|
||||
def __init__(self, config: Optional[BaseLlmConfig] = None):
|
||||
def __init__(self, config: Optional[Union[BaseLlmConfig, TogetherConfig, Dict]] = None):
|
||||
# Convert to TogetherConfig if needed
|
||||
if config is None:
|
||||
config = TogetherConfig()
|
||||
elif isinstance(config, dict):
|
||||
config = TogetherConfig(**config)
|
||||
elif isinstance(config, BaseLlmConfig) and not isinstance(config, TogetherConfig):
|
||||
# Convert BaseLlmConfig to TogetherConfig
|
||||
config = TogetherConfig(
|
||||
model=config.model,
|
||||
temperature=config.temperature,
|
||||
api_key=config.api_key,
|
||||
max_tokens=config.max_tokens,
|
||||
top_p=config.top_p,
|
||||
top_k=config.top_k,
|
||||
enable_vision=config.enable_vision,
|
||||
vision_details=config.vision_details,
|
||||
http_client_proxies=config.http_client_proxies,
|
||||
)
|
||||
|
||||
super().__init__(config)
|
||||
|
||||
if not self.config.model:
|
||||
self.config.model = "MiniMaxAI/MiniMax-M3"
|
||||
|
||||
api_key = self.config.api_key or os.getenv("TOGETHER_API_KEY")
|
||||
self.client = Together(api_key=api_key)
|
||||
base_url = self.config.together_base_url or os.getenv("TOGETHER_API_BASE") or "https://api.together.ai/v1"
|
||||
self.client = Together(api_key=api_key, base_url=base_url)
|
||||
|
||||
def _parse_response(self, response, tools):
|
||||
"""
|
||||
|
||||
@@ -13,6 +13,7 @@ from mem0.configs.llms.lmstudio import LMStudioConfig
|
||||
from mem0.configs.llms.minimax import MinimaxConfig
|
||||
from mem0.configs.llms.ollama import OllamaConfig
|
||||
from mem0.configs.llms.openai import OpenAIConfig
|
||||
from mem0.configs.llms.together import TogetherConfig
|
||||
from mem0.configs.llms.vllm import VllmConfig
|
||||
from mem0.configs.llms.xai import XAIConfig
|
||||
from mem0.configs.rerankers.base import BaseRerankerConfig
|
||||
@@ -43,7 +44,7 @@ class LlmFactory:
|
||||
"ollama": ("mem0.llms.ollama.OllamaLLM", OllamaConfig),
|
||||
"openai": ("mem0.llms.openai.OpenAILLM", OpenAIConfig),
|
||||
"groq": ("mem0.llms.groq.GroqLLM", BaseLlmConfig),
|
||||
"together": ("mem0.llms.together.TogetherLLM", BaseLlmConfig),
|
||||
"together": ("mem0.llms.together.TogetherLLM", TogetherConfig),
|
||||
"aws_bedrock": ("mem0.llms.aws_bedrock.AWSBedrockLLM", AWSBedrockConfig),
|
||||
"litellm": ("mem0.llms.litellm.LiteLLM", BaseLlmConfig),
|
||||
"azure_openai": ("mem0.llms.azure_openai.AzureOpenAILLM", AzureOpenAIConfig),
|
||||
|
||||
@@ -85,3 +85,29 @@ def test_explicit_config_overrides_defaults(mock_together_client):
|
||||
mock_together_client.embeddings.create.return_value = Mock(data=[Mock(embedding=[0.0] * 768)])
|
||||
embedder.embed("hello")
|
||||
mock_together_client.embeddings.create.assert_called_once_with(model="BAAI/bge-base-en-v1.5", input="hello")
|
||||
|
||||
|
||||
def test_together_embedding_base_url(monkeypatch):
|
||||
# case1: default config uses Together's official base url
|
||||
monkeypatch.delenv("TOGETHER_API_BASE", raising=False)
|
||||
config = BaseEmbedderConfig(model=DEFAULT_MODEL, embedding_dims=DEFAULT_EMBEDDING_DIMS, api_key="api_key")
|
||||
embedder = TogetherEmbedding(config)
|
||||
assert str(embedder.client.base_url) == "https://api.together.ai/v1/"
|
||||
|
||||
# case2: with env variable TOGETHER_API_BASE
|
||||
provider_base_url = "https://api.provider.com/v1/"
|
||||
monkeypatch.setenv("TOGETHER_API_BASE", provider_base_url)
|
||||
config = BaseEmbedderConfig(model=DEFAULT_MODEL, embedding_dims=DEFAULT_EMBEDDING_DIMS, api_key="api_key")
|
||||
embedder = TogetherEmbedding(config)
|
||||
assert str(embedder.client.base_url) == provider_base_url
|
||||
|
||||
# case3: with config.together_base_url (explicit config beats env var)
|
||||
config_base_url = "https://api.config.com/v1/"
|
||||
config = BaseEmbedderConfig(
|
||||
model=DEFAULT_MODEL,
|
||||
embedding_dims=DEFAULT_EMBEDDING_DIMS,
|
||||
api_key="api_key",
|
||||
together_base_url=config_base_url,
|
||||
)
|
||||
embedder = TogetherEmbedding(config)
|
||||
assert str(embedder.client.base_url) == config_base_url
|
||||
|
||||
@@ -3,6 +3,7 @@ from unittest.mock import Mock, patch
|
||||
import pytest
|
||||
|
||||
from mem0.configs.llms.base import BaseLlmConfig
|
||||
from mem0.configs.llms.together import TogetherConfig
|
||||
from mem0.llms.together import TogetherLLM
|
||||
|
||||
|
||||
@@ -14,6 +15,38 @@ def mock_together_client():
|
||||
yield mock_client
|
||||
|
||||
|
||||
def test_together_llm_base_url(monkeypatch):
|
||||
# case1: default config uses Together's official base url
|
||||
monkeypatch.delenv("TOGETHER_API_BASE", raising=False)
|
||||
config = BaseLlmConfig(
|
||||
model="mistralai/Mixtral-8x7B-Instruct-v0.1", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
)
|
||||
llm = TogetherLLM(config)
|
||||
assert str(llm.client.base_url) == "https://api.together.ai/v1/"
|
||||
|
||||
# case2: with env variable TOGETHER_API_BASE
|
||||
provider_base_url = "https://api.provider.com/v1/"
|
||||
monkeypatch.setenv("TOGETHER_API_BASE", provider_base_url)
|
||||
config = TogetherConfig(
|
||||
model="mistralai/Mixtral-8x7B-Instruct-v0.1", temperature=0.7, max_tokens=100, top_p=1.0, api_key="api_key"
|
||||
)
|
||||
llm = TogetherLLM(config)
|
||||
assert str(llm.client.base_url) == provider_base_url
|
||||
|
||||
# case3: with config.together_base_url (explicit config beats env var)
|
||||
config_base_url = "https://api.config.com/v1/"
|
||||
config = TogetherConfig(
|
||||
model="mistralai/Mixtral-8x7B-Instruct-v0.1",
|
||||
temperature=0.7,
|
||||
max_tokens=100,
|
||||
top_p=1.0,
|
||||
api_key="api_key",
|
||||
together_base_url=config_base_url,
|
||||
)
|
||||
llm = TogetherLLM(config)
|
||||
assert str(llm.client.base_url) == config_base_url
|
||||
|
||||
|
||||
def test_generate_response_without_tools(mock_together_client):
|
||||
config = BaseLlmConfig(model="mistralai/Mixtral-8x7B-Instruct-v0.1", temperature=0.7, max_tokens=100, top_p=1.0)
|
||||
llm = TogetherLLM(config)
|
||||
|
||||
Reference in New Issue
Block a user