@promptbook/node 0.72.0-5 → 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/umd/index.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('fs/promises'), require('path'), require('spacetrim'), require('prettier'), require('prettier/parser-html'), require('waitasecond'), require('papaparse'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('path/posix'), require('dotenv')) :
3
- typeof define === 'function' && define.amd ? define(['exports', 'colors', 'fs/promises', 'path', 'spacetrim', 'prettier', 'prettier/parser-html', 'waitasecond', 'papaparse', 'crypto-js/enc-hex', 'crypto-js/sha256', 'path/posix', 'dotenv'], factory) :
4
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-node"] = {}, global.colors, global.promises, global.path, global.spaceTrim, global.prettier, global.parserHtml, global.waitasecond, global.papaparse, global.hexEncoder, global.sha256, global.posix, global.dotenv));
5
- })(this, (function (exports, colors, promises, path, spaceTrim, prettier, parserHtml, waitasecond, papaparse, hexEncoder, sha256, posix, dotenv) { 'use strict';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('fs/promises'), require('path'), require('spacetrim'), require('prettier'), require('prettier/parser-html'), require('child_process'), require('waitasecond'), require('crypto-js'), require('crypto-js/enc-hex'), require('papaparse'), require('@mozilla/readability'), require('jsdom'), require('showdown'), require('mime-types'), require('dotenv'), require('crypto-js/sha256')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'colors', 'fs/promises', 'path', 'spacetrim', 'prettier', 'prettier/parser-html', 'child_process', 'waitasecond', 'crypto-js', 'crypto-js/enc-hex', 'papaparse', '@mozilla/readability', 'jsdom', 'showdown', 'mime-types', 'dotenv', 'crypto-js/sha256'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-node"] = {}, global.colors, global.promises, global.path, global.spaceTrim, global.prettier, global.parserHtml, global.child_process, global.waitasecond, global.cryptoJs, global.hexEncoder, global.papaparse, global.readability, global.jsdom, global.showdown, global.mimeTypes, global.dotenv, global.sha256));
5
+ })(this, (function (exports, colors, promises, path, spaceTrim, prettier, parserHtml, child_process, waitasecond, cryptoJs, hexEncoder, papaparse, readability, jsdom, showdown, mimeTypes, dotenv, sha256) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
@@ -28,14 +28,14 @@
28
28
  var spaceTrim__default = /*#__PURE__*/_interopDefaultLegacy(spaceTrim);
29
29
  var parserHtml__default = /*#__PURE__*/_interopDefaultLegacy(parserHtml);
30
30
  var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
31
- var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
32
31
  var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
32
+ var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
33
33
 
34
34
  // ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
35
35
  /**
36
36
  * The version of the Promptbook library
37
37
  */
38
- var PROMPTBOOK_VERSION = '0.72.0-4';
38
+ var PROMPTBOOK_VERSION = '0.72.0-6';
39
39
  // TODO: [main] !!!! List here all the versions and annotate + put into script
40
40
 
41
41
  /*! *****************************************************************************
@@ -401,6 +401,14 @@
401
401
  * @public exported from `@promptbook/core`
402
402
  */
403
403
  var MAX_FILENAME_LENGTH = 30;
404
+ /**
405
+ * Where to store the scrape cache
406
+ *
407
+ * Note: When the folder does not exist, it is created recursively
408
+ *
409
+ * @public exported from `@promptbook/core`
410
+ */
411
+ var SCRAPE_CACHE_DIRNAME = '/.promptbook/scrape-cache';
404
412
  /**
405
413
  * The name of the builded pipeline collection made by CLI `ptbk make` and for lookup in `createCollectionFromDirectory`
406
414
  *
@@ -720,6 +728,22 @@
720
728
  * TODO: [🧠] Should be in generated .ptbk.md file GENERATOR_WARNING
721
729
  */
722
730
 
731
+ /**
732
+ * This error indicates that the promptbook can not retrieve knowledge from external sources
733
+ *
734
+ * @public exported from `@promptbook/core`
735
+ */
736
+ var KnowledgeScrapeError = /** @class */ (function (_super) {
737
+ __extends(KnowledgeScrapeError, _super);
738
+ function KnowledgeScrapeError(message) {
739
+ var _this = _super.call(this, message) || this;
740
+ _this.name = 'KnowledgeScrapeError';
741
+ Object.setPrototypeOf(_this, KnowledgeScrapeError.prototype);
742
+ return _this;
743
+ }
744
+ return KnowledgeScrapeError;
745
+ }(Error));
746
+
723
747
  /**
724
748
  * Async version of Array.forEach
725
749
  *
@@ -727,6 +751,7 @@
727
751
  * @param options - Options for the function
728
752
  * @param callbackfunction - Function to call for each item
729
753
  * @public exported from `@promptbook/utils`
754
+ * @deprecated [🪂] Use queues instead
730
755
  */
731
756
  function forEachAsync(array, options, callbackfunction) {
732
757
  return __awaiter(this, void 0, void 0, function () {
@@ -796,1105 +821,1399 @@
796
821
  }
797
822
 
798
823
  /**
799
- * Represents the usage with no resources consumed
800
- *
801
- * @public exported from `@promptbook/core`
802
- */
803
- var ZERO_USAGE = $deepFreeze({
804
- price: { value: 0 },
805
- input: {
806
- tokensCount: { value: 0 },
807
- charactersCount: { value: 0 },
808
- wordsCount: { value: 0 },
809
- sentencesCount: { value: 0 },
810
- linesCount: { value: 0 },
811
- paragraphsCount: { value: 0 },
812
- pagesCount: { value: 0 },
813
- },
814
- output: {
815
- tokensCount: { value: 0 },
816
- charactersCount: { value: 0 },
817
- wordsCount: { value: 0 },
818
- sentencesCount: { value: 0 },
819
- linesCount: { value: 0 },
820
- paragraphsCount: { value: 0 },
821
- pagesCount: { value: 0 },
822
- },
823
- });
824
- /**
825
- * Represents the usage with unknown resources consumed
826
- *
827
- * @public exported from `@promptbook/core`
828
- */
829
- $deepFreeze({
830
- price: { value: 0, isUncertain: true },
831
- input: {
832
- tokensCount: { value: 0, isUncertain: true },
833
- charactersCount: { value: 0, isUncertain: true },
834
- wordsCount: { value: 0, isUncertain: true },
835
- sentencesCount: { value: 0, isUncertain: true },
836
- linesCount: { value: 0, isUncertain: true },
837
- paragraphsCount: { value: 0, isUncertain: true },
838
- pagesCount: { value: 0, isUncertain: true },
839
- },
840
- output: {
841
- tokensCount: { value: 0, isUncertain: true },
842
- charactersCount: { value: 0, isUncertain: true },
843
- wordsCount: { value: 0, isUncertain: true },
844
- sentencesCount: { value: 0, isUncertain: true },
845
- linesCount: { value: 0, isUncertain: true },
846
- paragraphsCount: { value: 0, isUncertain: true },
847
- pagesCount: { value: 0, isUncertain: true },
848
- },
849
- });
850
-
851
- 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"}];
852
-
853
- /**
854
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
824
+ * This error type indicates that some tools are missing for pipeline execution or preparation
855
825
  *
856
826
  * @public exported from `@promptbook/core`
857
827
  */
858
- var ParseError = /** @class */ (function (_super) {
859
- __extends(ParseError, _super);
860
- function ParseError(message) {
861
- var _this = _super.call(this, message) || this;
862
- _this.name = 'ParseError';
863
- Object.setPrototypeOf(_this, ParseError.prototype);
828
+ var MissingToolsError = /** @class */ (function (_super) {
829
+ __extends(MissingToolsError, _super);
830
+ function MissingToolsError(message) {
831
+ var _this = _super.call(this, spaceTrim.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;
832
+ _this.name = 'MissingToolsError';
833
+ Object.setPrototypeOf(_this, MissingToolsError.prototype);
864
834
  return _this;
865
835
  }
866
- return ParseError;
836
+ return MissingToolsError;
867
837
  }(Error));
838
+
868
839
  /**
869
- * TODO: Maybe split `ParseError` and `ApplyError`
840
+ * Detects if the code is running in a Node.js environment
841
+ *
842
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
843
+ *
844
+ * @public exported from `@promptbook/utils`
870
845
  */
846
+ var $isRunningInNode = new Function("\n try {\n return this === global;\n } catch (e) {\n return false;\n }\n");
871
847
 
872
848
  /**
873
- * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
849
+ * This error type indicates that you try to use a feature that is not available in the current environment
874
850
  *
875
851
  * @public exported from `@promptbook/core`
876
852
  */
877
- var PipelineLogicError = /** @class */ (function (_super) {
878
- __extends(PipelineLogicError, _super);
879
- function PipelineLogicError(message) {
853
+ var EnvironmentMismatchError = /** @class */ (function (_super) {
854
+ __extends(EnvironmentMismatchError, _super);
855
+ function EnvironmentMismatchError(message) {
880
856
  var _this = _super.call(this, message) || this;
881
- _this.name = 'PipelineLogicError';
882
- Object.setPrototypeOf(_this, PipelineLogicError.prototype);
857
+ _this.name = 'EnvironmentMismatchError';
858
+ Object.setPrototypeOf(_this, EnvironmentMismatchError.prototype);
883
859
  return _this;
884
860
  }
885
- return PipelineLogicError;
861
+ return EnvironmentMismatchError;
886
862
  }(Error));
887
863
 
888
864
  /**
889
- * Tests if given string is valid semantic version
890
- *
891
- * Note: There are two simmilar functions:
892
- * - `isValidSemanticVersion` which tests any semantic version
893
- * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
865
+ * Normalize options for `execCommand` and `execCommands`
894
866
  *
895
- * @public exported from `@promptbook/utils`
867
+ * @private internal utility of `execCommand` and `execCommands`
896
868
  */
897
- function isValidSemanticVersion(version) {
898
- if (typeof version !== 'string') {
899
- return false;
869
+ function execCommandNormalizeOptions(options) {
870
+ var _a;
871
+ var _b, _c, _d;
872
+ var command;
873
+ var cwd;
874
+ var crashOnError;
875
+ var args = [];
876
+ var timeout;
877
+ if (typeof options === 'string') {
878
+ // TODO: [1] DRY default values
879
+ command = options;
880
+ cwd = process.cwd();
881
+ crashOnError = true;
882
+ timeout = Infinity;
900
883
  }
901
- if (version.startsWith('0.0.0')) {
902
- return false;
884
+ else {
885
+ /*
886
+ TODO:
887
+ if ((options as any).commands !== undefined) {
888
+ commands = (options as any).commands;
889
+ } else {
890
+ commands = [(options as any).command];
891
+ }
892
+ */
893
+ // TODO: [1] DRY default values
894
+ command = options.command;
895
+ cwd = (_b = options.cwd) !== null && _b !== void 0 ? _b : process.cwd();
896
+ crashOnError = (_c = options.crashOnError) !== null && _c !== void 0 ? _c : true;
897
+ timeout = (_d = options.timeout) !== null && _d !== void 0 ? _d : Infinity;
898
+ }
899
+ // TODO: /(-[a-zA-Z0-9-]+\s+[^\s]*)|[^\s]*/g
900
+ var _ = Array.from(command.matchAll(/(".*")|([^\s]*)/g))
901
+ .map(function (_a) {
902
+ var _b = __read(_a, 1), match = _b[0];
903
+ return match;
904
+ })
905
+ .filter(function (arg) { return arg !== ''; });
906
+ if (_.length > 1) {
907
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
908
+ _a = __read(_), command = _a[0], args = _a.slice(1);
903
909
  }
904
- return /^\d+\.\d+\.\d+(-\d+)?$/i.test(version);
905
- }
906
-
907
- /**
908
- * Tests if given string is valid promptbook version
909
- * It looks into list of known promptbook versions.
910
- *
911
- * @see https://www.npmjs.com/package/promptbook?activeTab=versions
912
- * 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.
913
- * Note: There are two simmilar functions:
914
- * - `isValidSemanticVersion` which tests any semantic version
915
- * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
916
- *
917
- * @public exported from `@promptbook/utils`
918
- */
919
- function isValidPromptbookVersion(version) {
920
- if (!isValidSemanticVersion(version)) {
921
- return false;
910
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
911
+ if (options.args) {
912
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
913
+ args = __spreadArray(__spreadArray([], __read(args), false), __read(options.args), false);
922
914
  }
923
- if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
924
- return false;
915
+ var humanReadableCommand = !['npx', 'npm'].includes(command) ? command : args[0];
916
+ if (['ts-node'].includes(humanReadableCommand)) {
917
+ humanReadableCommand += " ".concat(args[1]);
925
918
  }
926
- // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_VERSIONS
927
- return true;
919
+ return { command: command, humanReadableCommand: humanReadableCommand, args: args, cwd: cwd, crashOnError: crashOnError, timeout: timeout };
928
920
  }
921
+ // TODO: This should show type error> execCommandNormalizeOptions({ command: '', commands: [''] });
929
922
 
930
923
  /**
931
- * Checks if an URL is reserved for private networks or localhost.
924
+ * Run one command in a shell
932
925
  *
933
- * Note: There are two simmilar functions:
934
- * - `isUrlOnPrivateNetwork` which tests full URL
935
- * - `isHostnameOnPrivateNetwork` *(this one)* which tests just hostname
926
+ * Note: There are 2 similar functions in the codebase:
927
+ * - `$execCommand` which runs a single command
928
+ * - `$execCommands` which runs multiple commands
936
929
  *
937
- * @public exported from `@promptbook/utils`
930
+ * @public exported from `@promptbook/node`
938
931
  */
939
- function isHostnameOnPrivateNetwork(hostname) {
940
- if (hostname === 'example.com' ||
941
- hostname === 'localhost' ||
942
- hostname.endsWith('.localhost') ||
943
- hostname.endsWith('.local') ||
944
- hostname.endsWith('.test') ||
945
- hostname === '127.0.0.1' ||
946
- hostname === '::1') {
947
- return true;
948
- }
949
- if (hostname.includes(':')) {
950
- // IPv6
951
- var ipParts = hostname.split(':');
952
- return ipParts[0] === 'fc00' || ipParts[0] === 'fd00' || ipParts[0] === 'fe80';
953
- }
954
- else {
955
- // IPv4
956
- var ipParts = hostname.split('.').map(function (part) { return Number.parseInt(part, 10); });
957
- return (ipParts[0] === 10 ||
958
- (ipParts[0] === 172 && ipParts[1] >= 16 && ipParts[1] <= 31) ||
959
- (ipParts[0] === 192 && ipParts[1] === 168));
960
- }
932
+ function $execCommand(options) {
933
+ if (!$isRunningInNode()) {
934
+ throw new EnvironmentMismatchError('Function `$execCommand` can run only in Node environment.js');
935
+ }
936
+ return new Promise(
937
+ // <- TODO: [🧱] Implement in a functional (not new Class) way
938
+ function (resolve, reject) {
939
+ // eslint-disable-next-line prefer-const
940
+ var _a = execCommandNormalizeOptions(options), command = _a.command, humanReadableCommand = _a.humanReadableCommand, args = _a.args, cwd = _a.cwd, crashOnError = _a.crashOnError, timeout = _a.timeout;
941
+ if (timeout !== Infinity) {
942
+ // TODO: In waitasecond forTime(Infinity) should be equivalent to forEver()
943
+ waitasecond.forTime(timeout).then(function () {
944
+ if (crashOnError) {
945
+ reject(new Error("Command \"".concat(humanReadableCommand, "\" exceeded time limit of ").concat(timeout, "ms")));
946
+ }
947
+ else {
948
+ console.warn("Command \"".concat(humanReadableCommand, "\" exceeded time limit of ").concat(timeout, "ms but continues running"));
949
+ resolve('Command exceeded time limit');
950
+ }
951
+ });
952
+ }
953
+ if (/^win/.test(process.platform) && ['npm', 'npx'].includes(command)) {
954
+ command = "".concat(command, ".cmd");
955
+ }
956
+ // !!!!!! Verbose mode - to all consoles
957
+ console.info(colors__default["default"].yellow(cwd) + ' ' + colors__default["default"].green(command) + ' ' + colors__default["default"].blue(args.join(' ')));
958
+ try {
959
+ var commandProcess = child_process.spawn(command, args, { cwd: cwd, shell: true });
960
+ commandProcess.on('message', function (message) {
961
+ console.info({ message: message });
962
+ });
963
+ var output_1 = [];
964
+ commandProcess.stdout.on('data', function (stdout) {
965
+ output_1.push(stdout.toString());
966
+ console.info(stdout.toString());
967
+ });
968
+ commandProcess.stderr.on('data', function (stderr) {
969
+ output_1.push(stderr.toString());
970
+ if (stderr.toString().trim()) {
971
+ console.warn(stderr.toString());
972
+ }
973
+ });
974
+ var finishWithCode = function (code) {
975
+ if (code !== 0) {
976
+ if (crashOnError) {
977
+ reject(new Error(output_1.join('\n').trim() ||
978
+ "Command \"".concat(humanReadableCommand, "\" exited with code ").concat(code)));
979
+ }
980
+ else {
981
+ console.warn("Command \"".concat(humanReadableCommand, "\" exited with code ").concat(code));
982
+ resolve(spaceTrim.spaceTrim(output_1.join('\n')));
983
+ }
984
+ }
985
+ else {
986
+ resolve(spaceTrim.spaceTrim(output_1.join('\n')));
987
+ }
988
+ };
989
+ commandProcess.on('close', finishWithCode);
990
+ commandProcess.on('exit', finishWithCode);
991
+ commandProcess.on('disconnect', function () {
992
+ // Note: Unexpected disconnection should always result in rejection
993
+ reject(new Error("Command \"".concat(humanReadableCommand, "\" disconnected")));
994
+ });
995
+ commandProcess.on('error', function (error) {
996
+ if (crashOnError) {
997
+ reject(new Error("Command \"".concat(humanReadableCommand, "\" failed: \n").concat(error.message)));
998
+ }
999
+ else {
1000
+ console.warn(error);
1001
+ resolve(spaceTrim.spaceTrim(output_1.join('\n')));
1002
+ }
1003
+ });
1004
+ }
1005
+ catch (error) {
1006
+ // Note: Unexpected error in sync code should always result in rejection
1007
+ reject(error);
1008
+ }
1009
+ });
961
1010
  }
1011
+ /**
1012
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
1013
+ */
962
1014
 
963
1015
  /**
964
- * Checks if an IP address or hostname is reserved for private networks or localhost.
1016
+ * Checks if the file exists
965
1017
  *
966
- * Note: There are two simmilar functions:
967
- * - `isUrlOnPrivateNetwork` *(this one)* which tests full URL
968
- * - `isHostnameOnPrivateNetwork` which tests just hostname
1018
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the filesystem
969
1019
  *
970
- * @param {string} ipAddress - The IP address to check.
971
- * @returns {boolean} Returns true if the IP address is reserved for private networks or localhost, otherwise false.
972
- * @public exported from `@promptbook/utils`
1020
+ * @private within the repository
973
1021
  */
974
- function isUrlOnPrivateNetwork(url) {
975
- if (typeof url === 'string') {
976
- url = new URL(url);
977
- }
978
- return isHostnameOnPrivateNetwork(url.hostname);
1022
+ function $isFileExisting(filename) {
1023
+ return __awaiter(this, void 0, void 0, function () {
1024
+ var isReadAccessAllowed, isFile;
1025
+ return __generator(this, function (_a) {
1026
+ switch (_a.label) {
1027
+ case 0:
1028
+ if (!$isRunningInNode()) {
1029
+ throw new EnvironmentMismatchError('Function `$isFileExisting` works only in Node environment.js');
1030
+ }
1031
+ return [4 /*yield*/, promises.access(filename, promises.constants.R_OK)
1032
+ .then(function () { return true; })
1033
+ .catch(function () { return false; })];
1034
+ case 1:
1035
+ isReadAccessAllowed = _a.sent();
1036
+ if (!isReadAccessAllowed) {
1037
+ return [2 /*return*/, false];
1038
+ }
1039
+ return [4 /*yield*/, promises.stat(filename)
1040
+ .then(function (fileStat) { return fileStat.isFile(); })
1041
+ .catch(function () { return false; })];
1042
+ case 2:
1043
+ isFile = _a.sent();
1044
+ return [2 /*return*/, isFile];
1045
+ }
1046
+ });
1047
+ });
979
1048
  }
1049
+ /**
1050
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
1051
+ * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
1052
+ * TODO: [🖇] What about symlinks?
1053
+ */
980
1054
 
981
1055
  /**
982
- * Tests if given string is valid URL.
983
- *
984
- * Note: Dataurl are considered perfectly valid.
985
- * Note: There are two simmilar functions:
986
- * - `isValidUrl` which tests any URL
987
- * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
1056
+ * Get the file extension from a file name
988
1057
  *
989
- * @public exported from `@promptbook/utils`
1058
+ * @private within the repository
990
1059
  */
991
- function isValidUrl(url) {
992
- if (typeof url !== 'string') {
993
- return false;
994
- }
995
- try {
996
- if (url.startsWith('blob:')) {
997
- url = url.replace(/^blob:/, '');
998
- }
999
- var urlObject = new URL(url /* because fail is handled */);
1000
- if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
1001
- return false;
1002
- }
1003
- return true;
1004
- }
1005
- catch (error) {
1006
- return false;
1007
- }
1060
+ function getFileExtension(value) {
1061
+ var match = value.match(/\.([0-9a-z]+)(?:[?#]|$)/i);
1062
+ return match ? match[1].toLowerCase() : null;
1008
1063
  }
1009
1064
 
1065
+ var defaultDiacriticsRemovalMap = [
1066
+ {
1067
+ base: 'A',
1068
+ 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',
1069
+ },
1070
+ { base: 'AA', letters: '\uA732' },
1071
+ { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
1072
+ { base: 'AO', letters: '\uA734' },
1073
+ { base: 'AU', letters: '\uA736' },
1074
+ { base: 'AV', letters: '\uA738\uA73A' },
1075
+ { base: 'AY', letters: '\uA73C' },
1076
+ {
1077
+ base: 'B',
1078
+ letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
1079
+ },
1080
+ {
1081
+ base: 'C',
1082
+ letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
1083
+ },
1084
+ {
1085
+ base: 'D',
1086
+ letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0',
1087
+ },
1088
+ { base: 'DZ', letters: '\u01F1\u01C4' },
1089
+ { base: 'Dz', letters: '\u01F2\u01C5' },
1090
+ {
1091
+ base: 'E',
1092
+ 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',
1093
+ },
1094
+ { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
1095
+ {
1096
+ base: 'G',
1097
+ letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
1098
+ },
1099
+ {
1100
+ base: 'H',
1101
+ letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
1102
+ },
1103
+ {
1104
+ base: 'I',
1105
+ letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
1106
+ },
1107
+ { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
1108
+ {
1109
+ base: 'K',
1110
+ letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
1111
+ },
1112
+ {
1113
+ base: 'L',
1114
+ letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
1115
+ },
1116
+ { base: 'LJ', letters: '\u01C7' },
1117
+ { base: 'Lj', letters: '\u01C8' },
1118
+ { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
1119
+ {
1120
+ base: 'N',
1121
+ letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
1122
+ },
1123
+ { base: 'NJ', letters: '\u01CA' },
1124
+ { base: 'Nj', letters: '\u01CB' },
1125
+ {
1126
+ base: 'O',
1127
+ 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',
1128
+ },
1129
+ { base: 'OI', letters: '\u01A2' },
1130
+ { base: 'OO', letters: '\uA74E' },
1131
+ { base: 'OU', letters: '\u0222' },
1132
+ { base: 'OE', letters: '\u008C\u0152' },
1133
+ { base: 'oe', letters: '\u009C\u0153' },
1134
+ {
1135
+ base: 'P',
1136
+ letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
1137
+ },
1138
+ { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
1139
+ {
1140
+ base: 'R',
1141
+ letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
1142
+ },
1143
+ {
1144
+ base: 'S',
1145
+ letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
1146
+ },
1147
+ {
1148
+ base: 'T',
1149
+ letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
1150
+ },
1151
+ { base: 'TZ', letters: '\uA728' },
1152
+ {
1153
+ base: 'U',
1154
+ 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',
1155
+ },
1156
+ { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
1157
+ { base: 'VY', letters: '\uA760' },
1158
+ {
1159
+ base: 'W',
1160
+ letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
1161
+ },
1162
+ { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
1163
+ {
1164
+ base: 'Y',
1165
+ letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
1166
+ },
1167
+ {
1168
+ base: 'Z',
1169
+ letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
1170
+ },
1171
+ {
1172
+ base: 'a',
1173
+ 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',
1174
+ },
1175
+ { base: 'aa', letters: '\uA733' },
1176
+ { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
1177
+ { base: 'ao', letters: '\uA735' },
1178
+ { base: 'au', letters: '\uA737' },
1179
+ { base: 'av', letters: '\uA739\uA73B' },
1180
+ { base: 'ay', letters: '\uA73D' },
1181
+ {
1182
+ base: 'b',
1183
+ letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
1184
+ },
1185
+ {
1186
+ base: 'c',
1187
+ letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
1188
+ },
1189
+ {
1190
+ base: 'd',
1191
+ letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
1192
+ },
1193
+ { base: 'dz', letters: '\u01F3\u01C6' },
1194
+ {
1195
+ base: 'e',
1196
+ 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',
1197
+ },
1198
+ { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
1199
+ {
1200
+ base: 'g',
1201
+ letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
1202
+ },
1203
+ {
1204
+ base: 'h',
1205
+ letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
1206
+ },
1207
+ { base: 'hv', letters: '\u0195' },
1208
+ {
1209
+ base: 'i',
1210
+ letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
1211
+ },
1212
+ { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
1213
+ {
1214
+ base: 'k',
1215
+ letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
1216
+ },
1217
+ {
1218
+ base: 'l',
1219
+ letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
1220
+ },
1221
+ { base: 'lj', letters: '\u01C9' },
1222
+ { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
1223
+ {
1224
+ base: 'n',
1225
+ letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
1226
+ },
1227
+ { base: 'nj', letters: '\u01CC' },
1228
+ {
1229
+ base: 'o',
1230
+ 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',
1231
+ },
1232
+ { base: 'oi', letters: '\u01A3' },
1233
+ { base: 'ou', letters: '\u0223' },
1234
+ { base: 'oo', letters: '\uA74F' },
1235
+ {
1236
+ base: 'p',
1237
+ letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
1238
+ },
1239
+ { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
1240
+ {
1241
+ base: 'r',
1242
+ letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
1243
+ },
1244
+ {
1245
+ base: 's',
1246
+ letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
1247
+ },
1248
+ {
1249
+ base: 't',
1250
+ letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
1251
+ },
1252
+ { base: 'tz', letters: '\uA729' },
1253
+ {
1254
+ base: 'u',
1255
+ 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',
1256
+ },
1257
+ { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
1258
+ { base: 'vy', letters: '\uA761' },
1259
+ {
1260
+ base: 'w',
1261
+ letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
1262
+ },
1263
+ { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
1264
+ {
1265
+ base: 'y',
1266
+ letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
1267
+ },
1268
+ {
1269
+ base: 'z',
1270
+ letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
1271
+ },
1272
+ ];
1010
1273
  /**
1011
- * Tests if given string is valid pipeline URL URL.
1274
+ * Map of letters from diacritic variant to diacritless variant
1275
+ * Contains lowercase and uppercase separatelly
1012
1276
  *
1013
- * Note: There are two simmilar functions:
1014
- * - `isValidUrl` which tests any URL
1015
- * - `isValidPipelineUrl` *(this one)* which tests just pipeline URL
1277
+ * > "á" => "a"
1278
+ * > "ě" => "e"
1279
+ * > "Ă" => "A"
1280
+ * > ...
1016
1281
  *
1017
1282
  * @public exported from `@promptbook/utils`
1018
1283
  */
1019
- function isValidPipelineUrl(url) {
1020
- if (!isValidUrl(url)) {
1021
- return false;
1022
- }
1023
- if (!url.startsWith('https://')) {
1024
- return false;
1025
- }
1026
- if (!url.endsWith('.ptbk.md')) {
1027
- return false;
1028
- }
1029
- if (url.includes('#')) {
1030
- // TODO: [🐠]
1031
- return false;
1032
- }
1033
- if (isUrlOnPrivateNetwork(url)) {
1034
- return false;
1284
+ var DIACRITIC_VARIANTS_LETTERS = {};
1285
+ // tslint:disable-next-line: prefer-for-of
1286
+ for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
1287
+ var letters = defaultDiacriticsRemovalMap[i].letters;
1288
+ // tslint:disable-next-line: prefer-for-of
1289
+ for (var j = 0; j < letters.length; j++) {
1290
+ DIACRITIC_VARIANTS_LETTERS[letters[j]] = defaultDiacriticsRemovalMap[i].base;
1035
1291
  }
1036
- return true;
1037
1292
  }
1038
- /**
1039
- * TODO: [🐠] Maybe more info why the URL is invalid
1040
- */
1041
-
1042
- /**
1043
- * Validates PipelineJson if it is logically valid
1044
- *
1045
- * It checks:
1046
- * - if it has correct parameters dependency
1047
- *
1048
- * It does NOT check:
1049
- * - if it is valid json
1050
- * - if it is meaningful
1293
+ // <- TODO: [🍓] Put to maker function to save execution time if not needed
1294
+ /*
1295
+ @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
1296
+ Licensed under the Apache License, Version 2.0 (the "License");
1297
+ you may not use this file except in compliance with the License.
1298
+ You may obtain a copy of the License at
1299
+
1300
+ http://www.apache.org/licenses/LICENSE-2.0
1301
+
1302
+ Unless required by applicable law or agreed to in writing, software
1303
+ distributed under the License is distributed on an "AS IS" BASIS,
1304
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1305
+ See the License for the specific language governing permissions and
1306
+ limitations under the License.
1307
+ */
1308
+
1309
+ /**
1310
+ * @@@
1051
1311
  *
1052
- * @param pipeline valid or invalid PipelineJson
1053
- * @returns the same pipeline if it is logically valid
1054
- * @throws {PipelineLogicError} on logical error in the pipeline
1055
- * @public exported from `@promptbook/core`
1312
+ * @param input @@@
1313
+ * @returns @@@
1314
+ * @public exported from `@promptbook/utils`
1056
1315
  */
1057
- function validatePipeline(pipeline) {
1058
- if (IS_PIPELINE_LOGIC_VALIDATED) {
1059
- validatePipelineCore(pipeline);
1060
- }
1061
- else {
1062
- try {
1063
- validatePipelineCore(pipeline);
1064
- }
1065
- catch (error) {
1066
- if (!(error instanceof PipelineLogicError)) {
1067
- throw error;
1068
- }
1069
- console.error(spaceTrim.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 "); }));
1070
- }
1071
- }
1072
- return pipeline;
1316
+ function removeDiacritics(input) {
1317
+ /*eslint no-control-regex: "off"*/
1318
+ return input.replace(/[^\u0000-\u007E]/g, function (a) {
1319
+ return DIACRITIC_VARIANTS_LETTERS[a] || a;
1320
+ });
1073
1321
  }
1074
1322
  /**
1075
- * @private internal function for `validatePipeline`
1323
+ * TODO: [Ж] Variant for cyrillic (and in general non-latin) letters
1076
1324
  */
1077
- function validatePipelineCore(pipeline) {
1078
- // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
1079
- var e_1, _a, e_2, _b, e_3, _c;
1080
- var pipelineIdentification = (function () {
1081
- // Note: This is a 😐 implementation of [🚞]
1082
- var _ = [];
1083
- if (pipeline.sourceFile !== undefined) {
1084
- _.push("File: ".concat(pipeline.sourceFile));
1085
- }
1086
- if (pipeline.pipelineUrl !== undefined) {
1087
- _.push("Url: ".concat(pipeline.pipelineUrl));
1088
- }
1089
- return _.join('\n');
1090
- })();
1091
- if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1092
- // <- Note: [🚲]
1093
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Invalid promptbook URL \"".concat(pipeline.pipelineUrl, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1094
- }
1095
- if (pipeline.promptbookVersion !== undefined && !isValidPromptbookVersion(pipeline.promptbookVersion)) {
1096
- // <- Note: [🚲]
1097
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Invalid Promptbook Version \"".concat(pipeline.promptbookVersion, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1098
- }
1099
- // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1100
- if (!Array.isArray(pipeline.parameters)) {
1101
- // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1102
- throw new ParseError(spaceTrim.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 "); }));
1103
- }
1104
- // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1105
- if (!Array.isArray(pipeline.templates)) {
1106
- // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1107
- throw new ParseError(spaceTrim.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 "); }));
1108
- }
1109
- var _loop_1 = function (parameter) {
1110
- if (parameter.isInput && parameter.isOutput) {
1111
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n\n Parameter {".concat(parameter.name, "} can not be both input and output\n\n ").concat(block(pipelineIdentification), "\n "); }));
1112
- }
1113
- // Note: Testing that parameter is either intermediate or output BUT not created and unused
1114
- if (!parameter.isInput &&
1115
- !parameter.isOutput &&
1116
- !pipeline.templates.some(function (template) { return template.dependentParameterNames.includes(parameter.name); })) {
1117
- throw new PipelineLogicError(spaceTrim.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 "); }));
1118
- }
1119
- // Note: Testing that parameter is either input or result of some template
1120
- if (!parameter.isInput &&
1121
- !pipeline.templates.some(function (template) { return template.resultingParameterName === parameter.name; })) {
1122
- throw new PipelineLogicError(spaceTrim.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 "); }));
1123
- }
1124
- };
1325
+
1326
+ /**
1327
+ * @@@
1328
+ *
1329
+ * @param text @@@
1330
+ * @returns @@@
1331
+ * @example 'hello-world'
1332
+ * @example 'i-love-promptbook'
1333
+ * @public exported from `@promptbook/utils`
1334
+ */
1335
+ function normalizeToKebabCase(text) {
1336
+ var e_1, _a;
1337
+ text = removeDiacritics(text);
1338
+ var charType;
1339
+ var lastCharType = 'OTHER';
1340
+ var normalizedName = '';
1125
1341
  try {
1126
- // Note: Check each parameter individually
1127
- for (var _d = __values(pipeline.parameters), _e = _d.next(); !_e.done; _e = _d.next()) {
1128
- var parameter = _e.value;
1129
- _loop_1(parameter);
1342
+ for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
1343
+ var char = text_1_1.value;
1344
+ var normalizedChar = void 0;
1345
+ if (/^[a-z]$/.test(char)) {
1346
+ charType = 'LOWERCASE';
1347
+ normalizedChar = char;
1348
+ }
1349
+ else if (/^[A-Z]$/.test(char)) {
1350
+ charType = 'UPPERCASE';
1351
+ normalizedChar = char.toLowerCase();
1352
+ }
1353
+ else if (/^[0-9]$/.test(char)) {
1354
+ charType = 'NUMBER';
1355
+ normalizedChar = char;
1356
+ }
1357
+ else {
1358
+ charType = 'OTHER';
1359
+ normalizedChar = '-';
1360
+ }
1361
+ if (charType !== lastCharType &&
1362
+ !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
1363
+ !(lastCharType === 'NUMBER') &&
1364
+ !(charType === 'NUMBER')) {
1365
+ normalizedName += '-';
1366
+ }
1367
+ normalizedName += normalizedChar;
1368
+ lastCharType = charType;
1130
1369
  }
1131
1370
  }
1132
1371
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
1133
1372
  finally {
1134
1373
  try {
1135
- if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
1374
+ if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
1136
1375
  }
1137
1376
  finally { if (e_1) throw e_1.error; }
1138
1377
  }
1139
- // Note: All input parameters are defined - so that they can be used as result of some template
1140
- var definedParameters = new Set(pipeline.parameters.filter(function (_a) {
1141
- var isInput = _a.isInput;
1142
- return isInput;
1143
- }).map(function (_a) {
1144
- var name = _a.name;
1145
- return name;
1146
- }));
1147
- var _loop_2 = function (template) {
1148
- var e_4, _h, e_5, _j;
1149
- if (definedParameters.has(template.resultingParameterName)) {
1150
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Parameter {".concat(template.resultingParameterName, "} is defined multiple times\n\n ").concat(block(pipelineIdentification), "\n "); }));
1151
- }
1152
- if (RESERVED_PARAMETER_NAMES.includes(template.resultingParameterName)) {
1153
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Parameter name {".concat(template.resultingParameterName, "} is reserved, please use different name\n\n ").concat(block(pipelineIdentification), "\n "); }));
1154
- }
1155
- definedParameters.add(template.resultingParameterName);
1156
- if (template.jokerParameterNames && template.jokerParameterNames.length > 0) {
1157
- if (!template.format &&
1158
- !template.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1159
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Joker parameters are used for {".concat(template.resultingParameterName, "} but no expectations are defined\n\n ").concat(block(pipelineIdentification), "\n "); }));
1160
- }
1161
- var _loop_4 = function (joker) {
1162
- if (!template.dependentParameterNames.includes(joker)) {
1163
- throw new PipelineLogicError(spaceTrim.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 "); }));
1164
- }
1165
- };
1166
- try {
1167
- for (var _k = (e_4 = void 0, __values(template.jokerParameterNames)), _l = _k.next(); !_l.done; _l = _k.next()) {
1168
- var joker = _l.value;
1169
- _loop_4(joker);
1170
- }
1171
- }
1172
- catch (e_4_1) { e_4 = { error: e_4_1 }; }
1173
- finally {
1174
- try {
1175
- if (_l && !_l.done && (_h = _k.return)) _h.call(_k);
1176
- }
1177
- finally { if (e_4) throw e_4.error; }
1178
- }
1179
- }
1180
- if (template.expectations) {
1181
- var _loop_5 = function (unit, min, max) {
1182
- if (min !== undefined && max !== undefined && min > max) {
1183
- throw new PipelineLogicError(spaceTrim.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 "); }));
1184
- }
1185
- if (min !== undefined && min < 0) {
1186
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Min expectation of ".concat(unit, " must be zero or positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1187
- }
1188
- if (max !== undefined && max <= 0) {
1189
- throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Max expectation of ".concat(unit, " must be positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1190
- }
1191
- };
1192
- try {
1193
- for (var _m = (e_5 = void 0, __values(Object.entries(template.expectations))), _o = _m.next(); !_o.done; _o = _m.next()) {
1194
- var _p = __read(_o.value, 2), unit = _p[0], _q = _p[1], min = _q.min, max = _q.max;
1195
- _loop_5(unit, min, max);
1196
- }
1197
- }
1198
- catch (e_5_1) { e_5 = { error: e_5_1 }; }
1199
- finally {
1200
- try {
1201
- if (_o && !_o.done && (_j = _m.return)) _j.call(_m);
1202
- }
1203
- finally { if (e_5) throw e_5.error; }
1204
- }
1205
- }
1206
- };
1378
+ normalizedName = normalizedName.split(/-+/g).join('-');
1379
+ normalizedName = normalizedName.split(/-?\/-?/g).join('/');
1380
+ normalizedName = normalizedName.replace(/^-/, '');
1381
+ normalizedName = normalizedName.replace(/-$/, '');
1382
+ return normalizedName;
1383
+ }
1384
+
1385
+ /**
1386
+ * Tests if given string is valid URL.
1387
+ *
1388
+ * Note: Dataurl are considered perfectly valid.
1389
+ * Note: There are two simmilar functions:
1390
+ * - `isValidUrl` which tests any URL
1391
+ * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
1392
+ *
1393
+ * @public exported from `@promptbook/utils`
1394
+ */
1395
+ function isValidUrl(url) {
1396
+ if (typeof url !== 'string') {
1397
+ return false;
1398
+ }
1207
1399
  try {
1208
- // Note: Checking each template individually
1209
- for (var _f = __values(pipeline.templates), _g = _f.next(); !_g.done; _g = _f.next()) {
1210
- var template = _g.value;
1211
- _loop_2(template);
1400
+ if (url.startsWith('blob:')) {
1401
+ url = url.replace(/^blob:/, '');
1212
1402
  }
1213
- }
1214
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
1215
- finally {
1216
- try {
1217
- if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
1403
+ var urlObject = new URL(url /* because fail is handled */);
1404
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
1405
+ return false;
1218
1406
  }
1219
- finally { if (e_2) throw e_2.error; }
1407
+ return true;
1220
1408
  }
1221
- // Note: Detect circular dependencies
1222
- var resovedParameters = pipeline.parameters
1223
- .filter(function (_a) {
1224
- var isInput = _a.isInput;
1225
- return isInput;
1226
- })
1227
- .map(function (_a) {
1228
- var name = _a.name;
1229
- return name;
1230
- });
1231
- try {
1232
- // Note: All reserved parameters are resolved
1233
- 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()) {
1234
- var reservedParameterName = RESERVED_PARAMETER_NAMES_1_1.value;
1235
- resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), [reservedParameterName], false);
1236
- }
1409
+ catch (error) {
1410
+ return false;
1237
1411
  }
1238
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
1239
- finally {
1240
- try {
1241
- if (RESERVED_PARAMETER_NAMES_1_1 && !RESERVED_PARAMETER_NAMES_1_1.done && (_c = RESERVED_PARAMETER_NAMES_1.return)) _c.call(RESERVED_PARAMETER_NAMES_1);
1242
- }
1243
- finally { if (e_3) throw e_3.error; }
1412
+ }
1413
+
1414
+ /**
1415
+ * Removes emojis from a string and fix whitespaces
1416
+ *
1417
+ * @param text with emojis
1418
+ * @returns text without emojis
1419
+ * @public exported from `@promptbook/utils`
1420
+ */
1421
+ function removeEmojis(text) {
1422
+ // Replace emojis (and also ZWJ sequence) with hyphens
1423
+ text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1424
+ text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1425
+ text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1426
+ text = text.replace(/\p{Extended_Pictographic}/gu, '');
1427
+ return text;
1428
+ }
1429
+
1430
+ /**
1431
+ * Tests if given string is valid URL.
1432
+ *
1433
+ * Note: This does not check if the file exists only if the path is valid
1434
+ * @public exported from `@promptbook/utils`
1435
+ */
1436
+ function isValidFilePath(filename) {
1437
+ if (typeof filename !== 'string') {
1438
+ return false;
1244
1439
  }
1245
- var unresovedTemplates = __spreadArray([], __read(pipeline.templates), false);
1246
- var loopLimit = LOOP_LIMIT;
1247
- var _loop_3 = function () {
1248
- if (loopLimit-- < 0) {
1249
- // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1250
- throw new UnexpectedError(spaceTrim.spaceTrim(function (block) { return "\n Loop limit reached during detection of circular dependencies in `validatePipeline`\n\n ".concat(block(pipelineIdentification), "\n "); }));
1251
- }
1252
- var currentlyResovedTemplates = unresovedTemplates.filter(function (template) {
1253
- return template.dependentParameterNames.every(function (name) { return resovedParameters.includes(name); });
1254
- });
1255
- if (currentlyResovedTemplates.length === 0) {
1256
- throw new PipelineLogicError(
1257
- // TODO: [🐎] DRY
1258
- spaceTrim.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
1259
- .map(function (_a) {
1260
- var resultingParameterName = _a.resultingParameterName, dependentParameterNames = _a.dependentParameterNames;
1261
- return "- Parameter {".concat(resultingParameterName, "} which depends on ").concat(dependentParameterNames
1262
- .map(function (dependentParameterName) { return "{".concat(dependentParameterName, "}"); })
1263
- .join(' and '));
1264
- })
1265
- .join('\n')), "\n\n Resolved:\n ").concat(block(resovedParameters.map(function (name) { return "- Parameter {".concat(name, "}"); }).join('\n')), "\n\n\n "); }));
1266
- }
1267
- resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), __read(currentlyResovedTemplates.map(function (_a) {
1268
- var resultingParameterName = _a.resultingParameterName;
1269
- return resultingParameterName;
1270
- })), false);
1271
- unresovedTemplates = unresovedTemplates.filter(function (template) { return !currentlyResovedTemplates.includes(template); });
1272
- };
1273
- while (unresovedTemplates.length > 0) {
1274
- _loop_3();
1440
+ var filenameSlashes = filename.split('\\').join('/');
1441
+ // Absolute Unix path: /hello.txt
1442
+ if (/^(\/)/i.test(filenameSlashes)) {
1443
+ return true;
1444
+ }
1445
+ // Absolute Windows path: /hello.txt
1446
+ if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
1447
+ return true;
1275
1448
  }
1449
+ // Relative path: ./hello.txt
1450
+ if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
1451
+ return true;
1452
+ }
1453
+ return false;
1276
1454
  }
1455
+
1277
1456
  /**
1278
- * TODO: !!!!! [🧞‍♀️] Do not allow joker + foreach
1279
- * TODO: [🧠] Work with promptbookVersion
1280
- * TODO: Use here some json-schema, Zod or something similar and change it to:
1281
- * > /**
1282
- * > * Validates PipelineJson if it is logically valid.
1283
- * > *
1284
- * > * It checks:
1285
- * > * - it has a valid structure
1286
- * > * - ...
1287
- * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
1457
+ * @@@
1458
+ *
1459
+ * @param value @@@
1460
+ * @returns @@@
1461
+ * @example @@@
1462
+ * @public exported from `@promptbook/utils`
1288
1463
  */
1464
+ function titleToName(value) {
1465
+ if (isValidUrl(value)) {
1466
+ value = value.replace(/^https?:\/\//, '');
1467
+ value = value.replace(/\.html$/, '');
1468
+ }
1469
+ else if (isValidFilePath(value)) {
1470
+ value = path.basename(value);
1471
+ // Note: Keeping extension in the name
1472
+ }
1473
+ value = value.split('/').join('-');
1474
+ value = removeEmojis(value);
1475
+ value = normalizeToKebabCase(value);
1476
+ // TODO: [🧠] Maybe warn or add some padding to short name which are not good identifiers
1477
+ return value;
1478
+ }
1479
+
1289
1480
  /**
1290
- * TODO: [🐣][main] !!!! Validate that all samples match expectations
1291
- * TODO: [🐣][🐝][main] !!!! Validate that knowledge is valid (non-void)
1292
- * TODO: [🐣][main] !!!! Validate that persona can be used only with CHAT variant
1293
- * TODO: [🐣][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1294
- * TODO: [🐣][main] !!!! Validate that reserved parameter is not used as joker
1295
- * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
1296
- * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
1481
+ * @@@
1482
+ *
1483
+ * @private for `FileCacheStorage`
1297
1484
  */
1485
+ function nameToSubfolderPath(name) {
1486
+ return [name.substr(0, 1).toLowerCase(), name.substr(1, 1).toLowerCase()];
1487
+ }
1298
1488
 
1299
1489
  /**
1300
- * This error indicates that promptbook not found in the collection
1490
+ * Just marks a place of place where should be something implemented
1491
+ * No side effects.
1492
+ *
1493
+ * Note: It can be usefull suppressing eslint errors of unused variables
1494
+ *
1495
+ * @param value any values
1496
+ * @returns void
1497
+ * @private within the repository
1498
+ */
1499
+ function TODO_USE() {
1500
+ var value = [];
1501
+ for (var _i = 0; _i < arguments.length; _i++) {
1502
+ value[_i] = arguments[_i];
1503
+ }
1504
+ }
1505
+
1506
+ /**
1507
+ * Create a filename for intermediate cache for scrapers
1508
+ *
1509
+ * Note: It also checks if directory exists and creates it if not
1510
+ *
1511
+ * @private as internal utility for scrapers
1512
+ */
1513
+ function getScraperIntermediateSource(source, options) {
1514
+ return __awaiter(this, void 0, void 0, function () {
1515
+ var sourceFilename, url, rootDirname, cacheDirname, isCacheCleaned, extension, isVerbose, hash, semanticName, pieces, name, cacheFilename, isDestroyed, fileHandler;
1516
+ return __generator(this, function (_a) {
1517
+ switch (_a.label) {
1518
+ case 0:
1519
+ sourceFilename = source.filename, url = source.url;
1520
+ rootDirname = options.rootDirname, cacheDirname = options.cacheDirname, isCacheCleaned = options.isCacheCleaned, extension = options.extension, isVerbose = options.isVerbose;
1521
+ hash = cryptoJs.SHA256(
1522
+ // <- TODO: [🥬] Encapsulate sha256 to some private utility function
1523
+ hexEncoder__default["default"].parse(sourceFilename || url || 'untitled'))
1524
+ .toString( /* hex */)
1525
+ .substring(0, 20);
1526
+ semanticName = normalizeToKebabCase(titleToName((sourceFilename || url || '').split('intermediate').join(''))).substring(0, 20);
1527
+ pieces = ['intermediate', semanticName, hash].filter(function (piece) { return piece !== ''; });
1528
+ name = pieces.join('-').split('--').join('-');
1529
+ // <- TODO: Use MAX_FILENAME_LENGTH
1530
+ TODO_USE(rootDirname); // <- TODO: !!!!!!
1531
+ cacheFilename = path.join.apply(void 0, __spreadArray(__spreadArray([process.cwd(),
1532
+ cacheDirname], __read(nameToSubfolderPath(hash /* <- TODO: [🎎] Maybe add some SHA256 prefix */)), false), [name], false)).split('\\')
1533
+ .join('/') +
1534
+ '.' +
1535
+ extension;
1536
+ return [4 /*yield*/, promises.mkdir(path.dirname(cacheFilename), { recursive: true })];
1537
+ case 1:
1538
+ _a.sent();
1539
+ isDestroyed = true;
1540
+ fileHandler = {
1541
+ filename: cacheFilename,
1542
+ get isDestroyed() {
1543
+ return isDestroyed;
1544
+ },
1545
+ destroy: function () {
1546
+ return __awaiter(this, void 0, void 0, function () {
1547
+ return __generator(this, function (_a) {
1548
+ switch (_a.label) {
1549
+ case 0:
1550
+ if (!isCacheCleaned) return [3 /*break*/, 2];
1551
+ if (isVerbose) {
1552
+ console.info('legacyDocumentScraper: Clening cache');
1553
+ }
1554
+ return [4 /*yield*/, promises.rm(cacheFilename)];
1555
+ case 1:
1556
+ _a.sent();
1557
+ _a.label = 2;
1558
+ case 2:
1559
+ isDestroyed = true;
1560
+ return [2 /*return*/];
1561
+ }
1562
+ });
1563
+ });
1564
+ },
1565
+ };
1566
+ return [2 /*return*/, fileHandler];
1567
+ }
1568
+ });
1569
+ });
1570
+ }
1571
+ /**
1572
+ * Note: Not using `FileCacheStorage` for two reasons:
1573
+ * 1) Need to store more than serialized JSONs
1574
+ * 2) Need to switch between a `rootDirname` and `cacheDirname` <- TODO: !!!!
1575
+ * TODO: [🐱‍🐉][🧠] Make some smart crop
1576
+ */
1577
+
1578
+ 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"}];
1579
+
1580
+ /**
1581
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
1301
1582
  *
1302
1583
  * @public exported from `@promptbook/core`
1303
1584
  */
1304
- var NotFoundError = /** @class */ (function (_super) {
1305
- __extends(NotFoundError, _super);
1306
- function NotFoundError(message) {
1585
+ var ParseError = /** @class */ (function (_super) {
1586
+ __extends(ParseError, _super);
1587
+ function ParseError(message) {
1307
1588
  var _this = _super.call(this, message) || this;
1308
- _this.name = 'NotFoundError';
1309
- Object.setPrototypeOf(_this, NotFoundError.prototype);
1589
+ _this.name = 'ParseError';
1590
+ Object.setPrototypeOf(_this, ParseError.prototype);
1310
1591
  return _this;
1311
1592
  }
1312
- return NotFoundError;
1593
+ return ParseError;
1313
1594
  }(Error));
1595
+ /**
1596
+ * TODO: Maybe split `ParseError` and `ApplyError`
1597
+ */
1314
1598
 
1315
1599
  /**
1316
- * This error indicates errors in referencing promptbooks between each other
1600
+ * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
1317
1601
  *
1318
1602
  * @public exported from `@promptbook/core`
1319
1603
  */
1320
- var PipelineUrlError = /** @class */ (function (_super) {
1321
- __extends(PipelineUrlError, _super);
1322
- function PipelineUrlError(message) {
1604
+ var PipelineLogicError = /** @class */ (function (_super) {
1605
+ __extends(PipelineLogicError, _super);
1606
+ function PipelineLogicError(message) {
1323
1607
  var _this = _super.call(this, message) || this;
1324
- _this.name = 'PipelineUrlError';
1325
- Object.setPrototypeOf(_this, PipelineUrlError.prototype);
1608
+ _this.name = 'PipelineLogicError';
1609
+ Object.setPrototypeOf(_this, PipelineLogicError.prototype);
1326
1610
  return _this;
1327
1611
  }
1328
- return PipelineUrlError;
1612
+ return PipelineLogicError;
1329
1613
  }(Error));
1330
1614
 
1331
1615
  /**
1332
- * Parses the template and returns the list of all parameter names
1616
+ * Tests if given string is valid semantic version
1617
+ *
1618
+ * Note: There are two simmilar functions:
1619
+ * - `isValidSemanticVersion` which tests any semantic version
1620
+ * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
1333
1621
  *
1334
- * @param template the template with parameters in {curly} braces
1335
- * @returns the list of parameter names
1336
1622
  * @public exported from `@promptbook/utils`
1337
1623
  */
1338
- function extractParameterNames(template) {
1339
- var e_1, _a;
1340
- var matches = template.matchAll(/{\w+}/g);
1341
- var parameterNames = new Set();
1342
- try {
1343
- for (var matches_1 = __values(matches), matches_1_1 = matches_1.next(); !matches_1_1.done; matches_1_1 = matches_1.next()) {
1344
- var match = matches_1_1.value;
1345
- var parameterName = match[0].slice(1, -1);
1346
- parameterNames.add(parameterName);
1347
- }
1624
+ function isValidSemanticVersion(version) {
1625
+ if (typeof version !== 'string') {
1626
+ return false;
1348
1627
  }
1349
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1350
- finally {
1351
- try {
1352
- if (matches_1_1 && !matches_1_1.done && (_a = matches_1.return)) _a.call(matches_1);
1353
- }
1354
- finally { if (e_1) throw e_1.error; }
1628
+ if (version.startsWith('0.0.0')) {
1629
+ return false;
1355
1630
  }
1356
- return parameterNames;
1631
+ return /^\d+\.\d+\.\d+(-\d+)?$/i.test(version);
1357
1632
  }
1358
1633
 
1359
1634
  /**
1360
- * Unprepare just strips the preparation data of the pipeline
1635
+ * Tests if given string is valid promptbook version
1636
+ * It looks into list of known promptbook versions.
1361
1637
  *
1362
- * @public exported from `@promptbook/core`
1638
+ * @see https://www.npmjs.com/package/promptbook?activeTab=versions
1639
+ * 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.
1640
+ * Note: There are two simmilar functions:
1641
+ * - `isValidSemanticVersion` which tests any semantic version
1642
+ * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
1643
+ *
1644
+ * @public exported from `@promptbook/utils`
1363
1645
  */
1364
- function unpreparePipeline(pipeline) {
1365
- var personas = pipeline.personas, knowledgeSources = pipeline.knowledgeSources, templates = pipeline.templates;
1366
- personas = personas.map(function (persona) { return (__assign(__assign({}, persona), { modelRequirements: undefined, preparationIds: undefined })); });
1367
- knowledgeSources = knowledgeSources.map(function (knowledgeSource) { return (__assign(__assign({}, knowledgeSource), { preparationIds: undefined })); });
1368
- templates = templates.map(function (template) {
1369
- var dependentParameterNames = template.dependentParameterNames;
1370
- var parameterNames = extractParameterNames(template.preparedContent || '');
1371
- dependentParameterNames = dependentParameterNames.filter(function (dependentParameterName) { return !parameterNames.has(dependentParameterName); });
1372
- var templateUnprepared = __assign(__assign({}, template), { dependentParameterNames: dependentParameterNames });
1373
- delete templateUnprepared.preparedContent;
1374
- return templateUnprepared;
1375
- });
1376
- return $asDeeplyFrozenSerializableJson('Unprepared PipelineJson', __assign(__assign({}, pipeline), { templates: templates, knowledgeSources: knowledgeSources, knowledgePieces: [], personas: personas, preparations: [] }));
1646
+ function isValidPromptbookVersion(version) {
1647
+ if (!isValidSemanticVersion(version)) {
1648
+ return false;
1649
+ }
1650
+ if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
1651
+ return false;
1652
+ }
1653
+ // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_VERSIONS
1654
+ return true;
1377
1655
  }
1656
+
1378
1657
  /**
1379
- * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
1380
- * TODO: Write tests for `preparePipeline`
1381
- * TODO: [🍙] Make some standard order of json properties
1658
+ * Checks if an URL is reserved for private networks or localhost.
1659
+ *
1660
+ * Note: There are two simmilar functions:
1661
+ * - `isUrlOnPrivateNetwork` which tests full URL
1662
+ * - `isHostnameOnPrivateNetwork` *(this one)* which tests just hostname
1663
+ *
1664
+ * @public exported from `@promptbook/utils`
1382
1665
  */
1666
+ function isHostnameOnPrivateNetwork(hostname) {
1667
+ if (hostname === 'example.com' ||
1668
+ hostname === 'localhost' ||
1669
+ hostname.endsWith('.localhost') ||
1670
+ hostname.endsWith('.local') ||
1671
+ hostname.endsWith('.test') ||
1672
+ hostname === '127.0.0.1' ||
1673
+ hostname === '::1') {
1674
+ return true;
1675
+ }
1676
+ if (hostname.includes(':')) {
1677
+ // IPv6
1678
+ var ipParts = hostname.split(':');
1679
+ return ipParts[0] === 'fc00' || ipParts[0] === 'fd00' || ipParts[0] === 'fe80';
1680
+ }
1681
+ else {
1682
+ // IPv4
1683
+ var ipParts = hostname.split('.').map(function (part) { return Number.parseInt(part, 10); });
1684
+ return (ipParts[0] === 10 ||
1685
+ (ipParts[0] === 172 && ipParts[1] >= 16 && ipParts[1] <= 31) ||
1686
+ (ipParts[0] === 192 && ipParts[1] === 168));
1687
+ }
1688
+ }
1383
1689
 
1384
1690
  /**
1385
- * Library of pipelines that groups together pipelines for an application.
1386
- * This implementation is a very thin wrapper around the Array / Map of pipelines.
1691
+ * Checks if an IP address or hostname is reserved for private networks or localhost.
1387
1692
  *
1388
- * @private internal function of `createCollectionFromJson`, use `createCollectionFromJson` instead
1389
- * @see https://github.com/webgptorg/pipeline#pipeline-collection
1693
+ * Note: There are two simmilar functions:
1694
+ * - `isUrlOnPrivateNetwork` *(this one)* which tests full URL
1695
+ * - `isHostnameOnPrivateNetwork` which tests just hostname
1696
+ *
1697
+ * @param {string} ipAddress - The IP address to check.
1698
+ * @returns {boolean} Returns true if the IP address is reserved for private networks or localhost, otherwise false.
1699
+ * @public exported from `@promptbook/utils`
1390
1700
  */
1391
- var SimplePipelineCollection = /** @class */ (function () {
1392
- /**
1393
- * Constructs a pipeline collection from pipelines
1394
- *
1395
- * @param pipelines @@@
1396
- *
1397
- * Note: During the construction logic of all pipelines are validated
1398
- * Note: It is not recommended to use this constructor directly, use `createCollectionFromJson` *(or other variant)* instead
1399
- */
1400
- function SimplePipelineCollection() {
1401
- var e_1, _a;
1402
- var pipelines = [];
1403
- for (var _i = 0; _i < arguments.length; _i++) {
1404
- pipelines[_i] = arguments[_i];
1405
- }
1406
- this.collection = new Map();
1407
- try {
1408
- for (var pipelines_1 = __values(pipelines), pipelines_1_1 = pipelines_1.next(); !pipelines_1_1.done; pipelines_1_1 = pipelines_1.next()) {
1409
- var pipeline = pipelines_1_1.value;
1410
- // TODO: [👠] DRY
1411
- if (pipeline.pipelineUrl === undefined) {
1412
- throw new PipelineUrlError(spaceTrim.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 ")));
1413
- }
1414
- // Note: [🐨]
1415
- validatePipeline(pipeline);
1416
- // TODO: [🦄] DRY
1417
- // Note: [🦄]
1418
- if (
1419
- // TODO: [🐽]
1420
- this.collection.has(pipeline.pipelineUrl) &&
1421
- pipelineJsonToString(unpreparePipeline(pipeline)) !==
1422
- pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
1423
- var existing = this.collection.get(pipeline.pipelineUrl);
1424
- throw new PipelineUrlError(spaceTrim.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 ")));
1425
- }
1426
- // Note: [🧠] Overwrite existing pipeline with the same URL
1427
- this.collection.set(pipeline.pipelineUrl, pipeline);
1428
- }
1429
- }
1430
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1431
- finally {
1432
- try {
1433
- if (pipelines_1_1 && !pipelines_1_1.done && (_a = pipelines_1.return)) _a.call(pipelines_1);
1434
- }
1435
- finally { if (e_1) throw e_1.error; }
1436
- }
1701
+ function isUrlOnPrivateNetwork(url) {
1702
+ if (typeof url === 'string') {
1703
+ url = new URL(url);
1437
1704
  }
1438
- /**
1439
- * Gets all pipelines in the collection
1440
- */
1441
- SimplePipelineCollection.prototype.listPipelines = function () {
1442
- return Array.from(this.collection.keys());
1443
- };
1444
- /**
1445
- * Gets pipeline by its URL
1446
- *
1447
- * Note: This is not a direct fetching from the URL, but a lookup in the collection
1448
- */
1449
- SimplePipelineCollection.prototype.getPipelineByUrl = function (url) {
1450
- var _this = this;
1451
- var pipeline = this.collection.get(url);
1452
- if (!pipeline) {
1453
- if (this.listPipelines().length === 0) {
1454
- throw new NotFoundError(spaceTrim.spaceTrim("\n Pipeline with url \"".concat(url, "\" not found\n\n No pipelines available\n ")));
1455
- }
1456
- throw new NotFoundError(spaceTrim.spaceTrim(function (block) { return "\n Pipeline with url \"".concat(url, "\" not found\n\n Available pipelines:\n ").concat(block(_this.listPipelines()
1457
- .map(function (pipelineUrl) { return "- ".concat(pipelineUrl); })
1458
- .join('\n')), "\n\n "); }));
1459
- }
1460
- return pipeline;
1461
- };
1462
- /**
1463
- * Checks whether given prompt was defined in any pipeline in the collection
1464
- */
1465
- SimplePipelineCollection.prototype.isResponsibleForPrompt = function (prompt) {
1466
- return true;
1467
- };
1468
- return SimplePipelineCollection;
1469
- }());
1705
+ return isHostnameOnPrivateNetwork(url.hostname);
1706
+ }
1470
1707
 
1471
1708
  /**
1472
- * Creates PipelineCollection from array of PipelineJson or PipelineString
1709
+ * Tests if given string is valid pipeline URL URL.
1473
1710
  *
1474
- * Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
1475
- * Note: Syntax, parsing, and logic consistency checks are performed on all sources during build
1711
+ * Note: There are two simmilar functions:
1712
+ * - `isValidUrl` which tests any URL
1713
+ * - `isValidPipelineUrl` *(this one)* which tests just pipeline URL
1476
1714
  *
1477
- * @param promptbookSources
1478
- * @returns PipelineCollection
1479
- * @public exported from `@promptbook/core`
1715
+ * @public exported from `@promptbook/utils`
1480
1716
  */
1481
- function createCollectionFromJson() {
1482
- var promptbooks = [];
1483
- for (var _i = 0; _i < arguments.length; _i++) {
1484
- promptbooks[_i] = arguments[_i];
1717
+ function isValidPipelineUrl(url) {
1718
+ if (!isValidUrl(url)) {
1719
+ return false;
1485
1720
  }
1486
- return new (SimplePipelineCollection.bind.apply(SimplePipelineCollection, __spreadArray([void 0], __read(promptbooks), false)))();
1721
+ if (!url.startsWith('https://')) {
1722
+ return false;
1723
+ }
1724
+ if (!url.endsWith('.ptbk.md')) {
1725
+ return false;
1726
+ }
1727
+ if (url.includes('#')) {
1728
+ // TODO: [🐠]
1729
+ return false;
1730
+ }
1731
+ if (isUrlOnPrivateNetwork(url)) {
1732
+ return false;
1733
+ }
1734
+ return true;
1487
1735
  }
1736
+ /**
1737
+ * TODO: [🐠] Maybe more info why the URL is invalid
1738
+ */
1488
1739
 
1489
- var defaultDiacriticsRemovalMap = [
1490
- {
1491
- base: 'A',
1492
- 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',
1493
- },
1494
- { base: 'AA', letters: '\uA732' },
1495
- { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
1496
- { base: 'AO', letters: '\uA734' },
1497
- { base: 'AU', letters: '\uA736' },
1498
- { base: 'AV', letters: '\uA738\uA73A' },
1499
- { base: 'AY', letters: '\uA73C' },
1500
- {
1501
- base: 'B',
1502
- letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
1503
- },
1504
- {
1505
- base: 'C',
1506
- letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
1507
- },
1508
- {
1509
- base: 'D',
1510
- letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0',
1511
- },
1512
- { base: 'DZ', letters: '\u01F1\u01C4' },
1513
- { base: 'Dz', letters: '\u01F2\u01C5' },
1514
- {
1515
- base: 'E',
1516
- 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',
1517
- },
1518
- { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
1519
- {
1520
- base: 'G',
1521
- letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
1522
- },
1523
- {
1524
- base: 'H',
1525
- letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
1526
- },
1527
- {
1528
- base: 'I',
1529
- letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
1530
- },
1531
- { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
1532
- {
1533
- base: 'K',
1534
- letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
1535
- },
1536
- {
1537
- base: 'L',
1538
- letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
1539
- },
1540
- { base: 'LJ', letters: '\u01C7' },
1541
- { base: 'Lj', letters: '\u01C8' },
1542
- { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
1543
- {
1544
- base: 'N',
1545
- letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
1546
- },
1547
- { base: 'NJ', letters: '\u01CA' },
1548
- { base: 'Nj', letters: '\u01CB' },
1549
- {
1550
- base: 'O',
1551
- 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',
1552
- },
1553
- { base: 'OI', letters: '\u01A2' },
1554
- { base: 'OO', letters: '\uA74E' },
1555
- { base: 'OU', letters: '\u0222' },
1556
- { base: 'OE', letters: '\u008C\u0152' },
1557
- { base: 'oe', letters: '\u009C\u0153' },
1558
- {
1559
- base: 'P',
1560
- letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
1561
- },
1562
- { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
1563
- {
1564
- base: 'R',
1565
- letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
1566
- },
1567
- {
1568
- base: 'S',
1569
- letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
1570
- },
1571
- {
1572
- base: 'T',
1573
- letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
1574
- },
1575
- { base: 'TZ', letters: '\uA728' },
1576
- {
1577
- base: 'U',
1578
- 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',
1579
- },
1580
- { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
1581
- { base: 'VY', letters: '\uA760' },
1582
- {
1583
- base: 'W',
1584
- letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
1585
- },
1586
- { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
1587
- {
1588
- base: 'Y',
1589
- letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
1590
- },
1591
- {
1592
- base: 'Z',
1593
- letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
1594
- },
1595
- {
1596
- base: 'a',
1597
- 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',
1598
- },
1599
- { base: 'aa', letters: '\uA733' },
1600
- { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
1601
- { base: 'ao', letters: '\uA735' },
1602
- { base: 'au', letters: '\uA737' },
1603
- { base: 'av', letters: '\uA739\uA73B' },
1604
- { base: 'ay', letters: '\uA73D' },
1605
- {
1606
- base: 'b',
1607
- letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
1608
- },
1609
- {
1610
- base: 'c',
1611
- letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
1612
- },
1613
- {
1614
- base: 'd',
1615
- letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
1616
- },
1617
- { base: 'dz', letters: '\u01F3\u01C6' },
1618
- {
1619
- base: 'e',
1620
- 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',
1621
- },
1622
- { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
1623
- {
1624
- base: 'g',
1625
- letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
1626
- },
1627
- {
1628
- base: 'h',
1629
- letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
1630
- },
1631
- { base: 'hv', letters: '\u0195' },
1632
- {
1633
- base: 'i',
1634
- letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
1635
- },
1636
- { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
1637
- {
1638
- base: 'k',
1639
- letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
1640
- },
1641
- {
1642
- base: 'l',
1643
- letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
1644
- },
1645
- { base: 'lj', letters: '\u01C9' },
1646
- { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
1647
- {
1648
- base: 'n',
1649
- letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
1650
- },
1651
- { base: 'nj', letters: '\u01CC' },
1652
- {
1653
- base: 'o',
1654
- 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',
1655
- },
1656
- { base: 'oi', letters: '\u01A3' },
1657
- { base: 'ou', letters: '\u0223' },
1658
- { base: 'oo', letters: '\uA74F' },
1659
- {
1660
- base: 'p',
1661
- letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
1662
- },
1663
- { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
1664
- {
1665
- base: 'r',
1666
- letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
1667
- },
1668
- {
1669
- base: 's',
1670
- letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
1671
- },
1672
- {
1673
- base: 't',
1674
- letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
1675
- },
1676
- { base: 'tz', letters: '\uA729' },
1677
- {
1678
- base: 'u',
1679
- 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',
1680
- },
1681
- { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
1682
- { base: 'vy', letters: '\uA761' },
1683
- {
1684
- base: 'w',
1685
- letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
1686
- },
1687
- { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
1688
- {
1689
- base: 'y',
1690
- letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
1691
- },
1692
- {
1693
- base: 'z',
1694
- letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
1695
- },
1696
- ];
1697
1740
  /**
1698
- * Map of letters from diacritic variant to diacritless variant
1699
- * Contains lowercase and uppercase separatelly
1700
- *
1701
- * > "á" => "a"
1702
- * > "ě" => "e"
1703
- * > "Ă" => "A"
1704
- * > ...
1741
+ * Validates PipelineJson if it is logically valid
1705
1742
  *
1706
- * @public exported from `@promptbook/utils`
1707
- */
1708
- var DIACRITIC_VARIANTS_LETTERS = {};
1709
- // tslint:disable-next-line: prefer-for-of
1710
- for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
1711
- var letters = defaultDiacriticsRemovalMap[i].letters;
1712
- // tslint:disable-next-line: prefer-for-of
1713
- for (var j = 0; j < letters.length; j++) {
1714
- DIACRITIC_VARIANTS_LETTERS[letters[j]] = defaultDiacriticsRemovalMap[i].base;
1715
- }
1716
- }
1717
- // <- TODO: [🍓] Put to maker function to save execution time if not needed
1718
- /*
1719
- @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
1720
- Licensed under the Apache License, Version 2.0 (the "License");
1721
- you may not use this file except in compliance with the License.
1722
- You may obtain a copy of the License at
1723
-
1724
- http://www.apache.org/licenses/LICENSE-2.0
1725
-
1726
- Unless required by applicable law or agreed to in writing, software
1727
- distributed under the License is distributed on an "AS IS" BASIS,
1728
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1729
- See the License for the specific language governing permissions and
1730
- limitations under the License.
1731
- */
1732
-
1733
- /**
1734
- * @@@
1743
+ * It checks:
1744
+ * - if it has correct parameters dependency
1735
1745
  *
1736
- * @param input @@@
1737
- * @returns @@@
1738
- * @public exported from `@promptbook/utils`
1739
- */
1740
- function removeDiacritics(input) {
1741
- /*eslint no-control-regex: "off"*/
1742
- return input.replace(/[^\u0000-\u007E]/g, function (a) {
1743
- return DIACRITIC_VARIANTS_LETTERS[a] || a;
1744
- });
1745
- }
1746
- /**
1747
- * TODO: [Ж] Variant for cyrillic (and in general non-latin) letters
1748
- */
1749
-
1750
- /**
1751
- * @@@
1746
+ * It does NOT check:
1747
+ * - if it is valid json
1748
+ * - if it is meaningful
1752
1749
  *
1753
- * @param text @@@
1754
- * @returns @@@
1755
- * @example 'hello-world'
1756
- * @example 'i-love-promptbook'
1757
- * @public exported from `@promptbook/utils`
1750
+ * @param pipeline valid or invalid PipelineJson
1751
+ * @returns the same pipeline if it is logically valid
1752
+ * @throws {PipelineLogicError} on logical error in the pipeline
1753
+ * @public exported from `@promptbook/core`
1758
1754
  */
1759
- function normalizeToKebabCase(text) {
1760
- var e_1, _a;
1761
- text = removeDiacritics(text);
1762
- var charType;
1763
- var lastCharType = 'OTHER';
1764
- var normalizedName = '';
1765
- try {
1766
- for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
1767
- var char = text_1_1.value;
1768
- var normalizedChar = void 0;
1769
- if (/^[a-z]$/.test(char)) {
1770
- charType = 'LOWERCASE';
1771
- normalizedChar = char;
1772
- }
1773
- else if (/^[A-Z]$/.test(char)) {
1774
- charType = 'UPPERCASE';
1775
- normalizedChar = char.toLowerCase();
1776
- }
1777
- else if (/^[0-9]$/.test(char)) {
1778
- charType = 'NUMBER';
1779
- normalizedChar = char;
1780
- }
1781
- else if (/^\/$/.test(char)) {
1782
- charType = 'SLASH';
1783
- normalizedChar = char;
1784
- }
1785
- else {
1786
- charType = 'OTHER';
1787
- normalizedChar = '-';
1788
- }
1789
- if (charType !== lastCharType &&
1790
- !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
1791
- !(lastCharType === 'NUMBER') &&
1792
- !(charType === 'NUMBER')) {
1793
- normalizedName += '-';
1794
- }
1795
- normalizedName += normalizedChar;
1796
- lastCharType = charType;
1797
- }
1755
+ function validatePipeline(pipeline) {
1756
+ if (IS_PIPELINE_LOGIC_VALIDATED) {
1757
+ validatePipelineCore(pipeline);
1798
1758
  }
1799
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
1800
- finally {
1759
+ else {
1801
1760
  try {
1802
- if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
1761
+ validatePipelineCore(pipeline);
1762
+ }
1763
+ catch (error) {
1764
+ if (!(error instanceof PipelineLogicError)) {
1765
+ throw error;
1766
+ }
1767
+ console.error(spaceTrim.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 "); }));
1803
1768
  }
1804
- finally { if (e_1) throw e_1.error; }
1805
1769
  }
1806
- normalizedName = normalizedName.split(/-+/g).join('-');
1807
- normalizedName = normalizedName.split(/-?\/-?/g).join('/');
1808
- normalizedName = normalizedName.replace(/^-/, '');
1809
- normalizedName = normalizedName.replace(/-$/, '');
1810
- return normalizedName;
1770
+ return pipeline;
1811
1771
  }
1812
-
1813
1772
  /**
1814
- * Removes emojis from a string and fix whitespaces
1815
- *
1816
- * @param text with emojis
1817
- * @returns text without emojis
1818
- * @public exported from `@promptbook/utils`
1773
+ * @private internal function for `validatePipeline`
1819
1774
  */
1820
- function removeEmojis(text) {
1821
- // Replace emojis (and also ZWJ sequence) with hyphens
1822
- text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1823
- text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1824
- text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1825
- text = text.replace(/\p{Extended_Pictographic}/gu, '');
1826
- return text;
1827
- }
1828
-
1829
- /**
1830
- * @@@
1831
- *
1832
- * @param value @@@
1833
- * @returns @@@
1834
- * @example @@@
1835
- * @public exported from `@promptbook/utils`
1836
- */
1837
- function titleToName(value) {
1838
- if (value.startsWith('http://') || value.startsWith('https://')) {
1839
- // TODO: Maybe check against some list unallowed characters
1840
- return value;
1775
+ function validatePipelineCore(pipeline) {
1776
+ // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
1777
+ var e_1, _a, e_2, _b, e_3, _c;
1778
+ var pipelineIdentification = (function () {
1779
+ // Note: This is a 😐 implementation of [🚞]
1780
+ var _ = [];
1781
+ if (pipeline.sourceFile !== undefined) {
1782
+ _.push("File: ".concat(pipeline.sourceFile));
1783
+ }
1784
+ if (pipeline.pipelineUrl !== undefined) {
1785
+ _.push("Url: ".concat(pipeline.pipelineUrl));
1786
+ }
1787
+ return _.join('\n');
1788
+ })();
1789
+ if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1790
+ // <- Note: [🚲]
1791
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Invalid promptbook URL \"".concat(pipeline.pipelineUrl, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1841
1792
  }
1842
- if (value.startsWith('./') || value.startsWith('../')) {
1843
- // TODO: Maybe check against some list unallowed characters
1844
- return value;
1793
+ if (pipeline.promptbookVersion !== undefined && !isValidPromptbookVersion(pipeline.promptbookVersion)) {
1794
+ // <- Note: [🚲]
1795
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Invalid Promptbook Version \"".concat(pipeline.promptbookVersion, "\"\n\n ").concat(block(pipelineIdentification), "\n "); }));
1796
+ }
1797
+ // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1798
+ if (!Array.isArray(pipeline.parameters)) {
1799
+ // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1800
+ throw new ParseError(spaceTrim.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 "); }));
1801
+ }
1802
+ // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1803
+ if (!Array.isArray(pipeline.templates)) {
1804
+ // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1805
+ throw new ParseError(spaceTrim.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 "); }));
1806
+ }
1807
+ var _loop_1 = function (parameter) {
1808
+ if (parameter.isInput && parameter.isOutput) {
1809
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n\n Parameter {".concat(parameter.name, "} can not be both input and output\n\n ").concat(block(pipelineIdentification), "\n "); }));
1810
+ }
1811
+ // Note: Testing that parameter is either intermediate or output BUT not created and unused
1812
+ if (!parameter.isInput &&
1813
+ !parameter.isOutput &&
1814
+ !pipeline.templates.some(function (template) { return template.dependentParameterNames.includes(parameter.name); })) {
1815
+ throw new PipelineLogicError(spaceTrim.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 "); }));
1816
+ }
1817
+ // Note: Testing that parameter is either input or result of some template
1818
+ if (!parameter.isInput &&
1819
+ !pipeline.templates.some(function (template) { return template.resultingParameterName === parameter.name; })) {
1820
+ throw new PipelineLogicError(spaceTrim.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 "); }));
1821
+ }
1822
+ };
1823
+ try {
1824
+ // Note: Check each parameter individually
1825
+ for (var _d = __values(pipeline.parameters), _e = _d.next(); !_e.done; _e = _d.next()) {
1826
+ var parameter = _e.value;
1827
+ _loop_1(parameter);
1828
+ }
1829
+ }
1830
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1831
+ finally {
1832
+ try {
1833
+ if (_e && !_e.done && (_a = _d.return)) _a.call(_d);
1834
+ }
1835
+ finally { if (e_1) throw e_1.error; }
1836
+ }
1837
+ // Note: All input parameters are defined - so that they can be used as result of some template
1838
+ var definedParameters = new Set(pipeline.parameters.filter(function (_a) {
1839
+ var isInput = _a.isInput;
1840
+ return isInput;
1841
+ }).map(function (_a) {
1842
+ var name = _a.name;
1843
+ return name;
1844
+ }));
1845
+ var _loop_2 = function (template) {
1846
+ var e_4, _h, e_5, _j;
1847
+ if (definedParameters.has(template.resultingParameterName)) {
1848
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Parameter {".concat(template.resultingParameterName, "} is defined multiple times\n\n ").concat(block(pipelineIdentification), "\n "); }));
1849
+ }
1850
+ if (RESERVED_PARAMETER_NAMES.includes(template.resultingParameterName)) {
1851
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Parameter name {".concat(template.resultingParameterName, "} is reserved, please use different name\n\n ").concat(block(pipelineIdentification), "\n "); }));
1852
+ }
1853
+ definedParameters.add(template.resultingParameterName);
1854
+ if (template.jokerParameterNames && template.jokerParameterNames.length > 0) {
1855
+ if (!template.format &&
1856
+ !template.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1857
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Joker parameters are used for {".concat(template.resultingParameterName, "} but no expectations are defined\n\n ").concat(block(pipelineIdentification), "\n "); }));
1858
+ }
1859
+ var _loop_4 = function (joker) {
1860
+ if (!template.dependentParameterNames.includes(joker)) {
1861
+ throw new PipelineLogicError(spaceTrim.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 "); }));
1862
+ }
1863
+ };
1864
+ try {
1865
+ for (var _k = (e_4 = void 0, __values(template.jokerParameterNames)), _l = _k.next(); !_l.done; _l = _k.next()) {
1866
+ var joker = _l.value;
1867
+ _loop_4(joker);
1868
+ }
1869
+ }
1870
+ catch (e_4_1) { e_4 = { error: e_4_1 }; }
1871
+ finally {
1872
+ try {
1873
+ if (_l && !_l.done && (_h = _k.return)) _h.call(_k);
1874
+ }
1875
+ finally { if (e_4) throw e_4.error; }
1876
+ }
1877
+ }
1878
+ if (template.expectations) {
1879
+ var _loop_5 = function (unit, min, max) {
1880
+ if (min !== undefined && max !== undefined && min > max) {
1881
+ throw new PipelineLogicError(spaceTrim.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 "); }));
1882
+ }
1883
+ if (min !== undefined && min < 0) {
1884
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Min expectation of ".concat(unit, " must be zero or positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1885
+ }
1886
+ if (max !== undefined && max <= 0) {
1887
+ throw new PipelineLogicError(spaceTrim.spaceTrim(function (block) { return "\n Max expectation of ".concat(unit, " must be positive\n\n ").concat(block(pipelineIdentification), "\n "); }));
1888
+ }
1889
+ };
1890
+ try {
1891
+ for (var _m = (e_5 = void 0, __values(Object.entries(template.expectations))), _o = _m.next(); !_o.done; _o = _m.next()) {
1892
+ var _p = __read(_o.value, 2), unit = _p[0], _q = _p[1], min = _q.min, max = _q.max;
1893
+ _loop_5(unit, min, max);
1894
+ }
1895
+ }
1896
+ catch (e_5_1) { e_5 = { error: e_5_1 }; }
1897
+ finally {
1898
+ try {
1899
+ if (_o && !_o.done && (_j = _m.return)) _j.call(_m);
1900
+ }
1901
+ finally { if (e_5) throw e_5.error; }
1902
+ }
1903
+ }
1904
+ };
1905
+ try {
1906
+ // Note: Checking each template individually
1907
+ for (var _f = __values(pipeline.templates), _g = _f.next(); !_g.done; _g = _f.next()) {
1908
+ var template = _g.value;
1909
+ _loop_2(template);
1910
+ }
1911
+ }
1912
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
1913
+ finally {
1914
+ try {
1915
+ if (_g && !_g.done && (_b = _f.return)) _b.call(_f);
1916
+ }
1917
+ finally { if (e_2) throw e_2.error; }
1918
+ }
1919
+ // Note: Detect circular dependencies
1920
+ var resovedParameters = pipeline.parameters
1921
+ .filter(function (_a) {
1922
+ var isInput = _a.isInput;
1923
+ return isInput;
1924
+ })
1925
+ .map(function (_a) {
1926
+ var name = _a.name;
1927
+ return name;
1928
+ });
1929
+ try {
1930
+ // Note: All reserved parameters are resolved
1931
+ 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()) {
1932
+ var reservedParameterName = RESERVED_PARAMETER_NAMES_1_1.value;
1933
+ resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), [reservedParameterName], false);
1934
+ }
1935
+ }
1936
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
1937
+ finally {
1938
+ try {
1939
+ if (RESERVED_PARAMETER_NAMES_1_1 && !RESERVED_PARAMETER_NAMES_1_1.done && (_c = RESERVED_PARAMETER_NAMES_1.return)) _c.call(RESERVED_PARAMETER_NAMES_1);
1940
+ }
1941
+ finally { if (e_3) throw e_3.error; }
1942
+ }
1943
+ var unresovedTemplates = __spreadArray([], __read(pipeline.templates), false);
1944
+ var loopLimit = LOOP_LIMIT;
1945
+ var _loop_3 = function () {
1946
+ if (loopLimit-- < 0) {
1947
+ // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1948
+ throw new UnexpectedError(spaceTrim.spaceTrim(function (block) { return "\n Loop limit reached during detection of circular dependencies in `validatePipeline`\n\n ".concat(block(pipelineIdentification), "\n "); }));
1949
+ }
1950
+ var currentlyResovedTemplates = unresovedTemplates.filter(function (template) {
1951
+ return template.dependentParameterNames.every(function (name) { return resovedParameters.includes(name); });
1952
+ });
1953
+ if (currentlyResovedTemplates.length === 0) {
1954
+ throw new PipelineLogicError(
1955
+ // TODO: [🐎] DRY
1956
+ spaceTrim.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
1957
+ .map(function (_a) {
1958
+ var resultingParameterName = _a.resultingParameterName, dependentParameterNames = _a.dependentParameterNames;
1959
+ return "- Parameter {".concat(resultingParameterName, "} which depends on ").concat(dependentParameterNames
1960
+ .map(function (dependentParameterName) { return "{".concat(dependentParameterName, "}"); })
1961
+ .join(' and '));
1962
+ })
1963
+ .join('\n')), "\n\n Resolved:\n ").concat(block(resovedParameters.map(function (name) { return "- Parameter {".concat(name, "}"); }).join('\n')), "\n\n\n "); }));
1964
+ }
1965
+ resovedParameters = __spreadArray(__spreadArray([], __read(resovedParameters), false), __read(currentlyResovedTemplates.map(function (_a) {
1966
+ var resultingParameterName = _a.resultingParameterName;
1967
+ return resultingParameterName;
1968
+ })), false);
1969
+ unresovedTemplates = unresovedTemplates.filter(function (template) { return !currentlyResovedTemplates.includes(template); });
1970
+ };
1971
+ while (unresovedTemplates.length > 0) {
1972
+ _loop_3();
1845
1973
  }
1846
- value = removeEmojis(value);
1847
- value = normalizeToKebabCase(value);
1848
- // TODO: [🧠] Maybe warn or add some padding to short name which are not good identifiers
1849
- return value;
1850
1974
  }
1975
+ /**
1976
+ * TODO: !!!!! [🧞‍♀️] Do not allow joker + foreach
1977
+ * TODO: [🧠] Work with promptbookVersion
1978
+ * TODO: Use here some json-schema, Zod or something similar and change it to:
1979
+ * > /**
1980
+ * > * Validates PipelineJson if it is logically valid.
1981
+ * > *
1982
+ * > * It checks:
1983
+ * > * - it has a valid structure
1984
+ * > * - ...
1985
+ * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
1986
+ */
1987
+ /**
1988
+ * TODO: [🧳][main] !!!! Validate that all samples match expectations
1989
+ * TODO: [🧳][🐝][main] !!!! Validate that knowledge is valid (non-void)
1990
+ * TODO: [🧳][main] !!!! Validate that persona can be used only with CHAT variant
1991
+ * TODO: [🧳][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1992
+ * TODO: [🧳][main] !!!! Validate that reserved parameter is not used as joker
1993
+ * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
1994
+ * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
1995
+ */
1851
1996
 
1852
1997
  /**
1853
- * This error indicates errors during the execution of the pipeline
1998
+ * This error indicates that promptbook not found in the collection
1854
1999
  *
1855
2000
  * @public exported from `@promptbook/core`
1856
2001
  */
1857
- var PipelineExecutionError = /** @class */ (function (_super) {
1858
- __extends(PipelineExecutionError, _super);
1859
- function PipelineExecutionError(message) {
2002
+ var NotFoundError = /** @class */ (function (_super) {
2003
+ __extends(NotFoundError, _super);
2004
+ function NotFoundError(message) {
1860
2005
  var _this = _super.call(this, message) || this;
1861
- _this.name = 'PipelineExecutionError';
1862
- Object.setPrototypeOf(_this, PipelineExecutionError.prototype);
2006
+ _this.name = 'NotFoundError';
2007
+ Object.setPrototypeOf(_this, NotFoundError.prototype);
1863
2008
  return _this;
1864
2009
  }
1865
- return PipelineExecutionError;
2010
+ return NotFoundError;
1866
2011
  }(Error));
1867
2012
 
1868
2013
  /**
1869
- * This error indicates that the pipeline collection cannot be propperly loaded
2014
+ * This error indicates errors in referencing promptbooks between each other
1870
2015
  *
1871
2016
  * @public exported from `@promptbook/core`
1872
2017
  */
1873
- var CollectionError = /** @class */ (function (_super) {
1874
- __extends(CollectionError, _super);
1875
- function CollectionError(message) {
2018
+ var PipelineUrlError = /** @class */ (function (_super) {
2019
+ __extends(PipelineUrlError, _super);
2020
+ function PipelineUrlError(message) {
1876
2021
  var _this = _super.call(this, message) || this;
1877
- _this.name = 'CollectionError';
1878
- Object.setPrototypeOf(_this, CollectionError.prototype);
2022
+ _this.name = 'PipelineUrlError';
2023
+ Object.setPrototypeOf(_this, PipelineUrlError.prototype);
1879
2024
  return _this;
1880
2025
  }
1881
- return CollectionError;
2026
+ return PipelineUrlError;
1882
2027
  }(Error));
1883
2028
 
1884
2029
  /**
1885
- * This error type indicates that you try to use a feature that is not available in the current environment
2030
+ * Parses the template and returns the list of all parameter names
2031
+ *
2032
+ * @param template the template with parameters in {curly} braces
2033
+ * @returns the list of parameter names
2034
+ * @public exported from `@promptbook/utils`
2035
+ */
2036
+ function extractParameterNames(template) {
2037
+ var e_1, _a;
2038
+ var matches = template.matchAll(/{\w+}/g);
2039
+ var parameterNames = new Set();
2040
+ try {
2041
+ for (var matches_1 = __values(matches), matches_1_1 = matches_1.next(); !matches_1_1.done; matches_1_1 = matches_1.next()) {
2042
+ var match = matches_1_1.value;
2043
+ var parameterName = match[0].slice(1, -1);
2044
+ parameterNames.add(parameterName);
2045
+ }
2046
+ }
2047
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2048
+ finally {
2049
+ try {
2050
+ if (matches_1_1 && !matches_1_1.done && (_a = matches_1.return)) _a.call(matches_1);
2051
+ }
2052
+ finally { if (e_1) throw e_1.error; }
2053
+ }
2054
+ return parameterNames;
2055
+ }
2056
+
2057
+ /**
2058
+ * Unprepare just strips the preparation data of the pipeline
1886
2059
  *
1887
2060
  * @public exported from `@promptbook/core`
1888
2061
  */
1889
- var EnvironmentMismatchError = /** @class */ (function (_super) {
1890
- __extends(EnvironmentMismatchError, _super);
1891
- function EnvironmentMismatchError(message) {
2062
+ function unpreparePipeline(pipeline) {
2063
+ var personas = pipeline.personas, knowledgeSources = pipeline.knowledgeSources, templates = pipeline.templates;
2064
+ personas = personas.map(function (persona) { return (__assign(__assign({}, persona), { modelRequirements: undefined, preparationIds: undefined })); });
2065
+ knowledgeSources = knowledgeSources.map(function (knowledgeSource) { return (__assign(__assign({}, knowledgeSource), { preparationIds: undefined })); });
2066
+ templates = templates.map(function (template) {
2067
+ var dependentParameterNames = template.dependentParameterNames;
2068
+ var parameterNames = extractParameterNames(template.preparedContent || '');
2069
+ dependentParameterNames = dependentParameterNames.filter(function (dependentParameterName) { return !parameterNames.has(dependentParameterName); });
2070
+ var templateUnprepared = __assign(__assign({}, template), { dependentParameterNames: dependentParameterNames });
2071
+ delete templateUnprepared.preparedContent;
2072
+ return templateUnprepared;
2073
+ });
2074
+ return $asDeeplyFrozenSerializableJson('Unprepared PipelineJson', __assign(__assign({}, pipeline), { templates: templates, knowledgeSources: knowledgeSources, knowledgePieces: [], personas: personas, preparations: [] }));
2075
+ }
2076
+ /**
2077
+ * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
2078
+ * TODO: Write tests for `preparePipeline`
2079
+ * TODO: [🍙] Make some standard order of json properties
2080
+ */
2081
+
2082
+ /**
2083
+ * Library of pipelines that groups together pipelines for an application.
2084
+ * This implementation is a very thin wrapper around the Array / Map of pipelines.
2085
+ *
2086
+ * @private internal function of `createCollectionFromJson`, use `createCollectionFromJson` instead
2087
+ * @see https://github.com/webgptorg/pipeline#pipeline-collection
2088
+ */
2089
+ var SimplePipelineCollection = /** @class */ (function () {
2090
+ /**
2091
+ * Constructs a pipeline collection from pipelines
2092
+ *
2093
+ * @param pipelines @@@
2094
+ *
2095
+ * Note: During the construction logic of all pipelines are validated
2096
+ * Note: It is not recommended to use this constructor directly, use `createCollectionFromJson` *(or other variant)* instead
2097
+ */
2098
+ function SimplePipelineCollection() {
2099
+ var e_1, _a;
2100
+ var pipelines = [];
2101
+ for (var _i = 0; _i < arguments.length; _i++) {
2102
+ pipelines[_i] = arguments[_i];
2103
+ }
2104
+ this.collection = new Map();
2105
+ try {
2106
+ for (var pipelines_1 = __values(pipelines), pipelines_1_1 = pipelines_1.next(); !pipelines_1_1.done; pipelines_1_1 = pipelines_1.next()) {
2107
+ var pipeline = pipelines_1_1.value;
2108
+ // TODO: [👠] DRY
2109
+ if (pipeline.pipelineUrl === undefined) {
2110
+ throw new PipelineUrlError(spaceTrim.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 ")));
2111
+ }
2112
+ // Note: [🐨]
2113
+ validatePipeline(pipeline);
2114
+ // TODO: [🦄] DRY
2115
+ // Note: [🦄]
2116
+ if (
2117
+ // TODO: [🐽]
2118
+ this.collection.has(pipeline.pipelineUrl) &&
2119
+ pipelineJsonToString(unpreparePipeline(pipeline)) !==
2120
+ pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
2121
+ var existing = this.collection.get(pipeline.pipelineUrl);
2122
+ throw new PipelineUrlError(spaceTrim.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 ")));
2123
+ }
2124
+ // Note: [🧠] Overwrite existing pipeline with the same URL
2125
+ this.collection.set(pipeline.pipelineUrl, pipeline);
2126
+ }
2127
+ }
2128
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2129
+ finally {
2130
+ try {
2131
+ if (pipelines_1_1 && !pipelines_1_1.done && (_a = pipelines_1.return)) _a.call(pipelines_1);
2132
+ }
2133
+ finally { if (e_1) throw e_1.error; }
2134
+ }
2135
+ }
2136
+ /**
2137
+ * Gets all pipelines in the collection
2138
+ */
2139
+ SimplePipelineCollection.prototype.listPipelines = function () {
2140
+ return Array.from(this.collection.keys());
2141
+ };
2142
+ /**
2143
+ * Gets pipeline by its URL
2144
+ *
2145
+ * Note: This is not a direct fetching from the URL, but a lookup in the collection
2146
+ */
2147
+ SimplePipelineCollection.prototype.getPipelineByUrl = function (url) {
2148
+ var _this = this;
2149
+ var pipeline = this.collection.get(url);
2150
+ if (!pipeline) {
2151
+ if (this.listPipelines().length === 0) {
2152
+ throw new NotFoundError(spaceTrim.spaceTrim("\n Pipeline with url \"".concat(url, "\" not found\n\n No pipelines available\n ")));
2153
+ }
2154
+ throw new NotFoundError(spaceTrim.spaceTrim(function (block) { return "\n Pipeline with url \"".concat(url, "\" not found\n\n Available pipelines:\n ").concat(block(_this.listPipelines()
2155
+ .map(function (pipelineUrl) { return "- ".concat(pipelineUrl); })
2156
+ .join('\n')), "\n\n "); }));
2157
+ }
2158
+ return pipeline;
2159
+ };
2160
+ /**
2161
+ * Checks whether given prompt was defined in any pipeline in the collection
2162
+ */
2163
+ SimplePipelineCollection.prototype.isResponsibleForPrompt = function (prompt) {
2164
+ return true;
2165
+ };
2166
+ return SimplePipelineCollection;
2167
+ }());
2168
+
2169
+ /**
2170
+ * Creates PipelineCollection from array of PipelineJson or PipelineString
2171
+ *
2172
+ * Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
2173
+ * Note: Syntax, parsing, and logic consistency checks are performed on all sources during build
2174
+ *
2175
+ * @param promptbookSources
2176
+ * @returns PipelineCollection
2177
+ * @public exported from `@promptbook/core`
2178
+ */
2179
+ function createCollectionFromJson() {
2180
+ var promptbooks = [];
2181
+ for (var _i = 0; _i < arguments.length; _i++) {
2182
+ promptbooks[_i] = arguments[_i];
2183
+ }
2184
+ return new (SimplePipelineCollection.bind.apply(SimplePipelineCollection, __spreadArray([void 0], __read(promptbooks), false)))();
2185
+ }
2186
+
2187
+ /**
2188
+ * This error indicates errors during the execution of the pipeline
2189
+ *
2190
+ * @public exported from `@promptbook/core`
2191
+ */
2192
+ var PipelineExecutionError = /** @class */ (function (_super) {
2193
+ __extends(PipelineExecutionError, _super);
2194
+ function PipelineExecutionError(message) {
1892
2195
  var _this = _super.call(this, message) || this;
1893
- _this.name = 'EnvironmentMismatchError';
1894
- Object.setPrototypeOf(_this, EnvironmentMismatchError.prototype);
2196
+ _this.name = 'PipelineExecutionError';
2197
+ Object.setPrototypeOf(_this, PipelineExecutionError.prototype);
1895
2198
  return _this;
1896
2199
  }
1897
- return EnvironmentMismatchError;
2200
+ return PipelineExecutionError;
2201
+ }(Error));
2202
+
2203
+ /**
2204
+ * This error indicates that the pipeline collection cannot be propperly loaded
2205
+ *
2206
+ * @public exported from `@promptbook/core`
2207
+ */
2208
+ var CollectionError = /** @class */ (function (_super) {
2209
+ __extends(CollectionError, _super);
2210
+ function CollectionError(message) {
2211
+ var _this = _super.call(this, message) || this;
2212
+ _this.name = 'CollectionError';
2213
+ Object.setPrototypeOf(_this, CollectionError.prototype);
2214
+ return _this;
2215
+ }
2216
+ return CollectionError;
1898
2217
  }(Error));
1899
2218
 
1900
2219
  /**
@@ -2395,6 +2714,59 @@
2395
2714
  * TODO: [🧠] Is there a way how to meaningfully test this utility
2396
2715
  */
2397
2716
 
2717
+ /**
2718
+ * Represents the usage with no resources consumed
2719
+ *
2720
+ * @public exported from `@promptbook/core`
2721
+ */
2722
+ var ZERO_USAGE = $deepFreeze({
2723
+ price: { value: 0 },
2724
+ input: {
2725
+ tokensCount: { value: 0 },
2726
+ charactersCount: { value: 0 },
2727
+ wordsCount: { value: 0 },
2728
+ sentencesCount: { value: 0 },
2729
+ linesCount: { value: 0 },
2730
+ paragraphsCount: { value: 0 },
2731
+ pagesCount: { value: 0 },
2732
+ },
2733
+ output: {
2734
+ tokensCount: { value: 0 },
2735
+ charactersCount: { value: 0 },
2736
+ wordsCount: { value: 0 },
2737
+ sentencesCount: { value: 0 },
2738
+ linesCount: { value: 0 },
2739
+ paragraphsCount: { value: 0 },
2740
+ pagesCount: { value: 0 },
2741
+ },
2742
+ });
2743
+ /**
2744
+ * Represents the usage with unknown resources consumed
2745
+ *
2746
+ * @public exported from `@promptbook/core`
2747
+ */
2748
+ $deepFreeze({
2749
+ price: { value: 0, isUncertain: true },
2750
+ input: {
2751
+ tokensCount: { value: 0, isUncertain: true },
2752
+ charactersCount: { value: 0, isUncertain: true },
2753
+ wordsCount: { value: 0, isUncertain: true },
2754
+ sentencesCount: { value: 0, isUncertain: true },
2755
+ linesCount: { value: 0, isUncertain: true },
2756
+ paragraphsCount: { value: 0, isUncertain: true },
2757
+ pagesCount: { value: 0, isUncertain: true },
2758
+ },
2759
+ output: {
2760
+ tokensCount: { value: 0, isUncertain: true },
2761
+ charactersCount: { value: 0, isUncertain: true },
2762
+ wordsCount: { value: 0, isUncertain: true },
2763
+ sentencesCount: { value: 0, isUncertain: true },
2764
+ linesCount: { value: 0, isUncertain: true },
2765
+ paragraphsCount: { value: 0, isUncertain: true },
2766
+ pagesCount: { value: 0, isUncertain: true },
2767
+ },
2768
+ });
2769
+
2398
2770
  /**
2399
2771
  * Function `addUsage` will add multiple usages into one
2400
2772
  *
@@ -2673,29 +3045,12 @@
2673
3045
  }
2674
3046
 
2675
3047
  /**
2676
- * Just marks a place of place where should be something implemented
2677
- * No side effects.
3048
+ * This error indicates problems parsing the format value
2678
3049
  *
2679
- * Note: It can be usefull suppressing eslint errors of unused variables
3050
+ * For example, when the format value is not a valid JSON or CSV
3051
+ * This is not thrown directly but in extended classes
2680
3052
  *
2681
- * @param value any values
2682
- * @returns void
2683
- * @private within the repository
2684
- */
2685
- function TODO_USE() {
2686
- var value = [];
2687
- for (var _i = 0; _i < arguments.length; _i++) {
2688
- value[_i] = arguments[_i];
2689
- }
2690
- }
2691
-
2692
- /**
2693
- * This error indicates problems parsing the format value
2694
- *
2695
- * For example, when the format value is not a valid JSON or CSV
2696
- * This is not thrown directly but in extended classes
2697
- *
2698
- * @public exported from `@promptbook/core`
3053
+ * @public exported from `@promptbook/core`
2699
3054
  */
2700
3055
  var AbstractFormatError = /** @class */ (function (_super) {
2701
3056
  __extends(AbstractFormatError, _super);
@@ -2732,7 +3087,7 @@
2732
3087
  */
2733
3088
  var MANDATORY_CSV_SETTINGS = Object.freeze({
2734
3089
  header: true,
2735
- // encoding: 'utf8',
3090
+ // encoding: 'utf-8',
2736
3091
  });
2737
3092
 
2738
3093
  /**
@@ -4164,25 +4519,26 @@
4164
4519
  */
4165
4520
  function executePipeline(options) {
4166
4521
  return __awaiter(this, void 0, void 0, function () {
4167
- 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;
4168
- var e_1, _e, e_2, _f;
4169
- return __generator(this, function (_g) {
4170
- switch (_g.label) {
4522
+ 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;
4523
+ var e_1, _f, e_2, _g;
4524
+ return __generator(this, function (_h) {
4525
+ switch (_h.label) {
4171
4526
  case 0:
4172
4527
  inputParameters = options.inputParameters, tools = options.tools, onProgress = options.onProgress, pipeline = options.pipeline, setPreparedPipeline = options.setPreparedPipeline, pipelineIdentification = options.pipelineIdentification, settings = options.settings;
4173
- maxParallelCount = settings.maxParallelCount, isVerbose = settings.isVerbose;
4528
+ maxParallelCount = settings.maxParallelCount, rootDirname = settings.rootDirname, _a = settings.isVerbose, isVerbose = _a === void 0 ? IS_VERBOSE : _a;
4174
4529
  preparedPipeline = options.preparedPipeline;
4175
4530
  llmTools = joinLlmExecutionTools.apply(void 0, __spreadArray([], __read(arrayableToArray(tools.llm)), false));
4176
4531
  if (!(preparedPipeline === undefined)) return [3 /*break*/, 2];
4177
4532
  return [4 /*yield*/, preparePipeline(pipeline, {
4178
4533
  llmTools: llmTools,
4534
+ rootDirname: rootDirname,
4179
4535
  isVerbose: isVerbose,
4180
4536
  maxParallelCount: maxParallelCount,
4181
4537
  })];
4182
4538
  case 1:
4183
- preparedPipeline = _g.sent();
4539
+ preparedPipeline = _h.sent();
4184
4540
  setPreparedPipeline(preparedPipeline);
4185
- _g.label = 2;
4541
+ _h.label = 2;
4186
4542
  case 2:
4187
4543
  errors = [];
4188
4544
  warnings = [];
@@ -4195,17 +4551,17 @@
4195
4551
  promptExecutions: [],
4196
4552
  };
4197
4553
  isReturned = false;
4198
- _g.label = 3;
4554
+ _h.label = 3;
4199
4555
  case 3:
4200
- _g.trys.push([3, 9, 10, 11]);
4201
- _a = __values(preparedPipeline.parameters.filter(function (_a) {
4556
+ _h.trys.push([3, 9, 10, 11]);
4557
+ _b = __values(preparedPipeline.parameters.filter(function (_a) {
4202
4558
  var isInput = _a.isInput;
4203
4559
  return isInput;
4204
- })), _b = _a.next();
4205
- _g.label = 4;
4560
+ })), _c = _b.next();
4561
+ _h.label = 4;
4206
4562
  case 4:
4207
- if (!!_b.done) return [3 /*break*/, 8];
4208
- parameter = _b.value;
4563
+ if (!!_c.done) return [3 /*break*/, 8];
4564
+ parameter = _c.value;
4209
4565
  if (!(inputParameters[parameter.name] === undefined)) return [3 /*break*/, 7];
4210
4566
  isReturned = true;
4211
4567
  if (!(onProgress !== undefined)) return [3 /*break*/, 6];
@@ -4213,8 +4569,8 @@
4213
4569
  return [4 /*yield*/, waitasecond.forTime(IMMEDIATE_TIME)];
4214
4570
  case 5:
4215
4571
  // Note: Wait a short time to prevent race conditions
4216
- _g.sent();
4217
- _g.label = 6;
4572
+ _h.sent();
4573
+ _h.label = 6;
4218
4574
  case 6: return [2 /*return*/, $asDeeplyFrozenSerializableJson("Unuccessful PipelineExecutorResult (with missing parameter {".concat(parameter.name, "}) PipelineExecutorResult"), {
4219
4575
  isSuccessful: false,
4220
4576
  errors: __spreadArray([
@@ -4227,24 +4583,24 @@
4227
4583
  preparedPipeline: preparedPipeline,
4228
4584
  })];
4229
4585
  case 7:
4230
- _b = _a.next();
4586
+ _c = _b.next();
4231
4587
  return [3 /*break*/, 4];
4232
4588
  case 8: return [3 /*break*/, 11];
4233
4589
  case 9:
4234
- e_1_1 = _g.sent();
4590
+ e_1_1 = _h.sent();
4235
4591
  e_1 = { error: e_1_1 };
4236
4592
  return [3 /*break*/, 11];
4237
4593
  case 10:
4238
4594
  try {
4239
- if (_b && !_b.done && (_e = _a.return)) _e.call(_a);
4595
+ if (_c && !_c.done && (_f = _b.return)) _f.call(_b);
4240
4596
  }
4241
4597
  finally { if (e_1) throw e_1.error; }
4242
4598
  return [7 /*endfinally*/];
4243
4599
  case 11:
4244
4600
  _loop_1 = function (parameterName) {
4245
4601
  var parameter;
4246
- return __generator(this, function (_h) {
4247
- switch (_h.label) {
4602
+ return __generator(this, function (_j) {
4603
+ switch (_j.label) {
4248
4604
  case 0:
4249
4605
  parameter = preparedPipeline.parameters.find(function (_a) {
4250
4606
  var name = _a.name;
@@ -4261,8 +4617,8 @@
4261
4617
  return [4 /*yield*/, waitasecond.forTime(IMMEDIATE_TIME)];
4262
4618
  case 2:
4263
4619
  // Note: Wait a short time to prevent race conditions
4264
- _h.sent();
4265
- _h.label = 3;
4620
+ _j.sent();
4621
+ _j.label = 3;
4266
4622
  case 3: return [2 /*return*/, { value: $asDeeplyFrozenSerializableJson(spaceTrim.spaceTrim(function (block) { return "\n Unuccessful PipelineExecutorResult (with extra parameter {".concat(parameter.name, "}) PipelineExecutorResult\n\n ").concat(block(pipelineIdentification), "\n "); }), {
4267
4623
  isSuccessful: false,
4268
4624
  errors: __spreadArray([
@@ -4278,39 +4634,39 @@
4278
4634
  }
4279
4635
  });
4280
4636
  };
4281
- _g.label = 12;
4637
+ _h.label = 12;
4282
4638
  case 12:
4283
- _g.trys.push([12, 17, 18, 19]);
4284
- _c = __values(Object.keys(inputParameters)), _d = _c.next();
4285
- _g.label = 13;
4639
+ _h.trys.push([12, 17, 18, 19]);
4640
+ _d = __values(Object.keys(inputParameters)), _e = _d.next();
4641
+ _h.label = 13;
4286
4642
  case 13:
4287
- if (!!_d.done) return [3 /*break*/, 16];
4288
- parameterName = _d.value;
4643
+ if (!!_e.done) return [3 /*break*/, 16];
4644
+ parameterName = _e.value;
4289
4645
  return [5 /*yield**/, _loop_1(parameterName)];
4290
4646
  case 14:
4291
- state_1 = _g.sent();
4647
+ state_1 = _h.sent();
4292
4648
  if (typeof state_1 === "object")
4293
4649
  return [2 /*return*/, state_1.value];
4294
- _g.label = 15;
4650
+ _h.label = 15;
4295
4651
  case 15:
4296
- _d = _c.next();
4652
+ _e = _d.next();
4297
4653
  return [3 /*break*/, 13];
4298
4654
  case 16: return [3 /*break*/, 19];
4299
4655
  case 17:
4300
- e_2_1 = _g.sent();
4656
+ e_2_1 = _h.sent();
4301
4657
  e_2 = { error: e_2_1 };
4302
4658
  return [3 /*break*/, 19];
4303
4659
  case 18:
4304
4660
  try {
4305
- if (_d && !_d.done && (_f = _c.return)) _f.call(_c);
4661
+ if (_e && !_e.done && (_g = _d.return)) _g.call(_d);
4306
4662
  }
4307
4663
  finally { if (e_2) throw e_2.error; }
4308
4664
  return [7 /*endfinally*/];
4309
4665
  case 19:
4310
4666
  parametersToPass = inputParameters;
4311
- _g.label = 20;
4667
+ _h.label = 20;
4312
4668
  case 20:
4313
- _g.trys.push([20, 25, , 28]);
4669
+ _h.trys.push([20, 25, , 28]);
4314
4670
  resovedParameterNames_1 = preparedPipeline.parameters
4315
4671
  .filter(function (_a) {
4316
4672
  var isInput = _a.isInput;
@@ -4325,8 +4681,8 @@
4325
4681
  loopLimit = LOOP_LIMIT;
4326
4682
  _loop_2 = function () {
4327
4683
  var currentTemplate, work_1;
4328
- return __generator(this, function (_j) {
4329
- switch (_j.label) {
4684
+ return __generator(this, function (_k) {
4685
+ switch (_k.label) {
4330
4686
  case 0:
4331
4687
  if (loopLimit-- < 0) {
4332
4688
  // Note: Really UnexpectedError not LimitReachedError - this should be catched during validatePipeline
@@ -4352,7 +4708,7 @@
4352
4708
  if (!!currentTemplate) return [3 /*break*/, 3];
4353
4709
  /* [🤹‍♂️] */ return [4 /*yield*/, Promise.race(resolving_1)];
4354
4710
  case 2:
4355
- /* [🤹‍♂️] */ _j.sent();
4711
+ /* [🤹‍♂️] */ _k.sent();
4356
4712
  return [3 /*break*/, 4];
4357
4713
  case 3:
4358
4714
  unresovedTemplates_1 = unresovedTemplates_1.filter(function (template) { return template !== currentTemplate; });
@@ -4387,24 +4743,24 @@
4387
4743
  // <- Note: Errors are catched here [3]
4388
4744
  // 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
4389
4745
  resolving_1.push(work_1);
4390
- _j.label = 4;
4746
+ _k.label = 4;
4391
4747
  case 4: return [2 /*return*/];
4392
4748
  }
4393
4749
  });
4394
4750
  };
4395
- _g.label = 21;
4751
+ _h.label = 21;
4396
4752
  case 21:
4397
4753
  if (!(unresovedTemplates_1.length > 0)) return [3 /*break*/, 23];
4398
4754
  return [5 /*yield**/, _loop_2()];
4399
4755
  case 22:
4400
- _g.sent();
4756
+ _h.sent();
4401
4757
  return [3 /*break*/, 21];
4402
4758
  case 23: return [4 /*yield*/, Promise.all(resolving_1)];
4403
4759
  case 24:
4404
- _g.sent();
4760
+ _h.sent();
4405
4761
  return [3 /*break*/, 28];
4406
4762
  case 25:
4407
- error_1 = _g.sent();
4763
+ error_1 = _h.sent();
4408
4764
  if (!(error_1 instanceof Error)) {
4409
4765
  throw error_1;
4410
4766
  }
@@ -4424,8 +4780,8 @@
4424
4780
  return [4 /*yield*/, waitasecond.forTime(IMMEDIATE_TIME)];
4425
4781
  case 26:
4426
4782
  // Note: Wait a short time to prevent race conditions
4427
- _g.sent();
4428
- _g.label = 27;
4783
+ _h.sent();
4784
+ _h.label = 27;
4429
4785
  case 27: return [2 /*return*/, $asDeeplyFrozenSerializableJson('Unuccessful PipelineExecutorResult (with misc errors) PipelineExecutorResult', {
4430
4786
  isSuccessful: false,
4431
4787
  errors: __spreadArray([error_1], __read(errors), false).map(serializeError),
@@ -4452,8 +4808,8 @@
4452
4808
  return [4 /*yield*/, waitasecond.forTime(IMMEDIATE_TIME)];
4453
4809
  case 29:
4454
4810
  // Note: Wait a short time to prevent race conditions
4455
- _g.sent();
4456
- _g.label = 30;
4811
+ _h.sent();
4812
+ _h.label = 30;
4457
4813
  case 30: return [2 /*return*/, $asDeeplyFrozenSerializableJson('Successful PipelineExecutorResult', {
4458
4814
  isSuccessful: true,
4459
4815
  errors: errors.map(serializeError),
@@ -4465,211 +4821,883 @@
4465
4821
  })];
4466
4822
  }
4467
4823
  });
4468
- });
4469
- }
4824
+ });
4825
+ }
4826
+ /**
4827
+ * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
4828
+ */
4829
+
4830
+ /**
4831
+ * Creates executor function from pipeline and execution tools.
4832
+ *
4833
+ * @returns The executor function
4834
+ * @throws {PipelineLogicError} on logical error in the pipeline
4835
+ * @public exported from `@promptbook/core`
4836
+ */
4837
+ function createPipelineExecutor(options) {
4838
+ var _this = this;
4839
+ var pipeline = options.pipeline, tools = options.tools, _a = options.settings, settings = _a === void 0 ? {} : _a;
4840
+ 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;
4841
+ validatePipeline(pipeline);
4842
+ var pipelineIdentification = (function () {
4843
+ // Note: This is a 😐 implementation of [🚞]
4844
+ var _ = [];
4845
+ if (pipeline.sourceFile !== undefined) {
4846
+ _.push("File: ".concat(pipeline.sourceFile));
4847
+ }
4848
+ if (pipeline.pipelineUrl !== undefined) {
4849
+ _.push("Url: ".concat(pipeline.pipelineUrl));
4850
+ }
4851
+ return _.join('\n');
4852
+ })();
4853
+ var preparedPipeline;
4854
+ if (isPipelinePrepared(pipeline)) {
4855
+ preparedPipeline = pipeline;
4856
+ }
4857
+ else if (isNotPreparedWarningSupressed !== true) {
4858
+ console.warn(spaceTrim.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 "); }));
4859
+ }
4860
+ var runCount = 0;
4861
+ var pipelineExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
4862
+ return __generator(this, function (_a) {
4863
+ runCount++;
4864
+ return [2 /*return*/, /* not await */ executePipeline({
4865
+ pipeline: pipeline,
4866
+ preparedPipeline: preparedPipeline,
4867
+ setPreparedPipeline: function (newPreparedPipeline) {
4868
+ preparedPipeline = newPreparedPipeline;
4869
+ },
4870
+ inputParameters: inputParameters,
4871
+ tools: tools,
4872
+ onProgress: onProgress,
4873
+ pipelineIdentification: spaceTrim.spaceTrim(function (block) { return "\n ".concat(block(pipelineIdentification), "\n ").concat(runCount === 1 ? '' : "Run #".concat(runCount), "\n "); }),
4874
+ settings: {
4875
+ maxExecutionAttempts: maxExecutionAttempts,
4876
+ maxParallelCount: maxParallelCount,
4877
+ csvSettings: csvSettings,
4878
+ isVerbose: isVerbose,
4879
+ isNotPreparedWarningSupressed: isNotPreparedWarningSupressed,
4880
+ rootDirname: rootDirname,
4881
+ },
4882
+ })];
4883
+ });
4884
+ }); };
4885
+ return pipelineExecutor;
4886
+ }
4887
+ /**
4888
+ * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
4889
+ */
4890
+
4891
+ /**
4892
+ * Scraper for markdown files
4893
+ *
4894
+ * @see `documentationUrl` for more details
4895
+ * @public exported from `@promptbook/core`
4896
+ */
4897
+ var markdownScraper = {
4898
+ /**
4899
+ * Mime types that this scraper can handle
4900
+ */
4901
+ mimeTypes: ['text/markdown', 'text/plain'],
4902
+ /**
4903
+ * Link to documentation
4904
+ */
4905
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
4906
+ /**
4907
+ * Scrapes the markdown file and returns the knowledge pieces or `null` if it can't scrape it
4908
+ */
4909
+ scrape: function (source, options) {
4910
+ return __awaiter(this, void 0, void 0, function () {
4911
+ var llmTools, _a, maxParallelCount, _b, isVerbose, collection, prepareKnowledgeFromMarkdownExecutor, _c, prepareTitleExecutor, _d, prepareKeywordsExecutor, _e, knowledgeContent, result, outputParameters, knowledgePiecesRaw, knowledgeTextPieces, knowledge;
4912
+ var _f, _g, _h;
4913
+ var _this = this;
4914
+ return __generator(this, function (_j) {
4915
+ switch (_j.label) {
4916
+ case 0:
4917
+ llmTools = options.llmTools, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
4918
+ if (llmTools === undefined) {
4919
+ throw new MissingToolsError('LLM tools are required for scraping external files');
4920
+ // <- Note: This scraper is used in all other scrapers, so saying "external files" not "markdown files"
4921
+ }
4922
+ TODO_USE(maxParallelCount); // <- [🪂]
4923
+ collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
4924
+ _c = createPipelineExecutor;
4925
+ _f = {};
4926
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md')];
4927
+ case 1:
4928
+ prepareKnowledgeFromMarkdownExecutor = _c.apply(void 0, [(_f.pipeline = _j.sent(),
4929
+ _f.tools = {
4930
+ llm: llmTools,
4931
+ },
4932
+ _f)]);
4933
+ _d = createPipelineExecutor;
4934
+ _g = {};
4935
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md')];
4936
+ case 2:
4937
+ prepareTitleExecutor = _d.apply(void 0, [(_g.pipeline = _j.sent(),
4938
+ _g.tools = {
4939
+ llm: llmTools,
4940
+ },
4941
+ _g)]);
4942
+ _e = createPipelineExecutor;
4943
+ _h = {};
4944
+ return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md')];
4945
+ case 3:
4946
+ prepareKeywordsExecutor = _e.apply(void 0, [(_h.pipeline = _j.sent(),
4947
+ _h.tools = {
4948
+ llm: llmTools,
4949
+ },
4950
+ _h)]);
4951
+ return [4 /*yield*/, source.asText()];
4952
+ case 4:
4953
+ knowledgeContent = _j.sent();
4954
+ return [4 /*yield*/, prepareKnowledgeFromMarkdownExecutor({ knowledgeContent: knowledgeContent })];
4955
+ case 5:
4956
+ result = _j.sent();
4957
+ assertsExecutionSuccessful(result);
4958
+ outputParameters = result.outputParameters;
4959
+ knowledgePiecesRaw = outputParameters.knowledgePieces;
4960
+ knowledgeTextPieces = (knowledgePiecesRaw || '').split('\n---\n');
4961
+ // <- TODO: [main] !!!!! Smarter split and filter out empty pieces
4962
+ if (isVerbose) {
4963
+ console.info('knowledgeTextPieces:', knowledgeTextPieces);
4964
+ }
4965
+ return [4 /*yield*/, Promise.all(
4966
+ // TODO: [🪂] !! Do not send all at once but in chunks
4967
+ knowledgeTextPieces.map(function (knowledgeTextPiece, i) { return __awaiter(_this, void 0, void 0, function () {
4968
+ var name, title, knowledgePieceContent, keywords, index, titleResult, _a, titleRaw, keywordsResult, _b, keywordsRaw, embeddingResult, error_1;
4969
+ return __generator(this, function (_c) {
4970
+ switch (_c.label) {
4971
+ case 0:
4972
+ name = "piece-".concat(i);
4973
+ title = spaceTrim__default["default"](knowledgeTextPiece.substring(0, 100));
4974
+ knowledgePieceContent = spaceTrim__default["default"](knowledgeTextPiece);
4975
+ keywords = [];
4976
+ index = [];
4977
+ _c.label = 1;
4978
+ case 1:
4979
+ _c.trys.push([1, 7, , 8]);
4980
+ return [4 /*yield*/, prepareTitleExecutor({ knowledgePieceContent: knowledgePieceContent })];
4981
+ case 2:
4982
+ titleResult = _c.sent();
4983
+ _a = titleResult.outputParameters.title, titleRaw = _a === void 0 ? 'Untitled' : _a;
4984
+ title = spaceTrim__default["default"](titleRaw) /* <- TODO: Maybe do in pipeline */;
4985
+ name = titleToName(title);
4986
+ return [4 /*yield*/, prepareKeywordsExecutor({ knowledgePieceContent: knowledgePieceContent })];
4987
+ case 3:
4988
+ keywordsResult = _c.sent();
4989
+ _b = keywordsResult.outputParameters.keywords, keywordsRaw = _b === void 0 ? '' : _b;
4990
+ keywords = (keywordsRaw || '')
4991
+ .split(',')
4992
+ .map(function (keyword) { return keyword.trim(); })
4993
+ .filter(function (keyword) { return keyword !== ''; });
4994
+ if (isVerbose) {
4995
+ console.info("Keywords for \"".concat(title, "\":"), keywords);
4996
+ }
4997
+ if (!!llmTools.callEmbeddingModel) return [3 /*break*/, 4];
4998
+ // TODO: [🟥] Detect browser / node and make it colorfull
4999
+ console.error('No callEmbeddingModel function provided');
5000
+ return [3 /*break*/, 6];
5001
+ case 4: return [4 /*yield*/, llmTools.callEmbeddingModel({
5002
+ title: "Embedding for ".concat(title) /* <- Note: No impact on embedding result itself, just for logging */,
5003
+ parameters: {},
5004
+ content: knowledgePieceContent,
5005
+ modelRequirements: {
5006
+ modelVariant: 'EMBEDDING',
5007
+ },
5008
+ })];
5009
+ case 5:
5010
+ embeddingResult = _c.sent();
5011
+ index.push({
5012
+ modelName: embeddingResult.modelName,
5013
+ position: embeddingResult.content,
5014
+ });
5015
+ _c.label = 6;
5016
+ case 6: return [3 /*break*/, 8];
5017
+ case 7:
5018
+ error_1 = _c.sent();
5019
+ // Note: Here is expected error:
5020
+ // > PipelineExecutionError: You have not provided any `LlmExecutionTools` that support model variant "EMBEDDING
5021
+ if (!(error_1 instanceof PipelineExecutionError)) {
5022
+ throw error_1;
5023
+ }
5024
+ // TODO: [🟥] Detect browser / node and make it colorfull
5025
+ console.error(error_1, "<- Note: This error is not critical to prepare the pipeline, just knowledge pieces won't have embeddings");
5026
+ return [3 /*break*/, 8];
5027
+ case 8: return [2 /*return*/, {
5028
+ name: name,
5029
+ title: title,
5030
+ content: knowledgePieceContent,
5031
+ keywords: keywords,
5032
+ index: index,
5033
+ // <- TODO: [☀] sources,
5034
+ }];
5035
+ }
5036
+ });
5037
+ }); }))];
5038
+ case 6:
5039
+ knowledge = _j.sent();
5040
+ return [2 /*return*/, knowledge];
5041
+ }
5042
+ });
5043
+ });
5044
+ },
5045
+ } /* TODO: [🦷] as const */;
5046
+ /**
5047
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5048
+ * TODO: [🪂] Do it in parallel 11:11
5049
+ * TODO: [🦷] Ideally use `as const satisfies Scraper` BUT this combination throws errors
5050
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5051
+ */
5052
+
5053
+ /**
5054
+ * Scraper of .docx and .odt files
5055
+ *
5056
+ * @see `documentationUrl` for more details
5057
+ * @public exported from `@promptbook/core`
5058
+ */
5059
+ var documentScraper = {
5060
+ /**
5061
+ * Mime types that this scraper can handle
5062
+ */
5063
+ mimeTypes: ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'],
5064
+ /**
5065
+ * Link to documentation
5066
+ */
5067
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5068
+ /**
5069
+ * Convert the `.docx` or `.odt` to `.md` file and returns intermediate source
5070
+ *
5071
+ * 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
5072
+ */
5073
+ $convert: function (source, options) {
5074
+ return __awaiter(this, void 0, void 0, function () {
5075
+ var _a, externalProgramsPaths, rootDirname, _b, cacheDirname, _c, isCacheCleaned, _d, isVerbose, extension, cacheFilehandler, command_1;
5076
+ return __generator(this, function (_e) {
5077
+ switch (_e.label) {
5078
+ case 0:
5079
+ _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;
5080
+ if (!$isRunningInNode()) {
5081
+ throw new KnowledgeScrapeError('Scraping .docx files is only supported in Node environment');
5082
+ }
5083
+ if (externalProgramsPaths.pandocPath === undefined) {
5084
+ throw new MissingToolsError('Pandoc is required for scraping .docx files');
5085
+ }
5086
+ if (source.filename === null) {
5087
+ // TODO: [🧠] Maybe save file as temporary
5088
+ throw new KnowledgeScrapeError('When parsing .docx file, it must be real file in the file system');
5089
+ }
5090
+ extension = getFileExtension(source.filename);
5091
+ return [4 /*yield*/, getScraperIntermediateSource(source, {
5092
+ rootDirname: rootDirname,
5093
+ cacheDirname: cacheDirname,
5094
+ isCacheCleaned: isCacheCleaned,
5095
+ extension: 'md',
5096
+ isVerbose: isVerbose,
5097
+ })];
5098
+ case 1:
5099
+ cacheFilehandler = _e.sent();
5100
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5101
+ case 2:
5102
+ if (!!(_e.sent())) return [3 /*break*/, 5];
5103
+ command_1 = "\"".concat(externalProgramsPaths.pandocPath, "\" -f ").concat(extension, " -t markdown \"").concat(source.filename, "\" -o \"").concat(cacheFilehandler.filename, "\"");
5104
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook
5105
+ return [4 /*yield*/, $execCommand(command_1)];
5106
+ case 3:
5107
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook
5108
+ _e.sent();
5109
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5110
+ case 4:
5111
+ // Note: [0]
5112
+ if (!(_e.sent())) {
5113
+ throw new UnexpectedError(spaceTrim__default["default"](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 "); }));
5114
+ }
5115
+ _e.label = 5;
5116
+ case 5: return [2 /*return*/, cacheFilehandler];
5117
+ }
5118
+ });
5119
+ });
5120
+ },
5121
+ /**
5122
+ * Scrapes the docx file and returns the knowledge pieces or `null` if it can't scrape it
5123
+ */
5124
+ scrape: function (source, options) {
5125
+ return __awaiter(this, void 0, void 0, function () {
5126
+ var cacheFilehandler, markdownSource, knowledge;
5127
+ return __generator(this, function (_a) {
5128
+ switch (_a.label) {
5129
+ case 0: return [4 /*yield*/, documentScraper.$convert(source, options)];
5130
+ case 1:
5131
+ cacheFilehandler = _a.sent();
5132
+ markdownSource = {
5133
+ source: source.source,
5134
+ filename: cacheFilehandler.filename,
5135
+ url: null,
5136
+ mimeType: 'text/markdown',
5137
+ asText: function () {
5138
+ return __awaiter(this, void 0, void 0, function () {
5139
+ return __generator(this, function (_a) {
5140
+ switch (_a.label) {
5141
+ case 0: return [4 /*yield*/, promises.readFile(cacheFilehandler.filename, 'utf-8')];
5142
+ case 1:
5143
+ // Note: [0] In $convert we check that the file exists
5144
+ return [2 /*return*/, _a.sent()];
5145
+ }
5146
+ });
5147
+ });
5148
+ },
5149
+ asJson: function () {
5150
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asJson`');
5151
+ },
5152
+ asBlob: function () {
5153
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asBlob`');
5154
+ },
5155
+ };
5156
+ knowledge = markdownScraper.scrape(markdownSource, options);
5157
+ return [4 /*yield*/, cacheFilehandler.destroy()];
5158
+ case 2:
5159
+ _a.sent();
5160
+ return [2 /*return*/, knowledge];
5161
+ }
5162
+ });
5163
+ });
5164
+ },
5165
+ } /* TODO: [🦷] as const */;
5166
+ /**
5167
+ * TODO: [👣] Converted documents can act as cached items - there is no need to run conversion each time
5168
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5169
+ * TODO: [🪂] Do it in parallel 11:11
5170
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5171
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5172
+ */
5173
+
5174
+ /**
5175
+ * Scraper for .docx files
5176
+ *
5177
+ * @see `documentationUrl` for more details
5178
+ * @public exported from `@promptbook/core`
5179
+ */
5180
+ var legacyDocumentScraper = {
5181
+ /**
5182
+ * Mime types that this scraper can handle
5183
+ */
5184
+ mimeTypes: ['application/msword', 'text/rtf'],
5185
+ /**
5186
+ * Link to documentation
5187
+ */
5188
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5189
+ /**
5190
+ * Convert the `.doc` or `.rtf` to `.doc` file and returns intermediate source
5191
+ *
5192
+ * 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
5193
+ */
5194
+ $convert: function (source, options) {
5195
+ return __awaiter(this, void 0, void 0, function () {
5196
+ var _a, externalProgramsPaths, rootDirname, _b, cacheDirname, _c, isCacheCleaned, _d, isVerbose, extension, cacheFilehandler, documentSourceOutdirPathForLibreOffice_1, command_1, files_1, file;
5197
+ return __generator(this, function (_e) {
5198
+ switch (_e.label) {
5199
+ case 0:
5200
+ _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;
5201
+ if (!$isRunningInNode()) {
5202
+ throw new KnowledgeScrapeError('Scraping .doc files is only supported in Node environment');
5203
+ }
5204
+ if (externalProgramsPaths.libreOfficePath === undefined) {
5205
+ throw new MissingToolsError('LibreOffice is required for scraping .doc and .rtf files');
5206
+ }
5207
+ if (source.filename === null) {
5208
+ // TODO: [🧠] Maybe save file as temporary
5209
+ throw new KnowledgeScrapeError('When parsing .doc or .rtf file, it must be real file in the file system');
5210
+ }
5211
+ extension = getFileExtension(source.filename);
5212
+ return [4 /*yield*/, getScraperIntermediateSource(source, {
5213
+ rootDirname: rootDirname,
5214
+ cacheDirname: cacheDirname,
5215
+ isCacheCleaned: isCacheCleaned,
5216
+ extension: 'docx',
5217
+ isVerbose: isVerbose,
5218
+ })];
5219
+ case 1:
5220
+ cacheFilehandler = _e.sent();
5221
+ if (isVerbose) {
5222
+ console.info("documentScraper: Converting .".concat(extension, " -> .docx"));
5223
+ }
5224
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5225
+ case 2:
5226
+ if (!!(_e.sent())) return [3 /*break*/, 8];
5227
+ documentSourceOutdirPathForLibreOffice_1 = path.join(path.dirname(cacheFilehandler.filename), 'libreoffice')
5228
+ .split('\\')
5229
+ .join('/');
5230
+ command_1 = "\"".concat(externalProgramsPaths.libreOfficePath, "\" --headless --convert-to docx \"").concat(source.filename, "\" --outdir \"").concat(documentSourceOutdirPathForLibreOffice_1, "\"");
5231
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook - this should trigger build polution error
5232
+ return [4 /*yield*/, $execCommand(command_1)];
5233
+ case 3:
5234
+ // TODO: !!!!!! [🕊] Make execCommand standard (?node-)util of the promptbook - this should trigger build polution error
5235
+ _e.sent();
5236
+ return [4 /*yield*/, promises.readdir(documentSourceOutdirPathForLibreOffice_1)];
5237
+ case 4:
5238
+ files_1 = _e.sent();
5239
+ if (files_1.length !== 1) {
5240
+ throw new UnexpectedError(spaceTrim__default["default"](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 "); }));
5241
+ }
5242
+ file = files_1[0];
5243
+ return [4 /*yield*/, promises.rename(path.join(documentSourceOutdirPathForLibreOffice_1, file), cacheFilehandler.filename)];
5244
+ case 5:
5245
+ _e.sent();
5246
+ return [4 /*yield*/, promises.rmdir(documentSourceOutdirPathForLibreOffice_1)];
5247
+ case 6:
5248
+ _e.sent();
5249
+ return [4 /*yield*/, $isFileExisting(cacheFilehandler.filename)];
5250
+ case 7:
5251
+ if (!(_e.sent())) {
5252
+ throw new UnexpectedError(spaceTrim__default["default"](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 "); }));
5253
+ }
5254
+ _e.label = 8;
5255
+ case 8: return [2 /*return*/, cacheFilehandler];
5256
+ }
5257
+ });
5258
+ });
5259
+ },
5260
+ /**
5261
+ * Scrapes the `.doc` or `.rtf` file and returns the knowledge pieces or `null` if it can't scrape it
5262
+ */
5263
+ scrape: function (source, options) {
5264
+ return __awaiter(this, void 0, void 0, function () {
5265
+ var cacheFilehandler, markdownSource, knowledge;
5266
+ return __generator(this, function (_a) {
5267
+ switch (_a.label) {
5268
+ case 0: return [4 /*yield*/, legacyDocumentScraper.$convert(source, options)];
5269
+ case 1:
5270
+ cacheFilehandler = _a.sent();
5271
+ markdownSource = {
5272
+ source: source.source,
5273
+ filename: cacheFilehandler.filename,
5274
+ url: null,
5275
+ mimeType: 'text/markdown',
5276
+ asText: function () {
5277
+ throw new UnexpectedError('Did not expect that `documentScraper` would need to get the content `asText`');
5278
+ },
5279
+ asJson: function () {
5280
+ throw new UnexpectedError('Did not expect that `documentScraper` would need to get the content `asJson`');
5281
+ },
5282
+ asBlob: function () {
5283
+ throw new UnexpectedError('Did not expect that `documentScraper` would need to get the content `asBlob`');
5284
+ },
5285
+ };
5286
+ knowledge = documentScraper.scrape(markdownSource, options);
5287
+ return [4 /*yield*/, cacheFilehandler.destroy()];
5288
+ case 2:
5289
+ _a.sent();
5290
+ return [2 /*return*/, knowledge];
5291
+ }
5292
+ });
5293
+ });
5294
+ },
5295
+ } /* TODO: [🦷] as const */;
5296
+ /**
5297
+ * TODO: [👣] Converted documents can act as cached items - there is no need to run conversion each time
5298
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5299
+ * TODO: [🪂] Do it in parallel 11:11
5300
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5301
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5302
+ */
5303
+
5304
+ /**
5305
+ * Scraper for .docx files
5306
+ *
5307
+ * @see `documentationUrl` for more details
5308
+ * @public exported from `@promptbook/core`
5309
+ */
5310
+ var pdfScraper = {
5311
+ /**
5312
+ * Mime types that this scraper can handle
5313
+ */
5314
+ mimeTypes: ['application/pdf'],
5315
+ /**
5316
+ * Link to documentation
5317
+ */
5318
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5319
+ /**
5320
+ * Converts the `.pdf` file to `.md` file and returns intermediate source
5321
+ */
5322
+ $convert: function (source, options) {
5323
+ return __awaiter(this, void 0, void 0, function () {
5324
+ return __generator(this, function (_a) {
5325
+ TODO_USE(source);
5326
+ TODO_USE(options);
5327
+ throw new NotYetImplementedError('PDF conversion not yet implemented');
5328
+ });
5329
+ });
5330
+ },
5331
+ /**
5332
+ * Scrapes the `.pdf` file and returns the knowledge pieces or `null` if it can't scrape it
5333
+ */
5334
+ scrape: function (source, options) {
5335
+ return __awaiter(this, void 0, void 0, function () {
5336
+ return __generator(this, function (_a) {
5337
+ TODO_USE(source);
5338
+ TODO_USE(options);
5339
+ /*
5340
+ const {
5341
+ externalProgramsPaths = {},
5342
+ cacheDirname = SCRAPE_CACHE_DIRNAME,
5343
+ isCacheCleaned = false,
5344
+ isVerbose = IS_VERBOSE,
5345
+ } = options;
5346
+ */
5347
+ throw new NotYetImplementedError('PDF scraping not yet implemented');
5348
+ });
5349
+ });
5350
+ },
5351
+ } /* TODO: [🦷] as const */;
5352
+ /**
5353
+ * TODO: [👣] Converted documents can act as cached items - there is no need to run conversion each time
5354
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5355
+ * TODO: [🪂] Do it in parallel 11:11
5356
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5357
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
5358
+ */
5359
+
5360
+ /**
5361
+ * A converter instance that uses showdown and highlight extensions
5362
+ *
5363
+ * @type {Converter}
5364
+ * @private for markdown and html knowledge scrapers
5365
+ */
5366
+ var markdownConverter = new showdown.Converter({
5367
+ flavor: 'github', // <- TODO: !!!!!! Explicitly specify the flavor of promptbook markdown
5368
+ /*
5369
+ > import showdownHighlight from 'showdown-highlight';
5370
+ > extensions: [
5371
+ > showdownHighlight({
5372
+ > // Whether to add the classes to the <pre> tag, default is false
5373
+ > pre: true,
5374
+ > // Whether to use hljs' auto language detection, default is true
5375
+ > auto_detection: true,
5376
+ > }),
5377
+ > ],
5378
+ */
5379
+ });
5380
+ /**
5381
+ * TODO: !!!!!! Figure out better name not to confuse with `Converter`
5382
+ * TODO: !!!!!! Lazy-make converter
5383
+ */
5384
+
5385
+ /**
5386
+ * Scraper for .docx files
5387
+ *
5388
+ * @see `documentationUrl` for more details
5389
+ * @public exported from `@promptbook/core`
5390
+ */
5391
+ var websiteScraper = {
5392
+ /**
5393
+ * Mime types that this scraper can handle
5394
+ */
5395
+ mimeTypes: ['text/html'],
5396
+ /**
5397
+ * Link to documentation
5398
+ */
5399
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5400
+ /**
5401
+ * Convert the website to `.md` file and returns intermediate source
5402
+ *
5403
+ * 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
5404
+ */
5405
+ $convert: function (source, options) {
5406
+ return __awaiter(this, void 0, void 0, function () {
5407
+ var
5408
+ // TODO: [🧠] Maybe in node use headless browser not just JSDOM
5409
+ // externalProgramsPaths = {},
5410
+ rootDirname, _a, cacheDirname, _b, isCacheCleaned, _c, isVerbose, jsdom$1, _d, reader, article, html, i, cacheFilehandler, markdown;
5411
+ return __generator(this, function (_e) {
5412
+ switch (_e.label) {
5413
+ case 0:
5414
+ 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;
5415
+ // TODO: !!!!!! Does this work in browser? Make it work.
5416
+ if (source.url === null) {
5417
+ throw new KnowledgeScrapeError('Website scraper requires URL');
5418
+ }
5419
+ _d = jsdom.JSDOM.bind;
5420
+ return [4 /*yield*/, source.asText()];
5421
+ case 1:
5422
+ jsdom$1 = new (_d.apply(jsdom.JSDOM, [void 0, _e.sent(), {
5423
+ url: source.url,
5424
+ }]))();
5425
+ reader = new readability.Readability(jsdom$1.window.document);
5426
+ article = reader.parse();
5427
+ console.log(article);
5428
+ return [4 /*yield*/, waitasecond.forTime(10000)];
5429
+ case 2:
5430
+ _e.sent();
5431
+ html = (article === null || article === void 0 ? void 0 : article.content) || (article === null || article === void 0 ? void 0 : article.textContent) || jsdom$1.window.document.body.innerHTML;
5432
+ // Note: Unwrap html such as it is convertable by `markdownConverter`
5433
+ for (i = 0; i < 2; i++) {
5434
+ html = html.replace(/<div\s*(?:id="readability-page-\d+"\s+class="page")?>(.*)<\/div>/is, '$1');
5435
+ }
5436
+ if (html.includes('<div')) {
5437
+ html = (article === null || article === void 0 ? void 0 : article.textContent) || '';
5438
+ }
5439
+ return [4 /*yield*/, getScraperIntermediateSource(source, {
5440
+ rootDirname: rootDirname,
5441
+ cacheDirname: cacheDirname,
5442
+ isCacheCleaned: isCacheCleaned,
5443
+ extension: 'html',
5444
+ isVerbose: isVerbose,
5445
+ })];
5446
+ case 3:
5447
+ cacheFilehandler = _e.sent();
5448
+ return [4 /*yield*/, promises.writeFile(cacheFilehandler.filename, html, 'utf-8')];
5449
+ case 4:
5450
+ _e.sent();
5451
+ markdown = markdownConverter.makeMarkdown(html, jsdom$1.window.document);
5452
+ return [2 /*return*/, __assign(__assign({}, cacheFilehandler), { markdown: markdown })];
5453
+ }
5454
+ });
5455
+ });
5456
+ },
5457
+ /**
5458
+ * Scrapes the website and returns the knowledge pieces or `null` if it can't scrape it
5459
+ */
5460
+ scrape: function (source, options) {
5461
+ return __awaiter(this, void 0, void 0, function () {
5462
+ var cacheFilehandler, markdownSource, knowledge;
5463
+ return __generator(this, function (_a) {
5464
+ switch (_a.label) {
5465
+ case 0: return [4 /*yield*/, websiteScraper.$convert(source, options)];
5466
+ case 1:
5467
+ cacheFilehandler = _a.sent();
5468
+ markdownSource = {
5469
+ source: source.source,
5470
+ filename: cacheFilehandler.filename,
5471
+ url: null,
5472
+ mimeType: 'text/markdown',
5473
+ asText: function () {
5474
+ return cacheFilehandler.markdown;
5475
+ },
5476
+ asJson: function () {
5477
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asJson`');
5478
+ },
5479
+ asBlob: function () {
5480
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asBlob`');
5481
+ },
5482
+ };
5483
+ knowledge = markdownScraper.scrape(markdownSource, options);
5484
+ return [4 /*yield*/, cacheFilehandler.destroy()];
5485
+ case 2:
5486
+ _a.sent();
5487
+ return [2 /*return*/, knowledge];
5488
+ }
5489
+ });
5490
+ });
5491
+ },
5492
+ } /* TODO: [🦷] as const */;
4470
5493
  /**
4471
- * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5494
+ * TODO: !!!!!! Put into separate package
5495
+ * TODO: [👣] Scraped website in .md can act as cache item - there is no need to run conversion each time
5496
+ * TODO: [🦖] Make some system for putting scrapers to separete packages
5497
+ * TODO: [🪂] Do it in parallel 11:11
5498
+ * TODO: [🦷] Ideally use `as const satisfies Converter & Scraper` BUT this combination throws errors
5499
+ * Note: No need to aggregate usage here, it is done by intercepting the llmTools
4472
5500
  */
4473
5501
 
5502
+ // TODO: [🦖] !!!!!! Pass scrapers as dependency,
4474
5503
  /**
4475
- * Creates executor function from pipeline and execution tools.
5504
+ * @@@
4476
5505
  *
4477
- * @returns The executor function
4478
- * @throws {PipelineLogicError} on logical error in the pipeline
4479
5506
  * @public exported from `@promptbook/core`
4480
5507
  */
4481
- function createPipelineExecutor(options) {
4482
- var _this = this;
4483
- var pipeline = options.pipeline, tools = options.tools, _a = options.settings, settings = _a === void 0 ? {} : _a;
4484
- 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;
4485
- validatePipeline(pipeline);
4486
- var pipelineIdentification = (function () {
4487
- // Note: This is a 😐 implementation of [🚞]
4488
- var _ = [];
4489
- if (pipeline.sourceFile !== undefined) {
4490
- _.push("File: ".concat(pipeline.sourceFile));
4491
- }
4492
- if (pipeline.pipelineUrl !== undefined) {
4493
- _.push("Url: ".concat(pipeline.pipelineUrl));
4494
- }
4495
- return _.join('\n');
4496
- })();
4497
- var preparedPipeline;
4498
- if (isPipelinePrepared(pipeline)) {
4499
- preparedPipeline = pipeline;
4500
- }
4501
- else if (isNotPreparedWarningSupressed !== true) {
4502
- console.warn(spaceTrim.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 "); }));
4503
- }
4504
- var runCount = 0;
4505
- var pipelineExecutor = function (inputParameters, onProgress) { return __awaiter(_this, void 0, void 0, function () {
4506
- return __generator(this, function (_a) {
4507
- runCount++;
4508
- return [2 /*return*/, /* not await */ executePipeline({
4509
- pipeline: pipeline,
4510
- preparedPipeline: preparedPipeline,
4511
- setPreparedPipeline: function (newPreparedPipeline) {
4512
- preparedPipeline = newPreparedPipeline;
4513
- },
4514
- inputParameters: inputParameters,
4515
- tools: tools,
4516
- onProgress: onProgress,
4517
- pipelineIdentification: spaceTrim.spaceTrim(function (block) { return "\n ".concat(block(pipelineIdentification), "\n ").concat(runCount === 1 ? '' : "Run #".concat(runCount), "\n "); }),
4518
- settings: {
4519
- maxExecutionAttempts: maxExecutionAttempts,
4520
- maxParallelCount: maxParallelCount,
4521
- csvSettings: csvSettings,
4522
- isVerbose: isVerbose,
4523
- isNotPreparedWarningSupressed: isNotPreparedWarningSupressed,
4524
- },
4525
- })];
4526
- });
4527
- }); };
4528
- return pipelineExecutor;
5508
+ var SCRAPERS = [
5509
+ markdownScraper,
5510
+ documentScraper,
5511
+ legacyDocumentScraper,
5512
+ pdfScraper,
5513
+ websiteScraper,
5514
+ // <- Note: [♓️] This is the order of the scrapers for knowledge, BUT consider some better (more explicit) way to do this
5515
+ ];
5516
+
5517
+ /**
5518
+ * Creates unique name for the source
5519
+ *
5520
+ * @private within the repository
5521
+ */
5522
+ function sourceContentToName(sourceContent) {
5523
+ // TODO: !!!!!! Better name for source than gibberish hash
5524
+ var hash = cryptoJs.SHA256(hexEncoder__default["default"].parse(JSON.stringify(sourceContent)))
5525
+ // <- TODO: [🥬] Encapsulate sha256 to some private utility function
5526
+ .toString( /* hex */)
5527
+ .substring(0, 20);
5528
+ // <- TODO: [🥬] Make some system for hashes and ids of promptbook
5529
+ var semanticName = normalizeToKebabCase(sourceContent.substring(0, 20));
5530
+ var pieces = ['source', semanticName, hash].filter(function (piece) { return piece !== ''; });
5531
+ var name = pieces.join('-').split('--').join('-');
5532
+ // <- TODO: Use MAX_FILENAME_LENGTH
5533
+ return name;
4529
5534
  }
4530
5535
  /**
4531
- * TODO: [🐚] Change onProgress to object that represents the running execution, can be subscribed via RxJS to and also awaited
5536
+ * TODO: [🐱‍🐉][🧠] Make some smart crop NOT source-i-m-pavol-a-develop-... BUT source-i-m-pavol-a-developer-...
5537
+ */
5538
+
5539
+ /**
5540
+ * Convert file extension to mime type
5541
+ *
5542
+ * @private within the repository
4532
5543
  */
5544
+ function extensionToMimeType(value) {
5545
+ return mimeTypes.lookup(value) || 'application/octet-stream';
5546
+ }
4533
5547
 
4534
5548
  /**
4535
5549
  * @@@
4536
5550
  *
4537
- * @public exported from `@promptbook/core`
5551
+ * @private for scraper utilities
4538
5552
  */
4539
- function prepareKnowledgeFromMarkdown(knowledgeContent /* <- TODO: [🖖] (?maybe not) Always the file */, options) {
5553
+ function makeKnowledgeSourceHandler(knowledgeSource, options) {
5554
+ var _a;
4540
5555
  return __awaiter(this, void 0, void 0, function () {
4541
- var llmTools, _a, maxParallelCount, _b, isVerbose, collection, prepareKnowledgeFromMarkdownExecutor, _c, prepareTitleExecutor, _d, prepareKeywordsExecutor, _e, result, outputParameters, knowledgePiecesRaw, knowledgeTextPieces, knowledge;
4542
- var _f, _g, _h;
4543
- var _this = this;
4544
- return __generator(this, function (_j) {
4545
- switch (_j.label) {
5556
+ var sourceContent, name, _b, _c, rootDirname, _d, isVerbose, url, response_1, mimeType, filename_1, fileExtension, mimeType_1;
5557
+ return __generator(this, function (_e) {
5558
+ switch (_e.label) {
4546
5559
  case 0:
4547
- llmTools = options.llmTools, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
4548
- TODO_USE(maxParallelCount); // <- [🪂]
4549
- collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
4550
- _c = createPipelineExecutor;
4551
- _f = {};
4552
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md')];
5560
+ sourceContent = knowledgeSource.sourceContent;
5561
+ name = knowledgeSource.name;
5562
+ _b = options || {}, _c = _b.rootDirname, rootDirname = _c === void 0 ? null : _c, _d = _b.isVerbose, isVerbose = _d === void 0 ? IS_VERBOSE : _d;
5563
+ TODO_USE(isVerbose);
5564
+ if (!name) {
5565
+ name = sourceContentToName(sourceContent);
5566
+ }
5567
+ if (!isValidUrl(sourceContent)) return [3 /*break*/, 2];
5568
+ url = sourceContent;
5569
+ return [4 /*yield*/, fetch(url)];
4553
5570
  case 1:
4554
- prepareKnowledgeFromMarkdownExecutor = _c.apply(void 0, [(_f.pipeline = _j.sent(),
4555
- _f.tools = {
4556
- llm: llmTools,
5571
+ response_1 = _e.sent();
5572
+ mimeType = ((_a = response_1.headers.get('content-type')) === null || _a === void 0 ? void 0 : _a.split(';')[0]) || 'text/html';
5573
+ return [2 /*return*/, {
5574
+ source: name,
5575
+ filename: null,
5576
+ url: url,
5577
+ mimeType: mimeType,
5578
+ asBlob: function () {
5579
+ return __awaiter(this, void 0, void 0, function () {
5580
+ var content;
5581
+ return __generator(this, function (_a) {
5582
+ switch (_a.label) {
5583
+ case 0: return [4 /*yield*/, response_1.blob()];
5584
+ case 1:
5585
+ content = _a.sent();
5586
+ return [2 /*return*/, content];
5587
+ }
5588
+ });
5589
+ });
4557
5590
  },
4558
- _f)]);
4559
- _d = createPipelineExecutor;
4560
- _g = {};
4561
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-title.ptbk.md')];
4562
- case 2:
4563
- prepareTitleExecutor = _d.apply(void 0, [(_g.pipeline = _j.sent(),
4564
- _g.tools = {
4565
- llm: llmTools,
5591
+ asJson: function () {
5592
+ return __awaiter(this, void 0, void 0, function () {
5593
+ var content;
5594
+ return __generator(this, function (_a) {
5595
+ switch (_a.label) {
5596
+ case 0: return [4 /*yield*/, response_1.json()];
5597
+ case 1:
5598
+ content = _a.sent();
5599
+ return [2 /*return*/, content];
5600
+ }
5601
+ });
5602
+ });
4566
5603
  },
4567
- _g)]);
4568
- _e = createPipelineExecutor;
4569
- _h = {};
4570
- return [4 /*yield*/, collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-knowledge-keywords.ptbk.md')];
4571
- case 3:
4572
- prepareKeywordsExecutor = _e.apply(void 0, [(_h.pipeline = _j.sent(),
4573
- _h.tools = {
4574
- llm: llmTools,
5604
+ asText: function () {
5605
+ return __awaiter(this, void 0, void 0, function () {
5606
+ var content;
5607
+ return __generator(this, function (_a) {
5608
+ switch (_a.label) {
5609
+ case 0: return [4 /*yield*/, response_1.text()];
5610
+ case 1:
5611
+ content = _a.sent();
5612
+ return [2 /*return*/, content];
5613
+ }
5614
+ });
5615
+ });
4575
5616
  },
4576
- _h)]);
4577
- return [4 /*yield*/, prepareKnowledgeFromMarkdownExecutor({ knowledgeContent: knowledgeContent })];
4578
- case 4:
4579
- result = _j.sent();
4580
- assertsExecutionSuccessful(result);
4581
- outputParameters = result.outputParameters;
4582
- knowledgePiecesRaw = outputParameters.knowledgePieces;
4583
- knowledgeTextPieces = (knowledgePiecesRaw || '').split('\n---\n');
4584
- // <- TODO: [main] !!!!! Smarter split and filter out empty pieces
4585
- if (isVerbose) {
4586
- console.info('knowledgeTextPieces:', knowledgeTextPieces);
5617
+ }];
5618
+ case 2:
5619
+ if (!(isValidFilePath(sourceContent) || /\.[a-z]{1,10}$/i.exec(sourceContent))) return [3 /*break*/, 4];
5620
+ if (!$isRunningInNode()) {
5621
+ throw new EnvironmentMismatchError('Importing knowledge source file works only in Node.js environment');
4587
5622
  }
4588
- return [4 /*yield*/, Promise.all(
4589
- // TODO: [🪂] !! Do not send all at once but in chunks
4590
- knowledgeTextPieces.map(function (knowledgeTextPiece, i) { return __awaiter(_this, void 0, void 0, function () {
4591
- var name, title, knowledgePieceContent, keywords, index, titleResult, _a, titleRaw, keywordsResult, _b, keywordsRaw, embeddingResult, error_1;
4592
- return __generator(this, function (_c) {
4593
- switch (_c.label) {
4594
- case 0:
4595
- name = "piece-".concat(i);
4596
- title = spaceTrim__default["default"](knowledgeTextPiece.substring(0, 100));
4597
- knowledgePieceContent = spaceTrim__default["default"](knowledgeTextPiece);
4598
- keywords = [];
4599
- index = [];
4600
- _c.label = 1;
4601
- case 1:
4602
- _c.trys.push([1, 7, , 8]);
4603
- return [4 /*yield*/, prepareTitleExecutor({ knowledgePieceContent: knowledgePieceContent })];
4604
- case 2:
4605
- titleResult = _c.sent();
4606
- _a = titleResult.outputParameters.title, titleRaw = _a === void 0 ? 'Untitled' : _a;
4607
- title = spaceTrim__default["default"](titleRaw) /* <- TODO: Maybe do in pipeline */;
4608
- name = titleToName(title);
4609
- return [4 /*yield*/, prepareKeywordsExecutor({ knowledgePieceContent: knowledgePieceContent })];
4610
- case 3:
4611
- keywordsResult = _c.sent();
4612
- _b = keywordsResult.outputParameters.keywords, keywordsRaw = _b === void 0 ? '' : _b;
4613
- keywords = (keywordsRaw || '')
4614
- .split(',')
4615
- .map(function (keyword) { return keyword.trim(); })
4616
- .filter(function (keyword) { return keyword !== ''; });
4617
- if (isVerbose) {
4618
- console.info("Keywords for \"".concat(title, "\":"), keywords);
5623
+ if (rootDirname === null) {
5624
+ throw new EnvironmentMismatchError('Can not import file knowledge in non-file pipeline');
5625
+ // <- TODO: [🧠] What is the best error type here`
5626
+ }
5627
+ filename_1 = path.join(rootDirname, sourceContent).split('\\').join('/');
5628
+ fileExtension = getFileExtension(filename_1);
5629
+ mimeType_1 = extensionToMimeType(fileExtension || '');
5630
+ return [4 /*yield*/, $isFileExisting(filename_1)];
5631
+ case 3:
5632
+ if (!(_e.sent())) {
5633
+ throw new NotFoundError(spaceTrim__default["default"](function (block) { return "\n Can not make source handler for file which does not exist:\n\n File:\n ".concat(block(filename_1), "\n "); }));
5634
+ }
5635
+ // TODO: !!!!!! Test security file - file is scoped to the project (maybe do this in `filesystemTools`)
5636
+ return [2 /*return*/, {
5637
+ source: name,
5638
+ filename: filename_1,
5639
+ url: null,
5640
+ mimeType: mimeType_1,
5641
+ asBlob: function () {
5642
+ return __awaiter(this, void 0, void 0, function () {
5643
+ var content;
5644
+ return __generator(this, function (_a) {
5645
+ switch (_a.label) {
5646
+ case 0: return [4 /*yield*/, promises.readFile(filename_1)];
5647
+ case 1:
5648
+ content = _a.sent();
5649
+ // <- Note: Its OK to use sync in tooling for tests
5650
+ return [2 /*return*/, new Blob([
5651
+ content,
5652
+ // <- TODO: !!!!!! Maybe not working
5653
+ ], { type: mimeType_1 })];
4619
5654
  }
4620
- if (!!llmTools.callEmbeddingModel) return [3 /*break*/, 4];
4621
- // TODO: [🟥] Detect browser / node and make it colorfull
4622
- console.error('No callEmbeddingModel function provided');
4623
- return [3 /*break*/, 6];
4624
- case 4: return [4 /*yield*/, llmTools.callEmbeddingModel({
4625
- title: "Embedding for ".concat(title) /* <- Note: No impact on embedding result itself, just for logging */,
4626
- parameters: {},
4627
- content: knowledgePieceContent,
4628
- modelRequirements: {
4629
- modelVariant: 'EMBEDDING',
4630
- },
4631
- })];
4632
- case 5:
4633
- embeddingResult = _c.sent();
4634
- index.push({
4635
- modelName: embeddingResult.modelName,
4636
- position: embeddingResult.content,
4637
- });
4638
- _c.label = 6;
4639
- case 6: return [3 /*break*/, 8];
4640
- case 7:
4641
- error_1 = _c.sent();
4642
- // Note: Here is expected error:
4643
- // > PipelineExecutionError: You have not provided any `LlmExecutionTools` that support model variant "EMBEDDING
4644
- if (!(error_1 instanceof PipelineExecutionError)) {
4645
- throw error_1;
5655
+ });
5656
+ });
5657
+ },
5658
+ asJson: function () {
5659
+ return __awaiter(this, void 0, void 0, function () {
5660
+ var _a, _b;
5661
+ return __generator(this, function (_c) {
5662
+ switch (_c.label) {
5663
+ case 0:
5664
+ _b = (_a = JSON).parse;
5665
+ return [4 /*yield*/, promises.readFile(filename_1, 'utf-8')];
5666
+ case 1: return [2 /*return*/, _b.apply(_a, [_c.sent()])];
4646
5667
  }
4647
- // TODO: [🟥] Detect browser / node and make it colorfull
4648
- console.error(error_1, "<- Note: This error is not critical to prepare the pipeline, just knowledge pieces won't have embeddings");
4649
- return [3 /*break*/, 8];
4650
- case 8: return [2 /*return*/, {
4651
- name: name,
4652
- title: title,
4653
- content: knowledgePieceContent,
4654
- keywords: keywords,
4655
- index: index,
4656
- // <- TODO: [☀] sources,
4657
- }];
4658
- }
4659
- });
4660
- }); }))];
4661
- case 5:
4662
- knowledge = _j.sent();
4663
- return [2 /*return*/, knowledge];
5668
+ });
5669
+ });
5670
+ },
5671
+ asText: function () {
5672
+ return __awaiter(this, void 0, void 0, function () {
5673
+ return __generator(this, function (_a) {
5674
+ switch (_a.label) {
5675
+ case 0: return [4 /*yield*/, promises.readFile(filename_1, 'utf-8')];
5676
+ case 1: return [2 /*return*/, _a.sent()];
5677
+ }
5678
+ });
5679
+ });
5680
+ },
5681
+ }];
5682
+ case 4: return [2 /*return*/, {
5683
+ source: name,
5684
+ filename: null,
5685
+ url: null,
5686
+ mimeType: 'text/markdown',
5687
+ asText: function () {
5688
+ return knowledgeSource.sourceContent;
5689
+ },
5690
+ asJson: function () {
5691
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asJson`');
5692
+ },
5693
+ asBlob: function () {
5694
+ throw new UnexpectedError('Did not expect that `markdownScraper` would need to get the content `asBlob`');
5695
+ },
5696
+ }];
4664
5697
  }
4665
5698
  });
4666
5699
  });
4667
5700
  }
4668
- /**
4669
- * TODO: [🐝][🔼][main] !!! Export via `@promptbook/markdown`
4670
- * TODO: [🪂] Do it in parallel 11:11
4671
- * Note: No need to aggregate usage here, it is done by intercepting the llmTools
4672
- */
4673
5701
 
4674
5702
  /**
4675
5703
  * Prepares the knowle
@@ -4679,21 +5707,64 @@
4679
5707
  */
4680
5708
  function prepareKnowledgePieces(knowledgeSources, options) {
4681
5709
  return __awaiter(this, void 0, void 0, function () {
4682
- var _a, maxParallelCount, knowledgePrepared;
5710
+ var _a, maxParallelCount, rootDirname, _b, isVerbose, knowledgePreparedUnflatten, knowledgePrepared;
4683
5711
  var _this = this;
4684
- return __generator(this, function (_b) {
4685
- switch (_b.label) {
5712
+ return __generator(this, function (_c) {
5713
+ switch (_c.label) {
4686
5714
  case 0:
4687
- _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a;
4688
- knowledgePrepared = [];
4689
- return [4 /*yield*/, forEachAsync(knowledgeSources, { maxParallelCount: maxParallelCount }, function (knowledgeSource) { return __awaiter(_this, void 0, void 0, function () {
4690
- var partialPieces, pieces;
4691
- return __generator(this, function (_a) {
4692
- switch (_a.label) {
4693
- case 0: return [4 /*yield*/, prepareKnowledgeFromMarkdown(knowledgeSource.sourceContent, // <- TODO: [🐝][main] !!! Unhardcode markdown, detect which type it is - BE AWARE of big package size
4694
- options)];
5715
+ _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, rootDirname = options.rootDirname, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
5716
+ knowledgePreparedUnflatten = new Array(knowledgeSources.length);
5717
+ return [4 /*yield*/, forEachAsync(knowledgeSources, { maxParallelCount: maxParallelCount }, function (knowledgeSource, index) { return __awaiter(_this, void 0, void 0, function () {
5718
+ var partialPieces, sourceHandler, SCRAPERS_1, SCRAPERS_1_1, scraper, partialPiecesUnchecked, e_1_1, pieces;
5719
+ var e_1, _a;
5720
+ return __generator(this, function (_b) {
5721
+ switch (_b.label) {
5722
+ case 0:
5723
+ partialPieces = null;
5724
+ return [4 /*yield*/, makeKnowledgeSourceHandler(knowledgeSource, { rootDirname: rootDirname, isVerbose: isVerbose })];
4695
5725
  case 1:
4696
- partialPieces = _a.sent();
5726
+ sourceHandler = _b.sent();
5727
+ _b.label = 2;
5728
+ case 2:
5729
+ _b.trys.push([2, 7, 8, 9]);
5730
+ SCRAPERS_1 = __values(SCRAPERS), SCRAPERS_1_1 = SCRAPERS_1.next();
5731
+ _b.label = 3;
5732
+ case 3:
5733
+ if (!!SCRAPERS_1_1.done) return [3 /*break*/, 6];
5734
+ scraper = SCRAPERS_1_1.value;
5735
+ if (!scraper.mimeTypes.includes(sourceHandler.mimeType)
5736
+ // <- TODO: [🦔] Implement mime-type wildcards
5737
+ ) {
5738
+ return [3 /*break*/, 5];
5739
+ }
5740
+ return [4 /*yield*/, scraper.scrape(sourceHandler, options)];
5741
+ case 4:
5742
+ partialPiecesUnchecked = _b.sent();
5743
+ if (partialPiecesUnchecked !== null) {
5744
+ partialPieces = partialPiecesUnchecked;
5745
+ return [3 /*break*/, 6];
5746
+ }
5747
+ _b.label = 5;
5748
+ case 5:
5749
+ SCRAPERS_1_1 = SCRAPERS_1.next();
5750
+ return [3 /*break*/, 3];
5751
+ case 6: return [3 /*break*/, 9];
5752
+ case 7:
5753
+ e_1_1 = _b.sent();
5754
+ e_1 = { error: e_1_1 };
5755
+ return [3 /*break*/, 9];
5756
+ case 8:
5757
+ try {
5758
+ if (SCRAPERS_1_1 && !SCRAPERS_1_1.done && (_a = SCRAPERS_1.return)) _a.call(SCRAPERS_1);
5759
+ }
5760
+ finally { if (e_1) throw e_1.error; }
5761
+ return [7 /*endfinally*/];
5762
+ case 9:
5763
+ if (partialPieces === null) {
5764
+ throw new KnowledgeScrapeError(spaceTrim__default["default"](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; })
5765
+ .map(function (mimeType) { return "- ".concat(mimeType); })
5766
+ .join('\n')), "\n\n\n "); }));
5767
+ }
4697
5768
  pieces = partialPieces.map(function (partialPiece) { return (__assign(__assign({}, partialPiece), { sources: [
4698
5769
  {
4699
5770
  name: knowledgeSource.name,
@@ -4701,13 +5772,14 @@
4701
5772
  // <- TODO: [❎]
4702
5773
  },
4703
5774
  ] })); });
4704
- knowledgePrepared.push.apply(knowledgePrepared, __spreadArray([], __read(pieces), false));
5775
+ knowledgePreparedUnflatten[index] = pieces;
4705
5776
  return [2 /*return*/];
4706
5777
  }
4707
5778
  });
4708
5779
  }); })];
4709
5780
  case 1:
4710
- _b.sent();
5781
+ _c.sent();
5782
+ knowledgePrepared = knowledgePreparedUnflatten.flat();
4711
5783
  return [2 /*return*/, knowledgePrepared];
4712
5784
  }
4713
5785
  });
@@ -4724,7 +5796,7 @@
4724
5796
  >
4725
5797
  > export async function prepareKnowledgePieces(
4726
5798
  > knowledge: PrepareKnowledgeKnowledge,
4727
- > options: PrepareOptions,
5799
+ > options: PrepareAndScrapeOptions,
4728
5800
  > ):
4729
5801
  */
4730
5802
  /**
@@ -4837,6 +5909,9 @@
4837
5909
  switch (_d.label) {
4838
5910
  case 0:
4839
5911
  llmTools = options.llmTools, _a = options.isVerbose, isVerbose = _a === void 0 ? IS_VERBOSE : _a;
5912
+ if (llmTools === undefined) {
5913
+ throw new MissingToolsError('LLM tools are required for preparing persona');
5914
+ }
4840
5915
  collection = createCollectionFromJson.apply(void 0, __spreadArray([], __read(PipelineCollection), false));
4841
5916
  _b = createPipelineExecutor;
4842
5917
  _c = {};
@@ -4980,7 +6055,7 @@
4980
6055
  */
4981
6056
  function preparePipeline(pipeline, options) {
4982
6057
  return __awaiter(this, void 0, void 0, function () {
4983
- var llmTools, _a, maxParallelCount, _b, isVerbose, parameters, templates,
6058
+ var llmTools, rootDirname, _a, maxParallelCount, _b, isVerbose, parameters, templates,
4984
6059
  /*
4985
6060
  <- TODO: [🧠][🪑] `promptbookVersion` */
4986
6061
  knowledgeSources /*
@@ -4993,8 +6068,11 @@
4993
6068
  if (isPipelinePrepared(pipeline)) {
4994
6069
  return [2 /*return*/, pipeline];
4995
6070
  }
4996
- llmTools = options.llmTools, _a = options.maxParallelCount, maxParallelCount = _a === void 0 ? MAX_PARALLEL_COUNT : _a, _b = options.isVerbose, isVerbose = _b === void 0 ? IS_VERBOSE : _b;
6071
+ 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;
4997
6072
  parameters = pipeline.parameters, templates = pipeline.templates, knowledgeSources = pipeline.knowledgeSources, personas = pipeline.personas;
6073
+ if (llmTools === undefined) {
6074
+ throw new MissingToolsError('LLM tools are required for preparing the pipeline');
6075
+ }
4998
6076
  llmToolsWithUsage = countTotalUsage(llmTools);
4999
6077
  currentPreparation = {
5000
6078
  id: 1,
@@ -5016,6 +6094,7 @@
5016
6094
  switch (_a.label) {
5017
6095
  case 0: return [4 /*yield*/, preparePersona(persona.description, {
5018
6096
  llmTools: llmToolsWithUsage,
6097
+ rootDirname: rootDirname,
5019
6098
  maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
5020
6099
  isVerbose: isVerbose,
5021
6100
  })];
@@ -5030,11 +6109,7 @@
5030
6109
  case 1:
5031
6110
  _c.sent();
5032
6111
  knowledgeSourcesPrepared = knowledgeSources.map(function (source) { return (__assign(__assign({}, source), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
5033
- return [4 /*yield*/, prepareKnowledgePieces(knowledgeSources /* <- TODO: [🧊] {knowledgeSources, knowledgePieces} */, {
5034
- llmTools: llmToolsWithUsage,
5035
- maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
5036
- isVerbose: isVerbose,
5037
- })];
6112
+ return [4 /*yield*/, prepareKnowledgePieces(knowledgeSources /* <- TODO: [🧊] {knowledgeSources, knowledgePieces} */, __assign(__assign({}, options), { llmTools: llmToolsWithUsage, rootDirname: rootDirname, maxParallelCount: maxParallelCount /* <- TODO: [🪂] */, isVerbose: isVerbose }))];
5038
6113
  case 2:
5039
6114
  partialknowledgePiecesPrepared = _c.sent();
5040
6115
  knowledgePiecesPrepared = partialknowledgePiecesPrepared.map(function (piece) { return (__assign(__assign({}, piece), { preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id] })); });
@@ -5044,6 +6119,7 @@
5044
6119
  knowledgePiecesCount: knowledgePiecesPrepared.length,
5045
6120
  }, {
5046
6121
  llmTools: llmToolsWithUsage,
6122
+ rootDirname: rootDirname,
5047
6123
  maxParallelCount: maxParallelCount /* <- TODO: [🪂] */,
5048
6124
  isVerbose: isVerbose,
5049
6125
  })];
@@ -5066,36 +6142,10 @@
5066
6142
  * @see https://docs.anthropic.com/en/docs/test-and-evaluate/strengthen-guardrails/increase-consistency#specify-the-desired-output-format
5067
6143
  */
5068
6144
 
5069
- /**
5070
- * Tests if given string is valid URL.
5071
- *
5072
- * Note: This does not check if the file exists only if the path is valid
5073
- * @public exported from `@promptbook/utils`
5074
- */
5075
- function isValidFilePath(filePath) {
5076
- if (typeof filePath !== 'string') {
5077
- return false;
5078
- }
5079
- var filePathSlashes = filePath.split('\\').join('/');
5080
- // Absolute Unix path: /hello.txt
5081
- if (/^(\/)/i.test(filePathSlashes)) {
5082
- return true;
5083
- }
5084
- // Absolute Windows path: /hello.txt
5085
- if (/^([A-Z]{1,2}:\/?)\//i.test(filePathSlashes)) {
5086
- return true;
5087
- }
5088
- // Relative path: ./hello.txt
5089
- if (/^(\.\.?\/)+/i.test(filePathSlashes)) {
5090
- return true;
5091
- }
5092
- return false;
5093
- }
5094
-
5095
6145
  /**
5096
6146
  * Parses the knowledge command
5097
6147
  *
5098
- * @see ./KNOWLEDGE-README.md for more details
6148
+ * @see `documentationUrl` for more details
5099
6149
  * @private within the commands folder
5100
6150
  */
5101
6151
  var knowledgeCommandParser = {
@@ -5113,7 +6163,7 @@
5113
6163
  */
5114
6164
  description: "Tells promptbook which external knowledge to use",
5115
6165
  /**
5116
- * Link to discussion
6166
+ * Link to documentation
5117
6167
  */
5118
6168
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/41',
5119
6169
  /**
@@ -5157,11 +6207,8 @@
5157
6207
  */
5158
6208
  $applyToPipelineJson: function (command, $pipelineJson) {
5159
6209
  var sourceContent = command.sourceContent;
5160
- var name = 'source-' + sha256__default["default"](hexEncoder__default["default"].parse(JSON.stringify(sourceContent))).toString( /* hex */);
5161
- // <- TODO: [🥬] Encapsulate sha256 to some private utility function
5162
- // <- TODO: This should be replaced with a better name later in preparation (done with some propper LLM summarization)
5163
6210
  $pipelineJson.knowledgeSources.push({
5164
- name: name,
6211
+ name: sourceContentToName(sourceContent),
5165
6212
  sourceContent: sourceContent,
5166
6213
  });
5167
6214
  },
@@ -5209,7 +6256,7 @@
5209
6256
  /**
5210
6257
  * Parses the template command
5211
6258
  *
5212
- * @see ./TEMPLATE-README.md for more details
6259
+ * @see `documentationUrl` for more details
5213
6260
  * @private within the commands folder
5214
6261
  */
5215
6262
  var templateCommandParser = {
@@ -5245,7 +6292,7 @@
5245
6292
  */
5246
6293
  description: "What should the code template template do",
5247
6294
  /**
5248
- * Link to discussion
6295
+ * Link to documentation
5249
6296
  */
5250
6297
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/64',
5251
6298
  /**
@@ -5470,7 +6517,7 @@
5470
6517
  /**
5471
6518
  * Parses the expect command
5472
6519
  *
5473
- * @see ./EXPECT-README.md for more details
6520
+ * @see `documentationUrl` for more details
5474
6521
  * @private within the commands folder
5475
6522
  */
5476
6523
  var expectCommandParser = {
@@ -5488,7 +6535,7 @@
5488
6535
  */
5489
6536
  description: spaceTrim__default["default"]("\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 "),
5490
6537
  /**
5491
- * Link to discussion
6538
+ * Link to documentation
5492
6539
  */
5493
6540
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/30',
5494
6541
  /**
@@ -5648,10 +6695,6 @@
5648
6695
  charType = 'NUMBER';
5649
6696
  normalizedChar = char;
5650
6697
  }
5651
- else if (/^\/$/.test(char)) {
5652
- charType = 'SLASH';
5653
- normalizedChar = char;
5654
- }
5655
6698
  else {
5656
6699
  charType = 'OTHER';
5657
6700
  normalizedChar = '_';
@@ -5858,7 +6901,7 @@
5858
6901
  *
5859
6902
  * Note: @@@ This command is used as foreach for new commands - it should NOT be used in any `.ptbk.md` file
5860
6903
  *
5861
- * @see ./FOREACH-README.md for more details <- TODO: @@@ Write theese README files OR remove this link + add annotation here (to all commands)
6904
+ * @see `documentationUrl` for more details
5862
6905
  * @private within the commands folder
5863
6906
  */
5864
6907
  var foreachCommandParser = {
@@ -5880,7 +6923,7 @@
5880
6923
  */
5881
6924
  description: "@@",
5882
6925
  /**
5883
- * Link to discussion
6926
+ * Link to documentation
5884
6927
  */
5885
6928
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/148',
5886
6929
  /**
@@ -6015,7 +7058,7 @@
6015
7058
  /**
6016
7059
  * Parses the format command
6017
7060
  *
6018
- * @see ./FORMAT-README.md for more details
7061
+ * @see `documentationUrl` for more details
6019
7062
  * @private within the commands folder
6020
7063
  */
6021
7064
  var formatCommandParser = {
@@ -6033,7 +7076,7 @@
6033
7076
  */
6034
7077
  description: spaceTrim__default["default"]("\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 "),
6035
7078
  /**
6036
- * Link to discussion
7079
+ * Link to documentation
6037
7080
  */
6038
7081
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/30',
6039
7082
  /**
@@ -6089,7 +7132,7 @@
6089
7132
  /**
6090
7133
  * Parses the joker command
6091
7134
  *
6092
- * @see ./JOKER-README.md for more details
7135
+ * @see `documentationUrl` for more details
6093
7136
  * @private within the commands folder
6094
7137
  */
6095
7138
  var jokerCommandParser = {
@@ -6107,7 +7150,7 @@
6107
7150
  */
6108
7151
  description: "Joker parameter is used instead of executing the template result if jokers value meets the expectations requirements",
6109
7152
  /**
6110
- * Link to discussion
7153
+ * Link to documentation
6111
7154
  */
6112
7155
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/66',
6113
7156
  /**
@@ -6168,7 +7211,7 @@
6168
7211
  /**
6169
7212
  * Parses the model command
6170
7213
  *
6171
- * @see ./MODEL-README.md for more details
7214
+ * @see `documentationUrl` for more details
6172
7215
  * @private within the commands folder
6173
7216
  */
6174
7217
  var modelCommandParser = {
@@ -6186,7 +7229,7 @@
6186
7229
  */
6187
7230
  description: "Tells which `modelRequirements` (for example which model) to use for the prompt template execution",
6188
7231
  /**
6189
- * Link to discussion
7232
+ * Link to documentation
6190
7233
  */
6191
7234
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/67',
6192
7235
  /**
@@ -6268,7 +7311,11 @@
6268
7311
  // TODO: [🚜] DRY
6269
7312
  if ($templateJson.modelRequirements[command.key] !== undefined) {
6270
7313
  if ($templateJson.modelRequirements[command.key] === command.value) {
6271
- console.warn("Multiple commands `MODEL ".concat(command.key, " ").concat(command.value, "` in the template \"").concat($templateJson.title || $templateJson.name, "\""));
7314
+ console.warn("Multiple commands `MODEL ".concat({
7315
+ modelName: 'NAME',
7316
+ modelVariant: 'VARIANT',
7317
+ maxTokens: '???',
7318
+ }[command.key], " ").concat(command.value, "` in the template \"").concat($templateJson.title || $templateJson.name, "\""));
6272
7319
  }
6273
7320
  else {
6274
7321
  throw new ParseError(spaceTrim__default["default"]("\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 ")));
@@ -6311,7 +7358,7 @@
6311
7358
  /**
6312
7359
  * Parses the parameter command
6313
7360
  *
6314
- * @see ./PARAMETER-README.md for more details
7361
+ * @see `documentationUrl` for more details
6315
7362
  * @private within the commands folder
6316
7363
  */
6317
7364
  var parameterCommandParser = {
@@ -6336,7 +7383,7 @@
6336
7383
  */
6337
7384
  description: "Describes one parameter of the template",
6338
7385
  /**
6339
- * Link to discussion
7386
+ * Link to documentation
6340
7387
  */
6341
7388
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/68',
6342
7389
  /**
@@ -6421,7 +7468,7 @@
6421
7468
  /**
6422
7469
  * Parses the persona command
6423
7470
  *
6424
- * @see ./PERSONA-README.md for more details
7471
+ * @see `documentationUrl` for more details
6425
7472
  * @private within the commands folder
6426
7473
  */
6427
7474
  var personaCommandParser = {
@@ -6443,7 +7490,7 @@
6443
7490
  */
6444
7491
  description: "Persona command is used to specify who the system is, it will be transformed into system message, top_t,...",
6445
7492
  /**
6446
- * Link to discussion
7493
+ * Link to documentation
6447
7494
  */
6448
7495
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/22',
6449
7496
  /**
@@ -6559,7 +7606,7 @@
6559
7606
  /**
6560
7607
  * Parses the postprocess command
6561
7608
  *
6562
- * @see ./POSTPROCESS-README.md for more details
7609
+ * @see `documentationUrl` for more details
6563
7610
  * @private within the commands folder
6564
7611
  */
6565
7612
  var postprocessCommandParser = {
@@ -6578,7 +7625,7 @@
6578
7625
  */
6579
7626
  description: "Defines the postprocess function to be used on the result from LLM and before the result is validated",
6580
7627
  /**
6581
- * Link to discussion
7628
+ * Link to documentation
6582
7629
  */
6583
7630
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/31',
6584
7631
  /**
@@ -6639,7 +7686,7 @@
6639
7686
  /**
6640
7687
  * Parses the PROMPTBOOK_VERSION command
6641
7688
  *
6642
- * @see ./PROMPTBOOK_VERSION-README.md for more details
7689
+ * @see `documentationUrl` for more details
6643
7690
  * @private within the commands folder
6644
7691
  */
6645
7692
  var promptbookVersionCommandParser = {
@@ -6658,7 +7705,7 @@
6658
7705
  */
6659
7706
  description: "Which version of the promptbook is the .ptbk.md using",
6660
7707
  /**
6661
- * Link to discussion
7708
+ * Link to documentation
6662
7709
  */
6663
7710
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/69',
6664
7711
  /**
@@ -6717,7 +7764,7 @@
6717
7764
  /**
6718
7765
  * Parses the url command
6719
7766
  *
6720
- * @see ./URL-README.md for more details
7767
+ * @see `documentationUrl` for more details
6721
7768
  * @private within the commands folder
6722
7769
  */
6723
7770
  var urlCommandParser = {
@@ -6740,7 +7787,7 @@
6740
7787
  */
6741
7788
  description: "Declares unique URL for the pipeline",
6742
7789
  /**
6743
- * Link to discussion
7790
+ * Link to documentation
6744
7791
  */
6745
7792
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/70',
6746
7793
  /**
@@ -6820,7 +7867,7 @@
6820
7867
  /**
6821
7868
  * Parses the action command
6822
7869
  *
6823
- * @see ./ACTION-README.md for more details
7870
+ * @see `documentationUrl` for more details
6824
7871
  * @private within the commands folder
6825
7872
  */
6826
7873
  var actionCommandParser = {
@@ -6838,7 +7885,7 @@
6838
7885
  */
6839
7886
  description: "Actions influences from the pipeline or template into external world. Like turning on a light, sending an email, etc.",
6840
7887
  /**
6841
- * Link to discussion
7888
+ * Link to documentation
6842
7889
  */
6843
7890
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/72',
6844
7891
  /**
@@ -6890,7 +7937,7 @@
6890
7937
  /**
6891
7938
  * Parses the instrument command
6892
7939
  *
6893
- * @see ./INSTRUMENT-README.md for more details
7940
+ * @see `documentationUrl` for more details
6894
7941
  * @private within the commands folder
6895
7942
  */
6896
7943
  var instrumentCommandParser = {
@@ -6908,7 +7955,7 @@
6908
7955
  */
6909
7956
  description: "Instrument command is used to specify the instrument to be used in the pipeline or template like search, calculate, etc.",
6910
7957
  /**
6911
- * Link to discussion
7958
+ * Link to documentation
6912
7959
  */
6913
7960
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/71',
6914
7961
  /**
@@ -6963,7 +8010,7 @@
6963
8010
  *
6964
8011
  * Note: @@@ This command is used as boilerplate for new commands - it should NOT be used in any `.ptbk.md` file
6965
8012
  *
6966
- * @see ./BOILERPLATE-README.md for more details <- TODO: @@@ Write theese README files OR remove this link + add annotation here (to all commands)
8013
+ * @see `documentationUrl` for more details
6967
8014
  * @private within the commands folder
6968
8015
  */
6969
8016
  var boilerplateCommandParser = {
@@ -6985,7 +8032,7 @@
6985
8032
  */
6986
8033
  description: "@@",
6987
8034
  /**
6988
- * Link to discussion
8035
+ * Link to documentation
6989
8036
  */
6990
8037
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
6991
8038
  /**
@@ -7835,16 +8882,17 @@
7835
8882
  * @public exported from `@promptbook/core`
7836
8883
  */
7837
8884
  function pipelineStringToJson(pipelineString, options) {
7838
- if (options === void 0) { options = { llmTools: null }; }
7839
8885
  return __awaiter(this, void 0, void 0, function () {
7840
8886
  var llmTools, pipelineJson;
7841
8887
  return __generator(this, function (_a) {
7842
8888
  switch (_a.label) {
7843
8889
  case 0:
7844
- llmTools = options.llmTools;
8890
+ llmTools = (options || {}).llmTools;
7845
8891
  pipelineJson = pipelineStringToJsonSync(pipelineString);
7846
- if (!(llmTools !== null)) return [3 /*break*/, 2];
7847
- return [4 /*yield*/, preparePipeline(pipelineJson, { llmTools: llmTools })];
8892
+ if (!(llmTools !== undefined)) return [3 /*break*/, 2];
8893
+ return [4 /*yield*/, preparePipeline(pipelineJson, options || {
8894
+ rootDirname: null,
8895
+ })];
7848
8896
  case 1:
7849
8897
  pipelineJson = _a.sent();
7850
8898
  _a.label = 2;
@@ -7861,51 +8909,6 @@
7861
8909
  * TODO: [🧠] Should be in generated JSON file GENERATOR_WARNING
7862
8910
  */
7863
8911
 
7864
- /**
7865
- * Detects if the code is running in a Node.js environment
7866
- *
7867
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
7868
- *
7869
- * @public exported from `@promptbook/utils`
7870
- */
7871
- var $isRunningInNode = new Function("\n try {\n return this === global;\n } catch (e) {\n return false;\n }\n");
7872
-
7873
- /**
7874
- * Checks if the file exists
7875
- *
7876
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the filesystem
7877
- *
7878
- * @private within the repository
7879
- */
7880
- function $isFileExisting(filePath) {
7881
- return __awaiter(this, void 0, void 0, function () {
7882
- var isReadAccessAllowed, isFile;
7883
- return __generator(this, function (_a) {
7884
- switch (_a.label) {
7885
- case 0: return [4 /*yield*/, promises.access(filePath, promises.constants.R_OK)
7886
- .then(function () { return true; })
7887
- .catch(function () { return false; })];
7888
- case 1:
7889
- isReadAccessAllowed = _a.sent();
7890
- if (!isReadAccessAllowed) {
7891
- return [2 /*return*/, false];
7892
- }
7893
- return [4 /*yield*/, promises.stat(filePath)
7894
- .then(function (fileStat) { return fileStat.isFile(); })
7895
- .catch(function () { return false; })];
7896
- case 2:
7897
- isFile = _a.sent();
7898
- return [2 /*return*/, isFile];
7899
- }
7900
- });
7901
- });
7902
- }
7903
- /**
7904
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
7905
- * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
7906
- * TODO: [🖇] What about symlinks?
7907
- */
7908
-
7909
8912
  /**
7910
8913
  * Checks if the directory exists
7911
8914
  *
@@ -7918,9 +8921,13 @@
7918
8921
  var isReadAccessAllowed, isDirectory;
7919
8922
  return __generator(this, function (_a) {
7920
8923
  switch (_a.label) {
7921
- case 0: return [4 /*yield*/, promises.access(directoryPath, promises.constants.R_OK)
7922
- .then(function () { return true; })
7923
- .catch(function () { return false; })];
8924
+ case 0:
8925
+ if (!$isRunningInNode()) {
8926
+ throw new EnvironmentMismatchError('Function `$isDirectoryExisting` works only in Node environment.js');
8927
+ }
8928
+ return [4 /*yield*/, promises.access(directoryPath, promises.constants.R_OK)
8929
+ .then(function () { return true; })
8930
+ .catch(function () { return false; })];
7924
8931
  case 1:
7925
8932
  isReadAccessAllowed = _a.sent();
7926
8933
  if (!isReadAccessAllowed) {
@@ -7937,7 +8944,7 @@
7937
8944
  });
7938
8945
  }
7939
8946
  /**
7940
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
8947
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
7941
8948
  * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
7942
8949
  * TODO: [🧠][📂] "directory" vs "folder"
7943
8950
  * TODO: [🖇] What about symlinks?
@@ -7953,26 +8960,32 @@
7953
8960
  * @returns List of all files in the directory
7954
8961
  * @private internal function of `createCollectionFromDirectory`
7955
8962
  */
7956
- function $listAllFiles(path, isRecursive) {
8963
+ function $listAllFiles(path$1, isRecursive) {
7957
8964
  return __awaiter(this, void 0, void 0, function () {
7958
8965
  var dirents, fileNames, _a, _b, dirent, subPath, _c, _d, _e, _f, e_1_1;
7959
8966
  var e_1, _g;
7960
8967
  return __generator(this, function (_h) {
7961
8968
  switch (_h.label) {
7962
- case 0: return [4 /*yield*/, $isDirectoryExisting(path)];
8969
+ case 0:
8970
+ if (!$isRunningInNode()) {
8971
+ throw new EnvironmentMismatchError('Function `$listAllFiles` works only in Node environment.js');
8972
+ }
8973
+ return [4 /*yield*/, $isDirectoryExisting(path$1)];
7963
8974
  case 1:
7964
8975
  if (!(_h.sent())) {
7965
- throw new Error("Directory \"".concat(path, "\" does not exist or is not readable"));
8976
+ throw new Error("Directory \"".concat(path$1, "\" does not exist or is not readable"));
7966
8977
  // <- TODO: Use some custom error class
7967
8978
  }
7968
- return [4 /*yield*/, promises.readdir(path, {
8979
+ return [4 /*yield*/, promises.readdir(path$1, {
7969
8980
  withFileTypes: true /* Note: This is not working: recursive: isRecursive */,
7970
8981
  })];
7971
8982
  case 2:
7972
8983
  dirents = _h.sent();
7973
- fileNames = dirents.filter(function (dirent) { return dirent.isFile(); }).map(function (_a) {
8984
+ fileNames = dirents
8985
+ .filter(function (dirent) { return dirent.isFile(); })
8986
+ .map(function (_a) {
7974
8987
  var name = _a.name;
7975
- return posix.join(path, name);
8988
+ return path.join(path$1, name).split('\\').join('/');
7976
8989
  });
7977
8990
  if (!isRecursive) return [3 /*break*/, 10];
7978
8991
  _h.label = 3;
@@ -7983,13 +8996,13 @@
7983
8996
  case 4:
7984
8997
  if (!!_b.done) return [3 /*break*/, 7];
7985
8998
  dirent = _b.value;
7986
- subPath = posix.join(path, dirent.name);
8999
+ subPath = path.join(path$1, dirent.name);
7987
9000
  _d = (_c = fileNames.push).apply;
7988
9001
  _e = [fileNames];
7989
9002
  _f = [[]];
7990
9003
  return [4 /*yield*/, $listAllFiles(subPath, isRecursive)];
7991
9004
  case 5:
7992
- _d.apply(_c, _e.concat([__spreadArray.apply(void 0, _f.concat([__read.apply(void 0, [(_h.sent())]), false]))]));
9005
+ _d.apply(_c, _e.concat([__spreadArray.apply(void 0, _f.concat([__read.apply(void 0, [(_h.sent()).map(function (filename) { return filename; })]), false]))]));
7993
9006
  _h.label = 6;
7994
9007
  case 6:
7995
9008
  _b = _a.next();
@@ -8011,7 +9024,8 @@
8011
9024
  });
8012
9025
  }
8013
9026
  /**
8014
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9027
+ * TODO: [😶] Unite floder listing
9028
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8015
9029
  * TODO: [🖇] What about symlinks?
8016
9030
  */
8017
9031
 
@@ -8114,7 +9128,7 @@
8114
9128
  */
8115
9129
  function createCollectionFromDirectory(path$1, options) {
8116
9130
  return __awaiter(this, void 0, void 0, function () {
8117
- var makedLibraryFilePath, _a, _b, isRecursive, _c, isVerbose, _d, isLazyLoaded, _e, isCrashedOnError, collection;
9131
+ var makedLibraryFilePath, _a, llmTools, _b, isRecursive, _c, isVerbose, _d, isLazyLoaded, _e, isCrashedOnError, collection;
8118
9132
  var _this = this;
8119
9133
  return __generator(this, function (_f) {
8120
9134
  switch (_f.label) {
@@ -8133,7 +9147,7 @@
8133
9147
  // TODO: !! Implement;
8134
9148
  // TODO: [🌗]
8135
9149
  }
8136
- _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;
9150
+ _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;
8137
9151
  collection = createCollectionFromPromise(function () { return __awaiter(_this, void 0, void 0, function () {
8138
9152
  var fileNames, collection, _loop_1, fileNames_1, fileNames_1_1, fileName, e_1_1;
8139
9153
  var e_1, _a;
@@ -8159,20 +9173,24 @@
8159
9173
  });
8160
9174
  collection = new Map();
8161
9175
  _loop_1 = function (fileName) {
8162
- var sourceFile, pipeline, pipelineString, _c, _d, existing, error_1, wrappedErrorMessage;
9176
+ var sourceFile, rootDirname, pipeline, pipelineString, _c, _d, existing, error_1, wrappedErrorMessage;
8163
9177
  return __generator(this, function (_e) {
8164
9178
  switch (_e.label) {
8165
9179
  case 0:
8166
9180
  sourceFile = './' + fileName.split('\\').join('/');
9181
+ rootDirname = path.dirname(sourceFile).split('\\').join('/');
8167
9182
  _e.label = 1;
8168
9183
  case 1:
8169
9184
  _e.trys.push([1, 8, , 9]);
8170
9185
  pipeline = null;
8171
9186
  if (!fileName.endsWith('.ptbk.md')) return [3 /*break*/, 4];
8172
- return [4 /*yield*/, promises.readFile(fileName, 'utf8')];
9187
+ return [4 /*yield*/, promises.readFile(fileName, 'utf-8')];
8173
9188
  case 2:
8174
9189
  pipelineString = (_e.sent());
8175
- return [4 /*yield*/, pipelineStringToJson(pipelineString, options)];
9190
+ return [4 /*yield*/, pipelineStringToJson(pipelineString, {
9191
+ llmTools: llmTools,
9192
+ rootDirname: rootDirname,
9193
+ })];
8176
9194
  case 3:
8177
9195
  pipeline = _e.sent();
8178
9196
  pipeline = __assign(__assign({}, pipeline), { sourceFile: sourceFile });
@@ -8180,7 +9198,7 @@
8180
9198
  case 4:
8181
9199
  if (!fileName.endsWith('.ptbk.json')) return [3 /*break*/, 6];
8182
9200
  _d = (_c = JSON).parse;
8183
- return [4 /*yield*/, promises.readFile(fileName, 'utf8')];
9201
+ return [4 /*yield*/, promises.readFile(fileName, 'utf-8')];
8184
9202
  case 5:
8185
9203
  // TODO: Handle non-valid JSON files
8186
9204
  pipeline = _d.apply(_c, [_e.sent()]);
@@ -8288,7 +9306,7 @@
8288
9306
  });
8289
9307
  }
8290
9308
  /**
8291
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9309
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8292
9310
  * TODO: [🖇] What about symlinks? Maybe option isSymlinksFollowed
8293
9311
  */
8294
9312
 
@@ -8379,7 +9397,7 @@
8379
9397
  * TODO: Add Azure OpenAI
8380
9398
  * TODO: [🧠][🍛]
8381
9399
  * TODO: [🧠] Is there some meaningfull way how to test this util
8382
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9400
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8383
9401
  * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
8384
9402
  * TODO: This should be maybe not under `_common` but under `utils`
8385
9403
  * TODO: [🧠] Maybe pass env as argument
@@ -8556,7 +9574,7 @@
8556
9574
  * TODO: @@@ write `createLlmToolsFromEnv` vs `createLlmToolsFromConfigurationFromEnv` vs `createLlmToolsFromConfiguration`
8557
9575
  * TODO: [🧠][🍛] Which name is better `createLlmToolsFromEnv` or `createLlmToolsFromEnvironment`?
8558
9576
  * TODO: [🧠] Is there some meaningfull way how to test this util
8559
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9577
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8560
9578
  * TODO: [🥃] Allow `ptbk make` without llm tools
8561
9579
  * TODO: This should be maybe not under `_common` but under `utils`
8562
9580
  */
@@ -8621,40 +9639,32 @@
8621
9639
  * TODO: [🍙] Make some standard order of json properties
8622
9640
  */
8623
9641
 
8624
- /**
8625
- * @@@
8626
- *
8627
- * @private for `FilesStorage`
8628
- */
8629
- function nameToSubfolderPath(name) {
8630
- return [name.substr(0, 1).toLowerCase(), name.substr(1, 1).toLowerCase()];
8631
- }
8632
-
8633
9642
  /**
8634
9643
  * @@@
8635
9644
  *
8636
9645
  * @public exported from `@promptbook/node`
8637
9646
  */
8638
- var FilesStorage = /** @class */ (function () {
8639
- function FilesStorage(options) {
9647
+ var FileCacheStorage = /** @class */ (function () {
9648
+ function FileCacheStorage(options) {
8640
9649
  this.options = options;
8641
9650
  if (!$isRunningInNode()) {
8642
- throw new EnvironmentMismatchError("FilesStorage works only in Node.js environment");
9651
+ throw new EnvironmentMismatchError("FileCacheStorage works only in Node.js environment");
8643
9652
  }
8644
9653
  }
8645
9654
  /**
8646
9655
  * @@@
8647
9656
  */
8648
- FilesStorage.prototype.getFilenameForKey = function (key) {
9657
+ FileCacheStorage.prototype.getFilenameForKey = function (key) {
9658
+ // TODO: [👬] DRY
8649
9659
  var name = titleToName(key);
8650
9660
  var hash = sha256__default["default"](hexEncoder__default["default"].parse(name)).toString( /* hex */);
8651
9661
  // <- TODO: [🥬] Encapsulate sha256 to some private utility function
8652
- return path.join.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));
9662
+ return path.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));
8653
9663
  };
8654
9664
  /**
8655
9665
  * @@@ 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.
8656
9666
  */
8657
- FilesStorage.prototype.getItem = function (key) {
9667
+ FileCacheStorage.prototype.getItem = function (key) {
8658
9668
  return __awaiter(this, void 0, void 0, function () {
8659
9669
  var filename, fileContent, value;
8660
9670
  return __generator(this, function (_a) {
@@ -8679,7 +9689,7 @@
8679
9689
  /**
8680
9690
  * @@@ Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
8681
9691
  */
8682
- FilesStorage.prototype.setItem = function (key, value) {
9692
+ FileCacheStorage.prototype.setItem = function (key, value) {
8683
9693
  return __awaiter(this, void 0, void 0, function () {
8684
9694
  var filename, fileContent;
8685
9695
  return __generator(this, function (_a) {
@@ -8704,7 +9714,7 @@
8704
9714
  /**
8705
9715
  * @@@ 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.
8706
9716
  */
8707
- FilesStorage.prototype.removeItem = function (key) {
9717
+ FileCacheStorage.prototype.removeItem = function (key) {
8708
9718
  return __awaiter(this, void 0, void 0, function () {
8709
9719
  var filename;
8710
9720
  return __generator(this, function (_a) {
@@ -8721,14 +9731,66 @@
8721
9731
  });
8722
9732
  });
8723
9733
  };
8724
- return FilesStorage;
9734
+ return FileCacheStorage;
8725
9735
  }());
8726
9736
  /**
8727
9737
  * TODO: [🌗] Maybe some checkers, not all valid JSONs are desired and valid values
8728
- * Note: [🟢] This code should never be published outside of `@promptbook/node` and `@promptbook/cli` and `@promptbook/cli`
9738
+ * Note: [🟢] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
9739
+ */
9740
+
9741
+ /**
9742
+ * Run multiple commands in a shell in sequence
9743
+ *
9744
+ * Note: There are 2 similar functions in the codebase:
9745
+ * - `$execCommand` which runs a single command
9746
+ * - `$execCommands` which runs multiple commands
9747
+ *
9748
+ * @public exported from `@promptbook/node`
9749
+ */
9750
+ function $execCommands(_a) {
9751
+ var commands = _a.commands, cwd = _a.cwd, crashOnError = _a.crashOnError;
9752
+ return __awaiter(this, void 0, void 0, function () {
9753
+ var commands_1, commands_1_1, command, e_1_1;
9754
+ var e_1, _b;
9755
+ return __generator(this, function (_c) {
9756
+ switch (_c.label) {
9757
+ case 0:
9758
+ _c.trys.push([0, 5, 6, 7]);
9759
+ commands_1 = __values(commands), commands_1_1 = commands_1.next();
9760
+ _c.label = 1;
9761
+ case 1:
9762
+ if (!!commands_1_1.done) return [3 /*break*/, 4];
9763
+ command = commands_1_1.value;
9764
+ return [4 /*yield*/, $execCommand({ command: command, cwd: cwd, crashOnError: crashOnError })];
9765
+ case 2:
9766
+ _c.sent();
9767
+ _c.label = 3;
9768
+ case 3:
9769
+ commands_1_1 = commands_1.next();
9770
+ return [3 /*break*/, 1];
9771
+ case 4: return [3 /*break*/, 7];
9772
+ case 5:
9773
+ e_1_1 = _c.sent();
9774
+ e_1 = { error: e_1_1 };
9775
+ return [3 /*break*/, 7];
9776
+ case 6:
9777
+ try {
9778
+ if (commands_1_1 && !commands_1_1.done && (_b = commands_1.return)) _b.call(commands_1);
9779
+ }
9780
+ finally { if (e_1) throw e_1.error; }
9781
+ return [7 /*endfinally*/];
9782
+ case 7: return [2 /*return*/];
9783
+ }
9784
+ });
9785
+ });
9786
+ }
9787
+ /**
9788
+ * Note: [🟢 <- TODO: [🦖] !!!!!! Split scrapers into packages and enable] Code in this file should never be published outside of `@promptbook/node` and `@promptbook/cli`
8729
9789
  */
8730
9790
 
8731
- exports.FilesStorage = FilesStorage;
9791
+ exports.$execCommand = $execCommand;
9792
+ exports.$execCommands = $execCommands;
9793
+ exports.FileCacheStorage = FileCacheStorage;
8732
9794
  exports.PROMPTBOOK_VERSION = PROMPTBOOK_VERSION;
8733
9795
  exports.createCollectionFromDirectory = createCollectionFromDirectory;
8734
9796
  exports.createLlmToolsFromConfigurationFromEnv = createLlmToolsFromConfigurationFromEnv;