@promptbook/remote-server 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 +338 -216
  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 +338 -216
  75. package/umd/index.umd.js.map +1 -1
package/umd/index.umd.js CHANGED
@@ -48,7 +48,7 @@
48
48
  * @generated
49
49
  * @see https://github.com/webgptorg/promptbook
50
50
  */
51
- const PROMPTBOOK_ENGINE_VERSION = '0.94.0';
51
+ const PROMPTBOOK_ENGINE_VERSION = '0.98.0-10';
52
52
  /**
53
53
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
54
54
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -188,7 +188,7 @@
188
188
  *
189
189
  * @public exported from `@promptbook/core`
190
190
  */
191
- const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [🤹‍♂️]
191
+ const DEFAULT_MAX_EXECUTION_ATTEMPTS = 7; // <- TODO: [🤹‍♂️]
192
192
  // <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
193
193
  // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
194
194
  /**
@@ -1241,7 +1241,7 @@
1241
1241
  else {
1242
1242
  for (const [subName, subValue] of Object.entries(value)) {
1243
1243
  if (subValue === undefined) {
1244
- // Note: undefined in object is serializable - it is just omited
1244
+ // Note: undefined in object is serializable - it is just omitted
1245
1245
  continue;
1246
1246
  }
1247
1247
  checkSerializableAsJson({ name: `${name}.${subName}`, value: subValue, message });
@@ -1906,7 +1906,7 @@
1906
1906
  throw new Error(spaceTrim__default["default"]((block) => `
1907
1907
  ${block(error.message)}
1908
1908
 
1909
- The JSON text:
1909
+ The expected JSON text:
1910
1910
  ${block(value)}
1911
1911
  `));
1912
1912
  }
@@ -2187,7 +2187,7 @@
2187
2187
  * Note: [💞] Ignore a discrepancy between file name and entity name
2188
2188
  */
2189
2189
 
2190
- 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"}];
2190
+ 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"}];
2191
2191
 
2192
2192
  /**
2193
2193
  * Checks if value is valid email
@@ -2307,7 +2307,7 @@
2307
2307
  });
2308
2308
  }
2309
2309
  catch (error) {
2310
- // TODO: [🟥] Detect browser / node and make it colorfull
2310
+ // TODO: [🟥] Detect browser / node and make it colorful
2311
2311
  console.error('There was an error with prettifying the markdown, using the original as the fallback', {
2312
2312
  error,
2313
2313
  html: content,
@@ -2572,7 +2572,7 @@
2572
2572
 
2573
2573
  Note: You have probably forgotten to run "ptbk make" to update the collection
2574
2574
  Note: Pipelines with the same URL are not allowed
2575
- Only exepction is when the pipelines are identical
2575
+ Only exception is when the pipelines are identical
2576
2576
 
2577
2577
  `));
2578
2578
  }
@@ -2725,12 +2725,12 @@
2725
2725
  get title() {
2726
2726
  return `${llmTools.title} (+usage)`;
2727
2727
  // <- TODO: [🧈] Maybe standartize the suffix when wrapping `LlmExecutionTools` up
2728
- // <- TODO: [🧈][🧠] Does it make sence to suffix "(+usage)"?
2728
+ // <- TODO: [🧈][🧠] Does it make sense to suffix "(+usage)"?
2729
2729
  },
2730
2730
  get description() {
2731
2731
  return `${llmTools.description} (+usage)`;
2732
2732
  // <- TODO: [🧈] Maybe standartize the suffix when wrapping `LlmExecutionTools` up
2733
- // <- TODO: [🧈][🧠] Does it make sence to suffix "(+usage)"?
2733
+ // <- TODO: [🧈][🧠] Does it make sense to suffix "(+usage)"?
2734
2734
  },
2735
2735
  checkConfiguration() {
2736
2736
  return /* not await */ llmTools.checkConfiguration();
@@ -2957,13 +2957,13 @@
2957
2957
 
2958
2958
  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.
2959
2959
  `);
2960
- // TODO: [🟥] Detect browser / node and make it colorfull
2960
+ // TODO: [🟥] Detect browser / node and make it colorful
2961
2961
  console.warn(warningMessage);
2962
2962
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
2963
2963
  /*
2964
2964
  return {
2965
2965
  async listModels() {
2966
- // TODO: [🟥] Detect browser / node and make it colorfull
2966
+ // TODO: [🟥] Detect browser / node and make it colorful
2967
2967
  console.warn(
2968
2968
  spaceTrim(
2969
2969
  (block) => `
@@ -3239,17 +3239,17 @@
3239
3239
  * Mixes registered scrapers from $scrapersMetadataRegister and $scrapersRegister
3240
3240
  */
3241
3241
  const all = [];
