@convo-lang/convo-lang
Version:
The language of AI
295 lines • 10.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isLockedConvoObject = exports.isConvoObject = exports.convo = void 0;
const common_1 = require("@iyio/common");
const Conversation_1 = require("./Conversation");
const convo_lib_1 = require("./convo-lib");
const convo_template_1 = require("./convo-template");
const convo_types_1 = require("./convo-types");
const jsonEndReg = /@json[ \t]*$/;
let fnIndex = 0;
/**
* Converts a template literal string into a ConvoObject. The completion of the conversation
* is not started until then, catch, finally, getValue or getCompletionAsync is called. After one
* of the previously stated functions or getInput, getValueAsync or getCompletionAsync are called
* the ConvoObject is considered finalized and non of the setter function will be allowed
* to be called, if they are called an error will be thrown.
*/
const convo = (strings, valueOrZodType, ...values) => {
const isLocked = valueOrZodType === lockFlag;
if (isLocked) {
valueOrZodType = values.shift();
}
const cloneSrc = {
valueOrZodType,
values: [...values]
};
let options;
let conversation;
const zodName = (0, common_1.getZodTypeName)(valueOrZodType);
const dependencies = [
valueOrZodType,
...values,
...strings,
];
const isFinalized = () => (conversation || _input !== undefined) ? true : false;
let _input;
const getInput = () => {
if (_input !== undefined) {
return _input;
}
let prefix = '';
if (zodName && jsonEndReg.test(strings[0] ?? '')) {
prefix = (0, convo_template_1.convoScript) `> define\nInlineJsonType=${valueOrZodType}\n\n`;
values.splice(0, 0, ' InlineJsonType');
}
else {
values.splice(0, 0, valueOrZodType);
}
for (let i = 0; i < values.length; i++) {
const fn = values[i];
if (typeof fn !== 'function') {
continue;
}
const index = fnIndex++;
const name = `_inline_extern_function_${index}_`;
const next = strings[i + 1];
if (next?.startsWith('_')) { // call function
values[i] = name.substring(0, name.length - 1);
if (!internalExternFunctions) {
internalExternFunctions = {};
}
internalExternFunctions[name] = fn;
}
else { // define as function body
values[i] = `(${name}(__args))`;
if (!externScopeFunctions) {
externScopeFunctions = {};
}
const externFn = fn;
externScopeFunctions[name] = (scope) => {
const argsObj = scope.paramValues?.[0];
if (!argsObj || !(typeof argsObj === 'object')) {
throw new Error(`__args object should be passed to ${name}`);
}
const scopeFn = scope[convo_types_1.convoScopeFnDefKey];
if (!scopeFn) {
throw new Error(`convoScopeFnDefKey not defined in scope when calling ${name}`);
}
const args = [];
for (const p of scopeFn.params) {
if (p.label) {
args.push(argsObj[p.label]);
}
}
return externFn(...args);
};
}
}
_input = prefix + (0, convo_template_1.convoScript)(strings, ...values);
return _input;
};
const getOutputOptions = () => {
// must call get input since it can register extern functions
getInput();
return {
defaultVars: (options?.defaultVars || defaultVars) ? { ...options?.defaultVars, ...defaultVars } : undefined,
externFunctions: (options?.externFunctions || externFunctions || internalExternFunctions) ? { ...options?.externFunctions, ...internalExternFunctions, ...externFunctions } : undefined,
externScopeFunctions: (options?.externScopeFunctions || externScopeFunctions) ? { ...options?.externScopeFunctions, ...externScopeFunctions } : undefined,
};
};
const getConversation = () => {
if (conversation) {
return conversation;
}
conversation = new Conversation_1.Conversation({
...options,
...getOutputOptions(),
});
return conversation;
};
const assertUpdate = () => {
if (isFinalized()) {
throw new Error('Unable modify finalized convo object');
}
if (isLocked) {
throw new Error('Unable locked finalized convo object');
}
};
const setConversation = (_conversation) => {
dependencies.push(`instId:${_conversation.instanceId}`);
conversation = _conversation;
return _self;
};
const setOptions = (_options) => {
assertUpdate();
for (const e in _options) {
const v = _options[e];
dependencies.push(e, v);
}
options = _options;
return _self;
};
const getValueAsync = async () => {
return (await getCompletionAsync()).value;
};
let valuePromise;
const getCompletionAsync = () => {
return valuePromise ?? (valuePromise = _getCompletionAsync());
};
const _getCompletionAsync = async () => {
const cv = getConversation();
cv.append(getInput());
const completion = await cv.completeAsync({ returnOnCalled: true });
return {
value: (0, convo_lib_1.getAssumedConvoCompletionValue)(completion),
completion
};
};
let defaultVars;
const addVars = (vars) => {
assertUpdate();
if (!defaultVars) {
defaultVars = {};
}
for (const e in vars) {
const v = vars[e];
defaultVars[e] = v;
dependencies.push(e, v);
}
return _self;
};
let externScopeFunctions;
let externFunctions;
let internalExternFunctions;
const setExternFunctions = (functions) => {
assertUpdate();
if (!externFunctions) {
externFunctions = {};
}
for (const e in functions) {
const fn = functions[e];
dependencies.push(e, fn);
if (fn) {
externFunctions[e] = fn;
}
}
return _self;
};
const clone = (lock) => {
const clone = (lock ?
(0, exports.convo)(strings, lockFlag, cloneSrc.valueOrZodType, ...cloneSrc.values) :
(0, exports.convo)(strings, cloneSrc.valueOrZodType, ...cloneSrc.values));
if (defaultVars) {
clone.addVars(defaultVars);
}
if (externFunctions) {
clone.setExternFunctions(externFunctions);
}
if (options) {
clone.setOptions(options);
}
return clone;
};
const _self = {
getInput,
dependencies,
zodType: zodName ? valueOrZodType : undefined,
isFinalized,
getConversation,
setConversation,
getValueAsync,
getCompletionAsync,
setOptions,
addVars,
setExternFunctions,
getOutputOptions,
debug: (verbose) => {
const f = isFinalized();
console.log('ConvoObject', {
isFinalized: f,
input: f ? getInput() : null,
vars: defaultVars,
dependencies,
options,
externFunctions,
externScopeFunctions,
internalExternFunctions,
conversation: verbose ? getConversation() : undefined,
});
return _self;
},
convertAsync: () => {
const c = getConversation().clone();
c.append(getInput());
return c.toModelInputAsync();
},
flattenAsync: () => {
const c = getConversation().clone();
c.append(getInput());
return c.flattenAsync();
},
clone: () => {
return clone(false);
},
then: (callback) => {
getValueAsync().then(callback);
return _self;
},
catch: (callback) => {
getValueAsync().catch(callback);
return _self;
},
finally: (callback) => {
getValueAsync().finally(callback);
return _self;
},
proxyFunctions: (proxy) => {
assertUpdate();
if (typeof valueOrZodType === 'function') {
const proxied = proxy(0, valueOrZodType);
if (proxied) {
valueOrZodType = proxied;
dependencies[0] = proxied;
}
}
for (let i = 0; i < values.length; i++) {
const fn = values[i];
if (typeof fn !== 'function') {
continue;
}
const proxied = proxy(i + 1, fn);
if (proxied) {
values[i] = proxied;
dependencies[i + 1] = proxied;
}
}
},
lock: () => {
const c = clone(true);
return {
dependencies: c.dependencies,
zodType: c.zodType,
clone: c.clone,
debug: c.debug,
isFinalized: c.isFinalized,
getOutputOptions: c.getOutputOptions,
};
}
};
_self[isLocked ? lockedConvoObjectIdentifier : convoObjectIdentifier] = true;
return _self;
};
exports.convo = convo;
const isConvoObject = (value) => {
return value?.[convoObjectIdentifier] === true;
};
exports.isConvoObject = isConvoObject;
const isLockedConvoObject = (value) => {
return value?.[lockedConvoObjectIdentifier] === true;
};
exports.isLockedConvoObject = isLockedConvoObject;
const convoObjectIdentifier = Symbol('ConvoObject');
const lockedConvoObjectIdentifier = Symbol('LockedConvoObject');
const lockFlag = Symbol();
//# sourceMappingURL=convoAsync.js.map