@promptbook/node 0.72.0-6 → 0.72.0-7

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 (120) hide show
  1. package/README.md +6 -0
  2. package/esm/index.es.js +2427 -1362
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/browser.index.d.ts +1 -1
  5. package/esm/typings/src/_packages/core.index.d.ts +24 -10
  6. package/esm/typings/src/_packages/node.index.d.ts +6 -2
  7. package/esm/typings/src/_packages/types.index.d.ts +28 -20
  8. package/esm/typings/src/cli/cli-commands/about.d.ts +1 -1
  9. package/esm/typings/src/cli/cli-commands/hello.d.ts +2 -1
  10. package/esm/typings/src/cli/cli-commands/make.d.ts +1 -1
  11. package/esm/typings/src/cli/cli-commands/prettify.d.ts +2 -1
  12. package/esm/typings/src/cli/cli-commands/test-command.d.ts +13 -0
  13. package/esm/typings/src/cli/main.d.ts +1 -1
  14. package/esm/typings/src/cli/promptbookCli.d.ts +1 -1
  15. package/esm/typings/src/collection/constructors/createCollectionFromDirectory.d.ts +8 -5
  16. package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +1 -1
  17. package/esm/typings/src/commands/FOREACH/foreachCommandParser.d.ts +1 -1
  18. package/esm/typings/src/commands/FORMAT/formatCommandParser.d.ts +1 -1
  19. package/esm/typings/src/commands/JOKER/jokerCommandParser.d.ts +1 -1
  20. package/esm/typings/src/commands/KNOWLEDGE/knowledgeCommandParser.d.ts +1 -1
  21. package/esm/typings/src/commands/KNOWLEDGE/utils/sourceContentToName.d.ts +11 -0
  22. package/esm/typings/src/commands/KNOWLEDGE/utils/sourceContentToName.test.d.ts +4 -0
  23. package/esm/typings/src/commands/MODEL/modelCommandParser.d.ts +1 -1
  24. package/esm/typings/src/commands/PARAMETER/parameterCommandParser.d.ts +1 -1
  25. package/esm/typings/src/commands/PERSONA/personaCommandParser.d.ts +1 -1
  26. package/esm/typings/src/commands/POSTPROCESS/postprocessCommandParser.d.ts +1 -1
  27. package/esm/typings/src/commands/PROMPTBOOK_VERSION/promptbookVersionCommandParser.d.ts +1 -1
  28. package/esm/typings/src/commands/TEMPLATE/templateCommandParser.d.ts +1 -1
  29. package/esm/typings/src/commands/URL/urlCommandParser.d.ts +1 -1
  30. package/esm/typings/src/commands/X_ACTION/actionCommandParser.d.ts +1 -1
  31. package/esm/typings/src/commands/X_INSTRUMENT/instrumentCommandParser.d.ts +1 -1
  32. package/esm/typings/src/commands/_BOILERPLATE/boilerplateCommandParser.d.ts +1 -1
  33. package/esm/typings/src/config.d.ts +10 -0
  34. package/esm/typings/src/conversion/pipelineStringToJson.d.ts +2 -15
  35. package/esm/typings/src/conversion/validation/_importPipeline.d.ts +1 -1
  36. package/esm/typings/src/conversion/validation/validatePipeline.d.ts +5 -5
  37. package/esm/typings/src/{knowledge/dialogs → dialogs}/callback/CallbackInterfaceTools.d.ts +2 -2
  38. package/esm/typings/src/{knowledge/dialogs → dialogs}/callback/CallbackInterfaceToolsOptions.d.ts +2 -2
  39. package/esm/typings/src/{knowledge/dialogs → dialogs}/simple-prompt/SimplePromptInterfaceTools.d.ts +4 -4
  40. package/esm/typings/src/errors/KnowledgeScrapeError.d.ts +9 -0
  41. package/esm/typings/src/errors/MissingToolsError.d.ts +9 -0
  42. package/esm/typings/src/execution/ExecutionTools.d.ts +3 -3
  43. package/esm/typings/src/execution/createPipelineExecutor/00-CreatePipelineExecutorOptions.d.ts +5 -2
  44. package/esm/typings/src/execution/createPipelineExecutor/00-CreatePipelineExecutorSettings.d.ts +2 -13
  45. package/esm/typings/src/execution/createPipelineExecutor/00-createPipelineExecutor.d.ts +1 -1
  46. package/esm/typings/src/execution/createPipelineExecutor/10-executePipeline.d.ts +1 -1
  47. package/esm/typings/src/execution/translation/automatic-translate/translateMessages.d.ts +3 -0
  48. package/esm/typings/src/execution/utils/forEachAsync.d.ts +1 -0
  49. package/esm/typings/src/llm-providers/_common/createLlmToolsFromConfigurationFromEnv.d.ts +1 -1
  50. package/esm/typings/src/llm-providers/_common/createLlmToolsFromEnv.d.ts +1 -1
  51. package/esm/typings/src/llm-providers/_common/getLlmToolsForCli.d.ts +1 -1
  52. package/esm/typings/src/llm-providers/anthropic-claude/playground/playground.d.ts +1 -0
  53. package/esm/typings/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +6 -0
  54. package/esm/typings/src/llm-providers/azure-openai/playground/playground.d.ts +1 -0
  55. package/esm/typings/src/llm-providers/langtail/playground/playground.d.ts +3 -0
  56. package/esm/typings/src/llm-providers/multiple/playground/playground.d.ts +3 -0
  57. package/esm/typings/src/llm-providers/openai/playground/playground.d.ts +1 -0
  58. package/esm/typings/src/llm-providers/remote/playground/playground.d.ts +3 -0
  59. package/esm/typings/src/personas/preparePersona.d.ts +2 -2
  60. package/esm/typings/src/prepare/PrepareAndScrapeOptions.d.ts +67 -0
  61. package/esm/typings/src/prepare/preparePipeline.d.ts +2 -2
  62. package/esm/typings/src/prepare/prepareTemplates.d.ts +2 -2
  63. package/esm/typings/src/scrapers/_common/Converter.d.ts +28 -0
  64. package/esm/typings/src/scrapers/_common/Scraper.d.ts +71 -0
  65. package/esm/typings/src/scrapers/_common/ScraperIntermediateSource.d.ts +11 -0
  66. package/esm/typings/src/{knowledge/prepare-knowledge → scrapers}/_common/prepareKnowledgePieces.d.ts +4 -4
  67. package/esm/typings/src/scrapers/_common/utils/getScraperIntermediateSource.d.ts +33 -0
  68. package/esm/typings/src/scrapers/_common/utils/getScraperIntermediateSource.test.d.ts +4 -0
  69. package/esm/typings/src/scrapers/_common/utils/makeKnowledgeSourceHandler.d.ts +10 -0
  70. package/esm/typings/src/scrapers/document/documentScraper.d.ts +37 -0
  71. package/esm/typings/src/scrapers/document/documentScraper.test.d.ts +4 -0
  72. package/esm/typings/src/scrapers/document/playground/document-scraper-playground.d.ts +5 -0
  73. package/esm/typings/src/scrapers/document-legacy/legacyDocumentScraper.d.ts +37 -0
  74. package/esm/typings/src/scrapers/document-legacy/legacyDocumentScraper.test.d.ts +4 -0
  75. package/esm/typings/src/scrapers/document-legacy/playground/legacy-document-scraper-playground.d.ts +5 -0
  76. package/esm/typings/src/scrapers/index.d.ts +7 -0
  77. package/esm/typings/src/scrapers/markdown/markdownScraper.d.ts +29 -0
  78. package/esm/typings/src/scrapers/markdown/playground/markdown-scraper-playground.d.ts +5 -0
  79. package/esm/typings/src/scrapers/pdf/pdfScraper.d.ts +35 -0
  80. package/esm/typings/src/scrapers/pdf/playground/pdf-scraper-playground.d.ts +5 -0
  81. package/esm/typings/src/scrapers/website/playground/website-scraper-playground.d.ts +5 -0
  82. package/esm/typings/src/scrapers/website/utils/markdownConverter.d.ts +12 -0
  83. package/esm/typings/src/scrapers/website/websiteScraper.d.ts +43 -0
  84. package/esm/typings/src/storage/{files-storage/FilesStorage.d.ts → file-cache-storage/FileCacheStorage.d.ts} +5 -5
  85. package/esm/typings/src/storage/file-cache-storage/FileCacheStorageOptions.d.ts +10 -0
  86. package/esm/typings/src/storage/{files-storage → file-cache-storage}/utils/nameToSubfolderPath.d.ts +1 -1
  87. package/esm/typings/src/storage/file-cache-storage/utils/nameToSubfolderPath.test.d.ts +1 -0
  88. package/esm/typings/src/storage/local-storage/getLocalStorage.d.ts +1 -1
  89. package/esm/typings/src/storage/local-storage/getSessionStorage.d.ts +1 -1
  90. package/esm/typings/src/types/PipelineJson/KnowledgeSourceJson.d.ts +9 -2
  91. package/esm/typings/src/types/PipelineJson/PipelineJson.d.ts +2 -2
  92. package/esm/typings/src/types/typeAliases.d.ts +8 -11
  93. package/esm/typings/src/utils/execCommand/$execCommand.d.ts +14 -0
  94. package/esm/typings/src/utils/execCommand/$execCommands.d.ts +17 -0
  95. package/esm/typings/src/utils/execCommand/IExecCommandOptions.d.ts +23 -0
  96. package/esm/typings/src/utils/execCommand/execCommand.test.d.ts +1 -0
  97. package/esm/typings/src/utils/execCommand/execCommandNormalizeOptions.d.ts +10 -0
  98. package/esm/typings/src/utils/execCommand/execCommandNormalizeOptions.test.d.ts +1 -0
  99. package/esm/typings/src/utils/files/$isDirectoryExisting.d.ts +3 -3
  100. package/esm/typings/src/utils/files/$isFileExisting.d.ts +3 -3
  101. package/esm/typings/src/utils/files/$listAllFiles.d.ts +5 -4
  102. package/esm/typings/src/utils/files/extensionToMimeType.d.ts +8 -0
  103. package/esm/typings/src/utils/files/extensionToMimeType.test.d.ts +1 -0
  104. package/esm/typings/src/utils/files/getFileExtension.d.ts +8 -0
  105. package/esm/typings/src/utils/files/getFileExtension.test.d.ts +1 -0
  106. package/esm/typings/src/utils/validators/filePath/isValidFilePath.d.ts +2 -2
  107. package/package.json +6 -2
  108. package/umd/index.umd.js +2428 -1366
  109. package/umd/index.umd.js.map +1 -1
  110. package/esm/typings/src/knowledge/prepare-knowledge/_common/Scraper.d.ts +0 -37
  111. package/esm/typings/src/knowledge/prepare-knowledge/markdown/playground/markdown-knowledge-playground.d.ts +0 -2
  112. package/esm/typings/src/knowledge/prepare-knowledge/markdown/prepareKnowledgeFromMarkdown.d.ts +0 -14
  113. package/esm/typings/src/knowledge/prepare-knowledge/pdf/prepareKnowledgeFromPdf.d.ts +0 -15
  114. package/esm/typings/src/prepare/PrepareOptions.d.ts +0 -22
  115. package/esm/typings/src/storage/files-storage/FilesStorageOptions.d.ts +0 -10
  116. /package/esm/typings/src/{knowledge/dialogs → dialogs}/user-interface-execution-tools.test.d.ts +0 -0
  117. /package/esm/typings/src/{knowledge/prepare-knowledge → scrapers}/_common/prepareKnowledgePieces.test.d.ts +0 -0
  118. /package/esm/typings/src/{knowledge/prepare-knowledge/markdown/prepareKnowledgeFromMarkdown.test.d.ts → scrapers/markdown/markdownScraper.test.d.ts} +0 -0
  119. /package/esm/typings/src/{knowledge/prepare-knowledge/pdf/prepareKnowledgeFromPdf.test.d.ts → scrapers/website/utils/markdownConverter.test.d.ts} +0 -0
  120. /package/esm/typings/src/{storage/files-storage/utils/nameToSubfolderPath.test.d.ts → scrapers/website/websiteScraper.test.d.ts} +0 -0
package/esm/index.es.js CHANGED
@@ -1,21 +1,26 @@
1
1
  import colors from 'colors';
2
- import { stat, access, constants, readdir, readFile, writeFile, mkdir, unlink } from 'fs/promises';
3
- import { join as join$1, dirname } from 'path';
2
+ import { stat, access, constants, mkdir, rm, readFile, rmdir, rename, readdir, writeFile, unlink } from 'fs/promises';
3
+ import { basename, join, dirname } from 'path';
4
4
  import spaceTrim$1, { spaceTrim } from 'spacetrim';
5
5
  import { format } from 'prettier';
6
6
  import parserHtml from 'prettier/parser-html';
7
+ import { spawn } from 'child_process';
7
8
  import { forTime } from 'waitasecond';
8
- import { unparse, parse } from 'papaparse';
9
+ import { SHA256 } from 'crypto-js';
9
10
  import hexEncoder from 'crypto-js/enc-hex';
10
- import sha256 from 'crypto-js/sha256';
11
- import { join } from 'path/posix';
11
+ import { unparse, parse } from 'papaparse';
12
+ import { Readability } from '@mozilla/readability';
13
+ import { JSDOM } from 'jsdom';
14
+ import { Converter } from 'showdown';
15
+ import { lookup } from 'mime-types';
12
16
  import * as dotenv from 'dotenv';
17
+ import sha256 from 'crypto-js/sha256';
13
18
 
14
19
  // ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
15
20
  /**
16
21
  * The version of the Promptbook library
17
22
  */
18
- var PROMPTBOOK_VERSION = '0.72.0-5';
23
+ var PROMPTBOOK_VERSION = '0.72.0-6';
19
24
  // TODO: [main] !!!! List here all the versions and annotate + put into script
20
25
 
21
26
  /*! *****************************************************************************
@@ -381,6 +386,14 @@ var MAX_EXECUTION_ATTEMPTS = 3; // <- TODO: [🤹‍♂️]
381
386
  * @public exported from `@promptbook/core`
382
387
  */
383
388
  var MAX_FILENAME_LENGTH = 30;
389
+ /**
390
+ * Where to store the scrape cache
391
+ *
392
+ * Note: When the folder does not exist, it is created recursively
393
+ *
394
+ * @public exported from `@promptbook/core`
395
+ */
396
+ var SCRAPE_CACHE_DIRNAME = '/.promptbook/scrape-cache';
384
397
  /**
385
398
  * The name of the builded pipeline collection made by CLI `ptbk make` and for lookup in `createCollectionFromDirectory`
386
399
  *
@@ -700,6 +713,22 @@ function templateParameterJsonToString(templateParameterJson) {
700
713
  * TODO: [🧠] Should be in generated .ptbk.md file GENERATOR_WARNING
701
714
  */
702
715
 
716
+ /**
717
+ * This error indicates that the promptbook can not retrieve knowledge from external sources
718
+ *
719
+ * @public exported from `@promptbook/core`
720
+ */
721
+ var KnowledgeScrapeError = /** @class */ (function (_super) {
722
+ __extends(KnowledgeScrapeError, _super);
723
+ function KnowledgeScrapeError(message) {
724
+ var _this = _super.call(this, message) || this;
725
+ _this.name = 'KnowledgeScrapeError';
726
+ Object.setPrototypeOf(_this, KnowledgeScrapeError.prototype);
727
+ return _this;
728
+ }
729
+ return KnowledgeScrapeError;
730
+ }(Error));
731
+
703
732
  /**
704
733
  * Async version of Array.forEach
705
734
  *
@@ -707,6 +736,7 @@ function templateParameterJsonToString(templateParameterJson) {
707
736
  * @param options - Options for the function
708
737
  * @param callbackfunction - Function to call for each item
709
738
  * @public exported from `@promptbook/utils`
739
+ * @deprecated [🪂] Use queues instead
710
740
  */
