@promptbook/cli 0.74.0-4 → 0.74.0-6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/index.es.js CHANGED
@@ -16,6 +16,7 @@ import * as dotenv from 'dotenv';
16
16
  import sha256 from 'crypto-js/sha256';
17
17
  import glob from 'glob-promise';
18
18
  import prompts from 'prompts';
19
+ import moment from 'moment';
19
20
  import { io } from 'socket.io-client';
20
21
  import Anthropic from '@anthropic-ai/sdk';
21
22
  import { OpenAIClient, AzureKeyCredential } from '@azure/openai';
@@ -36,7 +37,7 @@ var BOOK_LANGUAGE_VERSION = '1.0.0';
36
37
  *
37
38
  * @see https://github.com/webgptorg/promptbook
38
39
  */
39
- var PROMPTBOOK_ENGINE_VERSION = '0.74.0-3';
40
+ var PROMPTBOOK_ENGINE_VERSION = '0.74.0-5';
40
41
  /**
41
42
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
42
43
  */
@@ -160,31 +161,6 @@ function __spreadArray(to, from, pack) {
160
161
  return to.concat(ar || Array.prototype.slice.call(from));
161
162
  }
162
163
 
163
- /**
164
- * This error type indicates that you try to use a feature that is not available in the current environment
165
- *
166
- * @public exported from `@promptbook/core`
167
- */
168
- var EnvironmentMismatchError = /** @class */ (function (_super) {
169
- __extends(EnvironmentMismatchError, _super);
170
- function EnvironmentMismatchError(message) {
171
- var _this = _super.call(this, message) || this;
172
- _this.name = 'EnvironmentMismatchError';
173
- Object.setPrototypeOf(_this, EnvironmentMismatchError.prototype);
174
- return _this;
175
- }
176
- return EnvironmentMismatchError;
177
- }(Error));
178
-
179
- /**
180
- * Detects if the code is running in a Node.js environment
181
- *
182
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
183
- *
184
- * @public exported from `@promptbook/utils`
185
- */
186
- var $isRunningInNode = new Function("\n try {\n return this === global;\n } catch (e) {\n return false;\n }\n");
187
-
188
164
  /**
189
165
  * Returns the same value that is passed as argument.
190
166
  * No side effects.
@@ -526,6 +502,15 @@ var RESERVED_PARAMETER_MISSING_VALUE = 'MISSING-' + REPLACING_NONCE;
526
502
  * @private within the repository
527
503
  */
528
504
  var RESERVED_PARAMETER_RESTRICTED = 'RESTRICTED-' + REPLACING_NONCE;
505
+ /**
506
+ * The thresholds for the relative time in the `moment` NPM package.
507
+ *
508
+ * @see https://momentjscom.readthedocs.io/en/latest/moment/07-customization/13-relative-time-threshold/
509
+ * @private within the repository - too low-level in comparison with other constants
510
+ */
511
+ var MOMENT_ARG_THRESHOLDS = {
512
+ 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.
513
+ };
529
514
  /**
530
515
  * @@@
531
516
  *
@@ -569,6 +554,31 @@ true);
569
554
  * TODO: [🧠][🧜‍♂️] Maybe join remoteUrl and path into single value
570
555
  */
571
556
 
557
+ /**
558
+ * This error type indicates that you try to use a feature that is not available in the current environment
559
+ *
560
+ * @public exported from `@promptbook/core`
561
+ */
562
+ var EnvironmentMismatchError = /** @class */ (function (_super) {
563
+ __extends(EnvironmentMismatchError, _super);
564
+ function EnvironmentMismatchError(message) {
565
+ var _this = _super.call(this, message) || this;
566
+ _this.name = 'EnvironmentMismatchError';
567
+ Object.setPrototypeOf(_this, EnvironmentMismatchError.prototype);
568
+ return _this;
569
+ }
570
+ return EnvironmentMismatchError;
571
+ }(Error));
572
+
573
+ /**
574
+ * Detects if the code is running in a Node.js environment
575
+ *
576
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
577
+ *
578
+ * @public exported from `@promptbook/utils`
579
+ */
580
+ var $isRunningInNode = new Function("\n try {\n return this === global;\n } catch (e) {\n return false;\n }\n");
581
+
572
582
  /**
573
583
  * Initializes `about` command for Promptbook CLI utilities
574
584
  *
@@ -1710,7 +1720,7 @@ function isValidPipelineUrl(url) {
1710
1720
  if (!url.startsWith('https://')) {
1711
1721
  return false;
1712
1722
  }
1713
- if (!url.endsWith('.ptbk.md')) {
1723
+ if (!(url.endsWith('.book.md') || url.endsWith('.book') || url.endsWith('.ptbk.md') || url.endsWith('.ptbk'))) {
1714
1724
  return false;
1715
1725
  }
1716
1726
  if (url.includes('#')) {
@@ -10209,13 +10219,13 @@ function initializeMakeCommand(program) {
10209
10219
  makeCommand.option('-f, --format <format>', spaceTrim$1("\n Output format of builded collection \"javascript\", \"typescript\" or \"json\"\n\n Note: You can use multiple formats separated by comma\n "), 'javascript' /* <- Note: [🏳‍🌈] */);
10210
10220
  makeCommand.option('--no-validation', "Do not validate logic of pipelines in collection", true);
10211
10221
  makeCommand.option('--validation', "Types of validations separated by comma (options \"logic\",\"imports\")", 'logic,imports');
10212
- makeCommand.option('--reload', "Call LLM models even if same prompt with result is in the cache", false);
10213
- makeCommand.option('--verbose', "Is output verbose", false);
10222
+ makeCommand.option('-r, --reload', "Call LLM models even if same prompt with result is in the cache", false);
10223
+ makeCommand.option('-v, --verbose', "Is output verbose", false);
10214
10224
  makeCommand.option('-o, --out-file <path>', spaceTrim$1("\n Where to save the builded collection\n\n Note: If you keep it \"".concat(DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, "\" it will be saved in the root of the promptbook directory\n If you set it to a path, it will be saved in that path\n BUT you can use only one format and set correct extension\n ")), DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME);
