@promptbook/core 0.81.0-8 → 0.82.0-0

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 (110) hide show
  1. package/README.md +25 -4
  2. package/esm/index.es.js +1147 -932
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/books/index.d.ts +38 -0
  5. package/esm/typings/src/_packages/core.index.d.ts +12 -4
  6. package/esm/typings/src/_packages/markdown-utils.index.d.ts +2 -2
  7. package/esm/typings/src/_packages/node.index.d.ts +0 -2
  8. package/esm/typings/src/_packages/remote-client.index.d.ts +7 -3
  9. package/esm/typings/src/_packages/remote-server.index.d.ts +2 -2
  10. package/esm/typings/src/_packages/templates.index.d.ts +2 -2
  11. package/esm/typings/src/_packages/types.index.d.ts +34 -30
  12. package/esm/typings/src/_packages/utils.index.d.ts +2 -0
  13. package/esm/typings/src/_packages/wizzard.index.d.ts +44 -0
  14. package/esm/typings/src/cli/cli-commands/make.d.ts +1 -1
  15. package/esm/typings/src/cli/cli-commands/run.d.ts +2 -2
  16. package/esm/typings/src/collection/constructors/createCollectionFromDirectory.d.ts +11 -0
  17. package/esm/typings/src/collection/constructors/createCollectionFromUrl.d.ts +1 -1
  18. package/esm/typings/src/commands/index.d.ts +1 -1
  19. package/esm/typings/src/config.d.ts +3 -3
  20. package/esm/typings/src/conversion/compilePipeline.d.ts +1 -4
  21. package/esm/typings/src/conversion/compilePipelineOnRemoteServer.d.ts +18 -0
  22. package/esm/typings/src/conversion/{precompilePipeline.d.ts → parsePipeline.d.ts} +3 -3
  23. package/esm/typings/src/conversion/prettify/renderPipelineMermaidOptions.d.ts +3 -3
  24. package/esm/typings/src/conversion/validation/validatePipeline.d.ts +7 -7
  25. package/esm/typings/src/errors/utils/getErrorReportUrl.d.ts +1 -1
  26. package/esm/typings/src/execution/PipelineExecutor.d.ts +2 -2
  27. package/esm/typings/src/execution/createPipelineExecutor/10-executePipeline.d.ts +2 -2
  28. package/esm/typings/src/formfactors/generator/GeneratorFormfactorDefinition.d.ts +9 -4
  29. package/esm/typings/src/formfactors/image-generator/ImageGeneratorFormfactorDefinition.d.ts +24 -0
  30. package/esm/typings/src/formfactors/index.d.ts +31 -9
  31. package/esm/typings/src/high-level-abstractions/_common/HighLevelAbstraction.d.ts +1 -1
  32. package/esm/typings/src/high-level-abstractions/index.d.ts +3 -3
  33. package/esm/typings/src/high-level-abstractions/quick-chatbot/QuickChatbotHla.d.ts +3 -0
  34. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
  35. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
  36. package/esm/typings/src/llm-providers/_common/register/{$provideLlmToolsForCli.d.ts → $provideLlmToolsForWizzardOrCli.d.ts} +2 -2
  37. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
  38. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +1 -1
  39. package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  40. package/esm/typings/src/llm-providers/anthropic-claude/createAnthropicClaudeExecutionTools.d.ts +2 -2
  41. package/esm/typings/src/llm-providers/anthropic-claude/playground/playground.d.ts +2 -2
  42. package/esm/typings/src/llm-providers/anthropic-claude/register-configuration.d.ts +1 -0
  43. package/esm/typings/src/llm-providers/anthropic-claude/register-constructor.d.ts +2 -0
  44. package/esm/typings/src/llm-providers/azure-openai/register-configuration.d.ts +1 -0
  45. package/esm/typings/src/llm-providers/azure-openai/register-constructor.d.ts +1 -0
  46. package/esm/typings/src/llm-providers/google/register-configuration.d.ts +1 -0
  47. package/esm/typings/src/llm-providers/google/register-constructor.d.ts +1 -0
  48. package/esm/typings/src/llm-providers/openai/playground/playground.d.ts +1 -1
  49. package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +2 -0
  50. package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +2 -0
  51. package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -1
  52. package/esm/typings/src/llm-providers/vercel/playground/playground.d.ts +1 -1
  53. package/esm/typings/src/other/templates/getBookTemplates.d.ts +22 -0
  54. package/esm/typings/src/personas/preparePersona.d.ts +4 -4
  55. package/esm/typings/src/pipeline/PipelineString.d.ts +0 -3
  56. package/esm/typings/src/pipeline/book-notation.d.ts +14 -0
  57. package/esm/typings/src/pipeline/isValidPipelineString.d.ts +13 -0
  58. package/esm/typings/src/pipeline/isValidPipelineString.test.d.ts +4 -0
  59. package/esm/typings/src/pipeline/validatePipelineString.d.ts +14 -0
  60. package/esm/typings/src/prepare/isPipelinePrepared.d.ts +3 -1
  61. package/esm/typings/src/prepare/preparePipeline.d.ts +4 -2
  62. package/esm/typings/src/prepare/preparePipelineOnRemoteServer.d.ts +14 -0
  63. package/esm/typings/src/prepare/prepareTasks.d.ts +1 -1
  64. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/PromptbookServer_Error.d.ts +1 -1
  65. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/PromptbookServer_ListModels_Request.d.ts +4 -4
  66. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/PromptbookServer_ListModels_Response.d.ts +1 -1
  67. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/PromptbookServer_Prompt_Progress.d.ts +1 -1
  68. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/PromptbookServer_Prompt_Request.d.ts +5 -5
  69. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/PromptbookServer_Prompt_Response.d.ts +1 -1
  70. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/RemoteLlmExecutionToolsOptions.d.ts +7 -7
  71. package/esm/typings/src/{llm-providers/remote → remote-server}/interfaces/RemoteServerOptions.d.ts +10 -10
  72. package/esm/typings/src/scrapers/_common/Converter.d.ts +1 -0
  73. package/esm/typings/src/scrapers/_common/Scraper.d.ts +1 -1
  74. package/esm/typings/src/scrapers/_common/ScraperIntermediateSource.d.ts +3 -0
  75. package/esm/typings/src/scrapers/_common/register/ScraperAndConverterMetadata.d.ts +2 -0
  76. package/esm/typings/src/scrapers/_common/utils/scraperFetch.d.ts +3 -0
  77. package/esm/typings/src/scrapers/document/register-constructor.d.ts +1 -0
  78. package/esm/typings/src/scrapers/document/register-metadata.d.ts +1 -0
  79. package/esm/typings/src/scrapers/document-legacy/register-constructor.d.ts +1 -0
  80. package/esm/typings/src/scrapers/document-legacy/register-metadata.d.ts +1 -0
  81. package/esm/typings/src/scrapers/markdown/register-constructor.d.ts +1 -0
  82. package/esm/typings/src/scrapers/markdown/register-metadata.d.ts +1 -0
  83. package/esm/typings/src/scrapers/pdf/PdfScraper.d.ts +1 -0
  84. package/esm/typings/src/scrapers/pdf/createPdfScraper.d.ts +1 -1
  85. package/esm/typings/src/scrapers/pdf/register-constructor.d.ts +1 -0
  86. package/esm/typings/src/scrapers/pdf/register-metadata.d.ts +2 -1
  87. package/esm/typings/src/scrapers/website/createWebsiteScraper.d.ts +3 -1
  88. package/esm/typings/src/scrapers/website/register-constructor.d.ts +1 -0
  89. package/esm/typings/src/scrapers/website/register-metadata.d.ts +1 -0
  90. package/esm/typings/src/scripting/javascript/JavascriptEvalExecutionTools.test.d.ts +1 -1
  91. package/esm/typings/src/scripting/javascript/utils/preserve.d.ts +2 -1
  92. package/esm/typings/src/types/typeAliases.d.ts +16 -2
  93. package/esm/typings/src/utils/markdown/flattenMarkdown.d.ts +1 -1
  94. package/esm/typings/src/utils/markdown/{removeContentComments.d.ts → removeMarkdownComments.d.ts} +2 -2
  95. package/esm/typings/src/utils/organization/$sideEffect.d.ts +9 -0
  96. package/esm/typings/src/utils/serialization/checkSerializableAsJson.d.ts +1 -1
  97. package/esm/typings/src/utils/serialization/isSerializableAsJson.d.ts +2 -2
  98. package/esm/typings/src/utils/validators/filePath/isRootPath.d.ts +12 -0
  99. package/esm/typings/src/utils/validators/filePath/isRootPath.test.d.ts +4 -0
  100. package/esm/typings/src/utils/validators/filePath/isValidFilePath.d.ts +3 -0
  101. package/esm/typings/src/wizzard/$getCompiledBook.d.ts +16 -0
  102. package/esm/typings/src/wizzard/wizzard.d.ts +52 -8
  103. package/package.json +1 -1
  104. package/umd/index.umd.js +1152 -933
  105. package/umd/index.umd.js.map +1 -1
  106. package/esm/typings/src/other/templates/getBookTemplate.d.ts +0 -21
  107. package/esm/typings/src/scripting/javascript/utils/unknownToString.d.ts +0 -8
  108. /package/esm/typings/src/conversion/{precompilePipeline.test.d.ts → parsePipeline.test.d.ts} +0 -0
  109. /package/esm/typings/src/{llm-providers/remote → remote-server}/startRemoteServer.d.ts +0 -0
  110. /package/esm/typings/src/utils/markdown/{removeContentComments.test.d.ts → removeMarkdownComments.test.d.ts} +0 -0
package/esm/index.es.js CHANGED
@@ -25,7 +25,7 @@ var BOOK_LANGUAGE_VERSION = '1.0.0';
25
25
  * @generated
26
26
  * @see https://github.com/webgptorg/promptbook
27
27
  */
28
- var PROMPTBOOK_ENGINE_VERSION = '0.81.0-7';
28
+ var PROMPTBOOK_ENGINE_VERSION = '0.81.0-23';
29
29
  /**
30
30
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
31
31
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -177,6 +177,66 @@ function collectionToJson(collection) {
177
177
  * TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
178
178
  */
179
179
 
180
+ /**
181
+ * Function isValidJsonString will tell you if the string is valid JSON or not
182
+ *
183
+ * @public exported from `@promptbook/utils`
184
+ */
185
+ function isValidJsonString(value /* <- [👨‍⚖️] */) {
186
+ try {
187
+ JSON.parse(value);
188
+ return true;
189
+ }
190
+ catch (error) {
191
+ if (!(error instanceof Error)) {
192
+ throw error;
193
+ }
194
+ if (error.message.includes('Unexpected token')) {
195
+ return false;
196
+ }
197
+ return false;
198
+ }
199
+ }
200
+
201
+ /**
202
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
203
+ *
204
+ * @public exported from `@promptbook/core`
205
+ */
206
+ var ParseError = /** @class */ (function (_super) {
207
+ __extends(ParseError, _super);
208
+ function ParseError(message) {
209
+ var _this = _super.call(this, message) || this;
210
+ _this.name = 'ParseError';
211
+ Object.setPrototypeOf(_this, ParseError.prototype);
212
+ return _this;
213
+ }
214
+ return ParseError;
215
+ }(Error));
216
+ /**
217
+ * TODO: Maybe split `ParseError` and `ApplyError`
218
+ */
219
+
220
+ /**
221
+ * Function `validatePipelineString` will validate the if the string is a valid pipeline string
222
+ * It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
223
+ *
224
+ * @param {string} pipelineString the candidate for a pipeline string
225
+ * @returns {PipelineString} the same string as input, but validated as valid
226
+ * @throws {ParseError} if the string is not a valid pipeline string
227
+ * @public exported from `@promptbook/core`
228
+ */
229
+ function validatePipelineString(pipelineString) {
230
+ if (isValidJsonString(pipelineString)) {
231
+ throw new ParseError('Expected a book, but got a JSON string');
232
+ }
233
+ // <- TODO: Implement the validation + add tests when the pipeline logic considered as invalid
234
+ return pipelineString;
235
+ }
236
+ /**
237
+ * TODO: [🧠][🈴] Where is the best location for this file
238
+ */
239
+
180
240
  /**
181
241
  * Prettify the html code
182
242
  *
@@ -243,7 +303,7 @@ function pipelineJsonToString(pipelineJson) {
243
303
  if (bookVersion !== "undefined") {
244
304
  commands.push("BOOK VERSION ".concat(bookVersion));
245
305
  }
246
- // TODO: [main] !!!!! This increases size of the bundle and is probbably not necessary
306
+ // TODO: [main] !!5 This increases size of the bundle and is probbably not necessary
247
307
  pipelineString = prettifyMarkdown(pipelineString);
248
308
  try {
249
309
  for (var _g = __values(parameters.filter(function (_a) {
@@ -391,12 +451,12 @@ function pipelineJsonToString(pipelineJson) {
391
451
  pipelineString += '```' + contentLanguage;
392
452
  pipelineString += '\n';
393
453
  pipelineString += spaceTrim(content);
394
- // <- TODO: [main] !!! Escape
454
+ // <- TODO: [main] !!3 Escape
395
455
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
396
456
  pipelineString += '\n';
397
457
  pipelineString += '```';
398
458
  pipelineString += '\n\n';
399
- pipelineString += "`-> {".concat(resultingParameterName, "}`"); // <- TODO: [main] !!! If the parameter here has description, add it and use taskParameterJsonToString
459
+ pipelineString += "`-> {".concat(resultingParameterName, "}`"); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
400
460
  }
401
461
  }
402
462
  catch (e_3_1) { e_3 = { error: e_3_1 }; }
@@ -406,7 +466,7 @@ function pipelineJsonToString(pipelineJson) {
406
466
  }
407
467
  finally { if (e_3) throw e_3.error; }
408
468
  }
409
- return pipelineString;
469
+ return validatePipelineString(pipelineString);
410
470
  }
411
471
  /**
412
472
  * @private internal utility of `pipelineJsonToString`
@@ -503,7 +563,7 @@ var LOGO_DARK_SRC = "https://promptbook.studio/_next/static/media/promptbook-log
503
563
  *
504
564
  * @public exported from `@promptbook/core`
505
565
  */
506
- var DEFAULT_TITLE = "Untitled";
566
+ var DEFAULT_BOOK_TITLE = "\u2728 Untitled Book";
507
567
  // <- TODO: [🧠] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
508
568
  /**
509
569
  * The maximum number of iterations for a loops
@@ -564,14 +624,14 @@ var DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [🤹‍♂️]
564
624
  var DEFAULT_MAX_EXECUTION_ATTEMPTS = 3; // <- TODO: [🤹‍♂️]
565
625
  /**
566
626
  * @@@
567
- * TODO: [🐝][main] !!! Use
627
+ * TODO: [🐝][main] !!3 Use
568
628
  *
569
629
  * @public exported from `@promptbook/core`
570
630
  */
571
631
  var DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH = 3;
572
632
  /**
573
633
  * @@@
574
- * TODO: [🐝][main] !!! Use
634
+ * TODO: [🐝][main] !!3 Use
575
635
  *
576
636
  * @public exported from `@promptbook/core`
577
637
  */
@@ -583,6 +643,7 @@ var DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL = 200;
583
643
  * @public exported from `@promptbook/core`
584
644
  */
585
645
  var DEFAULT_BOOKS_DIRNAME = './books';
646
+ // <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
586
647
  /**
587
648
  * Where to store the cache of executions for promptbook CLI
588
649
  *
@@ -733,7 +794,7 @@ function $deepFreeze(objectValue) {
733
794
  /**
734
795
  * Make error report URL for the given error
735
796
  *
736
- * @private !!!!!!
797
+ * @private private within the repository
737
798
  */
