Skip to main content
Glama
tool-integrator.ts34.5 kB
import { SuggestedTool } from './types'; import { callInternalLlm } from './utils/openrouter-client'; // Import LLM utility /** * Classe qui gère l'intégration avec d'autres outils MCP */ export class ToolIntegrator { // Registre des outils connus private knownTools: Map<string, { name: string; description: string; keywords: string[]; useCase: string; }> = new Map(); constructor() { // Initialiser avec des outils MCP courants this.initializeKnownTools(); } /** * Initialise le registre avec des outils MCP courants */ private initializeKnownTools(): void { // Outils de recherche web this.knownTools.set('perplexity_search_web', { name: 'perplexity_search_web', description: 'Recherche web avancée avec Perplexity AI et filtrage de récence', keywords: ['recherche', 'web', 'internet', 'information', 'récent', 'actualité', 'perplexity', 'temps réel', 'fraîcheur'], useCase: 'Utiliser pour obtenir des informations récentes et pertinentes du web avec filtrage de récence configurable' }); this.knownTools.set('brave_web_search', { name: 'brave_web_search', description: 'Recherche web générale avec l\'API Brave Search', keywords: ['recherche', 'web', 'internet', 'information', 'brave', 'articles', 'nouvelles', 'contenu'], useCase: 'Utiliser pour des requêtes générales, articles, actualités et recherche de contenu en ligne avec pagination' }); this.knownTools.set('brave_local_search', { name: 'brave_local_search', description: 'Recherche locale de commerces et lieux avec l\'API Brave Local Search', keywords: ['recherche', 'local', 'entreprise', 'lieu', 'adresse', 'proximité', 'restaurant', 'magasin', 'localisation'], useCase: 'Idéal pour trouver des entreprises, restaurants, services et lieux à proximité d\'une localisation' }); this.knownTools.set('tavily-search', { name: 'tavily-search', description: 'Outil de recherche web puissant avec Tavily AI Search Engine', keywords: ['recherche', 'web', 'internet', 'information', 'tavily', 'ai', 'détaillé', 'avancé', 'domaine'], useCase: 'Recherche web complète et détaillée avec filtrage par domaines, contrôle de fraîcheur et résultats contextuels' }); this.knownTools.set('tavily-extract', { name: 'tavily-extract', description: 'Extraction de contenu web avec Tavily', keywords: ['extraction', 'contenu', 'web', 'page', 'url', 'tavily', 'texte', 'analyse', 'scraping'], useCase: 'Utiliser pour extraire et traiter du contenu à partir d\'URLs spécifiques, idéal pour l\'analyse de documents web' }); // Outils pour les fichiers système locaux (via les outils Cline standard) this.knownTools.set('read_file', { name: 'read_file', description: 'Lire le contenu complet d\'un fichier depuis le système de fichiers local', keywords: ['fichier', 'lecture', 'contenu', 'texte', 'document', 'filesystem', 'local'], useCase: 'Utiliser pour examiner le contenu d\'un fichier spécifique sur le système local' }); this.knownTools.set('write_to_file', { name: 'write_to_file', description: 'Créer ou écraser un fichier local avec un nouveau contenu', keywords: ['fichier', 'écriture', 'création', 'contenu', 'texte', 'document', 'filesystem', 'local', 'sauvegarder'], useCase: 'Utiliser pour créer ou mettre à jour un fichier local avec un nouveau contenu' }); this.knownTools.set('list_files', { name: 'list_files', description: 'Lister le contenu d\'un répertoire local', keywords: ['fichier', 'dossier', 'répertoire', 'liste', 'contenu', 'directory', 'filesystem', 'local', 'ls'], useCase: 'Utiliser pour voir tous les fichiers et dossiers dans un répertoire local spécifié' }); this.knownTools.set('replace_in_file', { name: 'replace_in_file', description: 'Modifier un fichier local en remplaçant des sections spécifiques', keywords: ['fichier', 'modifier', 'édition', 'remplacer', 'patch', 'diff', 'local'], useCase: 'Utiliser pour faire des modifications ciblées dans un fichier existant sur le système local' }); this.knownTools.set('search_files', { // Outil Cline standard pour la recherche regex locale name: 'search_files', description: 'Rechercher un motif regex dans les fichiers locaux', keywords: ['recherche', 'fichier', 'motif', 'regex', 'grep', 'local', 'contenu'], useCase: 'Utiliser pour trouver des motifs spécifiques dans les fichiers locaux' }); this.knownTools.set('execute_command', { name: 'execute_command', description: 'Exécuter une commande CLI sur le système local', keywords: ['commande', 'cli', 'terminal', 'shell', 'exécuter', 'script', 'système', 'bash', 'zsh'], useCase: 'Utiliser pour exécuter des commandes système, des scripts ou interagir avec le terminal local' }); // Outils Smart-E2B pour l'exécution de code dans un sandbox this.knownTools.set('executeJavaScript', { name: 'executeJavaScript', description: 'Exécution de code JavaScript dans un sandbox sécurisé via smart-e2b', keywords: ['code', 'javascript', 'exécution', 'programmation', 'script', 'e2b', 'sandbox', 'js', 'node'], useCase: 'Utiliser pour exécuter du code JavaScript dans un environnement isolé et sécurisé' }); this.knownTools.set('executePython', { name: 'executePython', description: 'Exécution de code Python dans un sandbox sécurisé via smart-e2b', keywords: ['code', 'python', 'exécution', 'programmation', 'script', 'e2b', 'sandbox', 'py', 'pandas', 'numpy'], useCase: 'Utiliser pour exécuter du code Python dans un environnement isolé et sécurisé' }); this.knownTools.set('uploadFile', { // E2B specific name: 'uploadFile', description: 'Télécharger un fichier vers le sandbox smart-e2b', keywords: ['fichier', 'upload', 'téléchargement', 'e2b', 'sandbox', 'transfert'], useCase: 'Permet de télécharger des fichiers vers l\'environnement sandbox E2B pour traitement' }); this.knownTools.set('listFiles', { // E2B specific name: 'listFiles', description: 'Lister les fichiers dans le sandbox smart-e2b', keywords: ['fichier', 'liste', 'répertoire', 'e2b', 'sandbox', 'dossier'], useCase: 'Permet de voir les fichiers disponibles dans l\'environnement sandbox E2B' }); this.knownTools.set('readFile', { // E2B specific name: 'readFile', description: 'Lire le contenu d\'un fichier dans le sandbox smart-e2b', keywords: ['fichier', 'lecture', 'contenu', 'e2b', 'sandbox', 'texte'], useCase: 'Permet de lire le contenu d\'un fichier dans l\'environnement sandbox E2B' }); // Outil de réflexion séquentielle this.knownTools.set('sequentialthinking', { name: 'sequentialthinking', description: 'Outil de réflexion séquentielle pour résolution de problèmes', keywords: ['réflexion', 'pensée', 'séquentiel', 'étape', 'problème', 'raisonnement', 'plan'], useCase: 'Utiliser pour une résolution de problèmes par étapes, avec révision et ramification possibles' }); // Outil Smart-Thinking (lui-même) this.knownTools.set('smartthinking', { name: 'smartthinking', description: 'Outil principal de Smart-Thinking pour ajouter/gérer des pensées', keywords: ['pensée', 'ajouter', 'raisonnement', 'graphe', 'smart-thinking', 'connecter', 'lier'], useCase: 'Utiliser pour ajouter de nouvelles pensées, établir des connexions et gérer le graphe de raisonnement' }); } /** * Suggère des outils pertinents pour un contenu donné avec option pour la vérification. * Tente d'utiliser le LLM interne pour une meilleure pertinence, avec repli sur l'heuristique. * * @param content Le contenu pour lequel suggérer des outils * @param options Options de configuration (limite, mode vérification, etc) * @returns Une promesse résolvant vers un tableau d'outils suggérés */ public async suggestToolsGeneric(content: string, options: { limit?: number, verificationMode?: boolean, toolFilter?: string[], previousSuggestions?: SuggestedTool[], // Gardé pour l'heuristique de repli reasoningStage?: 'initial' | 'developing' | 'advanced' | 'final' // Gardé pour l'heuristique de repli } = {}): Promise<SuggestedTool[]> { const { limit = 3, verificationMode = false, toolFilter = [], } = options; // Déterminer les outils disponibles à considérer let availableTools = Array.from(this.knownTools.values()); if (verificationMode) { const verificationToolNames = [ 'perplexity_search_web', 'tavily-search', 'brave_web_search', 'tavily-extract', 'executePython', 'executeJavaScript' // On pourrait ajouter 'read_file' si la vérification implique des fichiers locaux ]; availableTools = availableTools.filter(tool => verificationToolNames.includes(tool.name)); } else if (toolFilter.length > 0) { availableTools = availableTools.filter(tool => toolFilter.includes(tool.name)); } if (availableTools.length === 0) { console.warn("Aucun outil disponible pour la suggestion."); return []; } // --- Tentative de suggestion via LLM --- let llmSuggestions: SuggestedTool[] | null = null; try { const toolListString = availableTools.map(t => `- ${t.name}: ${t.description}`).join('\n'); // Prompt amélioré pour être plus précis sur le format JSON attendu const systemPrompt = `You are an expert assistant selecting the best tools for a given task based on the user's thought content. Analyze the user's thought and suggest the top ${limit} most relevant tools from the provided list ONLY. Explain briefly (max 15 words) why each tool is relevant for the specific thought content. Respond ONLY with a valid JSON array of objects, where each object has exactly two keys: "name" (string, the tool name from the list) and "reason" (string, your brief explanation). Do not include any other text or formatting outside the JSON array. Available tools:\n${toolListString}`; const userPrompt = `Thought content:\n"${content}"\n\nSuggest the top ${limit} relevant tools from the list in JSON array format:`; const llmResponse = await callInternalLlm(systemPrompt, userPrompt, 1000); // Increased tokens slightly if (llmResponse) { // Tentative de nettoyage de la réponse LLM pour extraire le JSON const jsonMatch = llmResponse.match(/\[\s*\{[\s\S]*\}\s*\]/); if (jsonMatch) { const jsonString = jsonMatch[0]; try { const parsedSuggestions = JSON.parse(jsonString); if (Array.isArray(parsedSuggestions) && parsedSuggestions.length > 0) { const validatedSuggestions: SuggestedTool[] = []; let priority = 1; for (const suggestion of parsedSuggestions) { // Vérification plus stricte du format de l'objet if (suggestion && typeof suggestion.name === 'string' && typeof suggestion.reason === 'string' && Object.keys(suggestion).length === 2) { const knownTool = this.knownTools.get(suggestion.name); // S'assurer que l'outil suggéré est dans la liste des outils disponibles pour ce contexte if (knownTool && availableTools.some(at => at.name === knownTool.name)) { validatedSuggestions.push({ name: knownTool.name, confidence: 1.0 / priority, // Confiance simple basée sur le rang reason: suggestion.reason, priority: priority++ }); if (validatedSuggestions.length >= limit) break; } else { console.warn(`LLM suggested an unknown or unavailable tool: ${suggestion.name}`); } } else { console.warn(`LLM suggestion item has invalid format: ${JSON.stringify(suggestion)}`); } } if (validatedSuggestions.length > 0) { console.error(`Smart-Thinking: Suggestions d'outils fournies par le LLM interne.`); llmSuggestions = validatedSuggestions; // Stocker les suggestions validées } } } catch (parseError) { console.warn(`LLM tool suggestion response was not valid JSON or structure incorrect: ${llmResponse}`, parseError); } } else { console.warn(`Could not extract JSON array from LLM response: ${llmResponse}`); } } } catch (llmError) { console.error('Error calling LLM for tool suggestion:', llmError); } // Si le LLM a fourni des suggestions valides, les retourner if (llmSuggestions && llmSuggestions.length > 0) { return llmSuggestions; } // --- Repli (Fallback) vers l'heuristique si le LLM échoue ou ne renvoie rien de valide --- console.warn("LLM tool suggestion failed or returned no valid tools. Falling back to heuristic method."); // Passer les options originales à l'heuristique return this.suggestToolsHeuristic(content, options); } /** * Méthode heuristique originale pour suggérer des outils (utilisée comme repli). */ private suggestToolsHeuristic(content: string, options: { limit?: number, verificationMode?: boolean, toolFilter?: string[], previousSuggestions?: SuggestedTool[], reasoningStage?: 'initial' | 'developing' | 'advanced' | 'final' } = {}): SuggestedTool[] { const { limit = 3, verificationMode = false, toolFilter = [], previousSuggestions = [], reasoningStage = 'initial' } = options; // Déterminer les outils à considérer selon le mode let relevantTools = Array.from(this.knownTools.values()); // Filtrer les outils si nécessaire if (verificationMode) { const verificationToolNames = [ 'perplexity_search_web', 'tavily-search', 'brave_web_search', 'tavily-extract', 'executePython', 'executeJavaScript' ]; relevantTools = relevantTools.filter(tool => verificationToolNames.includes(tool.name)); } else if (toolFilter.length > 0) { relevantTools = relevantTools.filter(tool => toolFilter.includes(tool.name)); } if (relevantTools.length === 0) return []; // Retourner vide si aucun outil pertinent // Convertir le contenu en mots-clés const contentWords = content.toLowerCase().split(/\W+/).filter(word => word.length > 3); // Analyse du contenu pour détecter des intentions/besoins spécifiques const needsWebSearch = this.containsAny(content.toLowerCase(), ['recherche', 'trouve', 'cherche', 'information', 'récent', 'actualité', 'web', 'internet']); const needsCodeExecution = this.containsAny(content.toLowerCase(), ['code', 'calcul', 'programme', 'python', 'javascript', 'script', 'algorithme', 'exécute', 'js', 'sandbox']); const needsFileOperation = !verificationMode && this.containsAny(content.toLowerCase(), ['fichier', 'document', 'lecture', 'écriture', 'sauvegarde', 'dossier', 'répertoire', 'arborescence', 'local']); const needsLocalSearch = !verificationMode && this.containsAny(content.toLowerCase(), ['local', 'près', 'proximité', 'entreprise', 'restaurant', 'magasin', 'adresse', 'lieu']); const needsContentExtraction = this.containsAny(content.toLowerCase(), ['extrait', 'extraction', 'contenu', 'page', 'url', 'site', 'web', 'article']); // Détections supplémentaires (uniquement en mode non-vérification) const needsDirectoryListing = !verificationMode && this.containsAny(content.toLowerCase(), ['liste', 'lister', 'contenu', 'répertoire', 'dossier', 'afficher', 'voir']); // const needsDirectoryTree = !verificationMode && this.containsAny(content.toLowerCase(), ['arborescence', 'structure', 'hiérarchie', 'tree', 'visualiser']); // Requires execute_command const needsFileCreation = !verificationMode && this.containsAny(content.toLowerCase(), ['créer', 'nouveau', 'dossier', 'répertoire', 'mkdir']); // Requires execute_command or write_to_file const needsFileMove = !verificationMode && this.containsAny(content.toLowerCase(), ['déplacer', 'renommer', 'déplacement', 'transfert', 'mv', 'move']); // Requires execute_command const needsFileSearch = !verificationMode && this.containsAny(content.toLowerCase(), ['chercher', 'trouver', 'rechercher', 'pattern', 'motif', 'fichier']); // Use search_files const needsPythonExecution = this.containsAny(content.toLowerCase(), ['python', 'py', 'pandas', 'numpy', 'sklearn']); const needsJavaScriptExecution = this.containsAny(content.toLowerCase(), ['javascript', 'js', 'node', 'react', 'vue', 'angular']); // Détection des besoins de vérification de faits ou d'informations const needsFactChecking = this.containsAny(content.toLowerCase(), [ 'vérifier', 'confirmer', 'source', 'preuve', 'statistique', 'données', 'affirme', 'selon', 'citation', 'cité', 'mentionné', 'rapporté' ]); // Détection d'incertitude ou de doute const hasUncertainty = this.containsAny(content.toLowerCase(), [ 'peut-être', 'potentiellement', 'probablement', 'semble', 'apparaît', 'pourrait', 'il se peut', 'incertain', 'doute', 'question', 'hypothèse' ]); // Facteur d'ajustement basé sur l'étape de raisonnement let stageFactor = 1.0; switch (reasoningStage) { case 'initial': stageFactor = 0.7; break; case 'developing': stageFactor = 1.0; break; case 'advanced': stageFactor = 1.2; break; case 'final': stageFactor = 1.3; break; } // Calculer un score pour chaque outil const toolScores = relevantTools.map(tool => { const matchingKeywords = tool.keywords.filter(keyword => contentWords.includes(keyword) || content.toLowerCase().includes(keyword) ); let keywordScore = 0; for (let i = 0; i < matchingKeywords.length; i++) { keywordScore += 1 / (i + 1); } keywordScore = Math.min(keywordScore / 2, 0.6); let score = keywordScore; // Apply heuristic boosts if (needsWebSearch && ['perplexity_search_web', 'brave_web_search', 'tavily-search'].includes(tool.name)) score += verificationMode ? 0.4 : 0.3; if ((needsFactChecking || hasUncertainty) && ['perplexity_search_web', 'tavily-search'].includes(tool.name)) score += 0.3; if (needsContentExtraction && tool.name === 'tavily-extract') score += 0.5; if (needsCodeExecution && ['executePython', 'executeJavaScript'].includes(tool.name)) score += verificationMode ? 0.5 : 0.3; if (needsPythonExecution && tool.name === 'executePython') score += 0.3; if (needsJavaScriptExecution && tool.name === 'executeJavaScript') score += 0.3; if (!verificationMode) { if (needsFileOperation && ['read_file', 'write_to_file', 'list_files', 'replace_in_file', 'execute_command', 'readFile', 'listFiles', 'uploadFile'].includes(tool.name)) score += 0.3; if (needsDirectoryListing && (tool.name === 'list_files' || tool.name === 'listFiles')) score += 0.3; if (needsFileCreation && (tool.name === 'write_to_file' || tool.name === 'execute_command')) score += 0.4; // write_to_file can create dirs if (needsFileMove && tool.name === 'execute_command') score += 0.4; // mv needs execute_command if (needsFileSearch && tool.name === 'search_files') score += 0.4; // Use dedicated search_files tool if (needsLocalSearch && tool.name === 'brave_local_search') score += 0.4; } else { if (['perplexity_search_web', 'tavily-search'].includes(tool.name)) score += 0.2; } score *= stageFactor; const toolWasSuggestedBefore = previousSuggestions.some(s => s.name === tool.name); if (toolWasSuggestedBefore) { const prevSuggestion = previousSuggestions.find(s => s.name === tool.name); score *= (prevSuggestion && prevSuggestion.confidence > 0.7) ? 0.5 : 0.7; } return { tool, score }; }); // Filtrer et normaliser les résultats const minScore = reasoningStage === 'initial' ? 0.05 : 0.1; const suggestedTools = toolScores .filter(item => item.score > minScore) .sort((a, b) => b.score - a.score) .slice(0, limit) .map((item, index) => ({ name: item.tool.name, confidence: Math.min(Math.max(item.score, 0), 1), reason: verificationMode ? this.generateVerificationReason(item.tool, content) : this.generateReason(item.tool, content), priority: index + 1 })); // Outil par défaut si aucun n'est trouvé if (suggestedTools.length === 0 && relevantTools.length > 0) { const defaultConfidence = verificationMode ? 0.5 * stageFactor : 0.3 * stageFactor; const defaultToolName = verificationMode ? 'tavily-search' : 'smartthinking'; // Default to smartthinking if not verification const defaultTool = this.knownTools.get(defaultToolName) || this.knownTools.get('tavily-search')!; // Fallback to tavily suggestedTools.push({ name: defaultTool.name, confidence: Math.min(defaultConfidence, 1.0), reason: verificationMode ? 'Outil de recherche général pour la vérification des informations' : 'Aucun outil spécifique n\'a été identifié. Une recherche web ou une nouvelle pensée pourrait aider.', priority: 1 }); } return suggestedTools; } /** * Suggère des outils de vérification pertinents pour un contenu donné * @param content Le contenu pour lequel suggérer des outils * @param limit Le nombre maximum d'outils à suggérer * @returns Une promesse résolvant vers un tableau d'outils suggérés */ public async suggestVerificationTools(content: string, limit: number = 3): Promise<SuggestedTool[]> { // Utilise suggestToolsGeneric en mode vérification return this.suggestToolsGeneric(content, { limit, verificationMode: true }); } /** * Génère une raison spécifique pour la vérification avec un outil * * @param tool L'outil suggéré * @param content Le contenu à vérifier * @returns Une raison explicative pour la vérification */ private generateVerificationReason(tool: any, _content: string): string { // ... (implementation unchanged) ... switch (tool.name) { case 'perplexity_search_web': return 'Vérification via Perplexity pour obtenir des informations récentes et factuelles'; case 'tavily-search': return 'Recherche approfondie via Tavily pour vérifier l\'exactitude des informations'; case 'brave_web_search': return 'Vérification des faits via Brave Search pour une source alternative'; case 'tavily-extract': return 'Extraction de contenu pour vérifier les informations depuis des sources spécifiques'; case 'executePython': return 'Vérification des calculs et analyses par exécution de code Python'; case 'executeJavaScript': return 'Vérification des calculs et analyses par exécution de code JavaScript'; default: return tool.useCase || 'Outil de vérification des informations'; } } /** * Exécute un outil de vérification sur un contenu donné * * @param toolName Le nom de l'outil à exécuter * @param content Le contenu à vérifier * @returns Le résultat de la vérification */ public async executeVerificationTool(toolName: string, content: string): Promise<any> { // ... (implementation unchanged) ... switch (toolName) { case 'perplexity_search_web': return this.executePerplexitySearch(content); case 'tavily-search': return this.executeTavilySearch(content); case 'brave_web_search': return this.executeBraveSearch(content); case 'tavily-extract': return this.executeTavilyExtract(content); case 'executePython': return this.executePythonVerification(content); case 'executeJavaScript': return this.executeJavaScriptVerification(content); default: throw new Error(`Outil de vérification non pris en charge: ${toolName}`); } } // ... (Private methods for executing specific tools remain unchanged) ... private async executePerplexitySearch(content: string): Promise<any> { // Note: Dans une implémentation réelle, ceci ferait un appel à l'API Perplexity console.log(`Exécution de perplexity_search_web pour vérifier: ${content}`); // Simule un résultat de vérification return { isValid: true, confidence: 0.85, source: "Perplexity Search API", details: "Information vérifiée via Perplexity Search" }; } private async executeTavilySearch(content: string): Promise<any> { // Note: Dans une implémentation réelle, ceci ferait un appel à l'API Tavily console.log(`Exécution de tavily-search pour vérifier: ${content}`); // Simule un résultat de vérification return { isValid: true, confidence: 0.9, source: "Tavily Search API", details: "Information vérifiée via Tavily Search" }; } private async executeBraveSearch(content: string): Promise<any> { // Note: Dans une implémentation réelle, ceci ferait un appel à l'API Brave console.log(`Exécution de brave_web_search pour vérifier: ${content}`); // Simule un résultat de vérification return { isValid: true, confidence: 0.8, source: "Brave Search API", details: "Information vérifiée via Brave Search" }; } private async executeTavilyExtract(content: string): Promise<any> { // Note: Dans une implémentation réelle, ceci ferait un appel à l'API Tavily Extract console.log(`Exécution de tavily-extract pour vérifier: ${content}`); // Simule un résultat de vérification return { isValid: true, confidence: 0.85, source: "Tavily Extract API", details: "Information vérifiée via extraction de contenu" }; } private async executePythonVerification(content: string): Promise<any> { // Note: Dans une implémentation réelle, ceci utiliserait Smart-E2B pour exécuter du code Python console.log(`Exécution de Python pour vérifier: ${content}`); // Simule un résultat de vérification return { isValid: true, confidence: 0.95, source: "Smart-E2B Python Execution", details: "Calculs vérifiés via exécution Python" }; } private async executeJavaScriptVerification(content: string): Promise<any> { // Note: Dans une implémentation réelle, ceci utiliserait Smart-E2B pour exécuter du code JavaScript console.log(`Exécution de JavaScript pour vérifier: ${content}`); // Simule un résultat de vérification return { isValid: true, confidence: 0.95, source: "Smart-E2B JavaScript Execution", details: "Calculs vérifiés via exécution JavaScript" }; } /** * Suggère des outils pertinents pour un contenu donné (méthode publique principale) * * @param content Le contenu pour lequel suggérer des outils * @param limit Le nombre maximum d'outils à suggérer * @returns Une promesse résolvant vers un tableau d'outils suggérés */ async suggestTools(content: string, limit: number = 3): Promise<SuggestedTool[]> { // Utilise suggestToolsGeneric en mode non-vérification return this.suggestToolsGeneric(content, { limit, verificationMode: false }); } /** * 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 */ private containsAny(text: string, terms: string[]): boolean { return terms.some(term => text.includes(term)); } /** * Génère une raison explicative pour la suggestion d'un outil (utilisé par l'heuristique) * * @param tool L'outil suggéré * @param content Le contenu pour lequel l'outil est suggéré * @returns Une raison explicative */ private generateReason(tool: any, content: string): string { // ... (implementation unchanged) ... const isQuestion = content.includes('?'); const isTopic = content.length < 50 && !isQuestion; const isComplex = content.length > 200; const mentionsUrl = /https?:\/\/[^\s]+/.test(content); // Raisons spécifiques pour chaque outil switch (tool.name) { case 'perplexity_search_web': if (isQuestion) { return 'Cette question nécessite des informations récentes que Perplexity peut fournir efficacement.'; } else if (isTopic) { return 'Ce sujet mérite une exploration avec Perplexity pour obtenir des informations à jour.'; } else { return 'Perplexity peut aider à trouver des informations récentes et pertinentes sur ce sujet.'; } case 'brave_web_search': if (isQuestion) { return 'Cette question peut être résolue avec une recherche web générale via Brave Search.'; } else { return 'Brave Search peut fournir des résultats pertinents sur ce sujet avec une bonne couverture générale.'; } case 'brave_local_search': return 'Ce sujet concerne des lieux ou services locaux que Brave Local Search peut aider à trouver.'; case 'tavily-search': if (isComplex) { return 'Cette recherche complexe bénéficierait de la capacité de Tavily à traiter des requêtes détaillées.'; } else { return 'Tavily Search permet d\'obtenir des résultats bien contextualisés sur ce sujet.'; } case 'tavily-extract': if (mentionsUrl) { return 'Tavily Extract peut analyser et extraire du contenu pertinent des URLs mentionnées.'; } else { return 'Pour une analyse approfondie de pages web, Tavily Extract peut extraire du contenu structuré.'; } case 'executePython': return 'Ce problème peut être résolu avec l\'exécution de code Python dans un environnement sandbox sécurisé.'; case 'executeJavaScript': return 'Ce problème peut être résolu avec l\'exécution de code JavaScript dans un environnement sandbox sécurisé.'; case 'list_files': // Updated name return 'Pour visualiser le contenu de ce répertoire local, cet outil permet de lister tous les fichiers et dossiers.'; // case 'directory_tree': // Potentially use execute_command ls -R or similar // return 'Pour comprendre la structure complète de ce répertoire, une visualisation arborescente serait utile.'; // case 'create_directory': // Potentially use execute_command mkdir // return 'Pour organiser les fichiers, la création de répertoires permettrait une meilleure structure.'; // case 'move_file': // Potentially use execute_command mv // return 'Pour réorganiser les fichiers, cet outil permet de déplacer ou renommer des éléments.'; case 'search_files': // Use dedicated search_files tool return 'Pour trouver rapidement les fichiers correspondant à ce critère dans les fichiers locaux.'; case 'read_file': return 'Cet outil permet de lire le contenu complet du fichier local spécifié.'; case 'write_to_file': // Updated name return 'Pour créer ou modifier un fichier local avec le contenu spécifié.'; case 'replace_in_file': return 'Pour effectuer des modifications ciblées dans un fichier local existant.'; case 'uploadFile': return 'Pour transférer un fichier vers l\'environnement sandbox afin de l\'utiliser pour l\'exécution de code.'; case 'readFile': return 'Pour lire le contenu d\'un fichier dans l\'environnement sandbox E2B.'; case 'listFiles': return 'Pour visualiser le contenu du répertoire sandbox E2B.'; case 'execute_command': return 'Pour exécuter une commande système ou un script sur la machine locale.'; case 'smartthinking': return 'Pour ajouter une nouvelle pensée ou étape de raisonnement au graphe actuel.'; case 'sequentialthinking': return 'Pour décomposer un problème complexe en étapes séquentielles et structurées.'; default: // Si aucune personnalisation spécifique n'est applicable, utiliser le cas d'usage général return tool.useCase || `Utiliser ${tool.name} pour ${tool.description.toLowerCase()}`; } } /** * Ajoute un nouvel outil au registre * * @param name Le nom de l'outil * @param description La description de l'outil * @param keywords Les mots-clés associés * @param useCase Le cas d'usage de l'outil */ addTool( name: string, description: string, keywords: string[], useCase: string ): void { this.knownTools.set(name, { name, description, keywords, useCase }); } /** * Supprime un outil du registre * * @param name Le nom de l'outil à supprimer * @returns true si l'outil a été supprimé, false sinon */ removeTool(name: string): boolean { return this.knownTools.delete(name); } /** * Récupère tous les outils du registre * * @returns Un tableau de tous les outils */ getAllTools(): any[] { return Array.from(this.knownTools.values()); } }

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/Leghis/Smart-Thinking'

If you have feedback or need assistance with the MCP directory API, please join our Discord server