@yugenlab/vaayu 0.1.8 → 0.1.10

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 (29) hide show
  1. package/README.md +1 -1
  2. package/chunks/{chunk-7UOXFHEB.js → chunk-77725AR7.js} +416 -397
  3. package/chunks/{chunk-YSC77CKZ.js → chunk-AGK3A7R7.js} +2844 -3208
  4. package/chunks/{chunk-DOQMEQ5S.js → chunk-AS3DJFY3.js} +5 -5
  5. package/chunks/{chunk-NHRBVSN3.js → chunk-HIYHTWFW.js} +44 -9
  6. package/chunks/{chunk-IGBRBFXX.js → chunk-JGI4SDWS.js} +2 -2
  7. package/chunks/{chunk-D3RVJGO7.js → chunk-M7THR63C.js} +48 -74
  8. package/chunks/{chunk-OBYBBGHA.js → chunk-N22M7D4P.js} +118 -106
  9. package/chunks/{chunk-PJEYJQ2C.js → chunk-O4KV7TFP.js} +2 -2
  10. package/chunks/{chunk-S2HDNNC7.js → chunk-OT4G2L46.js} +552 -641
  11. package/chunks/chunk-TND3MU4Z.js +426 -0
  12. package/chunks/{chunk-LVE2EOOH.js → chunk-VJHNE47S.js} +84 -75
  13. package/chunks/{consolidation-indexer-CD6DS2HO.js → consolidation-indexer-VKQ6DNU3.js} +4 -4
  14. package/chunks/{day-consolidation-U3X6P4ZG.js → day-consolidation-BH3QU2SZ.js} +6 -2
  15. package/chunks/{graphrag-LAZSXLLI.js → graphrag-D7OXWAWD.js} +2 -2
  16. package/chunks/{hierarchical-temporal-search-ETXYYJZK.js → hierarchical-temporal-search-PVHVA3NZ.js} +2 -2
  17. package/chunks/{hybrid-search-TX6T3KYH.js → hybrid-search-G2NAJKJ7.js} +4 -4
  18. package/chunks/{periodic-consolidation-4MACZE6S.js → periodic-consolidation-LMYMNS4Q.js} +2 -2
  19. package/chunks/{recall-IUPQCBYP.js → recall-ZNL4DJ2L.js} +3 -3
  20. package/chunks/{search-HHSVHBXC.js → search-35JMSGUT.js} +3 -3
  21. package/chunks/{session-store-NDUDYAC7.js → session-store-3BRPGC6P.js} +2 -2
  22. package/chunks/{src-ZAKUL232.js → src-Y3TGMINC.js} +12 -12
  23. package/chunks/vasana-engine-MU25OQ23.js +30 -0
  24. package/gateway.js +492 -226
  25. package/package.json +1 -1
  26. package/vaayu-mark-npm.png +0 -0
  27. package/chunks/chunk-TEQKXGIK.js +0 -752
  28. package/chunks/vasana-engine-G6BPOFX7.js +0 -10
  29. package/vaayu-mark.png +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  blobToVector,
3
3
  vectorToBlob
