@promptbook/node 0.95.0 β†’ 0.98.0-10

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 (25) hide show
  1. package/README.md +12 -0
  2. package/esm/index.es.js +257 -194
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/anthropic-claude.index.d.ts +2 -2
  5. package/esm/typings/src/_packages/cli.index.d.ts +4 -0
  6. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  7. package/esm/typings/src/_packages/openai.index.d.ts +10 -0
  8. package/esm/typings/src/_packages/types.index.d.ts +12 -2
  9. package/esm/typings/src/_packages/wizard.index.d.ts +4 -0
  10. package/esm/typings/src/config.d.ts +1 -1
  11. package/esm/typings/src/execution/createPipelineExecutor/$OngoingTaskResult.d.ts +8 -0
  12. package/esm/typings/src/execution/utils/validatePromptResult.d.ts +53 -0
  13. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +3 -3
  14. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +2 -2
  15. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +2 -2
  16. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +4 -4
  17. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionToolsOptions.d.ts +52 -0
  18. package/esm/typings/src/llm-providers/openai/OpenAiExecutionToolsOptions.d.ts +3 -5
  19. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +74 -0
  20. package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +11 -0
  21. package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +14 -0
  22. package/esm/typings/src/version.d.ts +1 -1
  23. package/package.json +2 -2
  24. package/umd/index.umd.js +257 -194
  25. package/umd/index.umd.js.map +1 -1
package/README.md CHANGED
@@ -25,6 +25,10 @@ Write AI applications using plain human language across multiple models and plat
25
25
 
26
26
 
27
27
 
28
+ <blockquote style="color: #ff8811">
29
+ <b>⚠ Warning:</b> This is a pre-release version of the library. It is not yet ready for production use. Please look at <a href="https://www.npmjs.com/package/@promptbook/core?activeTab=versions">latest stable release</a>.
30
+ </blockquote>
31
+
28
32
  ## πŸ“¦ Package `@promptbook/node`
29
33
 
