@agentmemory/agentmemory 0.9.12 → 0.9.14

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.
@@ -1,12 +1,14 @@
1
1
  import { a as jaccardSimilarity, i as generateId, n as STREAM, r as fingerprintId, t as KV } from "./cli.mjs";
2
- import { _ as loadSnapshotConfig, a as detectLlmProviderKind, d as isContextInjectionEnabled, f as isGraphExtractionEnabled, g as loadFallbackConfig, h as loadEmbeddingConfig, i as detectEmbeddingProvider, l as isAutoCompressEnabled, m as loadConfig, n as getVisibleTools, o as getConsolidationDecayDays, p as loadClaudeBridgeConfig, r as VERSION, s as getEnvVar, t as getAllTools, u as isConsolidationEnabled, v as loadTeamConfig } from "./tools-registry-NUso4hxA.mjs";
2
+ import { a as isManagedImagePath, getImageRefCount, i as getMaxBytes, n as IMAGES_DIR, r as deleteImage, t as withKeyedLock } from "./image-refs-HVu22rfu.mjs";
3
+ import { _ as loadSnapshotConfig, a as detectLlmProviderKind, d as isContextInjectionEnabled, f as isGraphExtractionEnabled, g as loadFallbackConfig, h as loadEmbeddingConfig, i as detectEmbeddingProvider, l as isAutoCompressEnabled, m as loadConfig, n as getVisibleTools, o as getConsolidationDecayDays, p as loadClaudeBridgeConfig, r as VERSION, s as getEnvVar, t as getAllTools, u as isConsolidationEnabled, v as loadTeamConfig } from "./tools-registry-BDimtXJb.mjs";
4
+ import { createRequire } from "node:module";
3
5
  import { execFile } from "node:child_process";
