@promptbook/pdf 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 +184 -123
  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 +184 -123
  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/pdf`
29
33
 
30
34
  - Promptbooks are [divided into several](#-packages) packages, all are published from [single monorepo](https://github.com/webgptorg/promptbook).
@@ -58,6 +62,8 @@ Rest of the documentation is common for **entire promptbook ecosystem**:
58
62
 
59
63
  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**!
60
64
 
65
+
66
+
61
67
  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!
62
68
 
63
69
  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.
@@ -183,6 +189,8 @@ Join our growing community of developers and users:
183
189
 
184
190
  _A concise, Markdown-based DSL for crafting AI workflows and automations._
185
191
 
192
+
193
+
186
194
  ### Introduction
187
195
 
188
196
  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.
@@ -232,6 +240,8 @@ Personas can have access to different knowledge, tools and actions. They can als
232
240
 
233
241
  - [PERSONA](https://github.com/webgptorg/promptbook/blob/main/documents/commands/PERSONA.md)
234
242
 
243
+
244
+
235
245
  ### **3. How:** Knowledge, Instruments and Actions
236
246
 
237
247
  The resources used by the personas are used to do the work.
@@ -331,6 +341,8 @@ The following glossary is used to clarify certain concepts:
331
341
 
332
342
  _Note: This section is not a complete dictionary, more list of general AI / LLM terms that has connection with Promptbook_
333
343
 
344
+
345
+
334
346
  ### πŸ’― Core concepts
335
347
 
336
348
  - [πŸ“š Collection of pipelines](https://github.com/webgptorg/promptbook/discussions/65)
package/esm/index.es.js CHANGED
@@ -26,7 +26,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
26
26
  * @generated
27
27
  * @see https://github.com/webgptorg/promptbook
28
28
  */
29
- const PROMPTBOOK_ENGINE_VERSION = '0.95.0';
29
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-10';
30
30
  /**
31
31
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
32
32
  * Note: [πŸ’ž] Ignore a discrepancy between file name and entity name
@@ -175,7 +175,7 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
175
175
  *
176
176
  * @public exported from `@promptbook/core`
177
177
  */
178
- const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
178
+ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
179
179
  // <- TODO: [πŸ•] Make also `BOOKS_DIRNAME_ALTERNATIVES`
180
180
  // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
181
181
  /**
@@ -2401,7 +2401,7 @@ function jsonParse(value) {
2401
2401
  throw new Error(spaceTrim((block) => `
2402
2402
  ${block(error.message)}
2403
2403
 
2404
- The JSON text:
2404
+ The expected JSON text:
2405
2405
  ${block(value)}