30
34
  - Promptbooks are [divided into several](#-packages) packages, all are published from [single monorepo](https://github.com/webgptorg/promptbook).
@@ -60,6 +64,8 @@ Rest of the documentation is common for **entire promptbook ecosystem**:
60
64
 
61
65
  During the computer revolution, we have seen [multiple generations of computer languages](https://github.com/webgptorg/promptbook/discussions/180), from the physical rewiring of the vacuum tubes through low-level machine code to the high-level languages like Python or JavaScript. And now, we're on the edge of the **next revolution**!
62
66
 
67
+
68
+
63
69
  It's a revolution of writing software in **plain human language** that is understandable and executable by both humans and machines – and it's going to change everything!
64
70
 
65
71
  The incredible growth in power of microprocessors and the Moore's Law have been the driving force behind the ever-more powerful languages, and it's been an amazing journey! Similarly, the large language models (like GPT or Claude) are the next big thing in language technology, and they're set to transform the way we interact with computers.
@@ -185,6 +191,8 @@ Join our growing community of developers and users:
185
191
 
186
192
  _A concise, Markdown-based DSL for crafting AI workflows and automations._
187
193
 
194
+
195
+
188
196
  ### Introduction
189
197
 
190
198
  Book is a Markdown-based language that simplifies the creation of AI applications, workflows, and automations. With human-readable commands, you can define inputs, outputs, personas, knowledge sources, and actionsβ€”without needing model-specific details.
@@ -234,6 +242,8 @@ Personas can have access to different knowledge, tools and actions. They can als
234
242
 
235
243
  - [PERSONA](https://github.com/webgptorg/promptbook/blob/main/documents/commands/PERSONA.md)
236
244
 
245
+
246
+
237
247
  ### **3. How:** Knowledge, Instruments and Actions
238
248
 
239
249
  The resources used by the personas are used to do the work.
@@ -333,6 +343,8 @@ The following glossary is used to clarify certain concepts:
333
343
 
334
344
  _Note: This section is not a complete dictionary, more list of general AI / LLM terms that has connection with Promptbook_
335
345
 
346
+
347
+
336
348
  ### πŸ’― Core concepts
337
349
 
338
350
  - [πŸ“š Collection of pipelines](https://github.com/webgptorg/promptbook/discussions/65)
package/esm/index.es.js CHANGED
@@ -30,7 +30,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
30
30
  * @generated
31
31
  * @see https://github.com/webgptorg/promptbook
32
32
  */
33
- const PROMPTBOOK_ENGINE_VERSION = '0.95.0';
33
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-10';
34
34
  /**
35
35
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
36
36
  * Note: [πŸ’ž] Ignore a discrepancy between file name and entity name
@@ -174,7 +174,7 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
174
174
  *
175
175
  * @public exported from `@promptbook/core`
176
176
  */
177
- const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
177
+ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
178
178
  // <- TODO: [πŸ•] Make also `BOOKS_DIRNAME_ALTERNATIVES`
179
179
  // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
180
180
  /**
@@ -344,7 +344,7 @@ function jsonParse(value) {
344
344
  throw new Error(spaceTrim((block) => `
345
345
  ${block(error.message)}
346
346
 
347
- The JSON text:
347
+ The expected JSON text:
348
348
  ${block(value)}
349
349
  `));
350
350
  }
@@ -3105,108 +3105,6 @@ function joinLlmExecutionTools(...llmExecutionTools) {
3105
3105
  * TODO: [πŸ‘·β€β™‚οΈ] @@@ Manual about construction of llmTools
3106
3106
  */
3107
3107
 
3108
- /**
3109
- * Extracts all code blocks from markdown.
3110
- *
3111
- * Note: There are multiple similar functions:
3112
- * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
3113
- * - `extractJsonBlock` extracts exactly one valid JSON code block
3114
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3115
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3116
- *
3117
- * @param markdown any valid markdown
3118
- * @returns code blocks with language and content
3119
- * @throws {ParseError} if block is not closed properly
3120
- * @public exported from `@promptbook/markdown-utils`
3121
- */
3122
- function extractAllBlocksFromMarkdown(markdown) {
3123
- const codeBlocks = [];
3124
- const lines = markdown.split('\n');
3125
- // Note: [0] Ensure that the last block notated by gt > will be closed
3126
- lines.push('');
3127
- let currentCodeBlock = null;
3128
- for (const line of lines) {
3129
- if (line.startsWith('> ') || line === '>') {
3130
- if (currentCodeBlock === null) {
3131
- currentCodeBlock = { blockNotation: '>', language: null, content: '' };
3132
- } /* not else */
3133
- if (currentCodeBlock.blockNotation === '>') {
3134
- if (currentCodeBlock.content !== '') {
3135
- currentCodeBlock.content += '\n';
3136
- }
3137
- currentCodeBlock.content += line.slice(2);
3138
- }
3139
- }
3140
- else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '>' /* <- Note: [0] */) {
3141
- codeBlocks.push(currentCodeBlock);
3142
- currentCodeBlock = null;
3143
- }
3144
- /* not else */
3145
- if (line.startsWith('```')) {
3146
- const language = line.slice(3).trim() || null;
3147
- if (currentCodeBlock === null) {
3148
- currentCodeBlock = { blockNotation: '```', language, content: '' };
3149
- }
3150
- else {
3151
- if (language !== null) {
3152
- throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed and already opening new ${language} code block`);
3153
- }
3154
- codeBlocks.push(currentCodeBlock);
3155
- currentCodeBlock = null;
3156
- }
3157
- }
3158
- else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '```') {
3159
- if (currentCodeBlock.content !== '') {
3160
- currentCodeBlock.content += '\n';
3161
- }
3162
- currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make proper unescape */;
3163
- }
3164
- }
3165
- if (currentCodeBlock !== null) {
3166
- throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed at the end of the markdown`);
3167
- }
3168
- return codeBlocks;
3169
- }
3170
- /**
3171
- * TODO: Maybe name for `blockNotation` instead of '```' and '>'
3172
- */
3173
-
3174
- /**
3175
- * Extracts extracts exactly one valid JSON code block
3176
- *
3177
- * - When given string is a valid JSON as it is, it just returns it
3178
- * - When there is no JSON code block the function throws a `ParseError`
3179
- * - When there are multiple JSON code blocks the function throws a `ParseError`
3180
- *
3181
- * Note: It is not important if marked as ```json BUT if it is VALID JSON
3182
- * Note: There are multiple similar function:
3183
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
3184
- * - `extractJsonBlock` extracts exactly one valid JSON code block
3185
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3186
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3187
- *
3188
- * @public exported from `@promptbook/markdown-utils`
3189
- * @throws {ParseError} if there is no valid JSON block in the markdown
3190
- */
3191
- function extractJsonBlock(markdown) {
3192
- if (isValidJsonString(markdown)) {
3193
- return markdown;
3194
- }
3195
- const codeBlocks = extractAllBlocksFromMarkdown(markdown);
3196
- const jsonBlocks = codeBlocks.filter(({ content }) => isValidJsonString(content));
3197
- if (jsonBlocks.length === 0) {
3198
- throw new Error('There is no valid JSON block in the markdown');
3199
- }
3200
- if (jsonBlocks.length > 1) {
3201
- throw new Error('There are multiple JSON code blocks in the markdown');
3202
- }
3203
- return jsonBlocks[0].content;
3204
- }
3205
- /**
3206
- * TODO: Add some auto-healing logic + extract YAML, JSON5, TOML, etc.
3207
- * TODO: [🏒] Make this logic part of `JsonFormatParser` or `isValidJsonString`
3208
- */
3209
-
3210
3108
  /**
3211
3109
  * Takes an item or an array of items and returns an array of items
3212
3110
  *
@@ -3314,6 +3212,108 @@ function templateParameters(template, parameters) {
3314
3212
  return replacedTemplates;
3315
3213
  }
3316
3214
 
3215
+ /**
3216
+ * Extracts all code blocks from markdown.
3217
+ *
3218
+ * Note: There are multiple similar functions:
3219
+ * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
3220
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
3221
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3222
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3223
+ *
3224
+ * @param markdown any valid markdown
3225
+ * @returns code blocks with language and content
3226
+ * @throws {ParseError} if block is not closed properly
3227
+ * @public exported from `@promptbook/markdown-utils`
3228
+ */
3229
+ function extractAllBlocksFromMarkdown(markdown) {
3230
+ const codeBlocks = [];
3231
+ const lines = markdown.split('\n');
3232
+ // Note: [0] Ensure that the last block notated by gt > will be closed
3233
+ lines.push('');
3234
+ let currentCodeBlock = null;
3235
+ for (const line of lines) {
3236
+ if (line.startsWith('> ') || line === '>') {
3237
+ if (currentCodeBlock === null) {
3238
+ currentCodeBlock = { blockNotation: '>', language: null, content: '' };
3239
+ } /* not else */
3240
+ if (currentCodeBlock.blockNotation === '>') {
3241
+ if (currentCodeBlock.content !== '') {
3242
+ currentCodeBlock.content += '\n';
3243
+ }
3244
+ currentCodeBlock.content += line.slice(2);
3245
+ }
3246
+ }
3247
+ else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '>' /* <- Note: [0] */) {
3248
+ codeBlocks.push(currentCodeBlock);
3249
+ currentCodeBlock = null;
3250
+ }
3251
+ /* not else */
3252
+ if (line.startsWith('```')) {
3253
+ const language = line.slice(3).trim() || null;
3254
+ if (currentCodeBlock === null) {
3255
+ currentCodeBlock = { blockNotation: '```', language, content: '' };
3256
+ }
3257
+ else {
3258
+ if (language !== null) {
3259
+ throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed and already opening new ${language} code block`);
3260
+ }
3261
+ codeBlocks.push(currentCodeBlock);
3262
+ currentCodeBlock = null;
3263
+ }
3264
+ }
3265
+ else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '```') {
3266
+ if (currentCodeBlock.content !== '') {
3267
+ currentCodeBlock.content += '\n';
3268
+ }
3269
+ currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make proper unescape */;
3270
+ }
3271
+ }
3272
+ if (currentCodeBlock !== null) {
3273
+ throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed at the end of the markdown`);
3274
+ }
3275
+ return codeBlocks;
3276
+ }
3277
+ /**
3278
+ * TODO: Maybe name for `blockNotation` instead of '```' and '>'
3279
+ */
3280
+
3281
+ /**
3282
+ * Extracts extracts exactly one valid JSON code block
3283
+ *
3284
+ * - When given string is a valid JSON as it is, it just returns it
3285
+ * - When there is no JSON code block the function throws a `ParseError`
3286
+ * - When there are multiple JSON code blocks the function throws a `ParseError`
3287
+ *
3288
+ * Note: It is not important if marked as ```json BUT if it is VALID JSON
3289
+ * Note: There are multiple similar function:
3290
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
3291
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
3292
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3293
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3294
+ *
3295
+ * @public exported from `@promptbook/markdown-utils`
3296
+ * @throws {ParseError} if there is no valid JSON block in the markdown
3297
+ */
3298
+ function extractJsonBlock(markdown) {
3299
+ if (isValidJsonString(markdown)) {
3300
+ return markdown;
3301
+ }
3302
+ const codeBlocks = extractAllBlocksFromMarkdown(markdown);
3303
+ const jsonBlocks = codeBlocks.filter(({ content }) => isValidJsonString(content));
3304
+ if (jsonBlocks.length === 0) {
3305
+ throw new Error('There is no valid JSON block in the markdown');
3306
+ }
3307
+ if (jsonBlocks.length > 1) {
3308
+ throw new Error('There are multiple JSON code blocks in the markdown');
3309
+ }
3310
+ return jsonBlocks[0].content;
3311
+ }
3312
+ /**
3313
+ * TODO: Add some auto-healing logic + extract YAML, JSON5, TOML, etc.
3314
+ * TODO: [🏒] Make this logic part of `JsonFormatParser` or `isValidJsonString`
3315
+ */
3316
+
3317
3317
  /**
3318
3318
  * Counts number of characters in the text
3319
3319
  *
@@ -3735,6 +3735,68 @@ function checkExpectations(expectations, value) {
3735
3735
  * Note: [πŸ’] and [🀠] are interconnected together
3736
3736
  */
3737
3737
 
3738
+ /**
3739
+ * Validates a prompt result against expectations and format requirements.
3740
+ * This function provides a common abstraction for result validation that can be used
3741
+ * by both execution logic and caching logic to ensure consistency.
3742
+ *
3743
+ * @param options - The validation options including result string, expectations, and format
3744
+ * @returns Validation result with processed string and validity status
3745
+ * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
3746
+ */
3747
+ function validatePromptResult(options) {
3748
+ const { resultString, expectations, format } = options;
3749
+ let processedResultString = resultString;
3750
+ let validationError;
3751
+ try {
3752
+ // TODO: [πŸ’] Unite object for expecting amount and format
3753
+ if (format) {
3754
+ if (format === 'JSON') {
3755
+ if (!isValidJsonString(processedResultString)) {
3756
+ // TODO: [🏒] Do more universally via `FormatParser`
3757
+ try {
3758
+ processedResultString = extractJsonBlock(processedResultString);
3759
+ }
3760
+ catch (error) {
3761
+ keepUnused(error);
3762
+ throw new ExpectError(spaceTrim$1((block) => `
3763
+ Expected valid JSON string
3764
+
3765
+ The expected JSON text:
3766
+ ${block(processedResultString)}
3767
+ `));
3768
+ }
3769
+ }
3770
+ }
3771
+ else {
3772
+ throw new UnexpectedError(`Unknown format "${format}"`);
3773
+ }
3774
+ }
3775
+ // TODO: [πŸ’] Unite object for expecting amount and format
3776
+ if (expectations) {
3777
+ checkExpectations(expectations, processedResultString);
3778
+ }
3779
+ return {
3780
+ isValid: true,
3781
+ processedResultString,
3782
+ };
3783
+ }
3784
+ catch (error) {
3785
+ if (error instanceof ExpectError) {
3786
+ validationError = error;
3787
+ }
3788
+ else {
3789
+ // Re-throw non-ExpectError errors (like UnexpectedError)
3790
+ throw error;
3791
+ }
3792
+ return {
3793
+ isValid: false,
3794
+ processedResultString,
3795
+ error: validationError,
3796
+ };
3797
+ }
3798
+ }
3799
+
3738
3800
  /**
3739
3801
  * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
3740
3802
  * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
@@ -3752,17 +3814,18 @@ async function executeAttempts(options) {
3752
3814
  $resultString: null,
3753
3815
  $expectError: null,
3754
3816
  $scriptPipelineExecutionErrors: [],
3817
+ $failedResults: [], // Track all failed attempts
3755
3818
  };
3756
3819
  // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
3757
3820
  const _llms = arrayableToArray(tools.llm);
3758
3821
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
3759
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
3760
- const isJokerAttempt = attempt < 0;
3761
- const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
3822
+ attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
3823
+ const isJokerAttempt = attemptIndex < 0;
3824
+ const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
3762
3825
  // TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
3763
3826
  if (isJokerAttempt && !jokerParameterName) {
3764
3827
  throw new UnexpectedError(spaceTrim$1((block) => `
3765
- Joker not found in attempt ${attempt}
3828
+ Joker not found in attempt ${attemptIndex}
3766
3829
 
3767
3830
  ${block(pipelineIdentification)}
3768
3831
  `));
@@ -3960,35 +4023,18 @@ async function executeAttempts(options) {
3960
4023
  }
3961
4024
  }
3962
4025
  // TODO: [πŸ’] Unite object for expecting amount and format
3963
- if (task.format) {
3964
- if (task.format === 'JSON') {
3965
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
3966
- // TODO: [🏒] Do more universally via `FormatParser`
3967
- try {
3968
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
3969
- }
3970
- catch (error) {
3971
- keepUnused(error);
3972
- throw new ExpectError(spaceTrim$1((block) => `
3973
- Expected valid JSON string
3974
-
3975
- ${block(
3976
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
3977
- `));
3978
- }
3979
- }
3980
- }
3981
- else {
3982
- throw new UnexpectedError(spaceTrim$1((block) => `
3983
- Unknown format "${task.format}"
3984
-
3985
- ${block(pipelineIdentification)}
3986
- `));
4026
+ // Use the common validation function for both format and expectations
4027
+ if (task.format || task.expectations) {
4028
+ const validationResult = validatePromptResult({
4029
+ resultString: $ongoingTaskResult.$resultString || '',
4030
+ expectations: task.expectations,
4031
+ format: task.format,
4032
+ });
4033
+ if (!validationResult.isValid) {
4034
+ throw validationResult.error;
3987
4035
  }
3988
- }
3989
- // TODO: [πŸ’] Unite object for expecting amount and format
3990
- if (task.expectations) {
3991
- checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
4036
+ // Update the result string in case format processing modified it (e.g., JSON extraction)
4037
+ $ongoingTaskResult.$resultString = validationResult.processedResultString;
3992
4038
  }
3993
4039
  break attempts;
3994
4040
  }
@@ -3997,6 +4043,15 @@ async function executeAttempts(options) {
3997
4043
  throw error;
3998
4044
  }
3999
4045
  $ongoingTaskResult.$expectError = error;
4046
+ // Store each failed attempt
4047
+ if (!Array.isArray($ongoingTaskResult.$failedResults)) {
4048
+ $ongoingTaskResult.$failedResults = [];
4049
+ }
4050
+ $ongoingTaskResult.$failedResults.push({
4051
+ attemptIndex,
4052
+ result: $ongoingTaskResult.$resultString,
4053
+ error: error,
4054
+ });
4000
4055
  }
4001
4056
  finally {
4002
4057
  if (!isJokerAttempt &&
@@ -4018,35 +4073,41 @@ async function executeAttempts(options) {
4018
4073
  });
4019
4074
  }
4020
4075
  }
4021
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
4076
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
4077
+ // Note: Create a summary of all failures
4078
+ const failuresSummary = $ongoingTaskResult.$failedResults
4079
+ .map((failure) => spaceTrim$1((block) => {
4080
+ var _a, _b;
4081
+ return `
4082
+ Attempt ${failure.attemptIndex + 1}:
4083
+ Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
4084
+ ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
4085
+
4086
+ Result:
4087
+ ${block(failure.result === null
4088
+ ? 'null'
4089
+ : spaceTrim$1(failure.result)
4090
+ .split('\n')
4091
+ .map((line) => `> ${line}`)
4092
+ .join('\n'))}
4093
+ `;
4094
+ }))
4095
+ .join('\n\n---\n\n');
4022
4096
  throw new PipelineExecutionError(spaceTrim$1((block) => {
4023
- var _a, _b, _c;
4097
+ var _a;
4024
4098
  return `
4025
4099
  LLM execution failed ${maxExecutionAttempts}x
4026
4100
 
4027
4101
  ${block(pipelineIdentification)}
4028
4102
 
4029
- ---
4030
4103
  The Prompt:
4031
4104
  ${block((((_a = $ongoingTaskResult.$prompt) === null || _a === void 0 ? void 0 : _a.content) || '')
4032
4105
  .split('\n')
4033
4106
  .map((line) => `> ${line}`)
4034
4107
  .join('\n'))}
4035
4108
 
4036
- Last error ${((_b = $ongoingTaskResult.$expectError) === null || _b === void 0 ? void 0 : _b.name) || ''}:
4037
- ${block((((_c = $ongoingTaskResult.$expectError) === null || _c === void 0 ? void 0 : _c.message) || '')
4038
- .split('\n')
4039
- .map((line) => `> ${line}`)
4040
- .join('\n'))}
4041
-
4042
- Last result:
4043
- ${block($ongoingTaskResult.$resultString === null
4044
- ? 'null'
4045
- : spaceTrim$1($ongoingTaskResult.$resultString)
4046
- .split('\n')
4047
- .map((line) => `> ${line}`)
4048
- .join('\n'))}
4049
- ---
4109
+ All Failed Attempts:
4110
+ ${block(failuresSummary)}
4050
4111
  `;
4051
4112
  }));
4052
4113
  }
@@ -10117,6 +10178,46 @@ async function $provideLlmToolsConfigurationFromEnv() {
10117
10178
  * Note: [🟒] Code in this file should never be never released in packages that could be imported into browser environment
10118
10179
  */
10119
10180
 
10181
+ /**
10182
+ * Detects if the code is running in a browser environment in main thread (Not in a web worker)
10183
+ *
10184
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10185
+ *
10186
+ * @public exported from `@promptbook/utils`
10187
+ */
10188
+ const $isRunningInBrowser = new Function(`
10189
+ try {
10190
+ return this === window;
10191
+ } catch (e) {
10192
+ return false;
10193
+ }
10194
+ `);
10195
+ /**
10196
+ * TODO: [🎺]
10197
+ */
10198
+
10199
+ /**
10200
+ * Detects if the code is running in a web worker
10201
+ *
10202
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10203
+ *
10204
+ * @public exported from `@promptbook/utils`
10205
+ */
10206
+ const $isRunningInWebWorker = new Function(`
10207
+ try {
10208
+ if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
10209
+ return true;
10210
+ } else {
10211
+ return false;
10212
+ }
10213
+ } catch (e) {
10214
+ return false;
10215
+ }
10216
+ `);
10217
+ /**
10218
+ * TODO: [🎺]
10219
+ */
10220
+
10120
10221
  /**
10121
10222
  * Creates LLM execution tools from provided configuration objects
10122
10223
  *
@@ -10137,8 +10238,10 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
10137
10238
  .list()
10138
10239
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
10139
10240
  if (registeredItem === undefined) {
10241
+ console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
10140
10242
  throw new Error(spaceTrim((block) => `
10141
10243
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
10244
+ Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
10142
10245
 
10143
10246
  You have probably forgotten install and import the provider package.
10144
10247
  To fix this issue, you can:
@@ -10265,24 +10368,6 @@ async function $provideScrapersForNode(tools, options) {
10265
10368
  * Note: [🟒] Code in this file should never be never released in packages that could be imported into browser environment
10266
10369
  */
10267
10370
 
10268
- /**
10269
- * Detects if the code is running in a browser environment in main thread (Not in a web worker)
10270
- *
10271
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10272
- *
10273
- * @public exported from `@promptbook/utils`
10274
- */
10275
- new Function(`
10276
- try {
10277
- return this === window;
10278
- } catch (e) {
10279
- return false;
10280
- }
10281
- `);
10282
- /**
10283
- * TODO: [🎺]
10284
- */
10285
-
10286
10371
  /**
10287
10372
  * Detects if the code is running in jest environment
10288
10373
  *
@@ -10301,28 +10386,6 @@ new Function(`
10301
10386
  * TODO: [🎺]
10302
10387
  */
10303
10388
 
10304
- /**
10305
- * Detects if the code is running in a web worker
10306
- *
10307
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10308
- *
10309
- * @public exported from `@promptbook/utils`
10310
- */
10311
- new Function(`
10312
- try {
10313
- if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
10314
- return true;
10315
- } else {
10316
- return false;
10317
- }
10318
- } catch (e) {
10319
- return false;
10320
- }
10321
- `);
10322
- /**
10323
- * TODO: [🎺]
10324
- */
10325
-
10326
10389
  /**
10327
10390
  * Makes first letter of a string uppercase
10328
10391
  *