mem0ai 3.0.9 → 3.0.12

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
@@ -44,6 +44,7 @@ __export(index_exports, {
44
44
  LangchainEmbedder: () => LangchainEmbedder,
45
45
  LangchainLLM: () => LangchainLLM,
46
46
  LangchainVectorStore: () => LangchainVectorStore,
47
+ LiteLLM: () => LiteLLM,
47
48
  Memory: () => Memory,
48
49
  MemoryConfigSchema: () => MemoryConfigSchema,
49
50
  MemoryVectorStore: () => MemoryVectorStore,
@@ -397,7 +398,11 @@ var AnthropicLLM = class {
397
398
  if (!apiKey) {
398
399
  throw new Error("Anthropic API key is required");
399
400
  }
400
- this.client = new import_sdk.default({ apiKey });
401
+ const clientArgs = { apiKey };
402
+ if (config.baseURL) {
403
+ clientArgs.baseURL = config.baseURL;
404
+ }
405
+ this.client = new import_sdk.default(clientArgs);
401
406
  this.model = config.model || "claude-sonnet-4-6";
402
407
  this.maxTokens = (_a2 = config.maxTokens) != null ? _a2 : 2e3;
403
408
  this.temperature = (_b2 = config.temperature) != null ? _b2 : 0.1;
@@ -1890,13 +1895,15 @@ var RedisDB = class {
1890
1895
  }
1891
1896
  async insert(vectors, ids, payloads) {
1892
1897
  const data = vectors.map((vector, idx) => {
1898
+ var _a2, _b2;
1893
1899
  const payload = toSnakeCase(payloads[idx]);
1894
1900
  const id = ids[idx];
1901
+ const createdAt = payload.created_at ? new Date(payload.created_at).getTime() : 0;
1895
1902
  const entry = {
1896
1903
  memory_id: id,
1897
- hash: payload.hash,
1898
- memory: payload.data,
1899
- created_at: new Date(payload.created_at).getTime(),
1904
+ hash: (_a2 = payload.hash) != null ? _a2 : "",
1905
+ memory: (_b2 = payload.data) != null ? _b2 : "",
1906
+ created_at: createdAt,
1900
1907
  embedding: new Float32Array(vector).buffer
1901
1908
  };
1902
1909
  ["agent_id", "run_id", "user_id"].forEach((field) => {
@@ -2075,13 +2082,16 @@ var RedisDB = class {
2075
2082
  }
2076
2083
  }
2077
2084
  async update(vectorId, vector, payload) {
2085
+ var _a2, _b2;
2078
2086
  const snakePayload = toSnakeCase(payload);
2087
+ const createdAt = snakePayload.created_at ? new Date(snakePayload.created_at).getTime() : 0;
2088
+ const updatedAt = snakePayload.updated_at ? new Date(snakePayload.updated_at).getTime() : 0;
2079
2089
  const entry = {
2080
2090
  memory_id: vectorId,
2081
- hash: snakePayload.hash,
2082
- memory: snakePayload.data,
2083
- created_at: new Date(snakePayload.created_at).getTime(),
2084
- updated_at: new Date(snakePayload.updated_at).getTime(),
2091
+ hash: (_a2 = snakePayload.hash) != null ? _a2 : "",
2092
+ memory: (_b2 = snakePayload.data) != null ? _b2 : "",
2093
+ created_at: createdAt,
2094
+ updated_at: updatedAt,
2085
2095
  embedding: Buffer.from(new Float32Array(vector).buffer)
2086
2096
  };
2087
2097
  ["agent_id", "run_id", "user_id"].forEach((field) => {
@@ -2327,6 +2337,66 @@ var DeepSeekLLM = class extends OpenAILLM {
2327
2337
  }
2328
2338
  };
2329
2339
 
2340
+ // src/oss/src/llms/litellm.ts
2341
+ var LiteLLM = class extends OpenAILLM {
2342
+ constructor(config) {
2343
+ super({
2344
+ ...config,
2345
+ apiKey: config.apiKey || process.env.LITELLM_API_KEY || "sk-anything",
2346
+ baseURL: config.baseURL || process.env.LITELLM_API_BASE || "http://localhost:4000",
2347
+ model: config.model || "gpt-5-mini"
2348
+ });
2349
+ }
2350
+ async generateResponse(messages, responseFormat, tools) {
2351
+ try {
2352
+ return await super.generateResponse(messages, responseFormat, tools);
2353
+ } catch (err) {
2354
+ const message = err instanceof Error ? err.message : String(err);
2355
+ throw new Error(`LiteLLM failed: ${message}`);
2356
+ }
2357
+ }
2358
+ async generateChat(messages) {
2359
+ try {
2360
+ return await super.generateChat(messages);
2361
+ } catch (err) {
2362
+ const message = err instanceof Error ? err.message : String(err);
2363
+ throw new Error(`LiteLLM failed: ${message}`);
2364
+ }
2365
+ }
2366
+ };
2367
+
2368
+ // src/oss/src/llms/minimax.ts
2369
+ var MiniMaxLLM = class extends OpenAILLM {
2370
+ constructor(config) {
2371
+ const apiKey = config.apiKey || process.env.MINIMAX_API_KEY;
2372
+ if (!apiKey) {
2373
+ throw new Error("MiniMax API key is required");
2374
+ }
2375
+ super({
2376
+ ...config,
2377
+ apiKey,
2378
+ baseURL: config.baseURL || process.env.MINIMAX_API_BASE || "https://api.minimax.io/v1",
2379
+ model: config.model || "MiniMax-M2.7"
2380
+ });
2381
+ }
2382
+ async generateResponse(messages, responseFormat, tools) {
2383
+ try {
2384
+ return await super.generateResponse(messages, responseFormat, tools);
2385
+ } catch (err) {
2386
+ const message = err instanceof Error ? err.message : String(err);
2387
+ throw new Error(`MiniMax LLM failed: ${message}`);
2388
+ }
2389
+ }
2390
+ async generateChat(messages) {
2391
+ try {
2392
+ return await super.generateChat(messages);
2393
+ } catch (err) {
2394
+ const message = err instanceof Error ? err.message : String(err);
2395
+ throw new Error(`MiniMax LLM failed: ${message}`);
2396
+ }
2397
+ }
2398
+ };
2399
+
2330
2400
  // src/oss/src/vector_stores/supabase.ts
2331
2401
  var import_supabase_js = require("@supabase/supabase-js");
2332
2402
  var SupabaseDB = class {
@@ -2894,7 +2964,7 @@ var GoogleLLM = class {
2894
2964
  };
2895
2965
 
2896
2966
  // src/oss/src/llms/azure.ts
2897
- var import_openai7 = require("openai");
2967
+ var import_openai9 = require("openai");
2898
2968
  var AzureOpenAILLM = class {
2899
2969
  constructor(config) {
2900
2970
  var _a2;
@@ -2902,7 +2972,7 @@ var AzureOpenAILLM = class {
2902
2972
  throw new Error("Azure OpenAI requires both API key and endpoint");
2903
2973
  }
2904
2974
  const { endpoint, ...rest } = config.modelProperties;
2905
- this.client = new import_openai7.AzureOpenAI({
2975
+ this.client = new import_openai9.AzureOpenAI({
2906
2976
  apiKey: config.apiKey,
2907
2977
  endpoint,
2908
2978
  ...rest
@@ -2955,7 +3025,7 @@ var AzureOpenAILLM = class {
2955
3025
  };
2956
3026
 
2957
3027
  // src/oss/src/embeddings/azure.ts
2958
- var import_openai8 = require("openai");
3028
+ var import_openai10 = require("openai");
2959
3029
  var AzureOpenAIEmbedder = class {
2960
3030
  constructor(config) {
2961
3031
  var _a2;
@@ -2963,7 +3033,7 @@ var AzureOpenAIEmbedder = class {
2963
3033
  throw new Error("Azure OpenAI requires both API key and endpoint");
2964
3034
  }
2965
3035
  const { endpoint, ...rest } = config.modelProperties;
2966
- this.client = new import_openai8.AzureOpenAI({
3036
+ this.client = new import_openai10.AzureOpenAI({
2967
3037
  apiKey: config.apiKey,
2968
3038
  endpoint,
2969
3039
  ...rest
@@ -4600,24 +4670,59 @@ function buildFilterConditions(filters, startIndex) {
4600
4670
  }
4601
4671
  return { conditions, values, paramIndex };
4602
4672
  }
4673
+ function getConnectionString(config) {
4674
+ var _a2;
4675
+ return ((_a2 = config.connectionString) == null ? void 0 : _a2.trim()) || void 0;
4676
+ }
4677
+ function validateConnectionConfig(config) {
4678
+ if (getConnectionString(config)) {
4679
+ return;
4680
+ }
4681
+ const missingFields = ["user", "password", "host", "port"].filter((field) => {
4682
+ const v = config[field];
4683
+ return v === void 0 || v === null || v === "";
4684
+ });
4685
+ if (missingFields.length > 0) {
4686
+ throw new Error(
4687
+ `PGVector requires either connectionString or ${missingFields.join(", ")}`
4688
+ );
4689
+ }
4690
+ }
4691
+ function buildClientConfig(config, database) {
4692
+ const connectionString = getConnectionString(config);
4693
+ if (connectionString) {
4694
+ return {
4695
+ connectionString,
4696
+ ...config.ssl !== void 0 ? { ssl: config.ssl } : {}
4697
+ };
4698
+ }
4699
+ return {
4700
+ database,
4701
+ user: config.user,
4702
+ password: config.password,
4703
+ host: config.host,
4704
+ port: config.port,
4705
+ ...config.ssl !== void 0 ? { ssl: config.ssl } : {}
4706
+ };
4707
+ }
4603
4708
  var PGVector = class {
4604
4709
  constructor(config) {
4710
+ validateConnectionConfig(config);
4605
4711
  this.collectionName = validateIdentifier(
4606
4712
  config.collectionName || "memories",
4607
4713
  "collectionName"
4608
4714
  );
4609
4715
  this.useDiskann = config.diskann || false;
4610
4716
  this.useHnsw = config.hnsw || false;
4611
- this.dbName = validateIdentifier(config.dbname || "vector_store", "dbname");
4717
+ this.useDirectConnection = !!getConnectionString(config);
4718
+ this.dbName = this.useDirectConnection ? "" : validateIdentifier(config.dbname || "vector_store", "dbname");
4612
4719
  this.config = config;
4613
- this.client = new Client({
4614
- database: "postgres",
4615
- // Initially connect to default postgres database
4616
- user: config.user,
4617
- password: config.password,
4618
- host: config.host,
4619
- port: config.port
4620
- });
4720
+ this.client = new Client(
4721
+ buildClientConfig(
4722
+ config,
4723
+ this.useDirectConnection ? void 0 : "postgres"
4724
+ )
4725
+ );
4621
4726
  this.initialize().catch(console.error);
4622
4727
  }
4623
4728
  col() {
@@ -4632,19 +4737,15 @@ var PGVector = class {
4632
4737
  async _doInitialize() {
4633
4738
  try {
4634
4739
  await this.client.connect();
4635
- const dbExists = await this.checkDatabaseExists(this.dbName);
4636
- if (!dbExists) {
4637
- await this.createDatabase(this.dbName);
4638
- }
4639
- await this.client.end();
4640
- this.client = new Client({
4641
- database: this.dbName,
4642
- user: this.config.user,
4643
- password: this.config.password,
4644
- host: this.config.host,
4645
- port: this.config.port
4646
- });
4647
- await this.client.connect();
4740
+ if (!this.useDirectConnection) {
4741
+ const dbExists = await this.checkDatabaseExists(this.dbName);
4742
+ if (!dbExists) {
4743
+ await this.createDatabase(this.dbName);
4744
+ }
4745
+ await this.client.end();
4746
+ this.client = new Client(buildClientConfig(this.config, this.dbName));
4747
+ await this.client.connect();
4748
+ }
4648
4749
  await this.client.query("CREATE EXTENSION IF NOT EXISTS vector");
4649
4750
  await this.client.query(`
4650
4751
  CREATE TABLE IF NOT EXISTS memory_migrations (
@@ -4915,6 +5016,10 @@ var LLMFactory = class {
4915
5016
  return new LangchainLLM(config);
4916
5017
  case "deepseek":
4917
5018
  return new DeepSeekLLM(config);
5019
+ case "litellm":
5020
+ return new LiteLLM(config);
5021
+ case "minimax":
5022
+ return new MiniMaxLLM(config);
4918
5023
  default:
4919
5024
  throw new Error(`Unsupported LLM provider: ${provider}`);
4920
5025
  }
@@ -5144,6 +5249,7 @@ var get_image_description = async (image_url) => {
5144
5249
  return response;
5145
5250
  };
5146
5251
  var parse_vision_messages = async (messages) => {
5252
+ var _a2;
5147
5253
  const parsed_messages = [];
5148
5254
  for (const message of messages) {
5149
5255
  let new_message = {
@@ -5152,9 +5258,11 @@ var parse_vision_messages = async (messages) => {
5152
5258
  };
5153
5259
  if (message.role !== "system") {
5154
5260
  if (typeof message.content === "object" && message.content.type === "image_url") {
5155
- const description = await get_image_description(
5156
- message.content.image_url.url
5157
- );
5261
+ const imageUrl = (_a2 = message.content.image_url) == null ? void 0 : _a2.url;
5262
+ if (!imageUrl) {
5263
+ throw new Error("image_url content part is missing image_url.url");
5264
+ }
5265
+ const description = await get_image_description(imageUrl);
5158
5266
  new_message.content = typeof description === "string" ? description : JSON.stringify(description);
5159
5267
  parsed_messages.push(new_message);
5160
5268
  } else parsed_messages.push(message);
@@ -5164,7 +5272,7 @@ var parse_vision_messages = async (messages) => {
5164
5272
  };
5165
5273
 
5166
5274
  // src/oss/src/utils/telemetry.ts
5167
- var version = true ? "3.0.9" : "dev";
5275
+ var version = true ? "3.0.12" : "dev";
5168
5276
  var MEM0_TELEMETRY = true;
5169
5277
  var _a, _b;
5170
5278
  try {
@@ -6697,7 +6805,24 @@ var NON_SPECIFIC_ADJ = /* @__PURE__ */ new Set([
6697
6805
  "collaborative",
6698
6806
  "final",
6699
6807
  "initial",
6700
- "side"
6808
+ "side",
6809
+ "top"
6810
+ ]);
6811
+ var TOPIC_PREFIX_WORDS = /* @__PURE__ */ new Set([
6812
+ "a",
6813
+ "an",
6814
+ "the",
6815
+ "my",
6816
+ "your",
6817
+ "our",
6818
+ "their",
6819
+ "his",
6820
+ "her",
6821
+ "its",
6822
+ "this",
6823
+ "that",
6824
+ "these",
6825
+ "those"
6701
6826
  ]);
6702
6827
  var GENERIC_ENDINGS = /* @__PURE__ */ new Set([
6703
6828
  "work",
@@ -6764,6 +6889,23 @@ var GENERIC_CAPS = /* @__PURE__ */ new Set([
6764
6889
  "advantages",
6765
6890
  "disadvantages"
6766
6891
  ]);
6892
+ var GENERIC_SINGLE_ENTITY_TERMS = /* @__PURE__ */ new Set([
6893
+ "user",
6894
+ "assistant",
6895
+ "agent",
6896
+ "customer",
6897
+ "client",
6898
+ "person",
6899
+ "people",
6900
+ "human",
6901
+ "memory",
6902
+ "message",
6903
+ "conversation",
6904
+ "chat",
6905
+ "session",
6906
+ "system",
6907
+ "top"
6908
+ ]);
6767
6909
  var FORMATTING_MARKERS = /* @__PURE__ */ new Set([
6768
6910
  "*",
6769
6911
  "-",
@@ -6810,22 +6952,64 @@ function stripGenericEnding(words) {
6810
6952
  }
6811
6953
  return words;
6812
6954
  }
6813
- function isSentenceStart(tokens, idx, rawText) {
6814
- if (idx === 0) {
6815
- return true;
6955
+ function stripTopicPrefix(words) {
6956
+ let start = 0;
6957
+ while (start < words.length && TOPIC_PREFIX_WORDS.has(words[start].toLowerCase())) {
6958
+ start++;
6816
6959
  }
6817
- const prev = tokens[idx - 1];
6818
- if (/[.!?:]$/.test(prev)) {
6819
- return true;
6820
- }
6821
- if (FORMATTING_MARKERS.has(prev)) {
6822
- return true;
6823
- }
6824
- const tokenStart = rawText.indexOf(tokens[idx]);
6825
- if (tokenStart > 0 && rawText.charAt(tokenStart - 1) === "\n") {
6960
+ return words.slice(start);
6961
+ }
6962
+ function cleanToken(token) {
6963
+ return token.replace(/^[^\w.]+|[^\w.]+$/g, "");
6964
+ }
6965
+ function tokenize(text) {
6966
+ var _a2;
6967
+ return (_a2 = text.match(
6968
+ /[A-Za-z_][\w-]*(?:\.[A-Za-z_][\w-]*)*|\d[\d,]*(?:\.\d+)?|[,:;.!?&]/g
6969
+ )) != null ? _a2 : [];
6970
+ }
6971
+ function isCapitalized(token) {
6972
+ return /^[A-Z]/.test(token) && /[A-Za-z]/.test(token);
6973
+ }
6974
+ function hasInternalCapOrDigit(token) {
6975
+ return /\d/.test(token) || /[A-Z]/.test(token.slice(1)) || /^[A-Z]{2,}$/.test(token);
6976
+ }
6977
+ function isBadSingleNameToken(token) {
6978
+ const lower = token.toLowerCase();
6979
+ return GENERIC_SINGLE_ENTITY_TERMS.has(lower) || GENERIC_CAPS.has(lower);
6980
+ }
6981
+ function looksLikeMetricCount(token) {
6982
+ return /^\d[\d,]*(?:\.\d+)?$/.test(token);
6983
+ }
6984
+ function isMetricListContext(tokens, idx) {
6985
+ const prev = idx > 0 ? tokens[idx - 1] : "";
6986
+ const next = idx + 1 < tokens.length ? tokens[idx + 1] : "";
6987
+ return [":", ",", ";"].includes(prev) || [",", ";"].includes(next);
6988
+ }
6989
+ function isSentenceStart(tokens, idx) {
6990
+ if (idx === 0) return true;
6991
+ return [".", "!", "?", ":"].includes(tokens[idx - 1]) || FORMATTING_MARKERS.has(tokens[idx - 1]);
6992
+ }
6993
+ function isListItemNameToken(tokens, idx) {
6994
+ const token = cleanToken(tokens[idx]);
6995
+ if (!isCapitalized(token) || isBadSingleNameToken(token)) return false;
6996
+ const next = idx + 1 < tokens.length ? cleanToken(tokens[idx + 1]) : "";
6997
+ if (!looksLikeMetricCount(next)) return false;
6998
+ return isMetricListContext(tokens, idx) || isMetricListContext(tokens, idx + 1);
6999
+ }
7000
+ function isNameToken(tokens, idx) {
7001
+ const token = cleanToken(tokens[idx]);
7002
+ if (!token || !isCapitalized(token) || isBadSingleNameToken(token))
7003
+ return false;
7004
+ if (hasInternalCapOrDigit(token) || isListItemNameToken(tokens, idx))
6826
7005
  return true;
6827
- }
6828
- return false;
7006
+ return !isSentenceStart(tokens, idx);
7007
+ }
7008
+ function cleanEntityText(text) {
7009
+ return text.replace(/^\*+\s*|\s*\*+$/g, "").replace(/\s*:+$/g, "").replace(/^\d+\s*\.\s*/, "").replace(/\s+\d[\d,]*(?:\.\d+)?$/g, "").replace(/[.,;!?]+$/, "").trim().replace(/\s+/g, " ");
7010
+ }
7011
+ function isCoordinatedNameTopic(text) {
7012
+ return /\b[A-Z][\w-]+\s+and\s+[A-Z][\w-]+\b/.test(text);
6829
7013
  }
6830
7014
  function extractQuoted(text) {
6831
7015
  const entities = [];
@@ -6846,62 +7030,57 @@ function extractQuoted(text) {
6846
7030
  }
6847
7031
  return entities;
6848
7032
  }
7033
+ function extractIdentifiers(text) {
7034
+ const entities = [];
7035
+ const identifierRe = /\b[A-Za-z_][\w-]*(?:\.[A-Za-z_][\w-]*)+\b/g;
7036
+ let match;
7037
+ while ((match = identifierRe.exec(text)) !== null) {
7038
+ entities.push({ type: "IDENTIFIER", text: match[0] });
7039
+ }
7040
+ return entities;
7041
+ }
6849
7042
  function extractProper(text) {
6850
7043
  const entities = [];
6851
- const tokens = text.split(/\s+/).filter(Boolean);
6852
- const functionWords = /* @__PURE__ */ new Set([
6853
- "'s",
6854
- "of",
6855
- "the",
6856
- "in",
6857
- "and",
6858
- "for",
6859
- "at",
6860
- "is"
6861
- ]);
7044
+ const tokens = tokenize(text);
7045
+ const innerConnectors = /* @__PURE__ */ new Set(["of", "the", "in", "for", "at"]);
6862
7046
  let i = 0;
6863
7047
  while (i < tokens.length) {
6864
- const tok = tokens[i];
6865
- if (FORMATTING_MARKERS.has(tok)) {
7048
+ const token = cleanToken(tokens[i]);
7049
+ const next = i + 1 < tokens.length ? tokens[i + 1] : "";
7050
+ const afterNext = i + 2 < tokens.length ? cleanToken(tokens[i + 2]) : "";
7051
+ if (token && next === "&" && afterNext && isCapitalized(token) && isCapitalized(afterNext) && !isBadSingleNameToken(token) && !isBadSingleNameToken(afterNext)) {
7052
+ entities.push({
7053
+ type: "PROPER",
7054
+ text: cleanEntityText(`${token} & ${afterNext}`)
7055
+ });
7056
+ i += 3;
7057
+ continue;
7058
+ }
7059
+ if (!isNameToken(tokens, i)) {
6866
7060
  i++;
6867
7061
  continue;
6868
7062
  }
6869
- const isLabel = i + 1 < tokens.length && tokens[i + 1] === ":";
6870
- const isCap = tok.length > 0 && tok.charAt(0) === tok.charAt(0).toUpperCase() && /[A-Z]/.test(tok.charAt(0));
6871
- if (isCap && !isLabel) {
6872
- const seq = [
6873
- { token: tok, idx: i }
6874
- ];
6875
- let j = i + 1;
6876
- while (j < tokens.length) {
6877
- const t = tokens[j];
6878
- const tIsCap = t.length > 0 && t.charAt(0) === t.charAt(0).toUpperCase() && /[A-Z]/.test(t.charAt(0));
6879
- if (tIsCap || functionWords.has(t.toLowerCase())) {
6880
- seq.push({ token: t, idx: j });
6881
- j++;
6882
- } else {
6883
- break;
6884
- }
6885
- }
6886
- while (seq.length > 0 && functionWords.has(seq[seq.length - 1].token.toLowerCase())) {
6887
- seq.pop();
7063
+ const span = [cleanToken(tokens[i])];
7064
+ let j = i + 1;
7065
+ while (j < tokens.length) {
7066
+ const current = cleanToken(tokens[j]);
7067
+ if (isNameToken(tokens, j)) {
7068
+ span.push(current);
7069
+ j++;
7070
+ continue;
6888
7071
  }
6889
- if (seq.length > 0) {
6890
- const hasMidCap = seq.some(({ token, idx: tokenIdx }) => {
6891
- const isCapWord = /[A-Z]/.test(token.charAt(0)) && !functionWords.has(token.toLowerCase());
6892
- return isCapWord && !isSentenceStart(tokens, tokenIdx, text);
6893
- });
6894
- if (hasMidCap) {
6895
- const phrase = seq.map((s) => s.token).join(" ");
6896
- if (phrase.length > 2) {
6897
- entities.push({ type: "PROPER", text: phrase });
6898
- }
6899
- }
7072
+ if (innerConnectors.has(current.toLowerCase()) && j + 1 < tokens.length && isNameToken(tokens, j + 1)) {
7073
+ span.push(current, cleanToken(tokens[j + 1]));
7074
+ j += 2;
7075
+ continue;
6900
7076
  }
6901
- i = j;
6902
- } else {
6903
- i++;
7077
+ break;
6904
7078
  }
7079
+ const phrase = cleanEntityText(span.join(" "));
7080
+ if (phrase.length > 2) {
7081
+ entities.push({ type: "PROPER", text: phrase });
7082
+ }
7083
+ i = Math.max(j, i + 1);
6905
7084
  }
6906
7085
  return entities;
6907
7086
  }
@@ -6933,11 +7112,11 @@ function extractCompoundsWithNlp(text) {
6933
7112
  const filtered = words.filter(
6934
7113
  (w) => !NON_SPECIFIC_ADJ.has(w.toLowerCase())
6935
7114
  );
6936
- const cleaned = stripGenericEnding(filtered);
7115
+ const cleaned = stripGenericEnding(stripTopicPrefix(filtered));
6937
7116
  if (cleaned.length >= 2) {
6938
- const phrase = cleaned.join(" ");
7117
+ const phrase = cleanEntityText(cleaned.join(" "));
6939
7118
  if (phrase.length > 3) {
6940
- entities.push({ type: "COMPOUND", text: phrase });
7119
+ entities.push({ type: "TOPIC", text: phrase });
6941
7120
  }
6942
7121
  }
6943
7122
  }
@@ -6945,7 +7124,7 @@ function extractCompoundsWithNlp(text) {
6945
7124
  }
6946
7125
  function extractCompoundsRegex(text) {
6947
7126
  const entities = [];
6948
- const compoundRe = /\b([A-Z][a-z]+(?:\s+(?:of|and|the|for|in)\s+)?[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b/g;
7127
+ const compoundRe = /\b([A-Z][a-z]+(?:\s+(?:of|the|for|in)\s+)?[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b/g;
6949
7128
  let match;
6950
7129
  while ((match = compoundRe.exec(text)) !== null) {
6951
7130
  const phrase = match[1].trim();
@@ -6956,9 +7135,12 @@ function extractCompoundsRegex(text) {
6956
7135
  const filtered = words.filter(
6957
7136
  (w) => !NON_SPECIFIC_ADJ.has(w.toLowerCase())
6958
7137
  );
6959
- const cleaned = stripGenericEnding(filtered);
7138
+ const cleaned = stripGenericEnding(stripTopicPrefix(filtered));
6960
7139
  if (cleaned.length >= 2) {
6961
- entities.push({ type: "COMPOUND", text: cleaned.join(" ") });
7140
+ entities.push({
7141
+ type: "TOPIC",
7142
+ text: cleanEntityText(cleaned.join(" "))
7143
+ });
6962
7144
  }
6963
7145
  }
6964
7146
  }
@@ -6980,9 +7162,12 @@ function extractCompoundsRegex(text) {
6980
7162
  const filtered = words.filter(
6981
7163
  (w) => !NON_SPECIFIC_ADJ.has(w.toLowerCase())
6982
7164
  );
6983
- const cleaned = stripGenericEnding(filtered);
7165
+ const cleaned = stripGenericEnding(stripTopicPrefix(filtered));
6984
7166
  if (cleaned.length >= 2) {
6985
- entities.push({ type: "COMPOUND", text: cleaned.join(" ") });
7167
+ entities.push({
7168
+ type: "TOPIC",
7169
+ text: cleanEntityText(cleaned.join(" "))
7170
+ });
6986
7171
  }
6987
7172
  }
6988
7173
  }
@@ -6995,6 +7180,7 @@ function extractEntities(text) {
6995
7180
  const raw = [];
6996
7181
  raw.push(...extractQuoted(text));
6997
7182
  raw.push(...extractProper(text));
7183
+ raw.push(...extractIdentifiers(text));
6998
7184
  if (nlp) {
6999
7185
  raw.push(...extractCompoundsWithNlp(text));
7000
7186
  } else {
@@ -7012,13 +7198,13 @@ function extractEntities(text) {
7012
7198
  const cleaned = [];
7013
7199
  for (const entity of deduped) {
7014
7200
  let txt = entity.text.trim();
7015
- txt = txt.replace(/^\*+\s*|\s*\*+$/g, "");
7016
- txt = txt.replace(/\s*:+$/, "");
7017
- txt = txt.replace(/^\d+\s*\.\s*/, "");
7018
- txt = txt.replace(/[.,;!?]+$/, "").trim();
7201
+ txt = cleanEntityText(txt);
7019
7202
  if (!txt || txt.length <= 2 || hasArtifacts(txt)) {
7020
7203
  continue;
7021
7204
  }
7205
+ if (entity.type === "TOPIC" && (/^\d/.test(txt) || isCoordinatedNameTopic(txt))) {
7206
+ continue;
7207
+ }
7022
7208
  if (entity.type === "PROPER" && !txt.includes(" ") && GENERIC_CAPS.has(txt.toLowerCase())) {
7023
7209
  continue;
7024
7210
  }
@@ -7026,9 +7212,9 @@ function extractEntities(text) {
7026
7212
  }
7027
7213
  const typePriority = {
7028
7214
  PROPER: 0,
7029
- COMPOUND: 1,
7215
+ IDENTIFIER: 1,
7030
7216
  QUOTED: 2,
7031
- NOUN: 3
7217
+ TOPIC: 3
7032
7218
  };
7033
7219
  const best = /* @__PURE__ */ new Map();
7034
7220
  for (const entity of cleaned) {
@@ -7039,10 +7225,14 @@ function extractEntities(text) {
7039
7225
  }
7040
7226
  }
7041
7227
  const bestEntities = Array.from(best.values());
7042
- const allLower = bestEntities.map((e) => e.text.toLowerCase());
7043
7228
  return bestEntities.filter(
7044
- (entity) => !allLower.some(
7045
- (other) => entity.text.toLowerCase() !== other && other.includes(entity.text.toLowerCase())
7229
+ (entity) => !bestEntities.some(
7230
+ (other) => {
7231
+ var _a3, _b3;
7232
+ return entity.text.toLowerCase() !== other.text.toLowerCase() && ((_a3 = typePriority[entity.type]) != null ? _a3 : 99) >= ((_b3 = typePriority[other.type]) != null ? _b3 : 99) && new RegExp(
7233
+ `(^|\\s)${entity.text.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\s|$)`
7234
+ ).test(other.text.toLowerCase());
7235
+ }
7046
7236
  )
7047
7237
  );
7048
7238
  }
@@ -7334,6 +7524,32 @@ var Memory = class _Memory {
7334
7524
  if (payload.run_id) filters.run_id = payload.run_id;
7335
7525
  return filters;
7336
7526
  }
7527
+ _normalizeEntityText(value) {
7528
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
7529
+ }
7530
+ async _existingEntitiesByText(entityStore, filters) {
7531
+ var _a2;
7532
+ const rowsByText = /* @__PURE__ */ new Map();
7533
+ let rows = [];
7534
+ try {
7535
+ const listed = await entityStore.list(filters, 1e4);
7536
+ rows = Array.isArray(listed) && Array.isArray(listed[0]) ? listed[0] : listed;
7537
+ } catch (e) {
7538
+ console.debug(
7539
+ `Exact entity lookup failed, falling back to semantic dedup: ${e}`
7540
+ );
7541
+ return rowsByText;
7542
+ }
7543
+ for (const row of rows) {
7544
+ const text = (_a2 = row.payload) == null ? void 0 : _a2.data;
7545
+ if (typeof text !== "string") continue;
7546
+ const key = this._normalizeEntityText(text);
7547
+ if (key && !rowsByText.has(key)) {
7548
+ rowsByText.set(key, row);
7549
+ }
7550
+ }
7551
+ return rowsByText;
7552
+ }
7337
7553
  /**
7338
7554
  * Remove `memoryId` from every entity record scoped to `filters`.
7339
7555
  * If an entity's `linkedMemoryIds` becomes empty after removal, the
@@ -7411,6 +7627,10 @@ var Memory = class _Memory {
7411
7627
  const entities = extractEntities(text);
7412
7628
  if (entities.length === 0) return;
7413
7629
  const entityStore = await this.getEntityStore();
7630
+ const exactMatches = await this._existingEntitiesByText(
7631
+ entityStore,
7632
+ filters
7633
+ );
7414
7634
  for (const entity of entities) {
7415
7635
  try {
7416
7636
  let entityVec;
@@ -7421,12 +7641,18 @@ var Memory = class _Memory {
7421
7641
  continue;
7422
7642
  }
7423
7643
  let matches = [];
7424
- try {
7425
- matches = await entityStore.search(entityVec, 1, filters);
7426
- } catch (e) {
7644
+ const exactMatch = exactMatches.get(
7645
+ this._normalizeEntityText(entity.text)
7646
+ );
7647
+ if (!exactMatch) {
7648
+ try {
7649
+ matches = await entityStore.search(entityVec, 1, filters);
7650
+ } catch (e) {
7651
+ }
7427
7652
  }
7428
- if (matches.length > 0 && ((_a2 = matches[0].score) != null ? _a2 : 0) >= 0.95) {
7429
- const match = matches[0];
7653
+ const semanticMatch = matches.length > 0 && ((_a2 = matches[0].score) != null ? _a2 : 0) >= 0.95 ? matches[0] : void 0;
7654
+ const match = exactMatch != null ? exactMatch : semanticMatch;
7655
+ if (match) {
7430
7656
  const payload = match.payload || {};
7431
7657
  const linked = new Set(
7432
7658
  Array.isArray(payload.linkedMemoryIds) ? payload.linkedMemoryIds : []
@@ -7588,6 +7814,25 @@ var Memory = class _Memory {
7588
7814
  "messages is required and cannot be undefined or null. Provide a string or array of messages."
7589
7815
  );
7590
7816
  }
7817
+ if (Array.isArray(messages)) {
7818
+ if (messages.length === 0) {
7819
+ throw new Error(
7820
+ "messages array cannot be empty. Provide at least one message with non-empty content."
7821
+ );
7822
+ }
7823
+ const allBlank = messages.every(
7824
+ (m) => typeof m.content === "string" && m.content.trim() === ""
7825
+ );
7826
+ if (allBlank) {
7827
+ throw new Error(
7828
+ "messages array cannot contain only blank content. Provide at least one message with non-empty content."
7829
+ );
7830
+ }
7831
+ } else if (messages.trim() === "") {
7832
+ throw new Error(
7833
+ "messages string cannot be empty. Provide non-empty content."
7834
+ );
7835
+ }
7591
7836
  const temporalUsageNotice = detectTemporalUsageFromMetadata(
7592
7837
  config == null ? void 0 : config.metadata
7593
7838
  );
@@ -7647,7 +7892,7 @@ var Memory = class _Memory {
7647
7892
  if (!infer) {
7648
7893
  const returnedMemories = [];
7649
7894
  for (const message of messages) {
7650
- if (message.content === "system") {
7895
+ if (message.role === "system") {
7651
7896
  continue;
7652
7897
  }
7653
7898
  const memoryId = await this.createMemory(
@@ -7671,7 +7916,7 @@ var Memory = class _Memory {
7671
7916
  } catch (e) {
7672
7917
  }
7673
7918
  }
7674
- const parsedMessages = messages.map((m) => m.content).join("\n");
7919
+ const parsedMessages = messages.map((m) => `${m.role}: ${m.content}`).join("\n");
7675
7920
  const queryEmbedding = await this.embedder.embed(parsedMessages);
7676
7921
  const existingResults = await this.vectorStore.search(
7677
7922
  queryEmbedding,
@@ -7924,6 +8169,10 @@ var Memory = class _Memory {
7924
8169
  }
7925
8170
  if (valid.length > 0) {
7926
8171
  const entityStore = await this.getEntityStore();
8172
+ const exactMatches = await this._existingEntitiesByText(
8173
+ entityStore,
8174
+ filters
8175
+ );
7927
8176
  const toInsertVectors = [];
7928
8177
  const toInsertIds = [];
7929
8178
  const toInsertPayloads = [];
@@ -7931,12 +8180,16 @@ var Memory = class _Memory {
7931
8180
  const { entityType, entityText, memoryIds } = globalEntities[key];
7932
8181
  const entityVec = entityEmbeddings[j];
7933
8182
  let matches = [];
7934
- try {
7935
- matches = await entityStore.search(entityVec, 1, filters);
7936
- } catch (e) {
8183
+ const exactMatch = exactMatches.get(key);
8184
+ if (!exactMatch) {
8185
+ try {
8186
+ matches = await entityStore.search(entityVec, 1, filters);
8187
+ } catch (e) {
8188
+ }
7937
8189
  }
7938
- if (matches.length > 0 && ((_f = matches[0].score) != null ? _f : 0) >= 0.95) {
7939
- const match = matches[0];
8190
+ const semanticMatch = matches.length > 0 && ((_f = matches[0].score) != null ? _f : 0) >= 0.95 ? matches[0] : void 0;
8191
+ const match = exactMatch != null ? exactMatch : semanticMatch;
8192
+ if (match) {
7940
8193
  const payload = match.payload || {};
7941
8194
  const linked = new Set((_g = payload.linkedMemoryIds) != null ? _g : []);
7942
8195
  for (const mid of memoryIds) linked.add(mid);
@@ -8030,7 +8283,13 @@ var Memory = class _Memory {
8030
8283
  memoryItem.metadata[key] = value;
8031
8284
  }
8032
8285
  }
8033
- const result = { ...memoryItem, ...filters };
8286
+ const result = {
8287
+ ...memoryItem,
8288
+ ...filters,
8289
+ ...memory.payload.attributedTo && {
8290
+ attributedTo: memory.payload.attributedTo
8291
+ }
8292
+ };
8034
8293
  await this._displayFirstRunNotice("get");
8035
8294
  return result;
8036
8295
  }
@@ -8228,6 +8487,7 @@ var Memory = class _Memory {
8228
8487
  ...payload.user_id && { user_id: payload.user_id },
8229
8488
  ...payload.agent_id && { agent_id: payload.agent_id },
8230
8489
  ...payload.run_id && { run_id: payload.run_id },
8490
+ ...payload.attributedTo && { attributedTo: payload.attributedTo },
8231
8491
  ...scored.scoreDetails && { score_details: scored.scoreDetails }
8232
8492
  };
8233
8493
  });
@@ -8301,7 +8561,9 @@ var Memory = class _Memory {
8301
8561
  has_agent_id: !!config.agentId,
8302
8562
  has_run_id: !!config.runId
8303
8563
  });
8304
- const { userId, agentId, runId } = config;
8564
+ const userId = validateAndTrimEntityId(config.userId, "userId");
8565
+ const agentId = validateAndTrimEntityId(config.agentId, "agentId");
8566
+ const runId = validateAndTrimEntityId(config.runId, "runId");
8305
8567
  const filters = {};
8306
8568
  if (userId) filters.user_id = userId;
8307
8569
  if (agentId) filters.agent_id = agentId;
@@ -8421,7 +8683,10 @@ var Memory = class _Memory {
8421
8683
  metadata: Object.entries(mem.payload).filter(([key]) => !excludedKeys.has(key)).reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
8422
8684
  ...mem.payload.user_id && { user_id: mem.payload.user_id },
8423
8685
  ...mem.payload.agent_id && { agent_id: mem.payload.agent_id },
8424
- ...mem.payload.run_id && { run_id: mem.payload.run_id }
8686
+ ...mem.payload.run_id && { run_id: mem.payload.run_id },
8687
+ ...mem.payload.attributedTo && {
8688
+ attributedTo: mem.payload.attributedTo
8689
+ }
8425
8690
  }));
8426
8691
  const result = { results };
8427
8692
  const scaleThresholdNotice = detectScaleThresholdFromTopK(topK);
@@ -8656,6 +8921,7 @@ var Memory = class _Memory {
8656
8921
  LangchainEmbedder,
8657
8922
  LangchainLLM,
8658
8923
  LangchainVectorStore,
8924
+ LiteLLM,
8659
8925
  Memory,
8660
8926
  MemoryConfigSchema,
8661
8927
  MemoryVectorStore,