@@ -16,7 +16,7 @@ import { IRange, Range } from '../../../util/vs/editor/common/core/range';
1616import { IInstantiationService , ServicesAccessor } from '../../../util/vs/platform/instantiation/common/instantiation' ;
1717import { FileChunk , FileChunkWithEmbedding } from '../../chunking/common/chunk' ;
1818import { stripChunkTextMetadata } from '../../chunking/common/chunkingStringUtils' ;
19- import { EmbeddingType , EmbeddingVector } from '../../embeddings/common/embeddingsComputer' ;
19+ import { Embedding , EmbeddingType , EmbeddingVector } from '../../embeddings/common/embeddingsComputer' ;
2020import { IFileSystemService } from '../../filesystem/common/fileSystemService' ;
2121import { ILogService } from '../../log/common/logService' ;
2222import { FileRepresentation , IWorkspaceFileIndex } from './workspaceFileIndex' ;
@@ -430,7 +430,6 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
430430 db . exec ( 'DELETE FROM CacheMeta;' ) ;
431431 db . prepare ( 'INSERT INTO CacheMeta (version, embeddingModel) VALUES (?, ?)' ) . run ( this . version , embeddingType . id ) ;
432432
433-
434433 // Load existing disk db if it exists
435434 const diskCache = await instantiationService . invokeFunction ( accessor => DiskCache . readDiskCache (
436435 accessor ,
@@ -456,7 +455,10 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
456455 chunk . range . startColumn ,
457456 chunk . range . endLineNumber ,
458457 chunk . range . endColumn ,
459- Float32Array . from ( typeof chunk . embedding === 'string' ? DiskCache . decodeEmbedding ( chunk . embedding ) : chunk . embedding ) ,
458+ packEmbedding ( {
459+ type : embeddingType ,
460+ value : typeof chunk . embedding === 'string' ? DiskCache . decodeEmbedding ( chunk . embedding ) : chunk . embedding ,
461+ } ) ,
460462 chunk . chunkHash ?? ''
461463 ) ;
462464 }
@@ -532,8 +534,7 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
532534 if ( all . length > 0 ) {
533535 const out = new Map < string , FileChunkWithEmbedding > ( ) ;
534536 for ( const row of all ) {
535- const embeddingData = row . embedding as Uint8Array ;
536- const embedding = Array . from ( new Float32Array ( embeddingData . buffer , embeddingData . byteOffset , embeddingData . byteLength / Float32Array . BYTES_PER_ELEMENT ) ) ;
537+ const embedding = unpackEmbedding ( this . embeddingType , row . embedding as Uint8Array ) ;
537538
538539 const chunk : FileChunkWithEmbedding = {
539540 chunk : {
@@ -542,10 +543,7 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
542543 rawText : undefined ,
543544 range : new Range ( row . range_startLineNumber as number , row . range_startColumn as number , row . range_endLineNumber as number , row . range_endColumn as number ) ,
544545 } ,
545- embedding : {
546- type : this . embeddingType ,
547- value : embedding ,
548- } ,
546+ embedding,
549547 chunkHash : row . chunkHash as string ,
550548 } ;
551549 if ( chunk . chunkHash ) {
@@ -576,18 +574,14 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
576574 contentVersionId : fileIdResult . contentVersionId as string | undefined ,
577575 fileHash : undefined ,
578576 value : chunks . map ( ( row ) : FileChunkWithEmbedding => {
579- const embeddingData = row . embedding as Uint8Array ;
580577 return {
581578 chunk : {
582579 file : file . uri ,
583580 text : row . text as string ,
584581 rawText : undefined ,
585582 range : new Range ( row . range_startLineNumber as number , row . range_startColumn as number , row . range_endLineNumber as number , row . range_endColumn as number ) ,
586583 } ,
587- embedding : {
588- type : this . embeddingType ,
589- value : Array . from ( new Float32Array ( embeddingData . buffer , embeddingData . byteOffset , embeddingData . byteLength / Float32Array . BYTES_PER_ELEMENT ) ) ,
590- } ,
584+ embedding : unpackEmbedding ( this . embeddingType , row . embedding as Uint8Array ) ,
591585 chunkHash : row . chunkHash as string | undefined ,
592586 } ;
593587 } ) ,
@@ -643,16 +637,14 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
643637
644638 this . db . exec ( 'BEGIN TRANSACTION' ) ;
645639 for ( const chunk of newEntry . value ?? [ ] ) {
646- const float32Array = Float32Array . from ( chunk . embedding . value ) ;
647- const embeddingData = new Uint8Array ( float32Array . buffer , float32Array . byteOffset , float32Array . byteLength ) ;
648640 insertStatement . run (
649641 fileResult . lastInsertRowid as number ,
650642 chunk . chunk . text ,
651643 chunk . chunk . range . startLineNumber ,
652644 chunk . chunk . range . startColumn ,
653645 chunk . chunk . range . endLineNumber ,
654646 chunk . chunk . range . endColumn ,
655- embeddingData ,
647+ packEmbedding ( chunk . embedding ) ,
656648 chunk . chunkHash ?? '' ,
657649 ) ;
658650 }
@@ -665,4 +657,52 @@ class DbCache implements IWorkspaceChunkAndEmbeddingCache {
665657
666658 return chunks ;
667659 }
660+ }
661+
662+ /**
663+ * Packs the embedding into a binary value for efficient storage.
664+ */
665+ export function packEmbedding ( embedding : Embedding ) : Uint8Array {
666+ if ( embedding . type . equals ( EmbeddingType . metis_1024_I16_Binary ) ) {
667+ // Generate packed binary
668+ if ( embedding . value . length % 8 !== 0 ) {
669+ throw new Error ( `Embedding value length must be a multiple of 8 for ${ embedding . type . id } , got ${ embedding . value . length } ` ) ;
670+ }
671+
672+ const data = new Uint8Array ( embedding . value . length / 8 ) ;
673+ for ( let i = 0 ; i < embedding . value . length ; i += 8 ) {
674+ let value = 0 ;
675+ for ( let j = 0 ; j < 8 ; j ++ ) {
676+ value |= ( embedding . value [ i + j ] >= 0 ? 1 : 0 ) << j ;
677+ }
678+ data [ i / 8 ] = value ;
679+ }
680+ return data ;
681+ }
682+
683+ // All other formats default to float32 for now
684+ const data = Float32Array . from ( embedding . value ) ;
685+ return new Uint8Array ( data . buffer , data . byteOffset , data . byteLength ) ;
686+ }
687+
688+ /**
689+ * Unpacks an embedding from a binary value packed with {@link packEmbedding}.
690+ */
691+ export function unpackEmbedding ( type : EmbeddingType , data : Uint8Array ) : Embedding {
692+ if ( type . equals ( EmbeddingType . metis_1024_I16_Binary ) ) {
693+ // Old versions may have stored the values as a float32
694+ if ( data . length <= 1024 ) {
695+ const values = new Array ( data . length * 8 ) ;
696+ for ( let i = 0 ; i < data . length ; i ++ ) {
697+ const byte = data [ i ] ;
698+ for ( let j = 0 ; j < 8 ; j ++ ) {
699+ values [ i * 8 + j ] = ( byte & ( 1 << j ) ) > 0 ? 0.03125 : - 0.03125 ;
700+ }
701+ }
702+ return { type, value : values } ;
703+ }
704+ }
705+
706+ const float32Array = new Float32Array ( data . buffer , data . byteOffset , data . byteLength / 4 ) ;
707+ return { type, value : Array . from ( float32Array ) } ;
668708}
0 commit comments