@convo-lang/convo-lang
Version:
The language of AI
1,049 lines • 40.4 kB
JavaScript
"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