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
|
@@ -1369,8 +1369,8 @@ async function acquireLock(lockPath) {
|
|
|
1369
1369
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
1370
1370
|
if (code === "EEXIST" || code === "EPERM") {
|
|
1371
1371
|
try {
|
|
1372
|
-
const
|
|
1373
|
-
if (Date.now() -
|
|
1372
|
+
const stat5 = await fs2.stat(lockPath);
|
|
1373
|
+
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
1374
1374
|
await fs2.unlink(lockPath).catch(() => {
|
|
1375
1375
|
});
|
|
1376
1376
|
continue;
|
|
@@ -2481,24 +2481,131 @@ var init_transformers_provider = __esm({
|
|
|
2481
2481
|
// src/embedding/api-provider.ts
|
|
2482
2482
|
var api_provider_exports = {};
|
|
2483
2483
|
__export(api_provider_exports, {
|
|
2484
|
-
APIEmbeddingProvider: () => APIEmbeddingProvider
|
|
2484
|
+
APIEmbeddingProvider: () => APIEmbeddingProvider,
|
|
2485
|
+
convertArrayCacheToJsonl: () => convertArrayCacheToJsonl,
|
|
2486
|
+
ensureDiskCacheLoaded: () => ensureDiskCacheLoaded,
|
|
2487
|
+
getApiEmbeddingCachePayloadBytesForTests: () => getApiEmbeddingCachePayloadBytesForTests,
|
|
2488
|
+
getApiEmbeddingDiskCacheLoadCountForTests: () => getApiEmbeddingDiskCacheLoadCountForTests,
|
|
2489
|
+
getApiEmbeddingJsonlLineCountCallsForTests: () => getApiEmbeddingJsonlLineCountCallsForTests,
|
|
2490
|
+
getApiEmbeddingMaxEntriesForDimensionsForTests: () => getApiEmbeddingMaxEntriesForDimensionsForTests,
|
|
2491
|
+
migrateJsonArrayCacheToJsonl: () => migrateJsonArrayCacheToJsonl,
|
|
2492
|
+
parseCacheJsonInWorker: () => parseCacheJsonInWorker,
|
|
2493
|
+
resetApiEmbeddingCacheForTests: () => resetApiEmbeddingCacheForTests,
|
|
2494
|
+
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
2495
|
+
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
2485
2496
|
});
|
|
2486
2497
|
import { createHash as createHash2 } from "crypto";
|
|
2487
|
-
import {
|
|
2498
|
+
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
2499
|
+
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
2488
2500
|
import { join as join3 } from "path";
|
|
2489
2501
|
import { homedir as homedir7 } from "os";
|
|
2502
|
+
import { createInterface } from "readline";
|
|
2490
2503
|
function cacheDir() {
|
|
2491
2504
|
return process.env.MEMORIX_DATA_DIR || join3(homedir7(), ".memorix", "data");
|
|
2492
2505
|
}
|
|
2493
2506
|
function cacheFile() {
|
|
2494
2507
|
return join3(cacheDir(), ".embedding-api-cache.json");
|
|
2495
2508
|
}
|
|
2509
|
+
function cacheJsonlFile() {
|
|
2510
|
+
return join3(cacheDir(), ".embedding-api-cache.jsonl");
|
|
2511
|
+
}
|
|
2496
2512
|
function dimsCacheFile() {
|
|
2497
2513
|
return join3(cacheDir(), ".embedding-dims-cache.json");
|
|
2498
2514
|
}
|
|
2499
2515
|
function cacheMetaFile() {
|
|
2500
2516
|
return join3(cacheDir(), ".embedding-api-cache-meta.json");
|
|
2501
2517
|
}
|
|
2518
|
+
function cacheStatFile() {
|
|
2519
|
+
return join3(cacheDir(), ".embedding-api-cache-stat.json");
|
|
2520
|
+
}
|
|
2521
|
+
function payloadBytes(vector) {
|
|
2522
|
+
return vector.length * BYTES_PER_DIM;
|
|
2523
|
+
}
|
|
2524
|
+
function maxCachePayloadBytes() {
|
|
2525
|
+
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
2526
|
+
if (raw) {
|
|
2527
|
+
const parsed = Number.parseInt(raw, 10);
|
|
2528
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
2529
|
+
}
|
|
2530
|
+
return MAX_CACHE_PAYLOAD_BYTES;
|
|
2531
|
+
}
|
|
2532
|
+
function maxEntriesForDimensions(dimensions) {
|
|
2533
|
+
const dim = Math.max(1, Math.floor(dimensions));
|
|
2534
|
+
const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
|
|
2535
|
+
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
2536
|
+
}
|
|
2537
|
+
function rememberDimensions(vector) {
|
|
2538
|
+
if (vector.length > 0 && (cacheDimensions === null || vector.length > cacheDimensions)) {
|
|
2539
|
+
cacheDimensions = vector.length;
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
function evictOldest() {
|
|
2543
|
+
const firstKey = cache3.keys().next().value;
|
|
2544
|
+
if (firstKey === void 0) return;
|
|
2545
|
+
const old = cache3.get(firstKey);
|
|
2546
|
+
cache3.delete(firstKey);
|
|
2547
|
+
if (old) cachePayloadBytes -= payloadBytes(old);
|
|
2548
|
+
}
|
|
2549
|
+
function evictToFit(incomingBytes, incomingDims) {
|
|
2550
|
+
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
2551
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
|
|
2552
|
+
evictOldest();
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
function isNumberArray(value) {
|
|
2556
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
2557
|
+
}
|
|
2558
|
+
function parseCacheRow(raw) {
|
|
2559
|
+
if (Array.isArray(raw)) {
|
|
2560
|
+
const hash4 = raw[0];
|
|
2561
|
+
const vector = raw[1];
|
|
2562
|
+
if (typeof hash4 === "string" && isNumberArray(vector)) {
|
|
2563
|
+
return { hash: hash4, vector };
|
|
2564
|
+
}
|
|
2565
|
+
return null;
|
|
2566
|
+
}
|
|
2567
|
+
if (raw && typeof raw === "object") {
|
|
2568
|
+
const row = raw;
|
|
2569
|
+
if (typeof row.h === "string" && isNumberArray(row.v)) {
|
|
2570
|
+
return { hash: row.h, vector: row.v };
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
return null;
|
|
2574
|
+
}
|
|
2575
|
+
function cacheInsert(hash4, value, dirty) {
|
|
2576
|
+
rememberDimensions(value);
|
|
2577
|
+
const incoming = payloadBytes(value);
|
|
2578
|
+
const existing = cache3.get(hash4);
|
|
2579
|
+
if (existing) {
|
|
2580
|
+
cachePayloadBytes -= payloadBytes(existing);
|
|
2581
|
+
cache3.delete(hash4);
|
|
2582
|
+
}
|
|
2583
|
+
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
2584
|
+
cache3.set(hash4, value);
|
|
2585
|
+
cachePayloadBytes += incoming;
|
|
2586
|
+
if (dirty) diskCacheDirty2 = true;
|
|
2587
|
+
}
|
|
2588
|
+
async function readCacheStat() {
|
|
2589
|
+
try {
|
|
2590
|
+
const data = JSON.parse(await readFile2(cacheStatFile(), "utf-8"));
|
|
2591
|
+
if (typeof data.entryCount === "number" && Number.isFinite(data.entryCount) && data.entryCount >= 0) {
|
|
2592
|
+
return {
|
|
2593
|
+
version: 1,
|
|
2594
|
+
entryCount: Math.floor(data.entryCount),
|
|
2595
|
+
dimensions: isValidDimension(data.dimensions) ? data.dimensions : null
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
2598
|
+
} catch {
|
|
2599
|
+
}
|
|
2600
|
+
return null;
|
|
2601
|
+
}
|
|
2602
|
+
async function writeCacheStat(stat5) {
|
|
2603
|
+
try {
|
|
2604
|
+
await mkdir2(cacheDir(), { recursive: true });
|
|
2605
|
+
await writeFile2(cacheStatFile(), JSON.stringify(stat5));
|
|
2606
|
+
} catch {
|
|
2607
|
+
}
|
|
2608
|
+
}
|
|
2502
2609
|
function normalizeText(text2) {
|
|
2503
2610
|
return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
|
|
2504
2611
|
}
|
|
@@ -2584,29 +2691,300 @@ function toProviderInput(input, baseUrl) {
|
|
|
2584
2691
|
}
|
|
2585
2692
|
return { type: input.modality, url: input.url };
|
|
2586
2693
|
}
|
|
2694
|
+
function parseCacheJsonInWorker(filePath) {
|
|
2695
|
+
return new Promise((resolve, reject) => {
|
|
2696
|
+
void import("worker_threads").then(({ Worker }) => {
|
|
2697
|
+
const worker = new Worker(
|
|
2698
|
+
`
|
|
2699
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
2700
|
+
const { readFileSync } = require('node:fs');
|
|
2701
|
+
try {
|
|
2702
|
+
const raw = readFileSync(workerData.filePath, 'utf8');
|
|
2703
|
+
parentPort.postMessage({ ok: true, entries: JSON.parse(raw) });
|
|
2704
|
+
} catch (err) {
|
|
2705
|
+
parentPort.postMessage({
|
|
2706
|
+
ok: false,
|
|
2707
|
+
error: err instanceof Error ? err.message : String(err),
|
|
2708
|
+
});
|
|
2709
|
+
}
|
|
2710
|
+
`,
|
|
2711
|
+
{ eval: true, workerData: { filePath } }
|
|
2712
|
+
);
|
|
2713
|
+
worker.once("message", (msg) => {
|
|
2714
|
+
void worker.terminate();
|
|
2715
|
+
if (msg?.ok && Array.isArray(msg.entries)) {
|
|
2716
|
+
resolve(msg.entries);
|
|
2717
|
+
return;
|
|
2718
|
+
}
|
|
2719
|
+
reject(new Error(msg?.error || "embedding cache worker parse failed"));
|
|
2720
|
+
});
|
|
2721
|
+
worker.once("error", reject);
|
|
2722
|
+
}).catch(reject);
|
|
2723
|
+
});
|
|
2724
|
+
}
|
|
2725
|
+
function findJsonValueEnd(source) {
|
|
2726
|
+
let i2 = 0;
|
|
2727
|
+
while (i2 < source.length && /\s/.test(source[i2])) i2 += 1;
|
|
2728
|
+
if (i2 >= source.length) return -1;
|
|
2729
|
+
const start = source[i2];
|
|
2730
|
+
if (start === '"') {
|
|
2731
|
+
i2 += 1;
|
|
2732
|
+
while (i2 < source.length) {
|
|
2733
|
+
if (source[i2] === "\\") {
|
|
2734
|
+
i2 += 2;
|
|
2735
|
+
continue;
|
|
2736
|
+
}
|
|
2737
|
+
if (source[i2] === '"') return i2 + 1;
|
|
2738
|
+
i2 += 1;
|
|
2739
|
+
}
|
|
2740
|
+
return -1;
|
|
2741
|
+
}
|
|
2742
|
+
if (start === "{" || start === "[") {
|
|
2743
|
+
const close = start === "{" ? "}" : "]";
|
|
2744
|
+
let depth = 0;
|
|
2745
|
+
let inString = false;
|
|
2746
|
+
for (; i2 < source.length; i2 += 1) {
|
|
2747
|
+
const ch = source[i2];
|
|
2748
|
+
if (inString) {
|
|
2749
|
+
if (ch === "\\") {
|
|
2750
|
+
i2 += 1;
|
|
2751
|
+
continue;
|
|
2752
|
+
}
|
|
2753
|
+
if (ch === '"') inString = false;
|
|
2754
|
+
continue;
|
|
2755
|
+
}
|
|
2756
|
+
if (ch === '"') {
|
|
2757
|
+
inString = true;
|
|
2758
|
+
continue;
|
|
2759
|
+
}
|
|
2760
|
+
if (ch === start) depth += 1;
|
|
2761
|
+
else if (ch === close) {
|
|
2762
|
+
depth -= 1;
|
|
2763
|
+
if (depth === 0) return i2 + 1;
|
|
2764
|
+
}
|
|
2765
|
+
}
|
|
2766
|
+
return -1;
|
|
2767
|
+
}
|
|
2768
|
+
const rest = source.slice(i2);
|
|
2769
|
+
const match2 = rest.match(/^(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/);
|
|
2770
|
+
return match2 ? i2 + match2[0].length : -1;
|
|
2771
|
+
}
|
|
2772
|
+
async function streamJsonArrayToJsonl(filePath, tmpPath) {
|
|
2773
|
+
const input = createReadStream(filePath, { encoding: "utf8" });
|
|
2774
|
+
const out = createWriteStream(tmpPath);
|
|
2775
|
+
let buf = "";
|
|
2776
|
+
let started = false;
|
|
2777
|
+
let count2 = 0;
|
|
2778
|
+
const writeLine = async (line) => {
|
|
2779
|
+
if (!out.write(line)) {
|
|
2780
|
+
await new Promise((resolve, reject) => {
|
|
2781
|
+
out.once("drain", resolve);
|
|
2782
|
+
out.once("error", reject);
|
|
2783
|
+
});
|
|
2784
|
+
}
|
|
2785
|
+
};
|
|
2786
|
+
try {
|
|
2787
|
+
for await (const chunk of input) {
|
|
2788
|
+
buf += chunk;
|
|
2789
|
+
if (!started) {
|
|
2790
|
+
const idx = buf.search(/\S/);
|
|
2791
|
+
if (idx < 0) continue;
|
|
2792
|
+
if (buf[idx] !== "[") throw new Error("embedding cache is not a JSON array");
|
|
2793
|
+
buf = buf.slice(idx + 1);
|
|
2794
|
+
started = true;
|
|
2795
|
+
}
|
|
2796
|
+
while (true) {
|
|
2797
|
+
buf = buf.replace(/^\s*,?\s*/, "");
|
|
2798
|
+
if (!buf) break;
|
|
2799
|
+
if (buf[0] === "]") {
|
|
2800
|
+
buf = "";
|
|
2801
|
+
break;
|
|
2802
|
+
}
|
|
2803
|
+
const end = findJsonValueEnd(buf);
|
|
2804
|
+
if (end < 0) break;
|
|
2805
|
+
const value = JSON.parse(buf.slice(0, end));
|
|
2806
|
+
buf = buf.slice(end);
|
|
2807
|
+
const row = parseCacheRow(value);
|
|
2808
|
+
if (row) {
|
|
2809
|
+
await writeLine(`${JSON.stringify({ h: row.hash, v: row.vector })}
|
|
2810
|
+
`);
|
|
2811
|
+
count2 += 1;
|
|
2812
|
+
if (count2 % 50 === 0) {
|
|
2813
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
2814
|
+
}
|
|
2815
|
+
}
|
|
2816
|
+
}
|
|
2817
|
+
if (buf.length > MAX_MIGRATION_VALUE_BYTES) {
|
|
2818
|
+
throw new Error("embedding cache entry too large to migrate safely");
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
} finally {
|
|
2822
|
+
await new Promise((resolve, reject) => {
|
|
2823
|
+
out.end(() => resolve());
|
|
2824
|
+
out.once("error", reject);
|
|
2825
|
+
});
|
|
2826
|
+
}
|
|
2827
|
+
return count2;
|
|
2828
|
+
}
|
|
2829
|
+
async function migrateJsonArrayCacheToJsonl(filePath, jsonlPath) {
|
|
2830
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
2831
|
+
try {
|
|
2832
|
+
const count2 = await streamJsonArrayToJsonl(filePath, tmpPath);
|
|
2833
|
+
await rename(tmpPath, jsonlPath);
|
|
2834
|
+
diskCacheEntryCount = count2;
|
|
2835
|
+
await writeCacheStat({
|
|
2836
|
+
version: 1,
|
|
2837
|
+
entryCount: count2,
|
|
2838
|
+
dimensions: cacheDimensions
|
|
2839
|
+
});
|
|
2840
|
+
return count2;
|
|
2841
|
+
} catch (err) {
|
|
2842
|
+
await unlink(tmpPath).catch(() => void 0);
|
|
2843
|
+
throw err;
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
function convertArrayCacheToJsonl(filePath, jsonlPath) {
|
|
2847
|
+
return migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
2848
|
+
}
|
|
2849
|
+
async function loadCacheJsonl(filePath) {
|
|
2850
|
+
const rl = createInterface({
|
|
2851
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
2852
|
+
crlfDelay: Infinity
|
|
2853
|
+
});
|
|
2854
|
+
let loaded = 0;
|
|
2855
|
+
let onDiskCount = 0;
|
|
2856
|
+
for await (const line of rl) {
|
|
2857
|
+
const trimmed = line.trim();
|
|
2858
|
+
if (!trimmed) continue;
|
|
2859
|
+
try {
|
|
2860
|
+
const row = parseCacheRow(JSON.parse(trimmed));
|
|
2861
|
+
if (!row) continue;
|
|
2862
|
+
onDiskCount += 1;
|
|
2863
|
+
cacheInsert(row.hash, row.vector, false);
|
|
2864
|
+
loaded = cache3.size;
|
|
2865
|
+
} catch {
|
|
2866
|
+
}
|
|
2867
|
+
if (onDiskCount % 250 === 0) {
|
|
2868
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
diskCacheEntryCount = onDiskCount;
|
|
2872
|
+
await writeCacheStat({
|
|
2873
|
+
version: 1,
|
|
2874
|
+
entryCount: onDiskCount,
|
|
2875
|
+
dimensions: cacheDimensions
|
|
2876
|
+
});
|
|
2877
|
+
return loaded;
|
|
2878
|
+
}
|
|
2879
|
+
async function countJsonlLines(filePath) {
|
|
2880
|
+
jsonlLineCountCalls += 1;
|
|
2881
|
+
try {
|
|
2882
|
+
const rl = createInterface({
|
|
2883
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
2884
|
+
crlfDelay: Infinity
|
|
2885
|
+
});
|
|
2886
|
+
let count2 = 0;
|
|
2887
|
+
for await (const line of rl) {
|
|
2888
|
+
if (line.trim()) count2 += 1;
|
|
2889
|
+
}
|
|
2890
|
+
return count2;
|
|
2891
|
+
} catch {
|
|
2892
|
+
return 0;
|
|
2893
|
+
}
|
|
2894
|
+
}
|
|
2895
|
+
async function resolveOnDiskCount(jsonlPath) {
|
|
2896
|
+
if (diskCacheEntryCount > 0) return diskCacheEntryCount;
|
|
2897
|
+
const sidecar = await readCacheStat();
|
|
2898
|
+
if (sidecar) {
|
|
2899
|
+
diskCacheEntryCount = sidecar.entryCount;
|
|
2900
|
+
if (sidecar.dimensions && cacheDimensions === null) cacheDimensions = sidecar.dimensions;
|
|
2901
|
+
return sidecar.entryCount;
|
|
2902
|
+
}
|
|
2903
|
+
try {
|
|
2904
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
2905
|
+
} catch {
|
|
2906
|
+
return 0;
|
|
2907
|
+
}
|
|
2908
|
+
const counted = await countJsonlLines(jsonlPath);
|
|
2909
|
+
diskCacheEntryCount = counted;
|
|
2910
|
+
await writeCacheStat({
|
|
2911
|
+
version: 1,
|
|
2912
|
+
entryCount: counted,
|
|
2913
|
+
dimensions: cacheDimensions
|
|
2914
|
+
});
|
|
2915
|
+
return counted;
|
|
2916
|
+
}
|
|
2587
2917
|
async function loadDiskCache2() {
|
|
2588
|
-
if (diskCacheLoaded) return;
|
|
2918
|
+
if (diskCacheLoaded) return cache3.size;
|
|
2919
|
+
let loaded = 0;
|
|
2589
2920
|
try {
|
|
2590
|
-
const
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2921
|
+
const jsonlPath = cacheJsonlFile();
|
|
2922
|
+
let hasJsonl = false;
|
|
2923
|
+
try {
|
|
2924
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
2925
|
+
hasJsonl = true;
|
|
2926
|
+
} catch {
|
|
2927
|
+
hasJsonl = false;
|
|
2928
|
+
}
|
|
2929
|
+
if (hasJsonl) {
|
|
2930
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
2931
|
+
} else {
|
|
2932
|
+
const filePath = cacheFile();
|
|
2933
|
+
await stat(filePath);
|
|
2934
|
+
await migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
2935
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
2936
|
+
}
|
|
2937
|
+
diskCacheLoadCount += 1;
|
|
2938
|
+
console.error(`[memorix] Loaded ${loaded} cached API embeddings from disk`);
|
|
2594
2939
|
} catch {
|
|
2595
2940
|
}
|
|
2596
2941
|
diskCacheLoaded = true;
|
|
2942
|
+
return loaded;
|
|
2597
2943
|
}
|
|
2598
2944
|
function startDiskCacheLoad() {
|
|
2599
2945
|
if (diskCacheLoaded || diskCacheLoadPromise) return;
|
|
2600
|
-
diskCacheLoadPromise = loadDiskCache2().catch(() => {
|
|
2946
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
2601
2947
|
});
|
|
2602
2948
|
}
|
|
2603
2949
|
async function ensureDiskCacheLoaded() {
|
|
2604
|
-
if (diskCacheLoaded) return;
|
|
2605
|
-
if (diskCacheLoadPromise) {
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
}
|
|
2609
|
-
await
|
|
2950
|
+
if (diskCacheLoaded) return cache3.size;
|
|
2951
|
+
if (!diskCacheLoadPromise) {
|
|
2952
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
2953
|
+
});
|
|
2954
|
+
}
|
|
2955
|
+
await diskCacheLoadPromise;
|
|
2956
|
+
return cache3.size;
|
|
2957
|
+
}
|
|
2958
|
+
function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
2959
|
+
return diskCacheLoadCount;
|
|
2960
|
+
}
|
|
2961
|
+
function resetApiEmbeddingCacheForTests() {
|
|
2962
|
+
cache3.clear();
|
|
2963
|
+
cachePayloadBytes = 0;
|
|
2964
|
+
cacheDimensions = null;
|
|
2965
|
+
diskCacheEntryCount = 0;
|
|
2966
|
+
diskCacheLoaded = false;
|
|
2967
|
+
diskCacheLoadPromise = null;
|
|
2968
|
+
diskCacheLoadCount = 0;
|
|
2969
|
+
diskCacheDirty2 = false;
|
|
2970
|
+
jsonlLineCountCalls = 0;
|
|
2971
|
+
}
|
|
2972
|
+
function seedApiEmbeddingCacheForTests(entries) {
|
|
2973
|
+
cache3.clear();
|
|
2974
|
+
cachePayloadBytes = 0;
|
|
2975
|
+
cacheDimensions = null;
|
|
2976
|
+
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
2977
|
+
diskCacheLoaded = true;
|
|
2978
|
+
diskCacheDirty2 = true;
|
|
2979
|
+
}
|
|
2980
|
+
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
2981
|
+
return cachePayloadBytes;
|
|
2982
|
+
}
|
|
2983
|
+
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
2984
|
+
return jsonlLineCountCalls;
|
|
2985
|
+
}
|
|
2986
|
+
function getApiEmbeddingMaxEntriesForDimensionsForTests(dimensions) {
|
|
2987
|
+
return maxEntriesForDimensions(dimensions);
|
|
2610
2988
|
}
|
|
2611
2989
|
function dimsCacheKey(config) {
|
|
2612
2990
|
return [
|
|
@@ -2722,8 +3100,46 @@ async function saveDiskCacheNow() {
|
|
|
2722
3100
|
if (!diskCacheDirty2) return;
|
|
2723
3101
|
try {
|
|
2724
3102
|
await mkdir2(cacheDir(), { recursive: true });
|
|
2725
|
-
const
|
|
2726
|
-
await
|
|
3103
|
+
const jsonlPath = cacheJsonlFile();
|
|
3104
|
+
const existing = await resolveOnDiskCount(jsonlPath);
|
|
3105
|
+
if (existing > 0 && cache3.size < Math.ceil(existing * 0.5)) {
|
|
3106
|
+
console.error(
|
|
3107
|
+
`[memorix] Refusing to overwrite embedding cache (${existing} on disk vs ${cache3.size} in memory)`
|
|
3108
|
+
);
|
|
3109
|
+
diskCacheDirty2 = false;
|
|
3110
|
+
return;
|
|
3111
|
+
}
|
|
3112
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
3113
|
+
await new Promise((resolve, reject) => {
|
|
3114
|
+
const out = createWriteStream(tmpPath);
|
|
3115
|
+
const entries = cache3.entries();
|
|
3116
|
+
const writeBatch = () => {
|
|
3117
|
+
for (let i2 = 0; i2 < 50; i2++) {
|
|
3118
|
+
const next = entries.next();
|
|
3119
|
+
if (next.done) {
|
|
3120
|
+
out.end();
|
|
3121
|
+
return;
|
|
3122
|
+
}
|
|
3123
|
+
const [hash4, vector] = next.value;
|
|
3124
|
+
if (!out.write(`${JSON.stringify({ h: hash4, v: vector })}
|
|
3125
|
+
`)) {
|
|
3126
|
+
out.once("drain", writeBatch);
|
|
3127
|
+
return;
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
setImmediate(writeBatch);
|
|
3131
|
+
};
|
|
3132
|
+
out.on("finish", resolve);
|
|
3133
|
+
out.on("error", reject);
|
|
3134
|
+
writeBatch();
|
|
3135
|
+
});
|
|
3136
|
+
await rename(tmpPath, jsonlPath);
|
|
3137
|
+
diskCacheEntryCount = cache3.size;
|
|
3138
|
+
await writeCacheStat({
|
|
3139
|
+
version: 1,
|
|
3140
|
+
entryCount: cache3.size,
|
|
3141
|
+
dimensions: cacheDimensions
|
|
3142
|
+
});
|
|
2727
3143
|
diskCacheDirty2 = false;
|
|
2728
3144
|
} catch {
|
|
2729
3145
|
}
|
|
@@ -2737,12 +3153,7 @@ function scheduleDiskSave() {
|
|
|
2737
3153
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
2738
3154
|
}
|
|
2739
3155
|
function cacheSet(hash4, value) {
|
|
2740
|
-
|
|
2741
|
-
const firstKey = cache3.keys().next().value;
|
|
2742
|
-
if (firstKey !== void 0) cache3.delete(firstKey);
|
|
2743
|
-
}
|
|
2744
|
-
cache3.set(hash4, value);
|
|
2745
|
-
diskCacheDirty2 = true;
|
|
3156
|
+
cacheInsert(hash4, value, true);
|
|
2746
3157
|
}
|
|
2747
3158
|
function resolveEnvEmbeddingApiKey() {
|
|
2748
3159
|
return process.env.MEMORIX_EMBEDDING_API_KEY;
|
|
@@ -2861,18 +3272,27 @@ async function waitForRetry(waitMs, signal) {
|
|
|
2861
3272
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
2862
3273
|
});
|
|
2863
3274
|
}
|
|
2864
|
-
var cache3,
|
|
3275
|
+
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;
|
|
2865
3276
|
var init_api_provider = __esm({
|
|
2866
3277
|
"src/embedding/api-provider.ts"() {
|
|
2867
3278
|
"use strict";
|
|
2868
3279
|
init_esm_shims();
|
|
2869
3280
|
init_provider();
|
|
2870
3281
|
cache3 = /* @__PURE__ */ new Map();
|
|
2871
|
-
|
|
3282
|
+
MAX_CACHE_ENTRIES = 2e5;
|
|
3283
|
+
MAX_CACHE_PAYLOAD_BYTES = 256 * 1024 * 1024;
|
|
3284
|
+
BYTES_PER_DIM = 8;
|
|
3285
|
+
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
3286
|
+
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
3287
|
+
cachePayloadBytes = 0;
|
|
3288
|
+
cacheDimensions = null;
|
|
3289
|
+
diskCacheEntryCount = 0;
|
|
2872
3290
|
diskCacheDirty2 = false;
|
|
2873
3291
|
diskSaveTimer = null;
|
|
2874
3292
|
diskCacheLoaded = false;
|
|
2875
3293
|
diskCacheLoadPromise = null;
|
|
3294
|
+
diskCacheLoadCount = 0;
|
|
3295
|
+
jsonlLineCountCalls = 0;
|
|
2876
3296
|
MAX_INPUT_CHARS = 32e3;
|
|
2877
3297
|
MAX_CONCURRENCY = 4;
|
|
2878
3298
|
DISK_SAVE_DEBOUNCE_MS = 5e3;
|
|
@@ -2930,7 +3350,9 @@ var init_api_provider = __esm({
|
|
|
2930
3350
|
if (config.requestedDimensions) {
|
|
2931
3351
|
console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);
|
|
2932
3352
|
}
|
|
2933
|
-
|
|
3353
|
+
if (allowNetworkProbe) {
|
|
3354
|
+
startDiskCacheLoad();
|
|
3355
|
+
}
|
|
2934
3356
|
return new _APIEmbeddingProvider(config, probeDimensions);
|
|
2935
3357
|
}
|
|
2936
3358
|
static resolveConfig() {
|
|
@@ -3268,7 +3690,12 @@ function warnOnce(message) {
|
|
|
3268
3690
|
lastEmbeddingWarningAt = now3;
|
|
3269
3691
|
console.error(message);
|
|
3270
3692
|
}
|
|
3693
|
+
function embeddingModeToken() {
|
|
3694
|
+
return process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim() ?? "";
|
|
3695
|
+
}
|
|
3271
3696
|
function getEmbeddingMode2() {
|
|
3697
|
+
const token = embeddingModeToken();
|
|
3698
|
+
if (cachedEmbeddingMode && cachedEmbeddingModeToken === token) return cachedEmbeddingMode;
|
|
3272
3699
|
try {
|
|
3273
3700
|
let cfg;
|
|
3274
3701
|
try {
|
|
@@ -3277,10 +3704,17 @@ function getEmbeddingMode2() {
|
|
|
3277
3704
|
cfg = (init_config(), __toCommonJS(config_exports));
|
|
3278
3705
|
}
|
|
3279
3706
|
const { getEmbeddingMode: cfgMode } = cfg;
|
|
3280
|
-
|
|
3707
|
+
cachedEmbeddingMode = cfgMode();
|
|
3708
|
+
cachedEmbeddingModeToken = token;
|
|
3709
|
+
return cachedEmbeddingMode;
|
|
3281
3710
|
} catch {
|
|
3282
|
-
|
|
3283
|
-
|
|
3711
|
+
if (token === "fastembed" || token === "transformers" || token === "api" || token === "auto") {
|
|
3712
|
+
cachedEmbeddingMode = token;
|
|
3713
|
+
cachedEmbeddingModeToken = token;
|
|
3714
|
+
return token;
|
|
3715
|
+
}
|
|
3716
|
+
cachedEmbeddingMode = "off";
|
|
3717
|
+
cachedEmbeddingModeToken = token;
|
|
3284
3718
|
return "off";
|
|
3285
3719
|
}
|
|
3286
3720
|
}
|
|
@@ -3536,13 +3970,15 @@ function isEmbeddingExplicitlyDisabled() {
|
|
|
3536
3970
|
function resetProvider() {
|
|
3537
3971
|
provider = null;
|
|
3538
3972
|
initPromise = null;
|
|
3973
|
+
cachedEmbeddingMode = null;
|
|
3974
|
+
cachedEmbeddingModeToken = null;
|
|
3539
3975
|
lastInitWasTemporaryFailure = false;
|
|
3540
3976
|
lastFailureTimestamp = 0;
|
|
3541
3977
|
lastEmbeddingFailure = null;
|
|
3542
3978
|
lastEmbeddingWarning = "";
|
|
3543
3979
|
lastEmbeddingWarningAt = 0;
|
|
3544
3980
|
}
|
|
3545
|
-
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
3981
|
+
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, cachedEmbeddingMode, cachedEmbeddingModeToken, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
3546
3982
|
var init_provider = __esm({
|
|
3547
3983
|
"src/embedding/provider.ts"() {
|
|
3548
3984
|
"use strict";
|
|
@@ -3566,6 +4002,8 @@ var init_provider = __esm({
|
|
|
3566
4002
|
MAX_INLINE_EMBEDDING_BYTES = 5 * 1024 * 1024;
|
|
3567
4003
|
provider = null;
|
|
3568
4004
|
initPromise = null;
|
|
4005
|
+
cachedEmbeddingMode = null;
|
|
4006
|
+
cachedEmbeddingModeToken = null;
|
|
3569
4007
|
lastInitWasTemporaryFailure = false;
|
|
3570
4008
|
lastEmbeddingFailure = null;
|
|
3571
4009
|
lastEmbeddingWarning = "";
|
|
@@ -5323,6 +5761,9 @@ async function attachCachedVectors(database, candidates) {
|
|
|
5323
5761
|
await update(database, candidates[index].id, { ...existing, embedding: vector });
|
|
5324
5762
|
} catch {
|
|
5325
5763
|
}
|
|
5764
|
+
if (index % 50 === 0) {
|
|
5765
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
5766
|
+
}
|
|
5326
5767
|
}
|
|
5327
5768
|
}
|
|
5328
5769
|
async function hydrateIndex(observations2, options = {}) {
|
|
@@ -5373,17 +5814,24 @@ async function hydrateIndex(observations2, options = {}) {
|
|
|
5373
5814
|
await insert2(database, doc);
|
|
5374
5815
|
rememberObservationDoc(doc);
|
|
5375
5816
|
inserted++;
|
|
5817
|
+
if (inserted % 50 === 0) {
|
|
5818
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
5819
|
+
}
|
|
5820
|
+
if (inserted % 200 === 0) {
|
|
5821
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
5822
|
+
}
|
|
5376
5823
|
} catch {
|
|
5377
5824
|
}
|
|
5378
5825
|
}
|
|
5379
|
-
deferredCachedVectorHydration = deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
5826
|
+
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
5380
5827
|
}) : null;
|
|
5381
5828
|
return inserted;
|
|
5382
5829
|
}
|
|
5383
|
-
async function hydrateIndexForStartup(observations2) {
|
|
5830
|
+
async function hydrateIndexForStartup(observations2, options = {}) {
|
|
5384
5831
|
return hydrateIndex(observations2, {
|
|
5385
5832
|
allowNetworkProbe: false,
|
|
5386
|
-
deferCachedVectors: true
|
|
5833
|
+
deferCachedVectors: true,
|
|
5834
|
+
skipCachedVectors: options.skipCachedVectors
|
|
5387
5835
|
});
|
|
5388
5836
|
}
|
|
5389
5837
|
function getDeferredCachedVectorHydration() {
|
|
@@ -8502,7 +8950,7 @@ var init_types2 = __esm({
|
|
|
8502
8950
|
|
|
8503
8951
|
// src/media/asset-store.ts
|
|
8504
8952
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
8505
|
-
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename, rm, stat, writeFile as writeFile3 } from "fs/promises";
|
|
8953
|
+
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
8506
8954
|
import path9 from "path";
|
|
8507
8955
|
function mediaRoot(dataDir) {
|
|
8508
8956
|
return path9.resolve(dataDir, "media");
|
|
@@ -8575,7 +9023,7 @@ async function persistBuffer(bytes, destination) {
|
|
|
8575
9023
|
const temporary = `${destination}.${randomUUID5()}.tmp`;
|
|
8576
9024
|
try {
|
|
8577
9025
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
8578
|
-
await
|
|
9026
|
+
await rename2(temporary, destination);
|
|
8579
9027
|
return true;
|
|
8580
9028
|
} catch (error) {
|
|
8581
9029
|
if (error?.code === "EEXIST" && await destinationExists(destination)) return false;
|
|
@@ -59655,9 +60103,9 @@ var require_node_domexception = __commonJS({
|
|
|
59655
60103
|
});
|
|
59656
60104
|
|
|
59657
60105
|
// node_modules/fetch-blob/from.js
|
|
59658
|
-
import { statSync as statSync2, createReadStream, promises as fs7 } from "fs";
|
|
60106
|
+
import { statSync as statSync2, createReadStream as createReadStream2, promises as fs7 } from "fs";
|
|
59659
60107
|
import { basename } from "path";
|
|
59660
|
-
var import_node_domexception,
|
|
60108
|
+
var import_node_domexception, stat3, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
|
|
59661
60109
|
var init_from = __esm({
|
|
59662
60110
|
"node_modules/fetch-blob/from.js"() {
|
|
59663
60111
|
"use strict";
|
|
@@ -59665,23 +60113,23 @@ var init_from = __esm({
|
|
|
59665
60113
|
import_node_domexception = __toESM(require_node_domexception(), 1);
|
|
59666
60114
|
init_file();
|
|
59667
60115
|
init_fetch_blob();
|
|
59668
|
-
({ stat:
|
|
60116
|
+
({ stat: stat3 } = fs7);
|
|
59669
60117
|
blobFromSync = (path21, type) => fromBlob(statSync2(path21), path21, type);
|
|
59670
|
-
blobFrom = (path21, type) =>
|
|
59671
|
-
fileFrom = (path21, type) =>
|
|
60118
|
+
blobFrom = (path21, type) => stat3(path21).then((stat5) => fromBlob(stat5, path21, type));
|
|
60119
|
+
fileFrom = (path21, type) => stat3(path21).then((stat5) => fromFile(stat5, path21, type));
|
|
59672
60120
|
fileFromSync = (path21, type) => fromFile(statSync2(path21), path21, type);
|
|
59673
|
-
fromBlob = (
|
|
60121
|
+
fromBlob = (stat5, path21, type = "") => new fetch_blob_default([new BlobDataItem({
|
|
59674
60122
|
path: path21,
|
|
59675
|
-
size:
|
|
59676
|
-
lastModified:
|
|
60123
|
+
size: stat5.size,
|
|
60124
|
+
lastModified: stat5.mtimeMs,
|
|
59677
60125
|
start: 0
|
|
59678
60126
|
})], { type });
|
|
59679
|
-
fromFile = (
|
|
60127
|
+
fromFile = (stat5, path21, type = "") => new file_default([new BlobDataItem({
|
|
59680
60128
|
path: path21,
|
|
59681
|
-
size:
|
|
59682
|
-
lastModified:
|
|
60129
|
+
size: stat5.size,
|
|
60130
|
+
lastModified: stat5.mtimeMs,
|
|
59683
60131
|
start: 0
|
|
59684
|
-
})], basename(path21), { type, lastModified:
|
|
60132
|
+
})], basename(path21), { type, lastModified: stat5.mtimeMs });
|
|
59685
60133
|
BlobDataItem = class _BlobDataItem {
|
|
59686
60134
|
#path;
|
|
59687
60135
|
#start;
|
|
@@ -59704,11 +60152,11 @@ var init_from = __esm({
|
|
|
59704
60152
|
});
|
|
59705
60153
|
}
|
|
59706
60154
|
async *stream() {
|
|
59707
|
-
const { mtimeMs } = await
|
|
60155
|
+
const { mtimeMs } = await stat3(this.#path);
|
|
59708
60156
|
if (mtimeMs > this.lastModified) {
|
|
59709
60157
|
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");
|
|
59710
60158
|
}
|
|
59711
|
-
yield*
|
|
60159
|
+
yield* createReadStream2(this.#path, {
|
|
59712
60160
|
start: this.#start,
|
|
59713
60161
|
end: this.#start + this.size - 1
|
|
59714
60162
|
});
|
|
@@ -75338,7 +75786,7 @@ var init_wrapper = __esm({
|
|
|
75338
75786
|
});
|
|
75339
75787
|
|
|
75340
75788
|
// node_modules/@google/genai/dist/node/index.mjs
|
|
75341
|
-
import { createWriteStream } from "fs";
|
|
75789
|
+
import { createWriteStream as createWriteStream2 } from "fs";
|
|
75342
75790
|
import * as fs8 from "fs/promises";
|
|
75343
75791
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
75344
75792
|
import { Readable } from "stream";
|
|
@@ -92618,7 +93066,7 @@ ${underline}`);
|
|
|
92618
93066
|
if (params.downloadPath) {
|
|
92619
93067
|
const response = await downloadFile(params, apiClient);
|
|
92620
93068
|
if (response instanceof HttpResponse) {
|
|
92621
|
-
const writer =
|
|
93069
|
+
const writer = createWriteStream2(params.downloadPath);
|
|
92622
93070
|
const body = Readable.fromWeb(response.responseInternal.body);
|
|
92623
93071
|
body.pipe(writer);
|
|
92624
93072
|
await finished(writer);
|
|
@@ -142536,7 +142984,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
142536
142984
|
};
|
|
142537
142985
|
}
|
|
142538
142986
|
function toRetentionDocument(obs, accessMap) {
|
|
142539
|
-
const
|
|
142987
|
+
const access2 = accessMap?.get(obs.id);
|
|
142540
142988
|
return {
|
|
142541
142989
|
id: `obs-${obs.id}`,
|
|
142542
142990
|
observationId: obs.id,
|
|
@@ -142550,8 +142998,8 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
142550
142998
|
tokens: obs.tokens,
|
|
142551
142999
|
createdAt: obs.createdAt,
|
|
142552
143000
|
projectId: obs.projectId,
|
|
142553
|
-
accessCount:
|
|
142554
|
-
lastAccessedAt:
|
|
143001
|
+
accessCount: access2?.accessCount ?? 0,
|
|
143002
|
+
lastAccessedAt: access2?.lastAccessedAt ?? "",
|
|
142555
143003
|
status: obs.status ?? "active",
|
|
142556
143004
|
source: obs.source ?? "agent",
|
|
142557
143005
|
sourceDetail: obs.sourceDetail ?? "",
|
|
@@ -144661,7 +145109,7 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
144661
145109
|
const rel = normalizeCodePath(relative(projectRoot, abs));
|
|
144662
145110
|
try {
|
|
144663
145111
|
const text2 = readFileSync6(abs, "utf-8");
|
|
144664
|
-
const
|
|
145112
|
+
const stat5 = fileStat ?? statSync3(abs);
|
|
144665
145113
|
const file = {
|
|
144666
145114
|
id: makeCodeFileId(projectId, rel),
|
|
144667
145115
|
projectId,
|
|
@@ -144670,8 +145118,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
144670
145118
|
contentHash: hashText(text2),
|
|
144671
145119
|
// Preserve filesystem precision. Rounding here made same-size edits in
|
|
144672
145120
|
// a short Windows timestamp window indistinguishable to refresh.
|
|
144673
|
-
mtimeMs: Number(
|
|
144674
|
-
sizeBytes: Number(
|
|
145121
|
+
mtimeMs: Number(stat5.mtimeMs),
|
|
145122
|
+
sizeBytes: Number(stat5.size),
|
|
144675
145123
|
indexedAt
|
|
144676
145124
|
};
|
|
144677
145125
|
return {
|
|
@@ -144698,18 +145146,18 @@ async function indexProjectLite(options) {
|
|
|
144698
145146
|
let skippedOversizedFiles = 0;
|
|
144699
145147
|
let unreadableFiles = 0;
|
|
144700
145148
|
for (const abs of paths) {
|
|
144701
|
-
let
|
|
145149
|
+
let stat5;
|
|
144702
145150
|
try {
|
|
144703
|
-
|
|
145151
|
+
stat5 = statSync3(abs);
|
|
144704
145152
|
} catch {
|
|
144705
145153
|
unreadableFiles++;
|
|
144706
145154
|
continue;
|
|
144707
145155
|
}
|
|
144708
|
-
if (Number(
|
|
145156
|
+
if (Number(stat5.size) > maxFileBytes) {
|
|
144709
145157
|
skippedOversizedFiles++;
|
|
144710
145158
|
continue;
|
|
144711
145159
|
}
|
|
144712
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
145160
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
144713
145161
|
if (!attempt.delta) {
|
|
144714
145162
|
if (attempt.unreadable) unreadableFiles++;
|
|
144715
145163
|
continue;
|
|
@@ -144737,16 +145185,16 @@ async function refreshProjectLite(store, options) {
|
|
|
144737
145185
|
for (const abs of paths) {
|
|
144738
145186
|
const rel = normalizeCodePath(relative(options.projectRoot, abs));
|
|
144739
145187
|
seenPaths.add(rel);
|
|
144740
|
-
let
|
|
145188
|
+
let stat5;
|
|
144741
145189
|
try {
|
|
144742
|
-
|
|
145190
|
+
stat5 = statSync3(abs);
|
|
144743
145191
|
} catch {
|
|
144744
145192
|
unreadableFiles++;
|
|
144745
145193
|
continue;
|
|
144746
145194
|
}
|
|
144747
145195
|
const existing = existingByPath.get(rel);
|
|
144748
|
-
const mtimeMs = Number(
|
|
144749
|
-
const sizeBytes = Number(
|
|
145196
|
+
const mtimeMs = Number(stat5.mtimeMs);
|
|
145197
|
+
const sizeBytes = Number(stat5.size);
|
|
144750
145198
|
if (sizeBytes > maxFileBytes) {
|
|
144751
145199
|
skippedOversizedFiles++;
|
|
144752
145200
|
if (existing) oversizedExistingFileIds.add(existing.id);
|
|
@@ -144756,7 +145204,7 @@ async function refreshProjectLite(store, options) {
|
|
|
144756
145204
|
unchangedFiles++;
|
|
144757
145205
|
continue;
|
|
144758
145206
|
}
|
|
144759
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
145207
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
144760
145208
|
if (!attempt.delta) {
|
|
144761
145209
|
if (attempt.unreadable) unreadableFiles++;
|
|
144762
145210
|
continue;
|
|
@@ -148153,12 +148601,25 @@ __export(observations_exports, {
|
|
|
148153
148601
|
prepareSearchIndex: () => prepareSearchIndex,
|
|
148154
148602
|
probeSearchIndex: () => probeSearchIndex,
|
|
148155
148603
|
reindexObservations: () => reindexObservations,
|
|
148604
|
+
resetObservationRuntime: () => resetObservationRuntime,
|
|
148156
148605
|
resolveObservations: () => resolveObservations,
|
|
148157
148606
|
storeObservation: () => storeObservation,
|
|
148158
148607
|
suggestTopicKey: () => suggestTopicKey,
|
|
148159
148608
|
updateObservationAdmission: () => updateObservationAdmission,
|
|
148160
148609
|
withFreshObservations: () => withFreshObservations
|
|
148161
148610
|
});
|
|
148611
|
+
function resetObservationRuntime() {
|
|
148612
|
+
observations = [];
|
|
148613
|
+
nextId = 1;
|
|
148614
|
+
projectDir = null;
|
|
148615
|
+
searchIndexPrepared = false;
|
|
148616
|
+
corpusLoaded = false;
|
|
148617
|
+
loadedObservationStore = null;
|
|
148618
|
+
embeddingWriteMode = "background";
|
|
148619
|
+
embeddingWorkerProjectRoot = void 0;
|
|
148620
|
+
vectorMissingIds.clear();
|
|
148621
|
+
vectorSchemaUpgradePromise = null;
|
|
148622
|
+
}
|
|
148162
148623
|
function logEmbeddingFailureOnce(key, message) {
|
|
148163
148624
|
const now3 = Date.now();
|
|
148164
148625
|
const last = embeddingFailureLogTimestamps.get(key) ?? 0;
|
|
@@ -148267,23 +148728,33 @@ async function upgradeVectorSchemaAfterFirstEmbedding(embedding) {
|
|
|
148267
148728
|
async function initObservations(dir, options = {}) {
|
|
148268
148729
|
embeddingWriteMode = options.embeddingWriteMode ?? "background";
|
|
148269
148730
|
embeddingWorkerProjectRoot = options.projectRoot;
|
|
148270
|
-
if (projectDir === dir) return;
|
|
148271
148731
|
await initObservationStore(dir);
|
|
148272
148732
|
const store = getObservationStore();
|
|
148273
|
-
|
|
148733
|
+
if (projectDir === dir && loadedObservationStore === store) {
|
|
148734
|
+
if (options.skipCorpusLoad || corpusLoaded) return;
|
|
148735
|
+
}
|
|
148274
148736
|
nextId = await store.loadIdCounter();
|
|
148275
148737
|
projectDir = dir;
|
|
148276
148738
|
searchIndexPrepared = false;
|
|
148277
148739
|
vectorSchemaUpgradePromise = null;
|
|
148740
|
+
if (options.skipCorpusLoad) {
|
|
148741
|
+
observations = [];
|
|
148742
|
+
corpusLoaded = false;
|
|
148743
|
+
loadedObservationStore = store;
|
|
148744
|
+
return;
|
|
148745
|
+
}
|
|
148746
|
+
observations = await store.loadAll();
|
|
148747
|
+
corpusLoaded = true;
|
|
148748
|
+
loadedObservationStore = store;
|
|
148278
148749
|
}
|
|
148279
148750
|
function scheduleObservationEmbedding(input) {
|
|
148280
148751
|
const { observationId: observationId2, projectId, searchableText, doc } = input;
|
|
148281
148752
|
vectorMissingIds.add(observationId2);
|
|
148753
|
+
if (isEmbeddingExplicitlyDisabled()) {
|
|
148754
|
+
vectorMissingIds.delete(observationId2);
|
|
148755
|
+
return;
|
|
148756
|
+
}
|
|
148282
148757
|
if (embeddingWriteMode === "deferred") {
|
|
148283
|
-
if (isEmbeddingExplicitlyDisabled()) {
|
|
148284
|
-
vectorMissingIds.delete(observationId2);
|
|
148285
|
-
return;
|
|
148286
|
-
}
|
|
148287
148758
|
queueVectorBackfill(projectId, {
|
|
148288
148759
|
detachedWorker: true,
|
|
148289
148760
|
projectRoot: embeddingWorkerProjectRoot
|
|
@@ -148330,7 +148801,7 @@ function scheduleObservationEmbedding(input) {
|
|
|
148330
148801
|
});
|
|
148331
148802
|
}
|
|
148332
148803
|
async function ensureFreshObservations() {
|
|
148333
|
-
if (!projectDir) return false;
|
|
148804
|
+
if (!projectDir || !corpusLoaded) return false;
|
|
148334
148805
|
try {
|
|
148335
148806
|
const store = getObservationStore();
|
|
148336
148807
|
const wasStale = await store.ensureFresh();
|
|
@@ -148371,7 +148842,7 @@ async function storeObservation(input) {
|
|
|
148371
148842
|
});
|
|
148372
148843
|
if (safeAttachments) input = { ...input, attachments: safeAttachments };
|
|
148373
148844
|
await ensureFreshObservations();
|
|
148374
|
-
if (input.topicKey) {
|
|
148845
|
+
if (input.topicKey && corpusLoaded) {
|
|
148375
148846
|
const existing = observations.find(
|
|
148376
148847
|
(o) => o.topicKey === input.topicKey && o.projectId === input.projectId
|
|
148377
148848
|
);
|
|
@@ -148468,13 +148939,17 @@ async function storeObservation(input) {
|
|
|
148468
148939
|
});
|
|
148469
148940
|
observation.writeGeneration = store.getGeneration();
|
|
148470
148941
|
if (upsertedInsideLock || reloadCacheAfterCommit) {
|
|
148471
|
-
|
|
148472
|
-
|
|
148473
|
-
|
|
148474
|
-
|
|
148942
|
+
if (corpusLoaded) {
|
|
148943
|
+
observations = await store.loadAll();
|
|
148944
|
+
nextId = await store.loadIdCounter();
|
|
148945
|
+
if (upsertedInsideLock) {
|
|
148946
|
+
observation = observations.find((candidate) => candidate.id === observation.id) ?? observation;
|
|
148947
|
+
}
|
|
148948
|
+
} else {
|
|
148949
|
+
nextId = await store.loadIdCounter();
|
|
148475
148950
|
}
|
|
148476
148951
|
} else {
|
|
148477
|
-
observations.push(observation);
|
|
148952
|
+
if (corpusLoaded) observations.push(observation);
|
|
148478
148953
|
nextId = observation.id + 1;
|
|
148479
148954
|
}
|
|
148480
148955
|
if (upsertedInsideLock) return;
|
|
@@ -148542,7 +149017,9 @@ async function storeObservation(input) {
|
|
|
148542
149017
|
createdByAgentId: input.createdByAgentId ?? "",
|
|
148543
149018
|
sharedWithAgentIds: JSON.stringify(input.sharedWithAgentIds ?? [])
|
|
148544
149019
|
};
|
|
148545
|
-
|
|
149020
|
+
if (corpusLoaded) {
|
|
149021
|
+
await insertObservation(doc);
|
|
149022
|
+
}
|
|
148546
149023
|
};
|
|
148547
149024
|
await assignAndPersist();
|
|
148548
149025
|
if (upsertedInsideLock) {
|
|
@@ -148904,9 +149381,11 @@ async function reindexObservations() {
|
|
|
148904
149381
|
searchIndexPrepared = true;
|
|
148905
149382
|
return count2;
|
|
148906
149383
|
}
|
|
148907
|
-
async function prepareSearchIndex() {
|
|
149384
|
+
async function prepareSearchIndex(options = {}) {
|
|
148908
149385
|
if (searchIndexPrepared) return 0;
|
|
148909
|
-
const count2 = await hydrateIndexForStartup(observations
|
|
149386
|
+
const count2 = await hydrateIndexForStartup(observations, {
|
|
149387
|
+
skipCachedVectors: options.skipCachedVectors
|
|
149388
|
+
});
|
|
148910
149389
|
if (count2 === 0) {
|
|
148911
149390
|
searchIndexPrepared = true;
|
|
148912
149391
|
return 0;
|
|
@@ -149098,7 +149577,7 @@ async function backfillVectorEmbeddings(options = {}) {
|
|
|
149098
149577
|
...lastFailure ? { lastError: lastFailure } : {}
|
|
149099
149578
|
};
|
|
149100
149579
|
}
|
|
149101
|
-
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
149580
|
+
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
149102
149581
|
var init_observations = __esm({
|
|
149103
149582
|
"src/memory/observations.ts"() {
|
|
149104
149583
|
"use strict";
|
|
@@ -149117,6 +149596,8 @@ var init_observations = __esm({
|
|
|
149117
149596
|
projectDir = null;
|
|
149118
149597
|
searchIndexPrepared = false;
|
|
149119
149598
|
embeddingWriteMode = "background";
|
|
149599
|
+
corpusLoaded = false;
|
|
149600
|
+
loadedObservationStore = null;
|
|
149120
149601
|
vectorMissingIds = /* @__PURE__ */ new Set();
|
|
149121
149602
|
vectorBackfillRunning = false;
|
|
149122
149603
|
vectorSchemaUpgradePromise = null;
|