738
799
  function getErrorReportUrl(error) {
739
800
  var report = {
@@ -854,7 +915,7 @@ function checkSerializableAsJson(options) {
854
915
  if (!(error instanceof Error)) {
855
916
  throw error;
856
917
  }
857
- throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is not serializable\n\n ").concat(block(error.toString()), "\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
918
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is not serializable\n\n ").concat(block(error.stack || error.message), "\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
858
919
  }
859
920
  /*
860
921
  TODO: [0] Is there some more elegant way to check circular references?
@@ -884,7 +945,7 @@ function checkSerializableAsJson(options) {
884
945
  }
885
946
  /**
886
947
  * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
887
- * TODO: [🧠][main] !!! In-memory cache of same values to prevent multiple checks
948
+ * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
888
949
  * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
889
950
  */
890
951
 
@@ -896,7 +957,6 @@ function checkSerializableAsJson(options) {
896
957
  function deepClone(objectValue) {
897
958
  return JSON.parse(JSON.stringify(objectValue));
898
959
  /*
899
- !!!!!!!!
900
960
  TODO: [🧠] Is there a better implementation?
901
961
  > const propertyNames = Object.getOwnPropertyNames(objectValue);
902
962
  > for (const propertyName of propertyNames) {
@@ -1008,25 +1068,6 @@ var RESERVED_PARAMETER_NAMES = exportJson({
1008
1068
  * Note: [💞] Ignore a discrepancy between file name and entity name
1009
1069
  */
1010
1070
 
1011
- /**
1012
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
1013
- *
1014
- * @public exported from `@promptbook/core`
1015
- */
1016
- var ParseError = /** @class */ (function (_super) {
1017
- __extends(ParseError, _super);
1018
- function ParseError(message) {
1019
- var _this = _super.call(this, message) || this;
1020
- _this.name = 'ParseError';
1021
- Object.setPrototypeOf(_this, ParseError.prototype);
1022
- return _this;
1023
- }
1024
- return ParseError;
1025
- }(Error));
1026
- /**
1027
- * TODO: Maybe split `ParseError` and `ApplyError`
1028
- */
1029
-
1030
1071
  /**
1031
1072
  * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
1032
1073
  *
@@ -1081,7 +1122,7 @@ function isValidPromptbookVersion(version) {
1081
1122
  if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
1082
1123
  return false;
1083
1124
  }
1084
- // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
1125
+ // <- TODO: [main] !!3 Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
1085
1126
  return true;
1086
1127
  }
1087
1128
 
@@ -1181,9 +1222,6 @@ function isValidPipelineUrl(url) {
1181
1222
  if (!url.startsWith('https://')) {
1182
1223
  return false;
1183
1224
  }
1184
- if (!(url.endsWith('.book.md') || url.endsWith('.book') || url.endsWith('.book.md') || url.endsWith('.ptbk'))) {
1185
- return false;
1186
- }
1187
1225
  if (url.includes('#')) {
1188
1226
  // TODO: [🐠]
1189
1227
  return false;
@@ -1214,11 +1252,11 @@ function isValidPipelineUrl(url) {
1214
1252
  */
1215
1253
  function validatePipeline(pipeline) {
1216
1254
  if (IS_PIPELINE_LOGIC_VALIDATED) {
1217
- validatePipelineCore(pipeline);
1255
+ validatePipeline_InnerFunction(pipeline);
1218
1256
  }
1219
1257
  else {
1220
1258
  try {
1221
- validatePipelineCore(pipeline);
1259
+ validatePipeline_InnerFunction(pipeline);
1222
1260
  }
1223
1261
  catch (error) {
1224
1262
  if (!(error instanceof PipelineLogicError)) {
@@ -1232,7 +1270,7 @@ function validatePipeline(pipeline) {
1232
1270
  /**
1233
1271
  * @private internal function for `validatePipeline`
1234
1272
  */
1235
- function validatePipelineCore(pipeline) {
1273
+ function validatePipeline_InnerFunction(pipeline) {
1236
1274
  // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
1237
1275
  var e_1, _a, e_2, _b, e_3, _c;
1238
1276
  var pipelineIdentification = (function () {
@@ -1456,11 +1494,11 @@ function validatePipelineCore(pipeline) {
1456
1494
  _loop_3();
1457
1495
  }
1458
1496
  // Note: Check that formfactor is corresponding to the pipeline interface
1459
- // TODO: !!!!!! Implement this
1497
+ // TODO: !!6 Implement this
1460
1498
  // pipeline.formfactorName
1461
1499
  }
1462
1500
  /**
1463
- * TODO: !! [🧞‍♀️] Do not allow joker + foreach
1501
+ * TODO: [🧞‍♀️] Do not allow joker + foreach
1464
1502
  * TODO: [🧠] Work with promptbookVersion
1465
1503
  * TODO: Use here some json-schema, Zod or something similar and change it to:
1466
1504
  * > /**
@@ -1472,11 +1510,11 @@ function validatePipelineCore(pipeline) {
1472
1510
  * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
1473
1511
  */
1474
1512
  /**
1475
- * TODO: [🧳][main] !!!! Validate that all examples match expectations
1476
- * TODO: [🧳][🐝][main] !!!! Validate that knowledge is valid (non-void)
1477
- * TODO: [🧳][main] !!!! Validate that persona can be used only with CHAT variant
1478
- * TODO: [🧳][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1479
- * TODO: [🧳][main] !!!! Validate that reserved parameter is not used as joker
1513
+ * TODO: [🧳][main] !!4 Validate that all examples match expectations
1514
+ * TODO: [🧳][🐝][main] !!4 Validate that knowledge is valid (non-void)
1515
+ * TODO: [🧳][main] !!4 Validate that persona can be used only with CHAT variant
1516
+ * TODO: [🧳][main] !!4 Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1517
+ * TODO: [🧳][main] !!4 Validate that reserved parameter is not used as joker
1480
1518
  * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
1481
1519
  * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
1482
1520
  */
@@ -1612,7 +1650,7 @@ var SimplePipelineCollection = /** @class */ (function () {
1612
1650
  pipelineJsonToString(unpreparePipeline(pipeline)) !==
1613
1651
  pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
1614
1652
  var existing = this.collection.get(pipeline.pipelineUrl);
1615
- throw new PipelineUrlError(spaceTrim$1("\n Pipeline with URL \"".concat(pipeline.pipelineUrl, "\" is already in the collection \uD83C\uDF4E\n\n Conflicting files:\n ").concat(existing.sourceFile || 'Unknown', "\n ").concat(pipeline.sourceFile || 'Unknown', "\n\n Note: You have probably forgotten to run \"ptbk make\" to update the collection\n Note: Pipelines with the same URL are not allowed\n Only exepction is when the pipelines are identical\n\n ")));
1653
+ throw new PipelineUrlError(spaceTrim$1("\n Pipeline with URL ".concat(pipeline.pipelineUrl, " is already in the collection \uD83C\uDF4E\n\n Conflicting files:\n ").concat(existing.sourceFile || 'Unknown', "\n ").concat(pipeline.sourceFile || 'Unknown', "\n\n Note: You have probably forgotten to run \"ptbk make\" to update the collection\n Note: Pipelines with the same URL are not allowed\n Only exepction is when the pipelines are identical\n\n ")));
1616
1654
  }
1617
1655
  // Note: [🧠] Overwrite existing pipeline with the same URL
1618
1656
  this.collection.set(pipeline.pipelineUrl, pipeline);
@@ -1796,7 +1834,7 @@ function createCollectionFromUrl(url, options) {
1796
1834
  });
1797
1835
  }
1798
1836
  /**
1799
- * TODO: [main] !!!! [🧠] Library precompilation and do not mix markdown and json promptbooks
1837
+ * TODO: [main] !!4 [🧠] Library precompilation and do not mix markdown and json promptbooks
1800
1838
  */
1801
1839
 
1802
1840
  /**
@@ -1866,7 +1904,7 @@ function createSubcollection(collection, predicate) {
1866
1904
  case 0: return [4 /*yield*/, collection.isResponsibleForPrompt(prompt)];
1867
1905
  case 1:
1868
1906
  isResponsible = _a.sent();
1869
- // TODO: !! Only if responsible, check if predicate is true
1907
+ // TODO: Only if responsible, check if predicate is true
1870
1908
  return [2 /*return*/, isResponsible];
1871
1909
  }
1872
1910
  });
@@ -1879,6 +1917,8 @@ function createSubcollection(collection, predicate) {
1879
1917
  };
1880
1918
  }
1881
1919
 
1920
+ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book.md`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book.md`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book.md"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book.md`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book.md"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book.md",formfactorName:"GENERIC",parameters:[{name:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book.md`\n- INPUT PARAMETER `{availableModelNames}` List of available model names separated by comma (,)\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n\\`\\`\\`json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelRequirements}`\n"}],sourceFile:"./books/prepare-persona.book.md"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book.md",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the task:\n\n> {book}\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Title starts with emoticon",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book.md`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the task:\n\n> {book}\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Title starts with emoticon\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book.md"}];
1921
+
1882
1922
  /**
1883
1923
  * This error type indicates that some tools are missing for pipeline execution or preparation
1884
1924
  *
@@ -1896,660 +1936,75 @@ var MissingToolsError = /** @class */ (function (_super) {
1896
1936
  }(Error));
1897
1937
 
1898
1938
  /**
1899
- * Async version of Array.forEach
1939
+ * This error indicates errors during the execution of the pipeline
1900
1940
  *
1901
- * @param array - Array to iterate over
1902
- * @param options - Options for the function
1903
- * @param callbackfunction - Function to call for each item
1904
- * @public exported from `@promptbook/utils`
1905
- * @deprecated [🪂] Use queues instead
1941
+ * @public exported from `@promptbook/core`
1906
1942
  */
1907
- function forEachAsync(array, options, callbackfunction) {
1908
- return __awaiter(this, void 0, void 0, function () {
1909
- var _a, maxParallelCount, index, runningTasks, tasks, _loop_1, _b, _c, item, e_1_1;
1910
- var e_1, _d;
1911
- return __generator(this, function (_e) {
1912
- switch (_e.label) {
1913
- case 0:
1914
- _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? Infinity : _a;
1915
- index = 0;
1916
- runningTasks = [];
1917
- tasks = [];
1918
- _loop_1 = function (item) {
1919
- var currentIndex, task;
1920
- return __generator(this, function (_f) {
1921
- switch (_f.label) {
1922
- case 0:
1923
- currentIndex = index++;
1924
- task = callbackfunction(item, currentIndex, array);
1925
- tasks.push(task);
1926
- runningTasks.push(task);
1927
- /* not await */ Promise.resolve(task).then(function () {
1928
- runningTasks = runningTasks.filter(function (t) { return t !== task; });
1929
- });
1930
- if (!(maxParallelCount < runningTasks.length)) return [3 /*break*/, 2];
1931
- return [4 /*yield*/, Promise.race(runningTasks)];
1932
- case 1:
1933
- _f.sent();
1934
- _f.label = 2;
1935
- case 2: return [2 /*return*/];
1936
- }
1937
- });
1938
- };
1939
- _e.label = 1;
1940
- case 1:
1941
- _e.trys.push([1, 6, 7, 8]);
1942
- _b = __values(array), _c = _b.next();
1943
- _e.label = 2;
1944
- case 2:
1945
- if (!!_c.done) return [3 /*break*/, 5];
1946
- item = _c.value;
1947
- return [5 /*yield**/, _loop_1(item)];
1948
- case 3:
1949
- _e.sent();
1950
- _e.label = 4;
1951
- case 4:
1952
- _c = _b.next();
1953
- return [3 /*break*/, 2];
1954
- case 5: return [3 /*break*/, 8];
1955
- case 6:
1956
- e_1_1 = _e.sent();
1957
- e_1 = { error: e_1_1 };
1958
- return [3 /*break*/, 8];
1959
- case 7:
1960
- try {
1961
- if (_c && !_c.done && (_d = _b.return)) _d.call(_b);
1962
- }
1963
- finally { if (e_1) throw e_1.error; }
1964
- return [7 /*endfinally*/];
1965
- case 8: return [4 /*yield*/, Promise.all(tasks)];
1966
- case 9:
1967
- _e.sent();
1968
- return [2 /*return*/];
1969
- }
1970
- });
1971
- });
1972
- }
1943
+ var PipelineExecutionError = /** @class */ (function (_super) {
1944
+ __extends(PipelineExecutionError, _super);
1945
+ function PipelineExecutionError(message) {
1946
+ var _this = _super.call(this, message) || this;
1947
+ _this.name = 'PipelineExecutionError';
1948
+ Object.setPrototypeOf(_this, PipelineExecutionError.prototype);
1949
+ return _this;
1950
+ }
1951
+ return PipelineExecutionError;
1952
+ }(Error));
1973
1953
 
1974
1954
  /**
1975
- * Represents the usage with no resources consumed
1955
+ * This error indicates problems parsing the format value
1956
+ *
1957
+ * For example, when the format value is not a valid JSON or CSV
1958
+ * This is not thrown directly but in extended classes
1976
1959
  *
1977
1960
  * @public exported from `@promptbook/core`
1978
1961
  */
1979
- var ZERO_USAGE = $deepFreeze({
1980
- price: { value: 0 },
1981
- input: {
1982
- tokensCount: { value: 0 },
1983
- charactersCount: { value: 0 },
1984
- wordsCount: { value: 0 },
1985
- sentencesCount: { value: 0 },
1986
- linesCount: { value: 0 },
1987
- paragraphsCount: { value: 0 },
1988
- pagesCount: { value: 0 },
1989
- },
1990
- output: {
1991
- tokensCount: { value: 0 },
1992
- charactersCount: { value: 0 },
1993
- wordsCount: { value: 0 },
1994
- sentencesCount: { value: 0 },
1995
- linesCount: { value: 0 },
1996
- paragraphsCount: { value: 0 },
1997
- pagesCount: { value: 0 },
1998
- },
1999
- });
1962
+ var AbstractFormatError = /** @class */ (function (_super) {
1963
+ __extends(AbstractFormatError, _super);
1964
+ // Note: To allow instanceof do not put here error `name`
1965
+ // public readonly name = 'AbstractFormatError';
1966
+ function AbstractFormatError(message) {
1967
+ var _this = _super.call(this, message) || this;
1968
+ Object.setPrototypeOf(_this, AbstractFormatError.prototype);
1969
+ return _this;
1970
+ }
1971
+ return AbstractFormatError;
1972
+ }(Error));
1973
+
2000
1974
  /**
2001
- * Represents the usage with unknown resources consumed
1975
+ * This error indicates problem with parsing of CSV
2002
1976
  *
2003
1977
  * @public exported from `@promptbook/core`
2004
1978
  */
2005
- var UNCERTAIN_USAGE = $deepFreeze({
2006
- price: { value: 0, isUncertain: true },
2007
- input: {
2008
- tokensCount: { value: 0, isUncertain: true },
2009
- charactersCount: { value: 0, isUncertain: true },
2010
- wordsCount: { value: 0, isUncertain: true },
2011
- sentencesCount: { value: 0, isUncertain: true },
2012
- linesCount: { value: 0, isUncertain: true },
2013
- paragraphsCount: { value: 0, isUncertain: true },
2014
- pagesCount: { value: 0, isUncertain: true },
2015
- },
2016
- output: {
2017
- tokensCount: { value: 0, isUncertain: true },
2018
- charactersCount: { value: 0, isUncertain: true },
2019
- wordsCount: { value: 0, isUncertain: true },
2020
- sentencesCount: { value: 0, isUncertain: true },
2021
- linesCount: { value: 0, isUncertain: true },
2022
- paragraphsCount: { value: 0, isUncertain: true },
2023
- pagesCount: { value: 0, isUncertain: true },
2024
- },
2025
- });
1979
+ var CsvFormatError = /** @class */ (function (_super) {
1980
+ __extends(CsvFormatError, _super);
1981
+ function CsvFormatError(message) {
1982
+ var _this = _super.call(this, message) || this;
1983
+ _this.name = 'CsvFormatError';
1984
+ Object.setPrototypeOf(_this, CsvFormatError.prototype);
1985
+ return _this;
1986
+ }
1987
+ return CsvFormatError;
1988
+ }(AbstractFormatError));
1989
+
2026
1990
  /**
2027
- * Note: [💞] Ignore a discrepancy between file name and entity name
1991
+ * This error indicates that the pipeline collection cannot be propperly loaded
1992
+ *
1993
+ * @public exported from `@promptbook/core`
2028
1994
  */
1995
+ var CollectionError = /** @class */ (function (_super) {
1996
+ __extends(CollectionError, _super);
1997
+ function CollectionError(message) {
1998
+ var _this = _super.call(this, message) || this;
1999
+ _this.name = 'CollectionError';
2000
+ Object.setPrototypeOf(_this, CollectionError.prototype);
2001
+ return _this;
2002
+ }
2003
+ return CollectionError;
2004
+ }(Error));
2029
2005
 
2030
2006
  /**
2031
- * Function `addUsage` will add multiple usages into one
2032
- *
2033
- * Note: If you provide 0 values, it returns ZERO_USAGE
2034
- *
2035
- * @public exported from `@promptbook/core`
2036
- */
2037
- function addUsage() {
2038
- var usageItems = [];
2039
- for (var _i = 0; _i < arguments.length; _i++) {
2040
- usageItems[_i] = arguments[_i];
2041
- }
2042
- return usageItems.reduce(function (acc, item) {
2043
- var e_1, _a, e_2, _b;
2044
- var _c;
2045
- acc.price.value += ((_c = item.price) === null || _c === void 0 ? void 0 : _c.value) || 0;
2046
- try {
2047
- for (var _d = __values(Object.keys(acc.input)), _e = _d.next(); !_e.done; _e = _d.next()) {
2048
- var key = _e.value;
2049
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2050
- //@ts-ignore
2051
- if (item.input[key]) {
2052
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2053
- //@ts-ignore
2054
- acc.input[key].value += item.input[key].value || 0;
2055
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2056
- //@ts-ignore
2057
- if (item.input[key].isUncertain) {
2058
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2059
- //@ts-ignore
2060
- acc.input[key].isUncertain = true;
2061
- }
2062
- }
2063
- }
2064
- }
2065
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
2066
- finally {
2067
- try {
2068
- if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
2069
- }
2070
- finally { if (e_1) throw e_1.error; }
2071
- }
2072
- try {
2073
- for (var _f = __values(Object.keys(acc.output)), _g = _f.next(); !_g.done; _g = _f.next()) {
2074
- var key = _g.value;
2075
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2076
- //@ts-ignore
2077
- if (item.output[key]) {
2078
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2079
- //@ts-ignore
2080
- acc.output[key].value += item.output[key].value || 0;
2081
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2082
- //@ts-ignore
2083
- if (item.output[key].isUncertain) {
2084
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2085
- //@ts-ignore
2086
- acc.output[key].isUncertain = true;
2087
- }
2088
- }
2089
- }
2090
- }
2091
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
2092
- finally {
2093
- try {
2094
- if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
2095
- }
2096
- finally { if (e_2) throw e_2.error; }
2097
- }
2098
- return acc;
2099
- }, deepClone(ZERO_USAGE));
2100
- }
2101
-
2102
- /**
2103
- * Intercepts LLM tools and counts total usage of the tools
2104
- *
2105
- * @param llmTools LLM tools to be intercepted with usage counting
2106
- * @returns LLM tools with same functionality with added total cost counting
2107
- * @public exported from `@promptbook/core`
2108
- */
2109
- function countTotalUsage(llmTools) {
2110
- var _this = this;
2111
- var totalUsage = ZERO_USAGE;
2112
- var proxyTools = {
2113
- get title() {
2114
- // TODO: [🧠] Maybe put here some suffix
2115
- return llmTools.title;
2116
- },
2117
- get description() {
2118
- // TODO: [🧠] Maybe put here some suffix
2119
- return llmTools.description;
2120
- },
2121
- checkConfiguration: function () {
2122
- return __awaiter(this, void 0, void 0, function () {
2123
- return __generator(this, function (_a) {
2124
- return [2 /*return*/, /* not await */ llmTools.checkConfiguration()];
2125
- });
2126
- });
2127
- },
2128
- listModels: function () {
2129
- return /* not await */ llmTools.listModels();
2130
- },
2131
- getTotalUsage: function () {
2132
- // <- Note: [🥫] Not using getter `get totalUsage` but `getTotalUsage` to allow this object to be proxied
2133
- return totalUsage;
2134
- },
2135
- };
2136
- if (llmTools.callChatModel !== undefined) {
2137
- proxyTools.callChatModel = function (prompt) { return __awaiter(_this, void 0, void 0, function () {
2138
- var promptResult;
2139
- return __generator(this, function (_a) {
2140
- switch (_a.label) {
2141
- case 0: return [4 /*yield*/, llmTools.callChatModel(prompt)];
2142
- case 1:
2143
- promptResult = _a.sent();
2144
- totalUsage = addUsage(totalUsage, promptResult.usage);
2145
- return [2 /*return*/, promptResult];
2146
- }
2147
- });
2148
- }); };
2149
- }
2150
- if (llmTools.callCompletionModel !== undefined) {
2151
- proxyTools.callCompletionModel = function (prompt) { return __awaiter(_this, void 0, void 0, function () {
2152
- var promptResult;
2153
- return __generator(this, function (_a) {
2154
- switch (_a.label) {
2155
- case 0: return [4 /*yield*/, llmTools.callCompletionModel(prompt)];
2156
- case 1:
2157
- promptResult = _a.sent();
2158
- totalUsage = addUsage(totalUsage, promptResult.usage);
2159
- return [2 /*return*/, promptResult];
2160
- }
2161
- });
2162
- }); };
2163
- }
2164
- if (llmTools.callEmbeddingModel !== undefined) {
2165
- proxyTools.callEmbeddingModel = function (prompt) { return __awaiter(_this, void 0, void 0, function () {
2166
- var promptResult;
2167
- return __generator(this, function (_a) {
2168
- switch (_a.label) {
2169
- case 0: return [4 /*yield*/, llmTools.callEmbeddingModel(prompt)];
2170
- case 1:
2171
- promptResult = _a.sent();
2172
- totalUsage = addUsage(totalUsage, promptResult.usage);
2173
- return [2 /*return*/, promptResult];
2174
- }
2175
- });
2176
- }); };
2177
- }
2178
- // <- Note: [🤖]
2179
- return proxyTools;
2180
- }
2181
- /**
2182
- * TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
2183
- * TODO: [🧠] Is there some meaningfull way how to test this util
2184
- * TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
2185
- * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
2186
- * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2187
- */
2188
-
2189
- /**
2190
- * This error indicates errors during the execution of the pipeline
2191
- *
2192
- * @public exported from `@promptbook/core`
2193
- */
2194
- var PipelineExecutionError = /** @class */ (function (_super) {
2195
- __extends(PipelineExecutionError, _super);
2196
- function PipelineExecutionError(message) {
2197
- var _this = _super.call(this, message) || this;
2198
- _this.name = 'PipelineExecutionError';
2199
- Object.setPrototypeOf(_this, PipelineExecutionError.prototype);
2200
- return _this;
2201
- }
2202
- return PipelineExecutionError;
2203
- }(Error));
2204
-
2205
- /**
2206
- * Multiple LLM Execution Tools is a proxy server that uses multiple execution tools internally and exposes the executor interface externally.
2207
- *
2208
- * Note: Internal utility of `joinLlmExecutionTools` but exposed type
2209
- * @public exported from `@promptbook/core`
2210
- */
2211
- var MultipleLlmExecutionTools = /** @class */ (function () {
2212
- /**
2213
- * Gets array of execution tools in order of priority
2214
- */
2215
- function MultipleLlmExecutionTools() {
2216
- var llmExecutionTools = [];
2217
- for (var _i = 0; _i < arguments.length; _i++) {
2218
- llmExecutionTools[_i] = arguments[_i];
2219
- }
2220
- this.llmExecutionTools = llmExecutionTools;
2221
- }
2222
- Object.defineProperty(MultipleLlmExecutionTools.prototype, "title", {
2223
- get: function () {
2224
- return 'Multiple LLM Providers';
2225
- },
2226
- enumerable: false,
2227
- configurable: true
2228
- });
2229
- Object.defineProperty(MultipleLlmExecutionTools.prototype, "description", {
2230
- get: function () {
2231
- return this.llmExecutionTools.map(function (_a, index) {
2232
- var title = _a.title;
2233
- return "".concat(index + 1, ") `").concat(title, "`");
2234
- }).join('\n');
2235
- },
2236
- enumerable: false,
2237
- configurable: true
2238
- });
2239
- /**
2240
- * Check the configuration of all execution tools
2241
- */
2242
- MultipleLlmExecutionTools.prototype.checkConfiguration = function () {
2243
- return __awaiter(this, void 0, void 0, function () {
2244
- var _a, _b, llmExecutionTools, e_1_1;
2245
- var e_1, _c;
2246
- return __generator(this, function (_d) {
2247
- switch (_d.label) {
2248
- case 0:
2249
- _d.trys.push([0, 5, 6, 7]);
2250
- _a = __values(this.llmExecutionTools), _b = _a.next();
2251
- _d.label = 1;
2252
- case 1:
2253
- if (!!_b.done) return [3 /*break*/, 4];
2254
- llmExecutionTools = _b.value;
2255
- return [4 /*yield*/, llmExecutionTools.checkConfiguration()];
2256
- case 2:
2257
- _d.sent();
2258
- _d.label = 3;
2259
- case 3:
2260
- _b = _a.next();
2261
- return [3 /*break*/, 1];
2262
- case 4: return [3 /*break*/, 7];
2263
- case 5:
2264
- e_1_1 = _d.sent();
2265
- e_1 = { error: e_1_1 };
2266
- return [3 /*break*/, 7];
2267
- case 6:
2268
- try {
2269
- if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
2270
- }
2271
- finally { if (e_1) throw e_1.error; }
2272
- return [7 /*endfinally*/];
2273
- case 7: return [2 /*return*/];
2274
- }
2275
- });
2276
- });
2277
- };
2278
- /**
2279
- * List all available models that can be used
2280
- * This lists is a combination of all available models from all execution tools
2281
- */
2282
- MultipleLlmExecutionTools.prototype.listModels = function () {
2283
- return __awaiter(this, void 0, void 0, function () {
2284
- var availableModels, _a, _b, llmExecutionTools, models, e_2_1;
2285
- var e_2, _c;
2286
- return __generator(this, function (_d) {
2287
- switch (_d.label) {
2288
- case 0:
2289
- availableModels = [];
2290
- _d.label = 1;
2291
- case 1:
2292
- _d.trys.push([1, 6, 7, 8]);
2293
- _a = __values(this.llmExecutionTools), _b = _a.next();
2294
- _d.label = 2;
2295
- case 2:
2296
- if (!!_b.done) return [3 /*break*/, 5];
2297
- llmExecutionTools = _b.value;
2298
- return [4 /*yield*/, llmExecutionTools.listModels()];
2299
- case 3:
2300
- models = _d.sent();
2301
- availableModels.push.apply(availableModels, __spreadArray([], __read(models), false));
2302
- _d.label = 4;
2303
- case 4:
2304
- _b = _a.next();
2305
- return [3 /*break*/, 2];
2306
- case 5: return [3 /*break*/, 8];
2307
- case 6:
2308
- e_2_1 = _d.sent();
2309
- e_2 = { error: e_2_1 };
2310
- return [3 /*break*/, 8];
2311
- case 7:
2312
- try {
2313
- if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
2314
- }
2315
- finally { if (e_2) throw e_2.error; }
2316
- return [7 /*endfinally*/];
2317
- case 8: return [2 /*return*/, availableModels];
2318
- }
2319
- });
2320
- });
2321
- };
2322
- /**
2323
- * Calls the best available chat model
2324
- */
2325
- MultipleLlmExecutionTools.prototype.callChatModel = function (prompt) {
2326
- return this.callCommonModel(prompt);
2327
- };
2328
- /**
2329
- * Calls the best available completion model
2330
- */
2331
- MultipleLlmExecutionTools.prototype.callCompletionModel = function (prompt) {
2332
- return this.callCommonModel(prompt);
2333
- };
2334
- /**
2335
- * Calls the best available embedding model
2336
- */
2337
- MultipleLlmExecutionTools.prototype.callEmbeddingModel = function (prompt) {
2338
- return this.callCommonModel(prompt);
2339
- };
2340
- // <- Note: [🤖]
2341
- /**
2342
- * Calls the best available model
2343
- *
2344
- * Note: This should be private or protected but is public to be usable with duck typing
2345
- */
2346
- MultipleLlmExecutionTools.prototype.callCommonModel = function (prompt) {
2347
- return __awaiter(this, void 0, void 0, function () {
2348
- var errors, _a, _b, llmExecutionTools, _c, error_1, e_3_1;
2349
- var e_3, _d;
2350
- var _this = this;
2351
- return __generator(this, function (_e) {
2352
- switch (_e.label) {
2353
- case 0:
2354
- errors = [];
2355
- _e.label = 1;
2356
- case 1:
2357
- _e.trys.push([1, 15, 16, 17]);
2358
- _a = __values(this.llmExecutionTools), _b = _a.next();
2359
- _e.label = 2;
2360
- case 2:
2361
- if (!!_b.done) return [3 /*break*/, 14];
2362
- llmExecutionTools = _b.value;
2363
- _e.label = 3;
2364
- case 3:
2365
- _e.trys.push([3, 12, , 13]);
2366
- _c = prompt.modelRequirements.modelVariant;
2367
- switch (_c) {
2368
- case 'CHAT': return [3 /*break*/, 4];
2369
- case 'COMPLETION': return [3 /*break*/, 6];
2370
- case 'EMBEDDING': return [3 /*break*/, 8];
2371
- }
2372
- return [3 /*break*/, 10];
2373
- case 4:
2374
- if (llmExecutionTools.callChatModel === undefined) {
2375
- return [3 /*break*/, 13];
2376
- }
2377
- return [4 /*yield*/, llmExecutionTools.callChatModel(prompt)];
2378
- case 5: return [2 /*return*/, _e.sent()];
2379
- case 6:
2380
- if (llmExecutionTools.callCompletionModel === undefined) {
2381
- return [3 /*break*/, 13];
2382
- }
2383
- return [4 /*yield*/, llmExecutionTools.callCompletionModel(prompt)];
2384
- case 7: return [2 /*return*/, _e.sent()];
2385
- case 8:
2386
- if (llmExecutionTools.callEmbeddingModel === undefined) {
2387
- return [3 /*break*/, 13];
2388
- }
2389
- return [4 /*yield*/, llmExecutionTools.callEmbeddingModel(prompt)];
2390
- case 9: return [2 /*return*/, _e.sent()];
2391
- case 10: throw new UnexpectedError("Unknown model variant \"".concat(prompt.modelRequirements.modelVariant, "\""));
2392
- case 11: return [3 /*break*/, 13];
2393
- case 12:
2394
- error_1 = _e.sent();
2395
- if (!(error_1 instanceof Error) || error_1 instanceof UnexpectedError) {
2396
- throw error_1;
2397
- }
2398
- errors.push(error_1);
2399
- return [3 /*break*/, 13];
2400
- case 13:
2401
- _b = _a.next();
2402
- return [3 /*break*/, 2];
2403
- case 14: return [3 /*break*/, 17];
2404
- case 15:
2405
- e_3_1 = _e.sent();
2406
- e_3 = { error: e_3_1 };
2407
- return [3 /*break*/, 17];
2408
- case 16:
2409
- try {
2410
- if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
2411
- }
2412
- finally { if (e_3) throw e_3.error; }
2413
- return [7 /*endfinally*/];
2414
- case 17:
2415
- if (errors.length === 1) {
2416
- throw errors[0];
2417
- }
2418
- else if (errors.length > 1) {
2419
- throw new PipelineExecutionError(
2420
- // TODO: Tell which execution tools failed like
2421
- // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
2422
- // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
2423
- // 3) ...
2424
- spaceTrim(function (block) { return "\n All execution tools failed:\n\n ".concat(block(errors
2425
- .map(function (error, i) { return "".concat(i + 1, ") **").concat(error.name || 'Error', ":** ").concat(error.message); })
2426
- .join('\n')), "\n\n "); }));
2427
- }
2428
- else if (this.llmExecutionTools.length === 0) {
2429
- throw new PipelineExecutionError("You have not provided any `LlmExecutionTools`");
2430
- }
2431
- else {
2432
- throw new PipelineExecutionError(spaceTrim(function (block) { return "\n You have not provided any `LlmExecutionTools` that support model variant \"".concat(prompt.modelRequirements.modelVariant, "\"\n\n Available `LlmExecutionTools`:\n ").concat(block(_this.description), "\n\n "); }));
2433
- }
2434
- }
2435
- });
2436
- });
2437
- };
2438
- return MultipleLlmExecutionTools;
2439
- }());
2440
- /**
2441
- * TODO: [🧠][🎛] Aggregating multiple models - have result not only from one first aviable model BUT all of them
2442
- * TODO: [🏖] If no llmTools have for example not defined `callCompletionModel` this will still return object with defined `callCompletionModel` which just throws `PipelineExecutionError`, make it undefined instead
2443
- * Look how `countTotalUsage` (and `cacheLlmTools`) implements it
2444
- */
2445
-
2446
- /**
2447
- * Joins multiple LLM Execution Tools into one
2448
- *
2449
- * @returns {LlmExecutionTools} Single wrapper for multiple LlmExecutionTools
2450
- *
2451
- * 0) If there is no LlmExecutionTools, it warns and returns valid but empty LlmExecutionTools
2452
- * 1) If there is only one LlmExecutionTools, it returns it wrapped in a proxy object
2453
- * 2) If there are multiple LlmExecutionTools, first will be used first, second will be used if the first hasn`t defined model variant or fails, etc.
2454
- * 3) When all LlmExecutionTools fail, it throws an error with a list of all errors merged into one
2455
- *
2456
- *
2457
- * Tip: You don't have to use this function directly, just pass an array of LlmExecutionTools to the `ExecutionTools`
2458
- *
2459
- * @public exported from `@promptbook/core`
2460
- */
2461
- function joinLlmExecutionTools() {
2462
- var llmExecutionTools = [];
2463
- for (var _i = 0; _i < arguments.length; _i++) {
2464
- llmExecutionTools[_i] = arguments[_i];
2465
- }
2466
- if (llmExecutionTools.length === 0) {
2467
- var warningMessage = spaceTrim("\n You have not provided any `LlmExecutionTools`\n This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.\n\n Technically, it's not an error, but it's probably not what you want because it does not make sense to use Promptbook without language models.\n ");
2468
- // TODO: [🟥] Detect browser / node and make it colorfull
2469
- console.warn(warningMessage);
2470
- /*
2471
- return {
2472
- async listModels() {
2473
- // TODO: [🟥] Detect browser / node and make it colorfull
2474
- console.warn(
2475
- spaceTrim(
2476
- (block) => `
2477
-
2478
- You can't list models because you have no LLM Execution Tools defined:
2479
-
2480
- tl;dr
2481
-
2482
- ${block(warningMessage)}
2483
- `,
2484
- ),
2485
- );
2486
- return [];
2487
- },
2488
- };
2489
- */
2490
- }
2491
- return new (MultipleLlmExecutionTools.bind.apply(MultipleLlmExecutionTools, __spreadArray([void 0], __read(llmExecutionTools), false)))();
2492
- }
2493
- /**
2494
- * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2495
- */
2496
-
2497
- var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book.md`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book.md`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book.md"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book.md`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book.md",formfactorName:"GENERIC",parameters:[{name:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book.md`\n- INPUT PARAMETER `{availableModelNames}` List of available model names separated by comma (,)\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n\\`\\`\\`json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelRequirements}`\n"}],sourceFile:"./books/prepare-persona.book.md"}];
2498
-
2499
- /**
2500
- * This error indicates problems parsing the format value
2501
- *
2502
- * For example, when the format value is not a valid JSON or CSV
2503
- * This is not thrown directly but in extended classes
2504
- *
2505
- * @public exported from `@promptbook/core`
2506
- */
2507
- var AbstractFormatError = /** @class */ (function (_super) {
2508
- __extends(AbstractFormatError, _super);
2509
- // Note: To allow instanceof do not put here error `name`
2510
- // public readonly name = 'AbstractFormatError';
2511
- function AbstractFormatError(message) {
2512
- var _this = _super.call(this, message) || this;
2513
- Object.setPrototypeOf(_this, AbstractFormatError.prototype);
2514
- return _this;
2515
- }
2516
- return AbstractFormatError;
2517
- }(Error));
2518
-
2519
- /**
2520
- * This error indicates problem with parsing of CSV
2521
- *
2522
- * @public exported from `@promptbook/core`
2523
- */
2524
- var CsvFormatError = /** @class */ (function (_super) {
2525
- __extends(CsvFormatError, _super);
2526
- function CsvFormatError(message) {
2527
- var _this = _super.call(this, message) || this;
2528
- _this.name = 'CsvFormatError';
2529
- Object.setPrototypeOf(_this, CsvFormatError.prototype);
2530
- return _this;
2531
- }
2532
- return CsvFormatError;
2533
- }(AbstractFormatError));
2534
-
2535
- /**
2536
- * This error indicates that the pipeline collection cannot be propperly loaded
2537
- *
2538
- * @public exported from `@promptbook/core`
2539
- */
2540
- var CollectionError = /** @class */ (function (_super) {
2541
- __extends(CollectionError, _super);
2542
- function CollectionError(message) {
2543
- var _this = _super.call(this, message) || this;
2544
- _this.name = 'CollectionError';
2545
- Object.setPrototypeOf(_this, CollectionError.prototype);
2546
- return _this;
2547
- }
2548
- return CollectionError;
2549
- }(Error));
2550
-
2551
- /**
2552
- * This error type indicates that you try to use a feature that is not available in the current environment
2007
+ * This error type indicates that you try to use a feature that is not available in the current environment
2553
2008
  *
2554
2009
  * @public exported from `@promptbook/core`
2555
2010
  */
@@ -2735,11 +2190,16 @@ function assertsExecutionSuccessful(executionResult) {
2735
2190
  /**
2736
2191
  * Determine if the pipeline is fully prepared
2737
2192
  *
2193
+ * @see https://github.com/webgptorg/promptbook/discussions/196
2194
+ *
2738
2195
  * @public exported from `@promptbook/core`
2739
2196
  */
2740
2197
  function isPipelinePrepared(pipeline) {
2741
2198
  // Note: Ignoring `pipeline.preparations` @@@
2742
2199
  // Note: Ignoring `pipeline.knowledgePieces` @@@
2200
+ if (pipeline.title === undefined || pipeline.title === '' || pipeline.title === DEFAULT_BOOK_TITLE) {
2201
+ return false;
2202
+ }
2743
2203
  if (!pipeline.personas.every(function (persona) { return persona.modelRequirements !== undefined; })) {
2744
2204
  return false;
2745
2205
  }
@@ -2755,7 +2215,7 @@ function isPipelinePrepared(pipeline) {
2755
2215
  return true;
2756
2216
  }
2757
2217
  /**
2758
- * TODO: [🔃][main] !! If the pipeline was prepared with different version or different set of models, prepare it once again
2218
+ * TODO: [🔃][main] If the pipeline was prepared with different version or different set of models, prepare it once again
2759
2219
  * TODO: [🐠] Maybe base this on `makeValidator`
2760
2220
  * TODO: [🧊] Pipeline can be partially prepared, this should return true ONLY if fully prepared
2761
2221
  * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
@@ -2764,6 +2224,81 @@ function isPipelinePrepared(pipeline) {
2764
2224
  * - [♨] Are tasks prepared
2765
2225
  */
2766
2226
 
2227
+ /**
2228
+ * Format either small or big number
2229
+ *
2230
+ * @public exported from `@promptbook/utils`
2231
+ */
2232
+ function numberToString(value) {
2233
+ if (value === 0) {
2234
+ return '0';
2235
+ }
2236
+ else if (Number.isNaN(value)) {
2237
+ return VALUE_STRINGS.nan;
2238
+ }
2239
+ else if (value === Infinity) {
2240
+ return VALUE_STRINGS.infinity;
2241
+ }
2242
+ else if (value === -Infinity) {
2243
+ return VALUE_STRINGS.negativeInfinity;
2244
+ }
2245
+ for (var exponent = 0; exponent < 15; exponent++) {
2246
+ var factor = Math.pow(10, exponent);
2247
+ var valueRounded = Math.round(value * factor) / factor;
2248
+ if (Math.abs(value - valueRounded) / value < SMALL_NUMBER) {
2249
+ return valueRounded.toFixed(exponent);
2250
+ }
2251
+ }
2252
+ return value.toString();
2253
+ }
2254
+
2255
+ /**
2256
+ * Function `valueToString` will convert the given value to string
2257
+ * This is useful and used in the `templateParameters` function
2258
+ *
2259
+ * Note: This function is not just calling `toString` method
2260
+ * It's more complex and can handle this conversion specifically for LLM models
2261
+ * See `VALUE_STRINGS`
2262
+ *
2263
+ * Note: There are 2 similar functions
2264
+ * - `valueToString` converts value to string for LLM models as human-readable string
2265
+ * - `asSerializable` converts value to string to preserve full information to be able to convert it back
2266
+ *
2267
+ * @public exported from `@promptbook/utils`
2268
+ */
2269
+ function valueToString(value) {
2270
+ try {
2271
+ if (value === '') {
2272
+ return VALUE_STRINGS.empty;
2273
+ }
2274
+ else if (value === null) {
2275
+ return VALUE_STRINGS.null;
2276
+ }
2277
+ else if (value === undefined) {
2278
+ return VALUE_STRINGS.undefined;
2279
+ }
2280
+ else if (typeof value === 'string') {
2281
+ return value;
2282
+ }
2283
+ else if (typeof value === 'number') {
2284
+ return numberToString(value);
2285
+ }
2286
+ else if (value instanceof Date) {
2287
+ return value.toISOString();
2288
+ }
2289
+ else {
2290
+ return JSON.stringify(value);
2291
+ }
2292
+ }
2293
+ catch (error) {
2294
+ if (!(error instanceof Error)) {
2295
+ throw error;
2296
+ }
2297
+ console.error(error);
2298
+ return VALUE_STRINGS.unserializable;
2299
+ }
2300
+ }
2301
+
2767
2302
  /**
2768
2303
  * Serializes an error into a [🚉] JSON-serializable object
2769
2304
  *
@@ -2781,6 +2316,134 @@ function serializeError(error) {
2781
2316
  };
2782
2317
  }
2783
2318
 
2319
+ /**
2320
+ * Represents the usage with no resources consumed
2321
+ *
2322
+ * @public exported from `@promptbook/core`
2323
+ */
2324
+ var ZERO_USAGE = $deepFreeze({
2325
+ price: { value: 0 },
2326
+ input: {
2327
+ tokensCount: { value: 0 },
2328
+ charactersCount: { value: 0 },
2329
+ wordsCount: { value: 0 },
2330
+ sentencesCount: { value: 0 },
2331
+ linesCount: { value: 0 },
2332
+ paragraphsCount: { value: 0 },
2333
+ pagesCount: { value: 0 },
2334
+ },
2335
+ output: {
2336
+ tokensCount: { value: 0 },
2337
+ charactersCount: { value: 0 },
2338
+ wordsCount: { value: 0 },
2339
+ sentencesCount: { value: 0 },
2340
+ linesCount: { value: 0 },
2341
+ paragraphsCount: { value: 0 },
2342
+ pagesCount: { value: 0 },
2343
+ },
2344
+ });
2345
+ /**
2346
+ * Represents the usage with unknown resources consumed
2347
+ *
2348
+ * @public exported from `@promptbook/core`
2349
+ */
2350
+ var UNCERTAIN_USAGE = $deepFreeze({
2351
+ price: { value: 0, isUncertain: true },
2352
+ input: {
2353
+ tokensCount: { value: 0, isUncertain: true },
2354
+ charactersCount: { value: 0, isUncertain: true },
2355
+ wordsCount: { value: 0, isUncertain: true },
2356
+ sentencesCount: { value: 0, isUncertain: true },
2357
+ linesCount: { value: 0, isUncertain: true },
2358
+ paragraphsCount: { value: 0, isUncertain: true },
2359
+ pagesCount: { value: 0, isUncertain: true },
2360
+ },
2361
+ output: {
2362
+ tokensCount: { value: 0, isUncertain: true },
2363
+ charactersCount: { value: 0, isUncertain: true },
2364
+ wordsCount: { value: 0, isUncertain: true },
2365
+ sentencesCount: { value: 0, isUncertain: true },
2366
+ linesCount: { value: 0, isUncertain: true },
2367
+ paragraphsCount: { value: 0, isUncertain: true },
2368
+ pagesCount: { value: 0, isUncertain: true },
2369
+ },
2370
+ });
2371
+ /**
2372
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2373
+ */
2374
+
2375
+ /**
2376
+ * Function `addUsage` will add multiple usages into one
2377
+ *
2378
+ * Note: If you provide 0 values, it returns ZERO_USAGE
2379
+ *
2380
+ * @public exported from `@promptbook/core`
2381
+ */
2382
+ function addUsage() {
2383
+ var usageItems = [];
2384
+ for (var _i = 0; _i < arguments.length; _i++) {
2385
+ usageItems[_i] = arguments[_i];
2386
+ }
2387
+ return usageItems.reduce(function (acc, item) {
2388
+ var e_1, _a, e_2, _b;
2389
+ var _c;
2390
+ acc.price.value += ((_c = item.price) === null || _c === void 0 ? void 0 : _c.value) || 0;
2391
+ try {
2392
+ for (var _d = __values(Object.keys(acc.input)), _e = _d.next(); !_e.done; _e = _d.next()) {
2393
+ var key = _e.value;
2394
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2395
+ //@ts-ignore
2396
+ if (item.input[key]) {
2397
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2398
+ //@ts-ignore
2399
+ acc.input[key].value += item.input[key].value || 0;
2400
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2401
+ //@ts-ignore
2402
+ if (item.input[key].isUncertain) {
2403
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2404
+ //@ts-ignore
2405
+ acc.input[key].isUncertain = true;
2406
+ }
2407
+ }
2408
+ }
2409
+ }
2410
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2411
+ finally {
2412
+ try {
2413
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
2414
+ }
2415
+ finally { if (e_1) throw e_1.error; }
2416
+ }
2417
+ try {
2418
+ for (var _f = __values(Object.keys(acc.output)), _g = _f.next(); !_g.done; _g = _f.next()) {
2419
+ var key = _g.value;
2420
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2421
+ //@ts-ignore
2422
+ if (item.output[key]) {
2423
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2424
+ //@ts-ignore
2425
+ acc.output[key].value += item.output[key].value || 0;
2426
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2427
+ //@ts-ignore
2428
+ if (item.output[key].isUncertain) {
2429
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
2430
+ //@ts-ignore
2431
+ acc.output[key].isUncertain = true;
2432
+ }
2433
+ }
2434
+ }
2435
+ }
2436
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
2437
+ finally {
2438
+ try {
2439
+ if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
2440
+ }
2441
+ finally { if (e_2) throw e_2.error; }
2442
+ }
2443
+ return acc;
2444
+ }, deepClone(ZERO_USAGE));
2445
+ }
2446
+
2784
2447
  /**
2785
2448
  * Parses the given script and returns the list of all used variables that are not defined in the script
2786
2449
  *
@@ -2835,7 +2498,7 @@ function extractVariablesFromScript(script) {
2835
2498
  if (!(error instanceof Error)) {
2836
2499
  throw error;
2837
2500
  }
2838
- throw new ParseError(spaceTrim$1(function (block) { return "\n Can not extract variables from the script\n\n ".concat(block(error.toString()), "}\n\n\n Found variables:\n\n ").concat(Array.from(variables)
2501
+ throw new ParseError(spaceTrim$1(function (block) { return "\n Can not extract variables from the script\n ".concat(block(error.stack || error.message), "\n\n Found variables:\n ").concat(Array.from(variables)
2839
2502
  .map(function (variableName, i) { return "".concat(i + 1, ") ").concat(variableName); })
2840
2503
  .join('\n'), "\n\n\n The script:\n\n ```javascript\n ").concat(block(originalScript), "\n ```\n "); }));
2841
2504
  }
@@ -3100,41 +2763,20 @@ var CsvFormatDefinition = {
3100
2763
  case 1:
3101
2764
  mappedData = _a.sent();
3102
2765
  return [2 /*return*/, unparse(mappedData, __assign(__assign({}, settings), MANDATORY_CSV_SETTINGS))];
3103
- }
3104
- });
3105
- });
3106
- },
3107
- },
3108
- ],
3109
- };
3110
- /**
3111
- * TODO: [🍓] In `CsvFormatDefinition` implement simple `isValid`
3112
- * TODO: [🍓] In `CsvFormatDefinition` implement partial `canBeValid`
3113
- * TODO: [🍓] In `CsvFormatDefinition` implement `heal
3114
- * TODO: [🍓] In `CsvFormatDefinition` implement `subvalueDefinitions`
3115
- * TODO: [🏢] Allow to expect something inside CSV objects and other formats
3116
- */
3117
-
3118
- /**
3119
- * Function isValidJsonString will tell you if the string is valid JSON or not
3120
- *
3121
- * @public exported from `@promptbook/utils`
3122
- */
3123
- function isValidJsonString(value /* <- [👨‍⚖️] */) {
3124
- try {
3125
- JSON.parse(value);
3126
- return true;
3127
- }
3128
- catch (error) {
3129
- if (!(error instanceof Error)) {
3130
- throw error;
3131
- }
3132
- if (error.message.includes('Unexpected token')) {
3133
- return false;
3134
- }
3135
- return false;
3136
- }
3137
- }
2766
+ }
2767
+ });
2768
+ });
2769
+ },
2770
+ },
2771
+ ],
2772
+ };
2773
+ /**
2774
+ * TODO: [🍓] In `CsvFormatDefinition` implement simple `isValid`
2775
+ * TODO: [🍓] In `CsvFormatDefinition` implement partial `canBeValid`
2776
+ * TODO: [🍓] In `CsvFormatDefinition` implement `heal
2777
+ * TODO: [🍓] In `CsvFormatDefinition` implement `subvalueDefinitions`
2778
+ * TODO: [🏢] Allow to expect something inside CSV objects and other formats
2779
+ */
3138
2780
 
