family-ai-agent 1.0.6 → 1.0.7
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/.letta/settings.local.json +3 -0
- package/dist/database/adapters/base-adapter.d.ts +81 -0
- package/dist/database/adapters/base-adapter.d.ts.map +1 -0
- package/dist/database/adapters/base-adapter.js +105 -0
- package/dist/database/adapters/base-adapter.js.map +1 -0
- package/dist/database/adapters/index.d.ts +49 -0
- package/dist/database/adapters/index.d.ts.map +1 -0
- package/dist/database/adapters/index.js +200 -0
- package/dist/database/adapters/index.js.map +1 -0
- package/dist/database/adapters/postgres-adapter.d.ts +75 -0
- package/dist/database/adapters/postgres-adapter.d.ts.map +1 -0
- package/dist/database/adapters/postgres-adapter.js +225 -0
- package/dist/database/adapters/postgres-adapter.js.map +1 -0
- package/dist/database/adapters/sqlite-adapter.d.ts +72 -0
- package/dist/database/adapters/sqlite-adapter.d.ts.map +1 -0
- package/dist/database/adapters/sqlite-adapter.js +368 -0
- package/dist/database/adapters/sqlite-adapter.js.map +1 -0
- package/dist/database/cache/cache-keys.d.ts +180 -0
- package/dist/database/cache/cache-keys.d.ts.map +1 -0
- package/dist/database/cache/cache-keys.js +107 -0
- package/dist/database/cache/cache-keys.js.map +1 -0
- package/dist/database/cache/index.d.ts +24 -0
- package/dist/database/cache/index.d.ts.map +1 -0
- package/dist/database/cache/index.js +34 -0
- package/dist/database/cache/index.js.map +1 -0
- package/dist/database/cache/query-cache.d.ts +67 -0
- package/dist/database/cache/query-cache.d.ts.map +1 -0
- package/dist/database/cache/query-cache.js +177 -0
- package/dist/database/cache/query-cache.js.map +1 -0
- package/dist/database/client.d.ts +63 -4
- package/dist/database/client.d.ts.map +1 -1
- package/dist/database/client.js +147 -59
- package/dist/database/client.js.map +1 -1
- package/dist/database/db-config.d.ts +104 -0
- package/dist/database/db-config.d.ts.map +1 -0
- package/dist/database/db-config.js +167 -0
- package/dist/database/db-config.js.map +1 -0
- package/dist/database/drizzle/index.d.ts +42 -0
- package/dist/database/drizzle/index.d.ts.map +1 -0
- package/dist/database/drizzle/index.js +48 -0
- package/dist/database/drizzle/index.js.map +1 -0
- package/dist/database/drizzle/schema/audit.d.ts +533 -0
- package/dist/database/drizzle/schema/audit.d.ts.map +1 -0
- package/dist/database/drizzle/schema/audit.js +71 -0
- package/dist/database/drizzle/schema/audit.js.map +1 -0
- package/dist/database/drizzle/schema/checkpoints.d.ts +665 -0
- package/dist/database/drizzle/schema/checkpoints.d.ts.map +1 -0
- package/dist/database/drizzle/schema/checkpoints.js +110 -0
- package/dist/database/drizzle/schema/checkpoints.js.map +1 -0
- package/dist/database/drizzle/schema/conversations.d.ts +449 -0
- package/dist/database/drizzle/schema/conversations.d.ts.map +1 -0
- package/dist/database/drizzle/schema/conversations.js +91 -0
- package/dist/database/drizzle/schema/conversations.js.map +1 -0
- package/dist/database/drizzle/schema/documents.d.ts +600 -0
- package/dist/database/drizzle/schema/documents.d.ts.map +1 -0
- package/dist/database/drizzle/schema/documents.js +100 -0
- package/dist/database/drizzle/schema/documents.js.map +1 -0
- package/dist/database/drizzle/schema/index.d.ts +3084 -0
- package/dist/database/drizzle/schema/index.d.ts.map +1 -0
- package/dist/database/drizzle/schema/index.js +46 -0
- package/dist/database/drizzle/schema/index.js.map +1 -0
- package/dist/database/drizzle/schema/memories.d.ts +435 -0
- package/dist/database/drizzle/schema/memories.d.ts.map +1 -0
- package/dist/database/drizzle/schema/memories.js +73 -0
- package/dist/database/drizzle/schema/memories.js.map +1 -0
- package/dist/database/drizzle/schema/tasks.d.ts +565 -0
- package/dist/database/drizzle/schema/tasks.d.ts.map +1 -0
- package/dist/database/drizzle/schema/tasks.js +84 -0
- package/dist/database/drizzle/schema/tasks.js.map +1 -0
- package/dist/database/health/circuit-breaker.d.ts +81 -0
- package/dist/database/health/circuit-breaker.d.ts.map +1 -0
- package/dist/database/health/circuit-breaker.js +184 -0
- package/dist/database/health/circuit-breaker.js.map +1 -0
- package/dist/database/health/health-monitor.d.ts +69 -0
- package/dist/database/health/health-monitor.d.ts.map +1 -0
- package/dist/database/health/health-monitor.js +174 -0
- package/dist/database/health/health-monitor.js.map +1 -0
- package/dist/database/health/index.d.ts +27 -0
- package/dist/database/health/index.d.ts.map +1 -0
- package/dist/database/health/index.js +23 -0
- package/dist/database/health/index.js.map +1 -0
- package/dist/database/index.d.ts +16 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +41 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/migrations/index.d.ts +34 -0
- package/dist/database/migrations/index.d.ts.map +1 -0
- package/dist/database/migrations/index.js +45 -0
- package/dist/database/migrations/index.js.map +1 -0
- package/dist/database/migrations/migrator.d.ts +77 -0
- package/dist/database/migrations/migrator.d.ts.map +1 -0
- package/dist/database/migrations/migrator.js +258 -0
- package/dist/database/migrations/migrator.js.map +1 -0
- package/dist/database/migrations/versions/001_initial.d.ts +9 -0
- package/dist/database/migrations/versions/001_initial.d.ts.map +1 -0
- package/dist/database/migrations/versions/001_initial.js +183 -0
- package/dist/database/migrations/versions/001_initial.js.map +1 -0
- package/dist/database/types.d.ts +255 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +8 -0
- package/dist/database/types.js.map +1 -0
- package/dist/database/vector/embedding-cache.d.ts +92 -0
- package/dist/database/vector/embedding-cache.d.ts.map +1 -0
- package/dist/database/vector/embedding-cache.js +185 -0
- package/dist/database/vector/embedding-cache.js.map +1 -0
- package/dist/database/vector/hnsw-index.d.ts +111 -0
- package/dist/database/vector/hnsw-index.d.ts.map +1 -0
- package/dist/database/vector/hnsw-index.js +337 -0
- package/dist/database/vector/hnsw-index.js.map +1 -0
- package/dist/database/vector/index.d.ts +75 -0
- package/dist/database/vector/index.d.ts.map +1 -0
- package/dist/database/vector/index.js +213 -0
- package/dist/database/vector/index.js.map +1 -0
- package/dist/database/vector/similarity.d.ts +67 -0
- package/dist/database/vector/similarity.d.ts.map +1 -0
- package/dist/database/vector/similarity.js +176 -0
- package/dist/database/vector/similarity.js.map +1 -0
- package/package.json +6 -3
- package/src/database/adapters/base-adapter.ts +171 -0
- package/src/database/adapters/index.ts +224 -0
- package/src/database/adapters/postgres-adapter.ts +285 -0
- package/src/database/adapters/sqlite-adapter.ts +420 -0
- package/src/database/cache/cache-keys.ts +150 -0
- package/src/database/cache/index.ts +44 -0
- package/src/database/cache/query-cache.ts +213 -0
- package/src/database/client.ts +166 -64
- package/src/database/db-config.ts +194 -0
- package/src/database/drizzle/index.ts +66 -0
- package/src/database/drizzle/schema/audit.ts +127 -0
- package/src/database/drizzle/schema/checkpoints.ts +164 -0
- package/src/database/drizzle/schema/conversations.ts +138 -0
- package/src/database/drizzle/schema/documents.ts +157 -0
- package/src/database/drizzle/schema/index.ts +139 -0
- package/src/database/drizzle/schema/memories.ts +127 -0
- package/src/database/drizzle/schema/tasks.ts +129 -0
- package/src/database/health/circuit-breaker.ts +214 -0
- package/src/database/health/health-monitor.ts +224 -0
- package/src/database/health/index.ts +41 -0
- package/src/database/index.ts +157 -0
- package/src/database/migrations/index.ts +52 -0
- package/src/database/migrations/migrator.ts +325 -0
- package/src/database/migrations/versions/001_initial.ts +198 -0
- package/src/database/types.ts +324 -0
- package/src/database/vector/embedding-cache.ts +234 -0
- package/src/database/vector/hnsw-index.ts +452 -0
- package/src/database/vector/index.ts +292 -0
- package/src/database/vector/similarity.ts +198 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector Similarity Functions
|
|
3
|
+
*
|
|
4
|
+
* Mathematical utilities for computing vector similarity.
|
|
5
|
+
* Used for in-memory vector search in SQLite mode.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute cosine similarity between two vectors
|
|
9
|
+
* Returns a value between -1 and 1, where 1 means identical direction
|
|
10
|
+
*/
|
|
11
|
+
export declare function cosineSimilarity(a: number[], b: number[]): number;
|
|
12
|
+
/**
|
|
13
|
+
* Compute Euclidean distance between two vectors
|
|
14
|
+
*/
|
|
15
|
+
export declare function euclideanDistance(a: number[], b: number[]): number;
|
|
16
|
+
/**
|
|
17
|
+
* Compute dot product of two vectors
|
|
18
|
+
*/
|
|
19
|
+
export declare function dotProduct(a: number[], b: number[]): number;
|
|
20
|
+
/**
|
|
21
|
+
* Compute L2 norm (magnitude) of a vector
|
|
22
|
+
*/
|
|
23
|
+
export declare function l2Norm(v: number[]): number;
|
|
24
|
+
/**
|
|
25
|
+
* Normalize a vector to unit length
|
|
26
|
+
*/
|
|
27
|
+
export declare function normalize(v: number[]): number[];
|
|
28
|
+
/**
|
|
29
|
+
* Parse embedding from JSON string or array
|
|
30
|
+
*/
|
|
31
|
+
export declare function parseEmbedding(value: string | number[] | null | undefined): number[] | null;
|
|
32
|
+
/**
|
|
33
|
+
* Serialize embedding to JSON string
|
|
34
|
+
*/
|
|
35
|
+
export declare function serializeEmbedding(embedding: number[]): string;
|
|
36
|
+
/**
|
|
37
|
+
* Compute hash of embedding for caching
|
|
38
|
+
*/
|
|
39
|
+
export declare function hashEmbedding(embedding: number[]): string;
|
|
40
|
+
/**
|
|
41
|
+
* Quantize embedding to reduce memory usage
|
|
42
|
+
* Converts float32 to int8 (-128 to 127)
|
|
43
|
+
*/
|
|
44
|
+
export declare function quantize(embedding: number[]): Int8Array;
|
|
45
|
+
/**
|
|
46
|
+
* Dequantize int8 back to float
|
|
47
|
+
*/
|
|
48
|
+
export declare function dequantize(quantized: Int8Array): number[];
|
|
49
|
+
/**
|
|
50
|
+
* Cosine similarity for quantized vectors (faster)
|
|
51
|
+
*/
|
|
52
|
+
export declare function quantizedCosineSimilarity(a: Int8Array, b: Int8Array): number;
|
|
53
|
+
declare const _default: {
|
|
54
|
+
cosineSimilarity: typeof cosineSimilarity;
|
|
55
|
+
euclideanDistance: typeof euclideanDistance;
|
|
56
|
+
dotProduct: typeof dotProduct;
|
|
57
|
+
l2Norm: typeof l2Norm;
|
|
58
|
+
normalize: typeof normalize;
|
|
59
|
+
parseEmbedding: typeof parseEmbedding;
|
|
60
|
+
serializeEmbedding: typeof serializeEmbedding;
|
|
61
|
+
hashEmbedding: typeof hashEmbedding;
|
|
62
|
+
quantize: typeof quantize;
|
|
63
|
+
dequantize: typeof dequantize;
|
|
64
|
+
quantizedCosineSimilarity: typeof quantizedCosineSimilarity;
|
|
65
|
+
};
|
|
66
|
+
export default _default;
|
|
67
|
+
//# sourceMappingURL=similarity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../../../src/database/vector/similarity.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAoBjE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAYlE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAW3D;AAED;;GAEG;AACH,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,CAM1C;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAM/C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,IAAI,CA0B3F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAE9D;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,MAAM,CAKzD;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAS,CAOvD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,EAAE,CAMzD;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,MAAM,CAoB5E;;;;;;;;;;;;;;AAED,wBAYE"}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector Similarity Functions
|
|
3
|
+
*
|
|
4
|
+
* Mathematical utilities for computing vector similarity.
|
|
5
|
+
* Used for in-memory vector search in SQLite mode.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Compute cosine similarity between two vectors
|
|
9
|
+
* Returns a value between -1 and 1, where 1 means identical direction
|
|
10
|
+
*/
|
|
11
|
+
export function cosineSimilarity(a, b) {
|
|
12
|
+
if (a.length !== b.length) {
|
|
13
|
+
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
|
|
14
|
+
}
|
|
15
|
+
let dotProduct = 0;
|
|
16
|
+
let normA = 0;
|
|
17
|
+
let normB = 0;
|
|
18
|
+
for (let i = 0; i < a.length; i++) {
|
|
19
|
+
dotProduct += a[i] * b[i];
|
|
20
|
+
normA += a[i] * a[i];
|
|
21
|
+
normB += b[i] * b[i];
|
|
22
|
+
}
|
|
23
|
+
if (normA === 0 || normB === 0) {
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compute Euclidean distance between two vectors
|
|
30
|
+
*/
|
|
31
|
+
export function euclideanDistance(a, b) {
|
|
32
|
+
if (a.length !== b.length) {
|
|
33
|
+
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
|
|
34
|
+
}
|
|
35
|
+
let sum = 0;
|
|
36
|
+
for (let i = 0; i < a.length; i++) {
|
|
37
|
+
const diff = a[i] - b[i];
|
|
38
|
+
sum += diff * diff;
|
|
39
|
+
}
|
|
40
|
+
return Math.sqrt(sum);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Compute dot product of two vectors
|
|
44
|
+
*/
|
|
45
|
+
export function dotProduct(a, b) {
|
|
46
|
+
if (a.length !== b.length) {
|
|
47
|
+
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
|
|
48
|
+
}
|
|
49
|
+
let sum = 0;
|
|
50
|
+
for (let i = 0; i < a.length; i++) {
|
|
51
|
+
sum += a[i] * b[i];
|
|
52
|
+
}
|
|
53
|
+
return sum;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Compute L2 norm (magnitude) of a vector
|
|
57
|
+
*/
|
|
58
|
+
export function l2Norm(v) {
|
|
59
|
+
let sum = 0;
|
|
60
|
+
for (let i = 0; i < v.length; i++) {
|
|
61
|
+
sum += v[i] * v[i];
|
|
62
|
+
}
|
|
63
|
+
return Math.sqrt(sum);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Normalize a vector to unit length
|
|
67
|
+
*/
|
|
68
|
+
export function normalize(v) {
|
|
69
|
+
const norm = l2Norm(v);
|
|
70
|
+
if (norm === 0) {
|
|
71
|
+
return v.slice();
|
|
72
|
+
}
|
|
73
|
+
return v.map((x) => x / norm);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Parse embedding from JSON string or array
|
|
77
|
+
*/
|
|
78
|
+
export function parseEmbedding(value) {
|
|
79
|
+
if (!value)
|
|
80
|
+
return null;
|
|
81
|
+
if (Array.isArray(value)) {
|
|
82
|
+
return value;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
// Try parsing as JSON array
|
|
86
|
+
const parsed = JSON.parse(value);
|
|
87
|
+
if (Array.isArray(parsed)) {
|
|
88
|
+
return parsed;
|
|
89
|
+
}
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
catch {
|
|
93
|
+
// Try parsing as PostgreSQL vector format: [0.1, 0.2, ...]
|
|
94
|
+
const match = value.match(/^\[(.+)\]$/);
|
|
95
|
+
if (match) {
|
|
96
|
+
try {
|
|
97
|
+
return match[1].split(',').map((s) => parseFloat(s.trim()));
|
|
98
|
+
}
|
|
99
|
+
catch {
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Serialize embedding to JSON string
|
|
108
|
+
*/
|
|
109
|
+
export function serializeEmbedding(embedding) {
|
|
110
|
+
return JSON.stringify(embedding);
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Compute hash of embedding for caching
|
|
114
|
+
*/
|
|
115
|
+
export function hashEmbedding(embedding) {
|
|
116
|
+
// Simple hash using first and last few elements + length
|
|
117
|
+
const first = embedding.slice(0, 4).map((n) => n.toFixed(4)).join(',');
|
|
118
|
+
const last = embedding.slice(-4).map((n) => n.toFixed(4)).join(',');
|
|
119
|
+
return `${embedding.length}:${first}:${last}`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Quantize embedding to reduce memory usage
|
|
123
|
+
* Converts float32 to int8 (-128 to 127)
|
|
124
|
+
*/
|
|
125
|
+
export function quantize(embedding) {
|
|
126
|
+
const quantized = new Int8Array(embedding.length);
|
|
127
|
+
for (let i = 0; i < embedding.length; i++) {
|
|
128
|
+
// Scale from [-1, 1] to [-128, 127]
|
|
129
|
+
quantized[i] = Math.round(Math.max(-128, Math.min(127, embedding[i] * 127)));
|
|
130
|
+
}
|
|
131
|
+
return quantized;
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Dequantize int8 back to float
|
|
135
|
+
*/
|
|
136
|
+
export function dequantize(quantized) {
|
|
137
|
+
const result = new Array(quantized.length);
|
|
138
|
+
for (let i = 0; i < quantized.length; i++) {
|
|
139
|
+
result[i] = quantized[i] / 127;
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Cosine similarity for quantized vectors (faster)
|
|
145
|
+
*/
|
|
146
|
+
export function quantizedCosineSimilarity(a, b) {
|
|
147
|
+
if (a.length !== b.length) {
|
|
148
|
+
throw new Error(`Vector dimension mismatch: ${a.length} vs ${b.length}`);
|
|
149
|
+
}
|
|
150
|
+
let dotProduct = 0;
|
|
151
|
+
let normA = 0;
|
|
152
|
+
let normB = 0;
|
|
153
|
+
for (let i = 0; i < a.length; i++) {
|
|
154
|
+
dotProduct += a[i] * b[i];
|
|
155
|
+
normA += a[i] * a[i];
|
|
156
|
+
normB += b[i] * b[i];
|
|
157
|
+
}
|
|
158
|
+
if (normA === 0 || normB === 0) {
|
|
159
|
+
return 0;
|
|
160
|
+
}
|
|
161
|
+
return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
|
|
162
|
+
}
|
|
163
|
+
export default {
|
|
164
|
+
cosineSimilarity,
|
|
165
|
+
euclideanDistance,
|
|
166
|
+
dotProduct,
|
|
167
|
+
l2Norm,
|
|
168
|
+
normalize,
|
|
169
|
+
parseEmbedding,
|
|
170
|
+
serializeEmbedding,
|
|
171
|
+
hashEmbedding,
|
|
172
|
+
quantize,
|
|
173
|
+
dequantize,
|
|
174
|
+
quantizedCosineSimilarity,
|
|
175
|
+
};
|
|
176
|
+
//# sourceMappingURL=similarity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.js","sourceRoot":"","sources":["../../../src/database/vector/similarity.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "family-ai-agent",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Multi-agent AI system with memory and autonomous capabilities",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -50,7 +50,9 @@
|
|
|
50
50
|
"jsdom": "^25.0.1",
|
|
51
51
|
"validator": "^13.12.0",
|
|
52
52
|
"dockerode": "^4.0.2",
|
|
53
|
-
"marked": "^15.0.4"
|
|
53
|
+
"marked": "^15.0.4",
|
|
54
|
+
"sql.js": "^1.11.0",
|
|
55
|
+
"better-sqlite3": "^11.6.0"
|
|
54
56
|
},
|
|
55
57
|
"devDependencies": {
|
|
56
58
|
"@types/node": "^22.10.2",
|
|
@@ -65,7 +67,8 @@
|
|
|
65
67
|
"prettier": "^3.4.2",
|
|
66
68
|
"drizzle-kit": "^0.30.1",
|
|
67
69
|
"@typescript-eslint/eslint-plugin": "^8.18.1",
|
|
68
|
-
"@typescript-eslint/parser": "^8.18.1"
|
|
70
|
+
"@typescript-eslint/parser": "^8.18.1",
|
|
71
|
+
"@types/better-sqlite3": "^7.6.11"
|
|
69
72
|
},
|
|
70
73
|
"engines": {
|
|
71
74
|
"node": ">=20.0.0"
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Base Database Adapter
|
|
3
|
+
*
|
|
4
|
+
* Abstract base class for database adapters.
|
|
5
|
+
* Provides common functionality and interface contract.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {
|
|
9
|
+
DatabaseAdapter,
|
|
10
|
+
DatabaseType,
|
|
11
|
+
QueryResult,
|
|
12
|
+
TransactionClient,
|
|
13
|
+
PoolStats,
|
|
14
|
+
} from '../types.js';
|
|
15
|
+
import { createLogger } from '../../utils/logger.js';
|
|
16
|
+
import { MemoryError } from '../../utils/errors.js';
|
|
17
|
+
|
|
18
|
+
const logger = createLogger('DatabaseAdapter');
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Abstract base adapter class
|
|
22
|
+
*/
|
|
23
|
+
export abstract class BaseAdapter implements DatabaseAdapter {
|
|
24
|
+
abstract readonly type: DatabaseType;
|
|
25
|
+
protected _isInitialized = false;
|
|
26
|
+
|
|
27
|
+
get isInitialized(): boolean {
|
|
28
|
+
return this._isInitialized;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Initialize the database connection
|
|
33
|
+
*/
|
|
34
|
+
abstract initialize(): Promise<void>;
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Execute a raw SQL query
|
|
38
|
+
*/
|
|
39
|
+
abstract query<T extends Record<string, any> = Record<string, any>>(
|
|
40
|
+
sql: string,
|
|
41
|
+
params?: unknown[]
|
|
42
|
+
): Promise<QueryResult<T>>;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Execute a transaction
|
|
46
|
+
*/
|
|
47
|
+
abstract transaction<T>(
|
|
48
|
+
callback: (client: TransactionClient) => Promise<T>
|
|
49
|
+
): Promise<T>;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Check database health
|
|
53
|
+
*/
|
|
54
|
+
abstract healthCheck(): Promise<boolean>;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Get connection pool statistics
|
|
58
|
+
*/
|
|
59
|
+
getPoolStats?(): PoolStats;
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Close all connections
|
|
63
|
+
*/
|
|
64
|
+
abstract close(): Promise<void>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Ensure adapter is initialized before operations
|
|
68
|
+
*/
|
|
69
|
+
protected ensureInitialized(): void {
|
|
70
|
+
if (!this._isInitialized) {
|
|
71
|
+
throw new MemoryError('Database adapter not initialized. Call initialize() first.');
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Log query execution
|
|
77
|
+
*/
|
|
78
|
+
protected logQuery(sql: string, durationMs: number, rowCount: number | null): void {
|
|
79
|
+
logger.debug('Query executed', {
|
|
80
|
+
database: this.type,
|
|
81
|
+
duration: durationMs,
|
|
82
|
+
rows: rowCount,
|
|
83
|
+
query: sql.slice(0, 100),
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Log query error
|
|
89
|
+
*/
|
|
90
|
+
protected logError(sql: string, error: unknown): void {
|
|
91
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
|
|
92
|
+
logger.error('Query failed', {
|
|
93
|
+
database: this.type,
|
|
94
|
+
error: errorMessage,
|
|
95
|
+
query: sql.slice(0, 100),
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Convert PostgreSQL parameter placeholders ($1, $2) to SQLite (?)
|
|
101
|
+
*/
|
|
102
|
+
protected convertPlaceholders(sql: string): string {
|
|
103
|
+
return sql.replace(/\$\d+/g, '?');
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Convert PostgreSQL-specific syntax to SQLite
|
|
108
|
+
*/
|
|
109
|
+
protected convertToSqlite(sql: string): string {
|
|
110
|
+
let converted = this.convertPlaceholders(sql);
|
|
111
|
+
|
|
112
|
+
// Replace NOW() with CURRENT_TIMESTAMP
|
|
113
|
+
converted = converted.replace(/NOW\(\)/gi, 'CURRENT_TIMESTAMP');
|
|
114
|
+
|
|
115
|
+
// Remove ::type casts
|
|
116
|
+
converted = converted.replace(/::[a-zA-Z_]+(\[\])?/g, '');
|
|
117
|
+
|
|
118
|
+
// Replace JSONB with JSON (SQLite uses text)
|
|
119
|
+
converted = converted.replace(/JSONB/gi, 'JSON');
|
|
120
|
+
|
|
121
|
+
// Replace gen_random_uuid() with a placeholder (handled in code)
|
|
122
|
+
converted = converted.replace(/gen_random_uuid\(\)/gi, "lower(hex(randomblob(16)))");
|
|
123
|
+
|
|
124
|
+
return converted;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Extract RETURNING clause from SQL
|
|
129
|
+
*/
|
|
130
|
+
protected extractReturning(sql: string): string | null {
|
|
131
|
+
const match = sql.match(/RETURNING\s+(.+?)$/i);
|
|
132
|
+
return match ? match[1]!.trim() : null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Extract table name from INSERT/UPDATE/DELETE
|
|
137
|
+
*/
|
|
138
|
+
protected extractTableName(sql: string): string | null {
|
|
139
|
+
const insertMatch = sql.match(/INSERT\s+INTO\s+["']?(\w+)["']?/i);
|
|
140
|
+
if (insertMatch) return insertMatch[1]!;
|
|
141
|
+
|
|
142
|
+
const updateMatch = sql.match(/UPDATE\s+["']?(\w+)["']?/i);
|
|
143
|
+
if (updateMatch) return updateMatch[1]!;
|
|
144
|
+
|
|
145
|
+
const deleteMatch = sql.match(/DELETE\s+FROM\s+["']?(\w+)["']?/i);
|
|
146
|
+
if (deleteMatch) return deleteMatch[1]!;
|
|
147
|
+
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Check if SQL is a SELECT query
|
|
153
|
+
*/
|
|
154
|
+
protected isSelectQuery(sql: string): boolean {
|
|
155
|
+
return sql.trim().toUpperCase().startsWith('SELECT');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Check if SQL has RETURNING clause
|
|
160
|
+
*/
|
|
161
|
+
protected hasReturning(sql: string): boolean {
|
|
162
|
+
return /RETURNING\s+/i.test(sql);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Adapter factory function type
|
|
168
|
+
*/
|
|
169
|
+
export type AdapterFactory = () => Promise<DatabaseAdapter>;
|
|
170
|
+
|
|
171
|
+
export default BaseAdapter;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Adapter Factory
|
|
3
|
+
*
|
|
4
|
+
* Factory for creating database adapters with auto-detection support.
|
|
5
|
+
* Tries PostgreSQL first, falls back to SQLite automatically.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import pg from 'pg';
|
|
9
|
+
|
|
10
|
+
import { PostgresAdapter } from './postgres-adapter.js';
|
|
11
|
+
import { SQLiteAdapter } from './sqlite-adapter.js';
|
|
12
|
+
import { BaseAdapter } from './base-adapter.js';
|
|
13
|
+
import { getDatabaseConfig, buildPostgresUrl, getDefaultSqlitePath } from '../db-config.js';
|
|
14
|
+
import type { DatabaseAdapter, DetectionResult, DatabaseConfig } from '../types.js';
|
|
15
|
+
import { createLogger } from '../../utils/logger.js';
|
|
16
|
+
|
|
17
|
+
const { Pool } = pg;
|
|
18
|
+
const logger = createLogger('AdapterFactory');
|
|
19
|
+
|
|
20
|
+
// Singleton adapter instance
|
|
21
|
+
let adapterInstance: DatabaseAdapter | null = null;
|
|
22
|
+
let initPromise: Promise<DatabaseAdapter> | null = null;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Detect which database to use
|
|
26
|
+
*/
|
|
27
|
+
export async function detectDatabase(config: DatabaseConfig): Promise<DetectionResult> {
|
|
28
|
+
// 1. Check for explicit configuration
|
|
29
|
+
if (config.type !== 'auto') {
|
|
30
|
+
if (config.type === 'postgresql') {
|
|
31
|
+
return {
|
|
32
|
+
type: 'postgresql',
|
|
33
|
+
connectionString: config.postgresUrl ?? buildPostgresUrl({
|
|
34
|
+
DATABASE_URL: config.postgresUrl,
|
|
35
|
+
DB_HOST: config.postgresHost,
|
|
36
|
+
DB_PORT: config.postgresPort,
|
|
37
|
+
DB_USER: config.postgresUser,
|
|
38
|
+
DB_PASSWORD: config.postgresPassword,
|
|
39
|
+
DB_NAME: config.postgresDatabase,
|
|
40
|
+
DB_POOL_MAX: config.postgresPoolMax,
|
|
41
|
+
DB_POOL_IDLE_TIMEOUT_MS: config.postgresIdleTimeoutMs,
|
|
42
|
+
DB_POOL_CONNECTION_TIMEOUT_MS: config.postgresConnectionTimeoutMs,
|
|
43
|
+
DATABASE_TYPE: 'postgresql',
|
|
44
|
+
SQLITE_PATH: config.sqlitePath,
|
|
45
|
+
DB_HEALTH_CHECK_INTERVAL_MS: config.healthCheckIntervalMs,
|
|
46
|
+
DB_CIRCUIT_BREAKER_THRESHOLD: config.circuitBreakerThreshold,
|
|
47
|
+
DB_CIRCUIT_BREAKER_TIMEOUT_MS: config.circuitBreakerTimeoutMs,
|
|
48
|
+
DB_CACHE_MAX_SIZE: config.cacheMaxSize,
|
|
49
|
+
DB_CACHE_TTL_MS: config.cacheTtlMs,
|
|
50
|
+
VECTOR_DIMENSION: config.vectorDimension,
|
|
51
|
+
VECTOR_MIN_SIMILARITY: config.vectorMinSimilarity,
|
|
52
|
+
}),
|
|
53
|
+
reason: 'Explicit PostgreSQL configuration',
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
type: 'sqlite',
|
|
58
|
+
sqlitePath: config.sqlitePath ?? getDefaultSqlitePath(),
|
|
59
|
+
reason: 'Explicit SQLite configuration',
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 2. Check for DATABASE_URL (usually means PostgreSQL is intended)
|
|
64
|
+
if (config.postgresUrl) {
|
|
65
|
+
return {
|
|
66
|
+
type: 'postgresql',
|
|
67
|
+
connectionString: config.postgresUrl,
|
|
68
|
+
reason: 'DATABASE_URL environment variable set',
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// 3. Try PostgreSQL connection
|
|
73
|
+
try {
|
|
74
|
+
const connectionString = buildPostgresUrl({
|
|
75
|
+
DATABASE_URL: config.postgresUrl,
|
|
76
|
+
DB_HOST: config.postgresHost,
|
|
77
|
+
DB_PORT: config.postgresPort,
|
|
78
|
+
DB_USER: config.postgresUser,
|
|
79
|
+
DB_PASSWORD: config.postgresPassword,
|
|
80
|
+
DB_NAME: config.postgresDatabase,
|
|
81
|
+
DB_POOL_MAX: config.postgresPoolMax,
|
|
82
|
+
DB_POOL_IDLE_TIMEOUT_MS: config.postgresIdleTimeoutMs,
|
|
83
|
+
DB_POOL_CONNECTION_TIMEOUT_MS: config.postgresConnectionTimeoutMs,
|
|
84
|
+
DATABASE_TYPE: 'auto',
|
|
85
|
+
SQLITE_PATH: config.sqlitePath,
|
|
86
|
+
DB_HEALTH_CHECK_INTERVAL_MS: config.healthCheckIntervalMs,
|
|
87
|
+
DB_CIRCUIT_BREAKER_THRESHOLD: config.circuitBreakerThreshold,
|
|
88
|
+
DB_CIRCUIT_BREAKER_TIMEOUT_MS: config.circuitBreakerTimeoutMs,
|
|
89
|
+
DB_CACHE_MAX_SIZE: config.cacheMaxSize,
|
|
90
|
+
DB_CACHE_TTL_MS: config.cacheTtlMs,
|
|
91
|
+
VECTOR_DIMENSION: config.vectorDimension,
|
|
92
|
+
VECTOR_MIN_SIMILARITY: config.vectorMinSimilarity,
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const pool = new Pool({
|
|
96
|
+
connectionString,
|
|
97
|
+
connectionTimeoutMillis: 3000, // Quick timeout for detection
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const client = await pool.connect();
|
|
102
|
+
await client.query('SELECT 1');
|
|
103
|
+
client.release();
|
|
104
|
+
await pool.end();
|
|
105
|
+
|
|
106
|
+
logger.info('PostgreSQL connection successful');
|
|
107
|
+
return {
|
|
108
|
+
type: 'postgresql',
|
|
109
|
+
connectionString,
|
|
110
|
+
reason: 'PostgreSQL connection successful',
|
|
111
|
+
};
|
|
112
|
+
} finally {
|
|
113
|
+
await pool.end().catch(() => {});
|
|
114
|
+
}
|
|
115
|
+
} catch (error) {
|
|
116
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
117
|
+
logger.debug('PostgreSQL not available, falling back to SQLite', { error: message });
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// 4. Fall back to SQLite
|
|
121
|
+
const sqlitePath = config.sqlitePath ?? getDefaultSqlitePath();
|
|
122
|
+
return {
|
|
123
|
+
type: 'sqlite',
|
|
124
|
+
sqlitePath,
|
|
125
|
+
reason: 'PostgreSQL unavailable, using SQLite fallback',
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Create database adapter based on detection result
|
|
131
|
+
*/
|
|
132
|
+
export async function createAdapter(detection: DetectionResult, config: DatabaseConfig): Promise<DatabaseAdapter> {
|
|
133
|
+
let adapter: DatabaseAdapter;
|
|
134
|
+
|
|
135
|
+
if (detection.type === 'postgresql') {
|
|
136
|
+
adapter = new PostgresAdapter(detection.connectionString!, config);
|
|
137
|
+
} else {
|
|
138
|
+
adapter = new SQLiteAdapter(detection.sqlitePath!, config);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
await adapter.initialize();
|
|
142
|
+
return adapter;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Get or create the database adapter singleton
|
|
147
|
+
*/
|
|
148
|
+
export async function getAdapter(): Promise<DatabaseAdapter> {
|
|
149
|
+
if (adapterInstance?.isInitialized) {
|
|
150
|
+
return adapterInstance;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (!initPromise) {
|
|
154
|
+
initPromise = initializeAdapter();
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return initPromise;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Initialize the database adapter
|
|
162
|
+
*/
|
|
163
|
+
async function initializeAdapter(): Promise<DatabaseAdapter> {
|
|
164
|
+
const config = getDatabaseConfig();
|
|
165
|
+
const detection = await detectDatabase(config);
|
|
166
|
+
|
|
167
|
+
logger.info('Database detected', {
|
|
168
|
+
type: detection.type,
|
|
169
|
+
reason: detection.reason,
|
|
170
|
+
path: detection.sqlitePath,
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
adapterInstance = await createAdapter(detection, config);
|
|
174
|
+
return adapterInstance;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Close the database adapter
|
|
179
|
+
*/
|
|
180
|
+
export async function closeAdapter(): Promise<void> {
|
|
181
|
+
if (adapterInstance) {
|
|
182
|
+
await adapterInstance.close();
|
|
183
|
+
adapterInstance = null;
|
|
184
|
+
initPromise = null;
|
|
185
|
+
logger.info('Database adapter closed');
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Reset adapter (for testing)
|
|
191
|
+
*/
|
|
192
|
+
export function resetAdapter(): void {
|
|
193
|
+
adapterInstance = null;
|
|
194
|
+
initPromise = null;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Check if adapter is initialized
|
|
199
|
+
*/
|
|
200
|
+
export function isAdapterInitialized(): boolean {
|
|
201
|
+
return adapterInstance?.isInitialized ?? false;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get current adapter type
|
|
206
|
+
*/
|
|
207
|
+
export function getAdapterType(): 'postgresql' | 'sqlite' | null {
|
|
208
|
+
return adapterInstance?.type ?? null;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Re-export adapter classes
|
|
212
|
+
export { PostgresAdapter } from './postgres-adapter.js';
|
|
213
|
+
export { SQLiteAdapter } from './sqlite-adapter.js';
|
|
214
|
+
export { BaseAdapter } from './base-adapter.js';
|
|
215
|
+
|
|
216
|
+
export default {
|
|
217
|
+
getAdapter,
|
|
218
|
+
closeAdapter,
|
|
219
|
+
resetAdapter,
|
|
220
|
+
detectDatabase,
|
|
221
|
+
createAdapter,
|
|
222
|
+
isAdapterInitialized,
|
|
223
|
+
getAdapterType,
|
|
224
|
+
};
|