@promptbook/cli 0.81.0-8 → 0.81.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 (95) hide show
  1. package/README.md +25 -8
  2. package/esm/index.es.js +1192 -794
  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/templates.index.d.ts +2 -2
  9. package/esm/typings/src/_packages/types.index.d.ts +4 -0
  10. package/esm/typings/src/_packages/utils.index.d.ts +2 -0
  11. package/esm/typings/src/_packages/wizzard.index.d.ts +44 -0
  12. package/esm/typings/src/cli/cli-commands/make.d.ts +1 -1
  13. package/esm/typings/src/cli/cli-commands/run.d.ts +2 -2
  14. package/esm/typings/src/collection/constructors/createCollectionFromDirectory.d.ts +11 -0
  15. package/esm/typings/src/collection/constructors/createCollectionFromUrl.d.ts +1 -1
  16. package/esm/typings/src/commands/index.d.ts +1 -1
  17. package/esm/typings/src/config.d.ts +3 -3
  18. package/esm/typings/src/conversion/compilePipeline.d.ts +1 -4
  19. package/esm/typings/src/conversion/{precompilePipeline.d.ts → parsePipeline.d.ts} +3 -3
  20. package/esm/typings/src/conversion/prettify/renderPipelineMermaidOptions.d.ts +3 -3
  21. package/esm/typings/src/conversion/validation/validatePipeline.d.ts +7 -7
  22. package/esm/typings/src/errors/utils/getErrorReportUrl.d.ts +1 -1
  23. package/esm/typings/src/execution/PipelineExecutor.d.ts +2 -2
  24. package/esm/typings/src/execution/createPipelineExecutor/10-executePipeline.d.ts +2 -2
  25. package/esm/typings/src/formfactors/generator/GeneratorFormfactorDefinition.d.ts +9 -4
  26. package/esm/typings/src/formfactors/image-generator/ImageGeneratorFormfactorDefinition.d.ts +24 -0
  27. package/esm/typings/src/formfactors/index.d.ts +31 -9
  28. package/esm/typings/src/high-level-abstractions/_common/HighLevelAbstraction.d.ts +1 -1
  29. package/esm/typings/src/high-level-abstractions/index.d.ts +3 -3
  30. package/esm/typings/src/high-level-abstractions/quick-chatbot/QuickChatbotHla.d.ts +3 -0
  31. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
  32. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
  33. package/esm/typings/src/llm-providers/_common/register/{$provideLlmToolsForCli.d.ts → $provideLlmToolsForWizzardOrCli.d.ts} +2 -2
  34. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
  35. package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  36. package/esm/typings/src/llm-providers/anthropic-claude/createAnthropicClaudeExecutionTools.d.ts +2 -2
  37. package/esm/typings/src/llm-providers/anthropic-claude/playground/playground.d.ts +2 -2
  38. package/esm/typings/src/llm-providers/anthropic-claude/register-configuration.d.ts +1 -0
  39. package/esm/typings/src/llm-providers/anthropic-claude/register-constructor.d.ts +2 -0
  40. package/esm/typings/src/llm-providers/azure-openai/register-configuration.d.ts +1 -0
  41. package/esm/typings/src/llm-providers/azure-openai/register-constructor.d.ts +1 -0
  42. package/esm/typings/src/llm-providers/google/register-configuration.d.ts +1 -0
  43. package/esm/typings/src/llm-providers/google/register-constructor.d.ts +1 -0
  44. package/esm/typings/src/llm-providers/openai/playground/playground.d.ts +1 -1
  45. package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +2 -0
  46. package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +2 -0
  47. package/esm/typings/src/llm-providers/vercel/playground/playground.d.ts +1 -1
  48. package/esm/typings/src/other/templates/getBookTemplates.d.ts +22 -0
  49. package/esm/typings/src/personas/preparePersona.d.ts +4 -4
  50. package/esm/typings/src/pipeline/PipelineString.d.ts +0 -3
  51. package/esm/typings/src/pipeline/book-notation.d.ts +14 -0
  52. package/esm/typings/src/pipeline/isValidPipelineString.d.ts +13 -0
  53. package/esm/typings/src/pipeline/isValidPipelineString.test.d.ts +4 -0
  54. package/esm/typings/src/pipeline/validatePipelineString.d.ts +14 -0
  55. package/esm/typings/src/prepare/isPipelinePrepared.d.ts +3 -1
  56. package/esm/typings/src/prepare/preparePipeline.d.ts +2 -0
  57. package/esm/typings/src/prepare/prepareTasks.d.ts +1 -1
  58. package/esm/typings/src/scrapers/_common/Converter.d.ts +1 -0
  59. package/esm/typings/src/scrapers/_common/Scraper.d.ts +1 -1
  60. package/esm/typings/src/scrapers/_common/ScraperIntermediateSource.d.ts +3 -0
  61. package/esm/typings/src/scrapers/_common/register/ScraperAndConverterMetadata.d.ts +2 -0
  62. package/esm/typings/src/scrapers/_common/utils/scraperFetch.d.ts +3 -0
  63. package/esm/typings/src/scrapers/document/register-constructor.d.ts +1 -0
  64. package/esm/typings/src/scrapers/document/register-metadata.d.ts +1 -0
  65. package/esm/typings/src/scrapers/document-legacy/register-constructor.d.ts +1 -0
  66. package/esm/typings/src/scrapers/document-legacy/register-metadata.d.ts +1 -0
  67. package/esm/typings/src/scrapers/markdown/register-constructor.d.ts +1 -0
  68. package/esm/typings/src/scrapers/markdown/register-metadata.d.ts +1 -0
  69. package/esm/typings/src/scrapers/pdf/PdfScraper.d.ts +1 -0
  70. package/esm/typings/src/scrapers/pdf/createPdfScraper.d.ts +1 -1
  71. package/esm/typings/src/scrapers/pdf/register-constructor.d.ts +1 -0
  72. package/esm/typings/src/scrapers/pdf/register-metadata.d.ts +2 -1
  73. package/esm/typings/src/scrapers/website/createWebsiteScraper.d.ts +3 -1
  74. package/esm/typings/src/scrapers/website/register-constructor.d.ts +1 -0
  75. package/esm/typings/src/scrapers/website/register-metadata.d.ts +1 -0
  76. package/esm/typings/src/scripting/javascript/JavascriptEvalExecutionTools.test.d.ts +1 -1
  77. package/esm/typings/src/scripting/javascript/utils/preserve.d.ts +2 -1
  78. package/esm/typings/src/types/typeAliases.d.ts +16 -2
  79. package/esm/typings/src/utils/markdown/flattenMarkdown.d.ts +1 -1
  80. package/esm/typings/src/utils/markdown/{removeContentComments.d.ts → removeMarkdownComments.d.ts} +2 -2
  81. package/esm/typings/src/utils/organization/$sideEffect.d.ts +9 -0
  82. package/esm/typings/src/utils/serialization/checkSerializableAsJson.d.ts +1 -1
  83. package/esm/typings/src/utils/serialization/isSerializableAsJson.d.ts +2 -2
  84. package/esm/typings/src/utils/validators/filePath/isRootPath.d.ts +12 -0
  85. package/esm/typings/src/utils/validators/filePath/isRootPath.test.d.ts +4 -0
  86. package/esm/typings/src/utils/validators/filePath/isValidFilePath.d.ts +3 -0
  87. package/esm/typings/src/wizzard/$getCompiledBook.d.ts +16 -0
  88. package/esm/typings/src/wizzard/wizzard.d.ts +52 -8
  89. package/package.json +1 -1
  90. package/umd/index.umd.js +1192 -794
  91. package/umd/index.umd.js.map +1 -1
  92. package/esm/typings/src/other/templates/getBookTemplate.d.ts +0 -21
  93. package/esm/typings/src/scripting/javascript/utils/unknownToString.d.ts +0 -8
  94. /package/esm/typings/src/conversion/{precompilePipeline.test.d.ts → parsePipeline.test.d.ts} +0 -0
  95. /package/esm/typings/src/utils/markdown/{removeContentComments.test.d.ts → removeMarkdownComments.test.d.ts} +0 -0
package/esm/index.es.js CHANGED
@@ -39,7 +39,7 @@ var BOOK_LANGUAGE_VERSION = '1.0.0';
39
39
  * @generated
40
40
  * @see https://github.com/webgptorg/promptbook
41
41
  */
42
- var PROMPTBOOK_ENGINE_VERSION = '0.81.0-7';
42
+ var PROMPTBOOK_ENGINE_VERSION = '0.81.0-24';
43
43
  /**
44
44
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
45
45
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -223,7 +223,7 @@ var CLAIM = "It's time for a paradigm shift. The future of software in plain Eng
223
223
  *
224
224
  * @public exported from `@promptbook/core`
225
225
  */
226
- var DEFAULT_TITLE = "Untitled";
226
+ var DEFAULT_BOOK_TITLE = "\u2728 Untitled Book";
227
227
  /**
228
228
  * Warning message for the generated sections and files files
229
229
  *
@@ -308,6 +308,7 @@ var DEFAULT_MAX_EXECUTION_ATTEMPTS = 3; // <- TODO: [🤹‍♂️]
308
308
  * @public exported from `@promptbook/core`
309
309
  */
310
310
  var DEFAULT_BOOKS_DIRNAME = './books';
311
+ // <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
311
312
  /**
312
313
  * Where to store the cache of executions for promptbook CLI
313
314
  *
@@ -519,7 +520,7 @@ function $provideFilesystemForNode(options) {
519
520
  /**
520
521
  * Make error report URL for the given error
521
522
  *
522
- * @private !!!!!!
523
+ * @private private within the repository
523
524
  */
524
525
  function getErrorReportUrl(error) {
525
526
  var report = {
@@ -690,7 +691,7 @@ function checkSerializableAsJson(options) {
690
691
  if (!(error instanceof Error)) {
691
692
  throw error;
692
693
  }
693
- 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 "); }));
694
+ 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 "); }));
694
695
  }
695
696
  /*
696
697
  TODO: [0] Is there some more elegant way to check circular references?
@@ -720,7 +721,7 @@ function checkSerializableAsJson(options) {
720
721
  }
721
722
  /**
722
723
  * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
723
- * TODO: [🧠][main] !!! In-memory cache of same values to prevent multiple checks
724
+ * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
724
725
  * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
725
726
  */
726
727
 
@@ -732,7 +733,6 @@ function checkSerializableAsJson(options) {
732
733
  function deepClone(objectValue) {
733
734
  return JSON.parse(JSON.stringify(objectValue));
734
735
  /*
735
- !!!!!!!!
736
736
  TODO: [🧠] Is there a better implementation?
737
737
  > const propertyNames = Object.getOwnPropertyNames(objectValue);
738
738
  > for (const propertyName of propertyNames) {
@@ -844,7 +844,7 @@ var RESERVED_PARAMETER_NAMES = exportJson({
844
844
  * Note: [💞] Ignore a discrepancy between file name and entity name
845
845
  */
846
846
 
847
- // <- TODO: !!!!!!! Auto convert to type `import { ... } from 'type-fest';`
847
+ // <- TODO: Auto convert to type `import { ... } from 'type-fest';`
848
848
  /**
849
849
  * Tests if the value is [🚉] serializable as JSON
850
850
  *
@@ -874,7 +874,7 @@ function isSerializableAsJson(value) {
874
874
  }
875
875
  }
876
876
  /**
877
- * TODO: [🧠][main] !!! In-memory cache of same values to prevent multiple checks
877
+ * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
878
878
  * TODO: [🧠][💺] Can be done this on type-level?
879
879
  */
880
880
 
@@ -967,21 +967,44 @@ function isValidFilePath(filename) {
967
967
  if (typeof filename !== 'string') {
968
968
  return false;
969
969
  }
970
+ if (filename.split('\n').length > 1) {
971
+ return false;
972
+ }
973
+ if (filename.split(' ').length >
974
+ 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
975
+ return false;
976
+ }
970
977
  var filenameSlashes = filename.split('\\').join('/');
971
978
  // Absolute Unix path: /hello.txt
972
979
  if (/^(\/)/i.test(filenameSlashes)) {
980
+ // console.log(filename, 'Absolute Unix path: /hello.txt');
973
981
  return true;
974
982
  }
975
983
  // Absolute Windows path: /hello.txt
976
984
  if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
985
+ // console.log(filename, 'Absolute Windows path: /hello.txt');
977
986
  return true;
978
987
  }
979
988
  // Relative path: ./hello.txt
980
989
  if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
990
+ // console.log(filename, 'Relative path: ./hello.txt');
991
+ return true;
992
+ }
993
+ // Allow paths like foo/hello
994
+ if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
995
+ // console.log(filename, 'Allow paths like foo/hello');
996
+ return true;
997
+ }
998
+ // Allow paths like hello.book
999
+ if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
1000
+ // console.log(filename, 'Allow paths like hello.book');
981
1001
  return true;
982
1002
  }
983
1003
  return false;
984
1004
  }
1005
+ /**
1006
+ * TODO: [🍏] Implement for MacOs
1007
+ */
985
1008
 
986
1009
  /**
987
1010
  * Tests if given string is valid URL.
@@ -1616,7 +1639,7 @@ function cacheLlmTools(llmTools, options) {
1616
1639
  return [3 /*break*/, 11];
1617
1640
  case 10: throw new PipelineExecutionError("Unknown model variant \"".concat(prompt.modelRequirements.modelVariant, "\""));
1618
1641
  case 11:
1619
- // TODO: [🧠] !!!!! How to do timing in mixed cache / non-cache situation
1642
+ // TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
1620
1643
  // promptResult.timing: FromtoItems
1621
1644
  return [4 /*yield*/, storage.setItem(key, {
1622
1645
  date: $getCurrentDate(),
@@ -1625,7 +1648,7 @@ function cacheLlmTools(llmTools, options) {
1625
1648
  promptResult: promptResult,
1626
1649
  })];
1627
1650
  case 12:
1628
- // TODO: [🧠] !!!!! How to do timing in mixed cache / non-cache situation
1651
+ // TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
1629
1652
  // promptResult.timing: FromtoItems
1630
1653
  _c.sent();
1631
1654
  return [2 /*return*/, promptResult];
@@ -2046,6 +2069,25 @@ var $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
2046
2069
  * TODO: [®] DRY Register logic
2047
2070
  */
2048
2071
 
2072
+ /**
2073
+ * Determines if the given path is a root path.
2074
+ *
2075
+ * Note: This does not check if the file exists only if the path is valid
2076
+ * @public exported from `@promptbook/utils`
2077
+ */
2078
+ function isRootPath(value) {
2079
+ if (value === '/') {
2080
+ return true;
2081
+ }
2082
+ if (/^[A-Z]:\\$/i.test(value)) {
2083
+ return true;
2084
+ }
2085
+ return false;
2086
+ }
2087
+ /**
2088
+ * TODO: [🍏] Make for MacOS paths
2089
+ */
2090
+
2049
2091
  /**
2050
2092
  * @@@
2051
2093
  *
@@ -2060,17 +2102,45 @@ var $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
2060
2102
  * @public exported from `@promptbook/node`
2061
2103
  */
2062
2104
  function $provideLlmToolsConfigurationFromEnv() {
2063
- if (!$isRunningInNode()) {
2064
- throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
2065
- }
2066
- dotenv.config();
2067
- // TODO: Walk to the root of the project and find the nearest `.env` file
2068
- // @see https://collboard.fra1.cdn.digitaloceanspaces.com/usercontent/education/image/png/1/2/ad/image.png
2069
- var llmToolsConfiguration = $llmToolsMetadataRegister
2070
- .list()
2071
- .map(function (metadata) { return metadata.createConfigurationFromEnv(process.env); })
2072
- .filter(function (configuration) { return configuration !== null; });
2073
- return llmToolsConfiguration;
2105
+ return __awaiter(this, void 0, void 0, function () {
2106
+ var rootDirname, i, envFilename, llmToolsConfiguration;
2107
+ return __generator(this, function (_a) {
2108
+ switch (_a.label) {
2109
+ case 0:
2110
+ if (!$isRunningInNode()) {
2111
+ throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
2112
+ }
2113
+ rootDirname = process.cwd();
2114
+ i = 0;
2115
+ _a.label = 1;
2116
+ case 1:
2117
+ if (!(i < LOOP_LIMIT)) return [3 /*break*/, 4];
2118
+ envFilename = join(rootDirname, '.env' /* <- TODO: [🕝] Make here more candidates */);
2119
+ return [4 /*yield*/, isFileExisting(envFilename, $provideFilesystemForNode())];
2120
+ case 2:
2121
+ // console.log({ rootDirname, envFilename });
2122
+ if (_a.sent()) {
2123
+ dotenv.config({ path: envFilename });
2124
+ return [3 /*break*/, 4];
2125
+ }
2126
+ if (isRootPath(rootDirname)) {
2127
+ return [3 /*break*/, 4];
2128
+ }
2129
+ // Note: If the directory does not exist, try the parent directory
2130
+ rootDirname = join(rootDirname, '..');
2131
+ _a.label = 3;
2132
+ case 3:
2133
+ i++;
2134
+ return [3 /*break*/, 1];
2135
+ case 4:
2136
+ llmToolsConfiguration = $llmToolsMetadataRegister
2137
+ .list()
2138
+ .map(function (metadata) { return metadata.createConfigurationFromEnv(process.env); })
2139
+ .filter(function (configuration) { return configuration !== null; });
2140
+ return [2 /*return*/, llmToolsConfiguration];
2141
+ }
2142
+ });
2143
+ });
2074
2144
  }
2075
2145
  /**
2076
2146
  * TODO: [🧠][🪁] Maybe do allow to do auto-install if package not registered and not found
@@ -2585,15 +2655,28 @@ function createLlmToolsFromConfiguration(configuration, options) {
2585
2655
  */
2586
2656
  function $provideLlmToolsFromEnv(options) {
2587
2657
  if (options === void 0) { options = {}; }
2588
- if (!$isRunningInNode()) {
2589
- throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
2590
- }
2591
- var configuration = $provideLlmToolsConfigurationFromEnv();
2592
- if (configuration.length === 0) {
2593
- // TODO: [🥃]
2594
- throw new Error(spaceTrim(function (block) { return "\n No LLM tools found in the environment\n\n Please set one of environment variables:\n - OPENAI_API_KEY\n - ANTHROPIC_CLAUDE_API_KEY\n\n ".concat(block($registeredLlmToolsMessage()), "}\n "); }));
2595
- }
2596
- return createLlmToolsFromConfiguration(configuration, options);
2658
+ return __awaiter(this, void 0, void 0, function () {
2659
+ var configuration;
2660
+ return __generator(this, function (_a) {
2661
+ switch (_a.label) {
2662
+ case 0:
2663
+ if (!$isRunningInNode()) {
2664
+ throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
2665
+ }
2666
+ return [4 /*yield*/, $provideLlmToolsConfigurationFromEnv()];
2667
+ case 1:
2668
+ configuration = _a.sent();
2669
+ if (configuration.length === 0) {
2670
+ if ($llmToolsMetadataRegister.list().length === 0) {
2671
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n No LLM tools registered, this is probably a bug in the Promptbook library\n\n ".concat(block($registeredLlmToolsMessage()), "}\n "); }));
2672
+ }
2673
+ // TODO: [🥃]
2674
+ throw new Error(spaceTrim(function (block) { return "\n No LLM tools found in the environment\n\n ".concat(block($registeredLlmToolsMessage()), "}\n "); }));
2675
+ }
2676
+ return [2 /*return*/, createLlmToolsFromConfiguration(configuration, options)];
2677
+ }
2678
+ });
2679
+ });
2597
2680
  }
2598
2681
  /**
2599
2682
  * TODO: @@@ write `$provideLlmToolsFromEnv` vs `$provideLlmToolsConfigurationFromEnv` vs `createLlmToolsFromConfiguration`
@@ -2610,22 +2693,35 @@ function $provideLlmToolsFromEnv(options) {
2610
2693
  *
2611
2694
  * @private within the repository - for CLI utils
2612
2695
  */
2613
- function $provideLlmToolsForCli(options) {
2614
- if (!$isRunningInNode()) {
2615
- throw new EnvironmentMismatchError('Function `$provideLlmToolsForTestingAndScriptsAndPlayground` works only in Node.js environment');
2616
- }
2617
- var isCacheReloaded = (options !== null && options !== void 0 ? options : {}).isCacheReloaded;
2618
- return cacheLlmTools(countTotalUsage(
2619
- // <- Note: for example here we don`t want the [🌯]
2620
- $provideLlmToolsFromEnv()), {
2621
- storage: new FileCacheStorage({ fs: $provideFilesystemForNode() }, {
2622
- rootFolderPath: join(process.cwd(), DEFAULT_EXECUTIONS_CACHE_DIRNAME),
2623
- }),
2624
- isCacheReloaded: isCacheReloaded,
2696
+ function $provideLlmToolsForWizzardOrCli(options) {
2697
+ return __awaiter(this, void 0, void 0, function () {
2698
+ var isCacheReloaded, _a, _b;
2699
+ return __generator(this, function (_c) {
2700
+ switch (_c.label) {
2701
+ case 0:
2702
+ if (!$isRunningInNode()) {
2703
+ throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
2704
+ }
2705
+ isCacheReloaded = (options !== null && options !== void 0 ? options : {}).isCacheReloaded;
2706
+ _a = cacheLlmTools;
2707
+ _b = countTotalUsage;
2708
+ // <- Note: for example here we don`t want the [🌯]
2709
+ return [4 /*yield*/, $provideLlmToolsFromEnv()];
2710
+ case 1: return [2 /*return*/, _a.apply(void 0, [_b.apply(void 0, [
2711
+ // <- Note: for example here we don`t want the [🌯]
2712
+ _c.sent()]),
2713
+ {
2714
+ storage: new FileCacheStorage({ fs: $provideFilesystemForNode() }, {
2715
+ rootFolderPath: join(process.cwd(), DEFAULT_EXECUTIONS_CACHE_DIRNAME),
2716
+ }),
2717
+ isCacheReloaded: isCacheReloaded,
2718
+ }])];
2719
+ }
2720
+ });
2625
2721
  });
2626
2722
  }
2627
2723
  /**
2628
- * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
2724
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
2629
2725
  * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2630
2726
  * TODO: [🥃] Allow `ptbk make` without llm tools
2631
2727
  * TODO: This should be maybe not under `_common` but under `utils-internal` / `utils/internal`
@@ -2643,10 +2739,14 @@ function initializeListModelsCommand(program) {
2643
2739
  listModelsCommand.description(spaceTrim("\n List all available and configured LLM models\n "));
2644
2740
  listModelsCommand.action(function () { return __awaiter(_this, void 0, void 0, function () {
2645
2741
  return __generator(this, function (_a) {
2646
- $provideLlmToolsForCli({});
2647
- // <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
2648
- console.info($registeredLlmToolsMessage());
2649
- return [2 /*return*/, process.exit(0)];
2742
+ switch (_a.label) {
2743
+ case 0: return [4 /*yield*/, $provideLlmToolsForWizzardOrCli({})];
2744
+ case 1:
2745
+ _a.sent();
2746
+ // <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
2747
+ console.info($registeredLlmToolsMessage());
2748
+ return [2 /*return*/, process.exit(0)];
2749
+ }
2650
2750
  });
2651
2751
  }); });
2652
2752
  }
