1- // Node.js built-in modules
2- import { promises as fs } from 'fs' ;
3- import * as path from 'path' ;
4-
51import type { AgentContext } from '@agentuity/sdk' ;
6-
72import { processDoc } from './docs-processor' ;
83import { VECTOR_STORE_NAME } from './config' ;
94
10- export const DEFAULT_CONTENT_DIR = path . resolve ( __dirname , '../../../../content' ) ;
11-
12- /**
13- * Checks if a document has changed by comparing its hash.
14- * @param docPath Absolute path to the .mdx file
15- * @param newHash Newly computed hash
16- * @returns true if changed, false if unchanged
17- */
18- export async function hasDocChanged ( ctx : AgentContext , docPath : string , newHash : string ) : Promise < boolean > {
19- const vectors = await ctx . vector . search ( VECTOR_STORE_NAME , {
20- query : ' ' ,
21- limit : 1 ,
22- metadata : { path : docPath } ,
23- } ) ;
24- if ( vectors . length > 0 ) {
25- const storedHash = vectors [ 0 ] ?. metadata ?. hash ;
26- return storedHash !== newHash ;
27- }
28- return true ;
5+ interface FilePayload {
6+ path : string ;
7+ content : string ; // base64-encoded
298}
309
31- interface OrchestratorOptions {
32- changedFiles : string [ ] ; // Absolute file paths
33- removedFiles : string [ ] ; // Absolute file paths
34- contentDir ?: string ; // Defaults to /content
10+ interface SyncPayload {
11+ commit ?: string ;
12+ repo ?: string ;
13+ changed : FilePayload [ ] ;
14+ removed : string [ ] ;
3515}
3616
3717interface SyncStats {
38- processed : number ;
39- deleted : number ;
40- errors : number ;
41- errorFiles : string [ ] ;
18+ processed : number ;
19+ deleted : number ;
20+ errors : number ;
21+ errorFiles : string [ ] ;
4222}
4323
4424/**
45- * Helper to remove all vectors for a given relative path from the vector store.
25+ * Helper to remove all vectors for a given logical path from the vector store.
4626 */
47- async function removeVectorsByRelativePath ( ctx : AgentContext , relativePath : string , vectorStoreName : string ) {
48- ctx . logger . info ( 'Removing vectors for path: %s, store: %s, metadata: %o' , relativePath , vectorStoreName , { path : relativePath } ) ;
49- const vectors = await ctx . vector . search ( vectorStoreName , {
50- query : ' ' ,
51- limit : 1000 ,
52- metadata : { path : relativePath } ,
53- } ) ;
54- if ( vectors . length > 0 ) {
55- // Delete vectors one by one to avoid issues with large batches
56- for ( const vector of vectors ) {
57- await ctx . vector . delete ( vectorStoreName , vector . key ) ;
58- }
59- } else {
60- ctx . logger . info ( 'No vectors found for path: %s, store: %s, metadata: %o' , relativePath , vectorStoreName , { path : relativePath } ) ;
27+ async function removeVectorsByPath ( ctx : AgentContext , logicalPath : string , vectorStoreName : string ) {
28+ ctx . logger . info ( 'Removing vectors for path: %s' , logicalPath ) ;
29+ const vectors = await ctx . vector . search ( vectorStoreName , {
30+ query : ' ' ,
31+ limit : 1000 ,
32+ metadata : { path : logicalPath } ,
33+ } ) ;
34+
35+ if ( vectors . length > 0 ) {
36+ // Delete vectors one by one to avoid issues with large batches
37+ for ( const vector of vectors ) {
38+ await ctx . vector . delete ( vectorStoreName , vector . key ) ;
6139 }
40+ ctx . logger . info ( 'Removed %d vectors for path: %s' , vectors . length , logicalPath ) ;
41+ } else {
42+ ctx . logger . info ( 'No vectors found for path: %s' , logicalPath ) ;
43+ }
6244}
6345
64- export async function syncDocs ( ctx : AgentContext , options : OrchestratorOptions ) : Promise < SyncStats > {
65- const { changedFiles, removedFiles } = options ;
66- const contentDir = options . contentDir || DEFAULT_CONTENT_DIR ;
67- let processed = 0 , deleted = 0 , errors = 0 ;
68- const errorFiles : string [ ] = [ ] ;
46+ /**
47+ * Process documentation sync from embedded payload - completely filesystem-free
48+ */
49+ export async function syncDocsFromPayload ( ctx : AgentContext , payload : SyncPayload ) : Promise < SyncStats > {
50+ const { changed, removed } = payload ;
51+ let processed = 0 , deleted = 0 , errors = 0 ;
52+ const errorFiles : string [ ] = [ ] ;
6953
70- for ( const absolutePath of changedFiles ) {
71- try {
72- // Compute relative path for metadata and vector store
73- const relativePath = path . relative ( contentDir , absolutePath ) ;
74- await removeVectorsByRelativePath ( ctx , relativePath , VECTOR_STORE_NAME ) ;
75- const content = await fs . readFile ( absolutePath , 'utf-8' ) ;
76- const chunks = await processDoc ( content ) ;
77- for ( const chunk of chunks ) {
78- chunk . metadata = {
79- ...chunk . metadata ,
80- path : relativePath ,
81- } ;
82- await ctx . vector . upsert ( VECTOR_STORE_NAME , chunk ) ;
83- }
84- processed ++ ;
85- } catch ( err ) {
86- errors ++ ;
87- errorFiles . push ( absolutePath ) ;
88- ctx . logger . error ( 'Error processing file %s: %o' , absolutePath , err ) ;
89- }
54+ // Process changed files with embedded content
55+ for ( const file of changed ) {
56+ try {
57+ const { path : logicalPath , content : base64Content } = file ;
58+
59+ // Base64-decode the content
60+ const content = Buffer . from ( base64Content , 'base64' ) . toString ( 'utf-8' ) ;
61+
62+ // Remove existing vectors for this path
63+ await removeVectorsByPath ( ctx , logicalPath , VECTOR_STORE_NAME ) ;
64+
65+ // Process the document content into chunks
66+ const chunks = await processDoc ( content ) ;
67+
68+ // Upsert chunks with path metadata
69+ for ( const chunk of chunks ) {
70+ chunk . metadata = {
71+ ...chunk . metadata ,
72+ path : logicalPath ,
73+ } ;
74+ await ctx . vector . upsert ( VECTOR_STORE_NAME , chunk ) ;
75+ }
76+
77+ processed ++ ;
78+ ctx . logger . info ( 'Successfully processed file: %s (%d chunks)' , logicalPath , chunks . length ) ;
79+ } catch ( err ) {
80+ errors ++ ;
81+ errorFiles . push ( file . path ) ;
82+ ctx . logger . error ( 'Error processing file %s: %o' , file . path , err ) ;
9083 }
84+ }
9185
92- for ( const absolutePath of removedFiles ) {
93- try {
94- const relativePath = path . relative ( contentDir , absolutePath ) ;
95- await removeVectorsByRelativePath ( ctx , relativePath , VECTOR_STORE_NAME ) ;
96- deleted ++ ;
97- } catch ( err ) {
98- errors ++ ;
99- errorFiles . push ( absolutePath ) ;
100- ctx . logger . error ( 'Error deleting file %s: %o' , absolutePath , err ) ;
101- }
86+ // Process removed files
87+ for ( const logicalPath of removed ) {
88+ try {
89+ await removeVectorsByPath ( ctx , logicalPath , VECTOR_STORE_NAME ) ;
90+ deleted ++ ;
91+ ctx . logger . info ( 'Successfully removed file: %s' , logicalPath ) ;
92+ } catch ( err ) {
93+ errors ++ ;
94+ errorFiles . push ( logicalPath ) ;
95+ ctx . logger . error ( 'Error deleting file %s: %o' , logicalPath , err ) ;
10296 }
97+ }
10398
104- return { processed, deleted, errors, errorFiles } ;
99+ const stats = { processed, deleted, errors, errorFiles } ;
100+ ctx . logger . info ( 'Sync completed: %o' , stats ) ;
101+ return stats ;
105102}
0 commit comments