@snoai/memory 1.2.14 → 1.5.1

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 (157) hide show
  1. package/README.md +1 -1
  2. package/dist/{access-tracker-DT04huAG.d.ts → access-tracker-D-riPZRY.d.ts} +4 -4
  3. package/dist/{adapter-BMx-VcJy.d.ts → adapter-BM58hult.d.ts} +2 -2
  4. package/dist/{atomic-memory-extraction-_OEsSJbC.d.ts → atomic-memory-extraction-BNBCB1XD.d.ts} +4 -4
  5. package/dist/{atomic-memory-extraction-De86y7O-.js → atomic-memory-extraction-BaBrfESt.js} +5 -5
  6. package/dist/{b-profile-section-dictionary-provider-DTE4uWyh.d.ts → b-profile-section-dictionary-provider-D2kzg9Re.d.ts} +1 -1
  7. package/dist/{capture-policy-detector-B8sqRTlB.d.ts → capture-policy-detector-CoT-j_Ic.d.ts} +1 -1
  8. package/dist/client.d.ts +1 -1
  9. package/dist/{config-C1X5rsAx.js → config-BhlMin82.js} +743 -412
  10. package/dist/{connection-PQcq3TPO.js → connection-BtK-3r-f.js} +1 -20
  11. package/dist/{connection-3IVXpuPE.d.ts → connection-D989FqGS.d.ts} +1 -17
  12. package/dist/{derived-suppression-cache-Cha_e2Cr.d.ts → derived-suppression-cache-BW52dq3w.d.ts} +1 -1
  13. package/dist/diagnostic-encoder.js +1 -1
  14. package/dist/{embedding-provider-client-vynZMuit.d.ts → embedding-provider-client-CELWtPgt.d.ts} +6 -0
  15. package/dist/{embedding-provider-client-40tpzKou.js → embedding-provider-client-CgpUK_1G.js} +16 -1
  16. package/dist/{index-8CfO_-6T.d.ts → index-BGu91bjB.d.ts} +19 -4
  17. package/dist/{index-C8tTzfrH.d.ts → index-GoYmsx8b.d.ts} +2 -2
  18. package/dist/index.d.ts +10 -10
  19. package/dist/index.js +4 -4
  20. package/dist/internal/config/index.d.ts +2 -2
  21. package/dist/internal/config/index.js +19 -4
  22. package/dist/internal/config/plugin-config-schema.d.ts +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 +1 -1
  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 +3 -3
  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 +6 -6
  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 +2 -2
  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 +1 -1
  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/telemetry/observe-ledger.d.ts +1 -1
  95. package/dist/internal/model/llm-client.d.ts +2 -2
  96. package/dist/internal/model/llm-client.js +1 -1
  97. package/dist/internal/model/llm-mode-routing.d.ts +1 -1
  98. package/dist/internal/model/llm-mode-routing.js +1 -1
  99. package/dist/internal/store/atomic-memory-cutover-sql.js +1 -1
  100. package/dist/internal/store/connection.d.ts +2 -2
  101. package/dist/internal/store/connection.js +2 -2
  102. package/dist/internal/store/maintenance.d.ts +2 -2
  103. package/dist/internal/store/maintenance.js +6 -6
  104. package/dist/internal/store/memory-kinds-cutover-migrator.d.ts +0 -2
  105. package/dist/internal/store/memory-kinds-cutover-migrator.js +1 -10
  106. package/dist/internal/store/store.d.ts +2 -2
  107. package/dist/internal/store/store.js +1 -1
  108. package/dist/{llm-client-BoClMktv.d.ts → llm-client-9XCsnmf0.d.ts} +1 -1
  109. package/dist/{llm-client-DDdUjYWS.js → llm-client-Z_VkmTsW.js} +1 -1
  110. package/dist/{log-site-catalog.generated-DGia_6ZR.js → log-site-catalog.generated-lc-iJczN.js} +70 -56
  111. package/dist/log-site-catalog.json +1 -1
  112. package/dist/{memory-entry-projector-DHo8jH10.js → memory-entry-projector-B36Nwsi_.js} +2 -1
  113. package/dist/{memory-kind-policy-C7p4o8ru.d.ts → memory-kind-policy-DcEvUTKl.d.ts} +1 -1
  114. package/dist/{memory-metadata-codec-CFY8YtXf.d.ts → memory-metadata-codec-CLtCCf-b.d.ts} +1 -1
  115. package/dist/{memory-runtime-CCPRiAk9.js → memory-runtime-De1T9jTv.js} +76 -60
  116. package/dist/{memory-snapshot-DADY3InD.d.ts → memory-snapshot-BXB2APN0.d.ts} +2 -2
  117. package/dist/{memory-store-base-D0bLwzyF.d.ts → memory-store-base-yOAD7Ff8.d.ts} +5 -5
  118. package/dist/{memory-store-shared-CURizQIy.js → memory-store-shared-pOb59ScU.js} +1 -1
  119. package/dist/{memory-temporality-classifier-DL14kjtv.d.ts → memory-temporality-classifier-BxmM3FOb.d.ts} +1 -1
  120. package/dist/{memory-temporality-classifier-BwBKEQbL.js → memory-temporality-classifier-s7TjoKB-.js} +2 -2
  121. package/dist/{memory-tier-promoter-Cf1OdoZK.d.ts → memory-tier-promoter-DjJwYB4w.d.ts} +1 -1
  122. package/dist/memory-tool-dependencies-BsaSVzC8.d.ts +14 -0
  123. package/dist/{memory-tool-dependencies-aAr7Pkuj.js → memory-tool-dependencies-C8JSCWCz.js} +1 -1
  124. package/dist/{model-call-table-DoIl2S0P.js → model-call-table-CPyQfBJ6.js} +7 -7
  125. package/dist/{observable-embedder-CPyX9y7c.d.ts → observable-embedder-DCtHXucw.d.ts} +2 -2
  126. package/dist/{observable-llm-client-C8ndPJck.d.ts → observable-llm-client-DykY0exK.d.ts} +3 -3
  127. package/dist/{observable-memory-store-DhOfgjkU.d.ts → observable-memory-store-ZBTjMAHj.d.ts} +5 -5
  128. package/dist/{observable-retriever-CUlmCFy5.d.ts → observable-retriever-f8ENkQnP.d.ts} +6 -6
  129. package/dist/paths-m8yncZgm.d.ts +1 -0
  130. package/dist/{plugin-config-schema-BPg-ppSt.d.ts → plugin-config-schema-CsKKIHq9.d.ts} +2 -2
  131. package/dist/{profile-BksZRjJ8.d.ts → profile-CxdMGvxU.d.ts} +1 -1
  132. package/dist/{profile-section-writer-Dd4FKpt5.js → profile-section-writer-B54r7JN1.js} +2 -2
  133. package/dist/{reflection-command-hooks-mCOmD8b6.d.ts → reflection-command-hooks-_B_XZBIz.d.ts} +4 -4
  134. package/dist/{reflection-command-hooks-B2P4zDr6.js → reflection-command-hooks-a1kgC2cr.js} +5 -4
  135. package/dist/{reflection-deps-BYkAaKxD.d.ts → reflection-deps-DQBHeGYK.d.ts} +3 -3
  136. package/dist/{reflection-embedded-generator-DV-NkeU-.js → reflection-embedded-generator-DEuTWrBh.js} +1 -1
  137. package/dist/{reflection-embedded-generator-ve1PhgUY.d.ts → reflection-embedded-generator-LmZQqGER.d.ts} +3 -3
  138. package/dist/{reflection-injection-hooks-CphBCA9F.d.ts → reflection-injection-hooks-CTDCwu2_.d.ts} +4 -4
  139. package/dist/{reflection-lifecycle-hooks-CFGYh_8m.d.ts → reflection-lifecycle-hooks-eFUc2mcd.d.ts} +3 -3
  140. package/dist/{rem-batch-executor-TSYG7oVi.js → rem-batch-executor-D42YWCNg.js} +1 -1
  141. package/dist/{rem-trigger-i_E8I9lv.js → rem-trigger-BKr4Qmhn.js} +97 -7
  142. package/dist/{retriever-6ybsoVuY.d.ts → retriever-BsjtyINJ.d.ts} +12 -9
  143. package/dist/{retriever-Dnjl_FHu.js → retriever-CsBW6MZv.js} +71 -5
  144. package/dist/{runtime-audit-log-DWpWmCx5.d.ts → runtime-audit-log-C-L0v2HU.d.ts} +1 -1
  145. package/dist/{server-DsaVeSaM.js → server-BPOT66a_.js} +9 -9
  146. package/dist/sidecar/main.js +2 -2
  147. package/dist/sno-station-mem-runtime-dependencies-B47DIcei.d.ts +31 -0
  148. package/dist/{sno-station-mem-runtime-dependencies-zzcjHD_N.js → sno-station-mem-runtime-dependencies-DES7ZvMt.js} +7 -7
  149. package/dist/{store-HyzTUvwj.d.ts → store-CukgAPqu.d.ts} +2 -2
  150. package/dist/{store-COwW7mIh.js → store-DRwqWMTh.js} +3 -3
  151. package/dist/{strategy-hook-runner-B_m1L5CB.d.ts → strategy-hook-runner-BlJxjMjC.d.ts} +7 -7
  152. package/dist/{strategy-hook-runner-CALbWcys.js → strategy-hook-runner-s8dAEQ3P.js} +2 -2
  153. package/dist/{types-Dm_XhSne.d.ts → types-C9Hngi-p.d.ts} +1 -1
  154. package/package.json +2 -2
  155. package/dist/memory-tool-dependencies-Bxdpvs3Z.d.ts +0 -14
  156. package/dist/paths-DnNN0G1t.d.ts +0 -1
  157. package/dist/sno-station-mem-runtime-dependencies-DtKDYdsh.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) {
@@ -145,7 +688,7 @@ var ModelNotLoadedError = class extends Error {
145
688
  this.name = "ModelNotLoadedError";
146
689
  }
147
690
  };
