85 lines
3.4 KiB
JavaScript
85 lines
3.4 KiB
JavaScript
const VALID_CATEGORIES = new Set(['semantic', 'extraction', 'lifecycle', 'behavior', 'policy']);
|
|
const VALID_CAPABILITIES = new Set(['resolve', 'write', 'compact']);
|
|
|
|
function kebabCase(value) {
|
|
return String(value ?? '')
|
|
.trim()
|
|
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
.replace(/[^a-zA-Z0-9]+/g, '-')
|
|
.replace(/^-+|-+$/g, '')
|
|
.toLowerCase();
|
|
}
|
|
|
|
function screamingSnake(value) {
|
|
return String(value ?? '')
|
|
.trim()
|
|
.replace(/([a-z0-9])([A-Z])/g, '$1_$2')
|
|
.replace(/[^a-zA-Z0-9]+/g, '_')
|
|
.replace(/^_+|_+$/g, '')
|
|
.toUpperCase();
|
|
}
|
|
|
|
function normalizeCapabilities(capabilities) {
|
|
const normalized = [...new Set(
|
|
(Array.isArray(capabilities) ? capabilities : String(capabilities ?? '').split(','))
|
|
.map((item) => String(item).trim())
|
|
.filter(Boolean),
|
|
)];
|
|
if (normalized.length === 0) throw new Error('At least one capability is required');
|
|
for (const capability of normalized) {
|
|
if (!VALID_CAPABILITIES.has(capability)) {
|
|
throw new Error(`Unsupported Memory V2 capability: ${capability}`);
|
|
}
|
|
}
|
|
return normalized;
|
|
}
|
|
|
|
export function normalizeMemoryV2AdapterScaffoldOptions({
|
|
name,
|
|
category,
|
|
role = 'optional-plugin',
|
|
capabilities,
|
|
flag = null,
|
|
} = {}) {
|
|
const normalizedName = kebabCase(name);
|
|
if (!normalizedName) throw new Error('Adapter name is required');
|
|
const normalizedCategory = String(category ?? '').trim();
|
|
if (!VALID_CATEGORIES.has(normalizedCategory)) {
|
|
throw new Error(`Adapter category must be one of: ${[...VALID_CATEGORIES].join(', ')}`);
|
|
}
|
|
const normalizedCapabilities = normalizeCapabilities(capabilities);
|
|
const normalizedFlag = flag
|
|
? screamingSnake(flag)
|
|
: `MEMORY_${screamingSnake(normalizedName)}_ENABLED`;
|
|
return {
|
|
name: normalizedName,
|
|
factoryName: `create${normalizedName
|
|
.split('-')
|
|
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
.join('')}MemoryBackend`,
|
|
category: normalizedCategory,
|
|
role: kebabCase(role) || 'optional-plugin',
|
|
capabilities: normalizedCapabilities,
|
|
flag: normalizedFlag,
|
|
};
|
|
}
|
|
|
|
function operationMethod(operation) {
|
|
if (operation === 'resolve') {
|
|
return `\n async resolve() {\n return {\n memories: [],\n semanticMemories: [],\n behaviorSummary: null,\n activeGoals: [],\n };\n },`;
|
|
}
|
|
if (operation === 'write') {
|
|
return `\n async write() {\n return { saved: 0, analyzed: 0, memories: 0 };\n },`;
|
|
}
|
|
if (operation === 'compact') {
|
|
return `\n async compact() {\n return { analyzed: 0, memories: 0 };\n },`;
|
|
}
|
|
return '';
|
|
}
|
|
|
|
export function renderMemoryV2AdapterScaffold(options = {}) {
|
|
const normalized = normalizeMemoryV2AdapterScaffoldOptions(options);
|
|
const methods = normalized.capabilities.map((capability) => operationMethod(capability)).join('\n');
|
|
return `// Generated Memory V2 backend scaffold.\n// Keep disabled by default. Wire real clients only through memory-v2-runtime.mjs.\n\nexport function ${normalized.factoryName}({ enabled = false, unavailableReason = 'not_configured' } = {}) {\n return {\n name: '${normalized.name}',\n category: '${normalized.category}',\n role: '${normalized.role}',\n flag: '${normalized.flag}',\n unavailableReason,\n\n isAvailable() {\n return Boolean(enabled);\n },\n\n getUnavailableReason() {\n return this.isAvailable() ? null : unavailableReason;\n },${methods}\n };\n}\n`;
|
|
}
|