3242
- for (const { packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser, } of $scrapersMetadataRegister.list()) {
3242
+ for (const { packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser, } of $scrapersMetadataRegister.list()) {
3243
3243
  if (all.some((item) => item.packageName === packageName && item.className === className)) {
3244
3244
  continue;
3245
3245
  }
3246
- all.push({ packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser });
3246
+ all.push({ packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser });
3247
3247
  }
3248
- for (const { packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser, } of $scrapersRegister.list()) {
3248
+ for (const { packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser, } of $scrapersRegister.list()) {
3249
3249
  if (all.some((item) => item.packageName === packageName && item.className === className)) {
3250
3250
  continue;
3251
3251
  }
3252
- all.push({ packageName, className, mimeTypes, documentationUrl, isAvilableInBrowser });
3252
+ all.push({ packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser });
3253
3253
  }
3254
3254
  for (const { metadata } of availableScrapers) {
3255
3255
  all.push(metadata);
@@ -3261,8 +3261,8 @@
3261
3261
  const isInstalled = $scrapersRegister
3262
3262
  .list()
3263
3263
  .find(({ packageName, className }) => metadata.packageName === packageName && metadata.className === className);
3264
- const isAvilableInTools = availableScrapers.some(({ metadata: { packageName, className } }) => metadata.packageName === packageName && metadata.className === className);
3265
- return { ...metadata, isMetadataAviailable, isInstalled, isAvilableInTools };
3264
+ const isAvailableInTools = availableScrapers.some(({ metadata: { packageName, className } }) => metadata.packageName === packageName && metadata.className === className);
3265
+ return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
3266
3266
  });
3267
3267
  if (metadata.length === 0) {
3268
3268
  return spaceTrim__default["default"](`
@@ -3275,7 +3275,7 @@
3275
3275
  return spaceTrim__default["default"]((block) => `
3276
3276
  Available scrapers are:
3277
3277
  ${block(metadata
3278
- .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvilableInBrowser, isAvilableInTools, }, i) => {
3278
+ .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
3279
3279
  const more = [];
3280
3280
  // TODO: [🧠] Maybe use `documentationUrl`
3281
3281
  if (isMetadataAviailable) {
@@ -3284,16 +3284,16 @@
3284
3284
  if (isInstalled) {
3285
3285
  more.push(`🟩 Installed`);
3286
3286
  } // not else
3287
- if (isAvilableInTools) {
3287
+ if (isAvailableInTools) {
3288
3288
  more.push(`🟦 Available in tools`);
3289
3289
  } // not else
3290
3290
  if (!isMetadataAviailable && isInstalled) {
3291
3291
  more.push(`When no metadata registered but scraper is installed, it is an unexpected behavior`);
3292
3292
  } // not else
3293
- if (!isInstalled && isAvilableInTools) {
3293
+ if (!isInstalled && isAvailableInTools) {
3294
3294
  more.push(`When the scraper is not installed but available in tools, it is an unexpected compatibility behavior`);
3295
3295
  } // not else
3296
- if (!isAvilableInBrowser) {
3296
+ if (!isAvailableInBrowser) {
3297
3297
  more.push(`Not usable in browser`);
3298
3298
  }
3299
3299
  const moreText = more.length === 0 ? '' : ` *(${more.join('; ')})*`;
@@ -4020,7 +4020,7 @@
4020
4020
  /**
4021
4021
  * TODO: [🧊] In future one preparation can take data from previous preparation and save tokens and time
4022
4022
  * Put `knowledgePieces` into `PrepareKnowledgeOptions`
4023
- * TODO: [🪂] More than max things can run in parallel by acident [1,[2a,2b,_],[3a,3b,_]]
4023
+ * TODO: [🪂] More than max things can run in parallel by accident [1,[2a,2b,_],[3a,3b,_]]
4024
4024
  * TODO: [🧠][❎] Do here proper M:N mapping
4025
4025
  * [x] One source can make multiple pieces
4026
4026
  * [ ] One piece can have multiple sources
@@ -4828,6 +4828,94 @@
4828
4828
  return mappedParameters;
4829
4829
  }
4830
4830
 
4831
+ /**
4832
+ * Just says that the variable is not used but should be kept
4833
+ * No side effects.
4834
+ *
4835
+ * Note: It can be useful for:
4836
+ *
4837
+ * 1) Suppressing eager optimization of unused imports
4838
+ * 2) Suppressing eslint errors of unused variables in the tests
4839
+ * 3) Keeping the type of the variable for type testing
4840
+ *
4841
+ * @param value any values
4842
+ * @returns void
4843
+ * @private within the repository
4844
+ */
4845
+ function keepUnused(...valuesToKeep) {
4846
+ }
4847
+
4848
+ /**
4849
+ * Replaces parameters in template with values from parameters object
4850
+ *
4851
+ * Note: This function is not places strings into string,
4852
+ * It's more complex and can handle this operation specifically for LLM models
4853
+ *
4854
+ * @param template the template with parameters in {curly} braces
4855
+ * @param parameters the object with parameters
4856
+ * @returns the template with replaced parameters
4857
+ * @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
4858
+ * @public exported from `@promptbook/utils`
4859
+ */
4860
+ function templateParameters(template, parameters) {
4861
+ for (const [parameterName, parameterValue] of Object.entries(parameters)) {
4862
+ if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
4863
+ throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
4864
+ }
4865
+ else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
4866
+ // TODO: [🍵]
4867
+ throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
4868
+ }
4869
+ }
4870
+ let replacedTemplates = template;
4871
+ let match;
4872
+ let loopLimit = LOOP_LIMIT;
4873
+ while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
4874
+ .exec(replacedTemplates))) {
4875
+ if (loopLimit-- < 0) {
4876
+ throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
4877
+ }
4878
+ const precol = match.groups.precol;
4879
+ const parameterName = match.groups.parameterName;
4880
+ if (parameterName === '') {
4881
+ // Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
4882
+ continue;
4883
+ }
4884
+ if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
4885
+ throw new PipelineExecutionError('Parameter is already opened or not closed');
4886
+ }
4887
+ if (parameters[parameterName] === undefined) {
4888
+ throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4889
+ }
4890
+ let parameterValue = parameters[parameterName];
4891
+ if (parameterValue === undefined) {
4892
+ throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4893
+ }
4894
+ parameterValue = valueToString(parameterValue);
4895
+ // Escape curly braces in parameter values to prevent prompt-injection
4896
+ parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4897
+ if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
4898
+ parameterValue = parameterValue
4899
+ .split('\n')
4900
+ .map((line, index) => (index === 0 ? line : `${precol}${line}`))
4901
+ .join('\n');
4902
+ }
4903
+ replacedTemplates =
4904
+ replacedTemplates.substring(0, match.index + precol.length) +
4905
+ parameterValue +
4906
+ replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
4907
+ }
4908
+ // [💫] Check if there are parameters that are not closed properly
4909
+ if (/{\w+$/.test(replacedTemplates)) {
4910
+ throw new PipelineExecutionError('Parameter is not closed');
4911
+ }
4912
+ // [💫] Check if there are parameters that are not opened properly
4913
+ if (/^\w+}/.test(replacedTemplates)) {
4914
+ throw new PipelineExecutionError('Parameter is not opened');
4915
+ }
4916
+ return replacedTemplates;
4917
+ }
4918
+
4831
4919
  /**
4832
4920
  * Extracts all code blocks from markdown.
4833
4921
  *
@@ -4930,94 +5018,6 @@
4930
5018
  * TODO: [🏢] Make this logic part of `JsonFormatParser` or `isValidJsonString`
4931
5019
  */
4932
5020
 
4933
- /**
4934
- * Just says that the variable is not used but should be kept
4935
- * No side effects.
4936
- *
4937
- * Note: It can be useful for:
4938
- *
4939
- * 1) Suppressing eager optimization of unused imports
4940
- * 2) Suppressing eslint errors of unused variables in the tests
4941
- * 3) Keeping the type of the variable for type testing
4942
- *
4943
- * @param value any values
4944
- * @returns void
4945
- * @private within the repository
4946
- */
4947
- function keepUnused(...valuesToKeep) {
4948
- }
4949
-
4950
- /**
4951
- * Replaces parameters in template with values from parameters object
4952
- *
4953
- * Note: This function is not places strings into string,
4954
- * It's more complex and can handle this operation specifically for LLM models
4955
- *
4956
- * @param template the template with parameters in {curly} braces
4957
- * @param parameters the object with parameters
4958
- * @returns the template with replaced parameters
4959
- * @throws {PipelineExecutionError} if parameter is not defined, not closed, or not opened
4960
- * @public exported from `@promptbook/utils`
4961
- */
4962
- function templateParameters(template, parameters) {
4963
- for (const [parameterName, parameterValue] of Object.entries(parameters)) {
4964
- if (parameterValue === RESERVED_PARAMETER_MISSING_VALUE) {
4965
- throw new UnexpectedError(`Parameter \`{${parameterName}}\` has missing value`);
4966
- }
4967
- else if (parameterValue === RESERVED_PARAMETER_RESTRICTED) {
4968
- // TODO: [🍵]
4969
- throw new UnexpectedError(`Parameter \`{${parameterName}}\` is restricted to use`);
4970
- }
4971
- }
4972
- let replacedTemplates = template;
4973
- let match;
4974
- let loopLimit = LOOP_LIMIT;
4975
- while ((match = /^(?<precol>.*){(?<parameterName>\w+)}(.*)/m /* <- Not global */
4976
- .exec(replacedTemplates))) {
4977
- if (loopLimit-- < 0) {
4978
- throw new LimitReachedError('Loop limit reached during parameters replacement in `templateParameters`');
4979
- }
4980
- const precol = match.groups.precol;
4981
- const parameterName = match.groups.parameterName;
4982
- if (parameterName === '') {
4983
- // Note: Skip empty placeholders. It's used to avoid confusion with JSON-like strings
4984
- continue;
4985
- }
4986
- if (parameterName.indexOf('{') !== -1 || parameterName.indexOf('}') !== -1) {
4987
- throw new PipelineExecutionError('Parameter is already opened or not closed');
4988
- }
4989
- if (parameters[parameterName] === undefined) {
4990
- throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4991
- }
4992
- let parameterValue = parameters[parameterName];
4993
- if (parameterValue === undefined) {
4994
- throw new PipelineExecutionError(`Parameter \`{${parameterName}}\` is not defined`);
4995
- }
4996
- parameterValue = valueToString(parameterValue);
4997
- // Escape curly braces in parameter values to prevent prompt-injection
4998
- parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
4999
- if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
5000
- parameterValue = parameterValue
5001
- .split('\n')
5002
- .map((line, index) => (index === 0 ? line : `${precol}${line}`))
5003
- .join('\n');
5004
- }
5005
- replacedTemplates =
5006
- replacedTemplates.substring(0, match.index + precol.length) +
5007
- parameterValue +
5008
- replacedTemplates.substring(match.index + precol.length + parameterName.length + 2);
5009
- }
5010
- // [💫] Check if there are parameters that are not closed properly
5011
- if (/{\w+$/.test(replacedTemplates)) {
5012
- throw new PipelineExecutionError('Parameter is not closed');
5013
- }
5014
- // [💫] Check if there are parameters that are not opened properly
5015
- if (/^\w+}/.test(replacedTemplates)) {
5016
- throw new PipelineExecutionError('Parameter is not opened');
5017
- }
5018
- return replacedTemplates;
5019
- }
5020
-
5021
5021
  /**
5022
5022
  * Counts number of characters in the text
5023
5023
  *
@@ -5178,6 +5178,68 @@
5178
5178
  * Note: [💝] and [🤠] are interconnected together
5179
5179
  */
5180
5180
 
5181
+ /**
5182
+ * Validates a prompt result against expectations and format requirements.
5183
+ * This function provides a common abstraction for result validation that can be used
5184
+ * by both execution logic and caching logic to ensure consistency.
5185
+ *
5186
+ * @param options - The validation options including result string, expectations, and format
5187
+ * @returns Validation result with processed string and validity status
5188
+ * @private internal function of `createPipelineExecutor` and `cacheLlmTools`
5189
+ */
5190
+ function validatePromptResult(options) {
5191
+ const { resultString, expectations, format } = options;
5192
+ let processedResultString = resultString;
5193
+ let validationError;
5194
+ try {
5195
+ // TODO: [💝] Unite object for expecting amount and format
5196
+ if (format) {
5197
+ if (format === 'JSON') {
5198
+ if (!isValidJsonString(processedResultString)) {
5199
+ // TODO: [🏢] Do more universally via `FormatParser`
5200
+ try {
5201
+ processedResultString = extractJsonBlock(processedResultString);
5202
+ }
5203
+ catch (error) {
5204
+ keepUnused(error);
5205
+ throw new ExpectError(spaceTrim.spaceTrim((block) => `
5206
+ Expected valid JSON string
5207
+
5208
+ The expected JSON text:
5209
+ ${block(processedResultString)}
5210
+ `));
5211
+ }
5212
+ }
5213
+ }
5214
+ else {
5215
+ throw new UnexpectedError(`Unknown format "${format}"`);
5216
+ }
5217
+ }
5218
+ // TODO: [💝] Unite object for expecting amount and format
5219
+ if (expectations) {
5220
+ checkExpectations(expectations, processedResultString);
5221
+ }
5222
+ return {
5223
+ isValid: true,
5224
+ processedResultString,
5225
+ };
5226
+ }
5227
+ catch (error) {
5228
+ if (error instanceof ExpectError) {
5229
+ validationError = error;
5230
+ }
5231
+ else {
5232
+ // Re-throw non-ExpectError errors (like UnexpectedError)
5233
+ throw error;
5234
+ }
5235
+ return {
5236
+ isValid: false,
5237
+ processedResultString,
5238
+ error: validationError,
5239
+ };
5240
+ }
5241
+ }
5242
+
5181
5243
  /**
5182
5244
  * Executes a pipeline task with multiple attempts, including joker and retry logic. Handles different task types
5183
5245
  * (prompt, script, dialog, etc.), applies postprocessing, checks expectations, and updates the execution report.
@@ -5195,17 +5257,18 @@
5195
5257
  $resultString: null,
5196
5258
  $expectError: null,
5197
5259
  $scriptPipelineExecutionErrors: [],
5260
+ $failedResults: [], // Track all failed attempts
5198
5261
  };
5199
5262
  // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
5200
5263
  const _llms = arrayableToArray(tools.llm);
5201
5264
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
5202
- attempts: for (let attempt = -jokerParameterNames.length; attempt < maxAttempts; attempt++) {
5203
- const isJokerAttempt = attempt < 0;
5204
- const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
5265
+ attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
5266
+ const isJokerAttempt = attemptIndex < 0;
5267
+ const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
5205
5268
  // TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
5206
5269
  if (isJokerAttempt && !jokerParameterName) {
5207
5270
  throw new UnexpectedError(spaceTrim.spaceTrim((block) => `
5208
- Joker not found in attempt ${attempt}
5271
+ Joker not found in attempt ${attemptIndex}
5209
5272
 
5210
5273
  ${block(pipelineIdentification)}
5211
5274
  `));
@@ -5403,35 +5466,18 @@
5403
5466
  }
5404
5467
  }
5405
5468
  // TODO: [💝] Unite object for expecting amount and format
5406
- if (task.format) {
5407
- if (task.format === 'JSON') {
5408
- if (!isValidJsonString($ongoingTaskResult.$resultString || '')) {
5409
- // TODO: [🏢] Do more universally via `FormatParser`
5410
- try {
5411
- $ongoingTaskResult.$resultString = extractJsonBlock($ongoingTaskResult.$resultString || '');
5412
- }
5413
- catch (error) {
5414
- keepUnused(error);
5415
- throw new ExpectError(spaceTrim.spaceTrim((block) => `
5416
- Expected valid JSON string
5417
-
5418
- ${block(
5419
- /*<- Note: No need for `pipelineIdentification`, it will be catched and added later */ '')}
5420
- `));
5421
- }
5422
- }
5423
- }
5424
- else {
5425
- throw new UnexpectedError(spaceTrim.spaceTrim((block) => `
5426
- Unknown format "${task.format}"
5427
-
5428
- ${block(pipelineIdentification)}
5429
- `));
5469
+ // Use the common validation function for both format and expectations
5470
+ if (task.format || task.expectations) {
5471
+ const validationResult = validatePromptResult({
5472
+ resultString: $ongoingTaskResult.$resultString || '',
5473
+ expectations: task.expectations,
5474
+ format: task.format,
5475
+ });
5476
+ if (!validationResult.isValid) {
5477
+ throw validationResult.error;
5430
5478
  }
5431
- }
5432
- // TODO: [💝] Unite object for expecting amount and format
5433
- if (task.expectations) {
5434
- checkExpectations(task.expectations, $ongoingTaskResult.$resultString || '');
5479
+ // Update the result string in case format processing modified it (e.g., JSON extraction)
5480
+ $ongoingTaskResult.$resultString = validationResult.processedResultString;
5435
5481
  }
5436
5482
  break attempts;
5437
5483
  }
@@ -5440,6 +5486,15 @@
5440
5486
  throw error;
5441
5487
  }
5442
5488
  $ongoingTaskResult.$expectError = error;
5489
+ // Store each failed attempt
5490
+ if (!Array.isArray($ongoingTaskResult.$failedResults)) {
5491
+ $ongoingTaskResult.$failedResults = [];
5492
+ }
5493
+ $ongoingTaskResult.$failedResults.push({
5494
+ attemptIndex,
5495
+ result: $ongoingTaskResult.$resultString,
5496
+ error: error,
5497
+ });
5443
5498
  }
5444
5499
  finally {
5445
5500
  if (!isJokerAttempt &&
@@ -5461,35 +5516,41 @@
5461
5516
  });
5462
5517
  }
5463
5518
  }
5464
- if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
5519
+ if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
5520
+ // Note: Create a summary of all failures
5521
+ const failuresSummary = $ongoingTaskResult.$failedResults
5522
+ .map((failure) => spaceTrim.spaceTrim((block) => {
5523
+ var _a, _b;
5524
+ return `
5525
+ Attempt ${failure.attemptIndex + 1}:
5526
+ Error ${((_a = failure.error) === null || _a === void 0 ? void 0 : _a.name) || ''}:
5527
+ ${block((_b = failure.error) === null || _b === void 0 ? void 0 : _b.message.split('\n').map((line) => `> ${line}`).join('\n'))}
5528
+
5529
+ Result:
5530
+ ${block(failure.result === null
5531
+ ? 'null'
5532
+ : spaceTrim.spaceTrim(failure.result)
5533
+ .split('\n')
5534
+ .map((line) => `> ${line}`)
5535
+ .join('\n'))}
5536
+ `;
5537
+ }))
5538
+ .join('\n\n---\n\n');
5465
5539
  throw new PipelineExecutionError(spaceTrim.spaceTrim((block) => {
5466
- var _a, _b, _c;
5540
+ var _a;
5467
5541
  return `
