UNPKG

@convo-lang/convo-lang

Version:
260 lines 8.87 kB
import { getErrorMessage } from "@iyio/common"; import { convoMessageToStringSafe, convoRoles, convoTags, convoVars, defaultConvoNodeId } from "./convo-lib.js"; export const applyConvoNodeOrdering = (messages, conversation, appendTail = messages[messages.length - 1]?.role === convoRoles.goto) => { const inlineMessages = {}; const functionMessages = {}; const systemMessages = {}; const scriptMessages = {}; const allMessages = {}; let currentNodeId; for (let i = 0; i < messages.length; i++) { const msg = messages[i]; if (!msg) { continue; } switch (msg.role) { case convoRoles.node: { currentNodeId = msg.nodeId; if (currentNodeId === defaultConvoNodeId) { currentNodeId = undefined; } break; } case convoRoles.to: case convoRoles.from: case convoRoles.exit: // do nothing. Messages should not be added break; case convoRoles.goto: case convoRoles.nodeEnd: case convoRoles.exitGraph: currentNodeId = undefined; break; default: if (currentNodeId) { if (conversation.isSystemMessage(msg)) { (systemMessages[currentNodeId] ?? (systemMessages[currentNodeId] = [])).push(msg); } else if (msg.fn && !msg.fn.topLevel && !msg.fn.call) { (functionMessages[currentNodeId] ?? (functionMessages[currentNodeId] = [])).push(msg); } else if (conversation.isUserMessage(msg) || conversation.isAssistantMessage(msg)) { messages.splice(i, 1); i--; (inlineMessages[currentNodeId] ?? (inlineMessages[currentNodeId] = [])).push(msg); } else if (msg.role === convoRoles.define || msg.role === convoRoles.do) { messages.splice(i, 1); i--; (scriptMessages[currentNodeId] ?? (scriptMessages[currentNodeId] = [])).push(msg); (inlineMessages[currentNodeId] ?? (inlineMessages[currentNodeId] = [])).push(msg, { role: convoRoles._sourceRef, content: convoMessageToStringSafe(msg) }); } (allMessages[currentNodeId] ?? (allMessages[currentNodeId] = [])).push(msg); } break; } } if (appendTail) { for (let i = messages.length - 1; i >= 0; i--) { const msg = messages[i]; if (msg?.role !== convoRoles.goto) { continue; } const insert = inlineMessages[msg.gotoNodeId ?? '']; if (!insert) { break; } messages.splice(i + 1, 0, ...insert.map(m => ({ ...m }))); i += insert.length; break; } } return { inlineMessages, functionMessages, systemMessages, scriptMessages, allMessages }; }; export const getConvoNodeOutput = (messages, exe, startIndex) => { for (let i = startIndex ?? (messages.length - 1); i >= 0; i--) { const msg = messages[i]; if (!msg) { continue; } if ((msg.isUser || msg.isAssistant) && msg.content) { return msg.content; } if (msg.role === convoRoles.result) { return exe.getVar(convoVars.__return); } } return undefined; }; export const convoTagToNodeRoute = (tag) => { const route = { toNodeId: tag.label || defaultConvoNodeId, nlCondition: tag.statement ? undefined : tag.value, condition: tag.statement, }; if (route.nlCondition === 'else') { delete route.nlCondition; } if (tag.name === convoTags.exit) { route.exit = true; } if (route.toNodeId === 'auto') { if (route.nlCondition) { route.auto = route.nlCondition.split(/\s+/).filter(n => n); delete route.nlCondition; } else { route.auto = true; } } return route; }; export const getConvoNodeMessages = (nodeId, messages, includeRoutes = true) => { let inNode = false; const nodeMessages = []; for (const msg of messages) { switch (msg.role) { case convoRoles.node: if (msg.nodeId === nodeId) { inNode = true; nodeMessages.push(msg); } else { inNode = false; } break; case convoRoles.nodeEnd: case convoRoles.goto: case convoRoles.exitGraph: inNode = false; break; case convoRoles.to: case convoRoles.from: case convoRoles.exit: if (includeRoutes && inNode) { nodeMessages.push(msg); } break; default: if (inNode) { nodeMessages.push(msg); } break; } } return nodeMessages; }; export const getExtendedConvoNodeDescription = (node, source, sourceMessages) => { const messages = source.messages.filter(m => m.nodeId === node.nodeId); const srcMsgs = getConvoNodeMessages(node.nodeId, sourceMessages); const extended = { ...node, messages, sourceMessages: srcMsgs, convo: srcMsgs.map(m => convoMessageToStringSafe(m) ?? '').join('\n\n'), }; return extended; }; export const createConvoNodeGraph = (source, sourceMessages) => { const graph = { nodes: (source.nodeDescriptions ?? []).map(n => getExtendedConvoNodeDescription(n, source, sourceMessages)), entry: undefined, }; let entryId; for (const msg of source.messages) { if (msg.role === convoRoles.goto && msg.gotoNodeId) { entryId = msg.gotoNodeId; break; } } if (entryId) { graph.entry = graph.nodes.find(n => n.nodeId = entryId); } return graph; }; export const removeConvoNodeMessages = (messages) => { let currentNodeId; for (let i = 0; i < messages.length; i++) { const msg = messages[i]; if (!msg) { continue; } switch (msg.role) { case convoRoles.node: currentNodeId = msg.nodeId; messages.splice(i, 1); i--; break; case convoRoles.goto: case convoRoles.nodeEnd: case convoRoles.exitGraph: currentNodeId = undefined; messages.splice(i, 1); i--; break; // always remove case convoRoles.to: case convoRoles.from: case convoRoles.exit: messages.splice(i, 1); i--; break; default: if (currentNodeId) { messages.splice(i, 1); i--; } break; } } }; export const getConvoConvoNodeResults = (flat) => { const results = []; const stack = flat.exe.getVar(convoVars.__nodeStack); if (!Array.isArray(stack)) { return results; } for (let i = 0; i < stack.length; i++) { const node = stack[i]; if (!node) { continue; } const next = stack[i + 1]; results.push({ ...node, output: next ? next.input : flat.exe.getVar('output'), }); } return results; }; export const createConvoNodeGraphResult = (completion, errorObject, error = errorObject ? getErrorMessage(errorObject) : undefined) => { if (!completion) { return { success: false, error: error ?? 'Completion unable to be created', errorObject, exited: false, }; } const last = completion.nodeResults?.[0]; if (!last || error) { return { success: false, error: error ?? 'Completion contained no node results', errorObject, finalCompletion: completion, exited: completion.graphExited ?? false, }; } return { success: true, result: last, allResults: completion.nodeResults ?? [], finalCompletion: completion, exited: completion.graphExited ?? false, }; }; //# sourceMappingURL=convo-node-graph-lib.js.map