@promptbook/cli 0.89.0-8 → 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 (50) hide show
  1. package/README.md +9 -11
  2. package/esm/index.es.js +969 -612
  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 +12 -4
  6. package/esm/typings/src/_packages/remote-client.index.d.ts +6 -6
  7. package/esm/typings/src/_packages/remote-server.index.d.ts +6 -6
  8. package/esm/typings/src/_packages/types.index.d.ts +24 -14
  9. package/esm/typings/src/_packages/utils.index.d.ts +4 -0
  10. package/esm/typings/src/cli/cli-commands/login.d.ts +0 -1
  11. package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +16 -3
  12. package/esm/typings/src/cli/test/ptbk.d.ts +1 -1
  13. package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +2 -0
  14. package/esm/typings/src/config.d.ts +10 -19
  15. package/esm/typings/src/errors/0-index.d.ts +8 -2
  16. package/esm/typings/src/errors/PipelineExecutionError.d.ts +1 -1
  17. package/esm/typings/src/errors/PromptbookFetchError.d.ts +9 -0
  18. package/esm/typings/src/errors/WrappedError.d.ts +10 -0
  19. package/esm/typings/src/errors/assertsError.d.ts +11 -0
  20. package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
  21. package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +9 -0
  22. package/esm/typings/src/formats/csv/utils/isValidCsvString.test.d.ts +1 -0
  23. package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +3 -0
  24. package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +9 -0
  25. package/esm/typings/src/formats/xml/utils/isValidXmlString.test.d.ts +1 -0
  26. package/esm/typings/src/llm-providers/_common/register/$provideEnvFilename.d.ts +12 -0
  27. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +2 -8
  28. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +2 -0
  29. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +15 -4
  30. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -0
  31. package/esm/typings/src/remote-server/openapi-types.d.ts +284 -0
  32. package/esm/typings/src/remote-server/openapi.d.ts +187 -0
  33. package/esm/typings/src/remote-server/socket-types/_subtypes/{PromptbookServer_Identification.d.ts → Identification.d.ts} +9 -3
  34. package/esm/typings/src/remote-server/socket-types/_subtypes/identificationToPromptbookToken.d.ts +11 -0
  35. package/esm/typings/src/remote-server/socket-types/_subtypes/promptbookTokenToIdentification.d.ts +10 -0
  36. package/esm/typings/src/remote-server/socket-types/listModels/PromptbookServer_ListModels_Request.d.ts +2 -2
  37. package/esm/typings/src/remote-server/socket-types/prepare/PromptbookServer_PreparePipeline_Request.d.ts +2 -2
  38. package/esm/typings/src/remote-server/socket-types/prompt/PromptbookServer_Prompt_Request.d.ts +2 -2
  39. package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
  40. package/esm/typings/src/remote-server/types/RemoteClientOptions.d.ts +2 -2
  41. package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +57 -38
  42. package/esm/typings/src/scrapers/_common/utils/{scraperFetch.d.ts → promptbookFetch.d.ts} +2 -2
  43. package/esm/typings/src/storage/env-storage/$EnvStorage.d.ts +40 -0
  44. package/esm/typings/src/types/typeAliases.d.ts +26 -0
  45. package/package.json +15 -11
  46. package/umd/index.umd.js +972 -615
  47. package/umd/index.umd.js.map +1 -1
  48. package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
  49. package/esm/typings/src/playground/BrjappConnector.d.ts +0 -67
  50. package/esm/typings/src/playground/brjapp-api-schema.d.ts +0 -12879
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-8';
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
  *
@@ -897,119 +982,278 @@
897
982
  `);
898
983
  }
899
984
  /**
900
- * TODO: [®] DRY Register logic
901
- * TODO: [🧠][⚛] Maybe pass env as argument
902
- */
903
-
904
- /**
905
- * Just says that the variable is not used but should be kept
906
- * No side effects.
907
- *
908
- * Note: It can be usefull for:
909
- *
910
- * 1) Suppressing eager optimization of unused imports
911
- * 2) Suppressing eslint errors of unused variables in the tests
912
- * 3) Keeping the type of the variable for type testing
913
- *
914
- * @param value any values
915
- * @returns void
916
- * @private within the repository
985
+ * TODO: [®] DRY Register logic
986
+ * TODO: [🧠][⚛] Maybe pass env as argument
987
+ */
988
+
989
+ /**
990
+ * Just says that the variable is not used but should be kept
991
+ * No side effects.
992
+ *
993
+ * Note: It can be usefull for:
994
+ *
995
+ * 1) Suppressing eager optimization of unused imports
996
+ * 2) Suppressing eslint errors of unused variables in the tests
997
+ * 3) Keeping the type of the variable for type testing
998
+ *
999
+ * @param value any values
1000
+ * @returns void
1001
+ * @private within the repository
1002
+ */
1003
+ function keepUnused(...valuesToKeep) {
1004
+ }
1005
+
1006
+ /**
1007
+ * Just says that the variable is not used directlys but should be kept because the existence of the variable is important
1008
+ *
1009
+ * @param value any values
1010
+ * @returns void
1011
+ * @private within the repository
1012
+ */
1013
+ function $sideEffect(...sideEffectSubjects) {
1014
+ keepUnused(...sideEffectSubjects);
1015
+ }
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
+
1051
+ /**
1052
+ * Just marks a place of place where should be something implemented
1053
+ * No side effects.
1054
+ *
1055
+ * Note: It can be usefull suppressing eslint errors of unused variables
1056
+ *
1057
+ * @param value any values
1058
+ * @returns void
1059
+ * @private within the repository
1060
+ */
1061
+ function TODO_USE(...value) {
1062
+ }
1063
+
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
917
1173
  */
918
- function keepUnused(...valuesToKeep) {
919
- }
920
1174
 
921
1175
  /**
922
- * Just says that the variable is not used directlys but should be kept because the existence of the variable is important
1176
+ * Stores data in .env variables
923
1177
  *
924
- * @param value any values
925
- * @returns void
926
- * @private within the repository
927
- */
928
- function $sideEffect(...sideEffectSubjects) {
929
- keepUnused(...sideEffectSubjects);
930
- }
931
-
932
- /**
933
- * Stores data in memory (HEAP)
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`
934
1179
  *
935
- * @public exported from `@promptbook/core`
1180
+ * @private within the repository - for CLI utils
936
1181
  */
