@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,192 @@
1
+ import { enLocalePack } from "../conflict/locale-packs/en.js";
2
+ import "../conflict/locale-packs/index.js";
3
+ import { stage1ExactDedup } from "../conflict/stages/stage1-exact-dedup.js";
4
+ import { stage2EmbeddingThreeZone } from "../conflict/stages/stage2-embedding-three-zone.js";
5
+ import { DEFAULT_CONFLICT_THRESHOLDS } from "../conflict/types.js";
6
+ import "../conflict/index.js";
7
+
8
+ //#region src/consolidator/reconcile.ts
9
+ /**
10
+ * Classify a candidate against its nearest neighbours using the conflict
11
+ * pipeline's first two (cheap, LLM-free) stages. Reuses
12
+ * {@link stage1ExactDedup} + {@link stage2EmbeddingThreeZone} verbatim so
13
+ * the zone thresholds stay aligned with the inline write path.
14
+ *
15
+ * @stable
16
+ */
17
+ async function preFilterCandidate(candidateText, neighbors, opts = {}) {
18
+ const thresholds = opts.thresholds ?? DEFAULT_CONFLICT_THRESHOLDS;
19
+ const localePack = opts.localePack ?? enLocalePack;
20
+ const ctx = {
21
+ candidate: synthCandidate(candidateText),
22
+ existing: neighbors,
23
+ localePack,
24
+ thresholds
25
+ };
26
+ const s1 = await stage1ExactDedup.evaluate(ctx);
27
+ if (s1.kind === "dedup") return {
28
+ route: "noop",
29
+ targetId: s1.existingId,
30
+ ...s1.similarity !== void 0 ? { similarity: s1.similarity } : {},
31
+ reason: s1.reason ?? "exact-hash-match"
32
+ };
33
+ const s2 = await stage2EmbeddingThreeZone.evaluate(ctx);
34
+ if (s2.kind === "dedup") return {
35
+ route: "noop",
36
+ targetId: s2.existingId,
37
+ ...s2.similarity !== void 0 ? { similarity: s2.similarity } : {},
38
+ reason: s2.reason ?? "embedding-zone"
39
+ };
40
+ if (s2.kind === "admit") return {
41
+ route: "add",
42
+ reason: s2.reason ?? "embedding-cold-zone"
43
+ };
44
+ return { route: "reconcile" };
45
+ }
46
+ /**
47
+ * System prompt for the reconcile pass. Mirrors the deep-phase judge
48
+ * style but expands the decision space to the full ADD/UPDATE/NOOP/
49
+ * CONFLICT loop and asks for the `targetId` of the resolved neighbour.
50
+ *
51
+ * @internal
52
+ */
53
+ const RECONCILE_SYSTEM_PROMPT = [
54
+ "You reconcile a candidate memory against the user's existing related memories.",
55
+ "Return strictly JSON: { \"action\": \"add\" | \"update\" | \"noop\" | \"conflict\", \"targetId\"?: string, \"reason\": string }.",
56
+ "Use \"update\" when the candidate is a newer version of an existing memory (a changed preference, location, job, or fact).",
57
+ "Use \"noop\" when the candidate adds nothing new (a duplicate or subset of an existing memory).",
58
+ "Use \"conflict\" when the candidate contradicts an existing memory and the older one should be closed.",
59
+ "Use \"add\" when the candidate is independent of every listed memory, or when you are unsure.",
60
+ "For \"update\", \"noop\", and \"conflict\", set \"targetId\" to the id of the existing memory you are resolving against."
61
+ ].join(" ");
62
+ /**
63
+ * Run one reconcile pass. The decision is always safe to apply: parse
64
+ * failures and dangling `targetId`s degrade to an additive write.
65
+ *
66
+ * @stable
67
+ */
68
+ async function reconcileCandidate(args) {
69
+ const request = buildReconcileRequest(args);
70
+ const response = await args.provider.generate(request);
71
+ const usage = response.usage;
72
+ const promptTokens = usage.promptTokens ?? 0;
73
+ const completionTokens = usage.completionTokens ?? 0;
74
+ const totalTokens = promptTokens + completionTokens + (usage.reasoningTokens ?? 0);
75
+ const validIds = new Set(args.neighbors.map((n) => n.id));
76
+ return {
77
+ decision: parseReconcile(response.text, validIds),
78
+ usage: {
79
+ promptTokens,
80
+ completionTokens,
81
+ totalTokens
82
+ }
83
+ };
84
+ }
85
+ /**
86
+ * Parse the reconcile model output into a {@link ReconcileDecision}.
87
+ * Tolerates fenced blocks + trailing commentary; an unparseable body,
88
+ * an unknown action, or a `targetId` that is not in `validTargetIds`
89
+ * all degrade to `{ action: 'add' }` (audited via the reason).
90
+ *
91
+ * @internal
92
+ */
93
+ function parseReconcile(text, validTargetIds) {
94
+ const fallback = {
95
+ action: "add",
96
+ reason: "reconcile-parse-failure"
97
+ };
98
+ if (text === void 0 || text.length === 0) return fallback;
99
+ const candidate = stripFence(text).trim();
100
+ if (candidate.length === 0) return fallback;
101
+ let parsed;
102
+ try {
103
+ parsed = JSON.parse(candidate);
104
+ } catch {
105
+ const slice = sliceJsonObject(candidate);
106
+ if (slice === null) return fallback;
107
+ try {
108
+ parsed = JSON.parse(slice);
109
+ } catch {
110
+ return fallback;
111
+ }
112
+ }
113
+ if (parsed === null || typeof parsed !== "object") return fallback;
114
+ const obj = parsed;
115
+ const reason = typeof obj.reason === "string" && obj.reason.length > 0 ? obj.reason : void 0;
116
+ if (obj.action === "add") return {
117
+ action: "add",
118
+ ...reason !== void 0 ? { reason } : {}
119
+ };
120
+ if (obj.action === "update" || obj.action === "noop" || obj.action === "conflict") {
121
+ const targetId = typeof obj.targetId === "string" ? obj.targetId : null;
122
+ if (targetId === null || !validTargetIds.has(targetId)) return {
123
+ action: "add",
124
+ reason: "reconcile-invalid-target"
125
+ };
126
+ if (obj.action === "noop") return {
127
+ action: "noop",
128
+ targetId,
129
+ ...reason !== void 0 ? { reason } : {}
130
+ };
131
+ return {
132
+ action: obj.action,
133
+ targetId,
134
+ reason: reason ?? `reconcile-${obj.action}`
135
+ };
136
+ }
137
+ return fallback;
138
+ }
139
+ function buildReconcileRequest(args) {
140
+ const neighborLines = args.neighbors.map((n, i) => {
141
+ const vf = n.validFrom !== void 0 ? ` (validFrom: ${n.validFrom})` : "";
142
+ return `${i + 1}. [id: ${n.id}]${vf} ${n.text}`;
143
+ }).join("\n");
144
+ return {
145
+ messages: [{
146
+ role: "user",
147
+ content: [
148
+ `Candidate memory: ${args.candidateText}`,
149
+ "",
150
+ "Existing related memories:",
151
+ neighborLines.length > 0 ? neighborLines : "(none)"
152
+ ].join("\n")
153
+ }],
154
+ systemMessage: RECONCILE_SYSTEM_PROMPT,
155
+ temperature: 0,
156
+ maxTokens: 256,
157
+ metadata: {
158
+ userId: args.scope.userId,
159
+ ...args.scope.sessionId !== void 0 ? { sessionId: args.scope.sessionId } : {},
160
+ ...args.scope.agentId !== void 0 ? { agentId: args.scope.agentId } : {}
161
+ },
162
+ outputType: { kind: "structured" }
163
+ };
164
+ }
165
+ /**
166
+ * Minimal candidate `Fact` for the pre-filter stage context. Stage 1
167
+ * reads only `text`; Stage 2 reads only the neighbour scores — the
168
+ * other fields are never inspected, so a synthetic id/scope is safe.
169
+ */
170
+ function synthCandidate(text) {
171
+ return {
172
+ id: "__reconcile_candidate__",
173
+ kind: "semantic",
174
+ userId: "__reconcile_candidate__",
175
+ sensitivity: "internal",
176
+ text,
177
+ createdAt: (/* @__PURE__ */ new Date(0)).toISOString()
178
+ };
179
+ }
180
+ function stripFence(text) {
181
+ return /^```[^\n]*\n([\s\S]*?)\n```/u.exec(text.trim())?.[1] ?? text;
182
+ }
183
+ function sliceJsonObject(text) {
184
+ const start = text.indexOf("{");
185
+ const end = text.lastIndexOf("}");
186
+ if (start < 0 || end < start) return null;
187
+ return text.slice(start, end + 1);
188
+ }
189
+
190
+ //#endregion
191
+ export { preFilterCandidate, reconcileCandidate };
192
+ //# sourceMappingURL=reconcile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reconcile.js","names":["ctx: StageContext","fallback: ReconcileDecision","parsed: unknown"],"sources":["../../src/consolidator/reconcile.ts"],"sourcesContent":["/**\n * Neighbour-aware write reconciliation (P0-3) — the `reconcile` half of\n * Mem0's extract→reconcile loop (arXiv:2504.19413), with Graphorin's\n * bi-temporal twist.\n *\n * Two pieces live here:\n *\n * - {@link preFilterCandidate} — a *cheap*, LLM-free classifier that\n * reuses the conflict pipeline's Stage 1 (exact-dedup) + Stage 2\n * (embedding three-zone) over the candidate's nearest neighbours.\n * Clear hot / near-dup neighbours short-circuit to `noop`; a clearly\n * cold field (or no neighbours at all) short-circuits to `add`. Only\n * the ambiguous CONFLICT-CHECK mid-zone is routed to `reconcile`, so\n * the consolidator spends an LLM call only where it actually helps.\n *\n * - {@link reconcileCandidate} — one provider pass that, with the\n * neighbours *in view*, chooses ADD / UPDATE / NOOP / CONFLICT.\n * Parsing is defensive: malformed output, an unknown action, or a\n * `targetId` that is not one of the supplied neighbours all fall back\n * to a safe additive write (audited) so a flaky model never wedges\n * the pipeline or rewrites the wrong fact.\n *\n * @packageDocumentation\n */\n\nimport type { Fact, MemoryHit, Provider, ProviderRequest, SessionScope } from '@graphorin/core';\nimport {\n type ConflictThresholds,\n DEFAULT_CONFLICT_THRESHOLDS,\n type ReconcileDecision,\n type StageContext,\n} from '../conflict/index.js';\nimport { enLocalePack, type LocalePack } from '../conflict/locale-packs/index.js';\nimport { stage1ExactDedup } from '../conflict/stages/stage1-exact-dedup.js';\nimport { stage2EmbeddingThreeZone } from '../conflict/stages/stage2-embedding-three-zone.js';\n\n/**\n * Pre-filter routing decision. `add` and `noop` are resolved without an\n * LLM call; `reconcile` means the candidate landed in the ambiguous\n * mid-zone and should be handed to {@link reconcileCandidate}.\n *\n * @stable\n */\nexport type PreFilterRoute =\n | { readonly route: 'add'; readonly reason: string }\n | {\n readonly route: 'noop';\n readonly targetId: string;\n readonly similarity?: number;\n readonly reason: string;\n }\n | { readonly route: 'reconcile' };\n\n/**\n * Classify a candidate against its nearest neighbours using the conflict\n * pipeline's first two (cheap, LLM-free) stages. Reuses\n * {@link stage1ExactDedup} + {@link stage2EmbeddingThreeZone} verbatim so\n * the zone thresholds stay aligned with the inline write path.\n *\n * @stable\n */\nexport async function preFilterCandidate(\n candidateText: string,\n neighbors: ReadonlyArray<MemoryHit<Fact>>,\n opts: { readonly thresholds?: ConflictThresholds; readonly localePack?: LocalePack } = {},\n): Promise<PreFilterRoute> {\n const thresholds = opts.thresholds ?? DEFAULT_CONFLICT_THRESHOLDS;\n const localePack = opts.localePack ?? enLocalePack;\n const ctx: StageContext = {\n candidate: synthCandidate(candidateText),\n existing: neighbors,\n localePack,\n thresholds,\n };\n\n const s1 = await stage1ExactDedup.evaluate(ctx);\n if (s1.kind === 'dedup') {\n return {\n route: 'noop',\n targetId: s1.existingId,\n ...(s1.similarity !== undefined ? { similarity: s1.similarity } : {}),\n reason: s1.reason ?? 'exact-hash-match',\n };\n }\n\n const s2 = await stage2EmbeddingThreeZone.evaluate(ctx);\n if (s2.kind === 'dedup') {\n return {\n route: 'noop',\n targetId: s2.existingId,\n ...(s2.similarity !== undefined ? { similarity: s2.similarity } : {}),\n reason: s2.reason ?? 'embedding-zone',\n };\n }\n if (s2.kind === 'admit') {\n return { route: 'add', reason: s2.reason ?? 'embedding-cold-zone' };\n }\n // s2.kind === 'continue' → CONFLICT-CHECK mid-zone → spend an LLM call.\n return { route: 'reconcile' };\n}\n\n/** A neighbour surfaced to the reconcile prompt. */\nexport interface ReconcileNeighbor {\n readonly id: string;\n readonly text: string;\n readonly validFrom?: string;\n}\n\n/** Token usage for the single reconcile provider call (budget accounting). */\nexport interface ReconcileUsage {\n readonly promptTokens: number;\n readonly completionTokens: number;\n readonly totalTokens: number;\n}\n\n/** Result of {@link reconcileCandidate}: the decision + its token cost. */\nexport interface ReconcileResult {\n readonly decision: ReconcileDecision;\n readonly usage: ReconcileUsage;\n}\n\n/** Inputs to {@link reconcileCandidate}. */\nexport interface ReconcileCandidateArgs {\n readonly candidateText: string;\n readonly neighbors: ReadonlyArray<ReconcileNeighbor>;\n readonly provider: Provider;\n readonly scope: SessionScope;\n}\n\n/**\n * System prompt for the reconcile pass. Mirrors the deep-phase judge\n * style but expands the decision space to the full ADD/UPDATE/NOOP/\n * CONFLICT loop and asks for the `targetId` of the resolved neighbour.\n *\n * @internal\n */\nexport const RECONCILE_SYSTEM_PROMPT = [\n \"You reconcile a candidate memory against the user's existing related memories.\",\n 'Return strictly JSON: { \"action\": \"add\" | \"update\" | \"noop\" | \"conflict\", \"targetId\"?: string, \"reason\": string }.',\n 'Use \"update\" when the candidate is a newer version of an existing memory (a changed preference, location, job, or fact).',\n 'Use \"noop\" when the candidate adds nothing new (a duplicate or subset of an existing memory).',\n 'Use \"conflict\" when the candidate contradicts an existing memory and the older one should be closed.',\n 'Use \"add\" when the candidate is independent of every listed memory, or when you are unsure.',\n 'For \"update\", \"noop\", and \"conflict\", set \"targetId\" to the id of the existing memory you are resolving against.',\n].join(' ');\n\n/**\n * Run one reconcile pass. The decision is always safe to apply: parse\n * failures and dangling `targetId`s degrade to an additive write.\n *\n * @stable\n */\nexport async function reconcileCandidate(args: ReconcileCandidateArgs): Promise<ReconcileResult> {\n const request = buildReconcileRequest(args);\n const response = await args.provider.generate(request);\n const usage = response.usage;\n const promptTokens = usage.promptTokens ?? 0;\n const completionTokens = usage.completionTokens ?? 0;\n const totalTokens = promptTokens + completionTokens + (usage.reasoningTokens ?? 0);\n const validIds = new Set(args.neighbors.map((n) => n.id));\n const decision = parseReconcile(response.text, validIds);\n return { decision, usage: { promptTokens, completionTokens, totalTokens } };\n}\n\n/**\n * Parse the reconcile model output into a {@link ReconcileDecision}.\n * Tolerates fenced blocks + trailing commentary; an unparseable body,\n * an unknown action, or a `targetId` that is not in `validTargetIds`\n * all degrade to `{ action: 'add' }` (audited via the reason).\n *\n * @internal\n */\nexport function parseReconcile(\n text: string | undefined,\n validTargetIds: ReadonlySet<string>,\n): ReconcileDecision {\n const fallback: ReconcileDecision = { action: 'add', reason: 'reconcile-parse-failure' };\n if (text === undefined || text.length === 0) return fallback;\n const candidate = stripFence(text).trim();\n if (candidate.length === 0) return fallback;\n let parsed: unknown;\n try {\n parsed = JSON.parse(candidate);\n } catch {\n const slice = sliceJsonObject(candidate);\n if (slice === null) return fallback;\n try {\n parsed = JSON.parse(slice);\n } catch {\n return fallback;\n }\n }\n if (parsed === null || typeof parsed !== 'object') return fallback;\n const obj = parsed as { action?: unknown; targetId?: unknown; reason?: unknown };\n const reason = typeof obj.reason === 'string' && obj.reason.length > 0 ? obj.reason : undefined;\n if (obj.action === 'add') {\n return { action: 'add', ...(reason !== undefined ? { reason } : {}) };\n }\n if (obj.action === 'update' || obj.action === 'noop' || obj.action === 'conflict') {\n const targetId = typeof obj.targetId === 'string' ? obj.targetId : null;\n if (targetId === null || !validTargetIds.has(targetId)) {\n // The model referenced a fact that is not one of the supplied\n // neighbours — never rewrite an unverified id; add instead.\n return { action: 'add', reason: 'reconcile-invalid-target' };\n }\n if (obj.action === 'noop') {\n return { action: 'noop', targetId, ...(reason !== undefined ? { reason } : {}) };\n }\n return { action: obj.action, targetId, reason: reason ?? `reconcile-${obj.action}` };\n }\n return fallback;\n}\n\nfunction buildReconcileRequest(args: ReconcileCandidateArgs): ProviderRequest {\n const neighborLines = args.neighbors\n .map((n, i) => {\n const vf = n.validFrom !== undefined ? ` (validFrom: ${n.validFrom})` : '';\n return `${i + 1}. [id: ${n.id}]${vf} ${n.text}`;\n })\n .join('\\n');\n const userBlock = [\n `Candidate memory: ${args.candidateText}`,\n '',\n 'Existing related memories:',\n neighborLines.length > 0 ? neighborLines : '(none)',\n ].join('\\n');\n return {\n messages: [{ role: 'user', content: userBlock }],\n systemMessage: RECONCILE_SYSTEM_PROMPT,\n temperature: 0,\n // MCON-14: per-call output cap — the decision shape is tiny.\n maxTokens: 256,\n metadata: {\n userId: args.scope.userId,\n ...(args.scope.sessionId !== undefined ? { sessionId: args.scope.sessionId } : {}),\n ...(args.scope.agentId !== undefined ? { agentId: args.scope.agentId } : {}),\n },\n outputType: { kind: 'structured' },\n };\n}\n\n/**\n * Minimal candidate `Fact` for the pre-filter stage context. Stage 1\n * reads only `text`; Stage 2 reads only the neighbour scores — the\n * other fields are never inspected, so a synthetic id/scope is safe.\n */\nfunction synthCandidate(text: string): Fact {\n return {\n id: '__reconcile_candidate__',\n kind: 'semantic',\n userId: '__reconcile_candidate__',\n sensitivity: 'internal',\n text,\n createdAt: new Date(0).toISOString(),\n };\n}\n\nfunction stripFence(text: string): string {\n const match = /^```[^\\n]*\\n([\\s\\S]*?)\\n```/u.exec(text.trim());\n return match?.[1] ?? text;\n}\n\nfunction sliceJsonObject(text: string): string | null {\n const start = text.indexOf('{');\n const end = text.lastIndexOf('}');\n if (start < 0 || end < start) return null;\n return text.slice(start, end + 1);\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA6DA,eAAsB,mBACpB,eACA,WACA,OAAuF,EAAE,EAChE;CACzB,MAAM,aAAa,KAAK,cAAc;CACtC,MAAM,aAAa,KAAK,cAAc;CACtC,MAAMA,MAAoB;EACxB,WAAW,eAAe,cAAc;EACxC,UAAU;EACV;EACA;EACD;CAED,MAAM,KAAK,MAAM,iBAAiB,SAAS,IAAI;AAC/C,KAAI,GAAG,SAAS,QACd,QAAO;EACL,OAAO;EACP,UAAU,GAAG;EACb,GAAI,GAAG,eAAe,SAAY,EAAE,YAAY,GAAG,YAAY,GAAG,EAAE;EACpE,QAAQ,GAAG,UAAU;EACtB;CAGH,MAAM,KAAK,MAAM,yBAAyB,SAAS,IAAI;AACvD,KAAI,GAAG,SAAS,QACd,QAAO;EACL,OAAO;EACP,UAAU,GAAG;EACb,GAAI,GAAG,eAAe,SAAY,EAAE,YAAY,GAAG,YAAY,GAAG,EAAE;EACpE,QAAQ,GAAG,UAAU;EACtB;AAEH,KAAI,GAAG,SAAS,QACd,QAAO;EAAE,OAAO;EAAO,QAAQ,GAAG,UAAU;EAAuB;AAGrE,QAAO,EAAE,OAAO,aAAa;;;;;;;;;AAsC/B,MAAa,0BAA0B;CACrC;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC,KAAK,IAAI;;;;;;;AAQX,eAAsB,mBAAmB,MAAwD;CAC/F,MAAM,UAAU,sBAAsB,KAAK;CAC3C,MAAM,WAAW,MAAM,KAAK,SAAS,SAAS,QAAQ;CACtD,MAAM,QAAQ,SAAS;CACvB,MAAM,eAAe,MAAM,gBAAgB;CAC3C,MAAM,mBAAmB,MAAM,oBAAoB;CACnD,MAAM,cAAc,eAAe,oBAAoB,MAAM,mBAAmB;CAChF,MAAM,WAAW,IAAI,IAAI,KAAK,UAAU,KAAK,MAAM,EAAE,GAAG,CAAC;AAEzD,QAAO;EAAE,UADQ,eAAe,SAAS,MAAM,SAAS;EACrC,OAAO;GAAE;GAAc;GAAkB;GAAa;EAAE;;;;;;;;;;AAW7E,SAAgB,eACd,MACA,gBACmB;CACnB,MAAMC,WAA8B;EAAE,QAAQ;EAAO,QAAQ;EAA2B;AACxF,KAAI,SAAS,UAAa,KAAK,WAAW,EAAG,QAAO;CACpD,MAAM,YAAY,WAAW,KAAK,CAAC,MAAM;AACzC,KAAI,UAAU,WAAW,EAAG,QAAO;CACnC,IAAIC;AACJ,KAAI;AACF,WAAS,KAAK,MAAM,UAAU;SACxB;EACN,MAAM,QAAQ,gBAAgB,UAAU;AACxC,MAAI,UAAU,KAAM,QAAO;AAC3B,MAAI;AACF,YAAS,KAAK,MAAM,MAAM;UACpB;AACN,UAAO;;;AAGX,KAAI,WAAW,QAAQ,OAAO,WAAW,SAAU,QAAO;CAC1D,MAAM,MAAM;CACZ,MAAM,SAAS,OAAO,IAAI,WAAW,YAAY,IAAI,OAAO,SAAS,IAAI,IAAI,SAAS;AACtF,KAAI,IAAI,WAAW,MACjB,QAAO;EAAE,QAAQ;EAAO,GAAI,WAAW,SAAY,EAAE,QAAQ,GAAG,EAAE;EAAG;AAEvE,KAAI,IAAI,WAAW,YAAY,IAAI,WAAW,UAAU,IAAI,WAAW,YAAY;EACjF,MAAM,WAAW,OAAO,IAAI,aAAa,WAAW,IAAI,WAAW;AACnE,MAAI,aAAa,QAAQ,CAAC,eAAe,IAAI,SAAS,CAGpD,QAAO;GAAE,QAAQ;GAAO,QAAQ;GAA4B;AAE9D,MAAI,IAAI,WAAW,OACjB,QAAO;GAAE,QAAQ;GAAQ;GAAU,GAAI,WAAW,SAAY,EAAE,QAAQ,GAAG,EAAE;GAAG;AAElF,SAAO;GAAE,QAAQ,IAAI;GAAQ;GAAU,QAAQ,UAAU,aAAa,IAAI;GAAU;;AAEtF,QAAO;;AAGT,SAAS,sBAAsB,MAA+C;CAC5E,MAAM,gBAAgB,KAAK,UACxB,KAAK,GAAG,MAAM;EACb,MAAM,KAAK,EAAE,cAAc,SAAY,gBAAgB,EAAE,UAAU,KAAK;AACxE,SAAO,GAAG,IAAI,EAAE,SAAS,EAAE,GAAG,GAAG,GAAG,GAAG,EAAE;GACzC,CACD,KAAK,KAAK;AAOb,QAAO;EACL,UAAU,CAAC;GAAE,MAAM;GAAQ,SAPX;IAChB,qBAAqB,KAAK;IAC1B;IACA;IACA,cAAc,SAAS,IAAI,gBAAgB;IAC5C,CAAC,KAAK,KAAK;GAEqC,CAAC;EAChD,eAAe;EACf,aAAa;EAEb,WAAW;EACX,UAAU;GACR,QAAQ,KAAK,MAAM;GACnB,GAAI,KAAK,MAAM,cAAc,SAAY,EAAE,WAAW,KAAK,MAAM,WAAW,GAAG,EAAE;GACjF,GAAI,KAAK,MAAM,YAAY,SAAY,EAAE,SAAS,KAAK,MAAM,SAAS,GAAG,EAAE;GAC5E;EACD,YAAY,EAAE,MAAM,cAAc;EACnC;;;;;;;AAQH,SAAS,eAAe,MAAoB;AAC1C,QAAO;EACL,IAAI;EACJ,MAAM;EACN,QAAQ;EACR,aAAa;EACb;EACA,4BAAW,IAAI,KAAK,EAAE,EAAC,aAAa;EACrC;;AAGH,SAAS,WAAW,MAAsB;AAExC,QADc,+BAA+B,KAAK,KAAK,MAAM,CAAC,GAC/C,MAAM;;AAGvB,SAAS,gBAAgB,MAA6B;CACpD,MAAM,QAAQ,KAAK,QAAQ,IAAI;CAC/B,MAAM,MAAM,KAAK,YAAY,IAAI;AACjC,KAAI,QAAQ,KAAK,MAAM,MAAO,QAAO;AACrC,QAAO,KAAK,MAAM,OAAO,MAAM,EAAE"}
@@ -0,0 +1,62 @@
1
+ import { ConsolidatorConfig, ConsolidatorPhase, ConsolidatorStatus, ConsolidatorTier, ConsolidatorTriggerReason, CreateConsolidatorOptions, PhaseListener, PhaseOutcome } from "./types.js";
2
+ import { RegisterTriggersResult, SchedulerLike } from "./scheduler.js";
3
+ import { SessionScope } from "@graphorin/core";
4
+
5
+ //#region src/consolidator/runtime.d.ts
6
+
7
+ /**
8
+ * Consolidator runtime surface returned by {@link createConsolidator}.
9
+ * Compatible with the placeholder shape so the facade can swap the
10
+ * implementation without breaking consumers.
11
+ *
12
+ * @stable
13
+ */
14
+ interface Consolidator {
15
+ start(): Promise<void>;
16
+ stop(): Promise<void>;
17
+ trigger(reason: ConsolidatorTriggerReason, scope: SessionScope): Promise<PhaseOutcome | null>;
18
+ status(): Promise<ConsolidatorStatus>;
19
+ /**
20
+ * Manual trigger for the requested phase. Skips phase gating + the
21
+ * idle/cron scheduler so admins can flush the queue on demand.
22
+ */
23
+ fireNow(phase: ConsolidatorPhase, scope?: SessionScope): Promise<PhaseOutcome | null>;
24
+ /** Replace the active tier — recomputes ceilings + phase set. */
25
+ setTier(tier: ConsolidatorTier): Promise<void>;
26
+ /** Pause the consolidator until the next budget reset. */
27
+ pause(): Promise<void>;
28
+ /** Resume after `pause()`. */
29
+ resume(): Promise<void>;
30
+ /** Subscribe to phase-finished notifications. Returns an unsubscribe. */
31
+ onPhaseFinished(listener: PhaseListener): () => void;
32
+ /**
33
+ * Record memory-pipeline LLM spend that happened OUTSIDE a phase run
34
+ * (MCON-15 — e.g. workflow induction) so the daily ceilings cover it.
35
+ * Counted under the deep-phase bucket.
36
+ */
37
+ recordExternalSpend(tokens: number, costUsd?: number): void;
38
+ /** Active config — frozen snapshot. */
39
+ config(): ConsolidatorConfig;
40
+ /**
41
+ * Register this consolidator's cron / idle triggers with a
42
+ * `@graphorin/triggers` scheduler so they fire `trigger(...)`
43
+ * automatically (the daemon ↔ triggers bridge — MCON-4). Uses the
44
+ * configured `defaultScope`; throws if none was set. Turn / event
45
+ * triggers are skipped (consumer-emitted). The standalone server calls
46
+ * this in `beforeStart`.
47
+ */
48
+ registerWithScheduler(scheduler: SchedulerLike): Promise<RegisterTriggersResult>;
49
+ /** True when `tier === 'free'`. */
50
+ isFree(): boolean;
51
+ /** Drain DLQ rows whose `nextRetryAt` <= now. */
52
+ drainDlq(scope: SessionScope): Promise<number>;
53
+ }
54
+ /**
55
+ * Build the runtime consolidator.
56
+ *
57
+ * @stable
58
+ */
59
+ declare function createConsolidator(opts: CreateConsolidatorOptions): Consolidator;
60
+ //#endregion
61
+ export { Consolidator, createConsolidator };
62
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.d.ts","names":[],"sources":["../../src/consolidator/runtime.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;;AAsGiC,UAtChB,YAAA,CAsCgB;EAAO,KAAA,EAAA,EArC7B,OAqC6B,CAAA,IAAA,CAAA;EAQxB,IAAA,EAAA,EA5CN,OA4CM,CAAA,IAAA,CAAkB;kBA3ChB,kCAAkC,eAAe,QAAQ;YAC/D,QAAQ;;;;;iBAKH,2BAA2B,eAAe,QAAQ;;gBAEnD,mBAAmB;;WAExB;;YAEC;;4BAEgB;;;;;;;;YAQhB;;;;;;;;;mCASuB,gBAAgB,QAAQ;;;;kBAIzC,eAAe;;;;;;;iBAQjB,kBAAA,OAAyB,4BAA4B"}