@promptbook/legacy-documents 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/legacy-documents`
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
@@ -28,7 +28,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
28
28
  * @generated
29
29
  * @see https://github.com/webgptorg/promptbook
30
30
  */
31
- const PROMPTBOOK_ENGINE_VERSION = '0.95.0';
31
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-10';
32
32
  /**
33
33
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
34
34
  * Note: [πŸ’ž] Ignore a discrepancy between file name and entity name
@@ -177,7 +177,7 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
177
177
  *
178
178
  * @public exported from `@promptbook/core`
179
179
  */
180
- const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
180
+ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [πŸ€Ήβ€β™‚οΈ]
181
181
  // <- TODO: [πŸ•] Make also `BOOKS_DIRNAME_ALTERNATIVES`
182
182
  // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
183
183
  /**
@@ -2562,7 +2562,7 @@ function jsonParse(value) {
2562
2562
  throw new Error(spaceTrim$1((block) => `
2563
2563
  ${block(error.message)}
2564
2564
 
2565
- The JSON text:
2565
+ The expected JSON text:
2566
2566
  ${block(value)}
2567
2567
  `));
2568
2568
  }
@@ -4639,6 +4639,77 @@ function mapAvailableToExpectedParameters(options) {
4639
4639
  return mappedParameters;
4640
4640
  }
4641
4641
 
4642
+ /**
4643
+ * Replaces parameters in template with values from parameters object
4644
+ *
4645
+ * Note: This function is not places strings into string,
4646
+ * It's more complex and can handle this operation specifically for LLM models
4647
+ *
4648
+ * @param template the template with parameters in {curly} braces
4649
+ * @param parameters the object with parameters
4650
+ * @returns the template with replaced parameters
4651
+ * @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
4652
+ * @public exported from `@promptbook/utils`
4653
+ */
4654
+ function templateParameters(template, parameters) {
4655
+ for (const [parameterName, parameterValue] of Object.entries(parameters)) {
4656
+ if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
4657
+ throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
4658
+ }
4659
+ else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
4660
+ // TODO: [🍡]
4661
+ throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
4662
+ }
4663
+ }
4664
+ let replacedTemplates = template;
4665
+ let match;
4666
+ let loopLimit = LOOP_LIMIT;
4667
+ while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
4668
+ .exec(replacedTemplates))) {
4669
+ if (loopLimit-- < 0) {
4670
+ throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
4671
+ }
4672
+ const precol = match.groups.precol;
4673
+ const parameterName = match.groups.parameterName;
4674
+ if (parameterName === '') {
4675
+ // Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
4676
+ continue;
4677
+ }
4678
+ if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
4679
+ throw new PipelineExecutionError('Parameter is already opened or not closed');
4680
+ }
4681
+ if (parameters[parameterName] === undefined) {
4682
+ throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4683
+ }
4684
+ let parameterValue = parameters[parameterName];
4685
+ if (parameterValue === undefined) {
4686
+ throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4687
+ }
4688
+ parameterValue = valueToString(parameterValue);
4689
+ // Escape curly braces in parameter values to prevent prompt-injection
4690
+ parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4691
+ if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
4692
+ parameterValue = parameterValue
4693
+ .split('\n')
4694
+ .map((line, index) => (index === 0 ? line : `${precol}${line}`))
4695
+ .join('\n');
4696
+ }
4697
+ replacedTemplates =
4698
+ replacedTemplates.substring(0, match.index + precol.length) +
4699
+ parameterValue +
4700
+ replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
4701
+ }
4702
+ // [πŸ’«] Check if there are parameters that are not closed properly
4703
+ if (/{\w+$/.test(replacedTemplates)) {
4704
+ throw new PipelineExecutionError('Parameter is not closed');
4705
+ }
4706
+ // [πŸ’«] Check if there are parameters that are not opened properly
4707
+ if (/^\w+}/.test(replacedTemplates)) {
4708
+ throw new PipelineExecutionError('Parameter is not opened');
4709
+ }
4710
+ return replacedTemplates;
4711
+ }
4712
+
4642
4713
  /**
4643
4714
  * Extracts all code blocks from markdown.
4644
4715
  *
@@ -4741,77 +4812,6 @@ function extractJsonBlock(markdown) {
4741
4812
  * TODO: [🏒] Make this logic part of `JsonFormatParser` or `isValidJsonString`
4742
4813
  */
4743
4814
 
4744
- /**
4745
- * Replaces parameters in template with values from parameters object
4746
- *
4747
- * Note: This function is not places strings into string,
4748
- * It's more complex and can handle this operation specifically for LLM models
4749
- *
4750
- * @param template the template with parameters in {curly} braces
4751
- * @param parameters the object with parameters
4752
- * @returns the template with replaced parameters
4753
- * @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
4754
- * @public exported from `@promptbook/utils`
4755
- */
4756
- function templateParameters(template, parameters) {
4757
- for (const [parameterName, parameterValue] of Object.entries(parameters)) {
4758
- if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
4759
- throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
4760
- }
4761
- else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
4762
- // TODO: [🍡]
4763
- throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
4764
- }
4765
- }
4766
- let replacedTemplates = template;
4767
- let match;
4768
- let loopLimit = LOOP_LIMIT;
4769
- while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
4770
- .exec(replacedTemplates))) {
4771
- if (loopLimit-- < 0) {
4772
- throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
4773
- }
4774
- const precol = match.groups.precol;
4775
- const parameterName = match.groups.parameterName;
4776
- if (parameterName === '') {
4777
- // Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
4778
- continue;
4779
- }
4780
- if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
4781
- throw new PipelineExecutionError('Parameter is already opened or not closed');
4782
- }
4783
- if (parameters[parameterName] === undefined) {
4784
- throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4785
- }
4786
- let parameterValue = parameters[parameterName];
4787
- if (parameterValue === undefined) {
4788
- throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4789
- }
4790
- parameterValue = valueToString(parameterValue);
4791
- // Escape curly braces in parameter values to prevent prompt-injection
4792
- parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4793
- if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
4794
- parameterValue = parameterValue
4795
- .split('\n')
4796
- .map((line, index) => (index === 0 ? line : `${precol}${line}`))
4797
- .join('\n');
4798
- }
4799
- replacedTemplates =
4800
- replacedTemplates.substring(0, match.index + precol.length) +
4801
- parameterValue +
4802
- replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
4803
- }
4804
- // [πŸ’«] Check if there are parameters that are not closed properly
4805
- if (/{\w+$/.test(replacedTemplates)) {
4806
- throw new PipelineExecutionError('Parameter is not closed');
4807
- }
4808
- // [πŸ’«] Check if there are parameters that are not opened properly
4809
- if (/^\w+}/.test(replacedTemplates)) {
4810
- throw new PipelineExecutionError('Parameter is not opened');
4811
- }
4812
- return replacedTemplates;
4813
- }
4814
-
4815
4815
  /**
4816
4816
  * Counts number of characters in the text
4817
4817
  *
@@ -4972,6 +4972,68 @@ function checkExpectations(expectations, value) {
4972
4972
  * Note: [πŸ’] and [🀠] are interconnected together
4973
4973
  */
4974
4974
 
4975
+ /**
4976
+ * Validates a prompt result against expectations and format requirements.
4977
+ * This function provides a common abstraction for result validation that can be used
4978
+ * by both execution logic and caching logic to ensure consistency.
4979
+ *
4980
+ * @param options - The validation options including result string, expectations, and format
4981
+ * @returns Validation result with processed string and validity status
4982
+ * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
4983
+ */
4984
+ function validatePromptResult(options) {
4985
+ const { resultString, expectations, format } = options;
4986
+ let processedResultString = resultString;
4987
+ let validationError;
4988
+ try {
4989
+ // TODO: [πŸ’] Unite object for expecting amount and format
4990
+ if (format) {
4991
+ if (format === 'JSON') {
4992
+ if (!isValidJsonString(processedResultString)) {
4993
+ // TODO: [🏒] Do more universally via `FormatParser`
4994
+ try {
4995
+ processedResultString = extractJsonBlock(processedResultString);
4996
+ }
4997
+ catch (error) {
4998
+ keepUnused(error);
4999
+ throw new ExpectError(spaceTrim((block) => `
5000
+ Expected valid JSON string
5001
+
5002
+ The expected JSON text:
5003
+ ${block(processedResultString)}
5004
+ `));
5005
+ }
5006
+ }
5007
+ }
5008
+ else {
5009
+ throw new UnexpectedError(`Unknown format "${format}"`);
5010
+ }
5011
+ }
5012
+ // TODO: [πŸ’] Unite object for expecting amount and format
5013
+ if (expectations) {
5014
+ checkExpectations(expectations, processedResultString);
5015
+ }
5016
+ return {
5017
+ isValid: true,
5018
+ processedResultString,
5019
+ };
5020
+ }
5021
+ catch (error) {
5022
+ if (error instanceof ExpectError) {
5023
+ validationError = error;
5024
+ }
5025
+ else {
5026
+ // Re-throw non-ExpectError errors (like UnexpectedError)
5027
+ throw error;
5028
+ }
5029
+ return {
5030
+ isValid: false,
5031
+ processedResultString,
5032
+ error: validationError,
5033
+ };
5034
+ }
5035
+ }
5036
+
4975
5037
  /**
4976
5038
  * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
4977
5039
  * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
@@ -4989,17 +5051,18 @@ async function executeAttempts(options) {
4989
5051
  $resultString: null,
4990
5052
  $expectError: null,
4991
5053
  $scriptPipelineExecutionErrors: [],
5054
+ $failedResults: [], // Track all failed attempts
4992
5055
  };
4993
5056
  // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
4994
5057
  const _llms = arrayableToArray(tools.llm);
4995
5058
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
4996
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
4997
- const isJokerAttempt = attempt < 0;
4998
- const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
5059
+ attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
5060
+ const isJokerAttempt = attemptIndex < 0;
5061
+ const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
4999
5062
  // TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
5000
5063
  if (isJokerAttempt && !jokerParameterName) {
5001
5064
  throw new UnexpectedError(spaceTrim((block) => `