148
- var LocalEmbedProvider = class LocalEmbedProvider {
691
+ var LocalEmbedProvider = class {
149
692
  _disposed = false;
150
693
  cacheDir;
151
694
  dtype;
@@ -158,16 +701,10 @@ var LocalEmbedProvider = class LocalEmbedProvider {
158
701
  pipelineKey;
159
702
  offline;
160
703
  mirror;
161
- /**
162
- * Guard: transformers `env` is process-global — only one cacheDir is allowed per process.
163
- * Intentionally never reset during normal operation; use `resetStaticState()` only in tests.
164
- */
165
- static configuredCacheDir;
166
704
  /** Reset static state — FOR TESTS ONLY. Not safe in production. */
167
705
  static resetStaticState() {
168
- LocalEmbedProvider.configuredCacheDir = void 0;
169
706
  sharedExtractor = void 0;
170
- sharedLoading = void 0;
707
+ sharedLoading$1 = void 0;
171
708
  sharedRefCount = 0;
172
709
  sharedPipelineKey = void 0;
173
710
  }
@@ -179,7 +716,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
179
716
  this.cacheDir = resolve(config?.cacheDir ?? LOCAL_EMBEDDING_CACHE_DIR_DEFAULT);
180
717
  this.dtype = config?.dtype ?? "q8";
181
718
  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);
719
+ this.revision = config?.revision ?? (this.modelId === "tss-deposium/pplx-embed-v1-0.6b-onnx-int8-standard" ? "a18fdffe7480e6ea5643acb7757142b33838817a" : void 0);
183
720
  this.nativeDim = config?.nativeDim ?? 1024;
184
721
  this.outputDim = config?.outputDim ?? this.nativeDim;
185
722
  if (this.outputDim > this.nativeDim) throw new Error(`outputDim (${this.outputDim}) cannot exceed nativeDim (${this.nativeDim}) — Matryoshka truncation only shrinks dimensions.`);
@@ -200,21 +737,21 @@ var LocalEmbedProvider = class LocalEmbedProvider {
200
737
  if (this._disposed) throw new Error("LocalEmbedProvider has been disposed");
201
738
  this.assertCompatibleSharedPipeline();
202
739
  if (sharedExtractor) return sharedExtractor;
203
- if (sharedLoading) {
204
- const extractor = await sharedLoading;
740
+ if (sharedLoading$1) {
741
+ const extractor = await sharedLoading$1;
205
742
  if (this._disposed) throw new Error("LocalEmbedProvider has been disposed");
206
743
  if (!sharedExtractor) sharedExtractor = extractor;
207
744
  return extractor;
208
745
  }
209
746
  sharedPipelineKey = this.pipelineKey;
210
- sharedLoading = this.initPipeline();
747
+ sharedLoading$1 = this.initPipeline();
211
748
  try {
212
- const extractor = await sharedLoading;
749
+ const extractor = await sharedLoading$1;
213
750
  sharedExtractor = extractor;
214
751
  if (this._disposed) throw new Error("LocalEmbedProvider has been disposed");
215
752
  return extractor;
216
753
  } finally {
217
- sharedLoading = void 0;
754
+ sharedLoading$1 = void 0;
218
755
  if (!sharedExtractor && sharedRefCount === 0) sharedPipelineKey = void 0;
219
756
  }
220
757
  }
@@ -223,15 +760,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
223
760
  throw new Error("LocalEmbedProvider shared ONNX pipeline is already loaded with a different model, revision, dtype, cacheDir, or sessionOptions. Dispose all live providers before changing pipeline configuration.");
224
761
  }
225
762
  async initPipeline() {
226
- 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
- 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}/`;
763
+ const { pipeline } = await import("@huggingface/transformers");
235
764
  log$1$1.info("loading ONNX model", {
236
765
  model: this.modelId,
237
766
  cacheDir: this.cacheDir,
@@ -248,10 +777,20 @@ var LocalEmbedProvider = class LocalEmbedProvider {
248
777
  const t0 = performance.now();
249
778
  try {
250
779
  const sessionOptions = buildSessionOptions(this.sessionOptions);
251
- const extractor = await pipeline("feature-extraction", this.modelId, {
780
+ const download = {
781
+ cacheDir: this.cacheDir,
782
+ offline: this.offline,
783
+ mirror: this.mirror
784
+ };
785
+ 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);
786
+ const extractor = await pipeline("feature-extraction", await downloadModel(spec, download), {
252
787
  dtype: this.dtype,
253
788
  device: "cpu",
254
- session_options: sessionOptions
789
+ session_options: sessionOptions,
790
+ local_files_only: true
791
+ }).catch((error) => {
792
+ forgetDownload(this.cacheDir, spec);
793
+ throw error;
255
794
  });
256
795
  const durationMs = Math.round(performance.now() - t0);
257
796
  log$1$1.info("ONNX model loaded", {
@@ -335,7 +874,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
335
874
  this._disposed = true;
336
875
  sharedRefCount = Math.max(0, sharedRefCount - 1);
337
876
  if (sharedRefCount > 0) return;
338
- const pending = sharedLoading;
877
+ const pending = sharedLoading$1;
339
878
  if (pending) {
340
879
  const extractor = await pending.catch(() => void 0);
341
880
  if (sharedRefCount > 0) {
@@ -349,7 +888,7 @@ var LocalEmbedProvider = class LocalEmbedProvider {
349
888
  await sharedExtractor.dispose();
350
889
  sharedExtractor = void 0;
351
890
  }
352
- if (sharedLoading === void 0) sharedPipelineKey = void 0;
891
+ if (sharedLoading$1 === void 0) sharedPipelineKey = void 0;
353
892
  }
354
893
  async warmup() {
355
894
  await this.embed("warmup");
@@ -502,397 +1041,180 @@ var CachedEmbeddingProvider = class {
502
1041
  }
503
1042
  };
504
1043
  /**
505
- * model-download.ts — Shared ONNX model download utility.
1044
+ * Local cross-encoder that scores how well each text answers a query, on the CPU.
506
1045
  *
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.
1046
+ * The model reads Chinese and English (and other languages). It downloads through the shared downloader and loads in
1047
+ * the background on first use: until it is ready, or if it cannot load (offline with nothing cached, say), `score`
1048
+ * answers undefined and the caller keeps its own order.
511
1049
  */
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
- }
1050
+ const log$4 = createLogger("embedder:local-reranker");
552
1051
  /**
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.
1052
+ * Horizon-Labs/multilingual-reranker-small (Apache-2.0) in an 8-bit ONNX file Sno published; pinned revision and
1053
+ * file hashes, the same supply-chain rule as the embedding model.
560
1054
  */
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
- }
1055
+ const LOCAL_RERANK_MODEL = {
1056
+ id: "sno-lab/multilingual-reranker-small-int8",
1057
+ revision: "ce76796ae42628f54f501271aeac16df8ecc8a6f",
1058
+ files: [
1059
+ {
1060
+ path: "config.json",
1061
+ size: 1995,
1062
+ sha256: "e9fd043628cd796a364020164a7a6ca78d29b0ec5cf135464489f54110f4b1da"
1063
+ },
1064
+ {
1065
+ path: "special_tokens_map.json",
1066
+ size: 636,
1067
+ sha256: "baec30ea10906f16adb8c18af7a34023002c1746542612b8b41c9f09e1351351"
1068
+ },
1069
+ {
1070
+ path: "tokenizer.json",
1071
+ size: 34363439,
1072
+ sha256: "7925f638b5444897efe3b4608eed56c1652f0ed39c2662c8302de1bc264c6088"
1073
+ },
1074
+ {
1075
+ path: "tokenizer_config.json",
1076
+ size: 46440,
1077
+ sha256: "ea349495764b24570b4560fe2e4a557e5c0a47e6bce782c2409b1d6445cf8633"
1078
+ },
1079
+ {
1080
+ path: "onnx/model_quantized.onnx",
1081
+ size: 171363319,
1082
+ sha256: "d2b03e74b3ea60ca486a118b4e2ab6bc96b173c64224a689d653e135753d89ad"
603
1083
  }
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;
1084
+ ]
1085
+ };
1086
+ const SCORE_BATCH = 5;
1087
+ const LOAD_RETRY_MS = 6e5;
1088
+ let shared;
1089
+ let sharedLoading = false;
1090
+ let sharedUsers = 0;
1091
+ let sharedFailedAt;
1092
+ let releases = 0;
1093
+ const scoring = /* @__PURE__ */ new Set();
1094
+ var LocalReranker = class {
1095
+ options;
1096
+ disposed = false;
1097
+ constructor(options) {
1098
+ this.options = options;
1099
+ sharedUsers += 1;
616
1100
  }
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 {}
1101
+ /**
1102
+ * Raw relevance logits, one per text (higher is more relevant), or undefined while the model is not loaded.
1103
+ * The first call starts the load and does not wait for it.
1104
+ */
1105
+ async score(query, texts, signal) {
1106
+ if (texts.length === 0) return [];
1107
+ const loaded = shared;
1108
+ if (!loaded) {
1109
+ if (sharedFailedAt !== void 0 && Date.now() - sharedFailedAt >= LOAD_RETRY_MS) {
1110
+ sharedFailedAt = void 0;
1111
+ sharedLoading = false;
1112
+ }
1113
+ if (!sharedLoading) {
1114
+ sharedLoading = true;
1115
+ this.load();
1116
+ }
1117
+ return;
629
1118
  }
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;
1119
+ const run = this.run(loaded, query, texts, signal);
1120
+ scoring.add(run);
682
1121
  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;
1122
+ return await run;
1123
+ } finally {
1124
+ scoring.delete(run);
726
1125
  }
727
- await sleep(LOCK_POLL_INTERVAL_MS);
728
1126
  }
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;
1127
+ async dispose() {
1128
+ if (this.disposed) return;
1129
+ this.disposed = true;
1130
+ sharedUsers = Math.max(0, sharedUsers - 1);
1131
+ if (sharedUsers > 0) return;
1132
+ const loaded = shared;
1133
+ releases += 1;
1134
+ shared = void 0;
1135
+ sharedLoading = false;
1136
+ sharedFailedAt = void 0;
1137
+ await Promise.allSettled(scoring);
1138
+ await loaded?.dispose();
755
1139
  }
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"
1140
+ async run(loaded, query, texts, signal) {
1141
+ const order = texts.map((_, index) => index).sort((a, b) => (texts[a]?.length ?? 0) - (texts[b]?.length ?? 0));
1142
+ const scores = new Array(texts.length).fill(0);
1143
+ for (let start = 0; start < order.length; start += SCORE_BATCH) {
1144
+ if (signal?.aborted) return void 0;
1145
+ const run = order.slice(start, start + SCORE_BATCH);
1146
+ const inputs = loaded.tokenizer(new Array(run.length).fill(query), {
1147
+ text_pair: run.map((index) => texts[index] ?? ""),
1148
+ padding: true,
1149
+ truncation: true,
1150
+ max_length: 512
770
1151
  });
771
- return;
1152
+ const { logits } = await loaded.model(inputs);
1153
+ for (const [i, index] of run.entries()) scores[index] = Number(logits.data[i] ?? 0);
772
1154
  }
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)}`);
1155
+ return scores;
774
1156
  }
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();
1157
+ async load() {
1158
+ const release = releases;
1159
+ const started = performance.now();
836
1160
  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`);
1161
+ const { AutoModelForSequenceClassification, AutoTokenizer } = await import("@huggingface/transformers");
1162
+ const dir = await downloadModel(LOCAL_RERANK_MODEL, this.options);
1163
+ const open = async () => {
1164
+ return {
1165
+ tokenizer: await AutoTokenizer.from_pretrained(dir, { local_files_only: true }),
1166
+ model: await AutoModelForSequenceClassification.from_pretrained(dir, {
1167
+ dtype: "q8",
1168
+ device: "cpu",
1169
+ local_files_only: true,
1170
+ session_options: {
1171
+ ...LOCAL_EMBEDDING_SESSION_OPTIONS_DEFAULT,
1172
+ interOpNumThreads: 1,
1173
+ ...this.options.intraOpNumThreads ? { intraOpNumThreads: this.options.intraOpNumThreads } : {}
846
1174
  }
847
- } else if (progress.status === "done" && progress.file) process.stderr.write(` done ${progress.file}\n`);
1175
+ })
1176
+ };
1177
+ };
1178
+ const { tokenizer, model } = await open().catch((error) => {
1179
+ forgetDownload(this.options.cacheDir, LOCAL_RERANK_MODEL);
1180
+ throw error;
1181
+ });
1182
+ if (release !== releases) {
1183
+ await model.dispose();
1184
+ return;
1185
+ }
1186
+ shared = {
1187
+ tokenizer: (texts, options) => tokenizer(texts, options),
1188
+ model: (inputs) => model(inputs),
1189
+ dispose: async () => {
1190
+ await model.dispose();
848
1191
  }
1192
+ };
1193
+ log$4.info("local reranker loaded", {
1194
+ duration_ms: Math.round(performance.now() - started),
1195
+ model: LOCAL_RERANK_MODEL.id
1196
+ }, {
1197
+ event_name: "embedder.local_reranker.loaded",
1198
+ file: "packages/embedder/src/local-reranker.ts",
1199
+ function: "load",
1200
+ site_id: "embedder.local_reranker.loaded"
849
1201
  });
850
- } finally {
851
- env.cacheDir = prevCacheDir;
852
- env.allowRemoteModels = prevAllowRemote;
853
- env.localModelPath = prevLocalModelPath;
854
- env.remoteHost = prevRemoteHost;
855
- env.remotePathTemplate = prevRemotePathTemplate;
1202
+ return shared;
1203
+ } catch (error) {
1204
+ log$4.warn("local reranker unavailable; recall keeps its cosine order", {
1205
+ error,
1206
+ offline: this.options.offline === true
1207
+ }, {
1208
+ event_name: "embedder.local_reranker.unavailable",
1209
+ file: "packages/embedder/src/local-reranker.ts",
1210
+ function: "load",
1211
+ site_id: "embedder.local_reranker.unavailable"
1212
+ });
1213
+ sharedFailedAt = Date.now();
1214
+ return;
856
1215
  }
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
1216
  }
895
- }
1217
+ };
896
1218
  //#endregion
897
1219
  //#region config/index.ts
898
1220
  /**
@@ -1015,10 +1337,19 @@ const MMR_LAMBDA = .7;
1015
1337
  const RERANK_BLEND_VECTOR = .3;
1016
1338
  /** Weight for cross-encoder score in rerank blend */
1017
1339
  const RERANK_BLEND_CROSS = .7;
1018
- /** Fusion-score weight in local cosine-blend rerank */
1019
- const LIGHTWEIGHT_FUSION_WEIGHT = .7;
1340
+ /**
1341
+ * Fusion-score weight in local cosine-blend rerank.
1342
+ *
1343
+ * The fused score keeps a keyword-only hit at its full keyword score, so a memory sharing one word with the query
1344
+ * outranks the one that answers it; at 0.7 the local ranking passed that order through almost unchanged. Measured
1345
+ * 2026-10-15 on LoCoMo (1,540 questions, the product store and retriever, weights fitted on half the conversations
1346
+ * and checked on the other half): the right memory in the first five went from 27% to 68% in English and from 9% to
1347
+ * 58% in a Chinese translation at 0.1 / 0.9. A candidate with no stored vector keeps its fused score and would now
1348
+ * rank high; none of 27,064 candidates in 299 real local rankings lacked one.
1349
+ */
1350
+ const LIGHTWEIGHT_FUSION_WEIGHT = .1;
1020
1351
  /** Cosine-similarity weight in local cosine-blend rerank */
1021
- const LIGHTWEIGHT_COSINE_WEIGHT = .3;
1352
+ const LIGHTWEIGHT_COSINE_WEIGHT = .9;
1022
1353
  /** Default timeout for rerank API calls in milliseconds */
1023
1354
  const DEFAULT_RERANK_TIMEOUT_MS = 15e3;
1024
1355
  /**
@@ -2036,13 +2367,13 @@ const MODEL_CALLS = {
2036
2367
  }
2037
2368
  },
2038
2369
  R2: {
2039
- description: "label local sessions before the nightly cloud upload",
2040
- calledBy: "RSI skill",
2370
+ description: "label local sessions before the Self Learning cloud upload",
2371
+ calledBy: "Self Learning",
2041
2372
  destinations: host
2042
2373
  },
2043
2374
  R3: {
2044
- description: "upload sessions nightly for cloud experience and skill review",
2045
- calledBy: "RSI skill",
2375
+ description: "upload sessions nightly for Self Learning",
2376
+ calledBy: "Self Learning",
2046
2377
  destinations: {
2047
2378
  "local-first": "off",
2048
2379
  "agent-native": "sno-gpu",
@@ -2051,7 +2382,7 @@ const MODEL_CALLS = {
2051
2382
  },
2052
2383
  R4: {
2053
2384
  description: "recall one relevant cloud experience on a session's first prompt",
2054
- calledBy: "RSI skill",
2385
+ calledBy: "Self Learning",
2055
2386
  destinations: {
2056
2387
  "local-first": "off",
2057
2388
  "agent-native": "sno-gpu",
@@ -2059,8 +2390,8 @@ const MODEL_CALLS = {
2059
2390
  }
2060
2391
  },
2061
2392
  R5: {
2062
- description: "generate local lessons and skill reminders nightly",
2063
- calledBy: "RSI skill",
2393
+ description: "generate local lessons and skill reminders nightly for Self Learning",
2394
+ calledBy: "Self Learning",
2064
2395
  destinations: {
2065
2396
  "local-first": "host",
2066
2397
  "agent-native": "off",
@@ -2666,4 +2997,4 @@ function readMaintenanceOverrides() {
2666
2997
  };
2667
2998
  }
2668
2999
  //#endregion
2669
- 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_DEFAULT_SKIN_ID 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, ensureModelDownloaded 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, REM_SIDECAR_TOKEN_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, memoryMethod 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, FIXED_MEMORY_SNO_EXTRACT_PROFILE as Lt, retrievalConfigSchema as M, DEFAULT_RERANK_TIMEOUT_MS as Mn, MEMORY_RECONNECT_INTERVAL_MS as Mr, FIXED_MEMORY_PROVIDER_PROJECT_AGENTS as Mt, isObserveAgentId as N, DEFAULT_SCOPE as Nn, MEMORY_ROUTES as Nr, FIXED_MEMORY_PROVIDER_PROJECT_MAPPINGS as Nt, MODEL_CALLS as O, DEFAULT_RECALL_LIFECYCLE as On, MEMORY_BODY_LIMIT_BYTES as Or, FIXED_MEMORY_MEMORIES_FACT_ID_UPDATE_GUARD as Ot, observeAgentId as P, DEFAULT_VECTOR_WEIGHT as Pn, MEMORY_SKIN_HEADER 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_ERROR_STATUS as jr, FIXED_MEMORY_PROVIDER_AGENT_MAPPINGS as jt, MODEL_CALL_WORKLOAD as k, DEFAULT_RECALL_TOKEN_BUDGET as kn, MEMORY_CANCEL_ON_DISCONNECT_HEADER 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 };
3000
+ 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 };