fix: harden Voyage schema templating

This commit is contained in:
Eva
2026-05-06 17:55:28 -07:00
committed by Garry Tan
parent 3004a87550
commit d52d4fd617
2 changed files with 34 additions and 3 deletions
+17 -3
View File
@@ -25,6 +25,22 @@ import { validateSlug, contentHash, rowToPage, rowToChunk, rowToSearchResult, pa
import { resolveBoostMap, resolveHardExcludes } from './search/source-boost.ts';
import { buildSourceFactorCase, buildHardExcludeClause, buildVisibilityClause } from './search/sql-ranking.ts';
function escapeSqlStringLiteral(value: string): string {
return value.replace(/'/g, "''");
}
export function getPostgresSchema(dims: number = 1536, model: string = 'text-embedding-3-large'): string {
const parsedDims = Number(dims);
if (!Number.isInteger(parsedDims) || parsedDims <= 0) {
throw new Error(`Invalid embedding dimensions: ${dims}`);
}
const sanitizedModel = escapeSqlStringLiteral(String(model));
return applyChunkEmbeddingIndexPolicy(SCHEMA_SQL, parsedDims)
.replace(/vector\(1536\)/g, `vector(${parsedDims})`)
.replace(/'text-embedding-3-large'/g, `'${sanitizedModel}'`)
.replace(/\('embedding_dimensions', '1536'\)/g, `('embedding_dimensions', '${parsedDims}')`);
}
// CONNECTION_ERROR_PATTERNS / isConnectionError were used by the per-call
// executeRaw retry that #406 originally shipped. Eng-review D3 dropped that
// retry as unsound (regex idempotence-boundary doesn't hold for writable
@@ -111,9 +127,7 @@ export class PostgresEngine implements BrainEngine {
model = gw.getEmbeddingModel().split(':').slice(1).join(':') || model;
} catch { /* gateway not yet configured — use defaults */ }
const sql = applyChunkEmbeddingIndexPolicy(SCHEMA_SQL, dims)
.replace(/vector\(1536\)/g, `vector(${dims})`)
.replace(/'text-embedding-3-large'/g, `'${model}'`);
const sql = getPostgresSchema(dims, model);
// Advisory lock prevents concurrent initSchema() calls from deadlocking
// on DDL statements (DROP TRIGGER + CREATE TRIGGER acquire AccessExclusiveLock).
+17
View File
@@ -1,5 +1,6 @@
import { describe, test, expect } from 'bun:test';
import { getPGLiteSchema, PGLITE_SCHEMA_SQL } from '../../src/core/pglite-schema.ts';
import { getPostgresSchema } from '../../src/core/postgres-engine.ts';
describe('getPGLiteSchema', () => {
test('default produces v0.13-compatible schema (1536d + text-embedding-3-large)', () => {
@@ -41,3 +42,19 @@ describe('getPGLiteSchema', () => {
expect(PGLITE_SCHEMA_SQL).toBe(getPGLiteSchema());
});
});
describe('getPostgresSchema', () => {
test('Voyage 2048d updates vector column and seeded config but skips HNSW', () => {
const sql = getPostgresSchema(2048, 'voyage-4-large');
expect(sql).toMatch(/vector\(2048\)/);
expect(sql).toMatch(/\('embedding_model', 'voyage-4-large'\)/);
expect(sql).toMatch(/\('embedding_dimensions', '2048'\)/);
expect(sql).not.toContain('idx_chunks_embedding ON content_chunks USING hnsw');
});
test('escapes configured model before inserting into schema SQL literals', () => {
const sql = getPostgresSchema(1024, "voyage-weird'quoted");
expect(sql).toContain("'voyage-weird''quoted'");
expect(sql).not.toContain("'voyage-weird'quoted'");
});
});