@promptbook/markdown-utils 0.92.0-3 → 0.92.0-31

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 (172) hide show
  1. package/esm/index.es.js +555 -274
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/src/_packages/browser.index.d.ts +2 -0
  4. package/esm/typings/src/_packages/core.index.d.ts +22 -6
  5. package/esm/typings/src/_packages/deepseek.index.d.ts +2 -0
  6. package/esm/typings/src/_packages/google.index.d.ts +2 -0
  7. package/esm/typings/src/_packages/types.index.d.ts +4 -2
  8. package/esm/typings/src/_packages/utils.index.d.ts +2 -0
  9. package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +1 -1
  10. package/esm/typings/src/collection/PipelineCollection.d.ts +0 -2
  11. package/esm/typings/src/collection/SimplePipelineCollection.d.ts +1 -1
  12. package/esm/typings/src/commands/FOREACH/ForeachJson.d.ts +6 -6
  13. package/esm/typings/src/commands/FOREACH/foreachCommandParser.d.ts +0 -2
  14. package/esm/typings/src/commands/FORMFACTOR/formfactorCommandParser.d.ts +1 -1
  15. package/esm/typings/src/commands/_BOILERPLATE/boilerplateCommandParser.d.ts +1 -1
  16. package/esm/typings/src/commands/_common/types/CommandParser.d.ts +36 -28
  17. package/esm/typings/src/config.d.ts +41 -11
  18. package/esm/typings/src/constants.d.ts +43 -2
  19. package/esm/typings/src/conversion/archive/loadArchive.d.ts +2 -2
  20. package/esm/typings/src/errors/0-BoilerplateError.d.ts +2 -2
  21. package/esm/typings/src/executables/$provideExecutablesForNode.d.ts +1 -1
  22. package/esm/typings/src/executables/apps/locateLibreoffice.d.ts +2 -1
  23. package/esm/typings/src/executables/apps/locatePandoc.d.ts +2 -1
  24. package/esm/typings/src/executables/locateApp.d.ts +2 -2
  25. package/esm/typings/src/executables/platforms/locateAppOnLinux.d.ts +2 -1
  26. package/esm/typings/src/executables/platforms/locateAppOnMacOs.d.ts +2 -1
  27. package/esm/typings/src/executables/platforms/locateAppOnWindows.d.ts +2 -1
  28. package/esm/typings/src/execution/AbstractTaskResult.d.ts +1 -1
  29. package/esm/typings/src/execution/CommonToolsOptions.d.ts +5 -1
  30. package/esm/typings/src/execution/LlmExecutionToolsConstructor.d.ts +2 -1
  31. package/esm/typings/src/execution/PipelineExecutorResult.d.ts +4 -2
  32. package/esm/typings/src/execution/createPipelineExecutor/$OngoingTaskResult.d.ts +12 -9
  33. package/esm/typings/src/execution/createPipelineExecutor/10-executePipeline.d.ts +13 -10
  34. package/esm/typings/src/execution/createPipelineExecutor/20-executeTask.d.ts +12 -9
  35. package/esm/typings/src/execution/createPipelineExecutor/30-executeFormatSubvalues.d.ts +15 -3
  36. package/esm/typings/src/execution/createPipelineExecutor/40-executeAttempts.d.ts +20 -14
  37. package/esm/typings/src/execution/createPipelineExecutor/computeCosineSimilarity.d.ts +13 -0
  38. package/esm/typings/src/execution/createPipelineExecutor/filterJustOutputParameters.d.ts +7 -6
  39. package/esm/typings/src/execution/createPipelineExecutor/getContextForTask.d.ts +5 -1
  40. package/esm/typings/src/execution/createPipelineExecutor/getExamplesForTask.d.ts +1 -1
  41. package/esm/typings/src/execution/createPipelineExecutor/getKnowledgeForTask.d.ts +21 -5
  42. package/esm/typings/src/execution/createPipelineExecutor/getReservedParametersForTask.d.ts +19 -5
  43. package/esm/typings/src/execution/createPipelineExecutor/knowledgePiecesToString.d.ts +9 -0
  44. package/esm/typings/src/execution/translation/automatic-translate/automatic-translators/LindatAutomaticTranslator.d.ts +4 -4
  45. package/esm/typings/src/execution/utils/checkExpectations.d.ts +1 -1
  46. package/esm/typings/src/execution/utils/uncertainNumber.d.ts +3 -2
  47. package/esm/typings/src/formats/_common/{FormatDefinition.d.ts → FormatParser.d.ts} +8 -6
  48. package/esm/typings/src/formats/_common/FormatSubvalueParser.d.ts +66 -0
  49. package/esm/typings/src/formats/csv/CsvFormatParser.d.ts +17 -0
  50. package/esm/typings/src/formats/csv/CsvSettings.d.ts +2 -2
  51. package/esm/typings/src/formats/csv/utils/csvParse.d.ts +12 -0
  52. package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +1 -1
  53. package/esm/typings/src/formats/index.d.ts +2 -2
  54. package/esm/typings/src/formats/json/{JsonFormatDefinition.d.ts → JsonFormatParser.d.ts} +6 -6
  55. package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +1 -1
  56. package/esm/typings/src/formats/json/utils/jsonParse.d.ts +8 -0
  57. package/esm/typings/src/formats/text/{TextFormatDefinition.d.ts → TextFormatParser.d.ts} +7 -7
  58. package/esm/typings/src/formats/xml/XmlFormatParser.d.ts +19 -0
  59. package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +1 -1
  60. package/esm/typings/src/formfactors/_boilerplate/BoilerplateFormfactorDefinition.d.ts +3 -2
  61. package/esm/typings/src/formfactors/_common/AbstractFormfactorDefinition.d.ts +16 -7
  62. package/esm/typings/src/formfactors/_common/FormfactorDefinition.d.ts +3 -1
  63. package/esm/typings/src/formfactors/_common/string_formfactor_name.d.ts +2 -1
  64. package/esm/typings/src/formfactors/chatbot/ChatbotFormfactorDefinition.d.ts +2 -2
  65. package/esm/typings/src/formfactors/completion/CompletionFormfactorDefinition.d.ts +29 -0
  66. package/esm/typings/src/formfactors/generator/GeneratorFormfactorDefinition.d.ts +2 -1
  67. package/esm/typings/src/formfactors/generic/GenericFormfactorDefinition.d.ts +2 -2
  68. package/esm/typings/src/formfactors/index.d.ts +33 -8
  69. package/esm/typings/src/formfactors/matcher/MatcherFormfactorDefinition.d.ts +4 -2
  70. package/esm/typings/src/formfactors/sheets/SheetsFormfactorDefinition.d.ts +3 -2
  71. package/esm/typings/src/formfactors/translator/TranslatorFormfactorDefinition.d.ts +3 -2
  72. package/esm/typings/src/high-level-abstractions/index.d.ts +2 -2
  73. package/esm/typings/src/llm-providers/_common/register/$llmToolsMetadataRegister.d.ts +3 -3
  74. package/esm/typings/src/llm-providers/_common/register/$llmToolsRegister.d.ts +3 -3
  75. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +4 -4
  76. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +4 -3
  77. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +17 -4
  78. package/esm/typings/src/llm-providers/_common/register/LlmToolsConfiguration.d.ts +11 -4
  79. package/esm/typings/src/llm-providers/_common/register/LlmToolsMetadata.d.ts +27 -5
  80. package/esm/typings/src/llm-providers/_common/register/LlmToolsOptions.d.ts +9 -2
  81. package/esm/typings/src/llm-providers/_common/register/createLlmToolsFromConfiguration.d.ts +12 -3
  82. package/esm/typings/src/llm-providers/_common/utils/cache/CacheItem.d.ts +10 -5
  83. package/esm/typings/src/llm-providers/_common/utils/cache/CacheLlmToolsOptions.d.ts +5 -3
  84. package/esm/typings/src/llm-providers/_common/utils/cache/cacheLlmTools.d.ts +3 -3
  85. package/esm/typings/src/llm-providers/_common/utils/count-total-usage/limitTotalUsage.d.ts +5 -5
  86. package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  87. package/esm/typings/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +4 -0
  88. package/esm/typings/src/llm-providers/deepseek/deepseek-models.d.ts +23 -0
  89. package/esm/typings/src/llm-providers/google/google-models.d.ts +23 -0
  90. package/esm/typings/src/llm-providers/openai/OpenAiExecutionTools.d.ts +4 -0
  91. package/esm/typings/src/llm-providers/openai/openai-models.d.ts +1 -1
  92. package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +2 -2
  93. package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +2 -2
  94. package/esm/typings/src/migrations/migratePipeline.d.ts +9 -0
  95. package/esm/typings/src/other/templates/getBookTemplates.d.ts +2 -2
  96. package/esm/typings/src/personas/preparePersona.d.ts +1 -1
  97. package/esm/typings/src/pipeline/PipelineInterface/PipelineInterface.d.ts +3 -3
  98. package/esm/typings/src/pipeline/PipelineInterface/constants.d.ts +1 -1
  99. package/esm/typings/src/pipeline/PipelineInterface/getPipelineInterface.d.ts +1 -1
  100. package/esm/typings/src/pipeline/PipelineInterface/isPipelineImplementingInterface.d.ts +5 -4
  101. package/esm/typings/src/pipeline/PipelineInterface/isPipelineInterfacesEqual.d.ts +1 -1
  102. package/esm/typings/src/pipeline/PipelineJson/CommonTaskJson.d.ts +9 -6
  103. package/esm/typings/src/pipeline/PipelineJson/PersonaJson.d.ts +4 -2
  104. package/esm/typings/src/pipeline/PipelineJson/PipelineJson.d.ts +3 -2
  105. package/esm/typings/src/pipeline/PipelineString.d.ts +3 -1
  106. package/esm/typings/src/pipeline/book-notation.d.ts +2 -2
  107. package/esm/typings/src/postprocessing/utils/extractJsonBlock.d.ts +1 -1
  108. package/esm/typings/src/prepare/prepareTasks.d.ts +7 -4
  109. package/esm/typings/src/remote-server/openapi-types.d.ts +348 -6
  110. package/esm/typings/src/remote-server/openapi.d.ts +398 -4
  111. package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +2 -1
  112. package/esm/typings/src/scrapers/_boilerplate/BoilerplateScraper.d.ts +3 -3
  113. package/esm/typings/src/scrapers/_boilerplate/createBoilerplateScraper.d.ts +1 -1
  114. package/esm/typings/src/scrapers/_boilerplate/register-metadata.d.ts +1 -1
  115. package/esm/typings/src/scrapers/_common/Converter.d.ts +3 -1
  116. package/esm/typings/src/scrapers/_common/Scraper.d.ts +4 -3
  117. package/esm/typings/src/scrapers/_common/ScraperIntermediateSource.d.ts +4 -2
  118. package/esm/typings/src/scrapers/_common/register/$provideFilesystemForNode.d.ts +2 -1
  119. package/esm/typings/src/scrapers/_common/register/$provideScrapersForBrowser.d.ts +6 -3
  120. package/esm/typings/src/scrapers/_common/register/$provideScrapersForNode.d.ts +3 -5
  121. package/esm/typings/src/scrapers/_common/register/$scrapersMetadataRegister.d.ts +3 -3
  122. package/esm/typings/src/scrapers/_common/register/$scrapersRegister.d.ts +3 -2
  123. package/esm/typings/src/scrapers/_common/register/ScraperAndConverterMetadata.d.ts +8 -5
  124. package/esm/typings/src/scrapers/_common/register/ScraperConstructor.d.ts +2 -1
  125. package/esm/typings/src/scrapers/_common/utils/getScraperIntermediateSource.d.ts +6 -5
  126. package/esm/typings/src/scrapers/_common/utils/makeKnowledgeSourceHandler.d.ts +3 -1
  127. package/esm/typings/src/scrapers/document/createDocumentScraper.d.ts +1 -1
  128. package/esm/typings/src/scrapers/document-legacy/createLegacyDocumentScraper.d.ts +2 -1
  129. package/esm/typings/src/scrapers/markdown/createMarkdownScraper.d.ts +4 -1
  130. package/esm/typings/src/scrapers/markitdown/MarkitdownScraper.d.ts +1 -1
  131. package/esm/typings/src/scrapers/pdf/createPdfScraper.d.ts +2 -1
  132. package/esm/typings/src/scrapers/website/createWebsiteScraper.d.ts +3 -4
  133. package/esm/typings/src/scripting/javascript/postprocessing-functions.d.ts +5 -1
  134. package/esm/typings/src/storage/file-cache-storage/FileCacheStorage.d.ts +12 -5
  135. package/esm/typings/src/storage/file-cache-storage/FileCacheStorageOptions.d.ts +4 -2
  136. package/esm/typings/src/storage/file-cache-storage/utils/nameToSubfolderPath.d.ts +2 -1
  137. package/esm/typings/src/storage/local-storage/getIndexedDbStorage.d.ts +10 -0
  138. package/esm/typings/src/storage/local-storage/utils/makePromptbookStorageFromIndexedDb.d.ts +7 -0
  139. package/esm/typings/src/storage/local-storage/utils/makePromptbookStorageFromWebStorage.d.ts +2 -1
  140. package/esm/typings/src/types/IntermediateFilesStrategy.d.ts +2 -1
  141. package/esm/typings/src/types/ModelVariant.d.ts +5 -5
  142. package/esm/typings/src/types/typeAliases.d.ts +17 -13
  143. package/esm/typings/src/utils/$Register.d.ts +8 -7
  144. package/esm/typings/src/utils/editable/edit-pipeline-string/addPipelineCommand.d.ts +2 -2
  145. package/esm/typings/src/utils/editable/edit-pipeline-string/deflatePipeline.d.ts +4 -1
  146. package/esm/typings/src/utils/editable/utils/isFlatPipeline.d.ts +2 -1
  147. package/esm/typings/src/utils/environment/$getGlobalScope.d.ts +2 -1
  148. package/esm/typings/src/utils/expectation-counters/index.d.ts +1 -1
  149. package/esm/typings/src/utils/markdown/extractAllListItemsFromMarkdown.d.ts +1 -1
  150. package/esm/typings/src/utils/normalization/nameToUriPart.d.ts +4 -4
  151. package/esm/typings/src/utils/normalization/nameToUriParts.d.ts +4 -4
  152. package/esm/typings/src/utils/normalization/normalize-to-kebab-case.d.ts +3 -3
  153. package/esm/typings/src/utils/normalization/normalizeTo_SCREAMING_CASE.d.ts +3 -3
  154. package/esm/typings/src/utils/normalization/normalizeTo_camelCase.d.ts +4 -4
  155. package/esm/typings/src/utils/normalization/normalizeTo_snake_case.d.ts +3 -3
  156. package/esm/typings/src/utils/normalization/removeDiacritics.d.ts +3 -3
  157. package/esm/typings/src/utils/normalization/searchKeywords.d.ts +4 -1
  158. package/esm/typings/src/utils/normalization/titleToName.d.ts +4 -4
  159. package/esm/typings/src/utils/organization/empty_object.d.ts +2 -2
  160. package/esm/typings/src/utils/organization/just_empty_object.d.ts +4 -4
  161. package/esm/typings/src/utils/parameters/mapAvailableToExpectedParameters.d.ts +7 -7
  162. package/esm/typings/src/utils/serialization/clonePipeline.d.ts +4 -3
  163. package/esm/typings/src/utils/serialization/deepClone.d.ts +5 -1
  164. package/esm/typings/src/utils/validators/javascriptName/isValidJavascriptName.d.ts +3 -3
  165. package/esm/typings/src/utils/validators/parameterName/validateParameterName.d.ts +5 -4
  166. package/esm/typings/src/version.d.ts +2 -1
  167. package/package.json +1 -1
  168. package/umd/index.umd.js +555 -274
  169. package/umd/index.umd.js.map +1 -1
  170. package/esm/typings/src/formats/_common/FormatSubvalueDefinition.d.ts +0 -31
  171. package/esm/typings/src/formats/csv/CsvFormatDefinition.d.ts +0 -17
  172. package/esm/typings/src/formats/xml/XmlFormatDefinition.d.ts +0 -19
