pi-mega-compact 0.21.1 → 0.21.3
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/dist/config.js +13 -2
- package/dist/dedup/l1-minhash.js +5 -4
- package/dist/extensions/dashboard-server/routes-rag-settings-helpers.js +1 -0
- package/dist/extensions/mega-compact-child.js +126 -0
- package/dist/extensions/mega-compact.js +10 -0
- package/dist/extensions/mega-config.js +11 -3
- package/dist/src/bridge/factory.js +181 -0
- package/dist/src/bridge/types.js +10 -0
- package/dist/src/bridge.js +1 -0
- package/dist/src/config.js +13 -2
- package/dist/src/dedup/l1-minhash.js +5 -4
- package/dist/src/recall/validator.js +8 -1
- package/dist/src/recall/vote.js +34 -9
- package/dist/src/store/sqlite/fts5-search.js +6 -1
- package/dist/src/vector-read.js +6 -2
- package/dist/src/vectorStore/add.js +5 -1
- package/extensions/dashboard-server/routes-rag-settings-helpers.ts +6 -0
- package/extensions/mega-compact-child.ts +129 -0
- package/extensions/mega-compact.ts +10 -0
- package/extensions/mega-config-types.ts +5 -0
- package/extensions/mega-config.ts +11 -3
- package/package.json +1 -1
- package/src/bridge/factory.ts +231 -0
- package/src/bridge/types.ts +138 -0
- package/src/bridge.ts +24 -0
- package/src/config.ts +12 -3
- package/src/dedup/l1-minhash.ts +5 -4
- package/src/recall/validator.ts +8 -1
- package/src/recall/vote.ts +29 -8
- package/src/store/sqlite/fts5-search.ts +7 -1
- package/src/vector-read.ts +9 -2
- package/src/vectorStore/add.ts +7 -1
package/src/recall/vote.ts
CHANGED
|
@@ -46,16 +46,32 @@ export interface VoteOptions {
|
|
|
46
46
|
recencyCount?: number;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
-
/**
|
|
50
|
-
|
|
49
|
+
/**
|
|
50
|
+
* Per-source normalization: map raw scores to 0..1 via min-max within source.
|
|
51
|
+
*
|
|
52
|
+
* E1 follow-up (PR #18 review): non-finite scores (NaN/±Infinity) are DROPPED
|
|
53
|
+
* before the min/max fold — a single NaN silently propagates through Math.min/
|
|
54
|
+
* max and turns EVERY normalized score of that source into NaN (verified),
|
|
55
|
+
* poisoning the whole 3-source quorum. Dropping the bad entry degrades that
|
|
56
|
+
* source gracefully instead. Exported so the guard is unit-testable directly.
|
|
57
|
+
*/
|
|
58
|
+
export function normalizeScores(scores: number[]): Map<number, number> {
|
|
51
59
|
const map = new Map<number, number>();
|
|
52
|
-
|
|
53
|
-
const min = Math.min(...scores);
|
|
54
|
-
const max = Math.max(...scores);
|
|
55
|
-
const span = max - min;
|
|
60
|
+
const finite: { idx: number; s: number }[] = [];
|
|
56
61
|
scores.forEach((s, i) => {
|
|
57
|
-
|
|
62
|
+
if (Number.isFinite(s)) finite.push({ idx: i, s });
|
|
58
63
|
});
|
|
64
|
+
if (finite.length === 0) return map;
|
|
65
|
+
let min = Infinity;
|
|
66
|
+
let max = -Infinity;
|
|
67
|
+
for (const { s } of finite) {
|
|
68
|
+
if (s < min) min = s;
|
|
69
|
+
if (s > max) max = s;
|
|
70
|
+
}
|
|
71
|
+
const span = max - min;
|
|
72
|
+
for (const { idx, s } of finite) {
|
|
73
|
+
map.set(idx, span === 0 ? 1 : (s - min) / span);
|
|
74
|
+
}
|
|
59
75
|
return map;
|
|
60
76
|
}
|
|
61
77
|
|
|
@@ -150,7 +166,12 @@ export function voteRecall(opts: VoteOptions, store: VectorStore): VoteResult {
|
|
|
150
166
|
const norm = perSource.find((p) => p.name === src.name)!.norm;
|
|
151
167
|
const bestByCp = new Map<string, number>();
|
|
152
168
|
src.cands.forEach((c, i) => {
|
|
153
|
-
|
|
169
|
+
// E1 follow-up: normalizeScores dropped non-finite scores; such a hit is
|
|
170
|
+
// NOT a valid nomination — skip it entirely instead of defaulting it to
|
|
171
|
+
// 0 (which would still name the checkpoint and let it rank last into the
|
|
172
|
+
// fallback ranking).
|
|
173
|
+
const n = norm.get(i);
|
|
174
|
+
if (n === undefined) return;
|
|
154
175
|
const prev = bestByCp.get(c.checkpointId);
|
|
155
176
|
if (prev === undefined || n > prev) bestByCp.set(c.checkpointId, n);
|
|
156
177
|
seenIds.add(c.checkpointId);
|
|
@@ -124,7 +124,13 @@ export function hydrateFts5Hits(
|
|
|
124
124
|
const out: HydratedFts5Hit[] = [];
|
|
125
125
|
for (const h of hits) {
|
|
126
126
|
const cp = cpMap.get(h.id);
|
|
127
|
-
|
|
127
|
+
// H1 follow-up (PR #18 review): exclude SemDeDup-'removed' rows. The FTS5
|
|
128
|
+
// index is NOT pruned by vectorSemDedup, so a removed row can still MATCH;
|
|
129
|
+
// hydrating it would let the fts5 voter NAME a dead checkpoint (a removed
|
|
130
|
+
// row plus a recency vote is a 2/3 agreement that passes the validator).
|
|
131
|
+
// Mirrors vectorSearch's read-time filter.
|
|
132
|
+
if (cp && cp.dedupStatus !== "removed")
|
|
133
|
+
out.push({ checkpointId: h.id, score: h.score, summary: cp.summary });
|
|
128
134
|
}
|
|
129
135
|
return out;
|
|
130
136
|
}
|
package/src/vector-read.ts
CHANGED
|
@@ -100,8 +100,11 @@ export function vectorDedupe(
|
|
|
100
100
|
: regionHashOrText;
|
|
101
101
|
const state = loadSessionState(sid, stateDir);
|
|
102
102
|
if (state.storedRegionHashes.includes(hash)) return true;
|
|
103
|
+
// H1 follow-up (PR #18 review): a SemDeDup-'removed' row's regionHash must not
|
|
104
|
+
// report "already represented" — its content is excluded from recall, so the
|
|
105
|
+
// incoming region is NOT deduplicated in any retrievable sense.
|
|
103
106
|
return listCheckpoints(sid, stateDir).some(
|
|
104
|
-
(c) => c.regionHash === hash,
|
|
107
|
+
(c) => c.dedupStatus !== "removed" && c.regionHash === hash,
|
|
105
108
|
);
|
|
106
109
|
}
|
|
107
110
|
|
|
@@ -157,7 +160,11 @@ export function vectorTopSimilar(store: VectorStore, sessionId: string, n: numbe
|
|
|
157
160
|
const current = ordered[ordered.length - 1];
|
|
158
161
|
|
|
159
162
|
const scored: SearchHit[] = ordered
|
|
160
|
-
.filter(
|
|
163
|
+
.filter(
|
|
164
|
+
(cp) =>
|
|
165
|
+
cp.checkpointId !== current.checkpointId &&
|
|
166
|
+
cp.dedupStatus !== "removed", // H1 follow-up: mirror vectorSearch's filter
|
|
167
|
+
)
|
|
161
168
|
.map((cp) => ({
|
|
162
169
|
checkpoint: cp,
|
|
163
170
|
score: cosineSimilarity(current.embedding, cp.embedding),
|
package/src/vectorStore/add.ts
CHANGED
|
@@ -54,7 +54,13 @@ export function addCheckpoint(store: VectorStore, input: AddInput): AddResult {
|
|
|
54
54
|
const t0 = Date.now();
|
|
55
55
|
const sessionId = normalizeSessionId(input.sessionId);
|
|
56
56
|
const regionHash = computeRegionHash(input.regionText);
|
|
57
|
-
|
|
57
|
+
// H1: exclude SemDeDup-'removed' rows from dedup matching. search() already
|
|
58
|
+
// filters these, but add() did NOT — so an L0/L1/L2 match against a previously
|
|
59
|
+
// removed duplicate would upsertCheckpoint it back to active, resurrecting it
|
|
60
|
+
// into recall and defeating SemDeDup.
|
|
61
|
+
const all = listCheckpoints(sessionId, store.stateDir).filter(
|
|
62
|
+
(cp) => cp.dedupStatus !== "removed",
|
|
63
|
+
);
|
|
58
64
|
// Honest "tokens saved" base for this region. For a deduped add the whole
|
|
59
65
|
// original region is discarded (nothing new stored); for a new checkpoint
|
|
60
66
|
// we persist (orig − stored). Falls back to stored when orig is unknown.
|