@knolo/core 3.2.1 → 3.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +68 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -0
- package/dist/indexer.d.ts +5 -4
- package/dist/indexer.js +6 -5
- package/dist/memory/consolidate.d.ts +15 -0
- package/dist/memory/consolidate.js +71 -0
- package/dist/memory/cortex.d.ts +43 -0
- package/dist/memory/cortex.js +93 -0
- package/dist/memory/engram.d.ts +48 -0
- package/dist/memory/engram.js +90 -0
- package/dist/memory/graph_adapter.d.ts +3 -0
- package/dist/memory/graph_adapter.js +65 -0
- package/dist/memory/index.d.ts +13 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/label.d.ts +4 -0
- package/dist/memory/label.js +53 -0
- package/dist/memory/log.d.ts +36 -0
- package/dist/memory/log.js +241 -0
- package/dist/memory/recall.d.ts +23 -0
- package/dist/memory/recall.js +167 -0
- package/dist/query.d.ts +10 -0
- package/dist/query.js +90 -7
- package/dist/semantic/cosine.d.ts +2 -0
- package/dist/semantic/cosine.js +20 -0
- package/dist/semantic/provider.d.ts +3 -0
- package/dist/semantic/provider.js +13 -0
- package/dist/semantic/rerank.d.ts +23 -0
- package/dist/semantic/rerank.js +42 -0
- package/dist/semantic/sidecar.d.ts +10 -0
- package/dist/semantic/sidecar.js +32 -0
- package/dist/semantic/types.d.ts +44 -0
- package/dist/semantic/types.js +1 -0
- package/package.json +2 -2
package/dist/query.js
CHANGED
|
@@ -15,6 +15,8 @@ import { diversifyAndDedupe } from "./quality/diversify.js";
|
|
|
15
15
|
import { knsSignature, knsDistance } from "./quality/signature.js";
|
|
16
16
|
import { decodeScaleF16, quantizeEmbeddingInt8L2Norm } from "./semantic.js";
|
|
17
17
|
import { expandQueryWithGraph } from "./graph/query_expand.js";
|
|
18
|
+
import { rerankCandidates } from "./semantic/rerank.js";
|
|
19
|
+
import { parseSidecar } from "./semantic/sidecar.js";
|
|
18
20
|
export function validateQueryOptions(opts) {
|
|
19
21
|
if (!opts)
|
|
20
22
|
return;
|
|
@@ -78,6 +80,19 @@ export function validateSemanticQueryOptions(options) {
|
|
|
78
80
|
if (options.queryEmbedding !== undefined && !(options.queryEmbedding instanceof Float32Array)) {
|
|
79
81
|
throw new Error("query(...): semantic.queryEmbedding must be a Float32Array.");
|
|
80
82
|
}
|
|
83
|
+
if (options.sidecarPath !== undefined && typeof options.sidecarPath !== "string") {
|
|
84
|
+
throw new Error("query(...): semantic.sidecarPath must be a string when provided.");
|
|
85
|
+
}
|
|
86
|
+
if (options.minSemanticScore !== undefined && (!Number.isFinite(options.minSemanticScore) || options.minSemanticScore < 0 || options.minSemanticScore > 1)) {
|
|
87
|
+
throw new Error("query(...): semantic.minSemanticScore must be a finite number between 0 and 1.");
|
|
88
|
+
}
|
|
89
|
+
if (options.provider) {
|
|
90
|
+
if (options.provider.type !== "ollama")
|
|
91
|
+
throw new Error('query(...): semantic.provider.type must be "ollama".');
|
|
92
|
+
if (typeof options.provider.modelId !== "string" || !options.provider.modelId.trim()) {
|
|
93
|
+
throw new Error("query(...): semantic.provider.modelId must be a non-empty string.");
|
|
94
|
+
}
|
|
95
|
+
}
|
|
81
96
|
if (options.blend) {
|
|
82
97
|
if (options.blend.enabled !== undefined && typeof options.blend.enabled !== "boolean") {
|
|
83
98
|
throw new Error("query(...): semantic.blend.enabled must be a boolean when provided.");
|
|
@@ -115,6 +130,9 @@ export function query(pack, q, opts = {}) {
|
|
|
115
130
|
wSem: Math.max(0, opts.semantic?.blend?.wSem ?? 0.25),
|
|
116
131
|
},
|
|
117
132
|
queryEmbedding: opts.semantic?.queryEmbedding,
|
|
133
|
+
sidecar: resolveSemanticSidecar(opts.semantic?.sidecar, opts.semantic?.sidecarPath),
|
|
134
|
+
provider: opts.semantic?.provider,
|
|
135
|
+
minSemanticScore: opts.semantic?.minSemanticScore,
|
|
118
136
|
force: opts.semantic?.force ?? false,
|
|
119
137
|
};
|
|
120
138
|
const graphQuery = opts.graph?.expand === true
|
|
@@ -163,7 +181,7 @@ export function query(pack, q, opts = {}) {
|
|
|
163
181
|
let pos = p[i++];
|
|
164
182
|
const positions = [];
|
|
165
183
|
while (pos !== 0) {
|
|
166
|
-
positions.push(pos);
|
|
184
|
+
positions.push(pos - 1);
|
|
167
185
|
pos = p[i++];
|
|
168
186
|
}
|
|
169
187
|
termDf++;
|
|
@@ -284,9 +302,16 @@ export function query(pack, q, opts = {}) {
|
|
|
284
302
|
return [];
|
|
285
303
|
}
|
|
286
304
|
const confidence = lexConfidence(prelim);
|
|
305
|
+
let semanticScores;
|
|
306
|
+
let blendedScores;
|
|
307
|
+
const originalLexicalScores = new Map(prelim.map((item) => [item.blockId, item.score]));
|
|
287
308
|
if (shouldRerankWithSemantic(pack, semanticOpts, confidence)) {
|
|
288
|
-
|
|
309
|
+
const semanticResult = rerankLexicalHitsWithSemantic(pack, prelim, semanticOpts);
|
|
310
|
+
prelim = semanticResult.hits;
|
|
311
|
+
semanticScores = semanticResult.semanticScores;
|
|
312
|
+
blendedScores = semanticResult.blendedScores;
|
|
289
313
|
}
|
|
314
|
+
const retrievalMode = semanticScores ? "hybrid" : "lexical";
|
|
290
315
|
// --- KNS tie-breaker + de-dup/MMR
|
|
291
316
|
const qSig = knsSignature(normalize(q));
|
|
292
317
|
const pool = prelim.slice(0, topK * 5).map((r) => {
|
|
@@ -298,6 +323,13 @@ export function query(pack, q, opts = {}) {
|
|
|
298
323
|
text,
|
|
299
324
|
source: pack.docIds?.[r.blockId] ?? undefined,
|
|
300
325
|
namespace: pack.namespaces?.[r.blockId] ?? undefined,
|
|
326
|
+
evidence: {
|
|
327
|
+
retrieval: retrievalMode,
|
|
328
|
+
lexicalScore: originalLexicalScores.get(r.blockId) ?? r.score,
|
|
329
|
+
semanticScore: semanticScores?.get(r.blockId),
|
|
330
|
+
blendedScore: blendedScores?.get(r.blockId),
|
|
331
|
+
modelId: semanticOpts.provider?.modelId ?? semanticOpts.sidecar?.modelId,
|
|
332
|
+
},
|
|
301
333
|
};
|
|
302
334
|
});
|
|
303
335
|
const finalHits = diversifyAndDedupe(pool, { k: topK });
|
|
@@ -315,19 +347,66 @@ export function lexConfidence(hits) {
|
|
|
315
347
|
function shouldRerankWithSemantic(pack, opts, confidence) {
|
|
316
348
|
if (!opts.enabled || opts.mode !== "rerank")
|
|
317
349
|
return false;
|
|
318
|
-
if (!pack.semantic)
|
|
350
|
+
if (!pack.semantic && !opts.sidecar)
|
|
319
351
|
return false;
|
|
320
352
|
if (!opts.queryEmbedding) {
|
|
321
353
|
throw new Error("query(...): semantic.queryEmbedding (Float32Array) is required when semantic.enabled=true.");
|
|
322
354
|
}
|
|
323
355
|
return opts.force || confidence < opts.minLexConfidence;
|
|
324
356
|
}
|
|
357
|
+
function resolveSemanticSidecar(sidecar, sidecarPath) {
|
|
358
|
+
if (sidecar)
|
|
359
|
+
return sidecar;
|
|
360
|
+
if (!sidecarPath)
|
|
361
|
+
return undefined;
|
|
362
|
+
const raw = sidecarPath.trim();
|
|
363
|
+
if (!raw)
|
|
364
|
+
return undefined;
|
|
365
|
+
if (raw.startsWith("{")) {
|
|
366
|
+
return parseSidecar(raw);
|
|
367
|
+
}
|
|
368
|
+
if (raw.startsWith("data:")) {
|
|
369
|
+
const comma = raw.indexOf(",");
|
|
370
|
+
if (comma <= 0)
|
|
371
|
+
return undefined;
|
|
372
|
+
const meta = raw.slice(5, comma).toLowerCase();
|
|
373
|
+
const payload = raw.slice(comma + 1);
|
|
374
|
+
const decoded = meta.includes(";base64")
|
|
375
|
+
? decodeBase64(payload)
|
|
376
|
+
: decodeURIComponent(payload);
|
|
377
|
+
if (!decoded.trim())
|
|
378
|
+
return undefined;
|
|
379
|
+
return parseSidecar(decoded);
|
|
380
|
+
}
|
|
381
|
+
return undefined;
|
|
382
|
+
}
|
|
383
|
+
function decodeBase64(input) {
|
|
384
|
+
const normalized = input.replace(/\s+/g, "");
|
|
385
|
+
const atobFn = globalThis.atob;
|
|
386
|
+
if (typeof atobFn === "function")
|
|
387
|
+
return atobFn(normalized);
|
|
388
|
+
const maybeBufferCtor = globalThis.Buffer;
|
|
389
|
+
if (maybeBufferCtor?.from)
|
|
390
|
+
return maybeBufferCtor.from(normalized, "base64").toString("utf8");
|
|
391
|
+
throw new Error("query(...): Unable to decode semantic.sidecarPath base64 payload in this runtime.");
|
|
392
|
+
}
|
|
325
393
|
function rerankLexicalHitsWithSemantic(pack, prelim, opts) {
|
|
394
|
+
if (opts.sidecar && opts.queryEmbedding) {
|
|
395
|
+
const sidecarResult = rerankCandidates({
|
|
396
|
+
lexical: prelim,
|
|
397
|
+
sidecar: opts.sidecar,
|
|
398
|
+
queryEmbedding: opts.queryEmbedding,
|
|
399
|
+
topN: opts.topN,
|
|
400
|
+
blend: opts.blend,
|
|
401
|
+
minSemanticScore: opts.minSemanticScore,
|
|
402
|
+
});
|
|
403
|
+
return { hits: sidecarResult.reranked, semanticScores: sidecarResult.semanticScores, blendedScores: sidecarResult.blendedScores };
|
|
404
|
+
}
|
|
326
405
|
const sem = pack.semantic;
|
|
327
406
|
if (!sem || !opts.queryEmbedding)
|
|
328
|
-
return prelim;
|
|
407
|
+
return { hits: prelim };
|
|
329
408
|
if (sem.dims <= 0 || sem.vecs.length === 0 || sem.dims !== opts.queryEmbedding.length)
|
|
330
|
-
return prelim;
|
|
409
|
+
return { hits: prelim };
|
|
331
410
|
const topN = Math.min(opts.topN, prelim.length);
|
|
332
411
|
const rerankSlice = prelim.slice(0, topN);
|
|
333
412
|
const tail = prelim.slice(topN);
|
|
@@ -342,15 +421,19 @@ function rerankLexicalHitsWithSemantic(pack, prelim, opts) {
|
|
|
342
421
|
const wLex = denom > 0 ? opts.blend.wLex / denom : 0.5;
|
|
343
422
|
const wSem = denom > 0 ? opts.blend.wSem / denom : 0.5;
|
|
344
423
|
const reranked = new Array(topN);
|
|
424
|
+
const semanticScores = new Map();
|
|
425
|
+
const blendedScores = new Map();
|
|
345
426
|
for (let i = 0; i < topN; i++) {
|
|
346
427
|
const hit = rerankSlice[i];
|
|
428
|
+
semanticScores.set(hit.blockId, normSem[i]);
|
|
429
|
+
blendedScores.set(hit.blockId, opts.blend.enabled ? wLex * normLex[i] + wSem * normSem[i] : semScores[i]);
|
|
347
430
|
reranked[i] = {
|
|
348
431
|
blockId: hit.blockId,
|
|
349
|
-
score:
|
|
432
|
+
score: blendedScores.get(hit.blockId) ?? hit.score,
|
|
350
433
|
};
|
|
351
434
|
}
|
|
352
435
|
reranked.sort((a, b) => b.score - a.score || a.blockId - b.blockId);
|
|
353
|
-
return [...reranked, ...tail];
|
|
436
|
+
return { hits: [...reranked, ...tail], semanticScores, blendedScores };
|
|
354
437
|
}
|
|
355
438
|
function scoreSemanticInt8(queryQ, queryScale, semantic, hits) {
|
|
356
439
|
const scores = new Float64Array(hits.length);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function normalizeVector(vector) {
|
|
2
|
+
let normSq = 0;
|
|
3
|
+
for (let i = 0; i < vector.length; i++)
|
|
4
|
+
normSq += vector[i] * vector[i];
|
|
5
|
+
const norm = Math.sqrt(normSq);
|
|
6
|
+
if (!norm)
|
|
7
|
+
return new Float32Array(vector.length);
|
|
8
|
+
const out = new Float32Array(vector.length);
|
|
9
|
+
for (let i = 0; i < vector.length; i++)
|
|
10
|
+
out[i] = vector[i] / norm;
|
|
11
|
+
return out;
|
|
12
|
+
}
|
|
13
|
+
export function cosineSimilarity(a, b) {
|
|
14
|
+
if (a.length !== b.length || a.length === 0)
|
|
15
|
+
return 0;
|
|
16
|
+
let dot = 0;
|
|
17
|
+
for (let i = 0; i < a.length; i++)
|
|
18
|
+
dot += a[i] * b[i];
|
|
19
|
+
return dot;
|
|
20
|
+
}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { EmbeddingProvider, SemanticQueryOptions } from './types.js';
|
|
2
|
+
export declare function ensureProviderModelId(options?: SemanticQueryOptions): string | undefined;
|
|
3
|
+
export declare function assertProviderCompatible(options?: SemanticQueryOptions, provider?: EmbeddingProvider): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function ensureProviderModelId(options) {
|
|
2
|
+
return options?.provider?.modelId;
|
|
3
|
+
}
|
|
4
|
+
export function assertProviderCompatible(options, provider) {
|
|
5
|
+
if (!options?.enabled)
|
|
6
|
+
return;
|
|
7
|
+
if (!provider && !options.queryEmbedding) {
|
|
8
|
+
throw new Error('semantic.enabled=true requires either semantic.queryEmbedding or an EmbeddingProvider.');
|
|
9
|
+
}
|
|
10
|
+
if (provider && options.provider?.modelId && options.provider.modelId !== provider.modelId) {
|
|
11
|
+
throw new Error(`Semantic provider model mismatch: options requested ${options.provider.modelId}, provider exposes ${provider.modelId}.`);
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { SemanticSidecar } from './types.js';
|
|
2
|
+
export declare function rerankCandidates(params: {
|
|
3
|
+
lexical: Array<{
|
|
4
|
+
blockId: number;
|
|
5
|
+
score: number;
|
|
6
|
+
}>;
|
|
7
|
+
sidecar: SemanticSidecar;
|
|
8
|
+
queryEmbedding: Float32Array;
|
|
9
|
+
topN: number;
|
|
10
|
+
blend: {
|
|
11
|
+
enabled: boolean;
|
|
12
|
+
wLex: number;
|
|
13
|
+
wSem: number;
|
|
14
|
+
};
|
|
15
|
+
minSemanticScore?: number;
|
|
16
|
+
}): {
|
|
17
|
+
reranked: Array<{
|
|
18
|
+
blockId: number;
|
|
19
|
+
score: number;
|
|
20
|
+
}>;
|
|
21
|
+
semanticScores: Map<number, number>;
|
|
22
|
+
blendedScores: Map<number, number>;
|
|
23
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { cosineSimilarity, normalizeVector } from './cosine.js';
|
|
2
|
+
export function rerankCandidates(params) {
|
|
3
|
+
const topN = Math.min(params.topN, params.lexical.length);
|
|
4
|
+
const head = params.lexical.slice(0, topN);
|
|
5
|
+
const tail = params.lexical.slice(topN);
|
|
6
|
+
const q = normalizeVector(params.queryEmbedding);
|
|
7
|
+
const semanticScores = new Map();
|
|
8
|
+
const blendedScores = new Map();
|
|
9
|
+
const lexNorm = minMax(head.map((h) => h.score));
|
|
10
|
+
const semRaw = [];
|
|
11
|
+
for (const item of head) {
|
|
12
|
+
const rec = params.sidecar.blocks.find((b) => b.blockId === item.blockId);
|
|
13
|
+
const vec = rec ? Float32Array.from(rec.vector) : new Float32Array(q.length);
|
|
14
|
+
semRaw.push(cosineSimilarity(q, vec));
|
|
15
|
+
}
|
|
16
|
+
const semNorm = minMax(semRaw);
|
|
17
|
+
const denom = params.blend.wLex + params.blend.wSem;
|
|
18
|
+
const wLex = denom > 0 ? params.blend.wLex / denom : 0.7;
|
|
19
|
+
const wSem = denom > 0 ? params.blend.wSem / denom : 0.3;
|
|
20
|
+
const reranked = head.map((item, idx) => {
|
|
21
|
+
const sem = semNorm[idx];
|
|
22
|
+
semanticScores.set(item.blockId, sem);
|
|
23
|
+
if ((params.minSemanticScore ?? 0) > sem) {
|
|
24
|
+
blendedScores.set(item.blockId, lexNorm[idx]);
|
|
25
|
+
return { blockId: item.blockId, score: lexNorm[idx] };
|
|
26
|
+
}
|
|
27
|
+
const blended = params.blend.enabled ? wLex * lexNorm[idx] + wSem * sem : sem;
|
|
28
|
+
blendedScores.set(item.blockId, blended);
|
|
29
|
+
return { blockId: item.blockId, score: blended };
|
|
30
|
+
});
|
|
31
|
+
reranked.sort((a, b) => b.score - a.score || a.blockId - b.blockId);
|
|
32
|
+
return { reranked: [...reranked, ...tail], semanticScores, blendedScores };
|
|
33
|
+
}
|
|
34
|
+
function minMax(values) {
|
|
35
|
+
if (values.length === 0)
|
|
36
|
+
return values;
|
|
37
|
+
const min = Math.min(...values);
|
|
38
|
+
const max = Math.max(...values);
|
|
39
|
+
if (!Number.isFinite(min) || !Number.isFinite(max) || max <= min)
|
|
40
|
+
return values.map(() => 1);
|
|
41
|
+
return values.map((v) => Math.min(1, Math.max(0, (v - min) / (max - min))));
|
|
42
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Pack } from '../pack.runtime.js';
|
|
2
|
+
import type { SemanticSidecar } from './types.js';
|
|
3
|
+
export declare function createPackFingerprint(pack: Pick<Pack, 'blocks' | 'docIds' | 'meta'>): string;
|
|
4
|
+
export declare function serializeSidecar(sidecar: SemanticSidecar): string;
|
|
5
|
+
export declare function parseSidecar(raw: string): SemanticSidecar;
|
|
6
|
+
export declare function validateSidecarForPack(input: {
|
|
7
|
+
sidecar: SemanticSidecar;
|
|
8
|
+
pack: Pick<Pack, 'blocks' | 'docIds' | 'meta'>;
|
|
9
|
+
modelId: string;
|
|
10
|
+
}): void;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function createPackFingerprint(pack) {
|
|
2
|
+
let hash = 2166136261;
|
|
3
|
+
const parts = [String(pack.meta?.version ?? 0), ...(pack.docIds ?? []), ...pack.blocks];
|
|
4
|
+
for (const part of parts) {
|
|
5
|
+
const text = String(part ?? '');
|
|
6
|
+
for (let i = 0; i < text.length; i++) {
|
|
7
|
+
hash ^= text.charCodeAt(i);
|
|
8
|
+
hash = Math.imul(hash, 16777619);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
return `fnv1a-${(hash >>> 0).toString(16).padStart(8, '0')}`;
|
|
12
|
+
}
|
|
13
|
+
export function serializeSidecar(sidecar) {
|
|
14
|
+
return `${JSON.stringify(sidecar, null, 2)}\n`;
|
|
15
|
+
}
|
|
16
|
+
export function parseSidecar(raw) {
|
|
17
|
+
const parsed = JSON.parse(raw);
|
|
18
|
+
if (parsed.version !== 1)
|
|
19
|
+
throw new Error(`Unsupported semantic sidecar version: ${parsed.version}`);
|
|
20
|
+
if (parsed.metric !== 'cosine')
|
|
21
|
+
throw new Error(`Unsupported semantic metric: ${parsed.metric}`);
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
export function validateSidecarForPack(input) {
|
|
25
|
+
const expectedFingerprint = createPackFingerprint(input.pack);
|
|
26
|
+
if (input.sidecar.packFingerprint !== expectedFingerprint) {
|
|
27
|
+
throw new Error(`Semantic sidecar pack fingerprint mismatch: expected ${expectedFingerprint}, got ${input.sidecar.packFingerprint}. Regenerate the sidecar for this pack.`);
|
|
28
|
+
}
|
|
29
|
+
if (input.sidecar.modelId !== input.modelId) {
|
|
30
|
+
throw new Error(`Semantic model mismatch: sidecar model is ${input.sidecar.modelId}, but query provider is ${input.modelId}. Use the same embedding model or regenerate the sidecar.`);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export interface EmbeddingProvider {
|
|
2
|
+
readonly modelId: string;
|
|
3
|
+
embedQuery(text: string): Promise<Float32Array>;
|
|
4
|
+
embedTexts(texts: string[]): Promise<Float32Array[]>;
|
|
5
|
+
}
|
|
6
|
+
export interface SemanticSidecar {
|
|
7
|
+
version: 1;
|
|
8
|
+
packFingerprint: string;
|
|
9
|
+
modelId: string;
|
|
10
|
+
dimension: number;
|
|
11
|
+
metric: 'cosine';
|
|
12
|
+
createdAt: string;
|
|
13
|
+
blocks: Array<{
|
|
14
|
+
blockId: number;
|
|
15
|
+
vector: number[];
|
|
16
|
+
}>;
|
|
17
|
+
}
|
|
18
|
+
export type SemanticQueryOptions = {
|
|
19
|
+
enabled?: boolean;
|
|
20
|
+
mode?: 'rerank';
|
|
21
|
+
topN?: number;
|
|
22
|
+
minLexConfidence?: number;
|
|
23
|
+
minSemanticScore?: number;
|
|
24
|
+
blend?: {
|
|
25
|
+
enabled?: boolean;
|
|
26
|
+
wLex?: number;
|
|
27
|
+
wSem?: number;
|
|
28
|
+
};
|
|
29
|
+
provider?: {
|
|
30
|
+
type: 'ollama';
|
|
31
|
+
modelId: string;
|
|
32
|
+
endpoint?: string;
|
|
33
|
+
};
|
|
34
|
+
sidecarPath?: string;
|
|
35
|
+
queryEmbedding?: Float32Array;
|
|
36
|
+
force?: boolean;
|
|
37
|
+
};
|
|
38
|
+
export type RetrievalEvidence = {
|
|
39
|
+
retrieval: 'lexical' | 'hybrid';
|
|
40
|
+
lexicalScore?: number;
|
|
41
|
+
semanticScore?: number;
|
|
42
|
+
blendedScore?: number;
|
|
43
|
+
modelId?: string;
|
|
44
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knolo/core",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Local-first knowledge packs for small LLMs.",
|
|
6
6
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"build": "tsc -p tsconfig.json",
|
|
35
35
|
"prepublishOnly": "npm run build",
|
|
36
36
|
"smoke": "node scripts/smoke.mjs",
|
|
37
|
-
"test": "npm run build && node scripts/check-runtime-no-node.mjs && node scripts/test.mjs",
|
|
37
|
+
"test": "npm run build && node scripts/check-runtime-no-node.mjs && node --test test/*.test.mjs && node scripts/test.mjs",
|
|
38
38
|
"format": "prettier --write src/agent.ts src/pack.ts src/pack.runtime.ts src/pack.node.ts src/node.ts src/builder.ts src/index.ts scripts/test.mjs scripts/check-runtime-no-node.mjs ../../README.md README.md",
|
|
39
39
|
"format:check": "prettier --check src/agent.ts src/pack.ts src/pack.runtime.ts src/pack.node.ts src/node.ts src/builder.ts src/index.ts scripts/test.mjs scripts/check-runtime-no-node.mjs ../../README.md README.md",
|
|
40
40
|
"check:runtime-no-node": "node scripts/check-runtime-no-node.mjs"
|