937
- class MemoryStorage {
1182
+ class $EnvStorage {
938
1183
  constructor() {
939
- this.storage = {};
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);
940
1202
  }
941
1203
  /**
942
1204
  * Returns the number of key/value pairs currently present in the list associated with the object.
943
1205
  */
944
1206
  get length() {
945
- return Object.keys(this.storage).length;
1207
+ throw new NotYetImplementedError('Method `$EnvStorage.length` not implemented.');
946
1208
  }
947
1209
  /**
948
1210
  * Empties the list associated with the object of all key/value pairs, if there are any.
949
1211
  */
950
1212
  clear() {
951
- this.storage = {};
1213
+ throw new NotYetImplementedError('Method `$EnvStorage.clear` not implemented.');
952
1214
  }
953
1215
  /**
954
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.
955
1217
  */
956
- getItem(key) {
957
- return this.storage[key] || null;
1218
+ async getItem(key) {
1219
+ dotenv__namespace.config({ path: await this.$provideOrCreateEnvFile() });
1220
+ return process.env[this.transformKey(key)] || null;
958
1221
  }
959
1222
  /**
960
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.
961
1224
  */
962
1225
  key(index) {
963
- return Object.keys(this.storage)[index] || null;
1226
+ throw new NotYetImplementedError('Method `$EnvStorage.key` not implemented.');
964
1227
  }
965
1228
  /**
966
1229
  * Sets the value of the pair identified by key to value, creating a new key/value pair if none existed for key previously.
967
1230
  */
968
- setItem(key, value) {
969
- this.storage[key] = value;
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');
970
1247
  }
971
1248
  /**
972
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.
973
1250
  */
974
1251
  removeItem(key) {
975
- delete this.storage[key];
976
- }
977
- }
978
-
979
- /**
980
- * Just marks a place of place where should be something implemented
981
- * No side effects.
982
- *
983
- * Note: It can be usefull suppressing eslint errors of unused variables
984
- *
985
- * @param value any values
986
- * @returns void
987
- * @private within the repository
988
- */
989
- function TODO_USE(...value) {
990
- }
991
-
992
- /**
993
- * @@@
994
- *
995
- * @public exported from `@promptbook/node`
996
- */
997
- function $provideFilesystemForNode(options) {
998
- if (!$isRunningInNode()) {
999
- throw new EnvironmentMismatchError('Function `$provideFilesystemForNode` works only in Node.js environment');
1252
+ throw new NotYetImplementedError('Method `$EnvStorage.removeItem` not implemented.');
1000
1253
  }
1001
- return {
1002
- stat: promises.stat,
1003
- access: promises.access,
1004
- constants: promises.constants,
1005
- readFile: promises.readFile,
1006
- writeFile: promises.writeFile,
1007
- readdir: promises.readdir,
1008
- mkdir: promises.mkdir,
1009
- };
1010
1254
  }
1011
1255
  /**
1012
- * 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
1013
1257
  */
1014
1258
 
1015
1259
  /**
@@ -1145,9 +1389,7 @@
1145
1389
  JSON.stringify(value); // <- TODO: [0]
1146
1390
  }
1147
1391
  catch (error) {
1148
- if (!(error instanceof Error)) {
1149
- throw error;
1150
- }
1392
+ assertsError(error);
1151
1393
  throw new UnexpectedError(spaceTrim__default["default"]((block) => `
1152
1394
  \`${name}\` is not serializable
1153
1395
 
@@ -1380,31 +1622,6 @@
1380
1622
  * TODO: [🍙] Make some standard order of json properties
1381
1623
  */
1382
1624
 
1383
- /**
1384
- * Checks if the file exists
1385
- *
1386
- * @private within the repository
1387
- */
1388
- async function isFileExisting(filename, fs) {
1389
- const isReadAccessAllowed = await fs
1390
- .access(filename, fs.constants.R_OK)
1391
- .then(() => true)
1392
- .catch(() => false);
1393
- if (!isReadAccessAllowed) {
1394
- return false;
1395
- }
1396
- const isFile = await fs
1397
- .stat(filename)
1398
- .then((fileStat) => fileStat.isFile())
1399
- .catch(() => false);
1400
- return isFile;
1401
- }
1402
- /**
1403
- * Note: Not [~🟢~] because it is not directly dependent on `fs
1404
- * TODO: [🐠] This can be a validator - with variants that return true/false and variants that throw errors with meaningless messages
1405
- * TODO: [🖇] What about symlinks?
1406
- */
1407
-
1408
1625
  /**
1409
1626
  * Removes emojis from a string and fix whitespaces
1410
1627
  *
@@ -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
  /**
@@ -2115,6 +2332,19 @@
2115
2332
  }
2116
2333
  }
2117
2334
 
2335
+ /**
2336
+ * Error thrown when a fetch request fails
2337
+ *
2338
+ * @public exported from `@promptbook/core`
2339
+ */
2340
+ class PromptbookFetchError extends Error {
2341
+ constructor(message) {
2342
+ super(message);
2343
+ this.name = 'PromptbookFetchError';
2344
+ Object.setPrototypeOf(this, PromptbookFetchError.prototype);
2345
+ }
2346
+ }
2347
+
2118
2348
  /**
2119
2349
  * Index of all custom errors
2120
2350
  *
@@ -2135,7 +2365,10 @@
2135
2365
  PipelineExecutionError,
2136
2366
  PipelineLogicError,
2137
2367
  PipelineUrlError,
2368
+ AuthenticationError,
2369
+ PromptbookFetchError,
2138
2370
  UnexpectedError,
2371
+ WrappedError,
2139
2372
  // TODO: [🪑]> VersionMismatchError,
2140
2373
  };
2141
2374
  /**
@@ -2152,7 +2385,6 @@
2152
2385
  TypeError,
2153
2386
  URIError,
2154
2387
  AggregateError,
2155
- AuthenticationError,
2156
2388
  /*
2157
2389
  Note: Not widely supported
2158
2390
  > InternalError,
@@ -2210,17 +2442,31 @@
2210
2442
  */
2211
2443
  async function createRemoteClient(options) {
2212
2444
  const { remoteServerUrl } = options;
2213
- let path = new URL(remoteServerUrl).pathname;
2214
- if (path.endsWith('/')) {
2215
- 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
+ `));
2216
2463
  }
2217
- path = `${path}/socket.io`;
2218
2464
  return new Promise((resolve, reject) => {
2219
2465
  const socket = socket_ioClient.io(remoteServerUrl, {
2220
2466
  retries: CONNECTION_RETRIES_LIMIT,
2221
2467
  timeout: CONNECTION_TIMEOUT_MS,
2222
- path,
2223
- transports: [/*'websocket', <- TODO: [🌬] Make websocket transport work */ 'polling'],
2468
+ path: '/socket.io',
2469
+ transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
2224
2470
  });
2225
2471
  // console.log('Connecting to', this.options.remoteServerUrl.href, { socket });
2226
2472
  socket.on('connect', () => {
@@ -2345,6 +2591,53 @@
2345
2591
  * TODO: [🧠] Maybe remove `@promptbook/remote-client` and just use `@promptbook/core`
2346
2592
  */
2347
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
+
2348
2641
  /**
2349
2642
  * Simple wrapper `new Date().toISOString()`
2350
2643
  *
@@ -2631,29 +2924,11 @@
2631
2924
  * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2632
2925
  */
2633
2926
 
2634
- /**
2635
- * Determines if the given path is a root path.
2636
- *
2637
- * Note: This does not check if the file exists only if the path is valid
2638
- * @public exported from `@promptbook/utils`
2639
- */
2640
- function isRootPath(value) {
2641
- if (value === '/') {
2642
- return true;
2643
- }
2644
- if (/^[A-Z]:\\$/i.test(value)) {
2645
- return true;
2646
- }
2647
- return false;
2648
- }
2649
- /**
2650
- * TODO: [🍏] Make for MacOS paths
2651
- */
2652
-
2653
2927
  /**
2654
2928
  * @@@
2655
2929
  *
2656
2930
  * @@@ .env
2931
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
2657
2932
  *
2658
2933
  * It looks for environment variables:
2659
2934
  * - `process.env.OPENAI_API_KEY`
@@ -2667,33 +2942,9 @@
2667
2942
  if (!$isRunningInNode()) {
2668
2943
  throw new EnvironmentMismatchError('Function `$provideLlmToolsFromEnv` works only in Node.js environment');
2669
2944
  }
2670
- const envFilePatterns = [
2671
- '.env',
2672
- '.env.test',
2673
- '.env.local',
2674
- '.env.development.local',
2675
- '.env.development',
2676
- '.env.production.local',
2677
- '.env.production',
2678
- '.env.prod.local',
2679
- '.env.prod',
2680
- // <- TODO: Maybe add more patterns
2681
- ];
2682
- let rootDirname = process.cwd();
2683
- up_to_root: for (let i = 0; i < LOOP_LIMIT; i++) {
2684
- for (const pattern of envFilePatterns) {
2685
- const envFilename = path.join(rootDirname, pattern);
2686
- if (await isFileExisting(envFilename, $provideFilesystemForNode())) {
2687
- $setUsedEnvFilename(envFilename);
2688
- dotenv__namespace.config({ path: envFilename });
2689
- break up_to_root;
2690
- }
2691
- }
2692
- if (isRootPath(rootDirname)) {
2693
- break up_to_root;
2694
- }
2695
- // Note: If the directory does not exist, try the parent directory
2696
- rootDirname = path.join(rootDirname, '..');
2945
+ const envFilepath = await $provideEnvFilename();
2946
+ if (envFilepath !== null) {
2947
+ dotenv__namespace.config({ path: envFilepath });
2697
2948
  }
2698
2949
  const llmToolsConfiguration = $llmToolsMetadataRegister
2699
2950
  .list()
@@ -2702,15 +2953,8 @@
2702
2953
  return llmToolsConfiguration;
2703
2954
  }
2704
2955
  /**
2705
- * TODO: [🧠][🪁] Maybe do allow to do auto-install if package not registered and not found
2706
- * TODO: Add Azure OpenAI
2707
- * TODO: [🧠][🍛]
2708
- * TODO: [🧠] Is there some meaningfull way how to test this util
2709
2956
  * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
2710
- * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
2711
- * TODO: This should be maybe not under `_common` but under `utils`
2712
- * TODO: [🧠][⚛] Maybe pass env as argument
2713
- * TODO: [®] DRY Register logic */
2957
+ */
2714
2958
 
2715
2959
  /**
2716
2960
  * Multiple LLM Execution Tools is a proxy server that uses multiple execution tools internally and exposes the executor interface externally.
@@ -2806,14 +3050,15 @@
2806
3050
  }
2807
3051
  }
2808
3052
  catch (error) {
2809
- if (!(error instanceof Error) || error instanceof UnexpectedError) {
3053
+ assertsError(error);
3054
+ if (error instanceof UnexpectedError) {
2810
3055
  throw error;
2811
3056
  }
2812
3057
  errors.push({ llmExecutionTools, error });
2813
3058
  }
2814
3059
  }
2815
3060
  if (errors.length === 1) {
2816
- throw errors[0];
3061
+ throw errors[0].error;
2817
3062
  }
2818
3063
  else if (errors.length > 1) {
2819
3064
  throw new PipelineExecutionError(
@@ -2960,6 +3205,7 @@
2960
3205
  * Note: This function is not cached, every call creates new instance of `MultipleLlmExecutionTools`
2961
3206
  *
2962
3207
  * @@@ .env
3208
+ * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file
2963
3209
  *
2964
3210
  * It looks for environment variables:
2965
3211
  * - `process.env.OPENAI_API_KEY`
@@ -3004,6 +3250,8 @@
3004
3250
  /**
3005
3251
  * Returns LLM tools for CLI
3006
3252
  *
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
3254
+ *
3007
3255
  * @private within the repository - for CLI utils
3008
3256
  */
3009
3257
  async function $provideLlmToolsForWizzardOrCli(options) {
@@ -3011,16 +3259,27 @@
3011
3259
  throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
3012
3260
  }
3013
3261
  options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
3014
- const { strategy, isCacheReloaded } = options;
3262
+ const { isLoginloaded, strategy, isCacheReloaded } = options;
3015
3263
  let llmExecutionTools;
3016
3264
  if (strategy === 'REMOTE_SERVER') {
3017
3265
  const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
3018
- const storage = new MemoryStorage(); // <- TODO: !!!!!! Save to `.promptbook` folder
3019
- const key = `${remoteServerUrl}-identification`;
3020
- let identification = await storage.getItem(key);
3021
- 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) {
3022
3274
  identification = await loginPrompt();
3023
- 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);
3024
3283
  }
3025
3284
  llmExecutionTools = new RemoteLlmExecutionTools({
3026
3285
  remoteServerUrl,
@@ -3044,11 +3303,42 @@
3044
3303
  });
3045
3304
  }
3046
3305
  /**
3047
- * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
3048
- * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
3049
- * TODO: [🥃] Allow `ptbk make` without llm tools
3050
- * TODO: This should be maybe not under `_common` but under `utils-internal` / `utils/internal`
3051
- * TODO: [®] DRY Register logic
3306
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
3307
+ * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
3308
+ * TODO: [🥃] Allow `ptbk make` without llm tools
3309
+ * TODO: This should be maybe not under `_common` but under `utils-internal` / `utils/internal`
3310
+ * TODO: [®] DRY Register logic
3311
+ */
3312
+
3313
+ /**
3314
+ * The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
3315
+ *
3316
+ * @public exported from `@promptbook/core`
3317
+ */
3318
+ const promptbookFetch = async (urlOrRequest, init) => {
3319
+ try {
3320
+ return await fetch(urlOrRequest, init);
3321
+ }
3322
+ catch (error) {
3323
+ assertsError(error);
3324
+ let url;
3325
+ if (typeof urlOrRequest === 'string') {
3326
+ url = urlOrRequest;
3327
+ }
3328
+ else if (urlOrRequest instanceof Request) {
3329
+ url = urlOrRequest.url;
3330
+ }
3331
+ throw new PromptbookFetchError(spaceTrim__default["default"]((block) => `
3332
+ Can not fetch "${url}"
3333
+
3334
+ Fetch error:
3335
+ ${block(error.message)}
3336
+
3337
+ `));
3338
+ }
3339
+ };
3340
+ /**
3341
+ * TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
3052
3342
  */
3053
3343
 
3054
3344
  /**
@@ -3069,8 +3359,8 @@
3069
3359
  /**
3070
3360
  * @private utility of CLI
3071
3361
  */
3072
- function $provideLlmToolsForCli(options) {
3073
- const { cliOptions: {
3362
+ async function $provideLlmToolsForCli(options) {
3363
+ const { isLoginloaded, cliOptions: {
3074
3364
  /* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
3075
3365
  let strategy;
3076
3366
  if (/^b/i.test(provider)) {
@@ -3084,7 +3374,11 @@
3084
3374
  process.exit(1);
3085
3375
  }
3086
3376
  if (strategy === 'BRING_YOUR_OWN_KEYS') {
3087
- 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 };
3088
3382
  }
3089
3383
  else if (strategy === 'REMOTE_SERVER') {
3090
3384
  if (!isValidUrl(remoteServerUrlRaw)) {
@@ -3092,7 +3386,8 @@
3092
3386
  process.exit(1);
3093
3387
  }
3094
3388
  const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
3095
- return /* not await */ $provideLlmToolsForWizzardOrCli({
3389
+ const llm = await $provideLlmToolsForWizzardOrCli({
3390
+ isLoginloaded,
3096
3391
  strategy,
3097
3392
  appId: CLI_APP_ID,
3098
3393
  remoteServerUrl,
@@ -3102,6 +3397,10 @@
3102
3397
  console.log(colors__default["default"].red(`You can not login to remote server in non-interactive mode`));
3103
3398
  process.exit(1);
3104
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
+ `)));
3105
3404
  const { username, password } = await prompts__default["default"]([
3106
3405
  {
3107
3406
  type: 'text',
@@ -3119,7 +3418,8 @@
3119
3418
  },
3120
3419
  ]);
