UNPKG

@emanuelsan/mosaic-js

Version:

Composable Markdown-based AI instruction engine for Node.js

76 lines 3.25 kB
import { Effect, Console, Data, Context } from 'effect'; import { isValidTemplateSelector } from './utils/isValidTemplateSelector'; import { buildTemplateTree } from './utils/buildTemplateTree'; import { checkDirectory } from './utils/checkDirectory'; import { decodeVariables, } from './utils/decodeVariables'; import { decodeTemplateOverrides, } from './utils/decodeTemplateOverrides'; import { Directory } from './utils/normalizeToRelativeSelector'; // Error Types Definitions class InvalidTemplateSelectorError extends Data.TaggedError('InvalidTemplateSelectorError') { } export class MosaicVariables extends Context.Tag('MosaicVariables')() { } // Class Definitions export class Mosaic { instructionsDir; variables = {}; overrides = {}; /** * Creates a new Mosaic instance. * @param instructionsDir - Path to the directory containing all the markdown files to be parsed and assembled. * This directory should contain the modular instruction templates for expansion. */ constructor(instructionsDir) { this.instructionsDir = instructionsDir; } compose(templateSelector) { // Create the full Effect context const context = Context.empty().pipe(Context.add(MosaicVariables, { templateVariables: Effect.succeed(this.variables), templateOverrides: Effect.succeed(this.overrides), }), Context.add(Directory, { templateDir: Effect.succeed(this.instructionsDir), })); // Define the full expansion pipeline const pipeline = Effect.gen(function* () { const validation = yield* isValidTemplateSelector(templateSelector); if (!validation.valid) { yield* Console.error(`${templateSelector} is not a valid template selector. Returning empty string.`); return yield* Effect.fail(new InvalidTemplateSelectorError({ message: 'Invalid template selector', })); } // Build the template tree, recursively expand and flatten it const finalNode = yield* buildTemplateTree(templateSelector); return finalNode.content; }); // Provide context and run the pipeline const result = Effect.runSync(Effect.provide(pipeline, context)); return result; } /** * Creates a new Mosaic instance from a directory of markdown files. * @param instructionsDir - Path to the directory that this mosaic will have as a parse base. */ static fromDirectory(instructionsDir) { return Effect.runSync(checkDirectory(instructionsDir)); } provideVariables(variables) { const decoded = Effect.runSync(decodeVariables(variables)); this.variables = { ...this.variables, ...decoded, }; return this; } provideOverrides(overrides) { const effect = Effect.provideService(decodeTemplateOverrides(overrides), Directory, { templateDir: Effect.succeed(this.instructionsDir) }); const decoded = Effect.runSync(effect); this.overrides = { ...this.overrides, ...decoded, }; return this; } } //# sourceMappingURL=Mosaic.js.map