@ainetwork/adk-provider-memory-mongodb 0.4.0 → 0.5.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/dist/{chunk-GPOFS7ZT.js → chunk-2XJ6S2W5.js} +12 -7
- package/dist/chunk-2XJ6S2W5.js.map +1 -0
- package/dist/{chunk-5CCEN7NK.js → chunk-QULDFKGZ.js} +5 -1
- package/dist/chunk-QULDFKGZ.js.map +1 -0
- package/dist/chunk-RC275GLE.js +70 -0
- package/dist/chunk-RC275GLE.js.map +1 -0
- package/dist/{chunk-NGLXQZLX.js → chunk-SJ2FHHN6.js} +13 -10
- package/dist/chunk-SJ2FHHN6.js.map +1 -0
- package/dist/index.cjs +322 -75
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -3
- package/dist/index.d.ts +11 -3
- package/dist/index.js +232 -59
- package/dist/index.js.map +1 -1
- package/dist/models/messages.model.cjs +4 -0
- package/dist/models/messages.model.cjs.map +1 -1
- package/dist/models/messages.model.d.cts +14 -1
- package/dist/models/messages.model.d.ts +14 -1
- package/dist/models/messages.model.js +1 -1
- package/dist/models/threads.model.cjs +11 -6
- package/dist/models/threads.model.cjs.map +1 -1
- package/dist/models/threads.model.d.cts +22 -9
- package/dist/models/threads.model.d.ts +22 -9
- package/dist/models/threads.model.js +1 -1
- package/dist/models/user-workflow.model.cjs +105 -0
- package/dist/models/user-workflow.model.cjs.map +1 -0
- package/dist/models/user-workflow.model.d.cts +92 -0
- package/dist/models/user-workflow.model.d.ts +92 -0
- package/dist/models/user-workflow.model.js +9 -0
- package/dist/models/{workflow.model.cjs → workflow-template.model.cjs} +18 -15
- package/dist/models/workflow-template.model.cjs.map +1 -0
- package/dist/models/workflow-template.model.d.cts +60 -0
- package/dist/models/workflow-template.model.d.ts +60 -0
- package/dist/models/workflow-template.model.js +9 -0
- package/dist/models/workflow-template.model.js.map +1 -0
- package/implements/base.memory.ts +130 -12
- package/implements/thread.memory.ts +48 -22
- package/implements/user-workflow.memory.ts +87 -0
- package/implements/workflow-template.memory.ts +69 -0
- package/models/messages.model.ts +7 -0
- package/models/threads.model.ts +16 -9
- package/models/user-workflow.model.ts +91 -0
- package/models/workflow-template.model.ts +58 -0
- package/package.json +3 -3
- package/dist/chunk-5CCEN7NK.js.map +0 -1
- package/dist/chunk-GPOFS7ZT.js.map +0 -1
- package/dist/chunk-NGLXQZLX.js.map +0 -1
- package/dist/models/workflow.model.cjs.map +0 -1
- package/dist/models/workflow.model.d.cts +0 -54
- package/dist/models/workflow.model.d.ts +0 -54
- package/dist/models/workflow.model.js +0 -9
- package/implements/workflow.memory.ts +0 -78
- package/models/workflow.model.ts +0 -46
- /package/dist/models/{workflow.model.js.map → user-workflow.model.js.map} +0 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import mongoose, { Schema, Document } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
declare const WorkflowTemplateObjectSchema: Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
4
|
+
timestamps: true;
|
|
5
|
+
}, {
|
|
6
|
+
createdAt: NativeDate;
|
|
7
|
+
updatedAt: NativeDate;
|
|
8
|
+
} & {
|
|
9
|
+
description: string;
|
|
10
|
+
title: string;
|
|
11
|
+
content: string;
|
|
12
|
+
active: boolean;
|
|
13
|
+
templateId: string;
|
|
14
|
+
variables?: any;
|
|
15
|
+
}, Document<unknown, {}, mongoose.FlatRecord<{
|
|
16
|
+
createdAt: NativeDate;
|
|
17
|
+
updatedAt: NativeDate;
|
|
18
|
+
} & {
|
|
19
|
+
description: string;
|
|
20
|
+
title: string;
|
|
21
|
+
content: string;
|
|
22
|
+
active: boolean;
|
|
23
|
+
templateId: string;
|
|
24
|
+
variables?: any;
|
|
25
|
+
}>, {}> & mongoose.FlatRecord<{
|
|
26
|
+
createdAt: NativeDate;
|
|
27
|
+
updatedAt: NativeDate;
|
|
28
|
+
} & {
|
|
29
|
+
description: string;
|
|
30
|
+
title: string;
|
|
31
|
+
content: string;
|
|
32
|
+
active: boolean;
|
|
33
|
+
templateId: string;
|
|
34
|
+
variables?: any;
|
|
35
|
+
}> & {
|
|
36
|
+
_id: mongoose.Types.ObjectId;
|
|
37
|
+
} & {
|
|
38
|
+
__v: number;
|
|
39
|
+
}>;
|
|
40
|
+
interface WorkflowTemplateDocument extends Document {
|
|
41
|
+
templateId: string;
|
|
42
|
+
title: string;
|
|
43
|
+
description: string;
|
|
44
|
+
active: boolean;
|
|
45
|
+
content: string;
|
|
46
|
+
variables?: Record<string, {
|
|
47
|
+
id: string;
|
|
48
|
+
label: string;
|
|
49
|
+
type: "select" | "date_range" | "date_parts" | "text" | "number";
|
|
50
|
+
options?: Array<string>;
|
|
51
|
+
resolveAt?: "creation" | "execution";
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
declare const WorkflowTemplateModel: mongoose.Model<WorkflowTemplateDocument, {}, {}, {}, Document<unknown, {}, WorkflowTemplateDocument, {}> & WorkflowTemplateDocument & Required<{
|
|
55
|
+
_id: unknown;
|
|
56
|
+
}> & {
|
|
57
|
+
__v: number;
|
|
58
|
+
}, any>;
|
|
59
|
+
|
|
60
|
+
export { type WorkflowTemplateDocument, WorkflowTemplateModel, WorkflowTemplateObjectSchema };
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import mongoose, { Schema, Document } from 'mongoose';
|
|
2
|
+
|
|
3
|
+
declare const WorkflowTemplateObjectSchema: Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, {
|
|
4
|
+
timestamps: true;
|
|
5
|
+
}, {
|
|
6
|
+
createdAt: NativeDate;
|
|
7
|
+
updatedAt: NativeDate;
|
|
8
|
+
} & {
|
|
9
|
+
description: string;
|
|
10
|
+
title: string;
|
|
11
|
+
content: string;
|
|
12
|
+
active: boolean;
|
|
13
|
+
templateId: string;
|
|
14
|
+
variables?: any;
|
|
15
|
+
}, Document<unknown, {}, mongoose.FlatRecord<{
|
|
16
|
+
createdAt: NativeDate;
|
|
17
|
+
updatedAt: NativeDate;
|
|
18
|
+
} & {
|
|
19
|
+
description: string;
|
|
20
|
+
title: string;
|
|
21
|
+
content: string;
|
|
22
|
+
active: boolean;
|
|
23
|
+
templateId: string;
|
|
24
|
+
variables?: any;
|
|
25
|
+
}>, {}> & mongoose.FlatRecord<{
|
|
26
|
+
createdAt: NativeDate;
|
|
27
|
+
updatedAt: NativeDate;
|
|
28
|
+
} & {
|
|
29
|
+
description: string;
|
|
30
|
+
title: string;
|
|
31
|
+
content: string;
|
|
32
|
+
active: boolean;
|
|
33
|
+
templateId: string;
|
|
34
|
+
variables?: any;
|
|
35
|
+
}> & {
|
|
36
|
+
_id: mongoose.Types.ObjectId;
|
|
37
|
+
} & {
|
|
38
|
+
__v: number;
|
|
39
|
+
}>;
|
|
40
|
+
interface WorkflowTemplateDocument extends Document {
|
|
41
|
+
templateId: string;
|
|
42
|
+
title: string;
|
|
43
|
+
description: string;
|
|
44
|
+
active: boolean;
|
|
45
|
+
content: string;
|
|
46
|
+
variables?: Record<string, {
|
|
47
|
+
id: string;
|
|
48
|
+
label: string;
|
|
49
|
+
type: "select" | "date_range" | "date_parts" | "text" | "number";
|
|
50
|
+
options?: Array<string>;
|
|
51
|
+
resolveAt?: "creation" | "execution";
|
|
52
|
+
}>;
|
|
53
|
+
}
|
|
54
|
+
declare const WorkflowTemplateModel: mongoose.Model<WorkflowTemplateDocument, {}, {}, {}, Document<unknown, {}, WorkflowTemplateDocument, {}> & WorkflowTemplateDocument & Required<{
|
|
55
|
+
_id: unknown;
|
|
56
|
+
}> & {
|
|
57
|
+
__v: number;
|
|
58
|
+
}, any>;
|
|
59
|
+
|
|
60
|
+
export { type WorkflowTemplateDocument, WorkflowTemplateModel, WorkflowTemplateObjectSchema };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { IAgentMemory, IIntentMemory, IMemory, IThreadMemory,
|
|
1
|
+
import { IAgentMemory, IIntentMemory, IMemory, IUserWorkflowMemory, IThreadMemory, IWorkflowTemplateMemory } from "@ainetwork/adk/modules";
|
|
2
2
|
import mongoose from "mongoose";
|
|
3
3
|
import { loggers } from "@ainetwork/adk/utils/logger";
|
|
4
4
|
import { MongoDBAgent } from "./agent.memory";
|
|
5
5
|
import { MongoDBIntent } from "./intent.memory";
|
|
6
6
|
import { MongoDBThread } from "./thread.memory";
|
|
7
|
-
import {
|
|
7
|
+
import { MongoDBUserWorkflow } from "./user-workflow.memory";
|
|
8
|
+
import { MongoDBWorkflowTemplate } from "./workflow-template.memory";
|
|
9
|
+
import { MessageModel } from "../models/messages.model";
|
|
8
10
|
|
|
9
11
|
export interface MongoDBMemoryConfig {
|
|
10
12
|
uri: string;
|
|
@@ -15,6 +17,7 @@ export interface MongoDBMemoryConfig {
|
|
|
15
17
|
socketTimeoutMS?: number;
|
|
16
18
|
connectTimeoutMS?: number;
|
|
17
19
|
operationTimeoutMS?: number; // Timeout for database operations
|
|
20
|
+
threadTTLSeconds?: number; // TTL for thread documents (in seconds). Orphaned messages are periodically cleaned up.
|
|
18
21
|
}
|
|
19
22
|
|
|
20
23
|
export class MongoDBMemory implements IMemory {
|
|
@@ -28,11 +31,14 @@ export class MongoDBMemory implements IMemory {
|
|
|
28
31
|
private connectionConfig: mongoose.ConnectOptions;
|
|
29
32
|
private eventListenersSetup: boolean = false;
|
|
30
33
|
private operationTimeoutMS: number;
|
|
34
|
+
private threadTTLSeconds?: number;
|
|
35
|
+
private orphanCleanupTimer?: ReturnType<typeof setInterval>;
|
|
31
36
|
|
|
32
37
|
private agentMemory: MongoDBAgent;
|
|
33
38
|
private intentMemory: MongoDBIntent;
|
|
34
39
|
private threadMemory: MongoDBThread;
|
|
35
|
-
private
|
|
40
|
+
private workflowTemplateMemory: MongoDBWorkflowTemplate;
|
|
41
|
+
private userWorkflowMemory: MongoDBUserWorkflow;
|
|
36
42
|
|
|
37
43
|
constructor(config: string | MongoDBMemoryConfig) {
|
|
38
44
|
const cfg = typeof config === 'string' ? { uri: config } : config;
|
|
@@ -41,8 +47,13 @@ export class MongoDBMemory implements IMemory {
|
|
|
41
47
|
this.maxReconnectAttempts = cfg.maxReconnectAttempts ?? 5;
|
|
42
48
|
this.reconnectInterval = cfg.reconnectInterval ?? 5000;
|
|
43
49
|
this.operationTimeoutMS = cfg.operationTimeoutMS ?? 10000; // Default 10 seconds
|
|
50
|
+
if (cfg.threadTTLSeconds !== undefined && cfg.threadTTLSeconds > 0) {
|
|
51
|
+
this.threadTTLSeconds = cfg.threadTTLSeconds;
|
|
52
|
+
}
|
|
44
53
|
this.connectionConfig = {
|
|
45
|
-
maxPoolSize: cfg.maxPoolSize ??
|
|
54
|
+
maxPoolSize: cfg.maxPoolSize ?? 10,
|
|
55
|
+
minPoolSize: 0,
|
|
56
|
+
maxIdleTimeMS: 30000,
|
|
46
57
|
serverSelectionTimeoutMS: cfg.serverSelectionTimeoutMS ?? 30000,
|
|
47
58
|
socketTimeoutMS: cfg.socketTimeoutMS ?? 45000,
|
|
48
59
|
connectTimeoutMS: cfg.connectTimeoutMS ?? 30000,
|
|
@@ -73,7 +84,12 @@ export class MongoDBMemory implements IMemory {
|
|
|
73
84
|
this.getOperationTimeout.bind(this)
|
|
74
85
|
);
|
|
75
86
|
|
|
76
|
-
this.
|
|
87
|
+
this.workflowTemplateMemory = new MongoDBWorkflowTemplate(
|
|
88
|
+
this.executeWithRetry.bind(this),
|
|
89
|
+
this.getOperationTimeout.bind(this)
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
this.userWorkflowMemory = new MongoDBUserWorkflow(
|
|
77
93
|
this.executeWithRetry.bind(this),
|
|
78
94
|
this.getOperationTimeout.bind(this)
|
|
79
95
|
);
|
|
@@ -91,8 +107,12 @@ export class MongoDBMemory implements IMemory {
|
|
|
91
107
|
return this.intentMemory;
|
|
92
108
|
}
|
|
93
109
|
|
|
94
|
-
public
|
|
95
|
-
return this.
|
|
110
|
+
public getWorkflowTemplateMemory(): IWorkflowTemplateMemory {
|
|
111
|
+
return this.workflowTemplateMemory;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public getUserWorkflowMemory(): IUserWorkflowMemory {
|
|
115
|
+
return this.userWorkflowMemory;
|
|
96
116
|
}
|
|
97
117
|
|
|
98
118
|
private setupMongooseEventListeners(): void {
|
|
@@ -134,7 +154,7 @@ export class MongoDBMemory implements IMemory {
|
|
|
134
154
|
|
|
135
155
|
this.reconnecting = true;
|
|
136
156
|
|
|
137
|
-
while (this.reconnectAttempts < this.maxReconnectAttempts && !this.
|
|
157
|
+
while (this.reconnectAttempts < this.maxReconnectAttempts && !this.connected) {
|
|
138
158
|
this.reconnectAttempts++;
|
|
139
159
|
loggers.agent.info(
|
|
140
160
|
`Attempting to reconnect to MongoDB (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`
|
|
@@ -163,7 +183,7 @@ export class MongoDBMemory implements IMemory {
|
|
|
163
183
|
|
|
164
184
|
this.reconnecting = false;
|
|
165
185
|
|
|
166
|
-
if (!this.
|
|
186
|
+
if (!this.connected) {
|
|
167
187
|
loggers.agent.error(
|
|
168
188
|
`Failed to reconnect to MongoDB after ${this.maxReconnectAttempts} attempts`
|
|
169
189
|
);
|
|
@@ -179,6 +199,8 @@ export class MongoDBMemory implements IMemory {
|
|
|
179
199
|
await mongoose.connect(this.uri, this.connectionConfig);
|
|
180
200
|
this.connected = true;
|
|
181
201
|
this.reconnectAttempts = 0;
|
|
202
|
+
await this.setupTTLIndex();
|
|
203
|
+
this.startOrphanCleanup();
|
|
182
204
|
} catch (error) {
|
|
183
205
|
loggers.agent.error("Failed to connect to MongoDB:", error);
|
|
184
206
|
throw error;
|
|
@@ -186,11 +208,15 @@ export class MongoDBMemory implements IMemory {
|
|
|
186
208
|
}
|
|
187
209
|
|
|
188
210
|
public async disconnect(): Promise<void> {
|
|
189
|
-
if (!this.
|
|
211
|
+
if (!this.connected) {
|
|
190
212
|
return;
|
|
191
213
|
}
|
|
192
214
|
|
|
193
215
|
try {
|
|
216
|
+
if (this.orphanCleanupTimer) {
|
|
217
|
+
clearInterval(this.orphanCleanupTimer);
|
|
218
|
+
this.orphanCleanupTimer = undefined;
|
|
219
|
+
}
|
|
194
220
|
await mongoose.disconnect();
|
|
195
221
|
this.connected = false;
|
|
196
222
|
} catch (error) {
|
|
@@ -204,7 +230,7 @@ export class MongoDBMemory implements IMemory {
|
|
|
204
230
|
}
|
|
205
231
|
|
|
206
232
|
private async ensureConnection(): Promise<void> {
|
|
207
|
-
if (!this.
|
|
233
|
+
if (!this.connected && !this.reconnecting) {
|
|
208
234
|
await this.connect();
|
|
209
235
|
}
|
|
210
236
|
|
|
@@ -215,11 +241,79 @@ export class MongoDBMemory implements IMemory {
|
|
|
215
241
|
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
216
242
|
}
|
|
217
243
|
|
|
218
|
-
if (!this.
|
|
244
|
+
if (!this.connected) {
|
|
219
245
|
throw new Error("MongoDB is not connected and reconnection failed");
|
|
220
246
|
}
|
|
221
247
|
}
|
|
222
248
|
|
|
249
|
+
private async setupTTLIndex(): Promise<void> {
|
|
250
|
+
if (this.threadTTLSeconds === undefined) return;
|
|
251
|
+
|
|
252
|
+
try {
|
|
253
|
+
const db = mongoose.connection.db;
|
|
254
|
+
if (!db) return;
|
|
255
|
+
|
|
256
|
+
const collection = db.collection('threads');
|
|
257
|
+
const indexes = await collection.indexes();
|
|
258
|
+
const existingTTL = indexes.find(
|
|
259
|
+
(idx) => idx.key?.updatedAt !== undefined && idx.expireAfterSeconds !== undefined
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
if (existingTTL) {
|
|
263
|
+
if (existingTTL.expireAfterSeconds !== this.threadTTLSeconds) {
|
|
264
|
+
await db.command({
|
|
265
|
+
collMod: 'threads',
|
|
266
|
+
index: { keyPattern: { updatedAt: 1 }, expireAfterSeconds: this.threadTTLSeconds },
|
|
267
|
+
});
|
|
268
|
+
loggers.agent.info(`Thread TTL index updated to ${this.threadTTLSeconds} seconds`);
|
|
269
|
+
}
|
|
270
|
+
} else {
|
|
271
|
+
await collection.createIndex(
|
|
272
|
+
{ updatedAt: 1 },
|
|
273
|
+
{ expireAfterSeconds: this.threadTTLSeconds },
|
|
274
|
+
);
|
|
275
|
+
loggers.agent.info(`Thread TTL index created with ${this.threadTTLSeconds} seconds`);
|
|
276
|
+
}
|
|
277
|
+
} catch (error) {
|
|
278
|
+
loggers.agent.error('Failed to setup TTL index:', error);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
private startOrphanCleanup(): void {
|
|
283
|
+
if (this.threadTTLSeconds === undefined) return;
|
|
284
|
+
if (this.orphanCleanupTimer) return;
|
|
285
|
+
|
|
286
|
+
// Run cleanup at half the TTL interval, with a minimum of 60s and maximum of 1 hour
|
|
287
|
+
const intervalMs = Math.max(60_000, Math.min(this.threadTTLSeconds * 500, 3_600_000));
|
|
288
|
+
this.orphanCleanupTimer = setInterval(() => {
|
|
289
|
+
this.cleanupOrphanedMessages().catch((error) => {
|
|
290
|
+
loggers.agent.error('Orphaned message cleanup failed:', error);
|
|
291
|
+
});
|
|
292
|
+
}, intervalMs);
|
|
293
|
+
|
|
294
|
+
loggers.agent.info(`Orphaned message cleanup scheduled every ${Math.round(intervalMs / 1000)}s`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
private async cleanupOrphanedMessages(): Promise<void> {
|
|
298
|
+
if (!this.connected) return;
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
const db = mongoose.connection.db;
|
|
302
|
+
if (!db) return;
|
|
303
|
+
|
|
304
|
+
const existingThreadIds = await db.collection('threads').distinct('threadId');
|
|
305
|
+
const result = await MessageModel.deleteMany({
|
|
306
|
+
threadId: { $nin: existingThreadIds },
|
|
307
|
+
});
|
|
308
|
+
|
|
309
|
+
if (result.deletedCount > 0) {
|
|
310
|
+
loggers.agent.info(`Cleaned up ${result.deletedCount} orphaned messages`);
|
|
311
|
+
}
|
|
312
|
+
} catch (error) {
|
|
313
|
+
loggers.agent.error('Failed to cleanup orphaned messages:', error);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
|
|
223
317
|
/**
|
|
224
318
|
* Get the operation timeout in milliseconds
|
|
225
319
|
*/
|
|
@@ -246,6 +340,30 @@ export class MongoDBMemory implements IMemory {
|
|
|
246
340
|
throw error;
|
|
247
341
|
}
|
|
248
342
|
|
|
343
|
+
// Check if it's a TooManyLogicalSessions error
|
|
344
|
+
if (error.code === 261 || error.codeName === "TooManyLogicalSessions") {
|
|
345
|
+
loggers.agent.warn(
|
|
346
|
+
`${operationName} failed due to too many sessions, disconnecting to release sessions...`
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
try {
|
|
350
|
+
await mongoose.disconnect();
|
|
351
|
+
this.connected = false;
|
|
352
|
+
} catch (disconnectError) {
|
|
353
|
+
loggers.agent.error("Failed to disconnect during session cleanup:", disconnectError);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
await new Promise((resolve) => setTimeout(resolve, 5000));
|
|
357
|
+
await this.ensureConnection();
|
|
358
|
+
|
|
359
|
+
try {
|
|
360
|
+
return await operation();
|
|
361
|
+
} catch (retryError: any) {
|
|
362
|
+
loggers.agent.error(`${operationName} failed after session cleanup retry:`, retryError);
|
|
363
|
+
throw retryError;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
|
|
249
367
|
// Check if it's a connection-related error
|
|
250
368
|
if (
|
|
251
369
|
error.name === "MongoNetworkError" ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MessageObject, ThreadMetadata, ThreadObject, ThreadType } from "@ainetwork/adk/types/memory";
|
|
1
|
+
import type { MessageObject, ThreadMetadata, ThreadObject, ThreadType, ThreadFilter } from "@ainetwork/adk/types/memory";
|
|
2
2
|
import { MessageRole } from "@ainetwork/adk/types/memory";
|
|
3
3
|
import { IThreadMemory } from "@ainetwork/adk/modules";
|
|
4
4
|
import { ThreadDocument, ThreadModel } from "../models/threads.model";
|
|
@@ -44,6 +44,8 @@ export class MongoDBThread implements IThreadMemory {
|
|
|
44
44
|
userId: thread.userId,
|
|
45
45
|
type: thread.type as ThreadType,
|
|
46
46
|
title: thread.title || "New thread",
|
|
47
|
+
isPinned: thread.isPinned ?? false,
|
|
48
|
+
workflowId: thread.workflowId,
|
|
47
49
|
messages: []
|
|
48
50
|
};
|
|
49
51
|
messages.forEach((message: MessageDocument) => {
|
|
@@ -65,19 +67,18 @@ export class MongoDBThread implements IThreadMemory {
|
|
|
65
67
|
userId: string,
|
|
66
68
|
threadId: string,
|
|
67
69
|
title: string,
|
|
70
|
+
workflowId?: string,
|
|
68
71
|
): Promise<ThreadObject> {
|
|
69
72
|
return this.executeWithRetry(async () => {
|
|
70
|
-
const now = Date.now();
|
|
71
73
|
await ThreadModel.create({
|
|
72
74
|
type,
|
|
73
75
|
userId,
|
|
74
76
|
threadId,
|
|
75
77
|
title,
|
|
76
|
-
|
|
77
|
-
created_at: now,
|
|
78
|
+
workflowId,
|
|
78
79
|
});
|
|
79
80
|
|
|
80
|
-
return { type, userId, threadId, title, messages: []};
|
|
81
|
+
return { type, userId, threadId, title, workflowId, messages: []};
|
|
81
82
|
}, `createThread(${userId}, ${threadId})`);
|
|
82
83
|
};
|
|
83
84
|
|
|
@@ -87,20 +88,25 @@ export class MongoDBThread implements IThreadMemory {
|
|
|
87
88
|
messages: MessageObject[]
|
|
88
89
|
): Promise<void> {
|
|
89
90
|
return this.executeWithRetry(async () => {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
91
|
+
if (messages.length > 0) {
|
|
92
|
+
const messageIds = messages.map((m) => m.messageId);
|
|
93
|
+
await MessageModel.deleteMany({ threadId, userId, messageId: { $in: messageIds } });
|
|
94
|
+
await MessageModel.insertMany(
|
|
95
|
+
messages.map((message) => ({
|
|
96
|
+
threadId,
|
|
97
|
+
messageId: message.messageId,
|
|
98
|
+
userId,
|
|
99
|
+
role: message.role,
|
|
100
|
+
content: message.content,
|
|
101
|
+
timestamp: message.timestamp,
|
|
102
|
+
metadata: message.metadata,
|
|
103
|
+
}))
|
|
104
|
+
);
|
|
103
105
|
}
|
|
106
|
+
await ThreadModel.updateOne(
|
|
107
|
+
{ threadId, userId },
|
|
108
|
+
{ $set: { updatedAt: new Date() } }
|
|
109
|
+
);
|
|
104
110
|
}, `addMessagesToThread(${userId}, ${threadId})`);
|
|
105
111
|
};
|
|
106
112
|
|
|
@@ -116,11 +122,14 @@ export class MongoDBThread implements IThreadMemory {
|
|
|
116
122
|
}, `deleteThread(${userId}, ${threadId})`);
|
|
117
123
|
};
|
|
118
124
|
|
|
119
|
-
public async listThreads(userId: string): Promise<ThreadMetadata[]> {
|
|
125
|
+
public async listThreads(userId: string, filter?: ThreadFilter): Promise<ThreadMetadata[]> {
|
|
120
126
|
return this.executeWithRetry(async () => {
|
|
121
127
|
const timeout = this.getOperationTimeout();
|
|
122
|
-
const
|
|
123
|
-
|
|
128
|
+
const query: Record<string, any> = { userId };
|
|
129
|
+
if (filter?.workflowId) query.workflowId = filter.workflowId;
|
|
130
|
+
if (filter?.type) query.type = filter.type;
|
|
131
|
+
const threads = await ThreadModel.find(query)
|
|
132
|
+
.sort({ updatedAt: -1 })
|
|
124
133
|
.maxTimeMS(timeout);
|
|
125
134
|
const data: ThreadMetadata[] = threads.map((thread: ThreadDocument) => {
|
|
126
135
|
return {
|
|
@@ -128,10 +137,27 @@ export class MongoDBThread implements IThreadMemory {
|
|
|
128
137
|
userId,
|
|
129
138
|
threadId: thread.threadId,
|
|
130
139
|
title: thread.title,
|
|
131
|
-
|
|
140
|
+
isPinned: thread.isPinned ?? false,
|
|
141
|
+
workflowId: thread.workflowId,
|
|
142
|
+
createdAt: thread.createdAt?.toISOString(),
|
|
143
|
+
updatedAt: thread.updatedAt?.toISOString(),
|
|
132
144
|
} as ThreadMetadata;
|
|
133
145
|
})
|
|
134
146
|
return data;
|
|
135
147
|
}, `listThreads(${userId})`);
|
|
136
148
|
};
|
|
149
|
+
|
|
150
|
+
public async updateThreadPin(
|
|
151
|
+
userId: string,
|
|
152
|
+
threadId: string,
|
|
153
|
+
isPinned: boolean
|
|
154
|
+
): Promise<void> {
|
|
155
|
+
return this.executeWithRetry(async () => {
|
|
156
|
+
const timeout = this.getOperationTimeout();
|
|
157
|
+
await ThreadModel.updateOne(
|
|
158
|
+
{ threadId, userId },
|
|
159
|
+
{ $set: { isPinned } }
|
|
160
|
+
).maxTimeMS(timeout);
|
|
161
|
+
}, `updateThreadPin(${userId}, ${threadId})`);
|
|
162
|
+
};
|
|
137
163
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { IUserWorkflowMemory } from "@ainetwork/adk/modules";
|
|
2
|
+
import type { UserWorkflow } from "@ainetwork/adk/types/memory";
|
|
3
|
+
import { UserWorkflowModel } from "../models/user-workflow.model";
|
|
4
|
+
|
|
5
|
+
export type ExecuteWithRetryFn = <T>(
|
|
6
|
+
operation: () => Promise<T>,
|
|
7
|
+
operationName?: string
|
|
8
|
+
) => Promise<T>;
|
|
9
|
+
|
|
10
|
+
export type GetOperationTimeoutFn = () => number;
|
|
11
|
+
|
|
12
|
+
export class MongoDBUserWorkflow implements IUserWorkflowMemory {
|
|
13
|
+
private executeWithRetry: ExecuteWithRetryFn;
|
|
14
|
+
private getOperationTimeout: GetOperationTimeoutFn;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
executeWithRetry: ExecuteWithRetryFn,
|
|
18
|
+
getOperationTimeout: GetOperationTimeoutFn
|
|
19
|
+
) {
|
|
20
|
+
this.executeWithRetry = executeWithRetry;
|
|
21
|
+
this.getOperationTimeout = getOperationTimeout;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async createUserWorkflow(workflow: UserWorkflow): Promise<UserWorkflow> {
|
|
25
|
+
return this.executeWithRetry(async () => {
|
|
26
|
+
const created = await UserWorkflowModel.create(workflow);
|
|
27
|
+
return created.toObject() as UserWorkflow;
|
|
28
|
+
}, "createUserWorkflow()");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async getUserWorkflow(workflowId: string): Promise<UserWorkflow | undefined> {
|
|
32
|
+
return this.executeWithRetry(async () => {
|
|
33
|
+
const timeout = this.getOperationTimeout();
|
|
34
|
+
const workflow = await UserWorkflowModel.findOne({ workflowId })
|
|
35
|
+
.maxTimeMS(timeout)
|
|
36
|
+
.lean<UserWorkflow>();
|
|
37
|
+
return workflow || undefined;
|
|
38
|
+
}, "getUserWorkflow()");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public async updateUserWorkflow(workflowId: string, updates: Partial<UserWorkflow>): Promise<void> {
|
|
42
|
+
if (!updates.userId) {
|
|
43
|
+
throw new Error("userId is required for updateUserWorkflow");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const { userId, workflowId: _workflowId, ...mutableUpdates } = updates;
|
|
47
|
+
|
|
48
|
+
return this.executeWithRetry(async () => {
|
|
49
|
+
const timeout = this.getOperationTimeout();
|
|
50
|
+
await UserWorkflowModel.updateOne(
|
|
51
|
+
{ workflowId, userId },
|
|
52
|
+
{ $set: mutableUpdates }
|
|
53
|
+
).maxTimeMS(timeout);
|
|
54
|
+
}, "updateUserWorkflow()");
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
public async deleteUserWorkflow(workflowId: string, userId: string): Promise<void> {
|
|
58
|
+
return this.executeWithRetry(async () => {
|
|
59
|
+
const timeout = this.getOperationTimeout();
|
|
60
|
+
await UserWorkflowModel.deleteOne({ workflowId, userId }).maxTimeMS(timeout);
|
|
61
|
+
}, "deleteUserWorkflow()");
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public async listUserWorkflows(userId?: string): Promise<UserWorkflow[]> {
|
|
65
|
+
return this.executeWithRetry(async () => {
|
|
66
|
+
const timeout = this.getOperationTimeout();
|
|
67
|
+
const query = userId ? { userId } : {};
|
|
68
|
+
const workflows = await UserWorkflowModel.find(query)
|
|
69
|
+
.maxTimeMS(timeout)
|
|
70
|
+
.lean<UserWorkflow[]>();
|
|
71
|
+
return workflows;
|
|
72
|
+
}, "listUserWorkflows()");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
public async listActiveScheduledWorkflows(): Promise<UserWorkflow[]> {
|
|
76
|
+
return this.executeWithRetry(async () => {
|
|
77
|
+
const timeout = this.getOperationTimeout();
|
|
78
|
+
const workflows = await UserWorkflowModel.find({
|
|
79
|
+
active: true,
|
|
80
|
+
schedule: { $exists: true, $ne: null },
|
|
81
|
+
})
|
|
82
|
+
.maxTimeMS(timeout)
|
|
83
|
+
.lean<UserWorkflow[]>();
|
|
84
|
+
return workflows;
|
|
85
|
+
}, "listActiveScheduledWorkflows()");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { IWorkflowTemplateMemory } from "@ainetwork/adk/modules";
|
|
2
|
+
import type { WorkflowTemplate } from "@ainetwork/adk/types/memory";
|
|
3
|
+
import { WorkflowTemplateModel } from "../models/workflow-template.model";
|
|
4
|
+
|
|
5
|
+
export type ExecuteWithRetryFn = <T>(
|
|
6
|
+
operation: () => Promise<T>,
|
|
7
|
+
operationName?: string
|
|
8
|
+
) => Promise<T>;
|
|
9
|
+
|
|
10
|
+
export type GetOperationTimeoutFn = () => number;
|
|
11
|
+
|
|
12
|
+
export class MongoDBWorkflowTemplate implements IWorkflowTemplateMemory {
|
|
13
|
+
private executeWithRetry: ExecuteWithRetryFn;
|
|
14
|
+
private getOperationTimeout: GetOperationTimeoutFn;
|
|
15
|
+
|
|
16
|
+
constructor(
|
|
17
|
+
executeWithRetry: ExecuteWithRetryFn,
|
|
18
|
+
getOperationTimeout: GetOperationTimeoutFn
|
|
19
|
+
) {
|
|
20
|
+
this.executeWithRetry = executeWithRetry;
|
|
21
|
+
this.getOperationTimeout = getOperationTimeout;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
public async createTemplate(template: WorkflowTemplate): Promise<WorkflowTemplate> {
|
|
25
|
+
return this.executeWithRetry(async () => {
|
|
26
|
+
const created = await WorkflowTemplateModel.create(template);
|
|
27
|
+
return created.toObject() as WorkflowTemplate;
|
|
28
|
+
}, "createTemplate()");
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public async getTemplate(templateId: string): Promise<WorkflowTemplate | undefined> {
|
|
32
|
+
return this.executeWithRetry(async () => {
|
|
33
|
+
const timeout = this.getOperationTimeout();
|
|
34
|
+
const template = await WorkflowTemplateModel.findOne({ templateId })
|
|
35
|
+
.maxTimeMS(timeout)
|
|
36
|
+
.lean<WorkflowTemplate>();
|
|
37
|
+
return template || undefined;
|
|
38
|
+
}, "getTemplate()");
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
public async updateTemplate(templateId: string, updates: Partial<WorkflowTemplate>): Promise<void> {
|
|
42
|
+
const { templateId: _templateId, ...mutableUpdates } = updates;
|
|
43
|
+
|
|
44
|
+
return this.executeWithRetry(async () => {
|
|
45
|
+
const timeout = this.getOperationTimeout();
|
|
46
|
+
await WorkflowTemplateModel.updateOne(
|
|
47
|
+
{ templateId },
|
|
48
|
+
{ $set: mutableUpdates }
|
|
49
|
+
).maxTimeMS(timeout);
|
|
50
|
+
}, "updateTemplate()");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
public async deleteTemplate(templateId: string): Promise<void> {
|
|
54
|
+
return this.executeWithRetry(async () => {
|
|
55
|
+
const timeout = this.getOperationTimeout();
|
|
56
|
+
await WorkflowTemplateModel.deleteOne({ templateId }).maxTimeMS(timeout);
|
|
57
|
+
}, "deleteTemplate()");
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
public async listTemplates(): Promise<WorkflowTemplate[]> {
|
|
61
|
+
return this.executeWithRetry(async () => {
|
|
62
|
+
const timeout = this.getOperationTimeout();
|
|
63
|
+
const templates = await WorkflowTemplateModel.find()
|
|
64
|
+
.maxTimeMS(timeout)
|
|
65
|
+
.lean<WorkflowTemplate[]>();
|
|
66
|
+
return templates;
|
|
67
|
+
}, "listTemplates()");
|
|
68
|
+
}
|
|
69
|
+
}
|
package/models/messages.model.ts
CHANGED
|
@@ -47,8 +47,13 @@ export const MessageObjectSchema = new Schema(
|
|
|
47
47
|
default: {},
|
|
48
48
|
},
|
|
49
49
|
},
|
|
50
|
+
{
|
|
51
|
+
timestamps: true,
|
|
52
|
+
},
|
|
50
53
|
);
|
|
51
54
|
|
|
55
|
+
MessageObjectSchema.index({ threadId: 1, messageId: 1 }, { unique: true });
|
|
56
|
+
|
|
52
57
|
// Message Document interface
|
|
53
58
|
export interface MessageDocument extends Document {
|
|
54
59
|
messageId: string;
|
|
@@ -60,6 +65,8 @@ export interface MessageDocument extends Document {
|
|
|
60
65
|
parts: any[];
|
|
61
66
|
};
|
|
62
67
|
timestamp: number;
|
|
68
|
+
createdAt: Date;
|
|
69
|
+
updatedAt: Date;
|
|
63
70
|
metadata?: { [key: string]: unknown };
|
|
64
71
|
}
|
|
65
72
|
|