@cortexkit/opencode-magic-context 0.49.0 → 0.49.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/dist/{announcement-fp14dw0n.js → announcement-hdbkt8v5.js} +1 -1
  2. package/dist/auto-search-worker.js +3 -3
  3. package/dist/config/{mural-model-deprecation.d.ts → deprecated-config.d.ts} +4 -1
  4. package/dist/config/deprecated-config.d.ts.map +1 -0
  5. package/dist/config/index.d.ts.map +1 -1
  6. package/dist/config/project-security.d.ts +2 -2
  7. package/dist/config/schema/magic-context.d.ts +4 -4
  8. package/dist/config/schema/magic-context.d.ts.map +1 -1
  9. package/dist/{conflict-warning-hook-kzx4dmk1.js → conflict-warning-hook-asnt6hfc.js} +3 -3
  10. package/dist/{context-nj5f293n.js → context-tfyhtdcs.js} +111 -45
  11. package/dist/{derive-budgets-qz5rrr08.js → derive-budgets-j4ry8j8n.js} +1 -1
  12. package/dist/{embedding-backfill-aetxv1vt.js → embedding-backfill-wyc3ykyf.js} +7 -7
  13. package/dist/embedding-worker-process.js +30 -0
  14. package/dist/embedding-worker.js +5 -5
  15. package/dist/features/magic-context/dreamer/task-registry.d.ts +2 -3
  16. package/dist/features/magic-context/dreamer/task-registry.d.ts.map +1 -1
  17. package/dist/features/magic-context/memory/embedding-worker-client.d.ts +8 -1
  18. package/dist/features/magic-context/memory/embedding-worker-client.d.ts.map +1 -1
  19. package/dist/features/magic-context/memory/embedding-worker-process.d.ts +2 -0
  20. package/dist/features/magic-context/memory/embedding-worker-process.d.ts.map +1 -0
  21. package/dist/features/magic-context/memory/onnx-telemetry.d.ts +3 -0
  22. package/dist/features/magic-context/memory/onnx-telemetry.d.ts.map +1 -0
  23. package/dist/features/magic-context/overflow-detection.d.ts +1 -2
  24. package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
  25. package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
  26. package/dist/features/magic-context/transform-decision-log.d.ts +1 -1
  27. package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
  28. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts +1 -0
  29. package/dist/features/magic-context/user-memory/storage-user-memory.d.ts.map +1 -1
  30. package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
  31. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts +1 -0
  32. package/dist/hooks/magic-context/final-wire-token-estimate.d.ts.map +1 -1
  33. package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
  34. package/dist/hooks/magic-context/hook.d.ts +1 -0
  35. package/dist/hooks/magic-context/hook.d.ts.map +1 -1
  36. package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
  37. package/dist/hooks/magic-context/lkg-measured-request.d.ts +3 -1
  38. package/dist/hooks/magic-context/lkg-measured-request.d.ts.map +1 -1
  39. package/dist/hooks/magic-context/lkg-persist.d.ts +8 -14
  40. package/dist/hooks/magic-context/lkg-persist.d.ts.map +1 -1
  41. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts +62 -0
  42. package/dist/hooks/magic-context/lkg-recovery-fence.d.ts.map +1 -0
  43. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts +38 -0
  44. package/dist/hooks/magic-context/lkg-recovery-prefix.d.ts.map +1 -0
  45. package/dist/hooks/magic-context/lkg-replay.d.ts +3 -1
  46. package/dist/hooks/magic-context/lkg-replay.d.ts.map +1 -1
  47. package/dist/hooks/magic-context/lkg-slot.d.ts.map +1 -1
  48. package/dist/hooks/magic-context/opaque-thinking.d.ts +12 -0
  49. package/dist/hooks/magic-context/opaque-thinking.d.ts.map +1 -0
  50. package/dist/hooks/magic-context/pass-outcome.d.ts +2 -2
  51. package/dist/hooks/magic-context/pending-materialization.d.ts +8 -0
  52. package/dist/hooks/magic-context/pending-materialization.d.ts.map +1 -0
  53. package/dist/hooks/magic-context/read-session-db.d.ts +3 -0
  54. package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
  55. package/dist/hooks/magic-context/recomp-orchestrator.d.ts.map +1 -1
  56. package/dist/hooks/magic-context/rust-mode-transform.d.ts +1 -0
  57. package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
  58. package/dist/hooks/magic-context/strip-content.d.ts +5 -2
  59. package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
  60. package/dist/hooks/magic-context/system-date-refresh.d.ts +29 -0
  61. package/dist/hooks/magic-context/system-date-refresh.d.ts.map +1 -0
  62. package/dist/hooks/magic-context/system-prompt-dates.d.ts +6 -0
  63. package/dist/hooks/magic-context/system-prompt-dates.d.ts.map +1 -0
  64. package/dist/hooks/magic-context/system-prompt-delivery.d.ts +47 -0
  65. package/dist/hooks/magic-context/system-prompt-delivery.d.ts.map +1 -0
  66. package/dist/hooks/magic-context/system-prompt-hash.d.ts +4 -0
  67. package/dist/hooks/magic-context/system-prompt-hash.d.ts.map +1 -1
  68. package/dist/hooks/magic-context/tag-messages.d.ts +8 -0
  69. package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
  70. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +2 -0
  71. package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
  72. package/dist/hooks/magic-context/transform.d.ts +6 -0
  73. package/dist/hooks/magic-context/transform.d.ts.map +1 -1
  74. package/dist/{index-9qjqq45k.js → index-0pjvpfkf.js} +21 -1
  75. package/dist/index-6m7rdv7y.js +733 -0
  76. package/dist/{index-1r0k9js3.js → index-6tfxmc4n.js} +10 -10
  77. package/dist/{index-gzcmtmar.js → index-7w18gg78.js} +25 -1
  78. package/dist/{index-nm6a8xpd.js → index-att4bfan.js} +1 -1
  79. package/dist/{index-ezmszwbd.js → index-eypn4ba6.js} +7 -4
  80. package/dist/{index-ha87j7a8.js → index-fdtkt5r1.js} +6 -6
  81. package/dist/{index-kp5qe690.js → index-fg00p1cg.js} +38 -36
  82. package/dist/{index-1bc61ans.js → index-fvnzcnww.js} +44 -1
  83. package/dist/index-gbmqa9x9.js +1170 -0
  84. package/dist/{index-pxwp2hjk.js → index-gzky5rva.js} +30 -53
  85. package/dist/{index-kq57tdf0.js → index-k6xvbj2e.js} +255 -1075
  86. package/dist/{index-0w56v4fm.js → index-mw7c950g.js} +1 -1
  87. package/dist/{index-1g30axtz.js → index-p0n5ryq8.js} +82 -900
  88. package/dist/{index-b7mv1jx3.js → index-p1hnwfd8.js} +1 -1
  89. package/dist/{index-peshmj6h.js → index-r2zcs71c.js} +6 -4
  90. package/dist/{index-kmpvemph.js → index-rafsaxac.js} +2 -2
  91. package/dist/{index-stbr4ce6.js → index-s7fc0fkn.js} +1 -1
  92. package/dist/{index-hj2q50k0.js → index-sfhndpcb.js} +463 -6
  93. package/dist/index-sv0bb7vg.js +6972 -0
  94. package/dist/{index-57mrqed8.js → index-w23dh319.js} +17 -258
  95. package/dist/{index-9rt53q79.js → index-xgrwmj82.js} +1 -1
  96. package/dist/{index-h2py7207.js → index-xnanvj3w.js} +765 -1255
  97. package/dist/{index-2jcbj7r1.js → index-zfzdpeq2.js} +2269 -3802
  98. package/dist/{index-s4j7t92z.js → index-zg8yq4ya.js} +29 -744
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +209 -61
  101. package/dist/{message-index-bounded-h0mrd4pr.js → message-index-bounded-hqktkhdy.js} +7 -6
  102. package/dist/migration-worker.js +6 -5
  103. package/dist/plugin/hooks/create-session-hooks.d.ts +3 -1
  104. package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
  105. package/dist/plugin/messages-transform.d.ts.map +1 -1
  106. package/dist/plugin/rpc-handlers.d.ts.map +1 -1
  107. package/dist/{project-embedding-registry-rtt0djyb.js → project-embedding-registry-0gv3h6y8.js} +6 -6
  108. package/dist/raw-ordinal-warmup-worker.js +1 -1
  109. package/dist/{read-session-chunk-ty89v75e.js → read-session-chunk-5mh0bh8y.js} +5 -4
  110. package/dist/{recomp-orchestrator-4f1yyd1q.js → recomp-orchestrator-kpkhkjhq.js} +20 -19
  111. package/dist/{search-pz4f4wge.js → search-p9w39qv4.js} +15 -14
  112. package/dist/{send-session-notification-38cd5dqt.js → send-session-notification-xffh3bbe.js} +2 -2
  113. package/dist/shared/models-dev-cache.d.ts.map +1 -1
  114. package/dist/shared/storage-file-mutex.d.ts +9 -0
  115. package/dist/shared/storage-file-mutex.d.ts.map +1 -0
  116. package/dist/shared/storage-permissions.d.ts +6 -0
  117. package/dist/shared/storage-permissions.d.ts.map +1 -1
  118. package/dist/shared/window-geometry.d.ts +9 -66
  119. package/dist/shared/window-geometry.d.ts.map +1 -1
  120. package/dist/standalone-plugin-marker.d.ts +8 -0
  121. package/dist/standalone-plugin-marker.d.ts.map +1 -0
  122. package/dist/tools/ctx-reduce/constants.d.ts +1 -2
  123. package/dist/tools/ctx-reduce/constants.d.ts.map +1 -1
  124. package/dist/tools/ctx-reduce/tools.d.ts +1 -1
  125. package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
  126. package/dist/{transform-postprocess-phase-tck4g20s.js → transform-postprocess-phase-481j5a7z.js} +20 -19
  127. package/dist/v2/auto-search-worker.js +3 -3
  128. package/dist/v2/{context-crbt6p1y.js → context-gsdtha5v.js} +873 -2122
  129. package/dist/v2/{derive-budgets-fgej9j46.js → derive-budgets-enckmg7y.js} +2 -2
  130. package/dist/v2/{embedding-backfill-ph1qfyn3.js → embedding-backfill-dbvjbcmm.js} +8 -9
  131. package/dist/v2/embedding-worker-process.js +29 -0
  132. package/dist/v2/embedding-worker.js +3 -4
  133. package/dist/v2/hooks/context.d.ts.map +1 -1
  134. package/dist/v2/hooks/copied-tag-notation.d.ts +19 -0
  135. package/dist/v2/hooks/copied-tag-notation.d.ts.map +1 -0
  136. package/dist/v2/hooks/payload.d.ts.map +1 -1
  137. package/dist/v2/hooks/system-prompt-response.d.ts +5 -0
  138. package/dist/v2/hooks/system-prompt-response.d.ts.map +1 -0
  139. package/dist/v2/{message-index-bounded-xwqdywxg.js → message-index-bounded-p6v0n8qh.js} +8 -7
  140. package/dist/v2/migration-worker.js +6 -5
  141. package/dist/v2/{project-embedding-registry-d6m7tyxr.js → project-embedding-registry-nyq7z8y6.js} +7 -8
  142. package/dist/v2/raw-ordinal-warmup-worker.js +2 -2
  143. package/dist/v2/{read-session-chunk-8p5mdryx.js → read-session-chunk-fhyfe4qa.js} +6 -5
  144. package/dist/v2/{recomp-orchestrator-ckfgt6wq.js → recomp-orchestrator-5xy7w136.js} +22 -22
  145. package/dist/v2/{search-ym8rehhz.js → search-j7bakcwa.js} +17 -17
  146. package/dist/v2/{send-session-notification-5m0yapqx.js → send-session-notification-f6v698r5.js} +2 -2
  147. package/dist/v2/{server-jvxzm1jy.js → server-1fszbabv.js} +28 -28
  148. package/dist/v2/{server-3j4d00kf.js → server-2htmbqbv.js} +25 -1
  149. package/dist/v2/{server-c5rrgrcd.js → server-4c7jt8gq.js} +25 -1
  150. package/dist/v2/{server-ycw9qqcy.js → server-4enr7s6x.js} +1 -1
  151. package/dist/v2/{server-v4mewb78.js → server-6tcrjfw8.js} +1 -1
  152. package/dist/v2/{server-x4hscabv.js → server-7spkq1y6.js} +2257 -3746
  153. package/dist/v2/{server-sa8jvrfc.js → server-7vkj6zhb.js} +29 -744
  154. package/dist/v2/{server-xwz4dqh9.js → server-8xmq9h3f.js} +30 -53
  155. package/dist/v2/{server-1tk82krw.js → server-bgzy0phk.js} +463 -6
  156. package/dist/v2/server-c7n2ftng.js +6860 -0
  157. package/dist/v2/server-cvgn49tr.js +733 -0
  158. package/dist/v2/{server-zm570tr2.js → server-cw6521wn.js} +232 -7
  159. package/dist/v2/{server-pj4pjv02.js → server-czb2rkpk.js} +21 -1
  160. package/dist/v2/{server-19zjmn02.js → server-d6g4whc2.js} +20 -14
  161. package/dist/v2/{server-1bc61ans.js → server-fvnzcnww.js} +44 -1
  162. package/dist/v2/{server-w32kmdez.js → server-kh958yj8.js} +3 -3
  163. package/dist/v2/{server-q4ph9bwn.js → server-mqvtz7wz.js} +7 -7
  164. package/dist/v2/{server-2s6ayq3t.js → server-ras2sxnc.js} +133 -13
  165. package/dist/v2/{server-ss95ky04.js → server-s2st631p.js} +1 -1
  166. package/dist/v2/{server-2s9qz6n7.js → server-t528t8qm.js} +1 -1
  167. package/dist/v2/{server-8k2agx29.js → server-vb7pbd9p.js} +17 -258
  168. package/dist/v2/{server-zp53y8js.js → server-zbxjj2mz.js} +2 -2
  169. package/dist/v2/server.d.ts.map +1 -1
  170. package/dist/v2/server.js +149 -5
  171. package/dist/v2/{storage-tags-8vw924zn.js → storage-tags-5yxrvkaf.js} +1 -1
  172. package/dist/v2/{wrapup-orchestrator-a7efxaax.js → wrapup-orchestrator-yem5422s.js} +28 -28
  173. package/dist/{wrapup-orchestrator-barbc6h9.js → wrapup-orchestrator-xvrr27ws.js} +21 -20
  174. package/package.json +4 -4
  175. package/src/config/{mural-model-deprecation.ts → deprecated-config.ts} +19 -0
  176. package/src/config/index.test.ts +15 -37
  177. package/src/config/index.ts +2 -3
  178. package/src/config/project-security.ts +3 -3
  179. package/src/config/schema/magic-context.ts +11 -7
  180. package/src/features/magic-context/dreamer/task-registry.ts +2 -3
  181. package/src/shared/models-dev-cache.ts +1 -7
  182. package/src/shared/sqlite-640-review.test.ts +5 -1
  183. package/src/shared/storage-file-mutex-review.test.ts +162 -0
  184. package/src/shared/storage-file-mutex.ts +130 -0
  185. package/src/shared/storage-permissions.ts +46 -0
  186. package/src/shared/window-geometry.test.ts +102 -236
  187. package/src/shared/window-geometry.ts +23 -413
  188. package/dist/config/mural-model-deprecation.d.ts.map +0 -1
  189. package/dist/index-2jgwttpt.js +0 -3269
  190. package/dist/index-mfkzp7qj.js +0 -229
  191. package/dist/v2/server-4ez8mntn.js +0 -3213
  192. package/dist/v2/server-mfkzp7qj.js +0 -229
  193. package/src/shared/__fixtures__/window-overlay.v1.json +0 -337
  194. /package/dist/{index-2pp04pmg.js → index-69vas84q.js} +0 -0
  195. /package/dist/v2/{index-2pp04pmg.js → index-69vas84q.js} +0 -0
