@promptbook/utils 0.92.0-9 → 0.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.md +143 -91
  2. package/esm/index.es.js +864 -827
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/browser.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/core.index.d.ts +26 -14
  6. package/esm/typings/src/_packages/types.index.d.ts +6 -2
  7. package/esm/typings/src/collection/PipelineCollection.d.ts +0 -2
  8. package/esm/typings/src/collection/SimplePipelineCollection.d.ts +1 -1
  9. package/esm/typings/src/commands/FOREACH/ForeachJson.d.ts +6 -6
  10. package/esm/typings/src/commands/FOREACH/foreachCommandParser.d.ts +0 -2
  11. package/esm/typings/src/commands/FORMFACTOR/formfactorCommandParser.d.ts +1 -1
  12. package/esm/typings/src/commands/_BOILERPLATE/boilerplateCommandParser.d.ts +1 -1
  13. package/esm/typings/src/commands/_common/types/CommandParser.d.ts +36 -28
  14. package/esm/typings/src/config.d.ts +41 -11
  15. package/esm/typings/src/constants.d.ts +43 -2
  16. package/esm/typings/src/conversion/parsePipeline.d.ts +2 -2
  17. package/esm/typings/src/errors/0-BoilerplateError.d.ts +2 -2
  18. package/esm/typings/src/errors/CollectionError.d.ts +1 -1
  19. package/esm/typings/src/executables/$provideExecutablesForNode.d.ts +1 -1
  20. package/esm/typings/src/executables/apps/locateLibreoffice.d.ts +2 -1
  21. package/esm/typings/src/executables/apps/locatePandoc.d.ts +2 -1
  22. package/esm/typings/src/executables/locateApp.d.ts +2 -2
  23. package/esm/typings/src/executables/platforms/locateAppOnLinux.d.ts +2 -1
  24. package/esm/typings/src/executables/platforms/locateAppOnMacOs.d.ts +2 -1
  25. package/esm/typings/src/executables/platforms/locateAppOnWindows.d.ts +2 -1
  26. package/esm/typings/src/execution/AbstractTaskResult.d.ts +1 -1
  27. package/esm/typings/src/execution/CommonToolsOptions.d.ts +3 -3
  28. package/esm/typings/src/execution/ExecutionTask.d.ts +19 -1
  29. package/esm/typings/src/execution/LlmExecutionToolsConstructor.d.ts +2 -1
  30. package/esm/typings/src/execution/PipelineExecutorResult.d.ts +4 -2
  31. package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
  32. package/esm/typings/src/execution/ScriptExecutionTools.d.ts +1 -1
  33. package/esm/typings/src/execution/createPipelineExecutor/$OngoingTaskResult.d.ts +12 -9
  34. package/esm/typings/src/execution/createPipelineExecutor/10-executePipeline.d.ts +13 -10
  35. package/esm/typings/src/execution/createPipelineExecutor/20-executeTask.d.ts +12 -9
  36. package/esm/typings/src/execution/createPipelineExecutor/30-executeFormatSubvalues.d.ts +15 -3
  37. package/esm/typings/src/execution/createPipelineExecutor/40-executeAttempts.d.ts +21 -15
  38. package/esm/typings/src/execution/createPipelineExecutor/computeCosineSimilarity.d.ts +13 -0
  39. package/esm/typings/src/execution/createPipelineExecutor/filterJustOutputParameters.d.ts +7 -6
  40. package/esm/typings/src/execution/createPipelineExecutor/getContextForTask.d.ts +5 -1
  41. package/esm/typings/src/execution/createPipelineExecutor/getExamplesForTask.d.ts +1 -1
  42. package/esm/typings/src/execution/createPipelineExecutor/getKnowledgeForTask.d.ts +12 -9
  43. package/esm/typings/src/execution/createPipelineExecutor/getReservedParametersForTask.d.ts +18 -5
  44. package/esm/typings/src/execution/createPipelineExecutor/knowledgePiecesToString.d.ts +9 -0
  45. package/esm/typings/src/execution/execution-report/ExecutionReportJson.d.ts +1 -1
  46. package/esm/typings/src/execution/execution-report/ExecutionReportString.d.ts +1 -1
  47. package/esm/typings/src/execution/translation/automatic-translate/automatic-translators/LindatAutomaticTranslator.d.ts +4 -4
  48. package/esm/typings/src/execution/utils/checkExpectations.d.ts +3 -3
  49. package/esm/typings/src/execution/utils/uncertainNumber.d.ts +3 -2
  50. package/esm/typings/src/execution/utils/usageToWorktime.d.ts +1 -1
  51. package/esm/typings/src/formats/_common/{FormatDefinition.d.ts → FormatParser.d.ts} +8 -6
  52. package/esm/typings/src/formats/_common/FormatSubvalueParser.d.ts +66 -0
  53. package/esm/typings/src/formats/csv/CsvFormatParser.d.ts +17 -0
  54. package/esm/typings/src/formats/csv/CsvSettings.d.ts +2 -2
  55. package/esm/typings/src/formats/csv/utils/csvParse.d.ts +12 -0
  56. package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +1 -1
  57. package/esm/typings/src/formats/index.d.ts +2 -2
  58. package/esm/typings/src/formats/json/JsonFormatParser.d.ts +19 -0
  59. package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +1 -1
  60. package/esm/typings/src/formats/json/utils/jsonParse.d.ts +0 -3
  61. package/esm/typings/src/formats/text/{TextFormatDefinition.d.ts → TextFormatParser.d.ts} +7 -7
  62. package/esm/typings/src/formats/xml/XmlFormatParser.d.ts +19 -0
  63. package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +1 -1
  64. package/esm/typings/src/formfactors/_boilerplate/BoilerplateFormfactorDefinition.d.ts +3 -2
  65. package/esm/typings/src/formfactors/_common/AbstractFormfactorDefinition.d.ts +16 -7
  66. package/esm/typings/src/formfactors/_common/FormfactorDefinition.d.ts +3 -1
  67. package/esm/typings/src/formfactors/_common/string_formfactor_name.d.ts +2 -1
  68. package/esm/typings/src/formfactors/chatbot/ChatbotFormfactorDefinition.d.ts +2 -2
  69. package/esm/typings/src/formfactors/completion/CompletionFormfactorDefinition.d.ts +29 -0
  70. package/esm/typings/src/formfactors/generator/GeneratorFormfactorDefinition.d.ts +2 -1
  71. package/esm/typings/src/formfactors/generic/GenericFormfactorDefinition.d.ts +2 -2
  72. package/esm/typings/src/formfactors/index.d.ts +33 -8
  73. package/esm/typings/src/formfactors/matcher/MatcherFormfactorDefinition.d.ts +4 -2
  74. package/esm/typings/src/formfactors/sheets/SheetsFormfactorDefinition.d.ts +3 -2
  75. package/esm/typings/src/formfactors/translator/TranslatorFormfactorDefinition.d.ts +3 -2
  76. package/esm/typings/src/high-level-abstractions/index.d.ts +2 -2
  77. package/esm/typings/src/llm-providers/_common/register/$llmToolsMetadataRegister.d.ts +3 -3
  78. package/esm/typings/src/llm-providers/_common/register/$llmToolsRegister.d.ts +3 -3
  79. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +4 -4
  80. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +4 -3
  81. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +18 -5
  82. package/esm/typings/src/llm-providers/_common/register/LlmToolsConfiguration.d.ts +11 -4
  83. package/esm/typings/src/llm-providers/_common/register/LlmToolsMetadata.d.ts +21 -42
  84. package/esm/typings/src/llm-providers/_common/register/LlmToolsOptions.d.ts +9 -2
  85. package/esm/typings/src/llm-providers/_common/register/createLlmToolsFromConfiguration.d.ts +13 -4
  86. package/esm/typings/src/llm-providers/_common/utils/cache/CacheItem.d.ts +10 -5
  87. package/esm/typings/src/llm-providers/_common/utils/cache/CacheLlmToolsOptions.d.ts +11 -3
  88. package/esm/typings/src/llm-providers/_common/utils/cache/cacheLlmTools.d.ts +3 -3
  89. package/esm/typings/src/llm-providers/_common/utils/count-total-usage/limitTotalUsage.d.ts +5 -5
  90. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +6 -0
  91. package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  92. package/esm/typings/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +1 -1
  93. package/esm/typings/src/llm-providers/azure-openai/AzureOpenAiExecutionToolsOptions.d.ts +4 -4
  94. package/esm/typings/src/llm-providers/deepseek/deepseek-models.d.ts +1 -1
  95. package/esm/typings/src/llm-providers/google/google-models.d.ts +1 -1
  96. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +1 -1
  97. package/esm/typings/src/llm-providers/openai/openai-models.d.ts +1 -1
  98. package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +2 -2
  99. package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +2 -2
  100. package/esm/typings/src/migrations/migratePipeline.d.ts +9 -0
  101. package/esm/typings/src/other/templates/getBookTemplates.d.ts +2 -2
  102. package/esm/typings/src/pipeline/PipelineInterface/PipelineInterface.d.ts +3 -3
  103. package/esm/typings/src/pipeline/PipelineInterface/constants.d.ts +1 -1
  104. package/esm/typings/src/pipeline/PipelineInterface/getPipelineInterface.d.ts +1 -1
  105. package/esm/typings/src/pipeline/PipelineInterface/isPipelineImplementingInterface.d.ts +5 -4
  106. package/esm/typings/src/pipeline/PipelineInterface/isPipelineInterfacesEqual.d.ts +1 -1
  107. package/esm/typings/src/pipeline/PipelineJson/CommonTaskJson.d.ts +10 -7
  108. package/esm/typings/src/pipeline/PipelineJson/ParameterJson.d.ts +1 -1
  109. package/esm/typings/src/pipeline/PipelineJson/PipelineJson.d.ts +3 -2
  110. package/esm/typings/src/pipeline/PipelineString.d.ts +3 -1
  111. package/esm/typings/src/pipeline/book-notation.d.ts +2 -2
  112. package/esm/typings/src/postprocessing/utils/extractBlock.d.ts +1 -1
  113. package/esm/typings/src/postprocessing/utils/extractJsonBlock.d.ts +2 -2
  114. package/esm/typings/src/prepare/prepareTasks.d.ts +8 -5
  115. package/esm/typings/src/remote-server/openapi.d.ts +1 -1
  116. package/esm/typings/src/remote-server/socket-types/listModels/PromptbookServer_ListModels_Response.d.ts +1 -1
  117. package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -1
  118. package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +7 -6
  119. package/esm/typings/src/scrapers/_boilerplate/BoilerplateScraper.d.ts +3 -3
  120. package/esm/typings/src/scrapers/_boilerplate/createBoilerplateScraper.d.ts +1 -1
  121. package/esm/typings/src/scrapers/_boilerplate/register-metadata.d.ts +1 -1
  122. package/esm/typings/src/scrapers/_common/Converter.d.ts +3 -1
  123. package/esm/typings/src/scrapers/_common/Scraper.d.ts +4 -3
  124. package/esm/typings/src/scrapers/_common/ScraperIntermediateSource.d.ts +4 -2
  125. package/esm/typings/src/scrapers/_common/prepareKnowledgePieces.d.ts +2 -2
  126. package/esm/typings/src/scrapers/_common/register/$provideFilesystemForNode.d.ts +2 -1
  127. package/esm/typings/src/scrapers/_common/register/$provideScrapersForBrowser.d.ts +6 -3
  128. package/esm/typings/src/scrapers/_common/register/$provideScrapersForNode.d.ts +3 -5
  129. package/esm/typings/src/scrapers/_common/register/$scrapersMetadataRegister.d.ts +3 -3
  130. package/esm/typings/src/scrapers/_common/register/$scrapersRegister.d.ts +3 -2
  131. package/esm/typings/src/scrapers/_common/register/ScraperAndConverterMetadata.d.ts +8 -5
  132. package/esm/typings/src/scrapers/_common/register/ScraperConstructor.d.ts +2 -1
  133. package/esm/typings/src/scrapers/_common/utils/getScraperIntermediateSource.d.ts +6 -5
  134. package/esm/typings/src/scrapers/_common/utils/makeKnowledgeSourceHandler.d.ts +3 -1
  135. package/esm/typings/src/scrapers/document/createDocumentScraper.d.ts +1 -1
  136. package/esm/typings/src/scrapers/document-legacy/createLegacyDocumentScraper.d.ts +2 -1
  137. package/esm/typings/src/scrapers/markdown/createMarkdownScraper.d.ts +4 -1
  138. package/esm/typings/src/scrapers/markitdown/MarkitdownScraper.d.ts +1 -1
  139. package/esm/typings/src/scrapers/pdf/createPdfScraper.d.ts +2 -1
  140. package/esm/typings/src/scrapers/website/createWebsiteScraper.d.ts +3 -4
  141. package/esm/typings/src/scripting/javascript/JavascriptExecutionTools.d.ts +1 -1
  142. package/esm/typings/src/scripting/javascript/postprocessing-functions.d.ts +5 -1
  143. package/esm/typings/src/scripting/javascript/utils/preserve.d.ts +1 -1
  144. package/esm/typings/src/storage/_common/PromptbookStorage.d.ts +1 -1
  145. package/esm/typings/src/storage/file-cache-storage/FileCacheStorage.d.ts +12 -5
  146. package/esm/typings/src/storage/file-cache-storage/FileCacheStorageOptions.d.ts +4 -2
  147. package/esm/typings/src/storage/file-cache-storage/utils/nameToSubfolderPath.d.ts +2 -1
  148. package/esm/typings/src/storage/local-storage/getIndexedDbStorage.d.ts +11 -0
  149. package/esm/typings/src/storage/local-storage/utils/IndexedDbStorageOptions.d.ts +14 -0
  150. package/esm/typings/src/storage/local-storage/utils/makePromptbookStorageFromIndexedDb.d.ts +8 -0
  151. package/esm/typings/src/storage/local-storage/utils/makePromptbookStorageFromWebStorage.d.ts +2 -1
  152. package/esm/typings/src/types/IntermediateFilesStrategy.d.ts +2 -1
  153. package/esm/typings/src/types/ModelRequirements.d.ts +2 -2
  154. package/esm/typings/src/types/ModelVariant.d.ts +5 -5
  155. package/esm/typings/src/types/typeAliases.d.ts +22 -19
  156. package/esm/typings/src/utils/$Register.d.ts +8 -7
  157. package/esm/typings/src/utils/editable/edit-pipeline-string/addPipelineCommand.d.ts +2 -2
  158. package/esm/typings/src/utils/editable/edit-pipeline-string/deflatePipeline.d.ts +4 -1
  159. package/esm/typings/src/utils/editable/utils/isFlatPipeline.d.ts +2 -1
  160. package/esm/typings/src/utils/editable/utils/stringifyPipelineJson.d.ts +1 -1
  161. package/esm/typings/src/utils/environment/$getGlobalScope.d.ts +2 -1
  162. package/esm/typings/src/utils/expectation-counters/index.d.ts +1 -1
  163. package/esm/typings/src/utils/markdown/extractAllBlocksFromMarkdown.d.ts +2 -2
  164. package/esm/typings/src/utils/markdown/extractAllListItemsFromMarkdown.d.ts +1 -1
  165. package/esm/typings/src/utils/markdown/extractOneBlockFromMarkdown.d.ts +2 -2
  166. package/esm/typings/src/utils/normalization/nameToUriPart.d.ts +4 -4
  167. package/esm/typings/src/utils/normalization/nameToUriParts.d.ts +4 -4
  168. package/esm/typings/src/utils/normalization/normalize-to-kebab-case.d.ts +3 -3
  169. package/esm/typings/src/utils/normalization/normalizeTo_SCREAMING_CASE.d.ts +3 -3
  170. package/esm/typings/src/utils/normalization/normalizeTo_camelCase.d.ts +4 -4
  171. package/esm/typings/src/utils/normalization/normalizeTo_snake_case.d.ts +3 -3
  172. package/esm/typings/src/utils/normalization/removeDiacritics.d.ts +3 -3
  173. package/esm/typings/src/utils/normalization/searchKeywords.d.ts +4 -1
  174. package/esm/typings/src/utils/normalization/titleToName.d.ts +4 -4
  175. package/esm/typings/src/utils/organization/TODO_USE.d.ts +1 -1
  176. package/esm/typings/src/utils/organization/empty_object.d.ts +2 -2
  177. package/esm/typings/src/utils/organization/just.d.ts +1 -1
  178. package/esm/typings/src/utils/organization/just_empty_object.d.ts +4 -4
  179. package/esm/typings/src/utils/organization/keepUnused.d.ts +1 -1
  180. package/esm/typings/src/utils/parameters/mapAvailableToExpectedParameters.d.ts +7 -7
  181. package/esm/typings/src/utils/removeQuotes.d.ts +2 -2
  182. package/esm/typings/src/utils/serialization/clonePipeline.d.ts +4 -3
  183. package/esm/typings/src/utils/serialization/deepClone.d.ts +5 -1
  184. package/esm/typings/src/utils/trimCodeBlock.d.ts +1 -1
  185. package/esm/typings/src/utils/trimEndOfCodeBlock.d.ts +1 -1
  186. package/esm/typings/src/utils/unwrapResult.d.ts +2 -2
  187. package/esm/typings/src/utils/validators/javascriptName/isValidJavascriptName.d.ts +3 -3
  188. package/esm/typings/src/utils/validators/parameterName/validateParameterName.d.ts +5 -4
  189. package/esm/typings/src/utils/validators/semanticVersion/isValidPromptbookVersion.d.ts +1 -1
  190. package/esm/typings/src/utils/validators/semanticVersion/isValidSemanticVersion.d.ts +1 -1
  191. package/esm/typings/src/utils/validators/url/isHostnameOnPrivateNetwork.d.ts +1 -1
  192. package/esm/typings/src/utils/validators/url/isUrlOnPrivateNetwork.d.ts +1 -1
  193. package/esm/typings/src/utils/validators/url/isValidPipelineUrl.d.ts +1 -1
  194. package/esm/typings/src/utils/validators/url/isValidUrl.d.ts +1 -1
  195. package/esm/typings/src/version.d.ts +2 -1
  196. package/esm/typings/src/wizzard/wizzard.d.ts +1 -1
  197. package/package.json +14 -2
  198. package/umd/index.umd.js +871 -834
  199. package/umd/index.umd.js.map +1 -1
  200. package/esm/typings/src/formats/_common/FormatSubvalueDefinition.d.ts +0 -31
  201. package/esm/typings/src/formats/csv/CsvFormatDefinition.d.ts +0 -17
  202. package/esm/typings/src/formats/json/JsonFormatDefinition.d.ts +0 -19
  203. package/esm/typings/src/formats/xml/XmlFormatDefinition.d.ts +0 -19
  204. /package/esm/typings/src/llm-providers/{multiple → _multiple}/MultipleLlmExecutionTools.d.ts +0 -0
  205. /package/esm/typings/src/llm-providers/{multiple → _multiple}/joinLlmExecutionTools.d.ts +0 -0
  206. /package/esm/typings/src/llm-providers/{multiple → _multiple}/playground/playground.d.ts +0 -0
