contextual-agent-sdk
Version:
SDK for building AI agents with seamless voice-text context switching
215 lines • 7.62 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MongoStorageProvider = void 0;
const mongodb_1 = require("mongodb");
class MongoStorageProvider {
client;
db;
collection;
eventHandlers = new Set();
cleanupTimer;
constructor(config) {
if (!config.url) {
throw new Error('MongoDB URL is required');
}
this.client = new mongodb_1.MongoClient(config.url, {
auth: config.username ? {
username: config.username,
password: config.password
} : undefined,
tls: config.ssl,
tlsCertificateKeyFile: config.certPath,
maxPoolSize: config.maxConnections,
connectTimeoutMS: config.timeout
});
this.initialize(config).catch(error => {
this.emitEvent(this.createEvent('error', error));
});
}
async initialize(config) {
await this.client.connect();
this.db = this.client.db();
this.collection = this.db.collection('sessions');
await this.collection.createIndex({ userId: 1 });
await this.collection.createIndex({ 'lastActivity': 1 }, { expireAfterSeconds: 3600 });
if (config.cleanupInterval && config.maxAge) {
this.cleanupTimer = setInterval(() => {
this.cleanup(config.maxAge).catch(error => {
this.emitEvent(this.createEvent('error', error));
});
}, config.cleanupInterval);
}
}
async createSession(sessionId, session) {
if (!this.collection)
throw new Error('MongoDB not initialized');
const mongoSession = {
...session,
_id: sessionId
};
await this.collection.insertOne(mongoSession);
this.emitEvent(this.createEvent('session_created', sessionId));
}
async getSession(sessionId) {
if (!this.collection)
throw new Error('MongoDB not initialized');
const session = await this.collection.findOne({ _id: sessionId });
if (!session)
return null;
return this.convertDates(session);
}
async updateSession(sessionId, session) {
if (!this.collection)
throw new Error('MongoDB not initialized');
await this.collection.updateOne({ _id: sessionId }, { $set: session });
this.emitEvent(this.createEvent('session_updated', sessionId));
}
async deleteSession(sessionId) {
if (!this.collection)
throw new Error('MongoDB not initialized');
const result = await this.collection.deleteOne({ _id: sessionId });
const deleted = result.deletedCount === 1;
if (deleted) {
this.emitEvent(this.createEvent('session_deleted', sessionId));
}
return deleted;
}
async getSessions(filter) {
if (!this.collection)
throw new Error('MongoDB not initialized');
const query = this.buildMongoQuery(filter);
const sessions = await this.collection.find(query).toArray();
return sessions.map(session => this.convertDates(session));
}
async deleteSessions(filter) {
if (!this.collection)
throw new Error('MongoDB not initialized');
const query = this.buildMongoQuery(filter);
const result = await this.collection.deleteMany(query);
return result.deletedCount;
}
async cleanup(maxAge) {
if (!this.collection)
throw new Error('MongoDB not initialized');
this.emitEvent(this.createEvent('cleanup_started'));
const result = await this.collection.deleteMany({
lastActivity: {
$lt: new Date(Date.now() - maxAge)
}
});
this.emitEvent(this.createEvent('cleanup_completed', result.deletedCount));
}
async healthCheck() {
try {
if (!this.db)
return false;
await this.db.command({ ping: 1 });
return true;
}
catch {
return false;
}
}
async getStats() {
if (!this.collection)
throw new Error('MongoDB not initialized');
const sessions = await this.getSessions();
const now = Date.now();
const oneDayAgo = now - 24 * 60 * 60 * 1000;
const activeSessions = sessions.filter(s => s.lastActivity.getTime() > oneDayAgo);
const durations = sessions.map(s => s.lastActivity.getTime() - s.startTime.getTime());
const avgDuration = durations.length > 0
? durations.reduce((a, b) => a + b, 0) / durations.length
: 0;
const modalityCount = sessions.reduce((acc, s) => {
acc[s.currentModality]++;
return acc;
}, { text: 0, voice: 0 });
const storageSize = sessions.reduce((size, session) => {
return size + JSON.stringify(session).length;
}, 0);
return {
totalSessions: sessions.length,
activeSessionsLast24h: activeSessions.length,
averageSessionDuration: avgDuration,
modalityDistribution: modalityCount,
storageSize
};
}
on(handler) {
this.eventHandlers.add(handler);
}
off(handler) {
this.eventHandlers.delete(handler);
}
emitEvent(event) {
this.eventHandlers.forEach(handler => handler(event));
}
createEvent(type, data) {
switch (type) {
case 'session_created':
case 'session_updated':
case 'session_deleted':
return { type, sessionId: data };
case 'cleanup_completed':
return { type, deletedCount: data };
case 'error':
return { type, error: data };
default:
return { type };
}
}
buildMongoQuery(filter) {
if (!filter)
return {};
const query = {};
if (filter.userId) {
query.userId = filter.userId;
}
if (filter.modality) {
query.currentModality = filter.modality;
}
if (filter.startTime) {
query.startTime = {};
if (filter.startTime.from) {
query.startTime.$gte = filter.startTime.from;
}
if (filter.startTime.to) {
query.startTime.$lte = filter.startTime.to;
}
}
if (filter.lastActivity) {
query.lastActivity = {};
if (filter.lastActivity.from) {
query.lastActivity.$gte = filter.lastActivity.from;
}
if (filter.lastActivity.to) {
query.lastActivity.$lte = filter.lastActivity.to;
}
}
return query;
}
convertDates(session) {
const { _id, ...sessionData } = session;
return {
...sessionData,
startTime: new Date(session.startTime),
lastActivity: new Date(session.lastActivity),
context: {
...session.context,
memoryBank: session.context.memoryBank.map(memory => ({
...memory,
timestamp: new Date(memory.timestamp)
}))
}
};
}
async shutdown() {
if (this.cleanupTimer) {
clearInterval(this.cleanupTimer);
}
await this.client.close();
}
}
exports.MongoStorageProvider = MongoStorageProvider;
//# sourceMappingURL=MongoStorageProvider.js.map