feat(EMBEDDINGS-0001): enable local embedder by default and overhaul settings page
- Wire local embedding provider as the default on startup when no profile is configured - Refactor embedding settings into dedicated service, DTOs, mappers and models - Rebuild settings page with profile management UI and live test feedback - Expose index summary (indexed versions + embedding count) on repo endpoints - Harden indexing pipeline and context search with additional test coverage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,16 +27,20 @@ function createTestDb(): Database.Database {
|
||||
client.pragma('foreign_keys = ON');
|
||||
|
||||
const migrationsFolder = join(import.meta.dirname, '../db/migrations');
|
||||
const migrationSql = readFileSync(join(migrationsFolder, '0000_large_master_chief.sql'), 'utf-8');
|
||||
|
||||
// Drizzle migration files use `--> statement-breakpoint` as separator.
|
||||
const statements = migrationSql
|
||||
.split('--> statement-breakpoint')
|
||||
.map((s) => s.trim())
|
||||
.filter(Boolean);
|
||||
for (const migration of [
|
||||
'0000_large_master_chief.sql',
|
||||
'0001_quick_nighthawk.sql',
|
||||
'0002_silky_stellaris.sql'
|
||||
]) {
|
||||
const statements = readFileSync(join(migrationsFolder, migration), 'utf-8')
|
||||
.split('--> statement-breakpoint')
|
||||
.map((statement) => statement.trim())
|
||||
.filter(Boolean);
|
||||
|
||||
for (const stmt of statements) {
|
||||
client.exec(stmt);
|
||||
for (const statement of statements) {
|
||||
client.exec(statement);
|
||||
}
|
||||
}
|
||||
|
||||
return client;
|
||||
@@ -408,6 +412,83 @@ describe('RepositoryService.getVersions()', () => {
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// getIndexSummary()
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
describe('RepositoryService.getIndexSummary()', () => {
|
||||
let client: Database.Database;
|
||||
let service: RepositoryService;
|
||||
|
||||
beforeEach(() => {
|
||||
client = createTestDb();
|
||||
service = makeService(client);
|
||||
service.add({ source: 'github', sourceUrl: 'https://github.com/facebook/react', branch: 'main' });
|
||||
});
|
||||
|
||||
it('returns embedding counts and indexed version labels', () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const docId = crypto.randomUUID();
|
||||
const versionDocId = crypto.randomUUID();
|
||||
const snippetId = crypto.randomUUID();
|
||||
const versionSnippetId = crypto.randomUUID();
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO repository_versions (id, repository_id, tag, state, created_at)
|
||||
VALUES (?, '/facebook/react', ?, 'indexed', ?)`
|
||||
)
|
||||
.run('/facebook/react/v18.3.0', 'v18.3.0', now);
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO documents (id, repository_id, version_id, file_path, checksum, indexed_at)
|
||||
VALUES (?, '/facebook/react', NULL, 'README.md', 'base', ?)`
|
||||
)
|
||||
.run(docId, now);
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO documents (id, repository_id, version_id, file_path, checksum, indexed_at)
|
||||
VALUES (?, '/facebook/react', ?, 'README.md', 'version', ?)`
|
||||
)
|
||||
.run(versionDocId, '/facebook/react/v18.3.0', now);
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO snippets (id, document_id, repository_id, version_id, type, content, created_at)
|
||||
VALUES (?, ?, '/facebook/react', NULL, 'info', 'base snippet', ?)`
|
||||
)
|
||||
.run(snippetId, docId, now);
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO snippets (id, document_id, repository_id, version_id, type, content, created_at)
|
||||
VALUES (?, ?, '/facebook/react', ?, 'info', 'version snippet', ?)`
|
||||
)
|
||||
.run(versionSnippetId, versionDocId, '/facebook/react/v18.3.0', now);
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO snippet_embeddings (snippet_id, profile_id, model, dimensions, embedding, created_at)
|
||||
VALUES (?, 'local-default', 'Xenova/all-MiniLM-L6-v2', 2, ?, ?)`
|
||||
)
|
||||
.run(snippetId, Buffer.from(Float32Array.from([1, 0]).buffer), now);
|
||||
|
||||
client
|
||||
.prepare(
|
||||
`INSERT INTO snippet_embeddings (snippet_id, profile_id, model, dimensions, embedding, created_at)
|
||||
VALUES (?, 'local-default', 'Xenova/all-MiniLM-L6-v2', 2, ?, ?)`
|
||||
)
|
||||
.run(versionSnippetId, Buffer.from(Float32Array.from([0, 1]).buffer), now);
|
||||
|
||||
expect(service.getIndexSummary('/facebook/react')).toEqual({
|
||||
embeddingCount: 2,
|
||||
indexedVersions: ['main', 'v18.3.0']
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// createIndexingJob()
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user