@promptbook/core 0.44.0-1 โ†’ 0.44.0-11

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 (31) hide show
  1. package/esm/index.es.js +940 -756
  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 +3 -2
  5. package/esm/typings/config.d.ts +4 -0
  6. package/esm/typings/execution/plugins/natural-execution-tools/mocked/MockedEchoNaturalExecutionTools.d.ts +1 -1
  7. package/esm/typings/execution/plugins/natural-execution-tools/mocked/MockedFackedNaturalExecutionTools.d.ts +19 -0
  8. package/esm/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.d.ts +15 -0
  9. package/esm/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.test.d.ts +1 -0
  10. package/esm/typings/execution/plugins/natural-execution-tools/mocked/faked-completion.test.d.ts +1 -0
  11. package/esm/typings/execution/plugins/script-execution-tools/javascript/JavascriptExecutionToolsOptions.d.ts +5 -1
  12. package/esm/typings/execution/utils/checkExpectations.d.ts +25 -0
  13. package/esm/typings/execution/utils/checkExpectations.test.d.ts +1 -0
  14. package/esm/typings/types/Prompt.d.ts +13 -0
  15. package/esm/typings/types/PromptbookJson/PromptTemplateJson.d.ts +14 -4
  16. package/package.json +2 -1
  17. package/umd/index.umd.js +983 -803
  18. package/umd/index.umd.js.map +1 -1
  19. package/umd/typings/_packages/core.index.d.ts +2 -1
  20. package/umd/typings/_packages/utils.index.d.ts +3 -2
  21. package/umd/typings/config.d.ts +4 -0
  22. package/umd/typings/execution/plugins/natural-execution-tools/mocked/MockedEchoNaturalExecutionTools.d.ts +1 -1
  23. package/umd/typings/execution/plugins/natural-execution-tools/mocked/MockedFackedNaturalExecutionTools.d.ts +19 -0
  24. package/umd/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.d.ts +15 -0
  25. package/umd/typings/execution/plugins/natural-execution-tools/mocked/fakeTextToExpectations.test.d.ts +1 -0
  26. package/umd/typings/execution/plugins/natural-execution-tools/mocked/faked-completion.test.d.ts +1 -0
  27. package/umd/typings/execution/plugins/script-execution-tools/javascript/JavascriptExecutionToolsOptions.d.ts +5 -1
  28. package/umd/typings/execution/utils/checkExpectations.d.ts +25 -0
  29. package/umd/typings/execution/utils/checkExpectations.test.d.ts +1 -0
  30. package/umd/typings/types/Prompt.d.ts +13 -0
  31. package/umd/typings/types/PromptbookJson/PromptTemplateJson.d.ts +14 -4
package/esm/index.es.js CHANGED
@@ -1,7 +1,8 @@
1
- import spaceTrim from 'spacetrim';
1
+ import { spaceTrim } from 'spacetrim';
2
2
  import 'prettier';
3
3
  import 'prettier/parser-html';
4
4
  import 'moment';
5
+ import { LoremIpsum } from 'lorem-ipsum';
5
6
 
6
7
  /*! *****************************************************************************
7
8
  Copyright (c) Microsoft Corporation.
@@ -122,6 +123,30 @@ function __spreadArray(to, from, pack) {
122
123
  return to.concat(ar || Array.prototype.slice.call(from));
123
124
  }
124
125
 
126
+ /**
127
+ * This error type indicates that the error should not happen and its last check before crashing with some other error
128
+ */
129
+ var UnexpectedError = /** @class */ (function (_super) {
130
+ __extends(UnexpectedError, _super);
131
+ function UnexpectedError(message) {
132
+ var _this = _super.call(this, spaceTrim(function (block) { return "\n ".concat(block(message), "\n\n Note: This error should not happen.\n It's probbably a bug in the promptbook library\n\n Please report issue:\n https://github.com/webgptorg/promptbook/issues\n\n Or contact us on me@pavolhejny.com\n\n "); })) || this;
133
+ _this.name = 'UnexpectedError';
134
+ Object.setPrototypeOf(_this, UnexpectedError.prototype);
135
+ return _this;
136
+ }
137
+ return UnexpectedError;
138
+ }(Error));
139
+
140
+ /**
141
+ * Removes HTML or Markdown comments from a string.
142
+ *
143
+ * @param {string} content - The string to remove comments from.
144
+ * @returns {string} The input string with all comments removed.
145
+ */
146
+ function removeContentComments(content) {
147
+ return spaceTrim(content.replace(/<!--(.*?)-->/gs, ''));
148
+ }
149
+
125
150
  /**
126
151
  * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
127
152
  */
@@ -137,604 +162,154 @@ var PromptbookSyntaxError = /** @class */ (function (_super) {
137
162
  }(Error));
138
163
 
139
164
  /**
140
- * Supported script languages
141
- */
142
- var SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
143
-
144
- /**
145
- * Parses the template and returns the list of all parameter names
165
+ * Function parseNumber will parse number from string
146
166
  *
147
- * @param template the template with parameters in {curly} braces
148
- * @returns the list of parameter names
167
+ * Unlike Number.parseInt, Number.parseFloat it will never ever result in NaN
168
+ * Note: it also works only with decimal numbers
149
169
  *
150
- * @private within the library
170
+ * @returns parsed number
171
+ * @throws {PromptbookSyntaxError} if the value is not a number
172
+ *
173
+ * @private within the parseCommand
151
174
  */
