@graphorin/memory 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (287) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/LICENSE +21 -0
  3. package/README.md +401 -0
  4. package/dist/conflict/index.d.ts +3 -0
  5. package/dist/conflict/index.js +7 -0
  6. package/dist/conflict/locale-packs/en.js +262 -0
  7. package/dist/conflict/locale-packs/en.js.map +1 -0
  8. package/dist/conflict/locale-packs/index.js +4 -0
  9. package/dist/conflict/locale-packs/types.d.ts +103 -0
  10. package/dist/conflict/locale-packs/types.d.ts.map +1 -0
  11. package/dist/conflict/locale-packs/types.js +55 -0
  12. package/dist/conflict/locale-packs/types.js.map +1 -0
  13. package/dist/conflict/pipeline.d.ts +35 -0
  14. package/dist/conflict/pipeline.d.ts.map +1 -0
  15. package/dist/conflict/pipeline.js +257 -0
  16. package/dist/conflict/pipeline.js.map +1 -0
  17. package/dist/conflict/stages/helpers.js +66 -0
  18. package/dist/conflict/stages/helpers.js.map +1 -0
  19. package/dist/conflict/stages/stage1-exact-dedup.js +21 -0
  20. package/dist/conflict/stages/stage1-exact-dedup.js.map +1 -0
  21. package/dist/conflict/stages/stage2-embedding-three-zone.js +37 -0
  22. package/dist/conflict/stages/stage2-embedding-three-zone.js.map +1 -0
  23. package/dist/conflict/stages/stage3-heuristic-regex.js +45 -0
  24. package/dist/conflict/stages/stage3-heuristic-regex.js.map +1 -0
  25. package/dist/conflict/stages/stage4-subject-predicate.js +31 -0
  26. package/dist/conflict/stages/stage4-subject-predicate.js.map +1 -0
  27. package/dist/conflict/stages/stage5-defer-to-deep.js +22 -0
  28. package/dist/conflict/stages/stage5-defer-to-deep.js.map +1 -0
  29. package/dist/conflict/types.d.ts +222 -0
  30. package/dist/conflict/types.d.ts.map +1 -0
  31. package/dist/conflict/types.js +50 -0
  32. package/dist/conflict/types.js.map +1 -0
  33. package/dist/consolidator/budget.d.ts +1 -0
  34. package/dist/consolidator/budget.js +214 -0
  35. package/dist/consolidator/budget.js.map +1 -0
  36. package/dist/consolidator/decay.d.ts +35 -0
  37. package/dist/consolidator/decay.d.ts.map +1 -0
  38. package/dist/consolidator/decay.js +91 -0
  39. package/dist/consolidator/decay.js.map +1 -0
  40. package/dist/consolidator/dlq.js +58 -0
  41. package/dist/consolidator/dlq.js.map +1 -0
  42. package/dist/consolidator/errors.d.ts +54 -0
  43. package/dist/consolidator/errors.d.ts.map +1 -0
  44. package/dist/consolidator/errors.js +67 -0
  45. package/dist/consolidator/errors.js.map +1 -0
  46. package/dist/consolidator/idempotency.d.ts +1 -0
  47. package/dist/consolidator/idempotency.js +22 -0
  48. package/dist/consolidator/idempotency.js.map +1 -0
  49. package/dist/consolidator/index.d.ts +34 -0
  50. package/dist/consolidator/index.d.ts.map +1 -0
  51. package/dist/consolidator/index.js +163 -0
  52. package/dist/consolidator/index.js.map +1 -0
  53. package/dist/consolidator/lock.d.ts +2 -0
  54. package/dist/consolidator/lock.js +89 -0
  55. package/dist/consolidator/lock.js.map +1 -0
  56. package/dist/consolidator/noise-filter.d.ts +2 -0
  57. package/dist/consolidator/noise-filter.js +173 -0
  58. package/dist/consolidator/noise-filter.js.map +1 -0
  59. package/dist/consolidator/phases/deep.d.ts +4 -0
  60. package/dist/consolidator/phases/deep.js +198 -0
  61. package/dist/consolidator/phases/deep.js.map +1 -0
  62. package/dist/consolidator/phases/induce.d.ts +154 -0
  63. package/dist/consolidator/phases/induce.d.ts.map +1 -0
  64. package/dist/consolidator/phases/induce.js +253 -0
  65. package/dist/consolidator/phases/induce.js.map +1 -0
  66. package/dist/consolidator/phases/light.d.ts +4 -0
  67. package/dist/consolidator/phases/light.js +99 -0
  68. package/dist/consolidator/phases/light.js.map +1 -0
  69. package/dist/consolidator/phases/reflect.js +287 -0
  70. package/dist/consolidator/phases/reflect.js.map +1 -0
  71. package/dist/consolidator/phases/standard.d.ts +8 -0
  72. package/dist/consolidator/phases/standard.js +499 -0
  73. package/dist/consolidator/phases/standard.js.map +1 -0
  74. package/dist/consolidator/reconcile.js +192 -0
  75. package/dist/consolidator/reconcile.js.map +1 -0
  76. package/dist/consolidator/runtime.d.ts +62 -0
  77. package/dist/consolidator/runtime.d.ts.map +1 -0
  78. package/dist/consolidator/runtime.js +580 -0
  79. package/dist/consolidator/runtime.js.map +1 -0
  80. package/dist/consolidator/scheduler.d.ts +111 -0
  81. package/dist/consolidator/scheduler.d.ts.map +1 -0
  82. package/dist/consolidator/scheduler.js +71 -0
  83. package/dist/consolidator/scheduler.js.map +1 -0
  84. package/dist/consolidator/triggers.d.ts +40 -0
  85. package/dist/consolidator/triggers.d.ts.map +1 -0
  86. package/dist/consolidator/triggers.js +94 -0
  87. package/dist/consolidator/triggers.js.map +1 -0
  88. package/dist/consolidator/types.d.ts +397 -0
  89. package/dist/consolidator/types.d.ts.map +1 -0
  90. package/dist/consolidator/types.js +117 -0
  91. package/dist/consolidator/types.js.map +1 -0
  92. package/dist/context-engine/annotations.d.ts +118 -0
  93. package/dist/context-engine/annotations.d.ts.map +1 -0
  94. package/dist/context-engine/annotations.js +102 -0
  95. package/dist/context-engine/annotations.js.map +1 -0
  96. package/dist/context-engine/auto-recall.d.ts +52 -0
  97. package/dist/context-engine/auto-recall.d.ts.map +1 -0
  98. package/dist/context-engine/auto-recall.js +41 -0
  99. package/dist/context-engine/auto-recall.js.map +1 -0
  100. package/dist/context-engine/compaction/clear-tool-results.d.ts +55 -0
  101. package/dist/context-engine/compaction/clear-tool-results.d.ts.map +1 -0
  102. package/dist/context-engine/compaction/clear-tool-results.js +97 -0
  103. package/dist/context-engine/compaction/clear-tool-results.js.map +1 -0
  104. package/dist/context-engine/compaction/compactor.d.ts +52 -0
  105. package/dist/context-engine/compaction/compactor.d.ts.map +1 -0
  106. package/dist/context-engine/compaction/compactor.js +196 -0
  107. package/dist/context-engine/compaction/compactor.js.map +1 -0
  108. package/dist/context-engine/compaction/hooks/reanchor-persona-block.d.ts +15 -0
  109. package/dist/context-engine/compaction/hooks/reanchor-persona-block.d.ts.map +1 -0
  110. package/dist/context-engine/compaction/hooks/reanchor-persona-block.js +27 -0
  111. package/dist/context-engine/compaction/hooks/reanchor-persona-block.js.map +1 -0
  112. package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.d.ts +18 -0
  113. package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.d.ts.map +1 -0
  114. package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.js +47 -0
  115. package/dist/context-engine/compaction/hooks/reanchor-pinned-facts.js.map +1 -0
  116. package/dist/context-engine/compaction/hooks/reanchor-project-rules.d.ts +15 -0
  117. package/dist/context-engine/compaction/hooks/reanchor-project-rules.d.ts.map +1 -0
  118. package/dist/context-engine/compaction/hooks/reanchor-project-rules.js +32 -0
  119. package/dist/context-engine/compaction/hooks/reanchor-project-rules.js.map +1 -0
  120. package/dist/context-engine/compaction/hooks/types.d.ts +42 -0
  121. package/dist/context-engine/compaction/hooks/types.d.ts.map +1 -0
  122. package/dist/context-engine/compaction/index.d.ts +9 -0
  123. package/dist/context-engine/compaction/index.js +9 -0
  124. package/dist/context-engine/compaction/templates/summary-9-section.d.ts +84 -0
  125. package/dist/context-engine/compaction/templates/summary-9-section.d.ts.map +1 -0
  126. package/dist/context-engine/compaction/templates/summary-9-section.js +84 -0
  127. package/dist/context-engine/compaction/templates/summary-9-section.js.map +1 -0
  128. package/dist/context-engine/compaction/thresholds.d.ts +68 -0
  129. package/dist/context-engine/compaction/thresholds.d.ts.map +1 -0
  130. package/dist/context-engine/compaction/thresholds.js +63 -0
  131. package/dist/context-engine/compaction/thresholds.js.map +1 -0
  132. package/dist/context-engine/compaction/types.d.ts +202 -0
  133. package/dist/context-engine/compaction/types.d.ts.map +1 -0
  134. package/dist/context-engine/engine.d.ts +258 -0
  135. package/dist/context-engine/engine.d.ts.map +1 -0
  136. package/dist/context-engine/engine.js +424 -0
  137. package/dist/context-engine/engine.js.map +1 -0
  138. package/dist/context-engine/index.d.ts +68 -0
  139. package/dist/context-engine/index.d.ts.map +1 -0
  140. package/dist/context-engine/index.js +24 -0
  141. package/dist/context-engine/locale-packs/en.d.ts +14 -0
  142. package/dist/context-engine/locale-packs/en.d.ts.map +1 -0
  143. package/dist/context-engine/locale-packs/en.js +87 -0
  144. package/dist/context-engine/locale-packs/en.js.map +1 -0
  145. package/dist/context-engine/locale-packs/index.js +4 -0
  146. package/dist/context-engine/locale-packs/resolver.d.ts +41 -0
  147. package/dist/context-engine/locale-packs/resolver.d.ts.map +1 -0
  148. package/dist/context-engine/locale-packs/resolver.js +119 -0
  149. package/dist/context-engine/locale-packs/resolver.js.map +1 -0
  150. package/dist/context-engine/locale-packs/types.d.ts +119 -0
  151. package/dist/context-engine/locale-packs/types.d.ts.map +1 -0
  152. package/dist/context-engine/locale-packs/types.js +24 -0
  153. package/dist/context-engine/locale-packs/types.js.map +1 -0
  154. package/dist/context-engine/metadata.d.ts +40 -0
  155. package/dist/context-engine/metadata.d.ts.map +1 -0
  156. package/dist/context-engine/metadata.js +66 -0
  157. package/dist/context-engine/metadata.js.map +1 -0
  158. package/dist/context-engine/preambles/inbound-en.d.ts +20 -0
  159. package/dist/context-engine/preambles/inbound-en.d.ts.map +1 -0
  160. package/dist/context-engine/preambles/inbound-en.js +23 -0
  161. package/dist/context-engine/preambles/inbound-en.js.map +1 -0
  162. package/dist/context-engine/privacy-filter.d.ts +108 -0
  163. package/dist/context-engine/privacy-filter.d.ts.map +1 -0
  164. package/dist/context-engine/privacy-filter.js +113 -0
  165. package/dist/context-engine/privacy-filter.js.map +1 -0
  166. package/dist/context-engine/templates/base-en.d.ts +19 -0
  167. package/dist/context-engine/templates/base-en.d.ts.map +1 -0
  168. package/dist/context-engine/templates/base-en.js +22 -0
  169. package/dist/context-engine/templates/base-en.js.map +1 -0
  170. package/dist/context-engine/templates/composer.d.ts +55 -0
  171. package/dist/context-engine/templates/composer.d.ts.map +1 -0
  172. package/dist/context-engine/templates/composer.js +51 -0
  173. package/dist/context-engine/templates/composer.js.map +1 -0
  174. package/dist/context-engine/token-budget.d.ts +99 -0
  175. package/dist/context-engine/token-budget.d.ts.map +1 -0
  176. package/dist/context-engine/token-budget.js +211 -0
  177. package/dist/context-engine/token-budget.js.map +1 -0
  178. package/dist/context-engine/token-counter.d.ts +54 -0
  179. package/dist/context-engine/token-counter.d.ts.map +1 -0
  180. package/dist/context-engine/token-counter.js +81 -0
  181. package/dist/context-engine/token-counter.js.map +1 -0
  182. package/dist/errors/index.d.ts +171 -0
  183. package/dist/errors/index.d.ts.map +1 -0
  184. package/dist/errors/index.js +206 -0
  185. package/dist/errors/index.js.map +1 -0
  186. package/dist/facade.d.ts +278 -0
  187. package/dist/facade.d.ts.map +1 -0
  188. package/dist/facade.js +265 -0
  189. package/dist/facade.js.map +1 -0
  190. package/dist/graph/entity-resolver.d.ts +135 -0
  191. package/dist/graph/entity-resolver.d.ts.map +1 -0
  192. package/dist/graph/entity-resolver.js +202 -0
  193. package/dist/graph/entity-resolver.js.map +1 -0
  194. package/dist/graph/index.d.ts +1 -0
  195. package/dist/index.d.ts +103 -0
  196. package/dist/index.d.ts.map +1 -0
  197. package/dist/index.js +95 -0
  198. package/dist/index.js.map +1 -0
  199. package/dist/internal/contextualize.d.ts +14 -0
  200. package/dist/internal/contextualize.d.ts.map +1 -0
  201. package/dist/internal/contextualize.js +110 -0
  202. package/dist/internal/contextualize.js.map +1 -0
  203. package/dist/internal/embedder-binding.js +50 -0
  204. package/dist/internal/embedder-binding.js.map +1 -0
  205. package/dist/internal/id.js +24 -0
  206. package/dist/internal/id.js.map +1 -0
  207. package/dist/internal/injection-heuristics.js +64 -0
  208. package/dist/internal/injection-heuristics.js.map +1 -0
  209. package/dist/internal/spans.js +35 -0
  210. package/dist/internal/spans.js.map +1 -0
  211. package/dist/internal/storage-adapter.d.ts +742 -0
  212. package/dist/internal/storage-adapter.d.ts.map +1 -0
  213. package/dist/migration/embedder-migration.d.ts +124 -0
  214. package/dist/migration/embedder-migration.d.ts.map +1 -0
  215. package/dist/migration/embedder-migration.js +109 -0
  216. package/dist/migration/embedder-migration.js.map +1 -0
  217. package/dist/migration/index.d.ts +2 -0
  218. package/dist/migration/index.js +3 -0
  219. package/dist/search/explain.d.ts +74 -0
  220. package/dist/search/explain.d.ts.map +1 -0
  221. package/dist/search/explain.js +50 -0
  222. package/dist/search/explain.js.map +1 -0
  223. package/dist/search/index.d.ts +6 -0
  224. package/dist/search/index.js +6 -0
  225. package/dist/search/iterative.d.ts +223 -0
  226. package/dist/search/iterative.d.ts.map +1 -0
  227. package/dist/search/iterative.js +330 -0
  228. package/dist/search/iterative.js.map +1 -0
  229. package/dist/search/query-transform.d.ts +112 -0
  230. package/dist/search/query-transform.d.ts.map +1 -0
  231. package/dist/search/query-transform.js +184 -0
  232. package/dist/search/query-transform.js.map +1 -0
  233. package/dist/search/rrf.d.ts +95 -0
  234. package/dist/search/rrf.d.ts.map +1 -0
  235. package/dist/search/rrf.js +166 -0
  236. package/dist/search/rrf.js.map +1 -0
  237. package/dist/search/types.d.ts +50 -0
  238. package/dist/search/types.d.ts.map +1 -0
  239. package/dist/tiers/episodic-memory.d.ts +142 -0
  240. package/dist/tiers/episodic-memory.d.ts.map +1 -0
  241. package/dist/tiers/episodic-memory.js +254 -0
  242. package/dist/tiers/episodic-memory.js.map +1 -0
  243. package/dist/tiers/index.d.ts +8 -0
  244. package/dist/tiers/index.js +9 -0
  245. package/dist/tiers/insight-memory.d.ts +71 -0
  246. package/dist/tiers/insight-memory.d.ts.map +1 -0
  247. package/dist/tiers/insight-memory.js +133 -0
  248. package/dist/tiers/insight-memory.js.map +1 -0
  249. package/dist/tiers/procedural-memory.d.ts +147 -0
  250. package/dist/tiers/procedural-memory.d.ts.map +1 -0
  251. package/dist/tiers/procedural-memory.js +267 -0
  252. package/dist/tiers/procedural-memory.js.map +1 -0
  253. package/dist/tiers/semantic-memory.d.ts +461 -0
  254. package/dist/tiers/semantic-memory.d.ts.map +1 -0
  255. package/dist/tiers/semantic-memory.js +631 -0
  256. package/dist/tiers/semantic-memory.js.map +1 -0
  257. package/dist/tiers/session-memory.d.ts +117 -0
  258. package/dist/tiers/session-memory.d.ts.map +1 -0
  259. package/dist/tiers/session-memory.js +163 -0
  260. package/dist/tiers/session-memory.js.map +1 -0
  261. package/dist/tiers/shared-memory.d.ts +29 -0
  262. package/dist/tiers/shared-memory.d.ts.map +1 -0
  263. package/dist/tiers/shared-memory.js +58 -0
  264. package/dist/tiers/shared-memory.js.map +1 -0
  265. package/dist/tiers/working-memory.d.ts +129 -0
  266. package/dist/tiers/working-memory.d.ts.map +1 -0
  267. package/dist/tiers/working-memory.js +229 -0
  268. package/dist/tiers/working-memory.js.map +1 -0
  269. package/dist/tools/block-tools.d.ts +98 -0
  270. package/dist/tools/block-tools.d.ts.map +1 -0
  271. package/dist/tools/block-tools.js +114 -0
  272. package/dist/tools/block-tools.js.map +1 -0
  273. package/dist/tools/fact-tools.d.ts +294 -0
  274. package/dist/tools/fact-tools.d.ts.map +1 -0
  275. package/dist/tools/fact-tools.js +293 -0
  276. package/dist/tools/fact-tools.js.map +1 -0
  277. package/dist/tools/index.d.ts +35 -0
  278. package/dist/tools/index.d.ts.map +1 -0
  279. package/dist/tools/index.js +36 -0
  280. package/dist/tools/index.js.map +1 -0
  281. package/dist/tools/recall-tools.d.ts +209 -0
  282. package/dist/tools/recall-tools.d.ts.map +1 -0
  283. package/dist/tools/recall-tools.js +170 -0
  284. package/dist/tools/recall-tools.js.map +1 -0
  285. package/dist/tools/types.d.ts +40 -0
  286. package/dist/tools/types.d.ts.map +1 -0
  287. package/package.json +119 -0
