@equationalapplications/core-llm-wiki 3.2.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/index.d.mts +29 -2
- package/dist/index.d.ts +29 -2
- package/dist/index.js +134 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +134 -23
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -10,7 +10,7 @@ async function setupDatabase(db, prefix) {
|
|
|
10
10
|
body TEXT NOT NULL,
|
|
11
11
|
tags TEXT NOT NULL DEFAULT '[]',
|
|
12
12
|
confidence TEXT NOT NULL DEFAULT 'inferred',
|
|
13
|
-
source_type TEXT NOT NULL DEFAULT '
|
|
13
|
+
source_type TEXT NOT NULL DEFAULT 'librarian_inferred',
|
|
14
14
|
source_hash TEXT,
|
|
15
15
|
source_ref TEXT,
|
|
16
16
|
created_at INTEGER NOT NULL,
|
|
@@ -412,6 +412,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
412
412
|
constructor(db, options) {
|
|
413
413
|
this.activeMaintenanceJobs = /* @__PURE__ */ new Set();
|
|
414
414
|
this.activeIngestJobs = /* @__PURE__ */ new Set();
|
|
415
|
+
this.statusSubscribers = /* @__PURE__ */ new Map();
|
|
415
416
|
this.miniSearch = new MiniSearch({
|
|
416
417
|
fields: ["title", "body", "tags"],
|
|
417
418
|
storeFields: ["entity_id"],
|
|
@@ -587,6 +588,44 @@ var _WikiMemory = class _WikiMemory {
|
|
|
587
588
|
_warnCrossEntityCollision(type, id, existingEntityId, targetEntityId) {
|
|
588
589
|
console.warn(`[WikiMemory] importDump: ${type} id "${id}" already belongs to entity "${existingEntityId}"; skipping for entity "${targetEntityId}"`);
|
|
589
590
|
}
|
|
591
|
+
/** Maps pre-rename enum strings from older dumps to current source_type values. */
|
|
592
|
+
_normalizeImportedSourceType(raw, ctx) {
|
|
593
|
+
if (raw === "user_document") return "immutable_document";
|
|
594
|
+
if (raw === "agent_inferred") return "librarian_inferred";
|
|
595
|
+
const allowed = ["user_stated", "librarian_inferred", "user_confirmed", "immutable_document"];
|
|
596
|
+
if (allowed.includes(raw)) return raw;
|
|
597
|
+
const where = ctx !== void 0 ? ` for entity "${ctx.entityId}" fact "${ctx.factId}"` : "";
|
|
598
|
+
throw new Error(
|
|
599
|
+
`importDump: invalid source_type "${raw}"${where} (expected one of: ${allowed.join(", ")}, or legacy aliases user_document / agent_inferred)`
|
|
600
|
+
);
|
|
601
|
+
}
|
|
602
|
+
async assertNoLegacySourceTypes() {
|
|
603
|
+
const legacyProbe = await this.db.getFirstAsync(
|
|
604
|
+
`SELECT 1 AS one FROM ${this.prefix}entries
|
|
605
|
+
WHERE source_type IN ('user_document', 'agent_inferred')
|
|
606
|
+
LIMIT 1`,
|
|
607
|
+
[]
|
|
608
|
+
);
|
|
609
|
+
if (!legacyProbe) return;
|
|
610
|
+
const legacyCount = await this.db.getFirstAsync(
|
|
611
|
+
`SELECT COUNT(*) as count FROM ${this.prefix}entries
|
|
612
|
+
WHERE source_type IN ('user_document', 'agent_inferred')`,
|
|
613
|
+
[]
|
|
614
|
+
);
|
|
615
|
+
const count = legacyCount?.count ?? 0;
|
|
616
|
+
const migrationSQL = `
|
|
617
|
+
-- Migrate legacy source_type values (targets your WikiMemory prefix: ${this.prefix})
|
|
618
|
+
UPDATE ${this.prefix}entries SET source_type = 'immutable_document' WHERE source_type = 'user_document';
|
|
619
|
+
UPDATE ${this.prefix}entries SET source_type = 'librarian_inferred' WHERE source_type = 'agent_inferred';
|
|
620
|
+
`.trim();
|
|
621
|
+
throw new Error(
|
|
622
|
+
`Database contains ${count} entries with legacy source_type values ('user_document' or 'agent_inferred'). These enum values were renamed in this release. Running without migration would allow legacy 'user_document' facts to bypass immutability guards, causing data corruption.
|
|
623
|
+
|
|
624
|
+
${migrationSQL}
|
|
625
|
+
|
|
626
|
+
After running the migration SQL, restart your application.`
|
|
627
|
+
);
|
|
628
|
+
}
|
|
590
629
|
async _notifyEmbeddingPersisted(entityId, factId, vector) {
|
|
591
630
|
if (!this.options.vectorRanker?.onEmbeddingPersisted) return;
|
|
592
631
|
const vectorCopy = vector ? vector.slice() : null;
|
|
@@ -688,6 +727,9 @@ var _WikiMemory = class _WikiMemory {
|
|
|
688
727
|
);
|
|
689
728
|
}
|
|
690
729
|
}
|
|
730
|
+
if (entriesExistedBeforeSetup) {
|
|
731
|
+
await this.assertNoLegacySourceTypes();
|
|
732
|
+
}
|
|
691
733
|
const rows = await this.db.getAllAsync(`
|
|
692
734
|
SELECT rowid, source_ref FROM ${this.prefix}entries
|
|
693
735
|
WHERE source_ref IS NOT NULL
|
|
@@ -775,6 +817,24 @@ var _WikiMemory = class _WikiMemory {
|
|
|
775
817
|
}
|
|
776
818
|
return false;
|
|
777
819
|
}
|
|
820
|
+
_copyEntityStatus(s) {
|
|
821
|
+
return { ingesting: s.ingesting, librarian: s.librarian, heal: s.heal };
|
|
822
|
+
}
|
|
823
|
+
_notifyStatusSubscribers(entityId) {
|
|
824
|
+
const set = this.statusSubscribers.get(entityId);
|
|
825
|
+
if (!set || set.size === 0) return;
|
|
826
|
+
for (const entry of Array.from(set)) {
|
|
827
|
+
if (!set.has(entry)) continue;
|
|
828
|
+
const next = this.getEntityStatus(entityId);
|
|
829
|
+
if (entry.last.ingesting === next.ingesting && entry.last.librarian === next.librarian && entry.last.heal === next.heal) continue;
|
|
830
|
+
entry.last = this._copyEntityStatus(next);
|
|
831
|
+
try {
|
|
832
|
+
entry.callback(this._copyEntityStatus(next));
|
|
833
|
+
} catch (err) {
|
|
834
|
+
console.error(`[WikiMemory.subscribeEntityStatus] callback error for entityId="${entityId}" during transition emission`, err);
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
}
|
|
778
838
|
_validatePruneDuration(value, name) {
|
|
779
839
|
if (value !== null && value !== void 0 && (typeof value !== "number" || !isFinite(value) || value < 0)) {
|
|
780
840
|
throw new Error(`Invalid ${name}: must be a non-negative finite number or null`);
|
|
@@ -824,7 +884,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
824
884
|
const cutoff = now - retainSoftDeletedFor * 864e5;
|
|
825
885
|
const entriesToDelete = await this.db.getAllAsync(
|
|
826
886
|
`SELECT id, entity_id FROM ${this.prefix}entries
|
|
827
|
-
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at
|
|
887
|
+
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at <= ?`,
|
|
828
888
|
[entityId, cutoff]
|
|
829
889
|
);
|
|
830
890
|
const succeeded = [];
|
|
@@ -844,7 +904,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
844
904
|
const chunk = succeeded.slice(i, i + chunkSize);
|
|
845
905
|
const placeholders = chunk.map(() => "?").join(",");
|
|
846
906
|
const entryResult = await this.db.runAsync(
|
|
847
|
-
`DELETE FROM ${this.prefix}entries WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at
|
|
907
|
+
`DELETE FROM ${this.prefix}entries WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at <= ? AND id IN (${placeholders})`,
|
|
848
908
|
[entityId, cutoff, ...chunk.map((r) => r.id)]
|
|
849
909
|
);
|
|
850
910
|
deletedEntries += entryResult.changes;
|
|
@@ -852,7 +912,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
852
912
|
}
|
|
853
913
|
const taskResult = await this.db.runAsync(
|
|
854
914
|
`DELETE FROM ${this.prefix}tasks
|
|
855
|
-
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at
|
|
915
|
+
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at <= ?`,
|
|
856
916
|
[entityId, cutoff]
|
|
857
917
|
);
|
|
858
918
|
deletedTasks = taskResult.changes;
|
|
@@ -890,7 +950,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
890
950
|
const cutoff = now - retainEventsFor * 864e5;
|
|
891
951
|
const eventResult = await this.db.runAsync(
|
|
892
952
|
`DELETE FROM ${this.prefix}events
|
|
893
|
-
WHERE entity_id = ? AND created_at
|
|
953
|
+
WHERE entity_id = ? AND created_at <= ?`,
|
|
894
954
|
[entityId, cutoff]
|
|
895
955
|
);
|
|
896
956
|
deletedEvents = eventResult.changes;
|
|
@@ -1517,7 +1577,11 @@ var _WikiMemory = class _WikiMemory {
|
|
|
1517
1577
|
const jobKey = this._librarianKey(entityId);
|
|
1518
1578
|
if (!this.activeMaintenanceJobs.has(jobKey) && !this.activeMaintenanceJobs.has(this._pruneKey(entityId)) && !this._isReembedActive(entityId) && !this._isImportActiveFor(entityId) && !this._isForgetActiveFor(entityId)) {
|
|
1519
1579
|
this.activeMaintenanceJobs.add(jobKey);
|
|
1520
|
-
this.
|
|
1580
|
+
this._notifyStatusSubscribers(entityId);
|
|
1581
|
+
this.runLibrarianThenMaybeHeal(entityId, count).catch(console.error).finally(() => {
|
|
1582
|
+
this.activeMaintenanceJobs.delete(jobKey);
|
|
1583
|
+
this._notifyStatusSubscribers(entityId);
|
|
1584
|
+
});
|
|
1521
1585
|
}
|
|
1522
1586
|
}
|
|
1523
1587
|
}
|
|
@@ -1536,6 +1600,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
1536
1600
|
const healKey = this._healKey(entityId);
|
|
1537
1601
|
if (!this.activeMaintenanceJobs.has(healKey)) {
|
|
1538
1602
|
this.activeMaintenanceJobs.add(healKey);
|
|
1603
|
+
this._notifyStatusSubscribers(entityId);
|
|
1539
1604
|
try {
|
|
1540
1605
|
await this._doRunHeal(entityId);
|
|
1541
1606
|
await this.db.runAsync(`
|
|
@@ -1545,6 +1610,7 @@ var _WikiMemory = class _WikiMemory {
|
|
|
1545
1610
|
`, [entityId, currentEventCount, currentEventCount]);
|
|
1546
1611
|
} finally {
|
|
1547
1612
|
this.activeMaintenanceJobs.delete(healKey);
|
|
1613
|
+
this._notifyStatusSubscribers(entityId);
|
|
1548
1614
|
}
|
|
1549
1615
|
}
|
|
1550
1616
|
}
|
|
@@ -1591,7 +1657,7 @@ ${JSON.stringify(currentFacts, null, 2)}`;
|
|
|
1591
1657
|
let skip = false;
|
|
1592
1658
|
if (newTokens.size >= MIN_TOKENS_TO_QUALIFY) {
|
|
1593
1659
|
for (const existing of currentFactsRows) {
|
|
1594
|
-
if (existing.source_type !== "
|
|
1660
|
+
if (existing.source_type !== "librarian_inferred") continue;
|
|
1595
1661
|
const existingTokens = titleTokens(existing.title);
|
|
1596
1662
|
if (existingTokens.size >= MIN_TOKENS_TO_QUALIFY) {
|
|
1597
1663
|
if (jaccardScore(newTokens, existingTokens) >= FUZZY_THRESHOLD) {
|
|
@@ -1606,7 +1672,7 @@ ${JSON.stringify(currentFacts, null, 2)}`;
|
|
|
1606
1672
|
await this.db.runAsync(`
|
|
1607
1673
|
INSERT INTO ${this.prefix}entries (id, entity_id, title, body, tags, confidence, source_type, created_at, updated_at)
|
|
1608
1674
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1609
|
-
`, [id, entityId, fact.title, fact.body, JSON.stringify(fact.tags), fact.confidence, "
|
|
1675
|
+
`, [id, entityId, fact.title, fact.body, JSON.stringify(fact.tags), fact.confidence, "librarian_inferred", now, now]);
|
|
1610
1676
|
insertedFacts.push({ id, entity_id: entityId, title: fact.title, body: fact.body, tags: JSON.stringify(fact.tags) });
|
|
1611
1677
|
}
|
|
1612
1678
|
for (const task of validTasks) {
|
|
@@ -1639,25 +1705,25 @@ ${JSON.stringify(currentFacts, null, 2)}`;
|
|
|
1639
1705
|
if (orphanAfterDays !== null) {
|
|
1640
1706
|
const orphanThreshold = now - orphanAfterDays * MS_PER_DAY;
|
|
1641
1707
|
await this.db.runAsync(`
|
|
1642
|
-
UPDATE ${this.prefix}entries
|
|
1643
|
-
SET deleted_at = ?, updated_at = ?
|
|
1644
|
-
WHERE entity_id = ? AND access_count = 0 AND created_at
|
|
1708
|
+
UPDATE ${this.prefix}entries
|
|
1709
|
+
SET deleted_at = ?, updated_at = ?
|
|
1710
|
+
WHERE entity_id = ? AND access_count = 0 AND created_at <= ? AND source_type != 'immutable_document' AND deleted_at IS NULL
|
|
1645
1711
|
`, [now, now, entityId, orphanThreshold]);
|
|
1646
1712
|
}
|
|
1647
1713
|
if (staleInferredAfterDays !== null) {
|
|
1648
1714
|
const staleThreshold = now - staleInferredAfterDays * MS_PER_DAY;
|
|
1649
1715
|
await this.db.runAsync(`
|
|
1650
|
-
UPDATE ${this.prefix}entries
|
|
1651
|
-
SET confidence = 'tentative', updated_at = ?
|
|
1652
|
-
WHERE entity_id = ? AND confidence = 'inferred' AND (last_accessed_at
|
|
1716
|
+
UPDATE ${this.prefix}entries
|
|
1717
|
+
SET confidence = 'tentative', updated_at = ?
|
|
1718
|
+
WHERE entity_id = ? AND confidence = 'inferred' AND (last_accessed_at <= ? OR (last_accessed_at IS NULL AND created_at <= ?)) AND source_type != 'immutable_document' AND deleted_at IS NULL
|
|
1653
1719
|
`, [now, entityId, staleThreshold, staleThreshold]);
|
|
1654
1720
|
}
|
|
1655
1721
|
});
|
|
1656
1722
|
const allFactsRows = await this.db.getAllAsync(`SELECT * FROM ${this.prefix}entries WHERE entity_id = ? AND deleted_at IS NULL`, [entityId]);
|
|
1657
1723
|
const allTasks = await this.db.getAllAsync(`SELECT * FROM ${this.prefix}tasks WHERE entity_id = ? AND status IN ('pending', 'in_progress') AND deleted_at IS NULL`, [entityId]);
|
|
1658
1724
|
const recentEvents = await this.db.getAllAsync(`SELECT * FROM ${this.prefix}events WHERE entity_id = ? ORDER BY created_at DESC LIMIT 20`, [entityId]);
|
|
1659
|
-
const healCandidates = allFactsRows.filter((f) => f.source_type !== "
|
|
1660
|
-
const documentAnchors = allFactsRows.filter((f) => f.source_type === "
|
|
1725
|
+
const healCandidates = allFactsRows.filter((f) => f.source_type !== "immutable_document");
|
|
1726
|
+
const documentAnchors = allFactsRows.filter((f) => f.source_type === "immutable_document").map(({ id, title, source_ref }) => ({ id, title, source_ref }));
|
|
1661
1727
|
const userPrompt = `Heal Candidates:
|
|
1662
1728
|
${JSON.stringify(healCandidates.map((f) => {
|
|
1663
1729
|
const { embedding: _embedding, embedding_blob: _blob, ...rest } = f;
|
|
@@ -1700,7 +1766,7 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
1700
1766
|
await this.db.runAsync(`
|
|
1701
1767
|
INSERT INTO ${this.prefix}entries (id, entity_id, title, body, tags, confidence, source_type, created_at, updated_at)
|
|
1702
1768
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
1703
|
-
`, [id, entityId, fact.title, fact.body, JSON.stringify(fact.tags), fact.confidence, "
|
|
1769
|
+
`, [id, entityId, fact.title, fact.body, JSON.stringify(fact.tags), fact.confidence, "librarian_inferred", now, now]);
|
|
1704
1770
|
insertedFacts.push({ id, entity_id: entityId, title: fact.title, body: fact.body, tags: JSON.stringify(fact.tags) });
|
|
1705
1771
|
}
|
|
1706
1772
|
});
|
|
@@ -1736,10 +1802,12 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
1736
1802
|
throw new WikiBusyError("forget", entityId);
|
|
1737
1803
|
}
|
|
1738
1804
|
this.activeMaintenanceJobs.add(jobKey);
|
|
1805
|
+
this._notifyStatusSubscribers(entityId);
|
|
1739
1806
|
try {
|
|
1740
1807
|
await this._doRunLibrarian(entityId);
|
|
1741
1808
|
} finally {
|
|
1742
1809
|
this.activeMaintenanceJobs.delete(jobKey);
|
|
1810
|
+
this._notifyStatusSubscribers(entityId);
|
|
1743
1811
|
}
|
|
1744
1812
|
}
|
|
1745
1813
|
async runHeal(entityId) {
|
|
@@ -1760,10 +1828,12 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
1760
1828
|
throw new WikiBusyError("forget", entityId);
|
|
1761
1829
|
}
|
|
1762
1830
|
this.activeMaintenanceJobs.add(jobKey);
|
|
1831
|
+
this._notifyStatusSubscribers(entityId);
|
|
1763
1832
|
try {
|
|
1764
1833
|
await this._doRunHeal(entityId);
|
|
1765
1834
|
} finally {
|
|
1766
1835
|
this.activeMaintenanceJobs.delete(jobKey);
|
|
1836
|
+
this._notifyStatusSubscribers(entityId);
|
|
1767
1837
|
}
|
|
1768
1838
|
}
|
|
1769
1839
|
async runReembed(entityId, opts) {
|
|
@@ -1903,6 +1973,40 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
1903
1973
|
heal: this.activeMaintenanceJobs.has(this._healKey(entityId))
|
|
1904
1974
|
};
|
|
1905
1975
|
}
|
|
1976
|
+
/**
|
|
1977
|
+
* Subscribe to {@link EntityStatus} changes for a single entity. The callback
|
|
1978
|
+
* is invoked synchronously once with the current status before this method
|
|
1979
|
+
* returns, then again on every transition where any of `ingesting`,
|
|
1980
|
+
* `librarian`, or `heal` flips. No polling, no duplicate snapshots.
|
|
1981
|
+
*
|
|
1982
|
+
* Returns an idempotent unsubscribe function.
|
|
1983
|
+
*
|
|
1984
|
+
* See also {@link getEntityStatus} for a synchronous point-in-time read.
|
|
1985
|
+
*/
|
|
1986
|
+
subscribeEntityStatus(entityId, callback) {
|
|
1987
|
+
const initial = this.getEntityStatus(entityId);
|
|
1988
|
+
let set = this.statusSubscribers.get(entityId);
|
|
1989
|
+
if (!set) {
|
|
1990
|
+
set = /* @__PURE__ */ new Set();
|
|
1991
|
+
this.statusSubscribers.set(entityId, set);
|
|
1992
|
+
}
|
|
1993
|
+
const entry = { callback, last: this._copyEntityStatus(initial) };
|
|
1994
|
+
set.add(entry);
|
|
1995
|
+
try {
|
|
1996
|
+
callback(this._copyEntityStatus(initial));
|
|
1997
|
+
} catch (err) {
|
|
1998
|
+
console.error(`[WikiMemory.subscribeEntityStatus] callback error for entityId="${entityId}" during initial emission`, err);
|
|
1999
|
+
}
|
|
2000
|
+
let active = true;
|
|
2001
|
+
return () => {
|
|
2002
|
+
if (!active) return;
|
|
2003
|
+
active = false;
|
|
2004
|
+
const s = this.statusSubscribers.get(entityId);
|
|
2005
|
+
if (!s) return;
|
|
2006
|
+
s.delete(entry);
|
|
2007
|
+
if (s.size === 0) this.statusSubscribers.delete(entityId);
|
|
2008
|
+
};
|
|
2009
|
+
}
|
|
1906
2010
|
clearVectorCache() {
|
|
1907
2011
|
this.vectorCache.clear();
|
|
1908
2012
|
}
|
|
@@ -2000,6 +2104,7 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
2000
2104
|
this.activeMaintenanceJobs.add(this._importKey(entityId));
|
|
2001
2105
|
}
|
|
2002
2106
|
try {
|
|
2107
|
+
await this.assertNoLegacySourceTypes();
|
|
2003
2108
|
for (const [entityId, bundle] of Object.entries(dump.entities)) {
|
|
2004
2109
|
await this._doImportEntity(entityId, bundle, merge);
|
|
2005
2110
|
}
|
|
@@ -2053,6 +2158,10 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
2053
2158
|
}
|
|
2054
2159
|
}
|
|
2055
2160
|
for (const fact of bundle.facts) {
|
|
2161
|
+
const sourceType = this._normalizeImportedSourceType(String(fact.source_type), {
|
|
2162
|
+
entityId,
|
|
2163
|
+
factId: fact.id
|
|
2164
|
+
});
|
|
2056
2165
|
const tagsJson = JSON.stringify(Array.isArray(fact.tags) ? fact.tags : []);
|
|
2057
2166
|
const safeUpdatedAt = Number.isFinite(fact.updated_at) ? fact.updated_at : 0;
|
|
2058
2167
|
const existing = existingFactsById.get(fact.id);
|
|
@@ -2101,14 +2210,14 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
2101
2210
|
if (blobData != null) {
|
|
2102
2211
|
await this.db.runAsync(
|
|
2103
2212
|
`UPDATE ${this.prefix}entries SET entity_id = ?, title = ?, body = ?, tags = ?, confidence = ?, source_type = ?, source_hash = ?, source_ref = ?, created_at = ?, updated_at = ?, last_accessed_at = ?, access_count = ?, deleted_at = ?, embedding_blob = ?, embedding = NULL WHERE id = ?`,
|
|
2104
|
-
[entityId, fact.title, fact.body, tagsJson, fact.confidence,
|
|
2213
|
+
[entityId, fact.title, fact.body, tagsJson, fact.confidence, sourceType, fact.source_hash, fact.source_ref, fact.created_at, safeUpdatedAt, fact.last_accessed_at, fact.access_count, fact.deleted_at, blobData, fact.id]
|
|
2105
2214
|
);
|
|
2106
2215
|
factsWithPreservedBlob.set(fact.id, blobData);
|
|
2107
2216
|
if (!fact.deleted_at) preservedBlobDims.add(blobData.byteLength / 4);
|
|
2108
2217
|
} else {
|
|
2109
2218
|
await this.db.runAsync(
|
|
2110
2219
|
`UPDATE ${this.prefix}entries SET entity_id = ?, title = ?, body = ?, tags = ?, confidence = ?, source_type = ?, source_hash = ?, source_ref = ?, created_at = ?, updated_at = ?, last_accessed_at = ?, access_count = ?, deleted_at = ?, embedding_blob = NULL, embedding = NULL WHERE id = ?`,
|
|
2111
|
-
[entityId, fact.title, fact.body, tagsJson, fact.confidence,
|
|
2220
|
+
[entityId, fact.title, fact.body, tagsJson, fact.confidence, sourceType, fact.source_hash, fact.source_ref, fact.created_at, safeUpdatedAt, fact.last_accessed_at, fact.access_count, fact.deleted_at, fact.id]
|
|
2112
2221
|
);
|
|
2113
2222
|
}
|
|
2114
2223
|
existingFactsById.set(fact.id, { id: fact.id, entity_id: entityId, updated_at: safeUpdatedAt });
|
|
@@ -2118,14 +2227,14 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
2118
2227
|
if (blobData != null) {
|
|
2119
2228
|
await this.db.runAsync(
|
|
2120
2229
|
`INSERT INTO ${this.prefix}entries (id, entity_id, title, body, tags, confidence, source_type, source_hash, source_ref, created_at, updated_at, last_accessed_at, access_count, deleted_at, embedding_blob) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2121
|
-
[fact.id, entityId, fact.title, fact.body, tagsJson, fact.confidence,
|
|
2230
|
+
[fact.id, entityId, fact.title, fact.body, tagsJson, fact.confidence, sourceType, fact.source_hash, fact.source_ref, fact.created_at, safeUpdatedAt, fact.last_accessed_at, fact.access_count, fact.deleted_at, blobData]
|
|
2122
2231
|
);
|
|
2123
2232
|
factsWithPreservedBlob.set(fact.id, blobData);
|
|
2124
2233
|
if (!fact.deleted_at) preservedBlobDims.add(blobData.byteLength / 4);
|
|
2125
2234
|
} else {
|
|
2126
2235
|
await this.db.runAsync(
|
|
2127
2236
|
`INSERT INTO ${this.prefix}entries (id, entity_id, title, body, tags, confidence, source_type, source_hash, source_ref, created_at, updated_at, last_accessed_at, access_count, deleted_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2128
|
-
[fact.id, entityId, fact.title, fact.body, tagsJson, fact.confidence,
|
|
2237
|
+
[fact.id, entityId, fact.title, fact.body, tagsJson, fact.confidence, sourceType, fact.source_hash, fact.source_ref, fact.created_at, safeUpdatedAt, fact.last_accessed_at, fact.access_count, fact.deleted_at]
|
|
2129
2238
|
);
|
|
2130
2239
|
}
|
|
2131
2240
|
existingFactsById.set(fact.id, { id: fact.id, entity_id: entityId, updated_at: safeUpdatedAt });
|
|
@@ -2423,6 +2532,7 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
2423
2532
|
throw new WikiBusyError("forget", entityId);
|
|
2424
2533
|
}
|
|
2425
2534
|
this.activeIngestJobs.add(jobKey);
|
|
2535
|
+
this._notifyStatusSubscribers(entityId);
|
|
2426
2536
|
try {
|
|
2427
2537
|
const { chunks, truncated } = chunkText(params.documentChunk, maxChunkLength, chunkOverlap);
|
|
2428
2538
|
if (chunks.length === 0) {
|
|
@@ -2472,7 +2582,7 @@ ${chunk}`;
|
|
|
2472
2582
|
await this.db.runAsync(
|
|
2473
2583
|
`INSERT INTO ${this.prefix}entries (id, entity_id, title, body, tags, confidence, source_type, source_hash, source_ref, created_at, updated_at)
|
|
2474
2584
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
2475
|
-
[id, entityId, fact.title, fact.body, JSON.stringify(fact.tags), fact.confidence, "
|
|
2585
|
+
[id, entityId, fact.title, fact.body, JSON.stringify(fact.tags), fact.confidence, "immutable_document", sourceHash, sourceRef, now, now]
|
|
2476
2586
|
);
|
|
2477
2587
|
insertedFacts.push({ id, entity_id: entityId, title: fact.title, body: fact.body, tags: JSON.stringify(fact.tags) });
|
|
2478
2588
|
}
|
|
@@ -2494,6 +2604,7 @@ ${chunk}`;
|
|
|
2494
2604
|
return { truncated, chunks: chunks.length };
|
|
2495
2605
|
} finally {
|
|
2496
2606
|
this.activeIngestJobs.delete(jobKey);
|
|
2607
|
+
this._notifyStatusSubscribers(entityId);
|
|
2497
2608
|
}
|
|
2498
2609
|
}
|
|
2499
2610
|
};
|
|
@@ -2731,6 +2842,6 @@ function createWiki(db, options) {
|
|
|
2731
2842
|
return new WikiMemory(db, options);
|
|
2732
2843
|
}
|
|
2733
2844
|
|
|
2734
|
-
export { PrunePartialFailureError, WikiBusyError, WikiMemory, createWiki, formatContext, formatMemoryDump };
|
|
2845
|
+
export { PrunePartialFailureError, WikiBusyError, WikiMemory, createWiki, formatContext, formatMemoryDump, parseEmbedding };
|
|
2735
2846
|
//# sourceMappingURL=index.mjs.map
|
|
2736
2847
|
//# sourceMappingURL=index.mjs.map
|