mumpix 1.0.19 → 1.0.29
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/CHANGELOG.md +42 -14
- package/README.md +185 -8
- package/bin/mumpix.js +1 -405
- package/examples/agent-memory.js +1 -1
- package/examples/basic.js +1 -1
- package/examples/behavioral-primitives.js +50 -0
- package/examples/verified-mode.js +1 -1
- package/package.json +17 -13
- package/scripts/test-license-modes.cjs +87 -0
- package/src/brp/index.js +1 -0
- package/src/collapse/index.js +1 -0
- package/src/core/MumpixDB.js +210 -322
- package/src/core/audit.js +1 -173
- package/src/core/auth.js +1 -232
- package/src/core/inverted-index.js +144 -0
- package/src/core/license.js +1 -267
- package/src/core/ml-dsa.mjs +1 -25
- package/src/core/ml-kem.mjs +1 -32
- package/src/core/recall.js +1 -176
- package/src/core/store.js +335 -286
- package/src/core/wal-writer.js +83 -0
- package/src/index.js +20 -34
- package/src/integrations/developer-sdk.js +1 -165
- package/src/integrations/langchain-official.js +1 -0
- package/src/integrations/langchain.js +1 -131
- package/src/integrations/llamaindex-official.js +1 -0
- package/src/integrations/llamaindex.js +1 -86
- package/src/integrations/vector-sidecar.js +325 -0
- package/src/rlp/index.js +1 -0
- package/src/temporal/engine.js +1 -1894
- package/src/temporal/indexes.js +1 -178
- package/src/temporal/operators.js +1 -186
- package/scripts/postinstall-auth.js +0 -101
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
|
|
6
|
+
function defaultVectorPath(db) {
|
|
7
|
+
if (!db || !db.path) {
|
|
8
|
+
throw new Error("Mumpix vector adapters require an opened MumpixDB instance with a path.");
|
|
9
|
+
}
|
|
10
|
+
return `${db.path}.vectors.json`;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function emptyData() {
|
|
14
|
+
return {
|
|
15
|
+
version: 1,
|
|
16
|
+
embeddingDict: {},
|
|
17
|
+
textIdToRecordId: {},
|
|
18
|
+
textIdToRefDocId: {},
|
|
19
|
+
metadataDict: {},
|
|
20
|
+
textDict: {},
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function loadData(vectorPath) {
|
|
25
|
+
try {
|
|
26
|
+
const parsed = JSON.parse(fs.readFileSync(vectorPath, "utf8"));
|
|
27
|
+
return { ...emptyData(), ...(parsed && typeof parsed === "object" ? parsed : {}) };
|
|
28
|
+
} catch {
|
|
29
|
+
return emptyData();
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function saveData(vectorPath, data) {
|
|
34
|
+
fs.mkdirSync(path.dirname(vectorPath), { recursive: true });
|
|
35
|
+
const tmp = `${vectorPath}.tmp`;
|
|
36
|
+
fs.writeFileSync(tmp, JSON.stringify({ ...emptyData(), ...data, version: 1 }, null, 2), "utf8");
|
|
37
|
+
fs.renameSync(tmp, vectorPath);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function dot(left, right) {
|
|
41
|
+
const length = Math.min(left.length, right.length);
|
|
42
|
+
let score = 0;
|
|
43
|
+
for (let i = 0; i < length; i += 1) score += Number(left[i] || 0) * Number(right[i] || 0);
|
|
44
|
+
return score;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function magnitude(vector) {
|
|
48
|
+
return Math.sqrt(dot(vector, vector));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function cosine(left, right) {
|
|
52
|
+
if (!(Array.isArray(left) && Array.isArray(right) && left.length && right.length)) return 0;
|
|
53
|
+
const denom = magnitude(left) * magnitude(right);
|
|
54
|
+
return denom ? dot(left, right) / denom : 0;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function filterMatches(metadata, filters) {
|
|
58
|
+
if (!filters || !Array.isArray(filters.filters)) return true;
|
|
59
|
+
const condition = String(filters.condition || "and").toLowerCase();
|
|
60
|
+
const checks = filters.filters.map((filter) => {
|
|
61
|
+
const actual = metadata ? metadata[filter.key] : undefined;
|
|
62
|
+
const expected = filter.value;
|
|
63
|
+
const operator = filter.operator || "==";
|
|
64
|
+
if (operator === "is_empty") {
|
|
65
|
+
return actual == null || actual === "" || (Array.isArray(actual) && actual.length === 0);
|
|
66
|
+
}
|
|
67
|
+
if (actual === undefined) return false;
|
|
68
|
+
if (operator === "==" || operator === "eq") return actual === expected;
|
|
69
|
+
if (operator === "!=" || operator === "ne") return actual !== expected;
|
|
70
|
+
if (operator === "in") return Array.isArray(expected) && expected.includes(actual);
|
|
71
|
+
if (operator === "nin") return Array.isArray(expected) && !expected.includes(actual);
|
|
72
|
+
if (operator === "any") return Array.isArray(actual) && Array.isArray(expected) && expected.some((value) => actual.includes(value));
|
|
73
|
+
if (operator === "all") return Array.isArray(actual) && Array.isArray(expected) && expected.every((value) => actual.includes(value));
|
|
74
|
+
if (operator === "contains") return Array.isArray(actual) && actual.includes(expected);
|
|
75
|
+
if (operator === "text_match") return String(actual).includes(String(expected));
|
|
76
|
+
if (operator === ">") return Number(actual) > Number(expected);
|
|
77
|
+
if (operator === "<") return Number(actual) < Number(expected);
|
|
78
|
+
if (operator === ">=") return Number(actual) >= Number(expected);
|
|
79
|
+
if (operator === "<=") return Number(actual) <= Number(expected);
|
|
80
|
+
return false;
|
|
81
|
+
});
|
|
82
|
+
return condition === "or" ? checks.some(Boolean) : checks.every(Boolean);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function topKPush(top, hit, k) {
|
|
86
|
+
if (k <= 0) return;
|
|
87
|
+
if (top.length < k) {
|
|
88
|
+
top.push(hit);
|
|
89
|
+
if (top.length === k) top.sort((a, b) => a.score - b.score);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
if (hit.score <= top[0].score) return;
|
|
93
|
+
top[0] = hit;
|
|
94
|
+
let index = 0;
|
|
95
|
+
while (index + 1 < top.length && top[index].score > top[index + 1].score) {
|
|
96
|
+
const next = top[index + 1];
|
|
97
|
+
top[index + 1] = top[index];
|
|
98
|
+
top[index] = next;
|
|
99
|
+
index += 1;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function intersectSets(left, right) {
|
|
104
|
+
if (!left) return new Set(right);
|
|
105
|
+
const out = new Set();
|
|
106
|
+
for (const value of left) {
|
|
107
|
+
if (right.has(value)) out.add(value);
|
|
108
|
+
}
|
|
109
|
+
return out;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function metadataValueKey(value) {
|
|
113
|
+
return `${typeof value}:${String(value)}`;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function equalityCandidateSet(index, filters) {
|
|
117
|
+
if (!filters || !Array.isArray(filters.filters)) return null;
|
|
118
|
+
if (String(filters.condition || "and").toLowerCase() !== "and") return null;
|
|
119
|
+
let candidates = null;
|
|
120
|
+
for (const filter of filters.filters) {
|
|
121
|
+
const operator = filter.operator || "==";
|
|
122
|
+
if (operator !== "==" && operator !== "eq") continue;
|
|
123
|
+
const byValue = index.metadataIndexes.get(String(filter.key));
|
|
124
|
+
if (!byValue) return new Set();
|
|
125
|
+
const ids = byValue.get(metadataValueKey(filter.value));
|
|
126
|
+
if (!ids) return new Set();
|
|
127
|
+
candidates = intersectSets(candidates, ids);
|
|
128
|
+
if (candidates.size === 0) return candidates;
|
|
129
|
+
}
|
|
130
|
+
return candidates;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function buildPackedIndex(data) {
|
|
134
|
+
const ids = [];
|
|
135
|
+
const vectors = [];
|
|
136
|
+
let dims = 0;
|
|
137
|
+
|
|
138
|
+
for (const [id, vector] of Object.entries(data.embeddingDict || {})) {
|
|
139
|
+
if (!Array.isArray(vector) || vector.length === 0) continue;
|
|
140
|
+
if (!dims) dims = vector.length;
|
|
141
|
+
if (vector.length !== dims) continue;
|
|
142
|
+
ids.push(String(id));
|
|
143
|
+
vectors.push(vector);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
const packed = new Float32Array(ids.length * dims);
|
|
147
|
+
const norms = new Float32Array(ids.length);
|
|
148
|
+
const idToOffset = new Map();
|
|
149
|
+
|
|
150
|
+
for (let row = 0; row < vectors.length; row += 1) {
|
|
151
|
+
const vector = vectors[row];
|
|
152
|
+
let norm = 0;
|
|
153
|
+
const base = row * dims;
|
|
154
|
+
for (let col = 0; col < dims; col += 1) {
|
|
155
|
+
const value = Number(vector[col] || 0);
|
|
156
|
+
packed[base + col] = value;
|
|
157
|
+
norm += value * value;
|
|
158
|
+
}
|
|
159
|
+
norms[row] = Math.sqrt(norm) || 0;
|
|
160
|
+
idToOffset.set(ids[row], row);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const metadataIndexes = new Map();
|
|
164
|
+
for (const [id, metadata] of Object.entries(data.metadataDict || {})) {
|
|
165
|
+
if (!idToOffset.has(String(id)) || !metadata || typeof metadata !== "object") continue;
|
|
166
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
167
|
+
if (value == null || typeof value === "object") continue;
|
|
168
|
+
const field = String(key);
|
|
169
|
+
if (!metadataIndexes.has(field)) metadataIndexes.set(field, new Map());
|
|
170
|
+
const byValue = metadataIndexes.get(field);
|
|
171
|
+
const valueKey = metadataValueKey(value);
|
|
172
|
+
if (!byValue.has(valueKey)) byValue.set(valueKey, new Set());
|
|
173
|
+
byValue.get(valueKey).add(String(id));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return { ids, dims, packed, norms, idToOffset, metadataIndexes };
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function vectorNorm(query) {
|
|
181
|
+
let norm = 0;
|
|
182
|
+
for (let i = 0; i < query.length; i += 1) {
|
|
183
|
+
const value = Number(query[i] || 0);
|
|
184
|
+
norm += value * value;
|
|
185
|
+
}
|
|
186
|
+
return Math.sqrt(norm) || 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function packedCosine(index, row, query, queryNorm) {
|
|
190
|
+
if (!index.dims || !queryNorm || !index.norms[row]) return 0;
|
|
191
|
+
const base = row * index.dims;
|
|
192
|
+
let score = 0;
|
|
193
|
+
for (let col = 0; col < index.dims; col += 1) {
|
|
194
|
+
score += index.packed[base + col] * Number(query[col] || 0);
|
|
195
|
+
}
|
|
196
|
+
return score / (index.norms[row] * queryNorm);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function candidateIdsFromOptions(index, options) {
|
|
200
|
+
let candidates = options.docIds ? new Set(options.docIds.map(String)) : null;
|
|
201
|
+
const equalitySet = equalityCandidateSet(index, options.filters);
|
|
202
|
+
if (equalitySet) candidates = intersectSets(candidates, equalitySet);
|
|
203
|
+
return candidates;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function queryDefault(data, index, query, k, options = {}) {
|
|
207
|
+
const limit = Math.max(0, Number(k) || 0);
|
|
208
|
+
if (!limit) return [];
|
|
209
|
+
|
|
210
|
+
const candidates = candidateIdsFromOptions(index, options);
|
|
211
|
+
const queryNorm = vectorNorm(query);
|
|
212
|
+
const top = [];
|
|
213
|
+
const ids = candidates ? Array.from(candidates) : index.ids;
|
|
214
|
+
|
|
215
|
+
for (const id of ids) {
|
|
216
|
+
const row = index.idToOffset.get(String(id));
|
|
217
|
+
if (row == null) continue;
|
|
218
|
+
const metadata = data.metadataDict[id] || {};
|
|
219
|
+
if (!filterMatches(metadata, options.filters)) continue;
|
|
220
|
+
topKPush(top, { id, score: packedCosine(index, row, query, queryNorm) }, limit);
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return top.sort((a, b) => b.score - a.score);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function queryMmr(data, index, query, k, options = {}) {
|
|
227
|
+
const lambda = Number.isFinite(options.lambda) ? options.lambda : 0.5;
|
|
228
|
+
const pool = queryDefault(data, index, query, Math.max(4 * k, k), options);
|
|
229
|
+
const selected = [];
|
|
230
|
+
while (selected.length < k && pool.length) {
|
|
231
|
+
let bestIndex = 0;
|
|
232
|
+
let bestScore = -Infinity;
|
|
233
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
234
|
+
const candidate = pool[i];
|
|
235
|
+
const candidateVector = data.embeddingDict[candidate.id] || [];
|
|
236
|
+
const diversity = selected.length
|
|
237
|
+
? Math.max(...selected.map((hit) => cosine(candidateVector, data.embeddingDict[hit.id] || [])))
|
|
238
|
+
: 0;
|
|
239
|
+
const score = lambda * candidate.score - (1 - lambda) * diversity;
|
|
240
|
+
if (score > bestScore) {
|
|
241
|
+
bestScore = score;
|
|
242
|
+
bestIndex = i;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
selected.push(pool.splice(bestIndex, 1)[0]);
|
|
246
|
+
}
|
|
247
|
+
return selected;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
class MumpixVectorSidecar {
|
|
251
|
+
constructor(db, options = {}) {
|
|
252
|
+
this.db = db;
|
|
253
|
+
this.vectorPath = options.vectorPath || defaultVectorPath(db);
|
|
254
|
+
this.data = options.data || loadData(this.vectorPath);
|
|
255
|
+
this._packedIndex = null;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
persist() {
|
|
259
|
+
saveData(this.vectorPath, this.data);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
_invalidateIndex() {
|
|
263
|
+
this._packedIndex = null;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
_index() {
|
|
267
|
+
if (!this._packedIndex) this._packedIndex = buildPackedIndex(this.data);
|
|
268
|
+
return this._packedIndex;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
get(id) {
|
|
272
|
+
return this.data.embeddingDict[String(id)] || null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
async addItem({ id, text, embedding, metadata = {}, refDocId = null }) {
|
|
276
|
+
if (!Array.isArray(embedding)) {
|
|
277
|
+
throw new Error("Mumpix vector adapters require numeric embeddings.");
|
|
278
|
+
}
|
|
279
|
+
const record = await this.db.remember(text || metadata.text || String(id));
|
|
280
|
+
const textId = String(id || record.id);
|
|
281
|
+
this.data.embeddingDict[textId] = embedding.map(Number);
|
|
282
|
+
this.data.textIdToRecordId[textId] = String(record.id);
|
|
283
|
+
this.data.textIdToRefDocId[textId] = String(refDocId || metadata.refDocId || record.id);
|
|
284
|
+
this.data.metadataDict[textId] = { ...metadata, mumpixRecordId: record.id };
|
|
285
|
+
this.data.textDict[textId] = text || metadata.text || "";
|
|
286
|
+
this._invalidateIndex();
|
|
287
|
+
this.persist();
|
|
288
|
+
return textId;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
deleteRefDoc(refDocId) {
|
|
292
|
+
const target = String(refDocId);
|
|
293
|
+
for (const [textId, storedRefDocId] of Object.entries(this.data.textIdToRefDocId)) {
|
|
294
|
+
if (String(storedRefDocId) !== target && String(textId) !== target) continue;
|
|
295
|
+
delete this.data.embeddingDict[textId];
|
|
296
|
+
delete this.data.textIdToRecordId[textId];
|
|
297
|
+
delete this.data.textIdToRefDocId[textId];
|
|
298
|
+
delete this.data.metadataDict[textId];
|
|
299
|
+
delete this.data.textDict[textId];
|
|
300
|
+
}
|
|
301
|
+
this._invalidateIndex();
|
|
302
|
+
this.persist();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
query(query, k, options = {}) {
|
|
306
|
+
const index = this._index();
|
|
307
|
+
const hits =
|
|
308
|
+
String(options.mode || "default").toLowerCase() === "mmr"
|
|
309
|
+
? queryMmr(this.data, index, query, k, options)
|
|
310
|
+
: queryDefault(this.data, index, query, k, options);
|
|
311
|
+
return {
|
|
312
|
+
ids: hits.map((hit) => hit.id),
|
|
313
|
+
similarities: hits.map((hit) => hit.score),
|
|
314
|
+
records: hits.map((hit) => ({
|
|
315
|
+
id: hit.id,
|
|
316
|
+
score: hit.score,
|
|
317
|
+
text: this.data.textDict[hit.id] || "",
|
|
318
|
+
metadata: this.data.metadataDict[hit.id] || {},
|
|
319
|
+
embedding: this.data.embeddingDict[hit.id] || [],
|
|
320
|
+
})),
|
|
321
|
+
};
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
module.exports = { MumpixVectorSidecar, cosine };
|
package/src/rlp/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";const e=[{id:"promotion",name:"Promotion mechanism",description:"Records successful patterns as genes with evidence thresholds."},{id:"retrieval",name:"Retrieval mechanism",description:"Queries the gene library before LLM fallback."},{id:"domain_routing",name:"Domain routing",description:"Scopes retrieval to prevent cross-domain monopoly."},{id:"retrieval_pathway_repair",name:"Retrieval pathway repair",description:"Ensures promoted genes are reachable and their actions are executable."},{id:"decay_calibration",name:"Decay calibration",description:"Keeps confidence decay thresholds above the empirical natural concentration baseline."}],a=[["gap_1",1,"Promotion without retrieval","Genes are promoted but never queried."],["gap_2",2,"Universal policy collapse","A single gene monopolizes all decisions."],["gap_3",3,"Confidence asymmetry","High-confidence universal genes crowd out specialized genes."],["gap_4",4,"Ranking exclusion","Non-dominant genes are absent from the top-k candidate set."],["gap_5",5,"Specification-implementation gap","Domain filters are accepted but not enforced."],["gap_6",6,"Promotion-retrieval orthogonality","Promotion does not guarantee utilization."],["gap_7",7,"Zero-learning fixed point","Exploration set to zero prevents new promotions."],["gap_8",8,"Bootstrap phase stall","No specialized genes exist until enough LLM observations accumulate."],["gap_9",9,"Bypass pathway promotions","Promotions enter a ledger path that does not participate in retrieval."],["gap_10",10,"Action Deserialization Failure","Genes are credited as executed while action fields are empty or unparseable."],["gap_11",11,"Confidence Decay Miscalibration","Anti-monopoly decay is set at or below the natural concentration baseline."],["gap_12",12,"Execution State Contamination","A gene sequence fails mid-execution and leaves contaminated environment state."],["gap_13",13,"Trigger Signature Drift","The environment evolves so a trigger no longer denotes the same condition."],["gap_14",14,"Trigger-Sequence Divergence","Trigger revalidations diverge too far from the original proven sequence."]].map(([e,a,t,n])=>({id:e,number:a,name:t,description:n}));function t(e){const t=String(e).toLowerCase();return a.find(e=>String(e.number)===t||e.id===t||e.id===`gap_${t}`)||null}module.exports={REQUIRED_MECHANISMS:e,FAILURE_MODES:a,ARCHITECTURAL_LAWS:[{number:1,name:"Domain Constraint",statement:"Any globally-ranked behavioral retrieval system without domain constraints will converge to a single-policy attractor state."},{number:2,name:"Decay Calibration",statement:"Any confidence-decay mechanism whose trigger lies at or below the domain empirical concentration baseline will re-instantiate universal policy collapse."},{number:3,name:"Execution State Isolation",statement:"Any behavioral execution system without execution state isolation will converge to contaminated context as a stable failure mode."}],gap:t,validateActionBoundary:function(e){if(!e||"object"!=typeof e)return{ok:!1,gap:t(10),error:"record must be an object"};const a=e.executable_payload||e.action||e.payload;if(!a)return{ok:!1,gap:t(10),error:"action payload is empty"};try{const e="string"==typeof a?JSON.parse(a):a;if(!e||"object"!=typeof e)throw new Error("payload must be an object");return"DO"!==e.intent||Array.isArray(e.sequence)&&0!==e.sequence.length?{ok:!0,payload:e}:{ok:!1,gap:t(10),error:"DO payload has no executable sequence"}}catch(e){return{ok:!1,gap:t(10),error:e.message}}},mechanismChecklist:function(a={}){const t=new Set(Object.entries(a).filter(([,e])=>Boolean(e)).map(([e])=>e));return e.map(e=>({...e,present:t.has(e.id)}))}};
|