@getplumb/core 0.4.3 → 0.4.5
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/dist/chunker.d.ts +2 -27
- package/dist/chunker.d.ts.map +1 -1
- package/dist/chunker.js +2 -36
- package/dist/chunker.js.map +1 -1
- package/dist/context-builder.d.ts +18 -6
- package/dist/context-builder.d.ts.map +1 -1
- package/dist/context-builder.js +48 -24
- package/dist/context-builder.js.map +1 -1
- package/dist/embedder.d.ts.map +1 -1
- package/dist/embedder.js +6 -0
- package/dist/embedder.js.map +1 -1
- package/dist/index.d.ts +4 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/dist/local-store.d.ts +24 -31
- package/dist/local-store.d.ts.map +1 -1
- package/dist/local-store.js +81 -331
- package/dist/local-store.js.map +1 -1
- package/dist/memory-facts-search.d.ts +33 -0
- package/dist/memory-facts-search.d.ts.map +1 -0
- package/dist/memory-facts-search.js +143 -0
- package/dist/memory-facts-search.js.map +1 -0
- package/dist/read-path.d.ts +22 -13
- package/dist/read-path.d.ts.map +1 -1
- package/dist/read-path.js +19 -15
- package/dist/read-path.js.map +1 -1
- package/dist/schema.d.ts +13 -8
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +63 -83
- package/dist/schema.js.map +1 -1
- package/dist/scorer.d.ts +12 -10
- package/dist/scorer.d.ts.map +1 -1
- package/dist/scorer.js +13 -10
- package/dist/scorer.js.map +1 -1
- package/dist/store.d.ts +1 -6
- package/dist/store.d.ts.map +1 -1
- package/dist/types.d.ts +27 -1
- package/dist/types.d.ts.map +1 -1
- package/dist/wasm-db.d.ts +17 -20
- package/dist/wasm-db.d.ts.map +1 -1
- package/dist/wasm-db.js +51 -56
- package/dist/wasm-db.js.map +1 -1
- package/package.json +5 -6
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory facts hybrid search (Layer 2 retrieval).
|
|
3
|
+
*
|
|
4
|
+
* Pipeline (same as raw-log-search, but for memory_facts table):
|
|
5
|
+
* 1. BM25 keyword search over memory_facts content
|
|
6
|
+
* 2. KNN vector search via JS cosine similarity
|
|
7
|
+
* 3. Reciprocal Rank Fusion (RRF, k=60) merges both ranked lists
|
|
8
|
+
* 4. Apply MEMORY_FACT_BOOST (2.0×) to RRF scores
|
|
9
|
+
* 5. Return top-k by boosted score
|
|
10
|
+
*
|
|
11
|
+
* Search is cross-session: no session filter is applied.
|
|
12
|
+
* The caller (LocalStore) passes its internal db handle — no separate DB connection.
|
|
13
|
+
*/
|
|
14
|
+
import { Bm25 } from './bm25.js';
|
|
15
|
+
import { embedQuery } from './embedder.js';
|
|
16
|
+
import { knnSearch, deserializeEmbedding } from './vector-search.js';
|
|
17
|
+
import { scoreMemoryFact } from './scorer.js';
|
|
18
|
+
// RRF constant (standard k=60; higher = less weight on top-1 rank).
|
|
19
|
+
const RRF_K = 60;
|
|
20
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
21
|
+
/**
|
|
22
|
+
* Merge two ranked lists via Reciprocal Rank Fusion.
|
|
23
|
+
* Each list entry is [id, score] ordered by descending relevance (rank 1 = index 0).
|
|
24
|
+
* Returns a map of id → rrf_score.
|
|
25
|
+
*/
|
|
26
|
+
function rrf(vecRanked, bm25Ranked) {
|
|
27
|
+
const scores = new Map();
|
|
28
|
+
for (let rank = 0; rank < vecRanked.length; rank++) {
|
|
29
|
+
const id = vecRanked[rank]?.[0];
|
|
30
|
+
if (id === undefined)
|
|
31
|
+
continue;
|
|
32
|
+
scores.set(id, (scores.get(id) ?? 0) + 1 / (RRF_K + rank + 1));
|
|
33
|
+
}
|
|
34
|
+
for (let rank = 0; rank < bm25Ranked.length; rank++) {
|
|
35
|
+
const id = bm25Ranked[rank]?.[0];
|
|
36
|
+
if (id === undefined)
|
|
37
|
+
continue;
|
|
38
|
+
scores.set(id, (scores.get(id) ?? 0) + 1 / (RRF_K + rank + 1));
|
|
39
|
+
}
|
|
40
|
+
return scores;
|
|
41
|
+
}
|
|
42
|
+
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
43
|
+
/**
|
|
44
|
+
* Hybrid search over memory_facts.
|
|
45
|
+
*
|
|
46
|
+
* @param db The WASM SQLite Database instance
|
|
47
|
+
* @param userId Scopes the search to this user's data
|
|
48
|
+
* @param query Natural language query string
|
|
49
|
+
* @param limit Number of results to return (default 10)
|
|
50
|
+
*/
|
|
51
|
+
export async function searchMemoryFacts(db, userId, query, limit = 10) {
|
|
52
|
+
// ── 1. Fetch all memory_facts rows (non-deleted, with embeddings) ────────
|
|
53
|
+
const stmt = db.prepare(`SELECT id, content, source_session_id, source_session_label, tags, created_at, vec_rowid
|
|
54
|
+
FROM memory_facts
|
|
55
|
+
WHERE user_id = ? AND deleted_at IS NULL AND embed_status = 'done'
|
|
56
|
+
ORDER BY created_at DESC`);
|
|
57
|
+
stmt.bind([userId]);
|
|
58
|
+
const allRows = [];
|
|
59
|
+
while (stmt.step()) {
|
|
60
|
+
allRows.push(stmt.get({}));
|
|
61
|
+
}
|
|
62
|
+
stmt.finalize();
|
|
63
|
+
if (allRows.length === 0)
|
|
64
|
+
return [];
|
|
65
|
+
const idToRow = new Map(allRows.map((r) => [r.id, r]));
|
|
66
|
+
// ── 2. BM25 search ───────────────────────────────────────────────────────
|
|
67
|
+
const corpus = allRows.map((r) => r.content);
|
|
68
|
+
const bm25 = new Bm25(corpus);
|
|
69
|
+
const bm25RawScores = bm25.scores(query);
|
|
70
|
+
const bm25Ranked = allRows
|
|
71
|
+
.map((r, i) => [r.id, bm25RawScores[i] ?? 0])
|
|
72
|
+
.sort((a, b) => b[1] - a[1]);
|
|
73
|
+
// ── 3. Vector search via JS cosine similarity ───────────────────────────
|
|
74
|
+
const queryVec = await embedQuery(query);
|
|
75
|
+
// Fetch all embeddings from vec_raw_log (memory_facts use same table)
|
|
76
|
+
const vecRowids = allRows
|
|
77
|
+
.filter((r) => r.vec_rowid !== null)
|
|
78
|
+
.map((r) => r.vec_rowid);
|
|
79
|
+
if (vecRowids.length === 0) {
|
|
80
|
+
// No embeddings available — fall back to BM25 only
|
|
81
|
+
const bm25Only = bm25Ranked
|
|
82
|
+
.slice(0, limit)
|
|
83
|
+
.map(([id, score]) => {
|
|
84
|
+
const row = idToRow.get(id);
|
|
85
|
+
const boostedScore = scoreMemoryFact(score);
|
|
86
|
+
return {
|
|
87
|
+
content: row.content,
|
|
88
|
+
source_session_id: row.source_session_id,
|
|
89
|
+
source_session_label: row.source_session_label,
|
|
90
|
+
created_at: row.created_at,
|
|
91
|
+
tags: row.tags ? JSON.parse(row.tags) : null,
|
|
92
|
+
final_score: boostedScore,
|
|
93
|
+
};
|
|
94
|
+
});
|
|
95
|
+
return bm25Only;
|
|
96
|
+
}
|
|
97
|
+
// Fetch embeddings for these vec_rowids
|
|
98
|
+
const placeholders = vecRowids.map(() => '?').join(',');
|
|
99
|
+
const vecStmt = db.prepare(`SELECT id, embedding FROM vec_raw_log WHERE id IN (${placeholders})`);
|
|
100
|
+
vecStmt.bind(vecRowids);
|
|
101
|
+
const vecCorpus = [];
|
|
102
|
+
while (vecStmt.step()) {
|
|
103
|
+
const row = vecStmt.get({});
|
|
104
|
+
vecCorpus.push({
|
|
105
|
+
id: row.id,
|
|
106
|
+
embedding: deserializeEmbedding(row.embedding),
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
vecStmt.finalize();
|
|
110
|
+
// Perform KNN search
|
|
111
|
+
const vecFetchLimit = Math.min(allRows.length, Math.max(limit * 3, 50));
|
|
112
|
+
const vecResults = knnSearch(queryVec, vecCorpus, vecFetchLimit);
|
|
113
|
+
// Map vec_raw_log ids back to memory_facts ids
|
|
114
|
+
const vecRanked = [];
|
|
115
|
+
for (const vecResult of vecResults) {
|
|
116
|
+
const factRow = allRows.find((r) => r.vec_rowid === vecResult.id);
|
|
117
|
+
if (factRow !== undefined) {
|
|
118
|
+
vecRanked.push([factRow.id, 1 - vecResult.distance]);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// ── 4. RRF merge ────────────────────────────────────────────────────────
|
|
122
|
+
const rrfScores = rrf(vecRanked, bm25Ranked);
|
|
123
|
+
// ── 5. Apply MEMORY_FACT_BOOST ──────────────────────────────────────────
|
|
124
|
+
const boostedScores = [];
|
|
125
|
+
for (const [id, rrfScore] of rrfScores) {
|
|
126
|
+
const boosted = scoreMemoryFact(rrfScore);
|
|
127
|
+
boostedScores.push([id, boosted]);
|
|
128
|
+
}
|
|
129
|
+
boostedScores.sort((a, b) => b[1] - a[1]);
|
|
130
|
+
// ── 6. Build output ─────────────────────────────────────────────────────
|
|
131
|
+
return boostedScores.slice(0, limit).map(([id, finalScore]) => {
|
|
132
|
+
const row = idToRow.get(id);
|
|
133
|
+
return {
|
|
134
|
+
content: row.content,
|
|
135
|
+
source_session_id: row.source_session_id,
|
|
136
|
+
source_session_label: row.source_session_label,
|
|
137
|
+
created_at: row.created_at,
|
|
138
|
+
tags: row.tags ? JSON.parse(row.tags) : null,
|
|
139
|
+
final_score: finalScore,
|
|
140
|
+
};
|
|
141
|
+
});
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=memory-facts-search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"memory-facts-search.js","sourceRoot":"","sources":["../src/memory-facts-search.ts"],"names":[],"mappings":"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"}
|
package/dist/read-path.d.ts
CHANGED
|
@@ -1,39 +1,48 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Read path — Layer
|
|
2
|
+
* Read path — Layer 2 (memory facts) retrieval.
|
|
3
3
|
*
|
|
4
4
|
* buildMemoryContext() is called before every agent response. It queries
|
|
5
|
-
*
|
|
5
|
+
* memory_facts, applies score boosting, and returns a MemoryContext ready
|
|
6
6
|
* for formatContextBlock().
|
|
7
7
|
*
|
|
8
8
|
* Search is always cross-session — no session filter is applied.
|
|
9
9
|
*/
|
|
10
|
-
import type {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
readonly
|
|
14
|
-
readonly
|
|
10
|
+
import type { MemoryFactSearchResult } from './local-store.js';
|
|
11
|
+
/** A memory fact chunk with metadata and boosted score. */
|
|
12
|
+
export interface MemoryFactChunk {
|
|
13
|
+
readonly content: string;
|
|
14
|
+
readonly sourceSessionId: string;
|
|
15
|
+
readonly sourceSessionLabel: string | null;
|
|
15
16
|
readonly timestamp: Date;
|
|
16
|
-
|
|
17
|
+
readonly tags: readonly string[] | null;
|
|
18
|
+
/** Final score from hybrid search with MEMORY_FACT_BOOST applied. */
|
|
17
19
|
readonly score: number;
|
|
18
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Memory context returned by buildMemoryContext().
|
|
23
|
+
*
|
|
24
|
+
* relatedMemories holds curated memory facts (high-signal).
|
|
25
|
+
*/
|
|
19
26
|
export interface MemoryContext {
|
|
20
|
-
readonly
|
|
27
|
+
readonly relatedMemories: MemoryFactChunk[];
|
|
21
28
|
}
|
|
22
29
|
export interface ReadPathOptions {
|
|
23
|
-
/** Max
|
|
24
|
-
|
|
30
|
+
/** Max memory facts returned. Default: 5. */
|
|
31
|
+
maxMemoryFacts?: number;
|
|
25
32
|
}
|
|
26
33
|
/**
|
|
27
34
|
* Minimal store interface required by the read path.
|
|
28
35
|
* LocalStore satisfies this; tests can pass a mock.
|
|
29
36
|
*/
|
|
30
37
|
export interface ReadPathStore {
|
|
31
|
-
|
|
38
|
+
/** Layer 2: hybrid search over curated memory facts. */
|
|
39
|
+
searchMemoryFacts(query: string, limit?: number): Promise<readonly MemoryFactSearchResult[]>;
|
|
32
40
|
}
|
|
33
41
|
/**
|
|
34
42
|
* Build a structured MemoryContext for a given query.
|
|
35
43
|
*
|
|
36
|
-
* Queries Layer
|
|
44
|
+
* Queries Layer 2 (memory facts hybrid search).
|
|
45
|
+
* Memory facts get MEMORY_FACT_BOOST (2.0×) applied to their scores.
|
|
37
46
|
*
|
|
38
47
|
* @param query Natural language query (the incoming user message or context).
|
|
39
48
|
* @param store Any store implementing ReadPathStore (typically LocalStore).
|
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;AAEH,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"read-path.d.ts","sourceRoot":"","sources":["../src/read-path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAI/D,2DAA2D;AAC3D,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAAC;IACxC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,eAAe,EAAE,eAAe,EAAE,CAAC;CAC7C;AAED,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,wDAAwD;IACxD,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,sBAAsB,EAAE,CAAC,CAAC;CAC9F;AAID;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,aAAa,EACpB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,aAAa,CAAC,CAuBxB"}
|
package/dist/read-path.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Read path — Layer
|
|
2
|
+
* Read path — Layer 2 (memory facts) retrieval.
|
|
3
3
|
*
|
|
4
4
|
* buildMemoryContext() is called before every agent response. It queries
|
|
5
|
-
*
|
|
5
|
+
* memory_facts, applies score boosting, and returns a MemoryContext ready
|
|
6
6
|
* for formatContextBlock().
|
|
7
7
|
*
|
|
8
8
|
* Search is always cross-session — no session filter is applied.
|
|
@@ -11,27 +11,31 @@
|
|
|
11
11
|
/**
|
|
12
12
|
* Build a structured MemoryContext for a given query.
|
|
13
13
|
*
|
|
14
|
-
* Queries Layer
|
|
14
|
+
* Queries Layer 2 (memory facts hybrid search).
|
|
15
|
+
* Memory facts get MEMORY_FACT_BOOST (2.0×) applied to their scores.
|
|
15
16
|
*
|
|
16
17
|
* @param query Natural language query (the incoming user message or context).
|
|
17
18
|
* @param store Any store implementing ReadPathStore (typically LocalStore).
|
|
18
19
|
* @param options Optional limits.
|
|
19
20
|
*/
|
|
20
21
|
export async function buildMemoryContext(query, store, options) {
|
|
21
|
-
const
|
|
22
|
-
const
|
|
23
|
-
// ── Query Layer
|
|
24
|
-
const
|
|
25
|
-
// ── Build
|
|
26
|
-
const
|
|
27
|
-
.slice(0,
|
|
22
|
+
const maxMemoryFacts = options?.maxMemoryFacts ?? 5;
|
|
23
|
+
const memoryCandidateLimit = maxMemoryFacts * 2;
|
|
24
|
+
// ── Query Layer 2 (memory facts) ─────────────────────────────────────────
|
|
25
|
+
const memoryFactResults = await store.searchMemoryFacts(query, memoryCandidateLimit);
|
|
26
|
+
// ── Build memory fact chunks (scores already have MEMORY_FACT_BOOST applied) ─
|
|
27
|
+
const relatedMemories = memoryFactResults
|
|
28
|
+
.slice(0, maxMemoryFacts)
|
|
28
29
|
.map((r) => ({
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
timestamp: new Date(r.
|
|
30
|
+
content: r.content,
|
|
31
|
+
sourceSessionId: r.source_session_id,
|
|
32
|
+
sourceSessionLabel: r.source_session_label,
|
|
33
|
+
timestamp: new Date(r.created_at),
|
|
34
|
+
tags: r.tags,
|
|
33
35
|
score: r.final_score,
|
|
34
36
|
}));
|
|
35
|
-
return {
|
|
37
|
+
return {
|
|
38
|
+
relatedMemories,
|
|
39
|
+
};
|
|
36
40
|
}
|
|
37
41
|
//# 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;AAwCH,iFAAiF;AAEjF;;;;;;;;;GASG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,KAAa,EACb,KAAoB,EACpB,OAAyB;IAEzB,MAAM,cAAc,GAAG,OAAO,EAAE,cAAc,IAAI,CAAC,CAAC;IAEpD,MAAM,oBAAoB,GAAG,cAAc,GAAG,CAAC,CAAC;IAEhD,4EAA4E;IAC5E,MAAM,iBAAiB,GAAG,MAAM,KAAK,CAAC,iBAAiB,CAAC,KAAK,EAAE,oBAAoB,CAAC,CAAC;IAErF,gFAAgF;IAChF,MAAM,eAAe,GAAsB,iBAAiB;SACzD,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC;SACxB,GAAG,CAAC,CAAC,CAAyB,EAAE,EAAE,CAAC,CAAC;QACnC,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,eAAe,EAAE,CAAC,CAAC,iBAAiB;QACpC,kBAAkB,EAAE,CAAC,CAAC,oBAAoB;QAC1C,SAAS,EAAE,IAAI,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC;QACjC,IAAI,EAAE,CAAC,CAAC,IAAI;QACZ,KAAK,EAAE,CAAC,CAAC,WAAW;KACrB,CAAC,CAAC,CAAC;IAEN,OAAO;QACL,eAAe;KAChB,CAAC;AACJ,CAAC"}
|
package/dist/schema.d.ts
CHANGED
|
@@ -1,20 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SQLite schema for Plumb LocalStore.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
4
|
+
* Tables:
|
|
5
|
+
* - memory_facts: Curated facts written by the agent via plumb_remember
|
|
6
|
+
* - vec_raw_log: Embedding vectors for memory_facts (keyed by vec_rowid)
|
|
7
|
+
* - nudge_log: One-time upgrade prompt tracking
|
|
6
8
|
*
|
|
7
9
|
* Design principles:
|
|
8
10
|
* - Cross-session by design: session info stored as metadata, not as a boundary
|
|
9
|
-
* - Indexes on high-cardinality query axes: user_id,
|
|
11
|
+
* - Indexes on high-cardinality query axes: user_id, embed_status
|
|
10
12
|
*/
|
|
11
|
-
export declare const CREATE_RAW_LOG_TABLE = "\n CREATE TABLE IF NOT EXISTS raw_log (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL,\n session_id TEXT NOT NULL,\n session_label TEXT,\n user_message TEXT NOT NULL,\n agent_response TEXT NOT NULL,\n timestamp TEXT NOT NULL,\n source TEXT NOT NULL,\n chunk_text TEXT NOT NULL,\n chunk_index INTEGER NOT NULL,\n vec_rowid INTEGER,\n content_hash TEXT,\n embed_status TEXT NOT NULL DEFAULT 'pending',\n embed_error TEXT,\n embed_model TEXT,\n parent_id TEXT REFERENCES raw_log(id),\n UNIQUE(user_id, content_hash)\n )\n";
|
|
12
|
-
export declare const CREATE_RAW_LOG_INDEXES: string[];
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* Memory facts table for curated, high-signal facts written by Terra.
|
|
15
|
+
* Each fact is a short, dense piece of information stored as a single chunk.
|
|
16
|
+
*
|
|
17
|
+
* confidence (0–1) and decay_rate ('slow'|'medium'|'fast') drive scoring.
|
|
18
|
+
* source_session_label is optional human-readable session name for provenance.
|
|
19
|
+
* vec_rowid links to vec_raw_log for vector similarity search.
|
|
16
20
|
*/
|
|
17
|
-
export declare const
|
|
21
|
+
export declare const CREATE_MEMORY_FACTS_TABLE = "\n CREATE TABLE IF NOT EXISTS memory_facts (\n id TEXT PRIMARY KEY,\n user_id TEXT NOT NULL,\n content TEXT NOT NULL,\n confidence REAL NOT NULL DEFAULT 0.9,\n decay_rate TEXT NOT NULL DEFAULT 'slow',\n source_session_id TEXT NOT NULL,\n source_session_label TEXT,\n tags TEXT,\n created_at TEXT NOT NULL,\n deleted_at TEXT,\n embed_status TEXT NOT NULL DEFAULT 'pending',\n embed_error TEXT,\n embed_model TEXT,\n vec_rowid INTEGER\n )\n";
|
|
22
|
+
export declare const CREATE_MEMORY_FACTS_INDEXES: string[];
|
|
18
23
|
/**
|
|
19
24
|
* Nudge log table for tracking one-time upgrade prompts.
|
|
20
25
|
* Each trigger type fires exactly once per install.
|
package/dist/schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,mnBAiBrC,CAAC;AAEF,eAAO,MAAM,2BAA2B,UAGvC,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,8JAMlC,CAAC;AAEF,wBAAgB,WAAW,CAAC,EAAE,EAAE,OAAO,cAAc,EAAE,MAAM,GAAG,IAAI,CA6CnE"}
|
package/dist/schema.js
CHANGED
|
@@ -1,50 +1,45 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SQLite schema for Plumb LocalStore.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* -
|
|
4
|
+
* Tables:
|
|
5
|
+
* - memory_facts: Curated facts written by the agent via plumb_remember
|
|
6
|
+
* - vec_raw_log: Embedding vectors for memory_facts (keyed by vec_rowid)
|
|
7
|
+
* - nudge_log: One-time upgrade prompt tracking
|
|
6
8
|
*
|
|
7
9
|
* Design principles:
|
|
8
10
|
* - Cross-session by design: session info stored as metadata, not as a boundary
|
|
9
|
-
* - Indexes on high-cardinality query axes: user_id,
|
|
11
|
+
* - Indexes on high-cardinality query axes: user_id, embed_status
|
|
10
12
|
*/
|
|
11
|
-
export const CREATE_RAW_LOG_TABLE = `
|
|
12
|
-
CREATE TABLE IF NOT EXISTS raw_log (
|
|
13
|
-
id TEXT PRIMARY KEY,
|
|
14
|
-
user_id TEXT NOT NULL,
|
|
15
|
-
session_id TEXT NOT NULL,
|
|
16
|
-
session_label TEXT,
|
|
17
|
-
user_message TEXT NOT NULL,
|
|
18
|
-
agent_response TEXT NOT NULL,
|
|
19
|
-
timestamp TEXT NOT NULL,
|
|
20
|
-
source TEXT NOT NULL,
|
|
21
|
-
chunk_text TEXT NOT NULL,
|
|
22
|
-
chunk_index INTEGER NOT NULL,
|
|
23
|
-
vec_rowid INTEGER,
|
|
24
|
-
content_hash TEXT,
|
|
25
|
-
embed_status TEXT NOT NULL DEFAULT 'pending',
|
|
26
|
-
embed_error TEXT,
|
|
27
|
-
embed_model TEXT,
|
|
28
|
-
parent_id TEXT REFERENCES raw_log(id),
|
|
29
|
-
UNIQUE(user_id, content_hash)
|
|
30
|
-
)
|
|
31
|
-
`;
|
|
32
|
-
export const CREATE_RAW_LOG_INDEXES = [
|
|
33
|
-
`CREATE INDEX IF NOT EXISTS idx_raw_log_user_id ON raw_log (user_id)`,
|
|
34
|
-
`CREATE INDEX IF NOT EXISTS idx_raw_log_session_id ON raw_log (session_id)`,
|
|
35
|
-
`CREATE INDEX IF NOT EXISTS idx_raw_log_timestamp ON raw_log (timestamp)`,
|
|
36
|
-
`CREATE INDEX IF NOT EXISTS idx_raw_log_parent_id ON raw_log (parent_id)`,
|
|
37
|
-
];
|
|
38
13
|
/**
|
|
39
|
-
*
|
|
40
|
-
*
|
|
14
|
+
* Memory facts table for curated, high-signal facts written by Terra.
|
|
15
|
+
* Each fact is a short, dense piece of information stored as a single chunk.
|
|
16
|
+
*
|
|
17
|
+
* confidence (0–1) and decay_rate ('slow'|'medium'|'fast') drive scoring.
|
|
18
|
+
* source_session_label is optional human-readable session name for provenance.
|
|
19
|
+
* vec_rowid links to vec_raw_log for vector similarity search.
|
|
41
20
|
*/
|
|
42
|
-
export const
|
|
43
|
-
CREATE TABLE IF NOT EXISTS
|
|
44
|
-
id
|
|
45
|
-
|
|
21
|
+
export const CREATE_MEMORY_FACTS_TABLE = `
|
|
22
|
+
CREATE TABLE IF NOT EXISTS memory_facts (
|
|
23
|
+
id TEXT PRIMARY KEY,
|
|
24
|
+
user_id TEXT NOT NULL,
|
|
25
|
+
content TEXT NOT NULL,
|
|
26
|
+
confidence REAL NOT NULL DEFAULT 0.9,
|
|
27
|
+
decay_rate TEXT NOT NULL DEFAULT 'slow',
|
|
28
|
+
source_session_id TEXT NOT NULL,
|
|
29
|
+
source_session_label TEXT,
|
|
30
|
+
tags TEXT,
|
|
31
|
+
created_at TEXT NOT NULL,
|
|
32
|
+
deleted_at TEXT,
|
|
33
|
+
embed_status TEXT NOT NULL DEFAULT 'pending',
|
|
34
|
+
embed_error TEXT,
|
|
35
|
+
embed_model TEXT,
|
|
36
|
+
vec_rowid INTEGER
|
|
46
37
|
)
|
|
47
38
|
`;
|
|
39
|
+
export const CREATE_MEMORY_FACTS_INDEXES = [
|
|
40
|
+
`CREATE INDEX IF NOT EXISTS idx_memory_facts_user_id ON memory_facts (user_id)`,
|
|
41
|
+
`CREATE INDEX IF NOT EXISTS idx_memory_facts_embed_status ON memory_facts (embed_status)`,
|
|
42
|
+
];
|
|
48
43
|
/**
|
|
49
44
|
* Nudge log table for tracking one-time upgrade prompts.
|
|
50
45
|
* Each trigger type fires exactly once per install.
|
|
@@ -57,24 +52,6 @@ export const CREATE_NUDGE_LOG_TABLE = `
|
|
|
57
52
|
)
|
|
58
53
|
`;
|
|
59
54
|
export function applySchema(db) {
|
|
60
|
-
db.exec(CREATE_RAW_LOG_TABLE);
|
|
61
|
-
for (const idx of CREATE_RAW_LOG_INDEXES) {
|
|
62
|
-
db.exec(idx);
|
|
63
|
-
}
|
|
64
|
-
db.exec(CREATE_VEC_RAW_LOG);
|
|
65
|
-
// Conditional migration: add content_hash column to raw_log if it doesn't exist yet.
|
|
66
|
-
const rawLogColumns = db.exec({
|
|
67
|
-
sql: 'PRAGMA table_info(raw_log)',
|
|
68
|
-
rowMode: 'object',
|
|
69
|
-
returnValue: 'resultRows',
|
|
70
|
-
});
|
|
71
|
-
const hasContentHash = rawLogColumns.some((c) => c.name === 'content_hash');
|
|
72
|
-
if (!hasContentHash) {
|
|
73
|
-
db.exec('ALTER TABLE raw_log ADD COLUMN content_hash TEXT');
|
|
74
|
-
// Create unique constraint on (user_id, content_hash).
|
|
75
|
-
// SQLite UNIQUE constraints ignore NULL values, so existing rows with NULL won't conflict.
|
|
76
|
-
db.exec('CREATE UNIQUE INDEX IF NOT EXISTS idx_raw_log_content_hash ON raw_log(user_id, content_hash)');
|
|
77
|
-
}
|
|
78
55
|
// Conditional migration: create nudge_log table if it doesn't exist yet.
|
|
79
56
|
const tables = db.exec({
|
|
80
57
|
sql: `SELECT name FROM sqlite_master WHERE type='table' AND name='nudge_log'`,
|
|
@@ -84,39 +61,42 @@ export function applySchema(db) {
|
|
|
84
61
|
if (tables.length === 0) {
|
|
85
62
|
db.exec(CREATE_NUDGE_LOG_TABLE);
|
|
86
63
|
}
|
|
87
|
-
// T-
|
|
88
|
-
const
|
|
89
|
-
sql: '
|
|
64
|
+
// T-118: Create memory_facts table if it doesn't exist (for curated facts from agent).
|
|
65
|
+
const memoryFactsTables = db.exec({
|
|
66
|
+
sql: `SELECT name FROM sqlite_master WHERE type='table' AND name='memory_facts'`,
|
|
90
67
|
rowMode: 'object',
|
|
91
68
|
returnValue: 'resultRows',
|
|
92
69
|
});
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
db.exec('ALTER TABLE raw_log ADD COLUMN embed_error TEXT');
|
|
99
|
-
db.exec('ALTER TABLE raw_log ADD COLUMN embed_model TEXT');
|
|
100
|
-
// Backfill embed_status for existing rows based on vec_rowid.
|
|
101
|
-
// Rows with vec_rowid already set -> embed_status='done', embed_model='Xenova/bge-small-en-v1.5'
|
|
102
|
-
db.exec(`
|
|
103
|
-
UPDATE raw_log
|
|
104
|
-
SET embed_status = 'done', embed_model = 'Xenova/bge-small-en-v1.5'
|
|
105
|
-
WHERE vec_rowid IS NOT NULL
|
|
106
|
-
`);
|
|
107
|
-
// Rows with vec_rowid=NULL remain embed_status='pending' (from DEFAULT).
|
|
70
|
+
if (memoryFactsTables.length === 0) {
|
|
71
|
+
db.exec(CREATE_MEMORY_FACTS_TABLE);
|
|
72
|
+
for (const idx of CREATE_MEMORY_FACTS_INDEXES) {
|
|
73
|
+
db.exec(idx);
|
|
74
|
+
}
|
|
108
75
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
76
|
+
else {
|
|
77
|
+
// Conditional migration: add structured fact columns to existing memory_facts table.
|
|
78
|
+
const memFactColumns = db.exec({
|
|
79
|
+
sql: 'PRAGMA table_info(memory_facts)',
|
|
80
|
+
rowMode: 'object',
|
|
81
|
+
returnValue: 'resultRows',
|
|
82
|
+
});
|
|
83
|
+
const memFactColNames = new Set(memFactColumns.map((c) => c.name));
|
|
84
|
+
if (!memFactColNames.has('confidence'))
|
|
85
|
+
db.exec(`ALTER TABLE memory_facts ADD COLUMN confidence REAL NOT NULL DEFAULT 0.9`);
|
|
86
|
+
if (!memFactColNames.has('decay_rate'))
|
|
87
|
+
db.exec(`ALTER TABLE memory_facts ADD COLUMN decay_rate TEXT NOT NULL DEFAULT 'slow'`);
|
|
88
|
+
if (!memFactColNames.has('source_session_label'))
|
|
89
|
+
db.exec(`ALTER TABLE memory_facts ADD COLUMN source_session_label TEXT`);
|
|
90
|
+
if (!memFactColNames.has('deleted_at'))
|
|
91
|
+
db.exec(`ALTER TABLE memory_facts ADD COLUMN deleted_at TEXT`);
|
|
120
92
|
}
|
|
93
|
+
// T-128: Share vec_raw_log for memory_facts embeddings (table may exist from old raw_log usage)
|
|
94
|
+
// Create only if it doesn't exist - this allows existing DBs to continue working
|
|
95
|
+
db.exec(`
|
|
96
|
+
CREATE TABLE IF NOT EXISTS vec_raw_log (
|
|
97
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
98
|
+
embedding TEXT NOT NULL
|
|
99
|
+
)
|
|
100
|
+
`);
|
|
121
101
|
}
|
|
122
102
|
//# sourceMappingURL=schema.js.map
|
package/dist/schema.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG;;;;;;;;;;;;;;;;;CAiBxC,CAAC;AAEF,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,+EAA+E;IAC/E,yFAAyF;CAC1F,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG;;;;;;CAMrC,CAAC;AAEF,MAAM,UAAU,WAAW,CAAC,EAAiC;IAC3D,yEAAyE;IACzE,MAAM,MAAM,GAAG,EAAE,CAAC,IAAI,CAAC;QACrB,GAAG,EAAE,wEAAwE;QAC7E,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,YAAY;KAC1B,CAA4B,CAAC;IAC9B,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,IAAI,CAAC,sBAAsB,CAAC,CAAC;IAClC,CAAC;IAED,uFAAuF;IACvF,MAAM,iBAAiB,GAAG,EAAE,CAAC,IAAI,CAAC;QAChC,GAAG,EAAE,2EAA2E;QAChF,OAAO,EAAE,QAAQ;QACjB,WAAW,EAAE,YAAY;KAC1B,CAA4B,CAAC;IAC9B,IAAI,iBAAiB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnC,EAAE,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACnC,KAAK,MAAM,GAAG,IAAI,2BAA2B,EAAE,CAAC;YAC9C,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACf,CAAC;IACH,CAAC;SAAM,CAAC;QACN,qFAAqF;QACrF,MAAM,cAAc,GAAG,EAAE,CAAC,IAAI,CAAC;YAC7B,GAAG,EAAE,iCAAiC;YACtC,OAAO,EAAE,QAAQ;YACjB,WAAW,EAAE,YAAY;SAC1B,CAA4B,CAAC;QAC9B,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;QAEnE,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,0EAA0E,CAAC,CAAC;QAC5H,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,6EAA6E,CAAC,CAAC;QAC/H,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,sBAAsB,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,+DAA+D,CAAC,CAAC;QAC3H,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC;YAAE,EAAE,CAAC,IAAI,CAAC,qDAAqD,CAAC,CAAC;IACzG,CAAC;IAED,gGAAgG;IAChG,iFAAiF;IACjF,EAAE,CAAC,IAAI,CAAC;;;;;GAKP,CAAC,CAAC;AACL,CAAC"}
|
package/dist/scorer.d.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
+
/** Memory fact score boost multiplier (applied after RRF fusion). */
|
|
2
|
+
export declare const MEMORY_FACT_BOOST = 2;
|
|
3
|
+
/** Memory fact minimum score threshold (after boost) for fallback logic.
|
|
4
|
+
* Calibrated for RRF hybrid scores: top ~25% of boosted fact scores qualify.
|
|
5
|
+
*/
|
|
6
|
+
export declare const MEMORY_FACT_MIN_SCORE = 0.054;
|
|
1
7
|
export interface ScoreResult {
|
|
2
8
|
readonly score: number;
|
|
3
9
|
readonly isCold: boolean;
|
|
4
10
|
}
|
|
5
|
-
/**
|
|
6
|
-
* Minimal shape required by scoreRawLog().
|
|
7
|
-
* raw_log rows carry a timestamp; other fields are not needed for scoring.
|
|
8
|
-
*/
|
|
9
|
-
export interface RawLogChunk {
|
|
10
|
-
readonly timestamp: Date;
|
|
11
|
-
}
|
|
12
11
|
/**
|
|
13
12
|
* Computes the exponential decay multiplier: e^(-lambda × age_in_days).
|
|
14
13
|
*/
|
|
15
14
|
export declare function computeDecay(lambda: number, ageInDays: number): number;
|
|
16
15
|
/**
|
|
17
|
-
* Scores a
|
|
18
|
-
*
|
|
16
|
+
* Scores a memory fact by applying MEMORY_FACT_BOOST to its hybrid search score.
|
|
17
|
+
* Memory facts are high-signal curated content, so they get a 2.0× boost.
|
|
18
|
+
*
|
|
19
|
+
* @param hybridScore The RRF-fused score from BM25 + vector search.
|
|
20
|
+
* @returns The boosted score.
|
|
19
21
|
*/
|
|
20
|
-
export declare function
|
|
22
|
+
export declare function scoreMemoryFact(hybridScore: number): number;
|
|
21
23
|
//# sourceMappingURL=scorer.d.ts.map
|
package/dist/scorer.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"scorer.d.ts","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,eAAO,MAAM,iBAAiB,IAAM,CAAC;AAErC;;GAEG;AACH,eAAO,MAAM,qBAAqB,QAAQ,CAAC;AAE3C,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAE3D"}
|
package/dist/scorer.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
const
|
|
3
|
-
/**
|
|
4
|
-
|
|
1
|
+
/** Memory fact score boost multiplier (applied after RRF fusion). */
|
|
2
|
+
export const MEMORY_FACT_BOOST = 2.0;
|
|
3
|
+
/** Memory fact minimum score threshold (after boost) for fallback logic.
|
|
4
|
+
* Calibrated for RRF hybrid scores: top ~25% of boosted fact scores qualify.
|
|
5
|
+
*/
|
|
6
|
+
export const MEMORY_FACT_MIN_SCORE = 0.054;
|
|
5
7
|
/**
|
|
6
8
|
* Computes the exponential decay multiplier: e^(-lambda × age_in_days).
|
|
7
9
|
*/
|
|
@@ -9,12 +11,13 @@ export function computeDecay(lambda, ageInDays) {
|
|
|
9
11
|
return Math.exp(-lambda * ageInDays);
|
|
10
12
|
}
|
|
11
13
|
/**
|
|
12
|
-
* Scores a
|
|
13
|
-
*
|
|
14
|
+
* Scores a memory fact by applying MEMORY_FACT_BOOST to its hybrid search score.
|
|
15
|
+
* Memory facts are high-signal curated content, so they get a 2.0× boost.
|
|
16
|
+
*
|
|
17
|
+
* @param hybridScore The RRF-fused score from BM25 + vector search.
|
|
18
|
+
* @returns The boosted score.
|
|
14
19
|
*/
|
|
15
|
-
export function
|
|
16
|
-
|
|
17
|
-
const score = computeDecay(RAW_LOG_LAMBDA, ageInDays);
|
|
18
|
-
return { score, isCold: score < COLD_THRESHOLD };
|
|
20
|
+
export function scoreMemoryFact(hybridScore) {
|
|
21
|
+
return hybridScore * MEMORY_FACT_BOOST;
|
|
19
22
|
}
|
|
20
23
|
//# sourceMappingURL=scorer.js.map
|
package/dist/scorer.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"scorer.js","sourceRoot":"","sources":["../src/scorer.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AAErC;;GAEG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,CAAC;AAO3C;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,SAAiB;IAC5D,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;AACvC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,WAAmB;IACjD,OAAO,WAAW,GAAG,iBAAiB,CAAC;AACzC,CAAC"}
|
package/dist/store.d.ts
CHANGED
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { StoreStatus } from './types.js';
|
|
2
2
|
export interface MemoryStore {
|
|
3
3
|
/**
|
|
4
4
|
* Return current store statistics.
|
|
5
5
|
*/
|
|
6
6
|
status(): Promise<StoreStatus>;
|
|
7
|
-
/**
|
|
8
|
-
* High-level entry point for ingesting a conversation exchange.
|
|
9
|
-
* Writes to raw_log table and enqueues embedding.
|
|
10
|
-
*/
|
|
11
|
-
ingest(exchange: MessageExchange): Promise<IngestResult>;
|
|
12
7
|
}
|
|
13
8
|
//# sourceMappingURL=store.d.ts.map
|
package/dist/store.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../src/store.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,MAAM,IAAI,OAAO,CAAC,WAAW,CAAC,CAAC;CAChC"}
|