@promptbook/cli 0.89.0-9 → 0.89.0

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.
Files changed (40) hide show
  1. package/README.md +9 -11
  2. package/esm/index.es.js +925 -616
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/servers.d.ts +40 -0
  5. package/esm/typings/src/_packages/core.index.d.ts +8 -4
  6. package/esm/typings/src/_packages/types.index.d.ts +18 -0
  7. package/esm/typings/src/_packages/utils.index.d.ts +4 -0
  8. package/esm/typings/src/cli/cli-commands/login.d.ts +0 -1
  9. package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +16 -3
  10. package/esm/typings/src/cli/test/ptbk.d.ts +1 -1
  11. package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +2 -0
  12. package/esm/typings/src/config.d.ts +10 -19
  13. package/esm/typings/src/errors/0-index.d.ts +7 -4
  14. package/esm/typings/src/errors/PipelineExecutionError.d.ts +1 -1
  15. package/esm/typings/src/errors/WrappedError.d.ts +10 -0
  16. package/esm/typings/src/errors/assertsError.d.ts +11 -0
  17. package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
  18. package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +9 -0
  19. package/esm/typings/src/formats/csv/utils/isValidCsvString.test.d.ts +1 -0
  20. package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +3 -0
  21. package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +9 -0
  22. package/esm/typings/src/formats/xml/utils/isValidXmlString.test.d.ts +1 -0
  23. package/esm/typings/src/llm-providers/_common/register/{$provideEnvFilepath.d.ts → $provideEnvFilename.d.ts} +2 -2
  24. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
  25. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
  26. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +11 -2
  27. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
  28. package/esm/typings/src/remote-server/openapi-types.d.ts +284 -0
  29. package/esm/typings/src/remote-server/openapi.d.ts +187 -0
  30. package/esm/typings/src/remote-server/socket-types/_subtypes/Identification.d.ts +7 -1
  31. package/esm/typings/src/remote-server/socket-types/_subtypes/identificationToPromptbookToken.d.ts +11 -0
  32. package/esm/typings/src/remote-server/socket-types/_subtypes/promptbookTokenToIdentification.d.ts +10 -0
  33. package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
  34. package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +15 -9
  35. package/esm/typings/src/storage/env-storage/$EnvStorage.d.ts +40 -0
  36. package/esm/typings/src/types/typeAliases.d.ts +26 -0
  37. package/package.json +15 -11
  38. package/umd/index.umd.js +929 -620
  39. package/umd/index.umd.js.map +1 -1
  40. package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
package/umd/index.umd.js CHANGED
@@ -1,8 +1,8 @@
1
1
  (function (global, factory) {
2
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('waitasecond'), require('prompts'), require('path'), require('fs/promises'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('crypto'), require('socket.io-client'), require('rxjs'), require('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';
2
+ typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('colors'), require('commander'), require('spacetrim'), require('waitasecond'), require('prompts'), require('path'), require('fs/promises'), require('dotenv'), require('crypto-js/enc-hex'), require('crypto-js/sha256'), require('crypto'), require('socket.io-client'), require('rxjs'), require('child_process'), require('jszip'), require('prettier'), require('prettier/parser-html'), require('papaparse'), require('crypto-js'), require('mime-types'), require('glob-promise'), require('moment'), require('express'), require('http'), require('socket.io'), require('express-openapi-validator'), require('swagger-ui-express'), require('@anthropic-ai/sdk'), require('@azure/openai'), require('openai'), require('@mozilla/readability'), require('jsdom'), require('showdown')) :
3
+ typeof define === 'function' && define.amd ? define(['exports', 'colors', 'commander', 'spacetrim', 'waitasecond', 'prompts', 'path', 'fs/promises', 'dotenv', 'crypto-js/enc-hex', 'crypto-js/sha256', 'crypto', 'socket.io-client', 'rxjs', 'child_process', 'jszip', 'prettier', 'prettier/parser-html', 'papaparse', 'crypto-js', 'mime-types', 'glob-promise', 'moment', 'express', 'http', 'socket.io', 'express-openapi-validator', 'swagger-ui-express', '@anthropic-ai/sdk', '@azure/openai', 'openai', '@mozilla/readability', 'jsdom', 'showdown'], factory) :
4
+ (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["promptbook-cli"] = {}, global.colors, global.commander, global.spaceTrim, global.waitasecond, global.prompts, global.path, global.promises, global.dotenv, global.hexEncoder, global.sha256, global.crypto, global.socket_ioClient, global.rxjs, global.child_process, global.JSZip, global.prettier, global.parserHtml, global.papaparse, global.cryptoJs, global.mimeTypes, global.glob, global.moment, global.express, global.http, global.socket_io, global.OpenApiValidator, global.swaggerUi, global.Anthropic, global.openai, global.OpenAI, global.readability, global.jsdom, global.showdown));
5
+ })(this, (function (exports, colors, commander, spaceTrim, waitasecond, prompts, path, promises, dotenv, hexEncoder, sha256, crypto, socket_ioClient, rxjs, child_process, JSZip, prettier, parserHtml, papaparse, cryptoJs, mimeTypes, glob, moment, express, http, socket_io, OpenApiValidator, swaggerUi, Anthropic, openai, OpenAI, readability, jsdom, showdown) { 'use strict';
6
6
 
7
7
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
8
8
 
@@ -28,16 +28,16 @@
28
28
  var commander__default = /*#__PURE__*/_interopDefaultLegacy(commander);
29
29
  var spaceTrim__default = /*#__PURE__*/_interopDefaultLegacy(spaceTrim);
30
30
  var prompts__default = /*#__PURE__*/_interopDefaultLegacy(prompts);
31
+ var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
31
32
  var hexEncoder__default = /*#__PURE__*/_interopDefaultLegacy(hexEncoder);
32
33
  var sha256__default = /*#__PURE__*/_interopDefaultLegacy(sha256);
33
- var dotenv__namespace = /*#__PURE__*/_interopNamespace(dotenv);
34
34
  var JSZip__default = /*#__PURE__*/_interopDefaultLegacy(JSZip);
35
35
  var parserHtml__default = /*#__PURE__*/_interopDefaultLegacy(parserHtml);
36
36
  var glob__default = /*#__PURE__*/_interopDefaultLegacy(glob);
37
37
  var moment__default = /*#__PURE__*/_interopDefaultLegacy(moment);
38
38
  var express__default = /*#__PURE__*/_interopDefaultLegacy(express);
39
39
  var http__default = /*#__PURE__*/_interopDefaultLegacy(http);
40
- var swaggerJsdoc__default = /*#__PURE__*/_interopDefaultLegacy(swaggerJsdoc);
40
+ var OpenApiValidator__namespace = /*#__PURE__*/_interopNamespace(OpenApiValidator);
41
41
  var swaggerUi__default = /*#__PURE__*/_interopDefaultLegacy(swaggerUi);
42
42
  var Anthropic__default = /*#__PURE__*/_interopDefaultLegacy(Anthropic);
43
43
  var OpenAI__default = /*#__PURE__*/_interopDefaultLegacy(OpenAI);
@@ -56,12 +56,43 @@
56
56
  * @generated
57
57
  * @see https://github.com/webgptorg/promptbook
58
58
  */
59
- const PROMPTBOOK_ENGINE_VERSION = '0.89.0-9';
59
+ const PROMPTBOOK_ENGINE_VERSION = '0.89.0';
60
60
  /**
61
61
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
62
62
  * Note: [💞] Ignore a discrepancy between file name and entity name
63
63
  */
64
64
 
65
+ /**
66
+ * Available remote servers for the Promptbook
67
+ *
68
+ * @public exported from `@promptbook/core`
69
+ */
70
+ const REMOTE_SERVER_URLS = [
71
+ {
72
+ title: 'Promptbook',
73
+ description: `Servers of Promptbook.studio`,
74
+ owner: 'AI Web, LLC <legal@ptbk.io> (https://www.ptbk.io/)',
75
+ isAnonymousModeAllowed: true,
76
+ urls: [
77
+ 'https://promptbook.s5.ptbk.io/',
78
+ // Note: Servers 1-4 are not running
79
+ ],
80
+ },
81
+ /*
82
+ Note: Working on older version of Promptbook and not supported anymore
83
+ {
84
+ title: 'Pavol Promptbook Server',
85
+ description: `Personal server of Pavol Hejný with simple testing server, DO NOT USE IT FOR PRODUCTION`,
86
+ owner: 'Pavol Hejný <pavol@ptbk.io> (https://www.pavolhejny.com/)',
87
+ isAnonymousModeAllowed: true,
88
+ urls: ['https://api.pavolhejny.com/promptbook'],
89
+ },
90
+ */
91
+ ];
92
+ /**
93
+ * Note: [💞] Ignore a discrepancy between file name and entity name
94
+ */
95
+
65
96
  /**
66
97
  * Returns the same value that is passed as argument.
67
98
  * No side effects.
@@ -116,6 +147,7 @@
116
147
  * @public exported from `@promptbook/core`
117
148
  */
118
149
  const CLAIM = `It's time for a paradigm shift. The future of software in plain English, French or Latin`;
150
+ // <- TODO: [🐊] Pick the best claim
119
151
  /**
120
152
  * When the title is not provided, the default title is used
121
153
  *
@@ -146,6 +178,12 @@
146
178
  * @private within the repository
147
179
  */
148
180
  const GENERATOR_WARNING_BY_PROMPTBOOK_CLI = `⚠️ WARNING: This code has been generated by \`@promptbook/cli\` so that any manual changes will be overwritten`;
181
+ /**
182
+ * Warning message for the automatically generated sections of `.env` files
183
+ *
184
+ * @private within the repository
185
+ */
186
+ const GENERATOR_WARNING_IN_ENV = `Note: Added by Promptbook`;
149
187
  // <- TODO: [🧠] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
150
188
  /**
151
189
  * The maximum number of iterations for a loops
@@ -166,6 +204,7 @@
166
204
  infinity: '(infinity; ∞)',
167
205
  negativeInfinity: '(negative infinity; -∞)',
168
206
  unserializable: '(unserializable value)',
207
+ circular: '(circular JSON)',
169
208
  };
170
209
  /**
171
210
  * Small number limit
@@ -225,7 +264,7 @@
225
264
  */
226
265
  const DEFAULT_BOOKS_DIRNAME = './books';
227
266
  // <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
228
- // TODO: !!!!!! Just .promptbook dir, hardocode others
267
+ // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
229
268
  /**
230
269
  * Where to store the temporary downloads
231
270
  *
@@ -281,11 +320,11 @@
281
320
  ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
282
321
  };
283
322
  /**
284
- * @@@
323
+ * Default remote server URL for the Promptbook
285
324
  *
286
325
  * @public exported from `@promptbook/core`
287
326
  */
288
- const DEFAULT_REMOTE_SERVER_URL = 'https://api.pavolhejny.com/promptbook';
327
+ const DEFAULT_REMOTE_SERVER_URL = REMOTE_SERVER_URLS[0].urls[0];
289
328
  // <- TODO: [🧜‍♂️]
290
329
  /**
291
330
  * @@@
@@ -419,6 +458,122 @@
419
458
  * TODO: [🎺]
420
459
  */
421
460
 
461
+ /**
462
+ * Make error report URL for the given error
463
+ *
464
+ * @private private within the repository
465
+ */
466
+ function getErrorReportUrl(error) {
467
+ const report = {
468
+ title: `🐜 Error report from ${NAME}`,
469
+ body: spaceTrim__default["default"]((block) => `
470
+
471
+
472
+ \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
473
+
474
+ \`\`\`
475
+ ${block(error.message || '(no error message)')}
476
+ \`\`\`
477
+
478
+
479
+ ## More info:
480
+
481
+ - **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
482
+ - **Book language version:** ${BOOK_LANGUAGE_VERSION}
483
+ - **Time:** ${new Date().toISOString()}
484
+
485
+ <details>
486
+ <summary>Stack trace:</summary>
487
+
488
+ ## Stack trace:
489
+
490
+ \`\`\`stacktrace
491
+ ${block(error.stack || '(empty)')}
492
+ \`\`\`
493
+ </details>
494
+
495
+ `),
496
+ };
497
+ const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
498
+ reportUrl.searchParams.set('labels', 'bug');
499
+ reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
500
+ reportUrl.searchParams.set('title', report.title);
501
+ reportUrl.searchParams.set('body', report.body);
502
+ return reportUrl;
503
+ }
504
+
505
+ /**
506
+ * This error type indicates that the error should not happen and its last check before crashing with some other error
507
+ *
508
+ * @public exported from `@promptbook/core`
509
+ */
510
+ class UnexpectedError extends Error {
511
+ constructor(message) {
512
+ super(spaceTrim.spaceTrim((block) => `
513
+ ${block(message)}
514
+
515
+ Note: This error should not happen.
516
+ It's probbably a bug in the pipeline collection
517
+
518
+ Please report issue:
519
+ ${block(getErrorReportUrl(new Error(message)).href)}
520
+
521
+ Or contact us on ${ADMIN_EMAIL}
522
+
523
+ `));
524
+ this.name = 'UnexpectedError';
525
+ Object.setPrototypeOf(this, UnexpectedError.prototype);
526
+ }
527
+ }
528
+
529
+ /**
530
+ * This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
531
+ *
532
+ * @public exported from `@promptbook/core`
533
+ */
534
+ class WrappedError extends Error {
535
+ constructor(whatWasThrown) {
536
+ const tag = `[🤮]`;
537
+ console.error(tag, whatWasThrown);
538
+ super(spaceTrim.spaceTrim(`
539
+ Non-Error object was thrown
540
+
541
+ Note: Look for ${tag} in the console for more details
542
+ Please report issue on ${ADMIN_EMAIL}
543
+ `));
544
+ this.name = 'WrappedError';
545
+ Object.setPrototypeOf(this, WrappedError.prototype);
546
+ }
547
+ }
548
+
549
+ /**
550
+ * Helper used in catch blocks to assert that the error is an instance of `Error`
551
+ *
552
+ * @param whatWasThrown Any object that was thrown
553
+ * @returns Nothing if the error is an instance of `Error`
554
+ * @throws `WrappedError` or `UnexpectedError` if the error is not standard
555
+ *
556
+ * @private within the repository
557
+ */
558
+ function assertsError(whatWasThrown) {
559
+ // Case 1: Handle error which was rethrown as `WrappedError`
560
+ if (whatWasThrown instanceof WrappedError) {
561
+ const wrappedError = whatWasThrown;
562
+ throw wrappedError;
563
+ }
564
+ // Case 2: Handle unexpected errors
565
+ if (whatWasThrown instanceof UnexpectedError) {
566
+ const unexpectedError = whatWasThrown;
567
+ throw unexpectedError;
568
+ }
569
+ // Case 3: Handle standard errors - keep them up to consumer
570
+ if (whatWasThrown instanceof Error) {
571
+ return;
572
+ }
573
+ // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
574
+ throw new WrappedError(whatWasThrown);
575
+ }
576
+
422
577
  /**
423
578
  * Wraps action to handle error console logging and exit process with error code
424
579
  *
@@ -433,9 +588,7 @@
433
588
  return process.exit(0);
434
589
  }
435
590
  catch (error) {
436
- if (!(error instanceof Error)) {
437
- throw error;
438
- }
591
+ assertsError(error);
439
592
  // console.error(colors.bgRed(error.name));
440
593
  console.error(colors__default["default"].red(/* error.stack || */ error.message));
441
594
  return process.exit(1);
@@ -542,74 +695,6 @@
542
695
  }