4
6
  import { constants, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
5
7
  import { basename, dirname, extname, join, resolve, sep } from "node:path";
6
8
  import { fileURLToPath } from "node:url";
7
9
  import { homedir } from "node:os";
8
10
  import { createHash, createHmac, randomBytes, timingSafeEqual } from "node:crypto";
9
- import { lstat, mkdir, open, readFile, readdir, stat, unlink, utimes, writeFile } from "node:fs/promises";
11
+ import { lstat, mkdir, open, readFile, readdir, stat, writeFile } from "node:fs/promises";
10
12
  import { TriggerAction, registerWorker } from "iii-sdk";
11
13
  import Anthropic from "@anthropic-ai/sdk";
12
14
  import { z } from "zod";
@@ -15,113 +17,6 @@ import { lookup } from "node:dns/promises";
15
17
  import { isIP } from "node:net";
16
18
  import { createServer } from "node:http";
17
19
 
18
- //#region src/utils/image-store.ts
19
- const IMAGES_DIR = join(homedir(), ".agentmemory", "images");
20
- const DEFAULT_MAX_BYTES = 500 * 1024 * 1024;
21
- function getMaxBytes() {
22
- return Number(process.env.AGENTMEMORY_IMAGE_STORE_MAX_BYTES) || DEFAULT_MAX_BYTES;
23
- }
24
- function isManagedImagePath(filePath) {
25
- const resolved = resolve(filePath);
26
- const normalizedImagesDir = resolve(IMAGES_DIR);
27
- return resolved.startsWith(normalizedImagesDir + sep) || resolved === normalizedImagesDir;
28
- }
29
- function contentHash(data) {
30
- return createHash("sha256").update(data).digest("hex");
31
- }
32
- async function saveImageToDisk(base64Data) {
33
- if (!base64Data) return {
34
- filePath: "",
35
- bytesWritten: 0
36
- };
37
- if (!existsSync(IMAGES_DIR)) await mkdir(IMAGES_DIR, { recursive: true });
38
- let cleanBase64 = base64Data;
39
- let ext = "png";
40
- if (base64Data.startsWith("data:image/")) {
41
- const commaIdx = base64Data.indexOf(",");
42
- if (commaIdx !== -1) {
43
- const meta = base64Data.substring(0, commaIdx);
44
- if (meta.includes("jpeg") || meta.includes("jpg")) ext = "jpg";
45
- else if (meta.includes("webp")) ext = "webp";
46
- else if (meta.includes("gif")) ext = "gif";
47
- cleanBase64 = base64Data.substring(commaIdx + 1);
48
- }
49
- } else if (base64Data.startsWith("/9j/")) ext = "jpg";
50
- const filePath = join(IMAGES_DIR, `${contentHash(cleanBase64)}.${ext}`);
51
- if (existsSync(filePath)) return {
52
- filePath,
53
- bytesWritten: 0
54
- };
55
- await writeFile(filePath, Buffer.from(cleanBase64, "base64"));
56
- return {
57
- filePath,
58
- bytesWritten: (await stat(filePath)).size
59
- };
60
- }
61
- async function deleteImage(filePath) {
62
- if (!filePath) return { deletedBytes: 0 };
63
- if (!isManagedImagePath(filePath)) return { deletedBytes: 0 };
64
- try {
65
- if (existsSync(filePath)) {
66
- const size = (await stat(filePath)).size;
67
- await unlink(filePath);
68
- return { deletedBytes: size };
69
- }
70
- } catch (err) {
71
- console.error("[agentmemory] Failed to delete image context:", err);
72
- }
73
- return { deletedBytes: 0 };
74
- }
75
- /** Touch an image file to update its mtime (marking it as recently used for LRU eviction) */
76
- async function touchImage(filePath) {
77
- if (!filePath || !isManagedImagePath(filePath)) return;
78
- try {
79
- if (existsSync(filePath)) {
80
- const now = /* @__PURE__ */ new Date();
81
- await utimes(filePath, now, now);
82
- }
83
- } catch (err) {}
84
- }
85
-
86
- //#endregion
87
- //#region src/state/keyed-mutex.ts
88
- const locks = /* @__PURE__ */ new Map();
89
- function withKeyedLock(key, fn) {
90
- const next = (locks.get(key) ?? Promise.resolve()).then(fn, fn);
91
- const cleanup = next.then(() => {}, () => {});
92
- locks.set(key, cleanup);
93
- cleanup.then(() => {
94
- if (locks.get(key) === cleanup) locks.delete(key);
95
- });
96
- return next;
97
- }
98
-
99
- //#endregion
100
- //#region src/functions/image-refs.ts
101
- async function getImageRefCount(kv, filePath) {
102
- const count = await kv.get(KV.imageRefs, filePath);
103
- return count ? Number(count) : 0;
104
- }
105
- async function incrementImageRef(kv, filePath) {
106
- return withKeyedLock(`imgRef:${filePath}`, async () => {
107
- const current = await getImageRefCount(kv, filePath);
108
- await kv.set(KV.imageRefs, filePath, current + 1);
109
- await touchImage(filePath);
110
- });
111
- }
112
- async function decrementImageRef(kv, sdk, filePath) {
113
- return withKeyedLock(`imgRef:${filePath}`, async () => {
114
- const current = await getImageRefCount(kv, filePath);
115
- if (current <= 1) {
116
- await kv.delete(KV.imageEmbeddings, filePath);
117
- await kv.delete(KV.imageRefs, filePath);
118
- const { deletedBytes } = await deleteImage(filePath);
119
- if (deletedBytes > 0) sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: -deletedBytes });
120
- } else await kv.set(KV.imageRefs, filePath, current - 1);
121
- });
122
- }
123
-
124
- //#endregion
125
20
  //#region src/providers/agent-sdk.ts
126
21
  var AgentSDKProvider = class {
127
22
  name = "agent-sdk";
@@ -462,7 +357,8 @@ var FallbackChainProvider = class {
462
357
  //#endregion
463
358
  //#region src/providers/embedding/gemini.ts
464
359
  const BATCH_LIMIT = 100;
465
- const API_BASE = "https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:batchEmbedContent";
360
+ const MODEL = "models/gemini-embedding-001";
361
+ const API_BASE = `https://generativelanguage.googleapis.com/v1beta/${MODEL}:batchEmbedContents`;
466
362
  var GeminiEmbeddingProvider = class {
467
363
  name = "gemini";
468
364
  dimensions = 768;
@@ -483,8 +379,9 @@ var GeminiEmbeddingProvider = class {
483
379
  method: "POST",
484
380
  headers: { "Content-Type": "application/json" },
485
381
  body: JSON.stringify({ requests: chunk.map((t) => ({
486
- model: "models/text-embedding-004",
487
- content: { parts: [{ text: t }] }
382
+ model: MODEL,
383
+ content: { parts: [{ text: t }] },
384
+ outputDimensionality: this.dimensions
488
385
  })) })
489
386
  });
490
387
  if (!response.ok) {
@@ -492,11 +389,26 @@ var GeminiEmbeddingProvider = class {
492
389
  throw new Error(`Gemini embedding failed (${response.status}): ${err}`);
493
390
  }
494
391
  const data = await response.json();
495
- for (const emb of data.embeddings) results.push(new Float32Array(emb.values));
392
+ for (const emb of data.embeddings) results.push(l2Normalize(new Float32Array(emb.values)));
496
393
  }
497
394
  return results;
498
395
  }
499
396
  };
