@gotza02/smartagent 1.2.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/LICENSE +21 -0
- package/README.md +422 -0
- package/dist/config/index.d.ts +72 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +329 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/agent-manager.d.ts +116 -0
- package/dist/core/agent-manager.d.ts.map +1 -0
- package/dist/core/agent-manager.js +460 -0
- package/dist/core/agent-manager.js.map +1 -0
- package/dist/core/context-manager.d.ts +107 -0
- package/dist/core/context-manager.d.ts.map +1 -0
- package/dist/core/context-manager.js +467 -0
- package/dist/core/context-manager.js.map +1 -0
- package/dist/core/database.d.ts +82 -0
- package/dist/core/database.d.ts.map +1 -0
- package/dist/core/database.js +751 -0
- package/dist/core/database.js.map +1 -0
- package/dist/core/event-emitter.d.ts +110 -0
- package/dist/core/event-emitter.d.ts.map +1 -0
- package/dist/core/event-emitter.js +240 -0
- package/dist/core/event-emitter.js.map +1 -0
- package/dist/core/metrics.d.ts +108 -0
- package/dist/core/metrics.d.ts.map +1 -0
- package/dist/core/metrics.js +281 -0
- package/dist/core/metrics.js.map +1 -0
- package/dist/core/middleware.d.ts +63 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +194 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/plugin-system.d.ts +86 -0
- package/dist/core/plugin-system.d.ts.map +1 -0
- package/dist/core/plugin-system.js +251 -0
- package/dist/core/plugin-system.js.map +1 -0
- package/dist/core/task-scheduler.d.ts +130 -0
- package/dist/core/task-scheduler.d.ts.map +1 -0
- package/dist/core/task-scheduler.js +401 -0
- package/dist/core/task-scheduler.js.map +1 -0
- package/dist/engines/auto-router.d.ts +76 -0
- package/dist/engines/auto-router.d.ts.map +1 -0
- package/dist/engines/auto-router.js +445 -0
- package/dist/engines/auto-router.js.map +1 -0
- package/dist/engines/parallel-execution.d.ts +104 -0
- package/dist/engines/parallel-execution.d.ts.map +1 -0
- package/dist/engines/parallel-execution.js +591 -0
- package/dist/engines/parallel-execution.js.map +1 -0
- package/dist/engines/sequential-thinking.d.ts +88 -0
- package/dist/engines/sequential-thinking.d.ts.map +1 -0
- package/dist/engines/sequential-thinking.js +406 -0
- package/dist/engines/sequential-thinking.js.map +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1101 -0
- package/dist/index.js.map +1 -0
- package/dist/security/validation.d.ts +87 -0
- package/dist/security/validation.d.ts.map +1 -0
- package/dist/security/validation.js +465 -0
- package/dist/security/validation.js.map +1 -0
- package/dist/tools/filesystem.d.ts +90 -0
- package/dist/tools/filesystem.d.ts.map +1 -0
- package/dist/tools/filesystem.js +292 -0
- package/dist/tools/filesystem.js.map +1 -0
- package/dist/tools/terminal.d.ts +99 -0
- package/dist/tools/terminal.d.ts.map +1 -0
- package/dist/tools/terminal.js +363 -0
- package/dist/tools/terminal.js.map +1 -0
- package/dist/types/index.d.ts +306 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +54 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/logger.d.ts +22 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +189 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +71 -0
|
@@ -0,0 +1,751 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Database Manager
|
|
3
|
+
* SQLite/libSQL database operations for context persistence
|
|
4
|
+
*/
|
|
5
|
+
import { createClient } from "@libsql/client";
|
|
6
|
+
import { homedir } from "os";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { mkdirSync, existsSync } from "fs";
|
|
9
|
+
import { randomUUID } from "crypto";
|
|
10
|
+
import { logger } from "../utils/logger.js";
|
|
11
|
+
const SWARM_DIR = join(homedir(), ".swarm-mcp-enterprise");
|
|
12
|
+
const DB_PATH = `file:${join(SWARM_DIR, "swarm.db")}`;
|
|
13
|
+
/**
|
|
14
|
+
* Database Manager
|
|
15
|
+
* Handles all database operations
|
|
16
|
+
*/
|
|
17
|
+
export class DatabaseManager {
|
|
18
|
+
client = null;
|
|
19
|
+
initialized = false;
|
|
20
|
+
/**
|
|
21
|
+
* Initialize database connection and schema
|
|
22
|
+
*/
|
|
23
|
+
async initialize() {
|
|
24
|
+
if (this.initialized)
|
|
25
|
+
return;
|
|
26
|
+
// Create directory if not exists
|
|
27
|
+
if (!existsSync(SWARM_DIR)) {
|
|
28
|
+
mkdirSync(SWARM_DIR, { recursive: true });
|
|
29
|
+
}
|
|
30
|
+
// Create client
|
|
31
|
+
this.client = createClient({ url: DB_PATH });
|
|
32
|
+
// Create tables
|
|
33
|
+
await this.createSchema();
|
|
34
|
+
this.initialized = true;
|
|
35
|
+
// logger.info("Database initialized", { path: DB_PATH });
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Create database schema
|
|
39
|
+
*/
|
|
40
|
+
async createSchema() {
|
|
41
|
+
if (!this.client)
|
|
42
|
+
throw new Error("Database not initialized");
|
|
43
|
+
// Agents table
|
|
44
|
+
await this.client.execute(`
|
|
45
|
+
CREATE TABLE IF NOT EXISTS agents (
|
|
46
|
+
id TEXT PRIMARY KEY,
|
|
47
|
+
type TEXT NOT NULL,
|
|
48
|
+
name TEXT NOT NULL,
|
|
49
|
+
mode TEXT DEFAULT 'plan',
|
|
50
|
+
status TEXT DEFAULT 'idle',
|
|
51
|
+
current_task TEXT,
|
|
52
|
+
capabilities TEXT,
|
|
53
|
+
metadata TEXT,
|
|
54
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
55
|
+
last_active_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
56
|
+
health_check_at TEXT
|
|
57
|
+
)
|
|
58
|
+
`);
|
|
59
|
+
// Tasks table
|
|
60
|
+
await this.client.execute(`
|
|
61
|
+
CREATE TABLE IF NOT EXISTS tasks (
|
|
62
|
+
id TEXT PRIMARY KEY,
|
|
63
|
+
agent_id TEXT NOT NULL,
|
|
64
|
+
type TEXT NOT NULL,
|
|
65
|
+
description TEXT NOT NULL,
|
|
66
|
+
context TEXT,
|
|
67
|
+
status TEXT DEFAULT 'pending',
|
|
68
|
+
priority INTEGER DEFAULT 5,
|
|
69
|
+
result TEXT,
|
|
70
|
+
error TEXT,
|
|
71
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
72
|
+
started_at TEXT,
|
|
73
|
+
completed_at TEXT,
|
|
74
|
+
timeout INTEGER DEFAULT 60,
|
|
75
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id)
|
|
76
|
+
)
|
|
77
|
+
`);
|
|
78
|
+
// Thought chains table
|
|
79
|
+
await this.client.execute(`
|
|
80
|
+
CREATE TABLE IF NOT EXISTS thought_chains (
|
|
81
|
+
id TEXT PRIMARY KEY,
|
|
82
|
+
agent_id TEXT NOT NULL,
|
|
83
|
+
task_id TEXT NOT NULL,
|
|
84
|
+
title TEXT NOT NULL,
|
|
85
|
+
thoughts TEXT,
|
|
86
|
+
branches TEXT,
|
|
87
|
+
current_step INTEGER DEFAULT 0,
|
|
88
|
+
status TEXT DEFAULT 'active',
|
|
89
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
90
|
+
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
91
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id),
|
|
92
|
+
FOREIGN KEY (task_id) REFERENCES tasks(id)
|
|
93
|
+
)
|
|
94
|
+
`);
|
|
95
|
+
// Contexts table
|
|
96
|
+
await this.client.execute(`
|
|
97
|
+
CREATE TABLE IF NOT EXISTS contexts (
|
|
98
|
+
id TEXT PRIMARY KEY,
|
|
99
|
+
agent_id TEXT NOT NULL,
|
|
100
|
+
messages TEXT,
|
|
101
|
+
artifacts TEXT,
|
|
102
|
+
checkpoints TEXT,
|
|
103
|
+
summary TEXT,
|
|
104
|
+
token_count INTEGER DEFAULT 0,
|
|
105
|
+
max_tokens INTEGER DEFAULT 4000,
|
|
106
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
107
|
+
updated_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
108
|
+
FOREIGN KEY (agent_id) REFERENCES agents(id)
|
|
109
|
+
)
|
|
110
|
+
`);
|
|
111
|
+
// Handoffs table
|
|
112
|
+
await this.client.execute(`
|
|
113
|
+
CREATE TABLE IF NOT EXISTS handoffs (
|
|
114
|
+
id TEXT PRIMARY KEY,
|
|
115
|
+
from_agent_id TEXT NOT NULL,
|
|
116
|
+
to_agent_id TEXT NOT NULL,
|
|
117
|
+
task_id TEXT NOT NULL,
|
|
118
|
+
context_snapshot TEXT,
|
|
119
|
+
notes TEXT,
|
|
120
|
+
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
121
|
+
FOREIGN KEY (from_agent_id) REFERENCES agents(id),
|
|
122
|
+
FOREIGN KEY (to_agent_id) REFERENCES agents(id),
|
|
123
|
+
FOREIGN KEY (task_id) REFERENCES tasks(id)
|
|
124
|
+
)
|
|
125
|
+
`);
|
|
126
|
+
// Checkpoints table
|
|
127
|
+
await this.client.execute(`
|
|
128
|
+
CREATE TABLE IF NOT EXISTS checkpoints (
|
|
129
|
+
id TEXT PRIMARY KEY,
|
|
130
|
+
context_id TEXT NOT NULL,
|
|
131
|
+
sequence INTEGER NOT NULL,
|
|
132
|
+
messages TEXT,
|
|
133
|
+
artifacts TEXT,
|
|
134
|
+
thought_chain_id TEXT,
|
|
135
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
136
|
+
FOREIGN KEY (context_id) REFERENCES contexts(id),
|
|
137
|
+
FOREIGN KEY (thought_chain_id) REFERENCES thought_chains(id)
|
|
138
|
+
)
|
|
139
|
+
`);
|
|
140
|
+
// Audit logs table
|
|
141
|
+
await this.client.execute(`
|
|
142
|
+
CREATE TABLE IF NOT EXISTS audit_logs (
|
|
143
|
+
id TEXT PRIMARY KEY,
|
|
144
|
+
timestamp TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
145
|
+
level TEXT NOT NULL,
|
|
146
|
+
category TEXT NOT NULL,
|
|
147
|
+
agent_id TEXT,
|
|
148
|
+
task_id TEXT,
|
|
149
|
+
action TEXT NOT NULL,
|
|
150
|
+
details TEXT,
|
|
151
|
+
ip TEXT,
|
|
152
|
+
user_agent TEXT
|
|
153
|
+
)
|
|
154
|
+
`);
|
|
155
|
+
// Parallel executions table
|
|
156
|
+
await this.client.execute(`
|
|
157
|
+
CREATE TABLE IF NOT EXISTS parallel_executions (
|
|
158
|
+
id TEXT PRIMARY KEY,
|
|
159
|
+
batch_id TEXT NOT NULL,
|
|
160
|
+
tasks TEXT,
|
|
161
|
+
max_concurrency INTEGER DEFAULT 5,
|
|
162
|
+
status TEXT DEFAULT 'pending',
|
|
163
|
+
results TEXT,
|
|
164
|
+
aggregated_report TEXT,
|
|
165
|
+
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
|
|
166
|
+
completed_at TEXT
|
|
167
|
+
)
|
|
168
|
+
`);
|
|
169
|
+
// Create indexes
|
|
170
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status)`);
|
|
171
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_agents_type ON agents(type)`);
|
|
172
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_tasks_agent_id ON tasks(agent_id)`);
|
|
173
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_tasks_status ON tasks(status)`);
|
|
174
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_thought_chains_agent ON thought_chains(agent_id)`);
|
|
175
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_contexts_agent ON contexts(agent_id)`);
|
|
176
|
+
await this.client.execute(`CREATE INDEX IF NOT EXISTS idx_audit_timestamp ON audit_logs(timestamp)`);
|
|
177
|
+
}
|
|
178
|
+
// ============================================
|
|
179
|
+
// Agent Operations
|
|
180
|
+
// ============================================
|
|
181
|
+
async saveAgent(agent) {
|
|
182
|
+
if (!this.client)
|
|
183
|
+
throw new Error("Database not initialized");
|
|
184
|
+
await this.client.execute({
|
|
185
|
+
sql: `
|
|
186
|
+
INSERT OR REPLACE INTO agents
|
|
187
|
+
(id, type, name, mode, status, current_task, capabilities, metadata, created_at, last_active_at, health_check_at)
|
|
188
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
189
|
+
`,
|
|
190
|
+
args: [
|
|
191
|
+
agent.id,
|
|
192
|
+
agent.type,
|
|
193
|
+
agent.name,
|
|
194
|
+
agent.mode,
|
|
195
|
+
agent.status,
|
|
196
|
+
agent.currentTask || null,
|
|
197
|
+
JSON.stringify(agent.capabilities),
|
|
198
|
+
JSON.stringify(agent.metadata),
|
|
199
|
+
agent.createdAt,
|
|
200
|
+
agent.lastActiveAt,
|
|
201
|
+
agent.healthCheckAt || null,
|
|
202
|
+
],
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
async getAgent(agentId) {
|
|
206
|
+
if (!this.client)
|
|
207
|
+
throw new Error("Database not initialized");
|
|
208
|
+
const result = await this.client.execute({
|
|
209
|
+
sql: "SELECT * FROM agents WHERE id = ?",
|
|
210
|
+
args: [agentId],
|
|
211
|
+
});
|
|
212
|
+
if (result.rows.length === 0)
|
|
213
|
+
return null;
|
|
214
|
+
const row = result.rows[0];
|
|
215
|
+
return this.rowToAgent(row);
|
|
216
|
+
}
|
|
217
|
+
async getAllAgents() {
|
|
218
|
+
if (!this.client)
|
|
219
|
+
throw new Error("Database not initialized");
|
|
220
|
+
const result = await this.client.execute("SELECT * FROM agents");
|
|
221
|
+
return result.rows.map((row) => this.rowToAgent(row));
|
|
222
|
+
}
|
|
223
|
+
async getAgentsByType(type) {
|
|
224
|
+
if (!this.client)
|
|
225
|
+
throw new Error("Database not initialized");
|
|
226
|
+
const result = await this.client.execute({
|
|
227
|
+
sql: "SELECT * FROM agents WHERE type = ?",
|
|
228
|
+
args: [type],
|
|
229
|
+
});
|
|
230
|
+
return result.rows.map((row) => this.rowToAgent(row));
|
|
231
|
+
}
|
|
232
|
+
async getAgentsByStatus(status) {
|
|
233
|
+
if (!this.client)
|
|
234
|
+
throw new Error("Database not initialized");
|
|
235
|
+
const result = await this.client.execute({
|
|
236
|
+
sql: "SELECT * FROM agents WHERE status = ?",
|
|
237
|
+
args: [status],
|
|
238
|
+
});
|
|
239
|
+
return result.rows.map((row) => this.rowToAgent(row));
|
|
240
|
+
}
|
|
241
|
+
async deleteAgent(agentId) {
|
|
242
|
+
if (!this.client)
|
|
243
|
+
throw new Error("Database not initialized");
|
|
244
|
+
const result = await this.client.execute({
|
|
245
|
+
sql: "DELETE FROM agents WHERE id = ?",
|
|
246
|
+
args: [agentId],
|
|
247
|
+
});
|
|
248
|
+
return result.rowsAffected > 0;
|
|
249
|
+
}
|
|
250
|
+
// ============================================
|
|
251
|
+
// Task Operations
|
|
252
|
+
// ============================================
|
|
253
|
+
async saveTask(task) {
|
|
254
|
+
if (!this.client)
|
|
255
|
+
throw new Error("Database not initialized");
|
|
256
|
+
await this.client.execute({
|
|
257
|
+
sql: `
|
|
258
|
+
INSERT OR REPLACE INTO tasks
|
|
259
|
+
(id, agent_id, type, description, context, status, priority, result, error, created_at, started_at, completed_at, timeout)
|
|
260
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
261
|
+
`,
|
|
262
|
+
args: [
|
|
263
|
+
task.id,
|
|
264
|
+
task.agentId,
|
|
265
|
+
task.type,
|
|
266
|
+
task.description,
|
|
267
|
+
JSON.stringify(task.context),
|
|
268
|
+
task.status,
|
|
269
|
+
task.priority,
|
|
270
|
+
task.result ? JSON.stringify(task.result) : null,
|
|
271
|
+
task.error || null,
|
|
272
|
+
task.createdAt,
|
|
273
|
+
task.startedAt || null,
|
|
274
|
+
task.completedAt || null,
|
|
275
|
+
task.timeout,
|
|
276
|
+
],
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
async getTask(taskId) {
|
|
280
|
+
if (!this.client)
|
|
281
|
+
throw new Error("Database not initialized");
|
|
282
|
+
const result = await this.client.execute({
|
|
283
|
+
sql: "SELECT * FROM tasks WHERE id = ?",
|
|
284
|
+
args: [taskId],
|
|
285
|
+
});
|
|
286
|
+
if (result.rows.length === 0)
|
|
287
|
+
return null;
|
|
288
|
+
return this.rowToTask(result.rows[0]);
|
|
289
|
+
}
|
|
290
|
+
async getTasksByAgent(agentId) {
|
|
291
|
+
if (!this.client)
|
|
292
|
+
throw new Error("Database not initialized");
|
|
293
|
+
const result = await this.client.execute({
|
|
294
|
+
sql: "SELECT * FROM tasks WHERE agent_id = ? ORDER BY created_at DESC",
|
|
295
|
+
args: [agentId],
|
|
296
|
+
});
|
|
297
|
+
return result.rows.map((row) => this.rowToTask(row));
|
|
298
|
+
}
|
|
299
|
+
async getTasksByStatus(status) {
|
|
300
|
+
if (!this.client)
|
|
301
|
+
throw new Error("Database not initialized");
|
|
302
|
+
const result = await this.client.execute({
|
|
303
|
+
sql: "SELECT * FROM tasks WHERE status = ?",
|
|
304
|
+
args: [status],
|
|
305
|
+
});
|
|
306
|
+
return result.rows.map((row) => this.rowToTask(row));
|
|
307
|
+
}
|
|
308
|
+
// ============================================
|
|
309
|
+
// Context Operations
|
|
310
|
+
// ============================================
|
|
311
|
+
async saveContext(context) {
|
|
312
|
+
if (!this.client)
|
|
313
|
+
throw new Error("Database not initialized");
|
|
314
|
+
await this.client.execute({
|
|
315
|
+
sql: `
|
|
316
|
+
INSERT OR REPLACE INTO contexts
|
|
317
|
+
(id, agent_id, messages, artifacts, checkpoints, summary, token_count, max_tokens, created_at, updated_at)
|
|
318
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
319
|
+
`,
|
|
320
|
+
args: [
|
|
321
|
+
context.id,
|
|
322
|
+
context.agentId,
|
|
323
|
+
JSON.stringify(context.messages),
|
|
324
|
+
JSON.stringify(context.artifacts),
|
|
325
|
+
JSON.stringify(context.checkpoints),
|
|
326
|
+
context.summary || null,
|
|
327
|
+
context.tokenCount,
|
|
328
|
+
context.maxTokens,
|
|
329
|
+
context.createdAt,
|
|
330
|
+
context.updatedAt,
|
|
331
|
+
],
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
async getContext(contextId) {
|
|
335
|
+
if (!this.client)
|
|
336
|
+
throw new Error("Database not initialized");
|
|
337
|
+
const result = await this.client.execute({
|
|
338
|
+
sql: "SELECT * FROM contexts WHERE id = ?",
|
|
339
|
+
args: [contextId],
|
|
340
|
+
});
|
|
341
|
+
if (result.rows.length === 0)
|
|
342
|
+
return null;
|
|
343
|
+
return this.rowToContext(result.rows[0]);
|
|
344
|
+
}
|
|
345
|
+
async getContextByAgent(agentId) {
|
|
346
|
+
if (!this.client)
|
|
347
|
+
throw new Error("Database not initialized");
|
|
348
|
+
const result = await this.client.execute({
|
|
349
|
+
sql: "SELECT * FROM contexts WHERE agent_id = ? ORDER BY updated_at DESC LIMIT 1",
|
|
350
|
+
args: [agentId],
|
|
351
|
+
});
|
|
352
|
+
if (result.rows.length === 0)
|
|
353
|
+
return null;
|
|
354
|
+
return this.rowToContext(result.rows[0]);
|
|
355
|
+
}
|
|
356
|
+
// ============================================
|
|
357
|
+
// Checkpoint Operations
|
|
358
|
+
// ============================================
|
|
359
|
+
async saveCheckpoint(checkpoint) {
|
|
360
|
+
if (!this.client)
|
|
361
|
+
throw new Error("Database not initialized");
|
|
362
|
+
await this.client.execute({
|
|
363
|
+
sql: `
|
|
364
|
+
INSERT OR REPLACE INTO checkpoints
|
|
365
|
+
(id, context_id, sequence, messages, artifacts, thought_chain_id, created_at)
|
|
366
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
367
|
+
`,
|
|
368
|
+
args: [
|
|
369
|
+
checkpoint.id,
|
|
370
|
+
checkpoint.contextId,
|
|
371
|
+
checkpoint.sequence,
|
|
372
|
+
JSON.stringify(checkpoint.messages),
|
|
373
|
+
JSON.stringify(checkpoint.artifacts),
|
|
374
|
+
checkpoint.thoughtChainId || null,
|
|
375
|
+
checkpoint.createdAt,
|
|
376
|
+
],
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
async getCheckpointsByContext(contextId) {
|
|
380
|
+
if (!this.client)
|
|
381
|
+
throw new Error("Database not initialized");
|
|
382
|
+
const result = await this.client.execute({
|
|
383
|
+
sql: "SELECT * FROM checkpoints WHERE context_id = ? ORDER BY sequence ASC",
|
|
384
|
+
args: [contextId],
|
|
385
|
+
});
|
|
386
|
+
return result.rows.map((row) => this.rowToCheckpoint(row));
|
|
387
|
+
}
|
|
388
|
+
// ============================================
|
|
389
|
+
// Handoff Operations
|
|
390
|
+
// ============================================
|
|
391
|
+
async saveHandoff(handoff) {
|
|
392
|
+
if (!this.client)
|
|
393
|
+
throw new Error("Database not initialized");
|
|
394
|
+
await this.client.execute({
|
|
395
|
+
sql: `
|
|
396
|
+
INSERT OR REPLACE INTO handoffs
|
|
397
|
+
(id, from_agent_id, to_agent_id, task_id, context_snapshot, notes, timestamp)
|
|
398
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
399
|
+
`,
|
|
400
|
+
args: [
|
|
401
|
+
handoff.id,
|
|
402
|
+
handoff.fromAgentId,
|
|
403
|
+
handoff.toAgentId,
|
|
404
|
+
handoff.taskId,
|
|
405
|
+
JSON.stringify(handoff.contextSnapshot),
|
|
406
|
+
handoff.notes || null,
|
|
407
|
+
handoff.timestamp,
|
|
408
|
+
],
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
async getHandoffsByAgent(agentId) {
|
|
412
|
+
if (!this.client)
|
|
413
|
+
throw new Error("Database not initialized");
|
|
414
|
+
const result = await this.client.execute({
|
|
415
|
+
sql: `
|
|
416
|
+
SELECT * FROM handoffs
|
|
417
|
+
WHERE from_agent_id = ? OR to_agent_id = ?
|
|
418
|
+
ORDER BY timestamp DESC
|
|
419
|
+
`,
|
|
420
|
+
args: [agentId, agentId],
|
|
421
|
+
});
|
|
422
|
+
return result.rows.map((row) => this.rowToHandoff(row));
|
|
423
|
+
}
|
|
424
|
+
// ============================================
|
|
425
|
+
// Audit Log Operations
|
|
426
|
+
// ============================================
|
|
427
|
+
async saveAuditLog(log) {
|
|
428
|
+
if (!this.client)
|
|
429
|
+
throw new Error("Database not initialized");
|
|
430
|
+
await this.client.execute({
|
|
431
|
+
sql: `
|
|
432
|
+
INSERT INTO audit_logs
|
|
433
|
+
(id, timestamp, level, category, agent_id, task_id, action, details)
|
|
434
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
435
|
+
`,
|
|
436
|
+
args: [
|
|
437
|
+
randomUUID(),
|
|
438
|
+
new Date().toISOString(),
|
|
439
|
+
log.level,
|
|
440
|
+
log.category,
|
|
441
|
+
log.agentId || null,
|
|
442
|
+
log.taskId || null,
|
|
443
|
+
log.action,
|
|
444
|
+
log.details ? JSON.stringify(log.details) : null,
|
|
445
|
+
],
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
async getAuditLogs(options = {}) {
|
|
449
|
+
if (!this.client)
|
|
450
|
+
throw new Error("Database not initialized");
|
|
451
|
+
let sql = "SELECT * FROM audit_logs WHERE 1=1";
|
|
452
|
+
const args = [];
|
|
453
|
+
if (options.level) {
|
|
454
|
+
sql += " AND level = ?";
|
|
455
|
+
args.push(options.level);
|
|
456
|
+
}
|
|
457
|
+
if (options.category) {
|
|
458
|
+
sql += " AND category = ?";
|
|
459
|
+
args.push(options.category);
|
|
460
|
+
}
|
|
461
|
+
if (options.agentId) {
|
|
462
|
+
sql += " AND agent_id = ?";
|
|
463
|
+
args.push(options.agentId);
|
|
464
|
+
}
|
|
465
|
+
if (options.since) {
|
|
466
|
+
sql += " AND timestamp > ?";
|
|
467
|
+
args.push(options.since.toISOString());
|
|
468
|
+
}
|
|
469
|
+
sql += " ORDER BY timestamp DESC";
|
|
470
|
+
if (options.limit) {
|
|
471
|
+
sql += " LIMIT ?";
|
|
472
|
+
args.push(options.limit);
|
|
473
|
+
}
|
|
474
|
+
const result = await this.client.execute({ sql, args: args });
|
|
475
|
+
return result.rows;
|
|
476
|
+
}
|
|
477
|
+
// ============================================
|
|
478
|
+
// Thought Chain Operations
|
|
479
|
+
// ============================================
|
|
480
|
+
async saveThoughtChain(chain) {
|
|
481
|
+
if (!this.client)
|
|
482
|
+
throw new Error("Database not initialized");
|
|
483
|
+
const branchesObj = {};
|
|
484
|
+
for (const [key, value] of chain.branches.entries()) {
|
|
485
|
+
branchesObj[key] = value;
|
|
486
|
+
}
|
|
487
|
+
await this.client.execute({
|
|
488
|
+
sql: `
|
|
489
|
+
INSERT OR REPLACE INTO thought_chains
|
|
490
|
+
(id, agent_id, task_id, title, thoughts, branches, current_step, status, created_at, updated_at)
|
|
491
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
492
|
+
`,
|
|
493
|
+
args: [
|
|
494
|
+
chain.id,
|
|
495
|
+
chain.agentId,
|
|
496
|
+
chain.taskId,
|
|
497
|
+
chain.title,
|
|
498
|
+
JSON.stringify(chain.thoughts),
|
|
499
|
+
JSON.stringify(branchesObj),
|
|
500
|
+
chain.currentStep,
|
|
501
|
+
chain.status,
|
|
502
|
+
chain.createdAt,
|
|
503
|
+
chain.updatedAt,
|
|
504
|
+
],
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
async getThoughtChain(chainId) {
|
|
508
|
+
if (!this.client)
|
|
509
|
+
throw new Error("Database not initialized");
|
|
510
|
+
const result = await this.client.execute({
|
|
511
|
+
sql: "SELECT * FROM thought_chains WHERE id = ?",
|
|
512
|
+
args: [chainId],
|
|
513
|
+
});
|
|
514
|
+
if (result.rows.length === 0)
|
|
515
|
+
return null;
|
|
516
|
+
return this.rowToThoughtChain(result.rows[0]);
|
|
517
|
+
}
|
|
518
|
+
async getThoughtChainsByAgent(agentId) {
|
|
519
|
+
if (!this.client)
|
|
520
|
+
throw new Error("Database not initialized");
|
|
521
|
+
const result = await this.client.execute({
|
|
522
|
+
sql: "SELECT * FROM thought_chains WHERE agent_id = ? ORDER BY updated_at DESC",
|
|
523
|
+
args: [agentId],
|
|
524
|
+
});
|
|
525
|
+
return result.rows.map((row) => this.rowToThoughtChain(row));
|
|
526
|
+
}
|
|
527
|
+
// ============================================
|
|
528
|
+
// Parallel Execution Operations
|
|
529
|
+
// ============================================
|
|
530
|
+
async saveParallelExecution(execution) {
|
|
531
|
+
if (!this.client)
|
|
532
|
+
throw new Error("Database not initialized");
|
|
533
|
+
const resultsObj = {};
|
|
534
|
+
for (const [key, value] of execution.results.entries()) {
|
|
535
|
+
resultsObj[key] = value;
|
|
536
|
+
}
|
|
537
|
+
await this.client.execute({
|
|
538
|
+
sql: `
|
|
539
|
+
INSERT OR REPLACE INTO parallel_executions
|
|
540
|
+
(id, batch_id, tasks, max_concurrency, status, results, aggregated_report, created_at, completed_at)
|
|
541
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
542
|
+
`,
|
|
543
|
+
args: [
|
|
544
|
+
execution.id,
|
|
545
|
+
execution.batchId,
|
|
546
|
+
JSON.stringify(execution.tasks),
|
|
547
|
+
execution.maxConcurrency,
|
|
548
|
+
execution.status,
|
|
549
|
+
JSON.stringify(resultsObj),
|
|
550
|
+
execution.aggregatedReport || null,
|
|
551
|
+
execution.createdAt,
|
|
552
|
+
execution.completedAt || null,
|
|
553
|
+
],
|
|
554
|
+
});
|
|
555
|
+
}
|
|
556
|
+
async getParallelExecution(executionId) {
|
|
557
|
+
if (!this.client)
|
|
558
|
+
throw new Error("Database not initialized");
|
|
559
|
+
const result = await this.client.execute({
|
|
560
|
+
sql: "SELECT * FROM parallel_executions WHERE id = ?",
|
|
561
|
+
args: [executionId],
|
|
562
|
+
});
|
|
563
|
+
if (result.rows.length === 0)
|
|
564
|
+
return null;
|
|
565
|
+
return this.rowToParallelExecution(result.rows[0]);
|
|
566
|
+
}
|
|
567
|
+
// ============================================
|
|
568
|
+
// Statistics
|
|
569
|
+
// ============================================
|
|
570
|
+
async getSystemStats() {
|
|
571
|
+
if (!this.client)
|
|
572
|
+
throw new Error("Database not initialized");
|
|
573
|
+
const [totalAgents, agentsByStatus, agentsByType, totalTasks, tasksByStatus, totalContexts, totalCheckpoints, totalHandoffs,] = await Promise.all([
|
|
574
|
+
this.client.execute("SELECT COUNT(*) as count FROM agents"),
|
|
575
|
+
this.client.execute("SELECT status, COUNT(*) as count FROM agents GROUP BY status"),
|
|
576
|
+
this.client.execute("SELECT type, COUNT(*) as count FROM agents GROUP BY type"),
|
|
577
|
+
this.client.execute("SELECT COUNT(*) as count FROM tasks"),
|
|
578
|
+
this.client.execute("SELECT status, COUNT(*) as count FROM tasks GROUP BY status"),
|
|
579
|
+
this.client.execute("SELECT COUNT(*) as count FROM contexts"),
|
|
580
|
+
this.client.execute("SELECT COUNT(*) as count FROM checkpoints"),
|
|
581
|
+
this.client.execute("SELECT COUNT(*) as count FROM handoffs"),
|
|
582
|
+
]);
|
|
583
|
+
return {
|
|
584
|
+
totalAgents: totalAgents.rows[0]?.count ?? 0,
|
|
585
|
+
agentsByStatus: Object.fromEntries(agentsByStatus.rows.map((r) => [
|
|
586
|
+
r.status,
|
|
587
|
+
r.count,
|
|
588
|
+
])),
|
|
589
|
+
agentsByType: Object.fromEntries(agentsByType.rows.map((r) => [
|
|
590
|
+
r.type,
|
|
591
|
+
r.count,
|
|
592
|
+
])),
|
|
593
|
+
totalTasks: totalTasks.rows[0]?.count ?? 0,
|
|
594
|
+
tasksByStatus: Object.fromEntries(tasksByStatus.rows.map((r) => [
|
|
595
|
+
r.status,
|
|
596
|
+
r.count,
|
|
597
|
+
])),
|
|
598
|
+
totalContexts: totalContexts.rows[0]?.count ?? 0,
|
|
599
|
+
totalCheckpoints: totalCheckpoints.rows[0]?.count ?? 0,
|
|
600
|
+
totalHandoffs: totalHandoffs.rows[0]?.count ?? 0,
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
// ============================================
|
|
604
|
+
// Safe JSON Parsing
|
|
605
|
+
// ============================================
|
|
606
|
+
safeJsonParse(json, defaultValue) {
|
|
607
|
+
if (!json)
|
|
608
|
+
return defaultValue;
|
|
609
|
+
try {
|
|
610
|
+
return JSON.parse(json);
|
|
611
|
+
}
|
|
612
|
+
catch (error) {
|
|
613
|
+
logger.error("Failed to parse JSON from database", {
|
|
614
|
+
error: error instanceof Error ? error.message : String(error),
|
|
615
|
+
json: json.substring(0, 200),
|
|
616
|
+
});
|
|
617
|
+
return defaultValue;
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
// ============================================
|
|
621
|
+
// Row Converters
|
|
622
|
+
// ============================================
|
|
623
|
+
rowToAgent(row) {
|
|
624
|
+
return {
|
|
625
|
+
id: row.id,
|
|
626
|
+
type: row.type,
|
|
627
|
+
name: row.name,
|
|
628
|
+
mode: row.mode || "plan",
|
|
629
|
+
status: row.status,
|
|
630
|
+
currentTask: row.current_task,
|
|
631
|
+
capabilities: this.safeJsonParse(row.capabilities, []),
|
|
632
|
+
metadata: this.safeJsonParse(row.metadata, {}),
|
|
633
|
+
createdAt: row.created_at,
|
|
634
|
+
lastActiveAt: row.last_active_at,
|
|
635
|
+
healthCheckAt: row.health_check_at,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
rowToTask(row) {
|
|
639
|
+
return {
|
|
640
|
+
id: row.id,
|
|
641
|
+
agentId: row.agent_id,
|
|
642
|
+
type: row.type,
|
|
643
|
+
description: row.description,
|
|
644
|
+
context: this.safeJsonParse(row.context, {}),
|
|
645
|
+
status: row.status,
|
|
646
|
+
priority: row.priority || 5,
|
|
647
|
+
result: row.result ? this.safeJsonParse(row.result, undefined) : undefined,
|
|
648
|
+
error: row.error,
|
|
649
|
+
createdAt: row.created_at,
|
|
650
|
+
startedAt: row.started_at,
|
|
651
|
+
completedAt: row.completed_at,
|
|
652
|
+
timeout: row.timeout || 60,
|
|
653
|
+
};
|
|
654
|
+
}
|
|
655
|
+
rowToContext(row) {
|
|
656
|
+
return {
|
|
657
|
+
id: row.id,
|
|
658
|
+
agentId: row.agent_id,
|
|
659
|
+
messages: this.safeJsonParse(row.messages, []),
|
|
660
|
+
artifacts: this.safeJsonParse(row.artifacts, []),
|
|
661
|
+
checkpoints: this.safeJsonParse(row.checkpoints, []),
|
|
662
|
+
summary: row.summary,
|
|
663
|
+
tokenCount: row.token_count || 0,
|
|
664
|
+
maxTokens: row.max_tokens || 4000,
|
|
665
|
+
createdAt: row.created_at,
|
|
666
|
+
updatedAt: row.updated_at,
|
|
667
|
+
};
|
|
668
|
+
}
|
|
669
|
+
rowToCheckpoint(row) {
|
|
670
|
+
return {
|
|
671
|
+
id: row.id,
|
|
672
|
+
contextId: row.context_id,
|
|
673
|
+
sequence: row.sequence,
|
|
674
|
+
messages: this.safeJsonParse(row.messages, []),
|
|
675
|
+
artifacts: this.safeJsonParse(row.artifacts, []),
|
|
676
|
+
thoughtChainId: row.thought_chain_id,
|
|
677
|
+
createdAt: row.created_at,
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
rowToHandoff(row) {
|
|
681
|
+
return {
|
|
682
|
+
id: row.id,
|
|
683
|
+
fromAgentId: row.from_agent_id,
|
|
684
|
+
toAgentId: row.to_agent_id,
|
|
685
|
+
taskId: row.task_id,
|
|
686
|
+
contextSnapshot: this.safeJsonParse(row.context_snapshot, { messages: [], artifacts: [] }),
|
|
687
|
+
notes: row.notes,
|
|
688
|
+
timestamp: row.timestamp,
|
|
689
|
+
};
|
|
690
|
+
}
|
|
691
|
+
rowToThoughtChain(row) {
|
|
692
|
+
const branchesObj = this.safeJsonParse(row.branches, {});
|
|
693
|
+
const branches = new Map();
|
|
694
|
+
for (const [key, value] of Object.entries(branchesObj)) {
|
|
695
|
+
branches.set(key, value);
|
|
696
|
+
}
|
|
697
|
+
return {
|
|
698
|
+
id: row.id,
|
|
699
|
+
agentId: row.agent_id,
|
|
700
|
+
taskId: row.task_id,
|
|
701
|
+
title: row.title,
|
|
702
|
+
thoughts: this.safeJsonParse(row.thoughts, []),
|
|
703
|
+
branches,
|
|
704
|
+
currentStep: row.current_step || 0,
|
|
705
|
+
status: row.status || "active",
|
|
706
|
+
createdAt: row.created_at,
|
|
707
|
+
updatedAt: row.updated_at,
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
rowToParallelExecution(row) {
|
|
711
|
+
const resultsObj = this.safeJsonParse(row.results, {});
|
|
712
|
+
const results = new Map();
|
|
713
|
+
for (const [key, value] of Object.entries(resultsObj)) {
|
|
714
|
+
results.set(key, value);
|
|
715
|
+
}
|
|
716
|
+
return {
|
|
717
|
+
id: row.id,
|
|
718
|
+
batchId: row.batch_id,
|
|
719
|
+
tasks: this.safeJsonParse(row.tasks, []),
|
|
720
|
+
maxConcurrency: row.max_concurrency || 5,
|
|
721
|
+
status: row.status || "pending",
|
|
722
|
+
results,
|
|
723
|
+
aggregatedReport: row.aggregated_report,
|
|
724
|
+
createdAt: row.created_at,
|
|
725
|
+
completedAt: row.completed_at,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
/**
|
|
729
|
+
* Close database connection
|
|
730
|
+
*/
|
|
731
|
+
async close() {
|
|
732
|
+
if (this.client) {
|
|
733
|
+
try {
|
|
734
|
+
// Attempt to close the client if it has a close method
|
|
735
|
+
await this.client.close?.();
|
|
736
|
+
}
|
|
737
|
+
catch (error) {
|
|
738
|
+
// Log but don't throw - client might not have close method or already closed
|
|
739
|
+
logger.debug("Note during database close (non-critical)", {
|
|
740
|
+
error: error instanceof Error ? error.message : String(error),
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
this.client = null;
|
|
744
|
+
this.initialized = false;
|
|
745
|
+
logger.info("Database connection closed");
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
// Export singleton instance
|
|
750
|
+
export const database = new DatabaseManager();
|
|
751
|
+
//# sourceMappingURL=database.js.map
|