2406
2406
  `));
2407
2407
  }
@@ -4488,6 +4488,77 @@ function mapAvailableToExpectedParameters(options) {
4488
4488
  return mappedParameters;
4489
4489
  }
4490
4490
 
4491
+ /**
4492
+ * Replaces parameters in template with values from parameters object
4493
+ *
4494
+ * Note: This function is not places strings into string,
4495
+ * It's more complex and can handle this operation specifically for LLM models
4496
+ *
4497
+ * @param template the template with parameters in {curly} braces
4498
+ * @param parameters the object with parameters
4499
+ * @returns the template with replaced parameters
4500
+ * @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
4501
+ * @public exported from `@promptbook/utils`
4502
+ */
4503
+ function templateParameters(template, parameters) {
4504
+ for (const [parameterName, parameterValue] of Object.entries(parameters)) {
4505
+ if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
4506
+ throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
4507
+ }
4508
+ else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
4509
+ // TODO: [🍡]
4510
+ throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
4511
+ }
4512
+ }
4513
+ let replacedTemplates = template;
4514
+ let match;
4515
+ let loopLimit = LOOP_LIMIT;
4516
+ while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
4517
+ .exec(replacedTemplates))) {
4518
+ if (loopLimit-- < 0) {
4519
+ throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
4520
+ }
4521
+ const precol = match.groups.precol;
4522
+ const parameterName = match.groups.parameterName;
4523
+ if (parameterName === '') {
4524
+ // Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
4525
+ continue;
4526
+ }
4527
+ if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
4528
+ throw new PipelineExecutionError('Parameter is already opened or not closed');
4529
+ }
4530
+ if (parameters[parameterName] === undefined) {
4531
+ throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4532
+ }
4533
+ let parameterValue = parameters[parameterName];
4534
+ if (parameterValue === undefined) {
4535
+ throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4536
+ }
4537
+ parameterValue = valueToString(parameterValue);
4538
+ // Escape curly braces in parameter values to prevent prompt-injection
4539
+ parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4540
+ if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
4541
+ parameterValue = parameterValue
4542
+ .split('\n')
4543
+ .map((line, index) => (index === 0 ? line : `${precol}${line}`))
4544
+ .join('\n');
4545
+ }
4546
+ replacedTemplates =
4547
+ replacedTemplates.substring(0, match.index + precol.length) +
4548
+ parameterValue +
4549
+ replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
4550
+ }
4551
+ // [πŸ’«] Check if there are parameters that are not closed properly
4552
+ if (/{\w+$/.test(replacedTemplates)) {
4553
+ throw new PipelineExecutionError('Parameter is not closed');
4554
+ }
4555
+ // [πŸ’«] Check if there are parameters that are not opened properly
4556
+ if (/^\w+}/.test(replacedTemplates)) {
4557
+ throw new PipelineExecutionError('Parameter is not opened');
4558
+ }
4559
+ return replacedTemplates;
4560
+ }
4561
+
4491
4562
  /**
4492
4563
  * Extracts all code blocks from markdown.
4493
4564
  *
@@ -4590,77 +4661,6 @@ function extractJsonBlock(markdown) {
4590
4661
  * TODO: [🏒] Make this logic part of `JsonFormatParser` or `isValidJsonString`
4591
4662
  */
4592
4663
 
4593
- /**
4594
- * Replaces parameters in template with values from parameters object
4595
- *
4596
- * Note: This function is not places strings into string,
4597
- * It's more complex and can handle this operation specifically for LLM models
4598
- *
4599
- * @param template the template with parameters in {curly} braces
4600
- * @param parameters the object with parameters
4601
- * @returns the template with replaced parameters
4602
- * @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
4603
- * @public exported from `@promptbook/utils`
4604
- */
4605
- function templateParameters(template, parameters) {
4606
- for (const [parameterName, parameterValue] of Object.entries(parameters)) {
4607
- if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
4608
- throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
4609
- }
4610
- else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
4611
- // TODO: [🍡]
4612
- throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
4613
- }
4614
- }
4615
- let replacedTemplates = template;
4616
- let match;
4617
- let loopLimit = LOOP_LIMIT;
4618
- while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
4619
- .exec(replacedTemplates))) {
4620
- if (loopLimit-- < 0) {
4621
- throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
4622
- }
4623
- const precol = match.groups.precol;
4624
- const parameterName = match.groups.parameterName;
4625
- if (parameterName === '') {
4626
- // Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
4627
- continue;
4628
- }
4629
- if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
4630
- throw new PipelineExecutionError('Parameter is already opened or not closed');
4631
- }
4632
- if (parameters[parameterName] === undefined) {
4633
- throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4634
- }
4635
- let parameterValue = parameters[parameterName];
4636
- if (parameterValue === undefined) {
4637
- throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4638
- }
4639
- parameterValue = valueToString(parameterValue);
4640
- // Escape curly braces in parameter values to prevent prompt-injection
4641
- parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4642
- if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
4643
- parameterValue = parameterValue
4644
- .split('\n')
4645
- .map((line, index) => (index === 0 ? line : `${precol}${line}`))
4646
- .join('\n');
4647
- }
4648
- replacedTemplates =
4649
- replacedTemplates.substring(0, match.index + precol.length) +
4650
- parameterValue +
4651
- replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
4652
- }
4653
- // [πŸ’«] Check if there are parameters that are not closed properly
4654
- if (/{\w+$/.test(replacedTemplates)) {
4655
- throw new PipelineExecutionError('Parameter is not closed');
4656
- }
4657
- // [πŸ’«] Check if there are parameters that are not opened properly
4658
- if (/^\w+}/.test(replacedTemplates)) {
4659
- throw new PipelineExecutionError('Parameter is not opened');
4660
- }
4661
- return replacedTemplates;
4662
- }
4663
-
4664
4664
  /**
4665
4665
  * Counts number of characters in the text
4666
4666
  *
@@ -4821,6 +4821,68 @@ function checkExpectations(expectations, value) {
4821
4821
  * Note: [πŸ’] and [🀠] are interconnected together
4822
4822
  */
4823
4823
 
4824
+ /**
4825
+ * Validates a prompt result against expectations and format requirements.
4826
+ * This function provides a common abstraction for result validation that can be used
4827
+ * by both execution logic and caching logic to ensure consistency.
4828
+ *
4829
+ * @param options - The validation options including result string, expectations, and format
4830
+ * @returns Validation result with processed string and validity status
4831
+ * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
4832
+ */
4833
+ function validatePromptResult(options) {
4834
+ const { resultString, expectations, format } = options;
4835
+ let processedResultString = resultString;
4836
+ let validationError;
4837
+ try {
4838
+ // TODO: [πŸ’] Unite object for expecting amount and format
4839
+ if (format) {
4840
+ if (format === 'JSON') {
4841
+ if (!isValidJsonString(processedResultString)) {
4842
+ // TODO: [🏒] Do more universally via `FormatParser`
4843
+ try {
4844
+ processedResultString = extractJsonBlock(processedResultString);
4845
+ }
4846
+ catch (error) {
4847
+ keepUnused(error);
4848
+ throw new ExpectError(spaceTrim$1((block) => `
4849
+ Expected valid JSON string
4850
+
4851
+ The expected JSON text:
4852
+ ${block(processedResultString)}
4853
+ `));
4854
+ }
4855
+ }
4856
+ }
4857
+ else {
4858
+ throw new UnexpectedError(`Unknown format "${format}"`);
4859
+ }
4860
+ }
4861
+ // TODO: [πŸ’] Unite object for expecting amount and format
4862
+ if (expectations) {
4863
+ checkExpectations(expectations, processedResultString);
4864
+ }
4865
+ return {
4866
+ isValid: true,
4867
+ processedResultString,
4868
+ };
4869
+ }
4870
+ catch (error) {
4871
+ if (error instanceof ExpectError) {
4872
+ validationError = error;
4873
+ }
4874
+ else {
4875
+ // Re-throw non-ExpectError errors (like UnexpectedError)
4876
+ throw error;
4877
+ }
4878
+ return {
4879
+ isValid: false,
4880
+ processedResultString,
4881
+ error: validationError,
4882
+ };
4883
+ }
4884
+ }
4885
+
4824
4886
  /**
4825
4887
  * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
4826
4888
  * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
@@ -4838,17 +4900,18 @@ async function executeAttempts(options) {
4838
4900
  $resultString: null,
4839
4901
  $expectError: null,
4840
4902
  $scriptPipelineExecutionErrors: [],
4903
+ $failedResults: [], // Track all failed attempts
4841
4904
  };
4842
4905
  // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
4843
4906
  const _llms = arrayableToArray(tools.llm);
4844
4907
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
4845
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
4846
- const isJokerAttempt = attempt < 0;
4847
- const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
4908
+ attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
4909
+ const isJokerAttempt = attemptIndex < 0;
4910
+ const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
4848
4911
  // TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
4849
4912
  if (isJokerAttempt && !jokerParameterName) {
4850
4913
  throw new UnexpectedError(spaceTrim$1((block) => `
