@iyio/convo-lang
Version:
A conversational language.
846 lines • 31.7 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.isReservedConvoRole = exports.convoLabeledScopeParamsToObj = exports.getConvoMetadata = exports.createConvoMetadataForStatement = exports.mapToConvoTags = exports.convoTagsToMap = exports.getConvoTag = exports.containsConvoTag = exports.convoTagMapToCode = exports.setConvoScopeError = exports.createConvoScopeFunction = exports.makeAnyConvoType = exports.createConvoBaseTypeDef = exports.createConvoType = exports.createOptionalConvoValue = exports.allowedConvoDefinitionFunctions = exports.defaultConvoVisionResponse = exports.defaultConvoVisionSystemMessage = exports.getConvoDateString = exports.defaultConvoRenderTarget = exports.convoDateFormat = exports.convoTaskTriggers = exports.convoTags = exports.defaultConvoRagTol = exports.convoVars = exports.convoFunctions = exports.convoRoles = exports.defaultConvoTask = exports.convoCaptureMetadataTag = exports.convoMetadataKey = exports.convoEnumFnName = exports.convoGlobalRef = exports.convoCallFunctionModifier = exports.convoLocalFunctionModifier = exports.convoPipeFnName = exports.convoTestFnName = exports.convoDefaultFnName = exports.convoCaseFnName = exports.convoSwitchFnName = exports.convoJsonArrayFnName = exports.convoJsonMapFnName = exports.convoArrayFnName = exports.convoMapFnName = exports.convoNewFnName = exports.convoStructFnName = exports.convoDisableAutoCompleteName = exports.convoResultErrorName = exports.convoResultReturnName = exports.convoArgsName = exports.convoBodyFnName = void 0;
exports.isConvoThreadFilterMatch = exports.getLastCompletionMessage = exports.convoMessageToString = exports.escapeConvoTagValue = exports.convoRagDocRefToMessage = exports.shouldDisableConvoAutoScroll = exports.getFlatConvoTag = exports.parseConvoBooleanTag = exports.getConvoStatementSource = exports.parseConvoMessageTemplate = exports.isConvoMessageIncludedInTask = exports.concatConvoCodeAndAppendEmptyUserMessage = exports.concatConvoCode = exports.removeDanglingConvoUserMessage = exports.parseConvoJsonMessage = exports.resetConvoUsageTokens = exports.createEmptyConvoTokenUsage = exports.addConvoUsageTokens = exports.parseConvoUsageTokens = exports.convoUsageTokensToString = exports.validateConvoTypeName = exports.validateConvoFunctionName = exports.validateConvoVarName = exports.isValidConvoTypeName = exports.isValidConvoFunctionName = exports.isValidConvoVarName = exports.convoStringToComment = exports.convoStringToCommentOut = exports.convoDescriptionToComment = exports.convoDescriptionToCommentOut = exports.collapseConvoPipes = exports.defaultConvoPrintFunction = exports.spreadConvoArgs = exports.escapeConvoMessageContent = exports.formatConvoMessage = exports.isValidConvoIdentifier = exports.isValidConvoRole = void 0;
const common_1 = require("@iyio/common");
const json5_1 = require("@iyio/json5");
const date_fns_1 = require("date-fns");
const ConvoError_1 = require("./ConvoError");
const convo_types_1 = require("./convo-types");
exports.convoBodyFnName = '__body';
exports.convoArgsName = '__args';
exports.convoResultReturnName = '__return';
exports.convoResultErrorName = '__error';
exports.convoDisableAutoCompleteName = '__disableAutoComplete';
exports.convoStructFnName = 'struct';
exports.convoNewFnName = 'new';
exports.convoMapFnName = 'map';
exports.convoArrayFnName = 'array';
exports.convoJsonMapFnName = 'jsonMap';
exports.convoJsonArrayFnName = 'jsonArray';
exports.convoSwitchFnName = 'switch';
exports.convoCaseFnName = 'case';
exports.convoDefaultFnName = 'default';
exports.convoTestFnName = 'test';
exports.convoPipeFnName = 'pipe';
exports.convoLocalFunctionModifier = 'local';
exports.convoCallFunctionModifier = 'call';
exports.convoGlobalRef = 'convo';
exports.convoEnumFnName = 'enum';
exports.convoMetadataKey = Symbol('convoMetadataKey');
exports.convoCaptureMetadataTag = 'captureMetadata';
exports.defaultConvoTask = 'default';
exports.convoRoles = {
user: 'user',
assistant: 'assistant',
rag: 'rag',
/**
* Used to define a prefix to add to rag messages
*/
ragPrefix: 'ragPrefix',
/**
* Used to define a suffix to add to rag messages
*/
ragSuffix: 'ragSuffix',
};
exports.convoFunctions = {
queryImage: 'queryImage',
getState: 'getState',
};
/**
* reserved system variables
*/
exports.convoVars = {
/**
* In environments that have access to the filesystem __cwd defines the current working directory.
*/
__cwd: '__cwd',
/**
* When set to true debugging information will be added to conversations.
*/
__debug: '__debug',
/**
* Sets the default model
*/
__model: '__model',
/**
* Sets the default completion endpoint
*/
__endpoint: '__endpoint',
/**
* When set to true time tracking will be enabled.
*/
__trackTime: '__trackTime',
/**
* When set to true token usage tracking will be enabled.
*/
__trackTokenUsage: '__trackTokenUsage',
/**
* When set to true the model used as a completion provider will be tracked.
*/
__trackModel: '__trackModel',
/**
* When defined __visionSystemMessage will be injected into the system message of conversations
* with vision capabilities. __visionSystemMessage will override the default vision
* system message.
*/
__visionSystemMessage: '__visionSystemMessage',
/**
* The default system message used for completing vision requests. Vision requests are typically
* completed in a separate conversation that supports vision messages. By default the system
* message of the conversation that triggered the vision request will be used.
*/
__visionServiceSystemMessage: '__visionServiceSystemMessage',
/**
* Response used with the system is not able to generate a vision response.
*/
__defaultVisionResponse: '__defaultVisionResponse',
/**
* A reference to markdown vars.
*/
__md: '__md',
/**
* Enables retrieval augmented generation (RAG). The value of the __rag can either be true,
* false or a number. The value indicates the number of rag results that should be sent to the
* LLM by default all rag message will be sent to the LLM. When setting the number of rag
* messages to a fixed number only the last N number of rag messages will be sent to the LLM.
* Setting __rag to a fixed number can help to reduce prompt size.
*/
__rag: '__rag',
/**
* An object that will be passed to the rag callback of a conversation. If the value is not an
* object it is ignored.
*/
__ragParams: '__ragParams',
/**
* The tolerance that determines if matched rag content should be included as contact.
*/
__ragTol: '__ragTol',
/**
* Sets the current thread filter. Can either be a string or a ConvoThreadFilter. If __threadFilter
* is a string it will be converted into a filter that looks like `{includeThreads:[__threadId]}`.
*/
__threadFilter: '__threadFilter'
};
exports.defaultConvoRagTol = 1.2;
exports.convoTags = {
/**
* When applied to a function the return value of the function will not be used to generate a
* new assistant message.
*/
disableAutoComplete: 'disableAutoComplete',
/**
* Used to indicate that a message should be evaluated at the edge of a conversation with the
* latest state. @edge is most commonly used with system message to ensure that all injected values
* are updated with the latest state of the conversation.
*/
edge: 'edge',
/**
* Used to track the time messages are created.
*/
time: 'time',
/**
* Used to track the number of tokens a message used
*/
tokenUsage: 'tokenUsage',
/**
* Used to track the model used to generate completions
*/
model: 'model',
/**
* Sets the requested model to complete a message with
*/
responseModel: 'responseModel',
/**
* Used to track the endpoint to generate completions
*/
endpoint: 'endpoint',
/**
* Sets the requested endpoint to complete a message with
*/
responseEndpoint: 'responseEndpoint',
/**
* Sets the format as message should be responded to with.
*/
responseFormat: 'responseFormat',
/**
* Causes the response of the tagged message to be assigned to a variable
*/
responseAssign: 'responseAssign',
/**
* When used with a message the json tag is short and for `@responseFormat json`
*/
json: 'json',
/**
* The format of a message
*/
format: 'format',
/**
* Used to assign the content or jsonValue of a message to a variable
*/
assign: 'assign',
/**
* Used to enable capabilities. Only the first and last message in the conversation are used
* to determine current capabilities. Multiple capability tags can be
* applied to a message and multiple capabilities can be specified by separating them with a
* comma.
*/
capability: 'capability',
/**
* Shorthand for `@capability vision`
*/
enableVision: 'enableVision',
/**
* Sets the task a message is part of. By default messages are part of the "default" task
*/
task: 'task',
/**
* Sets the max number of non-system messages that should be included in a task completion
*/
maxTaskMessageCount: 'maxTaskMessageCount',
/**
* Defines what triggers a task
*/
taskTrigger: 'taskTrigger',
/**
* Defines a message as a template
*/
template: 'template',
/**
* used to track the name of templates used to generate messages
*/
sourceTemplate: 'sourceTemplate',
/**
* Used to mark a message as a component. The value of the tag is used as the component name.
* If no value is provided then the component will be unnamed.
*/
component: 'component',
/**
* When applied to a message the message should be rendered but not sent to LLMs
*/
renderOnly: 'renderOnly',
/**
* Controls where a message is rendered. By default messages are rendered in the default chat
* view, but applications can define different render targets.
*/
renderTarget: 'renderTarget',
toolId: 'toolId',
/**
* When applied to the last content or component messages auto scrolling will be disabled
*/
disableAutoScroll: 'disableAutoScroll',
/**
* When applied to a message the content of the message will be parsed as markdown
*/
markdown: 'markdown',
/**
* When applied to a message the content of the message will be parsed as markdown and the
* elements of the markdown will be auto assigned to vars
*/
markdownVars: 'markdownVars',
/**
* When applied to a message the message is conditionally added to the flattened view of a
* conversation. When the condition is false the message will not be visible to the user
* or the LLM.
*
* @note The example below uses (at) instead of the at symbol because of a limitation of jsdoc.
*
* The example below will only render and send the second system message to the LLM
* @example
*
* ``` convo
* > define
* animal = 'dog'
*
* (at)condition animal frog
* > system
* You are a frog and you like to hop around.
*
* (at)condition animal dog
* > system
* You are a dog and you like to eat dirt.
* ```
*/
condition: 'condition',
/**
* A URL to the source of the message. Typically used with RAG.
*/
sourceUrl: 'sourceUrl',
/**
* The ID of the source content of the message. Typically used with RAG.
*/
sourceId: 'sourceId',
/**
* The name of the source content of the message. Typically used with RAG.
*/
sourceName: 'sourceName',
/**
* When applied to a message the message becomes a clickable suggestion that when clicked will
* add a new user message with the content of the message. If the suggestion tag defines a value
* that value will be displayed on the clickable button instead of the message content but the
* message content will still be used as the user messaged added to the conversation when clicked.
* Suggestion message are render only and not seen by LLMs.
*/
suggestion: 'suggestion',
/**
* Sets the threadId of the current message and all following messages. Using the `@thread` tag
* without a value will clear the current thread id.
*/
thread: 'thread',
/**
* Used to mark a function as a node output.
*/
output: 'output',
/**
* Used to mark a function as an error callback
*/
errorCallback: 'errorCallback',
/**
* Used to import external convo script code
*/
import: 'import',
/**
* Causes a message to be concatenated with the previous message. Both the message the tag
* is attached to and the previous message must be content messages or the tag is ignored.
* When a message is concatenated to another message all other tags except the condition
* tag are ignored.
*/
concat: 'concat',
};
exports.convoTaskTriggers = {
/**
* Triggers a text message is received. Function calls will to trigger.
*/
onResponse: 'onResponse'
};
exports.convoDateFormat = "yyyy-MM-dd'T'HH:mm:ssxxx";
exports.defaultConvoRenderTarget = 'default';
const getConvoDateString = (date = new Date()) => {
return (0, date_fns_1.format)(date, exports.convoDateFormat);
};
exports.getConvoDateString = getConvoDateString;
exports.defaultConvoVisionSystemMessage = ('If the user references a markdown image without a ' +
'description or the description can not answer the user\'s question or ' +
`complete the user\`s request call the ${exports.convoFunctions.queryImage} function. ` +
'Do not use the URL of the image to make any assumptions about the image.');
exports.defaultConvoVisionResponse = 'Unable to answer or respond to questions or requests for the given image or images';
exports.allowedConvoDefinitionFunctions = [
exports.convoNewFnName,
exports.convoStructFnName,
exports.convoMapFnName,
exports.convoArrayFnName,
exports.convoEnumFnName,
exports.convoJsonMapFnName,
exports.convoJsonArrayFnName,
exports.convoFunctions.getState,
];
const createOptionalConvoValue = (value) => {
return {
[convo_types_1.convoObjFlag]: 'optional',
value,
};
};
exports.createOptionalConvoValue = createOptionalConvoValue;
const createConvoType = (typeDef) => {
typeDef[convo_types_1.convoObjFlag] = 'type';
return typeDef;
};
exports.createConvoType = createConvoType;
const createConvoBaseTypeDef = (type) => {
return {
[convo_types_1.convoObjFlag]: 'type',
type,
};
};
exports.createConvoBaseTypeDef = createConvoBaseTypeDef;
const makeAnyConvoType = (type, value) => {
if (!value) {
return value;
}
value[convo_types_1.convoObjFlag] = 'type';
value['type'] = type;
return value;
};
exports.makeAnyConvoType = makeAnyConvoType;
const createConvoScopeFunction = (fnOrCtrl, fn) => {
if (typeof fnOrCtrl === 'function') {
return fnOrCtrl;
}
if (!fn) {
fn = (scope) => scope.paramValues ? scope.paramValues[scope.paramValues.length - 1] : undefined;
}
if (fnOrCtrl) {
fn[convo_types_1.convoFlowControllerKey] = fnOrCtrl;
}
return fn;
};
exports.createConvoScopeFunction = createConvoScopeFunction;
const setConvoScopeError = (scope, error) => {
if (typeof error === 'string') {
error = {
message: error,
statement: scope?.s,
};
}
if (!scope) {
throw error;
}
scope.error = error;
if (scope.onError) {
const oe = scope.onError;
delete scope.onError;
delete scope.onComplete;
for (let i = 0; i < oe.length; i++) {
oe[i]?.(error);
}
}
};
exports.setConvoScopeError = setConvoScopeError;
const notWord = /\W/g;
const newline = /[\n\r]/g;
const convoTagMapToCode = (tagsMap, append = '', tab = '') => {
const out = [];
for (const e in tagsMap) {
const v = tagsMap[e];
out.push(`${tab}@${e.replace(notWord, '_')}${v ? ' ' + v.replace(newline, ' ') : ''}`);
}
return out.join('\n') + append;
};
exports.convoTagMapToCode = convoTagMapToCode;
const containsConvoTag = (tags, tagName) => {
if (!tags) {
return false;
}
for (let i = 0; i < tags.length; i++) {
if (tags[i]?.name === tagName) {
return true;
}
}
return false;
};
exports.containsConvoTag = containsConvoTag;
const getConvoTag = (tags, tagName) => {
if (!tags) {
return undefined;
}
for (let i = 0; i < tags.length; i++) {
const tag = tags[i];
if (tag?.name === tagName) {
return tag;
}
}
return undefined;
};
exports.getConvoTag = getConvoTag;
const convoTagsToMap = (tags) => {
const map = {};
for (const t of tags) {
map[t.name] = t.value;
}
return map;
};
exports.convoTagsToMap = convoTagsToMap;
const mapToConvoTags = (map) => {
const tags = [];
for (const e in map) {
tags.push({
name: e,
value: map[e]
});
}
return tags;
};
exports.mapToConvoTags = mapToConvoTags;
const createConvoMetadataForStatement = (statement) => {
return {
name: ((statement.set && !statement.setPath) ?
statement.set
: statement.label ?
statement.label
:
undefined),
comment: statement.comment,
tags: statement.tags,
};
};
exports.createConvoMetadataForStatement = createConvoMetadataForStatement;
const getConvoMetadata = (value) => {
return value?.[exports.convoMetadataKey];
};
exports.getConvoMetadata = getConvoMetadata;
const convoLabeledScopeParamsToObj = (scope) => {
const obj = {};
const labels = scope.labels;
let metadata = undefined;
if (scope.cm || (scope.s.tags && (0, exports.containsConvoTag)(scope.s.tags, exports.convoCaptureMetadataTag))) {
metadata = (0, exports.createConvoMetadataForStatement)(scope.s);
metadata.properties = {};
obj[exports.convoMetadataKey] = metadata;
}
if (labels) {
for (const e in labels) {
const label = labels[e];
if (label === undefined) {
continue;
}
const isOptional = typeof label === 'object';
const index = isOptional ? label.value : label;
if (index !== undefined) {
const v = scope.paramValues?.[index];
obj[e] = isOptional ? (0, exports.createOptionalConvoValue)(v) : v;
if (metadata?.properties && scope.s.params) {
const propStatement = scope.s.params[index];
if (propStatement) {
metadata.properties[e] = {
name: e,
comment: propStatement.comment,
tags: propStatement.tags
};
}
}
}
}
}
return obj;
};
exports.convoLabeledScopeParamsToObj = convoLabeledScopeParamsToObj;
const isReservedConvoRole = (role) => {
return convo_types_1.convoReservedRoles.includes(role);
};
exports.isReservedConvoRole = isReservedConvoRole;
const isValidConvoRole = (role) => {
return /^\w+$/.test(role);
};
exports.isValidConvoRole = isValidConvoRole;
const isValidConvoIdentifier = (role) => {
return /^[a-z]\w*$/.test(role);
};
exports.isValidConvoIdentifier = isValidConvoIdentifier;
const formatConvoMessage = (role, content, prefix = '') => {
if (!(0, exports.isValidConvoRole)(role)) {
throw new ConvoError_1.ConvoError('invalid-role', undefined, `(${role}) is not a valid role`);
}
if ((0, exports.isReservedConvoRole)(role)) {
throw new ConvoError_1.ConvoError('use-of-reserved-role-not-allowed', undefined, `${role} is a reserved role`);
}
return `${prefix}> ${role}\n${(0, exports.escapeConvoMessageContent)(content)}`;
};
exports.formatConvoMessage = formatConvoMessage;
const escapeConvoMessageContent = (content, isStartOfMessage = true, options) => {
// todo escape tags at end of message
if (content.includes('{{')) {
content = content.replace(/\{\{/g, '\\{{');
}
if (content.includes('>')) {
content = content.replace(
// the non start of message reg should be the same except no start of input char should be included
isStartOfMessage ?
/((?:\n|\r|^)[ \t]*\\*)>/g :
/((?:\n|\r)[ \t]*\\*)>/g, (_, space) => `${space}\\>`);
}
if (options?.removeNewLines) {
content = content.replace(/[\n\r]/g, '');
}
return content;
};
exports.escapeConvoMessageContent = escapeConvoMessageContent;
const spreadConvoArgs = (args, format) => {
const json = JSON.stringify(args, null, format ? 4 : undefined);
return json.substring(1, json.length - 1);
};
exports.spreadConvoArgs = spreadConvoArgs;
const defaultConvoPrintFunction = (...args) => {
console.log(...args);
return args[args.length - 1];
};
exports.defaultConvoPrintFunction = defaultConvoPrintFunction;
const collapseConvoPipes = (statement) => {
const params = statement.params;
if (!params) {
return 0;
}
delete statement._hasPipes;
let count = 0;
for (let i = 0; i < params.length; i++) {
const s = params[i];
if (!s?._pipe) {
continue;
}
count++;
const dest = params[i - 1];
const src = params[i + 1];
if (i === 0 || i === params.length - 1 || !dest || !src) { // discard - pipes need a target and source
params.splice(i, 1);
i--;
continue;
}
if (dest.fn === exports.convoPipeFnName) {
if (!dest.params) {
dest.params = [];
}
dest.params.unshift(src);
params.splice(i, 2);
}
else {
const pipeCall = {
s: dest.s,
e: dest.e,
fn: exports.convoPipeFnName,
params: [src, dest]
};
params.splice(i - 1, 3, pipeCall);
}
i--;
}
return count;
};
exports.collapseConvoPipes = collapseConvoPipes;
const convoDescriptionToCommentOut = (description, tab = '', out) => {
const lines = description.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
out.push(`${tab}# ${line}`);
}
};
exports.convoDescriptionToCommentOut = convoDescriptionToCommentOut;
const convoDescriptionToComment = (description, tab = '') => {
const out = [];
(0, exports.convoDescriptionToCommentOut)(description, tab, out);
return out.join('\n');
};
exports.convoDescriptionToComment = convoDescriptionToComment;
const convoStringToCommentOut = (str, tab = '', out) => {
const lines = str.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
out.push(`${tab}// ${line}`);
}
};
exports.convoStringToCommentOut = convoStringToCommentOut;
const convoStringToComment = (str, tab = '') => {
const out = [];
(0, exports.convoStringToCommentOut)(str, tab, out);
return out.join('\n');
};
exports.convoStringToComment = convoStringToComment;
const nameReg = /^[a-z_]\w{,254}$/;
const typeNameReg = /^[A-Z]\w{,254}$/;
const isValidConvoVarName = (name) => {
return nameReg.test(name);
};
exports.isValidConvoVarName = isValidConvoVarName;
const isValidConvoFunctionName = (name) => {
return nameReg.test(name);
};
exports.isValidConvoFunctionName = isValidConvoFunctionName;
const isValidConvoTypeName = (typeName) => {
return typeNameReg.test(typeName);
};
exports.isValidConvoTypeName = isValidConvoTypeName;
const validateConvoVarName = (name) => {
if (nameReg.test(name)) {
throw new ConvoError_1.ConvoError('invalid-variable-name', undefined, `${name} is an invalid Convo variable name. Variable names must start with a lower case letter followed by 0 to 254 more word characters`);
}
};
exports.validateConvoVarName = validateConvoVarName;
const validateConvoFunctionName = (name) => {
if (nameReg.test(name)) {
throw new ConvoError_1.ConvoError('invalid-function-name', undefined, `${name} is an invalid Convo function name. Function names must start with a lower case letter followed by 0 to 254 more word characters`);
}
};
exports.validateConvoFunctionName = validateConvoFunctionName;
const validateConvoTypeName = (name) => {
if (nameReg.test(name)) {
throw new ConvoError_1.ConvoError('invalid-type-name', undefined, `${name} is an invalid Convo type name. Type names must start with an upper case letter followed by 0 to 254 more word characters`);
}
};
exports.validateConvoTypeName = validateConvoTypeName;
const convoUsageTokensToString = (usage) => {
return `${usage.inputTokens ?? 0} / ${usage.outputTokens ?? 0}${usage.tokenPrice ? ' / $' + usage.tokenPrice : ''}`;
};
exports.convoUsageTokensToString = convoUsageTokensToString;
const parseConvoUsageTokens = (str) => {
const parts = str.split('/');
return {
inputTokens: Number(parts[0]) || 0,
outputTokens: Number(parts[1]) || 0,
tokenPrice: Number(parts[2]?.replace('$', '')) || 0,
};
};
exports.parseConvoUsageTokens = parseConvoUsageTokens;
const addConvoUsageTokens = (to, from) => {
if (typeof from === 'string') {
from = (0, exports.parseConvoUsageTokens)(from);
}
to.inputTokens += from.inputTokens;
to.outputTokens += from.outputTokens;
to.tokenPrice += from.tokenPrice;
};
exports.addConvoUsageTokens = addConvoUsageTokens;
const createEmptyConvoTokenUsage = () => ({
inputTokens: 0,
outputTokens: 0,
tokenPrice: 0,
});
exports.createEmptyConvoTokenUsage = createEmptyConvoTokenUsage;
const resetConvoUsageTokens = (usage) => {
usage.inputTokens = 0;
usage.outputTokens = 0;
usage.tokenPrice = 0;
};
exports.resetConvoUsageTokens = resetConvoUsageTokens;
const parseConvoJsonMessage = (json) => {
return (0, json5_1.parseJson5)(json
.replace(/^\s*`+\s*\w*/, '')
.replace(/`+\s*$/, '')
.trim());
};
exports.parseConvoJsonMessage = parseConvoJsonMessage;
const danglingReg = /[\r\n^](\s*>\s*user\s*)$/;
const removeDanglingConvoUserMessage = (code) => {
const dm = danglingReg.exec(code);
if (!dm) {
return code;
}
return code.substring(0, code.length - (dm[1] ?? '').length).trim();
};
exports.removeDanglingConvoUserMessage = removeDanglingConvoUserMessage;
const concatConvoCode = (a, b) => {
const dm = danglingReg.exec(a);
if (!dm) {
return a + b;
}
return a.substring(0, a.length - (dm[1] ?? '').length) + b;
};
exports.concatConvoCode = concatConvoCode;
const concatConvoCodeAndAppendEmptyUserMessage = (a, b) => {
const code = (0, exports.concatConvoCode)(a, b);
if (!danglingReg.test(code)) {
return code + '\n\n> user\n';
}
else {
return code;
}
};
exports.concatConvoCodeAndAppendEmptyUserMessage = concatConvoCodeAndAppendEmptyUserMessage;
const isConvoMessageIncludedInTask = (msg, task) => {
const msgTask = (0, exports.getConvoTag)(msg.tags, exports.convoTags.task)?.value ?? exports.defaultConvoTask;
return msgTask === task;
};
exports.isConvoMessageIncludedInTask = isConvoMessageIncludedInTask;
const parseConvoMessageTemplate = (msg, template) => {
const match = /^(\w+)\s*([\w.]+)?\s*(.*)/.exec(template);
return match ? {
message: msg,
name: match[1],
watchPath: match[2],
matchValue: match[3],
} : {
message: msg,
};
};
exports.parseConvoMessageTemplate = parseConvoMessageTemplate;
const getConvoStatementSource = (statement, code) => {
return code.substring(statement.s, statement.e);
};
exports.getConvoStatementSource = getConvoStatementSource;
/**
* If the value is empty, null or undefined true is returned, otherwise the Boolean
* constructor is used to parse the value.
*/
const parseConvoBooleanTag = (value) => {
if (!value) {
return true;
}
return Boolean(value);
};
exports.parseConvoBooleanTag = parseConvoBooleanTag;
const getFlatConvoTag = (message, tagName) => {
if (!message?.tags || !(tagName in message.tags)) {
return false;
}
return (0, exports.parseConvoBooleanTag)(message.tags[tagName]);
};
exports.getFlatConvoTag = getFlatConvoTag;
const shouldDisableConvoAutoScroll = (messages) => {
for (let i = messages.length - 1; i >= 0; i--) {
const m = messages[i];
if (m && (m.content !== undefined || m.component !== undefined)) {
return (0, exports.getFlatConvoTag)(m, exports.convoTags.disableAutoScroll);
}
}
return false;
};
exports.shouldDisableConvoAutoScroll = shouldDisableConvoAutoScroll;
const convoRagDocRefToMessage = (doc, role) => {
const msg = {
role,
content: doc.content,
tags: []
};
if (doc.sourceId) {
msg.sourceId = doc.sourceId;
msg.tags?.push({ name: exports.convoTags.sourceId, value: doc.sourceId });
}
if (doc.sourceName) {
msg.sourceName = doc.sourceName;
msg.tags?.push({ name: exports.convoTags.sourceName, value: doc.sourceName });
}
if (doc.sourceUrl) {
msg.sourceUrl = doc.sourceUrl;
msg.tags?.push({ name: exports.convoTags.sourceUrl, value: doc.sourceUrl });
}
if (!msg.tags?.length) {
delete msg.tags;
}
return msg;
};
exports.convoRagDocRefToMessage = convoRagDocRefToMessage;
const escapeConvoTagValue = (value) => {
return value.replace(/\s/g, ' ');
};
exports.escapeConvoTagValue = escapeConvoTagValue;
const convoMessageToString = (msg) => {
if (msg.fn || msg.statement) {
throw new common_1.UnsupportedError('convoMessageToString only supports text based messages without embedded statements');
}
const out = [];
if (msg.tags) {
for (const tag of msg.tags) {
out.push(`@${tag.name}${tag.value === undefined ? '' : ' ' + (0, exports.escapeConvoTagValue)(tag.value)}`);
}
}
out.push(`> ${msg.role ?? 'user'}`);
if (msg.content) {
out.push((0, exports.escapeConvoMessageContent)(msg.content, true));
}
return out.join('\n');
};
exports.convoMessageToString = convoMessageToString;
const getLastCompletionMessage = (messages) => {
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i];
if (!msg || msg.role === 'function') {
continue;
}
return msg;
}
return undefined;
};
exports.getLastCompletionMessage = getLastCompletionMessage;
const isConvoThreadFilterMatch = (filter, tid) => {
if ((filter.excludeNonThreaded && !tid) || filter.excludeThreads?.includes(tid ?? '')) {
return false;
}
if (filter.includeNonThreaded && !tid) {
return true;
}
else if (filter.includeThreads) {
return filter.includeThreads.includes(tid ?? '');
}
else {
return true;
}
};
exports.isConvoThreadFilterMatch = isConvoThreadFilterMatch;
//# sourceMappingURL=convo-lib.js.map