3121
3420
  const loginUrl = `${remoteServerUrl}/login`;
3122
- const response = await fetch(loginUrl, {
3421
+ // TODO: [🧠] Should we use normal `fetch` or `scraperFetch`
3422
+ const response = await promptbookFetch(loginUrl, {
3123
3423
  method: 'POST',
3124
3424
  headers: {
3125
3425
  'Content-Type': 'application/json',
@@ -3130,13 +3430,6 @@
3130
3430
  password,
3131
3431
  }),
3132
3432
  });
3133
- console.log('!!!', {
3134
- loginUrl,
3135
- username,
3136
- password,
3137
- // type: response.type,
3138
- // text: await response.text(),
3139
- });
3140
3433
  const { isSuccess, message, error, identification } = (await response.json());
3141
3434
  if (message) {
3142
3435
  if (isSuccess) {
@@ -3158,6 +3451,7 @@
3158
3451
  return identification;
3159
3452
  },
3160
3453
  });
3454
+ return { strategy, llm };
3161
3455
  }
3162
3456
  else {
3163
3457
  throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
@@ -3179,11 +3473,12 @@
3179
3473
  listModelsCommand.alias('models');
3180
3474
  listModelsCommand.alias('llm');
3181
3475
  listModelsCommand.action(handleActionErrors(async (cliOptions) => {
3182
- console.log('!!!', cliOptions);
3183
- // TODO: !!!!!! Not relevant for remote server and also for `about` command
3184
- const llm = await $provideLlmToolsForCli({ cliOptions });
3476
+ const { strategy, llm } = await $provideLlmToolsForCli({ cliOptions });
3185
3477
  $sideEffect(llm);
3186
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
+ }
3187
3482
  console.info($registeredLlmToolsMessage());
3188
3483
  return process.exit(0);
3189
3484
  }));