4
- } from "./chunk-LVE2EOOH.js";
4
+ } from "./chunk-VJHNE47S.js";
5
5
  import {
6
6
  EmbeddingService,
7
7
  cosineSimilarity,
@@ -186,7 +186,7 @@ async function backfillConsolidationIndices() {
186
186
  db.prepare("SELECT id FROM embeddings WHERE source_type IN ('daily_summary', 'monthly_summary', 'yearly_summary')").all().map((r) => r.id)
187
187
  );
188
188
  try {
189
- const { listDayFiles, readDayFile } = await import("./day-consolidation-U3X6P4ZG.js");
189
+ const { listDayFiles, readDayFile } = await import("./day-consolidation-BH3QU2SZ.js");
190
190
  const dayFiles = listDayFiles();
191
191
  for (const date of dayFiles) {
192
192
  const id = buildEmbeddingId("daily", date);
@@ -200,8 +200,8 @@ async function backfillConsolidationIndices() {
200
200
  } catch {
201
201
  }
202
202
  try {
203
- const { PeriodicConsolidation } = await import("./periodic-consolidation-4MACZE6S.js");
204
- const { listSessionProjects } = await import("./session-store-NDUDYAC7.js");
203
+ const { PeriodicConsolidation } = await import("./periodic-consolidation-LMYMNS4Q.js");
204
+ const { listSessionProjects } = await import("./session-store-3BRPGC6P.js");
205
205
  const projectEntries = listSessionProjects();
206
206
  for (const entry of projectEntries) {
207
207
  const project = entry.project;
@@ -237,4 +237,4 @@ export {
237
237
  searchConsolidationSummaries,
238
238
  backfillConsolidationIndices
239
239
  };
240
- //# sourceMappingURL=chunk-DOQMEQ5S.js.map
240
+ //# sourceMappingURL=chunk-AS3DJFY3.js.map
@@ -516,11 +516,33 @@ function upsertSessionToDb(meta, filePath) {
516
516
  `);
517
517
  }
518
518
  }
519
- function insertTurnToDb(sessionId, turn) {
519
+ function isRecoverableSessionConstraintError(err) {
520
+ if (!(err instanceof Error)) return false;
521
+ const lower = err.message.toLowerCase();
522
+ return lower.includes("foreign key constraint failed") || lower.includes("constraint failed");
523
+ }
524
+ function seedSessionRowForTurn(sessionId, project, filePath) {
525
+ const db = getAgentDb();
526
+ const now = Date.now();
527
+ const normalizedFilePath = path.isAbsolute(filePath) ? path.relative(getChitraguptaHome(), filePath) : filePath;
528
+ db.prepare(`
529
+ INSERT OR IGNORE INTO sessions (id, project, title, created_at, updated_at, turn_count, file_path)
530
+ VALUES (?, ?, ?, ?, ?, ?, ?)
531
+ `).run(
532
+ sessionId,
533
+ project,
534
+ "Recovered Session",
535
+ now,
536
+ now,
537
+ 0,
538
+ normalizedFilePath
539
+ );
540
+ }
541
+ function insertTurnToDb(sessionId, turn, context) {
520
542
  try {
521
543
  const db = getAgentDb();
522
- const now = Date.now();
523
- const insertTurn = db.transaction(() => {
544
+ const writeTurn2 = db.transaction(() => {
545
+ const now = Date.now();
524
546
  const result = db.prepare(`
525
547
  INSERT OR IGNORE INTO turns (session_id, turn_number, role, content, agent, model, tool_calls, created_at)
526
548
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
@@ -535,7 +557,7 @@ function insertTurnToDb(sessionId, turn) {
535
557
  now
536
558
  );
537
559
  if (result.changes > 0) {
538
- db.prepare("INSERT INTO turns_fts (rowid, content) VALUES (?, ?)").run(
560
+ db.prepare("INSERT OR IGNORE INTO turns_fts (rowid, content) VALUES (?, ?)").run(
539
561
  result.lastInsertRowid,
540
562
  turn.content
541
563
  );
@@ -544,10 +566,23 @@ function insertTurnToDb(sessionId, turn) {
544
566
  "UPDATE sessions SET turn_count = turn_count + 1, updated_at = ? WHERE id = ?"
545
567
  ).run(now, sessionId);
546
568
  });
547
- insertTurn();
569
+ try {
570
+ writeTurn2();
571
+ return;
572
+ } catch (err) {
573
+ if (context && isRecoverableSessionConstraintError(err)) {
574
+ seedSessionRowForTurn(sessionId, context.project, context.filePath);
575
+ writeTurn2();
576
+ return;
577
+ }
578
+ throw err;
579
+ }
548
580
  } catch (err) {
549
- process.stderr.write(`[chitragupta] turn insert failed for session ${sessionId}: ${err instanceof Error ? err.message : err}
550
- `);
581
+ const code = typeof err === "object" && err !== null && "code" in err ? String(err.code) : "unknown";
582
+ process.stderr.write(
583
+ `[chitragupta] turn insert failed for session ${sessionId} (turn=${turn.turnNumber}, role=${turn.role}, code=${code}): ${err instanceof Error ? err.message : err}
584
+ `
585
+ );
551
586
  }
552
587
  }
553
588
  function createSession(opts) {
@@ -814,7 +849,7 @@ function addTurn(sessionId, project, turn) {
814
849
  ${turnMd}
815
850
  `, "utf-8");
816
851
  cacheInvalidate(sessionId, project);
817
- insertTurnToDb(sessionId, turn);
852
+ insertTurnToDb(sessionId, turn, { project, filePath });
818
853
  }).catch((err) => {
819
854
  throw err;
820
855
  }).finally(() => {
@@ -1005,4 +1040,4 @@ export {
1005
1040
  findSessionByMetadata,
1006
1041
  migrateExistingSessions
1007
1042
  };
1008
- //# sourceMappingURL=chunk-NHRBVSN3.js.map
1043
+ //# sourceMappingURL=chunk-HIYHTWFW.js.map
@@ -7,7 +7,7 @@ var DEPTH_BOOST = {
7
7
  async function hierarchicalTemporalSearch(query, options) {
8
8
  const limit = options?.limit ?? 10;
9
9
  const results = [];
10
- const { searchConsolidationSummaries } = await import("./consolidation-indexer-CD6DS2HO.js");
10
+ const { searchConsolidationSummaries } = await import("./consolidation-indexer-VKQ6DNU3.js");
11
11
  const yearlyHits = await searchConsolidationSummaries(query, "yearly", {
12
12
  limit: 3,
13
13
  project: options?.project
@@ -120,4 +120,4 @@ function deduplicateAndSort(results, limit) {
120
120
  export {
121
121
  hierarchicalTemporalSearch
122
122
  };
123
- //# sourceMappingURL=chunk-IGBRBFXX.js.map
123
+ //# sourceMappingURL=chunk-JGI4SDWS.js.map
@@ -1,26 +1,8 @@
1
1
  import {
2
2
  searchSessions
3
- } from "./chunk-PJEYJQ2C.js";
3
+ } from "./chunk-O4KV7TFP.js";
4
4
 
5
- // ../chitragupta/packages/smriti/src/hybrid-search.ts
6
- var PRAMANA_RELIABILITY = {
7
- pratyaksha: 1,
8
- anumana: 0.85,
9
- shabda: 0.75,
10
- upamana: 0.6,
11
- arthapatti: 0.5,
12
- anupalabdhi: 0.4
13
- };
14
- var DEFAULT_CONFIG = {
15
- k: 60,
16
- topK: 10,
17
- enableBM25: true,
18
- enableVector: true,
19
- enableGraphRAG: true,
20
- pramanaWeight: 0.1,
21
- enablePramana: true,
22
- minScore: 0
23
- };
5
+ // ../chitragupta/packages/smriti/src/hybrid-search-learner.ts
24
6
  function gaussianRandom() {
25
7
  const u1 = Math.random();
26
8
  const u2 = Math.random();
@@ -61,15 +43,17 @@ var SIGNAL_INDEX = {
61
43
  };
62
44
  var NUM_SIGNALS = 4;
63
45
  var HybridWeightLearner = class {
64
- /** Success counts (α) for each of the 4 signals. */
46
+ /** Success counts (alpha) for each of the 4 signals. */
65
47
  _alphas;
66
- /** Failure counts (β) for each of the 4 signals. */
48
+ /** Failure counts (beta) for each of the 4 signals. */
67
49
  _betas;
68
50
  /** Total feedback events received. */
69
51
  _totalFeedback;
70
52
  /**
71
- * @param priorAlpha - Initial α for all signals. Default: 1 (uniform prior).
72
- * @param priorBeta - Initial β for all signals. Default: 1 (uniform prior).
53
+ * Create a new weight learner with the given prior.
54
+ *
55
+ * @param priorAlpha - Initial alpha for all signals. Default: 1 (uniform prior).
56
+ * @param priorBeta - Initial beta for all signals. Default: 1 (uniform prior).
73
57
  */
74
58
  constructor(priorAlpha = 1, priorBeta = 1) {
75
59
  this._alphas = new Float64Array(NUM_SIGNALS);
@@ -83,7 +67,7 @@ var HybridWeightLearner = class {
83
67
  /**
84
68
  * Sample a weight vector from the Beta posteriors.
85
69
  *
86
- * Each signal's weight is sampled from Beta(α_i, β_i), then the 4
70
+ * Each signal's weight is sampled from Beta(alpha_i, beta_i), then the 4
87
71
  * weights are normalized to sum to 1 (Dirichlet-like normalization).
88
72
  *
89
73
  * @returns Normalized weight vector { bm25, vector, graphrag, pramana }.
@@ -122,8 +106,10 @@ var HybridWeightLearner = class {
122
106
  this._totalFeedback += 1;
123
107
  }
124
108
  /**
125
- * Get the posterior mean for each signal: α / (α + β).
109
+ * Get the posterior mean for each signal: alpha / (alpha + beta).
126
110
  * Useful for diagnostics and logging.
111
+ *
112
+ * @returns Posterior mean for each of the 4 signals.
127
113
  */
128
114
  means() {
129
115
  const m = (i) => this._alphas[i] / (this._alphas[i] + this._betas[i]);
@@ -148,6 +134,8 @@ var HybridWeightLearner = class {
148
134
  /**
149
135
  * Restore the learner state from a serialized object.
150
136
  *
137
+ * Silently ignores invalid data to avoid corrupting the current state.
138
+ *
151
139
  * @param data - Previously serialized state from `serialize()`.
152
140
  */
153
141
  restore(data) {
@@ -161,6 +149,26 @@ var HybridWeightLearner = class {
161
149
  this._totalFeedback = data.totalFeedback ?? 0;
162
150
  }
163
151
  };
152
+
153
+ // ../chitragupta/packages/smriti/src/hybrid-search.ts
154
+ var PRAMANA_RELIABILITY = {
155
+ pratyaksha: 1,
156
+ anumana: 0.85,
157
+ shabda: 0.75,
158
+ upamana: 0.6,
159
+ arthapatti: 0.5,
160
+ anupalabdhi: 0.4
161
+ };
162
+ var DEFAULT_CONFIG = {
163
+ k: 60,
164
+ topK: 10,
165
+ enableBM25: true,
166
+ enableVector: true,
167
+ enableGraphRAG: true,
168
+ pramanaWeight: 0.1,
169
+ enablePramana: true,
170
+ minScore: 0
171
+ };
164
172
  function shouldRetrieve(query) {
165
173
  const lower = query.toLowerCase().trim();
166
174
  const gapPatterns = [
@@ -199,6 +207,7 @@ var HybridSearchEngine = class {
199
207
  config;
200
208
  weightLearner;
201
209
  kalaChakra;
210
+ /** Create a new hybrid search engine with optional engines and learner. */
202
211
  constructor(config, recallEngine, graphEngine, weightLearner) {
203
212
  this.config = { ...DEFAULT_CONFIG, ...config };
204
213
  this.recallEngine = recallEngine ?? null;
@@ -206,51 +215,33 @@ var HybridSearchEngine = class {
206
215
  this.weightLearner = weightLearner ?? null;
207
216
  this.kalaChakra = null;
208
217
  }
209
- /**
210
- * Set or replace the RecallEngine instance.
211
- */
218
+ /** Set or replace the RecallEngine instance. */
212
219
  setRecallEngine(engine) {
213
220
  this.recallEngine = engine;
214
221
  }
215
- /**
216
- * Set or replace the GraphRAGEngine instance.
217
- */
222
+ /** Set or replace the GraphRAGEngine instance. */
218
223
  setGraphEngine(engine) {
219
224
  this.graphEngine = engine;
220
225
  }
221
- /**
222
- * Set or replace the HybridWeightLearner instance.
223
- */
226
+ /** Set or replace the HybridWeightLearner instance. */
224
227
  setWeightLearner(learner) {
225
228
  this.weightLearner = learner;
226
229
  }
227
- /**
228
- * Get the current HybridWeightLearner, or null if not set.
229
- */
230
+ /** Get the current HybridWeightLearner, or null if not set. */
230
231
  getWeightLearner() {
231
232
  return this.weightLearner;
232
233
  }
233
- /**
234
- * Set or replace the KalaChakra temporal awareness engine.
235
- * When set, search results with timestamps receive a temporal boost.
236
- */
234
+ /** Set or replace the KalaChakra temporal awareness engine. */
237
235
  setKalaChakra(kala) {
238
236
  this.kalaChakra = kala;
239
237
  }
240
- /**
241
- * Get the current KalaChakra instance, or null if not set.
242
- */
238
+ /** Get the current KalaChakra instance, or null if not set. */
243
239
  getKalaChakra() {
244
240
  return this.kalaChakra;
245
241
  }
246
242
  /**
247
- * Record feedback for a search result.
248
- *
249
- * Updates the Thompson Sampling weight learner based on which signals
250
- * contributed to the result the user selected (success) or rejected (failure).
251
- *
252
- * @param result - The search result receiving feedback.
253
- * @param success - true = user found it useful, false = irrelevant.
243
+ * Record feedback for a search result. Updates Thompson Sampling posteriors
244
+ * for each contributing signal (and pramana if present).
254
245
  */
255
246
  recordFeedback(result, success) {
256
247
  if (!this.weightLearner) return;
@@ -262,20 +253,8 @@ var HybridSearchEngine = class {
262
253
  }
263
254
  }
264
255
  /**
265
- * Perform hybrid search across all enabled rankers.
266
- *
267
- * Each ranker produces its own ranking. Results are fused via RRF:
268
- * score(d) = Σ w_i / (k + rank_i(d))
269
- *
270
- * When a HybridWeightLearner is set, w_i are Thompson-sampled weights.
271
- * Otherwise, all weights are 1.0 (standard RRF).
272
- *
273
- * When pramana is enabled, each result receives an additive epistemic boost:
274
- * finalScore += δ * pramanaReliability(d)
275
- *
276
- * @param query - The search query.
277
- * @param configOverride - Optional per-query config overrides.
278
- * @returns Fused results sorted by score descending.
256
+ * Perform hybrid search across all enabled rankers, fusing via weighted RRF.
257
+ * When a HybridWeightLearner is set, weights are Thompson-sampled; otherwise uniform.
279
258
  */
280
259
  async search(query, configOverride) {
281
260
  const cfg = { ...this.config, ...configOverride };
@@ -412,12 +391,7 @@ var HybridSearchEngine = class {
412
391
  timestamp: r.timestamp
413
392
  }));
414
393
  }
415
- /**
416
- * Self-RAG gated search — only retrieves if the query signals a knowledge gap.
417
- *
418
- * @param query - The query to evaluate and optionally search.
419
- * @returns Results if retrieval was triggered, empty array otherwise.
420
- */
394
+ /** Self-RAG gated search -- only retrieves if the query signals a knowledge gap. */
421
395
  async gatedSearch(query, configOverride) {
422
396
  if (!shouldRetrieve(query)) return [];
423
397
  return this.search(query, configOverride);
@@ -425,9 +399,9 @@ var HybridSearchEngine = class {
425
399
  };
426
400
 
427
401
  export {
428
- PRAMANA_RELIABILITY,
429
402
  HybridWeightLearner,
403
+ PRAMANA_RELIABILITY,
430
404
  shouldRetrieve,
431
405
  HybridSearchEngine
432
406
  };
433
- //# sourceMappingURL=chunk-D3RVJGO7.js.map
407
+ //# sourceMappingURL=chunk-M7THR63C.js.map
@@ -2,7 +2,7 @@ import {
2
2
  DatabaseManager
3
3
  } from "./chunk-U62ABYKD.js";
4
4
 
5
- // ../chitragupta/packages/smriti/src/vasana-engine.ts
5
+ // ../chitragupta/packages/smriti/src/vasana-bocpd.ts
6
6
  var FNV_OFFSET = 2166136261;
7
7
  var FNV_PRIME = 16777619;
8
8
  function fnv1a(input) {
@@ -13,7 +13,7 @@ function fnv1a(input) {
13
13
  }
14
14
  return hash.toString(16).padStart(8, "0");
15
15
  }
16
- var DEFAULT_CONFIG = {
16
+ var DEFAULT_VASANA_CONFIG = {
17
17
  lambda: 50,
18
18
  changePointThreshold: 0.3,
19
19
  stabilityWindow: 5,
@@ -66,13 +66,104 @@ function logStudentT(x, nu, mu, sigma) {
66
66
  const z = (x - mu) / safeSigma;
67
67
  return lgamma((nu + 1) / 2) - lgamma(nu / 2) - 0.5 * Math.log(nu * Math.PI * safeSigma * safeSigma) - (nu + 1) / 2 * Math.log(1 + z * z / nu);
68
68
  }
69
+ function initBOCPD(cfg) {
70
+ return {
71
+ logR: [0],
72
+ // P(r=0) = 1
73
+ stats: [{
74
+ mu: cfg.priorMu,
75
+ kappa: cfg.priorKappa,
76
+ alpha: cfg.priorAlpha,
77
+ beta: cfg.priorAlpha
78
+ }],
79
+ stableCount: 0,
80
+ totalObs: 0,
81
+ recentCpProbs: []
82
+ };
83
+ }
84
+ function updateBOCPD(st, x, cfg) {
85
+ const logH = -Math.log(cfg.lambda);
86
+ const log1H = Math.log(1 - 1 / cfg.lambda);
87
+ const n = st.logR.length;
88
+ const lpp = new Array(n);
89
+ for (let r = 0; r < n; r++) {
90
+ const s = st.stats[r];
91
+ lpp[r] = logStudentT(x, 2 * s.alpha, s.mu, Math.sqrt(s.beta * (s.kappa + 1) / (s.alpha * s.kappa)));
92
+ }
93
+ const cpTerms = new Array(n);
94
+ const newLR = new Array(n + 1);
95
+ for (let r = 0; r < n; r++) {
96
+ newLR[r + 1] = lpp[r] + st.logR[r] + log1H;
97
+ cpTerms[r] = lpp[r] + st.logR[r] + logH;
98
+ }
99
+ newLR[0] = logsumexp(cpTerms);
100
+ const logZ = logsumexp(newLR);
101
+ for (let i = 0; i <= n; i++) newLR[i] -= logZ;
102
+ const newS = new Array(n + 1);
103
+ newS[0] = {
104
+ mu: cfg.priorMu,
105
+ kappa: cfg.priorKappa,
106
+ alpha: cfg.priorAlpha,
107
+ beta: cfg.priorAlpha
108
+ };
109
+ for (let r = 0; r < n; r++) {
110
+ const p = st.stats[r];
111
+ const k = p.kappa + 1;
112
+ const dx = x - p.mu;
113
+ newS[r + 1] = {
114
+ mu: (p.kappa * p.mu + x) / k,
115
+ kappa: k,
116
+ alpha: p.alpha + 0.5,
117
+ beta: p.beta + 0.5 * p.kappa * dx * dx / k
118
+ };
119
+ }
120
+ if (newLR.length > cfg.maxRunLength) {
121
+ const idx = newLR.map((lp, i) => ({ lp, i })).sort((a, b) => b.lp - a.lp);
122
+ const keep = new Set(idx.slice(0, cfg.maxRunLength).map((e) => e.i));
123
+ const pR = [], pS = [];
124
+ for (let i = 0; i <= n; i++) if (keep.has(i)) {
125
+ pR.push(newLR[i]);
126
+ pS.push(newS[i]);
127
+ }
128
+ const norm = logsumexp(pR);
129
+ for (let i = 0; i < pR.length; i++) pR[i] -= norm;
130
+ st.logR = pR;
131
+ st.stats = pS;
132
+ } else {
133
+ st.logR = newLR;
134
+ st.stats = newS;
135
+ }
136
+ st.totalObs++;
137
+ const cpProb = st.logR.length > 0 ? Math.exp(st.logR[0]) : 0;
138
+ if (!st.recentCpProbs) st.recentCpProbs = [];
139
+ st.recentCpProbs.push(cpProb);
140
+ if (st.recentCpProbs.length > cfg.anomalyRevertWindow) {
141
+ st.recentCpProbs.shift();
142
+ }
143
+ }
144
+ function serializeBOCPD(states, obs) {
145
+ return {
146
+ features: Object.fromEntries(states),
147
+ observations: Object.fromEntries(obs)
148
+ };
149
+ }
150
+ function deserializeBOCPD(raw) {
151
+ return {
152
+ states: new Map(Object.entries(raw.features)),
153
+ obs: new Map(
154
+ Object.entries(raw.observations).map(([k, v]) => [k, Array.isArray(v) ? v : []])
155
+ )
156
+ };
157
+ }
158
+
159
+ // ../chitragupta/packages/smriti/src/vasana-engine.ts
69
160
  var VasanaEngine = class {
70
161
  cfg;
71
162
  states = /* @__PURE__ */ new Map();
72
163
  obs = /* @__PURE__ */ new Map();
73
164
  cache = /* @__PURE__ */ new Map();
74
165
  constructor(config) {
75
- const merged = { ...DEFAULT_CONFIG, ...config };
166
+ const merged = { ...DEFAULT_VASANA_CONFIG, ...config };
76
167
  for (const [k, ceil] of Object.entries(HARD_CEILINGS)) {
77
168
  const key = k;
78
169
  if (typeof merged[key] === "number" && typeof ceil === "number")
@@ -84,12 +175,12 @@ var VasanaEngine = class {
84
175
  /** Observe a samskara: extract features and update BOCPD state per dimension. */
85
176
  observe(samskara) {
86
177
  for (const [feat, val] of this.extractFeatures(samskara)) {
87
- if (!this.states.has(feat)) this.states.set(feat, this.initState());
178
+ if (!this.states.has(feat)) this.states.set(feat, initBOCPD(this.cfg));
88
179
  const buf = this.obs.get(feat) ?? [];
89
180
  buf.push(val);
90
181
  if (buf.length > this.cfg.windowSize) buf.splice(0, buf.length - this.cfg.windowSize);
91
182
  this.obs.set(feat, buf);
92
- this.updateBOCPD(feat, val);
183
+ updateBOCPD(this.states.get(feat), val, this.cfg);
93
184
  }
94
185
  }
95
186
  /** Run crystallization: stability check, holdout validation, vasana upsert. */
@@ -264,10 +355,7 @@ var VasanaEngine = class {
264
355
  }
265
356
  /** Persist BOCPD state (run-length distributions + observations) to SQLite. */
266
357
  persist() {
267
- const json = JSON.stringify({
268
- features: Object.fromEntries(this.states),
269
- observations: Object.fromEntries(this.obs)
270
- });
358
+ const json = JSON.stringify(serializeBOCPD(this.states, this.obs));
271
359
  DatabaseManager.instance().get("agent").prepare(
272
360
  `INSERT OR REPLACE INTO consolidation_rules
273
361
  (id, category, rule_text, confidence, source_sessions, created_at, updated_at, hit_count, project)
@@ -283,9 +371,10 @@ var VasanaEngine = class {
283
371
  ).get();
284
372
  if (!row) return;
285
373
  try {
286
- const s = JSON.parse(row.rule_text);
287
- this.states = new Map(Object.entries(s.features));
288
- this.obs = new Map(Object.entries(s.observations).map(([k, v]) => [k, Array.isArray(v) ? v : []]));
374
+ const raw = JSON.parse(row.rule_text);
375
+ const { states, obs } = deserializeBOCPD(raw);
376
+ this.states = states;
377
+ this.obs = obs;
289
378
  } catch (err) {
290
379
  process.stderr.write(`[vasana-engine] restore() failed to parse BOCPD state: ${err instanceof Error ? err.message : err}
291
380
  `);
@@ -293,98 +382,14 @@ var VasanaEngine = class {
293
382
  this.obs.clear();
294
383
  }
295
384
  }
296
- // ── BOCPD Core (Adams & MacKay 2007) ─────────────────────────────────
297
- initState() {
298
- return {
299
- logR: [0],
300
- // P(r=0) = 1
301
- stats: [{
302
- mu: this.cfg.priorMu,
303
- kappa: this.cfg.priorKappa,
304
- alpha: this.cfg.priorAlpha,
305
- beta: this.cfg.priorAlpha
306
- }],
307
- stableCount: 0,
308
- totalObs: 0,
309
- recentCpProbs: []
310
- };
311
- }
312
- /**
313
- * Online BOCPD update for one observation on one feature dimension.
314
- *
315
- * 1. Predictive P(x_t | r) via Student-t with Normal-Gamma sufficient stats
316
- * 2. Growth: P(r_t=r+1) = P(x|r) * P(r) * (1-H)
317
- * 3. Change-point: P(r_t=0) = sum_r P(x|r) * P(r) * H
318
- * 4. Normalize, update sufficient stats, prune low-probability tails
319
- */
320
- updateBOCPD(feat, x) {
321
- const st = this.states.get(feat);
322
- const logH = -Math.log(this.cfg.lambda);
323
- const log1H = Math.log(1 - 1 / this.cfg.lambda);
324
- const n = st.logR.length;
325
- const lpp = new Array(n);
326
- for (let r = 0; r < n; r++) {
327
- const s = st.stats[r];
328
- lpp[r] = logStudentT(x, 2 * s.alpha, s.mu, Math.sqrt(s.beta * (s.kappa + 1) / (s.alpha * s.kappa)));
329
- }
330
- const cpTerms = new Array(n);
331
- const newLR = new Array(n + 1);
332
- for (let r = 0; r < n; r++) {
333
- newLR[r + 1] = lpp[r] + st.logR[r] + log1H;
334
- cpTerms[r] = lpp[r] + st.logR[r] + logH;
335
- }
336
- newLR[0] = logsumexp(cpTerms);
337
- const logZ = logsumexp(newLR);
338
- for (let i = 0; i <= n; i++) newLR[i] -= logZ;
339
- const newS = new Array(n + 1);
340
- newS[0] = {
341
- mu: this.cfg.priorMu,
342
- kappa: this.cfg.priorKappa,
343
- alpha: this.cfg.priorAlpha,
344
- beta: this.cfg.priorAlpha
345
- };
346
- for (let r = 0; r < n; r++) {
347
- const p = st.stats[r];
348
- const k = p.kappa + 1;
349
- const dx = x - p.mu;
350
- newS[r + 1] = {
351
- mu: (p.kappa * p.mu + x) / k,
352
- kappa: k,
353
- alpha: p.alpha + 0.5,
354
- beta: p.beta + 0.5 * p.kappa * dx * dx / k
355
- };
356
- }
357
- if (newLR.length > this.cfg.maxRunLength) {
358
- const idx = newLR.map((lp, i) => ({ lp, i })).sort((a, b) => b.lp - a.lp);
359
- const keep = new Set(idx.slice(0, this.cfg.maxRunLength).map((e) => e.i));
360
- const pR = [], pS = [];
361
- for (let i = 0; i <= n; i++) if (keep.has(i)) {
362
- pR.push(newLR[i]);
363
- pS.push(newS[i]);
364
- }
365
- const norm = logsumexp(pR);
366
- for (let i = 0; i < pR.length; i++) pR[i] -= norm;
367
- st.logR = pR;
368
- st.stats = pS;
369
- } else {
370
- st.logR = newLR;
371
- st.stats = newS;
372
- }
373
- st.totalObs++;
374
- const cpProb = st.logR.length > 0 ? Math.exp(st.logR[0]) : 0;
375
- if (!st.recentCpProbs) st.recentCpProbs = [];
376
- st.recentCpProbs.push(cpProb);
377
- if (st.recentCpProbs.length > this.cfg.anomalyRevertWindow) {
378
- st.recentCpProbs.shift();
379
- }
380
- }
385
+ // ── Deviation Classification ─────────────────────────────────────────
381
386
  /**
382
387
  * Classify a deviation as change-point, anomaly, or stable.
383
388
  *
384
389
  * Joint anomaly/change-point discrimination (arxiv 2508.06385):
385
- * - If P(r=0) > threshold and persists across the revert window change-point
386
- * - If P(r=0) > threshold but reverts within the window anomaly (one-off)
387
- * - Otherwise stable
390
+ * - If P(r=0) > threshold and persists across the revert window -> change-point
391
+ * - If P(r=0) > threshold but reverts within the window -> anomaly (one-off)
392
+ * - Otherwise -> stable
388
393
  */
389
394
  classifyDeviation(st) {
390
395
  if (st.logR.length === 0) return "stable";
@@ -398,9 +403,6 @@ var VasanaEngine = class {
398
403
  }
399
404
  return "anomaly";
400
405
  }
401
- isChangePoint(st) {
402
- return this.classifyDeviation(st) === "change-point";
403
- }
404
406
  stabilityScore(st) {
405
407
  if (st.logR.length === 0) return 0;
406
408
  return Math.max(0, Math.min(1, 1 - Math.exp(st.logR[0])));
@@ -456,8 +458,8 @@ var VasanaEngine = class {
456
458
  return m;
457
459
  }
458
460
  // ── SQLite Helpers ───────────────────────────────────────────────────
459
- // Schema mapping: Vasana.tendencyname, sourceSamskarassource_samskaras(JSON),
460
- // reinforcementCountactivation_count, lastActivatedlast_activated
461
+ // Schema mapping: Vasana.tendency->name, sourceSamskaras->source_samskaras(JSON),
462
+ // reinforcementCount->activation_count, lastActivated->last_activated
461
463
  saveVasana(v) {
462
464
  const db = DatabaseManager.instance().get("agent");
463
465
  const existing = db.prepare(
@@ -540,6 +542,16 @@ function jsonArr(s) {
540
542
  }
541
543
 
542
544
  export {
545
+ fnv1a,
546
+ DEFAULT_VASANA_CONFIG,
547
+ HARD_CEILINGS,
548
+ logsumexp,
549
+ lgamma,
550
+ logStudentT,
551
+ initBOCPD,
552
+ updateBOCPD,
553
+ serializeBOCPD,
554
+ deserializeBOCPD,
543
555
  VasanaEngine
544
556
  };
545
- //# sourceMappingURL=chunk-OBYBBGHA.js.map
557
+ //# sourceMappingURL=chunk-N22M7D4P.js.map
@@ -5,7 +5,7 @@ import {
5
5
  import {
6
6
  listSessions,
7
7
  loadSession
8
- } from "./chunk-NHRBVSN3.js";
8
+ } from "./chunk-HIYHTWFW.js";
9
9
  import {
10
10
  initAgentSchema
11
11
  } from "./chunk-YJRXLRTE.js";
@@ -346,4 +346,4 @@ export {
346
346
  searchSessions,
347
347
  searchMemory
348
348
  };
349
- //# sourceMappingURL=chunk-PJEYJQ2C.js.map
349
+ //# sourceMappingURL=chunk-O4KV7TFP.js.map