UNPKG

@convo-lang/convo-lang

Version:
1,049 lines 40.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.ConvoExecutionContext = exports.executeConvoFunction = void 0; const common_1 = require("@iyio/common"); const json5_1 = require("@iyio/json5"); const Conversation_1 = require("./Conversation"); const ConvoError_1 = require("./ConvoError"); const convo_cached_parsing_1 = require("./convo-cached-parsing"); const convo_default_vars_1 = require("./convo-default-vars"); const convo_lib_1 = require("./convo-lib"); const convo_parser_1 = require("./convo-parser"); const convo_types_1 = require("./convo-types"); const convo_zod_1 = require("./convo-zod"); const argsCacheKey = Symbol('argsCacheKey'); const returnCacheKey = Symbol('returnCacheKey'); const executeConvoFunction = (fn, args = {}) => { const exe = new ConvoExecutionContext(); const r = exe.executeFunction(fn, args); return r.valuePromise ?? r.value; }; exports.executeConvoFunction = executeConvoFunction; const createDefaultScope = (vars) => { return { _d: true, vars, i: 0, s: { s: 0, e: 0 }, }; }; const copyDefaultScope = (scope) => { if (scope._d) { scope = { ...scope }; delete scope._d; } return scope; }; class ConvoExecutionContext { sharedVars; nextSuspendId = 1; suspendedScopes = {}; sharedSetters = []; convo; parentConvo; print = convo_lib_1.defaultConvoPrintFunction; dynamicFunctionCallback; defaultThrowOnUndefined = false; disableInlinePrompts = false; maxInlinePromptDepth = 10; isReadonly = 0; flat; varPrefix; constructor(convo, parentConvo) { this.convo = { ...convo, exe: this, convoPipeSink: convo?.convoPipeSink ?? ((value) => { this.print('CONVO_PIPE <<', value); }) }; this.sharedVars = { ...convo_default_vars_1.defaultConvoVars, [convo_lib_1.convoGlobalRef]: this.convo }; this.parentConvo = parentConvo; } getUserSharedVars() { const vars = { ...this.sharedVars }; delete vars['convo']; delete vars['graphCtrl']; delete vars['evalJavascript']; for (const e in convo_default_vars_1.defaultConvoVars) { delete vars[e]; } return vars; } getUserSharedVarsExcludeTypes() { const vars = this.getUserSharedVars(); for (const e in vars) { if (e[0] === e[0]?.toUpperCase() || (typeof vars[e] === 'function')) { delete vars[e]; } } return vars; } loadFunctions(messages, externFunctions) { for (const msg of messages) { if (msg.fn && !msg.fn.call && !msg.fn.topLevel) { this.setVar(true, (0, convo_lib_1.createConvoScopeFunction)({ usesLabels: true, catchReturn: true, sourceFn: msg.fn }, (scope, ctx) => { if (msg.fn?.body) { const r = this.executeFunction(msg.fn, (0, convo_lib_1.convoLabeledScopeFnParamsToObj)(scope, msg.fn.params)); return r.valuePromise ?? r.value; } else { const externFn = externFunctions?.[msg.fn?.name ?? '']; if (!externFn) { (0, convo_lib_1.setConvoScopeError)(scope, `No extern function provided for ${msg.fn?.name}`); return; } return externFn(scope, ctx); } }), msg.fn.name); } } if (externFunctions) { for (const e in externFunctions) { const fn = externFunctions[e]; if (!fn || this.sharedVars[e] !== undefined) { continue; } this.setVar(true, (0, convo_lib_1.createConvoScopeFunction)(fn), e); } } } clearSharedSetters() { this.sharedSetters.splice(0, this.sharedSetters.length); } executeStatement(statement) { const vars = {}; const scope = { i: 0, vars, s: statement, }; return this.execute(scope, vars); } executeFunction(fn, args = {}) { if (fn.call) { throw new ConvoError_1.ConvoError('proxy-call-not-supported', { fn }, 'executeFunction does not support proxy calls. Use executeFunctionAsync instead'); } const scheme = this.getConvoFunctionArgsScheme(fn); let parsed = scheme.safeParse(args); if (parsed.success === false) { const r = (0, common_1.zodCoerceObject)(scheme, args); if (r.result) { parsed = { data: r.result, success: true }; } else { throw new ConvoError_1.ConvoError('invalid-args', { fn }, `Invalid args passed to convo function. fn = ${fn.name}, message = ${parsed.error.message}`); } } args = parsed.data; const vars = { [convo_lib_1.convoArgsName]: args, }; let scope; if (fn.body) { scope = { i: 0, vars, [convo_types_1.convoScopeFnDefKey]: fn, s: { fn: convo_lib_1.convoBodyFnName, params: fn.body, s: 0, e: 0, }, }; for (const e in args) { this.setVar(false, args[e], e, undefined, scope); } if (scheme.shape) { for (const e in scheme.shape) { if (vars[e] === undefined) { this.setVar(false, undefined, e, undefined, scope); } } } } else { if (typeof this.sharedVars[fn.name] !== 'function') { throw new ConvoError_1.ConvoError('function-not-defined', { fn }, `No function defined by name ${fn.name}`); } const params = []; for (const e in args) { params.push({ s: 0, e: 0, label: e, value: args[e] }); } scope = { i: 0, vars, s: { fn: fn.name, params, s: 0, e: 0, }, }; } return this.execute(scope, vars, this.getConvoFunctionReturnScheme(fn)); } async executeFunctionAsync(fn, args = {}) { const result = await this.executeFunctionResultAsync(fn, args); if (result.valuePromise) { return await result.valuePromise; } else { return result.value; } } async executeFunctionResultAsync(fn, args = {}) { if (fn.call) { const v = this.sharedVars[fn.name]; const callee = v?.[convo_types_1.convoFlowControllerKey]?.sourceFn; if (!callee && (0, convo_lib_1.isConvoScopeFunction)(v)) { args = await this.paramsToObjAsync(fn.params); const paramValues = []; const labels = {}; for (const e in args) { const value = args[e]; labels[e] = paramValues.length; paramValues.push(value); } const scope = { i: 0, s: { s: 0, e: 0, fn: fn.name, }, vars: { [convo_lib_1.convoArgsName]: args, }, paramValues, labels, [convo_types_1.convoScopeFnKey]: v, [convo_types_1.convoScopeFnDefKey]: fn, }; const r = v(scope, this); const isP = (0, common_1.isPromise)(r); return { scope, value: isP ? undefined : r, valuePromise: isP ? r : undefined, }; } if (!callee) { // add exception for "responseWithText" function throw new ConvoError_1.ConvoError('function-not-defined', { fn }, `executeFunctionResultAsync - No function defined by the name ${fn.name}`); } args = await this.paramsToObjAsync(fn.params); fn = callee; } return this.executeFunction(fn, args); } getConvoFunctionArgsValue(fn) { const r = this.paramsToObj(fn.params ?? []); if (r.valuePromise) { throw new ConvoError_1.ConvoError('function-call-args-suspended'); } return r.value; } getConvoFunctionArgsScheme(fn, cache = true) { if (cache) { const s = fn[argsCacheKey]; if (s) { return s; } } let scheme; if (fn.paramType) { const type = this.getVarAsType(fn.paramType); if (!type) { throw new ConvoError_1.ConvoError('function-args-type-not-defined', { fn }); } if (!(0, common_1.valueIsZodObject)(type)) { throw new ConvoError_1.ConvoError('function-args-type-not-an-object', { fn }); } scheme = type; } else { scheme = this.paramsToScheme(fn.params ?? []); } if (cache) { fn[argsCacheKey] = scheme; } return scheme; } getConvoFunctionReturnScheme(fn, cache = true) { if (!fn.returnType) { return undefined; } if (cache) { const s = fn[returnCacheKey]; if (s) { return s; } } const typeVar = this.sharedVars[fn.returnType]; if (!typeVar) { throw new ConvoError_1.ConvoError('function-return-type-not-defined', { fn }, `Function return type not defined. function = ${fn.name}, returnType = ${fn.returnType}`); } const scheme = (0, convo_zod_1.convoValueToZodType)(typeVar); if (cache) { fn[returnCacheKey] = scheme; } return scheme; } getVarAsType(name) { const typeVar = this.sharedVars[name]; if (!typeVar) { return undefined; } return (0, convo_zod_1.convoValueToZodType)(typeVar); } paramsToObj(params) { const vars = {}; const scope = this.executeScope({ i: 0, vars, s: { fn: convo_lib_1.convoMapFnName, params, s: 0, e: 0, } }, undefined, createDefaultScope(vars)); return this.execute(scope, vars); } async paramsToObjAsync(params) { const r = this.paramsToObj(params); if (r.valuePromise) { return await r.valuePromise; } else { return r.value; } } paramsToScheme(params) { const vars = {}; const scope = this.executeScope({ i: 0, vars, s: { fn: convo_lib_1.convoStructFnName, params, s: 0, e: 0, } }, undefined, createDefaultScope(vars)); if (scope.si) { throw new ConvoError_1.ConvoError('suspended-scheme-statements-not-supported', { statements: params }, 'scheme statements should not be suspended'); } const zType = (0, convo_zod_1.convoValueToZodType)(scope.v); if (!(0, common_1.valueIsZodObject)(zType)) { throw new ConvoError_1.ConvoError('zod-object-expected', { statements: params }, 'ZodObject expected when converting ConvoStatements to zod type'); } return zType; } execute(scope, vars, resultScheme) { scope = this.executeScope(scope, undefined, createDefaultScope(vars)); if (scope.si) { return { scope, valuePromise: new Promise((r, j) => { if (!scope.onComplete) { scope.onComplete = []; } if (!scope.onError) { scope.onError = []; } scope.onError.push(j); if (resultScheme) { scope.onComplete.push(value => { const parsed = resultScheme.safeParse(value); if (parsed.success === true) { r(parsed.data); } else if (parsed.success === false) { j(new ConvoError_1.ConvoError('invalid-return-value-type', { statement: scope.s }, `Invalid result value - ${parsed.error.message}`)); } else { r(value); } }); } else { scope.onComplete.push(r); } }) }; } else { if (scope.error) { throw scope.error; } else { if (resultScheme) { const parsed = resultScheme.safeParse(scope.v); if (parsed.success === true) { return { scope, value: parsed.data }; } else if (parsed.success === false) { throw new ConvoError_1.ConvoError('invalid-return-value-type', { statement: scope.s }, `Invalid result value - ${parsed.error.message}`); } } return { scope, value: scope.v }; } } } executeScope(scope, parent, defaultScope, resumeParamScope, prevPi) { const statement = scope.s; let value = undefined; if (statement.fn) { scope = copyDefaultScope(scope); if (parent) { scope[convo_types_1.convoScopeFnDefKey] = parent[convo_types_1.convoScopeFnDefKey]; } const fn = scope[convo_types_1.convoScopeFnKey] ?? (scope[convo_types_1.convoScopeFnKey] = statement.fnPath ? (0, common_1.getValueByAryPath)(this.sharedVars, statement.fnPath)?.[statement.fn] : this.sharedVars[statement.fn]) ?? this.dynamicFunctionCallback ?? this.convo.conversation?.dynamicFunctionCallback; if (typeof fn !== 'function') { const errPath = statement.fnPath ? statement.fnPath.join('.') + '.' + statement.fn : statement.fn; (0, convo_lib_1.setConvoScopeError)(scope, `${errPath} is not a function`); value = undefined; return scope; } if (!scope.paramValues) { scope.paramValues = []; } const flowCtrl = fn[convo_types_1.convoFlowControllerKey]; const parentStartIndex = parent?.i ?? 0; if (flowCtrl?.keepData && parent?.childCtrlData) { const dr = parent.childCtrlData[parentStartIndex.toString()]; if (dr) { scope.ctrlData = dr.ctrlData; scope.childCtrlData = dr.childCtrlData; } } const shouldExecute = flowCtrl?.shouldExecute?.(scope, parent, this) ?? true; if (shouldExecute) { delete scope.li; if (flowCtrl?.startParam) { const startI = flowCtrl.startParam(scope, parent, this); if (startI === false) { scope.i = statement.params?.length ?? 0; } else { scope.i = Math.max(0, startI); } } if (statement.params?.length) { if (flowCtrl?.usesLabels && !scope.labels) { scope.labels = {}; } while (scope.i < statement.params.length && (scope.bi !== scope.i)) { const paramStatement = statement.params[scope.i]; if (paramStatement) { let paramScope; if (resumeParamScope) { paramScope = resumeParamScope; resumeParamScope = undefined; } else { const d = defaultScope; d.s = paramStatement; paramScope = this.executeScope(d, scope, defaultScope); } if (paramScope.error) { (0, convo_lib_1.setConvoScopeError)(scope, paramScope.error); return scope; } if (paramScope.si) { this.suspendScope(scope, paramScope); paramScope.pi = scope.si; if (prevPi) { scope.pi = prevPi; } return scope; } if (flowCtrl?.discardParams) { scope.paramValues[0] = paramScope.v; } else { scope.paramValues.push(paramScope.v); } if (paramScope.r) { value = paramScope.v; scope.r = true; break; } if (paramScope.bl) { if (flowCtrl?.catchBreak) { break; } else if (scope.li === scope.i) { delete scope.fromIndex; delete scope.gotoIndex; delete scope.li; } else { scope.bl = true; return scope; } } if (scope.fromIndex === scope.i && scope.gotoIndex !== undefined) { scope.i = scope.gotoIndex; delete scope.fromIndex; delete scope.gotoIndex; } else if (flowCtrl?.nextParam) { const f = flowCtrl.nextParam(scope, parent, paramStatement, this); if (f === false) { break; } scope.i = f; } else { scope.i++; } } else { (0, convo_lib_1.setConvoScopeError)(scope, 'Parameter expected'); return scope; } } } if (!scope.r) { if (statement.fnPath) { value = (0, common_1.getValueByAryPath)(this.sharedVars, statement.fnPath)?.[statement.fn]?.(...(scope.paramValues ?? emptyAry)); } else { value = fn(scope, this); } if (statement.prompt) { if (this.disableInlinePrompts) { (0, convo_lib_1.setConvoScopeError)(scope, { message: `Inline prompts not allowed in current content. Inline prompts can not be used in content messages or top level statements`, statement, }); return scope; } if (statement.prompt.isStatic) { value = this.executeStaticPrompt(statement.prompt, value, scope); } else { value = this.executePromptAsync(statement.prompt, scope); } } } } if (scope.r) { if (flowCtrl?.catchReturn) { scope.r = false; } } else if (flowCtrl) { if (flowCtrl.keepData && parent) { if (!parent.childCtrlData) { parent.childCtrlData = {}; } const dr = { ctrlData: scope.ctrlData, childCtrlData: scope.childCtrlData, }; parent.childCtrlData[parentStartIndex.toString()] = dr; } if (flowCtrl.transformResult) { value = flowCtrl.transformResult(value, scope, parent, this); } } } else if (statement.ref) { value = this.getVarEx(statement.ref, statement.refPath, scope); } else if (statement.prompt) { if (this.disableInlinePrompts) { (0, convo_lib_1.setConvoScopeError)(scope, { message: `Inline prompts not allowed in current content. Inline prompts can not be used in content messages or top level statements`, statement, }); return scope; } if (statement.prompt.isStatic) { value = this.executeStaticPrompt(statement.prompt, statement.value, scope); } else { value = this.executePromptAsync(statement.prompt, scope); } } else { value = statement.value; } if (scope.error) { return scope; } if ((0, common_1.isPromise)(value)) { scope = copyDefaultScope(scope); this.suspendScope(scope); value.then(v => { scope.v = v; this.completeScope(scope, parent, defaultScope); }).catch(e => { (0, convo_lib_1.setConvoScopeError)(scope, { message: `Promise throw error - ${e?.message}`, error: e, statement, }); this.completeScope(scope, parent, defaultScope); }); } else { scope.v = value; this.completeScope(scope, parent, defaultScope); } return scope; } lastInlineConversation; executeStaticPrompt(prompt, value, scope) { this.beforeHandlePromptResult(prompt); const valueIsString = typeof value === 'string'; if ((prompt.continue && prompt.isStatic) && valueIsString) { if (!this.lastInlineConversation) { this.lastInlineConversation = this.createInlineConversation(prompt); } this.applyInlinePrompt(prompt, this.lastInlineConversation, scope); this.lastInlineConversation.append((prompt.hasRole ? '' : '> user\n') + value, { addTags: [{ name: convo_lib_1.convoTags.disableModifiers }] }); } if (prompt.jsonType && valueIsString) { value = (0, json5_1.parseJson5)(value); } return this.handlePromptResult(prompt, value, scope); } createInlineConversation(prompt) { const options = { disableAutoFlatten: true, disableTriggers: true, disableTransforms: !prompt.transforms }; return (this.parentConvo ?? new Conversation_1.Conversation(options))?.clone({ inlinePrompt: prompt, triggerName: this.getVar(convo_lib_1.convoVars.__trigger) }, options); } applyInlinePrompt(prompt, convo, scope) { convo.inlinePrompt = prompt; for (const e in convo.defaultVars) { delete convo.defaultVars[e]; } const vars = this.getUserSharedVars(); for (const e in vars) { convo.defaultVars[e] = vars[e]; } for (const e in scope.vars) { if (e in convo_default_vars_1.defaultConvoVars) { continue; } convo.defaultVars[e] = scope.vars[e]; } } async executePromptAsync(prompt, scope) { if (this.parentConvo && this.parentConvo.childDepth > this.maxInlinePromptDepth) { throw new Error('Max inline prompt depth reached'); } const sub = (prompt.continue && this.lastInlineConversation) ? this.lastInlineConversation : this.createInlineConversation(prompt); this.applyInlinePrompt(prompt, sub, scope); if (prompt.continue || prompt.extend) { this.lastInlineConversation = sub; } if (prompt.messages?.length) { sub.appendMessageObject(prompt.messages); } this.beforeHandlePromptResult(prompt); const disposeTask = prompt.task ? this.parentConvo?.addTask(prompt.task) : undefined; let r; try { r = await sub.completeAsync(); } finally { disposeTask?.(); } let value; if (r.message?.format === 'json') { value = (0, json5_1.parseJson5)(r.message.content ?? ''); if (r.message.formatTypeName === 'TrueFalse') { value = value?.isTrue; } } else { value = r.message?.content; } return this.handlePromptResult(prompt, value, scope); } beforeHandlePromptResult(prompt) { // systemMessages if (prompt.systemMessages) { const append = (convo, type) => { if (!convo.findMessage({ tag: convo_lib_1.convoTags.stdSystem, tagValue: type })) { convo.append((0, convo_lib_1.getConvoSystemMessage)(type), { disableAutoFlatten: true }); } }; for (const s of prompt.systemMessages) { if (this.parentConvo) { append(this.parentConvo, s); } if (this.lastInlineConversation) { append(this.lastInlineConversation, s); } } } } handlePromptResult(prompt, value, scope) { if (prompt?.not) { value = !value; } if (prompt.assignOutputTo) { this.setVar(undefined, value, prompt.assignOutputTo, undefined, scope); } if (this.parentConvo) { // appendOutput if (prompt.appendOutput) { const output = typeof value === 'string' ? value : JSON.stringify(value); this.parentConvo.append(((0, convo_parser_1.doesConvoContentHaveMessage)(output) ? '' : '> append\n') + output, { disableAutoFlatten: true }); } // action if (prompt.action) { let content = value; if (typeof content !== 'string') { try { content = JSON.stringify(content); } catch { content = content + ''; } } if ((0, convo_types_1.isConvoMessageModification)(prompt.action)) { this.parentConvo.appendModification(prompt.action, content, this.flat); } else if (prompt.action === 'respond' && this.flat) { this.parentConvo.appendResponse(prompt.hasRole ? content : `> assistant\n${(0, convo_lib_1.escapeConvo)(content)}`, this.flat); } } } return (!prompt.preSpace && (typeof value === 'string')) ? value.trim() : value; } suspendScope(scope, waitFor) { if (!scope.si) { scope.si = (this.nextSuspendId++).toString(); } this.suspendedScopes[scope.si] = scope; if (waitFor) { scope.wi = waitFor.si; } } completeScope(scope, parent, defaultScope) { if (scope.wi) { throw new ConvoError_1.ConvoError('scope-waiting', { statement: scope.s }, `scope waiting on scope(${scope.wi}) before resuming`); } const statement = scope.s; if (statement.set) { this.setVar(statement.shared, scope.v, statement.set, statement.setPath, scope); } if (statement.label && parent?.labels) { parent.labels[statement.label] = statement.opt ? (0, convo_lib_1.createOptionalConvoValue)(parent.i) : parent.i; } delete scope.pi; const resume = scope.si ? [] : null; if (scope.si) { const si = scope.si; delete scope.si; delete this.suspendedScopes[si]; for (const e in this.suspendedScopes) { const ss = this.suspendedScopes[e]; if (ss?.wi === si) { delete this.suspendedScopes[e]; delete ss.wi; resume.push(ss); } } } if (scope.onComplete) { const oc = scope.onComplete; delete scope.onComplete; delete scope.onError; for (let i = 0; i < oc.length; i++) { oc[i]?.(scope.v); } } if (resume) { for (const r of resume) { const parent = r.pi ? this.suspendedScopes[r.pi] : undefined; if (r.pi && !parent) { throw new ConvoError_1.ConvoError('suspension-parent-not-found', { statement: scope.s }); } const prevPi = r.pi; delete r.pi; this.executeScope(r, parent, defaultScope, scope, prevPi); } } } getRefValue(statement, scope, throwUndefined = true) { if (!statement) { return undefined; } if (!statement.ref) { throw new ConvoError_1.ConvoError('variable-ref-required', { statement }); } return this.getVarEx(statement.ref, statement.refPath, scope, throwUndefined); } getVarEx(name, path, scope, throwUndefined = this.defaultThrowOnUndefined) { let value = scope?.vars[name] ?? this.sharedVars[name]; if (value === undefined && (scope ? !(name in scope.vars) : true) && !(name in this.sharedVars)) { if (throwUndefined) { (0, convo_lib_1.setConvoScopeError)(scope, `reference to undefined var - ${name}`); } } else if (path) { value = (0, common_1.getValueByAryPath)(value, path); } if (!path && value === undefined) { return this.getVarAlias(name); } else { return value; } } getVar(nameOrPath, scope, defaultValue) { let path = undefined; if (nameOrPath.includes('.')) { path = nameOrPath.split('.'); nameOrPath = path.shift() ?? ''; } return this.getVarEx(nameOrPath, path, scope ?? undefined, false) ?? defaultValue; } getStringVar(nameOrPath, scope, defaultValue) { const val = this.getVar(nameOrPath, scope, defaultValue); return (typeof val === 'string') ? val : undefined; } setRefValue(statement, value, scope) { if (!statement) { return value; } if (!statement.ref) { throw new ConvoError_1.ConvoError('variable-ref-required', { statement }); } this.setVar(statement.shared, value, statement.ref, statement.refPath, scope); return value; } setDefaultVarValue(value, name, path) { if (name in convo_default_vars_1.defaultConvoVars) { (0, convo_lib_1.setConvoScopeError)(null, `Overriding builtin var not allowed - ${name}`); return value; } if (this.sharedVars[name] !== undefined) { return this.sharedVars[name]; } return this.setVar(true, value, name, path); } setVar(shared, value, name, path, scope) { if (name in convo_default_vars_1.defaultConvoVars) { (0, convo_lib_1.setConvoScopeError)(scope, `Overriding builtin var not allowed - ${name}`); return value; } if (this.isReadonly) { const msg = `Current context is readonly. Unable to set ${name}`; if (scope) { (0, convo_lib_1.setConvoScopeError)(scope, msg); return value; } else { throw new Error(msg); } } if (this.varPrefix) { name = this.varPrefix + name; } const vars = (shared || !scope || (scope && scope.vars[name] === undefined && this.sharedVars[name] !== undefined)) ? this.sharedVars : scope.vars; if (shared !== false && vars === this.sharedVars && (typeof value !== 'function')) { const setterName = path ? name + '.' + path.join('.') : name; const i = this.sharedSetters.indexOf(setterName); if (i !== -1) { this.sharedSetters.splice(i, 1); } this.sharedSetters.push(setterName); } if (path) { let obj = vars[name]; if (obj === undefined || obj === null) { if (this.defaultThrowOnUndefined) { (0, convo_lib_1.setConvoScopeError)(scope, `reference to undefined var for setting path - ${name}`); } return value; } if (path.length > 1) { obj = (0, common_1.getValueByAryPath)(obj, path, undefined, path.length - 1); if (obj === undefined || obj === null) { if (this.defaultThrowOnUndefined) { (0, convo_lib_1.setConvoScopeError)(scope, `reference to undefined var at path - ${name}.${path.join('.')}`); } return value; } } obj[path[path.length - 1] ?? ''] = value; } else { vars[name] = value; } return value; } setVarUsingCompletionMessage(shared, msg, name, path, scope) { if (msg.format === 'json') { try { this.setVar(shared, msg.content ? (0, convo_lib_1.parseConvoJsonMessage)(msg.content) : null, name, path, scope); } catch (ex) { this.setVar(shared, (0, common_1.getErrorMessage)(ex), name, path, scope); } } else { this.setVar(shared, msg.content ?? '', name, path, scope); } } consumeVars(otherExec) { if (!otherExec) { return; } for (const e in otherExec.sharedVars) { if (this.sharedVars[e] === undefined) { this.sharedVars[e] = otherExec.sharedVars[e]; } } } getTagValueByName(msg, tagName, defaultValue) { const tag = (0, convo_lib_1.getConvoTag)(msg?.tags, tagName); if (!tag) { return defaultValue; } return this.getTagValue(tag, defaultValue); } getTagValue(tag, defaultValue) { let value; if (tag.statement) { const r = this.getTagStatementValue(tag); value = r.length > 1 ? r : r[0]; } else { value = tag.value; } return value === undefined ? defaultValue : value; } isTagConditionTrueByName(msg, tagName, defaultValue = false) { const tag = (0, convo_lib_1.getConvoTag)(msg?.tags, tagName); if (!tag) { return false; } return this.isTagConditionTrue(tag, defaultValue); } isTagConditionTrue(tag, defaultValue = false) { if (tag.statement) { return this.getTagStatementValue(tag).every(v => v); } else if (tag.value !== undefined) { let tagValue = tag.value.trim(); if (!tagValue) { return true; } const not = tagValue.startsWith('!'); if (not) { tagValue = tagValue.substring(1).trim(); } const parts = tagValue.split(/\s+/); if (parts.length < 1) { return false; } let value = this.getVar(parts[0] ?? ''); if (not) { value = !value; } if (parts.length === 1) { return value ? true : false; } let v2; if (parts.length > 2) { parts.shift(); v2 = parts.join(' '); } else { v2 = parts[1]; } return value?.toString() === v2; } else { return defaultValue; } } getTagStatementValue(tag) { if (!tag.statement?.length) { return []; } this.isReadonly++; try { const values = tag.statement.map(s => { const r = this.executeStatement(s); if (r.valuePromise) { throw new Error('Tag value statements are not allowed to return promises'); } return r.value; }); return values; } finally { this.isReadonly--; } } enableRag(paramValues) { this.setVar(true, true, convo_lib_1.convoVars.__rag); let ragParams = this.getVar(convo_lib_1.convoVars.__ragParams); if (!ragParams || (typeof ragParams !== 'object')) { ragParams = {}; this.setVar(true, ragParams, convo_lib_1.convoVars.__ragParams); } if (!Array.isArray(ragParams.values)) { ragParams.values = []; } const ary = ragParams.values; if (paramValues) { for (const v of paramValues) { if (!ary.includes(v)) { ary.push(v); } } } return ary; } clearRag() { this.setVar(true, false, convo_lib_1.convoVars.__rag); this.setVar(true, undefined, convo_lib_1.convoVars.__ragParams); } /** * Gets built-in type aliases by name. Used to provide predefined types * that are commonly used in Convo-Lang but not explicitly defined in user code. * * @param name - The name of the type alias to retrieve * @returns The type definition, or undefined if the alias doesn't exist */ getVarAlias(name) { switch (name) { case 'TrueFalse': return (0, convo_cached_parsing_1.parseConvoType)('TrueFalse', /*convo*/ ` > define TrueFalse=struct( isTrue:boolean ) `); default: return undefined; } } } exports.ConvoExecutionContext = ConvoExecutionContext; const emptyAry = []; //# sourceMappingURL=ConvoExecutionContext.js.map