/ src / agents / utils / context-loader.js
context-loader.js
 1  /**
 2   * Context Loader Utility
 3   *
 4   * Loads and merges markdown context files for agent system.
 5   * Each agent loads base.md + their role-specific context file(s).
 6   */
 7  
 8  import fs from 'fs/promises';
 9  import path from 'path';
10  import { fileURLToPath } from 'url';
11  
12  const __filename = fileURLToPath(import.meta.url);
13  const __dirname = path.dirname(__filename);
14  
15  /**
16   * Load context files and merge them into a single string
17   *
18   * @param {string[]} contextFiles - Array of context filenames (e.g., ['base.md', 'developer.md'])
19   * @returns {Promise<string>} - Merged context content
20   *
21   * @example
22   * const context = await loadContextFiles(['base.md', 'developer.md']);
23   * // Returns ~25KB merged context for Developer Agent
24   */
25  export async function loadContextFiles(contextFiles) {
26    if (!Array.isArray(contextFiles) || contextFiles.length === 0) {
27      throw new Error('contextFiles must be a non-empty array');
28    }
29  
30    const contextsDir = path.join(__dirname, '..', 'contexts');
31    const contents = [];
32  
33    for (const file of contextFiles) {
34      const filePath = path.join(contextsDir, file);
35  
36      try {
37        const content = await fs.readFile(filePath, 'utf8');
38        contents.push(content);
39      } catch (error) {
40        if (error.code === 'ENOENT') {
41          throw new Error(`Context file not found: ${file} (expected at ${filePath})`);
42        }
43        throw error;
44      }
45    }
46  
47    // Merge with separators
48    return contents.join('\n\n---\n\n');
49  }
50  
51  /**
52   * Get the size of loaded context in bytes
53   *
54   * @param {string} context - Context string
55   * @returns {number} - Size in bytes
56   */
57  export function getContextSize(context) {
58    return Buffer.byteLength(context, 'utf8');
59  }
60  
61  /**
62   * Get the size of loaded context in kilobytes
63   *
64   * @param {string} context - Context string
65   * @returns {number} - Size in KB (rounded to 1 decimal)
66   */
67  export function getContextSizeKB(context) {
68    return Math.round((getContextSize(context) / 1024) * 10) / 10;
69  }
70  
71  /**
72   * Load and validate context files, returning metadata
73   *
74   * @param {string[]} contextFiles - Array of context filenames
75   * @returns {Promise<{context: string, size: number, sizeKB: number, files: string[]}>}
76   *
77   * @example
78   * const { context, sizeKB } = await loadContextWithMetadata(['base.md', 'qa.md']);
79   * console.log(`Loaded ${sizeKB}KB context for QA Agent`);
80   */
81  export async function loadContextWithMetadata(contextFiles) {
82    const context = await loadContextFiles(contextFiles);
83    const size = getContextSize(context);
84    const sizeKB = getContextSizeKB(context);
85  
86    return {
87      context,
88      size,
89      sizeKB,
90      files: contextFiles,
91    };
92  }