5468
5542
  LLM execution failed ${maxExecutionAttempts}x
5469
5543
 
5470
5544
  ${block(pipelineIdentification)}
5471
5545
 
5472
- ---
5473
5546
  The Prompt:
5474
5547
  ${block((((_a = $ongoingTaskResult.$prompt) === null || _a === void 0 ? void 0 : _a.content) || '')
5475
5548
  .split('\n')
5476
5549
  .map((line) => `> ${line}`)
5477
5550
  .join('\n'))}
5478
5551
 
5479
- Last error ${((_b = $ongoingTaskResult.$expectError) === null || _b === void 0 ? void 0 : _b.name) || ''}:
5480
- ${block((((_c = $ongoingTaskResult.$expectError) === null || _c === void 0 ? void 0 : _c.message) || '')
5481
- .split('\n')
5482
- .map((line) => `> ${line}`)
5483
- .join('\n'))}
5484
-
5485
- Last result:
5486
- ${block($ongoingTaskResult.$resultString === null
5487
- ? 'null'
5488
- : spaceTrim.spaceTrim($ongoingTaskResult.$resultString)
5489
- .split('\n')
5490
- .map((line) => `> ${line}`)
5491
- .join('\n'))}
5492
- ---
5552
+ All Failed Attempts:
5553
+ ${block(failuresSummary)}
5493
5554
  `;
5494
5555
  }));
5495
5556
  }
@@ -5709,10 +5770,10 @@
5709
5770
  */
5710
5771
  async function getKnowledgeForTask(options) {
5711
5772
  const { tools, preparedPipeline, task, parameters } = options;
5712
- const firstKnowlegePiece = preparedPipeline.knowledgePieces[0];
5713
- const firstKnowlegeIndex = firstKnowlegePiece === null || firstKnowlegePiece === void 0 ? void 0 : firstKnowlegePiece.index[0];
5773
+ const firstKnowledgePiece = preparedPipeline.knowledgePieces[0];
5774
+ const firstKnowledgeIndex = firstKnowledgePiece === null || firstKnowledgePiece === void 0 ? void 0 : firstKnowledgePiece.index[0];
5714
5775
  // <- TODO: Do not use just first knowledge piece and first index to determine embedding model, use also keyword search
5715
- if (firstKnowlegePiece === undefined || firstKnowlegeIndex === undefined) {
5776
+ if (firstKnowledgePiece === undefined || firstKnowledgeIndex === undefined) {
5716
5777
  return ''; // <- Note: Np knowledge present, return empty string
5717
5778
  }
5718
5779
  try {
@@ -5723,7 +5784,7 @@
5723
5784
  title: 'Knowledge Search',
5724
5785
  modelRequirements: {
5725
5786
  modelVariant: 'EMBEDDING',
5726
- modelName: firstKnowlegeIndex.modelName,
5787
+ modelName: firstKnowledgeIndex.modelName,
5727
5788
  },
5728
5789
  content: task.content,
5729
5790
  parameters,
@@ -5731,7 +5792,7 @@
5731
5792
  const taskEmbeddingResult = await llmTools.callEmbeddingModel(taskEmbeddingPrompt);
5732
5793
  const knowledgePiecesWithRelevance = preparedPipeline.knowledgePieces.map((knowledgePiece) => {
5733
5794
  const { index } = knowledgePiece;
5734
- const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowlegeIndex.modelName);
5795
+ const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowledgeIndex.modelName);
5735
5796
  // <- TODO: Do not use just first knowledge piece and first index to determine embedding model
5736
5797
  if (knowledgePieceIndex === undefined) {
5737
5798
  return {
@@ -5752,8 +5813,8 @@
5752
5813
  task,
5753
5814
  taskEmbeddingPrompt,
5754
5815
  taskEmbeddingResult,
5755
- firstKnowlegePiece,
5756
- firstKnowlegeIndex,
5816
+ firstKnowledgePiece,
5817
+ firstKnowledgeIndex,
5757
5818
  knowledgePiecesWithRelevance,
5758
5819
  knowledgePiecesSorted,
5759
5820
  knowledgePiecesLimited,
@@ -5822,7 +5883,7 @@
5822
5883
  * @private internal utility of `createPipelineExecutor`
5823
5884
  */
5824
5885
  async function executeTask(options) {
5825
- const { currentTask, preparedPipeline, parametersToPass, tools, onProgress, $executionReport, pipelineIdentification, maxExecutionAttempts, maxParallelCount, csvSettings, isVerbose, rootDirname, cacheDirname, intermediateFilesStrategy, isAutoInstalled, isNotPreparedWarningSupressed, } = options;
5886
+ const { currentTask, preparedPipeline, parametersToPass, tools, onProgress, $executionReport, pipelineIdentification, maxExecutionAttempts, maxParallelCount, csvSettings, isVerbose, rootDirname, cacheDirname, intermediateFilesStrategy, isAutoInstalled, isNotPreparedWarningSuppressed, } = options;
5826
5887
  const priority = preparedPipeline.tasks.length - preparedPipeline.tasks.indexOf(currentTask);
5827
5888
  // Note: Check consistency of used and dependent parameters which was also done in `validatePipeline`, but it’s good to doublecheck
5828
5889
  const usedParameterNames = extractParameterNamesFromTask(currentTask);
@@ -5910,7 +5971,7 @@
5910
5971
  cacheDirname,
5911
5972
  intermediateFilesStrategy,
5912
5973
  isAutoInstalled,
5913
- isNotPreparedWarningSupressed,
5974
+ isNotPreparedWarningSuppressed,
5914
5975
  });
5915
5976
  await onProgress({
5916
5977
  outputParameters: {
@@ -6005,7 +6066,7 @@
6005
6066
  }
6006
6067
  return exportJson({
6007
6068
  name: `executionReport`,
6008
- message: `Unuccessful PipelineExecutorResult (with missing parameter {${parameter.name}}) PipelineExecutorResult`,
6069
+ message: `Unsuccessful PipelineExecutorResult (with missing parameter {${parameter.name}}) PipelineExecutorResult`,
6009
6070
  order: [],
6010
6071
  value: {
6011
6072
  isSuccessful: false,
@@ -6042,7 +6103,7 @@
6042
6103
  return exportJson({
6043
6104
  name: 'pipelineExecutorResult',
6044
6105
  message: spaceTrim.spaceTrim((block) => `
