@quarry-systems/drift-retrieval-sqlite 0.1.0
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 +168 -0
- package/package.json +41 -0
- package/src/index.d.ts +52 -0
- package/src/index.js +301 -0
- package/src/index.js.map +1 -0
- package/src/plugin.manifest.d.ts +9 -0
- package/src/plugin.manifest.js +47 -0
- package/src/plugin.manifest.js.map +1 -0
package/README.md
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
# @quarry-systems/mcg-retrieval-sqlite
|
|
2
|
+
|
|
3
|
+
 
|
|
4
|
+
|
|
5
|
+
SQLite FTS5 retrieval adapter for MCG RAG pipelines.
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- **Full-text search**: SQLite FTS5 for keyword-based retrieval
|
|
10
|
+
- **Local-first**: Perfect for development and small-scale RAG
|
|
11
|
+
- **Zero-ops**: No external search service required
|
|
12
|
+
- **Unified model**: Source-agnostic documents and chunks
|
|
13
|
+
- **Fast indexing**: Automatic FTS triggers for real-time updates
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @quarry-systems/mcg-retrieval-sqlite
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import { createSQLiteRetrieval } from '@quarry-systems/mcg-retrieval-sqlite';
|
|
25
|
+
|
|
26
|
+
// In-memory (for testing)
|
|
27
|
+
const retrieval = createSQLiteRetrieval({ filename: ':memory:' });
|
|
28
|
+
|
|
29
|
+
// File-based (for persistence)
|
|
30
|
+
const retrieval = createSQLiteRetrieval({ filename: './data/rag.db' });
|
|
31
|
+
|
|
32
|
+
// Ingest a document
|
|
33
|
+
const doc = await retrieval.upsertDocument({
|
|
34
|
+
id: 'doc-1',
|
|
35
|
+
sourceType: 'url',
|
|
36
|
+
sourceRef: 'https://example.com/page',
|
|
37
|
+
title: 'Example Page',
|
|
38
|
+
metadata: { author: 'John Doe' }
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
// Index chunks
|
|
42
|
+
await retrieval.upsertChunks(doc.id, [
|
|
43
|
+
{ sequence: 0, text: 'First paragraph about AI...' },
|
|
44
|
+
{ sequence: 1, text: 'Second paragraph about ML...' }
|
|
45
|
+
]);
|
|
46
|
+
|
|
47
|
+
// Search
|
|
48
|
+
const results = await retrieval.search('artificial intelligence', {
|
|
49
|
+
topK: 5,
|
|
50
|
+
sourceTypes: ['url']
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
console.log(results[0]);
|
|
54
|
+
// {
|
|
55
|
+
// chunk: { id: '...', text: '...', ... },
|
|
56
|
+
// doc: { id: 'doc-1', title: 'Example Page', ... },
|
|
57
|
+
// score: 2.5,
|
|
58
|
+
// highlights: ['<mark>artificial intelligence</mark> is...']
|
|
59
|
+
// }
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Integration with MCG
|
|
63
|
+
|
|
64
|
+
```typescript
|
|
65
|
+
import { ManagedCyclicGraph } from '@quarry-systems/managed-cyclic-graph';
|
|
66
|
+
import { createSQLiteRetrieval } from '@quarry-systems/mcg-retrieval-sqlite';
|
|
67
|
+
|
|
68
|
+
// Create retrieval adapter
|
|
69
|
+
const retrieval = createSQLiteRetrieval({ filename: './data/rag.db' });
|
|
70
|
+
|
|
71
|
+
// Build RAG ingest graph
|
|
72
|
+
const ingestGraph = new ManagedCyclicGraph()
|
|
73
|
+
.use({ services: { retrieval } })
|
|
74
|
+
.node('fetchUrl', {
|
|
75
|
+
type: 'action',
|
|
76
|
+
action: async (ctx) => {
|
|
77
|
+
const response = await fetch(ctx.data.url);
|
|
78
|
+
const text = await response.text();
|
|
79
|
+
return { url: ctx.data.url, content: text };
|
|
80
|
+
}
|
|
81
|
+
})
|
|
82
|
+
.node('indexDocument', {
|
|
83
|
+
type: 'action',
|
|
84
|
+
action: async (ctx, services) => {
|
|
85
|
+
// Index document
|
|
86
|
+
const doc = await services.retrieval.upsertDocument({
|
|
87
|
+
id: `doc-${Date.now()}`,
|
|
88
|
+
sourceType: 'url',
|
|
89
|
+
sourceRef: ctx.data.url,
|
|
90
|
+
title: ctx.data.url,
|
|
91
|
+
metadata: { indexedAt: Date.now() }
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
// Split into chunks (simple example)
|
|
95
|
+
const chunks = ctx.data.content
|
|
96
|
+
.split('\n\n')
|
|
97
|
+
.map((text, i) => ({ sequence: i, text }));
|
|
98
|
+
|
|
99
|
+
await services.retrieval.upsertChunks(doc.id, chunks);
|
|
100
|
+
|
|
101
|
+
return { docId: doc.id, chunks: chunks.length };
|
|
102
|
+
}
|
|
103
|
+
})
|
|
104
|
+
.edge('fetchUrl', 'indexDocument')
|
|
105
|
+
.build();
|
|
106
|
+
|
|
107
|
+
// Build RAG query graph
|
|
108
|
+
const queryGraph = new ManagedCyclicGraph()
|
|
109
|
+
.use({ services: { retrieval } })
|
|
110
|
+
.node('search', {
|
|
111
|
+
type: 'action',
|
|
112
|
+
action: async (ctx, services) => {
|
|
113
|
+
const results = await services.retrieval.search(ctx.data.query, {
|
|
114
|
+
topK: 5
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
return {
|
|
118
|
+
query: ctx.data.query,
|
|
119
|
+
results: results.map(r => ({
|
|
120
|
+
text: r.chunk.text,
|
|
121
|
+
score: r.score,
|
|
122
|
+
source: r.doc.sourceRef
|
|
123
|
+
}))
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
})
|
|
127
|
+
.build();
|
|
128
|
+
|
|
129
|
+
// Execute
|
|
130
|
+
await ingestGraph.run({ url: 'https://example.com/article' });
|
|
131
|
+
await queryGraph.run({ query: 'What is the main topic?' });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
## API
|
|
135
|
+
|
|
136
|
+
Implements `RetrievalAdapter` from `@quarry-systems/mcg-contracts`:
|
|
137
|
+
|
|
138
|
+
- `upsertDocument(doc)` - Create or update document
|
|
139
|
+
- `upsertChunks(docId, chunks)` - Index chunks (replaces existing)
|
|
140
|
+
- `deleteDocument(docId)` - Delete document and chunks
|
|
141
|
+
- `search(query, options)` - Full-text search with BM25 scoring
|
|
142
|
+
- `getDocument(docId)` - Get document by ID
|
|
143
|
+
- `getChunks(docId)` - Get all chunks for document
|
|
144
|
+
- `listDocuments(options)` - List documents with filtering
|
|
145
|
+
|
|
146
|
+
## Configuration
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
interface SQLiteRetrievalConfig {
|
|
150
|
+
/** Path to SQLite database file (use ':memory:' for in-memory) */
|
|
151
|
+
filename: string;
|
|
152
|
+
|
|
153
|
+
/** Enable WAL mode for better concurrency (default: true) */
|
|
154
|
+
walMode?: boolean;
|
|
155
|
+
}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Testing
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
npm test
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
All tests run in-memory with no external dependencies.
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@quarry-systems/drift-retrieval-sqlite",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "SQLite FTS5 retrieval adapter for Drift RAG pipelines",
|
|
5
|
+
"main": "./src/index.js",
|
|
6
|
+
"types": "./src/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsc -p .",
|
|
9
|
+
"test": "vitest run",
|
|
10
|
+
"test:watch": "vitest"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"drift",
|
|
14
|
+
"retrieval",
|
|
15
|
+
"rag",
|
|
16
|
+
"sqlite",
|
|
17
|
+
"fts5",
|
|
18
|
+
"search",
|
|
19
|
+
"backend",
|
|
20
|
+
"node"
|
|
21
|
+
],
|
|
22
|
+
"author": "Quarry Systems",
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"engines": {
|
|
25
|
+
"node": ">=18.0.0"
|
|
26
|
+
},
|
|
27
|
+
"browser": false,
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"better-sqlite3": "^11.0.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/better-sqlite3": "^7.6.0",
|
|
33
|
+
"typescript": "^5.3.0",
|
|
34
|
+
"vitest": "^2.1.0"
|
|
35
|
+
},
|
|
36
|
+
"files": [
|
|
37
|
+
"dist",
|
|
38
|
+
"src"
|
|
39
|
+
],
|
|
40
|
+
"type": "commonjs"
|
|
41
|
+
}
|
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCG SQLite FTS5 Retrieval Adapter
|
|
3
|
+
*
|
|
4
|
+
* SQLite-based retrieval using FTS5 for full-text search.
|
|
5
|
+
* Ideal for local development, testing, and small-scale RAG applications.
|
|
6
|
+
*
|
|
7
|
+
* @packageDocumentation
|
|
8
|
+
*/
|
|
9
|
+
import type { RetrievalAdapter } from '@quarry-systems/drift-contracts';
|
|
10
|
+
/**
|
|
11
|
+
* SQLite retrieval store configuration.
|
|
12
|
+
*/
|
|
13
|
+
export interface SQLiteRetrievalConfig {
|
|
14
|
+
/** Path to SQLite database file (use ':memory:' for in-memory) */
|
|
15
|
+
filename: string;
|
|
16
|
+
/** Enable WAL mode for better concurrency (default: true) */
|
|
17
|
+
walMode?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Create a SQLite FTS5 retrieval adapter.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* // In-memory for testing
|
|
25
|
+
* const retrieval = createSQLiteRetrieval({ filename: ':memory:' });
|
|
26
|
+
*
|
|
27
|
+
* // File-based for persistence
|
|
28
|
+
* const retrieval = createSQLiteRetrieval({ filename: './data/rag.db' });
|
|
29
|
+
*
|
|
30
|
+
* // Ingest a document
|
|
31
|
+
* const doc = await retrieval.upsertDocument({
|
|
32
|
+
* id: 'doc-1',
|
|
33
|
+
* sourceType: 'url',
|
|
34
|
+
* sourceRef: 'https://example.com/page',
|
|
35
|
+
* title: 'Example',
|
|
36
|
+
* metadata: {}
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Index chunks
|
|
40
|
+
* await retrieval.upsertChunks(doc.id, [
|
|
41
|
+
* { sequence: 0, text: 'First paragraph about AI...' },
|
|
42
|
+
* { sequence: 1, text: 'Second paragraph about ML...' }
|
|
43
|
+
* ]);
|
|
44
|
+
*
|
|
45
|
+
* // Search
|
|
46
|
+
* const results = await retrieval.search('artificial intelligence', { topK: 5 });
|
|
47
|
+
* ```
|
|
48
|
+
*/
|
|
49
|
+
export declare function createSQLiteRetrieval(config: SQLiteRetrievalConfig): RetrievalAdapter & {
|
|
50
|
+
close(): void;
|
|
51
|
+
};
|
|
52
|
+
export type { RetrievalAdapter, Document, DocumentInput, Chunk, ChunkInput, ChunkMatch, SearchOptions, SourceType, } from '@quarry-systems/drift-contracts';
|
package/src/index.js
ADDED
|
@@ -0,0 +1,301 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCG SQLite FTS5 Retrieval Adapter
|
|
4
|
+
*
|
|
5
|
+
* SQLite-based retrieval using FTS5 for full-text search.
|
|
6
|
+
* Ideal for local development, testing, and small-scale RAG applications.
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createSQLiteRetrieval = createSQLiteRetrieval;
|
|
12
|
+
const tslib_1 = require("tslib");
|
|
13
|
+
const better_sqlite3_1 = tslib_1.__importDefault(require("better-sqlite3"));
|
|
14
|
+
// ============================================================================
|
|
15
|
+
// Schema Creation
|
|
16
|
+
// ============================================================================
|
|
17
|
+
const CREATE_TABLES_SQL = `
|
|
18
|
+
-- Documents table
|
|
19
|
+
CREATE TABLE IF NOT EXISTS rag_documents (
|
|
20
|
+
id TEXT PRIMARY KEY,
|
|
21
|
+
source_type TEXT NOT NULL,
|
|
22
|
+
source_ref TEXT NOT NULL,
|
|
23
|
+
title TEXT,
|
|
24
|
+
metadata TEXT,
|
|
25
|
+
content_hash TEXT,
|
|
26
|
+
indexed_at INTEGER NOT NULL
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE INDEX IF NOT EXISTS rag_docs_source_idx ON rag_documents(source_type, source_ref);
|
|
30
|
+
CREATE INDEX IF NOT EXISTS rag_docs_hash_idx ON rag_documents(content_hash);
|
|
31
|
+
|
|
32
|
+
-- Chunks table
|
|
33
|
+
CREATE TABLE IF NOT EXISTS rag_chunks (
|
|
34
|
+
id TEXT PRIMARY KEY,
|
|
35
|
+
doc_id TEXT NOT NULL REFERENCES rag_documents(id) ON DELETE CASCADE,
|
|
36
|
+
sequence INTEGER NOT NULL,
|
|
37
|
+
text TEXT NOT NULL,
|
|
38
|
+
metadata TEXT,
|
|
39
|
+
embedding BLOB
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
CREATE INDEX IF NOT EXISTS rag_chunks_doc_idx ON rag_chunks(doc_id, sequence);
|
|
43
|
+
|
|
44
|
+
-- FTS5 virtual table for full-text search
|
|
45
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS rag_chunks_fts USING fts5(
|
|
46
|
+
text,
|
|
47
|
+
content='rag_chunks',
|
|
48
|
+
content_rowid='rowid'
|
|
49
|
+
);
|
|
50
|
+
`;
|
|
51
|
+
const CREATE_TRIGGERS_SQL = `
|
|
52
|
+
-- Triggers to keep FTS in sync (only create if not exists)
|
|
53
|
+
CREATE TRIGGER IF NOT EXISTS rag_chunks_ai AFTER INSERT ON rag_chunks BEGIN
|
|
54
|
+
INSERT INTO rag_chunks_fts(rowid, text) VALUES (new.rowid, new.text);
|
|
55
|
+
END;
|
|
56
|
+
|
|
57
|
+
CREATE TRIGGER IF NOT EXISTS rag_chunks_ad AFTER DELETE ON rag_chunks BEGIN
|
|
58
|
+
INSERT INTO rag_chunks_fts(rag_chunks_fts, rowid, text) VALUES('delete', old.rowid, old.text);
|
|
59
|
+
END;
|
|
60
|
+
|
|
61
|
+
CREATE TRIGGER IF NOT EXISTS rag_chunks_au AFTER UPDATE ON rag_chunks BEGIN
|
|
62
|
+
INSERT INTO rag_chunks_fts(rag_chunks_fts, rowid, text) VALUES('delete', old.rowid, old.text);
|
|
63
|
+
INSERT INTO rag_chunks_fts(rowid, text) VALUES (new.rowid, new.text);
|
|
64
|
+
END;
|
|
65
|
+
`;
|
|
66
|
+
// ============================================================================
|
|
67
|
+
// SQLite Retrieval Implementation
|
|
68
|
+
// ============================================================================
|
|
69
|
+
/**
|
|
70
|
+
* Create a SQLite FTS5 retrieval adapter.
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```typescript
|
|
74
|
+
* // In-memory for testing
|
|
75
|
+
* const retrieval = createSQLiteRetrieval({ filename: ':memory:' });
|
|
76
|
+
*
|
|
77
|
+
* // File-based for persistence
|
|
78
|
+
* const retrieval = createSQLiteRetrieval({ filename: './data/rag.db' });
|
|
79
|
+
*
|
|
80
|
+
* // Ingest a document
|
|
81
|
+
* const doc = await retrieval.upsertDocument({
|
|
82
|
+
* id: 'doc-1',
|
|
83
|
+
* sourceType: 'url',
|
|
84
|
+
* sourceRef: 'https://example.com/page',
|
|
85
|
+
* title: 'Example',
|
|
86
|
+
* metadata: {}
|
|
87
|
+
* });
|
|
88
|
+
*
|
|
89
|
+
* // Index chunks
|
|
90
|
+
* await retrieval.upsertChunks(doc.id, [
|
|
91
|
+
* { sequence: 0, text: 'First paragraph about AI...' },
|
|
92
|
+
* { sequence: 1, text: 'Second paragraph about ML...' }
|
|
93
|
+
* ]);
|
|
94
|
+
*
|
|
95
|
+
* // Search
|
|
96
|
+
* const results = await retrieval.search('artificial intelligence', { topK: 5 });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
function createSQLiteRetrieval(config) {
|
|
100
|
+
const sqlite = new better_sqlite3_1.default(config.filename);
|
|
101
|
+
// Enable WAL mode for better concurrency (default: true)
|
|
102
|
+
if (config.walMode !== false) {
|
|
103
|
+
sqlite.pragma('journal_mode = WAL');
|
|
104
|
+
}
|
|
105
|
+
// Enable foreign keys
|
|
106
|
+
sqlite.pragma('foreign_keys = ON');
|
|
107
|
+
// Create tables
|
|
108
|
+
sqlite.exec(CREATE_TABLES_SQL);
|
|
109
|
+
// Create triggers (separate to handle IF NOT EXISTS properly)
|
|
110
|
+
try {
|
|
111
|
+
sqlite.exec(CREATE_TRIGGERS_SQL);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
// Triggers may already exist, ignore
|
|
115
|
+
}
|
|
116
|
+
// Prepared statements
|
|
117
|
+
const stmts = {
|
|
118
|
+
upsertDoc: sqlite.prepare(`
|
|
119
|
+
INSERT INTO rag_documents (id, source_type, source_ref, title, metadata, content_hash, indexed_at)
|
|
120
|
+
VALUES (@id, @sourceType, @sourceRef, @title, @metadata, @contentHash, @indexedAt)
|
|
121
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
122
|
+
source_type = @sourceType,
|
|
123
|
+
source_ref = @sourceRef,
|
|
124
|
+
title = @title,
|
|
125
|
+
metadata = @metadata,
|
|
126
|
+
content_hash = @contentHash,
|
|
127
|
+
indexed_at = @indexedAt
|
|
128
|
+
`),
|
|
129
|
+
getDoc: sqlite.prepare(`
|
|
130
|
+
SELECT id, source_type, source_ref, title, metadata, content_hash, indexed_at
|
|
131
|
+
FROM rag_documents WHERE id = ?
|
|
132
|
+
`),
|
|
133
|
+
deleteDoc: sqlite.prepare(`DELETE FROM rag_documents WHERE id = ?`),
|
|
134
|
+
deleteChunks: sqlite.prepare(`DELETE FROM rag_chunks WHERE doc_id = ?`),
|
|
135
|
+
insertChunk: sqlite.prepare(`
|
|
136
|
+
INSERT INTO rag_chunks (id, doc_id, sequence, text, metadata, embedding)
|
|
137
|
+
VALUES (@id, @docId, @sequence, @text, @metadata, @embedding)
|
|
138
|
+
`),
|
|
139
|
+
getChunks: sqlite.prepare(`
|
|
140
|
+
SELECT id, doc_id, sequence, text, metadata, embedding
|
|
141
|
+
FROM rag_chunks WHERE doc_id = ? ORDER BY sequence
|
|
142
|
+
`),
|
|
143
|
+
listDocs: sqlite.prepare(`
|
|
144
|
+
SELECT id, source_type, source_ref, title, metadata, content_hash, indexed_at
|
|
145
|
+
FROM rag_documents
|
|
146
|
+
ORDER BY indexed_at DESC
|
|
147
|
+
LIMIT ? OFFSET ?
|
|
148
|
+
`),
|
|
149
|
+
listDocsByType: sqlite.prepare(`
|
|
150
|
+
SELECT id, source_type, source_ref, title, metadata, content_hash, indexed_at
|
|
151
|
+
FROM rag_documents
|
|
152
|
+
WHERE source_type = ?
|
|
153
|
+
ORDER BY indexed_at DESC
|
|
154
|
+
LIMIT ? OFFSET ?
|
|
155
|
+
`),
|
|
156
|
+
searchFts: sqlite.prepare(`
|
|
157
|
+
SELECT
|
|
158
|
+
c.id, c.doc_id, c.sequence, c.text, c.metadata, c.embedding,
|
|
159
|
+
d.id as d_id, d.source_type, d.source_ref, d.title,
|
|
160
|
+
d.metadata as d_metadata, d.content_hash, d.indexed_at,
|
|
161
|
+
bm25(rag_chunks_fts) as score,
|
|
162
|
+
snippet(rag_chunks_fts, 0, '<mark>', '</mark>', '...', 32) as highlight
|
|
163
|
+
FROM rag_chunks_fts fts
|
|
164
|
+
JOIN rag_chunks c ON c.rowid = fts.rowid
|
|
165
|
+
JOIN rag_documents d ON d.id = c.doc_id
|
|
166
|
+
WHERE rag_chunks_fts MATCH ?
|
|
167
|
+
ORDER BY score
|
|
168
|
+
LIMIT ?
|
|
169
|
+
`),
|
|
170
|
+
};
|
|
171
|
+
function mapRowToDoc(row) {
|
|
172
|
+
return {
|
|
173
|
+
id: row.id,
|
|
174
|
+
sourceType: row.source_type,
|
|
175
|
+
sourceRef: row.source_ref,
|
|
176
|
+
title: row.title,
|
|
177
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : {},
|
|
178
|
+
contentHash: row.content_hash,
|
|
179
|
+
indexedAt: row.indexed_at,
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
function mapRowToChunk(row) {
|
|
183
|
+
return {
|
|
184
|
+
id: row.id,
|
|
185
|
+
docId: row.doc_id,
|
|
186
|
+
sequence: row.sequence,
|
|
187
|
+
text: row.text,
|
|
188
|
+
metadata: row.metadata ? JSON.parse(row.metadata) : undefined,
|
|
189
|
+
embedding: row.embedding ? Array.from(new Float32Array(row.embedding.buffer)) : undefined,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
name: 'sqlite-fts',
|
|
194
|
+
async upsertDocument(doc) {
|
|
195
|
+
const now = Date.now();
|
|
196
|
+
stmts.upsertDoc.run({
|
|
197
|
+
id: doc.id,
|
|
198
|
+
sourceType: doc.sourceType,
|
|
199
|
+
sourceRef: doc.sourceRef,
|
|
200
|
+
title: doc.title ?? null,
|
|
201
|
+
metadata: JSON.stringify(doc.metadata),
|
|
202
|
+
contentHash: doc.contentHash ?? null,
|
|
203
|
+
indexedAt: now,
|
|
204
|
+
});
|
|
205
|
+
return {
|
|
206
|
+
...doc,
|
|
207
|
+
indexedAt: now,
|
|
208
|
+
};
|
|
209
|
+
},
|
|
210
|
+
async upsertChunks(docId, chunks) {
|
|
211
|
+
// Delete existing chunks first
|
|
212
|
+
stmts.deleteChunks.run(docId);
|
|
213
|
+
// Insert new chunks
|
|
214
|
+
const insertMany = sqlite.transaction((items) => {
|
|
215
|
+
for (const chunk of items) {
|
|
216
|
+
const id = crypto.randomUUID();
|
|
217
|
+
stmts.insertChunk.run({
|
|
218
|
+
id,
|
|
219
|
+
docId,
|
|
220
|
+
sequence: chunk.sequence,
|
|
221
|
+
text: chunk.text,
|
|
222
|
+
metadata: chunk.metadata ? JSON.stringify(chunk.metadata) : null,
|
|
223
|
+
embedding: chunk.embedding ? Buffer.from(new Float32Array(chunk.embedding).buffer) : null,
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
});
|
|
227
|
+
insertMany(chunks);
|
|
228
|
+
return chunks.length;
|
|
229
|
+
},
|
|
230
|
+
async deleteDocument(docId) {
|
|
231
|
+
stmts.deleteDoc.run(docId);
|
|
232
|
+
},
|
|
233
|
+
async search(query, options) {
|
|
234
|
+
const topK = options?.topK ?? 10;
|
|
235
|
+
// Escape special FTS5 characters and format query
|
|
236
|
+
const ftsQuery = query
|
|
237
|
+
.replace(/['"]/g, '')
|
|
238
|
+
.split(/\s+/)
|
|
239
|
+
.filter(Boolean)
|
|
240
|
+
.map(term => `"${term}"`)
|
|
241
|
+
.join(' OR ');
|
|
242
|
+
if (!ftsQuery) {
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const rows = stmts.searchFts.all(ftsQuery, topK);
|
|
247
|
+
const results = rows.map(row => ({
|
|
248
|
+
chunk: mapRowToChunk(row),
|
|
249
|
+
doc: {
|
|
250
|
+
id: row.d_id,
|
|
251
|
+
sourceType: row.source_type,
|
|
252
|
+
sourceRef: row.source_ref,
|
|
253
|
+
title: row.title,
|
|
254
|
+
metadata: row.d_metadata ? JSON.parse(row.d_metadata) : {},
|
|
255
|
+
contentHash: row.content_hash,
|
|
256
|
+
indexedAt: row.indexed_at,
|
|
257
|
+
},
|
|
258
|
+
score: Math.abs(row.score), // BM25 returns negative scores
|
|
259
|
+
highlights: row.highlight ? [row.highlight] : undefined,
|
|
260
|
+
}));
|
|
261
|
+
// Apply filters
|
|
262
|
+
let filtered = results;
|
|
263
|
+
if (options?.sourceTypes?.length) {
|
|
264
|
+
filtered = filtered.filter(r => options.sourceTypes.includes(r.doc.sourceType));
|
|
265
|
+
}
|
|
266
|
+
if (options?.minScore !== undefined) {
|
|
267
|
+
filtered = filtered.filter(r => r.score >= options.minScore);
|
|
268
|
+
}
|
|
269
|
+
return filtered;
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// FTS query syntax error, return empty
|
|
273
|
+
return [];
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
async getDocument(docId) {
|
|
277
|
+
const row = stmts.getDoc.get(docId);
|
|
278
|
+
return row ? mapRowToDoc(row) : null;
|
|
279
|
+
},
|
|
280
|
+
async getChunks(docId) {
|
|
281
|
+
const rows = stmts.getChunks.all(docId);
|
|
282
|
+
return rows.map(mapRowToChunk);
|
|
283
|
+
},
|
|
284
|
+
async listDocuments(options) {
|
|
285
|
+
const limit = options?.limit ?? 100;
|
|
286
|
+
const offset = options?.offset ?? 0;
|
|
287
|
+
let rows;
|
|
288
|
+
if (options?.sourceType) {
|
|
289
|
+
rows = stmts.listDocsByType.all(options.sourceType, limit, offset);
|
|
290
|
+
}
|
|
291
|
+
else {
|
|
292
|
+
rows = stmts.listDocs.all(limit, offset);
|
|
293
|
+
}
|
|
294
|
+
return rows.map(mapRowToDoc);
|
|
295
|
+
},
|
|
296
|
+
close() {
|
|
297
|
+
sqlite.close();
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
//# sourceMappingURL=index.js.map
|
package/src/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/drift/drift-plugins/mcg-retrieval-sqlite/src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin Manifest for @quarry-systems/mcg-retrieval-sqlite
|
|
3
|
+
*
|
|
4
|
+
* This manifest declares the plugin's metadata, capabilities, and requirements.
|
|
5
|
+
* It enables future security policies, sandboxing, and hosted execution.
|
|
6
|
+
*/
|
|
7
|
+
import type { PluginManifest } from '@quarry-systems/drift-contracts';
|
|
8
|
+
export declare const manifest: PluginManifest;
|
|
9
|
+
export default manifest;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Plugin Manifest for @quarry-systems/mcg-retrieval-sqlite
|
|
4
|
+
*
|
|
5
|
+
* This manifest declares the plugin's metadata, capabilities, and requirements.
|
|
6
|
+
* It enables future security policies, sandboxing, and hosted execution.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.manifest = void 0;
|
|
10
|
+
exports.manifest = {
|
|
11
|
+
name: '@quarry-systems/mcg-retrieval-sqlite',
|
|
12
|
+
version: '0.6.0',
|
|
13
|
+
apiVersion: '1.0',
|
|
14
|
+
description: 'SQLite-based retrieval plugin for Managed Cyclic Graph (MCG)',
|
|
15
|
+
author: {
|
|
16
|
+
name: 'Quarry Systems',
|
|
17
|
+
email: 'support@quarrysystems.com',
|
|
18
|
+
},
|
|
19
|
+
license: 'ISC',
|
|
20
|
+
type: ['node'],
|
|
21
|
+
capabilities: {
|
|
22
|
+
network: false,
|
|
23
|
+
filesystem: true, // Reads/writes SQLite database files
|
|
24
|
+
secrets: false,
|
|
25
|
+
subprocess: false,
|
|
26
|
+
},
|
|
27
|
+
nodes: [],
|
|
28
|
+
services: [
|
|
29
|
+
{
|
|
30
|
+
id: 'sqliteRetrieval',
|
|
31
|
+
name: 'SQLite Retrieval Service',
|
|
32
|
+
description: 'SQLite-based document retrieval and search service',
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
peerDependencies: {
|
|
36
|
+
'@quarry-systems/drift-core': '^0.6.0',
|
|
37
|
+
'@quarry-systems/drift-contracts': '^0.6.0',
|
|
38
|
+
},
|
|
39
|
+
keywords: ['drift', 'mcg', 'managed-cyclic-graph', 'plugin', 'retrieval', 'sqlite', 'search', 'rag'],
|
|
40
|
+
repository: {
|
|
41
|
+
type: 'git',
|
|
42
|
+
url: 'https://github.com/quarry-systems/quarry-systems',
|
|
43
|
+
directory: 'libs/drift/drift-plugins/mcg-retrieval-sqlite',
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
exports.default = exports.manifest;
|
|
47
|
+
//# sourceMappingURL=plugin.manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.manifest.js","sourceRoot":"","sources":["../../../../../../libs/drift/drift-plugins/mcg-retrieval-sqlite/src/plugin.manifest.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAIU,QAAA,QAAQ,GAAmB;IACtC,IAAI,EAAE,sCAAsC;IAC5C,OAAO,EAAE,OAAO;IAChB,UAAU,EAAE,KAAK;IAEjB,WAAW,EAAE,8DAA8D;IAE3E,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,KAAK,EAAE,2BAA2B;KACnC;IAED,OAAO,EAAE,KAAK;IAEd,IAAI,EAAE,CAAC,MAAM,CAAC;IAEd,YAAY,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,IAAI,EAAI,qCAAqC;QACzD,OAAO,EAAE,KAAK;QACd,UAAU,EAAE,KAAK;KAClB;IAED,KAAK,EAAE,EAAE;IAET,QAAQ,EAAE;QACR;YACE,EAAE,EAAE,iBAAiB;YACrB,IAAI,EAAE,0BAA0B;YAChC,WAAW,EAAE,oDAAoD;SAClE;KACF;IAED,gBAAgB,EAAE;QAChB,4BAA4B,EAAE,QAAQ;QACtC,iCAAiC,EAAE,QAAQ;KAC5C;IAED,QAAQ,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,sBAAsB,EAAE,QAAQ,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,KAAK,CAAC;IAEpG,UAAU,EAAE;QACV,IAAI,EAAE,KAAK;QACX,GAAG,EAAE,kDAAkD;QACvD,SAAS,EAAE,+CAA+C;KAC3D;CACF,CAAC;AAEF,kBAAe,gBAAQ,CAAC"}
|