543
696
  }
544
697
 
545
- /**
546
- * Make error report URL for the given error
547
- *
548
- * @private private within the repository
549
- */
550
- function getErrorReportUrl(error) {
551
- const report = {
552
- title: `🐜 Error report from ${NAME}`,
553
- body: spaceTrim__default["default"]((block) => `
554
-
555
-
556
- \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
557
-
558
- \`\`\`
559
- ${block(error.message || '(no error message)')}
560
- \`\`\`
561
-
562
-
563
- ## More info:
564
-
565
- - **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
566
- - **Book language version:** ${BOOK_LANGUAGE_VERSION}
567
- - **Time:** ${new Date().toISOString()}
568
-
569
- <details>
570
- <summary>Stack trace:</summary>
571
-
572
- ## Stack trace:
573
-
574
- \`\`\`stacktrace
575
- ${block(error.stack || '(empty)')}
576
- \`\`\`
577
- </details>
578
-
579
- `),
580
- };
581
- const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
582
- reportUrl.searchParams.set('labels', 'bug');
583
- reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
584
- reportUrl.searchParams.set('title', report.title);
585
- reportUrl.searchParams.set('body', report.body);
586
- return reportUrl;
587
- }
588
-
589
- /**
590
- * This error type indicates that the error should not happen and its last check before crashing with some other error
591
- *
592
- * @public exported from `@promptbook/core`
593
- */
594
- class UnexpectedError extends Error {
595
- constructor(message) {
596
- super(spaceTrim.spaceTrim((block) => `
597
- ${block(message)}
598
-
599
- Note: This error should not happen.
600
- It's probbably a bug in the pipeline collection
601
-
602
- Please report issue:
603
- ${block(getErrorReportUrl(new Error(message)).href)}
604
-
605
- Or contact us on ${ADMIN_EMAIL}
606
-
607
- `));
608
- this.name = 'UnexpectedError';
609
- Object.setPrototypeOf(this, UnexpectedError.prototype);
610
- }
611
- }
612
-
613
698
  /**
614
699
  * @@@
615
700
  *
@@ -929,6 +1014,40 @@
929
1014
  keepUnused(...sideEffectSubjects);
930
1015
  }
931
1016
 
1017
+ /**
1018
+ * Convert identification to Promptbook token
1019
+ *
1020
+ * @param identification
1021
+ *
1022
+ * @public exported from `@promptbook/core`
1023
+ */
1024
+ function identificationToPromptbookToken(identification) {
1025
+ const { appId, userId, userToken } = identification;
1026
+ const promptbookToken = `${appId}-${userId}-${userToken}`;
1027
+ return promptbookToken;
1028
+ }
1029
+
1030
+ /**
1031
+ * Convert Promptbook token to identification
1032
+ *
1033
+ * @param promptbookToken
1034
+ *
1035
+ * @public exported from `@promptbook/core`
1036
+ */
1037
+ function promptbookTokenToIdentification(promptbookToken) {
1038
+ const [appId, userId, userToken] = promptbookToken.split('-');
1039
+ if (!appId || !userId || !userToken) {
1040
+ throw new Error(`Invalid promptbook token: ${promptbookToken}`);
1041
+ }
1042
+ const identification = {
1043
+ appId,
1044
+ userId,
1045
+ userToken,
1046
+ isAnonymous: false,
1047
+ };
1048
+ return identification;
1049
+ }
1050
+
932
1051
  /**
933
1052
  * Just marks a place of place where should be something implemented
934
1053
  * No side effects.
@@ -942,27 +1061,199 @@
942
1061
  function TODO_USE(...value) {
943
1062
  }
944
1063
 
945
- /**
946
- * @@@
947
- *
948
- * @public exported from `@promptbook/node`
949
- */
950
- function $provideFilesystemForNode(options) {
951
- if (!$isRunningInNode()) {
952
- throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
1064
+ /**
1065
+ * @@@
1066
+ *
1067
+ * @public exported from `@promptbook/node`
1068
+ */
1069
+ function $provideFilesystemForNode(options) {
1070
+ if (!$isRunningInNode()) {
1071
+ throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
1072
+ }
1073
+ return {
1074
+ stat: promises.stat,
1075
+ access: promises.access,
1076
+ constants: promises.constants,
1077
+ readFile: promises.readFile,
1078
+ writeFile: promises.writeFile,
1079
+ readdir: promises.readdir,
1080
+ mkdir: promises.mkdir,
1081
+ };
1082
+ }
1083
+ /**
1084
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
1085
+ */
1086
+
1087
+ /**
1088
+ * Checks if the file exists
1089
+ *
1090
+ * @private within the repository
1091
+ */
1092
+ async function isFileExisting(filename, fs) {
1093
+ const isReadAccessAllowed = await fs
1094
+ .access(filename, fs.constants.R_OK)
1095
+ .then(() => true)
1096
+ .catch(() => false);
1097
+ if (!isReadAccessAllowed) {
1098
+ return false;
1099
+ }
1100
+ const isFile = await fs
1101
+ .stat(filename)
1102
+ .then((fileStat) => fileStat.isFile())
1103
+ .catch(() => false);
1104
+ return isFile;
1105
+ }
1106
+ /**
1107
+ * Note: Not [~🟢~] because it is not directly dependent on `fs
1108
+ * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
1109
+ * TODO: [🖇] What about symlinks?
1110
+ */
1111
+
1112
+ /**
1113
+ * Determines if the given path is a root path.
1114
+ *
1115
+ * Note: This does not check if the file exists only if the path is valid
1116
+ * @public exported from `@promptbook/utils`
1117
+ */
1118
+ function isRootPath(value) {
1119
+ if (value === '/') {
1120
+ return true;
1121
+ }
1122
+ if (/^[A-Z]:\\$/i.test(value)) {
1123
+ return true;
1124
+ }
1125
+ return false;
1126
+ }
1127
+ /**
1128
+ * TODO: [🍏] Make for MacOS paths
1129
+ */
1130
+
1131
+ /**
1132
+ * Provides the path to the `.env` file
1133
+ *
1134
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
1135
+ *
1136
+ * @private within the repository - for CLI utils
1137
+ */
1138
+ async function $provideEnvFilename() {
1139
+ if (!$isRunningInNode()) {
1140
+ throw new EnvironmentMismatchError('Function `$provideEnvFilename` works only in Node.js environment');
1141
+ }
1142
+ const envFilePatterns = [
1143
+ '.env',
1144
+ '.env.test',
1145
+ '.env.local',
1146
+ '.env.development.local',
1147
+ '.env.development',
1148
+ '.env.production.local',
1149
+ '.env.production',
1150
+ '.env.prod.local',
1151
+ '.env.prod',
1152
+ // <- TODO: Maybe add more patterns
1153
+ ];
1154
+ let rootDirname = process.cwd();
1155
+ up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
1156
+ for (const pattern of envFilePatterns) {
1157
+ const envFilename = path.join(rootDirname, pattern);
1158
+ if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
1159
+ $setUsedEnvFilename(envFilename);
1160
+ return envFilename;
1161
+ }
1162
+ }
1163
+ if (isRootPath(rootDirname)) {
1164
+ break up_to_root;
1165
+ }
1166
+ // Note: If the directory does not exist, try the parent directory
1167
+ rootDirname = path.join(rootDirname, '..');
1168
+ }
1169
+ return null;
1170
+ }
1171
+ /**
1172
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
1173
+ */
1174
+
1175
+ /**
1176
+ * Stores data in .env variables
1177
+ *
1178
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes to `process.env`
1179
+ *
1180
+ * @private within the repository - for CLI utils
1181
+ */
1182
+ class $EnvStorage {
1183
+ constructor() {
1184
+ this.envFilename = null;
1185
+ }
1186
+ async $provideOrCreateEnvFile() {
1187
+ if (this.envFilename !== null) {
1188
+ return this.envFilename;
1189
+ }
1190
+ let envFilename = await $provideEnvFilename();
1191
+ if (envFilename !== null) {
1192
+ this.envFilename = envFilename;
1193
+ return envFilename;
1194
+ }
1195
+ envFilename = path.join(process.cwd(), '.env');
1196
+ await promises.writeFile(envFilename, '# This file was initialized by Promptbook', 'utf-8');
1197
+ this.envFilename = envFilename;
1198
+ return envFilename;
1199
+ }
1200
+ transformKey(key) {
1201
+ return normalizeTo_SCREAMING_CASE(key);
1202
+ }
1203
+ /**
1204
+ * Returns the number of key/value pairs currently present in the list associated with the object.
1205
+ */
1206
+ get length() {
1207
+ throw new NotYetImplementedError('Method `$EnvStorage.length` not implemented.');
1208
+ }
1209
+ /**
1210
+ * Empties the list associated with the object of all key/value pairs, if there are any.
1211
+ */
1212
+ clear() {
1213
+ throw new NotYetImplementedError('Method `$EnvStorage.clear` not implemented.');
1214
+ }
1215
+ /**
1216
+ * 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.
1217
+ */
1218
+ async getItem(key) {
1219
+ dotenv__namespace.config({ path: await this.$provideOrCreateEnvFile() });
1220
+ return process.env[this.transformKey(key)] || null;
1221
+ }
1222
+ /**
1223
+ * 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.
1224
+ */
1225
+ key(index) {
1226
+ throw new NotYetImplementedError('Method `$EnvStorage.key` not implemented.');
1227
+ }
1228
+ /**
1229
+ * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
1230
+ */
1231
+ async setItem(key, value) {
1232
+ const envFilename = await this.$provideOrCreateEnvFile();
1233
+ const envContent = await promises.readFile(envFilename, 'utf-8');
1234
+ const transformedKey = this.transformKey(key);
1235
+ const updatedEnvContent = envContent
1236
+ .split('\n')
1237
+ .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
1238
+ .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
1239
+ .join('\n');
1240
+ const newEnvContent = spaceTrim__default["default"]((block) => `
1241
+ ${block(updatedEnvContent)}
1242
+
1243
+ # ${GENERATOR_WARNING_IN_ENV}
1244
+ ${transformedKey}=${JSON.stringify(value)}
1245
+ `);
1246
+ await promises.writeFile(envFilename, newEnvContent, 'utf-8');
1247
+ }
1248
+ /**
1249
+ * 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.
1250
+ */
1251
+ removeItem(key) {
1252
+ throw new NotYetImplementedError('Method `$EnvStorage.removeItem` not implemented.');
953
1253
  }
954
- return {
955
- stat: promises.stat,
956
- access: promises.access,
957
- constants: promises.constants,
958
- readFile: promises.readFile,
959
- writeFile: promises.writeFile,
960
- readdir: promises.readdir,
961
- mkdir: promises.mkdir,
962
- };
963
1254
  }
