UNPKG

smart-thinking-mcp

Version:

Un serveur MCP avancé pour le raisonnement multi-dimensionnel, adaptatif et collaboratif

1,010 lines 42 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ThoughtGraph = void 0; const events_1 = require("events"); /** * Classe qui gère le graphe de pensées et ses opérations */ class ThoughtGraph { nodes = new Map(); hyperlinks = new Map(); sessionId; embeddingService; qualityEvaluator; eventEmitter; constructor(sessionId, embeddingService, qualityEvaluator) { this.sessionId = sessionId || this.generateUniqueId(); this.embeddingService = embeddingService; this.qualityEvaluator = qualityEvaluator; this.eventEmitter = new events_1.EventEmitter(); // Configurer les écouteurs d'événements this.setupEventListeners(); } /** * Configure les écouteurs d'événements pour la vérification continue */ setupEventListeners() { // Configurer ici des écouteurs si nécessaire } /** * Vérifie les calculs dans une pensée et les annote si nécessaire * * @param thoughtId L'identifiant de la pensée à vérifier * @param content Le contenu de la pensée */ async checkForCalculationsAndVerify(thoughtId, content) { if (!this.qualityEvaluator) return; // Détecter si la pensée contient des calculs avec des expressions régulières simples const hasSimpleCalculations = /\d+\s*[\+\-\*\/]\s*\d+\s*=/.test(content); const hasComplexCalculations = /calcul\s*(?:complexe|avancé)?\s*:?\s*([^=]+)=\s*\d+/.test(content); if (hasSimpleCalculations || hasComplexCalculations) { console.error(`Smart-Thinking: Détection en temps réel de calculs dans la pensée ${thoughtId}, vérification...`); try { // Vérifier les calculs de manière asynchrone const verifiedCalculations = await this.qualityEvaluator.detectAndVerifyCalculations(content); if (verifiedCalculations.length > 0) { // Mettre à jour le contenu de la pensée avec les annotations const updatedContent = this.qualityEvaluator.annotateThoughtWithVerifications(content, verifiedCalculations); // Mettre à jour la pensée sans déclencher à nouveau les vérifications const thought = this.nodes.get(thoughtId); if (thought) { thought.content = updatedContent; thought.metadata.calculationsVerified = true; thought.metadata.lastUpdated = new Date(); thought.metadata.verificationTimestamp = new Date(); } // Émettre un événement pour notifier que des calculs ont été vérifiés this.eventEmitter.emit('calculations-verified', { thoughtId, verifiedCalculations, updatedContent }); // Journaliser le résultat de la vérification console.error(`Smart-Thinking: ${verifiedCalculations.length} calcul(s) vérifié(s) dans la pensée ${thoughtId}`); } } catch (error) { console.error(`Smart-Thinking: Erreur lors de la vérification des calculs:`, error); } } } /** * Permet d'enregistrer un écouteur d'événement externe * * @param event Le nom de l'événement * @param listener La fonction de rappel à exécuter */ on(event, listener) { this.eventEmitter.on(event, listener); } /** * Génère un identifiant unique */ generateUniqueId() { return Date.now().toString(36) + Math.random().toString(36).substring(2); } /** * Ajoute une nouvelle pensée au graphe * * @param content Le contenu de la pensée * @param type Le type de pensée * @param connections Les connexions à d'autres pensées * @returns L'identifiant de la pensée ajoutée */ addThought(content, type = 'regular', connections = []) { const id = this.generateUniqueId(); const node = { id, content, type, timestamp: new Date(), connections: [...connections], metrics: { confidence: 0.5, // Valeur par défaut relevance: 0.5, // Valeur par défaut quality: 0.5 // Valeur par défaut }, metadata: { sessionId: this.sessionId } }; this.nodes.set(id, node); // Établir les connexions bidirectionnelles this.establishConnections(id, connections); // Émettre un événement pour notifier de l'ajout d'une pensée this.eventEmitter.emit('thought-added', id, node); // Vérifier automatiquement les calculs si nécessaire this.checkForCalculationsAndVerify(id, content); return id; } /** * Établit des connexions bidirectionnelles entre les pensées * * @param sourceId L'identifiant de la pensée source * @param connections Les connexions à établir */ establishConnections(sourceId, connections) { for (const connection of connections) { const targetNode = this.nodes.get(connection.targetId); if (targetNode) { targetNode.connections.push({ targetId: sourceId, type: this.getReciprocalConnectionType(connection.type), strength: connection.strength, description: connection.description, // Transférer les attributs si présents attributes: connection.attributes, inferred: connection.inferred, inferenceConfidence: connection.inferenceConfidence, bidirectional: connection.bidirectional }); } } } /** * Détermine le type de connexion réciproque * * @param type Le type de connexion original * @returns Le type de connexion réciproque */ getReciprocalConnectionType(type) { switch (type) { case 'supports': return 'supports'; case 'contradicts': return 'contradicts'; case 'refines': return 'derives'; case 'derives': return 'refines'; case 'branches': return 'branches'; case 'associates': return 'associates'; case 'exemplifies': return 'generalizes'; case 'generalizes': return 'exemplifies'; case 'compares': return 'compares'; case 'contrasts': return 'contrasts'; case 'questions': return 'questions'; case 'extends': return 'extended-by'; case 'analyzes': return 'analyzed-by'; case 'synthesizes': return 'component-of'; case 'applies': return 'applied-by'; case 'evaluates': return 'evaluated-by'; case 'cites': return 'cited-by'; default: return 'associates'; } } /** * Récupère une pensée par son identifiant * * @param id L'identifiant de la pensée * @returns La pensée ou undefined si non trouvée */ getThought(id) { return this.nodes.get(id); } /** * Met à jour les métriques d'une pensée * * @param id L'identifiant de la pensée * @param metrics Les nouvelles métriques * @returns true si la mise à jour a réussi, false sinon */ updateThoughtMetrics(id, metrics) { const thought = this.nodes.get(id); if (!thought) return false; thought.metrics = { ...thought.metrics, ...metrics }; return true; } /** * Récupère toutes les pensées * * @returns Un tableau de toutes les pensées */ getAllThoughts() { return Array.from(this.nodes.values()); } /** * Récupère les pensées les plus récentes * * @param limit Le nombre maximum de pensées à récupérer * @returns Un tableau des pensées les plus récentes */ getRecentThoughts(limit = 5) { return Array.from(this.nodes.values()) .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()) .slice(0, limit); } /** * Récupère les pensées connectées à une pensée spécifique * * @param thoughtId L'identifiant de la pensée * @returns Un tableau des pensées connectées */ getConnectedThoughts(thoughtId) { const thought = this.nodes.get(thoughtId); if (!thought) return []; return thought.connections .map(conn => this.nodes.get(conn.targetId)) .filter((node) => node !== undefined); } /** * Récupère les pensées les plus pertinentes pour un contexte donné * * @param context Le contexte pour lequel chercher des pensées pertinentes * @param limit Le nombre maximum de pensées à récupérer * @returns Un tableau des pensées les plus pertinentes */ async getRelevantThoughts(context, limit = 5) { const allThoughts = Array.from(this.nodes.values()); // Si pas de pensées ou pas de service d'embeddings, utiliser l'algorithme de base if (allThoughts.length === 0 || !this.embeddingService) { return this.getRelevantThoughtsWithKeywords(context, limit); } try { // Utiliser le service d'embeddings pour trouver les pensées similaires const thoughtTexts = allThoughts.map(thought => thought.content); const similarResults = await this.embeddingService.findSimilarTexts(context, thoughtTexts, limit); // Convertir les résultats en pensées return similarResults.map(result => { const matchingThought = allThoughts.find(thought => thought.content === result.text); if (matchingThought) { // Stocker le score de similarité dans les métadonnées pour référence future matchingThought.metadata.similarityScore = result.score; } return matchingThought; }).filter(thought => thought !== undefined); } catch (error) { console.error('Erreur lors de la recherche de pensées pertinentes avec embeddings:', error); // En cas d'erreur, revenir à l'algorithme basé sur les mots-clés return this.getRelevantThoughtsWithKeywords(context, limit); } } /** * Implémentation de secours basée sur les mots-clés * * @param context Le contexte pour lequel chercher des pensées pertinentes * @param limit Le nombre maximum de pensées à récupérer * @returns Un tableau des pensées les plus pertinentes */ getRelevantThoughtsWithKeywords(context, limit = 5) { // Une implémentation simple basée sur la correspondance de mots-clés const contextWords = context.toLowerCase().split(/\W+/).filter(word => word.length > 3); return Array.from(this.nodes.values()) .map(thought => { const thoughtWords = thought.content.toLowerCase().split(/\W+/).filter(word => word.length > 3); // Calculer un score simple basé sur le nombre de mots partagés const matchingWords = contextWords.filter(word => thoughtWords.includes(word)); const score = matchingWords.length / Math.max(contextWords.length, 1); return { thought, score }; }) .sort((a, b) => b.score - a.score) .slice(0, limit) .map(item => item.thought); } /** * Crée un hyperlien entre plusieurs pensées * * @param nodeIds Les identifiants des pensées à connecter * @param type Le type de connexion * @param label Une étiquette descriptive facultative * @param attributes Attributs sémantiques facultatifs * @param strength La force de la connexion (0 à 1) * @returns L'identifiant de l'hyperlien créé */ createHyperlink(nodeIds, type, label, attributes, strength = 0.5) { // Vérifier que les nœuds existent if (nodeIds.some(id => !this.nodes.has(id))) { console.error('Certains nœuds spécifiés n\'existent pas'); return ''; } // Générer un ID unique pour l'hyperlien const id = this.generateUniqueId(); // Créer l'hyperlien const hyperlink = { id, nodeIds, type, label, attributes, strength, inferred: false, confidence: 1.0, // Non inféré, donc confiance maximale metadata: { createdAt: new Date(), sessionId: this.sessionId } }; // Ajouter l'hyperlien à la collection this.hyperlinks.set(id, hyperlink); return id; } /** * Récupère un hyperlien par son identifiant * * @param id L'identifiant de l'hyperlien * @returns L'hyperlien ou undefined si non trouvé */ getHyperlink(id) { return this.hyperlinks.get(id); } /** * Récupère tous les hyperliens * * @returns Un tableau de tous les hyperliens */ getAllHyperlinks() { return Array.from(this.hyperlinks.values()); } /** * Récupère les hyperliens impliquant une pensée spécifique * * @param thoughtId L'identifiant de la pensée * @returns Un tableau des hyperliens impliquant cette pensée */ getHyperlinksForThought(thoughtId) { return Array.from(this.hyperlinks.values()) .filter(hyperlink => hyperlink.nodeIds.includes(thoughtId)); } /** * Infère des relations entre pensées basées sur l'analyse de contenu et de contexte * * @param confidenceThreshold Seuil de confiance minimum pour les relations inférées (0 à 1) * @returns Le nombre de nouvelles relations inférées */ async inferRelations(confidenceThreshold = 0.7) { if (!this.embeddingService) { console.error('Service d\'embeddings non disponible pour l\'inférence de relations'); return 0; } const thoughts = this.getAllThoughts(); let newRelationsCount = 0; // Inférence basée sur la similarité sémantique const similarityCount = await this.inferRelationsBySimilarity(thoughts, confidenceThreshold); // Inférence basée sur la transitivité des relations const transitivityCount = this.inferRelationsByTransitivity(confidenceThreshold); // Inférence basée sur des patterns dans le graphe const patternsCount = this.inferRelationsByPatterns(confidenceThreshold); newRelationsCount = similarityCount + transitivityCount + patternsCount; return newRelationsCount; } /** * Infère des relations basées sur la similarité sémantique * * @param thoughts Les pensées à analyser * @param confidenceThreshold Seuil de confiance minimum * @returns Le nombre de nouvelles relations inférées */ async inferRelationsBySimilarity(thoughts, confidenceThreshold) { if (thoughts.length < 2 || !this.embeddingService) return 0; let newRelationsCount = 0; const thoughtTexts = thoughts.map(t => t.content); // Calculer les similarités entre toutes les paires de pensées for (let i = 0; i < thoughts.length; i++) { const sourceThought = thoughts[i]; // Trouver les pensées similaires const similarResults = await this.embeddingService.findSimilarTexts(sourceThought.content, thoughtTexts.filter((_, index) => index !== i), 10); // Créer des connexions pour les pensées suffisamment similaires for (const result of similarResults) { if (result.score < confidenceThreshold) continue; const targetThought = thoughts.find(t => t.content === result.text); if (!targetThought) continue; // Éviter les doublons const hasConnection = sourceThought.connections.some(conn => conn.targetId === targetThought.id); if (!hasConnection) { // Déterminer le type de connexion en fonction du contexte const connectionType = this.inferConnectionType(sourceThought, targetThought); // Ajouter la nouvelle connexion this.addInferredConnection(sourceThought.id, targetThought.id, connectionType, result.score); newRelationsCount++; } } } return newRelationsCount; } /** * Infère des relations basées sur la transitivité * * @param confidenceThreshold Seuil de confiance minimum * @returns Le nombre de nouvelles relations inférées */ inferRelationsByTransitivity(confidenceThreshold) { let newRelationsCount = 0; const thoughts = this.getAllThoughts(); // Règles de transitivité pour certains types de connexions const transitivityRules = { // Si A supporte B et B supporte C, alors A supporte C (transitivité affaiblie) 'supports': [ { firstType: 'supports', secondType: 'supports', resultType: 'supports', confidenceMultiplier: 0.8 } ], // Si A contredit B et B supporte C, alors A contredit C (transitivité inversée) 'contradicts': [ { firstType: 'contradicts', secondType: 'supports', resultType: 'contradicts', confidenceMultiplier: 0.7 } ], // Autres règles... }; // Appliquer les règles de transitivité for (const thought of thoughts) { for (const conn1 of thought.connections) { const secondThought = this.getThought(conn1.targetId); if (!secondThought) continue; const rules = transitivityRules[conn1.type] || []; for (const rule of rules) { if (conn1.type !== rule.firstType) continue; for (const conn2 of secondThought.connections) { if (conn2.type !== rule.secondType) continue; const thirdThought = this.getThought(conn2.targetId); if (!thirdThought || thirdThought.id === thought.id) continue; // Éviter les cycles et les doublons const hasConnection = thought.connections.some(c => c.targetId === thirdThought.id); if (!hasConnection) { // Calculer la confiance basée sur les connexions existantes const confidence = conn1.strength * conn2.strength * rule.confidenceMultiplier; if (confidence >= confidenceThreshold) { this.addInferredConnection(thought.id, thirdThought.id, rule.resultType, confidence); newRelationsCount++; } } } } } } return newRelationsCount; } /** * Infère des relations basées sur des patterns dans le graphe * * @param confidenceThreshold Seuil de confiance minimum * @returns Le nombre de nouvelles relations inférées */ inferRelationsByPatterns(confidenceThreshold) { let newRelationsCount = 0; // Détecter les clusters de pensées fortement connectées const clusters = this.detectClusters(); // Pour chaque cluster, créer des hyperliens entre les membres for (const cluster of clusters) { if (cluster.nodeIds.length >= 3) { // Créer un hyperlien pour le groupe si la confiance est suffisante if (cluster.cohesion >= confidenceThreshold) { this.createHyperlink(cluster.nodeIds, 'associates', // Type par défaut, pourrait être affiné `Cluster: ${cluster.label || 'Sans nom'}`, { nature: 'associative', scope: 'broad' }, cluster.cohesion); newRelationsCount++; } // Également, inférer des relations individuelles entre les membres du cluster for (let i = 0; i < cluster.nodeIds.length; i++) { for (let j = i + 1; j < cluster.nodeIds.length; j++) { const thought1 = this.getThought(cluster.nodeIds[i]); const thought2 = this.getThought(cluster.nodeIds[j]); if (!thought1 || !thought2) continue; // Vérifier si une connexion existe déjà const hasConnection = thought1.connections.some(conn => conn.targetId === thought2.id); if (!hasConnection) { // La confiance est basée sur la cohésion du cluster const confidence = cluster.cohesion * 0.9; if (confidence >= confidenceThreshold) { this.addInferredConnection(thought1.id, thought2.id, 'associates', confidence); newRelationsCount++; } } } } } } return newRelationsCount; } /** * Détecte des clusters (groupes) de pensées fortement connectées * * @returns Un tableau de clusters détectés */ detectClusters() { const clusters = []; // Algorithme simple de clustering basé sur la connectivité const thoughts = this.getAllThoughts(); const visited = new Set(); for (const thought of thoughts) { if (visited.has(thought.id)) continue; // Parcourir le graphe à partir de cette pensée const cluster = this.exploreCommunity(thought.id, visited); // Seulement considérer les clusters avec au moins 2 nœuds if (cluster.nodeIds.length >= 2) { clusters.push(cluster); } } return clusters; } /** * Explore une communauté connectée à partir d'un nœud de départ * * @param startNodeId ID du nœud de départ * @param visited Ensemble des nœuds déjà visités * @returns Un cluster de nœuds connectés */ exploreCommunity(startNodeId, visited) { const communityNodes = []; const queue = [startNodeId]; const connectivityScores = []; while (queue.length > 0) { const currentId = queue.shift(); if (visited.has(currentId)) continue; visited.add(currentId); communityNodes.push(currentId); const thought = this.getThought(currentId); if (!thought) continue; // Évaluer les connexions for (const conn of thought.connections) { if (!visited.has(conn.targetId) && conn.strength > 0.5) { queue.push(conn.targetId); connectivityScores.push(conn.strength); } } } // Calculer la cohésion du cluster basée sur la force moyenne des connexions const avgConnectivity = connectivityScores.length > 0 ? connectivityScores.reduce((sum, score) => sum + score, 0) / connectivityScores.length : 0; return { nodeIds: communityNodes, cohesion: avgConnectivity }; } /** * Infère le type de connexion approprié entre deux pensées * * @param sourceThought La pensée source * @param targetThought La pensée cible * @returns Le type de connexion inféré */ inferConnectionType(sourceThought, targetThought) { // Analyse simple basée sur le contenu et le type des pensées const sourceContent = sourceThought.content.toLowerCase(); const targetContent = targetThought.content.toLowerCase(); // Recherche de mots-clés indiquant des contradictions const contradictionMarkers = [ 'cependant', 'mais', 'toutefois', 'contrairement', 'oppose', 'contredit', 'différent', 'désaccord', 'conteste' ]; if (contradictionMarkers.some(marker => sourceContent.includes(marker) || targetContent.includes(marker))) { return 'contradicts'; } // Recherche de mots-clés indiquant un support const supportMarkers = [ 'confirme', 'soutient', 'renforce', 'valide', 'appuie', 'corrobore', 'accord', 'similaire' ]; if (supportMarkers.some(marker => sourceContent.includes(marker) || targetContent.includes(marker))) { return 'supports'; } // Inférence basée sur les types de pensées if (sourceThought.type === 'conclusion' && targetThought.type !== 'conclusion') { return 'synthesizes'; } if (sourceThought.type === 'hypothesis' && targetThought.type === 'regular') { return 'generalizes'; } if (sourceThought.type === 'regular' && targetThought.type === 'hypothesis') { return 'exemplifies'; } if (sourceThought.type === 'meta') { return 'analyzes'; } if (sourceThought.type === 'revision') { return 'refines'; } // Par défaut, type d'association générique return 'associates'; } /** * Ajoute une connexion inférée entre deux pensées * * @param sourceId ID de la pensée source * @param targetId ID de la pensée cible * @param type Type de connexion * @param confidence Niveau de confiance dans l'inférence * @returns true si l'ajout a réussi, false sinon */ addInferredConnection(sourceId, targetId, type, confidence) { const sourceThought = this.getThought(sourceId); const targetThought = this.getThought(targetId); if (!sourceThought || !targetThought) { return false; } // Créer la connexion avec marquage d'inférence const connection = { targetId, type, strength: confidence, inferred: true, inferenceConfidence: confidence, attributes: { certainty: this.mapConfidenceToCertainty(confidence) } }; // Ajouter la connexion à la pensée source sourceThought.connections.push(connection); // Créer une connexion réciproque si nécessaire if (this.shouldCreateReciprocalConnection(type)) { const reciprocalType = this.getReciprocalConnectionType(type); targetThought.connections.push({ targetId: sourceId, type: reciprocalType, strength: confidence, inferred: true, inferenceConfidence: confidence, attributes: { certainty: this.mapConfidenceToCertainty(confidence) } }); } return true; } /** * Détermine si une connexion réciproque doit être créée * * @param type Le type de connexion * @returns true si une connexion réciproque doit être créée */ shouldCreateReciprocalConnection(type) { // Certains types de connexion sont intrinsèquement bidirectionnels const bidirectionalTypes = [ 'associates', 'compares', 'contrasts' ]; return bidirectionalTypes.includes(type); } /** * Convertit un niveau de confiance en niveau de certitude * * @param confidence Le niveau de confiance (0 à 1) * @returns Le niveau de certitude correspondant */ mapConfidenceToCertainty(confidence) { if (confidence >= 0.9) return 'definite'; if (confidence >= 0.75) return 'high'; if (confidence >= 0.5) return 'moderate'; if (confidence >= 0.3) return 'low'; return 'speculative'; } /** * Enrichit une pensée existante avec des attributs sémantiques pour ses connexions * * @param thoughtId L'ID de la pensée à enrichir * @returns Le nombre de connexions enrichies */ enrichThoughtConnections(thoughtId) { const thought = this.getThought(thoughtId); if (!thought) return 0; let enrichedCount = 0; for (const connection of thought.connections) { // Ignorer les connexions déjà enrichies if (connection.attributes) continue; const targetThought = this.getThought(connection.targetId); if (!targetThought) continue; // Enrichir avec des attributs sémantiques inférés du contexte connection.attributes = this.inferConnectionAttributes(thought, targetThought, connection.type); enrichedCount++; } return enrichedCount; } /** * Infère des attributs sémantiques pour une connexion * * @param sourceThought La pensée source * @param targetThought La pensée cible * @param type Le type de connexion * @returns Les attributs sémantiques inférés */ inferConnectionAttributes(sourceThought, targetThought, type) { const attributes = {}; // Inférer la temporalité if (sourceThought.timestamp < targetThought.timestamp) { attributes.temporality = 'before'; } else { attributes.temporality = 'after'; } // Inférer la nature switch (type) { case 'supports': case 'contradicts': attributes.nature = 'associative'; break; case 'derives': case 'refines': attributes.nature = 'hierarchical'; break; case 'branches': attributes.nature = 'sequential'; break; case 'analyzes': case 'evaluates': attributes.nature = 'causal'; break; case 'exemplifies': case 'generalizes': attributes.nature = 'hierarchical'; break; default: attributes.nature = 'associative'; } // Inférer la directionnalité if (['associates', 'compares', 'contrasts'].includes(type)) { attributes.directionality = 'bidirectional'; } else { attributes.directionality = 'unidirectional'; } return attributes; } /** * Suggère les prochaines étapes de raisonnement * AMÉLIORÉ: Inclut des recommandations d'outils spécifiques * * @param limit Le nombre maximum de suggestions * @returns Un tableau de suggestions pour les prochaines étapes */ suggestNextSteps(limit = 3) { if (this.nodes.size === 0) { return [{ description: "Commencez par définir le problème ou la question à explorer", type: 'regular', confidence: 0.9, reasoning: "Une définition claire du problème est essentielle pour un raisonnement efficace" }]; } const suggestions = []; const recentThoughts = this.getRecentThoughts(3); const recentContent = recentThoughts.map(t => t.content).join(' '); const allThoughts = this.getAllThoughts(); // Analyser le contenu récent pour détecter des besoins spécifiques const needsFactChecking = this.containsAny(recentContent.toLowerCase(), ['vérifier', 'confirmer', 'source', 'preuve', 'statistique', 'données', 'affirme', 'selon']); const needsCalculation = this.containsAny(recentContent.toLowerCase(), ['calculer', 'calcul', 'équation', 'résoudre', 'chiffre', 'formule', 'mathématique']); const needsExternalInfo = this.containsAny(recentContent.toLowerCase(), ['chercher', 'information', 'recherche', 'trouver', 'données', 'référence', 'source', 'actualité']); const containsUncertainty = this.containsAny(recentContent.toLowerCase(), ['peut-être', 'probablement', 'semble', 'possible', 'hypothèse', 'incertain', 'pourrait']); // Suggestions basées sur les besoins détectés if (needsFactChecking) { suggestions.push({ description: "Vérifiez les informations avec une recherche web", type: 'regular', confidence: 0.9, reasoning: "Utilisez l'outil perplexity_search_web ou tavily-search pour confirmer les faits mentionnés" }); } if (needsCalculation) { suggestions.push({ description: "Exécutez du code pour effectuer les calculs nécessaires", type: 'regular', confidence: 0.85, reasoning: "Utilisez l'outil executePython ou executeJavaScript pour résoudre les calculs ou équations" }); } if (needsExternalInfo) { suggestions.push({ description: "Recherchez des informations supplémentaires en ligne", type: 'regular', confidence: 0.9, reasoning: "Utilisez les outils de recherche web pour enrichir votre analyse avec des données pertinentes" }); } // Vérifier s'il y a des contradictions à résoudre const hasContradictions = allThoughts.some(thought => thought.connections.some(conn => conn.type === 'contradicts')); if (hasContradictions) { suggestions.push({ description: "Résolvez les contradictions en consultant des sources fiables", type: 'meta', confidence: 0.85, reasoning: "Utilisez tavily-search ou perplexity_search_web pour vérifier quelle position est correcte" }); } // Suggestion pour extraire du contenu web si des URL sont mentionnées const containsUrl = /https?:\/\/[^\s]+/.test(recentContent); if (containsUrl) { suggestions.push({ description: "Extrayez et analysez le contenu des URL mentionnées", type: 'regular', confidence: 0.85, reasoning: "Utilisez l'outil tavily-extract pour analyser en profondeur le contenu des pages web" }); } // Vérifier si une méta-réflexion serait utile const hasMeta = allThoughts.some(thought => thought.type === 'meta'); if (allThoughts.length >= 5 && !hasMeta) { suggestions.push({ description: "Faites une méta-réflexion sur votre approche jusqu'à présent", type: 'meta', confidence: 0.7, reasoning: "La méta-cognition peut améliorer la qualité du raisonnement" }); } // Vérifier s'il est temps de former une hypothèse const hasHypothesis = allThoughts.some(thought => thought.type === 'hypothesis'); if ((allThoughts.length >= 3 && !hasHypothesis) || containsUncertainty) { suggestions.push({ description: "Formulez une hypothèse basée sur vos observations", type: 'hypothesis', confidence: 0.75, reasoning: "Une hypothèse claire peut guider la suite de votre raisonnement" }); } // Vérifier s'il est temps de conclure const hasConclusion = allThoughts.some(thought => thought.type === 'conclusion'); if (allThoughts.length >= 7 && !hasConclusion) { suggestions.push({ description: "Rédigez une conclusion provisoire basée sur votre analyse", type: 'conclusion', confidence: 0.8, reasoning: "Même provisoire, une conclusion peut aider à synthétiser votre réflexion" }); } // Vérifier si des hyperliens ont été créés const hasHyperlinks = this.hyperlinks.size > 0; if (hasHyperlinks) { suggestions.push({ description: "Explorez les relations complexes identifiées dans les clusters de pensées", type: 'meta', confidence: 0.8, reasoning: "L'analyse des relations multi-nœuds peut révéler des insights cachés" }); } // Si aucune suggestion n'a été faite, proposer une continuation simple if (suggestions.length === 0) { suggestions.push({ description: "Continuez votre raisonnement en développant vos idées actuelles", type: 'regular', confidence: 0.6, reasoning: "Approfondir les pensées existantes peut révéler de nouvelles perspectives" }); } return suggestions.slice(0, limit); } /** * Vérifie si un texte contient l'un des termes donnés * * @param text Le texte à vérifier * @param terms Les termes à rechercher * @returns true si le texte contient au moins un des termes, false sinon */ containsAny(text, terms) { return terms.some(term => text.includes(term)); } /** * Met à jour le contenu d'une pensée existante * * @param id L'identifiant de la pensée à mettre à jour * @param newContent Le nouveau contenu de la pensée * @returns true si la mise à jour a réussi, false sinon */ updateThoughtContent(id, newContent) { const thought = this.nodes.get(id); if (!thought) return false; const oldContent = thought.content; thought.content = newContent; thought.metadata.lastUpdated = new Date(); // Émettre un événement pour notifier de la mise à jour d'une pensée this.eventEmitter.emit('thought-updated', id, thought, { oldContent }); // Vérifier automatiquement les calculs si nécessaire this.checkForCalculationsAndVerify(id, newContent); return true; } /** * Efface toutes les pensées du graphe */ clear() { this.nodes.clear(); this.hyperlinks.clear(); } /** * Exporte le graphe de pensées sous forme de JSON * * @returns Une représentation JSON du graphe */ exportToJson() { return JSON.stringify(Array.from(this.nodes.values())); } /** * Exporte le graphe enrichi (nœuds et hyperliens) sous forme de JSON * * @returns Une représentation JSON du graphe enrichi */ exportEnrichedGraph() { const exportData = { nodes: Array.from(this.nodes.values()), hyperlinks: Array.from(this.hyperlinks.values()) }; return JSON.stringify(exportData); } /** * Importe un graphe de pensées depuis un JSON * * @param json Le JSON à importer * @returns true si l'importation a réussi, false sinon */ importFromJson(json) { try { const nodes = JSON.parse(json); this.clear(); for (const node of nodes) { this.nodes.set(node.id, { ...node, timestamp: new Date(node.timestamp) }); } return true; } catch (error) { console.error('Erreur lors de l\'importation du graphe:', error); return false; } } /** * Importe un graphe enrichi depuis un JSON * * @param json Le JSON à importer * @returns true si l'importation a réussi, false sinon */ importEnrichedGraph(json) { try { const data = JSON.parse(json); // Importer les nœuds if (Array.isArray(data.nodes)) { this.clear(); for (const node of data.nodes) { this.nodes.set(node.id, { ...node, timestamp: new Date(node.timestamp) }); } } // Importer les hyperliens if (Array.isArray(data.hyperlinks)) { this.hyperlinks.clear(); for (const hyperlink of data.hyperlinks) { this.hyperlinks.set(hyperlink.id, hyperlink); } } return true; } catch (error) { console.error('Erreur lors de l\'importation du graphe enrichi:', error); return false; } } } exports.ThoughtGraph = ThoughtGraph; //# sourceMappingURL=thought-graph.js.map