3139
2781
  /**
3140
2782
  * Definition for JSON format
@@ -3328,15 +2970,307 @@ function mapAvailableToExpectedParameters(options) {
3328
2970
  .map(function (parameterName) { return "- {".concat(parameterName, "}"); })
3329
2971
  .join('\n')), "\n\n "); }));
3330
2972
  }
3331
- var expectedParameterNamesArray = Array.from(expectedParameterNames);
3332
- var availableParametersNamesArray = Array.from(availableParametersNames);
3333
- for (var i = 0; i < expectedParameterNames.size; i++) {
3334
- mappedParameters[expectedParameterNamesArray[i]] = availableParameters[availableParametersNamesArray[i]];
2973
+ var expectedParameterNamesArray = Array.from(expectedParameterNames);
2974
+ var availableParametersNamesArray = Array.from(availableParametersNames);
2975
+ for (var i = 0; i < expectedParameterNames.size; i++) {
2976
+ mappedParameters[expectedParameterNamesArray[i]] = availableParameters[availableParametersNamesArray[i]];
2977
+ }
2978
+ // Note: [👨‍👨‍👧] Now we can freeze `mappedParameters` to prevent @@@
2979
+ Object.freeze(mappedParameters);
2980
+ return mappedParameters;
2981
+ }
2982
+
2983
+ /**
2984
+ * Multiple LLM Execution Tools is a proxy server that uses multiple execution tools internally and exposes the executor interface externally.
2985
+ *
2986
+ * Note: Internal utility of `joinLlmExecutionTools` but exposed type
2987
+ * @public exported from `@promptbook/core`
2988
+ */
2989
+ var MultipleLlmExecutionTools = /** @class */ (function () {
2990
+ /**
2991
+ * Gets array of execution tools in order of priority
2992
+ */
2993
+ function MultipleLlmExecutionTools() {
2994
+ var llmExecutionTools = [];
2995
+ for (var _i = 0; _i < arguments.length; _i++) {
2996
+ llmExecutionTools[_i] = arguments[_i];
2997
+ }
2998
+ this.llmExecutionTools = llmExecutionTools;
2999
+ }
3000
+ Object.defineProperty(MultipleLlmExecutionTools.prototype, "title", {
3001
+ get: function () {
3002
+ return 'Multiple LLM Providers';
3003
+ },
3004
+ enumerable: false,
3005
+ configurable: true
3006
+ });
3007
+ Object.defineProperty(MultipleLlmExecutionTools.prototype, "description", {
3008
+ get: function () {
3009
+ return this.llmExecutionTools.map(function (_a, index) {
3010
+ var title = _a.title;
3011
+ return "".concat(index + 1, ") `").concat(title, "`");
3012
+ }).join('\n');
3013
+ },
3014
+ enumerable: false,
3015
+ configurable: true
3016
+ });
3017
+ /**
3018
+ * Check the configuration of all execution tools
3019
+ */
3020
+ MultipleLlmExecutionTools.prototype.checkConfiguration = function () {
3021
+ return __awaiter(this, void 0, void 0, function () {
3022
+ var _a, _b, llmExecutionTools, e_1_1;
3023
+ var e_1, _c;
3024
+ return __generator(this, function (_d) {
3025
+ switch (_d.label) {
3026
+ case 0:
3027
+ _d.trys.push([0, 5, 6, 7]);
3028
+ _a = __values(this.llmExecutionTools), _b = _a.next();
3029
+ _d.label = 1;
3030
+ case 1:
3031
+ if (!!_b.done) return [3 /*break*/, 4];
3032
+ llmExecutionTools = _b.value;
3033
+ return [4 /*yield*/, llmExecutionTools.checkConfiguration()];
3034
+ case 2:
3035
+ _d.sent();
3036
+ _d.label = 3;
3037
+ case 3:
3038
+ _b = _a.next();
3039
+ return [3 /*break*/, 1];
3040
+ case 4: return [3 /*break*/, 7];
3041
+ case 5:
3042
+ e_1_1 = _d.sent();
3043
+ e_1 = { error: e_1_1 };
3044
+ return [3 /*break*/, 7];
3045
+ case 6:
3046
+ try {
3047
+ if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
3048
+ }
3049
+ finally { if (e_1) throw e_1.error; }
3050
+ return [7 /*endfinally*/];
3051
+ case 7: return [2 /*return*/];
3052
+ }
3053
+ });
3054
+ });
3055
+ };
3056
+ /**
3057
+ * List all available models that can be used
3058
+ * This lists is a combination of all available models from all execution tools
3059
+ */
3060
+ MultipleLlmExecutionTools.prototype.listModels = function () {
3061
+ return __awaiter(this, void 0, void 0, function () {
3062
+ var availableModels, _a, _b, llmExecutionTools, models, e_2_1;
3063
+ var e_2, _c;
3064
+ return __generator(this, function (_d) {
3065
+ switch (_d.label) {
3066
+ case 0:
3067
+ availableModels = [];
3068
+ _d.label = 1;
3069
+ case 1:
3070
+ _d.trys.push([1, 6, 7, 8]);
3071
+ _a = __values(this.llmExecutionTools), _b = _a.next();
3072
+ _d.label = 2;
3073
+ case 2:
3074
+ if (!!_b.done) return [3 /*break*/, 5];
3075
+ llmExecutionTools = _b.value;
3076
+ return [4 /*yield*/, llmExecutionTools.listModels()];
3077
+ case 3:
3078
+ models = _d.sent();
3079
+ availableModels.push.apply(availableModels, __spreadArray([], __read(models), false));
3080
+ _d.label = 4;
3081
+ case 4:
3082
+ _b = _a.next();
3083
+ return [3 /*break*/, 2];
3084
+ case 5: return [3 /*break*/, 8];
3085
+ case 6:
3086
+ e_2_1 = _d.sent();
3087
+ e_2 = { error: e_2_1 };
3088
+ return [3 /*break*/, 8];
3089
+ case 7:
3090
+ try {
3091
+ if (_b && !_b.done && (_c = _a.return)) _c.call(_a);
3092
+ }
3093
+ finally { if (e_2) throw e_2.error; }
3094
+ return [7 /*endfinally*/];
3095
+ case 8: return [2 /*return*/, availableModels];
3096
+ }
3097
+ });
3098
+ });
3099
+ };
3100
+ /**
3101
+ * Calls the best available chat model
3102
+ */
3103
+ MultipleLlmExecutionTools.prototype.callChatModel = function (prompt) {
3104
+ return this.callCommonModel(prompt);
3105
+ };
3106
+ /**
3107
+ * Calls the best available completion model
3108
+ */
3109
+ MultipleLlmExecutionTools.prototype.callCompletionModel = function (prompt) {
3110
+ return this.callCommonModel(prompt);
3111
+ };
3112
+ /**
3113
+ * Calls the best available embedding model
3114
+ */
3115
+ MultipleLlmExecutionTools.prototype.callEmbeddingModel = function (prompt) {
3116
+ return this.callCommonModel(prompt);
3117
+ };
3118
+ // <- Note: [🤖]
3119
+ /**
3120
+ * Calls the best available model
3121
+ *
3122
+ * Note: This should be private or protected but is public to be usable with duck typing
3123
+ */
3124
+ MultipleLlmExecutionTools.prototype.callCommonModel = function (prompt) {
3125
+ return __awaiter(this, void 0, void 0, function () {
3126
+ var errors, _a, _b, llmExecutionTools, _c, error_1, e_3_1;
3127
+ var e_3, _d;
3128
+ var _this = this;
3129
+ return __generator(this, function (_e) {
3130
+ switch (_e.label) {
3131
+ case 0:
3132
+ errors = [];
3133
+ _e.label = 1;
3134
+ case 1:
3135
+ _e.trys.push([1, 15, 16, 17]);
3136
+ _a = __values(this.llmExecutionTools), _b = _a.next();
3137
+ _e.label = 2;
3138
+ case 2:
3139
+ if (!!_b.done) return [3 /*break*/, 14];
3140
+ llmExecutionTools = _b.value;
3141
+ _e.label = 3;
3142
+ case 3:
3143
+ _e.trys.push([3, 12, , 13]);
3144
+ _c = prompt.modelRequirements.modelVariant;
3145
+ switch (_c) {
3146
+ case 'CHAT': return [3 /*break*/, 4];
3147
+ case 'COMPLETION': return [3 /*break*/, 6];
3148
+ case 'EMBEDDING': return [3 /*break*/, 8];
3149
+ }
3150
+ return [3 /*break*/, 10];
3151
+ case 4:
3152
+ if (llmExecutionTools.callChatModel === undefined) {
3153
+ return [3 /*break*/, 13];
3154
+ }
3155
+ return [4 /*yield*/, llmExecutionTools.callChatModel(prompt)];
3156
+ case 5: return [2 /*return*/, _e.sent()];
3157
+ case 6:
3158
+ if (llmExecutionTools.callCompletionModel === undefined) {
3159
+ return [3 /*break*/, 13];
3160
+ }
3161
+ return [4 /*yield*/, llmExecutionTools.callCompletionModel(prompt)];
3162
+ case 7: return [2 /*return*/, _e.sent()];
3163
+ case 8:
3164
+ if (llmExecutionTools.callEmbeddingModel === undefined) {
3165
+ return [3 /*break*/, 13];
3166
+ }
3167
+ return [4 /*yield*/, llmExecutionTools.callEmbeddingModel(prompt)];
3168
+ case 9: return [2 /*return*/, _e.sent()];
3169
+ case 10: throw new UnexpectedError("Unknown model variant \"".concat(prompt.modelRequirements.modelVariant, "\""));
3170
+ case 11: return [3 /*break*/, 13];
3171
+ case 12:
3172
+ error_1 = _e.sent();
3173
+ if (!(error_1 instanceof Error) || error_1 instanceof UnexpectedError) {
3174
+ throw error_1;
3175
+ }
3176
+ errors.push(error_1);
3177
+ return [3 /*break*/, 13];
3178
+ case 13:
3179
+ _b = _a.next();
3180
+ return [3 /*break*/, 2];
3181
+ case 14: return [3 /*break*/, 17];
3182
+ case 15:
3183
+ e_3_1 = _e.sent();
3184
+ e_3 = { error: e_3_1 };
3185
+ return [3 /*break*/, 17];
3186
+ case 16:
3187
+ try {
3188
+ if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
3189
+ }
3190
+ finally { if (e_3) throw e_3.error; }
3191
+ return [7 /*endfinally*/];
3192
+ case 17:
3193
+ if (errors.length === 1) {
3194
+ throw errors[0];
3195
+ }
3196
+ else if (errors.length > 1) {
3197
+ throw new PipelineExecutionError(
3198
+ // TODO: Tell which execution tools failed like
3199
+ // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
3200
+ // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
3201
+ // 3) ...
3202
+ spaceTrim(function (block) { return "\n All execution tools failed:\n\n ".concat(block(errors
3203
+ .map(function (error, i) { return "".concat(i + 1, ") **").concat(error.name || 'Error', ":** ").concat(error.message); })
3204
+ .join('\n')), "\n\n "); }));
3205
+ }
3206
+ else if (this.llmExecutionTools.length === 0) {
3207
+ throw new PipelineExecutionError("You have not provided any `LlmExecutionTools`");
3208
+ }
3209
+ else {
3210
+ throw new PipelineExecutionError(spaceTrim(function (block) { return "\n You have not provided any `LlmExecutionTools` that support model variant \"".concat(prompt.modelRequirements.modelVariant, "\"\n\n Available `LlmExecutionTools`:\n ").concat(block(_this.description), "\n\n "); }));
3211
+ }
3212
+ }
3213
+ });
3214
+ });
3215
+ };
3216
+ return MultipleLlmExecutionTools;
3217
+ }());
3218
+ /**
3219
+ * TODO: [🧠][🎛] Aggregating multiple models - have result not only from one first aviable model BUT all of them
3220
+ * TODO: [🏖] If no llmTools have for example not defined `callCompletionModel` this will still return object with defined `callCompletionModel` which just throws `PipelineExecutionError`, make it undefined instead
3221
+ * Look how `countTotalUsage` (and `cacheLlmTools`) implements it
3222
+ */
3223
+
3224
+ /**
3225
+ * Joins multiple LLM Execution Tools into one
3226
+ *
3227
+ * @returns {LlmExecutionTools} Single wrapper for multiple LlmExecutionTools
3228
+ *
3229
+ * 0) If there is no LlmExecutionTools, it warns and returns valid but empty LlmExecutionTools
3230
+ * 1) If there is only one LlmExecutionTools, it returns it wrapped in a proxy object
3231
+ * 2) If there are multiple LlmExecutionTools, first will be used first, second will be used if the first hasn`t defined model variant or fails, etc.
3232
+ * 3) When all LlmExecutionTools fail, it throws an error with a list of all errors merged into one
3233
+ *
3234
+ *
3235
+ * Tip: You don't have to use this function directly, just pass an array of LlmExecutionTools to the `ExecutionTools`
3236
+ *
3237
+ * @public exported from `@promptbook/core`
3238
+ */
3239
+ function joinLlmExecutionTools() {
3240
+ var llmExecutionTools = [];
3241
+ for (var _i = 0; _i < arguments.length; _i++) {
3242
+ llmExecutionTools[_i] = arguments[_i];
3243
+ }
3244
+ if (llmExecutionTools.length === 0) {
3245
+ var warningMessage = spaceTrim("\n You have not provided any `LlmExecutionTools`\n This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.\n\n Technically, it's not an error, but it's probably not what you want because it does not make sense to use Promptbook without language models.\n ");
3246
+ // TODO: [🟥] Detect browser / node and make it colorfull
3247
+ console.warn(warningMessage);
3248
+ /*
3249
+ return {
3250
+ async listModels() {
3251
+ // TODO: [🟥] Detect browser / node and make it colorfull
3252
+ console.warn(
3253
+ spaceTrim(
3254
+ (block) => `
3255
+
3256
+ You can't list models because you have no LLM Execution Tools defined:
3257
+
3258
+ tl;dr
3259
+
3260
+ ${block(warningMessage)}
3261
+ `,
3262
+ ),
3263
+ );
3264
+ return [];
3265
+ },
3266
+ };
3267
+ */
3335
3268
  }
3336
- // Note: [👨‍👨‍👧] Now we can freeze `mappedParameters` to prevent @@@
3337
- Object.freeze(mappedParameters);
3338
- return mappedParameters;
3269
+ return new (MultipleLlmExecutionTools.bind.apply(MultipleLlmExecutionTools, __spreadArray([void 0], __read(llmExecutionTools), false)))();
3339
3270
  }
