UNPKG

trellis

Version:

Agentic State Engine — event-sourced causal graph with branching, decision traces, and realtime sync for AI-native applications

362 lines (359 loc) 11.9 kB
import { __esm } from "./chunk-2ESYSVXG.js"; // src/core/store/eav-store.ts function* flatten(obj, base = "") { if (Array.isArray(obj)) { for (const v of obj) { yield* flatten(v, base); } } else if (obj && typeof obj === "object") { for (const [k, v] of Object.entries(obj)) { yield* flatten(v, base ? `${base}.${k}` : k); } } else { yield [base, obj]; } } function jsonEntityFacts(entityId, root, type) { const facts = [{ e: entityId, a: "type", v: type }]; for (const [a, v] of flatten(root)) { if (v === void 0 || v === null) continue; if (Array.isArray(v)) { for (const el of v) { facts.push({ e: entityId, a, v: el }); } } else if (typeof v === "object") { } else { facts.push({ e: entityId, a, v }); } } return facts; } var EAVStore; var init_eav_store = __esm({ "src/core/store/eav-store.ts"() { "use strict"; EAVStore = class { facts = []; links = []; catalog = /* @__PURE__ */ new Map(); // Indexes for fast lookups eavIndex = /* @__PURE__ */ new Map(); aevIndex = /* @__PURE__ */ new Map(); aveIndex = /* @__PURE__ */ new Map(); // Link indexes for graph queries linkIndex = /* @__PURE__ */ new Map(); // e1 -> a -> e2s linkReverseIndex = /* @__PURE__ */ new Map(); // e2 -> a -> e1s linkAttrIndex = /* @__PURE__ */ new Map(); // a -> [(e1, e2)] // Distinct value tracking distinct = /* @__PURE__ */ new Map(); // attr -> set of valueKey addFacts(facts) { for (let i = 0; i < facts.length; i++) { const fact = facts[i]; if (fact) { if (this.hasFact(fact.e, fact.a, fact.v)) { continue; } this.facts.push(fact); this.updateIndexes(fact, this.facts.length - 1); this.updateCatalog(fact); } } } /** * Check if a fact already exists in the store. */ hasFact(entity, attribute, value) { const valueKey = this.valueKey(value); const indices = this.aveIndex.get(attribute)?.get(valueKey); if (!indices) return false; for (const idx of indices) { const fact = this.facts[idx]; if (fact && fact.e === entity && fact.a === attribute) { return true; } } return false; } addLinks(links) { for (const link of links) { this.links.push(link); this.updateLinkIndexes(link); } } deleteFacts(factsToDelete) { for (const fact of factsToDelete) { const valueKey = this.valueKey(fact.v); const indices = this.aveIndex.get(fact.a)?.get(valueKey); if (!indices) continue; let foundIdx = -1; for (const idx of indices) { const storedFact = this.facts[idx]; if (storedFact && storedFact.e === fact.e && storedFact.a === fact.a) { foundIdx = idx; break; } } if (foundIdx !== -1) { this.facts[foundIdx] = void 0; this.eavIndex.get(fact.e)?.get(fact.a)?.delete(foundIdx); this.aevIndex.get(fact.a)?.get(fact.e)?.delete(foundIdx); this.aveIndex.get(fact.a)?.get(valueKey)?.delete(foundIdx); const entry = this.catalog.get(fact.a); if (entry) { } } } } deleteLinks(linksToDelete) { for (const link of linksToDelete) { const initialLen = this.links.length; this.links = this.links.filter( (l) => !(l.e1 === link.e1 && l.a === link.a && l.e2 === link.e2) ); if (this.links.length < initialLen) { this.linkIndex.get(link.e1)?.get(link.a)?.delete(link.e2); this.linkReverseIndex.get(link.e2)?.get(link.a)?.delete(link.e1); const attrPairs = this.linkAttrIndex.get(link.a); if (attrPairs) { for (const pair of attrPairs) { if (pair[0] === link.e1 && pair[1] === link.e2) { attrPairs.delete(pair); break; } } } } } } updateIndexes(fact, index) { if (!this.eavIndex.has(fact.e)) { this.eavIndex.set(fact.e, /* @__PURE__ */ new Map()); } if (!this.eavIndex.get(fact.e).has(fact.a)) { this.eavIndex.get(fact.e).set(fact.a, /* @__PURE__ */ new Set()); } this.eavIndex.get(fact.e).get(fact.a).add(index); if (!this.aevIndex.has(fact.a)) { this.aevIndex.set(fact.a, /* @__PURE__ */ new Map()); } if (!this.aevIndex.get(fact.a).has(fact.e)) { this.aevIndex.get(fact.a).set(fact.e, /* @__PURE__ */ new Set()); } this.aevIndex.get(fact.a).get(fact.e).add(index); if (!this.aveIndex.has(fact.a)) { this.aveIndex.set(fact.a, /* @__PURE__ */ new Map()); } const valueKey = this.valueKey(fact.v); if (!this.aveIndex.get(fact.a).has(valueKey)) { this.aveIndex.get(fact.a).set(valueKey, /* @__PURE__ */ new Set()); } this.aveIndex.get(fact.a).get(valueKey).add(index); } updateLinkIndexes(link) { if (!this.linkIndex.has(link.e1)) { this.linkIndex.set(link.e1, /* @__PURE__ */ new Map()); } const e1Attrs = this.linkIndex.get(link.e1); if (!e1Attrs.has(link.a)) { e1Attrs.set(link.a, /* @__PURE__ */ new Set()); } e1Attrs.get(link.a).add(link.e2); if (!this.linkReverseIndex.has(link.e2)) { this.linkReverseIndex.set(link.e2, /* @__PURE__ */ new Map()); } const e2Attrs = this.linkReverseIndex.get(link.e2); if (!e2Attrs.has(link.a)) { e2Attrs.set(link.a, /* @__PURE__ */ new Set()); } e2Attrs.get(link.a).add(link.e1); if (!this.linkAttrIndex.has(link.a)) { this.linkAttrIndex.set(link.a, /* @__PURE__ */ new Set()); } this.linkAttrIndex.get(link.a).add([link.e1, link.e2]); } valueKey(v) { if (v instanceof Date) return `date:${v.toISOString()}`; return `${typeof v}:${v}`; } updateCatalog(fact) { const entry = this.catalog.get(fact.a) || { attribute: fact.a, type: this.inferType(fact.v), cardinality: "one", distinctCount: 0, examples: [] }; const factType = this.inferType(fact.v); if (entry.type !== factType && entry.type !== "mixed") { entry.type = "mixed"; } const entityAttrs = this.eavIndex.get(fact.e)?.get(fact.a); if (entityAttrs && entityAttrs.size > 1) { entry.cardinality = "many"; } const k = this.valueKey(fact.v); const s = this.distinct.get(fact.a) || (this.distinct.set(fact.a, /* @__PURE__ */ new Set()), this.distinct.get(fact.a)); s.add(k); entry.distinctCount = s.size; if (entry.examples.length < 5 && !entry.examples.includes(fact.v)) { entry.examples.push(fact.v); } if (typeof fact.v === "number") { entry.min = Math.min(entry.min ?? fact.v, fact.v); entry.max = Math.max(entry.max ?? fact.v, fact.v); } this.catalog.set(fact.a, entry); } inferType(v) { if (typeof v === "string") return "string"; if (typeof v === "number") return "number"; if (typeof v === "boolean") return "boolean"; if (v instanceof Date) return "date"; return "mixed"; } // Query methods getFactsByEntity(entity) { const indices = this.eavIndex.get(entity); if (!indices) return []; const result = []; for (const attrIndices of indices.values()) { for (const idx of attrIndices) { const fact = this.facts[idx]; if (fact) { result.push(fact); } } } return result; } getFactsByAttribute(attribute) { const indices = this.aevIndex.get(attribute); if (!indices) return []; const result = []; for (const entityIndices of indices.values()) { for (const idx of entityIndices) { const fact = this.facts[idx]; if (fact) { result.push(fact); } } } return result; } getFactsByValue(attribute, value) { const indices = this.aveIndex.get(attribute)?.get(this.valueKey(value)); if (!indices) return []; return Array.from(indices).map((idx) => this.facts[idx]).filter((fact) => fact !== void 0); } getCatalog() { return Array.from(this.catalog.values()); } getCatalogEntry(attribute) { return this.catalog.get(attribute); } // Statistics getAllFacts() { return this.facts.filter((f) => f !== void 0); } getAllLinks() { return [...this.links]; } getLinksByEntity(entity) { const results = []; const forwardLinks = this.linkIndex.get(entity); if (forwardLinks) { for (const [attr, targets] of forwardLinks) { for (const target of targets) { results.push({ e1: entity, a: attr, e2: target }); } } } const reverseLinks = this.linkReverseIndex.get(entity); if (reverseLinks) { for (const [attr, sources] of reverseLinks) { for (const source of sources) { results.push({ e1: source, a: attr, e2: entity }); } } } return results; } getLinksByAttribute(attribute) { const results = []; const links = this.linkAttrIndex.get(attribute); if (links) { for (const [e1, e2] of links) { results.push({ e1, a: attribute, e2 }); } } return results; } getLinksByEntityAndAttribute(entity, attribute) { const results = []; const attrs = this.linkIndex.get(entity); if (attrs) { const targets = attrs.get(attribute); if (targets) { for (const target of targets) { results.push({ e1: entity, a: attribute, e2: target }); } } } return results; } getStats() { return { totalFacts: this.facts.length, totalLinks: this.links.length, uniqueEntities: this.eavIndex.size, uniqueAttributes: this.aevIndex.size, catalogEntries: this.catalog.size }; } /** * Creates a serializable snapshot of the current store state. */ snapshot() { return { facts: this.facts.filter((f) => f !== void 0), links: [...this.links], catalog: this.getCatalog() }; } /** * Restores the store state from a snapshot and rebuilds all indexes. */ restore(snapshot) { this.facts = []; this.links = []; this.catalog.clear(); this.eavIndex.clear(); this.aevIndex.clear(); this.aveIndex.clear(); this.linkIndex.clear(); this.linkReverseIndex.clear(); this.linkAttrIndex.clear(); this.distinct.clear(); this.addFacts(snapshot.facts); this.addLinks(snapshot.links); if (snapshot.catalog) { for (const entry of snapshot.catalog) { this.catalog.set(entry.attribute, entry); } } } }; } }); export { flatten, jsonEntityFacts, EAVStore, init_eav_store };