Compare commits

...

118 Commits

Author SHA1 Message Date
Dev Khant 5327d6e50d version bump -> 0.1.89 (#2533) 2025-04-11 13:40:47 +05:30
Dev Khant 15a3e20371 Store user_id in vectordb (#2466) 2025-04-11 13:37:34 +05:30
Dev Khant 19d7beef43 Add support for Langchain VectorStores (#2518) 2025-04-11 13:37:18 +05:30
Vir Kothari 8b789adb15 Add YT assistant chrome extension (#2485) 2025-04-10 22:14:57 +05:30
Antaripa Saha fd065fe9cc Personal Study Buddy (#2531) 2025-04-10 08:12:39 -07:00
Antaripa Saha b5127f7c62 personal assistant (#2530) 2025-04-10 20:24:18 +05:30
Dev-Khant 37d9fed690 doc: update agno 2025-04-10 15:49:36 +05:30
Dev Khant 31861e9acb Doc: Add agno example (#2529) 2025-04-10 15:46:46 +05:30
Dev Khant 07462adc9a Formatting (#2526) 2025-04-10 11:42:25 +05:30
Dev Khant 616313b8b5 Add async support (#2492)
Co-authored-by: Deshraj Yadav <deshrajdry@gmail.com>
2025-04-10 11:16:44 +05:30
Dev Khant 44f2490667 Doc: modify 2 examples to show OpenAIResponses API (#2525) 2025-04-10 10:24:10 +05:30
Dev Khant 3cc794fb98 version bump -> 0.1.88 (#2524) 2025-04-10 01:02:05 +05:30
Dev Khant ff6b251c66 Handle HF logging (#2523) 2025-04-10 01:01:00 +05:30
Sergio Toro 55df395fd6 fix: extract entities tool_calls some times is an array (#2481) 2025-04-10 00:03:52 +05:30
Dev Khant 244e60cea6 update python changelog (#2522) 2025-04-09 23:38:10 +05:30
Dev Khant b480c71f0f version bump -> 0.1.87 (#2521) 2025-04-09 23:34:15 +05:30
Saket Aryan 309c8c18a6 Add user_id in TS OSS SDK (#2514) 2025-04-09 10:24:56 -07:00
Dev Khant f4d8647264 Doc: update memory export (#2519) 2025-04-09 17:34:16 +05:30
Dev Khant f95c4cbbe5 Update MAKEFILE (#2517) 2025-04-09 12:04:39 +05:30
Dev Khant 00c7cc432c Remove redundant lines (#2516) 2025-04-09 11:02:37 +05:30
ytkimirti 91abc03880 Add Upstash Vector support (#2493) 2025-04-09 10:06:07 +05:30
Saket Aryan 9100e95175 Fix Batch API docs (#2512) 2025-04-07 23:54:16 +05:30
Dev Khant cdb8dcdb9e Add embeding_dims param to FAISS (#2513) 2025-04-07 23:29:55 +05:30
Dev-Khant 2a79add7a5 hotfix: _create_procedural_memory 2025-04-07 16:07:26 +05:30
Dev Khant 9dfa9b4412 Add langchain embedding, update langchain LLM and version bump -> 0.1.84 (#2510) 2025-04-07 15:27:26 +05:30
Dev Khant 5509066925 Doc: changelog update (#2509) 2025-04-07 11:51:52 +05:30
Dev Khant 3712522b14 Fix langchain llm and update changelog (#2508) 2025-04-07 11:49:39 +05:30
Dev Khant 93f34e4116 Formatting and version bump -> 0.1.82 (#2507) 2025-04-07 11:31:16 +05:30
Dev Khant 39e5cbfacc Support for langchain LLMs (#2506) 2025-04-07 11:28:30 +05:30
Dev Khant d30c78c5eb Doc: update output_format (#2498) 2025-04-03 10:46:06 +05:30
Dev Khant 039756abbe Doc: pipecat integration (#2494) 2025-04-02 18:44:04 +05:30
Mrinank Bhowmick cb38c2dae7 Feature/google as new llm and embedder in mem0-ts (#2468)
Co-authored-by: Saket Aryan <94069182+whysosaket@users.noreply.github.com>
2025-04-02 15:56:18 +05:30
Pranav Puranik 4dc9f6fad6 adding lmstudio and together in docs (#2489) 2025-04-02 11:21:27 +05:30
Anusha Yella 1b1f02eb57 fix/failing-unit-tests (#2486) 2025-04-02 10:36:02 +05:30
Dev Khant 1db1105cad Set output_format='v1.1' and update docs (#2480) 2025-04-02 10:35:29 +05:30
Saket Aryan 91a28c7f04 Docs: Flowise Integration Documentation for Mem0 Memory Setup (#2482) 2025-04-01 10:16:53 -07:00
Dev Khant a78e1894b1 Doc: Add llms.txt (#2484) 2025-04-01 22:06:20 +05:30
Sergio Toro 83338295d8 feat: add development docker compose (#2411) 2025-04-01 16:19:30 +05:30
Dev Khant aff70807c6 update faqs (#2477) 2025-04-01 00:40:50 +05:30
Dev Khant 648c86b53d doc: fix lmstudio link (#2476) 2025-04-01 00:28:02 +05:30
Dev Khant de0b2de9c2 doc: fix links (#2475) 2025-03-31 22:20:55 +05:30
Saket Aryan e3f460fba4 Added Mastra Example (#2473) 2025-03-30 11:56:00 -07:00
Saket Aryan fe7b336922 Update Demo Mem0AI (#2471) 2025-03-30 12:49:54 +05:30
Saket Aryan 1033ab227c Introduce Ping in Mem0 Client (#2472) 2025-03-30 12:49:36 +05:30
Saket Aryan 5ed15c3bcd AI SDK Updates (#2470) 2025-03-30 11:10:30 +05:30
Deshraj Yadav c1f5a655ba Minor fixes in procedural memory (#2469) 2025-03-29 17:20:58 -07:00
Deshraj Yadav 72bb631bb5 Add support for procedural memory (#2460) 2025-03-29 15:58:12 -07:00
Dev Khant 2bf9286071 update for faiss doc (#2464) 2025-03-29 13:51:01 +05:30
Dev Khant 884b597312 bump version -> 0.1.79 (#2463) 2025-03-29 13:46:00 +05:30
Dev Khant f1471bcc55 update changelog (#2462) 2025-03-29 13:39:11 +05:30
Dev Khant 9ae23f9c88 Add Faiss Support (#2461) 2025-03-29 13:35:36 +05:30
Dev Khant cbecbb7b64 doc: update email example (#2459) 2025-03-29 00:11:02 +05:30
Dev Khant f8ad0c2b2c Doc: Add example for email processing (#2458) 2025-03-29 00:09:22 +05:30
Dev Khant d0da9a1ae0 Doc: Add changelog (#2455) 2025-03-28 12:18:17 +05:30
Saket Aryan bc4ab3db77 Add Infer Property (#2452) 2025-03-27 21:18:42 +05:30
Dev Khant 0eb53b9f27 doc: update API reference for expiration_date (#2450) 2025-03-27 12:24:26 +05:30
Prateek Chhikara 3cef3ed95e Added Evaluation folder (#2448) 2025-03-26 12:37:54 -07:00
Dev Khant 45e5f2af93 Doc: Update API reference section and Add elevenlabs example (#2447) 2025-03-27 00:13:09 +05:30
Prateek Chhikara 32ba13b3ea Updated multimodal docs (#2446) 2025-03-26 09:56:16 -07:00
Parshva Daftari 69a91d5cbb Mem0 livekit example (#2442) 2025-03-26 16:06:23 +05:30
Dev Khant 2004427acd tools fix and formatting (#2441) 2025-03-26 11:25:03 +05:30
Saket Aryan 2517ccd489 fix(deployments): Add package.json file to fix deployment errors (#2440) 2025-03-26 10:31:09 +05:30
Saket Aryan 9d0300f774 Update Vercel AI SDK to support tools call (#2383) 2025-03-26 10:30:44 +05:30
Saket Aryan 366d263e0b docs(supabase-ts): Update Docs for Supabase TS (#2439) 2025-03-26 10:11:01 +05:30
Pranav Puranik 4321d24284 Open AI env var fix (#2384) 2025-03-26 08:43:33 +05:30
Dev Khant 9cb2a13f3b fix for Azure AI and version bump -> 0.1.76 (#2438) 2025-03-25 18:10:36 +05:30
Dev Khant 5ec7889d9a embedchain version bump -> 0.1.128 (#2437) 2025-03-25 13:18:34 +05:30
Dev Khant b54845bcc9 Add feeback method to client and doc changes (#2435) 2025-03-25 11:39:19 +05:30
Saket Aryan 1ae2747ff8 Add Supabase History DB to run Mem0 OSS on Serverless (#2429) 2025-03-24 16:14:29 -07:00
Parshva Daftari 953a5a4a2d Azure openai fixes (#2428) 2025-03-25 00:34:21 +05:30
Saket Aryan 2b49c9eedd Supabase Vector Store (#2427) 2025-03-25 00:15:50 +05:30
Anusha Yella 9db5f62262 fix-azure-ai-search-test-cases (#2422) 2025-03-24 15:20:02 +05:30
Dev Khant a1bd4285db version bump -> 0.1.75 (#2426) 2025-03-24 15:17:00 +05:30
Dev Khant e77a10a8da Add LM Studio support (#2425) 2025-03-24 13:32:26 +05:30
Gaurav Agerwala e4307ae420 Fix: Export ollama (#2421)
Co-authored-by: Gaurav Agerwala <ice@Gauravs-MacBook-Pro.local>
2025-03-23 02:06:23 +05:30
Saket Aryan 7c89d00079 Adds Langchain Community Package (#2417) 2025-03-22 10:44:40 +05:30
Dev Khant 563eaae5ee Openai Agents SDK voice demo (#2416) 2025-03-22 01:09:37 +05:30
Dev Khant 6733f78f81 Doc: Support for expiration date in ADD (#2419) 2025-03-21 23:38:25 +05:30
Saket Aryan c11637bd2f Update Node SDK Docs for Update Method (#2418) 2025-03-21 21:23:57 +05:30
Dev-Khant ff30cb8ddd version bump -> 0.1.74 2025-03-21 13:06:40 +05:30
Parshva Daftari 2e853c3d22 Updated VDB Docs (#2409) 2025-03-20 23:47:57 +05:30
Dev Khant 3cc7013fde fix pinecone (#2414) 2025-03-20 23:47:09 +05:30
Dev Khant 8e6a08aa83 Support for hybrid search in Azure AI vector store (#2408)
Co-authored-by: Deshraj Yadav <deshrajdry@gmail.com>
2025-03-20 22:57:00 +05:30
Wonbin Kim 8b9a8e5825 URGENT Hotfix - update default Elasticsearch search query (#2413) 2025-03-20 20:50:18 +05:30
Dev Khant afc630272d bump version -> 0.1.73 (#2412) 2025-03-20 19:30:29 +05:30
Parshva Daftari e33008e3a4 Add: Pinecone integration (#2395) 2025-03-20 12:57:32 +05:30
Mauricio A 7b516328a8 Feature/fix opensearch vector mapping (#2399) 2025-03-20 09:37:57 +05:30
Dev Khant 6d5889d98f version bump -> 0.1.72 (#2405) 2025-03-20 00:10:27 +05:30
Parshva Daftari ee66e0c954 Reverting the tools commit (#2404) 2025-03-20 00:09:00 +05:30
Prateek Chhikara 1aed611539 Added graph memory (#2403) 2025-03-19 09:51:15 -07:00
Saket Aryan 6c2b131d6e Added Feedback in SDK (#2393) 2025-03-19 09:11:45 -07:00
Gaurav Agerwala 2ffe9922f3 Added support for Ollama in TS SDK (#2345)
Co-authored-by: Dev Khant <devkhant24@gmail.com>
2025-03-19 21:38:19 +05:30
Dev Khant 540ada489b version bump -> 0.1.71 (#2402) 2025-03-19 21:36:06 +05:30
Dev Khant 65cffa0369 Fix: made tools support for graph (#2400) 2025-03-19 21:29:36 +05:30
Dev Khant 9f937943ba Doc: update oss quickstart page (#2401) 2025-03-19 17:27:09 +05:30
Dev-Khant 51a68bf7c5 Doc: update azure ai vector store 2025-03-18 14:32:12 +05:30
Dev-Khant 92541d8955 Doc: azure ai vector search 2025-03-18 14:17:56 +05:30
Dev Khant 0e0be18ecc Fix azure ai vector store (#2396) 2025-03-18 14:13:19 +05:30
Wonbin Kim 66d3f9b93c Support Custom Prompt for Memory Action Decision (#2371) 2025-03-18 10:43:01 +05:30
Wonbin Kim b8f40f728f Support Custom Search Query for Elasticsearch (#2372) 2025-03-18 10:34:34 +05:30
Prateek Chhikara 00a2ea9ff0 Added export instructions to docs (#2394) 2025-03-17 17:41:56 -07:00
Prateek Chhikara 9545836469 Added docs for add-v2 (#2381) 2025-03-17 15:39:17 -07:00
Saket Aryan 3acd9e20da Fix Redis Search (#2392) 2025-03-17 15:30:40 -07:00
Dev Khant d48ecd52ef update poetry lock file (#2391) 2025-03-18 01:11:05 +05:30
Saket Aryan 2fbea7705b Add Intercom to Docs (#2390) 2025-03-17 12:37:56 -07:00
Dev Khant d7a26bd0c3 Add infer param and version bump (#2389)
Co-authored-by: Deshraj Yadav <deshrajdry@gmail.com>
2025-03-18 01:04:58 +05:30
Farzad Sunavala e25dc4b504 bugfix: update Azure AI Search Config (#2380) 2025-03-17 22:19:46 +05:30
Parshva Daftari dab3349990 Neo4j embeddings error (#2377) 2025-03-17 21:57:23 +05:30
Saket Aryan 6db87e8d07 Make DEMO UI Responsive (#2382) 2025-03-14 20:00:28 -07:00
Saket Aryan faf811ee2d Added Custom Categories in Mem0-TS (#2370) 2025-03-14 22:07:46 +05:30
Anusha Yella ee80a43810 Remove tools from LLMs (#2363) 2025-03-14 17:42:48 +05:30
Dev Khant 4be426f762 version bump -> 0.1.68 (#2369) 2025-03-12 21:22:49 +05:30
Farzad Sunavala ba9c61938b feat: enhance Azure AI Search Integration with Binary Quantization, Pre/Post Filter Options, and user agent header (#2354) 2025-03-12 21:20:25 +05:30
Parshva Daftari 65f826e064 Fix langchain neo4j deprecation warning (#2350) 2025-03-12 15:30:45 +05:30
Saket Aryan b43363cdf3 OpenAI Inbuilt Tools (#2362) 2025-03-11 15:33:49 -07:00
Prateek Chhikara 89e786a88e Added agentic tool in docs (#2361) 2025-03-11 13:36:20 -07:00
Saket Aryan 2d5062bd40 Updated Demo (#2360) 2025-03-12 01:49:08 +05:30
Parshva Daftari b89628322d WeaviateDB Integration (#2339) 2025-03-11 00:12:17 +05:30
250 changed files with 34297 additions and 3959 deletions
+3 -2
View File
@@ -12,8 +12,9 @@ install:
install_all:
poetry install
poetry run pip install groq together boto3 litellm ollama chromadb sentence_transformers vertexai \
google-generativeai elasticsearch opensearch-py vecs
poetry run pip install groq together boto3 litellm ollama chromadb weaviate weaviate-client sentence_transformers vertexai \
google-generativeai elasticsearch opensearch-py vecs pinecone pinecone-text faiss-cpu langchain-community \
upstash-vector azure-search-documents
# Format code with ruff
format:
+4
View File
@@ -0,0 +1,4 @@
---
title: 'Feedback'
openapi: post /v1/feedback/
---
@@ -1,6 +1,6 @@
---
title: 'Get Memory Export'
openapi: get /v1/exports/
openapi: post /v1/exports/get
---
Retrieve the latest structured memory export after submitting an export job. You can filter the export by `user_id`, `run_id`, `session_id`, or `app_id` to get the most recent export matching your filters.
+175
View File
@@ -0,0 +1,175 @@
---
title: "Product Updates"
mode: "wide"
---
<Tabs>
<Tab title="Python">
<Update label="2025-04-09" description="v0.1.87">
**New Features:**
- **Upstash Vector:** Added support for Upstash Vector store
**Improvements:**
- **Code Quality:** Removed redundant code lines
- **Build:** Updated MAKEFILE
- **Documentation:** Updated memory export documentation
</Update>
<Update label="2025-04-07" description="v0.1.86">
**Improvements:**
- **FAISS:** Added embedding_dims parameter to FAISS vector store
</Update>
<Update label="2025-04-07" description="v0.1.84">
**New Features:**
- **Langchain Embedder:** Added Langchain embedder integration
**Improvements:**
- **Langchain LLM:** Updated Langchain LLM integration to directly pass the Langchain object LLM
</Update>
<Update label="2025-04-07" description="v0.1.83">
**Bug Fixes:**
- **Langchain LLM:** Fixed issues with Langchain LLM integration
</Update>
<Update label="2025-04-07" description="v0.1.82">
**New Features:**
- **LLM Integrations:** Added support for Langchain LLMs, Google as new LLM and embedder
- **Development:** Added development docker compose
**Improvements:**
- **Output Format:** Set output_format='v1.1' and updated documentation
**Documentation:**
- **Integrations:** Added LMStudio and Together.ai documentation
- **API Reference:** Updated output_format documentation
- **Integrations:** Added PipeCat integration documentation
- **Integrations:** Added Flowise integration documentation for Mem0 memory setup
**Bug Fixes:**
- **Tests:** Fixed failing unit tests
</Update>
<Update label="2025-04-02" description="v0.1.79">
**New Features:**
- **FAISS Support:** Added FAISS vector store support
</Update>
<Update label="2025-04-02" description="v0.1.78">
**New Features:**
- **Livekit Integration:** Added Mem0 livekit example
- **Evaluation:** Added evaluation framework and tools
**Documentation:**
- **Multimodal:** Updated multimodal documentation
- **Examples:** Added examples for email processing
- **API Reference:** Updated API reference section
- **Elevenlabs:** Added Elevenlabs integration example
**Bug Fixes:**
- **OpenAI Environment Variables:** Fixed issues with OpenAI environment variables
- **Deployment Errors:** Added `package.json` file to fix deployment errors
- **Tools:** Fixed tools issues and improved formatting
- **Docs:** Updated API reference section for `expiration date`
</Update>
<Update label="2025-03-26" description="v0.1.77">
**Bug Fixes:**
- **OpenAI Environment Variables:** Fixed issues with OpenAI environment variables
- **Deployment Errors:** Added `package.json` file to fix deployment errors
- **Tools:** Fixed tools issues and improved formatting
- **Docs:** Updated API reference section for `expiration date`
</Update>
<Update label="2025-03-19" description="v0.1.76">
**New Features:**
- **Supabase Vector Store:** Added support for Supabase Vector Store
- **Supabase History DB:** Added Supabase History DB to run Mem0 OSS on Serverless
- **Feedback Method:** Added feedback method to client
**Bug Fixes:**
- **Azure OpenAI:** Fixed issues with Azure OpenAI
- **Azure AI Search:** Fixed test cases for Azure AI Search
</Update>
</Tab>
<Tab title="TypeScript">
<Update label="2025-04-09" description="v2.1.15">
**Improvements:**
- **Client:** Added support for Mem0 to work with Chrome Extensions
</Update>
<Update label="2025-04-01" description="v2.1.14">
**New Features:**
- **Mastra Example:** Added Mastra example
- **Integrations:** Added Flowise integration documentation for Mem0 memory setup
**Improvements:**
- **Demo:** Updated Demo Mem0AI
- **Client:** Enhanced Ping method in Mem0 Client
- **AI SDK:** Updated AI SDK implementation
</Update>
<Update label="2025-03-29" description="v2.1.13">
**Improvements:**
- **Introuced `ping` method to check if API key is valid and populate org/project id**
</Update>
<Update label="2025-03-29" description="AI SDK v1.0.0">
**New Features:**
- **Vercel AI SDK Update:** Support threshold and rerank
**Improvements:**
- **Made add calls async to avoid blocking**
- **Bump `mem0ai` to use `2.1.12`**
</Update>
<Update label="2025-03-26" description="v2.1.12">
**New Features:**
- **Mem0 OSS:** Support infer param
**Improvements:**
- **Updated Supabase TS Docs**
- **Made package size smaller**
</Update>
<Update label="2025-03-19" description="v2.1.11">
**New Features:**
- **Supabase Vector Store Integration**
- **Feedback Method**
</Update>
</Tab>
<Tab title="Platform">
<Update label="2025-03-28" description="">
- **Updated Playground Prompt**
- **Send Email on User Addition to Org/Proj**
- **Fix Search Entity**
</Update>
<Update label="2025-03-19" description="">
- **General Stability & Performance Improvements**
</Update>
</Tab>
</Tabs>
+1
View File
@@ -84,6 +84,7 @@ Here's a comprehensive list of all parameters that can be used across different
| `memory_add_embedding_type` | The type of embedding to use for the add memory action | VertexAI |
| `memory_update_embedding_type` | The type of embedding to use for the update memory action | VertexAI |
| `memory_search_embedding_type` | The type of embedding to use for the search memory action | VertexAI |
| `lmstudio_base_url` | Base URL for LM Studio API | LM Studio |
</Tab>
<Tab title="TypeScript">
| Parameter | Description | Provider |
@@ -0,0 +1,120 @@
---
title: LangChain
---
Mem0 supports LangChain as a provider to access a wide range of embedding models. LangChain is a framework for developing applications powered by language models, making it easy to integrate various embedding providers through a consistent interface.
For a complete list of available embedding models supported by LangChain, refer to the [LangChain Text Embedding documentation](https://python.langchain.com/docs/integrations/text_embedding/).
## Usage
<CodeGroup>
```python Python
import os
from mem0 import Memory
from langchain_openai import OpenAIEmbeddings
# Set necessary environment variables for your chosen LangChain provider
os.environ["OPENAI_API_KEY"] = "your-api-key"
# Initialize a LangChain embeddings model directly
openai_embeddings = OpenAIEmbeddings(
model="text-embedding-3-small",
dimensions=1536
)
# Pass the initialized model to the config
config = {
"embedder": {
"provider": "langchain",
"config": {
"model": openai_embeddings
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
</CodeGroup>
## Supported LangChain Embedding Providers
LangChain supports a wide range of embedding providers, including:
- OpenAI (`OpenAIEmbeddings`)
- Cohere (`CohereEmbeddings`)
- Google (`VertexAIEmbeddings`)
- Hugging Face (`HuggingFaceEmbeddings`)
- Sentence Transformers (`HuggingFaceEmbeddings`)
- Azure OpenAI (`AzureOpenAIEmbeddings`)
- Ollama (`OllamaEmbeddings`)
- Together (`TogetherEmbeddings`)
- And many more
You can use any of these model instances directly in your configuration. For a complete and up-to-date list of available embedding providers, refer to the [LangChain Text Embedding documentation](https://python.langchain.com/docs/integrations/text_embedding/).
## Provider-Specific Configuration
When using LangChain as an embedder provider, you'll need to:
1. Set the appropriate environment variables for your chosen embedding provider
2. Import and initialize the specific model class you want to use
3. Pass the initialized model instance to the config
### Examples with Different Providers
#### HuggingFace Embeddings
```python
from langchain_huggingface import HuggingFaceEmbeddings
# Initialize a HuggingFace embeddings model
hf_embeddings = HuggingFaceEmbeddings(
model_name="BAAI/bge-small-en-v1.5",
encode_kwargs={"normalize_embeddings": True}
)
config = {
"embedder": {
"provider": "langchain",
"config": {
"model": hf_embeddings
}
}
}
```
#### Ollama Embeddings
```python
from langchain_ollama import OllamaEmbeddings
# Initialize an Ollama embeddings model
ollama_embeddings = OllamaEmbeddings(
model="nomic-embed-text"
)
config = {
"embedder": {
"provider": "langchain",
"config": {
"model": ollama_embeddings
}
}
}
```
<Note>
Make sure to install the necessary LangChain packages and any provider-specific dependencies.
</Note>
## Config
All available parameters for the `langchain` embedder config are present in [Master List of All Params in Config](../config).
@@ -0,0 +1,38 @@
You can use embedding models from LM Studio to run Mem0 locally.
### Usage
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your_api_key" # For LLM
config = {
"embedder": {
"provider": "lmstudio",
"config": {
"model": "nomic-embed-text-v1.5-GGUF/nomic-embed-text-v1.5.f16.gguf"
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I’m not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="john")
```
### Config
Here are the parameters available for configuring Ollama embedder:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `model` | The name of the OpenAI model to use | `nomic-embed-text-v1.5-GGUF/nomic-embed-text-v1.5.f16.gguf` |
| `embedding_dims` | Dimensions of the embedding model | `1536` |
| `lmstudio_base_url` | Base URL for LM Studio connection | `http://localhost:1234/v1` |
+2
View File
@@ -22,6 +22,8 @@ See the list of supported embedders below.
<Card title="Gemini" href="/components/embedders/models/gemini"></Card>
<Card title="Vertex AI" href="/components/embedders/models/vertexai"></Card>
<Card title="Together" href="/components/embedders/models/together"></Card>
<Card title="LM Studio" href="/components/embedders/models/lmstudio"></Card>
<Card title="Langchain" href="/components/embedders/models/langchain"></Card>
</CardGroup>
## Usage
+2 -1
View File
@@ -29,7 +29,7 @@ iconType: "solid"
Config values are applied in the following order of precedence (from highest to lowest):
1. Values explicitly set in the `config` object/dictionary
2. Environment variables (e.g., `OPENAI_API_KEY`, `OPENAI_API_BASE`)
2. Environment variables (e.g., `OPENAI_API_KEY`, `OPENAI_BASE_URL`)
3. Default values defined in the LLM implementation
This means that values specified in the `config` will override corresponding environment variables, which in turn override default values.
@@ -108,6 +108,7 @@ Here's a comprehensive list of all parameters that can be used across different
| `azure_kwargs` | Azure LLM args for initialization | AzureOpenAI |
| `deepseek_base_url` | Base URL for DeepSeek API | DeepSeek |
| `xai_base_url` | Base URL for XAI API | XAI |
| `lmstudio_base_url` | Base URL for LM Studio API | LM Studio |
</Tab>
<Tab title="TypeScript">
| Parameter | Description | Provider |
@@ -4,6 +4,9 @@ title: Azure OpenAI
To use Azure OpenAI models, you have to set the `LLM_AZURE_OPENAI_API_KEY`, `LLM_AZURE_ENDPOINT`, `LLM_AZURE_DEPLOYMENT` and `LLM_AZURE_API_VERSION` environment variables. You can obtain the Azure API key from the [Azure](https://azure.microsoft.com/).
> **Note**: The following are currently unsupported with reasoning models `Parallel tool calling`,`temperature`, `top_p`, `presence_penalty`, `frequency_penalty`, `logprobs`, `top_logprobs`, `logit_bias`, `max_tokens`
## Usage
```python
+77
View File
@@ -0,0 +1,77 @@
---
title: LangChain
---
Mem0 supports LangChain as a provider to access a wide range of LLM models. LangChain is a framework for developing applications powered by language models, making it easy to integrate various LLM providers through a consistent interface.
For a complete list of available chat models supported by LangChain, refer to the [LangChain Chat Models documentation](https://python.langchain.com/docs/integrations/chat).
## Usage
<CodeGroup>
```python Python
import os
from mem0 import Memory
from langchain_openai import ChatOpenAI
# Set necessary environment variables for your chosen LangChain provider
os.environ["OPENAI_API_KEY"] = "your-api-key"
# Initialize a LangChain model directly
openai_model = ChatOpenAI(
model="gpt-4o",
temperature=0.2,
max_tokens=2000
)
# Pass the initialized model to the config
config = {
"llm": {
"provider": "langchain",
"config": {
"model": openai_model
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
</CodeGroup>
## Supported LangChain Providers
LangChain supports a wide range of LLM providers, including:
- OpenAI (`ChatOpenAI`)
- Anthropic (`ChatAnthropic`)
- Google (`ChatGoogleGenerativeAI`, `ChatGooglePalm`)
- Mistral (`ChatMistralAI`)
- Ollama (`ChatOllama`)
- Azure OpenAI (`AzureChatOpenAI`)
- HuggingFace (`HuggingFaceChatEndpoint`)
- And many more
You can use any of these model instances directly in your configuration. For a complete and up-to-date list of available providers, refer to the [LangChain Chat Models documentation](https://python.langchain.com/docs/integrations/chat).
## Provider-Specific Configuration
When using LangChain as a provider, you'll need to:
1. Set the appropriate environment variables for your chosen LLM provider
2. Import and initialize the specific model class you want to use
3. Pass the initialized model instance to the config
<Note>
Make sure to install the necessary LangChain packages and any provider-specific dependencies.
</Note>
## Config
All available parameters for the `langchain` config are present in [Master List of All Params in Config](../config).
+82
View File
@@ -0,0 +1,82 @@
---
title: LM Studio
---
To use LM Studio with Mem0, you'll need to have LM Studio running locally with its server enabled. LM Studio provides a way to run local LLMs with an OpenAI-compatible API.
## Usage
<CodeGroup>
```python Python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your-api-key" # used for embedding model
config = {
"llm": {
"provider": "lmstudio",
"config": {
"model": "lmstudio-community/Meta-Llama-3.1-70B-Instruct-GGUF/Meta-Llama-3.1-70B-Instruct-IQ2_M.gguf",
"temperature": 0.2,
"max_tokens": 2000,
"lmstudio_base_url": "http://localhost:1234/v1", # default LM Studio API URL
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
</CodeGroup>
### Running Completely Locally
You can also use LM Studio for both LLM and embedding to run Mem0 entirely locally:
```python
from mem0 import Memory
# No external API keys needed!
config = {
"llm": {
"provider": "lmstudio"
},
"embedder": {
"provider": "lmstudio"
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice123", metadata={"category": "movies"})
```
<Note>
When using LM Studio for both LLM and embedding, make sure you have:
1. An LLM model loaded for generating responses
2. An embedding model loaded for vector embeddings
3. The server enabled with the correct endpoints accessible
</Note>
<Note>
To use LM Studio, you need to:
1. Download and install [LM Studio](https://lmstudio.ai/)
2. Start a local server from the "Server" tab
3. Set the appropriate `lmstudio_base_url` in your configuration (default is usually http://localhost:1234/v1)
</Note>
## Config
All available parameters for the `lmstudio` config are present in [Master List of All Params in Config](../config).
+2
View File
@@ -32,6 +32,8 @@ To view all supported llms, visit the [Supported LLMs](./models).
<Card title="Gemini" href="/components/llms/models/gemini" />
<Card title="DeepSeek" href="/components/llms/models/deepseek" />
<Card title="xAI" href="/components/llms/models/xAI" />
<Card title="LM Studio" href="/components/llms/models/lmstudio" />
<Card title="Langchain" href="/components/llms/models/langchain" />
</CardGroup>
## Structured vs Unstructured Outputs
+1 -1
View File
@@ -8,7 +8,7 @@ iconType: "solid"
The `config` is defined as an object with two main keys:
- `vector_store`: Specifies the vector database provider and its configuration
- `provider`: The name of the vector database (e.g., "chroma", "pgvector", "qdrant", "milvus","azure_ai_search", "vertex_ai_vector_search")
- `provider`: The name of the vector database (e.g., "chroma", "pgvector", "qdrant", "milvus", "upstash_vector", "azure_ai_search", "vertex_ai_vector_search")
- `config`: A nested dictionary containing provider-specific settings
+99
View File
@@ -0,0 +1,99 @@
---
title: Azure AI Search
---
[Azure AI Search](https://learn.microsoft.com/azure/search/search-what-is-azure-search/) (formerly known as "Azure Cognitive Search") provides secure information retrieval at scale over user-owned content in traditional and generative AI search applications.
## Usage
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "sk-xx" # This key is used for embedding purpose
config = {
"vector_store": {
"provider": "azure_ai_search",
"config": {
"service_name": "ai-search-test",
"api_key": "*****",
"collection_name": "mem0",
"embedding_model_dims": 1536
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
## Using binary compression for large vector collections
```python
config = {
"vector_store": {
"provider": "azure_ai_search",
"config": {
"service_name": "ai-search-test",
"api_key": "*****",
"collection_name": "mem0",
"embedding_model_dims": 1536,
"compression_type": "binary",
"use_float16": True # Use half precision for storage efficiency
}
}
}
```
## Using hybrid search
```python
config = {
"vector_store": {
"provider": "azure_ai_search",
"config": {
"service_name": "ai-search-test",
"api_key": "*****",
"collection_name": "mem0",
"embedding_model_dims": 1536,
"hybrid_search": True,
"vector_filter_mode": "postFilter"
}
}
}
```
## Configuration Parameters
| Parameter | Description | Default Value | Options |
| --- | --- | --- | --- |
| `service_name` | Azure AI Search service name | Required | - |
| `api_key` | API key of the Azure AI Search service | Required | - |
| `collection_name` | The name of the collection/index to store vectors | `mem0` | Any valid index name |
| `embedding_model_dims` | Dimensions of the embedding model | `1536` | Any integer value |
| `compression_type` | Type of vector compression to use | `none` | `none`, `scalar`, `binary` |
| `use_float16` | Store vectors in half precision (Edm.Half) | `False` | `True`, `False` |
| `vector_filter_mode` | Vector filter mode to use | `preFilter` | `postFilter`, `preFilter` |
| `hybrid_search` | Use hybrid search | `False` | `True`, `False` |
## Notes on Configuration Options
- **compression_type**:
- `none`: No compression, uses full vector precision
- `scalar`: Scalar quantization with reasonable balance of speed and accuracy
- `binary`: Binary quantization for maximum compression with some accuracy trade-off
- **vector_filter_mode**:
- `preFilter`: Applies filters before vector search (faster)
- `postFilter`: Applies filters after vector search (may provide better relevance)
- **use_float16**: Using half precision (float16) reduces storage requirements but may slightly impact accuracy. Useful for very large vector collections.
- **Filterable Fields**: The implementation automatically extracts `user_id`, `run_id`, and `agent_id` fields from payloads for filtering.
@@ -1,44 +0,0 @@
[Azure AI Search](https://learn.microsoft.com/en-us/azure/search/search-what-is-azure-search/) (formerly known as "Azure Cognitive Search") provides secure information retrieval at scale over user-owned content in traditional and generative AI search applications.
### Usage
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "sk-xx" #this key is used for embedding purpose
config = {
"vector_store": {
"provider": "azure_ai_search",
"config": {
"service_name": "ai-search-test",
"api_key": "*****",
"collection_name": "mem0",
"embedding_model_dims": 1536 ,
"use_compression": False
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I’m not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
### Config
Let's see the available parameters for the `qdrant` config:
service_name (str): Azure Cognitive Search service name.
| Parameter | Description | Default Value |
| --- | --- | --- |
| `service_name` | Azure AI Search service name | `None` |
| `api_key` | API key of the Azure AI Search service | `None` |
| `collection_name` | The name of the collection/index to store the vectors, it will be created automatically if not exist | `mem0` |
| `embedding_model_dims` | Dimensions of the embedding model | `1536` |
| `use_compression` | Use scalar quantization vector compression | False |
@@ -54,6 +54,7 @@ Let's see the available parameters for the `elasticsearch` config:
| `password` | Password for basic authentication | `None` |
| `verify_certs` | Whether to verify SSL certificates | `True` |
| `auto_create_index` | Whether to automatically create the index | `True` |
| `custom_search_query` | Function returning a custom search query | `None` |
### Features
@@ -62,3 +63,46 @@ Let's see the available parameters for the `elasticsearch` config:
- Multiple authentication methods (Basic Auth, API Key)
- Automatic index creation with optimized mappings for vector search
- Memory isolation through payload filtering
- Custom search query function to customize the search query
### Custom Search Query
The `custom_search_query` parameter allows you to customize the search query when `Memory.search` is called.
__Example__
```python
import os
from typing import List, Optional, Dict
from mem0 import Memory
def custom_search_query(query: List[float], limit: int, filters: Optional[Dict]) -> Dict:
return {
"knn": {
"field": "vector",
"query_vector": query,
"k": limit,
"num_candidates": limit * 2
}
}
os.environ["OPENAI_API_KEY"] = "sk-xx"
config = {
"vector_store": {
"provider": "elasticsearch",
"config": {
"collection_name": "mem0",
"host": "localhost",
"port": 9200,
"embedding_model_dims": 1536,
"custom_search_query": custom_search_query
}
}
}
```
It should be a function that takes the following parameters:
- `query`: a query vector used in `Memory.search`
- `limit`: a number of results used in `Memory.search`
- `filters`: a dictionary of key-value pairs used in `Memory.search`. You can add custom pairs for the custom search query.
The function should return a query body for the Elasticsearch search API.
+72
View File
@@ -0,0 +1,72 @@
[FAISS](https://github.com/facebookresearch/faiss) is a library for efficient similarity search and clustering of dense vectors. It is designed to work with large-scale datasets and provides a high-performance search engine for vector data. FAISS is optimized for memory usage and search speed, making it an excellent choice for production environments.
### Usage
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "sk-xx"
config = {
"vector_store": {
"provider": "faiss",
"config": {
"collection_name": "test",
"path": "/tmp/faiss_memories",
"distance_strategy": "euclidean"
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
### Installation
To use FAISS in your mem0 project, you need to install the appropriate FAISS package for your environment:
```bash
# For CPU version
pip install faiss-cpu
# For GPU version (requires CUDA)
pip install faiss-gpu
```
### Config
Here are the parameters available for configuring FAISS:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `collection_name` | The name of the collection | `mem0` |
| `path` | Path to store FAISS index and metadata | `/tmp/faiss/<collection_name>` |
| `distance_strategy` | Distance metric strategy to use (options: 'euclidean', 'inner_product', 'cosine') | `euclidean` |
| `normalize_L2` | Whether to normalize L2 vectors (only applicable for euclidean distance) | `False` |
### Performance Considerations
FAISS offers several advantages for vector search:
1. **Efficiency**: FAISS is optimized for memory usage and speed, making it suitable for large-scale applications.
2. **Offline Support**: FAISS works entirely locally, with no need for external servers or API calls.
3. **Storage Options**: Vectors can be stored in-memory for maximum speed or persisted to disk.
4. **Multiple Index Types**: FAISS supports different index types optimized for various use cases (though mem0 currently uses the basic flat index).
### Distance Strategies
FAISS in mem0 supports three distance strategies:
- **euclidean**: L2 distance, suitable for most embedding models
- **inner_product**: Dot product similarity, useful for some specialized embeddings
- **cosine**: Cosine similarity, best for comparing semantic similarity regardless of vector magnitude
When using `cosine` or `inner_product` with normalized vectors, you may want to set `normalize_L2=True` for better results.
@@ -0,0 +1,85 @@
---
title: LangChain
---
Mem0 supports LangChain as a provider for vector store integration. LangChain provides a unified interface to various vector databases, making it easy to integrate different vector store providers through a consistent API.
<Note>
When using LangChain as your vector store provider, you must set the collection name to "mem0". This is a required configuration for proper integration with Mem0.
</Note>
## Usage
<CodeGroup>
```python Python
import os
from mem0 import Memory
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings
# Initialize a LangChain vector store
embeddings = OpenAIEmbeddings()
vector_store = Chroma(
persist_directory="./chroma_db",
embedding_function=embeddings,
collection_name="mem0" # Required collection name
)
# Pass the initialized vector store to the config
config = {
"vector_store": {
"provider": "langchain",
"config": {
"client": vector_store
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
</CodeGroup>
## Supported LangChain Vector Stores
LangChain supports a wide range of vector store providers, including:
- Chroma
- FAISS
- Pinecone
- Weaviate
- Milvus
- Qdrant
- And many more
You can use any of these vector store instances directly in your configuration. For a complete and up-to-date list of available providers, refer to the [LangChain Vector Stores documentation](https://python.langchain.com/docs/integrations/vectorstores).
## Limitations
When using LangChain as a vector store provider, there are some limitations to be aware of:
1. **Bulk Operations**: The `get_all` and `delete_all` operations are not supported when using LangChain as the vector store provider. This is because LangChain's vector store interface doesn't provide standardized methods for these bulk operations across all providers.
2. **Provider-Specific Features**: Some advanced features may not be available depending on the specific vector store implementation you're using through LangChain.
## Provider-Specific Configuration
When using LangChain as a vector store provider, you'll need to:
1. Set the appropriate environment variables for your chosen vector store provider
2. Import and initialize the specific vector store class you want to use
3. Pass the initialized vector store instance to the config
<Note>
Make sure to install the necessary LangChain packages and any provider-specific dependencies.
</Note>
## Config
All available parameters for the `langchain` vector store config are present in [Master List of All Params in Config](../config).
@@ -0,0 +1,92 @@
[Pinecone](https://www.pinecone.io/) is a fully managed vector database designed for machine learning applications, offering high performance vector search with low latency at scale. It's particularly well-suited for semantic search, recommendation systems, and other AI-powered applications.
> **Note**: Before configuring Pinecone, you need to select an embedding model (e.g., OpenAI, Cohere, or custom models) and ensure the `embedding_model_dims` in your config matches your chosen model's dimensions. For example, OpenAI's text-embedding-3-small uses 1536 dimensions.
### Usage
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "sk-xx"
os.environ["PINECONE_API_KEY"] = "your-api-key"
# Example using serverless configuration
config = {
"vector_store": {
"provider": "pinecone",
"config": {
"collection_name": "testing",
"embedding_model_dims": 1536, # Matches OpenAI's text-embedding-3-small
"serverless_config": {
"cloud": "aws", # Choose between 'aws' or 'gcp' or 'azure'
"region": "us-east-1"
},
"metric": "cosine"
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
### Config
Here are the parameters available for configuring Pinecone:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `collection_name` | Name of the index/collection | Required |
| `embedding_model_dims` | Dimensions of the embedding model (must match your chosen embedding model) | Required |
| `client` | Existing Pinecone client instance | `None` |
| `api_key` | API key for Pinecone | Environment variable: `PINECONE_API_KEY` |
| `environment` | Pinecone environment | `None` |
| `serverless_config` | Configuration for serverless deployment (AWS or GCP or Azure) | `None` |
| `pod_config` | Configuration for pod-based deployment | `None` |
| `hybrid_search` | Whether to enable hybrid search | `False` |
| `metric` | Distance metric for vector similarity | `"cosine"` |
| `batch_size` | Batch size for operations | `100` |
> **Important**: You must choose either `serverless_config` or `pod_config` for your deployment, but not both.
#### Serverless Config Example
```python
config = {
"vector_store": {
"provider": "pinecone",
"config": {
"collection_name": "memory_index",
"embedding_model_dims": 1536, # For OpenAI's text-embedding-3-small
"serverless_config": {
"cloud": "aws", # or "gcp" or "azure"
"region": "us-east-1" # Choose appropriate region
}
}
}
}
```
#### Pod Config Example
```python
config = {
"vector_store": {
"provider": "pinecone",
"config": {
"collection_name": "memory_index",
"embedding_model_dims": 1536, # For OpenAI's text-embedding-ada-002
"pod_config": {
"environment": "gcp-starter",
"replicas": 1,
"pod_type": "starter"
}
}
}
}
```
+93 -1
View File
@@ -4,7 +4,8 @@ Create a [Supabase](https://supabase.com/dashboard/projects) account and project
### Usage
```python
<CodeGroup>
```python Python
import os
from mem0 import Memory
@@ -32,10 +33,90 @@ messages = [
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
```typescript Typescript
import { Memory } from "mem0ai/oss";
const config = {
vectorStore: {
provider: "supabase",
config: {
collectionName: "memories",
embeddingModelDims: 1536,
supabaseUrl: process.env.SUPABASE_URL || "",
supabaseKey: process.env.SUPABASE_KEY || "",
tableName: "memories",
},
},
}
const memory = new Memory(config);
const messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
await memory.add(messages, { userId: "alice", metadata: { category: "movies" } });
```
</CodeGroup>
### SQL Migrations for TypeScript Implementation
The following SQL migrations are required to enable the vector extension and create the memories table:
```sql
-- Enable the vector extension
create extension if not exists vector;
-- Create the memories table
create table if not exists memories (
id text primary key,
embedding vector(1536),
metadata jsonb,
created_at timestamp with time zone default timezone('utc', now()),
updated_at timestamp with time zone default timezone('utc', now())
);
-- Create the vector similarity search function
create or replace function match_vectors(
query_embedding vector(1536),
match_count int,
filter jsonb default '{}'::jsonb
)
returns table (
id text,
similarity float,
metadata jsonb
)
language plpgsql
as $$
begin
return query
select
t.id::text,
1 - (t.embedding <=> query_embedding) as similarity,
t.metadata
from memories t
where case
when filter::text = '{}'::text then true
else t.metadata @> filter
end
order by t.embedding <=> query_embedding
limit match_count;
end;
$$;
```
Goto [Supabase](https://supabase.com/dashboard/projects) and run the above SQL migrations inside the SQL Editor.
### Config
Here are the parameters available for configuring Supabase:
<Tabs>
<Tab title="Python">
| Parameter | Description | Default Value |
| --- | --- | --- |
| `connection_string` | PostgreSQL connection string (required) | None |
@@ -43,6 +124,17 @@ Here are the parameters available for configuring Supabase:
| `embedding_model_dims` | Dimensions of the embedding model | `1536` |
| `index_method` | Vector index method to use | `auto` |
| `index_measure` | Distance measure for similarity search | `cosine_distance` |
</Tab>
<Tab title="TypeScript">
| Parameter | Description | Default Value |
| --- | --- | --- |
| `collectionName` | Name for the vector collection | `mem0` |
| `embeddingModelDims` | Dimensions of the embedding model | `1536` |
| `supabaseUrl` | Supabase URL | None |
| `supabaseKey` | Supabase key | None |
| `tableName` | Name for the vector table | `memories` |
</Tab>
</Tabs>
### Index Methods
@@ -0,0 +1,70 @@
[Upstash Vector](https://upstash.com/docs/vector) is a serverless vector database with built-in embedding models.
### Usage with Upstash embeddings
You can enable the built-in embedding models by setting `enable_embeddings` to `True`. This allows you to use Upstash's embedding models for vectorization.
```python
import os
from mem0 import Memory
os.environ["UPSTASH_VECTOR_REST_URL"] = "..."
os.environ["UPSTASH_VECTOR_REST_TOKEN"] = "..."
config = {
"vector_store": {
"provider": "upstash_vector",
"enable_embeddings": True,
}
}
m = Memory.from_config(config)
m.add("Likes to play cricket on weekends", user_id="alice", metadata={"category": "hobbies"})
```
<Note>
Setting `enable_embeddings` to `True` will bypass any external embedding provider you have configured.
</Note>
### Usage with external embedding providers
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "..."
os.environ["UPSTASH_VECTOR_REST_URL"] = "..."
os.environ["UPSTASH_VECTOR_REST_TOKEN"] = "..."
config = {
"vector_store": {
"provider": "upstash_vector",
},
"embedder": {
"provider": "openai",
"config": {
"model": "text-embedding-3-large"
},
}
}
m = Memory.from_config(config)
m.add("Likes to play cricket on weekends", user_id="alice", metadata={"category": "hobbies"})
```
### Config
Here are the parameters available for configuring Upstash Vector:
| Parameter | Description | Default Value |
| ------------------- | ---------------------------------- | ------------- |
| `url` | URL for the Upstash Vector index | `None` |
| `token` | Token for the Upstash Vector index | `None` |
| `client` | An `upstash_vector.Index` instance | `None` |
| `collection_name` | The default namespace used | `""` |
| `enable_embeddings` | Whether to use Upstash embeddings | `False` |
<Note>
When `url` and `token` are not provided, the `UPSTASH_VECTOR_REST_URL` and
`UPSTASH_VECTOR_REST_TOKEN` environment variables are used.
</Note>
@@ -1,4 +1,6 @@
## Google Cloud Vertex AI Vector Search
---
title: Vertex AI Vector Search
---
### Usage
@@ -0,0 +1,47 @@
[Weaviate](https://weaviate.io/) is an open-source vector search engine. It allows efficient storage and retrieval of high-dimensional vector embeddings, enabling powerful search and retrieval capabilities.
### Installation
```bash
pip install weaviate weaviate-client
```
### Usage
```python Python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "sk-xx"
config = {
"vector_store": {
"provider": "weaviate",
"config": {
"collection_name": "test",
"cluster_url": "http://localhost:8080",
"auth_client_secret": None,
}
}
}
m = Memory.from_config(config)
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movie? They can be quite engaging."},
{"role": "user", "content": "I’m not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
m.add(messages, user_id="alice", metadata={"category": "movies"})
```
### Config
Let's see the available parameters for the `weaviate` config:
| Parameter | Description | Default Value |
| --- | --- | --- |
| `collection_name` | The name of the collection to store the vectors | `mem0` |
| `embedding_model_dims` | Dimensions of the embedding model | `1536` |
| `cluster_url` | URL for the Weaviate server | `None` |
| `auth_client_secret` | API key for Weaviate authentication | `None` |
+7 -2
View File
@@ -18,13 +18,18 @@ See the list of supported vector databases below.
<Card title="Qdrant" href="/components/vectordbs/dbs/qdrant"></Card>
<Card title="Chroma" href="/components/vectordbs/dbs/chroma"></Card>
<Card title="Pgvector" href="/components/vectordbs/dbs/pgvector"></Card>
<Card title="Upstash Vector" href="/components/vectordbs/dbs/upstash-vector"></Card>
<Card title="Milvus" href="/components/vectordbs/dbs/milvus"></Card>
<Card title="Azure AI Search" href="/components/vectordbs/dbs/azure_ai_search"></Card>
<Card title="Pinecone" href="/components/vectordbs/dbs/pinecone"></Card>
<Card title="Azure" href="/components/vectordbs/dbs/azure"></Card>
<Card title="Redis" href="/components/vectordbs/dbs/redis"></Card>
<Card title="Elasticsearch" href="/components/vectordbs/dbs/elasticsearch"></Card>
<Card title="OpenSearch" href="/components/vectordbs/dbs/opensearch"></Card>
<Card title="Supabase" href="/components/vectordbs/dbs/supabase"></Card>
<Card title="Vertex AI Vector Search" href="/components/vectordbs/dbs/vertex_ai_vector_search"></Card>
<Card title="Vertex AI" href="/components/vectordbs/dbs/vertex_ai"></Card>
<Card title="Weaviate" href="/components/vectordbs/dbs/weaviate"></Card>
<Card title="FAISS" href="/components/vectordbs/dbs/faiss"></Card>
<Card title="LangChain" href="/components/vectordbs/dbs/langchain"></Card>
</CardGroup>
## Usage
+63 -9
View File
@@ -47,6 +47,7 @@
"pages": [
"features/platform-overview",
"features/advanced-retrieval",
"features/contextual-add",
"features/multimodal-support",
"features/selective-memory",
"features/custom-categories",
@@ -54,7 +55,9 @@
"features/direct-import",
"features/async-client",
"features/memory-export",
"features/webhooks"
"features/webhooks",
"features/graph-memory",
"features/feedback-mechanism"
]
}
]
@@ -70,8 +73,10 @@
"group": "Features",
"icon": "wrench",
"pages": [
"open-source/features/async-memory",
"features/openai_compatibility",
"features/custom-prompts",
"features/custom-fact-extraction-prompt",
"features/custom-update-memory-prompt",
"open-source/multimodal-support",
"open-source/features/rest-api"
]
@@ -106,7 +111,9 @@
"components/llms/models/aws_bedrock",
"components/llms/models/gemini",
"components/llms/models/deepseek",
"components/llms/models/xAI"
"components/llms/models/xAI",
"components/llms/models/lmstudio",
"components/llms/models/langchain"
]
}
]
@@ -125,12 +132,16 @@
"components/vectordbs/dbs/chroma",
"components/vectordbs/dbs/pgvector",
"components/vectordbs/dbs/milvus",
"components/vectordbs/dbs/azure_ai_search",
"components/vectordbs/dbs/pinecone",
"components/vectordbs/dbs/azure",
"components/vectordbs/dbs/redis",
"components/vectordbs/dbs/elasticsearch",
"components/vectordbs/dbs/opensearch",
"components/vectordbs/dbs/supabase",
"components/vectordbs/dbs/vertex_ai_vector_search"
"components/vectordbs/dbs/vertex_ai",
"components/vectordbs/dbs/weaviate",
"components/vectordbs/dbs/faiss",
"components/vectordbs/dbs/langchain"
]
}
]
@@ -150,7 +161,10 @@
"components/embedders/models/ollama",
"components/embedders/models/huggingface",
"components/embedders/models/vertexai",
"components/embedders/models/gemini"
"components/embedders/models/gemini",
"components/embedders/models/lmstudio",
"components/embedders/models/together",
"components/embedders/models/langchain"
]
}
]
@@ -177,6 +191,7 @@
"examples/overview",
"examples/mem0-demo",
"examples/ai_companion_js",
"examples/mem0-mastra",
"examples/mem0-with-ollama",
"examples/personal-ai-tutor",
"examples/customer-support-agent",
@@ -185,7 +200,12 @@
"examples/chrome-extension",
"examples/document-writing",
"examples/multimodal-demo",
"examples/personalized-deep-research"
"examples/personalized-deep-research",
"examples/mem0-agentic-tool",
"examples/openai-inbuilt-tools",
"examples/mem0-openai-voice-demo",
"examples/email_processing",
"examples/youtube-assistant"
]
}
]
@@ -199,6 +219,7 @@
"pages": [
"integrations/overview",
"integrations/vercel-ai-sdk",
"integrations/flowise",
"integrations/crewai",
"integrations/autogen",
"integrations/langchain",
@@ -206,7 +227,11 @@
"integrations/llama-index",
"integrations/langchain-tools",
"integrations/dify",
"integrations/mcp-server"
"integrations/mcp-server",
"integrations/livekit",
"integrations/elevenlabs",
"integrations/pipecat",
"integrations/agno"
]
}
]
@@ -237,7 +262,8 @@
"api-reference/memory/batch-delete",
"api-reference/memory/delete-memories",
"api-reference/memory/create-memory-export",
"api-reference/memory/get-memory-export"
"api-reference/memory/get-memory-export",
"api-reference/memory/feedback"
]
},
{
@@ -260,6 +286,18 @@
"api-reference/organization/delete-org"
]
},
{
"group": "Project APIs",
"icon": "folder",
"pages": [
"api-reference/project/create-project",
"api-reference/project/get-projects",
"api-reference/project/get-project",
"api-reference/project/get-project-members",
"api-reference/project/add-project-member",
"api-reference/project/delete-project"
]
},
{
"group": "Webhook APIs",
"icon": "webhook",
@@ -273,6 +311,19 @@
]
}
]
},
{
"tab": "Changelog",
"icon": "clock",
"groups": [
{
"group": "Product Updates",
"icon": "rocket",
"pages": [
"changelog/overview"
]
}
]
}
]
},
@@ -333,6 +384,9 @@
"posthog": {
"apiKey": "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX",
"apiHost": "https://mango.mem0.ai"
},
"intercom": {
"appId": "jjv2r0tt"
}
}
}
+186
View File
@@ -0,0 +1,186 @@
---
title: Email Processing with Mem0
---
This guide demonstrates how to build an intelligent email processing system using Mem0's memory capabilities. You'll learn how to store, categorize, retrieve, and analyze emails to create a smart email management solution.
## Overview
Email overload is a common challenge for many professionals. By leveraging Mem0's memory capabilities, you can build an intelligent system that:
- Stores emails as searchable memories
- Categorizes emails automatically
- Retrieves relevant past conversations
- Prioritizes messages based on importance
- Generates summaries and action items
## Setup
Before you begin, ensure you have the required dependencies installed:
```bash
pip install mem0ai openai
```
## Implementation
### Basic Email Memory System
The following example shows how to create a basic email processing system with Mem0:
```python
import os
from mem0 import MemoryClient
from email.parser import Parser
# Configure API keys
os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
# Initialize Mem0 client
client = MemoryClient()
class EmailProcessor:
def __init__(self):
"""Initialize the Email Processor with Mem0 memory client"""
self.client = client
def process_email(self, email_content, user_id):
"""
Process an email and store it in Mem0 memory
Args:
email_content (str): Raw email content
user_id (str): User identifier for memory association
"""
# Parse email
parser = Parser()
email = parser.parsestr(email_content)
# Extract email details
sender = email['from']
recipient = email['to']
subject = email['subject']
date = email['date']
body = self._get_email_body(email)
# Create message object for Mem0
message = {
"role": "user",
"content": f"Email from {sender}: {subject}\n\n{body}"
}
# Create metadata for better retrieval
metadata = {
"email_type": "incoming",
"sender": sender,
"recipient": recipient,
"subject": subject,
"date": date
}
# Store in Mem0 with appropriate categories
response = self.client.add(
messages=[message],
user_id=user_id,
metadata=metadata,
categories=["email", "correspondence"],
version="v2"
)
return response
def _get_email_body(self, email):
"""Extract the body content from an email"""
# Simplified extraction - in real-world, handle multipart emails
if email.is_multipart():
for part in email.walk():
if part.get_content_type() == "text/plain":
return part.get_payload(decode=True).decode()
else:
return email.get_payload(decode=True).decode()
def search_emails(self, query, user_id):
"""
Search through stored emails
Args:
query (str): Search query
user_id (str): User identifier
"""
# Search Mem0 for relevant emails
results = self.client.search(
query=query,
user_id=user_id,
categories=["email"],
output_format="v1.1",
version="v2"
)
return results
def get_email_thread(self, subject, user_id):
"""
Retrieve all emails in a thread based on subject
Args:
subject (str): Email subject to match
user_id (str): User identifier
"""
filters = {
"AND": [
{"user_id": user_id},
{"categories": {"contains": "email"}},
{"metadata": {"subject": {"contains": subject}}}
]
}
thread = self.client.get_all(
version="v2",
filters=filters,
output_format="v1.1"
)
return thread
# Initialize the processor
processor = EmailProcessor()
# Example raw email
sample_email = """From: alice@example.com
To: bob@example.com
Subject: Meeting Schedule Update
Date: Mon, 15 Jul 2024 14:22:05 -0700
Hi Bob,
I wanted to update you on the schedule for our upcoming project meeting.
We'll be meeting this Thursday at 2pm instead of Friday.
Could you please prepare your section of the presentation?
Thanks,
Alice
"""
# Process and store the email
user_id = "bob@example.com"
processor.process_email(sample_email, user_id)
# Later, search for emails about meetings
meeting_emails = processor.search_emails("meeting schedule", user_id)
print(f"Found {len(meeting_emails['results'])} relevant emails")
```
## Key Features and Benefits
- **Long-term Email Memory**: Store and retrieve email conversations across long periods
- **Semantic Search**: Find relevant emails even if they don't contain exact keywords
- **Intelligent Categorization**: Automatically sort emails into meaningful categories
- **Action Item Extraction**: Identify and track tasks mentioned in emails
- **Priority Management**: Focus on important emails based on AI-determined priority
- **Context Awareness**: Maintain thread context for more relevant interactions
## Conclusion
By combining Mem0's memory capabilities with email processing, you can create intelligent email management systems that help users organize, prioritize, and act on their inbox effectively. The advanced capabilities like automatic categorization, action item extraction, and priority management can significantly reduce the time spent on email management, allowing users to focus on more important tasks.
+226
View File
@@ -0,0 +1,226 @@
---
title: Mem0 as an Agentic Tool
---
Integrate Mem0's memory capabilities with OpenAI's Agents SDK to create AI agents with persistent memory.
You can create agents that remember past conversations and use that context to provide better responses.
## Installation
First, install the required packages:
```bash
pip install mem0ai pydantic openai-agents
```
You'll also need a custom agents framework for this implementation.
## Setting Up Environment Variables
Store your Mem0 API key as an environment variable:
```bash
export MEM0_API_KEY="your_mem0_api_key"
```
Or in your Python script:
```python
import os
os.environ["MEM0_API_KEY"] = "your_mem0_api_key"
```
## Code Structure
The integration consists of three main components:
1. **Context Manager**: Defines user context for memory operations
2. **Memory Tools**: Functions to add, search, and retrieve memories
3. **Memory Agent**: An agent configured to use these memory tools
## Step-by-Step Implementation
### 1. Import Dependencies
```python
from __future__ import annotations
import os
import asyncio
from pydantic import BaseModel
try:
from mem0 import AsyncMemoryClient
except ImportError:
raise ImportError("mem0 is not installed. Please install it using 'pip install mem0ai'.")
from agents import (
Agent,
ItemHelpers,
MessageOutputItem,
RunContextWrapper,
Runner,
ToolCallItem,
ToolCallOutputItem,
TResponseInputItem,
function_tool,
)
```
### 2. Define Memory Context
```python
class Mem0Context(BaseModel):
user_id: str | None = None
```
### 3. Initialize the Mem0 Client
```python
client = AsyncMemoryClient(api_key=os.getenv("MEM0_API_KEY"))
```
### 4. Create Memory Tools
#### Add to Memory
```python
@function_tool
async def add_to_memory(
context: RunContextWrapper[Mem0Context],
content: str,
) -> str:
"""
Add a message to Mem0
Args:
content: The content to store in memory.
"""
messages = [{"role": "user", "content": content}]
user_id = context.context.user_id or "default_user"
await client.add(messages, user_id=user_id)
return f"Stored message: {content}"
```
#### Search Memory
```python
@function_tool
async def search_memory(
context: RunContextWrapper[Mem0Context],
query: str,
) -> str:
"""
Search for memories in Mem0
Args:
query: The search query.
"""
user_id = context.context.user_id or "default_user"
memories = await client.search(query, user_id=user_id, output_format="v1.1")
results = '\n'.join([result["memory"] for result in memories["results"]])
return str(results)
```
#### Get All Memories
```python
@function_tool
async def get_all_memory(
context: RunContextWrapper[Mem0Context],
) -> str:
"""Retrieve all memories from Mem0"""
user_id = context.context.user_id or "default_user"
memories = await client.get_all(user_id=user_id, output_format="v1.1")
results = '\n'.join([result["memory"] for result in memories["results"]])
return str(results)
```
### 5. Configure the Memory Agent
```python
memory_agent = Agent[Mem0Context](
name="Memory Assistant",
instructions="""You are a helpful assistant with memory capabilities. You can:
1. Store new information using add_to_memory
2. Search existing information using search_memory
3. Retrieve all stored information using get_all_memory
When users ask questions:
- If they want to store information, use add_to_memory
- If they're searching for specific information, use search_memory
- If they want to see everything stored, use get_all_memory""",
tools=[add_to_memory, search_memory, get_all_memory],
)
```
### 6. Implement the Main Runtime Loop
```python
async def main():
current_agent: Agent[Mem0Context] = memory_agent
input_items: list[TResponseInputItem] = []
context = Mem0Context()
while True:
user_input = input("Enter your message (or 'quit' to exit): ")
if user_input.lower() == 'quit':
break
input_items.append({"content": user_input, "role": "user"})
result = await Runner.run(current_agent, input_items, context=context)
for new_item in result.new_items:
agent_name = new_item.agent.name
if isinstance(new_item, MessageOutputItem):
print(f"{agent_name}: {ItemHelpers.text_message_output(new_item)}")
elif isinstance(new_item, ToolCallItem):
print(f"{agent_name}: Calling a tool")
elif isinstance(new_item, ToolCallOutputItem):
print(f"{agent_name}: Tool call output: {new_item.output}")
else:
print(f"{agent_name}: Skipping item: {new_item.__class__.__name__}")
input_items = result.to_input_list()
if __name__ == "__main__":
asyncio.run(main())
```
## Usage Examples
### Storing Information
```
User: Remember that my favorite color is blue
Agent: Calling a tool
Agent: Tool call output: Stored message: my favorite color is blue
Agent: I've stored that your favorite color is blue in my memory. I'll remember that for future conversations.
```
### Searching Memory
```
User: What's my favorite color?
Agent: Calling a tool
Agent: Tool call output: my favorite color is blue
Agent: Your favorite color is blue, based on what you've told me earlier.
```
### Retrieving All Memories
```
User: What do you know about me?
Agent: Calling a tool
Agent: Tool call output: favorite color is blue
my birthday is on March 15
Agent: Based on our previous conversations, I know that:
1. Your favorite color is blue
2. Your birthday is on March 15
```
## Advanced Configuration
### Custom User IDs
You can specify different user IDs to maintain separate memory stores for multiple users:
```python
context = Mem0Context(user_id="user123")
```
## Resources
- [Mem0 Documentation](https://docs.mem0.ai)
- [Mem0 Dashboard](https://app.mem0.ai/dashboard)
- [API Reference](https://docs.mem0.ai/api-reference)
+126
View File
@@ -0,0 +1,126 @@
---
title: Mem0 with Mastra
---
In this example you'll learn how to use the Mem0 to add long-term memory capabilities to [Mastra's agent](https://mastra.ai/) via tool-use.
This memory integration can work alongside Mastra's [agent memory features](https://mastra.ai/docs/agents/01-agent-memory).
You can find the complete example code in the [Mastra repository](https://github.com/mastra-ai/mastra/tree/main/examples/memory-with-mem0).
## Overview
This guide will show you how to integrate Mem0 with Mastra to add long-term memory capabilities to your agents. We'll create tools that allow agents to save and retrieve memories using Mem0's API.
### Installation
1. **Install the Integration Package**
To install the Mem0 integration, run:
```bash
npm install @mastra/mem0
```
2. **Add the Integration to Your Project**
Create a new file for your integrations and import the integration:
```typescript integrations/index.ts
import { Mem0Integration } from "@mastra/mem0";
export const mem0 = new Mem0Integration({
config: {
apiKey: process.env.MEM0_API_KEY!,
userId: "alice",
},
});
```
3. **Use the Integration in Tools or Workflows**
You can now use the integration when defining tools for your agents or in workflows.
```typescript tools/index.ts
import { createTool } from "@mastra/core";
import { z } from "zod";
import { mem0 } from "../integrations";
export const mem0RememberTool = createTool({
id: "Mem0-remember",
description:
"Remember your agent memories that you've previously saved using the Mem0-memorize tool.",
inputSchema: z.object({
question: z
.string()
.describe("Question used to look up the answer in saved memories."),
}),
outputSchema: z.object({
answer: z.string().describe("Remembered answer"),
}),
execute: async ({ context }) => {
console.log(`Searching memory "${context.question}"`);
const memory = await mem0.searchMemory(context.question);
console.log(`\nFound memory "${memory}"\n`);
return {
answer: memory,
};
},
});
export const mem0MemorizeTool = createTool({
id: "Mem0-memorize",
description:
"Save information to mem0 so you can remember it later using the Mem0-remember tool.",
inputSchema: z.object({
statement: z.string().describe("A statement to save into memory"),
}),
execute: async ({ context }) => {
console.log(`\nCreating memory "${context.statement}"\n`);
// to reduce latency memories can be saved async without blocking tool execution
void mem0.createMemory(context.statement).then(() => {
console.log(`\nMemory "${context.statement}" saved.\n`);
});
return { success: true };
},
});
```
4. **Create a new agent**
```typescript agents/index.ts
import { openai } from '@ai-sdk/openai';
import { Agent } from '@mastra/core/agent';
import { mem0MemorizeTool, mem0RememberTool } from '../tools';
export const mem0Agent = new Agent({
name: 'Mem0 Agent',
instructions: `
You are a helpful assistant that has the ability to memorize and remember facts using Mem0.
`,
model: openai('gpt-4o'),
tools: { mem0RememberTool, mem0MemorizeTool },
});
```
5. **Run the agent**
```typescript index.ts
import { Mastra } from '@mastra/core/mastra';
import { createLogger } from '@mastra/core/logger';
import { mem0Agent } from './agents';
export const mastra = new Mastra({
agents: { mem0Agent },
logger: createLogger({
name: 'Mastra',
level: 'error',
}),
});
```
In the example above:
- We import the `@mastra/mem0` integration.
- We define two tools that uses the Mem0 API client to create new memories and recall previously saved memories.
- The tool accepts `question` as an input and returns the memory as a string.
+538
View File
@@ -0,0 +1,538 @@
---
title: 'Mem0 with OpenAI Agents SDK for Voice'
description: 'Integrate memory capabilities into your voice agents using Mem0 and OpenAI Agents SDK'
---
# Building Voice Agents with Memory using Mem0 and OpenAI Agents SDK
This guide demonstrates how to combine OpenAI's Agents SDK for voice applications with Mem0's memory capabilities to create a voice assistant that remembers user preferences and past interactions.
## Prerequisites
Before you begin, make sure you have:
1. Installed OpenAI Agents SDK with voice dependencies:
```bash
pip install 'openai-agents[voice]'
```
2. Installed Mem0 SDK:
```bash
pip install mem0ai
```
3. Installed other required dependencies:
```bash
pip install numpy sounddevice pydantic
```
4. Set up your API keys:
- OpenAI API key for the Agents SDK
- Mem0 API key from the Mem0 Platform
## Code Breakdown
Let's break down the key components of this implementation:
### 1. Setting Up Dependencies and Environment
```python
# OpenAI Agents SDK imports
from agents import (
Agent,
function_tool
)
from agents.voice import (
AudioInput,
SingleAgentVoiceWorkflow,
VoicePipeline
)
from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
# Mem0 imports
from mem0 import AsyncMemoryClient
# Set up API keys (replace with your actual keys)
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
# Define a global user ID for simplicity
USER_ID = "voice_user"
# Initialize Mem0 client
mem0_client = AsyncMemoryClient()
```
This section handles:
- Importing required modules from OpenAI Agents SDK and Mem0
- Setting up environment variables for API keys
- Defining a simple user identification system (using a global variable)
- Initializing the Mem0 client that will handle memory operations
### 2. Memory Tools with Function Decorators
The `@function_tool` decorator transforms Python functions into callable tools for the OpenAI agent. Here are the key memory tools:
#### Storing User Memories
```python
import logging
# Set up logging at the top of your file
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
force=True
)
logger = logging.getLogger("memory_voice_agent")
# Then use logger in your function tools
@function_tool
async def save_memories(
memory: str
) -> str:
"""Store a user memory in memory."""
# This will be visible in your console
logger.debug(f"Saving memory: {memory} for user {USER_ID}")
# Store the preference in Mem0
memory_content = f"User memory - {memory}"
await mem0_client.add(
memory_content,
user_id=USER_ID,
)
return f"I've saved your memory: {memory}"
```
This function:
- Takes a memory string
- Creates a formatted memory string
- Stores it in Mem0 using the `add()` method
- Includes metadata to categorize the memory for easier retrieval
- Returns a confirmation message that the agent will speak
#### Finding Relevant Memories
```python
@function_tool
async def search_memories(
query: str
) -> str:
"""
Find memories relevant to the current conversation.
Args:
query: The search query to find relevant memories
"""
print(f"Finding memories related to: {query}")
results = await mem0_client.search(
query,
user_id=USER_ID,
limit=5,
threshold=0.7, # Higher threshold for more relevant results
output_format="v1.1"
)
# Format and return the results
if not results.get('results', []):
return "I don't have any relevant memories about this topic."
memories = [f"• {result['memory']}" for result in results.get('results', [])]
return "Here's what I remember that might be relevant:\n" + "\n".join(memories)
```
This tool:
- Takes a search query string
- Passes it to Mem0's semantic search to find related memories
- Sets a threshold for relevance to ensure quality results
- Returns a formatted list of relevant memories or a default message
### 3. Creating the Voice Agent
```python
def create_memory_voice_agent():
# Create the agent with memory-enabled tools
agent = Agent(
name="Memory Assistant",
instructions=prompt_with_handoff_instructions(
"""You're speaking to a human, so be polite and concise.
Always respond in clear, natural English.
You have the ability to remember information about the user.
Use the save_memories tool when the user shares an important information worth remembering.
Use the search_memories tool when you need context from past conversations or user asks you to recall something.
""",
),
model="gpt-4o",
tools=[save_memories, search_memories],
)
return agent
```
This function:
- Creates an OpenAI Agent with specific instructions
- Configures it to use gpt-4o (you can use other models)
- Registers the memory-related tools with the agent
- Uses `prompt_with_handoff_instructions` to include standard voice agent behaviors
### 4. Microphone Recording Functionality
```python
async def record_from_microphone(duration=5, samplerate=24000):
"""Record audio from the microphone for a specified duration."""
print(f"Recording for {duration} seconds...")
# Create a buffer to store the recorded audio
frames = []
# Callback function to store audio data
def callback(indata, frames_count, time_info, status):
frames.append(indata.copy())
# Start recording
with sd.InputStream(samplerate=samplerate, channels=1, callback=callback, dtype=np.int16):
await asyncio.sleep(duration)
# Combine all frames into a single numpy array
audio_data = np.concatenate(frames)
return audio_data
```
This function:
- Creates a simple asynchronous microphone recording function
- Uses the sounddevice library to capture audio input
- Stores frames in a buffer during recording
- Combines frames into a single numpy array when complete
- Returns the audio data for processing
### 5. Main Loop and Voice Processing
```python
async def main():
# Create the agent
agent = create_memory_voice_agent()
# Set up the voice pipeline
pipeline = VoicePipeline(
workflow=SingleAgentVoiceWorkflow(agent)
)
# Configure TTS settings
pipeline.config.tts_settings.voice = "alloy"
pipeline.config.tts_settings.speed = 1.0
try:
while True:
# Get user input
print("\nPress Enter to start recording (or 'q' to quit)...")
user_input = input()
if user_input.lower() == 'q':
break
# Record and process audio
audio_data = await record_from_microphone(duration=5)
audio_input = AudioInput(buffer=audio_data)
result = await pipeline.run(audio_input)
# Play response and handle events
player = sd.OutputStream(samplerate=24000, channels=1, dtype=np.int16)
player.start()
agent_response = ""
print("\nAgent response:")
async for event in result.stream():
if event.type == "voice_stream_event_audio":
player.write(event.data)
elif event.type == "voice_stream_event_content":
content = event.data
agent_response += content
print(content, end="", flush=True)
# Save the agent's response to memory
if agent_response:
try:
await mem0_client.add(
f"Agent response: {agent_response}",
user_id=USER_ID,
metadata={"type": "agent_response"}
)
except Exception as e:
print(f"Failed to store memory: {e}")
except KeyboardInterrupt:
print("\nExiting...")
```
This main function orchestrates the entire process:
1. Creates the memory-enabled voice agent
2. Sets up the voice pipeline with TTS settings
3. Implements an interactive loop for recording and processing voice input
4. Handles streaming of response events (both audio and text)
5. Automatically saves the agent's responses to memory
6. Includes proper error handling and exit mechanisms
## Create a Memory-Enabled Voice Agent
Now that we've explained each component, here's the complete implementation that combines OpenAI Agents SDK for voice with Mem0's memory capabilities:
```python
import asyncio
import os
import logging
from typing import Optional, List, Dict, Any
import numpy as np
import sounddevice as sd
from pydantic import BaseModel
# OpenAI Agents SDK imports
from agents import (
Agent,
function_tool
)
from agents.voice import (
AudioInput,
SingleAgentVoiceWorkflow,
VoicePipeline
)
from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
# Mem0 imports
from mem0 import AsyncMemoryClient
# Set up API keys (replace with your actual keys)
os.environ["OPENAI_API_KEY"] = "your-openai-api-key"
os.environ["MEM0_API_KEY"] = "your-mem0-api-key"
# Define a global user ID for simplicity
USER_ID = "voice_user"
# Initialize Mem0 client
mem0_client = AsyncMemoryClient()
# Create tools that utilize Mem0's memory
@function_tool
async def save_memories(
memory: str
) -> str:
"""
Store a user memory in memory.
Args:
memory: The memory to save
"""
print(f"Saving memory: {memory} for user {USER_ID}")
# Store the preference in Mem0
memory_content = f"User memory - {memory}"
await mem0_client.add(
memory_content,
user_id=USER_ID,
)
return f"I've saved your memory: {memory}"
@function_tool
async def search_memories(
query: str
) -> str:
"""
Find memories relevant to the current conversation.
Args:
query: The search query to find relevant memories
"""
print(f"Finding memories related to: {query}")
results = await mem0_client.search(
query,
user_id=USER_ID,
limit=5,
threshold=0.7, # Higher threshold for more relevant results
output_format="v1.1"
)
# Format and return the results
if not results.get('results', []):
return "I don't have any relevant memories about this topic."
memories = [f"• {result['memory']}" for result in results.get('results', [])]
return "Here's what I remember that might be relevant:\n" + "\n".join(memories)
# Create the agent with memory-enabled tools
def create_memory_voice_agent():
# Create the agent with memory-enabled tools
agent = Agent(
name="Memory Assistant",
instructions=prompt_with_handoff_instructions(
"""You're speaking to a human, so be polite and concise.
Always respond in clear, natural English.
You have the ability to remember information about the user.
Use the save_memories tool when the user shares an important information worth remembering.
Use the search_memories tool when you need context from past conversations or user asks you to recall something.
""",
),
model="gpt-4o",
tools=[save_memories, search_memories],
)
return agent
async def record_from_microphone(duration=5, samplerate=24000):
"""Record audio from the microphone for a specified duration."""
print(f"Recording for {duration} seconds...")
# Create a buffer to store the recorded audio
frames = []
# Callback function to store audio data
def callback(indata, frames_count, time_info, status):
frames.append(indata.copy())
# Start recording
with sd.InputStream(samplerate=samplerate, channels=1, callback=callback, dtype=np.int16):
await asyncio.sleep(duration)
# Combine all frames into a single numpy array
audio_data = np.concatenate(frames)
return audio_data
async def main():
print("Starting Memory Voice Agent")
# Create the agent and context
agent = create_memory_voice_agent()
# Set up the voice pipeline
pipeline = VoicePipeline(
workflow=SingleAgentVoiceWorkflow(agent)
)
# Configure TTS settings
pipeline.config.tts_settings.voice = "alloy"
pipeline.config.tts_settings.speed = 1.0
try:
while True:
# Get user input
print("\nPress Enter to start recording (or 'q' to quit)...")
user_input = input()
if user_input.lower() == 'q':
break
# Record and process audio
audio_data = await record_from_microphone(duration=5)
audio_input = AudioInput(buffer=audio_data)
print("Processing your request...")
# Process the audio input
result = await pipeline.run(audio_input)
# Create an audio player
player = sd.OutputStream(samplerate=24000, channels=1, dtype=np.int16)
player.start()
# Store the agent's response for adding to memory
agent_response = ""
print("\nAgent response:")
# Play the audio stream as it comes in
async for event in result.stream():
if event.type == "voice_stream_event_audio":
player.write(event.data)
elif event.type == "voice_stream_event_content":
# Accumulate and print the text response
content = event.data
agent_response += content
print(content, end="", flush=True)
print("\n")
# Example of saving the conversation to Mem0 after completion
if agent_response:
try:
await mem0_client.add(
f"Agent response: {agent_response}",
user_id=USER_ID,
metadata={"type": "agent_response"}
)
except Exception as e:
print(f"Failed to store memory: {e}")
except KeyboardInterrupt:
print("\nExiting...")
if __name__ == "__main__":
asyncio.run(main())
```
## Key Features of This Implementation
This implementation offers several key features:
1. **Simplified User Management**: Uses a global `USER_ID` variable for simplicity, but can be extended to manage multiple users.
2. **Real Microphone Input**: Includes a `record_from_microphone()` function that captures actual voice input from your microphone.
3. **Interactive Voice Loop**: Implements a continuous interaction loop, allowing for multiple back-and-forth exchanges.
4. **Memory Management Tools**:
- `save_memories`: Stores user memories in Mem0
- `search_memories`: Searches for relevant past information
5. **Voice Configuration**: Demonstrates how to configure TTS settings for the voice response.
## Running the Example
To run this example:
1. Replace the placeholder API keys with your actual keys
2. Make sure your microphone is properly connected
3. Run the script with Python 3.8 or newer
4. Press Enter to start recording, then speak your request
5. Press 'q' to quit the application
The agent will listen to your request, process it through the OpenAI model, utilize Mem0 for memory operations as needed, and respond both through text output and voice speech.
## Best Practices for Voice Agents with Memory
1. **Optimizing Memory for Voice**: Keep memories concise and relevant for voice responses.
2. **Forgetting Mechanism**: Implement a way to delete or expire memories that are no longer relevant.
3. **Context Preservation**: Store enough context with each memory to make retrieval effective.
4. **Error Handling**: Implement robust error handling for memory operations, as voice interactions should continue smoothly even if memory operations fail.
## Conclusion
By combining OpenAI's Agents SDK with Mem0's memory capabilities, you can create voice agents that maintain persistent memory of user preferences and past interactions. This significantly enhances the user experience by making conversations more natural and personalized.
As you build your voice application, experiment with different memory strategies and filtering approaches to find the optimal balance between comprehensive memory and efficient retrieval for your specific use case.
## Debugging Function Tools
When working with the OpenAI Agents SDK, you might notice that regular `print()` statements inside `@function_tool` decorated functions don't appear in your console output. This is because the Agents SDK captures and redirects standard output when executing these functions.
To effectively debug your function tools, use Python's `logging` module instead:
```python
import logging
# Set up logging at the top of your file
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
force=True
)
logger = logging.getLogger("memory_voice_agent")
# Then use logger in your function tools
@function_tool
async def save_memories(
memory: str
) -> str:
"""Store a user memory in memory."""
# This will be visible in your console
logger.debug(f"Saving memory: {memory} for user {USER_ID}")
# Rest of your function...
```
+312
View File
@@ -0,0 +1,312 @@
---
title: OpenAI Inbuilt Tools
---
Integrate Mem0’s memory capabilities with OpenAI’s Inbuilt Tools to create AI agents with persistent memory.
## Getting Started
### Installation
```bash
npm install mem0ai openai zod
```
## Environment Setup
Save your Mem0 and OpenAI API keys in a `.env` file:
```
MEM0_API_KEY=your_mem0_api_key
OPENAI_API_KEY=your_openai_api_key
```
Get your Mem0 API key from the [Mem0 Dashboard](https://app.mem0.ai/dashboard/api-keys).
### Configuration
```javascript
const mem0Config = {
apiKey: process.env.MEM0_API_KEY,
user_id: "sample-user",
};
const openAIClient = new OpenAI();
const mem0Client = new MemoryClient(mem0Config);
```
### Adding Memories
Store user preferences, past interactions, or any relevant information:
<CodeGroup>
```javascript JavaScript
async function addUserPreferences() {
const mem0Client = new MemoryClient(mem0Config);
const userPreferences = "I Love BMW, Audi and Porsche. I Hate Mercedes. I love Red cars and Maroon cars. I have a budget of 120K to 150K USD. I like Audi the most.";
await mem0Client.add([{
role: "user",
content: userPreferences,
}], mem0Config);
}
await addUserPreferences();
```
```json Output (Memories)
[
{
"id": "ff9f3367-9e83-415d-b9c5-dc8befd9a4b4",
"data": { "memory": "Loves BMW, Audi, and Porsche" },
"event": "ADD"
},
{
"id": "04172ce6-3d7b-45a3-b4a1-ee9798593cb4",
"data": { "memory": "Hates Mercedes" },
"event": "ADD"
},
{
"id": "db363a5d-d258-4953-9e4c-777c120de34d",
"data": { "memory": "Loves red cars and maroon cars" },
"event": "ADD"
},
{
"id": "5519aaad-a2ac-4c0d-81d7-0d55c6ecdba8",
"data": { "memory": "Has a budget of 120K to 150K USD" },
"event": "ADD"
},
{
"id": "523b7693-7344-4563-922f-5db08edc8634",
"data": { "memory": "Likes Audi the most" },
"event": "ADD"
}
]
```
</CodeGroup>
### Retrieving Memories
Search for relevant memories based on the current user input:
```javascript
const relevantMemories = await mem0Client.search(userInput, mem0Config);
```
### Structured Responses with Zod
Define structured response schemas to get consistent output formats:
```javascript
// Define the schema for a car recommendation
const CarSchema = z.object({
car_name: z.string(),
car_price: z.string(),
car_url: z.string(),
car_image: z.string(),
car_description: z.string(),
});
// Schema for a list of car recommendations
const Cars = z.object({
cars: z.array(CarSchema),
});
// Create a function tool based on the schema
const carRecommendationTool = zodResponsesFunction({
name: "carRecommendations",
parameters: Cars
});
// Use the tool in your OpenAI request
const response = await openAIClient.responses.create({
model: "gpt-4o",
tools: [{ type: "web_search_preview" }, carRecommendationTool],
input: `${getMemoryString(relevantMemories)}\n${userInput}`,
});
```
### Using Web Search
Combine memory with web search for up-to-date recommendations:
```javascript
const response = await openAIClient.responses.create({
model: "gpt-4o",
tools: [{ type: "web_search_preview" }, carRecommendationTool],
input: `${getMemoryString(relevantMemories)}\n${userInput}`,
});
```
## Examples
### Complete Car Recommendation System
```javascript
import MemoryClient from "mem0ai";
import { OpenAI } from "openai";
import { zodResponsesFunction } from "openai/helpers/zod";
import { z } from "zod";
import dotenv from 'dotenv';
dotenv.config();
const mem0Config = {
apiKey: process.env.MEM0_API_KEY,
user_id: "sample-user",
};
async function run() {
// Responses without memories
console.log("\n\nRESPONSES WITHOUT MEMORIES\n\n");
await main();
// Adding sample memories
await addSampleMemories();
// Responses with memories
console.log("\n\nRESPONSES WITH MEMORIES\n\n");
await main(true);
}
// OpenAI Response Schema
const CarSchema = z.object({
car_name: z.string(),
car_price: z.string(),
car_url: z.string(),
car_image: z.string(),
car_description: z.string(),
});
const Cars = z.object({
cars: z.array(CarSchema),
});
async function main(memory = false) {
const openAIClient = new OpenAI();
const mem0Client = new MemoryClient(mem0Config);
const input = "Suggest me some cars that I can buy today.";
const tool = zodResponsesFunction({ name: "carRecommendations", parameters: Cars });
// Store the user input as a memory
await mem0Client.add([{
role: "user",
content: input,
}], mem0Config);
// Search for relevant memories
let relevantMemories = []
if (memory) {
relevantMemories = await mem0Client.search(input, mem0Config);
}
const response = await openAIClient.responses.create({
model: "gpt-4o",
tools: [{ type: "web_search_preview" }, tool],
input: `${getMemoryString(relevantMemories)}\n${input}`,
});
console.log(response.output);
}
async function addSampleMemories() {
const mem0Client = new MemoryClient(mem0Config);
const myInterests = "I Love BMW, Audi and Porsche. I Hate Mercedes. I love Red cars and Maroon cars. I have a budget of 120K to 150K USD. I like Audi the most.";
await mem0Client.add([{
role: "user",
content: myInterests,
}], mem0Config);
}
const getMemoryString = (memories) => {
const MEMORY_STRING_PREFIX = "These are the memories I have stored. Give more weightage to the question by users and try to answer that first. You have to modify your answer based on the memories I have provided. If the memories are irrelevant you can ignore them. Also don't reply to this section of the prompt, or the memories, they are only for your reference. The MEMORIES of the USER are: \n\n";
const memoryString = memories.map((mem) => `${mem.memory}`).join("\n") ?? "";
return memoryString.length > 0 ? `${MEMORY_STRING_PREFIX}${memoryString}` : "";
};
run().catch(console.error);
```
### Responses
<CodeGroup>
```json Without Memories
{
"cars": [
{
"car_name": "Toyota Camry",
"car_price": "$25,000",
"car_url": "https://www.toyota.com/camry/",
"car_image": "https://link-to-toyota-camry-image.com",
"car_description": "Reliable mid-size sedan with great fuel efficiency."
},
{
"car_name": "Honda Accord",
"car_price": "$26,000",
"car_url": "https://www.honda.com/accord/",
"car_image": "https://link-to-honda-accord-image.com",
"car_description": "Comfortable and spacious with advanced safety features."
},
{
"car_name": "Ford Mustang",
"car_price": "$28,000",
"car_url": "https://www.ford.com/mustang/",
"car_image": "https://link-to-ford-mustang-image.com",
"car_description": "Iconic sports car with powerful engine options."
},
{
"car_name": "Tesla Model 3",
"car_price": "$38,000",
"car_url": "https://www.tesla.com/model3",
"car_image": "https://link-to-tesla-model3-image.com",
"car_description": "Electric vehicle with advanced technology and long range."
},
{
"car_name": "Chevrolet Equinox",
"car_price": "$24,000",
"car_url": "https://www.chevrolet.com/equinox/",
"car_image": "https://link-to-chevron-equinox-image.com",
"car_description": "Compact SUV with a spacious interior and user-friendly technology."
}
]
}
```
```json With Memories
{
"cars": [
{
"car_name": "Audi RS7",
"car_price": "$118,500",
"car_url": "https://www.audiusa.com/us/web/en/models/rs7/2023/overview.html",
"car_image": "https://www.audiusa.com/content/dam/nemo/us/models/rs7/my23/gallery/1920x1080_AOZ_A717_191004.jpg",
"car_description": "The Audi RS7 is a high-performance hatchback with a sleek design, powerful 591-hp twin-turbo V8, and luxurious interior. It's available in various colors including red."
},
{
"car_name": "Porsche Panamera GTS",
"car_price": "$129,300",
"car_url": "https://www.porsche.com/usa/models/panamera/panamera-models/panamera-gts/",
"car_image": "https://files.porsche.com/filestore/image/multimedia/noneporsche-panamera-gts-sample-m02-high/normal/8a6327c3-6c7f-4c6f-a9a8-fb9f58b21795;sP;twebp/porsche-normal.webp",
"car_description": "The Porsche Panamera GTS is a luxury sports sedan with a 473-hp V8 engine, exquisite handling, and available in stunning red. Balances sportiness and comfort."
},
{
"car_name": "BMW M5",
"car_price": "$105,500",
"car_url": "https://www.bmwusa.com/vehicles/m-models/m5/sedan/overview.html",
"car_image": "https://www.bmwusa.com/content/dam/bmwusa/M/m5/2023/bmw-my23-m5-sapphire-black-twilight-purple-exterior-02.jpg",
"car_description": "The BMW M5 is a powerhouse sedan with a 600-hp V8 engine, known for its great handling and luxury. It comes in several distinctive colors including maroon."
}
]
}
```
</CodeGroup>
## Resources
- [Mem0 Documentation](https://docs.mem0.ai)
- [Mem0 Dashboard](https://app.mem0.ai/dashboard)
- [API Reference](https://docs.mem0.ai/api-reference)
- [OpenAI Documentation](https://platform.openai.com/docs)
+21 -1
View File
@@ -47,6 +47,10 @@ Explore how **Mem0** can power real-world applications and bring personalized, i
Add **long-term memory** to ChatGPT, Claude, or Perplexity via the **Mem0 Chrome Extension** — personalize your AI chats anywhere.
</Card>
<Card title="YouTube Assistant" icon="puzzle-piece" href="/examples/youtube-assistant">
Integrate **Mem0** into **YouTube's** native UI, providing personalized responses with video context.
</Card>
<Card title="Document Writing Assistant" icon="pen" href="/examples/document-writing">
Create a **Writing Assistant** that understands and adapts to your unique style, improving consistency and productivity.
</Card>
@@ -55,7 +59,23 @@ Explore how **Mem0** can power real-world applications and bring personalized, i
Supercharge AI with **Mem0's multimodal memory** — blend text, images, and more for richer, context-aware interactions.
</Card>
<Card title="Personalized Research Agent" icon="robot" href="/examples/personalized-deep-research">
<Card title="Personalized Research Agent" icon="magnifying-glass" href="/examples/personalized-deep-research">
Build a **Deep Research AI** that remembers your research goals and compiles insights from vast information sources.
</Card>
<Card title="Mem0 as an Agentic Tool" icon="robot" href="/examples/mem0-agentic-tool">
Integrate Mem0's memory capabilities with OpenAI's Agents SDK to create AI agents with persistent memory.
</Card>
<Card title="OpenAI Inbuilt Tools" icon="robot" href="/examples/openai-inbuilt-tools">
Use Mem0's memory capabilities with OpenAI's Inbuilt Tools to create AI agents with persistent memory.
</Card>
<Card title="Mem0 OpenAI Voice Demo" icon="microphone" href="/examples/mem0-openai-voice-demo">
Use Mem0's memory capabilities with OpenAI's Inbuilt Tools to create AI agents with persistent memory.
</Card>
<Card title="Email Processing" icon="envelope" href="/examples/email_processing">
Use Mem0's memory capabilities to process emails and create AI agents with persistent memory.
</Card>
</CardGroup>
+11 -11
View File
@@ -20,6 +20,7 @@ pip install openai mem0ai
Below is the complete code to create and interact with a Personalized AI Tutor using Mem0:
```python
import os
from openai import OpenAI
from mem0 import Memory
@@ -54,22 +55,21 @@ class PersonalAITutor:
:param question: The question to ask the AI.
:param user_id: Optional user ID to associate with the memory.
"""
# Start a streaming chat completion request to the AI
stream = self.client.chat.completions.create(
model="gpt-4",
stream=True,
messages=[
{"role": "system", "content": "You are a personal AI Tutor."},
{"role": "user", "content": question}
]
# Start a streaming response request to the AI
response = self.client.responses.create(
model="gpt-4o",
instructions="You are a personal AI Tutor.",
input=question,
stream=True
)
# Store the question in memory
self.memory.add(question, user_id=user_id, metadata={"app_id": self.app_id})
# Print the response from the AI in real-time
for chunk in stream:
if chunk.choices[0].delta.content is not None:
print(chunk.choices[0].delta.content, end="")
for event in response:
if event.type == "response.output_text.delta":
print(event.delta, end="")
def get_memories(self, user_id=None):
"""
+14 -9
View File
@@ -63,18 +63,23 @@ class PersonalTravelAssistant:
def ask_question(self, question, user_id):
# Fetch previous related memories
previous_memories = self.search_memories(question, user_id=user_id)
prompt = question
if previous_memories:
prompt = f"User input: {question}\n Previous memories: {previous_memories}"
self.messages.append({"role": "user", "content": prompt})
# Generate response using GPT-4o
response = self.client.chat.completions.create(
# Build the prompt
system_message = "You are a personal AI Assistant."
if previous_memories:
prompt = f"{system_message}\n\nUser input: {question}\nPrevious memories: {', '.join(previous_memories)}"
else:
prompt = f"{system_message}\n\nUser input: {question}"
# Generate response using Responses API
response = self.client.responses.create(
model="gpt-4o",
messages=self.messages
input=prompt
)
answer = response.choices[0].message.content
self.messages.append({"role": "assistant", "content": answer})
# Extract answer from the response
answer = response.output[0].content[0].text
# Store the question in memory
self.memory.add(question, user_id=user_id)
+56
View File
@@ -0,0 +1,56 @@
---
title: YouTube Assistant Extension
---
Enhance your YouTube experience with Mem0's **YouTube Assistant**, a Chrome extension that brings AI-powered chat directly to your YouTube videos. Get instant, personalized answers about video content while leveraging your own knowledge and memories - all without leaving the page.
## Features
- **Contextual AI Chat**: Ask questions about videos you're watching
- **Seamless Integration**: Chat interface sits alongside YouTube's native UI
- **Memory Integration**: Personalized responses based on your knowledge through Mem0
- **Real-Time Memory**: Memories are updated in real-time based on your interactions
## Installation
This extension is not available on the Chrome Web Store yet. You can install it manually using below method:
### Manual Installation (Developer Mode)
1. **Download the Extension**: Clone or download the extension files from the [Mem0 GitHub repository](https://github.com/mem0ai/mem0/tree/main/examples).
2. **Build**: Run `npm install` followed by `npm run build` to install the dependencies and build the extension.
3. **Access Chrome Extensions**: Open Google Chrome and navigate to `chrome://extensions`.
4. **Enable Developer Mode**: Toggle the "Developer mode" switch in the top right corner.
5. **Load Unpacked Extension**: Click "Load unpacked" and select the directory containing the extension files.
6. **Confirm Installation**: The Mem0 YouTube Assistant Extension should now appear in your Chrome toolbar.
## Setup
1. **Configure API Settings**: Click the extension icon and enter your OpenAI API key (required to use the extension)
2. **Customize Settings**: Configure additional settings such as model, temperature, and memory settings
3. **Navigate to YouTube**: Start using the assistant on any YouTube video
4. **Memories**: Enter your Mem0 API key to enable personalized responses, and feed initial memories from settings
## Demo Video
<video
autoPlay
muted
loop
playsInline
width="700"
height="400"
src="https://github.com/user-attachments/assets/c0334ccd-311b-4dd7-8034-ef88204fc751"
></video>
## Example Prompts
- "Can you summarize the main points of this video?"
- "Explain the concept they just mentioned"
- "How does this relate to what I already know?"
- "What are some practical applications of this topic related to my work?"
## Privacy and Data Security
Your API keys are stored locally in your browser. Your messages are sent to the Mem0 API for extracting and retrieving memories. Mem0 is committed to ensuring your data's privacy and security.
+17
View File
@@ -125,6 +125,23 @@ iconType: "solid"
This flexibility allows you to create highly contextually aware AI applications that can adapt to specific user needs and situations. Metadata provides an additional dimension for memory retrieval, enabling more precise and relevant responses.
</Accordion>
<Accordion title="How do I disable telemetry in Mem0?">
To disable telemetry in Mem0, you can set the `MEM0_TELEMETRY` environment variable to `False`:
```bash
MEM0_TELEMETRY=False
```
You can also disable telemetry programmatically in your code:
```python
import os
os.environ["MEM0_TELEMETRY"] = "False"
```
Setting this environment variable will prevent Mem0 from collecting and sending any usage data, ensuring complete privacy for your application.
</Accordion>
</AccordionGroup>
+205
View File
@@ -0,0 +1,205 @@
---
title: Contextual Add (ADD v2)
icon: "square-plus"
iconType: "solid"
---
Mem0 now supports an contextual add version (v2). To use it, set `version="v2"` during the add call. The default version is v1, which is deprecated now. We recommend migrating to `v2` for new applications.
## Key Differences Between v1 and v2
### Version 1 (Legacy)
In v1 (default), users needed to pass either the entire conversation history or past k messages with each new message to generate properly contextualized memories. This approach required:
- Manually tracking and sending previous messages using a sliding window approach
- Increased payload sizes as conversations grew longer, requiring careful window size management
<CodeGroup>
```python Python
# First interaction
messages1 = [
{"role": "user", "content": "Hi, I'm Alex and I live in San Francisco."},
{"role": "assistant", "content": "Hello Alex! Nice to meet you. San Francisco is a beautiful city."}
]
client.add(messages1, user_id="alex")
# Second interaction - must include previous messages for context
messages2 = [
{"role": "user", "content": "Hi, I'm Alex and I live in San Francisco."},
{"role": "assistant", "content": "Hello Alex! Nice to meet you. San Francisco is a beautiful city."},
{"role": "user", "content": "I like to eat sushi, and yesterday I went to Sunnyvale to eat sushi with my friends."},
{"role": "assistant", "content": "Sushi is really a tasty choice. What did you do this weekend?"}
]
client.add(messages2, user_id="alex")
```
```javascript JavaScript
// First interaction
const messages1 = [
{"role": "user", "content": "Hi, I'm Alex and I live in San Francisco."},
{"role": "assistant", "content": "Hello Alex! Nice to meet you. San Francisco is a beautiful city."}
];
client.add(messages1, { user_id: "alex" })
.then(response => console.log(response))
.catch(error => console.error(error));
// Second interaction - must include previous messages for context
const messages2 = [
{"role": "user", "content": "Hi, I'm Alex and I live in San Francisco."},
{"role": "assistant", "content": "Hello Alex! Nice to meet you. San Francisco is a beautiful city."},
{"role": "user", "content": "I like to eat sushi, and yesterday I went to Sunnyvale to eat sushi with my friends."},
{"role": "assistant", "content": "Sushi is really a tasty choice. What did you do this weekend?"}
];
client.add(messages2, { user_id: "alex" })
.then(response => console.log(response))
.catch(error => console.error(error));
```
</CodeGroup>
### Version 2 (Recommended)
In v2, Mem0 automatically manages conversation context. Users only need to send new messages, and the system will:
- Automatically retrieve relevant conversation history
- Generate properly contextualized memories
- Reduce payload sizes and simplify integration
<CodeGroup>
```python Python
# First interaction
messages1 = [
{"role": "user", "content": "Hi, I'm Alex and I live in San Francisco."},
{"role": "assistant", "content": "Hello Alex! Nice to meet you. San Francisco is a beautiful city."}
]
client.add(messages1, user_id="alex", version="v2")
# Second interaction - only need to send new messages
messages2 = [
{"role": "user", "content": "I like to eat sushi, and yesterday I went to Sunnyvale to eat sushi with my friends."},
{"role": "assistant", "content": "Sushi is really a tasty choice. What did you do this weekend?"}
]
client.add(messages2, user_id="alex", version="v2")
```
```javascript JavaScript
// First interaction
const messages1 = [
{"role": "user", "content": "Hi, I'm Alex and I live in San Francisco."},
{"role": "assistant", "content": "Hello Alex! Nice to meet you. San Francisco is a beautiful city."}
];
client.add(messages1, { user_id: "alex", version: "v2" })
.then(response => console.log(response))
.catch(error => console.error(error));
// Second interaction - only need to send new messages
const messages2 = [
{"role": "user", "content": "I like to eat sushi, and yesterday I went to Sunnyvale to eat sushi with my friends."},
{"role": "assistant", "content": "Sushi is really a tasty choice. What did you do this weekend?"}
];
client.add(messages2, { user_id: "alex", version: "v2" })
.then(response => console.log(response))
.catch(error => console.error(error));
```
</CodeGroup>
## Benefits of Using v2
1. **Simplified Integration**: No need to track and manage conversation history
2. **Reduced Payload Size**: Only send new messages, not the entire conversation
3. **Improved Memory Quality**: Automatic context retrieval ensures better memory generation
## Understanding ID Parameters in v2
When using contextual add v2, you have different options for how to organize and retrieve memories:
### Using Only `user_id`
When you provide only a `user_id`:
- Memories are associated with this user's long-term memory store
- The system will automatically retrieve relevant context from all of the user's previous conversations
- These memories persist indefinitely across all of the user's sessions
- Ideal for maintaining persistent user information (preferences, personal details, etc.)
<CodeGroup>
```python Python
# Adding to long-term user memory
messages = [
{"role": "user", "content": "I'm allergic to peanuts and shellfish."},
{"role": "assistant", "content": "I've noted your allergies to peanuts and shellfish."}
]
client.add(messages, user_id="alex", version="v2")
```
```javascript JavaScript
// Adding to long-term user memory
const messages = [
{"role": "user", "content": "I'm allergic to peanuts and shellfish."},
{"role": "assistant", "content": "I've noted your allergies to peanuts and shellfish."}
];
client.add(messages, { user_id: "alex", version: "v2" })
.then(response => console.log(response))
.catch(error => console.error(error));
```
</CodeGroup>
### Using `user_id` with `run_id`
When you provide both `user_id` and `run_id`:
- Memories are associated with a specific conversation session or interaction
- The system will retrieve context primarily from this specific session
- These memories are still tied to the user but are organized by the specific session
- Ideal for maintaining context within a specific conversation flow or task
- Helps prevent context from different conversations from interfering with each other
<CodeGroup>
```python Python
# Adding to a specific conversation session
messages = [
{"role": "user", "content": "For this trip to Paris, I want to focus on art museums."},
{"role": "assistant", "content": "Great! I'll help you plan your Paris trip with a focus on art museums."}
]
client.add(messages, user_id="alex", run_id="paris-trip-2024", version="v2")
# Later in the same conversation session
messages2 = [
{"role": "user", "content": "I'd like to visit the Louvre on Monday."},
{"role": "assistant", "content": "The Louvre is a great choice for Monday. Would you like information about opening hours?"}
]
client.add(messages2, user_id="alex", run_id="paris-trip-2024", version="v2")
```
```javascript JavaScript
// Adding to a specific conversation session
const messages = [
{"role": "user", "content": "For this trip to Paris, I want to focus on art museums."},
{"role": "assistant", "content": "Great! I'll help you plan your Paris trip with a focus on art museums."}
];
client.add(messages, { user_id: "alex", run_id: "paris-trip-2024", version: "v2" })
.then(response => console.log(response))
.catch(error => console.error(error));
// Later in the same conversation session
const messages2 = [
{"role": "user", "content": "I'd like to visit the Louvre on Monday."},
{"role": "assistant", "content": "The Louvre is a great choice for Monday. Would you like information about opening hours?"}
];
client.add(messages2, { user_id: "alex", run_id: "paris-trip-2024", version: "v2" })
.then(response => console.log(response))
.catch(error => console.error(error));
```
</CodeGroup>
Using `run_id` helps you organize memories into logical sessions or tasks, making it easier to maintain context for specific interactions while still associating everything with the user's overall profile.
If you have any questions, please feel free to reach out to us using one of the following methods:
<Snippet file="get-help.mdx" />
@@ -1,25 +1,25 @@
---
title: Custom Prompts
description: 'Enhance your product experience by adding custom prompts tailored to your needs'
title: Custom Fact Extraction Prompt
description: 'Enhance your product experience by adding custom fact extraction prompt tailored to your needs'
icon: "pencil"
iconType: "solid"
---
## Introduction to Custom Prompts
## Introduction to Custom Fact Extraction Prompt
Custom prompts allow you to tailor the behavior of your Mem0 instance to specific use cases or domains.
By defining a custom prompt, you can control how information is extracted, processed, and stored in your memory system.
Custom fact extraction prompt allow you to tailor the behavior of your Mem0 instance to specific use cases or domains.
By defining it, you can control how information is extracted from the user's message.
To create an effective custom prompt:
To create an effective custom fact extraction prompt:
1. Be specific about the information to extract.
2. Provide few-shot examples to guide the LLM.
3. Ensure examples follow the format shown below.
Example of a custom prompt:
Example of a custom fact extraction prompt:
<CodeGroup>
```python Python
custom_prompt = """
custom_fact_extraction_prompt = """
Please only extract entities containing customer support information, order details, and user information.
Here are some few shot examples:
@@ -67,7 +67,7 @@ Return the facts and customer information in a json format as shown above.
```
</CodeGroup>
Here we initialize the custom prompt in the config:
Here we initialize the custom fact extraction prompt in the config:
<CodeGroup>
```python Python
@@ -82,7 +82,7 @@ config = {
"max_tokens": 2000,
}
},
"custom_prompt": custom_prompt,
"custom_fact_extraction_prompt": custom_fact_extraction_prompt,
"version": "v1.1"
}
@@ -166,4 +166,4 @@ await memory.add('I like going to hikes', { userId: "user123" });
```
</CodeGroup>
The custom prompt will process both the user and assistant messages to extract relevant information according to the defined format.
The custom fact extraction prompt will process both the user and assistant messages to extract relevant information according to the defined format.
@@ -0,0 +1,239 @@
---
title: Custom Update Memory Prompt
icon: "pencil"
iconType: "solid"
---
Update memory prompt is a prompt used to determine the action to be performed on the memory.
By customizing this prompt, you can control how the memory is updated.
## Introduction
Mem0 memory system compares the newly retrieved facts with the existing memory and determines the action to be performed on the memory.
The kinds of actions are:
- Add
- Add the newly retrieved facts to the memory.
- Update
- Update the existing memory with the newly retrieved facts.
- Delete
- Delete the existing memory.
- No Change
- Do not make any changes to the memory.
### Example
Example of a custom update memory prompt:
<CodeGroup>
```python Python
UPDATE_MEMORY_PROMPT = """You are a smart memory manager which controls the memory of a system.
You can perform four operations: (1) add into the memory, (2) update the memory, (3) delete from the memory, and (4) no change.
Based on the above four operations, the memory will change.
Compare newly retrieved facts with the existing memory. For each new fact, decide whether to:
- ADD: Add it to the memory as a new element
- UPDATE: Update an existing memory element
- DELETE: Delete an existing memory element
- NONE: Make no change (if the fact is already present or irrelevant)
There are specific guidelines to select which operation to perform:
1. **Add**: If the retrieved facts contain new information not present in the memory, then you have to add it by generating a new ID in the id field.
- **Example**:
- Old Memory:
[
{
"id" : "0",
"text" : "User is a software engineer"
}
]
- Retrieved facts: ["Name is John"]
- New Memory:
{
"memory" : [
{
"id" : "0",
"text" : "User is a software engineer",
"event" : "NONE"
},
{
"id" : "1",
"text" : "Name is John",
"event" : "ADD"
}
]
}
2. **Update**: If the retrieved facts contain information that is already present in the memory but the information is totally different, then you have to update it.
If the retrieved fact contains information that conveys the same thing as the elements present in the memory, then you have to keep the fact which has the most information.
Example (a) -- if the memory contains "User likes to play cricket" and the retrieved fact is "Loves to play cricket with friends", then update the memory with the retrieved facts.
Example (b) -- if the memory contains "Likes cheese pizza" and the retrieved fact is "Loves cheese pizza", then you do not need to update it because they convey the same information.
If the direction is to update the memory, then you have to update it.
Please keep in mind while updating you have to keep the same ID.
Please note to return the IDs in the output from the input IDs only and do not generate any new ID.
- **Example**:
- Old Memory:
[
{
"id" : "0",
"text" : "I really like cheese pizza"
},
{
"id" : "1",
"text" : "User is a software engineer"
},
{
"id" : "2",
"text" : "User likes to play cricket"
}
]
- Retrieved facts: ["Loves chicken pizza", "Loves to play cricket with friends"]
- New Memory:
{
"memory" : [
{
"id" : "0",
"text" : "Loves cheese and chicken pizza",
"event" : "UPDATE",
"old_memory" : "I really like cheese pizza"
},
{
"id" : "1",
"text" : "User is a software engineer",
"event" : "NONE"
},
{
"id" : "2",
"text" : "Loves to play cricket with friends",
"event" : "UPDATE",
"old_memory" : "User likes to play cricket"
}
]
}
3. **Delete**: If the retrieved facts contain information that contradicts the information present in the memory, then you have to delete it. Or if the direction is to delete the memory, then you have to delete it.
Please note to return the IDs in the output from the input IDs only and do not generate any new ID.
- **Example**:
- Old Memory:
[
{
"id" : "0",
"text" : "Name is John"
},
{
"id" : "1",
"text" : "Loves cheese pizza"
}
]
- Retrieved facts: ["Dislikes cheese pizza"]
- New Memory:
{
"memory" : [
{
"id" : "0",
"text" : "Name is John",
"event" : "NONE"
},
{
"id" : "1",
"text" : "Loves cheese pizza",
"event" : "DELETE"
}
]
}
4. **No Change**: If the retrieved facts contain information that is already present in the memory, then you do not need to make any changes.
- **Example**:
- Old Memory:
[
{
"id" : "0",
"text" : "Name is John"
},
{
"id" : "1",
"text" : "Loves cheese pizza"
}
]
- Retrieved facts: ["Name is John"]
- New Memory:
{
"memory" : [
{
"id" : "0",
"text" : "Name is John",
"event" : "NONE"
},
{
"id" : "1",
"text" : "Loves cheese pizza",
"event" : "NONE"
}
]
}
"""
```
</CodeGroup>
## Output format
The prompt needs to guide the output to follow the structure as shown below:
<CodeGroup>
```json Add
{
"memory": [
{
"id" : "0",
"text" : "This information is new",
"event" : "ADD"
}
]
}
```
```json Update
{
"memory": [
{
"id" : "0",
"text" : "This information replaces the old information",
"event" : "UPDATE",
"old_memory" : "Old information"
}
]
}
```
```json Delete
{
"memory": [
{
"id" : "0",
"text" : "This information will be deleted",
"event" : "DELETE"
}
]
}
```
```json No Change
{
"memory": [
{
"id" : "0",
"text" : "No changes for this information",
"event" : "NONE"
}
]
}
```
</CodeGroup>
## custom update memory prompt vs custom prompt
| Feature | `custom_update_memory_prompt` | `custom_prompt` |
|---------|-------------------------------|-----------------|
| Use case | Determine the action to be performed on the memory | Extract the facts from messages |
| Reference | Retrieved facts from messages and old memory | Messages |
| Output | Action to be performed on the memory | Extracted facts |
+62
View File
@@ -0,0 +1,62 @@
---
title: Feedback Mechanism
icon: "thumbs-up"
iconType: "solid"
---
Mem0's **Feedback Mechanism** allows you to provide feedback on the memories generated by your application. This feedback is used to improve the accuracy of the memories and the search results.
## How it works
The feedback mechanism is a simple API that allows you to provide feedback on the memories generated by your application. The feedback is stored in the database and is used to improve the accuracy of the memories and the search results. Over time, Mem0 continuously learns from this feedback, refining its memory generation and search capabilities for better performance.
## Give Feedback
You can give feedback on a memory by calling the `feedback` method on the Mem0 client.
<CodeGroup>
```python Python
from mem0 import MemoryClient
client = MemoryClient(api_key="your_api_key")
client.feedback(memory_id="your-memory-id", feedback="NEGATIVE", feedback_reason="I don't like this memory because it is not relevant.")
```
```javascript JavaScript
import MemoryClient from 'mem0ai';
const client = new MemoryClient({ apiKey: 'your-api-key'});
client.feedback({
memory_id: "your-memory-id",
feedback: "NEGATIVE",
feedback_reason: "I don't like this memory because it is not relevant."
})
```
</CodeGroup>
## Feedback Types
The `feedback` parameter can be one of the following values:
- `POSITIVE`: The memory is useful.
- `NEGATIVE`: The memory is not useful.
- `VERY_NEGATIVE`: The memory is not useful at all.
## Parameters
The `feedback` method takes the following parameters:
- `memory_id`: The ID of the memory to give feedback on.
- `feedback`: The feedback to give on the memory. (Optional)
- `feedback_reason`: The reason for the feedback. (Optional)
The `feedback_reason` parameter is optional and can be used to provide a reason for the feedback.
<Note>
You can pass `None` or `null` to the `feedback` and `feedback_reason` parameters to remove the feedback for a memory.
</Note>
+295
View File
@@ -0,0 +1,295 @@
---
title: Graph Memory
icon: "circle-nodes"
iconType: "solid"
description: "Enable graph-based memory retrieval for more contextually relevant results"
---
## Overview
Graph Memory enhances memory pipeline by creating relationships between entities in your data. It builds a network of interconnected information for more contextually relevant search results.
This feature allows your AI applications to understand connections between entities, providing richer context for responses. It's ideal for applications needing relationship tracking and nuanced information retrieval across related memories.
## How Graph Memory Works
The Graph Memory feature analyzes how each entity connects and relates to each other. When enabled:
1. Mem0 automatically builds a graph representation of entities
2. Retrieval considers graph relationships between entities
3. Results include entities that may be contextually important even if they're not direct semantic matches
## Using Graph Memory
To use Graph Memory, you need to enable it in your API calls by setting the `enable_graph=True` parameter. You'll also need to specify `output_format="v1.1"` to receive the enriched response format.
### Adding Memories with Graph Memory
When adding new memories, enable Graph Memory to automatically build relationships with existing memories:
<CodeGroup>
```python Python
from mem0 import MemoryClient
client = MemoryClient(
api_key="your-api-key",
org_id="your-org-id",
project_id="your-project-id"
)
messages = [
{"role": "user", "content": "My name is Joseph"},
{"role": "assistant", "content": "Hello Joseph, it's nice to meet you!"},
{"role": "user", "content": "I'm from Seattle and I work as a software engineer"}
]
# Enable graph memory when adding
client.add(
messages,
user_id="joseph",
version="v1",
enable_graph=True,
output_format="v1.1"
)
```
```javascript JavaScript
import { MemoryClient } from "mem0";
const client = new MemoryClient({
apiKey: "your-api-key",
orgId: "your-org-id",
projectId: "your-project-id"
});
const messages = [
{ role: "user", content: "My name is Joseph" },
{ role: "assistant", content: "Hello Joseph, it's nice to meet you!" },
{ role: "user", content: "I'm from Seattle and I work as a software engineer" }
];
// Enable graph memory when adding
await client.add({
messages,
userId: "joseph",
version: "v1",
enableGraph: true,
outputFormat: "v1.1"
});
```
```json Output
{
"results": [
{
"memory": "Name is Joseph",
"event": "ADD",
"id": "4a5a417a-fa10-43b5-8c53-a77c45e80438"
},
{
"memory": "Is from Seattle",
"event": "ADD",
"id": "8d268d0f-5452-4714-b27d-ae46f676a49d"
},
{
"memory": "Is a software engineer",
"event": "ADD",
"id": "5f0a184e-ddea-4fe6-9b92-692d6a901df8"
}
]
}
```
</CodeGroup>
The graph memory would look like this:
<Frame>
<img src="/images/graph-platform.png" alt="Graph Memory Visualization showing relationships between entities" />
</Frame>
<Caption>Graph Memory creates a network of relationships between entities, enabling more contextual retrieval</Caption>
<Note>
Response for the graph memory's `add` operation will not be available directly in the response.
As adding graph memories is an asynchronous operation due to heavy processing,
you can use the `get_all()` endpoint to retrieve the memory with the graph metadata.
</Note>
### Searching with Graph Memory
When searching memories, Graph Memory helps retrieve entities that are contextually important even if they're not direct semantic matches.
<CodeGroup>
```python Python
# Search with graph memory enabled
results = client.search(
"what is my name?",
user_id="joseph",
enable_graph=True,
output_format="v1.1"
)
print(results)
```
```javascript JavaScript
// Search with graph memory enabled
const results = await client.search({
query: "what is my name?",
userId: "joseph",
enableGraph: true,
outputFormat: "v1.1"
});
console.log(results);
```
```json Output
{
"results": [
{
"id": "4a5a417a-fa10-43b5-8c53-a77c45e80438",
"memory": "Name is Joseph",
"user_id": "joseph",
"metadata": null,
"categories": ["personal_details"],
"immutable": false,
"created_at": "2025-03-19T09:09:00.146390-07:00",
"updated_at": "2025-03-19T09:09:00.146404-07:00",
"score": 0.3621795393335552
},
{
"id": "8d268d0f-5452-4714-b27d-ae46f676a49d",
"memory": "Is from Seattle",
"user_id": "joseph",
"metadata": null,
"categories": ["personal_details"],
"immutable": false,
"created_at": "2025-03-19T09:09:00.170680-07:00",
"updated_at": "2025-03-19T09:09:00.170692-07:00",
"score": 0.31212713194651254
}
],
"relations": [
{
"source": "joseph",
"source_type": "person",
"relationship": "name",
"target": "joseph",
"target_type": "person",
"score": 0.39
}
]
}
```
</CodeGroup>
### Retrieving All Memories with Graph Memory
When retrieving all memories, Graph Memory provides additional relationship context:
<CodeGroup>
```python Python
# Get all memories with graph context
memories = client.get_all(
user_id="joseph",
enable_graph=True,
output_format="v1.1"
)
print(memories)
```
```javascript JavaScript
// Get all memories with graph context
const memories = await client.getAll({
userId: "joseph",
enableGraph: true,
outputFormat: "v1.1"
});
console.log(memories);
```
```json Output
{
"results": [
{
"id": "5f0a184e-ddea-4fe6-9b92-692d6a901df8",
"memory": "Is a software engineer",
"user_id": "joseph",
"metadata": null,
"categories": ["professional_details"],
"immutable": false,
"created_at": "2025-03-19T09:09:00.194116-07:00",
"updated_at": "2025-03-19T09:09:00.194128-07:00",
},
{
"id": "8d268d0f-5452-4714-b27d-ae46f676a49d",
"memory": "Is from Seattle",
"user_id": "joseph",
"metadata": null,
"categories": ["personal_details"],
"immutable": false,
"created_at": "2025-03-19T09:09:00.170680-07:00",
"updated_at": "2025-03-19T09:09:00.170692-07:00",
},
{
"id": "4a5a417a-fa10-43b5-8c53-a77c45e80438",
"memory": "Name is Joseph",
"user_id": "joseph",
"metadata": null,
"categories": ["personal_details"],
"immutable": false,
"created_at": "2025-03-19T09:09:00.146390-07:00",
"updated_at": "2025-03-19T09:09:00.146404-07:00",
}
],
"relations": [
{
"source": "joseph",
"source_type": "person",
"relationship": "name",
"target": "joseph",
"target_type": "person"
},
{
"source": "joseph",
"source_type": "person",
"relationship": "city",
"target": "seattle",
"target_type": "city"
},
{
"source": "joseph",
"source_type": "person",
"relationship": "job",
"target": "software engineer",
"target_type": "job"
}
]
}
```
</CodeGroup>
## Best Practices
- Enable Graph Memory for applications where understanding context and relationships between memories is important
- Graph Memory works best with a rich history of related conversations
- Consider Graph Memory for long-running assistants that need to track evolving information
## Performance Considerations
Graph Memory requires additional processing and may increase response times slightly for very large memory stores. However, for most use cases, the improved retrieval quality outweighs the minimal performance impact.
If you have any questions, please feel free to reach out to us using one of the following methods:
<Snippet file="get-help.mdx" />
+40 -4
View File
@@ -71,13 +71,39 @@ Here's an example schema for extracting professional profile information:
### Submit Export Job
You can optionally provide additional instructions to guide how memories are processed and structured during export using the `export_instructions` parameter.
<CodeGroup>
```python Python
# Basic export request
response = client.create_memory_export(
schema=json_schema,
user_id="user123"
user_id="alice"
)
# Export with custom instructions
export_instructions = """
1. Create a comprehensive profile with detailed information in each category
2. Only mark fields as "None" when absolutely no relevant information exists
3. Base all information directly on the user's memories
4. When contradictions exist, prioritize the most recent information
5. Clearly distinguish between factual statements and inferences
"""
# For create operation, using only user_id filter as requested
filters = {
"AND": [
{"user_id": "alex"}
]
}
response = client.create_memory_export(
schema=json_schema,
filters=filters,
export_instructions=export_instructions # Optional
)
print(response)
```
@@ -87,7 +113,8 @@ curl -X POST "https://api.mem0.ai/v1/memories/export/" \
-H "Content-Type: application/json" \
-d '{
"schema": {json_schema},
"user_id": "user123"
"user_id": "alice",
"export_instructions": "1. Create a comprehensive profile with detailed information\n2. Only mark fields as \"None\" when absolutely no relevant information exists"
}'
```
@@ -107,12 +134,20 @@ Once the export job is complete, you can retrieve the structured data:
<CodeGroup>
```python Python
response = client.get_memory_export(user_id="user123")
# Corrected date range (assuming you meant July 10 to July 20)
filters = {
"AND": [
{"created_at": {"gte": "2024-07-10", "lte": "2024-07-20"}},
{"user_id": "alex"}
]
}
response = client.get_memory_export(filters=filters)
print(response)
```
```bash cURL
curl -X GET "https://api.mem0.ai/v1/memories/export/?user_id=user123" \
curl -X GET "https://api.mem0.ai/v1/memories/export/?user_id=alice" \
-H "Authorization: Token your-api-key"
```
@@ -137,6 +172,7 @@ You can apply various filters to customize which memories are included in the ex
- `agent_id`: Filter memories by specific agent
- `run_id`: Filter memories by specific run
- `session_id`: Filter memories by specific session
- `created_at`: Filter memories by date
<Note>
The export process may take some time to complete, especially when dealing with a large number of memories or complex schemas.
+142 -8
View File
@@ -1,15 +1,15 @@
---
title: Multimodal Support
description: Integrate images into your interactions with Mem0
description: Integrate images and documents into your interactions with Mem0
icon: "image"
iconType: "solid"
---
Mem0 extends its capabilities beyond text by supporting multimodal data, including images. With this feature, users can seamlessly integrate images into their interactions—allowing Mem0 to extract relevant information from visual content and enrich the memory system.
Mem0 extends its capabilities beyond text by supporting multimodal data, including images and documents. With this feature, users can seamlessly integrate visual and document content into their interactions—allowing Mem0 to extract relevant information from various media types and enrich the memory system.
## How It Works
When a user submits an image, Mem0 processes it to extract textual information and other pertinent details. These details are then added to the user's memory, enhancing the system's ability to understand and recall visual inputs.
When a user submits an image or document, Mem0 processes it to extract textual information and other pertinent details. These details are then added to the user's memory, enhancing the system's ability to understand and recall multimodal inputs.
<CodeGroup>
```python Python
@@ -90,11 +90,18 @@ await client.add(messages, { user_id: "alice" })
```
</CodeGroup>
## Image Integration Methods
## Supported Media Types
Mem0 supports incorporating images into user interactions using two primary methods: by providing an image URL or by using a Base64-encoded image. The examples below demonstrate both approaches.
Mem0 currently supports the following media types:
## 1. Using an Image URL (Recommended)
1. **Images** - JPG, PNG, and other common image formats
2. **Documents** - MDX, TXT, and PDF files
## Integration Methods
### 1. Images
#### Using an Image URL (Recommended)
You can include an image by providing its direct URL. This method is simple and efficient for online images.
@@ -115,7 +122,7 @@ image_message = {
client.add([image_message], user_id="alice")
```
## 2. Using Base64 Image Encoding for Local Files
#### Using Base64 Image Encoding for Local Files
For local images—or when embedding the image directly is preferable—you can use a Base64-encoded string.
@@ -164,7 +171,134 @@ const imageMessage = {
await client.add([imageMessage], { user_id: "alice" })
```
</CodeGroup>
Using these methods, you can seamlessly incorporate images into your interactions, further enhancing Mem0's multimodal capabilities.
### 2. Text Documents (MDX/TXT)
Mem0 supports both online and local text documents in MDX or TXT format.
#### Using a Document URL
```python
# Define the document URL
document_url = "https://www.w3.org/TR/2003/REC-PNG-20031110/iso_8859-1.txt"
# Create the message dictionary with the document URL
document_message = {
"role": "user",
"content": {
"type": "mdx_url",
"mdx_url": {
"url": document_url
}
}
}
client.add([document_message], user_id="alice")
```
#### Using Base64 Encoding for Local Documents
```python
import base64
# Path to the document file
document_path = "path/to/your/document.txt"
# Function to convert file to Base64
def file_to_base64(file_path):
with open(file_path, "rb") as file:
return base64.b64encode(file.read()).decode('utf-8')
# Encode the document in Base64
base64_document = file_to_base64(document_path)
# Create the message dictionary with the Base64-encoded document
document_message = {
"role": "user",
"content": {
"type": "mdx_url",
"mdx_url": {
"url": base64_document
}
}
}
client.add([document_message], user_id="alice")
```
### 3. PDF Documents
Mem0 supports PDF documents via URL.
```python
# Define the PDF URL
pdf_url = "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
# Create the message dictionary with the PDF URL
pdf_message = {
"role": "user",
"content": {
"type": "pdf_url",
"pdf_url": {
"url": pdf_url
}
}
}
client.add([pdf_message], user_id="alice")
```
## Complete Example with Multiple File Types
Here's a comprehensive example showing how to work with different file types:
```python
import base64
from mem0 import MemoryClient
client = MemoryClient()
def file_to_base64(file_path):
with open(file_path, "rb") as file:
return base64.b64encode(file.read()).decode('utf-8')
# Example 1: Using an image URL
image_message = {
"role": "user",
"content": {
"type": "image_url",
"image_url": {
"url": "https://example.com/sample-image.jpg"
}
}
}
# Example 2: Using a text document URL
text_message = {
"role": "user",
"content": {
"type": "mdx_url",
"mdx_url": {
"url": "https://www.w3.org/TR/2003/REC-PNG-20031110/iso_8859-1.txt"
}
}
}
# Example 3: Using a PDF URL
pdf_message = {
"role": "user",
"content": {
"type": "pdf_url",
"pdf_url": {
"url": "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf"
}
}
}
# Add each message to the memory system
client.add([image_message], user_id="alice")
client.add([text_message], user_id="alice")
client.add([pdf_message], user_id="alice")
```
Using these methods, you can seamlessly incorporate various media types into your interactions, further enhancing Mem0's multimodal capabilities.
If you have any questions, please feel free to reach out to us using one of the following methods:
+6
View File
@@ -12,6 +12,9 @@ Learn about the key features and capabilities that make Mem0 a powerful platform
<Card title="Advanced Retrieval" icon="magnifying-glass" href="/features/advanced-retrieval">
Superior search results using state-of-the-art algorithms, including keyword search, reranking, and filtering capabilities.
</Card>
<Card title="Contextual Add" icon="square-plus" href="/features/contextual-add">
Only send your latest conversation history - we automatically retrieve the rest and generate properly contextualized memories.
</Card>
<Card title="Multimodal Support" icon="photo-film" href="/features/multimodal-support">
Process and analyze various types of content including images.
</Card>
@@ -33,6 +36,9 @@ Learn about the key features and capabilities that make Mem0 a powerful platform
<Card title="Memory Export" icon="file-export" href="/features/memory-export">
Export memories in structured formats using customizable Pydantic schemas.
</Card>
<Card title="Graph Memory" icon="graph" href="/features/graph-memory">
Add memories in the form of nodes and edges in a graph database and search for related memories.
</Card>
</CardGroup>
## Getting Help
Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

+173
View File
@@ -0,0 +1,173 @@
---
title: Agno
---
Integrate [**Mem0**](https://github.com/mem0ai/mem0) with [Agno](https://github.com/agno-ai/agno), a Python framework for building autonomous agents. This integration enables Agno agents to access persistent memory across conversations, enhancing context retention and personalization.
## Overview
1. 🧠 Store and retrieve memories from Mem0 within Agno agents
2. 🖼️ Support for multimodal interactions (text and images)
3. 🔍 Semantic search for relevant past conversations
4. 🌐 Personalized responses based on user history
## Prerequisites
Before setting up Mem0 with Agno, ensure you have:
1. Installed the required packages:
```bash
pip install agno-ai mem0ai
```
2. Valid API keys:
- [Mem0 API Key](https://app.mem0.ai/dashboard/api-keys)
- OpenAI API Key (for the agent model)
## Integration Example
The following example demonstrates how to create an Agno agent with Mem0 memory integration, including support for image processing:
```python
import base64
from pathlib import Path
from typing import Optional
from agno.agent import Agent
from agno.media import Image
from agno.models.openai import OpenAIChat
from mem0 import MemoryClient
# Initialize the Mem0 client
client = MemoryClient()
# Define the agent
agent = Agent(
name="Personal Agent",
model=OpenAIChat(id="gpt-4"),
description="You are a helpful personal agent that helps me with day to day activities."
"You can process both text and images.",
markdown=True
)
def chat_user(
user_input: Optional[str] = None,
user_id: str = "user_123",
image_path: Optional[str] = None
) -> str:
"""
Handle user input with memory integration, supporting both text and images.
Args:
user_input: The user's text input
user_id: Unique identifier for the user
image_path: Path to an image file if provided
Returns:
The agent's response as a string
"""
if image_path:
# Convert image to base64
with open(image_path, "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode("utf-8")
# Create message objects for text and image
messages = []
if user_input:
messages.append({
"role": "user",
"content": user_input
})
messages.append({
"role": "user",
"content": {
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
})
# Store messages in memory
client.add(messages, user_id=user_id)
print("✅ Image and text stored in memory.")
if user_input:
# Search for relevant memories
memories = client.search(user_input, user_id=user_id)
memory_context = "\n".join(f"- {m['memory']}" for m in memories)
# Construct the prompt
prompt = f"""
You are a helpful personal assistant who helps users with their day-to-day activities and keeps track of everything.
Your task is to:
1. Analyze the given image (if present) and extract meaningful details to answer the user's question.
2. Use your past memory of the user to personalize your answer.
3. Combine the image content and memory to generate a helpful, context-aware response.
Here is what I remember about the user:
{memory_context}
User question:
{user_input}
"""
# Get response from agent
if image_path:
response = agent.run(prompt, images=[Image(filepath=Path(image_path))])
else:
response = agent.run(prompt)
# Store the interaction in memory
client.add(f"User: {user_input}\nAssistant: {response.content}", user_id=user_id)
return response.content
return "No user input or image provided."
# Example Usage
if __name__ == "__main__":
response = chat_user(
"This is the picture of what I brought with me in the trip to Bahamas",
image_path="travel_items.jpeg",
user_id="user_123"
)
print(response)
```
## Key Features
### 1. Multimodal Memory Storage
The integration supports storing both text and image data:
- **Text Storage**: Conversation history is saved in a structured format
- **Image Analysis**: Agents can analyze images and store visual information
- **Combined Context**: Memory retrieval combines both text and visual data
### 2. Personalized Agent Responses
Improve your agent's context awareness:
- **Memory Retrieval**: Semantic search finds relevant past interactions
- **User Preferences**: Personalize responses based on stored user information
- **Continuity**: Maintain conversation threads across multiple sessions
### 3. Flexible Configuration
Customize the integration to your needs:
- **User Identification**: Organize memories by user ID
- **Memory Search**: Configure search relevance and result count
- **Memory Formatting**: Support for various OpenAI message formats
## Help & Resources
- [Agno Documentation](https://docs.agno.com/introduction)
- [Mem0 Platform](https://app.mem0.ai/)
<Snippet file="get-help.mdx" />
+454
View File
@@ -0,0 +1,454 @@
---
title: ElevenLabs
---
Create voice-based conversational AI agents with memory capabilities by integrating ElevenLabs and Mem0. This integration enables persistent, context-aware voice interactions that remember past conversations.
## Overview
In this guide, we'll build a voice agent that:
1. Uses ElevenLabs Conversational AI for voice interaction
2. Leverages Mem0 to store and retrieve memories from past conversations
3. Provides personalized responses based on user history
## Setup and Configuration
Install necessary libraries:
```bash
pip install elevenlabs mem0 python-dotenv
```
Configure your environment variables:
<Note>You'll need both an ElevenLabs API key and a Mem0 API key to use this integration.</Note>
```bash
# Create a .env file with these variables
AGENT_ID=your-agent-id
USER_ID=unique-user-identifier
ELEVENLABS_API_KEY=your-elevenlabs-api-key
MEM0_API_KEY=your-mem0-api-key
```
## Integration Code Breakdown
Let's break down the implementation into manageable parts:
### 1. Imports and Environment Setup
First, we import required libraries and set up the environment:
```python
import os
import signal
import sys
from mem0 import AsyncMemoryClient
from elevenlabs.client import ElevenLabs
from elevenlabs.conversational_ai.conversation import Conversation
from elevenlabs.conversational_ai.default_audio_interface import DefaultAudioInterface
from elevenlabs.conversational_ai.conversation import ClientTools
```
These imports provide:
- Standard Python libraries for system operations and signal handling
- `AsyncMemoryClient` from Mem0 for memory operations
- ElevenLabs components for voice interaction
### 2. Environment Variables and Validation
Next, we validate the required environment variables:
```python
def main():
# Required environment variables
AGENT_ID = os.environ.get('AGENT_ID')
USER_ID = os.environ.get('USER_ID')
API_KEY = os.environ.get('ELEVENLABS_API_KEY')
MEM0_API_KEY = os.environ.get('MEM0_API_KEY')
# Validate required environment variables
if not AGENT_ID:
sys.stderr.write("AGENT_ID environment variable must be set\n")
sys.exit(1)
if not USER_ID:
sys.stderr.write("USER_ID environment variable must be set\n")
sys.exit(1)
if not API_KEY:
sys.stderr.write("ELEVENLABS_API_KEY not set, assuming the agent is public\n")
if not MEM0_API_KEY:
sys.stderr.write("MEM0_API_KEY environment variable must be set\n")
sys.exit(1)
# Set up Mem0 API key in the environment
os.environ['MEM0_API_KEY'] = MEM0_API_KEY
```
This section:
- Retrieves required environment variables
- Performs validation to ensure required variables are present
- Exits the application with an error message if required variables are missing
- Sets the Mem0 API key in the environment for the Mem0 client to use
### 3. Client Initialization
Initialize both the ElevenLabs and Mem0 clients:
```python
# Initialize ElevenLabs client
client = ElevenLabs(api_key=API_KEY)
# Initialize memory client and tools
client_tools = ClientTools()
mem0_client = AsyncMemoryClient()
```
Here we:
- Create an ElevenLabs client with the API key
- Initialize a ClientTools object for registering function tools
- Create an AsyncMemoryClient instance for Mem0 interactions
### 4. Memory Function Definitions
Define the two key memory functions that will be registered as tools:
```python
# Define memory-related functions for the agent
async def add_memories(parameters):
"""Add a message to the memory store"""
message = parameters.get("message")
await mem0_client.add(
messages=message,
user_id=USER_ID,
output_format="v1.1",
version="v2"
)
return "Memory added successfully"
async def retrieve_memories(parameters):
"""Retrieve relevant memories based on the input message"""
message = parameters.get("message")
# Set up filters to retrieve memories for this specific user
filters = {
"AND": [
{
"user_id": USER_ID
}
]
}
# Search for relevant memories using the message as a query
results = await mem0_client.search(
query=message,
version="v2",
filters=filters
)
# Extract and join the memory texts
memories = ' '.join([result["memory"] for result in results])
print("[ Memories ]", memories)
if memories:
return memories
return "No memories found"
```
These functions:
#### `add_memories`:
- Takes a message parameter containing information to remember
- Stores the message in Mem0 using the `add` method
- Associates the memory with the specific USER_ID
- Returns a success message to the agent
#### `retrieve_memories`:
- Takes a message parameter as the search query
- Sets up filters to only retrieve memories for the current user
- Uses semantic search to find relevant memories
- Joins all retrieved memories into a single text
- Prints retrieved memories to the console for debugging
- Returns the memories or a "No memories found" message if none are found
### 5. Registering Memory Functions as Tools
Register the memory functions with the ElevenLabs ClientTools system:
```python
# Register the memory functions as tools for the agent
client_tools.register("addMemories", add_memories, is_async=True)
client_tools.register("retrieveMemories", retrieve_memories, is_async=True)
```
This allows the ElevenLabs agent to:
- Access these functions through function calling
- Wait for asynchronous results (is_async=True)
- Call these functions by name ("addMemories" and "retrieveMemories")
### 6. Conversation Setup
Configure the conversation with ElevenLabs:
```python
# Initialize the conversation
conversation = Conversation(
client,
AGENT_ID,
# Assume auth is required when API_KEY is set
requires_auth=bool(API_KEY),
audio_interface=DefaultAudioInterface(),
client_tools=client_tools,
callback_agent_response=lambda response: print(f"Agent: {response}"),
callback_agent_response_correction=lambda original, corrected: print(f"Agent: {original} -> {corrected}"),
callback_user_transcript=lambda transcript: print(f"User: {transcript}"),
# callback_latency_measurement=lambda latency: print(f"Latency: {latency}ms"),
)
```
This sets up the conversation with:
- The ElevenLabs client and Agent ID
- Authentication requirements based on API key presence
- DefaultAudioInterface for handling audio I/O
- The client_tools with our memory functions
- Callback functions for:
- Displaying agent responses
- Showing corrected responses (when the agent self-corrects)
- Displaying user transcripts for debugging
- (Commented out) Latency measurements
### 7. Conversation Management
Start and manage the conversation:
```python
# Start the conversation
print(f"Starting conversation with user_id: {USER_ID}")
conversation.start_session()
# Handle Ctrl+C to gracefully end the session
signal.signal(signal.SIGINT, lambda sig, frame: conversation.end_session())
# Wait for the conversation to end and get the conversation ID
conversation_id = conversation.wait_for_session_end()
print(f"Conversation ID: {conversation_id}")
if __name__ == '__main__':
main()
```
This final section:
- Prints a message indicating the conversation has started
- Starts the conversation session
- Sets up a signal handler to gracefully end the session on Ctrl+C
- Waits for the session to end and gets the conversation ID
- Prints the conversation ID for reference
## Memory Tools Overview
This integration provides two key memory functions to your conversational AI agent:
### 1. Adding Memories (`addMemories`)
The `addMemories` tool allows your agent to store important information during a conversation, including:
- User preferences
- Important facts shared by the user
- Decisions or commitments made during the conversation
- Action items to follow up on
When the agent identifies information worth remembering, it calls this function to store it in the Mem0 database with the appropriate user ID.
#### How it works:
1. The agent identifies information that should be remembered
2. It formats the information as a message string
3. It calls the `addMemories` function with this message
4. The function stores the memory in Mem0 linked to the user's ID
5. Later conversations can retrieve this memory
#### Example usage in agent prompt:
```
When the user shares important information like preferences or personal details,
use the addMemories function to store this information for future reference.
```
### 2. Retrieving Memories (`retrieveMemories`)
The `retrieveMemories` tool allows your agent to search for and retrieve relevant memories from previous conversations. The agent can:
- Search for context related to the current topic
- Recall user preferences
- Remember previous interactions on similar topics
- Create continuity across multiple sessions
#### How it works:
1. The agent needs context for the current conversation
2. It calls `retrieveMemories` with the current conversation topic or question
3. The function performs a semantic search in Mem0
4. Relevant memories are returned to the agent
5. The agent incorporates these memories into its response
#### Example usage in agent prompt:
```
At the beginning of each conversation turn, use retrieveMemories to check if we've
discussed this topic before or if the user has shared relevant preferences.
```
## Configuring Your ElevenLabs Agent
To enable your agent to effectively use memory:
1. Add function calling capabilities to your agent in the ElevenLabs platform:
- Go to your agent settings in the ElevenLabs platform
- Navigate to the "Tools" section
- Enable function calling for your agent
- Add the memory tools as described below
2. Add the `addMemories` and `retrieveMemories` tools to your agent with these specifications:
For `addMemories`:
```json
{
"name": "addMemories",
"description": "Stores important information from the conversation to remember for future interactions",
"parameters": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The important information to remember"
}
},
"required": ["message"]
}
}
```
For `retrieveMemories`:
```json
{
"name": "retrieveMemories",
"description": "Retrieves relevant information from past conversations",
"parameters": {
"type": "object",
"properties": {
"message": {
"type": "string",
"description": "The query to search for in past memories"
}
},
"required": ["message"]
}
}
```
3. Update your agent's prompt to instruct it to use these memory functions. For example:
```
You are a helpful voice assistant that remembers past conversations with the user.
You have access to memory tools that allow you to remember important information:
- Use retrieveMemories at the beginning of the conversation to recall relevant context from prior conversations
- Use addMemories to store new important information such as:
* User preferences
* Personal details the user shares
* Important decisions made
* Tasks or follow-ups promised to the user
Before responding to complex questions, always check for relevant memories first.
When the user shares important information, make sure to store it for future reference.
```
## Example Conversation Flow
Here's how a typical conversation with memory might flow:
1. **User speaks**: "Hi, do you remember my favorite color?"
2. **Agent retrieves memories**:
```python
# Agent calls retrieve_memories
memories = retrieve_memories({"message": "user's favorite color"})
# If found: "The user's favorite color is blue"
```
3. **Agent processes with context**:
- If memories found: Prepares a personalized response
- If no memories: Prepares to ask and store the information
4. **Agent responds**:
- With memory: "Yes, your favorite color is blue!"
- Without memory: "I don't think you've told me your favorite color before. What is it?"
5. **User responds**: "It's actually green."
6. **Agent stores new information**:
```python
# Agent calls add_memories
add_memories({"message": "The user's favorite color is green"})
```
7. **Agent confirms**: "Thanks, I'll remember that your favorite color is green."
## Example Use Cases
- **Personal Assistant** - Remember user preferences, past requests, and important dates
```
User: "What restaurants did I say I liked last time?"
Agent: *retrieves memories* "You mentioned enjoying Bella Italia and The Golden Dragon."
```
- **Customer Support** - Recall previous issues a customer has had
```
User: "I'm having that same problem again!"
Agent: *retrieves memories* "Is this related to the login issue you reported last week?"
```
- **Educational AI** - Track student progress and tailor teaching accordingly
```
User: "Let's continue our math lesson."
Agent: *retrieves memories* "Last time we were working on quadratic equations. Would you like to continue with that?"
```
- **Healthcare Assistant** - Remember symptoms, medications, and health concerns
```
User: "Have I told you about my allergy medication?"
Agent: *retrieves memories* "Yes, you mentioned you're taking Claritin for your pollen allergies."
```
## Troubleshooting
- **Missing API Keys**:
- Error: "API_KEY environment variable must be set"
- Solution: Ensure all environment variables are set correctly in your .env file or system environment
- **Connection Issues**:
- Error: "Failed to connect to API"
- Solution: Check your network connection and API key permissions. Verify the API keys are valid and have the necessary permissions.
- **Empty Memory Results**:
- Symptom: Agent always responds with "No memories found"
- Solution: This is normal for new users. The memory database builds up over time as conversations occur. It's also possible your query isn't semantically similar to stored memories - try different phrasing.
- **Agent Not Using Memories**:
- Symptom: The agent retrieves memories but doesn't incorporate them in responses
- Solution: Update the agent's prompt to explicitly instruct it to use the retrieved memories in its responses
## Conclusion
By integrating ElevenLabs Conversational AI with Mem0, you can create voice agents that maintain context across conversations and provide personalized responses based on user history. This powerful combination enables:
- More natural, context-aware conversations
- Personalized user experiences that improve over time
- Reduced need for users to repeat information
- Long-term relationship building between users and AI agents
## Help
- For more details on ElevenLabs, visit the [ElevenLabs Conversational AI Documentation](https://elevenlabs.io/docs/api-reference/conversational-ai)
- For Mem0 documentation, refer to the [Mem0 Platform](https://app.mem0.ai/)
- If you need further assistance, please feel free to reach out to us through the following methods:
<Snippet file="get-help.mdx" />
+126
View File
@@ -0,0 +1,126 @@
---
title: Flowise
---
The [**Mem0 Memory**](https://github.com/mem0ai/mem0) integration with [Flowise](https://github.com/FlowiseAI/Flowise) enables persistent memory capabilities for your AI chatflows. [Flowise](https://flowiseai.com/) is an open-source low-code tool for developers to build customized LLM orchestration flows & AI agents using a drag & drop interface.
## Overview
1. 🧠 Provides persistent memory storage for Flowise chatflows
2. 🔄 Seamless integration with existing Flowise templates
3. 🚀 Compatible with various LLM nodes in Flowise
4. 📝 Supports custom memory configurations
5. ⚡ Easy to set up and manage
## Prerequisites
Before setting up Mem0 with Flowise, ensure you have:
1. [Flowise installed](https://github.com/FlowiseAI/Flowise#⚡quick-start) (NodeJS >= 18.15.0 required):
```bash
npm install -g flowise
npx flowise start
```
2. Access to the Flowise UI at http://localhost:3000
3. Basic familiarity with [Flowise's LLM orchestration](https://flowiseai.com/#features) concepts
## Setup and Configuration
### 1. Set Up Flowise
1. Open the Flowise application and create a new canvas, or select a template from the Flowise marketplace.
2. In this example, we use the **Conversation Chain** template.
3. Replace the default **Buffer Memory** with **Mem0 Memory**.
![Flowise Memory Integration](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-flow.png)
### 2. Obtain Your Mem0 API Key
1. Navigate to the [Mem0 API Key dashboard](https://app.mem0.ai/dashboard/api-keys).
2. Generate or copy your existing Mem0 API Key.
![Mem0 API Key](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/api-key.png)
### 3. Configure Mem0 Credentials
1. Enter the **Mem0 API Key** in the Mem0 Credentials section.
2. Configure additional settings as needed:
```typescript
{
"apiKey": "m0-xxx",
"userId": "user-123", // Optional: Specify user ID
"projectId": "proj-xxx", // Optional: Specify project ID
"orgId": "org-xxx" // Optional: Specify organization ID
}
```
<figure>
<img src="https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/creds.png" alt="Mem0 Credentials" />
<figcaption>Configure API Credentials</figcaption>
</figure>
## Memory Features
### 1. Basic Memory Storage
Test your memory configuration:
1. Save your Flowise configuration
2. Run a test chat and store some information
3. Verify the stored memories in the [Mem0 Dashboard](https://app.mem0.ai/dashboard/requests)
![Flowise Test Chat](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-chat-1.png)
### 2. Memory Retention
Validate memory persistence:
1. Clear the chat history in Flowise
2. Ask a question about previously stored information
3. Confirm that the AI remembers the context
![Testing Memory Retention](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/flowise-chat-2.png)
## Advanced Configuration
### Memory Settings
![Mem0 Settings](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/settings.png)
Available settings include:
1. **Search Only Mode**: Enable memory retrieval without creating new memories
2. **Mem0 Entities**: Configure identifiers:
- `user_id`: Unique identifier for each user
- `run_id`: Specific conversation session ID
- `app_id`: Application identifier
- `agent_id`: AI agent identifier
3. **Project ID**: Assign memories to specific projects
4. **Organization ID**: Organize memories by organization
### Platform Configuration
Additional settings available in [Mem0 Project Settings](https://app.mem0.ai/dashboard/project-settings):
1. **Custom Instructions**: Define memory extraction rules
2. **Expiration Date**: Set automatic memory cleanup periods
![Mem0 Project Settings](https://raw.githubusercontent.com/FlowiseAI/FlowiseDocs/main/en/.gitbook/assets/mem0/mem0-settings.png)
## Best Practices
1. **User Identification**: Use consistent `user_id` values for reliable memory retrieval
2. **Memory Organization**: Utilize projects and organizations for better memory management
3. **Regular Maintenance**: Monitor and clean up unused memories periodically
## Help & Resources
- [Flowise Documentation](https://flowiseai.com/docs)
- [Flowise GitHub Repository](https://github.com/FlowiseAI/Flowise)
- [Flowise Website](https://flowiseai.com/)
- [Mem0 Platform](https://app.mem0.ai/)
- Need assistance? Reach out through:
<Snippet file="get-help.mdx" />
+7 -7
View File
@@ -95,7 +95,7 @@ add_input = {
{"role": "user", "content": "Hi, I'm Alex. I'm a vegetarian and I'm allergic to nuts."},
{"role": "assistant", "content": "Hello Alex! I've noted that you're a vegetarian and have a nut allergy."}
],
"user_id": "alex123",
"user_id": "alex",
"output_format": "v1.1",
"metadata": {"food": "vegan"}
}
@@ -173,7 +173,7 @@ search_input = {
"filters": {
"AND": [
{"created_at": {"gte": "2024-07-20", "lte": "2024-12-10"}},
{"user_id": "alex123"}
{"user_id": "alex"}
]
},
"version": "v2"
@@ -186,7 +186,7 @@ result = search_tool.invoke(search_input)
{
"id": "1a75e827-7eca-45ea-8c5c-cfd43299f061",
"memory": "Name is Alex",
"user_id": "alex123",
"user_id": "alex",
"hash": "d0fccc8fa47f7a149ee95750c37bb0ca",
"metadata": {
"food": "vegan"
@@ -255,7 +255,7 @@ get_all_input = {
"version": "v2",
"filters": {
"AND": [
{"user_id": "alex123"},
{"user_id": "alex"},
{"created_at": {"gte": "2024-07-01", "lte": "2024-12-31"}}
]
},
@@ -274,7 +274,7 @@ get_all_result = get_all_tool.invoke(get_all_input)
{
"id": "1a75e827-7eca-45ea-8c5c-cfd43299f061",
"memory": "Name is Alex",
"user_id": "alex123",
"user_id": "alex",
"hash": "d0fccc8fa47f7a149ee95750c37bb0ca",
"metadata": {
"food": "vegan"
@@ -288,7 +288,7 @@ get_all_result = get_all_tool.invoke(get_all_input)
{
"id": "91509588-0b39-408a-8df3-84b3bce8c521",
"memory": "Is a vegetarian",
"user_id": "alex123",
"user_id": "alex",
"hash": "ce6b1c84586772ab9995a9477032df99",
"metadata": {
"food": "vegan"
@@ -303,7 +303,7 @@ get_all_result = get_all_tool.invoke(get_all_input)
{
"id": "8d74f7a0-6107-4589-bd6f-210f6bf4fbbb",
"memory": "Is allergic to nuts",
"user_id": "alex123",
"user_id": "alex",
"hash": "7873cd0e5a29c513253d9fad038e758b",
"metadata": {
"food": "vegan"
+353
View File
@@ -0,0 +1,353 @@
---
title: Livekit
---
This guide demonstrates how to create a memory-enabled voice assistant using LiveKit, Deepgram, OpenAI, and Mem0, focusing on creating an intelligent, context-aware travel planning agent.
## Prerequisites
Before you begin, make sure you have:
1. Installed Livekit Agents SDK with voice dependencies of silero and deepgram:
```bash
pip install livekit \
livekit-agents \
livekit-plugins-silero \
livekit-plugins-deepgram \
livekit-plugins-openai
```
2. Installed Mem0 SDK:
```bash
pip install mem0ai
```
3. Set up your API keys in a `.env` file:
```sh
LIVEKIT_URL=your_livekit_url
LIVEKIT_API_KEY=your_livekit_api_key
LIVEKIT_API_SECRET=your_livekit_api_secret
DEEPGRAM_API_KEY=your_deepgram_api_key
MEM0_API_KEY=your_mem0_api_key
OPENAI_API_KEY=your_openai_api_key
```
> **Note**: Make sure to have a Livekit and Deepgram account. You can find these variables `LIVEKIT_URL` , `LIVEKIT_API_KEY` and `LIVEKIT_API_SECRET` from [LiveKit Cloud Console](https://cloud.livekit.io/) and for more information you can refer this website [LiveKit Documentation](https://docs.livekit.io/home/cloud/keys-and-tokens/). For `DEEPGRAM_API_KEY` you can get from [Deepgram Console](https://console.deepgram.com/) refer this website [Deepgram Documentation](https://developers.deepgram.com/docs/create-additional-api-keys) for more details.
## Code Breakdown
Let's break down the key components of this implementation:
### 1. Setting Up Dependencies and Environment
```python
import asyncio
import logging
import os
from typing import List, Dict, Any, Annotated
import aiohttp
from dotenv import load_dotenv
from livekit.agents import (
AutoSubscribe,
JobContext,
JobProcess,
WorkerOptions,
cli,
llm,
metrics,
)
from livekit import rtc, api
from livekit.agents.pipeline import VoicePipelineAgent
from livekit.plugins import deepgram, openai, silero
from mem0 import AsyncMemoryClient
# Load environment variables
load_dotenv()
# Configure logging
logger = logging.getLogger("memory-assistant")
logger.setLevel(logging.INFO)
# Define a global user ID for simplicity
USER_ID = "voice_user"
# Initialize Mem0 client
mem0 = AsyncMemoryClient()
```
This section handles:
- Importing required modules
- Loading environment variables
- Setting up logging
- Extracting user identification
- Initializing the Mem0 client
### 2. Memory Enrichment Function
```python
async def _enrich_with_memory(agent: VoicePipelineAgent, chat_ctx: llm.ChatContext):
"""Add memories and Augment chat context with relevant memories"""
if not chat_ctx.messages:
return
# Store user message in Mem0
user_msg = chat_ctx.messages[-1]
await mem0.add(
[{"role": "user", "content": user_msg.content}],
user_id=USER_ID
)
# Search for relevant memories
results = await mem0.search(
user_msg.content,
user_id=USER_ID,
)
# Augment context with retrieved memories
if results:
memories = ' '.join([result["memory"] for result in results])
logger.info(f"Enriching with memory: {memories}")
rag_msg = llm.ChatMessage.create(
text=f"Relevant Memory: {memories}\n",
role="assistant",
)
# Modify chat context with retrieved memories
chat_ctx.messages[-1] = rag_msg
chat_ctx.messages.append(user_msg)
```
This function:
- Stores user messages in Mem0
- Performs semantic search for relevant memories
- Augments the chat context with retrieved memories
- Enables contextually aware responses
### 3. Prewarm and Entrypoint Functions
```python
def prewarm_process(proc: JobProcess):
# Preload silero VAD in memory to speed up session start
proc.userdata["vad"] = silero.VAD.load()
async def entrypoint(ctx: JobContext):
# Connect to LiveKit room
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
# Wait for participant
participant = await ctx.wait_for_participant()
# Initialize Mem0 client
mem0 = AsyncMemoryClient()
# Define initial system context
initial_ctx = llm.ChatContext().append(
role="system",
text=(
"""
You are a helpful voice assistant.
You are a travel guide named George and will help the user to plan a travel trip of their dreams.
You should help the user plan for various adventures like work retreats, family vacations or solo backpacking trips.
You should be careful to not suggest anything that would be dangerous, illegal or inappropriate.
You can remember past interactions and use them to inform your answers.
Use semantic memory retrieval to provide contextually relevant responses.
"""
),
)
# Create VoicePipelineAgent with memory capabilities
agent = VoicePipelineAgent(
chat_ctx=initial_ctx,
vad=silero.VAD.load(),
stt=deepgram.STT(),
llm=openai.LLM(model="gpt-4o-mini"),
tts=openai.TTS(),
before_llm_cb=_enrich_with_memory,
)
# Start agent and initial greeting
agent.start(ctx.room, participant)
await agent.say(
"Hello! I'm George. Can I help you plan an upcoming trip? ",
allow_interruptions=True
)
# Run the application
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint, prewarm_fnc=prewarm_process))
```
The entrypoint function:
- Connects to LiveKit room
- Initializes Mem0 memory client
- Sets up initial system context
- Creates a VoicePipelineAgent with memory enrichment
- Starts the agent with an initial greeting
## Create a Memory-Enabled Voice Agent
Now that we've explained each component, here's the complete implementation that combines OpenAI Agents SDK for voice with Mem0's memory capabilities:
```python
import asyncio
import logging
import os
from typing import List, Dict, Any, Annotated
import aiohttp
from dotenv import load_dotenv
from livekit.agents import (
AutoSubscribe,
JobContext,
JobProcess,
WorkerOptions,
cli,
llm,
metrics,
)
from livekit import rtc, api
from livekit.agents.pipeline import VoicePipelineAgent
from livekit.plugins import deepgram, openai, silero
from mem0 import AsyncMemoryClient
# Load environment variables
load_dotenv()
# Configure logging
logger = logging.getLogger("memory-assistant")
logger.setLevel(logging.INFO)
# Define a global user ID for simplicity
USER_ID = "voice_user"
# Initialize Mem0 memory client
mem0 = AsyncMemoryClient()
def prewarm_process(proc: JobProcess):
# Preload silero VAD in memory to speed up session start
proc.userdata["vad"] = silero.VAD.load()
async def entrypoint(ctx: JobContext):
# Connect to LiveKit room
await ctx.connect(auto_subscribe=AutoSubscribe.AUDIO_ONLY)
# Wait for participant
participant = await ctx.wait_for_participant()
async def _enrich_with_memory(agent: VoicePipelineAgent, chat_ctx: llm.ChatContext):
"""Add memories and Augment chat context with relevant memories"""
if not chat_ctx.messages:
return
# Store user message in Mem0
user_msg = chat_ctx.messages[-1]
await mem0.add(
[{"role": "user", "content": user_msg.content}],
user_id=USER_ID
)
# Search for relevant memories
results = await mem0.search(
user_msg.content,
user_id=USER_ID,
)
# Augment context with retrieved memories
if results:
memories = ' '.join([result["memory"] for result in results])
logger.info(f"Enriching with memory: {memories}")
rag_msg = llm.ChatMessage.create(
text=f"Relevant Memory: {memories}\n",
role="assistant",
)
# Modify chat context with retrieved memories
chat_ctx.messages[-1] = rag_msg
chat_ctx.messages.append(user_msg)
# Define initial system context
initial_ctx = llm.ChatContext().append(
role="system",
text=(
"""
You are a helpful voice assistant.
You are a travel guide named George and will help the user to plan a travel trip of their dreams.
You should help the user plan for various adventures like work retreats, family vacations or solo backpacking trips.
You should be careful to not suggest anything that would be dangerous, illegal or inappropriate.
You can remember past interactions and use them to inform your answers.
Use semantic memory retrieval to provide contextually relevant responses.
"""
),
)
# Create VoicePipelineAgent with memory capabilities
agent = VoicePipelineAgent(
chat_ctx=initial_ctx,
vad=silero.VAD.load(),
stt=deepgram.STT(),
llm=openai.LLM(model="gpt-4o-mini"),
tts=openai.TTS(),
before_llm_cb=_enrich_with_memory,
)
# Start agent and initial greeting
agent.start(ctx.room, participant)
await agent.say(
"Hello! I'm George. Can I help you plan an upcoming trip? ",
allow_interruptions=True
)
# Run the application
if __name__ == "__main__":
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint, prewarm_fnc=prewarm_process))
```
## Key Features of This Implementation
1. **Semantic Memory Retrieval**: Uses Mem0 to store and retrieve contextually relevant memories
2. **Voice Interaction**: Leverages LiveKit for voice communication
3. **Intelligent Context Management**: Augments conversations with past interactions
4. **Travel Planning Specialization**: Focused on creating a helpful travel guide assistant
## Running the Example
To run this example:
1. Install all required dependencies
2. Set up your `.env` file with the necessary API keys
3. Ensure your microphone and audio setup are configured
4. Run the script with Python 3.11 or newer and with the following command:
```sh
python mem0-livekit-voice-agent.py start
```
5. After the script starts, you can interact with the voice agent using [Livekit's Agent Platform](https://agents-playground.livekit.io/) and Connect to the agent inorder to start conversations.
## Best Practices for Voice Agents with Memory
1. **Context Preservation**: Store enough context with each memory for effective retrieval
2. **Privacy Considerations**: Implement secure memory management
3. **Relevant Memory Filtering**: Use semantic search to retrieve only the most pertinent memories
4. **Error Handling**: Implement robust error handling for memory operations
## Debugging Function Tools
- To run the script in debug mode simply start the assistant with `dev` mode:
```sh
python mem0-livekit-voice-agent.py dev
```
- When working with memory-enabled voice agents, use Python's `logging` module for effective debugging:
```python
import logging
# Set up logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger("memory_voice_agent")
```
+83
View File
@@ -220,4 +220,87 @@ Here are the available integrations for Mem0:
>
Integrate Mem0 as an MCP Server in Cursor.
</Card>
<Card
title="Livekit"
icon={
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
>
<text
x="12"
y="16"
fontFamily="Arial"
fontSize="12"
textAnchor="middle"
fill="currentColor"
fontWeight="bold"
>
LK
</text>
</svg>
}
href="/integrations/livekit"
>
Integrate Mem0 with Livekit for voice agents.
</Card>
<Card
title="ElevenLabs"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<rect width="24" height="24" fill="white"/>
<rect x="8" y="4" width="2" height="16" fill="black"/>
<rect x="14" y="4" width="2" height="16" fill="black"/>
</svg>
}
href="/integrations/elevenlabs"
>
Build voice agents with memory using ElevenLabs Conversational AI.
</Card>
<Card
title="Pipecat"
icon={
<svg
viewBox="0 0 24 24"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
>
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z" fill="currentColor"/>
<circle cx="8.5" cy="9" r="1.5" fill="currentColor"/>
<circle cx="15.5" cy="9" r="1.5" fill="currentColor"/>
<path d="M12 16c1.66 0 3-1.34 3-3H9c0 1.66 1.34 3 3 3z" fill="currentColor"/>
<path d="M17.5 12c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z" fill="currentColor"/>
<path d="M6.5 12c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9s1.5.67 1.5 1.5S7.33 12 6.5 12z" fill="currentColor"/>
</svg>
}
href="/integrations/pipecat"
>
Build conversational AI agents with memory using Pipecat.
</Card>
<Card
title="Agno"
icon={
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
>
<path d="M8 4h8v12h8" stroke="currentColor" strokeWidth="2" fill="none" transform="rotate(15, 12, 12)"/>
</svg>
}
href="/integrations/agno"
>
Build autonomous agents with memory using Agno framework.
</Card>
</CardGroup>
+218
View File
@@ -0,0 +1,218 @@
---
title: 'Pipecat'
description: 'Integrate Mem0 with Pipecat for conversational memory in AI agents'
---
# Pipecat Integration
Mem0 seamlessly integrates with [Pipecat](https://pipecat.ai), providing long-term memory capabilities for conversational AI agents. This integration allows your Pipecat-powered applications to remember past conversations and provide personalized responses based on user history.
## Installation
To use Mem0 with Pipecat, install the required dependencies:
```bash
pip install "pipecat-ai[mem0]"
```
You'll also need to set up your Mem0 API key as an environment variable:
```bash
export MEM0_API_KEY=your_mem0_api_key
```
You can obtain a Mem0 API key by signing up at [mem0.ai](https://mem0.ai).
## Configuration
Mem0 integration is provided through the `Mem0MemoryService` class in Pipecat. Here's how to configure it:
```python
from pipecat.services.mem0 import Mem0MemoryService
memory = Mem0MemoryService(
api_key=os.getenv("MEM0_API_KEY"), # Your Mem0 API key
user_id="unique_user_id", # Unique identifier for the end user
agent_id="my_agent", # Identifier for the agent using the memory
run_id="session_123", # Optional: specific conversation session ID
params={ # Optional: configuration parameters
"search_limit": 10, # Maximum memories to retrieve per query
"search_threshold": 0.1, # Relevance threshold (0.0 to 1.0)
"system_prompt": "Here are your past memories:", # Custom prefix for memories
"add_as_system_message": True, # Add memories as system (True) or user (False) message
"position": 1, # Position in context to insert memories
}
)
```
## Pipeline Integration
The `Mem0MemoryService` should be positioned between your context aggregator and LLM service in the Pipecat pipeline:
```python
pipeline = Pipeline([
transport.input(),
stt, # Speech-to-text for audio input
user_context, # User context aggregator
memory, # Mem0 Memory service enhances context here
llm, # LLM for response generation
tts, # Optional: Text-to-speech
transport.output(),
assistant_context # Assistant context aggregator
])
```
## Example: Voice Agent with Memory
Here's a complete example of a Pipecat voice agent with Mem0 memory integration:
```python
import asyncio
import os
from fastapi import FastAPI, WebSocket
from pipecat.frames.frames import TextFrame
from pipecat.pipeline.pipeline import Pipeline
from pipecat.pipeline.task import PipelineTask
from pipecat.pipeline.runner import PipelineRunner
from pipecat.services.mem0 import Mem0MemoryService
from pipecat.services.openai import OpenAILLMService, OpenAIUserContextAggregator, OpenAIAssistantContextAggregator
from pipecat.transports.network.fastapi_websocket import (
FastAPIWebsocketTransport,
FastAPIWebsocketParams
)
from pipecat.serializers.protobuf import ProtobufFrameSerializer
from pipecat.audio.vad.silero import SileroVADAnalyzer
from pipecat.services.whisper import WhisperSTTService
app = FastAPI()
@app.websocket("/chat")
async def websocket_endpoint(websocket: WebSocket):
await websocket.accept()
# Basic setup with minimal configuration
user_id = "user123"
# WebSocket transport
transport = FastAPIWebsocketTransport(
websocket=websocket,
params=FastAPIWebsocketParams(
audio_out_enabled=True,
vad_enabled=True,
vad_analyzer=SileroVADAnalyzer(),
vad_audio_passthrough=True,
serializer=ProtobufFrameSerializer(),
)
)
# Core services
user_context = OpenAIUserContextAggregator()
assistant_context = OpenAIAssistantContextAggregator()
stt = WhisperSTTService(api_key=os.getenv("OPENAI_API_KEY"))
# Memory service - the key component
memory = Mem0MemoryService(
api_key=os.getenv("MEM0_API_KEY"),
user_id=user_id,
agent_id="fastapi_memory_bot"
)
# LLM for response generation
llm = OpenAILLMService(
api_key=os.getenv("OPENAI_API_KEY"),
model="gpt-3.5-turbo",
system_prompt="You are a helpful assistant that remembers past conversations."
)
# Simple pipeline
pipeline = Pipeline([
transport.input(),
stt, # Speech-to-text for audio input
user_context,
memory, # Memory service enhances context here
llm,
transport.output(),
assistant_context
])
# Run the pipeline
runner = PipelineRunner()
task = PipelineTask(pipeline)
# Event handlers for WebSocket connections
@transport.event_handler("on_client_connected")
async def on_client_connected(transport, client):
# Send welcome message when client connects
await task.queue_frame(TextFrame("Hello! I'm a memory bot. I'll remember our conversation."))
@transport.event_handler("on_client_disconnected")
async def on_client_disconnected(transport, client):
# Clean up when client disconnects
await task.cancel()
await runner.run(task)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
```
## How It Works
When integrated with Pipecat, Mem0 provides two key functionalities:
### 1. Message Storage
All conversation messages are automatically stored in Mem0 for future reference:
- Captures the full message history from context frames
- Associates messages with the specified user, agent, and run IDs
- Stores metadata to enable efficient retrieval
### 2. Memory Retrieval
When a new user message is detected:
1. The message is used as a search query to find relevant past memories
2. Relevant memories are retrieved from Mem0's database
3. Memories are formatted and added to the conversation context
4. The enhanced context is passed to the LLM for response generation
## Additional Configuration Options
### Memory Search Parameters
You can customize how memories are retrieved and used:
```python
memory = Mem0MemoryService(
api_key=os.getenv("MEM0_API_KEY"),
user_id="user123",
params={
"search_limit": 5, # Retrieve up to 5 memories
"search_threshold": 0.2, # Higher threshold for more relevant matches
"api_version": "v2", # Mem0 API version
}
)
```
### Memory Presentation Options
Control how memories are presented to the LLM:
```python
memory = Mem0MemoryService(
api_key=os.getenv("MEM0_API_KEY"),
user_id="user123",
params={
"system_prompt": "Previous conversations with this user:",
"add_as_system_message": True, # Add as system message instead of user message
"position": 0, # Insert at the beginning of the context
}
)
```
## Resources
- [Mem0 Pipecat Integration](https://docs.pipecat.ai/server/services/memory/mem0)
- [Pipecat Documentation](https://docs.pipecat.ai)
+14 -1
View File
@@ -10,7 +10,6 @@ The [**Mem0 AI SDK Provider**](https://www.npmjs.com/package/@mem0/vercel-ai-pro
## Overview
In this guide, we'll create a Travel Agent AI that:
1. 🧠 Offers persistent memory storage for conversational AI
2. 🔄 Enables smooth integration with the Vercel AI SDK
3. 🚀 Ensures compatibility with multiple LLM providers
@@ -191,6 +190,20 @@ npm install @mem0/vercel-ai-provider
console.log(result);
```
### 5. Get sources from memory
```typescript
const { text, sources } = await generateText({
model: mem0("gpt-4-turbo"),
prompt: "Suggest me a good car to buy!",
});
console.log(sources);
```
The same can be done for `streamText` as well.
## Key Features
- `createMem0()`: Initializes a new Mem0 provider instance.
+122
View File
@@ -0,0 +1,122 @@
# Mem0
## High Level
[What is Mem0?](https://docs.mem0.ai/overview): consider using Mem0, when building conversational AI agents with memory. The page discusses the main reasons to use Mem0: Context Management, Smart Retrieval System, Simple API Integration and Dual Storage Architecture(vector and graph database).
[How is Mem0 different from traditional RAG?](https://docs.mem0.ai/faqs#how-mem0-is-different-from-traditional-rag): Mem0's memory for LLMs offers superior entity relationship understanding, contextual continuity, and adaptive learning compared to RAG. It retains information across sessions, dynamically updates with new data, and personalizes interactions, making it ideal for context-aware AI applications.
## Concepts
[Memory Types](https://docs.mem0.ai/core-concepts/memory-types): Mem0 implements both short-term memory (for conversation history and immediate context) and long-term memory (for persistent storage of factual, episodic, and semantic information) to maintain context and personalization across interactions.
[Memory Operations](https://docs.mem0.ai/core-concepts/memory-operations): Two core operations power Mem0's functionality: `add` Processes and stores conversations through information extraction, conflict resolution, and dual storage and `search` Retrieves relevant memories using semantic search with query processing and result ranking
[Information Processing](https://docs.mem0.ai/core-concepts/memory-operations): When adding memories, Mem0 uses LLMs to extract relevant information, identify entities and relationships, and resolve conflicts with existing data.
[Storage Architecture](https://docs.mem0.ai/core-concepts/memory-types): Mem0 combines vector embeddings for semantic information storage with efficient retrieval mechanisms, enabling fast access to relevant past interactions while maintaining user-specific context across sessions.
## How-to guides
### Installation
[Mem0 Installation](https://docs.mem0.ai/quickstart): Mem0 offers two installation options: Mem0 Platform (Managed Solution) and Mem0 OSS.
[How to: install Mem0 Platform (Managed Solution)](https://docs.mem0.ai/quickstart#mem0-platform-managed-solution): The easiest way to get started with Mem0 is to use the managed platform. This approach eliminates the need to set up and maintain your own infrastructure.
[How to: install Mem0 OSS](https://docs.mem0.ai/quickstart#mem0-open-source): If you prefer to manage your own infrastructure, you can install Mem0 OSS. This option requires setting up your own infrastructure and managing your own vector database.
## Platform
### Usage
[Initialize Client](https://docs.mem0.ai/platform/quickstart#3-instantiate-client): Mem0 gives two ways to initialize the client: Synchronous -> MemoryClient and Asynchronous -> AsyncMemoryClient.
[How to: add memories](https://docs.mem0.ai/platform/quickstart#4-1-create-memories): Add memories to Mem0 using messages or a simple string. The `add` method allows adding memories to a specific memory by providing `user_id`, `agent_id`, `run_id`, or `app_id`.
[How to: search memories](https://docs.mem0.ai/platform/quickstart#4-2-search-memories): Search memories in Mem0 by passing a query string and optional parameters. The `search` method returns a list of memories sorted by relevance. Csutom filters can also be passed to make the search more specific.
[How to: get all memories](https://docs.mem0.ai/platform/quickstart#4-4-get-all-memories): Get all the memories by passing a `user_id`, `agent_id`, `run_id`, or `app_id`. Also custom filters can be passed to filter the memories.
[How to: get memory history](https://docs.mem0.ai/platform/quickstart#4-5-get-memory-history): Get the history of a specific memory by passing `memory_id` after adding memories using the `add` method.
[How to: update memory](https://docs.mem0.ai/platform/quickstart#4-6-update-memory): Update a memory by passing `memory_id` after adding memories using the `add` method.
[How to: delete memory](https://docs.mem0.ai/platform/quickstart#4-7-delete-memories): Delete memories by passing `memory_id` after adding memories using the `add` method.
[How to: reset client](https://docs.mem0.ai/platform/quickstart#4-8-reset-client): Reset the client where all the memories, users, agents, sessions and runs are deleted.
[How to: batch update memories](https://docs.mem0.ai/platform/quickstart#4-9-batch-update-memories): Batch update memories by passing a list of memories to the `batch_update` method.
[How to: batch delete memories](https://docs.mem0.ai/platform/quickstart#4-10-batch-delete-memories): Batch delete memories by passing a list of memories to the `batch_delete` method.
## Features
[Graph Memory](https://docs.mem0.ai/features/graph-memory): Mem0's graph memory system builds relationships between entities in your data, enabling contextually relevant retrieval by analyzing connections between information points - activate it with `enable_graph=True` to enhance search results beyond direct semantic matches, ideal for applications tracking evolving relationships.
[Advanced Retrieval](https://docs.mem0.ai/features/advanced-retrieval): Mem0 offers enhanced search capabilities through three advanced retrieval modes: keyword search (improves recall by matching specific terms), reranking (ensures most relevant results appear first using neural networks), and filtering (narrows results by specific criteria) - each can be enabled independently or in combination to optimize search precision and relevance.
[Multimodal Support](https://docs.mem0.ai/features/multimodal-support): Mem0 extends beyond text by supporting images and documents (JPG, PNG, MDX, TXT, PDF), allowing users to integrate visual and document content through direct URLs or Base64 encoding, enhancing the memory system's ability to understand and recall information from various media types.
[Memory Customization](https://docs.mem0.ai/features/selective-memory): Mem0 enables selective memory storage through inclusion and exclusion rules, allowing users to focus on relevant information (like specific topics) while omitting irrelevant data (such as food preferences), resulting in more efficient, accurate, and privacy-conscious AI interactions.
[Custom Categories](https://docs.mem0.ai/features/custom-categories): Mem0 allows setting custom categories at both project level and during individual API calls, overriding default categories (like personal_details, family, sports) with more specific ones to improve memory categorization accuracy - simply provide a list of category dictionaries with descriptive definitions when adding memories.
[Async Client](https://docs.mem0.ai/features/async-client): Mem0 provides an AsyncMemoryClient for non-blocking operations, offering the same functionality as the synchronous client (add, search, get_all, delete, etc.) but with async/await support, making it ideal for high-concurrency applications that need to perform memory operations without blocking execution.
[Memory Export](https://docs.mem0.ai/features/memory-export): Mem0 enables exporting memories in structured formats using customizable Pydantic schemas, allowing you to transform stored memories into specific data structures by defining schemas, submitting export jobs with optional processing instructions, and retrieving the formatted data with various filtering options.
## OSS
### Usage
#### Python
[Initialize python client](https://docs.mem0.ai/open-source/python-quickstart#installation): Install Mem0 with `pip install mem0ai`, then initialize the client with `from mem0 import Memory; m = Memory()` (requires OpenAI API key). For advanced usage, configure with custom parameters or enable graph memory with `Memory(enable_graph=True)`.
[Configuration Parameters](https://docs.mem0.ai/open-source/python-quickstart#configuration-parameters): Mem0 offers extensive configuration options for vector stores (provider, host, port), LLMs (provider, model, temperature, API keys), embedders (provider, model), graph stores (provider, URL, credentials), and general settings (history path, API version, custom prompts) - all customizable through a comprehensive configuration dictionary.
[How to: add memories](https://docs.mem0.ai/open-source/python-quickstart#store-a-memory): Add memories to Mem0 using the Python OSS client's `add` method with messages or a simple string. This method allows adding memories to a specific memory by providing `user_id`, `agent_id`, `run_id`, or `app_id`.
[How to: search memories](https://docs.mem0.ai/open-source/python-quickstart#search-memories): Search memories in Mem0 using the Python OSS client by passing a query string and optional parameters. The `search` method returns a list of memories sorted by relevance. Custom filters can also be passed to make the search more specific.
[How to: get all memories](https://docs.mem0.ai/open-source/python-quickstart#retrieve-memories): Get all the memories using the Python OSS client by passing a `user_id`, `agent_id`, `run_id`, or `app_id`. Also custom filters can be passed to filter the memories.
[How to: get memory history](https://docs.mem0.ai/open-source/python-quickstart#memory-history): Get the history of a specific memory in the Python OSS client by passing `memory_id` after adding memories using the `add` method.
[How to: update memory](https://docs.mem0.ai/open-source/python-quickstart#update-a-memory): Update a memory in the Python OSS client by passing `memory_id` after adding memories using the `add` method.
[How to: delete memory](https://docs.mem0.ai/open-source/python-quickstart#delete-memory): Delete memories in the Python OSS client by passing `memory_id` after adding memories using the `add` method.
#### Node.js
[Initialize node client](https://docs.mem0.ai/open-source/node-quickstart#installation): Install Mem0 with `npm install mem0ai`, then initialize the client with `import { Memory } from 'mem0ai'; const m = new Memory();` (requires OpenAI API key). For advanced usage, configure with custom parameters or enable graph memory with `new Memory({ enableGraph: true })`.
[How to: add memories](https://docs.mem0.ai/open-source/node-quickstart#store-a-memory): Add memories to Mem0 using the Node.js OSS client's `add` method with messages or a simple string. This method allows adding memories to a specific memory by providing `user_id`, `agent_id`, `run_id`, or `app_id`.
[How to: search memories](https://docs.mem0.ai/open-source/node-quickstart#search-memories): Search memories in Mem0 using the Node.js OSS client by passing a query string and optional parameters. The `search` method returns a list of memories sorted by relevance. Custom filters can also be passed to make the search more specific.
[How to: get all memories](https://docs.mem0.ai/open-source/node-quickstart#retrieve-memories): Get all the memories using the Node.js OSS client by passing a `user_id`, `agent_id`, `run_id`, or `app_id`. Also custom filters can be passed to filter the memories.
[How to: get memory history](https://docs.mem0.ai/open-source/node-quickstart#memory-history): Get the history of a specific memory in the Node.js OSS client by passing `memory_id` after adding memories using the `add` method.
[How to: update memory](https://docs.mem0.ai/open-source/node-quickstart#update-a-memory): Update a memory in the Node.js OSS client by passing `memory_id` after adding memories using the `add` method.
[How to: delete memory](https://docs.mem0.ai/open-source/node-quickstart#delete-memory): Delete memories in the Node.js OSS client by passing `memory_id` after adding memories using the `add` method.
### Features
[OpenAI Compatibility](https://docs.mem0.ai/features/openai_compatibility): Mem0 offers seamless integration with OpenAI-compatible APIs, allowing developers to enhance conversational agents with structured memory by initializing with a Mem0 API key (or locally without one), supporting various LLM providers, and enabling personalized responses through user context persistence across interactions with parameters like user_id, agent_id, and custom filters.
[Custom Fact Extraction Prompt](https://docs.mem0.ai/features/custom-fact-extraction-prompt): Mem0 enables custom fact extraction prompts to tailor information extraction for specific use cases by defining domain-specific examples and formats, allowing precise control over what information is extracted from messages - simply provide a custom prompt with few-shot examples in the config when initializing the Memory client.
[Custom Update Memory Prompt](https://docs.mem0.ai/features/custom-update-memory-prompt): Mem0 enables customizing the update memory prompt to control how memories are modified by comparing newly retrieved facts with existing memories and determining appropriate actions (add, update, delete, or no change) based on custom logic and examples provided in the prompt configuration.
[REST API Server](https://docs.mem0.ai/open-source/features/rest-api): Mem0 provides a FastAPI-based REST API server that supports core operations (create/retrieve/search/update/delete memories) with OpenAPI documentation at /docs, easily deployable via Docker Compose with pre-configured databases (postgres pgvector, neo4j) - just set OPENAI_API_KEY to get started.
[Graph Memory](https://docs.mem0.ai/open-source/graph_memory/overview): Mem0's open-source graph memory system enables building and querying relationships between entities by installing with `pip install "mem0ai[graph]"` and configuring a graph store provider (like Neo4j) - this allows for more contextual memory retrieval by combining vector and graph-based approaches to track evolving relationships between information points.
### Components
#### LLMs
[OpenAI](https://docs.mem0.ai/components/llms/models/openai): Integrate OpenAI LLM models by setting OPENAI_API_KEY and configuring the Memory client with provider settings - supports both standard models (like gpt-4) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
[Anthropic](https://docs.mem0.ai/components/llms/models/anthropic): Integrate Anthropic LLM models by setting ANTHROPIC_API_KEY from your Account Settings Page and configuring the Memory client with provider settings - supports models like claude-3-7-sonnet-latest with customizable temperature and max_tokens parameters.
[Google AI](https://docs.mem0.ai/components/llms/models/google_AI): Integrate Gemini LLM models by setting GEMINI_API_KEY from Google Maker Suite and configuring the Memory client with litellm provider - supports models like gemini-pro with customizable temperature and max_tokens parameters.
[Groq](https://docs.mem0.ai/components/llms/models/groq): Integrate Groq's Language Processing Unit (LPU) optimized models by setting GROQ_API_KEY and configuring the Memory client with provider settings - supports models like mixtral-8x7b-32768 with customizable temperature and max_tokens parameters for high-performance AI inference.
[Together](https://docs.mem0.ai/components/llms/models/together): Integrate Together LLM models by setting TOGETHER_API_KEY and configuring the Memory client with provider settings - supports both standard models (like together-llama-3-8b-instant) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
[Deepseek](https://docs.mem0.ai/components/llms/models/deepseek): Integrate Deepseek LLM models by setting DEEPSEEK_API_KEY and configuring the Memory client with provider settings - supports both standard models (like deepseek-chat) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
[xAI](https://docs.mem0.ai/components/llms/models/xai): Integrate xAI LLM models by setting XAI_API_KEY and configuring the Memory client with provider settings - supports both standard models (like xai-chat) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
[LM Studio](https://docs.mem0.ai/components/llms/models/lmstudio): Run Mem0 locally with LM Studio by configuring the Memory client with provider settings and a local LM Studio server - supports using LM Studio for both LLM inference and embeddings, requiring no external API keys when running fully locally with appropriate models loaded.
[Ollama](https://docs.mem0.ai/components/llms/models/ollama): Run Mem0 locally with Ollama LLM models by configuring the Memory client with provider settings like model (e.g. mixtral:8x7b), temperature and max_tokens - supports tool calling and requires only OpenAI API key for embeddings.
[AWS Bedrock](https://docs.mem0.ai/components/llms/models/aws_bedrock): Integrate AWS Bedrock LLM models by setting AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY and configuring the Memory client with provider settings - supports both standard models (like bedrock-anthropic-claude-3-5-sonnet) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
[Azure OpenAI](https://docs.mem0.ai/components/llms/models/azure_openai): Integrate Azure OpenAI LLM models by setting LLM_AZURE_OPENAI_API_KEY, LLM_AZURE_ENDPOINT, LLM_AZURE_DEPLOYMENT and LLM_AZURE_API_VERSION environment variables and configuring the Memory client with provider settings - supports both standard and structured-output models with customizable deployment, API version, endpoint and headers (note: some features like parallel tool calling and temperature are currently unsupported).
[LiteLLM](https://docs.mem0.ai/components/llms/models/litellm): Integrate LiteLLM LLM models by setting LITELLM_API_KEY and configuring the Memory client with provider settings - supports both standard models (like llama3.1:8b) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
[Mistral](https://docs.mem0.ai/components/llms/models/mistral): Integrate Mistral LLM models by setting MISTRAL_API_KEY and configuring the Memory client with provider settings - supports both standard models (like mistral-large-latest) and structured-outputs, with options for temperature, max tokens and Openrouter integration.
#### Embedders
[OpenAI](https://docs.mem0.ai/components/embedders/models/openai): Integrate OpenAI embedding models by setting OPENAI_API_KEY and configuring the Memory client with provider settings - supports models like text-embedding-3-small (default) and text-embedding-3-large with customizable dimensions.
[Azure OpenAI](https://docs.mem0.ai/components/embedders/models/azure_openai): Integrate Azure OpenAI embedding models by setting EMBEDDING_AZURE_OPENAI_API_KEY, EMBEDDING_AZURE_ENDPOINT, EMBEDDING_AZURE_DEPLOYMENT and EMBEDDING_AZURE_API_VERSION environment variables and configuring the Memory client with provider settings - supports models like text-embedding-3-large with customizable dimensions and Azure-specific configurations through azure_kwargs.
[Vertex AI](https://docs.mem0.ai/components/embedders/models/google_ai): Integrate Google Cloud's Vertex AI embedding models by setting GOOGLE_APPLICATION_CREDENTIALS environment variable to your service account credentials JSON file and configuring the Memory client with provider settings - supports models like text-embedding-004 with customizable embedding types (RETRIEVAL_DOCUMENT, RETRIEVAL_QUERY, etc.) and dimensions.
[Groq](https://docs.mem0.ai/components/embedders/models/groq): Integrate Groq embedding models by setting GROQ_API_KEY and configuring the Memory client with provider settings - supports models like text-embedding-3-small (default) and text-embedding-3-large with customizable dimensions.
[Hugging Face](https://docs.mem0.ai/components/embedders/models/hugging_face): Run Mem0 locally with Hugging Face embedding models by configuring the Memory client with provider settings like model (e.g. multi-qa-MiniLM-L6-cos-v1), embedding dimensions and model_kwargs - requires only OpenAI API key for LLM functionality.
[Ollama](https://docs.mem0.ai/components/embedders/models/ollama): Run Mem0 locally with Ollama embedding models by configuring the Memory client with provider settings like model (e.g. nomic-embed-text), embedding dimensions (default 512) and custom base URL - requires only OpenAI API key for LLM functionality.
[Gemini](https://docs.mem0.ai/components/embedders/models/gemini): Integrate Gemini embedding models by setting GOOGLE_API_KEY and configuring the Memory client with provider settings - supports models like text-embedding-004 with customizable dimensions (default 768) and requires OpenAI API key for LLM functionality.
#### Vector Stores
[Qdrant](https://docs.mem0.ai/components/vectordbs/dbs/qdrant): Integrate Qdrant vector database by configuring the Memory client with provider settings like collection_name, host, port, and other parameters - supports both local and remote deployments with options for persistent storage and custom client configurations.
[Pinecone](https://docs.mem0.ai/components/vectordbs/dbs/pinecone): Integrate Pinecone's managed vector database by configuring the Memory client with serverless or pod deployment options, supporting high-performance vector search with customizable embedding dimensions, distance metrics, and cloud providers (AWS/GCP/Azure) - requires PINECONE_API_KEY and matching embedding model dimensions (e.g. 1536 for OpenAI).
[Milvus](https://docs.mem0.ai/components/vectordbs/dbs/milvus): Integrate Milvus open-source vector database by configuring the Memory client with provider settings like url (default localhost:19530), token (for Zilliz cloud), collection_name, embedding_model_dims (default 1536) and metric_type - supports both local and cloud deployments for AI applications of any scale.
[Weaviate](https://docs.mem0.ai/components/vectordbs/dbs/weaviate): Integrate Weaviate open-source vector search engine by configuring the Memory client with provider settings like collection_name (default: mem0), cluster_url, auth_client_secret and embedding_model_dims (default: 1536) - enables efficient storage and retrieval of high-dimensional vector embeddings.
[Chroma](https://docs.mem0.ai/components/vectordbs/dbs/chroma): Integrate Chroma AI-native open-source vector database by configuring the Memory client with provider settings like collection_name (default: mem0), path (default: db), host, port, and client - enables simple storage and search of embeddings with focus on speed and ease of use.
[Faiss](https://docs.mem0.ai/components/vectordbs/dbs/faiss): Integrate Faiss, a high-performance library for similarity search and clustering of dense vectors, by configuring the Memory client with settings like collection_name, path, and distance_strategy (euclidean/cosine/inner_product) - supports efficient local vector search with in-memory or persistent storage options and is optimized for large-scale production use.
[PGVector](https://docs.mem0.ai/components/vectordbs/dbs/pgvector): Integrate Postgres vector similarity search by configuring the Memory client with database connection settings (user, password, host, port), collection name, embedding dimensions and indexing options (diskann/hnsw) - requires creating vector extension in Postgres and supports both local and cloud deployments.
[Elasticsearch](https://docs.mem0.ai/components/vectordbs/dbs/elasticsearch): Integrate Elasticsearch vector database by configuring host, port, collection name and authentication settings - supports k-NN vector search, cloud/local deployments, custom search queries, and requires `pip install elasticsearch>=8.0.0`.
[Redis](https://docs.mem0.ai/components/vectordbs/dbs/redis): Integrate Redis vector database for real-time vector storage and search by configuring collection name, embedding dimensions (default 1536), and Redis URL - supports both local Docker deployment and remote Redis Stack instances.
[Supabase](https://docs.mem0.ai/components/vectordbs/dbs/supabase): Integrate Supabase's PostgreSQL database with pgvector extension by configuring connection string, collection name, and optional index settings (hnsw/ivfflat) - enables efficient vector similarity search with support for different distance measures (cosine/l2/l1) and requires SQL migrations to enable vector functionality.
[Azure AI Search](https://docs.mem0.ai/components/vectordbs/dbs/azure): Integrate Azure AI Search (formerly Azure Cognitive Search) by configuring service_name, api_key and collection_name - supports vector compression (none/scalar/binary), hybrid search modes, and customizable vector dimensions with automatic extraction of filterable fields like user_id.
[Vertex AI Search](https://docs.mem0.ai/components/vectordbs/dbs/vertex_ai): Integrate Google Cloud's Vertex AI Vector Search by configuring endpoint_id, index_id, deployment_index_id, project details and optional region/credentials - enables efficient vector similarity search through Google Cloud's managed service with support for both get and search operations.
+169
View File
@@ -0,0 +1,169 @@
---
title: Async Memory
description: 'Asynchronous memory for Mem0'
icon: "bolt"
iconType: "solid"
---
## AsyncMemory
The `AsyncMemory` class is a direct asynchronous interface to Mem0's in-process memory operations. Unlike the memory, which interacts with an API, `AsyncMemory` works directly with the underlying storage systems. This makes it ideal for applications where you want to embed Mem0 directly into your codebase.
### Initialization
To use `AsyncMemory`, import it from the `mem0.memory` module:
```python Python
import asyncio
from mem0 import AsyncMemory
# Initialize with default configuration
memory = AsyncMemory()
# Or initialize with custom configuration
from mem0.configs.base import MemoryConfig
custom_config = MemoryConfig(
# Your custom configuration here
)
memory = AsyncMemory(config=custom_config)
```
### Key Features
1. **Non-blocking Operations** - All memory operations use `asyncio` to avoid blocking the event loop
2. **Concurrent Processing** - Parallel execution of vector store and graph operations
3. **Efficient Resource Utilization** - Better handling of I/O bound operations
4. **Compatible with Async Frameworks** - Seamless integration with FastAPI, aiohttp, and other async frameworks
### Methods
All methods in `AsyncMemory` have the same parameters as the synchronous `Memory` class but are designed to be used with `async/await`.
#### Create memories
Add a new memory asynchronously:
```python Python
await memory.add(
messages=[
{"role": "user", "content": "I'm travelling to SF"},
{"role": "assistant", "content": "That's great to hear!"}
],
user_id="alice"
)
```
#### Retrieve memories
Retrieve memories related to a query:
```python Python
await memory.search(
query="Where am I travelling?",
user_id="alice"
)
```
#### List memories
List all memories for a `user_id`, `agent_id`, or `run_id`:
```python Python
await memory.get_all(user_id="alice")
```
#### Get specific memory
Retrieve a specific memory by its ID:
```python Python
await memory.get(memory_id="memory-id-here")
```
#### Update memory
Update an existing memory by ID:
```python Python
await memory.update(
memory_id="memory-id-here",
data="I'm travelling to Seattle"
)
```
#### Delete memory
Delete a specific memory by ID:
```python Python
await memory.delete(memory_id="memory-id-here")
```
#### Delete all memories
Delete all memories for a specific user, agent, or run:
```python Python
await memory.delete_all(user_id="alice")
```
Note: At least one filter (user_id, agent_id, or run_id) is required when using delete_all.
#### Memory History
Get the history of changes for a specific memory:
```python Python
await memory.history(memory_id="memory-id-here")
```
### Example: Concurrent Usage with Other APIs
`AsyncMemory` can be effectively combined with other async operations. Here's an example showing how to use it alongside OpenAI API calls in separate threads:
```python Python
import asyncio
from openai import AsyncOpenAI
from mem0 import AsyncMemory
async_openai_client = AsyncOpenAI()
async_memory = AsyncMemory()
async def chat_with_memories(message: str, user_id: str = "default_user") -> str:
# Retrieve relevant memories
search_result = await async_memory.search(query=message, user_id=user_id, limit=3)
relevant_memories = search_result["results"]
memories_str = "\n".join(f"- {entry['memory']}" for entry in relevant_memories)
# Generate Assistant response
system_prompt = f"You are a helpful AI. Answer the question based on query and memories.\nUser Memories:\n{memories_str}"
messages = [{"role": "system", "content": system_prompt}, {"role": "user", "content": message}]
response = await async_openai_client.chat.completions.create(model="gpt-4o-mini", messages=messages)
assistant_response = response.choices[0].message.content
# Create new memories from the conversation
messages.append({"role": "assistant", "content": assistant_response})
await async_memory.add(messages, user_id=user_id)
return assistant_response
async def async_main():
print("Chat with AI (type 'exit' to quit)")
while True:
user_input = input("You: ").strip()
if user_input.lower() == 'exit':
print("Goodbye!")
break
response = await chat_with_memories(user_input)
print(f"AI: {response}")
def main():
asyncio.run(async_main())
if __name__ == "__main__":
main()
```
If you have any questions or need further assistance, please don't hesitate to reach out:
<Snippet file="get-help.mdx" />
+63 -40
View File
@@ -7,7 +7,7 @@ iconType: "solid"
Mem0 provides a REST API server (written using FastAPI). Users can perform all operations through REST endpoints. The API also includes OpenAPI documentation, accessible at `/docs` when the server is running.
<Frame caption="APIs supported by Mem0 REST API Server">
<img src="/images/rest-api-server.png" />
<img src="/images/rest-api-server.png"/>
</Frame>
## Features
@@ -23,67 +23,90 @@ Mem0 provides a REST API server (written using FastAPI). Users can perform all o
## Running Locally
<Tabs>
<Tab title="With Docker">
<Tab title="With Docker Compose">
The Development Docker Compose comes pre-configured with postgres pgvector, neo4j and a `server/history/history.db` volume for the history database.
1. Create a `.env` file in the current directory and set your environment variables. For example:
The only required environment variable to run the server is `OPENAI_API_KEY`.
```txt
OPENAI_API_KEY=your-openai-api-key
```
1. Create a `.env` file in the `server/` directory and set your environment variables. For example:
2. Either pull the docker image from docker hub or build the docker image locally.
```txt
OPENAI_API_KEY=your-openai-api-key
```
<Tabs>
<Tab title="Pull from Docker Hub">
2. Run the Docker container using Docker Compose:
```bash
docker pull mem0/mem0-api-server
```
```bash
cd server
docker compose up
```
</Tab>
3. Access the API at http://localhost:8888.
<Tab title="Build Locally">
4. Making changes to the server code or the library code will automatically reload the server.
</Tab>
```bash
docker build -t mem0-api-server .
```
<Tab title="With Docker">
</Tab>
</Tabs>
1. Create a `.env` file in the current directory and set your environment variables. For example:
3. Run the Docker container:
```txt
OPENAI_API_KEY=your-openai-api-key
```
``` bash
docker run -p 8000:8000 mem0-api-server --env-file .env
```
2. Either pull the docker image from docker hub or build the docker image locally.
4. Access the API at http://localhost:8000.
<Tabs>
<Tab title="Pull from Docker Hub">
</Tab>
```bash
docker pull mem0/mem0-api-server
```
<Tab title="Without Docker">
</Tab>
1. Create a `.env` file in the current directory and set your environment variables. For example:
<Tab title="Build Locally">
```txt
OPENAI_API_KEY=your-openai-api-key
```
```bash
docker build -t mem0-api-server .
```
2. Install dependencies:
</Tab>
</Tabs>
```bash
pip install -r requirements.txt
```
3. Run the Docker container:
3. Start the FastAPI server:
``` bash
docker run -p 8000:8000 mem0-api-server --env-file .env
```
```bash
uvicorn main:app --reload
```
4. Access the API at http://localhost:8000.
4. Access the API at http://localhost:8000.
</Tab>
</Tab>
<Tab title="Without Docker">
1. Create a `.env` file in the current directory and set your environment variables. For example:
```txt
OPENAI_API_KEY=your-openai-api-key
```
2. Install dependencies:
```bash
pip install -r requirements.txt
```
3. Start the FastAPI server:
```bash
uvicorn main:app --reload
```
4. Access the API at http://localhost:8000.
</Tab>
</Tabs>
## Usage
+67 -1
View File
@@ -301,6 +301,56 @@ await memory.deleteAll({ userId: "alice" });
await memory.reset(); // Reset all memories
```
### History Store
Mem0 TypeScript SDK support history stores to run on a serverless environment:
We recommend using `Supabase` as a history store for serverless environments or disable history store to run on a serverless environment.
<CodeGroup>
```typescript Supabase
import { Memory } from 'mem0ai/oss';
const memory = new Memory({
historyStore: {
provider: 'supabase',
config: {
supabaseUrl: process.env.SUPABASE_URL || '',
supabaseKey: process.env.SUPABASE_KEY || '',
tableName: 'memory_history',
},
},
});
```
```typescript Disable History
import { Memory } from 'mem0ai/oss';
const memory = new Memory({
disableHistory: true,
});
```
</CodeGroup>
Mem0 uses SQLite as a default history store.
#### Create Memory History Table in Supabase
You may need to create a memory history table in Supabase to store the history of memories. Use the following SQL command in `SQL Editor` on the Supabase project dashboard to create a memory history table:
```sql
create table memory_history (
id text primary key,
memory_id text not null,
previous_value text,
new_value text,
action text not null,
created_at timestamp with time zone default timezone('utc', now()),
updated_at timestamp with time zone,
is_deleted integer default 0
);
```
## Configuration Parameters
Mem0 offers extensive configuration options to customize its behavior according to your needs. These configurations span across different components like vector stores, language models, embedders, and graph stores.
@@ -352,6 +402,14 @@ Mem0 offers extensive configuration options to customize its behavior according
| `customPrompt` | Custom prompt for memory processing | None |
</Accordion>
<Accordion title="History Table Configuration">
| Parameter | Description | Default |
|------------------|--------------------------------------|----------------------------|
| `provider` | History store provider | "sqlite" |
| `config` | History store configuration | None (Defaults to SQLite) |
| `disableHistory` | Disable history store | false |
</Accordion>
<Accordion title="Complete Configuration Example">
```typescript
const config = {
@@ -377,7 +435,15 @@ const config = {
model: 'gpt-4-turbo-preview',
},
},
historyDbPath: 'memory.db',
historyStore: {
provider: 'supabase',
config: {
supabaseUrl: process.env.SUPABASE_URL || '',
supabaseKey: process.env.SUPABASE_KEY || '',
tableName: 'memories',
},
},
disableHistory: false, // This is false by default
customPrompt: "I'm a virtual assistant. I'm here to help you with your queries.",
}
```
+29 -3
View File
@@ -22,8 +22,22 @@ pip install mem0ai
<Tabs>
<Tab title="Basic">
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your-api-key"
m = Memory()
```
</Tab>
<Tab title="Async">
```python
import os
from mem0 import AsyncMemory
os.environ["OPENAI_API_KEY"] = "your-api-key"
m = AsyncMemory()
```
</Tab>
<Tab title="Advanced">
@@ -42,8 +56,11 @@ docker run -p 6333:6333 -p 6334:6334 \
Then, instantiate memory with qdrant server:
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your-api-key"
config = {
"vector_store": {
"provider": "qdrant",
@@ -61,8 +78,11 @@ m = Memory.from_config(config)
<Tab title="Advanced (Graph Memory)">
```python
import os
from mem0 import Memory
os.environ["OPENAI_API_KEY"] = "your-api-key"
config = {
"graph_store": {
"provider": "neo4j",
@@ -85,14 +105,18 @@ m = Memory.from_config(config_dict=config)
<CodeGroup>
```python Code
const messages = [
messages = [
{"role": "user", "content": "I'm planning to watch a movie tonight. Any recommendations?"},
{"role": "assistant", "content": "How about a thriller movies? They can be quite engaging."},
{"role": "user", "content": "I'm not a big fan of thriller movies but I love sci-fi movies."},
{"role": "assistant", "content": "Got it! I'll avoid thriller recommendations and suggest sci-fi movies in the future."}
]
# Store inferred memories (default behavior)
result = m.add(messages, user_id="alice", metadata={"category": "movie_recommendations"})
# Store raw messages without inference
# result = m.add(messages, user_id="alice", metadata={"category": "movie_recommendations"}, infer=False)
```
```json Output
@@ -368,7 +392,8 @@ Mem0 offers extensive configuration options to customize its behavior according
|------------------|--------------------------------------|----------------------------|
| `history_db_path` | Path to the history database | "{mem0_dir}/history.db" |
| `version` | API version | "v1.1" |
| `custom_prompt` | Custom prompt for memory processing | None |
| `custom_fact_extraction_prompt` | Custom prompt for memory processing | None |
| `custom_update_memory_prompt` | Custom prompt for update memory | None |
</Accordion>
<Accordion title="Complete Configuration Example">
@@ -405,7 +430,8 @@ config = {
},
"history_db_path": "/path/to/history.db",
"version": "v1.1",
"custom_prompt": "Optional custom prompt for memory processing"
"custom_fact_extraction_prompt": "Optional custom prompt for fact extraction for memory",
"custom_update_memory_prompt": "Optional custom prompt for update memory"
}
```
</Accordion>
+285 -169
View File
@@ -379,7 +379,118 @@
}
},
"/v1/exports/": {
"get": {
"post": {
"tags": [
"exports"
],
"summary": "Create an export job with schema",
"description": "Create a structured export of memories based on a provided schema.",
"operationId": "exports_create",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["schema"],
"properties": {
"schema": {
"type": "object",
"description": "Schema definition for the export"
},
"filters": {
"type": "object",
"properties": {
"user_id": {"type": "string"},
"agent_id": {"type": "string"},
"app_id": {"type": "string"},
"run_id": {"type": "string"}
},
"description": "Filters to apply while exporting memories. Available fields are: user_id, agent_id, app_id, run_id."
},
"org_id": {
"type": "string",
"description": "Filter exports by organization ID"
},
"project_id": {
"type": "string",
"description": "Filter exports by project ID"
}
}
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Export created successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Memory export request received. The export will be ready in a few seconds."
},
"id": {
"type": "string",
"format": "uuid",
"example": "550e8400-e29b-41d4-a716-446655440000"
}
},
"required": ["message", "id"]
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Schema is required and must be a valid object"
}
}
}
}
}
}
},
"x-code-samples": [
{
"lang": "Python",
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"your_project_id\")\n\njson_schema = {pydantic_json_schema}\nfilters = {\n \"AND\": [\n {\"user_id\": \"alex\"}\n ]\n}\n\nresponse = client.create_memory_export(\n schema=json_schema,\n filters=filters\n)\nprint(response)"
},
{
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst jsonSchema = {pydantic_json_schema};\nconst filters = {\n AND: [\n {user_id: 'alex'}\n ]\n};\n\nclient.createMemoryExport({\n schema: jsonSchema,\n filters: filters\n})\n .then(result => console.log(result))\n .catch(error => console.error(error));"
},
{
"lang": "cURL",
"source": "curl --request POST \\\n --url 'https://api.mem0.ai/v1/exports/' \\\n --header 'Authorization: Token <api-key>' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"schema\": {pydantic_json_schema},\n \"filters\": {\n \"AND\": [\n {\"user_id\": \"alex\"}\n ]\n }\n }'"
},
{
"lang": "Go",
"source": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\turl := \"https://api.mem0.ai/v1/exports/\"\n\n\tfilters := map[string]interface{}{\n\t\t\"AND\": []map[string]interface{}{\n\t\t\t{\"user_id\": \"alex\"},\n\t\t},\n\t}\n\n\tdata := map[string]interface{}{\n\t\t\"schema\": map[string]interface{}{}, // Your schema here\n\t\t\"filters\": filters,\n\t}\n\n\tjsonData, _ := json.Marshal(data)\n\n\treq, _ := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonData))\n\n\treq.Header.Add(\"Authorization\", \"Token <api-key>\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(string(body))\n}"
},
{
"lang": "PHP",
"source": "<?php\n\n$curl = curl_init();\n\n$filters = [\n 'AND' => [\n ['user_id' => 'alex']\n ]\n];\n\n$data = array(\n \"schema\" => array(), // Your schema here\n \"filters\" => $filters\n);\n\ncurl_setopt_array($curl, [\n CURLOPT_URL => \"https://api.mem0.ai/v1/exports/\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode($data),\n CURLOPT_HTTPHEADER => [\n \"Authorization: Token <api-key>\",\n \"Content-Type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
},
{
"lang": "Java",
"source": "import com.mashape.unirest.http.HttpResponse;\nimport com.mashape.unirest.http.JsonNode;\nimport com.mashape.unirest.http.Unirest;\nimport org.json.JSONObject;\nimport org.json.JSONArray;\n\nJSONObject filters = new JSONObject()\n .put(\"AND\", new JSONArray()\n .put(new JSONObject().put(\"user_id\", \"alex\")));\n\nJSONObject data = new JSONObject()\n .put(\"schema\", new JSONObject()) // Your schema here\n .put(\"filters\", filters);\n\nHttpResponse<JsonNode> response = Unirest.post(\"https://api.mem0.ai/v1/exports/\")\n .header(\"Authorization\", \"Token <api-key>\")\n .header(\"Content-Type\", \"application/json\")\n .body(data.toString())\n .asJson();"
}
]
}
},
"/v1/exports/get": {
"post": {
"tags": [
"exports"
],
@@ -388,36 +499,20 @@
"operationId": "exports_list",
"parameters": [
{
"name": "user_id",
"in": "query",
"schema": {
"type": "string"
},
"description": "Filter exports by user ID"
},
{
"name": "run_id",
"in": "query",
"schema": {
"type": "string"
},
"description": "Filter exports by run ID"
},
{
"name": "session_id",
"in": "query",
"schema": {
"type": "string"
},
"description": "Filter exports by session ID"
},
{
"name": "app_id",
"in": "query",
"schema": {
"type": "string"
},
"description": "Filter exports by app ID"
"name": "filters",
"in": "query",
"schema": {
"type": "object",
"properties": {
"user_id": {"type": "string"},
"agent_id": {"type": "string"},
"app_id": {"type": "string"},
"run_id": {"type": "string"},
"created_at": {"type": "string"},
"updated_at": {"type": "string"}
},
"description": "Filters to apply while exporting memories. Available fields are: user_id, agent_id, app_id, run_id, created_at, updated_at."
}
},
{
"name": "org_id",
@@ -484,145 +579,30 @@
"x-code-samples": [
{
"lang": "Python",
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"project_id\")\n\nresponse = client.get_memory_export(user_id=\"your_user_id\")\nprint(response)"
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"project_id\")\n\nfilters = {\n \"AND\": [\n {\"created_at\": {\"gte\": \"2024-07-10\", \"lte\": \"2024-07-20\"}},\n {\"user_id\": \"alex\"}\n ]\n}\n\nresponse = client.get_memory_export(filters=filters)\nprint(response)"
},
{
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\n// Get memory export\nclient.getMemoryExport({ user_id: \"your_user_id\" })\n .then(result => console.log(result))\n .catch(error => console.error(error));"
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst filters = {\n AND: [\n {created_at: {gte: \"2024-07-10\", lte: \"2024-07-20\"}},\n {user_id: \"alex\"}\n ]\n};\n\n// Get memory export\nclient.getMemoryExport({ filters })\n .then(result => console.log(result))\n .catch(error => console.error(error));"
},
{
"lang": "cURL",
"source": "curl --request GET \\\n --url 'https://api.mem0.ai/v1/exports/?user_id=your_user_id' \\\n --header 'Authorization: Token <api-key>'"
"source": "curl --request GET \\\n --url 'https://api.mem0.ai/v1/exports/?filters={\"AND\":[{\"created_at\":{\"gte\":\"2024-07-10\",\"lte\":\"2024-07-20\"}},{\"user_id\":\"alex\"}]}' \\\n --header 'Authorization: Token <api-key>'"
},
{
"lang": "Go",
"source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\turl := \"https://api.mem0.ai/v1/exports/?user_id=your_user_id\"\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Authorization\", \"Token <api-key>\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(string(body))\n}"
"source": "package main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\tfilters := `{\"AND\":[{\"created_at\":{\"gte\":\"2024-07-10\",\"lte\":\"2024-07-20\"}},{\"user_id\":\"alex\"}]}`\n\turl := fmt.Sprintf(\"https://api.mem0.ai/v1/exports/?filters=%s\", filters)\n\n\treq, _ := http.NewRequest(\"GET\", url, nil)\n\n\treq.Header.Add(\"Authorization\", \"Token <api-key>\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(string(body))\n}"
},
{
"lang": "PHP",
"source": "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, [\n CURLOPT_URL => \"https://api.mem0.ai/v1/exports/?user_id=your_user_id\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"GET\",\n CURLOPT_HTTPHEADER => [\n \"Authorization: Token <api-key>\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
"source": "<?php\n\n$curl = curl_init();\n\n$filters = urlencode('{\"AND\":[{\"created_at\":{\"gte\":\"2024-07-10\",\"lte\":\"2024-07-20\"}},{\"user_id\":\"alex\"}]}');\n\ncurl_setopt_array($curl, [\n CURLOPT_URL => \"https://api.mem0.ai/v1/exports/?filters=\" . $filters,\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"GET\",\n CURLOPT_HTTPHEADER => [\n \"Authorization: Token <api-key>\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
},
{
"lang": "Java",
"source": "HttpResponse<String> response = Unirest.get(\"https://api.mem0.ai/v1/exports/?user_id=your_user_id\")\n .header(\"Authorization\", \"Token <api-key>\")\n .asString();"
"source": "String filters = \"{\\\"AND\\\":[{\\\"created_at\\\":{\\\"gte\\\":\\\"2024-07-10\\\",\\\"lte\\\":\\\"2024-07-20\\\"}},{\\\"user_id\\\":\\\"alex\\\"}]}\";\n\nHttpResponse<String> response = Unirest.get(\"https://api.mem0.ai/v1/exports/?filters=\" + filters)\n .header(\"Authorization\", \"Token <api-key>\")\n .asString();"
}
]
},
"post": {
"tags": [
"exports"
],
"summary": "Create an export job with schema",
"description": "Create a structured export of memories based on a provided schema.",
"operationId": "exports_create",
"requestBody": {
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["schema"],
"properties": {
"schema": {
"type": "object",
"description": "Schema definition for the export"
},
"user_id": {
"type": "string",
"description": "Filter exports by user ID"
},
"run_id": {
"type": "string",
"description": "Filter exports by run ID"
},
"session_id": {
"type": "string",
"description": "Filter exports by session ID"
},
"app_id": {
"type": "string",
"description": "Filter exports by app ID"
},
"org_id": {
"type": "string",
"description": "Filter exports by organization ID"
},
"project_id": {
"type": "string",
"description": "Filter exports by project ID"
}
}
}
}
},
"required": true
},
"responses": {
"201": {
"description": "Export created successfully",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Memory export request received. The export will be ready in a few seconds."
},
"id": {
"type": "string",
"format": "uuid",
"example": "550e8400-e29b-41d4-a716-446655440000"
}
},
"required": ["message", "id"]
}
}
}
},
"400": {
"description": "Bad Request",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"message": {
"type": "string",
"example": "Schema is required and must be a valid object"
}
}
}
}
}
}
},
"x-code-samples": [
{
"lang": "Python",
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"your_project_id\")\n\njson_schema = {pydantic_json_schema}\n\nresponse = client.create_memory_export(\n schema=json_schema,\n user_id=\"your_user_id\"\n)\nprint(response)"
},
{
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst jsonSchema = {pydantic_json_schema};\n\nclient.createMemoryExport({\n schema: jsonSchema,\n user_id: \"your_user_id\"\n})\n .then(result => console.log(result))\n .catch(error => console.error(error));"
},
{
"lang": "cURL",
"source": "curl --request POST \\\n --url 'https://api.mem0.ai/v1/exports/' \\\n --header 'Authorization: Token <api-key>' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"schema\": {pydantic_json_schema},\n \"user_id\": \"your_user_id\"\n }'"
},
{
"lang": "Go",
"source": "package main\n\nimport (\n\t\"bytes\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\turl := \"https://api.mem0.ai/v1/exports/\"\n\n\tdata := map[string]interface{}{\n\t\t\"schema\": map[string]interface{}{}, // Your schema here\n\t\t\"user_id\": \"user123\",\n\t}\n\n\tjsonData, _ := json.Marshal(data)\n\n\treq, _ := http.NewRequest(\"POST\", url, bytes.NewBuffer(jsonData))\n\n\treq.Header.Add(\"Authorization\", \"Token <api-key>\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(string(body))\n}"
},
{
"lang": "PHP",
"source": "<?php\n\n$curl = curl_init();\n\n$data = array(\n \"schema\" => array(), // Your schema here\n \"user_id\" => \"your_user_id\"\n);\n\ncurl_setopt_array($curl, [\n CURLOPT_URL => \"https://api.mem0.ai/v1/exports/\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => json_encode($data),\n CURLOPT_HTTPHEADER => [\n \"Authorization: Token <api-key>\",\n \"Content-Type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
},
{
"lang": "Java",
"source": "import com.mashape.unirest.http.HttpResponse;\nimport com.mashape.unirest.http.JsonNode;\nimport com.mashape.unirest.http.Unirest;\nimport org.json.JSONObject;\n\nJSONObject data = new JSONObject()\n .put(\"schema\", new JSONObject()) // Your schema here\n .put(\"user_id\", \"your_user_id\");\n\nHttpResponse<JsonNode> response = Unirest.post(\"https://api.mem0.ai/v1/exports/\")\n .header(\"Authorization\", \"Token <api-key>\")\n .header(\"Content-Type\", \"application/json\")\n .body(data.toString())\n .asJson();"
}
]
}
},
"/v1/memories/": {
"get": {
@@ -783,6 +763,14 @@
"title": "Immutable",
"default": false
},
"expiration_date": {
"type": "string",
"format": "date-time",
"description": "The date and time when the memory will expire. Format: YYYY-MM-DD",
"title": "Expiration date",
"nullable": true,
"default": null
},
"organization": {
"type": "string"
},
@@ -932,27 +920,27 @@
"x-code-samples": [
{
"lang": "Python",
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"your_project_id\")\n\nmessages = [\n {\"role\": \"user\", \"content\": \"<user-message>\"},\n {\"role\": \"assistant\", \"content\": \"<assistant-response>\"}\n]\n\nclient.add(messages, user_id=\"<user-id>\")"
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\n\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"your_project_id\")\n\nmessages = [\n {\"role\": \"user\", \"content\": \"<user-message>\"},\n {\"role\": \"assistant\", \"content\": \"<assistant-response>\"}\n]\n\nclient.add(messages, user_id=\"<user-id>\", version=\"v2\")"
},
{
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst messages = [\n { role: \"user\", content: \"Hi, I'm Alex. I'm a vegetarian and I'm allergic to nuts.\" },\n { role: \"assistant\", content: \"Hello Alex! I've noted that you're a vegetarian and have a nut allergy. I'll keep this in mind for any food-related recommendations or discussions.\" }\n];\n\nclient.add(messages, { user_id: \"<user_id>\" })\n .then(result => console.log(result))\n .catch(error => console.error(error));"
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst messages = [\n { role: \"user\", content: \"Hi, I'm Alex. I'm a vegetarian and I'm allergic to nuts.\" },\n { role: \"assistant\", content: \"Hello Alex! I've noted that you're a vegetarian and have a nut allergy. I'll keep this in mind for any food-related recommendations or discussions.\" }\n];\n\nclient.add(messages, { user_id: \"<user_id>\", version: \"v2\" })\n .then(result => console.log(result))\n .catch(error => console.error(error));"
},
{
"lang": "cURL",
"source": "curl --request POST \\\n --url https://api.mem0.ai/v1/memories/ \\\n --header 'Authorization: Token <api-key>' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"messages\": [\n {}\n ],\n \"agent_id\": \"<string>\",\n \"user_id\": \"<string>\",\n \"app_id\": \"<string>\",\n \"run_id\": \"<string>\",\n \"metadata\": {},\n \"includes\": \"<string>\",\n \"excludes\": \"<string>\",\n \"infer\": true,\n \"custom_categories\": {}, \n \"org_id\": \"<string>\",\n \"project_id\": \"<string>\"\n}'"
"source": "curl --request POST \\\n --url https://api.mem0.ai/v1/memories/ \\\n --header 'Authorization: Token <api-key>' \\\n --header 'Content-Type: application/json' \\\n --data '{\n \"messages\": [\n {}\n ],\n \"agent_id\": \"<string>\",\n \"user_id\": \"<string>\",\n \"app_id\": \"<string>\",\n \"run_id\": \"<string>\",\n \"metadata\": {},\n \"includes\": \"<string>\",\n \"excludes\": \"<string>\",\n \"infer\": true,\n \"custom_categories\": {}, \n \"org_id\": \"<string>\",\n \"project_id\": \"<string>\",\n \"version\": \"v2\"\n}'"
},
{
"lang": "Go",
"source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.mem0.ai/v1/memories/\"\n\n\tpayload := strings.NewReader(\"{\n \\\"messages\\\": [\n {}\n ],\n \\\"agent_id\\\": \\\"<string>\\\",\n \\\"user_id\\\": \\\"<string>\\\",\n \\\"app_id\\\": \\\"<string>\\\",\n \\\"run_id\\\": \\\"<string>\\\",\n \\\"metadata\\\": {},\n \\\"includes\\\": \\\"<string>\\\",\n \\\"excludes\\\": \\\"<string>\\\",\n \\\"infer\\\": true,\n \\\"custom_categories\\\": {},\n \\\"org_id\\\": \\\"<string>\\\",\n \\\"project_id\\\": \\\"<string>\"\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Authorization\", \"Token <api-key>\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}"
"source": "package main\n\nimport (\n\t\"fmt\"\n\t\"strings\"\n\t\"net/http\"\n\t\"io/ioutil\"\n)\n\nfunc main() {\n\n\turl := \"https://api.mem0.ai/v1/memories/\"\n\n\tpayload := strings.NewReader(\"{\n \\\"messages\\\": [\n {}\n ],\n \\\"agent_id\\\": \\\"<string>\\\",\n \\\"user_id\\\": \\\"<string>\\\",\n \\\"app_id\\\": \\\"<string>\\\",\n \\\"run_id\\\": \\\"<string>\\\",\n \\\"metadata\\\": {},\n \\\"includes\\\": \\\"<string>\\\",\n \\\"excludes\\\": \\\"<string>\\\",\n \\\"infer\\\": true,\n \\\"custom_categories\\\": {},\n \\\"org_id\\\": \\\"<string>\\\",\n \\\"project_id\\\": \\\"<string>\",\n \\\"version\\\": \"v2\"\n}\")\n\n\treq, _ := http.NewRequest(\"POST\", url, payload)\n\n\treq.Header.Add(\"Authorization\", \"Token <api-key>\")\n\treq.Header.Add(\"Content-Type\", \"application/json\")\n\n\tres, _ := http.DefaultClient.Do(req)\n\n\tdefer res.Body.Close()\n\tbody, _ := ioutil.ReadAll(res.Body)\n\n\tfmt.Println(res)\n\tfmt.Println(string(body))\n\n}"
},
{
"lang": "PHP",
"source": "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, [\n CURLOPT_URL => \"https://api.mem0.ai/v1/memories/\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => \"{\n \\\"messages\\\": [\n {}\n ],\n \\\"agent_id\\\": \\\"<string>\\\",\n \\\"user_id\\\": \\\"<string>\\\",\n \\\"app_id\\\": \\\"<string>\\\",\n \\\"run_id\\\": \\\"<string>\\\",\n \\\"metadata\\\": {},\n \\\"includes\\\": \\\"<string>\\\",\n \\\"excludes\\\": \\\"<string>\\\",\n \\\"infer\\\": true,\n \\\"custom_categories\\\": {}, \n \\\"org_id\\\": \\\"<string>\\\",\n \\\"project_id\\\": \\\"<string>\"\n}\",\n CURLOPT_HTTPHEADER => [\n \"Authorization: Token <api-key>\",\n \"Content-Type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
"source": "<?php\n\n$curl = curl_init();\n\ncurl_setopt_array($curl, [\n CURLOPT_URL => \"https://api.mem0.ai/v1/memories/\",\n CURLOPT_RETURNTRANSFER => true,\n CURLOPT_ENCODING => \"\",\n CURLOPT_MAXREDIRS => 10,\n CURLOPT_TIMEOUT => 30,\n CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,\n CURLOPT_CUSTOMREQUEST => \"POST\",\n CURLOPT_POSTFIELDS => \"{\n \\\"messages\\\": [\n {}\n ],\n \\\"agent_id\\\": \\\"<string>\\\",\n \\\"user_id\\\": \\\"<string>\\\",\n \\\"app_id\\\": \\\"<string>\\\",\n \\\"run_id\\\": \\\"<string>\\\",\n \\\"metadata\\\": {},\n \\\"includes\\\": \\\"<string>\\\",\n \\\"excludes\\\": \\\"<string>\\\",\n \\\"infer\\\": true,\n \\\"custom_categories\\\": {}, \n \\\"org_id\\\": \\\"<string>\\\",\n \\\"project_id\\\": \\\"<string>\",\n \\\"version\\\": \"v2\"\n}\",\n CURLOPT_HTTPHEADER => [\n \"Authorization: Token <api-key>\",\n \"Content-Type: application/json\"\n ],\n]);\n\n$response = curl_exec($curl);\n$err = curl_error($curl);\n\ncurl_close($curl);\n\nif ($err) {\n echo \"cURL Error #:\" . $err;\n} else {\n echo $response;\n}"
},
{
"lang": "Java",
"source": "HttpResponse<String> response = Unirest.post(\"https://api.mem0.ai/v1/memories/\")\n .header(\"Authorization\", \"Token <api-key>\")\n .header(\"Content-Type\", \"application/json\")\n .body(\"{\n \\\"messages\\\": [\n {}\n ],\n \\\"agent_id\\\": \\\"<string>\\\",\n \\\"user_id\\\": \\\"<string>\\\",\n \\\"app_id\\\": \\\"<string>\\\",\n \\\"run_id\\\": \\\"<string>\\\",\n \\\"metadata\\\": {},\n \\\"includes\\\": \\\"<string>\\\",\n \\\"excludes\\\": \\\"<string>\\\",\n \\\"infer\\\": true,\n \\\"custom_categories\\\": {}, \n \\\"org_id\\\": \\\"<string>\\\",\n \\\"project_id\\\": \\\"<string>\"\n}\")\n .asString();"
"source": "HttpResponse<String> response = Unirest.post(\"https://api.mem0.ai/v1/memories/\")\n .header(\"Authorization\", \"Token <api-key>\")\n .header(\"Content-Type\", \"application/json\")\n .body(\"{\n \\\"messages\\\": [\n {}\n ],\n \\\"agent_id\\\": \\\"<string>\\\",\n \\\"user_id\\\": \\\"<string>\\\",\n \\\"app_id\\\": \\\"<string>\\\",\n \\\"run_id\\\": \\\"<string>\\\",\n \\\"metadata\\\": {},\n \\\"includes\\\": \\\"<string>\\\",\n \\\"excludes\\\": \\\"<string>\\\",\n \\\"infer\\\": true,\n \\\"custom_categories\\\": {}, \n \\\"org_id\\\": \\\"<string>\\\",\n \\\"project_id\\\": \\\"<string>\",\n \\\"version\\\": \"v2\"\n}\")\n .asString();"
}
],
"x-codegen-request-body-name": "data"
@@ -1183,6 +1171,14 @@
"title": "Immutable",
"default": false
},
"expiration_date": {
"type": "string",
"format": "date-time",
"description": "The date and time when the memory will expire. Format: YYYY-MM-DD",
"title": "Expiration date",
"nullable": true,
"default": null
},
"organization": {
"type": "string"
},
@@ -1324,6 +1320,14 @@
"title": "Immutable",
"default": false
},
"expiration_date": {
"type": "string",
"format": "date-time",
"description": "The date and time when the memory will expire. Format: YYYY-MM-DD",
"title": "Expiration date",
"nullable": true,
"default": null
},
"created_at": {
"type": "string",
"format": "date-time",
@@ -1367,11 +1371,11 @@
"x-code-samples": [
{
"lang": "Python",
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"your_project_id\")\n\nquery = \"Your search query here\"\n\nresults = client.search(query, user_id=\"<user_id>\", output_format=\"v1.0\")\nprint(results)"
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\nclient = MemoryClient(api_key=\"your_api_key\", org_id=\"your_org_id\", project_id=\"your_project_id\")\n\nquery = \"Your search query here\"\n\nresults = client.search(query, user_id=\"<user_id>\", output_format=\"v1.1\")\nprint(results)"
},
{
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst query = \"Your search query here\";\n\nclient.search(query, { user_id: \"<user_id>\", output_format: \"v1.0\" })\n .then(result => console.log(result))\n .catch(error => console.error(error));"
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\nconst query = \"Your search query here\";\n\nclient.search(query, { user_id: \"<user_id>\", output_format: \"v1.1\" })\n .then(result => console.log(result))\n .catch(error => console.error(error));"
},
{
"lang": "cURL",
@@ -1451,6 +1455,14 @@
"title": "Immutable",
"default": false
},
"expiration_date": {
"type": "string",
"format": "date-time",
"description": "The date and time when the memory will expire. Format: YYYY-MM-DD",
"title": "Expiration date",
"nullable": true,
"default": null
},
"created_at": {
"type": "string",
"format": "date-time",
@@ -1761,7 +1773,7 @@
},
{
"lang": "JavaScript",
"source": "const options = {\n method: 'PUT',\n headers: {\n 'Authorization': 'Token <api-key>',\n 'Content-Type': 'application/json'\n },\n body: JSON.stringify({\n text: 'Your updated memory text here'\n })\n};\n\nfetch('https://api.mem0.ai/v1/memories/{memory_id}/', options)\n .then(response => response.json())\n .then(response => console.log(response))\n .catch(err => console.error(err));"
"source": "// To use the JavaScript SDK, install the package:\n// npm i mem0ai\n\nimport MemoryClient from 'mem0ai';\nconst client = new MemoryClient({ apiKey: \"your-api-key\" });\n\n// Update a specific memory\nconst memory_id=<memory_id>\nconst message=\"Your updated memory message here\"\nclient.update(memory_id, message)\n .then(result => console.log(result))\n .catch(error => console.error(error));"
},
{
"lang": "cURL",
@@ -2074,6 +2086,95 @@
"x-codegen-request-body-name": "data"
}
},
"/v1/feedback/": {
"post": {
"tags": [
"feedback"
],
"description": "Submit feedback for a memory.",
"operationId": "submit_feedback",
"requestBody": {
"content": {
"application/json": {
"schema": {
"required": [
"memory_id"
],
"type": "object",
"properties": {
"memory_id": {
"type": "string",
"description": "ID of the memory to provide feedback for"
},
"feedback": {
"type": "string",
"enum": ["POSITIVE", "NEGATIVE", "VERY_NEGATIVE"],
"nullable": true,
"description": "Type of feedback"
},
"feedback_reason": {
"type": "string",
"nullable": true,
"description": "Reason for the feedback"
}
}
}
}
},
"required": true
},
"responses": {
"200": {
"description": "Successful operation",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"id": {
"type": "string",
"format": "uuid",
"description": "Feedback ID"
},
"feedback": {
"type": "string",
"enum": ["POSITIVE", "NEGATIVE", "VERY_NEGATIVE"],
"nullable": true,
"description": "Type of feedback"
},
"feedback_reason": {
"type": "string",
"nullable": true,
"description": "Reason for the feedback"
}
}
}
}
}
},
"400": {
"description": "Invalid request"
},
"401": {
"description": "Unauthorized"
}
},
"x-code-samples": [
{
"lang": "Python",
"source": "# To use the Python SDK, install the package:\n# pip install mem0ai\n\nfrom mem0 import MemoryClient\nclient = MemoryClient(api_key=\"your_api_key\")\n\n# Submit feedback for a memory\nfeedback = client.feedback(memory_id=\"memory_id\", feedback=\"POSITIVE\")\nprint(feedback)"
},
{
"lang": "JavaScript",
"source": "// To use the JavaScript SDK, install the package:\n// npm install mem0ai\n\nimport MemoryClient from 'mem0ai';\n\nconst client = new MemoryClient({ apiKey: 'your-api-key'});\n\nclient.feedback({\n memory_id: \"your-memory-id\", \n feedback: \"NEGATIVE\", \n feedback_reason: \"I don't like this memory because it is not relevant.\"\n})"
},
{
"lang": "cURL",
"source": "curl --request POST \\\n --url https://api.mem0.ai/v1/feedback/ \\\n --header 'Authorization: Token <api-key>' \\\n --header 'Content-Type: application/json' \\\n --data '{\"memory_id\": \"memory_id\", \"feedback\": \"POSITIVE\"}'"
}
]
}
},
"/api/v1/orgs/organizations/": {
"get": {
"tags": [
@@ -3112,7 +3213,7 @@
"type": "object",
"properties": {
"message": {
"type": "string",
"type": "string",
"example": "Unauthorized to create projects in this organization."
}
}
@@ -3478,7 +3579,7 @@
"description": "Unauthorized to modify this project",
"content": {
"application/json": {
"schema": {
"schema": {
"type": "object",
"properties": {
"message": {
@@ -4069,7 +4170,7 @@
},
{
"lang": "cURL",
"source": "curl -X PUT \"https://api.mem0.ai/v1/memories/batch/\" \\\n -H \"Authorization: Token your-api-key\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"memories\": [\n {\n \"memory_id\": \"285ed74b-6e05-4043-b16b-3abd5b533496\",\n \"text\": \"Watches football\"\n },\n {\n \"memory_id\": \"2c9bd859-d1b7-4d33-a6b8-94e0147c4f07\",\n \"text\": \"Likes to travel\"\n }\n ]\n }'"
"source": "curl -X PUT \"https://api.mem0.ai/v1/batch/\" \\\n -H \"Authorization: Token your-api-key\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"memories\": [\n {\n \"memory_id\": \"285ed74b-6e05-4043-b16b-3abd5b533496\",\n \"text\": \"Watches football\"\n },\n {\n \"memory_id\": \"2c9bd859-d1b7-4d33-a6b8-94e0147c4f07\",\n \"text\": \"Likes to travel\"\n }\n ]\n }'"
}
]
},
@@ -4146,7 +4247,7 @@
},
{
"lang": "cURL",
"source": "curl -X DELETE \"https://api.mem0.ai/v1/memories/batch/\" \\\n -H \"Authorization: Token your-api-key\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"delete_memories\": [\n {\n \"memory_id\": \"285ed74b-6e05-4043-b16b-3abd5b533496\"\n },\n {\n \"memory_id\": \"2c9bd859-d1b7-4d33-a6b8-94e0147c4f07\"\n }\n ]\n }'"
"source": "curl -X DELETE \"https://api.mem0.ai/v1/batch/\" \\\n -H \"Authorization: Token your-api-key\" \\\n -H \"Content-Type: application/json\" \\\n -d '{\n \"memories\": [\n {\n \"memory_id\": \"285ed74b-6e05-4043-b16b-3abd5b533496\"\n },\n {\n \"memory_id\": \"2c9bd859-d1b7-4d33-a6b8-94e0147c4f07\"\n }\n ]\n }'"
}
]
}
@@ -4772,10 +4873,11 @@
"default": true
},
"output_format": {
"description": "It two output formats: `v1.0` (default) and `v1.1`. To enable the latest format, which provides enhanced detail for each memory operation, set the output_format parameter to `v1.1`. Note that `v1.0` will be deprecated in version 0.1.35.",
"description": "It two output formats: `v1.0` (default) and `v1.1`. We recommend using `v1.1` as `v1.0` will be deprecated soon.",
"title": "Output format",
"type": "string",
"nullable": true
"nullable": true,
"default": "v1.0"
},
"custom_categories": {
"description": "A list of categories with category name and it's description.",
@@ -4798,6 +4900,13 @@
"type": "boolean",
"default": false
},
"expiration_date": {
"description": "The date and time when the memory will expire. Format: YYYY-MM-DD",
"title": "Expiration date",
"type": "string",
"nullable": true,
"default": null
},
"org_id": {
"description": "The unique identifier of the organization associated with this memory.",
"title": "Organization id",
@@ -4809,6 +4918,12 @@
"title": "Project id",
"type": "string",
"nullable": true
},
"version": {
"description": "The version of the memory to use. The default version is v1, which is deprecated. We recommend using v2 for new applications.",
"title": "Version",
"type": "string",
"nullable": true
}
}
},
@@ -4887,7 +5002,8 @@
"title": "Output format",
"type": "string",
"nullable": true,
"description": "The search method supports two output formats: `v1.0` (default) and `v1.1`."
"default": "v1.0",
"description": "The search method supports two output formats: `v1.0` (default) and `v1.1`. We recommend using `v1.1` as `v1.0` will be deprecated soon."
},
"org_id": {
"title": "Organization id",
+231 -359
View File
@@ -86,11 +86,7 @@ messages = [
{"role": "assistant", "content": "Hello Alex! I've noted that you're a vegetarian and have a nut allergy. I'll keep this in mind for any food-related recommendations or discussions."}
]
# The default output_format is v1.0
client.add(messages, user_id="alex", output_format="v1.0")
# To use the latest output_format, set the output_format parameter to "v1.1"
client.add(messages, user_id="alex", output_format="v1.1", metadata={"food": "vegan"})
client.add(messages, user_id="alex", metadata={"food": "vegan"})
```
```javascript JavaScript
@@ -98,7 +94,7 @@ const messages = [
{"role": "user", "content": "Hi, I'm Alex. I'm a vegetarian and I'm allergic to nuts."},
{"role": "assistant", "content": "Hello Alex! I've noted that you're a vegetarian and have a nut allergy. I'll keep this in mind for any food-related recommendations or discussions."}
];
client.add(messages, { user_id: "alex", output_format: "v1.1", metadata: { food: "vegan" } })
client.add(messages, { user_id: "alex", metadata: { food: "vegan" } })
.then(response => console.log(response))
.catch(error => console.error(error));
```
@@ -113,39 +109,13 @@ curl -X POST "https://api.mem0.ai/v1/memories/" \
{"role": "assistant", "content": "Hello Alex! I've noted that you're a vegetarian and have a nut allergy. I'll keep this in mind for any food-related recommendations or discussions."}
],
"user_id": "alex",
"output_format": "v1.1",
"metadata": {
"food": "vegan"
}
}'
```
```json Output (v1.0)
[
{
"id": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5",
"data": {
"memory": "Name is Alex"
},
"event": "ADD"
},
{
"id": "b2c3d4e5-f6g7-8h9i-j0k1-l2m3n4o5p6q7",
"data": {
"memory": "Is a vegetarian"
},
"event": "ADD"
},
{
"id": "c3d4e5f6-g7h8-9i0j-k1l2-m3n4o5p6q7r8",
"data": {
"memory": "Is allergic to nuts"
},
"event": "ADD"
}
]
```
```json Output (v1.1)
```json Output
{
"results": [
{
@@ -166,9 +136,6 @@ curl -X POST "https://api.mem0.ai/v1/memories/" \
</CodeGroup>
<Note> The `add` method offers support for two output formats: `v1.0` (default) and `v1.1`. To enable the latest format, which provides enhanced detail for each memory operation, set the `output_format` parameter to `v1.1`. </Note>
<Note>
Messages passed along with `user_id`, `run_id`, or `app_id` are stored as user memories, while messages from the assistant are excluded from memory. To store messages for the assistant, use `agent_id` exclusively and avoid including other IDs, such as user_id, alongside it. This ensures the memory is properly attributed to the assistant.
</Note>
@@ -190,11 +157,7 @@ messages = [
{"role": "assistant", "content": "Great! I'll remember that you're interested in vegetarian restaurants in Tokyo for your upcoming trip. I'll prepare a list for you in our next interaction."}
]
# The default output_format is v1.0
client.add(messages, user_id="alex123", run_id="trip-planning-2024", output_format="v1.0")
# To use the latest output_format, set the output_format parameter to "v1.1"
client.add(messages, user_id="alex123", run_id="trip-planning-2024", output_format="v1.1")
client.add(messages, user_id="alex", run_id="trip-planning-2024")
```
```javascript JavaScript
@@ -204,7 +167,7 @@ const messages = [
{"role": "user", "content": "Yes, please! Especially in Tokyo."},
{"role": "assistant", "content": "Great! I'll remember that you're interested in vegetarian restaurants in Tokyo for your upcoming trip. I'll prepare a list for you in our next interaction."}
];
client.add(messages, { user_id: "alex123", run_id: "trip-planning-2024", output_format: "v1.1" })
client.add(messages, { user_id: "alex", run_id: "trip-planning-2024" })
.then(response => console.log(response))
.catch(error => console.error(error));
```
@@ -220,32 +183,12 @@ curl -X POST "https://api.mem0.ai/v1/memories/" \
{"role": "user", "content": "Yes, please! Especially in Tokyo."},
{"role": "assistant", "content": "Great! I'll remember that you're interested in vegetarian restaurants in Tokyo for your upcoming trip. I'll prepare a list for you in our next interaction."}
],
"user_id": "alex123",
"run_id": "trip-planning-2024",
"output_format": "v1.1"
"user_id": "alex",
"run_id": "trip-planning-2024"
}'
```
```json Output (v1.0)
[
{
"id": "f2968654-5cd8-4d58-9f40-57ee339846b6",
"data": {
"memory": "Interested in vegetarian restaurants in Tokyo"
},
"event": "ADD"
},
{
"id": "f2968654-5cd8-4d58-9f40-57ee339846b6",
"data": {
"memory": "Planning a trip to Japan next month"
},
"event": "ADD"
}
]
```
```json Output (v1.1)
```json Output
{
"results": [
{
@@ -273,11 +216,7 @@ messages = [
{"role": "assistant", "content": "Understood. I'm an AI tutor with a personality. My name is Alice."}
]
# The default output_format is v1.0
client.add(messages, agent_id="ai-tutor", output_format="v1.0")
# To use the latest output_format, set the output_format parameter to "v1.1"
client.add(messages, agent_id="ai-tutor", output_format="v1.1")
client.add(messages, agent_id="ai-tutor")
```
```javascript JavaScript
@@ -285,7 +224,7 @@ const messages = [
{"role": "system", "content": "You are an AI tutor with a personality. Give yourself a name for the user."},
{"role": "assistant", "content": "Understood. I'm an AI tutor with a personality. My name is Alice."}
];
client.add(messages, { agent_id: "ai-tutor", output_format: "v1.1" })
client.add(messages, { agent_id: "ai-tutor" })
.then(response => console.log(response))
.catch(error => console.error(error));
```
@@ -299,38 +238,11 @@ curl -X POST "https://api.mem0.ai/v1/memories/" \
{"role": "system", "content": "You are an AI tutor with a personality. Give yourself a name for the user."},
{"role": "assistant", "content": "Understood. I'm an AI tutor with a personality. My name is Alice."}
],
"agent_id": "ai-tutor",
"output_format": "v1.1"
"agent_id": "ai-tutor"
}'
```
```json Output (v1.0)
[
{
"id": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5",
"data": {
"memory": "Name is Alex"
},
"event": "ADD"
},
{
"id": "b2c3d4e5-f6g7-8h9i-j0k1-l2m3n4o5p6q7",
"data": {
"memory": "Is a vegetarian"
},
"event": "ADD"
},
{
"id": "c3d4e5f6-g7h8-9i0j-k1l2-m3n4o5p6q7r8",
"data": {
"memory": "Is allergic to nuts"
},
"event": "ADD"
}
]
```
```json Output (v1.1)
```json Output
{
"results": [
{
@@ -397,21 +309,109 @@ curl -X POST "https://api.mem0.ai/v1/memories/" \
```
```json Output
[
{
'id': 'c57abfa2-f0ac-48af-896a-21728dbcecee0',
'data': {'memory': 'Travelling to San Francisco'},
'event': 'ADD'
},
{ 'id': '0e8c003f-7db7-426a-9fdc-a46f9331a0c2',
'data': {'memory': 'Going to Dubai next month'},
'event': 'ADD'
}
]
{
"results": [
{
"id": "c57abfa2-f0ac-48af-896a-21728dbcecee0",
"data": {"memory": "Travelling to San Francisco"},
"event": "ADD"
},
{
"id": "0e8c003f-7db7-426a-9fdc-a46f9331a0c2",
"data": {"memory": "Going to Dubai next month"},
"event": "ADD"
}
]
}
```
</CodeGroup>
#### Setting Memory Expiration Date
You can set an expiration date for memories, after which they will no longer be retrieved in searches. This is useful for creating temporary memories or memories that are only relevant for a specific time period.
<CodeGroup>
```python Python
import datetime
messages = [
{
"role": "user",
"content": "I'll be in San Francisco until August 31st."
}
]
# Set an expiration date for this memory
client.add(messages=messages, user_id="alex", expiration_date=str(datetime.datetime.now().date() + datetime.timedelta(days=30)))
# You can also use an explicit date string
client.add(messages=messages, user_id="alex", expiration_date="2023-08-31")
```
```javascript JavaScript
const messages = [
{
"role": "user",
"content": "I'll be in San Francisco until August 31st."
}
];
// Set an expiration date 30 days from now
const expirationDate = new Date();
expirationDate.setDate(expirationDate.getDate() + 30);
client.add(messages, {
user_id: "alex",
expiration_date: expirationDate.toISOString().split('T')[0]
})
.then(response => console.log(response))
.catch(error => console.error(error));
// You can also use an explicit date string
client.add(messages, {
user_id: "alex",
expiration_date: "2023-08-31"
})
.then(response => console.log(response))
.catch(error => console.error(error));
```
```bash cURL
curl -X POST "https://api.mem0.ai/v1/memories/" \
-H "Authorization: Token your-api-key" \
-H "Content-Type: application/json" \
-d '{
"messages": [
{
"role": "user",
"content": "I'll be in San Francisco until August 31st."
}
],
"user_id": "alex",
"expiration_date": "2023-08-31"
}'
```
```json Output
{
"results": [
{
"id": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5",
"data": {
"memory": "In San Francisco until August 31st"
},
"event": "ADD"
}
]
}
```
</CodeGroup>
<Note>
Once a memory reaches its expiration date, it won't be included in search or get results.
</Note>
#### Monitor Memories
@@ -432,11 +432,7 @@ Pass user messages, interactions, and queries into our search method to retrieve
```python Python
query = "What should I cook for dinner today?"
# The default output_format is v1.0
client.search(query, user_id="alex", output_format="v1.0")
# To use the latest output_format, set the output_format parameter to "v1.1"
client.search(query, user_id="alex", output_format="v1.1")
client.search(query, user_id="alex")
```
```javascript JavaScript
@@ -457,22 +453,7 @@ curl -X POST "https://api.mem0.ai/v1/memories/search/" \
}'
```
```json Output (v1.0)
[
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
```
```json Output (v1.1)
```json Output
{
"results": [
{
@@ -482,6 +463,7 @@ curl -X POST "https://api.mem0.ai/v1/memories/search/" \
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
@@ -519,18 +501,21 @@ curl -X POST "https://api.mem0.ai/v1/memories/search/?version=v2" \
```
```json Output
[
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
{
"results": [
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
}
```
</CodeGroup>
@@ -609,18 +594,21 @@ curl -X POST "https://api.mem0.ai/v1/memories/search/?version=v2" \
```
```json Output
[
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": null,
"categories": ["food_preferences"],
"immutable": false,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
{
"results": [
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": null,
"categories": ["food_preferences"],
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
}
```
</CodeGroup>
@@ -674,18 +662,21 @@ curl -X POST "https://api.mem0.ai/v1/memories/search/?version=v2" \
```
```json Output
[
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": null,
"categories": ["food_preferences"],
"immutable": false,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
{
"results": [
{
"id": "7f165f7e-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": null,
"categories": ["food_preferences"],
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
}
```
</CodeGroup>
@@ -748,18 +739,21 @@ curl -X POST "https://api.mem0.ai/v1/memories/search/?version=v2" \
```
```json Output
[
{
"id": "654fee-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
{
"results": [
{
"id": "654fee-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
}
```
</CodeGroup>
@@ -843,46 +837,13 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&page=1&page_size=50"
-H "Authorization: Token your-api-key"
```
```json Output (v1.0)
{
"count": 204,
"next": "https://api.mem0.ai/v1/memories/?user_id=alex&page=2&page_size=50",
"previous": null,
"results": [
{
"id":"f38b689d-6b24-45b7-bced-17fbb4d8bac7",
"memory":"是素食主义者,对坚果过敏。",
"agent_id":"travel-assistant",
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":None,
"immutable": false,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories":None
},
{
"id":"0a14d8f0-e364-4f5c-b305-10da1f0d0878",
"memory":"Will maintain personalized travel preferences for each user. Provide customized recommendations based on dietary restrictions, interests, and past interactions.",
"agent_id":"travel-assistant",
"hash":"35a305373d639b0bffc6c2a3e2eb4244",
"metadata":"None",
"immutable": false,
"created_at":"2024-07-26T00:31:03.543759-07:00",
"updated_at":"2024-07-26T00:31:03.543778-07:00",
"categories":None
}
... (remaining 48 memories)
]
}
```
```json Output (v1.1)
{
"count": 204,
"next": "https://api.mem0.ai/v1/memories/?user_id=alex&output_format=v1.1&page=2&page_size=50",
"previous": null,
"results": {
"results": [
"results":
[
{
"id":"f38b689d-6b24-45b7-bced-17fbb4d8bac7",
"memory":"是素食主义者,对坚果过敏。",
@@ -890,6 +851,7 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&page=1&page_size=50"
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":None,
"immutable": false,
"expiration_date": null,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories":None
@@ -901,13 +863,13 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&page=1&page_size=50"
"hash":"35a305373d639b0bffc6c2a3e2eb4244",
"metadata":"None",
"immutable": false,
"expiration_date": null,
"created_at":"2024-07-26T00:31:03.543759-07:00",
"updated_at":"2024-07-26T00:31:03.543778-07:00",
"categories":None
}
... (remaining 48 memories)
]
}
]
}
```
@@ -932,46 +894,13 @@ curl -X GET "https://api.mem0.ai/v1/memories/?agent_id=ai-tutor&page=1&page_size
-H "Authorization: Token your-api-key"
```
```json Output (v1.0)
{
"count": 78,
"next": "https://api.mem0.ai/v1/memories/?agent_id=ai-tutor&page=2&page_size=50",
"previous": null,
"results": [
{
"id":"f38b689d-6b24-45b7-bced-17fbb4d8bac7",
"memory":"是素食主义者,对坚果过敏。",
"agent_id":"ai-tutor",
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":None,
"immutable": false,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories":None
},
{
"id":"0a14d8f0-e364-4f5c-b305-10da1f0d0878",
"memory":"My name is Alice.",
"agent_id":"ai-tutor",
"hash":"35a305373d639b0bffc6c2a3e2eb4244",
"metadata":None,
"immutable": false,
"created_at":"2024-07-26T00:31:03.543759-07:00",
"updated_at":"2024-07-26T00:31:03.543778-07:00",
"categories":None
}
... (remaining 48 memories)
]
}
```
```json Output (v1.1)
{
"count": 78,
"next": "https://api.mem0.ai/v1/memories/?agent_id=ai-tutor&output_format=v1.1&page=2&page_size=50",
"previous": null,
"results": {
"results": [
"results":
[
{
"id": "f38b689d-6b24-45b7-bced-17fbb4d8bac7",
"memory": "是素食主义者,对坚果过敏。",
@@ -979,6 +908,7 @@ curl -X GET "https://api.mem0.ai/v1/memories/?agent_id=ai-tutor&page=1&page_size
"hash": "62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":None,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-25T23:57:00.108347-07:00",
"updated_at": "2024-07-25T23:57:00.108367-07:00"
},
@@ -989,12 +919,12 @@ curl -X GET "https://api.mem0.ai/v1/memories/?agent_id=ai-tutor&page=1&page_size
"hash": "35a305373d639b0bffc6c2a3e2eb4244",
"metadata":None,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-26T00:31:03.543759-07:00",
"updated_at": "2024-07-26T00:31:03.543778-07:00"
}
... (remaining 48 memories)
]
}
]
}
```
</CodeGroup>
@@ -1004,78 +934,35 @@ curl -X GET "https://api.mem0.ai/v1/memories/?agent_id=ai-tutor&page=1&page_size
<CodeGroup>
```python Python
short_term_memories = client.get_all(user_id="alex123", run_id="trip-planning-2024", page=1, page_size=50)
short_term_memories = client.get_all(user_id="alex", run_id="trip-planning-2024", page=1, page_size=50)
```
```javascript JavaScript
client.getAll({ user_id: "alex123", run_id: "trip-planning-2024", page: 1, page_size: 50 })
client.getAll({ user_id: "alex", run_id: "trip-planning-2024", page: 1, page_size: 50 })
.then(memories => console.log(memories))
.catch(error => console.error(error));
```
```bash cURL
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&run_id=trip-planning-2024&page=1&page_size=50" \
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&run_id=trip-planning-2024&page=1&page_size=50" \
-H "Authorization: Token your-api-key"
```
```json Output (v1.0)
```json Output
{
"count": 18,
"next": null,
"previous": null,
"results": [
{
"id":"06d8df63-7bd2-4fad-9acb-60871bcecee0",
"memory":"Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id":"alex123",
"hash":"d2088c936e259f2f5d2d75543d31401c",
"metadata":None,
"immutable": false,
"created_at":"2024-07-26T00:25:16.566471-07:00",
"updated_at":"2024-07-26T00:25:16.566492-07:00",
"categories":None
},
{
"id":"b4229775-d860-4ccb-983f-0f628ca112f5",
"memory":"Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id":"alex123",
"hash":"d2088c936e259f2f5d2d75543d31401c",
"metadata":None,
"immutable": false,
"created_at":"2024-07-26T00:33:20.350542-07:00",
"updated_at":"2024-07-26T00:33:20.350560-07:00",
"categories":None
},
{
"id":"df1aca24-76cf-4b92-9f58-d03857efcb64",
"memory":"Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id":"alex123",
"hash":"d2088c936e259f2f5d2d75543d31401c",
"metadata":None,
"immutable": false,
"created_at":"2024-07-26T00:51:09.642275-07:00",
"updated_at":"2024-07-26T00:51:09.642295-07:00",
"categories":None
}
... (remaining 15 memories)
]
}
```
```json Output (v1.1)
{
"count": 18,
"next": null,
"previous": null,
"results": {
"results": [
"results":
[
{
"id": "06d8df63-7bd2-4fad-9acb-60871bcecee0",
"memory": "Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id": "alex123",
"user_id": "alex",
"hash": "d2088c936e259f2f5d2d75543d31401c",
"metadata":None,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-26T00:25:16.566471-07:00",
"updated_at": "2024-07-26T00:25:16.566492-07:00",
"categories": ["food_preferences"]
@@ -1083,10 +970,11 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&run_id=trip-planni
{
"id": "b4229775-d860-4ccb-983f-0f628ca112f5",
"memory": "Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id": "alex123",
"user_id": "alex",
"hash": "d2088c936e259f2f5d2d75543d31401c",
"metadata":None,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-26T00:33:20.350542-07:00",
"updated_at": "2024-07-26T00:33:20.350560-07:00",
"categories": ["food_preferences"]
@@ -1094,17 +982,17 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&run_id=trip-planni
{
"id": "df1aca24-76cf-4b92-9f58-d03857efcb64",
"memory": "Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id": "alex123",
"user_id": "alex",
"hash": "d2088c936e259f2f5d2d75543d31401c",
"metadata":None,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-26T00:51:09.642275-07:00",
"updated_at": "2024-07-26T00:51:09.642295-07:00",
"categories": None
}
... (remaining 15 memories)
]
}
}
```
</CodeGroup>
@@ -1133,10 +1021,11 @@ curl -X GET "https://api.mem0.ai/v1/memories/582bbe6d-506b-48c6-a4c6-5df3b1e6342
{
"id":"06d8df63-7bd2-4fad-9acb-60871bcecee0",
"memory":"Planning a trip to Japan next month. Interested in vegetarian restaurants in Tokyo.",
"user_id":"alex123",
"user_id":"alex",
"hash":"d2088c936e259f2f5d2d75543d31401c",
"metadata":"None",
"immutable": false,
"expiration_date": null,
"created_at":"2024-07-26T00:25:16.566471-07:00",
"updated_at":"2024-07-26T00:25:16.566492-07:00",
"categories": ["travel"]
@@ -1152,55 +1041,55 @@ You can filter memories by their categories when using get_all:
```python Python
# Get memories with specific categories
memories = client.get_all(user_id="alex123", categories=["likes"])
memories = client.get_all(user_id="alex", categories=["likes"])
# Get memories with multiple categories
memories = client.get_all(user_id="alex123", categories=["likes", "food_preferences"])
memories = client.get_all(user_id="alex", categories=["likes", "food_preferences"])
# Custom pagination with categories
memories = client.get_all(user_id="alex123", categories=["likes"], page=1, page_size=50)
memories = client.get_all(user_id="alex", categories=["likes"], page=1, page_size=50)
# Get memories with specific keywords
memories = client.get_all(user_id="alex123", keywords="to play", page=1, page_size=50)
memories = client.get_all(user_id="alex", keywords="to play", page=1, page_size=50)
```
```javascript JavaScript
// Get memories with specific categories
client.getAll({ user_id: "alex123", categories: ["likes"] })
client.getAll({ user_id: "alex", categories: ["likes"] })
.then(memories => console.log(memories))
.catch(error => console.error(error));
// Get memories with multiple categories
client.getAll({ user_id: "alex123", categories: ["likes", "food_preferences"] })
client.getAll({ user_id: "alex", categories: ["likes", "food_preferences"] })
.then(memories => console.log(memories))
.catch(error => console.error(error));
// Custom pagination with categories
client.getAll({ user_id: "alex123", categories: ["likes"], page: 1, page_size: 50 })
client.getAll({ user_id: "alex", categories: ["likes"], page: 1, page_size: 50 })
.then(memories => console.log(memories))
.catch(error => console.error(error));
// Get memories with specific keywords
client.getAll({ user_id: "alex123", keywords: "to play", page: 1, page_size: 50 })
client.getAll({ user_id: "alex", keywords: "to play", page: 1, page_size: 50 })
.then(memories => console.log(memories))
.catch(error => console.error(error));
```
```bash cURL
# Get memories with specific categories
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&categories=likes" \
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&categories=likes" \
-H "Authorization: Token your-api-key"
# Get memories with multiple categories
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&categories=likes,food_preferences" \
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&categories=likes,food_preferences" \
-H "Authorization: Token your-api-key"
# Custom pagination with categories
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&categories=likes&page=1&page_size=50" \
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&categories=likes&page=1&page_size=50" \
-H "Authorization: Token your-api-key"
# Get memories with specific keywords
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&keywords=to play&page=1&page_size=50" \
curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex&keywords=to play&page=1&page_size=50" \
-H "Authorization: Token your-api-key"
```
@@ -1213,10 +1102,11 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&keywords=to play&p
{
"id": "06d8df63-7bd2-4fad-9acb-60871bcecee0",
"memory": "Likes pizza and pasta",
"user_id": "alex123",
"user_id": "alex",
"hash": "d2088c936e259f2f5d2d75543d31401c",
"metadata": null,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-26T00:25:16.566471-07:00",
"updated_at": "2024-07-26T00:25:16.566492-07:00",
"categories": ["likes", "food_preferences"]
@@ -1224,10 +1114,11 @@ curl -X GET "https://api.mem0.ai/v1/memories/?user_id=alex123&keywords=to play&p
{
"id": "b4229775-d860-4ccb-983f-0f628ca112f5",
"memory": "Likes to travel to beach destinations",
"user_id": "alex123",
"user_id": "alex",
"hash": "d2088c936e259f2f5d2d75543d31401c",
"metadata": null,
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-26T00:33:20.350542-07:00",
"updated_at": "2024-07-26T00:33:20.350560-07:00",
"categories": ["likes"]
@@ -1355,6 +1246,7 @@ curl -X GET "https://api.mem0.ai/v1/memories/?version=v2&page=1&page_size=50" \
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":null,
"immutable": false,
"expiration_date": null,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories": ["food_preferences"]
@@ -1375,6 +1267,7 @@ curl -X GET "https://api.mem0.ai/v1/memories/?version=v2&page=1&page_size=50" \
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":null,
"immutable": false,
"expiration_date": null,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories": ["food_preferences"]
@@ -1464,45 +1357,25 @@ curl -X GET "https://api.mem0.ai/v1/memories/?version=v2&page=1&page_size=50" \
}'
```
```json Output (Default)
```json Output
[
{
"id":"f38b689d-6b24-45b7-bced-17fbb4d8bac7",
"memory":"Name: Alex. Vegetarian. Allergic to nuts.",
"user_id":"alex",
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":{"food":"vegan"},
"immutable": false,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories": ["food_preferences"]
}
{
"id": "654fee-b411-4afe-b7e5-35789b72c4a5",
"memory": "Name: Alex. Vegetarian. Allergic to nuts.",
"user_id": "alex",
"metadata": {"food": "vegan"},
"categories": ["food_preferences"],
"immutable": false,
"expiration_date": null,
"created_at": "2024-07-20T01:30:36.275141-07:00",
"updated_at": "2024-07-20T01:30:36.275172-07:00"
}
]
```
```json Output (Paginated)
{
"count": 1,
"next": null,
"previous": null,
"results": [
{
"id":"f38b689d-6b24-45b7-bced-17fbb4d8bac7",
"memory":"Name: Alex. Vegetarian. Allergic to nuts.",
"user_id":"alex",
"hash":"62bc074f56d1f909f1b4c2b639f56f6a",
"metadata":{"food":"vegan"},
"immutable": false,
"created_at":"2024-07-25T23:57:00.108347-07:00",
"updated_at":"2024-07-25T23:57:00.108367-07:00",
"categories": ["food_preferences"]
}
]
}
```
</CodeGroup>
### 4.5 Memory History
Get history of how a memory has changed over time.
@@ -1585,7 +1458,7 @@ curl -X GET "https://api.mem0.ai/v1/memories/<memory-id-here>/history/" \
],
"old_memory":"None",
"new_memory":"Turned vegetarian.",
"user_id":"alex123456",
"user_id":"alex",
"event":"ADD",
"metadata":"None",
"created_at":"2024-07-26T01:02:41.737310-07:00",
@@ -1815,8 +1688,7 @@ response = client.batch_update(update_memories)
print(response)
```
```javascript JavaScript
const updateMemories = [
{"memory_id": "285ed74b-6e05-4043-b16b-3abd5b533496",
const updateMemories = [{"memory_id": "285ed74b-6e05-4043-b16b-3abd5b533496",
text: "Watches football"
},
{"memory_id": "2c9bd859-d1b7-4d33-a6b8-94e0147c4f07",
+13 -1
View File
@@ -1,4 +1,5 @@
import os
import warnings
from typing import Optional
from chromadb.utils.embedding_functions import OpenAIEmbeddingFunction
@@ -16,7 +17,18 @@ class OpenAIEmbedder(BaseEmbedder):
self.config.model = "text-embedding-ada-002"
api_key = self.config.api_key or os.environ["OPENAI_API_KEY"]
api_base = self.config.api_base or os.environ.get("OPENAI_API_BASE")
api_base = (
self.config.api_base
or os.environ.get("OPENAI_API_BASE")
or os.getenv("OPENAI_BASE_URL")
or "https://api.openai.com/v1"
)
if os.environ.get("OPENAI_API_BASE"):
warnings.warn(
"The environment variable 'OPENAI_API_BASE' is deprecated and will be removed in the 0.1.140. "
"Please use 'OPENAI_BASE_URL' instead.",
DeprecationWarning
)
if api_key is None and os.getenv("OPENAI_ORGANIZATION") is None:
raise ValueError("OPENAI_API_KEY or OPENAI_ORGANIZATION environment variables not provided") # noqa:E501
+14 -1
View File
@@ -1,5 +1,6 @@
import json
import os
import warnings
from typing import Any, Callable, Dict, Optional, Type, Union
from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler
@@ -58,7 +59,19 @@ class OpenAILlm(BaseLlm):
"model_kwargs": config.model_kwargs or {},
}
api_key = config.api_key or os.environ["OPENAI_API_KEY"]
base_url = config.base_url or os.environ.get("OPENAI_API_BASE", None)
base_url = (
config.base_url
or os.getenv("OPENAI_API_BASE")
or os.getenv("OPENAI_BASE_URL")
or "https://api.openai.com/v1"
)
if os.environ.get("OPENAI_API_BASE"):
warnings.warn(
"The environment variable 'OPENAI_API_BASE' is deprecated and will be removed in the 0.1.140. "
"Please use 'OPENAI_BASE_URL' instead.",
DeprecationWarning
)
if config.top_p:
kwargs["top_p"] = config.top_p
if config.default_headers:
+564 -87
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,6 +1,6 @@
[tool.poetry]
name = "embedchain"
version = "0.1.127"
version = "0.1.128"
description = "Simplest open source retrieval (RAG) framework"
authors = [
"Taranjeet Singh <taranjeet@embedchain.ai>",
@@ -91,7 +91,7 @@ exclude = '''
color = true
[tool.poetry.dependencies]
python = ">=3.9,<=3.13"
python = ">=3.9,<=3.13.2"
python-dotenv = "^1.0.0"
langchain = "^0.3.1"
requests = "^2.31.0"
@@ -139,7 +139,7 @@ alembic = "^1.13.1"
langchain-cohere = "^0.3.0"
langchain-community = "^0.3.1"
langchain-aws = {version = "^0.2.1", optional = true}
langsmith = "^0.1.17"
langsmith = "^0.3.18"
[tool.poetry.group.dev.dependencies]
black = "^23.3.0"
View File
+1 -1
View File
@@ -70,7 +70,7 @@ const retrieveMemories = (memories: any) => {
export async function POST(req: Request) {
const { messages, system, tools, userId } = await req.json();
const memories = await getMemories(messages, { user_id: userId });
const memories = await getMemories(messages, { user_id: userId, rerank: true, threshold: 0.1 });
const mem0Instructions = retrieveMemories(memories);
const result = streamText({
+15 -10
View File
@@ -6,7 +6,7 @@ import { Thread } from "@/components/assistant-ui/thread";
import { ThreadList } from "@/components/assistant-ui/thread-list";
import { useEffect, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { Sun, Moon, MessageSquare } from "lucide-react";
import { Sun, Moon, AlignJustify } from "lucide-react";
import { Button } from "@/components/ui/button";
import ThemeAwareLogo from "@/components/mem0/theme-aware-logo";
import Link from "next/link";
@@ -63,7 +63,7 @@ export const Assistant = () => {
return (
<AssistantRuntimeProvider runtime={runtime}>
<div className={`h-dvh bg-[#f8fafc] dark:bg-zinc-900 text-[#1e293b] ${isDarkMode ? "dark" : ""}`}>
<div className={`bg-[#f8fafc] dark:bg-zinc-900 text-[#1e293b] ${isDarkMode ? "dark" : ""}`}>
<header className="h-16 border-b border-[#e2e8f0] flex items-center justify-between px-4 sm:px-6 bg-white dark:bg-zinc-900 dark:border-zinc-800 dark:text-white">
<div className="flex items-center">
<Link href="/" className="flex items-center">
@@ -71,29 +71,34 @@ export const Assistant = () => {
</Link>
</div>
<div className="flex items-center">
<Button
<Button
variant="ghost"
size="sm"
onClick={() => setSidebarOpen(true)}
className="text-[#475569] dark:text-zinc-300 md:hidden"
>
<MessageSquare className="w-10 h-10" />
</Button>
<AlignJustify size={24} className="md:hidden" />
</Button>
<div className="md:flex items-center hidden">
<button
className="p-2 rounded-full hover:bg-[#eef2ff] dark:hover:bg-zinc-800 text-[#475569] dark:text-zinc-300"
onClick={toggleDarkMode}
aria-label="Toggle theme"
>
{isDarkMode ? <Sun className="w-5 h-5" /> : <Moon className="w-5 h-5" />}
{isDarkMode ? <Sun className="w-6 h-6" /> : <Moon className="w-6 h-6" />}
</button>
<GithubButton url="https://github.com/mem0ai/mem0/tree/main/examples" />
<Link href={"https://app.mem0.ai/"} target="_blank" className="py-2 ml-2 px-4 font-semibold dark:bg-zinc-100 dark:hover:bg-zinc-200 bg-zinc-800 text-white rounded-full hover:bg-zinc-900 dark:text-[#475569]">
Save Memories
</Link>
</div>
</header>
<div className="grid grid-cols-1 md:grid-cols-[260px_1fr] gap-x-0 h-[calc(100vh-8rem)] md:h-[calc(100vh-4rem)]">
<div className="grid grid-cols-1 md:grid-cols-[260px_1fr] gap-x-0 h-[calc(100dvh-4rem)]">
<ThreadList onResetUserId={resetUserId} isDarkMode={isDarkMode} />
<Thread sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} onResetUserId={resetUserId} isDarkMode={isDarkMode} />
<Thread sidebarOpen={sidebarOpen} setSidebarOpen={setSidebarOpen} onResetUserId={resetUserId} isDarkMode={isDarkMode} toggleDarkMode={toggleDarkMode} />
</div>
</div>
</AssistantRuntimeProvider>
@@ -19,14 +19,14 @@ import {
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import ThemeAwareLogo from "@/components/assistant-ui/theme-aware-logo";
import Link from "next/link";
// import ThemeAwareLogo from "@/components/assistant-ui/theme-aware-logo";
// import Link from "next/link";
interface ThreadListProps {
onResetUserId?: () => void;
isDarkMode: boolean;
}
export const ThreadList: FC<ThreadListProps> = ({ onResetUserId, isDarkMode }) => {
export const ThreadList: FC<ThreadListProps> = ({ onResetUserId }) => {
const [open, setOpen] = useState(false);
return (
@@ -79,13 +79,7 @@ export const ThreadList: FC<ThreadListProps> = ({ onResetUserId, isDarkMode }) =
</div>
<ThreadListItems />
</div>
<div>
<Link href="https://www.assistant-ui.com/" target="_blank" className="flex justify-center items-center gap-2">
<h1 className="text-sm text-[#475569] dark:text-zinc-300 text-center">built using</h1>
<ThemeAwareLogo width={24} height={24} isDarkMode={isDarkMode} />
<p className="text-md font-bold dark:text-zinc-300">assistant-ui</p>
</Link>
</div>
</ThreadListPrimitive.Root>
</div>
);
@@ -22,9 +22,12 @@ import {
SendHorizontalIcon,
ArchiveIcon,
PlusIcon,
Sun,
Moon,
SaveIcon,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { Dispatch, SetStateAction, useState } from "react";
import { Dispatch, SetStateAction, useState, useRef } from "react";
import { Button } from "@/components/ui/button";
import { ScrollArea } from "../ui/scroll-area";
import { TooltipIconButton } from "@/components/assistant-ui/tooltip-icon-button";
@@ -42,14 +45,14 @@ import {
AlertDialogTitle,
AlertDialogTrigger,
} from "@/components/ui/alert-dialog";
import GithubButton from "../mem0/github-button";
import Link from "next/link";
import ThemeAwareLogo from "./theme-aware-logo";
interface ThreadProps {
sidebarOpen: boolean;
setSidebarOpen: Dispatch<SetStateAction<boolean>>;
onResetUserId?: () => void;
isDarkMode: boolean;
toggleDarkMode: () => void;
}
export const Thread: FC<ThreadProps> = ({
@@ -57,12 +60,14 @@ export const Thread: FC<ThreadProps> = ({
setSidebarOpen,
onResetUserId,
isDarkMode,
toggleDarkMode
}) => {
const [resetDialogOpen, setResetDialogOpen] = useState(false);
const composerInputRef = useRef<HTMLTextAreaElement>(null);
return (
<ThreadPrimitive.Root
className="bg-[#f8fafc] dark:bg-zinc-900 box-border h-full flex flex-col overflow-hidden relative"
className="bg-[#f8fafc] dark:bg-zinc-900 box-border flex flex-col overflow-hidden relative h-[calc(100dvh-4rem)] pb-4 md:h-full"
style={{
["--thread-max-width" as string]: "42rem",
}}
@@ -78,13 +83,13 @@ export const Thread: FC<ThreadProps> = ({
{/* Mobile sidebar drawer */}
<div
className={cn(
"fixed inset-y-0 left-0 z-40 w-[85%] bg-white dark:bg-zinc-900 transform transition-transform duration-300 ease-in-out md:hidden",
"fixed inset-y-0 left-0 z-40 w-[75%] bg-white shadow-lg rounded-r-lg dark:bg-zinc-900 transform transition-transform duration-300 ease-in-out md:hidden",
sidebarOpen ? "translate-x-0" : "-translate-x-full"
)}
>
<div className="h-full flex flex-col">
<div className="flex items-center justify-between border-b dark:text-white border-[#e2e8f0] dark:border-zinc-800 p-4">
<h2 className="font-medium">Recent Chats</h2>
<h2 className="font-medium">Settings</h2>
<div className="flex items-center gap-2">
{onResetUserId && (
<AlertDialog
@@ -141,13 +146,44 @@ export const Thread: FC<ThreadProps> = ({
<div className="flex flex-col justify-between items-stretch gap-1.5 h-full dark:text-white">
<ThreadListPrimitive.Root className="flex flex-col items-stretch gap-1.5 h-full dark:text-white">
<ThreadListPrimitive.New asChild>
<div className="flex items-center flex-col gap-2 w-full">
<Button
className="hover:bg-[#eef2ff] dark:hover:bg-zinc-800 dark:data-[active]:bg-zinc-800 flex items-center justify-start gap-1 rounded-lg px-2.5 py-2 text-start bg-[#4f46e5] text-white dark:bg-[#6366f1]"
className="hover:bg-zinc-600 w-full dark:hover:bg-zinc-800 dark:data-[active]:bg-zinc-800 flex items-center justify-start gap-1 rounded-lg px-2.5 py-2 text-start bg-[#4f46e5] text-white dark:bg-[#6366f1]"
variant="default"
>
<PlusIcon className="w-4 h-4" />
New Thread
</Button>
<Button
className="hover:bg-zinc-600 w-full dark:hover:bg-zinc-700 dark:data-[active]:bg-zinc-800 flex items-center justify-start gap-1 rounded-lg px-2.5 py-2 text-start bg-zinc-800 text-white"
onClick={toggleDarkMode}
aria-label="Toggle theme"
>
{isDarkMode ? (
<div className="flex items-center gap-2">
<Sun className="w-6 h-6" />
<span>Toggle Light Mode</span>
</div>
) : (
<div className="flex items-center gap-2">
<Moon className="w-6 h-6" />
<span>Toggle Dark Mode</span>
</div>
)}
</Button>
<GithubButton url="https://github.com/mem0ai/mem0/tree/main/examples" className="w-full rounded-lg h-9 pl-2 text-sm font-semibold bg-zinc-800 dark:border-zinc-800 dark:text-white text-white hover:bg-zinc-900" text="View on Github" />
<Link
href={"https://app.mem0.ai/"}
target="_blank"
className="py-2 px-4 w-full rounded-lg h-9 pl-3 text-sm font-semibold dark:bg-zinc-800 dark:hover:bg-zinc-700 bg-zinc-800 text-white hover:bg-zinc-900 dark:text-white"
>
<span className="flex items-center gap-2">
<SaveIcon className="w-4 h-4" />
Save Memories
</span>
</Link>
</div>
</ThreadListPrimitive.New>
<div className="mt-4 mb-2">
<h2 className="text-sm font-medium text-[#475569] dark:text-zinc-300 px-2.5">
@@ -156,29 +192,18 @@ export const Thread: FC<ThreadProps> = ({
</div>
<ThreadListPrimitive.Items components={{ ThreadListItem }} />
</ThreadListPrimitive.Root>
<div>
<Link
href="https://www.assistant-ui.com/"
target="_blank"
className="flex justify-center items-center gap-2"
>
<h1 className="text-sm text-[#475569] dark:text-zinc-300 text-center">
built using
</h1>
<ThemeAwareLogo width={24} height={24} isDarkMode={isDarkMode} />
<p className="text-md font-bold dark:text-zinc-300">
assistant-ui
</p>
</Link>
</div>
</div>
</div>
</div>
</div>
<ScrollArea className="flex-1">
<div className="flex h-full flex-col items-center px-4 pt-8 justify-end">
<ThreadWelcome />
<ScrollArea className="flex-1 w-full">
<div className="flex h-full flex-col w-full items-center px-4 pt-8 justify-end">
<ThreadWelcome
composerInputRef={
composerInputRef as React.RefObject<HTMLTextAreaElement>
}
/>
<ThreadPrimitive.Messages
components={{
@@ -194,9 +219,13 @@ export const Thread: FC<ThreadProps> = ({
</div>
</ScrollArea>
<div className="sticky bottom-0 mt-3 flex w-full max-w-[var(--thread-max-width)] flex-col items-center justify-end rounded-t-lg bg-inherit px-4 pb-4 mx-auto">
<div className="sticky bottom-0 flex w-full max-w-[var(--thread-max-width)] flex-col items-center justify-end rounded-t-lg bg-inherit px-4 md:pb-4 mx-auto">
<ThreadScrollToBottom />
<Composer />
<Composer
composerInputRef={
composerInputRef as React.RefObject<HTMLTextAreaElement>
}
/>
</div>
</ThreadPrimitive.Root>
);
@@ -216,57 +245,74 @@ const ThreadScrollToBottom: FC = () => {
);
};
const ThreadWelcome: FC = () => {
interface ThreadWelcomeProps {
composerInputRef: React.RefObject<HTMLTextAreaElement>;
}
const ThreadWelcome: FC<ThreadWelcomeProps> = ({ composerInputRef }) => {
return (
<ThreadPrimitive.Empty>
<div className="flex w-full max-w-[var(--thread-max-width)] flex-grow flex-col">
<div className="flex w-full flex-grow flex-col items-center justify-start h-[calc(100vh-23rem)] md:h-[calc(100vh-18rem)]">
<div className="flex w-full flex-grow flex-col mt-8 md:h-[calc(100vh-15rem)]">
<div className="flex w-full flex-grow flex-col items-center justify-start">
<div className="flex flex-col items-center justify-center h-full">
<div className="text-2xl md:text-4xl font-bold text-[#1e293b] dark:text-white mb-2">
<div className="text-[2rem] leading-[1] tracking-[-0.02em] md:text-4xl font-bold text-[#1e293b] dark:text-white mb-2 text-center md:w-full w-5/6">
Mem0 - ChatGPT with memory
</div>
<p className="text-center text-sm text-[#1e293b] dark:text-white mb-2 w-3/4">
<p className="text-center text-md text-[#1e293b] dark:text-white mb-2 md:w-3/4 w-5/6">
A personalized AI chat app powered by Mem0 that remembers your
preferences, facts, and memories.
</p>
</div>
</div>
<div className="flex flex-col items-center justify-center">
<div className="flex flex-col items-center justify-center mt-16">
<p className="mt-4 font-medium text-[#1e293b] dark:text-white">
How can I help you today?
</p>
<ThreadWelcomeSuggestions />
<ThreadWelcomeSuggestions composerInputRef={composerInputRef} />
</div>
</div>
</ThreadPrimitive.Empty>
);
};
const ThreadWelcomeSuggestions: FC = () => {
interface ThreadWelcomeSuggestionsProps {
composerInputRef: React.RefObject<HTMLTextAreaElement>;
}
const ThreadWelcomeSuggestions: FC<ThreadWelcomeSuggestionsProps> = ({ composerInputRef }) => {
return (
<div className="mt-3 flex w-full items-stretch justify-center gap-4 dark:text-white">
<div className="mt-3 flex flex-col md:flex-row w-full md:items-stretch justify-center gap-4 dark:text-white items-center">
<ThreadPrimitive.Suggestion
className="hover:bg-[#eef2ff] dark:hover:bg-zinc-800 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-[2rem] border border-[#e2e8f0] dark:border-zinc-700 p-3 transition-colors ease-in"
className="hover:bg-[#eef2ff] w-full dark:hover:bg-zinc-800 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-[2rem] border border-[#e2e8f0] dark:border-zinc-700 p-3 transition-colors ease-in"
prompt="I like to travel to "
method="replace"
onClick={() => {
composerInputRef.current?.focus();
}}
>
<span className="line-clamp-2 text-ellipsis text-sm font-semibold">
Travel
</span>
</ThreadPrimitive.Suggestion>
<ThreadPrimitive.Suggestion
className="hover:bg-[#eef2ff] dark:hover:bg-zinc-800 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-[2rem] border border-[#e2e8f0] dark:border-zinc-700 p-3 transition-colors ease-in"
className="hover:bg-[#eef2ff] w-full dark:hover:bg-zinc-800 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-[2rem] border border-[#e2e8f0] dark:border-zinc-700 p-3 transition-colors ease-in"
prompt="I like to eat "
method="replace"
onClick={() => {
composerInputRef.current?.focus();
}}
>
<span className="line-clamp-2 text-ellipsis text-sm font-semibold">
Food
</span>
</ThreadPrimitive.Suggestion>
<ThreadPrimitive.Suggestion
className="hover:bg-[#eef2ff] dark:hover:bg-zinc-800 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-[2rem] border border-[#e2e8f0] dark:border-zinc-700 p-3 transition-colors ease-in"
className="hover:bg-[#eef2ff] w-full dark:hover:bg-zinc-800 flex max-w-sm grow basis-0 flex-col items-center justify-center rounded-[2rem] border border-[#e2e8f0] dark:border-zinc-700 p-3 transition-colors ease-in"
prompt="I am working on "
method="replace"
onClick={() => {
composerInputRef.current?.focus();
}}
>
<span className="line-clamp-2 text-ellipsis text-sm font-semibold">
Project details
@@ -276,7 +322,11 @@ const ThreadWelcomeSuggestions: FC = () => {
);
};
const Composer: FC = () => {
interface ComposerProps {
composerInputRef: React.RefObject<HTMLTextAreaElement>;
}
const Composer: FC<ComposerProps> = ({ composerInputRef }) => {
return (
<ComposerPrimitive.Root className="focus-within:border-[#4f46e5]/20 dark:focus-within:border-[#6366f1]/20 flex w-full flex-wrap items-end rounded-full border border-[#e2e8f0] dark:border-zinc-700 bg-white dark:bg-zinc-800 px-2.5 shadow-sm transition-colors ease-in">
<ComposerPrimitive.Input
@@ -284,6 +334,7 @@ const Composer: FC = () => {
autoFocus
placeholder="Message to Mem0..."
className="placeholder:text-zinc-400 dark:placeholder:text-zinc-500 max-h-40 flex-grow resize-none border-none bg-transparent px-2 py-4 text-sm outline-none focus:ring-0 disabled:cursor-not-allowed text-[#1e293b] dark:text-zinc-200"
ref={composerInputRef}
/>
<ComposerAction />
</ComposerPrimitive.Root>
@@ -1,18 +1,18 @@
import { cn } from "@/lib/utils";
const GithubButton = ({ url }: { url: string }) => {
const GithubButton = ({ url, className, text }: { url: string, className?: string, text?: string }) => {
return (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className="flex items-center bg-black text-white rounded-full shadow-lg hover:bg-gray-800 transition border border-gray-700"
className={cn("flex items-center bg-black text-white rounded-full shadow-lg hover:bg-gray-800 transition border border-gray-700", className)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="white"
className="w-6 h-6"
className="w-5 h-5 md:w-6 md:h-6"
>
<path
fillRule="evenodd"
@@ -20,6 +20,7 @@ const GithubButton = ({ url }: { url: string }) => {
clipRule="evenodd"
/>
</svg>
{text && <span className="ml-2">{text}</span>}
</a>
);
};
+7 -2
View File
@@ -13,7 +13,7 @@
"@assistant-ui/react": "^0.8.2",
"@assistant-ui/react-ai-sdk": "^0.8.0",
"@assistant-ui/react-markdown": "^0.8.0",
"@mem0/vercel-ai-provider": "^0.0.14",
"@mem0/vercel-ai-provider": "^1.0.0",
"@radix-ui/react-alert-dialog": "^1.1.6",
"@radix-ui/react-avatar": "^1.1.3",
"@radix-ui/react-popover": "^1.1.6",
@@ -50,5 +50,10 @@
"tailwindcss": "^3.4.1",
"typescript": "^5"
},
"packageManager": "pnpm@10.5.2"
"packageManager": "pnpm@10.5.2",
"pnpm": {
"onlyBuiltDependencies": [
"sqlite3"
]
}
}
+101
View File
@@ -0,0 +1,101 @@
"""
Create your personal AI Assistant powered by memory that supports both text and images and remembers your preferences
In order to run this file, you need to set up your Mem0 API at Mem0 platform and also need a OpenAI API key.
export OPENAI_API_KEY="your_openai_api_key"
export MEM0_API_KEY="your_mem0_api_key"
"""
import base64
from pathlib import Path
from agno.agent import Agent
from agno.media import Image
from agno.models.openai import OpenAIChat
from mem0 import MemoryClient
# Initialize the Mem0 client
client = MemoryClient()
# Define the agent
agent = Agent(
name="Personal Agent",
model=OpenAIChat(id="gpt-4o"),
description="You are a helpful personal agent that helps me with day to day activities."
"You can process both text and images.",
markdown=True
)
# Function to handle user input with memory integration with support for images
def chat_user(user_input: str = None, user_id: str = "user_123", image_path: str = None):
if image_path:
with open(image_path, "rb") as image_file:
base64_image = base64.b64encode(image_file.read()).decode("utf-8")
# First: the text message
text_msg = {
"role": "user",
"content": user_input
}
# Second: the image message
image_msg = {
"role": "user",
"content": {
"type": "image_url",
"image_url": {
"url": f"data:image/jpeg;base64,{base64_image}"
}
}
}
# Send both as separate message objects
client.add([text_msg, image_msg], user_id=user_id, output_format='v1.1')
print("✅ Image uploaded and stored in memory.")
if user_input:
memories = client.search(user_input, user_id=user_id)
memory_context = "\n".join(f"- {m['memory']}" for m in memories)
prompt = f"""
You are a helpful personal assistant who helps user with his day-to-day activities and keep track of everything.
Your task is to:
1. Analyze the given image (if present) and extract meaningful details to answer the user's question.
2. Use your past memory of the user to personalize your answer.
3. Combine the image content and memory to generate a helpful, context-aware response.
Here is what remember about the user:
{memory_context}
User question:
{user_input}
"""
if image_path:
response = agent.run(prompt, images=[Image(filepath=Path(image_path))])
else:
response = agent.run(prompt)
client.add(f"User: {user_input}\nAssistant: {response.content}", user_id=user_id)
return response.content
return "No user input or image provided."
# Example Usage
user_id = "user_123"
print(chat_user("What did I ask you to remind me about?", user_id))
# # OUTPUT: You asked me to remind you to call your mom tomorrow. 📞
#
print(chat_user("When is my test?", user_id=user_id))
# OUTPUT: Your pilot's test is on your birthday, which is in five days. You're turning 25!
# Good luck with your preparations, and remember to take some time to relax amidst the studying.
print(chat_user("This is the picture of what I brought with me in the trip to Bahamas",
image_path="travel_items.jpeg", # this will be added to Mem0 memory
user_id=user_id))
print(chat_user("hey can you quickly tell me if brought my sunglasses to my trip, not able to find",
user_id=user_id))
# OUTPUT: Yes, you did bring your sunglasses on your trip to the Bahamas along with your laptop, face masks and other items..
# Since you can't find them now, perhaps check the pockets of jackets you wore or in your luggage compartments.
+84
View File
@@ -0,0 +1,84 @@
"""
Create your personal AI Study Buddy that remembers what you’ve studied (and where you struggled),
helps with spaced repetition and topic review, personalizes responses using your past interactions.
Supports both text and PDF/image inputs.
In order to run this file, you need to set up your Mem0 API at Mem0 platform and also need a OpenAI API key.
export OPENAI_API_KEY="your_openai_api_key"
export MEM0_API_KEY="your_mem0_api_key"
"""
import asyncio
from mem0 import MemoryClient
from agents import Agent, Runner
client = MemoryClient()
# Define your study buddy agent
study_agent = Agent(
name="StudyBuddy",
instructions="""You are a helpful study coach. You:
- Track what the user has studied before
- Identify topics the user has struggled with (e.g., "I'm confused", "this is hard")
- Help with spaced repetition by suggesting topics to revisit based on last review time
- Personalize answers using stored memories
- Summarize PDFs or notes the user uploads""")
# Upload and store PDF to Mem0
def upload_pdf(pdf_url: str, user_id: str):
pdf_message = {
"role": "user",
"content": {
"type": "pdf_url",
"pdf_url": {"url": pdf_url}
}
}
client.add([pdf_message], user_id=user_id)
print("✅ PDF uploaded and processed into memory.")
# Main interaction loop with your personal study buddy
async def study_buddy(user_id: str, topic: str, user_input: str):
memories = client.search(f"{topic}", user_id=user_id)
memory_context = "n".join(f"- {m['memory']}" for m in memories)
prompt = f"""
You are helping the user study the topic: {topic}.
Here are past memories from previous sessions:
{memory_context}
Now respond to the user's new question or comment:
{user_input}
"""
result = await Runner.run(study_agent, prompt)
response = result.final_output
client.add([
{"role": "user", "content": f'''Topic: {topic}nUser: {user_input}nnStudy Assistant: {response}'''}
], user_id=user_id, metadata={"topic": topic})
return response
# Example usage
async def main():
user_id = "Ajay"
pdf_url = "https://pages.physics.ua.edu/staff/fabi/ph101/classnotes/8RotD101.pdf"
upload_pdf(pdf_url, user_id) # Upload a relevant lecture PDF to memory
topic = "Lagrangian Mechanics"
# Demonstrate tracking previously learned topics
print(await study_buddy(user_id, topic, "Can you remind me of what we discussed about generalized coordinates?"))
# Demonstrate weakness detection
print(await study_buddy(user_id, topic, "I still don’t get what frequency domain really means."))
# Demonstrate spaced repetition prompting
topic = "Momentum Conservation"
print(await study_buddy(user_id, topic, "I think we covered this last week. Is it time to review momentum conservation again?"))
if __name__ == "__main__":
asyncio.run(main())
+83
View File
@@ -0,0 +1,83 @@
import MemoryClient from "mem0ai";
import { OpenAI } from "openai";
import { zodResponsesFunction } from "openai/helpers/zod";
import { z } from "zod";
const mem0Config = {
apiKey: process.env.MEM0_API_KEY, // GET THIS API KEY FROM MEM0 (https://app.mem0.ai/dashboard/api-keys)
user_id: "sample-user",
};
async function run() {
// RESPONES WITHOUT MEMORIES
console.log("\n\nRESPONES WITHOUT MEMORIES\n\n");
await main();
// ADDING SOME SAMPLE MEMORIES
await addSampleMemories();
// RESPONES WITH MEMORIES
console.log("\n\nRESPONES WITH MEMORIES\n\n");
await main(true);
}
// OpenAI Response Schema
const CarSchema = z.object({
car_name: z.string(),
car_price: z.string(),
car_url: z.string(),
car_image: z.string(),
car_description: z.string(),
});
const Cars = z.object({
cars: z.array(CarSchema),
});
async function main(memory = false) {
const openAIClient = new OpenAI();
const mem0Client = new MemoryClient(mem0Config);
const input = "Suggest me some cars that I can buy today.";
const tool = zodResponsesFunction({ name: "carRecommendations", parameters: Cars });
// First, let's store the user's memories from user input if any
await mem0Client.add([{
role: "user",
content: input,
}], mem0Config);
// Then search for relevant memories
let relevantMemories = []
if (memory) {
relevantMemories = await mem0Client.search(input, mem0Config);
}
const response = await openAIClient.responses.create({
model: "gpt-4o",
tools: [{ type: "web_search_preview" }, tool],
input: `${getMemoryString(relevantMemories)}\n${input}`,
});
console.log(response.output);
}
async function addSampleMemories() {
const mem0Client = new MemoryClient(mem0Config);
const myInterests = "I Love BMW, Audi and Porsche. I Hate Mercedes. I love Red cars and Maroon cars. I have a budget of 120K to 150K USD. I like Audi the most.";
await mem0Client.add([{
role: "user",
content: myInterests,
}], mem0Config);
}
const getMemoryString = (memories) => {
const MEMORY_STRING_PREFIX = "These are the memories I have stored. Give more weightage to the question by users and try to answer that first. You have to modify your answer based on the memories I have provided. If the memories are irrelevant you can ignore them. Also don't reply to this section of the prompt, or the memories, they are only for your reference. The MEMORIES of the USER are: \n\n";
const memoryString = memories.map((mem) => `${mem.memory}`).join("\n") ?? "";
return memoryString.length > 0 ? `${MEMORY_STRING_PREFIX}${memoryString}` : "";
};
run().catch(console.error);
@@ -0,0 +1,19 @@
{
"name": "openai-inbuilt-tools",
"version": "1.0.0",
"description": "",
"license": "ISC",
"author": "",
"type": "module",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node index.js"
},
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b",
"dependencies": {
"mem0ai": "^2.1.2",
"openai": "^4.87.2",
"zod": "^3.24.2"
}
}
@@ -0,0 +1,54 @@
{
"name": "mem0-sdk-chat-bot",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@mem0/vercel-ai-provider": "0.0.12",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-icons": "^1.3.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-slot": "^1.1.0",
"ai": "4.1.42",
"buffer": "^6.0.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"framer-motion": "^11.11.11",
"lucide-react": "^0.454.0",
"openai": "^4.86.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",
"mem0ai": "2.1.2",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/node": "^22.8.6",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.11.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.14",
"typescript": "~5.6.2",
"typescript-eslint": "^8.11.0",
"vite": "^6.2.1"
},
"packageManager": "pnpm@10.5.2+sha512.da9dc28cd3ff40d0592188235ab25d3202add8a207afbedc682220e4a0029ffbff4562102b9e6e46b4e3f9e8bd53e6d05de48544b0c57d4b0179e22c76d1199b"
}
+4
View File
@@ -0,0 +1,4 @@
node_modules
.env*
dist
package-lock.json
+88
View File
@@ -0,0 +1,88 @@
# Mem0 Assistant Chrome Extension
A powerful Chrome extension that combines AI chat with your personal knowledge base through mem0. Get instant, personalized answers about video content while leveraging your own knowledge and memories - all without leaving the page.
## Development
1. Install dependencies:
```bash
npm install
```
2. Start development mode:
```bash
npm run watch
```
3. Build for production:
```bash
npm run build
```
## Features
- AI-powered chat interface directly in YouTube
- Memory capabilities powered by Mem0
- Dark mode support
- Customizable options
## Permissions
- activeTab: For accessing the current tab
- storage: For saving user preferences
- scripting: For injecting content scripts
## Host Permissions
- youtube.com
- openai.com
- mem0.ai
## Features
- **Contextual AI Chat**: Ask questions about videos you're watching
- **Seamless Integration**: Chat interface sits alongside YouTube's native UI
- **OpenAI-Powered**: Uses GPT models for intelligent responses
- **Customizable**: Configure model settings, appearance, and behavior
- **Future mem0 Integration**: Personalized responses based on your knowledge (coming soon)
## Installation
### From Source (Developer Mode)
1. Download or clone this repository
2. Open Chrome and navigate to `chrome://extensions/`
3. Enable "Developer mode" (toggle in the top-right corner)
4. Click "Load unpacked" and select the extension directory
5. The extension should now be installed and visible in your toolbar
### Setup
1. Click the extension icon in your toolbar
2. Enter your OpenAI API key (required to use the extension)
3. Configure additional settings if desired
4. Navigate to YouTube to start using the assistant
## Usage
1. Visit any YouTube video
2. Click the AI assistant icon in the corner of the page to open the chat interface
3. Ask questions about the video content
4. The AI will respond with contextual information
### Example Prompts
- "Can you summarize the main points of this video?"
- "What is the speaker explaining at 5:23?"
- "Explain the concept they just mentioned"
- "How does this relate to [topic I'm learning about]?"
- "What are some practical applications of what's being discussed?"
- **API Settings**: Change model, adjust tokens, modify temperature
- **Interface Settings**: Control where and how the chat appears
- **Behavior Settings**: Configure auto-context extraction
## Privacy & Data
- Your API keys are stored locally in your browser
- Video context and transcript is processed locally and only sent to OpenAI when you ask questions
File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

@@ -0,0 +1,45 @@
{
"manifest_version": 3,
"name": "YouTube Assistant powered by Mem0",
"version": "1.0",
"description": "An AI-powered YouTube assistant with memory capabilities from Mem0",
"permissions": [
"activeTab",
"storage",
"scripting"
],
"host_permissions": [
"https://*.youtube.com/*",
"https://*.openai.com/*",
"https://*.mem0.ai/*"
],
"content_security_policy": {
"extension_pages": "script-src 'self'; object-src 'self'",
"sandbox": "sandbox allow-scripts; script-src 'self' 'unsafe-inline' 'unsafe-eval'; child-src 'self'"
},
"action": {
"default_popup": "public/popup.html"
},
"options_page": "public/options.html",
"content_scripts": [
{
"matches": ["https://*.youtube.com/*"],
"js": ["dist/content.bundle.js"],
"css": ["styles/content.css"]
}
],
"background": {
"service_worker": "src/background.js"
},
"web_accessible_resources": [
{
"resources": [
"assets/*",
"dist/*",
"styles/*",
"node_modules/mem0ai/dist/*"
],
"matches": ["https://*.youtube.com/*"]
}
]
}
+26
View File
@@ -0,0 +1,26 @@
{
"name": "mem0-assistant",
"version": "1.0.0",
"description": "A Chrome extension that integrates AI chat functionality directly into YouTube and other sites. Get instant answers about video content without leaving the page.",
"main": "background.js",
"scripts": {
"build": "webpack --config webpack.config.js",
"watch": "webpack --config webpack.config.js --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@babel/core": "^7.22.0",
"@babel/preset-env": "^7.22.0",
"babel-loader": "^9.1.2",
"css-loader": "^7.1.2",
"style-loader": "^4.0.0",
"webpack": "^5.85.0",
"webpack-cli": "^5.1.1",
"youtube-transcript": "^1.0.6"
},
"dependencies": {
"mem0ai": "^2.1.15"
}
}
@@ -0,0 +1,196 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>YouTube Assistant powered by Mem0</title>
<link rel="stylesheet" href="../styles/options.css">
</head>
<body>
<div class="main-content">
<header>
<div class="title-container">
<h1>YouTube Assistant</h1>
<div class="branding-container">
<span class="powered-by">powered by</span>
<a href="https://mem0.ai" target="_blank">
<img src="../assets/dark.svg" alt="Mem0 Logo" class="logo-img">
</a>
</div>
</div>
<div class="description">
Configure your YouTube Assistant preferences.
</div>
</header>
<div id="status-container"></div>
<div class="section">
<h2>Model Settings</h2>
<div class="form-group">
<label for="model">OpenAI Model</label>
<select id="model">
<option value="o3">o3</option>
<option value="o1">o1</option>
<option value="o1-mini">o1-mini</option>
<option value="o1-pro">o1-pro</option>
<option value="gpt-4o">GPT-4o</option>
<option value="gpt-4o-mini">GPT-4o mini</option>
</select>
<div class="description" style="margin-top: 8px; font-size: 13px">
Choose the OpenAI model to use depending on your needs.
</div>
</div>
<div class="form-group">
<label for="max-tokens">Maximum Response Length</label>
<input
type="number"
id="max-tokens"
min="50"
max="4000"
value="2000"
/>
<div class="description" style="margin-top: 8px; font-size: 13px">
Maximum number of tokens in the AI's response. Higher values allow
for longer responses but may increase processing time.
</div>
</div>
<div class="form-group">
<label for="temperature">Response Creativity</label>
<input
type="range"
id="temperature"
min="0"
max="1"
step="0.1"
value="0.7"
/>
<div
id="temperature-value"
style="display: inline-block; margin-left: 10px"
>
0.7
</div>
<div class="description" style="margin-top: 8px; font-size: 13px">
Controls response randomness. Lower values (0.1-0.3) are more
focused and deterministic, higher values (0.7-0.9) are more creative
and diverse.
</div>
</div>
</div>
<div class="section">
<h2>Create Memories</h2>
<div class="description">
Add information about yourself that you want the AI to remember. This
information will be used to provide more personalized responses.
</div>
<div class="form-group">
<label for="memory-input">Your Information</label>
<textarea
id="memory-input"
class="memory-input"
placeholder="Enter information about yourself that you want the AI to remember..."
></textarea>
</div>
<div class="actions">
<button id="add-memory" class="primary">
<span class="button-text">Add Memory</span>
</button>
</div>
<div id="memory-result" class="memory-result"></div>
</div>
<div class="actions">
<button id="reset-defaults" class="secondary-button">
Reset to Defaults
</button>
<button id="save-options">Save Changes</button>
</div>
</div>
<!-- Memories Sidebar -->
<div class="memories-sidebar" id="memories-sidebar">
<div class="memories-header">
<h2 class="memories-title">Your Memories</h2>
<div class="memories-actions">
<button
id="refresh-memories"
class="memory-action-btn"
title="Refresh Memories"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M23 4v6h-6"></path>
<path d="M1 20v-6h6"></path>
<path
d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"
></path>
</svg>
</button>
<button
id="delete-all-memories"
class="memory-action-btn delete"
title="Delete All Memories"
>
<svg
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M3 6h18"></path>
<path d="M19 6v14c0 1-1 2-2 2H7c-1 0-2-1-2-2V6"></path>
<path d="M8 6V4c0-1 1-2 2-2h4c1 0 2 1 2 2v2"></path>
</svg>
</button>
</div>
</div>
<div class="memories-list" id="memories-list">
<!-- Memories will be populated here -->
</div>
</div>
<!-- Edit Memory Modal -->
<div class="edit-memory-modal" id="edit-memory-modal">
<div class="edit-memory-content">
<div class="edit-memory-header">
<h3 class="edit-memory-title">Edit Memory</h3>
<button class="edit-memory-close" id="close-edit-modal">
&times;
</button>
</div>
<textarea class="edit-memory-textarea" id="edit-memory-text"></textarea>
<div class="edit-memory-actions">
<button class="memory-action-btn delete" id="delete-memory">
Delete
</button>
<button class="memory-action-btn" id="save-memory">
Save Changes
</button>
</div>
</div>
</div>
<script src="../dist/options.bundle.js"></script>
</body>
</html>
@@ -0,0 +1,165 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>YouTube Assistant powered by Mem0</title>
<link rel="stylesheet" href="../styles/popup.css">
</head>
<body>
<header>
<h1>YouTube Assistant</h1>
<div class="branding-container">
<span class="powered-by">powered by</span>
<a href="https://mem0.ai" target="_blank">
<img src="../assets/dark.svg" alt="Mem0 Logo" class="logo-img">
</a>
</div>
</header>
<div class="content">
<!-- Status area -->
<div id="status-container"></div>
<!-- API key input, only shown if not set -->
<div id="api-key-section" class="api-key-section">
<label for="api-key">OpenAI API Key</label>
<div class="api-key-input-wrapper">
<input type="password" id="api-key" placeholder="sk-..." />
<button class="toggle-password" id="toggle-openai-key">
<svg
class="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
</button>
</div>
<button id="save-api-key" class="save-button">
<svg
class="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"
></path>
<polyline points="17 21 17 13 7 13 7 21"></polyline>
<polyline points="7 3 7 8 15 8"></polyline>
</svg>
Save OpenAI Key
</button>
</div>
<!-- mem0 API key input -->
<div id="mem0-api-key-section" class="api-key-section">
<label for="mem0-api-key">Mem0 API Key</label>
<div class="api-key-input-wrapper">
<input
type="password"
id="mem0-api-key"
placeholder="Enter your mem0 API key"
/>
<button class="toggle-password" id="toggle-mem0-key">
<svg
class="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path>
<circle cx="12" cy="12" r="3"></circle>
</svg>
</button>
</div>
<div class="api-key-actions">
<p>Get your API key from <a href="https://mem0.ai" target="_blank" class="get-key-link">mem0.ai</a> to integrate memory features in the chat.</p>
<button id="save-mem0-api-key" class="save-button">
<svg
class="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z"
></path>
<polyline points="17 21 17 13 7 13 7 21"></polyline>
<polyline points="7 3 7 8 15 8"></polyline>
</svg>
Save Mem0 Key
</button>
</div>
</div>
<!-- Action buttons -->
<div class="actions">
<button id="toggle-chat">
<svg
class="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path
d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"
></path>
</svg>
Chat
</button>
<button id="open-options">
<svg
class="icon"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<circle cx="12" cy="12" r="3"></circle>
<path
d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"
></path>
</svg>
Settings
</button>
</div>
<!-- Future mem0 integration status -->
<div class="mem0-status">
<p>
Mem0 integration:
<span id="mem0-status-text">Not configured</span>
</p>
</div>
</div>
<script src="../src/popup.js"></script>
</body>
</html>
@@ -0,0 +1,255 @@
// Background script to handle API calls to OpenAI and manage extension state
// Configuration (will be stored in sync storage eventually)
let config = {
apiKey: "", // Will be set by user in options
mem0ApiKey: "", // Will be set by user in options
model: "gpt-4",
maxTokens: 2000,
temperature: 0.7,
enabledSites: ["youtube.com"],
};
// Track if config is loaded
let isConfigLoaded = false;
// Initialize configuration from storage
chrome.storage.sync.get(
["apiKey", "mem0ApiKey", "model", "maxTokens", "temperature", "enabledSites"],
(result) => {
if (result.apiKey) config.apiKey = result.apiKey;
if (result.mem0ApiKey) config.mem0ApiKey = result.mem0ApiKey;
if (result.model) config.model = result.model;
if (result.maxTokens) config.maxTokens = result.maxTokens;
if (result.temperature) config.temperature = result.temperature;
if (result.enabledSites) config.enabledSites = result.enabledSites;
isConfigLoaded = true;
}
);
// Listen for messages from content script or popup
chrome.runtime.onMessage.addListener((request, sender, sendResponse) => {
// Handle different message types
switch (request.action) {
case "sendChatRequest":
sendChatRequest(request.messages, request.model || config.model)
.then((response) => sendResponse(response))
.catch((error) => sendResponse({ error: error.message }));
return true; // Required for async response
case "saveConfig":
saveConfig(request.config)
.then(() => sendResponse({ success: true }))
.catch((error) => sendResponse({ error: error.message }));
return true;
case "getConfig":
// If config isn't loaded yet, load it first
if (!isConfigLoaded) {
chrome.storage.sync.get(
[
"apiKey",
"mem0ApiKey",
"model",
"maxTokens",
"temperature",
"enabledSites",
],
(result) => {
if (result.apiKey) config.apiKey = result.apiKey;
if (result.mem0ApiKey) config.mem0ApiKey = result.mem0ApiKey;
if (result.model) config.model = result.model;
if (result.maxTokens) config.maxTokens = result.maxTokens;
if (result.temperature) config.temperature = result.temperature;
if (result.enabledSites) config.enabledSites = result.enabledSites;
isConfigLoaded = true;
sendResponse({ config });
}
);
return true;
}
sendResponse({ config });
return false;
case "openOptions":
// Open options page
chrome.runtime.openOptionsPage(() => {
if (chrome.runtime.lastError) {
console.error(
"Error opening options page:",
chrome.runtime.lastError
);
// Fallback: Try to open directly in a new tab
chrome.tabs.create({ url: chrome.runtime.getURL("options.html") });
}
sendResponse({ success: true });
});
return true;
case "toggleChat":
// Forward the toggle request to the active tab
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]) {
chrome.tabs
.sendMessage(tabs[0].id, { action: "toggleChat" })
.then((response) => sendResponse(response))
.catch((error) => sendResponse({ error: error.message }));
} else {
sendResponse({ error: "No active tab found" });
}
});
return true;
}
});
// Handle extension icon click - toggle chat visibility
chrome.action.onClicked.addListener((tab) => {
chrome.tabs
.sendMessage(tab.id, { action: "toggleChat" })
.catch((error) => console.error("Error toggling chat:", error));
});
// Save configuration to sync storage
async function saveConfig(newConfig) {
// Validate API key if provided
if (newConfig.apiKey) {
try {
const isValid = await validateApiKey(newConfig.apiKey);
if (!isValid) {
throw new Error("Invalid API key");
}
} catch (error) {
throw new Error(`API key validation failed: ${error.message}`);
}
}
// Update local config
config = { ...config, ...newConfig };
// Save to sync storage
return chrome.storage.sync.set(newConfig);
}
// Validate OpenAI API key with a simple request
async function validateApiKey(apiKey) {
try {
const response = await fetch("https://api.openai.com/v1/models", {
method: "GET",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
});
if (!response.ok) {
throw new Error(`API returned ${response.status}`);
}
return true;
} catch (error) {
console.error("API key validation error:", error);
return false;
}
}
// Send a chat request to OpenAI API
async function sendChatRequest(messages, model) {
// Check if API key is set
if (!config.apiKey) {
return {
error:
"API key not configured. Please set your OpenAI API key in the extension options.",
};
}
try {
const response = await fetch("https://api.openai.com/v1/chat/completions", {
method: "POST",
headers: {
Authorization: `Bearer ${config.apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
model: model || config.model,
messages: messages.map((msg) => ({
role: msg.role,
content: msg.content,
})),
max_tokens: config.maxTokens,
temperature: config.temperature,
stream: true, // Enable streaming
}),
});
if (!response.ok) {
const errorData = await response.json();
throw new Error(
errorData.error?.message || `API returned ${response.status}`
);
}
// Create a ReadableStream from the response
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = "";
// Process the stream
while (true) {
const { done, value } = await reader.read();
if (done) break;
// Decode the chunk and add to buffer
buffer += decoder.decode(value, { stream: true });
// Process complete lines
const lines = buffer.split("\n");
buffer = lines.pop() || ""; // Keep the last incomplete line in the buffer
for (const line of lines) {
if (line.startsWith("data: ")) {
const data = line.slice(6);
if (data === "[DONE]") {
// Stream complete
return { done: true };
}
try {
const parsed = JSON.parse(data);
if (parsed.choices[0].delta.content) {
// Send the chunk to the content script
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]) {
chrome.tabs.sendMessage(tabs[0].id, {
action: "streamChunk",
chunk: parsed.choices[0].delta.content,
});
}
});
}
} catch (e) {
console.error("Error parsing chunk:", e);
}
}
}
}
return { done: true };
} catch (error) {
console.error("Error sending chat request:", error);
return { error: error.message };
}
}
// Future: Add mem0 integration functions here
// When ready, replace with actual implementation
function mem0Integration() {
// Placeholder for future mem0 integration
return {
getUserMemories: async (userId) => {
return { memories: [] };
},
saveMemory: async (userId, memory) => {
return { success: true };
},
};
}
+657
View File
@@ -0,0 +1,657 @@
// Main content script that injects the AI chat into YouTube
import { YoutubeTranscript } from "youtube-transcript";
import { MemoryClient } from "mem0ai";
// Configuration
const config = {
apiEndpoint: "https://api.openai.com/v1/chat/completions",
model: "gpt-4o",
chatPosition: "right", // Where to display the chat panel
autoExtract: true, // Automatically extract video context
mem0ApiKey: "", // Will be set through extension options
};
// Initialize Mem0AI - will be initialized properly when API key is available
let mem0client = null;
let mem0Initializing = false;
// Function to initialize Mem0AI with API key from storage
async function initializeMem0AI() {
if (mem0Initializing) return; // Prevent multiple simultaneous initialization attempts
mem0Initializing = true;
try {
// Get API key from storage
const items = await chrome.storage.sync.get(["mem0ApiKey"]);
if (items.mem0ApiKey) {
try {
// Create new client instance with v2.1.11 configuration
mem0client = new MemoryClient({
apiKey: items.mem0ApiKey,
projectId: "youtube-assistant", // Add a project ID for organization
isExtension: true,
});
// Set up custom instructions for the YouTube educational assistant
await mem0client.updateProject({
custom_instructions: `Your task: Create memories for a YouTube AI assistant. Focus on capturing:
1. User's Knowledge & Experience:
- Direct statements about their skills, knowledge, or experience
- Their level of expertise in specific areas
- Technologies, frameworks, or tools they work with
- Their learning journey or background
2. User's Interests & Goals:
- What they're trying to learn or understand (user messages may include the video title)
- Their specific questions or areas of confusion
- Their learning objectives or career goals
- Topics they want to explore further
3. Personal Context:
- Their current role or position
- Their learning style or preferences
- Their experience level in the video's topic
- Any challenges or difficulties they're facing
4. Video Engagement:
- Their reactions to the content
- Points they agree or disagree with
- Areas they want to discuss further
- Connections they make to other topics
For each message:
- Extract both explicit statements and implicit knowledge
- Capture both video-related and personal context
- Note any relationships between user's knowledge and video content
Remember: The goal is to build a comprehensive understanding of both the user's knowledge and their learning journey through YouTube.`,
});
return true;
} catch (error) {
console.error("Error initializing Mem0AI:", error);
return false;
}
} else {
console.log("No Mem0AI API key found in storage");
return false;
}
} catch (error) {
console.error("Error accessing storage:", error);
return false;
} finally {
mem0Initializing = false;
}
}
// Global state
let chatState = {
messages: [],
isVisible: false,
isLoading: false,
videoContext: null,
transcript: null, // Add transcript to state
userMemories: null, // Will store retrieved memories
currentStreamingMessage: null, // Track the current streaming message
};
// Function to extract video ID from YouTube URL
function getYouTubeVideoId(url) {
const urlObj = new URL(url);
const searchParams = new URLSearchParams(urlObj.search);
return searchParams.get("v");
}
// Function to fetch and log transcript
async function fetchAndLogTranscript() {
try {
// Check if we're on a YouTube video page
if (
window.location.hostname.includes("youtube.com") &&
window.location.pathname.includes("/watch")
) {
const videoId = getYouTubeVideoId(window.location.href);
if (videoId) {
// Fetch transcript using youtube-transcript package
const transcript = await YoutubeTranscript.fetchTranscript(videoId);
// Decode HTML entities in transcript text
const decodedTranscript = transcript.map((entry) => ({
...entry,
text: entry.text
.replace(/&amp;#39;/g, "'")
.replace(/&amp;quot;/g, '"')
.replace(/&amp;lt;/g, "<")
.replace(/&amp;gt;/g, ">")
.replace(/&amp;amp;/g, "&"),
}));
// Store transcript in state
chatState.transcript = decodedTranscript;
} else {
return;
}
}
} catch (error) {
console.error("Error fetching transcript:", error);
chatState.transcript = null;
}
}
// Initialize when the DOM is fully loaded
document.addEventListener("DOMContentLoaded", async () => {
init();
fetchAndLogTranscript();
await initializeMem0AI(); // Initialize Mem0AI
});
// Also attempt to initialize on window load to handle YouTube's SPA behavior
window.addEventListener("load", async () => {
init();
fetchAndLogTranscript();
await initializeMem0AI(); // Initialize Mem0AI
});
// Add another listener for YouTube's navigation events
window.addEventListener("yt-navigate-finish", () => {
init();
fetchAndLogTranscript();
});
// Main initialization function
function init() {
// Check if we're on a YouTube page
if (
!window.location.hostname.includes("youtube.com") ||
!window.location.pathname.includes("/watch")
) {
return;
}
// Give YouTube's DOM a moment to settle
setTimeout(() => {
// Only inject if not already present
if (!document.getElementById("ai-chat-assistant-container")) {
injectChatInterface();
setupEventListeners();
extractVideoContext();
}
}, 1500);
}
// Extract context from the current YouTube video
function extractVideoContext() {
if (!config.autoExtract) return;
try {
const videoTitle =
document.querySelector(
"h1.title.style-scope.ytd-video-primary-info-renderer"
)?.textContent ||
document.querySelector("h1.title")?.textContent ||
"Unknown Video";
const channelName =
document.querySelector("ytd-channel-name yt-formatted-string")
?.textContent ||
document.querySelector("ytd-channel-name")?.textContent ||
"Unknown Channel";
// Video ID from URL
const videoId = new URLSearchParams(window.location.search).get("v");
// Update state with basic video context first
chatState.videoContext = {
title: videoTitle,
channel: channelName,
videoId: videoId,
url: window.location.href,
};
} catch (error) {
console.error("Error extracting video context:", error);
chatState.videoContext = {
title: "Error extracting video information",
url: window.location.href,
};
}
}
// Inject the chat interface into the YouTube page
function injectChatInterface() {
// Create main container
const container = document.createElement("div");
container.id = "ai-chat-assistant-container";
container.className = "ai-chat-container";
// Set up basic HTML structure
container.innerHTML = `
<div class="ai-chat-header">
<div class="ai-chat-tabs">
<button class="ai-chat-tab active" data-tab="chat">Chat</button>
<button class="ai-chat-tab" data-tab="memories">Memories</button>
</div>
<div class="ai-chat-controls">
<button id="ai-chat-minimize" class="ai-chat-btn" title="Minimize">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</button>
<button id="ai-chat-close" class="ai-chat-btn" title="Close">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="18" y1="6" x2="6" y2="18"></line>
<line x1="6" y1="6" x2="18" y2="18"></line>
</svg>
</button>
</div>
</div>
<div class="ai-chat-body">
<div id="ai-chat-content" class="ai-chat-content">
<div id="ai-chat-messages" class="ai-chat-messages"></div>
<div class="ai-chat-input-container">
<textarea id="ai-chat-input" placeholder="Ask about this video..."></textarea>
<button id="ai-chat-send" class="ai-chat-send-btn" title="Send message">
<svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<line x1="22" y1="2" x2="11" y2="13"></line>
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
</svg>
</button>
</div>
</div>
<div id="ai-chat-memories" class="ai-chat-memories" style="display: none;">
<div class="memories-header">
<div class="memories-title">
Manage memories <a href="#" id="manage-memories-link" title="Open options page">here <svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
<polyline points="15 3 21 3 21 9"></polyline>
<line x1="10" y1="14" x2="21" y2="3"></line>
</svg></a>
</div>
<button id="refresh-memories" class="ai-chat-btn" title="Refresh memories">
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M23 4v6h-6"></path>
<path d="M1 20v-6h6"></path>
<path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"></path>
</svg>
</button>
</div>
<div id="memories-list" class="memories-list"></div>
</div>
</div>
`;
// Append to body
document.body.appendChild(container);
// Add welcome message
addMessage(
"assistant",
"Hello! I can help answer questions about this video. What would you like to know?"
);
}
// Set up event listeners for the chat interface
function setupEventListeners() {
// Tab switching
const tabs = document.querySelectorAll(".ai-chat-tab");
tabs.forEach((tab) => {
tab.addEventListener("click", () => {
// Update active tab
tabs.forEach((t) => t.classList.remove("active"));
tab.classList.add("active");
// Show corresponding content
const tabName = tab.dataset.tab;
document.getElementById("ai-chat-content").style.display =
tabName === "chat" ? "flex" : "none";
document.getElementById("ai-chat-memories").style.display =
tabName === "memories" ? "flex" : "none";
// Load memories if switching to memories tab
if (tabName === "memories") {
loadMemories();
}
});
});
// Refresh memories button
document
.getElementById("refresh-memories")
?.addEventListener("click", loadMemories);
// Toggle chat visibility
document.getElementById("ai-chat-toggle")?.addEventListener("click", () => {
const container = document.getElementById("ai-chat-assistant-container");
chatState.isVisible = !chatState.isVisible;
if (chatState.isVisible) {
container.classList.add("visible");
} else {
container.classList.remove("visible");
}
});
// Close button
document.getElementById("ai-chat-close")?.addEventListener("click", () => {
const container = document.getElementById("ai-chat-assistant-container");
container.classList.remove("visible");
chatState.isVisible = false;
});
// Minimize button
document.getElementById("ai-chat-minimize")?.addEventListener("click", () => {
const container = document.getElementById("ai-chat-assistant-container");
container.classList.toggle("minimized");
});
// Send message on button click
document
.getElementById("ai-chat-send")
?.addEventListener("click", sendMessage);
// Send message on Enter key (but allow Shift+Enter for new lines)
document.getElementById("ai-chat-input")?.addEventListener("keydown", (e) => {
if (e.key === "Enter" && !e.shiftKey) {
e.preventDefault();
sendMessage();
}
});
// Add click handler for manage memories link
document
.getElementById("manage-memories-link")
.addEventListener("click", (e) => {
e.preventDefault();
chrome.runtime.sendMessage({ action: "openOptions" }, (response) => {
if (chrome.runtime.lastError) {
console.error("Error opening options:", chrome.runtime.lastError);
// Fallback: Try to open directly in a new tab
chrome.tabs.create({ url: chrome.runtime.getURL("options.html") });
}
});
});
}
// Add a message to the chat
function addMessage(role, text, isStreaming = false) {
const messagesContainer = document.getElementById("ai-chat-messages");
if (!messagesContainer) return;
const messageElement = document.createElement("div");
messageElement.className = `ai-chat-message ${role}`;
// Enhanced markdown-like formatting
let formattedText = text
// Code blocks
.replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>")
// Inline code
.replace(/`([^`]+)`/g, "<code>$1</code>")
// Links
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>')
// Bold text
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
// Italic text
.replace(/\*([^*]+)\*/g, "<em>$1</em>")
// Lists
.replace(/^\s*[-*]\s+(.+)$/gm, "<li>$1</li>")
.replace(/(<li>.*<\/li>)/s, "<ul>$1</ul>")
// Line breaks
.replace(/\n/g, "<br>");
messageElement.innerHTML = formattedText;
messagesContainer.appendChild(messageElement);
// Scroll to bottom
messagesContainer.scrollTop = messagesContainer.scrollHeight;
// Add to messages array if not streaming
if (!isStreaming) {
chatState.messages.push({ role, content: text });
}
return messageElement;
}
// Format streaming text with markdown
function formatStreamingText(text) {
return text
// Code blocks
.replace(/```([\s\S]*?)```/g, "<pre><code>$1</code></pre>")
// Inline code
.replace(/`([^`]+)`/g, "<code>$1</code>")
// Links
.replace(/\[([^\]]+)\]\(([^)]+)\)/g, '<a href="$2" target="_blank">$1</a>')
// Bold text
.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>")
// Italic text
.replace(/\*([^*]+)\*/g, "<em>$1</em>")
// Lists
.replace(/^\s*[-*]\s+(.+)$/gm, "<li>$1</li>")
.replace(/(<li>.*<\/li>)/s, "<ul>$1</ul>")
// Line breaks
.replace(/\n/g, "<br>");
}
// Send a message to the AI
async function sendMessage() {
const inputElement = document.getElementById("ai-chat-input");
if (!inputElement) return;
const userMessage = inputElement.value.trim();
if (!userMessage) return;
// Clear input
inputElement.value = "";
// Add user message to chat
addMessage("user", userMessage);
// Show loading indicator
chatState.isLoading = true;
const loadingMessage = document.createElement("div");
loadingMessage.className = "ai-chat-message assistant loading";
loadingMessage.textContent = "Thinking...";
document.getElementById("ai-chat-messages").appendChild(loadingMessage);
try {
// If mem0client is available, store the message as a memory and search for relevant memories
if (mem0client) {
try {
// Store the message as a memory
await mem0client.add(
[
{
role: "user",
content: `${userMessage}\n\nVideo title: ${chatState.videoContext?.title}`,
},
],
{
user_id: "youtube-assistant-mem0", // Required parameter
metadata: {
videoId: chatState.videoContext?.videoId || "",
videoTitle: chatState.videoContext?.title || "",
},
}
);
// Search for relevant memories
const searchResults = await mem0client.search(userMessage, {
user_id: "youtube-assistant-mem0", // Required parameter
limit: 5,
});
// Store the retrieved memories
chatState.userMemories = searchResults || null;
} catch (memoryError) {
console.error("Error with Mem0AI operations:", memoryError);
// Continue with the chat process even if memory operations fail
}
}
// Prepare messages with context (now includes memories if available)
const contextualizedMessages = prepareMessagesWithContext();
// Remove loading message
document.getElementById("ai-chat-messages").removeChild(loadingMessage);
// Create a new message element for streaming
chatState.currentStreamingMessage = addMessage("assistant", "", true);
// Send to background script to handle API call
chrome.runtime.sendMessage(
{
action: "sendChatRequest",
messages: contextualizedMessages,
model: config.model,
},
(response) => {
chatState.isLoading = false;
if (response.error) {
addMessage("system", `Error: ${response.error}`);
}
}
);
} catch (error) {
// Remove loading indicator
document.getElementById("ai-chat-messages").removeChild(loadingMessage);
chatState.isLoading = false;
// Show error
addMessage("system", `Error: ${error.message}`);
}
}
// Prepare messages with added context
function prepareMessagesWithContext() {
const messages = [...chatState.messages];
// If we have video context, add it as system message at the beginning
if (chatState.videoContext) {
let transcriptSection = "";
// Add transcript if available
if (chatState.transcript) {
// Format transcript into a readable string
const formattedTranscript = chatState.transcript
.map((entry) => `${entry.text}`)
.join("\n");
transcriptSection = `\n\nTranscript:\n${formattedTranscript}`;
}
// Add user memories if available
let userMemoriesSection = "";
if (chatState.userMemories && chatState.userMemories.length > 0) {
const formattedMemories = chatState.userMemories
.map((memory) => `${memory.memory}`)
.join("\n");
userMemoriesSection = `\n\nUser Memories:\n${formattedMemories}\n\n`;
}
const systemContent = `You are an AI assistant helping with a YouTube video. Here's the context:
Title: ${chatState.videoContext.title}
Channel: ${chatState.videoContext.channel}
URL: ${chatState.videoContext.url}
${
userMemoriesSection
? `Use the user memories below to personalize your response based on their past interactions and interests. These memories represent relevant past conversations and information about the user.
${userMemoriesSection}
`
: ""
}
Please provide helpful, relevant information based on the video's content.
${
transcriptSection
? `"Use the transcript below to provide accurate answers about the video. Ignore if the transcript doesn't make sense."
${transcriptSection}
`
: "Since the transcript is not available, focus on general questions about the topic and use the video title for context. If asked about specific parts of the video content, politely explain that the video doesn't have a transcript."
}
Be concise and helpful in your responses.
`;
messages.unshift({
role: "system",
content: systemContent,
});
}
return messages;
}
// Listen for commands from the background script or popup
chrome.runtime.onMessage.addListener((message, sender, sendResponse) => {
if (message.action === "toggleChat") {
const container = document.getElementById("ai-chat-assistant-container");
chatState.isVisible = !chatState.isVisible;
if (chatState.isVisible) {
container.classList.add("visible");
} else {
container.classList.remove("visible");
}
sendResponse({ success: true });
} else if (message.action === "streamChunk") {
// Handle streaming chunks
if (chatState.currentStreamingMessage) {
const currentContent = chatState.currentStreamingMessage.innerHTML;
chatState.currentStreamingMessage.innerHTML = formatStreamingText(currentContent + message.chunk);
// Scroll to bottom
const messagesContainer = document.getElementById("ai-chat-messages");
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
}
});
// Load memories from mem0
async function loadMemories() {
try {
const memoriesContainer = document.getElementById("memories-list");
memoriesContainer.innerHTML =
'<div class="loading">Loading memories...</div>';
// If client isn't initialized, try to initialize it
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) {
memoriesContainer.innerHTML =
'<div class="error">Please set your Mem0 API key in the extension options.</div>';
return;
}
}
const response = await mem0client.getAll({
user_id: "youtube-assistant-mem0",
page: 1,
page_size: 50,
});
if (response && response.results) {
memoriesContainer.innerHTML = "";
response.results.forEach((memory) => {
const memoryElement = document.createElement("div");
memoryElement.className = "memory-item";
memoryElement.textContent = memory.memory;
memoriesContainer.appendChild(memoryElement);
});
if (response.results.length === 0) {
memoriesContainer.innerHTML =
'<div class="no-memories">No memories found</div>';
}
} else {
memoriesContainer.innerHTML =
'<div class="no-memories">No memories found</div>';
}
} catch (error) {
console.error("Error loading memories:", error);
document.getElementById("memories-list").innerHTML =
'<div class="error">Error loading memories. Please try again.</div>';
}
}
+452
View File
@@ -0,0 +1,452 @@
// Options page functionality for AI Chat Assistant
import { MemoryClient } from "mem0ai";
// Default configuration
const defaultConfig = {
model: "gpt-4o",
maxTokens: 2000,
temperature: 0.7,
enabledSites: ["youtube.com"],
};
// Initialize Mem0AI client
let mem0client = null;
// Initialize when the DOM is fully loaded
document.addEventListener("DOMContentLoaded", init);
// Initialize options page
async function init() {
// Set up event listeners
document
.getElementById("save-options")
.addEventListener("click", saveOptions);
document
.getElementById("reset-defaults")
.addEventListener("click", resetToDefaults);
document.getElementById("add-memory").addEventListener("click", addMemory);
// Set up slider value display
const temperatureSlider = document.getElementById("temperature");
const temperatureValue = document.getElementById("temperature-value");
temperatureSlider.addEventListener("input", () => {
temperatureValue.textContent = temperatureSlider.value;
});
// Set up memories sidebar functionality
document
.getElementById("refresh-memories")
.addEventListener("click", fetchMemories);
document
.getElementById("delete-all-memories")
.addEventListener("click", deleteAllMemories);
document
.getElementById("close-edit-modal")
.addEventListener("click", closeEditModal);
document.getElementById("save-memory").addEventListener("click", saveMemory);
document
.getElementById("delete-memory")
.addEventListener("click", deleteMemory);
// Load current configuration
await loadConfig();
// Initialize Mem0AI and load memories
await initializeMem0AI();
await fetchMemories();
}
// Initialize Mem0AI with API key from storage
async function initializeMem0AI() {
try {
const response = await chrome.runtime.sendMessage({ action: "getConfig" });
const mem0ApiKey = response.config.mem0ApiKey;
if (!mem0ApiKey) {
showMemoriesError("Please configure your Mem0 API key in the popup");
return false;
}
mem0client = new MemoryClient({
apiKey: mem0ApiKey,
projectId: "youtube-assistant",
isExtension: true,
});
return true;
} catch (error) {
console.error("Error initializing Mem0AI:", error);
showMemoriesError("Failed to initialize Mem0AI");
return false;
}
}
// Load configuration from storage
async function loadConfig() {
try {
const response = await chrome.runtime.sendMessage({ action: "getConfig" });
const config = response.config;
// Update form fields with current values
if (config.model) {
document.getElementById("model").value = config.model;
}
if (config.maxTokens) {
document.getElementById("max-tokens").value = config.maxTokens;
}
if (config.temperature !== undefined) {
const temperatureSlider = document.getElementById("temperature");
temperatureSlider.value = config.temperature;
document.getElementById("temperature-value").textContent =
config.temperature;
}
} catch (error) {
showStatus(`Error loading configuration: ${error.message}`, "error");
}
}
// Save options to storage
async function saveOptions() {
// Get values from form
const model = document.getElementById("model").value;
const maxTokens = parseInt(document.getElementById("max-tokens").value);
const temperature = parseFloat(document.getElementById("temperature").value);
// Validate inputs
if (maxTokens < 50 || maxTokens > 4000) {
showStatus("Maximum tokens must be between 50 and 4000", "error");
return;
}
if (temperature < 0 || temperature > 1) {
showStatus("Temperature must be between 0 and 1", "error");
return;
}
// Prepare config object
const config = {
model,
maxTokens,
temperature,
};
// Show loading status
showStatus("Saving options...", "warning");
try {
// Send to background script for saving
const response = await chrome.runtime.sendMessage({
action: "saveConfig",
config,
});
if (response.error) {
showStatus(`Error: ${response.error}`, "error");
} else {
showStatus("Options saved successfully", "success");
loadConfig(); // Refresh the UI with the latest saved values
}
} catch (error) {
showStatus(`Error: ${error.message}`, "error");
}
}
// Reset options to defaults
function resetToDefaults() {
if (
confirm(
"Are you sure you want to reset all options to their default values?"
)
) {
// Set form fields to default values
document.getElementById("model").value = defaultConfig.model;
document.getElementById("max-tokens").value = defaultConfig.maxTokens;
const temperatureSlider = document.getElementById("temperature");
temperatureSlider.value = defaultConfig.temperature;
document.getElementById("temperature-value").textContent =
defaultConfig.temperature;
showStatus("Restored default values. Click Save to apply.", "warning");
}
}
// Memories functionality
let currentMemory = null;
async function fetchMemories() {
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
const memories = await mem0client.getAll({
user_id: "youtube-assistant-mem0",
page: 1,
page_size: 50,
});
displayMemories(memories.results);
} catch (error) {
console.error("Error fetching memories:", error);
showMemoriesError("Failed to load memories");
}
}
function displayMemories(memories) {
const memoriesList = document.getElementById("memories-list");
memoriesList.innerHTML = "";
if (memories.length === 0) {
memoriesList.innerHTML = `
<div class="memory-item">
<div class="memory-content">No memories found. Your memories will appear here.</div>
</div>
`;
return;
}
memories.forEach((memory) => {
const memoryElement = document.createElement("div");
memoryElement.className = "memory-item";
memoryElement.innerHTML = `
<div class="memory-content">${memory.memory}</div>
<div class="memory-meta">Last updated: ${new Date(
memory.updated_at
).toLocaleString()}</div>
<div class="memory-actions">
<button class="memory-action-btn edit" data-id="${
memory.id
}">Edit</button>
<button class="memory-action-btn delete" data-id="${
memory.id
}">Delete</button>
</div>
`;
// Add event listeners
memoryElement
.querySelector(".edit")
.addEventListener("click", () => editMemory(memory));
memoryElement
.querySelector(".delete")
.addEventListener("click", () => deleteMemory(memory.id));
memoriesList.appendChild(memoryElement);
});
}
function showMemoriesError(message) {
const memoriesList = document.getElementById("memories-list");
memoriesList.innerHTML = `
<div class="memory-item">
<div class="memory-content">${message}</div>
</div>
`;
}
async function deleteAllMemories() {
if (
!confirm(
"Are you sure you want to delete all memories? This action cannot be undone."
)
) {
return;
}
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
await mem0client.deleteAll({
user_id: "youtube-assistant-mem0",
});
showStatus("All memories deleted successfully", "success");
await fetchMemories();
} catch (error) {
console.error("Error deleting memories:", error);
showStatus("Failed to delete memories", "error");
}
}
function editMemory(memory) {
currentMemory = memory;
const modal = document.getElementById("edit-memory-modal");
const textarea = document.getElementById("edit-memory-text");
textarea.value = memory.memory;
modal.classList.add("open");
}
function closeEditModal() {
const modal = document.getElementById("edit-memory-modal");
modal.classList.remove("open");
currentMemory = null;
}
async function saveMemory() {
if (!currentMemory) return;
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
const textarea = document.getElementById("edit-memory-text");
const updatedMemory = textarea.value.trim();
if (!updatedMemory) {
showStatus("Memory cannot be empty", "error");
return;
}
await mem0client.update(currentMemory.id, updatedMemory);
showStatus("Memory updated successfully", "success");
closeEditModal();
await fetchMemories();
} catch (error) {
console.error("Error updating memory:", error);
showStatus("Failed to update memory", "error");
}
}
async function deleteMemory(memoryId) {
if (
!confirm(
"Are you sure you want to delete this memory? This action cannot be undone."
)
) {
return;
}
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
await mem0client.delete(memoryId);
showStatus("Memory deleted successfully", "success");
await fetchMemories();
} catch (error) {
console.error("Error deleting memory:", error);
showStatus("Failed to delete memory", "error");
}
}
// Show status message
function showStatus(message, type = "info") {
const statusContainer = document.getElementById("status-container");
// Clear previous status
statusContainer.innerHTML = "";
// Create status element
const statusElement = document.createElement("div");
statusElement.className = `status ${type}`;
statusElement.textContent = message;
// Add to container
statusContainer.appendChild(statusElement);
// Auto-clear success messages after 3 seconds
if (type === "success") {
setTimeout(() => {
statusElement.style.opacity = "0";
setTimeout(() => {
if (statusContainer.contains(statusElement)) {
statusContainer.removeChild(statusElement);
}
}, 300);
}, 3000);
}
}
// Add memory to Mem0
async function addMemory() {
const memoryInput = document.getElementById("memory-input");
const addButton = document.getElementById("add-memory");
const memoryResult = document.getElementById("memory-result");
const buttonText = addButton.querySelector(".button-text");
const content = memoryInput.value.trim();
if (!content) {
showMemoryResult(
"Please enter some information to add as a memory",
"error"
);
return;
}
// Show loading state
addButton.disabled = true;
buttonText.textContent = "Adding...";
addButton.innerHTML =
'<div class="loading-spinner"></div><span class="button-text">Adding...</span>';
memoryResult.style.display = "none";
try {
if (!mem0client) {
const initialized = await initializeMem0AI();
if (!initialized) return;
}
const result = await mem0client.add(
[
{
role: "user",
content: content,
},
],
{
user_id: "youtube-assistant-mem0",
}
);
// Show success message with number of memories added
showMemoryResult(
`Added ${result.length || 0} new ${
result.length === 1 ? "memory" : "memories"
}`,
"success"
);
// Clear the input
memoryInput.value = "";
// Refresh the memories list
await fetchMemories();
} catch (error) {
showMemoryResult(`Error adding memory: ${error.message}`, "error");
} finally {
// Reset button state
addButton.disabled = false;
buttonText.textContent = "Add Memory";
addButton.innerHTML = '<span class="button-text">Add Memory</span>';
}
}
// Show memory result message
function showMemoryResult(message, type) {
const memoryResult = document.getElementById("memory-result");
memoryResult.textContent = message;
memoryResult.className = `memory-result ${type}`;
memoryResult.style.display = "block";
// Auto-clear success messages after 3 seconds
if (type === "success") {
setTimeout(() => {
memoryResult.style.opacity = "0";
setTimeout(() => {
memoryResult.style.display = "none";
memoryResult.style.opacity = "1";
}, 300);
}, 3000);
}
}
+241
View File
@@ -0,0 +1,241 @@
// Popup functionality for AI Chat Assistant
document.addEventListener("DOMContentLoaded", init);
// Initialize popup
async function init() {
try {
// Set up event listeners
document
.getElementById("toggle-chat")
.addEventListener("click", toggleChat);
document
.getElementById("open-options")
.addEventListener("click", openOptions);
document
.getElementById("save-api-key")
.addEventListener("click", saveApiKey);
document
.getElementById("save-mem0-api-key")
.addEventListener("click", saveMem0ApiKey);
// Set up password toggle listeners
document
.getElementById("toggle-openai-key")
.addEventListener("click", () => togglePasswordVisibility("api-key"));
document
.getElementById("toggle-mem0-key")
.addEventListener("click", () =>
togglePasswordVisibility("mem0-api-key")
);
// Load current configuration and wait for it to complete
await loadConfig();
} catch (error) {
console.error("Initialization error:", error);
showStatus("Error initializing popup", "error");
}
}
// Toggle chat visibility in the active tab
function toggleChat() {
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (tabs[0]) {
// First check if we can inject the content script
chrome.scripting
.executeScript({
target: { tabId: tabs[0].id },
files: ["dist/content.bundle.js"],
})
.then(() => {
// Now try to toggle the chat
chrome.tabs
.sendMessage(tabs[0].id, { action: "toggleChat" })
.then((response) => {
if (response && response.error) {
console.error("Error toggling chat:", response.error);
showStatus(
"Chat interface not available on this page",
"warning"
);
} else {
// Close the popup after successful toggle
window.close();
}
})
.catch((error) => {
console.error("Error toggling chat:", error);
showStatus(
"Chat interface not available on this page",
"warning"
);
});
})
.catch((error) => {
console.error("Error injecting content script:", error);
showStatus("Cannot inject chat interface on this page", "error");
});
}
});
}
// Open options page
function openOptions() {
// Send message to background script to handle opening options
chrome.runtime.sendMessage({ action: "openOptions" }, (response) => {
if (chrome.runtime.lastError) {
console.error("Error opening options:", chrome.runtime.lastError);
// Direct fallback if communication with background script fails
try {
chrome.tabs.create({ url: chrome.runtime.getURL("options.html") });
} catch (err) {
console.error("Fallback failed:", err);
// Last resort
window.open(chrome.runtime.getURL("options.html"), "_blank");
}
}
});
}
// Toggle password visibility
function togglePasswordVisibility(inputId) {
const input = document.getElementById(inputId);
const type = input.type === "password" ? "text" : "password";
input.type = type;
// Update the eye icon
const button = input.nextElementSibling;
const icon = button.querySelector(".icon");
if (type === "text") {
icon.innerHTML =
'<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"></path>';
} else {
icon.innerHTML =
'<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"></path><circle cx="12" cy="12" r="3"></circle>';
}
}
// Save API key to storage
async function saveApiKey() {
const apiKeyInput = document.getElementById("api-key");
const apiKey = apiKeyInput.value.trim();
// Show loading status
showStatus("Saving API key...", "warning");
try {
// Send to background script for validation and saving
const response = await chrome.runtime.sendMessage({
action: "saveConfig",
config: { apiKey },
});
if (response.error) {
showStatus(`Error: ${response.error}`, "error");
} else {
showStatus("API key saved successfully", "success");
loadConfig(); // Refresh the UI
}
} catch (error) {
showStatus(`Error: ${error.message}`, "error");
}
}
// Save mem0 API key to storage
async function saveMem0ApiKey() {
const apiKeyInput = document.getElementById("mem0-api-key");
const apiKey = apiKeyInput.value.trim();
// Show loading status
showStatus("Saving Mem0 API key...", "warning");
try {
// Send to background script for saving
const response = await chrome.runtime.sendMessage({
action: "saveConfig",
config: { mem0ApiKey: apiKey },
});
if (response.error) {
showStatus(`Error: ${response.error}`, "error");
} else {
showStatus("Mem0 API key saved successfully", "success");
loadConfig(); // Refresh the UI
}
} catch (error) {
showStatus(`Error: ${error.message}`, "error");
}
}
// Load configuration from storage
async function loadConfig() {
try {
// Add a small delay to ensure background script is ready
await new Promise((resolve) => setTimeout(resolve, 100));
const response = await chrome.runtime.sendMessage({ action: "getConfig" });
const config = response.config || {};
// Update OpenAI API key field
const apiKeyInput = document.getElementById("api-key");
if (config.apiKey) {
apiKeyInput.value = config.apiKey;
apiKeyInput.type = "password"; // Ensure it's hidden by default
document.getElementById("api-key-section").style.display = "block";
} else {
apiKeyInput.value = "";
document.getElementById("api-key-section").style.display = "block";
showStatus("Please set your OpenAI API key", "warning");
}
// Update mem0 API key field
const mem0ApiKeyInput = document.getElementById("mem0-api-key");
if (config.mem0ApiKey) {
mem0ApiKeyInput.value = config.mem0ApiKey;
mem0ApiKeyInput.type = "password"; // Ensure it's hidden by default
document.getElementById("mem0-api-key-section").style.display = "block";
document.getElementById("mem0-status-text").textContent = "Connected";
document.getElementById("mem0-status-text").style.color =
"var(--success-color)";
} else {
mem0ApiKeyInput.value = "";
document.getElementById("mem0-api-key-section").style.display = "block";
document.getElementById("mem0-status-text").textContent =
"Not configured";
document.getElementById("mem0-status-text").style.color =
"var(--warning-color)";
}
} catch (error) {
console.error("Error loading configuration:", error);
showStatus(`Error loading configuration: ${error.message}`, "error");
}
}
// Show status message
function showStatus(message, type = "info") {
const statusContainer = document.getElementById("status-container");
// Clear previous status
statusContainer.innerHTML = "";
// Create status element
const statusElement = document.createElement("div");
statusElement.className = `status ${type}`;
statusElement.textContent = message;
// Add to container
statusContainer.appendChild(statusElement);
// Auto-clear success messages after 3 seconds
if (type === "success") {
setTimeout(() => {
statusElement.style.opacity = "0";
setTimeout(() => {
if (statusContainer.contains(statusElement)) {
statusContainer.removeChild(statusElement);
}
}, 300);
}, 3000);
}
}
@@ -0,0 +1,492 @@
/* Styles for the AI Chat Assistant */
/* Modern Dark Theme with Blue Accents */
:root {
--chat-dark-bg: #1a1a1a;
--chat-darker-bg: #121212;
--chat-light-text: #f1f1f1;
--chat-blue-accent: #3d84f7;
--chat-blue-hover: #2d74e7;
--chat-blue-light: rgba(61, 132, 247, 0.15);
--chat-error: #ff4a4a;
--chat-border-radius: 12px;
--chat-message-radius: 12px;
--chat-transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Main container */
#ai-chat-assistant-container {
position: fixed;
right: 20px;
bottom: 20px;
width: 380px;
height: 550px;
background-color: var(--chat-dark-bg);
border-radius: var(--chat-border-radius);
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.3);
display: flex;
flex-direction: column;
z-index: 9999;
overflow: hidden;
transition: var(--chat-transition);
opacity: 0;
transform: translateY(20px) scale(0.98);
pointer-events: none;
font-family: 'Roboto', -apple-system, BlinkMacSystemFont, sans-serif;
border: 1px solid rgba(255, 255, 255, 0.08);
}
/* When visible */
#ai-chat-assistant-container.visible {
opacity: 1;
transform: translateY(0) scale(1);
pointer-events: all;
}
/* When minimized */
#ai-chat-assistant-container.minimized {
height: 50px;
}
#ai-chat-assistant-container.minimized .ai-chat-body {
display: none;
}
/* Header */
.ai-chat-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 12px 16px;
background-color: var(--chat-darker-bg);
color: var(--chat-light-text);
border-top-left-radius: var(--chat-border-radius);
border-top-right-radius: var(--chat-border-radius);
cursor: move;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.ai-chat-title {
font-weight: 500;
font-size: 15px;
display: flex;
align-items: center;
gap: 6px;
}
.ai-chat-title::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
background-color: var(--chat-blue-accent);
border-radius: 50%;
box-shadow: 0 0 10px var(--chat-blue-accent);
}
.ai-chat-controls {
display: flex;
gap: 8px;
}
.ai-chat-btn {
background: none;
border: none;
color: var(--chat-light-text);
font-size: 18px;
cursor: pointer;
width: 28px;
height: 28px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--chat-transition);
}
.ai-chat-btn:hover {
background-color: rgba(255, 255, 255, 0.08);
}
/* Body */
.ai-chat-body {
flex: 1;
display: flex;
flex-direction: column;
overflow: hidden;
background-color: var(--chat-dark-bg);
}
/* Messages container */
.ai-chat-messages {
flex: 1;
overflow-y: auto;
padding: 15px;
display: flex;
flex-direction: column;
gap: 12px;
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
.ai-chat-messages::-webkit-scrollbar {
width: 5px;
}
.ai-chat-messages::-webkit-scrollbar-track {
background: transparent;
}
.ai-chat-messages::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
/* Individual message */
.ai-chat-message {
max-width: 85%;
padding: 12px 16px;
border-radius: var(--chat-message-radius);
line-height: 1.5;
position: relative;
font-size: 14px;
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
animation: message-fade-in 0.3s ease;
word-break: break-word;
}
@keyframes message-fade-in {
from {
opacity: 0;
transform: translateY(10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* User message */
.ai-chat-message.user {
align-self: flex-end;
background-color: var(--chat-blue-accent);
color: white;
border-bottom-right-radius: 4px;
}
/* Assistant message */
.ai-chat-message.assistant {
align-self: flex-start;
background-color: rgba(255, 255, 255, 0.08);
color: var(--chat-light-text);
border-bottom-left-radius: 4px;
}
/* System message */
.ai-chat-message.system {
align-self: center;
background-color: rgba(255, 76, 76, 0.1);
color: var(--chat-error);
max-width: 90%;
font-size: 13px;
border-radius: 8px;
border: 1px solid rgba(255, 76, 76, 0.2);
}
/* Loading animation */
.ai-chat-message.loading {
background-color: rgba(255, 255, 255, 0.05);
color: rgba(255, 255, 255, 0.7);
}
.ai-chat-message.loading:after {
content: "...";
animation: thinking 1.5s infinite;
}
@keyframes thinking {
0% { content: "."; }
33% { content: ".."; }
66% { content: "..."; }
}
/* Input area */
.ai-chat-input-container {
display: flex;
padding: 12px 16px;
border-top: 1px solid rgba(255, 255, 255, 0.05);
background-color: var(--chat-darker-bg);
}
#ai-chat-input {
flex: 1;
border: 1px solid rgba(255, 255, 255, 0.1);
background-color: rgba(255, 255, 255, 0.05);
color: var(--chat-light-text);
border-radius: 20px;
padding: 10px 16px;
font-size: 14px;
resize: none;
max-height: 100px;
outline: none;
font-family: inherit;
transition: var(--chat-transition);
}
#ai-chat-input::placeholder {
color: rgba(255, 255, 255, 0.4);
}
#ai-chat-input:focus {
border-color: var(--chat-blue-accent);
background-color: rgba(255, 255, 255, 0.07);
box-shadow: 0 0 0 1px rgba(61, 132, 247, 0.1);
}
.ai-chat-send-btn {
background: none;
border: none;
color: var(--chat-blue-accent);
cursor: pointer;
padding: 8px;
margin-left: 8px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: var(--chat-transition);
}
.ai-chat-send-btn:hover {
background-color: var(--chat-blue-light);
transform: scale(1.05);
}
/* Toggle button */
.ai-chat-toggle {
position: fixed;
right: 20px;
bottom: 20px;
width: 56px;
height: 56px;
border-radius: 50%;
background-color: var(--chat-blue-accent);
color: white;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
box-shadow: 0 4px 15px rgba(61, 132, 247, 0.35);
z-index: 9998;
transition: var(--chat-transition);
border: none;
}
.ai-chat-toggle:hover {
transform: scale(1.05);
box-shadow: 0 6px 20px rgba(61, 132, 247, 0.45);
}
#ai-chat-assistant-container.visible + .ai-chat-toggle {
transform: scale(0);
opacity: 0;
}
/* Code formatting */
.ai-chat-message pre {
background-color: rgba(0, 0, 0, 0.3);
padding: 10px;
border-radius: 6px;
overflow-x: auto;
margin: 10px 0;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.ai-chat-message code {
font-family: 'Cascadia Code', 'Fira Code', 'Source Code Pro', monospace;
font-size: 12px;
}
.ai-chat-message.user code {
background-color: rgba(255, 255, 255, 0.2);
padding: 2px 5px;
border-radius: 3px;
}
.ai-chat-message.assistant code {
background-color: rgba(0, 0, 0, 0.3);
padding: 2px 5px;
border-radius: 3px;
color: #e2e2e2;
}
/* Links */
.ai-chat-message a {
color: var(--chat-blue-accent);
text-decoration: none;
border-bottom: 1px dotted rgba(61, 132, 247, 0.5);
transition: var(--chat-transition);
}
.ai-chat-message a:hover {
border-bottom: 1px solid var(--chat-blue-accent);
}
.ai-chat-message.user a {
color: white;
border-bottom: 1px dotted rgba(255, 255, 255, 0.5);
}
.ai-chat-message.user a:hover {
border-bottom: 1px solid white;
}
/* Responsive adjustments */
@media (max-width: 768px) {
#ai-chat-assistant-container {
width: calc(100% - 20px);
height: 60vh;
right: 10px;
bottom: 10px;
}
.ai-chat-toggle {
right: 10px;
bottom: 10px;
}
}
/* Tab styles */
.ai-chat-tabs {
display: flex;
gap: 10px;
margin-right: 10px;
}
.ai-chat-tab {
background: none;
border: none;
color: var(--chat-light-text);
padding: 5px 10px;
cursor: pointer;
font-size: 14px;
border-radius: 4px;
transition: var(--chat-transition);
}
.ai-chat-tab:hover {
background-color: rgba(255, 255, 255, 0.08);
}
.ai-chat-tab.active {
background-color: var(--chat-blue-accent);
color: white;
}
/* Content area */
.ai-chat-content {
display: flex;
flex-direction: column;
height: 100%;
}
/* Memories tab styles */
.ai-chat-memories {
display: flex;
flex-direction: column;
height: 100%;
background-color: var(--chat-dark-bg);
}
.memories-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px;
padding-left: 16px;
padding-right: 16px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.memories-title {
display: inline;
align-items: center;
font-size: 14px;
color: var(--chat-light-text);
}
.memories-title a {
color: var(--chat-blue-accent);
text-decoration: none;
font-weight: 500;
transition: var(--chat-transition);
display: inline-flex;
align-items: center;
gap: 4px;
}
.memories-title a:hover {
color: var(--chat-blue-hover);
text-decoration: underline;
}
.memories-title a svg {
vertical-align: middle;
}
.memories-title svg {
vertical-align: middle;
margin-left: 4px;
}
.memories-list {
flex: 1;
overflow-y: auto;
padding: 10px;
scrollbar-width: thin;
scrollbar-color: rgba(255, 255, 255, 0.1) transparent;
}
.memories-list::-webkit-scrollbar {
width: 5px;
}
.memories-list::-webkit-scrollbar-track {
background: transparent;
}
.memories-list::-webkit-scrollbar-thumb {
background-color: rgba(255, 255, 255, 0.1);
border-radius: 10px;
}
.memory-item {
background-color: rgba(255, 255, 255, 0.08);
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: var(--chat-message-radius);
padding: 12px 16px;
margin-bottom: 10px;
font-size: 14px;
line-height: 1.4;
color: var(--chat-light-text);
}
.memory-item:last-child {
margin-bottom: 0;
}
.loading, .no-memories, .error, .info {
text-align: center;
padding: 20px;
font-size: 14px;
color: var(--chat-light-text);
}
.error {
color: var(--chat-error);
font-size: 14px;
}
.info {
color: var(--chat-blue-accent);
}
@@ -0,0 +1,587 @@
:root {
--dark-bg: #1a1a1a;
--darker-bg: #121212;
--section-bg: #202020;
--light-text: #f1f1f1;
--dim-text: rgba(255, 255, 255, 0.7);
--dim-text-2: rgba(255, 255, 255, 0.5);
--blue-accent: #3d84f7;
--blue-hover: #2d74e7;
--blue-light: rgba(61, 132, 247, 0.15);
--error-color: #ff4a4a;
--warning-color: #ffaa33;
--success-color: #4caf50;
--border-radius: 8px;
--transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
body {
font-family: "Roboto", -apple-system, BlinkMacSystemFont, sans-serif;
margin: 0;
padding: 20px 20px 40px;
color: var(--light-text);
background-color: var(--dark-bg);
max-width: 1200px;
margin: 0 auto;
}
header {
max-width: 800px;
padding-left: 28px;
padding-top: 10px;
color: #f1f1f1;
}
h1 {
font-size: 32px;
margin: 0 0 12px 0;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
}
.title-container {
display: flex;
align-items: center;
gap: 10px;
}
.logo-img {
height: 20px;
width: auto;
margin-left: 8px;
position: relative;
top: 1px;
}
.powered-by {
font-size: 12px;
font-weight: normal;
color: rgba(255, 255, 255, 0.6);
line-height: 1;
}
.branding-container {
display: flex;
align-items: center;
justify-content: center;
}
.description {
color: var(--dim-text);
margin-bottom: 20px;
font-size: 15px;
line-height: 1.5;
}
.section {
margin-bottom: 30px;
background: var(--section-bg);
padding: 28px;
border-radius: var(--border-radius);
border: 1px solid rgba(255, 255, 255, 0.05);
box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
}
h2 {
font-size: 18px;
margin-top: 0;
margin-bottom: 15px;
color: var(--light-text);
display: flex;
align-items: center;
gap: 8px;
}
h2::before {
content: "";
display: inline-block;
width: 5px;
height: 20px;
background-color: var(--blue-accent);
border-radius: 3px;
}
.form-group {
margin-bottom: 20px;
}
label {
display: block;
margin-bottom: 8px;
font-weight: 500;
color: var(--light-text);
}
input[type="text"],
input[type="password"],
input[type="number"],
select {
width: 100%;
padding: 12px;
background-color: rgba(255, 255, 255, 0.05);
color: var(--light-text);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--border-radius);
font-size: 14px;
box-sizing: border-box;
transition: var(--transition);
}
input[type="text"]:focus,
input[type="password"]:focus,
input[type="number"]:focus,
select:focus {
border-color: var(--blue-accent);
outline: none;
box-shadow: 0 0 0 1px rgba(61, 132, 247, 0.2);
}
select {
appearance: none;
background-image: url("data:image/svg+xml;charset=US-ASCII,%3Csvg%20width%3D%2220%22%20height%3D%2220%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M5%207l5%205%205-5%22%20stroke%3D%22%23fff%22%20stroke-width%3D%221.5%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E");
background-repeat: no-repeat;
background-position: right 12px center;
}
input[type="number"] {
width: 120px;
}
input[type="checkbox"] {
margin-right: 10px;
position: relative;
width: 18px;
height: 18px;
-webkit-appearance: none;
appearance: none;
background-color: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 4px;
cursor: pointer;
transition: var(--transition);
}
input[type="checkbox"]:checked {
background-color: var(--blue-accent);
border-color: var(--blue-accent);
}
input[type="checkbox"]:checked::after {
content: "";
position: absolute;
left: 5px;
top: 2px;
width: 6px;
height: 10px;
border: solid white;
border-width: 0 2px 2px 0;
transform: rotate(45deg);
}
input[type="checkbox"]:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.checkbox-label {
display: flex;
align-items: center;
margin-bottom: 12px;
font-size: 14px;
color: var(--light-text);
}
.checkbox-label label {
margin-bottom: 0;
margin-left: 8px;
}
button {
background-color: var(--blue-accent);
color: white;
border: none;
padding: 12px 20px;
border-radius: var(--border-radius);
cursor: pointer;
font-size: 14px;
font-weight: 500;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
button:hover {
background-color: var(--blue-hover);
transform: translateY(-1px);
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2);
}
button:active {
transform: translateY(1px);
box-shadow: none;
}
button:disabled {
background-color: rgba(255, 255, 255, 0.1);
color: var(--dim-text-2);
cursor: not-allowed;
transform: none;
box-shadow: none;
}
.status {
padding: 15px;
border-radius: var(--border-radius);
margin-top: 20px;
font-size: 14px;
animation: fade-in 0.3s ease;
}
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(-5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.status.error {
background-color: rgba(255, 74, 74, 0.1);
color: var(--error-color);
border: 1px solid rgba(255, 74, 74, 0.2);
}
.status.success {
background-color: rgba(76, 175, 80, 0.1);
color: var(--success-color);
border: 1px solid rgba(76, 175, 80, 0.2);
}
.status.warning {
background-color: rgba(255, 170, 51, 0.1);
color: var(--warning-color);
border: 1px solid rgba(255, 170, 51, 0.2);
}
.actions {
display: flex;
gap: 10px;
}
.secondary-button {
background-color: rgba(255, 255, 255, 0.08);
color: var(--light-text);
}
.secondary-button:hover {
background-color: rgba(255, 255, 255, 0.12);
}
.api-key-container {
display: flex;
gap: 10px;
}
.api-key-container input {
flex: 1;
}
/* Slider styles */
.slider-container {
margin-top: 12px;
display: flex;
align-items: center;
}
.slider {
-webkit-appearance: none;
flex: 1;
height: 4px;
border-radius: 10px;
background: rgba(255, 255, 255, 0.1);
outline: none;
}
.slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--blue-accent);
cursor: pointer;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
transition: var(--transition);
}
.slider::-webkit-slider-thumb:hover {
transform: scale(1.1);
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
}
.slider::-moz-range-thumb {
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--blue-accent);
cursor: pointer;
box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
transition: var(--transition);
border: none;
}
.slider::-moz-range-thumb:hover {
transform: scale(1.1);
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
}
/* Add styles for memory creation section */
.memory-input {
width: 100%;
min-height: 150px;
padding: 12px;
background-color: rgba(255, 255, 255, 0.05);
color: var(--light-text);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--border-radius);
font-size: 14px;
box-sizing: border-box;
transition: var(--transition);
resize: vertical;
font-family: inherit;
}
.memory-input:focus {
border-color: var(--blue-accent);
outline: none;
box-shadow: 0 0 0 1px rgba(61, 132, 247, 0.2);
}
.memory-result {
margin-top: 15px;
padding: 12px;
border-radius: var(--border-radius);
font-size: 14px;
display: none;
}
.memory-result.success {
background-color: rgba(76, 175, 80, 0.1);
color: var(--success-color);
border: 1px solid rgba(76, 175, 80, 0.2);
display: block;
}
.memory-result.error {
background-color: rgba(255, 74, 74, 0.1);
color: var(--error-color);
border: 1px solid rgba(255, 74, 74, 0.2);
display: block;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 50%;
border-top-color: var(--light-text);
animation: spin 1s linear infinite;
margin-right: 8px;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* Add new styles for the memories sidebar */
.memories-sidebar {
position: fixed;
top: 0;
right: 0;
width: 384px;
height: 100vh;
background: var(--section-bg);
border-left: 1px solid rgba(255, 255, 255, 0.05);
transition: transform 0.3s ease;
z-index: 1000;
display: flex;
flex-direction: column;
}
.memories-sidebar.collapsed {
transform: translateX(384px);
}
.memories-header {
padding: 16px;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
display: flex;
justify-content: space-between;
align-items: center;
}
.memories-title {
font-size: 16px;
font-weight: 500;
color: var(--light-text);
}
.memories-actions {
display: flex;
gap: 8px;
}
.memories-list {
flex: 1;
overflow-y: auto;
padding: 16px;
}
.memory-item {
padding: 12px;
border: 1px solid rgba(255, 255, 255, 0.05);
border-radius: var(--border-radius);
margin-bottom: 12px;
cursor: pointer;
transition: var(--transition);
}
.memory-item:hover {
background: rgba(255, 255, 255, 0.05);
}
.memory-content {
font-size: 14px;
color: var(--light-text);
margin-bottom: 8px;
text-align: center;
text-wrap-style: pretty;
}
.memory-item .memory-content {
text-align: left;
}
.memory-meta {
font-size: 12px;
color: var(--dim-text);
}
.memory-actions {
display: flex;
gap: 8px;
margin-top: 8px;
}
.memory-action-btn {
padding: 8px;
font-size: 12px;
border-radius: 6px;
background: rgba(255, 255, 255, 0.05);
color: var(--light-text);
border: none;
cursor: pointer;
transition: var(--transition);
}
.memory-action-btn:hover {
background: rgba(255, 255, 255, 0.1);
}
.memory-action-btn.delete:hover {
background-color: var(--error-color);
}
.edit-memory-modal {
display: none;
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
z-index: 1100;
align-items: center;
justify-content: center;
}
.edit-memory-modal.open {
display: flex;
}
.edit-memory-content {
display: flex;
flex-direction: column;
background: var(--section-bg);
padding: 24px;
border-radius: var(--border-radius);
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.edit-memory-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.edit-memory-title {
font-size: 18px;
font-weight: 500;
color: var(--light-text);
}
.edit-memory-close {
background: none;
border: none;
color: var(--dim-text);
cursor: pointer;
padding: 4px;
font-size: 20px;
width: 30px;
}
.edit-memory-textarea {
min-height: 20px;
max-height: 70px;
padding: 12px;
background: rgba(255, 255, 255, 0.05);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--border-radius);
color: var(--light-text);
font-family: inherit;
margin-bottom: 16px;
resize: vertical;
}
.edit-memory-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.main-content {
margin-right: 400px;
transition: margin-right 0.3s ease;
max-width: 800px;
}
.main-content.sidebar-collapsed {
margin-right: 0;
}
#status-container {
margin-bottom: 12px;
}
@@ -0,0 +1,259 @@
:root {
--dark-bg: #1a1a1a;
--darker-bg: #121212;
--light-text: #f1f1f1;
--blue-accent: #3d84f7;
--blue-hover: #2d74e7;
--blue-light: rgba(61, 132, 247, 0.15);
--error-color: #ff4a4a;
--warning-color: #ffaa33;
--success-color: #4caf50;
--border-radius: 8px;
--transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
}
body {
font-family: "Roboto", -apple-system, BlinkMacSystemFont, sans-serif;
width: 320px;
margin: 0;
padding: 0;
color: var(--light-text);
background-color: var(--dark-bg);
}
header {
background-color: var(--darker-bg);
color: var(--light-text);
padding: 16px;
text-align: center;
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
h1 {
font-size: 18px;
margin: 0 0 8px 0;
font-weight: 500;
display: flex;
align-items: center;
justify-content: center;
}
.logo-img {
height: 16px;
width: auto;
margin-left: 8px;
position: relative;
top: 1px;
}
.powered-by {
font-size: 12px;
font-weight: normal;
color: rgba(255, 255, 255, 0.6);
line-height: 1;
}
.branding-container {
display: flex;
align-items: center;
justify-content: center;
margin-top: 4px;
}
.content {
padding: 16px;
}
.status {
padding: 12px;
border-radius: var(--border-radius);
margin-bottom: 16px;
font-size: 14px;
animation: fade-in 0.3s ease;
}
@keyframes fade-in {
from {
opacity: 0;
transform: translateY(-5px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.status.error {
background-color: rgba(255, 74, 74, 0.1);
color: var(--error-color);
border: 1px solid rgba(255, 74, 74, 0.2);
}
.status.success {
background-color: rgba(76, 175, 80, 0.1);
color: var(--success-color);
border: 1px solid rgba(76, 175, 80, 0.2);
}
.status.warning {
background-color: rgba(255, 170, 51, 0.1);
color: var(--warning-color);
border: 1px solid rgba(255, 170, 51, 0.2);
}
button {
background-color: var(--blue-accent);
color: white;
border: none;
padding: 12px 16px;
border-radius: 6px;
cursor: pointer;
width: 100%;
font-size: 14px;
font-weight: 500;
transition: var(--transition);
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
}
button:hover {
background-color: var(--blue-hover);
transform: translateY(-1px);
}
button:active {
transform: translateY(1px);
}
button:disabled {
background-color: rgba(255, 255, 255, 0.1);
color: rgba(255, 255, 255, 0.4);
cursor: not-allowed;
transform: none;
}
.actions {
display: flex;
flex-direction: row;
gap: 12px;
}
.api-key-section {
margin-bottom: 20px;
position: relative;
}
.api-key-input-wrapper {
position: relative;
display: flex;
align-items: center;
}
.toggle-password {
position: absolute;
right: 12px;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
padding: 4px;
cursor: pointer;
color: rgba(255, 255, 255, 0.5);
width: auto;
display: flex;
align-items: center;
justify-content: center;
}
.toggle-password:hover {
color: rgba(255, 255, 255, 0.8);
background: none;
transform: translateY(-50%);
}
.toggle-password .icon {
width: 16px;
height: 16px;
}
input[type="text"],
input[type="password"] {
width: 100%;
padding: 12px;
padding-right: 40px;
background-color: rgba(255, 255, 255, 0.05);
color: var(--light-text);
border: 1px solid rgba(255, 255, 255, 0.1);
border-radius: var(--border-radius);
margin-top: 6px;
box-sizing: border-box;
transition: var(--transition);
font-size: 14px;
}
input[type="text"]:focus,
input[type="password"]:focus {
border-color: var(--blue-accent);
outline: none;
box-shadow: 0 0 0 1px rgba(61, 132, 247, 0.2);
}
input::placeholder {
color: rgba(255, 255, 255, 0.3);
}
label {
font-size: 14px;
font-weight: 500;
color: rgba(255, 255, 255, 0.9);
display: block;
margin-bottom: 4px;
}
.save-button {
margin-top: 10px;
}
.mem0-status {
margin-top: 20px;
padding: 12px;
background-color: rgba(255, 255, 255, 0.03);
border-radius: var(--border-radius);
font-size: 13px;
color: rgba(255, 255, 255, 0.7);
}
.mem0-status p {
margin: 0;
}
#mem0-status-text {
color: var(--blue-accent);
font-weight: 500;
}
/* Icons */
.icon {
display: inline-block;
width: 18px;
height: 18px;
fill: currentColor;
}
.get-key-link {
color: var(--blue-accent);
text-decoration: none;
font-size: 13px;
transition: color 0.2s ease;
}
.get-key-link:hover {
color: var(--blue-accent-hover);
text-decoration: underline;
}
.get-key-link:visited {
color: var(--blue-accent);
}
@@ -0,0 +1,40 @@
const path = require('path');
module.exports = {
mode: 'production',
entry: {
content: './src/content.js',
options: './src/options.js',
popup: './src/popup.js',
background: './src/background.js'
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
devtool: 'source-map',
optimization: {
minimize: false
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
},
resolve: {
extensions: ['.js']
}
};
+20 -17
View File
@@ -1,6 +1,6 @@
{
"name": "mem0ai",
"version": "2.1.1",
"version": "2.1.15",
"description": "The Memory Layer For Your AI Apps",
"main": "./dist/index.js",
"module": "./dist/index.mjs",
@@ -31,9 +31,11 @@
"dist"
],
"scripts": {
"clean": "rm -rf dist",
"build": "npm run clean && prettier --check . && tsup",
"dev": "nodemon",
"clean": "rimraf dist",
"build": "npm run clean && npx prettier --check . && npx tsup",
"dev": "npx nodemon",
"start": "pnpm run example memory",
"example": "ts-node src/oss/examples/vector-stores/index.ts",
"test": "jest",
"test:ts": "jest --config jest.config.js",
"test:watch": "jest --config jest.config.js --watch",
@@ -55,7 +57,13 @@
"sourcemap": true,
"clean": true,
"treeshake": true,
"minify": false
"minify": false,
"external": [
"@mem0/community"
],
"noExternal": [
"!src/community/**"
]
},
"keywords": [
"mem0",
@@ -74,7 +82,9 @@
"dotenv": "^16.4.5",
"fix-tsup-cjs": "^1.2.0",
"jest": "^29.7.0",
"nodemon": "^3.0.1",
"prettier": "^3.5.2",
"rimraf": "^5.0.5",
"ts-jest": "^29.2.6",
"ts-node": "^10.9.2",
"tsup": "^8.3.0",
@@ -82,33 +92,26 @@
},
"dependencies": {
"axios": "1.7.7",
"neo4j-driver": "^5.28.1",
"openai": "4.28.0",
"redis": "^4.6.13",
"uuid": "9.0.1",
"zod": "3.22.4"
},
"peerDependencies": {
"@anthropic-ai/sdk": "0.18.0",
"@qdrant/js-client-rest": "1.13.0",
"@google/genai": "^0.7.0",
"@supabase/supabase-js": "^2.49.1",
"@types/jest": "29.5.14",
"@types/pg": "8.11.0",
"@types/sqlite3": "3.1.11",
"groq-sdk": "0.3.0",
"neo4j-driver": "^5.28.1",
"ollama": "^0.5.14",
"pg": "8.11.3",
"redis": "4.7.0",
"sqlite3": "5.1.7"
},
"peerDependenciesMeta": {
"posthog-node": {
"optional": true
},
"posthog-js": {
"optional": true
}
},
"optionalDependencies": {
"posthog-js": "^1.116.6"
},
"engines": {
"node": ">=18"
},
+7751
View File
File diff suppressed because it is too large Load Diff
+2 -12
View File
@@ -1,10 +1,4 @@
import { MemoryClient } from "./mem0";
import type { TelemetryClient, TelemetryInstance } from "./telemetry.types";
import {
telemetry,
captureClientEvent,
generateHash,
} from "./telemetry.browser";
import type * as MemoryTypes from "./mem0.types";
// Re-export all types from mem0.types
@@ -23,14 +17,10 @@ export type {
Message,
AllUsers,
User,
FeedbackPayload,
Feedback,
} from "./mem0.types";
// Export telemetry types
export type { TelemetryClient, TelemetryInstance };
// Export telemetry implementation
export { telemetry, captureClientEvent, generateHash };
// Export the main client
export { MemoryClient };
export default MemoryClient;
+126 -49
View File
@@ -12,6 +12,7 @@ import {
Webhook,
WebhookPayload,
Message,
FeedbackPayload,
} from "./mem0.types";
import { captureClientEvent, generateHash } from "./telemetry";
@@ -61,7 +62,7 @@ export default class MemoryClient {
(this.organizationName !== null && this.projectName === null)
) {
console.warn(
"Warning: Both organizationName and projectName must be provided together when using either. This will be removedfrom the version 1.0.40. Note that organizationName/projectName are being deprecated in favor of organizationId/projectId.",
"Warning: Both organizationName and projectName must be provided together when using either. This will be removed from version 1.0.40. Note that organizationName/projectName are being deprecated in favor of organizationId/projectId.",
);
}
@@ -71,7 +72,7 @@ export default class MemoryClient {
(this.organizationId !== null && this.projectId === null)
) {
console.warn(
"Warning: Both organizationId and projectId must be provided together when using either. This will be removedfrom the version 1.0.40.",
"Warning: Both organizationId and projectId must be provided together when using either. This will be removed from version 1.0.40.",
);
}
}
@@ -96,7 +97,6 @@ export default class MemoryClient {
});
this._validateApiKey();
this._validateOrgProject();
// Initialize with a temporary ID that will be updated
this.telemetryId = "";
@@ -107,59 +107,50 @@ export default class MemoryClient {
private async _initializeClient() {
try {
// do this only in browser
if (typeof window !== "undefined") {
this.telemetryId = await generateHash(this.apiKey);
await captureClientEvent("init", this);
// Generate telemetry ID
await this.ping();
if (!this.telemetryId) {
this.telemetryId = generateHash(this.apiKey);
}
// Wrap methods after initialization
this.add = this.wrapMethod("add", this.add);
this.get = this.wrapMethod("get", this.get);
this.getAll = this.wrapMethod("get_all", this.getAll);
this.search = this.wrapMethod("search", this.search);
this.delete = this.wrapMethod("delete", this.delete);
this.deleteAll = this.wrapMethod("delete_all", this.deleteAll);
this.history = this.wrapMethod("history", this.history);
this.users = this.wrapMethod("users", this.users);
this.deleteUser = this.wrapMethod("delete_user", this.deleteUser);
this.deleteUsers = this.wrapMethod("delete_users", this.deleteUsers);
this.batchUpdate = this.wrapMethod("batch_update", this.batchUpdate);
this.batchDelete = this.wrapMethod("batch_delete", this.batchDelete);
this.getProject = this.wrapMethod("get_project", this.getProject);
this.updateProject = this.wrapMethod(
"update_project",
this.updateProject,
);
this.getWebhooks = this.wrapMethod("get_webhook", this.getWebhooks);
this.createWebhook = this.wrapMethod(
"create_webhook",
this.createWebhook,
);
this.updateWebhook = this.wrapMethod(
"update_webhook",
this.updateWebhook,
);
this.deleteWebhook = this.wrapMethod(
"delete_webhook",
this.deleteWebhook,
);
} catch (error) {
this._validateOrgProject();
// Capture initialization event
captureClientEvent("init", this, {
api_version: "v1",
client_type: "MemoryClient",
}).catch((error: any) => {
console.error("Failed to capture event:", error);
});
} catch (error: any) {
console.error("Failed to initialize client:", error);
await captureClientEvent("init_error", this, {
error: error?.message || "Unknown error",
stack: error?.stack || "No stack trace",
});
}
}
wrapMethod(methodName: any, method: any) {
return async function (...args: any) {
// @ts-ignore
await captureClientEvent(methodName, this);
// @ts-ignore
return method.apply(this, args);
}.bind(this);
private _captureEvent(methodName: string, args: any[]) {
captureClientEvent(methodName, this, {
success: true,
args_count: args.length,
keys: args.length > 0 ? args[0] : [],
}).catch((error: any) => {
console.error("Failed to capture event:", error);
});
}
async _fetchWithErrorHandling(url: string, options: any): Promise<any> {
const response = await fetch(url, options);
const response = await fetch(url, {
...options,
headers: {
...options.headers,
Authorization: `Token ${this.apiKey}`,
"Mem0-User-ID": this.telemetryId,
},
});
if (!response.ok) {
const errorData = await response.text();
throw new APIError(`API request failed: ${errorData}`);
@@ -187,10 +178,31 @@ export default class MemoryClient {
);
}
async ping(): Promise<void> {
const response = await fetch(`${this.host}/v1/ping/`, {
headers: {
Authorization: `Token ${this.apiKey}`,
},
});
const data = await response.json();
if (data.status !== "ok") {
throw new Error("API Key is invalid");
}
const { org_id, project_id, user_email } = data;
this.organizationId = org_id || null;
this.projectId = project_id || null;
this.telemetryId = user_email || "";
}
async add(
messages: string | Array<Message>,
options: MemoryOptions = {},
): Promise<Array<Memory>> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
if (this.organizationName != null && this.projectName != null) {
options.org_name = this.organizationName;
@@ -205,7 +217,16 @@ export default class MemoryClient {
if (options.project_name) delete options.project_name;
}
if (options.api_version) {
options.version = options.api_version.toString();
}
const payload = this._preparePayload(messages, options);
// get payload keys whose value is not null or undefined
const payloadKeys = Object.keys(payload);
this._captureEvent("add", [payloadKeys]);
const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/`,
{
@@ -218,10 +239,15 @@ export default class MemoryClient {
}
async update(memoryId: string, message: string): Promise<Array<Memory>> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
const payload = {
text: message,
};
const payloadKeys = Object.keys(payload);
this._captureEvent("update", [payloadKeys]);
const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/`,
{
@@ -234,6 +260,8 @@ export default class MemoryClient {
}
async get(memoryId: string): Promise<Memory> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("get", []);
return this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/`,
{
@@ -243,7 +271,10 @@ export default class MemoryClient {
}
async getAll(options?: SearchOptions): Promise<Array<Memory>> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("get_all", [payloadKeys]);
const { api_version, page, page_size, ...otherOptions } = options!;
if (this.organizationName != null && this.projectName != null) {
otherOptions.org_name = this.organizationName;
@@ -288,7 +319,10 @@ export default class MemoryClient {
}
async search(query: string, options?: SearchOptions): Promise<Array<Memory>> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("search", [payloadKeys]);
const { api_version, ...otherOptions } = options!;
const payload = { query, ...otherOptions };
if (this.organizationName != null && this.projectName != null) {
@@ -317,6 +351,8 @@ export default class MemoryClient {
}
async delete(memoryId: string): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("delete", []);
return this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/`,
{
@@ -327,7 +363,10 @@ export default class MemoryClient {
}
async deleteAll(options: MemoryOptions = {}): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("delete_all", [payloadKeys]);
if (this.organizationName != null && this.projectName != null) {
options.org_name = this.organizationName;
options.project_name = this.projectName;
@@ -353,6 +392,8 @@ export default class MemoryClient {
}
async history(memoryId: string): Promise<Array<MemoryHistory>> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("history", []);
const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/history/`,
{
@@ -363,7 +404,9 @@ export default class MemoryClient {
}
async users(): Promise<AllUsers> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
this._captureEvent("users", []);
const options: MemoryOptions = {};
if (this.organizationName != null && this.projectName != null) {
options.org_name = this.organizationName;
@@ -392,6 +435,8 @@ export default class MemoryClient {
entityId: string,
entity: { type: string } = { type: "user" },
): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("delete_user", []);
const response = await this._fetchWithErrorHandling(
`${this.host}/v1/entities/${entity.type}/${entityId}/`,
{
@@ -403,7 +448,9 @@ export default class MemoryClient {
}
async deleteUsers(): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
this._captureEvent("delete_users", []);
const entities = await this.users();
for (const entity of entities.results) {
@@ -428,6 +475,8 @@ export default class MemoryClient {
}
async batchUpdate(memories: Array<MemoryUpdateBody>): Promise<string> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("batch_update", []);
const memoriesBody = memories.map((memory) => ({
memory_id: memory.memoryId,
text: memory.text,
@@ -444,6 +493,8 @@ export default class MemoryClient {
}
async batchDelete(memories: Array<string>): Promise<string> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("batch_delete", []);
const memoriesBody = memories.map((memory) => ({
memory_id: memory,
}));
@@ -459,8 +510,10 @@ export default class MemoryClient {
}
async getProject(options: ProjectOptions): Promise<ProjectResponse> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("get_project", [payloadKeys]);
const { fields } = options;
if (!(this.organizationId && this.projectId)) {
@@ -484,8 +537,9 @@ export default class MemoryClient {
async updateProject(
prompts: PromptUpdatePayload,
): Promise<Record<string, any>> {
if (this.telemetryId === "") await this.ping();
this._validateOrgProject();
this._captureEvent("update_project", []);
if (!(this.organizationId && this.projectId)) {
throw new Error(
"organizationId and projectId must be set to update instructions or categories",
@@ -505,6 +559,8 @@ export default class MemoryClient {
// WebHooks
async getWebhooks(data?: { projectId?: string }): Promise<Array<Webhook>> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("get_webhooks", []);
const project_id = data?.projectId || this.projectId;
const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/projects/${project_id}/`,
@@ -516,6 +572,8 @@ export default class MemoryClient {
}
async createWebhook(webhook: WebhookPayload): Promise<Webhook> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("create_webhook", []);
const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/projects/${this.projectId}/`,
{
@@ -528,6 +586,8 @@ export default class MemoryClient {
}
async updateWebhook(webhook: WebhookPayload): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("update_webhook", []);
const project_id = webhook.projectId || this.projectId;
const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/${webhook.webhookId}/`,
@@ -546,6 +606,8 @@ export default class MemoryClient {
async deleteWebhook(data: {
webhookId: string;
}): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
this._captureEvent("delete_webhook", []);
const webhook_id = data.webhookId || data;
const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/${webhook_id}/`,
@@ -556,6 +618,21 @@ export default class MemoryClient {
);
return response;
}
async feedback(data: FeedbackPayload): Promise<{ message: string }> {
if (this.telemetryId === "") await this.ping();
const payloadKeys = Object.keys(data || {});
this._captureEvent("feedback", [payloadKeys]);
const response = await this._fetchWithErrorHandling(
`${this.host}/v1/feedback/`,
{
method: "POST",
headers: this.headers,
body: JSON.stringify(data),
},
);
return response;
}
}
export { MemoryClient };
+15
View File
@@ -1,4 +1,6 @@
export interface MemoryOptions {
api_version?: API_VERSION | string;
version?: API_VERSION | string;
user_id?: string;
agent_id?: string;
app_id?: string;
@@ -17,6 +19,7 @@ export interface MemoryOptions {
enable_graph?: boolean;
start_date?: string;
end_date?: string;
custom_categories?: custom_categories[];
}
export interface ProjectOptions {
@@ -28,6 +31,12 @@ export enum API_VERSION {
V2 = "v2",
}
export enum Feedback {
POSITIVE = "POSITIVE",
NEGATIVE = "NEGATIVE",
VERY_NEGATIVE = "VERY_NEGATIVE",
}
export interface MultiModalMessages {
type: "image_url";
image_url: {
@@ -161,3 +170,9 @@ export interface WebhookPayload {
name: string;
url: string;
}
export interface FeedbackPayload {
memory_id: string;
feedback?: Feedback | null;
feedback_reason?: string | null;
}
-85
View File
@@ -1,85 +0,0 @@
// @ts-nocheck
import type { PostHog } from "posthog-js";
import type { TelemetryClient } from "./telemetry.types";
let version = "1.0.20";
const MEM0_TELEMETRY = process.env.MEM0_TELEMETRY !== "false";
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
const POSTHOG_HOST = "https://us.i.posthog.com";
// Browser-specific hash function using Web Crypto API
async function generateHash(input: string): Promise<string> {
const msgBuffer = new TextEncoder().encode(input);
const hashBuffer = await window.crypto.subtle.digest("SHA-256", msgBuffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
return hashArray.map((b) => b.toString(16).padStart(2, "0")).join("");
}
class BrowserTelemetry implements TelemetryClient {
client: PostHog | null = null;
constructor(projectApiKey: string, host: string) {
if (MEM0_TELEMETRY) {
this.initializeClient(projectApiKey, host);
}
}
private async initializeClient(projectApiKey: string, host: string) {
try {
const posthog = await import("posthog-js").catch(() => null);
if (posthog) {
posthog.init(projectApiKey, { api_host: host });
this.client = posthog;
}
} catch (error) {
// Silently fail if posthog-js is not available
this.client = null;
}
}
async captureEvent(distinctId: string, eventName: string, properties = {}) {
if (!this.client || !MEM0_TELEMETRY) return;
const eventProperties = {
client_source: "browser",
client_version: getVersion(),
browser: window.navigator.userAgent,
...properties,
};
try {
this.client.capture(eventName, eventProperties);
} catch (error) {
// Silently fail if telemetry fails
}
}
async shutdown() {
// No shutdown needed for browser client
}
}
function getVersion() {
return version;
}
const telemetry = new BrowserTelemetry(POSTHOG_API_KEY, POSTHOG_HOST);
async function captureClientEvent(
eventName: string,
instance: any,
additionalData = {},
) {
const eventData = {
function: `${instance.constructor.name}`,
...additionalData,
};
await telemetry.captureEvent(
instance.telemetryId,
`client.${eventName}`,
eventData,
);
}
export { telemetry, captureClientEvent, generateHash };
-107
View File
@@ -1,107 +0,0 @@
// @ts-nocheck
import type { TelemetryClient } from "./telemetry.types";
let version = "1.0.20";
const MEM0_TELEMETRY = process.env.MEM0_TELEMETRY !== "false";
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
const POSTHOG_HOST = "https://us.i.posthog.com";
// Node-specific hash function using crypto module
function generateHash(input: string): string {
const crypto = require("crypto");
return crypto.createHash("sha256").update(input).digest("hex");
}
class NodeTelemetry implements TelemetryClient {
client: any = null;
constructor(projectApiKey: string, host: string) {
if (MEM0_TELEMETRY) {
this.initializeClient(projectApiKey, host);
}
}
private async initializeClient(projectApiKey: string, host: string) {
try {
const { PostHog } = await import("posthog-node").catch(() => ({
PostHog: null,
}));
if (PostHog) {
this.client = new PostHog(projectApiKey, { host, flushAt: 1 });
}
} catch (error) {
// Silently fail if posthog-node is not available
this.client = null;
}
}
async captureEvent(distinctId: string, eventName: string, properties = {}) {
if (!this.client || !MEM0_TELEMETRY) return;
const eventProperties = {
client_source: "nodejs",
client_version: getVersion(),
...this.getEnvironmentInfo(),
...properties,
};
try {
this.client.capture({
distinctId,
event: eventName,
properties: eventProperties,
});
} catch (error) {
// Silently fail if telemetry fails
}
}
private getEnvironmentInfo() {
try {
const os = require("os");
return {
node_version: process.version,
os: process.platform,
os_version: os.release(),
os_arch: os.arch(),
};
} catch (error) {
return {};
}
}
async shutdown() {
if (this.client) {
try {
return this.client.shutdown();
} catch (error) {
// Silently fail shutdown
}
}
}
}
function getVersion() {
return version;
}
const telemetry = new NodeTelemetry(POSTHOG_API_KEY, POSTHOG_HOST);
async function captureClientEvent(
eventName: string,
instance: any,
additionalData = {},
) {
const eventData = {
function: `${instance.constructor.name}`,
...additionalData,
};
await telemetry.captureEvent(
instance.telemetryId,
`client.${eventName}`,
eventData,
);
}
export { telemetry, captureClientEvent, generateHash };
+99 -2
View File
@@ -1,3 +1,100 @@
// @ts-nocheck
// Re-export browser telemetry by default
export * from "./telemetry.browser";
import type { TelemetryClient, TelemetryOptions } from "./telemetry.types";
let version = "2.1.12";
// Safely check for process.env in different environments
let MEM0_TELEMETRY = true;
try {
MEM0_TELEMETRY = process?.env?.MEM0_TELEMETRY === "false" ? false : true;
} catch (error) {}
const POSTHOG_API_KEY = "phc_hgJkUVJFYtmaJqrvf6CYN67TIQ8yhXAkWzUn9AMU4yX";
const POSTHOG_HOST = "https://us.i.posthog.com/i/v0/e/";
// Simple hash function using random strings
function generateHash(input: string): string {
const randomStr =
Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
return randomStr;
}
class UnifiedTelemetry implements TelemetryClient {
private apiKey: string;
private host: string;
constructor(projectApiKey: string, host: string) {
this.apiKey = projectApiKey;
this.host = host;
}
async captureEvent(distinctId: string, eventName: string, properties = {}) {
if (!MEM0_TELEMETRY) return;
const eventProperties = {
client_version: version,
timestamp: new Date().toISOString(),
...properties,
$process_person_profile: false,
$lib: "posthog-node",
};
const payload = {
api_key: this.apiKey,
distinct_id: distinctId,
event: eventName,
properties: eventProperties,
};
try {
const response = await fetch(this.host, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
});
if (!response.ok) {
console.error("Telemetry event capture failed:", await response.text());
}
} catch (error) {
console.error("Telemetry event capture failed:", error);
}
}
async shutdown() {
// No shutdown needed for direct API calls
}
}
const telemetry = new UnifiedTelemetry(POSTHOG_API_KEY, POSTHOG_HOST);
async function captureClientEvent(
eventName: string,
instance: any,
additionalData = {},
) {
if (!instance.telemetryId) {
console.warn("No telemetry ID found for instance");
return;
}
const eventData = {
function: `${instance.constructor.name}`,
method: eventName,
api_host: instance.host,
timestamp: new Date().toISOString(),
client_version: version,
keys: additionalData?.keys || [],
...additionalData,
};
await telemetry.captureEvent(
instance.telemetryId,
`client.${eventName}`,
eventData,
);
}
export { telemetry, captureClientEvent, generateHash };
+19
View File
@@ -12,4 +12,23 @@ export interface TelemetryInstance {
constructor: {
name: string;
};
host?: string;
apiKey?: string;
}
export interface TelemetryEventData {
function: string;
method: string;
api_host?: string;
timestamp?: string;
client_source: "browser" | "nodejs";
client_version: string;
[key: string]: any;
}
export interface TelemetryOptions {
enabled?: boolean;
apiKey?: string;
host?: string;
version?: string;
}

Some files were not shown because too many files have changed in this diff Show More