@promptbook/core 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 +359 -170
  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 +1 -1
  24. package/umd/index.umd.js +359 -169
  25. package/umd/index.umd.js.map +1 -1
package/umd/index.umd.js CHANGED
@@ -27,7 +27,7 @@
27
27
  * @generated
28
28
  * @see https://github.com/webgptorg/promptbook
29
29
  */
30
- const PROMPTBOOK_ENGINE_VERSION = '0.95.0';
30
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-10';
31
31
  /**
32
32
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
33
33
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -354,7 +354,7 @@
354
354
  *
355
355
  * @public exported from `@promptbook/core`
356
356
  */
357
- const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
357
+ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
358
358
  /**
359
359
  * The maximum depth to which knowledge sources will be scraped when building a knowledge base.
360
360
  * This prevents infinite recursion and limits resource usage.
@@ -2255,7 +2255,7 @@
2255
2255
  throw new Error(spaceTrim__default["default"]((block) => `
2256
2256
  ${block(error.message)}
2257
2257
 
2258
- The JSON text:
2258
+ The expected JSON text:
2259
2259
  ${block(value)}
2260
2260
  `));
2261
2261
  }
@@ -3387,108 +3387,6 @@
3387
3387
  * TODO: [๐Ÿ‘ทโ€โ™‚๏ธ] @@@ Manual about construction of llmTools
3388
3388
  */
3389
3389
 