964
1255
  /**
965
- * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
1256
+ * TODO: Write file more securely - ensure that there can be no accidental overwriting of existing variables and other content
966
1257
  */
967
1258
 
968
1259
  /**
@@ -1098,9 +1389,7 @@
1098
1389
  JSON.stringify(value); // <- TODO: [0]
1099
1390
  }
1100
1391
  catch (error) {
1101
- if (!(error instanceof Error)) {
1102
- throw error;
1103
- }
1392
+ assertsError(error);
1104
1393
  throw new UnexpectedError(spaceTrim__default["default"]((block) => `
1105
1394
  \`${name}\` is not serializable
1106
1395
 
@@ -1333,31 +1622,6 @@
1333
1622
  * TODO: [🍙] Make some standard order of json properties
1334
1623
  */
1335
1624
 
1336
- /**
1337
- * Checks if the file exists
1338
- *
1339
- * @private within the repository
1340
- */
1341
- async function isFileExisting(filename, fs) {
1342
- const isReadAccessAllowed = await fs
1343
- .access(filename, fs.constants.R_OK)
1344
- .then(() => true)
1345
- .catch(() => false);
1346
- if (!isReadAccessAllowed) {
1347
- return false;
1348
- }
1349
- const isFile = await fs
1350
- .stat(filename)
1351
- .then((fileStat) => fileStat.isFile())
1352
- .catch(() => false);
1353
- return isFile;
1354
- }
1355
- /**
1356
- * Note: Not [~🟢~] because it is not directly dependent on `fs
1357
- * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
1358
- * TODO: [🖇] What about symlinks?
1359
- */
1360
-
1361
1625
  /**
1362
1626
  * Removes emojis from a string and fix whitespaces
1363
1627
  *
@@ -1863,53 +2127,6 @@
1863
2127
  * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
1864
2128
  */
1865
2129
 
1866
- /**
1867
- * Stores data in memory (HEAP)
1868
- *
1869
- * @public exported from `@promptbook/core`
1870
- */
1871
- class MemoryStorage {
1872
- constructor() {
1873
- this.storage = {};
1874
- }
1875
- /**
1876
- * Returns the number of key/value pairs currently present in the list associated with the object.
1877
- */
1878
- get length() {
1879
- return Object.keys(this.storage).length;
1880
- }
1881
- /**
1882
- * Empties the list associated with the object of all key/value pairs, if there are any.
1883
- */
1884
- clear() {
1885
- this.storage = {};
1886
- }
1887
- /**
1888
- * Returns the current value associated with the given key, or null if the given key does not exist in the list associated with the object.
1889
- */
1890
- getItem(key) {
1891
- return this.storage[key] || null;
1892
- }
1893
- /**
1894
- * Returns the name of the nth key in the list, or null if n is greater than or equal to the number of key/value pairs in the object.
1895
- */
1896
- key(index) {
1897
- return Object.keys(this.storage)[index] || null;
1898
- }
1899
- /**
1900
- * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
1901
- */
1902
- setItem(key, value) {
1903
- this.storage[key] = value;
1904
- }
1905
- /**
1906
- * Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
1907
- */
1908
- removeItem(key) {
1909
- delete this.storage[key];
1910
- }
1911
- }
1912
-
1913
2130
  /**
1914
2131
  * This error indicates problems parsing the format value
1915
2132
  *
@@ -2086,7 +2303,7 @@
2086
2303
  }
2087
2304
  }
2088
2305
  /**
2089
- * TODO: !!!!!! Add id to all errors
2306
+ * TODO: [🧠][🌂] Add id to all errors
2090
2307
  */
2091
2308
 
2092
2309
  /**
@@ -2148,7 +2365,10 @@
2148
2365
  PipelineExecutionError,
2149
2366
  PipelineLogicError,
2150
2367
  PipelineUrlError,
2368
+ AuthenticationError,
2369
+ PromptbookFetchError,
2151
2370
  UnexpectedError,
2371
+ WrappedError,
2152
2372
  // TODO: [🪑]> VersionMismatchError,
2153
2373
  };
2154
2374
  /**
@@ -2165,8 +2385,6 @@
2165
2385
  TypeError,
2166
2386
  URIError,
2167
2387
  AggregateError,
2168
- AuthenticationError,
2169
- PromptbookFetchError,
2170
2388
  /*
2171
2389
  Note: Not widely supported
2172
2390
  > InternalError,
@@ -2224,17 +2442,31 @@
2224
2442
  */
