UNPKG

meld

Version:

Meld: A template language for LLM prompts

146 lines (130 loc) 4.67 kB
import type { StateNode, StateNodeOptions, IStateFactory, StateOperation } from './types.js'; import { stateLogger as logger } from '@core/utils/logger.js'; import { randomUUID } from 'crypto'; export class StateFactory implements IStateFactory { private operations: StateOperation[] = []; createState(options?: StateNodeOptions): StateNode { const state: StateNode = { stateId: randomUUID(), variables: { text: new Map(options?.parentState?.variables.text ?? []), data: new Map(options?.parentState?.variables.data ?? []), path: new Map(options?.parentState?.variables.path ?? []) }, commands: new Map(options?.parentState?.commands ?? []), imports: new Set(options?.parentState?.imports ?? []), nodes: [...(options?.parentState?.nodes ?? [])], transformedNodes: options?.parentState?.transformedNodes ? [...options.parentState.transformedNodes] : undefined, filePath: options?.filePath ?? options?.parentState?.filePath, parentState: options?.parentState }; this.logOperation({ type: 'create', timestamp: Date.now(), source: options?.source ?? 'createState', details: { operation: 'createState', value: state } }); return state; } createChildState(parent: StateNode, options?: StateNodeOptions): StateNode { const child = this.createState({ ...options, parentState: parent, source: options?.source ?? 'createChildState' }); this.logOperation({ type: 'create', timestamp: Date.now(), source: options?.source ?? 'createChildState', details: { operation: 'createChildState', value: child } }); return child; } mergeStates(parent: StateNode, child: StateNode): StateNode { // Create new maps with parent values as base const text = new Map(parent.variables.text); const data = new Map(parent.variables.data); const path = new Map(parent.variables.path); const commands = new Map(parent.commands); // Merge child variables - last write wins for (const [key, value] of child.variables.text) { text.set(key, value); } for (const [key, value] of child.variables.data) { data.set(key, value); } for (const [key, value] of child.variables.path) { path.set(key, value); } for (const [key, value] of child.commands) { commands.set(key, value); } // Create new state with merged values const merged: StateNode = { variables: { text, data, path }, commands, imports: new Set([...parent.imports, ...child.imports]), // Preserve node order by appending all child nodes nodes: [...parent.nodes, ...child.nodes], // Merge transformed nodes if either parent or child has them transformedNodes: child.transformedNodes !== undefined ? [...child.transformedNodes] : parent.transformedNodes !== undefined ? [...parent.transformedNodes] : undefined, filePath: child.filePath ?? parent.filePath, parentState: parent.parentState, // Preserve parent's stateId to maintain identity stateId: parent.stateId, source: 'merge' }; this.logOperation({ type: 'merge', timestamp: Date.now(), source: 'mergeStates', details: { operation: 'mergeStates', value: merged } }); return merged; } updateState(state: StateNode, updates: Partial<StateNode>): StateNode { const updated: StateNode = { stateId: state.stateId, variables: { text: updates.variables?.text ?? new Map(state.variables.text), data: updates.variables?.data ?? new Map(state.variables.data), path: updates.variables?.path ?? new Map(state.variables.path) }, commands: updates.commands ?? new Map(state.commands), imports: new Set(updates.imports ?? state.imports), nodes: [...(updates.nodes ?? state.nodes)], transformedNodes: updates.transformedNodes !== undefined ? [...updates.transformedNodes] : state.transformedNodes, filePath: updates.filePath ?? state.filePath, parentState: updates.parentState ?? state.parentState }; this.logOperation({ type: 'update', timestamp: Date.now(), source: 'updateState', details: { operation: 'updateState', value: updated } }); return updated; } private logOperation(operation: StateOperation): void { this.operations.push(operation); logger.debug('State operation', operation); } }