@@ -2682,99 +2782,67 @@ function collectionToJson(collection) {
2682
2782
  * TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
2683
2783
  */
2684
2784
 
2785
+ 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- 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- 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 workflow:\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- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",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 workflow:\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- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book.md"}];
2786
+
2685
2787
  /**
2686
- * This error type indicates that some tools are missing for pipeline execution or preparation
2788
+ * Function isValidJsonString will tell you if the string is valid JSON or not
2789
+ *
2790
+ * @public exported from `@promptbook/utils`
2791
+ */
2792
+ function isValidJsonString(value /* <- [👨‍⚖️] */) {
2793
+ try {
2794
+ JSON.parse(value);
2795
+ return true;
2796
+ }
2797
+ catch (error) {
2798
+ if (!(error instanceof Error)) {
2799
+ throw error;
2800
+ }
2801
+ if (error.message.includes('Unexpected token')) {
2802
+ return false;
2803
+ }
2804
+ return false;
2805
+ }
2806
+ }
2807
+
2808
+ /**
2809
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
2687
2810
  *
2688
2811
  * @public exported from `@promptbook/core`
2689
2812
  */
2690
- var MissingToolsError = /** @class */ (function (_super) {
2691
- __extends(MissingToolsError, _super);
2692
- function MissingToolsError(message) {
2693
- var _this = _super.call(this, spaceTrim$1(function (block) { return "\n ".concat(block(message), "\n\n Note: You have probbably forgot to provide some tools for pipeline execution or preparation\n\n "); })) || this;
2694
- _this.name = 'MissingToolsError';
2695
- Object.setPrototypeOf(_this, MissingToolsError.prototype);
2813
+ var ParseError = /** @class */ (function (_super) {
2814
+ __extends(ParseError, _super);
2815
+ function ParseError(message) {
2816
+ var _this = _super.call(this, message) || this;
2817
+ _this.name = 'ParseError';
2818
+ Object.setPrototypeOf(_this, ParseError.prototype);
2696
2819
  return _this;
2697
2820
  }
2698
- return MissingToolsError;
2821
+ return ParseError;
2699
2822
  }(Error));
2823
+ /**
2824
+ * TODO: Maybe split `ParseError` and `ApplyError`
2825
+ */
2700
2826
 
2701
2827
  /**
2702
- * Async version of Array.forEach
2828
+ * Function `validatePipelineString` will validate the if the string is a valid pipeline string
2829
+ * 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.
2703
2830
  *
2704
- * @param array - Array to iterate over
2705
- * @param options - Options for the function
2706
- * @param callbackfunction - Function to call for each item
2707
- * @public exported from `@promptbook/utils`
2708
- * @deprecated [🪂] Use queues instead
2831
+ * @param {string} pipelineString the candidate for a pipeline string
2832
+ * @returns {PipelineString} the same string as input, but validated as valid
2833
+ * @throws {ParseError} if the string is not a valid pipeline string
2834
+ * @public exported from `@promptbook/core`
2709
2835
  */
2710
- function forEachAsync(array, options, callbackfunction) {
2711
- return __awaiter(this, void 0, void 0, function () {
2712
- var _a, maxParallelCount, index, runningTasks, tasks, _loop_1, _b, _c, item, e_1_1;
2713
- var e_1, _d;
2714
- return __generator(this, function (_e) {
2715
- switch (_e.label) {
2716
- case 0:
2717
- _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? Infinity : _a;
2718
- index = 0;
2719
- runningTasks = [];
2720
- tasks = [];
2721
- _loop_1 = function (item) {
2722
- var currentIndex, task;
2723
- return __generator(this, function (_f) {
2724
- switch (_f.label) {
2725
- case 0:
2726
- currentIndex = index++;
2727
- task = callbackfunction(item, currentIndex, array);
2728
- tasks.push(task);
2729
- runningTasks.push(task);
2730
- /* not await */ Promise.resolve(task).then(function () {
2731
- runningTasks = runningTasks.filter(function (t) { return t !== task; });
2732
- });
2733
- if (!(maxParallelCount < runningTasks.length)) return [3 /*break*/, 2];
2734
- return [4 /*yield*/, Promise.race(runningTasks)];
2735
- case 1:
2736
- _f.sent();
2737
- _f.label = 2;
2738
- case 2: return [2 /*return*/];
2739
- }
2740
- });
2741
- };
2742
- _e.label = 1;
2743
- case 1:
2744
- _e.trys.push([1, 6, 7, 8]);
2745
- _b = __values(array), _c = _b.next();
2746
- _e.label = 2;
2747
- case 2:
2748
- if (!!_c.done) return [3 /*break*/, 5];
2749
- item = _c.value;
2750
- return [5 /*yield**/, _loop_1(item)];
2751
- case 3:
2752
- _e.sent();
2753
- _e.label = 4;
2754
- case 4:
2755
- _c = _b.next();
2756
- return [3 /*break*/, 2];
2757
- case 5: return [3 /*break*/, 8];
2758
- case 6:
2759
- e_1_1 = _e.sent();
2760
- e_1 = { error: e_1_1 };
2761
- return [3 /*break*/, 8];
2762
- case 7:
2763
- try {
2764
- if (_c && !_c.done && (_d = _b.return)) _d.call(_b);
2765
- }
2766
- finally { if (e_1) throw e_1.error; }
2767
- return [7 /*endfinally*/];
2768
- case 8: return [4 /*yield*/, Promise.all(tasks)];
2769
- case 9:
2770
- _e.sent();
2771
- return [2 /*return*/];
2772
- }
2773
- });
2774
- });
2836
+ function validatePipelineString(pipelineString) {
2837
+ if (isValidJsonString(pipelineString)) {
2838
+ throw new ParseError('Expected a book, but got a JSON string');
2839
+ }
2840
+ // <- TODO: Implement the validation + add tests when the pipeline logic considered as invalid
2841
+ return pipelineString;
2775
2842
  }
2776
-
2777
- 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"}];
2843
+ /**
2844
+ * TODO: [🧠][🈴] Where is the best location for this file
2845
+ */
2778
2846
 
2779
2847
  /**
2780
2848
  * Prettify the html code
@@ -2842,7 +2910,7 @@ function pipelineJsonToString(pipelineJson) {
2842
2910
  if (bookVersion !== "undefined") {
2843
2911
  commands.push("BOOK VERSION ".concat(bookVersion));
2844
2912
  }
2845
- // TODO: [main] !!!!! This increases size of the bundle and is probbably not necessary
2913
+ // TODO: [main] !!5 This increases size of the bundle and is probbably not necessary
2846
2914
  pipelineString = prettifyMarkdown(pipelineString);
2847
2915
  try {
2848
2916
  for (var _g = __values(parameters.filter(function (_a) {
@@ -2990,12 +3058,12 @@ function pipelineJsonToString(pipelineJson) {
2990
3058
  pipelineString += '```' + contentLanguage;
2991
3059
  pipelineString += '\n';
2992
3060
  pipelineString += spaceTrim(content);
2993
- // <- TODO: [main] !!! Escape
3061
+ // <- TODO: [main] !!3 Escape
2994
3062
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
2995
3063
  pipelineString += '\n';
2996
3064
  pipelineString += '```';
2997
3065
  pipelineString += '\n\n';
2998
- pipelineString += "`-> {".concat(resultingParameterName, "}`"); // <- TODO: [main] !!! If the parameter here has description, add it and use taskParameterJsonToString
3066
+ pipelineString += "`-> {".concat(resultingParameterName, "}`"); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
2999
3067
  }
3000
3068
  }
3001
3069
  catch (e_3_1) { e_3 = { error: e_3_1 }; }
@@ -3005,7 +3073,7 @@ function pipelineJsonToString(pipelineJson) {
3005
3073
  }
3006
3074
  finally { if (e_3) throw e_3.error; }
3007
3075
  }
3008
- return pipelineString;
3076
+ return validatePipelineString(pipelineString);
3009
3077
  }
3010
3078
  /**
3011
3079
  * @private internal utility of `pipelineJsonToString`
@@ -3026,25 +3094,6 @@ function taskParameterJsonToString(taskParameterJson) {
3026
3094
  * TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
3027
3095
  */
3028
3096
 
3029
- /**
3030
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
3031
- *
3032
- * @public exported from `@promptbook/core`
3033
- */
3034
- var ParseError = /** @class */ (function (_super) {
3035
- __extends(ParseError, _super);
3036
- function ParseError(message) {
3037
- var _this = _super.call(this, message) || this;
3038
- _this.name = 'ParseError';
3039
- Object.setPrototypeOf(_this, ParseError.prototype);
3040
- return _this;
3041
- }
3042
- return ParseError;
3043
- }(Error));
3044
- /**
3045
- * TODO: Maybe split `ParseError` and `ApplyError`
3046
- */
3047
-
3048
3097
  /**
3049
3098
  * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
3050
3099
  *
@@ -3099,7 +3148,7 @@ function isValidPromptbookVersion(version) {
3099
3148
  if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
3100
3149
  return false;
3101
3150
  }
3102
- // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
3151
+ // <- TODO: [main] !!3 Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
3103
3152
  return true;
3104
3153
  }
3105
3154
 
@@ -3170,9 +3219,6 @@ function isValidPipelineUrl(url) {
3170
3219
  if (!url.startsWith('https://')) {
3171
3220
  return false;
3172
3221
  }
3173
- if (!(url.endsWith('.book.md') || url.endsWith('.book') || url.endsWith('.book.md') || url.endsWith('.ptbk'))) {
3174
- return false;
3175
- }
3176
3222
  if (url.includes('#')) {
3177
3223
  // TODO: [🐠]
3178
3224
  return false;
@@ -3203,11 +3249,11 @@ function isValidPipelineUrl(url) {
3203
3249
  */
3204
3250
  function validatePipeline(pipeline) {
3205
3251
  if (IS_PIPELINE_LOGIC_VALIDATED) {
3206
- validatePipelineCore(pipeline);
3252
+ validatePipeline_InnerFunction(pipeline);
3207
3253
  }
3208
3254
  else {
3209
3255
  try {
3210
- validatePipelineCore(pipeline);
3256
+ validatePipeline_InnerFunction(pipeline);
3211
3257
  }
3212
3258
  catch (error) {
3213
3259
  if (!(error instanceof PipelineLogicError)) {
@@ -3221,7 +3267,7 @@ function validatePipeline(pipeline) {
3221
3267
  /**
3222
3268
  * @private internal function for `validatePipeline`
3223
3269
  */
3224
- function validatePipelineCore(pipeline) {
3270
+ function validatePipeline_InnerFunction(pipeline) {
3225
3271
  // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
3226
3272
  var e_1, _a, e_2, _b, e_3, _c;
3227
3273
  var pipelineIdentification = (function () {
@@ -3445,11 +3491,11 @@ function validatePipelineCore(pipeline) {
3445
3491
  _loop_3();
3446
3492
  }
3447
3493
  // Note: Check that formfactor is corresponding to the pipeline interface
3448
- // TODO: !!!!!! Implement this
3494
+ // TODO: !!6 Implement this
3449
3495
  // pipeline.formfactorName
3450
3496
  }
3451
3497
  /**
3452
- * TODO: !! [🧞‍♀️] Do not allow joker + foreach
3498
+ * TODO: [🧞‍♀️] Do not allow joker + foreach
3453
3499
  * TODO: [🧠] Work with promptbookVersion
3454
3500
  * TODO: Use here some json-schema, Zod or something similar and change it to:
3455
3501
  * > /**
@@ -3461,11 +3507,11 @@ function validatePipelineCore(pipeline) {
3461
3507
  * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
3462
3508
  */
3463
3509
  /**
3464
- * TODO: [🧳][main] !!!! Validate that all examples match expectations
3465
- * TODO: [🧳][🐝][main] !!!! Validate that knowledge is valid (non-void)
3466
- * TODO: [🧳][main] !!!! Validate that persona can be used only with CHAT variant
3467
- * TODO: [🧳][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
3468
- * TODO: [🧳][main] !!!! Validate that reserved parameter is not used as joker
3510
+ * TODO: [🧳][main] !!4 Validate that all examples match expectations
3511
+ * TODO: [🧳][🐝][main] !!4 Validate that knowledge is valid (non-void)
3512
+ * TODO: [🧳][main] !!4 Validate that persona can be used only with CHAT variant
3513
+ * TODO: [🧳][main] !!4 Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
3514
+ * TODO: [🧳][main] !!4 Validate that reserved parameter is not used as joker
3469
3515
  * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
3470
3516
  * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
3471
3517
  */
@@ -3601,7 +3647,7 @@ var SimplePipelineCollection = /** @class */ (function () {
3601
3647
  pipelineJsonToString(unpreparePipeline(pipeline)) !==
3602
3648
  pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
3603
3649
  var existing = this.collection.get(pipeline.pipelineUrl);
3604
- 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 ")));
3650
+ 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 ")));
3605
3651
  }
3606
3652
  // Note: [🧠] Overwrite existing pipeline with the same URL
3607
3653
  this.collection.set(pipeline.pipelineUrl, pipeline);
@@ -3666,6 +3712,22 @@ function createCollectionFromJson() {
3666
3712
  return new (SimplePipelineCollection.bind.apply(SimplePipelineCollection, __spreadArray([void 0], __read(promptbooks), false)))();
3667
3713
  }
3668
3714
 
3715
+ /**
3716
+ * This error type indicates that some tools are missing for pipeline execution or preparation
3717
+ *
3718
+ * @public exported from `@promptbook/core`
3719
+ */
3720
+ var MissingToolsError = /** @class */ (function (_super) {
3721
+ __extends(MissingToolsError, _super);
3722
+ function MissingToolsError(message) {
3723
+ var _this = _super.call(this, spaceTrim$1(function (block) { return "\n ".concat(block(message), "\n\n Note: You have probbably forgot to provide some tools for pipeline execution or preparation\n\n "); })) || this;
3724
+ _this.name = 'MissingToolsError';
3725
+ Object.setPrototypeOf(_this, MissingToolsError.prototype);
3726
+ return _this;
3727
+ }
3728
+ return MissingToolsError;
3729
+ }(Error));
3730
+
3669
3731
  /**
3670
3732
  * This error indicates problems parsing the format value
3671
3733
  *
@@ -3873,11 +3935,16 @@ function assertsExecutionSuccessful(executionResult) {
3873
3935
  /**
3874
3936
  * Determine if the pipeline is fully prepared
3875
3937
  *
3938
+ * @see https://github.com/webgptorg/promptbook/discussions/196
3939
+ *
3876
3940
  * @public exported from `@promptbook/core`
3877
3941
  */
3878
3942
  function isPipelinePrepared(pipeline) {
3879
3943
  // Note: Ignoring `pipeline.preparations` @@@
3880
3944
  // Note: Ignoring `pipeline.knowledgePieces` @@@
3945
+ if (pipeline.title === undefined || pipeline.title === '' || pipeline.title === DEFAULT_BOOK_TITLE) {
3946
+ return false;
3947
+ }
3881
3948
  if (!pipeline.personas.every(function (persona) { return persona.modelRequirements !== undefined; })) {
3882
3949
  return false;
3883
3950
  }
@@ -3893,7 +3960,7 @@ function isPipelinePrepared(pipeline) {
3893
3960
  return true;
3894
3961
  }
3895
3962
  /**
3896
- * TODO: [🔃][main] !! If the pipeline was prepared with different version or different set of models, prepare it once again
3963
+ * TODO: [🔃][main] If the pipeline was prepared with different version or different set of models, prepare it once again
3897
3964
  * TODO: [🐠] Maybe base this on `makeValidator`
3898
3965
  * TODO: [🧊] Pipeline can be partially prepared, this should return true ONLY if fully prepared
3899
3966
  * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
@@ -3903,25 +3970,100 @@ function isPipelinePrepared(pipeline) {
3903
3970
  */
3904
3971
 
3905
3972
  /**
3906
- * Serializes an error into a [🚉] JSON-serializable object
3973
+ * Format either small or big number
3907
3974
  *
3908
3975
  * @public exported from `@promptbook/utils`
3909
3976
  */
3910
- function serializeError(error) {
3911
- var name = error.name, message = error.message, stack = error.stack;
3912
- if (!Object.keys(ALL_ERRORS).includes(name)) {
3913
- console.error(spaceTrim(function (block) { return "\n \n Cannot serialize error with name \"".concat(name, "\"\n\n ").concat(block(stack || message), "\n \n "); }));
3977
+ function numberToString(value) {
3978
+ if (value === 0) {
3979
+ return '0';
3914
3980
  }
3915
- return {
3916
- name: name,
3917
- message: message,
3918
- stack: stack,
3919
- };
3920
- }
3921
-
3922
- /**
3923
- * Parses the given script and returns the list of all used variables that are not defined in the script
3924
- *
3981
+ else if (Number.isNaN(value)) {
3982
+ return VALUE_STRINGS.nan;
3983
+ }
3984
+ else if (value === Infinity) {
3985
+ return VALUE_STRINGS.infinity;
3986
+ }
3987
+ else if (value === -Infinity) {
3988
+ return VALUE_STRINGS.negativeInfinity;
3989
+ }
3990
+ for (var exponent = 0; exponent < 15; exponent++) {
3991
+ var factor = Math.pow(10, exponent);
3992
+ var valueRounded = Math.round(value * factor) / factor;
3993
+ if (Math.abs(value - valueRounded) / value < SMALL_NUMBER) {
3994
+ return valueRounded.toFixed(exponent);
3995
+ }
3996
+ }
3997
+ return value.toString();
3998
+ }
3999
+
4000
+ /**
4001
+ * Function `valueToString` will convert the given value to string
4002
+ * This is useful and used in the `templateParameters` function
4003
+ *
4004
+ * Note: This function is not just calling `toString` method
4005
+ * It's more complex and can handle this conversion specifically for LLM models
4006
+ * See `VALUE_STRINGS`
4007
+ *
4008
+ * Note: There are 2 similar functions
4009
+ * - `valueToString` converts value to string for LLM models as human-readable string
4010
+ * - `asSerializable` converts value to string to preserve full information to be able to convert it back
4011
+ *
4012
+ * @public exported from `@promptbook/utils`
4013
+ */
4014
+ function valueToString(value) {
4015
+ try {
4016
+ if (value === '') {
4017
+ return VALUE_STRINGS.empty;
4018
+ }
4019
+ else if (value === null) {
4020
+ return VALUE_STRINGS.null;
4021
+ }
4022
+ else if (value === undefined) {
4023
+ return VALUE_STRINGS.undefined;
4024
+ }
4025
+ else if (typeof value === 'string') {
4026
+ return value;
4027
+ }
4028
+ else if (typeof value === 'number') {
4029
+ return numberToString(value);
4030
+ }
4031
+ else if (value instanceof Date) {
4032
+ return value.toISOString();
4033
+ }
4034
+ else {
4035
+ return JSON.stringify(value);
4036
+ }
4037
+ }
4038
+ catch (error) {
4039
+ if (!(error instanceof Error)) {
4040
+ throw error;
4041
+ }
4042
+ console.error(error);
4043
+ return VALUE_STRINGS.unserializable;
4044
+ }
4045
+ }
4046
+
4047
+ /**
4048
+ * Serializes an error into a [🚉] JSON-serializable object
4049
+ *
4050
+ * @public exported from `@promptbook/utils`
4051
+ */
4052
+ function serializeError(error) {
4053
+ var name = error.name, message = error.message, stack = error.stack;
4054
+ if (!Object.keys(ALL_ERRORS).includes(name)) {
4055
+ console.error(spaceTrim(function (block) { return "\n \n Cannot serialize error with name \"".concat(name, "\"\n\n ").concat(block(stack || message), "\n \n "); }));
4056
+ }
4057
+ return {
4058
+ name: name,
4059
+ message: message,
4060
+ stack: stack,
4061
+ };
4062
+ }
4063
+
4064
+ /**
4065
+ * Parses the given script and returns the list of all used variables that are not defined in the script
4066
+ *
3925
4067
  * @param script from which to extract the variables
3926
4068
  * @returns the list of variable names
3927
4069
  * @throws {ParseError} if the script is invalid
@@ -3973,7 +4115,7 @@ function extractVariablesFromScript(script) {
3973
4115
  if (!(error instanceof Error)) {
3974
4116
  throw error;
3975
4117
  }
3976
- 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)
4118
+ 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)
3977
4119
  .map(function (variableName, i) { return "".concat(i + 1, ") ").concat(variableName); })
3978
4120
  .join('\n'), "\n\n\n The script:\n\n ```javascript\n ").concat(block(originalScript), "\n ```\n "); }));
3979
4121
  }
@@ -4253,27 +4395,6 @@ var CsvFormatDefinition = {
4253
4395
  * TODO: [🏢] Allow to expect something inside CSV objects and other formats
4254
4396
  */
4255
4397
 
4256
- /**
4257
- * Function isValidJsonString will tell you if the string is valid JSON or not
4258
- *
4259
- * @public exported from `@promptbook/utils`
4260
- */
4261
- function isValidJsonString(value /* <- [👨‍⚖️] */) {
4262
- try {
4263
- JSON.parse(value);
4264
- return true;
4265
- }
4266
- catch (error) {
4267
- if (!(error instanceof Error)) {
4268
- throw error;
4269
- }
4270
- if (error.message.includes('Unexpected token')) {
4271
- return false;
4272
- }
4273
- return false;
4274
- }
4275
- }
4276
-
4277
4398
  /**
4278
4399
  * Definition for JSON format
4279
4400
  *
@@ -4611,81 +4732,6 @@ function arrayableToArray(input) {
4611
4732
  return [input];
4612
4733
  }
4613
4734
 
4614
- /**
4615
- * Format either small or big number
4616
- *
4617
- * @public exported from `@promptbook/utils`
4618
- */
4619
- function numberToString(value) {
4620
- if (value === 0) {
4621
- return '0';
4622
- }
4623
- else if (Number.isNaN(value)) {
4624
- return VALUE_STRINGS.nan;
4625
- }
4626
- else if (value === Infinity) {
4627
- return VALUE_STRINGS.infinity;
4628
- }
4629
- else if (value === -Infinity) {
4630
- return VALUE_STRINGS.negativeInfinity;
4631
- }
4632
- for (var exponent = 0; exponent < 15; exponent++) {
4633
- var factor = Math.pow(10, exponent);
4634
- var valueRounded = Math.round(value * factor) / factor;
4635
- if (Math.abs(value - valueRounded) / value < SMALL_NUMBER) {
4636
- return valueRounded.toFixed(exponent);
4637
- }
4638
- }
4639
- return value.toString();
4640
- }
4641
-
4642
- /**
4643
- * Function `valueToString` will convert the given value to string
4644
- * This is useful and used in the `templateParameters` function
4645
- *
4646
- * Note: This function is not just calling `toString` method
4647
- * It's more complex and can handle this conversion specifically for LLM models
4648
- * See `VALUE_STRINGS`
4649
- *
4650
- * Note: There are 2 similar functions
4651
- * - `valueToString` converts value to string for LLM models as human-readable string
4652
- * - `asSerializable` converts value to string to preserve full information to be able to convert it back
4653
- *
4654
- * @public exported from `@promptbook/utils`
4655
- */
4656
- function valueToString(value) {
4657
- try {
4658
- if (value === '') {
4659
- return VALUE_STRINGS.empty;
4660
- }
4661
- else if (value === null) {
4662
- return VALUE_STRINGS.null;
4663
- }
4664
- else if (value === undefined) {
4665
- return VALUE_STRINGS.undefined;
4666
- }
4667
- else if (typeof value === 'string') {
4668
- return value;
4669
- }
4670
- else if (typeof value === 'number') {
4671
- return numberToString(value);
4672
- }
4673
- else if (value instanceof Date) {
4674
- return value.toISOString();
4675
- }
4676
- else {
4677
- return JSON.stringify(value);
4678
- }
4679
- }
4680
- catch (error) {
4681
- if (!(error instanceof Error)) {
4682
- throw error;
4683
- }
4684
- console.error(error);
4685
- return VALUE_STRINGS.unserializable;
4686
- }
4687
- }
4688
-
4689
4735
  /**
4690
4736
  * Replaces parameters in template with values from parameters object
4691
4737
  *
@@ -4742,6 +4788,8 @@ function templateParameters(template, parameters) {
4742
4788
  throw new PipelineExecutionError("Parameter `{".concat(parameterName, "}` is not defined"));
4743
4789
  }
4744
4790
  parameterValue = valueToString(parameterValue);
4791
+ // Escape curly braces in parameter values to prevent prompt-injection
4792
+ parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4745
4793
  if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
4746
4794
  parameterValue = parameterValue
4747
4795
  .split('\n')
@@ -5101,7 +5149,7 @@ function executeAttempts(options) {
5101
5149
  promptTitle: task.title,
5102
5150
  promptMessage: templateParameters(task.description || '', parameters),
5103
5151
  defaultValue: templateParameters(preparedContent, parameters),
5104
- // TODO: [🧠] !! Figure out how to define placeholder in .book.md file
5152
+ // TODO: [🧠] Figure out how to define placeholder in .book.md file
5105
5153
  placeholder: undefined,
5106
5154
  priority: priority,
5107
5155
  }))];
@@ -5801,7 +5849,10 @@ function executePipeline(options) {
5801
5849
  finally { if (e_2) throw e_2.error; }
5802
5850
  return [7 /*endfinally*/];
5803
5851
  case 19:
5804
- parametersToPass = inputParameters;
5852
+ parametersToPass = Object.fromEntries(Object.entries(inputParameters).map(function (_a) {
5853
+ var _b = __read(_a, 2), key = _b[0], value = _b[1];
5854
+ return [key, valueToString(value)];
5855
+ }));
5805
5856
  _g.label = 20;
5806
5857
  case 20:
5807
5858
  _g.trys.push([20, 25, , 28]);
@@ -6037,46 +6088,122 @@ function createPipelineExecutor(options) {
6037
6088
  */
6038
6089
 
6039
6090
  /**
6040
- * Prepares the persona for the pipeline
6091
+ * Async version of Array.forEach
6041
6092
  *
6042
- * @see https://github.com/webgptorg/promptbook/discussions/22
6043
- * @public exported from `@promptbook/core`
6093
+ * @param array - Array to iterate over
6094
+ * @param options - Options for the function
6095
+ * @param callbackfunction - Function to call for each item
6096
+ * @public exported from `@promptbook/utils`
6097
+ * @deprecated [🪂] Use queues instead
6044
6098
  */
6045
- function preparePersona(personaDescription, tools, options) {
6099
+ function forEachAsync(array, options, callbackfunction) {
6046
6100
  return __awaiter(this, void 0, void 0, function () {
6047
- var _a, isVerbose, collection, preparePersonaExecutor, _b, _llms, llmTools, availableModels, availableModelNames, result, outputParameters, modelRequirementsRaw, modelRequirements, modelName, systemMessage, temperature;
6048
- var _c;
6049
- return __generator(this, function (_d) {
6050
- switch (_d.label) {
6101
+ var _a, maxParallelCount, index, runningTasks, tasks, _loop_1, _b, _c, item, e_1_1;
6102
+ var e_1, _d;
6103
+ return __generator(this, function (_e) {
6104
+ switch (_e.label) {
6051
6105
  case 0:
6052
- _a = options.isVerbose, isVerbose = _a === void 0 ? DEFAULT_IS_VERBOSE : _a;
6053
- if (tools === undefined || tools.llm === undefined) {
6054
- throw new MissingToolsError('LLM tools are required for preparing persona');
6055
- }
6056
- collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
6057
- _b = createPipelineExecutor;
6058
- _c = {};
6059
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book.md')];
6106
+ _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? Infinity : _a;
6107
+ index = 0;
6108
+ runningTasks = [];
6109
+ tasks = [];
6110
+ _loop_1 = function (item) {
6111
+ var currentIndex, task;
6112
+ return __generator(this, function (_f) {
6113
+ switch (_f.label) {
6114
+ case 0:
6115
+ currentIndex = index++;
6116
+ task = callbackfunction(item, currentIndex, array);
6117
+ tasks.push(task);
6118
+ runningTasks.push(task);
6119
+ /* not await */ Promise.resolve(task).then(function () {
6120
+ runningTasks = runningTasks.filter(function (t) { return t !== task; });
6121
+ });
6122
+ if (!(maxParallelCount < runningTasks.length)) return [3 /*break*/, 2];
6123
+ return [4 /*yield*/, Promise.race(runningTasks)];
6124
+ case 1:
6125
+ _f.sent();
6126
+ _f.label = 2;
6127
+ case 2: return [2 /*return*/];
6128
+ }
6129
+ });
6130
+ };
6131
+ _e.label = 1;
6060
6132
  case 1:
6061
- preparePersonaExecutor = _b.apply(void 0, [(_c.pipeline = _d.sent(),
6062
- _c.tools = tools,
6063
- _c)]);
6064
- _llms = arrayableToArray(tools.llm);
6065
- llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools.apply(void 0, __spreadArray([], __read(_llms), false));
6066
- return [4 /*yield*/, llmTools.listModels()];
6133
+ _e.trys.push([1, 6, 7, 8]);
6134
+ _b = __values(array), _c = _b.next();
6135
+ _e.label = 2;
6067
6136
  case 2:
6068
- availableModels = _d.sent();
6069
- availableModelNames = availableModels
6070
- .filter(function (_a) {
6071
- var modelVariant = _a.modelVariant;
6072
- return modelVariant === 'CHAT';
6073
- })
6074
- .map(function (_a) {
6075
- var modelName = _a.modelName;
6076
- return modelName;
6077
- })
6078
- .join(',');
6079
- return [4 /*yield*/, preparePersonaExecutor({ availableModelNames: availableModelNames, personaDescription: personaDescription })];
6137
+ if (!!_c.done) return [3 /*break*/, 5];
6138
+ item = _c.value;
6139
+ return [5 /*yield**/, _loop_1(item)];
6140
+ case 3:
6141
+ _e.sent();
6142
+ _e.label = 4;
6143
+ case 4:
6144
+ _c = _b.next();
6145
+ return [3 /*break*/, 2];
6146
+ case 5: return [3 /*break*/, 8];
6147
+ case 6:
6148
+ e_1_1 = _e.sent();
6149
+ e_1 = { error: e_1_1 };
6150
+ return [3 /*break*/, 8];
6151
+ case 7:
6152
+ try {
6153
+ if (_c && !_c.done && (_d = _b.return)) _d.call(_b);
6154
+ }
6155
+ finally { if (e_1) throw e_1.error; }
6156
+ return [7 /*endfinally*/];
6157
+ case 8: return [4 /*yield*/, Promise.all(tasks)];
6158
+ case 9:
6159
+ _e.sent();
6160
+ return [2 /*return*/];
6161
+ }
6162
+ });
6163
+ });
6164
+ }
6165
+
6166
+ /**
6167
+ * Prepares the persona for the pipeline
6168
+ *
6169
+ * @see https://github.com/webgptorg/promptbook/discussions/22
6170
+ * @public exported from `@promptbook/core`
6171
+ */
6172
+ function preparePersona(personaDescription, tools, options) {
6173
+ return __awaiter(this, void 0, void 0, function () {
6174
+ var _a, isVerbose, collection, preparePersonaExecutor, _b, _llms, llmTools, availableModels, availableModelNames, result, outputParameters, modelRequirementsRaw, modelRequirements, modelName, systemMessage, temperature;
6175
+ var _c;
6176
+ return __generator(this, function (_d) {
6177
+ switch (_d.label) {
6178
+ case 0:
6179
+ _a = options.isVerbose, isVerbose = _a === void 0 ? DEFAULT_IS_VERBOSE : _a;
6180
+ if (tools === undefined || tools.llm === undefined) {
6181
+ throw new MissingToolsError('LLM tools are required for preparing persona');
6182
+ }
6183
+ collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
6184
+ _b = createPipelineExecutor;
6185
+ _c = {};
6186
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book.md')];
6187
+ case 1:
6188
+ preparePersonaExecutor = _b.apply(void 0, [(_c.pipeline = _d.sent(),
6189
+ _c.tools = tools,
6190
+ _c)]);
6191
+ _llms = arrayableToArray(tools.llm);
6192
+ llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools.apply(void 0, __spreadArray([], __read(_llms), false));
6193
+ return [4 /*yield*/, llmTools.listModels()];
6194
+ case 2:
6195
+ availableModels = _d.sent();
6196
+ availableModelNames = availableModels
6197
+ .filter(function (_a) {
6198
+ var modelVariant = _a.modelVariant;
6199
+ return modelVariant === 'CHAT';
6200
+ })
6201
+ .map(function (_a) {
6202
+ var modelName = _a.modelName;
6203
+ return modelName;
6204
+ })
6205
+ .join(',');
6206
+ return [4 /*yield*/, preparePersonaExecutor({ availableModelNames: availableModelNames, personaDescription: personaDescription })];
6080
6207
  case 3:
6081
6208
  result = _d.sent();
6082
6209
  assertsExecutionSuccessful(result);
@@ -6098,10 +6225,10 @@ function preparePersona(personaDescription, tools, options) {
6098
6225
  });
6099
6226
  }
6100
6227
  /**
6101
- * TODO: [🔃][main] !! If the persona was prepared with different version or different set of models, prepare it once again
6102
- * TODO: [🏢] !! Check validity of `modelName` in pipeline
6103
- * TODO: [🏢] !! Check validity of `systemMessage` in pipeline
6104
- * TODO: [🏢] !! Check validity of `temperature` in pipeline
6228
+ * TODO: [🔃][main] If the persona was prepared with different version or different set of models, prepare it once again
6229
+ * TODO: [🏢] Check validity of `modelName` in pipeline
6230
+ * TODO: [🏢] Check validity of `systemMessage` in pipeline
6231
+ * TODO: [🏢] Check validity of `temperature` in pipeline
6105
6232
  */
6106
6233
 
6107
6234
  /**
@@ -6311,6 +6438,9 @@ var scraperFetch = function (url, init) { return __awaiter(void 0, void 0, void
6311
6438
  }
6312
6439
  });
6313
6440
  }); };
6441
+ /**
6442
+ * TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
6443
+ */
6314
6444
 
6315
6445
  /**
6316
6446
  * @@@
@@ -6378,7 +6508,7 @@ function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
6378
6508
  },
6379
6509
  }];
6380
6510
  case 2:
6381
- if (!(isValidFilePath(sourceContent) || /\.[a-z]{1,10}$/i.exec(sourceContent))) return [3 /*break*/, 4];
6511
+ if (!isValidFilePath(sourceContent)) return [3 /*break*/, 4];
6382
6512
  if (tools.fs === undefined) {
6383
6513
  throw new EnvironmentMismatchError('Can not import file knowledge without filesystem tools');
6384
6514
  // <- TODO: [🧠] What is the best error type here`
@@ -6393,7 +6523,7 @@ function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
6393
6523
  return [4 /*yield*/, isFileExisting(filename_1, tools.fs)];
6394
6524
  case 3:
6395
6525
  if (!(_f.sent())) {
6396
- 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 "); }));
6526
+ 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 "); }));
6397
6527
  }
6398
6528
  // TODO: [🧠][😿] Test security file - file is scoped to the project (BUT maybe do this in `filesystemTools`)
6399
6529
  return [2 /*return*/, {
@@ -6506,7 +6636,7 @@ function prepareKnowledgePieces(knowledgeSources, tools, options) {
6506
6636
  partialPieces = __spreadArray([], __read(partialPiecesUnchecked), false);
6507
6637
  return [2 /*return*/, "break"];
6508
6638
  }
6509
- 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
6639
+ 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
6510
6640
  .split('\n')
6511
6641
  .map(function (line) { return "> ".concat(line); })
6512
6642
  .join('\n')), "\n\n ").concat(block($registeredScrapersMessage(scrapers)), "\n\n\n "); }));
@@ -6544,7 +6674,7 @@ function prepareKnowledgePieces(knowledgeSources, tools, options) {
6544
6674
  return [7 /*endfinally*/];
6545
6675
  case 9:
6546
6676
  if (partialPieces === null) {
6547
- throw new KnowledgeScrapeError(spaceTrim(function (block) { return "\n Cannot scrape knowledge\n \n The source:\n > ".concat(block(knowledgeSource.sourceContent
6677
+ throw new KnowledgeScrapeError(spaceTrim(function (block) { return "\n Cannot scrape knowledge\n\n The source:\n > ".concat(block(knowledgeSource.sourceContent
6548
6678
  .split('\n')
6549
6679
  .map(function (line) { return "> ".concat(line); })
6550
6680
  .join('\n')), "\n\n No scraper found for the mime type \"").concat(sourceHandler.mimeType, "\"\n\n ").concat(block($registeredScrapersMessage(scrapers)), "\n\n\n "); }));
@@ -6635,7 +6765,7 @@ function prepareTasks(pipeline, tools, options) {
6635
6765
  * TODO: [😂] Adding knowledge should be convert to async high-level abstractions, simmilar thing with expectations to sync high-level abstractions
6636
6766
  * TODO: [🧠] Add context to each task (if missing)
6637
6767
  * TODO: [🧠] What is better name `prepareTask` or `prepareTaskAndParameters`
6638
- * TODO: [♨][main] !!! Prepare index the examples and maybe tasks
6768
+ * TODO: [♨][main] !!3 Prepare index the examples and maybe tasks
6639
6769
  * TODO: Write tests for `preparePipeline`
6640
6770
  * TODO: [🏏] Leverage the batch API and build queues @see https://platform.openai.com/docs/guides/batch
6641
6771
  * TODO: [🧊] In future one preparation can take data from previous preparation and save tokens and time
@@ -6645,6 +6775,8 @@ function prepareTasks(pipeline, tools, options) {
6645
6775
  /**
6646
6776
  * Prepare pipeline from string (markdown) format to JSON format
6647
6777
  *
6778
+ * @see https://github.com/webgptorg/promptbook/discussions/196
6779
+ *
6648
6780
  * Note: This function does not validate logic of the pipeline
6649
6781
  * Note: This function acts as part of compilation process
6650
6782
  * Note: When the pipeline is already prepared, it returns the same pipeline
@@ -6657,16 +6789,17 @@ function preparePipeline(pipeline, tools, options) {
6657
6789
  <- TODO: [🧠][🪑] `promptbookVersion` */
6658
6790
  knowledgeSources /*
6659
6791
  <- TODO: [🧊] `knowledgePieces` */, personas /*
6660
- <- TODO: [🧊] `preparations` */, _llms, llmTools, llmToolsWithUsage, currentPreparation, preparations, preparedPersonas, knowledgeSourcesPrepared, partialknowledgePiecesPrepared, knowledgePiecesPrepared, tasksPrepared /* TODO: parameters: parametersPrepared*/;
6792
+ <- TODO: [🧊] `preparations` */, sources, _llms, llmTools, llmToolsWithUsage, currentPreparation, preparations, title, collection, prepareTitleExecutor, _c, result, outputParameters, titleRaw, preparedPersonas, knowledgeSourcesPrepared, partialknowledgePiecesPrepared, knowledgePiecesPrepared, tasksPrepared /* TODO: parameters: parametersPrepared*/;
6793
+ var _d;
6661
6794
  var _this = this;
6662
- return __generator(this, function (_c) {
6663
- switch (_c.label) {
6795
+ return __generator(this, function (_e) {
6796
+ switch (_e.label) {
6664
6797
  case 0:
6665
6798
  if (isPipelinePrepared(pipeline)) {
6666
6799
  return [2 /*return*/, pipeline];
6667
6800
  }
6668
6801
  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;
6669
- parameters = pipeline.parameters, tasks = pipeline.tasks, knowledgeSources = pipeline.knowledgeSources, personas = pipeline.personas;
6802
+ parameters = pipeline.parameters, tasks = pipeline.tasks, knowledgeSources = pipeline.knowledgeSources, personas = pipeline.personas, sources = pipeline.sources;
6670
6803
  if (tools === undefined || tools.llm === undefined) {
6671
6804
  throw new MissingToolsError('LLM tools are required for preparing the pipeline');
6672
6805
  }
@@ -6684,6 +6817,33 @@ function preparePipeline(pipeline, tools, options) {
6684
6817
  // <- TODO: [🧊]
6685
6818
  currentPreparation,
6686
6819
  ];
6820
+ title = pipeline.title;
6821
+ if (!(title === undefined || title === '' || title === DEFAULT_BOOK_TITLE)) return [3 /*break*/, 3];
6822
+ collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
6823
+ _c = createPipelineExecutor;
6824
+ _d = {};
6825
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-title.book.md')];
6826
+ case 1:
6827
+ prepareTitleExecutor = _c.apply(void 0, [(_d.pipeline = _e.sent(),
6828
+ _d.tools = tools,
6829
+ _d)]);
6830
+ return [4 /*yield*/, prepareTitleExecutor({
6831
+ book: sources.map(function (_a) {
6832
+ var content = _a.content;
6833
+ return content;
6834
+ }).join('\n\n'),
6835
+ })];
6836
+ case 2:
6837
+ result = _e.sent();
6838
+ assertsExecutionSuccessful(result);
6839
+ outputParameters = result.outputParameters;
6840
+ titleRaw = outputParameters.title;
6841
+ if (isVerbose) {
6842
+ console.info("The title is \"".concat(titleRaw, "\""));
6843
+ }
6844
+ title = titleRaw || DEFAULT_BOOK_TITLE;
6845
+ _e.label = 3;
6846
+ case 3:
6687
6847
  preparedPersonas = new Array(personas.length);
6688
6848
  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 () {
6689
6849
  var modelRequirements, preparedPersona;
@@ -6702,12 +6862,12 @@ function preparePipeline(pipeline, tools, options) {
6702
6862
  }
6703
6863
  });
6704
6864
  }); })];
6705
- case 1:
6706
- _c.sent();
6865
+ case 4:
6866
+ _e.sent();
6707
6867
  knowledgeSourcesPrepared = knowledgeSources.map(function (source) { return (__assign(__assign({}, source), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
6708
6868
  return [4 /*yield*/, prepareKnowledgePieces(knowledgeSources /* <- TODO: [🧊] {knowledgeSources, knowledgePieces} */, __assign(__assign({}, tools), { llm: llmToolsWithUsage }), __assign(__assign({}, options), { rootDirname: rootDirname, maxParallelCount: maxParallelCount /* <- TODO: [🪂] */, isVerbose: isVerbose }))];
6709
- case 2:
6710
- partialknowledgePiecesPrepared = _c.sent();
6869
+ case 5:
6870
+ partialknowledgePiecesPrepared = _e.sent();
6711
6871
  knowledgePiecesPrepared = partialknowledgePiecesPrepared.map(function (piece) { return (__assign(__assign({}, piece), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
6712
6872
  return [4 /*yield*/, prepareTasks({
6713
6873
  parameters: parameters,
@@ -6718,8 +6878,8 @@ function preparePipeline(pipeline, tools, options) {
6718
6878
  maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
6719
6879
  isVerbose: isVerbose,
6720
6880
  })];
6721
- case 3:
6722
- tasksPrepared = (_c.sent()).tasksPrepared;
6881
+ case 6:
6882
+ tasksPrepared = (_e.sent()).tasksPrepared;
6723
6883
  // ----- /Tasks preparation -----
6724
6884
  // TODO: [😂] Use here all `AsyncHighLevelAbstraction`
6725
6885
  // Note: Count total usage
@@ -6730,7 +6890,7 @@ function preparePipeline(pipeline, tools, options) {
6730
6890
  order: ORDER_OF_PIPELINE_JSON,
6731
6891
  value: __assign(__assign({}, pipeline), {
6732
6892
  // <- TODO: Probbably deeply clone the pipeline because `$exportJson` freezes the subobjects
6733
- knowledgeSources: knowledgeSourcesPrepared, knowledgePieces: knowledgePiecesPrepared, tasks: __spreadArray([], __read(tasksPrepared), false),
6893
+ title: title, knowledgeSources: knowledgeSourcesPrepared, knowledgePieces: knowledgePiecesPrepared, tasks: __spreadArray([], __read(tasksPrepared), false),
6734
6894
  // <- TODO: [🪓] Here should be no need for spreading new array, just ` tasks: tasksPrepared`
6735
6895
  personas: preparedPersonas, preparations: __spreadArray([], __read(preparations), false) }),
6736
6896
  })];
@@ -6825,7 +6985,7 @@ var knowledgeCommandParser = {
6825
6985
  if (sourceContent === '') {
6826
6986
  throw new ParseError("Source is not defined");
6827
6987
  }
6828
- // TODO: [main] !!!! Following checks should be applied every link in the `sourceContent`
6988
+ // TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
6829
6989
  if (sourceContent.startsWith('http://')) {
6830
6990
  throw new ParseError("Source is not secure");
6831
6991
  }
@@ -6997,7 +7157,7 @@ var sectionCommandParser = {
6997
7157
  expectResultingParameterName();
6998
7158
  var parameter = $pipelineJson.parameters.find(function (param) { return param.name === $taskJson.resultingParameterName; });
6999
7159
  if (parameter === undefined) {
7000
- // TODO: !!!!!! Change to logic error for higher level abstractions to work
7160
+ // TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
7001
7161
  throw new ParseError("Parameter `{".concat($taskJson.resultingParameterName, "}` is not defined so can not define example value of it"));
7002
7162
  }
7003
7163
  parameter.exampleValues = parameter.exampleValues || [];
@@ -7008,7 +7168,7 @@ var sectionCommandParser = {
7008
7168
  if (command.taskType === 'KNOWLEDGE') {
7009
7169
  knowledgeCommandParser.$applyToPipelineJson({
7010
7170
  type: 'KNOWLEDGE',
7011
- sourceContent: $taskJson.content, // <- TODO: [🐝][main] !!! Work with KNOWLEDGE which not referring to the source file or website, but its content itself
7171
+ sourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
7012
7172
  }, $pipelineJson);
7013
7173
  $taskJson.isTask = false;
7014
7174
  return;
@@ -7887,20 +8047,24 @@ var ChatbotFormfactorDefinition = {
7887
8047
  */
7888
8048
  var GeneratorFormfactorDefinition = {
7889
8049
  name: 'GENERATOR',
7890
- description: "@@@",
8050
+ description: "Generates any kind (in HTML with possible scripts and css format) of content from input message",
7891
8051
  documentationUrl: "https://github.com/webgptorg/promptbook/discussions/184",
7892
8052
  pipelineInterface: {
7893
8053
  inputParameters: [
7894
- /* @@@ */
7895
8054
  {
7896
- name: 'nonce',
7897
- description: 'Just to prevent GENERATOR to be set as implicit formfactor',
8055
+ name: 'inputMessage',
8056
+ description: "Input message to be image made from",
7898
8057
  isInput: true,
7899
8058
  isOutput: false,
7900
8059
  },
7901
8060
  ],
7902
8061
  outputParameters: [
7903
- /* @@@ */
8062
+ {
8063
+ name: 'result',
8064
+ description: "Result in HTML to be shown to user",
8065
+ isInput: false,
8066
+ isOutput: true,
8067
+ },
7904
8068
  ],
7905
8069
  },
7906
8070
  };
@@ -7932,6 +8096,35 @@ var GenericFormfactorDefinition = {
7932
8096
  pipelineInterface: GENERIC_PIPELINE_INTERFACE,
7933
8097
  };
7934
8098
 
8099
+ /**
8100
+ * Image generator is form of app that generates image from input message
8101
+ *
8102
+ * @public exported from `@promptbook/core`
8103
+ */
8104
+ var ImageGeneratorFormfactorDefinition = {
8105
+ name: 'IMAGE_GENERATOR',
8106
+ description: "Generates prompt for image generation from input message",
8107
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/184",
8108
+ pipelineInterface: {
8109
+ inputParameters: [
8110
+ {
8111
+ name: 'inputMessage',
8112
+ description: "Input message to be image made from",
8113
+ isInput: true,
8114
+ isOutput: false,
8115
+ },
8116
+ ],
8117
+ outputParameters: [
8118
+ {
8119
+ name: 'prompt',
8120
+ description: "Prompt to be used for image generation",
8121
+ isInput: false,
8122
+ isOutput: true,
8123
+ },
8124
+ ],
8125
+ },
8126
+ };
8127
+
7935
8128
  /**
7936
8129
  * Matcher is form of app that @@@
7937
8130
  *
@@ -8030,6 +8223,7 @@ var FORMFACTOR_DEFINITIONS = [
8030
8223
  SheetsFormfactorDefinition,
8031
8224
  MatcherFormfactorDefinition,
8032
8225
  GeneratorFormfactorDefinition,
8226
+ ImageGeneratorFormfactorDefinition,
8033
8227
  ];
8034
8228
  /**
8035
8229
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -8416,7 +8610,7 @@ var parameterCommandParser = {
8416
8610
  * Note: `$` is used to indicate that this function mutates given `pipelineJson`
8417
8611
  */
8418
8612
  $applyToPipelineJson: function (command, $pipelineJson) {
8419
- // Note: [🍣] Do nothing, its application is implemented separately in `precompilePipeline`
8613
+ // Note: [🍣] Do nothing, its application is implemented separately in `parsePipeline`
8420
8614
  },
8421
8615
  /**
8422
8616
  * Apply the PARAMETER command to the `pipelineJson`
@@ -8424,7 +8618,7 @@ var parameterCommandParser = {
8424
8618
  * Note: `$` is used to indicate that this function mutates given `taskJson`
8425
8619
  */
8426
8620
  $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
8427
- // Note: [🍣] Do nothing, its application is implemented separately in `precompilePipeline`
8621
+ // Note: [🍣] Do nothing, its application is implemented separately in `parsePipeline`
8428
8622
  },
8429
8623
  /**
8430
8624
  * Converts the PARAMETER command back to string
@@ -8919,7 +9113,7 @@ var COMMANDS = [
8919
9113
  instrumentCommandParser,
8920
9114
  personaCommandParser,
8921
9115
  foreachCommandParser,
8922
- boilerplateCommandParser, // <- TODO: !! Only in development, remove in production
9116
+ boilerplateCommandParser, // <- TODO: Only in development, remove in production
8923
9117
  // <- 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
8924
9118
  ];
8925
9119
  /**
@@ -9343,7 +9537,7 @@ var QuickChatbotHla = {
9343
9537
  isOutput: true,
9344
9538
  exampleValues: ['Hello, I am a Pavol`s virtual avatar. How can I help you?'],
9345
9539
  });
9346
- // TODO: !!!!!! spaceTrim
9540
+ // TODO: Use spaceTrim in multiline strings
9347
9541
  $pipelineJson.tasks.push({
9348
9542
  taskType: 'PROMPT_TASK',
9349
9543
  name: 'create-an-answer',
@@ -9351,8 +9545,11 @@ var QuickChatbotHla = {
9351
9545
  content: 'Write a response to the user message:\n\n**Question from user**\n\n> {userMessage}\n\n**Previous conversation**\n\n> {previousConversationSummary}',
9352
9546
  resultingParameterName: 'chatbotResponse',
9353
9547
  personaName: personaName,
9354
- dependentParameterNames: ['userMessage', 'previousConversationSummary' /* !!!!!!, 'knowledge'*/],
9355
- // !!!!!! preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
9548
+ dependentParameterNames: [
9549
+ 'userMessage',
9550
+ 'previousConversationSummary' /* TODO: [🧠][📛], 'knowledge'*/,
9551
+ ],
9552
+ // TODO: [🧠][📛] preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
9356
9553
  }, {
9357
9554
  taskType: 'PROMPT_TASK',
9358
9555
  name: 'summarize-the-conversation',
@@ -9366,24 +9563,27 @@ var QuickChatbotHla = {
9366
9563
  max: 10,
9367
9564
  },
9368
9565
  },
9369
- dependentParameterNames: ['userMessage', 'chatbotResponse' /* !!!!!!, 'knowledge'*/],
9370
- // !!!!!! preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
9566
+ dependentParameterNames: ['userMessage', 'chatbotResponse' /* TODO: [🧠][📛], 'knowledge'*/],
9567
+ // TODO: [🧠][📛] preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
9371
9568
  }, {
9372
9569
  taskType: 'SIMPLE_TASK',
9373
9570
  name: 'title',
9374
9571
  title: 'Title',
9375
9572
  content: '{conversationSummary}',
9376
9573
  resultingParameterName: 'title',
9377
- dependentParameterNames: ['conversationSummary' /* !!!!!!, 'knowledge'*/],
9378
- // !!!!!! preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
9574
+ dependentParameterNames: ['conversationSummary' /* TODO: [🧠][📛], 'knowledge'*/],
9575
+ // TODO: [🧠][📛] preparedContent: '{content}\n\n## Knowledge\n\n{knowledge}',
9379
9576
  });
9380
9577
  },
9381
9578
  };
9579
+ /**
9580
+ * TODO: [🧠][📛] Should this be here?
9581
+ */
9382
9582
 
9383
9583
  /**
9384
9584
  * All high-level abstractions
9385
9585
  *
9386
- * @private internal index of `precompilePipeline` (= used for sync) and `preparePipeline` (= used for async)
9586
+ * @private internal index of `parsePipeline` (= used for sync) and `preparePipeline` (= used for async)
9387
9587
  */
9388
9588
  var HIGH_LEVEL_ABSTRACTIONS = [
9389
9589
  ImplicitFormfactorHla,
@@ -9517,7 +9717,7 @@ function splitMarkdownIntoSections(markdown) {
9517
9717
  return;
9518
9718
  }
9519
9719
  if (!section.startsWith('#')) {
9520
- section = "# ".concat(DEFAULT_TITLE, "\n\n").concat(section);
9720
+ section = "# ".concat(DEFAULT_BOOK_TITLE, "\n\n").concat(section);
9521
9721
  }
9522
9722
  sections.push(section);
9523
9723
  buffer = [];
@@ -9572,7 +9772,7 @@ function splitMarkdownIntoSections(markdown) {
9572
9772
  /**
9573
9773
  * Normalizes the markdown by flattening the structure
9574
9774
  *
9575
- * - It always have h1 - if there is no h1 in the markdown, it will be added "# Untitled"
9775
+ * - It always have h1 - if there is no h1 in the markdown, it will be added `DEFAULT_BOOK_TITLE`
9576
9776
  * - All other headings are normalized to h2
9577
9777
  *
9578
9778
  * @public exported from `@promptbook/markdown-utils`
@@ -9581,7 +9781,7 @@ function flattenMarkdown(markdown) {
9581
9781
  var e_1, _a;
9582
9782
  var sections = splitMarkdownIntoSections(markdown);
9583
9783
  if (sections.length === 0) {
9584
- return "# ".concat(DEFAULT_TITLE);
9784
+ return "# ".concat(DEFAULT_BOOK_TITLE);
9585
9785
  }
9586
9786
  var flattenedMarkdown = '';
9587
9787
  var parsedSections = sections.map(parseMarkdownSection);
@@ -9592,7 +9792,7 @@ function flattenMarkdown(markdown) {
9592
9792
  }
9593
9793
  else {
9594
9794
  parsedSections.unshift(firstSection);
9595
- flattenedMarkdown += "# ".concat(DEFAULT_TITLE) + "\n\n"; // <- [🧠] Maybe 3 new lines?
9795
+ flattenedMarkdown += "# ".concat(DEFAULT_BOOK_TITLE) + "\n\n"; // <- [🧠] Maybe 3 new lines?
9596
9796
  }
9597
9797
  try {
9598
9798
  for (var parsedSections_1 = __values(parsedSections), parsedSections_1_1 = parsedSections_1.next(); !parsedSections_1_1.done; parsedSections_1_1 = parsedSections_1.next()) {
@@ -9619,13 +9819,13 @@ function flattenMarkdown(markdown) {
9619
9819
  */
9620
9820
 
9621
9821
  /**
9622
- * Removes HTML or Markdown comments from a string.
9822
+ * Removes Markdown (or HTML) comments
9623
9823
  *
9624
9824
  * @param {string} content - The string to remove comments from.
9625
9825
  * @returns {string} The input string with all comments removed.
9626
9826
  * @public exported from `@promptbook/markdown-utils`
9627
9827
  */
9628
- function removeContentComments(content) {
9828
+ function removeMarkdownComments(content) {
9629
9829
  return spaceTrim$1(content.replace(/<!--(.*?)-->/gs, ''));
9630
9830
  }
9631
9831
 
@@ -9634,7 +9834,7 @@ function removeContentComments(content) {
9634
9834
  *
9635
9835
  * Note: There are 3 similar functions:
9636
9836
  * - `compilePipeline` **(preferred)** - which propperly compiles the promptbook and use embedding for external knowledge
9637
- * - `precompilePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
9837
+ * - `parsePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
9638
9838
  * - `preparePipeline` - just one step in the compilation process
9639
9839
  *
9640
9840
  * Note: This function does not validate logic of the pipeline only the parsing
@@ -9645,10 +9845,10 @@ function removeContentComments(content) {
9645
9845
  * @throws {ParseError} if the promptbook string is not valid
9646
9846
  * @public exported from `@promptbook/core`
9647
9847
  */
9648
- function precompilePipeline(pipelineString) {
9848
+ function parsePipeline(pipelineString) {
9649
9849
  var e_1, _a, e_2, _b, e_3, _c, e_4, _d, e_5, _e, e_6, _f;
9650
9850
  var $pipelineJson = {
9651
- title: DEFAULT_TITLE,
9851
+ title: DEFAULT_BOOK_TITLE,
9652
9852
  parameters: [],
9653
9853
  tasks: [],
9654
9854
  knowledgeSources: [],
@@ -9659,7 +9859,7 @@ function precompilePipeline(pipelineString) {
9659
9859
  {
9660
9860
  type: 'BOOK',
9661
9861
  path: null,
9662
- // <- TODO: !!!!!! Pass here path of the file
9862
+ // <- TODO: !!6 Pass here path of the file
9663
9863
  content: pipelineString,
9664
9864
  },
9665
9865
  ],
@@ -9677,18 +9877,44 @@ function precompilePipeline(pipelineString) {
9677
9877
  }
9678
9878
  // =============================================================
9679
9879
  // Note: 1️⃣ Parsing of the markdown into object
9880
+ // ==============
9881
+ // Note: 1️⃣◽1️⃣ Remove #!shebang and comments
9680
9882
  if (pipelineString.startsWith('#!')) {
9681
9883
  var _g = __read(pipelineString.split('\n')), shebangLine_1 = _g[0], restLines = _g.slice(1);
9682
9884
  if (!(shebangLine_1 || '').includes('ptbk')) {
9683
9885
  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 "); }));
9684
9886
  }
9685
- pipelineString = restLines.join('\n');
9686
- }
9687
- pipelineString = removeContentComments(pipelineString);
9887
+ pipelineString = validatePipelineString(restLines.join('\n'));
9888
+ }
9889
+ pipelineString = removeMarkdownComments(pipelineString);
9890
+ pipelineString = spaceTrim$1(pipelineString);
9891
+ // <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
9892
+ // ==============
9893
+ // Note: 1️⃣◽2️⃣ Process flat pipeline
9894
+ var isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
9895
+ var isLastLineReturnStatement = pipelineString.split('\n').pop().split('`').join('').startsWith('->');
9896
+ // TODO: Also (double)check
9897
+ // > const usedCommands
9898
+ // > const isBlocksUsed
9899
+ // > const returnStatementCount
9900
+ var isFlatPipeline = !isMarkdownBeginningWithHeadline && isLastLineReturnStatement;
9901
+ // console.log({ isMarkdownBeginningWithHeadline, isLastLineReturnStatement, isFlatPipeline });
9902
+ if (isFlatPipeline) {
9903
+ var pipelineStringLines = pipelineString.split('\n');
9904
+ var returnStatement_1 = pipelineStringLines.pop();
9905
+ var prompt_1 = spaceTrim$1(pipelineStringLines.join('\n'));
9906
+ 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 "); }));
9907
+ // <- TODO: Maybe use book` notation
9908
+ // console.log(pipelineString);
9909
+ }
9910
+ // ==============
9911
+ // Note: 1️⃣◽3️⃣ Parse the markdown
9688
9912
  pipelineString = flattenMarkdown(pipelineString) /* <- Note: [🥞] */;
9689
9913
  pipelineString = pipelineString.replaceAll(/`\{(?<parameterName>[a-z0-9_]+)\}`/gi, '{$<parameterName>}');
9690
9914
  pipelineString = pipelineString.replaceAll(/`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi, '-> {$<parameterName>}');
9691
9915
  var _h = __read(splitMarkdownIntoSections(pipelineString).map(parseMarkdownSection)), pipelineHead = _h[0], pipelineSections = _h.slice(1); /* <- Note: [🥞] */
9916
+ // ==============
9917
+ // Note: 1️⃣◽4️⃣ Check markdown structure
9692
9918
  if (pipelineHead === undefined) {
9693
9919
  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 "); }));
9694
9920
  }
@@ -10072,14 +10298,14 @@ function precompilePipeline(pipelineString) {
10072
10298
  // =============================================================
10073
10299
  return exportJson({
10074
10300
  name: 'pipelineJson',
10075
- message: "Result of `precompilePipeline`",
10301
+ message: "Result of `parsePipeline`",
10076
10302
  order: ORDER_OF_PIPELINE_JSON,
10077
10303
  value: __assign({ formfactorName: 'GENERIC' }, $pipelineJson),
10078
10304
  });
10079
10305
  }
10080
10306
  /**
10081
10307
  * TODO: [🧠] Maybe more things here can be refactored as high-level abstractions
10082
- * TODO: [main] !!!! Warn if used only sync version
10308
+ * TODO: [main] !!4 Warn if used only sync version
10083
10309
  * TODO: [🚞] Report here line/column of error
10084
10310
  * TODO: Use spaceTrim more effectively
10085
10311
  * TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
@@ -10092,10 +10318,7 @@ function precompilePipeline(pipelineString) {
10092
10318
  /**
10093
10319
  * Compile pipeline from string (markdown) format to JSON format
10094
10320
  *
10095
- * Note: There are 3 similar functions:
10096
- * - `compilePipeline` **(preferred)** - which propperly compiles the promptbook and use embedding for external knowledge
10097
- * - `precompilePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
10098
- * - `preparePipeline` - just one step in the compilation process
10321
+ * @see https://github.com/webgptorg/promptbook/discussions/196
10099
10322
  *
10100
10323
  * Note: This function does not validate logic of the pipeline only the parsing
10101
10324
  * Note: This function acts as compilation process
@@ -10113,7 +10336,7 @@ function compilePipeline(pipelineString, tools, options) {
10113
10336
  return __generator(this, function (_a) {
10114
10337
  switch (_a.label) {
10115
10338
  case 0:
10116
- pipelineJson = precompilePipeline(pipelineString);
10339
+ pipelineJson = parsePipeline(pipelineString);
10117
10340
  if (!(tools !== undefined && tools.llm !== undefined)) return [3 /*break*/, 2];
10118
10341
  return [4 /*yield*/, preparePipeline(pipelineJson, tools, options || {
10119
10342
  rootDirname: null,
@@ -10122,7 +10345,7 @@ function compilePipeline(pipelineString, tools, options) {
10122
10345
  pipelineJson = _a.sent();
10123
10346
  _a.label = 2;
10124
10347
  case 2:
10125
- // Note: No need to use `$exportJson` because `precompilePipeline` and `preparePipeline` already do that
10348
+ // Note: No need to use `$exportJson` because `parsePipeline` and `preparePipeline` already do that
10126
10349
  return [2 /*return*/, pipelineJson];
10127
10350
  }
10128
10351
  });
@@ -10486,23 +10709,95 @@ function $provideScrapersForNode(tools, options) {
10486
10709
  */
10487
10710
 
10488
10711
  /**
10489
- * Extracts code block from markdown.
10490
- *
10491
- * - When there are multiple or no code blocks the function throws a `ParseError`
10712
+ * Creates a Mermaid graph based on the promptbook
10492
10713
  *
10493
- * Note: There are multiple simmilar function:
10494
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
10495
- * - `extractJsonBlock` extracts exactly one valid JSON code block
10496
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
10497
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
10714
+ * Note: The result is not wrapped in a Markdown code block
10498
10715
  *
10499
- * @public exported from `@promptbook/markdown-utils`
10500
- * @throws {ParseError} if there is not exactly one code block in the markdown
10716
+ * @public exported from `@promptbook/utils`
10501
10717
  */
10502
- function extractBlock(markdown) {
10503
- var content = extractOneBlockFromMarkdown(markdown).content;
10504
- return content;
10718
+ function renderPromptbookMermaid(pipelineJson, options) {
10719
+ var _a = (options || {}).linkTask, linkTask = _a === void 0 ? function () { return null; } : _a;
10720
+ var parameterNameToTaskName = function (parameterName) {
10721
+ var parameter = pipelineJson.parameters.find(function (parameter) { return parameter.name === parameterName; });
10722
+ if (!parameter) {
10723
+ throw new UnexpectedError("Could not find {".concat(parameterName, "}"));
10724
+ // <- TODO: !!6 This causes problems when {knowledge} and other reserved parameters are used
10725
+ }
10726
+ if (parameter.isInput) {
10727
+ return 'input';
10728
+ }
10729
+ var task = pipelineJson.tasks.find(function (task) { return task.resultingParameterName === parameterName; });
10730
+ if (!task) {
10731
+ throw new Error("Could not find task for {".concat(parameterName, "}"));
10732
+ }
10733
+ return task.name || normalizeTo_camelCase('task-' + titleToName(task.title));
10734
+ };
10735
+ var promptbookMermaid = spaceTrim$1(function (block) { return "\n\n %% \uD83D\uDD2E Tip: Open this on GitHub or in the VSCode website to see the Mermaid graph visually\n\n flowchart LR\n subgraph \"".concat(pipelineJson.title, "\"\n\n direction TB\n\n input((Input)):::input\n ").concat(block(pipelineJson.tasks
10736
+ .flatMap(function (_a) {
10737
+ var title = _a.title, dependentParameterNames = _a.dependentParameterNames, resultingParameterName = _a.resultingParameterName;
10738
+ return __spreadArray([
10739
+ "".concat(parameterNameToTaskName(resultingParameterName), "(\"").concat(title, "\")")
10740
+ ], __read(dependentParameterNames.map(function (dependentParameterName) {
10741
+ return "".concat(parameterNameToTaskName(dependentParameterName), "--\"{").concat(dependentParameterName, "}\"-->").concat(parameterNameToTaskName(resultingParameterName));
10742
+ })), false);
10743
+ })
10744
+ .join('\n')), "\n\n ").concat(block(pipelineJson.parameters
10745
+ .filter(function (_a) {
10746
+ var isOutput = _a.isOutput;
10747
+ return isOutput;
10748
+ })
10749
+ .map(function (_a) {
10750
+ var name = _a.name;
10751
+ return "".concat(parameterNameToTaskName(name), "--\"{").concat(name, "}\"-->output");
10752
+ })
10753
+ .join('\n')), "\n output((Output)):::output\n\n ").concat(block(pipelineJson.tasks
10754
+ .map(function (task) {
10755
+ var link = linkTask(task);
10756
+ if (link === null) {
10757
+ return '';
10758
+ }
10759
+ var href = link.href, title = link.title;
10760
+ var taskName = parameterNameToTaskName(task.resultingParameterName);
10761
+ return "click ".concat(taskName, " href \"").concat(href, "\" \"").concat(title, "\";");
10762
+ })
10763
+ .filter(function (line) { return line !== ''; })
10764
+ .join('\n')), "\n\n classDef input color: grey;\n classDef output color: grey;\n\n end;\n\n "); });
10765
+ return promptbookMermaid;
10505
10766
  }
10767
+ /**
10768
+ * TODO: [🧠] FOREACH in mermaid graph
10769
+ * TODO: [🧠] Knowledge in mermaid graph
10770
+ * TODO: [🧠] Personas in mermaid graph
10771
+ * TODO: Maybe use some Mermaid package instead of string templating
10772
+ * TODO: [🕌] When more than 2 functionalities, split into separate functions
10773
+ */
10774
+
10775
+ /**
10776
+ * Detects if the code is running in a browser environment in main thread (Not in a web worker)
10777
+ *
10778
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10779
+ *
10780
+ * @public exported from `@promptbook/utils`
10781
+ */
10782
+ var $isRunningInBrowser = new Function("\n try {\n return this === window;\n } catch (e) {\n return false;\n }\n");
10783
+
10784
+ /**
10785
+ * Detects if the code is running in jest environment
10786
+ *
10787
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10788
+ *
10789
+ * @public exported from `@promptbook/utils`
10790
+ */
10791
+ var $isRunningInJest = new Function("\n try {\n return process.env.JEST_WORKER_ID !== undefined;\n } catch (e) {\n return false;\n }\n");
10792
+
10793
+ /**
10794
+ * Detects if the code is running in a web worker
10795
+ *
10796
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10797
+ *
10798
+ * @public exported from `@promptbook/utils`
10799
+ */
10800
+ var $isRunningInWebWorker = new Function("\n try {\n if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {\n return true;\n } else {\n return false;\n }\n } catch (e) {\n return false;\n }\n");
10506
10801
 
10507
10802
  /**
10508
10803
  * Makes first letter of a string uppercase
@@ -10513,6 +10808,21 @@ function decapitalize(word) {
10513
10808
  return word.substring(0, 1).toLowerCase() + word.substring(1);
10514
10809
  }
10515
10810
 
10811
+ /**
10812
+ * Parses keywords from a string
10813
+ *
10814
+ * @param {string} input
10815
+ * @returns {Set} of keywords without diacritics in lowercase
10816
+ * @public exported from `@promptbook/utils`
10817
+ */
10818
+ function parseKeywordsFromString(input) {
10819
+ var keywords = normalizeTo_SCREAMING_CASE(removeDiacritics(input))
10820
+ .toLowerCase()
10821
+ .split(/[^a-z0-9]+/gs)
10822
+ .filter(function (value) { return value; });
10823
+ return new Set(keywords);
10824
+ }
10825
+
10516
10826
  /**
10517
10827
  * @@@
10518
10828
  *
@@ -10566,21 +10876,6 @@ function normalizeWhitespaces(sentence) {
10566
10876
  return sentence.replace(/\s+/gs, ' ').trim();
10567
10877
  }
10568
10878
 
10569
- /**
10570
- * Parses keywords from a string
10571
- *
10572
- * @param {string} input
10573
- * @returns {Set} of keywords without diacritics in lowercase
10574
- * @public exported from `@promptbook/utils`
10575
- */
10576
- function parseKeywordsFromString(input) {
10577
- var keywords = normalizeTo_SCREAMING_CASE(removeDiacritics(input))
10578
- .toLowerCase()
10579
- .split(/[^a-z0-9]+/gs)
10580
- .filter(function (value) { return value; });
10581
- return new Set(keywords);
10582
- }
10583
-
10584
10879
  /**
10585
10880
  * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
10586
10881
  *
@@ -10687,6 +10982,25 @@ function unwrapResult(text, options) {
10687
10982
  * TODO: [🧠] Should this also unwrap the (parenthesis)
10688
10983
  */
10689
10984
 
10985
+ /**
10986
+ * Extracts code block from markdown.
10987
+ *
10988
+ * - When there are multiple or no code blocks the function throws a `ParseError`
10989
+ *
10990
+ * Note: There are multiple simmilar function:
10991
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
10992
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
10993
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
10994
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
10995
+ *
10996
+ * @public exported from `@promptbook/markdown-utils`
10997
+ * @throws {ParseError} if there is not exactly one code block in the markdown
10998
+ */
10999
+ function extractBlock(markdown) {
11000
+ var content = extractOneBlockFromMarkdown(markdown).content;
11001
+ return content;
11002
+ }
11003
+
10690
11004
  /**
10691
11005
  * Does nothing, but preserves the function in the bundle
10692
11006
  * Compiler is tricked into thinking the function is used
@@ -10721,37 +11035,10 @@ function preserve(func) {
10721
11035
  }); })();
10722
11036
  }
10723
11037
  /**
10724
- * TODO: !! [1] This maybe does memory leak
11038
+ * TODO: Probbably remove in favour of `keepImported`
11039
+ * TODO: [1] This maybe does memory leak
10725
11040
  */
10726
11041
 
10727
- /**
10728
- * Converts anything to string that can be used for debugging and logging
10729
- *
10730
- * @param value String value for logging
10731
- * @private internal util
10732
- */
10733
- function unknownToString(value) {
10734
- if (value === undefined) {
10735
- return 'undefined';
10736
- }
10737
- else if (value === null) {
10738
- return 'null';
10739
- }
10740
- else if (['number', 'string', 'boolean'].includes(typeof value)) {
10741
- return typeof value + ' ' + value.toString();
10742
- }
10743
- else if (typeof value === 'object' && Array.isArray(value)) {
10744
- return 'array containing [' + value.map(function (item) { return unknownToString(item); }).join(', ') + ']';
10745
- }
10746
- else if (typeof value === 'object') {
10747
- // TODO: Maybe serialize the object
10748
- return 'object';
10749
- }
10750
- else {
10751
- return 'unknown (Search in promptbook code for [🔹])';
10752
- }
10753
- }
10754
-
10755
11042
  /**
10756
11043
  * ScriptExecutionTools for JavaScript implemented via eval
10757
11044
  *
@@ -10881,7 +11168,7 @@ var JavascriptEvalExecutionTools = /** @class */ (function () {
10881
11168
  case 2:
10882
11169
  result = _a.sent();
10883
11170
  if (typeof result !== 'string') {
10884
- throw new PipelineExecutionError("Script must return a string, but returned ".concat(unknownToString(result)));
11171
+ throw new PipelineExecutionError("Script must return a string, but returned ".concat(valueToString(result)));
10885
11172
  }
10886
11173
  return [3 /*break*/, 4];
10887
11174
  case 3:
@@ -10908,7 +11195,7 @@ var JavascriptEvalExecutionTools = /** @class */ (function () {
10908
11195
  throw error_1;
10909
11196
  case 4:
10910
11197
  if (typeof result !== 'string') {
10911
- throw new PipelineExecutionError("Script must return a string, but ".concat(unknownToString(result)));
11198
+ throw new PipelineExecutionError("Script must return a string, but ".concat(valueToString(result)));
10912
11199
  }
10913
11200
  return [2 /*return*/, result];
10914
11201
  }
@@ -10948,9 +11235,11 @@ function $provideExecutionToolsForNode(options) {
10948
11235
  throw new EnvironmentMismatchError('Function `$getExecutionToolsForNode` works only in Node.js environment');
10949
11236
  }
10950
11237
  fs = $provideFilesystemForNode();
10951
- llm = $provideLlmToolsFromEnv(options);
10952
- return [4 /*yield*/, $provideExecutablesForNode(options)];
11238
+ return [4 /*yield*/, $provideLlmToolsFromEnv(options)];
10953
11239
  case 1:
11240
+ llm = _b.sent();
11241
+ return [4 /*yield*/, $provideExecutablesForNode(options)];
11242
+ case 2:
10954
11243
  executables = _b.sent();
10955
11244
  _a = {
10956
11245
  llm: llm,
@@ -10958,7 +11247,7 @@ function $provideExecutionToolsForNode(options) {
10958
11247
  executables: executables
10959
11248
  };
10960
11249
  return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, options)];
10961
- case 2:
11250
+ case 3:
10962
11251
  tools = (_a.scrapers = _b.sent(),
10963
11252
  _a.script = [new JavascriptExecutionTools(options)],
10964
11253
  _a);
@@ -11181,7 +11470,7 @@ function createCollectionFromPromise(promptbookSourcesPromiseOrFactory) {
11181
11470
  */
11182
11471
  function createCollectionFromDirectory(path, tools, options) {
11183
11472
  return __awaiter(this, void 0, void 0, function () {
11184
- var makedLibraryFilePath, _a, _b, isRecursive, _c, isVerbose, _d, isLazyLoaded, _e, isCrashedOnError, collection;
11473
+ var madeLibraryFilePath, _a, _b, isRecursive, _c, isVerbose, _d, isLazyLoaded, _e, isCrashedOnError, rootUrl, collection;
11185
11474
  var _this = this;
11186
11475
  return __generator(this, function (_f) {
11187
11476
  switch (_f.label) {
@@ -11196,18 +11485,18 @@ function createCollectionFromDirectory(path, tools, options) {
11196
11485
  throw new EnvironmentMismatchError('Can not create collection without filesystem tools');
11197
11486
  // <- TODO: [🧠] What is the best error type here`
11198
11487
  }
11199
- makedLibraryFilePath = join(path, "".concat(DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME
11488
+ madeLibraryFilePath = join(path, "".concat(DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME
11200
11489
  // <- TODO: [🦒] Allow to override (pass different value into the function)
11201
11490
  , ".json"));
11202
- return [4 /*yield*/, isFileExisting(makedLibraryFilePath, tools.fs)];
11491
+ return [4 /*yield*/, isFileExisting(madeLibraryFilePath, tools.fs)];
11203
11492
  case 3:
11204
11493
  if (!(_f.sent())) ;
11205
11494
  else {
11206
- colors.green("(In future, not implemented yet) Using your compiled pipeline collection ".concat(makedLibraryFilePath));
11207
- // TODO: !! Implement;
11495
+ colors.green("(In future, not implemented yet) Using your compiled pipeline collection ".concat(madeLibraryFilePath));
11496
+ // TODO: Implement;
11208
11497
  // TODO: [🌗]
11209
11498
  }
11210
- _a = options || {}, _b = _a.isRecursive, isRecursive = _b === void 0 ? true : _b, _c = _a.isVerbose, isVerbose = _c === void 0 ? DEFAULT_IS_VERBOSE : _c, _d = _a.isLazyLoaded, isLazyLoaded = _d === void 0 ? false : _d, _e = _a.isCrashedOnError, isCrashedOnError = _e === void 0 ? true : _e;
11499
+ _a = options || {}, _b = _a.isRecursive, isRecursive = _b === void 0 ? true : _b, _c = _a.isVerbose, isVerbose = _c === void 0 ? DEFAULT_IS_VERBOSE : _c, _d = _a.isLazyLoaded, isLazyLoaded = _d === void 0 ? false : _d, _e = _a.isCrashedOnError, isCrashedOnError = _e === void 0 ? true : _e, rootUrl = _a.rootUrl;
11211
11500
  collection = createCollectionFromPromise(function () { return __awaiter(_this, void 0, void 0, function () {
11212
11501
  var fileNames, collection, _loop_1, fileNames_1, fileNames_1_1, fileName, e_1_1;
11213
11502
  var e_1, _a;
@@ -11233,34 +11522,35 @@ function createCollectionFromDirectory(path, tools, options) {
11233
11522
  });
11234
11523
  collection = new Map();
11235
11524
  _loop_1 = function (fileName) {
11236
- var sourceFile, rootDirname, pipeline, pipelineString, _c, _d, existing, error_1, wrappedErrorMessage;
11237
- return __generator(this, function (_e) {
11238
- switch (_e.label) {
11525
+ var sourceFile, rootDirname, pipeline, pipelineString, _c, _d, _e, pipelineUrl, existing, error_1, wrappedErrorMessage;
11526
+ return __generator(this, function (_f) {
11527
+ switch (_f.label) {
11239
11528
  case 0:
11240
11529
  sourceFile = './' + fileName.split('\\').join('/');
11241
11530
  rootDirname = dirname(sourceFile).split('\\').join('/');
11242
- _e.label = 1;
11531
+ _f.label = 1;
11243
11532
  case 1:
11244
- _e.trys.push([1, 8, , 9]);
11533
+ _f.trys.push([1, 8, , 9]);
11245
11534
  pipeline = null;
11246
11535
  if (!fileName.endsWith('.book.md')) return [3 /*break*/, 4];
11536
+ _c = validatePipelineString;
11247
11537
  return [4 /*yield*/, readFile(fileName, 'utf-8')];
11248
11538
  case 2:
11249
- pipelineString = (_e.sent());
11539
+ pipelineString = _c.apply(void 0, [_f.sent()]);
11250
11540
  return [4 /*yield*/, compilePipeline(pipelineString, tools, {
11251
11541
  rootDirname: rootDirname,
11252
11542
  })];
11253
11543
  case 3:
11254
- pipeline = _e.sent();
11544
+ pipeline = _f.sent();
11255
11545
  pipeline = __assign(__assign({}, pipeline), { sourceFile: sourceFile });
11256
11546
  return [3 /*break*/, 7];
11257
11547
  case 4:
11258
11548
  if (!fileName.endsWith('.book.json')) return [3 /*break*/, 6];
11259
- _d = (_c = JSON).parse;
11549
+ _e = (_d = JSON).parse;
11260
11550
  return [4 /*yield*/, readFile(fileName, 'utf-8')];
11261
11551
  case 5:
11262
11552
  // TODO: Handle non-valid JSON files
11263
- pipeline = _d.apply(_c, [_e.sent()]);
11553
+ pipeline = _e.apply(_d, [_f.sent()]);
11264
11554
  // TODO: [🌗]
11265
11555
  pipeline = __assign(__assign({}, pipeline), { sourceFile: sourceFile });
11266
11556
  return [3 /*break*/, 7];
@@ -11268,10 +11558,24 @@ function createCollectionFromDirectory(path, tools, options) {
11268
11558
  if (isVerbose) {
11269
11559
  console.info(colors.gray("Skipped file ".concat(fileName.split('\\').join('/'), " \u2013\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060\u2060 Not a book")));
11270
11560
  }
11271
- _e.label = 7;
11561
+ _f.label = 7;
11272
11562
  case 7:
11273
11563
  // ---
11274
11564
  if (pipeline !== null) {
11565
+ if (rootUrl !== undefined) {
11566
+ if (pipeline.pipelineUrl === undefined) {
11567
+ pipelineUrl = rootUrl + '/' + fileName.split('\\').join('/');
11568
+ if (isVerbose) {
11569
+ console.info(colors.yellow("Implicitly set pipeline URL to ".concat(pipelineUrl, " from ").concat(fileName
11570
+ .split('\\')
11571
+ .join('/'))));
11572
+ }
11573
+ pipeline = __assign(__assign({}, pipeline), { pipelineUrl: pipelineUrl });
11574
+ }
11575
+ else if (!pipeline.pipelineUrl.startsWith(rootUrl)) {
11576
+ throw new PipelineUrlError(spaceTrim("\n Pipeline with URL ".concat(pipeline.pipelineUrl, " is not a child of the root URL ").concat(rootUrl, " \uD83C\uDF4F\n\n File:\n ").concat(sourceFile || 'Unknown', "\n\n ")));
11577
+ }
11578
+ }
11275
11579
  // TODO: [👠] DRY
11276
11580
  if (pipeline.pipelineUrl === undefined) {
11277
11581
  if (isVerbose) {
@@ -11303,17 +11607,17 @@ function createCollectionFromDirectory(path, tools, options) {
11303
11607
  }
11304
11608
  else {
11305
11609
  existing = collection.get(pipeline.pipelineUrl);
11306
- throw new PipelineUrlError(spaceTrim("\n Pipeline with URL \"".concat(pipeline.pipelineUrl, "\" is already in the collection \uD83C\uDF4F\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 ")));
11610
+ throw new PipelineUrlError(spaceTrim("\n Pipeline with URL ".concat(pipeline.pipelineUrl, " is already in the collection \uD83C\uDF4F\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 ")));
11307
11611
  }
11308
11612
  }
11309
11613
  }
11310
11614
  return [3 /*break*/, 9];
11311
11615
  case 8:
11312
- error_1 = _e.sent();
11616
+ error_1 = _f.sent();
11313
11617
  if (!(error_1 instanceof Error)) {
11314
11618
  throw error_1;
11315
11619
  }
11316
- wrappedErrorMessage = spaceTrim(function (block) { return "\n ".concat(error_1.name, " in pipeline ").concat(fileName.split('\\').join('/'), "\u2060:\n\n Original error message:\n ").concat(block(error_1.message), "\n\n Original stack trace:\n ").concat(block(error_1.stack || ''), "\n\n ---\n\n "); }) + '\n';
11620
+ wrappedErrorMessage = spaceTrim(function (block) { return "\n ".concat(error_1.name, " in pipeline ").concat(fileName.split('\\').join('/'), "\u2060:\n\n Original error message:\n ").concat(block(error_1.message), "\n\n Original stack trace:\n ").concat(block(error_1.stack || ''), "\n\n ---\n\n "); }) + '\n';
11317
11621
  if (isCrashedOnError) {
11318
11622
  throw new CollectionError(wrappedErrorMessage);
11319
11623
  }
@@ -11448,6 +11752,7 @@ function initializeMakeCommand(program) {
11448
11752
  // <- TODO: [🧟‍♂️] Unite path to promptbook collection argument
11449
11753
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
11450
11754
  makeCommand.option('--project-name', "Name of the project for whom collection is", 'Untitled Promptbook project');
11755
+ makeCommand.option('--root-url <url>', "Root URL of all pipelines to make", undefined);
11451
11756
  makeCommand.option('-f, --format <format>', spaceTrim("\n Output format of builded collection \"javascript\", \"typescript\" or \"json\"\n\n Note: You can use multiple formats separated by comma\n "), 'javascript' /* <- Note: [🏳‍🌈] */);
11452
11757
  makeCommand.option('--no-validation', "Do not validate logic of pipelines in collection", true);
11453
11758
  makeCommand.option('--validation', "Types of validations separated by comma (options \"logic\",\"imports\")", 'logic,imports');
@@ -11456,7 +11761,7 @@ function initializeMakeCommand(program) {
11456
11761
  makeCommand.option('-o, --output <path>', spaceTrim("\n Where to save the builded collection\n\n Note: If you keep it \"".concat(DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, "\" it will be saved in the root of the promptbook directory\n If you set it to a path, it will be saved in that path\n BUT you can use only one format and set correct extension\n ")), DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME);
11457
11762
  makeCommand.option('-fn, --function-name <functionName>', spaceTrim("\n Name of the function to get pipeline collection\n\n Note: This can be used only with \"javascript\" or \"typescript\" format\n\n "), DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME);
11458
11763
  makeCommand.action(function (path, _a) {
11459
- var projectName = _a.projectName, format = _a.format, functionName = _a.functionName, validation = _a.validation, isCacheReloaded = _a.reload, isVerbose = _a.verbose, output = _a.output;
11764
+ var projectName = _a.projectName, rootUrl = _a.rootUrl, format = _a.format, functionName = _a.functionName, validation = _a.validation, isCacheReloaded = _a.reload, isVerbose = _a.verbose, output = _a.output;
11460
11765
  return __awaiter(_this, void 0, void 0, function () {
11461
11766
  var formats, validations, prepareAndScrapeOptions, fs, llm, executables, tools, collection, pipelinesUrls, validations_1, validations_1_1, validation_1, pipelinesUrls_1, pipelinesUrls_1_1, pipelineUrl, pipeline, e_1_1, e_2_1, collectionJson, collectionJsonString, collectionJsonItems, saveFile;
11462
11767
  var _b, e_2, _c, e_1, _d;
@@ -11468,6 +11773,11 @@ function initializeMakeCommand(program) {
11468
11773
  console.error(colors.red("Function name \"".concat(functionName, "\" is not valid javascript name")));
11469
11774
  return [2 /*return*/, process.exit(1)];
11470
11775
  }
11776
+ if (rootUrl !== undefined &&
11777
+ !isValidUrl(rootUrl) /* <- Note: Not using `isValidPipelineUrl` because this is root url not book url */) {
11778
+ console.error(colors.red("Root URL ".concat(rootUrl, " is not valid URL")));
11779
+ return [2 /*return*/, process.exit(1)];
11780
+ }
11471
11781
  formats = (format || '')
11472
11782
  .split(',')
11473
11783
  .map(function (_) { return _.trim(); })
@@ -11485,16 +11795,18 @@ function initializeMakeCommand(program) {
11485
11795
  isCacheReloaded: isCacheReloaded,
11486
11796
  };
11487
11797
  fs = $provideFilesystemForNode(prepareAndScrapeOptions);
11488
- llm = $provideLlmToolsForCli(prepareAndScrapeOptions);
11489
- return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
11798
+ return [4 /*yield*/, $provideLlmToolsForWizzardOrCli(prepareAndScrapeOptions)];
11490
11799
  case 1:
11800
+ llm = _e.sent();
11801
+ return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
11802
+ case 2:
11491
11803
  executables = _e.sent();
11492
11804
  _b = {
11493
11805
  llm: llm,
11494
11806
  fs: fs
11495
11807
  };
11496
11808
  return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, prepareAndScrapeOptions)];
11497
- case 2:
11809
+ case 3:
11498
11810
  tools = (_b.scrapers = _e.sent(),
11499
11811
  _b.script = [
11500
11812
  /*new JavascriptExecutionTools(options)*/
@@ -11502,36 +11814,39 @@ function initializeMakeCommand(program) {
11502
11814
  _b);
11503
11815
  return [4 /*yield*/, createCollectionFromDirectory(path, tools, {
11504
11816
  isVerbose: isVerbose,
11817
+ rootUrl: rootUrl,
11505
11818
  isRecursive: true,
11819
+ isLazyLoaded: false,
11820
+ isCrashedOnError: true,
11506
11821
  // <- TODO: [🍖] Add `intermediateFilesStrategy`
11507
11822
  })];
11508
- case 3:
11823
+ case 4:
11509
11824
  collection = _e.sent();
11510
11825
  return [4 /*yield*/, collection.listPipelines()];
11511
- case 4:
11826
+ case 5:
11512
11827
  pipelinesUrls = _e.sent();
11513
11828
  if (pipelinesUrls.length === 0) {
11514
11829
  console.error(colors.red("No books found in \"".concat(path, "\"")));
11515
11830
  return [2 /*return*/, process.exit(1)];
11516
11831
  }
11517
- _e.label = 5;
11518
- case 5:
11519
- _e.trys.push([5, 16, 17, 18]);
11520
- validations_1 = __values(validations), validations_1_1 = validations_1.next();
11521
11832
  _e.label = 6;
11522
11833
  case 6:
11523
- if (!!validations_1_1.done) return [3 /*break*/, 15];
11524
- validation_1 = validations_1_1.value;
11834
+ _e.trys.push([6, 17, 18, 19]);
11835
+ validations_1 = __values(validations), validations_1_1 = validations_1.next();
11525
11836
  _e.label = 7;
11526
11837
  case 7:
11527
- _e.trys.push([7, 12, 13, 14]);
11528
- pipelinesUrls_1 = (e_1 = void 0, __values(pipelinesUrls)), pipelinesUrls_1_1 = pipelinesUrls_1.next();
11838
+ if (!!validations_1_1.done) return [3 /*break*/, 16];
11839
+ validation_1 = validations_1_1.value;
11529
11840
  _e.label = 8;
11530
11841
  case 8:
11531
- if (!!pipelinesUrls_1_1.done) return [3 /*break*/, 11];
11842
+ _e.trys.push([8, 13, 14, 15]);
11843
+ pipelinesUrls_1 = (e_1 = void 0, __values(pipelinesUrls)), pipelinesUrls_1_1 = pipelinesUrls_1.next();
11844
+ _e.label = 9;
11845
+ case 9:
11846
+ if (!!pipelinesUrls_1_1.done) return [3 /*break*/, 12];
11532
11847
  pipelineUrl = pipelinesUrls_1_1.value;
11533
11848
  return [4 /*yield*/, collection.getPipelineByUrl(pipelineUrl)];
11534
- case 9:
11849
+ case 10:
11535
11850
  pipeline = _e.sent();
11536
11851
  if (validation_1 === 'logic') {
11537
11852
  validatePipeline(pipeline);
@@ -11539,37 +11854,37 @@ function initializeMakeCommand(program) {
11539
11854
  console.info(colors.cyan("Validated logic of ".concat(pipeline.pipelineUrl)));
11540
11855
  }
11541
11856
  }
11542
- _e.label = 10;
11543
- case 10:
11857
+ _e.label = 11;
11858
+ case 11:
11544
11859
  pipelinesUrls_1_1 = pipelinesUrls_1.next();
11545
- return [3 /*break*/, 8];
11546
- case 11: return [3 /*break*/, 14];
11547
- case 12:
11860
+ return [3 /*break*/, 9];
11861
+ case 12: return [3 /*break*/, 15];
11862
+ case 13:
11548
11863
  e_1_1 = _e.sent();
11549
11864
  e_1 = { error: e_1_1 };
11550
- return [3 /*break*/, 14];
11551
- case 13:
11865
+ return [3 /*break*/, 15];
11866
+ case 14:
11552
11867
  try {
11553
11868
  if (pipelinesUrls_1_1 && !pipelinesUrls_1_1.done && (_d = pipelinesUrls_1.return)) _d.call(pipelinesUrls_1);
11554
11869
  }
11555
11870
  finally { if (e_1) throw e_1.error; }
11556
11871
  return [7 /*endfinally*/];
11557
- case 14:
11872
+ case 15:
11558
11873
  validations_1_1 = validations_1.next();
11559
- return [3 /*break*/, 6];
11560
- case 15: return [3 /*break*/, 18];
11561
- case 16:
11874
+ return [3 /*break*/, 7];
11875
+ case 16: return [3 /*break*/, 19];
11876
+ case 17:
11562
11877
  e_2_1 = _e.sent();
11563
11878
  e_2 = { error: e_2_1 };
11564
- return [3 /*break*/, 18];
11565
- case 17:
11879
+ return [3 /*break*/, 19];
11880
+ case 18:
11566
11881
  try {
11567
11882
  if (validations_1_1 && !validations_1_1.done && (_c = validations_1.return)) _c.call(validations_1);
11568
11883
  }
11569
11884
  finally { if (e_2) throw e_2.error; }
11570
11885
  return [7 /*endfinally*/];
11571
- case 18: return [4 /*yield*/, collectionToJson(collection)];
11572
- case 19:
11886
+ case 19: return [4 /*yield*/, collectionToJson(collection)];
11887
+ case 20:
11573
11888
  collectionJson = _e.sent();
11574
11889
  collectionJsonString = stringifyPipelineJson(collectionJson).trim();
11575
11890
  collectionJsonItems = (function () {
@@ -11601,32 +11916,32 @@ function initializeMakeCommand(program) {
11601
11916
  case 2:
11602
11917
  _a.sent();
11603
11918
  // Note: Log despite of verbose mode
11604
- console.info(colors.green("Maked ".concat(filename.split('\\').join('/'))));
11919
+ console.info(colors.green("Made ".concat(filename.split('\\').join('/'))));
11605
11920
  return [2 /*return*/];
11606
11921
  }
11607
11922
  });
11608
11923
  }); };
11609
- if (!formats.includes('json')) return [3 /*break*/, 21];
11924
+ if (!formats.includes('json')) return [3 /*break*/, 22];
11610
11925
  formats = formats.filter(function (format) { return format !== 'json'; });
11611
11926
  return [4 /*yield*/, saveFile('json', collectionJsonString)];
11612
- case 20:
11613
- _e.sent();
11614
- _e.label = 21;
11615
11927
  case 21:
11616
- if (!(formats.includes('javascript') || formats.includes('js'))) return [3 /*break*/, 23];
11928
+ _e.sent();
11929
+ _e.label = 22;
11930
+ case 22:
11931
+ if (!(formats.includes('javascript') || formats.includes('js'))) return [3 /*break*/, 24];
11617
11932
  formats = formats.filter(function (format) { return format !== 'javascript' && format !== 'js'; });
11618
11933
  return [4 /*yield*/, saveFile('js', spaceTrim(function (block) { return "\n // ".concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n\n import { createCollectionFromJson } from '@promptbook/core';\n\n /**\n * Pipeline collection for ").concat(projectName, "\n *\n * ").concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n *\n * @generated\n * @private internal cache for `").concat(functionName, "`\n */\n let pipelineCollection = null;\n\n\n /**\n * Get pipeline collection for ").concat(projectName, "\n *\n * ").concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n *\n * @generated\n * @returns {PipelineCollection} Library of promptbooks for ").concat(projectName, "\n */\n export function ").concat(functionName, "(){\n if(pipelineCollection===null){\n pipelineCollection = createCollectionFromJson(\n ").concat(block(collectionJsonItems), "\n );\n }\n\n return pipelineCollection;\n }\n "); }))];
11619
- case 22:
11620
- (_e.sent()) + '\n';
11621
- _e.label = 23;
11622
11934
  case 23:
11623
- if (!(formats.includes('typescript') || formats.includes('ts'))) return [3 /*break*/, 25];
11624
- formats = formats.filter(function (format) { return format !== 'typescript' && format !== 'ts'; });
11625
- return [4 /*yield*/, saveFile('ts', spaceTrim(function (block) { return "\n // ".concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n\n import { createCollectionFromJson } from '@promptbook/core';\n import type { PipelineCollection } from '@promptbook/types';\n\n /**\n * Pipeline collection for ").concat(projectName, "\n *\n * ").concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n *\n * @private internal cache for `").concat(functionName, "`\n * @generated\n */\n let pipelineCollection: null | PipelineCollection = null;\n\n\n /**\n * Get pipeline collection for ").concat(projectName, "\n *\n * ").concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n *\n * @generated\n * @returns {PipelineCollection} Library of promptbooks for ").concat(projectName, "\n */\n export function ").concat(functionName, "(): PipelineCollection{\n if(pipelineCollection===null){\n\n // TODO: !!!!!! Use book string literal notation\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n pipelineCollection = (createCollectionFromJson as (..._: any) => PipelineCollection)(\n ").concat(block(collectionJsonItems), "\n );\n }\n\n return pipelineCollection;\n }\n "); }) + '\n')];
11935
+ (_e.sent()) + '\n';
11936
+ _e.label = 24;
11626
11937
  case 24:
11627
- _e.sent();
11628
- _e.label = 25;
11938
+ if (!(formats.includes('typescript') || formats.includes('ts'))) return [3 /*break*/, 26];
11939
+ formats = formats.filter(function (format) { return format !== 'typescript' && format !== 'ts'; });
11940
+ return [4 /*yield*/, saveFile('ts', spaceTrim(function (block) { return "\n // ".concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n\n import { createCollectionFromJson } from '@promptbook/core';\n import type { PipelineCollection } from '@promptbook/types';\n\n /**\n * Pipeline collection for ").concat(projectName, "\n *\n * ").concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n *\n * @private internal cache for `").concat(functionName, "`\n * @generated\n */\n let pipelineCollection: null | PipelineCollection = null;\n\n\n /**\n * Get pipeline collection for ").concat(projectName, "\n *\n * ").concat(block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI), "\n *\n * @generated\n * @returns {PipelineCollection} Library of promptbooks for ").concat(projectName, "\n */\n export function ").concat(functionName, "(): PipelineCollection{\n if(pipelineCollection===null){\n\n // TODO: !!6 Use book string literal notation\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n pipelineCollection = (createCollectionFromJson as (..._: any) => PipelineCollection)(\n ").concat(block(collectionJsonItems), "\n );\n }\n\n return pipelineCollection;\n }\n "); }) + '\n')];
11629
11941
  case 25:
11942
+ _e.sent();
11943
+ _e.label = 26;
11944
+ case 26:
11630
11945
  if (formats.length > 0) {
11631
11946
  console.warn(colors.yellow("Format ".concat(formats.join(' and '), " is not supported")));
11632
11947
  }
@@ -11641,7 +11956,7 @@ function initializeMakeCommand(program) {
11641
11956
  });
11642
11957
  }
11643
11958
  /**
11644
- * TODO: [🥃][main] !!! Allow `ptbk make` without configuring any llm tools
11959
+ * TODO: [🥃][main] !!3 Allow `ptbk make` without configuring any llm tools
11645
11960
  * TODO: [0] DRY Javascript and typescript - Maybe make ONLY typescript and for javascript just remove types
11646
11961
  * Note: [💞] Ignore a discrepancy between file name and entity name
11647
11962
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
@@ -11659,85 +11974,21 @@ function addAutoGeneratedSection(content, options) {
11659
11974
  var sectionRegex = new RegExp("<!--".concat(sectionName, "-->([\\s\\S]*?)<!--/").concat(sectionName, "-->"), 'g');
11660
11975
  var sectionMatch = content.match(sectionRegex);
11661
11976
  var contentToInsert = spaceTrim$1(function (block) { return "\n <!--".concat(sectionName, "-->\n ").concat(block(warningLine), "\n ").concat(block(sectionContent), "\n <!--/").concat(sectionName, "-->\n "); });
11662
- if (sectionMatch) {
11663
- return content.replace(sectionRegex, contentToInsert);
11664
- }
11665
- // Note: Following is the case when the section is not found in the file so we add it there
11666
- var placeForSection = removeContentComments(content).match(/^##.*$/im);
11667
- if (placeForSection !== null) {
11668
- var _a = __read(placeForSection, 1), heading_1 = _a[0];
11669
- return content.replace(heading_1, spaceTrim$1(function (block) { return "\n ".concat(block(contentToInsert), "\n\n ").concat(block(heading_1), "\n "); }));
11670
- }
11671
- console.warn("No place where to put the section <!--".concat(sectionName, "-->, using the end of the file"));
11672
- // <- TODO: [🚎][💩] Some better way how to get warnings from pipeline parsing / logic
11673
- return spaceTrim$1(function (block) { return "\n ".concat(block(content), "\n\n ").concat(block(contentToInsert), "\n "); });
11674
- }
11675
- /**
11676
- * TODO: [🏛] This can be part of markdown builder
11677
- */
11678
-
11679
- /**
11680
- * Creates a Mermaid graph based on the promptbook
11681
- *
11682
- * Note: The result is not wrapped in a Markdown code block
11683
- *
11684
- * @public exported from `@promptbook/utils`
11685
- */
11686
- function renderPromptbookMermaid(pipelineJson, options) {
11687
- var _a = (options || {}).linkTask, linkTask = _a === void 0 ? function () { return null; } : _a;
11688
- var parameterNameToTaskName = function (parameterName) {
11689
- var parameter = pipelineJson.parameters.find(function (parameter) { return parameter.name === parameterName; });
11690
- if (!parameter) {
11691
- throw new UnexpectedError("Could not find {".concat(parameterName, "}"));
11692
- // <- TODO: !!!!!! This causes problems when {knowledge} and other reserved parameters are used
11693
- }
11694
- if (parameter.isInput) {
11695
- return 'input';
11696
- }
11697
- var task = pipelineJson.tasks.find(function (task) { return task.resultingParameterName === parameterName; });
11698
- if (!task) {
11699
- throw new Error("Could not find task for {".concat(parameterName, "}"));
11700
- }
11701
- return task.name || normalizeTo_camelCase('task-' + titleToName(task.title));
11702
- };
11703
- var promptbookMermaid = spaceTrim$1(function (block) { return "\n\n %% \uD83D\uDD2E Tip: Open this on GitHub or in the VSCode website to see the Mermaid graph visually\n\n flowchart LR\n subgraph \"".concat(pipelineJson.title, "\"\n\n direction TB\n\n input((Input)):::input\n ").concat(block(pipelineJson.tasks
11704
- .flatMap(function (_a) {
11705
- var title = _a.title, dependentParameterNames = _a.dependentParameterNames, resultingParameterName = _a.resultingParameterName;
11706
- return __spreadArray([
11707
- "".concat(parameterNameToTaskName(resultingParameterName), "(\"").concat(title, "\")")
11708
- ], __read(dependentParameterNames.map(function (dependentParameterName) {
11709
- return "".concat(parameterNameToTaskName(dependentParameterName), "--\"{").concat(dependentParameterName, "}\"-->").concat(parameterNameToTaskName(resultingParameterName));
11710
- })), false);
11711
- })
11712
- .join('\n')), "\n\n ").concat(block(pipelineJson.parameters
11713
- .filter(function (_a) {
11714
- var isOutput = _a.isOutput;
11715
- return isOutput;
11716
- })
11717
- .map(function (_a) {
11718
- var name = _a.name;
11719
- return "".concat(parameterNameToTaskName(name), "--\"{").concat(name, "}\"-->output");
11720
- })
11721
- .join('\n')), "\n output((Output)):::output\n\n ").concat(block(pipelineJson.tasks
11722
- .map(function (task) {
11723
- var link = linkTask(task);
11724
- if (link === null) {
11725
- return '';
11726
- }
11727
- var href = link.href, title = link.title;
11728
- var taskName = parameterNameToTaskName(task.resultingParameterName);
11729
- return "click ".concat(taskName, " href \"").concat(href, "\" \"").concat(title, "\";");
11730
- })
11731
- .filter(function (line) { return line !== ''; })
11732
- .join('\n')), "\n\n classDef input color: grey;\n classDef output color: grey;\n\n end;\n\n "); });
11733
- return promptbookMermaid;
11977
+ if (sectionMatch) {
11978
+ return content.replace(sectionRegex, contentToInsert);
11979
+ }
11980
+ // Note: Following is the case when the section is not found in the file so we add it there
11981
+ var placeForSection = removeMarkdownComments(content).match(/^##.*$/im);
11982
+ if (placeForSection !== null) {
11983
+ var _a = __read(placeForSection, 1), heading_1 = _a[0];
11984
+ return content.replace(heading_1, spaceTrim$1(function (block) { return "\n ".concat(block(contentToInsert), "\n\n ").concat(block(heading_1), "\n "); }));
11985
+ }
11986
+ console.warn("No place where to put the section <!--".concat(sectionName, "-->, using the end of the file"));
11987
+ // <- TODO: [🚎][💩] Some better way how to get warnings from pipeline parsing / logic
11988
+ return spaceTrim$1(function (block) { return "\n ".concat(block(content), "\n\n ").concat(block(contentToInsert), "\n "); });
11734
11989
  }
11735
11990
  /**
11736
- * TODO: [🧠] !! FOREACH in mermaid graph
11737
- * TODO: [🧠] !! Knowledge in mermaid graph
11738
- * TODO: [🧠] !! Personas in mermaid graph
11739
- * TODO: Maybe use some Mermaid package instead of string templating
11740
- * TODO: [🕌] When more than 2 functionalities, split into separate functions
11991
+ * TODO: [🏛] This can be part of markdown builder
11741
11992
  */
11742
11993
 
11743
11994
  /**
@@ -11770,6 +12021,7 @@ function prettifyPipelineString(pipelineString, options) {
11770
12021
  case 2:
11771
12022
  if (isPrettifyed) {
11772
12023
  pipelineString = prettifyMarkdown(pipelineString);
12024
+ // <- TODO: [😧] `prettifyMarkdown` should preserve discriminated type *(or at lease `PipelineString`)*
11773
12025
  }
11774
12026
  return [2 /*return*/, pipelineString];
11775
12027
  }
@@ -11798,18 +12050,18 @@ function initializePrettifyCommand(program) {
11798
12050
  prettifyCommand.action(function (filesGlob, _a) {
11799
12051
  var ignore = _a.ignore, isVerbose = _a.verbose;
11800
12052
  return __awaiter(_this, void 0, void 0, function () {
11801
- var filenames, filenames_1, filenames_1_1, filename, pipelineMarkdown, error_1, e_1_1;
11802
- var e_1, _b;
11803
- return __generator(this, function (_c) {
11804
- switch (_c.label) {
12053
+ var filenames, filenames_1, filenames_1_1, filename, pipelineMarkdown, _b, error_1, e_1_1;
12054
+ var e_1, _c;
12055
+ return __generator(this, function (_d) {
12056
+ switch (_d.label) {
11805
12057
  case 0: return [4 /*yield*/, glob(filesGlob, { ignore: ignore })];
11806
12058
  case 1:
11807
- filenames = _c.sent();
11808
- _c.label = 2;
12059
+ filenames = _d.sent();
12060
+ _d.label = 2;
11809
12061
  case 2:
11810
- _c.trys.push([2, 11, 12, 13]);
12062
+ _d.trys.push([2, 11, 12, 13]);
11811
12063
  filenames_1 = __values(filenames), filenames_1_1 = filenames_1.next();
11812
- _c.label = 3;
12064
+ _d.label = 3;
11813
12065
  case 3:
11814
12066
  if (!!filenames_1_1.done) return [3 /*break*/, 10];
11815
12067
  filename = filenames_1_1.value;
@@ -11817,28 +12069,29 @@ function initializePrettifyCommand(program) {
11817
12069
  console.info(colors.gray("Skipping ".concat(filename)));
11818
12070
  return [3 /*break*/, 9];
11819
12071
  }
12072
+ _b = validatePipelineString;
11820
12073
  return [4 /*yield*/, readFile(filename, 'utf-8')];
11821
12074
  case 4:
11822
- pipelineMarkdown = (_c.sent());
11823
- _c.label = 5;
12075
+ pipelineMarkdown = _b.apply(void 0, [_d.sent()]);
12076
+ _d.label = 5;
11824
12077
  case 5:
11825
- _c.trys.push([5, 8, , 9]);
12078
+ _d.trys.push([5, 8, , 9]);
11826
12079
  return [4 /*yield*/, prettifyPipelineString(pipelineMarkdown, {
11827
12080
  isGraphAdded: true,
11828
12081
  isPrettifyed: true,
11829
12082
  // <- [🕌]
11830
12083
  })];
11831
12084
  case 6:
11832
- pipelineMarkdown = _c.sent();
12085
+ pipelineMarkdown = _d.sent();
11833
12086
  return [4 /*yield*/, writeFile(filename, pipelineMarkdown)];
11834
12087
  case 7:
11835
- _c.sent();
12088
+ _d.sent();
11836
12089
  if (isVerbose) {
11837
12090
  console.info(colors.green("Prettify ".concat(filename)));
11838
12091
  }
11839
12092
  return [3 /*break*/, 9];
11840
12093
  case 8:
11841
- error_1 = _c.sent();
12094
+ error_1 = _d.sent();
11842
12095
  if (!(error_1 instanceof Error)) {
11843
12096
  throw error_1;
11844
12097
  }
@@ -11851,12 +12104,12 @@ function initializePrettifyCommand(program) {
11851
12104
  return [3 /*break*/, 3];
11852
12105
  case 10: return [3 /*break*/, 13];
11853
12106
  case 11:
11854
- e_1_1 = _c.sent();
12107
+ e_1_1 = _d.sent();
11855
12108
  e_1 = { error: e_1_1 };
11856
12109
  return [3 /*break*/, 13];
11857
12110
  case 12:
11858
12111
  try {
11859
- if (filenames_1_1 && !filenames_1_1.done && (_b = filenames_1.return)) _b.call(filenames_1);
12112
+ if (filenames_1_1 && !filenames_1_1.done && (_c = filenames_1.return)) _c.call(filenames_1);
11860
12113
  }
11861
12114
  finally { if (e_1) throw e_1.error; }
11862
12115
  return [7 /*endfinally*/];
@@ -12182,6 +12435,187 @@ function executionReportJsonToString(executionReportJson, options) {
12182
12435
  * TODO: [🧠] Should be in generated file GENERATOR_WARNING
12183
12436
  */
12184
12437
 
12438
+ /**
12439
+ * Function `isValidPipelineString` will validate the if the string is a valid pipeline string
12440
+ * 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.
12441
+ *
12442
+ * @param {string} pipelineString the candidate for a pipeline string
12443
+ * @returns {boolean} if the string is a valid pipeline string
12444
+ * @public exported from `@promptbook/core`
12445
+ */
12446
+ function isValidPipelineString(pipelineString) {
12447
+ try {
12448
+ validatePipelineString(pipelineString);
12449
+ return true;
12450
+ }
12451
+ catch (error) {
12452
+ if (!(error instanceof Error)) {
12453
+ throw error;
12454
+ }
12455
+ return false;
12456
+ }
12457
+ }
12458
+ /**
12459
+ * TODO: [🧠][🈴] Where is the best location for this file
12460
+ */
12461
+
12462
+ /**
12463
+ * @see ./wizzard.ts `getPipeline` method
12464
+ *
12465
+ * @private usable through `ptbk run` and `@prompbook/wizzard`
12466
+ */
12467
+ function $getCompiledBook(tools, pipelineSource, options) {
12468
+ return __awaiter(this, void 0, void 0, function () {
12469
+ var fs, fetch, filePathRaw, filePath, filePathCandidates, filePathCandidates_1, filePathCandidates_1_1, filePathCandidate, pipelineString, _a, pipelineJson, e_1_1, rootDirname, _loop_1, i, state_1, response_1, pipelineString, pipelineJson, pipelineJson;
12470
+ var e_1, _b;
12471
+ var _this = this;
12472
+ return __generator(this, function (_c) {
12473
+ switch (_c.label) {
12474
+ case 0:
12475
+ fs = tools.fs, fetch = tools.fetch;
12476
+ if (!isValidFilePath(pipelineSource)) return [3 /*break*/, 10];
12477
+ filePathRaw = pipelineSource;
12478
+ filePath = null;
12479
+ filePathCandidates = [filePathRaw, "".concat(filePathRaw, ".md"), "".concat(filePathRaw, ".book.md"), "".concat(filePathRaw, ".book.md")];
12480
+ filePathCandidates = __spreadArray(__spreadArray([], __read(filePathCandidates), false), __read(filePathCandidates.map(function (path) { return path.split('\\').join('/'); })), false);
12481
+ _c.label = 1;
12482
+ case 1:
12483
+ _c.trys.push([1, 8, 9, 10]);
12484
+ filePathCandidates_1 = __values(filePathCandidates), filePathCandidates_1_1 = filePathCandidates_1.next();
12485
+ _c.label = 2;
12486
+ case 2:
12487
+ if (!!filePathCandidates_1_1.done) return [3 /*break*/, 7];
12488
+ filePathCandidate = filePathCandidates_1_1.value;
12489
+ return [4 /*yield*/, isFileExisting(filePathCandidate, fs)
12490
+ // <- TODO: Also test that among the candidates the file is book not just any file
12491
+ ];
12492
+ case 3:
12493
+ if (!_c.sent()) return [3 /*break*/, 6];
12494
+ filePath = filePathCandidate;
12495
+ _a = validatePipelineString;
12496
+ return [4 /*yield*/, fs.readFile(filePath, 'utf-8')];
12497
+ case 4:
12498
+ pipelineString = _a.apply(void 0, [_c.sent()]);
12499
+ return [4 /*yield*/, compilePipeline(pipelineString, tools, __assign({ rootDirname: process.cwd() }, options))];
12500
+ case 5:
12501
+ pipelineJson = _c.sent();
12502
+ return [2 /*return*/, pipelineJson];
12503
+ case 6:
12504
+ filePathCandidates_1_1 = filePathCandidates_1.next();
12505
+ return [3 /*break*/, 2];
12506
+ case 7: return [3 /*break*/, 10];
12507
+ case 8:
12508
+ e_1_1 = _c.sent();
12509
+ e_1 = { error: e_1_1 };
12510
+ return [3 /*break*/, 10];
12511
+ case 9:
12512
+ try {
12513
+ if (filePathCandidates_1_1 && !filePathCandidates_1_1.done && (_b = filePathCandidates_1.return)) _b.call(filePathCandidates_1);
12514
+ }
12515
+ finally { if (e_1) throw e_1.error; }
12516
+ return [7 /*endfinally*/];
12517
+ case 10:
12518
+ if (!isValidPipelineUrl(pipelineSource)) return [3 /*break*/, 14];
12519
+ rootDirname = process.cwd();
12520
+ _loop_1 = function (i) {
12521
+ var booksDirname, collection_1, pipeline;
12522
+ return __generator(this, function (_d) {
12523
+ switch (_d.label) {
12524
+ case 0:
12525
+ booksDirname = join(rootDirname, DEFAULT_BOOKS_DIRNAME /* <- TODO: [🕝] Make here more candidates */);
12526
+ return [4 /*yield*/, isDirectoryExisting(booksDirname, fs)];
12527
+ case 1:
12528
+ if (!_d.sent()) return [3 /*break*/, 4];
12529
+ return [4 /*yield*/, createCollectionFromDirectory(booksDirname, tools, __assign({ isRecursive: true, rootDirname: booksDirname }, options))];
12530
+ case 2:
12531
+ collection_1 = _d.sent();
12532
+ return [4 /*yield*/, (function () { return __awaiter(_this, void 0, void 0, function () {
12533
+ var error_1;
12534
+ return __generator(this, function (_a) {
12535
+ switch (_a.label) {
12536
+ case 0:
12537
+ _a.trys.push([0, 2, , 3]);
12538
+ return [4 /*yield*/, collection_1.getPipelineByUrl(pipelineSource)];
12539
+ case 1: return [2 /*return*/, _a.sent()];
12540
+ case 2:
12541
+ error_1 = _a.sent();
12542
+ if (!(error_1 instanceof NotFoundError)) {
12543
+ throw error_1;
12544
+ }
12545
+ // Note: If the pipeline was not found in the collection, try next strategy
12546
+ return [2 /*return*/, null];
12547
+ case 3: return [2 /*return*/];
12548
+ }
12549
+ });
12550
+ }); })()];
12551
+ case 3:
12552
+ pipeline = _d.sent();
12553
+ // console.log({ pipeline });
12554
+ if (pipeline !== null) {
12555
+ return [2 /*return*/, { value: pipeline }];
12556
+ }
12557
+ _d.label = 4;
12558
+ case 4:
12559
+ if (isRootPath(rootDirname)) {
12560
+ return [2 /*return*/, "break-up_to_root"];
12561
+ }
12562
+ // Note: If the directory does not exist, try the parent directory
12563
+ rootDirname = join(rootDirname, '..');
12564
+ return [2 /*return*/];
12565
+ }
12566
+ });
12567
+ };
12568
+ i = 0;
12569
+ _c.label = 11;
12570
+ case 11:
12571
+ if (!(i < LOOP_LIMIT)) return [3 /*break*/, 14];
12572
+ return [5 /*yield**/, _loop_1(i)];
12573
+ case 12:
12574
+ state_1 = _c.sent();
12575
+ if (typeof state_1 === "object")
12576
+ return [2 /*return*/, state_1.value];
12577
+ switch (state_1) {
12578
+ case "break-up_to_root": return [3 /*break*/, 14];
12579
+ }
12580
+ _c.label = 13;
12581
+ case 13:
12582
+ i++;
12583
+ return [3 /*break*/, 11];
12584
+ case 14:
12585
+ if (!isValidPipelineUrl(pipelineSource)) return [3 /*break*/, 18];
12586
+ return [4 /*yield*/, fetch(pipelineSource)];
12587
+ case 15:
12588
+ response_1 = _c.sent();
12589
+ if (response_1.status >= 300) {
12590
+ throw new NotFoundError(spaceTrim(function (block) { return "\n Book not found on URL:\n ".concat(block(pipelineSource), "\n\n Request failed with status ").concat(block(response_1.status.toString()), " ").concat(block(response_1.statusText), "\n "); }));
12591
+ }
12592
+ return [4 /*yield*/, response_1.text()];
12593
+ case 16:
12594
+ pipelineString = _c.sent();
12595
+ // console.log({ pipelineString });
12596
+ if (!isValidPipelineString(pipelineString)) {
12597
+ throw new NotFoundError(spaceTrim(function (block) { return "\n Book not found on URL:\n ".concat(block(pipelineSource), "\n\n Requested URL does not seem to contain a valid book\n "); }));
12598
+ }
12599
+ return [4 /*yield*/, compilePipeline(pipelineString, tools, __assign({ rootDirname: null }, options))];
12600
+ case 17:
12601
+ pipelineJson = _c.sent();
12602
+ return [2 /*return*/, pipelineJson];
12603
+ case 18:
12604
+ if (!isValidPipelineString(pipelineSource)) return [3 /*break*/, 20];
12605
+ return [4 /*yield*/, compilePipeline(pipelineSource, tools, __assign({ rootDirname: null }, options))];
12606
+ case 19:
12607
+ pipelineJson = _c.sent();
12608
+ return [2 /*return*/, pipelineJson];
12609
+ case 20: /* not else */ throw new NotFoundError(spaceTrim(function (block) { return "\n Book not found:\n ".concat(block(pipelineSource), "\n\n Pipelines can be loaded from:\n 1) As a file ./books/write-cv.book.md\n 2) As a URL https://promptbook.studio/hejny/write-cv.book.md found in ./books folder recursively\n 2) As a URL https://promptbook.studio/hejny/write-cv.book.md fetched from the internet\n 3) As a string\n\n\n "); }));
12610
+ }
12611
+ });
12612
+ });
12613
+ }
12614
+ /**
12615
+ * TODO: Write unit test
12616
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
12617
+ */
12618
+
12185
12619
  /**
12186
12620
  * Run the interactive chatbot in CLI
12187
12621
  *
@@ -12308,20 +12742,20 @@ function initializeRunCommand(program) {
12308
12742
  var runCommand = program.command('run', { isDefault: true });
12309
12743
  runCommand.description(spaceTrim("\n Runs a pipeline\n "));
12310
12744
  // TODO: [🧅] DRY command arguments
12311
- runCommand.argument('<path>',
12745
+ runCommand.argument('<pipelineSource>',
12312
12746
  // <- Note: [🧟‍♂️] This is NOT promptbook collection directory BUT direct path to .book.md file
12313
- 'Path to book file');
12747
+ 'Path to book file OR URL to book file');
12314
12748
  runCommand.option('-r, --reload', "Call LLM models even if same prompt with result is in the cache", false);
12315
12749
  runCommand.option('-v, --verbose', "Is output verbose", false);
12316
12750
  runCommand.option('--no-interactive', "Input is not interactive, if true you need to pass all the input parameters through --json");
12317
12751
  runCommand.option('--no-formfactor', "When set, behavior of the interactive mode is not changed by the formfactor of the pipeline");
12318
12752
  runCommand.option('-j, --json <json>', "Pass all or some input parameters as JSON record, if used the output is also returned as JSON");
12319
12753
  runCommand.option('-s, --save-report <path>', "Save report to file");
12320
- runCommand.action(function (filePathRaw, options) { return __awaiter(_this, void 0, void 0, function () {
12321
- var isCacheReloaded, isInteractive, isFormfactorUsed, json, isVerbose, saveReport, inputParameters, prepareAndScrapeOptions, fs, filePath, filePathCandidates, filePathCandidates_1, filePathCandidates_1_1, filePathCandidate, e_1_1, llm, executables, tools, pipelineString, pipeline, error_1, pipelineExecutor, questions, response, result, isSuccessful, errors, warnings, outputParameters, executionReport, executionReportString, _a, _b, error, _c, _d, warning, _e, _f, key, value, separator;
12322
- var e_1, _g, _h, e_2, _j, e_3, _k, e_4, _l;
12323
- return __generator(this, function (_m) {
12324
- switch (_m.label) {
12754
+ runCommand.action(function (pipelineSource, options) { return __awaiter(_this, void 0, void 0, function () {
12755
+ var isCacheReloaded, isInteractive, isFormfactorUsed, json, isVerbose, saveReport, inputParameters, prepareAndScrapeOptions, fs, llm, error_1, executables, tools, pipeline, error_2, pipelineExecutor, questions, response, result, isSuccessful, errors, warnings, outputParameters, executionReport, executionReportString, _a, _b, error, _c, _d, warning, _e, _f, key, value, separator;
12756
+ var _g, e_1, _h, e_2, _j, e_3, _k;
12757
+ return __generator(this, function (_l) {
12758
+ switch (_l.label) {
12325
12759
  case 0:
12326
12760
  isCacheReloaded = options.reload, isInteractive = options.interactive, isFormfactorUsed = options.formfactor, json = options.json, isVerbose = options.verbose, saveReport = options.saveReport;
12327
12761
  if (saveReport && !saveReport.endsWith('.json') && !saveReport.endsWith('.md')) {
@@ -12341,104 +12775,65 @@ function initializeRunCommand(program) {
12341
12775
  console.info(colors.gray('--- Preparing tools ---'));
12342
12776
  }
12343
12777
  fs = $provideFilesystemForNode(prepareAndScrapeOptions);
12344
- filePath = null;
12345
- filePathCandidates = [filePathRaw, "".concat(filePathRaw, ".md"), "".concat(filePathRaw, ".book.md"), "".concat(filePathRaw, ".book.md")];
12346
- filePathCandidates = __spreadArray(__spreadArray([], __read(filePathCandidates), false), __read(filePathCandidates.map(function (path) { return path.split('\\').join('/'); })), false);
12347
- _m.label = 1;
12778
+ _l.label = 1;
12348
12779
  case 1:
12349
- _m.trys.push([1, 6, 7, 8]);
12350
- filePathCandidates_1 = __values(filePathCandidates), filePathCandidates_1_1 = filePathCandidates_1.next();
12351
- _m.label = 2;
12780
+ _l.trys.push([1, 3, , 4]);
12781
+ return [4 /*yield*/, $provideLlmToolsForWizzardOrCli(prepareAndScrapeOptions)];
12352
12782
  case 2:
12353
- if (!!filePathCandidates_1_1.done) return [3 /*break*/, 5];
12354
- filePathCandidate = filePathCandidates_1_1.value;
12355
- return [4 /*yield*/, isFileExisting(filePathCandidate, fs)
12356
- // <- TODO: Also test that among the candidates the file is book not just any file
12357
- ];
12783
+ llm = _l.sent();
12784
+ return [3 /*break*/, 4];
12358
12785
  case 3:
12359
- if (_m.sent()
12360
- // <- TODO: Also test that among the candidates the file is book not just any file
12361
- ) {
12362
- filePath = filePathCandidate;
12363
- return [3 /*break*/, 5];
12364
- }
12365
- _m.label = 4;
12366
- case 4:
12367
- filePathCandidates_1_1 = filePathCandidates_1.next();
12368
- return [3 /*break*/, 2];
12369
- case 5: return [3 /*break*/, 8];
12370
- case 6:
12371
- e_1_1 = _m.sent();
12372
- e_1 = { error: e_1_1 };
12373
- return [3 /*break*/, 8];
12374
- case 7:
12375
- try {
12376
- if (filePathCandidates_1_1 && !filePathCandidates_1_1.done && (_g = filePathCandidates_1.return)) _g.call(filePathCandidates_1);
12377
- }
12378
- finally { if (e_1) throw e_1.error; }
12379
- return [7 /*endfinally*/];
12380
- case 8:
12381
- if (filePath === null) {
12382
- console.error(colors.red("File \"".concat(filePathRaw, "\" does not exist")));
12383
- return [2 /*return*/, process.exit(1)];
12384
- }
12385
- try {
12386
- llm = $provideLlmToolsForCli(prepareAndScrapeOptions);
12786
+ error_1 = _l.sent();
12787
+ if (!(error_1 instanceof Error)) {
12788
+ throw error_1;
12387
12789
  }
12388
- catch (error) {
12389
- if (!(error instanceof Error)) {
12390
- throw error;
12391
- }
12392
- if (!error.message.includes('No LLM tools')) {
12393
- throw error;
12394
- }
12395
- console.error(colors.red(spaceTrim(function (block) { return "\n You need to configure LLM tools first\n\n 1) Create .env file at the root of your project\n 2) Configure API keys for LLM tools\n\n For example:\n ".concat(block($llmToolsMetadataRegister
12396
- .list()
12397
- .map(function (_a) {
12398
- var title = _a.title, envVariables = _a.envVariables;
12399
- return "- ".concat((envVariables || []).join(' + '), " (").concat(title, ")");
12400
- })
12401
- .join('\n')), "\n\n ").concat(block($registeredLlmToolsMessage()), "\n "); })));
12402
- return [2 /*return*/, process.exit(1)];
12790
+ if (!error_1.message.includes('No LLM tools')) {
12791
+ throw error_1;
12403
12792
  }
12404
- return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
12405
- case 9:
12406
- executables = _m.sent();
12407
- _h = {
12793
+ console.error(colors.red(spaceTrim(function (block) { return "\n You need to configure LLM tools first\n\n 1) Create .env file at the root of your project\n 2) Configure API keys for LLM tools\n\n For example:\n ".concat(block($llmToolsMetadataRegister
12794
+ .list()
12795
+ .map(function (_a) {
12796
+ var title = _a.title, envVariables = _a.envVariables;
12797
+ return "- ".concat((envVariables || []).join(' + '), " (").concat(title, ")");
12798
+ })
12799
+ .join('\n')), "\n\n ").concat(block($registeredLlmToolsMessage()), "\n "); })));
12800
+ return [2 /*return*/, process.exit(1)];
12801
+ case 4: return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
12802
+ case 5:
12803
+ executables = _l.sent();
12804
+ _g = {
12408
12805
  llm: llm,
12409
- fs: fs
12806
+ fs: fs,
12807
+ fetch: scraperFetch
12410
12808
  };
12411
12809
  return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, prepareAndScrapeOptions)];
12412
- case 10:
12413
- tools = (_h.scrapers = _m.sent(),
12414
- _h.script = [
12810
+ case 6:
12811
+ tools = (_g.scrapers = _l.sent(),
12812
+ _g.script = [
12415
12813
  /*new JavascriptExecutionTools(options)*/
12416
12814
  ],
12417
- _h);
12815
+ _g);
12418
12816
  if (isVerbose) {
12419
12817
  console.info(colors.gray('--- Reading file ---'));
12420
12818
  }
12421
- return [4 /*yield*/, readFile(filePath, 'utf-8')];
12422
- case 11:
12423
- pipelineString = (_m.sent());
12424
12819
  if (isVerbose) {
12425
12820
  console.info(colors.gray('--- Preparing pipeline ---'));
12426
12821
  }
12427
- _m.label = 12;
12428
- case 12:
12429
- _m.trys.push([12, 14, , 15]);
12430
- return [4 /*yield*/, compilePipeline(pipelineString, tools)];
12431
- case 13:
12432
- pipeline = _m.sent();
12433
- return [3 /*break*/, 15];
12434
- case 14:
12435
- error_1 = _m.sent();
12436
- if (!(error_1 instanceof ParseError)) {
12437
- throw error_1;
12822
+ _l.label = 7;
12823
+ case 7:
12824
+ _l.trys.push([7, 9, , 10]);
12825
+ return [4 /*yield*/, $getCompiledBook(tools, pipelineSource, prepareAndScrapeOptions)];
12826
+ case 8:
12827
+ pipeline = _l.sent();
12828
+ return [3 /*break*/, 10];
12829
+ case 9:
12830
+ error_2 = _l.sent();
12831
+ if (!(error_2 instanceof ParseError)) {
12832
+ throw error_2;
12438
12833
  }
12439
- console.error(colors.red(spaceTrim(function (block) { return "\n ".concat(block(error_1.message), "\n\n in ").concat(filePath, "\n "); })));
12834
+ console.error(colors.red(spaceTrim(function (block) { return "\n ".concat(block(error_2.message), "\n\n in ").concat(pipelineSource, "\n "); })));
12440
12835
  return [2 /*return*/, process.exit(1)];
12441
- case 15:
12836
+ case 10:
12442
12837
  if (isVerbose) {
12443
12838
  console.info(colors.gray('--- Validating pipeline ---'));
12444
12839
  }
@@ -12524,8 +12919,8 @@ function initializeRunCommand(program) {
12524
12919
  return [2 /*return*/, process.exit(1)];
12525
12920
  }
12526
12921
  return [4 /*yield*/, prompts(questions)];
12527
- case 16:
12528
- response = _m.sent();
12922
+ case 11:
12923
+ response = _l.sent();
12529
12924
  // <- TODO: [🧠][🍼] Change behavior according to the formfactor
12530
12925
  inputParameters = __assign(__assign({}, inputParameters), response);
12531
12926
  // TODO: Maybe do some validation of the response (and --json argument which is passed)
@@ -12538,26 +12933,26 @@ function initializeRunCommand(program) {
12538
12933
  console.info(taskProgress);
12539
12934
  }
12540
12935
  })];
12541
- case 17:
12542
- result = _m.sent();
12936
+ case 12:
12937
+ result = _l.sent();
12543
12938
  isSuccessful = result.isSuccessful, errors = result.errors, warnings = result.warnings, outputParameters = result.outputParameters, executionReport = result.executionReport;
12544
12939
  if (isVerbose) {
12545
12940
  console.info(colors.gray('--- Detailed Result ---'));
12546
12941
  console.info({ isSuccessful: isSuccessful, errors: errors, warnings: warnings, outputParameters: outputParameters, executionReport: executionReport });
12547
12942
  }
12548
- if (!(saveReport && saveReport.endsWith('.json'))) return [3 /*break*/, 19];
12943
+ if (!(saveReport && saveReport.endsWith('.json'))) return [3 /*break*/, 14];
12549
12944
  return [4 /*yield*/, writeFile(saveReport, JSON.stringify(executionReport, null, 4) + '\n', 'utf-8')];
12550
- case 18:
12551
- _m.sent();
12552
- return [3 /*break*/, 21];
12553
- case 19:
12554
- if (!(saveReport && saveReport.endsWith('.md'))) return [3 /*break*/, 21];
12945
+ case 13:
12946
+ _l.sent();
12947
+ return [3 /*break*/, 16];
12948
+ case 14:
12949
+ if (!(saveReport && saveReport.endsWith('.md'))) return [3 /*break*/, 16];
12555
12950
  executionReportString = executionReportJsonToString(executionReport);
12556
12951
  return [4 /*yield*/, writeFile(saveReport, executionReportString, 'utf-8')];
12557
- case 20:
12558
- _m.sent();
12559
- _m.label = 21;
12560
- case 21:
12952
+ case 15:
12953
+ _l.sent();
12954
+ _l.label = 16;
12955
+ case 16:
12561
12956
  if (saveReport && isVerbose) {
12562
12957
  console.info(colors.green("Report saved to ".concat(saveReport)));
12563
12958
  }
@@ -12575,12 +12970,12 @@ function initializeRunCommand(program) {
12575
12970
  console.error(colors.red(colors.bold(error.name) + ': ' + error.message));
12576
12971
  }
12577
12972
  }
12578
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
12973
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
12579
12974
  finally {
12580
12975
  try {
12581
- if (_b && !_b.done && (_j = _a.return)) _j.call(_a);
12976
+ if (_b && !_b.done && (_h = _a.return)) _h.call(_a);
12582
12977
  }
12583
- finally { if (e_2) throw e_2.error; }
12978
+ finally { if (e_1) throw e_1.error; }
12584
12979
  }
12585
12980
  try {
12586
12981
  for (_c = __values(warnings || []), _d = _c.next(); !_d.done; _d = _c.next()) {
@@ -12588,12 +12983,12 @@ function initializeRunCommand(program) {
12588
12983
  console.error(colors.red(colors.bold(warning.name) + ': ' + warning.message));
12589
12984
  }
12590
12985
  }
12591
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
12986
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
12592
12987
  finally {
12593
12988
  try {
12594
- if (_d && !_d.done && (_k = _c.return)) _k.call(_c);
12989
+ if (_d && !_d.done && (_j = _c.return)) _j.call(_c);
12595
12990
  }
12596
- finally { if (e_3) throw e_3.error; }
12991
+ finally { if (e_2) throw e_2.error; }
12597
12992
  }
12598
12993
  if (json === undefined) {
12599
12994
  try {
@@ -12604,12 +12999,12 @@ function initializeRunCommand(program) {
12604
12999
  console.info(colors.green(colors.bold(key) + separator + value));
12605
13000
  }
12606
13001
  }
12607
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
13002
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
12608
13003
  finally {
12609
13004
  try {
12610
- if (_f && !_f.done && (_l = _e.return)) _l.call(_e);
13005
+ if (_f && !_f.done && (_k = _e.return)) _k.call(_e);
12611
13006
  }
12612
- finally { if (e_4) throw e_4.error; }
13007
+ finally { if (e_3) throw e_3.error; }
12613
13008
  }
12614
13009
  }
12615
13010
  else {
@@ -12621,9 +13016,9 @@ function initializeRunCommand(program) {
12621
13016
  }); });
12622
13017
  }
12623
13018
  /**
12624
- * TODO: !!!!! Catch and wrap all errors from CLI
13019
+ * TODO: !!5 Catch and wrap all errors from CLI
12625
13020
  * TODO: [🧠] Pass `maxExecutionAttempts`, `csvSettings`
12626
- * TODO: [🥃][main] !!! Allow `ptbk run` without configuring any llm tools
13021
+ * TODO: [🥃][main] !!3 Allow `ptbk run` without configuring any llm tools
12627
13022
  * Note: [💞] Ignore a discrepancy between file name and entity name
12628
13023
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
12629
13024
  * TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
@@ -12647,75 +13042,78 @@ function initializeTestCommand(program) {
12647
13042
  testCommand.action(function (filesGlob, _a) {
12648
13043
  var ignore = _a.ignore, isCacheReloaded = _a.reload, isVerbose = _a.verbose;
12649
13044
  return __awaiter(_this, void 0, void 0, function () {
12650
- var prepareAndScrapeOptions, fs, llm, executables, tools, filenames, filenames_1, filenames_1_1, filename, pipeline, pipelineMarkdown, _b, _c, error_1, e_1_1;
12651
- var _d, e_1, _e;
12652
- return __generator(this, function (_f) {
12653
- switch (_f.label) {
13045
+ var prepareAndScrapeOptions, fs, llm, executables, tools, filenames, filenames_1, filenames_1_1, filename, pipeline, pipelineMarkdown, _b, _c, _d, error_1, e_1_1;
13046
+ var _e, e_1, _f;
13047
+ return __generator(this, function (_g) {
13048
+ switch (_g.label) {
12654
13049
  case 0:
12655
13050
  prepareAndScrapeOptions = {
12656
13051
  isVerbose: isVerbose,
12657
13052
  isCacheReloaded: isCacheReloaded,
12658
13053
  };
12659
13054
  fs = $provideFilesystemForNode(prepareAndScrapeOptions);
12660
- llm = $provideLlmToolsForCli(prepareAndScrapeOptions);
12661
- return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
13055
+ return [4 /*yield*/, $provideLlmToolsForWizzardOrCli(prepareAndScrapeOptions)];
12662
13056
  case 1:
12663
- executables = _f.sent();
12664
- _d = {
13057
+ llm = _g.sent();
13058
+ return [4 /*yield*/, $provideExecutablesForNode(prepareAndScrapeOptions)];
13059
+ case 2:
13060
+ executables = _g.sent();
13061
+ _e = {
12665
13062
  llm: llm,
12666
13063
  fs: fs
12667
13064
  };
12668
13065
  return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables }, prepareAndScrapeOptions)];
12669
- case 2:
12670
- tools = (_d.scrapers = _f.sent(),
12671
- _d.script = [
13066
+ case 3:
13067
+ tools = (_e.scrapers = _g.sent(),
13068
+ _e.script = [
12672
13069
  /*new JavascriptExecutionTools(options)*/
12673
13070
  ],
12674
- _d);
13071
+ _e);
12675
13072
  return [4 /*yield*/, glob(filesGlob, { ignore: ignore })];
12676
- case 3:
12677
- filenames = _f.sent();
12678
- _f.label = 4;
12679
13073
  case 4:
12680
- _f.trys.push([4, 16, 17, 18]);
12681
- filenames_1 = __values(filenames), filenames_1_1 = filenames_1.next();
12682
- _f.label = 5;
13074
+ filenames = _g.sent();
13075
+ _g.label = 5;
12683
13076
  case 5:
12684
- if (!!filenames_1_1.done) return [3 /*break*/, 15];
12685
- filename = filenames_1_1.value;
12686
- _f.label = 6;
13077
+ _g.trys.push([5, 17, 18, 19]);
13078
+ filenames_1 = __values(filenames), filenames_1_1 = filenames_1.next();
13079
+ _g.label = 6;
12687
13080
  case 6:
12688
- _f.trys.push([6, 13, , 14]);
13081
+ if (!!filenames_1_1.done) return [3 /*break*/, 16];
13082
+ filename = filenames_1_1.value;
13083
+ _g.label = 7;
13084
+ case 7:
13085
+ _g.trys.push([7, 14, , 15]);
12689
13086
  pipeline = void 0;
12690
- if (!filename.endsWith('.book.md')) return [3 /*break*/, 9];
13087
+ if (!filename.endsWith('.book.md')) return [3 /*break*/, 10];
13088
+ _b = validatePipelineString;
12691
13089
  return [4 /*yield*/, readFile(filename, 'utf-8')];
12692
- case 7:
12693
- pipelineMarkdown = (_f.sent());
12694
- return [4 /*yield*/, compilePipeline(pipelineMarkdown, tools)];
12695
13090
  case 8:
12696
- pipeline = _f.sent();
13091
+ pipelineMarkdown = _b.apply(void 0, [_g.sent()]);
13092
+ return [4 /*yield*/, compilePipeline(pipelineMarkdown, tools)];
13093
+ case 9:
13094
+ pipeline = _g.sent();
12697
13095
  if (isVerbose) {
12698
13096
  console.info(colors.green("Parsed ".concat(filename)));
12699
13097
  }
12700
- _f.label = 9;
12701
- case 9:
12702
- if (!filename.endsWith('.book.json')) return [3 /*break*/, 11];
12703
- _c = (_b = JSON).parse;
12704
- return [4 /*yield*/, readFile(filename, 'utf-8')];
13098
+ _g.label = 10;
12705
13099
  case 10:
12706
- pipeline = _c.apply(_b, [_f.sent()]);
12707
- return [3 /*break*/, 12];
13100
+ if (!filename.endsWith('.book.json')) return [3 /*break*/, 12];
13101
+ _d = (_c = JSON).parse;
13102
+ return [4 /*yield*/, readFile(filename, 'utf-8')];
12708
13103
  case 11:
13104
+ pipeline = _d.apply(_c, [_g.sent()]);
13105
+ return [3 /*break*/, 13];
13106
+ case 12:
12709
13107
  if (isVerbose) {
12710
13108
  console.info(colors.gray("Skipping ".concat(filename)));
12711
13109
  }
12712
- return [3 /*break*/, 14];
12713
- case 12:
13110
+ return [3 /*break*/, 15];
13111
+ case 13:
12714
13112
  validatePipeline(pipeline);
12715
13113
  console.info(colors.green("Validated ".concat(filename)));
12716
- return [3 /*break*/, 14];
12717
- case 13:
12718
- error_1 = _f.sent();
13114
+ return [3 /*break*/, 15];
13115
+ case 14:
13116
+ error_1 = _g.sent();
12719
13117
  if (!(error_1 instanceof Error)) {
12720
13118
  throw error_1;
12721
13119
  }
@@ -12723,21 +13121,21 @@ function initializeTestCommand(program) {
12723
13121
  console.error(colors.bgRed(error_1.name /* <- 11:11 */));
12724
13122
  console.error(colors.red(error_1.stack || error_1.message));
12725
13123
  return [2 /*return*/, process.exit(1)];
12726
- case 14:
13124
+ case 15:
12727
13125
  filenames_1_1 = filenames_1.next();
12728
- return [3 /*break*/, 5];
12729
- case 15: return [3 /*break*/, 18];
12730
- case 16:
12731
- e_1_1 = _f.sent();
12732
- e_1 = { error: e_1_1 };
12733
- return [3 /*break*/, 18];
13126
+ return [3 /*break*/, 6];
13127
+ case 16: return [3 /*break*/, 19];
12734
13128
  case 17:
13129
+ e_1_1 = _g.sent();
13130
+ e_1 = { error: e_1_1 };
13131
+ return [3 /*break*/, 19];
13132
+ case 18:
12735
13133
  try {
12736
- if (filenames_1_1 && !filenames_1_1.done && (_e = filenames_1.return)) _e.call(filenames_1);
13134
+ if (filenames_1_1 && !filenames_1_1.done && (_f = filenames_1.return)) _f.call(filenames_1);
12737
13135
  }
12738
13136
  finally { if (e_1) throw e_1.error; }
12739
13137
  return [7 /*endfinally*/];
12740
- case 18:
13138
+ case 19:
12741
13139
  console.info(colors.green("All pipelines are valid"));
12742
13140
  return [2 /*return*/, process.exit(0)];
12743
13141
  }
@@ -12818,6 +13216,7 @@ var _CLI = {
12818
13216
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
12819
13217
  *
12820
13218
  * @public exported from `@promptbook/core`
13219
+ * @public exported from `@promptbook/wizzard`
12821
13220
  * @public exported from `@promptbook/cli`
12822
13221
  */
12823
13222
  var _AnthropicClaudeMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -13139,12 +13538,12 @@ var ANTHROPIC_CLAUDE_MODELS = exportJson({
13139
13538
  output: computeUsage("$2.40 / 1M tokens"),
13140
13539
  },
13141
13540
  },
13142
- // TODO: [main] !!! Claude 1 and 2 has also completion versions - ask Hoagy
13541
+ // TODO: [main] !!3 Claude 1 and 2 has also completion versions - ask Hoagy
13143
13542
  ],
13144
13543
  });
13145
13544
  /**
13146
13545
  * Note: [🤖] Add models of new variant
13147
- * TODO: [🧠][main] !!! Add embedding models OR Anthropic has only chat+completion models?
13546
+ * TODO: [🧠][main] !!3 Add embedding models OR Anthropic has only chat+completion models?
13148
13547
  * TODO: [🧠] Some mechanism to propagate unsureness
13149
13548
  * TODO: [🧠][👮‍♀️] Put here more info like description, isVision, trainingDateCutoff, languages, strengths ( Top-level performance, intelligence, fluency, and understanding), contextWindow,...
13150
13549
  * TODO: [🎰] Some mechanism to auto-update available models
@@ -13519,8 +13918,8 @@ var createAnthropicClaudeExecutionTools = Object.assign(function (options) {
13519
13918
  className: 'AnthropicClaudeExecutionTools',
13520
13919
  });
13521
13920
  /**
13522
- * TODO: [🧠][main] !!!! Make anonymous this with all LLM providers
13523
- * TODO: [🧠][🧱][main] !!!! Maybe change all `new AnthropicClaudeExecutionTools` -> `createAnthropicClaudeExecutionTools` in manual
13921
+ * TODO: [🧠][main] !!4 Make anonymous this with all LLM providers
13922
+ * TODO: [🧠][🧱][main] !!4 Maybe change all `new AnthropicClaudeExecutionTools` -> `createAnthropicClaudeExecutionTools` in manual
13524
13923
  * TODO: [🧠] Maybe auto-detect usage in browser and determine default value of `isProxied`
13525
13924
  * TODO: [🦺] Is there some way how to put `packageName` and `className` on top and function definition on bottom?
13526
13925
  * TODO: [🎶] Naming "constructor" vs "creator" vs "factory"
@@ -13532,7 +13931,9 @@ var createAnthropicClaudeExecutionTools = Object.assign(function (options) {
13532
13931
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
13533
13932
  *
13534
13933
  * @public exported from `@promptbook/anthropic-claude`
13934
+ * @public exported from `@promptbook/wizzard`
13535
13935
  * @public exported from `@promptbook/cli`
13936
+ *
13536
13937
  */
13537
13938
  var _AnthropicClaudeRegistration = $llmToolsRegister.register(createAnthropicClaudeExecutionTools);
13538
13939
  /**
@@ -13546,6 +13947,7 @@ var _AnthropicClaudeRegistration = $llmToolsRegister.register(createAnthropicCla
13546
13947
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
13547
13948
  *
13548
13949
  * @public exported from `@promptbook/core`
13950
+ * @public exported from `@promptbook/wizzard`
13549
13951
  * @public exported from `@promptbook/cli`
13550
13952
  */
13551
13953
  var _AzureOpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -13922,7 +14324,7 @@ var OPENAI_MODELS = exportJson({
13922
14324
  prompt: computeUsage("$5.00 / 1M tokens"),
13923
14325
  output: computeUsage("$15.00 / 1M tokens"),
13924
14326
  },
13925
- //TODO: [main] !!! Add gpt-4o-mini-2024-07-18 and all others to be up to date
14327
+ //TODO: [main] !!3 Add gpt-4o-mini-2024-07-18 and all others to be up to date
13926
14328
  },
13927
14329
  /**/
13928
14330
  /**/
@@ -14072,7 +14474,7 @@ var AzureOpenAiExecutionTools = /** @class */ (function () {
14072
14474
  AzureOpenAiExecutionTools.prototype.listModels = function () {
14073
14475
  return __awaiter(this, void 0, void 0, function () {
14074
14476
  return __generator(this, function (_a) {
14075
- // TODO: [main] !!! Do here some filtering which models are really available as deployment
14477
+ // TODO: [main] !!3 Do here some filtering which models are really available as deployment
14076
14478
  // @see https://management.azure.com/subscriptions/subscriptionId/resourceGroups/resourceGroupName/providers/Microsoft.CognitiveServices/accounts/accountName/deployments?api-version=2023-05-01
14077
14479
  return [2 /*return*/, OPENAI_MODELS.map(function (_a) {
14078
14480
  var modelTitle = _a.modelTitle, modelName = _a.modelName, modelVariant = _a.modelVariant;
@@ -14353,6 +14755,7 @@ var createAzureOpenAiExecutionTools = Object.assign(function (options) {
14353
14755
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
14354
14756
  *
14355
14757
  * @public exported from `@promptbook/azure-openai`
14758
+ * @public exported from `@promptbook/wizzard`
14356
14759
  * @public exported from `@promptbook/cli`
14357
14760
  */
14358
14761
  var _AzureOpenAiRegistration = $llmToolsRegister.register(createAzureOpenAiExecutionTools);
@@ -14361,21 +14764,13 @@ var _AzureOpenAiRegistration = $llmToolsRegister.register(createAzureOpenAiExecu
14361
14764
  * Note: [💞] Ignore a discrepancy between file name and entity name
14362
14765
  */
14363
14766
 
14364
- /**
14365
- * Detects if the code is running in jest environment
14366
- *
14367
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
14368
- *
14369
- * @public exported from `@promptbook/utils`
14370
- */
14371
- var $isRunningInJest = new Function("\n try {\n return process.env.JEST_WORKER_ID !== undefined;\n } catch (e) {\n return false;\n }\n");
14372
-
14373
14767
  /**
14374
14768
  * Registration of LLM provider metadata
14375
14769
  *
14376
14770
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
14377
14771
  *
14378
14772
  * @public exported from `@promptbook/core`
14773
+ * @public exported from `@promptbook/wizzard`
14379
14774
  * @public exported from `@promptbook/cli`
14380
14775
  */
14381
14776
  var _GoogleMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -14634,6 +15029,7 @@ var createGoogleExecutionTools = Object.assign(function (options) {
14634
15029
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
14635
15030
  *
14636
15031
  * @public exported from `@promptbook/google`
15032
+ * @public exported from `@promptbook/wizzard`
14637
15033
  * @public exported from `@promptbook/cli`
14638
15034
  */
14639
15035
  var _GoogleRegistration = $llmToolsRegister.register(createGoogleExecutionTools);
@@ -14648,6 +15044,7 @@ var _GoogleRegistration = $llmToolsRegister.register(createGoogleExecutionTools)
14648
15044
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
14649
15045
  *
14650
15046
  * @public exported from `@promptbook/core`
15047
+ * @public exported from `@promptbook/wizzard`
14651
15048
  * @public exported from `@promptbook/cli`
14652
15049
  */
14653
15050
  var _OpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -14686,6 +15083,7 @@ var _OpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
14686
15083
  * Note: [🏐] Configurations registrations are done in @@@ BUT constructor @@@
14687
15084
  *
14688
15085
  * @public exported from `@promptbook/core`
15086
+ * @public exported from `@promptbook/wizzard`
14689
15087
  * @public exported from `@promptbook/cli`
14690
15088
  */
14691
15089
  var _OpenAiAssistantMetadataRegistration = $llmToolsMetadataRegister.register({
@@ -14728,24 +15126,6 @@ var _OpenAiAssistantMetadataRegistration = $llmToolsMetadataRegister.register({
14728
15126
  * Note: [💞] Ignore a discrepancy between file name and entity name
14729
15127
  */
14730
15128
 
14731
- /**
14732
- * Detects if the code is running in a browser environment in main thread (Not in a web worker)
14733
- *
14734
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
14735
- *
14736
- * @public exported from `@promptbook/utils`
14737
- */
14738
- var $isRunningInBrowser = new Function("\n try {\n return this === window;\n } catch (e) {\n return false;\n }\n");
14739
-
14740
- /**
14741
- * Detects if the code is running in a web worker
14742
- *
14743
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
14744
- *
14745
- * @public exported from `@promptbook/utils`
14746
- */
14747
- var $isRunningInWebWorker = new Function("\n try {\n if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {\n return true;\n } else {\n return false;\n }\n } catch (e) {\n return false;\n }\n");
14748
-
14749
15129
  /**
14750
15130
  * Computes the usage of the OpenAI API based on the response from OpenAI
14751
15131
  *
@@ -15248,7 +15628,7 @@ var OpenAiAssistantExecutionTools = /** @class */ (function (_super) {
15248
15628
  assistant_id: this.assistantId,
15249
15629
  thread: {
15250
15630
  messages: [
15251
- // TODO: [🗯] !! Allow threads to be passed
15631
+ // TODO: [🗯] Allow threads to be passed
15252
15632
  { role: 'user', content: rawPromptContent },
15253
15633
  ],
15254
15634
  },
@@ -15351,7 +15731,7 @@ var OpenAiAssistantExecutionTools = /** @class */ (function (_super) {
15351
15731
  * @public exported from `@promptbook/openai`
15352
15732
  */
15353
15733
  var createOpenAiAssistantExecutionTools = Object.assign(function (options) {
15354
- // TODO: [🧠][main] !!!! If browser, auto add `dangerouslyAllowBrowser`
15734
+ // TODO: [🧠][main] !!4 If browser, auto add `dangerouslyAllowBrowser`
15355
15735
  if (($isRunningInBrowser() || $isRunningInWebWorker()) && !options.dangerouslyAllowBrowser) {
15356
15736
  options = __assign(__assign({}, options), { dangerouslyAllowBrowser: true });
15357
15737
  }
@@ -15371,7 +15751,7 @@ var createOpenAiAssistantExecutionTools = Object.assign(function (options) {
15371
15751
  * @public exported from `@promptbook/openai`
15372
15752
  */
15373
15753
  var createOpenAiExecutionTools = Object.assign(function (options) {
15374
- // TODO: [🧠][main] !!!! If browser, auto add `dangerouslyAllowBrowser`
15754
+ // TODO: [🧠][main] !!4 If browser, auto add `dangerouslyAllowBrowser`
15375
15755
  if (($isRunningInBrowser() || $isRunningInWebWorker()) && !options.dangerouslyAllowBrowser) {
15376
15756
  options = __assign(__assign({}, options), { dangerouslyAllowBrowser: true });
15377
15757
  }
@@ -15391,6 +15771,7 @@ var createOpenAiExecutionTools = Object.assign(function (options) {
15391
15771
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available LLM tools
15392
15772
  *
15393
15773
  * @public exported from `@promptbook/openai`
15774
+ * @public exported from `@promptbook/wizzard`
15394
15775
  * @public exported from `@promptbook/cli`
15395
15776
  */
15396
15777
  var _OpenAiRegistration = $llmToolsRegister.register(createOpenAiExecutionTools);
@@ -15400,6 +15781,7 @@ var _OpenAiRegistration = $llmToolsRegister.register(createOpenAiExecutionTools)
15400
15781
  * Note: [🏐] Configurations registrations are done in @@@ BUT constructor @@@
15401
15782
  *
15402
15783
  * @public exported from `@promptbook/openai`
15784
+ * @public exported from `@promptbook/wizzard`
15403
15785
  * @public exported from `@promptbook/cli`
15404
15786
  */
15405
15787
  var _OpenAiAssistantRegistration = $llmToolsRegister.register(createOpenAiAssistantExecutionTools);
@@ -15653,6 +16035,7 @@ var markdownScraperMetadata = $deepFreeze({
15653
16035
  mimeTypes: ['text/markdown', 'text/plain'],
15654
16036
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
15655
16037
  isAvilableInBrowser: true,
16038
+ // <- 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
15656
16039
  requiredExecutables: [],
15657
16040
  }); /* <- Note: [🤛] */
15658
16041
  /**
@@ -15661,6 +16044,7 @@ var markdownScraperMetadata = $deepFreeze({
15661
16044
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
15662
16045
  *
15663
16046
  * @public exported from `@promptbook/core`
16047
+ * @public exported from `@promptbook/wizzard`
15664
16048
  * @public exported from `@promptbook/cli`
15665
16049
  */
15666
16050
  var _MarkdownScraperMetadataRegistration = $scrapersMetadataRegister.register(markdownScraperMetadata);
@@ -15746,12 +16130,12 @@ var MarkdownScraper = /** @class */ (function () {
15746
16130
  outputParameters = result.outputParameters;
15747
16131
  knowledgePiecesRaw = outputParameters.knowledgePieces;
15748
16132
  knowledgeTextPieces = (knowledgePiecesRaw || '').split('\n---\n');
15749
- // <- TODO: [main] !! Smarter split and filter out empty pieces
16133
+ // <- TODO: [main] Smarter split and filter out empty pieces
15750
16134
  if (isVerbose) {
15751
16135
  console.info('knowledgeTextPieces:', knowledgeTextPieces);
15752
16136
  }
15753
16137
  return [4 /*yield*/, Promise.all(
15754
- // TODO: [🪂] !! Do not send all at once but in chunks
16138
+ // TODO: [🪂] Do not send all at once but in chunks
15755
16139
  knowledgeTextPieces.map(function (knowledgeTextPiece, i) { return __awaiter(_this, void 0, void 0, function () {
15756
16140
  var name, title, knowledgePieceContent, keywords, index, titleResult, _a, titleRaw, keywordsResult, _b, keywordsRaw, embeddingResult, error_1;
15757
16141
  return __generator(this, function (_c) {
@@ -15850,6 +16234,7 @@ var documentScraperMetadata = $deepFreeze({
15850
16234
  mimeTypes: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
15851
16235
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
15852
16236
  isAvilableInBrowser: false,
16237
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
15853
16238
  requiredExecutables: ['Pandoc'],
15854
16239
  }); /* <- Note: [🤛] */
15855
16240
  /**
@@ -15858,6 +16243,7 @@ var documentScraperMetadata = $deepFreeze({
15858
16243
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
15859
16244
  *
15860
16245
  * @public exported from `@promptbook/core`
16246
+ * @public exported from `@promptbook/wizzard`
15861
16247
  * @public exported from `@promptbook/cli`
15862
16248
  */
15863
16249
  var _DocumentScraperMetadataRegistration = $scrapersMetadataRegister.register(documentScraperMetadata);
@@ -16013,6 +16399,7 @@ var legacyDocumentScraperMetadata = $deepFreeze({
16013
16399
  mimeTypes: ['application/msword', 'text/rtf'],
16014
16400
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
16015
16401
  isAvilableInBrowser: false,
16402
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
16016
16403
  requiredExecutables: [
16017
16404
  'Pandoc',
16018
16405
  'LibreOffice',
@@ -16025,6 +16412,7 @@ var legacyDocumentScraperMetadata = $deepFreeze({
16025
16412
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16026
16413
  *
16027
16414
  * @public exported from `@promptbook/core`
16415
+ * @public exported from `@promptbook/wizzard`
16028
16416
  * @public exported from `@promptbook/cli`
16029
16417
  */
16030
16418
  var _LegacyDocumentScraperMetadataRegistration = $scrapersMetadataRegister.register(legacyDocumentScraperMetadata);
@@ -16195,6 +16583,7 @@ var createLegacyDocumentScraper = Object.assign(function (tools, options) {
16195
16583
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16196
16584
  *
16197
16585
  * @public exported from `@promptbook/legacy-documents`
16586
+ * @public exported from `@promptbook/wizzard`
16198
16587
  * @public exported from `@promptbook/cli`
16199
16588
  */
16200
16589
  var _LegacyDocumentScraperRegistration = $scrapersRegister.register(createLegacyDocumentScraper);
@@ -16221,6 +16610,7 @@ var createDocumentScraper = Object.assign(function (tools, options) {
16221
16610
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16222
16611
  *
16223
16612
  * @public exported from `@promptbook/documents`
16613
+ * @public exported from `@promptbook/wizzard`
16224
16614
  * @public exported from `@promptbook/cli`
16225
16615
  */
16226
16616
  var _DocumentScraperRegistration = $scrapersRegister.register(createDocumentScraper);
@@ -16247,6 +16637,7 @@ var createMarkdownScraper = Object.assign(function (tools, options) {
16247
16637
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16248
16638
  *
16249
16639
  * @public exported from `@promptbook/markdown-utils`
16640
+ * @public exported from `@promptbook/wizzard`
16250
16641
  * @public exported from `@promptbook/cli`
16251
16642
  */
16252
16643
  var _MarkdownScraperRegistration = $scrapersRegister.register(createMarkdownScraper);
@@ -16266,7 +16657,8 @@ var pdfScraperMetadata = $deepFreeze({
16266
16657
  className: 'PdfScraper',
16267
16658
  mimeTypes: ['application/pdf'],
16268
16659
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
16269
- isAvilableInBrowser: true,
16660
+ isAvilableInBrowser: false,
16661
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
16270
16662
  requiredExecutables: [],
16271
16663
  }); /* <- Note: [🤛] */
16272
16664
  /**
@@ -16275,6 +16667,7 @@ var pdfScraperMetadata = $deepFreeze({
16275
16667
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16276
16668
  *
16277
16669
  * @public exported from `@promptbook/core`
16670
+ * @public exported from `@promptbook/wizzard`
16278
16671
  * @public exported from `@promptbook/cli`
16279
16672
  */
16280
16673
  var _PdfScraperMetadataRegistration = $scrapersMetadataRegister.register(pdfScraperMetadata);
@@ -16339,6 +16732,7 @@ var PdfScraper = /** @class */ (function () {
16339
16732
  * TODO: [👣] Converted pdf documents can act as cached items - there is no need to run conversion each time
16340
16733
  * TODO: [🪂] Do it in parallel 11:11
16341
16734
  * Note: No need to aggregate usage here, it is done by intercepting the llmTools
16735
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
16342
16736
  */
16343
16737
 
16344
16738
  /**
@@ -16359,6 +16753,7 @@ var createPdfScraper = Object.assign(function (tools, options) {
16359
16753
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16360
16754
  *
16361
16755
  * @public exported from `@promptbook/pdf`
16756
+ * @public exported from `@promptbook/wizzard`
16362
16757
  * @public exported from `@promptbook/cli`
16363
16758
  */
16364
16759
  var _PdfScraperRegistration = $scrapersRegister.register(createPdfScraper);
@@ -16379,6 +16774,7 @@ var websiteScraperMetadata = $deepFreeze({
16379
16774
  mimeTypes: ['text/html'],
16380
16775
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
16381
16776
  isAvilableInBrowser: false,
16777
+ // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
16382
16778
  requiredExecutables: [],
16383
16779
  }); /* <- Note: [🤛] */
16384
16780
  /**
@@ -16387,6 +16783,7 @@ var websiteScraperMetadata = $deepFreeze({
16387
16783
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16388
16784
  *
16389
16785
  * @public exported from `@promptbook/core`
16786
+ * @public exported from `@promptbook/wizzard`
16390
16787
  * @public exported from `@promptbook/cli`
16391
16788
  */
16392
16789
  var _WebsiteScraperMetadataRegistration = $scrapersMetadataRegister.register(websiteScraperMetadata);
@@ -16560,6 +16957,7 @@ var createWebsiteScraper = Object.assign(function (tools, options) {
16560
16957
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
16561
16958
  *
16562
16959
  * @public exported from `@promptbook/website-crawler`
16960
+ * @public exported from `@promptbook/wizzard`
16563
16961
  * @public exported from `@promptbook/cli`
16564
16962
  */
16565
16963
  var _WebsiteScraperRegistration = $scrapersRegister.register(createWebsiteScraper);