@snoai/memory 1.2.13 → 1.5.0

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.
Files changed (152) hide show
  1. package/README.md +1 -1
  2. package/dist/{access-tracker-CglGg8uS.d.ts → access-tracker-B1H2AJlH.d.ts} +4 -4
  3. package/dist/{adapter-Cxyzdq6H.d.ts → adapter-CgdVA88V.d.ts} +2 -2
  4. package/dist/{agent-llm-port-DY2290EK.d.ts → agent-llm-port-BlFrD2ro.d.ts} +5 -0
  5. package/dist/{atomic-memory-extraction-DO4yTfch.d.ts → atomic-memory-extraction-DCMTQ0h-.d.ts} +4 -4
  6. package/dist/{atomic-memory-extraction-DWhlXJT6.js → atomic-memory-extraction-De86y7O-.js} +4 -4
  7. package/dist/{b-profile-section-dictionary-provider-BkUdS1SY.d.ts → b-profile-section-dictionary-provider-DbqdRYMw.d.ts} +1 -1
  8. package/dist/{capture-policy-detector-C7MA4jSr.d.ts → capture-policy-detector-D4ziS7KF.d.ts} +1 -1
  9. package/dist/client.d.ts +1 -1
  10. package/dist/{config-D_KOwEyg.js → config-DWeuetYo.js} +740 -447
  11. package/dist/{derived-suppression-cache-CmS4xAaN.d.ts → derived-suppression-cache-2xOq6XHX.d.ts} +1 -1
  12. package/dist/diagnostic-encoder.js +1 -1
  13. package/dist/{embedding-provider-client-vynZMuit.d.ts → embedding-provider-client-CELWtPgt.d.ts} +6 -0
  14. package/dist/{embedding-provider-client-40tpzKou.js → embedding-provider-client-CgpUK_1G.js} +16 -1
  15. package/dist/{index-Pb9LrHgL.d.ts → index-BGu91bjB.d.ts} +25 -19
  16. package/dist/{index-CTi1R9T4.d.ts → index-PjHhlG6e.d.ts} +2 -2
  17. package/dist/index.d.ts +11 -11
  18. package/dist/index.js +5 -5
  19. package/dist/internal/config/index.d.ts +2 -2
  20. package/dist/internal/config/index.js +25 -19
  21. package/dist/internal/config/plugin-config-schema.d.ts +1 -1
  22. package/dist/internal/config/plugin-config-schema.js +1 -1
  23. package/dist/internal/config/product-mode.d.ts +1 -1
  24. package/dist/internal/config/settings.d.ts +1 -1
  25. package/dist/internal/config/settings.js +3 -30
  26. package/dist/internal/config/skin-defaults.d.ts +1 -1
  27. package/dist/internal/contract/profile.d.ts +1 -1
  28. package/dist/internal/contract/routes.d.ts +1 -1
  29. package/dist/internal/engine/bindings/memory-cli-shared.d.ts +5 -5
  30. package/dist/internal/engine/bindings/memory-forget-tool.js +1 -1
  31. package/dist/internal/engine/bindings/memory-list-tool.js +1 -1
  32. package/dist/internal/engine/bindings/memory-recall-tool.js +1 -1
  33. package/dist/internal/engine/bindings/memory-reflection-resolve-tool.js +1 -1
  34. package/dist/internal/engine/bindings/memory-stats-tool.js +1 -1
  35. package/dist/internal/engine/bindings/memory-store-tool.js +3 -3
  36. package/dist/internal/engine/bindings/memory-tool-access.d.ts +1 -1
  37. package/dist/internal/engine/bindings/memory-tool-access.js +1 -1
  38. package/dist/internal/engine/bindings/memory-tool-results.d.ts +1 -1
  39. package/dist/internal/engine/bindings/memory-tool-results.js +1 -1
  40. package/dist/internal/engine/bindings/memory-tool-schemas.d.ts +6 -6
  41. package/dist/internal/engine/bindings/memory-tool-schemas.js +1 -1
  42. package/dist/internal/engine/bindings/memory-update-tool.js +2 -2
  43. package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.d.ts +5 -5
  44. package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.js +2 -2
  45. package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.d.ts +4 -4
  46. package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.js +1 -1
  47. package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.d.ts +7 -7
  48. package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.js +2 -2
  49. package/dist/internal/engine/bindings/sno-station-mem-message-transcript.js +2 -2
  50. package/dist/internal/engine/bindings/sno-station-mem-reset-hook.d.ts +4 -4
  51. package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.d.ts +1 -1
  52. package/dist/internal/engine/extraction/atomic-memory-extraction.d.ts +1 -1
  53. package/dist/internal/engine/extraction/atomic-memory-extraction.js +1 -1
  54. package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.d.ts +1 -1
  55. package/dist/internal/engine/extraction/b-profile-section-rekey.d.ts +5 -5
  56. package/dist/internal/engine/extraction/capture-policy-detector.d.ts +1 -1
  57. package/dist/internal/engine/extraction/embedding-provider-client.d.ts +1 -1
  58. package/dist/internal/engine/extraction/embedding-provider-client.js +1 -1
  59. package/dist/internal/engine/extraction/memory-metadata-codec.d.ts +2 -2
  60. package/dist/internal/engine/extraction/memory-temporality-classifier.d.ts +1 -1
  61. package/dist/internal/engine/extraction/memory-temporality-classifier.js +1 -1
  62. package/dist/internal/engine/observability/adapter.d.ts +1 -1
  63. package/dist/internal/engine/observability/memory-snapshot.d.ts +1 -1
  64. package/dist/internal/engine/observability/observable-embedder.d.ts +1 -1
  65. package/dist/internal/engine/observability/observable-embedder.js +1 -1
  66. package/dist/internal/engine/observability/observable-llm-client.d.ts +1 -1
  67. package/dist/internal/engine/observability/observable-memory-store.d.ts +1 -1
  68. package/dist/internal/engine/observability/observable-memory-store.js +1 -1
  69. package/dist/internal/engine/observability/observable-retriever.d.ts +1 -1
  70. package/dist/internal/engine/observability/observable-retriever.js +1 -1
  71. package/dist/internal/engine/observability/runtime-diagnostics.d.ts +1 -1
  72. package/dist/internal/engine/observability/runtime-diagnostics.js +1 -1
  73. package/dist/internal/engine/operations/memory-tier-promoter.d.ts +1 -1
  74. package/dist/internal/engine/operations/runtime-audit-log.d.ts +2 -2
  75. package/dist/internal/engine/provider/provider-registration.d.ts +4 -4
  76. package/dist/internal/engine/provider/provider-row-renderer.d.ts +1 -1
  77. package/dist/internal/engine/reflection/reflection-command-hooks.d.ts +1 -1
  78. package/dist/internal/engine/reflection/reflection-command-hooks.js +1 -1
  79. package/dist/internal/engine/reflection/reflection-deps.d.ts +1 -1
  80. package/dist/internal/engine/reflection/reflection-embedded-generator.d.ts +1 -1
  81. package/dist/internal/engine/reflection/reflection-embedded-generator.js +1 -1
  82. package/dist/internal/engine/reflection/reflection-injection-hooks.d.ts +1 -1
  83. package/dist/internal/engine/reflection/reflection-injection-hooks.js +1 -1
  84. package/dist/internal/engine/reflection/reflection-lifecycle-hooks.d.ts +1 -1
  85. package/dist/internal/engine/reflection/reflection-lifecycle-hooks.js +1 -1
  86. package/dist/internal/engine/reflection/strategy-hook-runner.d.ts +3 -3
  87. package/dist/internal/engine/reflection/strategy-hook-runner.js +2 -2
  88. package/dist/internal/engine/retrieval/access-tracker.d.ts +1 -1
  89. package/dist/internal/engine/retrieval/retriever.d.ts +2 -2
  90. package/dist/internal/engine/retrieval/retriever.js +1 -1
  91. package/dist/internal/engine/shared/memory-kind-policy.d.ts +1 -1
  92. package/dist/internal/engine/shared/paths.d.ts +2 -2
  93. package/dist/internal/engine/shared/types.d.ts +2 -2
  94. package/dist/internal/engine/shared/types.js +1 -1
  95. package/dist/internal/engine/telemetry/observe-ledger.d.ts +1 -1
  96. package/dist/internal/model/agent-llm-port.d.ts +1 -1
  97. package/dist/internal/model/llm-client.d.ts +2 -2
  98. package/dist/internal/model/llm-client.js +1 -1
  99. package/dist/internal/model/llm-mode-routing.d.ts +1 -1
  100. package/dist/internal/store/maintenance.d.ts +2 -2
  101. package/dist/internal/store/maintenance.js +4 -4
  102. package/dist/internal/store/store.d.ts +2 -2
  103. package/dist/internal/store/store.js +1 -1
  104. package/dist/{llm-client-B7LSFL_m.d.ts → llm-client-C-K7oyfu.d.ts} +1 -1
  105. package/dist/{llm-client-C7yyFWu-.js → llm-client-DDdUjYWS.js} +10 -3
  106. package/dist/{log-site-catalog.generated-BODn_6Kx.js → log-site-catalog.generated-Cn8rTa65.js} +94 -73
  107. package/dist/log-site-catalog.json +1 -1
  108. package/dist/{memory-kind-policy-B4IBMAlv.d.ts → memory-kind-policy-DgPCjfY4.d.ts} +1 -1
  109. package/dist/{memory-metadata-codec-BQ8tBY-g.d.ts → memory-metadata-codec-CfP9JLVO.d.ts} +1 -1
  110. package/dist/{memory-runtime-4iOpeP09.js → memory-runtime-jQke2sBc.js} +118 -78
  111. package/dist/{memory-snapshot-B8mQbWR-.d.ts → memory-snapshot-B6a-6nJ7.d.ts} +2 -2
  112. package/dist/{memory-store-base-CTAMKigD.d.ts → memory-store-base-upd9MuG6.d.ts} +4 -4
  113. package/dist/{memory-temporality-classifier-epuZlfXa.js → memory-temporality-classifier-BwBKEQbL.js} +1 -1
  114. package/dist/{memory-temporality-classifier-LByFBiFJ.d.ts → memory-temporality-classifier-DPk3_9Or.d.ts} +1 -1
  115. package/dist/{memory-tier-promoter-CSGa4LBH.d.ts → memory-tier-promoter-Cq23yveQ.d.ts} +1 -1
  116. package/dist/memory-tool-dependencies-C9qgVGOn.d.ts +14 -0
  117. package/dist/{memory-tool-dependencies-xLaWzwpI.js → memory-tool-dependencies-aAr7Pkuj.js} +1 -1
  118. package/dist/{observable-embedder-Da0teBqx.d.ts → observable-embedder-DihQuuQD.d.ts} +2 -2
  119. package/dist/{observable-llm-client-i0sp0veF.d.ts → observable-llm-client-BglDBFN5.d.ts} +3 -3
  120. package/dist/{observable-memory-store-CS87pitJ.d.ts → observable-memory-store--n02Dre8.d.ts} +5 -5
  121. package/dist/{observable-retriever-Bhfg9DsZ.d.ts → observable-retriever-CV6odifA.d.ts} +6 -6
  122. package/dist/paths-qJqwGcKl.d.ts +1 -0
  123. package/dist/{plugin-config-schema-CvAGFPyE.js → plugin-config-schema-D9riSXDg.js} +3 -20
  124. package/dist/{plugin-config-schema-CcEeAEdi.d.ts → plugin-config-schema-dV2_HgBo.d.ts} +2 -8
  125. package/dist/{profile-BMvnRqf5.d.ts → profile-CoLKGobS.d.ts} +1 -1
  126. package/dist/{profile-section-writer-DeD9GPQJ.js → profile-section-writer-Dd4FKpt5.js} +2 -2
  127. package/dist/{reflection-command-hooks-S5L6ZWeh.js → reflection-command-hooks-B2P4zDr6.js} +3 -3
  128. package/dist/{reflection-command-hooks-CFXyoVvE.d.ts → reflection-command-hooks-Cfv836Wc.d.ts} +4 -4
  129. package/dist/{reflection-deps-BPMrDU0a.d.ts → reflection-deps-DihlwQxE.d.ts} +4 -4
  130. package/dist/{reflection-embedded-generator-CF-NbuPS.d.ts → reflection-embedded-generator-DCZaS6kz.d.ts} +4 -4
  131. package/dist/{reflection-embedded-generator-nmVrj4AZ.js → reflection-embedded-generator-DV-NkeU-.js} +1 -1
  132. package/dist/{reflection-injection-hooks-BRIr3lJM.d.ts → reflection-injection-hooks-BYxkrds6.d.ts} +4 -4
  133. package/dist/{reflection-lifecycle-hooks-Ci8y4qHk.d.ts → reflection-lifecycle-hooks-Bwq2y5pe.d.ts} +3 -3
  134. package/dist/{rem-batch-executor-CfWChDAk.js → rem-batch-executor-B_49KivZ.js} +1 -1
  135. package/dist/{rem-trigger-B1P5_RqV.js → rem-trigger-DL0MlLeo.js} +180 -160
  136. package/dist/{retriever-CpyZs2ND.js → retriever-CsBW6MZv.js} +158 -162
  137. package/dist/{retriever-DdikFSDC.d.ts → retriever-hTIkt3CJ.d.ts} +19 -26
  138. package/dist/{runtime-audit-log-BVOxzkh7.d.ts → runtime-audit-log-eBrt_iPp.d.ts} +1 -1
  139. package/dist/{server-DOL3D6bb.js → server-BnBzsvMF.js} +9 -9
  140. package/dist/sidecar/main.js +2 -2
  141. package/dist/sno-station-mem-runtime-dependencies-9L8WkMMV.d.ts +31 -0
  142. package/dist/{sno-station-mem-runtime-dependencies-DZe3z4RY.js → sno-station-mem-runtime-dependencies-DrVDRAmf.js} +6 -6
  143. package/dist/{store-DY_rWx__.js → store-COwW7mIh.js} +1 -1
  144. package/dist/{store-DraRJ-HI.d.ts → store-DEG06TLb.d.ts} +2 -2
  145. package/dist/{strategy-hook-runner-CltVTtzk.js → strategy-hook-runner-CALbWcys.js} +1 -1
  146. package/dist/{strategy-hook-runner-DH7OEQrH.d.ts → strategy-hook-runner-D1sRVThs.d.ts} +7 -7
  147. package/dist/{types-DZGL4QXi.d.ts → types-DBEwNYdR.d.ts} +1 -1
  148. package/package.json +2 -2
  149. package/settings.default.json +0 -4
  150. package/dist/memory-tool-dependencies-Bl11T6Xm.d.ts +0 -14
  151. package/dist/paths-B5y-npWs.d.ts +0 -1
  152. package/dist/sno-station-mem-runtime-dependencies-DgAm7WqA.d.ts +0 -31
