@ainetwork/adk-provider-memory-mongodb 0.2.3 → 0.3.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.
@@ -0,0 +1,23 @@
1
+ import mongoose, { Schema, Document } from 'mongoose';
2
+
3
+ declare const AgentObjectSchema: Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, {
4
+ agent_prompt?: string | null | undefined;
5
+ }, Document<unknown, {}, mongoose.FlatRecord<{
6
+ agent_prompt?: string | null | undefined;
7
+ }>, {}> & mongoose.FlatRecord<{
8
+ agent_prompt?: string | null | undefined;
9
+ }> & {
10
+ _id: mongoose.Types.ObjectId;
11
+ } & {
12
+ __v: number;
13
+ }>;
14
+ interface AgentDocument extends Document {
15
+ agent_prompt: string;
16
+ }
17
+ declare const AgentModel: mongoose.Model<AgentDocument, {}, {}, {}, Document<unknown, {}, AgentDocument, {}> & AgentDocument & Required<{
18
+ _id: unknown;
19
+ }> & {
20
+ __v: number;
21
+ }, any>;
22
+
23
+ export { type AgentDocument, AgentModel, AgentObjectSchema };
@@ -0,0 +1,23 @@
1
+ import mongoose, { Schema, Document } from 'mongoose';
2
+
3
+ declare const AgentObjectSchema: Schema<any, mongoose.Model<any, any, any, any, any, any>, {}, {}, {}, {}, mongoose.DefaultSchemaOptions, {
4
+ agent_prompt?: string | null | undefined;
5
+ }, Document<unknown, {}, mongoose.FlatRecord<{
6
+ agent_prompt?: string | null | undefined;
7
+ }>, {}> & mongoose.FlatRecord<{
8
+ agent_prompt?: string | null | undefined;
9
+ }> & {
10
+ _id: mongoose.Types.ObjectId;
11
+ } & {
12
+ __v: number;
13
+ }>;
14
+ interface AgentDocument extends Document {
15
+ agent_prompt: string;
16
+ }
17
+ declare const AgentModel: mongoose.Model<AgentDocument, {}, {}, {}, Document<unknown, {}, AgentDocument, {}> & AgentDocument & Required<{
18
+ _id: unknown;
19
+ }> & {
20
+ __v: number;
21
+ }, any>;
22
+
23
+ export { type AgentDocument, AgentModel, AgentObjectSchema };
@@ -0,0 +1,9 @@
1
+ import {
2
+ AgentModel,
3
+ AgentObjectSchema
4
+ } from "../chunk-OWGGE5EW.js";
5
+ export {
6
+ AgentModel,
7
+ AgentObjectSchema
8
+ };
9
+ //# sourceMappingURL=agent.model.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,46 @@
1
+ import { IAgentMemory } from "@ainetwork/adk/modules";
2
+ import { AgentModel } from "../models/agent.model";
3
+
4
+ export type ExecuteWithRetryFn = <T>(
5
+ operation: () => Promise<T>,
6
+ operationName?: string
7
+ ) => Promise<T>;
8
+
9
+ export type GetOperationTimeoutFn = () => number;
10
+
11
+ type AgentMetadata = {
12
+ agent_prompt: string;
13
+ }
14
+
15
+ export class MongoDBAgent implements IAgentMemory {
16
+ private executeWithRetry: ExecuteWithRetryFn;
17
+ private getOperationTimeout: GetOperationTimeoutFn;
18
+
19
+ constructor(
20
+ executeWithRetry: ExecuteWithRetryFn,
21
+ getOperationTimeout: GetOperationTimeoutFn
22
+ ) {
23
+ this.executeWithRetry = executeWithRetry;
24
+ this.getOperationTimeout = getOperationTimeout;
25
+ }
26
+
27
+ public async getAgentPrompt(): Promise<string> {
28
+ return this.executeWithRetry(async () => {
29
+ const timeout = this.getOperationTimeout();
30
+ const metadata = await AgentModel.findOne({
31
+ id: "agent_metadata"
32
+ }).maxTimeMS(timeout)
33
+ .lean<AgentMetadata>();
34
+ return metadata?.agent_prompt || "";
35
+ }, "getAgentPrompt()");
36
+ };
37
+
38
+ public async updateAgentPrompt(prompt: string): Promise<void> {
39
+ return this.executeWithRetry(async () => {
40
+ const timeout = this.getOperationTimeout();
41
+ await AgentModel.updateOne({
42
+ id: "agent_metadata",
43
+ }, { "agent_prompt": prompt }).maxTimeMS(timeout);
44
+ }, "updateAgentPrompt()");
45
+ };
46
+ }
@@ -1,52 +1,264 @@
1
- import { IMemory } from "node_modules/@ainetwork/adk/dist/esm/modules/memory/base.memory";
1
+ import { IAgentMemory, IIntentMemory, IMemory, IThreadMemory } from "node_modules/@ainetwork/adk/dist/esm/modules/memory/base.memory";
2
2
  import mongoose from "mongoose";
