@promptbook/pdf 0.94.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 (75) hide show
  1. package/README.md +6 -2
  2. package/esm/index.es.js +229 -168
  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 +14 -4
  9. package/esm/typings/src/_packages/{wizzard.index.d.ts → wizard.index.d.ts} +6 -2
  10. package/esm/typings/src/cli/cli-commands/prettify.d.ts +1 -1
  11. package/esm/typings/src/cli/cli-commands/test-command.d.ts +1 -1
  12. package/esm/typings/src/config.d.ts +1 -1
  13. package/esm/typings/src/conversion/archive/loadArchive.d.ts +1 -1
  14. package/esm/typings/src/conversion/archive/saveArchive.d.ts +2 -2
  15. package/esm/typings/src/conversion/prettify/renderPipelineMermaidOptions.d.ts +1 -1
  16. package/esm/typings/src/dialogs/callback/CallbackInterfaceTools.d.ts +1 -1
  17. package/esm/typings/src/execution/AbstractTaskResult.d.ts +2 -2
  18. package/esm/typings/src/execution/createPipelineExecutor/$OngoingTaskResult.d.ts +8 -0
  19. package/esm/typings/src/execution/createPipelineExecutor/00-CreatePipelineExecutorOptions.d.ts +1 -1
  20. package/esm/typings/src/execution/execution-report/ExecutionPromptReportJson.d.ts +2 -2
  21. package/esm/typings/src/execution/translation/automatic-translate/translateMessages.d.ts +1 -1
  22. package/esm/typings/src/execution/utils/validatePromptResult.d.ts +53 -0
  23. package/esm/typings/src/llm-providers/_common/register/{$provideLlmToolsForWizzardOrCli.d.ts → $provideLlmToolsForWizardOrCli.d.ts} +2 -2
  24. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +3 -3
  25. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +2 -2
  26. package/esm/typings/src/llm-providers/anthropic-claude/register-configuration.d.ts +1 -1
  27. package/esm/typings/src/llm-providers/anthropic-claude/register-constructor.d.ts +1 -1
  28. package/esm/typings/src/llm-providers/azure-openai/register-configuration.d.ts +1 -1
  29. package/esm/typings/src/llm-providers/azure-openai/register-constructor.d.ts +1 -1
  30. package/esm/typings/src/llm-providers/deepseek/register-configuration.d.ts +1 -1
  31. package/esm/typings/src/llm-providers/deepseek/register-constructor.d.ts +1 -1
  32. package/esm/typings/src/llm-providers/google/register-configuration.d.ts +1 -1
  33. package/esm/typings/src/llm-providers/google/register-constructor.d.ts +1 -1
  34. package/esm/typings/src/llm-providers/ollama/register-configuration.d.ts +1 -1
  35. package/esm/typings/src/llm-providers/ollama/register-constructor.d.ts +1 -1
  36. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +1 -1
  37. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +2 -2
  38. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +4 -4
  39. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionToolsOptions.d.ts +52 -0
  40. package/esm/typings/src/llm-providers/openai/OpenAiExecutionToolsOptions.d.ts +3 -5
  41. package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +74 -0
  42. package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +13 -2
  43. package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +16 -2
  44. package/esm/typings/src/remote-server/socket-types/listModels/PromptbookServer_ListModels_Request.d.ts +1 -1
  45. package/esm/typings/src/scrapers/_boilerplate/createBoilerplateScraper.d.ts +1 -1
  46. package/esm/typings/src/scrapers/_boilerplate/register-constructor.d.ts +1 -1
  47. package/esm/typings/src/scrapers/_boilerplate/register-metadata.d.ts +2 -2
  48. package/esm/typings/src/scrapers/_common/prepareKnowledgePieces.d.ts +1 -1
  49. package/esm/typings/src/scrapers/_common/register/ScraperAndConverterMetadata.d.ts +1 -1
  50. package/esm/typings/src/scrapers/document/createDocumentScraper.d.ts +1 -1
  51. package/esm/typings/src/scrapers/document/register-constructor.d.ts +1 -1
  52. package/esm/typings/src/scrapers/document/register-metadata.d.ts +2 -2
  53. package/esm/typings/src/scrapers/document-legacy/createLegacyDocumentScraper.d.ts +1 -1
  54. package/esm/typings/src/scrapers/document-legacy/register-constructor.d.ts +1 -1
  55. package/esm/typings/src/scrapers/document-legacy/register-metadata.d.ts +2 -2
  56. package/esm/typings/src/scrapers/markdown/createMarkdownScraper.d.ts +1 -4
  57. package/esm/typings/src/scrapers/markdown/register-constructor.d.ts +1 -1
  58. package/esm/typings/src/scrapers/markdown/register-metadata.d.ts +2 -2
  59. package/esm/typings/src/scrapers/markitdown/createMarkitdownScraper.d.ts +1 -1
  60. package/esm/typings/src/scrapers/markitdown/register-constructor.d.ts +1 -1
  61. package/esm/typings/src/scrapers/markitdown/register-metadata.d.ts +2 -2
  62. package/esm/typings/src/scrapers/pdf/createPdfScraper.d.ts +1 -1
  63. package/esm/typings/src/scrapers/pdf/register-constructor.d.ts +1 -1
  64. package/esm/typings/src/scrapers/pdf/register-metadata.d.ts +2 -2
  65. package/esm/typings/src/scrapers/website/createWebsiteScraper.d.ts +1 -1
  66. package/esm/typings/src/scrapers/website/register-constructor.d.ts +1 -1
  67. package/esm/typings/src/scrapers/website/register-metadata.d.ts +2 -2
  68. package/esm/typings/src/types/typeAliases.d.ts +1 -1
  69. package/esm/typings/src/utils/files/listAllFiles.d.ts +1 -1
  70. package/esm/typings/src/version.d.ts +1 -1
  71. package/esm/typings/src/{wizzard → wizard}/$getCompiledBook.d.ts +2 -2
  72. package/esm/typings/src/{wizzard/wizzard.d.ts → wizard/wizard.d.ts} +6 -6
  73. package/package.json +2 -14
  74. package/umd/index.umd.js +229 -168
  75. package/umd/index.umd.js.map +1 -1
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.94.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
  /**
@@ -875,7 +875,7 @@ async function getScraperIntermediateSource(source, options) {
875
875
  * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
876
876
  */