6045
- Unuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
6106
+ Unsuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
6046
6107
 
6047
6108
  ${block(pipelineIdentification)}
6048
6109
  `),
@@ -6183,7 +6244,7 @@
6183
6244
  }
6184
6245
  return exportJson({
6185
6246
  name: 'pipelineExecutorResult',
6186
- message: `Unuccessful PipelineExecutorResult (with misc errors) PipelineExecutorResult`,
6247
+ message: `Unsuccessful PipelineExecutorResult (with misc errors) PipelineExecutorResult`,
6187
6248
  order: [],
6188
6249
  value: {
6189
6250
  isSuccessful: false,
@@ -6234,7 +6295,7 @@
6234
6295
  * @public exported from `@promptbook/core`
6235
6296
  */
6236
6297
  function createPipelineExecutor(options) {
6237
- 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;
6298
+ 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;
6238
6299
  validatePipeline(pipeline);
6239
6300
  const pipelineIdentification = (() => {
6240
6301
  // Note: This is a 😐 implementation of [🚞]
@@ -6251,7 +6312,7 @@
6251
6312
  if (isPipelinePrepared(pipeline)) {
6252
6313
  preparedPipeline = pipeline;
6253
6314
  }
6254
- else if (isNotPreparedWarningSupressed !== true) {
6315
+ else if (isNotPreparedWarningSuppressed !== true) {
6255
6316
  console.warn(spaceTrim.spaceTrim((block) => `