@@ -0,0 +1,1170 @@
1
+ import {
2
+ DEFAULT_LOCAL_EMBEDDING_MODEL
3
+ } from "./index-k6xvbj2e.js";
4
+ import {
5
+ getSynapseLaneIdentity
6
+ } from "./index-vkbqdnkj.js";
7
+ import {
8
+ getHarness2
9
+ } from "./index-pavzsdc6.js";
10
+ import {
11
+ getMagicContextStorageDir
12
+ } from "./index-0sahzkwr.js";
13
+ import {
14
+ importPluginModule,
15
+ log2
16
+ } from "./index-nsjyysj0.js";
17
+ import {
18
+ computeNormalizedHash
19
+ } from "./index-2bvekkfy.js";
20
+ import {
21
+ shouldEnforcePrivateStoragePermissions,
22
+ ensureStorageDirectorySync,
23
+ writeStorageFileAsync,
24
+ writeStorageFileHandleAsync,
25
+ createStorageFileHandleAsync
26
+ } from "./index-fvnzcnww.js";
27
+
28
+ // src/features/magic-context/memory/embedding-model-match.ts
29
+ function parseEmbeddingModel(model) {
30
+ const lastColon = model.lastIndexOf(":");
31
+ if (lastColon > model.lastIndexOf("/")) {
32
+ return { base: model.slice(0, lastColon), tag: model.slice(lastColon + 1) };
33
+ }
34
+ return { base: model };
35
+ }
36
+ function normalizeEmbeddingModelId(model) {
37
+ return parseEmbeddingModel(model.trim().toLowerCase()).base;
38
+ }
39
+ function matchNormalizedEmbeddingModels(a, b) {
40
+ if (a.length === 0 || b.length === 0)
41
+ return true;
42
+ if (a === b)
43
+ return true;
44
+ const longer = a.length >= b.length ? a : b;
45
+ const shorter = a.length >= b.length ? b : a;
46
+ const isBoundary = (ch) => ch === "-" || ch === "/";
47
+ if (longer.startsWith(shorter) && isBoundary(longer.charAt(shorter.length)))
48
+ return true;
49
+ if (longer.endsWith(shorter) && isBoundary(longer.charAt(longer.length - shorter.length - 1)))
50
+ return true;
51
+ return false;
52
+ }
53
+ function embeddingModelsMatch(served, requested) {
54
+ const servedNormalized = served.trim().toLowerCase();
55
+ const requestedNormalized = requested.trim().toLowerCase();
56
+ const servedModel = parseEmbeddingModel(servedNormalized);
57
+ const requestedModel = parseEmbeddingModel(requestedNormalized);
58
+ if (servedModel.tag !== undefined && requestedModel.tag !== undefined && servedModel.tag !== requestedModel.tag) {
59
+ return false;
60
+ }
61
+ return matchNormalizedEmbeddingModels(servedModel.base, requestedModel.base);
62
+ }
63
+ var QWEN3_QUERY_INSTRUCTION = `Instruct: Given a web search query, retrieve relevant passages that answer the query
64
+ Query: `;
65
+ var INSTRUCT_WEB_SEARCH_QUERY_PREFIX = QWEN3_QUERY_INSTRUCTION;
66
+ var EMBEDDING_MODEL_PREFIX_FAMILIES = [
67
+ {
68
+ family: "qwen3-embedding",
69
+ basenamePattern: /^qwen3-embedding(?:-|$)/,
70
+ prefixes: { queryPrefix: QWEN3_QUERY_INSTRUCTION, documentPrefix: "" }
71
+ },
72
+ {
73
+ family: "gte-qwen-instruct",
74
+ basenamePattern: /^gte-qwen.*-instruct(?:-|$)/,
75
+ prefixes: { queryPrefix: INSTRUCT_WEB_SEARCH_QUERY_PREFIX, documentPrefix: "" }
76
+ },
77
+ {
78
+ family: "e5-instruct",
79
+ basenamePattern: /^(?:multilingual-)?e5-.*-instruct(?:-|$)/,
80
+ prefixes: { queryPrefix: INSTRUCT_WEB_SEARCH_QUERY_PREFIX, documentPrefix: "" }
81
+ },
82
+ {
83
+ family: "nomic-embed-text",
84
+ basenamePattern: /^nomic-embed-text(?:-|$)/,
85
+ prefixes: { queryPrefix: "search_query: ", documentPrefix: "search_document: " }
86
+ }
87
+ ];
88
+ function modelBasename(model) {
89
+ const normalized = normalizeEmbeddingModelId(model);
90
+ return normalized.slice(normalized.lastIndexOf("/") + 1);
91
+ }
92
+ function resolveEmbeddingTextPrefixes(model, queryInstruction, documentPrefix) {
93
+ const family = EMBEDDING_MODEL_PREFIX_FAMILIES.find(({ basenamePattern }) => basenamePattern.test(modelBasename(model)));
94
+ return {
95
+ queryPrefix: queryInstruction === false ? "" : queryInstruction !== undefined ? queryInstruction : family?.prefixes.queryPrefix ?? "",
96
+ documentPrefix: documentPrefix ?? family?.prefixes.documentPrefix ?? ""
97
+ };
98
+ }
99
+
100
+ // src/features/magic-context/memory/embedding-identity.ts
101
+ function normalizeEndpoint(endpoint) {
102
+ return endpoint?.trim().replace(/\/+$/, "") ?? "";
103
+ }
104
+ var LOCAL_EMBEDDING_RUNTIME_FINGERPRINT = "transformers@4.3.0;onnxruntime-node@1.30.0;onnxruntime-web@1.26.0-dev.20260416-b7804b056c";
105
+ function getEmbeddingProviderIdentity(config) {
106
+ if (config.provider === "off") {
107
+ return "embedding-provider:off";
108
+ }
109
+ if (config.provider === "synapse") {
110
+ const resolved = config;
111
+ if (!resolved.model || !resolved.synapse_fingerprint)
112
+ return "synapse:v1:pending";
113
+ return getSynapseLaneIdentity(resolved.model, resolved.synapse_fingerprint);
114
+ }
115
+ if (config.provider !== "local" && config.provider !== "openai-compatible") {
116
+ throw new Error("Unknown embedding provider");
117
+ }
118
+ const truncate = config.provider === "openai-compatible" ? config.truncate?.trim() : undefined;
119
+ const documentPrefix = config.provider === "openai-compatible" ? resolveEmbeddingTextPrefixes(config.model, config.query_instruction, config.document_prefix).documentPrefix : "";
120
+ const localDtype = config.provider === "local" && config.local_dtype && config.local_dtype !== "fp32" ? config.local_dtype : undefined;
121
+ const identityInput = config.provider === "openai-compatible" ? {
122
+ provider: "openai-compatible",
123
+ model: config.model.trim(),
124
+ endpoint: normalizeEndpoint(config.endpoint),
125
+ apiKeyPresent: Boolean(config.api_key?.trim()),
126
+ inputType: config.input_type?.trim() || "",
127
+ ...documentPrefix ? { documentPrefix } : {},
128
+ ...truncate ? { truncate } : {}
129
+ } : {
130
+ provider: "local",
131
+ model: config.model?.trim() || DEFAULT_LOCAL_EMBEDDING_MODEL,
132
+ endpoint: "",
133
+ apiKeyPresent: false,
134
+ runtimeFingerprint: LOCAL_EMBEDDING_RUNTIME_FINGERPRINT,
135
+ ...localDtype ? { localDtype } : {}
136
+ };
137
+ return `embedding-provider:${computeNormalizedHash(JSON.stringify(identityInput))}`;
138
+ }
139
+
140
+ // src/features/magic-context/memory/embedding-local.ts
141
+ import { readdirSync, statSync } from "node:fs";
142
+ import { stat, unlink } from "node:fs/promises";
143
+ import { dirname, join } from "node:path";
144
+ import { pathToFileURL } from "node:url";
145
+ import { workerData } from "node:worker_threads";
146
+
147
+ // src/features/magic-context/memory/embedding-failure.ts
148
+ function errorMessage(error) {
149
+ return error instanceof Error ? error.message : String(error ?? "unknown error");
150
+ }
151
+ function nestedMessages(error) {
152
+ const messages = [errorMessage(error)];
153
+ if (error && typeof error === "object" && "cause" in error) {
154
+ const cause = error.cause;
155
+ if (cause !== undefined)
156
+ messages.push(...nestedMessages(cause));
157
+ }
158
+ return messages;
159
+ }
160
+ function safeErrorDetail(message) {
161
+ return message.replace(/https?:\/\/[^\s"']+/gi, "<remote URL>").replace(/\/(?:Users|home)\/[^/\s]+/g, "~").replace(/\s+/g, " ").trim().slice(0, 240);
162
+ }
163
+ function hasAny(messages, patterns) {
164
+ return messages.some((message) => {
165
+ const lower = message.toLowerCase();
166
+ return patterns.some((pattern) => lower.includes(pattern));
167
+ });
168
+ }
169
+ function classifyLocalEmbeddingFailure(error, context = {}) {
170
+ const primaryMessages = nestedMessages(error);
171
+ const nativeMessages = context.nativeError === undefined ? [] : nestedMessages(context.nativeError);
172
+ if (hasAny(primaryMessages, [
173
+ "mc_embedding_fs_unavailable",
174
+ "file system cache is not available"
175
+ ]) || context.usesWasm && hasAny(primaryMessages, ["unable to get model file path or buffer"])) {
176
+ return {
177
+ class: "local_fs_unavailable",
178
+ reason: "the WASM model cache cannot access the Node filesystem",
179
+ retryable: false
180
+ };
181
+ }
182
+ if (hasAny(primaryMessages, [
183
+ "failed to fetch",
184
+ "fetch failed",
185
+ "network error",
186
+ "enotfound",
187
+ "econnreset",
188
+ "econnrefused",
189
+ "certificate",
190
+ "unable to load file",
191
+ "unauthorized access to file",
192
+ "forbidden access to file",
193
+ "not found at"
194
+ ]) || primaryMessages.some((message) => /\bHTTP\s+[45]\d\d\b/i.test(message))) {
195
+ return {
196
+ class: "local_download_failure",
197
+ reason: `the embedding model download failed: ${safeErrorDetail(primaryMessages[0])}`,
198
+ retryable: true
199
+ };
200
+ }
201
+ const bindingMessages = [...primaryMessages, ...nativeMessages];
202
+ if (hasAny(bindingMessages, [
203
+ "onnxruntime_binding.node",
204
+ "cannot find package 'onnxruntime-node'",
205
+ 'cannot find package "onnxruntime-node"',
206
+ "cannot find module 'onnxruntime-node'",
207
+ 'cannot find module "onnxruntime-node"',
208
+ "could not resolve: onnxruntime-node"
209
+ ])) {
210
+ const platform = context.platform ?? process.platform;
211
+ const arch = context.arch ?? process.arch;
212
+ return {
213
+ class: "local_binding_missing",
214
+ reason: platform === "darwin" && arch === "x64" ? "onnxruntime-node has no darwin/x64 native binding and the WASM fallback could not complete" : `onnxruntime-node has no usable native binding for ${platform}/${arch} and the WASM fallback could not complete`,
215
+ retryable: false
216
+ };
217
+ }
218
+ return {
219
+ class: "local_runtime_error",
220
+ reason: `the local embedding runtime failed: ${safeErrorDetail(primaryMessages[0])}`,
221
+ retryable: false
222
+ };
223
+ }
224
+ function dominantEmbeddingFailure(failures) {
225
+ const counts = new Map;
226
+ for (const failure of failures) {
227
+ const key = `${failure.class}\x00${failure.reason}`;
228
+ const current = counts.get(key);
229
+ if (current)
230
+ current.count += 1;
231
+ else
232
+ counts.set(key, { failure, count: 1 });
233
+ }
234
+ let dominant;
235
+ for (const candidate of counts.values()) {
236
+ if (!dominant || candidate.count > dominant.count)
237
+ dominant = candidate;
238
+ }
239
+ return dominant?.failure;
240
+ }
241
+
242
+ // src/features/magic-context/memory/embedding-worker-client.ts
243
+ import { fork } from "node:child_process";
244
+ import { Worker } from "node:worker_threads";
245
+
246
+ // src/features/magic-context/memory/onnx-telemetry.ts
247
+ import { isMainThread } from "node:worker_threads";
248
+ var FFI_SPECIFIER = "bun:ffi";
249
+ async function prepareNativeOnnxTelemetry() {
250
+ if (process.platform === "win32")
251
+ return true;
252
+ if (!process.versions.bun) {
253
+ if (!isMainThread)
254
+ return false;
255
+ process.env.ORT_DISABLE_TELEMETRY = "1";
256
+ return true;
257
+ }
258
+ let ffi;
259
+ try {
260
+ ffi = await import(FFI_SPECIFIER);
261
+ } catch {
262
+ return false;
263
+ }
264
+ const { dlopen, FFIType } = ffi;
265
+ const paths = process.platform === "darwin" ? ["/usr/lib/libSystem.B.dylib"] : ["libc.so.6", `/lib/ld-musl-${process.arch === "arm64" ? "aarch64" : "x86_64"}.so.1`];
266
+ for (const path of paths) {
267
+ try {
268
+ const library = dlopen(path, {
269
+ setenv: {
270
+ args: [FFIType.cstring, FFIType.cstring, FFIType.i32],
271
+ returns: FFIType.i32
272
+ },
273
+ getenv: { args: [FFIType.cstring], returns: FFIType.cstring }
274
+ });
275
+ try {
276
+ const name = Buffer.from("ORT_DISABLE_TELEMETRY\x00");
277
+ const value = Buffer.from("1\x00");
278
+ const disabled = library.symbols.setenv(name, value, 1) === 0 && String(library.symbols.getenv(name)) === "1";
279
+ if (disabled)
280
+ process.env.ORT_DISABLE_TELEMETRY = "1";
281
+ return disabled;
282
+ } finally {
283
+ library.close();
284
+ }
285
+ } catch {}
286
+ }
287
+ return false;
288
+ }
289
+
290
+ // src/features/magic-context/memory/embedding-worker-client.ts
291
+ var warnedWindowsTelemetry = false;
292
+
293
+ class EmbeddingWorkerClient {
294
+ data;
295
+ entry;
296
+ timeoutMs;
297
+ prepareTelemetry;
298
+ worker = null;
299
+ startPromise = null;
300
+ nextId = 1;
301
+ pending = new Map;
302
+ disposed = false;
303
+ constructor(data, entry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "./embedding-worker.ts" : "./embedding-worker.js", import.meta.url), timeoutMs = 5 * 60000, prepareTelemetry = prepareNativeOnnxTelemetry) {
304
+ this.data = data;
305
+ this.entry = entry;
306
+ this.timeoutMs = timeoutMs;
307
+ this.prepareTelemetry = prepareTelemetry;
308
+ }
309
+ start() {
310
+ if (this.startPromise)
311
+ return this.startPromise;
312
+ this.startPromise = this.startOwner().finally(() => {
313
+ this.startPromise = null;
314
+ });
315
+ return this.startPromise;
316
+ }
317
+ async startOwner() {
318
+ if (this.disposed)
319
+ throw new Error("embedding worker disposed");
320
+ if (this.worker)
321
+ return this.worker;
322
+ const compiledBun = process.versions.bun && globalThis.Bun?.isStandaloneExecutable;
323
+ const inProcess = !compiledBun && await this.prepareTelemetry();
324
+ if (this.disposed)
325
+ throw new Error("embedding worker disposed");
326
+ const worker = inProcess ? new Worker(this.entry, { workerData: this.data }) : fork(new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "./embedding-worker-process.ts" : "./embedding-worker-process.js", import.meta.url), [], {
327
+ env: {
328
+ ...process.env,
329
+ ORT_DISABLE_TELEMETRY: "1",
330
+ ...process.versions.bun ? { BUN_BE_BUN: "1" } : {}
331
+ },
332
+ execArgv: [],
333
+ serialization: "json",
334
+ ...{ windowsHide: true },
335
+ stdio: ["ignore", "inherit", "inherit", "ipc"]
336
+ });
337
+ if (process.platform === "win32" && this.data.runtimePreference !== "wasm") {
338
+ if (!warnedWindowsTelemetry) {
339
+ warnedWindowsTelemetry = true;
340
+ const warning = "[magic-context] ORT_DISABLE_TELEMETRY=1 prevents ONNX uploads on POSIX. Windows native ONNX uses OS-controlled ETW diagnostics instead and exposes no JavaScript telemetry-disable API; Windows diagnostic settings and trace collectors govern collection.";
341
+ log2(warning);
342
+ }
343
+ }
344
+ this.worker = worker;
345
+ worker.unref();
346
+ if (!(worker instanceof Worker))
347
+ worker.channel?.unref?.();
348
+ worker.on("message", (wire) => {
349
+ const reply = worker instanceof Worker ? wire : {
350
+ ...wire,
351
+ vectors: wire.vectors?.map((vector) => vector === null ? null : new Float32Array(Uint8Array.from(Buffer.from(vector, "base64")).buffer))
352
+ };
353
+ if (this.worker !== worker)
354
+ return;
355
+ const request = this.pending.get(reply.id);
356
+ if (!request)
357
+ return;
358
+ clearTimeout(request.timer);
359
+ this.pending.delete(reply.id);
360
+ if (reply.error)
361
+ request.reject(new Error(reply.error));
362
+ else
363
+ request.resolve(reply);
364
+ if (this.pending.size === 0) {
365
+ worker.unref();
366
+ if (!(worker instanceof Worker))
367
+ worker.channel?.unref?.();
368
+ }
369
+ });
370
+ const fail = (error) => {
371
+ if (this.worker !== worker)
372
+ return;
373
+ this.worker = null;
374
+ for (const request of this.pending.values()) {
375
+ clearTimeout(request.timer);
376
+ request.reject(error);
377
+ }
378
+ this.pending.clear();
379
+ log2("[magic-context] embedding worker exited unexpectedly:", error);
380
+ if (worker instanceof Worker)
381
+ worker.terminate();
382
+ else
383
+ worker.kill();
384
+ };
385
+ worker.on("error", fail);
386
+ worker.on("exit", (code, signal) => fail(new Error(`embedding worker exited (${signal ?? code})`)));
387
+ if (!(worker instanceof Worker))
388
+ worker.send({ entry: this.entry.href, data: this.data });
389
+ return worker;
390
+ }
391
+ isRunning() {
392
+ return this.worker !== null;
393
+ }
394
+ async request(texts, signal) {
395
+ if (signal?.aborted)
396
+ return Promise.reject(new Error("embedding request aborted"));
397
+ const worker = await this.start();
398
+ if (this.disposed)
399
+ throw new Error("embedding worker disposed");
400
+ if (signal?.aborted)
401
+ throw new Error("embedding request aborted");
402
+ return new Promise((resolve, reject) => {
403
+ const id = this.nextId++;
404
+ const timer = setTimeout(() => {
405
+ this.stop(new Error("embedding worker request timed out"));
406
+ }, this.timeoutMs);
407
+ const abort = () => {
408
+ clearTimeout(timer);
409
+ this.pending.delete(id);
410
+ signal?.removeEventListener("abort", abort);
411
+ reject(new Error("embedding request aborted"));
412
+ if (this.pending.size === 0) {
413
+ worker.unref();
414
+ if (!(worker instanceof Worker))
415
+ worker.channel?.unref?.();
416
+ }
417
+ };
418
+ signal?.addEventListener("abort", abort, { once: true });
419
+ const cleanup = () => signal?.removeEventListener("abort", abort);
420
+ this.pending.set(id, {
421
+ timer,
422
+ resolve: (reply) => {
423
+ cleanup();
424
+ resolve(reply);
425
+ },
426
+ reject: (error) => {
427
+ cleanup();
428
+ reject(error);
429
+ }
430
+ });
431
+ worker.ref();
432
+ if (!(worker instanceof Worker))
433
+ worker.channel?.ref?.();
434
+ try {
435
+ if (worker instanceof Worker)
436
+ worker.postMessage({ id, texts });
437
+ else
438
+ worker.send({ id, texts }, (error) => {
439
+ if (error && this.worker === worker)
440
+ this.stop(error);
441
+ });
442
+ } catch (error) {
443
+ this.stop(error instanceof Error ? error : new Error(String(error)));
444
+ }
445
+ });
446
+ }
447
+ async stop(error) {
448
+ const worker = this.worker;
449
+ this.worker = null;
450
+ for (const request of this.pending.values()) {
451
+ clearTimeout(request.timer);
452
+ request.reject(error);
453
+ }
454
+ this.pending.clear();
455
+ if (worker instanceof Worker) {
456
+ await worker.terminate();
457
+ } else if (worker && worker.exitCode === null && worker.signalCode === null) {
458
+ worker.ref();
459
+ worker.channel?.ref?.();
460
+ await new Promise((resolve) => {
461
+ worker.once("exit", () => resolve());
462
+ worker.kill();
463
+ });
464
+ }
465
+ }
466
+ async dispose() {
467
+ this.disposed = true;
468
+ await this.startPromise?.catch(() => {});
469
+ await this.stop(new Error("embedding worker disposed"));
470
+ }
471
+ }
472
+
473
+ // src/features/magic-context/memory/transformers-remote-host.ts
474
+ var DEFAULT_TRANSFORMERS_REMOTE_HOST = "https://huggingface.co/";
475
+ function readHuggingFaceEndpoint() {
476
+ return globalThis.process?.env?.HF_ENDPOINT;
477
+ }
478
+ function configureTransformersRemoteHost(env, endpoint = readHuggingFaceEndpoint()) {
479
+ const normalized = endpoint?.trim().replace(/\/+$/, "");
480
+ env.remoteHost = normalized ? `${normalized}/` : DEFAULT_TRANSFORMERS_REMOTE_HOST;
481
+ }
482
+
483
+ // src/features/magic-context/memory/embedding-local.ts
484
+ var BUN_NAPI_TEARDOWN_FIX_VERSION = [1, 4, 0];
485
+ function currentLocalEmbeddingHost() {
486
+ const bun = globalThis.Bun;
487
+ const hasProcess = typeof process !== "undefined";
488
+ const bunVersion = hasProcess && typeof process.versions?.bun === "string" ? process.versions.bun : undefined;
489
+ return {
490
+ isElectron: hasProcess && Boolean(process.versions?.electron),
491
+ isBun: Boolean(bun) || Boolean(bunVersion),
492
+ bunVersion,
493
+ hasNodeFilesystem: hasProcess && (typeof process.versions?.node === "string" || typeof bunVersion === "string")
494
+ };
495
+ }
496
+ function bunHasNapiTeardownFix(version) {
497
+ const match = version?.match(/^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/);
498
+ if (!match || match[4])
499
+ return false;
500
+ const parsed = [Number(match[1]), Number(match[2]), Number(match[3])];
501
+ return parsed.some((part) => !Number.isSafeInteger(part)) ? false : parsed[0] > BUN_NAPI_TEARDOWN_FIX_VERSION[0] || parsed[0] === BUN_NAPI_TEARDOWN_FIX_VERSION[0] && (parsed[1] > BUN_NAPI_TEARDOWN_FIX_VERSION[1] || parsed[1] === BUN_NAPI_TEARDOWN_FIX_VERSION[1] && parsed[2] >= BUN_NAPI_TEARDOWN_FIX_VERSION[2]);
502
+ }
503
+ function resolveLocalEmbeddingRuntime(preference = "auto", host = currentLocalEmbeddingHost()) {
504
+ if (preference === "native" || preference === "wasm")
505
+ return preference;
506
+ if (host.isElectron)
507
+ return "electron";
508
+ if (host.isBun && !bunHasNapiTeardownFix(host.bunVersion))
509
+ return "wasm";
510
+ return "native";
511
+ }
512
+ function resolveLocalEmbeddingWorkerRuntime(preference = "auto", host = currentLocalEmbeddingHost()) {
513
+ if (host.isBun && !bunHasNapiTeardownFix(host.bunVersion) && preference === "native")
514
+ return "wasm";
515
+ return resolveLocalEmbeddingRuntime(preference, host);
516
+ }
517
+ var LOCK_POLL_MS = 150;
518
+ var STALE_LOCK_MS = 3 * 60000;
519
+ var MAX_LOCK_WAIT_MS = 5 * 60000;
520
+ async function acquireModelLoadLock(lockPath) {
521
+ const waitStart = Date.now();
522
+ while (true) {
523
+ try {
524
+ const handle = await createStorageFileHandleAsync(lockPath, "wx");
525
+ try {
526
+ await writeStorageFileHandleAsync(handle, `pid=${process.pid} started=${Date.now()}
527
+ `);
528
+ } catch {}
529
+ await handle.close();
530
+ return async () => {
531
+ try {
532
+ await unlink(lockPath);
533
+ } catch {}
534
+ };
535
+ } catch (error) {
536
+ const code = error.code;
537
+ if (code !== "EEXIST" && code !== "EPERM") {
538
+ throw error;
539
+ }
540
+ try {
541
+ const info = await stat(lockPath);
542
+ if (Date.now() - info.mtimeMs > STALE_LOCK_MS) {
543
+ log2(`[magic-context] embedding-load lock stale (>${STALE_LOCK_MS}ms), taking over`);
544
+ try {
545
+ await unlink(lockPath);
546
+ } catch {}
547
+ continue;
548
+ }
549
+ } catch {
550
+ continue;
551
+ }
552
+ if (Date.now() - waitStart > MAX_LOCK_WAIT_MS) {
553
+ throw new Error(`[magic-context] embedding-load lock wait exceeded ${MAX_LOCK_WAIT_MS}ms; another process is still loading the model. Skipping this init attempt to avoid an unsynchronized native load.`);
554
+ }
555
+ await new Promise((resolve) => setTimeout(resolve, LOCK_POLL_MS));
556
+ }
557
+ }
558
+ }
559
+ function startLockHeartbeat(lockPath) {
560
+ const HEARTBEAT_MS = Math.floor(STALE_LOCK_MS / 3);
561
+ const timer = setInterval(() => {
562
+ writeStorageFileAsync(lockPath, `pid=${process.pid} alive=${Date.now()}
563
+ `).catch(() => {});
564
+ }, HEARTBEAT_MS);
565
+ timer.unref?.();
566
+ return () => clearInterval(timer);
567
+ }
568
+ var ONNX_RUNTIME_WEB_SPECIFIER = "onnxruntime-web";
569
+ var useInThreadTestRuntime = false;
570
+ var workerFactoryForTests;
571
+ var localEmbeddingRuntimeMode = "native";
572
+ var localEmbeddingProcessFailure = null;
573
+ var wasmRuntimeInjected = false;
574
+ var localEmbeddingHostForRuntime = currentLocalEmbeddingHost;
575
+ var resolveWasmOrtForRuntime = () => {
576
+ try {
577
+ return typeof import.meta.resolve === "function" ? import.meta.resolve(ONNX_RUNTIME_WEB_SPECIFIER) : undefined;
578
+ } catch {
579
+ return;
580
+ }
581
+ };
582
+ var importWasmOrtModule = async (specifier) => await import(specifier);
583
+ var importWasmOrtModuleForRuntime = importWasmOrtModule;
584
+ var importWasmOrtForRuntime = async () => {
585
+ const { createRequire: createRequireFn } = await import("node:module");
586
+ const requireFn = createRequireFn(import.meta.url);
587
+ const ortEntry = requireFn.resolve(ONNX_RUNTIME_WEB_SPECIFIER);
588
+ const ortSpecifier = resolveWasmOrtForRuntime() ?? ONNX_RUNTIME_WEB_SPECIFIER;
589
+ return {
590
+ module: await importWasmOrtModuleForRuntime(ortSpecifier),
591
+ entryPath: ortEntry
592
+ };
593
+ };
594
+ var importTransformersForRuntime = async () => {
595
+ return await importPluginModule(() => import("./transformers.node-3zqr6k1w.js"));
596
+ };
597
+ var importTransformersWasmFallbackForRuntime = async () => {
598
+ const webEntry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "../../../../dist/transformers-web.js" : "./transformers-web.js", import.meta.url).href;
599
+ return await importPluginModule(() => import(webEntry));
600
+ };
601
+ var importTransformersNodeWasmFallbackForRuntime = async () => {
602
+ const nodeWasmEntry = new URL(new URL(import.meta.url).pathname.endsWith(".ts") ? "../../../../dist/transformers-node-wasm.js" : "./transformers-node-wasm.js", import.meta.url).href;
603
+ return await importPluginModule(() => import(nodeWasmEntry));
604
+ };
605
+ var modelCacheDirForRuntime = () => workerData?.magicContextEmbeddingWorker && typeof workerData.modelCacheDir === "string" ? workerData.modelCacheDir : join(getMagicContextStorageDir(), "models");
606
+ var logForRuntime = log2;
607
+ var injectWasmOrtForRuntime = injectWasmOrt;
608
+ var loadedLocalEmbeddingRuntimes = new Map;
609
+ var nextLocalEmbeddingRuntimeId = 1;
610
+ function directoryBytes(path) {
611
+ let total = 0;
612
+ try {
613
+ for (const entry of readdirSync(path, { withFileTypes: true })) {
614
+ const entryPath = join(path, entry.name);
615
+ if (entry.isDirectory()) {
616
+ const childBytes = directoryBytes(entryPath);
617
+ if (childBytes === null)
618
+ return null;
619
+ total += childBytes;
620
+ } else if (entry.isFile()) {
621
+ total += statSync(entryPath).size;
622
+ }
623
+ }
624
+ return total;
625
+ } catch (error) {
626
+ return error.code === "ENOENT" ? 0 : null;
627
+ }
628
+ }
629
+ function getLocalEmbeddingNativeMemoryStats() {
630
+ const loaded = [...loadedLocalEmbeddingRuntimes.values()];
631
+ return {
632
+ loaded: loaded.length > 0,
633
+ providerCount: loaded.length,
634
+ models: [...new Set(loaded.map((entry) => entry.model))].sort(),
635
+ runtimes: [...new Set(loaded.map((entry) => entry.runtime))].sort(),
636
+ modelCacheBytes: loaded.length > 0 ? directoryBytes(modelCacheDirForRuntime()) : 0,
637
+ rssDeltaAtLoad: loaded.reduce((sum, entry) => sum + entry.rssDeltaAtLoad, 0),
638
+ externalDeltaAtLoad: loaded.reduce((sum, entry) => sum + entry.externalDeltaAtLoad, 0),
639
+ arrayBuffersDeltaAtLoad: loaded.reduce((sum, entry) => sum + entry.arrayBuffersDeltaAtLoad, 0)
640
+ };
641
+ }
642
+ async function ensureWasmOrtInjected() {
643
+ if (wasmRuntimeInjected)
644
+ return true;
645
+ if (!await injectWasmOrtForRuntime())
646
+ return false;
647
+ wasmRuntimeInjected = true;
648
+ return true;
649
+ }
650
+ async function injectWasmOrt() {
651
+ if (wasmRuntimeInjected)
652
+ return true;
653
+ try {
654
+ const { module: ortWeb, entryPath } = await importWasmOrtForRuntime();
655
+ if (ortWeb.env?.wasm) {
656
+ ortWeb.env.wasm.numThreads = 1;
657
+ ortWeb.env.wasm.wasmPaths = `${pathToFileURL(dirname(entryPath)).href}/`;
658
+ }
659
+ globalThis[Symbol.for("onnxruntime")] = ortWeb;
660
+ wasmRuntimeInjected = true;
661
+ return true;
662
+ } catch (error) {
663
+ log2("[magic-context] failed to inject onnxruntime-web:", error instanceof Error ? error.message : String(error));
664
+ return false;
665
+ }
666
+ }
667
+ function likelyMuslHint() {
668
+ if (process.platform !== "linux" || typeof process.report?.getReport !== "function")
669
+ return "";
670
+ try {
671
+ const report = process.report.getReport();
672
+ return typeof report.header?.glibcVersionRuntime === "string" ? "" : " Linux process report has no glibc runtime version (musl likely).";
673
+ } catch {
674
+ return "";
675
+ }
676
+ }
677
+ function localEmbeddingRuntimeIsDisabled() {
678
+ return localEmbeddingRuntimeMode === "disabled";
679
+ }
680
+
681
+ class LocalEmbeddingFallbackError extends Error {
682
+ nativeError;
683
+ constructor(nativeError, wasmError) {
684
+ super("the native local embedding runtime and its WASM fallback both failed", {
685
+ cause: wasmError
686
+ });
687
+ this.name = "LocalEmbeddingFallbackError";
688
+ this.nativeError = nativeError;
689
+ }
690
+ }
691
+
692
+ class LocalEmbeddingFsUnavailableError extends Error {
693
+ code = "MC_EMBEDDING_FS_UNAVAILABLE";
694
+ constructor() {
695
+ super("MC_EMBEDDING_FS_UNAVAILABLE: Node WASM bundle has no filesystem cache");
696
+ this.name = "LocalEmbeddingFsUnavailableError";
697
+ }
698
+ }
699
+ async function importWasmTransformersForHost() {
700
+ const host = localEmbeddingHostForRuntime();
701
+ if (host.isElectron) {
702
+ return importTransformersForRuntime();
703
+ }
704
+ return host.hasNodeFilesystem ? importTransformersNodeWasmFallbackForRuntime() : importTransformersWasmFallbackForRuntime();
705
+ }
706
+ function disableLocalEmbeddingsAfterRuntimeFailure(detail) {
707
+ localEmbeddingRuntimeMode = "disabled";
708
+ logForRuntime(`[magic-context] local embeddings are disabled because both the onnxruntime-node native binding and the onnxruntime-web (WASM) fallback failed to load. Native failure: ${detail}. Run \`npx @cortexkit/magic-context@latest doctor\` for diagnostics; reinstalling repairs missing package files but cannot add a native binding that upstream does not ship. Alternatively, configure an \`openai-compatible\` embedding HTTP endpoint. Existing memories are unaffected.`);
709
+ }
710
+ async function loadTransformersForLocalEmbedding(runtimePreference) {
711
+ if (localEmbeddingRuntimeMode === "disabled") {
712
+ throw new Error("local embedding runtime is disabled");
713
+ }
714
+ const resolvedRuntime = resolveLocalEmbeddingRuntime(runtimePreference, localEmbeddingHostForRuntime());
715
+ if (resolvedRuntime === "wasm") {
716
+ if (!await ensureWasmOrtInjected()) {
717
+ disableLocalEmbeddingsAfterRuntimeFailure("the selected WASM runtime is unavailable");
718
+ throw new Error("onnxruntime-web failed to load");
719
+ }
720
+ return { module: await importWasmTransformersForHost(), usesWasm: true };
721
+ }
722
+ if (localEmbeddingRuntimeMode === "wasm") {
723
+ if (!await ensureWasmOrtInjected()) {
724
+ disableLocalEmbeddingsAfterRuntimeFailure("the previously selected WASM runtime is unavailable");
725
+ throw new Error("onnxruntime-web failed to load");
726
+ }
727
+ try {
728
+ return { module: await importWasmTransformersForHost(), usesWasm: true };
729
+ } catch (wasmError) {
730
+ disableLocalEmbeddingsAfterRuntimeFailure("the previously selected WASM runtime failed to load");
731
+ throw wasmError;
732
+ }
733
+ }
734
+ const electron = resolvedRuntime === "electron";
735
+ if (electron) {
736
+ const wasInjected = wasmRuntimeInjected;
737
+ if (await ensureWasmOrtInjected()) {
738
+ if (!wasInjected) {
739
+ logForRuntime("[magic-context] Electron detected — using onnxruntime-web (WASM) for embeddings (bypasses onnxruntime-node native load)");
740
+ }
741
+ return { module: await importTransformersForRuntime(), usesWasm: true };
742
+ }
743
+ }
744
+ try {
745
+ return { module: await importTransformersForRuntime(), usesWasm: false };
746
+ } catch (nativeError) {
747
+ if (!isNativeRuntimeMissingError(nativeError) || electron) {
748
+ throw nativeError;
749
+ }
750
+ if (!await ensureWasmOrtInjected()) {
751
+ disableLocalEmbeddingsAfterRuntimeFailure(nativeError instanceof Error ? nativeError.message : String(nativeError));
752
+ throw nativeError;
753
+ }
754
+ localEmbeddingRuntimeMode = "wasm";
755
+ try {
756
+ const module = await importWasmTransformersForHost();
757
+ logForRuntime("[magic-context] onnxruntime-node failed to load; using onnxruntime-web (WASM) for local embeddings. WASM inference is slower than native; a remote `openai-compatible` provider may be faster." + likelyMuslHint());
758
+ return { module, usesWasm: true };
759
+ } catch (wasmError) {
760
+ disableLocalEmbeddingsAfterRuntimeFailure(nativeError instanceof Error ? nativeError.message : String(nativeError));
761
+ throw new LocalEmbeddingFallbackError(nativeError, wasmError);
762
+ }
763
+ }
764
+ }
765
+ var DEFAULT_LOCAL_DTYPE = "fp32";
766
+ async function withQuietConsole(fn) {
767
+ const origWarn = console.warn;
768
+ const origError = console.error;
769
+ const redirect = (...args) => {
770
+ const message = args.map((a) => typeof a === "string" ? a : String(a)).join(" ");
771
+ log2(`[transformers] ${message}`);
772
+ };
773
+ console.warn = redirect;
774
+ console.error = redirect;
775
+ try {
776
+ return await fn();
777
+ } finally {
778
+ console.warn = origWarn;
779
+ console.error = origError;
780
+ }
781
+ }
782
+ function isNativeRuntimeMissingError(error) {
783
+ const message = error instanceof Error ? error.message : String(error ?? "");
784
+ const lower = message.toLowerCase();
785
+ const code = error?.code;
786
+ const name = error?.name;
787
+ if (code === "ERR_DLOPEN_FAILED" && lower.includes("onnxruntime")) {
788
+ return true;
789
+ }
790
+ if (lower.includes('could not load the "sharp" module'))
791
+ return true;
792
+ const mentionsNativeRuntime = lower.includes("onnxruntime-node") || lower.includes("onnxruntime_binding");
793
+ if (!mentionsNativeRuntime)
794
+ return false;
795
+ return code === "ERR_MODULE_NOT_FOUND" || name === "ResolveMessage" || lower.includes("cannot find package") || lower.includes("cannot find module") || lower.includes("err_module_not_found");
796
+ }
797
+ function isTransientLoadError(error) {
798
+ const message = error instanceof Error ? error.message : String(error ?? "");
799
+ if (!message)
800
+ return false;
801
+ const lower = message.toLowerCase();
802
+ return lower.includes("protobuf parsing failed") || lower.includes("unable to get model file path or buffer") || lower.includes("ebusy") || lower.includes("resource busy") || lower.includes("resource temporarily unavailable");
803
+ }
804
+ function isArrayLikeNumber(value) {
805
+ if (typeof value !== "object" || value === null || !("length" in value)) {
806
+ return false;
807
+ }
808
+ const arr = value;
809
+ if (typeof arr.length !== "number") {
810
+ return false;
811
+ }
812
+ return arr.length === 0 || typeof arr[0] === "number";
813
+ }
814
+ function toFloat32Array(values) {
815
+ return values instanceof Float32Array ? new Float32Array(values) : Float32Array.from(Array.from(values));
816
+ }
817
+ function extractBatchEmbeddings(result, expectedCount) {
818
+ const { data } = result;
819
+ if (Array.isArray(data) && data.length === expectedCount && data.every((entry) => typeof entry !== "number" && isArrayLikeNumber(entry))) {
820
+ return data.map((entry) => toFloat32Array(entry));
821
+ }
822
+ if (!isArrayLikeNumber(data)) {
823
+ log2("[magic-context] embedding batch returned unexpected data shape");
824
+ return Array.from({ length: expectedCount }, () => null);
825
+ }
826
+ const flatData = toFloat32Array(data);
827
+ const dimension = result.dims?.at(-1) ?? flatData.length / expectedCount;
828
+ if (!Number.isInteger(dimension) || dimension <= 0 || flatData.length !== expectedCount * dimension) {
829
+ log2("[magic-context] embedding batch returned invalid dimensions");
830
+ return Array.from({ length: expectedCount }, () => null);
831
+ }
832
+ const embeddings = [];
833
+ for (let index = 0;index < expectedCount; index++) {
834
+ embeddings.push(flatData.slice(index * dimension, (index + 1) * dimension));
835
+ }
836
+ return embeddings;
837
+ }
838
+
839
+ class LocalEmbeddingProvider {
840
+ modelId;
841
+ maxInputTokens;
842
+ memoryStatsId = nextLocalEmbeddingRuntimeId++;
843
+ model;
844
+ dtype;
845
+ runtimePreference;
846
+ pipeline = null;
847
+ workerClient;
848
+ workerLoaded = false;
849
+ initPromise = null;
850
+ lastFailureReason = null;
851
+ usesWasm = false;
852
+ inFlight = 0;
853
+ disposing = false;
854
+ disposePromise = null;
855
+ inFlightWaiters = [];
856
+ constructor(model = DEFAULT_LOCAL_EMBEDDING_MODEL, maxInputTokens = 512, dtype = DEFAULT_LOCAL_DTYPE, runtimePreference = "auto") {
857
+ this.model = model;
858
+ this.maxInputTokens = maxInputTokens;
859
+ this.dtype = dtype || DEFAULT_LOCAL_DTYPE;
860
+ this.runtimePreference = runtimePreference;
861
+ this.workerClient = !workerData?.magicContextEmbeddingWorker && !useInThreadTestRuntime ? (workerFactoryForTests ?? ((data) => new EmbeddingWorkerClient(data)))({
862
+ magicContextEmbeddingWorker: true,
863
+ modelCacheDir: modelCacheDirForRuntime(),
864
+ enforcePrivateStoragePermissions: shouldEnforcePrivateStoragePermissions(),
865
+ harness: getHarness2(),
866
+ model,
867
+ maxInputTokens,
868
+ dtype: this.dtype,
869
+ runtimePreference
870
+ }) : null;
871
+ this.modelId = getEmbeddingProviderIdentity({
872
+ provider: "local",
873
+ model,
874
+ local_runtime: runtimePreference,
875
+ ...dtype && dtype !== DEFAULT_LOCAL_DTYPE ? { local_dtype: dtype } : {}
876
+ });
877
+ }
878
+ async initialize() {
879
+ if (this.workerClient && !this.disposing) {
880
+ if (this.workerLoaded && this.workerClient.isRunning())
881
+ return true;
882
+ try {
883
+ const reply = await this.workerClient.request();
884
+ this.recordWorkerReply(reply);
885
+ return reply.loaded;
886
+ } catch (error) {
887
+ this.recordWorkerFailure(error);
888
+ return false;
889
+ }
890
+ }
891
+ if (this.disposing) {
892
+ return false;
893
+ }
894
+ if (this.pipeline) {
895
+ return true;
896
+ }
897
+ if (localEmbeddingRuntimeMode === "disabled") {
898
+ this.lastFailureReason = localEmbeddingProcessFailure ?? classifyLocalEmbeddingFailure(new Error("local embedding runtime is disabled"));
899
+ return false;
900
+ }
901
+ if (this.initPromise) {
902
+ await this.initPromise;
903
+ return this.pipeline !== null;
904
+ }
905
+ const memoryBeforeLoad = process.memoryUsage();
906
+ this.initPromise = (async () => {
907
+ try {
908
+ if (this.disposing) {
909
+ return;
910
+ }
911
+ const { module: transformersModule, usesWasm } = await loadTransformersForLocalEmbedding(this.runtimePreference);
912
+ this.usesWasm = usesWasm;
913
+ const env = transformersModule.env;
914
+ configureTransformersRemoteHost(env);
915
+ const LogLevel = transformersModule.LogLevel;
916
+ if (LogLevel && "ERROR" in LogLevel) {
917
+ env.logLevel = LogLevel.ERROR;
918
+ }
919
+ const host = localEmbeddingHostForRuntime();
920
+ if (usesWasm && host.hasNodeFilesystem && !host.isElectron && (env.useFS !== true || env.useFSCache !== true)) {
921
+ throw new LocalEmbeddingFsUnavailableError;
922
+ }
923
+ const modelCacheDir = modelCacheDirForRuntime();
924
+ try {
925
+ ensureStorageDirectorySync(modelCacheDir);
926
+ env.cacheDir = modelCacheDir;
927
+ } catch {
928
+ log2("[magic-context] could not create model cache dir, using library default");
929
+ }
930
+ const createPipeline = transformersModule.pipeline;
931
+ const lockPath = join(modelCacheDir, ".load.lock");
932
+ const releaseLock = await acquireModelLoadLock(lockPath);
933
+ const stopHeartbeat = startLockHeartbeat(lockPath);
934
+ try {
935
+ const MAX_ATTEMPTS = 3;
936
+ let lastError;
937
+ for (let attempt = 1;attempt <= MAX_ATTEMPTS; attempt++) {
938
+ try {
939
+ const pipeline = await withQuietConsole(() => createPipeline("feature-extraction", this.model, {
940
+ dtype: this.dtype,
941
+ ...usesWasm ? { device: "auto" } : {}
942
+ }));
943
+ if (this.disposing) {
944
+ await pipeline.dispose?.();
945
+ this.pipeline = null;
946
+ } else {
947
+ this.pipeline = pipeline;
948
+ }
949
+ lastError = undefined;
950
+ break;
951
+ } catch (error) {
952
+ lastError = error;
953
+ if (!isTransientLoadError(error) || attempt === MAX_ATTEMPTS) {
954
+ break;
955
+ }
956
+ const delayMs = 300 * attempt + Math.floor(Math.random() * 200);
957
+ log2(`[magic-context] embedding model load attempt ${attempt}/${MAX_ATTEMPTS} failed transiently, retrying in ${delayMs}ms`);
958
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
959
+ }
960
+ }
961
+ if (this.pipeline) {
962
+ this.lastFailureReason = null;
963
+ localEmbeddingProcessFailure = null;
964
+ const memoryAfterLoad = process.memoryUsage();
965
+ loadedLocalEmbeddingRuntimes.set(this.memoryStatsId, {
966
+ model: this.model,
967
+ runtime: this.usesWasm ? "wasm" : "native",
968
+ rssDeltaAtLoad: memoryAfterLoad.rss - memoryBeforeLoad.rss,
969
+ externalDeltaAtLoad: memoryAfterLoad.external - memoryBeforeLoad.external,
970
+ arrayBuffersDeltaAtLoad: memoryAfterLoad.arrayBuffers - memoryBeforeLoad.arrayBuffers
971
+ });
972
+ log2(`[magic-context] embedding model loaded: ${this.model}`);
973
+ } else if (this.disposing) {
974
+ return;
975
+ } else {
976
+ throw lastError ?? new Error("unknown embedding load failure");
977
+ }
978
+ } finally {
979
+ stopHeartbeat();
980
+ await releaseLock();
981
+ }
982
+ } catch (error) {
983
+ const nativeError = error instanceof LocalEmbeddingFallbackError ? error.nativeError : undefined;
984
+ const failure = classifyLocalEmbeddingFailure(error, {
985
+ platform: process.platform,
986
+ arch: process.arch,
987
+ usesWasm: this.usesWasm,
988
+ nativeError
989
+ });
990
+ this.lastFailureReason = failure;
991
+ localEmbeddingProcessFailure = failure;
992
+ if (!localEmbeddingRuntimeIsDisabled() && isNativeRuntimeMissingError(error)) {
993
+ disableLocalEmbeddingsAfterRuntimeFailure(error instanceof Error ? error.message : String(error));
994
+ }
995
+ logForRuntime(`[magic-context] embedding model failed to load (${failure.class}: ${failure.reason}):`, error);
996
+ this.pipeline = null;
997
+ } finally {
998
+ this.initPromise = null;
999
+ }
1000
+ })();
1001
+ await this.initPromise;
1002
+ return this.pipeline !== null;
1003
+ }
1004
+ waitForInFlightToDrain() {
1005
+ if (this.inFlight === 0) {
1006
+ return Promise.resolve();
1007
+ }
1008
+ return new Promise((resolve) => {
1009
+ this.inFlightWaiters.push(resolve);
1010
+ });
1011
+ }
1012
+ finishInFlight() {
1013
+ this.inFlight = Math.max(0, this.inFlight - 1);
1014
+ if (this.inFlight !== 0)
1015
+ return;
1016
+ const waiters = this.inFlightWaiters.splice(0);
1017
+ for (const waiter of waiters) {
1018
+ waiter();
1019
+ }
1020
+ }
1021
+ async embed(text, signal, _purpose) {
1022
+ if (this.workerClient)
1023
+ return (await this.embedBatch([text], signal, _purpose))[0] ?? null;
1024
+ if (signal?.aborted)
1025
+ return null;
1026
+ if (this.disposing)
1027
+ return null;
1028
+ this.inFlight += 1;
1029
+ try {
1030
+ if (!await this.initialize()) {
1031
+ return null;
1032
+ }
1033
+ const pipeline = this.pipeline;
1034
+ if (!pipeline) {
1035
+ return null;
1036
+ }
1037
+ const result = await withQuietConsole(() => pipeline(text, {
1038
+ pooling: "mean",
1039
+ normalize: true
1040
+ }));
1041
+ const embedding = extractBatchEmbeddings(result, 1)[0] ?? null;
1042
+ if (!embedding) {
1043
+ this.lastFailureReason = classifyLocalEmbeddingFailure(new Error("local embedding pipeline returned no vector"), { usesWasm: this.usesWasm });
1044
+ } else {
1045
+ this.lastFailureReason = null;
1046
+ }
1047
+ return embedding;
1048
+ } catch (error) {
1049
+ const failure = classifyLocalEmbeddingFailure(error, { usesWasm: this.usesWasm });
1050
+ this.lastFailureReason = failure;
1051
+ logForRuntime(`[magic-context] embedding failed (${failure.class}: ${failure.reason}):`, error);
1052
+ return null;
1053
+ } finally {
1054
+ this.finishInFlight();
1055
+ }
1056
+ }
1057
+ async embedBatch(texts, signal, _purpose) {
1058
+ if (this.workerClient) {
1059
+ if (!texts.length)
1060
+ return [];
1061
+ if (signal?.aborted || this.disposing)
1062
+ return texts.map(() => null);
1063
+ try {
1064
+ const reply = await this.workerClient.request(texts, signal);
1065
+ this.recordWorkerReply(reply);
1066
+ return reply.vectors ?? texts.map(() => null);
1067
+ } catch (error) {
1068
+ this.recordWorkerFailure(error);
1069
+ return texts.map(() => null);
1070
+ }
1071
+ }
1072
+ if (texts.length === 0) {
1073
+ return [];
1074
+ }
1075
+ if (signal?.aborted) {
1076
+ return Array.from({ length: texts.length }, () => null);
1077
+ }
1078
+ if (this.disposing) {
1079
+ return Array.from({ length: texts.length }, () => null);
1080
+ }
1081
+ this.inFlight += 1;
1082
+ try {
1083
+ if (!await this.initialize()) {
1084
+ return Array.from({ length: texts.length }, () => null);
1085
+ }
1086
+ const pipeline = this.pipeline;
1087
+ if (!pipeline) {
1088
+ return Array.from({ length: texts.length }, () => null);
1089
+ }
1090
+ const result = await withQuietConsole(() => pipeline(texts, {
1091
+ pooling: "mean",
1092
+ normalize: true
1093
+ }));
1094
+ const embeddings = extractBatchEmbeddings(result, texts.length);
1095
+ if (embeddings.every((embedding) => embedding === null)) {
1096
+ this.lastFailureReason = classifyLocalEmbeddingFailure(new Error("local embedding pipeline returned no vectors"), { usesWasm: this.usesWasm });
1097
+ } else {
1098
+ this.lastFailureReason = null;
1099
+ }
1100
+ return embeddings;
1101
+ } catch (error) {
1102
+ const failure = classifyLocalEmbeddingFailure(error, { usesWasm: this.usesWasm });
1103
+ this.lastFailureReason = failure;
1104
+ logForRuntime(`[magic-context] embedding batch failed (${failure.class}: ${failure.reason}):`, error);
1105
+ return Array.from({ length: texts.length }, () => null);
1106
+ } finally {
1107
+ this.finishInFlight();
1108
+ }
1109
+ }
1110
+ recordWorkerReply(reply) {
1111
+ this.workerLoaded = reply.loaded;
1112
+ this.lastFailureReason = reply.failure ?? null;
1113
+ if (reply.loaded && reply.stats) {
1114
+ loadedLocalEmbeddingRuntimes.set(this.memoryStatsId, {
1115
+ model: this.model,
1116
+ runtime: reply.stats.runtimes[0] ?? "wasm",
1117
+ rssDeltaAtLoad: reply.stats.rssDeltaAtLoad,
1118
+ externalDeltaAtLoad: reply.stats.externalDeltaAtLoad,
1119
+ arrayBuffersDeltaAtLoad: reply.stats.arrayBuffersDeltaAtLoad
1120
+ });
1121
+ } else
1122
+ loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
1123
+ }
1124
+ recordWorkerFailure(error) {
1125
+ loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
1126
+ this.workerLoaded = false;
1127
+ this.lastFailureReason = classifyLocalEmbeddingFailure(error);
1128
+ logForRuntime("[magic-context] embedding worker failed:", error);
1129
+ }
1130
+ async dispose() {
1131
+ if (this.workerClient) {
1132
+ this.disposing = true;
1133
+ this.workerLoaded = false;
1134
+ loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
1135
+ await this.workerClient.dispose();
1136
+ return;
1137
+ }
1138
+ if (this.disposePromise) {
1139
+ return this.disposePromise;
1140
+ }
1141
+ this.disposing = true;
1142
+ this.disposePromise = (async () => {
1143
+ if (this.initPromise) {
1144
+ await this.initPromise;
1145
+ }
1146
+ await this.waitForInFlightToDrain();
1147
+ const pipelineToDispose = this.pipeline;
1148
+ this.pipeline = null;
1149
+ this.initPromise = null;
1150
+ loadedLocalEmbeddingRuntimes.delete(this.memoryStatsId);
1151
+ if (!pipelineToDispose) {
1152
+ return;
1153
+ }
1154
+ try {
1155
+ await pipelineToDispose.dispose?.();
1156
+ } catch (error) {
1157
+ log2("[magic-context] embedding model dispose failed:", error);
1158
+ }
1159
+ })();
1160
+ return this.disposePromise;
1161
+ }
1162
+ isLoaded() {
1163
+ return this.workerClient ? this.workerLoaded && this.workerClient.isRunning() : this.pipeline !== null;
1164
+ }
1165
+ getLastFailureReason() {
1166
+ return this.lastFailureReason;
1167
+ }
1168
+ }
1169
+
1170
+ export { embeddingModelsMatch, resolveEmbeddingTextPrefixes, getEmbeddingProviderIdentity, dominantEmbeddingFailure, resolveLocalEmbeddingWorkerRuntime, getLocalEmbeddingNativeMemoryStats, LocalEmbeddingProvider };