universal-ai-brain
Version:
🧠 UNIVERSAL AI BRAIN 3.3 - The world's most advanced cognitive architecture with 24 specialized systems, MongoDB 8.1 $rankFusion hybrid search, latest Voyage 3.5 embeddings, and framework-agnostic design. Works with Mastra, Vercel AI, LangChain, OpenAI A
1,039 lines (958 loc) • 34 kB
text/typescript
/**
* @file EpisodicMemoryCollection - MongoDB Atlas rich document storage for episodic memories
*
* This collection demonstrates MongoDB Atlas rich document storage capabilities for episodic memory.
* Based on official MongoDB Atlas documentation: https://www.mongodb.com/docs/manual/tutorial/query-documents/
*
* CRITICAL: This uses MongoDB Atlas EXCLUSIVE features:
* - Rich BSON document storage (Atlas optimized)
* - Nested documents and arrays for complex experiences
* - Advanced querying capabilities (Atlas enhanced)
* - Complex data modeling for episodic memories
*
* Features:
* - Rich document storage for complex episodic memories
* - Nested documents for multi-layered experiences
* - Array storage for sequential events and interactions
* - Complex querying for episodic retrieval
* - Temporal and contextual memory organization
*/
import { Db, ObjectId } from 'mongodb';
import { BaseCollection, BaseDocument } from './BaseCollection';
export interface EpisodicMemory extends BaseDocument {
agentId: string;
sessionId?: string;
timestamp: Date;
// Episodic memory identification
episode: {
id: string;
type: 'experience' | 'interaction' | 'learning' | 'decision' | 'observation' | 'reflection';
category: 'personal' | 'professional' | 'social' | 'educational' | 'emotional' | 'procedural';
importance: number; // 0-1 importance score
vividness: number; // 0-1 how vivid/clear the memory is
confidence: number; // 0-1 confidence in memory accuracy
// Core experience data (rich nested document)
experience: {
// What happened - the main event/experience
event: {
name: string;
description: string;
type: string;
duration: number; // milliseconds
outcome: 'success' | 'failure' | 'partial' | 'unknown';
significance: number; // 0-1
};
// When it happened - temporal context
temporal: {
startTime: Date;
endTime: Date;
duration: number; // milliseconds
timeOfDay: 'morning' | 'afternoon' | 'evening' | 'night';
dayOfWeek: string;
season?: string;
relativeTime: string; // "2 hours ago", "last week", etc.
};
// Where it happened - spatial context
spatial: {
location: string;
environment: string;
coordinates?: { lat: number; lng: number };
setting: 'indoor' | 'outdoor' | 'virtual' | 'mixed';
proximity: Record<string, number>; // distances to important objects/people
};
// Who was involved - social context (nested array)
participants: Array<{
id: string;
name: string;
role: string;
relationship: string;
involvement: 'primary' | 'secondary' | 'observer' | 'mentioned';
emotions: Array<{
emotion: string;
intensity: number; // 0-1
duration: number; // milliseconds
}>;
actions: Array<{
action: string;
timestamp: Date;
impact: number; // -1 to 1
}>;
}>;
// What was the context - environmental and situational
context: {
// Physical environment
physical: {
weather?: string;
lighting: string;
noise_level: number; // 0-1
temperature?: number;
objects: Array<{
object: string;
relevance: number; // 0-1
interaction: boolean;
}>;
};
// Social environment
social: {
group_size: number;
group_dynamics: string;
social_roles: Record<string, string>;
communication_style: string;
cultural_context: Record<string, any>;
};
// Cognitive environment
cognitive: {
mental_state: string;
attention_level: number; // 0-1
stress_level: number; // 0-1
motivation: number; // 0-1
goals: Array<{
goal: string;
priority: number; // 0-1
achieved: boolean;
}>;
};
// Emotional environment
emotional: {
mood: string;
emotional_state: Array<{
emotion: string;
intensity: number; // 0-1
valence: number; // -1 to 1 (negative to positive)
arousal: number; // 0-1 (calm to excited)
}>;
emotional_triggers: string[];
emotional_regulation: string;
};
};
// Sensory details (rich nested arrays)
sensory: {
visual: Array<{
description: string;
vividness: number; // 0-1
color_palette: string[];
movement: boolean;
focus_point: string;
}>;
auditory: Array<{
sound: string;
volume: number; // 0-1
pitch: string;
duration: number; // milliseconds
emotional_impact: number; // -1 to 1
}>;
tactile: Array<{
sensation: string;
intensity: number; // 0-1
texture: string;
temperature: string;
location: string; // on body
}>;
olfactory: Array<{
smell: string;
intensity: number; // 0-1
pleasantness: number; // -1 to 1
associations: string[];
}>;
gustatory: Array<{
taste: string;
intensity: number; // 0-1
pleasantness: number; // -1 to 1
associations: string[];
}>;
};
// Actions and behaviors (sequential array)
actions: Array<{
sequence: number;
timestamp: Date;
actor: string; // who performed the action
action: {
type: string;
description: string;
intent: string;
method: string;
tools_used: string[];
effort_level: number; // 0-1
};
result: {
immediate: string;
delayed?: string;
unexpected?: string;
satisfaction: number; // 0-1
};
learning: {
new_knowledge: string[];
skills_practiced: string[];
mistakes_made: string[];
insights_gained: string[];
};
}>;
// Dialogue and communication (nested conversation structure)
communication: Array<{
sequence: number;
timestamp: Date;
speaker: string;
listener: string[];
content: {
verbal: {
words: string;
tone: string;
volume: number; // 0-1
pace: string;
language: string;
};
nonverbal: {
gestures: string[];
facial_expression: string;
body_language: string;
eye_contact: boolean;
proximity: number; // distance in meters
};
intent: string;
emotion: string;
subtext?: string;
};
response: {
immediate: string;
emotional: string;
behavioral: string;
understanding: number; // 0-1
};
}>;
};
// Memory processing and organization
processing: {
// Encoding details
encoding: {
attention_level: number; // 0-1 during encoding
encoding_strategy: string;
interference: string[];
consolidation_status: 'fresh' | 'consolidating' | 'consolidated' | 'reconsolidating';
rehearsal_count: number;
};
// Retrieval patterns
retrieval: {
access_count: number;
last_accessed: Date;
retrieval_cues: Array<{
cue: string;
effectiveness: number; // 0-1
type: 'temporal' | 'spatial' | 'semantic' | 'emotional' | 'sensory';
}>;
retrieval_context: Array<{
context: string;
success_rate: number; // 0-1
}>;
};
// Memory connections (rich relationship mapping)
connections: {
// Similar episodes
similar_episodes: Array<{
episode_id: string;
similarity_score: number; // 0-1
similarity_type: 'temporal' | 'spatial' | 'semantic' | 'emotional' | 'procedural';
shared_elements: string[];
}>;
// Causal relationships
causal_links: Array<{
related_episode_id: string;
relationship_type: 'cause' | 'effect' | 'enabling' | 'preventing';
strength: number; // 0-1
confidence: number; // 0-1
}>;
// Thematic connections
themes: Array<{
theme: string;
relevance: number; // 0-1
related_episodes: string[];
}>;
// Emotional connections
emotional_links: Array<{
emotion: string;
intensity: number; // 0-1
related_episodes: string[];
emotional_pattern: string;
}>;
};
// Memory evolution and updates
evolution: {
original_version: Date;
modifications: Array<{
timestamp: Date;
type: 'detail_added' | 'detail_changed' | 'interpretation_updated' | 'connection_added';
description: string;
confidence_change: number; // change in confidence
trigger: string; // what caused the modification
}>;
stability: number; // 0-1 how stable/unchanging the memory is
reconstruction_count: number; // how many times memory has been reconstructed
};
};
// Learning and insights derived from episode (restructured to avoid parallel arrays)
learning: {
// Combined learning items to avoid parallel array indexing issues
learningItems: Array<{
id: string;
type: 'knowledge' | 'skill' | 'insight';
category: 'factual' | 'procedural' | 'conceptual' | 'metacognitive' | 'self_knowledge' | 'world_knowledge' | 'relationship_knowledge' | 'strategic_knowledge';
content: string;
confidence: number; // 0-1
generalizability?: number; // 0-1 (for knowledge)
application_contexts?: string[]; // (for knowledge)
level_before?: number; // 0-1 (for skills)
level_after?: number; // 0-1 (for skills)
practice_quality?: number; // 0-1 (for skills)
feedback_received?: string[]; // (for skills)
depth?: number; // 0-1 (for insights)
actionability?: number; // 0-1 (for insights)
emotional_impact?: number; // -1 to 1 (for insights)
}>;
// Behavioral patterns identified
patterns: Array<{
pattern: string;
frequency: number;
effectiveness: number; // 0-1
contexts: string[];
recommendations: string[];
}>;
};
// Emotional and psychological aspects
psychology: {
// Emotional processing
emotions: Array<{
emotion: string;
intensity: number; // 0-1
duration: number; // milliseconds
trigger: string;
regulation_strategy: string;
resolution: string;
}>;
// Psychological impact
impact: {
self_concept: number; // -1 to 1 impact on self-concept
confidence: number; // -1 to 1 impact on confidence
motivation: number; // -1 to 1 impact on motivation
stress_level: number; // -1 to 1 impact on stress
life_satisfaction: number; // -1 to 1 impact on life satisfaction
};
// Coping and adaptation
coping: {
strategies_used: string[];
effectiveness: Record<string, number>; // strategy -> effectiveness (0-1)
support_sought: string[];
adaptation_outcome: string;
};
};
};
// Metadata and quality indicators
metadata: {
framework: string;
version: string;
source: string;
reliability: number; // 0-1
completeness: number; // 0-1 how complete the memory record is
lastValidated: Date;
// Memory quality indicators
quality: {
detail_richness: number; // 0-1
coherence: number; // 0-1 internal consistency
plausibility: number; // 0-1 how plausible the memory is
uniqueness: number; // 0-1 how unique/distinctive
};
// Storage and retrieval optimization
storage: {
compression_level: number; // 0-1
indexing_priority: number; // 0-1
archival_status: 'active' | 'archived' | 'compressed' | 'deleted';
backup_copies: number;
};
};
}
export interface EpisodicFilter {
agentId?: string;
'episode.type'?: string;
'episode.category'?: string;
'episode.importance'?: { $gte?: number; $lte?: number };
'episode.experience.temporal.startTime'?: { $gte?: Date; $lte?: Date };
'episode.experience.participants.name'?: string;
'episode.experience.spatial.location'?: string;
timestamp?: { $gte?: Date; $lte?: Date };
}
/**
* EpisodicMemoryCollection - Manages episodic memories using MongoDB Atlas rich document storage
*
* This collection demonstrates MongoDB Atlas EXCLUSIVE features:
* - Rich BSON document storage for complex episodic memories
* - Nested documents and arrays for multi-layered experiences
* - Advanced querying capabilities for episodic retrieval
* - Complex data modeling for temporal and contextual memory organization
*
* CRITICAL: Optimized for MongoDB Atlas (not local MongoDB)
*/
export class EpisodicMemoryCollection extends BaseCollection<EpisodicMemory> {
protected collectionName = 'agent_episodic_memories';
constructor(db: Db) {
super(db);
this.collection = db.collection<EpisodicMemory>(this.collectionName);
}
/**
* Create indexes optimized for episodic memory retrieval and Atlas performance
* Following MongoDB Atlas documentation for rich document storage optimization
*/
async createIndexes(): Promise<void> {
try {
// Agent and episode identification index
await this.collection.createIndex({
agentId: 1,
'episode.id': 1,
'episode.type': 1,
timestamp: -1
}, {
name: 'agent_episode_type',
background: true
});
// Importance and temporal index for priority retrieval
await this.collection.createIndex({
'episode.importance': -1,
'episode.experience.temporal.startTime': -1,
'episode.vividness': -1
}, {
name: 'importance_temporal_vividness',
background: true
});
// Spatial and location-based index
await this.collection.createIndex({
'episode.experience.spatial.location': 1,
'episode.experience.spatial.environment': 1,
'episode.category': 1
}, {
name: 'spatial_location_category',
background: true
});
// Participant and social context index
await this.collection.createIndex({
'episode.experience.participants.name': 1,
'episode.experience.participants.role': 1,
'episode.type': 1
}, {
name: 'participants_social_context',
background: true
});
// Emotional and psychological index
await this.collection.createIndex({
'episode.psychology.emotions.emotion': 1,
'episode.psychology.emotions.intensity': -1,
'episode.psychology.impact.self_concept': -1
}, {
name: 'emotional_psychological_impact',
background: true
});
// Learning and knowledge index
await this.collection.createIndex({
'episode.learning.knowledge.type': 1,
'episode.learning.insights.type': 1,
'episode.learning.skills.skill': 1
}, {
name: 'learning_knowledge_skills',
background: true
});
// Memory connections and relationships index
await this.collection.createIndex({
'episode.processing.connections.similar_episodes.episode_id': 1,
'episode.processing.connections.causal_links.related_episode_id': 1,
'episode.processing.connections.themes.theme': 1
}, {
name: 'memory_connections_relationships',
background: true
});
// Retrieval and access patterns index
await this.collection.createIndex({
'episode.processing.retrieval.access_count': -1,
'episode.processing.retrieval.last_accessed': -1,
'episode.processing.encoding.consolidation_status': 1
}, {
name: 'retrieval_access_patterns',
background: true
});
// Quality and reliability index
await this.collection.createIndex({
'metadata.quality.detail_richness': -1,
'metadata.quality.coherence': -1,
'metadata.reliability': -1
}, {
name: 'quality_reliability',
background: true
});
console.log('✅ EpisodicMemoryCollection indexes created successfully');
console.log('📝 Note: Optimized for MongoDB Atlas rich document storage capabilities');
} catch (error) {
console.error('❌ Error creating EpisodicMemoryCollection indexes:', error);
throw error;
}
}
/**
* Store an episodic memory
*/
async storeEpisodicMemory(memory: Omit<EpisodicMemory, '_id' | 'createdAt' | 'updatedAt'>): Promise<string> {
const doc: EpisodicMemory = {
...memory,
_id: new ObjectId(),
createdAt: new Date(),
updatedAt: new Date()
};
const result = await this.collection.insertOne(doc);
return result.insertedId.toString();
}
/**
* Get episodic memories for an agent
*/
async getAgentEpisodicMemories(agentId: string, filter: Partial<EpisodicFilter> = {}): Promise<EpisodicMemory[]> {
const query: EpisodicFilter = { agentId, ...filter };
return await this.collection.find(query).sort({ 'episode.importance': -1, timestamp: -1 }).toArray();
}
/**
* Find memories by rich contextual search using MongoDB Atlas advanced querying
* Based on official MongoDB Atlas documentation for complex document queries
*/
async findMemoriesByContext(
agentId: string,
context: {
temporal?: { startDate?: Date; endDate?: Date; timeOfDay?: string };
spatial?: { location?: string; environment?: string };
social?: { participants?: string[]; groupSize?: number };
emotional?: { emotions?: string[]; minIntensity?: number };
thematic?: { themes?: string[]; categories?: string[] };
},
options: {
limit?: number;
minImportance?: number;
sortBy?: 'importance' | 'recency' | 'vividness' | 'relevance';
} = {}
): Promise<EpisodicMemory[]> {
const pipeline: any[] = [
{ $match: { agentId } }
];
// Build complex query based on context
const contextQuery: any = {};
if (context.temporal) {
if (context.temporal.startDate || context.temporal.endDate) {
contextQuery['episode.experience.temporal.startTime'] = {};
if (context.temporal.startDate) {
contextQuery['episode.experience.temporal.startTime'].$gte = context.temporal.startDate;
}
if (context.temporal.endDate) {
contextQuery['episode.experience.temporal.startTime'].$lte = context.temporal.endDate;
}
}
if (context.temporal.timeOfDay) {
contextQuery['episode.experience.temporal.timeOfDay'] = context.temporal.timeOfDay;
}
}
if (context.spatial) {
if (context.spatial.location) {
contextQuery['episode.experience.spatial.location'] = { $regex: context.spatial.location, $options: 'i' };
}
if (context.spatial.environment) {
contextQuery['episode.experience.spatial.environment'] = { $regex: context.spatial.environment, $options: 'i' };
}
}
if (context.social) {
if (context.social.participants && context.social.participants.length > 0) {
contextQuery['episode.experience.participants.name'] = { $in: context.social.participants };
}
if (context.social.groupSize) {
contextQuery['episode.experience.context.social.group_size'] = context.social.groupSize;
}
}
if (context.emotional) {
if (context.emotional.emotions && context.emotional.emotions.length > 0) {
contextQuery['episode.psychology.emotions.emotion'] = { $in: context.emotional.emotions };
}
if (context.emotional.minIntensity) {
contextQuery['episode.psychology.emotions.intensity'] = { $gte: context.emotional.minIntensity };
}
}
if (context.thematic) {
if (context.thematic.themes && context.thematic.themes.length > 0) {
contextQuery['episode.processing.connections.themes.theme'] = { $in: context.thematic.themes };
}
if (context.thematic.categories && context.thematic.categories.length > 0) {
contextQuery['episode.category'] = { $in: context.thematic.categories };
}
}
if (options.minImportance) {
contextQuery['episode.importance'] = { $gte: options.minImportance };
}
if (Object.keys(contextQuery).length > 0) {
pipeline.push({ $match: contextQuery });
}
// Add sorting
const sortField = options.sortBy || 'importance';
const sortStage: any = {};
switch (sortField) {
case 'importance':
sortStage['episode.importance'] = -1;
break;
case 'recency':
sortStage['episode.experience.temporal.startTime'] = -1;
break;
case 'vividness':
sortStage['episode.vividness'] = -1;
break;
case 'relevance':
sortStage['episode.processing.retrieval.access_count'] = -1;
break;
}
pipeline.push({ $sort: sortStage });
// Add limit
if (options.limit) {
pipeline.push({ $limit: options.limit });
}
return await this.collection.aggregate(pipeline).toArray() as EpisodicMemory[];
}
/**
* Find episodic patterns using MongoDB Atlas aggregation
*/
async findEpisodicPatterns(agentId: string): Promise<{
commonExperiences: Array<{ type: string; frequency: number; averageImportance: number }>;
frequentLocations: Array<{ location: string; frequency: number; averageVividness: number }>;
socialPatterns: Array<{ participant: string; frequency: number; averageEmotionalImpact: number }>;
emotionalPatterns: Array<{ emotion: string; frequency: number; averageIntensity: number }>;
learningPatterns: Array<{ knowledgeType: string; frequency: number; averageConfidence: number }>;
temporalPatterns: Array<{ timeOfDay: string; frequency: number; averageImportance: number }>;
}> {
const pipeline = [
{ $match: { agentId } },
{
$facet: {
commonExperiences: [
{
$group: {
_id: '$episode.type',
frequency: { $sum: 1 },
averageImportance: { $avg: '$episode.importance' }
}
},
{ $sort: { frequency: -1 } },
{ $limit: 10 },
{
$project: {
type: '$_id',
frequency: 1,
averageImportance: 1,
_id: 0
}
}
],
frequentLocations: [
{
$group: {
_id: '$episode.experience.spatial.location',
frequency: { $sum: 1 },
averageVividness: { $avg: '$episode.vividness' }
}
},
{ $sort: { frequency: -1 } },
{ $limit: 10 },
{
$project: {
location: '$_id',
frequency: 1,
averageVividness: 1,
_id: 0
}
}
],
socialPatterns: [
{ $unwind: '$episode.experience.participants' },
{
$group: {
_id: '$episode.experience.participants.name',
frequency: { $sum: 1 },
averageEmotionalImpact: { $avg: '$episode.psychology.impact.self_concept' }
}
},
{ $sort: { frequency: -1 } },
{ $limit: 10 },
{
$project: {
participant: '$_id',
frequency: 1,
averageEmotionalImpact: 1,
_id: 0
}
}
],
emotionalPatterns: [
{ $unwind: '$episode.psychology.emotions' },
{
$group: {
_id: '$episode.psychology.emotions.emotion',
frequency: { $sum: 1 },
averageIntensity: { $avg: '$episode.psychology.emotions.intensity' }
}
},
{ $sort: { frequency: -1 } },
{ $limit: 10 },
{
$project: {
emotion: '$_id',
frequency: 1,
averageIntensity: 1,
_id: 0
}
}
],
learningPatterns: [
{ $unwind: '$episode.learning.knowledge' },
{
$group: {
_id: '$episode.learning.knowledge.type',
frequency: { $sum: 1 },
averageConfidence: { $avg: '$episode.learning.knowledge.confidence' }
}
},
{ $sort: { frequency: -1 } },
{
$project: {
knowledgeType: '$_id',
frequency: 1,
averageConfidence: 1,
_id: 0
}
}
],
temporalPatterns: [
{
$group: {
_id: '$episode.experience.temporal.timeOfDay',
frequency: { $sum: 1 },
averageImportance: { $avg: '$episode.importance' }
}
},
{ $sort: { frequency: -1 } },
{
$project: {
timeOfDay: '$_id',
frequency: 1,
averageImportance: 1,
_id: 0
}
}
]
}
}
];
const results = await this.collection.aggregate(pipeline).toArray();
return results[0] as any || {
commonExperiences: [],
frequentLocations: [],
socialPatterns: [],
emotionalPatterns: [],
learningPatterns: [],
temporalPatterns: []
};
}
/**
* Update memory access patterns and retrieval statistics
*/
async updateMemoryAccess(episodeId: string, retrievalContext: string): Promise<void> {
await this.collection.updateOne(
{ 'episode.id': episodeId },
{
$inc: { 'episode.processing.retrieval.access_count': 1 },
$set: { 'episode.processing.retrieval.last_accessed': new Date() },
$push: {
'episode.processing.retrieval.retrieval_context': {
context: retrievalContext,
timestamp: new Date(),
success_rate: 1.0
}
}
}
);
}
/**
* Find related memories using rich document relationships
*/
async findRelatedMemories(
episodeId: string,
relationshipTypes: Array<'similar' | 'causal' | 'thematic' | 'emotional'> = ['similar'],
limit: number = 10
): Promise<Array<{
memory: EpisodicMemory;
relationshipType: string;
strength: number;
sharedElements: string[];
}>> {
// First get the source memory
const sourceMemory = await this.collection.findOne({ 'episode.id': episodeId });
if (!sourceMemory) {
return [];
}
const relatedMemories = [];
for (const relType of relationshipTypes) {
let relatedIds: string[] = [];
switch (relType) {
case 'similar':
relatedIds = sourceMemory.episode.processing.connections.similar_episodes.map(se => se.episode_id);
break;
case 'causal':
relatedIds = sourceMemory.episode.processing.connections.causal_links.map(cl => cl.related_episode_id);
break;
case 'thematic':
// Find memories with shared themes
const themes = sourceMemory.episode.processing.connections.themes.map(t => t.theme);
if (themes.length > 0) {
const thematicMemories = await this.collection.find({
'episode.processing.connections.themes.theme': { $in: themes },
'episode.id': { $ne: episodeId }
}).limit(limit).toArray();
for (const memory of thematicMemories) {
relatedMemories.push({
memory,
relationshipType: 'thematic',
strength: 0.7, // Default thematic strength
sharedElements: themes
});
}
}
continue;
case 'emotional':
// Find memories with similar emotional patterns
const emotions = sourceMemory.episode.psychology.emotions.map(e => e.emotion);
if (emotions.length > 0) {
const emotionalMemories = await this.collection.find({
'episode.psychology.emotions.emotion': { $in: emotions },
'episode.id': { $ne: episodeId }
}).limit(limit).toArray();
for (const memory of emotionalMemories) {
relatedMemories.push({
memory,
relationshipType: 'emotional',
strength: 0.6, // Default emotional strength
sharedElements: emotions
});
}
}
continue;
}
// For similar and causal relationships, get the actual memories
if (relatedIds.length > 0) {
const memories = await this.collection.find({
'episode.id': { $in: relatedIds }
}).limit(limit).toArray();
for (const memory of memories) {
const connection = relType === 'similar'
? sourceMemory.episode.processing.connections.similar_episodes.find(se => se.episode_id === memory.episode.id)
: sourceMemory.episode.processing.connections.causal_links.find(cl => cl.related_episode_id === memory.episode.id);
if (connection) {
relatedMemories.push({
memory,
relationshipType: relType,
strength: (connection as any).similarity_score || (connection as any).strength || 0.5,
sharedElements: (connection as any).shared_elements || []
});
}
}
}
}
// Sort by strength and return top results
return relatedMemories
.sort((a, b) => b.strength - a.strength)
.slice(0, limit);
}
/**
* Get memory statistics and insights
*/
async getMemoryStatistics(agentId: string): Promise<{
totalMemories: number;
averageImportance: number;
averageVividness: number;
memoryTypes: Record<string, number>;
temporalDistribution: Record<string, number>;
emotionalProfile: Record<string, number>;
learningProgress: {
totalKnowledge: number;
skillsDeveloped: number;
insightsGained: number;
};
}> {
const pipeline = [
{ $match: { agentId } },
{
$group: {
_id: null,
totalMemories: { $sum: 1 },
averageImportance: { $avg: '$episode.importance' },
averageVividness: { $avg: '$episode.vividness' },
memoryTypes: { $push: '$episode.type' },
timeOfDay: { $push: '$episode.experience.temporal.timeOfDay' },
emotions: { $push: '$episode.psychology.emotions' },
knowledge: { $push: '$episode.learning.knowledge' },
skills: { $push: '$episode.learning.skills' },
insights: { $push: '$episode.learning.insights' }
}
}
];
const results = await this.collection.aggregate(pipeline).toArray();
const data = results[0] as any;
if (!data) {
return {
totalMemories: 0,
averageImportance: 0,
averageVividness: 0,
memoryTypes: {},
temporalDistribution: {},
emotionalProfile: {},
learningProgress: { totalKnowledge: 0, skillsDeveloped: 0, insightsGained: 0 }
};
}
// Process memory types
const memoryTypes: Record<string, number> = {};
data.memoryTypes.forEach((type: string) => {
memoryTypes[type] = (memoryTypes[type] || 0) + 1;
});
// Process temporal distribution
const temporalDistribution: Record<string, number> = {};
data.timeOfDay.forEach((time: string) => {
if (time) {
temporalDistribution[time] = (temporalDistribution[time] || 0) + 1;
}
});
// Process emotional profile
const emotionalProfile: Record<string, number> = {};
data.emotions.forEach((emotionArray: any[]) => {
if (Array.isArray(emotionArray)) {
emotionArray.forEach((emotion: any) => {
if (emotion && emotion.emotion) {
emotionalProfile[emotion.emotion] = (emotionalProfile[emotion.emotion] || 0) + 1;
}
});
}
});
// Process learning progress
const totalKnowledge = data.knowledge.reduce((sum: number, knowledgeArray: any[]) => {
return sum + (Array.isArray(knowledgeArray) ? knowledgeArray.length : 0);
}, 0);
const skillsDeveloped = data.skills.reduce((sum: number, skillsArray: any[]) => {
return sum + (Array.isArray(skillsArray) ? skillsArray.length : 0);
}, 0);
const insightsGained = data.insights.reduce((sum: number, insightsArray: any[]) => {
return sum + (Array.isArray(insightsArray) ? insightsArray.length : 0);
}, 0);
return {
totalMemories: data.totalMemories,
averageImportance: data.averageImportance || 0,
averageVividness: data.averageVividness || 0,
memoryTypes,
temporalDistribution,
emotionalProfile,
learningProgress: {
totalKnowledge,
skillsDeveloped,
insightsGained
}
};
}
}