multimodemind 0.0.1 → 0.1.1
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/LICENSE +21 -0
- package/README.md +73 -4
- package/dist/cli/config.d.ts +14 -0
- package/dist/cli/config.d.ts.map +1 -0
- package/dist/cli/config.js +31 -0
- package/dist/cli/config.js.map +1 -0
- package/dist/cli/dashboard.d.ts +14 -0
- package/dist/cli/dashboard.d.ts.map +1 -0
- package/dist/cli/dashboard.js +277 -0
- package/dist/cli/dashboard.js.map +1 -0
- package/dist/embeddings/base.d.ts +19 -0
- package/dist/embeddings/base.d.ts.map +1 -0
- package/dist/embeddings/base.js +6 -0
- package/dist/embeddings/base.js.map +1 -0
- package/dist/embeddings/index.d.ts +11 -0
- package/dist/embeddings/index.d.ts.map +1 -0
- package/dist/embeddings/index.js +18 -0
- package/dist/embeddings/index.js.map +1 -0
- package/dist/embeddings/local.d.ts +19 -0
- package/dist/embeddings/local.d.ts.map +1 -0
- package/dist/embeddings/local.js +40 -0
- package/dist/embeddings/local.js.map +1 -0
- package/dist/embeddings/openai.d.ts +15 -0
- package/dist/embeddings/openai.d.ts.map +1 -0
- package/dist/embeddings/openai.js +33 -0
- package/dist/embeddings/openai.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +88 -0
- package/dist/index.js.map +1 -0
- package/dist/router/index.d.ts +25 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +82 -0
- package/dist/router/index.js.map +1 -0
- package/dist/stores/base.d.ts +40 -0
- package/dist/stores/base.d.ts.map +1 -0
- package/dist/stores/base.js +6 -0
- package/dist/stores/base.js.map +1 -0
- package/dist/stores/files.d.ts +23 -0
- package/dist/stores/files.d.ts.map +1 -0
- package/dist/stores/files.js +144 -0
- package/dist/stores/files.js.map +1 -0
- package/dist/stores/index.d.ts +7 -0
- package/dist/stores/index.d.ts.map +1 -0
- package/dist/stores/index.js +6 -0
- package/dist/stores/index.js.map +1 -0
- package/dist/stores/leveldb.d.ts +21 -0
- package/dist/stores/leveldb.d.ts.map +1 -0
- package/dist/stores/leveldb.js +99 -0
- package/dist/stores/leveldb.js.map +1 -0
- package/dist/stores/markdown.d.ts +25 -0
- package/dist/stores/markdown.d.ts.map +1 -0
- package/dist/stores/markdown.js +133 -0
- package/dist/stores/markdown.js.map +1 -0
- package/dist/stores/sqlite.d.ts +22 -0
- package/dist/stores/sqlite.d.ts.map +1 -0
- package/dist/stores/sqlite.js +125 -0
- package/dist/stores/sqlite.js.map +1 -0
- package/dist/stores/utils.d.ts +17 -0
- package/dist/stores/utils.d.ts.map +1 -0
- package/dist/stores/utils.js +40 -0
- package/dist/stores/utils.js.map +1 -0
- package/dist/stores/vector.d.ts +26 -0
- package/dist/stores/vector.d.ts.map +1 -0
- package/dist/stores/vector.js +106 -0
- package/dist/stores/vector.js.map +1 -0
- package/dist/tools/retrieve.d.ts +9 -0
- package/dist/tools/retrieve.d.ts.map +1 -0
- package/dist/tools/retrieve.js +41 -0
- package/dist/tools/retrieve.js.map +1 -0
- package/dist/tools/sources.d.ts +9 -0
- package/dist/tools/sources.d.ts.map +1 -0
- package/dist/tools/sources.js +34 -0
- package/dist/tools/sources.js.map +1 -0
- package/dist/tools/store.d.ts +10 -0
- package/dist/tools/store.d.ts.map +1 -0
- package/dist/tools/store.js +51 -0
- package/dist/tools/store.js.map +1 -0
- package/dist/types.d.ts +59 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +55 -13
- package/index.js +0 -1
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LevelDB store adapter — fast key-value memory for agent session state.
|
|
3
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
4
|
+
*/
|
|
5
|
+
import { Level } from 'level';
|
|
6
|
+
import { statSync } from 'fs';
|
|
7
|
+
import { newId, nowIso, cosineSimilarity, keywordScore } from './utils.js';
|
|
8
|
+
const DEFAULT_PATH = '.mmind/leveldb';
|
|
9
|
+
export class LevelDbStore {
|
|
10
|
+
type = 'leveldb';
|
|
11
|
+
name;
|
|
12
|
+
db = null;
|
|
13
|
+
dbPath;
|
|
14
|
+
constructor(dbPath = DEFAULT_PATH) {
|
|
15
|
+
this.dbPath = dbPath;
|
|
16
|
+
this.name = `leveldb:${dbPath}`;
|
|
17
|
+
}
|
|
18
|
+
async getDb() {
|
|
19
|
+
if (!this.db) {
|
|
20
|
+
this.db = new Level(this.dbPath, { valueEncoding: 'utf8' });
|
|
21
|
+
await this.db.open();
|
|
22
|
+
}
|
|
23
|
+
return this.db;
|
|
24
|
+
}
|
|
25
|
+
async isAvailable() {
|
|
26
|
+
try {
|
|
27
|
+
await this.getDb();
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async search(query, embedding, limit) {
|
|
35
|
+
const db = await this.getDb();
|
|
36
|
+
const results = [];
|
|
37
|
+
for await (const value of db.values()) {
|
|
38
|
+
const entry = JSON.parse(value);
|
|
39
|
+
const vecScore = embedding.length > 0 && entry.embedding
|
|
40
|
+
? cosineSimilarity(embedding, entry.embedding)
|
|
41
|
+
: 0;
|
|
42
|
+
const kwScore = keywordScore(entry.content, query);
|
|
43
|
+
const score = embedding.length > 0
|
|
44
|
+
? vecScore * 0.7 + kwScore * 0.3
|
|
45
|
+
: kwScore;
|
|
46
|
+
if (score > 0) {
|
|
47
|
+
results.push({ entry, score, source: this.name });
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
51
|
+
}
|
|
52
|
+
async store(entry) {
|
|
53
|
+
const db = await this.getDb();
|
|
54
|
+
const id = newId();
|
|
55
|
+
const now = nowIso();
|
|
56
|
+
const full = { ...entry, id, createdAt: now, updatedAt: now };
|
|
57
|
+
await db.put(id, JSON.stringify(full));
|
|
58
|
+
return id;
|
|
59
|
+
}
|
|
60
|
+
async get(id) {
|
|
61
|
+
const db = await this.getDb();
|
|
62
|
+
try {
|
|
63
|
+
const raw = await db.get(id);
|
|
64
|
+
return JSON.parse(raw);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async sources() {
|
|
71
|
+
try {
|
|
72
|
+
const db = await this.getDb();
|
|
73
|
+
let count = 0;
|
|
74
|
+
for await (const _ of db.keys())
|
|
75
|
+
count++;
|
|
76
|
+
let sizeBytes;
|
|
77
|
+
try {
|
|
78
|
+
sizeBytes = statSync(this.dbPath).size;
|
|
79
|
+
}
|
|
80
|
+
catch { /* dir, not file */ }
|
|
81
|
+
return {
|
|
82
|
+
type: this.type,
|
|
83
|
+
name: this.name,
|
|
84
|
+
available: true,
|
|
85
|
+
path: this.dbPath,
|
|
86
|
+
entryCount: count,
|
|
87
|
+
sizeBytes,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (err) {
|
|
91
|
+
return { type: this.type, name: this.name, available: false, error: String(err) };
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async close() {
|
|
95
|
+
await this.db?.close();
|
|
96
|
+
this.db = null;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=leveldb.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"leveldb.js","sourceRoot":"","sources":["../../src/stores/leveldb.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown vault store adapter.
|
|
3
|
+
* Reads existing .md files non-destructively; treats each file as one entry.
|
|
4
|
+
* Vault-agnostic — Obsidian is the reference case but any folder works.
|
|
5
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
6
|
+
*/
|
|
7
|
+
import type { MemoryEntry, RankedEntry, SourceInfo } from '../types.js';
|
|
8
|
+
import type { MemoryStore } from './base.js';
|
|
9
|
+
export declare class MarkdownStore implements MemoryStore {
|
|
10
|
+
readonly type: 'markdown';
|
|
11
|
+
readonly name: string;
|
|
12
|
+
private readonly vaultPath;
|
|
13
|
+
constructor(vaultPath: string);
|
|
14
|
+
isAvailable(): Promise<boolean>;
|
|
15
|
+
search(query: string, embedding: number[], limit: number): Promise<RankedEntry[]>;
|
|
16
|
+
/**
|
|
17
|
+
* store() appends a new .md file to the vault.
|
|
18
|
+
* Never modifies existing files.
|
|
19
|
+
*/
|
|
20
|
+
store(entry: Omit<MemoryEntry, 'id' | 'createdAt' | 'updatedAt'>): Promise<string>;
|
|
21
|
+
get(id: string): Promise<MemoryEntry | null>;
|
|
22
|
+
sources(): Promise<SourceInfo>;
|
|
23
|
+
close(): Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=markdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.d.ts","sourceRoot":"","sources":["../../src/stores/markdown.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAG7C,qBAAa,aAAc,YAAW,WAAW;IAC/C,QAAQ,CAAC,IAAI,EAAG,UAAU,CAAU;IACpC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,SAAS,EAAE,MAAM,EAG5B;IAEK,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAOpC;IAEK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAyCtF;IAED;;;OAGG;IACG,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAoBvF;IAEK,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAmBjD;IAEK,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,CAgBnC;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;CACF"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Markdown vault store adapter.
|
|
3
|
+
* Reads existing .md files non-destructively; treats each file as one entry.
|
|
4
|
+
* Vault-agnostic — Obsidian is the reference case but any folder works.
|
|
5
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
6
|
+
*/
|
|
7
|
+
import { readFileSync, statSync } from 'fs';
|
|
8
|
+
import { join, relative } from 'path';
|
|
9
|
+
import matter from 'gray-matter';
|
|
10
|
+
import fg from 'fast-glob';
|
|
11
|
+
import { keywordScore } from './utils.js';
|
|
12
|
+
export class MarkdownStore {
|
|
13
|
+
type = 'markdown';
|
|
14
|
+
name;
|
|
15
|
+
vaultPath;
|
|
16
|
+
constructor(vaultPath) {
|
|
17
|
+
this.vaultPath = vaultPath;
|
|
18
|
+
this.name = `markdown:${vaultPath}`;
|
|
19
|
+
}
|
|
20
|
+
async isAvailable() {
|
|
21
|
+
try {
|
|
22
|
+
statSync(this.vaultPath);
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async search(query, embedding, limit) {
|
|
30
|
+
const files = await fg('**/*.md', {
|
|
31
|
+
cwd: this.vaultPath,
|
|
32
|
+
ignore: ['.obsidian/**', '.trash/**', 'node_modules/**'],
|
|
33
|
+
absolute: true,
|
|
34
|
+
});
|
|
35
|
+
const results = [];
|
|
36
|
+
for (const filePath of files) {
|
|
37
|
+
try {
|
|
38
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
39
|
+
const { data: frontmatter, content } = matter(raw);
|
|
40
|
+
const fullText = [
|
|
41
|
+
frontmatter['title'] ?? '',
|
|
42
|
+
frontmatter['tags'] ? String(frontmatter['tags']) : '',
|
|
43
|
+
content,
|
|
44
|
+
].join(' ');
|
|
45
|
+
const kwScore = keywordScore(fullText, query);
|
|
46
|
+
// Markdown files don't carry stored embeddings — keyword only for now
|
|
47
|
+
const score = kwScore;
|
|
48
|
+
if (score > 0) {
|
|
49
|
+
const relPath = relative(this.vaultPath, filePath);
|
|
50
|
+
const entry = {
|
|
51
|
+
id: `md:${relPath}`,
|
|
52
|
+
content: content.slice(0, 4000), // cap for context window
|
|
53
|
+
metadata: { ...frontmatter, filePath, relPath },
|
|
54
|
+
storeType: this.type,
|
|
55
|
+
createdAt: statSync(filePath).birthtime.toISOString(),
|
|
56
|
+
updatedAt: statSync(filePath).mtime.toISOString(),
|
|
57
|
+
};
|
|
58
|
+
results.push({ entry, score, source: `${this.name}/${relPath}` });
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Skip unreadable files silently
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return results.sort((a, b) => b.score - a.score).slice(0, limit);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* store() appends a new .md file to the vault.
|
|
69
|
+
* Never modifies existing files.
|
|
70
|
+
*/
|
|
71
|
+
async store(entry) {
|
|
72
|
+
const { writeFileSync, mkdirSync } = await import('fs');
|
|
73
|
+
const now = new Date();
|
|
74
|
+
const slug = now.toISOString().replace(/[:.]/g, '-');
|
|
75
|
+
const filename = `mmind-${slug}.md`;
|
|
76
|
+
const filePath = join(this.vaultPath, filename);
|
|
77
|
+
const frontmatter = {
|
|
78
|
+
created: now.toISOString(),
|
|
79
|
+
source: 'multimodemind',
|
|
80
|
+
...entry.metadata,
|
|
81
|
+
};
|
|
82
|
+
const yamlLines = Object.entries(frontmatter)
|
|
83
|
+
.map(([k, v]) => `${k}: ${JSON.stringify(v)}`)
|
|
84
|
+
.join('\n');
|
|
85
|
+
const fileContent = `---\n${yamlLines}\n---\n\n${entry.content}\n`;
|
|
86
|
+
mkdirSync(this.vaultPath, { recursive: true });
|
|
87
|
+
writeFileSync(filePath, fileContent, 'utf-8');
|
|
88
|
+
return `md:${filename}`;
|
|
89
|
+
}
|
|
90
|
+
async get(id) {
|
|
91
|
+
// id format: "md:<relPath>"
|
|
92
|
+
const relPath = id.startsWith('md:') ? id.slice(3) : id;
|
|
93
|
+
const filePath = join(this.vaultPath, relPath);
|
|
94
|
+
try {
|
|
95
|
+
const raw = readFileSync(filePath, 'utf-8');
|
|
96
|
+
const { data: frontmatter, content } = matter(raw);
|
|
97
|
+
const stat = statSync(filePath);
|
|
98
|
+
return {
|
|
99
|
+
id,
|
|
100
|
+
content,
|
|
101
|
+
metadata: { ...frontmatter, filePath, relPath },
|
|
102
|
+
storeType: this.type,
|
|
103
|
+
createdAt: stat.birthtime.toISOString(),
|
|
104
|
+
updatedAt: stat.mtime.toISOString(),
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async sources() {
|
|
112
|
+
try {
|
|
113
|
+
const files = await fg('**/*.md', {
|
|
114
|
+
cwd: this.vaultPath,
|
|
115
|
+
ignore: ['.obsidian/**', '.trash/**'],
|
|
116
|
+
});
|
|
117
|
+
return {
|
|
118
|
+
type: this.type,
|
|
119
|
+
name: this.name,
|
|
120
|
+
available: true,
|
|
121
|
+
path: this.vaultPath,
|
|
122
|
+
entryCount: files.length,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
return { type: this.type, name: this.name, available: false, error: String(err) };
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
async close() {
|
|
130
|
+
// No open handles — nothing to close
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=markdown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/stores/markdown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite store adapter — structured, queryable memory.
|
|
3
|
+
* Uses better-sqlite3 (synchronous) for simplicity and reliability.
|
|
4
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
5
|
+
*/
|
|
6
|
+
import type { MemoryEntry, RankedEntry, SourceInfo } from '../types.js';
|
|
7
|
+
import type { MemoryStore } from './base.js';
|
|
8
|
+
export declare class SqliteStore implements MemoryStore {
|
|
9
|
+
readonly type: 'sqlite';
|
|
10
|
+
readonly name: string;
|
|
11
|
+
private db;
|
|
12
|
+
private readonly dbPath;
|
|
13
|
+
constructor(dbPath?: string);
|
|
14
|
+
private getDb;
|
|
15
|
+
isAvailable(): Promise<boolean>;
|
|
16
|
+
search(query: string, embedding: number[], limit: number): Promise<RankedEntry[]>;
|
|
17
|
+
store(entry: Omit<MemoryEntry, 'id' | 'createdAt' | 'updatedAt'>): Promise<string>;
|
|
18
|
+
get(id: string): Promise<MemoryEntry | null>;
|
|
19
|
+
sources(): Promise<SourceInfo>;
|
|
20
|
+
close(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=sqlite.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.d.ts","sourceRoot":"","sources":["../../src/stores/sqlite.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAkB7C,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,EAAE,CAAmB;IAC7B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAEhC,YAAY,MAAM,SAAe,EAGhC;IAED,OAAO,CAAC,KAAK;IAUP,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAOpC;IAEK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAqBtF;IAEK,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAiBvF;IAEK,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CAIjD;IAEK,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,CAiBnC;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAG3B;CACF"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite store adapter — structured, queryable memory.
|
|
3
|
+
* Uses better-sqlite3 (synchronous) for simplicity and reliability.
|
|
4
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
5
|
+
*/
|
|
6
|
+
import Database from 'better-sqlite3';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { statSync, mkdirSync } from 'fs';
|
|
9
|
+
import { dirname } from 'path';
|
|
10
|
+
import { newId, nowIso, cosineSimilarity, keywordScore } from './utils.js';
|
|
11
|
+
const DEFAULT_PATH = join(process.cwd(), '.mmind', 'memory.db');
|
|
12
|
+
const SCHEMA = `
|
|
13
|
+
CREATE TABLE IF NOT EXISTS entries (
|
|
14
|
+
id TEXT PRIMARY KEY,
|
|
15
|
+
content TEXT NOT NULL,
|
|
16
|
+
metadata TEXT NOT NULL DEFAULT '{}',
|
|
17
|
+
store_type TEXT NOT NULL DEFAULT 'sqlite',
|
|
18
|
+
created_at TEXT NOT NULL,
|
|
19
|
+
updated_at TEXT NOT NULL,
|
|
20
|
+
embedding TEXT -- JSON float array, nullable
|
|
21
|
+
);
|
|
22
|
+
CREATE INDEX IF NOT EXISTS idx_entries_created ON entries(created_at);
|
|
23
|
+
`;
|
|
24
|
+
export class SqliteStore {
|
|
25
|
+
type = 'sqlite';
|
|
26
|
+
name;
|
|
27
|
+
db = null;
|
|
28
|
+
dbPath;
|
|
29
|
+
constructor(dbPath = DEFAULT_PATH) {
|
|
30
|
+
this.dbPath = dbPath;
|
|
31
|
+
this.name = `sqlite:${dbPath}`;
|
|
32
|
+
}
|
|
33
|
+
getDb() {
|
|
34
|
+
if (!this.db) {
|
|
35
|
+
mkdirSync(dirname(this.dbPath), { recursive: true });
|
|
36
|
+
this.db = new Database(this.dbPath);
|
|
37
|
+
this.db.exec(SCHEMA);
|
|
38
|
+
this.db.pragma('journal_mode = WAL');
|
|
39
|
+
}
|
|
40
|
+
return this.db;
|
|
41
|
+
}
|
|
42
|
+
async isAvailable() {
|
|
43
|
+
try {
|
|
44
|
+
this.getDb();
|
|
45
|
+
return true;
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async search(query, embedding, limit) {
|
|
52
|
+
const db = this.getDb();
|
|
53
|
+
const rows = db
|
|
54
|
+
.prepare('SELECT * FROM entries ORDER BY created_at DESC LIMIT ?')
|
|
55
|
+
.all(Math.min(limit * 10, 500));
|
|
56
|
+
return rows
|
|
57
|
+
.map((row) => {
|
|
58
|
+
const entry = rowToEntry(row);
|
|
59
|
+
const vecScore = embedding.length > 0 && entry.embedding
|
|
60
|
+
? cosineSimilarity(embedding, entry.embedding)
|
|
61
|
+
: 0;
|
|
62
|
+
const kwScore = keywordScore(entry.content, query);
|
|
63
|
+
const score = embedding.length > 0
|
|
64
|
+
? vecScore * 0.7 + kwScore * 0.3
|
|
65
|
+
: kwScore;
|
|
66
|
+
return { entry, score, source: this.name };
|
|
67
|
+
})
|
|
68
|
+
.filter((r) => r.score > 0)
|
|
69
|
+
.sort((a, b) => b.score - a.score)
|
|
70
|
+
.slice(0, limit);
|
|
71
|
+
}
|
|
72
|
+
async store(entry) {
|
|
73
|
+
const id = newId();
|
|
74
|
+
const now = nowIso();
|
|
75
|
+
const db = this.getDb();
|
|
76
|
+
db.prepare(`
|
|
77
|
+
INSERT INTO entries (id, content, metadata, store_type, created_at, updated_at, embedding)
|
|
78
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
79
|
+
`).run(id, entry.content, JSON.stringify(entry.metadata), entry.storeType, now, now, entry.embedding ? JSON.stringify(entry.embedding) : null);
|
|
80
|
+
return id;
|
|
81
|
+
}
|
|
82
|
+
async get(id) {
|
|
83
|
+
const db = this.getDb();
|
|
84
|
+
const row = db.prepare('SELECT * FROM entries WHERE id = ?').get(id);
|
|
85
|
+
return row ? rowToEntry(row) : null;
|
|
86
|
+
}
|
|
87
|
+
async sources() {
|
|
88
|
+
try {
|
|
89
|
+
const db = this.getDb();
|
|
90
|
+
const count = db.prepare('SELECT COUNT(*) as n FROM entries').get().n;
|
|
91
|
+
let sizeBytes;
|
|
92
|
+
try {
|
|
93
|
+
sizeBytes = statSync(this.dbPath).size;
|
|
94
|
+
}
|
|
95
|
+
catch { /* ok */ }
|
|
96
|
+
return {
|
|
97
|
+
type: this.type,
|
|
98
|
+
name: this.name,
|
|
99
|
+
available: true,
|
|
100
|
+
path: this.dbPath,
|
|
101
|
+
entryCount: count,
|
|
102
|
+
sizeBytes,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
return { type: this.type, name: this.name, available: false, error: String(err) };
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async close() {
|
|
110
|
+
this.db?.close();
|
|
111
|
+
this.db = null;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
function rowToEntry(row) {
|
|
115
|
+
return {
|
|
116
|
+
id: row.id,
|
|
117
|
+
content: row.content,
|
|
118
|
+
metadata: JSON.parse(row.metadata),
|
|
119
|
+
storeType: row.store_type,
|
|
120
|
+
createdAt: row.created_at,
|
|
121
|
+
updatedAt: row.updated_at,
|
|
122
|
+
embedding: row.embedding ? JSON.parse(row.embedding) : undefined,
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=sqlite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sqlite.js","sourceRoot":"","sources":["../../src/stores/sqlite.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared store utilities.
|
|
3
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
4
|
+
*/
|
|
5
|
+
export declare function newId(): string;
|
|
6
|
+
export declare function nowIso(): string;
|
|
7
|
+
/**
|
|
8
|
+
* Cosine similarity between two equal-length vectors.
|
|
9
|
+
* Returns 0 when either vector is empty (no embedding available).
|
|
10
|
+
*/
|
|
11
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
12
|
+
/**
|
|
13
|
+
* Simple BM25-flavoured keyword score: fraction of query tokens present
|
|
14
|
+
* in the content, case-insensitive. Used by stores without vector support.
|
|
15
|
+
*/
|
|
16
|
+
export declare function keywordScore(content: string, query: string): number;
|
|
17
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/stores/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,wBAAgB,KAAK,IAAI,MAAM,CAE9B;AAED,wBAAgB,MAAM,IAAI,MAAM,CAE/B;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAUjE;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMnE"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared store utilities.
|
|
3
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
4
|
+
*/
|
|
5
|
+
import { randomUUID } from 'crypto';
|
|
6
|
+
export function newId() {
|
|
7
|
+
return randomUUID();
|
|
8
|
+
}
|
|
9
|
+
export function nowIso() {
|
|
10
|
+
return new Date().toISOString();
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Cosine similarity between two equal-length vectors.
|
|
14
|
+
* Returns 0 when either vector is empty (no embedding available).
|
|
15
|
+
*/
|
|
16
|
+
export function cosineSimilarity(a, b) {
|
|
17
|
+
if (a.length === 0 || b.length === 0 || a.length !== b.length)
|
|
18
|
+
return 0;
|
|
19
|
+
let dot = 0, magA = 0, magB = 0;
|
|
20
|
+
for (let i = 0; i < a.length; i++) {
|
|
21
|
+
dot += a[i] * b[i];
|
|
22
|
+
magA += a[i] * a[i];
|
|
23
|
+
magB += b[i] * b[i];
|
|
24
|
+
}
|
|
25
|
+
const denom = Math.sqrt(magA) * Math.sqrt(magB);
|
|
26
|
+
return denom === 0 ? 0 : dot / denom;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Simple BM25-flavoured keyword score: fraction of query tokens present
|
|
30
|
+
* in the content, case-insensitive. Used by stores without vector support.
|
|
31
|
+
*/
|
|
32
|
+
export function keywordScore(content, query) {
|
|
33
|
+
const tokens = query.toLowerCase().split(/\s+/).filter(Boolean);
|
|
34
|
+
if (tokens.length === 0)
|
|
35
|
+
return 0;
|
|
36
|
+
const lower = content.toLowerCase();
|
|
37
|
+
const hits = tokens.filter((t) => lower.includes(t)).length;
|
|
38
|
+
return hits / tokens.length;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/stores/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,MAAM,UAAU,KAAK;IACnB,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,MAAM;IACpB,OAAO,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAClC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,CAAW,EAAE,CAAW;IACvD,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,MAAM;QAAE,OAAO,CAAC,CAAC;IACxE,IAAI,GAAG,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,CAAC;IAChC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAClC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACrB,IAAI,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;QACtB,IAAI,IAAI,CAAC,CAAC,CAAC,CAAE,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC;IACxB,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChD,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,KAAK,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,OAAe,EAAE,KAAa;IACzD,MAAM,MAAM,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAChE,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,CAAC,CAAC;IAClC,MAAM,KAAK,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5D,OAAO,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC;AAC9B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector store adapter — local HNSW index via Vectra (pure TypeScript, MIT).
|
|
3
|
+
* Primary semantic search backend; other stores fall back to keyword scoring.
|
|
4
|
+
*
|
|
5
|
+
* Vectra metadata only allows string | number | boolean, so the full MemoryEntry
|
|
6
|
+
* is serialized as a JSON string in a single `data` field.
|
|
7
|
+
*
|
|
8
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
9
|
+
*/
|
|
10
|
+
import type { MemoryEntry, RankedEntry, SourceInfo } from '../types.js';
|
|
11
|
+
import type { MemoryStore } from './base.js';
|
|
12
|
+
export declare class VectorStore implements MemoryStore {
|
|
13
|
+
readonly type: 'vector';
|
|
14
|
+
readonly name: string;
|
|
15
|
+
private index;
|
|
16
|
+
private readonly indexPath;
|
|
17
|
+
constructor(indexPath?: string);
|
|
18
|
+
private getIndex;
|
|
19
|
+
isAvailable(): Promise<boolean>;
|
|
20
|
+
search(query: string, embedding: number[], limit: number): Promise<RankedEntry[]>;
|
|
21
|
+
store(entry: Omit<MemoryEntry, 'id' | 'createdAt' | 'updatedAt'>): Promise<string>;
|
|
22
|
+
get(id: string): Promise<MemoryEntry | null>;
|
|
23
|
+
sources(): Promise<SourceInfo>;
|
|
24
|
+
close(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=vector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector.d.ts","sourceRoot":"","sources":["../../src/stores/vector.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACxE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAS7C,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,EAAG,QAAQ,CAAU;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,OAAO,CAAC,KAAK,CAA0C;IACvD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IAEnC,YAAY,SAAS,SAAe,EAGnC;YAEa,QAAQ;IAShB,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC,CAOpC;IAEK,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAkBtF;IAEK,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,GAAG,WAAW,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,MAAM,CAAC,CAcvF;IAEK,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC,CASjD;IAEK,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,CAcnC;IAEK,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAE3B;CACF"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector store adapter — local HNSW index via Vectra (pure TypeScript, MIT).
|
|
3
|
+
* Primary semantic search backend; other stores fall back to keyword scoring.
|
|
4
|
+
*
|
|
5
|
+
* Vectra metadata only allows string | number | boolean, so the full MemoryEntry
|
|
6
|
+
* is serialized as a JSON string in a single `data` field.
|
|
7
|
+
*
|
|
8
|
+
* Copyright Old Cart Technology LLC — MIT License
|
|
9
|
+
*/
|
|
10
|
+
import { LocalIndex } from 'vectra';
|
|
11
|
+
import { newId, nowIso } from './utils.js';
|
|
12
|
+
const DEFAULT_PATH = '.mmind/vector-index';
|
|
13
|
+
export class VectorStore {
|
|
14
|
+
type = 'vector';
|
|
15
|
+
name;
|
|
16
|
+
index = null;
|
|
17
|
+
indexPath;
|
|
18
|
+
constructor(indexPath = DEFAULT_PATH) {
|
|
19
|
+
this.indexPath = indexPath;
|
|
20
|
+
this.name = `vector:${indexPath}`;
|
|
21
|
+
}
|
|
22
|
+
async getIndex() {
|
|
23
|
+
if (this.index)
|
|
24
|
+
return this.index;
|
|
25
|
+
this.index = new LocalIndex(this.indexPath);
|
|
26
|
+
if (!(await this.index.isIndexCreated())) {
|
|
27
|
+
await this.index.createIndex();
|
|
28
|
+
}
|
|
29
|
+
return this.index;
|
|
30
|
+
}
|
|
31
|
+
async isAvailable() {
|
|
32
|
+
try {
|
|
33
|
+
await this.getIndex();
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async search(query, embedding, limit) {
|
|
41
|
+
if (embedding.length === 0)
|
|
42
|
+
return []; // vector store requires an embedding
|
|
43
|
+
const idx = await this.getIndex();
|
|
44
|
+
// Vectra signature: queryItems(vector, queryText, topK)
|
|
45
|
+
// We pass the natural-language query for potential BM25 hybrid; topK = limit
|
|
46
|
+
const results = await idx.queryItems(embedding, query, limit);
|
|
47
|
+
return results
|
|
48
|
+
.map((r) => {
|
|
49
|
+
try {
|
|
50
|
+
const entry = JSON.parse(r.item.metadata['data']);
|
|
51
|
+
return { entry, score: r.score, source: this.name };
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
})
|
|
57
|
+
.filter((r) => r !== null);
|
|
58
|
+
}
|
|
59
|
+
async store(entry) {
|
|
60
|
+
if (!entry.embedding || entry.embedding.length === 0) {
|
|
61
|
+
throw new Error('VectorStore requires an embedding to store an entry');
|
|
62
|
+
}
|
|
63
|
+
const id = newId();
|
|
64
|
+
const now = nowIso();
|
|
65
|
+
const full = { ...entry, id, createdAt: now, updatedAt: now };
|
|
66
|
+
const idx = await this.getIndex();
|
|
67
|
+
await idx.insertItem({
|
|
68
|
+
id,
|
|
69
|
+
vector: entry.embedding,
|
|
70
|
+
metadata: { data: JSON.stringify(full) },
|
|
71
|
+
});
|
|
72
|
+
return id;
|
|
73
|
+
}
|
|
74
|
+
async get(id) {
|
|
75
|
+
const idx = await this.getIndex();
|
|
76
|
+
const item = await idx.getItem(id);
|
|
77
|
+
if (!item)
|
|
78
|
+
return null;
|
|
79
|
+
try {
|
|
80
|
+
return JSON.parse(item.metadata['data']);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async sources() {
|
|
87
|
+
try {
|
|
88
|
+
const idx = await this.getIndex();
|
|
89
|
+
const stats = await idx.listItems();
|
|
90
|
+
return {
|
|
91
|
+
type: this.type,
|
|
92
|
+
name: this.name,
|
|
93
|
+
available: true,
|
|
94
|
+
path: this.indexPath,
|
|
95
|
+
entryCount: stats.length,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return { type: this.type, name: this.name, available: false, error: String(err) };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async close() {
|
|
103
|
+
this.index = null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=vector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vector.js","sourceRoot":"","sources":["../../src/stores/vector.ts"],"names":[],"mappings":"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"}
|