@promptbook/node 0.98.0-6 โ†’ 0.98.0-9

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.
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.98.0-6';
33
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-9';
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 = 3; // <- 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.
@@ -3757,13 +3819,13 @@ async function executeAttempts(options) {
3757
3819
  // TODO: [๐Ÿš] Make arrayable LLMs -> single LLM DRY
3758
3820
  const _llms = arrayableToArray(tools.llm);
3759
3821
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
3760
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
3761
- const isJokerAttempt = attempt < 0;
3762
- 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];
3763
3825
  // TODO: [๐Ÿง ][๐Ÿญ] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
3764
3826
  if (isJokerAttempt && !jokerParameterName) {
3765
3827
  throw new UnexpectedError(spaceTrim$1((block) => `
3766
- Joker not found in attempt ${attempt}
3828
+ Joker not found in attempt ${attemptIndex}
3767
3829
 
3768
3830
  ${block(pipelineIdentification)}
3769
3831
  `));
@@ -3961,35 +4023,18 @@ async function executeAttempts(options) {
3961
4023
  }
3962
4024
  }
3963
4025
  // TODO: [๐Ÿ’] Unite object for expecting amount and format
3964
- if (task.format) {
3965
- if (task.format === 'JSON') {
3966
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
3967
- // TODO: [๐Ÿข] Do more universally via `FormatParser`
3968
- try {
3969
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
3970
- }
3971
- catch (error) {
3972
- keepUnused(error);
3973
- throw new ExpectError(spaceTrim$1((block) => `
3974
- Expected valid JSON string
3975
-
3976
- ${block(
3977
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
3978
- `));
3979
- }
3980
- }
3981
- }
3982
- else {
3983
- throw new UnexpectedError(spaceTrim$1((block) => `
3984
- Unknown format "${task.format}"
3985
-
3986
- ${block(pipelineIdentification)}
3987
- `));
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;
3988
4035
  }
3989
- }
3990
- // TODO: [๐Ÿ’] Unite object for expecting amount and format
3991
- if (task.expectations) {
3992
- 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;
3993
4038
  }
3994
4039
  break attempts;
3995
4040
  }
@@ -4003,6 +4048,7 @@ async function executeAttempts(options) {
4003
4048
  $ongoingTaskResult.$failedResults = [];
4004
4049
  }
4005
4050
  $ongoingTaskResult.$failedResults.push({
4051
+ attemptIndex,
4006
4052
  result: $ongoingTaskResult.$resultString,
4007
4053
  error: error,
4008
4054
  });
@@ -4027,19 +4073,13 @@ async function executeAttempts(options) {
4027
4073
  });
4028
4074
  }
4029
4075
  }
4030
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
4031
- // Store the current failure before throwing
4032
- $ongoingTaskResult.$failedResults = $ongoingTaskResult.$failedResults || [];
4033
- $ongoingTaskResult.$failedResults.push({
4034
- result: $ongoingTaskResult.$resultString,
4035
- error: $ongoingTaskResult.$expectError,
4036
- });
4037
- // Create a summary of all failures
4076
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
4077
+ // Note: Create a summary of all failures
4038
4078
  const failuresSummary = $ongoingTaskResult.$failedResults
4039
- .map((failure, index) => spaceTrim$1((block) => {
4079
+ .map((failure) => spaceTrim$1((block) => {
4040
4080
  var _a, _b;
4041
4081
  return `
4042
- Attempt ${index + 1}:
4082
+ Attempt ${failure.attemptIndex + 1}:
4043
4083
  Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
4044
4084
  ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
4045
4085
 
@@ -10158,6 +10198,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
10158
10198
  .list()
10159
10199
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
10160
10200
  if (registeredItem === undefined) {
10201
+ console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
10161
10202
  throw new Error(spaceTrim((block) => `
10162
10203
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
10163
10204