@promptbook/cli 0.100.0-45 → 0.100.0-47
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/esm/index.es.js +204 -107
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/components.index.d.ts +4 -0
- package/esm/typings/src/_packages/core.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +2 -6
- package/esm/typings/src/book-2.0/commitments/_misc/AgentModelRequirements.d.ts +1 -1
- package/esm/typings/src/book-components/Chat/Chat/Chat.d.ts +4 -10
- package/esm/typings/src/book-components/Chat/interfaces/ChatMessage.d.ts +12 -26
- package/esm/typings/src/book-components/Chat/interfaces/ChatParticipant.d.ts +30 -0
- package/esm/typings/src/book-components/Chat/utils/exportChatHistory.d.ts +2 -4
- package/esm/typings/src/book-components/Chat/utils/generatePdfContent.d.ts +2 -4
- package/esm/typings/src/book-components/Chat/utils/messagesToHtml.d.ts +2 -4
- package/esm/typings/src/book-components/Chat/utils/messagesToMarkdown.d.ts +2 -4
- package/esm/typings/src/book-components/Chat/utils/messagesToText.d.ts +2 -4
- package/esm/typings/src/config.d.ts +7 -0
- package/esm/typings/src/execution/ExecutionTask.d.ts +8 -0
- package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +8 -0
- package/esm/typings/src/playground/permanent/error-handling-playground.d.ts +5 -0
- package/esm/typings/src/utils/organization/preserve.d.ts +21 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -2
- package/umd/index.umd.js +208 -111
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/scripting/javascript/utils/preserve.d.ts +0 -14
package/esm/index.es.js
CHANGED
|
@@ -13,8 +13,9 @@ import { io } from 'socket.io-client';
|
|
|
13
13
|
import { Subject } from 'rxjs';
|
|
14
14
|
import { spawn } from 'child_process';
|
|
15
15
|
import JSZip from 'jszip';
|
|
16
|
-
import { format } from 'prettier';
|
|
17
16
|
import parserHtml from 'prettier/parser-html';
|
|
17
|
+
import parserMarkdown from 'prettier/parser-markdown';
|
|
18
|
+
import { format } from 'prettier/standalone';
|
|
18
19
|
import { parse, unparse } from 'papaparse';
|
|
19
20
|
import { SHA256 } from 'crypto-js';
|
|
20
21
|
import { lookup, extension } from 'mime-types';
|
|
@@ -47,7 +48,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
|
|
|
47
48
|
* @generated
|
|
48
49
|
* @see https://github.com/webgptorg/promptbook
|
|
49
50
|
*/
|
|
50
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.100.0-
|
|
51
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.100.0-47';
|
|
51
52
|
/**
|
|
52
53
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
53
54
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -376,6 +377,13 @@ const DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME = `getPipelineCollection`;
|
|
|
376
377
|
* @public exported from `@promptbook/core`
|
|
377
378
|
*/
|
|
378
379
|
const DEFAULT_MAX_REQUESTS_PER_MINUTE = 60;
|
|
380
|
+
/**
|
|
381
|
+
* API request timeout in milliseconds
|
|
382
|
+
* Can be overridden via API_REQUEST_TIMEOUT environment variable
|
|
383
|
+
*
|
|
384
|
+
* @public exported from `@promptbook/core`
|
|
385
|
+
*/
|
|
386
|
+
const API_REQUEST_TIMEOUT = parseInt(process.env.API_REQUEST_TIMEOUT || '90000');
|
|
379
387
|
/**
|
|
380
388
|
* Indicates whether pipeline logic validation is enabled. When true, the pipeline logic is checked for consistency.
|
|
381
389
|
*
|
|
@@ -5131,7 +5139,7 @@ function prettifyMarkdown(content) {
|
|
|
5131
5139
|
try {
|
|
5132
5140
|
return format(content, {
|
|
5133
5141
|
parser: 'markdown',
|
|
5134
|
-
plugins: [parserHtml],
|
|
5142
|
+
plugins: [parserMarkdown, parserHtml],
|
|
5135
5143
|
// TODO: DRY - make some import or auto-copy of .prettierrc
|
|
5136
5144
|
endOfLine: 'lf',
|
|
5137
5145
|
tabWidth: 4,
|
|
@@ -7596,64 +7604,74 @@ function createPipelineExecutor(options) {
|
|
|
7596
7604
|
});
|
|
7597
7605
|
});
|
|
7598
7606
|
};
|
|
7599
|
-
const pipelineExecutor = (inputParameters) =>
|
|
7600
|
-
|
|
7601
|
-
|
|
7602
|
-
|
|
7603
|
-
|
|
7604
|
-
|
|
7605
|
-
|
|
7606
|
-
|
|
7607
|
-
|
|
7608
|
-
|
|
7609
|
-
|
|
7610
|
-
|
|
7611
|
-
|
|
7612
|
-
|
|
7613
|
-
|
|
7614
|
-
|
|
7615
|
-
|
|
7616
|
-
|
|
7617
|
-
|
|
7618
|
-
// Find current task being executed (first task not yet completed)
|
|
7619
|
-
const remainingTasks = pipeline.tasks.filter((task) => !executedTaskTitles.has(task.title));
|
|
7620
|
-
if (remainingTasks.length > 0) {
|
|
7621
|
-
currentTaskName = remainingTasks[0].name;
|
|
7607
|
+
const pipelineExecutor = (inputParameters) => {
|
|
7608
|
+
const startTime = new Date().getTime();
|
|
7609
|
+
return createTask({
|
|
7610
|
+
taskType: 'EXECUTION',
|
|
7611
|
+
title: pipeline.title,
|
|
7612
|
+
taskProcessCallback(updateOngoingResult, updateTldr) {
|
|
7613
|
+
return pipelineExecutorWithCallback(inputParameters, async (newOngoingResult) => {
|
|
7614
|
+
var _a, _b;
|
|
7615
|
+
updateOngoingResult(newOngoingResult);
|
|
7616
|
+
// Calculate and update tldr based on pipeline progress
|
|
7617
|
+
const cv = newOngoingResult;
|
|
7618
|
+
// Calculate progress based on parameters resolved vs total parameters
|
|
7619
|
+
const totalParameters = pipeline.parameters.filter(p => !p.isInput).length;
|
|
7620
|
+
let resolvedParameters = 0;
|
|
7621
|
+
let currentTaskTitle = '';
|
|
7622
|
+
// Get the resolved parameters from output parameters
|
|
7623
|
+
if (cv === null || cv === void 0 ? void 0 : cv.outputParameters) {
|
|
7624
|
+
// Count how many output parameters have non-empty values
|
|
7625
|
+
resolvedParameters = Object.values(cv.outputParameters).filter(value => value !== undefined && value !== null && String(value).trim() !== '').length;
|
|
7622
7626
|
}
|
|
7623
|
-
|
|
7624
|
-
|
|
7625
|
-
|
|
7626
|
-
|
|
7627
|
-
|
|
7628
|
-
|
|
7629
|
-
|
|
7630
|
-
|
|
7631
|
-
|
|
7632
|
-
|
|
7633
|
-
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
7641
|
-
|
|
7642
|
-
|
|
7643
|
-
|
|
7644
|
-
|
|
7645
|
-
|
|
7646
|
-
|
|
7647
|
-
|
|
7648
|
-
|
|
7649
|
-
|
|
7650
|
-
|
|
7651
|
-
|
|
7652
|
-
|
|
7627
|
+
// Try to determine current task from execution report
|
|
7628
|
+
if (((_a = cv === null || cv === void 0 ? void 0 : cv.executionReport) === null || _a === void 0 ? void 0 : _a.promptExecutions) && cv.executionReport.promptExecutions.length > 0) {
|
|
7629
|
+
const lastExecution = cv.executionReport.promptExecutions[cv.executionReport.promptExecutions.length - 1];
|
|
7630
|
+
if ((_b = lastExecution === null || lastExecution === void 0 ? void 0 : lastExecution.prompt) === null || _b === void 0 ? void 0 : _b.title) {
|
|
7631
|
+
currentTaskTitle = lastExecution.prompt.title;
|
|
7632
|
+
}
|
|
7633
|
+
}
|
|
7634
|
+
// Calculate base progress percentage
|
|
7635
|
+
let percent = totalParameters > 0 ? resolvedParameters / totalParameters : 0;
|
|
7636
|
+
// Add time-based progress for current task if we haven't completed all parameters
|
|
7637
|
+
if (resolvedParameters < totalParameters) {
|
|
7638
|
+
const elapsedMs = new Date().getTime() - startTime;
|
|
7639
|
+
const estimatedTotalMs = totalParameters * 30 * 1000; // Estimate 30 seconds per parameter
|
|
7640
|
+
const timeProgress = Math.min(elapsedMs / estimatedTotalMs, 0.9); // Cap at 90% for time-based progress
|
|
7641
|
+
// If we have time progress but no parameter progress, show time progress
|
|
7642
|
+
if (percent === 0 && timeProgress > 0) {
|
|
7643
|
+
percent = Math.min(timeProgress, 0.1); // Show some progress but not more than 10%
|
|
7644
|
+
}
|
|
7645
|
+
else if (percent < 1) {
|
|
7646
|
+
// Add partial progress for current task
|
|
7647
|
+
const taskProgress = totalParameters > 0 ? (1 / totalParameters) * 0.5 : 0; // 50% of task progress
|
|
7648
|
+
percent = Math.min(percent + taskProgress, 0.95); // Cap at 95% until fully complete
|
|
7649
|
+
}
|
|
7650
|
+
}
|
|
7651
|
+
// Clamp to [0,1]
|
|
7652
|
+
percent = Math.min(Math.max(percent, 0), 1);
|
|
7653
|
+
// Generate message
|
|
7654
|
+
let message = '';
|
|
7655
|
+
if (currentTaskTitle) {
|
|
7656
|
+
message = `Executing: ${currentTaskTitle}`;
|
|
7657
|
+
}
|
|
7658
|
+
else if (resolvedParameters === 0) {
|
|
7659
|
+
message = 'Starting pipeline execution';
|
|
7660
|
+
}
|
|
7661
|
+
else if (resolvedParameters < totalParameters) {
|
|
7662
|
+
message = `Processing pipeline (${resolvedParameters}/${totalParameters} parameters resolved)`;
|
|
7663
|
+
}
|
|
7664
|
+
else {
|
|
7665
|
+
message = 'Completing pipeline execution';
|
|
7666
|
+
}
|
|
7667
|
+
updateTldr({
|
|
7668
|
+
percent: percent,
|
|
7669
|
+
message,
|
|
7670
|
+
});
|
|
7653
7671
|
});
|
|
7654
|
-
}
|
|
7655
|
-
}
|
|
7656
|
-
}
|
|
7672
|
+
},
|
|
7673
|
+
});
|
|
7674
|
+
};
|
|
7657
7675
|
// <- TODO: Make types such as there is no need to do `as` for `createTask`
|
|
7658
7676
|
return pipelineExecutor;
|
|
7659
7677
|
}
|
|
@@ -7716,7 +7734,7 @@ async function preparePersona(personaDescription, tools, options) {
|
|
|
7716
7734
|
const result = await preparePersonaExecutor({
|
|
7717
7735
|
availableModels /* <- Note: Passing as JSON */,
|
|
7718
7736
|
personaDescription,
|
|
7719
|
-
}).asPromise();
|
|
7737
|
+
}).asPromise({ isCrashedOnError: true });
|
|
7720
7738
|
const { outputParameters } = result;
|
|
7721
7739
|
const { modelsRequirements: modelsRequirementsJson } = outputParameters;
|
|
7722
7740
|
let modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
|
|
@@ -8209,7 +8227,7 @@ async function preparePipeline(pipeline, tools, options) {
|
|
|
8209
8227
|
});
|
|
8210
8228
|
const result = await prepareTitleExecutor({
|
|
8211
8229
|
book: sources.map(({ content }) => content).join('\n\n'),
|
|
8212
|
-
}).asPromise();
|
|
8230
|
+
}).asPromise({ isCrashedOnError: true });
|
|
8213
8231
|
const { outputParameters } = result;
|
|
8214
8232
|
const { title: titleRaw } = outputParameters;
|
|
8215
8233
|
if (isVerbose) {
|
|
@@ -12124,31 +12142,23 @@ function extractBlock(markdown) {
|
|
|
12124
12142
|
return content;
|
|
12125
12143
|
}
|
|
12126
12144
|
|
|
12145
|
+
/**
|
|
12146
|
+
* @private internal for `preserve`
|
|
12147
|
+
*/
|
|
12148
|
+
const _preserved = [];
|
|
12127
12149
|
/**
|
|
12128
12150
|
* Does nothing, but preserves the function in the bundle
|
|
12129
12151
|
* Compiler is tricked into thinking the function is used
|
|
12130
12152
|
*
|
|
12131
12153
|
* @param value any function to preserve
|
|
12132
12154
|
* @returns nothing
|
|
12133
|
-
* @private
|
|
12134
|
-
*/
|
|
12135
|
-
function preserve(
|
|
12136
|
-
|
|
12137
|
-
(async () => {
|
|
12138
|
-
// TODO: [💩] Change to `await forEver` or `forTime(Infinity)`
|
|
12139
|
-
await forTime(100000000);
|
|
12140
|
-
// [1]
|
|
12141
|
-
try {
|
|
12142
|
-
await func();
|
|
12143
|
-
}
|
|
12144
|
-
finally {
|
|
12145
|
-
// do nothing
|
|
12146
|
-
}
|
|
12147
|
-
})();
|
|
12155
|
+
* @private within the repository
|
|
12156
|
+
*/
|
|
12157
|
+
function $preserve(...value) {
|
|
12158
|
+
_preserved.push(...value);
|
|
12148
12159
|
}
|
|
12149
12160
|
/**
|
|
12150
|
-
*
|
|
12151
|
-
* TODO: [1] This maybe does memory leak
|
|
12161
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
12152
12162
|
*/
|
|
12153
12163
|
|
|
12154
12164
|
// Note: [💎]
|
|
@@ -12176,25 +12186,25 @@ class JavascriptEvalExecutionTools {
|
|
|
12176
12186
|
// Note: [💎]
|
|
12177
12187
|
// Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
|
|
12178
12188
|
const spaceTrim$1 = (_) => spaceTrim(_);
|
|
12179
|
-
preserve(spaceTrim$1);
|
|
12189
|
+
$preserve(spaceTrim$1);
|
|
12180
12190
|
const removeQuotes$1 = removeQuotes;
|
|
12181
|
-
preserve(removeQuotes$1);
|
|
12191
|
+
$preserve(removeQuotes$1);
|
|
12182
12192
|
const unwrapResult$1 = unwrapResult;
|
|
12183
|
-
preserve(unwrapResult$1);
|
|
12193
|
+
$preserve(unwrapResult$1);
|
|
12184
12194
|
const trimEndOfCodeBlock$1 = trimEndOfCodeBlock;
|
|
12185
|
-
preserve(trimEndOfCodeBlock$1);
|
|
12195
|
+
$preserve(trimEndOfCodeBlock$1);
|
|
12186
12196
|
const trimCodeBlock$1 = trimCodeBlock;
|
|
12187
|
-
preserve(trimCodeBlock$1);
|
|
12197
|
+
$preserve(trimCodeBlock$1);
|
|
12188
12198
|
// TODO: DRY [🍯]
|
|
12189
12199
|
const trim = (str) => str.trim();
|
|
12190
|
-
preserve(trim);
|
|
12200
|
+
$preserve(trim);
|
|
12191
12201
|
// TODO: DRY [🍯]
|
|
12192
12202
|
const reverse = (str) => str.split('').reverse().join('');
|
|
12193
|
-
preserve(reverse);
|
|
12203
|
+
$preserve(reverse);
|
|
12194
12204
|
const removeEmojis$1 = removeEmojis;
|
|
12195
|
-
preserve(removeEmojis$1);
|
|
12205
|
+
$preserve(removeEmojis$1);
|
|
12196
12206
|
const prettifyMarkdown$1 = prettifyMarkdown;
|
|
12197
|
-
preserve(prettifyMarkdown$1);
|
|
12207
|
+
$preserve(prettifyMarkdown$1);
|
|
12198
12208
|
//-------[n12:]---
|
|
12199
12209
|
const capitalize$1 = capitalize;
|
|
12200
12210
|
const decapitalize$1 = decapitalize;
|
|
@@ -12210,18 +12220,18 @@ class JavascriptEvalExecutionTools {
|
|
|
12210
12220
|
// TODO: DRY [🍯]
|
|
12211
12221
|
Array.from(parseKeywordsFromString(input)).join(', '); /* <- TODO: [🧠] What is the best format comma list, bullet list,...? */
|
|
12212
12222
|
const normalizeTo_SCREAMING_CASE$1 = normalizeTo_SCREAMING_CASE;
|
|
12213
|
-
preserve(capitalize$1);
|
|
12214
|
-
preserve(decapitalize$1);
|
|
12215
|
-
preserve(nameToUriPart$1);
|
|
12216
|
-
preserve(nameToUriParts$1);
|
|
12217
|
-
preserve(removeDiacritics$1);
|
|
12218
|
-
preserve(normalizeWhitespaces$1);
|
|
12219
|
-
preserve(normalizeToKebabCase$1);
|
|
12220
|
-
preserve(normalizeTo_camelCase$1);
|
|
12221
|
-
preserve(normalizeTo_snake_case$1);
|
|
12222
|
-
preserve(normalizeTo_PascalCase$1);
|
|
12223
|
-
preserve(parseKeywords);
|
|
12224
|
-
preserve(normalizeTo_SCREAMING_CASE$1);
|
|
12223
|
+
$preserve(capitalize$1);
|
|
12224
|
+
$preserve(decapitalize$1);
|
|
12225
|
+
$preserve(nameToUriPart$1);
|
|
12226
|
+
$preserve(nameToUriParts$1);
|
|
12227
|
+
$preserve(removeDiacritics$1);
|
|
12228
|
+
$preserve(normalizeWhitespaces$1);
|
|
12229
|
+
$preserve(normalizeToKebabCase$1);
|
|
12230
|
+
$preserve(normalizeTo_camelCase$1);
|
|
12231
|
+
$preserve(normalizeTo_snake_case$1);
|
|
12232
|
+
$preserve(normalizeTo_PascalCase$1);
|
|
12233
|
+
$preserve(parseKeywords);
|
|
12234
|
+
$preserve(normalizeTo_SCREAMING_CASE$1);
|
|
12225
12235
|
//-------[/n12]---
|
|
12226
12236
|
if (!script.includes('return')) {
|
|
12227
12237
|
script = `return ${script}`;
|
|
@@ -13722,7 +13732,7 @@ async function runInteractiveChatbot(options) {
|
|
|
13722
13732
|
previousConversationSummary: conversationSummary,
|
|
13723
13733
|
userMessage,
|
|
13724
13734
|
};
|
|
13725
|
-
const result = await pipelineExecutor(inputParameters).asPromise();
|
|
13735
|
+
const result = await pipelineExecutor(inputParameters).asPromise({ isCrashedOnError: true });
|
|
13726
13736
|
console.info(`\n`);
|
|
13727
13737
|
console.info(spaceTrim((block) => `
|
|
13728
13738
|
|
|
@@ -17817,7 +17827,18 @@ class OpenAiCompatibleExecutionTools {
|
|
|
17817
17827
|
const openAiOptions = { ...this.options };
|
|
17818
17828
|
delete openAiOptions.isVerbose;
|
|
17819
17829
|
delete openAiOptions.userId;
|
|
17820
|
-
|
|
17830
|
+
// Enhanced configuration for better ECONNRESET handling
|
|
17831
|
+
const enhancedOptions = {
|
|
17832
|
+
...openAiOptions,
|
|
17833
|
+
timeout: API_REQUEST_TIMEOUT,
|
|
17834
|
+
maxRetries: CONNECTION_RETRIES_LIMIT,
|
|
17835
|
+
defaultHeaders: {
|
|
17836
|
+
Connection: 'keep-alive',
|
|
17837
|
+
'Keep-Alive': 'timeout=30, max=100',
|
|
17838
|
+
...openAiOptions.defaultHeaders,
|
|
17839
|
+
},
|
|
17840
|
+
};
|
|
17841
|
+
this.client = new OpenAI(enhancedOptions);
|
|
17821
17842
|
}
|
|
17822
17843
|
return this.client;
|
|
17823
17844
|
}
|
|
@@ -17905,7 +17926,7 @@ class OpenAiCompatibleExecutionTools {
|
|
|
17905
17926
|
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
17906
17927
|
}
|
|
17907
17928
|
const rawResponse = await this.limiter
|
|
17908
|
-
.schedule(() => client.chat.completions.create(rawRequest))
|
|
17929
|
+
.schedule(() => this.makeRequestWithRetry(() => client.chat.completions.create(rawRequest)))
|
|
17909
17930
|
.catch((error) => {
|
|
17910
17931
|
assertsError(error);
|
|
17911
17932
|
if (this.options.isVerbose) {
|
|
@@ -17981,7 +18002,7 @@ class OpenAiCompatibleExecutionTools {
|
|
|
17981
18002
|
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
17982
18003
|
}
|
|
17983
18004
|
const rawResponse = await this.limiter
|
|
17984
|
-
.schedule(() => client.completions.create(rawRequest))
|
|
18005
|
+
.schedule(() => this.makeRequestWithRetry(() => client.completions.create(rawRequest)))
|
|
17985
18006
|
.catch((error) => {
|
|
17986
18007
|
assertsError(error);
|
|
17987
18008
|
if (this.options.isVerbose) {
|
|
@@ -18045,7 +18066,7 @@ class OpenAiCompatibleExecutionTools {
|
|
|
18045
18066
|
console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
18046
18067
|
}
|
|
18047
18068
|
const rawResponse = await this.limiter
|
|
18048
|
-
.schedule(() => client.embeddings.create(rawRequest))
|
|
18069
|
+
.schedule(() => this.makeRequestWithRetry(() => client.embeddings.create(rawRequest)))
|
|
18049
18070
|
.catch((error) => {
|
|
18050
18071
|
assertsError(error);
|
|
18051
18072
|
if (this.options.isVerbose) {
|
|
@@ -18103,6 +18124,76 @@ class OpenAiCompatibleExecutionTools {
|
|
|
18103
18124
|
}
|
|
18104
18125
|
return model;
|
|
18105
18126
|
}
|
|
18127
|
+
// <- Note: [🤖] getDefaultXxxModel
|
|
18128
|
+
/**
|
|
18129
|
+
* Makes a request with retry logic for network errors like ECONNRESET
|
|
18130
|
+
*/
|
|
18131
|
+
async makeRequestWithRetry(requestFn) {
|
|
18132
|
+
let lastError;
|
|
18133
|
+
for (let attempt = 1; attempt <= CONNECTION_RETRIES_LIMIT; attempt++) {
|
|
18134
|
+
try {
|
|
18135
|
+
return await requestFn();
|
|
18136
|
+
}
|
|
18137
|
+
catch (error) {
|
|
18138
|
+
assertsError(error);
|
|
18139
|
+
lastError = error;
|
|
18140
|
+
// Check if this is a retryable network error
|
|
18141
|
+
const isRetryableError = this.isRetryableNetworkError(error);
|
|
18142
|
+
if (!isRetryableError || attempt === CONNECTION_RETRIES_LIMIT) {
|
|
18143
|
+
if (this.options.isVerbose) {
|
|
18144
|
+
console.info(colors.bgRed('Final error after retries'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}:`, error);
|
|
18145
|
+
}
|
|
18146
|
+
throw error;
|
|
18147
|
+
}
|
|
18148
|
+
// Calculate exponential backoff delay
|
|
18149
|
+
const baseDelay = 1000; // 1 second
|
|
18150
|
+
const backoffDelay = baseDelay * Math.pow(2, attempt - 1);
|
|
18151
|
+
const jitterDelay = Math.random() * 500; // Add some randomness
|
|
18152
|
+
const totalDelay = backoffDelay + jitterDelay;
|
|
18153
|
+
if (this.options.isVerbose) {
|
|
18154
|
+
console.info(colors.bgYellow('Retrying request'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}, waiting ${Math.round(totalDelay)}ms:`, error.message);
|
|
18155
|
+
}
|
|
18156
|
+
// Wait before retrying
|
|
18157
|
+
await new Promise((resolve) => setTimeout(resolve, totalDelay));
|
|
18158
|
+
}
|
|
18159
|
+
}
|
|
18160
|
+
throw lastError;
|
|
18161
|
+
}
|
|
18162
|
+
/**
|
|
18163
|
+
* Determines if an error is retryable (network-related errors)
|
|
18164
|
+
*/
|
|
18165
|
+
isRetryableNetworkError(error) {
|
|
18166
|
+
const errorMessage = error.message.toLowerCase();
|
|
18167
|
+
const errorCode = error.code;
|
|
18168
|
+
// Network connection errors that should be retried
|
|
18169
|
+
const retryableErrors = [
|
|
18170
|
+
'econnreset',
|
|
18171
|
+
'enotfound',
|
|
18172
|
+
'econnrefused',
|
|
18173
|
+
'etimedout',
|
|
18174
|
+
'socket hang up',
|
|
18175
|
+
'network error',
|
|
18176
|
+
'fetch failed',
|
|
18177
|
+
'connection reset',
|
|
18178
|
+
'connection refused',
|
|
18179
|
+
'timeout',
|
|
18180
|
+
];
|
|
18181
|
+
// Check error message
|
|
18182
|
+
if (retryableErrors.some((retryableError) => errorMessage.includes(retryableError))) {
|
|
18183
|
+
return true;
|
|
18184
|
+
}
|
|
18185
|
+
// Check error code
|
|
18186
|
+
if (errorCode && retryableErrors.includes(errorCode.toLowerCase())) {
|
|
18187
|
+
return true;
|
|
18188
|
+
}
|
|
18189
|
+
// Check for specific HTTP status codes that are retryable
|
|
18190
|
+
const errorWithStatus = error;
|
|
18191
|
+
const httpStatus = errorWithStatus.status || errorWithStatus.statusCode;
|
|
18192
|
+
if (httpStatus && [429, 500, 502, 503, 504].includes(httpStatus)) {
|
|
18193
|
+
return true;
|
|
18194
|
+
}
|
|
18195
|
+
return false;
|
|
18196
|
+
}
|
|
18106
18197
|
}
|
|
18107
18198
|
/**
|
|
18108
18199
|
* TODO: [🛄] Some way how to re-wrap the errors from `OpenAiCompatibleExecutionTools`
|
|
@@ -19155,7 +19246,9 @@ class MarkdownScraper {
|
|
|
19155
19246
|
},
|
|
19156
19247
|
});
|
|
19157
19248
|
const knowledgeContent = await source.asText();
|
|
19158
|
-
const result = await prepareKnowledgeFromMarkdownExecutor({ knowledgeContent }).asPromise(
|
|
19249
|
+
const result = await prepareKnowledgeFromMarkdownExecutor({ knowledgeContent }).asPromise({
|
|
19250
|
+
isCrashedOnError: true,
|
|
19251
|
+
});
|
|
19159
19252
|
const { outputParameters } = result;
|
|
19160
19253
|
const { knowledgePieces: knowledgePiecesRaw } = outputParameters;
|
|
19161
19254
|
const knowledgeTextPieces = (knowledgePiecesRaw || '').split('\n---\n');
|
|
@@ -19179,12 +19272,16 @@ class MarkdownScraper {
|
|
|
19179
19272
|
];
|
|
19180
19273
|
*/
|
|
19181
19274
|
try {
|
|
19182
|
-
const titleResult = await prepareTitleExecutor({ knowledgePieceContent }).asPromise(
|
|
19275
|
+
const titleResult = await prepareTitleExecutor({ knowledgePieceContent }).asPromise({
|
|
19276
|
+
isCrashedOnError: true,
|
|
19277
|
+
});
|
|
19183
19278
|
const { title: titleRaw = 'Untitled' } = titleResult.outputParameters;
|
|
19184
19279
|
title = spaceTrim(titleRaw) /* <- TODO: Maybe do in pipeline */;
|
|
19185
19280
|
name = titleToName(title);
|
|
19186
19281
|
// --- Keywords
|
|
19187
|
-
const keywordsResult = await prepareKeywordsExecutor({ knowledgePieceContent }).asPromise(
|
|
19282
|
+
const keywordsResult = await prepareKeywordsExecutor({ knowledgePieceContent }).asPromise({
|
|
19283
|
+
isCrashedOnError: true,
|
|
19284
|
+
});
|
|
19188
19285
|
const { keywords: keywordsRaw = '' } = keywordsResult.outputParameters;
|
|
19189
19286
|
keywords = (keywordsRaw || '')
|
|
19190
19287
|
.split(',')
|