@remnic/core 9.3.562 → 9.3.564

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 (156) hide show
  1. package/dist/access-cli.js +40 -39
  2. package/dist/access-cli.js.map +1 -1
  3. package/dist/access-http.js +16 -16
  4. package/dist/access-mcp.js +13 -13
  5. package/dist/access-schema.js +3 -3
  6. package/dist/access-service.js +11 -11
  7. package/dist/active-recall.js +1 -1
  8. package/dist/adapters/index.js +4 -4
  9. package/dist/adapters/registry.js +2 -2
  10. package/dist/briefing.js +4 -4
  11. package/dist/causal-consolidation.js +5 -5
  12. package/dist/{chunk-I2K6KCVC.js → chunk-2FHLI4U6.js} +49 -49
  13. package/dist/chunk-3ONXXHQO.js +57 -0
  14. package/dist/chunk-3ONXXHQO.js.map +1 -0
  15. package/dist/{chunk-5GX5MUQ2.js → chunk-574MU2Y3.js} +3 -3
  16. package/dist/{chunk-65OLPXBU.js → chunk-5WB4C7KM.js} +6 -6
  17. package/dist/chunk-6PTSXBPE.js +483 -0
  18. package/dist/chunk-6PTSXBPE.js.map +1 -0
  19. package/dist/{chunk-Z56KAZQL.js → chunk-74VA26CT.js} +2 -2
  20. package/dist/{chunk-CC2ESOOG.js → chunk-7X7TBJRX.js} +2 -2
  21. package/dist/{chunk-O4M4WH6V.js → chunk-ARY5OOLG.js} +2 -2
  22. package/dist/{chunk-JBPKEARU.js → chunk-AU7Q3LSC.js} +4 -4
  23. package/dist/{chunk-PM3QHTFT.js → chunk-CF3ZF2YU.js} +3 -3
  24. package/dist/{chunk-SI3QCHWF.js → chunk-DARLGSFX.js} +5 -5
  25. package/dist/chunk-EWLQPEO6.js +308 -0
  26. package/dist/chunk-EWLQPEO6.js.map +1 -0
  27. package/dist/{chunk-FVCZINOF.js → chunk-FHBEL473.js} +2 -2
  28. package/dist/{chunk-7Q3RCKAQ.js → chunk-FXKPZ3H6.js} +2 -2
  29. package/dist/{chunk-5WLYNZPC.js → chunk-GBXGCFRH.js} +2 -2
  30. package/dist/{chunk-ILJXM3FV.js → chunk-HQO5EBUC.js} +10 -10
  31. package/dist/{chunk-FK556DDH.js → chunk-I4UNL747.js} +4 -4
  32. package/dist/{chunk-RLPIT4YI.js → chunk-IOTTZLFF.js} +38 -38
  33. package/dist/{chunk-TVZ6LKKS.js → chunk-IRFF6LSF.js} +8 -8
  34. package/dist/{chunk-M5T4Q2ZU.js → chunk-KGK2QKWL.js} +1 -1
  35. package/dist/chunk-KGK2QKWL.js.map +1 -0
  36. package/dist/{chunk-IPLYGWQF.js → chunk-KQAFEZQX.js} +5 -5
  37. package/dist/chunk-M46RYSMW.js +597 -0
  38. package/dist/chunk-M46RYSMW.js.map +1 -0
  39. package/dist/{chunk-KXULCVOC.js → chunk-M6I5Z4SR.js} +4 -2
  40. package/dist/chunk-M6I5Z4SR.js.map +1 -0
  41. package/dist/{chunk-JFN6K74Q.js → chunk-MQEIWDYW.js} +2 -2
  42. package/dist/{chunk-7H6CFEBJ.js → chunk-NZPF2SYV.js} +8 -1
  43. package/dist/{chunk-7H6CFEBJ.js.map → chunk-NZPF2SYV.js.map} +1 -1
  44. package/dist/{chunk-SML26KED.js → chunk-OB6353F7.js} +16 -12
  45. package/dist/chunk-OB6353F7.js.map +1 -0
  46. package/dist/{chunk-SOTR74FK.js → chunk-OPYFD6PD.js} +2 -2
  47. package/dist/{chunk-3C5RPJAX.js → chunk-OXJBNGBK.js} +2 -2
  48. package/dist/{chunk-BD5LHQWD.js → chunk-PPPZY2EU.js} +2 -2
  49. package/dist/{chunk-25BY3HHZ.js → chunk-SUTSSOYU.js} +2 -2
  50. package/dist/{chunk-KS7WO6EQ.js → chunk-VFB2G5YL.js} +20 -20
  51. package/dist/{chunk-BUUYY2H2.js → chunk-WP5OWVLZ.js} +4 -4
  52. package/dist/{chunk-6URPAY2D.js → chunk-XCAZF7KQ.js} +207 -53
  53. package/dist/chunk-XCAZF7KQ.js.map +1 -0
  54. package/dist/{chunk-S53PAX2V.js → chunk-XM7BYXT7.js} +2 -2
  55. package/dist/{chunk-FADZBOR4.js → chunk-XRWTAEZM.js} +2 -2
  56. package/dist/{chunk-E5OECWZ5.js → chunk-XT7XVA53.js} +2 -2
  57. package/dist/{chunk-R3PS27B4.js → chunk-Z4R6RI2N.js} +2 -2
  58. package/dist/cli.js +44 -43
  59. package/dist/compounding/engine.js +4 -4
  60. package/dist/config.js +1 -1
  61. package/dist/connectors/codex-materialize-runner.js +4 -4
  62. package/dist/connectors/index.js +4 -4
  63. package/dist/embedding-fallback.d.ts +12 -1
  64. package/dist/embedding-fallback.js +4 -1
  65. package/dist/entity-retrieval.js +4 -4
  66. package/dist/host-embedding-provider.d.ts +21 -0
  67. package/dist/host-embedding-provider.js +14 -0
  68. package/dist/host-embedding-provider.js.map +1 -0
  69. package/dist/index.d.ts +1 -0
  70. package/dist/index.js +71 -63
  71. package/dist/index.js.map +1 -1
  72. package/dist/lcm/index.js +3 -3
  73. package/dist/maintenance/memory-governance.js +4 -4
  74. package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +4 -4
  75. package/dist/maintenance/rebuild-memory-projection.js +5 -5
  76. package/dist/namespaces/migrate.js +14 -13
  77. package/dist/namespaces/search.js +9 -8
  78. package/dist/namespaces/storage.js +4 -4
  79. package/dist/operator-toolkit.js +17 -16
  80. package/dist/orchestrator.js +32 -31
  81. package/dist/recall-explain-renderer.js +3 -3
  82. package/dist/recall-xray-cli.js +4 -4
  83. package/dist/recall-xray-renderer.js +3 -3
  84. package/dist/recall-xray.js +2 -2
  85. package/dist/resume-bundles.js +2 -2
  86. package/dist/search/embed-helper.d.ts +48 -4
  87. package/dist/search/embed-helper.js +2 -1
  88. package/dist/search/factory.js +8 -7
  89. package/dist/search/index.d.ts +1 -0
  90. package/dist/search/index.js +12 -11
  91. package/dist/search/lancedb-backend.d.ts +11 -0
  92. package/dist/search/lancedb-backend.js +2 -2
  93. package/dist/search/meilisearch-backend.js +2 -2
  94. package/dist/search/orama-backend.d.ts +16 -0
  95. package/dist/search/orama-backend.js +2 -2
  96. package/dist/semantic-consolidation.js +5 -5
  97. package/dist/semantic-rule-promotion.js +4 -4
  98. package/dist/semantic-rule-verifier.js +4 -4
  99. package/dist/storage.js +3 -3
  100. package/dist/transfer/autodetect.js +1 -1
  101. package/dist/transfer/backup.js +1 -1
  102. package/dist/transfer/capsule-export.js +2 -2
  103. package/dist/transfer/types.d.ts +6 -6
  104. package/dist/types.d.ts +17 -0
  105. package/dist/types.js +1 -1
  106. package/dist/verified-recall.js +4 -4
  107. package/package.json +11 -1
  108. package/src/config.ts +18 -0
  109. package/src/embedding-fallback.ts +293 -61
  110. package/src/host-embedding-provider.ts +84 -0
  111. package/src/index.ts +7 -0
  112. package/src/namespaces/search.ts +9 -1
  113. package/src/qmd.test.ts +28 -0
  114. package/src/search/embed-helper.ts +319 -51
  115. package/src/search/factory.ts +6 -2
  116. package/src/search/lancedb-backend.ts +297 -41
  117. package/src/search/orama-backend.ts +418 -47
  118. package/src/types.ts +17 -0
  119. package/dist/chunk-6URPAY2D.js.map +0 -1
  120. package/dist/chunk-FUC4LZMD.js +0 -301
  121. package/dist/chunk-FUC4LZMD.js.map +0 -1
  122. package/dist/chunk-KXULCVOC.js.map +0 -1
  123. package/dist/chunk-M5T4Q2ZU.js.map +0 -1
  124. package/dist/chunk-ONPLNAPX.js +0 -133
  125. package/dist/chunk-ONPLNAPX.js.map +0 -1
  126. package/dist/chunk-QVJ4NWL2.js +0 -335
  127. package/dist/chunk-QVJ4NWL2.js.map +0 -1
  128. package/dist/chunk-SML26KED.js.map +0 -1
  129. /package/dist/{chunk-I2K6KCVC.js.map → chunk-2FHLI4U6.js.map} +0 -0
  130. /package/dist/{chunk-5GX5MUQ2.js.map → chunk-574MU2Y3.js.map} +0 -0
  131. /package/dist/{chunk-65OLPXBU.js.map → chunk-5WB4C7KM.js.map} +0 -0
  132. /package/dist/{chunk-Z56KAZQL.js.map → chunk-74VA26CT.js.map} +0 -0
  133. /package/dist/{chunk-CC2ESOOG.js.map → chunk-7X7TBJRX.js.map} +0 -0
  134. /package/dist/{chunk-O4M4WH6V.js.map → chunk-ARY5OOLG.js.map} +0 -0
  135. /package/dist/{chunk-JBPKEARU.js.map → chunk-AU7Q3LSC.js.map} +0 -0
  136. /package/dist/{chunk-PM3QHTFT.js.map → chunk-CF3ZF2YU.js.map} +0 -0
  137. /package/dist/{chunk-SI3QCHWF.js.map → chunk-DARLGSFX.js.map} +0 -0
  138. /package/dist/{chunk-FVCZINOF.js.map → chunk-FHBEL473.js.map} +0 -0
  139. /package/dist/{chunk-7Q3RCKAQ.js.map → chunk-FXKPZ3H6.js.map} +0 -0
  140. /package/dist/{chunk-5WLYNZPC.js.map → chunk-GBXGCFRH.js.map} +0 -0
  141. /package/dist/{chunk-ILJXM3FV.js.map → chunk-HQO5EBUC.js.map} +0 -0
  142. /package/dist/{chunk-FK556DDH.js.map → chunk-I4UNL747.js.map} +0 -0
  143. /package/dist/{chunk-RLPIT4YI.js.map → chunk-IOTTZLFF.js.map} +0 -0
  144. /package/dist/{chunk-TVZ6LKKS.js.map → chunk-IRFF6LSF.js.map} +0 -0
  145. /package/dist/{chunk-IPLYGWQF.js.map → chunk-KQAFEZQX.js.map} +0 -0
  146. /package/dist/{chunk-JFN6K74Q.js.map → chunk-MQEIWDYW.js.map} +0 -0
  147. /package/dist/{chunk-SOTR74FK.js.map → chunk-OPYFD6PD.js.map} +0 -0
  148. /package/dist/{chunk-3C5RPJAX.js.map → chunk-OXJBNGBK.js.map} +0 -0
  149. /package/dist/{chunk-BD5LHQWD.js.map → chunk-PPPZY2EU.js.map} +0 -0
  150. /package/dist/{chunk-25BY3HHZ.js.map → chunk-SUTSSOYU.js.map} +0 -0
  151. /package/dist/{chunk-KS7WO6EQ.js.map → chunk-VFB2G5YL.js.map} +0 -0
  152. /package/dist/{chunk-BUUYY2H2.js.map → chunk-WP5OWVLZ.js.map} +0 -0
  153. /package/dist/{chunk-S53PAX2V.js.map → chunk-XM7BYXT7.js.map} +0 -0
  154. /package/dist/{chunk-FADZBOR4.js.map → chunk-XRWTAEZM.js.map} +0 -0
  155. /package/dist/{chunk-E5OECWZ5.js.map → chunk-XT7XVA53.js.map} +0 -0
  156. /package/dist/{chunk-R3PS27B4.js.map → chunk-Z4R6RI2N.js.map} +0 -0
