mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-22 08:38:08 +02:00
Initial open-source release
This commit is contained in:
commit
1a42152e6f
1199 changed files with 257054 additions and 0 deletions
115
packages/context/src/wiki/sqlite-knowledge-index.test.ts
Normal file
115
packages/context/src/wiki/sqlite-knowledge-index.test.ts
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import { access, mkdtemp, rm } from 'node:fs/promises';
|
||||
import { tmpdir } from 'node:os';
|
||||
import { join } from 'node:path';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
import { SqliteKnowledgeIndex, type SqliteKnowledgeIndexPage } from './sqlite-knowledge-index.js';
|
||||
|
||||
describe('SqliteKnowledgeIndex', () => {
|
||||
let tempDir: string;
|
||||
let dbPath: string;
|
||||
|
||||
beforeEach(async () => {
|
||||
tempDir = await mkdtemp(join(tmpdir(), 'klo-sqlite-knowledge-index-'));
|
||||
dbPath = join(tempDir, 'db.sqlite');
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await rm(tempDir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
function page(overrides: Partial<SqliteKnowledgeIndexPage> = {}): SqliteKnowledgeIndexPage {
|
||||
return {
|
||||
path: 'knowledge/global/revenue.md',
|
||||
key: 'revenue',
|
||||
scope: 'GLOBAL',
|
||||
summary: 'Revenue definition',
|
||||
content: 'Revenue is the sum of paid order amounts.',
|
||||
tags: ['finance'],
|
||||
embedding: null,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
it('creates a SQLite FTS5 index and returns lexical lane candidates', async () => {
|
||||
const index = new SqliteKnowledgeIndex({ dbPath });
|
||||
|
||||
index.sync([
|
||||
page(),
|
||||
page({
|
||||
path: 'knowledge/global/support.md',
|
||||
key: 'support',
|
||||
summary: 'Support queue',
|
||||
content: 'Tickets are grouped by priority.',
|
||||
tags: ['operations'],
|
||||
}),
|
||||
]);
|
||||
|
||||
await expect(access(dbPath)).resolves.toBeUndefined();
|
||||
expect(index.searchLexicalCandidates({ queryText: 'paid order', limit: 10 })).toEqual([
|
||||
expect.objectContaining({
|
||||
id: 'knowledge/global/revenue.md',
|
||||
path: 'knowledge/global/revenue.md',
|
||||
rank: 1,
|
||||
rawScore: expect.any(Number),
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('removes stale rows when the Markdown source list changes', () => {
|
||||
const index = new SqliteKnowledgeIndex({ dbPath });
|
||||
index.rebuild([page(), page({ path: 'knowledge/global/churn.md', key: 'churn', content: 'Churn risk.' })]);
|
||||
expect(index.search('churn', 10)).toHaveLength(1);
|
||||
|
||||
index.rebuild([page()]);
|
||||
|
||||
expect(index.search('churn', 10)).toEqual([]);
|
||||
});
|
||||
|
||||
it('exposes existing search text and embedding state for incremental refresh', () => {
|
||||
const index = new SqliteKnowledgeIndex({ dbPath });
|
||||
index.sync([page({ path: 'knowledge/global/revenue.md', key: 'revenue', embedding: [1, 0] })]);
|
||||
|
||||
expect(index.getExistingPages()).toEqual(
|
||||
new Map([
|
||||
[
|
||||
'knowledge/global/revenue.md',
|
||||
expect.objectContaining({
|
||||
searchText: expect.stringContaining('Revenue definition'),
|
||||
embedding: [1, 0],
|
||||
}),
|
||||
],
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
it('returns semantic lane candidates from stored page embeddings', () => {
|
||||
const index = new SqliteKnowledgeIndex({ dbPath });
|
||||
index.sync([
|
||||
page({ path: 'knowledge/global/revenue.md', key: 'revenue', embedding: [1, 0] }),
|
||||
page({ path: 'knowledge/global/support.md', key: 'support', summary: 'Support queue', embedding: [0, 1] }),
|
||||
]);
|
||||
|
||||
expect(index.searchSemanticCandidates({ queryEmbedding: [1, 0], limit: 10 })).toEqual([
|
||||
expect.objectContaining({
|
||||
id: 'knowledge/global/revenue.md',
|
||||
path: 'knowledge/global/revenue.md',
|
||||
rank: 1,
|
||||
rawScore: 1,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'knowledge/global/support.md',
|
||||
path: 'knowledge/global/support.md',
|
||||
rank: 2,
|
||||
rawScore: 0,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns an empty result for blank or punctuation-only queries', () => {
|
||||
const index = new SqliteKnowledgeIndex({ dbPath });
|
||||
index.rebuild([page()]);
|
||||
|
||||
expect(index.search(' ', 10)).toEqual([]);
|
||||
expect(index.search('---', 10)).toEqual([]);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue