@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.
- package/README.md +6 -2
- package/esm/index.es.js +338 -216
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/anthropic-claude.index.d.ts +2 -2
- package/esm/typings/src/_packages/cli.index.d.ts +4 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/openai.index.d.ts +10 -0
- package/esm/typings/src/_packages/types.index.d.ts +14 -4
- package/esm/typings/src/_packages/{wizzard.index.d.ts → wizard.index.d.ts} +6 -2
- package/esm/typings/src/cli/cli-commands/prettify.d.ts +1 -1
- package/esm/typings/src/cli/cli-commands/test-command.d.ts +1 -1
- package/esm/typings/src/config.d.ts +1 -1
- package/esm/typings/src/conversion/archive/loadArchive.d.ts +1 -1
- package/esm/typings/src/conversion/archive/saveArchive.d.ts +2 -2
- package/esm/typings/src/conversion/prettify/renderPipelineMermaidOptions.d.ts +1 -1
- package/esm/typings/src/dialogs/callback/CallbackInterfaceTools.d.ts +1 -1
- package/esm/typings/src/execution/AbstractTaskResult.d.ts +2 -2
- package/esm/typings/src/execution/createPipelineExecutor/$OngoingTaskResult.d.ts +8 -0
- package/esm/typings/src/execution/createPipelineExecutor/00-CreatePipelineExecutorOptions.d.ts +1 -1
- package/esm/typings/src/execution/execution-report/ExecutionPromptReportJson.d.ts +2 -2
- package/esm/typings/src/execution/translation/automatic-translate/translateMessages.d.ts +1 -1
- package/esm/typings/src/execution/utils/validatePromptResult.d.ts +53 -0
- package/esm/typings/src/llm-providers/_common/register/{$provideLlmToolsForWizzardOrCli.d.ts → $provideLlmToolsForWizardOrCli.d.ts} +2 -2
- package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +3 -3
- package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +2 -2
- package/esm/typings/src/llm-providers/anthropic-claude/register-configuration.d.ts +1 -1
- package/esm/typings/src/llm-providers/anthropic-claude/register-constructor.d.ts +1 -1
- package/esm/typings/src/llm-providers/azure-openai/register-configuration.d.ts +1 -1
- package/esm/typings/src/llm-providers/azure-openai/register-constructor.d.ts +1 -1
- package/esm/typings/src/llm-providers/deepseek/register-configuration.d.ts +1 -1
- package/esm/typings/src/llm-providers/deepseek/register-constructor.d.ts +1 -1
- package/esm/typings/src/llm-providers/google/register-configuration.d.ts +1 -1
- package/esm/typings/src/llm-providers/google/register-constructor.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/register-configuration.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/register-constructor.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionToolsOptions.d.ts +2 -2
- package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +4 -4
- package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionToolsOptions.d.ts +52 -0
- package/esm/typings/src/llm-providers/openai/OpenAiExecutionToolsOptions.d.ts +3 -5
- package/esm/typings/src/llm-providers/openai/createOpenAiCompatibleExecutionTools.d.ts +74 -0
- package/esm/typings/src/llm-providers/openai/register-configuration.d.ts +13 -2
- package/esm/typings/src/llm-providers/openai/register-constructor.d.ts +16 -2
- package/esm/typings/src/remote-server/socket-types/listModels/PromptbookServer_ListModels_Request.d.ts +1 -1
- package/esm/typings/src/scrapers/_boilerplate/createBoilerplateScraper.d.ts +1 -1
- package/esm/typings/src/scrapers/_boilerplate/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/_boilerplate/register-metadata.d.ts +2 -2
- package/esm/typings/src/scrapers/_common/prepareKnowledgePieces.d.ts +1 -1
- package/esm/typings/src/scrapers/_common/register/ScraperAndConverterMetadata.d.ts +1 -1
- package/esm/typings/src/scrapers/document/createDocumentScraper.d.ts +1 -1
- package/esm/typings/src/scrapers/document/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/document/register-metadata.d.ts +2 -2
- package/esm/typings/src/scrapers/document-legacy/createLegacyDocumentScraper.d.ts +1 -1
- package/esm/typings/src/scrapers/document-legacy/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/document-legacy/register-metadata.d.ts +2 -2
- package/esm/typings/src/scrapers/markdown/createMarkdownScraper.d.ts +1 -4
- package/esm/typings/src/scrapers/markdown/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/markdown/register-metadata.d.ts +2 -2
- package/esm/typings/src/scrapers/markitdown/createMarkitdownScraper.d.ts +1 -1
- package/esm/typings/src/scrapers/markitdown/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/markitdown/register-metadata.d.ts +2 -2
- package/esm/typings/src/scrapers/pdf/createPdfScraper.d.ts +1 -1
- package/esm/typings/src/scrapers/pdf/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/pdf/register-metadata.d.ts +2 -2
- package/esm/typings/src/scrapers/website/createWebsiteScraper.d.ts +1 -1
- package/esm/typings/src/scrapers/website/register-constructor.d.ts +1 -1
- package/esm/typings/src/scrapers/website/register-metadata.d.ts +2 -2
- package/esm/typings/src/types/typeAliases.d.ts +1 -1
- package/esm/typings/src/utils/files/listAllFiles.d.ts +1 -1
- package/esm/typings/src/version.d.ts +1 -1
- package/esm/typings/src/{wizzard → wizard}/$getCompiledBook.d.ts +2 -2
- package/esm/typings/src/{wizzard/wizzard.d.ts → wizard/wizard.d.ts} +6 -6
- package/package.json +2 -14
- package/umd/index.umd.js +338 -216
- 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.
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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,
|
|
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,
|
|
3246
|
+
all.push({ packageName, className, mimeTypes, documentationUrl, isAvailableInBrowser });
|
|
3247
3247
|
}
|
|
3248
|
-
for (const { packageName, className, mimeTypes, documentationUrl,
|
|
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,
|
|
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
|
|
3265
|
-
return { ...metadata, isMetadataAviailable, isInstalled,
|
|
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,
|
|
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 (
|
|
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 &&
|
|
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 (!
|
|
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
|
|
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
|
|
5203
|
-
const isJokerAttempt =
|
|
5204
|
-
const jokerParameterName = jokerParameterNames[jokerParameterNames.length +
|
|
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 ${
|
|
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
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
|
|
5410
|
-
|
|
5411
|
-
|
|
5412
|
-
|
|
5413
|
-
|
|
5414
|
-
|
|
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
|
-
|
|
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 &&
|
|
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
|
|
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
|
-
|
|
5480
|
-
${block(
|
|
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
|
|
5713
|
-
const
|
|
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 (
|
|
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:
|
|
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 ===
|
|
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
|
-
|
|
5756
|
-
|
|
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,
|
|
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
|
-
|
|
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: `
|
|
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
|
-
|
|
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: `
|
|
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,
|
|
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 (
|
|
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
|
-
|
|
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: `
|
|
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();
|