@@ -1,21 +1,21 @@
1
+ import {
2
+ RemoteSearchBackend
3
+ } from "./chunk-JNANKJLN.js";
4
+ import {
5
+ EmbedHelper
6
+ } from "./chunk-EWLQPEO6.js";
1
7
  import {
2
8
  LanceDbBackend
3
- } from "./chunk-FUC4LZMD.js";
9
+ } from "./chunk-6PTSXBPE.js";
4
10
  import {
5
11
  MeilisearchBackend
6
- } from "./chunk-FK556DDH.js";
12
+ } from "./chunk-I4UNL747.js";
7
13
  import {
8
14
  NoopSearchBackend
9
15
  } from "./chunk-2I5JGH3M.js";
10
16
  import {
11
17
  OramaBackend
12
- } from "./chunk-QVJ4NWL2.js";
13
- import {
14
- RemoteSearchBackend
15
- } from "./chunk-JNANKJLN.js";
16
- import {
17
- EmbedHelper
18
- } from "./chunk-ONPLNAPX.js";
18
+ } from "./chunk-M46RYSMW.js";
19
19
  import {
20
20
  createConversationIndexBackend
21
21
  } from "./chunk-KIB7SDIJ.js";
@@ -49,7 +49,9 @@ function resolveNonQmdBackend(config) {
49
49
  });
