@promptbook/cli 0.89.0-9 → 0.92.0-10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -7
- package/esm/index.es.js +1832 -673
- 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 +14 -4
- package/esm/typings/src/_packages/deepseek.index.d.ts +2 -0
- package/esm/typings/src/_packages/google.index.d.ts +2 -0
- package/esm/typings/src/_packages/types.index.d.ts +18 -0
- package/esm/typings/src/_packages/utils.index.d.ts +6 -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/conversion/archive/loadArchive.d.ts +2 -2
- 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/CommonToolsOptions.d.ts +4 -0
- package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
- package/esm/typings/src/execution/createPipelineExecutor/getKnowledgeForTask.d.ts +12 -0
- package/esm/typings/src/execution/createPipelineExecutor/getReservedParametersForTask.d.ts +5 -0
- package/esm/typings/src/formats/csv/utils/csvParse.d.ts +12 -0
- 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/json/utils/jsonParse.d.ts +11 -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/llm-providers/_common/register/LlmToolsMetadata.d.ts +43 -0
- package/esm/typings/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +4 -0
- package/esm/typings/src/llm-providers/deepseek/deepseek-models.d.ts +23 -0
- package/esm/typings/src/llm-providers/google/google-models.d.ts +23 -0
- package/esm/typings/src/llm-providers/openai/OpenAiExecutionTools.d.ts +4 -0
- package/esm/typings/src/personas/preparePersona.d.ts +1 -1
- package/esm/typings/src/pipeline/PipelineJson/PersonaJson.d.ts +4 -2
- package/esm/typings/src/remote-server/openapi-types.d.ts +626 -0
- package/esm/typings/src/remote-server/openapi.d.ts +581 -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 +16 -11
- package/umd/index.umd.js +1835 -676
- package/umd/index.umd.js.map +1 -1
- package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
package/umd/index.umd.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
(function (global, factory) {
|
|
2
|
-
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('waitasecond'), require('prompts'), require('path'), require('fs/promises'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('crypto'), require('socket.io-client'), require('rxjs'), require('
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'waitasecond', 'prompts', 'path', 'fs/promises', 'crypto-js/enc-hex', 'crypto-js/sha256', 'crypto', 'socket.io-client', 'rxjs', '
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global.spaceTrim, global.waitasecond, global.prompts, global.path, global.promises, global.hexEncoder, global.sha256, global.crypto, global.socket_ioClient, global.rxjs, global.
|
|
5
|
-
})(this, (function (exports, colors, commander, spaceTrim, waitasecond, prompts, path, promises, hexEncoder, sha256, crypto, socket_ioClient, rxjs,
|
|
2
|
+
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('waitasecond'), require('prompts'), require('path'), require('fs/promises'), require('dotenv'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('crypto'), require('socket.io-client'), require('rxjs'), require('child_process'), require('jszip'), require('prettier'), require('prettier/parser-html'), require('papaparse'), require('crypto-js'), require('mime-types'), require('glob-promise'), require('moment'), require('express'), require('http'), require('socket.io'), require('express-openapi-validator'), require('swagger-ui-express'), require('@anthropic-ai/sdk'), require('@azure/openai'), require('bottleneck'), require('openai'), require('@mozilla/readability'), require('jsdom'), require('showdown')) :
|
|
3
|
+
typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'waitasecond', 'prompts', 'path', 'fs/promises', 'dotenv', 'crypto-js/enc-hex', 'crypto-js/sha256', 'crypto', 'socket.io-client', 'rxjs', 'child_process', 'jszip', 'prettier', 'prettier/parser-html', 'papaparse', 'crypto-js', 'mime-types', 'glob-promise', 'moment', 'express', 'http', 'socket.io', 'express-openapi-validator', 'swagger-ui-express', '@anthropic-ai/sdk', '@azure/openai', 'bottleneck', 'openai', '@mozilla/readability', 'jsdom', 'showdown'], factory) :
|
|
4
|
+
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global.spaceTrim, global.waitasecond, global.prompts, global.path, global.promises, global.dotenv, global.hexEncoder, global.sha256, global.crypto, global.socket_ioClient, global.rxjs, global.child_process, global.JSZip, global.prettier, global.parserHtml, global.papaparse, global.cryptoJs, global.mimeTypes, global.glob, global.moment, global.express, global.http, global.socket_io, global.OpenApiValidator, global.swaggerUi, global.Anthropic, global.openai, global.Bottleneck, global.OpenAI, global.readability, global.jsdom, global.showdown));
|
|
5
|
+
})(this, (function (exports, colors, commander, spaceTrim, waitasecond, prompts, path, promises, dotenv, hexEncoder, sha256, crypto, socket_ioClient, rxjs, child_process, JSZip, prettier, parserHtml, papaparse, cryptoJs, mimeTypes, glob, moment, express, http, socket_io, OpenApiValidator, swaggerUi, Anthropic, openai, Bottleneck, OpenAI, readability, jsdom, showdown) { 'use strict';
|
|
6
6
|
|
|
7
7
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
8
|
|
|
@@ -28,18 +28,19 @@
|
|
|
28
28
|
var commander__default = /*#__PURE__*/_interopDefaultLegacy(commander);
|
|
29
29
|
var spaceTrim__default = /*#__PURE__*/_interopDefaultLegacy(spaceTrim);
|
|
30
30
|
var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts);
|
|
31
|
+
var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
|
|
31
32
|
var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
|
|
32
33
|
var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
|
|
33
|
-
var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
|
|
34
34
|
var JSZip__default = /*#__PURE__*/_interopDefaultLegacy(JSZip);
|
|
35
35
|
var parserHtml__default = /*#__PURE__*/_interopDefaultLegacy(parserHtml);
|
|
36
36
|
var glob__default = /*#__PURE__*/_interopDefaultLegacy(glob);
|
|
37
37
|
var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
|
|
38
38
|
var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
|
|
39
39
|
var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
|
|
40
|
-
var
|
|
40
|
+
var OpenApiValidator__namespace = /*#__PURE__*/_interopNamespace(OpenApiValidator);
|
|
41
41
|
var swaggerUi__default = /*#__PURE__*/_interopDefaultLegacy(swaggerUi);
|
|
42
42
|
var Anthropic__default = /*#__PURE__*/_interopDefaultLegacy(Anthropic);
|
|
43
|
+
var Bottleneck__default = /*#__PURE__*/_interopDefaultLegacy(Bottleneck);
|
|
43
44
|
var OpenAI__default = /*#__PURE__*/_interopDefaultLegacy(OpenAI);
|
|
44
45
|
|
|
45
46
|
// ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
|
|
@@ -56,12 +57,43 @@
|
|
|
56
57
|
* @generated
|
|
57
58
|
* @see https://github.com/webgptorg/promptbook
|
|
58
59
|
*/
|
|
59
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.
|
|
60
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.92.0-10';
|
|
60
61
|
/**
|
|
61
62
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
62
63
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
63
64
|
*/
|
|
64
65
|
|
|
66
|
+
/**
|
|
67
|
+
* Available remote servers for the Promptbook
|
|
68
|
+
*
|
|
69
|
+
* @public exported from `@promptbook/core`
|
|
70
|
+
*/
|
|
71
|
+
const REMOTE_SERVER_URLS = [
|
|
72
|
+
{
|
|
73
|
+
title: 'Promptbook',
|
|
74
|
+
description: `Servers of Promptbook.studio`,
|
|
75
|
+
owner: 'AI Web, LLC <legal@ptbk.io> (https://www.ptbk.io/)',
|
|
76
|
+
isAnonymousModeAllowed: true,
|
|
77
|
+
urls: [
|
|
78
|
+
'https://promptbook.s5.ptbk.io/',
|
|
79
|
+
// Note: Servers 1-4 are not running
|
|
80
|
+
],
|
|
81
|
+
},
|
|
82
|
+
/*
|
|
83
|
+
Note: Working on older version of Promptbook and not supported anymore
|
|
84
|
+
{
|
|
85
|
+
title: 'Pavol Promptbook Server',
|
|
86
|
+
description: `Personal server of Pavol Hejný with simple testing server, DO NOT USE IT FOR PRODUCTION`,
|
|
87
|
+
owner: 'Pavol Hejný <pavol@ptbk.io> (https://www.pavolhejny.com/)',
|
|
88
|
+
isAnonymousModeAllowed: true,
|
|
89
|
+
urls: ['https://api.pavolhejny.com/promptbook'],
|
|
90
|
+
},
|
|
91
|
+
*/
|
|
92
|
+
];
|
|
93
|
+
/**
|
|
94
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
95
|
+
*/
|
|
96
|
+
|
|
65
97
|
/**
|
|
66
98
|
* Returns the same value that is passed as argument.
|
|
67
99
|
* No side effects.
|
|
@@ -116,6 +148,7 @@
|
|
|
116
148
|
* @public exported from `@promptbook/core`
|
|
117
149
|
*/
|
|
118
150
|
const CLAIM = `It's time for a paradigm shift. The future of software in plain English, French or Latin`;
|
|
151
|
+
// <- TODO: [🐊] Pick the best claim
|
|
119
152
|
/**
|
|
120
153
|
* When the title is not provided, the default title is used
|
|
121
154
|
*
|
|
@@ -146,6 +179,12 @@
|
|
|
146
179
|
* @private within the repository
|
|
147
180
|
*/
|
|
148
181
|
const GENERATOR_WARNING_BY_PROMPTBOOK_CLI = `⚠️ WARNING: This code has been generated by \`@promptbook/cli\` so that any manual changes will be overwritten`;
|
|
182
|
+
/**
|
|
183
|
+
* Warning message for the automatically generated sections of `.env` files
|
|
184
|
+
*
|
|
185
|
+
* @private within the repository
|
|
186
|
+
*/
|
|
187
|
+
const GENERATOR_WARNING_IN_ENV = `Note: Added by Promptbook`;
|
|
149
188
|
// <- TODO: [🧠] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
|
|
150
189
|
/**
|
|
151
190
|
* The maximum number of iterations for a loops
|
|
@@ -166,6 +205,7 @@
|
|
|
166
205
|
infinity: '(infinity; ∞)',
|
|
167
206
|
negativeInfinity: '(negative infinity; -∞)',
|
|
168
207
|
unserializable: '(unserializable value)',
|
|
208
|
+
circular: '(circular JSON)',
|
|
169
209
|
};
|
|
170
210
|
/**
|
|
171
211
|
* Small number limit
|
|
@@ -225,7 +265,7 @@
|
|
|
225
265
|
*/
|
|
226
266
|
const DEFAULT_BOOKS_DIRNAME = './books';
|
|
227
267
|
// <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
|
|
228
|
-
// TODO:
|
|
268
|
+
// TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
|
|
229
269
|
/**
|
|
230
270
|
* Where to store the temporary downloads
|
|
231
271
|
*
|
|
@@ -281,11 +321,11 @@
|
|
|
281
321
|
ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
|
|
282
322
|
};
|
|
283
323
|
/**
|
|
284
|
-
*
|
|
324
|
+
* Default remote server URL for the Promptbook
|
|
285
325
|
*
|
|
286
326
|
* @public exported from `@promptbook/core`
|
|
287
327
|
*/
|
|
288
|
-
const DEFAULT_REMOTE_SERVER_URL =
|
|
328
|
+
const DEFAULT_REMOTE_SERVER_URL = REMOTE_SERVER_URLS[0].urls[0];
|
|
289
329
|
// <- TODO: [🧜♂️]
|
|
290
330
|
/**
|
|
291
331
|
* @@@
|
|
@@ -419,6 +459,122 @@
|
|
|
419
459
|
* TODO: [🎺]
|
|
420
460
|
*/
|
|
421
461
|
|
|
462
|
+
/**
|
|
463
|
+
* Make error report URL for the given error
|
|
464
|
+
*
|
|
465
|
+
* @private private within the repository
|
|
466
|
+
*/
|
|
467
|
+
function getErrorReportUrl(error) {
|
|
468
|
+
const report = {
|
|
469
|
+
title: `🐜 Error report from ${NAME}`,
|
|
470
|
+
body: spaceTrim__default["default"]((block) => `
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
474
|
+
|
|
475
|
+
\`\`\`
|
|
476
|
+
${block(error.message || '(no error message)')}
|
|
477
|
+
\`\`\`
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
## More info:
|
|
481
|
+
|
|
482
|
+
- **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
|
|
483
|
+
- **Book language version:** ${BOOK_LANGUAGE_VERSION}
|
|
484
|
+
- **Time:** ${new Date().toISOString()}
|
|
485
|
+
|
|
486
|
+
<details>
|
|
487
|
+
<summary>Stack trace:</summary>
|
|
488
|
+
|
|
489
|
+
## Stack trace:
|
|
490
|
+
|
|
491
|
+
\`\`\`stacktrace
|
|
492
|
+
${block(error.stack || '(empty)')}
|
|
493
|
+
\`\`\`
|
|
494
|
+
</details>
|
|
495
|
+
|
|
496
|
+
`),
|
|
497
|
+
};
|
|
498
|
+
const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
|
|
499
|
+
reportUrl.searchParams.set('labels', 'bug');
|
|
500
|
+
reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
|
|
501
|
+
reportUrl.searchParams.set('title', report.title);
|
|
502
|
+
reportUrl.searchParams.set('body', report.body);
|
|
503
|
+
return reportUrl;
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* This error type indicates that the error should not happen and its last check before crashing with some other error
|
|
508
|
+
*
|
|
509
|
+
* @public exported from `@promptbook/core`
|
|
510
|
+
*/
|
|
511
|
+
class UnexpectedError extends Error {
|
|
512
|
+
constructor(message) {
|
|
513
|
+
super(spaceTrim.spaceTrim((block) => `
|
|
514
|
+
${block(message)}
|
|
515
|
+
|
|
516
|
+
Note: This error should not happen.
|
|
517
|
+
It's probbably a bug in the pipeline collection
|
|
518
|
+
|
|
519
|
+
Please report issue:
|
|
520
|
+
${block(getErrorReportUrl(new Error(message)).href)}
|
|
521
|
+
|
|
522
|
+
Or contact us on ${ADMIN_EMAIL}
|
|
523
|
+
|
|
524
|
+
`));
|
|
525
|
+
this.name = 'UnexpectedError';
|
|
526
|
+
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
/**
|
|
531
|
+
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
532
|
+
*
|
|
533
|
+
* @public exported from `@promptbook/core`
|
|
534
|
+
*/
|
|
535
|
+
class WrappedError extends Error {
|
|
536
|
+
constructor(whatWasThrown) {
|
|
537
|
+
const tag = `[🤮]`;
|
|
538
|
+
console.error(tag, whatWasThrown);
|
|
539
|
+
super(spaceTrim.spaceTrim(`
|
|
540
|
+
Non-Error object was thrown
|
|
541
|
+
|
|
542
|
+
Note: Look for ${tag} in the console for more details
|
|
543
|
+
Please report issue on ${ADMIN_EMAIL}
|
|
544
|
+
`));
|
|
545
|
+
this.name = 'WrappedError';
|
|
546
|
+
Object.setPrototypeOf(this, WrappedError.prototype);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Helper used in catch blocks to assert that the error is an instance of `Error`
|
|
552
|
+
*
|
|
553
|
+
* @param whatWasThrown Any object that was thrown
|
|
554
|
+
* @returns Nothing if the error is an instance of `Error`
|
|
555
|
+
* @throws `WrappedError` or `UnexpectedError` if the error is not standard
|
|
556
|
+
*
|
|
557
|
+
* @private within the repository
|
|
558
|
+
*/
|
|
559
|
+
function assertsError(whatWasThrown) {
|
|
560
|
+
// Case 1: Handle error which was rethrown as `WrappedError`
|
|
561
|
+
if (whatWasThrown instanceof WrappedError) {
|
|
562
|
+
const wrappedError = whatWasThrown;
|
|
563
|
+
throw wrappedError;
|
|
564
|
+
}
|
|
565
|
+
// Case 2: Handle unexpected errors
|
|
566
|
+
if (whatWasThrown instanceof UnexpectedError) {
|
|
567
|
+
const unexpectedError = whatWasThrown;
|
|
568
|
+
throw unexpectedError;
|
|
569
|
+
}
|
|
570
|
+
// Case 3: Handle standard errors - keep them up to consumer
|
|
571
|
+
if (whatWasThrown instanceof Error) {
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
// Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
|
|
575
|
+
throw new WrappedError(whatWasThrown);
|
|
576
|
+
}
|
|
577
|
+
|
|
422
578
|
/**
|
|
423
579
|
* Wraps action to handle error console logging and exit process with error code
|
|
424
580
|
*
|
|
@@ -433,9 +589,7 @@
|
|
|
433
589
|
return process.exit(0);
|
|
434
590
|
}
|
|
435
591
|
catch (error) {
|
|
436
|
-
|
|
437
|
-
throw error;
|
|
438
|
-
}
|
|
592
|
+
assertsError(error);
|
|
439
593
|
// console.error(colors.bgRed(error.name));
|
|
440
594
|
console.error(colors__default["default"].red(/* error.stack || */ error.message));
|
|
441
595
|
return process.exit(1);
|
|
@@ -542,74 +696,6 @@
|
|
|
542
696
|
}
|
|
543
697
|
}
|
|
544
698
|
|
|
545
|
-
/**
|
|
546
|
-
* Make error report URL for the given error
|
|
547
|
-
*
|
|
548
|
-
* @private private within the repository
|
|
549
|
-
*/
|
|
550
|
-
function getErrorReportUrl(error) {
|
|
551
|
-
const report = {
|
|
552
|
-
title: `🐜 Error report from ${NAME}`,
|
|
553
|
-
body: spaceTrim__default["default"]((block) => `
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
557
|
-
|
|
558
|
-
\`\`\`
|
|
559
|
-
${block(error.message || '(no error message)')}
|
|
560
|
-
\`\`\`
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
## More info:
|
|
564
|
-
|
|
565
|
-
- **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
|
|
566
|
-
- **Book language version:** ${BOOK_LANGUAGE_VERSION}
|
|
567
|
-
- **Time:** ${new Date().toISOString()}
|
|
568
|
-
|
|
569
|
-
<details>
|
|
570
|
-
<summary>Stack trace:</summary>
|
|
571
|
-
|
|
572
|
-
## Stack trace:
|
|
573
|
-
|
|
574
|
-
\`\`\`stacktrace
|
|
575
|
-
${block(error.stack || '(empty)')}
|
|
576
|
-
\`\`\`
|
|
577
|
-
</details>
|
|
578
|
-
|
|
579
|
-
`),
|
|
580
|
-
};
|
|
581
|
-
const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
|
|
582
|
-
reportUrl.searchParams.set('labels', 'bug');
|
|
583
|
-
reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
|
|
584
|
-
reportUrl.searchParams.set('title', report.title);
|
|
585
|
-
reportUrl.searchParams.set('body', report.body);
|
|
586
|
-
return reportUrl;
|
|
587
|
-
}
|
|
588
|
-
|
|
589
|
-
/**
|
|
590
|
-
* This error type indicates that the error should not happen and its last check before crashing with some other error
|
|
591
|
-
*
|
|
592
|
-
* @public exported from `@promptbook/core`
|
|
593
|
-
*/
|
|
594
|
-
class UnexpectedError extends Error {
|
|
595
|
-
constructor(message) {
|
|
596
|
-
super(spaceTrim.spaceTrim((block) => `
|
|
597
|
-
${block(message)}
|
|
598
|
-
|
|
599
|
-
Note: This error should not happen.
|
|
600
|
-
It's probbably a bug in the pipeline collection
|
|
601
|
-
|
|
602
|
-
Please report issue:
|
|
603
|
-
${block(getErrorReportUrl(new Error(message)).href)}
|
|
604
|
-
|
|
605
|
-
Or contact us on ${ADMIN_EMAIL}
|
|
606
|
-
|
|
607
|
-
`));
|
|
608
|
-
this.name = 'UnexpectedError';
|
|
609
|
-
Object.setPrototypeOf(this, UnexpectedError.prototype);
|
|
610
|
-
}
|
|
611
|
-
}
|
|
612
|
-
|
|
613
699
|
/**
|
|
614
700
|
* @@@
|
|
615
701
|
*
|
|
@@ -929,6 +1015,79 @@
|
|
|
929
1015
|
keepUnused(...sideEffectSubjects);
|
|
930
1016
|
}
|
|
931
1017
|
|
|
1018
|
+
/**
|
|
1019
|
+
* Converts a JavaScript Object Notation (JSON) string into an object.
|
|
1020
|
+
*
|
|
1021
|
+
* Note: This is wrapper around `JSON.parse()` with better error and type handling
|
|
1022
|
+
*
|
|
1023
|
+
* @public exported from `@promptbook/utils`
|
|
1024
|
+
*/
|
|
1025
|
+
function jsonParse(value) {
|
|
1026
|
+
if (value === undefined) {
|
|
1027
|
+
throw new Error(`Can not parse JSON from undefined value.`);
|
|
1028
|
+
}
|
|
1029
|
+
else if (typeof value !== 'string') {
|
|
1030
|
+
console.error('Can not parse JSON from non-string value.', { text: value });
|
|
1031
|
+
throw new Error(spaceTrim__default["default"](`
|
|
1032
|
+
Can not parse JSON from non-string value.
|
|
1033
|
+
|
|
1034
|
+
The value type: ${typeof value}
|
|
1035
|
+
See more in console.
|
|
1036
|
+
`));
|
|
1037
|
+
}
|
|
1038
|
+
try {
|
|
1039
|
+
return JSON.parse(value);
|
|
1040
|
+
}
|
|
1041
|
+
catch (error) {
|
|
1042
|
+
if (!(error instanceof Error)) {
|
|
1043
|
+
throw error;
|
|
1044
|
+
}
|
|
1045
|
+
throw new Error(spaceTrim__default["default"]((block) => `
|
|
1046
|
+
${block(error.message)}
|
|
1047
|
+
|
|
1048
|
+
The JSON text:
|
|
1049
|
+
${block(value)}
|
|
1050
|
+
`));
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
/**
|
|
1054
|
+
* TODO: !!!! Use in Promptbook.studio
|
|
1055
|
+
*/
|
|
1056
|
+
|
|
1057
|
+
/**
|
|
1058
|
+
* Convert identification to Promptbook token
|
|
1059
|
+
*
|
|
1060
|
+
* @param identification
|
|
1061
|
+
*
|
|
1062
|
+
* @public exported from `@promptbook/core`
|
|
1063
|
+
*/
|
|
1064
|
+
function identificationToPromptbookToken(identification) {
|
|
1065
|
+
const { appId, userId, userToken } = identification;
|
|
1066
|
+
const promptbookToken = `${appId}-${userId}-${userToken}`;
|
|
1067
|
+
return promptbookToken;
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* Convert Promptbook token to identification
|
|
1072
|
+
*
|
|
1073
|
+
* @param promptbookToken
|
|
1074
|
+
*
|
|
1075
|
+
* @public exported from `@promptbook/core`
|
|
1076
|
+
*/
|
|
1077
|
+
function promptbookTokenToIdentification(promptbookToken) {
|
|
1078
|
+
const [appId, userId, userToken] = promptbookToken.split('-');
|
|
1079
|
+
if (!appId || !userId || !userToken) {
|
|
1080
|
+
throw new Error(`Invalid promptbook token: ${promptbookToken}`);
|
|
1081
|
+
}
|
|
1082
|
+
const identification = {
|
|
1083
|
+
appId,
|
|
1084
|
+
userId,
|
|
1085
|
+
userToken,
|
|
1086
|
+
isAnonymous: false,
|
|
1087
|
+
};
|
|
1088
|
+
return identification;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
932
1091
|
/**
|
|
933
1092
|
* Just marks a place of place where should be something implemented
|
|
934
1093
|
* No side effects.
|
|
@@ -942,27 +1101,199 @@
|
|
|
942
1101
|
function TODO_USE(...value) {
|
|
943
1102
|
}
|
|
944
1103
|
|
|
945
|
-
/**
|
|
946
|
-
* @@@
|
|
947
|
-
*
|
|
948
|
-
* @public exported from `@promptbook/node`
|
|
949
|
-
*/
|
|
950
|
-
function $provideFilesystemForNode(options) {
|
|
951
|
-
if (!$isRunningInNode()) {
|
|
952
|
-
throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
|
|
1104
|
+
/**
|
|
1105
|
+
* @@@
|
|
1106
|
+
*
|
|
1107
|
+
* @public exported from `@promptbook/node`
|
|
1108
|
+
*/
|
|
1109
|
+
function $provideFilesystemForNode(options) {
|
|
1110
|
+
if (!$isRunningInNode()) {
|
|
1111
|
+
throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
|
|
1112
|
+
}
|
|
1113
|
+
return {
|
|
1114
|
+
stat: promises.stat,
|
|
1115
|
+
access: promises.access,
|
|
1116
|
+
constants: promises.constants,
|
|
1117
|
+
readFile: promises.readFile,
|
|
1118
|
+
writeFile: promises.writeFile,
|
|
1119
|
+
readdir: promises.readdir,
|
|
1120
|
+
mkdir: promises.mkdir,
|
|
1121
|
+
};
|
|
1122
|
+
}
|
|
1123
|
+
/**
|
|
1124
|
+
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1125
|
+
*/
|
|
1126
|
+
|
|
1127
|
+
/**
|
|
1128
|
+
* Checks if the file exists
|
|
1129
|
+
*
|
|
1130
|
+
* @private within the repository
|
|
1131
|
+
*/
|
|
1132
|
+
async function isFileExisting(filename, fs) {
|
|
1133
|
+
const isReadAccessAllowed = await fs
|
|
1134
|
+
.access(filename, fs.constants.R_OK)
|
|
1135
|
+
.then(() => true)
|
|
1136
|
+
.catch(() => false);
|
|
1137
|
+
if (!isReadAccessAllowed) {
|
|
1138
|
+
return false;
|
|
1139
|
+
}
|
|
1140
|
+
const isFile = await fs
|
|
1141
|
+
.stat(filename)
|
|
1142
|
+
.then((fileStat) => fileStat.isFile())
|
|
1143
|
+
.catch(() => false);
|
|
1144
|
+
return isFile;
|
|
1145
|
+
}
|
|
1146
|
+
/**
|
|
1147
|
+
* Note: Not [~🟢~] because it is not directly dependent on `fs
|
|
1148
|
+
* TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
|
|
1149
|
+
* TODO: [🖇] What about symlinks?
|
|
1150
|
+
*/
|
|
1151
|
+
|
|
1152
|
+
/**
|
|
1153
|
+
* Determines if the given path is a root path.
|
|
1154
|
+
*
|
|
1155
|
+
* Note: This does not check if the file exists only if the path is valid
|
|
1156
|
+
* @public exported from `@promptbook/utils`
|
|
1157
|
+
*/
|
|
1158
|
+
function isRootPath(value) {
|
|
1159
|
+
if (value === '/') {
|
|
1160
|
+
return true;
|
|
1161
|
+
}
|
|
1162
|
+
if (/^[A-Z]:\\$/i.test(value)) {
|
|
1163
|
+
return true;
|
|
1164
|
+
}
|
|
1165
|
+
return false;
|
|
1166
|
+
}
|
|
1167
|
+
/**
|
|
1168
|
+
* TODO: [🍏] Make for MacOS paths
|
|
1169
|
+
*/
|
|
1170
|
+
|
|
1171
|
+
/**
|
|
1172
|
+
* Provides the path to the `.env` file
|
|
1173
|
+
*
|
|
1174
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
|
|
1175
|
+
*
|
|
1176
|
+
* @private within the repository - for CLI utils
|
|
1177
|
+
*/
|
|
1178
|
+
async function $provideEnvFilename() {
|
|
1179
|
+
if (!$isRunningInNode()) {
|
|
1180
|
+
throw new EnvironmentMismatchError('Function `$provideEnvFilename` works only in Node.js environment');
|
|
1181
|
+
}
|
|
1182
|
+
const envFilePatterns = [
|
|
1183
|
+
'.env',
|
|
1184
|
+
'.env.test',
|
|
1185
|
+
'.env.local',
|
|
1186
|
+
'.env.development.local',
|
|
1187
|
+
'.env.development',
|
|
1188
|
+
'.env.production.local',
|
|
1189
|
+
'.env.production',
|
|
1190
|
+
'.env.prod.local',
|
|
1191
|
+
'.env.prod',
|
|
1192
|
+
// <- TODO: Maybe add more patterns
|
|
1193
|
+
];
|
|
1194
|
+
let rootDirname = process.cwd();
|
|
1195
|
+
up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
|
|
1196
|
+
for (const pattern of envFilePatterns) {
|
|
1197
|
+
const envFilename = path.join(rootDirname, pattern);
|
|
1198
|
+
if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
|
|
1199
|
+
$setUsedEnvFilename(envFilename);
|
|
1200
|
+
return envFilename;
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
if (isRootPath(rootDirname)) {
|
|
1204
|
+
break up_to_root;
|
|
1205
|
+
}
|
|
1206
|
+
// Note: If the directory does not exist, try the parent directory
|
|
1207
|
+
rootDirname = path.join(rootDirname, '..');
|
|
1208
|
+
}
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
/**
|
|
1212
|
+
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1213
|
+
*/
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Stores data in .env variables
|
|
1217
|
+
*
|
|
1218
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes to `process.env`
|
|
1219
|
+
*
|
|
1220
|
+
* @private within the repository - for CLI utils
|
|
1221
|
+
*/
|
|
1222
|
+
class $EnvStorage {
|
|
1223
|
+
constructor() {
|
|
1224
|
+
this.envFilename = null;
|
|
1225
|
+
}
|
|
1226
|
+
async $provideOrCreateEnvFile() {
|
|
1227
|
+
if (this.envFilename !== null) {
|
|
1228
|
+
return this.envFilename;
|
|
1229
|
+
}
|
|
1230
|
+
let envFilename = await $provideEnvFilename();
|
|
1231
|
+
if (envFilename !== null) {
|
|
1232
|
+
this.envFilename = envFilename;
|
|
1233
|
+
return envFilename;
|
|
1234
|
+
}
|
|
1235
|
+
envFilename = path.join(process.cwd(), '.env');
|
|
1236
|
+
await promises.writeFile(envFilename, '# This file was initialized by Promptbook', 'utf-8');
|
|
1237
|
+
this.envFilename = envFilename;
|
|
1238
|
+
return envFilename;
|
|
1239
|
+
}
|
|
1240
|
+
transformKey(key) {
|
|
1241
|
+
return normalizeTo_SCREAMING_CASE(key);
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
1245
|
+
*/
|
|
1246
|
+
get length() {
|
|
1247
|
+
throw new NotYetImplementedError('Method `$EnvStorage.length` not implemented.');
|
|
1248
|
+
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
1251
|
+
*/
|
|
1252
|
+
clear() {
|
|
1253
|
+
throw new NotYetImplementedError('Method `$EnvStorage.clear` not implemented.');
|
|
1254
|
+
}
|
|
1255
|
+
/**
|
|
1256
|
+
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
1257
|
+
*/
|
|
1258
|
+
async getItem(key) {
|
|
1259
|
+
dotenv__namespace.config({ path: await this.$provideOrCreateEnvFile() });
|
|
1260
|
+
return process.env[this.transformKey(key)] || null;
|
|
1261
|
+
}
|
|
1262
|
+
/**
|
|
1263
|
+
* Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
|
|
1264
|
+
*/
|
|
1265
|
+
key(index) {
|
|
1266
|
+
throw new NotYetImplementedError('Method `$EnvStorage.key` not implemented.');
|
|
1267
|
+
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
1270
|
+
*/
|
|
1271
|
+
async setItem(key, value) {
|
|
1272
|
+
const envFilename = await this.$provideOrCreateEnvFile();
|
|
1273
|
+
const envContent = await promises.readFile(envFilename, 'utf-8');
|
|
1274
|
+
const transformedKey = this.transformKey(key);
|
|
1275
|
+
const updatedEnvContent = envContent
|
|
1276
|
+
.split('\n')
|
|
1277
|
+
.filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
|
|
1278
|
+
.filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
|
|
1279
|
+
.join('\n');
|
|
1280
|
+
const newEnvContent = spaceTrim__default["default"]((block) => `
|
|
1281
|
+
${block(updatedEnvContent)}
|
|
1282
|
+
|
|
1283
|
+
# ${GENERATOR_WARNING_IN_ENV}
|
|
1284
|
+
${transformedKey}=${JSON.stringify(value)}
|
|
1285
|
+
`);
|
|
1286
|
+
await promises.writeFile(envFilename, newEnvContent, 'utf-8');
|
|
1287
|
+
}
|
|
1288
|
+
/**
|
|
1289
|
+
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
|
|
1290
|
+
*/
|
|
1291
|
+
removeItem(key) {
|
|
1292
|
+
throw new NotYetImplementedError('Method `$EnvStorage.removeItem` not implemented.');
|
|
953
1293
|
}
|
|
954
|
-
return {
|
|
955
|
-
stat: promises.stat,
|
|
956
|
-
access: promises.access,
|
|
957
|
-
constants: promises.constants,
|
|
958
|
-
readFile: promises.readFile,
|
|
959
|
-
writeFile: promises.writeFile,
|
|
960
|
-
readdir: promises.readdir,
|
|
961
|
-
mkdir: promises.mkdir,
|
|
962
|
-
};
|
|
963
1294
|
}
|
|
964
1295
|
/**
|
|
965
|
-
*
|
|
1296
|
+
* TODO: Write file more securely - ensure that there can be no accidental overwriting of existing variables and other content
|
|
966
1297
|
*/
|
|
967
1298
|
|
|
968
1299
|
/**
|
|
@@ -1098,9 +1429,7 @@
|
|
|
1098
1429
|
JSON.stringify(value); // <- TODO: [0]
|
|
1099
1430
|
}
|
|
1100
1431
|
catch (error) {
|
|
1101
|
-
|
|
1102
|
-
throw error;
|
|
1103
|
-
}
|
|
1432
|
+
assertsError(error);
|
|
1104
1433
|
throw new UnexpectedError(spaceTrim__default["default"]((block) => `
|
|
1105
1434
|
\`${name}\` is not serializable
|
|
1106
1435
|
|
|
@@ -1333,31 +1662,6 @@
|
|
|
1333
1662
|
* TODO: [🍙] Make some standard order of json properties
|
|
1334
1663
|
*/
|
|
1335
1664
|
|
|
1336
|
-
/**
|
|
1337
|
-
* Checks if the file exists
|
|
1338
|
-
*
|
|
1339
|
-
* @private within the repository
|
|
1340
|
-
*/
|
|
1341
|
-
async function isFileExisting(filename, fs) {
|
|
1342
|
-
const isReadAccessAllowed = await fs
|
|
1343
|
-
.access(filename, fs.constants.R_OK)
|
|
1344
|
-
.then(() => true)
|
|
1345
|
-
.catch(() => false);
|
|
1346
|
-
if (!isReadAccessAllowed) {
|
|
1347
|
-
return false;
|
|
1348
|
-
}
|
|
1349
|
-
const isFile = await fs
|
|
1350
|
-
.stat(filename)
|
|
1351
|
-
.then((fileStat) => fileStat.isFile())
|
|
1352
|
-
.catch(() => false);
|
|
1353
|
-
return isFile;
|
|
1354
|
-
}
|
|
1355
|
-
/**
|
|
1356
|
-
* Note: Not [~🟢~] because it is not directly dependent on `fs
|
|
1357
|
-
* TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
|
|
1358
|
-
* TODO: [🖇] What about symlinks?
|
|
1359
|
-
*/
|
|
1360
|
-
|
|
1361
1665
|
/**
|
|
1362
1666
|
* Removes emojis from a string and fix whitespaces
|
|
1363
1667
|
*
|
|
@@ -1831,7 +2135,7 @@
|
|
|
1831
2135
|
return null;
|
|
1832
2136
|
}
|
|
1833
2137
|
const fileContent = await promises.readFile(filename, 'utf-8');
|
|
1834
|
-
const value =
|
|
2138
|
+
const value = jsonParse(fileContent);
|
|
1835
2139
|
// TODO: [🌗]
|
|
1836
2140
|
return value;
|
|
1837
2141
|
}
|
|
@@ -1863,53 +2167,6 @@
|
|
|
1863
2167
|
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1864
2168
|
*/
|
|
1865
2169
|
|
|
1866
|
-
/**
|
|
1867
|
-
* Stores data in memory (HEAP)
|
|
1868
|
-
*
|
|
1869
|
-
* @public exported from `@promptbook/core`
|
|
1870
|
-
*/
|
|
1871
|
-
class MemoryStorage {
|
|
1872
|
-
constructor() {
|
|
1873
|
-
this.storage = {};
|
|
1874
|
-
}
|
|
1875
|
-
/**
|
|
1876
|
-
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
1877
|
-
*/
|
|
1878
|
-
get length() {
|
|
1879
|
-
return Object.keys(this.storage).length;
|
|
1880
|
-
}
|
|
1881
|
-
/**
|
|
1882
|
-
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
1883
|
-
*/
|
|
1884
|
-
clear() {
|
|
1885
|
-
this.storage = {};
|
|
1886
|
-
}
|
|
1887
|
-
/**
|
|
1888
|
-
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
1889
|
-
*/
|
|
1890
|
-
getItem(key) {
|
|
1891
|
-
return this.storage[key] || null;
|
|
1892
|
-
}
|
|
1893
|
-
/**
|
|
1894
|
-
* Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
|
|
1895
|
-
*/
|
|
1896
|
-
key(index) {
|
|
1897
|
-
return Object.keys(this.storage)[index] || null;
|
|
1898
|
-
}
|
|
1899
|
-
/**
|
|
1900
|
-
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
1901
|
-
*/
|
|
1902
|
-
setItem(key, value) {
|
|
1903
|
-
this.storage[key] = value;
|
|
1904
|
-
}
|
|
1905
|
-
/**
|
|
1906
|
-
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
|
|
1907
|
-
*/
|
|
1908
|
-
removeItem(key) {
|
|
1909
|
-
delete this.storage[key];
|
|
1910
|
-
}
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1913
2170
|
/**
|
|
1914
2171
|
* This error indicates problems parsing the format value
|
|
1915
2172
|
*
|
|
@@ -2086,7 +2343,7 @@
|
|
|
2086
2343
|
}
|
|
2087
2344
|
}
|
|
2088
2345
|
/**
|
|
2089
|
-
* TODO:
|
|
2346
|
+
* TODO: [🧠][🌂] Add id to all errors
|
|
2090
2347
|
*/
|
|
2091
2348
|
|
|
2092
2349
|
/**
|
|
@@ -2148,7 +2405,10 @@
|
|
|
2148
2405
|
PipelineExecutionError,
|
|
2149
2406
|
PipelineLogicError,
|
|
2150
2407
|
PipelineUrlError,
|
|
2408
|
+
AuthenticationError,
|
|
2409
|
+
PromptbookFetchError,
|
|
2151
2410
|
UnexpectedError,
|
|
2411
|
+
WrappedError,
|
|
2152
2412
|
// TODO: [🪑]> VersionMismatchError,
|
|
2153
2413
|
};
|
|
2154
2414
|
/**
|
|
@@ -2165,8 +2425,6 @@
|
|
|
2165
2425
|
TypeError,
|
|
2166
2426
|
URIError,
|
|
2167
2427
|
AggregateError,
|
|
2168
|
-
AuthenticationError,
|
|
2169
|
-
PromptbookFetchError,
|
|
2170
2428
|
/*
|
|
2171
2429
|
Note: Not widely supported
|
|
2172
2430
|
> InternalError,
|
|
@@ -2224,17 +2482,31 @@
|
|
|
2224
2482
|
*/
|
|
2225
2483
|
async function createRemoteClient(options) {
|
|
2226
2484
|
const { remoteServerUrl } = options;
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2485
|
+
if (!isValidUrl(remoteServerUrl)) {
|
|
2486
|
+
throw new Error(`Invalid \`remoteServerUrl\`: "${remoteServerUrl}"`);
|
|
2487
|
+
}
|
|
2488
|
+
const remoteServerUrlParsed = new URL(remoteServerUrl);
|
|
2489
|
+
if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
|
|
2490
|
+
remoteServerUrlParsed.pathname = '/';
|
|
2491
|
+
throw new Error(spaceTrim__default["default"]((block) => `
|
|
2492
|
+
Remote server requires root url \`/\`
|
|
2493
|
+
|
|
2494
|
+
You have provided \`remoteServerUrl\`:
|
|
2495
|
+
${block(remoteServerUrl)}
|
|
2496
|
+
|
|
2497
|
+
But something like this is expected:
|
|
2498
|
+
${block(remoteServerUrlParsed.href)}
|
|
2499
|
+
|
|
2500
|
+
Note: If you need to run multiple services on the same server, use 3rd or 4th degree subdomain
|
|
2501
|
+
|
|
2502
|
+
`));
|
|
2230
2503
|
}
|
|
2231
|
-
path = `${path}/socket.io`;
|
|
2232
2504
|
return new Promise((resolve, reject) => {
|
|
2233
2505
|
const socket = socket_ioClient.io(remoteServerUrl, {
|
|
2234
2506
|
retries: CONNECTION_RETRIES_LIMIT,
|
|
2235
2507
|
timeout: CONNECTION_TIMEOUT_MS,
|
|
2236
|
-
path,
|
|
2237
|
-
transports: [
|
|
2508
|
+
path: '/socket.io',
|
|
2509
|
+
transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
|
|
2238
2510
|
});
|
|
2239
2511
|
// console.log('Connecting to', this.options.remoteServerUrl.href, { socket });
|
|
2240
2512
|
socket.on('connect', () => {
|
|
@@ -2359,6 +2631,53 @@
|
|
|
2359
2631
|
* TODO: [🧠] Maybe remove `@promptbook/remote-client` and just use `@promptbook/core`
|
|
2360
2632
|
*/
|
|
2361
2633
|
|
|
2634
|
+
/**
|
|
2635
|
+
* Stores data in memory (HEAP)
|
|
2636
|
+
*
|
|
2637
|
+
* @public exported from `@promptbook/core`
|
|
2638
|
+
*/
|
|
2639
|
+
class MemoryStorage {
|
|
2640
|
+
constructor() {
|
|
2641
|
+
this.storage = {};
|
|
2642
|
+
}
|
|
2643
|
+
/**
|
|
2644
|
+
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
2645
|
+
*/
|
|
2646
|
+
get length() {
|
|
2647
|
+
return Object.keys(this.storage).length;
|
|
2648
|
+
}
|
|
2649
|
+
/**
|
|
2650
|
+
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
2651
|
+
*/
|
|
2652
|
+
clear() {
|
|
2653
|
+
this.storage = {};
|
|
2654
|
+
}
|
|
2655
|
+
/**
|
|
2656
|
+
* Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
|
|
2657
|
+
*/
|
|
2658
|
+
getItem(key) {
|
|
2659
|
+
return this.storage[key] || null;
|
|
2660
|
+
}
|
|
2661
|
+
/**
|
|
2662
|
+
* Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
|
|
2663
|
+
*/
|
|
2664
|
+
key(index) {
|
|
2665
|
+
return Object.keys(this.storage)[index] || null;
|
|
2666
|
+
}
|
|
2667
|
+
/**
|
|
2668
|
+
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
2669
|
+
*/
|
|
2670
|
+
setItem(key, value) {
|
|
2671
|
+
this.storage[key] = value;
|
|
2672
|
+
}
|
|
2673
|
+
/**
|
|
2674
|
+
* Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
|
|
2675
|
+
*/
|
|
2676
|
+
removeItem(key) {
|
|
2677
|
+
delete this.storage[key];
|
|
2678
|
+
}
|
|
2679
|
+
}
|
|
2680
|
+
|
|
2362
2681
|
/**
|
|
2363
2682
|
* Simple wrapper `new Date().toISOString()`
|
|
2364
2683
|
*
|
|
@@ -2645,74 +2964,11 @@
|
|
|
2645
2964
|
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
2646
2965
|
*/
|
|
2647
2966
|
|
|
2648
|
-
/**
|
|
2649
|
-
* Determines if the given path is a root path.
|
|
2650
|
-
*
|
|
2651
|
-
* Note: This does not check if the file exists only if the path is valid
|
|
2652
|
-
* @public exported from `@promptbook/utils`
|
|
2653
|
-
*/
|
|
2654
|
-
function isRootPath(value) {
|
|
2655
|
-
if (value === '/') {
|
|
2656
|
-
return true;
|
|
2657
|
-
}
|
|
2658
|
-
if (/^[A-Z]:\\$/i.test(value)) {
|
|
2659
|
-
return true;
|
|
2660
|
-
}
|
|
2661
|
-
return false;
|
|
2662
|
-
}
|
|
2663
|
-
/**
|
|
2664
|
-
* TODO: [🍏] Make for MacOS paths
|
|
2665
|
-
*/
|
|
2666
|
-
|
|
2667
|
-
/**
|
|
2668
|
-
* Provides the path to the `.env` file
|
|
2669
|
-
*
|
|
2670
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access .env file
|
|
2671
|
-
*
|
|
2672
|
-
* @private within the repository - for CLI utils
|
|
2673
|
-
*/
|
|
2674
|
-
async function $provideEnvFilepath() {
|
|
2675
|
-
if (!$isRunningInNode()) {
|
|
2676
|
-
throw new EnvironmentMismatchError('Function `$provideEnvFilepath` works only in Node.js environment');
|
|
2677
|
-
}
|
|
2678
|
-
const envFilePatterns = [
|
|
2679
|
-
'.env',
|
|
2680
|
-
'.env.test',
|
|
2681
|
-
'.env.local',
|
|
2682
|
-
'.env.development.local',
|
|
2683
|
-
'.env.development',
|
|
2684
|
-
'.env.production.local',
|
|
2685
|
-
'.env.production',
|
|
2686
|
-
'.env.prod.local',
|
|
2687
|
-
'.env.prod',
|
|
2688
|
-
// <- TODO: Maybe add more patterns
|
|
2689
|
-
];
|
|
2690
|
-
let rootDirname = process.cwd();
|
|
2691
|
-
up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
|
|
2692
|
-
for (const pattern of envFilePatterns) {
|
|
2693
|
-
const envFilename = path.join(rootDirname, pattern);
|
|
2694
|
-
if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
|
|
2695
|
-
$setUsedEnvFilename(envFilename);
|
|
2696
|
-
return envFilename;
|
|
2697
|
-
}
|
|
2698
|
-
}
|
|
2699
|
-
if (isRootPath(rootDirname)) {
|
|
2700
|
-
break up_to_root;
|
|
2701
|
-
}
|
|
2702
|
-
// Note: If the directory does not exist, try the parent directory
|
|
2703
|
-
rootDirname = path.join(rootDirname, '..');
|
|
2704
|
-
}
|
|
2705
|
-
return null;
|
|
2706
|
-
}
|
|
2707
|
-
/**
|
|
2708
|
-
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
2709
|
-
*/
|
|
2710
|
-
|
|
2711
2967
|
/**
|
|
2712
2968
|
* @@@
|
|
2713
2969
|
*
|
|
2714
2970
|
* @@@ .env
|
|
2715
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access
|
|
2971
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
|
|
2716
2972
|
*
|
|
2717
2973
|
* It looks for environment variables:
|
|
2718
2974
|
* - `process.env.OPENAI_API_KEY`
|
|
@@ -2726,7 +2982,7 @@
|
|
|
2726
2982
|
if (!$isRunningInNode()) {
|
|
2727
2983
|
throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
|
|
2728
2984
|
}
|
|
2729
|
-
const envFilepath = await $
|
|
2985
|
+
const envFilepath = await $provideEnvFilename();
|
|
2730
2986
|
if (envFilepath !== null) {
|
|
2731
2987
|
dotenv__namespace.config({ path: envFilepath });
|
|
2732
2988
|
}
|
|
@@ -2834,14 +3090,15 @@
|
|
|
2834
3090
|
}
|
|
2835
3091
|
}
|
|
2836
3092
|
catch (error) {
|
|
2837
|
-
|
|
3093
|
+
assertsError(error);
|
|
3094
|
+
if (error instanceof UnexpectedError) {
|
|
2838
3095
|
throw error;
|
|
2839
3096
|
}
|
|
2840
3097
|
errors.push({ llmExecutionTools, error });
|
|
2841
3098
|
}
|
|
2842
3099
|
}
|
|
2843
3100
|
if (errors.length === 1) {
|
|
2844
|
-
throw errors[0];
|
|
3101
|
+
throw errors[0].error;
|
|
2845
3102
|
}
|
|
2846
3103
|
else if (errors.length > 1) {
|
|
2847
3104
|
throw new PipelineExecutionError(
|
|
@@ -2988,7 +3245,7 @@
|
|
|
2988
3245
|
* Note: This function is not cached, every call creates new instance of `MultipleLlmExecutionTools`
|
|
2989
3246
|
*
|
|
2990
3247
|
* @@@ .env
|
|
2991
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access
|
|
3248
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
|
|
2992
3249
|
*
|
|
2993
3250
|
* It looks for environment variables:
|
|
2994
3251
|
* - `process.env.OPENAI_API_KEY`
|
|
@@ -3033,7 +3290,7 @@
|
|
|
3033
3290
|
/**
|
|
3034
3291
|
* Returns LLM tools for CLI
|
|
3035
3292
|
*
|
|
3036
|
-
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access
|
|
3293
|
+
* Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes this .env file
|
|
3037
3294
|
*
|
|
3038
3295
|
* @private within the repository - for CLI utils
|
|
3039
3296
|
*/
|
|
@@ -3042,18 +3299,27 @@
|
|
|
3042
3299
|
throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
|
|
3043
3300
|
}
|
|
3044
3301
|
options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
|
|
3045
|
-
const { strategy, isCacheReloaded } = options;
|
|
3302
|
+
const { isLoginloaded, strategy, isCacheReloaded } = options;
|
|
3046
3303
|
let llmExecutionTools;
|
|
3047
3304
|
if (strategy === 'REMOTE_SERVER') {
|
|
3048
3305
|
const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3306
|
+
const storage = new $EnvStorage();
|
|
3307
|
+
let key = `PROMPTBOOK_TOKEN`;
|
|
3308
|
+
if (remoteServerUrl !== DEFAULT_REMOTE_SERVER_URL) {
|
|
3309
|
+
key = `${key}_${remoteServerUrl.replace(/^https?:\/\//i, '')}`;
|
|
3310
|
+
}
|
|
3311
|
+
let identification = null;
|
|
3312
|
+
let promptbookToken = await storage.getItem(key);
|
|
3313
|
+
if (promptbookToken === null || isLoginloaded) {
|
|
3055
3314
|
identification = await loginPrompt();
|
|
3056
|
-
|
|
3315
|
+
// Note: When login prompt fails, `process.exit(1)` is called so no need to check for null
|
|
3316
|
+
if (identification.isAnonymous === false) {
|
|
3317
|
+
promptbookToken = identificationToPromptbookToken(identification);
|
|
3318
|
+
await storage.setItem(key, promptbookToken);
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
else {
|
|
3322
|
+
identification = promptbookTokenToIdentification(promptbookToken);
|
|
3057
3323
|
}
|
|
3058
3324
|
llmExecutionTools = new RemoteLlmExecutionTools({
|
|
3059
3325
|
remoteServerUrl,
|
|
@@ -3094,9 +3360,7 @@
|
|
|
3094
3360
|
return await fetch(urlOrRequest, init);
|
|
3095
3361
|
}
|
|
3096
3362
|
catch (error) {
|
|
3097
|
-
|
|
3098
|
-
throw error;
|
|
3099
|
-
}
|
|
3363
|
+
assertsError(error);
|
|
3100
3364
|
let url;
|
|
3101
3365
|
if (typeof urlOrRequest === 'string') {
|
|
3102
3366
|
url = urlOrRequest;
|
|
@@ -3135,8 +3399,8 @@
|
|
|
3135
3399
|
/**
|
|
3136
3400
|
* @private utility of CLI
|
|
3137
3401
|
*/
|
|
3138
|
-
function $provideLlmToolsForCli(options) {
|
|
3139
|
-
const { cliOptions: {
|
|
3402
|
+
async function $provideLlmToolsForCli(options) {
|
|
3403
|
+
const { isLoginloaded, cliOptions: {
|
|
3140
3404
|
/* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
|
|
3141
3405
|
let strategy;
|
|
3142
3406
|
if (/^b/i.test(provider)) {
|
|
@@ -3150,7 +3414,11 @@
|
|
|
3150
3414
|
process.exit(1);
|
|
3151
3415
|
}
|
|
3152
3416
|
if (strategy === 'BRING_YOUR_OWN_KEYS') {
|
|
3153
|
-
|
|
3417
|
+
if (isLoginloaded) {
|
|
3418
|
+
throw new UnexpectedError(`\`$provideLlmToolsForCli\` isLoginloaded is not supported for strategy "BRING_YOUR_OWN_KEYS"`);
|
|
3419
|
+
}
|
|
3420
|
+
const llm = await $provideLlmToolsForWizzardOrCli({ strategy, ...options });
|
|
3421
|
+
return { strategy, llm };
|
|
3154
3422
|
}
|
|
3155
3423
|
else if (strategy === 'REMOTE_SERVER') {
|
|
3156
3424
|
if (!isValidUrl(remoteServerUrlRaw)) {
|
|
@@ -3158,7 +3426,8 @@
|
|
|
3158
3426
|
process.exit(1);
|
|
3159
3427
|
}
|
|
3160
3428
|
const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
|
|
3161
|
-
|
|
3429
|
+
const llm = await $provideLlmToolsForWizzardOrCli({
|
|
3430
|
+
isLoginloaded,
|
|
3162
3431
|
strategy,
|
|
3163
3432
|
appId: CLI_APP_ID,
|
|
3164
3433
|
remoteServerUrl,
|
|
@@ -3168,6 +3437,10 @@
|
|
|
3168
3437
|
console.log(colors__default["default"].red(`You can not login to remote server in non-interactive mode`));
|
|
3169
3438
|
process.exit(1);
|
|
3170
3439
|
}
|
|
3440
|
+
console.info(colors__default["default"].cyan(spaceTrim__default["default"](`
|
|
3441
|
+
You will be logged in to ${remoteServerUrl}
|
|
3442
|
+
If you don't have an account, it will be created automatically.
|
|
3443
|
+
`)));
|
|
3171
3444
|
const { username, password } = await prompts__default["default"]([
|
|
3172
3445
|
{
|
|
3173
3446
|
type: 'text',
|
|
@@ -3185,7 +3458,6 @@
|
|
|
3185
3458
|
},
|
|
3186
3459
|
]);
|
|
3187
3460
|
const loginUrl = `${remoteServerUrl}/login`;
|
|
3188
|
-
console.log('!!!', { loginUrl });
|
|
3189
3461
|
// TODO: [🧠] Should we use normal `fetch` or `scraperFetch`
|
|
3190
3462
|
const response = await promptbookFetch(loginUrl, {
|
|
3191
3463
|
method: 'POST',
|
|
@@ -3198,20 +3470,7 @@
|
|
|
3198
3470
|
password,
|
|
3199
3471
|
}),
|
|
3200
3472
|
});
|
|
3201
|
-
|
|
3202
|
-
loginUrl,
|
|
3203
|
-
username,
|
|
3204
|
-
password,
|
|
3205
|
-
// type: response.type,
|
|
3206
|
-
// text: await response.text(),
|
|
3207
|
-
});
|
|
3208
|
-
const { isSuccess, message, error, identification } = (await response.json());
|
|
3209
|
-
console.log('!!!', {
|
|
3210
|
-
isSuccess,
|
|
3211
|
-
message,
|
|
3212
|
-
error,
|
|
3213
|
-
identification,
|
|
3214
|
-
});
|
|
3473
|
+
const { isSuccess, message, error, identification } = jsonParse(await response.text());
|
|
3215
3474
|
if (message) {
|
|
3216
3475
|
if (isSuccess) {
|
|
3217
3476
|
console.log(colors__default["default"].green(message));
|
|
@@ -3232,6 +3491,7 @@
|
|
|
3232
3491
|
return identification;
|
|
3233
3492
|
},
|
|
3234
3493
|
});
|
|
3494
|
+
return { strategy, llm };
|
|
3235
3495
|
}
|
|
3236
3496
|
else {
|
|
3237
3497
|
throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
|
|
@@ -3253,11 +3513,12 @@
|
|
|
3253
3513
|
listModelsCommand.alias('models');
|
|
3254
3514
|
listModelsCommand.alias('llm');
|
|
3255
3515
|
listModelsCommand.action(handleActionErrors(async (cliOptions) => {
|
|
3256
|
-
|
|
3257
|
-
// TODO: !!!!!! Not relevant for remote server and also for `about` command
|
|
3258
|
-
const llm = await $provideLlmToolsForCli({ cliOptions });
|
|
3516
|
+
const { strategy, llm } = await $provideLlmToolsForCli({ cliOptions });
|
|
3259
3517
|
$sideEffect(llm);
|
|
3260
3518
|
// <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
|
|
3519
|
+
if (strategy !== 'BRING_YOUR_OWN_KEYS') {
|
|
3520
|
+
console.warn(colors__default["default"].yellow(`You are using --strategy ${strategy} but models listed below are relevant for --strategy BRING_YOUR_OWN_KEYS`));
|
|
3521
|
+
}
|
|
3261
3522
|
console.info($registeredLlmToolsMessage());
|
|
3262
3523
|
return process.exit(0);
|
|
3263
3524
|
}));
|
|
@@ -3440,9 +3701,7 @@
|
|
|
3440
3701
|
return result.trim();
|
|
3441
3702
|
}
|
|
3442
3703
|
catch (error) {
|
|
3443
|
-
|
|
3444
|
-
throw error;
|
|
3445
|
-
}
|
|
3704
|
+
assertsError(error);
|
|
3446
3705
|
return null;
|
|
3447
3706
|
}
|
|
3448
3707
|
}
|
|
@@ -3497,9 +3756,7 @@
|
|
|
3497
3756
|
return result.trim() + toExec;
|
|
3498
3757
|
}
|
|
3499
3758
|
catch (error) {
|
|
3500
|
-
|
|
3501
|
-
throw error;
|
|
3502
|
-
}
|
|
3759
|
+
assertsError(error);
|
|
3503
3760
|
return null;
|
|
3504
3761
|
}
|
|
3505
3762
|
}
|
|
@@ -3530,9 +3787,7 @@
|
|
|
3530
3787
|
throw new Error(`Can not locate app ${appName} on Windows.`);
|
|
3531
3788
|
}
|
|
3532
3789
|
catch (error) {
|
|
3533
|
-
|
|
3534
|
-
throw error;
|
|
3535
|
-
}
|
|
3790
|
+
assertsError(error);
|
|
3536
3791
|
return null;
|
|
3537
3792
|
}
|
|
3538
3793
|
}
|
|
@@ -3791,6 +4046,7 @@
|
|
|
3791
4046
|
`));
|
|
3792
4047
|
listModelsCommand.alias('scrapers');
|
|
3793
4048
|
listModelsCommand.action(handleActionErrors(async () => {
|
|
4049
|
+
// TODO: [🌞] Do not allow on REMOTE_SERVER strategy
|
|
3794
4050
|
const scrapers = await $provideScrapersForNode({});
|
|
3795
4051
|
const executables = await $provideExecutablesForNode();
|
|
3796
4052
|
console.info(spaceTrim__default["default"]((block) => `
|
|
@@ -3826,42 +4082,20 @@
|
|
|
3826
4082
|
loginCommand.description(spaceTrim__default["default"](`
|
|
3827
4083
|
Login to the remote Promptbook server
|
|
3828
4084
|
`));
|
|
3829
|
-
loginCommand.action(handleActionErrors(async () => {
|
|
3830
|
-
//
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
{
|
|
3838
|
-
type: 'text',
|
|
3839
|
-
name: 'email',
|
|
3840
|
-
message: 'Enter your email:',
|
|
3841
|
-
validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
|
|
3842
|
-
},
|
|
3843
|
-
{
|
|
3844
|
-
type: 'password',
|
|
3845
|
-
name: 'password',
|
|
3846
|
-
message: 'Enter your password:',
|
|
3847
|
-
validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0 ? true : 'Password is required',
|
|
4085
|
+
loginCommand.action(handleActionErrors(async (cliOptions) => {
|
|
4086
|
+
// Note: Not interested in return value of this function but the side effect of logging in
|
|
4087
|
+
await $provideLlmToolsForCli({
|
|
4088
|
+
isLoginloaded: true,
|
|
4089
|
+
cliOptions: {
|
|
4090
|
+
...cliOptions,
|
|
4091
|
+
strategy: 'REMOTE_SERVER', // <- Note: Overriding strategy to `REMOTE_SERVER`
|
|
4092
|
+
// TODO: Do not allow flag `--strategy` in `login` command at all
|
|
3848
4093
|
},
|
|
3849
|
-
|
|
3850
|
-
TODO_USE(email, password);
|
|
3851
|
-
await waitasecond.forTime(1000);
|
|
3852
|
-
console.error(colors__default["default"].green(spaceTrim__default["default"](`
|
|
3853
|
-
Your account ${email} was successfully created.
|
|
3854
|
-
|
|
3855
|
-
Please verify your email:
|
|
3856
|
-
https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
|
|
3857
|
-
|
|
3858
|
-
After verification, you will receive 500 000 credits for free 🎉
|
|
3859
|
-
`)));
|
|
4094
|
+
});
|
|
3860
4095
|
return process.exit(0);
|
|
3861
4096
|
}));
|
|
3862
4097
|
}
|
|
3863
4098
|
/**
|
|
3864
|
-
* TODO: Pass remote server URL (and path)
|
|
3865
4099
|
* TODO: Implement non-interactive login
|
|
3866
4100
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3867
4101
|
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
@@ -4267,7 +4501,7 @@
|
|
|
4267
4501
|
if (!indexFile) {
|
|
4268
4502
|
throw new UnexpectedError(`Archive does not contain 'index.book.json' file`);
|
|
4269
4503
|
}
|
|
4270
|
-
const collectionJson =
|
|
4504
|
+
const collectionJson = jsonParse(await indexFile.async('text'));
|
|
4271
4505
|
for (const pipeline of collectionJson) {
|
|
4272
4506
|
validatePipeline(pipeline);
|
|
4273
4507
|
}
|
|
@@ -4277,11 +4511,14 @@
|
|
|
4277
4511
|
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
4278
4512
|
*/
|
|
4279
4513
|
|
|
4280
|
-
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"}];
|
|
4514
|
+
var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n```json\n{availableModels}\n```\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the workflow:\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
|
|
4281
4515
|
|
|
4282
4516
|
/**
|
|
4283
4517
|
* Function isValidJsonString will tell you if the string is valid JSON or not
|
|
4284
4518
|
*
|
|
4519
|
+
* @param value The string to check
|
|
4520
|
+
* @returns True if the string is a valid JSON string, false otherwise
|
|
4521
|
+
*
|
|
4285
4522
|
* @public exported from `@promptbook/utils`
|
|
4286
4523
|
*/
|
|
4287
4524
|
function isValidJsonString(value /* <- [👨⚖️] */) {
|
|
@@ -4290,9 +4527,7 @@
|
|
|
4290
4527
|
return true;
|
|
4291
4528
|
}
|
|
4292
4529
|
catch (error) {
|
|
4293
|
-
|
|
4294
|
-
throw error;
|
|
4295
|
-
}
|
|
4530
|
+
assertsError(error);
|
|
4296
4531
|
if (error.message.includes('Unexpected token')) {
|
|
4297
4532
|
return false;
|
|
4298
4533
|
}
|
|
@@ -4537,7 +4772,7 @@
|
|
|
4537
4772
|
*/
|
|
4538
4773
|
function unpreparePipeline(pipeline) {
|
|
4539
4774
|
let { personas, knowledgeSources, tasks } = pipeline;
|
|
4540
|
-
personas = personas.map((persona) => ({ ...persona,
|
|
4775
|
+
personas = personas.map((persona) => ({ ...persona, modelsRequirements: undefined, preparationIds: undefined }));
|
|
4541
4776
|
knowledgeSources = knowledgeSources.map((knowledgeSource) => ({ ...knowledgeSource, preparationIds: undefined }));
|
|
4542
4777
|
tasks = tasks.map((task) => {
|
|
4543
4778
|
let { dependentParameterNames } = task;
|
|
@@ -4695,7 +4930,7 @@
|
|
|
4695
4930
|
if (pipeline.title === undefined || pipeline.title === '' || pipeline.title === DEFAULT_BOOK_TITLE) {
|
|
4696
4931
|
return false;
|
|
4697
4932
|
}
|
|
4698
|
-
if (!pipeline.personas.every((persona) => persona.
|
|
4933
|
+
if (!pipeline.personas.every((persona) => persona.modelsRequirements !== undefined)) {
|
|
4699
4934
|
return false;
|
|
4700
4935
|
}
|
|
4701
4936
|
if (!pipeline.knowledgeSources.every((knowledgeSource) => knowledgeSource.preparationIds !== undefined)) {
|
|
@@ -4737,7 +4972,7 @@
|
|
|
4737
4972
|
const newObject = { ...object };
|
|
4738
4973
|
for (const [key, value] of Object.entries(object)) {
|
|
4739
4974
|
if (typeof value === 'string' && isValidJsonString(value)) {
|
|
4740
|
-
newObject[key] =
|
|
4975
|
+
newObject[key] = jsonParse(value);
|
|
4741
4976
|
}
|
|
4742
4977
|
else {
|
|
4743
4978
|
newObject[key] = jsonStringsToJsons(value);
|
|
@@ -4823,8 +5058,8 @@
|
|
|
4823
5058
|
updatedAt = new Date();
|
|
4824
5059
|
errors.push(...executionResult.errors);
|
|
4825
5060
|
warnings.push(...executionResult.warnings);
|
|
4826
|
-
// <- TODO:
|
|
4827
|
-
// TODO: [🧠]
|
|
5061
|
+
// <- TODO: [🌂] Only unique errors and warnings should be added (or filtered)
|
|
5062
|
+
// TODO: [🧠] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
|
|
4828
5063
|
// Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
|
|
4829
5064
|
// And delete `ExecutionTask.currentValue.preparedPipeline`
|
|
4830
5065
|
assertsTaskSuccessful(executionResult);
|
|
@@ -4834,6 +5069,7 @@
|
|
|
4834
5069
|
partialResultSubject.next(executionResult);
|
|
4835
5070
|
}
|
|
4836
5071
|
catch (error) {
|
|
5072
|
+
assertsError(error);
|
|
4837
5073
|
status = 'ERROR';
|
|
4838
5074
|
errors.push(error);
|
|
4839
5075
|
partialResultSubject.error(error);
|
|
@@ -4979,13 +5215,19 @@
|
|
|
4979
5215
|
return value.toISOString();
|
|
4980
5216
|
}
|
|
4981
5217
|
else {
|
|
4982
|
-
|
|
5218
|
+
try {
|
|
5219
|
+
return JSON.stringify(value);
|
|
5220
|
+
}
|
|
5221
|
+
catch (error) {
|
|
5222
|
+
if (error instanceof TypeError && error.message.includes('circular structure')) {
|
|
5223
|
+
return VALUE_STRINGS.circular;
|
|
5224
|
+
}
|
|
5225
|
+
throw error;
|
|
5226
|
+
}
|
|
4983
5227
|
}
|
|
4984
5228
|
}
|
|
4985
5229
|
catch (error) {
|
|
4986
|
-
|
|
4987
|
-
throw error;
|
|
4988
|
-
}
|
|
5230
|
+
assertsError(error);
|
|
4989
5231
|
console.error(error);
|
|
4990
5232
|
return VALUE_STRINGS.unserializable;
|
|
4991
5233
|
}
|
|
@@ -5042,9 +5284,7 @@
|
|
|
5042
5284
|
}
|
|
5043
5285
|
}
|
|
5044
5286
|
catch (error) {
|
|
5045
|
-
|
|
5046
|
-
throw error;
|
|
5047
|
-
}
|
|
5287
|
+
assertsError(error);
|
|
5048
5288
|
throw new ParseError(spaceTrim.spaceTrim((block) => `
|
|
5049
5289
|
Can not extract variables from the script
|
|
5050
5290
|
${block(error.stack || error.message)}
|
|
@@ -5163,6 +5403,46 @@
|
|
|
5163
5403
|
// encoding: 'utf-8',
|
|
5164
5404
|
});
|
|
5165
5405
|
|
|
5406
|
+
/**
|
|
5407
|
+
* Function to check if a string is valid CSV
|
|
5408
|
+
*
|
|
5409
|
+
* @param value The string to check
|
|
5410
|
+
* @returns True if the string is a valid CSV string, false otherwise
|
|
5411
|
+
*
|
|
5412
|
+
* @public exported from `@promptbook/utils`
|
|
5413
|
+
*/
|
|
5414
|
+
function isValidCsvString(value) {
|
|
5415
|
+
try {
|
|
5416
|
+
// A simple check for CSV format: at least one comma and no invalid characters
|
|
5417
|
+
if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
|
|
5418
|
+
return true;
|
|
5419
|
+
}
|
|
5420
|
+
return false;
|
|
5421
|
+
}
|
|
5422
|
+
catch (error) {
|
|
5423
|
+
assertsError(error);
|
|
5424
|
+
return false;
|
|
5425
|
+
}
|
|
5426
|
+
}
|
|
5427
|
+
|
|
5428
|
+
/**
|
|
5429
|
+
* Converts a CSV string into an object
|
|
5430
|
+
*
|
|
5431
|
+
* Note: This is wrapper around `papaparse.parse()` with better autohealing
|
|
5432
|
+
*
|
|
5433
|
+
* @private - for now until `@promptbook/csv` is released
|
|
5434
|
+
*/
|
|
5435
|
+
function csvParse(value /* <- TODO: string_csv */, settings, schema /* <- TODO: Make CSV Schemas */) {
|
|
5436
|
+
settings = { ...settings, ...MANDATORY_CSV_SETTINGS };
|
|
5437
|
+
// Note: Autoheal invalid '\n' characters
|
|
5438
|
+
if (settings.newline && !settings.newline.includes('\r') && value.includes('\r')) {
|
|
5439
|
+
console.warn('CSV string contains carriage return characters, but in the CSV settings the `newline` setting does not include them. Autohealing the CSV string.');
|
|
5440
|
+
value = value.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
|
|
5441
|
+
}
|
|
5442
|
+
const csv = papaparse.parse(value, settings);
|
|
5443
|
+
return csv;
|
|
5444
|
+
}
|
|
5445
|
+
|
|
5166
5446
|
/**
|
|
5167
5447
|
* Definition for CSV spreadsheet
|
|
5168
5448
|
*
|
|
@@ -5173,7 +5453,7 @@
|
|
|
5173
5453
|
formatName: 'CSV',
|
|
5174
5454
|
aliases: ['SPREADSHEET', 'TABLE'],
|
|
5175
5455
|
isValid(value, settings, schema) {
|
|
5176
|
-
return
|
|
5456
|
+
return isValidCsvString(value);
|
|
5177
5457
|
},
|
|
5178
5458
|
canBeValid(partialValue, settings, schema) {
|
|
5179
5459
|
return true;
|
|
@@ -5185,8 +5465,7 @@
|
|
|
5185
5465
|
{
|
|
5186
5466
|
subvalueName: 'ROW',
|
|
5187
5467
|
async mapValues(value, outputParameterName, settings, mapCallback) {
|
|
5188
|
-
|
|
5189
|
-
const csv = papaparse.parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
|
|
5468
|
+
const csv = csvParse(value, settings);
|
|
5190
5469
|
if (csv.errors.length !== 0) {
|
|
5191
5470
|
throw new CsvFormatError(spaceTrim__default["default"]((block) => `
|
|
5192
5471
|
CSV parsing error
|
|
@@ -5216,8 +5495,7 @@
|
|
|
5216
5495
|
{
|
|
5217
5496
|
subvalueName: 'CELL',
|
|
5218
5497
|
async mapValues(value, outputParameterName, settings, mapCallback) {
|
|
5219
|
-
|
|
5220
|
-
const csv = papaparse.parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
|
|
5498
|
+
const csv = csvParse(value, settings);
|
|
5221
5499
|
if (csv.errors.length !== 0) {
|
|
5222
5500
|
throw new CsvFormatError(spaceTrim__default["default"]((block) => `
|
|
5223
5501
|
CSV parsing error
|
|
@@ -5327,6 +5605,30 @@
|
|
|
5327
5605
|
* TODO: [🏢] Allow to expect something inside each item of list and other formats
|
|
5328
5606
|
*/
|
|
5329
5607
|
|
|
5608
|
+
/**
|
|
5609
|
+
* Function to check if a string is valid XML
|
|
5610
|
+
*
|
|
5611
|
+
* @param value
|
|
5612
|
+
* @returns True if the string is a valid XML string, false otherwise
|
|
5613
|
+
*
|
|
5614
|
+
* @public exported from `@promptbook/utils`
|
|
5615
|
+
*/
|
|
5616
|
+
function isValidXmlString(value) {
|
|
5617
|
+
try {
|
|
5618
|
+
const parser = new DOMParser();
|
|
5619
|
+
const parsedDocument = parser.parseFromString(value, 'application/xml');
|
|
5620
|
+
const parserError = parsedDocument.getElementsByTagName('parsererror');
|
|
5621
|
+
if (parserError.length > 0) {
|
|
5622
|
+
return false;
|
|
5623
|
+
}
|
|
5624
|
+
return true;
|
|
5625
|
+
}
|
|
5626
|
+
catch (error) {
|
|
5627
|
+
assertsError(error);
|
|
5628
|
+
return false;
|
|
5629
|
+
}
|
|
5630
|
+
}
|
|
5631
|
+
|
|
5330
5632
|
/**
|
|
5331
5633
|
* Definition for XML format
|
|
5332
5634
|
*
|
|
@@ -5336,7 +5638,7 @@
|
|
|
5336
5638
|
formatName: 'XML',
|
|
5337
5639
|
mimeType: 'application/xml',
|
|
5338
5640
|
isValid(value, settings, schema) {
|
|
5339
|
-
return
|
|
5641
|
+
return isValidXmlString(value);
|
|
5340
5642
|
},
|
|
5341
5643
|
canBeValid(partialValue, settings, schema) {
|
|
5342
5644
|
return true;
|
|
@@ -5928,9 +6230,7 @@
|
|
|
5928
6230
|
break scripts;
|
|
5929
6231
|
}
|
|
5930
6232
|
catch (error) {
|
|
5931
|
-
|
|
5932
|
-
throw error;
|
|
5933
|
-
}
|
|
6233
|
+
assertsError(error);
|
|
5934
6234
|
if (error instanceof UnexpectedError) {
|
|
5935
6235
|
throw error;
|
|
5936
6236
|
}
|
|
@@ -6000,9 +6300,7 @@
|
|
|
6000
6300
|
break scripts;
|
|
6001
6301
|
}
|
|
6002
6302
|
catch (error) {
|
|
6003
|
-
|
|
6004
|
-
throw error;
|
|
6005
|
-
}
|
|
6303
|
+
assertsError(error);
|
|
6006
6304
|
if (error instanceof UnexpectedError) {
|
|
6007
6305
|
throw error;
|
|
6008
6306
|
}
|
|
@@ -6245,13 +6543,79 @@
|
|
|
6245
6543
|
/**
|
|
6246
6544
|
* @@@
|
|
6247
6545
|
*
|
|
6546
|
+
* Here is the place where RAG (retrieval-augmented generation) happens
|
|
6547
|
+
*
|
|
6248
6548
|
* @private internal utility of `createPipelineExecutor`
|
|
6249
6549
|
*/
|
|
6250
6550
|
async function getKnowledgeForTask(options) {
|
|
6251
|
-
const { preparedPipeline, task } = options;
|
|
6252
|
-
|
|
6551
|
+
const { tools, preparedPipeline, task } = options;
|
|
6552
|
+
const firstKnowlegePiece = preparedPipeline.knowledgePieces[0];
|
|
6553
|
+
const firstKnowlegeIndex = firstKnowlegePiece === null || firstKnowlegePiece === void 0 ? void 0 : firstKnowlegePiece.index[0];
|
|
6554
|
+
// <- TODO: Do not use just first knowledge piece and first index to determine embedding model, use also keyword search
|
|
6555
|
+
if (firstKnowlegePiece === undefined || firstKnowlegeIndex === undefined) {
|
|
6556
|
+
return 'No knowledge pieces found';
|
|
6557
|
+
}
|
|
6558
|
+
// TODO: [🚐] Make arrayable LLMs -> single LLM DRY
|
|
6559
|
+
const _llms = arrayableToArray(tools.llm);
|
|
6560
|
+
const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
|
|
6561
|
+
const taskEmbeddingPrompt = {
|
|
6562
|
+
title: 'Knowledge Search',
|
|
6563
|
+
modelRequirements: {
|
|
6564
|
+
modelVariant: 'EMBEDDING',
|
|
6565
|
+
modelName: firstKnowlegeIndex.modelName,
|
|
6566
|
+
},
|
|
6567
|
+
content: task.content,
|
|
6568
|
+
parameters: {
|
|
6569
|
+
/* !!!!!!!! */
|
|
6570
|
+
},
|
|
6571
|
+
};
|
|
6572
|
+
const taskEmbeddingResult = await llmTools.callEmbeddingModel(taskEmbeddingPrompt);
|
|
6573
|
+
const knowledgePiecesWithRelevance = preparedPipeline.knowledgePieces.map((knowledgePiece) => {
|
|
6574
|
+
const { index } = knowledgePiece;
|
|
6575
|
+
const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowlegeIndex.modelName);
|
|
6576
|
+
// <- TODO: Do not use just first knowledge piece and first index to determine embedding model
|
|
6577
|
+
if (knowledgePieceIndex === undefined) {
|
|
6578
|
+
return {
|
|
6579
|
+
content: knowledgePiece.content,
|
|
6580
|
+
relevance: 0,
|
|
6581
|
+
};
|
|
6582
|
+
}
|
|
6583
|
+
const relevance = computeCosineSimilarity(knowledgePieceIndex.position, taskEmbeddingResult.content);
|
|
6584
|
+
return {
|
|
6585
|
+
content: knowledgePiece.content,
|
|
6586
|
+
relevance,
|
|
6587
|
+
};
|
|
6588
|
+
});
|
|
6589
|
+
const knowledgePiecesSorted = knowledgePiecesWithRelevance.sort((a, b) => a.relevance - b.relevance);
|
|
6590
|
+
const knowledgePiecesLimited = knowledgePiecesSorted.slice(0, 5);
|
|
6591
|
+
console.log('!!! Embedding', {
|
|
6592
|
+
task,
|
|
6593
|
+
taskEmbeddingPrompt,
|
|
6594
|
+
taskEmbeddingResult,
|
|
6595
|
+
firstKnowlegePiece,
|
|
6596
|
+
firstKnowlegeIndex,
|
|
6597
|
+
knowledgePiecesWithRelevance,
|
|
6598
|
+
knowledgePiecesSorted,
|
|
6599
|
+
knowledgePiecesLimited,
|
|
6600
|
+
});
|
|
6601
|
+
return knowledgePiecesLimited.map(({ content }) => `- ${content}`).join('\n');
|
|
6253
6602
|
// <- TODO: [🧠] Some smart aggregation of knowledge pieces, single-line vs multi-line vs mixed
|
|
6254
6603
|
}
|
|
6604
|
+
// TODO: !!!!!! Annotate + to new file
|
|
6605
|
+
function computeCosineSimilarity(embeddingVector1, embeddingVector2) {
|
|
6606
|
+
if (embeddingVector1.length !== embeddingVector2.length) {
|
|
6607
|
+
throw new TypeError('Embedding vectors must have the same length');
|
|
6608
|
+
}
|
|
6609
|
+
const dotProduct = embeddingVector1.reduce((sum, value, index) => sum + value * embeddingVector2[index], 0);
|
|
6610
|
+
const magnitude1 = Math.sqrt(embeddingVector1.reduce((sum, value) => sum + value * value, 0));
|
|
6611
|
+
const magnitude2 = Math.sqrt(embeddingVector2.reduce((sum, value) => sum + value * value, 0));
|
|
6612
|
+
return 1 - dotProduct / (magnitude1 * magnitude2);
|
|
6613
|
+
}
|
|
6614
|
+
/**
|
|
6615
|
+
* TODO: !!!! Verify if this is working
|
|
6616
|
+
* TODO: [♨] Implement Better - use keyword search
|
|
6617
|
+
* TODO: [♨] Examples of values
|
|
6618
|
+
*/
|
|
6255
6619
|
|
|
6256
6620
|
/**
|
|
6257
6621
|
* @@@
|
|
@@ -6259,9 +6623,9 @@
|
|
|
6259
6623
|
* @private internal utility of `createPipelineExecutor`
|
|
6260
6624
|
*/
|
|
6261
6625
|
async function getReservedParametersForTask(options) {
|
|
6262
|
-
const { preparedPipeline, task, pipelineIdentification } = options;
|
|
6626
|
+
const { tools, preparedPipeline, task, pipelineIdentification } = options;
|
|
6263
6627
|
const context = await getContextForTask(); // <- [🏍]
|
|
6264
|
-
const knowledge = await getKnowledgeForTask({ preparedPipeline, task });
|
|
6628
|
+
const knowledge = await getKnowledgeForTask({ tools, preparedPipeline, task });
|
|
6265
6629
|
const examples = await getExamplesForTask();
|
|
6266
6630
|
const currentDate = new Date().toISOString(); // <- TODO: [🧠][💩] Better
|
|
6267
6631
|
const modelName = RESERVED_PARAMETER_MISSING_VALUE;
|
|
@@ -6323,6 +6687,7 @@
|
|
|
6323
6687
|
}
|
|
6324
6688
|
const definedParameters = Object.freeze({
|
|
6325
6689
|
...(await getReservedParametersForTask({
|
|
6690
|
+
tools,
|
|
6326
6691
|
preparedPipeline,
|
|
6327
6692
|
task: currentTask,
|
|
6328
6693
|
pipelineIdentification,
|
|
@@ -6623,9 +6988,7 @@
|
|
|
6623
6988
|
await Promise.all(resolving);
|
|
6624
6989
|
}
|
|
6625
6990
|
catch (error /* <- Note: [3] */) {
|
|
6626
|
-
|
|
6627
|
-
throw error;
|
|
6628
|
-
}
|
|
6991
|
+
assertsError(error);
|
|
6629
6992
|
// Note: No need to rethrow UnexpectedError
|
|
6630
6993
|
// if (error instanceof UnexpectedError) {
|
|
6631
6994
|
// Note: Count usage, [🧠] Maybe put to separate function executionReportJsonToUsage + DRY [🤹♂️]
|
|
@@ -6810,27 +7173,48 @@
|
|
|
6810
7173
|
pipeline: await collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book'),
|
|
6811
7174
|
tools,
|
|
6812
7175
|
});
|
|
6813
|
-
// TODO: [🚐] Make arrayable LLMs -> single LLM DRY
|
|
6814
7176
|
const _llms = arrayableToArray(tools.llm);
|
|
6815
7177
|
const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
|
|
6816
|
-
const availableModels = await llmTools.listModels()
|
|
6817
|
-
const availableModelNames = availableModels
|
|
7178
|
+
const availableModels = (await llmTools.listModels())
|
|
6818
7179
|
.filter(({ modelVariant }) => modelVariant === 'CHAT')
|
|
6819
|
-
.map(({ modelName }) =>
|
|
6820
|
-
|
|
6821
|
-
|
|
7180
|
+
.map(({ modelName, modelDescription }) => ({
|
|
7181
|
+
modelName,
|
|
7182
|
+
modelDescription,
|
|
7183
|
+
// <- Note: `modelTitle` and `modelVariant` is not relevant for this task
|
|
7184
|
+
}));
|
|
7185
|
+
const result = await preparePersonaExecutor({
|
|
7186
|
+
availableModels /* <- Note: Passing as JSON */,
|
|
7187
|
+
personaDescription,
|
|
7188
|
+
}).asPromise();
|
|
6822
7189
|
const { outputParameters } = result;
|
|
6823
|
-
const {
|
|
6824
|
-
|
|
7190
|
+
const { modelsRequirements: modelsRequirementsJson } = outputParameters;
|
|
7191
|
+
let modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
|
|
6825
7192
|
if (isVerbose) {
|
|
6826
|
-
console.info(`PERSONA ${personaDescription}`,
|
|
7193
|
+
console.info(`PERSONA ${personaDescription}`, modelsRequirementsUnchecked);
|
|
6827
7194
|
}
|
|
6828
|
-
|
|
6829
|
-
|
|
7195
|
+
if (!Array.isArray(modelsRequirementsUnchecked)) {
|
|
7196
|
+
// <- TODO: Book should have syntax and system to enforce shape of JSON
|
|
7197
|
+
modelsRequirementsUnchecked = [modelsRequirementsUnchecked];
|
|
7198
|
+
/*
|
|
7199
|
+
throw new UnexpectedError(
|
|
7200
|
+
spaceTrim(
|
|
7201
|
+
(block) => `
|
|
7202
|
+
Invalid \`modelsRequirements\`:
|
|
7203
|
+
|
|
7204
|
+
\`\`\`json
|
|
7205
|
+
${block(JSON.stringify(modelsRequirementsUnchecked, null, 4))}
|
|
7206
|
+
\`\`\`
|
|
7207
|
+
`,
|
|
7208
|
+
),
|
|
7209
|
+
);
|
|
7210
|
+
*/
|
|
7211
|
+
}
|
|
7212
|
+
const modelsRequirements = modelsRequirementsUnchecked.map((modelRequirements) => ({
|
|
6830
7213
|
modelVariant: 'CHAT',
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
7214
|
+
...modelRequirements,
|
|
7215
|
+
}));
|
|
7216
|
+
return {
|
|
7217
|
+
modelsRequirements,
|
|
6834
7218
|
};
|
|
6835
7219
|
}
|
|
6836
7220
|
/**
|
|
@@ -6999,7 +7383,7 @@
|
|
|
6999
7383
|
> },
|
|
7000
7384
|
*/
|
|
7001
7385
|
async asJson() {
|
|
7002
|
-
return
|
|
7386
|
+
return jsonParse(await tools.fs.readFile(filename, 'utf-8'));
|
|
7003
7387
|
},
|
|
7004
7388
|
async asText() {
|
|
7005
7389
|
return await tools.fs.readFile(filename, 'utf-8');
|
|
@@ -7101,9 +7485,7 @@
|
|
|
7101
7485
|
knowledgePreparedUnflatten[index] = pieces;
|
|
7102
7486
|
}
|
|
7103
7487
|
catch (error) {
|
|
7104
|
-
|
|
7105
|
-
throw error;
|
|
7106
|
-
}
|
|
7488
|
+
assertsError(error);
|
|
7107
7489
|
console.warn(error);
|
|
7108
7490
|
// <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
7109
7491
|
}
|
|
@@ -7259,14 +7641,14 @@
|
|
|
7259
7641
|
// TODO: [🖌][🧠] Implement some `mapAsync` function
|
|
7260
7642
|
const preparedPersonas = new Array(personas.length);
|
|
7261
7643
|
await forEachAsync(personas, { maxParallelCount /* <- TODO: [🪂] When there are subtasks, this maximul limit can be broken */ }, async (persona, index) => {
|
|
7262
|
-
const
|
|
7644
|
+
const { modelsRequirements } = await preparePersona(persona.description, { ...tools, llm: llmToolsWithUsage }, {
|
|
7263
7645
|
rootDirname,
|
|
7264
7646
|
maxParallelCount /* <- TODO: [🪂] */,
|
|
7265
7647
|
isVerbose,
|
|
7266
7648
|
});
|
|
7267
7649
|
const preparedPersona = {
|
|
7268
7650
|
...persona,
|
|
7269
|
-
|
|
7651
|
+
modelsRequirements,
|
|
7270
7652
|
preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id],
|
|
7271
7653
|
// <- TODO: [🍙] Make some standard order of json properties
|
|
7272
7654
|
};
|
|
@@ -7901,6 +8283,8 @@
|
|
|
7901
8283
|
*/
|
|
7902
8284
|
|
|
7903
8285
|
/**
|
|
8286
|
+
import { WrappedError } from '../../errors/WrappedError';
|
|
8287
|
+
import { assertsError } from '../../errors/assertsError';
|
|
7904
8288
|
* Parses the expect command
|
|
7905
8289
|
*
|
|
7906
8290
|
* @see `documentationUrl` for more details
|
|
@@ -7992,9 +8376,7 @@
|
|
|
7992
8376
|
};
|
|
7993
8377
|
}
|
|
7994
8378
|
catch (error) {
|
|
7995
|
-
|
|
7996
|
-
throw error;
|
|
7997
|
-
}
|
|
8379
|
+
assertsError(error);
|
|
7998
8380
|
throw new ParseError(spaceTrim__default["default"]((block) => `
|
|
7999
8381
|
Invalid FORMAT command
|
|
8000
8382
|
${block(error.message)}:
|
|
@@ -11242,9 +11624,7 @@
|
|
|
11242
11624
|
}
|
|
11243
11625
|
}
|
|
11244
11626
|
catch (error) {
|
|
11245
|
-
|
|
11246
|
-
throw error;
|
|
11247
|
-
}
|
|
11627
|
+
assertsError(error);
|
|
11248
11628
|
if (error instanceof ReferenceError) {
|
|
11249
11629
|
const undefinedName = error.message.split(' ')[0];
|
|
11250
11630
|
/*
|
|
@@ -11519,9 +11899,7 @@
|
|
|
11519
11899
|
// ---
|
|
11520
11900
|
}
|
|
11521
11901
|
catch (error) {
|
|
11522
|
-
|
|
11523
|
-
throw error;
|
|
11524
|
-
}
|
|
11902
|
+
assertsError(error);
|
|
11525
11903
|
// TODO: [7] DRY
|
|
11526
11904
|
const wrappedErrorMessage = spaceTrim__default["default"]((block) => `
|
|
11527
11905
|
${error.name} in pipeline ${fileName.split('\\').join('/')}:
|
|
@@ -11612,9 +11990,7 @@
|
|
|
11612
11990
|
}
|
|
11613
11991
|
}
|
|
11614
11992
|
catch (error) {
|
|
11615
|
-
|
|
11616
|
-
throw error;
|
|
11617
|
-
}
|
|
11993
|
+
assertsError(error);
|
|
11618
11994
|
// TODO: [7] DRY
|
|
11619
11995
|
const wrappedErrorMessage = spaceTrim__default["default"]((block) => `
|
|
11620
11996
|
${error.name} in pipeline ${fileName.split('\\').join('/')}:
|
|
@@ -11830,7 +12206,7 @@
|
|
|
11830
12206
|
isCacheReloaded,
|
|
11831
12207
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
11832
12208
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
11833
|
-
const llm = await $provideLlmToolsForCli({
|
|
12209
|
+
const { llm } = await $provideLlmToolsForCli({
|
|
11834
12210
|
cliOptions,
|
|
11835
12211
|
...prepareAndScrapeOptions,
|
|
11836
12212
|
});
|
|
@@ -12123,9 +12499,7 @@
|
|
|
12123
12499
|
}
|
|
12124
12500
|
}
|
|
12125
12501
|
catch (error) {
|
|
12126
|
-
|
|
12127
|
-
throw error;
|
|
12128
|
-
}
|
|
12502
|
+
assertsError(error);
|
|
12129
12503
|
console.info(colors__default["default"].red(`Prettify ${error.name} ${filename}`));
|
|
12130
12504
|
console.error(colors__default["default"].bgRed(`${error.name} in ${path.basename(__filename)}`));
|
|
12131
12505
|
console.error(colors__default["default"].red(error.stack || error.message));
|
|
@@ -12445,9 +12819,7 @@
|
|
|
12445
12819
|
return true;
|
|
12446
12820
|
}
|
|
12447
12821
|
catch (error) {
|
|
12448
|
-
|
|
12449
|
-
throw error;
|
|
12450
|
-
}
|
|
12822
|
+
assertsError(error);
|
|
12451
12823
|
return false;
|
|
12452
12824
|
}
|
|
12453
12825
|
}
|
|
@@ -12672,9 +13044,7 @@
|
|
|
12672
13044
|
ongoingParameters = result.outputParameters;
|
|
12673
13045
|
}
|
|
12674
13046
|
catch (error) {
|
|
12675
|
-
|
|
12676
|
-
throw error;
|
|
12677
|
-
}
|
|
13047
|
+
assertsError(error);
|
|
12678
13048
|
// TODO: Allow to ressurect the chatbot after an error - prompt the user to continue
|
|
12679
13049
|
console.error(colors__default["default"].red(error.stack || error.message));
|
|
12680
13050
|
return process.exit(1);
|
|
@@ -12707,7 +13077,6 @@
|
|
|
12707
13077
|
runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
|
|
12708
13078
|
runCommand.option('-s, --save-report <path>', `Save report to file`);
|
|
12709
13079
|
runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
|
|
12710
|
-
console.log('!!!', cliOptions);
|
|
12711
13080
|
const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
|
|
12712
13081
|
if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
|
|
12713
13082
|
console.error(colors__default["default"].red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
|
|
@@ -12719,7 +13088,7 @@
|
|
|
12719
13088
|
}
|
|
12720
13089
|
let inputParameters = {};
|
|
12721
13090
|
if (json) {
|
|
12722
|
-
inputParameters =
|
|
13091
|
+
inputParameters = jsonParse(json);
|
|
12723
13092
|
// <- TODO: Maybe check shape of passed JSON and if its valid parameters Record
|
|
12724
13093
|
}
|
|
12725
13094
|
// TODO: DRY [◽]
|
|
@@ -12733,12 +13102,10 @@
|
|
|
12733
13102
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
12734
13103
|
let llm;
|
|
12735
13104
|
try {
|
|
12736
|
-
llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13105
|
+
llm = (await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions })).llm;
|
|
12737
13106
|
}
|
|
12738
13107
|
catch (error) {
|
|
12739
|
-
|
|
12740
|
-
throw error;
|
|
12741
|
-
}
|
|
13108
|
+
assertsError(error);
|
|
12742
13109
|
if (!error.message.includes('No LLM tools')) {
|
|
12743
13110
|
throw error;
|
|
12744
13111
|
}
|
|
@@ -12936,12 +13303,610 @@
|
|
|
12936
13303
|
}));
|
|
12937
13304
|
}
|
|
12938
13305
|
/**
|
|
12939
|
-
* TODO: !!5 Catch and wrap all errors from CLI
|
|
12940
|
-
* TODO: [🧠] Pass `maxExecutionAttempts`, `csvSettings`
|
|
12941
|
-
* TODO: [🥃][main] !!3 Allow `ptbk run` without configuring any llm tools
|
|
13306
|
+
* TODO: !!5 Catch and wrap all errors from CLI
|
|
13307
|
+
* TODO: [🧠] Pass `maxExecutionAttempts`, `csvSettings`
|
|
13308
|
+
* TODO: [🥃][main] !!3 Allow `ptbk run` without configuring any llm tools
|
|
13309
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
13310
|
+
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
13311
|
+
* TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
|
|
13312
|
+
*/
|
|
13313
|
+
|
|
13314
|
+
// TODO: !!!! List running services from REMOTE_SERVER_URLS
|
|
13315
|
+
// TODO: !!!! Import directly from YML
|
|
13316
|
+
/**
|
|
13317
|
+
* @private !!!! Decide how to expose this
|
|
13318
|
+
*/
|
|
13319
|
+
const openapiJson = {
|
|
13320
|
+
openapi: '3.0.0',
|
|
13321
|
+
info: {
|
|
13322
|
+
title: 'Promptbook Remote Server API (!!!! From YML)',
|
|
13323
|
+
version: '1.0.0',
|
|
13324
|
+
description: 'API documentation for the Promptbook Remote Server',
|
|
13325
|
+
},
|
|
13326
|
+
paths: {
|
|
13327
|
+
'/': {
|
|
13328
|
+
get: {
|
|
13329
|
+
summary: 'Get server details',
|
|
13330
|
+
description: 'Returns details about the Promptbook server.',
|
|
13331
|
+
responses: {
|
|
13332
|
+
'200': {
|
|
13333
|
+
description: 'Server details in markdown format.',
|
|
13334
|
+
content: {
|
|
13335
|
+
'text/markdown': {
|
|
13336
|
+
schema: {
|
|
13337
|
+
type: 'string',
|
|
13338
|
+
},
|
|
13339
|
+
},
|
|
13340
|
+
},
|
|
13341
|
+
},
|
|
13342
|
+
},
|
|
13343
|
+
},
|
|
13344
|
+
},
|
|
13345
|
+
'/login': {
|
|
13346
|
+
post: {
|
|
13347
|
+
summary: 'Login to the server',
|
|
13348
|
+
description: 'Login to the server and get identification.',
|
|
13349
|
+
requestBody: {
|
|
13350
|
+
required: true,
|
|
13351
|
+
content: {
|
|
13352
|
+
'application/json': {
|
|
13353
|
+
schema: {
|
|
13354
|
+
type: 'object',
|
|
13355
|
+
properties: {
|
|
13356
|
+
username: {
|
|
13357
|
+
type: 'string',
|
|
13358
|
+
},
|
|
13359
|
+
password: {
|
|
13360
|
+
type: 'string',
|
|
13361
|
+
},
|
|
13362
|
+
appId: {
|
|
13363
|
+
type: 'string',
|
|
13364
|
+
},
|
|
13365
|
+
},
|
|
13366
|
+
},
|
|
13367
|
+
},
|
|
13368
|
+
},
|
|
13369
|
+
},
|
|
13370
|
+
responses: {
|
|
13371
|
+
'201': {
|
|
13372
|
+
description: 'Successful login',
|
|
13373
|
+
content: {
|
|
13374
|
+
'application/json': {
|
|
13375
|
+
schema: {
|
|
13376
|
+
type: 'object',
|
|
13377
|
+
properties: {
|
|
13378
|
+
isSuccess: {
|
|
13379
|
+
type: 'boolean',
|
|
13380
|
+
},
|
|
13381
|
+
message: {
|
|
13382
|
+
type: 'string',
|
|
13383
|
+
},
|
|
13384
|
+
error: {
|
|
13385
|
+
type: 'object',
|
|
13386
|
+
},
|
|
13387
|
+
identification: {
|
|
13388
|
+
type: 'object',
|
|
13389
|
+
},
|
|
13390
|
+
},
|
|
13391
|
+
},
|
|
13392
|
+
},
|
|
13393
|
+
},
|
|
13394
|
+
},
|
|
13395
|
+
'400': {
|
|
13396
|
+
description: 'Bad request or login failed',
|
|
13397
|
+
content: {
|
|
13398
|
+
'application/json': {
|
|
13399
|
+
schema: {
|
|
13400
|
+
type: 'object',
|
|
13401
|
+
properties: {
|
|
13402
|
+
error: {
|
|
13403
|
+
type: 'object',
|
|
13404
|
+
},
|
|
13405
|
+
},
|
|
13406
|
+
},
|
|
13407
|
+
},
|
|
13408
|
+
},
|
|
13409
|
+
},
|
|
13410
|
+
'401': {
|
|
13411
|
+
description: 'Authentication error',
|
|
13412
|
+
content: {
|
|
13413
|
+
'application/json': {
|
|
13414
|
+
schema: {
|
|
13415
|
+
type: 'object',
|
|
13416
|
+
properties: {
|
|
13417
|
+
isSuccess: {
|
|
13418
|
+
type: 'boolean',
|
|
13419
|
+
enum: [false],
|
|
13420
|
+
},
|
|
13421
|
+
message: {
|
|
13422
|
+
type: 'string',
|
|
13423
|
+
},
|
|
13424
|
+
error: {
|
|
13425
|
+
type: 'object',
|
|
13426
|
+
},
|
|
13427
|
+
},
|
|
13428
|
+
},
|
|
13429
|
+
},
|
|
13430
|
+
},
|
|
13431
|
+
},
|
|
13432
|
+
},
|
|
13433
|
+
},
|
|
13434
|
+
},
|
|
13435
|
+
'/books': {
|
|
13436
|
+
get: {
|
|
13437
|
+
summary: 'List all books',
|
|
13438
|
+
description: 'Returns a list of all available books in the collection.',
|
|
13439
|
+
responses: {
|
|
13440
|
+
'200': {
|
|
13441
|
+
description: 'A list of books.',
|
|
13442
|
+
content: {
|
|
13443
|
+
'application/json': {
|
|
13444
|
+
schema: {
|
|
13445
|
+
type: 'array',
|
|
13446
|
+
items: {
|
|
13447
|
+
type: 'string',
|
|
13448
|
+
},
|
|
13449
|
+
},
|
|
13450
|
+
},
|
|
13451
|
+
},
|
|
13452
|
+
},
|
|
13453
|
+
'500': {
|
|
13454
|
+
description: 'No collection available',
|
|
13455
|
+
content: {
|
|
13456
|
+
'text/plain': {
|
|
13457
|
+
schema: {
|
|
13458
|
+
type: 'string',
|
|
13459
|
+
},
|
|
13460
|
+
},
|
|
13461
|
+
},
|
|
13462
|
+
},
|
|
13463
|
+
},
|
|
13464
|
+
},
|
|
13465
|
+
},
|
|
13466
|
+
'/books/{bookId}': {
|
|
13467
|
+
get: {
|
|
13468
|
+
summary: 'Get book content',
|
|
13469
|
+
description: 'Returns the content of a specific book.',
|
|
13470
|
+
parameters: [
|
|
13471
|
+
{
|
|
13472
|
+
in: 'path',
|
|
13473
|
+
name: 'bookId',
|
|
13474
|
+
required: true,
|
|
13475
|
+
schema: {
|
|
13476
|
+
type: 'string',
|
|
13477
|
+
},
|
|
13478
|
+
description: 'The ID of the book to retrieve.',
|
|
13479
|
+
},
|
|
13480
|
+
],
|
|
13481
|
+
responses: {
|
|
13482
|
+
'200': {
|
|
13483
|
+
description: 'The content of the book.',
|
|
13484
|
+
content: {
|
|
13485
|
+
'text/markdown': {
|
|
13486
|
+
schema: {
|
|
13487
|
+
type: 'string',
|
|
13488
|
+
},
|
|
13489
|
+
},
|
|
13490
|
+
},
|
|
13491
|
+
},
|
|
13492
|
+
'404': {
|
|
13493
|
+
description: 'Book not found.',
|
|
13494
|
+
content: {
|
|
13495
|
+
'application/json': {
|
|
13496
|
+
schema: {
|
|
13497
|
+
type: 'object',
|
|
13498
|
+
properties: {
|
|
13499
|
+
error: {
|
|
13500
|
+
type: 'object',
|
|
13501
|
+
},
|
|
13502
|
+
},
|
|
13503
|
+
},
|
|
13504
|
+
},
|
|
13505
|
+
},
|
|
13506
|
+
},
|
|
13507
|
+
'500': {
|
|
13508
|
+
description: 'No collection available',
|
|
13509
|
+
content: {
|
|
13510
|
+
'text/plain': {
|
|
13511
|
+
schema: {
|
|
13512
|
+
type: 'string',
|
|
13513
|
+
},
|
|
13514
|
+
},
|
|
13515
|
+
},
|
|
13516
|
+
},
|
|
13517
|
+
},
|
|
13518
|
+
},
|
|
13519
|
+
},
|
|
13520
|
+
'/executions': {
|
|
13521
|
+
get: {
|
|
13522
|
+
summary: 'List all executions',
|
|
13523
|
+
description: 'Returns a list of all running execution tasks.',
|
|
13524
|
+
responses: {
|
|
13525
|
+
'200': {
|
|
13526
|
+
description: 'A list of execution tasks.',
|
|
13527
|
+
content: {
|
|
13528
|
+
'application/json': {
|
|
13529
|
+
schema: {
|
|
13530
|
+
type: 'array',
|
|
13531
|
+
items: {
|
|
13532
|
+
type: 'object',
|
|
13533
|
+
properties: {
|
|
13534
|
+
nonce: {
|
|
13535
|
+
type: 'string',
|
|
13536
|
+
},
|
|
13537
|
+
taskId: {
|
|
13538
|
+
type: 'string',
|
|
13539
|
+
},
|
|
13540
|
+
taskType: {
|
|
13541
|
+
type: 'string',
|
|
13542
|
+
},
|
|
13543
|
+
status: {
|
|
13544
|
+
type: 'string',
|
|
13545
|
+
},
|
|
13546
|
+
createdAt: {
|
|
13547
|
+
type: 'string',
|
|
13548
|
+
format: 'date-time',
|
|
13549
|
+
},
|
|
13550
|
+
updatedAt: {
|
|
13551
|
+
type: 'string',
|
|
13552
|
+
format: 'date-time',
|
|
13553
|
+
},
|
|
13554
|
+
},
|
|
13555
|
+
},
|
|
13556
|
+
},
|
|
13557
|
+
},
|
|
13558
|
+
},
|
|
13559
|
+
},
|
|
13560
|
+
},
|
|
13561
|
+
},
|
|
13562
|
+
},
|
|
13563
|
+
'/executions/last': {
|
|
13564
|
+
get: {
|
|
13565
|
+
summary: 'Get the last execution',
|
|
13566
|
+
description: 'Returns details of the last execution task.',
|
|
13567
|
+
responses: {
|
|
13568
|
+
'200': {
|
|
13569
|
+
description: 'The last execution task with full details.',
|
|
13570
|
+
content: {
|
|
13571
|
+
'application/json': {
|
|
13572
|
+
schema: {
|
|
13573
|
+
type: 'object',
|
|
13574
|
+
properties: {
|
|
13575
|
+
nonce: {
|
|
13576
|
+
type: 'string',
|
|
13577
|
+
},
|
|
13578
|
+
taskId: {
|
|
13579
|
+
type: 'string',
|
|
13580
|
+
},
|
|
13581
|
+
taskType: {
|
|
13582
|
+
type: 'string',
|
|
13583
|
+
},
|
|
13584
|
+
status: {
|
|
13585
|
+
type: 'string',
|
|
13586
|
+
},
|
|
13587
|
+
errors: {
|
|
13588
|
+
type: 'array',
|
|
13589
|
+
items: {
|
|
13590
|
+
type: 'object',
|
|
13591
|
+
},
|
|
13592
|
+
},
|
|
13593
|
+
warnings: {
|
|
13594
|
+
type: 'array',
|
|
13595
|
+
items: {
|
|
13596
|
+
type: 'object',
|
|
13597
|
+
},
|
|
13598
|
+
},
|
|
13599
|
+
createdAt: {
|
|
13600
|
+
type: 'string',
|
|
13601
|
+
format: 'date-time',
|
|
13602
|
+
},
|
|
13603
|
+
updatedAt: {
|
|
13604
|
+
type: 'string',
|
|
13605
|
+
format: 'date-time',
|
|
13606
|
+
},
|
|
13607
|
+
currentValue: {
|
|
13608
|
+
type: 'object',
|
|
13609
|
+
},
|
|
13610
|
+
},
|
|
13611
|
+
},
|
|
13612
|
+
},
|
|
13613
|
+
},
|
|
13614
|
+
},
|
|
13615
|
+
'404': {
|
|
13616
|
+
description: 'No execution tasks found.',
|
|
13617
|
+
content: {
|
|
13618
|
+
'text/plain': {
|
|
13619
|
+
schema: {
|
|
13620
|
+
type: 'string',
|
|
13621
|
+
},
|
|
13622
|
+
},
|
|
13623
|
+
},
|
|
13624
|
+
},
|
|
13625
|
+
},
|
|
13626
|
+
},
|
|
13627
|
+
},
|
|
13628
|
+
'/executions/{taskId}': {
|
|
13629
|
+
get: {
|
|
13630
|
+
summary: 'Get specific execution',
|
|
13631
|
+
description: 'Returns details of a specific execution task.',
|
|
13632
|
+
parameters: [
|
|
13633
|
+
{
|
|
13634
|
+
in: 'path',
|
|
13635
|
+
name: 'taskId',
|
|
13636
|
+
required: true,
|
|
13637
|
+
schema: {
|
|
13638
|
+
type: 'string',
|
|
13639
|
+
},
|
|
13640
|
+
description: 'The ID of the execution task to retrieve.',
|
|
13641
|
+
},
|
|
13642
|
+
],
|
|
13643
|
+
responses: {
|
|
13644
|
+
'200': {
|
|
13645
|
+
description: 'The execution task with full details.',
|
|
13646
|
+
content: {
|
|
13647
|
+
'application/json': {
|
|
13648
|
+
schema: {
|
|
13649
|
+
type: 'object',
|
|
13650
|
+
properties: {
|
|
13651
|
+
nonce: {
|
|
13652
|
+
type: 'string',
|
|
13653
|
+
},
|
|
13654
|
+
taskId: {
|
|
13655
|
+
type: 'string',
|
|
13656
|
+
},
|
|
13657
|
+
taskType: {
|
|
13658
|
+
type: 'string',
|
|
13659
|
+
},
|
|
13660
|
+
status: {
|
|
13661
|
+
type: 'string',
|
|
13662
|
+
},
|
|
13663
|
+
errors: {
|
|
13664
|
+
type: 'array',
|
|
13665
|
+
items: {
|
|
13666
|
+
type: 'object',
|
|
13667
|
+
},
|
|
13668
|
+
},
|
|
13669
|
+
warnings: {
|
|
13670
|
+
type: 'array',
|
|
13671
|
+
items: {
|
|
13672
|
+
type: 'object',
|
|
13673
|
+
},
|
|
13674
|
+
},
|
|
13675
|
+
createdAt: {
|
|
13676
|
+
type: 'string',
|
|
13677
|
+
format: 'date-time',
|
|
13678
|
+
},
|
|
13679
|
+
updatedAt: {
|
|
13680
|
+
type: 'string',
|
|
13681
|
+
format: 'date-time',
|
|
13682
|
+
},
|
|
13683
|
+
currentValue: {
|
|
13684
|
+
type: 'object',
|
|
13685
|
+
},
|
|
13686
|
+
},
|
|
13687
|
+
},
|
|
13688
|
+
},
|
|
13689
|
+
},
|
|
13690
|
+
},
|
|
13691
|
+
'404': {
|
|
13692
|
+
description: 'Execution task not found.',
|
|
13693
|
+
content: {
|
|
13694
|
+
'text/plain': {
|
|
13695
|
+
schema: {
|
|
13696
|
+
type: 'string',
|
|
13697
|
+
},
|
|
13698
|
+
},
|
|
13699
|
+
},
|
|
13700
|
+
},
|
|
13701
|
+
},
|
|
13702
|
+
},
|
|
13703
|
+
},
|
|
13704
|
+
'/executions/new': {
|
|
13705
|
+
post: {
|
|
13706
|
+
summary: 'Start a new execution',
|
|
13707
|
+
description: 'Starts a new execution task for a given pipeline.',
|
|
13708
|
+
requestBody: {
|
|
13709
|
+
required: true,
|
|
13710
|
+
content: {
|
|
13711
|
+
'application/json': {
|
|
13712
|
+
schema: {
|
|
13713
|
+
type: 'object',
|
|
13714
|
+
properties: {
|
|
13715
|
+
pipelineUrl: {
|
|
13716
|
+
type: 'string',
|
|
13717
|
+
description: 'URL of the pipeline to execute',
|
|
13718
|
+
},
|
|
13719
|
+
book: {
|
|
13720
|
+
type: 'string',
|
|
13721
|
+
description: 'Alternative field for pipelineUrl',
|
|
13722
|
+
},
|
|
13723
|
+
inputParameters: {
|
|
13724
|
+
type: 'object',
|
|
13725
|
+
description: 'Parameters for pipeline execution',
|
|
13726
|
+
},
|
|
13727
|
+
identification: {
|
|
13728
|
+
type: 'object',
|
|
13729
|
+
description: 'User identification data',
|
|
13730
|
+
},
|
|
13731
|
+
},
|
|
13732
|
+
},
|
|
13733
|
+
},
|
|
13734
|
+
},
|
|
13735
|
+
},
|
|
13736
|
+
responses: {
|
|
13737
|
+
'200': {
|
|
13738
|
+
description: 'The newly created execution task.',
|
|
13739
|
+
content: {
|
|
13740
|
+
'application/json': {
|
|
13741
|
+
schema: {
|
|
13742
|
+
type: 'object',
|
|
13743
|
+
},
|
|
13744
|
+
},
|
|
13745
|
+
},
|
|
13746
|
+
},
|
|
13747
|
+
'400': {
|
|
13748
|
+
description: 'Invalid input.',
|
|
13749
|
+
content: {
|
|
13750
|
+
'application/json': {
|
|
13751
|
+
schema: {
|
|
13752
|
+
type: 'object',
|
|
13753
|
+
properties: {
|
|
13754
|
+
error: {
|
|
13755
|
+
type: 'object',
|
|
13756
|
+
},
|
|
13757
|
+
},
|
|
13758
|
+
},
|
|
13759
|
+
},
|
|
13760
|
+
},
|
|
13761
|
+
},
|
|
13762
|
+
'404': {
|
|
13763
|
+
description: 'Pipeline not found.',
|
|
13764
|
+
content: {
|
|
13765
|
+
'text/plain': {
|
|
13766
|
+
schema: {
|
|
13767
|
+
type: 'string',
|
|
13768
|
+
},
|
|
13769
|
+
},
|
|
13770
|
+
},
|
|
13771
|
+
},
|
|
13772
|
+
},
|
|
13773
|
+
},
|
|
13774
|
+
},
|
|
13775
|
+
'/api-docs': {
|
|
13776
|
+
get: {
|
|
13777
|
+
summary: 'API documentation UI',
|
|
13778
|
+
description: 'Swagger UI for API documentation',
|
|
13779
|
+
responses: {
|
|
13780
|
+
'200': {
|
|
13781
|
+
description: 'HTML Swagger UI',
|
|
13782
|
+
},
|
|
13783
|
+
},
|
|
13784
|
+
},
|
|
13785
|
+
},
|
|
13786
|
+
'/swagger': {
|
|
13787
|
+
get: {
|
|
13788
|
+
summary: 'API documentation UI (alternative path)',
|
|
13789
|
+
description: 'Swagger UI for API documentation',
|
|
13790
|
+
responses: {
|
|
13791
|
+
'200': {
|
|
13792
|
+
description: 'HTML Swagger UI',
|
|
13793
|
+
},
|
|
13794
|
+
},
|
|
13795
|
+
},
|
|
13796
|
+
},
|
|
13797
|
+
'/openapi': {
|
|
13798
|
+
get: {
|
|
13799
|
+
summary: 'OpenAPI specification',
|
|
13800
|
+
description: 'Returns the OpenAPI JSON specification',
|
|
13801
|
+
responses: {
|
|
13802
|
+
'200': {
|
|
13803
|
+
description: 'OpenAPI specification',
|
|
13804
|
+
content: {
|
|
13805
|
+
'application/json': {
|
|
13806
|
+
schema: {
|
|
13807
|
+
type: 'object',
|
|
13808
|
+
},
|
|
13809
|
+
},
|
|
13810
|
+
},
|
|
13811
|
+
},
|
|
13812
|
+
},
|
|
13813
|
+
},
|
|
13814
|
+
},
|
|
13815
|
+
},
|
|
13816
|
+
components: {
|
|
13817
|
+
schemas: {
|
|
13818
|
+
Error: {
|
|
13819
|
+
type: 'object',
|
|
13820
|
+
properties: {
|
|
13821
|
+
error: {
|
|
13822
|
+
type: 'object',
|
|
13823
|
+
},
|
|
13824
|
+
},
|
|
13825
|
+
},
|
|
13826
|
+
ExecutionTaskSummary: {
|
|
13827
|
+
type: 'object',
|
|
13828
|
+
properties: {
|
|
13829
|
+
nonce: {
|
|
13830
|
+
type: 'string',
|
|
13831
|
+
},
|
|
13832
|
+
taskId: {
|
|
13833
|
+
type: 'string',
|
|
13834
|
+
},
|
|
13835
|
+
taskType: {
|
|
13836
|
+
type: 'string',
|
|
13837
|
+
},
|
|
13838
|
+
status: {
|
|
13839
|
+
type: 'string',
|
|
13840
|
+
},
|
|
13841
|
+
createdAt: {
|
|
13842
|
+
type: 'string',
|
|
13843
|
+
format: 'date-time',
|
|
13844
|
+
},
|
|
13845
|
+
updatedAt: {
|
|
13846
|
+
type: 'string',
|
|
13847
|
+
format: 'date-time',
|
|
13848
|
+
},
|
|
13849
|
+
},
|
|
13850
|
+
},
|
|
13851
|
+
ExecutionTaskFull: {
|
|
13852
|
+
type: 'object',
|
|
13853
|
+
properties: {
|
|
13854
|
+
nonce: {
|
|
13855
|
+
type: 'string',
|
|
13856
|
+
},
|
|
13857
|
+
taskId: {
|
|
13858
|
+
type: 'string',
|
|
13859
|
+
},
|
|
13860
|
+
taskType: {
|
|
13861
|
+
type: 'string',
|
|
13862
|
+
},
|
|
13863
|
+
status: {
|
|
13864
|
+
type: 'string',
|
|
13865
|
+
},
|
|
13866
|
+
errors: {
|
|
13867
|
+
type: 'array',
|
|
13868
|
+
items: {
|
|
13869
|
+
type: 'object',
|
|
13870
|
+
},
|
|
13871
|
+
},
|
|
13872
|
+
warnings: {
|
|
13873
|
+
type: 'array',
|
|
13874
|
+
items: {
|
|
13875
|
+
type: 'object',
|
|
13876
|
+
},
|
|
13877
|
+
},
|
|
13878
|
+
createdAt: {
|
|
13879
|
+
type: 'string',
|
|
13880
|
+
format: 'date-time',
|
|
13881
|
+
},
|
|
13882
|
+
updatedAt: {
|
|
13883
|
+
type: 'string',
|
|
13884
|
+
format: 'date-time',
|
|
13885
|
+
},
|
|
13886
|
+
currentValue: {
|
|
13887
|
+
type: 'object',
|
|
13888
|
+
},
|
|
13889
|
+
},
|
|
13890
|
+
},
|
|
13891
|
+
},
|
|
13892
|
+
},
|
|
13893
|
+
tags: [
|
|
13894
|
+
{
|
|
13895
|
+
name: 'Books',
|
|
13896
|
+
description: 'Operations related to books and pipelines',
|
|
13897
|
+
},
|
|
13898
|
+
{
|
|
13899
|
+
name: 'Executions',
|
|
13900
|
+
description: 'Operations related to execution tasks',
|
|
13901
|
+
},
|
|
13902
|
+
{
|
|
13903
|
+
name: 'Authentication',
|
|
13904
|
+
description: 'Authentication operations',
|
|
13905
|
+
},
|
|
13906
|
+
],
|
|
13907
|
+
};
|
|
13908
|
+
/**
|
|
12942
13909
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
12943
|
-
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
12944
|
-
* TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
|
|
12945
13910
|
*/
|
|
12946
13911
|
|
|
12947
13912
|
/**
|
|
@@ -12954,7 +13919,7 @@
|
|
|
12954
13919
|
* @public exported from `@promptbook/remote-server`
|
|
12955
13920
|
*/
|
|
12956
13921
|
function startRemoteServer(options) {
|
|
12957
|
-
const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
|
|
13922
|
+
const { port, collection, createLlmExecutionTools, createExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
|
|
12958
13923
|
isAnonymousModeAllowed: false,
|
|
12959
13924
|
isApplicationModeAllowed: false,
|
|
12960
13925
|
collection: null,
|
|
@@ -12962,22 +13927,6 @@
|
|
|
12962
13927
|
login: null,
|
|
12963
13928
|
...options,
|
|
12964
13929
|
};
|
|
12965
|
-
// <- TODO: [🦪] Some helper type to be able to use discriminant union types with destructuring
|
|
12966
|
-
let { rootPath = '/' } = options;
|
|
12967
|
-
if (!rootPath.startsWith('/')) {
|
|
12968
|
-
rootPath = `/${rootPath}`;
|
|
12969
|
-
} /* not else */
|
|
12970
|
-
if (rootPath.endsWith('/')) {
|
|
12971
|
-
rootPath = rootPath.slice(0, -1);
|
|
12972
|
-
} /* not else */
|
|
12973
|
-
if (rootPath === '/') {
|
|
12974
|
-
rootPath = '';
|
|
12975
|
-
}
|
|
12976
|
-
const socketioPath = '/' +
|
|
12977
|
-
`${rootPath}/socket.io`
|
|
12978
|
-
.split('/')
|
|
12979
|
-
.filter((part) => part !== '')
|
|
12980
|
-
.join('/');
|
|
12981
13930
|
const startupDate = new Date();
|
|
12982
13931
|
async function getExecutionToolsFromIdentification(identification) {
|
|
12983
13932
|
if (identification === null || identification === undefined) {
|
|
@@ -13000,23 +13949,25 @@
|
|
|
13000
13949
|
}
|
|
13001
13950
|
else if (isAnonymous === false && createLlmExecutionTools !== null) {
|
|
13002
13951
|
// Note: Application mode
|
|
13003
|
-
|
|
13004
|
-
llm = await createLlmExecutionTools({
|
|
13005
|
-
appId,
|
|
13006
|
-
userId,
|
|
13007
|
-
customOptions,
|
|
13008
|
-
});
|
|
13952
|
+
llm = await createLlmExecutionTools(identification);
|
|
13009
13953
|
}
|
|
13010
13954
|
else {
|
|
13011
13955
|
throw new PipelineExecutionError(`You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured`);
|
|
13012
13956
|
}
|
|
13013
|
-
const
|
|
13014
|
-
const
|
|
13957
|
+
const customExecutionTools = createExecutionTools ? await createExecutionTools(identification) : {};
|
|
13958
|
+
const fs = customExecutionTools.fs || $provideFilesystemForNode();
|
|
13959
|
+
const executables = customExecutionTools.executables || (await $provideExecutablesForNode());
|
|
13960
|
+
const scrapers = customExecutionTools.scrapers || (await $provideScrapersForNode({ fs, llm, executables }));
|
|
13961
|
+
const script = customExecutionTools.script || (await $provideScriptingForNode({}));
|
|
13962
|
+
const fetch = customExecutionTools.fetch || promptbookFetch;
|
|
13963
|
+
const userInterface = customExecutionTools.userInterface || undefined;
|
|
13015
13964
|
const tools = {
|
|
13016
13965
|
llm,
|
|
13017
13966
|
fs,
|
|
13018
|
-
scrapers
|
|
13019
|
-
script
|
|
13967
|
+
scrapers,
|
|
13968
|
+
script,
|
|
13969
|
+
fetch,
|
|
13970
|
+
userInterface,
|
|
13020
13971
|
};
|
|
13021
13972
|
return tools;
|
|
13022
13973
|
}
|
|
@@ -13026,39 +13977,27 @@
|
|
|
13026
13977
|
response.setHeader('X-Powered-By', 'Promptbook engine');
|
|
13027
13978
|
next();
|
|
13028
13979
|
});
|
|
13029
|
-
|
|
13030
|
-
|
|
13031
|
-
|
|
13032
|
-
|
|
13033
|
-
|
|
13034
|
-
version: '1.0.0',
|
|
13035
|
-
description: 'API documentation for the Promptbook Remote Server',
|
|
13036
|
-
},
|
|
13037
|
-
servers: [
|
|
13038
|
-
{
|
|
13039
|
-
url: `http://localhost:${port}${rootPath}`,
|
|
13040
|
-
// <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
|
|
13041
|
-
},
|
|
13042
|
-
],
|
|
13980
|
+
// TODO: !!!! Expose openapiJson to consumer and also allow to add new routes
|
|
13981
|
+
app.use(OpenApiValidator__namespace.middleware({
|
|
13982
|
+
apiSpec: openapiJson,
|
|
13983
|
+
ignorePaths(path) {
|
|
13984
|
+
return path.startsWith('/api-docs') || path.startsWith('/swagger') || path.startsWith('/openapi');
|
|
13043
13985
|
},
|
|
13044
|
-
|
|
13045
|
-
|
|
13046
|
-
|
|
13047
|
-
app.use([`/api-docs`,
|
|
13986
|
+
validateRequests: true,
|
|
13987
|
+
validateResponses: true,
|
|
13988
|
+
}));
|
|
13989
|
+
app.use([`/api-docs`, `/swagger`], swaggerUi__default["default"].serve, swaggerUi__default["default"].setup(openapiJson, {
|
|
13990
|
+
// customCss: '.swagger-ui .topbar { display: none }',
|
|
13991
|
+
// customSiteTitle: 'BRJ API',
|
|
13992
|
+
// customfavIcon: 'https://brj.app/favicon.ico',
|
|
13993
|
+
}));
|
|
13994
|
+
app.get(`/openapi`, (request, response) => {
|
|
13995
|
+
response.json(openapiJson);
|
|
13996
|
+
});
|
|
13048
13997
|
const runningExecutionTasks = [];
|
|
13049
13998
|
// <- TODO: [🤬] Identify the users
|
|
13050
13999
|
// TODO: [🧠] Do here some garbage collection of finished tasks
|
|
13051
|
-
|
|
13052
|
-
* @swagger
|
|
13053
|
-
* /:
|
|
13054
|
-
* get:
|
|
13055
|
-
* summary: Get server details
|
|
13056
|
-
* description: Returns details about the Promptbook server.
|
|
13057
|
-
* responses:
|
|
13058
|
-
* 200:
|
|
13059
|
-
* description: Server details in markdown format.
|
|
13060
|
-
*/
|
|
13061
|
-
app.get(['/', rootPath], async (request, response) => {
|
|
14000
|
+
app.get('/', async (request, response) => {
|
|
13062
14001
|
var _a;
|
|
13063
14002
|
if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
|
|
13064
14003
|
return;
|
|
@@ -13077,8 +14016,6 @@
|
|
|
13077
14016
|
## Details
|
|
13078
14017
|
|
|
13079
14018
|
**Server port:** ${port}
|
|
13080
|
-
**Server root path:** ${rootPath}
|
|
13081
|
-
**Socket.io path:** ${socketioPath}
|
|
13082
14019
|
**Startup date:** ${startupDate.toISOString()}
|
|
13083
14020
|
**Anonymouse mode:** ${isAnonymousModeAllowed ? 'enabled' : 'disabled'}
|
|
13084
14021
|
**Application mode:** ${isApplicationModeAllowed ? 'enabled' : 'disabled'}
|
|
@@ -13117,38 +14054,7 @@
|
|
|
13117
14054
|
https://github.com/webgptorg/promptbook
|
|
13118
14055
|
`));
|
|
13119
14056
|
});
|
|
13120
|
-
|
|
13121
|
-
* @swagger
|
|
13122
|
-
*
|
|
13123
|
-
* /login:
|
|
13124
|
-
* post:
|
|
13125
|
-
* summary: Login to the server
|
|
13126
|
-
* description: Login to the server and get identification.
|
|
13127
|
-
* requestBody:
|
|
13128
|
-
* required: true
|
|
13129
|
-
* content:
|
|
13130
|
-
* application/json:
|
|
13131
|
-
* schema:
|
|
13132
|
-
* type: object
|
|
13133
|
-
* properties:
|
|
13134
|
-
* username:
|
|
13135
|
-
* type: string
|
|
13136
|
-
* password:
|
|
13137
|
-
* type: string
|
|
13138
|
-
* appId:
|
|
13139
|
-
* type: string
|
|
13140
|
-
* responses:
|
|
13141
|
-
* 200:
|
|
13142
|
-
* description: Successful login
|
|
13143
|
-
* content:
|
|
13144
|
-
* application/json:
|
|
13145
|
-
* schema:
|
|
13146
|
-
* type: object
|
|
13147
|
-
* properties:
|
|
13148
|
-
* identification:
|
|
13149
|
-
* type: object
|
|
13150
|
-
*/
|
|
13151
|
-
app.post([`/login`, `${rootPath}/login`], async (request, response) => {
|
|
14057
|
+
app.post(`/login`, async (request, response) => {
|
|
13152
14058
|
if (!isApplicationModeAllowed || login === null) {
|
|
13153
14059
|
response.status(400).send('Application mode is not allowed');
|
|
13154
14060
|
return;
|
|
@@ -13173,9 +14079,7 @@
|
|
|
13173
14079
|
return;
|
|
13174
14080
|
}
|
|
13175
14081
|
catch (error) {
|
|
13176
|
-
|
|
13177
|
-
throw error;
|
|
13178
|
-
}
|
|
14082
|
+
assertsError(error);
|
|
13179
14083
|
if (error instanceof AuthenticationError) {
|
|
13180
14084
|
response.status(401).send({
|
|
13181
14085
|
isSuccess: false,
|
|
@@ -13190,23 +14094,7 @@
|
|
|
13190
14094
|
response.status(400).send({ error: serializeError(error) });
|
|
13191
14095
|
}
|
|
13192
14096
|
});
|
|
13193
|
-
|
|
13194
|
-
* @swagger
|
|
13195
|
-
* /books:
|
|
13196
|
-
* get:
|
|
13197
|
-
* summary: List all books
|
|
13198
|
-
* description: Returns a list of all available books in the collection.
|
|
13199
|
-
* responses:
|
|
13200
|
-
* 200:
|
|
13201
|
-
* description: A list of books.
|
|
13202
|
-
* content:
|
|
13203
|
-
* application/json:
|
|
13204
|
-
* schema:
|
|
13205
|
-
* type: array
|
|
13206
|
-
* items:
|
|
13207
|
-
* type: string
|
|
13208
|
-
*/
|
|
13209
|
-
app.get([`/books`, `${rootPath}/books`], async (request, response) => {
|
|
14097
|
+
app.get(`/books`, async (request, response) => {
|
|
13210
14098
|
if (collection === null) {
|
|
13211
14099
|
response.status(500).send('No collection available');
|
|
13212
14100
|
return;
|
|
@@ -13216,30 +14104,7 @@
|
|
|
13216
14104
|
response.send(pipelines);
|
|
13217
14105
|
});
|
|
13218
14106
|
// TODO: [🧠] Is it secure / good idea to expose source codes of hosted books
|
|
13219
|
-
|
|
13220
|
-
* @swagger
|
|
13221
|
-
* /books/{bookId}:
|
|
13222
|
-
* get:
|
|
13223
|
-
* summary: Get book content
|
|
13224
|
-
* description: Returns the content of a specific book.
|
|
13225
|
-
* parameters:
|
|
13226
|
-
* - in: path
|
|
13227
|
-
* name: bookId
|
|
13228
|
-
* required: true
|
|
13229
|
-
* schema:
|
|
13230
|
-
* type: string
|
|
13231
|
-
* description: The ID of the book to retrieve.
|
|
13232
|
-
* responses:
|
|
13233
|
-
* 200:
|
|
13234
|
-
* description: The content of the book.
|
|
13235
|
-
* content:
|
|
13236
|
-
* text/markdown:
|
|
13237
|
-
* schema:
|
|
13238
|
-
* type: string
|
|
13239
|
-
* 404:
|
|
13240
|
-
* description: Book not found.
|
|
13241
|
-
*/
|
|
13242
|
-
app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
|
|
14107
|
+
app.get(`/books/*`, async (request, response) => {
|
|
13243
14108
|
try {
|
|
13244
14109
|
if (collection === null) {
|
|
13245
14110
|
response.status(500).send('No collection nor books available');
|
|
@@ -13258,9 +14123,7 @@
|
|
|
13258
14123
|
.send(source.content);
|
|
13259
14124
|
}
|
|
13260
14125
|
catch (error) {
|
|
13261
|
-
|
|
13262
|
-
throw error;
|
|
13263
|
-
}
|
|
14126
|
+
assertsError(error);
|
|
13264
14127
|
response
|
|
13265
14128
|
.status(404)
|
|
13266
14129
|
.send({ error: serializeError(error) });
|
|
@@ -13293,26 +14156,10 @@
|
|
|
13293
14156
|
};
|
|
13294
14157
|
}
|
|
13295
14158
|
}
|
|
13296
|
-
|
|
13297
|
-
|
|
13298
|
-
* /executions:
|
|
13299
|
-
* get:
|
|
13300
|
-
* summary: List all executions
|
|
13301
|
-
* description: Returns a list of all running execution tasks.
|
|
13302
|
-
* responses:
|
|
13303
|
-
* 200:
|
|
13304
|
-
* description: A list of execution tasks.
|
|
13305
|
-
* content:
|
|
13306
|
-
* application/json:
|
|
13307
|
-
* schema:
|
|
13308
|
-
* type: array
|
|
13309
|
-
* items:
|
|
13310
|
-
* type: object
|
|
13311
|
-
*/
|
|
13312
|
-
app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
|
|
13313
|
-
response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
|
|
14159
|
+
app.get(`/executions`, async (request, response) => {
|
|
14160
|
+
response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)) /* <- TODO: satisfies paths['/executions']['get']['responses']['200']['content']['application/json'] */);
|
|
13314
14161
|
});
|
|
13315
|
-
app.get(
|
|
14162
|
+
app.get(`/executions/last`, async (request, response) => {
|
|
13316
14163
|
// TODO: [🤬] Filter only for user
|
|
13317
14164
|
if (runningExecutionTasks.length === 0) {
|
|
13318
14165
|
response.status(404).send('No execution tasks found');
|
|
@@ -13321,7 +14168,7 @@
|
|
|
13321
14168
|
const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
|
|
13322
14169
|
response.send(exportExecutionTask(lastExecutionTask, true));
|
|
13323
14170
|
});
|
|
13324
|
-
app.get(
|
|
14171
|
+
app.get(`/executions/:taskId`, async (request, response) => {
|
|
13325
14172
|
const { taskId } = request.params;
|
|
13326
14173
|
// TODO: [🤬] Filter only for user
|
|
13327
14174
|
const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
|
|
@@ -13333,39 +14180,12 @@
|
|
|
13333
14180
|
}
|
|
13334
14181
|
response.send(exportExecutionTask(executionTask, true));
|
|
13335
14182
|
});
|
|
13336
|
-
|
|
13337
|
-
* @swagger
|
|
13338
|
-
* /executions/new:
|
|
13339
|
-
* post:
|
|
13340
|
-
* summary: Start a new execution
|
|
13341
|
-
* description: Starts a new execution task for a given pipeline.
|
|
13342
|
-
* requestBody:
|
|
13343
|
-
* required: true
|
|
13344
|
-
* content:
|
|
13345
|
-
* application/json:
|
|
13346
|
-
* schema:
|
|
13347
|
-
* type: object
|
|
13348
|
-
* properties:
|
|
13349
|
-
* pipelineUrl:
|
|
13350
|
-
* type: string
|
|
13351
|
-
* inputParameters:
|
|
13352
|
-
* type: object
|
|
13353
|
-
* identification:
|
|
13354
|
-
* type: object
|
|
13355
|
-
* responses:
|
|
13356
|
-
* 200:
|
|
13357
|
-
* description: The newly created execution task.
|
|
13358
|
-
* content:
|
|
13359
|
-
* application/json:
|
|
13360
|
-
* schema:
|
|
13361
|
-
* type: object
|
|
13362
|
-
* 400:
|
|
13363
|
-
* description: Invalid input.
|
|
13364
|
-
*/
|
|
13365
|
-
app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
|
|
14183
|
+
app.post(`/executions/new`, async (request, response) => {
|
|
13366
14184
|
try {
|
|
13367
14185
|
const { inputParameters, identification /* <- [🤬] */ } = request.body;
|
|
13368
|
-
const pipelineUrl = request.body
|
|
14186
|
+
const pipelineUrl = request.body
|
|
14187
|
+
.pipelineUrl /* <- TODO: as paths['/executions/new']['post']['requestBody']['content']['application/json'] */ ||
|
|
14188
|
+
request.body.book;
|
|
13369
14189
|
// TODO: [🧠] Check `pipelineUrl` and `inputParameters` here or it should be responsibility of `collection.getPipelineByUrl` and `pipelineExecutor`
|
|
13370
14190
|
const pipeline = await (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl));
|
|
13371
14191
|
if (pipeline === undefined) {
|
|
@@ -13379,7 +14199,7 @@
|
|
|
13379
14199
|
await waitasecond.forTime(10);
|
|
13380
14200
|
// <- Note: Wait for a while to wait for quick responses or sudden but asynchronous errors
|
|
13381
14201
|
// <- TODO: Put this into configuration
|
|
13382
|
-
response.send(executionTask);
|
|
14202
|
+
response.send(executionTask /* <- TODO: satisfies paths['/executions/new']['post']['responses']['200']['content']['application/json'] */);
|
|
13383
14203
|
/*/
|
|
13384
14204
|
executionTask.asObservable().subscribe({
|
|
13385
14205
|
next(partialResult) {
|
|
@@ -13399,19 +14219,24 @@
|
|
|
13399
14219
|
*/
|
|
13400
14220
|
}
|
|
13401
14221
|
catch (error) {
|
|
13402
|
-
|
|
13403
|
-
throw error;
|
|
13404
|
-
}
|
|
14222
|
+
assertsError(error);
|
|
13405
14223
|
response.status(400).send({ error: serializeError(error) });
|
|
13406
14224
|
}
|
|
13407
14225
|
});
|
|
14226
|
+
/**
|
|
14227
|
+
* Catch-all handler for unmatched routes
|
|
14228
|
+
*/
|
|
14229
|
+
app.use((request, response) => {
|
|
14230
|
+
response.status(404).send(`URL "${request.originalUrl}" was not found on Promptbook server.`);
|
|
14231
|
+
});
|
|
13408
14232
|
const httpServer = http__default["default"].createServer(app);
|
|
13409
14233
|
const server = new socket_io.Server(httpServer, {
|
|
13410
|
-
path:
|
|
13411
|
-
transports: [
|
|
14234
|
+
path: '/socket.io',
|
|
14235
|
+
transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
|
|
13412
14236
|
cors: {
|
|
13413
14237
|
origin: '*',
|
|
13414
14238
|
methods: ['GET', 'POST'],
|
|
14239
|
+
// <- TODO: [🌡] Allow to pass
|
|
13415
14240
|
},
|
|
13416
14241
|
});
|
|
13417
14242
|
server.on('connection', (socket) => {
|
|
@@ -13465,9 +14290,7 @@
|
|
|
13465
14290
|
socket.emit('prompt-response', { promptResult } /* <- Note: [🤛] */);
|
|
13466
14291
|
}
|
|
13467
14292
|
catch (error) {
|
|
13468
|
-
|
|
13469
|
-
throw error;
|
|
13470
|
-
}
|
|
14293
|
+
assertsError(error);
|
|
13471
14294
|
socket.emit('error', serializeError(error) /* <- Note: [🤛] */);
|
|
13472
14295
|
}
|
|
13473
14296
|
finally {
|
|
@@ -13489,9 +14312,7 @@
|
|
|
13489
14312
|
socket.emit('listModels-response', { models } /* <- Note: [🤛] */);
|
|
13490
14313
|
}
|
|
13491
14314
|
catch (error) {
|
|
13492
|
-
|
|
13493
|
-
throw error;
|
|
13494
|
-
}
|
|
14315
|
+
assertsError(error);
|
|
13495
14316
|
socket.emit('error', serializeError(error));
|
|
13496
14317
|
}
|
|
13497
14318
|
finally {
|
|
@@ -13512,9 +14333,7 @@
|
|
|
13512
14333
|
socket.emit('preparePipeline-response', { preparedPipeline } /* <- Note: [🤛] */);
|
|
13513
14334
|
}
|
|
13514
14335
|
catch (error) {
|
|
13515
|
-
|
|
13516
|
-
throw error;
|
|
13517
|
-
}
|
|
14336
|
+
assertsError(error);
|
|
13518
14337
|
socket.emit('error', serializeError(error));
|
|
13519
14338
|
// <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
|
|
13520
14339
|
}
|
|
@@ -13562,8 +14381,7 @@
|
|
|
13562
14381
|
};
|
|
13563
14382
|
}
|
|
13564
14383
|
/**
|
|
13565
|
-
* TODO:
|
|
13566
|
-
* TODO: [👩🏾🤝🧑🏾] Allow to pass custom fetch function here - PromptbookFetch
|
|
14384
|
+
* TODO: [🌡] Add CORS and security - probbably via `helmet`
|
|
13567
14385
|
* TODO: Split this file into multiple functions - handler for each request
|
|
13568
14386
|
* TODO: Maybe use `$exportJson`
|
|
13569
14387
|
* TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
|
|
@@ -13622,9 +14440,9 @@
|
|
|
13622
14440
|
if (url !== null) {
|
|
13623
14441
|
rootUrl = suffixUrl(url, '/books');
|
|
13624
14442
|
}
|
|
13625
|
-
|
|
13626
|
-
|
|
13627
|
-
|
|
14443
|
+
if (url !== null && url.pathname !== '/' && url.pathname !== '') {
|
|
14444
|
+
console.error(colors__default["default"].red(`URL of the server can not have path, but got "${url.pathname}"`));
|
|
14445
|
+
process.exit(1);
|
|
13628
14446
|
}
|
|
13629
14447
|
// TODO: DRY [◽]
|
|
13630
14448
|
const prepareAndScrapeOptions = {
|
|
@@ -13632,7 +14450,7 @@
|
|
|
13632
14450
|
isCacheReloaded,
|
|
13633
14451
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
13634
14452
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
13635
|
-
const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
14453
|
+
const { /* [0] strategy,*/ llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13636
14454
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
13637
14455
|
const tools = {
|
|
13638
14456
|
llm,
|
|
@@ -13651,7 +14469,6 @@
|
|
|
13651
14469
|
});
|
|
13652
14470
|
// console.log(path, await collection.listPipelines());
|
|
13653
14471
|
const server = startRemoteServer({
|
|
13654
|
-
rootPath,
|
|
13655
14472
|
port,
|
|
13656
14473
|
isAnonymousModeAllowed,
|
|
13657
14474
|
isApplicationModeAllowed: true,
|
|
@@ -13664,6 +14481,7 @@
|
|
|
13664
14481
|
TODO_USE({ appId, userId });
|
|
13665
14482
|
return llm;
|
|
13666
14483
|
},
|
|
14484
|
+
// <- TODO: [🧠][0] Maybe pass here strategy
|
|
13667
14485
|
});
|
|
13668
14486
|
keepUnused(server);
|
|
13669
14487
|
// Note: Already logged by `startRemoteServer`
|
|
@@ -13705,7 +14523,7 @@
|
|
|
13705
14523
|
isCacheReloaded,
|
|
13706
14524
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
13707
14525
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
13708
|
-
const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
14526
|
+
const { llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13709
14527
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
13710
14528
|
tools = {
|
|
13711
14529
|
llm,
|
|
@@ -13730,7 +14548,7 @@
|
|
|
13730
14548
|
}
|
|
13731
14549
|
}
|
|
13732
14550
|
if (filename.endsWith('.bookc')) {
|
|
13733
|
-
pipeline =
|
|
14551
|
+
pipeline = jsonParse(await promises.readFile(filename, 'utf-8'));
|
|
13734
14552
|
}
|
|
13735
14553
|
else {
|
|
13736
14554
|
if (isVerbose) {
|
|
@@ -13744,9 +14562,7 @@
|
|
|
13744
14562
|
}
|
|
13745
14563
|
}
|
|
13746
14564
|
catch (error) {
|
|
13747
|
-
|
|
13748
|
-
throw error;
|
|
13749
|
-
}
|
|
14565
|
+
assertsError(error);
|
|
13750
14566
|
console.info(colors__default["default"].red(`Pipeline is not valid ${filename}`));
|
|
13751
14567
|
console.error(colors__default["default"].bgRed(`${error.name} in ${path.basename(__filename)}`));
|
|
13752
14568
|
console.error(colors__default["default"].red(error.stack || error.message));
|
|
@@ -13841,6 +14657,37 @@
|
|
|
13841
14657
|
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
13842
14658
|
*/
|
|
13843
14659
|
|
|
14660
|
+
/**
|
|
14661
|
+
* How is the model provider trusted?
|
|
14662
|
+
*
|
|
14663
|
+
* @public exported from `@promptbook/core`
|
|
14664
|
+
*/
|
|
14665
|
+
// <- TODO: Maybe do better levels of trust
|
|
14666
|
+
/**
|
|
14667
|
+
* How is the model provider important?
|
|
14668
|
+
*
|
|
14669
|
+
* @public exported from `@promptbook/core`
|
|
14670
|
+
*/
|
|
14671
|
+
const MODEL_ORDER = {
|
|
14672
|
+
/**
|
|
14673
|
+
* Top-tier models, e.g. OpenAI, Anthropic,...
|
|
14674
|
+
*/
|
|
14675
|
+
TOP_TIER: 333,
|
|
14676
|
+
/**
|
|
14677
|
+
* Mid-tier models, e.g. Llama, Mistral, etc.
|
|
14678
|
+
*/
|
|
14679
|
+
NORMAL: 100,
|
|
14680
|
+
/**
|
|
14681
|
+
* Low-tier models, e.g. Phi, Tiny, etc.
|
|
14682
|
+
*/
|
|
14683
|
+
LOW_TIER: 0,
|
|
14684
|
+
};
|
|
14685
|
+
/**
|
|
14686
|
+
* TODO: Add configuration schema and maybe some documentation link
|
|
14687
|
+
* TODO: Maybe constrain LlmToolsConfiguration[number] by generic to ensure that `createConfigurationFromEnv` and `getBoilerplateConfiguration` always create same `packageName` and `className`
|
|
14688
|
+
* TODO: [®] DRY Register logic
|
|
14689
|
+
*/
|
|
14690
|
+
|
|
13844
14691
|
/**
|
|
13845
14692
|
* Registration of LLM provider metadata
|
|
13846
14693
|
*
|
|
@@ -13855,9 +14702,11 @@
|
|
|
13855
14702
|
packageName: '@promptbook/anthropic-claude',
|
|
13856
14703
|
className: 'AnthropicClaudeExecutionTools',
|
|
13857
14704
|
envVariables: ['ANTHROPIC_CLAUDE_API_KEY'],
|
|
14705
|
+
trustLevel: 'CLOSED',
|
|
14706
|
+
order: MODEL_ORDER.TOP_TIER,
|
|
13858
14707
|
getBoilerplateConfiguration() {
|
|
13859
14708
|
return {
|
|
13860
|
-
title: 'Anthropic Claude
|
|
14709
|
+
title: 'Anthropic Claude',
|
|
13861
14710
|
packageName: '@promptbook/anthropic-claude',
|
|
13862
14711
|
className: 'AnthropicClaudeExecutionTools',
|
|
13863
14712
|
options: {
|
|
@@ -13911,6 +14760,7 @@
|
|
|
13911
14760
|
modelVariant: 'CHAT',
|
|
13912
14761
|
modelTitle: 'Claude 3.5 Sonnet',
|
|
13913
14762
|
modelName: 'claude-3-5-sonnet-20240620',
|
|
14763
|
+
modelDescription: 'Latest Claude model with great reasoning, coding, and language understanding capabilities. 200K context window. Optimized balance of intelligence and speed.',
|
|
13914
14764
|
pricing: {
|
|
13915
14765
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
13916
14766
|
output: computeUsage(`$15.00 / 1M tokens`),
|
|
@@ -13920,6 +14770,7 @@
|
|
|
13920
14770
|
modelVariant: 'CHAT',
|
|
13921
14771
|
modelTitle: 'Claude 3 Opus',
|
|
13922
14772
|
modelName: 'claude-3-opus-20240229',
|
|
14773
|
+
modelDescription: 'Most capable Claude model excelling at complex reasoning, coding, and detailed instruction following. 200K context window. Best for sophisticated tasks requiring nuanced understanding.',
|
|
13923
14774
|
pricing: {
|
|
13924
14775
|
prompt: computeUsage(`$15.00 / 1M tokens`),
|
|
13925
14776
|
output: computeUsage(`$75.00 / 1M tokens`),
|
|
@@ -13929,6 +14780,7 @@
|
|
|
13929
14780
|
modelVariant: 'CHAT',
|
|
13930
14781
|
modelTitle: 'Claude 3 Sonnet',
|
|
13931
14782
|
modelName: 'claude-3-sonnet-20240229',
|
|
14783
|
+
modelDescription: 'Strong general-purpose model with excellent performance across reasoning, conversation, and coding tasks. 200K context window. Good balance of intelligence and cost-efficiency.',
|
|
13932
14784
|
pricing: {
|
|
13933
14785
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
13934
14786
|
output: computeUsage(`$15.00 / 1M tokens`),
|
|
@@ -13938,6 +14790,7 @@
|
|
|
13938
14790
|
modelVariant: 'CHAT',
|
|
13939
14791
|
modelTitle: 'Claude 3 Haiku',
|
|
13940
14792
|
modelName: ' claude-3-haiku-20240307',
|
|
14793
|
+
modelDescription: 'Fastest and most compact Claude model optimized for responsiveness in interactive applications. 200K context window. Excellent for quick responses and lightweight applications.',
|
|
13941
14794
|
pricing: {
|
|
13942
14795
|
prompt: computeUsage(`$0.25 / 1M tokens`),
|
|
13943
14796
|
output: computeUsage(`$1.25 / 1M tokens`),
|
|
@@ -13947,6 +14800,7 @@
|
|
|
13947
14800
|
modelVariant: 'CHAT',
|
|
13948
14801
|
modelTitle: 'Claude 2.1',
|
|
13949
14802
|
modelName: 'claude-2.1',
|
|
14803
|
+
modelDescription: 'Improved version of Claude 2 with better performance across reasoning and truthfulness. 100K context window. Legacy model with strong reliability.',
|
|
13950
14804
|
pricing: {
|
|
13951
14805
|
prompt: computeUsage(`$8.00 / 1M tokens`),
|
|
13952
14806
|
output: computeUsage(`$24.00 / 1M tokens`),
|
|
@@ -13956,6 +14810,7 @@
|
|
|
13956
14810
|
modelVariant: 'CHAT',
|
|
13957
14811
|
modelTitle: 'Claude 2',
|
|
13958
14812
|
modelName: 'claude-2.0',
|
|
14813
|
+
modelDescription: 'Legacy model with strong general reasoning and language capabilities. 100K context window. Superseded by newer Claude 3 models.',
|
|
13959
14814
|
pricing: {
|
|
13960
14815
|
prompt: computeUsage(`$8.00 / 1M tokens`),
|
|
13961
14816
|
output: computeUsage(`$24.00 / 1M tokens`),
|
|
@@ -13963,14 +14818,35 @@
|
|
|
13963
14818
|
},
|
|
13964
14819
|
{
|
|
13965
14820
|
modelVariant: 'CHAT',
|
|
13966
|
-
modelTitle: '
|
|
14821
|
+
modelTitle: 'Claude Instant 1.2',
|
|
13967
14822
|
modelName: 'claude-instant-1.2',
|
|
14823
|
+
modelDescription: 'Older, faster Claude model optimized for high throughput applications. Lower cost but less capable than newer models. 100K context window.',
|
|
13968
14824
|
pricing: {
|
|
13969
14825
|
prompt: computeUsage(`$0.80 / 1M tokens`),
|
|
13970
14826
|
output: computeUsage(`$2.40 / 1M tokens`),
|
|
13971
14827
|
},
|
|
13972
14828
|
},
|
|
13973
|
-
|
|
14829
|
+
{
|
|
14830
|
+
modelVariant: 'CHAT',
|
|
14831
|
+
modelTitle: 'Claude 3.7 Sonnet',
|
|
14832
|
+
modelName: 'claude-3-7-sonnet-20250219',
|
|
14833
|
+
modelDescription: 'Latest generation Claude model with advanced reasoning and language understanding. Enhanced capabilities over 3.5 with improved domain knowledge. 200K context window.',
|
|
14834
|
+
pricing: {
|
|
14835
|
+
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14836
|
+
output: computeUsage(`$15.00 / 1M tokens`),
|
|
14837
|
+
},
|
|
14838
|
+
},
|
|
14839
|
+
{
|
|
14840
|
+
modelVariant: 'CHAT',
|
|
14841
|
+
modelTitle: 'Claude 3.5 Haiku',
|
|
14842
|
+
modelName: 'claude-3-5-haiku-20241022',
|
|
14843
|
+
modelDescription: 'Fast and efficient Claude 3.5 variant optimized for speed and cost-effectiveness. Great for interactive applications requiring quick responses. 200K context window.',
|
|
14844
|
+
pricing: {
|
|
14845
|
+
prompt: computeUsage(`$0.25 / 1M tokens`),
|
|
14846
|
+
output: computeUsage(`$1.25 / 1M tokens`),
|
|
14847
|
+
},
|
|
14848
|
+
},
|
|
14849
|
+
// <- [🕕]
|
|
13974
14850
|
],
|
|
13975
14851
|
});
|
|
13976
14852
|
/**
|
|
@@ -14366,9 +15242,11 @@
|
|
|
14366
15242
|
packageName: '@promptbook/azure-openai',
|
|
14367
15243
|
className: 'AzureOpenAiExecutionTools',
|
|
14368
15244
|
envVariables: ['AZUREOPENAI_RESOURCE_NAME', 'AZUREOPENAI_DEPLOYMENT_NAME', 'AZUREOPENAI_API_KEY'],
|
|
15245
|
+
trustLevel: 'CLOSED_BUSINESS',
|
|
15246
|
+
order: MODEL_ORDER.NORMAL,
|
|
14369
15247
|
getBoilerplateConfiguration() {
|
|
14370
15248
|
return {
|
|
14371
|
-
title: 'Azure Open AI
|
|
15249
|
+
title: 'Azure Open AI',
|
|
14372
15250
|
packageName: '@promptbook/azure-openai',
|
|
14373
15251
|
className: 'AzureOpenAiExecutionTools',
|
|
14374
15252
|
options: {
|
|
@@ -14449,9 +15327,10 @@
|
|
|
14449
15327
|
modelVariant: 'COMPLETION',
|
|
14450
15328
|
modelTitle: 'davinci-002',
|
|
14451
15329
|
modelName: 'davinci-002',
|
|
15330
|
+
modelDescription: 'Legacy completion model with strong performance on text generation tasks. Optimized for complex instructions and longer outputs.',
|
|
14452
15331
|
pricing: {
|
|
14453
15332
|
prompt: computeUsage(`$2.00 / 1M tokens`),
|
|
14454
|
-
output: computeUsage(`$2.00 / 1M tokens`),
|
|
15333
|
+
output: computeUsage(`$2.00 / 1M tokens`),
|
|
14455
15334
|
},
|
|
14456
15335
|
},
|
|
14457
15336
|
/**/
|
|
@@ -14466,6 +15345,7 @@
|
|
|
14466
15345
|
modelVariant: 'CHAT',
|
|
14467
15346
|
modelTitle: 'gpt-3.5-turbo-16k',
|
|
14468
15347
|
modelName: 'gpt-3.5-turbo-16k',
|
|
15348
|
+
modelDescription: 'GPT-3.5 Turbo with extended 16k token context length for handling longer conversations and documents.',
|
|
14469
15349
|
pricing: {
|
|
14470
15350
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14471
15351
|
output: computeUsage(`$4.00 / 1M tokens`),
|
|
@@ -14489,6 +15369,7 @@
|
|
|
14489
15369
|
modelVariant: 'CHAT',
|
|
14490
15370
|
modelTitle: 'gpt-4',
|
|
14491
15371
|
modelName: 'gpt-4',
|
|
15372
|
+
modelDescription: 'GPT-4 is a powerful language model with enhanced reasoning, instruction-following capabilities, and 8K context window. Optimized for complex tasks requiring deep understanding.',
|
|
14492
15373
|
pricing: {
|
|
14493
15374
|
prompt: computeUsage(`$30.00 / 1M tokens`),
|
|
14494
15375
|
output: computeUsage(`$60.00 / 1M tokens`),
|
|
@@ -14500,6 +15381,7 @@
|
|
|
14500
15381
|
modelVariant: 'CHAT',
|
|
14501
15382
|
modelTitle: 'gpt-4-32k',
|
|
14502
15383
|
modelName: 'gpt-4-32k',
|
|
15384
|
+
modelDescription: 'Extended context version of GPT-4 with a 32K token window for processing very long inputs and generating comprehensive responses for complex tasks.',
|
|
14503
15385
|
pricing: {
|
|
14504
15386
|
prompt: computeUsage(`$60.00 / 1M tokens`),
|
|
14505
15387
|
output: computeUsage(`$120.00 / 1M tokens`),
|
|
@@ -14522,6 +15404,7 @@
|
|
|
14522
15404
|
modelVariant: 'CHAT',
|
|
14523
15405
|
modelTitle: 'gpt-4-turbo-2024-04-09',
|
|
14524
15406
|
modelName: 'gpt-4-turbo-2024-04-09',
|
|
15407
|
+
modelDescription: 'Latest stable GPT-4 Turbo model from April 2024 with enhanced reasoning and context handling capabilities. Offers 128K context window and improved performance.',
|
|
14525
15408
|
pricing: {
|
|
14526
15409
|
prompt: computeUsage(`$10.00 / 1M tokens`),
|
|
14527
15410
|
output: computeUsage(`$30.00 / 1M tokens`),
|
|
@@ -14533,6 +15416,7 @@
|
|
|
14533
15416
|
modelVariant: 'CHAT',
|
|
14534
15417
|
modelTitle: 'gpt-3.5-turbo-1106',
|
|
14535
15418
|
modelName: 'gpt-3.5-turbo-1106',
|
|
15419
|
+
modelDescription: 'November 2023 version of GPT-3.5 Turbo with improved instruction following and a 16K token context window.',
|
|
14536
15420
|
pricing: {
|
|
14537
15421
|
prompt: computeUsage(`$1.00 / 1M tokens`),
|
|
14538
15422
|
output: computeUsage(`$2.00 / 1M tokens`),
|
|
@@ -14544,6 +15428,7 @@
|
|
|
14544
15428
|
modelVariant: 'CHAT',
|
|
14545
15429
|
modelTitle: 'gpt-4-turbo',
|
|
14546
15430
|
modelName: 'gpt-4-turbo',
|
|
15431
|
+
modelDescription: 'More capable model than GPT-4 with improved instruction following, function calling and a 128K token context window for handling very large documents.',
|
|
14547
15432
|
pricing: {
|
|
14548
15433
|
prompt: computeUsage(`$10.00 / 1M tokens`),
|
|
14549
15434
|
output: computeUsage(`$30.00 / 1M tokens`),
|
|
@@ -14555,6 +15440,7 @@
|
|
|
14555
15440
|
modelVariant: 'COMPLETION',
|
|
14556
15441
|
modelTitle: 'gpt-3.5-turbo-instruct-0914',
|
|
14557
15442
|
modelName: 'gpt-3.5-turbo-instruct-0914',
|
|
15443
|
+
modelDescription: 'September 2023 version of GPT-3.5 Turbo optimized for completion-style instruction following with a 4K context window.',
|
|
14558
15444
|
pricing: {
|
|
14559
15445
|
prompt: computeUsage(`$1.50 / 1M tokens`),
|
|
14560
15446
|
output: computeUsage(`$2.00 / 1M tokens`), // <- For gpt-3.5-turbo-instruct
|
|
@@ -14566,6 +15452,7 @@
|
|
|
14566
15452
|
modelVariant: 'COMPLETION',
|
|
14567
15453
|
modelTitle: 'gpt-3.5-turbo-instruct',
|
|
14568
15454
|
modelName: 'gpt-3.5-turbo-instruct',
|
|
15455
|
+
modelDescription: 'Optimized version of GPT-3.5 for completion-style API with good instruction following and a 4K token context window.',
|
|
14569
15456
|
pricing: {
|
|
14570
15457
|
prompt: computeUsage(`$1.50 / 1M tokens`),
|
|
14571
15458
|
output: computeUsage(`$2.00 / 1M tokens`),
|
|
@@ -14583,9 +15470,10 @@
|
|
|
14583
15470
|
modelVariant: 'CHAT',
|
|
14584
15471
|
modelTitle: 'gpt-3.5-turbo',
|
|
14585
15472
|
modelName: 'gpt-3.5-turbo',
|
|
15473
|
+
modelDescription: 'Latest version of GPT-3.5 Turbo with improved performance and instruction following capabilities. Default 4K context window with options for 16K.',
|
|
14586
15474
|
pricing: {
|
|
14587
|
-
prompt: computeUsage(`$
|
|
14588
|
-
output: computeUsage(`$
|
|
15475
|
+
prompt: computeUsage(`$0.50 / 1M tokens`),
|
|
15476
|
+
output: computeUsage(`$1.50 / 1M tokens`),
|
|
14589
15477
|
},
|
|
14590
15478
|
},
|
|
14591
15479
|
/**/
|
|
@@ -14594,6 +15482,7 @@
|
|
|
14594
15482
|
modelVariant: 'CHAT',
|
|
14595
15483
|
modelTitle: 'gpt-3.5-turbo-0301',
|
|
14596
15484
|
modelName: 'gpt-3.5-turbo-0301',
|
|
15485
|
+
modelDescription: 'March 2023 version of GPT-3.5 Turbo with a 4K token context window. Legacy model maintained for backward compatibility.',
|
|
14597
15486
|
pricing: {
|
|
14598
15487
|
prompt: computeUsage(`$1.50 / 1M tokens`),
|
|
14599
15488
|
output: computeUsage(`$2.00 / 1M tokens`),
|
|
@@ -14605,9 +15494,10 @@
|
|
|
14605
15494
|
modelVariant: 'COMPLETION',
|
|
14606
15495
|
modelTitle: 'babbage-002',
|
|
14607
15496
|
modelName: 'babbage-002',
|
|
15497
|
+
modelDescription: 'Efficient legacy completion model with a good balance of performance and speed. Suitable for straightforward text generation tasks.',
|
|
14608
15498
|
pricing: {
|
|
14609
15499
|
prompt: computeUsage(`$0.40 / 1M tokens`),
|
|
14610
|
-
output: computeUsage(`$0.40 / 1M tokens`),
|
|
15500
|
+
output: computeUsage(`$0.40 / 1M tokens`),
|
|
14611
15501
|
},
|
|
14612
15502
|
},
|
|
14613
15503
|
/**/
|
|
@@ -14616,6 +15506,7 @@
|
|
|
14616
15506
|
modelVariant: 'CHAT',
|
|
14617
15507
|
modelTitle: 'gpt-4-1106-preview',
|
|
14618
15508
|
modelName: 'gpt-4-1106-preview',
|
|
15509
|
+
modelDescription: 'November 2023 preview version of GPT-4 Turbo with improved instruction following and a 128K token context window.',
|
|
14619
15510
|
pricing: {
|
|
14620
15511
|
prompt: computeUsage(`$10.00 / 1M tokens`),
|
|
14621
15512
|
output: computeUsage(`$30.00 / 1M tokens`),
|
|
@@ -14627,6 +15518,7 @@
|
|
|
14627
15518
|
modelVariant: 'CHAT',
|
|
14628
15519
|
modelTitle: 'gpt-4-0125-preview',
|
|
14629
15520
|
modelName: 'gpt-4-0125-preview',
|
|
15521
|
+
modelDescription: 'January 2024 preview version of GPT-4 Turbo with improved reasoning capabilities and a 128K token context window.',
|
|
14630
15522
|
pricing: {
|
|
14631
15523
|
prompt: computeUsage(`$10.00 / 1M tokens`),
|
|
14632
15524
|
output: computeUsage(`$30.00 / 1M tokens`),
|
|
@@ -14644,6 +15536,7 @@
|
|
|
14644
15536
|
modelVariant: 'CHAT',
|
|
14645
15537
|
modelTitle: 'gpt-3.5-turbo-0125',
|
|
14646
15538
|
modelName: 'gpt-3.5-turbo-0125',
|
|
15539
|
+
modelDescription: 'January 2024 version of GPT-3.5 Turbo with improved reasoning capabilities and a 16K token context window.',
|
|
14647
15540
|
pricing: {
|
|
14648
15541
|
prompt: computeUsage(`$0.50 / 1M tokens`),
|
|
14649
15542
|
output: computeUsage(`$1.50 / 1M tokens`),
|
|
@@ -14655,9 +15548,10 @@
|
|
|
14655
15548
|
modelVariant: 'CHAT',
|
|
14656
15549
|
modelTitle: 'gpt-4-turbo-preview',
|
|
14657
15550
|
modelName: 'gpt-4-turbo-preview',
|
|
15551
|
+
modelDescription: 'Preview version of GPT-4 Turbo that points to the latest model version. Features improved instruction following, 128K token context window and lower latency.',
|
|
14658
15552
|
pricing: {
|
|
14659
15553
|
prompt: computeUsage(`$10.00 / 1M tokens`),
|
|
14660
|
-
output: computeUsage(`$30.00 / 1M tokens`),
|
|
15554
|
+
output: computeUsage(`$30.00 / 1M tokens`),
|
|
14661
15555
|
},
|
|
14662
15556
|
},
|
|
14663
15557
|
/**/
|
|
@@ -14666,6 +15560,7 @@
|
|
|
14666
15560
|
modelVariant: 'EMBEDDING',
|
|
14667
15561
|
modelTitle: 'text-embedding-3-large',
|
|
14668
15562
|
modelName: 'text-embedding-3-large',
|
|
15563
|
+
modelDescription: "OpenAI's most capable text embedding model designed for high-quality embeddings for complex similarity tasks and information retrieval.",
|
|
14669
15564
|
pricing: {
|
|
14670
15565
|
prompt: computeUsage(`$0.13 / 1M tokens`),
|
|
14671
15566
|
// TODO: [🏏] Leverage the batch API @see https://platform.openai.com/docs/guides/batch
|
|
@@ -14678,6 +15573,7 @@
|
|
|
14678
15573
|
modelVariant: 'EMBEDDING',
|
|
14679
15574
|
modelTitle: 'text-embedding-3-small',
|
|
14680
15575
|
modelName: 'text-embedding-3-small',
|
|
15576
|
+
modelDescription: 'Cost-effective embedding model with good performance for simpler tasks like text similarity and retrieval. Good balance of quality and efficiency.',
|
|
14681
15577
|
pricing: {
|
|
14682
15578
|
prompt: computeUsage(`$0.02 / 1M tokens`),
|
|
14683
15579
|
// TODO: [🏏] Leverage the batch API @see https://platform.openai.com/docs/guides/batch
|
|
@@ -14690,6 +15586,7 @@
|
|
|
14690
15586
|
modelVariant: 'CHAT',
|
|
14691
15587
|
modelTitle: 'gpt-3.5-turbo-0613',
|
|
14692
15588
|
modelName: 'gpt-3.5-turbo-0613',
|
|
15589
|
+
modelDescription: 'June 2023 version of GPT-3.5 Turbo with function calling capabilities and a 4K token context window.',
|
|
14693
15590
|
pricing: {
|
|
14694
15591
|
prompt: computeUsage(`$1.50 / 1M tokens`),
|
|
14695
15592
|
output: computeUsage(`$2.00 / 1M tokens`),
|
|
@@ -14701,6 +15598,7 @@
|
|
|
14701
15598
|
modelVariant: 'EMBEDDING',
|
|
14702
15599
|
modelTitle: 'text-embedding-ada-002',
|
|
14703
15600
|
modelName: 'text-embedding-ada-002',
|
|
15601
|
+
modelDescription: 'Legacy text embedding model suitable for text similarity and retrieval augmented generation use cases. Replaced by newer embedding-3 models.',
|
|
14704
15602
|
pricing: {
|
|
14705
15603
|
prompt: computeUsage(`$0.1 / 1M tokens`),
|
|
14706
15604
|
// TODO: [🏏] Leverage the batch API @see https://platform.openai.com/docs/guides/batch
|
|
@@ -14731,11 +15629,11 @@
|
|
|
14731
15629
|
modelVariant: 'CHAT',
|
|
14732
15630
|
modelTitle: 'gpt-4o-2024-05-13',
|
|
14733
15631
|
modelName: 'gpt-4o-2024-05-13',
|
|
15632
|
+
modelDescription: 'May 2024 version of GPT-4o with enhanced multimodal capabilities, improved reasoning, and optimized for vision, audio and chat at lower latencies.',
|
|
14734
15633
|
pricing: {
|
|
14735
15634
|
prompt: computeUsage(`$5.00 / 1M tokens`),
|
|
14736
15635
|
output: computeUsage(`$15.00 / 1M tokens`),
|
|
14737
15636
|
},
|
|
14738
|
-
//TODO: [main] !!3 Add gpt-4o-mini-2024-07-18 and all others to be up to date
|
|
14739
15637
|
},
|
|
14740
15638
|
/**/
|
|
14741
15639
|
/**/
|
|
@@ -14743,6 +15641,7 @@
|
|
|
14743
15641
|
modelVariant: 'CHAT',
|
|
14744
15642
|
modelTitle: 'gpt-4o',
|
|
14745
15643
|
modelName: 'gpt-4o',
|
|
15644
|
+
modelDescription: "OpenAI's most advanced multimodal model optimized for performance, speed, and cost. Capable of vision, reasoning, and high quality text generation.",
|
|
14746
15645
|
pricing: {
|
|
14747
15646
|
prompt: computeUsage(`$5.00 / 1M tokens`),
|
|
14748
15647
|
output: computeUsage(`$15.00 / 1M tokens`),
|
|
@@ -14750,10 +15649,23 @@
|
|
|
14750
15649
|
},
|
|
14751
15650
|
/**/
|
|
14752
15651
|
/**/
|
|
15652
|
+
{
|
|
15653
|
+
modelVariant: 'CHAT',
|
|
15654
|
+
modelTitle: 'gpt-4o-mini',
|
|
15655
|
+
modelName: 'gpt-4o-mini',
|
|
15656
|
+
modelDescription: 'Smaller, more cost-effective version of GPT-4o with good performance across text, vision, and audio tasks at reduced complexity.',
|
|
15657
|
+
pricing: {
|
|
15658
|
+
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
15659
|
+
output: computeUsage(`$9.00 / 1M tokens`),
|
|
15660
|
+
},
|
|
15661
|
+
},
|
|
15662
|
+
/**/
|
|
15663
|
+
/**/
|
|
14753
15664
|
{
|
|
14754
15665
|
modelVariant: 'CHAT',
|
|
14755
15666
|
modelTitle: 'o1-preview',
|
|
14756
15667
|
modelName: 'o1-preview',
|
|
15668
|
+
modelDescription: 'Advanced reasoning model with exceptional performance on complex logical, mathematical, and analytical tasks. Built for deep reasoning and specialized professional tasks.',
|
|
14757
15669
|
pricing: {
|
|
14758
15670
|
prompt: computeUsage(`$15.00 / 1M tokens`),
|
|
14759
15671
|
output: computeUsage(`$60.00 / 1M tokens`),
|
|
@@ -14765,6 +15677,7 @@
|
|
|
14765
15677
|
modelVariant: 'CHAT',
|
|
14766
15678
|
modelTitle: 'o1-preview-2024-09-12',
|
|
14767
15679
|
modelName: 'o1-preview-2024-09-12',
|
|
15680
|
+
modelDescription: 'September 2024 version of O1 preview with specialized reasoning capabilities for complex tasks requiring precise analytical thinking.',
|
|
14768
15681
|
// <- TODO: [💩] Some better system to organize theese date suffixes and versions
|
|
14769
15682
|
pricing: {
|
|
14770
15683
|
prompt: computeUsage(`$15.00 / 1M tokens`),
|
|
@@ -14777,6 +15690,7 @@
|
|
|
14777
15690
|
modelVariant: 'CHAT',
|
|
14778
15691
|
modelTitle: 'o1-mini',
|
|
14779
15692
|
modelName: 'o1-mini',
|
|
15693
|
+
modelDescription: 'Smaller, cost-effective version of the O1 model with good performance on reasoning tasks while maintaining efficiency for everyday analytical use.',
|
|
14780
15694
|
pricing: {
|
|
14781
15695
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14782
15696
|
output: computeUsage(`$12.00 / 1M tokens`),
|
|
@@ -14788,10 +15702,10 @@
|
|
|
14788
15702
|
modelVariant: 'CHAT',
|
|
14789
15703
|
modelTitle: 'o1',
|
|
14790
15704
|
modelName: 'o1',
|
|
15705
|
+
modelDescription: "OpenAI's advanced reasoning model focused on logic and problem-solving. Designed for complex analytical tasks with rigorous step-by-step reasoning. 128K context window.",
|
|
14791
15706
|
pricing: {
|
|
14792
|
-
prompt: computeUsage(`$
|
|
14793
|
-
output: computeUsage(`$
|
|
14794
|
-
// <- TODO: !! Unsure, check the pricing
|
|
15707
|
+
prompt: computeUsage(`$15.00 / 1M tokens`),
|
|
15708
|
+
output: computeUsage(`$60.00 / 1M tokens`),
|
|
14795
15709
|
},
|
|
14796
15710
|
},
|
|
14797
15711
|
/**/
|
|
@@ -14800,6 +15714,7 @@
|
|
|
14800
15714
|
modelVariant: 'CHAT',
|
|
14801
15715
|
modelTitle: 'o3-mini',
|
|
14802
15716
|
modelName: 'o3-mini',
|
|
15717
|
+
modelDescription: 'Cost-effective reasoning model optimized for academic and scientific problem-solving. Efficient performance on STEM tasks with deep mathematical and scientific knowledge. 128K context window.',
|
|
14803
15718
|
pricing: {
|
|
14804
15719
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14805
15720
|
output: computeUsage(`$12.00 / 1M tokens`),
|
|
@@ -14812,6 +15727,7 @@
|
|
|
14812
15727
|
modelVariant: 'CHAT',
|
|
14813
15728
|
modelTitle: 'o1-mini-2024-09-12',
|
|
14814
15729
|
modelName: 'o1-mini-2024-09-12',
|
|
15730
|
+
modelDescription: "September 2024 version of O1-mini with balanced reasoning capabilities and cost-efficiency. Good for analytical tasks that don't require the full O1 model.",
|
|
14815
15731
|
pricing: {
|
|
14816
15732
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14817
15733
|
output: computeUsage(`$12.00 / 1M tokens`),
|
|
@@ -14823,12 +15739,14 @@
|
|
|
14823
15739
|
modelVariant: 'CHAT',
|
|
14824
15740
|
modelTitle: 'gpt-3.5-turbo-16k-0613',
|
|
14825
15741
|
modelName: 'gpt-3.5-turbo-16k-0613',
|
|
15742
|
+
modelDescription: 'June 2023 version of GPT-3.5 Turbo with extended 16k token context window for processing longer conversations and documents.',
|
|
14826
15743
|
pricing: {
|
|
14827
15744
|
prompt: computeUsage(`$3.00 / 1M tokens`),
|
|
14828
15745
|
output: computeUsage(`$4.00 / 1M tokens`),
|
|
14829
15746
|
},
|
|
14830
15747
|
},
|
|
14831
15748
|
/**/
|
|
15749
|
+
// <- [🕕]
|
|
14832
15750
|
],
|
|
14833
15751
|
});
|
|
14834
15752
|
/**
|
|
@@ -14846,6 +15764,9 @@
|
|
|
14846
15764
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
14847
15765
|
*/
|
|
14848
15766
|
|
|
15767
|
+
// Default rate limits (requests per minute) - adjust as needed based on Azure OpenAI tier
|
|
15768
|
+
const DEFAULT_RPM$1 = 60;
|
|
15769
|
+
// <- TODO: !!! Put in some better place
|
|
14849
15770
|
/**
|
|
14850
15771
|
* Execution Tools for calling Azure OpenAI API.
|
|
14851
15772
|
*
|
|
@@ -14863,6 +15784,10 @@
|
|
|
14863
15784
|
* OpenAI Azure API client.
|
|
14864
15785
|
*/
|
|
14865
15786
|
this.client = null;
|
|
15787
|
+
// TODO: Allow configuring rate limits via options
|
|
15788
|
+
this.limiter = new Bottleneck__default["default"]({
|
|
15789
|
+
minTime: 60000 / (this.options.maxRequestsPerMinute || DEFAULT_RPM$1),
|
|
15790
|
+
});
|
|
14866
15791
|
}
|
|
14867
15792
|
get title() {
|
|
14868
15793
|
return 'Azure OpenAI';
|
|
@@ -14940,7 +15865,9 @@
|
|
|
14940
15865
|
console.info(colors__default["default"].bgWhite('messages'), JSON.stringify(messages, null, 4));
|
|
14941
15866
|
}
|
|
14942
15867
|
const rawRequest = [modelName, messages, modelSettings];
|
|
14943
|
-
const rawResponse = await this.
|
|
15868
|
+
const rawResponse = await this.limiter
|
|
15869
|
+
.schedule(() => this.withTimeout(client.getChatCompletions(...rawRequest)))
|
|
15870
|
+
.catch((error) => {
|
|
14944
15871
|
if (this.options.isVerbose) {
|
|
14945
15872
|
console.info(colors__default["default"].bgRed('error'), error);
|
|
14946
15873
|
}
|
|
@@ -15036,7 +15963,9 @@
|
|
|
15036
15963
|
[rawPromptContent],
|
|
15037
15964
|
modelSettings,
|
|
15038
15965
|
];
|
|
15039
|
-
const rawResponse = await this.
|
|
15966
|
+
const rawResponse = await this.limiter
|
|
15967
|
+
.schedule(() => this.withTimeout(client.getCompletions(...rawRequest)))
|
|
15968
|
+
.catch((error) => {
|
|
15040
15969
|
if (this.options.isVerbose) {
|
|
15041
15970
|
console.info(colors__default["default"].bgRed('error'), error);
|
|
15042
15971
|
}
|
|
@@ -15176,9 +16105,11 @@
|
|
|
15176
16105
|
packageName: '@promptbook/deepseek',
|
|
15177
16106
|
className: 'DeepseekExecutionTools',
|
|
15178
16107
|
envVariables: ['DEEPSEEK_GENERATIVE_AI_API_KEY'],
|
|
16108
|
+
trustLevel: 'UNTRUSTED',
|
|
16109
|
+
order: MODEL_ORDER.NORMAL,
|
|
15179
16110
|
getBoilerplateConfiguration() {
|
|
15180
16111
|
return {
|
|
15181
|
-
title: 'Deepseek
|
|
16112
|
+
title: 'Deepseek',
|
|
15182
16113
|
packageName: '@promptbook/deepseek',
|
|
15183
16114
|
className: 'DeepseekExecutionTools',
|
|
15184
16115
|
options: {
|
|
@@ -15375,6 +16306,67 @@
|
|
|
15375
16306
|
};
|
|
15376
16307
|
}
|
|
15377
16308
|
|
|
16309
|
+
/**
|
|
16310
|
+
* List of available Deepseek models with descriptions
|
|
16311
|
+
*
|
|
16312
|
+
* Note: Done at 2025-04-22
|
|
16313
|
+
*
|
|
16314
|
+
* @see https://www.deepseek.com/models
|
|
16315
|
+
* @public exported from `@promptbook/deepseek`
|
|
16316
|
+
*/
|
|
16317
|
+
const DEEPSEEK_MODELS = exportJson({
|
|
16318
|
+
name: 'DEEPSEEK_MODELS',
|
|
16319
|
+
value: [
|
|
16320
|
+
{
|
|
16321
|
+
modelVariant: 'CHAT',
|
|
16322
|
+
modelTitle: 'Deepseek Chat',
|
|
16323
|
+
modelName: 'deepseek-chat',
|
|
16324
|
+
modelDescription: 'General-purpose language model with strong performance across conversation, reasoning, and content generation. 128K context window with excellent instruction following capabilities.',
|
|
16325
|
+
pricing: {
|
|
16326
|
+
prompt: computeUsage(`$1.00 / 1M tokens`),
|
|
16327
|
+
output: computeUsage(`$2.00 / 1M tokens`),
|
|
16328
|
+
},
|
|
16329
|
+
},
|
|
16330
|
+
{
|
|
16331
|
+
modelVariant: 'CHAT',
|
|
16332
|
+
modelTitle: 'Deepseek Reasoner',
|
|
16333
|
+
modelName: 'deepseek-reasoner',
|
|
16334
|
+
modelDescription: 'Specialized model focused on complex reasoning tasks like mathematical problem-solving and logical analysis. Enhanced step-by-step reasoning with explicit chain-of-thought processes. 128K context window.',
|
|
16335
|
+
pricing: {
|
|
16336
|
+
prompt: computeUsage(`$4.00 / 1M tokens`),
|
|
16337
|
+
output: computeUsage(`$8.00 / 1M tokens`),
|
|
16338
|
+
},
|
|
16339
|
+
},
|
|
16340
|
+
{
|
|
16341
|
+
modelVariant: 'CHAT',
|
|
16342
|
+
modelTitle: 'DeepSeek V3',
|
|
16343
|
+
modelName: 'deepseek-v3-0324',
|
|
16344
|
+
modelDescription: 'Advanced general-purpose model with improved reasoning, coding abilities, and multimodal understanding. Built on the latest DeepSeek architecture with enhanced knowledge representation.',
|
|
16345
|
+
pricing: {
|
|
16346
|
+
prompt: computeUsage(`$1.50 / 1M tokens`),
|
|
16347
|
+
output: computeUsage(`$3.00 / 1M tokens`),
|
|
16348
|
+
},
|
|
16349
|
+
},
|
|
16350
|
+
{
|
|
16351
|
+
modelVariant: 'CHAT',
|
|
16352
|
+
modelTitle: 'DeepSeek R1',
|
|
16353
|
+
modelName: 'deepseek-r1',
|
|
16354
|
+
modelDescription: 'Research-focused model optimized for scientific problem-solving and analytical tasks. Excellent performance on tasks requiring domain-specific expertise and critical thinking.',
|
|
16355
|
+
pricing: {
|
|
16356
|
+
prompt: computeUsage(`$5.00 / 1M tokens`),
|
|
16357
|
+
output: computeUsage(`$10.00 / 1M tokens`),
|
|
16358
|
+
},
|
|
16359
|
+
},
|
|
16360
|
+
// <- [🕕]
|
|
16361
|
+
],
|
|
16362
|
+
});
|
|
16363
|
+
/**
|
|
16364
|
+
* TODO: [🧠] Add information about context window sizes, capabilities, and relative performance characteristics
|
|
16365
|
+
* TODO: [🎰] Some mechanism to auto-update available models
|
|
16366
|
+
* TODO: [🧠] Verify pricing information is current with Deepseek's official documentation
|
|
16367
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
16368
|
+
*/
|
|
16369
|
+
|
|
15378
16370
|
/**
|
|
15379
16371
|
* Execution Tools for calling Deepseek API.
|
|
15380
16372
|
*
|
|
@@ -15396,12 +16388,7 @@
|
|
|
15396
16388
|
title: 'Deepseek',
|
|
15397
16389
|
description: 'Implementation of Deepseek models',
|
|
15398
16390
|
vercelProvider: deepseekVercelProvider,
|
|
15399
|
-
availableModels:
|
|
15400
|
-
// TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
|
|
15401
|
-
'deepseek-chat',
|
|
15402
|
-
'deepseek-reasoner',
|
|
15403
|
-
// <- TODO: How picking of the default model looks like in `createExecutionToolsFromVercelProvider`
|
|
15404
|
-
].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
|
|
16391
|
+
availableModels: DEEPSEEK_MODELS,
|
|
15405
16392
|
...options,
|
|
15406
16393
|
});
|
|
15407
16394
|
}, {
|
|
@@ -15441,9 +16428,11 @@
|
|
|
15441
16428
|
packageName: '@promptbook/google',
|
|
15442
16429
|
className: 'GoogleExecutionTools',
|
|
15443
16430
|
envVariables: ['GOOGLE_GENERATIVE_AI_API_KEY'],
|
|
16431
|
+
trustLevel: 'CLOSED',
|
|
16432
|
+
order: MODEL_ORDER.NORMAL,
|
|
15444
16433
|
getBoilerplateConfiguration() {
|
|
15445
16434
|
return {
|
|
15446
|
-
title: 'Google Gemini
|
|
16435
|
+
title: 'Google Gemini',
|
|
15447
16436
|
packageName: '@promptbook/google',
|
|
15448
16437
|
className: 'GoogleExecutionTools',
|
|
15449
16438
|
options: {
|
|
@@ -15476,6 +16465,173 @@
|
|
|
15476
16465
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
15477
16466
|
*/
|
|
15478
16467
|
|
|
16468
|
+
/**
|
|
16469
|
+
* List of available Google models with descriptions
|
|
16470
|
+
*
|
|
16471
|
+
* Note: Done at 2025-04-22
|
|
16472
|
+
*
|
|
16473
|
+
* @see https://ai.google.dev/models/gemini
|
|
16474
|
+
* @public exported from `@promptbook/google`
|
|
16475
|
+
*/
|
|
16476
|
+
const GOOGLE_MODELS = exportJson({
|
|
16477
|
+
name: 'GOOGLE_MODELS',
|
|
16478
|
+
value: [
|
|
16479
|
+
{
|
|
16480
|
+
modelVariant: 'CHAT',
|
|
16481
|
+
modelTitle: 'Gemini 2.5 Pro',
|
|
16482
|
+
modelName: 'gemini-2.5-pro-preview-03-25',
|
|
16483
|
+
modelDescription: 'Latest advanced multimodal model with exceptional reasoning, tool use, and instruction following. 1M token context window with improved vision capabilities for complex visual tasks.',
|
|
16484
|
+
pricing: {
|
|
16485
|
+
prompt: computeUsage(`$7.00 / 1M tokens`),
|
|
16486
|
+
output: computeUsage(`$21.00 / 1M tokens`),
|
|
16487
|
+
},
|
|
16488
|
+
},
|
|
16489
|
+
{
|
|
16490
|
+
modelVariant: 'CHAT',
|
|
16491
|
+
modelTitle: 'Gemini 2.0 Flash',
|
|
16492
|
+
modelName: 'gemini-2.0-flash',
|
|
16493
|
+
modelDescription: 'Fast, efficient model optimized for rapid response times. Good balance between performance and cost, with strong capabilities across text, code, and reasoning tasks. 128K context window.',
|
|
16494
|
+
pricing: {
|
|
16495
|
+
prompt: computeUsage(`$0.35 / 1M tokens`),
|
|
16496
|
+
output: computeUsage(`$1.05 / 1M tokens`),
|
|
16497
|
+
},
|
|
16498
|
+
},
|
|
16499
|
+
{
|
|
16500
|
+
modelVariant: 'CHAT',
|
|
16501
|
+
modelTitle: 'Gemini 2.0 Flash Lite',
|
|
16502
|
+
modelName: 'gemini-2.0-flash-lite',
|
|
16503
|
+
modelDescription: 'Streamlined version of Gemini 2.0 Flash, designed for extremely low-latency applications and edge deployments. Optimized for efficiency while maintaining core capabilities.',
|
|
16504
|
+
pricing: {
|
|
16505
|
+
prompt: computeUsage(`$0.20 / 1M tokens`),
|
|
16506
|
+
output: computeUsage(`$0.60 / 1M tokens`),
|
|
16507
|
+
},
|
|
16508
|
+
},
|
|
16509
|
+
{
|
|
16510
|
+
modelVariant: 'CHAT',
|
|
16511
|
+
modelTitle: 'Gemini 2.0 Flash Thinking',
|
|
16512
|
+
modelName: 'gemini-2.0-flash-thinking-exp-01-21',
|
|
16513
|
+
modelDescription: 'Experimental model focused on enhanced reasoning with explicit chain-of-thought processes. Designed for tasks requiring structured thinking and problem-solving approaches.',
|
|
16514
|
+
pricing: {
|
|
16515
|
+
prompt: computeUsage(`$0.35 / 1M tokens`),
|
|
16516
|
+
output: computeUsage(`$1.05 / 1M tokens`),
|
|
16517
|
+
},
|
|
16518
|
+
},
|
|
16519
|
+
{
|
|
16520
|
+
modelVariant: 'CHAT',
|
|
16521
|
+
modelTitle: 'Gemini 1.5 Flash',
|
|
16522
|
+
modelName: 'gemini-1.5-flash',
|
|
16523
|
+
modelDescription: 'Efficient model balancing speed and quality for general-purpose applications. 1M token context window with good multimodal capabilities and quick response times.',
|
|
16524
|
+
pricing: {
|
|
16525
|
+
prompt: computeUsage(`$0.35 / 1M tokens`),
|
|
16526
|
+
output: computeUsage(`$1.05 / 1M tokens`),
|
|
16527
|
+
},
|
|
16528
|
+
},
|
|
16529
|
+
{
|
|
16530
|
+
modelVariant: 'CHAT',
|
|
16531
|
+
modelTitle: 'Gemini 1.5 Flash Latest',
|
|
16532
|
+
modelName: 'gemini-1.5-flash-latest',
|
|
16533
|
+
modelDescription: 'Points to the latest version of Gemini 1.5 Flash, ensuring access to the most recent improvements and bug fixes while maintaining stable interfaces.',
|
|
16534
|
+
},
|
|
16535
|
+
{
|
|
16536
|
+
modelVariant: 'CHAT',
|
|
16537
|
+
modelTitle: 'Gemini 1.5 Flash 001',
|
|
16538
|
+
modelName: 'gemini-1.5-flash-001',
|
|
16539
|
+
modelDescription: 'First stable release of Gemini 1.5 Flash model with reliable performance characteristics for production applications. 1M token context window.',
|
|
16540
|
+
},
|
|
16541
|
+
{
|
|
16542
|
+
modelVariant: 'CHAT',
|
|
16543
|
+
modelTitle: 'Gemini 1.5 Flash 002',
|
|
16544
|
+
modelName: 'gemini-1.5-flash-002',
|
|
16545
|
+
modelDescription: 'Improved version of Gemini 1.5 Flash with enhanced instruction following and more consistent outputs. Refined for better application integration.',
|
|
16546
|
+
},
|
|
16547
|
+
{
|
|
16548
|
+
modelVariant: 'CHAT',
|
|
16549
|
+
modelTitle: 'Gemini 1.5 Flash Exp',
|
|
16550
|
+
modelName: 'gemini-1.5-flash-exp-0827',
|
|
16551
|
+
modelDescription: 'Experimental version of Gemini 1.5 Flash with new capabilities being tested. May offer improved performance but with potential behavior differences from stable releases.',
|
|
16552
|
+
},
|
|
16553
|
+
{
|
|
16554
|
+
modelVariant: 'CHAT',
|
|
16555
|
+
modelTitle: 'Gemini 1.5 Flash 8B',
|
|
16556
|
+
modelName: 'gemini-1.5-flash-8b',
|
|
16557
|
+
modelDescription: 'Compact 8B parameter model optimized for efficiency and deployment in resource-constrained environments. Good performance despite smaller size.',
|
|
16558
|
+
},
|
|
16559
|
+
{
|
|
16560
|
+
modelVariant: 'CHAT',
|
|
16561
|
+
modelTitle: 'Gemini 1.5 Flash 8B Latest',
|
|
16562
|
+
modelName: 'gemini-1.5-flash-8b-latest',
|
|
16563
|
+
modelDescription: 'Points to the most recent version of the compact 8B parameter model, providing latest improvements while maintaining a small footprint.',
|
|
16564
|
+
},
|
|
16565
|
+
{
|
|
16566
|
+
modelVariant: 'CHAT',
|
|
16567
|
+
modelTitle: 'Gemini 1.5 Flash 8B Exp',
|
|
16568
|
+
modelName: 'gemini-1.5-flash-8b-exp-0924',
|
|
16569
|
+
modelDescription: 'Experimental version of the 8B parameter model with new capabilities and optimizations being evaluated for future stable releases.',
|
|
16570
|
+
},
|
|
16571
|
+
{
|
|
16572
|
+
modelVariant: 'CHAT',
|
|
16573
|
+
modelTitle: 'Gemini 1.5 Flash 8B Exp',
|
|
16574
|
+
modelName: 'gemini-1.5-flash-8b-exp-0827',
|
|
16575
|
+
modelDescription: 'August experimental release of the efficient 8B parameter model with specific improvements to reasoning capabilities and response quality.',
|
|
16576
|
+
},
|
|
16577
|
+
{
|
|
16578
|
+
modelVariant: 'CHAT',
|
|
16579
|
+
modelTitle: 'Gemini 1.5 Pro Latest',
|
|
16580
|
+
modelName: 'gemini-1.5-pro-latest',
|
|
16581
|
+
modelDescription: 'Points to the most recent version of the flagship Gemini 1.5 Pro model, ensuring access to the latest capabilities and improvements.',
|
|
16582
|
+
pricing: {
|
|
16583
|
+
prompt: computeUsage(`$7.00 / 1M tokens`),
|
|
16584
|
+
output: computeUsage(`$21.00 / 1M tokens`),
|
|
16585
|
+
},
|
|
16586
|
+
},
|
|
16587
|
+
{
|
|
16588
|
+
modelVariant: 'CHAT',
|
|
16589
|
+
modelTitle: 'Gemini 1.5 Pro',
|
|
16590
|
+
modelName: 'gemini-1.5-pro',
|
|
16591
|
+
modelDescription: 'Flagship multimodal model with strong performance across text, code, vision, and audio tasks. 1M token context window with excellent reasoning capabilities.',
|
|
16592
|
+
pricing: {
|
|
16593
|
+
prompt: computeUsage(`$7.00 / 1M tokens`),
|
|
16594
|
+
output: computeUsage(`$21.00 / 1M tokens`),
|
|
16595
|
+
},
|
|
16596
|
+
},
|
|
16597
|
+
{
|
|
16598
|
+
modelVariant: 'CHAT',
|
|
16599
|
+
modelTitle: 'Gemini 1.5 Pro 001',
|
|
16600
|
+
modelName: 'gemini-1.5-pro-001',
|
|
16601
|
+
modelDescription: 'First stable release of Gemini 1.5 Pro with consistent performance characteristics and reliable behavior for production applications.',
|
|
16602
|
+
},
|
|
16603
|
+
{
|
|
16604
|
+
modelVariant: 'CHAT',
|
|
16605
|
+
modelTitle: 'Gemini 1.5 Pro 002',
|
|
16606
|
+
modelName: 'gemini-1.5-pro-002',
|
|
16607
|
+
modelDescription: 'Refined version of Gemini 1.5 Pro with improved instruction following, better multimodal understanding, and more consistent outputs.',
|
|
16608
|
+
},
|
|
16609
|
+
{
|
|
16610
|
+
modelVariant: 'CHAT',
|
|
16611
|
+
modelTitle: 'Gemini 1.5 Pro Exp',
|
|
16612
|
+
modelName: 'gemini-1.5-pro-exp-0827',
|
|
16613
|
+
modelDescription: 'Experimental version of Gemini 1.5 Pro with new capabilities and optimizations being tested before wider release. May offer improved performance.',
|
|
16614
|
+
},
|
|
16615
|
+
{
|
|
16616
|
+
modelVariant: 'CHAT',
|
|
16617
|
+
modelTitle: 'Gemini 1.0 Pro',
|
|
16618
|
+
modelName: 'gemini-1.0-pro',
|
|
16619
|
+
modelDescription: 'Original Gemini series foundation model with solid multimodal capabilities. 32K context window with good performance on text, code, and basic vision tasks.',
|
|
16620
|
+
pricing: {
|
|
16621
|
+
prompt: computeUsage(`$0.35 / 1M tokens`),
|
|
16622
|
+
output: computeUsage(`$1.05 / 1M tokens`),
|
|
16623
|
+
},
|
|
16624
|
+
},
|
|
16625
|
+
// <- [🕕]
|
|
16626
|
+
],
|
|
16627
|
+
});
|
|
16628
|
+
/**
|
|
16629
|
+
* TODO: [🧠] Add information about context window sizes, capabilities, and relative performance characteristics
|
|
16630
|
+
* TODO: [🎰] Some mechanism to auto-update available models
|
|
16631
|
+
* TODO: [🧠] Verify pricing information is current with Google's official documentation
|
|
16632
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
16633
|
+
*/
|
|
16634
|
+
|
|
15479
16635
|
/**
|
|
15480
16636
|
* Execution Tools for calling Google Gemini API.
|
|
15481
16637
|
*
|
|
@@ -15497,24 +16653,7 @@
|
|
|
15497
16653
|
title: 'Google',
|
|
15498
16654
|
description: 'Implementation of Google models',
|
|
15499
16655
|
vercelProvider: googleGeminiVercelProvider,
|
|
15500
|
-
availableModels:
|
|
15501
|
-
// TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
|
|
15502
|
-
'gemini-1.5-flash',
|
|
15503
|
-
'gemini-1.5-flash-latest',
|
|
15504
|
-
'gemini-1.5-flash-001',
|
|
15505
|
-
'gemini-1.5-flash-002',
|
|
15506
|
-
'gemini-1.5-flash-exp-0827',
|
|
15507
|
-
'gemini-1.5-flash-8b',
|
|
15508
|
-
'gemini-1.5-flash-8b-latest',
|
|
15509
|
-
'gemini-1.5-flash-8b-exp-0924',
|
|
15510
|
-
'gemini-1.5-flash-8b-exp-0827',
|
|
15511
|
-
'gemini-1.5-pro-latest',
|
|
15512
|
-
'gemini-1.5-pro',
|
|
15513
|
-
'gemini-1.5-pro-001',
|
|
15514
|
-
'gemini-1.5-pro-002',
|
|
15515
|
-
'gemini-1.5-pro-exp-0827',
|
|
15516
|
-
'gemini-1.0-pro',
|
|
15517
|
-
].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
|
|
16656
|
+
availableModels: GOOGLE_MODELS,
|
|
15518
16657
|
...options,
|
|
15519
16658
|
});
|
|
15520
16659
|
}, {
|
|
@@ -15554,9 +16693,11 @@
|
|
|
15554
16693
|
packageName: '@promptbook/openai',
|
|
15555
16694
|
className: 'OpenAiExecutionTools',
|
|
15556
16695
|
envVariables: ['OPENAI_API_KEY'],
|
|
16696
|
+
trustLevel: 'CLOSED',
|
|
16697
|
+
order: MODEL_ORDER.TOP_TIER,
|
|
15557
16698
|
getBoilerplateConfiguration() {
|
|
15558
16699
|
return {
|
|
15559
|
-
title: 'Open AI
|
|
16700
|
+
title: 'Open AI',
|
|
15560
16701
|
packageName: '@promptbook/openai',
|
|
15561
16702
|
className: 'OpenAiExecutionTools',
|
|
15562
16703
|
options: {
|
|
@@ -15594,9 +16735,11 @@
|
|
|
15594
16735
|
className: 'OpenAiAssistantExecutionTools',
|
|
15595
16736
|
envVariables: null,
|
|
15596
16737
|
// <- TODO: ['OPENAI_API_KEY', 'OPENAI_ASSISTANT_ID']
|
|
16738
|
+
trustLevel: 'CLOSED',
|
|
16739
|
+
order: MODEL_ORDER.NORMAL,
|
|
15597
16740
|
getBoilerplateConfiguration() {
|
|
15598
16741
|
return {
|
|
15599
|
-
title: 'Open AI Assistant
|
|
16742
|
+
title: 'Open AI Assistant',
|
|
15600
16743
|
packageName: '@promptbook/openai',
|
|
15601
16744
|
className: 'OpenAiAssistantExecutionTools',
|
|
15602
16745
|
options: {
|
|
@@ -15672,6 +16815,9 @@
|
|
|
15672
16815
|
* TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
|
|
15673
16816
|
*/
|
|
15674
16817
|
|
|
16818
|
+
// Default rate limits (requests per minute) - adjust as needed based on OpenAI tier
|
|
16819
|
+
const DEFAULT_RPM = 60;
|
|
16820
|
+
// <- TODO: !!! Put in some better place
|
|
15675
16821
|
/**
|
|
15676
16822
|
* Execution Tools for calling OpenAI API
|
|
15677
16823
|
*
|
|
@@ -15689,6 +16835,10 @@
|
|
|
15689
16835
|
* OpenAI API client.
|
|
15690
16836
|
*/
|
|
15691
16837
|
this.client = null;
|
|
16838
|
+
// TODO: Allow configuring rate limits via options
|
|
16839
|
+
this.limiter = new Bottleneck__default["default"]({
|
|
16840
|
+
minTime: 60000 / (this.options.maxRequestsPerMinute || DEFAULT_RPM),
|
|
16841
|
+
});
|
|
15692
16842
|
}
|
|
15693
16843
|
get title() {
|
|
15694
16844
|
return 'OpenAI';
|
|
@@ -15792,7 +16942,10 @@
|
|
|
15792
16942
|
if (this.options.isVerbose) {
|
|
15793
16943
|
console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
15794
16944
|
}
|
|
15795
|
-
const rawResponse = await
|
|
16945
|
+
const rawResponse = await this.limiter
|
|
16946
|
+
.schedule(() => client.chat.completions.create(rawRequest))
|
|
16947
|
+
.catch((error) => {
|
|
16948
|
+
assertsError(error);
|
|
15796
16949
|
if (this.options.isVerbose) {
|
|
15797
16950
|
console.info(colors__default["default"].bgRed('error'), error);
|
|
15798
16951
|
}
|
|
@@ -15868,7 +17021,10 @@
|
|
|
15868
17021
|
if (this.options.isVerbose) {
|
|
15869
17022
|
console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
15870
17023
|
}
|
|
15871
|
-
const rawResponse = await
|
|
17024
|
+
const rawResponse = await this.limiter
|
|
17025
|
+
.schedule(() => client.completions.create(rawRequest))
|
|
17026
|
+
.catch((error) => {
|
|
17027
|
+
assertsError(error);
|
|
15872
17028
|
if (this.options.isVerbose) {
|
|
15873
17029
|
console.info(colors__default["default"].bgRed('error'), error);
|
|
15874
17030
|
}
|
|
@@ -15931,7 +17087,10 @@
|
|
|
15931
17087
|
if (this.options.isVerbose) {
|
|
15932
17088
|
console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
|
|
15933
17089
|
}
|
|
15934
|
-
const rawResponse = await
|
|
17090
|
+
const rawResponse = await this.limiter
|
|
17091
|
+
.schedule(() => client.embeddings.create(rawRequest))
|
|
17092
|
+
.catch((error) => {
|
|
17093
|
+
assertsError(error);
|
|
15935
17094
|
if (this.options.isVerbose) {
|
|
15936
17095
|
console.info(colors__default["default"].bgRed('error'), error);
|
|
15937
17096
|
}
|