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
|
@@ -3126,8 +3126,8 @@ async function acquireLock(lockPath) {
|
|
|
3126
3126
|
const code = err instanceof Error && "code" in err ? err.code : void 0;
|
|
3127
3127
|
if (code === "EEXIST" || code === "EPERM") {
|
|
3128
3128
|
try {
|
|
3129
|
-
const
|
|
3130
|
-
if (Date.now() -
|
|
3129
|
+
const stat5 = await fs3.stat(lockPath);
|
|
3130
|
+
if (Date.now() - stat5.mtimeMs > LOCK_STALE_MS) {
|
|
3131
3131
|
await fs3.unlink(lockPath).catch(() => {
|
|
3132
3132
|
});
|
|
3133
3133
|
continue;
|
|
@@ -3583,24 +3583,131 @@ var init_transformers_provider = __esm({
|
|
|
3583
3583
|
// src/embedding/api-provider.ts
|
|
3584
3584
|
var api_provider_exports = {};
|
|
3585
3585
|
__export(api_provider_exports, {
|
|
3586
|
-
APIEmbeddingProvider: () => APIEmbeddingProvider
|
|
3586
|
+
APIEmbeddingProvider: () => APIEmbeddingProvider,
|
|
3587
|
+
convertArrayCacheToJsonl: () => convertArrayCacheToJsonl,
|
|
3588
|
+
ensureDiskCacheLoaded: () => ensureDiskCacheLoaded,
|
|
3589
|
+
getApiEmbeddingCachePayloadBytesForTests: () => getApiEmbeddingCachePayloadBytesForTests,
|
|
3590
|
+
getApiEmbeddingDiskCacheLoadCountForTests: () => getApiEmbeddingDiskCacheLoadCountForTests,
|
|
3591
|
+
getApiEmbeddingJsonlLineCountCallsForTests: () => getApiEmbeddingJsonlLineCountCallsForTests,
|
|
3592
|
+
getApiEmbeddingMaxEntriesForDimensionsForTests: () => getApiEmbeddingMaxEntriesForDimensionsForTests,
|
|
3593
|
+
migrateJsonArrayCacheToJsonl: () => migrateJsonArrayCacheToJsonl,
|
|
3594
|
+
parseCacheJsonInWorker: () => parseCacheJsonInWorker,
|
|
3595
|
+
resetApiEmbeddingCacheForTests: () => resetApiEmbeddingCacheForTests,
|
|
3596
|
+
saveDiskCacheNow: () => saveDiskCacheNow,
|
|
3597
|
+
seedApiEmbeddingCacheForTests: () => seedApiEmbeddingCacheForTests
|
|
3587
3598
|
});
|
|
3588
3599
|
import { createHash as createHash2 } from "crypto";
|
|
3589
|
-
import {
|
|
3600
|
+
import { createReadStream, createWriteStream, constants as fsConstants } from "fs";
|
|
3601
|
+
import { access, readFile as readFile2, writeFile as writeFile2, mkdir as mkdir2, rename, stat, unlink } from "fs/promises";
|
|
3590
3602
|
import { join as join3 } from "path";
|
|
3591
3603
|
import { homedir as homedir7 } from "os";
|
|
3604
|
+
import { createInterface } from "readline";
|
|
3592
3605
|
function cacheDir() {
|
|
3593
3606
|
return process.env.MEMORIX_DATA_DIR || join3(homedir7(), ".memorix", "data");
|
|
3594
3607
|
}
|
|
3595
3608
|
function cacheFile() {
|
|
3596
3609
|
return join3(cacheDir(), ".embedding-api-cache.json");
|
|
3597
3610
|
}
|
|
3611
|
+
function cacheJsonlFile() {
|
|
3612
|
+
return join3(cacheDir(), ".embedding-api-cache.jsonl");
|
|
3613
|
+
}
|
|
3598
3614
|
function dimsCacheFile() {
|
|
3599
3615
|
return join3(cacheDir(), ".embedding-dims-cache.json");
|
|
3600
3616
|
}
|
|
3601
3617
|
function cacheMetaFile() {
|
|
3602
3618
|
return join3(cacheDir(), ".embedding-api-cache-meta.json");
|
|
3603
3619
|
}
|
|
3620
|
+
function cacheStatFile() {
|
|
3621
|
+
return join3(cacheDir(), ".embedding-api-cache-stat.json");
|
|
3622
|
+
}
|
|
3623
|
+
function payloadBytes(vector) {
|
|
3624
|
+
return vector.length * BYTES_PER_DIM;
|
|
3625
|
+
}
|
|
3626
|
+
function maxCachePayloadBytes() {
|
|
3627
|
+
const raw = process.env.MEMORIX_EMBEDDING_CACHE_MAX_BYTES;
|
|
3628
|
+
if (raw) {
|
|
3629
|
+
const parsed = Number.parseInt(raw, 10);
|
|
3630
|
+
if (Number.isFinite(parsed) && parsed > 0) return parsed;
|
|
3631
|
+
}
|
|
3632
|
+
return MAX_CACHE_PAYLOAD_BYTES;
|
|
3633
|
+
}
|
|
3634
|
+
function maxEntriesForDimensions(dimensions) {
|
|
3635
|
+
const dim = Math.max(1, Math.floor(dimensions));
|
|
3636
|
+
const byBytes = Math.floor(maxCachePayloadBytes() / (dim * BYTES_PER_DIM));
|
|
3637
|
+
return Math.max(1, Math.min(MAX_CACHE_ENTRIES, byBytes));
|
|
3638
|
+
}
|
|
3639
|
+
function rememberDimensions(vector) {
|
|
3640
|
+
if (vector.length > 0 && (cacheDimensions === null || vector.length > cacheDimensions)) {
|
|
3641
|
+
cacheDimensions = vector.length;
|
|
3642
|
+
}
|
|
3643
|
+
}
|
|
3644
|
+
function evictOldest() {
|
|
3645
|
+
const firstKey = cache3.keys().next().value;
|
|
3646
|
+
if (firstKey === void 0) return;
|
|
3647
|
+
const old = cache3.get(firstKey);
|
|
3648
|
+
cache3.delete(firstKey);
|
|
3649
|
+
if (old) cachePayloadBytes -= payloadBytes(old);
|
|
3650
|
+
}
|
|
3651
|
+
function evictToFit(incomingBytes, incomingDims) {
|
|
3652
|
+
const limit2 = maxEntriesForDimensions(incomingDims);
|
|
3653
|
+
while (cache3.size > 0 && (cache3.size >= limit2 || cachePayloadBytes + incomingBytes > maxCachePayloadBytes())) {
|
|
3654
|
+
evictOldest();
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
function isNumberArray(value) {
|
|
3658
|
+
return Array.isArray(value) && value.every((entry) => typeof entry === "number");
|
|
3659
|
+
}
|
|
3660
|
+
function parseCacheRow(raw) {
|
|
3661
|
+
if (Array.isArray(raw)) {
|
|
3662
|
+
const hash4 = raw[0];
|
|
3663
|
+
const vector = raw[1];
|
|
3664
|
+
if (typeof hash4 === "string" && isNumberArray(vector)) {
|
|
3665
|
+
return { hash: hash4, vector };
|
|
3666
|
+
}
|
|
3667
|
+
return null;
|
|
3668
|
+
}
|
|
3669
|
+
if (raw && typeof raw === "object") {
|
|
3670
|
+
const row = raw;
|
|
3671
|
+
if (typeof row.h === "string" && isNumberArray(row.v)) {
|
|
3672
|
+
return { hash: row.h, vector: row.v };
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
return null;
|
|
3676
|
+
}
|
|
3677
|
+
function cacheInsert(hash4, value, dirty) {
|
|
3678
|
+
rememberDimensions(value);
|
|
3679
|
+
const incoming = payloadBytes(value);
|
|
3680
|
+
const existing = cache3.get(hash4);
|
|
3681
|
+
if (existing) {
|
|
3682
|
+
cachePayloadBytes -= payloadBytes(existing);
|
|
3683
|
+
cache3.delete(hash4);
|
|
3684
|
+
}
|
|
3685
|
+
evictToFit(incoming, value.length || cacheDimensions || DEFAULT_ASSUMED_DIMENSIONS);
|
|
3686
|
+
cache3.set(hash4, value);
|
|
3687
|
+
cachePayloadBytes += incoming;
|
|
3688
|
+
if (dirty) diskCacheDirty2 = true;
|
|
3689
|
+
}
|
|
3690
|
+
async function readCacheStat() {
|
|
3691
|
+
try {
|
|
3692
|
+
const data = JSON.parse(await readFile2(cacheStatFile(), "utf-8"));
|
|
3693
|
+
if (typeof data.entryCount === "number" && Number.isFinite(data.entryCount) && data.entryCount >= 0) {
|
|
3694
|
+
return {
|
|
3695
|
+
version: 1,
|
|
3696
|
+
entryCount: Math.floor(data.entryCount),
|
|
3697
|
+
dimensions: isValidDimension(data.dimensions) ? data.dimensions : null
|
|
3698
|
+
};
|
|
3699
|
+
}
|
|
3700
|
+
} catch {
|
|
3701
|
+
}
|
|
3702
|
+
return null;
|
|
3703
|
+
}
|
|
3704
|
+
async function writeCacheStat(stat5) {
|
|
3705
|
+
try {
|
|
3706
|
+
await mkdir2(cacheDir(), { recursive: true });
|
|
3707
|
+
await writeFile2(cacheStatFile(), JSON.stringify(stat5));
|
|
3708
|
+
} catch {
|
|
3709
|
+
}
|
|
3710
|
+
}
|
|
3604
3711
|
function normalizeText(text2) {
|
|
3605
3712
|
return text2.replace(/\s+/g, " ").trim().slice(0, MAX_INPUT_CHARS);
|
|
3606
3713
|
}
|
|
@@ -3686,29 +3793,300 @@ function toProviderInput(input, baseUrl) {
|
|
|
3686
3793
|
}
|
|
3687
3794
|
return { type: input.modality, url: input.url };
|
|
3688
3795
|
}
|
|
3796
|
+
function parseCacheJsonInWorker(filePath) {
|
|
3797
|
+
return new Promise((resolve, reject) => {
|
|
3798
|
+
void import("worker_threads").then(({ Worker }) => {
|
|
3799
|
+
const worker = new Worker(
|
|
3800
|
+
`
|
|
3801
|
+
const { parentPort, workerData } = require('node:worker_threads');
|
|
3802
|
+
const { readFileSync } = require('node:fs');
|
|
3803
|
+
try {
|
|
3804
|
+
const raw = readFileSync(workerData.filePath, 'utf8');
|
|
3805
|
+
parentPort.postMessage({ ok: true, entries: JSON.parse(raw) });
|
|
3806
|
+
} catch (err) {
|
|
3807
|
+
parentPort.postMessage({
|
|
3808
|
+
ok: false,
|
|
3809
|
+
error: err instanceof Error ? err.message : String(err),
|
|
3810
|
+
});
|
|
3811
|
+
}
|
|
3812
|
+
`,
|
|
3813
|
+
{ eval: true, workerData: { filePath } }
|
|
3814
|
+
);
|
|
3815
|
+
worker.once("message", (msg) => {
|
|
3816
|
+
void worker.terminate();
|
|
3817
|
+
if (msg?.ok && Array.isArray(msg.entries)) {
|
|
3818
|
+
resolve(msg.entries);
|
|
3819
|
+
return;
|
|
3820
|
+
}
|
|
3821
|
+
reject(new Error(msg?.error || "embedding cache worker parse failed"));
|
|
3822
|
+
});
|
|
3823
|
+
worker.once("error", reject);
|
|
3824
|
+
}).catch(reject);
|
|
3825
|
+
});
|
|
3826
|
+
}
|
|
3827
|
+
function findJsonValueEnd(source) {
|
|
3828
|
+
let i2 = 0;
|
|
3829
|
+
while (i2 < source.length && /\s/.test(source[i2])) i2 += 1;
|
|
3830
|
+
if (i2 >= source.length) return -1;
|
|
3831
|
+
const start = source[i2];
|
|
3832
|
+
if (start === '"') {
|
|
3833
|
+
i2 += 1;
|
|
3834
|
+
while (i2 < source.length) {
|
|
3835
|
+
if (source[i2] === "\\") {
|
|
3836
|
+
i2 += 2;
|
|
3837
|
+
continue;
|
|
3838
|
+
}
|
|
3839
|
+
if (source[i2] === '"') return i2 + 1;
|
|
3840
|
+
i2 += 1;
|
|
3841
|
+
}
|
|
3842
|
+
return -1;
|
|
3843
|
+
}
|
|
3844
|
+
if (start === "{" || start === "[") {
|
|
3845
|
+
const close = start === "{" ? "}" : "]";
|
|
3846
|
+
let depth = 0;
|
|
3847
|
+
let inString = false;
|
|
3848
|
+
for (; i2 < source.length; i2 += 1) {
|
|
3849
|
+
const ch = source[i2];
|
|
3850
|
+
if (inString) {
|
|
3851
|
+
if (ch === "\\") {
|
|
3852
|
+
i2 += 1;
|
|
3853
|
+
continue;
|
|
3854
|
+
}
|
|
3855
|
+
if (ch === '"') inString = false;
|
|
3856
|
+
continue;
|
|
3857
|
+
}
|
|
3858
|
+
if (ch === '"') {
|
|
3859
|
+
inString = true;
|
|
3860
|
+
continue;
|
|
3861
|
+
}
|
|
3862
|
+
if (ch === start) depth += 1;
|
|
3863
|
+
else if (ch === close) {
|
|
3864
|
+
depth -= 1;
|
|
3865
|
+
if (depth === 0) return i2 + 1;
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
return -1;
|
|
3869
|
+
}
|
|
3870
|
+
const rest = source.slice(i2);
|
|
3871
|
+
const match2 = rest.match(/^(?:-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?|true|false|null)/);
|
|
3872
|
+
return match2 ? i2 + match2[0].length : -1;
|
|
3873
|
+
}
|
|
3874
|
+
async function streamJsonArrayToJsonl(filePath, tmpPath) {
|
|
3875
|
+
const input = createReadStream(filePath, { encoding: "utf8" });
|
|
3876
|
+
const out = createWriteStream(tmpPath);
|
|
3877
|
+
let buf = "";
|
|
3878
|
+
let started = false;
|
|
3879
|
+
let count2 = 0;
|
|
3880
|
+
const writeLine = async (line) => {
|
|
3881
|
+
if (!out.write(line)) {
|
|
3882
|
+
await new Promise((resolve, reject) => {
|
|
3883
|
+
out.once("drain", resolve);
|
|
3884
|
+
out.once("error", reject);
|
|
3885
|
+
});
|
|
3886
|
+
}
|
|
3887
|
+
};
|
|
3888
|
+
try {
|
|
3889
|
+
for await (const chunk of input) {
|
|
3890
|
+
buf += chunk;
|
|
3891
|
+
if (!started) {
|
|
3892
|
+
const idx = buf.search(/\S/);
|
|
3893
|
+
if (idx < 0) continue;
|
|
3894
|
+
if (buf[idx] !== "[") throw new Error("embedding cache is not a JSON array");
|
|
3895
|
+
buf = buf.slice(idx + 1);
|
|
3896
|
+
started = true;
|
|
3897
|
+
}
|
|
3898
|
+
while (true) {
|
|
3899
|
+
buf = buf.replace(/^\s*,?\s*/, "");
|
|
3900
|
+
if (!buf) break;
|
|
3901
|
+
if (buf[0] === "]") {
|
|
3902
|
+
buf = "";
|
|
3903
|
+
break;
|
|
3904
|
+
}
|
|
3905
|
+
const end = findJsonValueEnd(buf);
|
|
3906
|
+
if (end < 0) break;
|
|
3907
|
+
const value = JSON.parse(buf.slice(0, end));
|
|
3908
|
+
buf = buf.slice(end);
|
|
3909
|
+
const row = parseCacheRow(value);
|
|
3910
|
+
if (row) {
|
|
3911
|
+
await writeLine(`${JSON.stringify({ h: row.hash, v: row.vector })}
|
|
3912
|
+
`);
|
|
3913
|
+
count2 += 1;
|
|
3914
|
+
if (count2 % 50 === 0) {
|
|
3915
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
3916
|
+
}
|
|
3917
|
+
}
|
|
3918
|
+
}
|
|
3919
|
+
if (buf.length > MAX_MIGRATION_VALUE_BYTES) {
|
|
3920
|
+
throw new Error("embedding cache entry too large to migrate safely");
|
|
3921
|
+
}
|
|
3922
|
+
}
|
|
3923
|
+
} finally {
|
|
3924
|
+
await new Promise((resolve, reject) => {
|
|
3925
|
+
out.end(() => resolve());
|
|
3926
|
+
out.once("error", reject);
|
|
3927
|
+
});
|
|
3928
|
+
}
|
|
3929
|
+
return count2;
|
|
3930
|
+
}
|
|
3931
|
+
async function migrateJsonArrayCacheToJsonl(filePath, jsonlPath) {
|
|
3932
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
3933
|
+
try {
|
|
3934
|
+
const count2 = await streamJsonArrayToJsonl(filePath, tmpPath);
|
|
3935
|
+
await rename(tmpPath, jsonlPath);
|
|
3936
|
+
diskCacheEntryCount = count2;
|
|
3937
|
+
await writeCacheStat({
|
|
3938
|
+
version: 1,
|
|
3939
|
+
entryCount: count2,
|
|
3940
|
+
dimensions: cacheDimensions
|
|
3941
|
+
});
|
|
3942
|
+
return count2;
|
|
3943
|
+
} catch (err) {
|
|
3944
|
+
await unlink(tmpPath).catch(() => void 0);
|
|
3945
|
+
throw err;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
function convertArrayCacheToJsonl(filePath, jsonlPath) {
|
|
3949
|
+
return migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
3950
|
+
}
|
|
3951
|
+
async function loadCacheJsonl(filePath) {
|
|
3952
|
+
const rl = createInterface({
|
|
3953
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
3954
|
+
crlfDelay: Infinity
|
|
3955
|
+
});
|
|
3956
|
+
let loaded = 0;
|
|
3957
|
+
let onDiskCount = 0;
|
|
3958
|
+
for await (const line of rl) {
|
|
3959
|
+
const trimmed = line.trim();
|
|
3960
|
+
if (!trimmed) continue;
|
|
3961
|
+
try {
|
|
3962
|
+
const row = parseCacheRow(JSON.parse(trimmed));
|
|
3963
|
+
if (!row) continue;
|
|
3964
|
+
onDiskCount += 1;
|
|
3965
|
+
cacheInsert(row.hash, row.vector, false);
|
|
3966
|
+
loaded = cache3.size;
|
|
3967
|
+
} catch {
|
|
3968
|
+
}
|
|
3969
|
+
if (onDiskCount % 250 === 0) {
|
|
3970
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
diskCacheEntryCount = onDiskCount;
|
|
3974
|
+
await writeCacheStat({
|
|
3975
|
+
version: 1,
|
|
3976
|
+
entryCount: onDiskCount,
|
|
3977
|
+
dimensions: cacheDimensions
|
|
3978
|
+
});
|
|
3979
|
+
return loaded;
|
|
3980
|
+
}
|
|
3981
|
+
async function countJsonlLines(filePath) {
|
|
3982
|
+
jsonlLineCountCalls += 1;
|
|
3983
|
+
try {
|
|
3984
|
+
const rl = createInterface({
|
|
3985
|
+
input: createReadStream(filePath, { encoding: "utf8" }),
|
|
3986
|
+
crlfDelay: Infinity
|
|
3987
|
+
});
|
|
3988
|
+
let count2 = 0;
|
|
3989
|
+
for await (const line of rl) {
|
|
3990
|
+
if (line.trim()) count2 += 1;
|
|
3991
|
+
}
|
|
3992
|
+
return count2;
|
|
3993
|
+
} catch {
|
|
3994
|
+
return 0;
|
|
3995
|
+
}
|
|
3996
|
+
}
|
|
3997
|
+
async function resolveOnDiskCount(jsonlPath) {
|
|
3998
|
+
if (diskCacheEntryCount > 0) return diskCacheEntryCount;
|
|
3999
|
+
const sidecar = await readCacheStat();
|
|
4000
|
+
if (sidecar) {
|
|
4001
|
+
diskCacheEntryCount = sidecar.entryCount;
|
|
4002
|
+
if (sidecar.dimensions && cacheDimensions === null) cacheDimensions = sidecar.dimensions;
|
|
4003
|
+
return sidecar.entryCount;
|
|
4004
|
+
}
|
|
4005
|
+
try {
|
|
4006
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
4007
|
+
} catch {
|
|
4008
|
+
return 0;
|
|
4009
|
+
}
|
|
4010
|
+
const counted = await countJsonlLines(jsonlPath);
|
|
4011
|
+
diskCacheEntryCount = counted;
|
|
4012
|
+
await writeCacheStat({
|
|
4013
|
+
version: 1,
|
|
4014
|
+
entryCount: counted,
|
|
4015
|
+
dimensions: cacheDimensions
|
|
4016
|
+
});
|
|
4017
|
+
return counted;
|
|
4018
|
+
}
|
|
3689
4019
|
async function loadDiskCache2() {
|
|
3690
|
-
if (diskCacheLoaded) return;
|
|
4020
|
+
if (diskCacheLoaded) return cache3.size;
|
|
4021
|
+
let loaded = 0;
|
|
3691
4022
|
try {
|
|
3692
|
-
const
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
4023
|
+
const jsonlPath = cacheJsonlFile();
|
|
4024
|
+
let hasJsonl = false;
|
|
4025
|
+
try {
|
|
4026
|
+
await access(jsonlPath, fsConstants.R_OK);
|
|
4027
|
+
hasJsonl = true;
|
|
4028
|
+
} catch {
|
|
4029
|
+
hasJsonl = false;
|
|
4030
|
+
}
|
|
4031
|
+
if (hasJsonl) {
|
|
4032
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
4033
|
+
} else {
|
|
4034
|
+
const filePath = cacheFile();
|
|
4035
|
+
await stat(filePath);
|
|
4036
|
+
await migrateJsonArrayCacheToJsonl(filePath, jsonlPath);
|
|
4037
|
+
loaded = await loadCacheJsonl(jsonlPath);
|
|
4038
|
+
}
|
|
4039
|
+
diskCacheLoadCount += 1;
|
|
4040
|
+
console.error(`[memorix] Loaded ${loaded} cached API embeddings from disk`);
|
|
3696
4041
|
} catch {
|
|
3697
4042
|
}
|
|
3698
4043
|
diskCacheLoaded = true;
|
|
4044
|
+
return loaded;
|
|
3699
4045
|
}
|
|
3700
4046
|
function startDiskCacheLoad() {
|
|
3701
4047
|
if (diskCacheLoaded || diskCacheLoadPromise) return;
|
|
3702
|
-
diskCacheLoadPromise = loadDiskCache2().catch(() => {
|
|
4048
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
3703
4049
|
});
|
|
3704
4050
|
}
|
|
3705
4051
|
async function ensureDiskCacheLoaded() {
|
|
3706
|
-
if (diskCacheLoaded) return;
|
|
3707
|
-
if (diskCacheLoadPromise) {
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
}
|
|
3711
|
-
await
|
|
4052
|
+
if (diskCacheLoaded) return cache3.size;
|
|
4053
|
+
if (!diskCacheLoadPromise) {
|
|
4054
|
+
diskCacheLoadPromise = loadDiskCache2().then(() => void 0).catch(() => {
|
|
4055
|
+
});
|
|
4056
|
+
}
|
|
4057
|
+
await diskCacheLoadPromise;
|
|
4058
|
+
return cache3.size;
|
|
4059
|
+
}
|
|
4060
|
+
function getApiEmbeddingDiskCacheLoadCountForTests() {
|
|
4061
|
+
return diskCacheLoadCount;
|
|
4062
|
+
}
|
|
4063
|
+
function resetApiEmbeddingCacheForTests() {
|
|
4064
|
+
cache3.clear();
|
|
4065
|
+
cachePayloadBytes = 0;
|
|
4066
|
+
cacheDimensions = null;
|
|
4067
|
+
diskCacheEntryCount = 0;
|
|
4068
|
+
diskCacheLoaded = false;
|
|
4069
|
+
diskCacheLoadPromise = null;
|
|
4070
|
+
diskCacheLoadCount = 0;
|
|
4071
|
+
diskCacheDirty2 = false;
|
|
4072
|
+
jsonlLineCountCalls = 0;
|
|
4073
|
+
}
|
|
4074
|
+
function seedApiEmbeddingCacheForTests(entries) {
|
|
4075
|
+
cache3.clear();
|
|
4076
|
+
cachePayloadBytes = 0;
|
|
4077
|
+
cacheDimensions = null;
|
|
4078
|
+
for (const [key, value] of entries) cacheInsert(key, value, true);
|
|
4079
|
+
diskCacheLoaded = true;
|
|
4080
|
+
diskCacheDirty2 = true;
|
|
4081
|
+
}
|
|
4082
|
+
function getApiEmbeddingCachePayloadBytesForTests() {
|
|
4083
|
+
return cachePayloadBytes;
|
|
4084
|
+
}
|
|
4085
|
+
function getApiEmbeddingJsonlLineCountCallsForTests() {
|
|
4086
|
+
return jsonlLineCountCalls;
|
|
4087
|
+
}
|
|
4088
|
+
function getApiEmbeddingMaxEntriesForDimensionsForTests(dimensions) {
|
|
4089
|
+
return maxEntriesForDimensions(dimensions);
|
|
3712
4090
|
}
|
|
3713
4091
|
function dimsCacheKey(config) {
|
|
3714
4092
|
return [
|
|
@@ -3824,8 +4202,46 @@ async function saveDiskCacheNow() {
|
|
|
3824
4202
|
if (!diskCacheDirty2) return;
|
|
3825
4203
|
try {
|
|
3826
4204
|
await mkdir2(cacheDir(), { recursive: true });
|
|
3827
|
-
const
|
|
3828
|
-
await
|
|
4205
|
+
const jsonlPath = cacheJsonlFile();
|
|
4206
|
+
const existing = await resolveOnDiskCount(jsonlPath);
|
|
4207
|
+
if (existing > 0 && cache3.size < Math.ceil(existing * 0.5)) {
|
|
4208
|
+
console.error(
|
|
4209
|
+
`[memorix] Refusing to overwrite embedding cache (${existing} on disk vs ${cache3.size} in memory)`
|
|
4210
|
+
);
|
|
4211
|
+
diskCacheDirty2 = false;
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4214
|
+
const tmpPath = `${jsonlPath}.tmp`;
|
|
4215
|
+
await new Promise((resolve, reject) => {
|
|
4216
|
+
const out = createWriteStream(tmpPath);
|
|
4217
|
+
const entries = cache3.entries();
|
|
4218
|
+
const writeBatch = () => {
|
|
4219
|
+
for (let i2 = 0; i2 < 50; i2++) {
|
|
4220
|
+
const next = entries.next();
|
|
4221
|
+
if (next.done) {
|
|
4222
|
+
out.end();
|
|
4223
|
+
return;
|
|
4224
|
+
}
|
|
4225
|
+
const [hash4, vector] = next.value;
|
|
4226
|
+
if (!out.write(`${JSON.stringify({ h: hash4, v: vector })}
|
|
4227
|
+
`)) {
|
|
4228
|
+
out.once("drain", writeBatch);
|
|
4229
|
+
return;
|
|
4230
|
+
}
|
|
4231
|
+
}
|
|
4232
|
+
setImmediate(writeBatch);
|
|
4233
|
+
};
|
|
4234
|
+
out.on("finish", resolve);
|
|
4235
|
+
out.on("error", reject);
|
|
4236
|
+
writeBatch();
|
|
4237
|
+
});
|
|
4238
|
+
await rename(tmpPath, jsonlPath);
|
|
4239
|
+
diskCacheEntryCount = cache3.size;
|
|
4240
|
+
await writeCacheStat({
|
|
4241
|
+
version: 1,
|
|
4242
|
+
entryCount: cache3.size,
|
|
4243
|
+
dimensions: cacheDimensions
|
|
4244
|
+
});
|
|
3829
4245
|
diskCacheDirty2 = false;
|
|
3830
4246
|
} catch {
|
|
3831
4247
|
}
|
|
@@ -3839,12 +4255,7 @@ function scheduleDiskSave() {
|
|
|
3839
4255
|
}, DISK_SAVE_DEBOUNCE_MS);
|
|
3840
4256
|
}
|
|
3841
4257
|
function cacheSet(hash4, value) {
|
|
3842
|
-
|
|
3843
|
-
const firstKey = cache3.keys().next().value;
|
|
3844
|
-
if (firstKey !== void 0) cache3.delete(firstKey);
|
|
3845
|
-
}
|
|
3846
|
-
cache3.set(hash4, value);
|
|
3847
|
-
diskCacheDirty2 = true;
|
|
4258
|
+
cacheInsert(hash4, value, true);
|
|
3848
4259
|
}
|
|
3849
4260
|
function resolveEnvEmbeddingApiKey() {
|
|
3850
4261
|
return process.env.MEMORIX_EMBEDDING_API_KEY;
|
|
@@ -3963,18 +4374,27 @@ async function waitForRetry(waitMs, signal) {
|
|
|
3963
4374
|
abortSignal.addEventListener("abort", onAbort, { once: true });
|
|
3964
4375
|
});
|
|
3965
4376
|
}
|
|
3966
|
-
var cache3,
|
|
4377
|
+
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;
|
|
3967
4378
|
var init_api_provider = __esm({
|
|
3968
4379
|
"src/embedding/api-provider.ts"() {
|
|
3969
4380
|
"use strict";
|
|
3970
4381
|
init_esm_shims();
|
|
3971
4382
|
init_provider2();
|
|
3972
4383
|
cache3 = /* @__PURE__ */ new Map();
|
|
3973
|
-
|
|
4384
|
+
MAX_CACHE_ENTRIES = 2e5;
|
|
4385
|
+
MAX_CACHE_PAYLOAD_BYTES = 256 * 1024 * 1024;
|
|
4386
|
+
BYTES_PER_DIM = 8;
|
|
4387
|
+
DEFAULT_ASSUMED_DIMENSIONS = 4096;
|
|
4388
|
+
MAX_MIGRATION_VALUE_BYTES = 16 * 1024 * 1024;
|
|
4389
|
+
cachePayloadBytes = 0;
|
|
4390
|
+
cacheDimensions = null;
|
|
4391
|
+
diskCacheEntryCount = 0;
|
|
3974
4392
|
diskCacheDirty2 = false;
|
|
3975
4393
|
diskSaveTimer = null;
|
|
3976
4394
|
diskCacheLoaded = false;
|
|
3977
4395
|
diskCacheLoadPromise = null;
|
|
4396
|
+
diskCacheLoadCount = 0;
|
|
4397
|
+
jsonlLineCountCalls = 0;
|
|
3978
4398
|
MAX_INPUT_CHARS = 32e3;
|
|
3979
4399
|
MAX_CONCURRENCY = 4;
|
|
3980
4400
|
DISK_SAVE_DEBOUNCE_MS = 5e3;
|
|
@@ -4032,7 +4452,9 @@ var init_api_provider = __esm({
|
|
|
4032
4452
|
if (config.requestedDimensions) {
|
|
4033
4453
|
console.error(`[memorix] Dimension shortening: ${config.requestedDimensions}d requested`);
|
|
4034
4454
|
}
|
|
4035
|
-
|
|
4455
|
+
if (allowNetworkProbe) {
|
|
4456
|
+
startDiskCacheLoad();
|
|
4457
|
+
}
|
|
4036
4458
|
return new _APIEmbeddingProvider(config, probeDimensions);
|
|
4037
4459
|
}
|
|
4038
4460
|
static resolveConfig() {
|
|
@@ -4370,7 +4792,12 @@ function warnOnce(message) {
|
|
|
4370
4792
|
lastEmbeddingWarningAt = now3;
|
|
4371
4793
|
console.error(message);
|
|
4372
4794
|
}
|
|
4795
|
+
function embeddingModeToken() {
|
|
4796
|
+
return process.env.MEMORIX_EMBEDDING?.toLowerCase()?.trim() ?? "";
|
|
4797
|
+
}
|
|
4373
4798
|
function getEmbeddingMode2() {
|
|
4799
|
+
const token = embeddingModeToken();
|
|
4800
|
+
if (cachedEmbeddingMode && cachedEmbeddingModeToken === token) return cachedEmbeddingMode;
|
|
4374
4801
|
try {
|
|
4375
4802
|
let cfg;
|
|
4376
4803
|
try {
|
|
@@ -4379,10 +4806,17 @@ function getEmbeddingMode2() {
|
|
|
4379
4806
|
cfg = (init_config(), __toCommonJS(config_exports));
|
|
4380
4807
|
}
|
|
4381
4808
|
const { getEmbeddingMode: cfgMode } = cfg;
|
|
4382
|
-
|
|
4809
|
+
cachedEmbeddingMode = cfgMode();
|
|
4810
|
+
cachedEmbeddingModeToken = token;
|
|
4811
|
+
return cachedEmbeddingMode;
|
|
4383
4812
|
} catch {
|
|
4384
|
-
|
|
4385
|
-
|
|
4813
|
+
if (token === "fastembed" || token === "transformers" || token === "api" || token === "auto") {
|
|
4814
|
+
cachedEmbeddingMode = token;
|
|
4815
|
+
cachedEmbeddingModeToken = token;
|
|
4816
|
+
return token;
|
|
4817
|
+
}
|
|
4818
|
+
cachedEmbeddingMode = "off";
|
|
4819
|
+
cachedEmbeddingModeToken = token;
|
|
4386
4820
|
return "off";
|
|
4387
4821
|
}
|
|
4388
4822
|
}
|
|
@@ -4638,13 +5072,15 @@ function isEmbeddingExplicitlyDisabled() {
|
|
|
4638
5072
|
function resetProvider() {
|
|
4639
5073
|
provider = null;
|
|
4640
5074
|
initPromise = null;
|
|
5075
|
+
cachedEmbeddingMode = null;
|
|
5076
|
+
cachedEmbeddingModeToken = null;
|
|
4641
5077
|
lastInitWasTemporaryFailure = false;
|
|
4642
5078
|
lastFailureTimestamp = 0;
|
|
4643
5079
|
lastEmbeddingFailure = null;
|
|
4644
5080
|
lastEmbeddingWarning = "";
|
|
4645
5081
|
lastEmbeddingWarningAt = 0;
|
|
4646
5082
|
}
|
|
4647
|
-
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
5083
|
+
var EmbeddingInputError, UnsupportedEmbeddingModalityError, MAX_INLINE_EMBEDDING_BYTES, provider, initPromise, cachedEmbeddingMode, cachedEmbeddingModeToken, lastInitWasTemporaryFailure, lastEmbeddingFailure, lastEmbeddingWarning, lastEmbeddingWarningAt, WARNING_COOLDOWN_MS, RETRY_COOLDOWN_MS, lastFailureTimestamp;
|
|
4648
5084
|
var init_provider2 = __esm({
|
|
4649
5085
|
"src/embedding/provider.ts"() {
|
|
4650
5086
|
"use strict";
|
|
@@ -4668,6 +5104,8 @@ var init_provider2 = __esm({
|
|
|
4668
5104
|
MAX_INLINE_EMBEDDING_BYTES = 5 * 1024 * 1024;
|
|
4669
5105
|
provider = null;
|
|
4670
5106
|
initPromise = null;
|
|
5107
|
+
cachedEmbeddingMode = null;
|
|
5108
|
+
cachedEmbeddingModeToken = null;
|
|
4671
5109
|
lastInitWasTemporaryFailure = false;
|
|
4672
5110
|
lastEmbeddingFailure = null;
|
|
4673
5111
|
lastEmbeddingWarning = "";
|
|
@@ -5809,6 +6247,9 @@ async function attachCachedVectors(database, candidates) {
|
|
|
5809
6247
|
await update(database, candidates[index].id, { ...existing, embedding: vector });
|
|
5810
6248
|
} catch {
|
|
5811
6249
|
}
|
|
6250
|
+
if (index % 50 === 0) {
|
|
6251
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
6252
|
+
}
|
|
5812
6253
|
}
|
|
5813
6254
|
}
|
|
5814
6255
|
async function hydrateIndex(observations2, options = {}) {
|
|
@@ -5859,17 +6300,24 @@ async function hydrateIndex(observations2, options = {}) {
|
|
|
5859
6300
|
await insert2(database, doc);
|
|
5860
6301
|
rememberObservationDoc(doc);
|
|
5861
6302
|
inserted++;
|
|
6303
|
+
if (inserted % 50 === 0) {
|
|
6304
|
+
await new Promise((resolve) => setImmediate(resolve));
|
|
6305
|
+
}
|
|
6306
|
+
if (inserted % 200 === 0) {
|
|
6307
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
6308
|
+
}
|
|
5862
6309
|
} catch {
|
|
5863
6310
|
}
|
|
5864
6311
|
}
|
|
5865
|
-
deferredCachedVectorHydration = deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
6312
|
+
deferredCachedVectorHydration = options.skipCachedVectors ? null : deferCachedVectors ? attachCachedVectors(database, candidates).catch(() => {
|
|
5866
6313
|
}) : null;
|
|
5867
6314
|
return inserted;
|
|
5868
6315
|
}
|
|
5869
|
-
async function hydrateIndexForStartup(observations2) {
|
|
6316
|
+
async function hydrateIndexForStartup(observations2, options = {}) {
|
|
5870
6317
|
return hydrateIndex(observations2, {
|
|
5871
6318
|
allowNetworkProbe: false,
|
|
5872
|
-
deferCachedVectors: true
|
|
6319
|
+
deferCachedVectors: true,
|
|
6320
|
+
skipCachedVectors: options.skipCachedVectors
|
|
5873
6321
|
});
|
|
5874
6322
|
}
|
|
5875
6323
|
function getDeferredCachedVectorHydration() {
|
|
@@ -8531,7 +8979,7 @@ var init_types2 = __esm({
|
|
|
8531
8979
|
|
|
8532
8980
|
// src/media/asset-store.ts
|
|
8533
8981
|
import { createHash as createHash4, randomUUID as randomUUID5 } from "crypto";
|
|
8534
|
-
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename, rm, stat, writeFile as writeFile3 } from "fs/promises";
|
|
8982
|
+
import { copyFile, lstat, mkdir as mkdir3, open, readFile as readFile3, readdir, rename as rename2, rm, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
8535
8983
|
import path10 from "path";
|
|
8536
8984
|
function mediaRoot(dataDir) {
|
|
8537
8985
|
return path10.resolve(dataDir, "media");
|
|
@@ -8604,7 +9052,7 @@ async function persistBuffer(bytes, destination) {
|
|
|
8604
9052
|
const temporary = `${destination}.${randomUUID5()}.tmp`;
|
|
8605
9053
|
try {
|
|
8606
9054
|
await writeFile3(temporary, bytes, { flag: "wx" });
|
|
8607
|
-
await
|
|
9055
|
+
await rename2(temporary, destination);
|
|
8608
9056
|
return true;
|
|
8609
9057
|
} catch (error) {
|
|
8610
9058
|
if (error?.code === "EEXIST" && await destinationExists(destination)) return false;
|
|
@@ -59684,9 +60132,9 @@ var require_node_domexception = __commonJS({
|
|
|
59684
60132
|
});
|
|
59685
60133
|
|
|
59686
60134
|
// node_modules/fetch-blob/from.js
|
|
59687
|
-
import { statSync as statSync2, createReadStream, promises as fs7 } from "fs";
|
|
60135
|
+
import { statSync as statSync2, createReadStream as createReadStream2, promises as fs7 } from "fs";
|
|
59688
60136
|
import { basename } from "path";
|
|
59689
|
-
var import_node_domexception,
|
|
60137
|
+
var import_node_domexception, stat3, blobFromSync, blobFrom, fileFrom, fileFromSync, fromBlob, fromFile, BlobDataItem;
|
|
59690
60138
|
var init_from = __esm({
|
|
59691
60139
|
"node_modules/fetch-blob/from.js"() {
|
|
59692
60140
|
"use strict";
|
|
@@ -59694,23 +60142,23 @@ var init_from = __esm({
|
|
|
59694
60142
|
import_node_domexception = __toESM(require_node_domexception(), 1);
|
|
59695
60143
|
init_file();
|
|
59696
60144
|
init_fetch_blob();
|
|
59697
|
-
({ stat:
|
|
60145
|
+
({ stat: stat3 } = fs7);
|
|
59698
60146
|
blobFromSync = (path21, type) => fromBlob(statSync2(path21), path21, type);
|
|
59699
|
-
blobFrom = (path21, type) =>
|
|
59700
|
-
fileFrom = (path21, type) =>
|
|
60147
|
+
blobFrom = (path21, type) => stat3(path21).then((stat5) => fromBlob(stat5, path21, type));
|
|
60148
|
+
fileFrom = (path21, type) => stat3(path21).then((stat5) => fromFile(stat5, path21, type));
|
|
59701
60149
|
fileFromSync = (path21, type) => fromFile(statSync2(path21), path21, type);
|
|
59702
|
-
fromBlob = (
|
|
60150
|
+
fromBlob = (stat5, path21, type = "") => new fetch_blob_default([new BlobDataItem({
|
|
59703
60151
|
path: path21,
|
|
59704
|
-
size:
|
|
59705
|
-
lastModified:
|
|
60152
|
+
size: stat5.size,
|
|
60153
|
+
lastModified: stat5.mtimeMs,
|
|
59706
60154
|
start: 0
|
|
59707
60155
|
})], { type });
|
|
59708
|
-
fromFile = (
|
|
60156
|
+
fromFile = (stat5, path21, type = "") => new file_default([new BlobDataItem({
|
|
59709
60157
|
path: path21,
|
|
59710
|
-
size:
|
|
59711
|
-
lastModified:
|
|
60158
|
+
size: stat5.size,
|
|
60159
|
+
lastModified: stat5.mtimeMs,
|
|
59712
60160
|
start: 0
|
|
59713
|
-
})], basename(path21), { type, lastModified:
|
|
60161
|
+
})], basename(path21), { type, lastModified: stat5.mtimeMs });
|
|
59714
60162
|
BlobDataItem = class _BlobDataItem {
|
|
59715
60163
|
#path;
|
|
59716
60164
|
#start;
|
|
@@ -59733,11 +60181,11 @@ var init_from = __esm({
|
|
|
59733
60181
|
});
|
|
59734
60182
|
}
|
|
59735
60183
|
async *stream() {
|
|
59736
|
-
const { mtimeMs } = await
|
|
60184
|
+
const { mtimeMs } = await stat3(this.#path);
|
|
59737
60185
|
if (mtimeMs > this.lastModified) {
|
|
59738
60186
|
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");
|
|
59739
60187
|
}
|
|
59740
|
-
yield*
|
|
60188
|
+
yield* createReadStream2(this.#path, {
|
|
59741
60189
|
start: this.#start,
|
|
59742
60190
|
end: this.#start + this.size - 1
|
|
59743
60191
|
});
|
|
@@ -75367,7 +75815,7 @@ var init_wrapper = __esm({
|
|
|
75367
75815
|
});
|
|
75368
75816
|
|
|
75369
75817
|
// node_modules/@google/genai/dist/node/index.mjs
|
|
75370
|
-
import { createWriteStream } from "fs";
|
|
75818
|
+
import { createWriteStream as createWriteStream2 } from "fs";
|
|
75371
75819
|
import * as fs8 from "fs/promises";
|
|
75372
75820
|
import { writeFile as writeFile4 } from "fs/promises";
|
|
75373
75821
|
import { Readable } from "stream";
|
|
@@ -92647,7 +93095,7 @@ ${underline}`);
|
|
|
92647
93095
|
if (params.downloadPath) {
|
|
92648
93096
|
const response = await downloadFile(params, apiClient);
|
|
92649
93097
|
if (response instanceof HttpResponse) {
|
|
92650
|
-
const writer =
|
|
93098
|
+
const writer = createWriteStream2(params.downloadPath);
|
|
92651
93099
|
const body = Readable.fromWeb(response.responseInternal.body);
|
|
92652
93100
|
body.pipe(writer);
|
|
92653
93101
|
await finished(writer);
|
|
@@ -142565,7 +143013,7 @@ function explainRetention(doc, referenceTime) {
|
|
|
142565
143013
|
};
|
|
142566
143014
|
}
|
|
142567
143015
|
function toRetentionDocument(obs, accessMap) {
|
|
142568
|
-
const
|
|
143016
|
+
const access2 = accessMap?.get(obs.id);
|
|
142569
143017
|
return {
|
|
142570
143018
|
id: `obs-${obs.id}`,
|
|
142571
143019
|
observationId: obs.id,
|
|
@@ -142579,8 +143027,8 @@ function toRetentionDocument(obs, accessMap) {
|
|
|
142579
143027
|
tokens: obs.tokens,
|
|
142580
143028
|
createdAt: obs.createdAt,
|
|
142581
143029
|
projectId: obs.projectId,
|
|
142582
|
-
accessCount:
|
|
142583
|
-
lastAccessedAt:
|
|
143030
|
+
accessCount: access2?.accessCount ?? 0,
|
|
143031
|
+
lastAccessedAt: access2?.lastAccessedAt ?? "",
|
|
142584
143032
|
status: obs.status ?? "active",
|
|
142585
143033
|
source: obs.source ?? "agent",
|
|
142586
143034
|
sourceDetail: obs.sourceDetail ?? "",
|
|
@@ -144690,7 +145138,7 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
144690
145138
|
const rel = normalizeCodePath(relative(projectRoot, abs));
|
|
144691
145139
|
try {
|
|
144692
145140
|
const text2 = readFileSync6(abs, "utf-8");
|
|
144693
|
-
const
|
|
145141
|
+
const stat5 = fileStat ?? statSync3(abs);
|
|
144694
145142
|
const file = {
|
|
144695
145143
|
id: makeCodeFileId(projectId, rel),
|
|
144696
145144
|
projectId,
|
|
@@ -144699,8 +145147,8 @@ function indexFileLite(projectId, projectRoot, abs, indexedAt, fileStat) {
|
|
|
144699
145147
|
contentHash: hashText(text2),
|
|
144700
145148
|
// Preserve filesystem precision. Rounding here made same-size edits in
|
|
144701
145149
|
// a short Windows timestamp window indistinguishable to refresh.
|
|
144702
|
-
mtimeMs: Number(
|
|
144703
|
-
sizeBytes: Number(
|
|
145150
|
+
mtimeMs: Number(stat5.mtimeMs),
|
|
145151
|
+
sizeBytes: Number(stat5.size),
|
|
144704
145152
|
indexedAt
|
|
144705
145153
|
};
|
|
144706
145154
|
return {
|
|
@@ -144727,18 +145175,18 @@ async function indexProjectLite(options) {
|
|
|
144727
145175
|
let skippedOversizedFiles = 0;
|
|
144728
145176
|
let unreadableFiles = 0;
|
|
144729
145177
|
for (const abs of paths) {
|
|
144730
|
-
let
|
|
145178
|
+
let stat5;
|
|
144731
145179
|
try {
|
|
144732
|
-
|
|
145180
|
+
stat5 = statSync3(abs);
|
|
144733
145181
|
} catch {
|
|
144734
145182
|
unreadableFiles++;
|
|
144735
145183
|
continue;
|
|
144736
145184
|
}
|
|
144737
|
-
if (Number(
|
|
145185
|
+
if (Number(stat5.size) > maxFileBytes) {
|
|
144738
145186
|
skippedOversizedFiles++;
|
|
144739
145187
|
continue;
|
|
144740
145188
|
}
|
|
144741
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
145189
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
144742
145190
|
if (!attempt.delta) {
|
|
144743
145191
|
if (attempt.unreadable) unreadableFiles++;
|
|
144744
145192
|
continue;
|
|
@@ -144766,16 +145214,16 @@ async function refreshProjectLite(store, options) {
|
|
|
144766
145214
|
for (const abs of paths) {
|
|
144767
145215
|
const rel = normalizeCodePath(relative(options.projectRoot, abs));
|
|
144768
145216
|
seenPaths.add(rel);
|
|
144769
|
-
let
|
|
145217
|
+
let stat5;
|
|
144770
145218
|
try {
|
|
144771
|
-
|
|
145219
|
+
stat5 = statSync3(abs);
|
|
144772
145220
|
} catch {
|
|
144773
145221
|
unreadableFiles++;
|
|
144774
145222
|
continue;
|
|
144775
145223
|
}
|
|
144776
145224
|
const existing = existingByPath.get(rel);
|
|
144777
|
-
const mtimeMs = Number(
|
|
144778
|
-
const sizeBytes = Number(
|
|
145225
|
+
const mtimeMs = Number(stat5.mtimeMs);
|
|
145226
|
+
const sizeBytes = Number(stat5.size);
|
|
144779
145227
|
if (sizeBytes > maxFileBytes) {
|
|
144780
145228
|
skippedOversizedFiles++;
|
|
144781
145229
|
if (existing) oversizedExistingFileIds.add(existing.id);
|
|
@@ -144785,7 +145233,7 @@ async function refreshProjectLite(store, options) {
|
|
|
144785
145233
|
unchangedFiles++;
|
|
144786
145234
|
continue;
|
|
144787
145235
|
}
|
|
144788
|
-
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt,
|
|
145236
|
+
const attempt = indexFileLite(options.projectId, options.projectRoot, abs, indexedAt, stat5);
|
|
144789
145237
|
if (!attempt.delta) {
|
|
144790
145238
|
if (attempt.unreadable) unreadableFiles++;
|
|
144791
145239
|
continue;
|
|
@@ -148182,12 +148630,25 @@ __export(observations_exports, {
|
|
|
148182
148630
|
prepareSearchIndex: () => prepareSearchIndex,
|
|
148183
148631
|
probeSearchIndex: () => probeSearchIndex,
|
|
148184
148632
|
reindexObservations: () => reindexObservations,
|
|
148633
|
+
resetObservationRuntime: () => resetObservationRuntime,
|
|
148185
148634
|
resolveObservations: () => resolveObservations,
|
|
148186
148635
|
storeObservation: () => storeObservation,
|
|
148187
148636
|
suggestTopicKey: () => suggestTopicKey,
|
|
148188
148637
|
updateObservationAdmission: () => updateObservationAdmission,
|
|
148189
148638
|
withFreshObservations: () => withFreshObservations
|
|
148190
148639
|
});
|
|
148640
|
+
function resetObservationRuntime() {
|
|
148641
|
+
observations = [];
|
|
148642
|
+
nextId = 1;
|
|
148643
|
+
projectDir = null;
|
|
148644
|
+
searchIndexPrepared = false;
|
|
148645
|
+
corpusLoaded = false;
|
|
148646
|
+
loadedObservationStore = null;
|
|
148647
|
+
embeddingWriteMode = "background";
|
|
148648
|
+
embeddingWorkerProjectRoot = void 0;
|
|
148649
|
+
vectorMissingIds.clear();
|
|
148650
|
+
vectorSchemaUpgradePromise = null;
|
|
148651
|
+
}
|
|
148191
148652
|
function logEmbeddingFailureOnce(key, message) {
|
|
148192
148653
|
const now3 = Date.now();
|
|
148193
148654
|
const last = embeddingFailureLogTimestamps.get(key) ?? 0;
|
|
@@ -148296,23 +148757,33 @@ async function upgradeVectorSchemaAfterFirstEmbedding(embedding) {
|
|
|
148296
148757
|
async function initObservations(dir, options = {}) {
|
|
148297
148758
|
embeddingWriteMode = options.embeddingWriteMode ?? "background";
|
|
148298
148759
|
embeddingWorkerProjectRoot = options.projectRoot;
|
|
148299
|
-
if (projectDir === dir) return;
|
|
148300
148760
|
await initObservationStore(dir);
|
|
148301
148761
|
const store = getObservationStore();
|
|
148302
|
-
|
|
148762
|
+
if (projectDir === dir && loadedObservationStore === store) {
|
|
148763
|
+
if (options.skipCorpusLoad || corpusLoaded) return;
|
|
148764
|
+
}
|
|
148303
148765
|
nextId = await store.loadIdCounter();
|
|
148304
148766
|
projectDir = dir;
|
|
148305
148767
|
searchIndexPrepared = false;
|
|
148306
148768
|
vectorSchemaUpgradePromise = null;
|
|
148769
|
+
if (options.skipCorpusLoad) {
|
|
148770
|
+
observations = [];
|
|
148771
|
+
corpusLoaded = false;
|
|
148772
|
+
loadedObservationStore = store;
|
|
148773
|
+
return;
|
|
148774
|
+
}
|
|
148775
|
+
observations = await store.loadAll();
|
|
148776
|
+
corpusLoaded = true;
|
|
148777
|
+
loadedObservationStore = store;
|
|
148307
148778
|
}
|
|
148308
148779
|
function scheduleObservationEmbedding(input) {
|
|
148309
148780
|
const { observationId: observationId2, projectId, searchableText, doc } = input;
|
|
148310
148781
|
vectorMissingIds.add(observationId2);
|
|
148782
|
+
if (isEmbeddingExplicitlyDisabled()) {
|
|
148783
|
+
vectorMissingIds.delete(observationId2);
|
|
148784
|
+
return;
|
|
148785
|
+
}
|
|
148311
148786
|
if (embeddingWriteMode === "deferred") {
|
|
148312
|
-
if (isEmbeddingExplicitlyDisabled()) {
|
|
148313
|
-
vectorMissingIds.delete(observationId2);
|
|
148314
|
-
return;
|
|
148315
|
-
}
|
|
148316
148787
|
queueVectorBackfill(projectId, {
|
|
148317
148788
|
detachedWorker: true,
|
|
148318
148789
|
projectRoot: embeddingWorkerProjectRoot
|
|
@@ -148359,7 +148830,7 @@ function scheduleObservationEmbedding(input) {
|
|
|
148359
148830
|
});
|
|
148360
148831
|
}
|
|
148361
148832
|
async function ensureFreshObservations() {
|
|
148362
|
-
if (!projectDir) return false;
|
|
148833
|
+
if (!projectDir || !corpusLoaded) return false;
|
|
148363
148834
|
try {
|
|
148364
148835
|
const store = getObservationStore();
|
|
148365
148836
|
const wasStale = await store.ensureFresh();
|
|
@@ -148400,7 +148871,7 @@ async function storeObservation(input) {
|
|
|
148400
148871
|
});
|
|
148401
148872
|
if (safeAttachments) input = { ...input, attachments: safeAttachments };
|
|
148402
148873
|
await ensureFreshObservations();
|
|
148403
|
-
if (input.topicKey) {
|
|
148874
|
+
if (input.topicKey && corpusLoaded) {
|
|
148404
148875
|
const existing = observations.find(
|
|
148405
148876
|
(o) => o.topicKey === input.topicKey && o.projectId === input.projectId
|
|
148406
148877
|
);
|
|
@@ -148497,13 +148968,17 @@ async function storeObservation(input) {
|
|
|
148497
148968
|
});
|
|
148498
148969
|
observation.writeGeneration = store.getGeneration();
|
|
148499
148970
|
if (upsertedInsideLock || reloadCacheAfterCommit) {
|
|
148500
|
-
|
|
148501
|
-
|
|
148502
|
-
|
|
148503
|
-
|
|
148971
|
+
if (corpusLoaded) {
|
|
148972
|
+
observations = await store.loadAll();
|
|
148973
|
+
nextId = await store.loadIdCounter();
|
|
148974
|
+
if (upsertedInsideLock) {
|
|
148975
|
+
observation = observations.find((candidate) => candidate.id === observation.id) ?? observation;
|
|
148976
|
+
}
|
|
148977
|
+
} else {
|
|
148978
|
+
nextId = await store.loadIdCounter();
|
|
148504
148979
|
}
|
|
148505
148980
|
} else {
|
|
148506
|
-
observations.push(observation);
|
|
148981
|
+
if (corpusLoaded) observations.push(observation);
|
|
148507
148982
|
nextId = observation.id + 1;
|
|
148508
148983
|
}
|
|
148509
148984
|
if (upsertedInsideLock) return;
|
|
@@ -148571,7 +149046,9 @@ async function storeObservation(input) {
|
|
|
148571
149046
|
createdByAgentId: input.createdByAgentId ?? "",
|
|
148572
149047
|
sharedWithAgentIds: JSON.stringify(input.sharedWithAgentIds ?? [])
|
|
148573
149048
|
};
|
|
148574
|
-
|
|
149049
|
+
if (corpusLoaded) {
|
|
149050
|
+
await insertObservation(doc);
|
|
149051
|
+
}
|
|
148575
149052
|
};
|
|
148576
149053
|
await assignAndPersist();
|
|
148577
149054
|
if (upsertedInsideLock) {
|
|
@@ -148933,9 +149410,11 @@ async function reindexObservations() {
|
|
|
148933
149410
|
searchIndexPrepared = true;
|
|
148934
149411
|
return count2;
|
|
148935
149412
|
}
|
|
148936
|
-
async function prepareSearchIndex() {
|
|
149413
|
+
async function prepareSearchIndex(options = {}) {
|
|
148937
149414
|
if (searchIndexPrepared) return 0;
|
|
148938
|
-
const count2 = await hydrateIndexForStartup(observations
|
|
149415
|
+
const count2 = await hydrateIndexForStartup(observations, {
|
|
149416
|
+
skipCachedVectors: options.skipCachedVectors
|
|
149417
|
+
});
|
|
148939
149418
|
if (count2 === 0) {
|
|
148940
149419
|
searchIndexPrepared = true;
|
|
148941
149420
|
return 0;
|
|
@@ -149127,7 +149606,7 @@ async function backfillVectorEmbeddings(options = {}) {
|
|
|
149127
149606
|
...lastFailure ? { lastError: lastFailure } : {}
|
|
149128
149607
|
};
|
|
149129
149608
|
}
|
|
149130
|
-
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
149609
|
+
var observations, nextId, projectDir, searchIndexPrepared, embeddingWriteMode, embeddingWorkerProjectRoot, corpusLoaded, loadedObservationStore, vectorMissingIds, vectorBackfillRunning, vectorSchemaUpgradePromise, lastVectorBackfill, embeddingFailureLogTimestamps, EMBEDDING_FAILURE_LOG_COOLDOWN_MS;
|
|
149131
149610
|
var init_observations = __esm({
|
|
149132
149611
|
"src/memory/observations.ts"() {
|
|
149133
149612
|
"use strict";
|
|
@@ -149146,6 +149625,8 @@ var init_observations = __esm({
|
|
|
149146
149625
|
projectDir = null;
|
|
149147
149626
|
searchIndexPrepared = false;
|
|
149148
149627
|
embeddingWriteMode = "background";
|
|
149628
|
+
corpusLoaded = false;
|
|
149629
|
+
loadedObservationStore = null;
|
|
149149
149630
|
vectorMissingIds = /* @__PURE__ */ new Set();
|
|
149150
149631
|
vectorBackfillRunning = false;
|
|
149151
149632
|
vectorSchemaUpgradePromise = null;
|