50
50
  }
51
51
  if (backend === "lancedb") {
52
- const embedHelper = new EmbedHelper(config);
52
+ const embedHelper = new EmbedHelper(config, {
53
+ hostEmbeddingExpectedDimension: config.lanceEmbeddingDimension
54
+ });
53
55
  return new LanceDbBackend({
54
56
  dbPath: config.lanceDbPath,
55
57
  collection,
@@ -69,7 +71,9 @@ function resolveNonQmdBackend(config) {
69
71
  });
70
72
  }
71
73
  if (backend === "orama") {
72
- const embedHelper = new EmbedHelper(config);
74
+ const embedHelper = new EmbedHelper(config, {
75
+ hostEmbeddingExpectedDimension: config.oramaEmbeddingDimension
76
+ });
73
77
  return new OramaBackend({
74
78
  dbPath: config.oramaDbPath,
75
79
  collection,
@@ -163,4 +167,4 @@ export {
163
167
  createConversationSearchBackend,
164
168
  createConversationIndexRuntime
165
169
  };
166
- //# sourceMappingURL=chunk-SML26KED.js.map
170
+ //# sourceMappingURL=chunk-OB6353F7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/search/factory.ts"],"sourcesContent":["import type { PluginConfig } from \"../types.js\";\nimport type { SearchBackend } from \"./port.js\";\nimport path from \"node:path\";\nimport { NoopSearchBackend } from \"./noop-backend.js\";\nimport { RemoteSearchBackend } from \"./remote-backend.js\";\nimport { LanceDbBackend } from \"./lancedb-backend.js\";\nimport { MeilisearchBackend } from \"./meilisearch-backend.js\";\nimport { OramaBackend } from \"./orama-backend.js\";\nimport { EmbedHelper } from \"./embed-helper.js\";\nimport { QmdClient, type QmdClientOptions } from \"../qmd.js\";\nimport { log } from \"../logger.js\";\nimport { FaissConversationIndexAdapter } from \"../conversation-index/faiss-adapter.js\";\nimport {\n createConversationIndexBackend,\n type ConversationIndexBackend,\n type ConversationQmdRuntime,\n} from \"../conversation-index/backend.js\";\n\n/**\n * Resolve non-QMD backends from config.\n * Returns a SearchBackend for \"noop\" or \"remote\", or undefined to signal \"use QMD\".\n */\nfunction resolveNonQmdBackend(config: PluginConfig): SearchBackend | undefined {\n const backend = config.searchBackend ?? \"qmd\";\n const collection = config.qmdCollection;\n\n if (backend === \"noop\") {\n return new NoopSearchBackend();\n }\n\n if (backend === \"remote\") {\n const baseUrl = config.remoteSearchBaseUrl || \"http://localhost:8181\";\n if (!config.remoteSearchBaseUrl) {\n log.warn(\"searchBackend is 'remote' but remoteSearchBaseUrl is not configured; using default http://localhost:8181\");\n }\n return new RemoteSearchBackend({\n baseUrl,\n apiKey: config.remoteSearchApiKey,\n timeoutMs: config.remoteSearchTimeoutMs,\n });\n }\n\n if (backend === \"lancedb\") {\n const embedHelper = new EmbedHelper(config, {\n hostEmbeddingExpectedDimension: config.lanceEmbeddingDimension,\n });\n return new LanceDbBackend({\n dbPath: config.lanceDbPath!,\n collection,\n embedHelper,\n memoryDir: config.memoryDir,\n embeddingDimension: config.lanceEmbeddingDimension!,\n });\n }\n\n if (backend === \"meilisearch\") {\n return new MeilisearchBackend({\n host: config.meilisearchHost!,\n apiKey: config.meilisearchApiKey,\n collection,\n timeoutMs: config.meilisearchTimeoutMs,\n autoIndex: config.meilisearchAutoIndex,\n memoryDir: config.memoryDir,\n });\n }\n\n if (backend === \"orama\") {\n const embedHelper = new EmbedHelper(config, {\n hostEmbeddingExpectedDimension: config.oramaEmbeddingDimension,\n });\n return new OramaBackend({\n dbPath: config.oramaDbPath!,\n collection,\n embedHelper,\n memoryDir: config.memoryDir,\n embeddingDimension: config.oramaEmbeddingDimension!,\n });\n }\n\n return undefined;\n}\n\n/** Shared QMD options derived from plugin config. */\nfunction qmdOptions(config: PluginConfig): QmdClientOptions {\n return {\n slowLog: {\n enabled: config.slowLogEnabled,\n thresholdMs: config.slowLogThresholdMs,\n },\n updateTimeoutMs: config.qmdUpdateTimeoutMs,\n updateMinIntervalMs: config.qmdUpdateMinIntervalMs,\n qmdPath: config.qmdPath,\n daemonUrl: config.qmdDaemonEnabled ? config.qmdDaemonUrl : undefined,\n daemonRecheckIntervalMs: config.qmdDaemonRecheckIntervalMs,\n qmdSupportedVersion: config.qmdSupportedVersion,\n qmdAutoUpgradeEnabled: config.qmdAutoUpgradeEnabled,\n qmdAutoUpgradeCheckIntervalMs: config.qmdAutoUpgradeCheckIntervalMs,\n qmdChunkStrategy: config.qmdChunkStrategy,\n qmdCandidateLimit: config.qmdCandidateLimit,\n qmdQueryRerankEnabled: config.qmdQueryRerankEnabled,\n qmdIndexName: config.qmdIndexName,\n qmdForceCpu: config.qmdForceCpu,\n qmdGpuBackend: config.qmdGpuBackend,\n qmdEmbedParallelism: config.qmdEmbedParallelism,\n qmdEmbedModel: config.qmdEmbedModel,\n qmdRerankModel: config.qmdRerankModel,\n qmdGenerateModel: config.qmdGenerateModel,\n };\n}\n\n/**\n * Create a SearchBackend from plugin config.\n *\n * - \"noop\" → NoopSearchBackend\n * - \"remote\" → RemoteSearchBackend (HTTP REST)\n * - \"qmd\" (default) → QmdClient if qmdEnabled, else NoopSearchBackend\n */\nexport function createSearchBackend(config: PluginConfig): SearchBackend {\n const nonQmd = resolveNonQmdBackend(config);\n if (nonQmd) return nonQmd;\n\n // Default: QMD — fall back to noop if qmdEnabled is false\n if (!config.qmdEnabled) {\n return new NoopSearchBackend();\n }\n\n return new QmdClient(config.qmdCollection, config.qmdMaxResults, qmdOptions(config));\n}\n\n/**\n * Create a SearchBackend for conversation index use.\n * Returns undefined if conversation index is not enabled or not using qmd backend.\n */\nexport function createConversationSearchBackend(config: PluginConfig): SearchBackend | undefined {\n if (!config.conversationIndexEnabled || config.conversationIndexBackend !== \"qmd\") {\n return undefined;\n }\n\n // Conversation index is QMD-only — do not use lancedb/meilisearch/orama even if\n // searchBackend is set to one of those. Only respect \"noop\" to allow disabling.\n const backend = config.searchBackend ?? \"qmd\";\n if (backend === \"noop\") return undefined;\n\n // QMD — respect qmdEnabled to avoid spawning the binary\n if (!config.qmdEnabled) return undefined;\n\n return new QmdClient(\n config.conversationIndexQmdCollection,\n Math.max(6, config.conversationRecallTopK),\n qmdOptions(config),\n );\n}\n\nexport interface ConversationIndexRuntime {\n qmd?: ConversationQmdRuntime;\n faiss?: FaissConversationIndexAdapter;\n backend?: ConversationIndexBackend;\n}\n\nexport function createConversationIndexRuntime(\n config: PluginConfig,\n overrides?: {\n getQmd?: () => ConversationQmdRuntime | undefined;\n getFaiss?: () => FaissConversationIndexAdapter | undefined;\n },\n): ConversationIndexRuntime {\n const qmd = createConversationSearchBackend(config) as ConversationQmdRuntime | undefined;\n let faiss: FaissConversationIndexAdapter | undefined;\n if (config.conversationIndexEnabled && config.conversationIndexBackend === \"faiss\") {\n try {\n faiss = new FaissConversationIndexAdapter({\n memoryDir: config.memoryDir,\n scriptPath: config.conversationIndexFaissScriptPath,\n pythonBin: config.conversationIndexFaissPythonBin,\n modelId: config.conversationIndexFaissModelId,\n indexDir: config.conversationIndexFaissIndexDir,\n upsertTimeoutMs: config.conversationIndexFaissUpsertTimeoutMs,\n searchTimeoutMs: config.conversationIndexFaissSearchTimeoutMs,\n healthTimeoutMs: config.conversationIndexFaissHealthTimeoutMs,\n maxBatchSize: config.conversationIndexFaissMaxBatchSize,\n maxSearchK: config.conversationIndexFaissMaxSearchK,\n });\n } catch (err) {\n log.warn(`Conversation index FAISS adapter disabled: ${err instanceof Error ? err.message : String(err)}`);\n }\n }\n\n const backend = createConversationIndexBackend({\n enabled: config.conversationIndexEnabled,\n backend: config.conversationIndexBackend,\n getQmd: () => overrides?.getQmd?.() ?? qmd,\n getFaiss: () => overrides?.getFaiss?.() ?? faiss,\n collectionDir: path.join(config.memoryDir, \"conversation-index\"),\n });\n\n return { qmd, faiss, backend };\n}\n"],"mappings":"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","names":[]}
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-ZFXCQPNO.js";
5
5
  import {
6
6
  StorageManager
7
- } from "./chunk-TVZ6LKKS.js";
7
+ } from "./chunk-IRFF6LSF.js";
8
8
  import {
9
9
  isSafeRouteNamespace
10
10
  } from "./chunk-U3PN77QT.js";
@@ -156,4 +156,4 @@ export {
156
156
  getCategoryDir,
157
157
  NamespaceStorageRouter
158
158
  };
159
- //# sourceMappingURL=chunk-SOTR74FK.js.map
159
+ //# sourceMappingURL=chunk-OPYFD6PD.js.map
@@ -3,7 +3,7 @@ import {
3
3
  } from "./chunk-SOBJ6NEY.js";
4
4
  import {
5
5
  summarizeDisclosureTokens
6
- } from "./chunk-7Q3RCKAQ.js";
6
+ } from "./chunk-FXKPZ3H6.js";
7
7
  import {
8
8
  summarizeRetrievedMemoryProvenance
9
9
  } from "./chunk-AC5LO7IU.js";
@@ -567,4 +567,4 @@ export {
567
567
  renderRecallExplain,
568
568
  parseRecallExplainFormat
569
569
  };
570
- //# sourceMappingURL=chunk-3C5RPJAX.js.map
570
+ //# sourceMappingURL=chunk-OXJBNGBK.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isValidCapsuleSince
3
- } from "./chunk-IPLYGWQF.js";
3
+ } from "./chunk-KQAFEZQX.js";
4
4
  import {
5
5
  CAPSULE_ID_PATTERN
6
6
  } from "./chunk-WEHSQBFR.js";