397
+ let zeroNormWarned = false;
398
+ function l2Normalize(vec) {
399
+ let sum = 0;
400
+ for (let i = 0; i < vec.length; i++) sum += vec[i] * vec[i];
401
+ const norm = Math.sqrt(sum);
402
+ if (norm === 0) {
403
+ if (!zeroNormWarned) {
404
+ zeroNormWarned = true;
405
+ process.stderr.write(`[agentmemory] warn: gemini-embedding-001 returned a zero-norm embedding (length=${vec.length}); leaving it un-normalized. Subsequent zero-norm vectors will not be reported.\n`);
406
+ }
407
+ return vec;
408
+ }
409
+ for (let i = 0; i < vec.length; i++) vec[i] = vec[i] / norm;
410
+ return vec;
411
+ }
500
412
 
501
413
  //#endregion
502
414
  //#region src/providers/embedding/openai.ts
@@ -1898,6 +1810,110 @@ function getSynonyms(stemmedTerm) {
1898
1810
  return syns ? [...syns] : [];
1899
1811
  }
1900
1812
 
1813
+ //#endregion
1814
+ //#region src/state/cjk-segmenter.ts
1815
+ const cjkRequire = createRequire(import.meta.url);
1816
+ const CJK_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
1817
+ const KANA_RE = /[\p{Script=Hiragana}\p{Script=Katakana}]/u;
1818
+ const HANGUL_RE = /\p{Script=Hangul}/u;
1819
+ const CJK_RUN_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]+/gu;
1820
+ const HANGUL_BLOCK_RE = /[가-힯]+/g;
1821
+ const hintShown = /* @__PURE__ */ new Set();
1822
+ function hasCjk(text) {
1823
+ return CJK_RE.test(text);
1824
+ }
1825
+ function showHintOnce(key, message) {
1826
+ if (hintShown.has(key)) return;
1827
+ hintShown.add(key);
1828
+ if (typeof process !== "undefined" && process.stderr?.write) process.stderr.write(`agentmemory: ${message}\n`);
1829
+ }
1830
+ let jiebaInstance = null;
1831
+ let jiebaLoaded = false;
1832
+ function getJieba() {
1833
+ if (jiebaLoaded) return jiebaInstance;
1834
+ jiebaLoaded = true;
1835
+ try {
1836
+ const mod = cjkRequire("@node-rs/jieba");
1837
+ try {
1838
+ const dictMod = cjkRequire("@node-rs/jieba/dict");
1839
+ jiebaInstance = mod.Jieba.withDict(dictMod.dict);
1840
+ } catch {
1841
+ jiebaInstance = new mod.Jieba();
1842
+ }
1843
+ return jiebaInstance;
1844
+ } catch {
1845
+ showHintOnce("jieba", "install @node-rs/jieba to improve Chinese search; falling back to whole-string tokenization");
1846
+ return null;
1847
+ }
1848
+ }
1849
+ let jaSegmenterInstance = null;
1850
+ let jaSegmenterLoaded = false;
1851
+ function getJaSegmenter() {
1852
+ if (jaSegmenterLoaded) return jaSegmenterInstance;
1853
+ jaSegmenterLoaded = true;
1854
+ try {
1855
+ jaSegmenterInstance = new (cjkRequire("tiny-segmenter"))();
1856
+ return jaSegmenterInstance;
1857
+ } catch {
1858
+ showHintOnce("tiny-segmenter", "install tiny-segmenter to improve Japanese search; falling back to whole-string tokenization");
1859
+ return null;
1860
+ }
1861
+ }
1862
+ function cleanTokens(tokens) {
1863
+ const out = [];
1864
+ for (const t of tokens) {
1865
+ const trimmed = t.trim();
1866
+ if (trimmed) out.push(trimmed);
1867
+ }
1868
+ return out;
1869
+ }
1870
+ function segmentHan(text) {
1871
+ const j = getJieba();
1872
+ if (!j) return [text];
1873
+ try {
1874
+ return cleanTokens(j.cut(text, true));
1875
+ } catch {
1876
+ return [text];
1877
+ }
1878
+ }
1879
+ function segmentKana(text) {
1880
+ const s = getJaSegmenter();
1881
+ if (!s) return [text];
1882
+ try {
1883
+ return cleanTokens(s.segment(text));
1884
+ } catch {
1885
+ return [text];
1886
+ }
1887
+ }
1888
+ function segmentHangul(text) {
1889
+ const out = [];
1890
+ for (const m of text.matchAll(HANGUL_BLOCK_RE)) if (m[0]) out.push(m[0]);
1891
+ return out;
1892
+ }
1893
+ function segmentCjk(text) {
1894
+ if (!hasCjk(text)) return [text];
1895
+ const out = [];
1896
+ let cursor = 0;
1897
+ for (const m of text.matchAll(CJK_RUN_RE)) {
1898
+ const start = m.index ?? 0;
1899
+ const run = m[0];
1900
+ const end = start + run.length;
1901
+ if (start > cursor) {
1902
+ const piece = text.slice(cursor, start).trim();
1903
+ if (piece) out.push(piece);
1904
+ }
1905
+ if (HANGUL_RE.test(run)) out.push(...segmentHangul(run));
1906
+ else if (KANA_RE.test(run)) out.push(...segmentKana(run));
1907
+ else out.push(...segmentHan(run));
1908
+ cursor = end;
1909
+ }
1910
+ if (cursor < text.length) {
1911
+ const trailing = text.slice(cursor).trim();
1912
+ if (trailing) out.push(trailing);
1913
+ }
1914
+ return out;
1915
+ }
1916
+
1901
1917
  //#endregion