877
877
 
878
- var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n```json\n{availableModels}\n```\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
878
+ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpful assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n```json\n{availableModels}\n```\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpful assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
879
879
 
880
880
  /**
881
881
  * Checks if value is valid email
@@ -1032,7 +1032,7 @@ function prettifyMarkdown(content) {
1032
1032
  });
1033
1033
  }
1034
1034
  catch (error) {
1035
- // TODO: [🟥] Detect browser / node and make it colorfull
1035
+ // TODO: [🟥] Detect browser / node and make it colorful
1036
1036
  console.error('There was an error with prettifying the markdown, using the original as the fallback', {
1037
1037
  error,
1038
1038
  html: content,
@@ -1314,7 +1314,7 @@ function checkSerializableAsJson(options) {
1314
1314
  else {
1315
1315
  for (const [subName, subValue] of Object.entries(value)) {
1316
1316
  if (subValue === undefined) {
1317
- // Note: undefined in object is serializable - it is just omited
1317
+ // Note: undefined in object is serializable - it is just omitted
1318
1318
  continue;
1319
1319
  }
1320
1320
  checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
@@ -2004,7 +2004,7 @@ class SimplePipelineCollection {
2004
2004
 
2005
2005
  Note: You have probably forgotten to run "ptbk make" to update the collection
2006
2006
  Note: Pipelines with the same URL are not allowed
2007
- Only exepction is when the pipelines are identical
2007
+ Only exception is when the pipelines are identical
2008
2008
 
2009
2009
  `));
2010
2010
  }
@@ -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
  }
@@ -2772,12 +2772,12 @@ function countUsage(llmTools) {
2772
2772
  get title() {
2773
2773
  return `${llmTools.title} (+usage)`;
2774
2774
  // <- TODO: [🧈] Maybe standartize the suffix when wrapping `LlmExecutionTools` up
2775
- // <- TODO: [🧈][🧠] Does it make sence to suffix "(+usage)"?
2775
+ // <- TODO: [🧈][🧠] Does it make sense to suffix "(+usage)"?
2776
2776
  },
2777
2777
  get description() {
2778
2778
  return `${llmTools.description} (+usage)`;
2779
2779
  // <- TODO: [🧈] Maybe standartize the suffix when wrapping `LlmExecutionTools` up
2780
- // <- TODO: [🧈][🧠] Does it make sence to suffix "(+usage)"?
2780
+ // <- TODO: [🧈][🧠] Does it make sense to suffix "(+usage)"?
2781
2781
  },
2782
2782
  checkConfiguration() {
2783
2783
  return /* not await */ llmTools.checkConfiguration();
