@promptbook/core 0.69.0-1 → 0.69.0-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.es.js +89 -30
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/types.index.d.ts +2 -0
- package/esm/typings/src/commands/FOREACH/ForeachCommand.d.ts +2 -6
- package/esm/typings/src/commands/FOREACH/ForeachJson.d.ts +26 -0
- package/esm/typings/src/commands/_common/types/CommandParser.d.ts +4 -4
- package/esm/typings/src/config.d.ts +7 -1
- package/esm/typings/src/conversion/prettify/renderPipelineMermaidOptions.d.ts +3 -0
- package/esm/typings/src/conversion/utils/extractParameterNamesFromTemplate.d.ts +1 -1
- package/esm/typings/src/conversion/validation/validatePipeline.d.ts +4 -0
- package/esm/typings/src/types/PipelineJson/ParameterJson.d.ts +1 -0
- package/esm/typings/src/types/PipelineJson/TemplateJsonCommon.d.ts +5 -0
- package/esm/typings/src/types/execution-report/ExecutionReportJson.d.ts +3 -0
- package/package.json +1 -1
- package/umd/index.umd.js +89 -30
- package/umd/index.umd.js.map +1 -1
package/esm/index.es.js
CHANGED
|
@@ -10,7 +10,7 @@ import moment from 'moment';
|
|
|
10
10
|
/**
|
|
11
11
|
* The version of the Promptbook library
|
|
12
12
|
*/
|
|
13
|
-
var PROMPTBOOK_VERSION = '0.69.0-
|
|
13
|
+
var PROMPTBOOK_VERSION = '0.69.0-1';
|
|
14
14
|
// TODO: !!!! List here all the versions and annotate + put into script
|
|
15
15
|
|
|
16
16
|
/*! *****************************************************************************
|
|
@@ -752,6 +752,15 @@ var DEFAULT_REMOTE_URL_PATH = '/promptbook/socket.io';
|
|
|
752
752
|
* @public exported from `@promptbook/core`
|
|
753
753
|
*/
|
|
754
754
|
var IS_VERBOSE = false;
|
|
755
|
+
/**
|
|
756
|
+
* @@@
|
|
757
|
+
*
|
|
758
|
+
* @private within the repository
|
|
759
|
+
*/
|
|
760
|
+
var IS_PIPELINE_LOGIC_VALIDATED = just(
|
|
761
|
+
/**/
|
|
762
|
+
// Note: In normal situations, we check the pipeline logic:
|
|
763
|
+
true);
|
|
755
764
|
/**
|
|
756
765
|
* TODO: [🧠][🧜♂️] Maybe join remoteUrl and path into single value
|
|
757
766
|
*/
|
|
@@ -961,6 +970,26 @@ function isValidPipelineUrl(url) {
|
|
|
961
970
|
* @public exported from `@promptbook/core`
|
|
962
971
|
*/
|
|
963
972
|
function validatePipeline(pipeline) {
|
|
973
|
+
if (IS_PIPELINE_LOGIC_VALIDATED) {
|
|
974
|
+
validatePipelineCore(pipeline);
|
|
975
|
+
}
|
|
976
|
+
else {
|
|
977
|
+
try {
|
|
978
|
+
validatePipelineCore(pipeline);
|
|
979
|
+
}
|
|
980
|
+
catch (error) {
|
|
981
|
+
if (!(error instanceof PipelineLogicError)) {
|
|
982
|
+
throw error;
|
|
983
|
+
}
|
|
984
|
+
console.error(spaceTrim$1(function (block) { return "\n Pipeline is not valid but logic errors are temporarily disabled via `IS_PIPELINE_LOGIC_VALIDATED`\n\n ".concat(block(error.message), "\n "); }));
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
return pipeline;
|
|
988
|
+
}
|
|
989
|
+
/**
|
|
990
|
+
* @private internal function for `validatePipeline`
|
|
991
|
+
*/
|
|
992
|
+
function validatePipelineCore(pipeline) {
|
|
964
993
|
// TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
|
|
965
994
|
var e_1, _a, e_2, _b, e_3, _c;
|
|
966
995
|
var pipelineIdentification = (function () {
|
|
@@ -1159,7 +1188,6 @@ function validatePipeline(pipeline) {
|
|
|
1159
1188
|
while (unresovedTemplates.length > 0) {
|
|
1160
1189
|
_loop_3();
|
|
1161
1190
|
}
|
|
1162
|
-
return pipeline;
|
|
1163
1191
|
}
|
|
1164
1192
|
/**
|
|
1165
1193
|
* TODO: [🧠] Work with promptbookVersion
|
|
@@ -1788,7 +1816,7 @@ function forEachAsync(array, options, callbackfunction) {
|
|
|
1788
1816
|
});
|
|
1789
1817
|
}
|
|
1790
1818
|
|
|
1791
|
-
var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md",promptbookVersion:"0.69.0-
|
|
1819
|
+
var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md",promptbookVersion:"0.69.0-1",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-from-markdown.ptbk.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md",promptbookVersion:"0.69.0-1",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-keywords.ptbk.md"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md",promptbookVersion:"0.69.0-1",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-title.ptbk.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.ptbk.md",promptbookVersion:"0.69.0-1",parameters:[{name:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Sample\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","personaDescription"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-persona.ptbk.md"}];
|
|
1792
1820
|
|
|
1793
1821
|
var defaultDiacriticsRemovalMap = [
|
|
1794
1822
|
{
|
|
@@ -2375,7 +2403,7 @@ function extractVariables(script) {
|
|
|
2375
2403
|
*/
|
|
2376
2404
|
function extractParameterNamesFromTemplate(template) {
|
|
2377
2405
|
var e_1, _a, e_2, _b, e_3, _c;
|
|
2378
|
-
var title = template.title, description = template.description, templateType = template.templateType, content = template.content, preparedContent = template.preparedContent, jokerParameterNames = template.jokerParameterNames;
|
|
2406
|
+
var title = template.title, description = template.description, templateType = template.templateType, content = template.content, preparedContent = template.preparedContent, jokerParameterNames = template.jokerParameterNames, foreach = template.foreach;
|
|
2379
2407
|
var parameterNames = new Set();
|
|
2380
2408
|
try {
|
|
2381
2409
|
for (var _d = __values(__spreadArray(__spreadArray(__spreadArray(__spreadArray([], __read(extractParameterNames(title)), false), __read(extractParameterNames(description || '')), false), __read(extractParameterNames(content)), false), __read(extractParameterNames(preparedContent || '')), false)), _e = _d.next(); !_e.done; _e = _d.next()) {
|
|
@@ -2420,6 +2448,14 @@ function extractParameterNamesFromTemplate(template) {
|
|
|
2420
2448
|
}
|
|
2421
2449
|
parameterNames.delete('content');
|
|
2422
2450
|
// <- Note {websiteContent} is used in `preparedContent`
|
|
2451
|
+
// Note: [🍭] Fixing dependent subparameterName from FOREACH command
|
|
2452
|
+
if (foreach !== undefined) {
|
|
2453
|
+
if (parameterNames.has(foreach.subparameterName)) {
|
|
2454
|
+
parameterNames.delete(foreach.subparameterName);
|
|
2455
|
+
parameterNames.add(foreach.parameterName);
|
|
2456
|
+
// <- TODO: [🚎] Warn/logic error when `subparameterName` not used
|
|
2457
|
+
}
|
|
2458
|
+
}
|
|
2423
2459
|
return parameterNames;
|
|
2424
2460
|
}
|
|
2425
2461
|
/**
|
|
@@ -3470,6 +3506,7 @@ function createPipelineExecutor(options) {
|
|
|
3470
3506
|
case 0:
|
|
3471
3507
|
isJokerAttempt = attempt < 0;
|
|
3472
3508
|
jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
|
|
3509
|
+
// TODO: [🧠] !!!!!! JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
|
|
3473
3510
|
if (isJokerAttempt && !jokerParameterName) {
|
|
3474
3511
|
throw new UnexpectedError(spaceTrim$1(function (block) { return "\n Joker not found in attempt ".concat(attempt, "\n\n ").concat(block(pipelineIdentification), "\n "); }));
|
|
3475
3512
|
}
|
|
@@ -3788,6 +3825,19 @@ function createPipelineExecutor(options) {
|
|
|
3788
3825
|
attempt++;
|
|
3789
3826
|
return [3 /*break*/, 4];
|
|
3790
3827
|
case 7:
|
|
3828
|
+
//------------------------------------
|
|
3829
|
+
/*
|
|
3830
|
+
|
|
3831
|
+
|
|
3832
|
+
|
|
3833
|
+
|
|
3834
|
+
|
|
3835
|
+
|
|
3836
|
+
|
|
3837
|
+
|
|
3838
|
+
|
|
3839
|
+
*/
|
|
3840
|
+
//------------------------------------
|
|
3791
3841
|
if (resultString === null) {
|
|
3792
3842
|
throw new UnexpectedError(spaceTrim$1(function (block) { return "\n Something went wrong and prompt result is null\n\n ".concat(block(pipelineIdentification), "\n "); }));
|
|
3793
3843
|
}
|
|
@@ -5297,20 +5347,21 @@ var foreachCommandParser = {
|
|
|
5297
5347
|
* Example usages of the FOREACH command
|
|
5298
5348
|
*/
|
|
5299
5349
|
examples: [
|
|
5300
|
-
'FOREACH List Line -> `{customer}`',
|
|
5301
|
-
'FOR List Line -> `{customer}`',
|
|
5302
|
-
'EACH List Line -> `{customer}`',
|
|
5350
|
+
'FOREACH List Line `{customers}` -> `{customer}`',
|
|
5351
|
+
'FOR List Line `{customers}` -> `{customer}`',
|
|
5352
|
+
'EACH List Line `{customers}` -> `{customer}`',
|
|
5303
5353
|
// <- TODO: [🍭] !!!!!! More
|
|
5304
5354
|
],
|
|
5305
5355
|
/**
|
|
5306
5356
|
* Parses the FOREACH command
|
|
5307
5357
|
*/
|
|
5308
5358
|
parse: function (input) {
|
|
5309
|
-
var args = input.args
|
|
5359
|
+
var args = input.args;
|
|
5310
5360
|
var formatName = normalizeTo_SCREAMING_CASE(args[0] || '');
|
|
5311
5361
|
var cellName = normalizeTo_SCREAMING_CASE(args[1] || '');
|
|
5312
|
-
var
|
|
5313
|
-
var
|
|
5362
|
+
var parameterNameWrapped = args[2];
|
|
5363
|
+
var assignSign = args[3];
|
|
5364
|
+
var subparameterNameWrapped = args[4];
|
|
5314
5365
|
if (![
|
|
5315
5366
|
'LIST',
|
|
5316
5367
|
'CSV',
|
|
@@ -5325,7 +5376,7 @@ var foreachCommandParser = {
|
|
|
5325
5376
|
'ROW',
|
|
5326
5377
|
'COLUMN',
|
|
5327
5378
|
'CELL',
|
|
5328
|
-
// <- TODO: [🏢] Unhardcode format
|
|
5379
|
+
// <- TODO: [🏢] Unhardcode format cells
|
|
5329
5380
|
].includes(cellName)) {
|
|
5330
5381
|
console.info({ args: args, cellName: cellName });
|
|
5331
5382
|
throw new Error("Format ".concat(formatName, " does not support cell \"").concat(cellName, "\""));
|
|
@@ -5335,24 +5386,27 @@ var foreachCommandParser = {
|
|
|
5335
5386
|
console.info({ args: args, assignSign: assignSign });
|
|
5336
5387
|
throw new Error("FOREACH command must have '->' to assign the value to the parameter");
|
|
5337
5388
|
}
|
|
5338
|
-
|
|
5339
|
-
if (
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
//
|
|
5346
|
-
) {
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5389
|
+
// TODO: !!!!!! Replace with propper parameter name validation
|
|
5390
|
+
if ((parameterNameWrapped === null || parameterNameWrapped === void 0 ? void 0 : parameterNameWrapped.substring(0, 1)) !== '{' ||
|
|
5391
|
+
(parameterNameWrapped === null || parameterNameWrapped === void 0 ? void 0 : parameterNameWrapped.substring(parameterNameWrapped.length - 1, parameterNameWrapped.length)) !== '}') {
|
|
5392
|
+
console.info({ args: args, parameterNameWrapped: parameterNameWrapped }, parameterNameWrapped === null || parameterNameWrapped === void 0 ? void 0 : parameterNameWrapped.substring(0, 1), parameterNameWrapped === null || parameterNameWrapped === void 0 ? void 0 : parameterNameWrapped.substring(parameterNameWrapped.length - 1, parameterNameWrapped.length));
|
|
5393
|
+
throw new Error("!!!!!! 1 Here will be error (with rules and precise error) from validateParameterName");
|
|
5394
|
+
}
|
|
5395
|
+
var parameterName = parameterNameWrapped.substring(1, parameterNameWrapped.length - 1);
|
|
5396
|
+
// TODO: !!!!!! Replace with propper parameter name validation
|
|
5397
|
+
if ((subparameterNameWrapped === null || subparameterNameWrapped === void 0 ? void 0 : subparameterNameWrapped.substring(0, 1)) !== '{' ||
|
|
5398
|
+
(subparameterNameWrapped === null || subparameterNameWrapped === void 0 ? void 0 : subparameterNameWrapped.substring(subparameterNameWrapped.length - 1, subparameterNameWrapped.length)) !==
|
|
5399
|
+
'}') {
|
|
5400
|
+
console.info({ args: args, subparameterNameWrapped: subparameterNameWrapped });
|
|
5401
|
+
throw new Error("!!!!!! 2 Here will be error (with rules and precise error) from validateParameterName");
|
|
5402
|
+
}
|
|
5403
|
+
var subparameterName = subparameterNameWrapped.substring(1, subparameterNameWrapped.length - 1);
|
|
5351
5404
|
return {
|
|
5352
5405
|
type: 'FOREACH',
|
|
5353
5406
|
formatName: formatName,
|
|
5354
5407
|
cellName: cellName,
|
|
5355
5408
|
parameterName: parameterName,
|
|
5409
|
+
subparameterName: subparameterName,
|
|
5356
5410
|
};
|
|
5357
5411
|
},
|
|
5358
5412
|
/**
|
|
@@ -5361,8 +5415,10 @@ var foreachCommandParser = {
|
|
|
5361
5415
|
* Note: `$` is used to indicate that this function mutates given `templateJson`
|
|
5362
5416
|
*/
|
|
5363
5417
|
$applyToTemplateJson: function (command, $templateJson, $pipelineJson) {
|
|
5364
|
-
|
|
5365
|
-
|
|
5418
|
+
var formatName = command.formatName, cellName = command.cellName, parameterName = command.parameterName, subparameterName = command.subparameterName;
|
|
5419
|
+
$templateJson.foreach = { formatName: formatName, cellName: cellName, parameterName: parameterName, subparameterName: subparameterName };
|
|
5420
|
+
keepUnused($pipelineJson); // <- TODO: !!!!!! BUT Maybe register subparameter from foreach into parameters of the pipeline
|
|
5421
|
+
// Note: [🍭] FOREACH apply has some sideeffects on different places in codebase
|
|
5366
5422
|
},
|
|
5367
5423
|
/**
|
|
5368
5424
|
* Converts the FOREACH command back to string
|
|
@@ -5371,8 +5427,7 @@ var foreachCommandParser = {
|
|
|
5371
5427
|
*/
|
|
5372
5428
|
stringify: function (command) {
|
|
5373
5429
|
keepUnused(command);
|
|
5374
|
-
return "";
|
|
5375
|
-
// <- TODO: [🍭] !!!!!! Implement
|
|
5430
|
+
return "---"; // <- TODO: [🛋] Implement
|
|
5376
5431
|
},
|
|
5377
5432
|
/**
|
|
5378
5433
|
* Reads the FOREACH command from the `TemplateJson`
|
|
@@ -5381,8 +5436,7 @@ var foreachCommandParser = {
|
|
|
5381
5436
|
*/
|
|
5382
5437
|
takeFromTemplateJson: function ($templateJson) {
|
|
5383
5438
|
keepUnused($templateJson);
|
|
5384
|
-
|
|
5385
|
-
// <- TODO: [🍭] !!!!!! Implement
|
|
5439
|
+
throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
|
|
5386
5440
|
},
|
|
5387
5441
|
};
|
|
5388
5442
|
/**
|
|
@@ -5497,6 +5551,7 @@ var jokerCommandParser = {
|
|
|
5497
5551
|
*/
|
|
5498
5552
|
parse: function (input) {
|
|
5499
5553
|
var args = input.args;
|
|
5554
|
+
// TODO: !!!!!! Replace with propper parameter name validation
|
|
5500
5555
|
var parametersMatch = (args.pop() || '').match(/^\{(?<parameterName>[a-z0-9_]+)\}$/im);
|
|
5501
5556
|
if (!parametersMatch || !parametersMatch.groups || !parametersMatch.groups.parameterName) {
|
|
5502
5557
|
throw new ParseError("Invalid joker");
|
|
@@ -5626,6 +5681,7 @@ var modelCommandParser = {
|
|
|
5626
5681
|
if ($pipelineJson.defaultModelRequirements[command.key] !== undefined) {
|
|
5627
5682
|
if ($pipelineJson.defaultModelRequirements[command.key] === command.value) {
|
|
5628
5683
|
console.warn("Multiple commands `MODEL ".concat(command.key, " ").concat(command.value, "` in the pipeline head"));
|
|
5684
|
+
// <- TODO: [🚎] Some better way how to get warnings from pipeline parsing / logic
|
|
5629
5685
|
}
|
|
5630
5686
|
else {
|
|
5631
5687
|
throw new ParseError(spaceTrim("\n Redefinition of MODEL `".concat(command.key, "` in the pipeline head\n\n You have used:\n - MODEL ").concat(command.key, " ").concat($pipelineJson.defaultModelRequirements[command.key], "\n - MODEL ").concat(command.key, " ").concat(command.value, "\n ")));
|
|
@@ -7381,6 +7437,9 @@ function renderPromptbookMermaid(pipelineJson, options) {
|
|
|
7381
7437
|
return promptbookMermaid;
|
|
7382
7438
|
}
|
|
7383
7439
|
/**
|
|
7440
|
+
* TODO: !!!!!! FOREACH in mermaid graph
|
|
7441
|
+
* TODO: !!!!!! Knowledge in mermaid graph
|
|
7442
|
+
* TODO: !!!!!! Personas in mermaid graph
|
|
7384
7443
|
* TODO: Maybe use some Mermaid package instead of string templating
|
|
7385
7444
|
* TODO: [🕌] When more than 2 functionalities, split into separate functions
|
|
7386
7445
|
*/
|