Skip to main content
Glama
manager.ts6.66 kB
import { promises as fs } from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; // Define the path to the JSONL file, you can change this to your desired local path const __dirname = path.dirname(fileURLToPath(import.meta.url)); const MEMORY_FILE_PATH = path.join(__dirname, '..', '..', 'memory.json'); // Types for the knowledge graph export interface Entity { name: string; entityType: string; observations: string[]; } export interface Relation { from: string; to: string; relationType: string; } export interface KnowledgeGraph { entities: Entity[]; relations: Relation[]; } export interface EntityInput { name: string; entityType: string; observations: string[]; } export interface RelationInput { from: string; to: string; relationType: string; } export interface ObservationInput { entityName: string; contents: string[]; } export interface DeletionInput { entityName: string; observations: string[]; } export interface ObservationResult { entityName: string; addedObservations: string[]; } // The KnowledgeGraphManager class contains all operations to interact with the knowledge graph export class KnowledgeGraphManager { private memoryFilePath: string; constructor(memoryFilePath?: string) { this.memoryFilePath = memoryFilePath || MEMORY_FILE_PATH; } async loadGraph(): Promise<KnowledgeGraph> { try { const data = await fs.readFile(this.memoryFilePath, "utf-8"); const lines = data.split("\n").filter(line => line.trim() !== ""); return lines.reduce((graph: KnowledgeGraph, line) => { const item = JSON.parse(line); if (item.type === "entity") graph.entities.push(item); if (item.type === "relation") graph.relations.push(item); return graph; }, { entities: [], relations: [] }); } catch (error: any) { if (error.code === "ENOENT") { return { entities: [], relations: [] }; } throw error; } } async saveGraph(graph: KnowledgeGraph): Promise<void> { const lines = [ ...graph.entities.map(e => JSON.stringify({ type: "entity", ...e })), ...graph.relations.map(r => JSON.stringify({ type: "relation", ...r })), ]; await fs.writeFile(this.memoryFilePath, lines.join("\n")); } async createEntities(entities: EntityInput[]): Promise<EntityInput[]> { const graph = await this.loadGraph(); const newEntities = entities.filter(e => !graph.entities.some(existingEntity => existingEntity.name === e.name)); graph.entities.push(...newEntities); await this.saveGraph(graph); return newEntities; } async createRelations(relations: RelationInput[]): Promise<RelationInput[]> { const graph = await this.loadGraph(); const newRelations = relations.filter(r => !graph.relations.some(existingRelation => existingRelation.from === r.from && existingRelation.to === r.to && existingRelation.relationType === r.relationType )); graph.relations.push(...newRelations); await this.saveGraph(graph); return newRelations; } async addObservations(observations: ObservationInput[]): Promise<ObservationResult[]> { const graph = await this.loadGraph(); const results = observations.map(o => { const entity = graph.entities.find(e => e.name === o.entityName); if (!entity) { throw new Error(`Entity with name ${o.entityName} not found`); } const newObservations = o.contents.filter(content => !entity.observations.includes(content)); entity.observations.push(...newObservations); return { entityName: o.entityName, addedObservations: newObservations }; }); await this.saveGraph(graph); return results; } async deleteEntities(entityNames: string[]): Promise<void> { const graph = await this.loadGraph(); graph.entities = graph.entities.filter(e => !entityNames.includes(e.name)); graph.relations = graph.relations.filter(r => !entityNames.includes(r.from) && !entityNames.includes(r.to)); await this.saveGraph(graph); } async deleteObservations(deletions: DeletionInput[]): Promise<void> { const graph = await this.loadGraph(); deletions.forEach(d => { const entity = graph.entities.find(e => e.name === d.entityName); if (entity) { entity.observations = entity.observations.filter(o => !d.observations.includes(o)); } }); await this.saveGraph(graph); } async deleteRelations(relations: RelationInput[]): Promise<void> { const graph = await this.loadGraph(); graph.relations = graph.relations.filter(r => !relations.some(delRelation => r.from === delRelation.from && r.to === delRelation.to && r.relationType === delRelation.relationType )); await this.saveGraph(graph); } async readGraph(): Promise<KnowledgeGraph> { return this.loadGraph(); } // Very basic search function async searchNodes(query: string): Promise<KnowledgeGraph> { const graph = await this.loadGraph(); // Filter entities const filteredEntities = graph.entities.filter(e => e.name.toLowerCase().includes(query.toLowerCase()) || e.entityType.toLowerCase().includes(query.toLowerCase()) || e.observations.some(o => o.toLowerCase().includes(query.toLowerCase())) ); // Create a Set of filtered entity names for quick lookup const filteredEntityNames = new Set(filteredEntities.map(e => e.name)); // Filter relations to only include those between filtered entities const filteredRelations = graph.relations.filter(r => filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to) ); const filteredGraph: KnowledgeGraph = { entities: filteredEntities, relations: filteredRelations, }; return filteredGraph; } async openNodes(names: string[]): Promise<KnowledgeGraph> { const graph = await this.loadGraph(); // Filter entities const filteredEntities = graph.entities.filter(e => names.includes(e.name)); // Create a Set of filtered entity names for quick lookup const filteredEntityNames = new Set(filteredEntities.map(e => e.name)); // Filter relations to only include those between filtered entities const filteredRelations = graph.relations.filter(r => filteredEntityNames.has(r.from) && filteredEntityNames.has(r.to) ); const filteredGraph: KnowledgeGraph = { entities: filteredEntities, relations: filteredRelations, }; return filteredGraph; } } // Export a default instance for convenience export const knowledgeGraphManager = new KnowledgeGraphManager();

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/ali-48/rag-mcp-server'

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