/** * Temporal Knowledge Graph for pi-mind memory system. * * Entity-relationship graph with temporal validity, deduplication, * confidence scoring, and bidirectional queries. * * Shares the same SQLite DB as FTS5 and vector search (.pi-mind-index.db). */ import Database from "better-sqlite3"; export interface Triple { subject: string; predicate: string; object: string; valid_from: string | null; valid_to: string | null; confidence: number; source_file: string | null; current: boolean; } export interface EntityInfo { id: string; name: string; type: string; properties: Record; } export declare class KnowledgeGraph { private db; /** * Lazy in-memory token → entity-name index, used by buildContext() to * avoid scanning all entity names + doing substring matching in JS on * every agent turn. null = not yet built; the first buildContext() call * triggers ensureEntityIndex(). Cleared on any addTriple() (newly * inserted triples can introduce new entities) and via * invalidateEntityIndexCache() from external bulk writers like * MemoryCore.rebuildKGFromFiles() after wiping the tables. */ private _entityTokenIndex; /** * Set of all entity names present in the index, kept in sync with * _entityTokenIndex. Used by the non-ASCII substring fallback in * buildContext (avoiding a second SELECT name FROM kg_entities). */ private _entityNames; constructor(db: InstanceType, opts?: { initSchema?: boolean; }); private initSchema; /** Migrate triples from old knowledge_graph table to new kg_triples */ private migrateOldTable; /** Ensure an entity exists, return its ID */ private ensureEntity; /** Get entity info */ getEntity(name: string): EntityInfo | null; /** Add a triple with deduplication. Returns triple ID or null if duplicate/invalid. */ addTriple(subject: string, predicate: string, object: string, opts?: { validFrom?: string; validTo?: string; confidence?: number; sourceFile?: string; }): string | null; /** Add multiple triples in a single transaction */ addTriplesBatch(triples: Array<[string, string, string, string?]>, sourceFile?: string): number; /** Mark a triple as expired */ invalidate(subject: string, predicate: string, object: string, ended?: string): void; /** Query all triples for an entity (bidirectional) */ queryEntity(name: string, opts?: { asOf?: string; direction?: "outgoing" | "incoming" | "both"; }): Triple[]; /** Query by relationship type */ queryRelationship(predicate: string, asOf?: string): Triple[]; /** Get timeline of all triples for an entity, sorted by valid_from */ timeline(entityName?: string): Triple[]; /** Get top-confidence current triples for L1 injection */ getTopTriples(limit?: number, minConfidence?: number): Triple[]; /** Get all entity names (for prompt matching) */ getAllEntityNames(): string[]; /** * Public invalidation hook. Callers that bulk-modify kg_entities / * kg_triples outside addTriple (notably MemoryCore.rebuildKGFromFiles * after DELETEing the tables) MUST call this so the next buildContext * doesn't serve a stale index. No-op if the index isn't built yet. */ invalidateEntityIndexCache(): void; private ensureEntityIndex; /** Build KG context block for a query (matches entity names in query text) */ buildContext(query: string): string; /** Stats for diagnostics */ stats(): { entities: number; triples: number; currentFacts: number; expiredFacts: number; }; /** * Predicates that are too generic / ambiguous to carry real signal. * Used by healthReport() to surface relation fragmentation: an agent * that writes `owns` in one place and `owner_of` in another will see * two top-predicates that should be one. The set is intentionally * small and obvious — adding entries should require a real observed * noise pattern, not a hunch. */ private static readonly SUSPICIOUS_PREDICATES; /** * Build a read-only health snapshot of the KG. Used by * `pi-mind-lint --kg-health` and surfaced via the `memory-audit` skill. * No writes. Safe to call from any context, including concurrent with * a syncIndex — the worst case is reading a mid-rebuild count, which * is still self-consistent within the call. */ healthReport(topN?: number): { summary: { entities: number; triples: number; currentFacts: number; expiredFacts: number; }; topPredicates: Array<{ predicate: string; count: number; }>; topSourceFiles: Array<{ source_file: string; triples: number; }>; topEntities: Array<{ name: string; outgoing: number; incoming: number; degree: number; }>; suspiciousPredicates: Array<{ predicate: string; count: number; reason: string; }>; orphans: { triplesPointingToMissingEntity: number; }; }; } //# sourceMappingURL=knowledge-graph.d.ts.map