@@ -3366,9 +3661,7 @@
3366
3661
  return result.trim();
3367
3662
  }
3368
3663
  catch (error) {
3369
- if (!(error instanceof Error)) {
3370
- throw error;
3371
- }
3664
+ assertsError(error);
3372
3665
  return null;
3373
3666
  }
3374
3667
  }
@@ -3423,9 +3716,7 @@
3423
3716
  return result.trim() + toExec;
3424
3717
  }
3425
3718
  catch (error) {
3426
- if (!(error instanceof Error)) {
3427
- throw error;
3428
- }
3719
+ assertsError(error);
3429
3720
  return null;
3430
3721
  }
3431
3722
  }
@@ -3456,9 +3747,7 @@
3456
3747
  throw new Error(`Can not locate app ${appName} on Windows.`);
3457
3748
  }
3458
3749
  catch (error) {
3459
- if (!(error instanceof Error)) {
3460
- throw error;
3461
- }
3750
+ assertsError(error);
3462
3751
  return null;
3463
3752
  }
3464
3753
  }
@@ -3717,6 +4006,7 @@
3717
4006
  `));
3718
4007
  listModelsCommand.alias('scrapers');
3719
4008
  listModelsCommand.action(handleActionErrors(async () => {
4009
+ // TODO: [🌞] Do not allow on REMOTE_SERVER strategy
3720
4010
  const scrapers = await $provideScrapersForNode({});
3721
4011
  const executables = await $provideExecutablesForNode();
3722
4012
  console.info(spaceTrim__default["default"]((block) => `
@@ -3752,42 +4042,20 @@
3752
4042
  loginCommand.description(spaceTrim__default["default"](`
3753
4043
  Login to the remote Promptbook server
3754
4044
  `));
3755
- loginCommand.action(handleActionErrors(async () => {
3756
- // @@@
3757
- console.error(colors__default["default"].green(spaceTrim__default["default"](`
3758
- You will be logged in to https://promptbook.studio server.
3759
- If you don't have an account, it will be created automatically.
3760
- `)));
3761
- // !!!!!!!!! Remove from here and use $provideLlmToolsForCli
3762
- const { email, password } = await prompts__default["default"]([
3763
- {
3764
- type: 'text',
3765
- name: 'email',
3766
- message: 'Enter your email:',
3767
- validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
3768
- },
3769
- {
3770
- type: 'password',
3771
- name: 'password',
3772
- message: 'Enter your password:',
3773
- 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
3774
4053
  },
3775
- ]);
3776
- TODO_USE(email, password);
3777
- await waitasecond.forTime(1000);
3778
- console.error(colors__default["default"].green(spaceTrim__default["default"](`
3779
- Your account ${email} was successfully created.
3780
-
3781
- Please verify your email:
3782
- https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
3783
-
3784
- After verification, you will receive 500 000 credits for free 🎉
3785
- `)));
4054
+ });
3786
4055
  return process.exit(0);
3787
4056
  }));
3788
4057
  }
3789
4058
  /**
3790
- * TODO: Pass remote server URL (and path)
3791
4059
  * TODO: Implement non-interactive login
3792
4060
  * Note: [💞] Ignore a discrepancy between file name and entity name
3793
4061
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
@@ -4208,6 +4476,9 @@
4208
4476
  /**
4209
4477
  * Function isValidJsonString will tell you if the string is valid JSON or not
4210
4478
  *
4479
+ * @param value The string to check
4480
+ * @returns True if the string is a valid JSON string, false otherwise
4481
+ *
4211
4482
  * @public exported from `@promptbook/utils`
4212
4483
  */
4213
4484
  function isValidJsonString(value /* <- [👨‍⚖️] */) {
@@ -4216,9 +4487,7 @@
4216
4487
  return true;
4217
4488
  }
4218
4489
  catch (error) {
4219
- if (!(error instanceof Error)) {
4220
- throw error;
4221
- }
4490
+ assertsError(error);
4222
4491
  if (error.message.includes('Unexpected token')) {
4223
4492
  return false;
4224
4493
  }
@@ -4749,8 +5018,8 @@
4749
5018
  updatedAt = new Date();
4750
5019
  errors.push(...executionResult.errors);
4751
5020
  warnings.push(...executionResult.warnings);
4752
- // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
4753
- // 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`
4754
5023
  // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
4755
5024
  // And delete `ExecutionTask.currentValue.preparedPipeline`
4756
5025
  assertsTaskSuccessful(executionResult);
@@ -4760,6 +5029,7 @@
4760
5029
  partialResultSubject.next(executionResult);
4761
5030
  }
4762
5031
  catch (error) {
5032
+ assertsError(error);
4763
5033
  status = 'ERROR';
4764
5034
  errors.push(error);
4765
5035
  partialResultSubject.error(error);
@@ -4905,13 +5175,19 @@
4905
5175
  return value.toISOString();
4906
5176
  }
4907
5177
  else {
4908
- 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
+ }
4909
5187
  }
4910
5188
  }
4911
5189
  catch (error) {
4912
- if (!(error instanceof Error)) {
4913
- throw error;
4914
- }
5190
+ assertsError(error);
4915
5191
  console.error(error);
4916
5192
  return VALUE_STRINGS.unserializable;
4917
5193
  }
@@ -4968,9 +5244,7 @@
4968
5244
  }
4969
5245
  }