@@ -1,8 +1,12 @@
1
1
  import { createLogger } from "@snoai/utils/logger";
2
2
  import path, { dirname, join, resolve } from "node:path";
3
- import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readdirSync, rmSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
4
- import { homedir, totalmem, userInfo } from "node:os";
3
+ import { closeSync, createReadStream, createWriteStream, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, utimesSync, writeFileSync } from "node:fs";
4
+ import { homedir, userInfo } from "node:os";
5
5
  import { fileURLToPath } from "node:url";
6
+ import { createHash } from "node:crypto";
7
+ import http from "node:http";
8
+ import https from "node:https";
9
+ import { pipeline } from "node:stream/promises";
6
10
  import { LRUCache } from "lru-cache";
7
11
  import { isLowercaseCanonicalUUIDv7 } from "@snoai/common-core";
8
12
  import { z } from "zod";
@@ -94,13 +98,552 @@ const LOCAL_EMBEDDING_SESSION_OPTIONS_DEFAULT = {
94
98
  */
95
99
  const LOCAL_EMBEDDING_CACHE_DIR_DEFAULT = join(CONSTANTS_DIR, "..", ".cache", "models");
96
100
  /**
101
+ * Downloads a model's files into <cacheDir>/<model>/<revision>/, the one place the loaders read a model from.
102
+ *
103
+ * A revision directory is complete when its marker names the same revision and file hashes and every file has its
104
+ * expected size; the marker is written last, so an interrupted download is never mistaken for a complete one. One process
105
+ * downloads a directory at a time (an O_EXCL lock with a heartbeat; a dead holder's lock is broken at once).
106
+ */
107
+ const log$3 = createLogger("embedder:downloader");
108
+ const HUB = "https://huggingface.co/";
109
+ const HUB_HOSTS = /* @__PURE__ */ new Set(["huggingface.co", "hf.co"]);
110
+ const MARKER = ".complete";
111
+ const MAX_REDIRECTS = 5;
112
+ /** A connection that sends nothing for this long is dropped (Node's own limit is five minutes). */
113
+ const STALL_MS = 3e4;
114
+ /** Tries per file; network errors, stalls, 408, 429 and 5xx wait 1, 2, 4, 8 s (or the server's Retry-After). */
115
+ const ATTEMPTS = 5;
116
+ const RETRY_AFTER_CAP_MS = 6e4;
117
+ const LOCK_HEARTBEAT_MS = 5e3;
118
+ const LOCK_POLL_MS = 2e3;
119
+ /** A lock not touched for this long belongs to a holder that hung or died. */
120
+ const LOCK_STALE_MS = 9e5;
121
+ function modelDir(cacheDir, spec) {
122
+ return join(resolve(cacheDir), spec.id, revisionDirName(spec.revision));
123
+ }
124
+ /** One directory level per revision, so a ref such as `refs/pr/1` is not nested (and not mistaken for an older copy). */
125
+ function revisionDirName(revision) {
126
+ return revision.replaceAll("/", "--");
127
+ }
128
+ /** Complete: the marker names this revision and the same hashes, and every file has its expected size. */
129
+ function isDownloaded(cacheDir, spec) {
130
+ const dir = modelDir(cacheDir, spec);
131
+ try {
132
+ const marker = JSON.parse(readFileSync(join(dir, MARKER), "utf8"));
133
+ if (marker.revision !== spec.revision || marker.verify === true) return false;
134
+ const recorded = new Map((readMarkerFiles(dir) ?? []).map((file) => [file.path, file]));
135
+ return spec.files.every((file) => statSync(join(dir, file.path), { throwIfNoEntry: false })?.size === file.size && sameIdentity(file, recorded.get(file.path)));
136
+ } catch {
137
+ return false;
138
+ }
139
+ }
140
+ function sameIdentity(file, recorded) {
141
+ return (!file.sha256 || recorded?.sha256 === file.sha256) && (!file.oid || recorded?.oid === file.oid);
142
+ }
143
+ /**
144
+ * For a loader that could not open the model: marks the download for checking, so the next start checks every file
145
+ * again and fetches any that differ (a file kept despite a SHA-256 mismatch, a copy that went bad on disk). The marker
146
+ * keeps its file list for offline use. Once per process: a load that keeps failing for another reason (memory, an
147
+ * unsupported op) does not re-hash the files each time.
148
+ */
149
+ function forgetDownload(cacheDir, spec) {
150
+ const dir = modelDir(cacheDir, spec);
151
+ if (forgotten.has(dir)) return;
152
+ forgotten.add(dir);
153
+ try {
154
+ const marker = JSON.parse(readFileSync(join(dir, MARKER), "utf8"));
155
+ writeFileSync(join(dir, MARKER), JSON.stringify({
156
+ ...marker,
157
+ verify: true
158
+ }));
159
+ } catch {}
160
+ }
161
+ const forgotten = /* @__PURE__ */ new Set();
162
+ const downloads = /* @__PURE__ */ new Map();
163
+ /** Makes the model's revision directory complete and returns it. */
164
+ function downloadModel(spec, options) {
165
+ const dir = modelDir(options.cacheDir, spec);
166
+ let download = downloads.get(dir);
167
+ if (!download) {
168
+ download = fetchModel(spec, options, dir).finally(() => downloads.delete(dir));
169
+ downloads.set(dir, download);
170
+ }
171
+ return download;
172
+ }
173
+ async function fetchModel(spec, options, dir) {
174
+ if (isDownloaded(options.cacheDir, spec)) return dir;
175
+ const lock = `${dir}.lock`;
176
+ await acquireLock(lock);
177
+ const heartbeat = setInterval(() => touch(lock), LOCK_HEARTBEAT_MS);
178
+ try {
179
+ if (isDownloaded(options.cacheDir, spec)) return dir;
180
+ const started = performance.now();
181
+ const host = hostOf(options.mirror);
182
+ log$3.info("model download started", {
183
+ model: spec.id,
184
+ revision: spec.revision,
185
+ cache_dir: dir
186
+ }, {
187
+ event_name: "embedder.downloader.started",
188
+ file: "packages/embedder/src/downloader.ts",
189
+ function: "fetchModel",
190
+ site_id: "embedder.downloader.started"
191
+ });
192
+ adoptFlatFiles(spec, options.cacheDir, dir);
193
+ const recorded = new Map((readMarkerFiles(dir) ?? []).map((file) => [file.path, file]));
194
+ for (const file of spec.files) {
195
+ const target = join(dir, file.path);
196
+ if (statSync(target, { throwIfNoEntry: false })?.size === file.size && (!file.oid || recorded.get(file.path)?.oid === file.oid) && (options.offline || (await hashCheck(target, file)).ok)) continue;
197
+ if (options.offline) throw new Error(`${spec.id}@${spec.revision.slice(0, 12)}: ${file.path} is not in ${dir} and downloads are off`);
198
+ await fetchFile(spec, `${host}${spec.id}/resolve/${encodeURIComponent(spec.revision)}/${file.path}`, target, file);
199
+ }
200
+ writeFileSync(join(dir, MARKER), JSON.stringify({
201
+ model: spec.id,
202
+ revision: spec.revision,
203
+ files: spec.files,
204
+ completedAt: (/* @__PURE__ */ new Date()).toISOString()
205
+ }));
206
+ removeOlderCopies(spec, options.cacheDir);
207
+ log$3.info("model download complete", {
208
+ model: spec.id,
209
+ revision: spec.revision,
210
+ duration_ms: Math.round(performance.now() - started)
211
+ }, {
212
+ event_name: "embedder.downloader.complete",
213
+ file: "packages/embedder/src/downloader.ts",
214
+ function: "fetchModel",
215
+ site_id: "embedder.downloader.complete"
216
+ });
217
+ return dir;
218
+ } finally {
219
+ clearInterval(heartbeat);
220
+ rmSync(lock, { force: true });
221
+ }
222
+ }
223
+ /**
224
+ * Releases before the revision directories kept one copy at <cacheDir>/<model>/<file>: a file of the expected size
225
+ * there moves into the revision directory instead of being fetched again.
226
+ */
227
+ function adoptFlatFiles(spec, cacheDir, dir) {
228
+ for (const file of spec.files) {
229
+ const flat = join(resolve(cacheDir), spec.id, file.path);
230
+ const target = join(dir, file.path);
231
+ if (statSync(target, { throwIfNoEntry: false })?.size === file.size) continue;
232
+ if (statSync(flat, { throwIfNoEntry: false })?.size !== file.size) continue;
233
+ mkdirSync(dirname(target), { recursive: true });
234
+ renameSync(flat, target);
235
+ }
236
+ }
237
+ /**
238
+ * Everything else under <cacheDir>/<model>/ is an older copy, except another revision's complete download, which an
239
+ * install of another version sharing this cache may still load; a copy that cannot be removed only costs disk.
240
+ */
241
+ function removeOlderCopies(spec, cacheDir) {
242
+ const root = join(resolve(cacheDir), spec.id);
243
+ const keep = /* @__PURE__ */ new Set([revisionDirName(spec.revision), `${revisionDirName(spec.revision)}.lock`]);
244
+ const downloading = (entry) => !lockIsStale(join(root, entry.endsWith(".lock") ? entry : `${entry}.lock`));
245
+ const complete = (entry) => statSync(join(root, entry, MARKER), { throwIfNoEntry: false }) !== void 0;
246
+ const older = readdirSync(root).filter((entry) => !keep.has(entry) && !downloading(entry) && !complete(entry)).map((entry) => join(root, entry));
247
+ older.push(join(resolve(cacheDir), ".download-complete"));
248
+ for (const path of older) try {
249
+ rmSync(path, {
250
+ recursive: true,
251
+ force: true
252
+ });
253
+ } catch (error) {
254
+ log$3.warn("older model copy not removed", {
255
+ path,
256
+ error
257
+ }, {
258
+ event_name: "embedder.downloader.cleanup_failed",
259
+ file: "packages/embedder/src/downloader.ts",
260
+ function: "removeOlderCopies",
261
+ site_id: "embedder.downloader.cleanup_failed"
262
+ });
263
+ }
264
+ }
265
+ const DTYPE_SUFFIX = {
266
+ fp32: "",
267
+ fp16: "_fp16",
268
+ int8: "_int8",
269
+ uint8: "_uint8",
270
+ q8: "_quantized",
271
+ q4: "_q4",
272
+ q4f16: "_q4f16",
273
+ bnb4: "_bnb4"
274
+ };
275
+ const LOADER_FILES = /* @__PURE__ */ new Set([
276
+ "config.json",
277
+ "tokenizer.json",
278
+ "tokenizer_config.json",
279
+ "special_tokens_map.json"
280
+ ]);
281
+ /**
282
+ * The files transformers.js loads for a model that is not pinned in code, as the hub lists them at `revision`;
283
+ * offline, as the marker of the last complete download lists them.
284
+ */
285
+ async function hubModelSpec(id, revision, dtype, options) {
286
+ const dir = modelDir(options.cacheDir, {
287
+ id,
288
+ revision
289
+ });
290
+ if (options.offline) {
291
+ const files = readMarkerFiles(dir);
292
+ if (!files) throw new Error(`${id}@${revision} is not in ${dir} and downloads are off`);
293
+ return {
294
+ id,
295
+ revision,
296
+ files
297
+ };
298
+ }
299
+ const weights = `onnx/model${DTYPE_SUFFIX[dtype] ?? ""}.onnx`;
300
+ const url = `${hostOf(options.mirror)}api/models/${id}/tree/${encodeURIComponent(revision)}?recursive=true`;
301
+ const cached = readMarkerFiles(dir);
302
+ let tree;
303
+ try {
304
+ tree = cached ? await getText(url) : await withRetries(`${id} file list`, () => getText(url));
305
+ } catch (error) {
306
+ if (!cached) throw error;
307
+ log$3.warn("hub file list unavailable; using the copy on disk", {
308
+ model: id,
309
+ revision,
310
+ error
311
+ }, {
312
+ event_name: "embedder.downloader.hub_unavailable",
313
+ file: "packages/embedder/src/downloader.ts",
314
+ function: "hubModelSpec",
315
+ site_id: "embedder.downloader.hub_unavailable"
316
+ });
317
+ return {
318
+ id,
319
+ revision,
320
+ files: cached
321
+ };
322
+ }
323
+ const files = parseTree(tree).filter((file) => LOADER_FILES.has(file.path) || file.path === weights || file.path.startsWith(`${weights}_data`));
324
+ if (!files.some((file) => file.path === weights)) throw new Error(`${id}@${revision} has no ${weights}`);
325
+ return {
326
+ id,
327
+ revision,
328
+ files
329
+ };
330
+ }
331
+ function readMarkerFiles(dir) {
332
+ try {
333
+ const marker = JSON.parse(readFileSync(join(dir, MARKER), "utf8"));
334
+ return Array.isArray(marker.files) ? parseTree(marker.files.map((file) => ({
335
+ type: "file",
336
+ ...file
337
+ }))) : void 0;
338
+ } catch {
339
+ return;
340
+ }
341
+ }
342
+ /** The hub's tree listing: [{ type, path, size, lfs?: { oid } }]; anything else is not a file it can serve. */
343
+ function parseTree(raw) {
344
+ const entries = typeof raw === "string" ? JSON.parse(raw) : raw;
345
+ if (!Array.isArray(entries)) throw new Error("the hub's file list is not a list");
346
+ return entries.flatMap((entry) => {
347
+ if (typeof entry !== "object" || entry === null) return [];
348
+ const { type, path, size, lfs, sha256, oid } = entry;
349
+ if (type !== "file" || typeof path !== "string" || typeof size !== "number") return [];
350
+ const hash = typeof sha256 === "string" ? sha256 : typeof lfs?.oid === "string" ? lfs.oid : void 0;
351
+ return [{
352
+ path,
353
+ size,
354
+ ...hash ? { sha256: hash } : {},
355
+ ...typeof oid === "string" ? { oid } : {}
356
+ }];
357
+ });
358
+ }
359
+ function hostOf(mirror) {
360
+ const host = mirror?.trim() || HUB;
361
+ return host.endsWith("/") ? host : `${host}/`;
362
+ }
363
+ async function fetchFile(spec, url, target, file) {
364
+ mkdirSync(dirname(target), { recursive: true });
365
+ const part = `${target}.part`;
366
+ let mismatches = 0;
367
+ return withRetries(`${spec.id} ${file.path}`, async () => {
368
+ if ((statSync(part, { throwIfNoEntry: false })?.size ?? 0) < file.size) await get(url, part);
369
+ const size = statSync(part).size;
370
+ if (size > file.size) rmSync(part, { force: true });
371
+ if (size !== file.size) throw new Error(`got ${size} bytes, expected ${file.size} (${url})`);
372
+ if (!(await hashCheck(part, file)).ok && ++mismatches === 1) {
373
+ rmSync(part, { force: true });
374
+ throw new Error(`content does not match its SHA-256 (${url})`);
375
+ }
376
+ renameSync(part, target);
377
+ });
378
+ }
379
+ /**
380
+ * Whether a file has its pinned SHA-256, and its actual hash. The check never blocks the model: a second fresh
381
+ * download that still differs is kept with an error in the log, and a check that fails to run counts as a match.
382
+ */
383
+ async function hashCheck(path, file) {
384
+ if (!file.sha256) return { ok: true };
385
+ try {
386
+ const hash = createHash("sha256");
387
+ await pipeline(createReadStream(path), hash);
388
+ const actual = hash.digest("hex");
389
+ if (actual === file.sha256) return {
390
+ ok: true,
391
+ actual
392
+ };
393
+ log$3.error("model file SHA-256 differs", {
394
+ path: file.path,
395
+ expected_sha256: file.sha256,
396
+ actual_sha256: actual
397
+ }, {
398
+ event_name: "embedder.downloader.sha256_mismatch",
399
+ file: "packages/embedder/src/downloader.ts",
400
+ function: "hashCheck",
401
+ site_id: "embedder.downloader.sha256_mismatch"
402
+ });
403
+ return {
404
+ ok: false,
405
+ actual
406
+ };
407
+ } catch (error) {
408
+ log$3.warn("model file SHA-256 not checked", {
409
+ path: file.path,
410
+ error
411
+ }, {
412
+ event_name: "embedder.downloader.sha256_unchecked",
413
+ file: "packages/embedder/src/downloader.ts",
414
+ function: "hashCheck",
415
+ site_id: "embedder.downloader.sha256_unchecked"
416
+ });
417
+ return { ok: true };
418
+ }
419
+ }
420
+ /** Runs `attemptOnce` until it succeeds, another try cannot help, or ATTEMPTS run out; the error names `label`. */
421
+ async function withRetries(label, attemptOnce) {
422
+ for (let attempt = 1;; attempt += 1) try {
423
+ return await attemptOnce();
424
+ } catch (error) {
425
+ const message = error instanceof Error ? error.message : String(error);
426
+ const delay = attempt < ATTEMPTS ? retryDelay(error, attempt) : void 0;
427
+ if (delay === void 0) throw new Error(`${label}: ${message} after ${attempt} attempt${attempt === 1 ? "" : "s"}`, { cause: error });
428
+ log$3.warn("model download failed; retrying", {
429
+ download_label: label,
430
+ attempt,
431
+ delay_ms: delay,
432
+ error
433
+ }, {
434
+ event_name: "embedder.downloader.retry",
435
+ file: "packages/embedder/src/downloader.ts",
436
+ function: "withRetries",
437
+ site_id: "embedder.downloader.retry"
438
+ });
439
+ await new Promise((resolveWait) => setTimeout(resolveWait, delay));
440
+ }
441
+ }
442
+ var HttpError = class extends Error {
443
+ status;
444
+ retryAfterMs;
445
+ constructor(status, retryAfterMs, url) {
446
+ super(`HTTP ${status} (${url})`);
447
+ this.status = status;
448
+ this.retryAfterMs = retryAfterMs;
449
+ }
450
+ };
451
+ /** Milliseconds before the next try, or undefined when another try cannot help (404, 401, 403 and other 4xx). */
452
+ function retryDelay(error, attempt) {
453
+ if (error instanceof HttpError) {
454
+ if (error.status !== 408 && error.status !== 429 && error.status < 500) return void 0;
455
+ if (error.retryAfterMs !== void 0) return Math.min(error.retryAfterMs, RETRY_AFTER_CAP_MS);
456
+ }
457
+ return 1e3 * 2 ** (attempt - 1);
458
+ }
459
+ /** Retry-After in seconds or as an HTTP date. */
460
+ function retryAfterMs(header) {
461
+ if (!header) return void 0;
462
+ const seconds = Number(header);
463
+ const ms = Number.isFinite(seconds) ? seconds * 1e3 : Date.parse(header) - Date.now();
464
+ return Number.isFinite(ms) ? Math.max(0, ms) : void 0;
465
+ }
466
+ /** The response to `url` after redirects. A socket silent for STALL_MS errors the request and its response. */
467
+ function open(url, headers, redirects = 0) {
468
+ return new Promise((resolvePromise, reject) => {
469
+ const client = url.startsWith("https:") ? https : http;
470
+ const agent = new client.Agent({ proxyEnv: process.env });
471
+ const token = HUB_HOSTS.has(new URL(url).hostname) ? process.env["HF_TOKEN"] ?? process.env["HF_ACCESS_TOKEN"] : void 0;
472
+ const auth = token ? { authorization: `Bearer ${token}` } : {};
473
+ const request = client.get(url, {
474
+ agent,
475
+ headers: {
476
+ "user-agent": "sno-station",
477
+ ...auth,
478
+ ...headers
479
+ }
480
+ }, (response) => {
481
+ const location = response.headers.location;
482
+ const status = response.statusCode ?? 0;
483
+ if (status < 300 || status >= 400 || !location) return resolvePromise(response);
484
+ response.resume();
485
+ if (redirects >= MAX_REDIRECTS) return reject(/* @__PURE__ */ new Error(`too many redirects (${url})`));
486
+ open(new URL(location, url).toString(), headers, redirects + 1).then(resolvePromise, reject);
487
+ });
488
+ request.setTimeout(STALL_MS, () => request.destroy(/* @__PURE__ */ new Error(`no data for ${STALL_MS / 1e3} s (${url})`)));
489
+ request.on("error", reject);
490
+ });
491
+ }
492
+ /** Streams one URL into `part`, resuming after the bytes already there. */
493
+ async function get(url, part) {
494
+ const start = statSync(part, { throwIfNoEntry: false })?.size ?? 0;
495
+ const response = await open(url, start > 0 ? { range: `bytes=${start}-` } : {});
496
+ const status = response.statusCode ?? 0;
497
+ const resumed = status === 206 && response.headers["content-range"]?.startsWith(`bytes ${start}-`) === true;
498
+ if (status === 416 || status === 206 && !resumed) {
499
+ response.resume();
500
+ rmSync(part, { force: true });
501
+ throw new Error(`HTTP ${status}: the host did not resume at byte ${start} (${url})`);
502
+ }
503
+ if (status !== 200 && status !== 206) {
504
+ response.resume();
505
+ throw new HttpError(status, retryAfterMs(response.headers["retry-after"]), url);
506
+ }
507
+ await pipeline(response, createWriteStream(part, { flags: resumed ? "a" : "w" }));
508
+ }
509
+ async function getText(url) {
510
+ const response = await open(url, { accept: "application/json" });
511
+ if (response.statusCode !== 200) {
512
+ response.resume();
513
+ throw new HttpError(response.statusCode ?? 0, retryAfterMs(response.headers["retry-after"]), url);
514
+ }
515
+ let text = "";
516
+ for await (const chunk of response) text += String(chunk);
517
+ return text;
518
+ }
519
+ function touch(lock) {
520
+ try {
521
+ const now = /* @__PURE__ */ new Date();
522
+ utimesSync(lock, now, now);
523
+ } catch {}
524
+ }
525
+ function tryLock(lock) {
526
+ mkdirSync(dirname(lock), { recursive: true });
527
+ try {
528
+ const fd = openSync(lock, "wx");
529
+ writeFileSync(fd, `${process.pid}\n${Date.now()}\n`);
530
+ closeSync(fd);
531
+ return true;
532
+ } catch (error) {
533
+ if (error instanceof Error && "code" in error && error.code === "EEXIST") return false;
534
+ throw error;
535
+ }
536
+ }
537
+ function lockIsStale(lock) {
538
+ try {
539
+ if (Date.now() - statSync(lock).mtimeMs > LOCK_STALE_MS) return true;
540
+ const pid = Number.parseInt(readFileSync(lock, "utf8").split("\n")[0] ?? "", 10);
541
+ if (!Number.isInteger(pid) || pid <= 0) return false;
542
+ process.kill(pid, 0);
543
+ return false;
544
+ } catch (error) {
545
+ return !(error instanceof Error && "code" in error && error.code === "EPERM");
546
+ }
547
+ }
548
+ /** Waits while a live holder keeps its lock fresh; breaks the lock of a holder that died or hung. */
549
+ async function acquireLock(lock) {
550
+ while (!tryLock(lock)) {
551
+ if (lockIsStale(lock)) {
552
+ try {
553
+ unlinkSync(lock);
554
+ } catch {}
555
+ continue;
556
+ }
557
+ await new Promise((resolveWait) => setTimeout(resolveWait, LOCK_POLL_MS));
558
+ }
559
+ }
560
+ /**
561
+ * model-download.ts — the bundled embedding model's files at its pinned revision, fetched through the shared
562
+ * downloader. User-facing progress goes to stderr (not stdout) so it doesn't interfere with structured log output
563
+ * or piped commands.
564
+ */
565
+ const log$2 = createLogger("embedder:model-download");
566
+ const DTYPE_SIZES = {
567
+ q4: "~400MB",
568
+ q8: "~639MB",
569
+ fp16: "~1.2GB",
570
+ fp32: "~639MB"
571
+ };
572
+ const TOKENIZER_FILES = [
573
+ {
574
+ path: "config.json",
575
+ size: 1651,
576
+ sha256: "c851a73845113421a2dd85b34446371635844b3875859794fb0d5fc9aee9948d"
577
+ },
578
+ {
579
+ path: "tokenizer.json",
580
+ size: 11423016,
581
+ sha256: "db86c3db621fcbcb43e5dd8981d46a9b30b715a41ce8994a9420ec5c8c3797d3"
582
+ },
583
+ {
584
+ path: "tokenizer_config.json",
585
+ size: 768,
586
+ sha256: "62b1e4690e44d8c7bec7f22f228331db2d9886160ed7dc4b2068ca24af87d68a"
587
+ }
588
+ ];
589
+ /** The weights for each dtype at the pinned revision; the repository ships one int8 file under both names. */
590
+ const WEIGHTS = {
591
+ q8: {
592
+ path: "onnx/model_quantized.onnx",
593
+ size: 602401737,
594
+ sha256: "b514c342c20aec2431ea213bde1a03083e117ac3b6e77ba6eee57cac8b79cd29"
595
+ },
596
+ fp32: {
597
+ path: "onnx/model.onnx",
598
+ size: 602401737,
599
+ sha256: "b514c342c20aec2431ea213bde1a03083e117ac3b6e77ba6eee57cac8b79cd29"
600
+ }
601
+ };
602
+ /** The bundled embedding model's files at its pinned revision for one dtype. */
603
+ function embeddingModelSpec(dtype = "q8") {
604
+ const weights = WEIGHTS[dtype];
605
+ if (!weights) throw new Error(`${LOCAL_EMBEDDING_MODEL} has no ${dtype} file at revision ${LOCAL_EMBEDDING_MODEL_REVISION}; use q8 or fp32`);
606
+ return {
607
+ id: LOCAL_EMBEDDING_MODEL,
608
+ revision: LOCAL_EMBEDDING_MODEL_REVISION,
609
+ files: [...TOKENIZER_FILES, weights]
610
+ };
611
+ }
612
+ function getDtypeDisplaySize(dtype) {
613
+ return DTYPE_SIZES[dtype] ?? "unknown size";
614
+ }
615
+ /** Downloads the bundled embedding model into cacheDir unless it is already complete there. */
616
+ async function ensureModelDownloaded(opts) {
617
+ const cacheDir = opts?.cacheDir ?? LOCAL_EMBEDDING_CACHE_DIR_DEFAULT;
618
+ const dtype = opts?.dtype ?? "q8";
619
+ const spec = embeddingModelSpec(dtype);
620
+ const fetching = !opts?.offline && !isDownloaded(cacheDir, spec);
621
+ const started = performance.now();
622
+ if (fetching) process.stderr.write(`\nPreparing the local embedding model (a first run downloads ${getDtypeDisplaySize(dtype)})...\n`);
623
+ await downloadModel(spec, {
624
+ cacheDir,
625
+ offline: opts?.offline,
626
+ mirror: opts?.mirror
627
+ });
628
+ if (fetching) process.stderr.write(` Ready in ${Math.round((performance.now() - started) / 1e3)}s: ${cacheDir}\n`);
629
+ log$2.info("local embedding model ready", {
630
+ cacheDir,
631
+ dtype
632
+ }, {
633
+ event_name: "embedder.model.download.complete",
634
+ file: "packages/embedder/src/model-download.ts",
635
+ function: "ensureModelDownloaded",
636
+ site_id: "embedder.model.download.complete"
637
+ });
638
+ }
639
+ /**
97
640
  * Local ONNX embedding provider — PPLX embed v1 0.6B INT8, 1024-d vectors.
98
641
  *
99
642
  * Self-contained: all params via constructor; no app-level config dependency.
100
643
  */
101
644
  const log$1$1 = createLogger("embedder:local");
102
645
  let sharedExtractor;
103
- let sharedLoading;
646
+ let sharedLoading$1;
104
647
  let sharedRefCount = 0;
105
648
  let sharedPipelineKey;
106
649
  function buildSessionOptions(options) {
@@ -167,7 +710,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
167
710
  static resetStaticState() {
168
711
  LocalEmbedProvider.configuredCacheDir = void 0;
169
712
  sharedExtractor = void 0;
170
- sharedLoading = void 0;
713
+ sharedLoading$1 = void 0;
171
714
  sharedRefCount = 0;
172
715
  sharedPipelineKey = void 0;
173
716
  }
@@ -179,7 +722,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
179
722
  this.cacheDir = resolve(config?.cacheDir ?? LOCAL_EMBEDDING_CACHE_DIR_DEFAULT);
180
723
  this.dtype = config?.dtype ?? "q8";
181
724
  this.modelId = config?.model ?? "tss-deposium/pplx-embed-v1-0.6b-onnx-int8-standard";
182
- this.revision = config?.revision ?? (config?.model === void 0 ? "a18fdffe7480e6ea5643acb7757142b33838817a" : void 0);
725
+ this.revision = config?.revision ?? (this.modelId === "tss-deposium/pplx-embed-v1-0.6b-onnx-int8-standard" ? "a18fdffe7480e6ea5643acb7757142b33838817a" : void 0);
183
726
  this.nativeDim = config?.nativeDim ?? 1024;
184
727
  this.outputDim = config?.outputDim ?? this.nativeDim;
185
728
  if (this.outputDim > this.nativeDim) throw new Error(`outputDim (${this.outputDim}) cannot exceed nativeDim (${this.nativeDim}) — Matryoshka truncation only shrinks dimensions.`);
@@ -200,21 +743,21 @@ var LocalEmbedProvider = class LocalEmbedProvider {
200
743
  if (this._disposed) throw new Error("LocalEmbedProvider has been disposed");
201
744
  this.assertCompatibleSharedPipeline();
202
745
  if (sharedExtractor) return sharedExtractor;
203
- if (sharedLoading) {
204
- const extractor = await sharedLoading;
746
+ if (sharedLoading$1) {
747
+ const extractor = await sharedLoading$1;
205
748
  if (this._disposed) throw new Error("LocalEmbedProvider has been disposed");
206
749
  if (!sharedExtractor) sharedExtractor = extractor;
207
750
  return extractor;
208
751
  }
209
752
  sharedPipelineKey = this.pipelineKey;
210
- sharedLoading = this.initPipeline();
753
+ sharedLoading$1 = this.initPipeline();
211
754
  try {
212
- const extractor = await sharedLoading;
755
+ const extractor = await sharedLoading$1;
213
756
  sharedExtractor = extractor;
214
757
  if (this._disposed) throw new Error("LocalEmbedProvider has been disposed");
215
758
  return extractor;
216
759
  } finally {
217
- sharedLoading = void 0;
760
+ sharedLoading$1 = void 0;
218
761
  if (!sharedExtractor && sharedRefCount === 0) sharedPipelineKey = void 0;
219
762
  }
220
763
  }
@@ -225,13 +768,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
225
768
  async initPipeline() {
226
769
  if (LocalEmbedProvider.configuredCacheDir !== void 0 && LocalEmbedProvider.configuredCacheDir !== this.cacheDir) throw new Error(`transformers env is global; LocalEmbedProvider cacheDir must be consistent (existing: ${LocalEmbedProvider.configuredCacheDir}, requested: ${this.cacheDir})`);
227
770
  LocalEmbedProvider.configuredCacheDir = this.cacheDir;
228
- const { env, pipeline } = await import("@huggingface/transformers");
229
- env.cacheDir = this.cacheDir;
230
- env.allowRemoteModels = !this.offline;
231
- env.localModelPath = this.cacheDir;
232
- env.remotePathTemplate = `{model}/resolve/${this.revision ?? "main"}/`;
233
- const hfEndpoint = this.mirror?.trim();
234
- if (hfEndpoint) env.remoteHost = hfEndpoint.endsWith("/") ? hfEndpoint : `${hfEndpoint}/`;
771
+ const { pipeline } = await import("@huggingface/transformers");
235
772
  log$1$1.info("loading ONNX model", {
236
773
  model: this.modelId,
237
774
  cacheDir: this.cacheDir,
@@ -248,10 +785,20 @@ var LocalEmbedProvider = class LocalEmbedProvider {
248
785
  const t0 = performance.now();
249
786
  try {
250
787
  const sessionOptions = buildSessionOptions(this.sessionOptions);
251
- const extractor = await pipeline("feature-extraction", this.modelId, {
788
+ const download = {
789
+ cacheDir: this.cacheDir,
790
+ offline: this.offline,
791
+ mirror: this.mirror
792
+ };
793
+ const spec = this.modelId === "tss-deposium/pplx-embed-v1-0.6b-onnx-int8-standard" && this.revision === "a18fdffe7480e6ea5643acb7757142b33838817a" ? embeddingModelSpec(this.dtype) : await hubModelSpec(this.modelId, this.revision ?? "main", this.dtype, download);
794
+ const extractor = await pipeline("feature-extraction", await downloadModel(spec, download), {
252
795
  dtype: this.dtype,
253
796
  device: "cpu",
254
- session_options: sessionOptions
797
+ session_options: sessionOptions,
798
+ local_files_only: true
799
+ }).catch((error) => {
800
+ forgetDownload(this.cacheDir, spec);
801
+ throw error;
255
802
  });
256
803
  const durationMs = Math.round(performance.now() - t0);
257
804
  log$1$1.info("ONNX model loaded", {
@@ -335,7 +882,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
335
882
  this._disposed = true;
336
883
  sharedRefCount = Math.max(0, sharedRefCount - 1);
337
884
  if (sharedRefCount > 0) return;
338
- const pending = sharedLoading;
885
+ const pending = sharedLoading$1;
339
886
  if (pending) {
340
887
  const extractor = await pending.catch(() => void 0);
341
888
  if (sharedRefCount > 0) {
@@ -349,7 +896,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
349
896
  await sharedExtractor.dispose();
350
897
  sharedExtractor = void 0;
351
898
  }
352
- if (sharedLoading === void 0) sharedPipelineKey = void 0;
899
+ if (sharedLoading$1 === void 0) sharedPipelineKey = void 0;
353
900
  }
354
901
  async warmup() {
355
902
  await this.embed("warmup");
@@ -502,397 +1049,180 @@ var CachedEmbeddingProvider = class {
502
1049
  }
503
1050
  };
504
1051
  /**
505
- * model-download.ts — Shared ONNX model download utility.
1052
+ * Local cross-encoder that scores how well each text answers a query, on the CPU.
506
1053
  *
507
- * Idempotent: skips download when a .download-complete marker and .onnx files
508
- * exist in cacheDir. Interrupted downloads (no marker) trigger re-download.
509
- * User-facing progress goes to stderr (not stdout) so it doesn't interfere
510
- * with structured log output or piped commands.
1054
+ * The model reads Chinese and English (and other languages). It downloads through the shared downloader and loads in
1055
+ * the background on first use: until it is ready, or if it cannot load (offline with nothing cached, say), `score`
1056
+ * answers undefined and the caller keeps its own order.
511
1057
  */
512
- const log$2 = createLogger("embedder:model-download");
513
- /** Marker file written after a successful download to distinguish complete vs partial cache. */
514
- const DOWNLOAD_COMPLETE_MARKER = ".download-complete";
515
- /** Lock file for cross-process download serialization (O_EXCL based). */
516
- const DOWNLOAD_LOCK_FILE = ".download-lock";
517
- /** Max time (ms) to wait for another process's download before giving up. */
518
- const LOCK_WAIT_TIMEOUT_MS = 6e5;
519
- /** Poll interval (ms) when waiting for a competing download to finish. */
520
- const LOCK_POLL_INTERVAL_MS = 2e3;
521
- /** Stale lock threshold (ms) — locks older than this are assumed abandoned. */
522
- const LOCK_STALE_MS = 9e5;
523
- /** Lock heartbeat interval (ms) while owning the download lock. */
524
- const LOCK_HEARTBEAT_INTERVAL_MS = 5e3;
525
- function parseDownloadMarker(raw) {
526
- try {
527
- const parsed = JSON.parse(raw);
528
- const model = parsed.model;
529
- const revision = parsed.revision;
530
- const dtype = parsed.dtype;
531
- const completedAt = parsed.completedAt;
532
- if (typeof model !== "string" || typeof revision !== "string" || typeof dtype !== "string" || typeof completedAt !== "string") return null;
533
- return {
534
- model,
535
- revision,
536
- dtype,
537
- completedAt
538
- };
539
- } catch {
540
- return null;
541
- }
542
- }
543
- const DTYPE_SIZES = {
544
- q4: "~400MB",
545
- q8: "~639MB",
546
- fp16: "~1.2GB",
547
- fp32: "~2.4GB"
548
- };
549
- function getSystemRamGB() {
550
- return Math.round(totalmem() / 1073741824);
551
- }
1058
+ const log$4 = createLogger("embedder:local-reranker");
552
1059
  /**
553
- * Check if a valid model download exists in cacheDir.
554
- *
555
- * When `expectedRevision` and/or `expectedDtype` are provided, the marker
556
- * metadata is validated against them — a mismatch (e.g. after model upgrade)
557
- * returns false so the caller re-downloads. Without these params the check
558
- * is structural only (marker + .onnx files), which is appropriate for
559
- * lock-wait polling where dtype/revision aren't available.
1060
+ * Horizon-Labs/multilingual-reranker-small (Apache-2.0) in an 8-bit ONNX file Sno published; pinned revision and
1061
+ * file hashes, the same supply-chain rule as the embedding model.
560
1062
  */
561
- function isModelCached(cacheDir, expectedRevision, expectedDtype) {
562
- try {
563
- if (!existsSync(cacheDir)) return false;
564
- const markerPath = join(cacheDir, DOWNLOAD_COMPLETE_MARKER);
565
- if (!existsSync(markerPath)) return false;
566
- const onnxDir = join(cacheDir, LOCAL_EMBEDDING_MODEL, "onnx");
567
- if (!existsSync(onnxDir) || !readdirSync(onnxDir).some((e) => e.endsWith(".onnx"))) return false;
568
- if (expectedRevision !== void 0 || expectedDtype !== void 0) {
569
- const marker = parseDownloadMarker(readFileSync(markerPath, "utf8"));
570
- if (!marker) {
571
- log$2.warn("download marker is corrupt, re-download needed", { cacheDir }, {
572
- event_name: "embedder.model.download.ismodelcached",
573
- file: "packages/embedder/src/model-download.ts",
574
- function: "isModelCached",
575
- site_id: "embedder.model.download.ismodelcached.1"
576
- });
577
- return false;
578
- }
579
- if (expectedRevision !== void 0 && marker.revision !== expectedRevision) {
580
- log$2.info("cached model revision mismatch, re-download needed", {
581
- cached: String(marker.revision),
582
- expected: expectedRevision
583
- }, {
584
- event_name: "embedder.model.download.ismodelcached",
585
- file: "packages/embedder/src/model-download.ts",
586
- function: "isModelCached",
587
- site_id: "embedder.model.download.ismodelcached.2"
588
- });
589
- return false;
590
- }
591
- if (expectedDtype !== void 0 && marker.dtype !== expectedDtype) {
592
- log$2.info("cached model dtype mismatch, re-download needed", {
593
- cached: String(marker.dtype),
594
- expected: expectedDtype
595
- }, {
596
- event_name: "embedder.model.download.ismodelcached",
597
- file: "packages/embedder/src/model-download.ts",
598
- function: "isModelCached",
599
- site_id: "embedder.model.download.ismodelcached.3"
600
- });
601
- return false;
602
- }
1063
+ const LOCAL_RERANK_MODEL = {
1064
+ id: "sno-lab/multilingual-reranker-small-int8",
1065
+ revision: "ce76796ae42628f54f501271aeac16df8ecc8a6f",
1066
+ files: [
1067
+ {
1068
+ path: "config.json",
1069
+ size: 1995,
1070
+ sha256: "e9fd043628cd796a364020164a7a6ca78d29b0ec5cf135464489f54110f4b1da"
1071
+ },
1072
+ {
1073
+ path: "special_tokens_map.json",
1074
+ size: 636,
1075
+ sha256: "baec30ea10906f16adb8c18af7a34023002c1746542612b8b41c9f09e1351351"
1076
+ },
1077
+ {
1078
+ path: "tokenizer.json",
1079
+ size: 34363439,
1080
+ sha256: "7925f638b5444897efe3b4608eed56c1652f0ed39c2662c8302de1bc264c6088"
1081
+ },
1082
+ {
1083
+ path: "tokenizer_config.json",
1084
+ size: 46440,
1085
+ sha256: "ea349495764b24570b4560fe2e4a557e5c0a47e6bce782c2409b1d6445cf8633"
1086
+ },
1087
+ {
1088
+ path: "onnx/model_quantized.onnx",
1089
+ size: 171363319,
1090
+ sha256: "d2b03e74b3ea60ca486a118b4e2ab6bc96b173c64224a689d653e135753d89ad"
603
1091
  }
604
- return true;
605
- } catch (error) {
606
- log$2.warn("failed to inspect model cache directory", {
607
- cacheDir,
608
- error
609
- }, {
610
- event_name: "embedder.model.download.ismodelcached",
611
- file: "packages/embedder/src/model-download.ts",
612
- function: "isModelCached",
613
- site_id: "embedder.model.download.ismodelcached.4"
614
- });
615
- return false;
1092
+ ]
1093
+ };
1094
+ const SCORE_BATCH = 5;
1095
+ const LOAD_RETRY_MS = 6e5;
1096
+ let shared;
1097
+ let sharedLoading = false;
1098
+ let sharedUsers = 0;
1099
+ let sharedFailedAt;
1100
+ let releases = 0;
1101
+ const scoring = /* @__PURE__ */ new Set();
1102
+ var LocalReranker = class {
1103
+ options;
1104
+ disposed = false;
1105
+ constructor(options) {
1106
+ this.options = options;
1107
+ sharedUsers += 1;
616
1108
  }
617
- }
618
- function getDirSizeMB(dirPath) {
619
- let total = 0;
620
- try {
621
- const entries = readdirSync(dirPath, { recursive: true });
622
- for (const entry of entries) {
623
- if (typeof entry !== "string") continue;
624
- const fullPath = join(dirPath, entry);
625
- try {
626
- const stat = statSync(fullPath);
627
- if (stat.isFile()) total += stat.size;
628
- } catch {}
1109
+ /**
1110
+ * Raw relevance logits, one per text (higher is more relevant), or undefined while the model is not loaded.
1111
+ * The first call starts the load and does not wait for it.
1112
+ */
1113
+ async score(query, texts, signal) {
1114
+ if (texts.length === 0) return [];
1115
+ const loaded = shared;
1116
+ if (!loaded) {
1117
+ if (sharedFailedAt !== void 0 && Date.now() - sharedFailedAt >= LOAD_RETRY_MS) {
1118
+ sharedFailedAt = void 0;
1119
+ sharedLoading = false;
1120
+ }
1121
+ if (!sharedLoading) {
1122
+ sharedLoading = true;
1123
+ this.load();
1124
+ }
1125
+ return;
629
1126
  }
630
- } catch (error) {
631
- log$2.warn("failed to read directory for size calculation", {
632
- dirPath,
633
- error
634
- }, {
635
- event_name: "embedder.model.download.getdirsizemb",
636
- file: "packages/embedder/src/model-download.ts",
637
- function: "getDirSizeMB",
638
- site_id: "embedder.model.download.getdirsizemb.5"
639
- });
640
- }
641
- return Math.round(total / 1048576);
642
- }
643
- function getDtypeDisplaySize(dtype) {
644
- return DTYPE_SIZES[dtype] ?? "unknown size";
645
- }
646
- /**
647
- * Acquire an exclusive download lock using O_EXCL (atomic create-if-not-exists).
648
- * Returns true if lock acquired, false if another process holds it.
649
- */
650
- function tryAcquireLock(cacheDir) {
651
- const lockPath = join(cacheDir, DOWNLOAD_LOCK_FILE);
652
- try {
653
- mkdirSync(cacheDir, { recursive: true });
654
- const fd = openSync(lockPath, "wx");
655
- writeFileSync(fd, `${process.pid}\n${Date.now()}\n`);
656
- closeSync(fd);
657
- return true;
658
- } catch (error) {
659
- if (error instanceof Error && "code" in error && error.code === "EEXIST") return false;
660
- throw error;
661
- }
662
- }
663
- function releaseLock(cacheDir) {
664
- try {
665
- unlinkSync(join(cacheDir, DOWNLOAD_LOCK_FILE));
666
- } catch {}
667
- }
668
- function heartbeatLock(cacheDir) {
669
- const lockPath = join(cacheDir, DOWNLOAD_LOCK_FILE);
670
- try {
671
- const now = /* @__PURE__ */ new Date();
672
- utimesSync(lockPath, now, now);
673
- } catch {}
674
- }
675
- function isLockStale(cacheDir) {
676
- const lockPath = join(cacheDir, DOWNLOAD_LOCK_FILE);
677
- try {
678
- const stat = statSync(lockPath);
679
- if (Date.now() - stat.mtimeMs > LOCK_STALE_MS) return true;
680
- const pid = Number.parseInt(readFileSync(lockPath, "utf8").split("\n")[0] ?? "", 10);
681
- if (!Number.isInteger(pid) || pid <= 0) return false;
1127
+ const run = this.run(loaded, query, texts, signal);
1128
+ scoring.add(run);
682
1129
  try {
683
- process.kill(pid, 0);
684
- return false;
685
- } catch (error) {
686
- return error instanceof Error && "code" in error && error.code === "ESRCH";
687
- }
688
- } catch {
689
- return true;
690
- }
691
- }
692
- function sleep(ms) {
693
- return new Promise((resolve) => setTimeout(resolve, ms));
694
- }
695
- /**
696
- * Wait for an existing download lock to be released (another process finishing).
697
- * If the lock is stale (abandoned), break it and return so the caller can retry.
698
- *
699
- * `expectedRevision` / `expectedDtype` are forwarded to `isModelCached` so a
700
- * concurrent revision/dtype upgrade is not satisfied by a stale matching-shape
701
- * cache from the previous version. Without them, two processes upgrading the
702
- * same cacheDir can both return "finished" on the old artifacts.
703
- */
704
- async function waitForLock(cacheDir, expectedRevision, expectedDtype) {
705
- const lockPath = join(cacheDir, DOWNLOAD_LOCK_FILE);
706
- const deadline = Date.now() + LOCK_WAIT_TIMEOUT_MS;
707
- log$2.info("another process is downloading the model, waiting...", { cacheDir }, {
708
- event_name: "embedder.model.download.waitforlock",
709
- file: "packages/embedder/src/model-download.ts",
710
- function: "waitForLock",
711
- site_id: "embedder.model.download.waitforlock.6"
712
- });
713
- process.stderr.write(" Waiting for another download to finish...\n");
714
- while (Date.now() < deadline) {
715
- if (!existsSync(lockPath)) return;
716
- if (isModelCached(cacheDir, expectedRevision, expectedDtype)) return;
717
- if (isLockStale(cacheDir)) {
718
- log$2.warn("breaking stale download lock", { cacheDir }, {
719
- event_name: "embedder.model.download.waitforlock",
720
- file: "packages/embedder/src/model-download.ts",
721
- function: "waitForLock",
722
- site_id: "embedder.model.download.waitforlock.7"
723
- });
724
- releaseLock(cacheDir);
725
- return;
1130
+ return await run;
1131
+ } finally {
1132
+ scoring.delete(run);
726
1133
  }
727
- await sleep(LOCK_POLL_INTERVAL_MS);
728
1134
  }
729
- throw new Error(`Timed out (${LOCK_WAIT_TIMEOUT_MS / 1e3}s) waiting for model download lock. Another process may still be downloading. Check ${join(cacheDir, DOWNLOAD_LOCK_FILE)}`);
730
- }
731
- /**
732
- * Ensure the local ONNX embedding model is downloaded. Idempotent.
733
- *
734
- * - If .download-complete marker + .onnx files exist in cacheDir, logs "already cached" and returns.
735
- * - Otherwise, downloads with progress output to stderr.
736
- * - Resets `env.allowRemoteModels = false` after download to prevent
737
- * surprise network calls during inference.
738
- */
739
- async function ensureModelDownloaded(opts) {
740
- const cacheDir = opts?.cacheDir ?? LOCAL_EMBEDDING_CACHE_DIR_DEFAULT;
741
- const ramGB = getSystemRamGB();
742
- const dtype = opts?.dtype ?? "q8";
743
- if (isModelCached(cacheDir, "a18fdffe7480e6ea5643acb7757142b33838817a", dtype)) {
744
- const sizeMB = getDirSizeMB(cacheDir);
745
- log$2.info("local embedding model already cached", {
746
- sizeMB,
747
- cacheDir
748
- }, {
749
- event_name: "embedder.model.download.ensuremodeldownloaded",
750
- file: "packages/embedder/src/model-download.ts",
751
- function: "ensureModelDownloaded",
752
- site_id: "embedder.model.download.ensuremodeldownloaded.8"
753
- });
754
- return;
1135
+ async dispose() {
1136
+ if (this.disposed) return;
1137
+ this.disposed = true;
1138
+ sharedUsers = Math.max(0, sharedUsers - 1);
1139
+ if (sharedUsers > 0) return;
1140
+ const loaded = shared;
1141
+ releases += 1;
1142
+ shared = void 0;
1143
+ sharedLoading = false;
1144
+ sharedFailedAt = void 0;
1145
+ await Promise.allSettled(scoring);
1146
+ await loaded?.dispose();
755
1147
  }
756
- if (opts?.offline) return;
757
- const lockWasPresent = existsSync(join(cacheDir, DOWNLOAD_LOCK_FILE));
758
- if (!tryAcquireLock(cacheDir)) {
759
- await waitForLock(cacheDir, LOCAL_EMBEDDING_MODEL_REVISION, dtype);
760
- if (isModelCached(cacheDir, "a18fdffe7480e6ea5643acb7757142b33838817a", dtype)) {
761
- const sizeMB = getDirSizeMB(cacheDir);
762
- log$2.info("local embedding model already cached (downloaded by another process)", {
763
- sizeMB,
764
- cacheDir
765
- }, {
766
- event_name: "embedder.model.download.ensuremodeldownloaded",
767
- file: "packages/embedder/src/model-download.ts",
768
- function: "ensureModelDownloaded",
769
- site_id: "embedder.model.download.ensuremodeldownloaded.9"
1148
+ async run(loaded, query, texts, signal) {
1149
+ const order = texts.map((_, index) => index).sort((a, b) => (texts[a]?.length ?? 0) - (texts[b]?.length ?? 0));
1150
+ const scores = new Array(texts.length).fill(0);
1151
+ for (let start = 0; start < order.length; start += SCORE_BATCH) {
1152
+ if (signal?.aborted) return void 0;
1153
+ const run = order.slice(start, start + SCORE_BATCH);
1154
+ const inputs = loaded.tokenizer(new Array(run.length).fill(query), {
1155
+ text_pair: run.map((index) => texts[index] ?? ""),
1156
+ padding: true,
1157
+ truncation: true,
1158
+ max_length: 512
770
1159
  });
771
- return;
1160
+ const { logits } = await loaded.model(inputs);
1161
+ for (const [i, index] of run.entries()) scores[index] = Number(logits.data[i] ?? 0);
772
1162
  }
773
- if (!tryAcquireLock(cacheDir)) throw new Error(`Failed to acquire model download lock after waiting. Another process may still be downloading. Check ${join(cacheDir, DOWNLOAD_LOCK_FILE)}`);
1163
+ return scores;
774
1164
  }
775
- const modelDir = join(cacheDir, LOCAL_EMBEDDING_MODEL);
776
- let completed = false;
777
- let startedEmpty = false;
778
- const lockHeartbeat = setInterval(() => heartbeatLock(cacheDir), LOCK_HEARTBEAT_INTERVAL_MS);
779
- try {
780
- heartbeatLock(cacheDir);
781
- if (lockWasPresent) {
782
- rmSync(join(cacheDir, DOWNLOAD_COMPLETE_MARKER), { force: true });
783
- rmSync(modelDir, {
784
- recursive: true,
785
- force: true
786
- });
787
- } else if (!existsSync(join(cacheDir, DOWNLOAD_COMPLETE_MARKER)) && existsSync(modelDir) && existsSync(join(modelDir, "onnx")) && readdirSync(join(modelDir, "onnx")).some((e) => e.endsWith(".onnx"))) {
788
- writeFileSync(join(cacheDir, DOWNLOAD_COMPLETE_MARKER), JSON.stringify({
789
- model: LOCAL_EMBEDDING_MODEL,
790
- revision: LOCAL_EMBEDDING_MODEL_REVISION,
791
- dtype,
792
- completedAt: (/* @__PURE__ */ new Date()).toISOString()
793
- }));
794
- completed = true;
795
- return;
796
- }
797
- startedEmpty = !existsSync(modelDir);
798
- const banner = [
799
- "",
800
- "Downloading local embedding model (first run only)",
801
- `${"─".repeat(52)}`,
802
- ` Model: ${LOCAL_EMBEDDING_MODEL}`,
803
- ` Revision: ${LOCAL_EMBEDDING_MODEL_REVISION.slice(0, 12)}`,
804
- ` Dtype: ${dtype} (${getDtypeDisplaySize(dtype)})`,
805
- ` RAM: ${ramGB}GB`,
806
- ` Cache dir: ${cacheDir}`,
807
- "",
808
- " This may take a few minutes on the first run...",
809
- ""
810
- ];
811
- process.stderr.write(`${banner.join("\n")}\n`);
812
- log$2.info("starting model download", {
813
- model: LOCAL_EMBEDDING_MODEL,
814
- revision: LOCAL_EMBEDDING_MODEL_REVISION,
815
- dtype,
816
- cacheDir
817
- }, {
818
- event_name: "embedder.model.download.ensuremodeldownloaded",
819
- file: "packages/embedder/src/model-download.ts",
820
- function: "ensureModelDownloaded",
821
- site_id: "embedder.model.download.ensuremodeldownloaded.10"
822
- });
823
- const { env, pipeline } = await import("@huggingface/transformers");
824
- const prevCacheDir = env.cacheDir;
825
- const prevAllowRemote = env.allowRemoteModels;
826
- const prevLocalModelPath = env.localModelPath;
827
- const prevRemoteHost = env.remoteHost;
828
- const prevRemotePathTemplate = env.remotePathTemplate;
829
- env.cacheDir = cacheDir;
830
- env.allowRemoteModels = true;
831
- env.localModelPath = cacheDir;
832
- env.remotePathTemplate = `{model}/resolve/${LOCAL_EMBEDDING_MODEL_REVISION}/`;
833
- if (opts?.mirror) env.remoteHost = opts.mirror.endsWith("/") ? opts.mirror : `${opts.mirror}/`;
834
- let lastProgress = 0;
835
- const startTime = performance.now();
1165
+ async load() {
1166
+ const release = releases;
1167
+ const started = performance.now();
836
1168
  try {
837
- await pipeline("feature-extraction", LOCAL_EMBEDDING_MODEL, {
838
- dtype,
839
- device: "cpu",
840
- progress_callback: (progress) => {
841
- if (progress.status === "progress" && typeof progress.progress === "number") {
842
- const pct = Math.round(progress.progress);
843
- if (pct >= lastProgress + 10) {
844
- lastProgress = pct;
845
- process.stderr.write(` ${pct}% — ${progress.file ?? ""}\n`);
1169
+ const { AutoModelForSequenceClassification, AutoTokenizer } = await import("@huggingface/transformers");
1170
+ const dir = await downloadModel(LOCAL_RERANK_MODEL, this.options);
1171
+ const open = async () => {
1172
+ return {
1173
+ tokenizer: await AutoTokenizer.from_pretrained(dir, { local_files_only: true }),
1174
+ model: await AutoModelForSequenceClassification.from_pretrained(dir, {
1175
+ dtype: "q8",
1176
+ device: "cpu",
1177
+ local_files_only: true,
1178
+ session_options: {
1179
+ ...LOCAL_EMBEDDING_SESSION_OPTIONS_DEFAULT,
1180
+ interOpNumThreads: 1,
1181
+ ...this.options.intraOpNumThreads ? { intraOpNumThreads: this.options.intraOpNumThreads } : {}
846
1182
  }
847
- } else if (progress.status === "done" && progress.file) process.stderr.write(` done ${progress.file}\n`);
1183
+ })
1184
+ };
1185
+ };
1186
+ const { tokenizer, model } = await open().catch((error) => {
1187
+ forgetDownload(this.options.cacheDir, LOCAL_RERANK_MODEL);
1188
+ throw error;
1189
+ });
1190
+ if (release !== releases) {
1191
+ await model.dispose();
1192
+ return;
1193
+ }
1194
+ shared = {
1195
+ tokenizer: (texts, options) => tokenizer(texts, options),
1196
+ model: (inputs) => model(inputs),
1197
+ dispose: async () => {
1198
+ await model.dispose();
848
1199
  }
1200
+ };
1201
+ log$4.info("local reranker loaded", {
1202
+ duration_ms: Math.round(performance.now() - started),
1203
+ model: LOCAL_RERANK_MODEL.id
1204
+ }, {
1205
+ event_name: "embedder.local_reranker.loaded",
1206
+ file: "packages/embedder/src/local-reranker.ts",
1207
+ function: "load",
1208
+ site_id: "embedder.local_reranker.loaded"
849
1209
  });
850
- } finally {
851
- env.cacheDir = prevCacheDir;
852
- env.allowRemoteModels = prevAllowRemote;
853
- env.localModelPath = prevLocalModelPath;
854
- env.remoteHost = prevRemoteHost;
855
- env.remotePathTemplate = prevRemotePathTemplate;
1210
+ return shared;
1211
+ } catch (error) {
1212
+ log$4.warn("local reranker unavailable; recall keeps its cosine order", {
1213
+ error,
1214
+ offline: this.options.offline === true
1215
+ }, {
1216
+ event_name: "embedder.local_reranker.unavailable",
1217
+ file: "packages/embedder/src/local-reranker.ts",
1218
+ function: "load",
1219
+ site_id: "embedder.local_reranker.unavailable"
1220
+ });
1221
+ sharedFailedAt = Date.now();
1222
+ return;
856
1223
  }
857
- writeFileSync(join(cacheDir, DOWNLOAD_COMPLETE_MARKER), JSON.stringify({
858
- model: LOCAL_EMBEDDING_MODEL,
859
- revision: LOCAL_EMBEDDING_MODEL_REVISION,
860
- dtype,
861
- completedAt: (/* @__PURE__ */ new Date()).toISOString()
862
- }));
863
- completed = true;
864
- const elapsedSec = Math.round((performance.now() - startTime) / 1e3);
865
- const finalSizeMB = getDirSizeMB(cacheDir);
866
- const summary = [
867
- "",
868
- " Download complete!",
869
- ` Size: ${finalSizeMB}MB | Time: ${elapsedSec}s`,
870
- ` Location: ${cacheDir}`,
871
- ""
872
- ];
873
- process.stderr.write(`${summary.join("\n")}\n`);
874
- log$2.info("model download complete", {
875
- model: LOCAL_EMBEDDING_MODEL,
876
- revision: LOCAL_EMBEDDING_MODEL_REVISION,
877
- dtype,
878
- sizeMB: finalSizeMB,
879
- elapsedSec,
880
- cacheDir
881
- }, {
882
- event_name: "embedder.model.download.ensuremodeldownloaded",
883
- file: "packages/embedder/src/model-download.ts",
884
- function: "ensureModelDownloaded",
885
- site_id: "embedder.model.download.ensuremodeldownloaded.11"
886
- });
887
- } finally {
888
- clearInterval(lockHeartbeat);
889
- if (!completed && startedEmpty) rmSync(modelDir, {
890
- recursive: true,
891
- force: true
892
- });
893
- releaseLock(cacheDir);
894
1224
  }
895
- }
1225
+ };
896
1226
  //#endregion
897
1227
  //#region config/index.ts
898
1228
  /**
@@ -906,7 +1236,7 @@ const MEMORY_SHUTDOWN_TIMEOUT_MS = 5e3;
906
1236
  const DEFAULT_IMPORTANCE = .7;
907
1237
  /** Default scope for memories without explicit scope */
908
1238
  const DEFAULT_SCOPE = "global";
909
- /** Default embedding vector dimension (Voyage AI 1024-d) */
1239
+ /** Default embedding vector dimension (the local PPLX embedder outputs 1024-d) */
910
1240
  const VECTOR_DIMENSION_DEFAULT = 1024;
911
1241
  /** Production sno.ai host origin used by @snoai/observability. */
912
1242
  const SNO_OBSERVE_DEFAULT_BASE_URL = "https://www.sno.ai";
@@ -1015,12 +1345,19 @@ const MMR_LAMBDA = .7;
1015
1345
  const RERANK_BLEND_VECTOR = .3;
1016
1346
  /** Weight for cross-encoder score in rerank blend */
1017
1347
  const RERANK_BLEND_CROSS = .7;
1018
- /** Fusion-score weight in local cosine-blend rerank */
1019
- const LIGHTWEIGHT_FUSION_WEIGHT = .7;
1348
+ /**
1349
+ * Fusion-score weight in local cosine-blend rerank.
1350
+ *
1351
+ * The fused score keeps a keyword-only hit at its full keyword score, so a memory sharing one word with the query
1352
+ * outranks the one that answers it; at 0.7 the local ranking passed that order through almost unchanged. Measured
1353
+ * 2026-10-15 on LoCoMo (1,540 questions, the product store and retriever, weights fitted on half the conversations
1354
+ * and checked on the other half): the right memory in the first five went from 27% to 68% in English and from 9% to
1355
+ * 58% in a Chinese translation at 0.1 / 0.9. A candidate with no stored vector keeps its fused score and would now
1356
+ * rank high; none of 27,064 candidates in 299 real local rankings lacked one.
1357
+ */
1358
+ const LIGHTWEIGHT_FUSION_WEIGHT = .1;
1020
1359
  /** Cosine-similarity weight in local cosine-blend rerank */
1021
- const LIGHTWEIGHT_COSINE_WEIGHT = .3;
1022
- /** Default rerank model identifier */
1023
- const DEFAULT_RERANK_MODEL = "rerank-2";
1360
+ const LIGHTWEIGHT_COSINE_WEIGHT = .9;
1024
1361
  /** Default timeout for rerank API calls in milliseconds */
1025
1362
  const DEFAULT_RERANK_TIMEOUT_MS = 15e3;
1026
1363
  /**
@@ -1477,7 +1814,6 @@ const retrievalConfigSchema = z.object({
1477
1814
  ]).default("lightweight"),
1478
1815
  candidatePoolSize: z.number().int().min(10).max(2e3).default(64),
1479
1816
  rerankApiKey: z.string().optional(),
1480
- rerankModel: z.string().default(DEFAULT_RERANK_MODEL),
1481
1817
  rerankTimeoutMs: z.number().int().min(1e3).max(12e4).default(DEFAULT_RERANK_TIMEOUT_MS),
1482
1818
  recencyHalfLifeDays: z.number().min(0).max(365).default(14),
1483
1819
  recencyWeight: z.number().min(0).max(RECENCY_WEIGHT_MAX).default(RECENCY_WEIGHT),
@@ -1504,20 +1840,9 @@ const retrievalConfigSchema = z.object({
1504
1840
  timeDecayFloor: z.number().min(0).max(1).optional(),
1505
1841
  /** Relevance vs diversity tradeoff (default: 0.7) */
1506
1842
  mmrLambda: z.number().min(0).max(1).optional(),
1507
- /** Custom rerank API endpoint URL. */
1843
+ /** Address of Sno's reranker (the Sno GPU address plus `/rerank`). */
1508
1844
  rerankEndpoint: z.string().optional(),
1509
- /** Rerank provider name */
1510
- rerankProvider: z.enum([
1511
- "jina",
1512
- "siliconflow",
1513
- "pinecone",
1514
- "voyage",
1515
- "dashscope",
1516
- "tei",
1517
- "sno-gpu",
1518
- "custom"
1519
- ]).optional(),
1520
- /** Hard cap on candidates sent per rerank API request (some deployments reject over-limit batches) */
1845
+ /** Cap on candidates sent to Sno's reranker in total */
1521
1846
  rerankMaxCandidates: z.number().int().min(1).max(2e3).optional(),
1522
1847
  /** Scaling factor for access-based reinforcement (0 = disabled, default: 0.5) */
1523
1848
  reinforcementFactor: z.number().min(0).max(5).default(.5),
@@ -1525,11 +1850,6 @@ const retrievalConfigSchema = z.object({
1525
1850
  maxHalfLifeMultiplier: z.number().min(1).max(10).default(3)
1526
1851
  }).prefault({}).transform((ret, ctx) => {
1527
1852
  if (ret.rerank === "none") return ret;
1528
- if ((ret.rerank === "cross-encoder" || ret.rerankEndpoint !== void 0) && ret.rerankProvider === void 0) ctx.addIssue({
1529
- code: z.ZodIssueCode.custom,
1530
- path: ["rerankProvider"],
1531
- message: "retrieval.rerankProvider is required when retrieval.rerank is \"cross-encoder\" or retrieval.rerankEndpoint is set: the provider decides the request shape and the per-request batch limit"
1532
- });
1533
1853
  if (ret.rerankEndpoint !== void 0) try {
1534
1854
  new URL(ret.rerankEndpoint);
1535
1855
  } catch {
@@ -2296,19 +2616,6 @@ const settingsSchema = z.strictObject({
2296
2616
  "cross-encoder",
2297
2617
  "none"
2298
2618
  ]),
2299
- provider: z.enum([
2300
- "jina",
2301
- "siliconflow",
2302
- "pinecone",
2303
- "voyage",
2304
- "dashscope",
2305
- "tei",
2306
- "sno-gpu",
2307
- "custom"
2308
- ]),
2309
- endpoint: z.string(),
2310
- model: z.string(),
2311
- apiKey: z.string(),
2312
2619
  timeoutMs: z.number().int().min(1e3).max(12e4),
2313
2620
  maxCandidates: z.number().int().min(1).max(2e3)
2314
2621
  }),
@@ -2401,10 +2708,6 @@ function defaultSettings() {
2401
2708
  },
2402
2709
  rerank: {
2403
2710
  mode: "cross-encoder",
2404
- provider: "sno-gpu",
2405
- endpoint: "",
2406
- model: engine.retrieval.rerankModel,
2407
- apiKey: "",
2408
2711
  timeoutMs: engine.retrieval.rerankTimeoutMs,
2409
2712
  maxCandidates: 64
2410
2713
  },
@@ -2474,18 +2777,11 @@ function defaultSettings() {
2474
2777
  };
2475
2778
  }
2476
2779
  /**
2477
- * The "sno-gpu" reranker is Sno's own: its address is the Sno GPU address and its key is the Sno GPU key, and nothing
2478
- * else: a third-party key or address in the rerank settings is never sent to Sno. Only REM Enhanced calls Sno GPU;
2479
- * any other mode, or no key yet, ranks locally, which is the configured strategy, not an error.
2780
+ * Recall ranking is local, or Sno's reranker: its address is the Sno GPU address and its key is the Sno GPU key. Only
2781
+ * REM Enhanced calls Sno GPU; any other mode, or no key yet, ranks locally, which is the configured strategy, not an error.
2480
2782
  */
2481
2783
  function rerankSettings(settings) {
2482
2784
  const { rerank, snoGpu } = settings;
2483
- if (rerank.provider !== "sno-gpu") return {
2484
- rerank: rerank.mode,
2485
- provider: rerank.provider,
2486
- endpoint: rerank.endpoint || void 0,
2487
- apiKey: rerank.apiKey
2488
- };
2489
2785
  let endpoint;
2490
2786
  try {
2491
2787
  endpoint = new URL("rerank", snoGpu.baseUrl.endsWith("/") ? snoGpu.baseUrl : `${snoGpu.baseUrl}/`).toString();
@@ -2500,7 +2796,6 @@ function rerankSettings(settings) {
2500
2796
  const local = rerank.mode !== "cross-encoder" || settings.mode !== "rem-enhanced" || !snoGpu.apiKey || endpoint === void 0;
2501
2797
  return {
2502
2798
  rerank: local && rerank.mode === "cross-encoder" ? "lightweight" : rerank.mode,
2503
- provider: local ? void 0 : rerank.provider,
2504
2799
  endpoint: local ? void 0 : endpoint,
2505
2800
  apiKey: local ? "" : snoGpu.apiKey
2506
2801
  };
@@ -2524,11 +2819,9 @@ function settingsToPluginConfig(settings) {
2524
2819
  },
2525
2820
  retrieval: {
2526
2821
  rerank: sno.rerank,
2527
- rerankProvider: sno.provider,
2528
2822
  recallTopK: settings.recall.prompt.limit,
2529
2823
  minScore: settings.recall.prompt.minScore,
2530
2824
  rerankEndpoint: sno.endpoint,
2531
- rerankModel: settings.rerank.model,
2532
2825
  rerankApiKey: sno.apiKey,
2533
2826
  rerankTimeoutMs: settings.rerank.timeoutMs,
2534
2827
  rerankMaxCandidates: settings.rerank.maxCandidates
@@ -2712,4 +3005,4 @@ function readMaintenanceOverrides() {
2712
3005
  };
2713
3006
  }
2714
3007
  //#endregion
2715
- export { FIXED_IDX_MEMORY_ACTIVE_TASK_CURRENT_REVISION as $, MAX_CANDIDATE_POOL_SIZE as $n, FIXED_PROTOCOL_VALUE_79 as $t, modelCallDestination as A, DEFAULT_REFLECTION_ERROR_SCAN_MAX_CHARS as An, MEMORY_CANCEL_ON_DISCONNECT_HEADER as Ar, FIXED_MEMORY_PROFILE_RECOVERY_ENTRIES as At, FIXED_EXTERNAL_VALUE_49 as B, FORGET_QUERY_MIN_SCORE as Bn, FIXED_PROTOCOL_VALUE_63 as Bt, getSnoStationMemStateDir as C, CHUNK_OVERLAP_TOKENS as Cn, CachedEmbeddingProvider as Cr, FIXED_MEMORY_CHUNKS_MEM_FACET_IDX as Ct, settingsToPluginConfig as D, DEFAULT_IMPORTANCE as Dn, LocalEmbedProvider as Dr, FIXED_MEMORY_MEMORIES_FACT_ID_INSERT_GUARD as Dt, defaultSettings as E, DEFAULT_BM25_WEIGHT as En, LOCAL_EMBEDDING_MODEL_REVISION as Er, FIXED_MEMORY_MEMORIES as Et, observeConfigSchema as F, DEFAULT_VECTOR_WEIGHT as Fn, MEMORY_SKIN_HEADER as Fr, FIXED_MEMORY_SNO_AI_EXTRACT as Ft, FIXED_EXTERNAL_VALUE_55 as G, IMPORTANCE_WEIGHT_BASE as Gn, FIXED_PROTOCOL_VALUE_68 as Gt, FIXED_EXTERNAL_VALUE_52 as H, HEAD_EXTRACT_MIN_CONTENT_TOKENS as Hn, FIXED_PROTOCOL_VALUE_65 as Ht, extractionConfigSchema as I, EMBEDDER_DIM as In, REM_SIDECAR_TOKEN_HEADER as Ir, FIXED_MEMORY_SNO_EXTRACT_CHAT as It, FIXED_EXTERNAL_VALUE_58 as J, LIGHTWEIGHT_COSINE_WEIGHT as Jn, FIXED_PROTOCOL_VALUE_74 as Jt, FIXED_EXTERNAL_VALUE_56 as K, INTEGRITY_CHECK_INTERVAL_MS as Kn, FIXED_PROTOCOL_VALUE_69 as Kt, memoryReflectionConfigSchema as L, EMBEDDER_MODEL_DEFAULT as Ln, memoryMethod as Lr, FIXED_MEMORY_SNO_EXTRACT_PROFILE as Lt, retrievalConfigSchema as M, DEFAULT_RERANK_MODEL as Mn, MEMORY_ERROR_STATUS as Mr, FIXED_MEMORY_PROVIDER_PROJECT_AGENTS as Mt, isObserveAgentId as N, DEFAULT_RERANK_TIMEOUT_MS as Nn, MEMORY_RECONNECT_INTERVAL_MS as Nr, FIXED_MEMORY_PROVIDER_PROJECT_MAPPINGS as Nt, MODEL_CALLS as O, DEFAULT_RECALL_LIFECYCLE as On, ensureModelDownloaded as Or, FIXED_MEMORY_MEMORIES_FACT_ID_UPDATE_GUARD as Ot, observeAgentId as P, DEFAULT_SCOPE as Pn, MEMORY_ROUTES as Pr, FIXED_MEMORY_ROW_PATH_PATTERN as Pt, FIXED_IDX_MEMORY as Q, MAX_AGGREGATION_RESULT_TOKENS as Qn, FIXED_PROTOCOL_VALUE_78 as Qt, selfImprovementConfigSchema as R, EMBEDDER_PROVIDER_DEFAULT as Rn, FIXED_MEMORY_TASK_LIFECYCLE_COMMANDS as Rt, getSidecarSocketPath as S, CHUNK_MIN_TOKENS as Sn, recallLifecycleSchema as Sr, FIXED_MEMORY_CHUNKS_MEMORY_ID_IDX as St, readSettings as T, CHUNK_TOKENIZER_MODE as Tn, LOCAL_EMBEDDING_MODEL as Tr, FIXED_MEMORY_EXTRACTION_TIMESTAMPS as Tt, FIXED_EXTERNAL_VALUE_53 as U, HEAD_EXTRACT_OVERLAP_DROP_RATIO as Un, FIXED_PROTOCOL_VALUE_66 as Ut, FIXED_EXTERNAL_VALUE_51 as V, FTS_MERGE_INTERVAL_MS as Vn, FIXED_PROTOCOL_VALUE_64 as Vt, FIXED_EXTERNAL_VALUE_54 as W, HEAD_EXTRACT_TOKEN_BUDGET as Wn, FIXED_PROTOCOL_VALUE_67 as Wt, FIXED_EXTERNAL_VALUE_8 as X, LIGHTWEIGHT_RERANK_PENALTY as Xn, FIXED_PROTOCOL_VALUE_76 as Xt, FIXED_EXTERNAL_VALUE_62 as Y, LIGHTWEIGHT_FUSION_WEIGHT as Yn, FIXED_PROTOCOL_VALUE_75 as Yt, FIXED_EXTERNAL_VALUE_9 as Z, MAINTENANCE_TICK_MS as Zn, FIXED_PROTOCOL_VALUE_77 as Zt, readRemTestHoldMs as _, BACKUP_MIN_FREE_DISK_RATIO as _n, USAGE_EVENT_RETENTION_INTERVAL_MS as _r, FIXED_MEMORY_CHUNKS as _t, REM_MODEL_OUTPUT_TOKEN_CAP as a, PERSISTED_PROVIDER_SYSTEM as an, MMR_LAMBDA as ar, FIXED_IDX_MEMORY_MEMORIES_LANE_PROJECT as at, getPrincipal as b, CHUNKING_VERSION as bn, experimentCandidatePoolOverride as br, FIXED_MEMORY_CHUNKS_AU as bt, REM_SIDECAR_ORIGIN as c, SUPPORTED_LOCALES as cn, PLANNER_STATISTICS_INTERVAL_MS as cr, FIXED_IDX_MEMORY_MEMORIES_PROJECT_FACT_KEY_ACTIVE as ct, getRemDiscoveryPath as d, ADJACENCY_BONUS_PER_PAIR as dn, REM_TRIGGER_CHECK_INTERVAL_MS as dr, FIXED_MEMORY_ACTIVE_TASK_EVIDENCE as dt, FIXED_VEC_MEMORY as en, MAX_CHUNK_FETCH_LIMIT as er, FIXED_IDX_MEMORY_ACTIVE_TASK_EVIDENCE_INSTANCE as et, getRemJobJournalPath as f, ATOMIC_CAPTURE_OUTPUT_TOKEN_BUDGET as fn, RERANK_BLEND_CROSS as fr, FIXED_MEMORY_ACTIVE_TASK_INSTANCES as ft, readRemOperationalConfig as g, BACKUP_INTERVAL_MS as gn, TIME_DECAY_FLOOR as gr, FIXED_MEMORY_ACTIVE_TASK_TRANSITIONS as gt, readMaintenanceOverrides as h, ATOMIC_EXTRACTION_MAX_INPUT_TOKENS as hn, SNO_OBSERVE_FLUSH_TIMEOUT_MS as hr, FIXED_MEMORY_ACTIVE_TASK_REVISIONS as ht, REM_JOBS_PATH_PREFIX as i, PERSISTED_CONTENT_HASH_V3 as in, MIN_RECALL_TOKEN_BUDGET as ir, FIXED_IDX_MEMORY_MEMORIES_FACT_ID as it, SESSION_STRATEGIES as j, DEFAULT_REFLECTION_SESSION_TTL_MS as jn, MEMORY_DEFAULT_SKIN_ID as jr, FIXED_MEMORY_PROVIDER_AGENT_MAPPINGS as jt, MODEL_CALL_WORKLOAD as k, DEFAULT_RECALL_TOKEN_BUDGET as kn, MEMORY_BODY_LIMIT_BYTES as kr, FIXED_MEMORY_MIGRATION_MARKERS as kt, REM_SOURCE as l, isSupportedLocale as ln, RECENCY_WEIGHT as lr, FIXED_IDX_MEMORY_MEMORIES_PROJECT_TIMESTAMP as lt, isRemTraceEnabled as m, ATOMIC_ENRICHMENT_OUTPUT_TOKEN_BUDGET as mn, RETRIEVAL_STORAGE_CHUNK_PROFILE as mr, FIXED_MEMORY_ACTIVE_TASK_MIGRATION_MANIFESTS as mt, MEMORY_USAGE_FLUSH_INTERVAL_MS as n, PERSISTED_CANDIDATE_HASH_V1 as nn, MAX_RECALLED_TODO_TOKENS as nr, FIXED_IDX_MEMORY_MEMORIES_CATEGORY as nt, REM_RUN_PATH as o, embeddingConfigSchema as on, MULTI_HIT_BONUS_CAP as or, FIXED_IDX_MEMORY_MEMORIES_PROJECT as ot, getRemTraceLogPath as p, ATOMIC_CAPTURE_TIMEOUT_MS as pn, RERANK_BLEND_VECTOR as pr, FIXED_MEMORY_ACTIVE_TASK_MIGRATION_EVIDENCE as pt, FIXED_EXTERNAL_VALUE_57 as q, INTRA_MEMORY_COSINE_THRESHOLD as qn, FIXED_PROTOCOL_VALUE_73 as qt, REM_CORRELATION_ID_HEADER as r, PERSISTED_CONTENT_HASH_V1 as rn, MEMORY_SHUTDOWN_TIMEOUT_MS as rr, FIXED_IDX_MEMORY_MEMORIES_CONTENT_HASH as rt, REM_SIDECAR_HOST as s, llmRoutingConfigSchema as sn, MULTI_HIT_BONUS_PER_HIT as sr, FIXED_IDX_MEMORY_MEMORIES_PROJECT_CONTENT_HASH as st, HEALTH_PATH as t, FIXED_VEC_MEMORY_CHUNKS as tn, MAX_LIST_LIMIT as tr, FIXED_IDX_MEMORY_ACTIVE_TASK_INSTANCES_PROJECTION as tt, getRemChassisJournalPath as u, ADJACENCY_BONUS_CAP as un, REFLECTION_SLICE_CACHE_TTL_MS as ur, FIXED_MEMORY as ut, SettingsUnavailableError as v, BONUS_TOTAL_INVARIANT as vn, USAGE_OUTBOX_INTERVAL_MS as vr, FIXED_MEMORY_CHUNKS_AD as vt, getStateDir as w, CHUNK_TARGET_TOKENS as wn, LOCAL_EMBEDDING_CACHE_DIR_DEFAULT as wr, FIXED_MEMORY_CHUNKS_MEM_IDX as wt, getSettingsPath as x, CHUNK_MAX_TOKENS as xn, experimentMmrDisabled as xr, FIXED_MEMORY_CHUNKS_FTS as xt, getDiscoveryPath as y, CACHE_TTL_MS as yn, VECTOR_DIMENSION_DEFAULT as yr, FIXED_MEMORY_CHUNKS_AI as yt, sessionMemoryConfigSchema as z, EVAL_QA_TRACES_FILENAME as zn, FIXED_MEMORY_UNPLACED_CANDIDATES as zt };
3008
+ export { FIXED_IDX_MEMORY_ACTIVE_TASK_CURRENT_REVISION as $, MAX_CHUNK_FETCH_LIMIT as $n, FIXED_PROTOCOL_VALUE_79 as $t, modelCallDestination as A, DEFAULT_REFLECTION_ERROR_SCAN_MAX_CHARS as An, MEMORY_CANCEL_ON_DISCONNECT_HEADER as Ar, FIXED_MEMORY_PROFILE_RECOVERY_ENTRIES as At, FIXED_EXTERNAL_VALUE_49 as B, FTS_MERGE_INTERVAL_MS as Bn, FIXED_PROTOCOL_VALUE_63 as Bt, getSnoStationMemStateDir as C, CHUNK_OVERLAP_TOKENS as Cn, LOCAL_EMBEDDING_CACHE_DIR_DEFAULT as Cr, FIXED_MEMORY_CHUNKS_MEM_FACET_IDX as Ct, settingsToPluginConfig as D, DEFAULT_IMPORTANCE as Dn, LocalReranker as Dr, FIXED_MEMORY_MEMORIES_FACT_ID_INSERT_GUARD as Dt, defaultSettings as E, DEFAULT_BM25_WEIGHT as En, LocalEmbedProvider as Er, FIXED_MEMORY_MEMORIES as Et, observeConfigSchema as F, EMBEDDER_DIM as Fn, MEMORY_SKIN_HEADER as Fr, FIXED_MEMORY_SNO_AI_EXTRACT as Ft, FIXED_EXTERNAL_VALUE_55 as G, INTEGRITY_CHECK_INTERVAL_MS as Gn, FIXED_PROTOCOL_VALUE_68 as Gt, FIXED_EXTERNAL_VALUE_52 as H, HEAD_EXTRACT_OVERLAP_DROP_RATIO as Hn, FIXED_PROTOCOL_VALUE_65 as Ht, extractionConfigSchema as I, EMBEDDER_MODEL_DEFAULT as In, REM_SIDECAR_TOKEN_HEADER as Ir, FIXED_MEMORY_SNO_EXTRACT_CHAT as It, FIXED_EXTERNAL_VALUE_58 as J, LIGHTWEIGHT_FUSION_WEIGHT as Jn, FIXED_PROTOCOL_VALUE_74 as Jt, FIXED_EXTERNAL_VALUE_56 as K, INTRA_MEMORY_COSINE_THRESHOLD as Kn, FIXED_PROTOCOL_VALUE_69 as Kt, memoryReflectionConfigSchema as L, EMBEDDER_PROVIDER_DEFAULT as Ln, memoryMethod as Lr, FIXED_MEMORY_SNO_EXTRACT_PROFILE as Lt, retrievalConfigSchema as M, DEFAULT_RERANK_TIMEOUT_MS as Mn, MEMORY_ERROR_STATUS as Mr, FIXED_MEMORY_PROVIDER_PROJECT_AGENTS as Mt, isObserveAgentId as N, DEFAULT_SCOPE as Nn, MEMORY_RECONNECT_INTERVAL_MS as Nr, FIXED_MEMORY_PROVIDER_PROJECT_MAPPINGS as Nt, MODEL_CALLS as O, DEFAULT_RECALL_LIFECYCLE as On, ensureModelDownloaded as Or, FIXED_MEMORY_MEMORIES_FACT_ID_UPDATE_GUARD as Ot, observeAgentId as P, DEFAULT_VECTOR_WEIGHT as Pn, MEMORY_ROUTES as Pr, FIXED_MEMORY_ROW_PATH_PATTERN as Pt, FIXED_IDX_MEMORY as Q, MAX_CANDIDATE_POOL_SIZE as Qn, FIXED_PROTOCOL_VALUE_78 as Qt, selfImprovementConfigSchema as R, EVAL_QA_TRACES_FILENAME as Rn, FIXED_MEMORY_TASK_LIFECYCLE_COMMANDS as Rt, getSidecarSocketPath as S, CHUNK_MIN_TOKENS as Sn, CachedEmbeddingProvider as Sr, FIXED_MEMORY_CHUNKS_MEMORY_ID_IDX as St, readSettings as T, CHUNK_TOKENIZER_MODE as Tn, LOCAL_EMBEDDING_MODEL_REVISION as Tr, FIXED_MEMORY_EXTRACTION_TIMESTAMPS as Tt, FIXED_EXTERNAL_VALUE_53 as U, HEAD_EXTRACT_TOKEN_BUDGET as Un, FIXED_PROTOCOL_VALUE_66 as Ut, FIXED_EXTERNAL_VALUE_51 as V, HEAD_EXTRACT_MIN_CONTENT_TOKENS as Vn, FIXED_PROTOCOL_VALUE_64 as Vt, FIXED_EXTERNAL_VALUE_54 as W, IMPORTANCE_WEIGHT_BASE as Wn, FIXED_PROTOCOL_VALUE_67 as Wt, FIXED_EXTERNAL_VALUE_8 as X, MAINTENANCE_TICK_MS as Xn, FIXED_PROTOCOL_VALUE_76 as Xt, FIXED_EXTERNAL_VALUE_62 as Y, LIGHTWEIGHT_RERANK_PENALTY as Yn, FIXED_PROTOCOL_VALUE_75 as Yt, FIXED_EXTERNAL_VALUE_9 as Z, MAX_AGGREGATION_RESULT_TOKENS as Zn, FIXED_PROTOCOL_VALUE_77 as Zt, readRemTestHoldMs as _, BACKUP_MIN_FREE_DISK_RATIO as _n, USAGE_OUTBOX_INTERVAL_MS as _r, FIXED_MEMORY_CHUNKS as _t, REM_MODEL_OUTPUT_TOKEN_CAP as a, PERSISTED_PROVIDER_SYSTEM as an, MULTI_HIT_BONUS_CAP as ar, FIXED_IDX_MEMORY_MEMORIES_LANE_PROJECT as at, getPrincipal as b, CHUNKING_VERSION as bn, experimentMmrDisabled as br, FIXED_MEMORY_CHUNKS_AU as bt, REM_SIDECAR_ORIGIN as c, SUPPORTED_LOCALES as cn, RECENCY_WEIGHT as cr, FIXED_IDX_MEMORY_MEMORIES_PROJECT_FACT_KEY_ACTIVE as ct, getRemDiscoveryPath as d, ADJACENCY_BONUS_PER_PAIR as dn, RERANK_BLEND_CROSS as dr, FIXED_MEMORY_ACTIVE_TASK_EVIDENCE as dt, FIXED_VEC_MEMORY as en, MAX_LIST_LIMIT as er, FIXED_IDX_MEMORY_ACTIVE_TASK_EVIDENCE_INSTANCE as et, getRemJobJournalPath as f, ATOMIC_CAPTURE_OUTPUT_TOKEN_BUDGET as fn, RERANK_BLEND_VECTOR as fr, FIXED_MEMORY_ACTIVE_TASK_INSTANCES as ft, readRemOperationalConfig as g, BACKUP_INTERVAL_MS as gn, USAGE_EVENT_RETENTION_INTERVAL_MS as gr, FIXED_MEMORY_ACTIVE_TASK_TRANSITIONS as gt, readMaintenanceOverrides as h, ATOMIC_EXTRACTION_MAX_INPUT_TOKENS as hn, TIME_DECAY_FLOOR as hr, FIXED_MEMORY_ACTIVE_TASK_REVISIONS as ht, REM_JOBS_PATH_PREFIX as i, PERSISTED_CONTENT_HASH_V3 as in, MMR_LAMBDA as ir, FIXED_IDX_MEMORY_MEMORIES_FACT_ID as it, SESSION_STRATEGIES as j, DEFAULT_REFLECTION_SESSION_TTL_MS as jn, MEMORY_DEFAULT_SKIN_ID as jr, FIXED_MEMORY_PROVIDER_AGENT_MAPPINGS as jt, MODEL_CALL_WORKLOAD as k, DEFAULT_RECALL_TOKEN_BUDGET as kn, MEMORY_BODY_LIMIT_BYTES as kr, FIXED_MEMORY_MIGRATION_MARKERS as kt, REM_SOURCE as l, isSupportedLocale as ln, REFLECTION_SLICE_CACHE_TTL_MS as lr, FIXED_IDX_MEMORY_MEMORIES_PROJECT_TIMESTAMP as lt, isRemTraceEnabled as m, ATOMIC_ENRICHMENT_OUTPUT_TOKEN_BUDGET as mn, SNO_OBSERVE_FLUSH_TIMEOUT_MS as mr, FIXED_MEMORY_ACTIVE_TASK_MIGRATION_MANIFESTS as mt, MEMORY_USAGE_FLUSH_INTERVAL_MS as n, PERSISTED_CANDIDATE_HASH_V1 as nn, MEMORY_SHUTDOWN_TIMEOUT_MS as nr, FIXED_IDX_MEMORY_MEMORIES_CATEGORY as nt, REM_RUN_PATH as o, embeddingConfigSchema as on, MULTI_HIT_BONUS_PER_HIT as or, FIXED_IDX_MEMORY_MEMORIES_PROJECT as ot, getRemTraceLogPath as p, ATOMIC_CAPTURE_TIMEOUT_MS as pn, RETRIEVAL_STORAGE_CHUNK_PROFILE as pr, FIXED_MEMORY_ACTIVE_TASK_MIGRATION_EVIDENCE as pt, FIXED_EXTERNAL_VALUE_57 as q, LIGHTWEIGHT_COSINE_WEIGHT as qn, FIXED_PROTOCOL_VALUE_73 as qt, REM_CORRELATION_ID_HEADER as r, PERSISTED_CONTENT_HASH_V1 as rn, MIN_RECALL_TOKEN_BUDGET as rr, FIXED_IDX_MEMORY_MEMORIES_CONTENT_HASH as rt, REM_SIDECAR_HOST as s, llmRoutingConfigSchema as sn, PLANNER_STATISTICS_INTERVAL_MS as sr, FIXED_IDX_MEMORY_MEMORIES_PROJECT_CONTENT_HASH as st, HEALTH_PATH as t, FIXED_VEC_MEMORY_CHUNKS as tn, MAX_RECALLED_TODO_TOKENS as tr, FIXED_IDX_MEMORY_ACTIVE_TASK_INSTANCES_PROJECTION as tt, getRemChassisJournalPath as u, ADJACENCY_BONUS_CAP as un, REM_TRIGGER_CHECK_INTERVAL_MS as ur, FIXED_MEMORY as ut, SettingsUnavailableError as v, BONUS_TOTAL_INVARIANT as vn, VECTOR_DIMENSION_DEFAULT as vr, FIXED_MEMORY_CHUNKS_AD as vt, getStateDir as w, CHUNK_TARGET_TOKENS as wn, LOCAL_EMBEDDING_MODEL as wr, FIXED_MEMORY_CHUNKS_MEM_IDX as wt, getSettingsPath as x, CHUNK_MAX_TOKENS as xn, recallLifecycleSchema as xr, FIXED_MEMORY_CHUNKS_FTS as xt, getDiscoveryPath as y, CACHE_TTL_MS as yn, experimentCandidatePoolOverride as yr, FIXED_MEMORY_CHUNKS_AI as yt, sessionMemoryConfigSchema as z, FORGET_QUERY_MIN_SCORE as zn, FIXED_MEMORY_UNPLACED_CANDIDATES as zt };