@equationalapplications/expo-llm-wiki 2.1.0 → 2.3.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 +122 -12
- package/dist/{WikiMemory-BDVn-TJf.d.mts → WikiMemory-ChQmVyvA.d.mts} +29 -3
- package/dist/{WikiMemory-BDVn-TJf.d.ts → WikiMemory-ChQmVyvA.d.ts} +29 -3
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +324 -39
- package/dist/index.mjs +323 -39
- package/dist/react/index.d.mts +30 -3
- package/dist/react/index.d.ts +30 -3
- package/dist/react/index.js +57 -3
- package/dist/react/index.mjs +56 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23,6 +23,7 @@ __export(index_exports, {
|
|
|
23
23
|
WikiBusyError: () => WikiBusyError,
|
|
24
24
|
WikiMemory: () => WikiMemory,
|
|
25
25
|
createWiki: () => createWiki,
|
|
26
|
+
formatContext: () => formatContext,
|
|
26
27
|
formatMemoryDump: () => formatMemoryDump
|
|
27
28
|
});
|
|
28
29
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -110,9 +111,64 @@ async function setupDatabase(db, prefix) {
|
|
|
110
111
|
heal_checkpoint INTEGER NOT NULL DEFAULT 0,
|
|
111
112
|
memory_checkpoint INTEGER NOT NULL DEFAULT 0
|
|
112
113
|
);
|
|
114
|
+
|
|
115
|
+
CREATE TABLE IF NOT EXISTS ${prefix}meta (
|
|
116
|
+
key TEXT PRIMARY KEY,
|
|
117
|
+
value TEXT NOT NULL
|
|
118
|
+
);
|
|
113
119
|
`);
|
|
114
120
|
}
|
|
115
121
|
|
|
122
|
+
// src/db/migrations.ts
|
|
123
|
+
var MIGRATIONS = [
|
|
124
|
+
{
|
|
125
|
+
version: 1,
|
|
126
|
+
description: "Rebuild FTS5 with porter unicode61 tokenizer",
|
|
127
|
+
run: async (db, prefix) => {
|
|
128
|
+
await db.withTransactionAsync(async () => {
|
|
129
|
+
await db.execAsync(`
|
|
130
|
+
DROP TRIGGER IF EXISTS ${prefix}entries_ai;
|
|
131
|
+
DROP TRIGGER IF EXISTS ${prefix}entries_ad;
|
|
132
|
+
DROP TRIGGER IF EXISTS ${prefix}entries_au;
|
|
133
|
+
DROP TABLE IF EXISTS ${prefix}entries_fts;
|
|
134
|
+
CREATE VIRTUAL TABLE ${prefix}entries_fts USING fts5(
|
|
135
|
+
title,
|
|
136
|
+
body,
|
|
137
|
+
tags,
|
|
138
|
+
content='${prefix}entries',
|
|
139
|
+
content_rowid='rowid',
|
|
140
|
+
tokenize='porter unicode61'
|
|
141
|
+
);
|
|
142
|
+
INSERT INTO ${prefix}entries_fts(rowid, title, body, tags)
|
|
143
|
+
SELECT rowid, title, body, tags FROM ${prefix}entries;
|
|
144
|
+
CREATE TRIGGER ${prefix}entries_ai AFTER INSERT ON ${prefix}entries BEGIN
|
|
145
|
+
INSERT INTO ${prefix}entries_fts(rowid, title, body, tags)
|
|
146
|
+
VALUES (new.rowid, new.title, new.body, new.tags);
|
|
147
|
+
END;
|
|
148
|
+
CREATE TRIGGER ${prefix}entries_ad AFTER DELETE ON ${prefix}entries BEGIN
|
|
149
|
+
INSERT INTO ${prefix}entries_fts(${prefix}entries_fts, rowid, title, body, tags)
|
|
150
|
+
VALUES ('delete', old.rowid, old.title, old.body, old.tags);
|
|
151
|
+
END;
|
|
152
|
+
CREATE TRIGGER ${prefix}entries_au AFTER UPDATE ON ${prefix}entries BEGIN
|
|
153
|
+
INSERT INTO ${prefix}entries_fts(${prefix}entries_fts, rowid, title, body, tags)
|
|
154
|
+
VALUES ('delete', old.rowid, old.title, old.body, old.tags);
|
|
155
|
+
INSERT INTO ${prefix}entries_fts(rowid, title, body, tags)
|
|
156
|
+
VALUES (new.rowid, new.title, new.body, new.tags);
|
|
157
|
+
END;
|
|
158
|
+
`);
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
];
|
|
163
|
+
for (let i = 1; i < MIGRATIONS.length; i++) {
|
|
164
|
+
if (MIGRATIONS[i].version <= MIGRATIONS[i - 1].version) {
|
|
165
|
+
throw new Error(
|
|
166
|
+
`migrations.ts: MIGRATIONS must be in strictly ascending version order. Found version ${MIGRATIONS[i].version} after ${MIGRATIONS[i - 1].version} at index ${i}.`
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
var CURRENT_SCHEMA_VERSION = MIGRATIONS.length > 0 ? MIGRATIONS[MIGRATIONS.length - 1].version : 0;
|
|
171
|
+
|
|
116
172
|
// src/types.ts
|
|
117
173
|
var WikiBusyError = class extends Error {
|
|
118
174
|
operation;
|
|
@@ -373,45 +429,54 @@ var WikiMemory = class {
|
|
|
373
429
|
this.prefix = options.config?.tablePrefix || "llm_wiki_";
|
|
374
430
|
}
|
|
375
431
|
async setup() {
|
|
376
|
-
await
|
|
377
|
-
|
|
378
|
-
`
|
|
379
|
-
[`${this.prefix}entries_fts`]
|
|
432
|
+
const entriesExistedBeforeSetup = await this.db.getFirstAsync(
|
|
433
|
+
`SELECT name FROM sqlite_master WHERE type='table' AND name=?`,
|
|
434
|
+
[`${this.prefix}entries`]
|
|
380
435
|
);
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
436
|
+
await setupDatabase(this.db, this.prefix);
|
|
437
|
+
let currentVersion;
|
|
438
|
+
if (!entriesExistedBeforeSetup) {
|
|
439
|
+
await this.db.runAsync(
|
|
440
|
+
`INSERT OR REPLACE INTO ${this.prefix}meta (key, value) VALUES ('schema_version', ?)`,
|
|
441
|
+
[String(CURRENT_SCHEMA_VERSION)]
|
|
442
|
+
);
|
|
443
|
+
currentVersion = CURRENT_SCHEMA_VERSION;
|
|
444
|
+
} else {
|
|
445
|
+
const metaRow = await this.db.getFirstAsync(
|
|
446
|
+
`SELECT value FROM ${this.prefix}meta WHERE key = 'schema_version'`
|
|
447
|
+
);
|
|
448
|
+
if (metaRow) {
|
|
449
|
+
currentVersion = parseInt(metaRow.value, 10);
|
|
450
|
+
if (!Number.isFinite(currentVersion)) currentVersion = 0;
|
|
451
|
+
} else {
|
|
452
|
+
const ftsMeta = await this.db.getFirstAsync(
|
|
453
|
+
`SELECT sql FROM sqlite_master WHERE type='table' AND name=?`,
|
|
454
|
+
[`${this.prefix}entries_fts`]
|
|
455
|
+
);
|
|
456
|
+
const hasPorter = /tokenize\s*=\s*['"]porter\s+unicode61['"]/i.test(ftsMeta?.sql ?? "");
|
|
457
|
+
currentVersion = hasPorter ? 1 : 0;
|
|
458
|
+
}
|
|
459
|
+
}
|
|
460
|
+
for (const migration of MIGRATIONS) {
|
|
461
|
+
if (migration.version > currentVersion) {
|
|
462
|
+
await migration.run(this.db, this.prefix);
|
|
463
|
+
await this.db.runAsync(
|
|
464
|
+
`INSERT OR REPLACE INTO ${this.prefix}meta (key, value) VALUES ('schema_version', ?)`,
|
|
465
|
+
[String(migration.version)]
|
|
466
|
+
);
|
|
467
|
+
currentVersion = migration.version;
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
if (entriesExistedBeforeSetup) {
|
|
471
|
+
const metaCheck = await this.db.getFirstAsync(
|
|
472
|
+
`SELECT value FROM ${this.prefix}meta WHERE key = 'schema_version'`
|
|
473
|
+
);
|
|
474
|
+
if (!metaCheck) {
|
|
475
|
+
await this.db.runAsync(
|
|
476
|
+
`INSERT OR REPLACE INTO ${this.prefix}meta (key, value) VALUES ('schema_version', ?)`,
|
|
477
|
+
[String(currentVersion)]
|
|
478
|
+
);
|
|
479
|
+
}
|
|
415
480
|
}
|
|
416
481
|
const rows = await this.db.getAllAsync(`
|
|
417
482
|
SELECT rowid, source_ref FROM ${this.prefix}entries
|
|
@@ -436,6 +501,101 @@ var WikiMemory = class {
|
|
|
436
501
|
}
|
|
437
502
|
});
|
|
438
503
|
}
|
|
504
|
+
async hasChanged(entityId, sourceRef, sourceHash) {
|
|
505
|
+
const normalizedRef = normalizeSourceRef(sourceRef);
|
|
506
|
+
if (!normalizedRef) {
|
|
507
|
+
throw new Error(`Invalid sourceRef: "${sourceRef}"`);
|
|
508
|
+
}
|
|
509
|
+
const normalizedHash = normalizeSourceHash(sourceHash);
|
|
510
|
+
if (!normalizedHash) {
|
|
511
|
+
throw new Error(`Invalid sourceHash: must be a 64-character hex string (normalized to lowercase)`);
|
|
512
|
+
}
|
|
513
|
+
const row = await this.db.getFirstAsync(
|
|
514
|
+
`SELECT source_hash FROM ${this.prefix}entries
|
|
515
|
+
WHERE entity_id = ? AND source_ref = ? AND deleted_at IS NULL
|
|
516
|
+
ORDER BY updated_at DESC
|
|
517
|
+
LIMIT 1`,
|
|
518
|
+
[entityId, normalizedRef]
|
|
519
|
+
);
|
|
520
|
+
if (!row) return true;
|
|
521
|
+
const normalizedStoredHash = row.source_hash ? normalizeSourceHash(row.source_hash) : null;
|
|
522
|
+
return normalizedStoredHash !== normalizedHash;
|
|
523
|
+
}
|
|
524
|
+
_pruneKey(entityId) {
|
|
525
|
+
return `${this.prefix}:${entityId}:prune`;
|
|
526
|
+
}
|
|
527
|
+
_validatePruneDuration(value, name) {
|
|
528
|
+
if (value !== null && value !== void 0 && (typeof value !== "number" || !isFinite(value) || value < 0)) {
|
|
529
|
+
throw new Error(`Invalid ${name}: must be a non-negative finite number or null`);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
async runPrune(entityId, options) {
|
|
533
|
+
const pruneKey = this._pruneKey(entityId);
|
|
534
|
+
const ingestPrefix = `${this.prefix}:${entityId}:`;
|
|
535
|
+
let isIngestRunning = false;
|
|
536
|
+
for (const k of this.activeIngestJobs) {
|
|
537
|
+
if (k.startsWith(ingestPrefix)) {
|
|
538
|
+
isIngestRunning = true;
|
|
539
|
+
break;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
let blockingOperation = null;
|
|
543
|
+
if (this.activeMaintenanceJobs.has(pruneKey)) {
|
|
544
|
+
blockingOperation = "prune";
|
|
545
|
+
} else if (this.activeMaintenanceJobs.has(this._librarianKey(entityId))) {
|
|
546
|
+
blockingOperation = "librarian";
|
|
547
|
+
} else if (this.activeMaintenanceJobs.has(this._healKey(entityId))) {
|
|
548
|
+
blockingOperation = "heal";
|
|
549
|
+
} else if (isIngestRunning) {
|
|
550
|
+
blockingOperation = "ingest";
|
|
551
|
+
}
|
|
552
|
+
if (blockingOperation !== null) {
|
|
553
|
+
throw new WikiBusyError(blockingOperation, entityId);
|
|
554
|
+
}
|
|
555
|
+
this.activeMaintenanceJobs.add(pruneKey);
|
|
556
|
+
try {
|
|
557
|
+
const retainSoftDeletedFor = options?.retainSoftDeletedFor !== void 0 ? options.retainSoftDeletedFor : this.options.config?.pruneRetainSoftDeletedFor ?? 7;
|
|
558
|
+
const retainEventsFor = options?.retainEventsFor !== void 0 ? options.retainEventsFor : this.options.config?.pruneEventsAfter ?? 30;
|
|
559
|
+
const vacuum = options?.vacuum ?? false;
|
|
560
|
+
this._validatePruneDuration(retainSoftDeletedFor, "retainSoftDeletedFor");
|
|
561
|
+
this._validatePruneDuration(retainEventsFor, "retainEventsFor");
|
|
562
|
+
const now = Date.now();
|
|
563
|
+
let deletedEntries = 0;
|
|
564
|
+
let deletedTasks = 0;
|
|
565
|
+
let deletedEvents = 0;
|
|
566
|
+
if (retainSoftDeletedFor !== null) {
|
|
567
|
+
const cutoff = now - retainSoftDeletedFor * 864e5;
|
|
568
|
+
const entryResult = await this.db.runAsync(
|
|
569
|
+
`DELETE FROM ${this.prefix}entries
|
|
570
|
+
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at < ?`,
|
|
571
|
+
[entityId, cutoff]
|
|
572
|
+
);
|
|
573
|
+
deletedEntries = entryResult.changes;
|
|
574
|
+
const taskResult = await this.db.runAsync(
|
|
575
|
+
`DELETE FROM ${this.prefix}tasks
|
|
576
|
+
WHERE entity_id = ? AND deleted_at IS NOT NULL AND deleted_at < ?`,
|
|
577
|
+
[entityId, cutoff]
|
|
578
|
+
);
|
|
579
|
+
deletedTasks = taskResult.changes;
|
|
580
|
+
}
|
|
581
|
+
if (retainEventsFor !== null) {
|
|
582
|
+
const cutoff = now - retainEventsFor * 864e5;
|
|
583
|
+
const eventResult = await this.db.runAsync(
|
|
584
|
+
`DELETE FROM ${this.prefix}events
|
|
585
|
+
WHERE entity_id = ? AND created_at < ?`,
|
|
586
|
+
[entityId, cutoff]
|
|
587
|
+
);
|
|
588
|
+
deletedEvents = eventResult.changes;
|
|
589
|
+
}
|
|
590
|
+
if (vacuum) {
|
|
591
|
+
await this.db.execAsync(`PRAGMA wal_checkpoint(TRUNCATE)`);
|
|
592
|
+
await this.db.execAsync(`VACUUM`);
|
|
593
|
+
}
|
|
594
|
+
return { entries: deletedEntries, tasks: deletedTasks, events: deletedEvents };
|
|
595
|
+
} finally {
|
|
596
|
+
this.activeMaintenanceJobs.delete(pruneKey);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
439
599
|
formatSearchQuery(query) {
|
|
440
600
|
const normalizeTokens = (value) => value.toLowerCase().replace(/[^a-z0-9\s]/g, "").split(/\s+/).filter((t) => t.length >= 3);
|
|
441
601
|
const baseTokens = normalizeTokens(query);
|
|
@@ -541,7 +701,7 @@ var WikiMemory = class {
|
|
|
541
701
|
if (memoryCheckpoint > count) memoryCheckpoint = 0;
|
|
542
702
|
if (count - memoryCheckpoint >= threshold) {
|
|
543
703
|
const jobKey = this._librarianKey(entityId);
|
|
544
|
-
if (!this.activeMaintenanceJobs.has(jobKey)) {
|
|
704
|
+
if (!this.activeMaintenanceJobs.has(jobKey) && !this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
545
705
|
this.activeMaintenanceJobs.add(jobKey);
|
|
546
706
|
this.runLibrarianThenMaybeHeal(entityId, count).catch(console.error).finally(() => this.activeMaintenanceJobs.delete(jobKey));
|
|
547
707
|
}
|
|
@@ -719,6 +879,9 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
719
879
|
if (this.activeMaintenanceJobs.has(jobKey)) {
|
|
720
880
|
throw new WikiBusyError("librarian", entityId);
|
|
721
881
|
}
|
|
882
|
+
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
883
|
+
throw new WikiBusyError("prune", entityId);
|
|
884
|
+
}
|
|
722
885
|
this.activeMaintenanceJobs.add(jobKey);
|
|
723
886
|
try {
|
|
724
887
|
await this._doRunLibrarian(entityId);
|
|
@@ -731,6 +894,9 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
731
894
|
if (this.activeMaintenanceJobs.has(jobKey)) {
|
|
732
895
|
throw new WikiBusyError("heal", entityId);
|
|
733
896
|
}
|
|
897
|
+
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
898
|
+
throw new WikiBusyError("prune", entityId);
|
|
899
|
+
}
|
|
734
900
|
this.activeMaintenanceJobs.add(jobKey);
|
|
735
901
|
try {
|
|
736
902
|
await this._doRunHeal(entityId);
|
|
@@ -981,6 +1147,9 @@ The following document anchors are provided for contradiction detection only. Do
|
|
|
981
1147
|
if (this.activeIngestJobs.has(jobKey)) {
|
|
982
1148
|
throw new WikiBusyError("ingest", entityId);
|
|
983
1149
|
}
|
|
1150
|
+
if (this.activeMaintenanceJobs.has(this._pruneKey(entityId))) {
|
|
1151
|
+
throw new WikiBusyError("prune", entityId);
|
|
1152
|
+
}
|
|
984
1153
|
this.activeIngestJobs.add(jobKey);
|
|
985
1154
|
try {
|
|
986
1155
|
const { chunks, truncated } = chunkText(params.documentChunk, maxChunkLength, chunkOverlap);
|
|
@@ -1118,6 +1287,121 @@ function formatMemoryDump(dump) {
|
|
|
1118
1287
|
};
|
|
1119
1288
|
}
|
|
1120
1289
|
|
|
1290
|
+
// src/utils/formatContext.ts
|
|
1291
|
+
function validateMaxOption(value, name) {
|
|
1292
|
+
if (!isFinite(value) || value < 0) {
|
|
1293
|
+
throw new Error(`Invalid ${name}: must be a non-negative finite number`);
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
var CONFIDENCE_WEIGHT = {
|
|
1297
|
+
certain: 1,
|
|
1298
|
+
inferred: 0.6,
|
|
1299
|
+
tentative: 0.3
|
|
1300
|
+
};
|
|
1301
|
+
function scoreFactFor(fact, weights, now) {
|
|
1302
|
+
const confW = CONFIDENCE_WEIGHT[fact.confidence] ?? 0.3;
|
|
1303
|
+
const ageDays = (now - fact.updated_at) / 864e5;
|
|
1304
|
+
const recencyDecay = Math.exp(-ageDays / 30);
|
|
1305
|
+
return confW * weights.confidence + Math.log(1 + fact.access_count) * weights.accessCount + recencyDecay * weights.recency;
|
|
1306
|
+
}
|
|
1307
|
+
function renderFactMarkdown(fact, includeConfidence, includeTags) {
|
|
1308
|
+
const confPart = includeConfidence ? ` (${fact.confidence})` : "";
|
|
1309
|
+
const tagPart = includeTags && fact.tags.length > 0 ? ` [${fact.tags.join(", ")}]` : "";
|
|
1310
|
+
return `- **${fact.title}**${confPart}${tagPart}
|
|
1311
|
+
${fact.body.replace(/\n/g, "\n ")}`;
|
|
1312
|
+
}
|
|
1313
|
+
function renderFactPlain(fact, includeConfidence, includeTags) {
|
|
1314
|
+
const confPart = includeConfidence ? ` (${fact.confidence})` : "";
|
|
1315
|
+
const tagPart = includeTags && fact.tags.length > 0 ? ` [${fact.tags.join(", ")}]` : "";
|
|
1316
|
+
return `${fact.title}${confPart}${tagPart}: ${fact.body}`;
|
|
1317
|
+
}
|
|
1318
|
+
function renderTaskMarkdown(task) {
|
|
1319
|
+
return `- [P${task.priority}] ${task.description.replace(/\n/g, "\n ")} (${task.status})`;
|
|
1320
|
+
}
|
|
1321
|
+
function renderTaskPlain(task) {
|
|
1322
|
+
return `[P${task.priority}] ${task.description} (${task.status})`;
|
|
1323
|
+
}
|
|
1324
|
+
function renderEventMarkdown(event) {
|
|
1325
|
+
const ts = new Date(event.created_at).toISOString();
|
|
1326
|
+
return `- [${event.event_type} @ ${ts}] ${event.summary.replace(/\n/g, "\n ")}`;
|
|
1327
|
+
}
|
|
1328
|
+
function renderEventPlain(event) {
|
|
1329
|
+
const ts = new Date(event.created_at).toISOString();
|
|
1330
|
+
return `[${event.event_type} @ ${ts}] ${event.summary}`;
|
|
1331
|
+
}
|
|
1332
|
+
function formatContext(bundle, options) {
|
|
1333
|
+
const opts = {
|
|
1334
|
+
format: options?.format ?? "markdown",
|
|
1335
|
+
maxFacts: options?.maxFacts ?? 10,
|
|
1336
|
+
maxTasks: options?.maxTasks ?? 10,
|
|
1337
|
+
maxEvents: options?.maxEvents ?? 10,
|
|
1338
|
+
includeConfidence: options?.includeConfidence ?? true,
|
|
1339
|
+
includeTags: options?.includeTags ?? true,
|
|
1340
|
+
factWeights: {
|
|
1341
|
+
confidence: options?.factWeights?.confidence ?? 1,
|
|
1342
|
+
accessCount: options?.factWeights?.accessCount ?? 0.3,
|
|
1343
|
+
recency: options?.factWeights?.recency ?? 0.5
|
|
1344
|
+
}
|
|
1345
|
+
};
|
|
1346
|
+
validateMaxOption(opts.maxFacts, "maxFacts");
|
|
1347
|
+
validateMaxOption(opts.maxTasks, "maxTasks");
|
|
1348
|
+
validateMaxOption(opts.maxEvents, "maxEvents");
|
|
1349
|
+
const weights = opts.factWeights;
|
|
1350
|
+
const now = Date.now();
|
|
1351
|
+
const sortedFacts = [...bundle.facts].sort((a, b) => scoreFactFor(b, weights, now) - scoreFactFor(a, weights, now)).slice(0, opts.maxFacts);
|
|
1352
|
+
const sortedTasks = [...bundle.tasks].sort((a, b) => b.priority - a.priority || a.created_at - b.created_at).slice(0, opts.maxTasks);
|
|
1353
|
+
const sortedEvents = [...bundle.events].sort((a, b) => b.created_at - a.created_at).slice(0, opts.maxEvents);
|
|
1354
|
+
if (sortedFacts.length === 0 && sortedTasks.length === 0 && sortedEvents.length === 0) {
|
|
1355
|
+
return "";
|
|
1356
|
+
}
|
|
1357
|
+
const isMarkdown = opts.format === "markdown";
|
|
1358
|
+
const lines = [];
|
|
1359
|
+
if (isMarkdown) {
|
|
1360
|
+
lines.push("## Memory");
|
|
1361
|
+
if (sortedFacts.length > 0) {
|
|
1362
|
+
lines.push("");
|
|
1363
|
+
lines.push("### Known Facts");
|
|
1364
|
+
for (const fact of sortedFacts) {
|
|
1365
|
+
lines.push(renderFactMarkdown(fact, opts.includeConfidence, opts.includeTags));
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
if (sortedTasks.length > 0) {
|
|
1369
|
+
lines.push("");
|
|
1370
|
+
lines.push("### Open Tasks");
|
|
1371
|
+
for (const task of sortedTasks) {
|
|
1372
|
+
lines.push(renderTaskMarkdown(task));
|
|
1373
|
+
}
|
|
1374
|
+
}
|
|
1375
|
+
if (sortedEvents.length > 0) {
|
|
1376
|
+
lines.push("");
|
|
1377
|
+
lines.push("### Recent Events");
|
|
1378
|
+
for (const event of sortedEvents) {
|
|
1379
|
+
lines.push(renderEventMarkdown(event));
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
} else {
|
|
1383
|
+
if (sortedFacts.length > 0) {
|
|
1384
|
+
lines.push("KNOWN FACTS:");
|
|
1385
|
+
for (const fact of sortedFacts) {
|
|
1386
|
+
lines.push(renderFactPlain(fact, opts.includeConfidence, opts.includeTags));
|
|
1387
|
+
}
|
|
1388
|
+
}
|
|
1389
|
+
if (sortedTasks.length > 0) {
|
|
1390
|
+
lines.push("OPEN TASKS:");
|
|
1391
|
+
for (const task of sortedTasks) {
|
|
1392
|
+
lines.push(renderTaskPlain(task));
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
if (sortedEvents.length > 0) {
|
|
1396
|
+
lines.push("RECENT EVENTS:");
|
|
1397
|
+
for (const event of sortedEvents) {
|
|
1398
|
+
lines.push(renderEventPlain(event));
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
return lines.join("\n");
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1121
1405
|
// src/index.ts
|
|
1122
1406
|
function createWiki(db, options) {
|
|
1123
1407
|
return new WikiMemory(db, options);
|
|
@@ -1127,5 +1411,6 @@ function createWiki(db, options) {
|
|
|
1127
1411
|
WikiBusyError,
|
|
1128
1412
|
WikiMemory,
|
|
1129
1413
|
createWiki,
|
|
1414
|
+
formatContext,
|
|
1130
1415
|
formatMemoryDump
|
|
1131
1416
|
});
|