mem0ai 2.1.38 → 2.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/oss/index.js CHANGED
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AnthropicLLM: () => AnthropicLLM,
34
+ AzureAISearch: () => AzureAISearch,
34
35
  AzureOpenAIEmbedder: () => AzureOpenAIEmbedder,
35
36
  EmbedderFactory: () => EmbedderFactory,
36
37
  GoogleEmbedder: () => GoogleEmbedder,
@@ -72,7 +73,9 @@ var MemoryConfigSchema = import_zod.z.object({
72
73
  modelProperties: import_zod.z.record(import_zod.z.string(), import_zod.z.any()).optional(),
73
74
  apiKey: import_zod.z.string().optional(),
74
75
  model: import_zod.z.union([import_zod.z.string(), import_zod.z.any()]).optional(),
75
- baseURL: import_zod.z.string().optional()
76
+ baseURL: import_zod.z.string().optional(),
77
+ embeddingDims: import_zod.z.number().optional(),
78
+ url: import_zod.z.string().optional()
76
79
  })
77
80
  }),
78
81
  vectorStore: import_zod.z.object({
@@ -121,6 +124,7 @@ var OpenAIEmbedder = class {
121
124
  constructor(config) {
122
125
  this.openai = new import_openai.default({ apiKey: config.apiKey });
123
126
  this.model = config.model || "text-embedding-3-small";
127
+ this.embeddingDims = config.embeddingDims || 1536;
124
128
  }
125
129
  async embed(text) {
126
130
  const response = await this.openai.embeddings.create({
@@ -158,6 +162,7 @@ var OllamaEmbedder = class {
158
162
  host: config.url || "http://localhost:11434"
159
163
  });
160
164
  this.model = config.model || "nomic-embed-text:latest";
165
+ this.embeddingDims = config.embeddingDims || 768;
161
166
  this.ensureModelExists().catch((err) => {
162
167
  logger.error(`Error ensuring model exists: ${err}`);
163
168
  });
@@ -200,7 +205,7 @@ var OpenAILLM = class {
200
205
  apiKey: config.apiKey,
201
206
  baseURL: config.baseURL
202
207
  });
203
- this.model = config.model || "gpt-4o-mini";
208
+ this.model = config.model || "gpt-4.1-nano-2025-04-14";
204
209
  }
205
210
  async generateResponse(messages, responseFormat, tools) {
206
211
  const completion = await this.openai.chat.completions.create({
@@ -329,7 +334,12 @@ var AnthropicLLM = class {
329
334
  system: typeof (systemMessage == null ? void 0 : systemMessage.content) === "string" ? systemMessage.content : void 0,
330
335
  max_tokens: 4096
331
336
  });
332
- return response.content[0].text;
337
+ const firstBlock = response.content[0];
338
+ if (firstBlock.type === "text") {
339
+ return firstBlock.text;
340
+ } else {
341
+ throw new Error("Unexpected response type from Anthropic API");
342
+ }
333
343
  }
334
344
  async generateChat(messages) {
335
345
  const response = await this.generateResponse(messages);
@@ -2231,14 +2241,17 @@ create table ${this.tableName} (
2231
2241
  var import_genai = require("@google/genai");
2232
2242
  var GoogleEmbedder = class {
2233
2243
  constructor(config) {
2234
- this.google = new import_genai.GoogleGenAI({ apiKey: config.apiKey });
2235
- this.model = config.model || "text-embedding-004";
2244
+ this.google = new import_genai.GoogleGenAI({
2245
+ apiKey: config.apiKey || process.env.GOOGLE_API_KEY
2246
+ });
2247
+ this.model = config.model || "gemini-embedding-001";
2248
+ this.embeddingDims = config.embeddingDims || 1536;
2236
2249
  }
2237
2250
  async embed(text) {
2238
2251
  const response = await this.google.models.embedContent({
2239
2252
  model: this.model,
2240
2253
  contents: text,
2241
- config: { outputDimensionality: 768 }
2254
+ config: { outputDimensionality: this.embeddingDims }
2242
2255
  });
2243
2256
  return response.embeddings[0].values;
2244
2257
  }
@@ -2367,6 +2380,7 @@ var AzureOpenAIEmbedder = class {
2367
2380
  ...rest
2368
2381
  });
2369
2382
  this.model = config.model || "text-embedding-3-small";
2383
+ this.embeddingDims = config.embeddingDims || 1536;
2370
2384
  }
2371
2385
  async embed(text) {
2372
2386
  const response = await this.client.embeddings.create({
@@ -3113,6 +3127,445 @@ var LangchainVectorStore = class {
3113
3127
  }
3114
3128
  };
3115
3129
 
3130
+ // src/oss/src/vector_stores/azure_ai_search.ts
3131
+ var import_search_documents = require("@azure/search-documents");
3132
+ var import_identity = require("@azure/identity");
3133
+ var AzureAISearch = class {
3134
+ constructor(config) {
3135
+ this.serviceName = config.serviceName;
3136
+ this.indexName = config.collectionName;
3137
+ this.embeddingModelDims = config.embeddingModelDims;
3138
+ this.compressionType = config.compressionType || "none";
3139
+ this.useFloat16 = config.useFloat16 || false;
3140
+ this.hybridSearch = config.hybridSearch || false;
3141
+ this.vectorFilterMode = config.vectorFilterMode || "preFilter";
3142
+ this.apiKey = config.apiKey;
3143
+ const serviceEndpoint = `https://${this.serviceName}.search.windows.net`;
3144
+ const credential = this.apiKey && this.apiKey !== "" && this.apiKey !== "your-api-key" ? new import_search_documents.AzureKeyCredential(this.apiKey) : new import_identity.DefaultAzureCredential();
3145
+ this.searchClient = new import_search_documents.SearchClient(
3146
+ serviceEndpoint,
3147
+ this.indexName,
3148
+ credential
3149
+ );
3150
+ this.indexClient = new import_search_documents.SearchIndexClient(serviceEndpoint, credential);
3151
+ this.initialize().catch(console.error);
3152
+ }
3153
+ /**
3154
+ * Initialize the Azure AI Search index if it doesn't exist
3155
+ */
3156
+ async initialize() {
3157
+ try {
3158
+ const collections = await this.listCols();
3159
+ if (!collections.includes(this.indexName)) {
3160
+ await this.createCol();
3161
+ }
3162
+ } catch (error) {
3163
+ console.error("Error initializing Azure AI Search:", error);
3164
+ throw error;
3165
+ }
3166
+ }
3167
+ /**
3168
+ * Create a new index in Azure AI Search
3169
+ */
3170
+ async createCol() {
3171
+ const vectorType = this.useFloat16 ? "Collection(Edm.Half)" : "Collection(Edm.Single)";
3172
+ const compressionConfigurations = [];
3173
+ let compressionName = void 0;
3174
+ if (this.compressionType === "scalar") {
3175
+ compressionName = "myCompression";
3176
+ compressionConfigurations.push({
3177
+ kind: "scalarQuantization",
3178
+ compressionName
3179
+ });
3180
+ } else if (this.compressionType === "binary") {
3181
+ compressionName = "myCompression";
3182
+ compressionConfigurations.push({
3183
+ kind: "binaryQuantization",
3184
+ compressionName
3185
+ });
3186
+ }
3187
+ const fields = [
3188
+ {
3189
+ name: "id",
3190
+ type: "Edm.String",
3191
+ key: true
3192
+ },
3193
+ {
3194
+ name: "user_id",
3195
+ type: "Edm.String",
3196
+ filterable: true
3197
+ },
3198
+ {
3199
+ name: "run_id",
3200
+ type: "Edm.String",
3201
+ filterable: true
3202
+ },
3203
+ {
3204
+ name: "agent_id",
3205
+ type: "Edm.String",
3206
+ filterable: true
3207
+ },
3208
+ {
3209
+ name: "vector",
3210
+ type: vectorType,
3211
+ searchable: true,
3212
+ vectorSearchDimensions: this.embeddingModelDims,
3213
+ vectorSearchProfileName: "my-vector-config"
3214
+ },
3215
+ {
3216
+ name: "payload",
3217
+ type: "Edm.String",
3218
+ searchable: true
3219
+ }
3220
+ ];
3221
+ const vectorSearch = {
3222
+ profiles: [
3223
+ {
3224
+ name: "my-vector-config",
3225
+ algorithmConfigurationName: "my-algorithms-config",
3226
+ compressionName: this.compressionType !== "none" ? compressionName : void 0
3227
+ }
3228
+ ],
3229
+ algorithms: [
3230
+ {
3231
+ kind: "hnsw",
3232
+ name: "my-algorithms-config"
3233
+ }
3234
+ ],
3235
+ compressions: compressionConfigurations
3236
+ };
3237
+ const index = {
3238
+ name: this.indexName,
3239
+ fields,
3240
+ vectorSearch
3241
+ };
3242
+ await this.indexClient.createOrUpdateIndex(index);
3243
+ }
3244
+ /**
3245
+ * Generate a document for insertion
3246
+ */
3247
+ generateDocument(vector, payload, id) {
3248
+ const document = {
3249
+ id,
3250
+ vector,
3251
+ payload: JSON.stringify(payload)
3252
+ };
3253
+ for (const field of ["user_id", "run_id", "agent_id"]) {
3254
+ if (field in payload) {
3255
+ document[field] = payload[field];
3256
+ }
3257
+ }
3258
+ return document;
3259
+ }
3260
+ /**
3261
+ * Insert vectors into the index
3262
+ */
3263
+ async insert(vectors, ids, payloads) {
3264
+ console.log(
3265
+ `Inserting ${vectors.length} vectors into index ${this.indexName}`
3266
+ );
3267
+ const documents = vectors.map(
3268
+ (vector, idx) => this.generateDocument(vector, payloads[idx] || {}, ids[idx])
3269
+ );
3270
+ const response = await this.searchClient.uploadDocuments(documents);
3271
+ for (const result of response.results) {
3272
+ if (!result.succeeded) {
3273
+ throw new Error(
3274
+ `Insert failed for document ${result.key}: ${result.errorMessage}`
3275
+ );
3276
+ }
3277
+ }
3278
+ }
3279
+ /**
3280
+ * Sanitize filter keys to remove non-alphanumeric characters
3281
+ */
3282
+ sanitizeKey(key) {
3283
+ return key.replace(/[^\w]/g, "");
3284
+ }
3285
+ /**
3286
+ * Build OData filter expression from SearchFilters
3287
+ */
3288
+ buildFilterExpression(filters) {
3289
+ const filterConditions = [];
3290
+ for (const [key, value] of Object.entries(filters)) {
3291
+ const safeKey = this.sanitizeKey(key);
3292
+ if (typeof value === "string") {
3293
+ const safeValue = value.replace(/'/g, "''");
3294
+ filterConditions.push(`${safeKey} eq '${safeValue}'`);
3295
+ } else {
3296
+ filterConditions.push(`${safeKey} eq ${value}`);
3297
+ }
3298
+ }
3299
+ return filterConditions.join(" and ");
3300
+ }
3301
+ /**
3302
+ * Extract JSON from payload string
3303
+ * Handles cases where payload might have extra text
3304
+ */
3305
+ extractJson(payload) {
3306
+ try {
3307
+ JSON.parse(payload);
3308
+ return payload;
3309
+ } catch (e) {
3310
+ const match = payload.match(/\{.*\}/s);
3311
+ return match ? match[0] : payload;
3312
+ }
3313
+ }
3314
+ /**
3315
+ * Search for similar vectors
3316
+ */
3317
+ async search(query, limit = 5, filters) {
3318
+ const filterExpression = filters ? this.buildFilterExpression(filters) : void 0;
3319
+ const vectorQuery = {
3320
+ kind: "vector",
3321
+ vector: query,
3322
+ kNearestNeighborsCount: limit,
3323
+ fields: ["vector"]
3324
+ };
3325
+ let searchResults;
3326
+ if (this.hybridSearch) {
3327
+ searchResults = await this.searchClient.search("*", {
3328
+ vectorSearchOptions: {
3329
+ queries: [vectorQuery],
3330
+ filterMode: this.vectorFilterMode
3331
+ },
3332
+ filter: filterExpression,
3333
+ top: limit,
3334
+ searchFields: ["payload"]
3335
+ });
3336
+ } else {
3337
+ searchResults = await this.searchClient.search("*", {
3338
+ vectorSearchOptions: {
3339
+ queries: [vectorQuery],
3340
+ filterMode: this.vectorFilterMode
3341
+ },
3342
+ filter: filterExpression,
3343
+ top: limit
3344
+ });
3345
+ }
3346
+ const results = [];
3347
+ for await (const result of searchResults.results) {
3348
+ const payloadStr = result.document.payload;
3349
+ const payload = JSON.parse(this.extractJson(payloadStr));
3350
+ results.push({
3351
+ id: result.document.id,
3352
+ score: result.score,
3353
+ payload
3354
+ });
3355
+ }
3356
+ return results;
3357
+ }
3358
+ /**
3359
+ * Delete a vector by ID
3360
+ */
3361
+ async delete(vectorId) {
3362
+ const response = await this.searchClient.deleteDocuments([
3363
+ { id: vectorId }
3364
+ ]);
3365
+ for (const result of response.results) {
3366
+ if (!result.succeeded) {
3367
+ throw new Error(
3368
+ `Delete failed for document ${vectorId}: ${result.errorMessage}`
3369
+ );
3370
+ }
3371
+ }
3372
+ console.log(
3373
+ `Deleted document with ID '${vectorId}' from index '${this.indexName}'.`
3374
+ );
3375
+ }
3376
+ /**
3377
+ * Update a vector and its payload
3378
+ */
3379
+ async update(vectorId, vector, payload) {
3380
+ const document = { id: vectorId };
3381
+ if (vector) {
3382
+ document.vector = vector;
3383
+ }
3384
+ if (payload) {
3385
+ document.payload = JSON.stringify(payload);
3386
+ for (const field of ["user_id", "run_id", "agent_id"]) {
3387
+ if (field in payload) {
3388
+ document[field] = payload[field];
3389
+ }
3390
+ }
3391
+ }
3392
+ const response = await this.searchClient.mergeOrUploadDocuments([document]);
3393
+ for (const result of response.results) {
3394
+ if (!result.succeeded) {
3395
+ throw new Error(
3396
+ `Update failed for document ${vectorId}: ${result.errorMessage}`
3397
+ );
3398
+ }
3399
+ }
3400
+ }
3401
+ /**
3402
+ * Retrieve a vector by ID
3403
+ */
3404
+ async get(vectorId) {
3405
+ try {
3406
+ const result = await this.searchClient.getDocument(vectorId);
3407
+ const payloadStr = result.payload;
3408
+ const payload = JSON.parse(this.extractJson(payloadStr));
3409
+ return {
3410
+ id: result.id,
3411
+ payload
3412
+ };
3413
+ } catch (error) {
3414
+ if ((error == null ? void 0 : error.statusCode) === 404) {
3415
+ return null;
3416
+ }
3417
+ throw error;
3418
+ }
3419
+ }
3420
+ /**
3421
+ * List all collections (indexes)
3422
+ */
3423
+ async listCols() {
3424
+ const names = [];
3425
+ for await (const index of this.indexClient.listIndexes()) {
3426
+ names.push(index.name);
3427
+ }
3428
+ return names;
3429
+ }
3430
+ /**
3431
+ * Delete the index
3432
+ */
3433
+ async deleteCol() {
3434
+ await this.indexClient.deleteIndex(this.indexName);
3435
+ }
3436
+ /**
3437
+ * Get information about the index
3438
+ */
3439
+ async colInfo() {
3440
+ const index = await this.indexClient.getIndex(this.indexName);
3441
+ return {
3442
+ name: index.name,
3443
+ fields: index.fields
3444
+ };
3445
+ }
3446
+ /**
3447
+ * List all vectors in the index
3448
+ */
3449
+ async list(filters, limit = 100) {
3450
+ const filterExpression = filters ? this.buildFilterExpression(filters) : void 0;
3451
+ const searchResults = await this.searchClient.search("*", {
3452
+ filter: filterExpression,
3453
+ top: limit
3454
+ });
3455
+ const results = [];
3456
+ for await (const result of searchResults.results) {
3457
+ const payloadStr = result.document.payload;
3458
+ const payload = JSON.parse(this.extractJson(payloadStr));
3459
+ results.push({
3460
+ id: result.document.id,
3461
+ score: result.score,
3462
+ payload
3463
+ });
3464
+ }
3465
+ return [results, results.length];
3466
+ }
3467
+ /**
3468
+ * Generate a random user ID
3469
+ */
3470
+ generateUUID() {
3471
+ return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(
3472
+ /[xy]/g,
3473
+ function(c) {
3474
+ const r = Math.random() * 16 | 0;
3475
+ const v = c === "x" ? r : r & 3 | 8;
3476
+ return v.toString(16);
3477
+ }
3478
+ );
3479
+ }
3480
+ /**
3481
+ * Get user ID from memory_migrations collection
3482
+ * Required by VectorStore interface
3483
+ */
3484
+ async getUserId() {
3485
+ try {
3486
+ const collections = await this.listCols();
3487
+ const migrationIndexExists = collections.includes("memory_migrations");
3488
+ if (!migrationIndexExists) {
3489
+ const migrationIndex = {
3490
+ name: "memory_migrations",
3491
+ fields: [
3492
+ {
3493
+ name: "id",
3494
+ type: "Edm.String",
3495
+ key: true
3496
+ },
3497
+ {
3498
+ name: "user_id",
3499
+ type: "Edm.String",
3500
+ searchable: false,
3501
+ filterable: true
3502
+ }
3503
+ ]
3504
+ };
3505
+ await this.indexClient.createOrUpdateIndex(migrationIndex);
3506
+ }
3507
+ const searchResults = await this.searchClient.search("*", {
3508
+ top: 1
3509
+ });
3510
+ for await (const result of searchResults.results) {
3511
+ const userId = result.document.user_id;
3512
+ if (userId) {
3513
+ return userId;
3514
+ }
3515
+ }
3516
+ const randomUserId = Math.random().toString(36).substring(2, 15) + Math.random().toString(36).substring(2, 15);
3517
+ await this.searchClient.uploadDocuments([
3518
+ {
3519
+ id: this.generateUUID(),
3520
+ user_id: randomUserId
3521
+ }
3522
+ ]);
3523
+ return randomUserId;
3524
+ } catch (error) {
3525
+ console.error("Error getting user ID:", error);
3526
+ throw error;
3527
+ }
3528
+ }
3529
+ /**
3530
+ * Set user ID in memory_migrations collection
3531
+ * Required by VectorStore interface
3532
+ */
3533
+ async setUserId(userId) {
3534
+ try {
3535
+ const searchResults = await this.searchClient.search("*", {
3536
+ top: 1
3537
+ });
3538
+ let pointId = this.generateUUID();
3539
+ for await (const result of searchResults.results) {
3540
+ pointId = result.document.id;
3541
+ break;
3542
+ }
3543
+ await this.searchClient.mergeOrUploadDocuments([
3544
+ {
3545
+ id: pointId,
3546
+ user_id: userId
3547
+ }
3548
+ ]);
3549
+ } catch (error) {
3550
+ console.error("Error setting user ID:", error);
3551
+ throw error;
3552
+ }
3553
+ }
3554
+ /**
3555
+ * Reset the index by deleting and recreating it
3556
+ */
3557
+ async reset() {
3558
+ console.log(`Resetting index ${this.indexName}...`);
3559
+ try {
3560
+ await this.deleteCol();
3561
+ await this.createCol();
3562
+ } catch (error) {
3563
+ console.error(`Error resetting index ${this.indexName}:`, error);
3564
+ throw error;
3565
+ }
3566
+ }
3567
+ };
3568
+
3116
3569
  // src/oss/src/utils/factory.ts
3117
3570
  var EmbedderFactory = class {
3118
3571
  static create(provider, config) {
@@ -3175,6 +3628,8 @@ var VectorStoreFactory = class {
3175
3628
  return new LangchainVectorStore(config);
3176
3629
  case "vectorize":
3177
3630
  return new VectorizeDB(config);
3631
+ case "azure-ai-search":
3632
+ return new AzureAISearch(config);
3178
3633
  default:
3179
3634
  throw new Error(`Unsupported vector store provider: ${provider}`);
3180
3635
  }
@@ -3289,6 +3744,7 @@ var ConfigManager = class {
3289
3744
  apiKey: (userConf == null ? void 0 : userConf.apiKey) !== void 0 ? userConf.apiKey : defaultConf.apiKey,
3290
3745
  model: finalModel,
3291
3746
  url: userConf == null ? void 0 : userConf.url,
3747
+ embeddingDims: userConf == null ? void 0 : userConf.embeddingDims,
3292
3748
  modelProperties: (userConf == null ? void 0 : userConf.modelProperties) !== void 0 ? userConf.modelProperties : defaultConf.modelProperties
3293
3749
  };
3294
3750
  })()
@@ -3499,7 +3955,7 @@ var MemoryGraph = class {
3499
3955
  }
3500
3956
  this.llm = LLMFactory.create(this.llmProvider, this.config.llm.config);
3501
3957
  this.structuredLlm = LLMFactory.create(
3502
- "openai_structured",
3958
+ this.llmProvider,
3503
3959
  this.config.llm.config
3504
3960
  );
3505
3961
  this.threshold = 0.7;
@@ -4239,8 +4695,13 @@ var Memory = class _Memory {
4239
4695
  return returnedMemories;
4240
4696
  }
4241
4697
  const parsedMessages = messages.map((m) => m.content).join("\n");
4242
- const [systemPrompt, userPrompt] = this.customPrompt ? [this.customPrompt, `Input:
4243
- ${parsedMessages}`] : getFactRetrievalMessages(parsedMessages);
4698
+ const [systemPrompt, userPrompt] = this.customPrompt ? [
4699
+ this.customPrompt.toLowerCase().includes("json") ? this.customPrompt : `${this.customPrompt}
4700
+
4701
+ You MUST return a valid JSON object with a 'facts' key containing an array of strings.`,
4702
+ `Input:
4703
+ ${parsedMessages}`
4704
+ ] : getFactRetrievalMessages(parsedMessages);
4244
4705
  const response = await this.llm.generateResponse(
4245
4706
  [
4246
4707
  { role: "system", content: systemPrompt },
@@ -4619,6 +5080,7 @@ ${parsedMessages}`] : getFactRetrievalMessages(parsedMessages);
4619
5080
  // Annotate the CommonJS export names for ESM import in node:
4620
5081
  0 && (module.exports = {
4621
5082
  AnthropicLLM,
5083
+ AzureAISearch,
4622
5084
  AzureOpenAIEmbedder,
4623
5085
  EmbedderFactory,
4624
5086
  GoogleEmbedder,