@getplumb/core 0.4.0 → 0.4.2
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/embedder.d.ts +9 -4
- package/dist/embedder.d.ts.map +1 -1
- package/dist/embedder.js +14 -21
- package/dist/embedder.js.map +1 -1
- package/dist/raw-log-search.d.ts.map +1 -1
- package/dist/raw-log-search.js +10 -1
- package/dist/raw-log-search.js.map +1 -1
- package/package.json +1 -1
- package/dist/extraction-queue.d.ts +0 -72
- package/dist/extraction-queue.d.ts.map +0 -1
- package/dist/extraction-queue.js +0 -101
- package/dist/extraction-queue.js.map +0 -1
- package/dist/extractor.d.ts +0 -22
- package/dist/extractor.d.ts.map +0 -1
- package/dist/extractor.js +0 -188
- package/dist/extractor.js.map +0 -1
- package/dist/extractor.test.d.ts +0 -2
- package/dist/extractor.test.d.ts.map +0 -1
- package/dist/extractor.test.js +0 -158
- package/dist/extractor.test.js.map +0 -1
- package/dist/fact-search.d.ts +0 -32
- package/dist/fact-search.d.ts.map +0 -1
- package/dist/fact-search.js +0 -174
- package/dist/fact-search.js.map +0 -1
- package/dist/fact-search.test.d.ts +0 -12
- package/dist/fact-search.test.d.ts.map +0 -1
- package/dist/fact-search.test.js +0 -117
- package/dist/fact-search.test.js.map +0 -1
- package/dist/llm-client.d.ts +0 -59
- package/dist/llm-client.d.ts.map +0 -1
- package/dist/llm-client.js +0 -227
- package/dist/llm-client.js.map +0 -1
- package/dist/local-store.test.d.ts +0 -2
- package/dist/local-store.test.d.ts.map +0 -1
- package/dist/local-store.test.js +0 -146
- package/dist/local-store.test.js.map +0 -1
- package/dist/raw-log-search.test.d.ts +0 -12
- package/dist/raw-log-search.test.d.ts.map +0 -1
- package/dist/raw-log-search.test.js +0 -124
- package/dist/raw-log-search.test.js.map +0 -1
- package/dist/read-path.test.d.ts +0 -15
- package/dist/read-path.test.d.ts.map +0 -1
- package/dist/read-path.test.js +0 -393
- package/dist/read-path.test.js.map +0 -1
- package/dist/scorer.test.d.ts +0 -10
- package/dist/scorer.test.d.ts.map +0 -1
- package/dist/scorer.test.js +0 -169
- package/dist/scorer.test.js.map +0 -1
package/dist/extractor.test.js
DELETED
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import { test } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import { extractFacts } from './extractor.js';
|
|
4
|
-
import { DecayRate } from './types.js';
|
|
5
|
-
// ---------------------------------------------------------------------------
|
|
6
|
-
// Test fixtures
|
|
7
|
-
// ---------------------------------------------------------------------------
|
|
8
|
-
const testExchange = {
|
|
9
|
-
userMessage: 'I prefer dark mode for all my editors.',
|
|
10
|
-
agentResponse: 'Noted, I will use dark mode settings.',
|
|
11
|
-
timestamp: new Date('2026-01-01T12:00:00Z'),
|
|
12
|
-
source: 'openclaw',
|
|
13
|
-
sessionId: 'session-001',
|
|
14
|
-
sessionLabel: 'prefs-chat',
|
|
15
|
-
};
|
|
16
|
-
const testExchangeNoLabel = {
|
|
17
|
-
userMessage: 'I use TypeScript for everything.',
|
|
18
|
-
agentResponse: 'Great choice.',
|
|
19
|
-
timestamp: new Date('2026-01-01T13:00:00Z'),
|
|
20
|
-
source: 'openclaw',
|
|
21
|
-
sessionId: 'session-002',
|
|
22
|
-
};
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
// In-memory mock store
|
|
25
|
-
// ---------------------------------------------------------------------------
|
|
26
|
-
function createMockStore() {
|
|
27
|
-
const stored = [];
|
|
28
|
-
const store = {
|
|
29
|
-
async store(fact) {
|
|
30
|
-
const id = crypto.randomUUID();
|
|
31
|
-
stored.push({ id, ...fact });
|
|
32
|
-
return id;
|
|
33
|
-
},
|
|
34
|
-
async search(_query, _limit) {
|
|
35
|
-
return [];
|
|
36
|
-
},
|
|
37
|
-
async delete(_id) { },
|
|
38
|
-
async status() {
|
|
39
|
-
return { factCount: stored.length, rawLogCount: 0, lastIngestion: null, storageBytes: 0 };
|
|
40
|
-
},
|
|
41
|
-
async ingest(_exchange) {
|
|
42
|
-
return { rawLogId: crypto.randomUUID(), factsExtracted: 0, factIds: [] };
|
|
43
|
-
},
|
|
44
|
-
};
|
|
45
|
-
return { store, stored };
|
|
46
|
-
}
|
|
47
|
-
// ---------------------------------------------------------------------------
|
|
48
|
-
// LLM mock helpers
|
|
49
|
-
// ---------------------------------------------------------------------------
|
|
50
|
-
function mockLLM(responseJson) {
|
|
51
|
-
return async (_prompt) => JSON.stringify(responseJson);
|
|
52
|
-
}
|
|
53
|
-
function mockLLMWithFences(responseJson) {
|
|
54
|
-
return async (_prompt) => '```json\n' + JSON.stringify(responseJson) + '\n```';
|
|
55
|
-
}
|
|
56
|
-
// ---------------------------------------------------------------------------
|
|
57
|
-
// Tests: structured output parsing
|
|
58
|
-
// ---------------------------------------------------------------------------
|
|
59
|
-
test('extractFacts: parses a valid JSON array and stores each fact', async () => {
|
|
60
|
-
const { store, stored } = createMockStore();
|
|
61
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLM([
|
|
62
|
-
{
|
|
63
|
-
subject: 'user',
|
|
64
|
-
predicate: 'prefers',
|
|
65
|
-
object: 'dark mode',
|
|
66
|
-
context: 'mentioned for all editors',
|
|
67
|
-
confidence: 0.9,
|
|
68
|
-
decay_rate: 'slow',
|
|
69
|
-
},
|
|
70
|
-
]));
|
|
71
|
-
assert.equal(result.length, 1);
|
|
72
|
-
assert.equal(result[0].subject, 'user');
|
|
73
|
-
assert.equal(result[0].predicate, 'prefers');
|
|
74
|
-
assert.equal(result[0].object, 'dark mode');
|
|
75
|
-
assert.equal(result[0].context, 'mentioned for all editors');
|
|
76
|
-
assert.equal(result[0].confidence, 0.9);
|
|
77
|
-
assert.equal(result[0].decayRate, DecayRate.slow);
|
|
78
|
-
assert.equal(result[0].sourceSessionId, 'session-001');
|
|
79
|
-
assert.equal(result[0].sourceSessionLabel, 'prefs-chat');
|
|
80
|
-
assert.match(result[0].id, /^[0-9a-f-]{36}$/);
|
|
81
|
-
assert.equal(stored.length, 1);
|
|
82
|
-
});
|
|
83
|
-
test('extractFacts: strips markdown code fences before parsing', async () => {
|
|
84
|
-
const { store } = createMockStore();
|
|
85
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLMWithFences([
|
|
86
|
-
{ subject: 'user', predicate: 'uses', object: 'TypeScript', confidence: 0.95, decay_rate: 'medium' },
|
|
87
|
-
]));
|
|
88
|
-
assert.equal(result.length, 1);
|
|
89
|
-
assert.equal(result[0].object, 'TypeScript');
|
|
90
|
-
assert.equal(result[0].decayRate, DecayRate.medium);
|
|
91
|
-
});
|
|
92
|
-
test('extractFacts: returns [] and stores nothing when LLM returns []', async () => {
|
|
93
|
-
const { store, stored } = createMockStore();
|
|
94
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLM([]));
|
|
95
|
-
assert.equal(result.length, 0);
|
|
96
|
-
assert.equal(stored.length, 0);
|
|
97
|
-
});
|
|
98
|
-
test('extractFacts: returns [] gracefully when LLM returns invalid JSON', async () => {
|
|
99
|
-
const { store, stored } = createMockStore();
|
|
100
|
-
const result = await extractFacts(testExchange, 'user-1', store, async () => 'This is definitely not JSON.');
|
|
101
|
-
assert.equal(result.length, 0);
|
|
102
|
-
assert.equal(stored.length, 0);
|
|
103
|
-
});
|
|
104
|
-
test('extractFacts: handles multiple facts in one LLM response', async () => {
|
|
105
|
-
const { store, stored } = createMockStore();
|
|
106
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLM([
|
|
107
|
-
{ subject: 'user', predicate: 'prefers', object: 'dark mode', confidence: 0.9, decay_rate: 'slow' },
|
|
108
|
-
{ subject: 'user', predicate: 'uses', object: 'vim keybindings', confidence: 0.8, decay_rate: 'medium' },
|
|
109
|
-
]));
|
|
110
|
-
assert.equal(result.length, 2);
|
|
111
|
-
assert.equal(stored.length, 2);
|
|
112
|
-
});
|
|
113
|
-
test('extractFacts: clamps confidence to [0, 1]', async () => {
|
|
114
|
-
const { store } = createMockStore();
|
|
115
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLM([
|
|
116
|
-
{ subject: 'a', predicate: 'b', object: 'c', confidence: 1.5, decay_rate: 'slow' },
|
|
117
|
-
{ subject: 'd', predicate: 'e', object: 'f', confidence: -0.3, decay_rate: 'fast' },
|
|
118
|
-
]));
|
|
119
|
-
assert.equal(result[0].confidence, 1.0);
|
|
120
|
-
assert.equal(result[1].confidence, 0.0);
|
|
121
|
-
});
|
|
122
|
-
test('extractFacts: unknown decay_rate defaults to medium', async () => {
|
|
123
|
-
const { store } = createMockStore();
|
|
124
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLM([{ subject: 'a', predicate: 'b', object: 'c', confidence: 0.5, decay_rate: 'unknown-rate' }]));
|
|
125
|
-
assert.equal(result[0].decayRate, DecayRate.medium);
|
|
126
|
-
});
|
|
127
|
-
test('extractFacts: sourceSessionLabel is omitted when exchange has no sessionLabel', async () => {
|
|
128
|
-
const { store } = createMockStore();
|
|
129
|
-
const result = await extractFacts(testExchangeNoLabel, 'user-1', store, mockLLM([{ subject: 'user', predicate: 'uses', object: 'TypeScript', confidence: 0.9, decay_rate: 'slow' }]));
|
|
130
|
-
assert.equal(result[0].sourceSessionId, 'session-002');
|
|
131
|
-
assert.equal(result[0].sourceSessionLabel, undefined);
|
|
132
|
-
});
|
|
133
|
-
test('extractFacts: context field is omitted when LLM does not include it', async () => {
|
|
134
|
-
const { store } = createMockStore();
|
|
135
|
-
const result = await extractFacts(testExchange, 'user-1', store, mockLLM([{ subject: 'user', predicate: 'prefers', object: 'dark mode', confidence: 0.9, decay_rate: 'slow' }]));
|
|
136
|
-
assert.equal(result[0].context, undefined);
|
|
137
|
-
});
|
|
138
|
-
// ---------------------------------------------------------------------------
|
|
139
|
-
// Tests: deduplication strategy
|
|
140
|
-
// ---------------------------------------------------------------------------
|
|
141
|
-
test('extractFacts dedup: inserts new entry when same subject+predicate already exists', async () => {
|
|
142
|
-
const { store, stored } = createMockStore();
|
|
143
|
-
const singleFact = [
|
|
144
|
-
{ subject: 'user', predicate: 'prefers', object: 'dark mode', confidence: 0.9, decay_rate: 'slow' },
|
|
145
|
-
];
|
|
146
|
-
// First extraction
|
|
147
|
-
await extractFacts(testExchange, 'user-1', store, mockLLM(singleFact));
|
|
148
|
-
assert.equal(stored.length, 1);
|
|
149
|
-
// Second extraction with same subject+predicate
|
|
150
|
-
await extractFacts(testExchange, 'user-1', store, mockLLM(singleFact));
|
|
151
|
-
assert.equal(stored.length, 2, 'should insert new entry, not overwrite existing');
|
|
152
|
-
// Both entries have unique IDs
|
|
153
|
-
assert.notEqual(stored[0].id, stored[1].id);
|
|
154
|
-
// Both have same subject+predicate
|
|
155
|
-
assert.equal(stored[0].subject, stored[1].subject);
|
|
156
|
-
assert.equal(stored[0].predicate, stored[1].predicate);
|
|
157
|
-
});
|
|
158
|
-
//# sourceMappingURL=extractor.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"extractor.test.js","sourceRoot":"","sources":["../src/extractor.test.ts"],"names":[],"mappings":"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"}
|
package/dist/fact-search.d.ts
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fact hybrid search (Layer 2 retrieval).
|
|
3
|
-
*
|
|
4
|
-
* Pipeline:
|
|
5
|
-
* 1. BM25 keyword search over concatenated fact text (subject+predicate+object+context)
|
|
6
|
-
* 2. KNN vector search via JS cosine similarity (replaces sqlite-vec)
|
|
7
|
-
* 3. Reciprocal Rank Fusion (RRF, k=60) merges both ranked lists
|
|
8
|
-
* 4. Recency decay: score *= e^(-lambda × age_in_days), using per-fact decay_rate
|
|
9
|
-
* 5. Cross-encoder reranker (top-20 candidates → Xenova/ms-marco-MiniLM-L-6-v2)
|
|
10
|
-
* 6. Return top-k by reranker score (falls back to RRF×decay if reranker fails)
|
|
11
|
-
*
|
|
12
|
-
* Decay lambdas by fact decay_rate:
|
|
13
|
-
* slow=0.003 (half-life ~231 days) — identity, stable preferences
|
|
14
|
-
* medium=0.012 (half-life ~58 days) — project context, tool choices
|
|
15
|
-
* fast=0.05 (half-life ~14 days) — transient state
|
|
16
|
-
*/
|
|
17
|
-
import type { WasmDb } from './wasm-db.js';
|
|
18
|
-
import type { SearchResult } from './types.js';
|
|
19
|
-
/**
|
|
20
|
-
* Hybrid search over facts.
|
|
21
|
-
*
|
|
22
|
-
* @param db The WASM SQLite Database instance
|
|
23
|
-
* @param userId Scopes the search to this user's data
|
|
24
|
-
* @param query Natural language query string
|
|
25
|
-
* @param limit Number of results to return (default 20)
|
|
26
|
-
* @param preloadedCorpus Optional pre-loaded vec_facts corpus (T-096: in-memory cache)
|
|
27
|
-
*/
|
|
28
|
-
export declare function searchFacts(db: WasmDb, userId: string, query: string, limit?: number, preloadedCorpus?: Array<{
|
|
29
|
-
rowid: number;
|
|
30
|
-
embedding: Float32Array;
|
|
31
|
-
}>): Promise<readonly SearchResult[]>;
|
|
32
|
-
//# sourceMappingURL=fact-search.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fact-search.d.ts","sourceRoot":"","sources":["../src/fact-search.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAG3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AA0F/C;;;;;;;;GAQG;AACH,wBAAsB,WAAW,CAC/B,EAAE,EAAE,MAAM,EACV,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,SAAK,EACV,eAAe,CAAC,EAAE,KAAK,CAAC;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,YAAY,CAAA;CAAE,CAAC,GAClE,OAAO,CAAC,SAAS,YAAY,EAAE,CAAC,CA2GlC"}
|
package/dist/fact-search.js
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fact hybrid search (Layer 2 retrieval).
|
|
3
|
-
*
|
|
4
|
-
* Pipeline:
|
|
5
|
-
* 1. BM25 keyword search over concatenated fact text (subject+predicate+object+context)
|
|
6
|
-
* 2. KNN vector search via JS cosine similarity (replaces sqlite-vec)
|
|
7
|
-
* 3. Reciprocal Rank Fusion (RRF, k=60) merges both ranked lists
|
|
8
|
-
* 4. Recency decay: score *= e^(-lambda × age_in_days), using per-fact decay_rate
|
|
9
|
-
* 5. Cross-encoder reranker (top-20 candidates → Xenova/ms-marco-MiniLM-L-6-v2)
|
|
10
|
-
* 6. Return top-k by reranker score (falls back to RRF×decay if reranker fails)
|
|
11
|
-
*
|
|
12
|
-
* Decay lambdas by fact decay_rate:
|
|
13
|
-
* slow=0.003 (half-life ~231 days) — identity, stable preferences
|
|
14
|
-
* medium=0.012 (half-life ~58 days) — project context, tool choices
|
|
15
|
-
* fast=0.05 (half-life ~14 days) — transient state
|
|
16
|
-
*/
|
|
17
|
-
import { Bm25 } from './bm25.js';
|
|
18
|
-
import { embedQuery, rerankScores } from './embedder.js';
|
|
19
|
-
import { knnSearch, deserializeEmbedding } from './vector-search.js';
|
|
20
|
-
// RRF constant (standard k=60).
|
|
21
|
-
const RRF_K = 60;
|
|
22
|
-
// Number of candidates passed to the cross-encoder.
|
|
23
|
-
const RERANK_TOP_K = 20;
|
|
24
|
-
// Decay lambdas by fact decay_rate field.
|
|
25
|
-
const DECAY_LAMBDAS = {
|
|
26
|
-
slow: 0.003,
|
|
27
|
-
medium: 0.012,
|
|
28
|
-
fast: 0.05,
|
|
29
|
-
};
|
|
30
|
-
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
31
|
-
function factText(row) {
|
|
32
|
-
return `${row.subject} ${row.predicate} ${row.object} ${row.context ?? ''}`.trim();
|
|
33
|
-
}
|
|
34
|
-
function ageInDays(timestamp) {
|
|
35
|
-
return (Date.now() - new Date(timestamp).getTime()) / (1_000 * 60 * 60 * 24);
|
|
36
|
-
}
|
|
37
|
-
function recencyDecay(timestamp, decayRate) {
|
|
38
|
-
const lambda = DECAY_LAMBDAS[decayRate] ?? DECAY_LAMBDAS.medium;
|
|
39
|
-
return Math.exp(-lambda * ageInDays(timestamp));
|
|
40
|
-
}
|
|
41
|
-
function rowToFact(row) {
|
|
42
|
-
return {
|
|
43
|
-
id: row.id,
|
|
44
|
-
subject: row.subject,
|
|
45
|
-
predicate: row.predicate,
|
|
46
|
-
object: row.object,
|
|
47
|
-
confidence: row.confidence,
|
|
48
|
-
decayRate: row.decay_rate,
|
|
49
|
-
timestamp: new Date(row.timestamp),
|
|
50
|
-
sourceSessionId: row.source_session_id,
|
|
51
|
-
...(row.source_session_label !== null ? { sourceSessionLabel: row.source_session_label } : {}),
|
|
52
|
-
...(row.context !== null ? { context: row.context } : {}),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
|
-
/**
|
|
56
|
-
* Merge two ranked lists via Reciprocal Rank Fusion.
|
|
57
|
-
*/
|
|
58
|
-
function rrf(vecRanked, bm25Ranked) {
|
|
59
|
-
const scores = new Map();
|
|
60
|
-
for (let rank = 0; rank < vecRanked.length; rank++) {
|
|
61
|
-
const id = vecRanked[rank]?.[0];
|
|
62
|
-
if (id === undefined)
|
|
63
|
-
continue;
|
|
64
|
-
scores.set(id, (scores.get(id) ?? 0) + 1 / (RRF_K + rank + 1));
|
|
65
|
-
}
|
|
66
|
-
for (let rank = 0; rank < bm25Ranked.length; rank++) {
|
|
67
|
-
const id = bm25Ranked[rank]?.[0];
|
|
68
|
-
if (id === undefined)
|
|
69
|
-
continue;
|
|
70
|
-
scores.set(id, (scores.get(id) ?? 0) + 1 / (RRF_K + rank + 1));
|
|
71
|
-
}
|
|
72
|
-
return scores;
|
|
73
|
-
}
|
|
74
|
-
// ─── Public API ───────────────────────────────────────────────────────────────
|
|
75
|
-
/**
|
|
76
|
-
* Hybrid search over facts.
|
|
77
|
-
*
|
|
78
|
-
* @param db The WASM SQLite Database instance
|
|
79
|
-
* @param userId Scopes the search to this user's data
|
|
80
|
-
* @param query Natural language query string
|
|
81
|
-
* @param limit Number of results to return (default 20)
|
|
82
|
-
* @param preloadedCorpus Optional pre-loaded vec_facts corpus (T-096: in-memory cache)
|
|
83
|
-
*/
|
|
84
|
-
export async function searchFacts(db, userId, query, limit = 20, preloadedCorpus) {
|
|
85
|
-
// ── 1. Fetch all non-deleted fact rows for this user ────────────────────
|
|
86
|
-
const stmt = db.prepare(`SELECT id, user_id, subject, predicate, object, confidence,
|
|
87
|
-
decay_rate, timestamp, source_session_id, source_session_label,
|
|
88
|
-
context, deleted_at, vec_rowid
|
|
89
|
-
FROM facts
|
|
90
|
-
WHERE user_id = ? AND deleted_at IS NULL AND confidence >= 0.65
|
|
91
|
-
ORDER BY timestamp DESC`);
|
|
92
|
-
stmt.bind([userId]);
|
|
93
|
-
const allRows = [];
|
|
94
|
-
while (stmt.step()) {
|
|
95
|
-
allRows.push(stmt.get({}));
|
|
96
|
-
}
|
|
97
|
-
stmt.finalize();
|
|
98
|
-
if (allRows.length === 0)
|
|
99
|
-
return [];
|
|
100
|
-
const idToRow = new Map(allRows.map((r) => [r.id, r]));
|
|
101
|
-
// ── 2. BM25 search ───────────────────────────────────────────────────────
|
|
102
|
-
const corpus = allRows.map(factText);
|
|
103
|
-
const bm25 = new Bm25(corpus);
|
|
104
|
-
const bm25RawScores = bm25.scores(query);
|
|
105
|
-
const bm25Ranked = allRows
|
|
106
|
-
.map((r, i) => [r.id, bm25RawScores[i] ?? 0])
|
|
107
|
-
.sort((a, b) => b[1] - a[1]);
|
|
108
|
-
// ── 3. Vector search via JS cosine similarity ───────────────────────────
|
|
109
|
-
const queryVec = await embedQuery(query);
|
|
110
|
-
// T-096: Use preloaded corpus if provided, otherwise fetch from vec_facts
|
|
111
|
-
let vecCorpus;
|
|
112
|
-
if (preloadedCorpus !== undefined) {
|
|
113
|
-
// Map rowid → id for knnSearch compatibility
|
|
114
|
-
vecCorpus = preloadedCorpus.map(entry => ({ id: entry.rowid, embedding: entry.embedding }));
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
// Fetch all embeddings from vec_facts (legacy path, used if cache not provided)
|
|
118
|
-
const vecStmt = db.prepare(`SELECT id, embedding FROM vec_facts`);
|
|
119
|
-
vecCorpus = [];
|
|
120
|
-
while (vecStmt.step()) {
|
|
121
|
-
const row = vecStmt.get({});
|
|
122
|
-
vecCorpus.push({
|
|
123
|
-
id: row.id,
|
|
124
|
-
embedding: deserializeEmbedding(row.embedding),
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
vecStmt.finalize();
|
|
128
|
-
}
|
|
129
|
-
// Perform KNN search
|
|
130
|
-
const vecFetchLimit = Math.min(allRows.length, Math.max(RERANK_TOP_K * 2, limit * 3, 50));
|
|
131
|
-
const vecResults = knnSearch(queryVec, vecCorpus, vecFetchLimit);
|
|
132
|
-
// Map vec_facts ids back to fact ids
|
|
133
|
-
const vecRanked = [];
|
|
134
|
-
for (const vecResult of vecResults) {
|
|
135
|
-
const factRow = allRows.find((r) => r.vec_rowid === vecResult.id);
|
|
136
|
-
if (factRow !== undefined) {
|
|
137
|
-
vecRanked.push([factRow.id, 1 - vecResult.distance]);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
// ── 4. RRF merge ────────────────────────────────────────────────────────
|
|
141
|
-
const rrfScores = rrf(vecRanked, bm25Ranked);
|
|
142
|
-
// ── 5. Recency decay (per-fact lambda) ──────────────────────────────────
|
|
143
|
-
const decayedScores = [];
|
|
144
|
-
for (const [id, rrfScore] of rrfScores) {
|
|
145
|
-
const row = idToRow.get(id);
|
|
146
|
-
if (row === undefined)
|
|
147
|
-
continue;
|
|
148
|
-
const decay = recencyDecay(row.timestamp, row.decay_rate);
|
|
149
|
-
decayedScores.push([id, rrfScore * decay]);
|
|
150
|
-
}
|
|
151
|
-
decayedScores.sort((a, b) => b[1] - a[1]);
|
|
152
|
-
// ── 6. Take top candidates for reranking ────────────────────────────────
|
|
153
|
-
const candidates = decayedScores.slice(0, Math.max(RERANK_TOP_K, limit));
|
|
154
|
-
// ── 7. Cross-encoder reranking ──────────────────────────────────────────
|
|
155
|
-
const passages = candidates.map(([id]) => factText(idToRow.get(id)));
|
|
156
|
-
const rerankerScores = await rerankScores(query, passages);
|
|
157
|
-
const hasRerankerSignal = rerankerScores.some((s) => s !== 0);
|
|
158
|
-
const ranked = candidates.map(([id, rrfDecayScore], i) => ({
|
|
159
|
-
id,
|
|
160
|
-
finalScore: hasRerankerSignal ? (rerankerScores[i] ?? 0) : rrfDecayScore,
|
|
161
|
-
}));
|
|
162
|
-
ranked.sort((a, b) => b.finalScore - a.finalScore);
|
|
163
|
-
// ── 8. Build output ─────────────────────────────────────────────────────
|
|
164
|
-
return ranked.slice(0, limit).map(({ id, finalScore }) => {
|
|
165
|
-
const row = idToRow.get(id);
|
|
166
|
-
const fact = rowToFact(row);
|
|
167
|
-
return {
|
|
168
|
-
fact,
|
|
169
|
-
score: finalScore,
|
|
170
|
-
ageInDays: ageInDays(row.timestamp),
|
|
171
|
-
};
|
|
172
|
-
});
|
|
173
|
-
}
|
|
174
|
-
//# sourceMappingURL=fact-search.js.map
|
package/dist/fact-search.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fact-search.js","sourceRoot":"","sources":["../src/fact-search.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Layer 2 hybrid search (fact-search.ts).
|
|
3
|
-
*
|
|
4
|
-
* Stores 3 facts with distinct topics via store.store(), then verifies that
|
|
5
|
-
* search() returns ranked results with the expected structure.
|
|
6
|
-
*
|
|
7
|
-
* Note: The first test run downloads the BAAI/bge-small-en-v1.5 embedding model
|
|
8
|
-
* (~100 MB) and the ms-marco cross-encoder (~50 MB) — subsequent runs use the
|
|
9
|
-
* local ~/.cache/huggingface/ cache.
|
|
10
|
-
*/
|
|
11
|
-
export {};
|
|
12
|
-
//# sourceMappingURL=fact-search.test.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fact-search.test.d.ts","sourceRoot":"","sources":["../src/fact-search.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
package/dist/fact-search.test.js
DELETED
|
@@ -1,117 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for Layer 2 hybrid search (fact-search.ts).
|
|
3
|
-
*
|
|
4
|
-
* Stores 3 facts with distinct topics via store.store(), then verifies that
|
|
5
|
-
* search() returns ranked results with the expected structure.
|
|
6
|
-
*
|
|
7
|
-
* Note: The first test run downloads the BAAI/bge-small-en-v1.5 embedding model
|
|
8
|
-
* (~100 MB) and the ms-marco cross-encoder (~50 MB) — subsequent runs use the
|
|
9
|
-
* local ~/.cache/huggingface/ cache.
|
|
10
|
-
*/
|
|
11
|
-
import { test, after } from 'node:test';
|
|
12
|
-
import assert from 'node:assert/strict';
|
|
13
|
-
import { tmpdir } from 'node:os';
|
|
14
|
-
import { join } from 'node:path';
|
|
15
|
-
import { rmSync } from 'node:fs';
|
|
16
|
-
import { LocalStore } from './local-store.js';
|
|
17
|
-
import { DecayRate } from './types.js';
|
|
18
|
-
const dbPath = join(tmpdir(), `plumb-fact-search-test-${Date.now()}.db`);
|
|
19
|
-
const store = new LocalStore({ dbPath, userId: 'fact-search-test-user' });
|
|
20
|
-
after(() => {
|
|
21
|
-
store.close();
|
|
22
|
-
rmSync(dbPath, { force: true });
|
|
23
|
-
});
|
|
24
|
-
// ─── Fixtures ────────────────────────────────────────────────────────────────
|
|
25
|
-
const FACTS = [
|
|
26
|
-
{
|
|
27
|
-
subject: 'Clay',
|
|
28
|
-
predicate: 'is actively searching for',
|
|
29
|
-
object: 'software engineering jobs',
|
|
30
|
-
context: 'Clay is looking at Samsara, applied to multiple companies, tracking applications and interviews',
|
|
31
|
-
confidence: 0.95,
|
|
32
|
-
decayRate: DecayRate.slow,
|
|
33
|
-
timestamp: new Date(Date.now() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
|
|
34
|
-
sourceSessionId: 'session-job-search',
|
|
35
|
-
sourceSessionLabel: 'job-search-chat',
|
|
36
|
-
},
|
|
37
|
-
{
|
|
38
|
-
subject: 'Clay',
|
|
39
|
-
predicate: 'prefers',
|
|
40
|
-
object: 'TypeScript over JavaScript',
|
|
41
|
-
context: 'Clay mentioned preferring strict typing and has all projects configured with strict mode',
|
|
42
|
-
confidence: 0.9,
|
|
43
|
-
decayRate: DecayRate.slow,
|
|
44
|
-
timestamp: new Date(Date.now() - 5 * 24 * 60 * 60 * 1000), // 5 days ago
|
|
45
|
-
sourceSessionId: 'session-ts-prefs',
|
|
46
|
-
sourceSessionLabel: 'typescript-chat',
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
subject: 'chocolate cake recipe',
|
|
50
|
-
predicate: 'requires',
|
|
51
|
-
object: '200g butter and 50g cocoa powder',
|
|
52
|
-
context: 'Classic recipe baked at 180 degrees for 30 minutes with ganache frosting',
|
|
53
|
-
confidence: 0.85,
|
|
54
|
-
decayRate: DecayRate.fast,
|
|
55
|
-
timestamp: new Date(Date.now() - 2 * 24 * 60 * 60 * 1000), // 2 days ago
|
|
56
|
-
sourceSessionId: 'session-cooking',
|
|
57
|
-
sourceSessionLabel: 'cooking-chat',
|
|
58
|
-
},
|
|
59
|
-
];
|
|
60
|
-
// ─── Store facts (shared setup) ──────────────────────────────────────────────
|
|
61
|
-
test('store 3 facts with distinct topics', { timeout: 120_000 }, async () => {
|
|
62
|
-
for (const fact of FACTS) {
|
|
63
|
-
const id = await store.store(fact);
|
|
64
|
-
assert.match(id, /^[0-9a-f-]{36}$/, 'id should be a UUID');
|
|
65
|
-
}
|
|
66
|
-
const status = await store.status();
|
|
67
|
-
assert.equal(status.factCount, 3, 'all 3 facts should be stored');
|
|
68
|
-
});
|
|
69
|
-
// ─── Search ──────────────────────────────────────────────────────────────────
|
|
70
|
-
test('search returns results with required SearchResult fields', { timeout: 120_000 }, async () => {
|
|
71
|
-
const results = await store.search('job search applications', 3);
|
|
72
|
-
assert.ok(results.length > 0, 'should return at least one result');
|
|
73
|
-
for (const r of results) {
|
|
74
|
-
assert.ok(typeof r.fact.id === 'string', 'fact.id must be a string');
|
|
75
|
-
assert.ok(typeof r.fact.subject === 'string', 'fact.subject must be a string');
|
|
76
|
-
assert.ok(typeof r.fact.predicate === 'string', 'fact.predicate must be a string');
|
|
77
|
-
assert.ok(typeof r.fact.object === 'string', 'fact.object must be a string');
|
|
78
|
-
assert.ok(typeof r.score === 'number', 'score must be a number');
|
|
79
|
-
assert.ok(typeof r.ageInDays === 'number', 'ageInDays must be a number');
|
|
80
|
-
assert.ok(r.fact.timestamp instanceof Date, 'timestamp must be a Date');
|
|
81
|
-
}
|
|
82
|
-
});
|
|
83
|
-
test('search ranks job-search fact first for job query', { timeout: 120_000 }, async () => {
|
|
84
|
-
const results = await store.search('job search applications Samsara', 3);
|
|
85
|
-
assert.ok(results.length > 0, 'should return results');
|
|
86
|
-
const top = results[0];
|
|
87
|
-
assert.ok(top !== undefined, 'should have a top result');
|
|
88
|
-
// The job-search fact should rank first.
|
|
89
|
-
assert.equal(top.fact.subject, 'Clay', 'top result subject should be Clay');
|
|
90
|
-
assert.ok(top.fact.object.includes('job') || top.fact.object.includes('engineering'), 'top result should be about job search');
|
|
91
|
-
});
|
|
92
|
-
test('search returns cooking fact in results for recipe query', { timeout: 120_000 }, async () => {
|
|
93
|
-
const results = await store.search('chocolate cake recipe baking', 3);
|
|
94
|
-
assert.ok(results.length > 0, 'should return results');
|
|
95
|
-
const cookingResult = results.find((r) => r.fact.sourceSessionId === 'session-cooking');
|
|
96
|
-
assert.ok(cookingResult !== undefined, 'cooking fact should appear in results');
|
|
97
|
-
});
|
|
98
|
-
test('search returns empty array when no facts exist', { timeout: 30_000 }, async () => {
|
|
99
|
-
const emptyStore = new LocalStore({
|
|
100
|
-
dbPath: join(tmpdir(), `plumb-fact-empty-${Date.now()}.db`),
|
|
101
|
-
userId: 'empty-user',
|
|
102
|
-
});
|
|
103
|
-
try {
|
|
104
|
-
const results = await emptyStore.search('anything', 5);
|
|
105
|
-
assert.deepEqual(results, []);
|
|
106
|
-
}
|
|
107
|
-
finally {
|
|
108
|
-
emptyStore.close();
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
test('benchmark smoke: job search query returns at least 1 result with correct subject', { timeout: 120_000 }, async () => {
|
|
112
|
-
const results = await store.search('job search applications', 5);
|
|
113
|
-
assert.ok(results.length >= 1, 'should return at least 1 result');
|
|
114
|
-
const jobResult = results.find((r) => r.fact.subject === 'Clay' && r.fact.object.includes('job'));
|
|
115
|
-
assert.ok(jobResult !== undefined, 'should find Clay job search fact');
|
|
116
|
-
});
|
|
117
|
-
//# sourceMappingURL=fact-search.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"fact-search.test.js","sourceRoot":"","sources":["../src/fact-search.test.ts"],"names":[],"mappings":"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"}
|
package/dist/llm-client.d.ts
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* LLM configuration that can be passed directly instead of relying on environment variables.
|
|
3
|
-
* When provided, these values take precedence over env vars.
|
|
4
|
-
*/
|
|
5
|
-
export interface LLMConfig {
|
|
6
|
-
/** Provider: 'google' (recommended) | 'openai' | 'anthropic' | 'ollama' | 'openai-compatible'. Defaults to 'openai'. */
|
|
7
|
-
provider?: string;
|
|
8
|
-
/** Model ID. Defaults to provider-specific default. */
|
|
9
|
-
model?: string;
|
|
10
|
-
/** API key. Takes precedence over env var for the given provider. */
|
|
11
|
-
apiKey?: string;
|
|
12
|
-
/** Base URL for 'openai-compatible' or 'ollama' providers. */
|
|
13
|
-
baseUrl?: string;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* Resolve the OpenAI API key from environment variables.
|
|
17
|
-
* Returns the key if found, otherwise throws a clear error.
|
|
18
|
-
*
|
|
19
|
-
* Set OPENAI_API_KEY in your environment before using Plumb with the OpenAI provider.
|
|
20
|
-
*
|
|
21
|
-
* @throws Error if no key is found
|
|
22
|
-
*/
|
|
23
|
-
export declare function resolveOpenAIKey(): string;
|
|
24
|
-
/**
|
|
25
|
-
* Resolve the Anthropic API key from environment variables.
|
|
26
|
-
* Returns the key if found, otherwise throws a clear error.
|
|
27
|
-
*
|
|
28
|
-
* Set ANTHROPIC_API_KEY in your environment before using Plumb with the Anthropic provider.
|
|
29
|
-
*
|
|
30
|
-
* @throws Error if no key is found
|
|
31
|
-
*/
|
|
32
|
-
export declare function resolveAnthropicKey(): string;
|
|
33
|
-
/**
|
|
34
|
-
* Resolve the Gemini API key from environment variables.
|
|
35
|
-
* Returns the key if found, otherwise throws a clear error.
|
|
36
|
-
*
|
|
37
|
-
* Set GEMINI_API_KEY in your environment before using Plumb with the Google provider.
|
|
38
|
-
*
|
|
39
|
-
* @throws Error if no key is found
|
|
40
|
-
*/
|
|
41
|
-
export declare function resolveGeminiKey(): string;
|
|
42
|
-
/**
|
|
43
|
-
* Calls the configured LLM with the given prompt and returns the text response.
|
|
44
|
-
* Provider and model are configurable via env:
|
|
45
|
-
* PLUMB_LLM_PROVIDER — 'openai' (default), 'anthropic', 'ollama', 'openai-compatible', 'google'
|
|
46
|
-
* PLUMB_LLM_MODEL — model ID, defaults vary per provider
|
|
47
|
-
* PLUMB_LLM_BASE_URL — for 'openai-compatible' provider
|
|
48
|
-
* OLLAMA_HOST — for 'ollama' provider (default: http://localhost:11434/v1)
|
|
49
|
-
*/
|
|
50
|
-
export declare function callLLM(prompt: string): Promise<string>;
|
|
51
|
-
/**
|
|
52
|
-
* Calls the LLM using explicitly provided config rather than environment variables.
|
|
53
|
-
* Falls back to env vars for any values not provided in config.
|
|
54
|
-
*
|
|
55
|
-
* Use this when you want to pass LLM credentials programmatically (e.g. from plugin config)
|
|
56
|
-
* without mutating process.env.
|
|
57
|
-
*/
|
|
58
|
-
export declare function callLLMWithConfig(prompt: string, config: LLMConfig): Promise<string>;
|
|
59
|
-
//# sourceMappingURL=llm-client.d.ts.map
|
package/dist/llm-client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"llm-client.d.ts","sourceRoot":"","sources":["../src/llm-client.ts"],"names":[],"mappings":"AAcA;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,wHAAwH;IACxH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,uDAAuD;IACvD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAQzC;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAQ5C;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAQzC;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2F7D;AAED;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAoF1F"}
|