1902
1918
  //#region src/state/search-index.ts
1903
1919
  var SearchIndex = class SearchIndex {
@@ -2054,7 +2070,15 @@ var SearchIndex = class SearchIndex {
2054
2070
  return this.tokenize(parts.join(" ").toLowerCase());
2055
2071
  }
2056
2072
  tokenize(text) {
2057
- return text.replace(/[^\p{L}\p{N}\s/.\\-_]/gu, " ").split(/\s+/).filter((t) => t.length > 1).map((t) => stem(t));
2073
+ const cleaned = text.replace(/[^\p{L}\p{N}\s/.\\-_]/gu, " ");
2074
+ const out = [];
2075
+ for (const raw of cleaned.split(/\s+/)) {
2076
+ if (raw.length < 2) continue;
2077
+ if (hasCjk(raw)) {
2078
+ for (const seg of segmentCjk(raw)) if (seg.length >= 1) out.push(seg);
2079
+ } else out.push(stem(raw));
2080
+ }
2081
+ return out;
2058
2082
  }
2059
2083
  getSortedTerms() {
2060
2084
  if (!this.sortedTerms) this.sortedTerms = Array.from(this.invertedIndex.keys()).sort();
@@ -2650,10 +2674,10 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
2650
2674
  };
2651
2675
  }
2652
2676
  if (pendingImageData && (pendingImageData.startsWith("data:image/") || pendingImageData.startsWith("iVBORw0KGgo") || pendingImageData.startsWith("/9j/"))) {
2653
- const { saveImageToDisk } = await import("./image-store-RY_BkYWK.mjs");
2677
+ const { saveImageToDisk } = await import("./image-store-BfN1vDbj.mjs");
2654
2678
  const { filePath, bytesWritten } = await saveImageToDisk(pendingImageData);
2655
2679
  raw.imageData = filePath;
2656
- const { incrementImageRef } = await import("./image-refs-BkMGNmEs.mjs");
2680
+ const { incrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
2657
2681
  await incrementImageRef(kv, filePath);
2658
2682
  sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: bytesWritten });