@@ -0,0 +1,580 @@
1
+ import { DEFAULT_SALIENCE_WEIGHTS } from "./decay.js";
2
+ import { CustomTierMisconfiguredError, ProviderNotConfiguredError } from "./errors.js";
3
+ import { BudgetTracker } from "./budget.js";
4
+ import { classifyError, describeError, nextBackoffMs } from "./dlq.js";
5
+ import { tipMessageId } from "./idempotency.js";
6
+ import { LockManager } from "./lock.js";
7
+ import { runDeepPhase } from "./phases/deep.js";
8
+ import { runLightPhase } from "./phases/light.js";
9
+ import { runStandardPhase } from "./phases/standard.js";
10
+ import { runReflectionPass } from "./phases/reflect.js";
11
+ import { registerConsolidatorTriggers } from "./scheduler.js";
12
+ import { CONSOLIDATOR_TIER_DEFAULTS } from "./types.js";
13
+ import { NOOP_TRACER } from "@graphorin/core";
14
+
15
+ //#region src/consolidator/runtime.ts
16
+ /**
17
+ * Build the runtime consolidator.
18
+ *
19
+ * @stable
20
+ */
21
+ function createConsolidator(opts) {
22
+ return new ConsolidatorImpl(opts);
23
+ }
24
+ var ConsolidatorImpl = class {
25
+ #semantic;
26
+ #episodic;
27
+ #store;
28
+ #consolidatorStore;
29
+ #tracer;
30
+ #now;
31
+ #randomId;
32
+ #provider;
33
+ /** Per-phase provider overrides (MCON-7); fall back to `#provider`. */
34
+ #cheapProvider;
35
+ #deepProvider;
36
+ #defaultScope;
37
+ #listeners = /* @__PURE__ */ new Set();
38
+ #lockManager;
39
+ #budget;
40
+ #config;
41
+ #running = false;
42
+ #manuallyPaused = false;
43
+ #deferredRuns = 0;
44
+ /**
45
+ * Message ids of the batch the most recent `#dispatch` operated on
46
+ * (MCON-10). Captured so a thrown phase can enqueue its DLQ row with
47
+ * the REAL failed slice instead of `[]` — replays must target the
48
+ * window that failed, not whatever the cursor points at later.
49
+ */
50
+ #lastDispatchMessageIds = [];
51
+ /**
52
+ * Bumped when the runtime cannot persist a deferred run to the
53
+ * audit log (e.g., adapter omits the consolidator surface). The
54
+ * `status()` reader merges this with the persisted count so
55
+ * library-mode callers still observe the deferral.
56
+ */
57
+ #deferredRunsAdjustment = 0;
58
+ #emptyExtractions = 0;
59
+ constructor(opts) {
60
+ this.#semantic = opts.semantic;
61
+ this.#episodic = opts.episodic ?? null;
62
+ this.#store = opts.store;
63
+ this.#consolidatorStore = this.#store.consolidator ?? null;
64
+ this.#tracer = opts.tracer ?? NOOP_TRACER;
65
+ this.#now = opts.now ?? Date.now;
66
+ this.#randomId = opts.randomId ?? (() => {
67
+ return `cr_${Math.floor(Math.random() * 1e9).toString(36)}${Math.floor(Math.random() * 1e9).toString(36)}`;
68
+ });
69
+ this.#provider = opts.provider ?? null;
70
+ this.#cheapProvider = opts.cheapProvider ?? null;
71
+ this.#deepProvider = opts.deepProvider ?? null;
72
+ this.#defaultScope = opts.defaultScope ?? null;
73
+ this.#config = resolveConfig(opts);
74
+ this.#lockManager = new LockManager({
75
+ store: this.#consolidatorStore,
76
+ waitMs: this.#config.lockWaitMs,
77
+ maxRunDurationMs: this.#config.ceilings.maxRunDurationMs,
78
+ now: this.#now,
79
+ randomId: this.#randomId
80
+ });
81
+ this.#budget = new BudgetTracker({
82
+ maxTokensPerDay: this.#config.ceilings.maxTokensPerDay,
83
+ maxCostPerDay: this.#config.ceilings.maxCostPerDay,
84
+ onExceed: this.#config.onExceed,
85
+ resetSemantics: this.#config.budgetResetSemantics,
86
+ now: this.#now
87
+ });
88
+ }
89
+ async start() {
90
+ this.#running = true;
91
+ }
92
+ async stop() {
93
+ this.#running = false;
94
+ }
95
+ async pause() {
96
+ this.#manuallyPaused = true;
97
+ }
98
+ async resume() {
99
+ this.#manuallyPaused = false;
100
+ }
101
+ config() {
102
+ return this.#config;
103
+ }
104
+ async registerWithScheduler(scheduler) {
105
+ if (this.#defaultScope === null) throw new Error("[graphorin/memory] Consolidator.registerWithScheduler requires a defaultScope. Pass `defaultScope` to createConsolidator / createMemory, or call registerConsolidatorTriggers(consolidator, scheduler, { scope }) directly.");
106
+ return registerConsolidatorTriggers(this, scheduler, { scope: this.#defaultScope });
107
+ }
108
+ isFree() {
109
+ return this.#config.tier === "free";
110
+ }
111
+ onPhaseFinished(listener) {
112
+ this.#listeners.add(listener);
113
+ return () => {
114
+ this.#listeners.delete(listener);
115
+ };
116
+ }
117
+ recordExternalSpend(tokens, costUsd) {
118
+ if (!Number.isFinite(tokens) || tokens <= 0) return;
119
+ this.#budget.record({
120
+ phase: "deep",
121
+ tokens,
122
+ costUsd: costUsd ?? 0
123
+ });
124
+ }
125
+ async setTier(tier) {
126
+ const preset = CONSOLIDATOR_TIER_DEFAULTS[tier];
127
+ if (preset === void 0) throw new Error(`[graphorin/memory] unknown consolidator tier '${tier}'`);
128
+ if (tier === "custom") throw new Error("[graphorin/memory] consolidator.setTier(\"custom\") requires explicit ceilings — re-create the consolidator with `tier: \"custom\"` + `ceilings`.");
129
+ this.#config = Object.freeze({
130
+ ...this.#config,
131
+ tier,
132
+ phases: preset.phases,
133
+ ceilings: preset.ceilings,
134
+ onExceed: preset.onExceed,
135
+ formEpisodes: preset.formEpisodes,
136
+ importanceScoring: preset.importanceScoring,
137
+ reflection: preset.reflection,
138
+ importanceThreshold: preset.importanceThreshold,
139
+ reflectionMaxQuestions: preset.reflectionMaxQuestions,
140
+ contextualRetrieval: preset.contextualRetrieval
141
+ });
142
+ this.#budget.reconfigure({
143
+ maxTokensPerDay: preset.ceilings.maxTokensPerDay,
144
+ maxCostPerDay: preset.ceilings.maxCostPerDay
145
+ });
146
+ }
147
+ async status() {
148
+ let lastRunAt;
149
+ let lastPhase;
150
+ const lastRuns = {};
151
+ let pendingConflicts = 0;
152
+ let dlqSize = 0;
153
+ let deferredFromStore = 0;
154
+ if (this.#consolidatorStore !== null && this.#defaultScope !== null) {
155
+ const state = await this.#consolidatorStore.getState(this.#defaultScope);
156
+ if (state !== null) {
157
+ if (state.lastCompletedAt !== null) lastRunAt = new Date(state.lastCompletedAt).toISOString();
158
+ if (state.lastPhase !== null) lastPhase = state.lastPhase;
159
+ }
160
+ dlqSize = (await this.#consolidatorStore.listFailedBatches(this.#defaultScope, 1e3)).length;
161
+ const recent = await this.#consolidatorStore.listRecentRuns(this.#defaultScope, 500);
162
+ for (const run of recent) {
163
+ if (run.status === "deferred") {
164
+ deferredFromStore += 1;
165
+ continue;
166
+ }
167
+ if (run.status !== "completed" && run.status !== "partial") continue;
168
+ const stamp = new Date(run.finishedAt ?? run.startedAt).toISOString();
169
+ if (run.phase === "light" && lastRuns.light === void 0) lastRuns.light = stamp;
170
+ else if (run.phase === "standard" && lastRuns.standard === void 0) lastRuns.standard = stamp;
171
+ else if (run.phase === "deep" && lastRuns.deep === void 0) lastRuns.deep = stamp;
172
+ }
173
+ }
174
+ if (this.#store.conflicts !== void 0 && this.#defaultScope !== null) pendingConflicts = (await this.#store.conflicts.listPending(this.#defaultScope, 1e3)).length;
175
+ const snapshot = this.#budget.snapshot();
176
+ const persistedDeferred = deferredFromStore + this.#deferredRunsAdjustment;
177
+ const totalDeferred = Math.max(persistedDeferred, this.#deferredRuns);
178
+ return {
179
+ tier: this.#config.tier,
180
+ triggers: this.#config.triggers,
181
+ phases: this.#config.phases,
182
+ running: this.#running,
183
+ paused: this.#manuallyPaused || snapshot.paused,
184
+ pendingConflicts,
185
+ queueDepth: pendingConflicts,
186
+ dlqSize,
187
+ deferredRuns: totalDeferred,
188
+ emptyExtractions: this.#emptyExtractions,
189
+ lastRuns: Object.freeze(lastRuns),
190
+ budget: {
191
+ tokensUsedToday: snapshot.tokensUsedToday,
192
+ costUsedToday: snapshot.costUsedToday,
193
+ tokensRemaining: snapshot.tokensRemaining,
194
+ costRemaining: snapshot.costRemaining,
195
+ resetAt: snapshot.resetAt
196
+ },
197
+ budgetRemaining: {
198
+ tokens: snapshot.tokensRemaining,
199
+ costUsd: snapshot.costRemaining
200
+ },
201
+ ...lastRunAt !== void 0 ? { lastRunAt } : {},
202
+ ...lastPhase !== void 0 ? { lastPhase } : {}
203
+ };
204
+ }
205
+ async trigger(reason, scope) {
206
+ if (!this.#running) return null;
207
+ if (this.#manuallyPaused) return null;
208
+ const phases = this.#planPhases(reason);
209
+ if (phases.length === 0) return null;
210
+ if (reason.kind !== "manual" && this.#config.ceilings.cooldownMs > 0) {
211
+ const eligibleAt = (this.#consolidatorStore !== null ? await this.#consolidatorStore.getState(scope) : null)?.nextEligibleAt ?? null;
212
+ const firstPhase = phases[0] ?? "light";
213
+ if (eligibleAt !== null && this.#now() < eligibleAt) return this.#emit({
214
+ ...skipOutcome(firstPhase, "cooldown"),
215
+ phase: firstPhase
216
+ }, scope, reason);
217
+ }
218
+ let last = null;
219
+ for (const phase of phases) {
220
+ last = await this.#runPhase(phase, scope, reason);
221
+ if (last?.status === "failed" || last?.status === "deferred") break;
222
+ }
223
+ return last;
224
+ }
225
+ async fireNow(phase, scope) {
226
+ const target = scope ?? this.#defaultScope;
227
+ if (target === null) throw new Error("[graphorin/memory] consolidator.fireNow requires a scope (default scope was not configured).");
228
+ if (!this.#config.phases.includes(phase) && phase !== "light") process.stderr.write(`[graphorin/memory] consolidator.fireNow('${phase}') runs a phase not enabled for tier '${this.#config.tier}' — proceeding (manual flushes bypass phase gating).\n`);
229
+ return this.#runPhase(phase, target, {
230
+ kind: "manual",
231
+ value: phase
232
+ });
233
+ }
234
+ async drainDlq(scope) {
235
+ const store = this.#consolidatorStore;
236
+ if (store === null) return 0;
237
+ const ready = await store.claimReadyBatches(scope, this.#now(), 50);
238
+ let drained = 0;
239
+ for (const row of ready) {
240
+ const replayPhase = row.phase ?? "standard";
241
+ let succeeded = false;
242
+ let deferred = false;
243
+ let lastError = null;
244
+ try {
245
+ const outcome = await this.#runPhase(replayPhase, scope, {
246
+ kind: "manual",
247
+ value: `dlq-replay:${replayPhase}`
248
+ });
249
+ if (outcome?.status === "completed" || outcome?.status === "partial") succeeded = true;
250
+ else if (outcome?.status === "deferred") {
251
+ deferred = true;
252
+ lastError = new Error(outcome.errorMessage ?? "replay deferred");
253
+ } else if (outcome?.errorMessage != null) lastError = new Error(outcome.errorMessage);
254
+ } catch (err) {
255
+ lastError = err;
256
+ }
257
+ if (succeeded) {
258
+ await store.markBatchSucceeded(row.id);
259
+ drained += 1;
260
+ continue;
261
+ }
262
+ if (deferred) {
263
+ const delayMs = nextBackoffMs({
264
+ retryCount: row.retryCount + 1,
265
+ baseMs: this.#config.dlqBaseBackoffMs,
266
+ maxMs: this.#config.dlqMaxBackoffMs
267
+ });
268
+ await store.rescheduleBatch(row.id, row.retryCount, this.#now() + delayMs);
269
+ continue;
270
+ }
271
+ const nextRetryCount = row.retryCount + 1;
272
+ if (nextRetryCount >= this.#config.dlqMaxRetries) await store.markBatchExhausted(row.id, describeError(lastError), nextRetryCount);
273
+ else {
274
+ const delayMs = nextBackoffMs({
275
+ retryCount: nextRetryCount,
276
+ baseMs: this.#config.dlqBaseBackoffMs,
277
+ maxMs: this.#config.dlqMaxBackoffMs
278
+ });
279
+ await store.rescheduleBatch(row.id, nextRetryCount, this.#now() + delayMs);
280
+ }
281
+ }
282
+ return drained;
283
+ }
284
+ #planPhases(reason) {
285
+ const enabled = new Set(this.#config.phases);
286
+ const planned = [];
287
+ if (reason.kind === "turn" || reason.kind === "idle" || reason.kind === "event") {
288
+ if (enabled.has("light")) planned.push("light");
289
+ if (enabled.has("standard")) planned.push("standard");
290
+ } else if (reason.kind === "cron" || reason.kind === "manual" || reason.kind === "budget") {
291
+ if (enabled.has("light")) planned.push("light");
292
+ if (enabled.has("standard")) planned.push("standard");
293
+ if (enabled.has("deep")) planned.push("deep");
294
+ }
295
+ return planned;
296
+ }
297
+ async #runPhase(phase, scope, reason) {
298
+ const precheck = this.#budget.precheck(phase);
299
+ if (!precheck.allowed && phase !== "light") return this.#emit({
300
+ ...skipOutcome(phase, precheck.reason ?? "paused"),
301
+ phase
302
+ }, scope, reason);
303
+ const acquisition = await this.#lockManager.acquire(scope);
304
+ if (acquisition.kind === "deferred") {
305
+ this.#deferredRuns += 1;
306
+ const deferredRunId = this.#randomId();
307
+ const deferredAt = this.#now();
308
+ if (this.#consolidatorStore !== null) try {
309
+ await this.#consolidatorStore.recordRunStart({
310
+ id: deferredRunId,
311
+ scope,
312
+ triggerKind: reason.kind,
313
+ phase,
314
+ startedAt: deferredAt
315
+ });
316
+ await this.#consolidatorStore.recordRunFinish({
317
+ id: deferredRunId,
318
+ finishedAt: deferredAt,
319
+ status: "deferred",
320
+ errorMessage: `lock held by ${acquisition.heldBy ?? "unknown"}`
321
+ });
322
+ } catch {
323
+ this.#deferredRunsAdjustment += 1;
324
+ }
325
+ else this.#deferredRunsAdjustment += 1;
326
+ return this.#emit({
327
+ phase,
328
+ status: "deferred",
329
+ factsCreated: 0,
330
+ factsUpdated: 0,
331
+ conflictsResolved: 0,
332
+ episodesFormed: 0,
333
+ insightsCreated: 0,
334
+ noiseFilteredCount: 0,
335
+ emptyExtractions: 0,
336
+ llmTokensUsed: 0,
337
+ llmCostUsd: null,
338
+ errorMessage: `lock held by ${acquisition.heldBy ?? "unknown"}`
339
+ }, scope, reason);
340
+ }
341
+ const runId = acquisition.runId;
342
+ const startedAt = this.#now();
343
+ if (this.#consolidatorStore !== null) await this.#consolidatorStore.recordRunStart({
344
+ id: runId,
345
+ scope,
346
+ triggerKind: reason.kind,
347
+ phase,
348
+ startedAt
349
+ });
350
+ let outcome;
351
+ try {
352
+ outcome = await this.#dispatch(phase, scope);
353
+ } catch (err) {
354
+ outcome = {
355
+ phase,
356
+ status: "failed",
357
+ factsCreated: 0,
358
+ factsUpdated: 0,
359
+ conflictsResolved: 0,
360
+ episodesFormed: 0,
361
+ insightsCreated: 0,
362
+ noiseFilteredCount: 0,
363
+ emptyExtractions: 0,
364
+ llmTokensUsed: 0,
365
+ llmCostUsd: null,
366
+ errorMessage: describeError(err)
367
+ };
368
+ const isDlqReplay = reason.kind === "manual" && typeof reason.value === "string" && reason.value.startsWith("dlq-replay:");
369
+ if (this.#consolidatorStore !== null && !isDlqReplay) await this.#consolidatorStore.enqueueFailedBatch({
370
+ id: this.#randomId(),
371
+ consolidatorRunId: runId,
372
+ scope,
373
+ messageIds: this.#lastDispatchMessageIds,
374
+ errorKind: classifyError(err),
375
+ errorMessage: describeError(err),
376
+ failedAt: this.#now(),
377
+ nextRetryAt: this.#now() + nextBackoffMs({
378
+ retryCount: 0,
379
+ baseMs: this.#config.dlqBaseBackoffMs,
380
+ maxMs: this.#config.dlqMaxBackoffMs
381
+ }),
382
+ retryCount: 0,
383
+ phase
384
+ });
385
+ }
386
+ if (outcome.emptyExtractions > 0) this.#emptyExtractions += outcome.emptyExtractions;
387
+ if (this.#consolidatorStore !== null) {
388
+ await this.#consolidatorStore.recordRunFinish({
389
+ id: runId,
390
+ finishedAt: this.#now(),
391
+ status: outcome.status,
392
+ llmTokensUsed: outcome.llmTokensUsed,
393
+ llmCostUsd: outcome.llmCostUsd,
394
+ factsCreated: outcome.factsCreated,
395
+ factsUpdated: outcome.factsUpdated,
396
+ conflictsResolved: outcome.conflictsResolved,
397
+ noiseFilteredCount: outcome.noiseFilteredCount,
398
+ emptyExtractions: outcome.emptyExtractions,
399
+ episodesFormed: outcome.episodesFormed,
400
+ insightsCreated: outcome.insightsCreated,
401
+ errorMessage: outcome.errorMessage
402
+ });
403
+ await this.#consolidatorStore.upsertState(scope, {
404
+ lastPhase: phase,
405
+ lastCompletedAt: this.#now(),
406
+ nextEligibleAt: this.#now() + this.#config.ceilings.cooldownMs
407
+ });
408
+ }
409
+ await this.#lockManager.release(scope, runId);
410
+ return this.#emit(outcome, scope, reason);
411
+ }
412
+ async #dispatch(phase, scope) {
413
+ this.#lastDispatchMessageIds = [];
414
+ const lastProcessedMessageId = (this.#consolidatorStore !== null ? await this.#consolidatorStore.getState(scope) : null)?.lastProcessedMessageId ?? null;
415
+ if (phase === "light") return await runLightPhase({
416
+ store: this.#store,
417
+ consolidatorStore: this.#consolidatorStore,
418
+ tracer: this.#tracer,
419
+ scope,
420
+ now: this.#now,
421
+ decayTauDays: this.#config.decayTauDays,
422
+ decayArchiveThreshold: this.#config.decayArchiveThreshold,
423
+ decayCapacity: this.#config.decayCapacity,
424
+ salienceWeights: this.#config.salienceWeights,
425
+ noiseFilters: this.#config.noiseFilters,
426
+ maxBatchSize: this.#config.maxStandardBatchSize,
427
+ lastProcessedMessageId,
428
+ tier: this.#config.tier
429
+ });
430
+ if (phase === "standard") {
431
+ const standardProvider = this.#cheapProvider ?? this.#provider;
432
+ if (standardProvider === null) throw new ProviderNotConfiguredError("standard");
433
+ const session = this.#store.session;
434
+ const rawBatch = typeof session.listMessagesSince === "function" ? await session.listMessagesSince(scope, lastProcessedMessageId, this.#config.maxStandardBatchSize) : [];
435
+ this.#lastDispatchMessageIds = rawBatch.map((r) => r.id);
436
+ const out = await runStandardPhase({
437
+ semantic: this.#semantic,
438
+ episodic: this.#episodic,
439
+ formEpisodes: this.#config.formEpisodes,
440
+ importanceScoring: this.#config.importanceScoring,
441
+ autoPromoteExtraction: this.#config.autoPromoteExtraction,
442
+ contextualRetrieval: this.#config.contextualRetrieval,
443
+ store: this.#store,
444
+ consolidatorStore: this.#consolidatorStore,
445
+ provider: standardProvider,
446
+ tracer: this.#tracer,
447
+ scope,
448
+ cheapModel: this.#config.cheapModel,
449
+ noiseFilters: this.#config.noiseFilters,
450
+ maxBatchSize: this.#config.maxStandardBatchSize,
451
+ lastProcessedMessageId,
452
+ budget: this.#budget,
453
+ tier: this.#config.tier === "free" ? "cheap" : this.#config.tier,
454
+ now: this.#now,
455
+ batch: rawBatch
456
+ });
457
+ const cursor = tipMessageId(rawBatch);
458
+ if (cursor !== null && this.#consolidatorStore !== null) await this.#consolidatorStore.upsertState(scope, { lastProcessedMessageId: cursor });
459
+ return out;
460
+ }
461
+ const deepProvider = this.#deepProvider ?? this.#provider;
462
+ if (deepProvider === null) throw new ProviderNotConfiguredError("deep");
463
+ const deepOut = await runDeepPhase({
464
+ store: this.#store,
465
+ consolidatorStore: this.#consolidatorStore,
466
+ provider: deepProvider,
467
+ tracer: this.#tracer,
468
+ scope,
469
+ deepModel: this.#config.deepModel,
470
+ maxConflictsPerRun: this.#config.maxDeepConflictsPerRun,
471
+ budget: this.#budget,
472
+ tier: this.#config.tier === "free" || this.#config.tier === "cheap" ? "standard" : this.#config.tier,
473
+ now: this.#now
474
+ });
475
+ const insightStore = this.#store.insights;
476
+ if (this.#config.reflection && this.#episodic !== null && insightStore !== void 0) {
477
+ const priorWatermark = this.#consolidatorStore !== null ? (await this.#consolidatorStore.getState(scope))?.reflectionWatermark ?? null : null;
478
+ const reflection = await runReflectionPass({
479
+ provider: deepProvider,
480
+ tracer: this.#tracer,
481
+ scope,
482
+ semantic: this.#semantic,
483
+ episodic: this.#episodic,
484
+ insights: insightStore,
485
+ budget: this.#budget,
486
+ importanceThreshold: this.#config.importanceThreshold,
487
+ reflectionWatermark: priorWatermark,
488
+ maxQuestions: this.#config.reflectionMaxQuestions,
489
+ now: this.#now
490
+ });
491
+ if (this.#consolidatorStore !== null && reflection.nextWatermark !== priorWatermark) await this.#consolidatorStore.upsertState(scope, { reflectionWatermark: reflection.nextWatermark });
492
+ return {
493
+ ...deepOut,
494
+ insightsCreated: reflection.insightsCreated,
495
+ llmTokensUsed: deepOut.llmTokensUsed + reflection.tokens,
496
+ llmCostUsd: deepOut.llmCostUsd === null && reflection.costUsd === 0 ? null : (deepOut.llmCostUsd ?? 0) + reflection.costUsd
497
+ };
498
+ }
499
+ return deepOut;
500
+ }
501
+ #emit(outcome, scope, reason) {
502
+ for (const listener of this.#listeners) try {
503
+ listener({
504
+ ...outcome,
505
+ scope,
506
+ trigger: reason
507
+ });
508
+ } catch {}
509
+ return outcome;
510
+ }
511
+ };
512
+ function skipOutcome(phase, reason) {
513
+ return {
514
+ phase,
515
+ status: "deferred",
516
+ factsCreated: 0,
517
+ factsUpdated: 0,
518
+ conflictsResolved: 0,
519
+ episodesFormed: 0,
520
+ insightsCreated: 0,
521
+ noiseFilteredCount: 0,
522
+ emptyExtractions: 0,
523
+ llmTokensUsed: 0,
524
+ llmCostUsd: null,
525
+ errorMessage: `phase skipped — ${reason}`
526
+ };
527
+ }
528
+ /** Resolve operator-supplied options into a fully-defaulted config. */
529
+ function resolveConfig(opts) {
530
+ const tier = opts.tier ?? "free";
531
+ const preset = CONSOLIDATOR_TIER_DEFAULTS[tier];
532
+ if (preset === void 0) throw new Error(`[graphorin/memory] unknown consolidator tier '${tier}'`);
533
+ const ceilings = {
534
+ ...preset.ceilings,
535
+ ...opts.ceilings ?? {}
536
+ };
537
+ const phases = opts.phases ?? preset.phases;
538
+ if (tier === "custom") {
539
+ const missing = [];
540
+ if (ceilings.maxTokensPerDay <= 0) missing.push("ceilings.maxTokensPerDay");
541
+ if (ceilings.maxCostPerDay <= 0) missing.push("ceilings.maxCostPerDay");
542
+ if (phases.length === 0) missing.push("phases");
543
+ if (missing.length > 0) throw new CustomTierMisconfiguredError(missing);
544
+ }
545
+ return Object.freeze({
546
+ triggers: Object.freeze([...opts.triggers ?? defaultTriggers()]),
547
+ tier,
548
+ phases: Object.freeze([...phases]),
549
+ ceilings,
550
+ onExceed: opts.onExceed ?? preset.onExceed,
551
+ cheapModel: opts.cheapModel ?? preset.cheapModel,
552
+ deepModel: opts.deepModel ?? preset.deepModel,
553
+ budgetResetSemantics: opts.budgetResetSemantics ?? "utc",
554
+ noiseFilters: Object.freeze([...opts.noiseFilters ?? ["default"]]),
555
+ lockWaitMs: opts.lockWaitMs ?? 3e4,
556
+ decayTauDays: opts.decayTauDays ?? 7,
557
+ decayArchiveThreshold: opts.decayArchiveThreshold ?? .05,
558
+ decayCapacity: opts.decayCapacity ?? null,
559
+ salienceWeights: opts.salienceWeights ?? DEFAULT_SALIENCE_WEIGHTS,
560
+ maxStandardBatchSize: opts.maxStandardBatchSize ?? 50,
561
+ maxDeepConflictsPerRun: opts.maxDeepConflictsPerRun ?? 20,
562
+ dlqMaxRetries: opts.dlqMaxRetries ?? 5,
563
+ dlqBaseBackoffMs: opts.dlqBaseBackoffMs ?? 6e4,
564
+ dlqMaxBackoffMs: opts.dlqMaxBackoffMs ?? 3600 * 1e3,
565
+ formEpisodes: opts.formEpisodes ?? preset.formEpisodes,
566
+ importanceScoring: opts.importanceScoring ?? preset.importanceScoring,
567
+ autoPromoteExtraction: opts.autoPromoteExtraction ?? false,
568
+ reflection: opts.reflection ?? preset.reflection,
569
+ importanceThreshold: opts.importanceThreshold ?? preset.importanceThreshold,
570
+ reflectionMaxQuestions: opts.reflectionMaxQuestions ?? preset.reflectionMaxQuestions,
571
+ contextualRetrieval: opts.contextualRetrieval ?? preset.contextualRetrieval
572
+ });
573
+ }
574
+ function defaultTriggers() {
575
+ return ["idle:5m", "cron:0 4 * * *"];
576
+ }
577
+
578
+ //#endregion
579
+ export { createConsolidator };
580
+ //# sourceMappingURL=runtime.js.map