@@ -417,4 +417,4 @@ export {
417
417
  actionConfidenceRequestSchema,
418
418
  validateRequest
419
419
  };
420
- //# sourceMappingURL=chunk-BD5LHQWD.js.map
420
+ //# sourceMappingURL=chunk-PPPZY2EU.js.map
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-DRD2Q7HQ.js";
5
5
  import {
6
6
  StorageManager
7
- } from "./chunk-TVZ6LKKS.js";
7
+ } from "./chunk-IRFF6LSF.js";
8
8
  import {
9
9
  parseContinuityImprovementLoops
10
10
  } from "./chunk-QSVPYQPG.js";
@@ -1259,4 +1259,4 @@ export {
1259
1259
  defaultTierMigrationCycleBudget,
1260
1260
  CompoundingEngine
1261
1261
  };
1262
- //# sourceMappingURL=chunk-25BY3HHZ.js.map
1262
+ //# sourceMappingURL=chunk-SUTSSOYU.js.map
@@ -14,12 +14,20 @@ import {
14
14
  normalizeTags,
15
15
  parseTagMatch
16
16
  } from "./chunk-BT7NVCML.js";
17
+ import {
18
+ toRecallExplainJson
19
+ } from "./chunk-OXJBNGBK.js";
17
20
  import {
18
21
  decideDisclosureEscalation
19
22
  } from "./chunk-H7XKCNR6.js";