3
3
  import { loggers } from "@ainetwork/adk/utils/logger";
4
+ import { MongoDBAgent } from "./agent.memory";
5
+ import { MongoDBIntent } from "./intent.memory";
6
+ import { MongoDBThread } from "./thread.memory";
7
+
8
+ export interface MongoDBMemoryConfig {
9
+ uri: string;
10
+ maxReconnectAttempts?: number;
11
+ reconnectInterval?: number;
12
+ maxPoolSize?: number;
13
+ serverSelectionTimeoutMS?: number;
14
+ socketTimeoutMS?: number;
15
+ connectTimeoutMS?: number;
16
+ operationTimeoutMS?: number; // Timeout for database operations
17
+ }
4
18
 
5
19
  export class MongoDBMemory implements IMemory {
6
- private _isConnected: boolean = false;
7
- private _uri: string;
20
+ private static instance: MongoDBMemory;
21
+ private uri: string;
22
+ private connected: boolean = false;
23
+ private reconnectAttempts: number = 0;
24
+ private maxReconnectAttempts: number;
25
+ private reconnectInterval: number;
26
+ private reconnecting: boolean = false;
27
+ private connectionConfig: mongoose.ConnectOptions;
28
+ private eventListenersSetup: boolean = false;
29
+ private operationTimeoutMS: number;
30
+
31
+ private agentMemory: MongoDBAgent;
32
+ private intentMemory: MongoDBIntent;
33
+ private threadMemory: MongoDBThread;
34
+
35
+ constructor(config: string | MongoDBMemoryConfig) {
36
+ const cfg = typeof config === 'string' ? { uri: config } : config;
37
+
38
+ this.uri = cfg.uri;
39
+ this.maxReconnectAttempts = cfg.maxReconnectAttempts ?? 5;
40
+ this.reconnectInterval = cfg.reconnectInterval ?? 5000;
41
+ this.operationTimeoutMS = cfg.operationTimeoutMS ?? 10000; // Default 10 seconds
42
+ this.connectionConfig = {
43
+ maxPoolSize: cfg.maxPoolSize ?? 1,
44
+ serverSelectionTimeoutMS: cfg.serverSelectionTimeoutMS ?? 30000,
45
+ socketTimeoutMS: cfg.socketTimeoutMS ?? 45000,
46
+ connectTimeoutMS: cfg.connectTimeoutMS ?? 30000,
47
+ bufferCommands: false,
48
+ };
49
+
50
+ if (!MongoDBMemory.instance) {
51
+ MongoDBMemory.instance = this;
52
+ this.setupMongooseEventListeners();
53
+ } else {
54
+ // Use existing instance's connection state
55
+ this.connected = MongoDBMemory.instance.connected;
56
+ this.operationTimeoutMS = MongoDBMemory.instance.operationTimeoutMS;
57
+ }
58
+
59
+ this.agentMemory = new MongoDBAgent(
60
+ this.executeWithRetry.bind(this),
61
+ this.getOperationTimeout.bind(this)
62
+ );
63
+
64
+ this.threadMemory = new MongoDBThread(
65
+ this.executeWithRetry.bind(this),
66
+ this.getOperationTimeout.bind(this)
67
+ );
68
+
69
+ this.intentMemory = new MongoDBIntent(
70
+ this.executeWithRetry.bind(this),
71
+ this.getOperationTimeout.bind(this)
72
+ );
73
+ }
74
+
75
+ public getAgentMemory(): IAgentMemory {
76
+ return this.agentMemory;
77
+ }
78
+
79
+ public getThreadMemory(): IThreadMemory {
80
+ return this.threadMemory;
81
+ }
82
+
83
+ public getIntentMemory(): IIntentMemory {
84
+ return this.intentMemory;
85
+ }
86
+
87
+ private setupMongooseEventListeners(): void {
88
+ if (this.eventListenersSetup) return;
89
+
90
+ this.eventListenersSetup = true;
91
+
92
+ mongoose.connection.on("connected", () => {
93
+ this.connected = true;
94
+ this.reconnectAttempts = 0;
95
+ this.reconnecting = false;
96
+ loggers.agent.info("MongoDB connected successfully");
97
+ });
98
+
99
+ mongoose.connection.on("disconnected", () => {
100
+ this.connected = false;
101
+ loggers.agent.warn("MongoDB disconnected");
102
+ this.handleDisconnection();
103
+ });
104
+
105
+ mongoose.connection.on("error", (error) => {
106
+ this.connected = false;
107
+ loggers.agent.error("MongoDB connection error:", error);
108
+ this.handleDisconnection();
109
+ });
110
+
111
+ mongoose.connection.on("reconnected", () => {
112
+ this.connected = true;
113
+ this.reconnectAttempts = 0;
114
+ this.reconnecting = false;
115
+ loggers.agent.info("MongoDB reconnected successfully");
116
+ });
117
+ }
118
+
119
+ private async handleDisconnection(): Promise<void> {
120
+ if (this.reconnecting) {
121
+ return;
122
+ }
123
+
124
+ this.reconnecting = true;
125
+
126
+ while (this.reconnectAttempts < this.maxReconnectAttempts && !this.isConnected) {
127
+ this.reconnectAttempts++;
128
+ loggers.agent.info(
129
+ `Attempting to reconnect to MongoDB (${this.reconnectAttempts}/${this.maxReconnectAttempts})...`
130
+ );
131
+
132
+ try {
133
+ await mongoose.connect(this.uri, this.connectionConfig);
134
+ this.connected = true;
135
+ this.reconnectAttempts = 0;
136
+ this.reconnecting = false;
137
+ loggers.agent.info("MongoDB reconnection successful");
138
+ return;
139
+ } catch (error) {
140
+ loggers.agent.error(
141
+ `Reconnection attempt ${this.reconnectAttempts} failed:`,
142
+ error
143
+ );
144
+
145
+ if (this.reconnectAttempts < this.maxReconnectAttempts) {
146
+ await new Promise((resolve) =>
147
+ setTimeout(resolve, this.reconnectInterval)
148
+ );
149
+ }
150
+ }
151
+ }
8
152
 
9
- constructor(uri: string) {
10
- this._uri = uri;
153
+ this.reconnecting = false;
154
+
155
+ if (!this.isConnected) {
156
+ loggers.agent.error(
157
+ `Failed to reconnect to MongoDB after ${this.maxReconnectAttempts} attempts`
158
+ );
159
+ }
11
160
  }
12
161
 
13
162
  public async connect(): Promise<void> {
14
- if (this._isConnected) {
15
- return;
16
- }
17
-
18
- try {
19
- await mongoose.connect(this._uri, {
20
- maxPoolSize: 1,
21
- serverSelectionTimeoutMS: 30000,
22
- socketTimeoutMS: 45000,
23
- connectTimeoutMS: 30000,
24
- bufferCommands: false,
25
- });
26
- this._isConnected = true;
27
- loggers.agent.info("MongoDB connected successfully");
28
- } catch (error) {
29
- loggers.agent.error("Failed to connect to MongoDB:", error);
30
- throw error;
31
- }
163
+ if (this.connected) {
164
+ return;
165
+ }
166
+
167
+ try {
168
+ await mongoose.connect(this.uri, this.connectionConfig);
169
+ this.connected = true;
170
+ this.reconnectAttempts = 0;
171
+ } catch (error) {
172
+ loggers.agent.error("Failed to connect to MongoDB:", error);
173
+ throw error;
174
+ }
32
175
  }
33
176
 
34
177
  public async disconnect(): Promise<void> {
35
- if (!this.isConnected) {
36
- return;
37
- }
178
+ if (!this.isConnected) {
179
+ return;
180
+ }
38
181
 
39
- try {
40
- await mongoose.disconnect();
41
- this._isConnected = false;
42
- loggers.agent.info("MongoDB disconnected successfully");
43
- } catch (error) {
44
- loggers.agent.error("Failed to disconnect from MongoDB:", error);
45
- throw error;
46
- }
182
+ try {
183
+ await mongoose.disconnect();
184
+ this.connected = false;
185
+ } catch (error) {
186
+ loggers.agent.error("Failed to disconnect from MongoDB:", error);
187
+ throw error;
188
+ }
47
189
  }
48
190
 
49
191
  public isConnected(): boolean {
50
- return this._isConnected;
192
+ return this.connected;
193
+ }
194
+
195
+ private async ensureConnection(): Promise<void> {
196
+ if (!this.isConnected && !this.reconnecting) {
197
+ await this.connect();
198
+ }
199
+
200
+ // Wait for reconnection if in progress
201
+ const maxWaitTime = 30000; // 30 seconds
202
+ const startTime = Date.now();
203
+ while (this.reconnecting && Date.now() - startTime < maxWaitTime) {
204
+ await new Promise((resolve) => setTimeout(resolve, 100));
205
+ }
206
+
207
+ if (!this.isConnected) {
208
+ throw new Error("MongoDB is not connected and reconnection failed");
209
+ }
210
+ }
211
+
212
+ /**
213
+ * Get the operation timeout in milliseconds
214
+ */
215
+ protected getOperationTimeout(): number {
216
+ return this.operationTimeoutMS;
217
+ }
218
+
219
+ /**
220
+ * Execute a database operation with automatic retry on connection errors
221
+ * Note: Use mongoose's maxTimeMS option in queries for timeout control
222
+ */
223
+ protected async executeWithRetry<T>(
224
+ operation: () => Promise<T>,
225
+ operationName: string = "Database operation"
226
+ ): Promise<T> {
227
+ await this.ensureConnection();
228
+
229
+ try {
230
+ return await operation();
231
+ } catch (error: any) {
232
+ // Check if it's a timeout error from MongoDB
233
+ if (error.code === 50 || error.message?.includes("operation exceeded time limit")) {
234
+ loggers.agent.error(`${operationName} exceeded time limit`);
235
+ throw error;
236
+ }
237
+
238
+ // Check if it's a connection-related error
239
+ if (
240
+ error.name === "MongoNetworkError" ||
241
+ error.name === "MongoServerError" ||
242
+ error.message?.includes("connection") ||
243
+ error.message?.includes("disconnect")
244
+ ) {
245
+ loggers.agent.warn(
246
+ `${operationName} failed due to connection issue, attempting reconnection...`
247
+ );
248
+
249
+ await this.ensureConnection();
250
+
251
+ // Retry the operation once after reconnection
252
+ try {
253
+ return await operation();
254
+ } catch (retryError: any) {
255
+ loggers.agent.error(`${operationName} failed after retry:`, retryError);
256
+ throw retryError;
257
+ }
258
+ }
259
+
260
+ // If it's not a connection error, just throw it
261
+ throw error;
262
+ }
51
263
  }
52
- }
264
+ }
@@ -1,35 +1,75 @@
1
1
  import type { Intent } from "@ainetwork/adk/types/memory";