3271
+ /**
3272
+ * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
3273
+ */
3340
3274
 
3341
3275
  /**
3342
3276
  * Extracts all code blocks from markdown.
@@ -3473,81 +3407,6 @@ function arrayableToArray(input) {
3473
3407
  return [input];
3474
3408
  }
3475
3409
 
3476
- /**
3477
- * Format either small or big number
3478
- *
3479
- * @public exported from `@promptbook/utils`
3480
- */
3481
- function numberToString(value) {
3482
- if (value === 0) {
3483
- return '0';
3484
- }
3485
- else if (Number.isNaN(value)) {
3486
- return VALUE_STRINGS.nan;
3487
- }
3488
- else if (value === Infinity) {
3489
- return VALUE_STRINGS.infinity;
3490
- }
3491
- else if (value === -Infinity) {
3492
- return VALUE_STRINGS.negativeInfinity;
3493
- }
3494
- for (var exponent = 0; exponent < 15; exponent++) {
3495
- var factor = Math.pow(10, exponent);
3496
- var valueRounded = Math.round(value * factor) / factor;
3497
- if (Math.abs(value - valueRounded) / value < SMALL_NUMBER) {
3498
- return valueRounded.toFixed(exponent);
3499
- }
3500
- }
3501
- return value.toString();
3502
- }
3503
-
3504
- /**
3505
- * Function `valueToString` will convert the given value to string
3506
- * This is useful and used in the `templateParameters` function
3507
- *
3508
- * Note: This function is not just calling `toString` method
3509
- * It's more complex and can handle this conversion specifically for LLM models
3510
- * See `VALUE_STRINGS`
3511
- *
3512
- * Note: There are 2 similar functions
3513
- * - `valueToString` converts value to string for LLM models as human-readable string
3514
- * - `asSerializable` converts value to string to preserve full information to be able to convert it back
3515
- *
3516
- * @public exported from `@promptbook/utils`
3517
- */
3518
- function valueToString(value) {
3519
- try {
3520
- if (value === '') {
3521
- return VALUE_STRINGS.empty;
3522
- }
3523
- else if (value === null) {
3524
- return VALUE_STRINGS.null;
3525
- }
3526
- else if (value === undefined) {
3527
- return VALUE_STRINGS.undefined;
3528
- }
3529
- else if (typeof value === 'string') {
3530
- return value;
3531
- }
3532
- else if (typeof value === 'number') {
3533
- return numberToString(value);
3534
- }
3535
- else if (value instanceof Date) {
3536
- return value.toISOString();
3537
- }
3538
- else {
3539
- return JSON.stringify(value);
3540
- }
3541
- }
3542
- catch (error) {
3543
- if (!(error instanceof Error)) {
3544
- throw error;
3545
- }
3546
- console.error(error);
3547
- return VALUE_STRINGS.unserializable;
3548
- }
3549
- }
3550
-
3551
3410
  /**
3552
3411
  * Replaces parameters in template with values from parameters object
3553
3412
  *
@@ -3604,6 +3463,8 @@ function templateParameters(template, parameters) {
3604
3463
  throw new PipelineExecutionError("Parameter `{".concat(parameterName, "}` is not defined"));
3605
3464
  }
3606
3465
  parameterValue = valueToString(parameterValue);
3466
+ // Escape curly braces in parameter values to prevent prompt-injection
3467
+ parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
3607
3468
  if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
3608
3469
  parameterValue = parameterValue
3609
3470
  .split('\n')
@@ -4246,7 +4107,7 @@ function executeAttempts(options) {
4246
4107
  promptTitle: task.title,
4247
4108
  promptMessage: templateParameters(task.description || '', parameters),
4248
4109
  defaultValue: templateParameters(preparedContent, parameters),
4249
- // TODO: [🧠] !! Figure out how to define placeholder in .book.md file
4110
+ // TODO: [🧠] Figure out how to define placeholder in .book.md file
4250
4111
  placeholder: undefined,
4251
4112
  priority: priority,
4252
4113
  }))];
@@ -4946,7 +4807,10 @@ function executePipeline(options) {
4946
4807
  finally { if (e_2) throw e_2.error; }
4947
4808
  return [7 /*endfinally*/];
