@promptbook/cli 0.89.0-5 → 0.89.0-7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/index.es.js +1405 -1066
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/core.index.d.ts +8 -4
- package/esm/typings/src/_packages/remote-client.index.d.ts +0 -2
- package/esm/typings/src/cli/common/$addGlobalOptionsToCommand.d.ts +7 -0
- package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +15 -0
- package/esm/typings/src/config.d.ts +15 -8
- package/esm/typings/src/errors/0-index.d.ts +3 -0
- package/esm/typings/src/errors/AuthenticationError.d.ts +9 -0
- package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +34 -1
- package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +1 -1
- package/esm/typings/src/llm-providers/anthropic-claude/register-configuration.d.ts +1 -1
- package/esm/typings/src/remote-server/types/RemoteClientOptions.d.ts +2 -10
- package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +30 -2
- package/package.json +3 -1
- package/umd/index.umd.js +1607 -1268
- package/umd/index.umd.js.map +1 -1
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('path'), require('fs/promises'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('crypto'), require('rxjs'), require('dotenv'), require('child_process'), require('jszip'), require('prettier'), require('prettier/parser-html'), require('papaparse'), require('crypto-js'), require('mime-types'), require('glob-promise'), require('
|
|
3
|
-
typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'waitasecond', 'path', 'fs/promises', 'crypto-js/enc-hex', 'crypto-js/sha256', 'crypto', 'rxjs', 'dotenv', 'child_process', 'jszip', 'prettier', 'prettier/parser-html', 'papaparse', 'crypto-js', 'mime-types', 'glob-promise', '
|
|
4
|
-
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global.spaceTrim, global.waitasecond, global.path, global.promises, global.hexEncoder, global.sha256, global.crypto, global.rxjs, global.dotenv, global.child_process, global.JSZip, global.prettier, global.parserHtml, global.papaparse, global.cryptoJs, global.mimeTypes, global.glob, global.
|
|
5
|
-
})(this, (function (exports, colors, commander, spaceTrim, waitasecond, path, promises, hexEncoder, sha256, crypto, rxjs, dotenv, child_process, JSZip, prettier, parserHtml, papaparse, cryptoJs, mimeTypes, glob,
|
|
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('dotenv'), 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('swagger-jsdoc'), require('swagger-ui-express'), require('@anthropic-ai/sdk'), require('@azure/openai'), 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', 'crypto-js/enc-hex', 'crypto-js/sha256', 'crypto', 'socket.io-client', 'rxjs', 'dotenv', 'child_process', 'jszip', 'prettier', 'prettier/parser-html', 'papaparse', 'crypto-js', 'mime-types', 'glob-promise', 'moment', 'express', 'http', 'socket.io', 'swagger-jsdoc', 'swagger-ui-express', '@anthropic-ai/sdk', '@azure/openai', '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.hexEncoder, global.sha256, global.crypto, global.socket_ioClient, global.rxjs, global.dotenv, 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.swaggerJsdoc, global.swaggerUi, global.Anthropic, global.openai, global.OpenAI, global.readability, global.jsdom, global.showdown));
|
|
5
|
+
})(this, (function (exports, colors, commander, spaceTrim, waitasecond, prompts, path, promises, hexEncoder, sha256, crypto, socket_ioClient, rxjs, dotenv, child_process, JSZip, prettier, parserHtml, papaparse, cryptoJs, mimeTypes, glob, moment, express, http, socket_io, swaggerJsdoc, swaggerUi, Anthropic, openai, 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
|
|
|
@@ -27,16 +27,18 @@
|
|
|
27
27
|
var colors__default = /*#__PURE__*/_interopDefaultLegacy(colors);
|
|
28
28
|
var commander__default = /*#__PURE__*/_interopDefaultLegacy(commander);
|
|
29
29
|
var spaceTrim__default = /*#__PURE__*/_interopDefaultLegacy(spaceTrim);
|
|
30
|
+
var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts);
|
|
30
31
|
var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
|
|
31
32
|
var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
|
|
32
33
|
var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
|
|
33
34
|
var JSZip__default = /*#__PURE__*/_interopDefaultLegacy(JSZip);
|
|
34
35
|
var parserHtml__default = /*#__PURE__*/_interopDefaultLegacy(parserHtml);
|
|
35
36
|
var glob__default = /*#__PURE__*/_interopDefaultLegacy(glob);
|
|
36
|
-
var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts);
|
|
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 swaggerJsdoc__default = /*#__PURE__*/_interopDefaultLegacy(swaggerJsdoc);
|
|
41
|
+
var swaggerUi__default = /*#__PURE__*/_interopDefaultLegacy(swaggerUi);
|
|
40
42
|
var Anthropic__default = /*#__PURE__*/_interopDefaultLegacy(Anthropic);
|
|
41
43
|
var OpenAI__default = /*#__PURE__*/_interopDefaultLegacy(OpenAI);
|
|
42
44
|
|
|
@@ -54,7 +56,7 @@
|
|
|
54
56
|
* @generated
|
|
55
57
|
* @see https://github.com/webgptorg/promptbook
|
|
56
58
|
*/
|
|
57
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.89.0-
|
|
59
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.89.0-7';
|
|
58
60
|
/**
|
|
59
61
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
60
62
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
@@ -223,6 +225,7 @@
|
|
|
223
225
|
*/
|
|
224
226
|
const DEFAULT_BOOKS_DIRNAME = './books';
|
|
225
227
|
// <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
|
|
228
|
+
// TODO: !!!!!! Just .promptbook dir, hardocode others
|
|
226
229
|
/**
|
|
227
230
|
* Where to store the temporary downloads
|
|
228
231
|
*
|
|
@@ -247,6 +250,21 @@
|
|
|
247
250
|
* @public exported from `@promptbook/core`
|
|
248
251
|
*/
|
|
249
252
|
const DEFAULT_SCRAPE_CACHE_DIRNAME = './.promptbook/scrape-cache';
|
|
253
|
+
/**
|
|
254
|
+
* Id of application for the CLI when using remote server
|
|
255
|
+
*
|
|
256
|
+
* @public exported from `@promptbook/core`
|
|
257
|
+
*/
|
|
258
|
+
const CLI_APP_ID = 'cli';
|
|
259
|
+
/*
|
|
260
|
+
TODO: [🌃]
|
|
261
|
+
/**
|
|
262
|
+
* Id of application for the wizzard when using remote server
|
|
263
|
+
*
|
|
264
|
+
* @public exported from `@promptbook/core`
|
|
265
|
+
* /
|
|
266
|
+
ex-port const WIZZARD_APP_ID: string_app_id = 'wizzard';
|
|
267
|
+
*/
|
|
250
268
|
/**
|
|
251
269
|
* The name of the builded pipeline collection made by CLI `ptbk make` and for lookup in `createCollectionFromDirectory`
|
|
252
270
|
*
|
|
@@ -267,13 +285,7 @@
|
|
|
267
285
|
*
|
|
268
286
|
* @public exported from `@promptbook/core`
|
|
269
287
|
*/
|
|
270
|
-
const
|
|
271
|
-
/**
|
|
272
|
-
* @@@
|
|
273
|
-
*
|
|
274
|
-
* @public exported from `@promptbook/core`
|
|
275
|
-
*/
|
|
276
|
-
const DEFAULT_REMOTE_URL_PATH = '/promptbook/socket.io';
|
|
288
|
+
const DEFAULT_REMOTE_SERVER_URL = 'https://api.pavolhejny.com/promptbook';
|
|
277
289
|
// <- TODO: [🧜♂️]
|
|
278
290
|
/**
|
|
279
291
|
* @@@
|
|
@@ -315,7 +327,7 @@
|
|
|
315
327
|
true);
|
|
316
328
|
/**
|
|
317
329
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
318
|
-
* TODO: [🧠][🧜♂️] Maybe join
|
|
330
|
+
* TODO: [🧠][🧜♂️] Maybe join remoteServerUrl and path into single value
|
|
319
331
|
*/
|
|
320
332
|
|
|
321
333
|
/**
|
|
@@ -493,7 +505,8 @@
|
|
|
493
505
|
helloCommand.alias('hi');
|
|
494
506
|
helloCommand.argument('[name]', 'Your name', 'Paul');
|
|
495
507
|
helloCommand.option('-g, --greeting <greeting>', `Greeting`, 'Hello');
|
|
496
|
-
helloCommand.action(handleActionErrors(async (name,
|
|
508
|
+
helloCommand.action(handleActionErrors(async (name, cliOptions) => {
|
|
509
|
+
const { greeting } = cliOptions;
|
|
497
510
|
console.info(colors__default["default"].cyan(`${greeting} ${name}`));
|
|
498
511
|
await waitasecond.forTime(1000);
|
|
499
512
|
console.info(colors__default["default"].rainbow(`Nice to meet you!`));
|
|
@@ -507,40 +520,27 @@
|
|
|
507
520
|
*/
|
|
508
521
|
|
|
509
522
|
/**
|
|
510
|
-
*
|
|
511
|
-
* No side effects.
|
|
512
|
-
*
|
|
513
|
-
* Note: It can be usefull suppressing eslint errors of unused variables
|
|
523
|
+
* This error type indicates that some part of the code is not implemented yet
|
|
514
524
|
*
|
|
515
|
-
* @
|
|
516
|
-
* @returns void
|
|
517
|
-
* @private within the repository
|
|
525
|
+
* @public exported from `@promptbook/core`
|
|
518
526
|
*/
|
|
519
|
-
|
|
520
|
-
|
|
527
|
+
class NotYetImplementedError extends Error {
|
|
528
|
+
constructor(message) {
|
|
529
|
+
super(spaceTrim.spaceTrim((block) => `
|
|
530
|
+
${block(message)}
|
|
521
531
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
532
|
+
Note: This feature is not implemented yet but it will be soon.
|
|
533
|
+
|
|
534
|
+
If you want speed up the implementation or just read more, look here:
|
|
535
|
+
https://github.com/webgptorg/promptbook
|
|
536
|
+
|
|
537
|
+
Or contact us on pavol@ptbk.io
|
|
538
|
+
|
|
539
|
+
`));
|
|
540
|
+
this.name = 'NotYetImplementedError';
|
|
541
|
+
Object.setPrototypeOf(this, NotYetImplementedError.prototype);
|
|
530
542
|
}
|
|
531
|
-
return {
|
|
532
|
-
stat: promises.stat,
|
|
533
|
-
access: promises.access,
|
|
534
|
-
constants: promises.constants,
|
|
535
|
-
readFile: promises.readFile,
|
|
536
|
-
writeFile: promises.writeFile,
|
|
537
|
-
readdir: promises.readdir,
|
|
538
|
-
mkdir: promises.mkdir,
|
|
539
|
-
};
|
|
540
543
|
}
|
|
541
|
-
/**
|
|
542
|
-
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
543
|
-
*/
|
|
544
544
|
|
|
545
545
|
/**
|
|
546
546
|
* Make error report URL for the given error
|
|
@@ -611,123 +611,569 @@
|
|
|
611
611
|
}
|
|
612
612
|
|
|
613
613
|
/**
|
|
614
|
-
*
|
|
614
|
+
* @@@
|
|
615
615
|
*
|
|
616
|
-
*
|
|
617
|
-
*
|
|
616
|
+
* Note: `$` is used to indicate that this function is not a pure function - it access global scope
|
|
617
|
+
*
|
|
618
|
+
* @private internal function of `$Register`
|
|
618
619
|
*/
|
|
619
|
-
function
|
|
620
|
-
|
|
621
|
-
const orderedValue = {
|
|
622
|
-
...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
|
|
623
|
-
...value,
|
|
624
|
-
};
|
|
625
|
-
return orderedValue;
|
|
620
|
+
function $getGlobalScope() {
|
|
621
|
+
return Function('return this')();
|
|
626
622
|
}
|
|
627
623
|
|
|
628
624
|
/**
|
|
629
|
-
*
|
|
630
|
-
*
|
|
631
|
-
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
632
|
-
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
625
|
+
* @@@
|
|
633
626
|
*
|
|
634
|
-
* @
|
|
627
|
+
* @param text @@@
|
|
628
|
+
* @returns @@@
|
|
629
|
+
* @example 'HELLO_WORLD'
|
|
630
|
+
* @example 'I_LOVE_PROMPTBOOK'
|
|
635
631
|
* @public exported from `@promptbook/utils`
|
|
636
632
|
*/
|
|
637
|
-
function
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
const
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
633
|
+
function normalizeTo_SCREAMING_CASE(text) {
|
|
634
|
+
let charType;
|
|
635
|
+
let lastCharType = 'OTHER';
|
|
636
|
+
let normalizedName = '';
|
|
637
|
+
for (const char of text) {
|
|
638
|
+
let normalizedChar;
|
|
639
|
+
if (/^[a-z]$/.test(char)) {
|
|
640
|
+
charType = 'LOWERCASE';
|
|
641
|
+
normalizedChar = char.toUpperCase();
|
|
642
|
+
}
|
|
643
|
+
else if (/^[A-Z]$/.test(char)) {
|
|
644
|
+
charType = 'UPPERCASE';
|
|
645
|
+
normalizedChar = char;
|
|
646
|
+
}
|
|
647
|
+
else if (/^[0-9]$/.test(char)) {
|
|
648
|
+
charType = 'NUMBER';
|
|
649
|
+
normalizedChar = char;
|
|
650
|
+
}
|
|
651
|
+
else {
|
|
652
|
+
charType = 'OTHER';
|
|
653
|
+
normalizedChar = '_';
|
|
654
|
+
}
|
|
655
|
+
if (charType !== lastCharType &&
|
|
656
|
+
!(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
|
|
657
|
+
!(lastCharType === 'NUMBER') &&
|
|
658
|
+
!(charType === 'NUMBER')) {
|
|
659
|
+
normalizedName += '_';
|
|
646
660
|
}
|
|
661
|
+
normalizedName += normalizedChar;
|
|
662
|
+
lastCharType = charType;
|
|
647
663
|
}
|
|
648
|
-
|
|
649
|
-
|
|
664
|
+
normalizedName = normalizedName.replace(/_+/g, '_');
|
|
665
|
+
normalizedName = normalizedName.replace(/_?\/_?/g, '/');
|
|
666
|
+
normalizedName = normalizedName.replace(/^_/, '');
|
|
667
|
+
normalizedName = normalizedName.replace(/_$/, '');
|
|
668
|
+
return normalizedName;
|
|
650
669
|
}
|
|
651
670
|
/**
|
|
652
|
-
* TODO:
|
|
671
|
+
* TODO: Tests
|
|
672
|
+
* > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: 'Moje tabule' })).toEqual('/VtG7sR9rRJqwNEdM2/Moje tabule');
|
|
673
|
+
* > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: 'ěščřžžýáíúů' })).toEqual('/VtG7sR9rRJqwNEdM2/escrzyaieuu');
|
|
674
|
+
* > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: ' ahoj ' })).toEqual('/VtG7sR9rRJqwNEdM2/ahoj');
|
|
675
|
+
* > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: ' ahoj_ahojAhoj ahoj ' })).toEqual('/VtG7sR9rRJqwNEdM2/ahoj-ahoj-ahoj-ahoj');
|
|
676
|
+
* TODO: [🌺] Use some intermediate util splitWords
|
|
653
677
|
*/
|
|
654
678
|
|
|
655
679
|
/**
|
|
656
|
-
*
|
|
657
|
-
* If not, throws an UnexpectedError with a rich error message and tracking
|
|
658
|
-
*
|
|
659
|
-
* - Almost all primitives are serializable BUT:
|
|
660
|
-
* - `undefined` is not serializable
|
|
661
|
-
* - `NaN` is not serializable
|
|
662
|
-
* - Objects and arrays are serializable if all their properties are serializable
|
|
663
|
-
* - Functions are not serializable
|
|
664
|
-
* - Circular references are not serializable
|
|
665
|
-
* - `Date` objects are not serializable
|
|
666
|
-
* - `Map` and `Set` objects are not serializable
|
|
667
|
-
* - `RegExp` objects are not serializable
|
|
668
|
-
* - `Error` objects are not serializable
|
|
669
|
-
* - `Symbol` objects are not serializable
|
|
670
|
-
* - And much more...
|
|
680
|
+
* @@@
|
|
671
681
|
*
|
|
672
|
-
* @
|
|
682
|
+
* @param text @@@
|
|
683
|
+
* @returns @@@
|
|
684
|
+
* @example 'hello_world'
|
|
685
|
+
* @example 'i_love_promptbook'
|
|
673
686
|
* @public exported from `@promptbook/utils`
|
|
674
687
|
*/
|
|
675
|
-
function
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
throw new UnexpectedError(`${name} is undefined`);
|
|
679
|
-
}
|
|
680
|
-
else if (value === null) {
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
else if (typeof value === 'boolean') {
|
|
684
|
-
return;
|
|
685
|
-
}
|
|
686
|
-
else if (typeof value === 'number' && !isNaN(value)) {
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
else if (typeof value === 'string') {
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
else if (typeof value === 'symbol') {
|
|
693
|
-
throw new UnexpectedError(`${name} is symbol`);
|
|
694
|
-
}
|
|
695
|
-
else if (typeof value === 'function') {
|
|
696
|
-
throw new UnexpectedError(`${name} is function`);
|
|
697
|
-
}
|
|
698
|
-
else if (typeof value === 'object' && Array.isArray(value)) {
|
|
699
|
-
for (let i = 0; i < value.length; i++) {
|
|
700
|
-
checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
|
|
701
|
-
}
|
|
702
|
-
}
|
|
703
|
-
else if (typeof value === 'object') {
|
|
704
|
-
if (value instanceof Date) {
|
|
705
|
-
throw new UnexpectedError(spaceTrim__default["default"]((block) => `
|
|
706
|
-
\`${name}\` is Date
|
|
707
|
-
|
|
708
|
-
Use \`string_date_iso8601\` instead
|
|
688
|
+
function normalizeTo_snake_case(text) {
|
|
689
|
+
return normalizeTo_SCREAMING_CASE(text).toLowerCase();
|
|
690
|
+
}
|
|
709
691
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
692
|
+
/**
|
|
693
|
+
* Register is @@@
|
|
694
|
+
*
|
|
695
|
+
* Note: `$` is used to indicate that this function is not a pure function - it accesses and adds variables in global scope.
|
|
696
|
+
*
|
|
697
|
+
* @private internal utility, exported are only signleton instances of this class
|
|
698
|
+
*/
|
|
699
|
+
class $Register {
|
|
700
|
+
constructor(registerName) {
|
|
701
|
+
this.registerName = registerName;
|
|
702
|
+
const storageName = `_promptbook_${normalizeTo_snake_case(registerName)}`;
|
|
703
|
+
const globalScope = $getGlobalScope();
|
|
704
|
+
if (globalScope[storageName] === undefined) {
|
|
705
|
+
globalScope[storageName] = [];
|
|
713
706
|
}
|
|
714
|
-
else if (
|
|
715
|
-
throw new UnexpectedError(
|
|
707
|
+
else if (!Array.isArray(globalScope[storageName])) {
|
|
708
|
+
throw new UnexpectedError(`Expected (global) ${storageName} to be an array, but got ${typeof globalScope[storageName]}`);
|
|
716
709
|
}
|
|
717
|
-
|
|
718
|
-
|
|
710
|
+
this.storage = globalScope[storageName];
|
|
711
|
+
}
|
|
712
|
+
list() {
|
|
713
|
+
// <- TODO: ReadonlyDeep<ReadonlyArray<TRegistered>>
|
|
714
|
+
return this.storage;
|
|
715
|
+
}
|
|
716
|
+
register(registered) {
|
|
717
|
+
const { packageName, className } = registered;
|
|
718
|
+
const existingRegistrationIndex = this.storage.findIndex((item) => item.packageName === packageName && item.className === className);
|
|
719
|
+
const existingRegistration = this.storage[existingRegistrationIndex];
|
|
720
|
+
if (!existingRegistration) {
|
|
721
|
+
this.storage.push(registered);
|
|
719
722
|
}
|
|
720
|
-
else
|
|
721
|
-
|
|
723
|
+
else {
|
|
724
|
+
this.storage[existingRegistrationIndex] = registered;
|
|
722
725
|
}
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
726
|
+
return {
|
|
727
|
+
registerName: this.registerName,
|
|
728
|
+
packageName,
|
|
729
|
+
className,
|
|
730
|
+
get isDestroyed() {
|
|
731
|
+
return false;
|
|
732
|
+
},
|
|
733
|
+
destroy() {
|
|
734
|
+
throw new NotYetImplementedError(`Registration to ${this.registerName} is permanent in this version of Promptbook`);
|
|
735
|
+
},
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
}
|
|
728
739
|
|
|
729
|
-
|
|
730
|
-
|
|
740
|
+
/**
|
|
741
|
+
* @@@
|
|
742
|
+
*
|
|
743
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
744
|
+
* @singleton Only one instance of each register is created per build, but thare can be more @@@
|
|
745
|
+
* @public exported from `@promptbook/core`
|
|
746
|
+
*/
|
|
747
|
+
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
748
|
+
/**
|
|
749
|
+
* TODO: [®] DRY Register logic
|
|
750
|
+
*/
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* @@@
|
|
754
|
+
*
|
|
755
|
+
* Note: `$` is used to indicate that this interacts with the global scope
|
|
756
|
+
* @singleton Only one instance of each register is created per build, but thare can be more @@@
|
|
757
|
+
* @public exported from `@promptbook/core`
|
|
758
|
+
*/
|
|
759
|
+
const $llmToolsRegister = new $Register('llm_execution_tools_constructors');
|
|
760
|
+
/**
|
|
761
|
+
* TODO: [®] DRY Register logic
|
|
762
|
+
*/
|
|
763
|
+
|
|
764
|
+
/**
|
|
765
|
+
* Path to the `.env` file which was used to configure LLM tools
|
|
766
|
+
*
|
|
767
|
+
* Note: `$` is used to indicate that this variable is changed by side effect in `$provideLlmToolsConfigurationFromEnv` through `$setUsedEnvFilename`
|
|
768
|
+
*/
|
|
769
|
+
let $usedEnvFilename = null;
|
|
770
|
+
/**
|
|
771
|
+
* Pass the `.env` file which was used to configure LLM tools
|
|
772
|
+
*
|
|
773
|
+
* Note: `$` is used to indicate that this variable is making side effect
|
|
774
|
+
*
|
|
775
|
+
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
776
|
+
*/
|
|
777
|
+
function $setUsedEnvFilename(filepath) {
|
|
778
|
+
$usedEnvFilename = filepath;
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Creates a message with all registered LLM tools
|
|
782
|
+
*
|
|
783
|
+
* Note: This function is used to create a (error) message when there is no constructor for some LLM provider
|
|
784
|
+
*
|
|
785
|
+
* @private internal function of `createLlmToolsFromConfiguration` and `$provideLlmToolsFromEnv`
|
|
786
|
+
*/
|
|
787
|
+
function $registeredLlmToolsMessage() {
|
|
788
|
+
let env;
|
|
789
|
+
if ($isRunningInNode()) {
|
|
790
|
+
env = process.env;
|
|
791
|
+
// <- TODO: [⚛] Some DRY way how to get to `process.env` and pass it into functions - ACRY search for `env`
|
|
792
|
+
}
|
|
793
|
+
else {
|
|
794
|
+
env = {};
|
|
795
|
+
}
|
|
796
|
+
/**
|
|
797
|
+
* Mixes registered LLM tools from $llmToolsMetadataRegister and $llmToolsRegister
|
|
798
|
+
*/
|
|
799
|
+
const all = [];
|
|
800
|
+
for (const { title, packageName, className, envVariables } of $llmToolsMetadataRegister.list()) {
|
|
801
|
+
if (all.some((item) => item.packageName === packageName && item.className === className)) {
|
|
802
|
+
continue;
|
|
803
|
+
}
|
|
804
|
+
all.push({ title, packageName, className, envVariables });
|
|
805
|
+
}
|
|
806
|
+
for (const { packageName, className } of $llmToolsRegister.list()) {
|
|
807
|
+
if (all.some((item) => item.packageName === packageName && item.className === className)) {
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
all.push({ packageName, className });
|
|
811
|
+
}
|
|
812
|
+
const metadata = all.map((metadata) => {
|
|
813
|
+
var _a, _b;
|
|
814
|
+
const isMetadataAviailable = $llmToolsMetadataRegister
|
|
815
|
+
.list()
|
|
816
|
+
.find(({ packageName, className }) => metadata.packageName === packageName && metadata.className === className);
|
|
817
|
+
const isInstalled = $llmToolsRegister
|
|
818
|
+
.list()
|
|
819
|
+
.find(({ packageName, className }) => metadata.packageName === packageName && metadata.className === className);
|
|
820
|
+
const isFullyConfigured = ((_a = metadata.envVariables) === null || _a === void 0 ? void 0 : _a.every((envVariableName) => env[envVariableName] !== undefined)) || false;
|
|
821
|
+
const isPartiallyConfigured = ((_b = metadata.envVariables) === null || _b === void 0 ? void 0 : _b.some((envVariableName) => env[envVariableName] !== undefined)) || false;
|
|
822
|
+
// <- Note: [🗨]
|
|
823
|
+
return { ...metadata, isMetadataAviailable, isInstalled, isFullyConfigured, isPartiallyConfigured };
|
|
824
|
+
});
|
|
825
|
+
const usedEnvMessage = $usedEnvFilename === null ? `Unknown \`.env\` file` : `Used \`.env\` file:\n${$usedEnvFilename}`;
|
|
826
|
+
if (metadata.length === 0) {
|
|
827
|
+
return spaceTrim__default["default"]((block) => `
|
|
828
|
+
No LLM providers are available.
|
|
829
|
+
|
|
830
|
+
${block(usedEnvMessage)}
|
|
831
|
+
`);
|
|
832
|
+
}
|
|
833
|
+
return spaceTrim__default["default"]((block) => `
|
|
834
|
+
|
|
835
|
+
${block(usedEnvMessage)}
|
|
836
|
+
|
|
837
|
+
Relevant environment variables:
|
|
838
|
+
${block(Object.keys(env)
|
|
839
|
+
.filter((envVariableName) => metadata.some(({ envVariables }) => envVariables === null || envVariables === void 0 ? void 0 : envVariables.includes(envVariableName)))
|
|
840
|
+
.map((envVariableName) => `- \`${envVariableName}\``)
|
|
841
|
+
.join('\n'))}
|
|
842
|
+
|
|
843
|
+
Available LLM providers are:
|
|
844
|
+
${block(metadata
|
|
845
|
+
.map(({ title, packageName, className, envVariables, isMetadataAviailable, isInstalled, isFullyConfigured, isPartiallyConfigured, }, i) => {
|
|
846
|
+
const morePieces = [];
|
|
847
|
+
if (just(false)) ;
|
|
848
|
+
else if (!isMetadataAviailable && !isInstalled) {
|
|
849
|
+
// TODO: [�][�] Maybe do allow to do auto-install if package not registered and not found
|
|
850
|
+
morePieces.push(`Not installed and no metadata, looks like a unexpected behavior`);
|
|
851
|
+
}
|
|
852
|
+
else if (isMetadataAviailable && !isInstalled) {
|
|
853
|
+
// TODO: [�][�]
|
|
854
|
+
morePieces.push(`Not installed`);
|
|
855
|
+
}
|
|
856
|
+
else if (!isMetadataAviailable && isInstalled) {
|
|
857
|
+
morePieces.push(`No metadata but installed, looks like a unexpected behavior`);
|
|
858
|
+
}
|
|
859
|
+
else if (isMetadataAviailable && isInstalled) {
|
|
860
|
+
morePieces.push(`Installed`);
|
|
861
|
+
}
|
|
862
|
+
else {
|
|
863
|
+
morePieces.push(`unknown state, looks like a unexpected behavior`);
|
|
864
|
+
} /* not else */
|
|
865
|
+
if (isFullyConfigured) {
|
|
866
|
+
morePieces.push(`Configured`);
|
|
867
|
+
}
|
|
868
|
+
else if (isPartiallyConfigured) {
|
|
869
|
+
morePieces.push(`Partially confugured, missing ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.filter((envVariable) => env[envVariable] === undefined).join(' + ')}`);
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
if (envVariables !== null) {
|
|
873
|
+
morePieces.push(`Not configured, to configure set env ${envVariables === null || envVariables === void 0 ? void 0 : envVariables.join(' + ')}`);
|
|
874
|
+
}
|
|
875
|
+
else {
|
|
876
|
+
morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
let providerMessage = spaceTrim__default["default"](`
|
|
880
|
+
${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
881
|
+
${morePieces.join('; ')}
|
|
882
|
+
`);
|
|
883
|
+
if ($isRunningInNode) {
|
|
884
|
+
if (isInstalled && isFullyConfigured) {
|
|
885
|
+
providerMessage = colors__default["default"].green(providerMessage);
|
|
886
|
+
}
|
|
887
|
+
else if (isInstalled && isPartiallyConfigured) {
|
|
888
|
+
providerMessage = colors__default["default"].yellow(providerMessage);
|
|
889
|
+
}
|
|
890
|
+
else {
|
|
891
|
+
providerMessage = colors__default["default"].gray(providerMessage);
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return providerMessage;
|
|
895
|
+
})
|
|
896
|
+
.join('\n'))}
|
|
897
|
+
`);
|
|
898
|
+
}
|
|
899
|
+
/**
|
|
900
|
+
* TODO: [®] DRY Register logic
|
|
901
|
+
* TODO: [🧠][⚛] Maybe pass env as argument
|
|
902
|
+
*/
|
|
903
|
+
|
|
904
|
+
/**
|
|
905
|
+
* Just says that the variable is not used but should be kept
|
|
906
|
+
* No side effects.
|
|
907
|
+
*
|
|
908
|
+
* Note: It can be usefull for:
|
|
909
|
+
*
|
|
910
|
+
* 1) Suppressing eager optimization of unused imports
|
|
911
|
+
* 2) Suppressing eslint errors of unused variables in the tests
|
|
912
|
+
* 3) Keeping the type of the variable for type testing
|
|
913
|
+
*
|
|
914
|
+
* @param value any values
|
|
915
|
+
* @returns void
|
|
916
|
+
* @private within the repository
|
|
917
|
+
*/
|
|
918
|
+
function keepUnused(...valuesToKeep) {
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
/**
|
|
922
|
+
* Just says that the variable is not used directlys but should be kept because the existence of the variable is important
|
|
923
|
+
*
|
|
924
|
+
* @param value any values
|
|
925
|
+
* @returns void
|
|
926
|
+
* @private within the repository
|
|
927
|
+
*/
|
|
928
|
+
function $sideEffect(...sideEffectSubjects) {
|
|
929
|
+
keepUnused(...sideEffectSubjects);
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
/**
|
|
933
|
+
* Checks if value is valid email
|
|
934
|
+
*
|
|
935
|
+
* @public exported from `@promptbook/utils`
|
|
936
|
+
*/
|
|
937
|
+
function isValidEmail(email) {
|
|
938
|
+
if (typeof email !== 'string') {
|
|
939
|
+
return false;
|
|
940
|
+
}
|
|
941
|
+
if (email.split('\n').length > 1) {
|
|
942
|
+
return false;
|
|
943
|
+
}
|
|
944
|
+
return /^.+@.+\..+$/.test(email);
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
/**
|
|
948
|
+
* Tests if given string is valid URL.
|
|
949
|
+
*
|
|
950
|
+
* Note: Dataurl are considered perfectly valid.
|
|
951
|
+
* Note: There are two simmilar functions:
|
|
952
|
+
* - `isValidUrl` which tests any URL
|
|
953
|
+
* - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
|
|
954
|
+
*
|
|
955
|
+
* @public exported from `@promptbook/utils`
|
|
956
|
+
*/
|
|
957
|
+
function isValidUrl(url) {
|
|
958
|
+
if (typeof url !== 'string') {
|
|
959
|
+
return false;
|
|
960
|
+
}
|
|
961
|
+
try {
|
|
962
|
+
if (url.startsWith('blob:')) {
|
|
963
|
+
url = url.replace(/^blob:/, '');
|
|
964
|
+
}
|
|
965
|
+
const urlObject = new URL(url /* because fail is handled */);
|
|
966
|
+
if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
|
|
967
|
+
return false;
|
|
968
|
+
}
|
|
969
|
+
return true;
|
|
970
|
+
}
|
|
971
|
+
catch (error) {
|
|
972
|
+
return false;
|
|
973
|
+
}
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/**
|
|
977
|
+
* Stores data in memory (HEAP)
|
|
978
|
+
*
|
|
979
|
+
* @public exported from `@promptbook/core`
|
|
980
|
+
*/
|
|
981
|
+
class MemoryStorage {
|
|
982
|
+
constructor() {
|
|
983
|
+
this.storage = {};
|
|
984
|
+
}
|
|
985
|
+
/**
|
|
986
|
+
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
987
|
+
*/
|
|
988
|
+
get length() {
|
|
989
|
+
return Object.keys(this.storage).length;
|
|
990
|
+
}
|
|
991
|
+
/**
|
|
992
|
+
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
993
|
+
*/
|
|
994
|
+
clear() {
|
|
995
|
+
this.storage = {};
|
|
996
|
+
}
|
|
997
|
+
/**
|
|
998
|
+
* 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.
|
|
999
|
+
*/
|
|
1000
|
+
getItem(key) {
|
|
1001
|
+
return this.storage[key] || null;
|
|
1002
|
+
}
|
|
1003
|
+
/**
|
|
1004
|
+
* 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.
|
|
1005
|
+
*/
|
|
1006
|
+
key(index) {
|
|
1007
|
+
return Object.keys(this.storage)[index] || null;
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
1011
|
+
*/
|
|
1012
|
+
setItem(key, value) {
|
|
1013
|
+
this.storage[key] = value;
|
|
1014
|
+
}
|
|
1015
|
+
/**
|
|
1016
|
+
* 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.
|
|
1017
|
+
*/
|
|
1018
|
+
removeItem(key) {
|
|
1019
|
+
delete this.storage[key];
|
|
1020
|
+
}
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
/**
|
|
1024
|
+
* Just marks a place of place where should be something implemented
|
|
1025
|
+
* No side effects.
|
|
1026
|
+
*
|
|
1027
|
+
* Note: It can be usefull suppressing eslint errors of unused variables
|
|
1028
|
+
*
|
|
1029
|
+
* @param value any values
|
|
1030
|
+
* @returns void
|
|
1031
|
+
* @private within the repository
|
|
1032
|
+
*/
|
|
1033
|
+
function TODO_USE(...value) {
|
|
1034
|
+
}
|
|
1035
|
+
|
|
1036
|
+
/**
|
|
1037
|
+
* @@@
|
|
1038
|
+
*
|
|
1039
|
+
* @public exported from `@promptbook/node`
|
|
1040
|
+
*/
|
|
1041
|
+
function $provideFilesystemForNode(options) {
|
|
1042
|
+
if (!$isRunningInNode()) {
|
|
1043
|
+
throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
|
|
1044
|
+
}
|
|
1045
|
+
return {
|
|
1046
|
+
stat: promises.stat,
|
|
1047
|
+
access: promises.access,
|
|
1048
|
+
constants: promises.constants,
|
|
1049
|
+
readFile: promises.readFile,
|
|
1050
|
+
writeFile: promises.writeFile,
|
|
1051
|
+
readdir: promises.readdir,
|
|
1052
|
+
mkdir: promises.mkdir,
|
|
1053
|
+
};
|
|
1054
|
+
}
|
|
1055
|
+
/**
|
|
1056
|
+
* Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
|
|
1057
|
+
*/
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Orders JSON object by keys
|
|
1061
|
+
*
|
|
1062
|
+
* @returns The same type of object as the input re-ordered
|
|
1063
|
+
* @public exported from `@promptbook/utils`
|
|
1064
|
+
*/
|
|
1065
|
+
function orderJson(options) {
|
|
1066
|
+
const { value, order } = options;
|
|
1067
|
+
const orderedValue = {
|
|
1068
|
+
...(order === undefined ? {} : Object.fromEntries(order.map((key) => [key, undefined]))),
|
|
1069
|
+
...value,
|
|
1070
|
+
};
|
|
1071
|
+
return orderedValue;
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
/**
|
|
1075
|
+
* Freezes the given object and all its nested objects recursively
|
|
1076
|
+
*
|
|
1077
|
+
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
1078
|
+
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
1079
|
+
*
|
|
1080
|
+
* @returns The same object as the input, but deeply frozen
|
|
1081
|
+
* @public exported from `@promptbook/utils`
|
|
1082
|
+
*/
|
|
1083
|
+
function $deepFreeze(objectValue) {
|
|
1084
|
+
if (Array.isArray(objectValue)) {
|
|
1085
|
+
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
1086
|
+
}
|
|
1087
|
+
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
1088
|
+
for (const propertyName of propertyNames) {
|
|
1089
|
+
const value = objectValue[propertyName];
|
|
1090
|
+
if (value && typeof value === 'object') {
|
|
1091
|
+
$deepFreeze(value);
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
Object.freeze(objectValue);
|
|
1095
|
+
return objectValue;
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
1099
|
+
*/
|
|
1100
|
+
|
|
1101
|
+
/**
|
|
1102
|
+
* Checks if the value is [🚉] serializable as JSON
|
|
1103
|
+
* If not, throws an UnexpectedError with a rich error message and tracking
|
|
1104
|
+
*
|
|
1105
|
+
* - Almost all primitives are serializable BUT:
|
|
1106
|
+
* - `undefined` is not serializable
|
|
1107
|
+
* - `NaN` is not serializable
|
|
1108
|
+
* - Objects and arrays are serializable if all their properties are serializable
|
|
1109
|
+
* - Functions are not serializable
|
|
1110
|
+
* - Circular references are not serializable
|
|
1111
|
+
* - `Date` objects are not serializable
|
|
1112
|
+
* - `Map` and `Set` objects are not serializable
|
|
1113
|
+
* - `RegExp` objects are not serializable
|
|
1114
|
+
* - `Error` objects are not serializable
|
|
1115
|
+
* - `Symbol` objects are not serializable
|
|
1116
|
+
* - And much more...
|
|
1117
|
+
*
|
|
1118
|
+
* @throws UnexpectedError if the value is not serializable as JSON
|
|
1119
|
+
* @public exported from `@promptbook/utils`
|
|
1120
|
+
*/
|
|
1121
|
+
function checkSerializableAsJson(options) {
|
|
1122
|
+
const { value, name, message } = options;
|
|
1123
|
+
if (value === undefined) {
|
|
1124
|
+
throw new UnexpectedError(`${name} is undefined`);
|
|
1125
|
+
}
|
|
1126
|
+
else if (value === null) {
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
else if (typeof value === 'boolean') {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
else if (typeof value === 'number' && !isNaN(value)) {
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
else if (typeof value === 'string') {
|
|
1136
|
+
return;
|
|
1137
|
+
}
|
|
1138
|
+
else if (typeof value === 'symbol') {
|
|
1139
|
+
throw new UnexpectedError(`${name} is symbol`);
|
|
1140
|
+
}
|
|
1141
|
+
else if (typeof value === 'function') {
|
|
1142
|
+
throw new UnexpectedError(`${name} is function`);
|
|
1143
|
+
}
|
|
1144
|
+
else if (typeof value === 'object' && Array.isArray(value)) {
|
|
1145
|
+
for (let i = 0; i < value.length; i++) {
|
|
1146
|
+
checkSerializableAsJson({ name: `${name}[${i}]`, value: value[i], message });
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
else if (typeof value === 'object') {
|
|
1150
|
+
if (value instanceof Date) {
|
|
1151
|
+
throw new UnexpectedError(spaceTrim__default["default"]((block) => `
|
|
1152
|
+
\`${name}\` is Date
|
|
1153
|
+
|
|
1154
|
+
Use \`string_date_iso8601\` instead
|
|
1155
|
+
|
|
1156
|
+
Additional message for \`${name}\`:
|
|
1157
|
+
${block(message || '(nothing)')}
|
|
1158
|
+
`));
|
|
1159
|
+
}
|
|
1160
|
+
else if (value instanceof Map) {
|
|
1161
|
+
throw new UnexpectedError(`${name} is Map`);
|
|
1162
|
+
}
|
|
1163
|
+
else if (value instanceof Set) {
|
|
1164
|
+
throw new UnexpectedError(`${name} is Set`);
|
|
1165
|
+
}
|
|
1166
|
+
else if (value instanceof RegExp) {
|
|
1167
|
+
throw new UnexpectedError(`${name} is RegExp`);
|
|
1168
|
+
}
|
|
1169
|
+
else if (value instanceof Error) {
|
|
1170
|
+
throw new UnexpectedError(spaceTrim__default["default"]((block) => `
|
|
1171
|
+
\`${name}\` is unserialized Error
|
|
1172
|
+
|
|
1173
|
+
Use function \`serializeError\`
|
|
1174
|
+
|
|
1175
|
+
Additional message for \`${name}\`:
|
|
1176
|
+
${block(message || '(nothing)')}
|
|
731
1177
|
|
|
732
1178
|
`));
|
|
733
1179
|
}
|
|
@@ -1051,51 +1497,22 @@
|
|
|
1051
1497
|
if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
|
|
1052
1498
|
// console.log(filename, 'Relative path: ./hello.txt');
|
|
1053
1499
|
return true;
|
|
1054
|
-
}
|
|
1055
|
-
// Allow paths like foo/hello
|
|
1056
|
-
if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
|
|
1057
|
-
// console.log(filename, 'Allow paths like foo/hello');
|
|
1058
|
-
return true;
|
|
1059
|
-
}
|
|
1060
|
-
// Allow paths like hello.book
|
|
1061
|
-
if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
|
|
1062
|
-
// console.log(filename, 'Allow paths like hello.book');
|
|
1063
|
-
return true;
|
|
1064
|
-
}
|
|
1065
|
-
return false;
|
|
1066
|
-
}
|
|
1067
|
-
/**
|
|
1068
|
-
* TODO: [🍏] Implement for MacOs
|
|
1069
|
-
*/
|
|
1070
|
-
|
|
1071
|
-
/**
|
|
1072
|
-
* Tests if given string is valid URL.
|
|
1073
|
-
*
|
|
1074
|
-
* Note: Dataurl are considered perfectly valid.
|
|
1075
|
-
* Note: There are two simmilar functions:
|
|
1076
|
-
* - `isValidUrl` which tests any URL
|
|
1077
|
-
* - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
|
|
1078
|
-
*
|
|
1079
|
-
* @public exported from `@promptbook/utils`
|
|
1080
|
-
*/
|
|
1081
|
-
function isValidUrl(url) {
|
|
1082
|
-
if (typeof url !== 'string') {
|
|
1083
|
-
return false;
|
|
1084
|
-
}
|
|
1085
|
-
try {
|
|
1086
|
-
if (url.startsWith('blob:')) {
|
|
1087
|
-
url = url.replace(/^blob:/, '');
|
|
1088
|
-
}
|
|
1089
|
-
const urlObject = new URL(url /* because fail is handled */);
|
|
1090
|
-
if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
|
|
1091
|
-
return false;
|
|
1092
|
-
}
|
|
1500
|
+
}
|
|
1501
|
+
// Allow paths like foo/hello
|
|
1502
|
+
if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
|
|
1503
|
+
// console.log(filename, 'Allow paths like foo/hello');
|
|
1093
1504
|
return true;
|
|
1094
1505
|
}
|
|
1095
|
-
|
|
1096
|
-
|
|
1506
|
+
// Allow paths like hello.book
|
|
1507
|
+
if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
|
|
1508
|
+
// console.log(filename, 'Allow paths like hello.book');
|
|
1509
|
+
return true;
|
|
1097
1510
|
}
|
|
1511
|
+
return false;
|
|
1098
1512
|
}
|
|
1513
|
+
/**
|
|
1514
|
+
* TODO: [🍏] Implement for MacOs
|
|
1515
|
+
*/
|
|
1099
1516
|
|
|
1100
1517
|
const defaultDiacriticsRemovalMap = [
|
|
1101
1518
|
{
|
|
@@ -1509,703 +1926,743 @@
|
|
|
1509
1926
|
*/
|
|
1510
1927
|
|
|
1511
1928
|
/**
|
|
1512
|
-
*
|
|
1929
|
+
* This error indicates problems parsing the format value
|
|
1513
1930
|
*
|
|
1514
|
-
*
|
|
1931
|
+
* For example, when the format value is not a valid JSON or CSV
|
|
1932
|
+
* This is not thrown directly but in extended classes
|
|
1515
1933
|
*
|
|
1516
|
-
* @
|
|
1517
|
-
* @returns secure random token
|
|
1934
|
+
* @public exported from `@promptbook/core`
|
|
1518
1935
|
*/
|
|
1519
|
-
|
|
1520
|
-
|
|
1936
|
+
class AbstractFormatError extends Error {
|
|
1937
|
+
// Note: To allow instanceof do not put here error `name`
|
|
1938
|
+
// public readonly name = 'AbstractFormatError';
|
|
1939
|
+
constructor(message) {
|
|
1940
|
+
super(message);
|
|
1941
|
+
Object.setPrototypeOf(this, AbstractFormatError.prototype);
|
|
1942
|
+
}
|
|
1521
1943
|
}
|
|
1522
|
-
/**
|
|
1523
|
-
* TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
1524
|
-
*/
|
|
1525
1944
|
|
|
1526
1945
|
/**
|
|
1527
|
-
* This error indicates
|
|
1946
|
+
* This error indicates problem with parsing of CSV
|
|
1528
1947
|
*
|
|
1529
1948
|
* @public exported from `@promptbook/core`
|
|
1530
1949
|
*/
|
|
1531
|
-
class
|
|
1950
|
+
class CsvFormatError extends AbstractFormatError {
|
|
1532
1951
|
constructor(message) {
|
|
1533
|
-
// Added id parameter
|
|
1534
1952
|
super(message);
|
|
1535
|
-
this.name = '
|
|
1536
|
-
|
|
1537
|
-
this.id = `error-${$randomToken(8 /* <- TODO: To global config + Use Base58 to avoid simmilar char conflicts */)}`;
|
|
1538
|
-
Object.setPrototypeOf(this, PipelineExecutionError.prototype);
|
|
1953
|
+
this.name = 'CsvFormatError';
|
|
1954
|
+
Object.setPrototypeOf(this, CsvFormatError.prototype);
|
|
1539
1955
|
}
|
|
1540
1956
|
}
|
|
1541
|
-
/**
|
|
1542
|
-
* TODO: !!!!!! Add id to all errors
|
|
1543
|
-
*/
|
|
1544
1957
|
|
|
1545
1958
|
/**
|
|
1546
|
-
*
|
|
1959
|
+
* AuthenticationError is thrown from login function which is dependency of remote server
|
|
1547
1960
|
*
|
|
1548
1961
|
* @public exported from `@promptbook/core`
|
|
1549
1962
|
*/
|
|
1550
|
-
class
|
|
1551
|
-
constructor() {
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
* Returns the number of key/value pairs currently present in the list associated with the object.
|
|
1556
|
-
*/
|
|
1557
|
-
get length() {
|
|
1558
|
-
return Object.keys(this.storage).length;
|
|
1559
|
-
}
|
|
1560
|
-
/**
|
|
1561
|
-
* Empties the list associated with the object of all key/value pairs, if there are any.
|
|
1562
|
-
*/
|
|
1563
|
-
clear() {
|
|
1564
|
-
this.storage = {};
|
|
1565
|
-
}
|
|
1566
|
-
/**
|
|
1567
|
-
* 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.
|
|
1568
|
-
*/
|
|
1569
|
-
getItem(key) {
|
|
1570
|
-
return this.storage[key] || null;
|
|
1571
|
-
}
|
|
1572
|
-
/**
|
|
1573
|
-
* 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.
|
|
1574
|
-
*/
|
|
1575
|
-
key(index) {
|
|
1576
|
-
return Object.keys(this.storage)[index] || null;
|
|
1577
|
-
}
|
|
1578
|
-
/**
|
|
1579
|
-
* Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
|
|
1580
|
-
*/
|
|
1581
|
-
setItem(key, value) {
|
|
1582
|
-
this.storage[key] = value;
|
|
1583
|
-
}
|
|
1584
|
-
/**
|
|
1585
|
-
* 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.
|
|
1586
|
-
*/
|
|
1587
|
-
removeItem(key) {
|
|
1588
|
-
delete this.storage[key];
|
|
1963
|
+
class AuthenticationError extends Error {
|
|
1964
|
+
constructor(message) {
|
|
1965
|
+
super(message);
|
|
1966
|
+
this.name = 'AuthenticationError';
|
|
1967
|
+
Object.setPrototypeOf(this, AuthenticationError.prototype);
|
|
1589
1968
|
}
|
|
1590
1969
|
}
|
|
1591
1970
|
|
|
1592
1971
|
/**
|
|
1593
|
-
*
|
|
1594
|
-
*
|
|
1595
|
-
* Note: `$` is used to indicate that this function is not a pure function - it is not deterministic because it depends on the current time
|
|
1972
|
+
* This error indicates that the pipeline collection cannot be propperly loaded
|
|
1596
1973
|
*
|
|
1597
|
-
* @
|
|
1598
|
-
* @public exported from `@promptbook/utils`
|
|
1974
|
+
* @public exported from `@promptbook/core`
|
|
1599
1975
|
*/
|
|
1600
|
-
|
|
1601
|
-
|
|
1976
|
+
class CollectionError extends Error {
|
|
1977
|
+
constructor(message) {
|
|
1978
|
+
super(message);
|
|
1979
|
+
this.name = 'CollectionError';
|
|
1980
|
+
Object.setPrototypeOf(this, CollectionError.prototype);
|
|
1981
|
+
}
|
|
1602
1982
|
}
|
|
1603
1983
|
|
|
1604
1984
|
/**
|
|
1605
|
-
*
|
|
1606
|
-
*
|
|
1607
|
-
* Note: It can take extended `LlmExecutionTools` and cache the
|
|
1985
|
+
* This error occurs when some expectation is not met in the execution of the pipeline
|
|
1608
1986
|
*
|
|
1609
|
-
* @param llmTools LLM tools to be intercepted with usage counting, it can contain extra methods like `totalUsage`
|
|
1610
|
-
* @returns LLM tools with same functionality with added total cost counting
|
|
1611
1987
|
* @public exported from `@promptbook/core`
|
|
1988
|
+
* Note: Do not throw this error, its reserved for `checkExpectations` and `createPipelineExecutor` and public ONLY to be serializable through remote server
|
|
1989
|
+
* Note: Always thrown in `checkExpectations` and catched in `createPipelineExecutor` and rethrown as `PipelineExecutionError`
|
|
1990
|
+
* Note: This is a kindof subtype of PipelineExecutionError
|
|
1612
1991
|
*/
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
get title() {
|
|
1619
|
-
// TODO: [🧠] Maybe put here some suffix
|
|
1620
|
-
return llmTools.title;
|
|
1621
|
-
},
|
|
1622
|
-
get description() {
|
|
1623
|
-
// TODO: [🧠] Maybe put here some suffix
|
|
1624
|
-
return llmTools.description;
|
|
1625
|
-
},
|
|
1626
|
-
listModels() {
|
|
1627
|
-
// TODO: [🧠] Should be model listing also cached?
|
|
1628
|
-
return /* not await */ llmTools.listModels();
|
|
1629
|
-
},
|
|
1630
|
-
};
|
|
1631
|
-
const callCommonModel = async (prompt) => {
|
|
1632
|
-
const { parameters, content, modelRequirements } = prompt;
|
|
1633
|
-
// <- Note: These are relevant things from the prompt that the cache key should depend on.
|
|
1634
|
-
const key = titleToName(prompt.title.substring(0, MAX_FILENAME_LENGTH - 10) +
|
|
1635
|
-
'-' +
|
|
1636
|
-
sha256__default["default"](hexEncoder__default["default"].parse(JSON.stringify({ parameters, content, modelRequirements }))).toString( /* hex */));
|
|
1637
|
-
const cacheItem = !isCacheReloaded ? await storage.getItem(key) : null;
|
|
1638
|
-
if (cacheItem) {
|
|
1639
|
-
return cacheItem.promptResult;
|
|
1640
|
-
}
|
|
1641
|
-
let promptResult;
|
|
1642
|
-
variant: switch (prompt.modelRequirements.modelVariant) {
|
|
1643
|
-
case 'CHAT':
|
|
1644
|
-
promptResult = await llmTools.callChatModel(prompt);
|
|
1645
|
-
break variant;
|
|
1646
|
-
case 'COMPLETION':
|
|
1647
|
-
promptResult = await llmTools.callCompletionModel(prompt);
|
|
1648
|
-
break variant;
|
|
1649
|
-
case 'EMBEDDING':
|
|
1650
|
-
promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
1651
|
-
break variant;
|
|
1652
|
-
// <- case [🤖]:
|
|
1653
|
-
default:
|
|
1654
|
-
throw new PipelineExecutionError(`Unknown model variant "${prompt.modelRequirements.modelVariant}"`);
|
|
1655
|
-
}
|
|
1656
|
-
// TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
|
|
1657
|
-
// promptResult.timing: FromtoItems
|
|
1658
|
-
await storage.setItem(key, {
|
|
1659
|
-
date: $getCurrentDate(),
|
|
1660
|
-
promptbookVersion: PROMPTBOOK_ENGINE_VERSION,
|
|
1661
|
-
prompt,
|
|
1662
|
-
promptResult,
|
|
1663
|
-
});
|
|
1664
|
-
return promptResult;
|
|
1665
|
-
};
|
|
1666
|
-
if (llmTools.callChatModel !== undefined) {
|
|
1667
|
-
proxyTools.callChatModel = async (prompt) => {
|
|
1668
|
-
return /* not await */ callCommonModel(prompt);
|
|
1669
|
-
};
|
|
1670
|
-
}
|
|
1671
|
-
if (llmTools.callCompletionModel !== undefined) {
|
|
1672
|
-
proxyTools.callCompletionModel = async (prompt) => {
|
|
1673
|
-
return /* not await */ callCommonModel(prompt);
|
|
1674
|
-
};
|
|
1675
|
-
}
|
|
1676
|
-
if (llmTools.callEmbeddingModel !== undefined) {
|
|
1677
|
-
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
1678
|
-
return /* not await */ callCommonModel(prompt);
|
|
1679
|
-
};
|
|
1992
|
+
class ExpectError extends Error {
|
|
1993
|
+
constructor(message) {
|
|
1994
|
+
super(message);
|
|
1995
|
+
this.name = 'ExpectError';
|
|
1996
|
+
Object.setPrototypeOf(this, ExpectError.prototype);
|
|
1680
1997
|
}
|
|
1681
|
-
// <- Note: [🤖]
|
|
1682
|
-
return proxyTools;
|
|
1683
1998
|
}
|
|
1684
|
-
/**
|
|
1685
|
-
* TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
|
|
1686
|
-
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
1687
|
-
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
1688
|
-
* @@@ write discussion about this and storages
|
|
1689
|
-
* @@@ write how to combine multiple interceptors
|
|
1690
|
-
*/
|
|
1691
1999
|
|
|
1692
2000
|
/**
|
|
1693
|
-
*
|
|
2001
|
+
* This error indicates that the promptbook can not retrieve knowledge from external sources
|
|
1694
2002
|
*
|
|
1695
2003
|
* @public exported from `@promptbook/core`
|
|
1696
2004
|
*/
|
|
1697
|
-
|
|
2005
|
+
class KnowledgeScrapeError extends Error {
|
|
2006
|
+
constructor(message) {
|
|
2007
|
+
super(message);
|
|
2008
|
+
this.name = 'KnowledgeScrapeError';
|
|
2009
|
+
Object.setPrototypeOf(this, KnowledgeScrapeError.prototype);
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
|
|
1698
2013
|
/**
|
|
1699
|
-
*
|
|
2014
|
+
* This error type indicates that some limit was reached
|
|
1700
2015
|
*
|
|
1701
2016
|
* @public exported from `@promptbook/core`
|
|
1702
2017
|
*/
|
|
1703
|
-
|
|
2018
|
+
class LimitReachedError extends Error {
|
|
2019
|
+
constructor(message) {
|
|
2020
|
+
super(message);
|
|
2021
|
+
this.name = 'LimitReachedError';
|
|
2022
|
+
Object.setPrototypeOf(this, LimitReachedError.prototype);
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
|
|
1704
2026
|
/**
|
|
1705
|
-
*
|
|
2027
|
+
* This error type indicates that some tools are missing for pipeline execution or preparation
|
|
1706
2028
|
*
|
|
1707
2029
|
* @public exported from `@promptbook/core`
|
|
1708
2030
|
*/
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
2031
|
+
class MissingToolsError extends Error {
|
|
2032
|
+
constructor(message) {
|
|
2033
|
+
super(spaceTrim.spaceTrim((block) => `
|
|
2034
|
+
${block(message)}
|
|
2035
|
+
|
|
2036
|
+
Note: You have probbably forgot to provide some tools for pipeline execution or preparation
|
|
2037
|
+
|
|
2038
|
+
`));
|
|
2039
|
+
this.name = 'MissingToolsError';
|
|
2040
|
+
Object.setPrototypeOf(this, MissingToolsError.prototype);
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
2045
|
+
* This error indicates that promptbook not found in the collection
|
|
2046
|
+
*
|
|
2047
|
+
* @public exported from `@promptbook/core`
|
|
2048
|
+
*/
|
|
2049
|
+
class NotFoundError extends Error {
|
|
2050
|
+
constructor(message) {
|
|
2051
|
+
super(message);
|
|
2052
|
+
this.name = 'NotFoundError';
|
|
2053
|
+
Object.setPrototypeOf(this, NotFoundError.prototype);
|
|
2054
|
+
}
|
|
2055
|
+
}
|
|
2056
|
+
|
|
1730
2057
|
/**
|
|
1731
|
-
*
|
|
2058
|
+
* This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
|
|
1732
2059
|
*
|
|
1733
2060
|
* @public exported from `@promptbook/core`
|
|
1734
2061
|
*/
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
linesCount: UNCERTAIN_ZERO_VALUE,
|
|
1743
|
-
paragraphsCount: UNCERTAIN_ZERO_VALUE,
|
|
1744
|
-
pagesCount: UNCERTAIN_ZERO_VALUE,
|
|
1745
|
-
},
|
|
1746
|
-
output: {
|
|
1747
|
-
tokensCount: UNCERTAIN_ZERO_VALUE,
|
|
1748
|
-
charactersCount: UNCERTAIN_ZERO_VALUE,
|
|
1749
|
-
wordsCount: UNCERTAIN_ZERO_VALUE,
|
|
1750
|
-
sentencesCount: UNCERTAIN_ZERO_VALUE,
|
|
1751
|
-
linesCount: UNCERTAIN_ZERO_VALUE,
|
|
1752
|
-
paragraphsCount: UNCERTAIN_ZERO_VALUE,
|
|
1753
|
-
pagesCount: UNCERTAIN_ZERO_VALUE,
|
|
1754
|
-
},
|
|
1755
|
-
});
|
|
2062
|
+
class ParseError extends Error {
|
|
2063
|
+
constructor(message) {
|
|
2064
|
+
super(message);
|
|
2065
|
+
this.name = 'ParseError';
|
|
2066
|
+
Object.setPrototypeOf(this, ParseError.prototype);
|
|
2067
|
+
}
|
|
2068
|
+
}
|
|
1756
2069
|
/**
|
|
1757
|
-
*
|
|
2070
|
+
* TODO: Maybe split `ParseError` and `ApplyError`
|
|
1758
2071
|
*/
|
|
1759
2072
|
|
|
1760
2073
|
/**
|
|
1761
|
-
*
|
|
2074
|
+
* Generates random token
|
|
1762
2075
|
*
|
|
1763
|
-
* Note:
|
|
2076
|
+
* Note: This function is cryptographically secure (it uses crypto.randomBytes internally)
|
|
1764
2077
|
*
|
|
1765
|
-
* @
|
|
2078
|
+
* @private internal helper function
|
|
2079
|
+
* @returns secure random token
|
|
1766
2080
|
*/
|
|
1767
|
-
function
|
|
1768
|
-
return
|
|
1769
|
-
var _a;
|
|
1770
|
-
acc.price.value += ((_a = item.price) === null || _a === void 0 ? void 0 : _a.value) || 0;
|
|
1771
|
-
for (const key of Object.keys(acc.input)) {
|
|
1772
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1773
|
-
//@ts-ignore
|
|
1774
|
-
if (item.input[key]) {
|
|
1775
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1776
|
-
//@ts-ignore
|
|
1777
|
-
acc.input[key].value += item.input[key].value || 0;
|
|
1778
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1779
|
-
//@ts-ignore
|
|
1780
|
-
if (item.input[key].isUncertain) {
|
|
1781
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1782
|
-
//@ts-ignore
|
|
1783
|
-
acc.input[key].isUncertain = true;
|
|
1784
|
-
}
|
|
1785
|
-
}
|
|
1786
|
-
}
|
|
1787
|
-
for (const key of Object.keys(acc.output)) {
|
|
1788
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1789
|
-
//@ts-ignore
|
|
1790
|
-
if (item.output[key]) {
|
|
1791
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1792
|
-
//@ts-ignore
|
|
1793
|
-
acc.output[key].value += item.output[key].value || 0;
|
|
1794
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1795
|
-
//@ts-ignore
|
|
1796
|
-
if (item.output[key].isUncertain) {
|
|
1797
|
-
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
1798
|
-
//@ts-ignore
|
|
1799
|
-
acc.output[key].isUncertain = true;
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
return acc;
|
|
1804
|
-
}, deepClone(ZERO_USAGE));
|
|
2081
|
+
function $randomToken(randomness) {
|
|
2082
|
+
return crypto.randomBytes(randomness).toString('hex');
|
|
1805
2083
|
}
|
|
2084
|
+
/**
|
|
2085
|
+
* TODO: Maybe use nanoid instead https://github.com/ai/nanoid
|
|
2086
|
+
*/
|
|
1806
2087
|
|
|
1807
2088
|
/**
|
|
1808
|
-
*
|
|
2089
|
+
* This error indicates errors during the execution of the pipeline
|
|
1809
2090
|
*
|
|
1810
|
-
* @param llmTools LLM tools to be intercepted with usage counting
|
|
1811
|
-
* @returns LLM tools with same functionality with added total cost counting
|
|
1812
2091
|
* @public exported from `@promptbook/core`
|
|
1813
2092
|
*/
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
get description() {
|
|
1823
|
-
// TODO: [🧠] Maybe put here some suffix
|
|
1824
|
-
return llmTools.description;
|
|
1825
|
-
},
|
|
1826
|
-
checkConfiguration() {
|
|
1827
|
-
return /* not await */ llmTools.checkConfiguration();
|
|
1828
|
-
},
|
|
1829
|
-
listModels() {
|
|
1830
|
-
return /* not await */ llmTools.listModels();
|
|
1831
|
-
},
|
|
1832
|
-
spending() {
|
|
1833
|
-
return spending.asObservable();
|
|
1834
|
-
},
|
|
1835
|
-
getTotalUsage() {
|
|
1836
|
-
// <- Note: [🥫] Not using getter `get totalUsage` but `getTotalUsage` to allow this object to be proxied
|
|
1837
|
-
return totalUsage;
|
|
1838
|
-
},
|
|
1839
|
-
};
|
|
1840
|
-
if (llmTools.callChatModel !== undefined) {
|
|
1841
|
-
proxyTools.callChatModel = async (prompt) => {
|
|
1842
|
-
// console.info('[🚕] callChatModel through countTotalUsage');
|
|
1843
|
-
const promptResult = await llmTools.callChatModel(prompt);
|
|
1844
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
1845
|
-
spending.next(promptResult.usage);
|
|
1846
|
-
return promptResult;
|
|
1847
|
-
};
|
|
1848
|
-
}
|
|
1849
|
-
if (llmTools.callCompletionModel !== undefined) {
|
|
1850
|
-
proxyTools.callCompletionModel = async (prompt) => {
|
|
1851
|
-
// console.info('[🚕] callCompletionModel through countTotalUsage');
|
|
1852
|
-
const promptResult = await llmTools.callCompletionModel(prompt);
|
|
1853
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
1854
|
-
spending.next(promptResult.usage);
|
|
1855
|
-
return promptResult;
|
|
1856
|
-
};
|
|
1857
|
-
}
|
|
1858
|
-
if (llmTools.callEmbeddingModel !== undefined) {
|
|
1859
|
-
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
1860
|
-
// console.info('[🚕] callEmbeddingModel through countTotalUsage');
|
|
1861
|
-
const promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
1862
|
-
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
1863
|
-
spending.next(promptResult.usage);
|
|
1864
|
-
return promptResult;
|
|
1865
|
-
};
|
|
2093
|
+
class PipelineExecutionError extends Error {
|
|
2094
|
+
constructor(message) {
|
|
2095
|
+
// Added id parameter
|
|
2096
|
+
super(message);
|
|
2097
|
+
this.name = 'PipelineExecutionError';
|
|
2098
|
+
// TODO: [🐙] DRY - Maybe $randomId
|
|
2099
|
+
this.id = `error-${$randomToken(8 /* <- TODO: To global config + Use Base58 to avoid simmilar char conflicts */)}`;
|
|
2100
|
+
Object.setPrototypeOf(this, PipelineExecutionError.prototype);
|
|
1866
2101
|
}
|
|
1867
|
-
// <- Note: [🤖]
|
|
1868
|
-
return proxyTools;
|
|
1869
2102
|
}
|
|
1870
2103
|
/**
|
|
1871
|
-
* TODO:
|
|
1872
|
-
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
1873
|
-
* TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
|
|
1874
|
-
* > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
|
|
1875
|
-
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
2104
|
+
* TODO: !!!!!! Add id to all errors
|
|
1876
2105
|
*/
|
|
1877
2106
|
|
|
1878
2107
|
/**
|
|
1879
|
-
* This error
|
|
2108
|
+
* This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
|
|
1880
2109
|
*
|
|
1881
2110
|
* @public exported from `@promptbook/core`
|
|
1882
2111
|
*/
|
|
1883
|
-
class
|
|
2112
|
+
class PipelineLogicError extends Error {
|
|
1884
2113
|
constructor(message) {
|
|
1885
|
-
super(
|
|
1886
|
-
|
|
2114
|
+
super(message);
|
|
2115
|
+
this.name = 'PipelineLogicError';
|
|
2116
|
+
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
1887
2119
|
|
|
1888
|
-
|
|
2120
|
+
/**
|
|
2121
|
+
* This error indicates errors in referencing promptbooks between each other
|
|
2122
|
+
*
|
|
2123
|
+
* @public exported from `@promptbook/core`
|
|
2124
|
+
*/
|
|
2125
|
+
class PipelineUrlError extends Error {
|
|
2126
|
+
constructor(message) {
|
|
2127
|
+
super(message);
|
|
2128
|
+
this.name = 'PipelineUrlError';
|
|
2129
|
+
Object.setPrototypeOf(this, PipelineUrlError.prototype);
|
|
2130
|
+
}
|
|
2131
|
+
}
|
|
1889
2132
|
|
|
1890
|
-
|
|
1891
|
-
|
|
2133
|
+
/**
|
|
2134
|
+
* Index of all custom errors
|
|
2135
|
+
*
|
|
2136
|
+
* @public exported from `@promptbook/core`
|
|
2137
|
+
*/
|
|
2138
|
+
const PROMPTBOOK_ERRORS = {
|
|
2139
|
+
AbstractFormatError,
|
|
2140
|
+
CsvFormatError,
|
|
2141
|
+
CollectionError,
|
|
2142
|
+
EnvironmentMismatchError,
|
|
2143
|
+
ExpectError,
|
|
2144
|
+
KnowledgeScrapeError,
|
|
2145
|
+
LimitReachedError,
|
|
2146
|
+
MissingToolsError,
|
|
2147
|
+
NotFoundError,
|
|
2148
|
+
NotYetImplementedError,
|
|
2149
|
+
ParseError,
|
|
2150
|
+
PipelineExecutionError,
|
|
2151
|
+
PipelineLogicError,
|
|
2152
|
+
PipelineUrlError,
|
|
2153
|
+
UnexpectedError,
|
|
2154
|
+
// TODO: [🪑]> VersionMismatchError,
|
|
2155
|
+
};
|
|
2156
|
+
/**
|
|
2157
|
+
* Index of all javascript errors
|
|
2158
|
+
*
|
|
2159
|
+
* @private for internal usage
|
|
2160
|
+
*/
|
|
2161
|
+
const COMMON_JAVASCRIPT_ERRORS = {
|
|
2162
|
+
Error,
|
|
2163
|
+
EvalError,
|
|
2164
|
+
RangeError,
|
|
2165
|
+
ReferenceError,
|
|
2166
|
+
SyntaxError,
|
|
2167
|
+
TypeError,
|
|
2168
|
+
URIError,
|
|
2169
|
+
AggregateError,
|
|
2170
|
+
AuthenticationError,
|
|
2171
|
+
/*
|
|
2172
|
+
Note: Not widely supported
|
|
2173
|
+
> InternalError,
|
|
2174
|
+
> ModuleError,
|
|
2175
|
+
> HeapError,
|
|
2176
|
+
> WebAssemblyCompileError,
|
|
2177
|
+
> WebAssemblyRuntimeError,
|
|
2178
|
+
*/
|
|
2179
|
+
};
|
|
2180
|
+
/**
|
|
2181
|
+
* Index of all errors
|
|
2182
|
+
*
|
|
2183
|
+
* @private for internal usage
|
|
2184
|
+
*/
|
|
2185
|
+
const ALL_ERRORS = {
|
|
2186
|
+
...PROMPTBOOK_ERRORS,
|
|
2187
|
+
...COMMON_JAVASCRIPT_ERRORS,
|
|
2188
|
+
};
|
|
2189
|
+
/**
|
|
2190
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2191
|
+
*/
|
|
1892
2192
|
|
|
1893
|
-
|
|
2193
|
+
/**
|
|
2194
|
+
* Deserializes the error object
|
|
2195
|
+
*
|
|
2196
|
+
* @public exported from `@promptbook/utils`
|
|
2197
|
+
*/
|
|
2198
|
+
function deserializeError(error) {
|
|
2199
|
+
const { name, stack, id } = error; // Added id
|
|
2200
|
+
let { message } = error;
|
|
2201
|
+
let ErrorClass = ALL_ERRORS[error.name];
|
|
2202
|
+
if (ErrorClass === undefined) {
|
|
2203
|
+
ErrorClass = Error;
|
|
2204
|
+
message = `${name}: ${message}`;
|
|
2205
|
+
}
|
|
2206
|
+
if (stack !== undefined && stack !== '') {
|
|
2207
|
+
message = spaceTrim__default["default"]((block) => `
|
|
2208
|
+
${block(message)}
|
|
1894
2209
|
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
2210
|
+
Original stack trace:
|
|
2211
|
+
${block(stack || '')}
|
|
2212
|
+
`);
|
|
1898
2213
|
}
|
|
2214
|
+
const deserializedError = new ErrorClass(message);
|
|
2215
|
+
deserializedError.id = id; // Assign id to the error object
|
|
2216
|
+
return deserializedError;
|
|
1899
2217
|
}
|
|
1900
2218
|
|
|
1901
2219
|
/**
|
|
1902
|
-
*
|
|
2220
|
+
* Creates a connection to the remote proxy server.
|
|
1903
2221
|
*
|
|
1904
|
-
* Note:
|
|
2222
|
+
* Note: This function creates a connection to the remote server and returns a socket but responsibility of closing the connection is on the caller
|
|
1905
2223
|
*
|
|
1906
|
-
*
|
|
2224
|
+
* @private internal utility function
|
|
1907
2225
|
*/
|
|
1908
|
-
function
|
|
1909
|
-
|
|
2226
|
+
async function createRemoteClient(options) {
|
|
2227
|
+
const { remoteServerUrl } = options;
|
|
2228
|
+
let path = new URL(remoteServerUrl).pathname;
|
|
2229
|
+
if (path.endsWith('/')) {
|
|
2230
|
+
path = path.slice(0, -1);
|
|
2231
|
+
}
|
|
2232
|
+
path = `${path}/socket.io`;
|
|
2233
|
+
return new Promise((resolve, reject) => {
|
|
2234
|
+
const socket = socket_ioClient.io(remoteServerUrl, {
|
|
2235
|
+
retries: CONNECTION_RETRIES_LIMIT,
|
|
2236
|
+
timeout: CONNECTION_TIMEOUT_MS,
|
|
2237
|
+
path,
|
|
2238
|
+
transports: [/*'websocket', <- TODO: [🌬] Make websocket transport work */ 'polling'],
|
|
2239
|
+
});
|
|
2240
|
+
// console.log('Connecting to', this.options.remoteServerUrl.href, { socket });
|
|
2241
|
+
socket.on('connect', () => {
|
|
2242
|
+
resolve(socket);
|
|
2243
|
+
});
|
|
2244
|
+
// TODO: [💩] Better timeout handling
|
|
2245
|
+
setTimeout(() => {
|
|
2246
|
+
reject(new Error(`Timeout while connecting to ${remoteServerUrl}`));
|
|
2247
|
+
}, CONNECTION_TIMEOUT_MS);
|
|
2248
|
+
});
|
|
1910
2249
|
}
|
|
1911
2250
|
|
|
1912
2251
|
/**
|
|
1913
|
-
*
|
|
2252
|
+
* Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
|
|
1914
2253
|
*
|
|
1915
|
-
*
|
|
1916
|
-
*
|
|
1917
|
-
*
|
|
1918
|
-
* @
|
|
1919
|
-
* @public exported from `@promptbook/
|
|
2254
|
+
* You can simply use `RemoteExecutionTools` on client-side javascript and connect to your remote server.
|
|
2255
|
+
* This is useful to make all logic on browser side but not expose your API keys or no need to use customer's GPU.
|
|
2256
|
+
*
|
|
2257
|
+
* @see https://github.com/webgptorg/promptbook#remote-server
|
|
2258
|
+
* @public exported from `@promptbook/remote-client`
|
|
1920
2259
|
*/
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
2260
|
+
class RemoteLlmExecutionTools {
|
|
2261
|
+
/* <- TODO: [🍚] `, Destroyable` */
|
|
2262
|
+
constructor(options) {
|
|
2263
|
+
this.options = options;
|
|
2264
|
+
}
|
|
2265
|
+
get title() {
|
|
2266
|
+
// TODO: [🧠] Maybe fetch title+description from the remote server (as well as if model methods are defined)
|
|
2267
|
+
return 'Remote server';
|
|
2268
|
+
}
|
|
2269
|
+
get description() {
|
|
2270
|
+
return 'Use all models by your remote server';
|
|
2271
|
+
}
|
|
2272
|
+
/**
|
|
2273
|
+
* Check the configuration of all execution tools
|
|
2274
|
+
*/
|
|
2275
|
+
async checkConfiguration() {
|
|
2276
|
+
const socket = await createRemoteClient(this.options);
|
|
2277
|
+
socket.disconnect();
|
|
2278
|
+
// TODO: [main] !!3 Check version of the remote server and compatibility
|
|
2279
|
+
// TODO: [🎍] Send checkConfiguration
|
|
2280
|
+
}
|
|
2281
|
+
/**
|
|
2282
|
+
* List all available models that can be used
|
|
2283
|
+
*/
|
|
2284
|
+
async listModels() {
|
|
2285
|
+
// TODO: [👒] Listing models (and checking configuration) probbably should go through REST API not Socket.io
|
|
2286
|
+
const socket = await createRemoteClient(this.options);
|
|
2287
|
+
socket.emit('listModels-request', {
|
|
2288
|
+
identification: this.options.identification,
|
|
2289
|
+
} /* <- Note: [🤛] */);
|
|
2290
|
+
const promptResult = await new Promise((resolve, reject) => {
|
|
2291
|
+
socket.on('listModels-response', (response) => {
|
|
2292
|
+
resolve(response.models);
|
|
2293
|
+
socket.disconnect();
|
|
2294
|
+
});
|
|
2295
|
+
socket.on('error', (error) => {
|
|
2296
|
+
reject(deserializeError(error));
|
|
2297
|
+
socket.disconnect();
|
|
2298
|
+
});
|
|
2299
|
+
});
|
|
2300
|
+
socket.disconnect();
|
|
2301
|
+
return promptResult;
|
|
2302
|
+
}
|
|
2303
|
+
/**
|
|
2304
|
+
* Calls remote proxy server to use a chat model
|
|
2305
|
+
*/
|
|
2306
|
+
callChatModel(prompt) {
|
|
2307
|
+
if (this.options.isVerbose) {
|
|
2308
|
+
console.info(`🖋 Remote callChatModel call`);
|
|
1938
2309
|
}
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2310
|
+
return /* not await */ this.callCommonModel(prompt);
|
|
2311
|
+
}
|
|
2312
|
+
/**
|
|
2313
|
+
* Calls remote proxy server to use a completion model
|
|
2314
|
+
*/
|
|
2315
|
+
callCompletionModel(prompt) {
|
|
2316
|
+
if (this.options.isVerbose) {
|
|
2317
|
+
console.info(`💬 Remote callCompletionModel call`);
|
|
1942
2318
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
2319
|
+
return /* not await */ this.callCommonModel(prompt);
|
|
2320
|
+
}
|
|
2321
|
+
/**
|
|
2322
|
+
* Calls remote proxy server to use a embedding model
|
|
2323
|
+
*/
|
|
2324
|
+
callEmbeddingModel(prompt) {
|
|
2325
|
+
if (this.options.isVerbose) {
|
|
2326
|
+
console.info(`💬 Remote callEmbeddingModel call`);
|
|
1948
2327
|
}
|
|
1949
|
-
|
|
1950
|
-
|
|
2328
|
+
return /* not await */ this.callCommonModel(prompt);
|
|
2329
|
+
}
|
|
2330
|
+
// <- Note: [🤖] callXxxModel
|
|
2331
|
+
/**
|
|
2332
|
+
* Calls remote proxy server to use both completion or chat model
|
|
2333
|
+
*/
|
|
2334
|
+
async callCommonModel(prompt) {
|
|
2335
|
+
const socket = await createRemoteClient(this.options);
|
|
2336
|
+
socket.emit('prompt-request', {
|
|
2337
|
+
identification: this.options.identification,
|
|
2338
|
+
prompt,
|
|
2339
|
+
} /* <- Note: [🤛] */);
|
|
2340
|
+
const promptResult = await new Promise((resolve, reject) => {
|
|
2341
|
+
socket.on('prompt-response', (response) => {
|
|
2342
|
+
resolve(response.promptResult);
|
|
2343
|
+
socket.disconnect();
|
|
2344
|
+
});
|
|
2345
|
+
socket.on('error', (error) => {
|
|
2346
|
+
reject(deserializeError(error));
|
|
2347
|
+
socket.disconnect();
|
|
2348
|
+
});
|
|
2349
|
+
});
|
|
2350
|
+
socket.disconnect();
|
|
2351
|
+
return promptResult;
|
|
1951
2352
|
}
|
|
1952
|
-
normalizedName = normalizedName.replace(/_+/g, '_');
|
|
1953
|
-
normalizedName = normalizedName.replace(/_?\/_?/g, '/');
|
|
1954
|
-
normalizedName = normalizedName.replace(/^_/, '');
|
|
1955
|
-
normalizedName = normalizedName.replace(/_$/, '');
|
|
1956
|
-
return normalizedName;
|
|
1957
2353
|
}
|
|
1958
2354
|
/**
|
|
1959
|
-
* TODO:
|
|
1960
|
-
*
|
|
1961
|
-
*
|
|
1962
|
-
*
|
|
1963
|
-
*
|
|
1964
|
-
* TODO: [
|
|
2355
|
+
* TODO: Maybe use `$exportJson`
|
|
2356
|
+
* TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
|
|
2357
|
+
* TODO: [🍓] Allow to list compatible models with each variant
|
|
2358
|
+
* TODO: [🗯] RemoteLlmExecutionTools should extend Destroyable and implement IDestroyable
|
|
2359
|
+
* TODO: [🧠][🌰] Allow to pass `title` for tracking purposes
|
|
2360
|
+
* TODO: [🧠] Maybe remove `@promptbook/remote-client` and just use `@promptbook/core`
|
|
1965
2361
|
*/
|
|
1966
2362
|
|
|
1967
2363
|
/**
|
|
1968
|
-
*
|
|
2364
|
+
* Simple wrapper `new Date().toISOString()`
|
|
1969
2365
|
*
|
|
1970
|
-
*
|
|
1971
|
-
*
|
|
1972
|
-
* @
|
|
1973
|
-
* @example 'i_love_promptbook'
|
|
2366
|
+
* Note: `$` is used to indicate that this function is not a pure function - it is not deterministic because it depends on the current time
|
|
2367
|
+
*
|
|
2368
|
+
* @returns string_date branded type
|
|
1974
2369
|
* @public exported from `@promptbook/utils`
|
|
1975
2370
|
*/
|
|
1976
|
-
function
|
|
1977
|
-
return
|
|
2371
|
+
function $getCurrentDate() {
|
|
2372
|
+
return new Date().toISOString();
|
|
1978
2373
|
}
|
|
1979
2374
|
|
|
1980
2375
|
/**
|
|
1981
|
-
*
|
|
2376
|
+
* Intercepts LLM tools and counts total usage of the tools
|
|
1982
2377
|
*
|
|
1983
|
-
* Note:
|
|
2378
|
+
* Note: It can take extended `LlmExecutionTools` and cache the
|
|
1984
2379
|
*
|
|
1985
|
-
* @
|
|
2380
|
+
* @param llmTools LLM tools to be intercepted with usage counting, it can contain extra methods like `totalUsage`
|
|
2381
|
+
* @returns LLM tools with same functionality with added total cost counting
|
|
2382
|
+
* @public exported from `@promptbook/core`
|
|
1986
2383
|
*/
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
2384
|
+
function cacheLlmTools(llmTools, options = {}) {
|
|
2385
|
+
const { storage = new MemoryStorage(), isCacheReloaded = false } = options;
|
|
2386
|
+
const proxyTools = {
|
|
2387
|
+
...llmTools,
|
|
2388
|
+
// <- Note: [🥫]
|
|
2389
|
+
get title() {
|
|
2390
|
+
// TODO: [🧠] Maybe put here some suffix
|
|
2391
|
+
return llmTools.title;
|
|
2392
|
+
},
|
|
2393
|
+
get description() {
|
|
2394
|
+
// TODO: [🧠] Maybe put here some suffix
|
|
2395
|
+
return llmTools.description;
|
|
2396
|
+
},
|
|
2397
|
+
listModels() {
|
|
2398
|
+
// TODO: [🧠] Should be model listing also cached?
|
|
2399
|
+
return /* not await */ llmTools.listModels();
|
|
2400
|
+
},
|
|
2401
|
+
};
|
|
2402
|
+
const callCommonModel = async (prompt) => {
|
|
2403
|
+
const { parameters, content, modelRequirements } = prompt;
|
|
2404
|
+
// <- Note: These are relevant things from the prompt that the cache key should depend on.
|
|
2405
|
+
const key = titleToName(prompt.title.substring(0, MAX_FILENAME_LENGTH - 10) +
|
|
2406
|
+
'-' +
|
|
2407
|
+
sha256__default["default"](hexEncoder__default["default"].parse(JSON.stringify({ parameters, content, modelRequirements }))).toString( /* hex */));
|
|
2408
|
+
const cacheItem = !isCacheReloaded ? await storage.getItem(key) : null;
|
|
2409
|
+
if (cacheItem) {
|
|
2410
|
+
return cacheItem.promptResult;
|
|
1994
2411
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
2412
|
+
let promptResult;
|
|
2413
|
+
variant: switch (prompt.modelRequirements.modelVariant) {
|
|
2414
|
+
case 'CHAT':
|
|
2415
|
+
promptResult = await llmTools.callChatModel(prompt);
|
|
2416
|
+
break variant;
|
|
2417
|
+
case 'COMPLETION':
|
|
2418
|
+
promptResult = await llmTools.callCompletionModel(prompt);
|
|
2419
|
+
break variant;
|
|
2420
|
+
case 'EMBEDDING':
|
|
2421
|
+
promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
2422
|
+
break variant;
|
|
2423
|
+
// <- case [🤖]:
|
|
2424
|
+
default:
|
|
2425
|
+
throw new PipelineExecutionError(`Unknown model variant "${prompt.modelRequirements.modelVariant}"`);
|
|
1997
2426
|
}
|
|
1998
|
-
|
|
2427
|
+
// TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
|
|
2428
|
+
// promptResult.timing: FromtoItems
|
|
2429
|
+
await storage.setItem(key, {
|
|
2430
|
+
date: $getCurrentDate(),
|
|
2431
|
+
promptbookVersion: PROMPTBOOK_ENGINE_VERSION,
|
|
2432
|
+
prompt,
|
|
2433
|
+
promptResult,
|
|
2434
|
+
});
|
|
2435
|
+
return promptResult;
|
|
2436
|
+
};
|
|
2437
|
+
if (llmTools.callChatModel !== undefined) {
|
|
2438
|
+
proxyTools.callChatModel = async (prompt) => {
|
|
2439
|
+
return /* not await */ callCommonModel(prompt);
|
|
2440
|
+
};
|
|
1999
2441
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2442
|
+
if (llmTools.callCompletionModel !== undefined) {
|
|
2443
|
+
proxyTools.callCompletionModel = async (prompt) => {
|
|
2444
|
+
return /* not await */ callCommonModel(prompt);
|
|
2445
|
+
};
|
|
2003
2446
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
const existingRegistration = this.storage[existingRegistrationIndex];
|
|
2008
|
-
if (!existingRegistration) {
|
|
2009
|
-
this.storage.push(registered);
|
|
2010
|
-
}
|
|
2011
|
-
else {
|
|
2012
|
-
this.storage[existingRegistrationIndex] = registered;
|
|
2013
|
-
}
|
|
2014
|
-
return {
|
|
2015
|
-
registerName: this.registerName,
|
|
2016
|
-
packageName,
|
|
2017
|
-
className,
|
|
2018
|
-
get isDestroyed() {
|
|
2019
|
-
return false;
|
|
2020
|
-
},
|
|
2021
|
-
destroy() {
|
|
2022
|
-
throw new NotYetImplementedError(`Registration to ${this.registerName} is permanent in this version of Promptbook`);
|
|
2023
|
-
},
|
|
2447
|
+
if (llmTools.callEmbeddingModel !== undefined) {
|
|
2448
|
+
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
2449
|
+
return /* not await */ callCommonModel(prompt);
|
|
2024
2450
|
};
|
|
2025
2451
|
}
|
|
2452
|
+
// <- Note: [🤖]
|
|
2453
|
+
return proxyTools;
|
|
2026
2454
|
}
|
|
2027
|
-
|
|
2028
|
-
/**
|
|
2029
|
-
* @@@
|
|
2030
|
-
*
|
|
2031
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
2032
|
-
* @singleton Only one instance of each register is created per build, but thare can be more @@@
|
|
2033
|
-
* @public exported from `@promptbook/core`
|
|
2034
|
-
*/
|
|
2035
|
-
const $llmToolsMetadataRegister = new $Register('llm_tools_metadata');
|
|
2036
2455
|
/**
|
|
2037
|
-
* TODO: [
|
|
2456
|
+
* TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
|
|
2457
|
+
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
2458
|
+
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
2459
|
+
* @@@ write discussion about this and storages
|
|
2460
|
+
* @@@ write how to combine multiple interceptors
|
|
2038
2461
|
*/
|
|
2039
2462
|
|
|
2040
2463
|
/**
|
|
2041
|
-
*
|
|
2464
|
+
* Represents the uncertain value
|
|
2042
2465
|
*
|
|
2043
|
-
*
|
|
2044
|
-
* @public exported from `@promptbook/utils`
|
|
2045
|
-
*/
|
|
2046
|
-
function isRootPath(value) {
|
|
2047
|
-
if (value === '/') {
|
|
2048
|
-
return true;
|
|
2049
|
-
}
|
|
2050
|
-
if (/^[A-Z]:\\$/i.test(value)) {
|
|
2051
|
-
return true;
|
|
2052
|
-
}
|
|
2053
|
-
return false;
|
|
2054
|
-
}
|
|
2055
|
-
/**
|
|
2056
|
-
* TODO: [🍏] Make for MacOS paths
|
|
2466
|
+
* @public exported from `@promptbook/core`
|
|
2057
2467
|
*/
|
|
2058
|
-
|
|
2468
|
+
const ZERO_VALUE = $deepFreeze({ value: 0 });
|
|
2059
2469
|
/**
|
|
2060
|
-
*
|
|
2470
|
+
* Represents the uncertain value
|
|
2061
2471
|
*
|
|
2062
|
-
* Note: `$` is used to indicate that this interacts with the global scope
|
|
2063
|
-
* @singleton Only one instance of each register is created per build, but thare can be more @@@
|
|
2064
2472
|
* @public exported from `@promptbook/core`
|
|
2065
2473
|
*/
|
|
2066
|
-
const
|
|
2474
|
+
const UNCERTAIN_ZERO_VALUE = $deepFreeze({ value: 0, isUncertain: true });
|
|
2067
2475
|
/**
|
|
2068
|
-
*
|
|
2476
|
+
* Represents the usage with no resources consumed
|
|
2477
|
+
*
|
|
2478
|
+
* @public exported from `@promptbook/core`
|
|
2069
2479
|
*/
|
|
2070
|
-
|
|
2480
|
+
const ZERO_USAGE = $deepFreeze({
|
|
2481
|
+
price: ZERO_VALUE,
|
|
2482
|
+
input: {
|
|
2483
|
+
tokensCount: ZERO_VALUE,
|
|
2484
|
+
charactersCount: ZERO_VALUE,
|
|
2485
|
+
wordsCount: ZERO_VALUE,
|
|
2486
|
+
sentencesCount: ZERO_VALUE,
|
|
2487
|
+
linesCount: ZERO_VALUE,
|
|
2488
|
+
paragraphsCount: ZERO_VALUE,
|
|
2489
|
+
pagesCount: ZERO_VALUE,
|
|
2490
|
+
},
|
|
2491
|
+
output: {
|
|
2492
|
+
tokensCount: ZERO_VALUE,
|
|
2493
|
+
charactersCount: ZERO_VALUE,
|
|
2494
|
+
wordsCount: ZERO_VALUE,
|
|
2495
|
+
sentencesCount: ZERO_VALUE,
|
|
2496
|
+
linesCount: ZERO_VALUE,
|
|
2497
|
+
paragraphsCount: ZERO_VALUE,
|
|
2498
|
+
pagesCount: ZERO_VALUE,
|
|
2499
|
+
},
|
|
2500
|
+
});
|
|
2071
2501
|
/**
|
|
2072
|
-
*
|
|
2502
|
+
* Represents the usage with unknown resources consumed
|
|
2073
2503
|
*
|
|
2074
|
-
*
|
|
2504
|
+
* @public exported from `@promptbook/core`
|
|
2075
2505
|
*/
|
|
2076
|
-
|
|
2506
|
+
const UNCERTAIN_USAGE = $deepFreeze({
|
|
2507
|
+
price: UNCERTAIN_ZERO_VALUE,
|
|
2508
|
+
input: {
|
|
2509
|
+
tokensCount: UNCERTAIN_ZERO_VALUE,
|
|
2510
|
+
charactersCount: UNCERTAIN_ZERO_VALUE,
|
|
2511
|
+
wordsCount: UNCERTAIN_ZERO_VALUE,
|
|
2512
|
+
sentencesCount: UNCERTAIN_ZERO_VALUE,
|
|
2513
|
+
linesCount: UNCERTAIN_ZERO_VALUE,
|
|
2514
|
+
paragraphsCount: UNCERTAIN_ZERO_VALUE,
|
|
2515
|
+
pagesCount: UNCERTAIN_ZERO_VALUE,
|
|
2516
|
+
},
|
|
2517
|
+
output: {
|
|
2518
|
+
tokensCount: UNCERTAIN_ZERO_VALUE,
|
|
2519
|
+
charactersCount: UNCERTAIN_ZERO_VALUE,
|
|
2520
|
+
wordsCount: UNCERTAIN_ZERO_VALUE,
|
|
2521
|
+
sentencesCount: UNCERTAIN_ZERO_VALUE,
|
|
2522
|
+
linesCount: UNCERTAIN_ZERO_VALUE,
|
|
2523
|
+
paragraphsCount: UNCERTAIN_ZERO_VALUE,
|
|
2524
|
+
pagesCount: UNCERTAIN_ZERO_VALUE,
|
|
2525
|
+
},
|
|
2526
|
+
});
|
|
2077
2527
|
/**
|
|
2078
|
-
*
|
|
2079
|
-
*
|
|
2080
|
-
* Note: `$` is used to indicate that this variable is making side effect
|
|
2081
|
-
*
|
|
2082
|
-
* @private internal log of `$provideLlmToolsConfigurationFromEnv` and `$registeredLlmToolsMessage`
|
|
2528
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2083
2529
|
*/
|
|
2084
|
-
|
|
2085
|
-
$usedEnvFilename = filepath;
|
|
2086
|
-
}
|
|
2530
|
+
|
|
2087
2531
|
/**
|
|
2088
|
-
*
|
|
2532
|
+
* Function `addUsage` will add multiple usages into one
|
|
2089
2533
|
*
|
|
2090
|
-
* Note:
|
|
2534
|
+
* Note: If you provide 0 values, it returns ZERO_USAGE
|
|
2091
2535
|
*
|
|
2092
|
-
* @
|
|
2536
|
+
* @public exported from `@promptbook/core`
|
|
2093
2537
|
*/
|
|
2094
|
-
function
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
for (const { packageName, className } of $llmToolsRegister.list()) {
|
|
2114
|
-
if (all.some((item) => item.packageName === packageName && item.className === className)) {
|
|
2115
|
-
continue;
|
|
2538
|
+
function addUsage(...usageItems) {
|
|
2539
|
+
return usageItems.reduce((acc, item) => {
|
|
2540
|
+
var _a;
|
|
2541
|
+
acc.price.value += ((_a = item.price) === null || _a === void 0 ? void 0 : _a.value) || 0;
|
|
2542
|
+
for (const key of Object.keys(acc.input)) {
|
|
2543
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2544
|
+
//@ts-ignore
|
|
2545
|
+
if (item.input[key]) {
|
|
2546
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2547
|
+
//@ts-ignore
|
|
2548
|
+
acc.input[key].value += item.input[key].value || 0;
|
|
2549
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2550
|
+
//@ts-ignore
|
|
2551
|
+
if (item.input[key].isUncertain) {
|
|
2552
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2553
|
+
//@ts-ignore
|
|
2554
|
+
acc.input[key].isUncertain = true;
|
|
2555
|
+
}
|
|
2556
|
+
}
|
|
2116
2557
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2558
|
+
for (const key of Object.keys(acc.output)) {
|
|
2559
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2560
|
+
//@ts-ignore
|
|
2561
|
+
if (item.output[key]) {
|
|
2562
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2563
|
+
//@ts-ignore
|
|
2564
|
+
acc.output[key].value += item.output[key].value || 0;
|
|
2565
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2566
|
+
//@ts-ignore
|
|
2567
|
+
if (item.output[key].isUncertain) {
|
|
2568
|
+
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
2569
|
+
//@ts-ignore
|
|
2570
|
+
acc.output[key].isUncertain = true;
|
|
2571
|
+
}
|
|
2572
|
+
}
|
|
2573
|
+
}
|
|
2574
|
+
return acc;
|
|
2575
|
+
}, deepClone(ZERO_USAGE));
|
|
2576
|
+
}
|
|
2577
|
+
|
|
2578
|
+
/**
|
|
2579
|
+
* Intercepts LLM tools and counts total usage of the tools
|
|
2580
|
+
*
|
|
2581
|
+
* @param llmTools LLM tools to be intercepted with usage counting
|
|
2582
|
+
* @returns LLM tools with same functionality with added total cost counting
|
|
2583
|
+
* @public exported from `@promptbook/core`
|
|
2584
|
+
*/
|
|
2585
|
+
function countUsage(llmTools) {
|
|
2586
|
+
let totalUsage = ZERO_USAGE;
|
|
2587
|
+
const spending = new rxjs.Subject();
|
|
2588
|
+
const proxyTools = {
|
|
2589
|
+
get title() {
|
|
2590
|
+
// TODO: [🧠] Maybe put here some suffix
|
|
2591
|
+
return llmTools.title;
|
|
2592
|
+
},
|
|
2593
|
+
get description() {
|
|
2594
|
+
// TODO: [🧠] Maybe put here some suffix
|
|
2595
|
+
return llmTools.description;
|
|
2596
|
+
},
|
|
2597
|
+
checkConfiguration() {
|
|
2598
|
+
return /* not await */ llmTools.checkConfiguration();
|
|
2599
|
+
},
|
|
2600
|
+
listModels() {
|
|
2601
|
+
return /* not await */ llmTools.listModels();
|
|
2602
|
+
},
|
|
2603
|
+
spending() {
|
|
2604
|
+
return spending.asObservable();
|
|
2605
|
+
},
|
|
2606
|
+
getTotalUsage() {
|
|
2607
|
+
// <- Note: [🥫] Not using getter `get totalUsage` but `getTotalUsage` to allow this object to be proxied
|
|
2608
|
+
return totalUsage;
|
|
2609
|
+
},
|
|
2610
|
+
};
|
|
2611
|
+
if (llmTools.callChatModel !== undefined) {
|
|
2612
|
+
proxyTools.callChatModel = async (prompt) => {
|
|
2613
|
+
// console.info('[🚕] callChatModel through countTotalUsage');
|
|
2614
|
+
const promptResult = await llmTools.callChatModel(prompt);
|
|
2615
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2616
|
+
spending.next(promptResult.usage);
|
|
2617
|
+
return promptResult;
|
|
2618
|
+
};
|
|
2168
2619
|
}
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2620
|
+
if (llmTools.callCompletionModel !== undefined) {
|
|
2621
|
+
proxyTools.callCompletionModel = async (prompt) => {
|
|
2622
|
+
// console.info('[🚕] callCompletionModel through countTotalUsage');
|
|
2623
|
+
const promptResult = await llmTools.callCompletionModel(prompt);
|
|
2624
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2625
|
+
spending.next(promptResult.usage);
|
|
2626
|
+
return promptResult;
|
|
2627
|
+
};
|
|
2174
2628
|
}
|
|
2175
|
-
|
|
2176
|
-
|
|
2629
|
+
if (llmTools.callEmbeddingModel !== undefined) {
|
|
2630
|
+
proxyTools.callEmbeddingModel = async (prompt) => {
|
|
2631
|
+
// console.info('[🚕] callEmbeddingModel through countTotalUsage');
|
|
2632
|
+
const promptResult = await llmTools.callEmbeddingModel(prompt);
|
|
2633
|
+
totalUsage = addUsage(totalUsage, promptResult.usage);
|
|
2634
|
+
spending.next(promptResult.usage);
|
|
2635
|
+
return promptResult;
|
|
2636
|
+
};
|
|
2177
2637
|
}
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2638
|
+
// <- Note: [🤖]
|
|
2639
|
+
return proxyTools;
|
|
2640
|
+
}
|
|
2641
|
+
/**
|
|
2642
|
+
* TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
|
|
2643
|
+
* TODO: [🧠] Is there some meaningfull way how to test this util
|
|
2644
|
+
* TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
|
|
2645
|
+
* > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
|
|
2646
|
+
* TODO: [👷♂️] @@@ Manual about construction of llmTools
|
|
2647
|
+
*/
|
|
2648
|
+
|
|
2649
|
+
/**
|
|
2650
|
+
* Determines if the given path is a root path.
|
|
2651
|
+
*
|
|
2652
|
+
* Note: This does not check if the file exists only if the path is valid
|
|
2653
|
+
* @public exported from `@promptbook/utils`
|
|
2654
|
+
*/
|
|
2655
|
+
function isRootPath(value) {
|
|
2656
|
+
if (value === '/') {
|
|
2657
|
+
return true;
|
|
2185
2658
|
}
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
${morePieces.join('; ')}
|
|
2189
|
-
`);
|
|
2190
|
-
if ($isRunningInNode) {
|
|
2191
|
-
if (isInstalled && isFullyConfigured) {
|
|
2192
|
-
providerMessage = colors__default["default"].green(providerMessage);
|
|
2193
|
-
}
|
|
2194
|
-
else if (isInstalled && isPartiallyConfigured) {
|
|
2195
|
-
providerMessage = colors__default["default"].yellow(providerMessage);
|
|
2196
|
-
}
|
|
2197
|
-
else {
|
|
2198
|
-
providerMessage = colors__default["default"].gray(providerMessage);
|
|
2199
|
-
}
|
|
2659
|
+
if (/^[A-Z]:\\$/i.test(value)) {
|
|
2660
|
+
return true;
|
|
2200
2661
|
}
|
|
2201
|
-
return
|
|
2202
|
-
})
|
|
2203
|
-
.join('\n'))}
|
|
2204
|
-
`);
|
|
2662
|
+
return false;
|
|
2205
2663
|
}
|
|
2206
2664
|
/**
|
|
2207
|
-
* TODO: [
|
|
2208
|
-
* TODO: [🧠][⚛] Maybe pass env as argument
|
|
2665
|
+
* TODO: [🍏] Make for MacOS paths
|
|
2209
2666
|
*/
|
|
2210
2667
|
|
|
2211
2668
|
/**
|
|
@@ -2568,10 +3025,33 @@
|
|
|
2568
3025
|
if (!$isRunningInNode()) {
|
|
2569
3026
|
throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
|
|
2570
3027
|
}
|
|
2571
|
-
|
|
3028
|
+
options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
|
|
3029
|
+
const { strategy, isCacheReloaded } = options;
|
|
3030
|
+
let llmExecutionTools;
|
|
3031
|
+
if (strategy === 'REMOTE_SERVER') {
|
|
3032
|
+
const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
|
|
3033
|
+
const storage = new MemoryStorage(); // <- TODO: !!!!!! Save to `.promptbook` folder
|
|
3034
|
+
const key = `${remoteServerUrl}-identification`;
|
|
3035
|
+
let identification = await storage.getItem(key);
|
|
3036
|
+
if (identification === null) {
|
|
3037
|
+
identification = await loginPrompt();
|
|
3038
|
+
await storage.setItem(key, identification);
|
|
3039
|
+
}
|
|
3040
|
+
llmExecutionTools = new RemoteLlmExecutionTools({
|
|
3041
|
+
remoteServerUrl,
|
|
3042
|
+
identification,
|
|
3043
|
+
});
|
|
3044
|
+
}
|
|
3045
|
+
else if (strategy === 'BRING_YOUR_OWN_KEYS') {
|
|
3046
|
+
llmExecutionTools = await $provideLlmToolsFromEnv();
|
|
3047
|
+
}
|
|
3048
|
+
else {
|
|
3049
|
+
throw new UnexpectedError(`\`$provideLlmToolsForWizzardOrCli\` wrong strategy "${strategy}"`);
|
|
3050
|
+
}
|
|
2572
3051
|
return cacheLlmTools(countUsage(
|
|
3052
|
+
// <- TODO: [🌯] We dont use countUsage at all, maybe just unwrap it
|
|
2573
3053
|
// <- Note: for example here we don`t want the [🌯]
|
|
2574
|
-
|
|
3054
|
+
llmExecutionTools), {
|
|
2575
3055
|
storage: new FileCacheStorage({ fs: $provideFilesystemForNode() }, {
|
|
2576
3056
|
rootFolderPath: path.join(process.cwd(), DEFAULT_EXECUTION_CACHE_DIRNAME),
|
|
2577
3057
|
}),
|
|
@@ -2587,31 +3067,88 @@
|
|
|
2587
3067
|
*/
|
|
2588
3068
|
|
|
2589
3069
|
/**
|
|
2590
|
-
*
|
|
2591
|
-
* No side effects.
|
|
2592
|
-
*
|
|
2593
|
-
* Note: It can be usefull for:
|
|
2594
|
-
*
|
|
2595
|
-
* 1) Suppressing eager optimization of unused imports
|
|
2596
|
-
* 2) Suppressing eslint errors of unused variables in the tests
|
|
2597
|
-
* 3) Keeping the type of the variable for type testing
|
|
2598
|
-
*
|
|
2599
|
-
* @param value any values
|
|
2600
|
-
* @returns void
|
|
2601
|
-
* @private within the repository
|
|
2602
|
-
*/
|
|
2603
|
-
function keepUnused(...valuesToKeep) {
|
|
2604
|
-
}
|
|
2605
|
-
|
|
2606
|
-
/**
|
|
2607
|
-
* Just says that the variable is not used directlys but should be kept because the existence of the variable is important
|
|
2608
|
-
*
|
|
2609
|
-
* @param value any values
|
|
2610
|
-
* @returns void
|
|
2611
|
-
* @private within the repository
|
|
3070
|
+
* @private utility of CLI
|
|
2612
3071
|
*/
|
|
2613
|
-
function $
|
|
2614
|
-
|
|
3072
|
+
function $provideLlmToolsForCli(options) {
|
|
3073
|
+
const { cliOptions: {
|
|
3074
|
+
/* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
|
|
3075
|
+
let strategy;
|
|
3076
|
+
if (/^b/i.test(provider)) {
|
|
3077
|
+
strategy = 'BRING_YOUR_OWN_KEYS';
|
|
3078
|
+
}
|
|
3079
|
+
else if (/^r/i.test(provider)) {
|
|
3080
|
+
strategy = 'REMOTE_SERVER';
|
|
3081
|
+
}
|
|
3082
|
+
else {
|
|
3083
|
+
console.log(colors__default["default"].red(`Unknown provider: "${provider}", please use "BRING_YOUR_OWN_KEYS" or "REMOTE_SERVER"`));
|
|
3084
|
+
process.exit(1);
|
|
3085
|
+
}
|
|
3086
|
+
if (strategy === 'BRING_YOUR_OWN_KEYS') {
|
|
3087
|
+
return /* not await */ $provideLlmToolsForWizzardOrCli({ strategy, ...options });
|
|
3088
|
+
}
|
|
3089
|
+
else if (strategy === 'REMOTE_SERVER') {
|
|
3090
|
+
if (!isValidUrl(remoteServerUrlRaw)) {
|
|
3091
|
+
console.log(colors__default["default"].red(`Invalid URL of remote server: "${remoteServerUrlRaw}"`));
|
|
3092
|
+
process.exit(1);
|
|
3093
|
+
}
|
|
3094
|
+
const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
|
|
3095
|
+
return /* not await */ $provideLlmToolsForWizzardOrCli({
|
|
3096
|
+
strategy,
|
|
3097
|
+
appId: CLI_APP_ID,
|
|
3098
|
+
remoteServerUrl,
|
|
3099
|
+
...options,
|
|
3100
|
+
async loginPrompt() {
|
|
3101
|
+
if (!isInteractive) {
|
|
3102
|
+
console.log(colors__default["default"].red(`You can not login to remote server in non-interactive mode`));
|
|
3103
|
+
process.exit(1);
|
|
3104
|
+
}
|
|
3105
|
+
const { username, password } = await prompts__default["default"]([
|
|
3106
|
+
{
|
|
3107
|
+
type: 'text',
|
|
3108
|
+
name: 'username',
|
|
3109
|
+
message: 'Enter your email:',
|
|
3110
|
+
validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
|
|
3111
|
+
},
|
|
3112
|
+
{
|
|
3113
|
+
type: 'password',
|
|
3114
|
+
name: 'password',
|
|
3115
|
+
message: 'Enter your password:',
|
|
3116
|
+
validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0
|
|
3117
|
+
? true
|
|
3118
|
+
: 'Password is required',
|
|
3119
|
+
},
|
|
3120
|
+
]);
|
|
3121
|
+
const loginUrl = `${remoteServerUrl}/login`;
|
|
3122
|
+
const response = await fetch(loginUrl, {
|
|
3123
|
+
method: 'POST',
|
|
3124
|
+
headers: {
|
|
3125
|
+
'Content-Type': 'application/json',
|
|
3126
|
+
},
|
|
3127
|
+
body: JSON.stringify({
|
|
3128
|
+
appId: CLI_APP_ID,
|
|
3129
|
+
username,
|
|
3130
|
+
password,
|
|
3131
|
+
}),
|
|
3132
|
+
});
|
|
3133
|
+
console.log('!!!', {
|
|
3134
|
+
loginUrl,
|
|
3135
|
+
username,
|
|
3136
|
+
password,
|
|
3137
|
+
// type: response.type,
|
|
3138
|
+
// text: await response.text(),
|
|
3139
|
+
});
|
|
3140
|
+
const body = (await response.json());
|
|
3141
|
+
if ('error' in body) {
|
|
3142
|
+
console.log(colors__default["default"].red(body.error.message));
|
|
3143
|
+
process.exit(1);
|
|
3144
|
+
}
|
|
3145
|
+
return body.identification;
|
|
3146
|
+
},
|
|
3147
|
+
});
|
|
3148
|
+
}
|
|
3149
|
+
else {
|
|
3150
|
+
throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
|
|
3151
|
+
}
|
|
2615
3152
|
}
|
|
2616
3153
|
|
|
2617
3154
|
/**
|
|
@@ -2628,8 +3165,10 @@
|
|
|
2628
3165
|
`));
|
|
2629
3166
|
listModelsCommand.alias('models');
|
|
2630
3167
|
listModelsCommand.alias('llm');
|
|
2631
|
-
listModelsCommand.action(handleActionErrors(async () => {
|
|
2632
|
-
|
|
3168
|
+
listModelsCommand.action(handleActionErrors(async (cliOptions) => {
|
|
3169
|
+
console.log('!!!', cliOptions);
|
|
3170
|
+
// TODO: !!!!!! Not relevant for remote server and also for `about` command
|
|
3171
|
+
const llm = await $provideLlmToolsForCli({ cliOptions });
|
|
2633
3172
|
$sideEffect(llm);
|
|
2634
3173
|
// <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
|
|
2635
3174
|
console.info($registeredLlmToolsMessage());
|
|
@@ -3189,49 +3728,73 @@
|
|
|
3189
3728
|
*/
|
|
3190
3729
|
|
|
3191
3730
|
/**
|
|
3192
|
-
*
|
|
3731
|
+
* Initializes `login` command for Promptbook CLI utilities
|
|
3193
3732
|
*
|
|
3194
|
-
* Note:
|
|
3733
|
+
* Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI
|
|
3195
3734
|
*
|
|
3196
|
-
* @
|
|
3197
|
-
*/
|
|
3198
|
-
async function collectionToJson(collection) {
|
|
3199
|
-
const pipelineUrls = await collection.listPipelines();
|
|
3200
|
-
const promptbooks = await Promise.all(pipelineUrls.map((url) => collection.getPipelineByUrl(url)));
|
|
3201
|
-
return promptbooks;
|
|
3202
|
-
}
|
|
3203
|
-
/**
|
|
3204
|
-
* TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
|
|
3735
|
+
* @private internal function of `promptbookCli`
|
|
3205
3736
|
*/
|
|
3737
|
+
function $initializeLoginCommand(program) {
|
|
3738
|
+
const loginCommand = program.command('login');
|
|
3739
|
+
loginCommand.description(spaceTrim__default["default"](`
|
|
3740
|
+
Login to the remote Promptbook server
|
|
3741
|
+
`));
|
|
3742
|
+
loginCommand.action(handleActionErrors(async () => {
|
|
3743
|
+
// @@@
|
|
3744
|
+
console.error(colors__default["default"].green(spaceTrim__default["default"](`
|
|
3745
|
+
You will be logged in to https://promptbook.studio server.
|
|
3746
|
+
If you don't have an account, it will be created automatically.
|
|
3747
|
+
`)));
|
|
3748
|
+
// !!!!!!!!! Remove from here and use $provideLlmToolsForCli
|
|
3749
|
+
const { email, password } = await prompts__default["default"]([
|
|
3750
|
+
{
|
|
3751
|
+
type: 'text',
|
|
3752
|
+
name: 'email',
|
|
3753
|
+
message: 'Enter your email:',
|
|
3754
|
+
validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
|
|
3755
|
+
},
|
|
3756
|
+
{
|
|
3757
|
+
type: 'password',
|
|
3758
|
+
name: 'password',
|
|
3759
|
+
message: 'Enter your password:',
|
|
3760
|
+
validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0 ? true : 'Password is required',
|
|
3761
|
+
},
|
|
3762
|
+
]);
|
|
3763
|
+
TODO_USE(email, password);
|
|
3764
|
+
await waitasecond.forTime(1000);
|
|
3765
|
+
console.error(colors__default["default"].green(spaceTrim__default["default"](`
|
|
3766
|
+
Your account ${email} was successfully created.
|
|
3206
3767
|
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3211
|
-
|
|
3212
|
-
|
|
3213
|
-
|
|
3214
|
-
super(message);
|
|
3215
|
-
this.name = 'ParseError';
|
|
3216
|
-
Object.setPrototypeOf(this, ParseError.prototype);
|
|
3217
|
-
}
|
|
3768
|
+
Please verify your email:
|
|
3769
|
+
https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
|
|
3770
|
+
|
|
3771
|
+
After verification, you will receive 500 000 credits for free 🎉
|
|
3772
|
+
`)));
|
|
3773
|
+
return process.exit(0);
|
|
3774
|
+
}));
|
|
3218
3775
|
}
|
|
3219
3776
|
/**
|
|
3220
|
-
* TODO:
|
|
3777
|
+
* TODO: Pass remote server URL (and path)
|
|
3778
|
+
* TODO: Implement non-interactive login
|
|
3779
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
3780
|
+
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
3221
3781
|
*/
|
|
3222
3782
|
|
|
3223
3783
|
/**
|
|
3224
|
-
*
|
|
3784
|
+
* Converts PipelineCollection to serialized JSON
|
|
3785
|
+
*
|
|
3786
|
+
* Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
|
|
3225
3787
|
*
|
|
3226
3788
|
* @public exported from `@promptbook/core`
|
|
3227
3789
|
*/
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
Object.setPrototypeOf(this, PipelineLogicError.prototype);
|
|
3233
|
-
}
|
|
3790
|
+
async function collectionToJson(collection) {
|
|
3791
|
+
const pipelineUrls = await collection.listPipelines();
|
|
3792
|
+
const promptbooks = await Promise.all(pipelineUrls.map((url) => collection.getPipelineByUrl(url)));
|
|
3793
|
+
return promptbooks;
|
|
3234
3794
|
}
|
|
3795
|
+
/**
|
|
3796
|
+
* TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
|
|
3797
|
+
*/
|
|
3235
3798
|
|
|
3236
3799
|
/**
|
|
3237
3800
|
* Tests if given string is valid semantic version
|
|
@@ -3629,21 +4192,6 @@
|
|
|
3629
4192
|
|
|
3630
4193
|
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"}];
|
|
3631
4194
|
|
|
3632
|
-
/**
|
|
3633
|
-
* Checks if value is valid email
|
|
3634
|
-
*
|
|
3635
|
-
* @public exported from `@promptbook/utils`
|
|
3636
|
-
*/
|
|
3637
|
-
function isValidEmail(email) {
|
|
3638
|
-
if (typeof email !== 'string') {
|
|
3639
|
-
return false;
|
|
3640
|
-
}
|
|
3641
|
-
if (email.split('\n').length > 1) {
|
|
3642
|
-
return false;
|
|
3643
|
-
}
|
|
3644
|
-
return /^.+@.+\..+$/.test(email);
|
|
3645
|
-
}
|
|
3646
|
-
|
|
3647
4195
|
/**
|
|
3648
4196
|
* Function isValidJsonString will tell you if the string is valid JSON or not
|
|
3649
4197
|
*
|
|
@@ -3877,32 +4425,6 @@
|
|
|
3877
4425
|
* TODO: [🧠] Should be in generated .book.md file GENERATOR_WARNING
|
|
3878
4426
|
*/
|
|
3879
4427
|
|
|
3880
|
-
/**
|
|
3881
|
-
* This error indicates that promptbook not found in the collection
|
|
3882
|
-
*
|
|
3883
|
-
* @public exported from `@promptbook/core`
|
|
3884
|
-
*/
|
|
3885
|
-
class NotFoundError extends Error {
|
|
3886
|
-
constructor(message) {
|
|
3887
|
-
super(message);
|
|
3888
|
-
this.name = 'NotFoundError';
|
|
3889
|
-
Object.setPrototypeOf(this, NotFoundError.prototype);
|
|
3890
|
-
}
|
|
3891
|
-
}
|
|
3892
|
-
|
|
3893
|
-
/**
|
|
3894
|
-
* This error indicates errors in referencing promptbooks between each other
|
|
3895
|
-
*
|
|
3896
|
-
* @public exported from `@promptbook/core`
|
|
3897
|
-
*/
|
|
3898
|
-
class PipelineUrlError extends Error {
|
|
3899
|
-
constructor(message) {
|
|
3900
|
-
super(message);
|
|
3901
|
-
this.name = 'PipelineUrlError';
|
|
3902
|
-
Object.setPrototypeOf(this, PipelineUrlError.prototype);
|
|
3903
|
-
}
|
|
3904
|
-
}
|
|
3905
|
-
|
|
3906
4428
|
/**
|
|
3907
4429
|
* Parses the task and returns the list of all parameter names
|
|
3908
4430
|
*
|
|
@@ -4073,24 +4595,6 @@
|
|
|
4073
4595
|
return new SimplePipelineCollection(...promptbooks);
|
|
4074
4596
|
}
|
|
4075
4597
|
|
|
4076
|
-
/**
|
|
4077
|
-
* This error type indicates that some tools are missing for pipeline execution or preparation
|
|
4078
|
-
*
|
|
4079
|
-
* @public exported from `@promptbook/core`
|
|
4080
|
-
*/
|
|
4081
|
-
class MissingToolsError extends Error {
|
|
4082
|
-
constructor(message) {
|
|
4083
|
-
super(spaceTrim.spaceTrim((block) => `
|
|
4084
|
-
${block(message)}
|
|
4085
|
-
|
|
4086
|
-
Note: You have probbably forgot to provide some tools for pipeline execution or preparation
|
|
4087
|
-
|
|
4088
|
-
`));
|
|
4089
|
-
this.name = 'MissingToolsError';
|
|
4090
|
-
Object.setPrototypeOf(this, MissingToolsError.prototype);
|
|
4091
|
-
}
|
|
4092
|
-
}
|
|
4093
|
-
|
|
4094
4598
|
/**
|
|
4095
4599
|
* Determine if the pipeline is fully prepared
|
|
4096
4600
|
*
|
|
@@ -4123,210 +4627,40 @@
|
|
|
4123
4627
|
* TODO: [🐠] Maybe base this on `makeValidator`
|
|
4124
4628
|
* TODO: [🧊] Pipeline can be partially prepared, this should return true ONLY if fully prepared
|
|
4125
4629
|
* TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
|
|
4126
|
-
* - [🏍] ? Is context in each task
|
|
4127
|
-
* - [♨] Are examples prepared
|
|
4128
|
-
* - [♨] Are tasks prepared
|
|
4129
|
-
*/
|
|
4130
|
-
|
|
4131
|
-
/**
|
|
4132
|
-
* Recursively converts JSON strings to JSON objects
|
|
4133
|
-
|
|
4134
|
-
* @public exported from `@promptbook/utils`
|
|
4135
|
-
*/
|
|
4136
|
-
function jsonStringsToJsons(object) {
|
|
4137
|
-
if (object === null) {
|
|
4138
|
-
return object;
|
|
4139
|
-
}
|
|
4140
|
-
if (Array.isArray(object)) {
|
|
4141
|
-
return object.map(jsonStringsToJsons);
|
|
4142
|
-
}
|
|
4143
|
-
if (typeof object !== 'object') {
|
|
4144
|
-
return object;
|
|
4145
|
-
}
|
|
4146
|
-
const newObject = { ...object };
|
|
4147
|
-
for (const [key, value] of Object.entries(object)) {
|
|
4148
|
-
if (typeof value === 'string' && isValidJsonString(value)) {
|
|
4149
|
-
newObject[key] = JSON.parse(value);
|
|
4150
|
-
}
|
|
4151
|
-
else {
|
|
4152
|
-
newObject[key] = jsonStringsToJsons(value);
|
|
4153
|
-
}
|
|
4154
|
-
}
|
|
4155
|
-
return newObject;
|
|
4156
|
-
}
|
|
4157
|
-
/**
|
|
4158
|
-
* TODO: Type the return type correctly
|
|
4159
|
-
*/
|
|
4160
|
-
|
|
4161
|
-
/**
|
|
4162
|
-
* This error indicates problems parsing the format value
|
|
4163
|
-
*
|
|
4164
|
-
* For example, when the format value is not a valid JSON or CSV
|
|
4165
|
-
* This is not thrown directly but in extended classes
|
|
4166
|
-
*
|
|
4167
|
-
* @public exported from `@promptbook/core`
|
|
4168
|
-
*/
|
|
4169
|
-
class AbstractFormatError extends Error {
|
|
4170
|
-
// Note: To allow instanceof do not put here error `name`
|
|
4171
|
-
// public readonly name = 'AbstractFormatError';
|
|
4172
|
-
constructor(message) {
|
|
4173
|
-
super(message);
|
|
4174
|
-
Object.setPrototypeOf(this, AbstractFormatError.prototype);
|
|
4175
|
-
}
|
|
4176
|
-
}
|
|
4177
|
-
|
|
4178
|
-
/**
|
|
4179
|
-
* This error indicates problem with parsing of CSV
|
|
4180
|
-
*
|
|
4181
|
-
* @public exported from `@promptbook/core`
|
|
4182
|
-
*/
|
|
4183
|
-
class CsvFormatError extends AbstractFormatError {
|
|
4184
|
-
constructor(message) {
|
|
4185
|
-
super(message);
|
|
4186
|
-
this.name = 'CsvFormatError';
|
|
4187
|
-
Object.setPrototypeOf(this, CsvFormatError.prototype);
|
|
4188
|
-
}
|
|
4189
|
-
}
|
|
4190
|
-
|
|
4191
|
-
/**
|
|
4192
|
-
* This error indicates that the pipeline collection cannot be propperly loaded
|
|
4193
|
-
*
|
|
4194
|
-
* @public exported from `@promptbook/core`
|
|
4195
|
-
*/
|
|
4196
|
-
class CollectionError extends Error {
|
|
4197
|
-
constructor(message) {
|
|
4198
|
-
super(message);
|
|
4199
|
-
this.name = 'CollectionError';
|
|
4200
|
-
Object.setPrototypeOf(this, CollectionError.prototype);
|
|
4201
|
-
}
|
|
4202
|
-
}
|
|
4203
|
-
|
|
4204
|
-
/**
|
|
4205
|
-
* This error occurs when some expectation is not met in the execution of the pipeline
|
|
4206
|
-
*
|
|
4207
|
-
* @public exported from `@promptbook/core`
|
|
4208
|
-
* Note: Do not throw this error, its reserved for `checkExpectations` and `createPipelineExecutor` and public ONLY to be serializable through remote server
|
|
4209
|
-
* Note: Always thrown in `checkExpectations` and catched in `createPipelineExecutor` and rethrown as `PipelineExecutionError`
|
|
4210
|
-
* Note: This is a kindof subtype of PipelineExecutionError
|
|
4211
|
-
*/
|
|
4212
|
-
class ExpectError extends Error {
|
|
4213
|
-
constructor(message) {
|
|
4214
|
-
super(message);
|
|
4215
|
-
this.name = 'ExpectError';
|
|
4216
|
-
Object.setPrototypeOf(this, ExpectError.prototype);
|
|
4217
|
-
}
|
|
4218
|
-
}
|
|
4219
|
-
|
|
4220
|
-
/**
|
|
4221
|
-
* This error indicates that the promptbook can not retrieve knowledge from external sources
|
|
4222
|
-
*
|
|
4223
|
-
* @public exported from `@promptbook/core`
|
|
4224
|
-
*/
|
|
4225
|
-
class KnowledgeScrapeError extends Error {
|
|
4226
|
-
constructor(message) {
|
|
4227
|
-
super(message);
|
|
4228
|
-
this.name = 'KnowledgeScrapeError';
|
|
4229
|
-
Object.setPrototypeOf(this, KnowledgeScrapeError.prototype);
|
|
4230
|
-
}
|
|
4231
|
-
}
|
|
4232
|
-
|
|
4233
|
-
/**
|
|
4234
|
-
* This error type indicates that some limit was reached
|
|
4235
|
-
*
|
|
4236
|
-
* @public exported from `@promptbook/core`
|
|
4237
|
-
*/
|
|
4238
|
-
class LimitReachedError extends Error {
|
|
4239
|
-
constructor(message) {
|
|
4240
|
-
super(message);
|
|
4241
|
-
this.name = 'LimitReachedError';
|
|
4242
|
-
Object.setPrototypeOf(this, LimitReachedError.prototype);
|
|
4243
|
-
}
|
|
4244
|
-
}
|
|
4245
|
-
|
|
4246
|
-
/**
|
|
4247
|
-
* Index of all custom errors
|
|
4248
|
-
*
|
|
4249
|
-
* @public exported from `@promptbook/core`
|
|
4250
|
-
*/
|
|
4251
|
-
const PROMPTBOOK_ERRORS = {
|
|
4252
|
-
AbstractFormatError,
|
|
4253
|
-
CsvFormatError,
|
|
4254
|
-
CollectionError,
|
|
4255
|
-
EnvironmentMismatchError,
|
|
4256
|
-
ExpectError,
|
|
4257
|
-
KnowledgeScrapeError,
|
|
4258
|
-
LimitReachedError,
|
|
4259
|
-
MissingToolsError,
|
|
4260
|
-
NotFoundError,
|
|
4261
|
-
NotYetImplementedError,
|
|
4262
|
-
ParseError,
|
|
4263
|
-
PipelineExecutionError,
|
|
4264
|
-
PipelineLogicError,
|
|
4265
|
-
PipelineUrlError,
|
|
4266
|
-
UnexpectedError,
|
|
4267
|
-
// TODO: [🪑]> VersionMismatchError,
|
|
4268
|
-
};
|
|
4269
|
-
/**
|
|
4270
|
-
* Index of all javascript errors
|
|
4271
|
-
*
|
|
4272
|
-
* @private for internal usage
|
|
4273
|
-
*/
|
|
4274
|
-
const COMMON_JAVASCRIPT_ERRORS = {
|
|
4275
|
-
Error,
|
|
4276
|
-
EvalError,
|
|
4277
|
-
RangeError,
|
|
4278
|
-
ReferenceError,
|
|
4279
|
-
SyntaxError,
|
|
4280
|
-
TypeError,
|
|
4281
|
-
URIError,
|
|
4282
|
-
AggregateError,
|
|
4283
|
-
/*
|
|
4284
|
-
Note: Not widely supported
|
|
4285
|
-
> InternalError,
|
|
4286
|
-
> ModuleError,
|
|
4287
|
-
> HeapError,
|
|
4288
|
-
> WebAssemblyCompileError,
|
|
4289
|
-
> WebAssemblyRuntimeError,
|
|
4290
|
-
*/
|
|
4291
|
-
};
|
|
4292
|
-
/**
|
|
4293
|
-
* Index of all errors
|
|
4294
|
-
*
|
|
4295
|
-
* @private for internal usage
|
|
4296
|
-
*/
|
|
4297
|
-
const ALL_ERRORS = {
|
|
4298
|
-
...PROMPTBOOK_ERRORS,
|
|
4299
|
-
...COMMON_JAVASCRIPT_ERRORS,
|
|
4300
|
-
};
|
|
4301
|
-
/**
|
|
4302
|
-
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
4303
|
-
*/
|
|
4304
|
-
|
|
4305
|
-
/**
|
|
4306
|
-
* Deserializes the error object
|
|
4307
|
-
*
|
|
4308
|
-
* @public exported from `@promptbook/utils`
|
|
4309
|
-
*/
|
|
4310
|
-
function deserializeError(error) {
|
|
4311
|
-
const { name, stack, id } = error; // Added id
|
|
4312
|
-
let { message } = error;
|
|
4313
|
-
let ErrorClass = ALL_ERRORS[error.name];
|
|
4314
|
-
if (ErrorClass === undefined) {
|
|
4315
|
-
ErrorClass = Error;
|
|
4316
|
-
message = `${name}: ${message}`;
|
|
4317
|
-
}
|
|
4318
|
-
if (stack !== undefined && stack !== '') {
|
|
4319
|
-
message = spaceTrim__default["default"]((block) => `
|
|
4320
|
-
${block(message)}
|
|
4630
|
+
* - [🏍] ? Is context in each task
|
|
4631
|
+
* - [♨] Are examples prepared
|
|
4632
|
+
* - [♨] Are tasks prepared
|
|
4633
|
+
*/
|
|
4321
4634
|
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4635
|
+
/**
|
|
4636
|
+
* Recursively converts JSON strings to JSON objects
|
|
4637
|
+
|
|
4638
|
+
* @public exported from `@promptbook/utils`
|
|
4639
|
+
*/
|
|
4640
|
+
function jsonStringsToJsons(object) {
|
|
4641
|
+
if (object === null) {
|
|
4642
|
+
return object;
|
|
4325
4643
|
}
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
|
|
4644
|
+
if (Array.isArray(object)) {
|
|
4645
|
+
return object.map(jsonStringsToJsons);
|
|
4646
|
+
}
|
|
4647
|
+
if (typeof object !== 'object') {
|
|
4648
|
+
return object;
|
|
4649
|
+
}
|
|
4650
|
+
const newObject = { ...object };
|
|
4651
|
+
for (const [key, value] of Object.entries(object)) {
|
|
4652
|
+
if (typeof value === 'string' && isValidJsonString(value)) {
|
|
4653
|
+
newObject[key] = JSON.parse(value);
|
|
4654
|
+
}
|
|
4655
|
+
else {
|
|
4656
|
+
newObject[key] = jsonStringsToJsons(value);
|
|
4657
|
+
}
|
|
4658
|
+
}
|
|
4659
|
+
return newObject;
|
|
4329
4660
|
}
|
|
4661
|
+
/**
|
|
4662
|
+
* TODO: Type the return type correctly
|
|
4663
|
+
*/
|
|
4330
4664
|
|
|
4331
4665
|
/**
|
|
4332
4666
|
* Asserts that the execution of a Promptbook is successful
|
|
@@ -4479,6 +4813,10 @@
|
|
|
4479
4813
|
|
|
4480
4814
|
Cannot serialize error with name "${name}"
|
|
4481
4815
|
|
|
4816
|
+
Authors of Promptbook probably forgot to add this error into the list of errors:
|
|
4817
|
+
https://github.com/webgptorg/promptbook/blob/main/src/errors/0-index.ts
|
|
4818
|
+
|
|
4819
|
+
|
|
4482
4820
|
${block(stack || message)}
|
|
4483
4821
|
|
|
4484
4822
|
`));
|
|
@@ -11389,7 +11727,6 @@
|
|
|
11389
11727
|
makeCommand.option('--no-validation', `Do not validate logic of pipelines in collection`, true);
|
|
11390
11728
|
makeCommand.option('--validation', `Types of validations separated by comma (options "logic","imports")`, 'logic,imports');
|
|
11391
11729
|
makeCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
|
|
11392
|
-
makeCommand.option('-v, --verbose', `Is output verbose`, false);
|
|
11393
11730
|
makeCommand.option('-o, --output <path>', spaceTrim__default["default"](`
|
|
11394
11731
|
Where to save the builded collection
|
|
11395
11732
|
|
|
@@ -11403,7 +11740,8 @@
|
|
|
11403
11740
|
Note: This can be used only with "javascript" or "typescript" format
|
|
11404
11741
|
|
|
11405
11742
|
`), DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME);
|
|
11406
|
-
makeCommand.action(handleActionErrors(async (path$1,
|
|
11743
|
+
makeCommand.action(handleActionErrors(async (path$1, cliOptions) => {
|
|
11744
|
+
const { projectName, rootUrl, format, functionName, validation, reload: isCacheReloaded, verbose: isVerbose, output, } = cliOptions;
|
|
11407
11745
|
if (!isValidJavascriptName(functionName)) {
|
|
11408
11746
|
console.error(colors__default["default"].red(`Function name "${functionName}" is not valid javascript name`));
|
|
11409
11747
|
return process.exit(1);
|
|
@@ -11431,7 +11769,10 @@
|
|
|
11431
11769
|
isCacheReloaded,
|
|
11432
11770
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
11433
11771
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
11434
|
-
const llm = await $
|
|
11772
|
+
const llm = await $provideLlmToolsForCli({
|
|
11773
|
+
cliOptions,
|
|
11774
|
+
...prepareAndScrapeOptions,
|
|
11775
|
+
});
|
|
11435
11776
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
11436
11777
|
const tools = {
|
|
11437
11778
|
llm,
|
|
@@ -11699,8 +12040,8 @@
|
|
|
11699
12040
|
// <- TODO: [🧟♂️] Unite path to promptbook collection argument
|
|
11700
12041
|
'Pipelines to prettify as glob pattern');
|
|
11701
12042
|
prettifyCommand.option('-i, --ignore <glob>', `Ignore as glob pattern`);
|
|
11702
|
-
prettifyCommand.
|
|
11703
|
-
|
|
12043
|
+
prettifyCommand.action(handleActionErrors(async (filesGlob, cliOptions) => {
|
|
12044
|
+
const { ignore, verbose: isVerbose } = cliOptions;
|
|
11704
12045
|
const filenames = await glob__default["default"](filesGlob, { ignore });
|
|
11705
12046
|
// <- TODO: [😶]
|
|
11706
12047
|
for (const filename of filenames) {
|
|
@@ -12301,13 +12642,12 @@
|
|
|
12301
12642
|
// TODO: [🧅] DRY command arguments
|
|
12302
12643
|
runCommand.argument('[pipelineSource]', 'Path to book file OR URL to book file, if not provided it will be asked');
|
|
12303
12644
|
runCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
|
|
12304
|
-
runCommand.option('-v, --verbose', `Is output verbose`, false);
|
|
12305
|
-
runCommand.option('--no-interactive', `Input is not interactive, if true you need to pass all the input parameters through --json`);
|
|
12306
12645
|
runCommand.option('--no-formfactor', `When set, behavior of the interactive mode is not changed by the formfactor of the pipeline`);
|
|
12307
12646
|
runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
|
|
12308
12647
|
runCommand.option('-s, --save-report <path>', `Save report to file`);
|
|
12309
|
-
runCommand.action(handleActionErrors(async (pipelineSource,
|
|
12310
|
-
|
|
12648
|
+
runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
|
|
12649
|
+
console.log('!!!', cliOptions);
|
|
12650
|
+
const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
|
|
12311
12651
|
if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
|
|
12312
12652
|
console.error(colors__default["default"].red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
|
|
12313
12653
|
return process.exit(1);
|
|
@@ -12332,7 +12672,7 @@
|
|
|
12332
12672
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
12333
12673
|
let llm;
|
|
12334
12674
|
try {
|
|
12335
|
-
llm = await $
|
|
12675
|
+
llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
12336
12676
|
}
|
|
12337
12677
|
catch (error) {
|
|
12338
12678
|
if (!(error instanceof Error)) {
|
|
@@ -12389,7 +12729,7 @@
|
|
|
12389
12729
|
fs,
|
|
12390
12730
|
fetch: scraperFetch,
|
|
12391
12731
|
scrapers: await $provideScrapersForNode({ fs, llm, executables }, prepareAndScrapeOptions),
|
|
12392
|
-
script: [new JavascriptExecutionTools(
|
|
12732
|
+
script: [new JavascriptExecutionTools(cliOptions)],
|
|
12393
12733
|
};
|
|
12394
12734
|
if (isVerbose) {
|
|
12395
12735
|
console.info(colors__default["default"].gray('--- Getting the book ---'));
|
|
@@ -12553,11 +12893,12 @@
|
|
|
12553
12893
|
* @public exported from `@promptbook/remote-server`
|
|
12554
12894
|
*/
|
|
12555
12895
|
function startRemoteServer(options) {
|
|
12556
|
-
const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, } = {
|
|
12896
|
+
const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
|
|
12557
12897
|
isAnonymousModeAllowed: false,
|
|
12558
12898
|
isApplicationModeAllowed: false,
|
|
12559
12899
|
collection: null,
|
|
12560
12900
|
createLlmExecutionTools: null,
|
|
12901
|
+
login: null,
|
|
12561
12902
|
...options,
|
|
12562
12903
|
};
|
|
12563
12904
|
// <- TODO: [🦪] Some helper type to be able to use discriminant union types with destructuring
|
|
@@ -12624,9 +12965,38 @@
|
|
|
12624
12965
|
response.setHeader('X-Powered-By', 'Promptbook engine');
|
|
12625
12966
|
next();
|
|
12626
12967
|
});
|
|
12968
|
+
const swaggerOptions = {
|
|
12969
|
+
definition: {
|
|
12970
|
+
openapi: '3.0.0',
|
|
12971
|
+
info: {
|
|
12972
|
+
title: 'Promptbook Remote Server API',
|
|
12973
|
+
version: '1.0.0',
|
|
12974
|
+
description: 'API documentation for the Promptbook Remote Server',
|
|
12975
|
+
},
|
|
12976
|
+
servers: [
|
|
12977
|
+
{
|
|
12978
|
+
url: `http://localhost:${port}${rootPath}`,
|
|
12979
|
+
// <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
|
|
12980
|
+
},
|
|
12981
|
+
],
|
|
12982
|
+
},
|
|
12983
|
+
apis: ['./src/remote-server/**/*.ts'], // Adjust path as needed
|
|
12984
|
+
};
|
|
12985
|
+
const swaggerSpec = swaggerJsdoc__default["default"](swaggerOptions);
|
|
12986
|
+
app.use([`/api-docs`, `${rootPath}/api-docs`], swaggerUi__default["default"].serve, swaggerUi__default["default"].setup(swaggerSpec));
|
|
12627
12987
|
const runningExecutionTasks = [];
|
|
12628
12988
|
// <- TODO: [🤬] Identify the users
|
|
12629
12989
|
// TODO: [🧠] Do here some garbage collection of finished tasks
|
|
12990
|
+
/**
|
|
12991
|
+
* @swagger
|
|
12992
|
+
* /:
|
|
12993
|
+
* get:
|
|
12994
|
+
* summary: Get server details
|
|
12995
|
+
* description: Returns details about the Promptbook server.
|
|
12996
|
+
* responses:
|
|
12997
|
+
* 200:
|
|
12998
|
+
* description: Server details in markdown format.
|
|
12999
|
+
*/
|
|
12630
13000
|
app.get(['/', rootPath], async (request, response) => {
|
|
12631
13001
|
var _a;
|
|
12632
13002
|
if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
|
|
@@ -12663,9 +13033,12 @@
|
|
|
12663
13033
|
|
|
12664
13034
|
## Paths
|
|
12665
13035
|
|
|
12666
|
-
${block(
|
|
12667
|
-
.
|
|
12668
|
-
|
|
13036
|
+
${block([
|
|
13037
|
+
...app._router.stack
|
|
13038
|
+
.map(({ route }) => (route === null || route === void 0 ? void 0 : route.path) || null)
|
|
13039
|
+
.filter((path) => path !== null),
|
|
13040
|
+
'/api-docs',
|
|
13041
|
+
]
|
|
12669
13042
|
.map((path) => `- ${path}`)
|
|
12670
13043
|
.join('\n'))}
|
|
12671
13044
|
|
|
@@ -12683,8 +13056,81 @@
|
|
|
12683
13056
|
https://github.com/webgptorg/promptbook
|
|
12684
13057
|
`));
|
|
12685
13058
|
});
|
|
12686
|
-
|
|
12687
|
-
|
|
13059
|
+
/**
|
|
13060
|
+
* @swagger
|
|
13061
|
+
*
|
|
13062
|
+
* /login:
|
|
13063
|
+
* post:
|
|
13064
|
+
* summary: Login to the server
|
|
13065
|
+
* description: Login to the server and get identification.
|
|
13066
|
+
* requestBody:
|
|
13067
|
+
* required: true
|
|
13068
|
+
* content:
|
|
13069
|
+
* application/json:
|
|
13070
|
+
* schema:
|
|
13071
|
+
* type: object
|
|
13072
|
+
* properties:
|
|
13073
|
+
* username:
|
|
13074
|
+
* type: string
|
|
13075
|
+
* password:
|
|
13076
|
+
* type: string
|
|
13077
|
+
* appId:
|
|
13078
|
+
* type: string
|
|
13079
|
+
* responses:
|
|
13080
|
+
* 200:
|
|
13081
|
+
* description: Successful login
|
|
13082
|
+
* content:
|
|
13083
|
+
* application/json:
|
|
13084
|
+
* schema:
|
|
13085
|
+
* type: object
|
|
13086
|
+
* properties:
|
|
13087
|
+
* identification:
|
|
13088
|
+
* type: object
|
|
13089
|
+
*/
|
|
13090
|
+
app.post([`/login`, `${rootPath}/login`], async (request, response) => {
|
|
13091
|
+
if (!isApplicationModeAllowed || login === null) {
|
|
13092
|
+
response.status(400).send('Application mode is not allowed');
|
|
13093
|
+
return;
|
|
13094
|
+
}
|
|
13095
|
+
try {
|
|
13096
|
+
const username = request.body.username;
|
|
13097
|
+
const password = request.body.password;
|
|
13098
|
+
const appId = request.body.appId;
|
|
13099
|
+
const identification = await login({ username, password, appId });
|
|
13100
|
+
response.status(201).send({ identification });
|
|
13101
|
+
return;
|
|
13102
|
+
}
|
|
13103
|
+
catch (error) {
|
|
13104
|
+
if (!(error instanceof Error)) {
|
|
13105
|
+
throw error;
|
|
13106
|
+
}
|
|
13107
|
+
if (error instanceof AuthenticationError) {
|
|
13108
|
+
response.status(401).send({ error: serializeError(error) });
|
|
13109
|
+
}
|
|
13110
|
+
console.warn(`Login function thrown different error than AuthenticationError`, {
|
|
13111
|
+
error,
|
|
13112
|
+
serializedError: serializeError(error),
|
|
13113
|
+
});
|
|
13114
|
+
response.status(400).send({ error: serializeError(error) });
|
|
13115
|
+
}
|
|
13116
|
+
});
|
|
13117
|
+
/**
|
|
13118
|
+
* @swagger
|
|
13119
|
+
* /books:
|
|
13120
|
+
* get:
|
|
13121
|
+
* summary: List all books
|
|
13122
|
+
* description: Returns a list of all available books in the collection.
|
|
13123
|
+
* responses:
|
|
13124
|
+
* 200:
|
|
13125
|
+
* description: A list of books.
|
|
13126
|
+
* content:
|
|
13127
|
+
* application/json:
|
|
13128
|
+
* schema:
|
|
13129
|
+
* type: array
|
|
13130
|
+
* items:
|
|
13131
|
+
* type: string
|
|
13132
|
+
*/
|
|
13133
|
+
app.get([`/books`, `${rootPath}/books`], async (request, response) => {
|
|
12688
13134
|
if (collection === null) {
|
|
12689
13135
|
response.status(500).send('No collection available');
|
|
12690
13136
|
return;
|
|
@@ -12694,7 +13140,30 @@
|
|
|
12694
13140
|
response.send(pipelines);
|
|
12695
13141
|
});
|
|
12696
13142
|
// TODO: [🧠] Is it secure / good idea to expose source codes of hosted books
|
|
12697
|
-
|
|
13143
|
+
/**
|
|
13144
|
+
* @swagger
|
|
13145
|
+
* /books/{bookId}:
|
|
13146
|
+
* get:
|
|
13147
|
+
* summary: Get book content
|
|
13148
|
+
* description: Returns the content of a specific book.
|
|
13149
|
+
* parameters:
|
|
13150
|
+
* - in: path
|
|
13151
|
+
* name: bookId
|
|
13152
|
+
* required: true
|
|
13153
|
+
* schema:
|
|
13154
|
+
* type: string
|
|
13155
|
+
* description: The ID of the book to retrieve.
|
|
13156
|
+
* responses:
|
|
13157
|
+
* 200:
|
|
13158
|
+
* description: The content of the book.
|
|
13159
|
+
* content:
|
|
13160
|
+
* text/markdown:
|
|
13161
|
+
* schema:
|
|
13162
|
+
* type: string
|
|
13163
|
+
* 404:
|
|
13164
|
+
* description: Book not found.
|
|
13165
|
+
*/
|
|
13166
|
+
app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
|
|
12698
13167
|
try {
|
|
12699
13168
|
if (collection === null) {
|
|
12700
13169
|
response.status(500).send('No collection nor books available');
|
|
@@ -12748,10 +13217,26 @@
|
|
|
12748
13217
|
};
|
|
12749
13218
|
}
|
|
12750
13219
|
}
|
|
12751
|
-
|
|
13220
|
+
/**
|
|
13221
|
+
* @swagger
|
|
13222
|
+
* /executions:
|
|
13223
|
+
* get:
|
|
13224
|
+
* summary: List all executions
|
|
13225
|
+
* description: Returns a list of all running execution tasks.
|
|
13226
|
+
* responses:
|
|
13227
|
+
* 200:
|
|
13228
|
+
* description: A list of execution tasks.
|
|
13229
|
+
* content:
|
|
13230
|
+
* application/json:
|
|
13231
|
+
* schema:
|
|
13232
|
+
* type: array
|
|
13233
|
+
* items:
|
|
13234
|
+
* type: object
|
|
13235
|
+
*/
|
|
13236
|
+
app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
|
|
12752
13237
|
response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
|
|
12753
13238
|
});
|
|
12754
|
-
app.get(`${rootPath}/executions/last
|
|
13239
|
+
app.get([`/executions/last`, `${rootPath}/executions/last`], async (request, response) => {
|
|
12755
13240
|
// TODO: [🤬] Filter only for user
|
|
12756
13241
|
if (runningExecutionTasks.length === 0) {
|
|
12757
13242
|
response.status(404).send('No execution tasks found');
|
|
@@ -12760,7 +13245,7 @@
|
|
|
12760
13245
|
const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
|
|
12761
13246
|
response.send(exportExecutionTask(lastExecutionTask, true));
|
|
12762
13247
|
});
|
|
12763
|
-
app.get(`${rootPath}/executions/:taskId
|
|
13248
|
+
app.get([`/executions/:taskId`, `${rootPath}/executions/:taskId`], async (request, response) => {
|
|
12764
13249
|
const { taskId } = request.params;
|
|
12765
13250
|
// TODO: [🤬] Filter only for user
|
|
12766
13251
|
const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
|
|
@@ -12772,7 +13257,36 @@
|
|
|
12772
13257
|
}
|
|
12773
13258
|
response.send(exportExecutionTask(executionTask, true));
|
|
12774
13259
|
});
|
|
12775
|
-
|
|
13260
|
+
/**
|
|
13261
|
+
* @swagger
|
|
13262
|
+
* /executions/new:
|
|
13263
|
+
* post:
|
|
13264
|
+
* summary: Start a new execution
|
|
13265
|
+
* description: Starts a new execution task for a given pipeline.
|
|
13266
|
+
* requestBody:
|
|
13267
|
+
* required: true
|
|
13268
|
+
* content:
|
|
13269
|
+
* application/json:
|
|
13270
|
+
* schema:
|
|
13271
|
+
* type: object
|
|
13272
|
+
* properties:
|
|
13273
|
+
* pipelineUrl:
|
|
13274
|
+
* type: string
|
|
13275
|
+
* inputParameters:
|
|
13276
|
+
* type: object
|
|
13277
|
+
* identification:
|
|
13278
|
+
* type: object
|
|
13279
|
+
* responses:
|
|
13280
|
+
* 200:
|
|
13281
|
+
* description: The newly created execution task.
|
|
13282
|
+
* content:
|
|
13283
|
+
* application/json:
|
|
13284
|
+
* schema:
|
|
13285
|
+
* type: object
|
|
13286
|
+
* 400:
|
|
13287
|
+
* description: Invalid input.
|
|
13288
|
+
*/
|
|
13289
|
+
app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
|
|
12776
13290
|
try {
|
|
12777
13291
|
const { inputParameters, identification /* <- [🤬] */ } = request.body;
|
|
12778
13292
|
const pipelineUrl = request.body.pipelineUrl || request.body.book;
|
|
@@ -13008,12 +13522,12 @@
|
|
|
13008
13522
|
`));
|
|
13009
13523
|
startServerCommand.option('--allow-anonymous', `Is anonymous mode allowed`, false);
|
|
13010
13524
|
startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
|
|
13011
|
-
startServerCommand.option('-v, --verbose', `Is output verbose`, false);
|
|
13012
13525
|
startServerCommand.description(spaceTrim__default["default"](`
|
|
13013
13526
|
Starts a remote server to execute books
|
|
13014
13527
|
`));
|
|
13015
13528
|
startServerCommand.alias('server');
|
|
13016
|
-
startServerCommand.action(handleActionErrors(async (path,
|
|
13529
|
+
startServerCommand.action(handleActionErrors(async (path, cliOptions) => {
|
|
13530
|
+
const { port: portRaw, url: rawUrl, allowAnonymous: isAnonymousModeAllowed, reload: isCacheReloaded, verbose: isVerbose, } = cliOptions;
|
|
13017
13531
|
if (rawUrl && !isValidUrl(rawUrl)) {
|
|
13018
13532
|
console.error(colors__default["default"].red(`Invalid URL: ${rawUrl}`));
|
|
13019
13533
|
return process.exit(1);
|
|
@@ -13042,7 +13556,7 @@
|
|
|
13042
13556
|
isCacheReloaded,
|
|
13043
13557
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
13044
13558
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
13045
|
-
const llm = await $
|
|
13559
|
+
const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13046
13560
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
13047
13561
|
const tools = {
|
|
13048
13562
|
llm,
|
|
@@ -13066,6 +13580,9 @@
|
|
|
13066
13580
|
isAnonymousModeAllowed,
|
|
13067
13581
|
isApplicationModeAllowed: true,
|
|
13068
13582
|
collection,
|
|
13583
|
+
async login() {
|
|
13584
|
+
throw new AuthenticationError('You can not login to the server started by `ptbk start-server` in cli, use `startRemoteServer` function instead.');
|
|
13585
|
+
},
|
|
13069
13586
|
createLlmExecutionTools(options) {
|
|
13070
13587
|
const { appId, userId } = options;
|
|
13071
13588
|
TODO_USE({ appId, userId });
|
|
@@ -13102,8 +13619,8 @@
|
|
|
13102
13619
|
testCommand.option('--no-validation', `Do not validate logic of pipelines in collection`, true);
|
|
13103
13620
|
testCommand.option('--no-prepare', `Do not prepare the pipelines, ideal when no LLM tools or scrapers available`, true);
|
|
13104
13621
|
testCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache `, false);
|
|
13105
|
-
testCommand.
|
|
13106
|
-
|
|
13622
|
+
testCommand.action(handleActionErrors(async (filesGlob, cliOptions) => {
|
|
13623
|
+
const { ignore: ignoreRaw = '', validation: isValidated, prepare: isPrepared, reload: isCacheReloaded, verbose: isVerbose, } = cliOptions;
|
|
13107
13624
|
let tools = undefined;
|
|
13108
13625
|
if (isPrepared) {
|
|
13109
13626
|
// TODO: DRY [◽]
|
|
@@ -13112,7 +13629,7 @@
|
|
|
13112
13629
|
isCacheReloaded,
|
|
13113
13630
|
}; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
|
|
13114
13631
|
const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
|
|
13115
|
-
const llm = await $
|
|
13632
|
+
const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
|
|
13116
13633
|
const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
|
|
13117
13634
|
tools = {
|
|
13118
13635
|
llm,
|
|
@@ -13173,56 +13690,16 @@
|
|
|
13173
13690
|
*/
|
|
13174
13691
|
|
|
13175
13692
|
/**
|
|
13176
|
-
*
|
|
13177
|
-
*
|
|
13178
|
-
* Note: `$` is used to indicate that this function is not a pure function - it registers a command in the CLI
|
|
13693
|
+
* Note: `$` is used to indicate that this function is not a pure function - it registers an option in the CLI
|
|
13179
13694
|
*
|
|
13180
|
-
* @private
|
|
13695
|
+
* @private utility of CLI
|
|
13181
13696
|
*/
|
|
13182
|
-
function $
|
|
13183
|
-
|
|
13184
|
-
|
|
13185
|
-
|
|
13186
|
-
`)
|
|
13187
|
-
loginCommand.action(handleActionErrors(async () => {
|
|
13188
|
-
// @@@
|
|
13189
|
-
console.error(colors__default["default"].green(spaceTrim__default["default"](`
|
|
13190
|
-
You will be logged in to https://promptbook.studio server.
|
|
13191
|
-
If you don't have an account, it will be created automatically.
|
|
13192
|
-
`)));
|
|
13193
|
-
const { email, password } = await prompts__default["default"]([
|
|
13194
|
-
{
|
|
13195
|
-
type: 'text',
|
|
13196
|
-
name: 'email',
|
|
13197
|
-
message: 'Enter your email:',
|
|
13198
|
-
validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
|
|
13199
|
-
},
|
|
13200
|
-
{
|
|
13201
|
-
type: 'password',
|
|
13202
|
-
name: 'password',
|
|
13203
|
-
message: 'Enter your password:',
|
|
13204
|
-
validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0 ? true : 'Password is required',
|
|
13205
|
-
},
|
|
13206
|
-
]);
|
|
13207
|
-
TODO_USE(email, password);
|
|
13208
|
-
await waitasecond.forTime(1000);
|
|
13209
|
-
console.error(colors__default["default"].green(spaceTrim__default["default"](`
|
|
13210
|
-
Your account ${email} was successfully created.
|
|
13211
|
-
|
|
13212
|
-
Please verify your email:
|
|
13213
|
-
https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
|
|
13214
|
-
|
|
13215
|
-
After verification, you will receive 500 000 credits for free 🎉
|
|
13216
|
-
`)));
|
|
13217
|
-
return process.exit(0);
|
|
13218
|
-
}));
|
|
13697
|
+
function $addGlobalOptionsToCommand(command) {
|
|
13698
|
+
command.option('-v, --verbose', `Log more details`, false);
|
|
13699
|
+
command.option('--no-interactive', `Input is not interactive, if true, no CLI input is prompted if required, so either defaults are used or the command fails with exit code 1`);
|
|
13700
|
+
command.option('-p, --provider <provider>', `Which LLM provider to use: "BYOK" / "BRING_YOUR_OWN_KEYS" or "REMOTE_SERVER" / "RS"`, 'REMOTE_SERVER');
|
|
13701
|
+
command.option('--remote-server-url <url>', `URL of remote server to use when `, DEFAULT_REMOTE_SERVER_URL);
|
|
13219
13702
|
}
|
|
13220
|
-
/**
|
|
13221
|
-
* TODO: Pass remote server URL (and path)
|
|
13222
|
-
* TODO: Implement non-interactive login
|
|
13223
|
-
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
13224
|
-
* Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
|
|
13225
|
-
*/
|
|
13226
13703
|
|
|
13227
13704
|
/**
|
|
13228
13705
|
* Runs CLI utilities of Promptbook package
|
|
@@ -13248,6 +13725,7 @@
|
|
|
13248
13725
|
program.alias('ptbk');
|
|
13249
13726
|
program.version(PROMPTBOOK_ENGINE_VERSION);
|
|
13250
13727
|
program.description(CLAIM);
|
|
13728
|
+
// Note: Theese options are valid for all commands
|
|
13251
13729
|
$initializeAboutCommand(program);
|
|
13252
13730
|
$initializeRunCommand(program);
|
|
13253
13731
|
$initializeLoginCommand(program);
|
|
@@ -13258,6 +13736,8 @@
|
|
|
13258
13736
|
$initializeListModelsCommand(program);
|
|
13259
13737
|
$initializeListScrapersCommand(program);
|
|
13260
13738
|
$initializeStartServerCommand(program);
|
|
13739
|
+
// TODO: [🧠] Should it be here or not> $addGlobalOptionsToCommand(program);
|
|
13740
|
+
program.commands.forEach($addGlobalOptionsToCommand);
|
|
13261
13741
|
program.parse(process.argv);
|
|
13262
13742
|
}
|
|
13263
13743
|
/**
|
|
@@ -13307,8 +13787,7 @@
|
|
|
13307
13787
|
options: {
|
|
13308
13788
|
apiKey: 'sk-ant-api03-',
|
|
13309
13789
|
isProxied: true,
|
|
13310
|
-
|
|
13311
|
-
path: DEFAULT_REMOTE_URL_PATH,
|
|
13790
|
+
remoteServerUrl: DEFAULT_REMOTE_SERVER_URL,
|
|
13312
13791
|
},
|
|
13313
13792
|
};
|
|
13314
13793
|
},
|
|
@@ -13331,146 +13810,6 @@
|
|
|
13331
13810
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
13332
13811
|
*/
|
|
13333
13812
|
|
|
13334
|
-
/**
|
|
13335
|
-
* Creates a connection to the remote proxy server.
|
|
13336
|
-
*
|
|
13337
|
-
* Note: This function creates a connection to the remote server and returns a socket but responsibility of closing the connection is on the caller
|
|
13338
|
-
*
|
|
13339
|
-
* @private internal utility function
|
|
13340
|
-
*/
|
|
13341
|
-
async function createRemoteClient(options) {
|
|
13342
|
-
const { remoteUrl, path } = options;
|
|
13343
|
-
return new Promise((resolve, reject) => {
|
|
13344
|
-
const socket = socket_ioClient.io(remoteUrl, {
|
|
13345
|
-
retries: CONNECTION_RETRIES_LIMIT,
|
|
13346
|
-
timeout: CONNECTION_TIMEOUT_MS,
|
|
13347
|
-
path,
|
|
13348
|
-
// path: `${this.remoteUrl.pathname}/socket.io`,
|
|
13349
|
-
transports: [/*'websocket', <- TODO: [🌬] Make websocket transport work */ 'polling'],
|
|
13350
|
-
});
|
|
13351
|
-
// console.log('Connecting to', this.options.remoteUrl.href, { socket });
|
|
13352
|
-
socket.on('connect', () => {
|
|
13353
|
-
resolve(socket);
|
|
13354
|
-
});
|
|
13355
|
-
// TODO: [💩] Better timeout handling
|
|
13356
|
-
setTimeout(() => {
|
|
13357
|
-
reject(new Error(`Timeout while connecting to ${remoteUrl}`));
|
|
13358
|
-
}, CONNECTION_TIMEOUT_MS);
|
|
13359
|
-
});
|
|
13360
|
-
}
|
|
13361
|
-
|
|
13362
|
-
/**
|
|
13363
|
-
* Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
|
|
13364
|
-
*
|
|
13365
|
-
* You can simply use `RemoteExecutionTools` on client-side javascript and connect to your remote server.
|
|
13366
|
-
* This is useful to make all logic on browser side but not expose your API keys or no need to use customer's GPU.
|
|
13367
|
-
*
|
|
13368
|
-
* @see https://github.com/webgptorg/promptbook#remote-server
|
|
13369
|
-
* @public exported from `@promptbook/remote-client`
|
|
13370
|
-
*/
|
|
13371
|
-
class RemoteLlmExecutionTools {
|
|
13372
|
-
/* <- TODO: [🍚] `, Destroyable` */
|
|
13373
|
-
constructor(options) {
|
|
13374
|
-
this.options = options;
|
|
13375
|
-
}
|
|
13376
|
-
get title() {
|
|
13377
|
-
// TODO: [🧠] Maybe fetch title+description from the remote server (as well as if model methods are defined)
|
|
13378
|
-
return 'Remote server';
|
|
13379
|
-
}
|
|
13380
|
-
get description() {
|
|
13381
|
-
return 'Use all models by your remote server';
|
|
13382
|
-
}
|
|
13383
|
-
/**
|
|
13384
|
-
* Check the configuration of all execution tools
|
|
13385
|
-
*/
|
|
13386
|
-
async checkConfiguration() {
|
|
13387
|
-
const socket = await createRemoteClient(this.options);
|
|
13388
|
-
socket.disconnect();
|
|
13389
|
-
// TODO: [main] !!3 Check version of the remote server and compatibility
|
|
13390
|
-
// TODO: [🎍] Send checkConfiguration
|
|
13391
|
-
}
|
|
13392
|
-
/**
|
|
13393
|
-
* List all available models that can be used
|
|
13394
|
-
*/
|
|
13395
|
-
async listModels() {
|
|
13396
|
-
// TODO: [👒] Listing models (and checking configuration) probbably should go through REST API not Socket.io
|
|
13397
|
-
const socket = await createRemoteClient(this.options);
|
|
13398
|
-
socket.emit('listModels-request', {
|
|
13399
|
-
identification: this.options.identification,
|
|
13400
|
-
} /* <- Note: [🤛] */);
|
|
13401
|
-
const promptResult = await new Promise((resolve, reject) => {
|
|
13402
|
-
socket.on('listModels-response', (response) => {
|
|
13403
|
-
resolve(response.models);
|
|
13404
|
-
socket.disconnect();
|
|
13405
|
-
});
|
|
13406
|
-
socket.on('error', (error) => {
|
|
13407
|
-
reject(deserializeError(error));
|
|
13408
|
-
socket.disconnect();
|
|
13409
|
-
});
|
|
13410
|
-
});
|
|
13411
|
-
socket.disconnect();
|
|
13412
|
-
return promptResult;
|
|
13413
|
-
}
|
|
13414
|
-
/**
|
|
13415
|
-
* Calls remote proxy server to use a chat model
|
|
13416
|
-
*/
|
|
13417
|
-
callChatModel(prompt) {
|
|
13418
|
-
if (this.options.isVerbose) {
|
|
13419
|
-
console.info(`🖋 Remote callChatModel call`);
|
|
13420
|
-
}
|
|
13421
|
-
return /* not await */ this.callCommonModel(prompt);
|
|
13422
|
-
}
|
|
13423
|
-
/**
|
|
13424
|
-
* Calls remote proxy server to use a completion model
|
|
13425
|
-
*/
|
|
13426
|
-
callCompletionModel(prompt) {
|
|
13427
|
-
if (this.options.isVerbose) {
|
|
13428
|
-
console.info(`💬 Remote callCompletionModel call`);
|
|
13429
|
-
}
|
|
13430
|
-
return /* not await */ this.callCommonModel(prompt);
|
|
13431
|
-
}
|
|
13432
|
-
/**
|
|
13433
|
-
* Calls remote proxy server to use a embedding model
|
|
13434
|
-
*/
|
|
13435
|
-
callEmbeddingModel(prompt) {
|
|
13436
|
-
if (this.options.isVerbose) {
|
|
13437
|
-
console.info(`💬 Remote callEmbeddingModel call`);
|
|
13438
|
-
}
|
|
13439
|
-
return /* not await */ this.callCommonModel(prompt);
|
|
13440
|
-
}
|
|
13441
|
-
// <- Note: [🤖] callXxxModel
|
|
13442
|
-
/**
|
|
13443
|
-
* Calls remote proxy server to use both completion or chat model
|
|
13444
|
-
*/
|
|
13445
|
-
async callCommonModel(prompt) {
|
|
13446
|
-
const socket = await createRemoteClient(this.options);
|
|
13447
|
-
socket.emit('prompt-request', {
|
|
13448
|
-
identification: this.options.identification,
|
|
13449
|
-
prompt,
|
|
13450
|
-
} /* <- Note: [🤛] */);
|
|
13451
|
-
const promptResult = await new Promise((resolve, reject) => {
|
|
13452
|
-
socket.on('prompt-response', (response) => {
|
|
13453
|
-
resolve(response.promptResult);
|
|
13454
|
-
socket.disconnect();
|
|
13455
|
-
});
|
|
13456
|
-
socket.on('error', (error) => {
|
|
13457
|
-
reject(deserializeError(error));
|
|
13458
|
-
socket.disconnect();
|
|
13459
|
-
});
|
|
13460
|
-
});
|
|
13461
|
-
socket.disconnect();
|
|
13462
|
-
return promptResult;
|
|
13463
|
-
}
|
|
13464
|
-
}
|
|
13465
|
-
/**
|
|
13466
|
-
* TODO: Maybe use `$exportJson`
|
|
13467
|
-
* TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
|
|
13468
|
-
* TODO: [🍓] Allow to list compatible models with each variant
|
|
13469
|
-
* TODO: [🗯] RemoteLlmExecutionTools should extend Destroyable and implement IDestroyable
|
|
13470
|
-
* TODO: [🧠][🌰] Allow to pass `title` for tracking purposes
|
|
13471
|
-
* TODO: [🧠] Maybe remove `@promptbook/remote-client` and just use `@promptbook/core`
|
|
13472
|
-
*/
|
|
13473
|
-
|
|
13474
13813
|
/**
|
|
13475
13814
|
* Function computeUsage will create price per one token based on the string value found on openai page
|
|
13476
13815
|
*
|