Compare commits

..
5 changed files with 70 additions and 19 deletions
Binary file not shown.

Before

Width:  |  Height:  |  Size: 122 KiB

After

Width:  |  Height:  |  Size: 178 KiB

+8 -6
View File
@@ -4539,7 +4539,7 @@
"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# Get all webhooks\nwebhooks = client.get_webhooks(project_id=\"your_project_id\")\nprint(webhooks)\n\n# Create a webhook\nwebhook = client.create_webhook(\n url=\"https://your-webhook-url.com\",\n name=\"My Webhook\",\n project_id=\"your_project_id\",\n event_types=[\"memory:add\"]\n)\nprint(webhook)"
"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# Get all webhooks\nwebhooks = client.get_webhooks(project_id=\"your_project_id\")\nprint(webhooks)\n\n# Create a webhook\nwebhook = client.create_webhook(\n url=\"https://your-webhook-url.com\",\n name=\"My Webhook\",\n project_id=\"your_project_id\",\n event_types=[\"memory:add\", \"memory:categorize\"]\n)\nprint(webhook)"
},
{
"lang": "JavaScript",
@@ -4606,7 +4606,8 @@
"enum": [
"memory:add",
"memory:update",
"memory:delete"
"memory:delete",
"memory:categorize"
]
},
"description": "List of event types to subscribe to."
@@ -4701,7 +4702,7 @@
"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\n# Create a webhook\nwebhook = client.create_webhook(\n url=\"https://your-webhook-url.com\",\n name=\"My Webhook\",\n project_id=\"your_project_id\",\n event_types=[\"memory:add\"]\n)\nprint(webhook)"
"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\n# Create a webhook\nwebhook = client.create_webhook(\n url=\"https://your-webhook-url.com\",\n name=\"My Webhook\",\n project_id=\"your_project_id\",\n event_types=[\"memory:add\", \"memory:categorize\"]\n)\nprint(webhook)"
},
{
"lang": "JavaScript",
@@ -4767,7 +4768,8 @@
"enum": [
"memory:add",
"memory:update",
"memory:delete"
"memory:delete",
"memory:categorize"
]
},
"description": "New list of event types to subscribe to"
@@ -4845,11 +4847,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\")\n\n# Update a webhook\nwebhook = client.update_webhook(\n webhook_id=\"your_webhook_id\",\n name=\"Updated Webhook\",\n url=\"https://new-webhook-url.com\",\n event_types=[\"memory:add\"]\n)\nprint(webhook)\n\n# Delete a webhook\nresponse = client.delete_webhook(webhook_id=\"your_webhook_id\")\nprint(response)"
"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# Update a webhook\nwebhook = client.update_webhook(\n webhook_id=\"your_webhook_id\",\n name=\"Updated Webhook\",\n url=\"https://new-webhook-url.com\",\n event_types=[\"memory:add\", \"memory:categorize\"]\n)\nprint(webhook)\n\n# Delete a webhook\nresponse = client.delete_webhook(webhook_id=\"your_webhook_id\")\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// Update a webhook\nclient.updateWebhook('your_webhook_id', {\n name: 'Updated Webhook',\n url: 'https://new-webhook-url.com',\n event_types: ['memory:add']\n})\n .then(webhook => console.log(webhook))\n .catch(err => console.error(err));\n\n// Delete a webhook\nclient.deleteWebhook('your_webhook_id')\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 webhook\nclient.updateWebhook('your_webhook_id', {\n name: 'Updated Webhook',\n url: 'https://new-webhook-url.com',\n event_types: ['memory:add', 'memory:categorize']\n})\n .then(webhook => console.log(webhook))\n .catch(err => console.error(err));\n\n// Delete a webhook\nclient.deleteWebhook('your_webhook_id')\n .then(response => console.log(response))\n .catch(err => console.error(err));"
},
{
"lang": "cURL",
+16 -3
View File
@@ -5,7 +5,7 @@ description: 'Configure and manage webhooks to receive real-time notifications a
## Overview
Webhooks enable real-time notifications for memory events in your Mem0 project. Webhooks are configured at the project level, meaning each webhook is tied to a specific project and receives events solely from that project. You can configure webhooks to send HTTP POST requests to your specified URLs whenever memories are created, updated, or deleted.
Webhooks enable real-time notifications for memory events in your Mem0 project. Webhooks are configured at the project level, meaning each webhook is tied to a specific project and receives events solely from that project. You can configure webhooks to send HTTP POST requests to your specified URLs whenever memories are created, updated, deleted, or categorized.
## Managing Webhooks
@@ -27,7 +27,7 @@ webhook = client.create_webhook(
url="https://your-app.com/webhook",
name="Memory Logger",
project_id="proj_123",
event_types=["memory_add"]
event_types=["memory_add", "memory_categorize"]
)
print(webhook)
```
@@ -41,7 +41,7 @@ const webhook = await client.createWebhook({
url: "https://your-app.com/webhook",
name: "Memory Logger",
projectId: "proj_123",
eventTypes: ["memory_add"]
eventTypes: ["memory_add", "memory_categorize"]
});
console.log(webhook);
```
@@ -167,11 +167,13 @@ Mem0 supports the following event types for webhooks:
- `memory_add`: Triggered when a memory is added.
- `memory_update`: Triggered when an existing memory is updated.
- `memory_delete`: Triggered when a memory is deleted.
- `memory_categorize`: Triggered when a memory is categorized.
## Webhook Payload
When a memory event occurs, Mem0 sends an HTTP POST request to your webhook URL with the following payload:
**Memory add/update/delete payload:**
```json
{
"event_details": {
@@ -184,6 +186,17 @@ When a memory event occurs, Mem0 sends an HTTP POST request to your webhook URL
}
```
**Memory categorize payload:**
```json
{
"event_details": {
"event": "CATEGORIZE",
"memory_id": "a1b2c3d4-e5f6-4g7h-8i9j-k0l1m2n3o4p5",
"categories": ["hobbies", "travel"]
}
}
```
## Best Practices
1. **Implement Retry Logic**: Ensure your webhook endpoint can handle temporary failures.
+45 -9
View File
@@ -56,6 +56,7 @@ interface AddOptions {
custom_categories?: Array<Record<string, string>>;
enable_graph?: boolean;
output_format?: string;
source?: string;
}
interface SearchOptions {
@@ -66,12 +67,14 @@ interface SearchOptions {
limit?: number;
keyword_search?: boolean;
reranking?: boolean;
source?: string;
}
interface ListOptions {
user_id: string;
run_id?: string;
page_size?: number;
source?: string;
}
interface MemoryItem {
@@ -152,6 +155,7 @@ class PlatformProvider implements Mem0Provider {
opts.custom_categories = options.custom_categories;
if (options.enable_graph) opts.enable_graph = options.enable_graph;
if (options.output_format) opts.output_format = options.output_format;
if (options.source) opts.source = options.source;
const result = await this.client.add(messages, opts);
return normalizeAddResult(result);
@@ -165,6 +169,7 @@ class PlatformProvider implements Mem0Provider {
if (options.threshold != null) opts.threshold = options.threshold;
if (options.keyword_search != null) opts.keyword_search = options.keyword_search;
if (options.reranking != null) opts.reranking = options.reranking;
if (options.source) opts.source = options.source;
const results = await this.client.search(query, opts);
return normalizeSearchResults(results);
@@ -181,6 +186,7 @@ class PlatformProvider implements Mem0Provider {
const opts: Record<string, unknown> = { user_id: options.user_id };
if (options.run_id) opts.run_id = options.run_id;
if (options.page_size != null) opts.page_size = options.page_size;
if (options.source) opts.source = options.source;
const results = await this.client.getAll(opts);
if (Array.isArray(results)) return results.map(normalizeMemoryItem);
@@ -247,6 +253,7 @@ class OSSProvider implements Mem0Provider {
// OSS SDK uses camelCase: userId/runId, not user_id/run_id
const addOpts: Record<string, unknown> = { userId: options.user_id };
if (options.run_id) addOpts.runId = options.run_id;
if (options.source) addOpts.source = options.source;
const result = await this.memory.add(messages, addOpts);
return normalizeAddResult(result);
}
@@ -260,6 +267,7 @@ class OSSProvider implements Mem0Provider {
else if (options.top_k != null) opts.limit = options.top_k;
if (options.keyword_search != null) opts.keyword_search = options.keyword_search;
if (options.reranking != null) opts.reranking = options.reranking;
if (options.source) opts.source = options.source;
const results = await this.memory.search(query, opts);
return normalizeSearchResults(results);
@@ -276,6 +284,7 @@ class OSSProvider implements Mem0Provider {
// OSS SDK uses camelCase: userId/runId, not user_id/run_id
const getAllOpts: Record<string, unknown> = { userId: options.user_id };
if (options.run_id) getAllOpts.runId = options.run_id;
if (options.source) getAllOpts.source = options.source;
const results = await this.memory.getAll(getAllOpts);
if (Array.isArray(results)) return results.map(normalizeMemoryItem);
if (results?.results && Array.isArray(results.results))
@@ -607,6 +616,22 @@ const memoryPlugin = {
// Track current session ID for tool-level session scoping
let currentSessionId: string | undefined;
// Track current agent ID for per-agent memory isolation
let currentAgentId: string | undefined;
// Helper: extract agentId from session key (pattern: agent:<agentId>:...)
// Returns undefined for the "main" agent to preserve default behavior.
function extractAgentId(sessionKey: string): string | undefined {
const match = sessionKey.match(/^agent:([^:]+):/);
return match && match[1] !== "main" ? match[1] : undefined;
}
// Helper: get effective userId for Mem0 operations.
// Precedence: explicit override > current agentId (non-main) > configured userId.
function effectiveUserId(userIdOverride?: string): string {
return userIdOverride || currentAgentId || cfg.userId;
}
api.logger.info(
`openclaw-mem0: registered (mode: ${cfg.mode}, user: ${cfg.userId}, graph: ${cfg.enableGraph}, autoRecall: ${cfg.autoRecall}, autoCapture: ${cfg.autoCapture})`,
);
@@ -614,7 +639,8 @@ const memoryPlugin = {
// Helper: build add options
function buildAddOptions(userIdOverride?: string, runId?: string): AddOptions {
const opts: AddOptions = {
user_id: userIdOverride || cfg.userId,
user_id: effectiveUserId(userIdOverride),
source: "OPENCLAW",
};
if (runId) opts.run_id = runId;
if (cfg.mode === "platform") {
@@ -633,12 +659,13 @@ const memoryPlugin = {
runId?: string,
): SearchOptions {
const opts: SearchOptions = {
user_id: userIdOverride || cfg.userId,
user_id: effectiveUserId(userIdOverride),
top_k: limit ?? cfg.topK,
limit: limit ?? cfg.topK,
threshold: cfg.searchThreshold,
keyword_search: true,
reranking: true,
source: "OPENCLAW",
};
if (runId) opts.run_id = runId;
return opts;
@@ -924,25 +951,27 @@ const memoryPlugin = {
try {
let memories: MemoryItem[] = [];
const uid = userId || cfg.userId;
const uid = effectiveUserId(userId);
if (scope === "session") {
if (currentSessionId) {
memories = await provider.getAll({
user_id: uid,
run_id: currentSessionId,
source: "OPENCLAW",
});
}
} else if (scope === "long-term") {
memories = await provider.getAll({ user_id: uid });
memories = await provider.getAll({ user_id: uid, source: "OPENCLAW" });
} else {
// "all" — combine both scopes
const longTerm = await provider.getAll({ user_id: uid });
const longTerm = await provider.getAll({ user_id: uid, source: "OPENCLAW" });
let session: MemoryItem[] = [];
if (currentSessionId) {
session = await provider.getAll({
user_id: uid,
run_id: currentSessionId,
source: "OPENCLAW",
});
}
const seen = new Set(longTerm.map((r) => r.id));
@@ -1195,6 +1224,7 @@ const memoryPlugin = {
try {
const memories = await provider.getAll({
user_id: cfg.userId,
source: "OPENCLAW",
});
console.log(`Mode: ${cfg.mode}`);
console.log(`User: ${cfg.userId}`);
@@ -1222,9 +1252,12 @@ const memoryPlugin = {
api.on("before_agent_start", async (event, ctx) => {
if (!event.prompt || event.prompt.length < 5) return;
// Track session ID
// Track session ID and agent ID
const sessionId = (ctx as any)?.sessionKey ?? undefined;
if (sessionId) currentSessionId = sessionId;
if (sessionId) {
currentSessionId = sessionId;
currentAgentId = extractAgentId(sessionId);
}
try {
// Search long-term memories (user-scoped)
@@ -1289,9 +1322,12 @@ const memoryPlugin = {
return;
}
// Track session ID
// Track session ID and agent ID
const sessionId = (ctx as any)?.sessionKey ?? undefined;
if (sessionId) currentSessionId = sessionId;
if (sessionId) {
currentSessionId = sessionId;
currentAgentId = extractAgentId(sessionId);
}
try {
// Extract messages, limiting to last 10
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@mem0/openclaw-mem0",
"version": "0.1.0",
"version": "0.1.2",
"type": "module",
"description": "Mem0 memory backend for OpenClaw — platform or self-hosted open-source",
"license": "Apache-2.0",