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