2659
2683
  if (process.env["AGENTMEMORY_IMAGE_EMBEDDINGS"] === "true") sdk.triggerVoid("mem::vision-embed", {
@@ -2666,7 +2690,7 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
2666
2690
  await kv.set(KV.observations(payload.sessionId), obsId, raw);
2667
2691
  } catch (error) {
2668
2692
  if (raw.imageData) {
2669
- const { deleteImage } = await import("./image-store-RY_BkYWK.mjs");
2693
+ const { deleteImage } = await import("./image-store-BfN1vDbj.mjs");
2670
2694
  const { deletedBytes } = await deleteImage(raw.imageData);
2671
2695
  if (deletedBytes > 0) sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: -deletedBytes });
2672
2696
  }
@@ -4752,7 +4776,7 @@ function registerRememberFunction(sdk, kv) {
4752
4776
  const deletedMemoryIds = [];
4753
4777
  const deletedObservationIds = [];
4754
4778
  let deletedSession = false;
4755
- const { decrementImageRef } = await import("./image-refs-BkMGNmEs.mjs");
4779
+ const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
4756
4780
  if (data.memoryId) {
4757
4781
  const mem = await kv.get(KV.memories, data.memoryId);
4758
4782
  await kv.delete(KV.memories, data.memoryId);
@@ -4811,7 +4835,7 @@ const DEFAULTS$1 = {
4811
4835
  function registerEvictFunction(sdk, kv) {
4812
4836
  sdk.registerFunction("mem::evict", async (data) => {
4813
4837
  const dryRun = data?.dryRun ?? false;
4814
- const { decrementImageRef } = await import("./image-refs-BkMGNmEs.mjs");
4838
+ const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
4815
4839
  const configOverride = await kv.get(KV.config, "eviction").catch(() => null);
4816
4840
  const cfg = {
4817
4841
  ...DEFAULTS$1,
@@ -5414,7 +5438,7 @@ function registerAutoForgetFunction(sdk, kv) {
5414
5438
  sdk.registerFunction("mem::auto-forget", async (data) => {
5415
5439
  const dryRun = data?.dryRun ?? false;
5416
5440
  const now = Date.now();
5417
- const { decrementImageRef } = await import("./image-refs-BkMGNmEs.mjs");
5441
+ const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
5418
5442
  const result = {
5419
5443
  ttlExpired: [],
5420
5444
  contradictions: [],
@@ -5655,7 +5679,9 @@ function registerExportImportFunction(sdk, kv) {
5655
5679
  "0.9.9",
5656
5680
  "0.9.10",
5657
5681
  "0.9.11",
5658
- "0.9.12"
5682
+ "0.9.12",
5683
+ "0.9.13",
5684
+ "0.9.14"
5659
5685
  ]).has(importData.version)) return {
5660
5686
  success: false,
5661
5687
  error: `Unsupported export version: ${importData.version}`
@@ -12012,7 +12038,7 @@ function registerRetentionFunctions(sdk, kv) {
12012
12038
  const threshold = typeof data?.threshold === "number" && Number.isFinite(data.threshold) ? data.threshold : DEFAULT_DECAY.tierThresholds.cold;
12013
12039
  const maxEvictRaw = typeof data?.maxEvict === "number" && Number.isInteger(data.maxEvict) ? data.maxEvict : 50;
12014
12040
  const maxEvict = Math.min(1e3, Math.max(0, maxEvictRaw));
12015
- const { decrementImageRef } = await import("./image-refs-BkMGNmEs.mjs");
12041
+ const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
12016
12042
  const candidates = (await kv.list(KV.retentionScores)).filter((s) => s.score < threshold).sort((a, b) => a.score - b.score).slice(0, maxEvict);
12017
12043
  if (data?.dryRun) return {
12018
12044
  success: true,
@@ -18367,5 +18393,5 @@ main().catch((err) => {
18367
18393
  });
18368
18394
 
18369
18395
  //#endregion
18370
- export { deleteImage as a, saveImageToDisk as c, IMAGES_DIR as i, touchImage as l, getImageRefCount as n, getMaxBytes as o, incrementImageRef as r, isManagedImagePath as s, decrementImageRef as t };
18371
- //# sourceMappingURL=src-Cqsy23f_.mjs.map
18396
+ export { };
18397
+ //# sourceMappingURL=src-BBI-ah3h.mjs.map