4970
5246
  catch (error) {
4971
- if (!(error instanceof Error)) {
4972
- throw error;
4973
- }
5247
+ assertsError(error);
4974
5248
  throw new ParseError(spaceTrim.spaceTrim((block) => `
4975
5249
  Can not extract variables from the script
4976
5250
  ${block(error.stack || error.message)}
@@ -5089,6 +5363,28 @@
5089
5363
  // encoding: 'utf-8',
5090
5364
  });
5091
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
+
5092
5388
  /**
5093
5389
  * Definition for CSV spreadsheet
5094
5390
  *
@@ -5099,7 +5395,7 @@
5099
5395
  formatName: 'CSV',
5100
5396
  aliases: ['SPREADSHEET', 'TABLE'],
5101
5397
  isValid(value, settings, schema) {
5102
- return true;
5398
+ return isValidCsvString(value);
5103
5399
  },
5104
5400
  canBeValid(partialValue, settings, schema) {
5105
5401
  return true;
@@ -5253,6 +5549,30 @@
5253
5549
  * TODO: [🏢] Allow to expect something inside each item of list and other formats
5254
5550
  */
5255
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
+
5256
5576
  /**
5257
5577
  * Definition for XML format
5258
5578
  *
@@ -5262,7 +5582,7 @@
5262
5582
  formatName: 'XML',
5263
5583
  mimeType: 'application/xml',
5264
5584
  isValid(value, settings, schema) {
5265
- return true;
5585
+ return isValidXmlString(value);
5266
5586
  },
5267
5587
  canBeValid(partialValue, settings, schema) {
5268
5588
  return true;
@@ -5854,9 +6174,7 @@
5854
6174
  break scripts;
5855
6175
  }
5856
6176
  catch (error) {
5857
- if (!(error instanceof Error)) {
5858
- throw error;
5859
- }
6177
+ assertsError(error);
5860
6178
  if (error instanceof UnexpectedError) {
5861
6179
  throw error;
5862
6180
  }
@@ -5926,9 +6244,7 @@
5926
6244
  break scripts;
5927
6245
  }
5928
6246
  catch (error) {
5929
- if (!(error instanceof Error)) {
5930
- throw error;
5931
- }
6247
+ assertsError(error);
5932
6248
  if (error instanceof UnexpectedError) {
5933
6249
  throw error;
5934
6250
  }
@@ -6549,9 +6865,7 @@
6549
6865
  await Promise.all(resolving);
6550
6866
  }
6551
6867
  catch (error /* <- Note: [3] */) {
6552
- if (!(error instanceof Error)) {
6553
- throw error;
6554
- }
6868
+ assertsError(error);
6555
6869
  // Note: No need to rethrow UnexpectedError
6556
6870
  // if (error instanceof UnexpectedError) {
6557
6871
  // Note: Count usage, [🧠] Maybe put to separate function executionReportJsonToUsage + DRY [🤹‍♂️]
@@ -6817,32 +7131,6 @@
6817
7131
  return mimeTypes.extension(value) || null;
6818
7132
  }
6819
7133
 
6820
- /**
6821
- * The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
6822
- *
6823
- * @private as default `fetch` function used in Promptbook scrapers
6824
- */
6825
- const scraperFetch = async (url, init) => {
6826
- try {
6827
- return await fetch(url, init);
6828
- }
6829
- catch (error) {
6830
- if (!(error instanceof Error)) {
6831
- throw error;
6832
- }
6833
- throw new KnowledgeScrapeError(spaceTrim__default["default"]((block) => `
6834
- Can not fetch "${url}"
6835
-
6836
- Fetch error:
6837
- ${block(error.message)}
6838
-
6839
- `));
6840
- }
6841
- };
6842
- /**
6843
- * TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
6844
- */
6845
-
6846
7134
  /**
6847
7135
  * @@@
6848
7136
  *
@@ -6851,7 +7139,7 @@
6851
7139
  async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
6852
7140
  // console.log('!! makeKnowledgeSourceHandler', knowledgeSource);
6853
7141
  var _a;
6854
- const { fetch = scraperFetch } = tools;
7142
+ const { fetch = promptbookFetch } = tools;
6855
7143
  const { knowledgeSourceContent } = knowledgeSource;
6856
7144
  let { name } = knowledgeSource;
6857
7145
  const { rootDirname = null,
@@ -7053,9 +7341,7 @@
7053
7341
  knowledgePreparedUnflatten[index] = pieces;
7054
7342
  }
7055
7343
  catch (error) {
7056
- if (!(error instanceof Error)) {
7057
- throw error;
7058
- }
7344
+ assertsError(error);
7059
7345
  console.warn(error);
7060
7346
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
7061
7347
  }
@@ -7853,6 +8139,8 @@
7853
8139
  */
7854
8140
 
7855
8141
  /**
8142
+ import { WrappedError } from '../../errors/WrappedError';
8143
+ import { assertsError } from '../../errors/assertsError';
7856
8144
  * Parses the expect command
7857
8145
  *
7858
8146
  * @see `documentationUrl` for more details
@@ -7944,9 +8232,7 @@
7944
8232
  };
7945
8233
  }
7946
8234
  catch (error) {
7947
- if (!(error instanceof Error)) {
7948
- throw error;
7949
- }
8235
+ assertsError(error);
7950
8236
  throw new ParseError(spaceTrim__default["default"]((block) => `
7951
8237
  Invalid FORMAT command
7952
8238
  ${block(error.message)}:
@@ -11194,9 +11480,7 @@
11194
11480
  }
11195
11481
  }
11196
11482
  catch (error) {
11197
- if (!(error instanceof Error)) {
11198
- throw error;
11199
- }
11483
+ assertsError(error);
11200
11484
  if (error instanceof ReferenceError) {
11201
11485
  const undefinedName = error.message.split(' ')[0];
11202
11486
  /*
@@ -11471,9 +11755,7 @@
11471
11755
  // ---
11472
11756
  }
11473
11757
  catch (error) {
11474
- if (!(error instanceof Error)) {
11475
- throw error;
11476
- }
11758
+ assertsError(error);
11477
11759
  // TODO: [7] DRY
11478
11760
  const wrappedErrorMessage = spaceTrim__default["default"]((block) => `
11479
11761
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
@@ -11564,9 +11846,7 @@
11564
11846
  }
11565
11847
  }
11566
11848
  catch (error) {
11567
- if (!(error instanceof Error)) {
11568
- throw error;
11569
- }
11849
+ assertsError(error);
11570
11850
  // TODO: [7] DRY
11571
11851
  const wrappedErrorMessage = spaceTrim__default["default"]((block) => `
11572
11852
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
@@ -11782,7 +12062,7 @@
11782
12062
  isCacheReloaded,
11783
12063
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
11784
12064
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
11785
- const llm = await $provideLlmToolsForCli({
12065
+ const { llm } = await $provideLlmToolsForCli({
11786
12066
  cliOptions,
11787
12067
  ...prepareAndScrapeOptions,
11788
12068
  });
@@ -12075,9 +12355,7 @@
12075
12355
  }
12076
12356
  }
12077
12357
  catch (error) {
12078
- if (!(error instanceof Error)) {
12079
- throw error;
12080
- }
12358
+ assertsError(error);
12081
12359
  console.info(colors__default["default"].red(`Prettify ${error.name} ${filename}`));
12082
12360
  console.error(colors__default["default"].bgRed(`${error.name} in ${path.basename(__filename)}`));
12083
12361
  console.error(colors__default["default"].red(error.stack || error.message));
@@ -12397,9 +12675,7 @@
12397
12675
  return true;
12398
12676
  }
12399
12677
  catch (error) {
12400
- if (!(error instanceof Error)) {
12401
- throw error;
12402
- }
12678
+ assertsError(error);
12403
12679
  return false;
12404
12680
  }
12405
12681
  }
@@ -12624,9 +12900,7 @@
12624
12900
  ongoingParameters = result.outputParameters;
12625
12901
  }
12626
12902
  catch (error) {
12627
- if (!(error instanceof Error)) {
12628
- throw error;
12629
- }
12903
+ assertsError(error);
12630
12904
  // TODO: Allow to ressurect the chatbot after an error - prompt the user to continue
12631
12905
  console.error(colors__default["default"].red(error.stack || error.message));
12632
12906
  return process.exit(1);
@@ -12659,7 +12933,6 @@
12659
12933
  runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
12660
12934
  runCommand.option('-s, --save-report <path>', `Save report to file`);
12661
12935
  runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
12662
- console.log('!!!', cliOptions);
12663
12936
  const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
12664
12937
  if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
12665
12938
  console.error(colors__default["default"].red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
@@ -12685,12 +12958,10 @@
12685
12958
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
12686
12959
  let llm;
12687
12960
  try {
12688
- llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
12961
+ llm = (await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions })).llm;
12689
12962
  }
12690
12963
  catch (error) {
12691
- if (!(error instanceof Error)) {
12692
- throw error;
12693
- }
12964
+ assertsError(error);
12694
12965
  if (!error.message.includes('No LLM tools')) {
12695
12966
  throw error;
12696
12967
  }
@@ -12740,7 +13011,7 @@
12740
13011
  const tools = {
12741
13012
  llm,
12742
13013
  fs,
12743
- fetch: scraperFetch,
13014
+ fetch: promptbookFetch,
12744
13015
  scrapers: await $provideScrapersForNode({ fs, llm, executables }, prepareAndScrapeOptions),
12745
13016
  script: [new JavascriptExecutionTools(cliOptions)],
12746
13017
  };
@@ -12896,6 +13167,198 @@
12896
13167
  * TODO: [🖇] What about symlinks? Maybe flag --follow-symlinks
12897
13168
  */
12898
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
+
12899
13362
  /**
12900
13363
  * Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
12901
13364
  *
@@ -12906,7 +13369,7 @@
12906
13369
  * @public exported from `@promptbook/remote-server`
12907
13370
  */
12908
13371
  function startRemoteServer(options) {
12909
- const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
13372
+ const { port, collection, createLlmExecutionTools, createExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
12910
13373
  isAnonymousModeAllowed: false,
12911
13374
  isApplicationModeAllowed: false,
12912
13375
  collection: null,
@@ -12914,22 +13377,6 @@
12914
13377
  login: null,
12915
13378
  ...options,
12916
13379
  };
12917
- // <- TODO: [🦪] Some helper type to be able to use discriminant union types with destructuring
12918
- let { rootPath = '/' } = options;
12919
- if (!rootPath.startsWith('/')) {
12920
- rootPath = `/${rootPath}`;
12921
- } /* not else */
12922
- if (rootPath.endsWith('/')) {
12923
- rootPath = rootPath.slice(0, -1);
12924
- } /* not else */
12925
- if (rootPath === '/') {
12926
- rootPath = '';
12927
- }
12928
- const socketioPath = '/' +
12929
- `${rootPath}/socket.io`
12930
- .split('/')
12931
- .filter((part) => part !== '')
12932
- .join('/');
12933
13380
  const startupDate = new Date();
12934
13381
  async function getExecutionToolsFromIdentification(identification) {
12935
13382
  if (identification === null || identification === undefined) {
@@ -12952,23 +13399,25 @@
12952
13399
  }
12953
13400
  else if (isAnonymous === false && createLlmExecutionTools !== null) {
12954
13401
  // Note: Application mode
12955
- const { appId, userId, customOptions } = identification;
12956
- llm = await createLlmExecutionTools({
12957
- appId,
12958
- userId,
12959
- customOptions,
12960
- });
13402
+ llm = await createLlmExecutionTools(identification);
12961
13403
  }
12962
13404
  else {
12963
13405
  throw new PipelineExecutionError(`You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured`);
12964
13406
  }
12965
- const fs = $provideFilesystemForNode();
12966
- 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;
12967
13414
  const tools = {
12968
13415
  llm,
12969
13416
  fs,
12970
- scrapers: await $provideScrapersForNode({ fs, llm, executables }),
12971
- script: await $provideScriptingForNode({}),
13417
+ scrapers,
13418
+ script,
13419
+ fetch,
13420
+ userInterface,
12972
13421
  };
12973
13422
  return tools;
12974
13423
  }
@@ -12978,39 +13427,27 @@
12978
13427
  response.setHeader('X-Powered-By', 'Promptbook engine');
12979
13428
  next();
12980
13429
  });
12981
- const swaggerOptions = {
12982
- definition: {
12983
- openapi: '3.0.0',
12984
- info: {
12985
- title: 'Promptbook Remote Server API',
12986
- version: '1.0.0',
12987
- description: 'API documentation for the Promptbook Remote Server',
12988
- },
12989
- servers: [
12990
- {
12991
- url: `http://localhost:${port}${rootPath}`,
12992
- // <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
12993
- },
12994
- ],
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');
12995
13435
  },
12996
- apis: ['./src/remote-server/**/*.ts'], // Adjust path as needed
12997
- };
12998
- const swaggerSpec = swaggerJsdoc__default["default"](swaggerOptions);
12999
- 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
+ });
13000
13447
  const runningExecutionTasks = [];
