contaigents
Version:
Modular AI Content Ecosystem with Audio Generation
246 lines (245 loc) • 9.86 kB
JavaScript
import { LocalKnowledgeBase } from './LocalKnowledgeBase.js';
/**
* Learning engine for continuous improvement and pattern recognition
*/
export class LearningEngine {
constructor() {
this.learningHistory = new Map();
this.knowledgeBase = new LocalKnowledgeBase();
}
/**
* Learn from successful tool execution
*/
async learnFromToolSuccess(toolName, parameters, result, context) {
const pattern = {
tool: toolName,
parameters,
context: {
projectType: context.metadata.type,
fileCount: context.fileTree.length
},
outcome: 'success',
timestamp: Date.now()
};
await this.knowledgeBase.storeKnowledge('pattern', `Successful ${toolName} usage: ${JSON.stringify(pattern)}`, 'tool_execution', 0.8);
this.recordLearningEvent('tool_success', pattern);
}
/**
* Learn from tool failures
*/
async learnFromToolFailure(toolName, parameters, error, context) {
const antiPattern = {
tool: toolName,
parameters,
context: {
projectType: context.metadata.type,
fileCount: context.fileTree.length
},
error,
timestamp: Date.now()
};
await this.knowledgeBase.storeKnowledge('rule', `Avoid ${toolName} with these parameters: ${JSON.stringify(antiPattern)}`, 'tool_failure', 0.7);
this.recordLearningEvent('tool_failure', antiPattern);
}
/**
* Learn from conversation patterns
*/
async learnFromConversation(conversation) {
const userMessages = conversation.messages.filter(m => m.role === 'user');
const assistantMessages = conversation.messages.filter(m => m.role === 'assistant');
// Learn from successful conversation patterns
if (conversation.status === 'completed' && userMessages.length > 1) {
const conversationPattern = {
projectType: conversation.context.metadata.type,
messageCount: conversation.messages.length,
duration: conversation.updatedAt - conversation.createdAt,
topics: this.extractTopics(userMessages.map(m => m.content)),
successful: true
};
await this.knowledgeBase.storeKnowledge('pattern', `Successful conversation pattern: ${JSON.stringify(conversationPattern)}`, 'conversation', 0.6);
}
// Learn user preferences
await this.learnUserPreferences(userMessages, conversation.context);
}
/**
* Learn user preferences from messages
*/
async learnUserPreferences(userMessages, context) {
const preferences = this.extractPreferences(userMessages.map(m => m.content));
for (const preference of preferences) {
await this.knowledgeBase.storeKnowledge('preference', `User prefers ${preference} in ${context.metadata.type} projects`, 'user_interaction', 0.5);
}
}
/**
* Get recommendations based on learning
*/
async getRecommendations(context, currentAction) {
const relevantKnowledge = await this.knowledgeBase.getRelevantKnowledge(context, 10);
const recommendations = [];
// Generate recommendations from patterns
const patterns = relevantKnowledge.filter(k => k.type === 'pattern');
for (const pattern of patterns.slice(0, 3)) {
try {
const patternData = JSON.parse(pattern.content);
if (patternData.tool && currentAction !== patternData.tool) {
recommendations.push(`Consider using ${patternData.tool} - it has worked well in similar contexts`);
}
}
catch (error) {
// Skip malformed patterns
}
}
// Generate recommendations from rules
const rules = relevantKnowledge.filter(k => k.type === 'rule');
for (const rule of rules.slice(0, 2)) {
recommendations.push(`Recommendation: ${rule.content}`);
}
return recommendations;
}
/**
* Predict success probability for an action
*/
async predictSuccess(toolName, parameters, context) {
const relevantKnowledge = await this.knowledgeBase.getRelevantKnowledge(context);
let successCount = 0;
let failureCount = 0;
let totalRelevance = 0;
for (const knowledge of relevantKnowledge) {
try {
const data = JSON.parse(knowledge.content);
if (data.tool === toolName) {
const relevance = this.calculateParameterSimilarity(parameters, data.parameters || {});
totalRelevance += relevance;
if (data.outcome === 'success' || knowledge.type === 'pattern') {
successCount += relevance;
}
else if (data.error || knowledge.type === 'rule') {
failureCount += relevance;
}
}
}
catch (error) {
// Skip malformed knowledge
}
}
const total = successCount + failureCount;
const probability = total > 0 ? successCount / total : 0.5; // Default to neutral if no data
const confidence = Math.min(1, totalRelevance / 3); // Confidence based on amount of relevant data
const reasoning = total > 0
? `Based on ${Math.round(total)} similar past executions`
: 'No historical data available for this action';
return { probability, confidence, reasoning };
}
/**
* Optimize parameters based on learning
*/
async optimizeParameters(toolName, baseParameters, context) {
const relevantKnowledge = await this.knowledgeBase.getRelevantKnowledge(context);
const improvements = [];
const optimizedParameters = { ...baseParameters };
// Find successful patterns for this tool
const successfulPatterns = relevantKnowledge
.filter(k => k.type === 'pattern')
.map(k => {
try {
return JSON.parse(k.content);
}
catch {
return null;
}
})
.filter(data => data && data.tool === toolName && data.outcome === 'success');
// Optimize based on successful patterns
for (const pattern of successfulPatterns) {
if (pattern.parameters) {
for (const [key, value] of Object.entries(pattern.parameters)) {
if (key in baseParameters && baseParameters[key] !== value) {
optimizedParameters[key] = value;
improvements.push(`Changed ${key} to ${value} based on successful pattern`);
}
}
}
}
return { optimizedParameters, improvements };
}
/**
* Generate learning insights
*/
async generateInsights() {
const stats = await this.knowledgeBase.getKnowledgeStats();
const topPatterns = stats.mostUsed.map(k => k.content.substring(0, 100) + '...');
const recommendations = [
`You have ${stats.total} learnings with ${(stats.averageConfidence * 100).toFixed(1)}% average confidence`,
'Most successful patterns involve consistent tool usage',
'Consider reviewing and cleaning up low-confidence learnings'
];
const improvementAreas = [
'Increase tool usage consistency',
'Provide more feedback on results',
'Explore new tool combinations'
];
return {
totalLearnings: stats.total,
topPatterns,
recommendations,
improvementAreas
};
}
/**
* Helper methods
*/
recordLearningEvent(type, data) {
if (!this.learningHistory.has(type)) {
this.learningHistory.set(type, []);
}
const events = this.learningHistory.get(type);
events.push(data);
// Keep only recent events
if (events.length > 100) {
events.splice(0, events.length - 100);
}
}
extractTopics(messages) {
const topics = new Set();
const topicKeywords = ['file', 'analyze', 'write', 'read', 'summarize', 'classify', 'project', 'documentation'];
for (const message of messages) {
const words = message.toLowerCase().split(/\s+/);
for (const keyword of topicKeywords) {
if (words.includes(keyword)) {
topics.add(keyword);
}
}
}
return Array.from(topics);
}
extractPreferences(messages) {
const preferences = [];
const preferencePatterns = [
/prefer\s+(\w+)/gi,
/like\s+(\w+)/gi,
/want\s+(\w+)/gi,
/need\s+(\w+)/gi
];
for (const message of messages) {
for (const pattern of preferencePatterns) {
const matches = message.match(pattern);
if (matches) {
preferences.push(...matches);
}
}
}
return preferences.slice(0, 5); // Limit to top 5 preferences
}
calculateParameterSimilarity(params1, params2) {
const keys1 = Object.keys(params1);
const keys2 = Object.keys(params2);
const allKeys = new Set([...keys1, ...keys2]);
let matches = 0;
for (const key of allKeys) {
if (params1[key] === params2[key]) {
matches++;
}
}
return allKeys.size > 0 ? matches / allKeys.size : 0;
}
}