diff --git a/mem0-ts/package.json b/mem0-ts/package.json index 47222493..4b47d02c 100644 --- a/mem0-ts/package.json +++ b/mem0-ts/package.json @@ -1,6 +1,6 @@ { "name": "mem0ai", - "version": "2.1.11", + "version": "2.1.12", "description": "The Memory Layer For Your AI Apps", "main": "./dist/index.js", "module": "./dist/index.mjs", @@ -92,7 +92,6 @@ }, "dependencies": { "axios": "1.7.7", - "neo4j-driver": "^5.28.1", "openai": "4.28.0", "uuid": "9.0.1", "zod": "3.22.4" @@ -105,22 +104,12 @@ "@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" }, diff --git a/mem0-ts/pnpm-lock.yaml b/mem0-ts/pnpm-lock.yaml index 1e76294b..9bdb9b48 100644 --- a/mem0-ts/pnpm-lock.yaml +++ b/mem0-ts/pnpm-lock.yaml @@ -92,10 +92,6 @@ importers: typescript: specifier: 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: "@ampproject/remapping@2.3.0": @@ -1052,12 +1048,6 @@ packages: cpu: [x64] os: [win32] - "@rrweb/types@2.0.0-alpha.17": - resolution: - { - integrity: sha512-AfDTVUuCyCaIG0lTSqYtrZqJX39ZEYzs4fYKnexhQ+id+kbZIpIJtaut5cto6dWZbB3SEe4fW0o90Po3LvTmfg==, - } - "@sevinf/maybe@0.5.0": resolution: { @@ -1788,12 +1778,6 @@ packages: integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==, } - core-js@3.40.0: - resolution: - { - integrity: sha512-7vsMc/Lty6AGnn7uFpYT56QesI5D2Y/UkgKounk87OP9Z2H9Z8kj6jzcSGAxFmUtDOS0ntK6lbQz+Nsa0Jj6mQ==, - } - create-jest@29.7.0: resolution: { @@ -2125,12 +2109,6 @@ packages: picomatch: optional: true - fflate@0.4.8: - resolution: - { - integrity: sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA==, - } - file-uri-to-path@1.0.0: resolution: { @@ -3663,20 +3641,6 @@ packages: 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: resolution: { @@ -3882,12 +3846,6 @@ packages: engines: { node: ">=18.0.0", npm: ">=8.0.0" } hasBin: true - rrweb-snapshot@2.0.0-alpha.18: - resolution: - { - integrity: sha512-hBHZL/NfgQX6wO1D9mpwqFu1NJPpim+moIcKhFEjVTZVRUfCln+LOugRc4teVTCISYHN8Cw5e2iNTWCSm+SkoA==, - } - run-parallel@1.2.0: resolution: { @@ -4518,12 +4476,6 @@ packages: } engines: { node: ">= 14" } - web-vitals@4.2.4: - resolution: - { - integrity: sha512-r4DIlprAGwJ7YM11VZp4R884m0Vmgr6EAKe3P+kO0PPj3Unqyvv59rczf6UiGcb9Z8QxZVcqKNwv/g0WNdWwsw==, - } - webidl-conversions@3.0.1: resolution: { @@ -5286,11 +5238,6 @@ snapshots: "@rollup/rollup-win32-x64-msvc@4.37.0": optional: true - "@rrweb/types@2.0.0-alpha.17": - dependencies: - rrweb-snapshot: 2.0.0-alpha.18 - optional: true - "@sevinf/maybe@0.5.0": {} "@sinclair/typebox@0.27.8": {} @@ -5750,9 +5697,6 @@ snapshots: 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)): dependencies: "@jest/types": 29.6.3 @@ -5950,9 +5894,6 @@ snapshots: optionalDependencies: picomatch: 4.0.2 - fflate@0.4.8: - optional: true - file-uri-to-path@1.0.0: {} filelist@1.0.4: @@ -7028,18 +6969,6 @@ snapshots: 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: dependencies: detect-libc: 2.0.3 @@ -7185,11 +7114,6 @@ snapshots: "@rollup/rollup-win32-x64-msvc": 4.37.0 fsevents: 2.3.3 - rrweb-snapshot@2.0.0-alpha.18: - dependencies: - postcss: 8.5.3 - optional: true - run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -7566,9 +7490,6 @@ snapshots: web-streams-polyfill@4.0.0-beta.3: {} - web-vitals@4.2.4: - optional: true - webidl-conversions@3.0.1: {} webidl-conversions@4.0.2: {} diff --git a/mem0-ts/src/client/index.ts b/mem0-ts/src/client/index.ts index 9a7217ee..7b8c3670 100644 --- a/mem0-ts/src/client/index.ts +++ b/mem0-ts/src/client/index.ts @@ -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 @@ -27,12 +21,6 @@ export type { 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; diff --git a/mem0-ts/src/client/mem0.ts b/mem0-ts/src/client/mem0.ts index 8ddabe22..14fc0c7a 100644 --- a/mem0-ts/src/client/mem0.ts +++ b/mem0-ts/src/client/mem0.ts @@ -62,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.", ); } @@ -72,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.", ); } } @@ -108,59 +108,42 @@ 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 + 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) { + // Capture initialization event + await captureClientEvent("init", this, { + api_version: "v1", + client_type: "MemoryClient", + }); + } 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 { - 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}`); @@ -211,6 +194,11 @@ export default class MemoryClient { } 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/`, { @@ -227,6 +215,10 @@ export default class MemoryClient { const payload = { text: message, }; + + const payloadKeys = Object.keys(payload); + this._captureEvent("update", [payloadKeys]); + const response = await this._fetchWithErrorHandling( `${this.host}/v1/memories/${memoryId}/`, { @@ -239,6 +231,7 @@ export default class MemoryClient { } async get(memoryId: string): Promise { + this._captureEvent("get", []); return this._fetchWithErrorHandling( `${this.host}/v1/memories/${memoryId}/`, { @@ -249,6 +242,8 @@ export default class MemoryClient { async getAll(options?: SearchOptions): Promise> { 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; @@ -294,6 +289,8 @@ export default class MemoryClient { async search(query: string, options?: SearchOptions): Promise> { 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) { @@ -322,6 +319,7 @@ export default class MemoryClient { } async delete(memoryId: string): Promise<{ message: string }> { + this._captureEvent("delete", []); return this._fetchWithErrorHandling( `${this.host}/v1/memories/${memoryId}/`, { @@ -333,6 +331,8 @@ export default class MemoryClient { async deleteAll(options: MemoryOptions = {}): Promise<{ message: string }> { 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; @@ -358,6 +358,7 @@ export default class MemoryClient { } async history(memoryId: string): Promise> { + this._captureEvent("history", []); const response = await this._fetchWithErrorHandling( `${this.host}/v1/memories/${memoryId}/history/`, { @@ -369,6 +370,7 @@ export default class MemoryClient { async users(): Promise { this._validateOrgProject(); + this._captureEvent("users", []); const options: MemoryOptions = {}; if (this.organizationName != null && this.projectName != null) { options.org_name = this.organizationName; @@ -397,6 +399,7 @@ export default class MemoryClient { entityId: string, entity: { type: string } = { type: "user" }, ): Promise<{ message: string }> { + this._captureEvent("delete_user", []); const response = await this._fetchWithErrorHandling( `${this.host}/v1/entities/${entity.type}/${entityId}/`, { @@ -409,6 +412,7 @@ export default class MemoryClient { async deleteUsers(): Promise<{ message: string }> { this._validateOrgProject(); + this._captureEvent("delete_users", []); const entities = await this.users(); for (const entity of entities.results) { @@ -433,6 +437,7 @@ export default class MemoryClient { } async batchUpdate(memories: Array): Promise { + this._captureEvent("batch_update", []); const memoriesBody = memories.map((memory) => ({ memory_id: memory.memoryId, text: memory.text, @@ -449,6 +454,7 @@ export default class MemoryClient { } async batchDelete(memories: Array): Promise { + this._captureEvent("batch_delete", []); const memoriesBody = memories.map((memory) => ({ memory_id: memory, })); @@ -465,7 +471,8 @@ export default class MemoryClient { async getProject(options: ProjectOptions): Promise { this._validateOrgProject(); - + const payloadKeys = Object.keys(options || {}); + this._captureEvent("get_project", [payloadKeys]); const { fields } = options; if (!(this.organizationId && this.projectId)) { @@ -490,7 +497,7 @@ export default class MemoryClient { prompts: PromptUpdatePayload, ): Promise> { 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", @@ -510,6 +517,7 @@ export default class MemoryClient { // WebHooks async getWebhooks(data?: { projectId?: string }): Promise> { + this._captureEvent("get_webhooks", []); const project_id = data?.projectId || this.projectId; const response = await this._fetchWithErrorHandling( `${this.host}/api/v1/webhooks/projects/${project_id}/`, @@ -521,6 +529,7 @@ export default class MemoryClient { } async createWebhook(webhook: WebhookPayload): Promise { + this._captureEvent("create_webhook", []); const response = await this._fetchWithErrorHandling( `${this.host}/api/v1/webhooks/projects/${this.projectId}/`, { @@ -533,6 +542,7 @@ export default class MemoryClient { } async updateWebhook(webhook: WebhookPayload): Promise<{ message: string }> { + this._captureEvent("update_webhook", []); const project_id = webhook.projectId || this.projectId; const response = await this._fetchWithErrorHandling( `${this.host}/api/v1/webhooks/${webhook.webhookId}/`, @@ -551,6 +561,7 @@ export default class MemoryClient { async deleteWebhook(data: { webhookId: string; }): Promise<{ message: string }> { + this._captureEvent("delete_webhook", []); const webhook_id = data.webhookId || data; const response = await this._fetchWithErrorHandling( `${this.host}/api/v1/webhooks/${webhook_id}/`, @@ -563,6 +574,8 @@ export default class MemoryClient { } async feedback(data: FeedbackPayload): Promise<{ message: string }> { + const payloadKeys = Object.keys(data || {}); + this._captureEvent("feedback", [payloadKeys]); const response = await this._fetchWithErrorHandling( `${this.host}/v1/feedback/`, { diff --git a/mem0-ts/src/client/telemetry.browser.ts b/mem0-ts/src/client/telemetry.browser.ts deleted file mode 100644 index a9e26a61..00000000 --- a/mem0-ts/src/client/telemetry.browser.ts +++ /dev/null @@ -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 { - 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 }; diff --git a/mem0-ts/src/client/telemetry.node.ts b/mem0-ts/src/client/telemetry.node.ts deleted file mode 100644 index 741497ad..00000000 --- a/mem0-ts/src/client/telemetry.node.ts +++ /dev/null @@ -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 }; diff --git a/mem0-ts/src/client/telemetry.ts b/mem0-ts/src/client/telemetry.ts index c1fc82db..e45aaadd 100644 --- a/mem0-ts/src/client/telemetry.ts +++ b/mem0-ts/src/client/telemetry.ts @@ -1,3 +1,97 @@ // @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 +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 }; diff --git a/mem0-ts/src/client/telemetry.types.ts b/mem0-ts/src/client/telemetry.types.ts index e3ecd16f..5b307d99 100644 --- a/mem0-ts/src/client/telemetry.types.ts +++ b/mem0-ts/src/client/telemetry.types.ts @@ -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; } diff --git a/mem0-ts/src/oss/src/memory/index.ts b/mem0-ts/src/oss/src/memory/index.ts index eaddaddc..8c930550 100644 --- a/mem0-ts/src/oss/src/memory/index.ts +++ b/mem0-ts/src/oss/src/memory/index.ts @@ -112,7 +112,7 @@ export class Memory { runId, metadata = {}, filters = {}, - prompt, + infer = true, } = config; if (userId) filters.userId = metadata.userId = userId; @@ -136,6 +136,7 @@ export class Memory { final_parsedMessages, metadata, filters, + infer, ); // Add to graph store if available @@ -161,7 +162,27 @@ export class Memory { messages: Message[], metadata: Record, filters: SearchFilters, + infer: boolean, ): Promise { + 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"); // Get prompts diff --git a/mem0-ts/src/oss/src/memory/memory.types.ts b/mem0-ts/src/oss/src/memory/memory.types.ts index 453fc56d..82bb59cd 100644 --- a/mem0-ts/src/oss/src/memory/memory.types.ts +++ b/mem0-ts/src/oss/src/memory/memory.types.ts @@ -10,7 +10,7 @@ export interface Entity { export interface AddMemoryOptions extends Entity { metadata?: Record; filters?: SearchFilters; - prompt?: string; + infer?: boolean; } export interface SearchMemoryOptions extends Entity {