@@ -3004,13 +3004,13 @@ function joinLlmExecutionTools(...llmExecutionTools) {
3004
3004
 
3005
3005
  Technically, it's not an error, but it's probably not what you want because it does not make sense to use Promptbook without language models.
3006
3006
  `);
3007
- // TODO: [🟥] Detect browser / node and make it colorfull
3007
+ // TODO: [🟥] Detect browser / node and make it colorful
3008
3008
  console.warn(warningMessage);
3009
3009
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
3010
3010
  /*
3011
3011
  return {
3012
3012
  async listModels() {
3013
- // TODO: [🟥] Detect browser / node and make it colorfull
3013
+ // TODO: [🟥] Detect browser / node and make it colorful
3014
3014
  console.warn(
3015
3015
  spaceTrim(
3016
3016
  (block) => `
@@ -3286,17 +3286,17 @@ function $registeredScrapersMessage(availableScrapers) {
3286
3286
  * Mixes registered scrapers from $scrapersMetadataRegister and $scrapersRegister
3287
3287
  */
3288
3288
  const all = [];
3289
- for (const { packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser, } of $scrapersMetadataRegister.list()) {
3289
+ for (const { packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser, } of $scrapersMetadataRegister.list()) {
3290
3290
  if (all.some((item) => item.packageName === packageName && item.className === className)) {
3291
3291
  continue;
3292
3292
  }
3293
- all.push({ packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser });
3293
+ all.push({ packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser });
3294
3294
  }
3295
- for (const { packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser, } of $scrapersRegister.list()) {
3295
+ for (const { packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser, } of $scrapersRegister.list()) {
3296
3296
  if (all.some((item) => item.packageName === packageName && item.className === className)) {
3297
3297
  continue;
3298
3298
  }
3299
- all.push({ packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser });
3299
+ all.push({ packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser });
3300
3300
  }
3301
3301
  for (const { metadata } of availableScrapers) {
3302
3302
  all.push(metadata);
@@ -3308,8 +3308,8 @@ function $registeredScrapersMessage(availableScrapers) {
3308
3308
  const isInstalled = $scrapersRegister
3309
3309
  .list()
3310
3310
  .find(({ packageName, className }) => metadata.packageName === packageName && metadata.className === className);
3311
- const isAvilableInTools = availableScrapers.some(({ metadata: { packageName, className } }) => metadata.packageName === packageName && metadata.className === className);
3312
- return { ...metadata, isMetadataAviailable, isInstalled, isAvilableInTools };
3311
+ const isAvailableInTools = availableScrapers.some(({ metadata: { packageName, className } }) => metadata.packageName === packageName && metadata.className === className);
3312
+ return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
3313
3313
  });
3314
3314
  if (metadata.length === 0) {
3315
3315
  return spaceTrim(`
@@ -3322,7 +3322,7 @@ function $registeredScrapersMessage(availableScrapers) {
3322
3322
  return spaceTrim((block) => `
3323
3323
  Available scrapers are:
3324
3324
  ${block(metadata
3325
- .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvilableInBrowser, isAvilableInTools, }, i) => {
3325
+ .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
3326
3326
  const more = [];
3327
3327
  // TODO: [🧠] Maybe use `documentationUrl`
3328
3328
  if (isMetadataAviailable) {
@@ -3331,16 +3331,16 @@ function $registeredScrapersMessage(availableScrapers) {
3331
3331
  if (isInstalled) {
3332
3332
  more.push(`🟩 Installed`);
3333
3333
  } // not else
3334
- if (isAvilableInTools) {
3334
+ if (isAvailableInTools) {
3335
3335
  more.push(`🟦 Available in tools`);
3336
3336
  } // not else
3337
3337
  if (!isMetadataAviailable && isInstalled) {
3338
3338
  more.push(`When no metadata registered but scraper is installed, it is an unexpected behavior`);
3339
3339
  } // not else
3340
- if (!isInstalled && isAvilableInTools) {
3340
+ if (!isInstalled && isAvailableInTools) {
3341
3341
  more.push(`When the scraper is not installed but available in tools, it is an unexpected compatibility behavior`);
3342
3342
  } // not else
3343
- if (!isAvilableInBrowser) {
3343
+ if (!isAvailableInBrowser) {
3344
3344
  more.push(`Not usable in browser`);
3345
3345
  }
3346
3346
  const moreText = more.length === 0 ? '' : ` *(${more.join('; ')})*`;
@@ -3680,7 +3680,7 @@ TODO: [🧊] This is how it can look in future
3680
3680
  /**
3681
3681
  * TODO: [🧊] In future one preparation can take data from previous preparation and save tokens and time
3682
3682
  * Put `knowledgePieces` into `PrepareKnowledgeOptions`
3683
- * TODO: [🪂] More than max things can run in parallel by acident [1,[2a,2b,_],[3a,3b,_]]
3683
+ * TODO: [🪂] More than max things can run in parallel by accident [1,[2a,2b,_],[3a,3b,_]]
3684
3684
  * TODO: [🧠][❎] Do here proper M:N mapping
3685
3685
  * [x] One source can make multiple pieces
3686
3686
  * [ ] One piece can have multiple sources
@@ -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
  }
@@ -5352,10 +5413,10 @@ function knowledgePiecesToString(knowledgePieces) {
5352
5413
  */
5353
5414
  async function getKnowledgeForTask(options) {
5354
5415
  const { tools, preparedPipeline, task, parameters } = options;
5355
- const firstKnowlegePiece = preparedPipeline.knowledgePieces[0];
5356
- const firstKnowlegeIndex = firstKnowlegePiece === null || firstKnowlegePiece === void 0 ? void 0 : firstKnowlegePiece.index[0];
5416
+ const firstKnowledgePiece = preparedPipeline.knowledgePieces[0];
5417
+ const firstKnowledgeIndex = firstKnowledgePiece === null || firstKnowledgePiece === void 0 ? void 0 : firstKnowledgePiece.index[0];
5357
5418
  // <- TODO: Do not use just first knowledge piece and first index to determine embedding model, use also keyword search
5358
- if (firstKnowlegePiece === undefined || firstKnowlegeIndex === undefined) {
5419
+ if (firstKnowledgePiece === undefined || firstKnowledgeIndex === undefined) {
5359
5420
  return ''; // <- Note: Np knowledge present, return empty string
5360
5421
  }
5361
5422
  try {
@@ -5366,7 +5427,7 @@ async function getKnowledgeForTask(options) {
5366
5427
  title: 'Knowledge Search',
5367
5428
  modelRequirements: {
5368
5429
  modelVariant: 'EMBEDDING',
5369
- modelName: firstKnowlegeIndex.modelName,
5430
+ modelName: firstKnowledgeIndex.modelName,
5370
5431
  },
5371
5432
  content: task.content,
5372
5433
  parameters,
@@ -5374,7 +5435,7 @@ async function getKnowledgeForTask(options) {
5374
5435
  const taskEmbeddingResult = await llmTools.callEmbeddingModel(taskEmbeddingPrompt);
5375
5436
  const knowledgePiecesWithRelevance = preparedPipeline.knowledgePieces.map((knowledgePiece) => {
5376
5437
  const { index } = knowledgePiece;
5377
- const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowlegeIndex.modelName);
5438
+ const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowledgeIndex.modelName);
5378
5439
  // <- TODO: Do not use just first knowledge piece and first index to determine embedding model
5379
5440
  if (knowledgePieceIndex === undefined) {
5380
5441
  return {
@@ -5395,8 +5456,8 @@ async function getKnowledgeForTask(options) {
5395
5456
  task,
5396
5457
  taskEmbeddingPrompt,
5397
5458
  taskEmbeddingResult,
5398
- firstKnowlegePiece,
5399
- firstKnowlegeIndex,
5459
+ firstKnowledgePiece,
5460
+ firstKnowledgeIndex,
5400
5461
  knowledgePiecesWithRelevance,
5401
5462
  knowledgePiecesSorted,
5402
5463
  knowledgePiecesLimited,
@@ -5465,7 +5526,7 @@ async function getReservedParametersForTask(options) {
5465
5526
  * @private internal utility of `createPipelineExecutor`
5466
5527
  */
5467
5528
  async function executeTask(options) {
5468
- const { currentTask, preparedPipeline, parametersToPass, tools, onProgress, $executionReport, pipelineIdentification, maxExecutionAttempts, maxParallelCount, csvSettings, isVerbose, rootDirname, cacheDirname, intermediateFilesStrategy, isAutoInstalled, isNotPreparedWarningSupressed, } = options;
5529
+ const { currentTask, preparedPipeline, parametersToPass, tools, onProgress, $executionReport, pipelineIdentification, maxExecutionAttempts, maxParallelCount, csvSettings, isVerbose, rootDirname, cacheDirname, intermediateFilesStrategy, isAutoInstalled, isNotPreparedWarningSuppressed, } = options;
5469
5530
  const priority = preparedPipeline.tasks.length - preparedPipeline.tasks.indexOf(currentTask);
5470
5531
  // Note: Check consistency of used and dependent parameters which was also done in `validatePipeline`, but it’s good to doublecheck
5471
5532
  const usedParameterNames = extractParameterNamesFromTask(currentTask);
@@ -5553,7 +5614,7 @@ async function executeTask(options) {
5553
5614
  cacheDirname,
5554
5615
  intermediateFilesStrategy,
5555
5616
  isAutoInstalled,
5556
- isNotPreparedWarningSupressed,
5617
+ isNotPreparedWarningSuppressed,
5557
5618
  });
5558
5619
  await onProgress({
5559
5620
  outputParameters: {
@@ -5648,7 +5709,7 @@ async function executePipeline(options) {
5648
5709
  }
5649
5710
  return exportJson({
5650
5711
  name: `executionReport`,
5651
- message: `Unuccessful PipelineExecutorResult (with missing parameter {${parameter.name}}) PipelineExecutorResult`,
5712
+ message: `Unsuccessful PipelineExecutorResult (with missing parameter {${parameter.name}}) PipelineExecutorResult`,
5652
5713
  order: [],
5653
5714
  value: {
5654
5715
  isSuccessful: false,
@@ -5685,7 +5746,7 @@ async function executePipeline(options) {
5685
5746
  return exportJson({
5686
5747
  name: 'pipelineExecutorResult',
5687
5748
  message: spaceTrim$1((block) => `
5688
- Unuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
5749
+ Unsuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
5689
5750
 
5690
5751
  ${block(pipelineIdentification)}
5691
5752
  `),
@@ -5826,7 +5887,7 @@ async function executePipeline(options) {
5826
5887
  }
5827
5888
  return exportJson({
5828
5889
  name: 'pipelineExecutorResult',
5829
- message: `Unuccessful PipelineExecutorResult (with misc errors) PipelineExecutorResult`,
5890
+ message: `Unsuccessful PipelineExecutorResult (with misc errors) PipelineExecutorResult`,
5830
5891
  order: [],
5831
5892
  value: {
5832
5893
  isSuccessful: false,
@@ -5877,7 +5938,7 @@ async function executePipeline(options) {
5877
5938
  * @public exported from `@promptbook/core`
5878
5939
  */
5879
5940
  function createPipelineExecutor(options) {
5880
- const { pipeline, tools, maxExecutionAttempts = DEFAULT_MAX_EXECUTION_ATTEMPTS, maxParallelCount = DEFAULT_MAX_PARALLEL_COUNT, csvSettings = DEFAULT_CSV_SETTINGS, isVerbose = DEFAULT_IS_VERBOSE, isNotPreparedWarningSupressed = false, cacheDirname = DEFAULT_SCRAPE_CACHE_DIRNAME, intermediateFilesStrategy = DEFAULT_INTERMEDIATE_FILES_STRATEGY, isAutoInstalled = DEFAULT_IS_AUTO_INSTALLED, rootDirname = null, } = options;
5941
+ const { pipeline, tools, maxExecutionAttempts = DEFAULT_MAX_EXECUTION_ATTEMPTS, maxParallelCount = DEFAULT_MAX_PARALLEL_COUNT, csvSettings = DEFAULT_CSV_SETTINGS, isVerbose = DEFAULT_IS_VERBOSE, isNotPreparedWarningSuppressed = false, cacheDirname = DEFAULT_SCRAPE_CACHE_DIRNAME, intermediateFilesStrategy = DEFAULT_INTERMEDIATE_FILES_STRATEGY, isAutoInstalled = DEFAULT_IS_AUTO_INSTALLED, rootDirname = null, } = options;
5881
5942
  validatePipeline(pipeline);
5882
5943
  const pipelineIdentification = (() => {
5883
5944
  // Note: This is a 😐 implementation of [🚞]
@@ -5894,7 +5955,7 @@ function createPipelineExecutor(options) {
5894
5955
  if (isPipelinePrepared(pipeline)) {
5895
5956
  preparedPipeline = pipeline;
5896
5957
  }
5897
- else if (isNotPreparedWarningSupressed !== true) {
5958
+ else if (isNotPreparedWarningSuppressed !== true) {
5898
5959
  console.warn(spaceTrim$1((block) => `
5899
5960
  Pipeline is not prepared
5900
5961
 
@@ -5927,7 +5988,7 @@ function createPipelineExecutor(options) {
5927
5988
  maxParallelCount,
5928
5989
  csvSettings,
5929
5990
  isVerbose,
5930
- isNotPreparedWarningSupressed,
5991
+ isNotPreparedWarningSuppressed,
5931
5992
  rootDirname,
5932
5993
  cacheDirname,
5933
5994
  intermediateFilesStrategy,
@@ -5936,7 +5997,7 @@ function createPipelineExecutor(options) {
5936
5997
  assertsError(error);
5937
5998
  return exportJson({
5938
5999
  name: 'pipelineExecutorResult',
5939
- message: `Unuccessful PipelineExecutorResult, last catch`,
6000
+ message: `Unsuccessful PipelineExecutorResult, last catch`,
5940
6001
  order: [],
5941
6002
  value: {
5942
6003
  isSuccessful: false,
@@ -5974,7 +6035,7 @@ const markdownScraperMetadata = $deepFreeze({
5974
6035
  className: 'MarkdownScraper',
5975
6036
  mimeTypes: ['text/markdown', 'text/plain'],
5976
6037
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
5977
- isAvilableInBrowser: true,
6038
+ isAvailableInBrowser: true,
5978
6039
  // <- Note: [🌏] This is the only scraper which makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
5979
6040
  requiredExecutables: [],
5980
6041
  }); /* <- Note: [🤛] */
@@ -5984,7 +6045,7 @@ const markdownScraperMetadata = $deepFreeze({
5984
6045
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
5985
6046
  *
5986
6047
  * @public exported from `@promptbook/core`
5987
- * @public exported from `@promptbook/wizzard`
6048
+ * @public exported from `@promptbook/wizard`
5988
6049
  * @public exported from `@promptbook/cli`
5989
6050
  */
5990
6051
  $scrapersMetadataRegister.register(markdownScraperMetadata);
@@ -6083,7 +6144,7 @@ class MarkdownScraper {
6083
6144
  }
6084
6145
  // ---
6085
6146
  if (!llmTools.callEmbeddingModel) {
6086
- // TODO: [🟥] Detect browser / node and make it colorfull
6147
+ // TODO: [🟥] Detect browser / node and make it colorful
6087
6148
  console.error('No callEmbeddingModel function provided');
6088
6149
  }
6089
6150
  else {
@@ -6109,7 +6170,7 @@ class MarkdownScraper {
6109
6170
  if (!(error instanceof PipelineExecutionError)) {
6110
6171
  throw error;
6111
6172
  }
6112
- // TODO: [🟥] Detect browser / node and make it colorfull
6173
+ // TODO: [🟥] Detect browser / node and make it colorful
6113
6174
  console.error(error, "<- Note: This error is not critical to prepare the pipeline, just knowledge pieces won't have embeddings");
6114
6175
  }
6115
6176
  return {
@@ -6145,7 +6206,7 @@ const markitdownScraperMetadata = $deepFreeze({
6145
6206
  // 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
6146
6207
  ],
6147
6208
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
6148
- isAvilableInBrowser: false,
6209
+ isAvailableInBrowser: false,
6149
6210
  // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
6150
6211
  requiredExecutables: [],
6151
6212
  }); /* <- Note: [🤛] */
@@ -6155,7 +6216,7 @@ const markitdownScraperMetadata = $deepFreeze({
6155
6216
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
6156
6217
  *
6157
6218
  * @public exported from `@promptbook/core`
6158
- * @public exported from `@promptbook/wizzard`
6219
+ * @public exported from `@promptbook/wizard`
6159
6220
  * @public exported from `@promptbook/cli`
6160
6221
  */
6161
6222
  $scrapersMetadataRegister.register(markitdownScraperMetadata);
@@ -6292,7 +6353,7 @@ const createMarkitdownScraper = Object.assign((tools, options) => {
6292
6353
  *
6293
6354
  * @public exported from `@promptbook/markitdown`
6294
6355
  * @public exported from `@promptbook/pdf`
6295
- * @public exported from `@promptbook/wizzard`
6356
+ * @public exported from `@promptbook/wizard`
6296
6357
  * @public exported from `@promptbook/cli`
6297
6358
  */
6298
6359
  const _MarkitdownScraperRegistration = $scrapersRegister.register(createMarkitdownScraper);
@@ -6313,7 +6374,7 @@ const pdfScraperMetadata = $deepFreeze({
6313
6374
  className: 'PdfScraper',
6314
6375
  mimeTypes: ['application/pdf-DISABLED'],
6315
6376
  documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
6316
- isAvilableInBrowser: false,
6377
+ isAvailableInBrowser: false,
6317
6378
  // <- Note: [🌏] Only `MarkdownScraper` makes sense to be available in the browser, for scraping non-markdown sources in the browser use a remote server
6318
6379
  requiredExecutables: [],
6319
6380
  }); /* <- Note: [🤛] */
@@ -6323,7 +6384,7 @@ const pdfScraperMetadata = $deepFreeze({
6323
6384
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
6324
6385
  *
6325
6386
  * @public exported from `@promptbook/core`
6326
- * @public exported from `@promptbook/wizzard`
6387
+ * @public exported from `@promptbook/wizard`
6327
6388
  * @public exported from `@promptbook/cli`
6328
6389
  */
6329
6390
  $scrapersMetadataRegister.register(pdfScraperMetadata);
@@ -6398,7 +6459,7 @@ const createPdfScraper = Object.assign((tools, options) => {
6398
6459
  * Warning: This is not useful for the end user, it is just a side effect of the mechanism that handles all available known scrapers
6399
6460
  *
6400
6461
  * @public exported from `@promptbook/pdf`
6401
- * @public exported from `@promptbook/wizzard`
6462
+ * @public exported from `@promptbook/wizard`
6402
6463
  * @public exported from `@promptbook/cli`
6403
6464
  */
6404
6465
  const _PdfScraperRegistration = $scrapersRegister.register(createPdfScraper);