Skip to main content
Glama
entity-handlers.js10.2 kB
import { logger } from "../logger.js"; /** * Entity Management Handlers * Handles entity creation, updates, and deletion with automatic similarity detection */ export class EntityHandlers { memoryManager; modernSimilarity; relationshipIndexer; constructor(memoryManager, modernSimilarity, relationshipIndexer) { this.memoryManager = memoryManager; this.modernSimilarity = modernSimilarity; this.relationshipIndexer = relationshipIndexer; } async handleCreateEntities(args) { let createBranch = args.branch_name; if (!createBranch && args.entities && args.entities.length > 0) { // Auto-suggest branch based on first entity const firstEntity = args.entities[0]; createBranch = await this.memoryManager.suggestBranch(firstEntity.entityType, firstEntity.observations?.join(" ")); } const createdEntities = await this.memoryManager.createEntities(args.entities, createBranch); let autoRelationsResults = []; // Handle auto_create_relations if enabled (defaults to true in SMART_MEMORY_TOOLS) if (args.auto_create_relations !== false) { logger.info("Starting automatic relationship detection..."); try { // Get existing entities from the branch to compare against const branchGraph = await this.memoryManager.readGraph(createBranch, ["active", "draft"], // Include both active and draft entities for comparison false // Don't include cross-context for similarity detection ); const existingEntities = branchGraph.entities; let totalRelationsCreated = 0; // Process each created entity for similarity detection for (const newEntity of createdEntities) { logger.debug(`Analyzing "${newEntity.name}" for similar entities...`); // Use statistical similarity engine to detect similar entities const similarEntities = await this.modernSimilarity.detectSimilarEntities(newEntity, existingEntities.filter((e) => e.name !== newEntity.name) // Exclude self ); if (similarEntities.length > 0) { logger.info(`Found ${similarEntities.length} similar entities for "${newEntity.name}"`); // Create relationships with high-confidence matches const relationsToCreate = []; for (const match of similarEntities) { // Only auto-create relationships for high confidence matches logger.debug(`Match: "${match.entity.name}" similarity=${match.similarity.toFixed(3)} confidence=${match.confidence} type=${match.suggestedRelationType}`); if (match.confidence === "high" || match.similarity > 0.5) { relationsToCreate.push({ from: newEntity.name, to: match.entity.name, relationType: match.suggestedRelationType, }); autoRelationsResults.push({ from: newEntity.name, to: match.entity.name, relationType: match.suggestedRelationType, similarity_score: match.similarity, confidence: match.confidence, reasoning: match.reasoning, auto_created: true, }); } else { // Log medium/low confidence matches for reference autoRelationsResults.push({ from: newEntity.name, to: match.entity.name, relationType: match.suggestedRelationType, similarity_score: match.similarity, confidence: match.confidence, reasoning: match.reasoning, auto_created: false, note: "Low confidence - relation suggested but not auto-created", }); } } // Create the high-confidence relations if (relationsToCreate.length > 0) { const createdRelations = await this.memoryManager.createRelations(relationsToCreate, createBranch); totalRelationsCreated += createdRelations.length; logger.info(`Auto-created ${createdRelations.length} high-confidence relations for "${newEntity.name}"`); } } else { logger.info(`No similar entities found for "${newEntity.name}"`); logger.debug(`Similarity analysis for "${newEntity.name}": found ${similarEntities.length} candidates, threshold: 0.78`); autoRelationsResults.push({ entity: newEntity.name, message: "No similar entities found above similarity threshold", similarity_threshold: 0.5, candidates_analyzed: existingEntities.length, similarity_results: similarEntities.length, }); } } logger.info(`Auto-relationship detection complete: ${totalRelationsCreated} relations created`); // Add summary to results autoRelationsResults.unshift({ summary: `Auto-relationship detection complete`, total_relations_created: totalRelationsCreated, entities_processed: createdEntities.length, similarity_engine: "ModernSimilarityEngine", similarity_threshold: 0.65, high_confidence_threshold: 0.85, }); // Notify background indexer about new entities if (this.relationshipIndexer) { for (const entity of createdEntities) { this.relationshipIndexer.onEntityCreated(entity.name, createBranch); } } } catch (error) { logger.error("Error during automatic relationship detection:", error); autoRelationsResults.push({ error: "Auto-relationship detection failed", message: error instanceof Error ? error.message : String(error), fallback: "Relations can still be created manually", }); } } return { content: [ { type: "text", text: JSON.stringify({ created_entities: createdEntities, branch: createBranch || "main", auto_relations_enabled: args.auto_create_relations !== false, auto_relations_results: autoRelationsResults, message: `Created ${createdEntities.length} entities in branch "${createBranch || "main"}"${args.auto_create_relations !== false ? " with auto-relationship detection enabled" : ""}`, }, null, 2), }, ], }; } async handleAddObservations(args) { if (!args.observations) { throw new Error("observations array is required"); } const results = await this.memoryManager.addObservations(args.observations, args.branch_name); return { content: [ { type: "text", text: JSON.stringify({ results, branch: args.branch_name || "main", message: `Added observations to ${results.length} entities in branch "${args.branch_name || "main"}"`, }, null, 2), }, ], }; } async handleUpdateEntityStatus(args) { if (!args.entity_name || !args.status) { throw new Error("entity_name and status are required"); } await this.memoryManager.updateEntityStatus(args.entity_name, args.status, args.status_reason, args.branch_name); return { content: [ { type: "text", text: JSON.stringify({ message: `Updated entity "${args.entity_name}" status to "${args.status}" in branch "${args.branch_name || "main"}"`, entity_name: args.entity_name, new_status: args.status, status_reason: args.status_reason, branch: args.branch_name || "main", }, null, 2), }, ], }; } async handleDeleteEntities(args) { if (!args.entity_names) { throw new Error("entity_names array is required"); } await this.memoryManager.deleteEntities(args.entity_names, args.branch_name); return { content: [ { type: "text", text: JSON.stringify({ message: `Deleted ${args.entity_names.length} entities from branch "${args.branch_name || "main"}"`, deleted_entities: args.entity_names, branch: args.branch_name || "main", }, null, 2), }, ], }; } }

Latest Blog Posts

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/PrismAero/agentic-memory-server'

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