UNPKG

aios-core

Version:

Synkra AIOS: AI-Orchestrated System for Full Stack Development - Core Framework

155 lines (133 loc) 4.51 kB
/** * L6 Keyword Layer Processor * * Scans manifest domains for recall keywords and matches them * against the user prompt. Loads domain files for matching domains. * Respects exclusion rules and deduplicates against previous layers. * * CARL parity: identical keyword matching behavior using domain-loader * matchKeywords() and isExcluded() functions. * * @module core/synapse/layers/l6-keyword * @version 1.0.0 * @created Story SYN-5 - Layer Processors L4-L7 */ const path = require('path'); const { loadDomainFile, matchKeywords, isExcluded } = require('../domain/domain-loader'); const LayerProcessor = require('./layer-processor'); /** * L6 Keyword Processor * * Matches recall keywords in manifest domains against the prompt. * Deduplicates domains already loaded by previous layers. * Returns null if no keyword matches. * * @extends LayerProcessor */ class L6KeywordProcessor extends LayerProcessor { constructor() { super({ name: 'keyword', layer: 6, timeout: 15 }); } /** * Match keywords and load corresponding domain rules. * * Detection flow: * 1. Build set of already-loaded domains from previousLayers * 2. Iterate manifest domains with recall keywords * 3. Check exclusion (global + domain) * 4. Check keyword match against prompt * 5. Skip if domain already loaded by previous layer * 6. Load domain file and collect rules * * @param {object} context * @param {string} context.prompt - Current prompt text * @param {object} context.session - Session state (SYN-2 schema) * @param {object} context.config - Config with synapsePath and manifest * @param {object[]} context.previousLayers - Results from previous layers * @returns {{ rules: string[], metadata: object } | null} */ process(context) { const { prompt, config, previousLayers } = context; const { manifest, synapsePath } = config; if (!prompt) { return null; } // 1. Build set of already-loaded domain sources const loadedSources = this._extractLoadedSources(previousLayers || []); const allRules = []; const matchedDomains = []; const skippedDuplicates = []; const globalExclude = manifest.globalExclude || []; // 2. Iterate domains with recall keywords for (const [domainName, domain] of Object.entries(manifest.domains || {})) { if (!domain.recall || domain.recall.length === 0) { continue; } // 3. Check exclusion if (isExcluded(prompt, globalExclude, domain.exclude || [])) { continue; } // 4. Check keyword match if (!matchKeywords(prompt, domain.recall)) { continue; } // 5. Check dedup against previous layers if (loadedSources.has(domainName)) { skippedDuplicates.push(domainName); continue; } // 6. Load domain file const domainFile = domain.file ? path.join(synapsePath, domain.file) : path.join(synapsePath, domainName.toLowerCase().replace(/_/g, '-')); const rules = loadDomainFile(domainFile); if (rules && rules.length > 0) { allRules.push(...rules); matchedDomains.push(domainName); } } if (allRules.length === 0) { return null; } return { rules: allRules, metadata: { layer: 6, matchedDomains, skippedDuplicates, }, }; } /** * Extract domain source identifiers from previous layer results. * * Looks at metadata.source and metadata.agentId from previous layers * to build a set of domain names that are already loaded. * * @param {object[]} previousLayers - Array of { name, metadata } from prior layers * @returns {Set<string>} Set of loaded domain identifiers * @private */ _extractLoadedSources(previousLayers) { const sources = new Set(); for (const layer of previousLayers) { if (!layer || !layer.metadata) continue; // Extract source identifier from metadata const source = layer.metadata.source; if (source) { sources.add(source); // Also add the uppercase domain key form const upperKey = source.toUpperCase().replace(/-/g, '_'); sources.add(upperKey); } // Track loaded domains from squad layer if (layer.metadata.domainsLoaded) { for (const d of layer.metadata.domainsLoaded) { sources.add(d); } } } return sources; } } module.exports = L6KeywordProcessor;