711
741
  function forEachAsync(array, options, callbackfunction) {
712
742
  return __awaiter(this, void 0, void 0, function () {
@@ -776,1105 +806,1399 @@ function forEachAsync(array, options, callbackfunction) {
776
806
  }
777
807
 
778
808
  /**
779
- * Represents the usage with no resources consumed
780
- *
781
- * @public exported from `@promptbook/core`
782
- */
783
- var ZERO_USAGE = $deepFreeze({
784
- price: { value: 0 },
785
- input: {
786
- tokensCount: { value: 0 },
787
- charactersCount: { value: 0 },
788
- wordsCount: { value: 0 },
789
- sentencesCount: { value: 0 },
790
- linesCount: { value: 0 },
791
- paragraphsCount: { value: 0 },
792
- pagesCount: { value: 0 },
793
- },
794
- output: {
795
- tokensCount: { value: 0 },
796
- charactersCount: { value: 0 },
797
- wordsCount: { value: 0 },
798
- sentencesCount: { value: 0 },
799
- linesCount: { value: 0 },
800
- paragraphsCount: { value: 0 },
801
- pagesCount: { value: 0 },
802
- },
803
- });
804
- /**
805
- * Represents the usage with unknown resources consumed
806
- *
807
- * @public exported from `@promptbook/core`
808
- */
809
- $deepFreeze({
810
- price: { value: 0, isUncertain: true },
811
- input: {
812
- tokensCount: { value: 0, isUncertain: true },
813
- charactersCount: { value: 0, isUncertain: true },
814
- wordsCount: { value: 0, isUncertain: true },
815
- sentencesCount: { value: 0, isUncertain: true },
816
- linesCount: { value: 0, isUncertain: true },
817
- paragraphsCount: { value: 0, isUncertain: true },
818
- pagesCount: { value: 0, isUncertain: true },
819
- },
820
- output: {
821
- tokensCount: { value: 0, isUncertain: true },
822
- charactersCount: { value: 0, isUncertain: true },
823
- wordsCount: { value: 0, isUncertain: true },
824
- sentencesCount: { value: 0, isUncertain: true },
825
- linesCount: { value: 0, isUncertain: true },
826
- paragraphsCount: { value: 0, isUncertain: true },
827
- pagesCount: { value: 0, isUncertain: true },
828
- },
829
- });
830
-
831
- var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-from-markdown.ptbk.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-keywords.ptbk.md"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-title.ptbk.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.ptbk.md",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}],templates:[{templateType:"PROMPT_TEMPLATE",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Sample\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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-persona.ptbk.md"}];
832
-
833
- /**
834
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
809
+ * This error type indicates that some tools are missing for pipeline execution or preparation
835
810
  *
836
811
  * @public exported from `@promptbook/core`
837
812
  */
838
- var ParseError = /** @class */ (function (_super) {
839
- __extends(ParseError, _super);
840
- function ParseError(message) {
841
- var _this = _super.call(this, message) || this;
842
- _this.name = 'ParseError';
843
- Object.setPrototypeOf(_this, ParseError.prototype);
813
+ var MissingToolsError = /** @class */ (function (_super) {
814
+ __extends(MissingToolsError, _super);
815
+ function MissingToolsError(message) {
816
+ var _this = _super.call(this, spaceTrim(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;
817
+ _this.name = 'MissingToolsError';
818
+ Object.setPrototypeOf(_this, MissingToolsError.prototype);
844
819
  return _this;
845
820
  }
846
- return ParseError;
821
+ return MissingToolsError;
847
822
  }(Error));
823
+
848
824
  /**
849
- * TODO: Maybe split `ParseError` and `ApplyError`
825
+ * Detects if the code is running in a Node.js environment
826
+ *
827
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
828
+ *
829
+ * @public exported from `@promptbook/utils`
850
830
  */
831
+ var $isRunningInNode = new Function("\n try {\n return this === global;\n } catch (e) {\n return false;\n }\n");
851
832
 
852
833
  /**
853
- * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
834
+ * This error type indicates that you try to use a feature that is not available in the current environment
854
835
  *
855
836
  * @public exported from `@promptbook/core`
856
837
  */
857
- var PipelineLogicError = /** @class */ (function (_super) {
858
- __extends(PipelineLogicError, _super);
859
- function PipelineLogicError(message) {
838
+ var EnvironmentMismatchError = /** @class */ (function (_super) {
839
+ __extends(EnvironmentMismatchError, _super);
840
+ function EnvironmentMismatchError(message) {
860
841
  var _this = _super.call(this, message) || this;
861
- _this.name = 'PipelineLogicError';
862
- Object.setPrototypeOf(_this, PipelineLogicError.prototype);
842
+ _this.name = 'EnvironmentMismatchError';
843
+ Object.setPrototypeOf(_this, EnvironmentMismatchError.prototype);
863
844
  return _this;
864
845
  }
865
- return PipelineLogicError;
846
+ return EnvironmentMismatchError;
866
847
  }(Error));
867
848
 
868
849
  /**
869
- * Tests if given string is valid semantic version
850
+ * Normalize options for `execCommand` and `execCommands`
870
851
  *
871
- * Note: There are two simmilar functions:
872
- * - `isValidSemanticVersion` which tests any semantic version
873
- * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
874
- *
875
- * @public exported from `@promptbook/utils`
852
+ * @private internal utility of `execCommand` and `execCommands`
876
853
  */
877
- function isValidSemanticVersion(version) {
878
- if (typeof version !== 'string') {
879
- return false;
854
+ function execCommandNormalizeOptions(options) {
855
+ var _a;
856
+ var _b, _c, _d;
857
+ var command;
858
+ var cwd;
859
+ var crashOnError;
860
+ var args = [];
861
+ var timeout;
862
+ if (typeof options === 'string') {
863
+ // TODO: [1] DRY default values
864
+ command = options;
865
+ cwd = process.cwd();
866
+ crashOnError = true;
867
+ timeout = Infinity;
880
868
  }
881
- if (version.startsWith('0.0.0')) {
882
- return false;
869
+ else {
870
+ /*
871
+ TODO:
872
+ if ((options as any).commands !== undefined) {
873
+ commands = (options as any).commands;
874
+ } else {
875
+ commands = [(options as any).command];
876
+ }
877
+ */
878
+ // TODO: [1] DRY default values
879
+ command = options.command;
880
+ cwd = (_b = options.cwd) !== null && _b !== void 0 ? _b : process.cwd();
881
+ crashOnError = (_c = options.crashOnError) !== null && _c !== void 0 ? _c : true;
882
+ timeout = (_d = options.timeout) !== null && _d !== void 0 ? _d : Infinity;
883
+ }
884
+ // TODO: /(-[a-zA-Z0-9-]+\s+[^\s]*)|[^\s]*/g
885
+ var _ = Array.from(command.matchAll(/(".*")|([^\s]*)/g))
886
+ .map(function (_a) {
887
+ var _b = __read(_a, 1), match = _b[0];
888
+ return match;
889
+ })
890
+ .filter(function (arg) { return arg !== ''; });
891
+ if (_.length > 1) {
892
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
893
+ _a = __read(_), command = _a[0], args = _a.slice(1);
883
894
  }
884
- return /^\d+\.\d+\.\d+(-\d+)?$/i.test(version);
885
- }
886
-
887
- /**
888
- * Tests if given string is valid promptbook version
889
- * It looks into list of known promptbook versions.
890
- *
891
- * @see https://www.npmjs.com/package/promptbook?activeTab=versions
892
- * Note: When you are using for example promptbook 2.0.0 and there already is promptbook 3.0.0 it don`t know about it.
893
- * Note: There are two simmilar functions:
894
- * - `isValidSemanticVersion` which tests any semantic version
895
- * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
896
- *
897
- * @public exported from `@promptbook/utils`
898
- */
899
- function isValidPromptbookVersion(version) {
900
- if (!isValidSemanticVersion(version)) {
901
- return false;
895
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
896
+ if (options.args) {
897
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
898
+ args = __spreadArray(__spreadArray([], __read(args), false), __read(options.args), false);
902
899
  }
903
- if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
904
- return false;
900
+ var humanReadableCommand = !['npx', 'npm'].includes(command) ? command : args[0];
901
+ if (['ts-node'].includes(humanReadableCommand)) {
902
+ humanReadableCommand += " ".concat(args[1]);
905
903
  }
906
- // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_VERSIONS
907
- return true;
904
+ return { command: command, humanReadableCommand: humanReadableCommand, args: args, cwd: cwd, crashOnError: crashOnError, timeout: timeout };
908
905
  }
906
+ // TODO: This should show type error> execCommandNormalizeOptions({ command: '', commands: [''] });
909
907
 
910
908
  /**
911
- * Checks if an URL is reserved for private networks or localhost.
909
+ * Run one command in a shell
912
910
  *
913
- * Note: There are two simmilar functions:
914
- * - `isUrlOnPrivateNetwork` which tests full URL
915
- * - `isHostnameOnPrivateNetwork` *(this one)* which tests just hostname
911
+ * Note: There are 2 similar functions in the codebase:
912
+ * - `$execCommand` which runs a single command
913
+ * - `$execCommands` which runs multiple commands
916
914
  *
917
- * @public exported from `@promptbook/utils`
915
+ * @public exported from `@promptbook/node`
918
916
  */
919
- function isHostnameOnPrivateNetwork(hostname) {
920
- if (hostname === 'example.com' ||
921
- hostname === 'localhost' ||
922
- hostname.endsWith('.localhost') ||
923
- hostname.endsWith('.local') ||
924
- hostname.endsWith('.test') ||
925
- hostname === '127.0.0.1' ||
926
- hostname === '::1') {
927
- return true;
928
- }
929
- if (hostname.includes(':')) {
930
- // IPv6
931
- var ipParts = hostname.split(':');
932
- return ipParts[0] === 'fc00' || ipParts[0] === 'fd00' || ipParts[0] === 'fe80';
933
- }
934
- else {
935
- // IPv4
936
- var ipParts = hostname.split('.').map(function (part) { return Number.parseInt(part, 10); });
937
- return (ipParts[0] === 10 ||
938
- (ipParts[0] === 172 && ipParts[1] >= 16 && ipParts[1] <= 31) ||
939
- (ipParts[0] === 192 && ipParts[1] === 168));
940
- }
917
+ function $execCommand(options) {
918
+ if (!$isRunningInNode()) {
919
+ throw new EnvironmentMismatchError('Function `$execCommand` can run only in Node environment.js');
920
+ }
921
+ return new Promise(
922
+ // <- TODO: [🧱] Implement in a functional (not new Class) way
923
+ function (resolve, reject) {
924
+ // eslint-disable-next-line prefer-const
925
+ var _a = execCommandNormalizeOptions(options), command = _a.command, humanReadableCommand = _a.humanReadableCommand, args = _a.args, cwd = _a.cwd, crashOnError = _a.crashOnError, timeout = _a.timeout;
926
+ if (timeout !== Infinity) {
927
+ // TODO: In waitasecond forTime(Infinity) should be equivalent to forEver()
928
+ forTime(timeout).then(function () {
929
+ if (crashOnError) {
930
+ reject(new Error("Command \"".concat(humanReadableCommand, "\" exceeded time limit of ").concat(timeout, "ms")));
931
+ }
932
+ else {
933
+ console.warn("Command \"".concat(humanReadableCommand, "\" exceeded time limit of ").concat(timeout, "ms but continues running"));
934
+ resolve('Command exceeded time limit');
935
+ }
936
+ });
937
+ }
938
+ if (/^win/.test(process.platform) && ['npm', 'npx'].includes(command)) {
939
+ command = "".concat(command, ".cmd");
940
+ }
941
+ // !!!!!! Verbose mode - to all consoles
942
+ console.info(colors.yellow(cwd) + ' ' + colors.green(command) + ' ' + colors.blue(args.join(' ')));
943
+ try {
944
+ var commandProcess = spawn(command, args, { cwd: cwd, shell: true });
945
+ commandProcess.on('message', function (message) {
946
+ console.info({ message: message });
947
+ });
948
+ var output_1 = [];
949
+ commandProcess.stdout.on('data', function (stdout) {
950
+ output_1.push(stdout.toString());
951
+ console.info(stdout.toString());
952
+ });
953
+ commandProcess.stderr.on('data', function (stderr) {
954
+ output_1.push(stderr.toString());
955
+ if (stderr.toString().trim()) {
956
+ console.warn(stderr.toString());
957
+ }
958
+ });
959
+ var finishWithCode = function (code) {
960
+ if (code !== 0) {
961
+ if (crashOnError) {
962
+ reject(new Error(output_1.join('\n').trim() ||
963
+ "Command \"".concat(humanReadableCommand, "\" exited with code ").concat(code)));
964
+ }
965
+ else {
966
+ console.warn("Command \"".concat(humanReadableCommand, "\" exited with code ").concat(code));
967
+ resolve(spaceTrim(output_1.join('\n')));
968
+ }
969
+ }
970
+ else {
971
+ resolve(spaceTrim(output_1.join('\n')));
972
+ }
973
+ };
974
+ commandProcess.on('close', finishWithCode);
975
+ commandProcess.on('exit', finishWithCode);
976
+ commandProcess.on('disconnect', function () {
977
+ // Note: Unexpected disconnection should always result in rejection
978
+ reject(new Error("Command \"".concat(humanReadableCommand, "\" disconnected")));
979
+ });
980
+ commandProcess.on('error', function (error) {
981
+ if (crashOnError) {
982
+ reject(new Error("Command \"".concat(humanReadableCommand, "\" failed: \n").concat(error.message)));
983
+ }
984
+ else {
985
+ console.warn(error);
986
+ resolve(spaceTrim(output_1.join('\n')));
987
+ }
988
+ });
989
+ }
990
+ catch (error) {
991
+ // Note: Unexpected error in sync code should always result in rejection
992
+ reject(error);
993
+ }
994
+ });
941
995
  }
996
+ /**
997
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
998
+ */
942
999
 
943
1000
  /**
944
- * Checks if an IP address or hostname is reserved for private networks or localhost.
1001
+ * Checks if the file exists
945
1002
  *
946
- * Note: There are two simmilar functions:
947
- * - `isUrlOnPrivateNetwork` *(this one)* which tests full URL
948
- * - `isHostnameOnPrivateNetwork` which tests just hostname
1003
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the filesystem
949
1004
  *
950
- * @param {string} ipAddress - The IP address to check.
951
- * @returns {boolean} Returns true if the IP address is reserved for private networks or localhost, otherwise false.
952
- * @public exported from `@promptbook/utils`
1005
+ * @private within the repository
953
1006
  */
954
- function isUrlOnPrivateNetwork(url) {
955
- if (typeof url === 'string') {
956
- url = new URL(url);
957
- }
958
- return isHostnameOnPrivateNetwork(url.hostname);
1007
+ function $isFileExisting(filename) {
1008
+ return __awaiter(this, void 0, void 0, function () {
1009
+ var isReadAccessAllowed, isFile;
1010
+ return __generator(this, function (_a) {
1011
+ switch (_a.label) {
1012
+ case 0:
1013
+ if (!$isRunningInNode()) {
1014
+ throw new EnvironmentMismatchError('Function `$isFileExisting` works only in Node environment.js');
1015
+ }
1016
+ return [4 /*yield*/, access(filename, constants.R_OK)
1017
+ .then(function () { return true; })
1018
+ .catch(function () { return false; })];
1019
+ case 1:
1020
+ isReadAccessAllowed = _a.sent();
1021
+ if (!isReadAccessAllowed) {
1022
+ return [2 /*return*/, false];
1023
+ }
1024
+ return [4 /*yield*/, stat(filename)
1025
+ .then(function (fileStat) { return fileStat.isFile(); })
1026
+ .catch(function () { return false; })];
1027
+ case 2:
1028
+ isFile = _a.sent();
1029
+ return [2 /*return*/, isFile];
1030
+ }
1031
+ });
1032
+ });
959
1033
  }
1034
+ /**
1035
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
1036
+ * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
1037
+ * TODO: [🖇] What about symlinks?
1038
+ */
960
1039
 
961
1040
  /**
962
- * Tests if given string is valid URL.
963
- *
964
- * Note: Dataurl are considered perfectly valid.
965
- * Note: There are two simmilar functions:
966
- * - `isValidUrl` which tests any URL
967
- * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
1041
+ * Get the file extension from a file name
968
1042
  *
969
- * @public exported from `@promptbook/utils`
1043
+ * @private within the repository
970
1044
  */
971
- function isValidUrl(url) {
972
- if (typeof url !== 'string') {
973
- return false;
974
- }
975
- try {
976
- if (url.startsWith('blob:')) {
977
- url = url.replace(/^blob:/, '');
978
- }
979
- var urlObject = new URL(url /* because fail is handled */);
980
- if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
981
- return false;
982
- }
983
- return true;
984
- }
985
- catch (error) {
986
- return false;
987
- }
1045
+ function getFileExtension(value) {
1046
+ var match = value.match(/\.([0-9a-z]+)(?:[?#]|$)/i);
1047
+ return match ? match[1].toLowerCase() : null;
988
1048
  }
989
1049
 
1050
+ var defaultDiacriticsRemovalMap = [
1051
+ {
1052
+ base: 'A',
1053
+ letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
1054
+ },
1055
+ { base: 'AA', letters: '\uA732' },
1056
+ { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
1057
+ { base: 'AO', letters: '\uA734' },
1058
+ { base: 'AU', letters: '\uA736' },
1059
+ { base: 'AV', letters: '\uA738\uA73A' },
1060
+ { base: 'AY', letters: '\uA73C' },
1061
+ {
1062
+ base: 'B',
1063
+ letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
1064
+ },
1065
+ {
1066
+ base: 'C',
1067
+ letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
1068
+ },
1069
+ {
1070
+ base: 'D',
1071
+ letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0',
1072
+ },
1073
+ { base: 'DZ', letters: '\u01F1\u01C4' },
1074
+ { base: 'Dz', letters: '\u01F2\u01C5' },
1075
+ {
1076
+ base: 'E',
1077
+ letters: '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E',
1078
+ },
1079
+ { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
1080
+ {
1081
+ base: 'G',
1082
+ letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
1083
+ },
1084
+ {
1085
+ base: 'H',
1086
+ letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
1087
+ },
1088
+ {
1089
+ base: 'I',
1090
+ letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
1091
+ },
1092
+ { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
1093
+ {
1094
+ base: 'K',
1095
+ letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
1096
+ },
1097
+ {
1098
+ base: 'L',
1099
+ letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
1100
+ },
1101
+ { base: 'LJ', letters: '\u01C7' },
1102
+ { base: 'Lj', letters: '\u01C8' },
1103
+ { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
1104
+ {
1105
+ base: 'N',
1106
+ letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
1107
+ },
1108
+ { base: 'NJ', letters: '\u01CA' },
1109
+ { base: 'Nj', letters: '\u01CB' },
1110
+ {
1111
+ base: 'O',
1112
+ letters: '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C',
1113
+ },
1114
+ { base: 'OI', letters: '\u01A2' },
1115
+ { base: 'OO', letters: '\uA74E' },
1116
+ { base: 'OU', letters: '\u0222' },
1117
+ { base: 'OE', letters: '\u008C\u0152' },
1118
+ { base: 'oe', letters: '\u009C\u0153' },
1119
+ {
1120
+ base: 'P',
1121
+ letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
1122
+ },
1123
+ { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
1124
+ {
1125
+ base: 'R',
1126
+ letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
1127
+ },
1128
+ {
1129
+ base: 'S',
1130
+ letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
1131
+ },
1132
+ {
1133
+ base: 'T',
1134
+ letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
1135
+ },
1136
+ { base: 'TZ', letters: '\uA728' },
1137
+ {
1138
+ base: 'U',
1139
+ letters: '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244',
1140
+ },
1141
+ { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
1142
+ { base: 'VY', letters: '\uA760' },
1143
+ {
1144
+ base: 'W',
1145
+ letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
1146
+ },
1147
+ { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
1148
+ {
1149
+ base: 'Y',
1150
+ letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
1151
+ },
1152
+ {
1153
+ base: 'Z',
1154
+ letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
1155
+ },
1156
+ {
1157
+ base: 'a',
1158
+ letters: '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250',
1159
+ },
1160
+ { base: 'aa', letters: '\uA733' },
1161
+ { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
1162
+ { base: 'ao', letters: '\uA735' },
1163
+ { base: 'au', letters: '\uA737' },
1164
+ { base: 'av', letters: '\uA739\uA73B' },
1165
+ { base: 'ay', letters: '\uA73D' },
1166
+ {
1167
+ base: 'b',
1168
+ letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
1169
+ },
1170
+ {
1171
+ base: 'c',
1172
+ letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
1173
+ },
1174
+ {
1175
+ base: 'd',
1176
+ letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
1177
+ },
1178
+ { base: 'dz', letters: '\u01F3\u01C6' },
1179
+ {
1180
+ base: 'e',
1181
+ letters: '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD',
1182
+ },
1183
+ { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
1184
+ {
1185
+ base: 'g',
1186
+ letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
1187
+ },
1188
+ {
1189
+ base: 'h',
1190
+ letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
1191
+ },
1192
+ { base: 'hv', letters: '\u0195' },
1193
+ {
1194
+ base: 'i',
1195
+ letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
1196
+ },
1197
+ { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
1198
+ {
1199
+ base: 'k',
1200
+ letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
1201
+ },
1202
+ {
1203
+ base: 'l',
1204
+ letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
1205
+ },
1206
+ { base: 'lj', letters: '\u01C9' },
1207
+ { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
1208
+ {
1209
+ base: 'n',
1210
+ letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
1211
+ },
1212
+ { base: 'nj', letters: '\u01CC' },
1213
+ {
1214
+ base: 'o',
1215
+ letters: '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275',
1216
+ },
1217
+ { base: 'oi', letters: '\u01A3' },
1218
+ { base: 'ou', letters: '\u0223' },
1219
+ { base: 'oo', letters: '\uA74F' },
1220
+ {
1221
+ base: 'p',
1222
+ letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
1223
+ },
1224
+ { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
1225
+ {
1226
+ base: 'r',
1227
+ letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
1228
+ },
1229
+ {
1230
+ base: 's',
1231
+ letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
1232
+ },
1233
+ {
1234
+ base: 't',
1235
+ letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
1236
+ },
1237
+ { base: 'tz', letters: '\uA729' },
1238
+ {
1239
+ base: 'u',
1240
+ letters: '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289',
1241
+ },
1242
+ { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
1243
+ { base: 'vy', letters: '\uA761' },
1244
+ {
1245
+ base: 'w',
1246
+ letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
1247
+ },
1248
+ { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
1249
+ {
1250
+ base: 'y',
1251
+ letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
1252
+ },
1253
+ {
1254
+ base: 'z',
1255
+ letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
1256
+ },
1257
+ ];
990
1258
  /**
991
- * Tests if given string is valid pipeline URL URL.
1259
+ * Map of letters from diacritic variant to diacritless variant
1260
+ * Contains lowercase and uppercase separatelly
992
1261
  *
993
- * Note: There are two simmilar functions:
994
- * - `isValidUrl` which tests any URL
995
- * - `isValidPipelineUrl` *(this one)* which tests just pipeline URL
1262
+ * > "á" => "a"
1263
+ * > "ě" => "e"
1264
+ * > "Ă" => "A"
1265
+ * > ...
996
1266
  *
997
1267
  * @public exported from `@promptbook/utils`
998
1268
  */
999
- function isValidPipelineUrl(url) {
1000
- if (!isValidUrl(url)) {
1001
- return false;
1002
- }
1003
- if (!url.startsWith('https://')) {
1004
- return false;
1005
- }
1006
- if (!url.endsWith('.ptbk.md')) {
1007
- return false;
1008
- }
1009
- if (url.includes('#')) {
1010
- // TODO: [🐠]
1011
- return false;
1012
- }
1013
- if (isUrlOnPrivateNetwork(url)) {
1014
- return false;
1269
+ var DIACRITIC_VARIANTS_LETTERS = {};
1270
+ // tslint:disable-next-line: prefer-for-of
1271
+ for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
1272
+ var letters = defaultDiacriticsRemovalMap[i].letters;
1273
+ // tslint:disable-next-line: prefer-for-of
1274
+ for (var j = 0; j < letters.length; j++) {
1275
+ DIACRITIC_VARIANTS_LETTERS[letters[j]] = defaultDiacriticsRemovalMap[i].base;
1015
1276
  }
1016
- return true;
1017
1277
  }
1018
- /**
1019
- * TODO: [🐠] Maybe more info why the URL is invalid
1020
- */
1021
-
1022
- /**
1023
- * Validates PipelineJson if it is logically valid
1024
- *
1025
- * It checks:
1026
- * - if it has correct parameters dependency
1278
+ // <- TODO: [🍓] Put to maker function to save execution time if not needed
1279
+ /*
1280
+ @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
1281
+ Licensed under the Apache License, Version 2.0 (the "License");
1282
+ you may not use this file except in compliance with the License.
1283
+ You may obtain a copy of the License at
1284
+
1285
+ http://www.apache.org/licenses/LICENSE-2.0
1286
+
1287
+ Unless required by applicable law or agreed to in writing, software
1288
+ distributed under the License is distributed on an "AS IS" BASIS,
1289
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1290
+ See the License for the specific language governing permissions and
1291
+ limitations under the License.
1292
+ */
1293
+
1294
+ /**
1295
+ * @@@
1027
1296
  *
1028
- * It does NOT check:
1029
- * - if it is valid json
1030
- * - if it is meaningful
1297
+ * @param input @@@
1298
+ * @returns @@@
1299
+ * @public exported from `@promptbook/utils`
1300
+ */
1301
+ function removeDiacritics(input) {
1302
+ /*eslint no-control-regex: "off"*/
1303
+ return input.replace(/[^\u0000-\u007E]/g, function (a) {
1304
+ return DIACRITIC_VARIANTS_LETTERS[a] || a;
1305
+ });
1306
+ }
1307
+ /**
1308
+ * TODO: [Ж] Variant for cyrillic (and in general non-latin) letters
1309
+ */
1310
+
1311
+ /**
1312
+ * @@@
1031
1313
  *
1032
- * @param pipeline valid or invalid PipelineJson
1033
- * @returns the same pipeline if it is logically valid
1034
- * @throws {PipelineLogicError} on logical error in the pipeline
1035
- * @public exported from `@promptbook/core`
1314
+ * @param text @@@
1315
+ * @returns @@@
1316
+ * @example 'hello-world'
1317
+ * @example 'i-love-promptbook'
1318
+ * @public exported from `@promptbook/utils`
1036
1319
  */
1037
- function validatePipeline(pipeline) {
1038
- if (IS_PIPELINE_LOGIC_VALIDATED) {
1039
- validatePipelineCore(pipeline);
1320
+ function normalizeToKebabCase(text) {
1321
+ var e_1, _a;
1322
+ text = removeDiacritics(text);
1323
+ var charType;
1324
+ var lastCharType = 'OTHER';
1325
+ var normalizedName = '';
1326
+ try {
1327
+ for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
1328
+ var char = text_1_1.value;
1329
+ var normalizedChar = void 0;
1330
+ if (/^[a-z]$/.test(char)) {
1331
+ charType = 'LOWERCASE';
1332
+ normalizedChar = char;
1333
+ }
1334
+ else if (/^[A-Z]$/.test(char)) {
1335
+ charType = 'UPPERCASE';
1336
+ normalizedChar = char.toLowerCase();
1337
+ }
1338
+ else if (/^[0-9]$/.test(char)) {
1339
+ charType = 'NUMBER';
1340
+ normalizedChar = char;
1341
+ }
1342
+ else {
1343
+ charType = 'OTHER';
1344
+ normalizedChar = '-';
1345
+ }
1346
+ if (charType !== lastCharType &&
1347
+ !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
1348
+ !(lastCharType === 'NUMBER') &&
1349
+ !(charType === 'NUMBER')) {
1350
+ normalizedName += '-';
1351
+ }
1352
+ normalizedName += normalizedChar;
1353
+ lastCharType = charType;
1354
+ }
1040
1355
  }
1041
- else {
1356
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1357
+ finally {
1042
1358
  try {
1043
- validatePipelineCore(pipeline);
1044
- }
1045
- catch (error) {
1046
- if (!(error instanceof PipelineLogicError)) {
1047
- throw error;
1048
- }
1049
- console.error(spaceTrim(function (block) { return "\n Pipeline is not valid but logic errors are temporarily disabled via `IS_PIPELINE_LOGIC_VALIDATED`\n\n ".concat(block(error.message), "\n "); }));
1359
+ if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
1050
1360
  }
1361
+ finally { if (e_1) throw e_1.error; }
1051
1362
  }
1052
- return pipeline;
1363
+ normalizedName = normalizedName.split(/-+/g).join('-');
1364
+ normalizedName = normalizedName.split(/-?\/-?/g).join('/');
1365
+ normalizedName = normalizedName.replace(/^-/, '');
1366
+ normalizedName = normalizedName.replace(/-$/, '');
1367
+ return normalizedName;
1053
1368
  }
1369
+
1054
1370
  /**
1055
- * @private internal function for `validatePipeline`
1371
+ * Tests if given string is valid URL.
1372
+ *
1373
+ * Note: Dataurl are considered perfectly valid.
1374
+ * Note: There are two simmilar functions:
1375
+ * - `isValidUrl` which tests any URL
1376
+ * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
1377
+ *
1378
+ * @public exported from `@promptbook/utils`
1056
1379
  */
1057
- function validatePipelineCore(pipeline) {
1058
- // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
1059
- var e_1, _a, e_2, _b, e_3, _c;
1060
- var pipelineIdentification = (function () {
1061
- // Note: This is a 😐 implementation of [🚞]
1062
- var _ = [];
1063
- if (pipeline.sourceFile !== undefined) {
1064
- _.push("File: ".concat(pipeline.sourceFile));
1380
+ function isValidUrl(url) {
1381
+ if (typeof url !== 'string') {
1382
+ return false;
1383
+ }
1384
+ try {
1385
+ if (url.startsWith('blob:')) {
1386
+ url = url.replace(/^blob:/, '');
1065
1387
  }
1066
- if (pipeline.pipelineUrl !== undefined) {
1067
- _.push("Url: ".concat(pipeline.pipelineUrl));
1388
+ var urlObject = new URL(url /* because fail is handled */);
1389
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
1390
+ return false;
1068
1391
  }
1069
- return _.join('\n');
1070
- })();
1071
- if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1072
- // <- Note: [🚲]
1073
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Invalid promptbook URL \"".concat(pipeline.pipelineUrl, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1392
+ return true;
1074
1393
  }
1075
- if (pipeline.promptbookVersion !== undefined && !isValidPromptbookVersion(pipeline.promptbookVersion)) {
1076
- // <- Note: [🚲]
1077
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Invalid Promptbook Version \"".concat(pipeline.promptbookVersion, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1394
+ catch (error) {
1395
+ return false;
1078
1396
  }
1079
- // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1080
- if (!Array.isArray(pipeline.parameters)) {
1081
- // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1082
- throw new ParseError(spaceTrim(function (block) { return "\n Pipeline is valid JSON but with wrong structure\n\n `PipelineJson.parameters` expected to be an array, but got ".concat(typeof pipeline.parameters, "\n\n ").concat(block(pipelineIdentification), "\n "); }));
1397
+ }
1398
+
1399
+ /**
1400
+ * Removes emojis from a string and fix whitespaces
1401
+ *
1402
+ * @param text with emojis
1403
+ * @returns text without emojis
1404
+ * @public exported from `@promptbook/utils`
1405
+ */
1406
+ function removeEmojis(text) {
1407
+ // Replace emojis (and also ZWJ sequence) with hyphens
1408
+ text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1409
+ text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1410
+ text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1411
+ text = text.replace(/\p{Extended_Pictographic}/gu, '');
1412
+ return text;
1413
+ }
1414
+
1415
+ /**
1416
+ * Tests if given string is valid URL.
1417
+ *
1418
+ * Note: This does not check if the file exists only if the path is valid
1419
+ * @public exported from `@promptbook/utils`
1420
+ */
1421
+ function isValidFilePath(filename) {
1422
+ if (typeof filename !== 'string') {
1423
+ return false;
1083
1424
  }
1084
- // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1085
- if (!Array.isArray(pipeline.templates)) {
1086
- // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1087
- throw new ParseError(spaceTrim(function (block) { return "\n Pipeline is valid JSON but with wrong structure\n\n `PipelineJson.templates` expected to be an array, but got ".concat(typeof pipeline.templates, "\n\n ").concat(block(pipelineIdentification), "\n "); }));
1425
+ var filenameSlashes = filename.split('\\').join('/');
1426
+ // Absolute Unix path: /hello.txt
1427
+ if (/^(\/)/i.test(filenameSlashes)) {
1428
+ return true;
1088
1429
  }
1089
- var _loop_1 = function (parameter) {
1090
- if (parameter.isInput && parameter.isOutput) {
1091
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n\n Parameter {".concat(parameter.name, "} can not be both input and output\n\n ").concat(block(pipelineIdentification), "\n "); }));
1092
- }
1093
- // Note: Testing that parameter is either intermediate or output BUT not created and unused
1094
- if (!parameter.isInput &&
1095
- !parameter.isOutput &&
1096
- !pipeline.templates.some(function (template) { return template.dependentParameterNames.includes(parameter.name); })) {
1097
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(parameter.name, "} is created but not used\n\n You can declare {").concat(parameter.name, "} as output parameter by adding in the header:\n - OUTPUT PARAMETER `{").concat(parameter.name, "}` ").concat(parameter.description || '', "\n\n ").concat(block(pipelineIdentification), "\n\n "); }));
1098
- }
1099
- // Note: Testing that parameter is either input or result of some template
1100
- if (!parameter.isInput &&
1101
- !pipeline.templates.some(function (template) { return template.resultingParameterName === parameter.name; })) {
1102
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(parameter.name, "} is declared but not defined\n\n You can do one of these:\n 1) Remove declaration of {").concat(parameter.name, "}\n 2) Add template that results in -> {").concat(parameter.name, "}\n\n ").concat(block(pipelineIdentification), "\n "); }));
1103
- }
1104
- };
1105
- try {
1106
- // Note: Check each parameter individually
1107
- for (var _d = __values(pipeline.parameters), _e = _d.next(); !_e.done; _e = _d.next()) {
1108
- var parameter = _e.value;
1109
- _loop_1(parameter);
1110
- }
1430
+ // Absolute Windows path: /hello.txt
1431
+ if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
1432
+ return true;
1111
1433
  }
1112
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1113
- finally {
1114
- try {
1115
- if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
1116
- }
1117
- finally { if (e_1) throw e_1.error; }
1434
+ // Relative path: ./hello.txt
1435
+ if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
1436
+ return true;
1118
1437
  }
1119
- // Note: All input parameters are defined - so that they can be used as result of some template
1120
- var definedParameters = new Set(pipeline.parameters.filter(function (_a) {
1121
- var isInput = _a.isInput;
1122
- return isInput;
1123
- }).map(function (_a) {
1124
- var name = _a.name;
1125
- return name;
1126
- }));
1127
- var _loop_2 = function (template) {
1128
- var e_4, _h, e_5, _j;
1129
- if (definedParameters.has(template.resultingParameterName)) {
1130
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(template.resultingParameterName, "} is defined multiple times\n\n ").concat(block(pipelineIdentification), "\n "); }));
1131
- }
1132
- if (RESERVED_PARAMETER_NAMES.includes(template.resultingParameterName)) {
1133
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter name {".concat(template.resultingParameterName, "} is reserved, please use different name\n\n ").concat(block(pipelineIdentification), "\n "); }));
1134
- }
1135
- definedParameters.add(template.resultingParameterName);
1136
- if (template.jokerParameterNames && template.jokerParameterNames.length > 0) {
1137
- if (!template.format &&
1138
- !template.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1139
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Joker parameters are used for {".concat(template.resultingParameterName, "} but no expectations are defined\n\n ").concat(block(pipelineIdentification), "\n "); }));
1140
- }
1141
- var _loop_4 = function (joker) {
1142
- if (!template.dependentParameterNames.includes(joker)) {
1143
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(joker, "} is used for {").concat(template.resultingParameterName, "} as joker but not in `dependentParameterNames`\n\n ").concat(block(pipelineIdentification), "\n "); }));
1144
- }
1145
- };
1146
- try {
1147
- for (var _k = (e_4 = void 0, __values(template.jokerParameterNames)), _l = _k.next(); !_l.done; _l = _k.next()) {
1148
- var joker = _l.value;
1149
- _loop_4(joker);
1150
- }
1151
- }
1152
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1153
- finally {
1154
- try {
1155
- if (_l && !_l.done && (_h = _k.return)) _h.call(_k);
1156
- }
1157
- finally { if (e_4) throw e_4.error; }
1158
- }
1159
- }
1160
- if (template.expectations) {
1161
- var _loop_5 = function (unit, min, max) {
1162
- if (min !== undefined && max !== undefined && min > max) {
1163
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Min expectation (=".concat(min, ") of ").concat(unit, " is higher than max expectation (=").concat(max, ")\n\n ").concat(block(pipelineIdentification), "\n "); }));
1164
- }
1165
- if (min !== undefined && min < 0) {
1166
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Min expectation of ".concat(unit, " must be zero or positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1167
- }
1168
- if (max !== undefined && max <= 0) {
1169
- throw new PipelineLogicError(spaceTrim(function (block) { return "\n Max expectation of ".concat(unit, " must be positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1170
- }
1171
- };
1172
- try {
1173
- for (var _m = (e_5 = void 0, __values(Object.entries(template.expectations))), _o = _m.next(); !_o.done; _o = _m.next()) {
1174
- var _p = __read(_o.value, 2), unit = _p[0], _q = _p[1], min = _q.min, max = _q.max;
1175
- _loop_5(unit, min, max);
1176
- }
1177
- }
1178
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
1179
- finally {
1180
- try {
1181
- if (_o && !_o.done && (_j = _m.return)) _j.call(_m);
1182
- }
1183
- finally { if (e_5) throw e_5.error; }
1184
- }
1185
- }
1186
- };
1187
- try {
1188
- // Note: Checking each template individually
1189
- for (var _f = __values(pipeline.templates), _g = _f.next(); !_g.done; _g = _f.next()) {
1190
- var template = _g.value;
1191
- _loop_2(template);
1192
- }
1193
- }
1194
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
1195
- finally {
1196
- try {
1197
- if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
1198
- }
1199
- finally { if (e_2) throw e_2.error; }
1200
- }
1201
- // Note: Detect circular dependencies
1202
- var resovedParameters = pipeline.parameters
1203
- .filter(function (_a) {
1204
- var isInput = _a.isInput;
1205
- return isInput;
1206
- })
1207
- .map(function (_a) {
1208
- var name = _a.name;
1209
- return name;
1210
- });
1211
- try {
1212
- // Note: All reserved parameters are resolved
1213
- for (var RESERVED_PARAMETER_NAMES_1 = __values(RESERVED_PARAMETER_NAMES), RESERVED_PARAMETER_NAMES_1_1 = RESERVED_PARAMETER_NAMES_1.next(); !RESERVED_PARAMETER_NAMES_1_1.done; RESERVED_PARAMETER_NAMES_1_1 = RESERVED_PARAMETER_NAMES_1.next()) {
1214
- var reservedParameterName = RESERVED_PARAMETER_NAMES_1_1.value;
1215
- resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), [reservedParameterName], false);
1216
- }
1438
+ return false;
1439
+ }
1440
+
1441
+ /**
1442
+ * @@@
1443
+ *
1444
+ * @param value @@@
1445
+ * @returns @@@
1446
+ * @example @@@
1447
+ * @public exported from `@promptbook/utils`
1448
+ */
1449
+ function titleToName(value) {
1450
+ if (isValidUrl(value)) {
1451
+ value = value.replace(/^https?:\/\//, '');
1452
+ value = value.replace(/\.html$/, '');
1217
1453
  }
1218
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
1219
- finally {
1220
- try {
1221
- if (RESERVED_PARAMETER_NAMES_1_1 && !RESERVED_PARAMETER_NAMES_1_1.done && (_c = RESERVED_PARAMETER_NAMES_1.return)) _c.call(RESERVED_PARAMETER_NAMES_1);
1222
- }
1223
- finally { if (e_3) throw e_3.error; }
1454
+ else if (isValidFilePath(value)) {
1455
+ value = basename(value);
1456
+ // Note: Keeping extension in the name
1224
1457
  }
1225
- var unresovedTemplates = __spreadArray([], __read(pipeline.templates), false);
1226
- var loopLimit = LOOP_LIMIT;
1227
- var _loop_3 = function () {
1228
- if (loopLimit-- < 0) {
1229
- // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1230
- throw new UnexpectedError(spaceTrim(function (block) { return "\n Loop limit reached during detection of circular dependencies in `validatePipeline`\n\n ".concat(block(pipelineIdentification), "\n "); }));
1231
- }
1232
- var currentlyResovedTemplates = unresovedTemplates.filter(function (template) {
1233
- return template.dependentParameterNames.every(function (name) { return resovedParameters.includes(name); });
1234
- });
1235
- if (currentlyResovedTemplates.length === 0) {
1236
- throw new PipelineLogicError(
1237
- // TODO: [🐎] DRY
1238
- spaceTrim(function (block) { return "\n\n Can not resolve some parameters:\n Either you are using a parameter that is not defined, or there are some circular dependencies.\n\n ".concat(block(pipelineIdentification), "\n\n Can not resolve:\n ").concat(block(unresovedTemplates
1239
- .map(function (_a) {
1240
- var resultingParameterName = _a.resultingParameterName, dependentParameterNames = _a.dependentParameterNames;
1241
- return "- Parameter {".concat(resultingParameterName, "} which depends on ").concat(dependentParameterNames
1242
- .map(function (dependentParameterName) { return "{".concat(dependentParameterName, "}"); })
1243
- .join(' and '));
1244
- })
1245
- .join('\n')), "\n\n Resolved:\n ").concat(block(resovedParameters.map(function (name) { return "- Parameter {".concat(name, "}"); }).join('\n')), "\n\n\n "); }));
1246
- }
1247
- resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), __read(currentlyResovedTemplates.map(function (_a) {
1248
- var resultingParameterName = _a.resultingParameterName;
1249
- return resultingParameterName;
1250
- })), false);
1251
- unresovedTemplates = unresovedTemplates.filter(function (template) { return !currentlyResovedTemplates.includes(template); });
1252
- };
1253
- while (unresovedTemplates.length > 0) {
1254
- _loop_3();
1458
+ value = value.split('/').join('-');
1459
+ value = removeEmojis(value);
1460
+ value = normalizeToKebabCase(value);
1461
+ // TODO: [🧠] Maybe warn or add some padding to short name which are not good identifiers
1462
+ return value;
1463
+ }
1464
+
1465
+ /**
1466
+ * @@@
1467
+ *
1468
+ * @private for `FileCacheStorage`
1469
+ */
1470
+ function nameToSubfolderPath(name) {
1471
+ return [name.substr(0, 1).toLowerCase(), name.substr(1, 1).toLowerCase()];
1472
+ }
1473
+
1474
+ /**
1475
+ * Just marks a place of place where should be something implemented
1476
+ * No side effects.
1477
+ *
1478
+ * Note: It can be usefull suppressing eslint errors of unused variables
1479
+ *
1480
+ * @param value any values
1481
+ * @returns void
1482
+ * @private within the repository
1483
+ */
1484
+ function TODO_USE() {
1485
+ var value = [];
1486
+ for (var _i = 0; _i < arguments.length; _i++) {
1487
+ value[_i] = arguments[_i];
1255
1488
  }
1256
1489
  }
1490
+
1257
1491
  /**
1258
- * TODO: !!!!! [🧞‍♀️] Do not allow joker + foreach
1259
- * TODO: [🧠] Work with promptbookVersion
1260
- * TODO: Use here some json-schema, Zod or something similar and change it to:
1261
- * > /**
1262
- * > * Validates PipelineJson if it is logically valid.
1263
- * > *
1264
- * > * It checks:
1265
- * > * - it has a valid structure
1266
- * > * - ...
1267
- * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
1492
+ * Create a filename for intermediate cache for scrapers
1493
+ *
1494
+ * Note: It also checks if directory exists and creates it if not
1495
+ *
1496
+ * @private as internal utility for scrapers
1268
1497
  */
1498
+ function getScraperIntermediateSource(source, options) {
1499
+ return __awaiter(this, void 0, void 0, function () {
1500
+ var sourceFilename, url, rootDirname, cacheDirname, isCacheCleaned, extension, isVerbose, hash, semanticName, pieces, name, cacheFilename, isDestroyed, fileHandler;
1501
+ return __generator(this, function (_a) {
1502
+ switch (_a.label) {
1503
+ case 0:
1504
+ sourceFilename = source.filename, url = source.url;
1505
+ rootDirname = options.rootDirname, cacheDirname = options.cacheDirname, isCacheCleaned = options.isCacheCleaned, extension = options.extension, isVerbose = options.isVerbose;
1506
+ hash = SHA256(
1507
+ // <- TODO: [🥬] Encapsulate sha256 to some private utility function
1508
+ hexEncoder.parse(sourceFilename || url || 'untitled'))
1509
+ .toString( /* hex */)
1510
+ .substring(0, 20);
1511
+ semanticName = normalizeToKebabCase(titleToName((sourceFilename || url || '').split('intermediate').join(''))).substring(0, 20);
1512
+ pieces = ['intermediate', semanticName, hash].filter(function (piece) { return piece !== ''; });
1513
+ name = pieces.join('-').split('--').join('-');
1514
+ // <- TODO: Use MAX_FILENAME_LENGTH
1515
+ TODO_USE(rootDirname); // <- TODO: !!!!!!
1516
+ cacheFilename = join.apply(void 0, __spreadArray(__spreadArray([process.cwd(),
1517
+ cacheDirname], __read(nameToSubfolderPath(hash /* <- TODO: [🎎] Maybe add some SHA256 prefix */)), false), [name], false)).split('\\')
1518
+ .join('/') +
1519
+ '.' +
1520
+ extension;
1521
+ return [4 /*yield*/, mkdir(dirname(cacheFilename), { recursive: true })];
1522
+ case 1:
1523
+ _a.sent();
1524
+ isDestroyed = true;
1525
+ fileHandler = {
1526
+ filename: cacheFilename,
1527
+ get isDestroyed() {
1528
+ return isDestroyed;
1529
+ },
1530
+ destroy: function () {
1531
+ return __awaiter(this, void 0, void 0, function () {
1532
+ return __generator(this, function (_a) {
1533
+ switch (_a.label) {
1534
+ case 0:
1535
+ if (!isCacheCleaned) return [3 /*break*/, 2];
1536
+ if (isVerbose) {
1537
+ console.info('legacyDocumentScraper: Clening cache');
1538
+ }
1539
+ return [4 /*yield*/, rm(cacheFilename)];
1540
+ case 1:
1541
+ _a.sent();
1542
+ _a.label = 2;
1543
+ case 2:
1544
+ isDestroyed = true;
1545
+ return [2 /*return*/];
1546
+ }
1547
+ });
1548
+ });
1549
+ },
1550
+ };
1551
+ return [2 /*return*/, fileHandler];
1552
+ }
1553
+ });
1554
+ });
1555
+ }
1269
1556
  /**
1270
- * TODO: [🐣][main] !!!! Validate that all samples match expectations
1271
- * TODO: [🐣][🐝][main] !!!! Validate that knowledge is valid (non-void)
1272
- * TODO: [🐣][main] !!!! Validate that persona can be used only with CHAT variant
1273
- * TODO: [🐣][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1274
- * TODO: [🐣][main] !!!! Validate that reserved parameter is not used as joker
1275
- * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
1276
- * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
1557
+ * Note: Not using `FileCacheStorage` for two reasons:
1558
+ * 1) Need to store more than serialized JSONs
1559
+ * 2) Need to switch between a `rootDirname` and `cacheDirname` <- TODO: !!!!
1560
+ * TODO: [🐱‍🐉][🧠] Make some smart crop
1277
1561
  */
1278
1562
 
1563
+ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-from-markdown.ptbk.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-keywords.ptbk.md"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],templates:[{templateType:"PROMPT_TEMPLATE",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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-knowledge-title.ptbk.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.ptbk.md",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}],templates:[{templateType:"PROMPT_TEMPLATE",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Sample\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"]}],knowledgeSources:[],knowledgePieces:[],personas:[],preparations:[],sourceFile:"./promptbook-collection/prepare-persona.ptbk.md"}];
1564
+
1279
1565
  /**
1280
- * This error indicates that promptbook not found in the collection
1566
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
1281
1567
  *
1282
1568
  * @public exported from `@promptbook/core`
1283
1569
  */
1284
- var NotFoundError = /** @class */ (function (_super) {
1285
- __extends(NotFoundError, _super);
1286
- function NotFoundError(message) {
1570
+ var ParseError = /** @class */ (function (_super) {
1571
+ __extends(ParseError, _super);
1572
+ function ParseError(message) {
1287
1573
  var _this = _super.call(this, message) || this;
1288
- _this.name = 'NotFoundError';
1289
- Object.setPrototypeOf(_this, NotFoundError.prototype);
1574
+ _this.name = 'ParseError';
1575
+ Object.setPrototypeOf(_this, ParseError.prototype);
1290
1576
  return _this;
1291
1577
  }
1292
- return NotFoundError;
1578
+ return ParseError;
1293
1579
  }(Error));
1580
+ /**
1581
+ * TODO: Maybe split `ParseError` and `ApplyError`
1582
+ */
1294
1583
 
1295
1584
  /**
1296
- * This error indicates errors in referencing promptbooks between each other
1585
+ * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
1297
1586
  *
1298
1587
  * @public exported from `@promptbook/core`
1299
1588
  */
1300
- var PipelineUrlError = /** @class */ (function (_super) {
1301
- __extends(PipelineUrlError, _super);
1302
- function PipelineUrlError(message) {
1589
+ var PipelineLogicError = /** @class */ (function (_super) {
1590
+ __extends(PipelineLogicError, _super);
1591
+ function PipelineLogicError(message) {
1303
1592
  var _this = _super.call(this, message) || this;
1304
- _this.name = 'PipelineUrlError';
1305
- Object.setPrototypeOf(_this, PipelineUrlError.prototype);
1593
+ _this.name = 'PipelineLogicError';
1594
+ Object.setPrototypeOf(_this, PipelineLogicError.prototype);
1306
1595
  return _this;
1307
1596
  }
1308
- return PipelineUrlError;
1597
+ return PipelineLogicError;
1309
1598
  }(Error));
1310
1599
 
1311
1600
  /**
1312
- * Parses the template and returns the list of all parameter names
1601
+ * Tests if given string is valid semantic version
1602
+ *
1603
+ * Note: There are two simmilar functions:
1604
+ * - `isValidSemanticVersion` which tests any semantic version
1605
+ * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
1313
1606
  *
1314
- * @param template the template with parameters in {curly} braces
1315
- * @returns the list of parameter names
1316
1607
  * @public exported from `@promptbook/utils`
1317
1608
  */
1318
- function extractParameterNames(template) {
1319
- var e_1, _a;
1320
- var matches = template.matchAll(/{\w+}/g);
1321
- var parameterNames = new Set();
1322
- try {
1323
- for (var matches_1 = __values(matches), matches_1_1 = matches_1.next(); !matches_1_1.done; matches_1_1 = matches_1.next()) {
1324
- var match = matches_1_1.value;
1325
- var parameterName = match[0].slice(1, -1);
1326
- parameterNames.add(parameterName);
1327
- }
1609
+ function isValidSemanticVersion(version) {
1610
+ if (typeof version !== 'string') {
1611
+ return false;
1328
1612
  }
1329
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1330
- finally {
1331
- try {
1332
- if (matches_1_1 && !matches_1_1.done && (_a = matches_1.return)) _a.call(matches_1);
1333
- }
1334
- finally { if (e_1) throw e_1.error; }
1613
+ if (version.startsWith('0.0.0')) {
1614
+ return false;
1335
1615
  }
1336
- return parameterNames;
1616
+ return /^\d+\.\d+\.\d+(-\d+)?$/i.test(version);
1337
1617
  }
1338
1618
 
1339
1619
  /**
1340
- * Unprepare just strips the preparation data of the pipeline
1620
+ * Tests if given string is valid promptbook version
1621
+ * It looks into list of known promptbook versions.
1341
1622
  *
1342
- * @public exported from `@promptbook/core`
1343
- */
1344
- function unpreparePipeline(pipeline) {
1345
- var personas = pipeline.personas, knowledgeSources = pipeline.knowledgeSources, templates = pipeline.templates;
1346
- personas = personas.map(function (persona) { return (__assign(__assign({}, persona), { modelRequirements: undefined, preparationIds: undefined })); });
1347
- knowledgeSources = knowledgeSources.map(function (knowledgeSource) { return (__assign(__assign({}, knowledgeSource), { preparationIds: undefined })); });
1348
- templates = templates.map(function (template) {
1349
- var dependentParameterNames = template.dependentParameterNames;
1350
- var parameterNames = extractParameterNames(template.preparedContent || '');
1351
- dependentParameterNames = dependentParameterNames.filter(function (dependentParameterName) { return !parameterNames.has(dependentParameterName); });
1352
- var templateUnprepared = __assign(__assign({}, template), { dependentParameterNames: dependentParameterNames });
1353
- delete templateUnprepared.preparedContent;
1354
- return templateUnprepared;
1355
- });
1356
- return $asDeeplyFrozenSerializableJson('Unprepared PipelineJson', __assign(__assign({}, pipeline), { templates: templates, knowledgeSources: knowledgeSources, knowledgePieces: [], personas: personas, preparations: [] }));
1357
- }
1358
- /**
1359
- * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
1360
- * TODO: Write tests for `preparePipeline`
1361
- * TODO: [🍙] Make some standard order of json properties
1623
+ * @see https://www.npmjs.com/package/promptbook?activeTab=versions
1624
+ * Note: When you are using for example promptbook 2.0.0 and there already is promptbook 3.0.0 it don`t know about it.
1625
+ * Note: There are two simmilar functions:
1626
+ * - `isValidSemanticVersion` which tests any semantic version
1627
+ * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
1628
+ *
1629
+ * @public exported from `@promptbook/utils`
1362
1630
  */
1363
-
1364
- /**
1365
- * Library of pipelines that groups together pipelines for an application.
1366
- * This implementation is a very thin wrapper around the Array / Map of pipelines.
1631
+ function isValidPromptbookVersion(version) {
1632
+ if (!isValidSemanticVersion(version)) {
1633
+ return false;
1634
+ }
1635
+ if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
1636
+ return false;
1637
+ }
1638
+ // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_VERSIONS
1639
+ return true;
1640
+ }
1641
+
1642
+ /**
1643
+ * Checks if an URL is reserved for private networks or localhost.
1367
1644
  *
1368
- * @private internal function of `createCollectionFromJson`, use `createCollectionFromJson` instead
1369
- * @see https://github.com/webgptorg/pipeline#pipeline-collection
1645
+ * Note: There are two simmilar functions:
1646
+ * - `isUrlOnPrivateNetwork` which tests full URL
1647
+ * - `isHostnameOnPrivateNetwork` *(this one)* which tests just hostname
1648
+ *
1649
+ * @public exported from `@promptbook/utils`
1370
1650
  */
1371
- var SimplePipelineCollection = /** @class */ (function () {
1372
- /**
1373
- * Constructs a pipeline collection from pipelines
1374
- *
1375
- * @param pipelines @@@
1376
- *
1377
- * Note: During the construction logic of all pipelines are validated
1378
- * Note: It is not recommended to use this constructor directly, use `createCollectionFromJson` *(or other variant)* instead
1379
- */
1380
- function SimplePipelineCollection() {
1381
- var e_1, _a;
1382
- var pipelines = [];
1383
- for (var _i = 0; _i < arguments.length; _i++) {
1384
- pipelines[_i] = arguments[_i];
1385
- }
1386
- this.collection = new Map();
1387
- try {
1388
- for (var pipelines_1 = __values(pipelines), pipelines_1_1 = pipelines_1.next(); !pipelines_1_1.done; pipelines_1_1 = pipelines_1.next()) {
1389
- var pipeline = pipelines_1_1.value;
1390
- // TODO: [👠] DRY
1391
- if (pipeline.pipelineUrl === undefined) {
1392
- throw new PipelineUrlError(spaceTrim("\n Pipeline with name \"".concat(pipeline.title, "\" does not have defined URL\n\n File:\n ").concat(pipeline.sourceFile || 'Unknown', "\n\n Note: Pipelines without URLs are called anonymous pipelines\n They can be used as standalone pipelines, but they cannot be referenced by other pipelines\n And also they cannot be used in the pipeline collection\n\n ")));
1393
- }
1394
- // Note: [🐨]
1395
- validatePipeline(pipeline);
1396
- // TODO: [🦄] DRY
1397
- // Note: [🦄]
1398
- if (
1399
- // TODO: [🐽]
1400
- this.collection.has(pipeline.pipelineUrl) &&
1401
- pipelineJsonToString(unpreparePipeline(pipeline)) !==
1402
- pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
1403
- var existing = this.collection.get(pipeline.pipelineUrl);
1404
- throw new PipelineUrlError(spaceTrim("\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 ")));
1405
- }
1406
- // Note: [🧠] Overwrite existing pipeline with the same URL
1407
- this.collection.set(pipeline.pipelineUrl, pipeline);
1408
- }
1409
- }
1410
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1411
- finally {
1412
- try {
1413
- if (pipelines_1_1 && !pipelines_1_1.done && (_a = pipelines_1.return)) _a.call(pipelines_1);
1414
- }
1415
- finally { if (e_1) throw e_1.error; }
1416
- }
1417
- }
1418
- /**
1419
- * Gets all pipelines in the collection
1420
- */
1421
- SimplePipelineCollection.prototype.listPipelines = function () {
1422
- return Array.from(this.collection.keys());
1423
- };
1424
- /**
1425
- * Gets pipeline by its URL
1426
- *
1427
- * Note: This is not a direct fetching from the URL, but a lookup in the collection
1428
- */
1429
- SimplePipelineCollection.prototype.getPipelineByUrl = function (url) {
1430
- var _this = this;
1431
- var pipeline = this.collection.get(url);
1432
- if (!pipeline) {
1433
- if (this.listPipelines().length === 0) {
1434
- throw new NotFoundError(spaceTrim("\n Pipeline with url \"".concat(url, "\" not found\n\n No pipelines available\n ")));
1435
- }
1436
- throw new NotFoundError(spaceTrim(function (block) { return "\n Pipeline with url \"".concat(url, "\" not found\n\n Available pipelines:\n ").concat(block(_this.listPipelines()
1437
- .map(function (pipelineUrl) { return "- ".concat(pipelineUrl); })
1438
- .join('\n')), "\n\n "); }));
1439
- }
1440
- return pipeline;
1441
- };
1442
- /**
1443
- * Checks whether given prompt was defined in any pipeline in the collection
1444
- */
1445
- SimplePipelineCollection.prototype.isResponsibleForPrompt = function (prompt) {
1651
+ function isHostnameOnPrivateNetwork(hostname) {
1652
+ if (hostname === 'example.com' ||
1653
+ hostname === 'localhost' ||
1654
+ hostname.endsWith('.localhost') ||
1655
+ hostname.endsWith('.local') ||
1656
+ hostname.endsWith('.test') ||
1657
+ hostname === '127.0.0.1' ||
1658
+ hostname === '::1') {
1446
1659
  return true;
1447
- };
1448
- return SimplePipelineCollection;
1449
- }());
1660
+ }
1661
+ if (hostname.includes(':')) {
1662
+ // IPv6
1663
+ var ipParts = hostname.split(':');
1664
+ return ipParts[0] === 'fc00' || ipParts[0] === 'fd00' || ipParts[0] === 'fe80';
1665
+ }
1666
+ else {
1667
+ // IPv4
1668
+ var ipParts = hostname.split('.').map(function (part) { return Number.parseInt(part, 10); });
1669
+ return (ipParts[0] === 10 ||
1670
+ (ipParts[0] === 172 && ipParts[1] >= 16 && ipParts[1] <= 31) ||
1671
+ (ipParts[0] === 192 && ipParts[1] === 168));
1672
+ }
1673
+ }
1450
1674
 
1451
1675
  /**
1452
- * Creates PipelineCollection from array of PipelineJson or PipelineString
1676
+ * Checks if an IP address or hostname is reserved for private networks or localhost.
1453
1677
  *
1454
- * Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
1455
- * Note: Syntax, parsing, and logic consistency checks are performed on all sources during build
1678
+ * Note: There are two simmilar functions:
1679
+ * - `isUrlOnPrivateNetwork` *(this one)* which tests full URL
1680
+ * - `isHostnameOnPrivateNetwork` which tests just hostname
1456
1681
  *
1457
- * @param promptbookSources
1458
- * @returns PipelineCollection
1459
- * @public exported from `@promptbook/core`
1682
+ * @param {string} ipAddress - The IP address to check.
1683
+ * @returns {boolean} Returns true if the IP address is reserved for private networks or localhost, otherwise false.
1684
+ * @public exported from `@promptbook/utils`
1460
1685
  */
1461
- function createCollectionFromJson() {
1462
- var promptbooks = [];
1463
- for (var _i = 0; _i < arguments.length; _i++) {
1464
- promptbooks[_i] = arguments[_i];
1686
+ function isUrlOnPrivateNetwork(url) {
1687
+ if (typeof url === 'string') {
1688
+ url = new URL(url);
1465
1689
  }
1466
- return new (SimplePipelineCollection.bind.apply(SimplePipelineCollection, __spreadArray([void 0], __read(promptbooks), false)))();
1690
+ return isHostnameOnPrivateNetwork(url.hostname);
1467
1691
  }
1468
1692
 
1469
- var defaultDiacriticsRemovalMap = [
1470
- {
1471
- base: 'A',
1472
- letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
1473
- },
1474
- { base: 'AA', letters: '\uA732' },
1475
- { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
1476
- { base: 'AO', letters: '\uA734' },
1477
- { base: 'AU', letters: '\uA736' },
1478
- { base: 'AV', letters: '\uA738\uA73A' },
1479
- { base: 'AY', letters: '\uA73C' },
1480
- {
1481
- base: 'B',
1482
- letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
1483
- },
1484
- {
1485
- base: 'C',
1486
- letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
1487
- },
1488
- {
1489
- base: 'D',
1490
- letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0',
1491
- },
1492
- { base: 'DZ', letters: '\u01F1\u01C4' },
1493
- { base: 'Dz', letters: '\u01F2\u01C5' },
1494
- {
1495
- base: 'E',
1496
- letters: '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E',
1497
- },
1498
- { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
1499
- {
1500
- base: 'G',
1501
- letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
1502
- },
1503
- {
1504
- base: 'H',
1505
- letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
1506
- },
1507
- {
1508
- base: 'I',
1509
- letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
1510
- },
1511
- { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
1512
- {
1513
- base: 'K',
1514
- letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
1515
- },
1516
- {
1517
- base: 'L',
1518
- letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
1519
- },
1520
- { base: 'LJ', letters: '\u01C7' },
1521
- { base: 'Lj', letters: '\u01C8' },
1522
- { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
1523
- {
1524
- base: 'N',
1525
- letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
1526
- },
1527
- { base: 'NJ', letters: '\u01CA' },
1528
- { base: 'Nj', letters: '\u01CB' },
1529
- {
1530
- base: 'O',
1531
- letters: '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C',
1532
- },
1533
- { base: 'OI', letters: '\u01A2' },
1534
- { base: 'OO', letters: '\uA74E' },
1535
- { base: 'OU', letters: '\u0222' },
1536
- { base: 'OE', letters: '\u008C\u0152' },
1537
- { base: 'oe', letters: '\u009C\u0153' },
1538
- {
1539
- base: 'P',
1540
- letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
1541
- },
1542
- { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
1543
- {
1544
- base: 'R',
1545
- letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
1546
- },
1547
- {
1548
- base: 'S',
1549
- letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
1550
- },
1551
- {
1552
- base: 'T',
1553
- letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
1554
- },
1555
- { base: 'TZ', letters: '\uA728' },
1556
- {
1557
- base: 'U',
1558
- letters: '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244',
1559
- },
1560
- { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
1561
- { base: 'VY', letters: '\uA760' },
1562
- {
1563
- base: 'W',
1564
- letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
1565
- },
1566
- { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
1567
- {
1568
- base: 'Y',
1569
- letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
1570
- },
1571
- {
1572
- base: 'Z',
1573
- letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
1574
- },
1575
- {
1576
- base: 'a',
1577
- letters: '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250',
1578
- },
1579
- { base: 'aa', letters: '\uA733' },
1580
- { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
1581
- { base: 'ao', letters: '\uA735' },
1582
- { base: 'au', letters: '\uA737' },
1583
- { base: 'av', letters: '\uA739\uA73B' },
1584
- { base: 'ay', letters: '\uA73D' },
1585
- {
1586
- base: 'b',
1587
- letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
1588
- },
1589
- {
1590
- base: 'c',
1591
- letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
1592
- },
1593
- {
1594
- base: 'd',
1595
- letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
1596
- },
1597
- { base: 'dz', letters: '\u01F3\u01C6' },
1598
- {
1599
- base: 'e',
1600
- letters: '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD',
1601
- },
1602
- { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
1603
- {
1604
- base: 'g',
1605
- letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
1606
- },
1607
- {
1608
- base: 'h',
1609
- letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
1610
- },
1611
- { base: 'hv', letters: '\u0195' },
1612
- {
1613
- base: 'i',
1614
- letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
1615
- },
1616
- { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
1617
- {
1618
- base: 'k',
1619
- letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
1620
- },
1621
- {
1622
- base: 'l',
1623
- letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
1624
- },
1625
- { base: 'lj', letters: '\u01C9' },
1626
- { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
1627
- {
1628
- base: 'n',
1629
- letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
1630
- },
1631
- { base: 'nj', letters: '\u01CC' },
1632
- {
1633
- base: 'o',
1634
- letters: '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275',
1635
- },
1636
- { base: 'oi', letters: '\u01A3' },
1637
- { base: 'ou', letters: '\u0223' },
1638
- { base: 'oo', letters: '\uA74F' },
1639
- {
1640
- base: 'p',
1641
- letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
1642
- },
1643
- { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
1644
- {
1645
- base: 'r',
1646
- letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
1647
- },
1648
- {
1649
- base: 's',
1650
- letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
1651
- },
1652
- {
1653
- base: 't',
1654
- letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
1655
- },
1656
- { base: 'tz', letters: '\uA729' },
1657
- {
1658
- base: 'u',
1659
- letters: '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289',
1660
- },
1661
- { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
1662
- { base: 'vy', letters: '\uA761' },
1663
- {
1664
- base: 'w',
1665
- letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
1666
- },
1667
- { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
1668
- {
1669
- base: 'y',
1670
- letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
1671
- },
1672
- {
1673
- base: 'z',
1674
- letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
1675
- },
1676
- ];
1677
1693
  /**
1678
- * Map of letters from diacritic variant to diacritless variant
1679
- * Contains lowercase and uppercase separatelly
1694
+ * Tests if given string is valid pipeline URL URL.
1680
1695
  *
1681
- * > "á" => "a"
1682
- * > "ě" => "e"
1683
- * > "Ă" => "A"
1684
- * > ...
1696
+ * Note: There are two simmilar functions:
1697
+ * - `isValidUrl` which tests any URL
1698
+ * - `isValidPipelineUrl` *(this one)* which tests just pipeline URL
1685
1699
  *
1686
1700
  * @public exported from `@promptbook/utils`
1687
1701
  */
1688
- var DIACRITIC_VARIANTS_LETTERS = {};
1689
- // tslint:disable-next-line: prefer-for-of
1690
- for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
1691
- var letters = defaultDiacriticsRemovalMap[i].letters;
1692
- // tslint:disable-next-line: prefer-for-of
1693
- for (var j = 0; j < letters.length; j++) {
1694
- DIACRITIC_VARIANTS_LETTERS[letters[j]] = defaultDiacriticsRemovalMap[i].base;
1702
+ function isValidPipelineUrl(url) {
1703
+ if (!isValidUrl(url)) {
1704
+ return false;
1695
1705
  }
1696
- }
1697
- // <- TODO: [🍓] Put to maker function to save execution time if not needed
1698
- /*
1699
- @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
1700
- Licensed under the Apache License, Version 2.0 (the "License");
1701
- you may not use this file except in compliance with the License.
1702
- You may obtain a copy of the License at
1703
-
1704
- http://www.apache.org/licenses/LICENSE-2.0
1705
-
1706
- Unless required by applicable law or agreed to in writing, software
1707
- distributed under the License is distributed on an "AS IS" BASIS,
1708
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1709
- See the License for the specific language governing permissions and
1710
- limitations under the License.
1711
- */
1712
-
1713
- /**
1714
- * @@@
1715
- *
1716
- * @param input @@@
1717
- * @returns @@@
1718
- * @public exported from `@promptbook/utils`
1719
- */
1720
- function removeDiacritics(input) {
1721
- /*eslint no-control-regex: "off"*/
1722
- return input.replace(/[^\u0000-\u007E]/g, function (a) {
1723
- return DIACRITIC_VARIANTS_LETTERS[a] || a;
1724
- });
1706
+ if (!url.startsWith('https://')) {
1707
+ return false;
1708
+ }
1709
+ if (!url.endsWith('.ptbk.md')) {
1710
+ return false;
1711
+ }
1712
+ if (url.includes('#')) {
1713
+ // TODO: [🐠]
1714
+ return false;
1715
+ }
1716
+ if (isUrlOnPrivateNetwork(url)) {
1717
+ return false;
1718
+ }
1719
+ return true;
1725
1720
  }
1726
1721
  /**
1727
- * TODO: [Ж] Variant for cyrillic (and in general non-latin) letters
1722
+ * TODO: [🐠] Maybe more info why the URL is invalid
1728
1723
  */
1729
1724
 
1730
1725
  /**
1731
- * @@@
1726
+ * Validates PipelineJson if it is logically valid
1732
1727
  *
1733
- * @param text @@@
1734
- * @returns @@@
1735
- * @example 'hello-world'
1736
- * @example 'i-love-promptbook'
1737
- * @public exported from `@promptbook/utils`
1728
+ * It checks:
1729
+ * - if it has correct parameters dependency
1730
+ *
1731
+ * It does NOT check:
1732
+ * - if it is valid json
1733
+ * - if it is meaningful
1734
+ *
1735
+ * @param pipeline valid or invalid PipelineJson
1736
+ * @returns the same pipeline if it is logically valid
1737
+ * @throws {PipelineLogicError} on logical error in the pipeline
1738
+ * @public exported from `@promptbook/core`
1738
1739
  */
1739
- function normalizeToKebabCase(text) {
1740
- var e_1, _a;
1741
- text = removeDiacritics(text);
1742
- var charType;
1743
- var lastCharType = 'OTHER';
1744
- var normalizedName = '';
1745
- try {
1746
- for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
1747
- var char = text_1_1.value;
1748
- var normalizedChar = void 0;
1749
- if (/^[a-z]$/.test(char)) {
1750
- charType = 'LOWERCASE';
1751
- normalizedChar = char;
1752
- }
1753
- else if (/^[A-Z]$/.test(char)) {
1754
- charType = 'UPPERCASE';
1755
- normalizedChar = char.toLowerCase();
1756
- }
1757
- else if (/^[0-9]$/.test(char)) {
1758
- charType = 'NUMBER';
1759
- normalizedChar = char;
1760
- }
1761
- else if (/^\/$/.test(char)) {
1762
- charType = 'SLASH';
1763
- normalizedChar = char;
1764
- }
1765
- else {
1766
- charType = 'OTHER';
1767
- normalizedChar = '-';
1768
- }
1769
- if (charType !== lastCharType &&
1770
- !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
1771
- !(lastCharType === 'NUMBER') &&
1772
- !(charType === 'NUMBER')) {
1773
- normalizedName += '-';
1774
- }
1775
- normalizedName += normalizedChar;
1776
- lastCharType = charType;
1777
- }
1740
+ function validatePipeline(pipeline) {
1741
+ if (IS_PIPELINE_LOGIC_VALIDATED) {
1742
+ validatePipelineCore(pipeline);
1778
1743
  }
1779
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1780
- finally {
1744
+ else {
1781
1745
  try {
1782
- if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
1746
+ validatePipelineCore(pipeline);
1747
+ }
1748
+ catch (error) {
1749
+ if (!(error instanceof PipelineLogicError)) {
1750
+ throw error;
1751
+ }
1752
+ console.error(spaceTrim(function (block) { return "\n Pipeline is not valid but logic errors are temporarily disabled via `IS_PIPELINE_LOGIC_VALIDATED`\n\n ".concat(block(error.message), "\n "); }));
1783
1753
  }
1784
- finally { if (e_1) throw e_1.error; }
1785
1754
  }
1786
- normalizedName = normalizedName.split(/-+/g).join('-');
1787
- normalizedName = normalizedName.split(/-?\/-?/g).join('/');
1788
- normalizedName = normalizedName.replace(/^-/, '');
1789
- normalizedName = normalizedName.replace(/-$/, '');
1790
- return normalizedName;
1755
+ return pipeline;
1791
1756
  }
1792
-
1793
1757
  /**
1794
- * Removes emojis from a string and fix whitespaces
1795
- *
1796
- * @param text with emojis
1797
- * @returns text without emojis
1798
- * @public exported from `@promptbook/utils`
1758
+ * @private internal function for `validatePipeline`
1799
1759
  */
1800
- function removeEmojis(text) {
1801
- // Replace emojis (and also ZWJ sequence) with hyphens
1802
- text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1803
- text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1804
- text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1805
- text = text.replace(/\p{Extended_Pictographic}/gu, '');
1806
- return text;
1807
- }
1808
-
1809
- /**
1810
- * @@@
1811
- *
1812
- * @param value @@@
1813
- * @returns @@@
1814
- * @example @@@
1815
- * @public exported from `@promptbook/utils`
1816
- */
1817
- function titleToName(value) {
1818
- if (value.startsWith('http://') || value.startsWith('https://')) {
1819
- // TODO: Maybe check against some list unallowed characters
1820
- return value;
1760
+ function validatePipelineCore(pipeline) {
1761
+ // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
1762
+ var e_1, _a, e_2, _b, e_3, _c;
1763
+ var pipelineIdentification = (function () {
1764
+ // Note: This is a 😐 implementation of [🚞]
1765
+ var _ = [];
1766
+ if (pipeline.sourceFile !== undefined) {
1767
+ _.push("File: ".concat(pipeline.sourceFile));
1768
+ }
1769
+ if (pipeline.pipelineUrl !== undefined) {
1770
+ _.push("Url: ".concat(pipeline.pipelineUrl));
1771
+ }
1772
+ return _.join('\n');
1773
+ })();
1774
+ if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1775
+ // <- Note: [🚲]
1776
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Invalid promptbook URL \"".concat(pipeline.pipelineUrl, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1821
1777
  }
1822
- if (value.startsWith('./') || value.startsWith('../')) {
1823
- // TODO: Maybe check against some list unallowed characters
1824
- return value;
1778
+ if (pipeline.promptbookVersion !== undefined && !isValidPromptbookVersion(pipeline.promptbookVersion)) {
1779
+ // <- Note: [🚲]
1780
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Invalid Promptbook Version \"".concat(pipeline.promptbookVersion, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1781
+ }
1782
+ // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1783
+ if (!Array.isArray(pipeline.parameters)) {
1784
+ // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1785
+ throw new ParseError(spaceTrim(function (block) { return "\n Pipeline is valid JSON but with wrong structure\n\n `PipelineJson.parameters` expected to be an array, but got ".concat(typeof pipeline.parameters, "\n\n ").concat(block(pipelineIdentification), "\n "); }));
1786
+ }
1787
+ // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1788
+ if (!Array.isArray(pipeline.templates)) {
1789
+ // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1790
+ throw new ParseError(spaceTrim(function (block) { return "\n Pipeline is valid JSON but with wrong structure\n\n `PipelineJson.templates` expected to be an array, but got ".concat(typeof pipeline.templates, "\n\n ").concat(block(pipelineIdentification), "\n "); }));
1791
+ }
1792
+ var _loop_1 = function (parameter) {
1793
+ if (parameter.isInput && parameter.isOutput) {
1794
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n\n Parameter {".concat(parameter.name, "} can not be both input and output\n\n ").concat(block(pipelineIdentification), "\n "); }));
1795
+ }
1796
+ // Note: Testing that parameter is either intermediate or output BUT not created and unused
1797
+ if (!parameter.isInput &&
1798
+ !parameter.isOutput &&
1799
+ !pipeline.templates.some(function (template) { return template.dependentParameterNames.includes(parameter.name); })) {
1800
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(parameter.name, "} is created but not used\n\n You can declare {").concat(parameter.name, "} as output parameter by adding in the header:\n - OUTPUT PARAMETER `{").concat(parameter.name, "}` ").concat(parameter.description || '', "\n\n ").concat(block(pipelineIdentification), "\n\n "); }));
1801
+ }
1802
+ // Note: Testing that parameter is either input or result of some template
1803
+ if (!parameter.isInput &&
1804
+ !pipeline.templates.some(function (template) { return template.resultingParameterName === parameter.name; })) {
1805
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(parameter.name, "} is declared but not defined\n\n You can do one of these:\n 1) Remove declaration of {").concat(parameter.name, "}\n 2) Add template that results in -> {").concat(parameter.name, "}\n\n ").concat(block(pipelineIdentification), "\n "); }));
1806
+ }
1807
+ };
1808
+ try {
1809
+ // Note: Check each parameter individually
1810
+ for (var _d = __values(pipeline.parameters), _e = _d.next(); !_e.done; _e = _d.next()) {
1811
+ var parameter = _e.value;
1812
+ _loop_1(parameter);
1813
+ }
1814
+ }
1815
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1816
+ finally {
1817
+ try {
1818
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
1819
+ }
1820
+ finally { if (e_1) throw e_1.error; }
1821
+ }
1822
+ // Note: All input parameters are defined - so that they can be used as result of some template
1823
+ var definedParameters = new Set(pipeline.parameters.filter(function (_a) {
1824
+ var isInput = _a.isInput;
1825
+ return isInput;
1826
+ }).map(function (_a) {
1827
+ var name = _a.name;
1828
+ return name;
1829
+ }));
1830
+ var _loop_2 = function (template) {
1831
+ var e_4, _h, e_5, _j;
1832
+ if (definedParameters.has(template.resultingParameterName)) {
1833
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(template.resultingParameterName, "} is defined multiple times\n\n ").concat(block(pipelineIdentification), "\n "); }));
1834
+ }
1835
+ if (RESERVED_PARAMETER_NAMES.includes(template.resultingParameterName)) {
1836
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter name {".concat(template.resultingParameterName, "} is reserved, please use different name\n\n ").concat(block(pipelineIdentification), "\n "); }));
1837
+ }
1838
+ definedParameters.add(template.resultingParameterName);
1839
+ if (template.jokerParameterNames && template.jokerParameterNames.length > 0) {
1840
+ if (!template.format &&
1841
+ !template.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1842
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Joker parameters are used for {".concat(template.resultingParameterName, "} but no expectations are defined\n\n ").concat(block(pipelineIdentification), "\n "); }));
1843
+ }
1844
+ var _loop_4 = function (joker) {
1845
+ if (!template.dependentParameterNames.includes(joker)) {
1846
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Parameter {".concat(joker, "} is used for {").concat(template.resultingParameterName, "} as joker but not in `dependentParameterNames`\n\n ").concat(block(pipelineIdentification), "\n "); }));
1847
+ }
1848
+ };
1849
+ try {
1850
+ for (var _k = (e_4 = void 0, __values(template.jokerParameterNames)), _l = _k.next(); !_l.done; _l = _k.next()) {
1851
+ var joker = _l.value;
1852
+ _loop_4(joker);
1853
+ }
1854
+ }
1855
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
1856
+ finally {
1857
+ try {
1858
+ if (_l && !_l.done && (_h = _k.return)) _h.call(_k);
1859
+ }
1860
+ finally { if (e_4) throw e_4.error; }
1861
+ }
1862
+ }
1863
+ if (template.expectations) {
1864
+ var _loop_5 = function (unit, min, max) {
1865
+ if (min !== undefined && max !== undefined && min > max) {
1866
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Min expectation (=".concat(min, ") of ").concat(unit, " is higher than max expectation (=").concat(max, ")\n\n ").concat(block(pipelineIdentification), "\n "); }));
1867
+ }
1868
+ if (min !== undefined && min < 0) {
1869
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Min expectation of ".concat(unit, " must be zero or positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1870
+ }
1871
+ if (max !== undefined && max <= 0) {
1872
+ throw new PipelineLogicError(spaceTrim(function (block) { return "\n Max expectation of ".concat(unit, " must be positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1873
+ }
1874
+ };
1875
+ try {
1876
+ for (var _m = (e_5 = void 0, __values(Object.entries(template.expectations))), _o = _m.next(); !_o.done; _o = _m.next()) {
1877
+ var _p = __read(_o.value, 2), unit = _p[0], _q = _p[1], min = _q.min, max = _q.max;
1878
+ _loop_5(unit, min, max);
1879
+ }
1880
+ }
1881
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
1882
+ finally {
1883
+ try {
1884
+ if (_o && !_o.done && (_j = _m.return)) _j.call(_m);
1885
+ }
1886
+ finally { if (e_5) throw e_5.error; }
1887
+ }
1888
+ }
1889
+ };
1890
+ try {
1891
+ // Note: Checking each template individually
1892
+ for (var _f = __values(pipeline.templates), _g = _f.next(); !_g.done; _g = _f.next()) {
1893
+ var template = _g.value;
1894
+ _loop_2(template);
1895
+ }
1896
+ }
1897
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
1898
+ finally {
1899
+ try {
1900
+ if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
1901
+ }
1902
+ finally { if (e_2) throw e_2.error; }
1903
+ }
1904
+ // Note: Detect circular dependencies
1905
+ var resovedParameters = pipeline.parameters
1906
+ .filter(function (_a) {
1907
+ var isInput = _a.isInput;
1908
+ return isInput;
1909
+ })
1910
+ .map(function (_a) {
1911
+ var name = _a.name;
1912
+ return name;
1913
+ });
1914
+ try {
1915
+ // Note: All reserved parameters are resolved
1916
+ for (var RESERVED_PARAMETER_NAMES_1 = __values(RESERVED_PARAMETER_NAMES), RESERVED_PARAMETER_NAMES_1_1 = RESERVED_PARAMETER_NAMES_1.next(); !RESERVED_PARAMETER_NAMES_1_1.done; RESERVED_PARAMETER_NAMES_1_1 = RESERVED_PARAMETER_NAMES_1.next()) {
1917
+ var reservedParameterName = RESERVED_PARAMETER_NAMES_1_1.value;
1918
+ resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), [reservedParameterName], false);
1919
+ }
1920
+ }
1921
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
1922
+ finally {
1923
+ try {
1924
+ if (RESERVED_PARAMETER_NAMES_1_1 && !RESERVED_PARAMETER_NAMES_1_1.done && (_c = RESERVED_PARAMETER_NAMES_1.return)) _c.call(RESERVED_PARAMETER_NAMES_1);
1925
+ }
1926
+ finally { if (e_3) throw e_3.error; }
1927
+ }
1928
+ var unresovedTemplates = __spreadArray([], __read(pipeline.templates), false);
1929
+ var loopLimit = LOOP_LIMIT;
1930
+ var _loop_3 = function () {
1931
+ if (loopLimit-- < 0) {
1932
+ // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1933
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n Loop limit reached during detection of circular dependencies in `validatePipeline`\n\n ".concat(block(pipelineIdentification), "\n "); }));
1934
+ }
1935
+ var currentlyResovedTemplates = unresovedTemplates.filter(function (template) {
1936
+ return template.dependentParameterNames.every(function (name) { return resovedParameters.includes(name); });
1937
+ });
1938
+ if (currentlyResovedTemplates.length === 0) {
1939
+ throw new PipelineLogicError(
1940
+ // TODO: [🐎] DRY
1941
+ spaceTrim(function (block) { return "\n\n Can not resolve some parameters:\n Either you are using a parameter that is not defined, or there are some circular dependencies.\n\n ".concat(block(pipelineIdentification), "\n\n Can not resolve:\n ").concat(block(unresovedTemplates
1942
+ .map(function (_a) {
1943
+ var resultingParameterName = _a.resultingParameterName, dependentParameterNames = _a.dependentParameterNames;
1944
+ return "- Parameter {".concat(resultingParameterName, "} which depends on ").concat(dependentParameterNames
1945
+ .map(function (dependentParameterName) { return "{".concat(dependentParameterName, "}"); })
1946
+ .join(' and '));
1947
+ })
1948
+ .join('\n')), "\n\n Resolved:\n ").concat(block(resovedParameters.map(function (name) { return "- Parameter {".concat(name, "}"); }).join('\n')), "\n\n\n "); }));
1949
+ }
1950
+ resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), __read(currentlyResovedTemplates.map(function (_a) {
1951
+ var resultingParameterName = _a.resultingParameterName;
1952
+ return resultingParameterName;
1953
+ })), false);
1954
+ unresovedTemplates = unresovedTemplates.filter(function (template) { return !currentlyResovedTemplates.includes(template); });
1955
+ };
1956
+ while (unresovedTemplates.length > 0) {
1957
+ _loop_3();
1825
1958
  }
1826
- value = removeEmojis(value);
1827
- value = normalizeToKebabCase(value);
1828
- // TODO: [🧠] Maybe warn or add some padding to short name which are not good identifiers
1829
- return value;
1830
1959
  }
1960
+ /**
1961
+ * TODO: !!!!! [🧞‍♀️] Do not allow joker + foreach
1962
+ * TODO: [🧠] Work with promptbookVersion
1963
+ * TODO: Use here some json-schema, Zod or something similar and change it to:
1964
+ * > /**
1965
+ * > * Validates PipelineJson if it is logically valid.
1966
+ * > *
1967
+ * > * It checks:
1968
+ * > * - it has a valid structure
1969
+ * > * - ...
1970
+ * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
1971
+ */
1972
+ /**
1973
+ * TODO: [🧳][main] !!!! Validate that all samples match expectations
1974
+ * TODO: [🧳][🐝][main] !!!! Validate that knowledge is valid (non-void)
1975
+ * TODO: [🧳][main] !!!! Validate that persona can be used only with CHAT variant
1976
+ * TODO: [🧳][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1977
+ * TODO: [🧳][main] !!!! Validate that reserved parameter is not used as joker
1978
+ * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
1979
+ * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
1980
+ */
1831
1981
 
1832
1982
  /**
1833
- * This error indicates errors during the execution of the pipeline
1983
+ * This error indicates that promptbook not found in the collection
1834
1984
  *
1835
1985
  * @public exported from `@promptbook/core`
1836
1986
  */
1837
- var PipelineExecutionError = /** @class */ (function (_super) {
1838
- __extends(PipelineExecutionError, _super);
1839
- function PipelineExecutionError(message) {
1987
+ var NotFoundError = /** @class */ (function (_super) {
1988
+ __extends(NotFoundError, _super);
1989
+ function NotFoundError(message) {
1840
1990
  var _this = _super.call(this, message) || this;
1841
- _this.name = 'PipelineExecutionError';
1842
- Object.setPrototypeOf(_this, PipelineExecutionError.prototype);
1991
+ _this.name = 'NotFoundError';
1992
+ Object.setPrototypeOf(_this, NotFoundError.prototype);
1843
1993
  return _this;
1844
1994
  }
1845
- return PipelineExecutionError;
1995
+ return NotFoundError;
1846
1996
  }(Error));
1847
1997
 
1848
1998
  /**
1849
- * This error indicates that the pipeline collection cannot be propperly loaded
1999
+ * This error indicates errors in referencing promptbooks between each other
1850
2000
  *
1851
2001
  * @public exported from `@promptbook/core`
1852
2002
  */
1853
- var CollectionError = /** @class */ (function (_super) {
1854
- __extends(CollectionError, _super);
1855
- function CollectionError(message) {
2003
+ var PipelineUrlError = /** @class */ (function (_super) {
2004
+ __extends(PipelineUrlError, _super);
2005
+ function PipelineUrlError(message) {
1856
2006
  var _this = _super.call(this, message) || this;
1857
- _this.name = 'CollectionError';
1858
- Object.setPrototypeOf(_this, CollectionError.prototype);
2007
+ _this.name = 'PipelineUrlError';
2008
+ Object.setPrototypeOf(_this, PipelineUrlError.prototype);
1859
2009
  return _this;
1860
2010
  }
1861
- return CollectionError;
2011
+ return PipelineUrlError;
1862
2012
  }(Error));
1863
2013
 
1864
2014
  /**
1865
- * This error type indicates that you try to use a feature that is not available in the current environment
2015
+ * Parses the template and returns the list of all parameter names
1866
2016
  *
1867
- * @public exported from `@promptbook/core`
1868
- */
1869
- var EnvironmentMismatchError = /** @class */ (function (_super) {
1870
- __extends(EnvironmentMismatchError, _super);
1871
- function EnvironmentMismatchError(message) {
2017
+ * @param template the template with parameters in {curly} braces
2018
+ * @returns the list of parameter names
2019
+ * @public exported from `@promptbook/utils`
2020
+ */
2021
+ function extractParameterNames(template) {
2022
+ var e_1, _a;
2023
+ var matches = template.matchAll(/{\w+}/g);
2024
+ var parameterNames = new Set();
2025
+ try {
2026
+ for (var matches_1 = __values(matches), matches_1_1 = matches_1.next(); !matches_1_1.done; matches_1_1 = matches_1.next()) {
2027
+ var match = matches_1_1.value;
2028
+ var parameterName = match[0].slice(1, -1);
2029
+ parameterNames.add(parameterName);
2030
+ }
2031
+ }
2032
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2033
+ finally {
2034
+ try {
2035
+ if (matches_1_1 && !matches_1_1.done && (_a = matches_1.return)) _a.call(matches_1);
2036
+ }
2037
+ finally { if (e_1) throw e_1.error; }
2038
+ }
2039
+ return parameterNames;
2040
+ }
2041
+
2042
+ /**
2043
+ * Unprepare just strips the preparation data of the pipeline
2044
+ *
2045
+ * @public exported from `@promptbook/core`
2046
+ */
2047
+ function unpreparePipeline(pipeline) {
2048
+ var personas = pipeline.personas, knowledgeSources = pipeline.knowledgeSources, templates = pipeline.templates;
2049
+ personas = personas.map(function (persona) { return (__assign(__assign({}, persona), { modelRequirements: undefined, preparationIds: undefined })); });
2050
+ knowledgeSources = knowledgeSources.map(function (knowledgeSource) { return (__assign(__assign({}, knowledgeSource), { preparationIds: undefined })); });
2051
+ templates = templates.map(function (template) {
2052
+ var dependentParameterNames = template.dependentParameterNames;
2053
+ var parameterNames = extractParameterNames(template.preparedContent || '');
2054
+ dependentParameterNames = dependentParameterNames.filter(function (dependentParameterName) { return !parameterNames.has(dependentParameterName); });
2055
+ var templateUnprepared = __assign(__assign({}, template), { dependentParameterNames: dependentParameterNames });
2056
+ delete templateUnprepared.preparedContent;
2057
+ return templateUnprepared;
2058
+ });
2059
+ return $asDeeplyFrozenSerializableJson('Unprepared PipelineJson', __assign(__assign({}, pipeline), { templates: templates, knowledgeSources: knowledgeSources, knowledgePieces: [], personas: personas, preparations: [] }));
2060
+ }
2061
+ /**
2062
+ * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
2063
+ * TODO: Write tests for `preparePipeline`
2064
+ * TODO: [🍙] Make some standard order of json properties
2065
+ */
2066
+
2067
+ /**
2068
+ * Library of pipelines that groups together pipelines for an application.
2069
+ * This implementation is a very thin wrapper around the Array / Map of pipelines.
2070
+ *
2071
+ * @private internal function of `createCollectionFromJson`, use `createCollectionFromJson` instead
2072
+ * @see https://github.com/webgptorg/pipeline#pipeline-collection
2073
+ */
2074
+ var SimplePipelineCollection = /** @class */ (function () {
2075
+ /**
2076
+ * Constructs a pipeline collection from pipelines
2077
+ *
2078
+ * @param pipelines @@@
2079
+ *
2080
+ * Note: During the construction logic of all pipelines are validated
2081
+ * Note: It is not recommended to use this constructor directly, use `createCollectionFromJson` *(or other variant)* instead
2082
+ */
2083
+ function SimplePipelineCollection() {
2084
+ var e_1, _a;
2085
+ var pipelines = [];
2086
+ for (var _i = 0; _i < arguments.length; _i++) {
2087
+ pipelines[_i] = arguments[_i];
2088
+ }
2089
+ this.collection = new Map();
2090
+ try {
2091
+ for (var pipelines_1 = __values(pipelines), pipelines_1_1 = pipelines_1.next(); !pipelines_1_1.done; pipelines_1_1 = pipelines_1.next()) {
2092
+ var pipeline = pipelines_1_1.value;
2093
+ // TODO: [👠] DRY
2094
+ if (pipeline.pipelineUrl === undefined) {
2095
+ throw new PipelineUrlError(spaceTrim("\n Pipeline with name \"".concat(pipeline.title, "\" does not have defined URL\n\n File:\n ").concat(pipeline.sourceFile || 'Unknown', "\n\n Note: Pipelines without URLs are called anonymous pipelines\n They can be used as standalone pipelines, but they cannot be referenced by other pipelines\n And also they cannot be used in the pipeline collection\n\n ")));
2096
+ }
2097
+ // Note: [🐨]
2098
+ validatePipeline(pipeline);
2099
+ // TODO: [🦄] DRY
2100
+ // Note: [🦄]
2101
+ if (
2102
+ // TODO: [🐽]
2103
+ this.collection.has(pipeline.pipelineUrl) &&
2104
+ pipelineJsonToString(unpreparePipeline(pipeline)) !==
2105
+ pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
2106
+ var existing = this.collection.get(pipeline.pipelineUrl);
2107
+ throw new PipelineUrlError(spaceTrim("\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 ")));
2108
+ }
2109
+ // Note: [🧠] Overwrite existing pipeline with the same URL
2110
+ this.collection.set(pipeline.pipelineUrl, pipeline);
2111
+ }
2112
+ }
2113
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2114
+ finally {
2115
+ try {
2116
+ if (pipelines_1_1 && !pipelines_1_1.done && (_a = pipelines_1.return)) _a.call(pipelines_1);
2117
+ }
2118
+ finally { if (e_1) throw e_1.error; }
2119
+ }
2120
+ }
2121
+ /**
2122
+ * Gets all pipelines in the collection
2123
+ */
2124
+ SimplePipelineCollection.prototype.listPipelines = function () {
2125
+ return Array.from(this.collection.keys());
2126
+ };
2127
+ /**
2128
+ * Gets pipeline by its URL
2129
+ *
2130
+ * Note: This is not a direct fetching from the URL, but a lookup in the collection
2131
+ */
2132
+ SimplePipelineCollection.prototype.getPipelineByUrl = function (url) {
2133
+ var _this = this;
2134
+ var pipeline = this.collection.get(url);
2135
+ if (!pipeline) {
2136
+ if (this.listPipelines().length === 0) {
2137
+ throw new NotFoundError(spaceTrim("\n Pipeline with url \"".concat(url, "\" not found\n\n No pipelines available\n ")));
2138
+ }
2139
+ throw new NotFoundError(spaceTrim(function (block) { return "\n Pipeline with url \"".concat(url, "\" not found\n\n Available pipelines:\n ").concat(block(_this.listPipelines()
2140
+ .map(function (pipelineUrl) { return "- ".concat(pipelineUrl); })
2141
+ .join('\n')), "\n\n "); }));
2142
+ }
2143
+ return pipeline;
2144
+ };
2145
+ /**
2146
+ * Checks whether given prompt was defined in any pipeline in the collection
2147
+ */
2148
+ SimplePipelineCollection.prototype.isResponsibleForPrompt = function (prompt) {
2149
+ return true;
2150
+ };
2151
+ return SimplePipelineCollection;
2152
+ }());
2153
+
2154
+ /**
2155
+ * Creates PipelineCollection from array of PipelineJson or PipelineString
2156
+ *
2157
+ * Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
2158
+ * Note: Syntax, parsing, and logic consistency checks are performed on all sources during build
2159
+ *
2160
+ * @param promptbookSources
2161
+ * @returns PipelineCollection
2162
+ * @public exported from `@promptbook/core`
2163
+ */
2164
+ function createCollectionFromJson() {
2165
+ var promptbooks = [];
2166
+ for (var _i = 0; _i < arguments.length; _i++) {
2167
+ promptbooks[_i] = arguments[_i];
2168
+ }
2169
+ return new (SimplePipelineCollection.bind.apply(SimplePipelineCollection, __spreadArray([void 0], __read(promptbooks), false)))();
2170
+ }
2171
+
2172
+ /**
2173
+ * This error indicates errors during the execution of the pipeline
2174
+ *
2175
+ * @public exported from `@promptbook/core`
2176
+ */
2177
+ var PipelineExecutionError = /** @class */ (function (_super) {
2178
+ __extends(PipelineExecutionError, _super);
2179
+ function PipelineExecutionError(message) {
1872
2180
  var _this = _super.call(this, message) || this;
1873
- _this.name = 'EnvironmentMismatchError';
1874
- Object.setPrototypeOf(_this, EnvironmentMismatchError.prototype);
2181
+ _this.name = 'PipelineExecutionError';
2182
+ Object.setPrototypeOf(_this, PipelineExecutionError.prototype);
1875
2183
  return _this;
1876
2184
  }
1877
- return EnvironmentMismatchError;
2185
+ return PipelineExecutionError;
2186
+ }(Error));
2187
+
2188
+ /**
2189
+ * This error indicates that the pipeline collection cannot be propperly loaded
2190
+ *
2191
+ * @public exported from `@promptbook/core`
2192
+ */
2193
+ var CollectionError = /** @class */ (function (_super) {
2194
+ __extends(CollectionError, _super);
2195
+ function CollectionError(message) {
2196
+ var _this = _super.call(this, message) || this;
2197
+ _this.name = 'CollectionError';
2198
+ Object.setPrototypeOf(_this, CollectionError.prototype);
2199
+ return _this;
2200
+ }
2201
+ return CollectionError;
1878
2202
  }(Error));
1879
2203
 
1880
2204
  /**
@@ -2375,6 +2699,59 @@ function deepClone(objectValue) {
2375
2699
  * TODO: [🧠] Is there a way how to meaningfully test this utility
2376
2700
  */
2377
2701
 
2702
+ /**
2703
+ * Represents the usage with no resources consumed
2704
+ *
2705
+ * @public exported from `@promptbook/core`
2706
+ */
2707
+ var ZERO_USAGE = $deepFreeze({
2708
+ price: { value: 0 },
2709
+ input: {
2710
+ tokensCount: { value: 0 },
2711
+ charactersCount: { value: 0 },
2712
+ wordsCount: { value: 0 },
2713
+ sentencesCount: { value: 0 },
2714
+ linesCount: { value: 0 },
2715
+ paragraphsCount: { value: 0 },
2716
+ pagesCount: { value: 0 },
2717
+ },
2718
+ output: {
2719
+ tokensCount: { value: 0 },
2720
+ charactersCount: { value: 0 },
2721
+ wordsCount: { value: 0 },
2722
+ sentencesCount: { value: 0 },
2723
+ linesCount: { value: 0 },
2724
+ paragraphsCount: { value: 0 },
2725
+ pagesCount: { value: 0 },
2726
+ },
2727
+ });
2728
+ /**
2729
+ * Represents the usage with unknown resources consumed
2730
+ *
2731
+ * @public exported from `@promptbook/core`
2732
+ */
2733
+ $deepFreeze({
2734
+ price: { value: 0, isUncertain: true },
2735
+ input: {
2736
+ tokensCount: { value: 0, isUncertain: true },
2737
+ charactersCount: { value: 0, isUncertain: true },
2738
+ wordsCount: { value: 0, isUncertain: true },
2739
+ sentencesCount: { value: 0, isUncertain: true },
2740
+ linesCount: { value: 0, isUncertain: true },
2741
+ paragraphsCount: { value: 0, isUncertain: true },
2742
+ pagesCount: { value: 0, isUncertain: true },
2743
+ },
2744
+ output: {
2745
+ tokensCount: { value: 0, isUncertain: true },
2746
+ charactersCount: { value: 0, isUncertain: true },
2747
+ wordsCount: { value: 0, isUncertain: true },
2748
+ sentencesCount: { value: 0, isUncertain: true },
2749
+ linesCount: { value: 0, isUncertain: true },
2750
+ paragraphsCount: { value: 0, isUncertain: true },
2751
+ pagesCount: { value: 0, isUncertain: true },
2752
+ },
2753
+ });
2754
+
2378
2755
  /**
2379
2756
  * Function `addUsage` will add multiple usages into one
2380
2757
  *
@@ -2653,29 +3030,12 @@ function union() {
2653
3030
  }
2654
3031
 
2655
3032
  /**
2656
- * Just marks a place of place where should be something implemented
2657
- * No side effects.
3033
+ * This error indicates problems parsing the format value
2658
3034
  *
2659
- * Note: It can be usefull suppressing eslint errors of unused variables
3035
+ * For example, when the format value is not a valid JSON or CSV
3036
+ * This is not thrown directly but in extended classes
2660
3037
  *
2661
- * @param value any values
2662
- * @returns void
2663
- * @private within the repository
2664
- */
2665
- function TODO_USE() {
2666
- var value = [];
2667
- for (var _i = 0; _i < arguments.length; _i++) {
2668
- value[_i] = arguments[_i];
2669
- }
2670
- }
2671
-
2672
- /**
2673
- * This error indicates problems parsing the format value
2674
- *
2675
- * For example, when the format value is not a valid JSON or CSV
2676
- * This is not thrown directly but in extended classes
2677
- *
2678
- * @public exported from `@promptbook/core`
3038
+ * @public exported from `@promptbook/core`
2679
3039
  */
2680
3040
  var AbstractFormatError = /** @class */ (function (_super) {
2681
3041
  __extends(AbstractFormatError, _super);
@@ -2712,7 +3072,7 @@ var CsvFormatError = /** @class */ (function (_super) {
2712
3072
  */
2713
3073
  var MANDATORY_CSV_SETTINGS = Object.freeze({
2714
3074
  header: true,
2715
- // encoding: 'utf8',
3075
+ // encoding: 'utf-8',
2716
3076
  });
2717
3077
 
2718
3078
  /**
@@ -4144,25 +4504,26 @@ function filterJustOutputParameters(options) {
4144
4504
  */
4145
4505
  function executePipeline(options) {
4146
4506
  return __awaiter(this, void 0, void 0, function () {
4147
- var inputParameters, tools, onProgress, pipeline, setPreparedPipeline, pipelineIdentification, settings, maxParallelCount, isVerbose, preparedPipeline, llmTools, errors, warnings, executionReport, isReturned, _a, _b, parameter, e_1_1, _loop_1, _c, _d, parameterName, state_1, e_2_1, parametersToPass, resovedParameterNames_1, unresovedTemplates_1, resolving_1, loopLimit, _loop_2, error_1, usage_1, outputParameters_1, usage, outputParameters;
4148
- var e_1, _e, e_2, _f;
4149
- return __generator(this, function (_g) {
4150
- switch (_g.label) {
4507
+ var inputParameters, tools, onProgress, pipeline, setPreparedPipeline, pipelineIdentification, settings, maxParallelCount, rootDirname, _a, isVerbose, preparedPipeline, llmTools, errors, warnings, executionReport, isReturned, _b, _c, parameter, e_1_1, _loop_1, _d, _e, parameterName, state_1, e_2_1, parametersToPass, resovedParameterNames_1, unresovedTemplates_1, resolving_1, loopLimit, _loop_2, error_1, usage_1, outputParameters_1, usage, outputParameters;
4508
+ var e_1, _f, e_2, _g;
4509
+ return __generator(this, function (_h) {
4510
+ switch (_h.label) {
4151
4511
  case 0:
4152
4512
  inputParameters = options.inputParameters, tools = options.tools, onProgress = options.onProgress, pipeline = options.pipeline, setPreparedPipeline = options.setPreparedPipeline, pipelineIdentification = options.pipelineIdentification, settings = options.settings;
4153
- maxParallelCount = settings.maxParallelCount, isVerbose = settings.isVerbose;
4513
+ maxParallelCount = settings.maxParallelCount, rootDirname = settings.rootDirname, _a = settings.isVerbose, isVerbose = _a === void 0 ? IS_VERBOSE : _a;
4154
4514
  preparedPipeline = options.preparedPipeline;
4155
4515
  llmTools = joinLlmExecutionTools.apply(void 0, __spreadArray([], __read(arrayableToArray(tools.llm)), false));
4156
4516
  if (!(preparedPipeline === undefined)) return [3 /*break*/, 2];
4157
4517
  return [4 /*yield*/, preparePipeline(pipeline, {
4158
4518
  llmTools: llmTools,
4519
+ rootDirname: rootDirname,
4159
4520
  isVerbose: isVerbose,
4160
4521
  maxParallelCount: maxParallelCount,
4161
4522
  })];
4162
4523
  case 1:
4163
- preparedPipeline = _g.sent();
4524
+ preparedPipeline = _h.sent();
4164
4525
  setPreparedPipeline(preparedPipeline);
4165
- _g.label = 2;
4526
+ _h.label = 2;
4166
4527
  case 2:
4167
4528
  errors = [];
4168
4529
  warnings = [];
@@ -4175,17 +4536,17 @@ function executePipeline(options) {
4175
4536
  promptExecutions: [],
4176
4537
  };
4177
4538
  isReturned = false;
4178
- _g.label = 3;
4539
+ _h.label = 3;
4179
4540
  case 3:
4180
- _g.trys.push([3, 9, 10, 11]);
4181
- _a = __values(preparedPipeline.parameters.filter(function (_a) {
4541
+ _h.trys.push([3, 9, 10, 11]);
4542
+ _b = __values(preparedPipeline.parameters.filter(function (_a) {
4182
4543
  var isInput = _a.isInput;
4183
4544
  return isInput;
4184
- })), _b = _a.next();
4185
- _g.label = 4;
4545
+ })), _c = _b.next();
4546
+ _h.label = 4;
4186
4547
  case 4:
4187
- if (!!_b.done) return [3 /*break*/, 8];
4188
- parameter = _b.value;
4548
+ if (!!_c.done) return [3 /*break*/, 8];
4549
+ parameter = _c.value;
4189
4550
  if (!(inputParameters[parameter.name] === undefined)) return [3 /*break*/, 7];
4190
4551
  isReturned = true;
4191
4552
  if (!(onProgress !== undefined)) return [3 /*break*/, 6];
@@ -4193,8 +4554,8 @@ function executePipeline(options) {
4193
4554
  return [4 /*yield*/, forTime(IMMEDIATE_TIME)];
4194
4555
  case 5:
4195
4556
  // Note: Wait a short time to prevent race conditions
4196
- _g.sent();
4197
- _g.label = 6;
4557
+ _h.sent();
4558
+ _h.label = 6;
4198
4559
  case 6: return [2 /*return*/, $asDeeplyFrozenSerializableJson("Unuccessful PipelineExecutorResult (with missing parameter {".concat(parameter.name, "}) PipelineExecutorResult"), {
4199
4560
  isSuccessful: false,
4200
4561
  errors: __spreadArray([
@@ -4207,24 +4568,24 @@ function executePipeline(options) {
4207
4568
  preparedPipeline: preparedPipeline,
4208
4569
  })];
4209
4570
  case 7:
4210
- _b = _a.next();
4571
+ _c = _b.next();
4211
4572
  return [3 /*break*/, 4];
4212
4573
  case 8: return [3 /*break*/, 11];
4213
4574
  case 9:
4214
- e_1_1 = _g.sent();
4575
+ e_1_1 = _h.sent();
4215
4576
  e_1 = { error: e_1_1 };
4216
4577
  return [3 /*break*/, 11];
4217
4578
  case 10:
4218
4579
  try {
4219
- if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
4580
+ if (_c && !_c.done && (_f = _b.return)) _f.call(_b);
4220
4581
  }
4221
4582
  finally { if (e_1) throw e_1.error; }
4222
4583
  return [7 /*endfinally*/];
4223
4584
  case 11:
4224
4585
  _loop_1 = function (parameterName) {
4225
4586
  var parameter;
4226
- return __generator(this, function (_h) {
4227
- switch (_h.label) {
4587
+ return __generator(this, function (_j) {
4588
+ switch (_j.label) {
4228
4589
  case 0:
4229
4590
  parameter = preparedPipeline.parameters.find(function (_a) {
4230
4591
  var name = _a.name;
@@ -4241,8 +4602,8 @@ function executePipeline(options) {
4241
4602
  return [4 /*yield*/, forTime(IMMEDIATE_TIME)];
4242
4603
  case 2:
4243
4604
  // Note: Wait a short time to prevent race conditions
4244
- _h.sent();
4245
- _h.label = 3;
4605
+ _j.sent();
4606
+ _j.label = 3;
4246
4607
  case 3: return [2 /*return*/, { value: $asDeeplyFrozenSerializableJson(spaceTrim(function (block) { return "\n Unuccessful PipelineExecutorResult (with extra parameter {".concat(parameter.name, "}) PipelineExecutorResult\n\n ").concat(block(pipelineIdentification), "\n "); }), {
4247
4608
  isSuccessful: false,
4248
4609
  errors: __spreadArray([
@@ -4258,39 +4619,39 @@ function executePipeline(options) {
4258
4619
  }
4259
4620
  });
4260
4621
  };
4261
- _g.label = 12;
4622
+ _h.label = 12;
4262
4623
  case 12:
4263
- _g.trys.push([12, 17, 18, 19]);
4264
- _c = __values(Object.keys(inputParameters)), _d = _c.next();
4265
- _g.label = 13;
4624
+ _h.trys.push([12, 17, 18, 19]);
4625
+ _d = __values(Object.keys(inputParameters)), _e = _d.next();
4626
+ _h.label = 13;
4266
4627
  case 13:
4267
- if (!!_d.done) return [3 /*break*/, 16];
4268
- parameterName = _d.value;
4628
+ if (!!_e.done) return [3 /*break*/, 16];
4629
+ parameterName = _e.value;
4269
4630
  return [5 /*yield**/, _loop_1(parameterName)];
4270
4631
  case 14:
4271
- state_1 = _g.sent();
4632
+ state_1 = _h.sent();
4272
4633
  if (typeof state_1 === "object")
4273
4634
  return [2 /*return*/, state_1.value];
4274
- _g.label = 15;
4635
+ _h.label = 15;
4275
4636
  case 15:
4276
- _d = _c.next();
4637
+ _e = _d.next();
4277
4638
  return [3 /*break*/, 13];
4278
4639
  case 16: return [3 /*break*/, 19];
4279
4640
  case 17:
4280
- e_2_1 = _g.sent();
4641
+ e_2_1 = _h.sent();
4281
4642
  e_2 = { error: e_2_1 };
4282
4643
  return [3 /*break*/, 19];
4283
4644
  case 18:
4284
4645
  try {
4285
- if (_d && !_d.done && (_f = _c.return)) _f.call(_c);
4646
+ if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
4286
4647
  }
4287
4648
  finally { if (e_2) throw e_2.error; }
4288
4649
  return [7 /*endfinally*/];
4289
4650
  case 19:
4290
4651
  parametersToPass = inputParameters;
4291
- _g.label = 20;
4652
+ _h.label = 20;
4292
4653
  case 20:
4293
- _g.trys.push([20, 25, , 28]);
4654
+ _h.trys.push([20, 25, , 28]);
4294
4655
  resovedParameterNames_1 = preparedPipeline.parameters
4295
4656
  .filter(function (_a) {
4296
4657
  var isInput = _a.isInput;
@@ -4305,8 +4666,8 @@ function executePipeline(options) {
4305
4666
  loopLimit = LOOP_LIMIT;
4306
4667
  _loop_2 = function () {
4307
4668
  var currentTemplate, work_1;
4308
- return __generator(this, function (_j) {
4309
- switch (_j.label) {
4669
+ return __generator(this, function (_k) {
4670
+ switch (_k.label) {
4310
4671
  case 0:
4311
4672
  if (loopLimit-- < 0) {
4312
4673
  // Note: Really UnexpectedError not LimitReachedError - this should be catched during validatePipeline
@@ -4332,7 +4693,7 @@ function executePipeline(options) {
4332
4693
  if (!!currentTemplate) return [3 /*break*/, 3];
4333
4694
  /* [🤹‍♂️] */ return [4 /*yield*/, Promise.race(resolving_1)];
4334
4695
  case 2:
4335
- /* [🤹‍♂️] */ _j.sent();
4696
+ /* [🤹‍♂️] */ _k.sent();
4336
4697
  return [3 /*break*/, 4];
4337
4698
  case 3:
4338
4699
  unresovedTemplates_1 = unresovedTemplates_1.filter(function (template) { return template !== currentTemplate; });
@@ -4367,24 +4728,24 @@ function executePipeline(options) {
4367
4728
  // <- Note: Errors are catched here [3]
4368
4729
  // TODO: BUT if in multiple templates are errors, only the first one is catched so maybe we should catch errors here and save them to errors array here
4369
4730
  resolving_1.push(work_1);
4370
- _j.label = 4;
4731
+ _k.label = 4;
4371
4732
  case 4: return [2 /*return*/];
4372
4733
  }
4373
4734
  });
4374
4735
  };
4375
- _g.label = 21;
4736
+ _h.label = 21;
4376
4737
  case 21:
4377
4738
  if (!(unresovedTemplates_1.length > 0)) return [3 /*break*/, 23];
4378
4739
  return [5 /*yield**/, _loop_2()];
4379
4740
  case 22:
4380
- _g.sent();
4741
+ _h.sent();
4381
4742
  return [3 /*break*/, 21];
4382
4743
  case 23: return [4 /*yield*/, Promise.all(resolving_1)];
4383
4744
  case 24:
4384
- _g.sent();
4745
+ _h.sent();
4385
4746
  return [3 /*break*/, 28];
4386
4747
  case 25:
4387
- error_1 = _g.sent();
4748
+ error_1 = _h.sent();
4388
4749
  if (!(error_1 instanceof Error)) {
4389
4750
  throw error_1;
4390
4751
  }
@@ -4404,8 +4765,8 @@ function executePipeline(options) {
4404
4765
  return [4 /*yield*/, forTime(IMMEDIATE_TIME)];
4405
4766
  case 26:
4406
4767
  // Note: Wait a short time to prevent race conditions
4407
- _g.sent();
4408
- _g.label = 27;
4768
+ _h.sent();
4769
+ _h.label = 27;
4409
4770
  case 27: return [2 /*return*/, $asDeeplyFrozenSerializableJson('Unuccessful PipelineExecutorResult (with misc errors) PipelineExecutorResult', {
4410
4771
  isSuccessful: false,
4411
4772
  errors: __spreadArray([error_1], __read(errors), false).map(serializeError),
@@ -4432,8 +4793,8 @@ function executePipeline(options) {
4432
4793
  return [4 /*yield*/, forTime(IMMEDIATE_TIME)];
4433
4794
  case 29:
4434
4795
  // Note: Wait a short time to prevent race conditions
4435
- _g.sent();
4436
- _g.label = 30;
4796
+ _h.sent();
4797
+ _h.label = 30;
4437
4798
  case 30: return [2 /*return*/, $asDeeplyFrozenSerializableJson('Successful PipelineExecutorResult', {
4438
4799
  isSuccessful: true,
4439
4800
  errors: errors.map(serializeError),
@@ -4445,211 +4806,883 @@ function executePipeline(options) {
4445
4806
  })];
4446
4807
  }
4447
4808
  });
4448
- });
4449
- }
4809
+ });
4810
+ }
4811
+ /**
4812
+ * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
4813
+ */
4814
+
4815
+ /**
4816
+ * Creates executor function from pipeline and execution tools.
4817
+ *
4818
+ * @returns The executor function
4819
+ * @throws {PipelineLogicError} on logical error in the pipeline
4820
+ * @public exported from `@promptbook/core`
4821
+ */
4822
+ function createPipelineExecutor(options) {
4823
+ var _this = this;
4824
+ var pipeline = options.pipeline, tools = options.tools, _a = options.settings, settings = _a === void 0 ? {} : _a;
4825
+ var _b = settings.maxExecutionAttempts, maxExecutionAttempts = _b === void 0 ? MAX_EXECUTION_ATTEMPTS : _b, _c = settings.maxParallelCount, maxParallelCount = _c === void 0 ? MAX_PARALLEL_COUNT : _c, _d = settings.csvSettings, csvSettings = _d === void 0 ? DEFAULT_CSV_SETTINGS : _d, _e = settings.isVerbose, isVerbose = _e === void 0 ? IS_VERBOSE : _e, _f = settings.isNotPreparedWarningSupressed, isNotPreparedWarningSupressed = _f === void 0 ? false : _f, _g = settings.rootDirname, rootDirname = _g === void 0 ? null : _g;
4826
+ validatePipeline(pipeline);
4827
+ var pipelineIdentification = (function () {
4828
+ // Note: This is a 😐 implementation of [🚞]
4829
+ var _ = [];
4830
+ if (pipeline.sourceFile !== undefined) {
4831
+ _.push("File: ".concat(pipeline.sourceFile));
4832
+ }
4833
+ if (pipeline.pipelineUrl !== undefined) {
4834
+ _.push("Url: ".concat(pipeline.pipelineUrl));
4835
+ }
4836
+ return _.join('\n');
4837
+ })();
4838
+ var preparedPipeline;
4839
+ if (isPipelinePrepared(pipeline)) {
4840
+ preparedPipeline = pipeline;
4841
+ }
4842
+ else if (isNotPreparedWarningSupressed !== true) {
4843
+ console.warn(spaceTrim(function (block) { return "\n Pipeline is not prepared\n\n ".concat(block(pipelineIdentification), "\n\n It will be prepared ad-hoc before the first execution and **returned as `preparedPipeline` in `PipelineExecutorResult`**\n But it is recommended to prepare the pipeline during collection preparation\n\n @see more at https://ptbk.io/prepare-pipeline\n "); }));
4844
+ }
4845
+ var runCount = 0;
4846
+ var pipelineExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
4847
+ return __generator(this, function (_a) {
4848
+ runCount++;
4849
+ return [2 /*return*/, /* not await */ executePipeline({
4850
+ pipeline: pipeline,
4851
+ preparedPipeline: preparedPipeline,
4852
+ setPreparedPipeline: function (newPreparedPipeline) {
4853
+ preparedPipeline = newPreparedPipeline;
4854
+ },
4855
+ inputParameters: inputParameters,
4856
+ tools: tools,
4857
+ onProgress: onProgress,
4858
+ pipelineIdentification: spaceTrim(function (block) { return "\n ".concat(block(pipelineIdentification), "\n ").concat(runCount === 1 ? '' : "Run #".concat(runCount), "\n "); }),
4859
+ settings: {
4860
+ maxExecutionAttempts: maxExecutionAttempts,
4861
+ maxParallelCount: maxParallelCount,
4862
+ csvSettings: csvSettings,
4863
+ isVerbose: isVerbose,
4864
+ isNotPreparedWarningSupressed: isNotPreparedWarningSupressed,
4865
+ rootDirname: rootDirname,
4866
+ },
4867
+ })];
4868
+ });
4869
+ }); };
4870
+ return pipelineExecutor;
4871
+ }
4872
+ /**
4873
+ * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
4874
+ */
4875
+
4876
+ /**
4877
+ * Scraper for markdown files
4878
+ *
4879
+ * @see `documentationUrl` for more details
4880
+ * @public exported from `@promptbook/core`
4881
+ */
4882
+ var markdownScraper = {
4883
+ /**
4884
+ * Mime types that this scraper can handle
4885
+ */
4886
+ mimeTypes: ['text/markdown', 'text/plain'],
4887
+ /**
4888
+ * Link to documentation
4889
+ */
4890
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
4891
+ /**
4892
+ * Scrapes the markdown file and returns the knowledge pieces or `null` if it can't scrape it
4893
+ */
4894
+ scrape: function (source, options) {
4895
+ return __awaiter(this, void 0, void 0, function () {
4896
+ var llmTools, _a, maxParallelCount, _b, isVerbose, collection, prepareKnowledgeFromMarkdownExecutor, _c, prepareTitleExecutor, _d, prepareKeywordsExecutor, _e, knowledgeContent, result, outputParameters, knowledgePiecesRaw, knowledgeTextPieces, knowledge;
4897
+ var _f, _g, _h;
4898
+ var _this = this;
4899
+ return __generator(this, function (_j) {
4900
+ switch (_j.label) {
4901
+ case 0:
4902
+ llmTools = options.llmTools, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
4903
+ if (llmTools === undefined) {
4904
+ throw new MissingToolsError('LLM tools are required for scraping external files');
4905
+ // <- Note: This scraper is used in all other scrapers, so saying "external files" not "markdown files"
4906
+ }
4907
+ TODO_USE(maxParallelCount); // <- [🪂]
4908
+ collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
4909
+ _c = createPipelineExecutor;
4910
+ _f = {};
4911
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md')];
4912
+ case 1:
4913
+ prepareKnowledgeFromMarkdownExecutor = _c.apply(void 0, [(_f.pipeline = _j.sent(),
4914
+ _f.tools = {
4915
+ llm: llmTools,
4916
+ },
4917
+ _f)]);
4918
+ _d = createPipelineExecutor;
4919
+ _g = {};
4920
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md')];
4921
+ case 2:
4922
+ prepareTitleExecutor = _d.apply(void 0, [(_g.pipeline = _j.sent(),
4923
+ _g.tools = {
4924
+ llm: llmTools,
4925
+ },
4926
+ _g)]);
4927
+ _e = createPipelineExecutor;
4928
+ _h = {};
4929
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md')];
4930
+ case 3:
4931
+ prepareKeywordsExecutor = _e.apply(void 0, [(_h.pipeline = _j.sent(),
4932
+ _h.tools = {
4933
+ llm: llmTools,
4934
+ },
4935
+ _h)]);
4936
+ return [4 /*yield*/, source.asText()];
4937
+ case 4:
4938
+ knowledgeContent = _j.sent();
4939
+ return [4 /*yield*/, prepareKnowledgeFromMarkdownExecutor({ knowledgeContent: knowledgeContent })];
4940
+ case 5:
4941
+ result = _j.sent();
4942
+ assertsExecutionSuccessful(result);
4943
+ outputParameters = result.outputParameters;
4944
+ knowledgePiecesRaw = outputParameters.knowledgePieces;
4945
+ knowledgeTextPieces = (knowledgePiecesRaw || '').split('\n---\n');
4946
+ // <- TODO: [main] !!!!! Smarter split and filter out empty pieces
4947
+ if (isVerbose) {
4948
+ console.info('knowledgeTextPieces:', knowledgeTextPieces);
4949
+ }
4950
+ return [4 /*yield*/, Promise.all(
4951
+ // TODO: [🪂] !! Do not send all at once but in chunks
4952
+ knowledgeTextPieces.map(function (knowledgeTextPiece, i) { return __awaiter(_this, void 0, void 0, function () {
4953
+ var name, title, knowledgePieceContent, keywords, index, titleResult, _a, titleRaw, keywordsResult, _b, keywordsRaw, embeddingResult, error_1;
4954
+ return __generator(this, function (_c) {
4955
+ switch (_c.label) {
4956
+ case 0:
4957
+ name = "piece-".concat(i);
4958
+ title = spaceTrim$1(knowledgeTextPiece.substring(0, 100));
4959
+ knowledgePieceContent = spaceTrim$1(knowledgeTextPiece);
4960
+ keywords = [];
4961
+ index = [];
4962
+ _c.label = 1;
4963
+ case 1:
4964
+ _c.trys.push([1, 7, , 8]);
4965
+ return [4 /*yield*/, prepareTitleExecutor({ knowledgePieceContent: knowledgePieceContent })];
4966
+ case 2:
4967
+ titleResult = _c.sent();
4968
+ _a = titleResult.outputParameters.title, titleRaw = _a === void 0 ? 'Untitled' : _a;
4969
+ title = spaceTrim$1(titleRaw) /* <- TODO: Maybe do in pipeline */;
4970
+ name = titleToName(title);
4971
+ return [4 /*yield*/, prepareKeywordsExecutor({ knowledgePieceContent: knowledgePieceContent })];
4972
+ case 3:
4973
+ keywordsResult = _c.sent();
4974
+ _b = keywordsResult.outputParameters.keywords, keywordsRaw = _b === void 0 ? '' : _b;
4975
+ keywords = (keywordsRaw || '')
4976
+ .split(',')
4977
+ .map(function (keyword) { return keyword.trim(); })
4978
+ .filter(function (keyword) { return keyword !== ''; });
4979
+ if (isVerbose) {
4980
+ console.info("Keywords for \"".concat(title, "\":"), keywords);
4981
+ }
4982
+ if (!!llmTools.callEmbeddingModel) return [3 /*break*/, 4];
4983
+ // TODO: [🟥] Detect browser / node and make it colorfull
4984
+ console.error('No callEmbeddingModel function provided');
4985
+ return [3 /*break*/, 6];
4986
+ case 4: return [4 /*yield*/, llmTools.callEmbeddingModel({
4987
+ title: "Embedding for ".concat(title) /* <- Note: No impact on embedding result itself, just for logging */,
4988
+ parameters: {},
4989
+ content: knowledgePieceContent,
4990
+ modelRequirements: {
4991
+ modelVariant: 'EMBEDDING',
4992
+ },
4993
+ })];
4994
+ case 5:
4995
+ embeddingResult = _c.sent();
4996
+ index.push({
4997
+ modelName: embeddingResult.modelName,
4998
+ position: embeddingResult.content,
4999
+ });
5000
+ _c.label = 6;
5001
+ case 6: return [3 /*break*/, 8];
5002
+ case 7:
5003
+ error_1 = _c.sent();
5004
+ // Note: Here is expected error:
5005
+ // > PipelineExecutionError: You have not provided any `LlmExecutionTools` that support model variant "EMBEDDING
5006
+ if (!(error_1 instanceof PipelineExecutionError)) {
5007
+ throw error_1;
5008
+ }
5009
+ // TODO: [🟥] Detect browser / node and make it colorfull
5010
+ console.error(error_1, "<- Note: This error is not critical to prepare the pipeline, just knowledge pieces won't have embeddings");
5011
+ return [3 /*break*/, 8];
5012
+ case 8: return [2 /*return*/, {
5013
+ name: name,
5014
+ title: title,
5015
+ content: knowledgePieceContent,
5016
+ keywords: keywords,
5017
+ index: index,
5018
+ // <- TODO: [☀] sources,
5019
+ }];
5020
+ }
5021
+ });
5022
+ }); }))];
5023
+ case 6:
5024
+ knowledge = _j.sent();
5025
+ return [2 /*return*/, knowledge];
5026
+ }
5027
+ });
5028
+ });
5029
+ },
5030
+ } /* TODO: [🦷] as const */;
5031
+ /**
5032
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5033
+ * TODO: [🪂] Do it in parallel 11:11
5034
+ * TODO: [🦷] Ideally use `as const satisfies Scraper` BUT this combination throws errors
5035
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5036
+ */
5037
+
5038
+ /**
5039
+ * Scraper of .docx and .odt files
5040
+ *
5041
+ * @see `documentationUrl` for more details
5042
+ * @public exported from `@promptbook/core`
5043
+ */
5044
+ var documentScraper = {
5045
+ /**
5046
+ * Mime types that this scraper can handle
5047
+ */
5048
+ mimeTypes: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
5049
+ /**
5050
+ * Link to documentation
5051
+ */
5052
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5053
+ /**
5054
+ * Convert the `.docx` or `.odt` to `.md` file and returns intermediate source
5055
+ *
5056
+ * Note: `$` is used to indicate that this function is not a pure function - it leaves files on the disk and you are responsible for cleaning them by calling `destroy` method of returned object
5057
+ */
5058
+ $convert: function (source, options) {
5059
+ return __awaiter(this, void 0, void 0, function () {
5060
+ var _a, externalProgramsPaths, rootDirname, _b, cacheDirname, _c, isCacheCleaned, _d, isVerbose, extension, cacheFilehandler, command_1;
5061
+ return __generator(this, function (_e) {
5062
+ switch (_e.label) {
5063
+ case 0:
5064
+ _a = options.externalProgramsPaths, externalProgramsPaths = _a === void 0 ? {} : _a, rootDirname = options.rootDirname, _b = options.cacheDirname, cacheDirname = _b === void 0 ? SCRAPE_CACHE_DIRNAME : _b, _c = options.isCacheCleaned, isCacheCleaned = _c === void 0 ? false : _c, _d = options.isVerbose, isVerbose = _d === void 0 ? IS_VERBOSE : _d;
5065
+ if (!$isRunningInNode()) {
5066
+ throw new KnowledgeScrapeError('Scraping .docx files is only supported in Node environment');
5067
+ }
5068
+ if (externalProgramsPaths.pandocPath === undefined) {
5069
+ throw new MissingToolsError('Pandoc is required for scraping .docx files');
5070
+ }
5071
+ if (source.filename === null) {
5072
+ // TODO: [🧠] Maybe save file as temporary
5073
+ throw new KnowledgeScrapeError('When parsing .docx file, it must be real file in the file system');
5074
+ }
5075
+ extension = getFileExtension(source.filename);
5076
+ return [4 /*yield*/, getScraperIntermediateSource(source, {
5077
+ rootDirname: rootDirname,
5078
+ cacheDirname: cacheDirname,
5079
+ isCacheCleaned: isCacheCleaned,
5080
+ extension: 'md',
5081
+ isVerbose: isVerbose,
5082
+ })];
5083
+ case 1:
5084
+ cacheFilehandler = _e.sent();
5085
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5086
+ case 2:
5087
+ if (!!(_e.sent())) return [3 /*break*/, 5];
5088
+ command_1 = "\"".concat(externalProgramsPaths.pandocPath, "\" -f ").concat(extension, " -t markdown \"").concat(source.filename, "\" -o \"").concat(cacheFilehandler.filename, "\"");
5089
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook
5090
+ return [4 /*yield*/, $execCommand(command_1)];
5091
+ case 3:
5092
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook
5093
+ _e.sent();
5094
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5095
+ case 4:
5096
+ // Note: [0]
5097
+ if (!(_e.sent())) {
5098
+ throw new UnexpectedError(spaceTrim$1(function (block) { return "\n File that was supposed to be created by Pandoc does not exist for unknown reason\n\n Expected file:\n ".concat(block(cacheFilehandler.filename), "\n\n Command:\n > ").concat(block(command_1), "\n\n "); }));
5099
+ }
5100
+ _e.label = 5;
5101
+ case 5: return [2 /*return*/, cacheFilehandler];
5102
+ }
5103
+ });
5104
+ });
5105
+ },
5106
+ /**
5107
+ * Scrapes the docx file and returns the knowledge pieces or `null` if it can't scrape it
5108
+ */
5109
+ scrape: function (source, options) {
5110
+ return __awaiter(this, void 0, void 0, function () {
5111
+ var cacheFilehandler, markdownSource, knowledge;
5112
+ return __generator(this, function (_a) {
5113
+ switch (_a.label) {
5114
+ case 0: return [4 /*yield*/, documentScraper.$convert(source, options)];
5115
+ case 1:
5116
+ cacheFilehandler = _a.sent();
5117
+ markdownSource = {
5118
+ source: source.source,
5119
+ filename: cacheFilehandler.filename,
5120
+ url: null,
5121
+ mimeType: 'text/markdown',
5122
+ asText: function () {
5123
+ return __awaiter(this, void 0, void 0, function () {
5124
+ return __generator(this, function (_a) {
5125
+ switch (_a.label) {
5126
+ case 0: return [4 /*yield*/, readFile(cacheFilehandler.filename, 'utf-8')];
5127
+ case 1:
5128
+ // Note: [0] In $convert we check that the file exists
5129
+ return [2 /*return*/, _a.sent()];
5130
+ }
5131
+ });
5132
+ });
5133
+ },
5134
+ asJson: function () {
5135
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asJson`');
5136
+ },
5137
+ asBlob: function () {
5138
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asBlob`');
5139
+ },
5140
+ };
5141
+ knowledge = markdownScraper.scrape(markdownSource, options);
5142
+ return [4 /*yield*/, cacheFilehandler.destroy()];
5143
+ case 2:
5144
+ _a.sent();
5145
+ return [2 /*return*/, knowledge];
5146
+ }
5147
+ });
5148
+ });
5149
+ },
5150
+ } /* TODO: [🦷] as const */;
5151
+ /**
5152
+ * TODO: [👣] Converted documents can act as cached items - there is no need to run conversion each time
5153
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5154
+ * TODO: [🪂] Do it in parallel 11:11
5155
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5156
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5157
+ */
5158
+
5159
+ /**
5160
+ * Scraper for .docx files
5161
+ *
5162
+ * @see `documentationUrl` for more details
5163
+ * @public exported from `@promptbook/core`
5164
+ */
5165
+ var legacyDocumentScraper = {
5166
+ /**
5167
+ * Mime types that this scraper can handle
5168
+ */
5169
+ mimeTypes: ['application/msword', 'text/rtf'],
5170
+ /**
5171
+ * Link to documentation
5172
+ */
5173
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5174
+ /**
5175
+ * Convert the `.doc` or `.rtf` to `.doc` file and returns intermediate source
5176
+ *
5177
+ * Note: `$` is used to indicate that this function is not a pure function - it leaves files on the disk and you are responsible for cleaning them by calling `destroy` method of returned object
5178
+ */
5179
+ $convert: function (source, options) {
5180
+ return __awaiter(this, void 0, void 0, function () {
5181
+ var _a, externalProgramsPaths, rootDirname, _b, cacheDirname, _c, isCacheCleaned, _d, isVerbose, extension, cacheFilehandler, documentSourceOutdirPathForLibreOffice_1, command_1, files_1, file;
5182
+ return __generator(this, function (_e) {
5183
+ switch (_e.label) {
5184
+ case 0:
5185
+ _a = options.externalProgramsPaths, externalProgramsPaths = _a === void 0 ? {} : _a, rootDirname = options.rootDirname, _b = options.cacheDirname, cacheDirname = _b === void 0 ? SCRAPE_CACHE_DIRNAME : _b, _c = options.isCacheCleaned, isCacheCleaned = _c === void 0 ? false : _c, _d = options.isVerbose, isVerbose = _d === void 0 ? IS_VERBOSE : _d;
5186
+ if (!$isRunningInNode()) {
5187
+ throw new KnowledgeScrapeError('Scraping .doc files is only supported in Node environment');
5188
+ }
5189
+ if (externalProgramsPaths.libreOfficePath === undefined) {
5190
+ throw new MissingToolsError('LibreOffice is required for scraping .doc and .rtf files');
5191
+ }
5192
+ if (source.filename === null) {
5193
+ // TODO: [🧠] Maybe save file as temporary
5194
+ throw new KnowledgeScrapeError('When parsing .doc or .rtf file, it must be real file in the file system');
5195
+ }
5196
+ extension = getFileExtension(source.filename);
5197
+ return [4 /*yield*/, getScraperIntermediateSource(source, {
5198
+ rootDirname: rootDirname,
5199
+ cacheDirname: cacheDirname,
5200
+ isCacheCleaned: isCacheCleaned,
5201
+ extension: 'docx',
5202
+ isVerbose: isVerbose,
5203
+ })];
5204
+ case 1:
5205
+ cacheFilehandler = _e.sent();
5206
+ if (isVerbose) {
5207
+ console.info("documentScraper: Converting .".concat(extension, " -> .docx"));
5208
+ }
5209
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5210
+ case 2:
5211
+ if (!!(_e.sent())) return [3 /*break*/, 8];
5212
+ documentSourceOutdirPathForLibreOffice_1 = join(dirname(cacheFilehandler.filename), 'libreoffice')
5213
+ .split('\\')
5214
+ .join('/');
5215
+ command_1 = "\"".concat(externalProgramsPaths.libreOfficePath, "\" --headless --convert-to docx \"").concat(source.filename, "\" --outdir \"").concat(documentSourceOutdirPathForLibreOffice_1, "\"");
5216
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook - this should trigger build polution error
5217
+ return [4 /*yield*/, $execCommand(command_1)];
5218
+ case 3:
5219
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook - this should trigger build polution error
5220
+ _e.sent();
5221
+ return [4 /*yield*/, readdir(documentSourceOutdirPathForLibreOffice_1)];
5222
+ case 4:
5223
+ files_1 = _e.sent();
5224
+ if (files_1.length !== 1) {
5225
+ throw new UnexpectedError(spaceTrim$1(function (block) { return "\n Expected exactly 1 file in the LibreOffice output directory, got ".concat(files_1.length, "\n\n The temporary folder:\n ").concat(block(documentSourceOutdirPathForLibreOffice_1), "\n\n Command:\n > ").concat(block(command_1), "\n "); }));
5226
+ }
5227
+ file = files_1[0];
5228
+ return [4 /*yield*/, rename(join(documentSourceOutdirPathForLibreOffice_1, file), cacheFilehandler.filename)];
5229
+ case 5:
5230
+ _e.sent();
5231
+ return [4 /*yield*/, rmdir(documentSourceOutdirPathForLibreOffice_1)];
5232
+ case 6:
5233
+ _e.sent();
5234
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5235
+ case 7:
5236
+ if (!(_e.sent())) {
5237
+ throw new UnexpectedError(spaceTrim$1(function (block) { return "\n File that was supposed to be created by LibreOffice does not exist for unknown reason\n\n Expected file:\n ".concat(block(cacheFilehandler.filename), "\n\n The temporary folder:\n ").concat(block(documentSourceOutdirPathForLibreOffice_1), "\n\n Command:\n > ").concat(block(command_1), "\n\n "); }));
5238
+ }
5239
+ _e.label = 8;
5240
+ case 8: return [2 /*return*/, cacheFilehandler];
5241
+ }
5242
+ });
5243
+ });
5244
+ },
5245
+ /**
5246
+ * Scrapes the `.doc` or `.rtf` file and returns the knowledge pieces or `null` if it can't scrape it
5247
+ */
5248
+ scrape: function (source, options) {
5249
+ return __awaiter(this, void 0, void 0, function () {
5250
+ var cacheFilehandler, markdownSource, knowledge;
5251
+ return __generator(this, function (_a) {
5252
+ switch (_a.label) {
5253
+ case 0: return [4 /*yield*/, legacyDocumentScraper.$convert(source, options)];
5254
+ case 1:
5255
+ cacheFilehandler = _a.sent();
5256
+ markdownSource = {
5257
+ source: source.source,
5258
+ filename: cacheFilehandler.filename,
5259
+ url: null,
5260
+ mimeType: 'text/markdown',
5261
+ asText: function () {
5262
+ throw new UnexpectedError('Did not expect that `documentScraper` would need to get the content `asText`');
5263
+ },
5264
+ asJson: function () {
5265
+ throw new UnexpectedError('Did not expect that `documentScraper` would need to get the content `asJson`');
5266
+ },
5267
+ asBlob: function () {
5268
+ throw new UnexpectedError('Did not expect that `documentScraper` would need to get the content `asBlob`');
5269
+ },
5270
+ };
5271
+ knowledge = documentScraper.scrape(markdownSource, options);
5272
+ return [4 /*yield*/, cacheFilehandler.destroy()];
5273
+ case 2:
5274
+ _a.sent();
5275
+ return [2 /*return*/, knowledge];
5276
+ }
5277
+ });
5278
+ });
5279
+ },
5280
+ } /* TODO: [🦷] as const */;
5281
+ /**
5282
+ * TODO: [👣] Converted documents can act as cached items - there is no need to run conversion each time
5283
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5284
+ * TODO: [🪂] Do it in parallel 11:11
5285
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5286
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5287
+ */
5288
+
5289
+ /**
5290
+ * Scraper for .docx files
5291
+ *
5292
+ * @see `documentationUrl` for more details
5293
+ * @public exported from `@promptbook/core`
5294
+ */
5295
+ var pdfScraper = {
5296
+ /**
5297
+ * Mime types that this scraper can handle
5298
+ */
5299
+ mimeTypes: ['application/pdf'],
5300
+ /**
5301
+ * Link to documentation
5302
+ */
5303
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5304
+ /**
5305
+ * Converts the `.pdf` file to `.md` file and returns intermediate source
5306
+ */
5307
+ $convert: function (source, options) {
5308
+ return __awaiter(this, void 0, void 0, function () {
5309
+ return __generator(this, function (_a) {
5310
+ TODO_USE(source);
5311
+ TODO_USE(options);
5312
+ throw new NotYetImplementedError('PDF conversion not yet implemented');
5313
+ });
5314
+ });
5315
+ },
5316
+ /**
5317
+ * Scrapes the `.pdf` file and returns the knowledge pieces or `null` if it can't scrape it
5318
+ */
5319
+ scrape: function (source, options) {
5320
+ return __awaiter(this, void 0, void 0, function () {
5321
+ return __generator(this, function (_a) {
5322
+ TODO_USE(source);
5323
+ TODO_USE(options);
5324
+ /*
5325
+ const {
5326
+ externalProgramsPaths = {},
5327
+ cacheDirname = SCRAPE_CACHE_DIRNAME,
5328
+ isCacheCleaned = false,
5329
+ isVerbose = IS_VERBOSE,
5330
+ } = options;
5331
+ */
5332
+ throw new NotYetImplementedError('PDF scraping not yet implemented');
5333
+ });
5334
+ });
5335
+ },
5336
+ } /* TODO: [🦷] as const */;
5337
+ /**
5338
+ * TODO: [👣] Converted documents can act as cached items - there is no need to run conversion each time
5339
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5340
+ * TODO: [🪂] Do it in parallel 11:11
5341
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5342
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5343
+ */
5344
+
5345
+ /**
5346
+ * A converter instance that uses showdown and highlight extensions
5347
+ *
5348
+ * @type {Converter}
5349
+ * @private for markdown and html knowledge scrapers
5350
+ */
5351
+ var markdownConverter = new Converter({
5352
+ flavor: 'github', // <- TODO: !!!!!! Explicitly specify the flavor of promptbook markdown
5353
+ /*
5354
+ > import showdownHighlight from 'showdown-highlight';
5355
+ > extensions: [
5356
+ > showdownHighlight({
5357
+ > // Whether to add the classes to the <pre> tag, default is false
5358
+ > pre: true,
5359
+ > // Whether to use hljs' auto language detection, default is true
5360
+ > auto_detection: true,
5361
+ > }),
5362
+ > ],
5363
+ */
5364
+ });
5365
+ /**
5366
+ * TODO: !!!!!! Figure out better name not to confuse with `Converter`
5367
+ * TODO: !!!!!! Lazy-make converter
5368
+ */
5369
+
5370
+ /**
5371
+ * Scraper for .docx files
5372
+ *
5373
+ * @see `documentationUrl` for more details
5374
+ * @public exported from `@promptbook/core`
5375
+ */
5376
+ var websiteScraper = {
5377
+ /**
5378
+ * Mime types that this scraper can handle
5379
+ */
5380
+ mimeTypes: ['text/html'],
5381
+ /**
5382
+ * Link to documentation
5383
+ */
5384
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5385
+ /**
5386
+ * Convert the website to `.md` file and returns intermediate source
5387
+ *
5388
+ * Note: `$` is used to indicate that this function is not a pure function - it leaves files on the disk and you are responsible for cleaning them by calling `destroy` method of returned object
5389
+ */
5390
+ $convert: function (source, options) {
5391
+ return __awaiter(this, void 0, void 0, function () {
5392
+ var
5393
+ // TODO: [🧠] Maybe in node use headless browser not just JSDOM
5394
+ // externalProgramsPaths = {},
5395
+ rootDirname, _a, cacheDirname, _b, isCacheCleaned, _c, isVerbose, jsdom, _d, reader, article, html, i, cacheFilehandler, markdown;
5396
+ return __generator(this, function (_e) {
5397
+ switch (_e.label) {
5398
+ case 0:
5399
+ rootDirname = options.rootDirname, _a = options.cacheDirname, cacheDirname = _a === void 0 ? SCRAPE_CACHE_DIRNAME : _a, _b = options.isCacheCleaned, isCacheCleaned = _b === void 0 ? false : _b, _c = options.isVerbose, isVerbose = _c === void 0 ? IS_VERBOSE : _c;
5400
+ // TODO: !!!!!! Does this work in browser? Make it work.
5401
+ if (source.url === null) {
5402
+ throw new KnowledgeScrapeError('Website scraper requires URL');
5403
+ }
5404
+ _d = JSDOM.bind;
5405
+ return [4 /*yield*/, source.asText()];
5406
+ case 1:
5407
+ jsdom = new (_d.apply(JSDOM, [void 0, _e.sent(), {
5408
+ url: source.url,
5409
+ }]))();
5410
+ reader = new Readability(jsdom.window.document);
5411
+ article = reader.parse();
5412
+ console.log(article);
5413
+ return [4 /*yield*/, forTime(10000)];
5414
+ case 2:
5415
+ _e.sent();
5416
+ html = (article === null || article === void 0 ? void 0 : article.content) || (article === null || article === void 0 ? void 0 : article.textContent) || jsdom.window.document.body.innerHTML;
5417
+ // Note: Unwrap html such as it is convertable by `markdownConverter`
5418
+ for (i = 0; i < 2; i++) {
5419
+ html = html.replace(/<div\s*(?:id="readability-page-\d+"\s+class="page")?>(.*)<\/div>/is, '$1');
5420
+ }
5421
+ if (html.includes('<div')) {
5422
+ html = (article === null || article === void 0 ? void 0 : article.textContent) || '';
5423
+ }
5424
+ return [4 /*yield*/, getScraperIntermediateSource(source, {
5425
+ rootDirname: rootDirname,
5426
+ cacheDirname: cacheDirname,
5427
+ isCacheCleaned: isCacheCleaned,
5428
+ extension: 'html',
5429
+ isVerbose: isVerbose,
5430
+ })];
5431
+ case 3:
5432
+ cacheFilehandler = _e.sent();
5433
+ return [4 /*yield*/, writeFile(cacheFilehandler.filename, html, 'utf-8')];
5434
+ case 4:
5435
+ _e.sent();
5436
+ markdown = markdownConverter.makeMarkdown(html, jsdom.window.document);
5437
+ return [2 /*return*/, __assign(__assign({}, cacheFilehandler), { markdown: markdown })];
5438
+ }
5439
+ });
5440
+ });
5441
+ },
5442
+ /**
5443
+ * Scrapes the website and returns the knowledge pieces or `null` if it can't scrape it
5444
+ */
5445
+ scrape: function (source, options) {
5446
+ return __awaiter(this, void 0, void 0, function () {
5447
+ var cacheFilehandler, markdownSource, knowledge;
5448
+ return __generator(this, function (_a) {
5449
+ switch (_a.label) {
5450
+ case 0: return [4 /*yield*/, websiteScraper.$convert(source, options)];
5451
+ case 1:
5452
+ cacheFilehandler = _a.sent();
5453
+ markdownSource = {
5454
+ source: source.source,
5455
+ filename: cacheFilehandler.filename,
5456
+ url: null,
5457
+ mimeType: 'text/markdown',
5458
+ asText: function () {
5459
+ return cacheFilehandler.markdown;
5460
+ },
5461
+ asJson: function () {
5462
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asJson`');
5463
+ },
5464
+ asBlob: function () {
5465
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asBlob`');
5466
+ },
5467
+ };
5468
+ knowledge = markdownScraper.scrape(markdownSource, options);
5469
+ return [4 /*yield*/, cacheFilehandler.destroy()];
5470
+ case 2:
5471
+ _a.sent();
5472
+ return [2 /*return*/, knowledge];
5473
+ }
5474
+ });
5475
+ });
5476
+ },
5477
+ } /* TODO: [🦷] as const */;
4450
5478
  /**
4451
- * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5479
+ * TODO: !!!!!! Put into separate package
5480
+ * TODO: [👣] Scraped website in .md can act as cache item - there is no need to run conversion each time
5481
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5482
+ * TODO: [🪂] Do it in parallel 11:11
5483
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5484
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
4452
5485
  */
4453
5486
 
5487
+ // TODO: [🦖] !!!!!! Pass scrapers as dependency,
4454
5488
  /**
4455
- * Creates executor function from pipeline and execution tools.
5489
+ * @@@
4456
5490
  *
4457
- * @returns The executor function
4458
- * @throws {PipelineLogicError} on logical error in the pipeline
4459
5491
  * @public exported from `@promptbook/core`
4460
5492
  */
4461
- function createPipelineExecutor(options) {
4462
- var _this = this;
4463
- var pipeline = options.pipeline, tools = options.tools, _a = options.settings, settings = _a === void 0 ? {} : _a;
4464
- var _b = settings.maxExecutionAttempts, maxExecutionAttempts = _b === void 0 ? MAX_EXECUTION_ATTEMPTS : _b, _c = settings.maxParallelCount, maxParallelCount = _c === void 0 ? MAX_PARALLEL_COUNT : _c, _d = settings.csvSettings, csvSettings = _d === void 0 ? DEFAULT_CSV_SETTINGS : _d, _e = settings.isVerbose, isVerbose = _e === void 0 ? IS_VERBOSE : _e, _f = settings.isNotPreparedWarningSupressed, isNotPreparedWarningSupressed = _f === void 0 ? false : _f;
4465
- validatePipeline(pipeline);
4466
- var pipelineIdentification = (function () {
4467
- // Note: This is a 😐 implementation of [🚞]
4468
- var _ = [];
4469
- if (pipeline.sourceFile !== undefined) {
4470
- _.push("File: ".concat(pipeline.sourceFile));
4471
- }
4472
- if (pipeline.pipelineUrl !== undefined) {
4473
- _.push("Url: ".concat(pipeline.pipelineUrl));
4474
- }
4475
- return _.join('\n');
4476
- })();
4477
- var preparedPipeline;
4478
- if (isPipelinePrepared(pipeline)) {
4479
- preparedPipeline = pipeline;
4480
- }
4481
- else if (isNotPreparedWarningSupressed !== true) {
4482
- console.warn(spaceTrim(function (block) { return "\n Pipeline is not prepared\n\n ".concat(block(pipelineIdentification), "\n\n It will be prepared ad-hoc before the first execution and **returned as `preparedPipeline` in `PipelineExecutorResult`**\n But it is recommended to prepare the pipeline during collection preparation\n\n @see more at https://ptbk.io/prepare-pipeline\n "); }));
4483
- }
4484
- var runCount = 0;
4485
- var pipelineExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
4486
- return __generator(this, function (_a) {
4487
- runCount++;
4488
- return [2 /*return*/, /* not await */ executePipeline({
4489
- pipeline: pipeline,
4490
- preparedPipeline: preparedPipeline,
4491
- setPreparedPipeline: function (newPreparedPipeline) {
4492
- preparedPipeline = newPreparedPipeline;
4493
- },
4494
- inputParameters: inputParameters,
4495
- tools: tools,
4496
- onProgress: onProgress,
4497
- pipelineIdentification: spaceTrim(function (block) { return "\n ".concat(block(pipelineIdentification), "\n ").concat(runCount === 1 ? '' : "Run #".concat(runCount), "\n "); }),
4498
- settings: {
4499
- maxExecutionAttempts: maxExecutionAttempts,
4500
- maxParallelCount: maxParallelCount,
4501
- csvSettings: csvSettings,
4502
- isVerbose: isVerbose,
4503
- isNotPreparedWarningSupressed: isNotPreparedWarningSupressed,
4504
- },
4505
- })];
4506
- });
4507
- }); };
4508
- return pipelineExecutor;
5493
+ var SCRAPERS = [
5494
+ markdownScraper,
5495
+ documentScraper,
5496
+ legacyDocumentScraper,
5497
+ pdfScraper,
5498
+ websiteScraper,
5499
+ // <- Note: [♓️] This is the order of the scrapers for knowledge, BUT consider some better (more explicit) way to do this
5500
+ ];
5501
+
5502
+ /**
5503
+ * Creates unique name for the source
5504
+ *
5505
+ * @private within the repository
5506
+ */
5507
+ function sourceContentToName(sourceContent) {
5508
+ // TODO: !!!!!! Better name for source than gibberish hash
5509
+ var hash = SHA256(hexEncoder.parse(JSON.stringify(sourceContent)))
5510
+ // <- TODO: [🥬] Encapsulate sha256 to some private utility function
5511
+ .toString( /* hex */)
5512
+ .substring(0, 20);
5513
+ // <- TODO: [🥬] Make some system for hashes and ids of promptbook
5514
+ var semanticName = normalizeToKebabCase(sourceContent.substring(0, 20));
5515
+ var pieces = ['source', semanticName, hash].filter(function (piece) { return piece !== ''; });
5516
+ var name = pieces.join('-').split('--').join('-');
5517
+ // <- TODO: Use MAX_FILENAME_LENGTH
5518
+ return name;
4509
5519
  }
4510
5520
  /**
4511
- * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5521
+ * TODO: [🐱‍🐉][🧠] Make some smart crop NOT source-i-m-pavol-a-develop-... BUT source-i-m-pavol-a-developer-...
5522
+ */
5523
+
5524
+ /**
5525
+ * Convert file extension to mime type
5526
+ *
5527
+ * @private within the repository
4512
5528
  */
5529
+ function extensionToMimeType(value) {
5530
+ return lookup(value) || 'application/octet-stream';
5531
+ }
4513
5532
 
4514
5533
  /**
4515
5534
  * @@@
4516
5535
  *
4517
- * @public exported from `@promptbook/core`
5536
+ * @private for scraper utilities
4518
5537
  */
4519
- function prepareKnowledgeFromMarkdown(knowledgeContent /* <- TODO: [🖖] (?maybe not) Always the file */, options) {
5538
+ function makeKnowledgeSourceHandler(knowledgeSource, options) {
5539
+ var _a;
4520
5540
  return __awaiter(this, void 0, void 0, function () {
4521
- var llmTools, _a, maxParallelCount, _b, isVerbose, collection, prepareKnowledgeFromMarkdownExecutor, _c, prepareTitleExecutor, _d, prepareKeywordsExecutor, _e, result, outputParameters, knowledgePiecesRaw, knowledgeTextPieces, knowledge;
4522
- var _f, _g, _h;
4523
- var _this = this;
4524
- return __generator(this, function (_j) {
4525
- switch (_j.label) {
5541
+ var sourceContent, name, _b, _c, rootDirname, _d, isVerbose, url, response_1, mimeType, filename_1, fileExtension, mimeType_1;
5542
+ return __generator(this, function (_e) {
5543
+ switch (_e.label) {
4526
5544
  case 0:
4527
- llmTools = options.llmTools, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
4528
- TODO_USE(maxParallelCount); // <- [🪂]
4529
- collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
4530
- _c = createPipelineExecutor;
4531
- _f = {};
4532
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md')];
5545
+ sourceContent = knowledgeSource.sourceContent;
5546
+ name = knowledgeSource.name;
5547
+ _b = options || {}, _c = _b.rootDirname, rootDirname = _c === void 0 ? null : _c, _d = _b.isVerbose, isVerbose = _d === void 0 ? IS_VERBOSE : _d;
5548
+ TODO_USE(isVerbose);
5549
+ if (!name) {
5550
+ name = sourceContentToName(sourceContent);
5551
+ }
5552
+ if (!isValidUrl(sourceContent)) return [3 /*break*/, 2];
5553
+ url = sourceContent;
5554
+ return [4 /*yield*/, fetch(url)];
4533
5555
  case 1:
4534
- prepareKnowledgeFromMarkdownExecutor = _c.apply(void 0, [(_f.pipeline = _j.sent(),
4535
- _f.tools = {
4536
- llm: llmTools,
5556
+ response_1 = _e.sent();
5557
+ mimeType = ((_a = response_1.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.split(';')[0]) || 'text/html';
5558
+ return [2 /*return*/, {
5559
+ source: name,
5560
+ filename: null,
5561
+ url: url,
5562
+ mimeType: mimeType,
5563
+ asBlob: function () {
5564
+ return __awaiter(this, void 0, void 0, function () {
5565
+ var content;
5566
+ return __generator(this, function (_a) {
5567
+ switch (_a.label) {
5568
+ case 0: return [4 /*yield*/, response_1.blob()];
5569
+ case 1:
5570
+ content = _a.sent();
5571
+ return [2 /*return*/, content];
5572
+ }
5573
+ });
5574
+ });
4537
5575
  },
4538
- _f)]);
4539
- _d = createPipelineExecutor;
4540
- _g = {};
4541
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md')];
4542
- case 2:
4543
- prepareTitleExecutor = _d.apply(void 0, [(_g.pipeline = _j.sent(),
4544
- _g.tools = {
4545
- llm: llmTools,
5576
+ asJson: function () {
5577
+ return __awaiter(this, void 0, void 0, function () {
5578
+ var content;
5579
+ return __generator(this, function (_a) {
5580
+ switch (_a.label) {
5581
+ case 0: return [4 /*yield*/, response_1.json()];
5582
+ case 1:
5583
+ content = _a.sent();
5584
+ return [2 /*return*/, content];
5585
+ }
5586
+ });
5587
+ });
4546
5588
  },
4547
- _g)]);
4548
- _e = createPipelineExecutor;
4549
- _h = {};
4550
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md')];
4551
- case 3:
4552
- prepareKeywordsExecutor = _e.apply(void 0, [(_h.pipeline = _j.sent(),
4553
- _h.tools = {
4554
- llm: llmTools,
5589
+ asText: function () {
5590
+ return __awaiter(this, void 0, void 0, function () {
5591
+ var content;
5592
+ return __generator(this, function (_a) {
5593
+ switch (_a.label) {
5594
+ case 0: return [4 /*yield*/, response_1.text()];
5595
+ case 1:
5596
+ content = _a.sent();
5597
+ return [2 /*return*/, content];
5598
+ }
5599
+ });
5600
+ });
4555
5601
  },
4556
- _h)]);
4557
- return [4 /*yield*/, prepareKnowledgeFromMarkdownExecutor({ knowledgeContent: knowledgeContent })];
4558
- case 4:
4559
- result = _j.sent();
4560
- assertsExecutionSuccessful(result);
4561
- outputParameters = result.outputParameters;
4562
- knowledgePiecesRaw = outputParameters.knowledgePieces;
4563
- knowledgeTextPieces = (knowledgePiecesRaw || '').split('\n---\n');
4564
- // <- TODO: [main] !!!!! Smarter split and filter out empty pieces
4565
- if (isVerbose) {
4566
- console.info('knowledgeTextPieces:', knowledgeTextPieces);
5602
+ }];
5603
+ case 2:
5604
+ if (!(isValidFilePath(sourceContent) || /\.[a-z]{1,10}$/i.exec(sourceContent))) return [3 /*break*/, 4];
5605
+ if (!$isRunningInNode()) {
5606
+ throw new EnvironmentMismatchError('Importing knowledge source file works only in Node.js environment');
4567
5607
  }
4568
- return [4 /*yield*/, Promise.all(
4569
- // TODO: [🪂] !! Do not send all at once but in chunks
4570
- knowledgeTextPieces.map(function (knowledgeTextPiece, i) { return __awaiter(_this, void 0, void 0, function () {
4571
- var name, title, knowledgePieceContent, keywords, index, titleResult, _a, titleRaw, keywordsResult, _b, keywordsRaw, embeddingResult, error_1;
4572
- return __generator(this, function (_c) {
4573
- switch (_c.label) {
4574
- case 0:
4575
- name = "piece-".concat(i);
4576
- title = spaceTrim$1(knowledgeTextPiece.substring(0, 100));
4577
- knowledgePieceContent = spaceTrim$1(knowledgeTextPiece);
4578
- keywords = [];
4579
- index = [];
4580
- _c.label = 1;
4581
- case 1:
4582
- _c.trys.push([1, 7, , 8]);
4583
- return [4 /*yield*/, prepareTitleExecutor({ knowledgePieceContent: knowledgePieceContent })];
4584
- case 2:
4585
- titleResult = _c.sent();
4586
- _a = titleResult.outputParameters.title, titleRaw = _a === void 0 ? 'Untitled' : _a;
4587
- title = spaceTrim$1(titleRaw) /* <- TODO: Maybe do in pipeline */;
4588
- name = titleToName(title);
4589
- return [4 /*yield*/, prepareKeywordsExecutor({ knowledgePieceContent: knowledgePieceContent })];
4590
- case 3:
4591
- keywordsResult = _c.sent();
4592
- _b = keywordsResult.outputParameters.keywords, keywordsRaw = _b === void 0 ? '' : _b;
4593
- keywords = (keywordsRaw || '')
4594
- .split(',')
4595
- .map(function (keyword) { return keyword.trim(); })
4596
- .filter(function (keyword) { return keyword !== ''; });
4597
- if (isVerbose) {
4598
- console.info("Keywords for \"".concat(title, "\":"), keywords);
5608
+ if (rootDirname === null) {
5609
+ throw new EnvironmentMismatchError('Can not import file knowledge in non-file pipeline');
5610
+ // <- TODO: [🧠] What is the best error type here`
5611
+ }
5612
+ filename_1 = join(rootDirname, sourceContent).split('\\').join('/');
5613
+ fileExtension = getFileExtension(filename_1);
5614
+ mimeType_1 = extensionToMimeType(fileExtension || '');
5615
+ return [4 /*yield*/, $isFileExisting(filename_1)];
5616
+ case 3:
5617
+ if (!(_e.sent())) {
5618
+ throw new NotFoundError(spaceTrim$1(function (block) { return "\n Can not make source handler for file which does not exist:\n\n File:\n ".concat(block(filename_1), "\n "); }));
5619
+ }
5620
+ // TODO: !!!!!! Test security file - file is scoped to the project (maybe do this in `filesystemTools`)
5621
+ return [2 /*return*/, {
5622
+ source: name,
5623
+ filename: filename_1,
5624
+ url: null,
5625
+ mimeType: mimeType_1,
5626
+ asBlob: function () {
5627
+ return __awaiter(this, void 0, void 0, function () {
5628
+ var content;
5629
+ return __generator(this, function (_a) {
5630
+ switch (_a.label) {
5631
+ case 0: return [4 /*yield*/, readFile(filename_1)];
5632
+ case 1:
5633
+ content = _a.sent();
5634
+ // <- Note: Its OK to use sync in tooling for tests
5635
+ return [2 /*return*/, new Blob([
5636
+ content,
5637
+ // <- TODO: !!!!!! Maybe not working
5638
+ ], { type: mimeType_1 })];
4599
5639
  }
4600
- if (!!llmTools.callEmbeddingModel) return [3 /*break*/, 4];
4601
- // TODO: [🟥] Detect browser / node and make it colorfull
4602
- console.error('No callEmbeddingModel function provided');
4603
- return [3 /*break*/, 6];
4604
- case 4: return [4 /*yield*/, llmTools.callEmbeddingModel({
4605
- title: "Embedding for ".concat(title) /* <- Note: No impact on embedding result itself, just for logging */,
4606
- parameters: {},
4607
- content: knowledgePieceContent,
4608
- modelRequirements: {
4609
- modelVariant: 'EMBEDDING',
4610
- },
4611
- })];
4612
- case 5:
4613
- embeddingResult = _c.sent();
4614
- index.push({
4615
- modelName: embeddingResult.modelName,
4616
- position: embeddingResult.content,
4617
- });
4618
- _c.label = 6;
4619
- case 6: return [3 /*break*/, 8];
4620
- case 7:
4621
- error_1 = _c.sent();
4622
- // Note: Here is expected error:
4623
- // > PipelineExecutionError: You have not provided any `LlmExecutionTools` that support model variant "EMBEDDING
4624
- if (!(error_1 instanceof PipelineExecutionError)) {
4625
- throw error_1;
5640
+ });
5641
+ });
5642
+ },
5643
+ asJson: function () {
5644
+ return __awaiter(this, void 0, void 0, function () {
5645
+ var _a, _b;
5646
+ return __generator(this, function (_c) {
5647
+ switch (_c.label) {
5648
+ case 0:
5649
+ _b = (_a = JSON).parse;
5650
+ return [4 /*yield*/, readFile(filename_1, 'utf-8')];
5651
+ case 1: return [2 /*return*/, _b.apply(_a, [_c.sent()])];
4626
5652
  }
4627
- // TODO: [🟥] Detect browser / node and make it colorfull
4628
- console.error(error_1, "<- Note: This error is not critical to prepare the pipeline, just knowledge pieces won't have embeddings");
4629
- return [3 /*break*/, 8];
4630
- case 8: return [2 /*return*/, {
4631
- name: name,
4632
- title: title,
4633
- content: knowledgePieceContent,
4634
- keywords: keywords,
4635
- index: index,
4636
- // <- TODO: [☀] sources,
4637
- }];
4638
- }
4639
- });
4640
- }); }))];
4641
- case 5:
4642
- knowledge = _j.sent();
4643
- return [2 /*return*/, knowledge];
5653
+ });
5654
+ });
5655
+ },
5656
+ asText: function () {
5657
+ return __awaiter(this, void 0, void 0, function () {
5658
+ return __generator(this, function (_a) {
5659
+ switch (_a.label) {
5660
+ case 0: return [4 /*yield*/, readFile(filename_1, 'utf-8')];
5661
+ case 1: return [2 /*return*/, _a.sent()];
5662
+ }
5663
+ });
5664
+ });
5665
+ },
5666
+ }];
5667
+ case 4: return [2 /*return*/, {
5668
+ source: name,
5669
+ filename: null,
5670
+ url: null,
5671
+ mimeType: 'text/markdown',
5672
+ asText: function () {
5673
+ return knowledgeSource.sourceContent;
5674
+ },
5675
+ asJson: function () {
5676
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asJson`');
5677
+ },
5678
+ asBlob: function () {
5679
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asBlob`');
5680
+ },
5681
+ }];
4644
5682
  }
4645
5683
  });
4646
5684
  });
4647
5685
  }
4648
- /**
4649
- * TODO: [🐝][🔼][main] !!! Export via `@promptbook/markdown`
4650
- * TODO: [🪂] Do it in parallel 11:11
4651
- * Note: No need to aggregate usage here, it is done by intercepting the llmTools
4652
- */
4653
5686
 
4654
5687
  /**
4655
5688
  * Prepares the knowle
@@ -4659,21 +5692,64 @@ function prepareKnowledgeFromMarkdown(knowledgeContent /* <- TODO: [🖖] (?mayb
4659
5692
  */
4660
5693
  function prepareKnowledgePieces(knowledgeSources, options) {
4661
5694
  return __awaiter(this, void 0, void 0, function () {
4662
- var _a, maxParallelCount, knowledgePrepared;
5695
+ var _a, maxParallelCount, rootDirname, _b, isVerbose, knowledgePreparedUnflatten, knowledgePrepared;
4663
5696
  var _this = this;
4664
- return __generator(this, function (_b) {
4665
- switch (_b.label) {
5697
+ return __generator(this, function (_c) {
5698
+ switch (_c.label) {
4666
5699
  case 0:
4667
- _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a;
4668
- knowledgePrepared = [];
4669
- return [4 /*yield*/, forEachAsync(knowledgeSources, { maxParallelCount: maxParallelCount }, function (knowledgeSource) { return __awaiter(_this, void 0, void 0, function () {
4670
- var partialPieces, pieces;
4671
- return __generator(this, function (_a) {
4672
- switch (_a.label) {
4673
- case 0: return [4 /*yield*/, prepareKnowledgeFromMarkdown(knowledgeSource.sourceContent, // <- TODO: [🐝][main] !!! Unhardcode markdown, detect which type it is - BE AWARE of big package size
4674
- options)];
5700
+ _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, rootDirname = options.rootDirname, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
5701
+ knowledgePreparedUnflatten = new Array(knowledgeSources.length);
5702
+ return [4 /*yield*/, forEachAsync(knowledgeSources, { maxParallelCount: maxParallelCount }, function (knowledgeSource, index) { return __awaiter(_this, void 0, void 0, function () {
5703
+ var partialPieces, sourceHandler, SCRAPERS_1, SCRAPERS_1_1, scraper, partialPiecesUnchecked, e_1_1, pieces;
5704
+ var e_1, _a;
5705
+ return __generator(this, function (_b) {
5706
+ switch (_b.label) {
5707
+ case 0:
5708
+ partialPieces = null;
5709
+ return [4 /*yield*/, makeKnowledgeSourceHandler(knowledgeSource, { rootDirname: rootDirname, isVerbose: isVerbose })];
4675
5710
  case 1:
4676
- partialPieces = _a.sent();
5711
+ sourceHandler = _b.sent();
5712
+ _b.label = 2;
5713
+ case 2:
5714
+ _b.trys.push([2, 7, 8, 9]);
5715
+ SCRAPERS_1 = __values(SCRAPERS), SCRAPERS_1_1 = SCRAPERS_1.next();
5716
+ _b.label = 3;
5717
+ case 3:
5718
+ if (!!SCRAPERS_1_1.done) return [3 /*break*/, 6];
5719
+ scraper = SCRAPERS_1_1.value;
5720
+ if (!scraper.mimeTypes.includes(sourceHandler.mimeType)
5721
+ // <- TODO: [🦔] Implement mime-type wildcards
5722
+ ) {
5723
+ return [3 /*break*/, 5];
5724
+ }
5725
+ return [4 /*yield*/, scraper.scrape(sourceHandler, options)];
5726
+ case 4:
5727
+ partialPiecesUnchecked = _b.sent();
5728
+ if (partialPiecesUnchecked !== null) {
5729
+ partialPieces = partialPiecesUnchecked;
5730
+ return [3 /*break*/, 6];
5731
+ }
5732
+ _b.label = 5;
5733
+ case 5:
5734
+ SCRAPERS_1_1 = SCRAPERS_1.next();
5735
+ return [3 /*break*/, 3];
5736
+ case 6: return [3 /*break*/, 9];
5737
+ case 7:
5738
+ e_1_1 = _b.sent();
5739
+ e_1 = { error: e_1_1 };
5740
+ return [3 /*break*/, 9];
5741
+ case 8:
5742
+ try {
5743
+ if (SCRAPERS_1_1 && !SCRAPERS_1_1.done && (_a = SCRAPERS_1.return)) _a.call(SCRAPERS_1);
5744
+ }
5745
+ finally { if (e_1) throw e_1.error; }
5746
+ return [7 /*endfinally*/];
5747
+ case 9:
5748
+ if (partialPieces === null) {
5749
+ throw new KnowledgeScrapeError(spaceTrim$1(function (block) { return "\n Cannot scrape knowledge from source: ".concat(knowledgeSource.sourceContent, "\n\n No scraper found for the mime type \"").concat(sourceHandler.mimeType, "\"\n\n Available scrapers:\n ").concat(block(SCRAPERS.flatMap(function (scraper) { return scraper.mimeTypes; })
5750
+ .map(function (mimeType) { return "- ".concat(mimeType); })
5751
+ .join('\n')), "\n\n\n "); }));
5752
+ }
4677
5753
  pieces = partialPieces.map(function (partialPiece) { return (__assign(__assign({}, partialPiece), { sources: [
4678
5754
  {
4679
5755
  name: knowledgeSource.name,
@@ -4681,13 +5757,14 @@ function prepareKnowledgePieces(knowledgeSources, options) {
4681
5757
  // <- TODO: [❎]
4682
5758
  },
4683
5759
  ] })); });
4684
- knowledgePrepared.push.apply(knowledgePrepared, __spreadArray([], __read(pieces), false));
5760
+ knowledgePreparedUnflatten[index] = pieces;
4685
5761
  return [2 /*return*/];
4686
5762
  }
4687
5763
  });
4688
5764
  }); })];
4689
5765
  case 1:
4690
- _b.sent();
5766
+ _c.sent();
5767
+ knowledgePrepared = knowledgePreparedUnflatten.flat();
4691
5768
  return [2 /*return*/, knowledgePrepared];
4692
5769
  }
4693
5770
  });
@@ -4704,7 +5781,7 @@ TODO: [🧊] This is how it can look in future
4704
5781
  >
4705
5782
  > export async function prepareKnowledgePieces(
4706
5783
  > knowledge: PrepareKnowledgeKnowledge,
4707
- > options: PrepareOptions,
5784
+ > options: PrepareAndScrapeOptions,
4708
5785
  > ):
4709
5786
  */
4710
5787
  /**
@@ -4817,6 +5894,9 @@ function preparePersona(personaDescription, options) {
4817
5894
  switch (_d.label) {
4818
5895
  case 0:
4819
5896
  llmTools = options.llmTools, _a = options.isVerbose, isVerbose = _a === void 0 ? IS_VERBOSE : _a;
5897
+ if (llmTools === undefined) {
5898
+ throw new MissingToolsError('LLM tools are required for preparing persona');
5899
+ }
4820
5900
  collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
4821
5901
  _b = createPipelineExecutor;
4822
5902
  _c = {};
@@ -4960,7 +6040,7 @@ function prepareTemplates(pipeline, options) {
4960
6040
  */
4961
6041
  function preparePipeline(pipeline, options) {
4962
6042
  return __awaiter(this, void 0, void 0, function () {
4963
- var llmTools, _a, maxParallelCount, _b, isVerbose, parameters, templates,
6043
+ var llmTools, rootDirname, _a, maxParallelCount, _b, isVerbose, parameters, templates,
4964
6044
  /*
4965
6045
  <- TODO: [🧠][🪑] `promptbookVersion` */
4966
6046
  knowledgeSources /*
@@ -4973,8 +6053,11 @@ function preparePipeline(pipeline, options) {
4973
6053
  if (isPipelinePrepared(pipeline)) {
4974
6054
  return [2 /*return*/, pipeline];
4975
6055
  }
4976
- llmTools = options.llmTools, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
6056
+ llmTools = options.llmTools, rootDirname = options.rootDirname, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
4977
6057
  parameters = pipeline.parameters, templates = pipeline.templates, knowledgeSources = pipeline.knowledgeSources, personas = pipeline.personas;
6058
+ if (llmTools === undefined) {
6059
+ throw new MissingToolsError('LLM tools are required for preparing the pipeline');
6060
+ }
4978
6061
  llmToolsWithUsage = countTotalUsage(llmTools);
4979
6062
  currentPreparation = {
4980
6063
  id: 1,
@@ -4996,6 +6079,7 @@ function preparePipeline(pipeline, options) {
4996
6079
  switch (_a.label) {
4997
6080
  case 0: return [4 /*yield*/, preparePersona(persona.description, {
4998
6081
  llmTools: llmToolsWithUsage,
6082
+ rootDirname: rootDirname,
4999
6083
  maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
5000
6084
  isVerbose: isVerbose,
5001
6085
  })];
@@ -5010,11 +6094,7 @@ function preparePipeline(pipeline, options) {
5010
6094
  case 1:
5011
6095
  _c.sent();
5012
6096
  knowledgeSourcesPrepared = knowledgeSources.map(function (source) { return (__assign(__assign({}, source), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
5013
- return [4 /*yield*/, prepareKnowledgePieces(knowledgeSources /* <- TODO: [🧊] {knowledgeSources, knowledgePieces} */, {
5014
- llmTools: llmToolsWithUsage,
5015
- maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
5016
- isVerbose: isVerbose,
5017
- })];
6097
+ return [4 /*yield*/, prepareKnowledgePieces(knowledgeSources /* <- TODO: [🧊] {knowledgeSources, knowledgePieces} */, __assign(__assign({}, options), { llmTools: llmToolsWithUsage, rootDirname: rootDirname, maxParallelCount: maxParallelCount /* <- TODO: [🪂] */, isVerbose: isVerbose }))];
5018
6098
  case 2:
5019
6099
  partialknowledgePiecesPrepared = _c.sent();
5020
6100
  knowledgePiecesPrepared = partialknowledgePiecesPrepared.map(function (piece) { return (__assign(__assign({}, piece), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
@@ -5024,6 +6104,7 @@ function preparePipeline(pipeline, options) {
5024
6104
  knowledgePiecesCount: knowledgePiecesPrepared.length,
5025
6105
  }, {
5026
6106
  llmTools: llmToolsWithUsage,
6107
+ rootDirname: rootDirname,
5027
6108
  maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
5028
6109
  isVerbose: isVerbose,
5029
6110
  })];
@@ -5046,36 +6127,10 @@ function preparePipeline(pipeline, options) {
5046
6127
  * @see https://docs.anthropic.com/en/docs/test-and-evaluate/strengthen-guardrails/increase-consistency#specify-the-desired-output-format
5047
6128
  */
5048
6129
 
5049
- /**
5050
- * Tests if given string is valid URL.
5051
- *
5052
- * Note: This does not check if the file exists only if the path is valid
5053
- * @public exported from `@promptbook/utils`
5054
- */
5055
- function isValidFilePath(filePath) {
5056
- if (typeof filePath !== 'string') {
5057
- return false;
5058
- }
5059
- var filePathSlashes = filePath.split('\\').join('/');
5060
- // Absolute Unix path: /hello.txt
5061
- if (/^(\/)/i.test(filePathSlashes)) {
5062
- return true;
5063
- }
5064
- // Absolute Windows path: /hello.txt
5065
- if (/^([A-Z]{1,2}:\/?)\//i.test(filePathSlashes)) {
5066
- return true;
5067
- }
5068
- // Relative path: ./hello.txt
5069
- if (/^(\.\.?\/)+/i.test(filePathSlashes)) {
5070
- return true;
5071
- }
5072
- return false;
5073
- }
5074
-
5075
6130
  /**
5076
6131
  * Parses the knowledge command
5077
6132
  *
5078
- * @see ./KNOWLEDGE-README.md for more details
6133
+ * @see `documentationUrl` for more details
5079
6134
  * @private within the commands folder
5080
6135
  */
5081
6136
  var knowledgeCommandParser = {
@@ -5093,7 +6148,7 @@ var knowledgeCommandParser = {
5093
6148
  */
5094
6149
  description: "Tells promptbook which external knowledge to use",
5095
6150
  /**
5096
- * Link to discussion
6151
+ * Link to documentation
5097
6152
  */
5098
6153
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/41',
5099
6154
  /**
@@ -5137,11 +6192,8 @@ var knowledgeCommandParser = {
5137
6192
  */
5138
6193
  $applyToPipelineJson: function (command, $pipelineJson) {
5139
6194
  var sourceContent = command.sourceContent;
5140
- var name = 'source-' + sha256(hexEncoder.parse(JSON.stringify(sourceContent))).toString( /* hex */);
5141
- // <- TODO: [🥬] Encapsulate sha256 to some private utility function
5142
- // <- TODO: This should be replaced with a better name later in preparation (done with some propper LLM summarization)
5143
6195
  $pipelineJson.knowledgeSources.push({
5144
- name: name,
6196
+ name: sourceContentToName(sourceContent),
5145
6197
  sourceContent: sourceContent,
5146
6198
  });
5147
6199
  },
@@ -5189,7 +6241,7 @@ var TemplateTypes = [
5189
6241
  /**
5190
6242
  * Parses the template command
5191
6243
  *
5192
- * @see ./TEMPLATE-README.md for more details
6244
+ * @see `documentationUrl` for more details
5193
6245
  * @private within the commands folder
5194
6246
  */
5195
6247
  var templateCommandParser = {
@@ -5225,7 +6277,7 @@ var templateCommandParser = {
5225
6277
  */
5226
6278
  description: "What should the code template template do",
5227
6279
  /**
5228
- * Link to discussion
6280
+ * Link to documentation
5229
6281
  */
5230
6282
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/64',
5231
6283
  /**
@@ -5450,7 +6502,7 @@ function parseNumber(value) {
5450
6502
  /**
5451
6503
  * Parses the expect command
5452
6504
  *
5453
- * @see ./EXPECT-README.md for more details
6505
+ * @see `documentationUrl` for more details
5454
6506
  * @private within the commands folder
5455
6507
  */
5456
6508
  var expectCommandParser = {
@@ -5468,7 +6520,7 @@ var expectCommandParser = {
5468
6520
  */
5469
6521
  description: spaceTrim$1("\n Expect command describes the desired output of the template (after post-processing)\n It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.\n "),
5470
6522
  /**
5471
- * Link to discussion
6523
+ * Link to documentation
5472
6524
  */
5473
6525
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/30',
5474
6526
  /**
@@ -5628,10 +6680,6 @@ function normalizeTo_SCREAMING_CASE(text) {
5628
6680
  charType = 'NUMBER';
5629
6681
  normalizedChar = char;
5630
6682
  }
5631
- else if (/^\/$/.test(char)) {
5632
- charType = 'SLASH';
5633
- normalizedChar = char;
5634
- }
5635
6683
  else {
5636
6684
  charType = 'OTHER';
5637
6685
  normalizedChar = '_';
@@ -5838,7 +6886,7 @@ function validateParameterName(parameterName) {
5838
6886
  *
5839
6887
  * Note: @@@ This command is used as foreach for new commands - it should NOT be used in any `.ptbk.md` file
5840
6888
  *
5841
- * @see ./FOREACH-README.md for more details <- TODO: @@@ Write theese README files OR remove this link + add annotation here (to all commands)
6889
+ * @see `documentationUrl` for more details
5842
6890
  * @private within the commands folder
5843
6891
  */
5844
6892
  var foreachCommandParser = {
@@ -5860,7 +6908,7 @@ var foreachCommandParser = {
5860
6908
  */
5861
6909
  description: "@@",
5862
6910
  /**
5863
- * Link to discussion
6911
+ * Link to documentation
5864
6912
  */
5865
6913
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/148',
5866
6914
  /**
@@ -5995,7 +7043,7 @@ var foreachCommandParser = {
5995
7043
  /**
5996
7044
  * Parses the format command
5997
7045
  *
5998
- * @see ./FORMAT-README.md for more details
7046
+ * @see `documentationUrl` for more details
5999
7047
  * @private within the commands folder
6000
7048
  */
6001
7049
  var formatCommandParser = {
@@ -6013,7 +7061,7 @@ var formatCommandParser = {
6013
7061
  */
6014
7062
  description: spaceTrim$1("\n Format command describes the desired output of the template (after post-processing)\n It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.\n "),
6015
7063
  /**
6016
- * Link to discussion
7064
+ * Link to documentation
6017
7065
  */
6018
7066
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/30',
6019
7067
  /**
@@ -6069,7 +7117,7 @@ var formatCommandParser = {
6069
7117
  /**
6070
7118
  * Parses the joker command
6071
7119
  *
6072
- * @see ./JOKER-README.md for more details
7120
+ * @see `documentationUrl` for more details
6073
7121
  * @private within the commands folder
6074
7122
  */
6075
7123
  var jokerCommandParser = {
@@ -6087,7 +7135,7 @@ var jokerCommandParser = {
6087
7135
  */
6088
7136
  description: "Joker parameter is used instead of executing the template result if jokers value meets the expectations requirements",
6089
7137
  /**
6090
- * Link to discussion
7138
+ * Link to documentation
6091
7139
  */
6092
7140
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/66',
6093
7141
  /**
@@ -6148,7 +7196,7 @@ var MODEL_VARIANTS = ['COMPLETION', 'CHAT', 'EMBEDDING' /* <- TODO [🏳] */ /*
6148
7196
  /**
6149
7197
  * Parses the model command
6150
7198
  *
6151
- * @see ./MODEL-README.md for more details
7199
+ * @see `documentationUrl` for more details
6152
7200
  * @private within the commands folder
6153
7201
  */
6154
7202
  var modelCommandParser = {
@@ -6166,7 +7214,7 @@ var modelCommandParser = {
6166
7214
  */
6167
7215
  description: "Tells which `modelRequirements` (for example which model) to use for the prompt template execution",
6168
7216
  /**
6169
- * Link to discussion
7217
+ * Link to documentation
6170
7218
  */
6171
7219
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/67',
6172
7220
  /**
@@ -6248,7 +7296,11 @@ var modelCommandParser = {
6248
7296
  // TODO: [🚜] DRY
6249
7297
  if ($templateJson.modelRequirements[command.key] !== undefined) {
6250
7298
  if ($templateJson.modelRequirements[command.key] === command.value) {
6251
- console.warn("Multiple commands `MODEL ".concat(command.key, " ").concat(command.value, "` in the template \"").concat($templateJson.title || $templateJson.name, "\""));
7299
+ console.warn("Multiple commands `MODEL ".concat({
7300
+ modelName: 'NAME',
7301
+ modelVariant: 'VARIANT',
7302
+ maxTokens: '???',
7303
+ }[command.key], " ").concat(command.value, "` in the template \"").concat($templateJson.title || $templateJson.name, "\""));
6252
7304
  }
6253
7305
  else {
6254
7306
  throw new ParseError(spaceTrim$1("\n Redefinition of MODEL `".concat(command.key, "` in the template \"").concat($templateJson.title || $templateJson.name, "\"\n\n You have used:\n - MODEL ").concat(command.key, " ").concat($templateJson.modelRequirements[command.key], "\n - MODEL ").concat(command.key, " ").concat(command.value, "\n ")));
@@ -6291,7 +7343,7 @@ var modelCommandParser = {
6291
7343
  /**
6292
7344
  * Parses the parameter command
6293
7345
  *
6294
- * @see ./PARAMETER-README.md for more details
7346
+ * @see `documentationUrl` for more details
6295
7347
  * @private within the commands folder
6296
7348
  */
6297
7349
  var parameterCommandParser = {
@@ -6316,7 +7368,7 @@ var parameterCommandParser = {
6316
7368
  */
6317
7369
  description: "Describes one parameter of the template",
6318
7370
  /**
6319
- * Link to discussion
7371
+ * Link to documentation
6320
7372
  */
6321
7373
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/68',
6322
7374
  /**
@@ -6401,7 +7453,7 @@ var parameterCommandParser = {
6401
7453
  /**
6402
7454
  * Parses the persona command
6403
7455
  *
6404
- * @see ./PERSONA-README.md for more details
7456
+ * @see `documentationUrl` for more details
6405
7457
  * @private within the commands folder
6406
7458
  */
6407
7459
  var personaCommandParser = {
@@ -6423,7 +7475,7 @@ var personaCommandParser = {
6423
7475
  */
6424
7476
  description: "Persona command is used to specify who the system is, it will be transformed into system message, top_t,...",
6425
7477
  /**
6426
- * Link to discussion
7478
+ * Link to documentation
6427
7479
  */
6428
7480
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/22',
6429
7481
  /**
@@ -6539,7 +7591,7 @@ function isValidJavascriptName(javascriptName) {
6539
7591
  /**
6540
7592
  * Parses the postprocess command
6541
7593
  *
6542
- * @see ./POSTPROCESS-README.md for more details
7594
+ * @see `documentationUrl` for more details
6543
7595
  * @private within the commands folder
6544
7596
  */
6545
7597
  var postprocessCommandParser = {
@@ -6558,7 +7610,7 @@ var postprocessCommandParser = {
6558
7610
  */
6559
7611
  description: "Defines the postprocess function to be used on the result from LLM and before the result is validated",
6560
7612
  /**
6561
- * Link to discussion
7613
+ * Link to documentation
6562
7614
  */
6563
7615
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/31',
6564
7616
  /**
@@ -6619,7 +7671,7 @@ var postprocessCommandParser = {
6619
7671
  /**
6620
7672
  * Parses the PROMPTBOOK_VERSION command
6621
7673
  *
6622
- * @see ./PROMPTBOOK_VERSION-README.md for more details
7674
+ * @see `documentationUrl` for more details
6623
7675
  * @private within the commands folder
6624
7676
  */
6625
7677
  var promptbookVersionCommandParser = {
@@ -6638,7 +7690,7 @@ var promptbookVersionCommandParser = {
6638
7690
  */
6639
7691
  description: "Which version of the promptbook is the .ptbk.md using",
6640
7692
  /**
6641
- * Link to discussion
7693
+ * Link to documentation
6642
7694
  */
6643
7695
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/69',
6644
7696
  /**
@@ -6697,7 +7749,7 @@ var promptbookVersionCommandParser = {
6697
7749
  /**
6698
7750
  * Parses the url command
6699
7751
  *
6700
- * @see ./URL-README.md for more details
7752
+ * @see `documentationUrl` for more details
6701
7753
  * @private within the commands folder
6702
7754
  */
6703
7755
  var urlCommandParser = {
@@ -6720,7 +7772,7 @@ var urlCommandParser = {
6720
7772
  */
6721
7773
  description: "Declares unique URL for the pipeline",
6722
7774
  /**
6723
- * Link to discussion
7775
+ * Link to documentation
6724
7776
  */
6725
7777
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/70',
6726
7778
  /**
@@ -6800,7 +7852,7 @@ var urlCommandParser = {
6800
7852
  /**
6801
7853
  * Parses the action command
6802
7854
  *
6803
- * @see ./ACTION-README.md for more details
7855
+ * @see `documentationUrl` for more details
6804
7856
  * @private within the commands folder
6805
7857
  */
6806
7858
  var actionCommandParser = {
@@ -6818,7 +7870,7 @@ var actionCommandParser = {
6818
7870
  */
6819
7871
  description: "Actions influences from the pipeline or template into external world. Like turning on a light, sending an email, etc.",
6820
7872
  /**
6821
- * Link to discussion
7873
+ * Link to documentation
6822
7874
  */
6823
7875
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/72',
6824
7876
  /**
@@ -6870,7 +7922,7 @@ var actionCommandParser = {
6870
7922
  /**
6871
7923
  * Parses the instrument command
6872
7924
  *
6873
- * @see ./INSTRUMENT-README.md for more details
7925
+ * @see `documentationUrl` for more details
6874
7926
  * @private within the commands folder
6875
7927
  */
6876
7928
  var instrumentCommandParser = {
@@ -6888,7 +7940,7 @@ var instrumentCommandParser = {
6888
7940
  */
6889
7941
  description: "Instrument command is used to specify the instrument to be used in the pipeline or template like search, calculate, etc.",
6890
7942
  /**
6891
- * Link to discussion
7943
+ * Link to documentation
6892
7944
  */
6893
7945
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/71',
6894
7946
  /**
@@ -6943,7 +7995,7 @@ var instrumentCommandParser = {
6943
7995
  *
6944
7996
  * Note: @@@ This command is used as boilerplate for new commands - it should NOT be used in any `.ptbk.md` file
6945
7997
  *
6946
- * @see ./BOILERPLATE-README.md for more details <- TODO: @@@ Write theese README files OR remove this link + add annotation here (to all commands)
7998
+ * @see `documentationUrl` for more details
6947
7999
  * @private within the commands folder
6948
8000
  */
6949
8001
  var boilerplateCommandParser = {
@@ -6965,7 +8017,7 @@ var boilerplateCommandParser = {
6965
8017
  */
6966
8018
  description: "@@",
6967
8019
  /**
6968
- * Link to discussion
8020
+ * Link to documentation
6969
8021
  */
6970
8022
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
6971
8023
  /**
@@ -7815,16 +8867,17 @@ function pipelineStringToJsonSync(pipelineString) {
7815
8867
  * @public exported from `@promptbook/core`
7816
8868
  */
7817
8869
  function pipelineStringToJson(pipelineString, options) {
7818
- if (options === void 0) { options = { llmTools: null }; }
7819
8870
  return __awaiter(this, void 0, void 0, function () {
7820
8871
  var llmTools, pipelineJson;
7821
8872
  return __generator(this, function (_a) {
7822
8873
  switch (_a.label) {
7823
8874
  case 0:
7824
- llmTools = options.llmTools;
8875
+ llmTools = (options || {}).llmTools;
7825
8876
  pipelineJson = pipelineStringToJsonSync(pipelineString);
7826
- if (!(llmTools !== null)) return [3 /*break*/, 2];
7827
- return [4 /*yield*/, preparePipeline(pipelineJson, { llmTools: llmTools })];
8877
+ if (!(llmTools !== undefined)) return [3 /*break*/, 2];
8878
+ return [4 /*yield*/, preparePipeline(pipelineJson, options || {
8879
+ rootDirname: null,
8880
+ })];
7828
8881
  case 1:
7829
8882
  pipelineJson = _a.sent();
7830
8883
  _a.label = 2;
@@ -7841,51 +8894,6 @@ function pipelineStringToJson(pipelineString, options) {
7841
8894
  * TODO: [🧠] Should be in generated JSON file GENERATOR_WARNING
7842
8895
  */
7843
8896
 
7844
- /**
7845
- * Detects if the code is running in a Node.js environment
7846
- *
7847
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
7848
- *
7849
- * @public exported from `@promptbook/utils`
7850
- */
7851
- var $isRunningInNode = new Function("\n try {\n return this === global;\n } catch (e) {\n return false;\n }\n");
7852
-
7853
- /**
7854
- * Checks if the file exists
7855
- *
7856
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the filesystem
7857
- *
7858
- * @private within the repository
7859
- */
7860
- function $isFileExisting(filePath) {
7861
- return __awaiter(this, void 0, void 0, function () {
7862
- var isReadAccessAllowed, isFile;
7863
- return __generator(this, function (_a) {
7864
- switch (_a.label) {
7865
- case 0: return [4 /*yield*/, access(filePath, constants.R_OK)
7866
- .then(function () { return true; })
7867
- .catch(function () { return false; })];
7868
- case 1:
7869
- isReadAccessAllowed = _a.sent();
7870
- if (!isReadAccessAllowed) {
7871
- return [2 /*return*/, false];
7872
- }
7873
- return [4 /*yield*/, stat(filePath)
7874
- .then(function (fileStat) { return fileStat.isFile(); })
7875
- .catch(function () { return false; })];
7876
- case 2:
7877
- isFile = _a.sent();
7878
- return [2 /*return*/, isFile];
7879
- }
7880
- });
7881
- });
7882
- }
7883
- /**
7884
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
7885
- * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
7886
- * TODO: [🖇] What about symlinks?
7887
- */
7888
-
7889
8897
  /**
7890
8898
  * Checks if the directory exists
7891
8899
  *
@@ -7898,9 +8906,13 @@ function $isDirectoryExisting(directoryPath) {
7898
8906
  var isReadAccessAllowed, isDirectory;
7899
8907
  return __generator(this, function (_a) {
7900
8908
  switch (_a.label) {
7901
- case 0: return [4 /*yield*/, access(directoryPath, constants.R_OK)
7902
- .then(function () { return true; })
7903
- .catch(function () { return false; })];
8909
+ case 0:
8910
+ if (!$isRunningInNode()) {
8911
+ throw new EnvironmentMismatchError('Function `$isDirectoryExisting` works only in Node environment.js');
8912
+ }
8913
+ return [4 /*yield*/, access(directoryPath, constants.R_OK)
8914
+ .then(function () { return true; })
8915
+ .catch(function () { return false; })];
7904
8916
  case 1:
7905
8917
  isReadAccessAllowed = _a.sent();
7906
8918
  if (!isReadAccessAllowed) {
@@ -7917,7 +8929,7 @@ function $isDirectoryExisting(directoryPath) {
7917
8929
  });
7918
8930
  }
7919
8931
  /**
7920
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
8932
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
7921
8933
  * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
7922
8934
  * TODO: [🧠][📂] "directory" vs "folder"
7923
8935
  * TODO: [🖇] What about symlinks?
@@ -7939,7 +8951,11 @@ function $listAllFiles(path, isRecursive) {
7939
8951
  var e_1, _g;
7940
8952
  return __generator(this, function (_h) {
7941
8953
  switch (_h.label) {
7942
- case 0: return [4 /*yield*/, $isDirectoryExisting(path)];
8954
+ case 0:
8955
+ if (!$isRunningInNode()) {
8956
+ throw new EnvironmentMismatchError('Function `$listAllFiles` works only in Node environment.js');
8957
+ }
8958
+ return [4 /*yield*/, $isDirectoryExisting(path)];
7943
8959
  case 1:
7944
8960
  if (!(_h.sent())) {
7945
8961
  throw new Error("Directory \"".concat(path, "\" does not exist or is not readable"));
@@ -7950,9 +8966,11 @@ function $listAllFiles(path, isRecursive) {
7950
8966
  })];
7951
8967
  case 2:
7952
8968
  dirents = _h.sent();
7953
- fileNames = dirents.filter(function (dirent) { return dirent.isFile(); }).map(function (_a) {
8969
+ fileNames = dirents
8970
+ .filter(function (dirent) { return dirent.isFile(); })
8971
+ .map(function (_a) {
7954
8972
  var name = _a.name;
7955
- return join(path, name);
8973
+ return join(path, name).split('\\').join('/');
7956
8974
  });
7957
8975
  if (!isRecursive) return [3 /*break*/, 10];
7958
8976
  _h.label = 3;
@@ -7969,7 +8987,7 @@ function $listAllFiles(path, isRecursive) {
7969
8987
  _f = [[]];
7970
8988
  return [4 /*yield*/, $listAllFiles(subPath, isRecursive)];
7971
8989
  case 5:
7972
- _d.apply(_c, _e.concat([__spreadArray.apply(void 0, _f.concat([__read.apply(void 0, [(_h.sent())]), false]))]));
8990
+ _d.apply(_c, _e.concat([__spreadArray.apply(void 0, _f.concat([__read.apply(void 0, [(_h.sent()).map(function (filename) { return filename; })]), false]))]));
7973
8991
  _h.label = 6;
7974
8992
  case 6:
7975
8993
  _b = _a.next();
@@ -7991,7 +9009,8 @@ function $listAllFiles(path, isRecursive) {
7991
9009
  });
7992
9010
  }
7993
9011
  /**
7994
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9012
+ * TODO: [😶] Unite floder listing
9013
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
7995
9014
  * TODO: [🖇] What about symlinks?
7996
9015
  */
7997
9016
 
@@ -8094,7 +9113,7 @@ function createCollectionFromPromise(promptbookSourcesPromiseOrFactory) {
8094
9113
  */
8095
9114
  function createCollectionFromDirectory(path, options) {
8096
9115
  return __awaiter(this, void 0, void 0, function () {
8097
- var makedLibraryFilePath, _a, _b, isRecursive, _c, isVerbose, _d, isLazyLoaded, _e, isCrashedOnError, collection;
9116
+ var makedLibraryFilePath, _a, llmTools, _b, isRecursive, _c, isVerbose, _d, isLazyLoaded, _e, isCrashedOnError, collection;
8098
9117
  var _this = this;
8099
9118
  return __generator(this, function (_f) {
8100
9119
  switch (_f.label) {
@@ -8102,7 +9121,7 @@ function createCollectionFromDirectory(path, options) {
8102
9121
  if (!$isRunningInNode()) {
8103
9122
  throw new Error('Function `createCollectionFromDirectory` can only be run in Node.js environment because it reads the file system.');
8104
9123
  }
8105
- makedLibraryFilePath = join$1(path, "".concat(PIPELINE_COLLECTION_BASE_FILENAME, ".json"));
9124
+ makedLibraryFilePath = join(path, "".concat(PIPELINE_COLLECTION_BASE_FILENAME, ".json"));
8106
9125
  return [4 /*yield*/, $isFileExisting(makedLibraryFilePath)];
8107
9126
  case 1:
8108
9127
  if (!(_f.sent())) {
@@ -8113,7 +9132,7 @@ function createCollectionFromDirectory(path, options) {
8113
9132
  // TODO: !! Implement;
8114
9133
  // TODO: [🌗]
8115
9134
  }
8116
- _a = options || {}, _b = _a.isRecursive, isRecursive = _b === void 0 ? true : _b, _c = _a.isVerbose, isVerbose = _c === void 0 ? IS_VERBOSE : _c, _d = _a.isLazyLoaded, isLazyLoaded = _d === void 0 ? false : _d, _e = _a.isCrashedOnError, isCrashedOnError = _e === void 0 ? true : _e;
9135
+ _a = options || {}, llmTools = _a.llmTools, _b = _a.isRecursive, isRecursive = _b === void 0 ? true : _b, _c = _a.isVerbose, isVerbose = _c === void 0 ? IS_VERBOSE : _c, _d = _a.isLazyLoaded, isLazyLoaded = _d === void 0 ? false : _d, _e = _a.isCrashedOnError, isCrashedOnError = _e === void 0 ? true : _e;
8117
9136
  collection = createCollectionFromPromise(function () { return __awaiter(_this, void 0, void 0, function () {
8118
9137
  var fileNames, collection, _loop_1, fileNames_1, fileNames_1_1, fileName, e_1_1;
8119
9138
  var e_1, _a;
@@ -8139,20 +9158,24 @@ function createCollectionFromDirectory(path, options) {
8139
9158
  });
8140
9159
  collection = new Map();
8141
9160
  _loop_1 = function (fileName) {
8142
- var sourceFile, pipeline, pipelineString, _c, _d, existing, error_1, wrappedErrorMessage;
9161
+ var sourceFile, rootDirname, pipeline, pipelineString, _c, _d, existing, error_1, wrappedErrorMessage;
8143
9162
  return __generator(this, function (_e) {
8144
9163
  switch (_e.label) {
8145
9164
  case 0:
8146
9165
  sourceFile = './' + fileName.split('\\').join('/');
9166
+ rootDirname = dirname(sourceFile).split('\\').join('/');
8147
9167
  _e.label = 1;
8148
9168
  case 1:
8149
9169
  _e.trys.push([1, 8, , 9]);
8150
9170
  pipeline = null;
8151
9171
  if (!fileName.endsWith('.ptbk.md')) return [3 /*break*/, 4];
8152
- return [4 /*yield*/, readFile(fileName, 'utf8')];
9172
+ return [4 /*yield*/, readFile(fileName, 'utf-8')];
8153
9173
  case 2:
8154
9174
  pipelineString = (_e.sent());
8155
- return [4 /*yield*/, pipelineStringToJson(pipelineString, options)];
9175
+ return [4 /*yield*/, pipelineStringToJson(pipelineString, {
9176
+ llmTools: llmTools,
9177
+ rootDirname: rootDirname,
9178
+ })];
8156
9179
  case 3:
8157
9180
  pipeline = _e.sent();
8158
9181
  pipeline = __assign(__assign({}, pipeline), { sourceFile: sourceFile });
@@ -8160,7 +9183,7 @@ function createCollectionFromDirectory(path, options) {
8160
9183
  case 4:
8161
9184
  if (!fileName.endsWith('.ptbk.json')) return [3 /*break*/, 6];
8162
9185
  _d = (_c = JSON).parse;
8163
- return [4 /*yield*/, readFile(fileName, 'utf8')];
9186
+ return [4 /*yield*/, readFile(fileName, 'utf-8')];
8164
9187
  case 5:
8165
9188
  // TODO: Handle non-valid JSON files
8166
9189
  pipeline = _d.apply(_c, [_e.sent()]);
@@ -8268,7 +9291,7 @@ function createCollectionFromDirectory(path, options) {
8268
9291
  });
8269
9292
  }
8270
9293
  /**
8271
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9294
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8272
9295
  * TODO: [🖇] What about symlinks? Maybe option isSymlinksFollowed
8273
9296
  */
8274
9297
 
@@ -8359,7 +9382,7 @@ function createLlmToolsFromConfigurationFromEnv() {
8359
9382
  * TODO: Add Azure OpenAI
8360
9383
  * TODO: [🧠][🍛]
8361
9384
  * TODO: [🧠] Is there some meaningfull way how to test this util
8362
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9385
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8363
9386
  * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
8364
9387
  * TODO: This should be maybe not under `_common` but under `utils`
8365
9388
  * TODO: [🧠] Maybe pass env as argument
@@ -8536,7 +9559,7 @@ function createLlmToolsFromEnv(options) {
8536
9559
  * TODO: @@@ write `createLlmToolsFromEnv` vs `createLlmToolsFromConfigurationFromEnv` vs `createLlmToolsFromConfiguration`
8537
9560
  * TODO: [🧠][🍛] Which name is better `createLlmToolsFromEnv` or `createLlmToolsFromEnvironment`?
8538
9561
  * TODO: [🧠] Is there some meaningfull way how to test this util
8539
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9562
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8540
9563
  * TODO: [🥃] Allow `ptbk make` without llm tools
8541
9564
  * TODO: This should be maybe not under `_common` but under `utils`
8542
9565
  */
@@ -8601,40 +9624,32 @@ function stringifyPipelineJson(pipeline) {
8601
9624
  * TODO: [🍙] Make some standard order of json properties
8602
9625
  */
8603
9626
 
8604
- /**
8605
- * @@@
8606
- *
8607
- * @private for `FilesStorage`
8608
- */
8609
- function nameToSubfolderPath(name) {
8610
- return [name.substr(0, 1).toLowerCase(), name.substr(1, 1).toLowerCase()];
8611
- }
8612
-
8613
9627
  /**
8614
9628
  * @@@
8615
9629
  *
8616
9630
  * @public exported from `@promptbook/node`
8617
9631
  */
8618
- var FilesStorage = /** @class */ (function () {
8619
- function FilesStorage(options) {
9632
+ var FileCacheStorage = /** @class */ (function () {
9633
+ function FileCacheStorage(options) {
8620
9634
  this.options = options;
8621
9635
  if (!$isRunningInNode()) {
8622
- throw new EnvironmentMismatchError("FilesStorage works only in Node.js environment");
9636
+ throw new EnvironmentMismatchError("FileCacheStorage works only in Node.js environment");
8623
9637
  }
8624
9638
  }
8625
9639
  /**
8626
9640
  * @@@
8627
9641
  */
8628
- FilesStorage.prototype.getFilenameForKey = function (key) {
9642
+ FileCacheStorage.prototype.getFilenameForKey = function (key) {
9643
+ // TODO: [👬] DRY
8629
9644
  var name = titleToName(key);
8630
9645
  var hash = sha256(hexEncoder.parse(name)).toString( /* hex */);
8631
9646
  // <- TODO: [🥬] Encapsulate sha256 to some private utility function
8632
- return join$1.apply(void 0, __spreadArray(__spreadArray([this.options.cacheFolderPath], __read(nameToSubfolderPath(hash /* <- TODO: [🎎] Maybe add some SHA256 prefix */)), false), ["".concat(name.substring(0, MAX_FILENAME_LENGTH), ".json")], false));
9647
+ return join.apply(void 0, __spreadArray(__spreadArray([this.options.rootFolderPath], __read(nameToSubfolderPath(hash /* <- TODO: [🎎] Maybe add some SHA256 prefix */)), false), ["".concat(name.substring(0, MAX_FILENAME_LENGTH), ".json")], false));
8633
9648
  };
8634
9649
  /**
8635
9650
  * @@@ Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
8636
9651
  */
8637
- FilesStorage.prototype.getItem = function (key) {
9652
+ FileCacheStorage.prototype.getItem = function (key) {
8638
9653
  return __awaiter(this, void 0, void 0, function () {
8639
9654
  var filename, fileContent, value;
8640
9655
  return __generator(this, function (_a) {
@@ -8659,7 +9674,7 @@ var FilesStorage = /** @class */ (function () {
8659
9674
  /**
8660
9675
  * @@@ Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
8661
9676
  */
8662
- FilesStorage.prototype.setItem = function (key, value) {
9677
+ FileCacheStorage.prototype.setItem = function (key, value) {
8663
9678
  return __awaiter(this, void 0, void 0, function () {
8664
9679
  var filename, fileContent;
8665
9680
  return __generator(this, function (_a) {
@@ -8684,7 +9699,7 @@ var FilesStorage = /** @class */ (function () {
8684
9699
  /**
8685
9700
  * @@@ Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
8686
9701
  */
8687
- FilesStorage.prototype.removeItem = function (key) {
9702
+ FileCacheStorage.prototype.removeItem = function (key) {
8688
9703
  return __awaiter(this, void 0, void 0, function () {
8689
9704
  var filename;
8690
9705
  return __generator(this, function (_a) {
@@ -8701,12 +9716,62 @@ var FilesStorage = /** @class */ (function () {
8701
9716
  });
8702
9717
  });
8703
9718
  };
8704
- return FilesStorage;
9719
+ return FileCacheStorage;
8705
9720
  }());
8706
9721
  /**
8707
9722
  * TODO: [🌗] Maybe some checkers, not all valid JSONs are desired and valid values
8708
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9723
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
9724
+ */
9725
+
9726
+ /**
9727
+ * Run multiple commands in a shell in sequence
9728
+ *
9729
+ * Note: There are 2 similar functions in the codebase:
9730
+ * - `$execCommand` which runs a single command
9731
+ * - `$execCommands` which runs multiple commands
9732
+ *
9733
+ * @public exported from `@promptbook/node`
9734
+ */
9735
+ function $execCommands(_a) {
9736
+ var commands = _a.commands, cwd = _a.cwd, crashOnError = _a.crashOnError;
9737
+ return __awaiter(this, void 0, void 0, function () {
9738
+ var commands_1, commands_1_1, command, e_1_1;
9739
+ var e_1, _b;
9740
+ return __generator(this, function (_c) {
9741
+ switch (_c.label) {
9742
+ case 0:
9743
+ _c.trys.push([0, 5, 6, 7]);
9744
+ commands_1 = __values(commands), commands_1_1 = commands_1.next();
9745
+ _c.label = 1;
9746
+ case 1:
9747
+ if (!!commands_1_1.done) return [3 /*break*/, 4];
9748
+ command = commands_1_1.value;
9749
+ return [4 /*yield*/, $execCommand({ command: command, cwd: cwd, crashOnError: crashOnError })];
9750
+ case 2:
9751
+ _c.sent();
9752
+ _c.label = 3;
9753
+ case 3:
9754
+ commands_1_1 = commands_1.next();
9755
+ return [3 /*break*/, 1];
9756
+ case 4: return [3 /*break*/, 7];
9757
+ case 5:
9758
+ e_1_1 = _c.sent();
9759
+ e_1 = { error: e_1_1 };
9760
+ return [3 /*break*/, 7];
9761
+ case 6:
9762
+ try {
9763
+ if (commands_1_1 && !commands_1_1.done && (_b = commands_1.return)) _b.call(commands_1);
9764
+ }
9765
+ finally { if (e_1) throw e_1.error; }
9766
+ return [7 /*endfinally*/];
9767
+ case 7: return [2 /*return*/];
9768
+ }
9769
+ });
9770
+ });
9771
+ }
9772
+ /**
9773
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8709
9774
  */
8710
9775
 
8711
- export { FilesStorage, PROMPTBOOK_VERSION, createCollectionFromDirectory, createLlmToolsFromConfigurationFromEnv, createLlmToolsFromEnv };
9776
+ export { $execCommand, $execCommands, FileCacheStorage, PROMPTBOOK_VERSION, createCollectionFromDirectory, createLlmToolsFromConfigurationFromEnv, createLlmToolsFromEnv };
8712
9777
  //# sourceMappingURL=index.es.js.map