20
23
  import {
21
- toRecallExplainJson
22
- } from "./chunk-3C5RPJAX.js";
24
+ buildProposedActions,
25
+ buildQualityScore,
26
+ groupActionsByStatus,
27
+ listMemoryGovernanceRuns,
28
+ readMemoryGovernanceRunArtifact,
29
+ runMemoryGovernance
30
+ } from "./chunk-XT7XVA53.js";
23
31
  import {
24
32
  clusterByKey,
25
33
  projectTagProjectId,
@@ -36,21 +44,13 @@ import {
36
44
  } from "./chunk-472U7RDF.js";
37
45
  import {
38
46
  estimateRecallTokens
39
- } from "./chunk-7Q3RCKAQ.js";
47
+ } from "./chunk-FXKPZ3H6.js";
40
48
  import {
41
49
  recordObjectiveStateSnapshotsFromObservedMessages
42
50
  } from "./chunk-WSGF57U2.js";
43
51
  import {
44
52
  objectiveStateStoreOverrideForNamespace
45
53
  } from "./chunk-UEY3VB6W.js";
46
- import {
47
- buildProposedActions,
48
- buildQualityScore,
49
- groupActionsByStatus,
50
- listMemoryGovernanceRuns,
51
- readMemoryGovernanceRunArtifact,
52
- runMemoryGovernance
53
- } from "./chunk-E5OECWZ5.js";
54
54
  import {
55
55
  recordMemoryOutcome
56
56
  } from "./chunk-EIR5VLIH.js";
@@ -80,14 +80,18 @@ import {
80
80
  buildBriefing,
81
81
  parseBriefingFocus,
82
82
  parseBriefingWindow
83
- } from "./chunk-JFN6K74Q.js";
83
+ } from "./chunk-MQEIWDYW.js";
84
84
  import {
85
85
  parseEntityFile
86
- } from "./chunk-TVZ6LKKS.js";
86
+ } from "./chunk-IRFF6LSF.js";
87
87
  import {
88
88
  DEFAULT_RECALL_DISCLOSURE,
89
89
  isRecallDisclosure
90
- } from "./chunk-M5T4Q2ZU.js";
90
+ } from "./chunk-KGK2QKWL.js";
91
+ import {
92
+ inferMemoryStatus,
93
+ toMemoryPathRel
94
+ } from "./chunk-RULE4VG5.js";
91
95
  import {
92
96
  normalizeProjectionPreview,
93
97
  normalizeProjectionTags
@@ -95,10 +99,6 @@ import {
95
99
  import {
96
100
  getMemoryProjectionPath
97
101
  } from "./chunk-KILOTVIF.js";
98
- import {
99
- inferMemoryStatus,
100
- toMemoryPathRel
101
- } from "./chunk-RULE4VG5.js";
102
102
  import {
103
103
  defaultCapsulesDir
104
104
  } from "./chunk-ZY2MNJR6.js";
@@ -125,7 +125,7 @@ import {
125
125
  } from "./chunk-VFUEZZBS.js";
126
126
  import {
127
127
  exportCapsule
128
- } from "./chunk-IPLYGWQF.js";
128
+ } from "./chunk-KQAFEZQX.js";
129
129
  import {
130
130
  OFFLINE_SYNC_SNAPSHOT_FORMAT,
131
131
  applyOfflineSyncChangeset,
@@ -4238,4 +4238,4 @@ export {
4238
4238
  shapeMemorySummary,
4239
4239
  EngramAccessService
4240
4240
  };
4241
- //# sourceMappingURL=chunk-KS7WO6EQ.js.map
4241
+ //# sourceMappingURL=chunk-VFB2G5YL.js.map
@@ -11,13 +11,13 @@ import {
11
11
  } from "./chunk-D24OXEPB.js";
12
12
  import {
13
13
  EngramAccessInputError
14
- } from "./chunk-KS7WO6EQ.js";
14
+ } from "./chunk-VFB2G5YL.js";
15
15
  import {
16
16
  projectTagProjectId
17
17
  } from "./chunk-EDQVAMQI.js";
18
18
  import {
19
19
  validateBriefingFormat
20
- } from "./chunk-JFN6K74Q.js";
20
+ } from "./chunk-MQEIWDYW.js";
21
21
  import {
22
22
  expandTildePath
23
23
  } from "./chunk-EYIEWJNI.js";