package/esm/index.es.js CHANGED
@@ -25,7 +25,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
25
25
  * @generated
26
26
  * @see https://github.com/webgptorg/promptbook
27
27
  */
28
- const PROMPTBOOK_ENGINE_VERSION = '0.92.0-3';
28
+ const PROMPTBOOK_ENGINE_VERSION = '0.92.0-31';
29
29
  /**
30
30
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
31
31
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -231,6 +231,21 @@ const DEFAULT_BOOK_TITLE = `✨ Untitled Book`;
231
231
  * @public exported from `@promptbook/core`
232
232
  */
233
233
  const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
234
+ /**
235
+ * Threshold value that determines when a dataset is considered "big"
236
+ * and may require special handling or optimizations
237
+ *
238
+ * For example, when error occurs in one item of the big dataset, it will not fail the whole pipeline
239
+ *
240
+ * @public exported from `@promptbook/core`
241
+ */
242
+ const BIG_DATASET_TRESHOLD = 50;
243
+ /**
244
+ * Placeholder text used to represent a placeholder value of failed operation
245
+ *
246
+ * @public exported from `@promptbook/core`
247
+ */
248
+ const FAILED_VALUE_PLACEHOLDER = '!?';
234
249
  // <- TODO: [🧠] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
235
250
  /**
236
251
  * The maximum number of iterations for a loops
@@ -310,7 +325,7 @@ const DEFAULT_DOWNLOAD_CACHE_DIRNAME = './.promptbook/download-cache';
310
325
  const DEFAULT_SCRAPE_CACHE_DIRNAME = './.promptbook/scrape-cache';
311
326
  // <- TODO: [🧜‍♂️]
312
327
  /**
313
- * @@@
328
+ * Default settings for parsing and generating CSV files in Promptbook.
314
329
  *
315
330
  * @public exported from `@promptbook/core`
316
331
  */
@@ -321,19 +336,19 @@ const DEFAULT_CSV_SETTINGS = Object.freeze({
321
336
  skipEmptyLines: true,
322
337
  });
323
338
  /**
324
- * @@@
339
+ * Controls whether verbose logging is enabled by default throughout the application.
325
340
  *
326
341
  * @public exported from `@promptbook/core`
327
342
  */
328
343
  let DEFAULT_IS_VERBOSE = false;
329
344
  /**
330
- * @@@
345
+ * Controls whether auto-installation of dependencies is enabled by default.
331
346
  *
332
347
  * @public exported from `@promptbook/core`
333
348
  */
334
349
  const DEFAULT_IS_AUTO_INSTALLED = false;
335
350
  /**
336
- * @@@
351
+ * Indicates whether pipeline logic validation is enabled. When true, the pipeline logic is checked for consistency.
337
352
  *
338
353
  * @private within the repository
339
354
  */