package/umd/index.umd.js CHANGED
@@ -22,7 +22,7 @@
22
22
  * @generated
23
23
  * @see https://github.com/webgptorg/promptbook
24
24
  */
25
- const PROMPTBOOK_ENGINE_VERSION = '0.92.0-9';
25
+ const PROMPTBOOK_ENGINE_VERSION = '0.93.0';
26
26
  /**
27
27
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
28
28
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -78,7 +78,7 @@
78
78
  const SMALL_NUMBER = 0.001;
79
79
  // <- TODO: [🧜‍♂️]
80
80
  /**
81
- * @@@
81
+ * Default settings for parsing and generating CSV files in Promptbook.
82
82
  *
83
83
  * @public exported from `@promptbook/core`
84
84
  */
@@ -93,6 +93,48 @@
93
93
  * TODO: [🧠][🧜‍♂️] Maybe join remoteServerUrl and path into single value
94
94
  */
95
95
 
96
+ /**
97
+ * Orders JSON object by keys
98
+ *
99
+ * @returns The same type of object as the input re-ordered
100
+ * @public exported from `@promptbook/utils`
101
+ */
102
+ function orderJson(options) {
103
+ const { value, order } = options;
104
+ const orderedValue = {
105
+ ...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
106
+ ...value,
107
+ };
108
+ return orderedValue;
109
+ }
110
+
111
+ /**
112
+ * Freezes the given object and all its nested objects recursively
113
+ *
114
+ * Note: `$` is used to indicate that this function is not a pure function - it mutates given object
115
+ * Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
116
+ *
117
+ * @returns The same object as the input, but deeply frozen
118
+ * @public exported from `@promptbook/utils`
119
+ */
120
+ function $deepFreeze(objectValue) {
121
+ if (Array.isArray(objectValue)) {
122
+ return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
123
+ }
124
+ const propertyNames = Object.getOwnPropertyNames(objectValue);
125
+ for (const propertyName of propertyNames) {
126
+ const value = objectValue[propertyName];
127
+ if (value && typeof value === 'object') {
128
+ $deepFreeze(value);
129
+ }
130
+ }
131
+ Object.freeze(objectValue);
132
+ return objectValue;
133
+ }
134
+ /**
135
+ * TODO: [🧠] Is there a way how to meaningfully test this utility
136
+ */
137
+
96
138
  /**
97
139
  * Make error report URL for the given error
98
140
  *
@@ -148,7 +190,7 @@
148
190
  ${block(message)}
149
191
 
150
192
  Note: This error should not happen.
151
- It's probbably a bug in the pipeline collection
193
+ It's probably a bug in the pipeline collection
152
194
 
153
195
  Please report issue:
154
196
  ${block(getErrorReportUrl(new Error(message)).href)}
@@ -162,158 +204,447 @@
162
204
  }
163
205
 
164
206
  /**
165
- * @@@
207
+ * This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
166
208
  *
167
- * @param text @@@
168
- * @param _isFirstLetterCapital @@@
169
- * @returns @@@
170
- * @example 'helloWorld'
171
- * @example 'iLovePromptbook'
172
- * @public exported from `@promptbook/utils`
209
+ * @public exported from `@promptbook/core`
173
210
  */