2
2
  import { IIntentMemory } from "@ainetwork/adk/modules";
3
- import { MongoDBMemory } from "./base.memory";
4
3
  import { IntentModel } from "../models/intent.model";
5
4
 
6
- export class MongoDBIntent extends MongoDBMemory implements IIntentMemory {
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 MongoDBIntent implements IIntentMemory {
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
+
7
24
  public async getIntent(intentId: string): Promise<Intent | undefined> {
8
- const intent = await IntentModel.findOne({ id: intentId }).lean<Intent>();
9
- return intent || undefined;
25
+ return this.executeWithRetry(async () => {
26
+ const timeout = this.getOperationTimeout();
27
+ const intent = await IntentModel.findOne({ id: intentId })
28
+ .maxTimeMS(timeout)
29
+ .lean<Intent>();
30
+ return intent || undefined;
31
+ }, `getIntent(${intentId})`);
10
32
  };
11
33
 
12
- public async getIntentByName(intentName: string): Promise<Intent | undefined> {
13
- const intent = await IntentModel.findOne({ name: intentName }).lean<Intent>();
14
- return intent || undefined;
15
- }
34
+ public async getIntentByName(intentName: string): Promise<Intent | undefined> {
35
+ return this.executeWithRetry(async () => {
36
+ const timeout = this.getOperationTimeout();
37
+ const intent = await IntentModel.findOne({ name: intentName })
38
+ .maxTimeMS(timeout)
39
+ .lean<Intent>();
40
+ return intent || undefined;
41
+ }, `getIntentByName(${intentName})`);
42
+ }
16
43
 
17
- public async saveIntent(intent: Intent): Promise<void> {
18
- await IntentModel.create(intent);
44
+ public async saveIntent(intent: Intent): Promise<void> {
45
+ return this.executeWithRetry(async () => {
46
+ await IntentModel.create(intent);
47
+ }, `saveIntent(${intent.id})`);
19
48
  };
20
49
 
21
- public async updateIntent(intentId: string, intent: Intent): Promise<void> {
22
- await IntentModel.updateOne({
23
- id: intentId,
24
- }, intent);
50
+ public async updateIntent(intentId: string, intent: Intent): Promise<void> {
51
+ return this.executeWithRetry(async () => {
52
+ const timeout = this.getOperationTimeout();
53
+ await IntentModel.updateOne({
54
+ id: intentId,
55
+ }, intent).maxTimeMS(timeout);
56
+ }, `updateIntent(${intentId})`);
25
57
  };
26
58
 
27
- public async deleteIntent(intentId: string): Promise<void> {
28
- await IntentModel.deleteOne({ id: intentId });
59
+ public async deleteIntent(intentId: string): Promise<void> {
60
+ return this.executeWithRetry(async () => {
61
+ const timeout = this.getOperationTimeout();
62
+ await IntentModel.deleteOne({ id: intentId }).maxTimeMS(timeout);
63
+ }, `deleteIntent(${intentId})`);
29
64
  };
30
65
 
31
- public async listIntents(): Promise<Intent[]> {
32
- const intents = await IntentModel.find().lean<Intent[]>();
33
- return intents;
66
+ public async listIntents(): Promise<Intent[]> {
67
+ return this.executeWithRetry(async () => {
68
+ const timeout = this.getOperationTimeout();
69
+ const intents = await IntentModel.find()
70
+ .maxTimeMS(timeout)
71
+ .lean<Intent[]>();
72
+ return intents;
73
+ }, `listIntents()`);
34
74
  };
35
- }
75
+ }