4948
4809
  case 19:
4949
- parametersToPass = inputParameters;
4810
+ parametersToPass = Object.fromEntries(Object.entries(inputParameters).map(function (_a) {
4811
+ var _b = __read(_a, 2), key = _b[0], value = _b[1];
4812
+ return [key, valueToString(value)];
4813
+ }));
4950
4814
  _g.label = 20;
4951
4815
  case 20:
4952
4816
  _g.trys.push([20, 25, , 28]);
@@ -5116,69 +4980,232 @@ function executePipeline(options) {
5116
4980
  });
5117
4981
  });
5118
4982
  }
5119
- /**
5120
- * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5121
- */
4983
+ /**
4984
+ * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
4985
+ */
4986
+
4987
+ /**
4988
+ * Creates executor function from pipeline and execution tools.
4989
+ *
4990
+ * @returns The executor function
4991
+ * @throws {PipelineLogicError} on logical error in the pipeline
4992
+ * @public exported from `@promptbook/core`
4993
+ */
4994
+ function createPipelineExecutor(options) {
4995
+ var _this = this;
4996
+ var pipeline = options.pipeline, tools = options.tools, _a = options.maxExecutionAttempts, maxExecutionAttempts = _a === void 0 ? DEFAULT_MAX_EXECUTION_ATTEMPTS : _a, _b = options.maxParallelCount, maxParallelCount = _b === void 0 ? DEFAULT_MAX_PARALLEL_COUNT : _b, _c = options.csvSettings, csvSettings = _c === void 0 ? DEFAULT_CSV_SETTINGS : _c, _d = options.isVerbose, isVerbose = _d === void 0 ? DEFAULT_IS_VERBOSE : _d, _e = options.isNotPreparedWarningSupressed, isNotPreparedWarningSupressed = _e === void 0 ? false : _e, _f = options.cacheDirname, cacheDirname = _f === void 0 ? DEFAULT_SCRAPE_CACHE_DIRNAME : _f, _g = options.intermediateFilesStrategy, intermediateFilesStrategy = _g === void 0 ? DEFAULT_INTERMEDIATE_FILES_STRATEGY : _g, _h = options.isAutoInstalled, isAutoInstalled = _h === void 0 ? DEFAULT_IS_AUTO_INSTALLED : _h, _j = options.rootDirname, rootDirname = _j === void 0 ? null : _j;
4997
+ validatePipeline(pipeline);
4998
+ var pipelineIdentification = (function () {
4999
+ // Note: This is a 😐 implementation of [🚞]
5000
+ var _ = [];
5001
+ if (pipeline.sourceFile !== undefined) {
5002
+ _.push("File: ".concat(pipeline.sourceFile));
5003
+ }
5004
+ if (pipeline.pipelineUrl !== undefined) {
5005
+ _.push("Url: ".concat(pipeline.pipelineUrl));
5006
+ }
5007
+ return _.join('\n');
5008
+ })();
5009
+ var preparedPipeline;
5010
+ if (isPipelinePrepared(pipeline)) {
5011
+ preparedPipeline = pipeline;
5012
+ }
5013
+ else if (isNotPreparedWarningSupressed !== true) {
5014
+ console.warn(spaceTrim$1(function (block) { return "\n Pipeline is not prepared\n\n ".concat(block(pipelineIdentification), "\n\n It will be prepared ad-hoc before the first execution and **returned as `preparedPipeline` in `PipelineExecutorResult`**\n But it is recommended to prepare the pipeline during collection preparation\n\n @see more at https://ptbk.io/prepare-pipeline\n "); }));
5015
+ }
5016
+ var runCount = 0;
5017
+ var pipelineExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
5018
+ return __generator(this, function (_a) {
5019
+ runCount++;
5020
+ return [2 /*return*/, /* not await */ executePipeline({
5021
+ pipeline: pipeline,
5022
+ preparedPipeline: preparedPipeline,
5023
+ setPreparedPipeline: function (newPreparedPipeline) {
5024
+ preparedPipeline = newPreparedPipeline;
5025
+ },
5026
+ inputParameters: inputParameters,
5027
+ tools: tools,
5028
+ onProgress: onProgress,
5029
+ pipelineIdentification: spaceTrim$1(function (block) { return "\n ".concat(block(pipelineIdentification), "\n ").concat(runCount === 1 ? '' : "Run #".concat(runCount), "\n "); }),
5030
+ maxExecutionAttempts: maxExecutionAttempts,
5031
+ maxParallelCount: maxParallelCount,
5032
+ csvSettings: csvSettings,
5033
+ isVerbose: isVerbose,
5034
+ isNotPreparedWarningSupressed: isNotPreparedWarningSupressed,
5035
+ rootDirname: rootDirname,
5036
+ cacheDirname: cacheDirname,
5037
+ intermediateFilesStrategy: intermediateFilesStrategy,
5038
+ isAutoInstalled: isAutoInstalled,
5039
+ })];
5040
+ });
5041
+ }); };
5042
+ return pipelineExecutor;
5043
+ }
5044
+ /**
5045
+ * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5046
+ */
5047
+
5048
+ /**
5049
+ * Async version of Array.forEach
5050
+ *
5051
+ * @param array - Array to iterate over
5052
+ * @param options - Options for the function
5053
+ * @param callbackfunction - Function to call for each item
5054
+ * @public exported from `@promptbook/utils`
5055
+ * @deprecated [🪂] Use queues instead
5056
+ */
5057
+ function forEachAsync(array, options, callbackfunction) {
5058
+ return __awaiter(this, void 0, void 0, function () {
5059
+ var _a, maxParallelCount, index, runningTasks, tasks, _loop_1, _b, _c, item, e_1_1;
5060
+ var e_1, _d;
5061
+ return __generator(this, function (_e) {
5062
+ switch (_e.label) {
5063
+ case 0:
5064
+ _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? Infinity : _a;
5065
+ index = 0;
5066
+ runningTasks = [];
5067
+ tasks = [];
5068
+ _loop_1 = function (item) {
5069
+ var currentIndex, task;
5070
+ return __generator(this, function (_f) {
5071
+ switch (_f.label) {
5072
+ case 0:
5073
+ currentIndex = index++;
5074
+ task = callbackfunction(item, currentIndex, array);
5075
+ tasks.push(task);
5076
+ runningTasks.push(task);
5077
+ /* not await */ Promise.resolve(task).then(function () {
5078
+ runningTasks = runningTasks.filter(function (t) { return t !== task; });
5079
+ });
5080
+ if (!(maxParallelCount < runningTasks.length)) return [3 /*break*/, 2];
5081
+ return [4 /*yield*/, Promise.race(runningTasks)];
5082
+ case 1:
5083
+ _f.sent();
5084
+ _f.label = 2;
5085
+ case 2: return [2 /*return*/];
5086
+ }
5087
+ });
5088
+ };
5089
+ _e.label = 1;
5090
+ case 1:
5091
+ _e.trys.push([1, 6, 7, 8]);
5092
+ _b = __values(array), _c = _b.next();
5093
+ _e.label = 2;
5094
+ case 2:
5095
+ if (!!_c.done) return [3 /*break*/, 5];
5096
+ item = _c.value;
5097
+ return [5 /*yield**/, _loop_1(item)];
5098
+ case 3:
5099
+ _e.sent();
5100
+ _e.label = 4;
5101
+ case 4:
5102
+ _c = _b.next();
5103
+ return [3 /*break*/, 2];
5104
+ case 5: return [3 /*break*/, 8];
5105
+ case 6:
5106
+ e_1_1 = _e.sent();
5107
+ e_1 = { error: e_1_1 };
5108
+ return [3 /*break*/, 8];
5109
+ case 7:
5110
+ try {
5111
+ if (_c && !_c.done && (_d = _b.return)) _d.call(_b);
5112
+ }
5113
+ finally { if (e_1) throw e_1.error; }
5114
+ return [7 /*endfinally*/];
5115
+ case 8: return [4 /*yield*/, Promise.all(tasks)];
5116
+ case 9:
5117
+ _e.sent();
5118
+ return [2 /*return*/];
5119
+ }
5120
+ });
5121
+ });
5122
+ }
5122
5123
 
5123
5124
  /**
5124
- * Creates executor function from pipeline and execution tools.
5125
+ * Intercepts LLM tools and counts total usage of the tools
5125
5126
  *
5126
- * @returns The executor function
5127
- * @throws {PipelineLogicError} on logical error in the pipeline
5127
+ * @param llmTools LLM tools to be intercepted with usage counting
5128
+ * @returns LLM tools with same functionality with added total cost counting
5128
5129
  * @public exported from `@promptbook/core`
5129
5130
  */
5130
- function createPipelineExecutor(options) {
5131
+ function countTotalUsage(llmTools) {
5131
5132
  var _this = this;
5132
- var pipeline = options.pipeline, tools = options.tools, _a = options.maxExecutionAttempts, maxExecutionAttempts = _a === void 0 ? DEFAULT_MAX_EXECUTION_ATTEMPTS : _a, _b = options.maxParallelCount, maxParallelCount = _b === void 0 ? DEFAULT_MAX_PARALLEL_COUNT : _b, _c = options.csvSettings, csvSettings = _c === void 0 ? DEFAULT_CSV_SETTINGS : _c, _d = options.isVerbose, isVerbose = _d === void 0 ? DEFAULT_IS_VERBOSE : _d, _e = options.isNotPreparedWarningSupressed, isNotPreparedWarningSupressed = _e === void 0 ? false : _e, _f = options.cacheDirname, cacheDirname = _f === void 0 ? DEFAULT_SCRAPE_CACHE_DIRNAME : _f, _g = options.intermediateFilesStrategy, intermediateFilesStrategy = _g === void 0 ? DEFAULT_INTERMEDIATE_FILES_STRATEGY : _g, _h = options.isAutoInstalled, isAutoInstalled = _h === void 0 ? DEFAULT_IS_AUTO_INSTALLED : _h, _j = options.rootDirname, rootDirname = _j === void 0 ? null : _j;
5133
- validatePipeline(pipeline);
5134
- var pipelineIdentification = (function () {
5135
- // Note: This is a 😐 implementation of [🚞]
5136
- var _ = [];
5137
- if (pipeline.sourceFile !== undefined) {
5138
- _.push("File: ".concat(pipeline.sourceFile));
5139
- }
5140
- if (pipeline.pipelineUrl !== undefined) {
5141
- _.push("Url: ".concat(pipeline.pipelineUrl));
5142
- }
5143
- return _.join('\n');
5144
- })();
5145
- var preparedPipeline;
5146
- if (isPipelinePrepared(pipeline)) {
5147
- preparedPipeline = pipeline;
5133
+ var totalUsage = ZERO_USAGE;
5134
+ var proxyTools = {
5135
+ get title() {
5136
+ // TODO: [🧠] Maybe put here some suffix
5137
+ return llmTools.title;
5138
+ },
5139
+ get description() {
5140
+ // TODO: [🧠] Maybe put here some suffix
5141
+ return llmTools.description;
5142
+ },
5143
+ checkConfiguration: function () {
5144
+ return __awaiter(this, void 0, void 0, function () {
5145
+ return __generator(this, function (_a) {
5146
+ return [2 /*return*/, /* not await */ llmTools.checkConfiguration()];
5147
+ });
5148
+ });
5149
+ },
5150
+ listModels: function () {
5151
+ return /* not await */ llmTools.listModels();
5152
+ },
5153
+ getTotalUsage: function () {
5154
+ // <- Note: [🥫] Not using getter `get totalUsage` but `getTotalUsage` to allow this object to be proxied
5155
+ return totalUsage;
5156
+ },
5157
+ };
5158
+ if (llmTools.callChatModel !== undefined) {
5159
+ proxyTools.callChatModel = function (prompt) { return __awaiter(_this, void 0, void 0, function () {
5160
+ var promptResult;
5161
+ return __generator(this, function (_a) {
5162
+ switch (_a.label) {
5163
+ case 0: return [4 /*yield*/, llmTools.callChatModel(prompt)];
5164
+ case 1:
5165
+ promptResult = _a.sent();
5166
+ totalUsage = addUsage(totalUsage, promptResult.usage);
5167
+ return [2 /*return*/, promptResult];
5168
+ }
5169
+ });
5170
+ }); };
5148
5171
  }
5149
- else if (isNotPreparedWarningSupressed !== true) {
5150
- console.warn(spaceTrim$1(function (block) { return "\n Pipeline is not prepared\n\n ".concat(block(pipelineIdentification), "\n\n It will be prepared ad-hoc before the first execution and **returned as `preparedPipeline` in `PipelineExecutorResult`**\n But it is recommended to prepare the pipeline during collection preparation\n\n @see more at https://ptbk.io/prepare-pipeline\n "); }));
5172
+ if (llmTools.callCompletionModel !== undefined) {
5173
+ proxyTools.callCompletionModel = function (prompt) { return __awaiter(_this, void 0, void 0, function () {
5174
+ var promptResult;
5175
+ return __generator(this, function (_a) {
5176
+ switch (_a.label) {
5177
+ case 0: return [4 /*yield*/, llmTools.callCompletionModel(prompt)];
5178
+ case 1:
5179
+ promptResult = _a.sent();
5180
+ totalUsage = addUsage(totalUsage, promptResult.usage);
5181
+ return [2 /*return*/, promptResult];
5182
+ }
5183
+ });
5184
+ }); };
5151
5185
  }
5152
- var runCount = 0;
5153
- var pipelineExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
5154
- return __generator(this, function (_a) {
5155
- runCount++;
5156
- return [2 /*return*/, /* not await */ executePipeline({
5157
- pipeline: pipeline,
5158
- preparedPipeline: preparedPipeline,
5159
- setPreparedPipeline: function (newPreparedPipeline) {
5160
- preparedPipeline = newPreparedPipeline;
5161
- },
5162
- inputParameters: inputParameters,
5163
- tools: tools,
5164
- onProgress: onProgress,
5165
- pipelineIdentification: spaceTrim$1(function (block) { return "\n ".concat(block(pipelineIdentification), "\n ").concat(runCount === 1 ? '' : "Run #".concat(runCount), "\n "); }),
5166
- maxExecutionAttempts: maxExecutionAttempts,
5167
- maxParallelCount: maxParallelCount,
5168
- csvSettings: csvSettings,
5169
- isVerbose: isVerbose,
5170
- isNotPreparedWarningSupressed: isNotPreparedWarningSupressed,
5171
- rootDirname: rootDirname,
5172
- cacheDirname: cacheDirname,
5173
- intermediateFilesStrategy: intermediateFilesStrategy,
5174
- isAutoInstalled: isAutoInstalled,
5175
- })];
5176
- });
5177
- }); };
5178
- return pipelineExecutor;
5186
+ if (llmTools.callEmbeddingModel !== undefined) {
5187
+ proxyTools.callEmbeddingModel = function (prompt) { return __awaiter(_this, void 0, void 0, function () {
5188
+ var promptResult;
5189
+ return __generator(this, function (_a) {
5190
+ switch (_a.label) {
5191
+ case 0: return [4 /*yield*/, llmTools.callEmbeddingModel(prompt)];
5192
+ case 1:
5193
+ promptResult = _a.sent();
5194
+ totalUsage = addUsage(totalUsage, promptResult.usage);
5195
+ return [2 /*return*/, promptResult];
5196
+ }
5197
+ });
5198
+ }); };
5199
+ }
5200
+ // <- Note: [🤖]
5201
+ return proxyTools;
5179
5202
  }