3390
- /**
3391
- * Extracts all code blocks from markdown.
3392
- *
3393
- * Note: There are multiple similar functions:
3394
- * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
3395
- * - `extractJsonBlock` extracts exactly one valid JSON code block
3396
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3397
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3398
- *
3399
- * @param markdown any valid markdown
3400
- * @returns code blocks with language and content
3401
- * @throws {ParseError} if block is not closed properly
3402
- * @public exported from `@promptbook/markdown-utils`
3403
- */
3404
- function extractAllBlocksFromMarkdown(markdown) {
3405
- const codeBlocks = [];
3406
- const lines = markdown.split('\n');
3407
- // Note: [0] Ensure that the last block notated by gt > will be closed
3408
- lines.push('');
3409
- let currentCodeBlock = null;
3410
- for (const line of lines) {
3411
- if (line.startsWith('> ') || line === '>') {
3412
- if (currentCodeBlock === null) {
3413
- currentCodeBlock = { blockNotation: '>', language: null, content: '' };
3414
- } /* not else */
3415
- if (currentCodeBlock.blockNotation === '>') {
3416
- if (currentCodeBlock.content !== '') {
3417
- currentCodeBlock.content += '\n';
3418
- }
3419
- currentCodeBlock.content += line.slice(2);
3420
- }
3421
- }
3422
- else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '>' /* <- Note: [0] */) {
3423
- codeBlocks.push(currentCodeBlock);
3424
- currentCodeBlock = null;
3425
- }
3426
- /* not else */
3427
- if (line.startsWith('```')) {
3428
- const language = line.slice(3).trim() || null;
3429
- if (currentCodeBlock === null) {
3430
- currentCodeBlock = { blockNotation: '```', language, content: '' };
3431
- }
3432
- else {
3433
- if (language !== null) {
3434
- throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed and already opening new ${language} code block`);
3435
- }
3436
- codeBlocks.push(currentCodeBlock);
3437
- currentCodeBlock = null;
3438
- }
3439
- }
3440
- else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '```') {
3441
- if (currentCodeBlock.content !== '') {
3442
- currentCodeBlock.content += '\n';
3443
- }
3444
- currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make proper unescape */;
3445
- }
3446
- }
3447
- if (currentCodeBlock !== null) {
3448
- throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed at the end of the markdown`);
3449
- }
3450
- return codeBlocks;
3451
- }
3452
- /**
3453
- * TODO: Maybe name for `blockNotation` instead of '```' and '>'
3454
- */
3455
-
3456
- /**
3457
- * Extracts extracts exactly one valid JSON code block
3458
- *
3459
- * - When given string is a valid JSON as it is, it just returns it
3460
- * - When there is no JSON code block the function throws a `ParseError`
3461
- * - When there are multiple JSON code blocks the function throws a `ParseError`
3462
- *
3463
- * Note: It is not important if marked as ```json BUT if it is VALID JSON
3464
- * Note: There are multiple similar function:
3465
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
3466
- * - `extractJsonBlock` extracts exactly one valid JSON code block
3467
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3468
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3469
- *
3470
- * @public exported from `@promptbook/markdown-utils`
3471
- * @throws {ParseError} if there is no valid JSON block in the markdown
3472
- */
3473
- function extractJsonBlock(markdown) {
3474
- if (isValidJsonString(markdown)) {
3475
- return markdown;
3476
- }
3477
- const codeBlocks = extractAllBlocksFromMarkdown(markdown);
3478
- const jsonBlocks = codeBlocks.filter(({ content }) => isValidJsonString(content));
3479
- if (jsonBlocks.length === 0) {
3480
- throw new Error('There is no valid JSON block in the markdown');
3481
- }
3482
- if (jsonBlocks.length > 1) {
3483
- throw new Error('There are multiple JSON code blocks in the markdown');
3484
- }
3485
- return jsonBlocks[0].content;
3486
- }
3487
- /**
3488
- * TODO: Add some auto-healing logic + extract YAML, JSON5, TOML, etc.
3489
- * TODO: [๐Ÿข] Make this logic part of `JsonFormatParser` or `isValidJsonString`
3490
- */
3491
-
3492
3390
  /**
3493
3391
  * Takes an item or an array of items and returns an array of items
3494
3392
  *
@@ -3596,6 +3494,108 @@
3596
3494
  return replacedTemplates;
3597
3495
  }
3598
3496
 
3497
+ /**
3498
+ * Extracts all code blocks from markdown.
3499
+ *
3500
+ * Note: There are multiple similar functions:
3501
+ * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
3502
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
3503
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3504
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3505
+ *
3506
+ * @param markdown any valid markdown
3507
+ * @returns code blocks with language and content
3508
+ * @throws {ParseError} if block is not closed properly
3509
+ * @public exported from `@promptbook/markdown-utils`
3510
+ */
3511
+ function extractAllBlocksFromMarkdown(markdown) {
3512
+ const codeBlocks = [];
3513
+ const lines = markdown.split('\n');
3514
+ // Note: [0] Ensure that the last block notated by gt > will be closed
3515
+ lines.push('');
3516
+ let currentCodeBlock = null;
3517
+ for (const line of lines) {
3518
+ if (line.startsWith('> ') || line === '>') {
3519
+ if (currentCodeBlock === null) {
3520
+ currentCodeBlock = { blockNotation: '>', language: null, content: '' };
3521
+ } /* not else */
3522
+ if (currentCodeBlock.blockNotation === '>') {
3523
+ if (currentCodeBlock.content !== '') {
3524
+ currentCodeBlock.content += '\n';
3525
+ }
3526
+ currentCodeBlock.content += line.slice(2);
3527
+ }
3528
+ }
3529
+ else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '>' /* <- Note: [0] */) {
3530
+ codeBlocks.push(currentCodeBlock);
3531
+ currentCodeBlock = null;
3532
+ }
3533
+ /* not else */
3534
+ if (line.startsWith('```')) {
3535
+ const language = line.slice(3).trim() || null;
3536
+ if (currentCodeBlock === null) {
3537
+ currentCodeBlock = { blockNotation: '```', language, content: '' };
3538
+ }
3539
+ else {
3540
+ if (language !== null) {
3541
+ throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed and already opening new ${language} code block`);
3542
+ }
3543
+ codeBlocks.push(currentCodeBlock);
3544
+ currentCodeBlock = null;
3545
+ }
3546
+ }
3547
+ else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '```') {
3548
+ if (currentCodeBlock.content !== '') {
3549
+ currentCodeBlock.content += '\n';
3550
+ }
3551
+ currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make proper unescape */;
3552
+ }
3553
+ }
3554
+ if (currentCodeBlock !== null) {
3555
+ throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed at the end of the markdown`);
3556
+ }
3557
+ return codeBlocks;
3558
+ }
3559
+ /**
3560
+ * TODO: Maybe name for `blockNotation` instead of '```' and '>'
3561
+ */
3562
+
3563
+ /**
3564
+ * Extracts extracts exactly one valid JSON code block
3565
+ *
3566
+ * - When given string is a valid JSON as it is, it just returns it
3567
+ * - When there is no JSON code block the function throws a `ParseError`
3568
+ * - When there are multiple JSON code blocks the function throws a `ParseError`
3569
+ *
3570
+ * Note: It is not important if marked as ```json BUT if it is VALID JSON
3571
+ * Note: There are multiple similar function:
3572
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
3573
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
3574
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
3575
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
3576
+ *
3577
+ * @public exported from `@promptbook/markdown-utils`
3578
+ * @throws {ParseError} if there is no valid JSON block in the markdown
3579
+ */
3580
+ function extractJsonBlock(markdown) {
3581
+ if (isValidJsonString(markdown)) {
3582
+ return markdown;
3583
+ }
3584
+ const codeBlocks = extractAllBlocksFromMarkdown(markdown);
3585
+ const jsonBlocks = codeBlocks.filter(({ content }) => isValidJsonString(content));
3586
+ if (jsonBlocks.length === 0) {
3587
+ throw new Error('There is no valid JSON block in the markdown');
3588
+ }
3589
+ if (jsonBlocks.length > 1) {
3590
+ throw new Error('There are multiple JSON code blocks in the markdown');
3591
+ }
3592
+ return jsonBlocks[0].content;
3593
+ }
3594
+ /**
3595
+ * TODO: Add some auto-healing logic + extract YAML, JSON5, TOML, etc.
3596
+ * TODO: [๐Ÿข] Make this logic part of `JsonFormatParser` or `isValidJsonString`
3597
+ */
3598
+
3599
3599
  /**
3600
3600
  * Counts number of characters in the text
3601
3601
  *
@@ -4039,6 +4039,68 @@
4039
4039
  * Note: [๐Ÿ’] and [๐Ÿค ] are interconnected together
4040
4040
  */
4041
4041
 
4042
+ /**
4043
+ * Validates a prompt result against expectations and format requirements.
4044
+ * This function provides a common abstraction for result validation that can be used
4045
+ * by both execution logic and caching logic to ensure consistency.
4046
+ *
4047
+ * @param options - The validation options including result string, expectations, and format
4048
+ * @returns Validation result with processed string and validity status
4049
+ * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
4050
+ */
4051
+ function validatePromptResult(options) {
4052
+ const { resultString, expectations, format } = options;
4053
+ let processedResultString = resultString;
4054
+ let validationError;
4055
+ try {
4056
+ // TODO: [๐Ÿ’] Unite object for expecting amount and format
4057
+ if (format) {
4058
+ if (format === 'JSON') {
4059
+ if (!isValidJsonString(processedResultString)) {
4060
+ // TODO: [๐Ÿข] Do more universally via `FormatParser`
4061
+ try {
4062
+ processedResultString = extractJsonBlock(processedResultString);
4063
+ }
4064
+ catch (error) {
4065
+ keepUnused(error);
4066
+ throw new ExpectError(spaceTrim.spaceTrim((block) => `
4067
+ Expected valid JSON string
4068
+
4069
+ The expected JSON text:
4070
+ ${block(processedResultString)}
4071
+ `));
4072
+ }
4073
+ }
4074
+ }
4075
+ else {
4076
+ throw new UnexpectedError(`Unknown format "${format}"`);
4077
+ }
4078
+ }
4079
+ // TODO: [๐Ÿ’] Unite object for expecting amount and format
4080
+ if (expectations) {
4081
+ checkExpectations(expectations, processedResultString);
4082
+ }
4083
+ return {
4084
+ isValid: true,
4085
+ processedResultString,
4086
+ };
4087
+ }
4088
+ catch (error) {
4089
+ if (error instanceof ExpectError) {
4090
+ validationError = error;
4091
+ }
4092
+ else {
4093
+ // Re-throw non-ExpectError errors (like UnexpectedError)
4094
+ throw error;
4095
+ }
4096
+ return {
4097
+ isValid: false,
4098
+ processedResultString,
4099
+ error: validationError,
4100
+ };
4101
+ }
4102
+ }
4103
+
4042
4104
  /**
4043
4105
  * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
4044
4106
  * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
@@ -4056,17 +4118,18 @@
4056
4118
  $resultString: null,
4057
4119
  $expectError: null,
4058
4120
  $scriptPipelineExecutionErrors: [],
4121
+ $failedResults: [], // Track all failed attempts
4059
4122
  };
4060
4123
  // TODO: [๐Ÿš] Make arrayable LLMs -> single LLM DRY
4061
4124
  const _llms = arrayableToArray(tools.llm);
4062
4125
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
4063
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
4064
- const isJokerAttempt = attempt < 0;
4065
- const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
4126
+ attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
4127
+ const isJokerAttempt = attemptIndex < 0;
4128
+ const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
4066
4129
  // TODO: [๐Ÿง ][๐Ÿญ] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
4067
4130
  if (isJokerAttempt && !jokerParameterName) {
4068
4131
  throw new UnexpectedError(spaceTrim.spaceTrim((block) => `
4069
- Joker not found in attempt ${attempt}
4132
+ Joker not found in attempt ${attemptIndex}
4070
4133
 
4071
4134
  ${block(pipelineIdentification)}
4072
4135
  `));
@@ -4264,35 +4327,18 @@
4264
4327
  }
4265
4328
  }
4266
4329
  // TODO: [๐Ÿ’] Unite object for expecting amount and format
4267
- if (task.format) {
4268
- if (task.format === 'JSON') {
4269
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
4270
- // TODO: [๐Ÿข] Do more universally via `FormatParser`
4271
- try {
4272
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
4273
- }
4274
- catch (error) {
4275
- keepUnused(error);
4276
- throw new ExpectError(spaceTrim.spaceTrim((block) => `
4277
- Expected valid JSON string
4278
-
4279
- ${block(
4280
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
4281
- `));
4282
- }
4283
- }
4284
- }
4285
- else {
4286
- throw new UnexpectedError(spaceTrim.spaceTrim((block) => `
4287
- Unknown format "${task.format}"
4288
-
4289
- ${block(pipelineIdentification)}
4290
- `));
4330
+ // Use the common validation function for both format and expectations
4331
+ if (task.format || task.expectations) {
4332
+ const validationResult = validatePromptResult({
4333
+ resultString: $ongoingTaskResult.$resultString || '',
4334
+ expectations: task.expectations,
4335
+ format: task.format,
4336
+ });
4337
+ if (!validationResult.isValid) {
4338
+ throw validationResult.error;
4291
4339
  }
4292
- }
4293
- // TODO: [๐Ÿ’] Unite object for expecting amount and format
4294
- if (task.expectations) {
4295
- checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
4340
+ // Update the result string in case format processing modified it (e.g., JSON extraction)
4341
+ $ongoingTaskResult.$resultString = validationResult.processedResultString;
4296
4342
  }
4297
4343
  break attempts;
4298
4344
  }
@@ -4301,6 +4347,15 @@
4301
4347
  throw error;
4302
4348
  }
4303
4349
  $ongoingTaskResult.$expectError = error;
4350
+ // Store each failed attempt
4351
+ if (!Array.isArray($ongoingTaskResult.$failedResults)) {
4352
+ $ongoingTaskResult.$failedResults = [];
4353
+ }
4354
+ $ongoingTaskResult.$failedResults.push({
4355
+ attemptIndex,
4356
+ result: $ongoingTaskResult.$resultString,
4357
+ error: error,
4358
+ });
4304
4359
  }
4305
4360
  finally {
4306
4361
  if (!isJokerAttempt &&
@@ -4322,35 +4377,41 @@
4322
4377
  });
4323
4378
  }
4324
4379
  }
4325
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
4380
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
4381
+ // Note: Create a summary of all failures
4382
+ const failuresSummary = $ongoingTaskResult.$failedResults
4383
+ .map((failure) => spaceTrim.spaceTrim((block) => {
4384
+ var _a, _b;
4385
+ return `
4386
+ Attempt ${failure.attemptIndex + 1}:
4387
+ Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
4388
+ ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
4389
+
4390
+ Result:
4391
+ ${block(failure.result === null
4392
+ ? 'null'
4393
+ : spaceTrim.spaceTrim(failure.result)
4394
+ .split('\n')
4395
+ .map((line) => `> ${line}`)
4396
+ .join('\n'))}
4397
+ `;
4398
+ }))
4399
+ .join('\n\n---\n\n');
4326
4400
  throw new PipelineExecutionError(spaceTrim.spaceTrim((block) => {
4327
- var _a, _b, _c;
4401
+ var _a;
4328
4402
  return `
4329
4403
  LLM execution failed ${maxExecutionAttempts}x
4330
4404
 
4331
4405
  ${block(pipelineIdentification)}
4332
4406
 
4333
- ---
4334
4407
  The Prompt:
4335
4408
  ${block((((_a = $ongoingTaskResult.$prompt) === null || _a === void 0 ? void 0 : _a.content) || '')
4336
4409
  .split('\n')
4337
4410
  .map((line) => `> ${line}`)
4338
4411
  .join('\n'))}
4339
4412
 
4340
- Last error ${((_b = $ongoingTaskResult.$expectError) === null || _b === void 0 ? void 0 : _b.name) || ''}:
4341
- ${block((((_c = $ongoingTaskResult.$expectError) === null || _c === void 0 ? void 0 : _c.message) || '')
4342
- .split('\n')
4343
- .map((line) => `> ${line}`)
4344
- .join('\n'))}
4345
-
4346
- Last result:
4347
- ${block($ongoingTaskResult.$resultString === null
4348
- ? 'null'
4349
- : spaceTrim.spaceTrim($ongoingTaskResult.$resultString)
4350
- .split('\n')
4351
- .map((line) => `> ${line}`)
4352
- .join('\n'))}
4353
- ---
4413
+ All Failed Attempts:
4414
+ ${block(failuresSummary)}
4354
4415
  `;
4355
4416
  }));
4356
4417
  }
@@ -10468,6 +10529,24 @@
10468
10529
  * TODO: [ยฎ] DRY Register logic
10469
10530
  */
10470
10531
 
10532
+ /**
10533
+ * Detects if the code is running in a browser environment in main thread (Not in a web worker)
10534
+ *
10535
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10536
+ *
10537
+ * @public exported from `@promptbook/utils`
10538
+ */
10539
+ const $isRunningInBrowser = new Function(`
10540
+ try {
10541
+ return this === window;
10542
+ } catch (e) {
10543
+ return false;
10544
+ }
10545
+ `);
10546
+ /**
10547
+ * TODO: [๐ŸŽบ]
10548
+ */
10549
+
10471
10550
  /**
10472
10551
  * Detects if the code is running in a Node.js environment
10473
10552
  *
@@ -10486,6 +10565,28 @@
10486
10565
  * TODO: [๐ŸŽบ]
10487
10566
  */
10488
10567
 
10568
+ /**
10569
+ * Detects if the code is running in a web worker
10570
+ *
10571
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
10572
+ *
10573
+ * @public exported from `@promptbook/utils`
10574
+ */
10575
+ const $isRunningInWebWorker = new Function(`
10576
+ try {
10577
+ if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
10578
+ return true;
10579
+ } else {
10580
+ return false;
10581
+ }
10582
+ } catch (e) {
10583
+ return false;
10584
+ }
10585
+ `);
10586
+ /**
10587
+ * TODO: [๐ŸŽบ]
10588
+ */
10589
+
10489
10590
  /**
10490
10591
  * Creates a message with all registered LLM tools
10491
10592
  *
@@ -10630,8 +10731,10 @@
10630
10731
  .list()
10631
10732
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
10632
10733
  if (registeredItem === undefined) {
10734
+ console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
10633
10735
  throw new Error(spaceTrim__default["default"]((block) => `
10634
10736
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
10737
+ Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
10635
10738
 
10636
10739
  You have probably forgotten install and import the provider package.
10637
10740
  To fix this issue, you can:
@@ -10759,6 +10862,7 @@
10759
10862
  },
10760
10863
  };
10761
10864
  const callCommonModel = async (prompt) => {
10865
+ var _a;
10762
10866
  const { parameters, content, modelRequirements } = prompt;
10763
10867
  // <- Note: These are relevant things from the prompt that the cache key should depend on.
10764
10868
  // TODO: Maybe some standalone function for normalization of content for cache
@@ -10809,21 +10913,70 @@
10809
10913
  }
10810
10914
  // TODO: [๐Ÿง ] !!5 How to do timing in mixed cache / non-cache situation
10811
10915
  // promptResult.timing: FromtoItems
10812
- await storage.setItem(key, {
10813
- date: $getCurrentDate(),
10814
- promptbookVersion: PROMPTBOOK_ENGINE_VERSION,
10815
- bookVersion: BOOK_LANGUAGE_VERSION,
10816
- prompt: {
10817
- ...prompt,
10818
- parameters: Object.entries(parameters).length === Object.entries(relevantParameters).length
10819
- ? parameters
10820
- : {
10821
- ...relevantParameters,
10822
- note: `<- Note: Only relevant parameters are stored in the cache`,
10823
- },
10824
- },
10825
- promptResult,
10826
- });
10916
+ // Check if the result is valid and should be cached
10917
+ // A result is considered failed if:
10918
+ // 1. It has a content property that is null or undefined
10919
+ // 2. It has an error property that is truthy
10920
+ // 3. It has a success property that is explicitly false
10921
+ // 4. It doesn't meet the prompt's expectations or format requirements
10922
+ const isBasicFailedResult = promptResult.content === null ||
10923
+ promptResult.content === undefined ||
10924
+ promptResult.error ||
10925
+ promptResult.success === false;
10926
+ let shouldCache = !isBasicFailedResult;
10927
+ // If the basic result is valid, check against expectations and format
10928
+ if (shouldCache && promptResult.content) {
10929
+ try {
10930
+ const validationResult = validatePromptResult({
10931
+ resultString: promptResult.content,
10932
+ expectations: prompt.expectations,
10933
+ format: prompt.format,
10934
+ });
10935
+ shouldCache = validationResult.isValid;
10936
+ if (!shouldCache && isVerbose) {
10937
+ console.info('Not caching result that fails expectations/format validation for key:', key, {
10938
+ content: promptResult.content,
10939
+ expectations: prompt.expectations,
10940
+ format: prompt.format,
10941
+ validationError: (_a = validationResult.error) === null || _a === void 0 ? void 0 : _a.message,
10942
+ });
10943
+ }
10944
+ }
10945
+ catch (error) {
10946
+ // If validation throws an unexpected error, don't cache
10947
+ shouldCache = false;
10948
+ if (isVerbose) {
10949
+ console.info('Not caching result due to validation error for key:', key, {
10950
+ content: promptResult.content,
10951
+ validationError: error instanceof Error ? error.message : String(error),
10952
+ });
10953
+ }
10954
+ }
10955
+ }
10956
+ if (shouldCache) {
10957
+ await storage.setItem(key, {
10958
+ date: $getCurrentDate(),
10959
+ promptbookVersion: PROMPTBOOK_ENGINE_VERSION,
10960
+ bookVersion: BOOK_LANGUAGE_VERSION,
10961
+ prompt: {
10962
+ ...prompt,
10963
+ parameters: Object.entries(parameters).length === Object.entries(relevantParameters).length
10964
+ ? parameters
10965
+ : {
10966
+ ...relevantParameters,
10967
+ note: `<- Note: Only relevant parameters are stored in the cache`,
10968
+ },
10969
+ },
10970
+ promptResult,
10971
+ });
10972
+ }
10973
+ else if (isVerbose && isBasicFailedResult) {
10974
+ console.info('Not caching failed result for key:', key, {
10975
+ content: promptResult.content,
10976
+ error: promptResult.error,
10977
+ success: promptResult.success,
10978
+ });
10979
+ }
10827
10980
  return promptResult;
10828
10981
  };
10829
10982
  if (llmTools.callChatModel !== undefined) {
@@ -11273,6 +11426,42 @@
11273
11426
  */
11274
11427
  },
11275
11428
  });
11429
+ /**
11430
+ * Registration of the OpenAI Compatible metadata
11431
+ *
11432
+ * Note: OpenAiCompatibleExecutionTools is an abstract class and cannot be instantiated directly.
11433
+ * It serves as a base class for OpenAiExecutionTools and other compatible implementations.
11434
+ *
11435
+ * @public exported from `@promptbook/core`
11436
+ * @public exported from `@promptbook/wizard`
11437
+ * @public exported from `@promptbook/cli`
11438
+ */
11439
+ const _OpenAiCompatibleMetadataRegistration = $llmToolsMetadataRegister.register({
11440
+ title: 'Open AI Compatible',
11441
+ packageName: '@promptbook/openai',
11442
+ className: 'OpenAiCompatibleExecutionTools',
11443
+ envVariables: ['OPENAI_API_KEY', 'OPENAI_BASE_URL'],
11444
+ trustLevel: 'CLOSED',
11445
+ order: MODEL_ORDERS.TOP_TIER,
11446
+ getBoilerplateConfiguration() {
11447
+ return {
11448
+ title: 'Open AI Compatible',
11449
+ packageName: '@promptbook/openai',
11450
+ className: 'OpenAiCompatibleExecutionTools',
11451
+ options: {
11452
+ apiKey: 'sk-',
11453
+ baseURL: 'https://api.openai.com/v1',
11454
+ defaultModelName: 'gpt-4-turbo',
11455
+ isProxied: false,
11456
+ remoteServerUrl: DEFAULT_REMOTE_SERVER_URL,
11457
+ maxRequestsPerMinute: DEFAULT_MAX_REQUESTS_PER_MINUTE,
11458
+ },
11459
+ };
11460
+ },
11461
+ createConfigurationFromEnv(env) {
11462
+ return null;
11463
+ },
11464
+ });
11276
11465
  /**
11277
11466
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
11278
11467
  */
@@ -11857,6 +12046,7 @@
11857
12046
  exports._MarkitdownScraperMetadataRegistration = _MarkitdownScraperMetadataRegistration;
11858
12047
  exports._OllamaMetadataRegistration = _OllamaMetadataRegistration;
11859
12048
  exports._OpenAiAssistantMetadataRegistration = _OpenAiAssistantMetadataRegistration;
12049
+ exports._OpenAiCompatibleMetadataRegistration = _OpenAiCompatibleMetadataRegistration;
11860
12050
  exports._OpenAiMetadataRegistration = _OpenAiMetadataRegistration;
11861
12051
  exports._PdfScraperMetadataRegistration = _PdfScraperMetadataRegistration;
11862
12052
  exports._WebsiteScraperMetadataRegistration = _WebsiteScraperMetadataRegistration;