5002
- Joker not found in attempt ${attempt}
5065
+ Joker not found in attempt ${attemptIndex}
5003
5066
 
5004
5067
  ${block(pipelineIdentification)}
5005
5068
  `));
@@ -5197,35 +5260,18 @@ async function executeAttempts(options) {
5197
5260
  }
5198
5261
  }
5199
5262
  // TODO: [πŸ’] Unite object for expecting amount and format
5200
- if (task.format) {
5201
- if (task.format === 'JSON') {
5202
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
5203
- // TODO: [🏒] Do more universally via `FormatParser`
5204
- try {
5205
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
5206
- }
5207
- catch (error) {
5208
- keepUnused(error);
5209
- throw new ExpectError(spaceTrim((block) => `
5210
- Expected valid JSON string
5211
-
5212
- ${block(
5213
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
5214
- `));
5215
- }
5216
- }
5217
- }
5218
- else {
5219
- throw new UnexpectedError(spaceTrim((block) => `
5220
- Unknown format "${task.format}"
5221
-
5222
- ${block(pipelineIdentification)}
5223
- `));
5263
+ // Use the common validation function for both format and expectations
5264
+ if (task.format || task.expectations) {
5265
+ const validationResult = validatePromptResult({
5266
+ resultString: $ongoingTaskResult.$resultString || '',
5267
+ expectations: task.expectations,
5268
+ format: task.format,
5269
+ });
5270
+ if (!validationResult.isValid) {
5271
+ throw validationResult.error;
5224
5272
  }
5225
- }
5226
- // TODO: [πŸ’] Unite object for expecting amount and format
5227
- if (task.expectations) {
5228
- checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
5273
+ // Update the result string in case format processing modified it (e.g., JSON extraction)
5274
+ $ongoingTaskResult.$resultString = validationResult.processedResultString;
5229
5275
  }
5230
5276
  break attempts;
5231
5277
  }
@@ -5234,6 +5280,15 @@ async function executeAttempts(options) {
5234
5280
  throw error;
5235
5281
  }
5236
5282
  $ongoingTaskResult.$expectError = error;
5283
+ // Store each failed attempt
5284
+ if (!Array.isArray($ongoingTaskResult.$failedResults)) {
5285
+ $ongoingTaskResult.$failedResults = [];
5286
+ }
5287
+ $ongoingTaskResult.$failedResults.push({
5288
+ attemptIndex,
5289
+ result: $ongoingTaskResult.$resultString,
5290
+ error: error,
5291
+ });
5237
5292
  }
5238
5293
  finally {
5239
5294
  if (!isJokerAttempt &&
@@ -5255,35 +5310,41 @@ async function executeAttempts(options) {
5255
5310
  });
5256
5311
  }
5257
5312
  }
5258
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
5313
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
5314
+ // Note: Create a summary of all failures
5315
+ const failuresSummary = $ongoingTaskResult.$failedResults
5316
+ .map((failure) => spaceTrim((block) => {
5317
+ var _a, _b;
5318
+ return `
5319
+ Attempt ${failure.attemptIndex + 1}:
5320
+ Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
5321
+ ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
5322
+
5323
+ Result:
5324
+ ${block(failure.result === null
5325
+ ? 'null'
5326
+ : spaceTrim(failure.result)
5327
+ .split('\n')
5328
+ .map((line) => `> ${line}`)
5329
+ .join('\n'))}
5330
+ `;
5331
+ }))
5332
+ .join('\n\n---\n\n');
5259
5333
  throw new PipelineExecutionError(spaceTrim((block) => {
5260
- var _a, _b, _c;
5334
+ var _a;
5261
5335
  return `
5262
5336
  LLM execution failed ${maxExecutionAttempts}x
5263
5337
 
5264
5338
  ${block(pipelineIdentification)}
5265
5339
 
5266
- ---
5267
5340
  The Prompt:
5268
5341
  ${block((((_a = $ongoingTaskResult.$prompt) === null || _a === void 0 ? void 0 : _a.content) || '')
5269
5342
  .split('\n')
5270
5343
  .map((line) => `> ${line}`)
5271
5344
  .join('\n'))}
5272
5345
 
5273
- Last error ${((_b = $ongoingTaskResult.$expectError) === null || _b === void 0 ? void 0 : _b.name) || ''}:
5274
- ${block((((_c = $ongoingTaskResult.$expectError) === null || _c === void 0 ? void 0 : _c.message) || '')
5275
- .split('\n')
5276
- .map((line) => `> ${line}`)
5277
- .join('\n'))}
5278
-
5279
- Last result:
5280
- ${block($ongoingTaskResult.$resultString === null
5281
- ? 'null'
5282
- : spaceTrim($ongoingTaskResult.$resultString)
5283
- .split('\n')
5284
- .map((line) => `> ${line}`)
5285
- .join('\n'))}
5286
- ---
5346
+ All Failed Attempts:
5347
+ ${block(failuresSummary)}
5287
5348
  `;
5288
5349
  }));
5289
5350
  }