@@ -466,7 +481,7 @@ function assertsError(whatWasThrown) {
466
481
  * Function isValidJsonString will tell you if the string is valid JSON or not
467
482
  *
468
483
  * @param value The string to check
469
- * @returns True if the string is a valid JSON string, false otherwise
484
+ * @returns `true` if the string is a valid JSON string, false otherwise
470
485
  *
471
486
  * @public exported from `@promptbook/utils`
472
487
  */
@@ -517,7 +532,7 @@ function extractJsonBlock(markdown) {
517
532
  }
518
533
  /**
519
534
  * TODO: Add some auto-healing logic + extract YAML, JSON5, TOML, etc.
520
- * TODO: [🏢] Make this logic part of `JsonFormatDefinition` or `isValidJsonString`
535
+ * TODO: [🏢] Make this logic part of `JsonFormatParser` or `isValidJsonString`
521
536
  */
522
537
 
523
538
  /**
@@ -537,7 +552,7 @@ function extractJsonBlock(markdown) {
537
552
  function keepUnused(...valuesToKeep) {
538
553
  }
539
554
 
540
- var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModelNames}` List of available model names separated by comma (,)\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n\\`\\`\\`json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
555
+ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with 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\nHere are the available models:\n\n```json\n{availableModels}\n```\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:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with 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\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
541
556
 
542
557
  /**
543
558
  * Checks if value is valid email
@@ -1016,8 +1031,12 @@ function checkSerializableAsJson(options) {
1016
1031
  */
1017
1032
 
1018
1033
  /**
1019
- * @@@
1034
+ * Creates a deep clone of the given object
1020
1035
  *
1036
+ * Note: This method only works for objects that are fully serializable to JSON and do not contain functions, Dates, or special types.
1037
+ *
1038
+ * @param objectValue The object to clone.
1039
+ * @returns A deep, writable clone of the input object.
1021
1040
  * @public exported from `@promptbook/utils`
1022
1041
  */
1023
1042
  function deepClone(objectValue) {
@@ -1099,13 +1118,13 @@ const ORDER_OF_PIPELINE_JSON = [
1099
1118
  */
1100
1119
  const REPLACING_NONCE = 'ptbkauk42kV2dzao34faw7FudQUHYPtW';
1101
1120
  /**
1102
- * @@@
1121
+ * Placeholder value indicating a parameter is missing its value.
1103
1122
  *
1104
1123
  * @private within the repository
1105
1124
  */
1106
1125
  const RESERVED_PARAMETER_MISSING_VALUE = 'MISSING-' + REPLACING_NONCE;
1107
1126
  /**
1108
- * @@@
1127
+ * Placeholder value indicating a parameter is restricted and cannot be used directly.
1109
1128
  *
1110
1129
  * @private within the repository
1111
1130
  */
@@ -1563,7 +1582,7 @@ function extractParameterNames(template) {
1563
1582
  */
1564
1583
  function unpreparePipeline(pipeline) {
1565
1584
  let { personas, knowledgeSources, tasks } = pipeline;
1566
- personas = personas.map((persona) => ({ ...persona, modelRequirements: undefined, preparationIds: undefined }));
1585
+ personas = personas.map((persona) => ({ ...persona, modelsRequirements: undefined, preparationIds: undefined }));
1567
1586
  knowledgeSources = knowledgeSources.map((knowledgeSource) => ({ ...knowledgeSource, preparationIds: undefined }));
1568
1587
  tasks = tasks.map((task) => {
1569
1588
  let { dependentParameterNames } = task;
@@ -1604,7 +1623,7 @@ class SimplePipelineCollection {
1604
1623
  /**
1605
1624
  * Constructs a pipeline collection from pipelines
1606
1625
  *
1607
- * @param pipelines @@@
1626
+ * @param pipelines Array of pipeline JSON objects to include in the collection
1608
1627
  *
1609
1628
  * Note: During the construction logic of all pipelines are validated
1610
1629
  * Note: It is not recommended to use this constructor directly, use `createCollectionFromJson` *(or other variant)* instead
@@ -1768,15 +1787,21 @@ class PipelineExecutionError extends Error {
1768
1787
  * @public exported from `@promptbook/core`
1769
1788
  */
1770
1789
  function isPipelinePrepared(pipeline) {
1771
- // Note: Ignoring `pipeline.preparations` @@@
1772
- // Note: Ignoring `pipeline.knowledgePieces` @@@
1790
+ // Note: Ignoring `pipeline.preparations`
1791
+ // Note: Ignoring `pipeline.knowledgePieces`
1773
1792
  if (pipeline.title === undefined || pipeline.title === '' || pipeline.title === DEFAULT_BOOK_TITLE) {
1793
+ // TODO: !!! Comment this out
1794
+ console.log('Pipeline is not prepared because title is undefined or empty', pipeline);
1774
1795
  return false;
1775
1796
  }
1776
- if (!pipeline.personas.every((persona) => persona.modelRequirements !== undefined)) {
1797
+ if (!pipeline.personas.every((persona) => persona.modelsRequirements !== undefined)) {
1798
+ // TODO: !!! Comment this out
1799
+ console.log('Pipeline is not prepared because personas are not prepared', pipeline.personas);
1777
1800
  return false;
1778
1801
  }
1779
1802
  if (!pipeline.knowledgeSources.every((knowledgeSource) => knowledgeSource.preparationIds !== undefined)) {
1803
+ // TODO: !!! Comment this out
1804
+ console.log('Pipeline is not prepared because knowledge sources are not prepared', pipeline.knowledgeSources);
1780
1805
  return false;
1781
1806
  }
1782
1807
  /*
@@ -1797,36 +1822,6 @@ function isPipelinePrepared(pipeline) {
1797
1822
  * - [♨] Are tasks prepared
1798
1823
  */
1799
1824
 
1800
- /**
1801
- * Recursively converts JSON strings to JSON objects
1802
-
1803
- * @public exported from `@promptbook/utils`
1804
- */
1805
- function jsonStringsToJsons(object) {
1806
- if (object === null) {
1807
- return object;
1808
- }
1809
- if (Array.isArray(object)) {
1810
- return object.map(jsonStringsToJsons);
1811
- }
1812
- if (typeof object !== 'object') {
1813
- return object;
1814
- }
1815
- const newObject = { ...object };
1816
- for (const [key, value] of Object.entries(object)) {
1817
- if (typeof value === 'string' && isValidJsonString(value)) {
1818
- newObject[key] = JSON.parse(value);
1819
- }
1820
- else {
1821
- newObject[key] = jsonStringsToJsons(value);
1822
- }
1823
- }
1824
- return newObject;
1825
- }
1826
- /**
1827
- * TODO: Type the return type correctly
1828
- */
1829
-
1830
1825
  /**
1831
1826
  * This error indicates problems parsing the format value
1832
1827
  *
@@ -2036,6 +2031,101 @@ const ALL_ERRORS = {
2036
2031
  * Note: [💞] Ignore a discrepancy between file name and entity name
2037
2032
  */
2038
2033
 
2034
+ /**
2035
+ * Serializes an error into a [🚉] JSON-serializable object
2036
+ *
2037
+ * @public exported from `@promptbook/utils`
2038
+ */
2039
+ function serializeError(error) {
2040
+ const { name, message, stack } = error;
2041
+ const { id } = error;
2042
+ if (!Object.keys(ALL_ERRORS).includes(name)) {
2043
+ console.error(spaceTrim((block) => `
2044
+
2045
+ Cannot serialize error with name "${name}"
2046
+
2047
+ Authors of Promptbook probably forgot to add this error into the list of errors:
2048
+ https://github.com/webgptorg/promptbook/blob/main/src/errors/0-index.ts
2049
+
2050
+
2051
+ ${block(stack || message)}
2052
+
2053
+ `));
2054
+ }
2055
+ return {
2056
+ name: name,
2057
+ message,
2058
+ stack,
2059
+ id, // Include id in the serialized object
2060
+ };
2061
+ }
2062
+
2063
+ /**
2064
+ * Converts a JavaScript Object Notation (JSON) string into an object.
2065
+ *
2066
+ * Note: This is wrapper around `JSON.parse()` with better error and type handling
2067
+ *
2068
+ * @public exported from `@promptbook/utils`
2069
+ */
2070
+ function jsonParse(value) {
2071
+ if (value === undefined) {
2072
+ throw new Error(`Can not parse JSON from undefined value.`);
2073
+ }
2074
+ else if (typeof value !== 'string') {
2075
+ console.error('Can not parse JSON from non-string value.', { text: value });
2076
+ throw new Error(spaceTrim(`
2077
+ Can not parse JSON from non-string value.
2078
+
2079
+ The value type: ${typeof value}
2080
+ See more in console.
2081
+ `));
2082
+ }
2083
+ try {
2084
+ return JSON.parse(value);
2085
+ }
2086
+ catch (error) {
2087
+ if (!(error instanceof Error)) {
2088
+ throw error;
2089
+ }
2090
+ throw new Error(spaceTrim((block) => `
2091
+ ${block(error.message)}
2092
+
2093
+ The JSON text:
2094
+ ${block(value)}
2095
+ `));
2096
+ }
2097
+ }
2098
+
2099
+ /**
2100
+ * Recursively converts JSON strings to JSON objects
2101
+
2102
+ * @public exported from `@promptbook/utils`
2103
+ */
2104
+ function jsonStringsToJsons(object) {
2105
+ if (object === null) {
2106
+ return object;
2107
+ }
2108
+ if (Array.isArray(object)) {
2109
+ return object.map(jsonStringsToJsons);
2110
+ }
2111
+ if (typeof object !== 'object') {
2112
+ return object;
2113
+ }
2114
+ const newObject = { ...object };
2115
+ for (const [key, value] of Object.entries(object)) {
2116
+ if (typeof value === 'string' && isValidJsonString(value)) {
2117
+ newObject[key] = jsonParse(value);
2118
+ }
2119
+ else {
2120
+ newObject[key] = jsonStringsToJsons(value);
2121
+ }
2122
+ }
2123
+ return newObject;
2124
+ }
2125
+ /**
2126
+ * TODO: Type the return type correctly
2127
+ */
2128
+
2039
2129
  /**
2040
2130
  * Deserializes the error object
2041
2131
  *
@@ -2201,64 +2291,6 @@ function createTask(options) {
2201
2291
  * TODO: [🐚] Split into more files and make `PrepareTask` & `RemoteTask` + split the function
2202
2292
  */
2203
2293
 
2204
- /**
2205
- * Serializes an error into a [🚉] JSON-serializable object
2206
- *
2207
- * @public exported from `@promptbook/utils`
2208
- */
2209
- function serializeError(error) {
2210
- const { name, message, stack } = error;
2211
- const { id } = error;
2212
- if (!Object.keys(ALL_ERRORS).includes(name)) {
2213
- console.error(spaceTrim((block) => `
2214
-
2215
- Cannot serialize error with name "${name}"
2216
-
2217
- Authors of Promptbook probably forgot to add this error into the list of errors:
2218
- https://github.com/webgptorg/promptbook/blob/main/src/errors/0-index.ts
2219
-
2220
-
2221
- ${block(stack || message)}
2222
-
2223
- `));
2224
- }
2225
- return {
2226
- name: name,
2227
- message,
2228
- stack,
2229
- id, // Include id in the serialized object
2230
- };
2231
- }
2232
-
2233
- /**
2234
- * Async version of Array.forEach
2235
- *
2236
- * @param array - Array to iterate over
2237
- * @param options - Options for the function
2238
- * @param callbackfunction - Function to call for each item
2239
- * @public exported from `@promptbook/utils`
2240
- * @deprecated [🪂] Use queues instead
2241
- */
2242
- async function forEachAsync(array, options, callbackfunction) {
2243
- const { maxParallelCount = Infinity } = options;
2244
- let index = 0;
2245
- let runningTasks = [];
2246
- const tasks = [];
2247
- for (const item of array) {
2248
- const currentIndex = index++;
2249
- const task = callbackfunction(item, currentIndex, array);
2250
- tasks.push(task);
2251
- runningTasks.push(task);
2252
- /* not await */ Promise.resolve(task).then(() => {
2253
- runningTasks = runningTasks.filter((t) => t !== task);
2254
- });
2255
- if (maxParallelCount < runningTasks.length) {
2256
- await Promise.race(runningTasks);
2257
- }
2258
- }
2259
- await Promise.all(tasks);
2260
- }
2261
-
2262
2294
  /**
2263
2295
  * Represents the uncertain value
2264
2296
  *
@@ -2302,7 +2334,7 @@ const ZERO_USAGE = $deepFreeze({
2302
2334
  *
2303
2335
  * @public exported from `@promptbook/core`
2304
2336
  */
2305
- $deepFreeze({
2337
+ const UNCERTAIN_USAGE = $deepFreeze({
2306
2338
  price: UNCERTAIN_ZERO_VALUE,
2307
2339
  input: {
2308
2340
  tokensCount: UNCERTAIN_ZERO_VALUE,
@@ -2327,6 +2359,35 @@ $deepFreeze({
2327
2359
  * Note: [💞] Ignore a discrepancy between file name and entity name
2328
2360
  */
2329
2361
 
2362
+ /**
2363
+ * Async version of Array.forEach
2364
+ *
2365
+ * @param array - Array to iterate over
2366
+ * @param options - Options for the function
2367
+ * @param callbackfunction - Function to call for each item
2368
+ * @public exported from `@promptbook/utils`
2369
+ * @deprecated [🪂] Use queues instead
2370
+ */
2371
+ async function forEachAsync(array, options, callbackfunction) {
2372
+ const { maxParallelCount = Infinity } = options;
2373
+ let index = 0;
2374
+ let runningTasks = [];
2375
+ const tasks = [];
2376
+ for (const item of array) {
2377
+ const currentIndex = index++;
2378
+ const task = callbackfunction(item, currentIndex, array);
2379
+ tasks.push(task);
2380
+ runningTasks.push(task);
2381
+ /* not await */ Promise.resolve(task).then(() => {
2382
+ runningTasks = runningTasks.filter((t) => t !== task);
2383
+ });
2384
+ if (maxParallelCount < runningTasks.length) {
2385
+ await Promise.race(runningTasks);
2386
+ }
2387
+ }
2388
+ await Promise.all(tasks);
2389
+ }
2390
+
2330
2391
  /**
2331
2392
  * Function `addUsage` will add multiple usages into one
2332
2393
  *
@@ -2673,27 +2734,48 @@ async function preparePersona(personaDescription, tools, options) {
2673
2734
  pipeline: await collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book'),
2674
2735
  tools,
2675
2736
  });
2676
- // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
2677
2737
  const _llms = arrayableToArray(tools.llm);
2678
2738
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
2679
- const availableModels = await llmTools.listModels();
2680
- const availableModelNames = availableModels
2739
+ const availableModels = (await llmTools.listModels())
2681
2740
  .filter(({ modelVariant }) => modelVariant === 'CHAT')
2682
- .map(({ modelName }) => modelName)
2683
- .join(',');
2684
- const result = await preparePersonaExecutor({ availableModelNames, personaDescription }).asPromise();
2741
+ .map(({ modelName, modelDescription }) => ({
2742
+ modelName,
2743
+ modelDescription,
2744
+ // <- Note: `modelTitle` and `modelVariant` is not relevant for this task
2745
+ }));
2746
+ const result = await preparePersonaExecutor({
2747
+ availableModels /* <- Note: Passing as JSON */,
2748
+ personaDescription,
2749
+ }).asPromise();
2685
2750
  const { outputParameters } = result;
2686
- const { modelRequirements: modelRequirementsRaw } = outputParameters;
2687
- const modelRequirements = JSON.parse(modelRequirementsRaw);
2751
+ const { modelsRequirements: modelsRequirementsJson } = outputParameters;
2752
+ let modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
2688
2753
  if (isVerbose) {
2689
- console.info(`PERSONA ${personaDescription}`, modelRequirements);
2754
+ console.info(`PERSONA ${personaDescription}`, modelsRequirementsUnchecked);
2690
2755
  }
2691
- const { modelName, systemMessage, temperature } = modelRequirements;
2692
- return {
2756
+ if (!Array.isArray(modelsRequirementsUnchecked)) {
2757
+ // <- TODO: Book should have syntax and system to enforce shape of JSON
2758
+ modelsRequirementsUnchecked = [modelsRequirementsUnchecked];
2759
+ /*
2760
+ throw new UnexpectedError(
2761
+ spaceTrim(
2762
+ (block) => `
2763
+ Invalid \`modelsRequirements\`:
2764
+
2765
+ \`\`\`json
2766
+ ${block(JSON.stringify(modelsRequirementsUnchecked, null, 4))}
2767
+ \`\`\`
2768
+ `,
2769
+ ),
2770
+ );
2771
+ */
2772
+ }
2773
+ const modelsRequirements = modelsRequirementsUnchecked.map((modelRequirements) => ({
2693
2774
  modelVariant: 'CHAT',
2694
- modelName,
2695
- systemMessage,
2696
- temperature,
2775
+ ...modelRequirements,
2776
+ }));
2777
+ return {
2778
+ modelsRequirements,
2697
2779
  };
2698
2780
  }
2699
2781
  /**
@@ -2704,7 +2786,8 @@ async function preparePersona(personaDescription, tools, options) {
2704
2786
  */
2705
2787
 
2706
2788
  /**
2707
- * @@@
2789
+ * Safely retrieves the global scope object (window in browser, global in Node.js)
2790
+ * regardless of the JavaScript environment in which the code is running
2708
2791
  *
2709
2792
  * Note: `$` is used to indicate that this function is not a pure function - it access global scope
2710
2793
  *
@@ -2715,10 +2798,10 @@ function $getGlobalScope() {
2715
2798
  }
2716
2799
 
2717
2800
  /**
2718
- * @@@
2801
+ * Normalizes a text string to SCREAMING_CASE (all uppercase with underscores).
2719
2802
  *
2720
- * @param text @@@
2721
- * @returns @@@
2803
+ * @param text The text string to be converted to SCREAMING_CASE format.
2804
+ * @returns The normalized text in SCREAMING_CASE format.
2722
2805
  * @example 'HELLO_WORLD'
2723
2806
  * @example 'I_LOVE_PROMPTBOOK'
2724
2807
  * @public exported from `@promptbook/utils`
@@ -2770,10 +2853,10 @@ function normalizeTo_SCREAMING_CASE(text) {
2770
2853
  */
2771
2854
 
2772
2855
  /**
2773
- * @@@
2856
+ * Normalizes a text string to snake_case format.
2774
2857
  *
2775
- * @param text @@@
2776
- * @returns @@@
2858
+ * @param text The text string to be converted to snake_case format.
2859
+ * @returns The normalized text in snake_case format.
2777
2860
  * @example 'hello_world'
2778
2861
  * @example 'i_love_promptbook'
2779
2862
  * @public exported from `@promptbook/utils`
@@ -2783,11 +2866,11 @@ function normalizeTo_snake_case(text) {
2783
2866
  }
2784
2867
 
2785
2868
  /**
2786
- * Register is @@@
2869
+ * Global registry for storing and managing registered entities of a given type.
2787
2870
  *
2788
2871
  * Note: `$` is used to indicate that this function is not a pure function - it accesses and adds variables in global scope.
2789
2872
  *
2790
- * @private internal utility, exported are only signleton instances of this class
2873
+ * @private internal utility, exported are only singleton instances of this class
2791
2874
  */
2792
2875
  class $Register {
2793
2876
  constructor(registerName) {
@@ -2831,10 +2914,10 @@ class $Register {
2831
2914
  }
2832
2915
 
2833
2916
  /**
2834
- * @@@
2917
+ * Global registry for storing metadata about all available scrapers and converters.
2835
2918
  *
2836
- * Note: `$` is used to indicate that this interacts with the global scope
2837
- * @singleton Only one instance of each register is created per build, but thare can be more @@@
2919
+ * Note: `$` is used to indicate that this interacts with the global scope.
2920
+ * @singleton Only one instance of each register is created per build, but there can be more in different contexts (e.g., tests).
2838
2921
  * @public exported from `@promptbook/core`
2839
2922
  */
2840
2923
  const $scrapersMetadataRegister = new $Register('scrapers_metadata');
@@ -2843,10 +2926,11 @@ const $scrapersMetadataRegister = new $Register('scrapers_metadata');
2843
2926
  */
2844
2927
 
2845
2928
  /**
2846
- * @@@
2929
+ * Registry for all available scrapers in the system.
2930
+ * Central point for registering and accessing different types of content scrapers.
2847
2931
  *
2848
2932
  * Note: `$` is used to indicate that this interacts with the global scope
2849
- * @singleton Only one instance of each register is created per build, but thare can be more @@@
2933
+ * @singleton Only one instance of each register is created per build, but there can be more than one in different build modules
2850
2934
  * @public exported from `@promptbook/core`
2851
2935
  */
2852
2936
  const $scrapersRegister = new $Register('scraper_constructors');
@@ -3186,10 +3270,10 @@ for (let i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
3186
3270
  */
3187
3271
 
3188
3272
  /**
3189
- * @@@
3273
+ * Removes diacritic marks (accents) from characters in a string.
3190
3274
  *
3191
- * @param input @@@
3192
- * @returns @@@
3275
+ * @param input The string containing diacritics to be normalized.
3276
+ * @returns The string with diacritics removed or normalized.
3193
3277
  * @public exported from `@promptbook/utils`
3194
3278
  */
3195
3279
  function removeDiacritics(input) {
@@ -3203,10 +3287,10 @@ function removeDiacritics(input) {
3203
3287
  */
3204
3288
 
3205
3289
  /**
3206
- * @@@
3290
+ * Converts a given text to kebab-case format.
3207
3291
  *
3208
- * @param text @@@
3209
- * @returns @@@
3292
+ * @param text The text to be converted.
3293
+ * @returns The kebab-case formatted string.
3210
3294
  * @example 'hello-world'
3211
3295
  * @example 'i-love-promptbook'
3212
3296
  * @public exported from `@promptbook/utils`
@@ -3275,7 +3359,8 @@ function knowledgeSourceContentToName(knowledgeSourceContent) {
3275
3359
  */
3276
3360
 
3277
3361
  /**
3278
- * @@@
3362
+ * Converts a name to a properly formatted subfolder path for cache storage.
3363
+ * Handles normalization and path formatting to create consistent cache directory structures.
3279
3364
  *
3280
3365
  * @private for `FileCacheStorage`
3281
3366
  */
@@ -3355,11 +3440,11 @@ function removeEmojis(text) {
3355
3440
  }
3356
3441
 
3357
3442
  /**
3358
- * @@@
3443
+ * Converts a title string into a normalized name.
3359
3444
  *
3360
- * @param value @@@
3361
- * @returns @@@
3362
- * @example @@@
3445
+ * @param value The title string to be converted to a name.
3446
+ * @returns A normalized name derived from the input title.
3447
+ * @example 'Hello World!' -> 'hello-world'
3363
3448
  * @public exported from `@promptbook/utils`
3364
3449
  */
3365
3450
  function titleToName(value) {
@@ -3410,7 +3495,9 @@ const promptbookFetch = async (urlOrRequest, init) => {
3410
3495
  */
3411
3496
 
3412
3497
  /**
3413
- * @@@
3498
+ * Factory function that creates a handler for processing knowledge sources.
3499
+ * Provides standardized processing of different types of knowledge sources
3500
+ * across various scraper implementations.
3414
3501
  *
3415
3502
  * @public exported from `@promptbook/core`
3416
3503
  */
@@ -3517,7 +3604,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
3517
3604
  > },
3518
3605
  */
3519
3606
  async asJson() {
3520
- return JSON.parse(await tools.fs.readFile(filename, 'utf-8'));
3607
+ return jsonParse(await tools.fs.readFile(filename, 'utf-8'));
3521
3608
  },
3522
3609
  async asText() {
3523
3610
  return await tools.fs.readFile(filename, 'utf-8');
@@ -3651,9 +3738,12 @@ TODO: [🧊] This is how it can look in future
3651
3738
  */
3652
3739
 
3653
3740
  /**
3654
- * @@@
3741
+ * Prepares tasks by adding knowledge to the prompt and ensuring all necessary parameters are included.
3655
3742
  *
3656
- * @public exported from `@promptbook/core`
3743
+ * @param tasks Sequence of tasks that are chained together to form a pipeline
3744
+ * @returns A promise that resolves to the prepared tasks.
3745
+ *
3746
+ * @private internal utility of `preparePipeline`
3657
3747
  */
3658
3748
  async function prepareTasks(pipeline, tools, options) {
3659
3749
  const { maxParallelCount = DEFAULT_MAX_PARALLEL_COUNT } = options;
@@ -3775,14 +3865,14 @@ async function preparePipeline(pipeline, tools, options) {
3775
3865
  // TODO: [🖌][🧠] Implement some `mapAsync` function
3776
3866
  const preparedPersonas = new Array(personas.length);
3777
3867
  await forEachAsync(personas, { maxParallelCount /* <- TODO: [🪂] When there are subtasks, this maximul limit can be broken */ }, async (persona, index) => {
3778
- const modelRequirements = await preparePersona(persona.description, { ...tools, llm: llmToolsWithUsage }, {
3868
+ const { modelsRequirements } = await preparePersona(persona.description, { ...tools, llm: llmToolsWithUsage }, {
3779
3869
  rootDirname,
3780
3870
  maxParallelCount /* <- TODO: [🪂] */,
3781
3871
  isVerbose,
3782
3872
  });
3783
3873
  const preparedPersona = {
3784
3874
  ...persona,
3785
- modelRequirements,
3875
+ modelsRequirements,
3786
3876
  preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id],
3787
3877
  // <- TODO: [🍙] Make some standard order of json properties
3788
3878
  };
@@ -4090,7 +4180,7 @@ function union(...sets) {
4090
4180
  }
4091
4181
 
4092
4182
  /**
4093
- * @@@
4183
+ * Contains configuration options for parsing and generating CSV files, such as delimiters and quoting rules.
4094
4184
  *
4095
4185
  * @public exported from `@promptbook/core`
4096
4186
  */
@@ -4099,11 +4189,29 @@ const MANDATORY_CSV_SETTINGS = Object.freeze({
4099
4189
  // encoding: 'utf-8',
4100
4190
  });
4101
4191
 
4192
+ /**
4193
+ * Converts a CSV string into an object
4194
+ *
4195
+ * Note: This is wrapper around `papaparse.parse()` with better autohealing
4196
+ *
4197
+ * @private - for now until `@promptbook/csv` is released
4198
+ */
4199
+ function csvParse(value /* <- TODO: string_csv */, settings, schema /* <- TODO: Make CSV Schemas */) {
4200
+ settings = { ...settings, ...MANDATORY_CSV_SETTINGS };
4201
+ // Note: Autoheal invalid '\n' characters
4202
+ if (settings.newline && !settings.newline.includes('\r') && value.includes('\r')) {
4203
+ console.warn('CSV string contains carriage return characters, but in the CSV settings the `newline` setting does not include them. Autohealing the CSV string.');
4204
+ value = value.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
4205
+ }
4206
+ const csv = parse(value, settings);
4207
+ return csv;
4208
+ }
4209
+
4102
4210
  /**
4103
4211
  * Function to check if a string is valid CSV
4104
4212
  *
4105
4213
  * @param value The string to check
4106
- * @returns True if the string is a valid CSV string, false otherwise
4214
+ * @returns `true` if the string is a valid CSV string, false otherwise
4107
4215
  *
4108
4216
  * @public exported from `@promptbook/utils`
4109
4217
  */
@@ -4127,7 +4235,7 @@ function isValidCsvString(value) {
4127
4235
  * @public exported from `@promptbook/core`
4128
4236
  * <- TODO: [🏢] Export from package `@promptbook/csv`
4129
4237
  */
4130
- const CsvFormatDefinition = {
4238
+ const CsvFormatParser = {
4131
4239
  formatName: 'CSV',
4132
4240
  aliases: ['SPREADSHEET', 'TABLE'],
4133
4241
  isValid(value, settings, schema) {
@@ -4139,12 +4247,12 @@ const CsvFormatDefinition = {
4139
4247
  heal(value, settings, schema) {
4140
4248
  throw new Error('Not implemented');
4141
4249
  },
4142
- subvalueDefinitions: [
4250
+ subvalueParsers: [
4143
4251
  {
4144
4252
  subvalueName: 'ROW',
4145
- async mapValues(value, outputParameterName, settings, mapCallback) {
4146
- // TODO: [👨🏾‍🤝‍👨🏼] DRY csv parsing
4147
- const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
4253
+ async mapValues(options) {
4254
+ const { value, outputParameterName, settings, mapCallback, onProgress } = options;
4255
+ const csv = csvParse(value, settings);
4148
4256
  if (csv.errors.length !== 0) {
4149
4257
  throw new CsvFormatError(spaceTrim((block) => `
4150
4258
  CSV parsing error
@@ -4159,23 +4267,37 @@ const CsvFormatDefinition = {
4159
4267
  ${block(value)}
4160
4268
  `));
4161
4269
  }
4162
- const mappedData = await Promise.all(csv.data.map(async (row, index) => {
4270
+ const mappedData = [];
4271
+ const length = csv.data.length;
4272
+ for (let index = 0; index < length; index++) {
4273
+ const row = csv.data[index];
4163
4274
  if (row[outputParameterName]) {
4164
4275
  throw new CsvFormatError(`Can not overwrite existing column "${outputParameterName}" in CSV row`);
4165
4276
  }
4166
- return {
4277
+ const mappedRow = {
4167
4278
  ...row,
4168
- [outputParameterName]: await mapCallback(row, index),
4279
+ [outputParameterName]: await mapCallback(row, index, length),
4169
4280
  };
4170
- }));
4281
+ mappedData.push(mappedRow);
4282
+ if (onProgress) {
4283
+ // Note: Report the CSV with all rows mapped so far
4284
+ /*
4285
+ // TODO: [🛕] Report progress with all the rows including the pending ones
4286
+ const progressData = mappedData.map((row, i) =>
4287
+ i > index ? { ...row, [outputParameterName]: PENDING_VALUE_PLACEHOLDER } : row,
4288
+ );
4289
+ */
4290
+ await onProgress(unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS }));
4291
+ }
4292
+ }
4171
4293
  return unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
4172
4294
  },
4173
4295
  },
4174
4296
  {
4175
4297
  subvalueName: 'CELL',
4176
- async mapValues(value, outputParameterName, settings, mapCallback) {
4177
- // TODO: [👨🏾‍🤝‍👨🏼] DRY csv parsing
4178
- const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
4298
+ async mapValues(options) {
4299
+ const { value, settings, mapCallback, onProgress } = options;
4300
+ const csv = csvParse(value, settings);
4179
4301
  if (csv.errors.length !== 0) {
4180
4302
  throw new CsvFormatError(spaceTrim((block) => `
4181
4303
  CSV parsing error
@@ -4191,9 +4313,9 @@ const CsvFormatDefinition = {
4191
4313
  `));
4192
4314
  }
4193
4315
  const mappedData = await Promise.all(csv.data.map(async (row, rowIndex) => {
4194
- return /* not await */ Promise.all(Object.entries(row).map(async ([key, value], columnIndex) => {
4316
+ return /* not await */ Promise.all(Object.entries(row).map(async ([key, value], columnIndex, array) => {
4195
4317
  const index = rowIndex * Object.keys(row).length + columnIndex;
4196
- return /* not await */ mapCallback({ [key]: value }, index);
4318
+ return /* not await */ mapCallback({ [key]: value }, index, array.length);
4197
4319
  }));
4198
4320
  }));
4199
4321
  return unparse(mappedData, { ...settings, ...MANDATORY_CSV_SETTINGS });
@@ -4202,10 +4324,10 @@ const CsvFormatDefinition = {
4202
4324
  ],
4203
4325
  };
4204
4326
  /**
4205
- * TODO: [🍓] In `CsvFormatDefinition` implement simple `isValid`
4206
- * TODO: [🍓] In `CsvFormatDefinition` implement partial `canBeValid`
4207
- * TODO: [🍓] In `CsvFormatDefinition` implement `heal
4208
- * TODO: [🍓] In `CsvFormatDefinition` implement `subvalueDefinitions`
4327
+ * TODO: [🍓] In `CsvFormatParser` implement simple `isValid`
4328
+ * TODO: [🍓] In `CsvFormatParser` implement partial `canBeValid`
4329
+ * TODO: [🍓] In `CsvFormatParser` implement `heal
4330
+ * TODO: [🍓] In `CsvFormatParser` implement `subvalueParsers`
4209
4331
  * TODO: [🏢] Allow to expect something inside CSV objects and other formats
4210
4332
  */
4211
4333
 
@@ -4214,7 +4336,7 @@ const CsvFormatDefinition = {
4214
4336
  *
4215
4337
  * @private still in development [🏢]
4216
4338
  */
4217
- const JsonFormatDefinition = {
4339
+ const JsonFormatParser = {
4218
4340
  formatName: 'JSON',
4219
4341
  mimeType: 'application/json',
4220
4342
  isValid(value, settings, schema) {
@@ -4226,28 +4348,28 @@ const JsonFormatDefinition = {
4226
4348
  heal(value, settings, schema) {
4227
4349
  throw new Error('Not implemented');
4228
4350
  },
4229
- subvalueDefinitions: [],
4351
+ subvalueParsers: [],
4230
4352
  };
4231
4353
  /**
4232
4354
  * TODO: [🧠] Maybe propper instance of object
4233
4355
  * TODO: [0] Make string_serialized_json
4234
4356
  * TODO: [1] Make type for JSON Settings and Schema
4235
4357
  * TODO: [🧠] What to use for validating JSONs - JSON Schema, ZoD, typescript types/interfaces,...?
4236
- * TODO: [🍓] In `JsonFormatDefinition` implement simple `isValid`
4237
- * TODO: [🍓] In `JsonFormatDefinition` implement partial `canBeValid`
4238
- * TODO: [🍓] In `JsonFormatDefinition` implement `heal
4239
- * TODO: [🍓] In `JsonFormatDefinition` implement `subvalueDefinitions`
4358
+ * TODO: [🍓] In `JsonFormatParser` implement simple `isValid`
4359
+ * TODO: [🍓] In `JsonFormatParser` implement partial `canBeValid`
4360
+ * TODO: [🍓] In `JsonFormatParser` implement `heal
4361
+ * TODO: [🍓] In `JsonFormatParser` implement `subvalueParsers`
4240
4362
  * TODO: [🏢] Allow to expect something inside JSON objects and other formats
4241
4363
  */
4242
4364
 
4243
4365
  /**
4244
4366
  * Definition for any text - this will be always valid
4245
4367
  *
4246
- * Note: This is not useful for validation, but for splitting and mapping with `subvalueDefinitions`
4368
+ * Note: This is not useful for validation, but for splitting and mapping with `subvalueParsers`
4247
4369
  *
4248
4370
  * @public exported from `@promptbook/core`
4249
4371
  */
4250
- const TextFormatDefinition = {
4372
+ const TextFormatParser = {
4251
4373
  formatName: 'TEXT',
4252
4374
  isValid(value) {
4253
4375
  return typeof value === 'string';
@@ -4256,19 +4378,20 @@ const TextFormatDefinition = {
4256
4378
  return typeof partialValue === 'string';
4257
4379
  },
4258
4380
  heal() {
4259
- throw new UnexpectedError('It does not make sense to call `TextFormatDefinition.heal`');
4381
+ throw new UnexpectedError('It does not make sense to call `TextFormatParser.heal`');
4260
4382
  },
4261
- subvalueDefinitions: [
4383
+ subvalueParsers: [
4262
4384
  {
4263
4385
  subvalueName: 'LINE',
4264
- async mapValues(value, outputParameterName, settings, mapCallback) {
4386
+ async mapValues(options) {
4387
+ const { value, mapCallback, onProgress } = options;
4265
4388
  const lines = value.split('\n');
4266
- const mappedLines = await Promise.all(lines.map((lineContent, lineNumber) =>
4389
+ const mappedLines = await Promise.all(lines.map((lineContent, lineNumber, array) =>
4267
4390
  // TODO: [🧠] Maybe option to skip empty line
4268
4391
  /* not await */ mapCallback({
4269
4392
  lineContent,
4270
4393
  // TODO: [🧠] Maybe also put here `lineNumber`
4271
- }, lineNumber)));
4394
+ }, lineNumber, array.length)));
4272
4395
  return mappedLines.join('\n');
4273
4396
  },
4274
4397
  },
@@ -4278,10 +4401,10 @@ const TextFormatDefinition = {
4278
4401
  /**
4279
4402
  * TODO: [1] Make type for XML Text and Schema
4280
4403
  * TODO: [🧠][🤠] Here should be all words, characters, lines, paragraphs, pages available as subvalues
4281
- * TODO: [🍓] In `TextFormatDefinition` implement simple `isValid`
4282
- * TODO: [🍓] In `TextFormatDefinition` implement partial `canBeValid`
4283
- * TODO: [🍓] In `TextFormatDefinition` implement `heal
4284
- * TODO: [🍓] In `TextFormatDefinition` implement `subvalueDefinitions`
4404
+ * TODO: [🍓] In `TextFormatParser` implement simple `isValid`
4405
+ * TODO: [🍓] In `TextFormatParser` implement partial `canBeValid`
4406
+ * TODO: [🍓] In `TextFormatParser` implement `heal
4407
+ * TODO: [🍓] In `TextFormatParser` implement `subvalueParsers`
4285
4408
  * TODO: [🏢] Allow to expect something inside each item of list and other formats
4286
4409
  */
4287
4410
 
@@ -4289,7 +4412,7 @@ const TextFormatDefinition = {
4289
4412
  * Function to check if a string is valid XML
4290
4413
  *
4291
4414
  * @param value
4292
- * @returns True if the string is a valid XML string, false otherwise
4415
+ * @returns `true` if the string is a valid XML string, false otherwise
4293
4416
  *
4294
4417
  * @public exported from `@promptbook/utils`
4295
4418
  */
@@ -4314,7 +4437,7 @@ function isValidXmlString(value) {
4314
4437
  *
4315
4438
  * @private still in development [🏢]
4316
4439
  */
4317
- const XmlFormatDefinition = {
4440
+ const XmlFormatParser = {
4318
4441
  formatName: 'XML',
4319
4442
  mimeType: 'application/xml',
4320
4443
  isValid(value, settings, schema) {
@@ -4326,17 +4449,17 @@ const XmlFormatDefinition = {
4326
4449
  heal(value, settings, schema) {
4327
4450
  throw new Error('Not implemented');
4328
4451
  },
4329
- subvalueDefinitions: [],
4452
+ subvalueParsers: [],
4330
4453
  };
4331
4454
  /**
4332
4455
  * TODO: [🧠] Maybe propper instance of object
4333
4456
  * TODO: [0] Make string_serialized_xml
4334
4457
  * TODO: [1] Make type for XML Settings and Schema
4335
4458
  * TODO: [🧠] What to use for validating XMLs - XSD,...
4336
- * TODO: [🍓] In `XmlFormatDefinition` implement simple `isValid`
4337
- * TODO: [🍓] In `XmlFormatDefinition` implement partial `canBeValid`
4338
- * TODO: [🍓] In `XmlFormatDefinition` implement `heal
4339
- * TODO: [🍓] In `XmlFormatDefinition` implement `subvalueDefinitions`
4459
+ * TODO: [🍓] In `XmlFormatParser` implement simple `isValid`
4460
+ * TODO: [🍓] In `XmlFormatParser` implement partial `canBeValid`
4461
+ * TODO: [🍓] In `XmlFormatParser` implement `heal
4462
+ * TODO: [🍓] In `XmlFormatParser` implement `subvalueParsers`
4340
4463
  * TODO: [🏢] Allow to expect something inside XML and other formats
4341
4464
  */
4342
4465
 
@@ -4345,24 +4468,19 @@ const XmlFormatDefinition = {
4345
4468
  *
4346
4469
  * @private internal index of `...` <- TODO [🏢]
4347
4470
  */
4348
- const FORMAT_DEFINITIONS = [
4349
- JsonFormatDefinition,
4350
- XmlFormatDefinition,
4351
- TextFormatDefinition,
4352
- CsvFormatDefinition,
4353
- ];
4471
+ const FORMAT_DEFINITIONS = [JsonFormatParser, XmlFormatParser, TextFormatParser, CsvFormatParser];
4354
4472
  /**
4355
4473
  * Note: [💞] Ignore a discrepancy between file name and entity name
4356
4474
  */
4357
4475
 
4358
4476
  /**
4359
- * Maps available parameters to expected parameters
4477
+ * Maps available parameters to expected parameters for a pipeline task.
4360
4478
  *
4361
4479
  * The strategy is:
4362
- * 1) @@@
4363
- * 2) @@@
4480
+ * 1) First, match parameters by name where both available and expected.
4481
+ * 2) Then, if there are unmatched expected and available parameters, map them by order.
4364
4482
  *
4365
- * @throws {PipelineExecutionError} @@@
4483
+ * @throws {PipelineExecutionError} If the number of unmatched expected and available parameters does not match, or mapping is ambiguous.
4366
4484
  * @private within the repository used in `createPipelineExecutor`
4367
4485
  */
4368
4486
  function mapAvailableToExpectedParameters(options) {
@@ -4385,7 +4503,7 @@ function mapAvailableToExpectedParameters(options) {
4385
4503
  else if (!availableParametersNames.has(parameterName) && expectedParameterNames.has(parameterName)) ;
4386
4504
  }
4387
4505
  if (expectedParameterNames.size === 0) {
4388
- // Note: [👨‍👨‍👧] Now we can freeze `mappedParameters` to prevent @@@
4506
+ // Note: [👨‍👨‍👧] Now we can freeze `mappedParameters` to prevent accidental modifications after mapping
4389
4507
  Object.freeze(mappedParameters);
4390
4508
  return mappedParameters;
4391
4509
  }
@@ -4416,7 +4534,7 @@ function mapAvailableToExpectedParameters(options) {
4416
4534
  for (let i = 0; i < expectedParameterNames.size; i++) {
4417
4535
  mappedParameters[expectedParameterNamesArray[i]] = availableParameters[availableParametersNamesArray[i]];
4418
4536
  }
4419
- // Note: [👨‍👨‍👧] Now we can freeze `mappedParameters` to prevent @@@
4537
+ // Note: [👨‍👨‍👧] Now we can freeze `mappedParameters` to prevent accidental modifications after mapping
4420
4538
  Object.freeze(mappedParameters);
4421
4539
  return mappedParameters;
4422
4540
  }
@@ -4461,10 +4579,12 @@ function templateParameters(template, parameters) {
4461
4579
  throw new PipelineExecutionError('Parameter is already opened or not closed');
4462
4580
  }
4463
4581
  if (parameters[parameterName] === undefined) {
4582
+ console.log('!!! templateParameters 1', { parameterName, template, parameters });
4464
4583
  throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4465
4584
  }
4466
4585
  let parameterValue = parameters[parameterName];
4467
4586
  if (parameterValue === undefined) {
4587
+ console.log('!!! templateParameters 2', { parameterName, template, parameters });
4468
4588
  throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4469
4589
  }
4470
4590
  parameterValue = valueToString(parameterValue);
@@ -4620,7 +4740,7 @@ const CountUtils = {
4620
4740
  PAGES: countPages,
4621
4741
  };
4622
4742
  /**
4623
- * TODO: [🧠][🤠] This should be probbably as part of `TextFormatDefinition`
4743
+ * TODO: [🧠][🤠] This should be probbably as part of `TextFormatParser`
4624
4744
  * Note: [💞] Ignore a discrepancy between file name and entity name
4625
4745
  */
4626
4746
 
@@ -4648,13 +4768,17 @@ function checkExpectations(expectations, value) {
4648
4768
  }
4649
4769
  /**
4650
4770
  * TODO: [💝] Unite object for expecting amount and format
4651
- * TODO: [🧠][🤠] This should be part of `TextFormatDefinition`
4771
+ * TODO: [🧠][🤠] This should be part of `TextFormatParser`
4652
4772
  * Note: [💝] and [🤠] are interconnected together
4653
4773
  */
4654
4774
 
4655
4775
  /**
4656
- * @@@
4776
+ * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
4777
+ * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
4778
+ * Throws errors if execution fails after all attempts.
4657
4779
  *
4780
+ * @param options - The options for execution, including task, parameters, pipeline, and configuration.
4781
+ * @returns The result string of the executed task.
4658
4782
  * @private internal utility of `createPipelineExecutor`
4659
4783
  */
4660
4784
  async function executeAttempts(options) {
@@ -4876,7 +5000,7 @@ async function executeAttempts(options) {
4876
5000
  if (task.format) {
4877
5001
  if (task.format === 'JSON') {
4878
5002
  if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
4879
- // TODO: [🏢] Do more universally via `FormatDefinition`
5003
+ // TODO: [🏢] Do more universally via `FormatParser`
4880
5004
  try {
4881
5005
  $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
4882
5006
  }
@@ -4978,12 +5102,16 @@ async function executeAttempts(options) {
4978
5102
  */
4979
5103
 
4980
5104
  /**
4981
- * @@@
5105
+ * Executes a pipeline task that requires mapping or iterating over subvalues of a parameter (such as rows in a CSV).
5106
+ * Handles format and subformat resolution, error handling, and progress reporting.
5107
+ *
5108
+ * @param options - Options for execution, including task details and progress callback.
5109
+ * @returns The result of the subvalue mapping or execution attempts.
4982
5110
  *
4983
5111
  * @private internal utility of `createPipelineExecutor`
4984
5112
  */
4985
5113
  async function executeFormatSubvalues(options) {
4986
- const { task, jokerParameterNames, parameters, priority, csvSettings, pipelineIdentification } = options;
5114
+ const { task, jokerParameterNames, parameters, priority, csvSettings, onProgress, pipelineIdentification } = options;
4987
5115
  if (task.foreach === undefined) {
4988
5116
  return /* not await */ executeAttempts(options);
4989
5117
  }
@@ -5014,16 +5142,16 @@ async function executeFormatSubvalues(options) {
5014
5142
  ${block(pipelineIdentification)}
5015
5143
  `));
5016
5144
  }
5017
- const subvalueDefinition = formatDefinition.subvalueDefinitions.find((subvalueDefinition) => [subvalueDefinition.subvalueName, ...(subvalueDefinition.aliases || [])].includes(task.foreach.subformatName));
5018
- if (subvalueDefinition === undefined) {
5145
+ const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(task.foreach.subformatName));
5146
+ if (subvalueParser === undefined) {
5019
5147
  throw new UnexpectedError(
5020
5148
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
5021
5149
  spaceTrim((block) => `
5022
5150
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
5023
5151
 
5024
5152
  Available subformat names for format "${formatDefinition.formatName}":
5025
- ${block(formatDefinition.subvalueDefinitions
5026
- .map((subvalueDefinition) => subvalueDefinition.subvalueName)
5153
+ ${block(formatDefinition.subvalueParsers
5154
+ .map((subvalueParser) => subvalueParser.subvalueName)
5027
5155
  .map((subvalueName) => `- ${subvalueName}`)
5028
5156
  .join('\n'))}
5029
5157
 
@@ -5037,53 +5165,83 @@ async function executeFormatSubvalues(options) {
5037
5165
  formatSettings = csvSettings;
5038
5166
  // <- TODO: [🤹‍♂️] More universal, make simmilar pattern for other formats for example \n vs \r\n in text
5039
5167
  }
5040
- const resultString = await subvalueDefinition.mapValues(parameterValue, task.foreach.outputSubparameterName, formatSettings, async (subparameters, index) => {
5041
- let mappedParameters;
5042
- // TODO: [🤹‍♂️][🪂] Limit to N concurrent executions
5043
- // TODO: When done [🐚] Report progress also for each subvalue here
5044
- try {
5045
- mappedParameters = mapAvailableToExpectedParameters({
5046
- expectedParameters: Object.fromEntries(task.foreach.inputSubparameterNames.map((subparameterName) => [subparameterName, null])),
5047
- availableParameters: subparameters,
5048
- });
5049
- }
5050
- catch (error) {
5051
- if (!(error instanceof PipelineExecutionError)) {
5052
- throw error;
5168
+ const resultString = await subvalueParser.mapValues({
5169
+ value: parameterValue,
5170
+ outputParameterName: task.foreach.outputSubparameterName,
5171
+ settings: formatSettings,
5172
+ onProgress(partialResultString) {
5173
+ return onProgress(Object.freeze({
5174
+ [task.resultingParameterName]: partialResultString,
5175
+ }));
5176
+ },
5177
+ async mapCallback(subparameters, index, length) {
5178
+ let mappedParameters;
5179
+ try {
5180
+ mappedParameters = mapAvailableToExpectedParameters({
5181
+ expectedParameters: Object.fromEntries(task.foreach.inputSubparameterNames.map((subparameterName) => [subparameterName, null])),
5182
+ availableParameters: subparameters,
5183
+ });
5053
5184
  }
5054
- throw new PipelineExecutionError(spaceTrim((block) => `
5055
- ${error.message}
5185
+ catch (error) {
5186
+ if (!(error instanceof PipelineExecutionError)) {
5187
+ throw error;
5188
+ }
5189
+ const highLevelError = new PipelineExecutionError(spaceTrim((block) => `
5190
+ ${error.message}
5056
5191
 
5057
- This is error in FOREACH command
5058
- You have probbably passed wrong data to pipeline or wrong data was generated which are processed by FOREACH command
5192
+ This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
5193
+ You have probbably passed wrong data to pipeline or wrong data was generated which are processed by FOREACH command
5059
5194
 
5060
- ${block(pipelineIdentification)}
5061
- Subparameter index: ${index}
5062
- `));
5063
- }
5064
- const allSubparameters = {
5065
- ...parameters,
5066
- ...mappedParameters,
5067
- };
5068
- // Note: [👨‍👨‍👧] Now we can freeze `subparameters` because we are sure that all and only used parameters are defined and are not going to be changed
5069
- Object.freeze(allSubparameters);
5070
- const subresultString = await executeAttempts({
5071
- ...options,
5072
- priority: priority + index,
5073
- parameters: allSubparameters,
5074
- pipelineIdentification: spaceTrim((block) => `
5075
- ${block(pipelineIdentification)}
5076
- Subparameter index: ${index}
5077
- `),
5078
- });
5079
- return subresultString;
5195
+ ${block(pipelineIdentification)}
5196
+ `));
5197
+ if (length > BIG_DATASET_TRESHOLD) {
5198
+ console.error(highLevelError);
5199
+ return FAILED_VALUE_PLACEHOLDER;
5200
+ }
5201
+ throw highLevelError;
5202
+ }
5203
+ const allSubparameters = {
5204
+ ...parameters,
5205
+ ...mappedParameters,
5206
+ };
5207
+ Object.freeze(allSubparameters);
5208
+ try {
5209
+ const subresultString = await executeAttempts({
5210
+ ...options,
5211
+ priority: priority + index,
5212
+ parameters: allSubparameters,
5213
+ pipelineIdentification: spaceTrim((block) => `
5214
+ ${block(pipelineIdentification)}
5215
+ Subparameter index: ${index}
5216
+ `),
5217
+ });
5218
+ return subresultString;
5219
+ }
5220
+ catch (error) {
5221
+ if (length > BIG_DATASET_TRESHOLD) {
5222
+ console.error(spaceTrim((block) => `
5223
+ ${error.message}
5224
+
5225
+ This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
5226
+
5227
+ ${block(pipelineIdentification)}
5228
+ `));
5229
+ return FAILED_VALUE_PLACEHOLDER;
5230
+ }
5231
+ throw error;
5232
+ }
5233
+ },
5080
5234
  });
5081
5235
  return resultString;
5082
5236
  }
5083
5237
 
5084
5238
  /**
5085
- * @@@
5239
+ * Returns the context for a given task, typically used to provide additional information or variables
5240
+ * required for the execution of the task within a pipeline. The context is returned as a string value
5241
+ * that may include markdown formatting.
5086
5242
  *
5243
+ * @param task - The task for which the context is being generated. This should be a deeply immutable TaskJson object.
5244
+ * @returns The context as a string, formatted as markdown and parameter value.
5087
5245
  * @private internal utility of `createPipelineExecutor`
5088
5246
  */
5089
5247
  async function getContextForTask(task) {
@@ -5091,7 +5249,7 @@ async function getContextForTask(task) {
5091
5249
  }
5092
5250
 
5093
5251
  /**
5094
- * @@@
5252
+ * Retrieves example values or templates for a given task, used to guide or validate pipeline execution.
5095
5253
  *
5096
5254
  * @private internal utility of `createPipelineExecutor`
5097
5255
  */
@@ -5100,25 +5258,127 @@ async function getExamplesForTask(task) {
5100
5258
  }
5101
5259
 
5102
5260
  /**
5103
- * @@@
5261
+ * Computes the cosine similarity between two embedding vectors
5262
+ *
5263
+ * Note: This is helping function for RAG (retrieval-augmented generation)
5264
+ *
5265
+ * @param embeddingVector1
5266
+ * @param embeddingVector2
5267
+ * @returns Cosine similarity between the two vectors
5268
+ *
5269
+ * @public exported from `@promptbook/core`
5270
+ */
5271
+ function computeCosineSimilarity(embeddingVector1, embeddingVector2) {
5272
+ if (embeddingVector1.length !== embeddingVector2.length) {
5273
+ throw new TypeError('Embedding vectors must have the same length');
5274
+ }
5275
+ const dotProduct = embeddingVector1.reduce((sum, value, index) => sum + value * embeddingVector2[index], 0);
5276
+ const magnitude1 = Math.sqrt(embeddingVector1.reduce((sum, value) => sum + value * value, 0));
5277
+ const magnitude2 = Math.sqrt(embeddingVector2.reduce((sum, value) => sum + value * value, 0));
5278
+ return 1 - dotProduct / (magnitude1 * magnitude2);
5279
+ }
5280
+
5281
+ /**
5282
+ *
5283
+ * @param knowledgePieces
5284
+ * @returns
5285
+ *
5286
+ * @private internal utility of `createPipelineExecutor`
5287
+ */
5288
+ function knowledgePiecesToString(knowledgePieces) {
5289
+ return knowledgePieces
5290
+ .map((knowledgePiece) => {
5291
+ const { content } = knowledgePiece;
5292
+ return `- ${content}`;
5293
+ })
5294
+ .join('\n');
5295
+ // <- TODO: [🧠] Some smarter aggregation of knowledge pieces, single-line vs multi-line vs mixed
5296
+ }
5297
+
5298
+ /**
5299
+ * Retrieves the most relevant knowledge pieces for a given task using embedding-based similarity search.
5300
+ * This is where retrieval-augmented generation (RAG) is performed to enhance the task with external knowledge.
5104
5301
  *
5105
5302
  * @private internal utility of `createPipelineExecutor`
5106
5303
  */
5107
5304
  async function getKnowledgeForTask(options) {
5108
- const { preparedPipeline, task } = options;
5109
- return preparedPipeline.knowledgePieces.map(({ content }) => `- ${content}`).join('\n');
5110
- // <- TODO: [🧠] Some smart aggregation of knowledge pieces, single-line vs multi-line vs mixed
5305
+ const { tools, preparedPipeline, task, parameters } = options;
5306
+ const firstKnowlegePiece = preparedPipeline.knowledgePieces[0];
5307
+ const firstKnowlegeIndex = firstKnowlegePiece === null || firstKnowlegePiece === void 0 ? void 0 : firstKnowlegePiece.index[0];
5308
+ // <- TODO: Do not use just first knowledge piece and first index to determine embedding model, use also keyword search
5309
+ if (firstKnowlegePiece === undefined || firstKnowlegeIndex === undefined) {
5310
+ return ''; // <- Note: Np knowledge present, return empty string
5311
+ }
5312
+ try {
5313
+ // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
5314
+ const _llms = arrayableToArray(tools.llm);
5315
+ const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
5316
+ const taskEmbeddingPrompt = {
5317
+ title: 'Knowledge Search',
5318
+ modelRequirements: {
5319
+ modelVariant: 'EMBEDDING',
5320
+ modelName: firstKnowlegeIndex.modelName,
5321
+ },
5322
+ content: task.content,
5323
+ parameters,
5324
+ };
5325
+ const taskEmbeddingResult = await llmTools.callEmbeddingModel(taskEmbeddingPrompt);
5326
+ const knowledgePiecesWithRelevance = preparedPipeline.knowledgePieces.map((knowledgePiece) => {
5327
+ const { index } = knowledgePiece;
5328
+ const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowlegeIndex.modelName);
5329
+ // <- TODO: Do not use just first knowledge piece and first index to determine embedding model
5330
+ if (knowledgePieceIndex === undefined) {
5331
+ return {
5332
+ content: knowledgePiece.content,
5333
+ relevance: 0,
5334
+ };
5335
+ }
5336
+ const relevance = computeCosineSimilarity(knowledgePieceIndex.position, taskEmbeddingResult.content);
5337
+ return {
5338
+ content: knowledgePiece.content,
5339
+ relevance,
5340
+ };
5341
+ });
5342
+ const knowledgePiecesSorted = knowledgePiecesWithRelevance.sort((a, b) => a.relevance - b.relevance);
5343
+ const knowledgePiecesLimited = knowledgePiecesSorted.slice(0, 5);
5344
+ console.log('!!! Embedding', {
5345
+ task,
5346
+ taskEmbeddingPrompt,
5347
+ taskEmbeddingResult,
5348
+ firstKnowlegePiece,
5349
+ firstKnowlegeIndex,
5350
+ knowledgePiecesWithRelevance,
5351
+ knowledgePiecesSorted,
5352
+ knowledgePiecesLimited,
5353
+ });
5354
+ return knowledgePiecesToString(knowledgePiecesLimited);
5355
+ }
5356
+ catch (error) {
5357
+ assertsError(error);
5358
+ console.error('Error in `getKnowledgeForTask`', error);
5359
+ // Note: If the LLM fails, just return all knowledge pieces
5360
+ return knowledgePiecesToString(preparedPipeline.knowledgePieces);
5361
+ }
5111
5362
  }
5363
+ /**
5364
+ * TODO: !!!! Verify if this is working
5365
+ * TODO: [♨] Implement Better - use keyword search
5366
+ * TODO: [♨] Examples of values
5367
+ */
5112
5368
 
5113
5369
  /**
5114
- * @@@
5370
+ * Retrieves all reserved parameters for a given pipeline task, including context, knowledge, examples, and metadata.
5371
+ * Ensures all reserved parameters are defined and throws if any are missing.
5372
+ *
5373
+ * @param options - Options including tools, pipeline, task, and context.
5374
+ * @returns An object containing all reserved parameters for the task.
5115
5375
  *
5116
5376
  * @private internal utility of `createPipelineExecutor`
5117
5377
  */
5118
5378
  async function getReservedParametersForTask(options) {
5119
- const { preparedPipeline, task, pipelineIdentification } = options;
5379
+ const { tools, preparedPipeline, task, parameters, pipelineIdentification } = options;
5120
5380
  const context = await getContextForTask(); // <- [🏍]
5121
- const knowledge = await getKnowledgeForTask({ preparedPipeline, task });
5381
+ const knowledge = await getKnowledgeForTask({ tools, preparedPipeline, task, parameters });
5122
5382
  const examples = await getExamplesForTask();
5123
5383
  const currentDate = new Date().toISOString(); // <- TODO: [🧠][💩] Better
5124
5384
  const modelName = RESERVED_PARAMETER_MISSING_VALUE;
@@ -5144,23 +5404,21 @@ async function getReservedParametersForTask(options) {
5144
5404
  }
5145
5405
 
5146
5406
  /**
5147
- * @@@
5407
+ * Executes a single task within a pipeline, handling parameter validation, error checking, and progress reporting.
5408
+ *
5409
+ * @param options - Options for execution, including the task, pipeline, parameters, and callbacks.
5410
+ * @returns The output parameters produced by the task.
5148
5411
  *
5149
5412
  * @private internal utility of `createPipelineExecutor`
5150
5413
  */
5151
5414
  async function executeTask(options) {
5152
5415
  const { currentTask, preparedPipeline, parametersToPass, tools, onProgress, $executionReport, pipelineIdentification, maxExecutionAttempts, maxParallelCount, csvSettings, isVerbose, rootDirname, cacheDirname, intermediateFilesStrategy, isAutoInstalled, isNotPreparedWarningSupressed, } = options;
5153
5416
  const priority = preparedPipeline.tasks.length - preparedPipeline.tasks.indexOf(currentTask);
5154
- await onProgress({
5155
- outputParameters: {
5156
- [currentTask.resultingParameterName]: '', // <- TODO: [🧠] What is the best value here?
5157
- },
5158
- });
5159
5417
  // Note: Check consistency of used and dependent parameters which was also done in `validatePipeline`, but it’s good to doublecheck
5160
5418
  const usedParameterNames = extractParameterNamesFromTask(currentTask);
5161
5419
  const dependentParameterNames = new Set(currentTask.dependentParameterNames);
5162
5420
  // TODO: [👩🏾‍🤝‍👩🏻] Use here `mapAvailableToExpectedParameters`
5163
- if (union(difference(usedParameterNames, dependentParameterNames), difference(dependentParameterNames, usedParameterNames)).size !== 0) {
5421
+ if (difference(union(difference(usedParameterNames, dependentParameterNames), difference(dependentParameterNames, usedParameterNames)), new Set(RESERVED_PARAMETER_NAMES)).size !== 0) {
5164
5422
  throw new UnexpectedError(spaceTrim$1((block) => `
5165
5423
  Dependent parameters are not consistent with used parameters:
5166
5424
 
@@ -5180,9 +5438,11 @@ async function executeTask(options) {
5180
5438
  }
5181
5439
  const definedParameters = Object.freeze({
5182
5440
  ...(await getReservedParametersForTask({
5441
+ tools,
5183
5442
  preparedPipeline,
5184
5443
  task: currentTask,
5185
5444
  pipelineIdentification,
5445
+ parameters: parametersToPass,
5186
5446
  })),
5187
5447
  ...parametersToPass,
5188
5448
  });
@@ -5228,6 +5488,7 @@ async function executeTask(options) {
5228
5488
  preparedPipeline,
5229
5489
  tools,
5230
5490
  $executionReport,
5491
+ onProgress,
5231
5492
  pipelineIdentification,
5232
5493
  maxExecutionAttempts,
5233
5494
  maxParallelCount,
@@ -5255,7 +5516,8 @@ async function executeTask(options) {
5255
5516
  */
5256
5517
 
5257
5518
  /**
5258
- * @@@
5519
+ * Filters and returns only the output parameters from the provided pipeline execution options.
5520
+ * Adds warnings for any expected output parameters that are missing.
5259
5521
  *
5260
5522
  * @private internal utility of `createPipelineExecutor`
5261
5523
  */
@@ -5280,9 +5542,12 @@ function filterJustOutputParameters(options) {
5280
5542
  }
5281
5543
 
5282
5544
  /**
5283
- * @@@
5545
+ * Executes an entire pipeline, resolving tasks in dependency order, handling errors, and reporting progress.
5284
5546
  *
5285
- * Note: This is not a `PipelineExecutor` (which is binded with one exact pipeline), but a utility function of `createPipelineExecutor` which creates `PipelineExecutor`
5547
+ * Note: This is not a `PipelineExecutor` (which is bound to a single pipeline), but a utility function used by `createPipelineExecutor` to create a `PipelineExecutor`.
5548
+ *
5549
+ * @param options - Options for execution, including input parameters, pipeline, and callbacks.
5550
+ * @returns The result of the pipeline execution, including output parameters, errors, and usage statistics.
5286
5551
  *
5287
5552
  * @private internal utility of `createPipelineExecutor`
5288
5553
  */
@@ -5605,6 +5870,22 @@ function createPipelineExecutor(options) {
5605
5870
  cacheDirname,
5606
5871
  intermediateFilesStrategy,
5607
5872
  isAutoInstalled,
5873
+ }).catch((error) => {
5874
+ assertsError(error);
5875
+ return exportJson({
5876
+ name: 'pipelineExecutorResult',
5877
+ message: `Unuccessful PipelineExecutorResult, last catch`,
5878
+ order: [],
5879
+ value: {
5880
+ isSuccessful: false,
5881
+ errors: [serializeError(error)],
5882
+ warnings: [],
5883
+ usage: UNCERTAIN_USAGE,
5884
+ executionReport: null,
5885
+ outputParameters: {},
5886
+ preparedPipeline,
5887
+ },
5888
+ });
5608
5889
  });
5609
5890
  };
5610
5891
  const pipelineExecutor = (inputParameters) => createTask({
@@ -5786,7 +6067,7 @@ class MarkdownScraper {
5786
6067
  */
5787
6068
 
5788
6069
  /**
5789
- * @@@
6070
+ * Creates a scraper for markdown content.
5790
6071
  *
5791
6072
  * @public exported from `@promptbook/markdown-utils`
5792
6073
  */
@@ -5941,7 +6222,7 @@ function escapeMarkdownBlock(value) {
5941
6222
  * Note: It can not work with html syntax and comments
5942
6223
  *
5943
6224
  * @param markdown any valid markdown
5944
- * @returns @@@
6225
+ * @returns An array of strings, each representing an individual list item found in the markdown
5945
6226
  * @public exported from `@promptbook/markdown-utils`
5946
6227
  */
5947
6228
  function extractAllListItemsFromMarkdown(markdown) {