| 73 | * - For very large single-user datasets (>100K vectors), consider partial HNSW indexes |
| 74 | */ |
| 75 | export class PgVectorProvider implements IVectorProvider { |
| 76 | private prisma: PrismaClient; |
| 77 | private dimensions: number; |
| 78 | private infrastructureInitialized = false; |
| 79 | |
| 80 | private readonly INDEX_CONFIGS = [ |
| 81 | { |
| 82 | table: "statement_embeddings", |
| 83 | name: "statement_embeddings_vector_idx", |
| 84 | }, |
| 85 | { |
| 86 | table: "episode_embeddings", |
| 87 | name: "episode_embeddings_vector_idx", |
| 88 | }, |
| 89 | { |
| 90 | table: "entity_embeddings", |
| 91 | name: "entity_embeddings_vector_idx", |
| 92 | }, |
| 93 | { |
| 94 | table: "compacted_session_embeddings", |
| 95 | name: "compacted_session_embeddings_vector_idx", |
| 96 | }, |
| 97 | { |
| 98 | table: "label_embeddings", |
| 99 | name: "label_embeddings_vector_idx", |
| 100 | }, |
| 101 | { |
| 102 | table: "voice_aspect_embeddings", |
| 103 | name: "voice_aspect_embeddings_vector_idx", |
| 104 | }, |
| 105 | ] as const; |
| 106 | |
| 107 | constructor(config: PgVectorConfig) { |
| 108 | this.prisma = config.prisma; |
| 109 | this.dimensions = config.dimensions |
| 110 | ?? (process.env.EMBEDDING_MODEL_SIZE |
| 111 | ? parseInt(process.env.EMBEDDING_MODEL_SIZE, 10) |
| 112 | : 1024); |
| 113 | } |
| 114 | |
| 115 | /** |
| 116 | * Initialize HNSW indexes for all embedding tables |
| 117 | * This method is idempotent and safe to call multiple times |
| 118 | * |
| 119 | * @returns true if initialization succeeded or was already done, false on failure |
| 120 | */ |
| 121 | async initializeInfrastructure(): Promise<boolean> { |
| 122 | if (this.infrastructureInitialized) { |
| 123 | console.log("[PgVector] Infrastructure already initialized, skipping..."); |
| 124 | return true; |
| 125 | } |
| 126 | |
| 127 | try { |
| 128 | console.log(`[PgVector] Initializing HNSW indexes with dimension ${this.dimensions}...`); |
| 129 | |
| 130 | // Create indexes if they don't exist |
| 131 | for (const { table, name } of this.INDEX_CONFIGS) { |
| 132 | await this.ensureIndex(table, name); |
nothing calls this directly
no outgoing calls
no test coverage detected