feat(integrations): add n8n community node for Mem0
Programmatic n8n node (n8n-nodes-mem0) with Add/Search/Get Many/Get/
Update/Delete memory operations against the Mem0 v3 API, plus API-key
credentials and usableAsTool support for the AI Agent node.
Add uses POST /v3/memories/add/ and polls GET /v1/event/{id}/ until the
async extraction resolves. No runtime dependencies (n8n verification
requirement); calls the REST API directly. MIT licensed per-package.
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
module.exports = {
|
||||
root: true,
|
||||
env: { browser: true, es6: true, node: true },
|
||||
parser: '@typescript-eslint/parser',
|
||||
parserOptions: { sourceType: 'module', extraFileExtensions: ['.json'] },
|
||||
ignorePatterns: ['.eslintrc.js', '**/*.js', '**/node_modules/**', '**/dist/**'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['package.json'],
|
||||
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||
extends: ['plugin:n8n-nodes-base/community'],
|
||||
rules: { 'n8n-nodes-base/community-package-json-name-still-default': 'off' },
|
||||
},
|
||||
{
|
||||
files: ['./credentials/**/*.ts'],
|
||||
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||
extends: ['plugin:n8n-nodes-base/credentials'],
|
||||
},
|
||||
{
|
||||
files: ['./nodes/**/*.ts'],
|
||||
plugins: ['eslint-plugin-n8n-nodes-base'],
|
||||
extends: ['plugin:n8n-nodes-base/nodes'],
|
||||
},
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
node_modules/
|
||||
dist/
|
||||
*.tsbuildinfo
|
||||
.env
|
||||
coverage/
|
||||
*.log
|
||||
.DS_Store
|
||||
@@ -0,0 +1,9 @@
|
||||
module.exports = {
|
||||
semi: true,
|
||||
trailingComma: 'all',
|
||||
bracketSpacing: true,
|
||||
useTabs: true,
|
||||
tabWidth: 2,
|
||||
printWidth: 100,
|
||||
singleQuote: true,
|
||||
};
|
||||
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 Mem0
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
@@ -0,0 +1,54 @@
|
||||
# n8n-nodes-mem0
|
||||
|
||||
This is an n8n community node that lets you use [Mem0](https://mem0.ai) — the memory layer for AI agents — in your n8n workflows.
|
||||
|
||||
Mem0 gives your agents long-term memory: add memories from conversations, then search and recall them across sessions.
|
||||
|
||||
[n8n](https://n8n.io) is a [fair-code licensed](https://docs.n8n.io/reference/license/) workflow automation platform.
|
||||
|
||||
[Installation](#installation) · [Operations](#operations) · [Credentials](#credentials) · [Usage](#usage) · [Resources](#resources)
|
||||
|
||||
## Installation
|
||||
|
||||
Follow the [community nodes installation guide](https://docs.n8n.io/integrations/community-nodes/installation/) and install `n8n-nodes-mem0`.
|
||||
|
||||
## Operations
|
||||
|
||||
The **Memory** resource supports:
|
||||
|
||||
| Operation | Description | Endpoint |
|
||||
| --- | --- | --- |
|
||||
| **Add** | Extract and store memories from messages | `POST /v3/memories/add/` |
|
||||
| **Search** | Semantic search over stored memories | `POST /v3/memories/search/` |
|
||||
| **Get Many** | List memories for a user (paginated) | `POST /v3/memories/` |
|
||||
| **Get** | Retrieve a single memory by ID | `GET /v1/memories/{id}/` |
|
||||
| **Update** | Update a memory's text or metadata | `PUT /v1/memories/{id}/` |
|
||||
| **Delete** | Delete a single memory by ID | `DELETE /v1/memories/{id}/` |
|
||||
|
||||
### Add & asynchronous extraction
|
||||
|
||||
By default, **Add** runs LLM-based extraction asynchronously — the API returns an event ID and the node polls until extraction finishes, then returns the resulting memories. Disable **Wait for Completion** to return immediately with the event ID, or set **Infer = false** (under Additional Fields) to store messages verbatim and return synchronously.
|
||||
|
||||
## Credentials
|
||||
|
||||
You need a Mem0 API key. Create one at [app.mem0.ai](https://app.mem0.ai) → Settings → API Keys. The key is sent as `Authorization: Token <key>`.
|
||||
|
||||
## Usage
|
||||
|
||||
This node is also **usable as a tool** by n8n's AI Agent node — attach it so an agent can "remember" and "recall" autonomously.
|
||||
|
||||
A typical loop:
|
||||
|
||||
1. **Search** memory before answering, filtered by `User ID`.
|
||||
2. **Add** durable facts after a meaningful exchange.
|
||||
|
||||
Memory writes are asynchronous by default; allow a moment after an Add before searching for the same content.
|
||||
|
||||
## Resources
|
||||
|
||||
- [Mem0 documentation](https://docs.mem0.ai)
|
||||
- [n8n community nodes documentation](https://docs.n8n.io/integrations/community-nodes/)
|
||||
|
||||
## License
|
||||
|
||||
[MIT](./LICENSE)
|
||||
@@ -0,0 +1,53 @@
|
||||
import {
|
||||
IAuthenticateGeneric,
|
||||
ICredentialTestRequest,
|
||||
ICredentialType,
|
||||
INodeProperties,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
export class Mem0Api implements ICredentialType {
|
||||
name = 'mem0Api';
|
||||
|
||||
displayName = 'Mem0 API';
|
||||
|
||||
documentationUrl = 'https://docs.mem0.ai/platform/quickstart';
|
||||
|
||||
properties: INodeProperties[] = [
|
||||
{
|
||||
displayName: 'API Key',
|
||||
name: 'apiKey',
|
||||
type: 'string',
|
||||
typeOptions: { password: true },
|
||||
default: '',
|
||||
required: true,
|
||||
description: 'Your Mem0 API key (starts with "m0-"). Create one at app.mem0.ai → Settings → API Keys.',
|
||||
},
|
||||
{
|
||||
displayName: 'Base URL',
|
||||
name: 'baseUrl',
|
||||
type: 'string',
|
||||
default: 'https://api.mem0.ai',
|
||||
description: 'Mem0 API base URL. Override only for self-hosted or non-default deployments.',
|
||||
},
|
||||
];
|
||||
|
||||
// Injects "Authorization: Token <apiKey>" on every request, matching the
|
||||
// scheme used by Mem0's official SDKs (Authorization: Token m0-...).
|
||||
authenticate: IAuthenticateGeneric = {
|
||||
type: 'generic',
|
||||
properties: {
|
||||
headers: {
|
||||
Authorization: '=Token {{$credentials.apiKey}}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Cheap authenticated GET; validates the key when the user clicks "Test".
|
||||
test: ICredentialTestRequest = {
|
||||
request: {
|
||||
baseURL: '={{$credentials.baseUrl}}',
|
||||
url: '/v1/ping/',
|
||||
method: 'GET',
|
||||
},
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
const path = require('path');
|
||||
const { task, src, dest } = require('gulp');
|
||||
|
||||
task('build:icons', copyIcons);
|
||||
|
||||
function copyIcons() {
|
||||
const nodeSource = path.resolve('nodes', '**', '*.{png,svg}');
|
||||
const nodeDestination = path.resolve('dist', 'nodes');
|
||||
src(nodeSource).pipe(dest(nodeDestination));
|
||||
|
||||
const credSource = path.resolve('credentials', '**', '*.{png,svg}');
|
||||
const credDestination = path.resolve('dist', 'credentials');
|
||||
return src(credSource, { allowEmpty: true }).pipe(dest(credDestination));
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// n8n loads nodes and credentials via the "n8n" key in package.json.
|
||||
// This entry point is intentionally empty.
|
||||
module.exports = {};
|
||||
@@ -0,0 +1,404 @@
|
||||
import {
|
||||
IExecuteFunctions,
|
||||
IDataObject,
|
||||
IHttpRequestMethods,
|
||||
IHttpRequestOptions,
|
||||
INodeExecutionData,
|
||||
INodeType,
|
||||
INodeTypeDescription,
|
||||
JsonObject,
|
||||
NodeApiError,
|
||||
NodeConnectionTypes,
|
||||
NodeOperationError,
|
||||
sleep,
|
||||
} from 'n8n-workflow';
|
||||
|
||||
// Poll settings for asynchronous (infer=true) memory addition.
|
||||
const POLL_INTERVAL_MS = 1500;
|
||||
const MAX_POLL_ATTEMPTS = 40; // ~60s ceiling
|
||||
|
||||
export class Mem0 implements INodeType {
|
||||
description: INodeTypeDescription = {
|
||||
displayName: 'Mem0',
|
||||
name: 'mem0',
|
||||
icon: 'file:mem0.svg',
|
||||
group: ['transform'],
|
||||
version: 1,
|
||||
subtitle: '={{$parameter["operation"] + ": " + $parameter["resource"]}}',
|
||||
description: 'Add, search, and manage long-term memories with Mem0',
|
||||
defaults: {
|
||||
name: 'Mem0',
|
||||
},
|
||||
// Makes the node available to the AI Agent (Tools Agent) node.
|
||||
usableAsTool: true,
|
||||
inputs: [NodeConnectionTypes.Main],
|
||||
outputs: [NodeConnectionTypes.Main],
|
||||
credentials: [
|
||||
{
|
||||
name: 'mem0Api',
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
displayName: 'Resource',
|
||||
name: 'resource',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
options: [{ name: 'Memory', value: 'memory' }],
|
||||
default: 'memory',
|
||||
},
|
||||
{
|
||||
displayName: 'Operation',
|
||||
name: 'operation',
|
||||
type: 'options',
|
||||
noDataExpression: true,
|
||||
displayOptions: { show: { resource: ['memory'] } },
|
||||
options: [
|
||||
{
|
||||
name: 'Add',
|
||||
value: 'add',
|
||||
action: 'Add a memory',
|
||||
description: 'Extract and store memories from messages',
|
||||
},
|
||||
{
|
||||
name: 'Search',
|
||||
value: 'search',
|
||||
action: 'Search memories',
|
||||
description: 'Semantic search over stored memories',
|
||||
},
|
||||
{
|
||||
name: 'Get Many',
|
||||
value: 'getAll',
|
||||
action: 'Get many memories',
|
||||
description: 'List stored memories for an entity',
|
||||
},
|
||||
{
|
||||
name: 'Get',
|
||||
value: 'get',
|
||||
action: 'Get a memory',
|
||||
description: 'Retrieve a single memory by ID',
|
||||
},
|
||||
{
|
||||
name: 'Update',
|
||||
value: 'update',
|
||||
action: 'Update a memory',
|
||||
description: 'Update the text or metadata of a memory',
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
value: 'delete',
|
||||
action: 'Delete a memory',
|
||||
description: 'Delete a single memory by ID',
|
||||
},
|
||||
],
|
||||
default: 'add',
|
||||
},
|
||||
|
||||
// ---- Add ---------------------------------------------------------
|
||||
{
|
||||
displayName: 'Messages',
|
||||
name: 'messages',
|
||||
placeholder: 'Add Message',
|
||||
type: 'fixedCollection',
|
||||
typeOptions: { multipleValues: true },
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['add'] } },
|
||||
default: {},
|
||||
description: 'The conversation messages to extract memories from',
|
||||
options: [
|
||||
{
|
||||
name: 'message',
|
||||
displayName: 'Message',
|
||||
values: [
|
||||
{
|
||||
displayName: 'Role',
|
||||
name: 'role',
|
||||
type: 'options',
|
||||
options: [
|
||||
{ name: 'User', value: 'user' },
|
||||
{ name: 'Assistant', value: 'assistant' },
|
||||
{ name: 'System', value: 'system' },
|
||||
],
|
||||
default: 'user',
|
||||
},
|
||||
{
|
||||
displayName: 'Content',
|
||||
name: 'content',
|
||||
type: 'string',
|
||||
typeOptions: { rows: 2 },
|
||||
default: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
displayName: 'User ID',
|
||||
name: 'userId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['add'] } },
|
||||
description: 'Associate the memories with this user',
|
||||
},
|
||||
{
|
||||
displayName: 'Wait for Completion',
|
||||
name: 'waitForCompletion',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['add'] } },
|
||||
description:
|
||||
'Whether to poll until memory extraction finishes and return the resulting memories. Turn off to return immediately with the event ID.',
|
||||
},
|
||||
{
|
||||
displayName: 'Additional Fields',
|
||||
name: 'addFields',
|
||||
type: 'collection',
|
||||
placeholder: 'Add Field',
|
||||
default: {},
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['add'] } },
|
||||
options: [
|
||||
{
|
||||
displayName: 'Agent ID',
|
||||
name: 'agent_id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Run ID',
|
||||
name: 'run_id',
|
||||
type: 'string',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Metadata (JSON)',
|
||||
name: 'metadata',
|
||||
type: 'json',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
displayName: 'Infer',
|
||||
name: 'infer',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
description:
|
||||
'Whether to run LLM extraction (async). Turn off to store messages verbatim (synchronous).',
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
// ---- Search ------------------------------------------------------
|
||||
{
|
||||
displayName: 'Query',
|
||||
name: 'query',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['search'] } },
|
||||
description: 'What to recall from memory',
|
||||
},
|
||||
{
|
||||
displayName: 'User ID',
|
||||
name: 'userId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['search'] } },
|
||||
description: 'Restrict the search to this user',
|
||||
},
|
||||
{
|
||||
displayName: 'Limit',
|
||||
name: 'limit',
|
||||
type: 'number',
|
||||
typeOptions: { minValue: 1 },
|
||||
default: 10,
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['search'] } },
|
||||
description: 'Max number of results to return',
|
||||
},
|
||||
|
||||
// ---- Get Many ----------------------------------------------------
|
||||
{
|
||||
displayName: 'User ID',
|
||||
name: 'userId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['getAll'] } },
|
||||
description: 'Restrict the listing to this user',
|
||||
},
|
||||
{
|
||||
displayName: 'Page',
|
||||
name: 'page',
|
||||
type: 'number',
|
||||
typeOptions: { minValue: 1 },
|
||||
default: 1,
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['getAll'] } },
|
||||
},
|
||||
{
|
||||
displayName: 'Page Size',
|
||||
name: 'pageSize',
|
||||
type: 'number',
|
||||
typeOptions: { minValue: 1 },
|
||||
default: 50,
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['getAll'] } },
|
||||
},
|
||||
|
||||
// ---- Get / Update / Delete (by ID) -------------------------------
|
||||
{
|
||||
displayName: 'Memory ID',
|
||||
name: 'memoryId',
|
||||
type: 'string',
|
||||
default: '',
|
||||
required: true,
|
||||
displayOptions: {
|
||||
show: { resource: ['memory'], operation: ['get', 'update', 'delete'] },
|
||||
},
|
||||
},
|
||||
{
|
||||
displayName: 'Text',
|
||||
name: 'text',
|
||||
type: 'string',
|
||||
default: '',
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['update'] } },
|
||||
description: 'The new memory text',
|
||||
},
|
||||
{
|
||||
displayName: 'Metadata (JSON)',
|
||||
name: 'metadata',
|
||||
type: 'json',
|
||||
default: '',
|
||||
displayOptions: { show: { resource: ['memory'], operation: ['update'] } },
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
|
||||
const items = this.getInputData();
|
||||
const returnData: INodeExecutionData[] = [];
|
||||
const baseUrl = ((await this.getCredentials('mem0Api')).baseUrl as string) || 'https://api.mem0.ai';
|
||||
|
||||
const request = async (
|
||||
method: IHttpRequestMethods,
|
||||
url: string,
|
||||
body?: IDataObject,
|
||||
qs?: IDataObject,
|
||||
): Promise<IDataObject> => {
|
||||
const options: IHttpRequestOptions = {
|
||||
method,
|
||||
url: `${baseUrl}${url}`,
|
||||
json: true,
|
||||
...(body ? { body } : {}),
|
||||
...(qs ? { qs } : {}),
|
||||
};
|
||||
return (await this.helpers.httpRequestWithAuthentication.call(
|
||||
this,
|
||||
'mem0Api',
|
||||
options,
|
||||
)) as IDataObject;
|
||||
};
|
||||
|
||||
for (let i = 0; i < items.length; i++) {
|
||||
try {
|
||||
const operation = this.getNodeParameter('operation', i) as string;
|
||||
let responseData: IDataObject | IDataObject[] = {};
|
||||
|
||||
if (operation === 'add') {
|
||||
const messagesUi = this.getNodeParameter('messages.message', i, []) as IDataObject[];
|
||||
if (!messagesUi.length) {
|
||||
throw new NodeOperationError(this.getNode(), 'At least one message is required', {
|
||||
itemIndex: i,
|
||||
});
|
||||
}
|
||||
const addFields = this.getNodeParameter('addFields', i, {}) as IDataObject;
|
||||
const body: IDataObject = {
|
||||
messages: messagesUi.map((m) => ({ role: m.role, content: m.content })),
|
||||
infer: addFields.infer !== undefined ? addFields.infer : true,
|
||||
};
|
||||
const userId = this.getNodeParameter('userId', i, '') as string;
|
||||
if (userId) body.user_id = userId;
|
||||
if (addFields.agent_id) body.agent_id = addFields.agent_id;
|
||||
if (addFields.run_id) body.run_id = addFields.run_id;
|
||||
if (addFields.metadata) {
|
||||
body.metadata =
|
||||
typeof addFields.metadata === 'string'
|
||||
? JSON.parse(addFields.metadata as string)
|
||||
: addFields.metadata;
|
||||
}
|
||||
|
||||
const addResp = await request('POST', '/v3/memories/add/', body);
|
||||
const waitForCompletion = this.getNodeParameter('waitForCompletion', i, true) as boolean;
|
||||
|
||||
// infer=true returns {event_id, status:PENDING}; poll until done.
|
||||
if (waitForCompletion && addResp.status === 'PENDING' && addResp.event_id) {
|
||||
responseData = await pollEvent(request, addResp.event_id as string, this);
|
||||
} else {
|
||||
responseData = addResp;
|
||||
}
|
||||
} else if (operation === 'search') {
|
||||
const body: IDataObject = {
|
||||
query: this.getNodeParameter('query', i) as string,
|
||||
output_format: 'v1.1',
|
||||
limit: this.getNodeParameter('limit', i, 10) as number,
|
||||
};
|
||||
const userId = this.getNodeParameter('userId', i, '') as string;
|
||||
if (userId) body.filters = { user_id: userId };
|
||||
const resp = await request('POST', '/v3/memories/search/', body);
|
||||
responseData = (resp.results as IDataObject[]) ?? resp;
|
||||
} else if (operation === 'getAll') {
|
||||
const userId = this.getNodeParameter('userId', i, '') as string;
|
||||
const page = this.getNodeParameter('page', i, 1) as number;
|
||||
const pageSize = this.getNodeParameter('pageSize', i, 50) as number;
|
||||
const body: IDataObject = {};
|
||||
if (userId) body.filters = { user_id: userId };
|
||||
const resp = await request('POST', '/v3/memories/', body, { page, page_size: pageSize });
|
||||
responseData = (resp.results as IDataObject[]) ?? resp;
|
||||
} else if (operation === 'get') {
|
||||
const memoryId = this.getNodeParameter('memoryId', i) as string;
|
||||
responseData = await request('GET', `/v1/memories/${memoryId}/`);
|
||||
} else if (operation === 'update') {
|
||||
const memoryId = this.getNodeParameter('memoryId', i) as string;
|
||||
const body: IDataObject = {};
|
||||
const text = this.getNodeParameter('text', i, '') as string;
|
||||
const metadata = this.getNodeParameter('metadata', i, '') as string;
|
||||
if (text) body.text = text;
|
||||
if (metadata) body.metadata = typeof metadata === 'string' ? JSON.parse(metadata) : metadata;
|
||||
responseData = await request('PUT', `/v1/memories/${memoryId}/`, body);
|
||||
} else if (operation === 'delete') {
|
||||
const memoryId = this.getNodeParameter('memoryId', i) as string;
|
||||
responseData = await request('DELETE', `/v1/memories/${memoryId}/`);
|
||||
}
|
||||
|
||||
const arr = Array.isArray(responseData) ? responseData : [responseData];
|
||||
for (const entry of arr) {
|
||||
returnData.push({ json: entry, pairedItem: { item: i } });
|
||||
}
|
||||
} catch (error) {
|
||||
if (this.continueOnFail()) {
|
||||
returnData.push({ json: { error: (error as Error).message }, pairedItem: { item: i } });
|
||||
continue;
|
||||
}
|
||||
if (error instanceof NodeApiError || error instanceof NodeOperationError) throw error;
|
||||
throw new NodeApiError(this.getNode(), error as JsonObject);
|
||||
}
|
||||
}
|
||||
|
||||
return [returnData];
|
||||
}
|
||||
}
|
||||
|
||||
// Polls GET /v1/event/{id}/ until the memory-addition event resolves.
|
||||
async function pollEvent(
|
||||
request: (m: IHttpRequestMethods, u: string) => Promise<IDataObject>,
|
||||
eventId: string,
|
||||
ctx: IExecuteFunctions,
|
||||
): Promise<IDataObject> {
|
||||
for (let attempt = 0; attempt < MAX_POLL_ATTEMPTS; attempt++) {
|
||||
const event = await request('GET', `/v1/event/${eventId}/`);
|
||||
const status = event.status as string;
|
||||
if (status === 'SUCCEEDED' || status === 'FAILED') {
|
||||
return event;
|
||||
}
|
||||
await sleep(POLL_INTERVAL_MS);
|
||||
}
|
||||
throw new NodeOperationError(
|
||||
ctx.getNode(),
|
||||
`Timed out waiting for memory event ${eventId} to complete`,
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64" fill="none">
|
||||
<rect width="64" height="64" rx="14" fill="#1B1B1F"/>
|
||||
<text x="32" y="41" font-family="Inter, Arial, sans-serif" font-size="24" font-weight="700" fill="#FFFFFF" text-anchor="middle">m0</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 299 B |
+4857
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"name": "n8n-nodes-mem0",
|
||||
"version": "0.1.0",
|
||||
"description": "n8n community node for Mem0 — the memory layer for AI agents. Add, search, get, update, and delete long-term memories.",
|
||||
"keywords": [
|
||||
"n8n-community-node-package",
|
||||
"mem0",
|
||||
"memory",
|
||||
"ai",
|
||||
"agents",
|
||||
"llm"
|
||||
],
|
||||
"license": "MIT",
|
||||
"homepage": "https://mem0.ai",
|
||||
"author": {
|
||||
"name": "Mem0",
|
||||
"email": "founders@mem0.ai"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mem0ai/mem0",
|
||||
"directory": "integrations/n8n-nodes-mem0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.15"
|
||||
},
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "npx rimraf dist && tsc && gulp build:icons",
|
||||
"dev": "tsc --watch",
|
||||
"format": "prettier nodes credentials --write",
|
||||
"lint": "eslint nodes credentials package.json",
|
||||
"lintfix": "eslint nodes credentials package.json --fix",
|
||||
"prepublishOnly": "npm run build && npm run lint"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"n8n": {
|
||||
"n8nNodesApiVersion": 1,
|
||||
"credentials": [
|
||||
"dist/credentials/Mem0Api.credentials.js"
|
||||
],
|
||||
"nodes": [
|
||||
"dist/nodes/Mem0/Mem0.node.js"
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/parser": "^8.0.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-plugin-n8n-nodes-base": "^1.16.3",
|
||||
"gulp": "^5.0.0",
|
||||
"n8n-workflow": "*",
|
||||
"prettier": "^3.3.0",
|
||||
"rimraf": "^5.0.0",
|
||||
"typescript": "^5.5.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"n8n-workflow": "*"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strict": true,
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"target": "es2019",
|
||||
"lib": ["es2019", "es2020", "es2022.error"],
|
||||
"removeComments": true,
|
||||
"useUnknownInCatchVariables": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedLocals": true,
|
||||
"strictNullChecks": true,
|
||||
"preserveConstEnums": true,
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"incremental": true,
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "./dist/"
|
||||
},
|
||||
"include": ["credentials/**/*", "nodes/**/*"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
Reference in New Issue
Block a user