5180
5203
  /**
5181
- * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5204
+ * TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
5205
+ * TODO: [🧠] Is there some meaningfull way how to test this util
5206
+ * TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
5207
+ * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
5208
+ * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
5182
5209
  */
5183
5210
 
5184
5211
  /**
@@ -5243,10 +5270,10 @@ function preparePersona(personaDescription, tools, options) {
5243
5270
  });
5244
5271
  }
5245
5272
  /**
5246
- * TODO: [🔃][main] !! If the persona was prepared with different version or different set of models, prepare it once again
5247
- * TODO: [🏢] !! Check validity of `modelName` in pipeline
5248
- * TODO: [🏢] !! Check validity of `systemMessage` in pipeline
5249
- * TODO: [🏢] !! Check validity of `temperature` in pipeline
5273
+ * TODO: [🔃][main] If the persona was prepared with different version or different set of models, prepare it once again
5274
+ * TODO: [🏢] Check validity of `modelName` in pipeline
5275
+ * TODO: [🏢] Check validity of `systemMessage` in pipeline
5276
+ * TODO: [🏢] Check validity of `temperature` in pipeline
5250
5277
  */
5251
5278
 
5252
5279
  /**
@@ -5686,21 +5713,44 @@ function isValidFilePath(filename) {
5686
5713
  if (typeof filename !== 'string') {
5687
5714
  return false;
5688
5715
  }
5716
+ if (filename.split('\n').length > 1) {
5717
+ return false;
5718
+ }
5719
+ if (filename.split(' ').length >
5720
+ 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
5721
+ return false;
5722
+ }
5689
5723
  var filenameSlashes = filename.split('\\').join('/');
5690
5724
  // Absolute Unix path: /hello.txt
5691
5725
  if (/^(\/)/i.test(filenameSlashes)) {
5726
+ // console.log(filename, 'Absolute Unix path: /hello.txt');
5692
5727
  return true;
5693
5728
  }
5694
5729
  // Absolute Windows path: /hello.txt
5695
5730
  if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
5731
+ // console.log(filename, 'Absolute Windows path: /hello.txt');
5696
5732
  return true;
5697
5733
  }
5698
5734
  // Relative path: ./hello.txt
5699
5735
  if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
5736
+ // console.log(filename, 'Relative path: ./hello.txt');
5737
+ return true;
5738
+ }
5739
+ // Allow paths like foo/hello
5740
+ if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
5741
+ // console.log(filename, 'Allow paths like foo/hello');
5742
+ return true;
5743
+ }
5744
+ // Allow paths like hello.book
5745
+ if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
5746
+ // console.log(filename, 'Allow paths like hello.book');
5700
5747
  return true;
5701
5748
  }
5702
5749
  return false;
5703
5750
  }
5751
+ /**
5752
+ * TODO: [🍏] Implement for MacOs
5753
+ */
5704
5754
 
5705
5755
  /**
5706
5756
  * The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
@@ -5725,6 +5775,9 @@ var scraperFetch = function (url, init) { return __awaiter(void 0, void 0, void
5725
5775
  }
5726
5776
  });
5727
5777
  }); };
5778
+ /**
5779
+ * TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
5780
+ */
5728
5781
 