4851
- Joker not found in attempt ${attempt}
4914
+ Joker not found in attempt ${attemptIndex}
4852
4915
 
4853
4916
  ${block(pipelineIdentification)}
4854
4917
  `));
@@ -5046,35 +5109,18 @@ async function executeAttempts(options) {
5046
5109
  }
5047
5110
  }
5048
5111
  // TODO: [πŸ’] Unite object for expecting amount and format
5049
- if (task.format) {
5050
- if (task.format === 'JSON') {
5051
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
5052
- // TODO: [🏒] Do more universally via `FormatParser`
5053
- try {
5054
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
5055
- }
5056
- catch (error) {
5057
- keepUnused(error);
5058
- throw new ExpectError(spaceTrim$1((block) => `
5059
- Expected valid JSON string
5060
-
5061
- ${block(
5062
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
5063
- `));
5064
- }
5065
- }
5066
- }
5067
- else {
5068
- throw new UnexpectedError(spaceTrim$1((block) => `
5069
- Unknown format "${task.format}"
5070
-
5071
- ${block(pipelineIdentification)}
5072
- `));
5112
+ // Use the common validation function for both format and expectations
5113
+ if (task.format || task.expectations) {
5114
+ const validationResult = validatePromptResult({
5115
+ resultString: $ongoingTaskResult.$resultString || '',
5116
+ expectations: task.expectations,
5117
+ format: task.format,
5118
+ });
5119
+ if (!validationResult.isValid) {
5120
+ throw validationResult.error;
5073
5121
  }
5074
- }
5075
- // TODO: [πŸ’] Unite object for expecting amount and format
5076
- if (task.expectations) {
5077
- checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
5122
+ // Update the result string in case format processing modified it (e.g., JSON extraction)
5123
+ $ongoingTaskResult.$resultString = validationResult.processedResultString;
5078
5124
  }
5079
5125
  break attempts;
5080
5126
  }
@@ -5083,6 +5129,15 @@ async function executeAttempts(options) {
5083
5129
  throw error;
5084
5130
  }
5085
5131
  $ongoingTaskResult.$expectError = error;
5132
+ // Store each failed attempt
5133
+ if (!Array.isArray($ongoingTaskResult.$failedResults)) {
5134
+ $ongoingTaskResult.$failedResults = [];
5135
+ }
5136
+ $ongoingTaskResult.$failedResults.push({
5137
+ attemptIndex,
5138
+ result: $ongoingTaskResult.$resultString,
5139
+ error: error,
5140
+ });
5086
5141
  }
5087
5142
  finally {
5088
5143
  if (!isJokerAttempt &&
@@ -5104,35 +5159,41 @@ async function executeAttempts(options) {
5104
5159
  });
5105
5160
  }
5106
5161
  }
5107
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
5162
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
5163
+ // Note: Create a summary of all failures
5164
+ const failuresSummary = $ongoingTaskResult.$failedResults
5165
+ .map((failure) => spaceTrim$1((block) => {
5166
+ var _a, _b;
5167
+ return `
5168
+ Attempt ${failure.attemptIndex + 1}:
5169
+ Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
5170
+ ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
5171
+
5172
+ Result:
5173
+ ${block(failure.result === null
5174
+ ? 'null'
5175
+ : spaceTrim$1(failure.result)
5176
+ .split('\n')
5177
+ .map((line) => `> ${line}`)
5178
+ .join('\n'))}
5179
+ `;
5180
+ }))
5181
+ .join('\n\n---\n\n');
5108
5182
  throw new PipelineExecutionError(spaceTrim$1((block) => {
5109
- var _a, _b, _c;
5183
+ var _a;
5110
5184
  return `
5111
5185
  LLM execution failed ${maxExecutionAttempts}x
5112
5186
 
5113
5187
  ${block(pipelineIdentification)}
5114
5188
 
5115
- ---
5116
5189
  The Prompt:
5117
5190
  ${block((((_a = $ongoingTaskResult.$prompt) === null || _a === void 0 ? void 0 : _a.content) || '')
5118
5191
  .split('\n')
5119
5192
  .map((line) => `> ${line}`)
5120
5193
  .join('\n'))}
5121
5194
 
5122
- Last error ${((_b = $ongoingTaskResult.$expectError) === null || _b === void 0 ? void 0 : _b.name) || ''}:
5123
- ${block((((_c = $ongoingTaskResult.$expectError) === null || _c === void 0 ? void 0 : _c.message) || '')
5124
- .split('\n')
5125
- .map((line) => `> ${line}`)
5126
- .join('\n'))}
5127
-
5128
- Last result:
5129
- ${block($ongoingTaskResult.$resultString === null
5130
- ? 'null'
5131
- : spaceTrim$1($ongoingTaskResult.$resultString)
5132
- .split('\n')
5133
- .map((line) => `> ${line}`)
5134
- .join('\n'))}
5135
- ---
5195
+ All Failed Attempts:
5196
+ ${block(failuresSummary)}
5136
5197
  `;
5137
5198
  }));
5138
5199
  }