13001
13448
  // <- TODO: [🤬] Identify the users
13002
13449
  // TODO: [🧠] Do here some garbage collection of finished tasks
13003
- /**
13004
- * @swagger
13005
- * /:
13006
- * get:
13007
- * summary: Get server details
13008
- * description: Returns details about the Promptbook server.
13009
- * responses:
13010
- * 200:
13011
- * description: Server details in markdown format.
13012
- */
13013
- app.get(['/', rootPath], async (request, response) => {
13450
+ app.get('/', async (request, response) => {
13014
13451
  var _a;
13015
13452
  if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
13016
13453
  return;
@@ -13029,8 +13466,6 @@
13029
13466
  ## Details
13030
13467
 
13031
13468
  **Server port:** ${port}
13032
- **Server root path:** ${rootPath}
13033
- **Socket.io path:** ${socketioPath}
13034
13469
  **Startup date:** ${startupDate.toISOString()}
13035
13470
  **Anonymouse mode:** ${isAnonymousModeAllowed ? 'enabled' : 'disabled'}
13036
13471
  **Application mode:** ${isApplicationModeAllowed ? 'enabled' : 'disabled'}
@@ -13069,38 +13504,7 @@
13069
13504
  https://github.com/webgptorg/promptbook
13070
13505
  `));
13071
13506
  });
13072
- /**
13073
- * @swagger
13074
- *
13075
- * /login:
13076
- * post:
13077
- * summary: Login to the server
13078
- * description: Login to the server and get identification.
13079
- * requestBody:
13080
- * required: true
13081
- * content:
13082
- * application/json:
13083
- * schema:
13084
- * type: object
13085
- * properties:
13086
- * username:
13087
- * type: string
13088
- * password:
13089
- * type: string
13090
- * appId:
13091
- * type: string
13092
- * responses:
13093
- * 200:
13094
- * description: Successful login
13095
- * content:
13096
- * application/json:
13097
- * schema:
13098
- * type: object
13099
- * properties:
13100
- * identification:
13101
- * type: object
13102
- */
13103
- app.post([`/login`, `${rootPath}/login`], async (request, response) => {
13507
+ app.post(`/login`, async (request, response) => {
13104
13508
  if (!isApplicationModeAllowed || login === null) {
13105
13509
  response.status(400).send('Application mode is not allowed');
13106
13510
  return;
@@ -13125,9 +13529,7 @@
13125
13529
  return;
13126
13530
  }
13127
13531
  catch (error) {
13128
- if (!(error instanceof Error)) {
13129
- throw error;
13130
- }
13532
+ assertsError(error);
13131
13533
  if (error instanceof AuthenticationError) {
13132
13534
  response.status(401).send({
13133
13535
  isSuccess: false,
@@ -13142,23 +13544,7 @@
13142
13544
  response.status(400).send({ error: serializeError(error) });
13143
13545
  }
13144
13546
  });
13145
- /**
13146
- * @swagger
13147
- * /books:
13148
- * get:
13149
- * summary: List all books
13150
- * description: Returns a list of all available books in the collection.
13151
- * responses:
13152
- * 200:
13153
- * description: A list of books.
13154
- * content:
13155
- * application/json:
13156
- * schema:
13157
- * type: array
13158
- * items:
13159
- * type: string
13160
- */
13161
- app.get([`/books`, `${rootPath}/books`], async (request, response) => {
13547
+ app.get(`/books`, async (request, response) => {
13162
13548
  if (collection === null) {
13163
13549
  response.status(500).send('No collection available');
13164
13550
  return;
@@ -13168,30 +13554,7 @@
13168
13554
  response.send(pipelines);
13169
13555
  });
13170
13556
  // TODO: [🧠] Is it secure / good idea to expose source codes of hosted books
13171
- /**
13172
- * @swagger
13173
- * /books/{bookId}:
13174
- * get:
13175
- * summary: Get book content
13176
- * description: Returns the content of a specific book.
13177
- * parameters:
13178
- * - in: path
13179
- * name: bookId
13180
- * required: true
13181
- * schema:
13182
- * type: string
13183
- * description: The ID of the book to retrieve.
13184
- * responses:
13185
- * 200:
13186
- * description: The content of the book.
13187
- * content:
13188
- * text/markdown:
13189
- * schema:
13190
- * type: string
13191
- * 404:
13192
- * description: Book not found.
13193
- */
13194
- app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
13557
+ app.get(`/books/*`, async (request, response) => {
13195
13558
  try {
13196
13559
  if (collection === null) {
13197
13560
  response.status(500).send('No collection nor books available');
@@ -13210,9 +13573,7 @@
13210
13573
  .send(source.content);
13211
13574
  }
13212
13575
  catch (error) {
13213
- if (!(error instanceof Error)) {
13214
- throw error;
13215
- }
13576
+ assertsError(error);
13216
13577
  response
13217
13578
  .status(404)
13218
13579
  .send({ error: serializeError(error) });
@@ -13245,26 +13606,10 @@
13245
13606
  };
13246
13607
  }
13247
13608
  }
13248
- /**
13249
- * @swagger
13250
- * /executions:
13251
- * get:
13252
- * summary: List all executions
13253
- * description: Returns a list of all running execution tasks.
13254
- * responses:
13255
- * 200:
13256
- * description: A list of execution tasks.
13257
- * content:
13258
- * application/json:
13259
- * schema:
13260
- * type: array
13261
- * items:
13262
- * type: object
13263
- */
13264
- app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
13265
- 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'] */);
13266
13611
  });
13267
- app.get([`/executions/last`, `${rootPath}/executions/last`], async (request, response) => {
13612
+ app.get(`/executions/last`, async (request, response) => {
13268
13613
  // TODO: [🤬] Filter only for user
13269
13614
  if (runningExecutionTasks.length === 0) {
13270
13615
  response.status(404).send('No execution tasks found');
@@ -13273,7 +13618,7 @@
13273
13618
  const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
13274
13619
  response.send(exportExecutionTask(lastExecutionTask, true));
13275
13620
  });
13276
- app.get([`/executions/:taskId`, `${rootPath}/executions/:taskId`], async (request, response) => {
13621
+ app.get(`/executions/:taskId`, async (request, response) => {
13277
13622
  const { taskId } = request.params;
13278
13623
  // TODO: [🤬] Filter only for user
13279
13624
  const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
@@ -13285,39 +13630,12 @@
13285
13630
  }
13286
13631
  response.send(exportExecutionTask(executionTask, true));
13287
13632
  });
13288
- /**
13289
- * @swagger
13290
- * /executions/new:
13291
- * post:
13292
- * summary: Start a new execution
13293
- * description: Starts a new execution task for a given pipeline.
13294
- * requestBody:
13295
- * required: true
13296
- * content:
13297
- * application/json:
13298
- * schema:
13299
- * type: object
13300
- * properties:
13301
- * pipelineUrl:
13302
- * type: string
13303
- * inputParameters:
13304
- * type: object
13305
- * identification:
13306
- * type: object
13307
- * responses:
13308
- * 200:
13309
- * description: The newly created execution task.
13310
- * content:
13311
- * application/json:
13312
- * schema:
13313
- * type: object
13314
- * 400:
13315
- * description: Invalid input.
13316
- */
13317
- app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
13633
+ app.post(`/executions/new`, async (request, response) => {
13318
13634
  try {
13319
13635
  const { inputParameters, identification /* <- [🤬] */ } = request.body;
13320
- 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;
13321
13639
  // TODO: [🧠] Check `pipelineUrl` and `inputParameters` here or it should be responsibility of `collection.getPipelineByUrl` and `pipelineExecutor`
13322
13640
  const pipeline = await (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl));
13323
13641
  if (pipeline === undefined) {
@@ -13331,7 +13649,7 @@
13331
13649
  await waitasecond.forTime(10);
13332
13650
  // <- Note: Wait for a while to wait for quick responses or sudden but asynchronous errors
13333
13651
  // <- TODO: Put this into configuration
13334
- response.send(executionTask);
13652
+ response.send(executionTask /* <- TODO: satisfies paths['/executions/new']['post']['responses']['200']['content']['application/json'] */);
13335
13653
  /*/
13336
13654
  executionTask.asObservable().subscribe({
13337
13655
  next(partialResult) {
@@ -13351,19 +13669,24 @@
13351
13669
  */
13352
13670
  }
13353
13671
  catch (error) {
13354
- if (!(error instanceof Error)) {
13355
- throw error;
13356
- }
13672
+ assertsError(error);
13357
13673
  response.status(400).send({ error: serializeError(error) });
13358
13674
  }
13359
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
+ });
13360
13682
  const httpServer = http__default["default"].createServer(app);
13361
13683
  const server = new socket_io.Server(httpServer, {
13362
- path: socketioPath,
13363
- transports: [/*'websocket', <- TODO: [🌬] Make websocket transport work */ 'polling'],
13684
+ path: '/socket.io',
13685
+ transports: ['polling', 'websocket' /*, <- TODO: [🌬] Allow to pass `transports`, add 'webtransport' */],
13364
13686
  cors: {
13365
13687
  origin: '*',
13366
13688
  methods: ['GET', 'POST'],
13689
+ // <- TODO: [🌡] Allow to pass
13367
13690
  },
13368
13691
  });
13369
13692
  server.on('connection', (socket) => {
@@ -13417,9 +13740,7 @@
13417
13740
  socket.emit('prompt-response', { promptResult } /* <- Note: [🤛] */);
13418
13741
  }
13419
13742
  catch (error) {
13420
- if (!(error instanceof Error)) {
13421
- throw error;
13422
- }
13743
+ assertsError(error);
13423
13744
  socket.emit('error', serializeError(error) /* <- Note: [🤛] */);
13424
13745
  }
13425
13746
  finally {
@@ -13441,9 +13762,7 @@
13441
13762
  socket.emit('listModels-response', { models } /* <- Note: [🤛] */);
13442
13763
  }
13443
13764
  catch (error) {
13444
- if (!(error instanceof Error)) {
13445
- throw error;
13446
- }
13765
+ assertsError(error);
13447
13766
  socket.emit('error', serializeError(error));
13448
13767
  }
13449
13768
  finally {
@@ -13464,9 +13783,7 @@
13464
13783
  socket.emit('preparePipeline-response', { preparedPipeline } /* <- Note: [🤛] */);
13465
13784
  }
13466
13785
  catch (error) {
13467
- if (!(error instanceof Error)) {
13468
- throw error;
13469
- }
13786
+ assertsError(error);
13470
13787
  socket.emit('error', serializeError(error));
13471
13788
  // <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
13472
13789
  }
@@ -13514,8 +13831,7 @@
13514
13831
  };
13515
13832
  }
13516
13833
  /**
13517
- * TODO: !! Add CORS and security - probbably via `helmet`
13518
- * TODO: [👩🏾‍🤝‍🧑🏾] Allow to pass custom fetch function here - PromptbookFetch
13834
+ * TODO: [🌡] Add CORS and security - probbably via `helmet`
13519
13835
  * TODO: Split this file into multiple functions - handler for each request
13520
13836
  * TODO: Maybe use `$exportJson`
13521
13837
  * TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`
@@ -13574,9 +13890,9 @@
13574
13890
  if (url !== null) {
13575
13891
  rootUrl = suffixUrl(url, '/books');
13576
13892
  }
13577
- let rootPath = '/';
13578
- if (url !== null) {
13579
- 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);
13580
13896
  }
13581
13897
  // TODO: DRY [◽]
13582
13898
  const prepareAndScrapeOptions = {
@@ -13584,7 +13900,7 @@
13584
13900
  isCacheReloaded,
13585
13901
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13586
13902
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13587
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13903
+ const { /* [0] strategy,*/ llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13588
13904
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13589
13905
  const tools = {
13590
13906
  llm,
@@ -13603,7 +13919,6 @@
13603
13919
  });
13604
13920
  // console.log(path, await collection.listPipelines());
13605
13921
  const server = startRemoteServer({
13606
- rootPath,
13607
13922
  port,
13608
13923
  isAnonymousModeAllowed,
13609
13924
  isApplicationModeAllowed: true,
@@ -13616,6 +13931,7 @@
13616
13931
  TODO_USE({ appId, userId });
13617
13932
  return llm;
13618
13933
  },
13934
+ // <- TODO: [🧠][0] Maybe pass here strategy
13619
13935
  });
13620
13936
  keepUnused(server);
13621
13937
  // Note: Already logged by `startRemoteServer`
@@ -13657,7 +13973,7 @@
13657
13973
  isCacheReloaded,
13658
13974
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13659
13975
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13660
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13976
+ const { llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13661
13977
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13662
13978
  tools = {
13663
13979
  llm,
@@ -13696,9 +14012,7 @@
13696
14012
  }
13697
14013
  }
13698
14014
  catch (error) {
13699
- if (!(error instanceof Error)) {
13700
- throw error;
13701
- }
14015
+ assertsError(error);
13702
14016
  console.info(colors__default["default"].red(`Pipeline is not valid ${filename}`));
13703
14017
  console.error(colors__default["default"].bgRed(`${error.name} in ${path.basename(__filename)}`));
13704
14018
  console.error(colors__default["default"].red(error.stack || error.message));
@@ -13922,7 +14236,25 @@
13922
14236
  output: computeUsage(`$2.40 / 1M tokens`),
13923
14237
  },
13924
14238
  },
13925
- // 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
+ // <- [🕕]
13926
14258
  ],
13927
14259
  });
