@promptbook/utils 0.44.0-0 → 0.44.0-10

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.
Files changed (37) hide show
  1. package/esm/index.es.js +641 -548
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/_packages/core.index.d.ts +2 -1
  4. package/esm/typings/_packages/utils.index.d.ts +21 -11
  5. package/esm/typings/config.d.ts +4 -0
  6. package/esm/typings/errors/PromptbookNotFoundError.d.ts +7 -0
  7. package/esm/typings/errors/{ExpectError.d.ts → _ExpectError.d.ts} +1 -0
  8. package/esm/typings/execution/plugins/natural-execution-tools/mocked/MockedEchoNaturalExecutionTools.d.ts +1 -1
  9. package/esm/typings/execution/plugins/natural-execution-tools/mocked/MockedFackedNaturalExecutionTools.d.ts +19 -0
  10. package/esm/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.d.ts +11 -0
  11. package/esm/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.test.d.ts +1 -0
  12. package/esm/typings/execution/plugins/natural-execution-tools/mocked/faked-completion.test.d.ts +1 -0
  13. package/esm/typings/execution/utils/checkExpectations.d.ts +25 -0
  14. package/esm/typings/execution/utils/checkExpectations.test.d.ts +1 -0
  15. package/esm/typings/types/Prompt.d.ts +8 -0
  16. package/esm/typings/types/PromptbookJson/PromptTemplateJson.d.ts +13 -4
  17. package/esm/typings/utils/expectation-counters/countSentences.d.ts +4 -0
  18. package/package.json +1 -4
  19. package/umd/index.umd.js +644 -547
  20. package/umd/index.umd.js.map +1 -1
  21. package/umd/typings/_packages/core.index.d.ts +2 -1
  22. package/umd/typings/_packages/utils.index.d.ts +21 -11
  23. package/umd/typings/config.d.ts +4 -0
  24. package/umd/typings/errors/PromptbookNotFoundError.d.ts +7 -0
  25. package/umd/typings/errors/{ExpectError.d.ts → _ExpectError.d.ts} +1 -0
  26. package/umd/typings/execution/plugins/natural-execution-tools/mocked/MockedEchoNaturalExecutionTools.d.ts +1 -1
  27. package/umd/typings/execution/plugins/natural-execution-tools/mocked/MockedFackedNaturalExecutionTools.d.ts +19 -0
  28. package/umd/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.d.ts +11 -0
  29. package/umd/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.test.d.ts +1 -0
  30. package/umd/typings/execution/plugins/natural-execution-tools/mocked/faked-completion.test.d.ts +1 -0
  31. package/umd/typings/execution/utils/checkExpectations.d.ts +25 -0
  32. package/umd/typings/execution/utils/checkExpectations.test.d.ts +1 -0
  33. package/umd/typings/types/Prompt.d.ts +8 -0
  34. package/umd/typings/types/PromptbookJson/PromptTemplateJson.d.ts +13 -4
  35. package/umd/typings/utils/expectation-counters/countSentences.d.ts +4 -0
  36. package/esm/typings/errors/NotFoundError.d.ts +0 -7
  37. package/umd/typings/errors/NotFoundError.d.ts +0 -7
package/umd/index.umd.js CHANGED
@@ -409,7 +409,7 @@
409
409
  /**
410
410
  * The version of the Promptbook library
411
411
  */
412
- var PROMPTBOOK_VERSION = '0.43.0';
412
+ var PROMPTBOOK_VERSION = '0.44.0-9';
413
413
 
414
414
  /**
415
415
  * Parses the given script and returns the list of all used variables that are not defined in the script
@@ -477,6 +477,7 @@
477
477
  */
478
478
  var EXPECTATION_UNITS = ['CHARACTERS', 'WORDS', 'SENTENCES', 'PARAGRAPHS', 'LINES', 'PAGES'];
479
479
  /**
480
+ * TODO: [💝] Unite object for expecting amount and format - remove expectFormat
480
481
  * TODO: use one helper type> (string_prompt | string_javascript | string_markdown) & string_template
481
482
  */
482
483
 
@@ -1056,7 +1057,7 @@
1056
1057
  executionType: executionType,
1057
1058
  jokers: jokers,
1058
1059
  postprocessing: postprocessing,
1059
- expectAmount: expectAmount,
1060
+ expectations: expectAmount,
1060
1061
  expectFormat: expectFormat,
1061
1062
  modelRequirements: templateModelRequirements,
1062
1063
  contentLanguage: executionType === 'SCRIPT' ? language : undefined,
@@ -1235,458 +1236,73 @@
1235
1236
  */
1236
1237
 
1237
1238
  /**
1238
- * This error occurs during the parameter replacement in the template
1239
+ * This error occurs when some expectation is not met in the execution of the pipeline
1239
1240
  *
1240
- * Note: This is a kindof subtype of PromptbookExecutionError because it occurs during the execution of the pipeline
1241
+ * @private Always catched and rethrown as `PromptbookExecutionError`
1242
+ * Note: This is a kindof subtype of PromptbookExecutionError
1241
1243
  */
1242
- var TemplateError = /** @class */ (function (_super) {
1243
- __extends(TemplateError, _super);
1244
- function TemplateError(message) {
1244
+ var ExpectError = /** @class */ (function (_super) {
1245
+ __extends(ExpectError, _super);
1246
+ function ExpectError(message) {
1245
1247
  var _this = _super.call(this, message) || this;
1246
- _this.name = 'TemplateError';
1247
- Object.setPrototypeOf(_this, TemplateError.prototype);
1248
+ _this.name = 'ExpectError';
1249
+ Object.setPrototypeOf(_this, ExpectError.prototype);
1248
1250
  return _this;
1249
1251
  }
1250
- return TemplateError;
1252
+ return ExpectError;
1251
1253
  }(Error));
1252
1254
 
1253
1255
  /**
1254
- * Replaces parameters in template with values from parameters object
1255
- *
1256
- * @param template the template with parameters in {curly} braces
1257
- * @param parameters the object with parameters
1258
- * @returns the template with replaced parameters
1259
- * @throws {TemplateError} if parameter is not defined, not closed, or not opened
1260
- *
1261
- * @private within the createPromptbookExecutor
1262
- */
1263
- function replaceParameters(template, parameters) {
1264
- var replacedTemplate = template;
1265
- var match;
1266
- var loopLimit = LOOP_LIMIT;
1267
- var _loop_1 = function () {
1268
- if (loopLimit-- < 0) {
1269
- throw new UnexpectedError('Loop limit reached during parameters replacement in `replaceParameters`');
1270
- }
1271
- var precol = match.groups.precol;
1272
- var parameterName = match.groups.parameterName;
1273
- if (parameterName === '') {
1274
- return "continue";
1275
- }
1276
- if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
1277
- throw new TemplateError('Parameter is already opened or not closed');
1278
- }
1279
- if (parameters[parameterName] === undefined) {
1280
- throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
1281
- }
1282
- var parameterValue = parameters[parameterName];
1283
- if (parameterValue === undefined) {
1284
- throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
1285
- }
1286
- parameterValue = parameterValue.toString();
1287
- if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
1288
- parameterValue = parameterValue
1289
- .split('\n')
1290
- .map(function (line, index) { return (index === 0 ? line : "".concat(precol).concat(line)); })
1291
- .join('\n');
1292
- }
1293
- replacedTemplate =
1294
- replacedTemplate.substring(0, match.index + precol.length) +
1295
- parameterValue +
1296
- replacedTemplate.substring(match.index + precol.length + parameterName.length + 2);
1297
- };
1298
- while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
1299
- .exec(replacedTemplate))) {
1300
- _loop_1();
1301
- }
1302
- // [💫] Check if there are parameters that are not closed properly
1303
- if (/{\w+$/.test(replacedTemplate)) {
1304
- throw new TemplateError('Parameter is not closed');
1305
- }
1306
- // [💫] Check if there are parameters that are not opened properly
1307
- if (/^\w+}/.test(replacedTemplate)) {
1308
- throw new TemplateError('Parameter is not opened');
1309
- }
1310
- return replacedTemplate;
1311
- }
1312
-
1313
- /**
1314
- * Format either small or big number
1315
- *
1316
- * @private within the library
1317
- */
1318
- function formatNumber(value) {
1319
- if (value === 0) {
1320
- return '0';
1321
- }
1322
- for (var exponent = 0; exponent < 15; exponent++) {
1323
- var factor = Math.pow(10, exponent);
1324
- var valueRounded = Math.round(value * factor) / factor;
1325
- if (Math.abs(value - valueRounded) / value <
1326
- 0.001 /* <- TODO: Pass as option, pass to executionReportJsonToString as option */) {
1327
- return valueRounded.toFixed(exponent);
1328
- }
1329
- }
1330
- return value.toString();
1331
- }
1332
-
1333
- /**
1334
- * Returns the same value that is passed as argument.
1335
- * No side effects.
1336
- *
1337
- * Note: It can be usefull for leveling indentation
1338
- *
1339
- * @param value any values
1340
- * @returns the same values
1341
- */
1342
- function just(value) {
1343
- if (value === undefined) {
1344
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1345
- return undefined;
1346
- }
1347
- return value;
1348
- }
1349
-
1350
- /**
1351
- * Removes emojis from a string and fix whitespaces
1352
- *
1353
- * @param text with emojis
1354
- * @returns text without emojis
1256
+ * Counts number of characters in the text
1355
1257
  */
