@getplumb/core 0.1.6 → 0.4.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 +2 -2
- package/dist/context-builder.d.ts +1 -7
- package/dist/context-builder.d.ts.map +1 -1
- package/dist/context-builder.js +7 -44
- package/dist/context-builder.js.map +1 -1
- package/dist/embedder.d.ts +16 -2
- package/dist/embedder.d.ts.map +1 -1
- package/dist/embedder.js +23 -4
- package/dist/embedder.js.map +1 -1
- package/dist/extraction-queue.d.ts +13 -3
- package/dist/extraction-queue.d.ts.map +1 -1
- package/dist/extraction-queue.js +21 -4
- package/dist/extraction-queue.js.map +1 -1
- package/dist/extractor.d.ts +2 -1
- package/dist/extractor.d.ts.map +1 -1
- package/dist/extractor.js +106 -7
- package/dist/extractor.js.map +1 -1
- package/dist/extractor.test.d.ts +2 -0
- package/dist/extractor.test.d.ts.map +1 -0
- package/dist/extractor.test.js +158 -0
- package/dist/extractor.test.js.map +1 -0
- package/dist/fact-search.d.ts +9 -5
- package/dist/fact-search.d.ts.map +1 -1
- package/dist/fact-search.js +25 -16
- package/dist/fact-search.js.map +1 -1
- package/dist/fact-search.test.d.ts +12 -0
- package/dist/fact-search.test.d.ts.map +1 -0
- package/dist/fact-search.test.js +117 -0
- package/dist/fact-search.test.js.map +1 -0
- package/dist/index.d.ts +6 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -5
- package/dist/index.js.map +1 -1
- package/dist/llm-client.d.ts +11 -2
- package/dist/llm-client.d.ts.map +1 -1
- package/dist/llm-client.js +47 -3
- package/dist/llm-client.js.map +1 -1
- package/dist/local-store.d.ts +19 -63
- package/dist/local-store.d.ts.map +1 -1
- package/dist/local-store.js +353 -262
- package/dist/local-store.js.map +1 -1
- package/dist/local-store.test.d.ts +2 -0
- package/dist/local-store.test.d.ts.map +1 -0
- package/dist/local-store.test.js +146 -0
- package/dist/local-store.test.js.map +1 -0
- package/dist/raw-log-search.d.ts +9 -5
- package/dist/raw-log-search.d.ts.map +1 -1
- package/dist/raw-log-search.js +107 -29
- package/dist/raw-log-search.js.map +1 -1
- package/dist/raw-log-search.test.d.ts +12 -0
- package/dist/raw-log-search.test.d.ts.map +1 -0
- package/dist/raw-log-search.test.js +124 -0
- package/dist/raw-log-search.test.js.map +1 -0
- package/dist/read-path.d.ts +6 -23
- package/dist/read-path.d.ts.map +1 -1
- package/dist/read-path.js +9 -48
- package/dist/read-path.js.map +1 -1
- package/dist/read-path.test.d.ts +15 -0
- package/dist/read-path.test.d.ts.map +1 -0
- package/dist/read-path.test.js +393 -0
- package/dist/read-path.test.js.map +1 -0
- package/dist/schema.d.ts +4 -13
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +42 -52
- package/dist/schema.js.map +1 -1
- package/dist/scorer.d.ts +0 -9
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +1 -31
- package/dist/scorer.js.map +1 -1
- package/dist/scorer.test.d.ts +10 -0
- package/dist/scorer.test.d.ts.map +1 -0
- package/dist/scorer.test.js +169 -0
- package/dist/scorer.test.js.map +1 -0
- package/dist/store.d.ts +2 -14
- package/dist/store.d.ts.map +1 -1
- package/dist/types.d.ts +0 -25
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +1 -6
- package/dist/types.js.map +1 -1
- package/dist/wasm-db.d.ts +63 -8
- package/dist/wasm-db.d.ts.map +1 -1
- package/dist/wasm-db.js +124 -31
- package/dist/wasm-db.js.map +1 -1
- package/package.json +14 -2
package/dist/read-path.d.ts
CHANGED
|
@@ -1,20 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Read path — Layer 1
|
|
2
|
+
* Read path — Layer 1 retrieval (raw log search only).
|
|
3
3
|
*
|
|
4
|
-
* buildMemoryContext() is called before every agent response. It queries
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* buildMemoryContext() is called before every agent response. It queries
|
|
5
|
+
* the raw_log table with hybrid search and returns a MemoryContext ready
|
|
6
|
+
* for formatContextBlock().
|
|
7
7
|
*
|
|
8
8
|
* Search is always cross-session — no session filter is applied.
|
|
9
9
|
*/
|
|
10
|
-
import type { SearchResult, Fact } from './types.js';
|
|
11
10
|
import type { RawLogSearchResult } from './local-store.js';
|
|
12
|
-
export interface ScoredFact {
|
|
13
|
-
readonly fact: Fact;
|
|
14
|
-
/** Decay-adjusted score in [0,1]. */
|
|
15
|
-
readonly score: number;
|
|
16
|
-
readonly ageInDays: number;
|
|
17
|
-
}
|
|
18
11
|
export interface RawChunk {
|
|
19
12
|
readonly chunkText: string;
|
|
20
13
|
readonly sessionId: string;
|
|
@@ -24,37 +17,27 @@ export interface RawChunk {
|
|
|
24
17
|
readonly score: number;
|
|
25
18
|
}
|
|
26
19
|
export interface MemoryContext {
|
|
27
|
-
readonly highConfidence: ScoredFact[];
|
|
28
|
-
readonly mediumConfidence: ScoredFact[];
|
|
29
|
-
readonly lowConfidence: ScoredFact[];
|
|
30
20
|
readonly relatedConversations: RawChunk[];
|
|
31
21
|
}
|
|
32
22
|
export interface ReadPathOptions {
|
|
33
|
-
/** Max facts returned per confidence tier. Default: 5. */
|
|
34
|
-
maxFactsPerTier?: number;
|
|
35
23
|
/** Max raw log chunks returned. Default: 3. */
|
|
36
24
|
maxRawChunks?: number;
|
|
37
|
-
/** Point-in-time for decay computation. Default: new Date(). */
|
|
38
|
-
now?: Date;
|
|
39
25
|
}
|
|
40
26
|
/**
|
|
41
27
|
* Minimal store interface required by the read path.
|
|
42
28
|
* LocalStore satisfies this; tests can pass a mock.
|
|
43
29
|
*/
|
|
44
30
|
export interface ReadPathStore {
|
|
45
|
-
search(query: string, limit?: number): Promise<readonly SearchResult[]>;
|
|
46
31
|
searchRawLog(query: string, limit?: number): Promise<readonly RawLogSearchResult[]>;
|
|
47
32
|
}
|
|
48
33
|
/**
|
|
49
34
|
* Build a structured MemoryContext for a given query.
|
|
50
35
|
*
|
|
51
|
-
* Queries Layer 1 (raw log hybrid search) and
|
|
52
|
-
* Facts are re-scored with scoreFact() and tiered by confidence band.
|
|
53
|
-
* Raw chunks are returned in hybrid-search score order.
|
|
36
|
+
* Queries Layer 1 (raw log hybrid search) and returns ranked chunks.
|
|
54
37
|
*
|
|
55
38
|
* @param query Natural language query (the incoming user message or context).
|
|
56
39
|
* @param store Any store implementing ReadPathStore (typically LocalStore).
|
|
57
|
-
* @param options Optional limits
|
|
40
|
+
* @param options Optional limits.
|
|
58
41
|
*/
|
|
59
42
|
export declare function buildMemoryContext(query: string, store: ReadPathStore, options?: ReadPathOptions): Promise<MemoryContext>;
|
|
60
43
|
//# sourceMappingURL=read-path.d.ts.map
|
package/dist/read-path.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-path.d.ts","sourceRoot":"","sources":["../src/read-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"read-path.d.ts","sourceRoot":"","sources":["../src/read-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,kBAAkB,CAAC;AAI3D,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IACrC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,oBAAoB,EAAE,QAAQ,EAAE,CAAC;CAC3C;AAED,MAAM,WAAW,eAAe;IAC9B,+CAA+C;IAC/C,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,kBAAkB,EAAE,CAAC,CAAC;CACrF;AAID;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,aAAa,CAAC,CAmBxB"}
|
package/dist/read-path.js
CHANGED
|
@@ -1,66 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Read path — Layer 1
|
|
2
|
+
* Read path — Layer 1 retrieval (raw log search only).
|
|
3
3
|
*
|
|
4
|
-
* buildMemoryContext() is called before every agent response. It queries
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* buildMemoryContext() is called before every agent response. It queries
|
|
5
|
+
* the raw_log table with hybrid search and returns a MemoryContext ready
|
|
6
|
+
* for formatContextBlock().
|
|
7
7
|
*
|
|
8
8
|
* Search is always cross-session — no session filter is applied.
|
|
9
9
|
*/
|
|
10
|
-
import { scoreFact } from './scorer.js';
|
|
11
|
-
// ─── Confidence band boundaries ───────────────────────────────────────────────
|
|
12
|
-
const HIGH_THRESHOLD = 0.7;
|
|
13
|
-
const LOW_THRESHOLD = 0.3;
|
|
14
10
|
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
15
11
|
/**
|
|
16
12
|
* Build a structured MemoryContext for a given query.
|
|
17
13
|
*
|
|
18
|
-
* Queries Layer 1 (raw log hybrid search) and
|
|
19
|
-
* Facts are re-scored with scoreFact() and tiered by confidence band.
|
|
20
|
-
* Raw chunks are returned in hybrid-search score order.
|
|
14
|
+
* Queries Layer 1 (raw log hybrid search) and returns ranked chunks.
|
|
21
15
|
*
|
|
22
16
|
* @param query Natural language query (the incoming user message or context).
|
|
23
17
|
* @param store Any store implementing ReadPathStore (typically LocalStore).
|
|
24
|
-
* @param options Optional limits
|
|
18
|
+
* @param options Optional limits.
|
|
25
19
|
*/
|
|
26
20
|
export async function buildMemoryContext(query, store, options) {
|
|
27
|
-
const maxFactsPerTier = options?.maxFactsPerTier ?? 5;
|
|
28
21
|
const maxRawChunks = options?.maxRawChunks ?? 3;
|
|
29
|
-
const now = options?.now ?? new Date();
|
|
30
|
-
// Fetch more candidates than needed so tiering has enough to fill each band.
|
|
31
|
-
const factCandidateLimit = maxFactsPerTier * 3 * 3; // 3 tiers × 3× headroom
|
|
32
22
|
const rawCandidateLimit = maxRawChunks * 3;
|
|
33
|
-
// ── Query Layer 1
|
|
34
|
-
const
|
|
35
|
-
store.search(query, factCandidateLimit),
|
|
36
|
-
store.searchRawLog(query, rawCandidateLimit),
|
|
37
|
-
]);
|
|
38
|
-
// ── Re-score facts with decay ──────────────────────────────────────────────
|
|
39
|
-
const scoredFacts = searchResults.map((result) => {
|
|
40
|
-
const { score } = scoreFact(result.fact, now);
|
|
41
|
-
const ageInDays = (now.getTime() - result.fact.timestamp.getTime()) / (1_000 * 60 * 60 * 24);
|
|
42
|
-
return { fact: result.fact, score, ageInDays };
|
|
43
|
-
});
|
|
44
|
-
// Sort by score descending.
|
|
45
|
-
scoredFacts.sort((a, b) => b.score - a.score);
|
|
46
|
-
// ── Tier facts into confidence bands ──────────────────────────────────────
|
|
47
|
-
const highConfidence = [];
|
|
48
|
-
const mediumConfidence = [];
|
|
49
|
-
const lowConfidence = [];
|
|
50
|
-
for (const sf of scoredFacts) {
|
|
51
|
-
if (sf.score > HIGH_THRESHOLD) {
|
|
52
|
-
if (highConfidence.length < maxFactsPerTier)
|
|
53
|
-
highConfidence.push(sf);
|
|
54
|
-
}
|
|
55
|
-
else if (sf.score >= LOW_THRESHOLD) {
|
|
56
|
-
if (mediumConfidence.length < maxFactsPerTier)
|
|
57
|
-
mediumConfidence.push(sf);
|
|
58
|
-
}
|
|
59
|
-
else {
|
|
60
|
-
if (lowConfidence.length < maxFactsPerTier)
|
|
61
|
-
lowConfidence.push(sf);
|
|
62
|
-
}
|
|
63
|
-
}
|
|
23
|
+
// ── Query Layer 1 (raw log) ───────────────────────────────────────────────
|
|
24
|
+
const rawLogResults = await store.searchRawLog(query, rawCandidateLimit);
|
|
64
25
|
// ── Build raw chunks (already ranked by hybrid search score) ──────────────
|
|
65
26
|
const relatedConversations = rawLogResults
|
|
66
27
|
.slice(0, maxRawChunks)
|
|
@@ -71,6 +32,6 @@ export async function buildMemoryContext(query, store, options) {
|
|
|
71
32
|
timestamp: new Date(r.timestamp),
|
|
72
33
|
score: r.final_score,
|
|
73
34
|
}));
|
|
74
|
-
return {
|
|
35
|
+
return { relatedConversations };
|
|
75
36
|
}
|
|
76
37
|
//# sourceMappingURL=read-path.js.map
|
package/dist/read-path.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"read-path.js","sourceRoot":"","sources":["../src/read-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"read-path.js","sourceRoot":"","sources":["../src/read-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAgCH,iFAAiF;AAEjF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAa,EACb,KAAoB,EACpB,OAAyB;IAEzB,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,IAAI,CAAC,CAAC;IAChD,MAAM,iBAAiB,GAAG,YAAY,GAAG,CAAC,CAAC;IAE3C,6EAA6E;IAC7E,MAAM,aAAa,GAAG,MAAM,KAAK,CAAC,YAAY,CAAC,KAAK,EAAE,iBAAiB,CAAC,CAAC;IAEzE,6EAA6E;IAC7E,MAAM,oBAAoB,GAAe,aAAa;SACnD,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC;SACtB,GAAG,CAAC,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC;QAC/B,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,SAAS,EAAE,CAAC,CAAC,UAAU;QACvB,YAAY,EAAE,CAAC,CAAC,aAAa;QAC7B,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;QAChC,KAAK,EAAE,CAAC,CAAC,WAAW;KACrB,CAAC,CAAC,CAAC;IAEN,OAAO,EAAE,oBAAoB,EAAE,CAAC;AAClC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for read-path.ts (buildMemoryContext) and context-builder.ts (formatContextBlock).
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* - Unit tests use a mock ReadPathStore to avoid ML model downloads and keep
|
|
6
|
+
* tests fast and deterministic.
|
|
7
|
+
* - One integration smoke test uses a real LocalStore with real facts inserted
|
|
8
|
+
* via store.store() (keyword search, no embedder needed) to verify the
|
|
9
|
+
* end-to-end cross-session provenance path.
|
|
10
|
+
*
|
|
11
|
+
* Cross-session test (acceptance criteria): facts ingested in session A must
|
|
12
|
+
* be returned when querying in session B context — no session filter applied.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=read-path.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-path.test.d.ts","sourceRoot":"","sources":["../src/read-path.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -0,0 +1,393 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for read-path.ts (buildMemoryContext) and context-builder.ts (formatContextBlock).
|
|
3
|
+
*
|
|
4
|
+
* Strategy:
|
|
5
|
+
* - Unit tests use a mock ReadPathStore to avoid ML model downloads and keep
|
|
6
|
+
* tests fast and deterministic.
|
|
7
|
+
* - One integration smoke test uses a real LocalStore with real facts inserted
|
|
8
|
+
* via store.store() (keyword search, no embedder needed) to verify the
|
|
9
|
+
* end-to-end cross-session provenance path.
|
|
10
|
+
*
|
|
11
|
+
* Cross-session test (acceptance criteria): facts ingested in session A must
|
|
12
|
+
* be returned when querying in session B context — no session filter applied.
|
|
13
|
+
*/
|
|
14
|
+
import { test, describe, after } from 'node:test';
|
|
15
|
+
import assert from 'node:assert/strict';
|
|
16
|
+
import { tmpdir } from 'node:os';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { rmSync } from 'node:fs';
|
|
19
|
+
import { buildMemoryContext } from './read-path.js';
|
|
20
|
+
import { formatContextBlock, formatAge } from './context-builder.js';
|
|
21
|
+
import { LocalStore } from './local-store.js';
|
|
22
|
+
import { DecayRate } from './types.js';
|
|
23
|
+
// ─── Mock store factory ───────────────────────────────────────────────────────
|
|
24
|
+
function makeStore(searchResults = [], rawLogResults = []) {
|
|
25
|
+
let searchCallCount = 0;
|
|
26
|
+
let rawLogCallCount = 0;
|
|
27
|
+
return {
|
|
28
|
+
get searchCallCount() { return searchCallCount; },
|
|
29
|
+
get rawLogCallCount() { return rawLogCallCount; },
|
|
30
|
+
async search(_query, _limit) {
|
|
31
|
+
searchCallCount++;
|
|
32
|
+
return searchResults;
|
|
33
|
+
},
|
|
34
|
+
async searchRawLog(_query, _limit) {
|
|
35
|
+
rawLogCallCount++;
|
|
36
|
+
return rawLogResults;
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
/** Build a minimal Fact with configurable fields. */
|
|
41
|
+
function makeFact(opts) {
|
|
42
|
+
const now = opts.now ?? new Date('2026-01-01T00:00:00.000Z');
|
|
43
|
+
const ageInDays = opts.ageInDays ?? 0;
|
|
44
|
+
const timestamp = new Date(now.getTime() - ageInDays * 24 * 60 * 60 * 1_000);
|
|
45
|
+
return {
|
|
46
|
+
id: crypto.randomUUID(),
|
|
47
|
+
subject: opts.subject ?? 'user',
|
|
48
|
+
predicate: opts.predicate ?? 'is',
|
|
49
|
+
object: opts.object ?? 'a developer',
|
|
50
|
+
confidence: opts.confidence,
|
|
51
|
+
decayRate: opts.decayRate ?? DecayRate.slow,
|
|
52
|
+
timestamp,
|
|
53
|
+
sourceSessionId: opts.sessionId ?? 'session-default',
|
|
54
|
+
...(opts.sessionLabel !== undefined ? { sourceSessionLabel: opts.sessionLabel } : {}),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/** Build a SearchResult wrapping a fact (store score is ignored; read-path re-scores). */
|
|
58
|
+
function makeSearchResult(fact, now) {
|
|
59
|
+
const ageInDays = (now.getTime() - fact.timestamp.getTime()) / (1_000 * 60 * 60 * 24);
|
|
60
|
+
return { fact, score: 1.0, ageInDays };
|
|
61
|
+
}
|
|
62
|
+
/** Build a RawLogSearchResult for testing. */
|
|
63
|
+
function makeRawChunk(opts) {
|
|
64
|
+
const now = opts.now ?? new Date('2026-01-01T00:00:00.000Z');
|
|
65
|
+
const ageInDays = opts.ageInDays ?? 0;
|
|
66
|
+
const timestamp = new Date(now.getTime() - ageInDays * 24 * 60 * 60 * 1_000);
|
|
67
|
+
return {
|
|
68
|
+
chunk_text: opts.text,
|
|
69
|
+
session_id: opts.sessionId,
|
|
70
|
+
session_label: opts.sessionLabel ?? null,
|
|
71
|
+
timestamp: timestamp.toISOString(),
|
|
72
|
+
final_score: opts.score ?? 0.5,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
// ─── formatAge unit tests ─────────────────────────────────────────────────────
|
|
76
|
+
describe('formatAge', () => {
|
|
77
|
+
test('< 1 day → today', () => {
|
|
78
|
+
assert.equal(formatAge(0), 'today');
|
|
79
|
+
assert.equal(formatAge(0.5), 'today');
|
|
80
|
+
assert.equal(formatAge(0.99), 'today');
|
|
81
|
+
});
|
|
82
|
+
test('1-2 days → yesterday', () => {
|
|
83
|
+
assert.equal(formatAge(1), 'yesterday');
|
|
84
|
+
assert.equal(formatAge(1.9), 'yesterday');
|
|
85
|
+
});
|
|
86
|
+
test('2-7 days → N days ago', () => {
|
|
87
|
+
assert.equal(formatAge(2), '2 days ago');
|
|
88
|
+
assert.equal(formatAge(6.9), '6 days ago');
|
|
89
|
+
});
|
|
90
|
+
test('7-14 days → 1 week ago', () => {
|
|
91
|
+
assert.equal(formatAge(7), '1 week ago');
|
|
92
|
+
assert.equal(formatAge(13.9), '1 week ago');
|
|
93
|
+
});
|
|
94
|
+
test('14-30 days → N weeks ago', () => {
|
|
95
|
+
assert.equal(formatAge(14), '2 weeks ago');
|
|
96
|
+
assert.equal(formatAge(21), '3 weeks ago');
|
|
97
|
+
});
|
|
98
|
+
test('30-60 days → 1 month ago', () => {
|
|
99
|
+
assert.equal(formatAge(30), '1 month ago');
|
|
100
|
+
assert.equal(formatAge(59), '1 month ago');
|
|
101
|
+
});
|
|
102
|
+
test('60-365 days → N months ago', () => {
|
|
103
|
+
assert.equal(formatAge(60), '2 months ago');
|
|
104
|
+
assert.equal(formatAge(90), '3 months ago');
|
|
105
|
+
});
|
|
106
|
+
test('365-730 days → 1 year ago', () => {
|
|
107
|
+
assert.equal(formatAge(365), '1 year ago');
|
|
108
|
+
assert.equal(formatAge(729), '1 year ago');
|
|
109
|
+
});
|
|
110
|
+
test('≥ 730 days → N years ago', () => {
|
|
111
|
+
assert.equal(formatAge(730), '2 years ago');
|
|
112
|
+
assert.equal(formatAge(1095), '3 years ago');
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
// ─── buildMemoryContext unit tests ────────────────────────────────────────────
|
|
116
|
+
describe('buildMemoryContext', () => {
|
|
117
|
+
const NOW = new Date('2026-01-01T00:00:00.000Z');
|
|
118
|
+
test('queries Layer 1 and Layer 2 in parallel (both called once)', async () => {
|
|
119
|
+
const store = makeStore();
|
|
120
|
+
await buildMemoryContext('anything', store, { now: NOW });
|
|
121
|
+
assert.equal(store.searchCallCount, 1, 'search() must be called once');
|
|
122
|
+
assert.equal(store.rawLogCallCount, 1, 'searchRawLog() must be called once');
|
|
123
|
+
});
|
|
124
|
+
test('empty store → empty MemoryContext', async () => {
|
|
125
|
+
const store = makeStore();
|
|
126
|
+
const ctx = await buildMemoryContext('test query', store, { now: NOW });
|
|
127
|
+
assert.deepEqual(ctx.highConfidence, []);
|
|
128
|
+
assert.deepEqual(ctx.mediumConfidence, []);
|
|
129
|
+
assert.deepEqual(ctx.lowConfidence, []);
|
|
130
|
+
assert.deepEqual(ctx.relatedConversations, []);
|
|
131
|
+
});
|
|
132
|
+
test('facts tiered correctly by scoreFact() score', async () => {
|
|
133
|
+
// confidence=0.95, slow decay, age=0 → score ~0.95 (high)
|
|
134
|
+
const highFact = makeFact({ confidence: 0.95, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
135
|
+
// confidence=0.5, slow decay, age=0 → score ~0.5 (medium)
|
|
136
|
+
const medFact = makeFact({ confidence: 0.5, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
137
|
+
// confidence=0.2, slow decay, age=0 → score ~0.2 (low)
|
|
138
|
+
const lowFact = makeFact({ confidence: 0.2, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
139
|
+
const store = makeStore([
|
|
140
|
+
makeSearchResult(highFact, NOW),
|
|
141
|
+
makeSearchResult(medFact, NOW),
|
|
142
|
+
makeSearchResult(lowFact, NOW),
|
|
143
|
+
]);
|
|
144
|
+
const ctx = await buildMemoryContext('query', store, { now: NOW });
|
|
145
|
+
assert.equal(ctx.highConfidence.length, 1, 'one high-confidence fact');
|
|
146
|
+
assert.equal(ctx.mediumConfidence.length, 1, 'one medium-confidence fact');
|
|
147
|
+
assert.equal(ctx.lowConfidence.length, 1, 'one low-confidence fact');
|
|
148
|
+
assert.ok(ctx.highConfidence[0].score > 0.7, 'high score > 0.7');
|
|
149
|
+
assert.ok(ctx.mediumConfidence[0].score >= 0.3 && ctx.mediumConfidence[0].score <= 0.7);
|
|
150
|
+
assert.ok(ctx.lowConfidence[0].score < 0.3, 'low score < 0.3');
|
|
151
|
+
});
|
|
152
|
+
test('facts sorted by score descending within each tier', async () => {
|
|
153
|
+
const f1 = makeFact({ confidence: 0.95, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
154
|
+
const f2 = makeFact({ confidence: 0.85, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
155
|
+
const f3 = makeFact({ confidence: 0.72, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
156
|
+
const store = makeStore([
|
|
157
|
+
makeSearchResult(f3, NOW),
|
|
158
|
+
makeSearchResult(f1, NOW),
|
|
159
|
+
makeSearchResult(f2, NOW),
|
|
160
|
+
]);
|
|
161
|
+
const ctx = await buildMemoryContext('query', store, { now: NOW });
|
|
162
|
+
const scores = ctx.highConfidence.map((sf) => sf.score);
|
|
163
|
+
for (let i = 1; i < scores.length; i++) {
|
|
164
|
+
assert.ok(scores[i - 1] >= scores[i], 'scores should be descending');
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
test('respects maxFactsPerTier limit', async () => {
|
|
168
|
+
const facts = Array.from({ length: 10 }, () => makeFact({ confidence: 0.9, decayRate: DecayRate.slow, ageInDays: 0, now: NOW }));
|
|
169
|
+
const store = makeStore(facts.map((f) => makeSearchResult(f, NOW)));
|
|
170
|
+
const ctx = await buildMemoryContext('query', store, { now: NOW, maxFactsPerTier: 3 });
|
|
171
|
+
assert.ok(ctx.highConfidence.length <= 3, 'high tier capped at 3');
|
|
172
|
+
});
|
|
173
|
+
test('respects maxRawChunks limit', async () => {
|
|
174
|
+
const chunks = Array.from({ length: 6 }, (_, i) => makeRawChunk({ text: `chunk ${i}`, sessionId: `sess-${i}`, score: 0.9 - i * 0.1, now: NOW }));
|
|
175
|
+
const store = makeStore([], chunks);
|
|
176
|
+
const ctx = await buildMemoryContext('query', store, { now: NOW, maxRawChunks: 2 });
|
|
177
|
+
assert.ok(ctx.relatedConversations.length <= 2, 'raw chunks capped at 2');
|
|
178
|
+
});
|
|
179
|
+
test('provenance fields present on ScoredFact', async () => {
|
|
180
|
+
const fact = makeFact({
|
|
181
|
+
confidence: 0.9,
|
|
182
|
+
decayRate: DecayRate.slow,
|
|
183
|
+
ageInDays: 3,
|
|
184
|
+
sessionId: 'session-A',
|
|
185
|
+
sessionLabel: 'planning-session',
|
|
186
|
+
now: NOW,
|
|
187
|
+
});
|
|
188
|
+
const store = makeStore([makeSearchResult(fact, NOW)]);
|
|
189
|
+
const ctx = await buildMemoryContext('query', store, { now: NOW });
|
|
190
|
+
const sf = ctx.highConfidence[0];
|
|
191
|
+
assert.ok(sf !== undefined, 'should have a high confidence fact');
|
|
192
|
+
assert.equal(sf.fact.sourceSessionId, 'session-A');
|
|
193
|
+
assert.equal(sf.fact.sourceSessionLabel, 'planning-session');
|
|
194
|
+
assert.ok(sf.ageInDays >= 3 && sf.ageInDays < 4, `ageInDays should be ~3, got ${sf.ageInDays}`);
|
|
195
|
+
});
|
|
196
|
+
test('provenance fields present on RawChunk', async () => {
|
|
197
|
+
const chunk = makeRawChunk({
|
|
198
|
+
text: 'We discussed the memory architecture in detail.',
|
|
199
|
+
sessionId: 'session-B',
|
|
200
|
+
sessionLabel: 'architecture-review',
|
|
201
|
+
ageInDays: 1,
|
|
202
|
+
score: 0.8,
|
|
203
|
+
now: NOW,
|
|
204
|
+
});
|
|
205
|
+
const store = makeStore([], [chunk]);
|
|
206
|
+
const ctx = await buildMemoryContext('query', store, { now: NOW });
|
|
207
|
+
const rc = ctx.relatedConversations[0];
|
|
208
|
+
assert.ok(rc !== undefined, 'should have a related conversation');
|
|
209
|
+
assert.equal(rc.sessionId, 'session-B');
|
|
210
|
+
assert.equal(rc.sessionLabel, 'architecture-review');
|
|
211
|
+
assert.equal(rc.score, 0.8);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
// ─── formatContextBlock unit tests ───────────────────────────────────────────
|
|
215
|
+
describe('formatContextBlock', () => {
|
|
216
|
+
const NOW = new Date('2026-01-01T00:00:00.000Z');
|
|
217
|
+
test('empty MemoryContext → empty string (no block injected)', () => {
|
|
218
|
+
const ctx = {
|
|
219
|
+
highConfidence: [],
|
|
220
|
+
mediumConfidence: [],
|
|
221
|
+
lowConfidence: [],
|
|
222
|
+
relatedConversations: [],
|
|
223
|
+
};
|
|
224
|
+
assert.equal(formatContextBlock(ctx), '');
|
|
225
|
+
});
|
|
226
|
+
test('output starts with [MEMORY CONTEXT]', () => {
|
|
227
|
+
const fact = makeFact({ confidence: 0.9, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
228
|
+
const ctx = {
|
|
229
|
+
highConfidence: [{ fact, score: 0.9, ageInDays: 0 }],
|
|
230
|
+
mediumConfidence: [],
|
|
231
|
+
lowConfidence: [],
|
|
232
|
+
relatedConversations: [],
|
|
233
|
+
};
|
|
234
|
+
const output = formatContextBlock(ctx);
|
|
235
|
+
assert.ok(output.startsWith('[MEMORY CONTEXT]'), `expected block header, got: ${output.slice(0, 50)}`);
|
|
236
|
+
});
|
|
237
|
+
test('fact line includes description, score (2dp), session label, age', () => {
|
|
238
|
+
const fact = makeFact({
|
|
239
|
+
subject: 'user',
|
|
240
|
+
predicate: 'is building',
|
|
241
|
+
object: 'Plumb',
|
|
242
|
+
confidence: 0.98,
|
|
243
|
+
decayRate: DecayRate.slow,
|
|
244
|
+
ageInDays: 0,
|
|
245
|
+
sessionId: 'session-X',
|
|
246
|
+
sessionLabel: 'tech-planning',
|
|
247
|
+
now: NOW,
|
|
248
|
+
});
|
|
249
|
+
const ctx = {
|
|
250
|
+
highConfidence: [{ fact, score: 0.98, ageInDays: 0 }],
|
|
251
|
+
mediumConfidence: [],
|
|
252
|
+
lowConfidence: [],
|
|
253
|
+
relatedConversations: [],
|
|
254
|
+
};
|
|
255
|
+
const output = formatContextBlock(ctx);
|
|
256
|
+
assert.ok(output.includes('user is building Plumb'), 'should include fact description');
|
|
257
|
+
assert.ok(output.includes('0.98'), 'should include score (2dp)');
|
|
258
|
+
assert.ok(output.includes('tech-planning'), 'should include session label');
|
|
259
|
+
assert.ok(output.includes('today'), 'should include age');
|
|
260
|
+
});
|
|
261
|
+
test('fact line falls back to sourceSessionId when label absent', () => {
|
|
262
|
+
const fact = makeFact({
|
|
263
|
+
confidence: 0.9,
|
|
264
|
+
decayRate: DecayRate.slow,
|
|
265
|
+
ageInDays: 0,
|
|
266
|
+
sessionId: 'session-fallback',
|
|
267
|
+
now: NOW,
|
|
268
|
+
// no sessionLabel
|
|
269
|
+
});
|
|
270
|
+
const ctx = {
|
|
271
|
+
highConfidence: [{ fact, score: 0.9, ageInDays: 0 }],
|
|
272
|
+
mediumConfidence: [],
|
|
273
|
+
lowConfidence: [],
|
|
274
|
+
relatedConversations: [],
|
|
275
|
+
};
|
|
276
|
+
const output = formatContextBlock(ctx);
|
|
277
|
+
assert.ok(output.includes('session-fallback'), 'should fall back to session ID');
|
|
278
|
+
});
|
|
279
|
+
test('raw chunk line includes session label, age, excerpt (max 200 chars)', () => {
|
|
280
|
+
const longText = 'A'.repeat(300);
|
|
281
|
+
const chunk = {
|
|
282
|
+
chunkText: longText,
|
|
283
|
+
sessionId: 'sess-raw',
|
|
284
|
+
sessionLabel: 'architecture-review',
|
|
285
|
+
timestamp: new Date(NOW.getTime() - 2 * 24 * 60 * 60 * 1_000), // 2 days ago
|
|
286
|
+
score: 0.75,
|
|
287
|
+
};
|
|
288
|
+
const ctx = {
|
|
289
|
+
highConfidence: [],
|
|
290
|
+
mediumConfidence: [],
|
|
291
|
+
lowConfidence: [],
|
|
292
|
+
relatedConversations: [chunk],
|
|
293
|
+
};
|
|
294
|
+
const output = formatContextBlock(ctx);
|
|
295
|
+
assert.ok(output.includes('architecture-review'), 'should include session label');
|
|
296
|
+
// Excerpt should be truncated to 200 chars.
|
|
297
|
+
const excerptMatch = output.match(/"([^"]+)"/);
|
|
298
|
+
assert.ok(excerptMatch !== null, 'should contain quoted excerpt');
|
|
299
|
+
assert.ok(excerptMatch[1].length <= 200, 'excerpt should be ≤ 200 chars');
|
|
300
|
+
});
|
|
301
|
+
test('omits tier section when that tier is empty', () => {
|
|
302
|
+
const fact = makeFact({ confidence: 0.5, decayRate: DecayRate.slow, ageInDays: 0, now: NOW });
|
|
303
|
+
const ctx = {
|
|
304
|
+
highConfidence: [],
|
|
305
|
+
mediumConfidence: [{ fact, score: 0.5, ageInDays: 0 }],
|
|
306
|
+
lowConfidence: [],
|
|
307
|
+
relatedConversations: [],
|
|
308
|
+
};
|
|
309
|
+
const output = formatContextBlock(ctx);
|
|
310
|
+
assert.ok(!output.includes('## High confidence'), 'no high section when empty');
|
|
311
|
+
assert.ok(output.includes('## Medium confidence'), 'medium section present');
|
|
312
|
+
assert.ok(!output.includes('## Low confidence'), 'no low section when empty');
|
|
313
|
+
assert.ok(!output.includes('## Related conversations'), 'no raw section when empty');
|
|
314
|
+
});
|
|
315
|
+
});
|
|
316
|
+
// ─── Cross-session integration test ─────────────────────────────────────────
|
|
317
|
+
// Uses a real LocalStore with store.store() (no embedder needed).
|
|
318
|
+
// Verifies that facts from session A appear when querying in session B context.
|
|
319
|
+
describe('Cross-session integration', () => {
|
|
320
|
+
const dbPath = join(tmpdir(), `plumb-readpath-integration-${Date.now()}.db`);
|
|
321
|
+
const store = new LocalStore({ dbPath, userId: 'readpath-test-user' });
|
|
322
|
+
after(() => {
|
|
323
|
+
store.close();
|
|
324
|
+
rmSync(dbPath, { force: true });
|
|
325
|
+
});
|
|
326
|
+
test('facts from session A returned in session B context', async () => {
|
|
327
|
+
const now = new Date();
|
|
328
|
+
// Ingest facts from session A.
|
|
329
|
+
await store.store({
|
|
330
|
+
subject: 'user',
|
|
331
|
+
predicate: 'prefers',
|
|
332
|
+
object: 'TypeScript',
|
|
333
|
+
confidence: 0.95,
|
|
334
|
+
decayRate: DecayRate.slow,
|
|
335
|
+
timestamp: now,
|
|
336
|
+
sourceSessionId: 'session-A',
|
|
337
|
+
sourceSessionLabel: 'tech-session',
|
|
338
|
+
});
|
|
339
|
+
await store.store({
|
|
340
|
+
subject: 'user',
|
|
341
|
+
predicate: 'is building',
|
|
342
|
+
object: 'Plumb memory system',
|
|
343
|
+
confidence: 0.9,
|
|
344
|
+
decayRate: DecayRate.slow,
|
|
345
|
+
timestamp: now,
|
|
346
|
+
sourceSessionId: 'session-A',
|
|
347
|
+
sourceSessionLabel: 'tech-session',
|
|
348
|
+
});
|
|
349
|
+
// Query from session B context — no session filter, so session A facts must appear.
|
|
350
|
+
// Use 'TypeScript' as query keyword (LIKE search in current store.search impl).
|
|
351
|
+
const ctx = await buildMemoryContext('TypeScript', store, { now });
|
|
352
|
+
const allFacts = [
|
|
353
|
+
...ctx.highConfidence,
|
|
354
|
+
...ctx.mediumConfidence,
|
|
355
|
+
...ctx.lowConfidence,
|
|
356
|
+
];
|
|
357
|
+
// At least one fact from session A must be in the results.
|
|
358
|
+
const sessionAFact = allFacts.find((sf) => sf.fact.sourceSessionId === 'session-A');
|
|
359
|
+
assert.ok(sessionAFact !== undefined, 'session A fact must appear in cross-session query');
|
|
360
|
+
// Verify provenance fields are populated.
|
|
361
|
+
assert.equal(sessionAFact.fact.sourceSessionLabel, 'tech-session', 'session label must be preserved in provenance');
|
|
362
|
+
assert.ok(sessionAFact.score > 0, 'score must be positive');
|
|
363
|
+
assert.ok(sessionAFact.ageInDays >= 0, 'ageInDays must be non-negative');
|
|
364
|
+
// Verify the formatted output includes provenance.
|
|
365
|
+
const formatted = formatContextBlock(ctx);
|
|
366
|
+
if (formatted !== '') {
|
|
367
|
+
assert.ok(formatted.startsWith('[MEMORY CONTEXT]'), 'output must start with block header');
|
|
368
|
+
assert.ok(formatted.includes('tech-session'), 'session label must appear in formatted output');
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
test('buildMemoryContext + formatContextBlock: full pipeline smoke test', async () => {
|
|
372
|
+
const now = new Date();
|
|
373
|
+
await store.store({
|
|
374
|
+
subject: 'user',
|
|
375
|
+
predicate: 'uses',
|
|
376
|
+
object: 'dark mode',
|
|
377
|
+
confidence: 0.85,
|
|
378
|
+
decayRate: DecayRate.slow,
|
|
379
|
+
timestamp: now,
|
|
380
|
+
sourceSessionId: 'session-B',
|
|
381
|
+
sessionLabel: 'settings-session',
|
|
382
|
+
});
|
|
383
|
+
const ctx = await buildMemoryContext('dark mode', store, { now });
|
|
384
|
+
const output = formatContextBlock(ctx);
|
|
385
|
+
// Either we got results (block present) or the keyword didn't match (empty) —
|
|
386
|
+
// both are valid since store.search() uses LIKE and 'dark mode' should match.
|
|
387
|
+
if (output !== '') {
|
|
388
|
+
assert.ok(output.includes('[MEMORY CONTEXT]'), 'block header present');
|
|
389
|
+
}
|
|
390
|
+
// No throw means pipeline ran end-to-end without error.
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
//# sourceMappingURL=read-path.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-path.test.js","sourceRoot":"","sources":["../src/read-path.test.ts"],"names":[],"mappings":"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"}
|