@agentmemory/agentmemory 0.9.11 → 0.9.13
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/.env.example +167 -0
- package/README.md +65 -1
- package/dist/.env.example +167 -0
- package/dist/cli.mjs +50 -4
- package/dist/cli.mjs.map +1 -1
- package/dist/image-refs-HVu22rfu.mjs +116 -0
- package/dist/image-refs-HVu22rfu.mjs.map +1 -0
- package/dist/image-store-BfN1vDbj.mjs +3 -0
- package/dist/index.mjs +214 -9
- package/dist/index.mjs.map +1 -1
- package/dist/{src-IbjZ5iJi.mjs → src-Ca9oX6Hq.mjs} +224 -125
- package/dist/src-Ca9oX6Hq.mjs.map +1 -0
- package/dist/{standalone-awLAlipf.mjs → standalone-BpbiNqr9.mjs} +2 -2
- package/dist/{standalone-awLAlipf.mjs.map → standalone-BpbiNqr9.mjs.map} +1 -1
- package/dist/standalone.mjs +1 -1
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-CzSNN8Ca.mjs → tools-registry-D5l632PP.mjs} +3 -3
- package/dist/{tools-registry-CzSNN8Ca.mjs.map → tools-registry-D5l632PP.mjs.map} +1 -1
- package/dist/viewer/index.html +52 -25
- package/package.json +8 -4
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/dist/image-refs-D4M1sJAz.mjs +0 -3
- package/dist/image-store-DR4g1FAW.mjs +0 -3
- package/dist/src-IbjZ5iJi.mjs.map +0 -1
|
@@ -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 {
|
|
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-D5l632PP.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,
|
|
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
|
|
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:
|
|
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
|
-
|
|
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();
|
|
@@ -2340,13 +2364,55 @@ async function deleteAccessLog(kv, memoryId) {
|
|
|
2340
2364
|
//#endregion
|
|
2341
2365
|
//#region src/functions/search.ts
|
|
2342
2366
|
let index = null;
|
|
2367
|
+
let vectorIndex = null;
|
|
2368
|
+
let currentEmbeddingProvider = null;
|
|
2343
2369
|
function getSearchIndex() {
|
|
2344
2370
|
if (!index) index = new SearchIndex();
|
|
2345
2371
|
return index;
|
|
2346
2372
|
}
|
|
2373
|
+
function setVectorIndex(idx) {
|
|
2374
|
+
vectorIndex = idx;
|
|
2375
|
+
}
|
|
2376
|
+
function setEmbeddingProvider(provider) {
|
|
2377
|
+
currentEmbeddingProvider = provider;
|
|
2378
|
+
}
|
|
2379
|
+
const EMBED_MAX_CHARS = 16e3;
|
|
2380
|
+
function clipEmbedInput(text) {
|
|
2381
|
+
if (text.length <= EMBED_MAX_CHARS) return text;
|
|
2382
|
+
return text.slice(0, EMBED_MAX_CHARS);
|
|
2383
|
+
}
|
|
2384
|
+
async function vectorIndexAddGuarded(id, sessionId, text, context) {
|
|
2385
|
+
const vi = vectorIndex;
|
|
2386
|
+
const ep = currentEmbeddingProvider;
|
|
2387
|
+
if (!vi || !ep) return false;
|
|
2388
|
+
try {
|
|
2389
|
+
const embedding = await ep.embed(clipEmbedInput(text));
|
|
2390
|
+
if (embedding.length !== ep.dimensions) {
|
|
2391
|
+
logger.warn("vector-index add: dimension mismatch — skipping", {
|
|
2392
|
+
kind: context.kind,
|
|
2393
|
+
id: context.logId,
|
|
2394
|
+
provider: ep.name,
|
|
2395
|
+
expected: ep.dimensions,
|
|
2396
|
+
received: embedding.length
|
|
2397
|
+
});
|
|
2398
|
+
return false;
|
|
2399
|
+
}
|
|
2400
|
+
vi.add(id, sessionId, embedding);
|
|
2401
|
+
return true;
|
|
2402
|
+
} catch (err) {
|
|
2403
|
+
logger.warn("vector-index add: embed failed — skipping", {
|
|
2404
|
+
kind: context.kind,
|
|
2405
|
+
id: context.logId,
|
|
2406
|
+
provider: ep.name,
|
|
2407
|
+
error: err instanceof Error ? err.message : String(err)
|
|
2408
|
+
});
|
|
2409
|
+
return false;
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2347
2412
|
async function rebuildIndex(kv) {
|
|
2348
2413
|
const idx = getSearchIndex();
|
|
2349
2414
|
idx.clear();
|
|
2415
|
+
vectorIndex?.clear();
|
|
2350
2416
|
let count = 0;
|
|
2351
2417
|
try {
|
|
2352
2418
|
const memories = await kv.list(KV.memories);
|
|
@@ -2354,6 +2420,10 @@ async function rebuildIndex(kv) {
|
|
|
2354
2420
|
if (memory.isLatest === false) continue;
|
|
2355
2421
|
if (!memory.title || !memory.content) continue;
|
|
2356
2422
|
idx.add(memoryToObservation(memory));
|
|
2423
|
+
await vectorIndexAddGuarded(memory.id, memory.sessionIds[0] ?? "memory", memory.title + " " + memory.content, {
|
|
2424
|
+
kind: "memory",
|
|
2425
|
+
logId: memory.id
|
|
2426
|
+
});
|
|
2357
2427
|
count++;
|
|
2358
2428
|
}
|
|
2359
2429
|
} catch (err) {
|
|
@@ -2378,6 +2448,10 @@ async function rebuildIndex(kv) {
|
|
|
2378
2448
|
if (failedSessions.length > 0) logger.warn("rebuildIndex: failed to load observations for sessions", { failedSessions });
|
|
2379
2449
|
for (const observations of obsPerSession) for (const obs of observations) if (obs.title && obs.narrative) {
|
|
2380
2450
|
idx.add(obs);
|
|
2451
|
+
await vectorIndexAddGuarded(obs.id, obs.sessionId, obs.title + " " + obs.narrative, {
|
|
2452
|
+
kind: "observation",
|
|
2453
|
+
logId: obs.id
|
|
2454
|
+
});
|
|
2381
2455
|
count++;
|
|
2382
2456
|
}
|
|
2383
2457
|
return count;
|
|
@@ -2600,10 +2674,10 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
|
|
|
2600
2674
|
};
|
|
2601
2675
|
}
|
|
2602
2676
|
if (pendingImageData && (pendingImageData.startsWith("data:image/") || pendingImageData.startsWith("iVBORw0KGgo") || pendingImageData.startsWith("/9j/"))) {
|
|
2603
|
-
const { saveImageToDisk } = await import("./image-store-
|
|
2677
|
+
const { saveImageToDisk } = await import("./image-store-BfN1vDbj.mjs");
|
|
2604
2678
|
const { filePath, bytesWritten } = await saveImageToDisk(pendingImageData);
|
|
2605
2679
|
raw.imageData = filePath;
|
|
2606
|
-
const { incrementImageRef } = await import("./image-refs-
|
|
2680
|
+
const { incrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
|
|
2607
2681
|
await incrementImageRef(kv, filePath);
|
|
2608
2682
|
sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: bytesWritten });
|
|
2609
2683
|
if (process.env["AGENTMEMORY_IMAGE_EMBEDDINGS"] === "true") sdk.triggerVoid("mem::vision-embed", {
|
|
@@ -2616,7 +2690,7 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
|
|
|
2616
2690
|
await kv.set(KV.observations(payload.sessionId), obsId, raw);
|
|
2617
2691
|
} catch (error) {
|
|
2618
2692
|
if (raw.imageData) {
|
|
2619
|
-
const { deleteImage } = await import("./image-store-
|
|
2693
|
+
const { deleteImage } = await import("./image-store-BfN1vDbj.mjs");
|
|
2620
2694
|
const { deletedBytes } = await deleteImage(raw.imageData);
|
|
2621
2695
|
if (deletedBytes > 0) sdk.triggerVoid("mem::disk-size-delta", { deltaBytes: -deletedBytes });
|
|
2622
2696
|
}
|
|
@@ -2684,6 +2758,10 @@ function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
|
|
|
2684
2758
|
const synthetic = buildSyntheticCompression(raw);
|
|
2685
2759
|
await kv.set(KV.observations(payload.sessionId), obsId, synthetic);
|
|
2686
2760
|
getSearchIndex().add(synthetic);
|
|
2761
|
+
await vectorIndexAddGuarded(synthetic.id, synthetic.sessionId, synthetic.title + " " + (synthetic.narrative || ""), {
|
|
2762
|
+
kind: "synthetic",
|
|
2763
|
+
logId: synthetic.id
|
|
2764
|
+
});
|
|
2687
2765
|
await sdk.trigger({
|
|
2688
2766
|
function_id: "stream::set",
|
|
2689
2767
|
payload: {
|
|
@@ -3821,7 +3899,20 @@ function registerCompressFunction(sdk, kv, provider, metricsStore) {
|
|
|
3821
3899
|
...data.raw.imageData ? { imageRef: data.raw.imageData } : {}
|
|
3822
3900
|
};
|
|
3823
3901
|
await kv.set(KV.observations(data.sessionId), data.observationId, compressed);
|
|
3824
|
-
|
|
3902
|
+
try {
|
|
3903
|
+
getSearchIndex().add(compressed);
|
|
3904
|
+
} catch (err) {
|
|
3905
|
+
logger.warn("Failed to index compressed observation into BM25", {
|
|
3906
|
+
obsId: compressed.id,
|
|
3907
|
+
sessionId: compressed.sessionId,
|
|
3908
|
+
title: compressed.title,
|
|
3909
|
+
error: err instanceof Error ? err.message : String(err)
|
|
3910
|
+
});
|
|
3911
|
+
}
|
|
3912
|
+
await vectorIndexAddGuarded(compressed.id, compressed.sessionId, compressed.title + " " + (compressed.narrative || ""), {
|
|
3913
|
+
kind: "observation",
|
|
3914
|
+
logId: compressed.id
|
|
3915
|
+
});
|
|
3825
3916
|
const streamResults = await Promise.allSettled([sdk.trigger({
|
|
3826
3917
|
function_id: "stream::set",
|
|
3827
3918
|
payload: {
|
|
@@ -4661,6 +4752,10 @@ function registerRememberFunction(sdk, kv) {
|
|
|
4661
4752
|
error: err instanceof Error ? err.message : String(err)
|
|
4662
4753
|
});
|
|
4663
4754
|
}
|
|
4755
|
+
await vectorIndexAddGuarded(memory.id, memory.sessionIds[0] ?? "memory", memory.title + " " + memory.content, {
|
|
4756
|
+
kind: "memory",
|
|
4757
|
+
logId: memory.id
|
|
4758
|
+
});
|
|
4664
4759
|
if (supersededId) await sdk.trigger({
|
|
4665
4760
|
function_id: "mem::cascade-update",
|
|
4666
4761
|
payload: { supersededMemoryId: supersededId },
|
|
@@ -4681,7 +4776,7 @@ function registerRememberFunction(sdk, kv) {
|
|
|
4681
4776
|
const deletedMemoryIds = [];
|
|
4682
4777
|
const deletedObservationIds = [];
|
|
4683
4778
|
let deletedSession = false;
|
|
4684
|
-
const { decrementImageRef } = await import("./image-refs-
|
|
4779
|
+
const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
|
|
4685
4780
|
if (data.memoryId) {
|
|
4686
4781
|
const mem = await kv.get(KV.memories, data.memoryId);
|
|
4687
4782
|
await kv.delete(KV.memories, data.memoryId);
|
|
@@ -4740,7 +4835,7 @@ const DEFAULTS$1 = {
|
|
|
4740
4835
|
function registerEvictFunction(sdk, kv) {
|
|
4741
4836
|
sdk.registerFunction("mem::evict", async (data) => {
|
|
4742
4837
|
const dryRun = data?.dryRun ?? false;
|
|
4743
|
-
const { decrementImageRef } = await import("./image-refs-
|
|
4838
|
+
const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
|
|
4744
4839
|
const configOverride = await kv.get(KV.config, "eviction").catch(() => null);
|
|
4745
4840
|
const cfg = {
|
|
4746
4841
|
...DEFAULTS$1,
|
|
@@ -5343,7 +5438,7 @@ function registerAutoForgetFunction(sdk, kv) {
|
|
|
5343
5438
|
sdk.registerFunction("mem::auto-forget", async (data) => {
|
|
5344
5439
|
const dryRun = data?.dryRun ?? false;
|
|
5345
5440
|
const now = Date.now();
|
|
5346
|
-
const { decrementImageRef } = await import("./image-refs-
|
|
5441
|
+
const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
|
|
5347
5442
|
const result = {
|
|
5348
5443
|
ttlExpired: [],
|
|
5349
5444
|
contradictions: [],
|
|
@@ -5583,7 +5678,9 @@ function registerExportImportFunction(sdk, kv) {
|
|
|
5583
5678
|
"0.9.8",
|
|
5584
5679
|
"0.9.9",
|
|
5585
5680
|
"0.9.10",
|
|
5586
|
-
"0.9.11"
|
|
5681
|
+
"0.9.11",
|
|
5682
|
+
"0.9.12",
|
|
5683
|
+
"0.9.13"
|
|
5587
5684
|
]).has(importData.version)) return {
|
|
5588
5685
|
success: false,
|
|
5589
5686
|
error: `Unsupported export version: ${importData.version}`
|
|
@@ -11940,7 +12037,7 @@ function registerRetentionFunctions(sdk, kv) {
|
|
|
11940
12037
|
const threshold = typeof data?.threshold === "number" && Number.isFinite(data.threshold) ? data.threshold : DEFAULT_DECAY.tierThresholds.cold;
|
|
11941
12038
|
const maxEvictRaw = typeof data?.maxEvict === "number" && Number.isInteger(data.maxEvict) ? data.maxEvict : 50;
|
|
11942
12039
|
const maxEvict = Math.min(1e3, Math.max(0, maxEvictRaw));
|
|
11943
|
-
const { decrementImageRef } = await import("./image-refs-
|
|
12040
|
+
const { decrementImageRef } = await import("./image-refs-HVu22rfu.mjs");
|
|
11944
12041
|
const candidates = (await kv.list(KV.retentionScores)).filter((s) => s.score < threshold).sort((a, b) => a.score - b.score).slice(0, maxEvict);
|
|
11945
12042
|
if (data?.dryRun) return {
|
|
11946
12043
|
success: true,
|
|
@@ -18077,6 +18174,8 @@ async function main() {
|
|
|
18077
18174
|
const metricsStore = new MetricsStore(kv);
|
|
18078
18175
|
const dedupMap = new DedupMap();
|
|
18079
18176
|
const vectorIndex = embeddingProvider ? new VectorIndex() : null;
|
|
18177
|
+
setVectorIndex(vectorIndex);
|
|
18178
|
+
setEmbeddingProvider(embeddingProvider);
|
|
18080
18179
|
initMetrics(hasGetMeter(sdk) ? sdk.getMeter.bind(sdk) : void 0);
|
|
18081
18180
|
registerPrivacyFunction(sdk);
|
|
18082
18181
|
registerObserveFunction(sdk, kv, dedupMap, config.maxObservationsPerSession);
|
|
@@ -18293,5 +18392,5 @@ main().catch((err) => {
|
|
|
18293
18392
|
});
|
|
18294
18393
|
|
|
18295
18394
|
//#endregion
|
|
18296
|
-
export {
|
|
18297
|
-
//# sourceMappingURL=src-
|
|
18395
|
+
export { };
|
|
18396
|
+
//# sourceMappingURL=src-Ca9oX6Hq.mjs.map
|