@drqedwards/pmll 2.0.4
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/LICENSE +21 -0
- package/README.md +26 -0
- package/agent_instructions.md +123 -0
- package/benchmarks/benchmark_retrieval.md +94 -0
- package/benchmarks/contextplus-standalone-speed.md +185 -0
- package/benchmarks/run_retrieval_stub.py +343 -0
- package/benchmarks/speed-test-results.md +163 -0
- package/benchmarks/three-way-speed-comparison.md +238 -0
- package/dist/embeddings.d.ts +32 -0
- package/dist/embeddings.d.ts.map +1 -0
- package/dist/embeddings.js +140 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/graphql.d.ts +81 -0
- package/dist/graphql.d.ts.map +1 -0
- package/dist/graphql.js +389 -0
- package/dist/graphql.js.map +1 -0
- package/dist/index.d.ts +55 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +645 -0
- package/dist/index.js.map +1 -0
- package/dist/kv-store.d.ts +32 -0
- package/dist/kv-store.d.ts.map +1 -0
- package/dist/kv-store.js +103 -0
- package/dist/kv-store.js.map +1 -0
- package/dist/memory-graph.d.ts +122 -0
- package/dist/memory-graph.d.ts.map +1 -0
- package/dist/memory-graph.js +345 -0
- package/dist/memory-graph.js.map +1 -0
- package/dist/peek.d.ts +67 -0
- package/dist/peek.d.ts.map +1 -0
- package/dist/peek.js +61 -0
- package/dist/peek.js.map +1 -0
- package/dist/q-promise-bridge.d.ts +58 -0
- package/dist/q-promise-bridge.d.ts.map +1 -0
- package/dist/q-promise-bridge.js +88 -0
- package/dist/q-promise-bridge.js.map +1 -0
- package/dist/solution-engine.d.ts +54 -0
- package/dist/solution-engine.d.ts.map +1 -0
- package/dist/solution-engine.js +73 -0
- package/dist/solution-engine.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kv-store.ts — In-process KV slot manager mirroring PMLL memory_silo_t semantics.
|
|
3
|
+
*
|
|
4
|
+
* Capacity: siloSize is enforced on set(). When at capacity and the key is new,
|
|
5
|
+
* the least-recently-used (LRU) slot is evicted. Updates never grow the silo.
|
|
6
|
+
*
|
|
7
|
+
* Concurrency: process-local; MCP assumes single-threaded / externally serialized access.
|
|
8
|
+
*/
|
|
9
|
+
export type PeekResult = [boolean, string | null, number | null];
|
|
10
|
+
export declare class PMMemoryStore {
|
|
11
|
+
private _slots;
|
|
12
|
+
private _nextIndex;
|
|
13
|
+
private _accessSeq;
|
|
14
|
+
siloSize: number;
|
|
15
|
+
constructor(siloSize?: number);
|
|
16
|
+
private _touch;
|
|
17
|
+
peek(key: string): PeekResult;
|
|
18
|
+
/**
|
|
19
|
+
* Store key/value. New keys at capacity evict the LRU entry.
|
|
20
|
+
*/
|
|
21
|
+
set(key: string, value: string): number;
|
|
22
|
+
private _evictLru;
|
|
23
|
+
flush(): number;
|
|
24
|
+
get size(): number;
|
|
25
|
+
has(key: string): boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare function getStore(sessionId: string, siloSize?: number): PMMemoryStore;
|
|
28
|
+
export declare function dropStore(sessionId: string): number;
|
|
29
|
+
/** Clear existing silo and return a fresh store (clear_on_init). */
|
|
30
|
+
export declare function resetStore(sessionId: string, siloSize?: number): PMMemoryStore;
|
|
31
|
+
export declare const _sessionStoresMap: Map<string, PMMemoryStore>;
|
|
32
|
+
//# sourceMappingURL=kv-store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv-store.d.ts","sourceRoot":"","sources":["../src/kv-store.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAWH,MAAM,MAAM,UAAU,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;AAEjE,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAkC;IAChD,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,UAAU,CAAK;IACvB,QAAQ,EAAE,MAAM,CAAC;gBAEL,QAAQ,GAAE,MAAY;IAIlC,OAAO,CAAC,MAAM;IAKd,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU;IAS7B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM;IA0BvC,OAAO,CAAC,SAAS;IAYjB,KAAK,IAAI,MAAM;IAQf,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;CAG1B;AAID,wBAAgB,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAY,GAAG,aAAa,CAOjF;AAED,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAInD;AAED,oEAAoE;AACpE,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,GAAE,MAAY,GAAG,aAAa,CAKnF;AAED,eAAO,MAAM,iBAAiB,4BAAiB,CAAC"}
|
package/dist/kv-store.js
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* kv-store.ts — In-process KV slot manager mirroring PMLL memory_silo_t semantics.
|
|
3
|
+
*
|
|
4
|
+
* Capacity: siloSize is enforced on set(). When at capacity and the key is new,
|
|
5
|
+
* the least-recently-used (LRU) slot is evicted. Updates never grow the silo.
|
|
6
|
+
*
|
|
7
|
+
* Concurrency: process-local; MCP assumes single-threaded / externally serialized access.
|
|
8
|
+
*/
|
|
9
|
+
export class PMMemoryStore {
|
|
10
|
+
_slots = new Map();
|
|
11
|
+
_nextIndex = 0;
|
|
12
|
+
_accessSeq = 0;
|
|
13
|
+
siloSize;
|
|
14
|
+
constructor(siloSize = 256) {
|
|
15
|
+
this.siloSize = Math.max(1, siloSize | 0);
|
|
16
|
+
}
|
|
17
|
+
_touch(slot) {
|
|
18
|
+
this._accessSeq += 1;
|
|
19
|
+
slot.lastAccessed = this._accessSeq;
|
|
20
|
+
}
|
|
21
|
+
peek(key) {
|
|
22
|
+
const slot = this._slots.get(key);
|
|
23
|
+
if (slot !== undefined && slot.resolved) {
|
|
24
|
+
this._touch(slot);
|
|
25
|
+
return [true, slot.value, slot.index];
|
|
26
|
+
}
|
|
27
|
+
return [false, null, null];
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Store key/value. New keys at capacity evict the LRU entry.
|
|
31
|
+
*/
|
|
32
|
+
set(key, value) {
|
|
33
|
+
const existing = this._slots.get(key);
|
|
34
|
+
if (existing !== undefined) {
|
|
35
|
+
existing.value = value;
|
|
36
|
+
existing.resolved = true;
|
|
37
|
+
this._touch(existing);
|
|
38
|
+
return existing.index;
|
|
39
|
+
}
|
|
40
|
+
if (this._slots.size >= this.siloSize) {
|
|
41
|
+
this._evictLru();
|
|
42
|
+
}
|
|
43
|
+
const index = this._nextIndex++;
|
|
44
|
+
const slot = {
|
|
45
|
+
index,
|
|
46
|
+
key,
|
|
47
|
+
value,
|
|
48
|
+
resolved: true,
|
|
49
|
+
lastAccessed: 0,
|
|
50
|
+
};
|
|
51
|
+
this._touch(slot);
|
|
52
|
+
this._slots.set(key, slot);
|
|
53
|
+
return index;
|
|
54
|
+
}
|
|
55
|
+
_evictLru() {
|
|
56
|
+
let victim = null;
|
|
57
|
+
let oldest = Infinity;
|
|
58
|
+
for (const [k, slot] of this._slots) {
|
|
59
|
+
if (slot.lastAccessed < oldest) {
|
|
60
|
+
oldest = slot.lastAccessed;
|
|
61
|
+
victim = k;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (victim !== null)
|
|
65
|
+
this._slots.delete(victim);
|
|
66
|
+
}
|
|
67
|
+
flush() {
|
|
68
|
+
const count = this._slots.size;
|
|
69
|
+
this._slots.clear();
|
|
70
|
+
this._nextIndex = 0;
|
|
71
|
+
this._accessSeq = 0;
|
|
72
|
+
return count;
|
|
73
|
+
}
|
|
74
|
+
get size() {
|
|
75
|
+
return this._slots.size;
|
|
76
|
+
}
|
|
77
|
+
has(key) {
|
|
78
|
+
return this._slots.has(key);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const _sessionStores = new Map();
|
|
82
|
+
export function getStore(sessionId, siloSize = 256) {
|
|
83
|
+
let store = _sessionStores.get(sessionId);
|
|
84
|
+
if (store === undefined) {
|
|
85
|
+
store = new PMMemoryStore(siloSize);
|
|
86
|
+
_sessionStores.set(sessionId, store);
|
|
87
|
+
}
|
|
88
|
+
return store;
|
|
89
|
+
}
|
|
90
|
+
export function dropStore(sessionId) {
|
|
91
|
+
const store = _sessionStores.get(sessionId);
|
|
92
|
+
_sessionStores.delete(sessionId);
|
|
93
|
+
return store !== undefined ? store.size : 0;
|
|
94
|
+
}
|
|
95
|
+
/** Clear existing silo and return a fresh store (clear_on_init). */
|
|
96
|
+
export function resetStore(sessionId, siloSize = 256) {
|
|
97
|
+
_sessionStores.delete(sessionId);
|
|
98
|
+
const store = new PMMemoryStore(siloSize);
|
|
99
|
+
_sessionStores.set(sessionId, store);
|
|
100
|
+
return store;
|
|
101
|
+
}
|
|
102
|
+
export const _sessionStoresMap = _sessionStores;
|
|
103
|
+
//# sourceMappingURL=kv-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"kv-store.js","sourceRoot":"","sources":["../src/kv-store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memory-graph.ts — In-memory property graph for long-term context memory.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from Context+ (github.com/drQedwards/contextplus) memory-graph.ts.
|
|
5
|
+
* Provides a persistent memory graph with typed nodes, weighted edges, decay
|
|
6
|
+
* scoring, and graph traversal for the PMLL MCP solution engine.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Nodes: concept, file, symbol, note — each with TF-IDF embeddings
|
|
10
|
+
* - Edges: typed relations with temporal decay (e^(-λt))
|
|
11
|
+
* - Search: cosine similarity + graph neighbor traversal
|
|
12
|
+
* - Persistence: in-process Map + JSON export/import (Python package uses SQLite;
|
|
13
|
+
* TS durable backend may follow). Session IDs namespace the graph.
|
|
14
|
+
*
|
|
15
|
+
* Process-local / single-threaded MCP assumption: no cross-process locking.
|
|
16
|
+
*
|
|
17
|
+
* The graph serves as the long-term memory layer complementing the existing
|
|
18
|
+
* short-term KV store (init/peek/set/resolve/flush tools).
|
|
19
|
+
*/
|
|
20
|
+
export type NodeType = "concept" | "file" | "symbol" | "note";
|
|
21
|
+
export type RelationType = "relates_to" | "depends_on" | "implements" | "references" | "similar_to" | "contains";
|
|
22
|
+
export interface MemoryNode {
|
|
23
|
+
id: string;
|
|
24
|
+
type: NodeType;
|
|
25
|
+
label: string;
|
|
26
|
+
content: string;
|
|
27
|
+
embedding: number[];
|
|
28
|
+
createdAt: number;
|
|
29
|
+
lastAccessed: number;
|
|
30
|
+
accessCount: number;
|
|
31
|
+
metadata: Record<string, string>;
|
|
32
|
+
}
|
|
33
|
+
export interface MemoryEdge {
|
|
34
|
+
id: string;
|
|
35
|
+
source: string;
|
|
36
|
+
target: string;
|
|
37
|
+
relation: RelationType;
|
|
38
|
+
weight: number;
|
|
39
|
+
createdAt: number;
|
|
40
|
+
metadata: Record<string, string>;
|
|
41
|
+
}
|
|
42
|
+
export interface TraversalResult {
|
|
43
|
+
node: MemoryNode;
|
|
44
|
+
depth: number;
|
|
45
|
+
pathRelations: string[];
|
|
46
|
+
relevanceScore: number;
|
|
47
|
+
}
|
|
48
|
+
export interface GraphSearchResult {
|
|
49
|
+
direct: TraversalResult[];
|
|
50
|
+
neighbors: TraversalResult[];
|
|
51
|
+
totalNodes: number;
|
|
52
|
+
totalEdges: number;
|
|
53
|
+
}
|
|
54
|
+
interface GraphStore {
|
|
55
|
+
nodes: Record<string, MemoryNode>;
|
|
56
|
+
edges: Record<string, MemoryEdge>;
|
|
57
|
+
}
|
|
58
|
+
/** Exposed for testing: direct access to graph store registry. */
|
|
59
|
+
export declare const _graphStoresMap: Map<string, GraphStore>;
|
|
60
|
+
/**
|
|
61
|
+
* Create or update a memory node in the session graph.
|
|
62
|
+
* If a node with the same label and type exists, updates it in place.
|
|
63
|
+
*/
|
|
64
|
+
export declare function upsertNode(sessionId: string, type: NodeType, label: string, content: string, metadata?: Record<string, string>): MemoryNode;
|
|
65
|
+
/**
|
|
66
|
+
* Create a typed edge between two nodes.
|
|
67
|
+
* Deduplicates: if the same source→target→relation already exists, updates weight.
|
|
68
|
+
*/
|
|
69
|
+
export declare function createRelation(sessionId: string, sourceId: string, targetId: string, relation: RelationType, weight?: number, metadata?: Record<string, string>): MemoryEdge | null;
|
|
70
|
+
/**
|
|
71
|
+
* Semantic search with graph traversal — finds direct matches then walks
|
|
72
|
+
* 1st/2nd-degree neighbors.
|
|
73
|
+
*/
|
|
74
|
+
export declare function searchGraph(sessionId: string, query: string, maxDepth?: number, topK?: number, edgeFilter?: RelationType[]): GraphSearchResult;
|
|
75
|
+
/**
|
|
76
|
+
* Remove decayed edges (e^(-λt) below threshold) and orphan nodes
|
|
77
|
+
* with low access counts.
|
|
78
|
+
*/
|
|
79
|
+
export declare function pruneStaleLinks(sessionId: string, threshold?: number): {
|
|
80
|
+
removed: number;
|
|
81
|
+
remaining: number;
|
|
82
|
+
};
|
|
83
|
+
/**
|
|
84
|
+
* Bulk-add nodes with auto-similarity linking (cosine ≥ 0.72 creates edges).
|
|
85
|
+
*/
|
|
86
|
+
export declare function addInterlinkedContext(sessionId: string, items: Array<{
|
|
87
|
+
type: NodeType;
|
|
88
|
+
label: string;
|
|
89
|
+
content: string;
|
|
90
|
+
metadata?: Record<string, string>;
|
|
91
|
+
}>, autoLink?: boolean): {
|
|
92
|
+
nodes: MemoryNode[];
|
|
93
|
+
edges: MemoryEdge[];
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Start from a node and walk outward — returns all reachable neighbors
|
|
97
|
+
* scored by decay and depth.
|
|
98
|
+
*/
|
|
99
|
+
export declare function retrieveWithTraversal(sessionId: string, startNodeId: string, maxDepth?: number, edgeFilter?: RelationType[]): TraversalResult[];
|
|
100
|
+
/**
|
|
101
|
+
* Get summary statistics for the session's memory graph.
|
|
102
|
+
*/
|
|
103
|
+
export declare function getGraphStats(sessionId: string): {
|
|
104
|
+
nodes: number;
|
|
105
|
+
edges: number;
|
|
106
|
+
types: Record<string, number>;
|
|
107
|
+
relations: Record<string, number>;
|
|
108
|
+
};
|
|
109
|
+
/**
|
|
110
|
+
* Export the full graph for a session as a JSON-serializable object.
|
|
111
|
+
*/
|
|
112
|
+
export declare function exportGraph(sessionId: string): GraphStore;
|
|
113
|
+
/**
|
|
114
|
+
* Import a graph from a JSON object into a session.
|
|
115
|
+
*/
|
|
116
|
+
export declare function importGraph(sessionId: string, data: GraphStore): void;
|
|
117
|
+
/**
|
|
118
|
+
* Clear the graph for a session.
|
|
119
|
+
*/
|
|
120
|
+
export declare function clearGraph(sessionId: string): number;
|
|
121
|
+
export {};
|
|
122
|
+
//# sourceMappingURL=memory-graph.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-graph.d.ts","sourceRoot":"","sources":["../src/memory-graph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAQH,MAAM,MAAM,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAE9D,MAAM,MAAM,YAAY,GACpB,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,YAAY,GACZ,UAAU,CAAC;AAEf,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,YAAY,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,SAAS,EAAE,eAAe,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,UAAU;IAClB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;CACnC;AAgBD,kEAAkE;AAClE,eAAO,MAAM,eAAe,yBAAe,CAAC;AAkC5C;;;GAGG;AACH,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,QAAQ,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,UAAU,CA4BZ;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,YAAY,EACtB,MAAM,CAAC,EAAE,MAAM,EACf,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,UAAU,GAAG,IAAI,CA4BnB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,GAAE,MAAU,EACpB,IAAI,GAAE,MAAU,EAChB,UAAU,CAAC,EAAE,YAAY,EAAE,GAC1B,iBAAiB,CAwCnB;AAiDD;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,GACjB;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,CAyBxC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,KAAK,CAAC;IACX,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,CAAC,EACF,QAAQ,GAAE,OAAc,GACvB;IAAE,KAAK,EAAE,UAAU,EAAE,CAAC;IAAC,KAAK,EAAE,UAAU,EAAE,CAAA;CAAE,CAoD9C;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,QAAQ,GAAE,MAAU,EACpB,UAAU,CAAC,EAAE,YAAY,EAAE,GAC1B,eAAe,EAAE,CAwBnB;AAgDD;;GAEG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG;IAChD,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,CAkBA;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAEzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,IAAI,CAErE;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAOpD"}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* memory-graph.ts — In-memory property graph for long-term context memory.
|
|
3
|
+
*
|
|
4
|
+
* Adapted from Context+ (github.com/drQedwards/contextplus) memory-graph.ts.
|
|
5
|
+
* Provides a persistent memory graph with typed nodes, weighted edges, decay
|
|
6
|
+
* scoring, and graph traversal for the PMLL MCP solution engine.
|
|
7
|
+
*
|
|
8
|
+
* Architecture:
|
|
9
|
+
* - Nodes: concept, file, symbol, note — each with TF-IDF embeddings
|
|
10
|
+
* - Edges: typed relations with temporal decay (e^(-λt))
|
|
11
|
+
* - Search: cosine similarity + graph neighbor traversal
|
|
12
|
+
* - Persistence: in-process Map + JSON export/import (Python package uses SQLite;
|
|
13
|
+
* TS durable backend may follow). Session IDs namespace the graph.
|
|
14
|
+
*
|
|
15
|
+
* Process-local / single-threaded MCP assumption: no cross-process locking.
|
|
16
|
+
*
|
|
17
|
+
* The graph serves as the long-term memory layer complementing the existing
|
|
18
|
+
* short-term KV store (init/peek/set/resolve/flush tools).
|
|
19
|
+
*/
|
|
20
|
+
import { embed, cosineSimilarity } from "./embeddings.js";
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
// Constants
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
const DECAY_LAMBDA = 0.05;
|
|
25
|
+
const SIMILARITY_THRESHOLD = 0.72;
|
|
26
|
+
const STALE_THRESHOLD = 0.15;
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Graph registry (session-scoped)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
const _graphStores = new Map();
|
|
31
|
+
/** Exposed for testing: direct access to graph store registry. */
|
|
32
|
+
export const _graphStoresMap = _graphStores;
|
|
33
|
+
function generateId(prefix) {
|
|
34
|
+
return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
35
|
+
}
|
|
36
|
+
function getGraph(sessionId) {
|
|
37
|
+
let store = _graphStores.get(sessionId);
|
|
38
|
+
if (!store) {
|
|
39
|
+
store = { nodes: {}, edges: {} };
|
|
40
|
+
_graphStores.set(sessionId, store);
|
|
41
|
+
}
|
|
42
|
+
return store;
|
|
43
|
+
}
|
|
44
|
+
function decayWeight(edge) {
|
|
45
|
+
const daysSinceCreation = (Date.now() - edge.createdAt) / 86_400_000;
|
|
46
|
+
return edge.weight * Math.exp(-DECAY_LAMBDA * daysSinceCreation);
|
|
47
|
+
}
|
|
48
|
+
function getEdgesForNode(graph, nodeId) {
|
|
49
|
+
return Object.values(graph.edges).filter((e) => e.source === nodeId || e.target === nodeId);
|
|
50
|
+
}
|
|
51
|
+
function getNeighborId(edge, fromId) {
|
|
52
|
+
return edge.source === fromId ? edge.target : edge.source;
|
|
53
|
+
}
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
// Core graph operations
|
|
56
|
+
// ---------------------------------------------------------------------------
|
|
57
|
+
/**
|
|
58
|
+
* Create or update a memory node in the session graph.
|
|
59
|
+
* If a node with the same label and type exists, updates it in place.
|
|
60
|
+
*/
|
|
61
|
+
export function upsertNode(sessionId, type, label, content, metadata) {
|
|
62
|
+
const graph = getGraph(sessionId);
|
|
63
|
+
const existing = Object.values(graph.nodes).find((n) => n.label === label && n.type === type);
|
|
64
|
+
if (existing) {
|
|
65
|
+
existing.content = content;
|
|
66
|
+
existing.lastAccessed = Date.now();
|
|
67
|
+
existing.accessCount++;
|
|
68
|
+
if (metadata)
|
|
69
|
+
Object.assign(existing.metadata, metadata);
|
|
70
|
+
existing.embedding = embed(`${label} ${content}`);
|
|
71
|
+
return existing;
|
|
72
|
+
}
|
|
73
|
+
const node = {
|
|
74
|
+
id: generateId("mn"),
|
|
75
|
+
type,
|
|
76
|
+
label,
|
|
77
|
+
content,
|
|
78
|
+
embedding: embed(`${label} ${content}`),
|
|
79
|
+
createdAt: Date.now(),
|
|
80
|
+
lastAccessed: Date.now(),
|
|
81
|
+
accessCount: 1,
|
|
82
|
+
metadata: metadata ?? {},
|
|
83
|
+
};
|
|
84
|
+
graph.nodes[node.id] = node;
|
|
85
|
+
return node;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Create a typed edge between two nodes.
|
|
89
|
+
* Deduplicates: if the same source→target→relation already exists, updates weight.
|
|
90
|
+
*/
|
|
91
|
+
export function createRelation(sessionId, sourceId, targetId, relation, weight, metadata) {
|
|
92
|
+
const graph = getGraph(sessionId);
|
|
93
|
+
if (!graph.nodes[sourceId] || !graph.nodes[targetId])
|
|
94
|
+
return null;
|
|
95
|
+
const duplicate = Object.values(graph.edges).find((e) => e.source === sourceId &&
|
|
96
|
+
e.target === targetId &&
|
|
97
|
+
e.relation === relation);
|
|
98
|
+
if (duplicate) {
|
|
99
|
+
duplicate.weight = weight ?? duplicate.weight;
|
|
100
|
+
if (metadata)
|
|
101
|
+
Object.assign(duplicate.metadata, metadata);
|
|
102
|
+
return duplicate;
|
|
103
|
+
}
|
|
104
|
+
const edge = {
|
|
105
|
+
id: generateId("me"),
|
|
106
|
+
source: sourceId,
|
|
107
|
+
target: targetId,
|
|
108
|
+
relation,
|
|
109
|
+
weight: weight ?? 1.0,
|
|
110
|
+
createdAt: Date.now(),
|
|
111
|
+
metadata: metadata ?? {},
|
|
112
|
+
};
|
|
113
|
+
graph.edges[edge.id] = edge;
|
|
114
|
+
return edge;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Semantic search with graph traversal — finds direct matches then walks
|
|
118
|
+
* 1st/2nd-degree neighbors.
|
|
119
|
+
*/
|
|
120
|
+
export function searchGraph(sessionId, query, maxDepth = 1, topK = 5, edgeFilter) {
|
|
121
|
+
const graph = getGraph(sessionId);
|
|
122
|
+
const nodes = Object.values(graph.nodes);
|
|
123
|
+
if (nodes.length === 0) {
|
|
124
|
+
return { direct: [], neighbors: [], totalNodes: 0, totalEdges: 0 };
|
|
125
|
+
}
|
|
126
|
+
const queryVec = embed(query);
|
|
127
|
+
const scored = nodes
|
|
128
|
+
.map((n) => ({ node: n, score: cosineSimilarity(queryVec, n.embedding) }))
|
|
129
|
+
.sort((a, b) => b.score - a.score);
|
|
130
|
+
const directHits = scored.slice(0, topK).map(({ node, score }) => {
|
|
131
|
+
node.lastAccessed = Date.now();
|
|
132
|
+
return {
|
|
133
|
+
node,
|
|
134
|
+
depth: 0,
|
|
135
|
+
pathRelations: [],
|
|
136
|
+
relevanceScore: Math.round(score * 1000) / 10,
|
|
137
|
+
};
|
|
138
|
+
});
|
|
139
|
+
const neighborResults = [];
|
|
140
|
+
const visited = new Set(directHits.map((h) => h.node.id));
|
|
141
|
+
for (const hit of directHits) {
|
|
142
|
+
traverseNeighbors(graph, hit.node.id, queryVec, 1, maxDepth, [hit.node.label], visited, neighborResults, edgeFilter);
|
|
143
|
+
}
|
|
144
|
+
neighborResults.sort((a, b) => b.relevanceScore - a.relevanceScore);
|
|
145
|
+
return {
|
|
146
|
+
direct: directHits,
|
|
147
|
+
neighbors: neighborResults.slice(0, topK * 2),
|
|
148
|
+
totalNodes: nodes.length,
|
|
149
|
+
totalEdges: Object.keys(graph.edges).length,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function traverseNeighbors(graph, nodeId, queryVec, depth, maxDepth, pathLabels, visited, results, edgeFilter) {
|
|
153
|
+
if (depth > maxDepth)
|
|
154
|
+
return;
|
|
155
|
+
for (const edge of getEdgesForNode(graph, nodeId)) {
|
|
156
|
+
if (edgeFilter && !edgeFilter.includes(edge.relation))
|
|
157
|
+
continue;
|
|
158
|
+
const neighborId = getNeighborId(edge, nodeId);
|
|
159
|
+
if (visited.has(neighborId))
|
|
160
|
+
continue;
|
|
161
|
+
const neighbor = graph.nodes[neighborId];
|
|
162
|
+
if (!neighbor)
|
|
163
|
+
continue;
|
|
164
|
+
visited.add(neighborId);
|
|
165
|
+
const similarity = cosineSimilarity(queryVec, neighbor.embedding);
|
|
166
|
+
const edgeDecay = decayWeight(edge);
|
|
167
|
+
const relevance = similarity * 0.6 + (edgeDecay / Math.max(edge.weight, 0.01)) * 0.4;
|
|
168
|
+
results.push({
|
|
169
|
+
node: neighbor,
|
|
170
|
+
depth,
|
|
171
|
+
pathRelations: [
|
|
172
|
+
...pathLabels,
|
|
173
|
+
`--[${edge.relation}]-->`,
|
|
174
|
+
neighbor.label,
|
|
175
|
+
],
|
|
176
|
+
relevanceScore: Math.round(relevance * 1000) / 10,
|
|
177
|
+
});
|
|
178
|
+
neighbor.lastAccessed = Date.now();
|
|
179
|
+
traverseNeighbors(graph, neighborId, queryVec, depth + 1, maxDepth, [...pathLabels, `--[${edge.relation}]-->`, neighbor.label], visited, results, edgeFilter);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Remove decayed edges (e^(-λt) below threshold) and orphan nodes
|
|
184
|
+
* with low access counts.
|
|
185
|
+
*/
|
|
186
|
+
export function pruneStaleLinks(sessionId, threshold) {
|
|
187
|
+
const graph = getGraph(sessionId);
|
|
188
|
+
const cutoff = threshold ?? STALE_THRESHOLD;
|
|
189
|
+
const toRemove = [];
|
|
190
|
+
for (const [edgeId, edge] of Object.entries(graph.edges)) {
|
|
191
|
+
if (decayWeight(edge) < cutoff)
|
|
192
|
+
toRemove.push(edgeId);
|
|
193
|
+
}
|
|
194
|
+
for (const id of toRemove)
|
|
195
|
+
delete graph.edges[id];
|
|
196
|
+
const orphanNodeIds = Object.keys(graph.nodes).filter((nodeId) => {
|
|
197
|
+
const n = graph.nodes[nodeId];
|
|
198
|
+
return (getEdgesForNode(graph, nodeId).length === 0 &&
|
|
199
|
+
n.accessCount <= 1 &&
|
|
200
|
+
Date.now() - n.lastAccessed > 7 * 86_400_000);
|
|
201
|
+
});
|
|
202
|
+
for (const id of orphanNodeIds)
|
|
203
|
+
delete graph.nodes[id];
|
|
204
|
+
return {
|
|
205
|
+
removed: toRemove.length + orphanNodeIds.length,
|
|
206
|
+
remaining: Object.keys(graph.edges).length,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Bulk-add nodes with auto-similarity linking (cosine ≥ 0.72 creates edges).
|
|
211
|
+
*/
|
|
212
|
+
export function addInterlinkedContext(sessionId, items, autoLink = true) {
|
|
213
|
+
const createdNodes = [];
|
|
214
|
+
for (const item of items) {
|
|
215
|
+
createdNodes.push(upsertNode(sessionId, item.type, item.label, item.content, item.metadata));
|
|
216
|
+
}
|
|
217
|
+
const createdEdges = [];
|
|
218
|
+
if (autoLink && createdNodes.length > 1) {
|
|
219
|
+
for (let i = 0; i < createdNodes.length; i++) {
|
|
220
|
+
for (let j = i + 1; j < createdNodes.length; j++) {
|
|
221
|
+
const similarity = cosineSimilarity(createdNodes[i].embedding, createdNodes[j].embedding);
|
|
222
|
+
if (similarity >= SIMILARITY_THRESHOLD) {
|
|
223
|
+
const edge = createRelation(sessionId, createdNodes[i].id, createdNodes[j].id, "similar_to", similarity);
|
|
224
|
+
if (edge)
|
|
225
|
+
createdEdges.push(edge);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// Also link to existing nodes
|
|
231
|
+
const graph = getGraph(sessionId);
|
|
232
|
+
const existingNodes = Object.values(graph.nodes)
|
|
233
|
+
.filter((n) => !createdNodes.find((cn) => cn.id === n.id))
|
|
234
|
+
.slice(0, 200);
|
|
235
|
+
if (autoLink) {
|
|
236
|
+
for (const newNode of createdNodes) {
|
|
237
|
+
for (const existing of existingNodes) {
|
|
238
|
+
const similarity = cosineSimilarity(newNode.embedding, existing.embedding);
|
|
239
|
+
if (similarity >= SIMILARITY_THRESHOLD) {
|
|
240
|
+
const edge = createRelation(sessionId, newNode.id, existing.id, "similar_to", similarity);
|
|
241
|
+
if (edge)
|
|
242
|
+
createdEdges.push(edge);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return { nodes: createdNodes, edges: createdEdges };
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Start from a node and walk outward — returns all reachable neighbors
|
|
251
|
+
* scored by decay and depth.
|
|
252
|
+
*/
|
|
253
|
+
export function retrieveWithTraversal(sessionId, startNodeId, maxDepth = 2, edgeFilter) {
|
|
254
|
+
const graph = getGraph(sessionId);
|
|
255
|
+
const startNode = graph.nodes[startNodeId];
|
|
256
|
+
if (!startNode)
|
|
257
|
+
return [];
|
|
258
|
+
startNode.lastAccessed = Date.now();
|
|
259
|
+
startNode.accessCount++;
|
|
260
|
+
const results = [
|
|
261
|
+
{
|
|
262
|
+
node: startNode,
|
|
263
|
+
depth: 0,
|
|
264
|
+
pathRelations: [startNode.label],
|
|
265
|
+
relevanceScore: 100,
|
|
266
|
+
},
|
|
267
|
+
];
|
|
268
|
+
const visited = new Set([startNodeId]);
|
|
269
|
+
collectTraversal(graph, startNodeId, 1, maxDepth, [startNode.label], visited, results, edgeFilter);
|
|
270
|
+
return results;
|
|
271
|
+
}
|
|
272
|
+
function collectTraversal(graph, nodeId, depth, maxDepth, pathLabels, visited, results, edgeFilter) {
|
|
273
|
+
if (depth > maxDepth)
|
|
274
|
+
return;
|
|
275
|
+
for (const edge of getEdgesForNode(graph, nodeId)) {
|
|
276
|
+
if (edgeFilter && !edgeFilter.includes(edge.relation))
|
|
277
|
+
continue;
|
|
278
|
+
const neighborId = getNeighborId(edge, nodeId);
|
|
279
|
+
if (visited.has(neighborId))
|
|
280
|
+
continue;
|
|
281
|
+
const neighbor = graph.nodes[neighborId];
|
|
282
|
+
if (!neighbor)
|
|
283
|
+
continue;
|
|
284
|
+
visited.add(neighborId);
|
|
285
|
+
neighbor.lastAccessed = Date.now();
|
|
286
|
+
const decayed = decayWeight(edge);
|
|
287
|
+
const depthPenalty = 1 / (1 + depth * 0.3);
|
|
288
|
+
const score = decayed * depthPenalty * 100;
|
|
289
|
+
results.push({
|
|
290
|
+
node: neighbor,
|
|
291
|
+
depth,
|
|
292
|
+
pathRelations: [
|
|
293
|
+
...pathLabels,
|
|
294
|
+
`--[${edge.relation}]-->`,
|
|
295
|
+
neighbor.label,
|
|
296
|
+
],
|
|
297
|
+
relevanceScore: Math.round(score * 10) / 10,
|
|
298
|
+
});
|
|
299
|
+
collectTraversal(graph, neighborId, depth + 1, maxDepth, [...pathLabels, `--[${edge.relation}]-->`, neighbor.label], visited, results, edgeFilter);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Get summary statistics for the session's memory graph.
|
|
304
|
+
*/
|
|
305
|
+
export function getGraphStats(sessionId) {
|
|
306
|
+
const graph = getGraph(sessionId);
|
|
307
|
+
const types = {};
|
|
308
|
+
const relations = {};
|
|
309
|
+
for (const node of Object.values(graph.nodes)) {
|
|
310
|
+
types[node.type] = (types[node.type] ?? 0) + 1;
|
|
311
|
+
}
|
|
312
|
+
for (const edge of Object.values(graph.edges)) {
|
|
313
|
+
relations[edge.relation] = (relations[edge.relation] ?? 0) + 1;
|
|
314
|
+
}
|
|
315
|
+
return {
|
|
316
|
+
nodes: Object.keys(graph.nodes).length,
|
|
317
|
+
edges: Object.keys(graph.edges).length,
|
|
318
|
+
types,
|
|
319
|
+
relations,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
/**
|
|
323
|
+
* Export the full graph for a session as a JSON-serializable object.
|
|
324
|
+
*/
|
|
325
|
+
export function exportGraph(sessionId) {
|
|
326
|
+
return getGraph(sessionId);
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Import a graph from a JSON object into a session.
|
|
330
|
+
*/
|
|
331
|
+
export function importGraph(sessionId, data) {
|
|
332
|
+
_graphStores.set(sessionId, data);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Clear the graph for a session.
|
|
336
|
+
*/
|
|
337
|
+
export function clearGraph(sessionId) {
|
|
338
|
+
const graph = _graphStores.get(sessionId);
|
|
339
|
+
if (!graph)
|
|
340
|
+
return 0;
|
|
341
|
+
const count = Object.keys(graph.nodes).length + Object.keys(graph.edges).length;
|
|
342
|
+
_graphStores.delete(sessionId);
|
|
343
|
+
return count;
|
|
344
|
+
}
|
|
345
|
+
//# sourceMappingURL=memory-graph.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-graph.js","sourceRoot":"","sources":["../src/memory-graph.ts"],"names":[],"mappings":"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"}
|