Add Infer Property (#2452)

This commit is contained in:
Saket Aryan
2025-03-27 21:18:42 +05:30
committed by GitHub
parent 0eb53b9f27
commit bc4ab3db77
10 changed files with 202 additions and 349 deletions

View File

@@ -1,6 +1,6 @@
{ {
"name": "mem0ai", "name": "mem0ai",
"version": "2.1.11", "version": "2.1.12",
"description": "The Memory Layer For Your AI Apps", "description": "The Memory Layer For Your AI Apps",
"main": "./dist/index.js", "main": "./dist/index.js",
"module": "./dist/index.mjs", "module": "./dist/index.mjs",
@@ -92,7 +92,6 @@
}, },
"dependencies": { "dependencies": {
"axios": "1.7.7", "axios": "1.7.7",
"neo4j-driver": "^5.28.1",
"openai": "4.28.0", "openai": "4.28.0",
"uuid": "9.0.1", "uuid": "9.0.1",
"zod": "3.22.4" "zod": "3.22.4"
@@ -105,22 +104,12 @@
"@types/pg": "8.11.0", "@types/pg": "8.11.0",
"@types/sqlite3": "3.1.11", "@types/sqlite3": "3.1.11",
"groq-sdk": "0.3.0", "groq-sdk": "0.3.0",
"neo4j-driver": "^5.28.1",
"ollama": "^0.5.14", "ollama": "^0.5.14",
"pg": "8.11.3", "pg": "8.11.3",
"redis": "4.7.0", "redis": "4.7.0",
"sqlite3": "5.1.7" "sqlite3": "5.1.7"
}, },
"peerDependenciesMeta": {
"posthog-node": {
"optional": true
},
"posthog-js": {
"optional": true
}
},
"optionalDependencies": {
"posthog-js": "^1.116.6"
},
"engines": { "engines": {
"node": ">=18" "node": ">=18"
}, },

79
mem0-ts/pnpm-lock.yaml generated
View File

@@ -92,10 +92,6 @@ importers:
typescript: typescript:
specifier: 5.5.4 specifier: 5.5.4
version: 5.5.4 version: 5.5.4
optionalDependencies:
posthog-js:
specifier: ^1.116.6
version: 1.224.1(@rrweb/types@2.0.0-alpha.17)
packages: packages:
"@ampproject/remapping@2.3.0": "@ampproject/remapping@2.3.0":
@@ -1052,12 +1048,6 @@ packages:
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
"@rrweb/types@2.0.0-alpha.17":
resolution:
{
integrity: sha512-AfDTVUuCyCaIG0lTSqYtrZqJX39ZEYzs4fYKnexhQ+id+kbZIpIJtaut5cto6dWZbB3SEe4fW0o90Po3LvTmfg==,
}
"@sevinf/maybe@0.5.0": "@sevinf/maybe@0.5.0":
resolution: resolution:
{ {
@@ -1788,12 +1778,6 @@ packages:
integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==,
} }
core-js@3.40.0:
resolution:
{
integrity: sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==,
}
create-jest@29.7.0: create-jest@29.7.0:
resolution: resolution:
{ {
@@ -2125,12 +2109,6 @@ packages:
picomatch: picomatch:
optional: true optional: true
fflate@0.4.8:
resolution:
{
integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==,
}
file-uri-to-path@1.0.0: file-uri-to-path@1.0.0:
resolution: resolution:
{ {
@@ -3663,20 +3641,6 @@ packages:
integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==, integrity: sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w==,
} }
posthog-js@1.224.1:
resolution:
{
integrity: sha512-C/0adjCiqvJ9JlGdlBT7HyxqBbMB8wFwb7/DKULyXfT4GJX/8ETaqXaJuSL3HLcuUJjxYPqDinBC6mt8QoVYnA==,
}
peerDependencies:
"@rrweb/types": 2.0.0-alpha.17
preact@10.26.3:
resolution:
{
integrity: sha512-OJCfNTdttkOTCbTN+gCnXn/woDqz1dIjvP+gdCoYGP2kKuX6w79FAP8qgY/r7jgAunvqHVVmEOKzKOFWzrXZdw==,
}
prebuild-install@7.1.3: prebuild-install@7.1.3:
resolution: resolution:
{ {
@@ -3882,12 +3846,6 @@ packages:
engines: { node: ">=18.0.0", npm: ">=8.0.0" } engines: { node: ">=18.0.0", npm: ">=8.0.0" }
hasBin: true hasBin: true
rrweb-snapshot@2.0.0-alpha.18:
resolution:
{
integrity: sha512-hBHZL/NfgQX6wO1D9mpwqFu1NJPpim+moIcKhFEjVTZVRUfCln+LOugRc4teVTCISYHN8Cw5e2iNTWCSm+SkoA==,
}
run-parallel@1.2.0: run-parallel@1.2.0:
resolution: resolution:
{ {
@@ -4518,12 +4476,6 @@ packages:
} }
engines: { node: ">= 14" } engines: { node: ">= 14" }
web-vitals@4.2.4:
resolution:
{
integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==,
}
webidl-conversions@3.0.1: webidl-conversions@3.0.1:
resolution: resolution:
{ {
@@ -5286,11 +5238,6 @@ snapshots:
"@rollup/rollup-win32-x64-msvc@4.37.0": "@rollup/rollup-win32-x64-msvc@4.37.0":
optional: true optional: true
"@rrweb/types@2.0.0-alpha.17":
dependencies:
rrweb-snapshot: 2.0.0-alpha.18
optional: true
"@sevinf/maybe@0.5.0": {} "@sevinf/maybe@0.5.0": {}
"@sinclair/typebox@0.27.8": {} "@sinclair/typebox@0.27.8": {}
@@ -5750,9 +5697,6 @@ snapshots:
convert-source-map@2.0.0: {} convert-source-map@2.0.0: {}
core-js@3.40.0:
optional: true
create-jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.5.4)): create-jest@29.7.0(@types/node@22.13.5)(ts-node@10.9.2(@types/node@22.13.5)(typescript@5.5.4)):
dependencies: dependencies:
"@jest/types": 29.6.3 "@jest/types": 29.6.3
@@ -5950,9 +5894,6 @@ snapshots:
optionalDependencies: optionalDependencies:
picomatch: 4.0.2 picomatch: 4.0.2
fflate@0.4.8:
optional: true
file-uri-to-path@1.0.0: {} file-uri-to-path@1.0.0: {}
filelist@1.0.4: filelist@1.0.4:
@@ -7028,18 +6969,6 @@ snapshots:
postgres-range@1.1.4: {} postgres-range@1.1.4: {}
posthog-js@1.224.1(@rrweb/types@2.0.0-alpha.17):
dependencies:
"@rrweb/types": 2.0.0-alpha.17
core-js: 3.40.0
fflate: 0.4.8
preact: 10.26.3
web-vitals: 4.2.4
optional: true
preact@10.26.3:
optional: true
prebuild-install@7.1.3: prebuild-install@7.1.3:
dependencies: dependencies:
detect-libc: 2.0.3 detect-libc: 2.0.3
@@ -7185,11 +7114,6 @@ snapshots:
"@rollup/rollup-win32-x64-msvc": 4.37.0 "@rollup/rollup-win32-x64-msvc": 4.37.0
fsevents: 2.3.3 fsevents: 2.3.3
rrweb-snapshot@2.0.0-alpha.18:
dependencies:
postcss: 8.5.3
optional: true
run-parallel@1.2.0: run-parallel@1.2.0:
dependencies: dependencies:
queue-microtask: 1.2.3 queue-microtask: 1.2.3
@@ -7566,9 +7490,6 @@ snapshots:
web-streams-polyfill@4.0.0-beta.3: {} web-streams-polyfill@4.0.0-beta.3: {}
web-vitals@4.2.4:
optional: true
webidl-conversions@3.0.1: {} webidl-conversions@3.0.1: {}
webidl-conversions@4.0.2: {} webidl-conversions@4.0.2: {}

View File

@@ -1,10 +1,4 @@
import { MemoryClient } from "./mem0"; 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"; import type * as MemoryTypes from "./mem0.types";
// Re-export all types from mem0.types // Re-export all types from mem0.types
@@ -27,12 +21,6 @@ export type {
Feedback, Feedback,
} from "./mem0.types"; } from "./mem0.types";
// Export telemetry types
export type { TelemetryClient, TelemetryInstance };
// Export telemetry implementation
export { telemetry, captureClientEvent, generateHash };
// Export the main client // Export the main client
export { MemoryClient }; export { MemoryClient };
export default MemoryClient; export default MemoryClient;

View File

@@ -62,7 +62,7 @@ export default class MemoryClient {
(this.organizationName !== null && this.projectName === null) (this.organizationName !== null && this.projectName === null)
) { ) {
console.warn( 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.",
); );
} }
@@ -72,7 +72,7 @@ export default class MemoryClient {
(this.organizationId !== null && this.projectId === null) (this.organizationId !== null && this.projectId === null)
) { ) {
console.warn( 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.",
); );
} }
} }
@@ -108,59 +108,42 @@ export default class MemoryClient {
private async _initializeClient() { private async _initializeClient() {
try { try {
// do this only in browser // Generate telemetry ID
if (typeof window !== "undefined") { this.telemetryId = generateHash(this.apiKey);
this.telemetryId = await generateHash(this.apiKey);
await captureClientEvent("init", this);
}
// Wrap methods after initialization // Capture initialization event
this.add = this.wrapMethod("add", this.add); await captureClientEvent("init", this, {
this.get = this.wrapMethod("get", this.get); api_version: "v1",
this.getAll = this.wrapMethod("get_all", this.getAll); client_type: "MemoryClient",
this.search = this.wrapMethod("search", this.search); });
this.delete = this.wrapMethod("delete", this.delete); } catch (error: any) {
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) {
console.error("Failed to initialize client:", error); 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) { private _captureEvent(methodName: string, args: any[]) {
return async function (...args: any) { captureClientEvent(methodName, this, {
// @ts-ignore success: true,
await captureClientEvent(methodName, this); args_count: args.length,
// @ts-ignore keys: args.length > 0 ? args[0] : [],
return method.apply(this, args); }).catch((error: any) => {
}.bind(this); console.error("Failed to capture event:", error);
});
} }
async _fetchWithErrorHandling(url: string, options: any): Promise<any> { 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) { if (!response.ok) {
const errorData = await response.text(); const errorData = await response.text();
throw new APIError(`API request failed: ${errorData}`); throw new APIError(`API request failed: ${errorData}`);
@@ -211,6 +194,11 @@ export default class MemoryClient {
} }
const payload = this._preparePayload(messages, options); 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( const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/`, `${this.host}/v1/memories/`,
{ {
@@ -227,6 +215,10 @@ export default class MemoryClient {
const payload = { const payload = {
text: message, text: message,
}; };
const payloadKeys = Object.keys(payload);
this._captureEvent("update", [payloadKeys]);
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/`, `${this.host}/v1/memories/${memoryId}/`,
{ {
@@ -239,6 +231,7 @@ export default class MemoryClient {
} }
async get(memoryId: string): Promise<Memory> { async get(memoryId: string): Promise<Memory> {
this._captureEvent("get", []);
return this._fetchWithErrorHandling( return this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/`, `${this.host}/v1/memories/${memoryId}/`,
{ {
@@ -249,6 +242,8 @@ export default class MemoryClient {
async getAll(options?: SearchOptions): Promise<Array<Memory>> { async getAll(options?: SearchOptions): Promise<Array<Memory>> {
this._validateOrgProject(); this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("get_all", [payloadKeys]);
const { api_version, page, page_size, ...otherOptions } = options!; const { api_version, page, page_size, ...otherOptions } = options!;
if (this.organizationName != null && this.projectName != null) { if (this.organizationName != null && this.projectName != null) {
otherOptions.org_name = this.organizationName; otherOptions.org_name = this.organizationName;
@@ -294,6 +289,8 @@ export default class MemoryClient {
async search(query: string, options?: SearchOptions): Promise<Array<Memory>> { async search(query: string, options?: SearchOptions): Promise<Array<Memory>> {
this._validateOrgProject(); this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("search", [payloadKeys]);
const { api_version, ...otherOptions } = options!; const { api_version, ...otherOptions } = options!;
const payload = { query, ...otherOptions }; const payload = { query, ...otherOptions };
if (this.organizationName != null && this.projectName != null) { if (this.organizationName != null && this.projectName != null) {
@@ -322,6 +319,7 @@ export default class MemoryClient {
} }
async delete(memoryId: string): Promise<{ message: string }> { async delete(memoryId: string): Promise<{ message: string }> {
this._captureEvent("delete", []);
return this._fetchWithErrorHandling( return this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/`, `${this.host}/v1/memories/${memoryId}/`,
{ {
@@ -333,6 +331,8 @@ export default class MemoryClient {
async deleteAll(options: MemoryOptions = {}): Promise<{ message: string }> { async deleteAll(options: MemoryOptions = {}): Promise<{ message: string }> {
this._validateOrgProject(); this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("delete_all", [payloadKeys]);
if (this.organizationName != null && this.projectName != null) { if (this.organizationName != null && this.projectName != null) {
options.org_name = this.organizationName; options.org_name = this.organizationName;
options.project_name = this.projectName; options.project_name = this.projectName;
@@ -358,6 +358,7 @@ export default class MemoryClient {
} }
async history(memoryId: string): Promise<Array<MemoryHistory>> { async history(memoryId: string): Promise<Array<MemoryHistory>> {
this._captureEvent("history", []);
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/v1/memories/${memoryId}/history/`, `${this.host}/v1/memories/${memoryId}/history/`,
{ {
@@ -369,6 +370,7 @@ export default class MemoryClient {
async users(): Promise<AllUsers> { async users(): Promise<AllUsers> {
this._validateOrgProject(); this._validateOrgProject();
this._captureEvent("users", []);
const options: MemoryOptions = {}; const options: MemoryOptions = {};
if (this.organizationName != null && this.projectName != null) { if (this.organizationName != null && this.projectName != null) {
options.org_name = this.organizationName; options.org_name = this.organizationName;
@@ -397,6 +399,7 @@ export default class MemoryClient {
entityId: string, entityId: string,
entity: { type: string } = { type: "user" }, entity: { type: string } = { type: "user" },
): Promise<{ message: string }> { ): Promise<{ message: string }> {
this._captureEvent("delete_user", []);
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/v1/entities/${entity.type}/${entityId}/`, `${this.host}/v1/entities/${entity.type}/${entityId}/`,
{ {
@@ -409,6 +412,7 @@ export default class MemoryClient {
async deleteUsers(): Promise<{ message: string }> { async deleteUsers(): Promise<{ message: string }> {
this._validateOrgProject(); this._validateOrgProject();
this._captureEvent("delete_users", []);
const entities = await this.users(); const entities = await this.users();
for (const entity of entities.results) { for (const entity of entities.results) {
@@ -433,6 +437,7 @@ export default class MemoryClient {
} }
async batchUpdate(memories: Array<MemoryUpdateBody>): Promise<string> { async batchUpdate(memories: Array<MemoryUpdateBody>): Promise<string> {
this._captureEvent("batch_update", []);
const memoriesBody = memories.map((memory) => ({ const memoriesBody = memories.map((memory) => ({
memory_id: memory.memoryId, memory_id: memory.memoryId,
text: memory.text, text: memory.text,
@@ -449,6 +454,7 @@ export default class MemoryClient {
} }
async batchDelete(memories: Array<string>): Promise<string> { async batchDelete(memories: Array<string>): Promise<string> {
this._captureEvent("batch_delete", []);
const memoriesBody = memories.map((memory) => ({ const memoriesBody = memories.map((memory) => ({
memory_id: memory, memory_id: memory,
})); }));
@@ -465,7 +471,8 @@ export default class MemoryClient {
async getProject(options: ProjectOptions): Promise<ProjectResponse> { async getProject(options: ProjectOptions): Promise<ProjectResponse> {
this._validateOrgProject(); this._validateOrgProject();
const payloadKeys = Object.keys(options || {});
this._captureEvent("get_project", [payloadKeys]);
const { fields } = options; const { fields } = options;
if (!(this.organizationId && this.projectId)) { if (!(this.organizationId && this.projectId)) {
@@ -490,7 +497,7 @@ export default class MemoryClient {
prompts: PromptUpdatePayload, prompts: PromptUpdatePayload,
): Promise<Record<string, any>> { ): Promise<Record<string, any>> {
this._validateOrgProject(); this._validateOrgProject();
this._captureEvent("update_project", []);
if (!(this.organizationId && this.projectId)) { if (!(this.organizationId && this.projectId)) {
throw new Error( throw new Error(
"organizationId and projectId must be set to update instructions or categories", "organizationId and projectId must be set to update instructions or categories",
@@ -510,6 +517,7 @@ export default class MemoryClient {
// WebHooks // WebHooks
async getWebhooks(data?: { projectId?: string }): Promise<Array<Webhook>> { async getWebhooks(data?: { projectId?: string }): Promise<Array<Webhook>> {
this._captureEvent("get_webhooks", []);
const project_id = data?.projectId || this.projectId; const project_id = data?.projectId || this.projectId;
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/projects/${project_id}/`, `${this.host}/api/v1/webhooks/projects/${project_id}/`,
@@ -521,6 +529,7 @@ export default class MemoryClient {
} }
async createWebhook(webhook: WebhookPayload): Promise<Webhook> { async createWebhook(webhook: WebhookPayload): Promise<Webhook> {
this._captureEvent("create_webhook", []);
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/projects/${this.projectId}/`, `${this.host}/api/v1/webhooks/projects/${this.projectId}/`,
{ {
@@ -533,6 +542,7 @@ export default class MemoryClient {
} }
async updateWebhook(webhook: WebhookPayload): Promise<{ message: string }> { async updateWebhook(webhook: WebhookPayload): Promise<{ message: string }> {
this._captureEvent("update_webhook", []);
const project_id = webhook.projectId || this.projectId; const project_id = webhook.projectId || this.projectId;
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/${webhook.webhookId}/`, `${this.host}/api/v1/webhooks/${webhook.webhookId}/`,
@@ -551,6 +561,7 @@ export default class MemoryClient {
async deleteWebhook(data: { async deleteWebhook(data: {
webhookId: string; webhookId: string;
}): Promise<{ message: string }> { }): Promise<{ message: string }> {
this._captureEvent("delete_webhook", []);
const webhook_id = data.webhookId || data; const webhook_id = data.webhookId || data;
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/api/v1/webhooks/${webhook_id}/`, `${this.host}/api/v1/webhooks/${webhook_id}/`,
@@ -563,6 +574,8 @@ export default class MemoryClient {
} }
async feedback(data: FeedbackPayload): Promise<{ message: string }> { async feedback(data: FeedbackPayload): Promise<{ message: string }> {
const payloadKeys = Object.keys(data || {});
this._captureEvent("feedback", [payloadKeys]);
const response = await this._fetchWithErrorHandling( const response = await this._fetchWithErrorHandling(
`${this.host}/v1/feedback/`, `${this.host}/v1/feedback/`,
{ {

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 = "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 };

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 };

View File

@@ -1,3 +1,97 @@
// @ts-nocheck // @ts-nocheck
// Re-export browser telemetry by default import type { TelemetryClient, TelemetryOptions } from "./telemetry.types";
export * from "./telemetry.browser";
let version = "2.1.12";
// Safely check for process.env in different environments
const MEM0_TELEMETRY = process?.env?.MEM0_TELEMETRY === "false" ? false : true;
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 };

View File

@@ -12,4 +12,23 @@ export interface TelemetryInstance {
constructor: { constructor: {
name: string; 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;
} }

View File

@@ -112,7 +112,7 @@ export class Memory {
runId, runId,
metadata = {}, metadata = {},
filters = {}, filters = {},
prompt, infer = true,
} = config; } = config;
if (userId) filters.userId = metadata.userId = userId; if (userId) filters.userId = metadata.userId = userId;
@@ -136,6 +136,7 @@ export class Memory {
final_parsedMessages, final_parsedMessages,
metadata, metadata,
filters, filters,
infer,
); );
// Add to graph store if available // Add to graph store if available
@@ -161,7 +162,27 @@ export class Memory {
messages: Message[], messages: Message[],
metadata: Record<string, any>, metadata: Record<string, any>,
filters: SearchFilters, filters: SearchFilters,
infer: boolean,
): Promise<MemoryItem[]> { ): Promise<MemoryItem[]> {
if (!infer) {
const returnedMemories: MemoryItem[] = [];
for (const message of messages) {
if (message.content === "system") {
continue;
}
const memoryId = await this.createMemory(
message.content as string,
{},
metadata,
);
returnedMemories.push({
id: memoryId,
memory: message.content as string,
metadata: { event: "ADD" },
});
}
return returnedMemories;
}
const parsedMessages = messages.map((m) => m.content).join("\n"); const parsedMessages = messages.map((m) => m.content).join("\n");
// Get prompts // Get prompts

View File

@@ -10,7 +10,7 @@ export interface Entity {
export interface AddMemoryOptions extends Entity { export interface AddMemoryOptions extends Entity {
metadata?: Record<string, any>; metadata?: Record<string, any>;
filters?: SearchFilters; filters?: SearchFilters;
prompt?: string; infer?: boolean;
} }
export interface SearchMemoryOptions extends Entity { export interface SearchMemoryOptions extends Entity {