@oh-my-pi/pi-mnemopi 18.8.6 → 18.8.7
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/CHANGELOG.md +6 -0
- package/package.json +5 -5
- package/src/core/episodic-graph.ts +83 -74
- package/src/db.ts +6 -4
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
+
## [18.8.7] - 2026-10-09
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Fixed proactive linking freezing the host for seconds per stored memory on large banks; a memory's graph links are now written in one commit instead of one per link ([#14998](https://github.com/can1357/oh-my-pi/issues/14998)).
|
|
10
|
+
|
|
5
11
|
## [18.8.5] - 2026-10-08
|
|
6
12
|
|
|
7
13
|
### Fixed
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"type": "module",
|
|
3
3
|
"name": "@oh-my-pi/pi-mnemopi",
|
|
4
|
-
"version": "18.8.
|
|
4
|
+
"version": "18.8.7",
|
|
5
5
|
"description": "Local SQLite memory engine for omp agents",
|
|
6
6
|
"homepage": "https://omp.sh",
|
|
7
7
|
"author": {
|
|
@@ -42,10 +42,10 @@
|
|
|
42
42
|
"fmt": "oxfmt --no-error-on-unmatched-pattern 'src/**/*.{ts,tsx}' '{test,bench,examples,scripts}/**/*.ts' '*.ts'"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@oh-my-pi/pi-ai": "18.8.
|
|
46
|
-
"@oh-my-pi/pi-catalog": "18.8.
|
|
47
|
-
"@oh-my-pi/pi-natives": "18.8.
|
|
48
|
-
"@oh-my-pi/pi-utils": "18.8.
|
|
45
|
+
"@oh-my-pi/pi-ai": "18.8.7",
|
|
46
|
+
"@oh-my-pi/pi-catalog": "18.8.7",
|
|
47
|
+
"@oh-my-pi/pi-natives": "18.8.7",
|
|
48
|
+
"@oh-my-pi/pi-utils": "18.8.7"
|
|
49
49
|
},
|
|
50
50
|
"peerDependencies": {
|
|
51
51
|
"fastembed": "3.0.0",
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
|
-
import { closeQuietly, type DatabasePath, openDatabase } from "../db";
|
|
2
|
+
import { closeQuietly, type DatabasePath, openDatabase, transaction } from "../db";
|
|
3
3
|
|
|
4
4
|
export interface Gist {
|
|
5
5
|
readonly id: string;
|
|
@@ -506,83 +506,92 @@ export class EpisodicGraph {
|
|
|
506
506
|
const extractEntities = options.extractEntities ?? true;
|
|
507
507
|
const gist = this.extractGist(content, memoryId);
|
|
508
508
|
const facts = extractEntities ? this.extractFacts(content, memoryId) : [];
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
this.
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
509
|
+
// One transaction for every gist/fact/edge write: autocommitted, each
|
|
510
|
+
// `addEdge` paid its own WAL commit (an fsync), so linking a memory
|
|
511
|
+
// against a large bank blocked the caller's event loop for seconds (#14998).
|
|
512
|
+
return transaction(this.db, () => {
|
|
513
|
+
const edges: GraphEdge[] = [];
|
|
514
|
+
const timestamp = nowIso();
|
|
515
|
+
|
|
516
|
+
const previousMemoryIds = linkExisting ? this.knownMemoryIds(memoryId) : [];
|
|
517
|
+
this.storeGist(gist, memoryId);
|
|
518
|
+
const gistEdge = { source: memoryId, target: gist.id, edgeType: "ctx", weight: 1, timestamp };
|
|
519
|
+
this.addEdge(gistEdge);
|
|
520
|
+
edges.push(gistEdge);
|
|
521
|
+
|
|
522
|
+
for (const fact of facts) {
|
|
523
|
+
this.storeFact(fact, memoryId, sessionId);
|
|
524
|
+
const edge = {
|
|
525
|
+
source: gist.id,
|
|
526
|
+
target: fact.id,
|
|
527
|
+
edgeType: "rel",
|
|
528
|
+
weight: fact.confidence,
|
|
529
|
+
timestamp,
|
|
530
|
+
};
|
|
531
|
+
this.addEdge(edge);
|
|
532
|
+
edges.push(edge);
|
|
533
|
+
}
|
|
530
534
|
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
535
|
+
if (linkExisting) {
|
|
536
|
+
const sourceTokens = contentTokenSet(content);
|
|
537
|
+
for (const otherId of previousMemoryIds) {
|
|
538
|
+
const otherContent = this.memoryContent(otherId, timestamp);
|
|
539
|
+
const lexicalScore = Math.round(jaccard(sourceTokens, contentTokenSet(otherContent)) * 1000) / 1000;
|
|
540
|
+
let wroteCtxEdge = false;
|
|
541
|
+
if (lexicalScore >= minLinkScore) {
|
|
542
|
+
const edge = {
|
|
543
|
+
source: memoryId,
|
|
544
|
+
target: otherId,
|
|
545
|
+
edgeType: "related_to",
|
|
546
|
+
weight: lexicalScore,
|
|
547
|
+
timestamp,
|
|
548
|
+
};
|
|
549
|
+
this.addEdge(edge);
|
|
550
|
+
edges.push(edge);
|
|
551
|
+
const ctxEdge = {
|
|
552
|
+
source: memoryId,
|
|
553
|
+
target: otherId,
|
|
554
|
+
edgeType: "ctx",
|
|
555
|
+
weight: lexicalScore,
|
|
556
|
+
timestamp,
|
|
557
|
+
};
|
|
558
|
+
this.addEdge(ctxEdge);
|
|
559
|
+
edges.push(ctxEdge);
|
|
560
|
+
wroteCtxEdge = true;
|
|
561
|
+
}
|
|
562
|
+
const entityScore = this.entityOverlapScore(memoryId, otherId);
|
|
563
|
+
if (entityScore > 0) {
|
|
564
|
+
const edge = {
|
|
565
|
+
source: memoryId,
|
|
566
|
+
target: otherId,
|
|
567
|
+
edgeType: "references",
|
|
568
|
+
weight: entityScore,
|
|
569
|
+
timestamp,
|
|
570
|
+
};
|
|
571
|
+
this.addEdge(edge);
|
|
572
|
+
edges.push(edge);
|
|
573
|
+
}
|
|
574
|
+
const contextualScore = Math.max(
|
|
575
|
+
lexicalScore,
|
|
576
|
+
entityScore,
|
|
577
|
+
this.temporalContextScore(memoryId, otherId),
|
|
578
|
+
);
|
|
579
|
+
if (!wroteCtxEdge && contextualScore >= minLinkScore) {
|
|
580
|
+
const ctxEdge = {
|
|
581
|
+
source: memoryId,
|
|
582
|
+
target: otherId,
|
|
583
|
+
edgeType: "ctx",
|
|
584
|
+
weight: contextualScore,
|
|
585
|
+
timestamp,
|
|
586
|
+
};
|
|
587
|
+
this.addEdge(ctxEdge);
|
|
588
|
+
edges.push(ctxEdge);
|
|
589
|
+
}
|
|
581
590
|
}
|
|
582
591
|
}
|
|
583
|
-
}
|
|
584
592
|
|
|
585
|
-
|
|
593
|
+
return { memoryId, gist, facts, edges };
|
|
594
|
+
});
|
|
586
595
|
}
|
|
587
596
|
getStats(): GraphStats {
|
|
588
597
|
const gists = this.count("gists");
|
package/src/db.ts
CHANGED
|
@@ -119,10 +119,12 @@ export function transaction<T>(db: Database, fn: () => T): T {
|
|
|
119
119
|
state.depth--;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
-
|
|
122
|
+
// Caller-owned Bun/SQLite transactions already batch these writes; do not
|
|
123
|
+
// commit or roll them back from this helper.
|
|
124
|
+
if (db.inTransaction) return fn();
|
|
125
|
+
db.exec("BEGIN DEFERRED");
|
|
123
126
|
state = { depth: 1 };
|
|
124
127
|
txDb[TX_STATE] = state;
|
|
125
|
-
db.exec("BEGIN DEFERRED");
|
|
126
128
|
try {
|
|
127
129
|
const result = fn();
|
|
128
130
|
state.depth = 0;
|
|
@@ -154,10 +156,10 @@ export async function transactionAsync<T>(db: Database, fn: () => Promise<T>): P
|
|
|
154
156
|
state.depth--;
|
|
155
157
|
}
|
|
156
158
|
}
|
|
157
|
-
|
|
159
|
+
if (db.inTransaction) return await fn();
|
|
160
|
+
db.exec("BEGIN DEFERRED");
|
|
158
161
|
state = { depth: 1 };
|
|
159
162
|
txDb[TX_STATE] = state;
|
|
160
|
-
db.exec("BEGIN DEFERRED");
|
|
161
163
|
try {
|
|
162
164
|
const result = await fn();
|
|
163
165
|
state.depth = 0;
|