13928
14260
  /**
@@ -14687,7 +15019,6 @@
14687
15019
  prompt: computeUsage(`$5.00 / 1M tokens`),
14688
15020
  output: computeUsage(`$15.00 / 1M tokens`),
14689
15021
  },
14690
- //TODO: [main] !!3 Add gpt-4o-mini-2024-07-18 and all others to be up to date
14691
15022
  },
14692
15023
  /**/
14693
15024
  /**/
@@ -14702,6 +15033,17 @@
14702
15033
  },
14703
15034
  /**/
14704
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
+ /**/
14705
15047
  {
14706
15048
  modelVariant: 'CHAT',
14707
15049
  modelTitle: 'o1-preview',
@@ -14781,6 +15123,7 @@
14781
15123
  },
14782
15124
  },
14783
15125
  /**/
15126
+ // <- [🕕]
14784
15127
  ],
14785
15128
  });
14786
15129
  /**
@@ -15349,11 +15692,17 @@
15349
15692
  description: 'Implementation of Deepseek models',
15350
15693
  vercelProvider: deepseekVercelProvider,
15351
15694
  availableModels: [
15352
- // TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
15353
- 'deepseek-chat',
15354
- 'deepseek-reasoner',
15695
+ {
15696
+ modelName: 'deepseek-chat',
15697
+ modelVariant: 'CHAT',
15698
+ },
15699
+ {
15700
+ modelName: 'deepseek-reasoner',
15701
+ modelVariant: 'CHAT',
15702
+ },
15703
+ // <- [🕕]
15355
15704
  // <- TODO: How picking of the default model looks like in `createExecutionToolsFromVercelProvider`
15356
- ].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
15705
+ ],
15357
15706
  ...options,
15358
15707
  });
15359
15708
  }, {
@@ -15451,6 +15800,10 @@
15451
15800
  vercelProvider: googleGeminiVercelProvider,
15452
15801
  availableModels: [
15453
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',
15454
15807
  'gemini-1.5-flash',
15455
15808
  'gemini-1.5-flash-latest',
15456
15809
  'gemini-1.5-flash-001',
@@ -15466,6 +15819,7 @@
15466
15819
  'gemini-1.5-pro-002',
15467
15820
  'gemini-1.5-pro-exp-0827',
15468
15821
  'gemini-1.0-pro',
15822
+ // <- [🕕]
15469
15823
  ].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
15470
15824
  ...options,
15471
15825
  });
@@ -15745,6 +16099,7 @@
15745
16099
  console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
15746
16100
  }
15747
16101
  const rawResponse = await client.chat.completions.create(rawRequest).catch((error) => {
16102
+ assertsError(error);
15748
16103
  if (this.options.isVerbose) {
15749
16104
  console.info(colors__default["default"].bgRed('error'), error);
15750
16105
  }
@@ -15821,6 +16176,7 @@
15821
16176
  console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
15822
16177
  }
15823
16178
  const rawResponse = await client.completions.create(rawRequest).catch((error) => {
16179
+ assertsError(error);
15824
16180
  if (this.options.isVerbose) {
15825
16181
  console.info(colors__default["default"].bgRed('error'), error);
15826
16182
  }
@@ -15884,6 +16240,7 @@
15884
16240
  console.info(colors__default["default"].bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
15885
16241
  }
15886
16242
  const rawResponse = await client.embeddings.create(rawRequest).catch((error) => {
16243
+ assertsError(error);
15887
16244
  if (this.options.isVerbose) {
15888
16245
  console.info(colors__default["default"].bgRed('error'), error);
15889
16246
  }