@promptbook/markdown-utils 0.89.0-9 โ 0.92.0-3
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 +9 -7
- package/esm/index.es.js +624 -532
- package/esm/index.es.js.map +1 -1
- package/esm/typings/servers.d.ts +40 -0
- package/esm/typings/src/_packages/core.index.d.ts +10 -4
- package/esm/typings/src/_packages/types.index.d.ts +18 -0
- package/esm/typings/src/_packages/utils.index.d.ts +4 -0
- package/esm/typings/src/cli/cli-commands/login.d.ts +0 -1
- package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +16 -3
- package/esm/typings/src/cli/test/ptbk.d.ts +1 -1
- package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +2 -0
- package/esm/typings/src/config.d.ts +10 -19
- package/esm/typings/src/errors/0-index.d.ts +7 -4
- package/esm/typings/src/errors/PipelineExecutionError.d.ts +1 -1
- package/esm/typings/src/errors/WrappedError.d.ts +10 -0
- package/esm/typings/src/errors/assertsError.d.ts +11 -0
- package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
- package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +9 -0
- package/esm/typings/src/formats/csv/utils/isValidCsvString.test.d.ts +1 -0
- package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +3 -0
- package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +9 -0
- package/esm/typings/src/formats/xml/utils/isValidXmlString.test.d.ts +1 -0
- package/esm/typings/src/llm-providers/_common/filterModels.d.ts +15 -0
- package/esm/typings/src/llm-providers/_common/register/{$provideEnvFilepath.d.ts โ $provideEnvFilename.d.ts} +2 -2
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +11 -2
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
- package/esm/typings/src/remote-server/openapi-types.d.ts +284 -0
- package/esm/typings/src/remote-server/openapi.d.ts +187 -0
- package/esm/typings/src/remote-server/socket-types/_subtypes/Identification.d.ts +7 -1
- package/esm/typings/src/remote-server/socket-types/_subtypes/identificationToPromptbookToken.d.ts +11 -0
- package/esm/typings/src/remote-server/socket-types/_subtypes/promptbookTokenToIdentification.d.ts +10 -0
- package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
- package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +15 -9
- package/esm/typings/src/storage/env-storage/$EnvStorage.d.ts +40 -0
- package/esm/typings/src/types/typeAliases.d.ts +26 -0
- package/package.json +7 -3
- package/umd/index.umd.js +624 -532
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
package/esm/index.es.js
CHANGED
|
@@ -25,7 +25,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
|
|
|
25
25
|
* @generated
|
|
26
26
|
* @see https://github.com/webgptorg/promptbook
|
|
27
27
|
*/
|
|
28
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.
|
|
28
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.92.0-3';
|
|
29
29
|
/**
|
|
30
30
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
31
31
|
* Note: [๐] Ignore a discrepancy between file name and entity name
|
|
@@ -173,547 +173,666 @@ function extractBlock(markdown) {
|
|
|
173
173
|
}
|
|
174
174
|
|
|
175
175
|
/**
|
|
176
|
-
*
|
|
176
|
+
* Returns the same value that is passed as argument.
|
|
177
|
+
* No side effects.
|
|
177
178
|
*
|
|
178
|
-
*
|
|
179
|
+
* Note: It can be usefull for:
|
|
180
|
+
*
|
|
181
|
+
* 1) Leveling indentation
|
|
182
|
+
* 2) Putting always-true or always-false conditions without getting eslint errors
|
|
183
|
+
*
|
|
184
|
+
* @param value any values
|
|
185
|
+
* @returns the same values
|
|
186
|
+
* @private within the repository
|
|
179
187
|
*/
|
|
180
|
-
function
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return true;
|
|
184
|
-
}
|
|
185
|
-
catch (error) {
|
|
186
|
-
if (!(error instanceof Error)) {
|
|
187
|
-
throw error;
|
|
188
|
-
}
|
|
189
|
-
if (error.message.includes('Unexpected token')) {
|
|
190
|
-
return false;
|
|
191
|
-
}
|
|
192
|
-
return false;
|
|
188
|
+
function just(value) {
|
|
189
|
+
if (value === undefined) {
|
|
190
|
+
return undefined;
|
|
193
191
|
}
|
|
192
|
+
return value;
|
|
194
193
|
}
|
|
195
194
|
|
|
196
195
|
/**
|
|
197
|
-
*
|
|
196
|
+
* Warning message for the generated sections and files files
|
|
198
197
|
*
|
|
199
|
-
*
|
|
200
|
-
|
|
201
|
-
|
|
198
|
+
* @private within the repository
|
|
199
|
+
*/
|
|
200
|
+
const GENERATOR_WARNING = `โ ๏ธ WARNING: This code has been generated so that any manual changes will be overwritten`;
|
|
201
|
+
/**
|
|
202
|
+
* Name for the Promptbook
|
|
202
203
|
*
|
|
203
|
-
*
|
|
204
|
-
* Note: There are multiple simmilar function:
|
|
205
|
-
* - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
|
|
206
|
-
* - `extractJsonBlock` extracts exactly one valid JSON code block
|
|
207
|
-
* - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
|
|
208
|
-
* - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
|
|
204
|
+
* TODO: [๐ฝ] Unite branding and make single place for it
|
|
209
205
|
*
|
|
210
|
-
* @public exported from `@promptbook/
|
|
211
|
-
* @throws {ParseError} if there is no valid JSON block in the markdown
|
|
206
|
+
* @public exported from `@promptbook/core`
|
|
212
207
|
*/
|
|
213
|
-
|
|
214
|
-
if (isValidJsonString(markdown)) {
|
|
215
|
-
return markdown;
|
|
216
|
-
}
|
|
217
|
-
const codeBlocks = extractAllBlocksFromMarkdown(markdown);
|
|
218
|
-
const jsonBlocks = codeBlocks.filter(({ content }) => isValidJsonString(content));
|
|
219
|
-
if (jsonBlocks.length === 0) {
|
|
220
|
-
throw new Error('There is no valid JSON block in the markdown');
|
|
221
|
-
}
|
|
222
|
-
if (jsonBlocks.length > 1) {
|
|
223
|
-
throw new Error('There are multiple JSON code blocks in the markdown');
|
|
224
|
-
}
|
|
225
|
-
return jsonBlocks[0].content;
|
|
226
|
-
}
|
|
208
|
+
const NAME = `Promptbook`;
|
|
227
209
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
210
|
+
* Email of the responsible person
|
|
211
|
+
*
|
|
212
|
+
* @public exported from `@promptbook/core`
|
|
230
213
|
*/
|
|
231
|
-
|
|
214
|
+
const ADMIN_EMAIL = 'pavol@ptbk.io';
|
|
232
215
|
/**
|
|
233
|
-
*
|
|
234
|
-
* No side effects.
|
|
216
|
+
* Name of the responsible person for the Promptbook on GitHub
|
|
235
217
|
*
|
|
236
|
-
*
|
|
218
|
+
* @public exported from `@promptbook/core`
|
|
219
|
+
*/
|
|
220
|
+
const ADMIN_GITHUB_NAME = 'hejny';
|
|
221
|
+
// <- TODO: [๐] Pick the best claim
|
|
222
|
+
/**
|
|
223
|
+
* When the title is not provided, the default title is used
|
|
237
224
|
*
|
|
238
|
-
*
|
|
239
|
-
|
|
240
|
-
|
|
225
|
+
* @public exported from `@promptbook/core`
|
|
226
|
+
*/
|
|
227
|
+
const DEFAULT_BOOK_TITLE = `โจ Untitled Book`;
|
|
228
|
+
/**
|
|
229
|
+
* Maximum file size limit
|
|
241
230
|
*
|
|
242
|
-
* @
|
|
243
|
-
* @returns void
|
|
244
|
-
* @private within the repository
|
|
231
|
+
* @public exported from `@promptbook/core`
|
|
245
232
|
*/
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
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:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the 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\nPick from the following models:\n\n- {availableModelNames}\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:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","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 `{availableModelNames}` List of available model names separated by comma (,)\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n\\`\\`\\`json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the 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\nPick from the following models:\n\n- {availableModelNames}\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`-> {modelRequirements}`\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"}];
|
|
250
|
-
|
|
233
|
+
const DEFAULT_MAX_FILE_SIZE = 100 * 1024 * 1024; // 100MB
|
|
234
|
+
// <- TODO: [๐ง ] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
|
|
251
235
|
/**
|
|
252
|
-
*
|
|
236
|
+
* The maximum number of iterations for a loops
|
|
237
|
+
*
|
|
238
|
+
* @private within the repository - too low-level in comparison with other `MAX_...`
|
|
239
|
+
*/
|
|
240
|
+
const LOOP_LIMIT = 1000;
|
|
241
|
+
/**
|
|
242
|
+
* Strings to represent various values in the context of parameter values
|
|
253
243
|
*
|
|
254
244
|
* @public exported from `@promptbook/utils`
|
|
255
245
|
*/
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
246
|
+
const VALUE_STRINGS = {
|
|
247
|
+
empty: '(nothing; empty string)',
|
|
248
|
+
null: '(no value; null)',
|
|
249
|
+
undefined: '(unknown value; undefined)',
|
|
250
|
+
nan: '(not a number; NaN)',
|
|
251
|
+
infinity: '(infinity; โ)',
|
|
252
|
+
negativeInfinity: '(negative infinity; -โ)',
|
|
253
|
+
unserializable: '(unserializable value)',
|
|
254
|
+
circular: '(circular JSON)',
|
|
255
|
+
};
|
|
266
256
|
/**
|
|
267
|
-
*
|
|
257
|
+
* Small number limit
|
|
268
258
|
*
|
|
269
|
-
* Note: This does not check if the file exists only if the path is valid
|
|
270
259
|
* @public exported from `@promptbook/utils`
|
|
271
260
|
*/
|
|
272
|
-
|
|
273
|
-
if (typeof filename !== 'string') {
|
|
274
|
-
return false;
|
|
275
|
-
}
|
|
276
|
-
if (filename.split('\n').length > 1) {
|
|
277
|
-
return false;
|
|
278
|
-
}
|
|
279
|
-
if (filename.split(' ').length >
|
|
280
|
-
5 /* <- TODO: [๐ง ][๐ท] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
|
|
281
|
-
return false;
|
|
282
|
-
}
|
|
283
|
-
const filenameSlashes = filename.split('\\').join('/');
|
|
284
|
-
// Absolute Unix path: /hello.txt
|
|
285
|
-
if (/^(\/)/i.test(filenameSlashes)) {
|
|
286
|
-
// console.log(filename, 'Absolute Unix path: /hello.txt');
|
|
287
|
-
return true;
|
|
288
|
-
}
|
|
289
|
-
// Absolute Windows path: /hello.txt
|
|
290
|
-
if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
|
|
291
|
-
// console.log(filename, 'Absolute Windows path: /hello.txt');
|
|
292
|
-
return true;
|
|
293
|
-
}
|
|
294
|
-
// Relative path: ./hello.txt
|
|
295
|
-
if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
|
|
296
|
-
// console.log(filename, 'Relative path: ./hello.txt');
|
|
297
|
-
return true;
|
|
298
|
-
}
|
|
299
|
-
// Allow paths like foo/hello
|
|
300
|
-
if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
|
|
301
|
-
// console.log(filename, 'Allow paths like foo/hello');
|
|
302
|
-
return true;
|
|
303
|
-
}
|
|
304
|
-
// Allow paths like hello.book
|
|
305
|
-
if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
|
|
306
|
-
// console.log(filename, 'Allow paths like hello.book');
|
|
307
|
-
return true;
|
|
308
|
-
}
|
|
309
|
-
return false;
|
|
310
|
-
}
|
|
261
|
+
const SMALL_NUMBER = 0.001;
|
|
311
262
|
/**
|
|
312
|
-
*
|
|
263
|
+
* Short time interval to prevent race conditions in milliseconds
|
|
264
|
+
*
|
|
265
|
+
* @private within the repository - too low-level in comparison with other `MAX_...`
|
|
313
266
|
*/
|
|
314
|
-
|
|
267
|
+
const IMMEDIATE_TIME = 10;
|
|
315
268
|
/**
|
|
316
|
-
*
|
|
269
|
+
* The maximum length of the (generated) filename
|
|
317
270
|
*
|
|
318
|
-
*
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
271
|
+
* @public exported from `@promptbook/core`
|
|
272
|
+
*/
|
|
273
|
+
const MAX_FILENAME_LENGTH = 30;
|
|
274
|
+
/**
|
|
275
|
+
* Strategy for caching the intermediate results for knowledge sources
|
|
322
276
|
*
|
|
323
|
-
* @public exported from `@promptbook/
|
|
277
|
+
* @public exported from `@promptbook/core`
|
|
324
278
|
*/
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
return false;
|
|
328
|
-
}
|
|
329
|
-
try {
|
|
330
|
-
if (url.startsWith('blob:')) {
|
|
331
|
-
url = url.replace(/^blob:/, '');
|
|
332
|
-
}
|
|
333
|
-
const urlObject = new URL(url /* because fail is handled */);
|
|
334
|
-
if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
337
|
-
return true;
|
|
338
|
-
}
|
|
339
|
-
catch (error) {
|
|
340
|
-
return false;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
279
|
+
const DEFAULT_INTERMEDIATE_FILES_STRATEGY = 'HIDE_AND_KEEP';
|
|
280
|
+
// <- TODO: [๐ก] Change to 'VISIBLE'
|
|
344
281
|
/**
|
|
345
|
-
*
|
|
346
|
-
* It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
|
|
282
|
+
* The maximum number of (LLM) tasks running in parallel
|
|
347
283
|
*
|
|
348
|
-
* @param {string} pipelineString the candidate for a pipeline string
|
|
349
|
-
* @returns {PipelineString} the same string as input, but validated as valid
|
|
350
|
-
* @throws {ParseError} if the string is not a valid pipeline string
|
|
351
284
|
* @public exported from `@promptbook/core`
|
|
352
285
|
*/
|
|
353
|
-
|
|
354
|
-
if (isValidJsonString(pipelineString)) {
|
|
355
|
-
throw new ParseError('Expected a book, but got a JSON string');
|
|
356
|
-
}
|
|
357
|
-
else if (isValidUrl(pipelineString)) {
|
|
358
|
-
throw new ParseError(`Expected a book, but got just the URL "${pipelineString}"`);
|
|
359
|
-
}
|
|
360
|
-
else if (isValidFilePath(pipelineString)) {
|
|
361
|
-
throw new ParseError(`Expected a book, but got just the file path "${pipelineString}"`);
|
|
362
|
-
}
|
|
363
|
-
else if (isValidEmail(pipelineString)) {
|
|
364
|
-
throw new ParseError(`Expected a book, but got just the email "${pipelineString}"`);
|
|
365
|
-
}
|
|
366
|
-
// <- TODO: Implement the validation + add tests when the pipeline logic considered as invalid
|
|
367
|
-
return pipelineString;
|
|
368
|
-
}
|
|
286
|
+
const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [๐คนโโ๏ธ]
|
|
369
287
|
/**
|
|
370
|
-
*
|
|
288
|
+
* The maximum number of attempts to execute LLM task before giving up
|
|
289
|
+
*
|
|
290
|
+
* @public exported from `@promptbook/core`
|
|
371
291
|
*/
|
|
372
|
-
|
|
292
|
+
const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [๐คนโโ๏ธ]
|
|
293
|
+
// <- TODO: [๐] Make also `BOOKS_DIRNAME_ALTERNATIVES`
|
|
294
|
+
// TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
|
|
373
295
|
/**
|
|
374
|
-
*
|
|
296
|
+
* Where to store the temporary downloads
|
|
375
297
|
*
|
|
376
|
-
*
|
|
377
|
-
*
|
|
378
|
-
* @
|
|
298
|
+
* Note: When the folder does not exist, it is created recursively
|
|
299
|
+
*
|
|
300
|
+
* @public exported from `@promptbook/core`
|
|
379
301
|
*/
|
|
380
|
-
|
|
381
|
-
try {
|
|
382
|
-
return format(content, {
|
|
383
|
-
parser: 'markdown',
|
|
384
|
-
plugins: [parserHtml],
|
|
385
|
-
// TODO: DRY - make some import or auto-copy of .prettierrc
|
|
386
|
-
endOfLine: 'lf',
|
|
387
|
-
tabWidth: 4,
|
|
388
|
-
singleQuote: true,
|
|
389
|
-
trailingComma: 'all',
|
|
390
|
-
arrowParens: 'always',
|
|
391
|
-
printWidth: 120,
|
|
392
|
-
htmlWhitespaceSensitivity: 'ignore',
|
|
393
|
-
jsxBracketSameLine: false,
|
|
394
|
-
bracketSpacing: true,
|
|
395
|
-
});
|
|
396
|
-
}
|
|
397
|
-
catch (error) {
|
|
398
|
-
// TODO: [๐ฅ] Detect browser / node and make it colorfull
|
|
399
|
-
console.error('There was an error with prettifying the markdown, using the original as the fallback', {
|
|
400
|
-
error,
|
|
401
|
-
html: content,
|
|
402
|
-
});
|
|
403
|
-
return content;
|
|
404
|
-
}
|
|
405
|
-
}
|
|
406
|
-
|
|
302
|
+
const DEFAULT_DOWNLOAD_CACHE_DIRNAME = './.promptbook/download-cache';
|
|
407
303
|
/**
|
|
408
|
-
*
|
|
304
|
+
* Where to store the scrape cache
|
|
305
|
+
*
|
|
306
|
+
* Note: When the folder does not exist, it is created recursively
|
|
409
307
|
*
|
|
410
|
-
* @deprecated TODO: [๐ฅ][๐ง ] Backup original files in `PipelineJson` same as in Promptbook.studio
|
|
411
|
-
* @param pipelineJson Promptbook in JSON format (.bookc)
|
|
412
|
-
* @returns Promptbook in string format (.book.md)
|
|
413
308
|
* @public exported from `@promptbook/core`
|
|
414
309
|
*/
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
let pipelineString = `# ${title}`;
|
|
418
|
-
if (description) {
|
|
419
|
-
pipelineString += '\n\n';
|
|
420
|
-
pipelineString += description;
|
|
421
|
-
}
|
|
422
|
-
const commands = [];
|
|
423
|
-
if (pipelineUrl) {
|
|
424
|
-
commands.push(`PIPELINE URL ${pipelineUrl}`);
|
|
425
|
-
}
|
|
426
|
-
if (bookVersion !== `undefined`) {
|
|
427
|
-
commands.push(`BOOK VERSION ${bookVersion}`);
|
|
428
|
-
}
|
|
429
|
-
// TODO: [main] !!5 This increases size of the bundle and is probbably not necessary
|
|
430
|
-
pipelineString = prettifyMarkdown(pipelineString);
|
|
431
|
-
for (const parameter of parameters.filter(({ isInput }) => isInput)) {
|
|
432
|
-
commands.push(`INPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
433
|
-
}
|
|
434
|
-
for (const parameter of parameters.filter(({ isOutput }) => isOutput)) {
|
|
435
|
-
commands.push(`OUTPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
436
|
-
}
|
|
437
|
-
pipelineString += '\n\n';
|
|
438
|
-
pipelineString += commands.map((command) => `- ${command}`).join('\n');
|
|
439
|
-
for (const task of tasks) {
|
|
440
|
-
const {
|
|
441
|
-
/* Note: Not using:> name, */
|
|
442
|
-
title, description,
|
|
443
|
-
/* Note: dependentParameterNames, */
|
|
444
|
-
jokerParameterNames: jokers, taskType, content, postprocessingFunctionNames: postprocessing, expectations, format, resultingParameterName, } = task;
|
|
445
|
-
pipelineString += '\n\n';
|
|
446
|
-
pipelineString += `## ${title}`;
|
|
447
|
-
if (description) {
|
|
448
|
-
pipelineString += '\n\n';
|
|
449
|
-
pipelineString += description;
|
|
450
|
-
}
|
|
451
|
-
const commands = [];
|
|
452
|
-
let contentLanguage = 'text';
|
|
453
|
-
if (taskType === 'PROMPT_TASK') {
|
|
454
|
-
const { modelRequirements } = task;
|
|
455
|
-
const { modelName, modelVariant } = modelRequirements || {};
|
|
456
|
-
// Note: Do nothing, it is default
|
|
457
|
-
// commands.push(`PROMPT`);
|
|
458
|
-
if (modelVariant) {
|
|
459
|
-
commands.push(`MODEL VARIANT ${capitalize(modelVariant)}`);
|
|
460
|
-
}
|
|
461
|
-
if (modelName) {
|
|
462
|
-
commands.push(`MODEL NAME \`${modelName}\``);
|
|
463
|
-
}
|
|
464
|
-
}
|
|
465
|
-
else if (taskType === 'SIMPLE_TASK') {
|
|
466
|
-
commands.push(`SIMPLE TEMPLATE`);
|
|
467
|
-
// Note: Nothing special here
|
|
468
|
-
}
|
|
469
|
-
else if (taskType === 'SCRIPT_TASK') {
|
|
470
|
-
commands.push(`SCRIPT`);
|
|
471
|
-
if (task.contentLanguage) {
|
|
472
|
-
contentLanguage = task.contentLanguage;
|
|
473
|
-
}
|
|
474
|
-
else {
|
|
475
|
-
contentLanguage = '';
|
|
476
|
-
}
|
|
477
|
-
}
|
|
478
|
-
else if (taskType === 'DIALOG_TASK') {
|
|
479
|
-
commands.push(`DIALOG`);
|
|
480
|
-
// Note: Nothing special here
|
|
481
|
-
} // <- }else if([๐
ฑ]
|
|
482
|
-
if (jokers) {
|
|
483
|
-
for (const joker of jokers) {
|
|
484
|
-
commands.push(`JOKER {${joker}}`);
|
|
485
|
-
}
|
|
486
|
-
} /* not else */
|
|
487
|
-
if (postprocessing) {
|
|
488
|
-
for (const postprocessingFunctionName of postprocessing) {
|
|
489
|
-
commands.push(`POSTPROCESSING \`${postprocessingFunctionName}\``);
|
|
490
|
-
}
|
|
491
|
-
} /* not else */
|
|
492
|
-
if (expectations) {
|
|
493
|
-
for (const [unit, { min, max }] of Object.entries(expectations)) {
|
|
494
|
-
if (min === max) {
|
|
495
|
-
commands.push(`EXPECT EXACTLY ${min} ${capitalize(unit + (min > 1 ? 's' : ''))}`);
|
|
496
|
-
}
|
|
497
|
-
else {
|
|
498
|
-
if (min !== undefined) {
|
|
499
|
-
commands.push(`EXPECT MIN ${min} ${capitalize(unit + (min > 1 ? 's' : ''))}`);
|
|
500
|
-
} /* not else */
|
|
501
|
-
if (max !== undefined) {
|
|
502
|
-
commands.push(`EXPECT MAX ${max} ${capitalize(unit + (max > 1 ? 's' : ''))}`);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
} /* not else */
|
|
507
|
-
if (format) {
|
|
508
|
-
if (format === 'JSON') {
|
|
509
|
-
// TODO: @deprecated remove
|
|
510
|
-
commands.push(`FORMAT JSON`);
|
|
511
|
-
}
|
|
512
|
-
} /* not else */
|
|
513
|
-
pipelineString += '\n\n';
|
|
514
|
-
pipelineString += commands.map((command) => `- ${command}`).join('\n');
|
|
515
|
-
pipelineString += '\n\n';
|
|
516
|
-
pipelineString += '```' + contentLanguage;
|
|
517
|
-
pipelineString += '\n';
|
|
518
|
-
pipelineString += spaceTrim(content);
|
|
519
|
-
// <- TODO: [main] !!3 Escape
|
|
520
|
-
// <- TODO: [๐ง ] Some clear strategy how to spaceTrim the blocks
|
|
521
|
-
pipelineString += '\n';
|
|
522
|
-
pipelineString += '```';
|
|
523
|
-
pipelineString += '\n\n';
|
|
524
|
-
pipelineString += `\`-> {${resultingParameterName}}\``; // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
|
|
525
|
-
}
|
|
526
|
-
return validatePipelineString(pipelineString);
|
|
527
|
-
}
|
|
310
|
+
const DEFAULT_SCRAPE_CACHE_DIRNAME = './.promptbook/scrape-cache';
|
|
311
|
+
// <- TODO: [๐งโโ๏ธ]
|
|
528
312
|
/**
|
|
529
|
-
*
|
|
313
|
+
* @@@
|
|
314
|
+
*
|
|
315
|
+
* @public exported from `@promptbook/core`
|
|
530
316
|
*/
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
return parameterString;
|
|
538
|
-
}
|
|
317
|
+
const DEFAULT_CSV_SETTINGS = Object.freeze({
|
|
318
|
+
delimiter: ',',
|
|
319
|
+
quoteChar: '"',
|
|
320
|
+
newline: '\n',
|
|
321
|
+
skipEmptyLines: true,
|
|
322
|
+
});
|
|
539
323
|
/**
|
|
540
|
-
*
|
|
541
|
-
*
|
|
542
|
-
*
|
|
543
|
-
* TODO: [๐] Escape all
|
|
544
|
-
* TODO: [๐ง ] Should be in generated .book.md file GENERATOR_WARNING
|
|
324
|
+
* @@@
|
|
325
|
+
*
|
|
326
|
+
* @public exported from `@promptbook/core`
|
|
545
327
|
*/
|
|
546
|
-
|
|
328
|
+
let DEFAULT_IS_VERBOSE = false;
|
|
547
329
|
/**
|
|
548
|
-
*
|
|
549
|
-
* No side effects.
|
|
550
|
-
*
|
|
551
|
-
* Note: It can be usefull for:
|
|
552
|
-
*
|
|
553
|
-
* 1) Leveling indentation
|
|
554
|
-
* 2) Putting always-true or always-false conditions without getting eslint errors
|
|
330
|
+
* @@@
|
|
555
331
|
*
|
|
556
|
-
* @
|
|
557
|
-
* @returns the same values
|
|
558
|
-
* @private within the repository
|
|
332
|
+
* @public exported from `@promptbook/core`
|
|
559
333
|
*/
|
|
560
|
-
|
|
561
|
-
if (value === undefined) {
|
|
562
|
-
return undefined;
|
|
563
|
-
}
|
|
564
|
-
return value;
|
|
565
|
-
}
|
|
566
|
-
|
|
334
|
+
const DEFAULT_IS_AUTO_INSTALLED = false;
|
|
567
335
|
/**
|
|
568
|
-
*
|
|
336
|
+
* @@@
|
|
569
337
|
*
|
|
570
338
|
* @private within the repository
|
|
571
339
|
*/
|
|
572
|
-
const
|
|
340
|
+
const IS_PIPELINE_LOGIC_VALIDATED = just(
|
|
341
|
+
/**/
|
|
342
|
+
// Note: In normal situations, we check the pipeline logic:
|
|
343
|
+
true);
|
|
573
344
|
/**
|
|
574
|
-
*
|
|
575
|
-
*
|
|
576
|
-
* TODO: [๐ฝ] Unite branding and make single place for it
|
|
577
|
-
*
|
|
578
|
-
* @public exported from `@promptbook/core`
|
|
345
|
+
* Note: [๐] Ignore a discrepancy between file name and entity name
|
|
346
|
+
* TODO: [๐ง ][๐งโโ๏ธ] Maybe join remoteServerUrl and path into single value
|
|
579
347
|
*/
|
|
580
|
-
|
|
348
|
+
|
|
581
349
|
/**
|
|
582
|
-
*
|
|
350
|
+
* Make error report URL for the given error
|
|
583
351
|
*
|
|
584
|
-
* @
|
|
352
|
+
* @private private within the repository
|
|
585
353
|
*/
|
|
586
|
-
|
|
354
|
+
function getErrorReportUrl(error) {
|
|
355
|
+
const report = {
|
|
356
|
+
title: `๐ Error report from ${NAME}`,
|
|
357
|
+
body: spaceTrim((block) => `
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
361
|
+
|
|
362
|
+
\`\`\`
|
|
363
|
+
${block(error.message || '(no error message)')}
|
|
364
|
+
\`\`\`
|
|
365
|
+
|
|
366
|
+
|
|
367
|
+
## More info:
|
|
368
|
+
|
|
369
|
+
- **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
|
|
370
|
+
- **Book language version:** ${BOOK_LANGUAGE_VERSION}
|
|
371
|
+
- **Time:** ${new Date().toISOString()}
|
|
372
|
+
|
|
373
|
+
<details>
|
|
374
|
+
<summary>Stack trace:</summary>
|
|
375
|
+
|
|
376
|
+
## Stack trace:
|
|
377
|
+
|
|
378
|
+
\`\`\`stacktrace
|
|
379
|
+
${block(error.stack || '(empty)')}
|
|
380
|
+
\`\`\`
|
|
381
|
+
</details>
|
|
382
|
+
|
|
383
|
+
`),
|
|
384
|
+
};
|
|
385
|
+
const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
|
|
386
|
+
reportUrl.searchParams.set('labels', 'bug');
|
|
387
|
+
reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
|
|
388
|
+
reportUrl.searchParams.set('title', report.title);
|
|
389
|
+
reportUrl.searchParams.set('body', report.body);
|
|
390
|
+
return reportUrl;
|
|
391
|
+
}
|
|
392
|
+
|
|
587
393
|
/**
|
|
588
|
-
*
|
|
394
|
+
* This error type indicates that the error should not happen and its last check before crashing with some other error
|
|
589
395
|
*
|
|
590
396
|
* @public exported from `@promptbook/core`
|
|
591
397
|
*/
|
|
592
|
-
|
|
398
|
+
class UnexpectedError extends Error {
|
|
399
|
+
constructor(message) {
|
|
400
|
+
super(spaceTrim$1((block) => `
|
|
401
|
+
${block(message)}
|
|
402
|
+
|
|
403
|
+
Note: This error should not happen.
|
|
404
|
+
It's probbably a bug in the pipeline collection
|
|
405
|
+
|
|
406
|
+
Please report issue:
|
|
407
|
+
${block(getErrorReportUrl(new Error(message)).href)}
|
|
408
|
+
|
|
409
|
+
Or contact us on ${ADMIN_EMAIL}
|
|
410
|
+
|
|
411
|
+
`));
|
|
412
|
+
this.name = 'UnexpectedError';
|
|
413
|
+
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
593
417
|
/**
|
|
594
|
-
*
|
|
418
|
+
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
595
419
|
*
|
|
596
420
|
* @public exported from `@promptbook/core`
|
|
597
421
|
*/
|
|
598
|
-
|
|
422
|
+
class WrappedError extends Error {
|
|
423
|
+
constructor(whatWasThrown) {
|
|
424
|
+
const tag = `[๐คฎ]`;
|
|
425
|
+
console.error(tag, whatWasThrown);
|
|
426
|
+
super(spaceTrim$1(`
|
|
427
|
+
Non-Error object was thrown
|
|
428
|
+
|
|
429
|
+
Note: Look for ${tag} in the console for more details
|
|
430
|
+
Please report issue on ${ADMIN_EMAIL}
|
|
431
|
+
`));
|
|
432
|
+
this.name = 'WrappedError';
|
|
433
|
+
Object.setPrototypeOf(this, WrappedError.prototype);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
|
|
599
437
|
/**
|
|
600
|
-
*
|
|
438
|
+
* Helper used in catch blocks to assert that the error is an instance of `Error`
|
|
601
439
|
*
|
|
602
|
-
* @
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
// <- TODO: [๐ง ] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
|
|
606
|
-
/**
|
|
607
|
-
* The maximum number of iterations for a loops
|
|
440
|
+
* @param whatWasThrown Any object that was thrown
|
|
441
|
+
* @returns Nothing if the error is an instance of `Error`
|
|
442
|
+
* @throws `WrappedError` or `UnexpectedError` if the error is not standard
|
|
608
443
|
*
|
|
609
|
-
* @private within the repository
|
|
444
|
+
* @private within the repository
|
|
610
445
|
*/
|
|
611
|
-
|
|
446
|
+
function assertsError(whatWasThrown) {
|
|
447
|
+
// Case 1: Handle error which was rethrown as `WrappedError`
|
|
448
|
+
if (whatWasThrown instanceof WrappedError) {
|
|
449
|
+
const wrappedError = whatWasThrown;
|
|
450
|
+
throw wrappedError;
|
|
451
|
+
}
|
|
452
|
+
// Case 2: Handle unexpected errors
|
|
453
|
+
if (whatWasThrown instanceof UnexpectedError) {
|
|
454
|
+
const unexpectedError = whatWasThrown;
|
|
455
|
+
throw unexpectedError;
|
|
456
|
+
}
|
|
457
|
+
// Case 3: Handle standard errors - keep them up to consumer
|
|
458
|
+
if (whatWasThrown instanceof Error) {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
// Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
|
|
462
|
+
throw new WrappedError(whatWasThrown);
|
|
463
|
+
}
|
|
464
|
+
|
|
612
465
|
/**
|
|
613
|
-
*
|
|
466
|
+
* Function isValidJsonString will tell you if the string is valid JSON or not
|
|
467
|
+
*
|
|
468
|
+
* @param value The string to check
|
|
469
|
+
* @returns True if the string is a valid JSON string, false otherwise
|
|
614
470
|
*
|
|
615
471
|
* @public exported from `@promptbook/utils`
|
|
616
472
|
*/
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
473
|
+
function isValidJsonString(value /* <- [๐จโโ๏ธ] */) {
|
|
474
|
+
try {
|
|
475
|
+
JSON.parse(value);
|
|
476
|
+
return true;
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
assertsError(error);
|
|
480
|
+
if (error.message.includes('Unexpected token')) {
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
626
487
|
/**
|
|
627
|
-
*
|
|
488
|
+
* Extracts extracts exactly one valid JSON code block
|
|
628
489
|
*
|
|
629
|
-
*
|
|
490
|
+
* - When given string is a valid JSON as it is, it just returns it
|
|
491
|
+
* - When there is no JSON code block the function throws a `ParseError`
|
|
492
|
+
* - When there are multiple JSON code blocks the function throws a `ParseError`
|
|
493
|
+
*
|
|
494
|
+
* Note: It is not important if marked as ```json BUT if it is VALID JSON
|
|
495
|
+
* Note: There are multiple simmilar function:
|
|
496
|
+
* - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
|
|
497
|
+
* - `extractJsonBlock` extracts exactly one valid JSON code block
|
|
498
|
+
* - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
|
|
499
|
+
* - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
|
|
500
|
+
*
|
|
501
|
+
* @public exported from `@promptbook/markdown-utils`
|
|
502
|
+
* @throws {ParseError} if there is no valid JSON block in the markdown
|
|
630
503
|
*/
|
|
631
|
-
|
|
504
|
+
function extractJsonBlock(markdown) {
|
|
505
|
+
if (isValidJsonString(markdown)) {
|
|
506
|
+
return markdown;
|
|
507
|
+
}
|
|
508
|
+
const codeBlocks = extractAllBlocksFromMarkdown(markdown);
|
|
509
|
+
const jsonBlocks = codeBlocks.filter(({ content }) => isValidJsonString(content));
|
|
510
|
+
if (jsonBlocks.length === 0) {
|
|
511
|
+
throw new Error('There is no valid JSON block in the markdown');
|
|
512
|
+
}
|
|
513
|
+
if (jsonBlocks.length > 1) {
|
|
514
|
+
throw new Error('There are multiple JSON code blocks in the markdown');
|
|
515
|
+
}
|
|
516
|
+
return jsonBlocks[0].content;
|
|
517
|
+
}
|
|
632
518
|
/**
|
|
633
|
-
*
|
|
634
|
-
*
|
|
635
|
-
* @private within the repository - too low-level in comparison with other `MAX_...`
|
|
519
|
+
* TODO: Add some auto-healing logic + extract YAML, JSON5, TOML, etc.
|
|
520
|
+
* TODO: [๐ข] Make this logic part of `JsonFormatDefinition` or `isValidJsonString`
|
|
636
521
|
*/
|
|
637
|
-
|
|
522
|
+
|
|
638
523
|
/**
|
|
639
|
-
*
|
|
524
|
+
* Just says that the variable is not used but should be kept
|
|
525
|
+
* No side effects.
|
|
640
526
|
*
|
|
641
|
-
*
|
|
527
|
+
* Note: It can be usefull for:
|
|
528
|
+
*
|
|
529
|
+
* 1) Suppressing eager optimization of unused imports
|
|
530
|
+
* 2) Suppressing eslint errors of unused variables in the tests
|
|
531
|
+
* 3) Keeping the type of the variable for type testing
|
|
532
|
+
*
|
|
533
|
+
* @param value any values
|
|
534
|
+
* @returns void
|
|
535
|
+
* @private within the repository
|
|
642
536
|
*/
|
|
643
|
-
|
|
537
|
+
function keepUnused(...valuesToKeep) {
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
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:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the 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\nPick from the following models:\n\n- {availableModelNames}\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:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","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 `{availableModelNames}` List of available model names separated by comma (,)\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n\\`\\`\\`json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the 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\nPick from the following models:\n\n- {availableModelNames}\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`-> {modelRequirements}`\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"}];
|
|
541
|
+
|
|
644
542
|
/**
|
|
645
|
-
*
|
|
543
|
+
* Checks if value is valid email
|
|
646
544
|
*
|
|
647
|
-
* @public exported from `@promptbook/
|
|
545
|
+
* @public exported from `@promptbook/utils`
|
|
648
546
|
*/
|
|
649
|
-
|
|
650
|
-
|
|
547
|
+
function isValidEmail(email) {
|
|
548
|
+
if (typeof email !== 'string') {
|
|
549
|
+
return false;
|
|
550
|
+
}
|
|
551
|
+
if (email.split('\n').length > 1) {
|
|
552
|
+
return false;
|
|
553
|
+
}
|
|
554
|
+
return /^.+@.+\..+$/.test(email);
|
|
555
|
+
}
|
|
556
|
+
|
|
651
557
|
/**
|
|
652
|
-
*
|
|
558
|
+
* Tests if given string is valid URL.
|
|
653
559
|
*
|
|
654
|
-
*
|
|
560
|
+
* Note: This does not check if the file exists only if the path is valid
|
|
561
|
+
* @public exported from `@promptbook/utils`
|
|
655
562
|
*/
|
|
656
|
-
|
|
563
|
+
function isValidFilePath(filename) {
|
|
564
|
+
if (typeof filename !== 'string') {
|
|
565
|
+
return false;
|
|
566
|
+
}
|
|
567
|
+
if (filename.split('\n').length > 1) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
if (filename.split(' ').length >
|
|
571
|
+
5 /* <- TODO: [๐ง ][๐ท] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
|
|
572
|
+
return false;
|
|
573
|
+
}
|
|
574
|
+
const filenameSlashes = filename.split('\\').join('/');
|
|
575
|
+
// Absolute Unix path: /hello.txt
|
|
576
|
+
if (/^(\/)/i.test(filenameSlashes)) {
|
|
577
|
+
// console.log(filename, 'Absolute Unix path: /hello.txt');
|
|
578
|
+
return true;
|
|
579
|
+
}
|
|
580
|
+
// Absolute Windows path: /hello.txt
|
|
581
|
+
if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
|
|
582
|
+
// console.log(filename, 'Absolute Windows path: /hello.txt');
|
|
583
|
+
return true;
|
|
584
|
+
}
|
|
585
|
+
// Relative path: ./hello.txt
|
|
586
|
+
if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
|
|
587
|
+
// console.log(filename, 'Relative path: ./hello.txt');
|
|
588
|
+
return true;
|
|
589
|
+
}
|
|
590
|
+
// Allow paths like foo/hello
|
|
591
|
+
if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
|
|
592
|
+
// console.log(filename, 'Allow paths like foo/hello');
|
|
593
|
+
return true;
|
|
594
|
+
}
|
|
595
|
+
// Allow paths like hello.book
|
|
596
|
+
if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
|
|
597
|
+
// console.log(filename, 'Allow paths like hello.book');
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
657
602
|
/**
|
|
658
|
-
*
|
|
659
|
-
*
|
|
660
|
-
* @public exported from `@promptbook/core`
|
|
603
|
+
* TODO: [๐] Implement for MacOs
|
|
661
604
|
*/
|
|
662
|
-
|
|
663
|
-
// <- TODO: [๐] Make also `BOOKS_DIRNAME_ALTERNATIVES`
|
|
664
|
-
// TODO: !!!!!! Just .promptbook dir, hardocode others
|
|
605
|
+
|
|
665
606
|
/**
|
|
666
|
-
*
|
|
607
|
+
* Tests if given string is valid URL.
|
|
667
608
|
*
|
|
668
|
-
* Note:
|
|
609
|
+
* Note: Dataurl are considered perfectly valid.
|
|
610
|
+
* Note: There are two simmilar functions:
|
|
611
|
+
* - `isValidUrl` which tests any URL
|
|
612
|
+
* - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
|
|
669
613
|
*
|
|
670
|
-
* @public exported from `@promptbook/
|
|
614
|
+
* @public exported from `@promptbook/utils`
|
|
671
615
|
*/
|
|
672
|
-
|
|
616
|
+
function isValidUrl(url) {
|
|
617
|
+
if (typeof url !== 'string') {
|
|
618
|
+
return false;
|
|
619
|
+
}
|
|
620
|
+
try {
|
|
621
|
+
if (url.startsWith('blob:')) {
|
|
622
|
+
url = url.replace(/^blob:/, '');
|
|
623
|
+
}
|
|
624
|
+
const urlObject = new URL(url /* because fail is handled */);
|
|
625
|
+
if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
628
|
+
return true;
|
|
629
|
+
}
|
|
630
|
+
catch (error) {
|
|
631
|
+
return false;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
|
|
673
635
|
/**
|
|
674
|
-
*
|
|
675
|
-
*
|
|
676
|
-
* Note: When the folder does not exist, it is created recursively
|
|
636
|
+
* Function `validatePipelineString` will validate the if the string is a valid pipeline string
|
|
637
|
+
* It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
|
|
677
638
|
*
|
|
639
|
+
* @param {string} pipelineString the candidate for a pipeline string
|
|
640
|
+
* @returns {PipelineString} the same string as input, but validated as valid
|
|
641
|
+
* @throws {ParseError} if the string is not a valid pipeline string
|
|
678
642
|
* @public exported from `@promptbook/core`
|
|
679
643
|
*/
|
|
680
|
-
|
|
681
|
-
|
|
644
|
+
function validatePipelineString(pipelineString) {
|
|
645
|
+
if (isValidJsonString(pipelineString)) {
|
|
646
|
+
throw new ParseError('Expected a book, but got a JSON string');
|
|
647
|
+
}
|
|
648
|
+
else if (isValidUrl(pipelineString)) {
|
|
649
|
+
throw new ParseError(`Expected a book, but got just the URL "${pipelineString}"`);
|
|
650
|
+
}
|
|
651
|
+
else if (isValidFilePath(pipelineString)) {
|
|
652
|
+
throw new ParseError(`Expected a book, but got just the file path "${pipelineString}"`);
|
|
653
|
+
}
|
|
654
|
+
else if (isValidEmail(pipelineString)) {
|
|
655
|
+
throw new ParseError(`Expected a book, but got just the email "${pipelineString}"`);
|
|
656
|
+
}
|
|
657
|
+
// <- TODO: Implement the validation + add tests when the pipeline logic considered as invalid
|
|
658
|
+
return pipelineString;
|
|
659
|
+
}
|
|
682
660
|
/**
|
|
683
|
-
*
|
|
684
|
-
*
|
|
685
|
-
* @public exported from `@promptbook/core`
|
|
661
|
+
* TODO: [๐ง ][๐ด] Where is the best location for this file
|
|
686
662
|
*/
|
|
687
|
-
|
|
688
|
-
delimiter: ',',
|
|
689
|
-
quoteChar: '"',
|
|
690
|
-
newline: '\n',
|
|
691
|
-
skipEmptyLines: true,
|
|
692
|
-
});
|
|
663
|
+
|
|
693
664
|
/**
|
|
694
|
-
*
|
|
665
|
+
* Prettify the html code
|
|
695
666
|
*
|
|
696
|
-
* @
|
|
667
|
+
* @param content raw html code
|
|
668
|
+
* @returns formatted html code
|
|
669
|
+
* @private withing the package because of HUGE size of prettier dependency
|
|
697
670
|
*/
|
|
698
|
-
|
|
671
|
+
function prettifyMarkdown(content) {
|
|
672
|
+
try {
|
|
673
|
+
return format(content, {
|
|
674
|
+
parser: 'markdown',
|
|
675
|
+
plugins: [parserHtml],
|
|
676
|
+
// TODO: DRY - make some import or auto-copy of .prettierrc
|
|
677
|
+
endOfLine: 'lf',
|
|
678
|
+
tabWidth: 4,
|
|
679
|
+
singleQuote: true,
|
|
680
|
+
trailingComma: 'all',
|
|
681
|
+
arrowParens: 'always',
|
|
682
|
+
printWidth: 120,
|
|
683
|
+
htmlWhitespaceSensitivity: 'ignore',
|
|
684
|
+
jsxBracketSameLine: false,
|
|
685
|
+
bracketSpacing: true,
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
catch (error) {
|
|
689
|
+
// TODO: [๐ฅ] Detect browser / node and make it colorfull
|
|
690
|
+
console.error('There was an error with prettifying the markdown, using the original as the fallback', {
|
|
691
|
+
error,
|
|
692
|
+
html: content,
|
|
693
|
+
});
|
|
694
|
+
return content;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
|
|
699
698
|
/**
|
|
700
|
-
*
|
|
699
|
+
* Converts promptbook in JSON format to string format
|
|
701
700
|
*
|
|
701
|
+
* @deprecated TODO: [๐ฅ][๐ง ] Backup original files in `PipelineJson` same as in Promptbook.studio
|
|
702
|
+
* @param pipelineJson Promptbook in JSON format (.bookc)
|
|
703
|
+
* @returns Promptbook in string format (.book.md)
|
|
702
704
|
* @public exported from `@promptbook/core`
|
|
703
705
|
*/
|
|
704
|
-
|
|
706
|
+
function pipelineJsonToString(pipelineJson) {
|
|
707
|
+
const { title, pipelineUrl, bookVersion, description, parameters, tasks } = pipelineJson;
|
|
708
|
+
let pipelineString = `# ${title}`;
|
|
709
|
+
if (description) {
|
|
710
|
+
pipelineString += '\n\n';
|
|
711
|
+
pipelineString += description;
|
|
712
|
+
}
|
|
713
|
+
const commands = [];
|
|
714
|
+
if (pipelineUrl) {
|
|
715
|
+
commands.push(`PIPELINE URL ${pipelineUrl}`);
|
|
716
|
+
}
|
|
717
|
+
if (bookVersion !== `undefined`) {
|
|
718
|
+
commands.push(`BOOK VERSION ${bookVersion}`);
|
|
719
|
+
}
|
|
720
|
+
// TODO: [main] !!5 This increases size of the bundle and is probbably not necessary
|
|
721
|
+
pipelineString = prettifyMarkdown(pipelineString);
|
|
722
|
+
for (const parameter of parameters.filter(({ isInput }) => isInput)) {
|
|
723
|
+
commands.push(`INPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
724
|
+
}
|
|
725
|
+
for (const parameter of parameters.filter(({ isOutput }) => isOutput)) {
|
|
726
|
+
commands.push(`OUTPUT PARAMETER ${taskParameterJsonToString(parameter)}`);
|
|
727
|
+
}
|
|
728
|
+
pipelineString += '\n\n';
|
|
729
|
+
pipelineString += commands.map((command) => `- ${command}`).join('\n');
|
|
730
|
+
for (const task of tasks) {
|
|
731
|
+
const {
|
|
732
|
+
/* Note: Not using:> name, */
|
|
733
|
+
title, description,
|
|
734
|
+
/* Note: dependentParameterNames, */
|
|
735
|
+
jokerParameterNames: jokers, taskType, content, postprocessingFunctionNames: postprocessing, expectations, format, resultingParameterName, } = task;
|
|
736
|
+
pipelineString += '\n\n';
|
|
737
|
+
pipelineString += `## ${title}`;
|
|
738
|
+
if (description) {
|
|
739
|
+
pipelineString += '\n\n';
|
|
740
|
+
pipelineString += description;
|
|
741
|
+
}
|
|
742
|
+
const commands = [];
|
|
743
|
+
let contentLanguage = 'text';
|
|
744
|
+
if (taskType === 'PROMPT_TASK') {
|
|
745
|
+
const { modelRequirements } = task;
|
|
746
|
+
const { modelName, modelVariant } = modelRequirements || {};
|
|
747
|
+
// Note: Do nothing, it is default
|
|
748
|
+
// commands.push(`PROMPT`);
|
|
749
|
+
if (modelVariant) {
|
|
750
|
+
commands.push(`MODEL VARIANT ${capitalize(modelVariant)}`);
|
|
751
|
+
}
|
|
752
|
+
if (modelName) {
|
|
753
|
+
commands.push(`MODEL NAME \`${modelName}\``);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
else if (taskType === 'SIMPLE_TASK') {
|
|
757
|
+
commands.push(`SIMPLE TEMPLATE`);
|
|
758
|
+
// Note: Nothing special here
|
|
759
|
+
}
|
|
760
|
+
else if (taskType === 'SCRIPT_TASK') {
|
|
761
|
+
commands.push(`SCRIPT`);
|
|
762
|
+
if (task.contentLanguage) {
|
|
763
|
+
contentLanguage = task.contentLanguage;
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
contentLanguage = '';
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
else if (taskType === 'DIALOG_TASK') {
|
|
770
|
+
commands.push(`DIALOG`);
|
|
771
|
+
// Note: Nothing special here
|
|
772
|
+
} // <- }else if([๐
ฑ]
|
|
773
|
+
if (jokers) {
|
|
774
|
+
for (const joker of jokers) {
|
|
775
|
+
commands.push(`JOKER {${joker}}`);
|
|
776
|
+
}
|
|
777
|
+
} /* not else */
|
|
778
|
+
if (postprocessing) {
|
|
779
|
+
for (const postprocessingFunctionName of postprocessing) {
|
|
780
|
+
commands.push(`POSTPROCESSING \`${postprocessingFunctionName}\``);
|
|
781
|
+
}
|
|
782
|
+
} /* not else */
|
|
783
|
+
if (expectations) {
|
|
784
|
+
for (const [unit, { min, max }] of Object.entries(expectations)) {
|
|
785
|
+
if (min === max) {
|
|
786
|
+
commands.push(`EXPECT EXACTLY ${min} ${capitalize(unit + (min > 1 ? 's' : ''))}`);
|
|
787
|
+
}
|
|
788
|
+
else {
|
|
789
|
+
if (min !== undefined) {
|
|
790
|
+
commands.push(`EXPECT MIN ${min} ${capitalize(unit + (min > 1 ? 's' : ''))}`);
|
|
791
|
+
} /* not else */
|
|
792
|
+
if (max !== undefined) {
|
|
793
|
+
commands.push(`EXPECT MAX ${max} ${capitalize(unit + (max > 1 ? 's' : ''))}`);
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
}
|
|
797
|
+
} /* not else */
|
|
798
|
+
if (format) {
|
|
799
|
+
if (format === 'JSON') {
|
|
800
|
+
// TODO: @deprecated remove
|
|
801
|
+
commands.push(`FORMAT JSON`);
|
|
802
|
+
}
|
|
803
|
+
} /* not else */
|
|
804
|
+
pipelineString += '\n\n';
|
|
805
|
+
pipelineString += commands.map((command) => `- ${command}`).join('\n');
|
|
806
|
+
pipelineString += '\n\n';
|
|
807
|
+
pipelineString += '```' + contentLanguage;
|
|
808
|
+
pipelineString += '\n';
|
|
809
|
+
pipelineString += spaceTrim(content);
|
|
810
|
+
// <- TODO: [main] !!3 Escape
|
|
811
|
+
// <- TODO: [๐ง ] Some clear strategy how to spaceTrim the blocks
|
|
812
|
+
pipelineString += '\n';
|
|
813
|
+
pipelineString += '```';
|
|
814
|
+
pipelineString += '\n\n';
|
|
815
|
+
pipelineString += `\`-> {${resultingParameterName}}\``; // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
|
|
816
|
+
}
|
|
817
|
+
return validatePipelineString(pipelineString);
|
|
818
|
+
}
|
|
705
819
|
/**
|
|
706
|
-
*
|
|
707
|
-
*
|
|
708
|
-
* @private within the repository
|
|
820
|
+
* @private internal utility of `pipelineJsonToString`
|
|
709
821
|
*/
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
822
|
+
function taskParameterJsonToString(taskParameterJson) {
|
|
823
|
+
const { name, description } = taskParameterJson;
|
|
824
|
+
let parameterString = `{${name}}`;
|
|
825
|
+
if (description) {
|
|
826
|
+
parameterString = `${parameterString} ${description}`;
|
|
827
|
+
}
|
|
828
|
+
return parameterString;
|
|
829
|
+
}
|
|
714
830
|
/**
|
|
715
|
-
*
|
|
716
|
-
* TODO: [๐ง ]
|
|
831
|
+
* TODO: [๐] Implement new features and commands into `pipelineJsonToString` + `taskParameterJsonToString` , use `stringifyCommand`
|
|
832
|
+
* TODO: [๐ง ] Is there a way to auto-detect missing features in pipelineJsonToString
|
|
833
|
+
* TODO: [๐] Maybe make some markdown builder
|
|
834
|
+
* TODO: [๐] Escape all
|
|
835
|
+
* TODO: [๐ง ] Should be in generated .book.md file GENERATOR_WARNING
|
|
717
836
|
*/
|
|
718
837
|
|
|
719
838
|
/**
|
|
@@ -758,74 +877,6 @@ function $deepFreeze(objectValue) {
|
|
|
758
877
|
* TODO: [๐ง ] Is there a way how to meaningfully test this utility
|
|
759
878
|
*/
|
|
760
879
|
|
|
761
|
-
/**
|
|
762
|
-
* Make error report URL for the given error
|
|
763
|
-
*
|
|
764
|
-
* @private private within the repository
|
|
765
|
-
*/
|
|
766
|
-
function getErrorReportUrl(error) {
|
|
767
|
-
const report = {
|
|
768
|
-
title: `๐ Error report from ${NAME}`,
|
|
769
|
-
body: spaceTrim((block) => `
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
773
|
-
|
|
774
|
-
\`\`\`
|
|
775
|
-
${block(error.message || '(no error message)')}
|
|
776
|
-
\`\`\`
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
## More info:
|
|
780
|
-
|
|
781
|
-
- **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
|
|
782
|
-
- **Book language version:** ${BOOK_LANGUAGE_VERSION}
|
|
783
|
-
- **Time:** ${new Date().toISOString()}
|
|
784
|
-
|
|
785
|
-
<details>
|
|
786
|
-
<summary>Stack trace:</summary>
|
|
787
|
-
|
|
788
|
-
## Stack trace:
|
|
789
|
-
|
|
790
|
-
\`\`\`stacktrace
|
|
791
|
-
${block(error.stack || '(empty)')}
|
|
792
|
-
\`\`\`
|
|
793
|
-
</details>
|
|
794
|
-
|
|
795
|
-
`),
|
|
796
|
-
};
|
|
797
|
-
const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
|
|
798
|
-
reportUrl.searchParams.set('labels', 'bug');
|
|
799
|
-
reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
|
|
800
|
-
reportUrl.searchParams.set('title', report.title);
|
|
801
|
-
reportUrl.searchParams.set('body', report.body);
|
|
802
|
-
return reportUrl;
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
/**
|
|
806
|
-
* This error type indicates that the error should not happen and its last check before crashing with some other error
|
|
807
|
-
*
|
|
808
|
-
* @public exported from `@promptbook/core`
|
|
809
|
-
*/
|
|
810
|
-
class UnexpectedError extends Error {
|
|
811
|
-
constructor(message) {
|
|
812
|
-
super(spaceTrim$1((block) => `
|
|
813
|
-
${block(message)}
|
|
814
|
-
|
|
815
|
-
Note: This error should not happen.
|
|
816
|
-
It's probbably a bug in the pipeline collection
|
|
817
|
-
|
|
818
|
-
Please report issue:
|
|
819
|
-
${block(getErrorReportUrl(new Error(message)).href)}
|
|
820
|
-
|
|
821
|
-
Or contact us on ${ADMIN_EMAIL}
|
|
822
|
-
|
|
823
|
-
`));
|
|
824
|
-
this.name = 'UnexpectedError';
|
|
825
|
-
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
|
|
829
880
|
/**
|
|
830
881
|
* Checks if the value is [๐] serializable as JSON
|
|
831
882
|
* If not, throws an UnexpectedError with a rich error message and tracking
|
|
@@ -917,9 +968,7 @@ function checkSerializableAsJson(options) {
|
|
|
917
968
|
JSON.stringify(value); // <- TODO: [0]
|
|
918
969
|
}
|
|
919
970
|
catch (error) {
|
|
920
|
-
|
|
921
|
-
throw error;
|
|
922
|
-
}
|
|
971
|
+
assertsError(error);
|
|
923
972
|
throw new UnexpectedError(spaceTrim((block) => `
|
|
924
973
|
\`${name}\` is not serializable
|
|
925
974
|
|
|
@@ -1708,7 +1757,7 @@ class PipelineExecutionError extends Error {
|
|
|
1708
1757
|
}
|
|
1709
1758
|
}
|
|
1710
1759
|
/**
|
|
1711
|
-
* TODO:
|
|
1760
|
+
* TODO: [๐ง ][๐] Add id to all errors
|
|
1712
1761
|
*/
|
|
1713
1762
|
|
|
1714
1763
|
/**
|
|
@@ -1945,7 +1994,10 @@ const PROMPTBOOK_ERRORS = {
|
|
|
1945
1994
|
PipelineExecutionError,
|
|
1946
1995
|
PipelineLogicError,
|
|
1947
1996
|
PipelineUrlError,
|
|
1997
|
+
AuthenticationError,
|
|
1998
|
+
PromptbookFetchError,
|
|
1948
1999
|
UnexpectedError,
|
|
2000
|
+
WrappedError,
|
|
1949
2001
|
// TODO: [๐ช]> VersionMismatchError,
|
|
1950
2002
|
};
|
|
1951
2003
|
/**
|
|
@@ -1962,8 +2014,6 @@ const COMMON_JAVASCRIPT_ERRORS = {
|
|
|
1962
2014
|
TypeError,
|
|
1963
2015
|
URIError,
|
|
1964
2016
|
AggregateError,
|
|
1965
|
-
AuthenticationError,
|
|
1966
|
-
PromptbookFetchError,
|
|
1967
2017
|
/*
|
|
1968
2018
|
Note: Not widely supported
|
|
1969
2019
|
> InternalError,
|
|
@@ -2086,8 +2136,8 @@ function createTask(options) {
|
|
|
2086
2136
|
updatedAt = new Date();
|
|
2087
2137
|
errors.push(...executionResult.errors);
|
|
2088
2138
|
warnings.push(...executionResult.warnings);
|
|
2089
|
-
// <- TODO:
|
|
2090
|
-
// TODO: [๐ง ]
|
|
2139
|
+
// <- TODO: [๐] Only unique errors and warnings should be added (or filtered)
|
|
2140
|
+
// TODO: [๐ง ] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
|
|
2091
2141
|
// Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
|
|
2092
2142
|
// And delete `ExecutionTask.currentValue.preparedPipeline`
|
|
2093
2143
|
assertsTaskSuccessful(executionResult);
|
|
@@ -2097,6 +2147,7 @@ function createTask(options) {
|
|
|
2097
2147
|
partialResultSubject.next(executionResult);
|
|
2098
2148
|
}
|
|
2099
2149
|
catch (error) {
|
|
2150
|
+
assertsError(error);
|
|
2100
2151
|
status = 'ERROR';
|
|
2101
2152
|
errors.push(error);
|
|
2102
2153
|
partialResultSubject.error(error);
|
|
@@ -2488,14 +2539,15 @@ class MultipleLlmExecutionTools {
|
|
|
2488
2539
|
}
|
|
2489
2540
|
}
|
|
2490
2541
|
catch (error) {
|
|
2491
|
-
|
|
2542
|
+
assertsError(error);
|
|
2543
|
+
if (error instanceof UnexpectedError) {
|
|
2492
2544
|
throw error;
|
|
2493
2545
|
}
|
|
2494
2546
|
errors.push({ llmExecutionTools, error });
|
|
2495
2547
|
}
|
|
2496
2548
|
}
|
|
2497
2549
|
if (errors.length === 1) {
|
|
2498
|
-
throw errors[0];
|
|
2550
|
+
throw errors[0].error;
|
|
2499
2551
|
}
|
|
2500
2552
|
else if (errors.length > 1) {
|
|
2501
2553
|
throw new PipelineExecutionError(
|
|
@@ -3336,9 +3388,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
|
|
|
3336
3388
|
return await fetch(urlOrRequest, init);
|
|
3337
3389
|
}
|
|
3338
3390
|
catch (error) {
|
|
3339
|
-
|
|
3340
|
-
throw error;
|
|
3341
|
-
}
|
|
3391
|
+
assertsError(error);
|
|
3342
3392
|
let url;
|
|
3343
3393
|
if (typeof urlOrRequest === 'string') {
|
|
3344
3394
|
url = urlOrRequest;
|
|
@@ -3569,9 +3619,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
|
|
|
3569
3619
|
knowledgePreparedUnflatten[index] = pieces;
|
|
3570
3620
|
}
|
|
3571
3621
|
catch (error) {
|
|
3572
|
-
|
|
3573
|
-
throw error;
|
|
3574
|
-
}
|
|
3622
|
+
assertsError(error);
|
|
3575
3623
|
console.warn(error);
|
|
3576
3624
|
// <- TODO: [๐ฎ] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
3577
3625
|
}
|
|
@@ -3863,13 +3911,19 @@ function valueToString(value) {
|
|
|
3863
3911
|
return value.toISOString();
|
|
3864
3912
|
}
|
|
3865
3913
|
else {
|
|
3866
|
-
|
|
3914
|
+
try {
|
|
3915
|
+
return JSON.stringify(value);
|
|
3916
|
+
}
|
|
3917
|
+
catch (error) {
|
|
3918
|
+
if (error instanceof TypeError && error.message.includes('circular structure')) {
|
|
3919
|
+
return VALUE_STRINGS.circular;
|
|
3920
|
+
}
|
|
3921
|
+
throw error;
|
|
3922
|
+
}
|
|
3867
3923
|
}
|
|
3868
3924
|
}
|
|
3869
3925
|
catch (error) {
|
|
3870
|
-
|
|
3871
|
-
throw error;
|
|
3872
|
-
}
|
|
3926
|
+
assertsError(error);
|
|
3873
3927
|
console.error(error);
|
|
3874
3928
|
return VALUE_STRINGS.unserializable;
|
|
3875
3929
|
}
|
|
@@ -3926,9 +3980,7 @@ function extractVariablesFromJavascript(script) {
|
|
|
3926
3980
|
}
|
|
3927
3981
|
}
|
|
3928
3982
|
catch (error) {
|
|
3929
|
-
|
|
3930
|
-
throw error;
|
|
3931
|
-
}
|
|
3983
|
+
assertsError(error);
|
|
3932
3984
|
throw new ParseError(spaceTrim$1((block) => `
|
|
3933
3985
|
Can not extract variables from the script
|
|
3934
3986
|
${block(error.stack || error.message)}
|
|
@@ -4047,6 +4099,28 @@ const MANDATORY_CSV_SETTINGS = Object.freeze({
|
|
|
4047
4099
|
// encoding: 'utf-8',
|
|
4048
4100
|
});
|
|
4049
4101
|
|
|
4102
|
+
/**
|
|
4103
|
+
* Function to check if a string is valid CSV
|
|
4104
|
+
*
|
|
4105
|
+
* @param value The string to check
|
|
4106
|
+
* @returns True if the string is a valid CSV string, false otherwise
|
|
4107
|
+
*
|
|
4108
|
+
* @public exported from `@promptbook/utils`
|
|
4109
|
+
*/
|
|
4110
|
+
function isValidCsvString(value) {
|
|
4111
|
+
try {
|
|
4112
|
+
// A simple check for CSV format: at least one comma and no invalid characters
|
|
4113
|
+
if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
|
|
4114
|
+
return true;
|
|
4115
|
+
}
|
|
4116
|
+
return false;
|
|
4117
|
+
}
|
|
4118
|
+
catch (error) {
|
|
4119
|
+
assertsError(error);
|
|
4120
|
+
return false;
|
|
4121
|
+
}
|
|
4122
|
+
}
|
|
4123
|
+
|
|
4050
4124
|
/**
|
|
4051
4125
|
* Definition for CSV spreadsheet
|
|
4052
4126
|
*
|
|
@@ -4057,7 +4131,7 @@ const CsvFormatDefinition = {
|
|
|
4057
4131
|
formatName: 'CSV',
|
|
4058
4132
|
aliases: ['SPREADSHEET', 'TABLE'],
|
|
4059
4133
|
isValid(value, settings, schema) {
|
|
4060
|
-
return
|
|
4134
|
+
return isValidCsvString(value);
|
|
4061
4135
|
},
|
|
4062
4136
|
canBeValid(partialValue, settings, schema) {
|
|
4063
4137
|
return true;
|
|
@@ -4211,6 +4285,30 @@ const TextFormatDefinition = {
|
|
|
4211
4285
|
* TODO: [๐ข] Allow to expect something inside each item of list and other formats
|
|
4212
4286
|
*/
|
|
4213
4287
|
|
|
4288
|
+
/**
|
|
4289
|
+
* Function to check if a string is valid XML
|
|
4290
|
+
*
|
|
4291
|
+
* @param value
|
|
4292
|
+
* @returns True if the string is a valid XML string, false otherwise
|
|
4293
|
+
*
|
|
4294
|
+
* @public exported from `@promptbook/utils`
|
|
4295
|
+
*/
|
|
4296
|
+
function isValidXmlString(value) {
|
|
4297
|
+
try {
|
|
4298
|
+
const parser = new DOMParser();
|
|
4299
|
+
const parsedDocument = parser.parseFromString(value, 'application/xml');
|
|
4300
|
+
const parserError = parsedDocument.getElementsByTagName('parsererror');
|
|
4301
|
+
if (parserError.length > 0) {
|
|
4302
|
+
return false;
|
|
4303
|
+
}
|
|
4304
|
+
return true;
|
|
4305
|
+
}
|
|
4306
|
+
catch (error) {
|
|
4307
|
+
assertsError(error);
|
|
4308
|
+
return false;
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
|
|
4214
4312
|
/**
|
|
4215
4313
|
* Definition for XML format
|
|
4216
4314
|
*
|
|
@@ -4220,7 +4318,7 @@ const XmlFormatDefinition = {
|
|
|
4220
4318
|
formatName: 'XML',
|
|
4221
4319
|
mimeType: 'application/xml',
|
|
4222
4320
|
isValid(value, settings, schema) {
|
|
4223
|
-
return
|
|
4321
|
+
return isValidXmlString(value);
|
|
4224
4322
|
},
|
|
4225
4323
|
canBeValid(partialValue, settings, schema) {
|
|
4226
4324
|
return true;
|
|
@@ -4691,9 +4789,7 @@ async function executeAttempts(options) {
|
|
|
4691
4789
|
break scripts;
|
|
4692
4790
|
}
|
|
4693
4791
|
catch (error) {
|
|
4694
|
-
|
|
4695
|
-
throw error;
|
|
4696
|
-
}
|
|
4792
|
+
assertsError(error);
|
|
4697
4793
|
if (error instanceof UnexpectedError) {
|
|
4698
4794
|
throw error;
|
|
4699
4795
|
}
|
|
@@ -4763,9 +4859,7 @@ async function executeAttempts(options) {
|
|
|
4763
4859
|
break scripts;
|
|
4764
4860
|
}
|
|
4765
4861
|
catch (error) {
|
|
4766
|
-
|
|
4767
|
-
throw error;
|
|
4768
|
-
}
|
|
4862
|
+
assertsError(error);
|
|
4769
4863
|
if (error instanceof UnexpectedError) {
|
|
4770
4864
|
throw error;
|
|
4771
4865
|
}
|
|
@@ -5386,9 +5480,7 @@ async function executePipeline(options) {
|
|
|
5386
5480
|
await Promise.all(resolving);
|
|
5387
5481
|
}
|
|
5388
5482
|
catch (error /* <- Note: [3] */) {
|
|
5389
|
-
|
|
5390
|
-
throw error;
|
|
5391
|
-
}
|
|
5483
|
+
assertsError(error);
|
|
5392
5484
|
// Note: No need to rethrow UnexpectedError
|
|
5393
5485
|
// if (error instanceof UnexpectedError) {
|
|
5394
5486
|
// Note: Count usage, [๐ง ] Maybe put to separate function executionReportJsonToUsage + DRY [๐คนโโ๏ธ]
|