10215
10225
  makeCommand.action(function (path, _a) {
10216
10226
  var projectName = _a.projectName, format = _a.format, validation = _a.validation, isCacheReloaded = _a.reload, isVerbose = _a.verbose, outFile = _a.outFile;
10217
10227
  return __awaiter(_this, void 0, void 0, function () {
10218
- var formats, validations, options, fs, llm, executables, tools, collection, validations_1, validations_1_1, validation_1, _b, _c, pipelineUrl, pipeline, e_1_1, e_2_1, collectionJson, collectionJsonString, collectionJsonItems, saveFile;
10228
+ var formats, validations, prepareAndScrapeOptions, fs, llm, executables, tools, collection, validations_1, validations_1_1, validation_1, _b, _c, pipelineUrl, pipeline, e_1_1, e_2_1, collectionJson, collectionJsonString, collectionJsonItems, saveFile;
10219
10229
  var _d, e_2, _e, e_1, _f;
10220
10230
  var _this = this;
10221
10231
  return __generator(this, function (_g) {
@@ -10233,20 +10243,20 @@ function initializeMakeCommand(program) {
10233
10243
  console.error(colors.red("You can only use one format if you specify --out-file"));
10234
10244
  return [2 /*return*/, process.exit(1)];
10235
10245
  }
10236
- options = {
10246
+ prepareAndScrapeOptions = {
10237
10247
  isVerbose: isVerbose,
10238
10248
  isCacheReloaded: isCacheReloaded,
10239
10249
  };
10240
- fs = $provideFilesystemForNode(options);
10241
- llm = $provideLlmToolsForCli(options);
10242
- return [4 /*yield*/, $provideExecutablesForNode(options)];
10250
+ fs = $provideFilesystemForNode(prepareAndScrapeOptions);
10251
+ llm = $provideLlmToolsForCli(prepareAndScrapeOptions);
10252
+ return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
10243
10253
  case 1:
10244
10254
  executables = _g.sent();
10245
10255
  _d = {
10246
10256
  llm: llm,
10247
10257
  fs: fs
10248
10258
  };
10249
- return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, options)];
10259
+ return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, prepareAndScrapeOptions)];
10250
10260
  case 2:
10251
10261
  tools = (_d.scrapers = _g.sent(),
10252
10262
  _d.script = [
@@ -10620,6 +10630,333 @@ function initializePrettifyCommand(program) {
10620
10630
  * TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
10621
10631
  */
10622
10632
 
10633
+ /**
10634
+ * Pretty print an embedding vector for logging
10635
+ *
10636
+ * @public exported from `@promptbook/core`
10637
+ */
10638
+ function embeddingVectorToString(embeddingVector) {
10639
+ var vectorLength = Math.pow(embeddingVector.reduce(function (acc, val) { return acc + Math.pow(val, 2); }, 0), 0.5);
10640
+ return "[EmbeddingVector; ".concat(embeddingVector.length, " dimensions; length: ").concat(vectorLength.toFixed(2), "; ").concat(embeddingVector.slice(0, 3).join(', '), "...]");
10641
+ }
10642
+
10643
+ /**
10644
+ * Format either small or big number
10645
+ *
10646
+ * @private within the repository
10647
+ */
10648
+ function formatNumber(value) {
10649
+ if (value === 0) {
10650
+ return '0';
10651
+ }
10652
+ for (var exponent = 0; exponent < 15; exponent++) {
10653
+ var factor = Math.pow(10, exponent);
10654
+ var valueRounded = Math.round(value * factor) / factor;
10655
+ if (Math.abs(value - valueRounded) / value <
10656
+ 0.001 /* <- TODO: Pass as option, pass to executionReportJsonToString as option */) {
10657
+ return valueRounded.toFixed(exponent);
10658
+ }
10659
+ }
10660
+ return value.toString();
10661
+ }
10662
+
10663
+ /**
10664
+ * Create a markdown table from a 2D array of strings
10665
+ *
10666
+ * @public exported from `@promptbook/markdown-utils`
10667
+ */
10668
+ function createMarkdownTable(table) {
10669
+ var columnWidths = table.reduce(function (widths, row) {
10670
+ row.forEach(function (subformat, columnIndex) {
10671
+ var cellLength = subformat.length;
10672
+ if (!widths[columnIndex] || cellLength > widths[columnIndex]) {
10673
+ widths[columnIndex] = cellLength;
10674
+ }
10675
+ });
10676
+ return widths;
10677
+ }, []);
10678
+ var header = "| ".concat(table[0]
10679
+ .map(function (subformat, columnIndex) { return subformat.padEnd(columnWidths[columnIndex]); })
10680
+ .join(' | '), " |");
10681
+ var separator = "|".concat(columnWidths.map(function (width) { return '-'.repeat(width + 2); }).join('|'), "|");
10682
+ var rows = table.slice(1).map(function (row) {
10683
+ var paddedRow = row.map(function (subformat, columnIndex) {
10684
+ return subformat.padEnd(columnWidths[columnIndex]);
10685
+ });
10686
+ return "| ".concat(paddedRow.join(' | '), " |");
10687
+ });
10688
+ return __spreadArray([header, separator], __read(rows), false).join('\n');
10689
+ }
10690
+ /**
10691
+ * TODO: [🏛] This can be part of markdown builder
10692
+ */
10693
+
10694
+ /**
10695
+ * Function createMarkdownChart will draw a chart in markdown from ⬛+🟦 tiles
10696
+ *
10697
+ * @public exported from `@promptbook/markdown-utils`
10698
+ */
10699
+ function createMarkdownChart(options) {
10700
+ var e_1, _a;
10701
+ var nameHeader = options.nameHeader, valueHeader = options.valueHeader, items = options.items, width = options.width, unitName = options.unitName;
10702
+ var from = Math.min.apply(Math, __spreadArray([], __read(items.map(function (item) { return item.from; })), false));
10703
+ var to = Math.max.apply(Math, __spreadArray([], __read(items.map(function (item) { return item.to; })), false));
10704
+ var scale = width / (to - from);
10705
+ var table = [[nameHeader, valueHeader]];
10706
+ try {
10707
+ for (var items_1 = __values(items), items_1_1 = items_1.next(); !items_1_1.done; items_1_1 = items_1.next()) {
10708
+ var item = items_1_1.value;
10709
+ var before = Math.round((item.from - from) * scale);
10710
+ var during = Math.round((item.to - item.from) * scale);
10711
+ var after = width - before - during;
10712
+ table.push([removeEmojis(item.title).trim(), '░'.repeat(before) + '█'.repeat(during) + '░'.repeat(after)]);
10713
+ }
10714
+ }
10715
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
10716
+ finally {
10717
+ try {
10718
+ if (items_1_1 && !items_1_1.done && (_a = items_1.return)) _a.call(items_1);
10719
+ }
10720
+ finally { if (e_1) throw e_1.error; }
10721
+ }
10722
+ 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_");
10723
+ return createMarkdownTable(table) + '\n\n' + legend;
10724
+ }
10725
+ /**
10726
+ * TODO: Maybe use Mermain Gant Diagrams
10727
+ * @see https://jojozhuang.github.io/tutorial/mermaid-cheat-sheet/
10728
+ */
10729
+
10730
+ /**
10731
+ * Function escapeMarkdownBlock will escape markdown block if needed
10732
+ * It is useful when you want have block in block
10733
+ *
10734
+ * @public exported from `@promptbook/markdown-utils`
10735
+ */
10736
+ function escapeMarkdownBlock(value) {
10737
+ return value.replace(/```/g, '\\`\\`\\`');
10738
+ }
10739
+ /**
10740
+ * TODO: [🏛] This can be part of markdown builder
10741
+ */
10742
+
10743
+ /**
10744
+ * Default options for generating an execution report string
10745
+ *
10746
+ * @public exported from `@promptbook/core`
10747
+ */
10748
+ var ExecutionReportStringOptionsDefaults = {
10749
+ taxRate: 0,
10750
+ chartsWidth: 36,
10751
+ };
10752
+
10753
+ /**
10754
+ * Count the duration of working time
10755
+ *
10756
+ * @private within the repository
10757
+ */
10758
+ function countWorkingDuration(items) {
10759
+ var e_1, _a;
10760
+ var steps = Array.from(new Set(items.flatMap(function (item) { return [item.from, item.to]; })));
10761
+ steps.sort(function (a, b) { return a - b; });
10762
+ var intervals = steps.map(function (step, index) { return [step, steps[index + 1] || 0]; }).slice(0, -1);
10763
+ var duration = 0;
10764
+ var _loop_1 = function (interval) {
10765
+ var _b = __read(interval, 2), from = _b[0], to = _b[1];
10766
+ if (items.some(function (item) { return item.from < to && item.to > from; })) {
10767
+ duration += to - from;
10768
+ }
10769
+ };
10770
+ try {
10771
+ for (var intervals_1 = __values(intervals), intervals_1_1 = intervals_1.next(); !intervals_1_1.done; intervals_1_1 = intervals_1.next()) {
10772
+ var interval = intervals_1_1.value;
10773
+ _loop_1(interval);
10774
+ }
10775
+ }
10776
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
10777
+ finally {
10778
+ try {
10779
+ if (intervals_1_1 && !intervals_1_1.done && (_a = intervals_1.return)) _a.call(intervals_1);
10780
+ }
10781
+ finally { if (e_1) throw e_1.error; }
10782
+ }
10783
+ return duration;
10784
+ }
10785
+
10786
+ /**
10787
+ * Converts execution report from JSON to string format
10788
+ *
10789
+ * @public exported from `@promptbook/core`
10790
+ */
10791
+ function executionReportJsonToString(executionReportJson, options) {
10792
+ var e_1, _a;
10793
+ var _b, _c, _d, _e, _f, _g;
10794
+ var _h = __assign(__assign({}, ExecutionReportStringOptionsDefaults), (options || {})), taxRate = _h.taxRate, chartsWidth = _h.chartsWidth;
10795
+ var executionReportString = spaceTrim(function (block) { return "\n # ".concat(executionReportJson.title || 'Execution report', "\n\n ").concat(block(executionReportJson.description || ''), "\n "); });
10796
+ var headerList = [];
10797
+ if (executionReportJson.pipelineUrl) {
10798
+ headerList.push("PIPELINE URL ".concat(executionReportJson.pipelineUrl));
10799
+ }
10800
+ headerList.push("PROMPTBOOK VERSION ".concat(executionReportJson.promptbookUsedVersion) +
10801
+ (!executionReportJson.promptbookRequestedVersion
10802
+ ? ''
10803
+ : " *(requested ".concat(executionReportJson.promptbookRequestedVersion, ")*")));
10804
+ if (executionReportJson.promptExecutions.length !== 0) {
10805
+ // TODO: What if startedAt OR/AND completedAt is not defined?
10806
+ var startedAt = moment(Math.min.apply(Math, __spreadArray([], __read(executionReportJson.promptExecutions
10807
+ .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; })
10808
+ .map(function (promptExecution) { return moment(promptExecution.result.timing.start).valueOf(); })), false)));
10809
+ var completedAt = moment(Math.max.apply(Math, __spreadArray([], __read(executionReportJson.promptExecutions
10810
+ .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; })
10811
+ .map(function (promptExecution) { return moment(promptExecution.result.timing.complete).valueOf(); })), false)));
10812
+ var timingItems = executionReportJson.promptExecutions.map(function (promptExecution) {
10813
+ var _a, _b, _c, _d;
10814
+ return ({
10815
+ title: promptExecution.prompt.title,
10816
+ from: moment((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.timing) === null || _b === void 0 ? void 0 : _b.start).valueOf() / 1000,
10817
+ to: moment((_d = (_c = promptExecution.result) === null || _c === void 0 ? void 0 : _c.timing) === null || _d === void 0 ? void 0 : _d.complete).valueOf() / 1000,
10818
+ });
10819
+ });
10820
+ var costItems = executionReportJson.promptExecutions
10821
+ .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'; })
10822
+ .map(function (promptExecution) {
10823
+ var _a, _b;
10824
+ return ({
10825
+ title: promptExecution.prompt.title,
10826
+ from: 0,
10827
+ to: (((_b = (_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.usage) === null || _b === void 0 ? void 0 : _b.price.value) || 0) /* <- TODO: look at uncertain numbers */ *
10828
+ (1 + taxRate),
10829
+ });
10830
+ });
10831
+ var duration = moment.duration(completedAt.diff(startedAt));
10832
+ var llmDuration = moment.duration(countWorkingDuration(timingItems) * 1000);
10833
+ 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'; });
10834
+ var cost = executionsWithKnownCost.reduce(function (cost, promptExecution) {
10835
+ return cost + (promptExecution.result.usage.price.value /* <- Look at uncertain number */ || 0);
10836
+ }, 0);
10837
+ headerList.push("STARTED AT ".concat(moment(startedAt).format("YYYY-MM-DD HH:mm:ss")));
10838
+ headerList.push("COMPLETED AT ".concat(moment(completedAt).format("YYYY-MM-DD HH:mm:ss")));
10839
+ headerList.push("TOTAL DURATION ".concat(duration.humanize(MOMENT_ARG_THRESHOLDS)));
10840
+ headerList.push("TOTAL LLM DURATION ".concat(llmDuration.humanize(MOMENT_ARG_THRESHOLDS)));
10841
+ headerList.push("TOTAL COST $".concat(formatNumber(cost * (1 + taxRate))) +
10842
+ (executionsWithKnownCost.length === executionReportJson.promptExecutions.length
10843
+ ? ''
10844
+ : " *(Some cost is unknown)*") +
10845
+ (taxRate !== 0 ? " *(with tax ".concat(taxRate * 100, "%)*") : ''));
10846
+ executionReportString += '\n\n' + headerList.map(function (header) { return "- ".concat(header); }).join('\n');
10847
+ executionReportString +=
10848
+ '\n\n' +
10849
+ '## 🗃 Index' +
10850
+ '\n\n' +
10851
+ executionReportJson.promptExecutions
10852
+ .map(function (promptExecution) {
10853
+ // TODO: Make some better system to convert hedings to links
10854
+ var hash = normalizeToKebabCase(promptExecution.prompt.title);
10855
+ if (/^\s*\p{Extended_Pictographic}/u.test(promptExecution.prompt.title)) {
10856
+ hash = '-' + hash;
10857
+ }
10858
+ // TODO: Make working hash link for the template in md + pdf
10859
+ return "- [".concat(promptExecution.prompt.title, "](#").concat(hash, ")");
10860
+ })
10861
+ .join('\n');
10862
+ executionReportString +=
10863
+ '\n\n' +
10864
+ '## ⌚ Time chart' +
10865
+ '\n\n' +
10866
+ createMarkdownChart({
10867
+ nameHeader: 'Template',
10868
+ valueHeader: 'Timeline',
10869
+ items: timingItems,
10870
+ width: chartsWidth,
10871
+ unitName: 'seconds',
10872
+ });
10873
+ executionReportString +=
10874
+ '\n\n' +
10875
+ '## 💸 Cost chart' +
10876
+ '\n\n' +
10877
+ createMarkdownChart({
10878
+ nameHeader: 'Template',
10879
+ valueHeader: 'Cost',
10880
+ items: costItems,
10881
+ width: chartsWidth,
10882
+ unitName: 'USD',
10883
+ });
10884
+ }
10885
+ else {
10886
+ headerList.push("TOTAL COST $0 *(Nothing executed)*");
10887
+ }
10888
+ var _loop_1 = function (promptExecution) {
10889
+ executionReportString += '\n\n\n\n' + "## ".concat(promptExecution.prompt.title);
10890
+ var templateList = [];
10891
+ // TODO: What if startedAt OR/AND completedAt is not defined?
10892
+ var startedAt = moment((_c = (_b = promptExecution.result) === null || _b === void 0 ? void 0 : _b.timing) === null || _c === void 0 ? void 0 : _c.start);
10893
+ var completedAt = moment((_e = (_d = promptExecution.result) === null || _d === void 0 ? void 0 : _d.timing) === null || _e === void 0 ? void 0 : _e.complete);
10894
+ var duration = moment.duration(completedAt.diff(startedAt));
10895
+ // Not need here:
10896
+ // > templateList.push(`STARTED AT ${moment(startedAt).calendar()}`);
10897
+ templateList.push("DURATION ".concat(duration.humanize(MOMENT_ARG_THRESHOLDS)));
10898
+ if (typeof ((_g = (_f = promptExecution.result) === null || _f === void 0 ? void 0 : _f.usage) === null || _g === void 0 ? void 0 : _g.price) === 'number') {
10899
+ templateList.push("COST $".concat(formatNumber(promptExecution.result.usage.price * (1 + taxRate))) +
10900
+ (taxRate !== 0 ? " *(with tax ".concat(taxRate * 100, "%)*") : ''));
10901
+ }
10902
+ else {
10903
+ templateList.push("COST UNKNOWN");
10904
+ }
10905
+ executionReportString += '\n\n' + templateList.map(function (header) { return "- ".concat(header); }).join('\n');
10906
+ /*
10907
+ - MODEL VARIANT ${promptExecution.prompt.modelRequirements.modelVariant}
10908
+ - MODEL NAME \`${promptExecution.result?.model}\` (requested \`${
10909
+ promptExecution.prompt.modelRequirements.modelName
10910
+
10911
+ */
10912
+ if (just(true)) {
10913
+ executionReportString +=
10914
+ '\n\n\n\n' +
10915
+ spaceTrim(function (block) {
10916
+ var _a;
10917
+ return "\n\n ### Prompt\n\n ```\n ".concat(block(escapeMarkdownBlock(((_a = promptExecution.result) === null || _a === void 0 ? void 0 : _a.rawPromptContent) || promptExecution.prompt.content)), "\n ```\n\n ");
10918
+ });
10919
+ }
10920
+ if (promptExecution.result && promptExecution.result.content) {
10921
+ executionReportString += '\n\n\n\n' + '### Result' + '\n\n';
10922
+ if (promptExecution.result === undefined) {
10923
+ executionReportString += '*No result*';
10924
+ }
10925
+ else if (typeof promptExecution.result.content === 'string') {
10926
+ executionReportString += spaceTrim(function (block) { return "\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.result.content)), "\n ```\n "); });
10927
+ }
10928
+ else {
10929
+ executionReportString += embeddingVectorToString(promptExecution.result.content);
10930
+ }
10931
+ }
10932
+ if (promptExecution.error && promptExecution.error.message) {
10933
+ executionReportString +=
10934
+ '\n\n\n\n' +
10935
+ spaceTrim(function (block) { return "\n\n ### Error\n\n ```\n ".concat(block(escapeMarkdownBlock(promptExecution.error.message)), "\n ```\n\n "); });
10936
+ }
10937
+ };
10938
+ try {
10939
+ for (var _j = __values(executionReportJson.promptExecutions), _k = _j.next(); !_k.done; _k = _j.next()) {
10940
+ var promptExecution = _k.value;
10941
+ _loop_1(promptExecution);
10942
+ }
10943
+ }
10944
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
10945
+ finally {
10946
+ try {
10947
+ if (_k && !_k.done && (_a = _j.return)) _a.call(_j);
10948
+ }
10949
+ finally { if (e_1) throw e_1.error; }
10950
+ }
10951
+ executionReportString = prettifyMarkdown(executionReportString);
10952
+ return executionReportString;
10953
+ }
10954
+ /**
10955
+ * TODO: Add mermaid chart for every report
10956
+ * TODO: [🧠] Allow to filter out some parts of the report by options
10957
+ * TODO: [🧠] Should be in generated file GENERATOR_WARNING
10958
+ */
10959
+
10623
10960
  /**
10624
10961
  * Initializes `run` command for Promptbook CLI utilities
10625
10962
  *
@@ -10627,126 +10964,240 @@ function initializePrettifyCommand(program) {
10627
10964
  */
10628
10965
  function initializeRunCommand(program) {
10629
10966
  var _this = this;
10630
- var runCommand = program.command('run');
10967
+ var runCommand = program.command('run', { isDefault: true });
10631
10968
  runCommand.description(spaceTrim$1("\n Runs a pipeline\n "));
10632
10969
  // TODO: [🧅] DRY command arguments
10633
10970
  runCommand.argument('<path>',
10634
10971
  // <- Note: [🧟‍♂️] This is NOT promptbook collection directory BUT direct path to .ptbk.md file
10635
- 'Path to `.ptbk.md` file');
10636
- runCommand.option('--reload', "Call LLM models even if same prompt with result is in the cache", false);
10637
- runCommand.option('--verbose', "Is output verbose", false);
10638
- runCommand.action(function (path, _a) {
10639
- var isCacheReloaded = _a.reload, isVerbose = _a.verbose;
10640
- return __awaiter(_this, void 0, void 0, function () {
10641
- var options, fs, llm, executables, tools, pipelineString, pipeline, questions, response, inputParameters, pipelineExecutor, result, isSuccessful, errors, outputParameters, executionReport, _b, _c, key, value, separator;
10642
- var _d, e_1, _e;
10643
- return __generator(this, function (_f) {
10644
- switch (_f.label) {
10645
- case 0:
10646
- options = {
10647
- isVerbose: isVerbose,
10648
- isCacheReloaded: isCacheReloaded,
10649
- };
10650
- fs = $provideFilesystemForNode(options);
10651
- try {
10652
- llm = $provideLlmToolsForCli(options);
10972
+ 'Path to book file');
10973
+ runCommand.option('-r, --reload', "Call LLM models even if same prompt with result is in the cache", false);
10974
+ runCommand.option('-v, --verbose', "Is output verbose", false);
10975
+ runCommand.option('--no-interactive', "Input is not interactive", false);
10976
+ runCommand.option('-s, --save-report <path>', "Save report to file");
10977
+ // TODO: !!!!!! Interactive mode
10978
+ // TODO: !!!!!! JSON output
10979
+ runCommand.action(function (filePathRaw, options) { return __awaiter(_this, void 0, void 0, function () {
10980
+ var isCacheReloaded, isVerbose, saveReport, prepareAndScrapeOptions, fs, filePath, filePathCandidates, filePathCandidates_1, filePathCandidates_1_1, filePathCandidate, e_1_1, llm, executables, tools, pipelineString, pipeline, pipelineExecutor, questions, response, inputParameters, result, isSuccessful, errors, warnings, outputParameters, executionReport, executionReportString, _a, _b, error, _c, _d, warning, _e, _f, key, value, separator;
10981
+ var e_1, _g, _h, e_2, _j, e_3, _k, e_4, _l;
10982
+ return __generator(this, function (_m) {
10983
+ switch (_m.label) {
10984
+ case 0:
10985
+ isCacheReloaded = options.reload, options.interactive, isVerbose = options.verbose, saveReport = options.saveReport;
10986
+ if (saveReport && !saveReport.endsWith('.json') && !saveReport.endsWith('.md')) {
10987
+ console.error(colors.red("Report file must be .json or .md"));
10988
+ return [2 /*return*/, process.exit(1)];
10989
+ }
10990
+ prepareAndScrapeOptions = {
10991
+ isVerbose: isVerbose,
10992
+ isCacheReloaded: isCacheReloaded,
10993
+ };
10994
+ if (isVerbose) {
10995
+ console.info(colors.gray('--- Preparing tools ---'));
10996
+ }
10997
+ fs = $provideFilesystemForNode(prepareAndScrapeOptions);
10998
+ filePath = null;
10999
+ filePathCandidates = [
11000
+ filePathRaw,
11001
+ "".concat(filePathRaw, ".md"),
11002
+ "".concat(filePathRaw, ".book.md"),
11003
+ "".concat(filePathRaw, ".ptbk.md"),
11004
+ ];
11005
+ _m.label = 1;
11006
+ case 1:
11007
+ _m.trys.push([1, 6, 7, 8]);
11008
+ filePathCandidates_1 = __values(filePathCandidates), filePathCandidates_1_1 = filePathCandidates_1.next();
11009
+ _m.label = 2;
11010
+ case 2:
11011
+ if (!!filePathCandidates_1_1.done) return [3 /*break*/, 5];
11012
+ filePathCandidate = filePathCandidates_1_1.value;
11013
+ return [4 /*yield*/, isFileExisting(filePathCandidate, fs)
11014
+ // <- TODO: Also test that among the candidates the file is book not just any file
11015
+ ];
11016
+ case 3:
11017
+ if (_m.sent()
11018
+ // <- TODO: Also test that among the candidates the file is book not just any file
11019
+ ) {
11020
+ filePath = filePathCandidate;
11021
+ return [3 /*break*/, 5];
11022
+ }
11023
+ _m.label = 4;
11024
+ case 4:
11025
+ filePathCandidates_1_1 = filePathCandidates_1.next();
11026
+ return [3 /*break*/, 2];
11027
+ case 5: return [3 /*break*/, 8];
11028
+ case 6:
11029
+ e_1_1 = _m.sent();
11030
+ e_1 = { error: e_1_1 };
11031
+ return [3 /*break*/, 8];
11032
+ case 7:
11033
+ try {
11034
+ if (filePathCandidates_1_1 && !filePathCandidates_1_1.done && (_g = filePathCandidates_1.return)) _g.call(filePathCandidates_1);
11035
+ }
11036
+ finally { if (e_1) throw e_1.error; }
11037
+ return [7 /*endfinally*/];
11038
+ case 8:
11039
+ if (filePath === null) {
11040
+ console.error(colors.red("File \"".concat(filePathRaw, "\" does not exist")));
11041
+ return [2 /*return*/, process.exit(1)];
11042
+ }
11043
+ try {
11044
+ llm = $provideLlmToolsForCli(prepareAndScrapeOptions);
11045
+ }
11046
+ catch (error) {
11047
+ if (!(error instanceof Error)) {
11048
+ throw error;
10653
11049
  }
10654
- catch (error) {
10655
- if (!(error instanceof Error)) {
10656
- throw error;
10657
- }
10658
- if (!error.message.includes('No LLM tools')) {
10659
- throw error;
11050
+ if (!error.message.includes('No LLM tools')) {
11051
+ throw error;
11052
+ }
11053
+ console.error(colors.red(spaceTrim$1("\n You need to configure LLM tools first\n\n 1) Create .env file\n 2) Add OPENAI_API_KEY=...\n 3) *(and/or)* Add ANTHROPIC_CLAUDE_API_KEY=...\n ")));
11054
+ return [2 /*return*/, process.exit(1)];
11055
+ }
11056
+ return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
11057
+ case 9:
11058
+ executables = _m.sent();
11059
+ _h = {
11060
+ llm: llm,
11061
+ fs: fs
11062
+ };
11063
+ return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, prepareAndScrapeOptions)];
11064
+ case 10:
11065
+ tools = (_h.scrapers = _m.sent(),
11066
+ _h.script = [
11067
+ /*new JavascriptExecutionTools(options)*/
11068
+ ],
11069
+ _h);
11070
+ if (isVerbose) {
11071
+ console.info(colors.gray('--- Reading file ---'));
11072
+ }
11073
+ return [4 /*yield*/, readFile(filePath, 'utf-8')];
11074
+ case 11:
11075
+ pipelineString = (_m.sent());
11076
+ if (isVerbose) {
11077
+ console.info(colors.gray('--- Preparing pipeline ---'));
11078
+ }
11079
+ return [4 /*yield*/, pipelineStringToJson(pipelineString, tools)];
11080
+ case 12:
11081
+ pipeline = _m.sent();
11082
+ if (isVerbose) {
11083
+ console.info(colors.gray('--- Validating pipeline ---'));
11084
+ }
11085
+ validatePipeline(pipeline);
11086
+ if (isVerbose) {
11087
+ console.info(colors.gray('--- Creating executor ---'));
11088
+ }
11089
+ pipelineExecutor = createPipelineExecutor({
11090
+ pipeline: pipeline,
11091
+ tools: tools,
11092
+ isNotPreparedWarningSupressed: true,
11093
+ maxExecutionAttempts: 3,
11094
+ // <- TODO: !!!!!! Why "LLM execution failed undefinedx"
11095
+ maxParallelCount: 1, // <- TODO: !!!!!! Pass
11096
+ });
11097
+ if (isVerbose) {
11098
+ console.info(colors.gray('--- Getting input parameters ---'));
11099
+ }
11100
+ questions = pipeline.parameters
11101
+ .filter(function (_a) {
11102
+ var isInput = _a.isInput;
11103
+ return isInput;
11104
+ })
11105
+ .map(function (_a) {
11106
+ var name = _a.name;
11107
+ return ({
11108
+ type: 'text',
11109
+ name: name,
11110
+ message: name,
11111
+ // TODO: Maybe use> validate: value => value < 18 ? `Forbidden` : true
11112
+ });
11113
+ });
11114
+ return [4 /*yield*/, prompts(questions)];
11115
+ case 13:
11116
+ response = _m.sent();
11117
+ inputParameters = response;
11118
+ if (isVerbose) {
11119
+ console.info(colors.gray('--- Executing ---'));
11120
+ }
11121
+ return [4 /*yield*/, pipelineExecutor(inputParameters, function (taskProgress) {
11122
+ if (isVerbose) {
11123
+ console.info(colors.gray('--- Progress ---'));
11124
+ console.info(taskProgress);
10660
11125
  }
10661
- console.error(colors.red(spaceTrim$1("\n You need to configure LLM tools first\n\n 1) Create .env file\n 2) Add OPENAI_API_KEY=...\n 3) *(and/or)* Add ANTHROPIC_CLAUDE_API_KEY=...\n ")));
10662
- return [2 /*return*/, process.exit(1)];
11126
+ })];
11127
+ case 14:
11128
+ result = _m.sent();
11129
+ isSuccessful = result.isSuccessful, errors = result.errors, warnings = result.warnings, outputParameters = result.outputParameters, executionReport = result.executionReport;
11130
+ if (isVerbose) {
11131
+ console.info(colors.gray('--- Detailed Result ---'));
11132
+ console.info({ isSuccessful: isSuccessful, errors: errors, warnings: warnings, outputParameters: outputParameters, executionReport: executionReport });
11133
+ }
11134
+ if (!(saveReport && saveReport.endsWith('.json'))) return [3 /*break*/, 16];
11135
+ return [4 /*yield*/, writeFile(saveReport, JSON.stringify(executionReport, null, 4) + '\n', 'utf-8')];
11136
+ case 15:
11137
+ _m.sent();
11138
+ return [3 /*break*/, 18];
11139
+ case 16:
11140
+ if (!(saveReport && saveReport.endsWith('.md'))) return [3 /*break*/, 18];
11141
+ executionReportString = executionReportJsonToString(executionReport);
11142
+ return [4 /*yield*/, writeFile(saveReport, executionReportString, 'utf-8')];
11143
+ case 17:
11144
+ _m.sent();
11145
+ _m.label = 18;
11146
+ case 18:
11147
+ if (saveReport && isVerbose) {
11148
+ console.info(colors.green("Report saved to ".concat(saveReport)));
11149
+ }
11150
+ if (isVerbose) {
11151
+ console.info(colors.gray('--- Usage ---'));
11152
+ console.info(colors.cyan(usageToHuman(result.usage)));
11153
+ }
11154
+ console.info(colors.gray('--- Result ---'));
11155
+ try {
11156
+ // TODO: [🧠] Should be errors or warnings shown first
11157
+ for (_a = __values(errors || []), _b = _a.next(); !_b.done; _b = _a.next()) {
11158
+ error = _b.value;
11159
+ console.error(colors.red(colors.bold(error.name) + ': ' + error.message));
10663
11160
  }
10664
- return [4 /*yield*/, $provideExecutablesForNode(options)];
10665
- case 1:
10666
- executables = _f.sent();
10667
- _d = {
10668
- llm: llm,
10669
- fs: fs
10670
- };
10671
- return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, options)];
10672
- case 2:
10673
- tools = (_d.scrapers = _f.sent(),
10674
- _d.script = [
10675
- /*new JavascriptExecutionTools(options)*/
10676
- ],
10677
- _d);
10678
- return [4 /*yield*/, isFileExisting(path, fs)];
10679
- case 3:
10680
- if (!(_f.sent())) {
10681
- console.error(colors.red("File \"".concat(path, "\" does not exist")));
10682
- return [2 /*return*/, process.exit(1)];
11161
+ }
11162
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
11163
+ finally {
11164
+ try {
11165
+ if (_b && !_b.done && (_j = _a.return)) _j.call(_a);
10683
11166
  }
10684
- return [4 /*yield*/, fs.readFile(path, 'utf-8')];
10685
- case 4:
10686
- pipelineString = (_f.sent());
10687
- return [4 /*yield*/, pipelineStringToJson(pipelineString, tools)];
10688
- case 5:
10689
- pipeline = _f.sent();
10690
- validatePipeline(pipeline);
10691
- questions = pipeline.parameters
10692
- .filter(function (_a) {
10693
- var isInput = _a.isInput;
10694
- return isInput;
10695
- })
10696
- .map(function (_a) {
10697
- var name = _a.name;
10698
- return ({
10699
- type: 'text',
10700
- name: name,
10701
- message: name,
10702
- // TODO: Maybe use> validate: value => value < 18 ? `Forbidden` : true
10703
- });
10704
- });
10705
- return [4 /*yield*/, prompts(questions)];
10706
- case 6:
10707
- response = _f.sent();
10708
- inputParameters = response;
10709
- // console.log(response);
10710
- return [4 /*yield*/, forTime(100)];
10711
- case 7:
10712
- // console.log(response);
10713
- _f.sent();
10714
- pipelineExecutor = createPipelineExecutor({ pipeline: pipeline, tools: tools, isNotPreparedWarningSupressed: true });
10715
- return [4 /*yield*/, pipelineExecutor(inputParameters, function (taskProgress) {
10716
- if (isVerbose) {
10717
- // TODO: !!!!!!! Pretty print taskProgress
10718
- console.log(taskProgress);
10719
- }
10720
- })];
10721
- case 8:
10722
- result = _f.sent();
10723
- isSuccessful = result.isSuccessful, errors = result.errors, outputParameters = result.outputParameters, executionReport = result.executionReport;
10724
- if (isVerbose) {
10725
- // TODO: !!!!!!! Pretty print
10726
- console.log({ isSuccessful: isSuccessful, errors: errors, outputParameters: outputParameters, executionReport: executionReport });
10727
- console.log(outputParameters);
11167
+ finally { if (e_2) throw e_2.error; }
11168
+ }
11169
+ try {
11170
+ for (_c = __values(warnings || []), _d = _c.next(); !_d.done; _d = _c.next()) {
11171
+ warning = _d.value;
11172
+ console.error(colors.red(colors.bold(warning.name) + ': ' + warning.message));
10728
11173
  }
10729
- console.info(colors.gray('--- Result: ---'));
11174
+ }
11175
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
11176
+ finally {
10730
11177
  try {
10731
- for (_b = __values(Object.keys(outputParameters)), _c = _b.next(); !_c.done; _c = _b.next()) {
10732
- key = _c.value;
10733
- value = outputParameters[key] || colors.grey(colors.italic('(nothing)'));
10734
- separator = countLines(value) > 1 || countWords(value) > 100 ? ':\n' : ': ';
10735
- console.info(colors.green(colors.bold(key) + separator + value));
10736
- }
11178
+ if (_d && !_d.done && (_k = _c.return)) _k.call(_c);
10737
11179
  }
10738
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
10739
- finally {
10740
- try {
10741
- if (_c && !_c.done && (_e = _b.return)) _e.call(_b);
10742
- }
10743
- finally { if (e_1) throw e_1.error; }
11180
+ finally { if (e_3) throw e_3.error; }
11181
+ }
11182
+ try {
11183
+ for (_e = __values(Object.keys(outputParameters)), _f = _e.next(); !_f.done; _f = _e.next()) {
11184
+ key = _f.value;
11185
+ value = outputParameters[key] || colors.grey(colors.italic('(nothing)'));
11186
+ separator = countLines(value) > 1 || countWords(value) > 100 ? ':\n' : ': ';
11187
+ console.info(colors.green(colors.bold(key) + separator + value));
10744
11188
  }
10745
- return [2 /*return*/, process.exit(0)];
10746
- }
10747
- });
11189
+ }
11190
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
11191
+ finally {
11192
+ try {
11193
+ if (_f && !_f.done && (_l = _e.return)) _l.call(_e);
11194
+ }
11195
+ finally { if (e_4) throw e_4.error; }
11196
+ }
11197
+ return [2 /*return*/, process.exit(0)];
11198
+ }
10748
11199
  });
10749
- });
11200
+ }); });
10750
11201
  }
10751
11202
  /**
10752
11203
  * TODO: !!!!!! Catch and wrap all errors from CLI
@@ -10769,30 +11220,30 @@ function initializeTestCommand(program) {
10769
11220
  // <- TODO: [🧟‍♂️] Unite path to promptbook collection argument
10770
11221
  'Pipelines to test as glob pattern');
10771
11222
  testCommand.option('-i, --ignore <glob>', "Ignore as glob pattern");
10772
- testCommand.option('--reload', "Call LLM models even if same prompt with result is in the cache ", false);
11223
+ testCommand.option('-r, --reload', "Call LLM models even if same prompt with result is in the cache ", false);
10773
11224
  testCommand.option('-v, --verbose', "Is output verbose", false);
10774
11225
  testCommand.action(function (filesGlob, _a) {
10775
11226
  var ignore = _a.ignore, isCacheReloaded = _a.reload, isVerbose = _a.verbose;
10776
11227
  return __awaiter(_this, void 0, void 0, function () {
10777
- var options, fs, llm, executables, tools, filenames, filenames_1, filenames_1_1, filename, pipeline, pipelineMarkdown, _b, _c, error_1, e_1_1;
11228
+ var prepareAndScrapeOptions, fs, llm, executables, tools, filenames, filenames_1, filenames_1_1, filename, pipeline, pipelineMarkdown, _b, _c, error_1, e_1_1;
10778
11229
  var _d, e_1, _e;
10779
11230
  return __generator(this, function (_f) {
10780
11231
  switch (_f.label) {
10781
11232
  case 0:
10782
- options = {
11233
+ prepareAndScrapeOptions = {
10783
11234
  isVerbose: isVerbose,
10784
11235
  isCacheReloaded: isCacheReloaded,
10785
11236
  };
10786
- fs = $provideFilesystemForNode(options);
10787
- llm = $provideLlmToolsForCli(options);
10788
- return [4 /*yield*/, $provideExecutablesForNode(options)];
11237
+ fs = $provideFilesystemForNode(prepareAndScrapeOptions);
11238
+ llm = $provideLlmToolsForCli(prepareAndScrapeOptions);
11239
+ return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
10789
11240
  case 1:
10790
11241
  executables = _f.sent();
10791
11242
  _d = {
10792
11243
  llm: llm,
10793
11244
  fs: fs
10794
11245
  };
10795
- return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, options)];
11246
+ return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, prepareAndScrapeOptions)];
10796
11247
  case 2:
10797
11248
  tools = (_d.scrapers = _f.sent(),
10798
11249
  _d.script = [
@@ -10895,7 +11346,7 @@ function promptbookCli() {
10895
11346
  program.name('promptbook');
10896
11347
  program.alias('ptbk');
10897
11348
  program.version(PROMPTBOOK_ENGINE_VERSION);
10898
- program.description(spaceTrim("\n Promptbook utilities for enhancing workflow with promptbooks\n "));
11349
+ program.description(CLAIM);
10899
11350
  initializeAboutCommand(program);
10900
11351
  initializeRunCommand(program);
10901
11352
  initializeHelloCommand(program);