family-ai-agent 1.0.6 → 1.0.8
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/cli/index.js +1 -1
- 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/cli/index.ts +1 -1
- 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,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Circuit Breaker
|
|
3
|
+
*
|
|
4
|
+
* Prevents cascade failures by temporarily blocking calls to failing services.
|
|
5
|
+
* Implements the circuit breaker pattern for database resilience.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { CircuitBreakerState, CircuitBreakerOptions } from '../types.js';
|
|
9
|
+
import { createLogger } from '../../utils/logger.js';
|
|
10
|
+
|
|
11
|
+
const logger = createLogger('CircuitBreaker');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Error thrown when circuit is open
|
|
15
|
+
*/
|
|
16
|
+
export class CircuitOpenError extends Error {
|
|
17
|
+
constructor(message: string = 'Circuit breaker is open') {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = 'CircuitOpenError';
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Default circuit breaker options
|
|
25
|
+
*/
|
|
26
|
+
const DEFAULT_OPTIONS: CircuitBreakerOptions = {
|
|
27
|
+
failureThreshold: 5,
|
|
28
|
+
resetTimeoutMs: 60000,
|
|
29
|
+
halfOpenMaxAttempts: 3,
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Circuit breaker for database operations
|
|
34
|
+
*/
|
|
35
|
+
export class CircuitBreaker {
|
|
36
|
+
private state: CircuitBreakerState = 'closed';
|
|
37
|
+
private failureCount: number = 0;
|
|
38
|
+
private successCount: number = 0;
|
|
39
|
+
private lastFailureTime: number = 0;
|
|
40
|
+
private options: CircuitBreakerOptions;
|
|
41
|
+
private stateChangeListeners: Array<(state: CircuitBreakerState) => void> = [];
|
|
42
|
+
|
|
43
|
+
constructor(options: Partial<CircuitBreakerOptions> = {}) {
|
|
44
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Execute a function with circuit breaker protection
|
|
49
|
+
*/
|
|
50
|
+
async execute<T>(fn: () => Promise<T>): Promise<T> {
|
|
51
|
+
// Check if circuit should transition from open to half-open
|
|
52
|
+
if (this.state === 'open') {
|
|
53
|
+
const timeSinceLastFailure = Date.now() - this.lastFailureTime;
|
|
54
|
+
if (timeSinceLastFailure >= this.options.resetTimeoutMs) {
|
|
55
|
+
this.transitionTo('half-open');
|
|
56
|
+
} else {
|
|
57
|
+
throw new CircuitOpenError(
|
|
58
|
+
`Circuit breaker is open. Retry in ${Math.ceil(
|
|
59
|
+
(this.options.resetTimeoutMs - timeSinceLastFailure) / 1000
|
|
60
|
+
)} seconds.`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
const result = await fn();
|
|
67
|
+
this.onSuccess();
|
|
68
|
+
return result;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
this.onFailure();
|
|
71
|
+
throw error;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Handle successful execution
|
|
77
|
+
*/
|
|
78
|
+
private onSuccess(): void {
|
|
79
|
+
this.failureCount = 0;
|
|
80
|
+
|
|
81
|
+
if (this.state === 'half-open') {
|
|
82
|
+
this.successCount++;
|
|
83
|
+
if (this.successCount >= this.options.halfOpenMaxAttempts) {
|
|
84
|
+
this.transitionTo('closed');
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Handle failed execution
|
|
91
|
+
*/
|
|
92
|
+
private onFailure(): void {
|
|
93
|
+
this.failureCount++;
|
|
94
|
+
this.lastFailureTime = Date.now();
|
|
95
|
+
this.successCount = 0;
|
|
96
|
+
|
|
97
|
+
if (this.state === 'half-open') {
|
|
98
|
+
// Immediately open on failure in half-open state
|
|
99
|
+
this.transitionTo('open');
|
|
100
|
+
} else if (this.failureCount >= this.options.failureThreshold) {
|
|
101
|
+
this.transitionTo('open');
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Transition to a new state
|
|
107
|
+
*/
|
|
108
|
+
private transitionTo(newState: CircuitBreakerState): void {
|
|
109
|
+
if (this.state === newState) return;
|
|
110
|
+
|
|
111
|
+
const oldState = this.state;
|
|
112
|
+
this.state = newState;
|
|
113
|
+
|
|
114
|
+
if (newState === 'closed') {
|
|
115
|
+
this.failureCount = 0;
|
|
116
|
+
this.successCount = 0;
|
|
117
|
+
} else if (newState === 'half-open') {
|
|
118
|
+
this.successCount = 0;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
logger.info('Circuit breaker state changed', {
|
|
122
|
+
from: oldState,
|
|
123
|
+
to: newState,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// Notify listeners
|
|
127
|
+
for (const listener of this.stateChangeListeners) {
|
|
128
|
+
try {
|
|
129
|
+
listener(newState);
|
|
130
|
+
} catch (error) {
|
|
131
|
+
logger.error('State change listener error', { error });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Register a state change listener
|
|
138
|
+
*/
|
|
139
|
+
onStateChange(listener: (state: CircuitBreakerState) => void): () => void {
|
|
140
|
+
this.stateChangeListeners.push(listener);
|
|
141
|
+
return () => {
|
|
142
|
+
const index = this.stateChangeListeners.indexOf(listener);
|
|
143
|
+
if (index >= 0) {
|
|
144
|
+
this.stateChangeListeners.splice(index, 1);
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Get current state
|
|
151
|
+
*/
|
|
152
|
+
getState(): CircuitBreakerState {
|
|
153
|
+
return this.state;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Check if circuit is open
|
|
158
|
+
*/
|
|
159
|
+
isOpen(): boolean {
|
|
160
|
+
return this.state === 'open';
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Check if circuit is half-open
|
|
165
|
+
*/
|
|
166
|
+
isHalfOpen(): boolean {
|
|
167
|
+
return this.state === 'half-open';
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Check if circuit is closed
|
|
172
|
+
*/
|
|
173
|
+
isClosed(): boolean {
|
|
174
|
+
return this.state === 'closed';
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Force circuit to open state
|
|
179
|
+
*/
|
|
180
|
+
trip(): void {
|
|
181
|
+
this.lastFailureTime = Date.now();
|
|
182
|
+
this.transitionTo('open');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Force circuit to closed state
|
|
187
|
+
*/
|
|
188
|
+
reset(): void {
|
|
189
|
+
this.transitionTo('closed');
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Get circuit breaker statistics
|
|
194
|
+
*/
|
|
195
|
+
getStats(): {
|
|
196
|
+
state: CircuitBreakerState;
|
|
197
|
+
failureCount: number;
|
|
198
|
+
successCount: number;
|
|
199
|
+
lastFailureTime: number | null;
|
|
200
|
+
timeSinceLastFailure: number | null;
|
|
201
|
+
} {
|
|
202
|
+
return {
|
|
203
|
+
state: this.state,
|
|
204
|
+
failureCount: this.failureCount,
|
|
205
|
+
successCount: this.successCount,
|
|
206
|
+
lastFailureTime: this.lastFailureTime || null,
|
|
207
|
+
timeSinceLastFailure: this.lastFailureTime
|
|
208
|
+
? Date.now() - this.lastFailureTime
|
|
209
|
+
: null,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export default CircuitBreaker;
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Monitor
|
|
3
|
+
*
|
|
4
|
+
* Monitors database connection health and provides status information.
|
|
5
|
+
* Integrates with circuit breaker for resilience.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { DatabaseAdapter, DatabaseHealth, HealthMonitorOptions } from '../types.js';
|
|
9
|
+
import { CircuitBreaker } from './circuit-breaker.js';
|
|
10
|
+
import { createLogger } from '../../utils/logger.js';
|
|
11
|
+
|
|
12
|
+
const logger = createLogger('HealthMonitor');
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Default health monitor options
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_OPTIONS: HealthMonitorOptions = {
|
|
18
|
+
checkIntervalMs: 30000,
|
|
19
|
+
errorThreshold: 3,
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Database health monitor
|
|
24
|
+
*/
|
|
25
|
+
export class HealthMonitor {
|
|
26
|
+
private adapter: DatabaseAdapter;
|
|
27
|
+
private circuitBreaker: CircuitBreaker;
|
|
28
|
+
private options: HealthMonitorOptions;
|
|
29
|
+
|
|
30
|
+
private checkInterval: NodeJS.Timeout | null = null;
|
|
31
|
+
private lastStatus: DatabaseHealth | null = null;
|
|
32
|
+
private consecutiveErrors: number = 0;
|
|
33
|
+
private isRunning: boolean = false;
|
|
34
|
+
|
|
35
|
+
constructor(
|
|
36
|
+
adapter: DatabaseAdapter,
|
|
37
|
+
circuitBreaker: CircuitBreaker,
|
|
38
|
+
options: Partial<HealthMonitorOptions> = {}
|
|
39
|
+
) {
|
|
40
|
+
this.adapter = adapter;
|
|
41
|
+
this.circuitBreaker = circuitBreaker;
|
|
42
|
+
this.options = { ...DEFAULT_OPTIONS, ...options };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Start health monitoring
|
|
47
|
+
*/
|
|
48
|
+
start(): void {
|
|
49
|
+
if (this.isRunning) return;
|
|
50
|
+
|
|
51
|
+
this.isRunning = true;
|
|
52
|
+
this.check(); // Initial check
|
|
53
|
+
|
|
54
|
+
this.checkInterval = setInterval(
|
|
55
|
+
() => this.check(),
|
|
56
|
+
this.options.checkIntervalMs
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
logger.info('Health monitor started', {
|
|
60
|
+
intervalMs: this.options.checkIntervalMs,
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Stop health monitoring
|
|
66
|
+
*/
|
|
67
|
+
stop(): void {
|
|
68
|
+
if (!this.isRunning) return;
|
|
69
|
+
|
|
70
|
+
if (this.checkInterval) {
|
|
71
|
+
clearInterval(this.checkInterval);
|
|
72
|
+
this.checkInterval = null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.isRunning = false;
|
|
76
|
+
logger.info('Health monitor stopped');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Perform a health check
|
|
81
|
+
*/
|
|
82
|
+
async check(): Promise<DatabaseHealth> {
|
|
83
|
+
const startTime = Date.now();
|
|
84
|
+
const errors: string[] = [];
|
|
85
|
+
let isHealthy = false;
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
isHealthy = await this.circuitBreaker.execute(async () => {
|
|
89
|
+
return this.adapter.healthCheck();
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
if (isHealthy) {
|
|
93
|
+
this.consecutiveErrors = 0;
|
|
94
|
+
} else {
|
|
95
|
+
this.consecutiveErrors++;
|
|
96
|
+
errors.push('Health check returned false');
|
|
97
|
+
}
|
|
98
|
+
} catch (error) {
|
|
99
|
+
this.consecutiveErrors++;
|
|
100
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
101
|
+
errors.push(message);
|
|
102
|
+
logger.warn('Health check failed', { error: message });
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const latencyMs = Date.now() - startTime;
|
|
106
|
+
const status = this.determineStatus(errors.length > 0, latencyMs);
|
|
107
|
+
|
|
108
|
+
this.lastStatus = {
|
|
109
|
+
status,
|
|
110
|
+
type: this.adapter.type,
|
|
111
|
+
latencyMs,
|
|
112
|
+
poolStats: this.adapter.getPoolStats?.(),
|
|
113
|
+
circuitState: this.circuitBreaker.getState(),
|
|
114
|
+
lastCheck: new Date(),
|
|
115
|
+
errors,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// Log status changes
|
|
119
|
+
if (status !== 'healthy') {
|
|
120
|
+
logger.warn('Database health degraded', {
|
|
121
|
+
status,
|
|
122
|
+
errors,
|
|
123
|
+
consecutiveErrors: this.consecutiveErrors,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return this.lastStatus;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Determine overall health status
|
|
132
|
+
*/
|
|
133
|
+
private determineStatus(
|
|
134
|
+
hasErrors: boolean,
|
|
135
|
+
latencyMs: number
|
|
136
|
+
): 'healthy' | 'degraded' | 'unhealthy' {
|
|
137
|
+
// Unhealthy if circuit is open or too many consecutive errors
|
|
138
|
+
if (
|
|
139
|
+
this.circuitBreaker.isOpen() ||
|
|
140
|
+
this.consecutiveErrors >= this.options.errorThreshold
|
|
141
|
+
) {
|
|
142
|
+
return 'unhealthy';
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Degraded if circuit is half-open, has errors, or high latency
|
|
146
|
+
if (
|
|
147
|
+
this.circuitBreaker.isHalfOpen() ||
|
|
148
|
+
hasErrors ||
|
|
149
|
+
latencyMs > 1000
|
|
150
|
+
) {
|
|
151
|
+
return 'degraded';
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return 'healthy';
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Get current health status
|
|
159
|
+
*/
|
|
160
|
+
getStatus(): DatabaseHealth | null {
|
|
161
|
+
return this.lastStatus;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Check if database is healthy
|
|
166
|
+
*/
|
|
167
|
+
isHealthy(): boolean {
|
|
168
|
+
return this.lastStatus?.status === 'healthy';
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Check if database is degraded
|
|
173
|
+
*/
|
|
174
|
+
isDegraded(): boolean {
|
|
175
|
+
return this.lastStatus?.status === 'degraded';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Check if database is unhealthy
|
|
180
|
+
*/
|
|
181
|
+
isUnhealthy(): boolean {
|
|
182
|
+
return this.lastStatus?.status === 'unhealthy';
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Wait for database to become healthy
|
|
187
|
+
*/
|
|
188
|
+
async waitForHealthy(timeoutMs: number = 30000): Promise<boolean> {
|
|
189
|
+
const startTime = Date.now();
|
|
190
|
+
|
|
191
|
+
while (Date.now() - startTime < timeoutMs) {
|
|
192
|
+
const status = await this.check();
|
|
193
|
+
if (status.status === 'healthy') {
|
|
194
|
+
return true;
|
|
195
|
+
}
|
|
196
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Get health summary for API responses
|
|
204
|
+
*/
|
|
205
|
+
getSummary(): {
|
|
206
|
+
healthy: boolean;
|
|
207
|
+
status: string;
|
|
208
|
+
database: string;
|
|
209
|
+
latencyMs: number;
|
|
210
|
+
circuitBreaker: string;
|
|
211
|
+
} {
|
|
212
|
+
const status = this.lastStatus;
|
|
213
|
+
|
|
214
|
+
return {
|
|
215
|
+
healthy: status?.status === 'healthy',
|
|
216
|
+
status: status?.status ?? 'unknown',
|
|
217
|
+
database: this.adapter.type,
|
|
218
|
+
latencyMs: status?.latencyMs ?? -1,
|
|
219
|
+
circuitBreaker: this.circuitBreaker.getState(),
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export default HealthMonitor;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Health Monitoring Exports
|
|
3
|
+
*
|
|
4
|
+
* Central export for health monitoring and circuit breaker functionality.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { CircuitBreaker, CircuitOpenError } from './circuit-breaker.js';
|
|
8
|
+
export { HealthMonitor } from './health-monitor.js';
|
|
9
|
+
|
|
10
|
+
import { CircuitBreaker } from './circuit-breaker.js';
|
|
11
|
+
import { HealthMonitor } from './health-monitor.js';
|
|
12
|
+
import type { DatabaseAdapter, CircuitBreakerOptions, HealthMonitorOptions } from '../types.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Create a health monitoring system for an adapter
|
|
16
|
+
*/
|
|
17
|
+
export function createHealthSystem(
|
|
18
|
+
adapter: DatabaseAdapter,
|
|
19
|
+
options: {
|
|
20
|
+
circuitBreaker?: Partial<CircuitBreakerOptions>;
|
|
21
|
+
healthMonitor?: Partial<HealthMonitorOptions>;
|
|
22
|
+
} = {}
|
|
23
|
+
): {
|
|
24
|
+
circuitBreaker: CircuitBreaker;
|
|
25
|
+
healthMonitor: HealthMonitor;
|
|
26
|
+
} {
|
|
27
|
+
const circuitBreaker = new CircuitBreaker(options.circuitBreaker);
|
|
28
|
+
const healthMonitor = new HealthMonitor(
|
|
29
|
+
adapter,
|
|
30
|
+
circuitBreaker,
|
|
31
|
+
options.healthMonitor
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
return { circuitBreaker, healthMonitor };
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export default {
|
|
38
|
+
CircuitBreaker,
|
|
39
|
+
HealthMonitor,
|
|
40
|
+
createHealthSystem,
|
|
41
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Layer
|
|
3
|
+
*
|
|
4
|
+
* Main entry point for the database abstraction layer.
|
|
5
|
+
* Provides unified access to PostgreSQL and SQLite with auto-detection.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Core types
|
|
9
|
+
export * from './types.js';
|
|
10
|
+
|
|
11
|
+
// Configuration
|
|
12
|
+
export { getDatabaseConfig, loadDatabaseConfig, buildPostgresUrl, getDefaultSqlitePath } from './db-config.js';
|
|
13
|
+
|
|
14
|
+
// Adapters
|
|
15
|
+
export {
|
|
16
|
+
getAdapter,
|
|
17
|
+
closeAdapter,
|
|
18
|
+
resetAdapter,
|
|
19
|
+
detectDatabase,
|
|
20
|
+
isAdapterInitialized,
|
|
21
|
+
getAdapterType,
|
|
22
|
+
PostgresAdapter,
|
|
23
|
+
SQLiteAdapter,
|
|
24
|
+
BaseAdapter,
|
|
25
|
+
} from './adapters/index.js';
|
|
26
|
+
|
|
27
|
+
// Drizzle ORM (exclude duplicate types already exported from types.js)
|
|
28
|
+
export {
|
|
29
|
+
// Drizzle factories
|
|
30
|
+
createPgDrizzle,
|
|
31
|
+
createSqliteDrizzle,
|
|
32
|
+
isPgDrizzle,
|
|
33
|
+
isSqliteDrizzle,
|
|
34
|
+
// Types
|
|
35
|
+
type DrizzlePgInstance,
|
|
36
|
+
type DrizzleSqliteInstance,
|
|
37
|
+
type DrizzleInstance,
|
|
38
|
+
// Conversations
|
|
39
|
+
conversationsPg,
|
|
40
|
+
messagesPg,
|
|
41
|
+
conversationsSqlite,
|
|
42
|
+
messagesSqlite,
|
|
43
|
+
type ConversationPg,
|
|
44
|
+
type NewConversationPg,
|
|
45
|
+
type MessagePg,
|
|
46
|
+
type NewMessagePg,
|
|
47
|
+
type ConversationSqlite,
|
|
48
|
+
type NewConversationSqlite,
|
|
49
|
+
type MessageSqlite,
|
|
50
|
+
type NewMessageSqlite,
|
|
51
|
+
type Conversation,
|
|
52
|
+
type NewConversation,
|
|
53
|
+
type Message,
|
|
54
|
+
type NewMessage,
|
|
55
|
+
// Long-term memories (excluding MemoryType - already in types.js)
|
|
56
|
+
longTermMemoriesPg,
|
|
57
|
+
longTermMemoriesSqlite,
|
|
58
|
+
type LongTermMemoryPg,
|
|
59
|
+
type NewLongTermMemoryPg,
|
|
60
|
+
type LongTermMemorySqlite,
|
|
61
|
+
type NewLongTermMemorySqlite,
|
|
62
|
+
type LongTermMemory,
|
|
63
|
+
type NewLongTermMemory,
|
|
64
|
+
type ParsedMemory,
|
|
65
|
+
// Documents
|
|
66
|
+
documentsPg,
|
|
67
|
+
documentChunksPg,
|
|
68
|
+
documentsSqlite,
|
|
69
|
+
documentChunksSqlite,
|
|
70
|
+
type DocumentPg,
|
|
71
|
+
type NewDocumentPg,
|
|
72
|
+
type DocumentChunkPg,
|
|
73
|
+
type NewDocumentChunkPg,
|
|
74
|
+
type DocumentSqlite,
|
|
75
|
+
type NewDocumentSqlite,
|
|
76
|
+
type DocumentChunkSqlite,
|
|
77
|
+
type NewDocumentChunkSqlite,
|
|
78
|
+
type Document,
|
|
79
|
+
type NewDocument,
|
|
80
|
+
type DocumentChunk,
|
|
81
|
+
type NewDocumentChunk,
|
|
82
|
+
type ParsedDocumentChunk,
|
|
83
|
+
// Checkpoints
|
|
84
|
+
checkpointsPg,
|
|
85
|
+
checkpointWritesPg,
|
|
86
|
+
checkpointsSqlite,
|
|
87
|
+
checkpointWritesSqlite,
|
|
88
|
+
type CheckpointPg,
|
|
89
|
+
type NewCheckpointPg,
|
|
90
|
+
type CheckpointWritePg,
|
|
91
|
+
type NewCheckpointWritePg,
|
|
92
|
+
type CheckpointSqlite,
|
|
93
|
+
type NewCheckpointSqlite,
|
|
94
|
+
type CheckpointWriteSqlite,
|
|
95
|
+
type NewCheckpointWriteSqlite,
|
|
96
|
+
type Checkpoint,
|
|
97
|
+
type NewCheckpoint,
|
|
98
|
+
type CheckpointWrite,
|
|
99
|
+
type NewCheckpointWrite,
|
|
100
|
+
// Audit logs (excluding AuditActionType - already in types.js)
|
|
101
|
+
auditLogsPg,
|
|
102
|
+
auditLogsSqlite,
|
|
103
|
+
type AuditLogPg,
|
|
104
|
+
type NewAuditLogPg,
|
|
105
|
+
type AuditLogSqlite,
|
|
106
|
+
type NewAuditLogSqlite,
|
|
107
|
+
type AuditLog,
|
|
108
|
+
type NewAuditLog,
|
|
109
|
+
type AuditStatus,
|
|
110
|
+
// Tasks (excluding TaskStatus - already in types.js)
|
|
111
|
+
tasksPg,
|
|
112
|
+
tasksSqlite,
|
|
113
|
+
type TaskPg,
|
|
114
|
+
type NewTaskPg,
|
|
115
|
+
type TaskSqlite,
|
|
116
|
+
type NewTaskSqlite,
|
|
117
|
+
type Task,
|
|
118
|
+
type NewTask,
|
|
119
|
+
TaskPriority,
|
|
120
|
+
type TaskPriorityLevel,
|
|
121
|
+
// Schema helpers
|
|
122
|
+
pgSchema,
|
|
123
|
+
sqliteSchema,
|
|
124
|
+
} from './drizzle/index.js';
|
|
125
|
+
|
|
126
|
+
// Vector search
|
|
127
|
+
export {
|
|
128
|
+
HNSWIndex,
|
|
129
|
+
EmbeddingCache,
|
|
130
|
+
PgVectorSearchEngine,
|
|
131
|
+
SqliteVectorSearchEngine,
|
|
132
|
+
createVectorSearchEngine,
|
|
133
|
+
cosineSimilarity,
|
|
134
|
+
euclideanDistance,
|
|
135
|
+
parseEmbedding,
|
|
136
|
+
serializeEmbedding,
|
|
137
|
+
} from './vector/index.js';
|
|
138
|
+
|
|
139
|
+
// Migrations
|
|
140
|
+
export { Migrator, createMigrator, runMigrations, getCurrentVersion, allMigrations } from './migrations/index.js';
|
|
141
|
+
|
|
142
|
+
// Health monitoring
|
|
143
|
+
export { CircuitBreaker, CircuitOpenError, HealthMonitor, createHealthSystem } from './health/index.js';
|
|
144
|
+
|
|
145
|
+
// Caching
|
|
146
|
+
export { QueryCache, getQueryCache, resetQueryCache, cacheKeys, invalidationPatterns } from './cache/index.js';
|
|
147
|
+
|
|
148
|
+
// Re-export client functions for backward compatibility
|
|
149
|
+
export {
|
|
150
|
+
initDatabase,
|
|
151
|
+
closePool,
|
|
152
|
+
query,
|
|
153
|
+
transaction,
|
|
154
|
+
getClient,
|
|
155
|
+
healthCheck,
|
|
156
|
+
getPool,
|
|
157
|
+
} from './client.js';
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration System Exports
|
|
3
|
+
*
|
|
4
|
+
* Central export for the database migration system.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export { Migrator } from './migrator.js';
|
|
8
|
+
export { migration001Initial } from './versions/001_initial.js';
|
|
9
|
+
|
|
10
|
+
import { Migrator } from './migrator.js';
|
|
11
|
+
import { migration001Initial } from './versions/001_initial.js';
|
|
12
|
+
import type { DatabaseAdapter, Migration } from '../types.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* All registered migrations in order
|
|
16
|
+
*/
|
|
17
|
+
export const allMigrations: Migration[] = [
|
|
18
|
+
migration001Initial,
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Create and configure a migrator with all registered migrations
|
|
23
|
+
*/
|
|
24
|
+
export function createMigrator(adapter: DatabaseAdapter): Migrator {
|
|
25
|
+
const migrator = new Migrator(adapter);
|
|
26
|
+
migrator.registerAll(allMigrations);
|
|
27
|
+
return migrator;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Run all pending migrations
|
|
32
|
+
*/
|
|
33
|
+
export async function runMigrations(adapter: DatabaseAdapter) {
|
|
34
|
+
const migrator = createMigrator(adapter);
|
|
35
|
+
return migrator.migrate();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get current schema version
|
|
40
|
+
*/
|
|
41
|
+
export async function getCurrentVersion(adapter: DatabaseAdapter): Promise<number> {
|
|
42
|
+
const migrator = createMigrator(adapter);
|
|
43
|
+
return migrator.getCurrentVersion();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export default {
|
|
47
|
+
Migrator,
|
|
48
|
+
allMigrations,
|
|
49
|
+
createMigrator,
|
|
50
|
+
runMigrations,
|
|
51
|
+
getCurrentVersion,
|
|
52
|
+
};
|