UNPKG

@convo-lang/convo-lang

Version:
219 lines 7.74 kB
import { getCodeParsingError, shortUuid } from "@iyio/common"; import { ConvoExecutionContext } from "./ConvoExecutionContext"; import { createEmptyConvoGraphDb } from "./convo-graph-lib"; import { isConvoGraphMsgType } from "./convo-graph-types"; import { getConvoTag, parseConvoJsonOrStringMessage } from "./convo-lib"; import { parseConvoCode } from "./convo-parser"; const exitEarly = false; export const parseConvoGraphCode = (code, options) => { const result = parseConvoCode(code, { logErrors: true, ...options, includeLineNumbers: true, }); if (result.error || !result.result || exitEarly) { return { endIndex: result.endIndex, error: result.error, }; } const startIndex = options?.startIndex ?? 0; let index = startIndex; const messages = result.result; let currentNode = null; let currentStep = null; let stepContentMsg = null; let error; const db = createEmptyConvoGraphDb(); let metadata = {}; const exe = new ConvoExecutionContext(); const getArgs = (msg) => { if (!msg.fn) { return {}; } const argsResult = exe.paramsToObj(msg.fn.params); if (argsResult.valuePromise) { return 'message args using async'; } return argsResult.value ?? {}; }; const appendContent = (endIndex) => { if (!stepContentMsg) { return true; } if (stepContentMsg.sourceCharIndex === undefined) { error = 'content message source char index undefined'; return false; } if (!currentNode) { error = 'No current node to append message content to'; return false; } const content = code.substring(stepContentMsg.sourceCharIndex, endIndex); if (currentStep) { currentStep.convo += '\n\n' + content; } else { if (currentNode.sharedConvo) { currentNode.sharedConvo += '\n\n' + content; } else { currentNode.sharedConvo = content; } } stepContentMsg = null; return true; }; parsingLoop: for (let i = 0; i < messages.length; i++) { const msg = messages[i]; if (!msg) { continue; } if (msg.sourceCharIndex === undefined) { error = 'message source char index undefined'; break parsingLoop; } index = msg.sourceCharIndex; const fn = msg.fn; if (!appendContent(index)) { break parsingLoop; } let type; let key; if (isConvoGraphMsgType(msg.role)) { type = msg.role; } else if (isConvoGraphMsgType(fn?.name)) { type = fn.name; } else if (fn?.modifiers) { for (const m of fn.modifiers) { if (isConvoGraphMsgType(m)) { type = m; key = fn.name; } } } if (type) { const args = getArgs(msg); if (typeof args === 'string') { error = args; break parsingLoop; } switch (type) { case 'node': if (!fn) { error = 'Node messages must be defined as functions'; break parsingLoop; } currentNode = { ...args, id: args['id'] ?? shortUuid(), key: args['key'] ?? key, steps: [], }; db.nodes.push(currentNode); currentStep = null; break; case 'step': if (!fn) { error = 'Step messages must be defined as functions'; break parsingLoop; } if (!currentNode) { error = 'Step messages can only appear under nodes'; break parsingLoop; } currentStep = { ...args, name: args['name'] ?? key, convo: '' }; currentNode.steps.push(currentStep); break; case 'edge': { if (!fn) { error = 'Edge messages must be defined as functions'; break parsingLoop; } const to = args['to'] ?? fn.returnType; if (!to) { error = 'Edges must define to as its return type or pass a to args'; break parsingLoop; } const edge = { ...args, id: args['id'] ?? shortUuid(), from: args['from'] ?? fn.name, to, }; if (fn.body?.length) { const first = fn.body[0]; const last = fn.body[fn.body.length - 1]; if (first && last) { const cond = code.substring(first.s, last.c ?? last.e); if (cond.trim()) { edge.conditionConvo = cond; } } } db.edges.push(edge); break; } case 'input': { currentStep = null; currentNode = null; const value = parseConvoJsonOrStringMessage(msg.content, true); const input = { id: getConvoTag(msg.tags, 'id')?.value || shortUuid(), isJson: value.isJson ? true : undefined, value: value.value }; if (msg.tags) { for (const tag of msg.tags) { if (input[tag.name] !== undefined || !tag.value) { continue; } input[tag.name] = numberInputProps.includes(tag.name) ? Number(tag.value) : tag.value; } } db.inputs.push(input); break; } case 'graph': { const value = parseConvoJsonOrStringMessage(msg.content); if ((typeof value.value === 'object') && value.value) { metadata = { ...metadata, ...value.value }; } break; } } } else { if (!currentNode) { error = `Non graph type messages must be defined within a node or node step. message: ${JSON.stringify(msg)}`; break parsingLoop; } stepContentMsg = msg; } } appendContent(code.length - 1); if (error) { return { endIndex: index, error: getCodeParsingError(code, index, error), }; } else { db.metadata = metadata; return { endIndex: index, result: { db, messages, }, }; } }; const numberInputProps = ['x', 'y']; //# sourceMappingURL=convo-graph-parser.js.map