@@ -3,6 +3,7 @@ import { canonical_token_set } from '../utils/text'
33import { inc_q , dec_q } from './decay'
44import { env , tier } from '../core/cfg'
55import { cos_sim , buf_to_vec , vec_to_buf } from '../utils/index'
6+ import { dbq } from '../core/queue'
67export interface sector_cfg {
78 model : string
89 decay_lambda : number
@@ -672,86 +673,88 @@ export async function add_hsg_memory(
672673 metadata ?: any ,
673674 user_id ?: string
674675) : Promise < { id : string , primary_sector : string , sectors : string [ ] , chunks ?: number , deduplicated ?: boolean } > {
675- const simhash = compute_simhash ( content )
676- const existing = await q . get_mem_by_simhash . get ( simhash )
677- if ( existing && hamming_dist ( simhash , existing . simhash ) <= 3 ) {
678- const now = Date . now ( )
679- const boosted_sal = Math . min ( 1 , existing . salience + 0.15 )
680- await q . upd_seen . run ( existing . id , now , boosted_sal , now )
681- return {
682- id : existing . id ,
683- primary_sector : existing . primary_sector ,
684- sectors : [ existing . primary_sector ] ,
685- deduplicated : true
686- }
687- }
688- const id = crypto . randomUUID ( )
689- const now = Date . now ( )
690- const chunks = chunk_text ( content )
691- const use_chunking = chunks . length > 1
692- const classification = classify_content ( content , metadata )
693- const all_sectors = [ classification . primary , ...classification . additional ]
694- await transaction . begin ( )
695- try {
696- const max_seg_res = await q . get_max_segment . get ( )
697- let cur_seg = max_seg_res ?. max_seg ?? 0
698- const seg_cnt_res = await q . get_segment_count . get ( cur_seg )
699- const seg_cnt = seg_cnt_res ?. c ?? 0
700- if ( seg_cnt >= env . seg_size ) {
701- cur_seg ++
702- console . log ( `[HSG] Rotated to segment ${ cur_seg } (previous segment full: ${ seg_cnt } memories)` )
703- }
704- const stored_content = extract_essence ( content , classification . primary , env . summary_max_length )
705- const sec_cfg = sector_configs [ classification . primary ]
706- const init_sal = Math . max ( 0 , Math . min ( 1 , 0.4 + 0.1 * classification . additional . length ) )
707- await q . ins_mem . run (
708- id ,
709- user_id || null ,
710- cur_seg ,
711- stored_content ,
712- simhash ,
713- classification . primary ,
714- tags || null ,
715- JSON . stringify ( metadata || { } ) ,
716- now ,
717- now ,
718- now ,
719- init_sal ,
720- sec_cfg . decay_lambda ,
721- 1 ,
722- null ,
723- null ,
724- null , // compressed_vec
725- 0 // feedback_score
726- )
727- const emb_res = await embedMultiSector ( id , content , all_sectors , use_chunking ? chunks : undefined )
728- for ( const result of emb_res ) {
729- const vec_buf = vectorToBuffer ( result . vector )
730- await q . ins_vec . run ( id , result . sector , vec_buf , result . dim )
676+ return dbq . exec ( async ( ) => {
677+ const simhash = compute_simhash ( content )
678+ const existing = await q . get_mem_by_simhash . get ( simhash )
679+ if ( existing && hamming_dist ( simhash , existing . simhash ) <= 3 ) {
680+ const now = Date . now ( )
681+ const boosted_sal = Math . min ( 1 , existing . salience + 0.15 )
682+ await q . upd_seen . run ( existing . id , now , boosted_sal , now )
683+ return {
684+ id : existing . id ,
685+ primary_sector : existing . primary_sector ,
686+ sectors : [ existing . primary_sector ] ,
687+ deduplicated : true
688+ }
731689 }
732- const mean_vec = calc_mean_vec ( emb_res , all_sectors )
733- const mean_vec_buf = vectorToBuffer ( mean_vec )
734- await q . upd_mean_vec . run ( id , mean_vec . length , mean_vec_buf )
690+ const id = crypto . randomUUID ( )
691+ const now = Date . now ( )
692+ const chunks = chunk_text ( content )
693+ const use_chunking = chunks . length > 1
694+ const classification = classify_content ( content , metadata )
695+ const all_sectors = [ classification . primary , ...classification . additional ]
696+ await transaction . begin ( )
697+ try {
698+ const max_seg_res = await q . get_max_segment . get ( )
699+ let cur_seg = max_seg_res ?. max_seg ?? 0
700+ const seg_cnt_res = await q . get_segment_count . get ( cur_seg )
701+ const seg_cnt = seg_cnt_res ?. c ?? 0
702+ if ( seg_cnt >= env . seg_size ) {
703+ cur_seg ++
704+ console . log ( `[HSG] Rotated to segment ${ cur_seg } (previous segment full: ${ seg_cnt } memories)` )
705+ }
706+ const stored_content = extract_essence ( content , classification . primary , env . summary_max_length )
707+ const sec_cfg = sector_configs [ classification . primary ]
708+ const init_sal = Math . max ( 0 , Math . min ( 1 , 0.4 + 0.1 * classification . additional . length ) )
709+ await q . ins_mem . run (
710+ id ,
711+ user_id || null ,
712+ cur_seg ,
713+ stored_content ,
714+ simhash ,
715+ classification . primary ,
716+ tags || null ,
717+ JSON . stringify ( metadata || { } ) ,
718+ now ,
719+ now ,
720+ now ,
721+ init_sal ,
722+ sec_cfg . decay_lambda ,
723+ 1 ,
724+ null ,
725+ null ,
726+ null , // compressed_vec
727+ 0 // feedback_score
728+ )
729+ const emb_res = await embedMultiSector ( id , content , all_sectors , use_chunking ? chunks : undefined )
730+ for ( const result of emb_res ) {
731+ const vec_buf = vectorToBuffer ( result . vector )
732+ await q . ins_vec . run ( id , result . sector , vec_buf , result . dim )
733+ }
734+ const mean_vec = calc_mean_vec ( emb_res , all_sectors )
735+ const mean_vec_buf = vectorToBuffer ( mean_vec )
736+ await q . upd_mean_vec . run ( id , mean_vec . length , mean_vec_buf )
735737
736- // Store compressed vector for smart tier (for future query optimization)
737- if ( tier === 'smart' && mean_vec . length > 128 ) {
738- const comp = compress_vec_for_storage ( mean_vec , 128 )
739- const comp_buf = vectorToBuffer ( comp )
740- await q . upd_compressed_vec . run ( comp_buf , id )
741- }
738+ // Store compressed vector for smart tier (for future query optimization)
739+ if ( tier === 'smart' && mean_vec . length > 128 ) {
740+ const comp = compress_vec_for_storage ( mean_vec , 128 )
741+ const comp_buf = vectorToBuffer ( comp )
742+ await q . upd_compressed_vec . run ( comp_buf , id )
743+ }
742744
743- await create_single_waypoint ( id , mean_vec , now )
744- await transaction . commit ( )
745- return {
746- id,
747- primary_sector : classification . primary ,
748- sectors : all_sectors ,
749- chunks : chunks . length
745+ await create_single_waypoint ( id , mean_vec , now )
746+ await transaction . commit ( )
747+ return {
748+ id,
749+ primary_sector : classification . primary ,
750+ sectors : all_sectors ,
751+ chunks : chunks . length
752+ }
753+ } catch ( error ) {
754+ await transaction . rollback ( )
755+ throw error
750756 }
751- } catch ( error ) {
752- await transaction . rollback ( )
753- throw error
754- }
757+ } )
755758}
756759export async function reinforce_memory ( id : string , boost : number = 0.1 ) : Promise < void > {
757760 const mem = await q . get_mem . get ( id )
@@ -765,35 +768,37 @@ export async function update_memory(
765768 tags ?: string [ ] ,
766769 metadata ?: any
767770) : Promise < { id : string , updated : boolean } > {
768- const mem = await q . get_mem . get ( id )
769- if ( ! mem ) throw new Error ( `Memory ${ id } not found` )
770- const new_content = content !== undefined ? content : mem . content
771- const new_tags = tags !== undefined ? j ( tags ) : ( mem . tags || '[]' )
772- const new_meta = metadata !== undefined ? j ( metadata ) : ( mem . meta || '{}' )
773- await transaction . begin ( )
774- try {
775- if ( content !== undefined && content !== mem . content ) {
776- const chunks = chunk_text ( new_content )
777- const use_chunking = chunks . length > 1
778- const classification = classify_content ( new_content , metadata )
779- const all_sectors = [ classification . primary , ...classification . additional ]
780- await q . del_vec . run ( id )
781- const emb_res = await embedMultiSector ( id , new_content , all_sectors , use_chunking ? chunks : undefined )
782- for ( const result of emb_res ) {
783- const vec_buf = vectorToBuffer ( result . vector )
784- await q . ins_vec . run ( id , result . sector , vec_buf , result . dim )
771+ return dbq . exec ( async ( ) => {
772+ const mem = await q . get_mem . get ( id )
773+ if ( ! mem ) throw new Error ( `Memory ${ id } not found` )
774+ const new_content = content !== undefined ? content : mem . content
775+ const new_tags = tags !== undefined ? j ( tags ) : ( mem . tags || '[]' )
776+ const new_meta = metadata !== undefined ? j ( metadata ) : ( mem . meta || '{}' )
777+ await transaction . begin ( )
778+ try {
779+ if ( content !== undefined && content !== mem . content ) {
780+ const chunks = chunk_text ( new_content )
781+ const use_chunking = chunks . length > 1
782+ const classification = classify_content ( new_content , metadata )
783+ const all_sectors = [ classification . primary , ...classification . additional ]
784+ await q . del_vec . run ( id )
785+ const emb_res = await embedMultiSector ( id , new_content , all_sectors , use_chunking ? chunks : undefined )
786+ for ( const result of emb_res ) {
787+ const vec_buf = vectorToBuffer ( result . vector )
788+ await q . ins_vec . run ( id , result . sector , vec_buf , result . dim )
789+ }
790+ const mean_vec = calc_mean_vec ( emb_res , all_sectors )
791+ const mean_vec_buf = vectorToBuffer ( mean_vec )
792+ await q . upd_mean_vec . run ( id , mean_vec . length , mean_vec_buf )
793+ await q . upd_mem_with_sector . run ( new_content , classification . primary , new_tags , new_meta , Date . now ( ) , id )
794+ } else {
795+ await q . upd_mem . run ( new_content , new_tags , new_meta , Date . now ( ) , id )
785796 }
786- const mean_vec = calc_mean_vec ( emb_res , all_sectors )
787- const mean_vec_buf = vectorToBuffer ( mean_vec )
788- await q . upd_mean_vec . run ( id , mean_vec . length , mean_vec_buf )
789- await q . upd_mem_with_sector . run ( new_content , classification . primary , new_tags , new_meta , Date . now ( ) , id )
790- } else {
791- await q . upd_mem . run ( new_content , new_tags , new_meta , Date . now ( ) , id )
797+ await transaction . commit ( )
798+ return { id, updated : true }
799+ } catch ( error ) {
800+ await transaction . rollback ( )
801+ throw error
792802 }
793- await transaction . commit ( )
794- return { id, updated : true }
795- } catch ( error ) {
796- await transaction . rollback ( )
797- throw error
798- }
803+ } )
799804}
0 commit comments