@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.
- package/README.md +1 -1
- package/chunks/{chunk-7UOXFHEB.js → chunk-77725AR7.js} +416 -397
- package/chunks/{chunk-YSC77CKZ.js → chunk-AGK3A7R7.js} +2844 -3208
- package/chunks/{chunk-DOQMEQ5S.js → chunk-AS3DJFY3.js} +5 -5
- package/chunks/{chunk-NHRBVSN3.js → chunk-HIYHTWFW.js} +44 -9
- package/chunks/{chunk-IGBRBFXX.js → chunk-JGI4SDWS.js} +2 -2
- package/chunks/{chunk-D3RVJGO7.js → chunk-M7THR63C.js} +48 -74
- package/chunks/{chunk-OBYBBGHA.js → chunk-N22M7D4P.js} +118 -106
- package/chunks/{chunk-PJEYJQ2C.js → chunk-O4KV7TFP.js} +2 -2
- package/chunks/{chunk-S2HDNNC7.js → chunk-OT4G2L46.js} +552 -641
- package/chunks/chunk-TND3MU4Z.js +426 -0
- package/chunks/{chunk-LVE2EOOH.js → chunk-VJHNE47S.js} +84 -75
- package/chunks/{consolidation-indexer-CD6DS2HO.js → consolidation-indexer-VKQ6DNU3.js} +4 -4
- package/chunks/{day-consolidation-U3X6P4ZG.js → day-consolidation-BH3QU2SZ.js} +6 -2
- package/chunks/{graphrag-LAZSXLLI.js → graphrag-D7OXWAWD.js} +2 -2
- package/chunks/{hierarchical-temporal-search-ETXYYJZK.js → hierarchical-temporal-search-PVHVA3NZ.js} +2 -2
- package/chunks/{hybrid-search-TX6T3KYH.js → hybrid-search-G2NAJKJ7.js} +4 -4
- package/chunks/{periodic-consolidation-4MACZE6S.js → periodic-consolidation-LMYMNS4Q.js} +2 -2
- package/chunks/{recall-IUPQCBYP.js → recall-ZNL4DJ2L.js} +3 -3
- package/chunks/{search-HHSVHBXC.js → search-35JMSGUT.js} +3 -3
- package/chunks/{session-store-NDUDYAC7.js → session-store-3BRPGC6P.js} +2 -2
- package/chunks/{src-ZAKUL232.js → src-Y3TGMINC.js} +12 -12
- package/chunks/vasana-engine-MU25OQ23.js +30 -0
- package/gateway.js +492 -226
- package/package.json +1 -1
- package/vaayu-mark-npm.png +0 -0
- package/chunks/chunk-TEQKXGIK.js +0 -752
- package/chunks/vasana-engine-G6BPOFX7.js +0 -10
- package/vaayu-mark.png +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
blobToVector,
|
|
3
3
|
vectorToBlob
|
|
4
|
-
} from "./chunk-
|
|
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-
|
|
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-
|
|
204
|
-
const { listSessionProjects } = await import("./session-store-
|
|
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-
|
|
240
|
+
//# sourceMappingURL=chunk-AS3DJFY3.js.map
|
|
@@ -516,11 +516,33 @@ function upsertSessionToDb(meta, filePath) {
|
|
|
516
516
|
`);
|
|
517
517
|
}
|
|
518
518
|
}
|
|
519
|
-
function
|
|
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
|
|
523
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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-
|
|
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-
|
|
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-
|
|
123
|
+
//# sourceMappingURL=chunk-JGI4SDWS.js.map
|
|
@@ -1,26 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
searchSessions
|
|
3
|
-
} from "./chunk-
|
|
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 (
|
|
46
|
+
/** Success counts (alpha) for each of the 4 signals. */
|
|
65
47
|
_alphas;
|
|
66
|
-
/** Failure counts (
|
|
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
|
-
*
|
|
72
|
-
*
|
|
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(
|
|
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-
|
|
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-
|
|
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
|
|
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 = { ...
|
|
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.
|
|
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.
|
|
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
|
|
287
|
-
|
|
288
|
-
this.
|
|
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
|
-
// ──
|
|
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
|
|
386
|
-
* - If P(r=0) > threshold but reverts within the window
|
|
387
|
-
* - Otherwise
|
|
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.tendency
|
|
460
|
-
// reinforcementCount
|
|
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-
|
|
557
|
+
//# sourceMappingURL=chunk-N22M7D4P.js.map
|
|
@@ -5,7 +5,7 @@ import {
|
|
|
5
5
|
import {
|
|
6
6
|
listSessions,
|
|
7
7
|
loadSession
|
|
8
|
-
} from "./chunk-
|
|
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-
|
|
349
|
+
//# sourceMappingURL=chunk-O4KV7TFP.js.map
|