5729
5782
  /**
5730
5783
  * @@@
@@ -5792,7 +5845,7 @@ function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
5792
5845
  },
5793
5846
  }];
5794
5847
  case 2:
5795
- if (!(isValidFilePath(sourceContent) || /\.[a-z]{1,10}$/i.exec(sourceContent))) return [3 /*break*/, 4];
5848
+ if (!isValidFilePath(sourceContent)) return [3 /*break*/, 4];
5796
5849
  if (tools.fs === undefined) {
5797
5850
  throw new EnvironmentMismatchError('Can not import file knowledge without filesystem tools');
5798
5851
  // <- TODO: [🧠] What is the best error type here`
@@ -5807,7 +5860,7 @@ function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
5807
5860
  return [4 /*yield*/, isFileExisting(filename_1, tools.fs)];
5808
5861
  case 3:
5809
5862
  if (!(_f.sent())) {
5810
- throw new NotFoundError(spaceTrim(function (block) { return "\n Can not make source handler for file which does not exist:\n\n File:\n ".concat(block(filename_1), "\n "); }));
5863
+ throw new NotFoundError(spaceTrim(function (block) { return "\n Can not make source handler for file which does not exist:\n\n File:\n ".concat(block(sourceContent), "\n\n Full file path:\n ").concat(block(filename_1), "\n "); }));
5811
5864
  }
5812
5865
  // TODO: [🧠][😿] Test security file - file is scoped to the project (BUT maybe do this in `filesystemTools`)
5813
5866
  return [2 /*return*/, {
@@ -5920,7 +5973,7 @@ function prepareKnowledgePieces(knowledgeSources, tools, options) {
5920
5973
  partialPieces = __spreadArray([], __read(partialPiecesUnchecked), false);
5921
5974
  return [2 /*return*/, "break"];
5922
5975
  }
5923
- console.warn(spaceTrim(function (block) { return "\n Cannot scrape knowledge from source despite the scraper `".concat(scraper.metadata.className, "` supports the mime type \"").concat(sourceHandler.mimeType, "\".\n \n The source:\n > ").concat(block(knowledgeSource.sourceContent
5976
+ console.warn(spaceTrim(function (block) { return "\n Cannot scrape knowledge from source despite the scraper `".concat(scraper.metadata.className, "` supports the mime type \"").concat(sourceHandler.mimeType, "\".\n\n The source:\n ").concat(block(knowledgeSource.sourceContent
5924
5977
  .split('\n')
5925
5978
  .map(function (line) { return "> ".concat(line); })
5926
5979
  .join('\n')), "\n\n ").concat(block($registeredScrapersMessage(scrapers)), "\n\n\n "); }));
@@ -5958,7 +6011,7 @@ function prepareKnowledgePieces(knowledgeSources, tools, options) {
5958
6011
  return [7 /*endfinally*/];
5959
6012
  case 9:
5960
6013
  if (partialPieces === null) {
5961
- throw new KnowledgeScrapeError(spaceTrim(function (block) { return "\n Cannot scrape knowledge\n \n The source:\n > ".concat(block(knowledgeSource.sourceContent
6014
+ throw new KnowledgeScrapeError(spaceTrim(function (block) { return "\n Cannot scrape knowledge\n\n The source:\n > ".concat(block(knowledgeSource.sourceContent
5962
6015
  .split('\n')
5963
6016
  .map(function (line) { return "> ".concat(line); })
5964
6017
  .join('\n')), "\n\n No scraper found for the mime type \"").concat(sourceHandler.mimeType, "\"\n\n ").concat(block($registeredScrapersMessage(scrapers)), "\n\n\n "); }));
@@ -6049,7 +6102,7 @@ function prepareTasks(pipeline, tools, options) {
6049
6102
  * TODO: [😂] Adding knowledge should be convert to async high-level abstractions, simmilar thing with expectations to sync high-level abstractions
6050
6103
  * TODO: [🧠] Add context to each task (if missing)
6051
6104
  * TODO: [🧠] What is better name `prepareTask` or `prepareTaskAndParameters`
6052
- * TODO: [♨][main] !!! Prepare index the examples and maybe tasks
6105
+ * TODO: [♨][main] !!3 Prepare index the examples and maybe tasks
6053
6106
  * TODO: Write tests for `preparePipeline`
6054
6107
  * TODO: [🏏] Leverage the batch API and build queues @see https://platform.openai.com/docs/guides/batch
6055
6108
  * TODO: [🧊] In future one preparation can take data from previous preparation and save tokens and time
@@ -6057,7 +6110,9 @@ function prepareTasks(pipeline, tools, options) {
6057
6110
  */
6058
6111
 
6059
6112
  /**
6060
- * Prepare pipeline from string (markdown) format to JSON format
6113
+ * Prepare pipeline locally
6114
+ *
6115
+ * @see https://github.com/webgptorg/promptbook/discussions/196
6061
6116
  *
6062
6117
  * Note: This function does not validate logic of the pipeline
6063
6118
  * Note: This function acts as part of compilation process
@@ -6071,16 +6126,17 @@ function preparePipeline(pipeline, tools, options) {
6071
6126
  <- TODO: [🧠][🪑] `promptbookVersion` */
6072
6127
  knowledgeSources /*
6073
6128
  <- TODO: [🧊] `knowledgePieces` */, personas /*
6074
- <- TODO: [🧊] `preparations` */, _llms, llmTools, llmToolsWithUsage, currentPreparation, preparations, preparedPersonas, knowledgeSourcesPrepared, partialknowledgePiecesPrepared, knowledgePiecesPrepared, tasksPrepared /* TODO: parameters: parametersPrepared*/;
6129
+ <- TODO: [🧊] `preparations` */, sources, _llms, llmTools, llmToolsWithUsage, currentPreparation, preparations, title, collection, prepareTitleExecutor, _c, result, outputParameters, titleRaw, preparedPersonas, knowledgeSourcesPrepared, partialknowledgePiecesPrepared, knowledgePiecesPrepared, tasksPrepared /* TODO: parameters: parametersPrepared*/;
6130
+ var _d;
6075
6131
  var _this = this;
6076
- return __generator(this, function (_c) {
6077
- switch (_c.label) {
6132
+ return __generator(this, function (_e) {
6133
+ switch (_e.label) {
6078
6134
  case 0:
6079
6135
  if (isPipelinePrepared(pipeline)) {
6080
6136
  return [2 /*return*/, pipeline];
6081
6137
  }
6082
6138
  rootDirname = options.rootDirname, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? DEFAULT_MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? DEFAULT_IS_VERBOSE : _b;
6083
- parameters = pipeline.parameters, tasks = pipeline.tasks, knowledgeSources = pipeline.knowledgeSources, personas = pipeline.personas;
6139
+ parameters = pipeline.parameters, tasks = pipeline.tasks, knowledgeSources = pipeline.knowledgeSources, personas = pipeline.personas, sources = pipeline.sources;
6084
6140
  if (tools === undefined || tools.llm === undefined) {
6085
6141
  throw new MissingToolsError('LLM tools are required for preparing the pipeline');
6086
6142
  }
@@ -6098,6 +6154,33 @@ function preparePipeline(pipeline, tools, options) {
6098
6154
  // <- TODO: [🧊]
6099
6155
  currentPreparation,
6100
6156
  ];
6157
+ title = pipeline.title;
6158
+ if (!(title === undefined || title === '' || title === DEFAULT_BOOK_TITLE)) return [3 /*break*/, 3];
6159
+ collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
6160
+ _c = createPipelineExecutor;
6161
+ _d = {};
6162
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-title.book.md')];
6163
+ case 1:
6164
+ prepareTitleExecutor = _c.apply(void 0, [(_d.pipeline = _e.sent(),
6165
+ _d.tools = tools,
6166
+ _d)]);
6167
+ return [4 /*yield*/, prepareTitleExecutor({
6168
+ book: sources.map(function (_a) {
6169
+ var content = _a.content;
6170
+ return content;
6171
+ }).join('\n\n'),
6172
+ })];
6173
+ case 2:
6174
+ result = _e.sent();
6175
+ assertsExecutionSuccessful(result);
6176
+ outputParameters = result.outputParameters;
6177
+ titleRaw = outputParameters.title;
6178
+ if (isVerbose) {
6179
+ console.info("The title is \"".concat(titleRaw, "\""));
6180
+ }
6181
+ title = titleRaw || DEFAULT_BOOK_TITLE;
6182
+ _e.label = 3;
6183
+ case 3:
6101
6184
  preparedPersonas = new Array(personas.length);
6102
6185
  return [4 /*yield*/, forEachAsync(personas, { maxParallelCount: maxParallelCount /* <- TODO: [🪂] When there are subtasks, this maximul limit can be broken */ }, function (persona, index) { return __awaiter(_this, void 0, void 0, function () {
6103
6186
  var modelRequirements, preparedPersona;
@@ -6116,12 +6199,12 @@ function preparePipeline(pipeline, tools, options) {
6116
6199
  }
6117
6200
  });
6118
6201
  }); })];
6119
- case 1:
6120
- _c.sent();
6202
+ case 4:
6203
+ _e.sent();
6121
6204
  knowledgeSourcesPrepared = knowledgeSources.map(function (source) { return (__assign(__assign({}, source), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
6122
6205
  return [4 /*yield*/, prepareKnowledgePieces(knowledgeSources /* <- TODO: [🧊] {knowledgeSources, knowledgePieces} */, __assign(__assign({}, tools), { llm: llmToolsWithUsage }), __assign(__assign({}, options), { rootDirname: rootDirname, maxParallelCount: maxParallelCount /* <- TODO: [🪂] */, isVerbose: isVerbose }))];
6123
- case 2:
6124
- partialknowledgePiecesPrepared = _c.sent();
6206
+ case 5:
6207
+ partialknowledgePiecesPrepared = _e.sent();
6125
6208
  knowledgePiecesPrepared = partialknowledgePiecesPrepared.map(function (piece) { return (__assign(__assign({}, piece), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
6126
6209
  return [4 /*yield*/, prepareTasks({
6127
6210
  parameters: parameters,
@@ -6132,8 +6215,8 @@ function preparePipeline(pipeline, tools, options) {
6132
6215
  maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
6133
6216
  isVerbose: isVerbose,
6134
6217
  })];
6135
- case 3:
6136
- tasksPrepared = (_c.sent()).tasksPrepared;
6218
+ case 6:
6219
+ tasksPrepared = (_e.sent()).tasksPrepared;
6137
6220
  // ----- /Tasks preparation -----
6138
6221
  // TODO: [😂] Use here all `AsyncHighLevelAbstraction`
6139
6222
  // Note: Count total usage
@@ -6144,7 +6227,7 @@ function preparePipeline(pipeline, tools, options) {
6144
6227
  order: ORDER_OF_PIPELINE_JSON,
6145
6228
  value: __assign(__assign({}, pipeline), {
6146
6229
  // <- TODO: Probbably deeply clone the pipeline because `$exportJson` freezes the subobjects
6147
- knowledgeSources: knowledgeSourcesPrepared, knowledgePieces: knowledgePiecesPrepared, tasks: __spreadArray([], __read(tasksPrepared), false),
6230
+ title: title, knowledgeSources: knowledgeSourcesPrepared, knowledgePieces: knowledgePiecesPrepared, tasks: __spreadArray([], __read(tasksPrepared), false),
6148
6231
  // <- TODO: [🪓] Here should be no need for spreading new array, just ` tasks: tasksPrepared`
6149
6232
  personas: preparedPersonas, preparations: __spreadArray([], __read(preparations), false) }),
6150
6233
  })];
@@ -6153,7 +6236,7 @@ function preparePipeline(pipeline, tools, options) {
6153
6236
  });
6154
6237
  }
6155
6238
  /**
6156
- * TODO: Write tests for `preparePipeline`
6239
+ * TODO: Write tests for `preparePipeline` and `preparePipelineOnRemoteServer`
6157
6240
  * TODO: [🏏] Leverage the batch API and build queues @see https://platform.openai.com/docs/guides/batch
6158
6241
  * TODO: [🧊] In future one preparation can take data from previous preparation and save tokens and time
6159
6242
  * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
@@ -6239,7 +6322,7 @@ var knowledgeCommandParser = {
6239
6322
  if (sourceContent === '') {
6240
6323
  throw new ParseError("Source is not defined");
6241
6324
  }
6242
- // TODO: [main] !!!! Following checks should be applied every link in the `sourceContent`
6325
+ // TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
6243
6326
  if (sourceContent.startsWith('http://')) {
6244
6327
  throw new ParseError("Source is not secure");
6245
6328
  }
@@ -6411,7 +6494,7 @@ var sectionCommandParser = {
6411
6494
  expectResultingParameterName();
6412
6495
  var parameter = $pipelineJson.parameters.find(function (param) { return param.name === $taskJson.resultingParameterName; });
6413
6496
  if (parameter === undefined) {
6414
- // TODO: !!!!!! Change to logic error for higher level abstractions to work
6497
+ // TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
6415
6498
  throw new ParseError("Parameter `{".concat($taskJson.resultingParameterName, "}` is not defined so can not define example value of it"));
6416
6499
  }
6417
6500
  parameter.exampleValues = parameter.exampleValues || [];
@@ -6422,7 +6505,7 @@ var sectionCommandParser = {
6422
6505
  if (command.taskType === 'KNOWLEDGE') {
6423
6506
  knowledgeCommandParser.$applyToPipelineJson({
6424
6507
  type: 'KNOWLEDGE',
6425
- sourceContent: $taskJson.content, // <- TODO: [🐝][main] !!! Work with KNOWLEDGE which not referring to the source file or website, but its content itself
6508
+ sourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
6426
6509
  }, $pipelineJson);
6427
6510
  $taskJson.isTask = false;
6428
6511
  return;
@@ -7317,20 +7400,24 @@ var ChatbotFormfactorDefinition = {
7317
7400
  */
7318
7401
  var GeneratorFormfactorDefinition = {
7319
7402
  name: 'GENERATOR',
7320
- description: "@@@",
7403
+ description: "Generates any kind (in HTML with possible scripts and css format) of content from input message",
7321
7404
  documentationUrl: "https://github.com/webgptorg/promptbook/discussions/184",
7322
7405
  pipelineInterface: {
7323
7406
  inputParameters: [
7324
- /* @@@ */
7325
7407
  {
7326
- name: 'nonce',
7327
- description: 'Just to prevent GENERATOR to be set as implicit formfactor',
7408
+ name: 'inputMessage',
7409
+ description: "Input message to be image made from",
7328
7410
  isInput: true,
7329
7411
  isOutput: false,
7330
7412
  },
7331
7413
  ],
7332
7414
  outputParameters: [
7333
- /* @@@ */
7415
+ {
7416
+ name: 'result',
7417
+ description: "Result in HTML to be shown to user",
7418
+ isInput: false,
7419
+ isOutput: true,
7420
+ },
7334
7421
  ],
7335
7422
  },
7336
7423
  };
@@ -7362,6 +7449,35 @@ var GenericFormfactorDefinition = {
7362
7449
  pipelineInterface: GENERIC_PIPELINE_INTERFACE,
7363
7450
  };
7364
7451
 
7452
+ /**
7453
+ * Image generator is form of app that generates image from input message
7454
+ *
7455
+ * @public exported from `@promptbook/core`
7456
+ */
7457
+ var ImageGeneratorFormfactorDefinition = {
7458
+ name: 'IMAGE_GENERATOR',
7459
+ description: "Generates prompt for image generation from input message",
7460
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/184",
7461
+ pipelineInterface: {
7462
+ inputParameters: [
7463
+ {
7464
+ name: 'inputMessage',
7465
+ description: "Input message to be image made from",
7466
+ isInput: true,
7467
+ isOutput: false,
7468
+ },
7469
+ ],
7470
+ outputParameters: [
7471
+ {
7472
+ name: 'prompt',
7473
+ description: "Prompt to be used for image generation",
7474
+ isInput: false,
7475
+ isOutput: true,
7476
+ },
7477
+ ],
7478
+ },
7479
+ };
7480
+
7365
7481
  /**
7366
7482
  * Matcher is form of app that @@@
7367
7483
  *
@@ -7460,6 +7576,7 @@ var FORMFACTOR_DEFINITIONS = [
7460
7576
  SheetsFormfactorDefinition,
7461
7577
  MatcherFormfactorDefinition,
7462
7578
  GeneratorFormfactorDefinition,
7579
+ ImageGeneratorFormfactorDefinition,
7463
7580
  ];
7464
7581
  /**
7465
7582
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -7846,7 +7963,7 @@ var parameterCommandParser = {
7846
7963
  * Note: `$` is used to indicate that this function mutates given `pipelineJson`
7847
7964
  */
7848
7965
  $applyToPipelineJson: function (command, $pipelineJson) {
7849
- // Note: [🍣] Do nothing, its application is implemented separately in `precompilePipeline`
7966
+ // Note: [🍣] Do nothing, its application is implemented separately in `parsePipeline`
7850
7967
  },
7851
7968
  /**
7852
7969
  * Apply the PARAMETER command to the `pipelineJson`
@@ -7854,7 +7971,7 @@ var parameterCommandParser = {
7854
7971
  * Note: `$` is used to indicate that this function mutates given `taskJson`
7855
7972
  */
7856
7973
  $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
7857
- // Note: [🍣] Do nothing, its application is implemented separately in `precompilePipeline`
7974
+ // Note: [🍣] Do nothing, its application is implemented separately in `parsePipeline`
7858
7975
  },
7859
7976
  /**
7860
7977
  * Converts the PARAMETER command back to string
@@ -8349,7 +8466,7 @@ var COMMANDS = [
8349
8466
  instrumentCommandParser,
8350
8467
  personaCommandParser,
8351
8468
  foreachCommandParser,
8352
- boilerplateCommandParser, // <- TODO: !! Only in development, remove in production
8469
+ boilerplateCommandParser, // <- TODO: Only in development, remove in production
8353
8470
  // <- Note: [♓️][💩] This is the order of the commands in the pipeline, BUT its not used in parsing and before usage maybe it should be done better
8354
8471
  ];
8355
8472
  /**
@@ -8773,7 +8890,7 @@ var QuickChatbotHla = {
8773
8890
  isOutput: true,
8774
8891
  exampleValues: ['Hello, I am a Pavol`s virtual avatar. How can I help you?'],
8775
8892
  });
8776
- // TODO: !!!!!! spaceTrim
8893
+ // TODO: Use spaceTrim in multiline strings
8777
8894
  $pipelineJson.tasks.push({
8778
8895
  taskType: 'PROMPT_TASK',
8779
8896
  name: 'create-an-answer',
@@ -8781,8 +8898,11 @@ var QuickChatbotHla = {
8781
8898
  content: 'Write a response to the user message:\n\n**Question from user**\n\n> {userMessage}\n\n**Previous conversation**\n\n> {previousConversationSummary}',
8782
8899
  resultingParameterName: 'chatbotResponse',
8783
8900
  personaName: personaName,
8784
- dependentParameterNames: ['userMessage', 'previousConversationSummary' /* !!!!!!, 'knowledge'*/],
8785
- // !!!!!! preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
8901
+ dependentParameterNames: [
8902
+ 'userMessage',
8903
+ 'previousConversationSummary' /* TODO: [🧠][📛], 'knowledge'*/,
8904
+ ],
8905
+ // TODO: [🧠][📛] preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
8786
8906
  }, {
8787
8907
  taskType: 'PROMPT_TASK',
8788
8908
  name: 'summarize-the-conversation',
@@ -8796,24 +8916,27 @@ var QuickChatbotHla = {
8796
8916
  max: 10,
8797
8917
  },
8798
8918
  },
8799
- dependentParameterNames: ['userMessage', 'chatbotResponse' /* !!!!!!, 'knowledge'*/],
8800
- // !!!!!! preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
8919
+ dependentParameterNames: ['userMessage', 'chatbotResponse' /* TODO: [🧠][📛], 'knowledge'*/],
8920
+ // TODO: [🧠][📛] preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
8801
8921
  }, {
8802
8922
  taskType: 'SIMPLE_TASK',
8803
8923
  name: 'title',
8804
8924
  title: 'Title',
8805
8925
  content: '{conversationSummary}',
8806
8926
  resultingParameterName: 'title',
8807
- dependentParameterNames: ['conversationSummary' /* !!!!!!, 'knowledge'*/],
8808
- // !!!!!! preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
8927
+ dependentParameterNames: ['conversationSummary' /* TODO: [🧠][📛], 'knowledge'*/],
8928
+ // TODO: [🧠][📛] preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
8809
8929
  });
8810
8930
  },
8811
8931
  };
8932
+ /**
8933
+ * TODO: [🧠][📛] Should this be here?
8934
+ */
8812
8935
 
8813
8936
  /**
8814
8937
  * All high-level abstractions
8815
8938
  *
8816
- * @private internal index of `precompilePipeline` (= used for sync) and `preparePipeline` (= used for async)
8939
+ * @private internal index of `parsePipeline` (= used for sync) and `preparePipeline` (= used for async)
8817
8940
  */
8818
8941
  var HIGH_LEVEL_ABSTRACTIONS = [
8819
8942
  ImplicitFormfactorHla,
@@ -8947,7 +9070,7 @@ function splitMarkdownIntoSections(markdown) {
8947
9070
  return;
8948
9071
  }
8949
9072
  if (!section.startsWith('#')) {
8950
- section = "# ".concat(DEFAULT_TITLE, "\n\n").concat(section);
9073
+ section = "# ".concat(DEFAULT_BOOK_TITLE, "\n\n").concat(section);
8951
9074
  }
8952
9075
  sections.push(section);
8953
9076
  buffer = [];
@@ -9002,7 +9125,7 @@ function splitMarkdownIntoSections(markdown) {
9002
9125
  /**
9003
9126
  * Normalizes the markdown by flattening the structure
9004
9127
  *
9005
- * - It always have h1 - if there is no h1 in the markdown, it will be added "# Untitled"
9128
+ * - It always have h1 - if there is no h1 in the markdown, it will be added `DEFAULT_BOOK_TITLE`
9006
9129
  * - All other headings are normalized to h2
9007
9130
  *
9008
9131
  * @public exported from `@promptbook/markdown-utils`
@@ -9011,7 +9134,7 @@ function flattenMarkdown(markdown) {
9011
9134
  var e_1, _a;
9012
9135
  var sections = splitMarkdownIntoSections(markdown);
9013
9136
  if (sections.length === 0) {
9014
- return "# ".concat(DEFAULT_TITLE);
9137
+ return "# ".concat(DEFAULT_BOOK_TITLE);
9015
9138
  }
9016
9139
  var flattenedMarkdown = '';
9017
9140
  var parsedSections = sections.map(parseMarkdownSection);
@@ -9022,7 +9145,7 @@ function flattenMarkdown(markdown) {
9022
9145
  }
9023
9146
  else {
9024
9147
  parsedSections.unshift(firstSection);
9025
- flattenedMarkdown += "# ".concat(DEFAULT_TITLE) + "\n\n"; // <- [🧠] Maybe 3 new lines?
9148
+ flattenedMarkdown += "# ".concat(DEFAULT_BOOK_TITLE) + "\n\n"; // <- [🧠] Maybe 3 new lines?
9026
9149
  }
9027
9150
  try {
9028
9151
  for (var parsedSections_1 = __values(parsedSections), parsedSections_1_1 = parsedSections_1.next(); !parsedSections_1_1.done; parsedSections_1_1 = parsedSections_1.next()) {
@@ -9049,13 +9172,13 @@ function flattenMarkdown(markdown) {
9049
9172
  */
9050
9173
 
9051
9174
  /**
9052
- * Removes HTML or Markdown comments from a string.
9175
+ * Removes Markdown (or HTML) comments
9053
9176
  *
9054
9177
  * @param {string} content - The string to remove comments from.
9055
9178
  * @returns {string} The input string with all comments removed.
9056
9179
  * @public exported from `@promptbook/markdown-utils`
9057
9180
  */
9058
- function removeContentComments(content) {
9181
+ function removeMarkdownComments(content) {
9059
9182
  return spaceTrim$1(content.replace(/<!--(.*?)-->/gs, ''));
9060
9183
  }
9061
9184
 
@@ -9088,7 +9211,7 @@ function titleToName(value) {
9088
9211
  *
9089
9212
  * Note: There are 3 similar functions:
9090
9213
  * - `compilePipeline` **(preferred)** - which propperly compiles the promptbook and use embedding for external knowledge
9091
- * - `precompilePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
9214
+ * - `parsePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
9092
9215
  * - `preparePipeline` - just one step in the compilation process
9093
9216
  *
9094
9217
  * Note: This function does not validate logic of the pipeline only the parsing
@@ -9099,10 +9222,10 @@ function titleToName(value) {
9099
9222
  * @throws {ParseError} if the promptbook string is not valid
9100
9223
  * @public exported from `@promptbook/core`
9101
9224
  */
9102
- function precompilePipeline(pipelineString) {
9225
+ function parsePipeline(pipelineString) {
9103
9226
  var e_1, _a, e_2, _b, e_3, _c, e_4, _d, e_5, _e, e_6, _f;
9104
9227
  var $pipelineJson = {
9105
- title: DEFAULT_TITLE,
9228
+ title: DEFAULT_BOOK_TITLE,
9106
9229
  parameters: [],
9107
9230
  tasks: [],
9108
9231
  knowledgeSources: [],
@@ -9113,7 +9236,7 @@ function precompilePipeline(pipelineString) {
9113
9236
  {
9114
9237
  type: 'BOOK',
9115
9238
  path: null,
9116
- // <- TODO: !!!!!! Pass here path of the file
9239
+ // <- TODO: !!6 Pass here path of the file
9117
9240
  content: pipelineString,
9118
9241
  },
9119
9242
  ],
@@ -9131,18 +9254,44 @@ function precompilePipeline(pipelineString) {
9131
9254
  }
9132
9255
  // =============================================================
9133
9256
  // Note: 1️⃣ Parsing of the markdown into object
9257
+ // ==============
9258
+ // Note: 1️⃣◽1️⃣ Remove #!shebang and comments
9134
9259
  if (pipelineString.startsWith('#!')) {
9135
9260
  var _g = __read(pipelineString.split('\n')), shebangLine_1 = _g[0], restLines = _g.slice(1);
9136
9261
  if (!(shebangLine_1 || '').includes('ptbk')) {
9137
9262
  throw new ParseError(spaceTrim$1(function (block) { return "\n It seems that you try to parse a book file which has non-standard shebang line for book files:\n Shebang line must contain 'ptbk'\n\n You have:\n ".concat(block(shebangLine_1 || '(empty line)'), "\n\n It should look like this:\n #!/usr/bin/env ptbk\n\n ").concat(block(getPipelineIdentification()), "\n "); }));
9138
9263
  }
9139
- pipelineString = restLines.join('\n');
9140
- }
9141
- pipelineString = removeContentComments(pipelineString);
9264
+ pipelineString = validatePipelineString(restLines.join('\n'));
9265
+ }
9266
+ pipelineString = removeMarkdownComments(pipelineString);
9267
+ pipelineString = spaceTrim$1(pipelineString);
9268
+ // <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
9269
+ // ==============
9270
+ // Note: 1️⃣◽2️⃣ Process flat pipeline
9271
+ var isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
9272
+ var isLastLineReturnStatement = pipelineString.split('\n').pop().split('`').join('').startsWith('->');
9273
+ // TODO: Also (double)check
9274
+ // > const usedCommands
9275
+ // > const isBlocksUsed
9276
+ // > const returnStatementCount
9277
+ var isFlatPipeline = !isMarkdownBeginningWithHeadline && isLastLineReturnStatement;
9278
+ // console.log({ isMarkdownBeginningWithHeadline, isLastLineReturnStatement, isFlatPipeline });
9279
+ if (isFlatPipeline) {
9280
+ var pipelineStringLines = pipelineString.split('\n');
9281
+ var returnStatement_1 = pipelineStringLines.pop();
9282
+ var prompt_1 = spaceTrim$1(pipelineStringLines.join('\n'));
9283
+ pipelineString = validatePipelineString(spaceTrim$1(function (block) { return "\n # ".concat(DEFAULT_BOOK_TITLE, "\n\n ## Prompt\n\n ```\n ").concat(block(prompt_1), "\n ```\n\n ").concat(returnStatement_1, "\n "); }));
9284
+ // <- TODO: Maybe use book` notation
9285
+ // console.log(pipelineString);
9286
+ }
9287
+ // ==============
9288
+ // Note: 1️⃣◽3️⃣ Parse the markdown
9142
9289
  pipelineString = flattenMarkdown(pipelineString) /* <- Note: [🥞] */;
9143
9290
  pipelineString = pipelineString.replaceAll(/`\{(?<parameterName>[a-z0-9_]+)\}`/gi, '{$<parameterName>}');
9144
9291
  pipelineString = pipelineString.replaceAll(/`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi, '-> {$<parameterName>}');
9145
9292
  var _h = __read(splitMarkdownIntoSections(pipelineString).map(parseMarkdownSection)), pipelineHead = _h[0], pipelineSections = _h.slice(1); /* <- Note: [🥞] */
9293
+ // ==============
9294
+ // Note: 1️⃣◽4️⃣ Check markdown structure
9146
9295
  if (pipelineHead === undefined) {
9147
9296
  throw new UnexpectedError(spaceTrim$1(function (block) { return "\n Pipeline head is not defined\n\n ".concat(block(getPipelineIdentification()), "\n\n This should never happen, because the pipeline already flattened\n "); }));
9148
9297
  }
@@ -9526,14 +9675,14 @@ function precompilePipeline(pipelineString) {
9526
9675
  // =============================================================
9527
9676
  return exportJson({
9528
9677
  name: 'pipelineJson',
9529
- message: "Result of `precompilePipeline`",
9678
+ message: "Result of `parsePipeline`",
9530
9679
  order: ORDER_OF_PIPELINE_JSON,
9531
9680
  value: __assign({ formfactorName: 'GENERIC' }, $pipelineJson),
9532
9681
  });
9533
9682
  }
9534
9683
  /**
9535
9684
  * TODO: [🧠] Maybe more things here can be refactored as high-level abstractions
9536
- * TODO: [main] !!!! Warn if used only sync version
9685
+ * TODO: [main] !!4 Warn if used only sync version
9537
9686
  * TODO: [🚞] Report here line/column of error
9538
9687
  * TODO: Use spaceTrim more effectively
9539
9688
  * TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
@@ -9546,10 +9695,7 @@ function precompilePipeline(pipelineString) {
9546
9695
  /**
9547
9696
  * Compile pipeline from string (markdown) format to JSON format
9548
9697
  *
9549
- * Note: There are 3 similar functions:
9550
- * - `compilePipeline` **(preferred)** - which propperly compiles the promptbook and use embedding for external knowledge
9551
- * - `precompilePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
9552
- * - `preparePipeline` - just one step in the compilation process
9698
+ * @see https://github.com/webgptorg/promptbook/discussions/196
9553
9699
  *
9554
9700
  * Note: This function does not validate logic of the pipeline only the parsing
9555
9701
  * Note: This function acts as compilation process
@@ -9567,7 +9713,7 @@ function compilePipeline(pipelineString, tools, options) {
9567
9713
  return __generator(this, function (_a) {
9568
9714
  switch (_a.label) {
9569
9715
  case 0:
9570
- pipelineJson = precompilePipeline(pipelineString);
9716
+ pipelineJson = parsePipeline(pipelineString);
9571
9717
  if (!(tools !== undefined && tools.llm !== undefined)) return [3 /*break*/, 2];
9572
9718
  return [4 /*yield*/, preparePipeline(pipelineJson, tools, options || {
9573
9719
  rootDirname: null,
@@ -9576,7 +9722,7 @@ function compilePipeline(pipelineString, tools, options) {
9576
9722
  pipelineJson = _a.sent();
9577
9723
  _a.label = 2;
9578
9724
  case 2:
9579
- // Note: No need to use `$exportJson` because `precompilePipeline` and `preparePipeline` already do that
9725
+ // Note: No need to use `$exportJson` because `parsePipeline` and `preparePipeline` already do that
9580
9726
  return [2 /*return*/, pipelineJson];
9581
9727
  }
9582
9728
  });
@@ -9603,7 +9749,7 @@ function addAutoGeneratedSection(content, options) {
9603
9749
  return content.replace(sectionRegex, contentToInsert);
9604
9750
  }
9605
9751
  // Note: Following is the case when the section is not found in the file so we add it there
9606
- var placeForSection = removeContentComments(content).match(/^##.*$/im);
9752
+ var placeForSection = removeMarkdownComments(content).match(/^##.*$/im);
9607
9753
  if (placeForSection !== null) {
9608
9754
  var _a = __read(placeForSection, 1), heading_1 = _a[0];
9609
9755
  return content.replace(heading_1, spaceTrim$1(function (block) { return "\n ".concat(block(contentToInsert), "\n\n ").concat(block(heading_1), "\n "); }));
@@ -9629,7 +9775,7 @@ function renderPromptbookMermaid(pipelineJson, options) {
9629
9775
  var parameter = pipelineJson.parameters.find(function (parameter) { return parameter.name === parameterName; });
9630
9776
  if (!parameter) {
9631
9777
  throw new UnexpectedError("Could not find {".concat(parameterName, "}"));
9632
- // <- TODO: !!!!!! This causes problems when {knowledge} and other reserved parameters are used
9778
+ // <- TODO: !!6 This causes problems when {knowledge} and other reserved parameters are used
9633
9779
  }
9634
9780
  if (parameter.isInput) {
9635
9781
  return 'input';
@@ -9673,9 +9819,9 @@ function renderPromptbookMermaid(pipelineJson, options) {
9673
9819
  return promptbookMermaid;
9674
9820
  }
9675
9821
  /**
9676
- * TODO: [🧠] !! FOREACH in mermaid graph
9677
- * TODO: [🧠] !! Knowledge in mermaid graph
9678
- * TODO: [🧠] !! Personas in mermaid graph
9822
+ * TODO: [🧠] FOREACH in mermaid graph
9823
+ * TODO: [🧠] Knowledge in mermaid graph
9824
+ * TODO: [🧠] Personas in mermaid graph
9679
9825
  * TODO: Maybe use some Mermaid package instead of string templating
9680
9826
  * TODO: [🕌] When more than 2 functionalities, split into separate functions
9681
9827
  */
@@ -9710,6 +9856,7 @@ function prettifyPipelineString(pipelineString, options) {
9710
9856
  case 2:
9711
9857
  if (isPrettifyed) {
9712
9858
  pipelineString = prettifyMarkdown(pipelineString);
9859
+ // <- TODO: [😧] `prettifyMarkdown` should preserve discriminated type *(or at lease `PipelineString`)*
9713
9860
  }
9714
9861
  return [2 /*return*/, pipelineString];
9715
9862
  }
@@ -10511,7 +10658,7 @@ function cacheLlmTools(llmTools, options) {
10511
10658
  return [3 /*break*/, 11];
10512
10659
  case 10: throw new PipelineExecutionError("Unknown model variant \"".concat(prompt.modelRequirements.modelVariant, "\""));
10513
10660
  case 11:
10514
- // TODO: [🧠] !!!!! How to do timing in mixed cache / non-cache situation
10661
+ // TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
10515
10662
  // promptResult.timing: FromtoItems
10516
10663
  return [4 /*yield*/, storage.setItem(key, {
10517
10664
  date: $getCurrentDate(),
@@ -10520,7 +10667,7 @@ function cacheLlmTools(llmTools, options) {
10520
10667
  promptResult: promptResult,
10521
10668
  })];
10522
10669
  case 12:
10523
- // TODO: [🧠] !!!!! How to do timing in mixed cache / non-cache situation
10670
+ // TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
10524
10671
  // promptResult.timing: FromtoItems
10525
10672
  _c.sent();
10526
10673
  return [2 /*return*/, promptResult];
@@ -10611,6 +10758,7 @@ function limitTotalUsage(llmTools, options) {
10611
10758
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
10612
10759
  *
10613
10760
  * @public exported from `@promptbook/core`
10761
+ * @public exported from `@promptbook/wizzard`
10614
10762
  * @public exported from `@promptbook/cli`
10615
10763
  */
10616
10764
  var _AnthropicClaudeMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -10656,6 +10804,7 @@ var _AnthropicClaudeMetadataRegistration = $llmToolsMetadataRegister.register({
10656
10804
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
10657
10805
  *
10658
10806
  * @public exported from `@promptbook/core`
10807
+ * @public exported from `@promptbook/wizzard`
10659
10808
  * @public exported from `@promptbook/cli`
10660
10809
  */
10661
10810
  var _AzureOpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -10732,6 +10881,7 @@ var $isRunningInJest = new Function("\n try {\n return process.env.JES
10732
10881
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
10733
10882
  *
10734
10883
  * @public exported from `@promptbook/core`
10884
+ * @public exported from `@promptbook/wizzard`
10735
10885
  * @public exported from `@promptbook/cli`
10736
10886
  */
10737
10887
  var _GoogleMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -10780,6 +10930,7 @@ var _GoogleMetadataRegistration = $llmToolsMetadataRegister.register({
10780
10930
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
10781
10931
  *
10782
10932
  * @public exported from `@promptbook/core`
10933
+ * @public exported from `@promptbook/wizzard`
10783
10934
  * @public exported from `@promptbook/cli`
10784
10935
  */
10785
10936
  var _OpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -10818,6 +10969,7 @@ var _OpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
10818
10969
  * Note: [🏐] Configurations registrations are done in @@@ BUT constructor @@@
10819
10970
  *
10820
10971
  * @public exported from `@promptbook/core`
10972
+ * @public exported from `@promptbook/wizzard`
10821
10973
  * @public exported from `@promptbook/cli`
10822
10974
  */
10823
10975
  var _OpenAiAssistantMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -10860,6 +11012,59 @@ var _OpenAiAssistantMetadataRegistration = $llmToolsMetadataRegister.register({
10860
11012
  * Note: [💞] Ignore a discrepancy between file name and entity name
10861
11013
  */
10862
11014
 
11015
+ /**
11016
+ * Function `isValidPipelineString` will validate the if the string is a valid pipeline string
11017
+ * It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
11018
+ *
11019
+ * @param {string} pipelineString the candidate for a pipeline string
11020
+ * @returns {boolean} if the string is a valid pipeline string
11021
+ * @public exported from `@promptbook/core`
11022
+ */
11023
+ function isValidPipelineString(pipelineString) {
11024
+ try {
11025
+ validatePipelineString(pipelineString);
11026
+ return true;
11027
+ }
11028
+ catch (error) {
11029
+ if (!(error instanceof Error)) {
11030
+ throw error;
11031
+ }
11032
+ return false;
11033
+ }
11034
+ }
11035
+ /**
11036
+ * TODO: [🧠][🈴] Where is the best location for this file
11037
+ */
11038
+
11039
+ /**
11040
+ * Tag function for notating a pipeline with a book\`...\ notation as template literal
11041
+ *
11042
+ * @param strings @@@
11043
+ * @param values @@@
11044
+ * @returns the pipeline string
11045
+ * @public exported from `@promptbook/core`
11046
+ */
11047
+ function book(strings) {
11048
+ var values = [];
11049
+ for (var _i = 1; _i < arguments.length; _i++) {
11050
+ values[_i - 1] = arguments[_i];
11051
+ }
11052
+ if (strings.length !== 1 && values.length !== 0) {
11053
+ throw new NotYetImplementedError("Only one string without interpolated value is supported for now in book`...` notation");
11054
+ }
11055
+ var pipelineString = strings[0];
11056
+ pipelineString = spaceTrim(pipelineString);
11057
+ if (!isValidPipelineString(pipelineString)) {
11058
+ // TODO: Make the CustomError for this
11059
+ throw new Error(spaceTrim("\n The string is not a valid pipeline string\n\n book`\n ".concat(pipelineString, "\n `\n ")));
11060
+ }
11061
+ return pipelineString;
11062
+ }
11063
+ /**
11064
+ * TODO: [🧠][🈴] Where is the best location for this file
11065
+ * Note: [💞] Ignore a discrepancy between file name and entity name
11066
+ */
11067
+
10863
11068
  /**
10864
11069
  * Metadata of the scraper
10865
11070
  *
@@ -10872,6 +11077,7 @@ var legacyDocumentScraperMetadata = $deepFreeze({
10872
11077
  mimeTypes: ['application/msword', 'text/rtf'],
10873
11078
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
10874
11079
  isAvilableInBrowser: false,
11080
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
10875
11081
  requiredExecutables: [
10876
11082
  'Pandoc',
10877
11083
  'LibreOffice',
@@ -10884,6 +11090,7 @@ var legacyDocumentScraperMetadata = $deepFreeze({
10884
11090
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
10885
11091
  *
10886
11092
  * @public exported from `@promptbook/core`
11093
+ * @public exported from `@promptbook/wizzard`
10887
11094
  * @public exported from `@promptbook/cli`
10888
11095
  */
10889
11096
  var _LegacyDocumentScraperMetadataRegistration = $scrapersMetadataRegister.register(legacyDocumentScraperMetadata);
@@ -10903,6 +11110,7 @@ var documentScraperMetadata = $deepFreeze({
10903
11110
  mimeTypes: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
10904
11111
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
10905
11112
  isAvilableInBrowser: false,
11113
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
10906
11114
  requiredExecutables: ['Pandoc'],
10907
11115
  }); /* <- Note: [🤛] */
10908
11116
  /**
@@ -10911,6 +11119,7 @@ var documentScraperMetadata = $deepFreeze({
10911
11119
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
10912
11120
  *
10913
11121
  * @public exported from `@promptbook/core`
11122
+ * @public exported from `@promptbook/wizzard`
10914
11123
  * @public exported from `@promptbook/cli`
10915
11124
  */
10916
11125
  var _DocumentScraperMetadataRegistration = $scrapersMetadataRegister.register(documentScraperMetadata);
@@ -10930,6 +11139,7 @@ var markdownScraperMetadata = $deepFreeze({
10930
11139
  mimeTypes: ['text/markdown', 'text/plain'],
10931
11140
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
10932
11141
  isAvilableInBrowser: true,
11142
+ // <- Note: [🌏] This is the only scraper which makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
10933
11143
  requiredExecutables: [],
10934
11144
  }); /* <- Note: [🤛] */
10935
11145
  /**
@@ -10938,6 +11148,7 @@ var markdownScraperMetadata = $deepFreeze({
10938
11148
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
10939
11149
  *
10940
11150
  * @public exported from `@promptbook/core`
11151
+ * @public exported from `@promptbook/wizzard`
10941
11152
  * @public exported from `@promptbook/cli`
10942
11153
  */
10943
11154
  var _MarkdownScraperMetadataRegistration = $scrapersMetadataRegister.register(markdownScraperMetadata);
@@ -10956,7 +11167,8 @@ var pdfScraperMetadata = $deepFreeze({
10956
11167
  className: 'PdfScraper',
10957
11168
  mimeTypes: ['application/pdf'],
10958
11169
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
10959
- isAvilableInBrowser: true,
11170
+ isAvilableInBrowser: false,
11171
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
10960
11172
  requiredExecutables: [],
10961
11173
  }); /* <- Note: [🤛] */
10962
11174
  /**
@@ -10965,6 +11177,7 @@ var pdfScraperMetadata = $deepFreeze({
10965
11177
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
10966
11178
  *
10967
11179
  * @public exported from `@promptbook/core`
11180
+ * @public exported from `@promptbook/wizzard`
10968
11181
  * @public exported from `@promptbook/cli`
10969
11182
  */
10970
11183
  var _PdfScraperMetadataRegistration = $scrapersMetadataRegister.register(pdfScraperMetadata);
@@ -10984,6 +11197,7 @@ var websiteScraperMetadata = $deepFreeze({
10984
11197
  mimeTypes: ['text/html'],
10985
11198
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
10986
11199
  isAvilableInBrowser: false,
11200
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
10987
11201
  requiredExecutables: [],
10988
11202
  }); /* <- Note: [🤛] */
10989
11203
  /**
@@ -10992,6 +11206,7 @@ var websiteScraperMetadata = $deepFreeze({
10992
11206
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
10993
11207
  *
10994
11208
  * @public exported from `@promptbook/core`
11209
+ * @public exported from `@promptbook/wizzard`
10995
11210
  * @public exported from `@promptbook/cli`
10996
11211
  */
10997
11212
  var _WebsiteScraperMetadataRegistration = $scrapersMetadataRegister.register(websiteScraperMetadata);
@@ -11080,5 +11295,5 @@ var PrefixStorage = /** @class */ (function () {
11080
11295
  return PrefixStorage;
11081
11296
  }());
11082
11297
 
11083
- export { $llmToolsMetadataRegister, $llmToolsRegister, $scrapersMetadataRegister, $scrapersRegister, ADMIN_EMAIL, ADMIN_GITHUB_NAME, AbstractFormatError, BOOK_LANGUAGE_VERSION, BlackholeStorage, BoilerplateError, BoilerplateFormfactorDefinition, CLAIM, CallbackInterfaceTools, ChatbotFormfactorDefinition, CollectionError, CsvFormatDefinition, CsvFormatError, DEFAULT_BOOKS_DIRNAME, DEFAULT_CSV_SETTINGS, DEFAULT_EXECUTIONS_CACHE_DIRNAME, DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME, DEFAULT_INTERMEDIATE_FILES_STRATEGY, DEFAULT_IS_AUTO_INSTALLED, DEFAULT_IS_VERBOSE, DEFAULT_MAX_EXECUTION_ATTEMPTS, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL, DEFAULT_MAX_PARALLEL_COUNT, DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, DEFAULT_REMOTE_URL, DEFAULT_REMOTE_URL_PATH, DEFAULT_SCRAPE_CACHE_DIRNAME, DEFAULT_TITLE, EXPECTATION_UNITS, EnvironmentMismatchError, ExecutionReportStringOptionsDefaults, ExpectError, FORMFACTOR_DEFINITIONS, GENERIC_PIPELINE_INTERFACE, GeneratorFormfactorDefinition, GenericFormfactorDefinition, KnowledgeScrapeError, LOGO_DARK_SRC, LOGO_LIGHT_SRC, LimitReachedError, MANDATORY_CSV_SETTINGS, MAX_FILENAME_LENGTH, MODEL_VARIANTS, MatcherFormfactorDefinition, MemoryStorage, MissingToolsError, MultipleLlmExecutionTools, NAME, NonTaskSectionTypes, NotFoundError, NotYetImplementedError, ORDER_OF_PIPELINE_JSON, PROMPTBOOK_ENGINE_VERSION, PROMPTBOOK_ERRORS, ParseError, PipelineExecutionError, PipelineLogicError, PipelineUrlError, PrefixStorage, RESERVED_PARAMETER_NAMES, SET_IS_VERBOSE, SectionTypes, SheetsFormfactorDefinition, TaskTypes, TextFormatDefinition, TranslatorFormfactorDefinition, UNCERTAIN_USAGE, UnexpectedError, ZERO_USAGE, _AnthropicClaudeMetadataRegistration, _AzureOpenAiMetadataRegistration, _DocumentScraperMetadataRegistration, _GoogleMetadataRegistration, _LegacyDocumentScraperMetadataRegistration, _MarkdownScraperMetadataRegistration, _OpenAiAssistantMetadataRegistration, _OpenAiMetadataRegistration, _PdfScraperMetadataRegistration, _WebsiteScraperMetadataRegistration, addUsage, assertsExecutionSuccessful, cacheLlmTools, collectionToJson, compilePipeline, countTotalUsage, createCollectionFromJson, createCollectionFromPromise, createCollectionFromUrl, createLlmToolsFromConfiguration, createPipelineExecutor, createSubcollection, embeddingVectorToString, executionReportJsonToString, extractParameterNamesFromTask, getPipelineInterface, isPassingExpectations, isPipelineImplementingInterface, isPipelineInterfacesEqual, isPipelinePrepared, joinLlmExecutionTools, limitTotalUsage, makeKnowledgeSourceHandler, pipelineJsonToString, precompilePipeline, prepareKnowledgePieces, preparePersona, preparePipeline, prepareTasks, prettifyPipelineString, unpreparePipeline, usageToHuman, usageToWorktime, validatePipeline };
11298
+ export { $llmToolsMetadataRegister, $llmToolsRegister, $scrapersMetadataRegister, $scrapersRegister, ADMIN_EMAIL, ADMIN_GITHUB_NAME, AbstractFormatError, BOOK_LANGUAGE_VERSION, BlackholeStorage, BoilerplateError, BoilerplateFormfactorDefinition, CLAIM, CallbackInterfaceTools, ChatbotFormfactorDefinition, CollectionError, CsvFormatDefinition, CsvFormatError, DEFAULT_BOOKS_DIRNAME, DEFAULT_BOOK_TITLE, DEFAULT_CSV_SETTINGS, DEFAULT_EXECUTIONS_CACHE_DIRNAME, DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME, DEFAULT_INTERMEDIATE_FILES_STRATEGY, DEFAULT_IS_AUTO_INSTALLED, DEFAULT_IS_VERBOSE, DEFAULT_MAX_EXECUTION_ATTEMPTS, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL, DEFAULT_MAX_PARALLEL_COUNT, DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, DEFAULT_REMOTE_URL, DEFAULT_REMOTE_URL_PATH, DEFAULT_SCRAPE_CACHE_DIRNAME, EXPECTATION_UNITS, EnvironmentMismatchError, ExecutionReportStringOptionsDefaults, ExpectError, FORMFACTOR_DEFINITIONS, GENERIC_PIPELINE_INTERFACE, GeneratorFormfactorDefinition, GenericFormfactorDefinition, ImageGeneratorFormfactorDefinition, KnowledgeScrapeError, LOGO_DARK_SRC, LOGO_LIGHT_SRC, LimitReachedError, MANDATORY_CSV_SETTINGS, MAX_FILENAME_LENGTH, MODEL_VARIANTS, MatcherFormfactorDefinition, MemoryStorage, MissingToolsError, MultipleLlmExecutionTools, NAME, NonTaskSectionTypes, NotFoundError, NotYetImplementedError, ORDER_OF_PIPELINE_JSON, PROMPTBOOK_ENGINE_VERSION, PROMPTBOOK_ERRORS, ParseError, PipelineExecutionError, PipelineLogicError, PipelineUrlError, PrefixStorage, RESERVED_PARAMETER_NAMES, SET_IS_VERBOSE, SectionTypes, SheetsFormfactorDefinition, TaskTypes, TextFormatDefinition, TranslatorFormfactorDefinition, UNCERTAIN_USAGE, UnexpectedError, ZERO_USAGE, _AnthropicClaudeMetadataRegistration, _AzureOpenAiMetadataRegistration, _DocumentScraperMetadataRegistration, _GoogleMetadataRegistration, _LegacyDocumentScraperMetadataRegistration, _MarkdownScraperMetadataRegistration, _OpenAiAssistantMetadataRegistration, _OpenAiMetadataRegistration, _PdfScraperMetadataRegistration, _WebsiteScraperMetadataRegistration, addUsage, assertsExecutionSuccessful, book, cacheLlmTools, collectionToJson, compilePipeline, countTotalUsage, createCollectionFromJson, createCollectionFromPromise, createCollectionFromUrl, createLlmToolsFromConfiguration, createPipelineExecutor, createSubcollection, embeddingVectorToString, executionReportJsonToString, extractParameterNamesFromTask, getPipelineInterface, isPassingExpectations, isPipelineImplementingInterface, isPipelineInterfacesEqual, isPipelinePrepared, isValidPipelineString, joinLlmExecutionTools, limitTotalUsage, makeKnowledgeSourceHandler, parsePipeline, pipelineJsonToString, prepareKnowledgePieces, preparePersona, preparePipeline, prepareTasks, prettifyPipelineString, unpreparePipeline, usageToHuman, usageToWorktime, validatePipeline, validatePipelineString };
11084
11299
  //# sourceMappingURL=index.es.js.map