1356
- function removeEmojis(text) {
1258
+ function countCharacters(text) {
1259
+ // Remove null characters
1260
+ text = text.replace(/\0/g, '');
1357
1261
  // Replace emojis (and also ZWJ sequence) with hyphens
1358
1262
  text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1359
1263
  text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1360
- text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1361
- text = text.replace(/\p{Extended_Pictographic}/gu, '');
1362
- return text;
1363
- }
1364
-
1365
- /**
1366
- * Create a markdown table from a 2D array of strings
1367
- *
1368
- * @private within the library
1369
- */
1370
- function createMarkdownTable(table) {
1371
- var columnWidths = table.reduce(function (widths, row) {
1372
- row.forEach(function (cell, columnIndex) {
1373
- var cellLength = cell.length;
1374
- if (!widths[columnIndex] || cellLength > widths[columnIndex]) {
1375
- widths[columnIndex] = cellLength;
1376
- }
1377
- });
1378
- return widths;
1379
- }, []);
1380
- var header = "| ".concat(table[0]
1381
- .map(function (cell, columnIndex) { return cell.padEnd(columnWidths[columnIndex]); })
1382
- .join(' | '), " |");
1383
- var separator = "|".concat(columnWidths.map(function (width) { return '-'.repeat(width + 2); }).join('|'), "|");
1384
- var rows = table.slice(1).map(function (row) {
1385
- var paddedRow = row.map(function (cell, columnIndex) {
1386
- return cell.padEnd(columnWidths[columnIndex]);
1387
- });
1388
- return "| ".concat(paddedRow.join(' | '), " |");
1389
- });
1390
- return __spreadArray([header, separator], __read(rows), false).join('\n');
1264
+ text = text.replace(/\p{Extended_Pictographic}(\u{200D}\p{Extended_Pictographic})*/gu, '-');
1265
+ return text.length;
1391
1266
  }
1392
1267
 
1393
1268
  /**
1394
- * Function createMarkdownChart will draw a chart in markdown from ⬛+🟦 tiles
1395
- *
1396
- * @private within the library
1269
+ * Counts number of lines in the text
1397
1270
  */
1398
- function createMarkdownChart(options) {
1399
- var e_1, _a;
1400
- var nameHeader = options.nameHeader, valueHeader = options.valueHeader, items = options.items, width = options.width, unitName = options.unitName;
1401
- var from = Math.min.apply(Math, __spreadArray([], __read(items.map(function (item) { return item.from; })), false));
1402
- var to = Math.max.apply(Math, __spreadArray([], __read(items.map(function (item) { return item.to; })), false));
1403
- var scale = width / (to - from);
1404
- var table = [[nameHeader, valueHeader]];
1405
- try {
1406
- for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
1407
- var item = items_1_1.value;
1408
- var before = Math.round((item.from - from) * scale);
1409
- var during = Math.round((item.to - item.from) * scale);
1410
- var after = width - before - during;
1411
- table.push([removeEmojis(item.title).trim(), '░'.repeat(before) + '█'.repeat(during) + '░'.repeat(after)]);
1412
- }
1413
- }
1414
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1415
- finally {
1416
- try {
1417
- if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
1418
- }
1419
- finally { if (e_1) throw e_1.error; }
1271
+ function countLines(text) {
1272
+ if (text === '') {
1273
+ return 0;
1420
1274
  }
1421
- var legend = "_Note: Each \u2588 represents ".concat(formatNumber(1 / scale), " ").concat(unitName, ", width of ").concat(valueHeader.toLowerCase(), " is ").concat(formatNumber(to - from), " ").concat(unitName, " = ").concat(width, " squares_");
1422
- return createMarkdownTable(table) + '\n\n' + legend;
1275
+ return text.split('\n').length;
1423
1276
  }
1424
- /**
1425
- * TODO: Maybe use Mermain Gant Diagrams
1426
- * @see https://jojozhuang.github.io/tutorial/mermaid-cheat-sheet/
1427
- */
1428
1277
 
1429
1278
  /**
1430
- * Function escapeMarkdownBlock will escape markdown block if needed
1431
- * It is useful when you want have block in block
1279
+ * Counts number of pages in the text
1432
1280
  */
1433
- function escapeMarkdownBlock(value) {
1434
- return value.replace(/```/g, '\\`\\`\\`');
1281
+ function countPages(text) {
1282
+ var sentencesPerPage = 5; // Assuming each page has 5 sentences
1283
+ var sentences = text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
1284
+ var pageCount = Math.ceil(sentences.length / sentencesPerPage);
1285
+ return pageCount;
1435
1286
  }
1436
1287
 
1437
1288
  /**
1438
- * Default options for generating an execution report string
1289
+ * Counts number of paragraphs in the text
1439
1290
  */
1440
- var ExecutionReportStringOptionsDefaults = {
1441
- taxRate: 0,
1442
- chartsWidth: 36,
1443
- };
1291
+ function countParagraphs(text) {
1292
+ return text.split(/\n\s*\n/).filter(function (paragraph) { return paragraph.trim() !== ''; }).length;
1293
+ }
1444
1294
 
1445
1295
  /**
1446
- * The thresholds for the relative time in the `moment` library.
1447
- *
1448
- * @see https://momentjscom.readthedocs.io/en/latest/moment/07-customization/13-relative-time-threshold/
1296
+ * Split text into sentences
1449
1297
  */
1450
- var MOMENT_ARG_THRESHOLDS = {
1451
- ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
1452
- };
1453
-
1298
+ function splitIntoSentences(text) {
1299
+ return text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
1300
+ }
1454
1301
  /**
1455
- * Count the duration of working time
1456
- *
1457
- * @private within the library
1302
+ * Counts number of sentences in the text
1458
1303
  */
1459
- function countWorkingDuration(items) {
1460
- var e_1, _a;
1461
- var steps = Array.from(new Set(items.flatMap(function (item) { return [item.from, item.to]; })));
1462
- steps.sort(function (a, b) { return a - b; });
1463
- var intervals = steps.map(function (step, index) { return [step, steps[index + 1] || 0]; }).slice(0, -1);
1464
- var duration = 0;
1465
- var _loop_1 = function (interval) {
1466
- var _b = __read(interval, 2), from = _b[0], to = _b[1];
1467
- if (items.some(function (item) { return item.from < to && item.to > from; })) {
1468
- duration += to - from;
1469
- }
1470
- };
1471
- try {
1472
- for (var intervals_1 = __values(intervals), intervals_1_1 = intervals_1.next(); !intervals_1_1.done; intervals_1_1 = intervals_1.next()) {
1473
- var interval = intervals_1_1.value;
1474
- _loop_1(interval);
1475
- }
1476
- }
1477
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1478
- finally {
1479
- try {
1480
- if (intervals_1_1 && !intervals_1_1.done && (_a = intervals_1.return)) _a.call(intervals_1);
1481
- }
1482
- finally { if (e_1) throw e_1.error; }
1483
- }
1484
- return duration;
1485
- }
1486
-
1487
- /**
1488
- * Converts execution report from JSON to string format
1489
- */
1490
- function executionReportJsonToString(executionReportJson, options) {
1491
- var e_1, _a;
1492
- var _b, _c, _d, _e, _f, _g;
1493
- var _h = __assign(__assign({}, ExecutionReportStringOptionsDefaults), (options || {})), taxRate = _h.taxRate, chartsWidth = _h.chartsWidth;
1494
- var executionReportString = spaceTrim__default["default"](function (block) { return "\n # ".concat(executionReportJson.title || 'Execution report', "\n\n ").concat(block(executionReportJson.description || ''), "\n "); });
1495
- var headerList = [];
1496
- if (executionReportJson.promptbookUrl) {
1497
- headerList.push("PROMPTBOOK URL ".concat(executionReportJson.promptbookUrl));
1498
- }
1499
- headerList.push("PROMPTBOOK VERSION ".concat(executionReportJson.promptbookUsedVersion) +
1500
- (!executionReportJson.promptbookRequestedVersion
1501
- ? ''
1502
- : " *(requested ".concat(executionReportJson.promptbookRequestedVersion, ")*")));
1503
- if (executionReportJson.promptExecutions.length !== 0) {
1504
- // TODO: What if startedAt OR/AND completedAt is not defined?
1505
- var startedAt = moment__default["default"](Math.min.apply(Math, __spreadArray([], __read(executionReportJson.promptExecutions
1506
- .filter(function (promptExecution) { var _a, _b; return (_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.start; })
1507
- .map(function (promptExecution) { return moment__default["default"](promptExecution.result.timing.start).valueOf(); })), false)));
1508
- var completedAt = moment__default["default"](Math.max.apply(Math, __spreadArray([], __read(executionReportJson.promptExecutions
1509
- .filter(function (promptExecution) { var _a, _b; return (_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.complete; })
1510
- .map(function (promptExecution) { return moment__default["default"](promptExecution.result.timing.complete).valueOf(); })), false)));
1511
- var timingItems = executionReportJson.promptExecutions.map(function (promptExecution) {
1512
- var _a, _b, _c, _d;
1513
- return ({
1514
- title: promptExecution.prompt.title,
1515
- from: moment__default["default"]((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.start).valueOf() / 1000,
1516
- to: moment__default["default"]((_d = (_c = promptExecution.result) === null || _c === void 0 ? void 0 : _c.timing) === null || _d === void 0 ? void 0 : _d.complete).valueOf() / 1000,
1517
- });
1518
- });
1519
- var costItems = executionReportJson.promptExecutions
1520
- .filter(function (promptExecution) { var _a, _b; return typeof ((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price) === 'number'; })
1521
- .map(function (promptExecution) {
1522
- var _a, _b;
1523
- return ({
1524
- title: promptExecution.prompt.title,
1525
- from: 0,
1526
- to: ((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price) * (1 + taxRate),
1527
- });
1528
- });
1529
- var duration = moment__default["default"].duration(completedAt.diff(startedAt));
1530
- var naturalDuration = moment__default["default"].duration(countWorkingDuration(timingItems) * 1000);
1531
- var executionsWithKnownCost = executionReportJson.promptExecutions.filter(function (promptExecution) { var _a, _b; return (((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price) || 'UNKNOWN') !== 'UNKNOWN'; });
1532
- var cost = executionsWithKnownCost.reduce(function (cost, promptExecution) { return cost + (promptExecution.result.usage.price || 0); }, 0);
1533
- headerList.push("STARTED AT ".concat(moment__default["default"](startedAt).format("YYYY-MM-DD HH:mm:ss")));
1534
- headerList.push("COMPLETED AT ".concat(moment__default["default"](completedAt).format("YYYY-MM-DD HH:mm:ss")));
1535
- headerList.push("TOTAL DURATION ".concat(duration.humanize(MOMENT_ARG_THRESHOLDS)));
1536
- headerList.push("TOTAL NATURAL DURATION ".concat(naturalDuration.humanize(MOMENT_ARG_THRESHOLDS)));
1537
- headerList.push("TOTAL COST $".concat(formatNumber(cost * (1 + taxRate))) +
1538
- (executionsWithKnownCost.length === executionReportJson.promptExecutions.length
1539
- ? ''
1540
- : " *(Some cost is unknown)*") +
1541
- (taxRate !== 0 ? " *(with tax ".concat(taxRate * 100, "%)*") : ''));
1542
- executionReportString += '\n\n' + headerList.map(function (header) { return "- ".concat(header); }).join('\n');
1543
- executionReportString +=
1544
- '\n\n' +
1545
- '## 🗃 Index' +
1546
- '\n\n' +
1547
- executionReportJson.promptExecutions
1548
- .map(function (promptExecution) {
1549
- // TODO: Make some better system to convert hedings to links
1550
- var hash = normalizeToKebabCase(promptExecution.prompt.title);
1551
- if (/^\s*\p{Extended_Pictographic}/u.test(promptExecution.prompt.title)) {
1552
- hash = '-' + hash;
1553
- }
1554
- // TODO: Make working hash link for the template in md + pdf
1555
- return "- [".concat(promptExecution.prompt.title, "](#").concat(hash, ")");
1556
- })
1557
- .join('\n');
1558
- executionReportString +=
1559
- '\n\n' +
1560
- '## ⌚ Time chart' +
1561
- '\n\n' +
1562
- createMarkdownChart({
1563
- nameHeader: 'Template',
1564
- valueHeader: 'Timeline',
1565
- items: timingItems,
1566
- width: chartsWidth,
1567
- unitName: 'seconds',
1568
- });
1569
- executionReportString +=
1570
- '\n\n' +
1571
- '## 💸 Cost chart' +
1572
- '\n\n' +
1573
- createMarkdownChart({
1574
- nameHeader: 'Template',
1575
- valueHeader: 'Cost',
1576
- items: costItems,
1577
- width: chartsWidth,
1578
- unitName: 'USD',
1579
- });
1580
- }
1581
- else {
1582
- headerList.push("TOTAL COST $0 *(Nothing executed)*");
1583
- }
1584
- var _loop_1 = function (promptExecution) {
1585
- executionReportString += '\n\n\n\n' + "## ".concat(promptExecution.prompt.title);
1586
- var templateList = [];
1587
- // TODO: What if startedAt OR/AND completedAt is not defined?
1588
- var startedAt = moment__default["default"]((_c = (_b = promptExecution.result) === null || _b === void 0 ? void 0 : _b.timing) === null || _c === void 0 ? void 0 : _c.start);
1589
- var completedAt = moment__default["default"]((_e = (_d = promptExecution.result) === null || _d === void 0 ? void 0 : _d.timing) === null || _e === void 0 ? void 0 : _e.complete);
1590
- var duration = moment__default["default"].duration(completedAt.diff(startedAt));
1591
- // Not need here:
1592
- // > templateList.push(`STARTED AT ${moment(startedAt).calendar()}`);
1593
- templateList.push("DURATION ".concat(duration.humanize(MOMENT_ARG_THRESHOLDS)));
1594
- if (typeof ((_g = (_f = promptExecution.result) === null || _f === void 0 ? void 0 : _f.usage) === null || _g === void 0 ? void 0 : _g.price) === 'number') {
1595
- templateList.push("COST $".concat(formatNumber(promptExecution.result.usage.price * (1 + taxRate))) +
1596
- (taxRate !== 0 ? " *(with tax ".concat(taxRate * 100, "%)*") : ''));
1597
- }
1598
- else {
1599
- templateList.push("COST UNKNOWN");
1600
- }
1601
- executionReportString += '\n\n' + templateList.map(function (header) { return "- ".concat(header); }).join('\n');
1602
- /*
1603
- - MODEL VARIANT ${promptExecution.prompt.modelRequirements.modelVariant}
1604
- - MODEL NAME \`${promptExecution.result?.model}\` (requested \`${
1605
- promptExecution.prompt.modelRequirements.modelName
1606
-
1607
- */
1608
- if (just(true)) {
1609
- executionReportString +=
1610
- '\n\n\n\n' +
1611
- spaceTrim__default["default"](function (block) { return "\n\n ### Prompt\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.prompt.content)), "\n ```\n\n "); });
1612
- }
1613
- if (promptExecution.result && promptExecution.result.content) {
1614
- executionReportString +=
1615
- '\n\n\n\n' +
1616
- spaceTrim__default["default"](function (block) { return "\n\n ### Result\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.result.content)), "\n ```\n "); });
1617
- }
1618
- if (promptExecution.error && promptExecution.error.message) {
1619
- executionReportString +=
1620
- '\n\n\n\n' +
1621
- spaceTrim__default["default"](function (block) { return "\n\n ### Error\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.error.message)), "\n ```\n\n "); });
1622
- }
1623
- };
1624
- try {
1625
- for (var _j = __values(executionReportJson.promptExecutions), _k = _j.next(); !_k.done; _k = _j.next()) {
1626
- var promptExecution = _k.value;
1627
- _loop_1(promptExecution);
1628
- }
1629
- }
1630
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1631
- finally {
1632
- try {
1633
- if (_k && !_k.done && (_a = _j.return)) _a.call(_j);
1634
- }
1635
- finally { if (e_1) throw e_1.error; }
1636
- }
1637
- executionReportString = prettifyMarkdown(executionReportString);
1638
- return executionReportString;
1639
- }
1640
- /**
1641
- * TODO: Add mermaid chart for every report
1642
- * TODO: [🧠] Allow to filter out some parts of the report by options
1643
- */
1644
-
1645
- /**
1646
- * Counts number of characters in the text
1647
- */
1648
- function countCharacters(text) {
1649
- // Remove null characters
1650
- text = text.replace(/\0/g, '');
1651
- // Replace emojis (and also ZWJ sequence) with hyphens
1652
- text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1653
- text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1654
- text = text.replace(/\p{Extended_Pictographic}(\u{200D}\p{Extended_Pictographic})*/gu, '-');
1655
- return text.length;
1656
- }
1657
-
1658
- /**
1659
- * Counts number of lines in the text
1660
- */
1661
- function countLines(text) {
1662
- if (text === '') {
1663
- return 0;
1664
- }
1665
- return text.split('\n').length;
1666
- }
1667
-
1668
- /**
1669
- * Counts number of pages in the text
1670
- */
1671
- function countPages(text) {
1672
- var sentencesPerPage = 5; // Assuming each page has 5 sentences
1673
- var sentences = text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
1674
- var pageCount = Math.ceil(sentences.length / sentencesPerPage);
1675
- return pageCount;
1676
- }
1677
-
1678
- /**
1679
- * Counts number of paragraphs in the text
1680
- */
1681
- function countParagraphs(text) {
1682
- return text.split(/\n\s*\n/).filter(function (paragraph) { return paragraph.trim() !== ''; }).length;
1683
- }
1684
-
1685
- /**
1686
- * Counts number of sentences in the text
1687
- */
1688
- function countSentences(text) {
1689
- return text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; }).length;
1304
+ function countSentences(text) {
1305
+ return splitIntoSentences(text).length;
1690
1306
  }
1691
1307
 
1692
1308
  var defaultDiacriticsRemovalMap = [
@@ -1964,163 +1580,488 @@
1964
1580
  };
1965
1581
 
1966
1582
  /**
1967
- * Function isValidJsonString will tell you if the string is valid JSON or not
1583
+ * Function checkExpectations will check if the expectations on given value are met
1584
+ *
1585
+ * Note: There are two simmilar functions:
1586
+ * - `checkExpectations` which throws an error if the expectations are not met
1587
+ * - `isPassingExpectations` which returns a boolean
1588
+ *
1589
+ * @throws {ExpectError} if the expectations are not met
1590
+ * @returns {void} Nothing
1968
1591
  */
1969
- function isValidJsonString(value) {
1592
+ function checkExpectations(expectations, value) {
1593
+ var e_1, _a;
1970
1594
  try {
1971
- JSON.parse(value);
1595
+ for (var _b = __values(Object.entries(expectations)), _c = _b.next(); !_c.done; _c = _b.next()) {
1596
+ var _d = __read(_c.value, 2), unit = _d[0], _e = _d[1], max = _e.max, min = _e.min;
1597
+ var amount = CountUtils[unit.toUpperCase()](value);
1598
+ if (min && amount < min) {
1599
+ throw new ExpectError("Expected at least ".concat(min, " ").concat(unit, " but got ").concat(amount));
1600
+ } /* not else */
1601
+ if (max && amount > max) {
1602
+ throw new ExpectError("Expected at most ".concat(max, " ").concat(unit, " but got ").concat(amount));
1603
+ }
1604
+ }
1605
+ }
1606
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1607
+ finally {
1608
+ try {
1609
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1610
+ }
1611
+ finally { if (e_1) throw e_1.error; }
1612
+ }
1613
+ }
1614
+ /**
1615
+ * Function checkExpectations will check if the expectations on given value are met
1616
+ *
1617
+ * Note: There are two simmilar functions:
1618
+ * - `checkExpectations` which throws an error if the expectations are not met
1619
+ * - `isPassingExpectations` which returns a boolean
1620
+ *
1621
+ * @returns {boolean} True if the expectations are met
1622
+ */
1623
+ function isPassingExpectations(expectations, value) {
1624
+ try {
1625
+ checkExpectations(expectations, value);
1972
1626
  return true;
1973
1627
  }
1974
1628
  catch (error) {
1975
- if (!(error instanceof Error)) {
1629
+ if (!(error instanceof ExpectError)) {
1976
1630
  throw error;
1977
1631
  }
1978
- if (error.message.includes('Unexpected token')) {
1979
- return false;
1980
- }
1981
1632
  return false;
1982
1633
  }
1983
1634
  }
1635
+ /**
1636
+ * TODO: [💝] Unite object for expecting amount and format
1637
+ */
1984
1638
 
1985
1639
  /**
1986
- * Extracts code block from markdown.
1987
- *
1988
- * Note: If there are multiple or no code blocks the function throws an error
1640
+ * This error occurs during the parameter replacement in the template
1989
1641
  *
1990
- * Note: There are 3 simmilar function:
1991
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
1992
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
1993
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
1642
+ * Note: This is a kindof subtype of PromptbookExecutionError because it occurs during the execution of the pipeline
1994
1643
  */
1995
- function extractBlock(markdown) {
1996
- var content = extractOneBlockFromMarkdown(markdown).content;
1997
- return content;
1998
- }
1999
- //
1644
+ var TemplateError = /** @class */ (function (_super) {
1645
+ __extends(TemplateError, _super);
1646
+ function TemplateError(message) {
1647
+ var _this = _super.call(this, message) || this;
1648
+ _this.name = 'TemplateError';
1649
+ Object.setPrototypeOf(_this, TemplateError.prototype);
1650
+ return _this;
1651
+ }
1652
+ return TemplateError;
1653
+ }(Error));
2000
1654
 
2001
1655
  /**
2002
- * Removes quotes from a string
1656
+ * Replaces parameters in template with values from parameters object
2003
1657
  *
2004
- * Tip: This is very usefull for post-processing of the result of the LLM model
2005
- * Note: This function removes only the same quotes from the beginning and the end of the string
2006
- * Note: There are two simmilar functions:
2007
- * - `removeQuotes` which removes only bounding quotes
2008
- * - `unwrapResult` which removes whole introduce sentence
1658
+ * @param template the template with parameters in {curly} braces
1659
+ * @param parameters the object with parameters
1660
+ * @returns the template with replaced parameters
1661
+ * @throws {TemplateError} if parameter is not defined, not closed, or not opened
2009
1662
  *
2010
- * @param text optionally quoted text
2011
- * @returns text without quotes
1663
+ * @private within the createPromptbookExecutor
2012
1664
  */
2013
- function removeQuotes(text) {
2014
- if (text.startsWith('"') && text.endsWith('"')) {
2015
- return text.slice(1, -1);
1665
+ function replaceParameters(template, parameters) {
1666
+ var replacedTemplate = template;
1667
+ var match;
1668
+ var loopLimit = LOOP_LIMIT;
1669
+ var _loop_1 = function () {
1670
+ if (loopLimit-- < 0) {
1671
+ throw new UnexpectedError('Loop limit reached during parameters replacement in `replaceParameters`');
1672
+ }
1673
+ var precol = match.groups.precol;
1674
+ var parameterName = match.groups.parameterName;
1675
+ if (parameterName === '') {
1676
+ return "continue";
1677
+ }
1678
+ if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
1679
+ throw new TemplateError('Parameter is already opened or not closed');
1680
+ }
1681
+ if (parameters[parameterName] === undefined) {
1682
+ throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
1683
+ }
1684
+ var parameterValue = parameters[parameterName];
1685
+ if (parameterValue === undefined) {
1686
+ throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
1687
+ }
1688
+ parameterValue = parameterValue.toString();
1689
+ if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
1690
+ parameterValue = parameterValue
1691
+ .split('\n')
1692
+ .map(function (line, index) { return (index === 0 ? line : "".concat(precol).concat(line)); })
1693
+ .join('\n');
1694
+ }
1695
+ replacedTemplate =
1696
+ replacedTemplate.substring(0, match.index + precol.length) +
1697
+ parameterValue +
1698
+ replacedTemplate.substring(match.index + precol.length + parameterName.length + 2);
1699
+ };
1700
+ while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
1701
+ .exec(replacedTemplate))) {
1702
+ _loop_1();
2016
1703
  }
2017
- if (text.startsWith('\'') && text.endsWith('\'')) {
2018
- return text.slice(1, -1);
1704
+ // [💫] Check if there are parameters that are not closed properly
1705
+ if (/{\w+$/.test(replacedTemplate)) {
1706
+ throw new TemplateError('Parameter is not closed');
1707
+ }
1708
+ // [💫] Check if there are parameters that are not opened properly
1709
+ if (/^\w+}/.test(replacedTemplate)) {
1710
+ throw new TemplateError('Parameter is not opened');
1711
+ }
1712
+ return replacedTemplate;
1713
+ }
1714
+
1715
+ /**
1716
+ * Format either small or big number
1717
+ *
1718
+ * @private within the library
1719
+ */
1720
+ function formatNumber(value) {
1721
+ if (value === 0) {
1722
+ return '0';
1723
+ }
1724
+ for (var exponent = 0; exponent < 15; exponent++) {
1725
+ var factor = Math.pow(10, exponent);
1726
+ var valueRounded = Math.round(value * factor) / factor;
1727
+ if (Math.abs(value - valueRounded) / value <
1728
+ 0.001 /* <- TODO: Pass as option, pass to executionReportJsonToString as option */) {
1729
+ return valueRounded.toFixed(exponent);
1730
+ }
1731
+ }
1732
+ return value.toString();
1733
+ }
1734
+
1735
+ /**
1736
+ * Returns the same value that is passed as argument.
1737
+ * No side effects.
1738
+ *
1739
+ * Note: It can be usefull for leveling indentation
1740
+ *
1741
+ * @param value any values
1742
+ * @returns the same values
1743
+ */
1744
+ function just(value) {
1745
+ if (value === undefined) {
1746
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1747
+ return undefined;
1748
+ }
1749
+ return value;
1750
+ }
1751
+
1752
+ /**
1753
+ * Removes emojis from a string and fix whitespaces
1754
+ *
1755
+ * @param text with emojis
1756
+ * @returns text without emojis
1757
+ */
1758
+ function removeEmojis(text) {
1759
+ // Replace emojis (and also ZWJ sequence) with hyphens
1760
+ text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1761
+ text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1762
+ text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1763
+ text = text.replace(/\p{Extended_Pictographic}/gu, '');
1764
+ return text;
1765
+ }
1766
+
1767
+ /**
1768
+ * Create a markdown table from a 2D array of strings
1769
+ *
1770
+ * @private within the library
1771
+ */
1772
+ function createMarkdownTable(table) {
1773
+ var columnWidths = table.reduce(function (widths, row) {
1774
+ row.forEach(function (cell, columnIndex) {
1775
+ var cellLength = cell.length;
1776
+ if (!widths[columnIndex] || cellLength > widths[columnIndex]) {
1777
+ widths[columnIndex] = cellLength;
1778
+ }
1779
+ });
1780
+ return widths;
1781
+ }, []);
1782
+ var header = "| ".concat(table[0]
1783
+ .map(function (cell, columnIndex) { return cell.padEnd(columnWidths[columnIndex]); })
1784
+ .join(' | '), " |");
1785
+ var separator = "|".concat(columnWidths.map(function (width) { return '-'.repeat(width + 2); }).join('|'), "|");
1786
+ var rows = table.slice(1).map(function (row) {
1787
+ var paddedRow = row.map(function (cell, columnIndex) {
1788
+ return cell.padEnd(columnWidths[columnIndex]);
1789
+ });
1790
+ return "| ".concat(paddedRow.join(' | '), " |");
1791
+ });
1792
+ return __spreadArray([header, separator], __read(rows), false).join('\n');
1793
+ }
1794
+
1795
+ /**
1796
+ * Function createMarkdownChart will draw a chart in markdown from ⬛+🟦 tiles
1797
+ *
1798
+ * @private within the library
1799
+ */
1800
+ function createMarkdownChart(options) {
1801
+ var e_1, _a;
1802
+ var nameHeader = options.nameHeader, valueHeader = options.valueHeader, items = options.items, width = options.width, unitName = options.unitName;
1803
+ var from = Math.min.apply(Math, __spreadArray([], __read(items.map(function (item) { return item.from; })), false));
1804
+ var to = Math.max.apply(Math, __spreadArray([], __read(items.map(function (item) { return item.to; })), false));
1805
+ var scale = width / (to - from);
1806
+ var table = [[nameHeader, valueHeader]];
1807
+ try {
1808
+ for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
1809
+ var item = items_1_1.value;
1810
+ var before = Math.round((item.from - from) * scale);
1811
+ var during = Math.round((item.to - item.from) * scale);
1812
+ var after = width - before - during;
1813
+ table.push([removeEmojis(item.title).trim(), '░'.repeat(before) + '█'.repeat(during) + '░'.repeat(after)]);
1814
+ }
1815
+ }
1816
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1817
+ finally {
1818
+ try {
1819
+ if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
1820
+ }
1821
+ finally { if (e_1) throw e_1.error; }
1822
+ }
1823
+ var legend = "_Note: Each \u2588 represents ".concat(formatNumber(1 / scale), " ").concat(unitName, ", width of ").concat(valueHeader.toLowerCase(), " is ").concat(formatNumber(to - from), " ").concat(unitName, " = ").concat(width, " squares_");
1824
+ return createMarkdownTable(table) + '\n\n' + legend;
1825
+ }
1826
+ /**
1827
+ * TODO: Maybe use Mermain Gant Diagrams
1828
+ * @see https://jojozhuang.github.io/tutorial/mermaid-cheat-sheet/
1829
+ */
1830
+
1831
+ /**
1832
+ * Function escapeMarkdownBlock will escape markdown block if needed
1833
+ * It is useful when you want have block in block
1834
+ */
1835
+ function escapeMarkdownBlock(value) {
1836
+ return value.replace(/```/g, '\\`\\`\\`');
1837
+ }
1838
+
1839
+ /**
1840
+ * Default options for generating an execution report string
1841
+ */
1842
+ var ExecutionReportStringOptionsDefaults = {
1843
+ taxRate: 0,
1844
+ chartsWidth: 36,
1845
+ };
1846
+
1847
+ /**
1848
+ * The thresholds for the relative time in the `moment` library.
1849
+ *
1850
+ * @see https://momentjscom.readthedocs.io/en/latest/moment/07-customization/13-relative-time-threshold/
1851
+ */
1852
+ var MOMENT_ARG_THRESHOLDS = {
1853
+ ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
1854
+ };
1855
+
1856
+ /**
1857
+ * Count the duration of working time
1858
+ *
1859
+ * @private within the library
1860
+ */
1861
+ function countWorkingDuration(items) {
1862
+ var e_1, _a;
1863
+ var steps = Array.from(new Set(items.flatMap(function (item) { return [item.from, item.to]; })));
1864
+ steps.sort(function (a, b) { return a - b; });
1865
+ var intervals = steps.map(function (step, index) { return [step, steps[index + 1] || 0]; }).slice(0, -1);
1866
+ var duration = 0;
1867
+ var _loop_1 = function (interval) {
1868
+ var _b = __read(interval, 2), from = _b[0], to = _b[1];
1869
+ if (items.some(function (item) { return item.from < to && item.to > from; })) {
1870
+ duration += to - from;
1871
+ }
1872
+ };
1873
+ try {
1874
+ for (var intervals_1 = __values(intervals), intervals_1_1 = intervals_1.next(); !intervals_1_1.done; intervals_1_1 = intervals_1.next()) {
1875
+ var interval = intervals_1_1.value;
1876
+ _loop_1(interval);
1877
+ }
1878
+ }
1879
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1880
+ finally {
1881
+ try {
1882
+ if (intervals_1_1 && !intervals_1_1.done && (_a = intervals_1.return)) _a.call(intervals_1);
1883
+ }
1884
+ finally { if (e_1) throw e_1.error; }
1885
+ }
1886
+ return duration;
1887
+ }
1888
+
1889
+ /**
1890
+ * Converts execution report from JSON to string format
1891
+ */
1892
+ function executionReportJsonToString(executionReportJson, options) {
1893
+ var e_1, _a;
1894
+ var _b, _c, _d, _e, _f, _g;
1895
+ var _h = __assign(__assign({}, ExecutionReportStringOptionsDefaults), (options || {})), taxRate = _h.taxRate, chartsWidth = _h.chartsWidth;
1896
+ var executionReportString = spaceTrim__default["default"](function (block) { return "\n # ".concat(executionReportJson.title || 'Execution report', "\n\n ").concat(block(executionReportJson.description || ''), "\n "); });
1897
+ var headerList = [];
1898
+ if (executionReportJson.promptbookUrl) {
1899
+ headerList.push("PROMPTBOOK URL ".concat(executionReportJson.promptbookUrl));
1900
+ }
1901
+ headerList.push("PROMPTBOOK VERSION ".concat(executionReportJson.promptbookUsedVersion) +
1902
+ (!executionReportJson.promptbookRequestedVersion
1903
+ ? ''
1904
+ : " *(requested ".concat(executionReportJson.promptbookRequestedVersion, ")*")));
1905
+ if (executionReportJson.promptExecutions.length !== 0) {
1906
+ // TODO: What if startedAt OR/AND completedAt is not defined?
1907
+ var startedAt = moment__default["default"](Math.min.apply(Math, __spreadArray([], __read(executionReportJson.promptExecutions
1908
+ .filter(function (promptExecution) { var _a, _b; return (_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.start; })
1909
+ .map(function (promptExecution) { return moment__default["default"](promptExecution.result.timing.start).valueOf(); })), false)));
1910
+ var completedAt = moment__default["default"](Math.max.apply(Math, __spreadArray([], __read(executionReportJson.promptExecutions
1911
+ .filter(function (promptExecution) { var _a, _b; return (_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.complete; })
1912
+ .map(function (promptExecution) { return moment__default["default"](promptExecution.result.timing.complete).valueOf(); })), false)));
1913
+ var timingItems = executionReportJson.promptExecutions.map(function (promptExecution) {
1914
+ var _a, _b, _c, _d;
1915
+ return ({
1916
+ title: promptExecution.prompt.title,
1917
+ from: moment__default["default"]((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.start).valueOf() / 1000,
1918
+ to: moment__default["default"]((_d = (_c = promptExecution.result) === null || _c === void 0 ? void 0 : _c.timing) === null || _d === void 0 ? void 0 : _d.complete).valueOf() / 1000,
1919
+ });
1920
+ });
1921
+ var costItems = executionReportJson.promptExecutions
1922
+ .filter(function (promptExecution) { var _a, _b; return typeof ((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price) === 'number'; })
1923
+ .map(function (promptExecution) {
1924
+ var _a, _b;
1925
+ return ({
1926
+ title: promptExecution.prompt.title,
1927
+ from: 0,
1928
+ to: ((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price) * (1 + taxRate),
1929
+ });
1930
+ });
1931
+ var duration = moment__default["default"].duration(completedAt.diff(startedAt));
1932
+ var naturalDuration = moment__default["default"].duration(countWorkingDuration(timingItems) * 1000);
1933
+ var executionsWithKnownCost = executionReportJson.promptExecutions.filter(function (promptExecution) { var _a, _b; return (((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price) || 'UNKNOWN') !== 'UNKNOWN'; });
1934
+ var cost = executionsWithKnownCost.reduce(function (cost, promptExecution) { return cost + (promptExecution.result.usage.price || 0); }, 0);
1935
+ headerList.push("STARTED AT ".concat(moment__default["default"](startedAt).format("YYYY-MM-DD HH:mm:ss")));
1936
+ headerList.push("COMPLETED AT ".concat(moment__default["default"](completedAt).format("YYYY-MM-DD HH:mm:ss")));
1937
+ headerList.push("TOTAL DURATION ".concat(duration.humanize(MOMENT_ARG_THRESHOLDS)));
1938
+ headerList.push("TOTAL NATURAL DURATION ".concat(naturalDuration.humanize(MOMENT_ARG_THRESHOLDS)));
1939
+ headerList.push("TOTAL COST $".concat(formatNumber(cost * (1 + taxRate))) +
1940
+ (executionsWithKnownCost.length === executionReportJson.promptExecutions.length
1941
+ ? ''
1942
+ : " *(Some cost is unknown)*") +
1943
+ (taxRate !== 0 ? " *(with tax ".concat(taxRate * 100, "%)*") : ''));
1944
+ executionReportString += '\n\n' + headerList.map(function (header) { return "- ".concat(header); }).join('\n');
1945
+ executionReportString +=
1946
+ '\n\n' +
1947
+ '## 🗃 Index' +
1948
+ '\n\n' +
1949
+ executionReportJson.promptExecutions
1950
+ .map(function (promptExecution) {
1951
+ // TODO: Make some better system to convert hedings to links
1952
+ var hash = normalizeToKebabCase(promptExecution.prompt.title);
1953
+ if (/^\s*\p{Extended_Pictographic}/u.test(promptExecution.prompt.title)) {
1954
+ hash = '-' + hash;
1955
+ }
1956
+ // TODO: Make working hash link for the template in md + pdf
1957
+ return "- [".concat(promptExecution.prompt.title, "](#").concat(hash, ")");
1958
+ })
1959
+ .join('\n');
1960
+ executionReportString +=
1961
+ '\n\n' +
1962
+ '## ⌚ Time chart' +
1963
+ '\n\n' +
1964
+ createMarkdownChart({
1965
+ nameHeader: 'Template',
1966
+ valueHeader: 'Timeline',
1967
+ items: timingItems,
1968
+ width: chartsWidth,
1969
+ unitName: 'seconds',
1970
+ });
1971
+ executionReportString +=
1972
+ '\n\n' +
1973
+ '## 💸 Cost chart' +
1974
+ '\n\n' +
1975
+ createMarkdownChart({
1976
+ nameHeader: 'Template',
1977
+ valueHeader: 'Cost',
1978
+ items: costItems,
1979
+ width: chartsWidth,
1980
+ unitName: 'USD',
1981
+ });
1982
+ }
1983
+ else {
1984
+ headerList.push("TOTAL COST $0 *(Nothing executed)*");
1985
+ }
1986
+ var _loop_1 = function (promptExecution) {
1987
+ executionReportString += '\n\n\n\n' + "## ".concat(promptExecution.prompt.title);
1988
+ var templateList = [];
1989
+ // TODO: What if startedAt OR/AND completedAt is not defined?
1990
+ var startedAt = moment__default["default"]((_c = (_b = promptExecution.result) === null || _b === void 0 ? void 0 : _b.timing) === null || _c === void 0 ? void 0 : _c.start);
1991
+ var completedAt = moment__default["default"]((_e = (_d = promptExecution.result) === null || _d === void 0 ? void 0 : _d.timing) === null || _e === void 0 ? void 0 : _e.complete);
1992
+ var duration = moment__default["default"].duration(completedAt.diff(startedAt));
1993
+ // Not need here:
1994
+ // > templateList.push(`STARTED AT ${moment(startedAt).calendar()}`);
1995
+ templateList.push("DURATION ".concat(duration.humanize(MOMENT_ARG_THRESHOLDS)));
1996
+ if (typeof ((_g = (_f = promptExecution.result) === null || _f === void 0 ? void 0 : _f.usage) === null || _g === void 0 ? void 0 : _g.price) === 'number') {
1997
+ templateList.push("COST $".concat(formatNumber(promptExecution.result.usage.price * (1 + taxRate))) +
1998
+ (taxRate !== 0 ? " *(with tax ".concat(taxRate * 100, "%)*") : ''));
1999
+ }
2000
+ else {
2001
+ templateList.push("COST UNKNOWN");
2002
+ }
2003
+ executionReportString += '\n\n' + templateList.map(function (header) { return "- ".concat(header); }).join('\n');
2004
+ /*
2005
+ - MODEL VARIANT ${promptExecution.prompt.modelRequirements.modelVariant}
2006
+ - MODEL NAME \`${promptExecution.result?.model}\` (requested \`${
2007
+ promptExecution.prompt.modelRequirements.modelName
2008
+
2009
+ */
2010
+ if (just(true)) {
2011
+ executionReportString +=
2012
+ '\n\n\n\n' +
2013
+ spaceTrim__default["default"](function (block) { return "\n\n ### Prompt\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.prompt.content)), "\n ```\n\n "); });
2014
+ }
2015
+ if (promptExecution.result && promptExecution.result.content) {
2016
+ executionReportString +=
2017
+ '\n\n\n\n' +
2018
+ spaceTrim__default["default"](function (block) { return "\n\n ### Result\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.result.content)), "\n ```\n "); });
2019
+ }
2020
+ if (promptExecution.error && promptExecution.error.message) {
2021
+ executionReportString +=
2022
+ '\n\n\n\n' +
2023
+ spaceTrim__default["default"](function (block) { return "\n\n ### Error\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.error.message)), "\n ```\n\n "); });
2024
+ }
2025
+ };
2026
+ try {
2027
+ for (var _j = __values(executionReportJson.promptExecutions), _k = _j.next(); !_k.done; _k = _j.next()) {
2028
+ var promptExecution = _k.value;
2029
+ _loop_1(promptExecution);
2030
+ }
2019
2031
  }
2020
- return text;
2021
- }
2022
-
2023
- /**
2024
- * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
2025
- *
2026
- * Note: This is usefull for post-processing of the result of the chat LLM model
2027
- * when the model wraps the result in the (markdown) code block.
2028
- *
2029
- */
2030
- function trimCodeBlock(value) {
2031
- value = spaceTrim__default["default"](value);
2032
- if (!/^```[a-z]*(.*)```$/is.test(value)) {
2033
- return value;
2032
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2033
+ finally {
2034
+ try {
2035
+ if (_k && !_k.done && (_a = _j.return)) _a.call(_j);
2036
+ }
2037
+ finally { if (e_1) throw e_1.error; }
2034
2038
  }
2035
- value = value.replace(/^```[a-z]*/i, '');
2036
- value = value.replace(/```$/i, '');
2037
- value = spaceTrim__default["default"](value);
2038
- return value;
2039
+ executionReportString = prettifyMarkdown(executionReportString);
2040
+ return executionReportString;
2039
2041
  }
2040
-
2041
2042
  /**
2042
- * Function trimEndOfCodeBlock will remove ending code block from the string if it is present.
2043
- *
2044
- * Note: This is usefull for post-processing of the result of the completion LLM model
2045
- * if you want to start code block in the prompt but you don't want to end it in the result.
2043
+ * TODO: Add mermaid chart for every report
2044
+ * TODO: [🧠] Allow to filter out some parts of the report by options
2046
2045
  */
2047
- function trimEndOfCodeBlock(value) {
2048
- value = spaceTrim__default["default"](value);
2049
- value = value.replace(/```$/g, '');
2050
- value = spaceTrim__default["default"](value);
2051
- return value;
2052
- }
2053
2046
 
2054
2047
  /**
2055
- * Removes quotes and optional introduce text from a string
2056
- *
2057
- * Tip: This is very usefull for post-processing of the result of the LLM model
2058
- * Note: This function trims the text and removes whole introduce sentence if it is present
2059
- * Note: There are two simmilar functions:
2060
- * - `removeQuotes` which removes only bounding quotes
2061
- * - `unwrapResult` which removes whole introduce sentence
2062
- *
2063
- * @param text optionally quoted text
2064
- * @returns text without quotes
2048
+ * Function isValidJsonString will tell you if the string is valid JSON or not
2065
2049
  */
2066
- function unwrapResult(text, options) {
2067
- var _a = options || {}, _b = _a.isTrimmed, isTrimmed = _b === void 0 ? true : _b, _c = _a.isIntroduceSentenceRemoved, isIntroduceSentenceRemoved = _c === void 0 ? true : _c;
2068
- var trimmedText = text;
2069
- // Remove leading and trailing spaces and newlines
2070
- if (isTrimmed) {
2071
- trimmedText = spaceTrim__default["default"](trimmedText);
2072
- }
2073
- var processedText = trimmedText;
2074
- if (isIntroduceSentenceRemoved) {
2075
- var introduceSentenceRegex = /^[a-zěščřžýáíéúů:\s]*:\s*/i;
2076
- if (introduceSentenceRegex.test(text)) {
2077
- // Remove the introduce sentence and quotes by replacing it with an empty string
2078
- processedText = processedText.replace(introduceSentenceRegex, '');
2079
- }
2080
- processedText = spaceTrim__default["default"](processedText);
2081
- }
2082
- if (processedText.length < 3) {
2083
- return trimmedText;
2084
- }
2085
- if (processedText.includes('\n')) {
2086
- return trimmedText;
2050
+ function isValidJsonString(value) {
2051
+ try {
2052
+ JSON.parse(value);
2053
+ return true;
2087
2054
  }
2088
- // Remove the quotes by extracting the substring without the first and last characters
2089
- var unquotedText = processedText.slice(1, -1);
2090
- // Check if the text starts and ends with quotes
2091
- if ([
2092
- ['"', '"'],
2093
- ["'", "'"],
2094
- ['`', '`'],
2095
- ['*', '*'],
2096
- ['_', '_'],
2097
- ['„', '“'],
2098
- ['«', '»'] /* <- QUOTES to config */,
2099
- ].some(function (_a) {
2100
- var _b = __read(_a, 2), startQuote = _b[0], endQuote = _b[1];
2101
- if (!processedText.startsWith(startQuote)) {
2102
- return false;
2103
- }
2104
- if (!processedText.endsWith(endQuote)) {
2105
- return false;
2106
- }
2107
- if (unquotedText.includes(startQuote) && !unquotedText.includes(endQuote)) {
2108
- return false;
2055
+ catch (error) {
2056
+ if (!(error instanceof Error)) {
2057
+ throw error;
2109
2058
  }
2110
- if (!unquotedText.includes(startQuote) && unquotedText.includes(endQuote)) {
2059
+ if (error.message.includes('Unexpected token')) {
2111
2060
  return false;
2112
2061
  }
2113
- return true;
2114
- })) {
2115
- return unwrapResult(unquotedText, { isTrimmed: false, isIntroduceSentenceRemoved: false });
2116
- }
2117
- else {
2118
- return processedText;
2062
+ return false;
2119
2063
  }
2120
2064
  }
2121
- /**
2122
- * TODO: [🧠] Should this also unwrap the (parenthesis)
2123
- */
2124
2065
 
2125
2066
  /**
2126
2067
  * Makes first letter of a string uppercase
@@ -2428,11 +2369,164 @@
2428
2369
  return true;
2429
2370
  }
2430
2371
 
2372
+ /**
2373
+ * Extracts code block from markdown.
2374
+ *
2375
+ * Note: If there are multiple or no code blocks the function throws an error
2376
+ *
2377
+ * Note: There are 3 simmilar function:
2378
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
2379
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
2380
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
2381
+ */
2382
+ function extractBlock(markdown) {
2383
+ var content = extractOneBlockFromMarkdown(markdown).content;
2384
+ return content;
2385
+ }
2386
+ //
2387
+
2388
+ /**
2389
+ * Removes quotes from a string
2390
+ *
2391
+ * Tip: This is very usefull for post-processing of the result of the LLM model
2392
+ * Note: This function removes only the same quotes from the beginning and the end of the string
2393
+ * Note: There are two simmilar functions:
2394
+ * - `removeQuotes` which removes only bounding quotes
2395
+ * - `unwrapResult` which removes whole introduce sentence
2396
+ *
2397
+ * @param text optionally quoted text
2398
+ * @returns text without quotes
2399
+ */
2400
+ function removeQuotes(text) {
2401
+ if (text.startsWith('"') && text.endsWith('"')) {
2402
+ return text.slice(1, -1);
2403
+ }
2404
+ if (text.startsWith('\'') && text.endsWith('\'')) {
2405
+ return text.slice(1, -1);
2406
+ }
2407
+ return text;
2408
+ }
2409
+
2410
+ /**
2411
+ * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
2412
+ *
2413
+ * Note: This is usefull for post-processing of the result of the chat LLM model
2414
+ * when the model wraps the result in the (markdown) code block.
2415
+ *
2416
+ */
2417
+ function trimCodeBlock(value) {
2418
+ value = spaceTrim__default["default"](value);
2419
+ if (!/^```[a-z]*(.*)```$/is.test(value)) {
2420
+ return value;
2421
+ }
2422
+ value = value.replace(/^```[a-z]*/i, '');
2423
+ value = value.replace(/```$/i, '');
2424
+ value = spaceTrim__default["default"](value);
2425
+ return value;
2426
+ }
2427
+
2428
+ /**
2429
+ * Function trimEndOfCodeBlock will remove ending code block from the string if it is present.
2430
+ *
2431
+ * Note: This is usefull for post-processing of the result of the completion LLM model
2432
+ * if you want to start code block in the prompt but you don't want to end it in the result.
2433
+ */
2434
+ function trimEndOfCodeBlock(value) {
2435
+ value = spaceTrim__default["default"](value);
2436
+ value = value.replace(/```$/g, '');
2437
+ value = spaceTrim__default["default"](value);
2438
+ return value;
2439
+ }
2440
+
2441
+ /**
2442
+ * Removes quotes and optional introduce text from a string
2443
+ *
2444
+ * Tip: This is very usefull for post-processing of the result of the LLM model
2445
+ * Note: This function trims the text and removes whole introduce sentence if it is present
2446
+ * Note: There are two simmilar functions:
2447
+ * - `removeQuotes` which removes only bounding quotes
2448
+ * - `unwrapResult` which removes whole introduce sentence
2449
+ *
2450
+ * @param text optionally quoted text
2451
+ * @returns text without quotes
2452
+ */
2453
+ function unwrapResult(text, options) {
2454
+ var _a = options || {}, _b = _a.isTrimmed, isTrimmed = _b === void 0 ? true : _b, _c = _a.isIntroduceSentenceRemoved, isIntroduceSentenceRemoved = _c === void 0 ? true : _c;
2455
+ var trimmedText = text;
2456
+ // Remove leading and trailing spaces and newlines
2457
+ if (isTrimmed) {
2458
+ trimmedText = spaceTrim__default["default"](trimmedText);
2459
+ }
2460
+ var processedText = trimmedText;
2461
+ if (isIntroduceSentenceRemoved) {
2462
+ var introduceSentenceRegex = /^[a-zěščřžýáíéúů:\s]*:\s*/i;
2463
+ if (introduceSentenceRegex.test(text)) {
2464
+ // Remove the introduce sentence and quotes by replacing it with an empty string
2465
+ processedText = processedText.replace(introduceSentenceRegex, '');
2466
+ }
2467
+ processedText = spaceTrim__default["default"](processedText);
2468
+ }
2469
+ if (processedText.length < 3) {
2470
+ return trimmedText;
2471
+ }
2472
+ if (processedText.includes('\n')) {
2473
+ return trimmedText;
2474
+ }
2475
+ // Remove the quotes by extracting the substring without the first and last characters
2476
+ var unquotedText = processedText.slice(1, -1);
2477
+ // Check if the text starts and ends with quotes
2478
+ if ([
2479
+ ['"', '"'],
2480
+ ["'", "'"],
2481
+ ['`', '`'],
2482
+ ['*', '*'],
2483
+ ['_', '_'],
2484
+ ['„', '“'],
2485
+ ['«', '»'] /* <- QUOTES to config */,
2486
+ ].some(function (_a) {
2487
+ var _b = __read(_a, 2), startQuote = _b[0], endQuote = _b[1];
2488
+ if (!processedText.startsWith(startQuote)) {
2489
+ return false;
2490
+ }
2491
+ if (!processedText.endsWith(endQuote)) {
2492
+ return false;
2493
+ }
2494
+ if (unquotedText.includes(startQuote) && !unquotedText.includes(endQuote)) {
2495
+ return false;
2496
+ }
2497
+ if (!unquotedText.includes(startQuote) && unquotedText.includes(endQuote)) {
2498
+ return false;
2499
+ }
2500
+ return true;
2501
+ })) {
2502
+ return unwrapResult(unquotedText, { isTrimmed: false, isIntroduceSentenceRemoved: false });
2503
+ }
2504
+ else {
2505
+ return processedText;
2506
+ }
2507
+ }
2508
+ /**
2509
+ * TODO: [🧠] Should this also unwrap the (parenthesis)
2510
+ */
2511
+
2512
+ // And the normalization (originally n12 library) utilities:
2513
+ var normalizeTo = {
2514
+ camelCase: normalizeTo_camelCase,
2515
+ PascalCase: normalizeTo_PascalCase,
2516
+ 'SCREAMING-CASE': normalizeTo_SCREAMING_CASE,
2517
+ snake_case: normalizeTo_snake_case,
2518
+ 'kebab-case': normalizeToKebabCase,
2519
+ };
2520
+ /**
2521
+ * TODO: [🧠] Maybe create some indipendent package like `markdown-tools` from both here exported and @private utilities
2522
+ */
2523
+
2431
2524
  exports.CountUtils = CountUtils;
2432
2525
  exports.DIACRITIC_VARIANTS_LETTERS = DIACRITIC_VARIANTS_LETTERS;
2433
2526
  exports.ExecutionReportStringOptionsDefaults = ExecutionReportStringOptionsDefaults;
2434
2527
  exports.assertsExecutionSuccessful = assertsExecutionSuccessful;
2435
2528
  exports.capitalize = capitalize;
2529
+ exports.checkExpectations = checkExpectations;
2436
2530
  exports.countCharacters = countCharacters;
2437
2531
  exports.countLines = countLines;
2438
2532
  exports.countPages = countPages;
@@ -2445,10 +2539,12 @@
2445
2539
  exports.extractAllListItemsFromMarkdown = extractAllListItemsFromMarkdown;
2446
2540
  exports.extractBlock = extractBlock;
2447
2541
  exports.extractOneBlockFromMarkdown = extractOneBlockFromMarkdown;
2542
+ exports.isPassingExpectations = isPassingExpectations;
2448
2543
  exports.isValidJsonString = isValidJsonString;
2449
2544
  exports.isValidKeyword = isValidKeyword;
2450
2545
  exports.nameToUriPart = nameToUriPart;
2451
2546
  exports.nameToUriParts = nameToUriParts;
2547
+ exports.normalizeTo = normalizeTo;
2452
2548
  exports.normalizeToKebabCase = normalizeToKebabCase;
2453
2549
  exports.normalizeTo_PascalCase = normalizeTo_PascalCase;
2454
2550
  exports.normalizeTo_SCREAMING_CASE = normalizeTo_SCREAMING_CASE;
@@ -2466,6 +2562,7 @@
2466
2562
  exports.removeQuotes = removeQuotes;
2467
2563
  exports.replaceParameters = replaceParameters;
2468
2564
  exports.searchKeywords = searchKeywords;
2565
+ exports.splitIntoSentences = splitIntoSentences;
2469
2566
  exports.trimCodeBlock = trimCodeBlock;
2470
2567
  exports.trimEndOfCodeBlock = trimEndOfCodeBlock;
2471
2568
  exports.unwrapResult = unwrapResult;