mumpix 1.0.20 → 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,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const fs = require("fs");
|
|
4
|
+
|
|
5
|
+
class WalWriter {
|
|
6
|
+
constructor(walPath, tier, opts = {}) {
|
|
7
|
+
this._walPath = walPath;
|
|
8
|
+
this._perRecord = tier === "strict" || tier === "verified";
|
|
9
|
+
this._intervalMs = Number.isFinite(opts.intervalMs) ? opts.intervalMs : 10;
|
|
10
|
+
this._maxPending = Number.isFinite(opts.maxPendingBytes)
|
|
11
|
+
? opts.maxPendingBytes
|
|
12
|
+
: 1024 * 1024;
|
|
13
|
+
this._fd = null;
|
|
14
|
+
this._pendingBytes = 0;
|
|
15
|
+
this._lastFlush = 0;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
_ensureFd() {
|
|
19
|
+
if (this._fd == null) {
|
|
20
|
+
this._fd = fs.openSync(this._walPath, "a");
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
append(line) {
|
|
25
|
+
this._ensureFd();
|
|
26
|
+
const buf = line.endsWith("\n") ? line : `${line}\n`;
|
|
27
|
+
fs.writeSync(this._fd, buf, null, "utf8");
|
|
28
|
+
|
|
29
|
+
if (this._perRecord) {
|
|
30
|
+
fs.fdatasyncSync(this._fd);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
this._pendingBytes += Buffer.byteLength(buf);
|
|
35
|
+
const now = Date.now();
|
|
36
|
+
if (
|
|
37
|
+
this._pendingBytes >= this._maxPending ||
|
|
38
|
+
now - this._lastFlush >= this._intervalMs
|
|
39
|
+
) {
|
|
40
|
+
this.flush();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
appendBatch(lines) {
|
|
45
|
+
if (!lines.length) return;
|
|
46
|
+
this._ensureFd();
|
|
47
|
+
const joined = `${lines.join("\n")}\n`;
|
|
48
|
+
fs.writeSync(this._fd, joined, null, "utf8");
|
|
49
|
+
this.flush();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
flush() {
|
|
53
|
+
if (this._fd == null) return;
|
|
54
|
+
fs.fdatasyncSync(this._fd);
|
|
55
|
+
this._pendingBytes = 0;
|
|
56
|
+
this._lastFlush = Date.now();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
close({ flush = true } = {}) {
|
|
60
|
+
if (this._fd == null) return;
|
|
61
|
+
if (flush) {
|
|
62
|
+
try {
|
|
63
|
+
fs.fdatasyncSync(this._fd);
|
|
64
|
+
} catch (_) {
|
|
65
|
+
// Best effort on shutdown.
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
fs.closeSync(this._fd);
|
|
70
|
+
} catch (_) {}
|
|
71
|
+
this._fd = null;
|
|
72
|
+
this._pendingBytes = 0;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
unlink({ flush = this._perRecord } = {}) {
|
|
76
|
+
this.close({ flush });
|
|
77
|
+
try {
|
|
78
|
+
fs.unlinkSync(this._walPath);
|
|
79
|
+
} catch (_) {}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
module.exports = { WalWriter };
|
package/src/index.js
CHANGED
|
@@ -1,51 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { MumpixDB } = require("./core/MumpixDB");
|
|
4
|
+
const { MumpixStore } = require("./core/store");
|
|
5
|
+
const { MumpixAudit } = require("./core/audit");
|
|
6
|
+
const { WalWriter } = require("./core/wal-writer");
|
|
7
|
+
const { InvertedIndex } = require("./core/inverted-index");
|
|
8
|
+
const { recall, recallMany, tokenize } = require("./core/recall");
|
|
9
|
+
const { MumpixDevClient, MumpixApiError } = require("./integrations/developer-sdk");
|
|
10
|
+
const temporal = require("./temporal/operators");
|
|
11
|
+
const temporalEngine = require("./temporal/engine");
|
|
12
|
+
const temporalIndexes = require("./temporal/indexes");
|
|
13
|
+
const brp = require("./brp");
|
|
14
|
+
const rlp = require("./rlp");
|
|
15
|
+
const collapse = require("./collapse");
|
|
2
16
|
|
|
3
|
-
/**
|
|
4
|
-
* mumpix — SQLite for AI
|
|
5
|
-
*
|
|
6
|
-
* Quick start:
|
|
7
|
-
* const { Mumpix } = require('mumpix')
|
|
8
|
-
* const db = Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
9
|
-
*
|
|
10
|
-
* await db.remember('User prefers TypeScript')
|
|
11
|
-
* const ans = await db.recall('What language do they prefer?')
|
|
12
|
-
* console.log(ans) // → 'User prefers TypeScript'
|
|
13
|
-
*
|
|
14
|
-
* await db.close()
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
const { MumpixDB } = require('./core/MumpixDB');
|
|
18
|
-
const { MumpixStore } = require('./core/store');
|
|
19
|
-
const { MumpixAudit } = require('./core/audit');
|
|
20
|
-
const { recall, recallMany, tokenize } = require('./core/recall');
|
|
21
|
-
const { MumpixDevClient, MumpixApiError } = require('./integrations/developer-sdk');
|
|
22
|
-
const temporal = require('./temporal/operators');
|
|
23
|
-
const temporalEngine = require('./temporal/engine');
|
|
24
|
-
const temporalIndexes = require('./temporal/indexes');
|
|
25
|
-
|
|
26
|
-
// Convenience alias: Mumpix.open() === MumpixDB.open()
|
|
27
17
|
const Mumpix = MumpixDB;
|
|
28
18
|
|
|
29
19
|
module.exports = {
|
|
30
|
-
// Primary export — use this
|
|
31
20
|
Mumpix,
|
|
32
21
|
MumpixDB,
|
|
33
|
-
|
|
34
|
-
// Lower-level exports for advanced use
|
|
35
22
|
MumpixStore,
|
|
36
23
|
MumpixAudit,
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
WalWriter,
|
|
25
|
+
InvertedIndex,
|
|
39
26
|
recall,
|
|
40
27
|
recallMany,
|
|
41
28
|
tokenize,
|
|
42
|
-
|
|
43
|
-
// Deterministic temporal event operators
|
|
44
29
|
temporal,
|
|
45
30
|
temporalEngine,
|
|
46
31
|
temporalIndexes,
|
|
47
|
-
|
|
48
|
-
|
|
32
|
+
brp,
|
|
33
|
+
rlp,
|
|
34
|
+
collapse,
|
|
49
35
|
MumpixDevClient,
|
|
50
36
|
MumpixApiError,
|
|
51
37
|
};
|
|
@@ -1,165 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
class MumpixApiError extends Error {
|
|
4
|
-
constructor(message, status, data) {
|
|
5
|
-
super(message);
|
|
6
|
-
this.name = 'MumpixApiError';
|
|
7
|
-
this.status = status;
|
|
8
|
-
this.data = data;
|
|
9
|
-
}
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
class MumpixDevClient {
|
|
13
|
-
constructor(opts = {}) {
|
|
14
|
-
const baseUrl = String(opts.baseUrl || 'http://127.0.0.1:3012').replace(/\/+$/, '');
|
|
15
|
-
this.baseUrl = baseUrl;
|
|
16
|
-
this.fetch = opts.fetch || globalThis.fetch;
|
|
17
|
-
this.defaultHeaders = opts.headers && typeof opts.headers === 'object' ? { ...opts.headers } : {};
|
|
18
|
-
if (typeof this.fetch !== 'function') {
|
|
19
|
-
throw new Error('MumpixDevClient requires fetch (Node 18+ or pass opts.fetch)');
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
_url(path, query) {
|
|
24
|
-
const cleanPath = String(path || '').startsWith('/') ? String(path) : `/${String(path || '')}`;
|
|
25
|
-
const url = new URL(this.baseUrl + cleanPath);
|
|
26
|
-
if (query && typeof query === 'object') {
|
|
27
|
-
for (const [key, value] of Object.entries(query)) {
|
|
28
|
-
if (value === undefined || value === null || value === '') continue;
|
|
29
|
-
url.searchParams.set(key, String(value));
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return url.toString();
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
async _request(path, opts = {}) {
|
|
36
|
-
const method = String(opts.method || 'GET').toUpperCase();
|
|
37
|
-
const headers = { ...this.defaultHeaders, ...(opts.headers || {}) };
|
|
38
|
-
let body = opts.body;
|
|
39
|
-
if (body && typeof body === 'object' && !(body instanceof ArrayBuffer) && !(body instanceof Uint8Array) && !(typeof FormData !== 'undefined' && body instanceof FormData)) {
|
|
40
|
-
headers['Content-Type'] = headers['Content-Type'] || 'application/json; charset=utf-8';
|
|
41
|
-
body = JSON.stringify(body);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const res = await this.fetch(this._url(path, opts.query), {
|
|
45
|
-
method,
|
|
46
|
-
headers,
|
|
47
|
-
body,
|
|
48
|
-
credentials: opts.credentials || 'include',
|
|
49
|
-
signal: opts.signal,
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
const contentType = String(res.headers.get('content-type') || '').toLowerCase();
|
|
53
|
-
let data;
|
|
54
|
-
if (contentType.includes('application/json')) {
|
|
55
|
-
data = await res.json().catch(() => null);
|
|
56
|
-
} else {
|
|
57
|
-
data = await res.text().catch(() => '');
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (!res.ok) {
|
|
61
|
-
const msg = data && typeof data === 'object' && data.error
|
|
62
|
-
? String(data.error)
|
|
63
|
-
: `Request failed (${res.status})`;
|
|
64
|
-
throw new MumpixApiError(msg, res.status, data);
|
|
65
|
-
}
|
|
66
|
-
return data;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
health() {
|
|
70
|
-
return this._request('/api/health');
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async remember(content) {
|
|
74
|
-
// Primary app API expects `text`. Keep `content` fallback for older endpoints.
|
|
75
|
-
try {
|
|
76
|
-
return await this._request('/remember', { method: 'POST', body: { text: content } });
|
|
77
|
-
} catch (error) {
|
|
78
|
-
if (error && Number(error.status) === 400) {
|
|
79
|
-
return this._request('/remember', { method: 'POST', body: { content } });
|
|
80
|
-
}
|
|
81
|
-
throw error;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
recall(query) {
|
|
86
|
-
return this._request('/recall', { method: 'POST', body: { query } });
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
recallMany(query, k = 5) {
|
|
90
|
-
return this._request('/recall-many', { method: 'POST', body: { query, k } });
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
memories() {
|
|
94
|
-
return this._request('/memories');
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
clear() {
|
|
98
|
-
return this._request('/memories', { method: 'DELETE' });
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
stats() {
|
|
102
|
-
return this._request('/stats');
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
settings() {
|
|
106
|
-
return this._request('/settings');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
updateSettings(patch) {
|
|
110
|
-
return this._request('/settings', { method: 'POST', body: patch || {} });
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
files() {
|
|
114
|
-
return this._request('/mumpix-explorer/files');
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
readFile(file, opts = {}) {
|
|
118
|
-
return this._request('/mumpix-explorer/read', {
|
|
119
|
-
query: {
|
|
120
|
-
file,
|
|
121
|
-
atTs: opts.atTs,
|
|
122
|
-
source: opts.source,
|
|
123
|
-
},
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
timeline(file, opts = {}) {
|
|
128
|
-
return this._request('/mumpix-explorer/timeline', {
|
|
129
|
-
query: {
|
|
130
|
-
file,
|
|
131
|
-
source: opts.source,
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
exportUrl(file, format = 'mumpix', opts = {}) {
|
|
137
|
-
return this._url('/mumpix-explorer/export', {
|
|
138
|
-
file,
|
|
139
|
-
format,
|
|
140
|
-
atTs: opts.atTs,
|
|
141
|
-
source: opts.source,
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
roms() {
|
|
146
|
-
return this._request('/emulator/roms');
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
manualForRom(file) {
|
|
150
|
-
return this._request('/emulator/manual', { query: { file } });
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
manualViewUrl(file, opts = {}) {
|
|
154
|
-
return this._url('/emulator/manual/view', {
|
|
155
|
-
file,
|
|
156
|
-
isolate: opts.isolate ? '1' : undefined,
|
|
157
|
-
v: opts.v || Date.now(),
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
module.exports = {
|
|
163
|
-
MumpixDevClient,
|
|
164
|
-
MumpixApiError,
|
|
165
|
-
};
|
|
1
|
+
"use strict";class e extends Error{constructor(e,t,r){super(e),this.name="MumpixApiError",this.status=t,this.data=r}}module.exports={MumpixDevClient:class{constructor(e={}){const t=String(e.baseUrl||"http://127.0.0.1:3012").replace(/\/+$/,"");if(this.baseUrl=t,this.fetch=e.fetch||globalThis.fetch,this.defaultHeaders=e.headers&&"object"==typeof e.headers?{...e.headers}:{},"function"!=typeof this.fetch)throw new Error("MumpixDevClient requires fetch (Node 18+ or pass opts.fetch)")}_url(e,t){const r=String(e||"").startsWith("/")?String(e):`/${String(e||"")}`,s=new URL(this.baseUrl+r);if(t&&"object"==typeof t)for(const[e,r]of Object.entries(t))null!=r&&""!==r&&s.searchParams.set(e,String(r));return s.toString()}async _request(t,r={}){const s=String(r.method||"GET").toUpperCase(),i={...this.defaultHeaders,...r.headers||{}};let o=r.body;!o||"object"!=typeof o||o instanceof ArrayBuffer||o instanceof Uint8Array||"undefined"!=typeof FormData&&o instanceof FormData||(i["Content-Type"]=i["Content-Type"]||"application/json; charset=utf-8",o=JSON.stringify(o));const a=await this.fetch(this._url(t,r.query),{method:s,headers:i,body:o,credentials:r.credentials||"include",signal:r.signal});let n;if(n=String(a.headers.get("content-type")||"").toLowerCase().includes("application/json")?await a.json().catch(()=>null):await a.text().catch(()=>""),!a.ok){const t=n&&"object"==typeof n&&n.error?String(n.error):`Request failed (${a.status})`;throw new e(t,a.status,n)}return n}health(){return this._request("/api/health")}async remember(e){try{return await this._request("/remember",{method:"POST",body:{text:e}})}catch(t){if(t&&400===Number(t.status))return this._request("/remember",{method:"POST",body:{content:e}});throw t}}recall(e){return this._request("/recall",{method:"POST",body:{query:e}})}recallMany(e,t=5){return this._request("/recall-many",{method:"POST",body:{query:e,k:t}})}memories(){return this._request("/memories")}clear(){return this._request("/memories",{method:"DELETE"})}stats(){return this._request("/stats")}settings(){return this._request("/settings")}updateSettings(e){return this._request("/settings",{method:"POST",body:e||{}})}files(){return this._request("/mumpix-explorer/files")}readFile(e,t={}){return this._request("/mumpix-explorer/read",{query:{file:e,atTs:t.atTs,source:t.source}})}timeline(e,t={}){return this._request("/mumpix-explorer/timeline",{query:{file:e,source:t.source}})}exportUrl(e,t="mumpix",r={}){return this._url("/mumpix-explorer/export",{file:e,format:t,atTs:r.atTs,source:r.source})}roms(){return this._request("/emulator/roms")}manualForRom(e){return this._request("/emulator/manual",{query:{file:e}})}manualViewUrl(e,t={}){return this._url("/emulator/manual/view",{file:e,isolate:t.isolate?"1":void 0,v:t.v||Date.now()})}},MumpixApiError:e};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";let e;try{e={...require("@langchain/core/vectorstores"),...require("@langchain/core/retrievers"),...require("@langchain/core/documents"),...require("@langchain/core/memory")}}catch(e){throw new Error("mumpix LangChain official adapters require optional peer dependency @langchain/core. Install it with: npm i @langchain/core")}const{VectorStore:t,BaseRetriever:r,Document:i,BaseMemory:a}=e,{MumpixVectorSidecar:s}=require("./vector-sidecar");function n(e){if(!e||"function"!=typeof e.embedDocuments||"function"!=typeof e.embedQuery)throw new Error("MumpixLangChainVectorStore requires a LangChain embeddings object for this operation.")}function c(e){return e&&"string"==typeof e.pageContent?e.pageContent:String(e||"")}function o(e){return e&&e.metadata&&"object"==typeof e.metadata?e.metadata:{}}function d(e){return new i({pageContent:e.text,metadata:{...e.metadata,id:e.id,score:e.score}})}module.exports={MumpixLangChainVectorStore:class extends t{constructor(e,t={}){super(t.embeddings||{},t),this.db=e,this.sidecar=new s(e,t)}_vectorstoreType(){return"mumpix"}async addDocuments(e,t={}){n(this.embeddings);const r=await this.embeddings.embedDocuments(e.map(c));return this.addVectors(r,e,t)}async addVectors(e,t){const r=[];for(let i=0;i<t.length;i++){const a=t[i],s=o(a),n=await this.sidecar.addItem({id:s.id||s.textId,text:c(a),embedding:e[i],metadata:s,refDocId:s.refDocId||s.source});r.push(n)}return r}async addTexts(e,t=[]){const r=e.map((e,r)=>new i({pageContent:e,metadata:Array.isArray(t)?t[r]||{}:t||{}}));return this.addDocuments(r)}async delete(e={}){const t=e.ids||e.id;if(Array.isArray(t))for(const e of t)this.sidecar.deleteRefDoc(e);else t?this.sidecar.deleteRefDoc(t):e.refDocId&&this.sidecar.deleteRefDoc(e.refDocId)}async similaritySearchVectorWithScore(e,t,r){return this.sidecar.query(e,t,{filters:r}).records.map(e=>[d(e),e.score])}async similaritySearch(e,t=4,r){n(this.embeddings);const i=await this.embeddings.embedQuery(String(e||""));return this.sidecar.query(i,t,{filters:r}).records.map(d)}async similaritySearchWithScore(e,t=4,r){n(this.embeddings);const i=await this.embeddings.embedQuery(String(e||""));return this.sidecar.query(i,t,{filters:r}).records.map(e=>[d(e),e.score])}async maxMarginalRelevanceSearch(e,t={}){n(this.embeddings);const r=await this.embeddings.embedQuery(String(e||""));return this.sidecar.query(r,t.k||4,{filters:t.filter,mode:"mmr",lambda:t.lambda}).records.map(d)}async save(){this.sidecar.persist()}},MumpixLangChainRetriever:class extends r{constructor(e,t={}){super(t),this.db=e,this.k=t.k||4,this.lc_namespace=["mumpix","retrievers"]}async _getRelevantDocuments(e){return(await this.db.recallMany(String(e||""),this.k)).map(e=>new i({pageContent:e.content,metadata:{id:e.id,ts:e.ts,score:e.score}}))}},MumpixLangChainMemory:class extends a{constructor({db:e,k:t=4,inputKey:r="input",outputKey:i="output",memoryKey:a="history"}={}){super(),this.db=e,this.k=t,this.inputKey=r,this.outputKey=i,this.memoryKey=a}get memoryKeys(){return[this.memoryKey]}async loadMemoryVariables(e){const t=e[this.inputKey]||"",r=await this.db.recallMany(String(t),this.k);return{[this.memoryKey]:r.map(e=>e.content).join("\n")}}async saveContext(e,t){const r=e[this.inputKey]||"",i=t[this.outputKey]||"";r&&await this.db.remember(`Human: ${r}`),i&&await this.db.remember(`AI: ${i}`)}async clear(){await this.db.clear()}}};
|
|
@@ -1,131 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Mumpix × LangChain integration
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* const { MumpixVectorStore } = require('mumpix/src/integrations/langchain')
|
|
8
|
-
* const db = Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
9
|
-
* const store = new MumpixVectorStore(db)
|
|
10
|
-
*
|
|
11
|
-
* // Use as a LangChain Memory:
|
|
12
|
-
* const memory = new MumpixChatMemory({ db })
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
const { recallMany } = require('../core/recall');
|
|
16
|
-
|
|
17
|
-
/**
|
|
18
|
-
* MumpixVectorStore — drop-in VectorStore adapter for LangChain.
|
|
19
|
-
*
|
|
20
|
-
* Works with any LangChain retriever that accepts .similaritySearch().
|
|
21
|
-
* No external vector library required — uses Mumpix's built-in TF-IDF.
|
|
22
|
-
*/
|
|
23
|
-
class MumpixVectorStore {
|
|
24
|
-
constructor(db) {
|
|
25
|
-
this.db = db;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* LangChain VectorStore interface
|
|
30
|
-
*/
|
|
31
|
-
async similaritySearch(query, k = 4) {
|
|
32
|
-
const results = await this.db.recallMany(query, k);
|
|
33
|
-
return results.map(r => ({
|
|
34
|
-
pageContent: r.content,
|
|
35
|
-
metadata: { id: r.id, ts: r.ts, score: r.score },
|
|
36
|
-
}));
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
async similaritySearchWithScore(query, k = 4) {
|
|
40
|
-
const results = await this.db.recallMany(query, k);
|
|
41
|
-
return results.map(r => ([
|
|
42
|
-
{ pageContent: r.content, metadata: { id: r.id, ts: r.ts } },
|
|
43
|
-
r.score,
|
|
44
|
-
]));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async addDocuments(docs) {
|
|
48
|
-
const results = [];
|
|
49
|
-
for (const doc of docs) {
|
|
50
|
-
const r = await this.db.remember(doc.pageContent);
|
|
51
|
-
results.push(r.id.toString());
|
|
52
|
-
}
|
|
53
|
-
return results;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
async addTexts(texts, metadatas = []) {
|
|
57
|
-
const ids = [];
|
|
58
|
-
for (const text of texts) {
|
|
59
|
-
const r = await this.db.remember(text);
|
|
60
|
-
ids.push(r.id.toString());
|
|
61
|
-
}
|
|
62
|
-
return ids;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* MumpixChatMemory — LangChain BaseChatMemory compatible adapter.
|
|
68
|
-
*
|
|
69
|
-
* Stores conversation turns as memories and retrieves them semantically.
|
|
70
|
-
*
|
|
71
|
-
* const memory = new MumpixChatMemory({ db, k: 3 })
|
|
72
|
-
* // Then pass as `memory` to LLMChain, ConversationChain, etc.
|
|
73
|
-
*/
|
|
74
|
-
class MumpixChatMemory {
|
|
75
|
-
constructor({ db, k = 4, inputKey = 'input', outputKey = 'output' } = {}) {
|
|
76
|
-
this.db = db;
|
|
77
|
-
this.k = k;
|
|
78
|
-
this.inputKey = inputKey;
|
|
79
|
-
this.outputKey = outputKey;
|
|
80
|
-
this.memoryKey = 'history';
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
get memoryKeys() {
|
|
84
|
-
return [this.memoryKey];
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
async loadMemoryVariables(values) {
|
|
88
|
-
const query = values[this.inputKey] || '';
|
|
89
|
-
const results = await this.db.recallMany(query, this.k);
|
|
90
|
-
const history = results.map(r => r.content).join('\n');
|
|
91
|
-
return { [this.memoryKey]: history };
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async saveContext(inputs, outputs) {
|
|
95
|
-
const input = inputs[this.inputKey] || '';
|
|
96
|
-
const output = outputs[this.outputKey] || '';
|
|
97
|
-
if (input) await this.db.remember(`Human: ${input}`);
|
|
98
|
-
if (output) await this.db.remember(`AI: ${output}`);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
async clear() {
|
|
102
|
-
await this.db.clear();
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* MumpixRetriever — LangChain BaseRetriever compatible adapter.
|
|
108
|
-
*
|
|
109
|
-
* const retriever = new MumpixRetriever(db, { k: 5 })
|
|
110
|
-
* const results = await retriever.getRelevantDocuments("query")
|
|
111
|
-
*/
|
|
112
|
-
class MumpixRetriever {
|
|
113
|
-
constructor(db, opts = {}) {
|
|
114
|
-
this.db = db;
|
|
115
|
-
this.k = opts.k || 4;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async getRelevantDocuments(query) {
|
|
119
|
-
const results = await this.db.recallMany(query, this.k);
|
|
120
|
-
return results.map(r => ({
|
|
121
|
-
pageContent: r.content,
|
|
122
|
-
metadata: { id: r.id, ts: r.ts, score: r.score },
|
|
123
|
-
}));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
module.exports = {
|
|
128
|
-
MumpixVectorStore,
|
|
129
|
-
MumpixChatMemory,
|
|
130
|
-
MumpixRetriever,
|
|
131
|
-
};
|
|
1
|
+
"use strict";const{recallMany:t}=require("../core/recall");module.exports={MumpixVectorStore:class{constructor(t){this.db=t}async similaritySearch(t,e=4){return(await this.db.recallMany(t,e)).map(t=>({pageContent:t.content,metadata:{id:t.id,ts:t.ts,score:t.score}}))}async similaritySearchWithScore(t,e=4){return(await this.db.recallMany(t,e)).map(t=>[{pageContent:t.content,metadata:{id:t.id,ts:t.ts}},t.score])}async addDocuments(t){const e=[];for(const s of t){const t=await this.db.remember(s.pageContent);e.push(t.id.toString())}return e}async addTexts(t,e=[]){const s=[];for(const e of t){const t=await this.db.remember(e);s.push(t.id.toString())}return s}},MumpixChatMemory:class{constructor({db:t,k:e=4,inputKey:s="input",outputKey:a="output"}={}){this.db=t,this.k=e,this.inputKey=s,this.outputKey=a,this.memoryKey="history"}get memoryKeys(){return[this.memoryKey]}async loadMemoryVariables(t){const e=t[this.inputKey]||"",s=(await this.db.recallMany(e,this.k)).map(t=>t.content).join("\n");return{[this.memoryKey]:s}}async saveContext(t,e){const s=t[this.inputKey]||"",a=e[this.outputKey]||"";s&&await this.db.remember(`Human: ${s}`),a&&await this.db.remember(`AI: ${a}`)}async clear(){await this.db.clear()}},MumpixRetriever:class{constructor(t,e={}){this.db=t,this.k=e.k||4}async getRelevantDocuments(t){return(await this.db.recallMany(t,this.k)).map(t=>({pageContent:t.content,metadata:{id:t.id,ts:t.ts,score:t.score}}))}}};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";let e,t;try{e=require("llamaindex"),t=require("llamaindex/vector-store")}catch(e){throw new Error("mumpix LlamaIndex official adapters require optional peer dependency llamaindex. Install it with: npm i llamaindex")}const{BaseRetriever:r,TextNode:i}=e,{BaseVectorStore:n,VectorStoreQueryMode:d}=t,{MumpixVectorSidecar:a}=require("./vector-sidecar"),s={getTextEmbedding:async()=>[],getQueryEmbedding:async()=>[]};function o(e){return e&&"function"==typeof e.getContent?String(e.getContent()||""):e&&"string"==typeof e.text?e.text:e&&"function"==typeof e.getText?String(e.getText()||""):String(e||"")}function c(e){if(e&&"function"==typeof e.getEmbedding)return e.getEmbedding();if(e&&Array.isArray(e.embedding))return e.embedding;throw new Error("MumpixLlamaIndexVectorStore.add() requires nodes with embeddings.")}function u(e){return e&&e.metadata&&"object"==typeof e.metadata?e.metadata:{}}function m(e){return e&&e.sourceNode&&(e.sourceNode.nodeId||e.sourceNode.id_)||e&&e.refDocId||e&&e.id_||null}function l(e){return new i({id_:String(e.id),text:e.text,metadata:e.metadata||{}})}module.exports={MumpixLlamaIndexVectorStore:class extends n{constructor(e,t={}){super({...t,embedModel:t.embedModel||t.embeddingModel||s}),this.db=e,this.storesText=!0,this.sidecar=new a(e,t)}client(){return null}async get(e){return this.sidecar.get(e)}async add(e){const t=[];for(const r of e){const e=await this.sidecar.addItem({id:r&&r.id_,text:o(r),embedding:c(r),metadata:u(r),refDocId:m(r)});t.push(e)}return t}async delete(e){this.sidecar.deleteRefDoc(e)}async query(e){if(!e||!Array.isArray(e.queryEmbedding))throw new Error("MumpixLlamaIndexVectorStore.query() requires query.queryEmbedding.");const t=e.mode===d.MMR?"mmr":"default",r=this.sidecar.query(e.queryEmbedding,e.similarityTopK||5,{mode:t,filters:e.filters,docIds:e.docIds,lambda:e.alpha});return{ids:r.ids,similarities:r.similarities,nodes:r.records.map(l)}}async persist(e){e&&(this.sidecar.vectorPath=e),this.sidecar.persist()}},MumpixLlamaIndexRetriever:class extends r{constructor(e,t={}){super(),this.db=e,this.topK=t.topK||5}async _retrieve(e){const t=function(e){return"string"==typeof e?e:e&&"string"==typeof e.query?e.query:e&&"string"==typeof e.queryStr?e.queryStr:String(e&&e.query?e.query:"")}(e);return(await this.db.recallMany(t,this.topK)).map(e=>({node:new i({id_:String(e.id),text:e.content,metadata:{ts:e.ts}}),score:e.score}))}}};
|
|
@@ -1,86 +1 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Mumpix × LlamaIndex integration
|
|
5
|
-
*
|
|
6
|
-
* Usage:
|
|
7
|
-
* const { MumpixReader, MumpixIndex } = require('mumpix/src/integrations/llamaindex')
|
|
8
|
-
* const db = Mumpix.open('./agent.mumpix', { consistency: 'strict' })
|
|
9
|
-
* const index = new MumpixIndex(db)
|
|
10
|
-
* const retriever = index.asRetriever({ topK: 5 })
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* MumpixIndex — wraps a MumpixDB as a LlamaIndex-style index.
|
|
15
|
-
*/
|
|
16
|
-
class MumpixIndex {
|
|
17
|
-
constructor(db) {
|
|
18
|
-
this.db = db;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
asRetriever(opts = {}) {
|
|
22
|
-
return new MumpixIndexRetriever(this.db, opts);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Insert a document / text node.
|
|
27
|
-
*/
|
|
28
|
-
async insert(node) {
|
|
29
|
-
const text = typeof node === 'string' ? node : (node.text || node.content || '');
|
|
30
|
-
return this.db.remember(text);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async insertMany(nodes) {
|
|
34
|
-
const results = [];
|
|
35
|
-
for (const n of nodes) results.push(await this.insert(n));
|
|
36
|
-
return results;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* MumpixIndexRetriever — LlamaIndex-compatible retriever.
|
|
42
|
-
*/
|
|
43
|
-
class MumpixIndexRetriever {
|
|
44
|
-
constructor(db, opts = {}) {
|
|
45
|
-
this.db = db;
|
|
46
|
-
this.topK = opts.topK || 5;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
async retrieve(queryBundle) {
|
|
50
|
-
const query = typeof queryBundle === 'string' ? queryBundle : queryBundle.queryStr;
|
|
51
|
-
const results = await this.db.recallMany(query, this.topK);
|
|
52
|
-
return results.map(r => ({
|
|
53
|
-
node: {
|
|
54
|
-
id_: r.id.toString(),
|
|
55
|
-
text: r.content,
|
|
56
|
-
metadata: { ts: r.ts },
|
|
57
|
-
getContent: () => r.content,
|
|
58
|
-
},
|
|
59
|
-
score: r.score,
|
|
60
|
-
}));
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
* MumpixReader — load .mumpix file contents as LlamaIndex documents.
|
|
66
|
-
*/
|
|
67
|
-
class MumpixReader {
|
|
68
|
-
constructor(db) {
|
|
69
|
-
this.db = db;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
async loadData() {
|
|
73
|
-
const memories = await this.db.list();
|
|
74
|
-
return memories.map(m => ({
|
|
75
|
-
id_: m.id.toString(),
|
|
76
|
-
text: m.content,
|
|
77
|
-
metadata: { source: 'mumpix', ts: m.ts },
|
|
78
|
-
}));
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
module.exports = {
|
|
83
|
-
MumpixIndex,
|
|
84
|
-
MumpixIndexRetriever,
|
|
85
|
-
MumpixReader,
|
|
86
|
-
};
|
|
1
|
+
"use strict";class t{constructor(t,e={}){this.db=t,this.topK=e.topK||5}async retrieve(t){const e="string"==typeof t?t:t.queryStr;return(await this.db.recallMany(e,this.topK)).map(t=>({node:{id_:t.id.toString(),text:t.content,metadata:{ts:t.ts},getContent:()=>t.content},score:t.score}))}}module.exports={MumpixIndex:class{constructor(t){this.db=t}asRetriever(e={}){return new t(this.db,e)}async insert(t){const e="string"==typeof t?t:t.text||t.content||"";return this.db.remember(e)}async insertMany(t){const e=[];for(const s of t)e.push(await this.insert(s));return e}},MumpixIndexRetriever:t,MumpixReader:class{constructor(t){this.db=t}async loadData(){return(await this.db.list()).map(t=>({id_:t.id.toString(),text:t.content,metadata:{source:"mumpix",ts:t.ts}}))}}};
|