memorix 1.6.1 → 1.6.2
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/CHANGELOG.md +22 -0
- package/TEAM.md +86 -86
- package/dist/cli/index.js +1574 -1063
- package/dist/index.js +588 -107
- package/dist/maintenance-runner.js +565 -84
- package/dist/media-audio-runner.js +565 -84
- package/dist/media-video-runner.js +565 -84
- package/dist/memcode-runtime/CHANGELOG.md +22 -0
- package/dist/sdk.js +621 -111
- package/dist/vector-backfill-runner.js +565 -84
- package/docs/DESIGN_DECISIONS.md +357 -357
- package/docs/PERFORMANCE.md +15 -0
- package/package.json +2 -1
- package/plugins/claude/memorix/.claude-plugin/plugin.json +1 -1
- package/plugins/codebuddy/memorix/.codebuddy-plugin/plugin.json +1 -1
- package/plugins/codex/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/copilot/memorix/plugin.json +1 -1
- package/plugins/gemini/memorix/gemini-extension.json +1 -1
- package/plugins/omp/memorix/package.json +1 -1
- package/plugins/openclaw/memorix/.codex-plugin/plugin.json +1 -1
- package/plugins/pi/memorix/package.json +1 -1
- package/server.json +2 -2
- package/src/audit/index.ts +156 -156
- package/src/cli/commands/background.ts +34 -2
- package/src/cli/commands/formation.ts +48 -48
- package/src/cli/commands/git-hook-install.ts +111 -111
- package/src/cli/commands/handoff.ts +54 -54
- package/src/cli/commands/hooks-status.ts +63 -63
- package/src/cli/commands/ingest.ts +44 -44
- package/src/cli/commands/integrate-shared.ts +15 -15
- package/src/cli/commands/lock.ts +82 -82
- package/src/cli/commands/message.ts +104 -104
- package/src/cli/commands/operator-shared.ts +6 -3
- package/src/cli/commands/poll.ts +58 -58
- package/src/cli/commands/reasoning.ts +118 -118
- package/src/cli/commands/serve-http.ts +4 -0
- package/src/cli/commands/skills.ts +114 -114
- package/src/cli/commands/task.ts +167 -167
- package/src/cli/commands/transfer.ts +47 -47
- package/src/cli/index.ts +406 -406
- package/src/cli/tui/ChatView.tsx +234 -234
- package/src/cli/tui/CommandBar.tsx +312 -312
- package/src/cli/tui/ContextRail.tsx +118 -118
- package/src/cli/tui/HeaderBar.tsx +72 -72
- package/src/cli/tui/LogoBanner.tsx +51 -51
- package/src/cli/tui/index.ts +41 -41
- package/src/cli/version.ts +7 -7
- package/src/cli/workbench.ts +1 -1
- package/src/dashboard/project-classification.ts +64 -64
- package/src/embedding/api-provider.ts +503 -27
- package/src/embedding/provider.ts +20 -3
- package/src/git/hooks-path.ts +85 -85
- package/src/hooks/lifecycle.ts +1 -0
- package/src/hooks/pattern-detector.ts +173 -173
- package/src/hooks/significance-filter.ts +250 -250
- package/src/llm/memory-manager.ts +328 -328
- package/src/llm/quality.ts +248 -248
- package/src/memory/attribution-guard.ts +249 -249
- package/src/memory/disclosure-policy.ts +135 -135
- package/src/memory/entity-extractor.ts +197 -197
- package/src/memory/formation/evaluate.ts +217 -217
- package/src/memory/freshness.ts +122 -122
- package/src/memory/graph.ts +197 -197
- package/src/memory/observations.ts +68 -18
- package/src/memory/refs.ts +94 -94
- package/src/memory/secret-filter.ts +79 -79
- package/src/orchestrate/adapters/claude-stream.ts +192 -192
- package/src/orchestrate/adapters/claude.ts +111 -111
- package/src/orchestrate/adapters/codex-stream.ts +134 -134
- package/src/orchestrate/adapters/codex.ts +41 -41
- package/src/orchestrate/adapters/gemini-stream.ts +166 -166
- package/src/orchestrate/adapters/gemini.ts +42 -42
- package/src/orchestrate/adapters/index.ts +73 -73
- package/src/orchestrate/adapters/opencode-stream.ts +143 -143
- package/src/orchestrate/adapters/opencode.ts +47 -47
- package/src/orchestrate/adapters/types.ts +77 -77
- package/src/orchestrate/capability-router.ts +284 -284
- package/src/orchestrate/cost-tracker.ts +219 -219
- package/src/orchestrate/error-recovery.ts +191 -191
- package/src/orchestrate/evidence.ts +140 -140
- package/src/orchestrate/ledger.ts +110 -110
- package/src/orchestrate/memorix-bridge.ts +343 -343
- package/src/orchestrate/output-budget.ts +80 -80
- package/src/orchestrate/permission.ts +152 -152
- package/src/orchestrate/pipeline-trace.ts +131 -131
- package/src/orchestrate/prompt-builder.ts +155 -155
- package/src/orchestrate/ring-buffer.ts +37 -37
- package/src/orchestrate/task-graph.ts +389 -389
- package/src/project/aliases.ts +374 -374
- package/src/rules/adapters/trae.ts +56 -56
- package/src/rules/syncer.ts +235 -235
- package/src/sdk.ts +12 -8
- package/src/search/query-expansion.ts +52 -52
- package/src/server/formation-timeout.ts +27 -27
- package/src/skills/mini-skills.ts +386 -386
- package/src/store/chat-store.ts +119 -119
- package/src/store/graph-store.ts +249 -249
- package/src/store/mini-skill-store.ts +349 -349
- package/src/store/orama-store.ts +21 -3
- package/src/store/persistence-json.ts +212 -212
- package/src/store/persistence.ts +291 -291
- package/src/store/project-affinity.ts +195 -195
- package/src/team/event-bus.ts +76 -76
- package/src/team/handoff.ts +161 -161
- package/src/team/poll.ts +132 -132
- package/src/workspace/mcp-adapters/codex.ts +191 -191
- package/src/workspace/mcp-adapters/copilot.ts +105 -105
- package/src/workspace/mcp-adapters/cursor.ts +53 -53
- package/src/workspace/mcp-adapters/kiro.ts +64 -64
- package/src/workspace/mcp-adapters/opencode.ts +123 -123
- package/src/workspace/mcp-adapters/trae.ts +134 -134
- package/src/workspace/mcp-adapters/windsurf.ts +91 -91
- package/src/workspace/sanitizer.ts +60 -60
|
@@ -2352,8 +2352,8 @@ async function acquireLock(lockPath) {
|
|
|
2352
2352
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
2353
2353
|
if (code === "EEXIST" || code === "EPERM") {
|
|
2354
2354
|
try {
|
|
2355
|
-
const
|
|
2356
|
-
if (Date.now() -
|
|
2355
|
+
const stat5 = await fs2.stat(lockPath);
|
|
2356
|
+
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
2357
2357
|
await fs2.unlink(lockPath).catch(() => {
|
|
2358
2358
|
});
|
|
2359
2359
|
continue;
|
|
@@ -3464,24 +3464,131 @@ var init_transformers_provider = __esm({
|
|
|
3464
3464
|
// src/embedding/api-provider.ts
|
|
3465
3465
|
var api_provider_exports = {};
|
|
3466
3466
|
__export(api_provider_exports, {
|
|
3467
|
-
APIEmbeddingProvider: () => APIEmbeddingProvider
|
|
3467
|
+
APIEmbeddingProvider: () => APIEmbeddingProvider,
|
|
3468
|
+
convertArrayCacheToJsonl: () => convertArrayCacheToJsonl,
|
|
3469
|
+
ensureDiskCacheLoaded: () => ensureDiskCacheLoaded,
|
|
3470
|
+
getApiEmbeddingCachePayloadBytesForTests: () => getApiEmbeddingCachePayloadBytesForTests,
|
|
3471
|
+
getApiEmbeddingDiskCacheLoadCountForTests: () => getApiEmbeddingDiskCacheLoadCountForTests,
|
|
3472
|
+
getApiEmbeddingJsonlLineCountCallsForTests: () => getApiEmbeddingJsonlLineCountCallsForTests,
|
|
3473
|
+
getApiEmbeddingMaxEntriesForDimensionsForTests: () => getApiEmbeddingMaxEntriesForDimensionsForTests,
|
|
3474
|
+
migrateJsonArrayCacheToJsonl: () => migrateJsonArrayCacheToJsonl,
|
|
3475
|
+
parseCacheJsonInWorker: () => parseCacheJsonInWorker,
|
|
3476
|
+
resetApiEmbeddingCacheForTests: () => resetApiEmbeddingCacheForTests,
|
|
3477
|
+
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
3478
|
+
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
3468
3479
|
});
|
|
3469
3480
|
import { createHash as createHash2 } from "crypto";
|
|
3470
|
-
import {
|
|
3481
|
+
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
3482
|
+
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
3471
3483
|
import { join as join3 } from "path";
|
|
3472
3484
|
import { homedir as homedir7 } from "os";
|
|
3485
|
+
import { createInterface } from "readline";
|
|
3473
3486
|
function cacheDir() {
|
|
3474
3487
|
return process.env.MEMORIX_DATA_DIR || join3(homedir7(), ".memorix", "data");
|
|
3475
3488
|
}
|
|
3476
3489
|
function cacheFile() {
|
|
3477
3490
|
return join3(cacheDir(), ".embedding-api-cache.json");
|
|
3478
3491
|
}
|
|
3492
|
+
function cacheJsonlFile() {
|
|
3493
|
+
return join3(cacheDir(), ".embedding-api-cache.jsonl");
|
|
3494
|
+
}
|
|
3479
3495
|
function dimsCacheFile() {
|
|
3480
3496
|
return join3(cacheDir(), ".embedding-dims-cache.json");
|
|
3481
3497
|
}
|
|
3482
3498
|
function cacheMetaFile() {
|
|
3483
3499
|
return join3(cacheDir(), ".embedding-api-cache-meta.json");
|
|
3484
3500
|
}
|
|
3501
|
+
function cacheStatFile() {
|
|
3502
|
+
return join3(cacheDir(), ".embedding-api-cache-stat.json");
|
|
3503
|
+
}
|
|
3504
|
+
function payloadBytes(vector) {
|
|
3505
|
+
return vector.length * BYTES_PER_DIM;
|
|
3506
|
+
}
|
|
3507
|
+
function maxCachePayloadBytes() {
|
|
3508
|
+
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
3509
|
+
if (raw) {
|
|
3510
|
+
const parsed = Number.parseInt(raw, 10);
|
|
3511
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
3512
|
+
}
|
|
3513
|
+
return MAX_CACHE_PAYLOAD_BYTES;
|
|
3514
|
+
}
|
|
3515
|
+
function maxEntriesForDimensions(dimensions) {
|
|
3516
|
+
const dim = Math.max(1, Math.floor(dimensions));
|
|
3517
|
+
const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
|
|
3518
|
+
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
3519
|
+
}
|
|
3520
|
+
function rememberDimensions(vector) {
|
|
3521
|
+
if (vector.length > 0 && (cacheDimensions === null || vector.length > cacheDimensions)) {
|
|
3522
|
+
cacheDimensions = vector.length;
|
|
3523
|
+
}
|
|
3524
|
+
}
|
|
3525
|
+
function evictOldest() {
|
|
3526
|
+
const firstKey = cache3.keys().next().value;
|
|
3527
|
+
if (firstKey === void 0) return;
|
|
3528
|
+
const old = cache3.get(firstKey);
|
|
3529
|
+
cache3.delete(firstKey);
|
|
3530
|
+
if (old) cachePayloadBytes -= payloadBytes(old);
|
|
3531
|
+
}
|
|
3532
|
+
function evictToFit(incomingBytes, incomingDims) {
|
|
3533
|
+
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
3534
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
|
|
3535
|
+
evictOldest();
|
|
3536
|
+
}
|
|
3537
|
+
}
|
|
3538
|
+
function isNumberArray(value) {
|
|
3539
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
3540
|
+
}
|
|
3541
|
+
function parseCacheRow(raw) {
|
|
3542
|
+
if (Array.isArray(raw)) {
|
|
3543
|
+
const hash4 = raw[0];
|
|
3544
|
+
const vector = raw[1];
|
|
3545
|
+
if (typeof hash4 === "string" && isNumberArray(vector)) {
|
|
3546
|
+
return { hash: hash4, vector };
|
|
3547
|
+
}
|
|
3548
|
+
return null;
|
|
3549
|
+
}
|
|
3550
|
+
if (raw && typeof raw === "object") {
|
|
3551
|
+
const row = raw;
|
|
3552
|
+
if (typeof row.h === "string" && isNumberArray(row.v)) {
|
|
3553
|
+
return { hash: row.h, vector: row.v };
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
return null;
|
|
3557
|
+
}
|
|
3558
|
+
function cacheInsert(hash4, value, dirty) {
|
|
3559
|
+
rememberDimensions(value);
|
|
3560
|
+
const incoming = payloadBytes(value);
|
|
3561
|
+
const existing = cache3.get(hash4);
|
|
3562
|
+
if (existing) {
|
|
3563
|
+
cachePayloadBytes -= payloadBytes(existing);
|
|
3564
|
+
cache3.delete(hash4);
|
|
3565
|
+
}
|
|
3566
|
+
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
3567
|
+
cache3.set(hash4, value);
|
|
3568
|
+
cachePayloadBytes += incoming;
|
|
3569
|
+
if (dirty) diskCacheDirty2 = true;
|
|
3570
|
+
}
|
|
3571
|
+
async function readCacheStat() {
|
|
3572
|
+
try {
|
|
3573
|
+
const data = JSON.parse(await readFile2(cacheStatFile(), "utf-8"));
|
|
3574
|
+
if (typeof data.entryCount === "number" && Number.isFinite(data.entryCount) && data.entryCount >= 0) {
|
|
3575
|
+
return {
|
|
3576
|
+
version: 1,
|
|
3577
|
+
entryCount: Math.floor(data.entryCount),
|
|
3578
|
+
dimensions: isValidDimension(data.dimensions) ? data.dimensions : null
|
|
3579
|
+
};
|
|
3580
|
+
}
|
|
3581
|
+
} catch {
|
|
3582
|
+
}
|
|
3583
|
+
return null;
|
|
3584
|
+
}
|
|
3585
|
+
async function writeCacheStat(stat5) {
|
|
3586
|
+
try {
|
|
3587
|
+
await mkdir2(cacheDir(), { recursive: true });
|
|
3588
|
+
await writeFile2(cacheStatFile(), JSON.stringify(stat5));
|
|
3589
|
+
} catch {
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3485
3592
|
function normalizeText(text2) {
|
|
3486
3593
|
return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
|
|
3487
3594
|
}
|
|
@@ -3567,29 +3674,300 @@ function toProviderInput(input, baseUrl) {
|
|
|
3567
3674
|
}
|
|
3568
3675
|
return { type: input.modality, url: input.url };
|
|
3569
3676
|
}
|
|
3677
|
+
function parseCacheJsonInWorker(filePath) {
|
|
3678
|
+
return new Promise((resolve, reject) => {
|
|
3679
|
+
void import("worker_threads").then(({ Worker }) => {
|
|
3680
|
+
const worker = new Worker(
|
|
3681
|
+
`
|
|
3682
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
3683
|
+
const { readFileSync } = require('node:fs');
|
|
3684
|
+
try {
|
|
3685
|
+
const raw = readFileSync(workerData.filePath, 'utf8');
|
|
3686
|
+
parentPort.postMessage({ ok: true, entries: JSON.parse(raw) });
|
|
3687
|
+
} catch (err) {
|
|
3688
|
+
parentPort.postMessage({
|
|
3689
|
+
ok: false,
|
|
3690
|
+
error: err instanceof Error ? err.message : String(err),
|
|
3691
|
+
});
|
|
3692
|
+
}
|
|
3693
|
+
`,
|
|
3694
|
+
{ eval: true, workerData: { filePath } }
|
|
3695
|
+
);
|
|
3696
|
+
worker.once("message", (msg) => {
|
|
3697
|
+
void worker.terminate();
|
|
3698
|
+
if (msg?.ok && Array.isArray(msg.entries)) {
|
|
3699
|
+
resolve(msg.entries);
|
|
3700
|
+
return;
|
|
3701
|
+
}
|
|
3702
|
+
reject(new Error(msg?.error || "embedding cache worker parse failed"));
|
|
3703
|
+
});
|
|
3704
|
+
worker.once("error", reject);
|
|
3705
|
+
}).catch(reject);
|
|
3706
|
+
});
|
|
3707
|
+
}
|
|
3708
|
+
function findJsonValueEnd(source) {
|
|
3709
|
+
let i2 = 0;
|
|
3710
|
+
while (i2 < source.length && /\s/.test(source[i2])) i2 += 1;
|
|
3711
|
+
if (i2 >= source.length) return -1;
|
|
3712
|
+
const start = source[i2];
|
|
3713
|
+
if (start === '"') {
|
|
3714
|
+
i2 += 1;
|
|
3715
|
+
while (i2 < source.length) {
|
|
3716
|
+
if (source[i2] === "\\") {
|
|
3717
|
+
i2 += 2;
|
|
3718
|
+
continue;
|
|
3719
|
+
}
|
|
3720
|
+
if (source[i2] === '"') return i2 + 1;
|
|
3721
|
+
i2 += 1;
|
|
3722
|
+
}
|
|
3723
|
+
return -1;
|
|
3724
|
+
}
|
|
3725
|
+
if (start === "{" || start === "[") {
|
|
3726
|
+
const close = start === "{" ? "}" : "]";
|
|
3727
|
+
let depth = 0;
|
|
3728
|
+
let inString = false;
|
|
3729
|
+
for (; i2 < source.length; i2 += 1) {
|
|
3730
|
+
const ch = source[i2];
|
|
3731
|
+
if (inString) {
|
|
3732
|
+
if (ch === "\\") {
|
|
3733
|
+
i2 += 1;
|
|
3734
|
+
continue;
|
|
3735
|
+
}
|
|
3736
|
+
if (ch === '"') inString = false;
|
|
3737
|
+
continue;
|
|
3738
|
+
}
|
|
3739
|
+
if (ch === '"') {
|
|
3740
|
+
inString = true;
|
|
3741
|
+
continue;
|
|
3742
|
+
}
|
|
3743
|
+
if (ch === start) depth += 1;
|
|
3744
|
+
else if (ch === close) {
|
|
3745
|
+
depth -= 1;
|
|
3746
|
+
if (depth === 0) return i2 + 1;
|
|
3747
|
+
}
|
|
3748
|
+
}
|
|
3749
|
+
return -1;
|
|
3750
|
+
}
|
|
3751
|
+
const rest = source.slice(i2);
|
|
3752
|
+
const match2 = rest.match(/^(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/);
|
|
3753
|
+
return match2 ? i2 + match2[0].length : -1;
|
|
3754
|
+
}
|
|
3755
|
+
async function streamJsonArrayToJsonl(filePath, tmpPath) {
|
|
3756
|
+
const input = createReadStream(filePath, { encoding: "utf8" });
|
|
3757
|
+
const out = createWriteStream(tmpPath);
|
|
3758
|
+
let buf = "";
|
|
3759
|
+
let started = false;
|
|
3760
|
+
let count2 = 0;
|
|
3761
|
+
const writeLine = async (line) => {
|
|
3762
|
+
if (!out.write(line)) {
|
|
3763
|
+
await new Promise((resolve, reject) => {
|
|
3764
|
+
out.once("drain", resolve);
|
|
3765
|
+
out.once("error", reject);
|
|
3766
|
+
});
|
|
3767
|
+
}
|
|
3768
|
+
};
|
|
3769
|
+
try {
|
|
3770
|
+
for await (const chunk of input) {
|
|
3771
|
+
buf += chunk;
|
|
3772
|
+
if (!started) {
|
|
3773
|
+
const idx = buf.search(/\S/);
|
|
3774
|
+
if (idx < 0) continue;
|
|
3775
|
+
if (buf[idx] !== "[") throw new Error("embedding cache is not a JSON array");
|
|
3776
|
+
buf = buf.slice(idx + 1);
|
|
3777
|
+
started = true;
|
|
3778
|
+
}
|
|
3779
|
+
while (true) {
|
|
3780
|
+
buf = buf.replace(/^\s*,?\s*/, "");
|
|
3781
|
+
if (!buf) break;
|
|
3782
|
+
if (buf[0] === "]") {
|
|
3783
|
+
buf = "";
|
|
3784
|
+
break;
|
|
3785
|
+
}
|
|
3786
|
+
const end = findJsonValueEnd(buf);
|
|
3787
|
+
if (end < 0) break;
|
|
3788
|
+
const value = JSON.parse(buf.slice(0, end));
|
|
3789
|
+
buf = buf.slice(end);
|
|
3790
|
+
const row = parseCacheRow(value);
|
|
3791
|
+
if (row) {
|
|
3792
|
+
await writeLine(`${JSON.stringify({ h: row.hash, v: row.vector })}
|
|
3793
|
+
`);
|
|
3794
|
+
count2 += 1;
|
|
3795
|
+
if (count2 % 50 === 0) {
|
|
3796
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
3797
|
+
}
|
|
3798
|
+
}
|
|
3799
|
+
}
|
|
3800
|
+
if (buf.length > MAX_MIGRATION_VALUE_BYTES) {
|
|
3801
|
+
throw new Error("embedding cache entry too large to migrate safely");
|
|
3802
|
+
}
|
|
3803
|
+
}
|
|
3804
|
+
} finally {
|
|
3805
|
+
await new Promise((resolve, reject) => {
|
|
3806
|
+
out.end(() => resolve());
|
|
3807
|
+
out.once("error", reject);
|
|
3808
|
+
});
|
|
3809
|
+
}
|
|
3810
|
+
return count2;
|
|
3811
|
+
}
|
|
3812
|
+
async function migrateJsonArrayCacheToJsonl(filePath, jsonlPath) {
|
|
3813
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
3814
|
+
try {
|
|
3815
|
+
const count2 = await streamJsonArrayToJsonl(filePath, tmpPath);
|
|
3816
|
+
await rename(tmpPath, jsonlPath);
|
|
3817
|
+
diskCacheEntryCount = count2;
|
|
3818
|
+
await writeCacheStat({
|
|
3819
|
+
version: 1,
|
|
3820
|
+
entryCount: count2,
|
|
3821
|
+
dimensions: cacheDimensions
|
|
3822
|
+
});
|
|
3823
|
+
return count2;
|
|
3824
|
+
} catch (err) {
|
|
3825
|
+
await unlink(tmpPath).catch(() => void 0);
|
|
3826
|
+
throw err;
|
|
3827
|
+
}
|
|
3828
|
+
}
|
|
3829
|
+
function convertArrayCacheToJsonl(filePath, jsonlPath) {
|
|
3830
|
+
return migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
3831
|
+
}
|
|
3832
|
+
async function loadCacheJsonl(filePath) {
|
|
3833
|
+
const rl = createInterface({
|
|
3834
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
3835
|
+
crlfDelay: Infinity
|
|
3836
|
+
});
|
|
3837
|
+
let loaded = 0;
|
|
3838
|
+
let onDiskCount = 0;
|
|
3839
|
+
for await (const line of rl) {
|
|
3840
|
+
const trimmed = line.trim();
|
|
3841
|
+
if (!trimmed) continue;
|
|
3842
|
+
try {
|
|
3843
|
+
const row = parseCacheRow(JSON.parse(trimmed));
|
|
3844
|
+
if (!row) continue;
|
|
3845
|
+
onDiskCount += 1;
|
|
3846
|
+
cacheInsert(row.hash, row.vector, false);
|
|
3847
|
+
loaded = cache3.size;
|
|
3848
|
+
} catch {
|
|
3849
|
+
}
|
|
3850
|
+
if (onDiskCount % 250 === 0) {
|
|
3851
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
3852
|
+
}
|
|
3853
|
+
}
|
|
3854
|
+
diskCacheEntryCount = onDiskCount;
|
|
3855
|
+
await writeCacheStat({
|
|
3856
|
+
version: 1,
|
|
3857
|
+
entryCount: onDiskCount,
|
|
3858
|
+
dimensions: cacheDimensions
|
|
3859
|
+
});
|
|
3860
|
+
return loaded;
|
|
3861
|
+
}
|
|
3862
|
+
async function countJsonlLines(filePath) {
|
|
3863
|
+
jsonlLineCountCalls += 1;
|
|
3864
|
+
try {
|
|
3865
|
+
const rl = createInterface({
|
|
3866
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
3867
|
+
crlfDelay: Infinity
|
|
3868
|
+
});
|
|
3869
|
+
let count2 = 0;
|
|
3870
|
+
for await (const line of rl) {
|
|
3871
|
+
if (line.trim()) count2 += 1;
|
|
3872
|
+
}
|
|
3873
|
+
return count2;
|
|
3874
|
+
} catch {
|
|
3875
|
+
return 0;
|
|
3876
|
+
}
|
|
3877
|
+
}
|
|
3878
|
+
async function resolveOnDiskCount(jsonlPath) {
|
|
3879
|
+
if (diskCacheEntryCount > 0) return diskCacheEntryCount;
|
|
3880
|
+
const sidecar = await readCacheStat();
|
|
3881
|
+
if (sidecar) {
|
|
3882
|
+
diskCacheEntryCount = sidecar.entryCount;
|
|
3883
|
+
if (sidecar.dimensions && cacheDimensions === null) cacheDimensions = sidecar.dimensions;
|
|
3884
|
+
return sidecar.entryCount;
|
|
3885
|
+
}
|
|
3886
|
+
try {
|
|
3887
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
3888
|
+
} catch {
|
|
3889
|
+
return 0;
|
|
3890
|
+
}
|
|
3891
|
+
const counted = await countJsonlLines(jsonlPath);
|
|
3892
|
+
diskCacheEntryCount = counted;
|
|
3893
|
+
await writeCacheStat({
|
|
3894
|
+
version: 1,
|
|
3895
|
+
entryCount: counted,
|
|
3896
|
+
dimensions: cacheDimensions
|
|
3897
|
+
});
|
|
3898
|
+
return counted;
|
|
3899
|
+
}
|
|
3570
3900
|
async function loadDiskCache2() {
|
|
3571
|
-
if (diskCacheLoaded) return;
|
|
3901
|
+
if (diskCacheLoaded) return cache3.size;
|
|
3902
|
+
let loaded = 0;
|
|
3572
3903
|
try {
|
|
3573
|
-
const
|
|
3574
|
-
|
|
3575
|
-
|
|
3576
|
-
|
|
3904
|
+
const jsonlPath = cacheJsonlFile();
|
|
3905
|
+
let hasJsonl = false;
|
|
3906
|
+
try {
|
|
3907
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
3908
|
+
hasJsonl = true;
|
|
3909
|
+
} catch {
|
|
3910
|
+
hasJsonl = false;
|
|
3911
|
+
}
|
|
3912
|
+
if (hasJsonl) {
|
|
3913
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
3914
|
+
} else {
|
|
3915
|
+
const filePath = cacheFile();
|
|
3916
|
+
await stat(filePath);
|
|
3917
|
+
await migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
3918
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
3919
|
+
}
|
|
3920
|
+
diskCacheLoadCount += 1;
|
|
3921
|
+
console.error(`[memorix] Loaded ${loaded} cached API embeddings from disk`);
|
|
3577
3922
|
} catch {
|
|
3578
3923
|
}
|
|
3579
3924
|
diskCacheLoaded = true;
|
|
3925
|
+
return loaded;
|
|
3580
3926
|
}
|
|
3581
3927
|
function startDiskCacheLoad() {
|
|
3582
3928
|
if (diskCacheLoaded || diskCacheLoadPromise) return;
|
|
3583
|
-
diskCacheLoadPromise = loadDiskCache2().catch(() => {
|
|
3929
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
3584
3930
|
});
|
|
3585
3931
|
}
|
|
3586
3932
|
async function ensureDiskCacheLoaded() {
|
|
3587
|
-
if (diskCacheLoaded) return;
|
|
3588
|
-
if (diskCacheLoadPromise) {
|
|
3589
|
-
|
|
3590
|
-
|
|
3591
|
-
}
|
|
3592
|
-
await
|
|
3933
|
+
if (diskCacheLoaded) return cache3.size;
|
|
3934
|
+
if (!diskCacheLoadPromise) {
|
|
3935
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
3936
|
+
});
|
|
3937
|
+
}
|
|
3938
|
+
await diskCacheLoadPromise;
|
|
3939
|
+
return cache3.size;
|
|
3940
|
+
}
|
|
3941
|
+
function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
3942
|
+
return diskCacheLoadCount;
|
|
3943
|
+
}
|
|
3944
|
+
function resetApiEmbeddingCacheForTests() {
|
|
3945
|
+
cache3.clear();
|
|
3946
|
+
cachePayloadBytes = 0;
|
|
3947
|
+
cacheDimensions = null;
|
|
3948
|
+
diskCacheEntryCount = 0;
|
|
3949
|
+
diskCacheLoaded = false;
|
|
3950
|
+
diskCacheLoadPromise = null;
|
|
3951
|
+
diskCacheLoadCount = 0;
|
|
3952
|
+
diskCacheDirty2 = false;
|
|
3953
|
+
jsonlLineCountCalls = 0;
|
|
3954
|
+
}
|
|
3955
|
+
function seedApiEmbeddingCacheForTests(entries) {
|
|
3956
|
+
cache3.clear();
|
|
3957
|
+
cachePayloadBytes = 0;
|
|
3958
|
+
cacheDimensions = null;
|
|
3959
|
+
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
3960
|
+
diskCacheLoaded = true;
|
|
3961
|
+
diskCacheDirty2 = true;
|
|
3962
|
+
}
|
|
3963
|
+
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
3964
|
+
return cachePayloadBytes;
|
|
3965
|
+
}
|
|
3966
|
+
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
3967
|
+
return jsonlLineCountCalls;
|
|
3968
|
+
}
|
|
3969
|
+
function getApiEmbeddingMaxEntriesForDimensionsForTests(dimensions) {
|
|
3970
|
+
return maxEntriesForDimensions(dimensions);
|
|
3593
3971
|
}
|
|
3594
3972
|
function dimsCacheKey(config) {
|
|
3595
3973
|
return [
|
|
@@ -3705,8 +4083,46 @@ async function saveDiskCacheNow() {
|
|
|
3705
4083
|
if (!diskCacheDirty2) return;
|
|
3706
4084
|
try {
|
|
3707
4085
|
await mkdir2(cacheDir(), { recursive: true });
|
|
3708
|
-
const
|
|
3709
|
-
await
|
|
4086
|
+
const jsonlPath = cacheJsonlFile();
|
|
4087
|
+
const existing = await resolveOnDiskCount(jsonlPath);
|
|
4088
|
+
if (existing > 0 && cache3.size < Math.ceil(existing * 0.5)) {
|
|
4089
|
+
console.error(
|
|
4090
|
+
`[memorix] Refusing to overwrite embedding cache (${existing} on disk vs ${cache3.size} in memory)`
|
|
4091
|
+
);
|
|
4092
|
+
diskCacheDirty2 = false;
|
|
4093
|
+
return;
|
|
4094
|
+
}
|
|
4095
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
4096
|
+
await new Promise((resolve, reject) => {
|
|
4097
|
+
const out = createWriteStream(tmpPath);
|
|
4098
|
+
const entries = cache3.entries();
|
|
4099
|
+
const writeBatch = () => {
|
|
4100
|
+
for (let i2 = 0; i2 < 50; i2++) {
|
|
4101
|
+
const next = entries.next();
|
|
4102
|
+
if (next.done) {
|
|
4103
|
+
out.end();
|
|
4104
|
+
return;
|
|
4105
|
+
}
|
|
4106
|
+
const [hash4, vector] = next.value;
|
|
4107
|
+
if (!out.write(`${JSON.stringify({ h: hash4, v: vector })}
|
|
4108
|
+
`)) {
|
|
4109
|
+
out.once("drain", writeBatch);
|
|
4110
|
+
return;
|
|
4111
|
+
}
|
|
4112
|
+
}
|
|
4113
|
+
setImmediate(writeBatch);
|
|
4114
|
+
};
|
|
4115
|
+
out.on("finish", resolve);
|
|
4116
|
+
out.on("error", reject);
|
|
4117
|
+
writeBatch();
|
|
4118
|
+
});
|
|
4119
|
+
await rename(tmpPath, jsonlPath);
|
|
4120
|
+
diskCacheEntryCount = cache3.size;
|
|
4121
|
+
await writeCacheStat({
|
|
4122
|
+
version: 1,
|
|
4123
|
+
entryCount: cache3.size,
|
|
4124
|
+
dimensions: cacheDimensions
|
|
4125
|
+
});
|
|
3710
4126
|
diskCacheDirty2 = false;
|
|
3711
4127
|
} catch {
|
|
3712
4128
|
}
|
|
@@ -3720,12 +4136,7 @@ function scheduleDiskSave() {
|
|
|
3720
4136
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
3721
4137
|
}
|
|
3722
4138
|
function cacheSet(hash4, value) {
|
|
3723
|
-
|
|
3724
|
-
const firstKey = cache3.keys().next().value;
|
|
3725
|
-
if (firstKey !== void 0) cache3.delete(firstKey);
|
|
3726
|
-
}
|
|
3727
|
-
cache3.set(hash4, value);
|
|
3728
|
-
diskCacheDirty2 = true;
|
|
4139
|
+
cacheInsert(hash4, value, true);
|
|
3729
4140
|
}
|
|
3730
4141
|
function resolveEnvEmbeddingApiKey() {
|
|
3731
4142
|
return process.env.MEMORIX_EMBEDDING_API_KEY;
|
|
@@ -3844,18 +4255,27 @@ async function waitForRetry(waitMs, signal) {
|
|
|
3844
4255
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
3845
4256
|
});
|
|
3846
4257
|
}
|
|
3847
|
-
var cache3,
|
|
4258
|
+
var cache3, MAX_CACHE_ENTRIES, MAX_CACHE_PAYLOAD_BYTES, BYTES_PER_DIM, DEFAULT_ASSUMED_DIMENSIONS, MAX_MIGRATION_VALUE_BYTES, cachePayloadBytes, cacheDimensions, diskCacheEntryCount, diskCacheDirty2, diskSaveTimer, diskCacheLoaded, diskCacheLoadPromise, diskCacheLoadCount, jsonlLineCountCalls, MAX_INPUT_CHARS, MAX_CONCURRENCY, DISK_SAVE_DEBOUNCE_MS, DEFAULT_MAX_BATCH_SIZE, DASHSCOPE_MAX_BATCH_SIZE, MAX_RETRIES2, BASE_DELAY_MS, EmbeddingAPIError, APIEmbeddingProvider;
|
|
3848
4259
|
var init_api_provider = __esm({
|
|
3849
4260
|
"src/embedding/api-provider.ts"() {
|
|
3850
4261
|
"use strict";
|
|
3851
4262
|
init_esm_shims();
|
|
3852
4263
|
init_provider();
|
|
3853
4264
|
cache3 = /* @__PURE__ */ new Map();
|
|
3854
|
-
|
|
4265
|
+
MAX_CACHE_ENTRIES = 2e5;
|
|
4266
|
+
MAX_CACHE_PAYLOAD_BYTES = 256 * 1024 * 1024;
|
|
4267
|
+
BYTES_PER_DIM = 8;
|
|
4268
|
+
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
4269
|
+
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
4270
|
+
cachePayloadBytes = 0;
|
|
4271
|
+
cacheDimensions = null;
|
|
4272
|
+
diskCacheEntryCount = 0;
|
|
3855
4273
|
diskCacheDirty2 = false;
|
|
3856
4274
|
diskSaveTimer = null;
|
|
3857
4275
|
diskCacheLoaded = false;
|
|
3858
4276
|
diskCacheLoadPromise = null;
|
|
4277
|
+
diskCacheLoadCount = 0;
|
|
4278
|
+
jsonlLineCountCalls = 0;
|
|
3859
4279
|
MAX_INPUT_CHARS = 32e3;
|
|
3860
4280
|
MAX_CONCURRENCY = 4;
|
|
3861
4281
|
DISK_SAVE_DEBOUNCE_MS = 5e3;
|
|
@@ -3913,7 +4333,9 @@ var init_api_provider = __esm({
|
|
|
3913
4333
|
if (config.requestedDimensions) {
|
|
3914
4334
|
console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);
|
|
3915
4335
|
}
|
|
3916
|
-
|
|
4336
|
+
if (allowNetworkProbe) {
|
|
4337
|
+
startDiskCacheLoad();
|
|
4338
|
+
}
|
|
3917
4339
|
return new _APIEmbeddingProvider(config, probeDimensions);
|
|
3918
4340
|
}
|
|
3919
4341
|
static resolveConfig() {
|
|
@@ -4251,7 +4673,12 @@ function warnOnce(message) {
|
|
|
4251
4673
|
lastEmbeddingWarningAt = now3;
|
|
4252
4674
|
console.error(message);
|
|
4253
4675
|
}
|
|
4676
|
+
function embeddingModeToken() {
|
|
4677
|
+
return process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim() ?? "";
|
|
4678
|
+
}
|
|
4254
4679
|
function getEmbeddingMode2() {
|
|
4680
|
+
const token = embeddingModeToken();
|
|
4681
|
+
if (cachedEmbeddingMode && cachedEmbeddingModeToken === token) return cachedEmbeddingMode;
|
|
4255
4682
|
try {
|
|
4256
4683
|
let cfg;
|
|
4257
4684
|
try {
|
|
@@ -4260,10 +4687,17 @@ function getEmbeddingMode2() {
|
|
|
4260
4687
|
cfg = (init_config(), __toCommonJS(config_exports));
|
|
4261
4688
|
}
|
|
4262
4689
|
const { getEmbeddingMode: cfgMode } = cfg;
|
|
4263
|
-
|
|
4690
|
+
cachedEmbeddingMode = cfgMode();
|
|
4691
|
+
cachedEmbeddingModeToken = token;
|
|
4692
|
+
return cachedEmbeddingMode;
|
|
4264
4693
|
} catch {
|
|
4265
|
-
|
|
4266
|
-
|
|
4694
|
+
if (token === "fastembed" || token === "transformers" || token === "api" || token === "auto") {
|
|
4695
|
+
cachedEmbeddingMode = token;
|
|
4696
|
+
cachedEmbeddingModeToken = token;
|
|
4697
|
+
return token;
|
|
4698
|
+
}
|
|
4699
|
+
cachedEmbeddingMode = "off";
|
|
4700
|
+
cachedEmbeddingModeToken = token;
|
|
4267
4701
|
return "off";
|
|
4268
4702
|
}
|
|
4269
4703
|
}
|
|
@@ -4519,13 +4953,15 @@ function isEmbeddingExplicitlyDisabled() {
|
|
|
4519
4953
|
function resetProvider() {
|
|
4520
4954
|
provider = null;
|
|
4521
4955
|
initPromise = null;
|
|
4956
|
+
cachedEmbeddingMode = null;
|
|
4957
|
+
cachedEmbeddingModeToken = null;
|
|
4522
4958
|
lastInitWasTemporaryFailure = false;
|
|
4523
4959
|
lastFailureTimestamp = 0;
|
|
4524
4960
|
lastEmbeddingFailure = null;
|
|
4525
4961
|
lastEmbeddingWarning = "";
|
|
4526
4962
|
lastEmbeddingWarningAt = 0;
|
|
4527
4963
|
}
|
|
4528
|
-
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
4964
|
+
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, cachedEmbeddingMode, cachedEmbeddingModeToken, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
4529
4965
|
var init_provider = __esm({
|
|
4530
4966
|
"src/embedding/provider.ts"() {
|
|
4531
4967
|
"use strict";
|
|
@@ -4549,6 +4985,8 @@ var init_provider = __esm({
|
|
|
4549
4985
|
MAX_INLINE_EMBEDDING_BYTES = 5 * 1024 * 1024;
|
|
4550
4986
|
provider = null;
|
|
4551
4987
|
initPromise = null;
|
|
4988
|
+
cachedEmbeddingMode = null;
|
|
4989
|
+
cachedEmbeddingModeToken = null;
|
|
4552
4990
|
lastInitWasTemporaryFailure = false;
|
|
4553
4991
|
lastEmbeddingFailure = null;
|
|
4554
4992
|
lastEmbeddingWarning = "";
|
|
@@ -6306,6 +6744,9 @@ async function attachCachedVectors(database, candidates) {
|
|
|
6306
6744
|
await update(database, candidates[index].id, { ...existing, embedding: vector });
|
|
6307
6745
|
} catch {
|
|
6308
6746
|
}
|
|
6747
|
+
if (index % 50 === 0) {
|
|
6748
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
6749
|
+
}
|
|
6309
6750
|
}
|
|
6310
6751
|
}
|
|
6311
6752
|
async function hydrateIndex(observations2, options = {}) {
|
|
@@ -6356,17 +6797,24 @@ async function hydrateIndex(observations2, options = {}) {
|
|
|
6356
6797
|
await insert2(database, doc);
|
|
6357
6798
|
rememberObservationDoc(doc);
|
|
6358
6799
|
inserted++;
|
|
6800
|
+
if (inserted % 50 === 0) {
|
|
6801
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
6802
|
+
}
|
|
6803
|
+
if (inserted % 200 === 0) {
|
|
6804
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
6805
|
+
}
|
|
6359
6806
|
} catch {
|
|
6360
6807
|
}
|
|
6361
6808
|
}
|
|
6362
|
-
deferredCachedVectorHydration = deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
6809
|
+
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
6363
6810
|
}) : null;
|
|
6364
6811
|
return inserted;
|
|
6365
6812
|
}
|
|
6366
|
-
async function hydrateIndexForStartup(observations2) {
|
|
6813
|
+
async function hydrateIndexForStartup(observations2, options = {}) {
|
|
6367
6814
|
return hydrateIndex(observations2, {
|
|
6368
6815
|
allowNetworkProbe: false,
|
|
6369
|
-
deferCachedVectors: true
|
|
6816
|
+
deferCachedVectors: true,
|
|
6817
|
+
skipCachedVectors: options.skipCachedVectors
|
|
6370
6818
|
});
|
|
6371
6819
|
}
|
|
6372
6820
|
function getDeferredCachedVectorHydration() {
|
|
@@ -8457,7 +8905,7 @@ var init_types2 = __esm({
|
|
|
8457
8905
|
|
|
8458
8906
|
// src/media/asset-store.ts
|
|
8459
8907
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
8460
|
-
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename, rm, stat, writeFile as writeFile3 } from "fs/promises";
|
|
8908
|
+
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
8461
8909
|
import path9 from "path";
|
|
8462
8910
|
function mediaRoot(dataDir) {
|
|
8463
8911
|
return path9.resolve(dataDir, "media");
|
|
@@ -8530,7 +8978,7 @@ async function persistBuffer(bytes, destination) {
|
|
|
8530
8978
|
const temporary = `${destination}.${randomUUID5()}.tmp`;
|
|
8531
8979
|
try {
|
|
8532
8980
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
8533
|
-
await
|
|
8981
|
+
await rename2(temporary, destination);
|
|
8534
8982
|
return true;
|
|
8535
8983
|
} catch (error) {
|
|
8536
8984
|
if (error?.code === "EEXIST" && await destinationExists(destination)) return false;
|
|
@@ -59610,9 +60058,9 @@ var require_node_domexception = __commonJS({
|
|
|
59610
60058
|
});
|
|
59611
60059
|
|
|
59612
60060
|
// node_modules/fetch-blob/from.js
|
|
59613
|
-
import { statSync as statSync2, createReadStream, promises as fs7 } from "fs";
|
|
60061
|
+
import { statSync as statSync2, createReadStream as createReadStream2, promises as fs7 } from "fs";
|
|
59614
60062
|
import { basename } from "path";
|
|
59615
|
-
var import_node_domexception,
|
|
60063
|
+
var import_node_domexception, stat3, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
|
|
59616
60064
|
var init_from = __esm({
|
|
59617
60065
|
"node_modules/fetch-blob/from.js"() {
|
|
59618
60066
|
"use strict";
|
|
@@ -59620,23 +60068,23 @@ var init_from = __esm({
|
|
|
59620
60068
|
import_node_domexception = __toESM(require_node_domexception(), 1);
|
|
59621
60069
|
init_file();
|
|
59622
60070
|
init_fetch_blob();
|
|
59623
|
-
({ stat:
|
|
60071
|
+
({ stat: stat3 } = fs7);
|
|
59624
60072
|
blobFromSync = (path21, type) => fromBlob(statSync2(path21), path21, type);
|
|
59625
|
-
blobFrom = (path21, type) =>
|
|
59626
|
-
fileFrom = (path21, type) =>
|
|
60073
|
+
blobFrom = (path21, type) => stat3(path21).then((stat5) => fromBlob(stat5, path21, type));
|
|
60074
|
+
fileFrom = (path21, type) => stat3(path21).then((stat5) => fromFile(stat5, path21, type));
|
|
59627
60075
|
fileFromSync = (path21, type) => fromFile(statSync2(path21), path21, type);
|
|
59628
|
-
fromBlob = (
|
|
60076
|
+
fromBlob = (stat5, path21, type = "") => new fetch_blob_default([new BlobDataItem({
|
|
59629
60077
|
path: path21,
|
|
59630
|
-
size:
|
|
59631
|
-
lastModified:
|
|
60078
|
+
size: stat5.size,
|
|
60079
|
+
lastModified: stat5.mtimeMs,
|
|
59632
60080
|
start: 0
|
|
59633
60081
|
})], { type });
|
|
59634
|
-
fromFile = (
|
|
60082
|
+
fromFile = (stat5, path21, type = "") => new file_default([new BlobDataItem({
|
|
59635
60083
|
path: path21,
|
|
59636
|
-
size:
|
|
59637
|
-
lastModified:
|
|
60084
|
+
size: stat5.size,
|
|
60085
|
+
lastModified: stat5.mtimeMs,
|
|
59638
60086
|
start: 0
|
|
59639
|
-
})], basename(path21), { type, lastModified:
|
|
60087
|
+
})], basename(path21), { type, lastModified: stat5.mtimeMs });
|
|
59640
60088
|
BlobDataItem = class _BlobDataItem {
|
|
59641
60089
|
#path;
|
|
59642
60090
|
#start;
|
|
@@ -59659,11 +60107,11 @@ var init_from = __esm({
|
|
|
59659
60107
|
});
|
|
59660
60108
|
}
|
|
59661
60109
|
async *stream() {
|
|
59662
|
-
const { mtimeMs } = await
|
|
60110
|
+
const { mtimeMs } = await stat3(this.#path);
|
|
59663
60111
|
if (mtimeMs > this.lastModified) {
|
|
59664
60112
|
throw new import_node_domexception.default("The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.", "NotReadableError");
|
|
59665
60113
|
}
|
|
59666
|
-
yield*
|
|
60114
|
+
yield* createReadStream2(this.#path, {
|
|
59667
60115
|
start: this.#start,
|
|
59668
60116
|
end: this.#start + this.size - 1
|
|
59669
60117
|
});
|
|
@@ -75293,7 +75741,7 @@ var init_wrapper = __esm({
|
|
|
75293
75741
|
});
|
|
75294
75742
|
|
|
75295
75743
|
// node_modules/@google/genai/dist/node/index.mjs
|
|
75296
|
-
import { createWriteStream } from "fs";
|
|
75744
|
+
import { createWriteStream as createWriteStream2 } from "fs";
|
|
75297
75745
|
import * as fs8 from "fs/promises";
|
|
75298
75746
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
75299
75747
|
import { Readable } from "stream";
|
|
@@ -92573,7 +93021,7 @@ ${underline}`);
|
|
|
92573
93021
|
if (params.downloadPath) {
|
|
92574
93022
|
const response = await downloadFile(params, apiClient);
|
|
92575
93023
|
if (response instanceof HttpResponse) {
|
|
92576
|
-
const writer =
|
|
93024
|
+
const writer = createWriteStream2(params.downloadPath);
|
|
92577
93025
|
const body = Readable.fromWeb(response.responseInternal.body);
|
|
92578
93026
|
body.pipe(writer);
|
|
92579
93027
|
await finished(writer);
|
|
@@ -142197,7 +142645,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
142197
142645
|
};
|
|
142198
142646
|
}
|
|
142199
142647
|
function toRetentionDocument(obs, accessMap) {
|
|
142200
|
-
const
|
|
142648
|
+
const access2 = accessMap?.get(obs.id);
|
|
142201
142649
|
return {
|
|
142202
142650
|
id: `obs-${obs.id}`,
|
|
142203
142651
|
observationId: obs.id,
|
|
@@ -142211,8 +142659,8 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
142211
142659
|
tokens: obs.tokens,
|
|
142212
142660
|
createdAt: obs.createdAt,
|
|
142213
142661
|
projectId: obs.projectId,
|
|
142214
|
-
accessCount:
|
|
142215
|
-
lastAccessedAt:
|
|
142662
|
+
accessCount: access2?.accessCount ?? 0,
|
|
142663
|
+
lastAccessedAt: access2?.lastAccessedAt ?? "",
|
|
142216
142664
|
status: obs.status ?? "active",
|
|
142217
142665
|
source: obs.source ?? "agent",
|
|
142218
142666
|
sourceDetail: obs.sourceDetail ?? "",
|
|
@@ -144322,7 +144770,7 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
144322
144770
|
const rel = normalizeCodePath(relative(projectRoot, abs));
|
|
144323
144771
|
try {
|
|
144324
144772
|
const text2 = readFileSync6(abs, "utf-8");
|
|
144325
|
-
const
|
|
144773
|
+
const stat5 = fileStat ?? statSync3(abs);
|
|
144326
144774
|
const file = {
|
|
144327
144775
|
id: makeCodeFileId(projectId, rel),
|
|
144328
144776
|
projectId,
|
|
@@ -144331,8 +144779,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
144331
144779
|
contentHash: hashText(text2),
|
|
144332
144780
|
// Preserve filesystem precision. Rounding here made same-size edits in
|
|
144333
144781
|
// a short Windows timestamp window indistinguishable to refresh.
|
|
144334
|
-
mtimeMs: Number(
|
|
144335
|
-
sizeBytes: Number(
|
|
144782
|
+
mtimeMs: Number(stat5.mtimeMs),
|
|
144783
|
+
sizeBytes: Number(stat5.size),
|
|
144336
144784
|
indexedAt
|
|
144337
144785
|
};
|
|
144338
144786
|
return {
|
|
@@ -144359,18 +144807,18 @@ async function indexProjectLite(options) {
|
|
|
144359
144807
|
let skippedOversizedFiles = 0;
|
|
144360
144808
|
let unreadableFiles = 0;
|
|
144361
144809
|
for (const abs of paths) {
|
|
144362
|
-
let
|
|
144810
|
+
let stat5;
|
|
144363
144811
|
try {
|
|
144364
|
-
|
|
144812
|
+
stat5 = statSync3(abs);
|
|
144365
144813
|
} catch {
|
|
144366
144814
|
unreadableFiles++;
|
|
144367
144815
|
continue;
|
|
144368
144816
|
}
|
|
144369
|
-
if (Number(
|
|
144817
|
+
if (Number(stat5.size) > maxFileBytes) {
|
|
144370
144818
|
skippedOversizedFiles++;
|
|
144371
144819
|
continue;
|
|
144372
144820
|
}
|
|
144373
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
144821
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
144374
144822
|
if (!attempt.delta) {
|
|
144375
144823
|
if (attempt.unreadable) unreadableFiles++;
|
|
144376
144824
|
continue;
|
|
@@ -144398,16 +144846,16 @@ async function refreshProjectLite(store, options) {
|
|
|
144398
144846
|
for (const abs of paths) {
|
|
144399
144847
|
const rel = normalizeCodePath(relative(options.projectRoot, abs));
|
|
144400
144848
|
seenPaths.add(rel);
|
|
144401
|
-
let
|
|
144849
|
+
let stat5;
|
|
144402
144850
|
try {
|
|
144403
|
-
|
|
144851
|
+
stat5 = statSync3(abs);
|
|
144404
144852
|
} catch {
|
|
144405
144853
|
unreadableFiles++;
|
|
144406
144854
|
continue;
|
|
144407
144855
|
}
|
|
144408
144856
|
const existing = existingByPath.get(rel);
|
|
144409
|
-
const mtimeMs = Number(
|
|
144410
|
-
const sizeBytes = Number(
|
|
144857
|
+
const mtimeMs = Number(stat5.mtimeMs);
|
|
144858
|
+
const sizeBytes = Number(stat5.size);
|
|
144411
144859
|
if (sizeBytes > maxFileBytes) {
|
|
144412
144860
|
skippedOversizedFiles++;
|
|
144413
144861
|
if (existing) oversizedExistingFileIds.add(existing.id);
|
|
@@ -144417,7 +144865,7 @@ async function refreshProjectLite(store, options) {
|
|
|
144417
144865
|
unchangedFiles++;
|
|
144418
144866
|
continue;
|
|
144419
144867
|
}
|
|
144420
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
144868
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
144421
144869
|
if (!attempt.delta) {
|
|
144422
144870
|
if (attempt.unreadable) unreadableFiles++;
|
|
144423
144871
|
continue;
|
|
@@ -147814,12 +148262,25 @@ __export(observations_exports, {
|
|
|
147814
148262
|
prepareSearchIndex: () => prepareSearchIndex,
|
|
147815
148263
|
probeSearchIndex: () => probeSearchIndex,
|
|
147816
148264
|
reindexObservations: () => reindexObservations,
|
|
148265
|
+
resetObservationRuntime: () => resetObservationRuntime,
|
|
147817
148266
|
resolveObservations: () => resolveObservations,
|
|
147818
148267
|
storeObservation: () => storeObservation,
|
|
147819
148268
|
suggestTopicKey: () => suggestTopicKey,
|
|
147820
148269
|
updateObservationAdmission: () => updateObservationAdmission,
|
|
147821
148270
|
withFreshObservations: () => withFreshObservations
|
|
147822
148271
|
});
|
|
148272
|
+
function resetObservationRuntime() {
|
|
148273
|
+
observations = [];
|
|
148274
|
+
nextId = 1;
|
|
148275
|
+
projectDir = null;
|
|
148276
|
+
searchIndexPrepared = false;
|
|
148277
|
+
corpusLoaded = false;
|
|
148278
|
+
loadedObservationStore = null;
|
|
148279
|
+
embeddingWriteMode = "background";
|
|
148280
|
+
embeddingWorkerProjectRoot = void 0;
|
|
148281
|
+
vectorMissingIds.clear();
|
|
148282
|
+
vectorSchemaUpgradePromise = null;
|
|
148283
|
+
}
|
|
147823
148284
|
function logEmbeddingFailureOnce(key, message) {
|
|
147824
148285
|
const now3 = Date.now();
|
|
147825
148286
|
const last = embeddingFailureLogTimestamps.get(key) ?? 0;
|
|
@@ -147928,23 +148389,33 @@ async function upgradeVectorSchemaAfterFirstEmbedding(embedding) {
|
|
|
147928
148389
|
async function initObservations(dir, options = {}) {
|
|
147929
148390
|
embeddingWriteMode = options.embeddingWriteMode ?? "background";
|
|
147930
148391
|
embeddingWorkerProjectRoot = options.projectRoot;
|
|
147931
|
-
if (projectDir === dir) return;
|
|
147932
148392
|
await initObservationStore(dir);
|
|
147933
148393
|
const store = getObservationStore();
|
|
147934
|
-
|
|
148394
|
+
if (projectDir === dir && loadedObservationStore === store) {
|
|
148395
|
+
if (options.skipCorpusLoad || corpusLoaded) return;
|
|
148396
|
+
}
|
|
147935
148397
|
nextId = await store.loadIdCounter();
|
|
147936
148398
|
projectDir = dir;
|
|
147937
148399
|
searchIndexPrepared = false;
|
|
147938
148400
|
vectorSchemaUpgradePromise = null;
|
|
148401
|
+
if (options.skipCorpusLoad) {
|
|
148402
|
+
observations = [];
|
|
148403
|
+
corpusLoaded = false;
|
|
148404
|
+
loadedObservationStore = store;
|
|
148405
|
+
return;
|
|
148406
|
+
}
|
|
148407
|
+
observations = await store.loadAll();
|
|
148408
|
+
corpusLoaded = true;
|
|
148409
|
+
loadedObservationStore = store;
|
|
147939
148410
|
}
|
|
147940
148411
|
function scheduleObservationEmbedding(input) {
|
|
147941
148412
|
const { observationId: observationId2, projectId, searchableText, doc } = input;
|
|
147942
148413
|
vectorMissingIds.add(observationId2);
|
|
148414
|
+
if (isEmbeddingExplicitlyDisabled()) {
|
|
148415
|
+
vectorMissingIds.delete(observationId2);
|
|
148416
|
+
return;
|
|
148417
|
+
}
|
|
147943
148418
|
if (embeddingWriteMode === "deferred") {
|
|
147944
|
-
if (isEmbeddingExplicitlyDisabled()) {
|
|
147945
|
-
vectorMissingIds.delete(observationId2);
|
|
147946
|
-
return;
|
|
147947
|
-
}
|
|
147948
148419
|
queueVectorBackfill(projectId, {
|
|
147949
148420
|
detachedWorker: true,
|
|
147950
148421
|
projectRoot: embeddingWorkerProjectRoot
|
|
@@ -147991,7 +148462,7 @@ function scheduleObservationEmbedding(input) {
|
|
|
147991
148462
|
});
|
|
147992
148463
|
}
|
|
147993
148464
|
async function ensureFreshObservations() {
|
|
147994
|
-
if (!projectDir) return false;
|
|
148465
|
+
if (!projectDir || !corpusLoaded) return false;
|
|
147995
148466
|
try {
|
|
147996
148467
|
const store = getObservationStore();
|
|
147997
148468
|
const wasStale = await store.ensureFresh();
|
|
@@ -148032,7 +148503,7 @@ async function storeObservation(input) {
|
|
|
148032
148503
|
});
|
|
148033
148504
|
if (safeAttachments) input = { ...input, attachments: safeAttachments };
|
|
148034
148505
|
await ensureFreshObservations();
|
|
148035
|
-
if (input.topicKey) {
|
|
148506
|
+
if (input.topicKey && corpusLoaded) {
|
|
148036
148507
|
const existing = observations.find(
|
|
148037
148508
|
(o) => o.topicKey === input.topicKey && o.projectId === input.projectId
|
|
148038
148509
|
);
|
|
@@ -148129,13 +148600,17 @@ async function storeObservation(input) {
|
|
|
148129
148600
|
});
|
|
148130
148601
|
observation.writeGeneration = store.getGeneration();
|
|
148131
148602
|
if (upsertedInsideLock || reloadCacheAfterCommit) {
|
|
148132
|
-
|
|
148133
|
-
|
|
148134
|
-
|
|
148135
|
-
|
|
148603
|
+
if (corpusLoaded) {
|
|
148604
|
+
observations = await store.loadAll();
|
|
148605
|
+
nextId = await store.loadIdCounter();
|
|
148606
|
+
if (upsertedInsideLock) {
|
|
148607
|
+
observation = observations.find((candidate) => candidate.id === observation.id) ?? observation;
|
|
148608
|
+
}
|
|
148609
|
+
} else {
|
|
148610
|
+
nextId = await store.loadIdCounter();
|
|
148136
148611
|
}
|
|
148137
148612
|
} else {
|
|
148138
|
-
observations.push(observation);
|
|
148613
|
+
if (corpusLoaded) observations.push(observation);
|
|
148139
148614
|
nextId = observation.id + 1;
|
|
148140
148615
|
}
|
|
148141
148616
|
if (upsertedInsideLock) return;
|
|
@@ -148203,7 +148678,9 @@ async function storeObservation(input) {
|
|
|
148203
148678
|
createdByAgentId: input.createdByAgentId ?? "",
|
|
148204
148679
|
sharedWithAgentIds: JSON.stringify(input.sharedWithAgentIds ?? [])
|
|
148205
148680
|
};
|
|
148206
|
-
|
|
148681
|
+
if (corpusLoaded) {
|
|
148682
|
+
await insertObservation(doc);
|
|
148683
|
+
}
|
|
148207
148684
|
};
|
|
148208
148685
|
await assignAndPersist();
|
|
148209
148686
|
if (upsertedInsideLock) {
|
|
@@ -148565,9 +149042,11 @@ async function reindexObservations() {
|
|
|
148565
149042
|
searchIndexPrepared = true;
|
|
148566
149043
|
return count2;
|
|
148567
149044
|
}
|
|
148568
|
-
async function prepareSearchIndex() {
|
|
149045
|
+
async function prepareSearchIndex(options = {}) {
|
|
148569
149046
|
if (searchIndexPrepared) return 0;
|
|
148570
|
-
const count2 = await hydrateIndexForStartup(observations
|
|
149047
|
+
const count2 = await hydrateIndexForStartup(observations, {
|
|
149048
|
+
skipCachedVectors: options.skipCachedVectors
|
|
149049
|
+
});
|
|
148571
149050
|
if (count2 === 0) {
|
|
148572
149051
|
searchIndexPrepared = true;
|
|
148573
149052
|
return 0;
|
|
@@ -148759,7 +149238,7 @@ async function backfillVectorEmbeddings(options = {}) {
|
|
|
148759
149238
|
...lastFailure ? { lastError: lastFailure } : {}
|
|
148760
149239
|
};
|
|
148761
149240
|
}
|
|
148762
|
-
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
149241
|
+
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
148763
149242
|
var init_observations = __esm({
|
|
148764
149243
|
"src/memory/observations.ts"() {
|
|
148765
149244
|
"use strict";
|
|
@@ -148778,6 +149257,8 @@ var init_observations = __esm({
|
|
|
148778
149257
|
projectDir = null;
|
|
148779
149258
|
searchIndexPrepared = false;
|
|
148780
149259
|
embeddingWriteMode = "background";
|
|
149260
|
+
corpusLoaded = false;
|
|
149261
|
+
loadedObservationStore = null;
|
|
148781
149262
|
vectorMissingIds = /* @__PURE__ */ new Set();
|
|
148782
149263
|
vectorBackfillRunning = false;
|
|
148783
149264
|
vectorSchemaUpgradePromise = null;
|