mem0ai 3.0.10 → 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.
@@ -1836,13 +1836,15 @@ var RedisDB = class {
1836
1836
  }
1837
1837
  async insert(vectors, ids, payloads) {
1838
1838
  const data = vectors.map((vector, idx) => {
1839
+ var _a2, _b2;
1839
1840
  const payload = toSnakeCase(payloads[idx]);
1840
1841
  const id = ids[idx];
1842
+ const createdAt = payload.created_at ? new Date(payload.created_at).getTime() : 0;
1841
1843
  const entry = {
1842
1844
  memory_id: id,
1843
- hash: payload.hash,
1844
- memory: payload.data,
1845
- created_at: new Date(payload.created_at).getTime(),
1845
+ hash: (_a2 = payload.hash) != null ? _a2 : "",
1846
+ memory: (_b2 = payload.data) != null ? _b2 : "",
1847
+ created_at: createdAt,
1846
1848
  embedding: new Float32Array(vector).buffer
1847
1849
  };
1848
1850
  ["agent_id", "run_id", "user_id"].forEach((field) => {
@@ -2021,13 +2023,16 @@ var RedisDB = class {
2021
2023
  }
2022
2024
  }
2023
2025
  async update(vectorId, vector, payload) {
2026
+ var _a2, _b2;
2024
2027
  const snakePayload = toSnakeCase(payload);
2028
+ const createdAt = snakePayload.created_at ? new Date(snakePayload.created_at).getTime() : 0;
2029
+ const updatedAt = snakePayload.updated_at ? new Date(snakePayload.updated_at).getTime() : 0;
2025
2030
  const entry = {
2026
2031
  memory_id: vectorId,
2027
- hash: snakePayload.hash,
2028
- memory: snakePayload.data,
2029
- created_at: new Date(snakePayload.created_at).getTime(),
2030
- updated_at: new Date(snakePayload.updated_at).getTime(),
2032
+ hash: (_a2 = snakePayload.hash) != null ? _a2 : "",
2033
+ memory: (_b2 = snakePayload.data) != null ? _b2 : "",
2034
+ created_at: createdAt,
2035
+ updated_at: updatedAt,
2031
2036
  embedding: Buffer.from(new Float32Array(vector).buffer)
2032
2037
  };
2033
2038
  ["agent_id", "run_id", "user_id"].forEach((field) => {
@@ -2273,6 +2278,66 @@ var DeepSeekLLM = class extends OpenAILLM {
2273
2278
  }
2274
2279
  };
2275
2280
 
2281
+ // src/oss/src/llms/litellm.ts
2282
+ var LiteLLM = class extends OpenAILLM {
2283
+ constructor(config) {
2284
+ super({
2285
+ ...config,
2286
+ apiKey: config.apiKey || process.env.LITELLM_API_KEY || "sk-anything",
2287
+ baseURL: config.baseURL || process.env.LITELLM_API_BASE || "http://localhost:4000",
2288
+ model: config.model || "gpt-5-mini"
2289
+ });
2290
+ }
2291
+ async generateResponse(messages, responseFormat, tools) {
2292
+ try {
2293
+ return await super.generateResponse(messages, responseFormat, tools);
2294
+ } catch (err) {
2295
+ const message = err instanceof Error ? err.message : String(err);
2296
+ throw new Error(`LiteLLM failed: ${message}`);
2297
+ }
2298
+ }
2299
+ async generateChat(messages) {
2300
+ try {
2301
+ return await super.generateChat(messages);
2302
+ } catch (err) {
2303
+ const message = err instanceof Error ? err.message : String(err);
2304
+ throw new Error(`LiteLLM failed: ${message}`);
2305
+ }
2306
+ }
2307
+ };
2308
+
2309
+ // src/oss/src/llms/minimax.ts
2310
+ var MiniMaxLLM = class extends OpenAILLM {
2311
+ constructor(config) {
2312
+ const apiKey = config.apiKey || process.env.MINIMAX_API_KEY;
2313
+ if (!apiKey) {
2314
+ throw new Error("MiniMax API key is required");
2315
+ }
2316
+ super({
2317
+ ...config,
2318
+ apiKey,
2319
+ baseURL: config.baseURL || process.env.MINIMAX_API_BASE || "https://api.minimax.io/v1",
2320
+ model: config.model || "MiniMax-M2.7"
2321
+ });
2322
+ }
2323
+ async generateResponse(messages, responseFormat, tools) {
2324
+ try {
2325
+ return await super.generateResponse(messages, responseFormat, tools);
2326
+ } catch (err) {
2327
+ const message = err instanceof Error ? err.message : String(err);
2328
+ throw new Error(`MiniMax LLM failed: ${message}`);
2329
+ }
2330
+ }
2331
+ async generateChat(messages) {
2332
+ try {
2333
+ return await super.generateChat(messages);
2334
+ } catch (err) {
2335
+ const message = err instanceof Error ? err.message : String(err);
2336
+ throw new Error(`MiniMax LLM failed: ${message}`);
2337
+ }
2338
+ }
2339
+ };
2340
+
2276
2341
  // src/oss/src/vector_stores/supabase.ts
2277
2342
  import { createClient as createClient2 } from "@supabase/supabase-js";
2278
2343
  var SupabaseDB = class {
@@ -4554,24 +4619,59 @@ function buildFilterConditions(filters, startIndex) {
4554
4619
  }
4555
4620
  return { conditions, values, paramIndex };
4556
4621
  }
4622
+ function getConnectionString(config) {
4623
+ var _a2;
4624
+ return ((_a2 = config.connectionString) == null ? void 0 : _a2.trim()) || void 0;
4625
+ }
4626
+ function validateConnectionConfig(config) {
4627
+ if (getConnectionString(config)) {
4628
+ return;
4629
+ }
4630
+ const missingFields = ["user", "password", "host", "port"].filter((field) => {
4631
+ const v = config[field];
4632
+ return v === void 0 || v === null || v === "";
4633
+ });
4634
+ if (missingFields.length > 0) {
4635
+ throw new Error(
4636
+ `PGVector requires either connectionString or ${missingFields.join(", ")}`
4637
+ );
4638
+ }
4639
+ }
4640
+ function buildClientConfig(config, database) {
4641
+ const connectionString = getConnectionString(config);
4642
+ if (connectionString) {
4643
+ return {
4644
+ connectionString,
4645
+ ...config.ssl !== void 0 ? { ssl: config.ssl } : {}
4646
+ };
4647
+ }
4648
+ return {
4649
+ database,
4650
+ user: config.user,
4651
+ password: config.password,
4652
+ host: config.host,
4653
+ port: config.port,
4654
+ ...config.ssl !== void 0 ? { ssl: config.ssl } : {}
4655
+ };
4656
+ }
4557
4657
  var PGVector = class {
4558
4658
  constructor(config) {
4659
+ validateConnectionConfig(config);
4559
4660
  this.collectionName = validateIdentifier(
4560
4661
  config.collectionName || "memories",
4561
4662
  "collectionName"
4562
4663
  );
4563
4664
  this.useDiskann = config.diskann || false;
4564
4665
  this.useHnsw = config.hnsw || false;
4565
- this.dbName = validateIdentifier(config.dbname || "vector_store", "dbname");
4666
+ this.useDirectConnection = !!getConnectionString(config);
4667
+ this.dbName = this.useDirectConnection ? "" : validateIdentifier(config.dbname || "vector_store", "dbname");
4566
4668
  this.config = config;
4567
- this.client = new Client({
4568
- database: "postgres",
4569
- // Initially connect to default postgres database
4570
- user: config.user,
4571
- password: config.password,
4572
- host: config.host,
4573
- port: config.port
4574
- });
4669
+ this.client = new Client(
4670
+ buildClientConfig(
4671
+ config,
4672
+ this.useDirectConnection ? void 0 : "postgres"
4673
+ )
4674
+ );
4575
4675
  this.initialize().catch(console.error);
4576
4676
  }
4577
4677
  col() {
@@ -4586,19 +4686,15 @@ var PGVector = class {
4586
4686
  async _doInitialize() {
4587
4687
  try {
4588
4688
  await this.client.connect();
4589
- const dbExists = await this.checkDatabaseExists(this.dbName);
4590
- if (!dbExists) {
4591
- await this.createDatabase(this.dbName);
4592
- }
4593
- await this.client.end();
4594
- this.client = new Client({
4595
- database: this.dbName,
4596
- user: this.config.user,
4597
- password: this.config.password,
4598
- host: this.config.host,
4599
- port: this.config.port
4600
- });
4601
- await this.client.connect();
4689
+ if (!this.useDirectConnection) {
4690
+ const dbExists = await this.checkDatabaseExists(this.dbName);
4691
+ if (!dbExists) {
4692
+ await this.createDatabase(this.dbName);
4693
+ }
4694
+ await this.client.end();
4695
+ this.client = new Client(buildClientConfig(this.config, this.dbName));
4696
+ await this.client.connect();
4697
+ }
4602
4698
  await this.client.query("CREATE EXTENSION IF NOT EXISTS vector");
4603
4699
  await this.client.query(`
4604
4700
  CREATE TABLE IF NOT EXISTS memory_migrations (
@@ -4869,6 +4965,10 @@ var LLMFactory = class {
4869
4965
  return new LangchainLLM(config);
4870
4966
  case "deepseek":
4871
4967
  return new DeepSeekLLM(config);
4968
+ case "litellm":
4969
+ return new LiteLLM(config);
4970
+ case "minimax":
4971
+ return new MiniMaxLLM(config);
4872
4972
  default:
4873
4973
  throw new Error(`Unsupported LLM provider: ${provider}`);
4874
4974
  }
@@ -5121,7 +5221,7 @@ var parse_vision_messages = async (messages) => {
5121
5221
  };
5122
5222
 
5123
5223
  // src/oss/src/utils/telemetry.ts
5124
- var version = true ? "3.0.10" : "dev";
5224
+ var version = true ? "3.0.12" : "dev";
5125
5225
  var MEM0_TELEMETRY = true;
5126
5226
  var _a, _b;
5127
5227
  try {
@@ -6654,7 +6754,24 @@ var NON_SPECIFIC_ADJ = /* @__PURE__ */ new Set([
6654
6754
  "collaborative",
6655
6755
  "final",
6656
6756
  "initial",
6657
- "side"
6757
+ "side",
6758
+ "top"
6759
+ ]);
6760
+ var TOPIC_PREFIX_WORDS = /* @__PURE__ */ new Set([
6761
+ "a",
6762
+ "an",
6763
+ "the",
6764
+ "my",
6765
+ "your",
6766
+ "our",
6767
+ "their",
6768
+ "his",
6769
+ "her",
6770
+ "its",
6771
+ "this",
6772
+ "that",
6773
+ "these",
6774
+ "those"
6658
6775
  ]);
6659
6776
  var GENERIC_ENDINGS = /* @__PURE__ */ new Set([
6660
6777
  "work",
@@ -6721,6 +6838,23 @@ var GENERIC_CAPS = /* @__PURE__ */ new Set([
6721
6838
  "advantages",
6722
6839
  "disadvantages"
6723
6840
  ]);
6841
+ var GENERIC_SINGLE_ENTITY_TERMS = /* @__PURE__ */ new Set([
6842
+ "user",
6843
+ "assistant",
6844
+ "agent",
6845
+ "customer",
6846
+ "client",
6847
+ "person",
6848
+ "people",
6849
+ "human",
6850
+ "memory",
6851
+ "message",
6852
+ "conversation",
6853
+ "chat",
6854
+ "session",
6855
+ "system",
6856
+ "top"
6857
+ ]);
6724
6858
  var FORMATTING_MARKERS = /* @__PURE__ */ new Set([
6725
6859
  "*",
6726
6860
  "-",
@@ -6767,22 +6901,64 @@ function stripGenericEnding(words) {
6767
6901
  }
6768
6902
  return words;
6769
6903
  }
6770
- function isSentenceStart(tokens, idx, rawText) {
6771
- if (idx === 0) {
6772
- return true;
6904
+ function stripTopicPrefix(words) {
6905
+ let start = 0;
6906
+ while (start < words.length && TOPIC_PREFIX_WORDS.has(words[start].toLowerCase())) {
6907
+ start++;
6773
6908
  }
6774
- const prev = tokens[idx - 1];
6775
- if (/[.!?:]$/.test(prev)) {
6776
- return true;
6777
- }
6778
- if (FORMATTING_MARKERS.has(prev)) {
6779
- return true;
6780
- }
6781
- const tokenStart = rawText.indexOf(tokens[idx]);
6782
- if (tokenStart > 0 && rawText.charAt(tokenStart - 1) === "\n") {
6909
+ return words.slice(start);
6910
+ }
6911
+ function cleanToken(token) {
6912
+ return token.replace(/^[^\w.]+|[^\w.]+$/g, "");
6913
+ }
6914
+ function tokenize(text) {
6915
+ var _a2;
6916
+ return (_a2 = text.match(
6917
+ /[A-Za-z_][\w-]*(?:\.[A-Za-z_][\w-]*)*|\d[\d,]*(?:\.\d+)?|[,:;.!?&]/g
6918
+ )) != null ? _a2 : [];
6919
+ }
6920
+ function isCapitalized(token) {
6921
+ return /^[A-Z]/.test(token) && /[A-Za-z]/.test(token);
6922
+ }
6923
+ function hasInternalCapOrDigit(token) {
6924
+ return /\d/.test(token) || /[A-Z]/.test(token.slice(1)) || /^[A-Z]{2,}$/.test(token);
6925
+ }
6926
+ function isBadSingleNameToken(token) {
6927
+ const lower = token.toLowerCase();
6928
+ return GENERIC_SINGLE_ENTITY_TERMS.has(lower) || GENERIC_CAPS.has(lower);
6929
+ }
6930
+ function looksLikeMetricCount(token) {
6931
+ return /^\d[\d,]*(?:\.\d+)?$/.test(token);
6932
+ }
6933
+ function isMetricListContext(tokens, idx) {
6934
+ const prev = idx > 0 ? tokens[idx - 1] : "";
6935
+ const next = idx + 1 < tokens.length ? tokens[idx + 1] : "";
6936
+ return [":", ",", ";"].includes(prev) || [",", ";"].includes(next);
6937
+ }
6938
+ function isSentenceStart(tokens, idx) {
6939
+ if (idx === 0) return true;
6940
+ return [".", "!", "?", ":"].includes(tokens[idx - 1]) || FORMATTING_MARKERS.has(tokens[idx - 1]);
6941
+ }
6942
+ function isListItemNameToken(tokens, idx) {
6943
+ const token = cleanToken(tokens[idx]);
6944
+ if (!isCapitalized(token) || isBadSingleNameToken(token)) return false;
6945
+ const next = idx + 1 < tokens.length ? cleanToken(tokens[idx + 1]) : "";
6946
+ if (!looksLikeMetricCount(next)) return false;
6947
+ return isMetricListContext(tokens, idx) || isMetricListContext(tokens, idx + 1);
6948
+ }
6949
+ function isNameToken(tokens, idx) {
6950
+ const token = cleanToken(tokens[idx]);
6951
+ if (!token || !isCapitalized(token) || isBadSingleNameToken(token))
6952
+ return false;
6953
+ if (hasInternalCapOrDigit(token) || isListItemNameToken(tokens, idx))
6783
6954
  return true;
6784
- }
6785
- return false;
6955
+ return !isSentenceStart(tokens, idx);
6956
+ }
6957
+ function cleanEntityText(text) {
6958
+ return text.replace(/^\*+\s*|\s*\*+$/g, "").replace(/\s*:+$/g, "").replace(/^\d+\s*\.\s*/, "").replace(/\s+\d[\d,]*(?:\.\d+)?$/g, "").replace(/[.,;!?]+$/, "").trim().replace(/\s+/g, " ");
6959
+ }
6960
+ function isCoordinatedNameTopic(text) {
6961
+ return /\b[A-Z][\w-]+\s+and\s+[A-Z][\w-]+\b/.test(text);
6786
6962
  }
6787
6963
  function extractQuoted(text) {
6788
6964
  const entities = [];
@@ -6803,62 +6979,57 @@ function extractQuoted(text) {
6803
6979
  }
6804
6980
  return entities;
6805
6981
  }
6982
+ function extractIdentifiers(text) {
6983
+ const entities = [];
6984
+ const identifierRe = /\b[A-Za-z_][\w-]*(?:\.[A-Za-z_][\w-]*)+\b/g;
6985
+ let match;
6986
+ while ((match = identifierRe.exec(text)) !== null) {
6987
+ entities.push({ type: "IDENTIFIER", text: match[0] });
6988
+ }
6989
+ return entities;
6990
+ }
6806
6991
  function extractProper(text) {
6807
6992
  const entities = [];
6808
- const tokens = text.split(/\s+/).filter(Boolean);
6809
- const functionWords = /* @__PURE__ */ new Set([
6810
- "'s",
6811
- "of",
6812
- "the",
6813
- "in",
6814
- "and",
6815
- "for",
6816
- "at",
6817
- "is"
6818
- ]);
6993
+ const tokens = tokenize(text);
6994
+ const innerConnectors = /* @__PURE__ */ new Set(["of", "the", "in", "for", "at"]);
6819
6995
  let i = 0;
6820
6996
  while (i < tokens.length) {
6821
- const tok = tokens[i];
6822
- if (FORMATTING_MARKERS.has(tok)) {
6997
+ const token = cleanToken(tokens[i]);
6998
+ const next = i + 1 < tokens.length ? tokens[i + 1] : "";
6999
+ const afterNext = i + 2 < tokens.length ? cleanToken(tokens[i + 2]) : "";
7000
+ if (token && next === "&" && afterNext && isCapitalized(token) && isCapitalized(afterNext) && !isBadSingleNameToken(token) && !isBadSingleNameToken(afterNext)) {
7001
+ entities.push({
7002
+ type: "PROPER",
7003
+ text: cleanEntityText(`${token} & ${afterNext}`)
7004
+ });
7005
+ i += 3;
7006
+ continue;
7007
+ }
7008
+ if (!isNameToken(tokens, i)) {
6823
7009
  i++;
6824
7010
  continue;
6825
7011
  }
6826
- const isLabel = i + 1 < tokens.length && tokens[i + 1] === ":";
6827
- const isCap = tok.length > 0 && tok.charAt(0) === tok.charAt(0).toUpperCase() && /[A-Z]/.test(tok.charAt(0));
6828
- if (isCap && !isLabel) {
6829
- const seq = [
6830
- { token: tok, idx: i }
6831
- ];
6832
- let j = i + 1;
6833
- while (j < tokens.length) {
6834
- const t = tokens[j];
6835
- const tIsCap = t.length > 0 && t.charAt(0) === t.charAt(0).toUpperCase() && /[A-Z]/.test(t.charAt(0));
6836
- if (tIsCap || functionWords.has(t.toLowerCase())) {
6837
- seq.push({ token: t, idx: j });
6838
- j++;
6839
- } else {
6840
- break;
6841
- }
6842
- }
6843
- while (seq.length > 0 && functionWords.has(seq[seq.length - 1].token.toLowerCase())) {
6844
- seq.pop();
7012
+ const span = [cleanToken(tokens[i])];
7013
+ let j = i + 1;
7014
+ while (j < tokens.length) {
7015
+ const current = cleanToken(tokens[j]);
7016
+ if (isNameToken(tokens, j)) {
7017
+ span.push(current);
7018
+ j++;
7019
+ continue;
6845
7020
  }
6846
- if (seq.length > 0) {
6847
- const hasMidCap = seq.some(({ token, idx: tokenIdx }) => {
6848
- const isCapWord = /[A-Z]/.test(token.charAt(0)) && !functionWords.has(token.toLowerCase());
6849
- return isCapWord && !isSentenceStart(tokens, tokenIdx, text);
6850
- });
6851
- if (hasMidCap) {
6852
- const phrase = seq.map((s) => s.token).join(" ");
6853
- if (phrase.length > 2) {
6854
- entities.push({ type: "PROPER", text: phrase });
6855
- }
6856
- }
7021
+ if (innerConnectors.has(current.toLowerCase()) && j + 1 < tokens.length && isNameToken(tokens, j + 1)) {
7022
+ span.push(current, cleanToken(tokens[j + 1]));
7023
+ j += 2;
7024
+ continue;
6857
7025
  }
6858
- i = j;
6859
- } else {
6860
- i++;
7026
+ break;
7027
+ }
7028
+ const phrase = cleanEntityText(span.join(" "));
7029
+ if (phrase.length > 2) {
7030
+ entities.push({ type: "PROPER", text: phrase });
6861
7031
  }
7032
+ i = Math.max(j, i + 1);
6862
7033
  }
6863
7034
  return entities;
6864
7035
  }
@@ -6890,11 +7061,11 @@ function extractCompoundsWithNlp(text) {
6890
7061
  const filtered = words.filter(
6891
7062
  (w) => !NON_SPECIFIC_ADJ.has(w.toLowerCase())
6892
7063
  );
6893
- const cleaned = stripGenericEnding(filtered);
7064
+ const cleaned = stripGenericEnding(stripTopicPrefix(filtered));
6894
7065
  if (cleaned.length >= 2) {
6895
- const phrase = cleaned.join(" ");
7066
+ const phrase = cleanEntityText(cleaned.join(" "));
6896
7067
  if (phrase.length > 3) {
6897
- entities.push({ type: "COMPOUND", text: phrase });
7068
+ entities.push({ type: "TOPIC", text: phrase });
6898
7069
  }
6899
7070
  }
6900
7071
  }
@@ -6902,7 +7073,7 @@ function extractCompoundsWithNlp(text) {
6902
7073
  }
6903
7074
  function extractCompoundsRegex(text) {
6904
7075
  const entities = [];
6905
- 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;
7076
+ const compoundRe = /\b([A-Z][a-z]+(?:\s+(?:of|the|for|in)\s+)?[A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)\b/g;
6906
7077
  let match;
6907
7078
  while ((match = compoundRe.exec(text)) !== null) {
6908
7079
  const phrase = match[1].trim();
@@ -6913,9 +7084,12 @@ function extractCompoundsRegex(text) {
6913
7084
  const filtered = words.filter(
6914
7085
  (w) => !NON_SPECIFIC_ADJ.has(w.toLowerCase())
6915
7086
  );
6916
- const cleaned = stripGenericEnding(filtered);
7087
+ const cleaned = stripGenericEnding(stripTopicPrefix(filtered));
6917
7088
  if (cleaned.length >= 2) {
6918
- entities.push({ type: "COMPOUND", text: cleaned.join(" ") });
7089
+ entities.push({
7090
+ type: "TOPIC",
7091
+ text: cleanEntityText(cleaned.join(" "))
7092
+ });
6919
7093
  }
6920
7094
  }
6921
7095
  }
@@ -6937,9 +7111,12 @@ function extractCompoundsRegex(text) {
6937
7111
  const filtered = words.filter(
6938
7112
  (w) => !NON_SPECIFIC_ADJ.has(w.toLowerCase())
6939
7113
  );
6940
- const cleaned = stripGenericEnding(filtered);
7114
+ const cleaned = stripGenericEnding(stripTopicPrefix(filtered));
6941
7115
  if (cleaned.length >= 2) {
6942
- entities.push({ type: "COMPOUND", text: cleaned.join(" ") });
7116
+ entities.push({
7117
+ type: "TOPIC",
7118
+ text: cleanEntityText(cleaned.join(" "))
7119
+ });
6943
7120
  }
6944
7121
  }
6945
7122
  }
@@ -6952,6 +7129,7 @@ function extractEntities(text) {
6952
7129
  const raw = [];
6953
7130
  raw.push(...extractQuoted(text));
6954
7131
  raw.push(...extractProper(text));
7132
+ raw.push(...extractIdentifiers(text));
6955
7133
  if (nlp) {
6956
7134
  raw.push(...extractCompoundsWithNlp(text));
6957
7135
  } else {
@@ -6969,13 +7147,13 @@ function extractEntities(text) {
6969
7147
  const cleaned = [];
6970
7148
  for (const entity of deduped) {
6971
7149
  let txt = entity.text.trim();
6972
- txt = txt.replace(/^\*+\s*|\s*\*+$/g, "");
6973
- txt = txt.replace(/\s*:+$/, "");
6974
- txt = txt.replace(/^\d+\s*\.\s*/, "");
6975
- txt = txt.replace(/[.,;!?]+$/, "").trim();
7150
+ txt = cleanEntityText(txt);
6976
7151
  if (!txt || txt.length <= 2 || hasArtifacts(txt)) {
6977
7152
  continue;
6978
7153
  }
7154
+ if (entity.type === "TOPIC" && (/^\d/.test(txt) || isCoordinatedNameTopic(txt))) {
7155
+ continue;
7156
+ }
6979
7157
  if (entity.type === "PROPER" && !txt.includes(" ") && GENERIC_CAPS.has(txt.toLowerCase())) {
6980
7158
  continue;
6981
7159
  }
@@ -6983,9 +7161,9 @@ function extractEntities(text) {
6983
7161
  }
6984
7162
  const typePriority = {
6985
7163
  PROPER: 0,
6986
- COMPOUND: 1,
7164
+ IDENTIFIER: 1,
6987
7165
  QUOTED: 2,
6988
- NOUN: 3
7166
+ TOPIC: 3
6989
7167
  };
6990
7168
  const best = /* @__PURE__ */ new Map();
6991
7169
  for (const entity of cleaned) {
@@ -6996,10 +7174,14 @@ function extractEntities(text) {
6996
7174
  }
6997
7175
  }
6998
7176
  const bestEntities = Array.from(best.values());
6999
- const allLower = bestEntities.map((e) => e.text.toLowerCase());
7000
7177
  return bestEntities.filter(
7001
- (entity) => !allLower.some(
7002
- (other) => entity.text.toLowerCase() !== other && other.includes(entity.text.toLowerCase())
7178
+ (entity) => !bestEntities.some(
7179
+ (other) => {
7180
+ var _a3, _b3;
7181
+ return entity.text.toLowerCase() !== other.text.toLowerCase() && ((_a3 = typePriority[entity.type]) != null ? _a3 : 99) >= ((_b3 = typePriority[other.type]) != null ? _b3 : 99) && new RegExp(
7182
+ `(^|\\s)${entity.text.toLowerCase().replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}(\\s|$)`
7183
+ ).test(other.text.toLowerCase());
7184
+ }
7003
7185
  )
7004
7186
  );
7005
7187
  }
@@ -7291,6 +7473,32 @@ var Memory = class _Memory {
7291
7473
  if (payload.run_id) filters.run_id = payload.run_id;
7292
7474
  return filters;
7293
7475
  }
7476
+ _normalizeEntityText(value) {
7477
+ return value.trim().toLowerCase().replace(/\s+/g, " ");
7478
+ }
7479
+ async _existingEntitiesByText(entityStore, filters) {
7480
+ var _a2;
7481
+ const rowsByText = /* @__PURE__ */ new Map();
7482
+ let rows = [];
7483
+ try {
7484
+ const listed = await entityStore.list(filters, 1e4);
7485
+ rows = Array.isArray(listed) && Array.isArray(listed[0]) ? listed[0] : listed;
7486
+ } catch (e) {
7487
+ console.debug(
7488
+ `Exact entity lookup failed, falling back to semantic dedup: ${e}`
7489
+ );
7490
+ return rowsByText;
7491
+ }
7492
+ for (const row of rows) {
7493
+ const text = (_a2 = row.payload) == null ? void 0 : _a2.data;
7494
+ if (typeof text !== "string") continue;
7495
+ const key = this._normalizeEntityText(text);
7496
+ if (key && !rowsByText.has(key)) {
7497
+ rowsByText.set(key, row);
7498
+ }
7499
+ }
7500
+ return rowsByText;
7501
+ }
7294
7502
  /**
7295
7503
  * Remove `memoryId` from every entity record scoped to `filters`.
7296
7504
  * If an entity's `linkedMemoryIds` becomes empty after removal, the
@@ -7368,6 +7576,10 @@ var Memory = class _Memory {
7368
7576
  const entities = extractEntities(text);
7369
7577
  if (entities.length === 0) return;
7370
7578
  const entityStore = await this.getEntityStore();
7579
+ const exactMatches = await this._existingEntitiesByText(
7580
+ entityStore,
7581
+ filters
7582
+ );
7371
7583
  for (const entity of entities) {
7372
7584
  try {
7373
7585
  let entityVec;
@@ -7378,12 +7590,18 @@ var Memory = class _Memory {
7378
7590
  continue;
7379
7591
  }
7380
7592
  let matches = [];
7381
- try {
7382
- matches = await entityStore.search(entityVec, 1, filters);
7383
- } catch (e) {
7593
+ const exactMatch = exactMatches.get(
7594
+ this._normalizeEntityText(entity.text)
7595
+ );
7596
+ if (!exactMatch) {
7597
+ try {
7598
+ matches = await entityStore.search(entityVec, 1, filters);
7599
+ } catch (e) {
7600
+ }
7384
7601
  }
7385
- if (matches.length > 0 && ((_a2 = matches[0].score) != null ? _a2 : 0) >= 0.95) {
7386
- const match = matches[0];
7602
+ const semanticMatch = matches.length > 0 && ((_a2 = matches[0].score) != null ? _a2 : 0) >= 0.95 ? matches[0] : void 0;
7603
+ const match = exactMatch != null ? exactMatch : semanticMatch;
7604
+ if (match) {
7387
7605
  const payload = match.payload || {};
7388
7606
  const linked = new Set(
7389
7607
  Array.isArray(payload.linkedMemoryIds) ? payload.linkedMemoryIds : []
@@ -7900,6 +8118,10 @@ var Memory = class _Memory {
7900
8118
  }
7901
8119
  if (valid.length > 0) {
7902
8120
  const entityStore = await this.getEntityStore();
8121
+ const exactMatches = await this._existingEntitiesByText(
8122
+ entityStore,
8123
+ filters
8124
+ );
7903
8125
  const toInsertVectors = [];
7904
8126
  const toInsertIds = [];
7905
8127
  const toInsertPayloads = [];
@@ -7907,12 +8129,16 @@ var Memory = class _Memory {
7907
8129
  const { entityType, entityText, memoryIds } = globalEntities[key];
7908
8130
  const entityVec = entityEmbeddings[j];
7909
8131
  let matches = [];
7910
- try {
7911
- matches = await entityStore.search(entityVec, 1, filters);
7912
- } catch (e) {
8132
+ const exactMatch = exactMatches.get(key);
8133
+ if (!exactMatch) {
8134
+ try {
8135
+ matches = await entityStore.search(entityVec, 1, filters);
8136
+ } catch (e) {
8137
+ }
7913
8138
  }
7914
- if (matches.length > 0 && ((_f = matches[0].score) != null ? _f : 0) >= 0.95) {
7915
- const match = matches[0];
8139
+ const semanticMatch = matches.length > 0 && ((_f = matches[0].score) != null ? _f : 0) >= 0.95 ? matches[0] : void 0;
8140
+ const match = exactMatch != null ? exactMatch : semanticMatch;
8141
+ if (match) {
7916
8142
  const payload = match.payload || {};
7917
8143
  const linked = new Set((_g = payload.linkedMemoryIds) != null ? _g : []);
7918
8144
  for (const mid of memoryIds) linked.add(mid);
@@ -8284,7 +8510,9 @@ var Memory = class _Memory {
8284
8510
  has_agent_id: !!config.agentId,
8285
8511
  has_run_id: !!config.runId
8286
8512
  });
8287
- const { userId, agentId, runId } = config;
8513
+ const userId = validateAndTrimEntityId(config.userId, "userId");
8514
+ const agentId = validateAndTrimEntityId(config.agentId, "agentId");
8515
+ const runId = validateAndTrimEntityId(config.runId, "runId");
8288
8516
  const filters = {};
8289
8517
  if (userId) filters.user_id = userId;
8290
8518
  if (agentId) filters.agent_id = agentId;
@@ -8641,6 +8869,7 @@ export {
8641
8869
  LangchainEmbedder,
8642
8870
  LangchainLLM,
8643
8871
  LangchainVectorStore,
8872
+ LiteLLM,
8644
8873
  Memory,
8645
8874
  MemoryConfigSchema,
8646
8875
  MemoryVectorStore,