2225
2443
  async function createRemoteClient(options) {
2226
2444
  const { remoteServerUrl } = options;
2227
- let path = new URL(remoteServerUrl).pathname;
2228
- if (path.endsWith('/')) {
2229
- path = path.slice(0, -1);
2445
+ if (!isValidUrl(remoteServerUrl)) {
2446
+ throw new Error(`Invalid \`remoteServerUrl\`: "${remoteServerUrl}"`);
2447
+ }
2448
+ const remoteServerUrlParsed = new URL(remoteServerUrl);
2449
+ if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
2450
+ remoteServerUrlParsed.pathname = '/';
2451
+ throw new Error(spaceTrim__default["default"]((block) => `
2452
+ Remote server requires root url \`/\`
2453
+
2454
+ You have provided \`remoteServerUrl\`:
2455
+ ${block(remoteServerUrl)}
2456
+
2457
+ But something like this is expected:
2458
+ ${block(remoteServerUrlParsed.href)}
2459
+
2460
+ Note: If you need to run multiple services on the same server, use 3rd or 4th degree subdomain
2461
+
2462
+ `));
2230
2463
  }
2231
- path = `${path}/socket.io`;
2232
2464
  return new Promise((resolve, reject) => {
2233
2465
  const socket = socket_ioClient.io(remoteServerUrl, {
2234
2466
  retries: CONNECTION_RETRIES_LIMIT,
2235
2467
  timeout: CONNECTION_TIMEOUT_MS,
2236
- path,
2237
- transports: [/*'websocket', <- TODO: [🌬] Make websocket transport work */ 'polling'],
2468
+ path: '/socket.io',
2469
+ transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
2238
2470
  });
2239
2471
  // console.log('Connecting to', this.options.remoteServerUrl.href, { socket });
2240
2472
  socket.on('connect', () => {
@@ -2359,6 +2591,53 @@
2359
2591
  * TODO: [🧠] Maybe remove `@promptbook/remote-client` and just use `@promptbook/core`
2360
2592
  */
2361
2593
 
2594
+ /**
2595
+ * Stores data in memory (HEAP)
2596
+ *
2597
+ * @public exported from `@promptbook/core`
2598
+ */
2599
+ class MemoryStorage {
2600
+ constructor() {
2601
+ this.storage = {};
2602
+ }
2603
+ /**
2604
+ * Returns the number of key/value pairs currently present in the list associated with the object.
2605
+ */
2606
+ get length() {
2607
+ return Object.keys(this.storage).length;
2608
+ }
2609
+ /**
2610
+ * Empties the list associated with the object of all key/value pairs, if there are any.
2611
+ */
2612
+ clear() {
2613
+ this.storage = {};
2614
+ }
2615
+ /**
2616
+ * 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.
2617
+ */
2618
+ getItem(key) {
2619
+ return this.storage[key] || null;
2620
+ }
2621
+ /**
2622
+ * 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.
2623
+ */
2624
+ key(index) {
2625
+ return Object.keys(this.storage)[index] || null;
2626
+ }
2627
+ /**
2628
+ * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
2629
+ */
2630
+ setItem(key, value) {
2631
+ this.storage[key] = value;
2632
+ }
2633
+ /**
2634
+ * 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.
2635
+ */
2636
+ removeItem(key) {
2637
+ delete this.storage[key];
2638
+ }
2639
+ }
2640
+
2362
2641
  /**
2363
2642
  * Simple wrapper `new Date().toISOString()`
2364
2643
  *
@@ -2617,102 +2896,39 @@
2617
2896
  };
2618
2897
  }
2619
2898
  if (llmTools.callCompletionModel !== undefined) {
2620
- proxyTools.callCompletionModel = async (prompt) => {
2621
- // console.info('[🚕] callCompletionModel through countTotalUsage');
2622
- const promptResult = await llmTools.callCompletionModel(prompt);
2623
- totalUsage = addUsage(totalUsage, promptResult.usage);
2624
- spending.next(promptResult.usage);
2625
- return promptResult;
2626
- };
2627
- }
2628
- if (llmTools.callEmbeddingModel !== undefined) {
2629
- proxyTools.callEmbeddingModel = async (prompt) => {
2630
- // console.info('[🚕] callEmbeddingModel through countTotalUsage');
2631
- const promptResult = await llmTools.callEmbeddingModel(prompt);
2632
- totalUsage = addUsage(totalUsage, promptResult.usage);
2633
- spending.next(promptResult.usage);
2634
- return promptResult;
2635
- };
2636
- }
2637
- // <- Note: [🤖]
2638
- return proxyTools;
2639
- }
2640
- /**
2641
- * TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
2642
- * TODO: [🧠] Is there some meaningfull way how to test this util
2643
- * TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
2644
- * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
2645
- * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2646
- */
2647
-
2648
- /**
2649
- * Determines if the given path is a root path.
2650
- *
2651
- * Note: This does not check if the file exists only if the path is valid
2652
- * @public exported from `@promptbook/utils`
2653
- */
2654
- function isRootPath(value) {
2655
- if (value === '/') {
2656
- return true;
2657
- }
2658
- if (/^[A-Z]:\\$/i.test(value)) {
2659
- return true;
2660
- }
2661
- return false;
2662
- }
2663
- /**
2664
- * TODO: [🍏] Make for MacOS paths
2665
- */
2666
-
2667
- /**
2668
- * Provides the path to the `.env` file
2669
- *
2670
- * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access .env file
2671
- *
2672
- * @private within the repository - for CLI utils
2673
- */
2674
- async function $provideEnvFilepath() {
2675
- if (!$isRunningInNode()) {
2676
- throw new EnvironmentMismatchError('Function `$provideEnvFilepath` works only in Node.js environment');
2677
- }
2678
- const envFilePatterns = [
2679
- '.env',
2680
- '.env.test',
2681
- '.env.local',
2682
- '.env.development.local',
2683
- '.env.development',
2684
- '.env.production.local',
2685
- '.env.production',
2686
- '.env.prod.local',
2687
- '.env.prod',
2688
- // <- TODO: Maybe add more patterns
2689
- ];
2690
- let rootDirname = process.cwd();
2691
- up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
2692
- for (const pattern of envFilePatterns) {
2693
- const envFilename = path.join(rootDirname, pattern);
2694
- if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
2695
- $setUsedEnvFilename(envFilename);
2696
- return envFilename;
2697
- }
2698
- }
2699
- if (isRootPath(rootDirname)) {
2700
- break up_to_root;
2701
- }
2702
- // Note: If the directory does not exist, try the parent directory
2703
- rootDirname = path.join(rootDirname, '..');
2899
+ proxyTools.callCompletionModel = async (prompt) => {
2900
+ // console.info('[🚕] callCompletionModel through countTotalUsage');
2901
+ const promptResult = await llmTools.callCompletionModel(prompt);
2902
+ totalUsage = addUsage(totalUsage, promptResult.usage);
2903
+ spending.next(promptResult.usage);
2904
+ return promptResult;
2905
+ };
2704
2906
  }
2705
- return null;
2907
+ if (llmTools.callEmbeddingModel !== undefined) {
2908
+ proxyTools.callEmbeddingModel = async (prompt) => {
2909
+ // console.info('[🚕] callEmbeddingModel through countTotalUsage');
2910
+ const promptResult = await llmTools.callEmbeddingModel(prompt);
2911
+ totalUsage = addUsage(totalUsage, promptResult.usage);
2912
+ spending.next(promptResult.usage);
2913
+ return promptResult;
2914
+ };
2915
+ }
2916
+ // <- Note: [🤖]
2917
+ return proxyTools;
2706
2918
  }
2707
2919
  /**
2708
- * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
2920
+ * TODO: [🧠][💸] Maybe make some common abstraction `interceptLlmTools` and use here (or use javascript Proxy?)
2921
+ * TODO: [🧠] Is there some meaningfull way how to test this util
2922
+ * TODO: [🧠][🌯] Maybe a way how to hide ability to `get totalUsage`
2923
+ * > const [llmToolsWithUsage,getUsage] = countTotalUsage(llmTools);
2924
+ * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2709
2925
  */
2710
2926
 
2711
2927
  /**
2712
2928
  * @@@
2713
2929
  *
2714
2930
  * @@@ .env
2715
- * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access .env file
2931
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
2716
2932
  *
2717
2933
  * It looks for environment variables:
2718
2934
  * - `process.env.OPENAI_API_KEY`
@@ -2726,7 +2942,7 @@
2726
2942
  if (!$isRunningInNode()) {
2727
2943
  throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
2728
2944
  }
2729
- const envFilepath = await $provideEnvFilepath();
2945
+ const envFilepath = await $provideEnvFilename();
2730
2946
  if (envFilepath !== null) {
2731
2947
  dotenv__namespace.config({ path: envFilepath });
2732
2948
  }
@@ -2834,14 +3050,15 @@
2834
3050
  }
2835
3051
  }
2836
3052
  catch (error) {
2837
- if (!(error instanceof Error) || error instanceof UnexpectedError) {
3053
+ assertsError(error);
3054
+ if (error instanceof UnexpectedError) {
2838
3055
  throw error;
2839
3056
  }
2840
3057
  errors.push({ llmExecutionTools, error });
2841
3058
  }
2842
3059
  }
2843
3060
  if (errors.length === 1) {
2844
- throw errors[0];
3061
+ throw errors[0].error;
2845
3062
  }
2846
3063
  else if (errors.length > 1) {
2847
3064
  throw new PipelineExecutionError(
@@ -2988,7 +3205,7 @@
2988
3205
  * Note: This function is not cached, every call creates new instance of `MultipleLlmExecutionTools`
2989
3206
  *
2990
3207
  * @@@ .env
2991
- * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access .env file
3208
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
2992
3209
  *
2993
3210
  * It looks for environment variables:
2994
3211
  * - `process.env.OPENAI_API_KEY`
@@ -3033,7 +3250,7 @@
3033
3250
  /**
3034
3251
  * Returns LLM tools for CLI
3035
3252
  *
3036
- * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access .env file and also writes this .env file
3253
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes this .env file
3037
3254
  *
3038
3255
  * @private within the repository - for CLI utils
3039
3256
  */
@@ -3042,18 +3259,27 @@
3042
3259
  throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
3043
3260
  }
3044
3261
  options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
3045
- const { strategy, isCacheReloaded } = options;
3262
+ const { isLoginloaded, strategy, isCacheReloaded } = options;
3046
3263
  let llmExecutionTools;
3047
3264
  if (strategy === 'REMOTE_SERVER') {
3048
3265
  const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
3049
- // TODO: !!!
3050
- // const envFilepath = await $provideEnvFilepath();
3051
- const storage = new MemoryStorage(); // <- TODO: !!!!!! Save to `.promptbook` folder
3052
- const key = `${remoteServerUrl}-identification`;
3053
- let identification = await storage.getItem(key);
3054
- if (identification === null) {
3266
+ const storage = new $EnvStorage();
3267
+ let key = `PROMPTBOOK_TOKEN`;
3268
+ if (remoteServerUrl !== DEFAULT_REMOTE_SERVER_URL) {
3269
+ key = `${key}_${remoteServerUrl.replace(/^https?:\/\//i, '')}`;
3270
+ }
3271
+ let identification = null;
3272
+ let promptbookToken = await storage.getItem(key);
3273
+ if (promptbookToken === null || isLoginloaded) {
3055
3274
  identification = await loginPrompt();
3056
- await storage.setItem(key, identification);
3275
+ // Note: When login prompt fails, `process.exit(1)` is called so no need to check for null
3276
+ if (identification.isAnonymous === false) {
3277
+ promptbookToken = identificationToPromptbookToken(identification);
3278
+ await storage.setItem(key, promptbookToken);
3279
+ }
3280
+ }
3281
+ else {
3282
+ identification = promptbookTokenToIdentification(promptbookToken);
3057
3283
  }
3058
3284
  llmExecutionTools = new RemoteLlmExecutionTools({
3059
3285
  remoteServerUrl,
@@ -3094,9 +3320,7 @@
3094
3320
  return await fetch(urlOrRequest, init);
3095
3321
  }
3096
3322
  catch (error) {
3097
- if (!(error instanceof Error)) {
3098
- throw error;
3099
- }
3323
+ assertsError(error);
3100
3324
  let url;
3101
3325
  if (typeof urlOrRequest === 'string') {
3102
3326
  url = urlOrRequest;
@@ -3135,8 +3359,8 @@
3135
3359
  /**
3136
3360
  * @private utility of CLI
3137
3361
  */
3138
- function $provideLlmToolsForCli(options) {
3139
- const { cliOptions: {
3362
+ async function $provideLlmToolsForCli(options) {
3363
+ const { isLoginloaded, cliOptions: {
3140
3364
  /* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
3141
3365
  let strategy;
3142
3366
  if (/^b/i.test(provider)) {
@@ -3150,7 +3374,11 @@
3150
3374
  process.exit(1);
3151
3375
  }
3152
3376
  if (strategy === 'BRING_YOUR_OWN_KEYS') {
3153
- return /* not await */ $provideLlmToolsForWizzardOrCli({ strategy, ...options });
3377
+ if (isLoginloaded) {
3378
+ throw new UnexpectedError(`\`$provideLlmToolsForCli\` isLoginloaded is not supported for strategy "BRING_YOUR_OWN_KEYS"`);
3379
+ }
3380
+ const llm = await $provideLlmToolsForWizzardOrCli({ strategy, ...options });
3381
+ return { strategy, llm };
3154
3382
  }
3155
3383
  else if (strategy === 'REMOTE_SERVER') {
3156
3384
  if (!isValidUrl(remoteServerUrlRaw)) {
@@ -3158,7 +3386,8 @@
3158
3386
  process.exit(1);
3159
3387
  }
3160
3388
  const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
3161
- return /* not await */ $provideLlmToolsForWizzardOrCli({
3389
+ const llm = await $provideLlmToolsForWizzardOrCli({
3390
+ isLoginloaded,
3162
3391
  strategy,
3163
3392
  appId: CLI_APP_ID,
3164
3393
  remoteServerUrl,
@@ -3168,6 +3397,10 @@
3168
3397
  console.log(colors__default["default"].red(`You can not login to remote server in non-interactive mode`));
3169
3398
  process.exit(1);
3170
3399
  }
3400
+ console.info(colors__default["default"].cyan(spaceTrim__default["default"](`
3401
+ You will be logged in to ${remoteServerUrl}
3402
+ If you don't have an account, it will be created automatically.
3403
+ `)));
3171
3404
  const { username, password } = await prompts__default["default"]([
3172
3405
  {
3173
3406
  type: 'text',
@@ -3185,7 +3418,6 @@
3185
3418
  },
3186
3419
  ]);
3187
3420
  const loginUrl = `${remoteServerUrl}/login`;
3188
- console.log('!!!', { loginUrl });
3189
3421
  // TODO: [🧠] Should we use normal `fetch` or `scraperFetch`
3190
3422
  const response = await promptbookFetch(loginUrl, {
3191
3423
  method: 'POST',
@@ -3198,20 +3430,7 @@
3198
3430
  password,
3199
3431
  }),
3200
3432
  });
3201
- console.log('!!!', {
3202
- loginUrl,
3203
- username,
3204
- password,
3205
- // type: response.type,
3206
- // text: await response.text(),
3207
- });
3208
3433
  const { isSuccess, message, error, identification } = (await response.json());
3209
- console.log('!!!', {
3210
- isSuccess,
3211
- message,
3212
- error,
3213
- identification,
3214
- });
3215
3434
  if (message) {
3216
3435
  if (isSuccess) {
3217
3436
  console.log(colors__default["default"].green(message));
@@ -3232,6 +3451,7 @@
3232
3451
  return identification;
3233
3452
  },
3234
3453
  });
3454
+ return { strategy, llm };
3235
3455
  }
3236
3456
  else {
3237
3457
  throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
@@ -3253,11 +3473,12 @@
3253
3473
  listModelsCommand.alias('models');
3254
3474
  listModelsCommand.alias('llm');
3255
3475
  listModelsCommand.action(handleActionErrors(async (cliOptions) => {
3256
- console.log('!!!', cliOptions);
3257
- // TODO: !!!!!! Not relevant for remote server and also for `about` command
3258
- const llm = await $provideLlmToolsForCli({ cliOptions });
3476
+ const { strategy, llm } = await $provideLlmToolsForCli({ cliOptions });
3259
3477
  $sideEffect(llm);
3260
3478
  // <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
3479
+ if (strategy !== 'BRING_YOUR_OWN_KEYS') {
3480
+ console.warn(colors__default["default"].yellow(`You are using --strategy ${strategy} but models listed below are relevant for --strategy BRING_YOUR_OWN_KEYS`));
3481
+ }
3261
3482
  console.info($registeredLlmToolsMessage());
3262
3483
  return process.exit(0);
3263
3484
  }));
@@ -3440,9 +3661,7 @@
3440
3661
  return result.trim();
3441
3662
  }
3442
3663
  catch (error) {
3443
- if (!(error instanceof Error)) {
3444
- throw error;
3445
- }
3664
+ assertsError(error);
3446
3665
  return null;
3447
3666
  }
3448
3667
  }
@@ -3497,9 +3716,7 @@
3497
3716
  return result.trim() + toExec;
3498
3717
  }
3499
3718
  catch (error) {
3500
- if (!(error instanceof Error)) {
3501
- throw error;
3502
- }
3719
+ assertsError(error);
3503
3720
  return null;
3504
3721
  }
3505
3722
  }
@@ -3530,9 +3747,7 @@
3530
3747
  throw new Error(`Can not locate app ${appName} on Windows.`);
3531
3748
  }
3532
3749
  catch (error) {
3533
- if (!(error instanceof Error)) {
3534
- throw error;
3535
- }
3750
+ assertsError(error);
3536
3751
  return null;
3537
3752
  }
3538
3753
  }
@@ -3791,6 +4006,7 @@
3791
4006
  `));
3792
4007
  listModelsCommand.alias('scrapers');
3793
4008
  listModelsCommand.action(handleActionErrors(async () => {
4009
+ // TODO: [🌞] Do not allow on REMOTE_SERVER strategy
3794
4010
  const scrapers = await $provideScrapersForNode({});
3795
4011
  const executables = await $provideExecutablesForNode();
3796
4012
  console.info(spaceTrim__default["default"]((block) => `
@@ -3826,42 +4042,20 @@
3826
4042
  loginCommand.description(spaceTrim__default["default"](`
3827
4043
  Login to the remote Promptbook server
3828
4044
  `));
3829
- loginCommand.action(handleActionErrors(async () => {
3830
- // @@@
3831
- console.error(colors__default["default"].green(spaceTrim__default["default"](`
3832
- You will be logged in to https://promptbook.studio server.
3833
- If you don't have an account, it will be created automatically.
3834
- `)));
3835
- // !!!!!!!!! Remove from here and use $provideLlmToolsForCli
3836
- const { email, password } = await prompts__default["default"]([
3837
- {
3838
- type: 'text',
3839
- name: 'email',
3840
- message: 'Enter your email:',
3841
- validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
3842
- },
3843
- {
3844
- type: 'password',
3845
- name: 'password',
3846
- message: 'Enter your password:',
3847
- validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0 ? true : 'Password is required',
4045
+ loginCommand.action(handleActionErrors(async (cliOptions) => {
4046
+ // Note: Not interested in return value of this function but the side effect of logging in
4047
+ await $provideLlmToolsForCli({
4048
+ isLoginloaded: true,
4049
+ cliOptions: {
4050
+ ...cliOptions,
4051
+ strategy: 'REMOTE_SERVER', // <- Note: Overriding strategy to `REMOTE_SERVER`
4052
+ // TODO: Do not allow flag `--strategy` in `login` command at all
3848
4053
  },
3849
- ]);
3850
- TODO_USE(email, password);
3851
- await waitasecond.forTime(1000);
3852
- console.error(colors__default["default"].green(spaceTrim__default["default"](`
3853
- Your account ${email} was successfully created.
3854
-
3855
- Please verify your email:
3856
- https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
3857
-
3858
- After verification, you will receive 500 000 credits for free 🎉
3859
- `)));
4054
+ });
3860
4055
  return process.exit(0);
3861
4056
  }));
3862
4057
  }
3863
4058
  /**
3864
- * TODO: Pass remote server URL (and path)
3865
4059
  * TODO: Implement non-interactive login
3866
4060
  * Note: [💞] Ignore a discrepancy between file name and entity name
3867
4061
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
@@ -4282,6 +4476,9 @@
4282
4476
  /**
4283
4477
  * Function isValidJsonString will tell you if the string is valid JSON or not
4284
4478
  *
4479
+ * @param value The string to check
4480
+ * @returns True if the string is a valid JSON string, false otherwise
4481
+ *
4285
4482
  * @public exported from `@promptbook/utils`
4286
4483
  */
4287
4484
  function isValidJsonString(value /* <- [👨‍⚖️] */) {
@@ -4290,9 +4487,7 @@
4290
4487
  return true;
4291
4488
  }
4292
4489
  catch (error) {
4293
- if (!(error instanceof Error)) {
4294
- throw error;
4295
- }
4490
+ assertsError(error);
4296
4491
  if (error.message.includes('Unexpected token')) {
4297
4492
  return false;
4298
4493
  }
@@ -4823,8 +5018,8 @@
4823
5018
  updatedAt = new Date();
4824
5019
  errors.push(...executionResult.errors);
4825
5020
  warnings.push(...executionResult.warnings);
4826
- // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
4827
- // TODO: [🧠] !!! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
5021
+ // <- TODO: [🌂] Only unique errors and warnings should be added (or filtered)
5022
+ // TODO: [🧠] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
4828
5023
  // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
4829
5024
  // And delete `ExecutionTask.currentValue.preparedPipeline`
4830
5025
  assertsTaskSuccessful(executionResult);
@@ -4834,6 +5029,7 @@
4834
5029
  partialResultSubject.next(executionResult);
4835
5030
  }
4836
5031
  catch (error) {
5032
+ assertsError(error);
4837
5033
  status = 'ERROR';
4838
5034
  errors.push(error);
4839
5035
  partialResultSubject.error(error);
@@ -4979,13 +5175,19 @@
4979
5175
  return value.toISOString();
4980
5176
  }
4981
5177
  else {
4982
- return JSON.stringify(value);
5178
+ try {
5179
+ return JSON.stringify(value);
5180
+ }
5181
+ catch (error) {
5182
+ if (error instanceof TypeError && error.message.includes('circular structure')) {
5183
+ return VALUE_STRINGS.circular;
5184
+ }
5185
+ throw error;
5186
+ }
4983
5187
  }
4984
5188
  }
4985
5189
  catch (error) {
4986
- if (!(error instanceof Error)) {
4987
- throw error;
4988
- }
5190
+ assertsError(error);
4989
5191
  console.error(error);
4990
5192
  return VALUE_STRINGS.unserializable;
4991
5193
  }
@@ -5042,9 +5244,7 @@
5042
5244
  }
5043
5245
  }
5044
5246
  catch (error) {
5045
- if (!(error instanceof Error)) {
5046
- throw error;
5047
- }
5247
+ assertsError(error);
5048
5248
  throw new ParseError(spaceTrim.spaceTrim((block) => `
5049
5249
  Can not extract variables from the script
5050
5250
  ${block(error.stack || error.message)}
@@ -5163,6 +5363,28 @@
5163
5363
  // encoding: 'utf-8',
5164
5364
  });
5165
5365
 
5366
+ /**
5367
+ * Function to check if a string is valid CSV
5368
+ *
5369
+ * @param value The string to check
5370
+ * @returns True if the string is a valid CSV string, false otherwise
5371
+ *
5372
+ * @public exported from `@promptbook/utils`
5373
+ */
5374
+ function isValidCsvString(value) {
5375
+ try {
5376
+ // A simple check for CSV format: at least one comma and no invalid characters
5377
+ if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
5378
+ return true;
5379
+ }
5380
+ return false;
5381
+ }
5382
+ catch (error) {
5383
+ assertsError(error);
5384
+ return false;
5385
+ }
5386
+ }
5387
+
5166
5388
  /**
5167
5389
  * Definition for CSV spreadsheet
5168
5390
  *
@@ -5173,7 +5395,7 @@
5173
5395
  formatName: 'CSV',
5174
5396
  aliases: ['SPREADSHEET', 'TABLE'],
5175
5397
  isValid(value, settings, schema) {
5176
- return true;
5398
+ return isValidCsvString(value);
5177
5399
  },
5178
5400
  canBeValid(partialValue, settings, schema) {
5179
5401
  return true;
@@ -5327,6 +5549,30 @@
5327
5549
  * TODO: [🏢] Allow to expect something inside each item of list and other formats
5328
5550
  */
5329
5551
 
5552
+ /**
5553
+ * Function to check if a string is valid XML
5554
+ *
5555
+ * @param value
5556
+ * @returns True if the string is a valid XML string, false otherwise
5557
+ *
5558
+ * @public exported from `@promptbook/utils`
5559
+ */
5560
+ function isValidXmlString(value) {
5561
+ try {
5562
+ const parser = new DOMParser();
5563
+ const parsedDocument = parser.parseFromString(value, 'application/xml');
5564
+ const parserError = parsedDocument.getElementsByTagName('parsererror');
5565
+ if (parserError.length > 0) {
5566
+ return false;
5567
+ }
5568
+ return true;
5569
+ }
5570
+ catch (error) {
5571
+ assertsError(error);
5572
+ return false;
5573
+ }
5574
+ }
5575
+
5330
5576
  /**
5331
5577
  * Definition for XML format
5332
5578
  *
@@ -5336,7 +5582,7 @@
5336
5582
  formatName: 'XML',
5337
5583
  mimeType: 'application/xml',
5338
5584
  isValid(value, settings, schema) {
5339
- return true;
5585
+ return isValidXmlString(value);
5340
5586
  },
5341
5587
  canBeValid(partialValue, settings, schema) {
5342
5588
  return true;
@@ -5928,9 +6174,7 @@
5928
6174
  break scripts;
5929
6175
  }
5930
6176
  catch (error) {
5931
- if (!(error instanceof Error)) {
5932
- throw error;
5933
- }
6177
+ assertsError(error);
5934
6178
  if (error instanceof UnexpectedError) {
5935
6179
  throw error;
5936
6180
  }
@@ -6000,9 +6244,7 @@
6000
6244
  break scripts;
6001
6245
  }
6002
6246
  catch (error) {
6003
- if (!(error instanceof Error)) {
6004
- throw error;
6005
- }
6247
+ assertsError(error);
6006
6248
  if (error instanceof UnexpectedError) {
6007
6249
  throw error;
6008
6250
  }
@@ -6623,9 +6865,7 @@
6623
6865
  await Promise.all(resolving);
6624
6866
  }
6625
6867
  catch (error /* <- Note: [3] */) {
6626
- if (!(error instanceof Error)) {
6627
- throw error;
6628
- }
6868
+ assertsError(error);
6629
6869
  // Note: No need to rethrow UnexpectedError
6630
6870
  // if (error instanceof UnexpectedError) {
6631
6871
  // Note: Count usage, [🧠] Maybe put to separate function executionReportJsonToUsage + DRY [🤹‍♂️]
@@ -7101,9 +7341,7 @@
7101
7341
  knowledgePreparedUnflatten[index] = pieces;
7102
7342
  }
7103
7343
  catch (error) {
7104
- if (!(error instanceof Error)) {
7105
- throw error;
7106
- }
7344
+ assertsError(error);
7107
7345
  console.warn(error);
7108
7346
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
7109
7347
  }
@@ -7901,6 +8139,8 @@
7901
8139
  */
7902
8140
 
7903
8141
  /**
8142
+ import { WrappedError } from '../../errors/WrappedError';
8143
+ import { assertsError } from '../../errors/assertsError';
7904
8144
  * Parses the expect command
7905
8145
  *
7906
8146
  * @see `documentationUrl` for more details
@@ -7992,9 +8232,7 @@
7992
8232
  };
7993
8233
  }
7994
8234
  catch (error) {
7995
- if (!(error instanceof Error)) {
7996
- throw error;
7997
- }
8235
+ assertsError(error);
7998
8236
  throw new ParseError(spaceTrim__default["default"]((block) => `
7999
8237
  Invalid FORMAT command
8000
8238
  ${block(error.message)}:
@@ -11242,9 +11480,7 @@
11242
11480
  }
11243
11481
  }
11244
11482
  catch (error) {
11245
- if (!(error instanceof Error)) {
11246
- throw error;
11247
- }
11483
+ assertsError(error);
11248
11484
  if (error instanceof ReferenceError) {
11249
11485
  const undefinedName = error.message.split(' ')[0];
11250
11486
  /*
@@ -11519,9 +11755,7 @@
11519
11755
  // ---
11520
11756
  }
11521
11757
  catch (error) {
11522
- if (!(error instanceof Error)) {
11523
- throw error;
11524
- }
11758
+ assertsError(error);
11525
11759
  // TODO: [7] DRY
11526
11760
  const wrappedErrorMessage = spaceTrim__default["default"]((block) => `
11527
11761
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
@@ -11612,9 +11846,7 @@
11612
11846
  }
11613
11847
  }
11614
11848
  catch (error) {
11615
- if (!(error instanceof Error)) {
11616
- throw error;
11617
- }
11849
+ assertsError(error);
11618
11850
  // TODO: [7] DRY
11619
11851
  const wrappedErrorMessage = spaceTrim__default["default"]((block) => `
11620
11852
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
@@ -11830,7 +12062,7 @@
11830
12062
  isCacheReloaded,
11831
12063
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
11832
12064
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
11833
- const llm = await $provideLlmToolsForCli({
12065
+ const { llm } = await $provideLlmToolsForCli({
11834
12066
  cliOptions,
11835
12067
  ...prepareAndScrapeOptions,
11836
12068
  });
@@ -12123,9 +12355,7 @@
12123
12355
  }
12124
12356
  }
12125
12357
  catch (error) {
12126
- if (!(error instanceof Error)) {
12127
- throw error;
12128
- }
12358
+ assertsError(error);
12129
12359
  console.info(colors__default["default"].red(`Prettify ${error.name} ${filename}`));
12130
12360
  console.error(colors__default["default"].bgRed(`${error.name} in ${path.basename(__filename)}`));
12131
12361
  console.error(colors__default["default"].red(error.stack || error.message));
@@ -12445,9 +12675,7 @@
12445
12675
  return true;
12446
12676
  }
12447
12677
  catch (error) {
12448
- if (!(error instanceof Error)) {
12449
- throw error;
12450
- }
12678
+ assertsError(error);
12451
12679
  return false;
12452
12680
  }
12453
12681
  }
@@ -12672,9 +12900,7 @@
12672
12900
  ongoingParameters = result.outputParameters;
12673
12901
  }
12674
12902
  catch (error) {
12675
- if (!(error instanceof Error)) {
12676
- throw error;
12677
- }
12903
+ assertsError(error);
12678
12904
  // TODO: Allow to ressurect the chatbot after an error - prompt the user to continue
12679
12905
  console.error(colors__default["default"].red(error.stack || error.message));
12680
12906
  return process.exit(1);
@@ -12707,7 +12933,6 @@
12707
12933
  runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
12708
12934
  runCommand.option('-s, --save-report <path>', `Save report to file`);
12709
12935
  runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
12710
- console.log('!!!', cliOptions);
12711
12936
  const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
12712
12937
  if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
12713
12938
  console.error(colors__default["default"].red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
@@ -12733,12 +12958,10 @@
12733
12958
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
12734
12959
  let llm;
12735
12960
  try {
12736
- llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
12961
+ llm = (await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions })).llm;
12737
12962
  }
12738
12963
  catch (error) {
12739
- if (!(error instanceof Error)) {
12740
- throw error;
12741
- }
12964
+ assertsError(error);
12742
12965
  if (!error.message.includes('No LLM tools')) {
12743
12966
  throw error;
12744
12967
  }
@@ -12944,6 +13167,198 @@
12944
13167
  * TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
12945
13168
  */
12946
13169
 
13170
+ // TODO: !!!! List running services from REMOTE_SERVER_URLS
13171
+ // TODO: !!!! Import directly from YML
13172
+ /**
13173
+ * @private !!!! Decide how to expose this
13174
+ */
13175
+ const openapiJson = {
13176
+ openapi: '3.0.0',
13177
+ info: {
13178
+ title: 'Promptbook Remote Server API (!!!! From TS)',
13179
+ version: '1.0.0',
13180
+ description: 'API documentation for the Promptbook Remote Server',
13181
+ },
13182
+ paths: {
13183
+ '/': {
13184
+ get: {
13185
+ summary: 'Get server details',
13186
+ description: 'Returns details about the Promptbook server.',
13187
+ responses: {
13188
+ '200': {
13189
+ description: 'Server details in markdown format.',
13190
+ },
13191
+ },
13192
+ },
13193
+ },
13194
+ '/login': {
13195
+ post: {
13196
+ summary: 'Login to the server',
13197
+ description: 'Login to the server and get identification.',
13198
+ requestBody: {
13199
+ required: true,
13200
+ content: {
13201
+ 'application/json': {
13202
+ schema: {
13203
+ type: 'object',
13204
+ properties: {
13205
+ username: {
13206
+ type: 'string',
13207
+ },
13208
+ password: {
13209
+ type: 'string',
13210
+ },
13211
+ appId: {
13212
+ type: 'string',
13213
+ },
13214
+ },
13215
+ },
13216
+ },
13217
+ },
13218
+ },
13219
+ responses: {
13220
+ '200': {
13221
+ description: 'Successful login',
13222
+ content: {
13223
+ 'application/json': {
13224
+ schema: {
13225
+ type: 'object',
13226
+ properties: {
13227
+ identification: {
13228
+ type: 'object',
13229
+ },
13230
+ },
13231
+ },
13232
+ },
13233
+ },
13234
+ },
13235
+ },
13236
+ },
13237
+ },
13238
+ '/books': {
13239
+ get: {
13240
+ summary: 'List all books',
13241
+ description: 'Returns a list of all available books in the collection.',
13242
+ responses: {
13243
+ '200': {
13244
+ description: 'A list of books.',
13245
+ content: {
13246
+ 'application/json': {
13247
+ schema: {
13248
+ type: 'array',
13249
+ items: {
13250
+ type: 'string',
13251
+ },
13252
+ },
13253
+ },
13254
+ },
13255
+ },
13256
+ },
13257
+ },
13258
+ },
13259
+ '/books/{bookId}': {
13260
+ get: {
13261
+ summary: 'Get book content',
13262
+ description: 'Returns the content of a specific book.',
13263
+ parameters: [
13264
+ {
13265
+ in: 'path',
13266
+ name: 'bookId',
13267
+ required: true,
13268
+ schema: {
13269
+ type: 'string',
13270
+ },
13271
+ description: 'The ID of the book to retrieve.',
13272
+ },
13273
+ ],
13274
+ responses: {
13275
+ '200': {
13276
+ description: 'The content of the book.',
13277
+ content: {
13278
+ 'text/markdown': {
13279
+ schema: {
13280
+ type: 'string',
13281
+ },
13282
+ },
13283
+ },
13284
+ },
13285
+ '404': {
13286
+ description: 'Book not found.',
13287
+ },
13288
+ },
13289
+ },
13290
+ },
13291
+ '/executions': {
13292
+ get: {
13293
+ summary: 'List all executions',
13294
+ description: 'Returns a list of all running execution tasks.',
13295
+ responses: {
13296
+ '200': {
13297
+ description: 'A list of execution tasks.',
13298
+ content: {
13299
+ 'application/json': {
13300
+ schema: {
13301
+ type: 'array',
13302
+ items: {
13303
+ type: 'object',
13304
+ },
13305
+ },
13306
+ },
13307
+ },
13308
+ },
13309
+ },
13310
+ },
13311
+ },
13312
+ '/executions/new': {
13313
+ post: {
13314
+ summary: 'Start a new execution',
13315
+ description: 'Starts a new execution task for a given pipeline.',
13316
+ requestBody: {
13317
+ required: true,
13318
+ content: {
13319
+ 'application/json': {
13320
+ schema: {
13321
+ type: 'object',
13322
+ properties: {
13323
+ pipelineUrl: {
13324
+ type: 'string',
13325
+ },
13326
+ inputParameters: {
13327
+ type: 'object',
13328
+ },
13329
+ identification: {
13330
+ type: 'object',
13331
+ },
13332
+ },
13333
+ },
13334
+ },
13335
+ },
13336
+ },
13337
+ responses: {
13338
+ '200': {
13339
+ description: 'The newly created execution task.',
13340
+ content: {
13341
+ 'application/json': {
13342
+ schema: {
13343
+ type: 'object',
13344
+ },
13345
+ },
13346
+ },
13347
+ },
13348
+ '400': {
13349
+ description: 'Invalid input.',
13350
+ },
13351
+ },
13352
+ },
13353
+ },
13354
+ },
13355
+ components: {},
13356
+ tags: [],
13357
+ };
13358
+ /**
13359
+ * Note: [💞] Ignore a discrepancy between file name and entity name
13360
+ */
13361
+
12947
13362
  /**
12948
13363
  * Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
12949
13364
  *
@@ -12954,7 +13369,7 @@
12954
13369
  * @public exported from `@promptbook/remote-server`
12955
13370
  */
12956
13371
  function startRemoteServer(options) {
12957
- const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
13372
+ const { port, collection, createLlmExecutionTools, createExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
12958
13373
  isAnonymousModeAllowed: false,
12959
13374
  isApplicationModeAllowed: false,
12960
13375
  collection: null,
@@ -12962,22 +13377,6 @@
12962
13377
  login: null,
12963
13378
  ...options,
12964
13379
  };
12965
- // <- TODO: [🦪] Some helper type to be able to use discriminant union types with destructuring
12966
- let { rootPath = '/' } = options;
12967
- if (!rootPath.startsWith('/')) {
12968
- rootPath = `/${rootPath}`;
12969
- } /* not else */
12970
- if (rootPath.endsWith('/')) {
12971
- rootPath = rootPath.slice(0, -1);
12972
- } /* not else */
12973
- if (rootPath === '/') {
12974
- rootPath = '';
12975
- }
12976
- const socketioPath = '/' +
12977
- `${rootPath}/socket.io`
12978
- .split('/')
12979
- .filter((part) => part !== '')
12980
- .join('/');
12981
13380
  const startupDate = new Date();
12982
13381
  async function getExecutionToolsFromIdentification(identification) {
12983
13382
  if (identification === null || identification === undefined) {
@@ -13000,23 +13399,25 @@
13000
13399
  }
13001
13400
  else if (isAnonymous === false && createLlmExecutionTools !== null) {
13002
13401
  // Note: Application mode
13003
- const { appId, userId, customOptions } = identification;
13004
- llm = await createLlmExecutionTools({
13005
- appId,
13006
- userId,
13007
- customOptions,
13008
- });
13402
+ llm = await createLlmExecutionTools(identification);
13009
13403
  }
13010
13404
  else {
13011
13405
  throw new PipelineExecutionError(`You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured`);
13012
13406
  }
13013
- const fs = $provideFilesystemForNode();
13014
- const executables = await $provideExecutablesForNode();
13407
+ const customExecutionTools = createExecutionTools ? await createExecutionTools(identification) : {};
13408
+ const fs = customExecutionTools.fs || $provideFilesystemForNode();
13409
+ const executables = customExecutionTools.executables || (await $provideExecutablesForNode());
13410
+ const scrapers = customExecutionTools.scrapers || (await $provideScrapersForNode({ fs, llm, executables }));
13411
+ const script = customExecutionTools.script || (await $provideScriptingForNode({}));
13412
+ const fetch = customExecutionTools.fetch || promptbookFetch;
13413
+ const userInterface = customExecutionTools.userInterface || undefined;
13015
13414
  const tools = {
13016
13415
  llm,
13017
13416
  fs,
13018
- scrapers: await $provideScrapersForNode({ fs, llm, executables }),
13019
- script: await $provideScriptingForNode({}),
13417
+ scrapers,
13418
+ script,
13419
+ fetch,
13420
+ userInterface,
13020
13421
  };
13021
13422
  return tools;
13022
13423
  }
@@ -13026,39 +13427,27 @@
13026
13427
  response.setHeader('X-Powered-By', 'Promptbook engine');
13027
13428
  next();
13028
13429
  });
13029
- const swaggerOptions = {
13030
- definition: {
13031
- openapi: '3.0.0',
13032
- info: {
13033
- title: 'Promptbook Remote Server API',
13034
- version: '1.0.0',
13035
- description: 'API documentation for the Promptbook Remote Server',
13036
- },
13037
- servers: [
13038
- {
13039
- url: `http://localhost:${port}${rootPath}`,
13040
- // <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
13041
- },
13042
- ],
13430
+ // TODO: !!!! Expose openapiJson to consumer and also allow to add new routes
13431
+ app.use(OpenApiValidator__namespace.middleware({
13432
+ apiSpec: openapiJson,
13433
+ ignorePaths(path) {
13434
+ return path.startsWith('/api-docs') || path.startsWith('/swagger') || path.startsWith('/openapi');
13043
13435
  },
13044
- apis: ['./src/remote-server/**/*.ts'], // Adjust path as needed
13045
- };
13046
- const swaggerSpec = swaggerJsdoc__default["default"](swaggerOptions);
13047
- app.use([`/api-docs`, `${rootPath}/api-docs`], swaggerUi__default["default"].serve, swaggerUi__default["default"].setup(swaggerSpec));
13436
+ validateRequests: true,
13437
+ validateResponses: true,
13438
+ }));
13439
+ app.use([`/api-docs`, `/swagger`], swaggerUi__default["default"].serve, swaggerUi__default["default"].setup(openapiJson, {
13440
+ // customCss: '.swagger-ui .topbar { display: none }',
13441
+ // customSiteTitle: 'BRJ API',
13442
+ // customfavIcon: 'https://brj.app/favicon.ico',
13443
+ }));
13444
+ app.get(`/openapi`, (request, response) => {
13445
+ response.json(openapiJson);
13446
+ });
13048
13447
  const runningExecutionTasks = [];
13049
13448
  // <- TODO: [🤬] Identify the users
13050
13449
  // TODO: [🧠] Do here some garbage collection of finished tasks
13051
- /**
13052
- * @swagger
13053
- * /:
13054
- * get:
13055
- * summary: Get server details
13056
- * description: Returns details about the Promptbook server.
13057
- * responses:
13058
- * 200:
13059
- * description: Server details in markdown format.
13060
- */
13061
- app.get(['/', rootPath], async (request, response) => {
13450
+ app.get('/', async (request, response) => {
13062
13451
  var _a;
13063
13452
  if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
13064
13453
  return;
@@ -13077,8 +13466,6 @@
13077
13466
  ## Details
13078
13467
 
13079
13468
  **Server port:** ${port}
13080
- **Server root path:** ${rootPath}
13081
- **Socket.io path:** ${socketioPath}
13082
13469
  **Startup date:** ${startupDate.toISOString()}
13083
13470
  **Anonymouse mode:** ${isAnonymousModeAllowed ? 'enabled' : 'disabled'}
13084
13471
  **Application mode:** ${isApplicationModeAllowed ? 'enabled' : 'disabled'}
@@ -13117,38 +13504,7 @@
13117
13504
  https://github.com/webgptorg/promptbook
13118
13505
  `));
13119
13506
  });
13120
- /**
13121
- * @swagger
13122
- *
13123
- * /login:
13124
- * post:
13125
- * summary: Login to the server
13126
- * description: Login to the server and get identification.
13127
- * requestBody:
13128
- * required: true
13129
- * content:
13130
- * application/json:
13131
- * schema:
13132
- * type: object
13133
- * properties:
13134
- * username:
13135
- * type: string
13136
- * password:
13137
- * type: string
13138
- * appId:
13139
- * type: string
13140
- * responses:
13141
- * 200:
13142
- * description: Successful login
13143
- * content:
13144
- * application/json:
13145
- * schema:
13146
- * type: object
13147
- * properties:
13148
- * identification:
13149
- * type: object
13150
- */
13151
- app.post([`/login`, `${rootPath}/login`], async (request, response) => {
13507
+ app.post(`/login`, async (request, response) => {
13152
13508
  if (!isApplicationModeAllowed || login === null) {
13153
13509
  response.status(400).send('Application mode is not allowed');
13154
13510
  return;
@@ -13173,9 +13529,7 @@
13173
13529
  return;
13174
13530
  }
13175
13531
  catch (error) {
13176
- if (!(error instanceof Error)) {
13177
- throw error;
13178
- }
13532
+ assertsError(error);
13179
13533
  if (error instanceof AuthenticationError) {
13180
13534
  response.status(401).send({
13181
13535
  isSuccess: false,
@@ -13190,23 +13544,7 @@
13190
13544
  response.status(400).send({ error: serializeError(error) });
13191
13545
  }
13192
13546
  });
13193
- /**
13194
- * @swagger
13195
- * /books:
13196
- * get:
13197
- * summary: List all books
13198
- * description: Returns a list of all available books in the collection.
13199
- * responses:
13200
- * 200:
13201
- * description: A list of books.
13202
- * content:
13203
- * application/json:
13204
- * schema:
13205
- * type: array
13206
- * items:
13207
- * type: string
13208
- */
13209
- app.get([`/books`, `${rootPath}/books`], async (request, response) => {
13547
+ app.get(`/books`, async (request, response) => {
13210
13548
  if (collection === null) {
13211
13549
  response.status(500).send('No collection available');
13212
13550
  return;
@@ -13216,30 +13554,7 @@
13216
13554
  response.send(pipelines);
13217
13555
  });
13218
13556
  // TODO: [🧠] Is it secure / good idea to expose source codes of hosted books
13219
- /**
13220
- * @swagger
13221
- * /books/{bookId}:
13222
- * get:
13223
- * summary: Get book content
13224
- * description: Returns the content of a specific book.
13225
- * parameters:
13226
- * - in: path
13227
- * name: bookId
13228
- * required: true
13229
- * schema:
13230
- * type: string
13231
- * description: The ID of the book to retrieve.
13232
- * responses:
13233
- * 200:
13234
- * description: The content of the book.
13235
- * content:
13236
- * text/markdown:
13237
- * schema:
13238
- * type: string
13239
- * 404:
13240
- * description: Book not found.
13241
- */
13242
- app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
13557
+ app.get(`/books/*`, async (request, response) => {
13243
13558
  try {
13244
13559
  if (collection === null) {
13245
13560
  response.status(500).send('No collection nor books available');
@@ -13258,9 +13573,7 @@
13258
13573
  .send(source.content);
13259
13574
  }
13260
13575
  catch (error) {
13261
- if (!(error instanceof Error)) {
13262
- throw error;
13263
- }
13576
+ assertsError(error);
13264
13577
  response
13265
13578
  .status(404)
13266
13579
  .send({ error: serializeError(error) });
@@ -13293,26 +13606,10 @@
13293
13606
  };
13294
13607
  }
13295
13608
  }
13296
- /**
13297
- * @swagger
13298
- * /executions:
13299
- * get:
13300
- * summary: List all executions
13301
- * description: Returns a list of all running execution tasks.
13302
- * responses:
13303
- * 200:
13304
- * description: A list of execution tasks.
13305
- * content:
13306
- * application/json:
13307
- * schema:
13308
- * type: array
13309
- * items:
13310
- * type: object
13311
- */
13312
- app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
13313
- response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
13609
+ app.get(`/executions`, async (request, response) => {
13610
+ response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)) /* <- TODO: satisfies paths['/executions']['get']['responses']['200']['content']['application/json'] */);
13314
13611
  });
13315
- app.get([`/executions/last`, `${rootPath}/executions/last`], async (request, response) => {
13612
+ app.get(`/executions/last`, async (request, response) => {
13316
13613
  // TODO: [🤬] Filter only for user
13317
13614
  if (runningExecutionTasks.length === 0) {
13318
13615
  response.status(404).send('No execution tasks found');
@@ -13321,7 +13618,7 @@
13321
13618
  const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
13322
13619
  response.send(exportExecutionTask(lastExecutionTask, true));
13323
13620
  });
13324
- app.get([`/executions/:taskId`, `${rootPath}/executions/:taskId`], async (request, response) => {
13621
+ app.get(`/executions/:taskId`, async (request, response) => {
13325
13622
  const { taskId } = request.params;
13326
13623
  // TODO: [🤬] Filter only for user
13327
13624
  const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
@@ -13333,39 +13630,12 @@
13333
13630
  }
13334
13631
  response.send(exportExecutionTask(executionTask, true));
13335
13632
  });
13336
- /**
13337
- * @swagger
13338
- * /executions/new:
13339
- * post:
13340
- * summary: Start a new execution
13341
- * description: Starts a new execution task for a given pipeline.
13342
- * requestBody:
13343
- * required: true
13344
- * content:
13345
- * application/json:
13346
- * schema:
13347
- * type: object
13348
- * properties:
13349
- * pipelineUrl:
13350
- * type: string
13351
- * inputParameters:
13352
- * type: object
13353
- * identification:
13354
- * type: object
13355
- * responses:
13356
- * 200:
13357
- * description: The newly created execution task.
13358
- * content:
13359
- * application/json:
13360
- * schema:
13361
- * type: object
13362
- * 400:
13363
- * description: Invalid input.
13364
- */
13365
- app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
13633
+ app.post(`/executions/new`, async (request, response) => {
13366
13634
  try {
13367
13635
  const { inputParameters, identification /* <- [🤬] */ } = request.body;
13368
- const pipelineUrl = request.body.pipelineUrl || request.body.book;
13636
+ const pipelineUrl = request.body
13637
+ .pipelineUrl /* <- TODO: as paths['/executions/new']['post']['requestBody']['content']['application/json'] */ ||
13638
+ request.body.book;
13369
13639
  // TODO: [🧠] Check `pipelineUrl` and `inputParameters` here or it should be responsibility of `collection.getPipelineByUrl` and `pipelineExecutor`
13370
13640
  const pipeline = await (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl));
13371
13641
  if (pipeline === undefined) {
@@ -13379,7 +13649,7 @@
13379
13649
  await waitasecond.forTime(10);
13380
13650
  // <- Note: Wait for a while to wait for quick responses or sudden but asynchronous errors
13381
13651
  // <- TODO: Put this into configuration
13382
- response.send(executionTask);
13652
+ response.send(executionTask /* <- TODO: satisfies paths['/executions/new']['post']['responses']['200']['content']['application/json'] */);
13383
13653
  /*/
13384
13654
  executionTask.asObservable().subscribe({
13385
13655
  next(partialResult) {
@@ -13399,19 +13669,24 @@
13399
13669
  */
13400
13670
  }
13401
13671
  catch (error) {
13402
- if (!(error instanceof Error)) {
13403
- throw error;
13404
- }
13672
+ assertsError(error);
13405
13673
  response.status(400).send({ error: serializeError(error) });
13406
13674
  }
13407
13675
  });
13676
+ /**
13677
+ * Catch-all handler for unmatched routes
13678
+ */
13679
+ app.use((request, response) => {
13680
+ response.status(404).send(`URL "${request.originalUrl}" was not found on Promptbook server.`);
13681
+ });
13408
13682
  const httpServer = http__default["default"].createServer(app);
13409
13683
  const server = new socket_io.Server(httpServer, {
13410
- path: socketioPath,
13411
- transports: [/*'websocket', <- TODO: [🌬] Make websocket transport work */ 'polling'],
13684
+ path: '/socket.io',
13685
+ transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
13412
13686
  cors: {
13413
13687
  origin: '*',
13414
13688
  methods: ['GET', 'POST'],
13689
+ // <- TODO: [🌡] Allow to pass
13415
13690
  },
13416
13691
  });
13417
13692
  server.on('connection', (socket) => {
@@ -13465,9 +13740,7 @@
13465
13740
  socket.emit('prompt-response', { promptResult } /* <- Note: [🤛] */);
13466
13741
  }
13467
13742
  catch (error) {
13468
- if (!(error instanceof Error)) {
13469
- throw error;
13470
- }
13743
+ assertsError(error);
13471
13744
  socket.emit('error', serializeError(error) /* <- Note: [🤛] */);
13472
13745
  }
13473
13746
  finally {
@@ -13489,9 +13762,7 @@
13489
13762
  socket.emit('listModels-response', { models } /* <- Note: [🤛] */);
13490
13763
  }
13491
13764
  catch (error) {
13492
- if (!(error instanceof Error)) {
13493
- throw error;
13494
- }
13765
+ assertsError(error);
13495
13766
  socket.emit('error', serializeError(error));
13496
13767
  }
13497
13768
  finally {
@@ -13512,9 +13783,7 @@
13512
13783
  socket.emit('preparePipeline-response', { preparedPipeline } /* <- Note: [🤛] */);
13513
13784
  }
13514
13785
  catch (error) {
13515
- if (!(error instanceof Error)) {
13516
- throw error;
13517
- }
13786
+ assertsError(error);
13518
13787
  socket.emit('error', serializeError(error));
13519
13788
  // <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
13520
13789
  }
@@ -13562,8 +13831,7 @@
13562
13831
  };
13563
13832
  }
13564
13833
  /**
13565
- * TODO: !! Add CORS and security - probbably via `helmet`
13566
- * TODO: [👩🏾‍🤝‍🧑🏾] Allow to pass custom fetch function here - PromptbookFetch
13834
+ * TODO: [🌡] Add CORS and security - probbably via `helmet`
13567
13835
  * TODO: Split this file into multiple functions - handler for each request
13568
13836
  * TODO: Maybe use `$exportJson`
13569
13837
  * TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
@@ -13622,9 +13890,9 @@
13622
13890
  if (url !== null) {
13623
13891
  rootUrl = suffixUrl(url, '/books');
13624
13892
  }
13625
- let rootPath = '/';
13626
- if (url !== null) {
13627
- rootPath = url.pathname;
13893
+ if (url !== null && url.pathname !== '/' && url.pathname !== '') {
13894
+ console.error(colors__default["default"].red(`URL of the server can not have path, but got "${url.pathname}"`));
13895
+ process.exit(1);
13628
13896
  }
13629
13897
  // TODO: DRY [◽]
13630
13898
  const prepareAndScrapeOptions = {
@@ -13632,7 +13900,7 @@
13632
13900
  isCacheReloaded,
13633
13901
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13634
13902
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13635
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13903
+ const { /* [0] strategy,*/ llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13636
13904
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13637
13905
  const tools = {
13638
13906
  llm,
@@ -13651,7 +13919,6 @@
13651
13919
  });
13652
13920
  // console.log(path, await collection.listPipelines());
13653
13921
  const server = startRemoteServer({
13654
- rootPath,
13655
13922
  port,
13656
13923
  isAnonymousModeAllowed,
13657
13924
  isApplicationModeAllowed: true,
@@ -13664,6 +13931,7 @@
13664
13931
  TODO_USE({ appId, userId });
13665
13932
  return llm;
13666
13933
  },
13934
+ // <- TODO: [🧠][0] Maybe pass here strategy
13667
13935
  });
13668
13936
  keepUnused(server);
13669
13937
  // Note: Already logged by `startRemoteServer`
@@ -13705,7 +13973,7 @@
13705
13973
  isCacheReloaded,
13706
13974
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13707
13975
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13708
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13976
+ const { llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13709
13977
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13710
13978
  tools = {
13711
13979
  llm,
@@ -13744,9 +14012,7 @@
13744
14012
  }
13745
14013
  }
13746
14014
  catch (error) {
13747
- if (!(error instanceof Error)) {
13748
- throw error;
13749
- }
14015
+ assertsError(error);
13750
14016
  console.info(colors__default["default"].red(`Pipeline is not valid ${filename}`));
13751
14017
  console.error(colors__default["default"].bgRed(`${error.name} in ${path.basename(__filename)}`));
13752
14018
  console.error(colors__default["default"].red(error.stack || error.message));
@@ -13970,7 +14236,25 @@
13970
14236
  output: computeUsage(`$2.40 / 1M tokens`),
13971
14237
  },
13972
14238
  },
13973
- // TODO: [main] !!3 Claude 1 and 2 has also completion versions - ask Hoagy
14239
+ {
14240
+ modelVariant: 'CHAT',
14241
+ modelTitle: 'Claude 3.7 Sonnet',
14242
+ modelName: 'claude-3-7-sonnet-20250219',
14243
+ pricing: {
14244
+ prompt: computeUsage(`$3.00 / 1M tokens`),
14245
+ output: computeUsage(`$15.00 / 1M tokens`),
14246
+ },
14247
+ },
14248
+ {
14249
+ modelVariant: 'CHAT',
14250
+ modelTitle: 'Claude 3.5 Haiku',
14251
+ modelName: 'claude-3-5-haiku-20241022',
14252
+ pricing: {
14253
+ prompt: computeUsage(`$0.25 / 1M tokens`),
14254
+ output: computeUsage(`$1.25 / 1M tokens`),
14255
+ },
14256
+ },
14257
+ // <- [🕕]
13974
14258
  ],
13975
14259
  });
13976
14260
  /**
@@ -14735,7 +15019,6 @@
14735
15019
  prompt: computeUsage(`$5.00 / 1M tokens`),
14736
15020
  output: computeUsage(`$15.00 / 1M tokens`),
14737
15021
  },
14738
- //TODO: [main] !!3 Add gpt-4o-mini-2024-07-18 and all others to be up to date
14739
15022
  },
14740
15023
  /**/
14741
15024
  /**/
@@ -14750,6 +15033,17 @@
14750
15033
  },
14751
15034
  /**/
14752
15035
  /**/
15036
+ {
15037
+ modelVariant: 'CHAT',
15038
+ modelTitle: 'gpt-4o-mini',
15039
+ modelName: 'gpt-4o-mini',
15040
+ pricing: {
15041
+ prompt: computeUsage(`$3.00 / 1M tokens`),
15042
+ output: computeUsage(`$9.00 / 1M tokens`),
15043
+ },
15044
+ },
15045
+ /**/
15046
+ /**/
14753
15047
  {
14754
15048
  modelVariant: 'CHAT',
14755
15049
  modelTitle: 'o1-preview',
@@ -14829,6 +15123,7 @@
14829
15123
  },
14830
15124
  },
14831
15125
  /**/
15126
+ // <- [🕕]
14832
15127
  ],
14833
15128
  });
14834
15129
  /**
@@ -15397,11 +15692,17 @@
15397
15692
  description: 'Implementation of Deepseek models',
15398
15693
  vercelProvider: deepseekVercelProvider,
15399
15694
  availableModels: [
15400
- // TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
15401
- 'deepseek-chat',
15402
- 'deepseek-reasoner',
15695
+ {
15696
+ modelName: 'deepseek-chat',
15697
+ modelVariant: 'CHAT',
15698
+ },
15699
+ {
15700
+ modelName: 'deepseek-reasoner',
15701
+ modelVariant: 'CHAT',
15702
+ },
15703
+ // <- [🕕]
15403
15704
  // <- TODO: How picking of the default model looks like in `createExecutionToolsFromVercelProvider`
15404
- ].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
15705
+ ],
15405
15706
  ...options,
15406
15707
  });
15407
15708
  }, {
@@ -15499,6 +15800,10 @@
15499
15800
  vercelProvider: googleGeminiVercelProvider,
15500
15801
  availableModels: [
15501
15802
  // TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
15803
+ 'gemini-2.5-pro-preview-03-25',
15804
+ 'gemini-2.0-flash',
15805
+ 'gemini-2.0-flash-lite',
15806
+ 'gemini-2.0-flash-thinking-exp-01-21',
15502
15807
  'gemini-1.5-flash',
15503
15808
  'gemini-1.5-flash-latest',
15504
15809
  'gemini-1.5-flash-001',
@@ -15514,6 +15819,7 @@
15514
15819
  'gemini-1.5-pro-002',
15515
15820
  'gemini-1.5-pro-exp-0827',
15516
15821
  'gemini-1.0-pro',
15822
+ // <- [🕕]
15517
15823
  ].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
15518
15824
  ...options,
15519
15825
  });
@@ -15793,6 +16099,7 @@
15793
16099
  console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
15794
16100
  }
15795
16101
  const rawResponse = await client.chat.completions.create(rawRequest).catch((error) => {
16102
+ assertsError(error);
15796
16103
  if (this.options.isVerbose) {
15797
16104
  console.info(colors__default["default"].bgRed('error'), error);
15798
16105
  }
@@ -15869,6 +16176,7 @@
15869
16176
  console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
15870
16177
  }
15871
16178
  const rawResponse = await client.completions.create(rawRequest).catch((error) => {
16179
+ assertsError(error);
15872
16180
  if (this.options.isVerbose) {
15873
16181
  console.info(colors__default["default"].bgRed('error'), error);
15874
16182
  }
@@ -15932,6 +16240,7 @@
15932
16240
  console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
15933
16241
  }
15934
16242
  const rawResponse = await client.embeddings.create(rawRequest).catch((error) => {
16243
+ assertsError(error);
15935
16244
  if (this.options.isVerbose) {
15936
16245
  console.info(colors__default["default"].bgRed('error'), error);
15937
16246
  }