6256
6317
  Pipeline is not prepared
6257
6318
 
@@ -6284,7 +6345,7 @@
6284
6345
  maxParallelCount,
6285
6346
  csvSettings,
6286
6347
  isVerbose,
6287
- isNotPreparedWarningSupressed,
6348
+ isNotPreparedWarningSuppressed,
6288
6349
  rootDirname,
6289
6350
  cacheDirname,
6290
6351
  intermediateFilesStrategy,
@@ -6293,7 +6354,7 @@
6293
6354
  assertsError(error);
6294
6355
  return exportJson({
6295
6356
  name: 'pipelineExecutorResult',
6296
- message: `Unuccessful PipelineExecutorResult, last catch`,
6357
+ message: `Unsuccessful PipelineExecutorResult, last catch`,
6297
6358
  order: [],
6298
6359
  value: {
6299
6360
  isSuccessful: false,
@@ -6320,6 +6381,46 @@
6320
6381
  return pipelineExecutor;
6321
6382
  }
6322
6383
 
6384
+ /**
6385
+ * Detects if the code is running in a browser environment in main thread (Not in a web worker)
6386
+ *
6387
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6388
+ *
6389
+ * @public exported from `@promptbook/utils`
6390
+ */
6391
+ const $isRunningInBrowser = new Function(`
6392
+ try {
6393
+ return this === window;
6394
+ } catch (e) {
6395
+ return false;
6396
+ }
6397
+ `);
6398
+ /**
6399
+ * TODO: [🎺]
6400
+ */
6401
+
6402
+ /**
6403
+ * Detects if the code is running in a web worker
6404
+ *
6405
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6406
+ *
6407
+ * @public exported from `@promptbook/utils`
6408
+ */
6409
+ const $isRunningInWebWorker = new Function(`
6410
+ try {
6411
+ if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
6412
+ return true;
6413
+ } else {
6414
+ return false;
6415
+ }
6416
+ } catch (e) {
6417
+ return false;
6418
+ }
6419
+ `);
6420
+ /**
6421
+ * TODO: [🎺]
6422
+ */
6423
+
6323
6424
  /**
6324
6425
  * Register for LLM tools.
6325
6426
  *
@@ -6488,8 +6589,10 @@
6488
6589
  .list()
6489
6590
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
6490
6591
  if (registeredItem === undefined) {
6592
+ console.log('!!! $llmToolsRegister.list()', $llmToolsRegister.list());
6491
6593
  throw new Error(spaceTrim__default["default"]((block) => `
6492
6594
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
6595
+ Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
6493
6596
 
6494
6597
  You have probably forgotten install and import the provider package.
6495
6598
  To fix this issue, you can:
@@ -6607,24 +6710,6 @@
6607
6710
  * TODO: [🌺] Use some intermediate util splitWords
6608
6711
  */
6609
6712
 
6610
- /**
6611
- * Detects if the code is running in a browser environment in main thread (Not in a web worker)
6612
- *
6613
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6614
- *
6615
- * @public exported from `@promptbook/utils`
6616
- */
6617
- new Function(`
6618
- try {
6619
- return this === window;
6620
- } catch (e) {
6621
- return false;
6622
- }
6623
- `);
6624
- /**
6625
- * TODO: [🎺]
6626
- */
6627
-
6628
6713
  /**
6629
6714
  * Detects if the code is running in jest environment
6630
6715
  *
@@ -6643,28 +6728,6 @@
6643
6728
  * TODO: [🎺]
6644
6729
  */
6645
6730
 
6646
- /**
6647
- * Detects if the code is running in a web worker
6648
- *
6649
- * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6650
- *
6651
- * @public exported from `@promptbook/utils`
6652
- */
6653
- new Function(`
6654
- try {
6655
- if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
6656
- return true;
6657
- } else {
6658
- return false;
6659
- }
6660
- } catch (e) {
6661
- return false;
6662
- }
6663
- `);
6664
- /**
6665
- * TODO: [🎺]
6666
- */
6667
-
6668
6731
  /**
6669
6732
  * Makes first letter of a string uppercase
6670
6733
  *
@@ -7836,6 +7899,66 @@
7836
7899
  response.setHeader('X-Powered-By', 'Promptbook engine');
7837
7900
  next();
7838
7901
  });
7902
+ // Note: OpenAI-compatible chat completions endpoint
7903
+ app.post('/v1/chat/completions', async (request, response) => {
7904
+ // TODO: !!!! Make more promptbook-native:
7905
+ try {
7906
+ const params = request.body;
7907
+ const { model, messages } = params;
7908
+ // Convert messages to a single prompt
7909
+ const prompt = messages
7910
+ .map((message) => `${message.role}: ${message.content}`)
7911
+ .join('\n');
7912
+ // Get pipeline for the book
7913
+ if (!collection) {
7914
+ throw new Error('No collection available');
7915
+ }
7916
+ const pipeline = await collection.getPipelineByUrl(model);
7917
+ const pipelineExecutor = createPipelineExecutor({
7918
+ pipeline,
7919
+ tools: await getExecutionToolsFromIdentification({
7920
+ isAnonymous: true,
7921
+ llmToolsConfiguration: [],
7922
+ }),
7923
+ });
7924
+ // Execute the pipeline with the prompt content as input
7925
+ const result = await pipelineExecutor({ prompt }).asPromise({ isCrashedOnError: true });
7926
+ if (!result.isSuccessful) {
7927
+ throw new Error(`Failed to execute book: ${result.errors.join(', ')}`);
7928
+ }
7929
+ // Return the result in OpenAI-compatible format
7930
+ response.json({
7931
+ id: 'chatcmpl-' + Math.random().toString(36).substring(2),
7932
+ object: 'chat.completion',
7933
+ created: Math.floor(Date.now() / 1000),
7934
+ model,
7935
+ choices: [
7936
+ {
7937
+ index: 0,
7938
+ message: {
7939
+ role: 'assistant',
7940
+ content: result.outputParameters.response,
7941
+ },
7942
+ finish_reason: 'stop',
7943
+ },
7944
+ ],
7945
+ usage: {
7946
+ prompt_tokens: 0,
7947
+ completion_tokens: 0,
7948
+ total_tokens: 0,
7949
+ },
7950
+ });
7951
+ }
7952
+ catch (error) {
7953
+ response.status(500).json({
7954
+ error: {
7955
+ message: error instanceof Error ? error.message : 'Unknown error',
7956
+ type: 'server_error',
7957
+ code: 'internal_error',
7958
+ },
7959
+ });
7960
+ }
7961
+ });
7839
7962
  // TODO: [🥺] Expose openapiJson to consumer and also allow to add new routes
7840
7963
  app.use(OpenApiValidator__namespace.middleware({
7841
7964
  apiSpec: openapiJson,
@@ -8196,7 +8319,6 @@
8196
8319
  catch (error) {
8197
8320
  assertsError(error);
8198
8321
  socket.emit('error', serializeError(error));
8199
- // <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
8200
8322
  }
8201
8323
  finally {
8202
8324
  socket.disconnect();