Files
memind/memory-v2-adapter-scaffold.mjs
T
2026-07-03 09:46:03 +08:00

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`;
}