152
- function extractParameters(template) {
153
- var e_1, _a;
154
- var matches = template.matchAll(/{\w+}/g);
155
- var parameterNames = [];
156
- try {
157
- for (var matches_1 = __values(matches), matches_1_1 = matches_1.next(); !matches_1_1.done; matches_1_1 = matches_1.next()) {
158
- var match = matches_1_1.value;
159
- var parameterName = match[0].slice(1, -1);
160
- if (!parameterNames.includes(parameterName)) {
161
- parameterNames.push(parameterName);
162
- }
163
- }
175
+ function parseNumber(value) {
176
+ var originalValue = value;
177
+ if (typeof value === 'number') {
178
+ value = value.toString(); // <- TODO: Maybe more efficient way to do this
164
179
  }
165
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
166
- finally {
167
- try {
168
- if (matches_1_1 && !matches_1_1.done && (_a = matches_1.return)) _a.call(matches_1);
169
- }
170
- finally { if (e_1) throw e_1.error; }
180
+ if (typeof value !== 'string') {
181
+ return 0;
171
182
  }
172
- return parameterNames;
173
- }
174
-
175
- /**
176
- * Computes the deepness of the markdown structure.
177
- *
178
- * @private within the library
179
- */
180
- function countMarkdownStructureDeepness(markdownStructure) {
181
- var e_1, _a;
182
- var maxDeepness = 0;
183
- try {
184
- for (var _b = __values(markdownStructure.sections), _c = _b.next(); !_c.done; _c = _b.next()) {
185
- var section = _c.value;
186
- maxDeepness = Math.max(maxDeepness, countMarkdownStructureDeepness(section));
183
+ value = value.trim();
184
+ if (value.startsWith('+')) {
185
+ return parseNumber(value.substring(1));
186
+ }
187
+ if (value.startsWith('-')) {
188
+ var number = parseNumber(value.substring(1));
189
+ if (number === 0) {
190
+ return 0; // <- Note: To prevent -0
187
191
  }
192
+ return -number;
188
193
  }
189
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
190
- finally {
191
- try {
192
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
194
+ value = value.replace(/,/g, '.');
195
+ value = value.toUpperCase();
196
+ if (value === '') {
197
+ return 0;
198
+ }
199
+ if (value === 'โ™พ' || value.startsWith('INF')) {
200
+ return Infinity;
201
+ }
202
+ if (value.includes('/')) {
203
+ var _a = __read(value.split('/'), 2), numerator_ = _a[0], denominator_ = _a[1];
204
+ var numerator = parseNumber(numerator_);
205
+ var denominator = parseNumber(denominator_);
206
+ if (denominator === 0) {
207
+ throw new PromptbookSyntaxError("Unable to parse number from \"".concat(originalValue, "\" because denominator is zero"));
193
208
  }
194
- finally { if (e_1) throw e_1.error; }
209
+ return numerator / denominator;
195
210
  }
196
- return maxDeepness + 1;
211
+ if (/^(NAN|NULL|NONE|UNDEFINED|ZERO|NO.*)$/.test(value)) {
212
+ return 0;
213
+ }
214
+ if (value.includes('E')) {
215
+ var _b = __read(value.split('E'), 2), significand = _b[0], exponent = _b[1];
216
+ return parseNumber(significand) * Math.pow(10, parseNumber(exponent));
217
+ }
218
+ if (!/^[0-9.]+$/.test(value) || value.split('.').length > 2) {
219
+ throw new PromptbookSyntaxError("Unable to parse number from \"".concat(originalValue, "\""));
220
+ }
221
+ var num = parseFloat(value);
222
+ if (isNaN(num)) {
223
+ throw new PromptbookSyntaxError("Unexpected NaN when parsing number from \"".concat(originalValue, "\""));
224
+ }
225
+ return num;
197
226
  }
198
-
199
227
  /**
200
- * The maximum number of iterations for a loops
228
+ * TODO: Maybe use sth. like safe-eval in fraction/calculation case @see https://www.npmjs.com/package/safe-eval
201
229
  */
202
- var LOOP_LIMIT = 1000;
203
230
 
204
231
  /**
205
- * This error type indicates that the error should not happen and its last check before crashing with some other error
232
+ * This error indicates errors during the execution of the promptbook
206
233
  */
207
- var UnexpectedError = /** @class */ (function (_super) {
208
- __extends(UnexpectedError, _super);
209
- function UnexpectedError(message) {
210
- var _this = _super.call(this, spaceTrim(function (block) { return "\n ".concat(block(message), "\n\n Note: This error should not happen.\n It's probbably a bug in the promptbook library\n\n Please report issue:\n https://github.com/webgptorg/promptbook/issues\n\n Or contact us on me@pavolhejny.com\n\n "); })) || this;
211
- _this.name = 'UnexpectedError';
212
- Object.setPrototypeOf(_this, UnexpectedError.prototype);
234
+ var PromptbookExecutionError = /** @class */ (function (_super) {
235
+ __extends(PromptbookExecutionError, _super);
236
+ function PromptbookExecutionError(message) {
237
+ var _this = _super.call(this, message) || this;
238
+ _this.name = 'PromptbookExecutionError';
239
+ Object.setPrototypeOf(_this, PromptbookExecutionError.prototype);
213
240
  return _this;
214
241
  }
215
- return UnexpectedError;
242
+ return PromptbookExecutionError;
216
243
  }(Error));
217
244
 
218
245
  /**
219
- * Parse a markdown string into a MarkdownStructure object.
220
- *
221
- * Note: This function does work with code blocks
222
- * Note: This function does not work with markdown comments
223
- *
224
- * @param markdown The markdown string to parse.
225
- * @returns The MarkdownStructure object.
246
+ * This error occurs when some expectation is not met in the execution of the pipeline
226
247
  *
227
- * @private within the library
248
+ * @private Always catched and rethrown as `PromptbookExecutionError`
249
+ * Note: This is a kindof subtype of PromptbookExecutionError
228
250
  */
229
- function markdownToMarkdownStructure(markdown) {
230
- var e_1, _a;
231
- var lines = markdown.split('\n');
232
- var root = { level: 0, title: '', contentLines: [], sections: [], parent: null };
233
- var current = root;
234
- var isInsideCodeBlock = false;
235
- try {
236
- for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
237
- var line = lines_1_1.value;
238
- var headingMatch = line.match(/^(?<mark>#{1,6})\s(?<title>.*)/);
239
- if (isInsideCodeBlock || !headingMatch) {
240
- if (line.startsWith('```')) {
241
- isInsideCodeBlock = !isInsideCodeBlock;
242
- }
243
- current.contentLines.push(line);
244
- }
245
- else {
246
- var level = headingMatch.groups.mark.length;
247
- var title = headingMatch.groups.title.trim();
248
- var parent_1 = void 0;
249
- if (level > current.level) {
250
- // Note: Going deeper (next section is child of current)
251
- parent_1 = current;
252
- }
253
- else {
254
- // Note: Going up or staying at the same level (next section is sibling or parent or grandparent,... of current)
255
- parent_1 = current;
256
- var loopLimit = LOOP_LIMIT;
257
- while (parent_1.level !== level - 1) {
258
- if (loopLimit-- < 0) {
259
- throw new UnexpectedError('Loop limit reached during parsing of markdown structure in `markdownToMarkdownStructure`');
260
- }
261
- if (parent_1.parent === null /* <- Note: We are in root */) {
262
- // [๐ŸŒป]
263
- throw new Error(spaceTrim("\n The file has an invalid structure.\n The markdown file must have exactly one top-level section.\n "));
264
- }
265
- parent_1 = parent_1.parent;
266
- }
267
- }
268
- var section = { level: level, title: title, contentLines: [], sections: [], parent: parent_1 };
269
- parent_1.sections.push(section);
270
- current = section;
271
- }
272
- }
273
- }
274
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
275
- finally {
276
- try {
277
- if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
278
- }
279
- finally { if (e_1) throw e_1.error; }
280
- }
281
- if (root.sections.length === 1) {
282
- var markdownStructure = parsingMarkdownStructureToMarkdownStructure(root.sections[0]);
283
- return markdownStructure;
251
+ var ExpectError = /** @class */ (function (_super) {
252
+ __extends(ExpectError, _super);
253
+ function ExpectError(message) {
254
+ var _this = _super.call(this, message) || this;
255
+ _this.name = 'ExpectError';
256
+ Object.setPrototypeOf(_this, ExpectError.prototype);
257
+ return _this;
284
258
  }
285
- // [๐ŸŒป]
286
- throw new Error('The markdown file must have exactly one top-level section.');
287
- // return root;
288
- }
259
+ return ExpectError;
260
+ }(Error));
261
+
289
262
  /**
290
- * @private
263
+ * Counts number of characters in the text
291
264
  */
292
- function parsingMarkdownStructureToMarkdownStructure(parsingMarkdownStructure) {
293
- var level = parsingMarkdownStructure.level, title = parsingMarkdownStructure.title, contentLines = parsingMarkdownStructure.contentLines, sections = parsingMarkdownStructure.sections;
294
- return {
295
- level: level,
296
- title: title,
297
- content: spaceTrim(contentLines.join('\n')),
298
- sections: sections.map(parsingMarkdownStructureToMarkdownStructure),
299
- };
265
+ function countCharacters(text) {
266
+ // Remove null characters
267
+ text = text.replace(/\0/g, '');
268
+ // Replace emojis (and also ZWJ sequence) with hyphens
269
+ text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
270
+ text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
271
+ text = text.replace(/\p{Extended_Pictographic}(\u{200D}\p{Extended_Pictographic})*/gu, '-');
272
+ return text.length;
300
273
  }
301
274
 
302
275
  /**
303
- * Utility function to extract all list items from markdown
304
- *
305
- * Note: It works with both ul and ol
306
- * Note: It omits list items in code blocks
307
- * Note: It flattens nested lists
308
- * Note: It can not work with html syntax and comments
309
- *
310
- * @param markdown any valid markdown
311
- * @returns
276
+ * Counts number of lines in the text
312
277
  */
313
- function extractAllListItemsFromMarkdown(markdown) {
314
- var e_1, _a;
315
- var lines = markdown.split('\n');
316
- var listItems = [];
317
- var isInCodeBlock = false;
318
- try {
319
- for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
320
- var line = lines_1_1.value;
321
- var trimmedLine = line.trim();
322
- if (trimmedLine.startsWith('```')) {
323
- isInCodeBlock = !isInCodeBlock;
324
- }
325
- if (!isInCodeBlock && (trimmedLine.startsWith('-') || trimmedLine.match(/^\d+\./))) {
326
- var listItem = trimmedLine.replace(/^-|\d+\./, '').trim();
327
- listItems.push(listItem);
328
- }
329
- }
330
- }
331
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
332
- finally {
333
- try {
334
- if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
335
- }
336
- finally { if (e_1) throw e_1.error; }
337
- }
338
- return listItems;
339
- }
340
-
341
- /**
342
- * Makes first letter of a string uppercase
343
- *
344
- */
345
- function capitalize(word) {
346
- return word.substring(0, 1).toUpperCase() + word.substring(1);
347
- }
348
-
349
- /**
350
- * Extracts all code blocks from markdown.
351
- *
352
- * Note: There are 3 simmilar function:
353
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
354
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
355
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
356
- *
357
- * @param markdown any valid markdown
358
- * @returns code blocks with language and content
359
- *
360
- */
361
- function extractAllBlocksFromMarkdown(markdown) {
362
- var e_1, _a;
363
- var codeBlocks = [];
364
- var lines = markdown.split('\n');
365
- var currentCodeBlock = null;
366
- try {
367
- for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
368
- var line = lines_1_1.value;
369
- if (line.startsWith('```')) {
370
- var language = line.slice(3).trim() || null;
371
- if (currentCodeBlock === null) {
372
- currentCodeBlock = { language: language, content: '' };
373
- }
374
- else {
375
- if (language !== null) {
376
- // [๐ŸŒป]
377
- throw new Error("".concat(capitalize(currentCodeBlock.language || 'the'), " code block was not closed and already opening new ").concat(language, " code block"));
378
- }
379
- codeBlocks.push(currentCodeBlock);
380
- currentCodeBlock = null;
381
- }
382
- }
383
- else if (currentCodeBlock !== null) {
384
- if (currentCodeBlock.content !== '') {
385
- currentCodeBlock.content += '\n';
386
- }
387
- currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make propper unescape */;
388
- }
389
- }
390
- }
391
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
392
- finally {
393
- try {
394
- if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
395
- }
396
- finally { if (e_1) throw e_1.error; }
397
- }
398
- if (currentCodeBlock !== null) {
399
- // [๐ŸŒป]
400
- throw new Error("".concat(capitalize(currentCodeBlock.language || 'the'), " code block was not closed at the end of the markdown"));
278
+ function countLines(text) {
279
+ if (text === '') {
280
+ return 0;
401
281
  }
402
- return codeBlocks;
282
+ return text.split('\n').length;
403
283
  }
404
284
 
405
285
  /**
406
- * Extracts exactly ONE code block from markdown.
407
- *
408
- * Note: If there are multiple or no code blocks the function throws an error
409
- *
410
- * Note: There are 3 simmilar function:
411
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
412
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
413
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
414
- *
415
- * @param markdown any valid markdown
416
- * @returns code block with language and content
286
+ * Counts number of pages in the text
417
287
  */
418
- function extractOneBlockFromMarkdown(markdown) {
419
- var codeBlocks = extractAllBlocksFromMarkdown(markdown);
420
- if (codeBlocks.length !== 1) {
421
- // TODO: Report more specific place where the error happened
422
- throw new Error(/* <- [๐ŸŒป] */ 'There should be exactly one code block in the markdown');
423
- }
424
- return codeBlocks[0];
288
+ function countPages(text) {
289
+ var sentencesPerPage = 5; // Assuming each page has 5 sentences
290
+ var sentences = text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
291
+ var pageCount = Math.ceil(sentences.length / sentencesPerPage);
292
+ return pageCount;
425
293
  }
426
- /***
427
- * TODO: [๐ŸŒป] !!! Decide of this is internal util, external util OR validator/postprocessor
428
- */
429
294
 
430
295
  /**
431
- * Removes HTML or Markdown comments from a string.
432
- *
433
- * @param {string} content - The string to remove comments from.
434
- * @returns {string} The input string with all comments removed.
296
+ * Counts number of paragraphs in the text
435
297
  */
436
- function removeContentComments(content) {
437
- return spaceTrim(content.replace(/<!--(.*?)-->/gs, ''));
298
+ function countParagraphs(text) {
299
+ return text.split(/\n\s*\n/).filter(function (paragraph) { return paragraph.trim() !== ''; }).length;
438
300
  }
439
301
 
440
302
  /**
441
- * The version of the Promptbook library
442
- */
443
- var PROMPTBOOK_VERSION = '0.44.0-0';
444
-
445
- /**
446
- * Parses the given script and returns the list of all used variables that are not defined in the script
447
- *
448
- * @param script from which to extract the variables
449
- * @returns the list of variable names
450
- * @throws {PromptbookSyntaxError} if the script is invalid
451
- *
452
- * @private within the promptbookStringToJson
303
+ * Split text into sentences
453
304
  */
454
- function extractVariables(script) {
455
- var variables = [];
456
- script = "(()=>{".concat(script, "})()");
457
- try {
458
- for (var i = 0; i < 100 /* <- TODO: This limit to configuration */; i++)
459
- try {
460
- eval(script);
461
- }
462
- catch (error) {
463
- if (!(error instanceof ReferenceError)) {
464
- throw error;
465
- }
466
- var undefinedName = error.message.split(' ')[0];
467
- /*
468
- Note: Remapping error
469
- From: [ReferenceError: thing is not defined],
470
- To: [Error: Parameter {thing} is not defined],
471
- */
472
- if (!undefinedName) {
473
- throw error;
474
- }
475
- if (script.includes(undefinedName + '(')) {
476
- script = "const ".concat(undefinedName, " = ()=>'';") + script;
477
- }
478
- else {
479
- variables.push(undefinedName);
480
- script = "const ".concat(undefinedName, " = '';") + script;
481
- }
482
- }
483
- }
484
- catch (error) {
485
- if (!(error instanceof Error)) {
486
- throw error;
487
- }
488
- throw new PromptbookSyntaxError(spaceTrim(function (block) { return "\n Can not extract variables from the script\n\n ".concat(block(error.name), ": ").concat(block(error.message), "\n "); }));
489
- }
490
- return variables;
305
+ function splitIntoSentences(text) {
306
+ return text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
491
307
  }
492
-
493
- /**
494
- * Execution type describes the way how the block is executed
495
- *
496
- * @see https://github.com/webgptorg/promptbook#execution-type
497
- */
498
- var ExecutionTypes = [
499
- 'PROMPT_TEMPLATE',
500
- 'SIMPLE_TEMPLATE',
501
- 'SCRIPT',
502
- 'PROMPT_DIALOG',
503
- // <- [๐Ÿฅป] Insert here when making new command
504
- ];
505
-
506
- /**
507
- * Units of text measurement
508
- */
509
- var EXPECTATION_UNITS = ['CHARACTERS', 'WORDS', 'SENTENCES', 'PARAGRAPHS', 'LINES', 'PAGES'];
510
- /**
511
- * TODO: use one helper type> (string_prompt | string_javascript | string_markdown) & string_template
512
- */
513
-
514
308
  /**
515
- * Removes Markdown formatting tags from a string.
516
- *
517
- * @param {string} str - The string to remove Markdown tags from.
518
- * @returns {string} The input string with all Markdown tags removed.
309
+ * Counts number of sentences in the text
519
310
  */
520
- function removeMarkdownFormatting(str) {
521
- // Remove bold formatting
522
- str = str.replace(/\*\*(.*?)\*\*/g, '$1');
523
- // Remove italic formatting
524
- str = str.replace(/\*(.*?)\*/g, '$1');
525
- // Remove code formatting
526
- str = str.replace(/`(.*?)`/g, '$1');
527
- return str;
528
- }
529
-
530
- /**
531
- * Function parseNumber will parse number from string
532
- *
533
- * Unlike Number.parseInt, Number.parseFloat it will never ever result in NaN
534
- * Note: it also works only with decimal numbers
535
- *
536
- * @returns parsed number
537
- * @throws {PromptbookSyntaxError} if the value is not a number
538
- *
539
- * @private within the parseCommand
540
- */
541
- function parseNumber(value) {
542
- var originalValue = value;
543
- if (typeof value === 'number') {
544
- value = value.toString(); // <- TODO: Maybe more efficient way to do this
545
- }
546
- if (typeof value !== 'string') {
547
- return 0;
548
- }
549
- value = value.trim();
550
- if (value.startsWith('+')) {
551
- return parseNumber(value.substring(1));
552
- }
553
- if (value.startsWith('-')) {
554
- var number = parseNumber(value.substring(1));
555
- if (number === 0) {
556
- return 0; // <- Note: To prevent -0
557
- }
558
- return -number;
559
- }
560
- value = value.replace(/,/g, '.');
561
- value = value.toUpperCase();
562
- if (value === '') {
563
- return 0;
564
- }
565
- if (value === 'โ™พ' || value.startsWith('INF')) {
566
- return Infinity;
567
- }
568
- if (value.includes('/')) {
569
- var _a = __read(value.split('/'), 2), numerator_ = _a[0], denominator_ = _a[1];
570
- var numerator = parseNumber(numerator_);
571
- var denominator = parseNumber(denominator_);
572
- if (denominator === 0) {
573
- throw new PromptbookSyntaxError("Unable to parse number from \"".concat(originalValue, "\" because denominator is zero"));
574
- }
575
- return numerator / denominator;
576
- }
577
- if (/^(NAN|NULL|NONE|UNDEFINED|ZERO|NO.*)$/.test(value)) {
578
- return 0;
579
- }
580
- if (value.includes('E')) {
581
- var _b = __read(value.split('E'), 2), significand = _b[0], exponent = _b[1];
582
- return parseNumber(significand) * Math.pow(10, parseNumber(exponent));
583
- }
584
- if (!/^[0-9.]+$/.test(value) || value.split('.').length > 2) {
585
- throw new PromptbookSyntaxError("Unable to parse number from \"".concat(originalValue, "\""));
586
- }
587
- var num = parseFloat(value);
588
- if (isNaN(num)) {
589
- throw new PromptbookSyntaxError("Unexpected NaN when parsing number from \"".concat(originalValue, "\""));
590
- }
591
- return num;
592
- }
593
- /**
594
- * TODO: Maybe use sth. like safe-eval in fraction/calculation case @see https://www.npmjs.com/package/safe-eval
595
- */
596
-
597
- /**
598
- * This error indicates errors during the execution of the promptbook
599
- */
600
- var PromptbookExecutionError = /** @class */ (function (_super) {
601
- __extends(PromptbookExecutionError, _super);
602
- function PromptbookExecutionError(message) {
603
- var _this = _super.call(this, message) || this;
604
- _this.name = 'PromptbookExecutionError';
605
- Object.setPrototypeOf(_this, PromptbookExecutionError.prototype);
606
- return _this;
607
- }
608
- return PromptbookExecutionError;
609
- }(Error));
610
-
611
- /**
612
- * This error occurs during the parameter replacement in the template
613
- *
614
- * Note: This is a kindof subtype of PromptbookExecutionError because it occurs during the execution of the pipeline
615
- */
616
- var TemplateError = /** @class */ (function (_super) {
617
- __extends(TemplateError, _super);
618
- function TemplateError(message) {
619
- var _this = _super.call(this, message) || this;
620
- _this.name = 'TemplateError';
621
- Object.setPrototypeOf(_this, TemplateError.prototype);
622
- return _this;
623
- }
624
- return TemplateError;
625
- }(Error));
626
-
627
- /**
628
- * Replaces parameters in template with values from parameters object
629
- *
630
- * @param template the template with parameters in {curly} braces
631
- * @param parameters the object with parameters
632
- * @returns the template with replaced parameters
633
- * @throws {TemplateError} if parameter is not defined, not closed, or not opened
634
- *
635
- * @private within the createPromptbookExecutor
636
- */
637
- function replaceParameters(template, parameters) {
638
- var replacedTemplate = template;
639
- var match;
640
- var loopLimit = LOOP_LIMIT;
641
- var _loop_1 = function () {
642
- if (loopLimit-- < 0) {
643
- throw new UnexpectedError('Loop limit reached during parameters replacement in `replaceParameters`');
644
- }
645
- var precol = match.groups.precol;
646
- var parameterName = match.groups.parameterName;
647
- if (parameterName === '') {
648
- return "continue";
649
- }
650
- if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
651
- throw new TemplateError('Parameter is already opened or not closed');
652
- }
653
- if (parameters[parameterName] === undefined) {
654
- throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
655
- }
656
- var parameterValue = parameters[parameterName];
657
- if (parameterValue === undefined) {
658
- throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
659
- }
660
- parameterValue = parameterValue.toString();
661
- if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
662
- parameterValue = parameterValue
663
- .split('\n')
664
- .map(function (line, index) { return (index === 0 ? line : "".concat(precol).concat(line)); })
665
- .join('\n');
666
- }
667
- replacedTemplate =
668
- replacedTemplate.substring(0, match.index + precol.length) +
669
- parameterValue +
670
- replacedTemplate.substring(match.index + precol.length + parameterName.length + 2);
671
- };
672
- while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
673
- .exec(replacedTemplate))) {
674
- _loop_1();
675
- }
676
- // [๐Ÿ’ซ] Check if there are parameters that are not closed properly
677
- if (/{\w+$/.test(replacedTemplate)) {
678
- throw new TemplateError('Parameter is not closed');
679
- }
680
- // [๐Ÿ’ซ] Check if there are parameters that are not opened properly
681
- if (/^\w+}/.test(replacedTemplate)) {
682
- throw new TemplateError('Parameter is not opened');
683
- }
684
- return replacedTemplate;
685
- }
686
-
687
- /**
688
- * Counts number of characters in the text
689
- */
690
- function countCharacters(text) {
691
- // Remove null characters
692
- text = text.replace(/\0/g, '');
693
- // Replace emojis (and also ZWJ sequence) with hyphens
694
- text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
695
- text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
696
- text = text.replace(/\p{Extended_Pictographic}(\u{200D}\p{Extended_Pictographic})*/gu, '-');
697
- return text.length;
698
- }
699
-
700
- /**
701
- * Counts number of lines in the text
702
- */
703
- function countLines(text) {
704
- if (text === '') {
705
- return 0;
706
- }
707
- return text.split('\n').length;
708
- }
709
-
710
- /**
711
- * Counts number of pages in the text
712
- */
713
- function countPages(text) {
714
- var sentencesPerPage = 5; // Assuming each page has 5 sentences
715
- var sentences = text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
716
- var pageCount = Math.ceil(sentences.length / sentencesPerPage);
717
- return pageCount;
718
- }
719
-
720
- /**
721
- * Counts number of paragraphs in the text
722
- */
723
- function countParagraphs(text) {
724
- return text.split(/\n\s*\n/).filter(function (paragraph) { return paragraph.trim() !== ''; }).length;
725
- }
726
-
727
- /**
728
- * Split text into sentences
729
- */
730
- function splitIntoSentences(text) {
731
- return text.split(/[.!?]+/).filter(function (sentence) { return sentence.trim() !== ''; });
732
- }
733
- /**
734
- * Counts number of sentences in the text
735
- */
736
- function countSentences(text) {
737
- return splitIntoSentences(text).length;
311
+ function countSentences(text) {
312
+ return splitIntoSentences(text).length;
738
313
  }
739
314
 
740
315
  var defaultDiacriticsRemovalMap = [
@@ -964,70 +539,356 @@ for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
964
539
  defaultDiacriticsRemovalMap[i].base;
965
540
  }
966
541
  }
967
- // <- TODO: !!!! Put to maker function
968
- /*
969
- @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
970
- Licensed under the Apache License, Version 2.0 (the "License");
971
- you may not use this file except in compliance with the License.
972
- You may obtain a copy of the License at
973
-
974
- http://www.apache.org/licenses/LICENSE-2.0
975
-
976
- Unless required by applicable law or agreed to in writing, software
977
- distributed under the License is distributed on an "AS IS" BASIS,
978
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
979
- See the License for the specific language governing permissions and
980
- limitations under the License.
981
- */
542
+ // <- TODO: !!!! Put to maker function
543
+ /*
544
+ @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
545
+ Licensed under the Apache License, Version 2.0 (the "License");
546
+ you may not use this file except in compliance with the License.
547
+ You may obtain a copy of the License at
548
+
549
+ http://www.apache.org/licenses/LICENSE-2.0
550
+
551
+ Unless required by applicable law or agreed to in writing, software
552
+ distributed under the License is distributed on an "AS IS" BASIS,
553
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
554
+ See the License for the specific language governing permissions and
555
+ limitations under the License.
556
+ */
557
+
558
+ /**
559
+ *
560
+ */
561
+ function removeDiacritics(input) {
562
+ /*eslint no-control-regex: "off"*/
563
+ return input.replace(/[^\u0000-\u007E]/g, function (a) {
564
+ return DIACRITIC_VARIANTS_LETTERS[a] || a;
565
+ });
566
+ }
567
+
568
+ /**
569
+ * Counts number of words in the text
570
+ */
571
+ function countWords(text) {
572
+ text = text.replace(/[\p{Extended_Pictographic}]/gu, 'a');
573
+ text = removeDiacritics(text);
574
+ return text.split(/[^a-zะฐ-ั0-9]+/i).filter(function (word) { return word.length > 0; }).length;
575
+ }
576
+
577
+ /**
578
+ * Index of all counter functions
579
+ */
580
+ var CountUtils = {
581
+ CHARACTERS: countCharacters,
582
+ WORDS: countWords,
583
+ SENTENCES: countSentences,
584
+ PARAGRAPHS: countParagraphs,
585
+ LINES: countLines,
586
+ PAGES: countPages,
587
+ };
588
+
589
+ /**
590
+ * Function checkExpectations will check if the expectations on given value are met
591
+ *
592
+ * Note: There are two simmilar functions:
593
+ * - `checkExpectations` which throws an error if the expectations are not met
594
+ * - `isPassingExpectations` which returns a boolean
595
+ *
596
+ * @throws {ExpectError} if the expectations are not met
597
+ * @returns {void} Nothing
598
+ */
599
+ function checkExpectations(expectations, value) {
600
+ var e_1, _a;
601
+ try {
602
+ for (var _b = __values(Object.entries(expectations)), _c = _b.next(); !_c.done; _c = _b.next()) {
603
+ var _d = __read(_c.value, 2), unit = _d[0], _e = _d[1], max = _e.max, min = _e.min;
604
+ var amount = CountUtils[unit.toUpperCase()](value);
605
+ if (min && amount < min) {
606
+ throw new ExpectError("Expected at least ".concat(min, " ").concat(unit, " but got ").concat(amount));
607
+ } /* not else */
608
+ if (max && amount > max) {
609
+ throw new ExpectError("Expected at most ".concat(max, " ").concat(unit, " but got ").concat(amount));
610
+ }
611
+ }
612
+ }
613
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
614
+ finally {
615
+ try {
616
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
617
+ }
618
+ finally { if (e_1) throw e_1.error; }
619
+ }
620
+ }
621
+ /**
622
+ * Function checkExpectations will check if the expectations on given value are met
623
+ *
624
+ * Note: There are two simmilar functions:
625
+ * - `checkExpectations` which throws an error if the expectations are not met
626
+ * - `isPassingExpectations` which returns a boolean
627
+ *
628
+ * @returns {boolean} True if the expectations are met
629
+ */
630
+ function isPassingExpectations(expectations, value) {
631
+ try {
632
+ checkExpectations(expectations, value);
633
+ return true;
634
+ }
635
+ catch (error) {
636
+ if (!(error instanceof ExpectError)) {
637
+ throw error;
638
+ }
639
+ return false;
640
+ }
641
+ }
642
+ /**
643
+ * TODO: [๐Ÿ’] Unite object for expecting amount and format
644
+ */
645
+
646
+ /**
647
+ * The maximum number of iterations for a loops
648
+ */
649
+ var LOOP_LIMIT = 1000;
650
+ /**
651
+ * The maximum number of iterations for a loops which adds characters one by one
652
+ */
653
+ var CHARACTER_LOOP_LIMIT = 100000;
654
+
655
+ /**
656
+ * This error occurs during the parameter replacement in the template
657
+ *
658
+ * Note: This is a kindof subtype of PromptbookExecutionError because it occurs during the execution of the pipeline
659
+ */
660
+ var TemplateError = /** @class */ (function (_super) {
661
+ __extends(TemplateError, _super);
662
+ function TemplateError(message) {
663
+ var _this = _super.call(this, message) || this;
664
+ _this.name = 'TemplateError';
665
+ Object.setPrototypeOf(_this, TemplateError.prototype);
666
+ return _this;
667
+ }
668
+ return TemplateError;
669
+ }(Error));
670
+
671
+ /**
672
+ * Replaces parameters in template with values from parameters object
673
+ *
674
+ * @param template the template with parameters in {curly} braces
675
+ * @param parameters the object with parameters
676
+ * @returns the template with replaced parameters
677
+ * @throws {TemplateError} if parameter is not defined, not closed, or not opened
678
+ *
679
+ * @private within the createPromptbookExecutor
680
+ */
681
+ function replaceParameters(template, parameters) {
682
+ var replacedTemplate = template;
683
+ var match;
684
+ var loopLimit = LOOP_LIMIT;
685
+ var _loop_1 = function () {
686
+ if (loopLimit-- < 0) {
687
+ throw new UnexpectedError('Loop limit reached during parameters replacement in `replaceParameters`');
688
+ }
689
+ var precol = match.groups.precol;
690
+ var parameterName = match.groups.parameterName;
691
+ if (parameterName === '') {
692
+ return "continue";
693
+ }
694
+ if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
695
+ throw new TemplateError('Parameter is already opened or not closed');
696
+ }
697
+ if (parameters[parameterName] === undefined) {
698
+ throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
699
+ }
700
+ var parameterValue = parameters[parameterName];
701
+ if (parameterValue === undefined) {
702
+ throw new TemplateError("Parameter {".concat(parameterName, "} is not defined"));
703
+ }
704
+ parameterValue = parameterValue.toString();
705
+ if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
706
+ parameterValue = parameterValue
707
+ .split('\n')
708
+ .map(function (line, index) { return (index === 0 ? line : "".concat(precol).concat(line)); })
709
+ .join('\n');
710
+ }
711
+ replacedTemplate =
712
+ replacedTemplate.substring(0, match.index + precol.length) +
713
+ parameterValue +
714
+ replacedTemplate.substring(match.index + precol.length + parameterName.length + 2);
715
+ };
716
+ while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
717
+ .exec(replacedTemplate))) {
718
+ _loop_1();
719
+ }
720
+ // [๐Ÿ’ซ] Check if there are parameters that are not closed properly
721
+ if (/{\w+$/.test(replacedTemplate)) {
722
+ throw new TemplateError('Parameter is not closed');
723
+ }
724
+ // [๐Ÿ’ซ] Check if there are parameters that are not opened properly
725
+ if (/^\w+}/.test(replacedTemplate)) {
726
+ throw new TemplateError('Parameter is not opened');
727
+ }
728
+ return replacedTemplate;
729
+ }
730
+
731
+ /**
732
+ * Function isValidJsonString will tell you if the string is valid JSON or not
733
+ */
734
+ function isValidJsonString(value) {
735
+ try {
736
+ JSON.parse(value);
737
+ return true;
738
+ }
739
+ catch (error) {
740
+ if (!(error instanceof Error)) {
741
+ throw error;
742
+ }
743
+ if (error.message.includes('Unexpected token')) {
744
+ return false;
745
+ }
746
+ return false;
747
+ }
748
+ }
749
+
750
+ /**
751
+ * Makes first letter of a string uppercase
752
+ *
753
+ */
754
+ function capitalize(word) {
755
+ return word.substring(0, 1).toUpperCase() + word.substring(1);
756
+ }
757
+
758
+ /**
759
+ * Extracts all code blocks from markdown.
760
+ *
761
+ * Note: There are 3 simmilar function:
762
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
763
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
764
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
765
+ *
766
+ * @param markdown any valid markdown
767
+ * @returns code blocks with language and content
768
+ *
769
+ */
770
+ function extractAllBlocksFromMarkdown(markdown) {
771
+ var e_1, _a;
772
+ var codeBlocks = [];
773
+ var lines = markdown.split('\n');
774
+ var currentCodeBlock = null;
775
+ try {
776
+ for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
777
+ var line = lines_1_1.value;
778
+ if (line.startsWith('```')) {
779
+ var language = line.slice(3).trim() || null;
780
+ if (currentCodeBlock === null) {
781
+ currentCodeBlock = { language: language, content: '' };
782
+ }
783
+ else {
784
+ if (language !== null) {
785
+ // [๐ŸŒป]
786
+ throw new Error("".concat(capitalize(currentCodeBlock.language || 'the'), " code block was not closed and already opening new ").concat(language, " code block"));
787
+ }
788
+ codeBlocks.push(currentCodeBlock);
789
+ currentCodeBlock = null;
790
+ }
791
+ }
792
+ else if (currentCodeBlock !== null) {
793
+ if (currentCodeBlock.content !== '') {
794
+ currentCodeBlock.content += '\n';
795
+ }
796
+ currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make propper unescape */;
797
+ }
798
+ }
799
+ }
800
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
801
+ finally {
802
+ try {
803
+ if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
804
+ }
805
+ finally { if (e_1) throw e_1.error; }
806
+ }
807
+ if (currentCodeBlock !== null) {
808
+ // [๐ŸŒป]
809
+ throw new Error("".concat(capitalize(currentCodeBlock.language || 'the'), " code block was not closed at the end of the markdown"));
810
+ }
811
+ return codeBlocks;
812
+ }
813
+
814
+ /**
815
+ * Utility function to extract all list items from markdown
816
+ *
817
+ * Note: It works with both ul and ol
818
+ * Note: It omits list items in code blocks
819
+ * Note: It flattens nested lists
820
+ * Note: It can not work with html syntax and comments
821
+ *
822
+ * @param markdown any valid markdown
823
+ * @returns
824
+ */
825
+ function extractAllListItemsFromMarkdown(markdown) {
826
+ var e_1, _a;
827
+ var lines = markdown.split('\n');
828
+ var listItems = [];
829
+ var isInCodeBlock = false;
830
+ try {
831
+ for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
832
+ var line = lines_1_1.value;
833
+ var trimmedLine = line.trim();
834
+ if (trimmedLine.startsWith('```')) {
835
+ isInCodeBlock = !isInCodeBlock;
836
+ }
837
+ if (!isInCodeBlock && (trimmedLine.startsWith('-') || trimmedLine.match(/^\d+\./))) {
838
+ var listItem = trimmedLine.replace(/^-|\d+\./, '').trim();
839
+ listItems.push(listItem);
840
+ }
841
+ }
842
+ }
843
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
844
+ finally {
845
+ try {
846
+ if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
847
+ }
848
+ finally { if (e_1) throw e_1.error; }
849
+ }
850
+ return listItems;
851
+ }
982
852
 
983
853
  /**
854
+ * Extracts exactly ONE code block from markdown.
984
855
  *
856
+ * Note: If there are multiple or no code blocks the function throws an error
857
+ *
858
+ * Note: There are 3 simmilar function:
859
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
860
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
861
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
862
+ *
863
+ * @param markdown any valid markdown
864
+ * @returns code block with language and content
985
865
  */
986
- function removeDiacritics(input) {
987
- /*eslint no-control-regex: "off"*/
988
- return input.replace(/[^\u0000-\u007E]/g, function (a) {
989
- return DIACRITIC_VARIANTS_LETTERS[a] || a;
990
- });
991
- }
992
-
993
- /**
994
- * Counts number of words in the text
995
- */
996
- function countWords(text) {
997
- text = text.replace(/[\p{Extended_Pictographic}]/gu, 'a');
998
- text = removeDiacritics(text);
999
- return text.split(/[^a-zะฐ-ั0-9]+/i).filter(function (word) { return word.length > 0; }).length;
866
+ function extractOneBlockFromMarkdown(markdown) {
867
+ var codeBlocks = extractAllBlocksFromMarkdown(markdown);
868
+ if (codeBlocks.length !== 1) {
869
+ // TODO: Report more specific place where the error happened
870
+ throw new Error(/* <- [๐ŸŒป] */ 'There should be exactly one code block in the markdown');
871
+ }
872
+ return codeBlocks[0];
1000
873
  }
1001
-
1002
- /**
1003
- * Index of all counter functions
874
+ /***
875
+ * TODO: [๐ŸŒป] !!! Decide of this is internal util, external util OR validator/postprocessor
1004
876
  */
1005
- var CountUtils = {
1006
- CHARACTERS: countCharacters,
1007
- WORDS: countWords,
1008
- SENTENCES: countSentences,
1009
- PARAGRAPHS: countParagraphs,
1010
- LINES: countLines,
1011
- PAGES: countPages,
1012
- };
1013
877
 
1014
878
  /**
1015
- * Function isValidJsonString will tell you if the string is valid JSON or not
879
+ * Removes Markdown formatting tags from a string.
880
+ *
881
+ * @param {string} str - The string to remove Markdown tags from.
882
+ * @returns {string} The input string with all Markdown tags removed.
1016
883
  */
1017
- function isValidJsonString(value) {
1018
- try {
1019
- JSON.parse(value);
1020
- return true;
1021
- }
1022
- catch (error) {
1023
- if (!(error instanceof Error)) {
1024
- throw error;
1025
- }
1026
- if (error.message.includes('Unexpected token')) {
1027
- return false;
1028
- }
1029
- return false;
1030
- }
884
+ function removeMarkdownFormatting(str) {
885
+ // Remove bold formatting
886
+ str = str.replace(/\*\*(.*?)\*\*/g, '$1');
887
+ // Remove italic formatting
888
+ str = str.replace(/\*(.*?)\*/g, '$1');
889
+ // Remove code formatting
890
+ str = str.replace(/`(.*?)`/g, '$1');
891
+ return str;
1031
892
  }
1032
893
 
1033
894
  /* tslint:disable */
@@ -1064,94 +925,313 @@ function normalizeTo_SCREAMING_CASE(sentence) {
1064
925
  normalizedChar = char;
1065
926
  }
1066
927
  else {
1067
- charType = 'OTHER';
1068
- normalizedChar = '_';
1069
- }
1070
- if (charType !== lastCharType &&
1071
- !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
1072
- !(lastCharType === 'NUMBER') &&
1073
- !(charType === 'NUMBER')) {
1074
- normalizedName += '_';
928
+ charType = 'OTHER';
929
+ normalizedChar = '_';
930
+ }
931
+ if (charType !== lastCharType &&
932
+ !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
933
+ !(lastCharType === 'NUMBER') &&
934
+ !(charType === 'NUMBER')) {
935
+ normalizedName += '_';
936
+ }
937
+ normalizedName += normalizedChar;
938
+ lastCharType = charType;
939
+ }
940
+ }
941
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
942
+ finally {
943
+ try {
944
+ if (sentence_1_1 && !sentence_1_1.done && (_a = sentence_1.return)) _a.call(sentence_1);
945
+ }
946
+ finally { if (e_1) throw e_1.error; }
947
+ }
948
+ normalizedName = normalizedName.replace(/_+/g, '_');
949
+ normalizedName = normalizedName.replace(/_?\/_?/g, '/');
950
+ normalizedName = normalizedName.replace(/^_/, '');
951
+ normalizedName = normalizedName.replace(/_$/, '');
952
+ return normalizedName;
953
+ }
954
+ /**
955
+ * TODO: [๐ŸŒบ] Use some intermediate util splitWords
956
+ */
957
+
958
+ /* tslint:disable */
959
+ function normalizeTo_camelCase(sentence, __firstLetterCapital) {
960
+ var e_1, _a;
961
+ if (__firstLetterCapital === void 0) { __firstLetterCapital = false; }
962
+ var charType;
963
+ var lastCharType = null;
964
+ var normalizedName = '';
965
+ try {
966
+ for (var sentence_1 = __values(sentence), sentence_1_1 = sentence_1.next(); !sentence_1_1.done; sentence_1_1 = sentence_1.next()) {
967
+ var char = sentence_1_1.value;
968
+ var normalizedChar = void 0;
969
+ if (/^[a-z]$/.test(char)) {
970
+ charType = 'LOWERCASE';
971
+ normalizedChar = char;
972
+ }
973
+ else if (/^[A-Z]$/.test(char)) {
974
+ charType = 'UPPERCASE';
975
+ normalizedChar = char.toLowerCase();
976
+ }
977
+ else if (/^[0-9]$/.test(char)) {
978
+ charType = 'NUMBER';
979
+ normalizedChar = char;
980
+ }
981
+ else {
982
+ charType = 'OTHER';
983
+ normalizedChar = '';
984
+ }
985
+ if (!lastCharType) {
986
+ if (__firstLetterCapital) {
987
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
988
+ }
989
+ }
990
+ else if (charType !== lastCharType &&
991
+ !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
992
+ !(lastCharType === 'NUMBER') &&
993
+ !(charType === 'NUMBER')) {
994
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: [๐ŸŒบ] DRY
995
+ }
996
+ normalizedName += normalizedChar;
997
+ lastCharType = charType;
998
+ }
999
+ }
1000
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1001
+ finally {
1002
+ try {
1003
+ if (sentence_1_1 && !sentence_1_1.done && (_a = sentence_1.return)) _a.call(sentence_1);
1004
+ }
1005
+ finally { if (e_1) throw e_1.error; }
1006
+ }
1007
+ return normalizedName;
1008
+ }
1009
+ /**
1010
+ * TODO: [๐ŸŒบ] Use some intermediate util splitWords
1011
+ */
1012
+
1013
+ function normalizeTo_PascalCase(sentence) {
1014
+ return normalizeTo_camelCase(sentence, true);
1015
+ }
1016
+
1017
+ /**
1018
+ * Supported script languages
1019
+ */
1020
+ var SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
1021
+
1022
+ /**
1023
+ * Parses the template and returns the list of all parameter names
1024
+ *
1025
+ * @param template the template with parameters in {curly} braces
1026
+ * @returns the list of parameter names
1027
+ *
1028
+ * @private within the library
1029
+ */
1030
+ function extractParameters(template) {
1031
+ var e_1, _a;
1032
+ var matches = template.matchAll(/{\w+}/g);
1033
+ var parameterNames = [];
1034
+ try {
1035
+ for (var matches_1 = __values(matches), matches_1_1 = matches_1.next(); !matches_1_1.done; matches_1_1 = matches_1.next()) {
1036
+ var match = matches_1_1.value;
1037
+ var parameterName = match[0].slice(1, -1);
1038
+ if (!parameterNames.includes(parameterName)) {
1039
+ parameterNames.push(parameterName);
1040
+ }
1041
+ }
1042
+ }
1043
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1044
+ finally {
1045
+ try {
1046
+ if (matches_1_1 && !matches_1_1.done && (_a = matches_1.return)) _a.call(matches_1);
1047
+ }
1048
+ finally { if (e_1) throw e_1.error; }
1049
+ }
1050
+ return parameterNames;
1051
+ }
1052
+
1053
+ /**
1054
+ * Computes the deepness of the markdown structure.
1055
+ *
1056
+ * @private within the library
1057
+ */
1058
+ function countMarkdownStructureDeepness(markdownStructure) {
1059
+ var e_1, _a;
1060
+ var maxDeepness = 0;
1061
+ try {
1062
+ for (var _b = __values(markdownStructure.sections), _c = _b.next(); !_c.done; _c = _b.next()) {
1063
+ var section = _c.value;
1064
+ maxDeepness = Math.max(maxDeepness, countMarkdownStructureDeepness(section));
1065
+ }
1066
+ }
1067
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1068
+ finally {
1069
+ try {
1070
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1071
+ }
1072
+ finally { if (e_1) throw e_1.error; }
1073
+ }
1074
+ return maxDeepness + 1;
1075
+ }
1076
+
1077
+ /**
1078
+ * Parse a markdown string into a MarkdownStructure object.
1079
+ *
1080
+ * Note: This function does work with code blocks
1081
+ * Note: This function does not work with markdown comments
1082
+ *
1083
+ * @param markdown The markdown string to parse.
1084
+ * @returns The MarkdownStructure object.
1085
+ *
1086
+ * @private within the library
1087
+ */
1088
+ function markdownToMarkdownStructure(markdown) {
1089
+ var e_1, _a;
1090
+ var lines = markdown.split('\n');
1091
+ var root = { level: 0, title: '', contentLines: [], sections: [], parent: null };
1092
+ var current = root;
1093
+ var isInsideCodeBlock = false;
1094
+ try {
1095
+ for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
1096
+ var line = lines_1_1.value;
1097
+ var headingMatch = line.match(/^(?<mark>#{1,6})\s(?<title>.*)/);
1098
+ if (isInsideCodeBlock || !headingMatch) {
1099
+ if (line.startsWith('```')) {
1100
+ isInsideCodeBlock = !isInsideCodeBlock;
1101
+ }
1102
+ current.contentLines.push(line);
1103
+ }
1104
+ else {
1105
+ var level = headingMatch.groups.mark.length;
1106
+ var title = headingMatch.groups.title.trim();
1107
+ var parent_1 = void 0;
1108
+ if (level > current.level) {
1109
+ // Note: Going deeper (next section is child of current)
1110
+ parent_1 = current;
1111
+ }
1112
+ else {
1113
+ // Note: Going up or staying at the same level (next section is sibling or parent or grandparent,... of current)
1114
+ parent_1 = current;
1115
+ var loopLimit = LOOP_LIMIT;
1116
+ while (parent_1.level !== level - 1) {
1117
+ if (loopLimit-- < 0) {
1118
+ throw new UnexpectedError('Loop limit reached during parsing of markdown structure in `markdownToMarkdownStructure`');
1119
+ }
1120
+ if (parent_1.parent === null /* <- Note: We are in root */) {
1121
+ // [๐ŸŒป]
1122
+ throw new Error(spaceTrim("\n The file has an invalid structure.\n The markdown file must have exactly one top-level section.\n "));
1123
+ }
1124
+ parent_1 = parent_1.parent;
1125
+ }
1126
+ }
1127
+ var section = { level: level, title: title, contentLines: [], sections: [], parent: parent_1 };
1128
+ parent_1.sections.push(section);
1129
+ current = section;
1075
1130
  }
1076
- normalizedName += normalizedChar;
1077
- lastCharType = charType;
1078
1131
  }
1079
1132
  }
1080
1133
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
1081
1134
  finally {
1082
1135
  try {
1083
- if (sentence_1_1 && !sentence_1_1.done && (_a = sentence_1.return)) _a.call(sentence_1);
1136
+ if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
1084
1137
  }
1085
1138
  finally { if (e_1) throw e_1.error; }
1086
1139
  }
1087
- normalizedName = normalizedName.replace(/_+/g, '_');
1088
- normalizedName = normalizedName.replace(/_?\/_?/g, '/');
1089
- normalizedName = normalizedName.replace(/^_/, '');
1090
- normalizedName = normalizedName.replace(/_$/, '');
1091
- return normalizedName;
1140
+ if (root.sections.length === 1) {
1141
+ var markdownStructure = parsingMarkdownStructureToMarkdownStructure(root.sections[0]);
1142
+ return markdownStructure;
1143
+ }
1144
+ // [๐ŸŒป]
1145
+ throw new Error('The markdown file must have exactly one top-level section.');
1146
+ // return root;
1092
1147
  }
1093
1148
  /**
1094
- * TODO: [๐ŸŒบ] Use some intermediate util splitWords
1149
+ * @private
1150
+ */
1151
+ function parsingMarkdownStructureToMarkdownStructure(parsingMarkdownStructure) {
1152
+ var level = parsingMarkdownStructure.level, title = parsingMarkdownStructure.title, contentLines = parsingMarkdownStructure.contentLines, sections = parsingMarkdownStructure.sections;
1153
+ return {
1154
+ level: level,
1155
+ title: title,
1156
+ content: spaceTrim(contentLines.join('\n')),
1157
+ sections: sections.map(parsingMarkdownStructureToMarkdownStructure),
1158
+ };
1159
+ }
1160
+
1161
+ /**
1162
+ * The version of the Promptbook library
1095
1163
  */
1164
+ var PROMPTBOOK_VERSION = '0.44.0-10';
1096
1165
 
1097
- /* tslint:disable */
1098
- function normalizeTo_camelCase(sentence, __firstLetterCapital) {
1099
- var e_1, _a;
1100
- if (__firstLetterCapital === void 0) { __firstLetterCapital = false; }
1101
- var charType;
1102
- var lastCharType = null;
1103
- var normalizedName = '';
1166
+ /**
1167
+ * Parses the given script and returns the list of all used variables that are not defined in the script
1168
+ *
1169
+ * @param script from which to extract the variables
1170
+ * @returns the list of variable names
1171
+ * @throws {PromptbookSyntaxError} if the script is invalid
1172
+ *
1173
+ * @private within the promptbookStringToJson
1174
+ */
1175
+ function extractVariables(script) {
1176
+ var variables = [];
1177
+ script = "(()=>{".concat(script, "})()");
1104
1178
  try {
1105
- for (var sentence_1 = __values(sentence), sentence_1_1 = sentence_1.next(); !sentence_1_1.done; sentence_1_1 = sentence_1.next()) {
1106
- var char = sentence_1_1.value;
1107
- var normalizedChar = void 0;
1108
- if (/^[a-z]$/.test(char)) {
1109
- charType = 'LOWERCASE';
1110
- normalizedChar = char;
1111
- }
1112
- else if (/^[A-Z]$/.test(char)) {
1113
- charType = 'UPPERCASE';
1114
- normalizedChar = char.toLowerCase();
1115
- }
1116
- else if (/^[0-9]$/.test(char)) {
1117
- charType = 'NUMBER';
1118
- normalizedChar = char;
1119
- }
1120
- else {
1121
- charType = 'OTHER';
1122
- normalizedChar = '';
1179
+ for (var i = 0; i < 100 /* <- TODO: This limit to configuration */; i++)
1180
+ try {
1181
+ eval(script);
1123
1182
  }
1124
- if (!lastCharType) {
1125
- if (__firstLetterCapital) {
1126
- normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
1183
+ catch (error) {
1184
+ if (!(error instanceof ReferenceError)) {
1185
+ throw error;
1186
+ }
1187
+ var undefinedName = error.message.split(' ')[0];
1188
+ /*
1189
+ Note: Remapping error
1190
+ From: [ReferenceError: thing is not defined],
1191
+ To: [Error: Parameter {thing} is not defined],
1192
+ */
1193
+ if (!undefinedName) {
1194
+ throw error;
1195
+ }
1196
+ if (script.includes(undefinedName + '(')) {
1197
+ script = "const ".concat(undefinedName, " = ()=>'';") + script;
1198
+ }
1199
+ else {
1200
+ variables.push(undefinedName);
1201
+ script = "const ".concat(undefinedName, " = '';") + script;
1127
1202
  }
1128
1203
  }
1129
- else if (charType !== lastCharType &&
1130
- !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
1131
- !(lastCharType === 'NUMBER') &&
1132
- !(charType === 'NUMBER')) {
1133
- normalizedChar = normalizedChar.toUpperCase(); //TODO: [๐ŸŒบ] DRY
1134
- }
1135
- normalizedName += normalizedChar;
1136
- lastCharType = charType;
1137
- }
1138
1204
  }
1139
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1140
- finally {
1141
- try {
1142
- if (sentence_1_1 && !sentence_1_1.done && (_a = sentence_1.return)) _a.call(sentence_1);
1205
+ catch (error) {
1206
+ if (!(error instanceof Error)) {
1207
+ throw error;
1143
1208
  }
1144
- finally { if (e_1) throw e_1.error; }
1209
+ throw new PromptbookSyntaxError(spaceTrim(function (block) { return "\n Can not extract variables from the script\n\n ".concat(block(error.name), ": ").concat(block(error.message), "\n "); }));
1145
1210
  }
1146
- return normalizedName;
1211
+ return variables;
1147
1212
  }
1213
+
1148
1214
  /**
1149
- * TODO: [๐ŸŒบ] Use some intermediate util splitWords
1215
+ * Execution type describes the way how the block is executed
1216
+ *
1217
+ * @see https://github.com/webgptorg/promptbook#execution-type
1150
1218
  */
1219
+ var ExecutionTypes = [
1220
+ 'PROMPT_TEMPLATE',
1221
+ 'SIMPLE_TEMPLATE',
1222
+ 'SCRIPT',
1223
+ 'PROMPT_DIALOG',
1224
+ // <- [๐Ÿฅป] Insert here when making new command
1225
+ ];
1151
1226
 
1152
- function normalizeTo_PascalCase(sentence) {
1153
- return normalizeTo_camelCase(sentence, true);
1154
- }
1227
+ /**
1228
+ * Units of text measurement
1229
+ */
1230
+ var EXPECTATION_UNITS = ['CHARACTERS', 'WORDS', 'SENTENCES', 'PARAGRAPHS', 'LINES', 'PAGES'];
1231
+ /**
1232
+ * TODO: [๐Ÿ’] Unite object for expecting amount and format - remove expectFormat
1233
+ * TODO: use one helper type> (string_prompt | string_javascript | string_markdown) & string_template
1234
+ */
1155
1235
 
1156
1236
  /**
1157
1237
  * Parses one line of ul/ol to command
@@ -1646,7 +1726,7 @@ function promptbookStringToJson(promptbookString) {
1646
1726
  executionType: executionType,
1647
1727
  jokers: jokers,
1648
1728
  postprocessing: postprocessing,
1649
- expectAmount: expectAmount,
1729
+ expectations: expectAmount,
1650
1730
  expectFormat: expectFormat,
1651
1731
  modelRequirements: templateModelRequirements,
1652
1732
  contentLanguage: executionType === 'SCRIPT' ? language : undefined,
@@ -1788,7 +1868,7 @@ function validatePromptbookJson(promptbook) {
1788
1868
  }
1789
1869
  if (template.jokers && template.jokers.length > 0) {
1790
1870
  if (!template.expectFormat &&
1791
- !template.expectAmount /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1871
+ !template.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1792
1872
  throw new PromptbookLogicError("Joker parameters are used for {".concat(template.resultingParameterName, "} but no expectations are defined"));
1793
1873
  }
1794
1874
  try {
@@ -1807,9 +1887,9 @@ function validatePromptbookJson(promptbook) {
1807
1887
  finally { if (e_3) throw e_3.error; }
1808
1888
  }
1809
1889
  }
1810
- if (template.expectAmount) {
1890
+ if (template.expectations) {
1811
1891
  try {
1812
- for (var _l = (e_4 = void 0, __values(Object.entries(template.expectAmount))), _m = _l.next(); !_m.done; _m = _l.next()) {
1892
+ for (var _l = (e_4 = void 0, __values(Object.entries(template.expectations))), _m = _l.next(); !_m.done; _m = _l.next()) {
1813
1893
  var _o = __read(_m.value, 2), unit = _o[0], _p = _o[1], min = _p.min, max = _p.max;
1814
1894
  if (min !== undefined && max !== undefined && min > max) {
1815
1895
  throw new PromptbookLogicError("Min expectation (=".concat(min, ") of ").concat(unit, " is higher than max expectation (=").concat(max, ")"));
@@ -1890,23 +1970,6 @@ function validatePromptbookJson(promptbook) {
1890
1970
  * > ex port function validatePromptbookJson(promptbook: unknown): asserts promptbook is PromptbookJson {
1891
1971
  */
1892
1972
 
1893
- /**
1894
- * This error occurs when some expectation is not met in the execution of the pipeline
1895
- *
1896
- * @private Always catched and rethrown as `PromptbookExecutionError`
1897
- * Note: This is a kindof subtype of PromptbookExecutionError
1898
- */
1899
- var ExpectError = /** @class */ (function (_super) {
1900
- __extends(ExpectError, _super);
1901
- function ExpectError(message) {
1902
- var _this = _super.call(this, message) || this;
1903
- _this.name = 'ExpectError';
1904
- Object.setPrototypeOf(_this, ExpectError.prototype);
1905
- return _this;
1906
- }
1907
- return ExpectError;
1908
- }(Error));
1909
-
1910
1973
  /**
1911
1974
  * Creates executor function from promptbook and execution tools.
1912
1975
  *
@@ -1921,10 +1984,10 @@ function createPromptbookExecutor(options) {
1921
1984
  var promptbookExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
1922
1985
  function executeSingleTemplate(currentTemplate) {
1923
1986
  return __awaiter(this, void 0, void 0, function () {
1924
- var name, title, priority, prompt, chatThread, completionResult, result, resultString, expectError, scriptExecutionErrors, maxAttempts, jokers, attempt, isJokerAttempt, joker, _a, _b, _c, _d, scriptTools, error_2, e_2_1, _e, _f, functionName, postprocessingError, _g, _h, scriptTools, error_3, e_3_1, e_4_1, _j, _k, _l, unit, _m, max, min, amount, error_4;
1925
- var e_2, _o, e_4, _p, e_3, _q, e_5, _r, _s;
1926
- return __generator(this, function (_t) {
1927
- switch (_t.label) {
1987
+ var name, title, priority, prompt, chatThread, completionResult, result, resultString, expectError, scriptExecutionErrors, maxAttempts, jokers, attempt, isJokerAttempt, joker, _a, _b, _c, _d, scriptTools, error_2, e_2_1, _e, _f, functionName, postprocessingError, _g, _h, scriptTools, error_3, e_3_1, e_4_1, error_4;
1988
+ var e_2, _j, e_4, _k, e_3, _l, _m;
1989
+ return __generator(this, function (_o) {
1990
+ switch (_o.label) {
1928
1991
  case 0:
1929
1992
  name = "promptbook-executor-frame-".concat(currentTemplate.name);
1930
1993
  title = currentTemplate.title;
@@ -1941,8 +2004,8 @@ function createPromptbookExecutor(options) {
1941
2004
  // <- [3]
1942
2005
  })];
1943
2006
  case 1:
1944
- _t.sent();
1945
- _t.label = 2;
2007
+ _o.sent();
2008
+ _o.label = 2;
1946
2009
  case 2:
1947
2010
  result = null;
1948
2011
  resultString = null;
@@ -1950,7 +2013,7 @@ function createPromptbookExecutor(options) {
1950
2013
  maxAttempts = currentTemplate.executionType === 'PROMPT_DIALOG' ? Infinity : maxExecutionAttempts;
1951
2014
  jokers = currentTemplate.jokers || [];
1952
2015
  attempt = -jokers.length;
1953
- _t.label = 3;
2016
+ _o.label = 3;
1954
2017
  case 3:
1955
2018
  if (!(attempt < maxAttempts)) return [3 /*break*/, 49];
1956
2019
  isJokerAttempt = attempt < 0;
@@ -1967,9 +2030,9 @@ function createPromptbookExecutor(options) {
1967
2030
  }
1968
2031
  resultString = parametersToPass[joker];
1969
2032
  }
1970
- _t.label = 4;
2033
+ _o.label = 4;
1971
2034
  case 4:
1972
- _t.trys.push([4, 45, 46, 47]);
2035
+ _o.trys.push([4, 45, 46, 47]);
1973
2036
  if (!!isJokerAttempt) return [3 /*break*/, 27];
1974
2037
  _a = currentTemplate.executionType;
1975
2038
  switch (_a) {
@@ -1991,6 +2054,7 @@ function createPromptbookExecutor(options) {
1991
2054
  parameters: parametersToPass,
1992
2055
  content: replaceParameters(currentTemplate.content, parametersToPass) /* <- [2] */,
1993
2056
  modelRequirements: currentTemplate.modelRequirements,
2057
+ expectations: currentTemplate.expectations,
1994
2058
  };
1995
2059
  _b = currentTemplate.modelRequirements.modelVariant;
1996
2060
  switch (_b) {
@@ -2000,14 +2064,14 @@ function createPromptbookExecutor(options) {
2000
2064
  return [3 /*break*/, 11];
2001
2065
  case 7: return [4 /*yield*/, tools.natural.gptChat(prompt)];
2002
2066
  case 8:
2003
- chatThread = _t.sent();
2067
+ chatThread = _o.sent();
2004
2068
  // TODO: [๐Ÿฌ] Destroy chatThread
2005
2069
  result = chatThread;
2006
2070
  resultString = chatThread.content;
2007
2071
  return [3 /*break*/, 12];
2008
2072
  case 9: return [4 /*yield*/, tools.natural.gptComplete(prompt)];
2009
2073
  case 10:
2010
- completionResult = _t.sent();
2074
+ completionResult = _o.sent();
2011
2075
  result = completionResult;
2012
2076
  resultString = completionResult.content;
2013
2077
  return [3 /*break*/, 12];
@@ -2022,27 +2086,27 @@ function createPromptbookExecutor(options) {
2022
2086
  }
2023
2087
  // TODO: DRY [1]
2024
2088
  scriptExecutionErrors = [];
2025
- _t.label = 14;
2089
+ _o.label = 14;
2026
2090
  case 14:
2027
- _t.trys.push([14, 21, 22, 23]);
2091
+ _o.trys.push([14, 21, 22, 23]);
2028
2092
  _c = (e_2 = void 0, __values(tools.script)), _d = _c.next();
2029
- _t.label = 15;
2093
+ _o.label = 15;
2030
2094
  case 15:
2031
2095
  if (!!_d.done) return [3 /*break*/, 20];
2032
2096
  scriptTools = _d.value;
2033
- _t.label = 16;
2097
+ _o.label = 16;
2034
2098
  case 16:
2035
- _t.trys.push([16, 18, , 19]);
2099
+ _o.trys.push([16, 18, , 19]);
2036
2100
  return [4 /*yield*/, scriptTools.execute({
2037
2101
  scriptLanguage: currentTemplate.contentLanguage,
2038
2102
  script: currentTemplate.content,
2039
2103
  parameters: parametersToPass,
2040
2104
  })];
2041
2105
  case 17:
2042
- resultString = _t.sent();
2106
+ resultString = _o.sent();
2043
2107
  return [3 /*break*/, 20];
2044
2108
  case 18:
2045
- error_2 = _t.sent();
2109
+ error_2 = _o.sent();
2046
2110
  if (!(error_2 instanceof Error)) {
2047
2111
  throw error_2;
2048
2112
  }
@@ -2053,12 +2117,12 @@ function createPromptbookExecutor(options) {
2053
2117
  return [3 /*break*/, 15];
2054
2118
  case 20: return [3 /*break*/, 23];
2055
2119
  case 21:
2056
- e_2_1 = _t.sent();
2120
+ e_2_1 = _o.sent();
2057
2121
  e_2 = { error: e_2_1 };
2058
2122
  return [3 /*break*/, 23];
2059
2123
  case 22:
2060
2124
  try {
2061
- if (_d && !_d.done && (_o = _c.return)) _o.call(_c);
2125
+ if (_d && !_d.done && (_j = _c.return)) _j.call(_c);
2062
2126
  }
2063
2127
  finally { if (e_2) throw e_2.error; }
2064
2128
  return [7 /*endfinally*/];
@@ -2084,46 +2148,46 @@ function createPromptbookExecutor(options) {
2084
2148
  })];
2085
2149
  case 25:
2086
2150
  // TODO: [๐ŸŒน] When making next attempt for `PROMPT DIALOG`, preserve the previous user input
2087
- resultString = _t.sent();
2151
+ resultString = _o.sent();
2088
2152
  return [3 /*break*/, 27];
2089
2153
  case 26: throw new PromptbookExecutionError(
2090
2154
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2091
2155
  "Unknown execution type \"".concat(currentTemplate.executionType, "\""));
2092
2156
  case 27:
2093
2157
  if (!(!isJokerAttempt && currentTemplate.postprocessing)) return [3 /*break*/, 44];
2094
- _t.label = 28;
2158
+ _o.label = 28;
2095
2159
  case 28:
2096
- _t.trys.push([28, 42, 43, 44]);
2160
+ _o.trys.push([28, 42, 43, 44]);
2097
2161
  _e = (e_4 = void 0, __values(currentTemplate.postprocessing)), _f = _e.next();
2098
- _t.label = 29;
2162
+ _o.label = 29;
2099
2163
  case 29:
2100
2164
  if (!!_f.done) return [3 /*break*/, 41];
2101
2165
  functionName = _f.value;
2102
2166
  // TODO: DRY [1]
2103
2167
  scriptExecutionErrors = [];
2104
2168
  postprocessingError = null;
2105
- _t.label = 30;
2169
+ _o.label = 30;
2106
2170
  case 30:
2107
- _t.trys.push([30, 37, 38, 39]);
2171
+ _o.trys.push([30, 37, 38, 39]);
2108
2172
  _g = (e_3 = void 0, __values(tools.script)), _h = _g.next();
2109
- _t.label = 31;
2173
+ _o.label = 31;
2110
2174
  case 31:
2111
2175
  if (!!_h.done) return [3 /*break*/, 36];
2112
2176
  scriptTools = _h.value;
2113
- _t.label = 32;
2177
+ _o.label = 32;
2114
2178
  case 32:
2115
- _t.trys.push([32, 34, , 35]);
2179
+ _o.trys.push([32, 34, , 35]);
2116
2180
  return [4 /*yield*/, scriptTools.execute({
2117
2181
  scriptLanguage: "javascript" /* <- TODO: Try it in each languages; In future allow postprocessing with arbitrary combination of languages to combine */,
2118
2182
  script: "".concat(functionName, "(resultString)"),
2119
2183
  parameters: __assign(__assign({}, parametersToPass), { resultString: resultString || '' }),
2120
2184
  })];
2121
2185
  case 33:
2122
- resultString = _t.sent();
2186
+ resultString = _o.sent();
2123
2187
  postprocessingError = null;
2124
2188
  return [3 /*break*/, 36];
2125
2189
  case 34:
2126
- error_3 = _t.sent();
2190
+ error_3 = _o.sent();
2127
2191
  if (!(error_3 instanceof Error)) {
2128
2192
  throw error_3;
2129
2193
  }
@@ -2135,12 +2199,12 @@ function createPromptbookExecutor(options) {
2135
2199
  return [3 /*break*/, 31];
2136
2200
  case 36: return [3 /*break*/, 39];
2137
2201
  case 37:
2138
- e_3_1 = _t.sent();
2202
+ e_3_1 = _o.sent();
2139
2203
  e_3 = { error: e_3_1 };
2140
2204
  return [3 /*break*/, 39];
2141
2205
  case 38:
2142
2206
  try {
2143
- if (_h && !_h.done && (_q = _g.return)) _q.call(_g);
2207
+ if (_h && !_h.done && (_l = _g.return)) _l.call(_g);
2144
2208
  }
2145
2209
  finally { if (e_3) throw e_3.error; }
2146
2210
  return [7 /*endfinally*/];
@@ -2148,22 +2212,23 @@ function createPromptbookExecutor(options) {
2148
2212
  if (postprocessingError) {
2149
2213
  throw postprocessingError;
2150
2214
  }
2151
- _t.label = 40;
2215
+ _o.label = 40;
2152
2216
  case 40:
2153
2217
  _f = _e.next();
2154
2218
  return [3 /*break*/, 29];
2155
2219
  case 41: return [3 /*break*/, 44];
2156
2220
  case 42:
2157
- e_4_1 = _t.sent();
2221
+ e_4_1 = _o.sent();
2158
2222
  e_4 = { error: e_4_1 };
2159
2223
  return [3 /*break*/, 44];
2160
2224
  case 43:
2161
2225
  try {
2162
- if (_f && !_f.done && (_p = _e.return)) _p.call(_e);
2226
+ if (_f && !_f.done && (_k = _e.return)) _k.call(_e);
2163
2227
  }
2164
2228
  finally { if (e_4) throw e_4.error; }
2165
2229
  return [7 /*endfinally*/];
2166
2230
  case 44:
2231
+ // TODO: [๐Ÿ’] Unite object for expecting amount and format
2167
2232
  if (currentTemplate.expectFormat) {
2168
2233
  if (currentTemplate.expectFormat === 'JSON') {
2169
2234
  if (!isValidJsonString(resultString || '')) {
@@ -2171,30 +2236,13 @@ function createPromptbookExecutor(options) {
2171
2236
  }
2172
2237
  }
2173
2238
  }
2174
- if (currentTemplate.expectAmount) {
2175
- try {
2176
- for (_j = (e_5 = void 0, __values(Object.entries(currentTemplate.expectAmount))), _k = _j.next(); !_k.done; _k = _j.next()) {
2177
- _l = __read(_k.value, 2), unit = _l[0], _m = _l[1], max = _m.max, min = _m.min;
2178
- amount = CountUtils[unit.toUpperCase()](resultString || '');
2179
- if (min && amount < min) {
2180
- throw new ExpectError("Expected at least ".concat(min, " ").concat(unit, " but got ").concat(amount));
2181
- } /* not else */
2182
- if (max && amount > max) {
2183
- throw new ExpectError("Expected at most ".concat(max, " ").concat(unit, " but got ").concat(amount));
2184
- }
2185
- }
2186
- }
2187
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
2188
- finally {
2189
- try {
2190
- if (_k && !_k.done && (_r = _j.return)) _r.call(_j);
2191
- }
2192
- finally { if (e_5) throw e_5.error; }
2193
- }
2239
+ // TODO: [๐Ÿ’] Unite object for expecting amount and format
2240
+ if (currentTemplate.expectations) {
2241
+ checkExpectations(currentTemplate.expectations, resultString || '');
2194
2242
  }
2195
2243
  return [3 /*break*/, 49];
2196
2244
  case 45:
2197
- error_4 = _t.sent();
2245
+ error_4 = _o.sent();
2198
2246
  if (!(error_4 instanceof ExpectError)) {
2199
2247
  throw error_4;
2200
2248
  }
@@ -2213,6 +2261,7 @@ function createPromptbookExecutor(options) {
2213
2261
  title: currentTemplate.title /* <- Note: If title in promptbook contains emojis, pass it innto report */,
2214
2262
  content: prompt.content,
2215
2263
  modelRequirements: prompt.modelRequirements,
2264
+ expectations: prompt.expectations,
2216
2265
  // <- Note: Do want to pass ONLY wanted information to the report
2217
2266
  },
2218
2267
  result: result || undefined,
@@ -2222,9 +2271,9 @@ function createPromptbookExecutor(options) {
2222
2271
  return [7 /*endfinally*/];
2223
2272
  case 47:
2224
2273
  if (expectError !== null && attempt === maxAttempts - 1) {
2225
- throw new PromptbookExecutionError(spaceTrim(function (block) { return "\n Natural execution failed ".concat(maxExecutionAttempts, "x\n\n ").concat(block((expectError === null || expectError === void 0 ? void 0 : expectError.message) || ''), "\n "); }));
2274
+ throw new PromptbookExecutionError(spaceTrim(function (block) { return "\n Natural execution failed ".concat(maxExecutionAttempts, "x\n\n Last error ").concat((expectError === null || expectError === void 0 ? void 0 : expectError.name) || '', ":\n ").concat(block((expectError === null || expectError === void 0 ? void 0 : expectError.message) || ''), "\n\n Last result:\n ").concat(resultString, "\n "); }));
2226
2275
  }
2227
- _t.label = 48;
2276
+ _o.label = 48;
2228
2277
  case 48:
2229
2278
  attempt++;
2230
2279
  return [3 /*break*/, 3];
@@ -2244,7 +2293,7 @@ function createPromptbookExecutor(options) {
2244
2293
  // <- [3]
2245
2294
  });
2246
2295
  }
2247
- parametersToPass = __assign(__assign({}, parametersToPass), (_s = {}, _s[currentTemplate.resultingParameterName] = resultString /* <- Note: Not need to detect parameter collision here because Promptbook checks logic consistency during construction */, _s));
2296
+ parametersToPass = __assign(__assign({}, parametersToPass), (_m = {}, _m[currentTemplate.resultingParameterName] = resultString /* <- Note: Not need to detect parameter collision here because Promptbook checks logic consistency during construction */, _m));
2248
2297
  return [2 /*return*/];
2249
2298
  }
2250
2299
  });
@@ -2448,9 +2497,144 @@ var MockedEchoNaturalExecutionTools = /** @class */ (function () {
2448
2497
  return MockedEchoNaturalExecutionTools;
2449
2498
  }());
2450
2499
  /**
2451
- * TODO: Allow in spaceTrim: nesting with > ${block(prompt.request)}
2500
+ * TODO: Allow in spaceTrim: nesting with > ${block(prompt.request)}, same as replace params
2501
+ */
2502
+
2503
+ /**
2504
+ * Gets the expectations and creates a fake text that meets the expectations
2505
+ *
2506
+ * Note: You can provide postprocessing functions to modify the text before checking the expectations
2507
+ * The result will be the text BEFORE the postprocessing
2508
+ *
2509
+ * @private internal util for MockedFackedNaturalExecutionTools
2510
+ */
2511
+ function $fakeTextToExpectations(expectations, postprocessing) {
2512
+ return __awaiter(this, void 0, void 0, function () {
2513
+ var lorem, loremText, text, loopLimit, textToCheck, _a, _b, func, e_1_1;
2514
+ var e_1, _c;
2515
+ return __generator(this, function (_d) {
2516
+ switch (_d.label) {
2517
+ case 0:
2518
+ lorem = new LoremIpsum({
2519
+ wordsPerSentence: { min: 5, max: 15 },
2520
+ sentencesPerParagraph: { min: 5, max: 15 },
2521
+ });
2522
+ loremText = '';
2523
+ text = '';
2524
+ loopLimit = CHARACTER_LOOP_LIMIT;
2525
+ _d.label = 1;
2526
+ case 1:
2527
+ if (!(loopLimit-- > 0)) return [3 /*break*/, 11];
2528
+ textToCheck = text;
2529
+ _d.label = 2;
2530
+ case 2:
2531
+ _d.trys.push([2, 7, 8, 9]);
2532
+ _a = (e_1 = void 0, __values(postprocessing || [])), _b = _a.next();
2533
+ _d.label = 3;
2534
+ case 3:
2535
+ if (!!_b.done) return [3 /*break*/, 6];
2536
+ func = _b.value;
2537
+ return [4 /*yield*/, func(textToCheck)];
2538
+ case 4:
2539
+ textToCheck = _d.sent();
2540
+ _d.label = 5;
2541
+ case 5:
2542
+ _b = _a.next();
2543
+ return [3 /*break*/, 3];
2544
+ case 6: return [3 /*break*/, 9];
2545
+ case 7:
2546
+ e_1_1 = _d.sent();
2547
+ e_1 = { error: e_1_1 };
2548
+ return [3 /*break*/, 9];
2549
+ case 8:
2550
+ try {
2551
+ if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
2552
+ }
2553
+ finally { if (e_1) throw e_1.error; }
2554
+ return [7 /*endfinally*/];
2555
+ case 9:
2556
+ if (isPassingExpectations(expectations, textToCheck)) {
2557
+ return [2 /*return*/, text]; // <- Note: Returning the text because the postprocessing
2558
+ }
2559
+ if (loremText === '') {
2560
+ loremText = lorem.generateParagraphs(1) + '\n\n';
2561
+ }
2562
+ text += loremText.substring(0, 1);
2563
+ loremText = loremText.substring(1);
2564
+ _d.label = 10;
2565
+ case 10: return [3 /*break*/, 1];
2566
+ case 11: throw new Error(spaceTrim(function (block) { return "\n Can not generate fake text to met the expectations\n\n Loop limit reached\n The expectations:\n ".concat(block(JSON.stringify(expectations, null, 4)), "\n\n The draft text:\n ").concat(block(text), "\n\n "); }));
2567
+ }
2568
+ });
2569
+ });
2570
+ }
2571
+ /**
2572
+ * TODO: Implement better - create FakeLLM from this
2573
+ * TODO: [๐Ÿ’] Unite object for expecting amount and format - use here also a format
2452
2574
  */
2453
2575
 
2576
+ /**
2577
+ * Mocked execution Tools for just faking expected responses for testing purposes
2578
+ */
2579
+ var MockedFackedNaturalExecutionTools = /** @class */ (function () {
2580
+ function MockedFackedNaturalExecutionTools(options) {
2581
+ this.options = options;
2582
+ }
2583
+ /**
2584
+ * Fakes chat model
2585
+ */
2586
+ MockedFackedNaturalExecutionTools.prototype.gptChat = function (prompt) {
2587
+ return __awaiter(this, void 0, void 0, function () {
2588
+ var content, result;
2589
+ return __generator(this, function (_a) {
2590
+ switch (_a.label) {
2591
+ case 0:
2592
+ if (this.options.isVerbose) {
2593
+ console.info('๐Ÿ’ฌ Mocked faked prompt', prompt);
2594
+ }
2595
+ return [4 /*yield*/, $fakeTextToExpectations(prompt.expectations || {
2596
+ sentences: { min: 1, max: 1 },
2597
+ }, prompt.postprocessing)];
2598
+ case 1:
2599
+ content = _a.sent();
2600
+ result = {
2601
+ content: content,
2602
+ model: 'mocked-facked',
2603
+ timing: {
2604
+ start: getCurrentIsoDate(),
2605
+ complete: getCurrentIsoDate(),
2606
+ },
2607
+ usage: {
2608
+ price: 0,
2609
+ inputTokens: 0,
2610
+ outputTokens: 0,
2611
+ },
2612
+ rawResponse: {
2613
+ note: 'This is mocked echo',
2614
+ },
2615
+ // <- [๐Ÿคนโ€โ™‚๏ธ]
2616
+ };
2617
+ if (this.options.isVerbose) {
2618
+ console.info('๐Ÿ’ฌ Mocked faked result', result);
2619
+ }
2620
+ return [2 /*return*/, result];
2621
+ }
2622
+ });
2623
+ });
2624
+ };
2625
+ /**
2626
+ * Fakes completion model
2627
+ */
2628
+ MockedFackedNaturalExecutionTools.prototype.gptComplete = function (prompt) {
2629
+ return __awaiter(this, void 0, void 0, function () {
2630
+ return __generator(this, function (_a) {
2631
+ return [2 /*return*/, this.gptChat(prompt)];
2632
+ });
2633
+ });
2634
+ };
2635
+ return MockedFackedNaturalExecutionTools;
2636
+ }());
2637
+
2454
2638
  /**
2455
2639
  * Delagates the user interaction to a async callback function
2456
2640
  * You need to provide your own implementation of this callback function and its bind to UI.
@@ -2794,5 +2978,5 @@ function createPromptbookSublibrary(library, predicate) {
2794
2978
  * TODO: !!! Annotate all + all to README and samples
2795
2979
  */
2796
2980
 
2797
- export { CallbackInterfaceTools, ExecutionTypes, MockedEchoNaturalExecutionTools, PROMPTBOOK_VERSION, SimplePromptInterfaceTools, SimplePromptbookLibrary, createPromptbookExecutor, createPromptbookLibraryFromPromise, createPromptbookLibraryFromSources, createPromptbookSublibrary, promptbookStringToJson, validatePromptbookJson };
2981
+ export { CallbackInterfaceTools, ExecutionTypes, MockedEchoNaturalExecutionTools, MockedFackedNaturalExecutionTools, PROMPTBOOK_VERSION, SimplePromptInterfaceTools, SimplePromptbookLibrary, createPromptbookExecutor, createPromptbookLibraryFromPromise, createPromptbookLibraryFromSources, createPromptbookSublibrary, promptbookStringToJson, validatePromptbookJson };
2798
2982
  //# sourceMappingURL=index.es.js.map