174
- function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
175
- let charType;
176
- let lastCharType = null;
177
- let normalizedName = '';
178
- for (const char of text) {
179
- let normalizedChar;
180
- if (/^[a-z]$/.test(char)) {
181
- charType = 'LOWERCASE';
182
- normalizedChar = char;
183
- }
184
- else if (/^[A-Z]$/.test(char)) {
185
- charType = 'UPPERCASE';
186
- normalizedChar = char.toLowerCase();
187
- }
188
- else if (/^[0-9]$/.test(char)) {
189
- charType = 'NUMBER';
190
- normalizedChar = char;
191
- }
192
- else {
193
- charType = 'OTHER';
194
- normalizedChar = '';
195
- }
196
- if (!lastCharType) {
197
- if (_isFirstLetterCapital) {
198
- normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
199
- }
200
- }
201
- else if (charType !== lastCharType &&
202
- !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
203
- !(lastCharType === 'NUMBER') &&
204
- !(charType === 'NUMBER')) {
205
- normalizedChar = normalizedChar.toUpperCase(); //TODO: [🌺] DRY
206
- }
207
- normalizedName += normalizedChar;
208
- lastCharType = charType;
211
+ class WrappedError extends Error {
212
+ constructor(whatWasThrown) {
213
+ const tag = `[🤮]`;
214
+ console.error(tag, whatWasThrown);
215
+ super(spaceTrim$1.spaceTrim(`
216
+ Non-Error object was thrown
217
+
218
+ Note: Look for ${tag} in the console for more details
219
+ Please report issue on ${ADMIN_EMAIL}
220
+ `));
221
+ this.name = 'WrappedError';
222
+ Object.setPrototypeOf(this, WrappedError.prototype);
209
223
  }
210
- return normalizedName;
211
224
  }
212
- /**
213
- * TODO: [🌺] Use some intermediate util splitWords
214
- */
215
225
 
216
226
  /**
217
- * Removes emojis from a string and fix whitespaces
227
+ * Helper used in catch blocks to assert that the error is an instance of `Error`
218
228
  *
219
- * @param text with emojis
220
- * @returns text without emojis
221
- * @public exported from `@promptbook/utils`
229
+ * @param whatWasThrown Any object that was thrown
230
+ * @returns Nothing if the error is an instance of `Error`
231
+ * @throws `WrappedError` or `UnexpectedError` if the error is not standard
232
+ *
233
+ * @private within the repository
222
234
  */
223
- function removeEmojis(text) {
224
- // Replace emojis (and also ZWJ sequence) with hyphens
225
- text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
226
- text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
227
- text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
228
- text = text.replace(/\p{Extended_Pictographic}/gu, '');
229
- return text;
235
+ function assertsError(whatWasThrown) {
236
+ // Case 1: Handle error which was rethrown as `WrappedError`
237
+ if (whatWasThrown instanceof WrappedError) {
238
+ const wrappedError = whatWasThrown;
239
+ throw wrappedError;
240
+ }
241
+ // Case 2: Handle unexpected errors
242
+ if (whatWasThrown instanceof UnexpectedError) {
243
+ const unexpectedError = whatWasThrown;
244
+ throw unexpectedError;
245
+ }
246
+ // Case 3: Handle standard errors - keep them up to consumer
247
+ if (whatWasThrown instanceof Error) {
248
+ return;
249
+ }
250
+ // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
251
+ throw new WrappedError(whatWasThrown);
230
252
  }
231
253
 
232
254
  /**
233
- * Tests if given string is valid URL.
255
+ * Checks if the value is [🚉] serializable as JSON
256
+ * If not, throws an UnexpectedError with a rich error message and tracking
234
257
  *
235
- * Note: This does not check if the file exists only if the path is valid
258
+ * - Almost all primitives are serializable BUT:
259
+ * - `undefined` is not serializable
260
+ * - `NaN` is not serializable
261
+ * - Objects and arrays are serializable if all their properties are serializable
262
+ * - Functions are not serializable
263
+ * - Circular references are not serializable
264
+ * - `Date` objects are not serializable
265
+ * - `Map` and `Set` objects are not serializable
266
+ * - `RegExp` objects are not serializable
267
+ * - `Error` objects are not serializable
268
+ * - `Symbol` objects are not serializable
269
+ * - And much more...
270
+ *
271
+ * @throws UnexpectedError if the value is not serializable as JSON
236
272
  * @public exported from `@promptbook/utils`
237
273
  */
238
- function isValidFilePath(filename) {
239
- if (typeof filename !== 'string') {
240
- return false;
274
+ function checkSerializableAsJson(options) {
275
+ const { value, name, message } = options;
276
+ if (value === undefined) {
277
+ throw new UnexpectedError(`${name} is undefined`);
241
278
  }
242
- if (filename.split('\n').length > 1) {
243
- return false;
279
+ else if (value === null) {
280
+ return;
244
281
  }
245
- if (filename.split(' ').length >
246
- 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
247
- return false;
282
+ else if (typeof value === 'boolean') {
283
+ return;
248
284
  }
249
- const filenameSlashes = filename.split('\\').join('/');
250
- // Absolute Unix path: /hello.txt
251
- if (/^(\/)/i.test(filenameSlashes)) {
252
- // console.log(filename, 'Absolute Unix path: /hello.txt');
253
- return true;
285
+ else if (typeof value === 'number' && !isNaN(value)) {
286
+ return;
254
287
  }
255
- // Absolute Windows path: /hello.txt
256
- if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
257
- // console.log(filename, 'Absolute Windows path: /hello.txt');
258
- return true;
288
+ else if (typeof value === 'string') {
289
+ return;
259
290
  }
260
- // Relative path: ./hello.txt
261
- if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
262
- // console.log(filename, 'Relative path: ./hello.txt');
263
- return true;
291
+ else if (typeof value === 'symbol') {
292
+ throw new UnexpectedError(`${name} is symbol`);
264
293
  }
265
- // Allow paths like foo/hello
266
- if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
267
- // console.log(filename, 'Allow paths like foo/hello');
268
- return true;
294
+ else if (typeof value === 'function') {
295
+ throw new UnexpectedError(`${name} is function`);
269
296
  }
270
- // Allow paths like hello.book
271
- if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
272
- // console.log(filename, 'Allow paths like hello.book');
273
- return true;
297
+ else if (typeof value === 'object' && Array.isArray(value)) {
298
+ for (let i = 0; i < value.length; i++) {
299
+ checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
300
+ }
274
301
  }
275
- return false;
276
- }
277
- /**
278
- * TODO: [🍏] Implement for MacOs
279
- */
302
+ else if (typeof value === 'object') {
303
+ if (value instanceof Date) {
304
+ throw new UnexpectedError(spaceTrim__default["default"]((block) => `
305
+ \`${name}\` is Date
280
306
 
281
- /**
282
- * Tests if given string is valid URL.
283
- *
284
- * Note: Dataurl are considered perfectly valid.
285
- * Note: There are two simmilar functions:
286
- * - `isValidUrl` which tests any URL
287
- * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
288
- *
289
- * @public exported from `@promptbook/utils`
290
- */
291
- function isValidUrl(url) {
292
- if (typeof url !== 'string') {
293
- return false;
294
- }
295
- try {
296
- if (url.startsWith('blob:')) {
297
- url = url.replace(/^blob:/, '');
307
+ Use \`string_date_iso8601\` instead
308
+
309
+ Additional message for \`${name}\`:
310
+ ${block(message || '(nothing)')}
311
+ `));
298
312
  }
299
- const urlObject = new URL(url /* because fail is handled */);
300
- if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
301
- return false;
313
+ else if (value instanceof Map) {
314
+ throw new UnexpectedError(`${name} is Map`);
302
315
  }
303
- return true;
304
- }
305
- catch (error) {
306
- return false;
307
- }
308
- }
316
+ else if (value instanceof Set) {
317
+ throw new UnexpectedError(`${name} is Set`);
318
+ }
319
+ else if (value instanceof RegExp) {
320
+ throw new UnexpectedError(`${name} is RegExp`);
321
+ }
322
+ else if (value instanceof Error) {
323
+ throw new UnexpectedError(spaceTrim__default["default"]((block) => `
324
+ \`${name}\` is unserialized Error
309
325
 
310
- const defaultDiacriticsRemovalMap = [
311
- {
312
- base: 'A',
313
- letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
314
- },
315
- { base: 'AA', letters: '\uA732' },
316
- { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
326
+ Use function \`serializeError\`
327
+
328
+ Additional message for \`${name}\`:
329
+ ${block(message || '(nothing)')}
330
+
331
+ `));
332
+ }
333
+ else {
334
+ for (const [subName, subValue] of Object.entries(value)) {
335
+ if (subValue === undefined) {
336
+ // Note: undefined in object is serializable - it is just omited
337
+ continue;
338
+ }
339
+ checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
340
+ }
341
+ try {
342
+ JSON.stringify(value); // <- TODO: [0]
343
+ }
344
+ catch (error) {
345
+ assertsError(error);
346
+ throw new UnexpectedError(spaceTrim__default["default"]((block) => `
347
+ \`${name}\` is not serializable
348
+
349
+ ${block(error.stack || error.message)}
350
+
351
+ Additional message for \`${name}\`:
352
+ ${block(message || '(nothing)')}
353
+ `));
354
+ }
355
+ /*
356
+ TODO: [0] Is there some more elegant way to check circular references?
357
+ const seen = new Set();
358
+ const stack = [{ value }];
359
+ while (stack.length > 0) {
360
+ const { value } = stack.pop()!;
361
+ if (typeof value === 'object' && value !== null) {
362
+ if (seen.has(value)) {
363
+ throw new UnexpectedError(`${name} has circular reference`);
364
+ }
365
+ seen.add(value);
366
+ if (Array.isArray(value)) {
367
+ stack.push(...value.map((value) => ({ value })));
368
+ } else {
369
+ stack.push(...Object.values(value).map((value) => ({ value })));
370
+ }
371
+ }
372
+ }
373
+ */
374
+ return;
375
+ }
376
+ }
377
+ else {
378
+ throw new UnexpectedError(spaceTrim__default["default"]((block) => `
379
+ \`${name}\` is unknown type
380
+
381
+ Additional message for \`${name}\`:
382
+ ${block(message || '(nothing)')}
383
+ `));
384
+ }
385
+ }
386
+ /**
387
+ * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
388
+ * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
389
+ * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
390
+ */
391
+
392
+ /**
393
+ * Creates a deep clone of the given object
394
+ *
395
+ * Note: This method only works for objects that are fully serializable to JSON and do not contain functions, Dates, or special types.
396
+ *
397
+ * @param objectValue The object to clone.
398
+ * @returns A deep, writable clone of the input object.
399
+ * @public exported from `@promptbook/utils`
400
+ */
401
+ function deepClone(objectValue) {
402
+ return JSON.parse(JSON.stringify(objectValue));
403
+ /*
404
+ TODO: [🧠] Is there a better implementation?
405
+ > const propertyNames = Object.getOwnPropertyNames(objectValue);
406
+ > for (const propertyName of propertyNames) {
407
+ > const value = (objectValue as really_any)[propertyName];
408
+ > if (value && typeof value === 'object') {
409
+ > deepClone(value);
410
+ > }
411
+ > }
412
+ > return Object.assign({}, objectValue);
413
+ */
414
+ }
415
+ /**
416
+ * TODO: [🧠] Is there a way how to meaningfully test this utility
417
+ */
418
+
419
+ /**
420
+ * Utility to export a JSON object from a function
421
+ *
422
+ * 1) Checks if the value is serializable as JSON
423
+ * 2) Makes a deep clone of the object
424
+ * 2) Orders the object properties
425
+ * 2) Deeply freezes the cloned object
426
+ *
427
+ * Note: This function does not mutates the given object
428
+ *
429
+ * @returns The same type of object as the input but read-only and re-ordered
430
+ * @public exported from `@promptbook/utils`
431
+ */
432
+ function exportJson(options) {
433
+ const { name, value, order, message } = options;
434
+ checkSerializableAsJson({ name, value, message });
435
+ const orderedValue =
436
+ // TODO: Fix error "Type instantiation is excessively deep and possibly infinite."
437
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
438
+ // @ts-ignore
439
+ order === undefined
440
+ ? deepClone(value)
441
+ : orderJson({
442
+ value: value,
443
+ // <- Note: checkSerializableAsJson asserts that the value is serializable as JSON
444
+ order: order,
445
+ });
446
+ $deepFreeze(orderedValue);
447
+ return orderedValue;
448
+ }
449
+ /**
450
+ * TODO: [🧠] Is there a way how to meaningfully test this utility
451
+ */
452
+
453
+ /**
454
+ * Nonce which is used for replacing things in strings
455
+ *
456
+ * @private within the repository
457
+ */
458
+ const REPLACING_NONCE = 'ptbkauk42kV2dzao34faw7FudQUHYPtW';
459
+ /**
460
+ * Placeholder value indicating a parameter is missing its value.
461
+ *
462
+ * @private within the repository
463
+ */
464
+ const RESERVED_PARAMETER_MISSING_VALUE = 'MISSING-' + REPLACING_NONCE;
465
+ /**
466
+ * Placeholder value indicating a parameter is restricted and cannot be used directly.
467
+ *
468
+ * @private within the repository
469
+ */
470
+ const RESERVED_PARAMETER_RESTRICTED = 'RESTRICTED-' + REPLACING_NONCE;
471
+ /**
472
+ * The names of the parameters that are reserved for special purposes
473
+ *
474
+ * @public exported from `@promptbook/core`
475
+ */
476
+ const RESERVED_PARAMETER_NAMES = exportJson({
477
+ name: 'RESERVED_PARAMETER_NAMES',
478
+ message: `The names of the parameters that are reserved for special purposes`,
479
+ value: [
480
+ 'content',
481
+ 'context',
482
+ 'knowledge',
483
+ 'examples',
484
+ 'modelName',
485
+ 'currentDate',
486
+ // <- TODO: list here all command names
487
+ // <- TODO: Add more like 'date', 'modelName',...
488
+ // <- TODO: Add [emoji] + instructions ACRY when adding new reserved parameter
489
+ ],
490
+ });
491
+ /**
492
+ * Note: [💞] Ignore a discrepancy between file name and entity name
493
+ */
494
+
495
+ /**
496
+ * Normalizes a given text to camelCase format.
497
+ *
498
+ * @param text The text to be normalized.
499
+ * @param _isFirstLetterCapital Whether the first letter should be capitalized.
500
+ * @returns The camelCase formatted string.
501
+ * @example 'helloWorld'
502
+ * @example 'iLovePromptbook'
503
+ * @public exported from `@promptbook/utils`
504
+ */
505
+ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
506
+ let charType;
507
+ let lastCharType = null;
508
+ let normalizedName = '';
509
+ for (const char of text) {
510
+ let normalizedChar;
511
+ if (/^[a-z]$/.test(char)) {
512
+ charType = 'LOWERCASE';
513
+ normalizedChar = char;
514
+ }
515
+ else if (/^[A-Z]$/.test(char)) {
516
+ charType = 'UPPERCASE';
517
+ normalizedChar = char.toLowerCase();
518
+ }
519
+ else if (/^[0-9]$/.test(char)) {
520
+ charType = 'NUMBER';
521
+ normalizedChar = char;
522
+ }
523
+ else {
524
+ charType = 'OTHER';
525
+ normalizedChar = '';
526
+ }
527
+ if (!lastCharType) {
528
+ if (_isFirstLetterCapital) {
529
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
530
+ }
531
+ }
532
+ else if (charType !== lastCharType &&
533
+ !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
534
+ !(lastCharType === 'NUMBER') &&
535
+ !(charType === 'NUMBER')) {
536
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: [🌺] DRY
537
+ }
538
+ normalizedName += normalizedChar;
539
+ lastCharType = charType;
540
+ }
541
+ return normalizedName;
542
+ }
543
+ /**
544
+ * TODO: [🌺] Use some intermediate util splitWords
545
+ */
546
+
547
+ /**
548
+ * Removes emojis from a string and fix whitespaces
549
+ *
550
+ * @param text with emojis
551
+ * @returns text without emojis
552
+ * @public exported from `@promptbook/utils`
553
+ */
554
+ function removeEmojis(text) {
555
+ // Replace emojis (and also ZWJ sequence) with hyphens
556
+ text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
557
+ text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
558
+ text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
559
+ text = text.replace(/\p{Extended_Pictographic}/gu, '');
560
+ return text;
561
+ }
562
+
563
+ /**
564
+ * Tests if given string is valid URL.
565
+ *
566
+ * Note: This does not check if the file exists only if the path is valid
567
+ * @public exported from `@promptbook/utils`
568
+ */
569
+ function isValidFilePath(filename) {
570
+ if (typeof filename !== 'string') {
571
+ return false;
572
+ }
573
+ if (filename.split('\n').length > 1) {
574
+ return false;
575
+ }
576
+ if (filename.split(' ').length >
577
+ 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
578
+ return false;
579
+ }
580
+ const filenameSlashes = filename.split('\\').join('/');
581
+ // Absolute Unix path: /hello.txt
582
+ if (/^(\/)/i.test(filenameSlashes)) {
583
+ // console.log(filename, 'Absolute Unix path: /hello.txt');
584
+ return true;
585
+ }
586
+ // Absolute Windows path: /hello.txt
587
+ if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
588
+ // console.log(filename, 'Absolute Windows path: /hello.txt');
589
+ return true;
590
+ }
591
+ // Relative path: ./hello.txt
592
+ if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
593
+ // console.log(filename, 'Relative path: ./hello.txt');
594
+ return true;
595
+ }
596
+ // Allow paths like foo/hello
597
+ if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
598
+ // console.log(filename, 'Allow paths like foo/hello');
599
+ return true;
600
+ }
601
+ // Allow paths like hello.book
602
+ if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
603
+ // console.log(filename, 'Allow paths like hello.book');
604
+ return true;
605
+ }
606
+ return false;
607
+ }
608
+ /**
609
+ * TODO: [🍏] Implement for MacOs
610
+ */
611
+
612
+ /**
613
+ * Tests if given string is valid URL.
614
+ *
615
+ * Note: Dataurl are considered perfectly valid.
616
+ * Note: There are two similar functions:
617
+ * - `isValidUrl` which tests any URL
618
+ * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
619
+ *
620
+ * @public exported from `@promptbook/utils`
621
+ */
622
+ function isValidUrl(url) {
623
+ if (typeof url !== 'string') {
624
+ return false;
625
+ }
626
+ try {
627
+ if (url.startsWith('blob:')) {
628
+ url = url.replace(/^blob:/, '');
629
+ }
630
+ const urlObject = new URL(url /* because fail is handled */);
631
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
632
+ return false;
633
+ }
634
+ return true;
635
+ }
636
+ catch (error) {
637
+ return false;
638
+ }
639
+ }
640
+
641
+ const defaultDiacriticsRemovalMap = [
642
+ {
643
+ base: 'A',
644
+ letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
645
+ },
646
+ { base: 'AA', letters: '\uA732' },
647
+ { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
317
648
  { base: 'AO', letters: '\uA734' },
318
649
  { base: 'AU', letters: '\uA736' },
319
650
  { base: 'AV', letters: '\uA738\uA73A' },
@@ -552,10 +883,10 @@
552
883
  */
553
884
 
554
885
  /**
555
- * @@@
886
+ * Removes diacritic marks (accents) from characters in a string.
556
887
  *
557
- * @param input @@@
558
- * @returns @@@
888
+ * @param input The string containing diacritics to be normalized.
889
+ * @returns The string with diacritics removed or normalized.
559
890
  * @public exported from `@promptbook/utils`
560
891
  */
561
892
  function removeDiacritics(input) {
@@ -569,10 +900,10 @@
569
900
  */
570
901
 
571
902
  /**
572
- * @@@
903
+ * Converts a given text to kebab-case format.
573
904
  *
574
- * @param text @@@
575
- * @returns @@@
905
+ * @param text The text to be converted.
906
+ * @returns The kebab-case formatted string.
576
907
  * @example 'hello-world'
577
908
  * @example 'i-love-promptbook'
578
909
  * @public exported from `@promptbook/utils`
@@ -620,11 +951,11 @@
620
951
  */
621
952
 
622
953
  /**
623
- * @@@
954
+ * Converts a title string into a normalized name.
624
955
  *
625
- * @param value @@@
626
- * @returns @@@
627
- * @example @@@
956
+ * @param value The title string to be converted to a name.
957
+ * @returns A normalized name derived from the input title.
958
+ * @example 'Hello World!' -> 'hello-world'
628
959
  * @public exported from `@promptbook/utils`
629
960
  */
630
961
  function titleToName(value) {
@@ -652,21 +983,63 @@
652
983
  */
653
984
  function renderPromptbookMermaid(pipelineJson, options) {
654
985
  const { linkTask = () => null } = options || {};
986
+ const MERMAID_PREFIX = 'pipeline_';
987
+ const MERMAID_KNOWLEDGE_NAME = MERMAID_PREFIX + 'knowledge';
988
+ const MERMAID_RESERVED_NAME = MERMAID_PREFIX + 'reserved';
989
+ const MERMAID_INPUT_NAME = MERMAID_PREFIX + 'input';
990
+ const MERMAID_OUTPUT_NAME = MERMAID_PREFIX + 'output';
655
991
  const parameterNameToTaskName = (parameterName) => {
992
+ if (parameterName === 'knowledge') {
993
+ return MERMAID_KNOWLEDGE_NAME;
994
+ }
995
+ else if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
996
+ return MERMAID_RESERVED_NAME;
997
+ }
656
998
  const parameter = pipelineJson.parameters.find((parameter) => parameter.name === parameterName);
657
999
  if (!parameter) {
658
1000
  throw new UnexpectedError(`Could not find {${parameterName}}`);
659
- // <- TODO: !!6 This causes problems when {knowledge} and other reserved parameters are used
1001
+ // <- TODO: This causes problems when {knowledge} and other reserved parameters are used
660
1002
  }
661
1003
  if (parameter.isInput) {
662
- return 'input';
1004
+ return MERMAID_INPUT_NAME;
663
1005
  }
664
1006
  const task = pipelineJson.tasks.find((task) => task.resultingParameterName === parameterName);
665
1007
  if (!task) {
666
1008
  throw new Error(`Could not find task for {${parameterName}}`);
667
1009
  }
668
- return task.name || normalizeTo_camelCase('task-' + titleToName(task.title));
1010
+ return MERMAID_PREFIX + (task.name || normalizeTo_camelCase('task-' + titleToName(task.title)));
669
1011
  };
1012
+ const inputAndIntermediateParametersMermaid = pipelineJson.tasks
1013
+ .flatMap(({ title, dependentParameterNames, resultingParameterName }) => [
1014
+ `${parameterNameToTaskName(resultingParameterName)}("${title}")`,
1015
+ ...dependentParameterNames.map((dependentParameterName) => `${parameterNameToTaskName(dependentParameterName)}--"{${dependentParameterName}}"-->${parameterNameToTaskName(resultingParameterName)}`),
1016
+ ])
1017
+ .join('\n');
1018
+ const outputParametersMermaid = pipelineJson.parameters
1019
+ .filter(({ isOutput }) => isOutput)
1020
+ .map(({ name }) => `${parameterNameToTaskName(name)}--"{${name}}"-->${MERMAID_OUTPUT_NAME}`)
1021
+ .join('\n');
1022
+ const linksMermaid = pipelineJson.tasks
1023
+ .map((task) => {
1024
+ const link = linkTask(task);
1025
+ if (link === null) {
1026
+ return '';
1027
+ }
1028
+ const { href, title } = link;
1029
+ const taskName = parameterNameToTaskName(task.resultingParameterName);
1030
+ return `click ${taskName} href "${href}" "${title}";`;
1031
+ })
1032
+ .filter((line) => line !== '')
1033
+ .join('\n');
1034
+ const interactionPointsMermaid = Object.entries({
1035
+ [MERMAID_INPUT_NAME]: 'Input',
1036
+ [MERMAID_OUTPUT_NAME]: 'Output',
1037
+ [MERMAID_RESERVED_NAME]: 'Other',
1038
+ [MERMAID_KNOWLEDGE_NAME]: 'Knowledge',
1039
+ })
1040
+ .filter(([MERMAID_NAME]) => (inputAndIntermediateParametersMermaid + outputParametersMermaid).includes(MERMAID_NAME))
1041
+ .map(([MERMAID_NAME, title]) => `${MERMAID_NAME}((${title})):::${MERMAID_NAME}`)
1042
+ .join('\n');
670
1043
  const promptbookMermaid = spaceTrim$1.spaceTrim((block) => `
671
1044
 
672
1045
  %% 🔮 Tip: Open this on GitHub or in the VSCode website to see the Mermaid graph visually
@@ -674,37 +1047,27 @@
674
1047
  flowchart LR
675
1048
  subgraph "${pipelineJson.title}"
676
1049
 
1050
+ %% Basic configuration
677
1051
  direction TB
678
1052
 
679
- input((Input)):::input
680
- ${block(pipelineJson.tasks
681
- .flatMap(({ title, dependentParameterNames, resultingParameterName }) => [
682
- `${parameterNameToTaskName(resultingParameterName)}("${title}")`,
683
- ...dependentParameterNames.map((dependentParameterName) => `${parameterNameToTaskName(dependentParameterName)}--"{${dependentParameterName}}"-->${parameterNameToTaskName(resultingParameterName)}`),
684
- ])
685
- .join('\n'))}
686
-
687
- ${block(pipelineJson.parameters
688
- .filter(({ isOutput }) => isOutput)
689
- .map(({ name }) => `${parameterNameToTaskName(name)}--"{${name}}"-->output`)
690
- .join('\n'))}
691
- output((Output)):::output
692
-
693
- ${block(pipelineJson.tasks
694
- .map((task) => {
695
- const link = linkTask(task);
696
- if (link === null) {
697
- return '';
698
- }
699
- const { href, title } = link;
700
- const taskName = parameterNameToTaskName(task.resultingParameterName);
701
- return `click ${taskName} href "${href}" "${title}";`;
702
- })
703
- .filter((line) => line !== '')
704
- .join('\n'))}
705
-
706
- classDef input color: grey;
707
- classDef output color: grey;
1053
+ %% Interaction points from pipeline to outside
1054
+ ${block(interactionPointsMermaid)}
1055
+
1056
+ %% Input and intermediate parameters
1057
+ ${block(inputAndIntermediateParametersMermaid)}
1058
+
1059
+
1060
+ %% Output parameters
1061
+ ${block(outputParametersMermaid)}
1062
+
1063
+ %% Links
1064
+ ${block(linksMermaid)}
1065
+
1066
+ %% Styles
1067
+ classDef ${MERMAID_INPUT_NAME} color: grey;
1068
+ classDef ${MERMAID_OUTPUT_NAME} color: grey;
1069
+ classDef ${MERMAID_RESERVED_NAME} color: grey;
1070
+ classDef ${MERMAID_KNOWLEDGE_NAME} color: grey;
708
1071
 
709
1072
  end;
710
1073
 
@@ -763,7 +1126,7 @@
763
1126
  }
764
1127
 
765
1128
  /**
766
- * This error indicates that the pipeline collection cannot be propperly loaded
1129
+ * This error indicates that the pipeline collection cannot be properly loaded
767
1130
  *
768
1131
  * @public exported from `@promptbook/core`
769
1132
  */
@@ -784,774 +1147,444 @@
784
1147
  constructor(message) {
785
1148
  super(message);
786
1149
  this.name = 'EnvironmentMismatchError';
787
- Object.setPrototypeOf(this, EnvironmentMismatchError.prototype);
788
- }
789
- }
790
-
791
- /**
792
- * This error occurs when some expectation is not met in the execution of the pipeline
793
- *
794
- * @public exported from `@promptbook/core`
795
- * Note: Do not throw this error, its reserved for `checkExpectations` and `createPipelineExecutor` and public ONLY to be serializable through remote server
796
- * Note: Always thrown in `checkExpectations` and catched in `createPipelineExecutor` and rethrown as `PipelineExecutionError`
797
- * Note: This is a kindof subtype of PipelineExecutionError
798
- */
799
- class ExpectError extends Error {
800
- constructor(message) {
801
- super(message);
802
- this.name = 'ExpectError';
803
- Object.setPrototypeOf(this, ExpectError.prototype);
804
- }
805
- }
806
-
807
- /**
808
- * This error indicates that the promptbook can not retrieve knowledge from external sources
809
- *
810
- * @public exported from `@promptbook/core`
811
- */
812
- class KnowledgeScrapeError extends Error {
813
- constructor(message) {
814
- super(message);
815
- this.name = 'KnowledgeScrapeError';
816
- Object.setPrototypeOf(this, KnowledgeScrapeError.prototype);
817
- }
818
- }
819
-
820
- /**
821
- * This error type indicates that some limit was reached
822
- *
823
- * @public exported from `@promptbook/core`
824
- */
825
- class LimitReachedError extends Error {
826
- constructor(message) {
827
- super(message);
828
- this.name = 'LimitReachedError';
829
- Object.setPrototypeOf(this, LimitReachedError.prototype);
830
- }
831
- }
832
-
833
- /**
834
- * This error type indicates that some tools are missing for pipeline execution or preparation
835
- *
836
- * @public exported from `@promptbook/core`
837
- */
838
- class MissingToolsError extends Error {
839
- constructor(message) {
840
- super(spaceTrim$1.spaceTrim((block) => `
841
- ${block(message)}
842
-
843
- Note: You have probbably forgot to provide some tools for pipeline execution or preparation
844
-
845
- `));
846
- this.name = 'MissingToolsError';
847
- Object.setPrototypeOf(this, MissingToolsError.prototype);
848
- }
849
- }
850
-
851
- /**
852
- * This error indicates that promptbook not found in the collection
853
- *
854
- * @public exported from `@promptbook/core`
855
- */
856
- class NotFoundError extends Error {
857
- constructor(message) {
858
- super(message);
859
- this.name = 'NotFoundError';
860
- Object.setPrototypeOf(this, NotFoundError.prototype);
861
- }
862
- }
863
-
864
- /**
865
- * This error type indicates that some part of the code is not implemented yet
866
- *
867
- * @public exported from `@promptbook/core`
868
- */
869
- class NotYetImplementedError extends Error {
870
- constructor(message) {
871
- super(spaceTrim$1.spaceTrim((block) => `
872
- ${block(message)}
873
-
874
- Note: This feature is not implemented yet but it will be soon.
875
-
876
- If you want speed up the implementation or just read more, look here:
877
- https://github.com/webgptorg/promptbook
878
-
879
- Or contact us on pavol@ptbk.io
880
-
881
- `));
882
- this.name = 'NotYetImplementedError';
883
- Object.setPrototypeOf(this, NotYetImplementedError.prototype);
884
- }
885
- }
886
-
887
- /**
888
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
889
- *
890
- * @public exported from `@promptbook/core`
891
- */
892
- class ParseError extends Error {
893
- constructor(message) {
894
- super(message);
895
- this.name = 'ParseError';
896
- Object.setPrototypeOf(this, ParseError.prototype);
897
- }
898
- }
899
- /**
900
- * TODO: Maybe split `ParseError` and `ApplyError`
901
- */
902
-
903
- /**
904
- * Generates random token
905
- *
906
- * Note: This function is cryptographically secure (it uses crypto.randomBytes internally)
907
- *
908
- * @private internal helper function
909
- * @returns secure random token
910
- */
911
- function $randomToken(randomness) {
912
- return crypto.randomBytes(randomness).toString('hex');
913
- }
914
- /**
915
- * TODO: Maybe use nanoid instead https://github.com/ai/nanoid
916
- */
917
-
918
- /**
919
- * This error indicates errors during the execution of the pipeline
920
- *
921
- * @public exported from `@promptbook/core`
922
- */
923
- class PipelineExecutionError extends Error {
924
- constructor(message) {
925
- // Added id parameter
926
- super(message);
927
- this.name = 'PipelineExecutionError';
928
- // TODO: [🐙] DRY - Maybe $randomId
929
- this.id = `error-${$randomToken(8 /* <- TODO: To global config + Use Base58 to avoid simmilar char conflicts */)}`;
930
- Object.setPrototypeOf(this, PipelineExecutionError.prototype);
1150
+ Object.setPrototypeOf(this, EnvironmentMismatchError.prototype);
931
1151
  }
932
1152
  }
933
- /**
934
- * TODO: [🧠][🌂] Add id to all errors
935
- */
936
1153
 
937
1154
  /**
938
- * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
1155
+ * This error occurs when some expectation is not met in the execution of the pipeline
939
1156
  *
940
1157
  * @public exported from `@promptbook/core`
1158
+ * Note: Do not throw this error, its reserved for `checkExpectations` and `createPipelineExecutor` and public ONLY to be serializable through remote server
1159
+ * Note: Always thrown in `checkExpectations` and catched in `createPipelineExecutor` and rethrown as `PipelineExecutionError`
1160
+ * Note: This is a kindof subtype of PipelineExecutionError
941
1161
  */
942
- class PipelineLogicError extends Error {
1162
+ class ExpectError extends Error {
943
1163
  constructor(message) {
944
1164
  super(message);
945
- this.name = 'PipelineLogicError';
946
- Object.setPrototypeOf(this, PipelineLogicError.prototype);
1165
+ this.name = 'ExpectError';
1166
+ Object.setPrototypeOf(this, ExpectError.prototype);
947
1167
  }
948
1168
  }
949
1169
 
950
1170
  /**
951
- * This error indicates errors in referencing promptbooks between each other
1171
+ * This error indicates that the promptbook can not retrieve knowledge from external sources
952
1172
  *
953
1173
  * @public exported from `@promptbook/core`
954
1174
  */
955
- class PipelineUrlError extends Error {
1175
+ class KnowledgeScrapeError extends Error {
956
1176
  constructor(message) {
957
1177
  super(message);
958
- this.name = 'PipelineUrlError';
959
- Object.setPrototypeOf(this, PipelineUrlError.prototype);
1178
+ this.name = 'KnowledgeScrapeError';
1179
+ Object.setPrototypeOf(this, KnowledgeScrapeError.prototype);
960
1180
  }
961
1181
  }
962
1182
 
963
1183
  /**
964
- * Error thrown when a fetch request fails
1184
+ * This error type indicates that some limit was reached
965
1185
  *
966
1186
  * @public exported from `@promptbook/core`
967
1187
  */
968
- class PromptbookFetchError extends Error {
1188
+ class LimitReachedError extends Error {
969
1189
  constructor(message) {
970
1190
  super(message);
971
- this.name = 'PromptbookFetchError';
972
- Object.setPrototypeOf(this, PromptbookFetchError.prototype);
1191
+ this.name = 'LimitReachedError';
1192
+ Object.setPrototypeOf(this, LimitReachedError.prototype);
973
1193
  }
974
1194
  }
975
1195
 
976
1196
  /**
977
- * This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
1197
+ * This error type indicates that some tools are missing for pipeline execution or preparation
978
1198
  *
979
1199
  * @public exported from `@promptbook/core`
980
1200
  */
981
- class WrappedError extends Error {
982
- constructor(whatWasThrown) {
983
- const tag = `[🤮]`;
984
- console.error(tag, whatWasThrown);
985
- super(spaceTrim$1.spaceTrim(`
986
- Non-Error object was thrown
1201
+ class MissingToolsError extends Error {
1202
+ constructor(message) {
1203
+ super(spaceTrim$1.spaceTrim((block) => `
1204
+ ${block(message)}
987
1205
 
988
- Note: Look for ${tag} in the console for more details
989
- Please report issue on ${ADMIN_EMAIL}
990
- `));
991
- this.name = 'WrappedError';
992
- Object.setPrototypeOf(this, WrappedError.prototype);
1206
+ Note: You have probably forgot to provide some tools for pipeline execution or preparation
1207
+
1208
+ `));
1209
+ this.name = 'MissingToolsError';
1210
+ Object.setPrototypeOf(this, MissingToolsError.prototype);
993
1211
  }
994
1212
  }
995
1213
 
996
1214
  /**
997
- * Index of all custom errors
1215
+ * This error indicates that promptbook not found in the collection
998
1216
  *
999
1217
  * @public exported from `@promptbook/core`
1000
1218
  */
1001
- const PROMPTBOOK_ERRORS = {
1002
- AbstractFormatError,
1003
- CsvFormatError,
1004
- CollectionError,
1005
- EnvironmentMismatchError,
1006
- ExpectError,
1007
- KnowledgeScrapeError,
1008
- LimitReachedError,
1009
- MissingToolsError,
1010
- NotFoundError,
1011
- NotYetImplementedError,
1012
- ParseError,
1013
- PipelineExecutionError,
1014
- PipelineLogicError,
1015
- PipelineUrlError,
1016
- AuthenticationError,
1017
- PromptbookFetchError,
1018
- UnexpectedError,
1019
- WrappedError,
1020
- // TODO: [🪑]> VersionMismatchError,
1021
- };
1022
- /**
1023
- * Index of all javascript errors
1024
- *
1025
- * @private for internal usage
1026
- */
1027
- const COMMON_JAVASCRIPT_ERRORS = {
1028
- Error,
1029
- EvalError,
1030
- RangeError,
1031
- ReferenceError,
1032
- SyntaxError,
1033
- TypeError,
1034
- URIError,
1035
- AggregateError,
1036
- /*
1037
- Note: Not widely supported
1038
- > InternalError,
1039
- > ModuleError,
1040
- > HeapError,
1041
- > WebAssemblyCompileError,
1042
- > WebAssemblyRuntimeError,
1043
- */
1044
- };
1045
- /**
1046
- * Index of all errors
1047
- *
1048
- * @private for internal usage
1049
- */
1050
- const ALL_ERRORS = {
1051
- ...PROMPTBOOK_ERRORS,
1052
- ...COMMON_JAVASCRIPT_ERRORS,
1053
- };
1054
- /**
1055
- * Note: [💞] Ignore a discrepancy between file name and entity name
1056
- */
1057
-
1058
- /**
1059
- * Deserializes the error object
1060
- *
1061
- * @public exported from `@promptbook/utils`
1062
- */
1063
- function deserializeError(error) {
1064
- const { name, stack, id } = error; // Added id
1065
- let { message } = error;
1066
- let ErrorClass = ALL_ERRORS[error.name];
1067
- if (ErrorClass === undefined) {
1068
- ErrorClass = Error;
1069
- message = `${name}: ${message}`;
1070
- }
1071
- if (stack !== undefined && stack !== '') {
1072
- message = spaceTrim__default["default"]((block) => `
1073
- ${block(message)}
1074
-
1075
- Original stack trace:
1076
- ${block(stack || '')}
1077
- `);
1219
+ class NotFoundError extends Error {
1220
+ constructor(message) {
1221
+ super(message);
1222
+ this.name = 'NotFoundError';
1223
+ Object.setPrototypeOf(this, NotFoundError.prototype);
1078
1224
  }
1079
- const deserializedError = new ErrorClass(message);
1080
- deserializedError.id = id; // Assign id to the error object
1081
- return deserializedError;
1082
1225
  }
1083
1226
 
1084
1227
  /**
1085
- * Serializes an error into a [🚉] JSON-serializable object
1228
+ * This error type indicates that some part of the code is not implemented yet
1086
1229
  *
1087
- * @public exported from `@promptbook/utils`
1230
+ * @public exported from `@promptbook/core`
1088
1231
  */
1089
- function serializeError(error) {
1090
- const { name, message, stack } = error;
1091
- const { id } = error;
1092
- if (!Object.keys(ALL_ERRORS).includes(name)) {
1093
- console.error(spaceTrim__default["default"]((block) => `
1094
-
1095
- Cannot serialize error with name "${name}"
1232
+ class NotYetImplementedError extends Error {
1233
+ constructor(message) {
1234
+ super(spaceTrim$1.spaceTrim((block) => `
1235
+ ${block(message)}
1096
1236
 
1097
- Authors of Promptbook probably forgot to add this error into the list of errors:
1098
- https://github.com/webgptorg/promptbook/blob/main/src/errors/0-index.ts
1237
+ Note: This feature is not implemented yet but it will be soon.
1099
1238
 
1239
+ If you want speed up the implementation or just read more, look here:
1240
+ https://github.com/webgptorg/promptbook
1100
1241
 
1101
- ${block(stack || message)}
1242
+ Or contact us on pavol@ptbk.io
1102
1243
 
1103
1244
  `));
1245
+ this.name = 'NotYetImplementedError';
1246
+ Object.setPrototypeOf(this, NotYetImplementedError.prototype);
1104
1247
  }
1105
- return {
1106
- name: name,
1107
- message,
1108
- stack,
1109
- id, // Include id in the serialized object
1110
- };
1111
1248
  }
1112
1249
 
1113
1250
  /**
1114
- * Async version of Array.forEach
1251
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
1115
1252
  *
1116
- * @param array - Array to iterate over
1117
- * @param options - Options for the function
1118
- * @param callbackfunction - Function to call for each item
1119
- * @public exported from `@promptbook/utils`
1120
- * @deprecated [🪂] Use queues instead
1253
+ * @public exported from `@promptbook/core`
1121
1254
  */
1122
- async function forEachAsync(array, options, callbackfunction) {
1123
- const { maxParallelCount = Infinity } = options;
1124
- let index = 0;
1125
- let runningTasks = [];
1126
- const tasks = [];
1127
- for (const item of array) {
1128
- const currentIndex = index++;
1129
- const task = callbackfunction(item, currentIndex, array);
1130
- tasks.push(task);
1131
- runningTasks.push(task);
1132
- /* not await */ Promise.resolve(task).then(() => {
1133
- runningTasks = runningTasks.filter((t) => t !== task);
1134
- });
1135
- if (maxParallelCount < runningTasks.length) {
1136
- await Promise.race(runningTasks);
1137
- }
1255
+ class ParseError extends Error {
1256
+ constructor(message) {
1257
+ super(message);
1258
+ this.name = 'ParseError';
1259
+ Object.setPrototypeOf(this, ParseError.prototype);
1138
1260
  }
1139
- await Promise.all(tasks);
1140
1261
  }
1262
+ /**
1263
+ * TODO: Maybe split `ParseError` and `ApplyError`
1264
+ */
1141
1265
 
1142
1266
  /**
1143
- * Helper used in catch blocks to assert that the error is an instance of `Error`
1267
+ * Generates random token
1144
1268
  *
1145
- * @param whatWasThrown Any object that was thrown
1146
- * @returns Nothing if the error is an instance of `Error`
1147
- * @throws `WrappedError` or `UnexpectedError` if the error is not standard
1269
+ * Note: This function is cryptographically secure (it uses crypto.randomBytes internally)
1148
1270
  *
1149
- * @private within the repository
1271
+ * @private internal helper function
1272
+ * @returns secure random token
1150
1273
  */
1151
- function assertsError(whatWasThrown) {
1152
- // Case 1: Handle error which was rethrown as `WrappedError`
1153
- if (whatWasThrown instanceof WrappedError) {
1154
- const wrappedError = whatWasThrown;
1155
- throw wrappedError;
1156
- }
1157
- // Case 2: Handle unexpected errors
1158
- if (whatWasThrown instanceof UnexpectedError) {
1159
- const unexpectedError = whatWasThrown;
1160
- throw unexpectedError;
1161
- }
1162
- // Case 3: Handle standard errors - keep them up to consumer
1163
- if (whatWasThrown instanceof Error) {
1164
- return;
1165
- }
1166
- // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
1167
- throw new WrappedError(whatWasThrown);
1274
+ function $randomToken(randomness) {
1275
+ return crypto.randomBytes(randomness).toString('hex');
1168
1276
  }
1277
+ /**
1278
+ * TODO: Maybe use nanoid instead https://github.com/ai/nanoid
1279
+ */
1169
1280
 
1170
1281
  /**
1171
- * Function to check if a string is valid CSV
1172
- *
1173
- * @param value The string to check
1174
- * @returns True if the string is a valid CSV string, false otherwise
1282
+ * This error indicates errors during the execution of the pipeline
1175
1283
  *
1176
- * @public exported from `@promptbook/utils`
1284
+ * @public exported from `@promptbook/core`
1177
1285
  */
1178
- function isValidCsvString(value) {
1179
- try {
1180
- // A simple check for CSV format: at least one comma and no invalid characters
1181
- if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
1182
- return true;
1183
- }
1184
- return false;
1185
- }
1186
- catch (error) {
1187
- assertsError(error);
1188
- return false;
1286
+ class PipelineExecutionError extends Error {
1287
+ constructor(message) {
1288
+ // Added id parameter
1289
+ super(message);
1290
+ this.name = 'PipelineExecutionError';
1291
+ // TODO: [🐙] DRY - Maybe $randomId
1292
+ this.id = `error-${$randomToken(8 /* <- TODO: To global config + Use Base58 to avoid similar char conflicts */)}`;
1293
+ Object.setPrototypeOf(this, PipelineExecutionError.prototype);
1189
1294
  }
1190
1295
  }
1296
+ /**
1297
+ * TODO: [🧠][🌂] Add id to all errors
1298
+ */
1191
1299
 
1192
1300
  /**
1193
- * Function isValidJsonString will tell you if the string is valid JSON or not
1194
- *
1195
- * @param value The string to check
1196
- * @returns True if the string is a valid JSON string, false otherwise
1301
+ * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
1197
1302
  *
1198
- * @public exported from `@promptbook/utils`
1303
+ * @public exported from `@promptbook/core`
1199
1304
  */
1200
- function isValidJsonString(value /* <- [👨‍⚖️] */) {
1201
- try {
1202
- JSON.parse(value);
1203
- return true;
1204
- }
1205
- catch (error) {
1206
- assertsError(error);
1207
- if (error.message.includes('Unexpected token')) {
1208
- return false;
1209
- }
1210
- return false;
1305
+ class PipelineLogicError extends Error {
1306
+ constructor(message) {
1307
+ super(message);
1308
+ this.name = 'PipelineLogicError';
1309
+ Object.setPrototypeOf(this, PipelineLogicError.prototype);
1211
1310
  }
1212
1311
  }
1213
1312
 
1214
1313
  /**
1215
- * Converts a JavaScript Object Notation (JSON) string into an object.
1216
- *
1217
- * Note: This is wrapper around `JSON.parse()` with better error and type handling
1314
+ * This error indicates errors in referencing promptbooks between each other
1218
1315
  *
1219
- * @public exported from `@promptbook/utils`
1316
+ * @public exported from `@promptbook/core`
1220
1317
  */
1221
- function jsonParse(value) {
1222
- if (value === undefined) {
1223
- throw new Error(`Can not parse JSON from undefined value.`);
1224
- }
1225
- else if (typeof value !== 'string') {
1226
- console.error('Can not parse JSON from non-string value.', { text: value });
1227
- throw new Error(spaceTrim__default["default"](`
1228
- Can not parse JSON from non-string value.
1229
-
1230
- The value type: ${typeof value}
1231
- See more in console.
1232
- `));
1233
- }
1234
- try {
1235
- return JSON.parse(value);
1236
- }
1237
- catch (error) {
1238
- if (!(error instanceof Error)) {
1239
- throw error;
1240
- }
1241
- throw new Error(spaceTrim__default["default"]((block) => `
1242
- ${block(error.message)}
1243
-
1244
- The JSON text:
1245
- ${block(value)}
1246
- `));
1318
+ class PipelineUrlError extends Error {
1319
+ constructor(message) {
1320
+ super(message);
1321
+ this.name = 'PipelineUrlError';
1322
+ Object.setPrototypeOf(this, PipelineUrlError.prototype);
1247
1323
  }
1248
1324
  }
1249
- /**
1250
- * TODO: !!!! Use in Promptbook.studio
1251
- */
1252
1325
 
1253
1326
  /**
1254
- * Function to check if a string is valid XML
1255
- *
1256
- * @param value
1257
- * @returns True if the string is a valid XML string, false otherwise
1327
+ * Error thrown when a fetch request fails
1258
1328
  *
1259
- * @public exported from `@promptbook/utils`
1329
+ * @public exported from `@promptbook/core`
1260
1330
  */
1261
- function isValidXmlString(value) {
1262
- try {
1263
- const parser = new DOMParser();
1264
- const parsedDocument = parser.parseFromString(value, 'application/xml');
1265
- const parserError = parsedDocument.getElementsByTagName('parsererror');
1266
- if (parserError.length > 0) {
1267
- return false;
1268
- }
1269
- return true;
1270
- }
1271
- catch (error) {
1272
- assertsError(error);
1273
- return false;
1331
+ class PromptbookFetchError extends Error {
1332
+ constructor(message) {
1333
+ super(message);
1334
+ this.name = 'PromptbookFetchError';
1335
+ Object.setPrototypeOf(this, PromptbookFetchError.prototype);
1274
1336
  }
1275
1337
  }
1276
1338
 
1277
1339
  /**
1278
- * Orders JSON object by keys
1340
+ * Index of all custom errors
1279
1341
  *
1280
- * @returns The same type of object as the input re-ordered
1281
- * @public exported from `@promptbook/utils`
1342
+ * @public exported from `@promptbook/core`
1282
1343
  */
1283
- function orderJson(options) {
1284
- const { value, order } = options;
1285
- const orderedValue = {
1286
- ...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
1287
- ...value,
1288
- };
1289
- return orderedValue;
1290
- }
1291
-
1344
+ const PROMPTBOOK_ERRORS = {
1345
+ AbstractFormatError,
1346
+ CsvFormatError,
1347
+ CollectionError,
1348
+ EnvironmentMismatchError,
1349
+ ExpectError,
1350
+ KnowledgeScrapeError,
1351
+ LimitReachedError,
1352
+ MissingToolsError,
1353
+ NotFoundError,
1354
+ NotYetImplementedError,
1355
+ ParseError,
1356
+ PipelineExecutionError,
1357
+ PipelineLogicError,
1358
+ PipelineUrlError,
1359
+ AuthenticationError,
1360
+ PromptbookFetchError,
1361
+ UnexpectedError,
1362
+ WrappedError,
1363
+ // TODO: [🪑]> VersionMismatchError,
1364
+ };
1292
1365
  /**
1293
- * Freezes the given object and all its nested objects recursively
1366
+ * Index of all javascript errors
1294
1367
  *
1295
- * Note: `$` is used to indicate that this function is not a pure function - it mutates given object
1296
- * Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
1368
+ * @private for internal usage
1369
+ */
1370
+ const COMMON_JAVASCRIPT_ERRORS = {
1371
+ Error,
1372
+ EvalError,
1373
+ RangeError,
1374
+ ReferenceError,
1375
+ SyntaxError,
1376
+ TypeError,
1377
+ URIError,
1378
+ AggregateError,
1379
+ /*
1380
+ Note: Not widely supported
1381
+ > InternalError,
1382
+ > ModuleError,
1383
+ > HeapError,
1384
+ > WebAssemblyCompileError,
1385
+ > WebAssemblyRuntimeError,
1386
+ */
1387
+ };
1388
+ /**
1389
+ * Index of all errors
1297
1390
  *
1298
- * @returns The same object as the input, but deeply frozen
1299
- * @public exported from `@promptbook/utils`
1391
+ * @private for internal usage
1300
1392
  */
1301
- function $deepFreeze(objectValue) {
1302
- if (Array.isArray(objectValue)) {
1303
- return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
1304
- }
1305
- const propertyNames = Object.getOwnPropertyNames(objectValue);
1306
- for (const propertyName of propertyNames) {
1307
- const value = objectValue[propertyName];
1308
- if (value && typeof value === 'object') {
1309
- $deepFreeze(value);
1310
- }
1311
- }
1312
- Object.freeze(objectValue);
1313
- return objectValue;
1314
- }
1393
+ const ALL_ERRORS = {
1394
+ ...PROMPTBOOK_ERRORS,
1395
+ ...COMMON_JAVASCRIPT_ERRORS,
1396
+ };
1315
1397
  /**
1316
- * TODO: [🧠] Is there a way how to meaningfully test this utility
1398
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1317
1399
  */
1318
1400
 
1319
1401
  /**
1320
- * Checks if the value is [🚉] serializable as JSON
1321
- * If not, throws an UnexpectedError with a rich error message and tracking
1322
- *
1323
- * - Almost all primitives are serializable BUT:
1324
- * - `undefined` is not serializable
1325
- * - `NaN` is not serializable
1326
- * - Objects and arrays are serializable if all their properties are serializable
1327
- * - Functions are not serializable
1328
- * - Circular references are not serializable
1329
- * - `Date` objects are not serializable
1330
- * - `Map` and `Set` objects are not serializable
1331
- * - `RegExp` objects are not serializable
1332
- * - `Error` objects are not serializable
1333
- * - `Symbol` objects are not serializable
1334
- * - And much more...
1402
+ * Deserializes the error object
1335
1403
  *
1336
- * @throws UnexpectedError if the value is not serializable as JSON
1337
1404
  * @public exported from `@promptbook/utils`
1338
1405
  */
1339
- function checkSerializableAsJson(options) {
1340
- const { value, name, message } = options;
1341
- if (value === undefined) {
1342
- throw new UnexpectedError(`${name} is undefined`);
1343
- }
1344
- else if (value === null) {
1345
- return;
1346
- }
1347
- else if (typeof value === 'boolean') {
1348
- return;
1349
- }
1350
- else if (typeof value === 'number' && !isNaN(value)) {
1351
- return;
1352
- }
1353
- else if (typeof value === 'string') {
1354
- return;
1355
- }
1356
- else if (typeof value === 'symbol') {
1357
- throw new UnexpectedError(`${name} is symbol`);
1358
- }
1359
- else if (typeof value === 'function') {
1360
- throw new UnexpectedError(`${name} is function`);
1361
- }
1362
- else if (typeof value === 'object' && Array.isArray(value)) {
1363
- for (let i = 0; i < value.length; i++) {
1364
- checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
1365
- }
1406
+ function deserializeError(error) {
1407
+ const { name, stack, id } = error; // Added id
1408
+ let { message } = error;
1409
+ let ErrorClass = ALL_ERRORS[error.name];
1410
+ if (ErrorClass === undefined) {
1411
+ ErrorClass = Error;
1412
+ message = `${name}: ${message}`;
1366
1413
  }
1367
- else if (typeof value === 'object') {
1368
- if (value instanceof Date) {
1369
- throw new UnexpectedError(spaceTrim__default["default"]((block) => `
1370
- \`${name}\` is Date
1371
-
1372
- Use \`string_date_iso8601\` instead
1414
+ if (stack !== undefined && stack !== '') {
1415
+ message = spaceTrim__default["default"]((block) => `
1416
+ ${block(message)}
1373
1417
 
1374
- Additional message for \`${name}\`:
1375
- ${block(message || '(nothing)')}
1376
- `));
1377
- }
1378
- else if (value instanceof Map) {
1379
- throw new UnexpectedError(`${name} is Map`);
1380
- }
1381
- else if (value instanceof Set) {
1382
- throw new UnexpectedError(`${name} is Set`);
1383
- }
1384
- else if (value instanceof RegExp) {
1385
- throw new UnexpectedError(`${name} is RegExp`);
1386
- }
1387
- else if (value instanceof Error) {
1388
- throw new UnexpectedError(spaceTrim__default["default"]((block) => `
1389
- \`${name}\` is unserialized Error
1418
+ Original stack trace:
1419
+ ${block(stack || '')}
1420
+ `);
1421
+ }
1422
+ const deserializedError = new ErrorClass(message);
1423
+ deserializedError.id = id; // Assign id to the error object
1424
+ return deserializedError;
1425
+ }
1390
1426
 
1391
- Use function \`serializeError\`
1427
+ /**
1428
+ * Serializes an error into a [🚉] JSON-serializable object
1429
+ *
1430
+ * @public exported from `@promptbook/utils`
1431
+ */
1432
+ function serializeError(error) {
1433
+ const { name, message, stack } = error;
1434
+ const { id } = error;
1435
+ if (!Object.keys(ALL_ERRORS).includes(name)) {
1436
+ console.error(spaceTrim__default["default"]((block) => `
1392
1437
 
1393
- Additional message for \`${name}\`:
1394
- ${block(message || '(nothing)')}
1438
+ Cannot serialize error with name "${name}"
1395
1439
 
1396
- `));
1397
- }
1398
- else {
1399
- for (const [subName, subValue] of Object.entries(value)) {
1400
- if (subValue === undefined) {
1401
- // Note: undefined in object is serializable - it is just omited
1402
- continue;
1403
- }
1404
- checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
1405
- }
1406
- try {
1407
- JSON.stringify(value); // <- TODO: [0]
1408
- }
1409
- catch (error) {
1410
- assertsError(error);
1411
- throw new UnexpectedError(spaceTrim__default["default"]((block) => `
1412
- \`${name}\` is not serializable
1440
+ Authors of Promptbook probably forgot to add this error into the list of errors:
1441
+ https://github.com/webgptorg/promptbook/blob/main/src/errors/0-index.ts
1413
1442
 
1414
- ${block(error.stack || error.message)}
1415
1443
 
1416
- Additional message for \`${name}\`:
1417
- ${block(message || '(nothing)')}
1418
- `));
1419
- }
1420
- /*
1421
- TODO: [0] Is there some more elegant way to check circular references?
1422
- const seen = new Set();
1423
- const stack = [{ value }];
1424
- while (stack.length > 0) {
1425
- const { value } = stack.pop()!;
1426
- if (typeof value === 'object' && value !== null) {
1427
- if (seen.has(value)) {
1428
- throw new UnexpectedError(`${name} has circular reference`);
1429
- }
1430
- seen.add(value);
1431
- if (Array.isArray(value)) {
1432
- stack.push(...value.map((value) => ({ value })));
1433
- } else {
1434
- stack.push(...Object.values(value).map((value) => ({ value })));
1435
- }
1436
- }
1437
- }
1438
- */
1439
- return;
1440
- }
1441
- }
1442
- else {
1443
- throw new UnexpectedError(spaceTrim__default["default"]((block) => `
1444
- \`${name}\` is unknown type
1444
+ ${block(stack || message)}
1445
1445
 
1446
- Additional message for \`${name}\`:
1447
- ${block(message || '(nothing)')}
1448
1446
  `));
1449
1447
  }
1448
+ return {
1449
+ name: name,
1450
+ message,
1451
+ stack,
1452
+ id, // Include id in the serialized object
1453
+ };
1450
1454
  }
1451
- /**
1452
- * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
1453
- * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
1454
- * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
1455
- */
1456
1455
 
1457
1456
  /**
1458
- * @@@
1457
+ * Async version of Array.forEach
1459
1458
  *
1459
+ * @param array - Array to iterate over
1460
+ * @param options - Options for the function
1461
+ * @param callbackfunction - Function to call for each item
1460
1462
  * @public exported from `@promptbook/utils`
1463
+ * @deprecated [🪂] Use queues instead
1461
1464
  */
1462
- function deepClone(objectValue) {
1463
- return JSON.parse(JSON.stringify(objectValue));
1464
- /*
1465
- TODO: [🧠] Is there a better implementation?
1466
- > const propertyNames = Object.getOwnPropertyNames(objectValue);
1467
- > for (const propertyName of propertyNames) {
1468
- > const value = (objectValue as really_any)[propertyName];
1469
- > if (value && typeof value === 'object') {
1470
- > deepClone(value);
1471
- > }
1472
- > }
1473
- > return Object.assign({}, objectValue);
1474
- */
1465
+ async function forEachAsync(array, options, callbackfunction) {
1466
+ const { maxParallelCount = Infinity } = options;
1467
+ let index = 0;
1468
+ let runningTasks = [];
1469
+ const tasks = [];
1470
+ for (const item of array) {
1471
+ const currentIndex = index++;
1472
+ const task = callbackfunction(item, currentIndex, array);
1473
+ tasks.push(task);
1474
+ runningTasks.push(task);
1475
+ /* not await */ Promise.resolve(task).then(() => {
1476
+ runningTasks = runningTasks.filter((t) => t !== task);
1477
+ });
1478
+ if (maxParallelCount < runningTasks.length) {
1479
+ await Promise.race(runningTasks);
1480
+ }
1481
+ }
1482
+ await Promise.all(tasks);
1475
1483
  }
1476
- /**
1477
- * TODO: [🧠] Is there a way how to meaningfully test this utility
1478
- */
1479
1484
 
1480
1485
  /**
1481
- * Utility to export a JSON object from a function
1482
- *
1483
- * 1) Checks if the value is serializable as JSON
1484
- * 2) Makes a deep clone of the object
1485
- * 2) Orders the object properties
1486
- * 2) Deeply freezes the cloned object
1486
+ * Function to check if a string is valid CSV
1487
1487
  *
1488
- * Note: This function does not mutates the given object
1488
+ * @param value The string to check
1489
+ * @returns `true` if the string is a valid CSV string, false otherwise
1489
1490
  *
1490
- * @returns The same type of object as the input but read-only and re-ordered
1491
1491
  * @public exported from `@promptbook/utils`
1492
1492
  */
1493
- function exportJson(options) {
1494
- const { name, value, order, message } = options;
1495
- checkSerializableAsJson({ name, value, message });
1496
- const orderedValue =
1497
- // TODO: Fix error "Type instantiation is excessively deep and possibly infinite."
1498
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1499
- // @ts-ignore
1500
- order === undefined
1501
- ? deepClone(value)
1502
- : orderJson({
1503
- value: value,
1504
- // <- Note: checkSerializableAsJson asserts that the value is serializable as JSON
1505
- order: order,
1506
- });
1507
- $deepFreeze(orderedValue);
1508
- return orderedValue;
1493
+ function isValidCsvString(value) {
1494
+ try {
1495
+ // A simple check for CSV format: at least one comma and no invalid characters
1496
+ if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
1497
+ return true;
1498
+ }
1499
+ return false;
1500
+ }
1501
+ catch (error) {
1502
+ assertsError(error);
1503
+ return false;
1504
+ }
1509
1505
  }
1510
- /**
1511
- * TODO: [🧠] Is there a way how to meaningfully test this utility
1512
- */
1513
1506
 
1514
1507
  /**
1515
- * Nonce which is used for replacing things in strings
1508
+ * Function isValidJsonString will tell you if the string is valid JSON or not
1516
1509
  *
1517
- * @private within the repository
1518
- */
1519
- const REPLACING_NONCE = 'ptbkauk42kV2dzao34faw7FudQUHYPtW';
1520
- /**
1521
- * @@@
1510
+ * @param value The string to check
1511
+ * @returns `true` if the string is a valid JSON string, false otherwise
1522
1512
  *
1523
- * @private within the repository
1513
+ * @public exported from `@promptbook/utils`
1524
1514
  */
1525
- const RESERVED_PARAMETER_MISSING_VALUE = 'MISSING-' + REPLACING_NONCE;
1515
+ function isValidJsonString(value /* <- [👨‍⚖️] */) {
1516
+ try {
1517
+ JSON.parse(value);
1518
+ return true;
1519
+ }
1520
+ catch (error) {
1521
+ assertsError(error);
1522
+ if (error.message.includes('Unexpected token')) {
1523
+ return false;
1524
+ }
1525
+ return false;
1526
+ }
1527
+ }
1528
+
1526
1529
  /**
1527
- * @@@
1530
+ * Converts a JavaScript Object Notation (JSON) string into an object.
1528
1531
  *
1529
- * @private within the repository
1530
- */
1531
- const RESERVED_PARAMETER_RESTRICTED = 'RESTRICTED-' + REPLACING_NONCE;
1532
- /**
1533
- * The names of the parameters that are reserved for special purposes
1532
+ * Note: This is wrapper around `JSON.parse()` with better error and type handling
1534
1533
  *
1535
- * @public exported from `@promptbook/core`
1534
+ * @public exported from `@promptbook/utils`
1536
1535
  */
1537
- exportJson({
1538
- name: 'RESERVED_PARAMETER_NAMES',
1539
- message: `The names of the parameters that are reserved for special purposes`,
1540
- value: [
1541
- 'content',
1542
- 'context',
1543
- 'knowledge',
1544
- 'examples',
1545
- 'modelName',
1546
- 'currentDate',
1547
- // <- TODO: list here all command names
1548
- // <- TODO: Add more like 'date', 'modelName',...
1549
- // <- TODO: Add [emoji] + instructions ACRY when adding new reserved parameter
1550
- ],
1551
- });
1536
+ function jsonParse(value) {
1537
+ if (value === undefined) {
1538
+ throw new Error(`Can not parse JSON from undefined value.`);
1539
+ }
1540
+ else if (typeof value !== 'string') {
1541
+ console.error('Can not parse JSON from non-string value.', { text: value });
1542
+ throw new Error(spaceTrim__default["default"](`
1543
+ Can not parse JSON from non-string value.
1544
+
1545
+ The value type: ${typeof value}
1546
+ See more in console.
1547
+ `));
1548
+ }
1549
+ try {
1550
+ return JSON.parse(value);
1551
+ }
1552
+ catch (error) {
1553
+ if (!(error instanceof Error)) {
1554
+ throw error;
1555
+ }
1556
+ throw new Error(spaceTrim__default["default"]((block) => `
1557
+ ${block(error.message)}
1558
+
1559
+ The JSON text:
1560
+ ${block(value)}
1561
+ `));
1562
+ }
1563
+ }
1564
+
1552
1565
  /**
1553
- * Note: [💞] Ignore a discrepancy between file name and entity name
1566
+ * Function to check if a string is valid XML
1567
+ *
1568
+ * @param value
1569
+ * @returns `true` if the string is a valid XML string, false otherwise
1570
+ *
1571
+ * @public exported from `@promptbook/utils`
1554
1572
  */
1573
+ function isValidXmlString(value) {
1574
+ try {
1575
+ const parser = new DOMParser();
1576
+ const parsedDocument = parser.parseFromString(value, 'application/xml');
1577
+ const parserError = parsedDocument.getElementsByTagName('parsererror');
1578
+ if (parserError.length > 0) {
1579
+ return false;
1580
+ }
1581
+ return true;
1582
+ }
1583
+ catch (error) {
1584
+ assertsError(error);
1585
+ return false;
1586
+ }
1587
+ }
1555
1588
 
1556
1589
  /**
1557
1590
  * Format either small or big number
@@ -1988,7 +2021,7 @@
1988
2021
  PAGES: countPages,
1989
2022
  };
1990
2023
  /**
1991
- * TODO: [🧠][🤠] This should be probbably as part of `TextFormatDefinition`
2024
+ * TODO: [🧠][🤠] This should be probably as part of `TextFormatParser`
1992
2025
  * Note: [💞] Ignore a discrepancy between file name and entity name
1993
2026
  */
1994
2027
 
@@ -2011,10 +2044,10 @@
2011
2044
  }
2012
2045
 
2013
2046
  /**
2014
- * @@@
2047
+ * Normalizes a text string to SCREAMING_CASE (all uppercase with underscores).
2015
2048
  *
2016
- * @param text @@@
2017
- * @returns @@@
2049
+ * @param text The text string to be converted to SCREAMING_CASE format.
2050
+ * @returns The normalized text in SCREAMING_CASE format.
2018
2051
  * @example 'HELLO_WORLD'
2019
2052
  * @example 'I_LOVE_PROMPTBOOK'
2020
2053
  * @public exported from `@promptbook/utils`
@@ -2099,11 +2132,11 @@
2099
2132
  }
2100
2133
 
2101
2134
  /**
2102
- * @@@
2135
+ * Converts a name string into a URI-compatible format.
2103
2136
  *
2104
- * @param name @@@
2105
- * @returns @@@
2106
- * @example @@@
2137
+ * @param name The string to be converted to a URI-compatible format.
2138
+ * @returns A URI-compatible string derived from the input name.
2139
+ * @example 'Hello World' -> 'hello-world'
2107
2140
  * @public exported from `@promptbook/utils`
2108
2141
  */
2109
2142
  function nameToUriPart(name) {
@@ -2117,11 +2150,11 @@
2117
2150
  }
2118
2151
 
2119
2152
  /**
2120
- * @@@
2153
+ * Converts a given name into URI-compatible parts.
2121
2154
  *
2122
- * @param name @@@
2123
- * @returns @@@
2124
- * @example @@@
2155
+ * @param name The name to be converted into URI parts.
2156
+ * @returns An array of URI-compatible parts derived from the name.
2157
+ * @example 'Example Name' -> ['example', 'name']
2125
2158
  * @public exported from `@promptbook/utils`
2126
2159
  */
2127
2160
  function nameToUriParts(name) {
@@ -2143,10 +2176,10 @@
2143
2176
  }
2144
2177
 
2145
2178
  /**
2146
- * @@@
2179
+ * Normalizes a text string to snake_case format.
2147
2180
  *
2148
- * @param text @@@
2149
- * @returns @@@
2181
+ * @param text The text string to be converted to snake_case format.
2182
+ * @returns The normalized text in snake_case format.
2150
2183
  * @example 'hello_world'
2151
2184
  * @example 'i_love_promptbook'
2152
2185
  * @public exported from `@promptbook/utils`
@@ -2198,7 +2231,7 @@
2198
2231
  */
2199
2232
 
2200
2233
  /**
2201
- * @@@
2234
+ * Searches set of keywords for a specific keyword
2202
2235
  *
2203
2236
  * @param haystack
2204
2237
  * @param needle
@@ -2213,6 +2246,9 @@
2213
2246
  }
2214
2247
  return true;
2215
2248
  }
2249
+ /**
2250
+ * TODO: Rename to `isKeywordInKeywords`
2251
+ */
2216
2252
 
2217
2253
  /**
2218
2254
  * Adds suffix to the URL
@@ -2324,9 +2360,9 @@
2324
2360
  /**
2325
2361
  * Removes quotes from a string
2326
2362
  *
2327
- * Tip: This is very usefull for post-processing of the result of the LLM model
2363
+ * Tip: This is very useful for post-processing of the result of the LLM model
2328
2364
  * Note: This function removes only the same quotes from the beginning and the end of the string
2329
- * Note: There are two simmilar functions:
2365
+ * Note: There are two similar functions:
2330
2366
  * - `removeQuotes` which removes only bounding quotes
2331
2367
  * - `unwrapResult` which removes whole introduce sentence
2332
2368
  *
@@ -2338,22 +2374,23 @@
2338
2374
  if (text.startsWith('"') && text.endsWith('"')) {
2339
2375
  return text.slice(1, -1);
2340
2376
  }
2341
- if (text.startsWith('\'') && text.endsWith('\'')) {
2377
+ if (text.startsWith("'") && text.endsWith("'")) {
2342
2378
  return text.slice(1, -1);
2343
2379
  }
2344
2380
  return text;
2345
2381
  }
2346
2382
 
2347
2383
  /**
2348
- * @@@
2384
+ * Creates a deep clone of a PipelineJson object, copying all properties explicitly.
2349
2385
  *
2350
- * Note: It is usefull @@@
2386
+ * Note: It is useful for ensuring that modifications to the returned pipeline do not affect the original.
2351
2387
  *
2352
- * @param pipeline
2388
+ * @param pipeline The pipeline to clone.
2389
+ * @returns A new PipelineJson object with the same properties as the input.
2353
2390
  * @public exported from `@promptbook/utils`
2354
2391
  */
2355
2392
  function clonePipeline(pipeline) {
2356
- // Note: Not using spread operator (...) because @@@
2393
+ // Note: Not using spread operator (...) because it does not deeply copy nested objects and may miss non-enumerable properties.
2357
2394
  const { pipelineUrl, sourceFile, title, bookVersion, description, formfactorName, parameters, tasks, knowledgeSources, knowledgePieces, personas, preparations, sources, } = pipeline;
2358
2395
  return {
2359
2396
  pipelineUrl,
@@ -2502,7 +2539,7 @@
2502
2539
  /**
2503
2540
  * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
2504
2541
  *
2505
- * Note: This is usefull for post-processing of the result of the chat LLM model
2542
+ * Note: This is useful for post-processing of the result of the chat LLM model
2506
2543
  * when the model wraps the result in the (markdown) code block.
2507
2544
  *
2508
2545
  * @public exported from `@promptbook/utils`
@@ -2521,7 +2558,7 @@
2521
2558
  /**
2522
2559
  * Function trimEndOfCodeBlock will remove ending code block from the string if it is present.
2523
2560
  *
2524
- * Note: This is usefull for post-processing of the result of the completion LLM model
2561
+ * Note: This is useful for post-processing of the result of the completion LLM model
2525
2562
  * if you want to start code block in the prompt but you don't want to end it in the result.
2526
2563
  *
2527
2564
  * @public exported from `@promptbook/utils`
@@ -2536,9 +2573,9 @@
2536
2573
  /**
2537
2574
  * Removes quotes and optional introduce text from a string
2538
2575
  *
2539
- * Tip: This is very usefull for post-processing of the result of the LLM model
2576
+ * Tip: This is very useful for post-processing of the result of the LLM model
2540
2577
  * Note: This function trims the text and removes whole introduce sentence if it is present
2541
- * Note: There are two simmilar functions:
2578
+ * Note: There are two similar functions:
2542
2579
  * - `removeQuotes` which removes only bounding quotes
2543
2580
  * - `unwrapResult` which removes whole introduce sentence
2544
2581
  *
@@ -2639,10 +2676,10 @@
2639
2676
  */
2640
2677
 
2641
2678
  /**
2642
- * @@@
2679
+ * Checks if the given value is a valid JavaScript identifier name.
2643
2680
  *
2644
- * @param javascriptName @@@
2645
- * @returns @@@
2681
+ * @param javascriptName The value to check for JavaScript identifier validity.
2682
+ * @returns `true` if the value is a valid JavaScript name, false otherwise.
2646
2683
  * @public exported from `@promptbook/utils`
2647
2684
  */
2648
2685
  function isValidJavascriptName(javascriptName) {
@@ -2655,7 +2692,7 @@
2655
2692
  /**
2656
2693
  * Tests if given string is valid semantic version
2657
2694
  *
2658
- * Note: There are two simmilar functions:
2695
+ * Note: There are two similar functions:
2659
2696
  * - `isValidSemanticVersion` which tests any semantic version
2660
2697
  * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
2661
2698
  *
@@ -2677,7 +2714,7 @@
2677
2714
  *
2678
2715
  * @see https://www.npmjs.com/package/promptbook?activeTab=versions
2679
2716
  * Note: When you are using for example promptbook 2.0.0 and there already is promptbook 3.0.0 it don`t know about it.
2680
- * Note: There are two simmilar functions:
2717
+ * Note: There are two similar functions:
2681
2718
  * - `isValidSemanticVersion` which tests any semantic version
2682
2719
  * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
2683
2720
  *
@@ -2697,7 +2734,7 @@
2697
2734
  /**
2698
2735
  * Checks if an URL is reserved for private networks or localhost.
2699
2736
  *
2700
- * Note: There are two simmilar functions:
2737
+ * Note: There are two similar functions:
2701
2738
  * - `isUrlOnPrivateNetwork` which tests full URL
2702
2739
  * - `isHostnameOnPrivateNetwork` *(this one)* which tests just hostname
2703
2740
  *
@@ -2730,7 +2767,7 @@
2730
2767
  /**
2731
2768
  * Checks if an IP address or hostname is reserved for private networks or localhost.
2732
2769
  *
2733
- * Note: There are two simmilar functions:
2770
+ * Note: There are two similar functions:
2734
2771
  * - `isUrlOnPrivateNetwork` *(this one)* which tests full URL
2735
2772
  * - `isHostnameOnPrivateNetwork` which tests just hostname
2736
2773
  *
@@ -2748,7 +2785,7 @@
2748
2785
  /**
2749
2786
  * Tests if given string is valid pipeline URL URL.
2750
2787
  *
2751
- * Note: There are two simmilar functions:
2788
+ * Note: There are two similar functions:
2752
2789
  * - `isValidUrl` which tests any URL
2753
2790
  * - `isValidPipelineUrl` *(this one)* which tests just pipeline URL
2754
2791
  *