@@ -26,7 +26,7 @@ import {
26
26
  } from "./chunk-JUC24CTX.js";
27
27
  import {
28
28
  validateRequest
29
- } from "./chunk-BD5LHQWD.js";
29
+ } from "./chunk-PPPZY2EU.js";
30
30
 
31
31
  // src/access-mcp.ts
32
32
  import { readFile } from "fs/promises";
@@ -2860,4 +2860,4 @@ ${body}`;
2860
2860
  export {
2861
2861
  EngramMcpServer
2862
2862
  };
2863
- //# sourceMappingURL=chunk-BUUYY2H2.js.map
2863
+ //# sourceMappingURL=chunk-WP5OWVLZ.js.map
@@ -1,3 +1,7 @@
1
+ import {
2
+ getHostEmbeddingProvider,
3
+ normalizeHostEmbeddingVector
4
+ } from "./chunk-3ONXXHQO.js";
1
5
  import {
2
6
  readEnvVar
3
7
  } from "./chunk-JUC24CTX.js";
@@ -15,6 +19,15 @@ var EmbeddingTimeoutError = class extends Error {
15
19
  super(message);
16
20
  }
17
21
  };
22
+ var EmbeddingProviderUnavailableError = class extends Error {
23
+ name = "EmbeddingProviderUnavailableError";
24
+ constructor(message) {
25
+ super(message);
26
+ }
27
+ };
28
+ function isLookupBackendUnavailableError(err) {
29
+ return err instanceof EmbeddingTimeoutError || err instanceof EmbeddingProviderUnavailableError;
30
+ }
18
31
  var DEFAULT_EMBEDDING_LOOKUP_TIMEOUT_MS = 5e3;
19
32
  var DEFAULT_EMBEDDING_INDEX_TIMEOUT_MS = 12e4;
20
33
  function resolveEmbeddingLookupTimeoutMs() {
@@ -109,23 +122,31 @@ var EmbeddingFallback = class {
109
122
  async search(query, limit, options = {}) {
110
123
  const provider = await this.resolveProvider();
111
124
  if (!provider) return [];
112
- const index = await this.loadIndex(provider);
113
- const ids = Object.keys(index.entries);
114
- if (ids.length === 0) return [];
115
- let queryVector;
116
- try {
117
- queryVector = await this.embed(query, provider, { mode: "lookup" });
118
- } catch (err) {
119
- if (err instanceof EmbeddingTimeoutError) {
120
- if (options.throwOnTimeout) {
121
- throw err;
125
+ let queryResult = await this.embedForSearch(query, provider, options);
126
+ if (!queryResult) return [];
127
+ const diskIdentity = await this.readIndexIdentityFromDisk();
128
+ if (diskIdentity && !sameIndexIdentity(diskIdentity, queryResult.provider)) {
129
+ const diskProvider = await this.resolveFallbackProviderForIndexIdentity(diskIdentity);
130
+ if (diskProvider) {
131
+ const diskQueryResult = await this.embedForSearch(query, diskProvider, options);
132
+ if (diskQueryResult && sameIndexIdentity(diskIdentity, diskQueryResult.provider)) {
133
+ queryResult = diskQueryResult;
134
+ } else {
135
+ log.debug(
136
+ `embedding fallback search skipped: preserved ${diskIdentity.provider}/${diskIdentity.model} index is unavailable for lookup`
137
+ );
138
+ return [];
122
139
  }
123
- log.debug("embedding fallback search: timeout on lookup, returning [] (throwOnTimeout=false)");
140
+ } else {
141
+ log.debug(
142
+ `embedding fallback search skipped: query provider ${queryResult.provider.type}/${queryResult.provider.model} does not match existing ${diskIdentity.provider}/${diskIdentity.model} index`
143
+ );
124
144
  return [];
125
145
  }
126
- throw err;
127
146
  }
128
- if (!queryVector) return [];
147
+ const index = await this.loadIndex(queryResult.provider);
148
+ const ids = Object.keys(index.entries);
149
+ if (ids.length === 0) return [];
129
150
  const includePrefix = normalizePathPrefix(options.pathPrefix);
130
151
  const excludePrefixes = (options.pathExcludePrefixes ?? []).map((p) => normalizePathPrefix(p)).filter((p) => typeof p === "string");
131
152
  const scored = ids.map((id) => {
@@ -133,7 +154,7 @@ var EmbeddingFallback = class {
133
154
  return {
134
155
  id,
135
156
  path: entry.path,
136
- score: cosineSimilarity(queryVector, entry.vector)
157
+ score: cosineSimilarity(queryResult.vector, entry.vector)
137
158
  };
138
159
  }).filter((r) => {
139
160
  if (!Number.isFinite(r.score)) return false;
@@ -151,13 +172,22 @@ var EmbeddingFallback = class {
151
172
  async indexFile(memoryId, content, filePath) {
152
173
  const provider = await this.resolveProvider();
153
174
  if (!provider) return;
154
- const vector = await this.embed(content, provider, { mode: "index" });
155
- if (!vector) return;
175
+ const result = await this.embedWithEffectiveProvider(content, provider, {
176
+ mode: "index"
177
+ });
178
+ if (!result) return;
156
179
  await this.enqueueIndexMutation(async () => {
157
- const index = await this.loadIndex(provider);
180
+ const existing = await this.readIndexIdentityFromDisk();
181
+ if (existing && !sameIndexIdentity(existing, result.provider) && !canReplaceIndexIdentity(existing, result.provider)) {
182
+ log.debug(
183
+ `embedding fallback index update skipped: ${result.provider.type}/${result.provider.model} would replace existing ${existing.provider}/${existing.model} index`
184
+ );
185
+ return;
186
+ }
187
+ const index = await this.loadIndex(result.provider);
158
188
  const relPath = toMemoryRelativePath(this.config.memoryDir, filePath);
159
189
  index.entries[memoryId] = {
160
- vector,
190
+ vector: result.vector,
161
191
  path: relPath
162
192
  };
163
193
  await this.saveIndex(index);
@@ -167,10 +197,23 @@ var EmbeddingFallback = class {
167
197
  const provider = await this.resolveProvider();
168
198
  if (!provider) return;
169
199
  await this.enqueueIndexMutation(async () => {
170
- const index = await this.loadIndex(provider);
171
- if (!index.entries[memoryId]) return;
172
- delete index.entries[memoryId];
173
- await this.saveIndex(index);
200
+ const providers = [provider];
201
+ const diskIdentity = await this.readIndexIdentityFromDisk();
202
+ if (diskIdentity && !providers.some((entry) => sameIndexIdentity(entry, diskIdentity))) {
203
+ providers.push(providerFromIndexIdentity(diskIdentity));
204
+ }
205
+ if (provider.type === "host") {
206
+ const fallbackProvider = await this.resolveProvider({ includeHost: false });
207
+ if (fallbackProvider && !providers.some((entry) => sameIndexIdentity(entry, fallbackProvider))) {
208
+ providers.push(fallbackProvider);
209
+ }
210
+ }
211
+ for (const indexProvider of providers) {
212
+ const index = await this.loadIndex(indexProvider);
213
+ if (!index.entries[memoryId]) continue;
214
+ delete index.entries[memoryId];
215
+ await this.saveIndex(index);
216
+ }
174
217
  });
175
218
  }
176
219
  enqueueIndexMutation(mutation) {
@@ -181,46 +224,112 @@ var EmbeddingFallback = class {
181
224
  );
182
225
  return run;
183
226
  }
184
- async resolveProvider() {
227
+ async resolveProvider(options = {}) {
185
228
  if (!this.config.embeddingFallbackEnabled) return null;
229
+ if (options.includeHost !== false && this.config.hostEmbeddingProviderEnabled !== false) {
230
+ const hostProvider = getHostEmbeddingProvider(this.config.memoryDir);
231
+ if (hostProvider) {
232
+ return {
233
+ type: "host",
234
+ model: hostProvider.model || hostProvider.id,
235
+ hostProvider
236
+ };
237
+ }
238
+ }
186
239
  const preferred = this.config.embeddingFallbackProvider;
187
240
  const providers = preferred === "auto" ? ["openai", "local"] : [preferred];
188
241
  for (const p of providers) {
189
- if (p === "openai" && this.config.openaiApiKey) {
190
- const baseUrl = this.config.openaiBaseUrl ?? "https://api.openai.com/v1";
191
- return {
192
- type: "openai",
193
- model: DEFAULT_OPENAI_MODEL,
194
- endpoint: `${baseUrl.replace(/\/$/, "")}/embeddings`,
195
- headers: {
196
- "Content-Type": "application/json",
197
- Authorization: `Bearer ${this.config.openaiApiKey}`
198
- }
199
- };
242
+ if (p === "openai") {
243
+ const provider = this.createOpenAiProvider();
244
+ if (provider) return provider;
200
245
  }
201
- if (p === "local" && this.config.localLlmEnabled && this.config.localLlmUrl) {
202
- const base = this.config.localLlmUrl.replace(/\/$/, "");
203
- const endpoint = /\/v1$/i.test(base) ? `${base}/embeddings` : `${base}/v1/embeddings`;
204
- const headers = {
205
- "Content-Type": "application/json",
206
- ...this.config.localLlmHeaders ?? {}
207
- };
208
- if (this.config.localLlmApiKey && this.config.localLlmAuthHeader !== false) {
209
- headers.Authorization = `Bearer ${this.config.localLlmApiKey}`;
210
- }
211
- return {
212
- type: "local",
213
- model: this.config.embeddingFallbackModel || this.config.localLlmModel || DEFAULT_OPENAI_MODEL,
214
- endpoint,
215
- headers
216
- };
246
+ if (p === "local") {
247
+ const provider = this.createLocalProvider();
248
+ if (provider) return provider;
217
249
  }
218
250
  }
219
251
  return null;
220
252
  }
253
+ async resolveFallbackProviderForIndexIdentity(identity) {
254
+ if (identity.provider === "openai") {
255
+ const provider = this.createOpenAiProvider();
256
+ return provider && sameIndexIdentity(provider, identity) ? provider : null;
257
+ }
258
+ if (identity.provider === "local") {
259
+ const provider = this.createLocalProvider();
260
+ return provider && sameIndexIdentity(provider, identity) ? provider : null;
261
+ }
262
+ return null;
263
+ }
264
+ createOpenAiProvider() {
265
+ if (!this.config.openaiApiKey) return null;
266
+ const baseUrl = this.config.openaiBaseUrl ?? "https://api.openai.com/v1";
267
+ return {
268
+ type: "openai",
269
+ model: DEFAULT_OPENAI_MODEL,
270
+ endpoint: `${baseUrl.replace(/\/$/, "")}/embeddings`,
271
+ headers: {
272
+ "Content-Type": "application/json",
273
+ Authorization: `Bearer ${this.config.openaiApiKey}`
274
+ }
275
+ };
276
+ }
277
+ createLocalProvider() {
278
+ if (!this.config.localLlmEnabled || !this.config.localLlmUrl) return null;
279
+ const base = this.config.localLlmUrl.replace(/\/$/, "");
280
+ const endpoint = /\/v1$/i.test(base) ? `${base}/embeddings` : `${base}/v1/embeddings`;
281
+ const headers = {
282
+ "Content-Type": "application/json",
283
+ ...this.config.localLlmHeaders ?? {}
284
+ };
285
+ if (this.config.localLlmApiKey && this.config.localLlmAuthHeader !== false) {
286
+ headers.Authorization = `Bearer ${this.config.localLlmApiKey}`;
287
+ }
288
+ return {
289
+ type: "local",
290
+ model: this.config.embeddingFallbackModel || this.config.localLlmModel || DEFAULT_OPENAI_MODEL,
291
+ endpoint,
292
+ headers
293
+ };
294
+ }
295
+ async embedForSearch(query, provider, options = {}) {
296
+ try {
297
+ return await this.embedWithEffectiveProvider(query, provider, {
298
+ mode: "lookup"
299
+ });
300
+ } catch (err) {
301
+ if (isLookupBackendUnavailableError(err)) {
302
+ if (options.throwOnTimeout) {
303
+ throw err;
304
+ }
305
+ log.debug("embedding fallback search: backend unavailable on lookup, returning [] (throwOnTimeout=false)");
306
+ return null;
307
+ }
308
+ throw err;
309
+ }
310
+ }
221
311
  async embed(input, provider, options = {}) {
312
+ const result = await this.embedWithEffectiveProvider(input, provider, options);
313
+ return result?.vector ?? null;
314
+ }
315
+ async embedWithEffectiveProvider(input, provider, options = {}) {
222
316
  const mode = options.mode ?? "lookup";
223
317
  const timeoutMs = mode === "index" ? resolveEmbeddingIndexTimeoutMs() : resolveEmbeddingLookupTimeoutMs();
318
+ if (provider.type === "host") {
319
+ const vector = await this.embedWithHostProvider(input, provider, mode, timeoutMs);
320
+ if (vector) return { provider, vector };
321
+ const fallbackProvider = await this.resolveProvider({ includeHost: false });
322
+ if (!fallbackProvider) {
323
+ if (mode === "lookup") {
324
+ throw new EmbeddingProviderUnavailableError(
325
+ `host embedding provider unavailable (${provider.hostProvider?.id ?? provider.model})`
326
+ );
327
+ }
328
+ return null;
329
+ }
330
+ return this.embedWithEffectiveProvider(input, fallbackProvider, options);
331
+ }
332
+ if (!provider.endpoint || !provider.headers) return null;
224
333
  try {
225
334
  const res = await fetch(provider.endpoint, {
226
335
  method: "POST",
@@ -244,9 +353,10 @@ var EmbeddingFallback = class {
244
353
  const payload = await res.json();
245
354
  const vector = payload?.data?.[0]?.embedding;
246
355
  if (!Array.isArray(vector)) return null;
247
- return vector.map((n) => Number(n)).filter((n) => Number.isFinite(n));
356
+ const normalized = vector.map((n) => Number(n)).filter((n) => Number.isFinite(n));
357
+ return normalized.length > 0 ? { provider, vector: normalized } : null;
248
358
  } catch (err) {
249
- if (err instanceof EmbeddingTimeoutError) {
359
+ if (isLookupBackendUnavailableError(err)) {
250
360
  throw err;
251
361
  }
252
362
  const isTimeout = err instanceof Error && (err.name === "TimeoutError" || err.name === "AbortError");
@@ -273,6 +383,20 @@ var EmbeddingFallback = class {
273
383
  return null;
274
384
  }
275
385
  }
386
+ async embedWithHostProvider(input, provider, mode, timeoutMs) {
387
+ const hostProvider = provider.hostProvider;
388
+ if (!hostProvider) return null;
389
+ try {
390
+ const vector = await hostProvider.embed(input.slice(0, 8e3), {
391
+ signal: AbortSignal.timeout(timeoutMs),
392
+ inputType: mode === "lookup" ? "query" : "document"
393
+ });
394
+ return normalizeHostEmbeddingVector(vector);
395
+ } catch (err) {
396
+ log.debug(`host embedding provider error: ${hostProvider.id}: ${err}`);
397
+ return null;
398
+ }
399
+ }
276
400
  async loadIndex(provider) {
277
401
  if (this.loaded && this.loaded.provider === provider.type && this.loaded.model === provider.model) {
278
402
  return this.loaded;
@@ -299,6 +423,20 @@ var EmbeddingFallback = class {
299
423
  };
300
424
  return this.loaded;
301
425
  }
426
+ async readIndexIdentityFromDisk() {
427
+ try {
428
+ const raw = await readFile(this.indexPath, "utf-8");
429
+ const parsed = JSON.parse(raw);
430
+ if (parsed && parsed.version === 1 && (parsed.provider === "openai" || parsed.provider === "local" || parsed.provider === "host") && typeof parsed.model === "string" && parsed.model.length > 0) {
431
+ return {
432
+ provider: parsed.provider,
433
+ model: parsed.model
434
+ };
435
+ }
436
+ } catch {
437
+ }
438
+ return null;
439
+ }
302
440
  async saveIndex(index) {
303
441
  const dir = path.dirname(this.indexPath);
304
442
  await mkdir(dir, { recursive: true });
@@ -334,6 +472,21 @@ function normalizePathPrefix(prefix) {
334
472
  if (!p.endsWith("/")) p = `${p}/`;
335
473
  return p;
336
474
  }
475
+ function sameIndexIdentity(left, right) {
476
+ return indexIdentityProvider(left) === indexIdentityProvider(right) && left.model === right.model;
477
+ }
478
+ function indexIdentityProvider(identity) {
479
+ return "provider" in identity ? identity.provider : identity.type;
480
+ }
481
+ function canReplaceIndexIdentity(existing, replacement) {
482
+ return existing.provider === "host" && !sameIndexIdentity(existing, replacement);
483
+ }
484
+ function providerFromIndexIdentity(identity) {
485
+ return {
486
+ type: identity.provider,
487
+ model: identity.model
488
+ };
489
+ }
337
490
  function cosineSimilarity(a, b) {
338
491
  const n = Math.min(a.length, b.length);
339
492
  if (n === 0) return 0;
@@ -354,6 +507,7 @@ function cosineSimilarity(a, b) {
354
507
 
355
508
  export {
356
509
  EmbeddingTimeoutError,
510
+ EmbeddingProviderUnavailableError,
357
511
  EmbeddingFallback
358
512
  };
359
- //# sourceMappingURL=chunk-6URPAY2D.js.map
513
+ //# sourceMappingURL=chunk-XCAZF7KQ.js.map