@promptbook/remote-server 0.89.0-2 → 0.89.0-20

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 (48) hide show
  1. package/README.md +10 -6
  2. package/esm/index.es.js +518 -242
  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 +20 -8
  6. package/esm/typings/src/_packages/remote-client.index.d.ts +6 -8
  7. package/esm/typings/src/_packages/remote-server.index.d.ts +6 -6
  8. package/esm/typings/src/_packages/types.index.d.ts +18 -16
  9. package/esm/typings/src/cli/cli-commands/login.d.ts +0 -1
  10. package/esm/typings/src/cli/common/$addGlobalOptionsToCommand.d.ts +7 -0
  11. package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +28 -0
  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 +24 -26
  15. package/esm/typings/src/errors/0-index.d.ts +9 -0
  16. package/esm/typings/src/errors/AuthenticationError.d.ts +9 -0
  17. package/esm/typings/src/errors/PipelineExecutionError.d.ts +1 -1
  18. package/esm/typings/src/errors/PromptbookFetchError.d.ts +9 -0
  19. package/esm/typings/src/errors/WrappedError.d.ts +10 -0
  20. package/esm/typings/src/errors/assertsError.d.ts +11 -0
  21. package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
  22. package/esm/typings/src/llm-providers/_common/register/$provideEnvFilename.d.ts +12 -0
  23. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +2 -8
  24. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +2 -0
  25. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +45 -1
  26. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -0
  27. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionToolsOptions.d.ts +1 -1
  28. package/esm/typings/src/llm-providers/anthropic-claude/register-configuration.d.ts +1 -1
  29. package/esm/typings/src/remote-server/RemoteServer.d.ts +23 -0
  30. package/esm/typings/src/remote-server/socket-types/_subtypes/{PromptbookServer_Identification.d.ts → Identification.d.ts} +3 -3
  31. package/esm/typings/src/remote-server/socket-types/_subtypes/identificationToPromptbookToken.d.ts +11 -0
  32. package/esm/typings/src/remote-server/socket-types/_subtypes/promptbookTokenToIdentification.d.ts +10 -0
  33. package/esm/typings/src/remote-server/socket-types/listModels/PromptbookServer_ListModels_Request.d.ts +2 -2
  34. package/esm/typings/src/remote-server/socket-types/prepare/PromptbookServer_PreparePipeline_Request.d.ts +2 -2
  35. package/esm/typings/src/remote-server/socket-types/prompt/PromptbookServer_Prompt_Request.d.ts +2 -2
  36. package/esm/typings/src/remote-server/startRemoteServer.d.ts +2 -3
  37. package/esm/typings/src/remote-server/types/RemoteClientOptions.d.ts +4 -12
  38. package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +89 -4
  39. package/esm/typings/src/scrapers/_common/utils/{scraperFetch.d.ts → promptbookFetch.d.ts} +2 -2
  40. package/esm/typings/src/storage/env-storage/$EnvStorage.d.ts +40 -0
  41. package/esm/typings/src/types/typeAliases.d.ts +19 -0
  42. package/esm/typings/src/utils/organization/TODO_narrow.d.ts +6 -0
  43. package/package.json +11 -5
  44. package/umd/index.umd.js +422 -146
  45. package/umd/index.umd.js.map +1 -1
  46. package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
  47. package/esm/typings/src/playground/BrjappConnector.d.ts +0 -67
  48. package/esm/typings/src/playground/brjapp-api-schema.d.ts +0 -12879
package/esm/index.es.js CHANGED
@@ -2,7 +2,9 @@ import colors from 'colors';
2
2
  import express from 'express';
3
3
  import http from 'http';
4
4
  import { Server } from 'socket.io';
5
- import spaceTrim$1, { spaceTrim } from 'spacetrim';
5
+ import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
6
+ import swaggerJsdoc from 'swagger-jsdoc';
7
+ import swaggerUi from 'swagger-ui-express';
6
8
  import { forTime } from 'waitasecond';
7
9
  import { randomBytes } from 'crypto';
8
10
  import { spawn } from 'child_process';
@@ -31,7 +33,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
31
33
  * @generated
32
34
  * @see https://github.com/webgptorg/promptbook
33
35
  */
34
- const PROMPTBOOK_ENGINE_VERSION = '0.89.0-2';
36
+ const PROMPTBOOK_ENGINE_VERSION = '0.89.0-20';
35
37
  /**
36
38
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
37
39
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -85,6 +87,7 @@ const ADMIN_GITHUB_NAME = 'hejny';
85
87
  * @public exported from `@promptbook/core`
86
88
  */
87
89
  const CLAIM = `It's time for a paradigm shift. The future of software in plain English, French or Latin`;
90
+ // <- TODO: [🐊] Pick the best claim
88
91
  /**
89
92
  * When the title is not provided, the default title is used
90
93
  *
@@ -117,6 +120,7 @@ const VALUE_STRINGS = {
117
120
  infinity: '(infinity; ∞)',
118
121
  negativeInfinity: '(negative infinity; -∞)',
119
122
  unserializable: '(unserializable value)',
123
+ circular: '(circular JSON)',
120
124
  };
121
125
  /**
122
126
  * Small number limit
@@ -156,6 +160,7 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [🤹‍♂️]
156
160
  */
157
161
  const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [🤹‍♂️]
158
162
  // <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
163
+ // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
159
164
  /**
160
165
  * Where to store the temporary downloads
161
166
  *
@@ -207,9 +212,138 @@ const IS_PIPELINE_LOGIC_VALIDATED = just(
207
212
  true);
208
213
  /**
209
214
  * Note: [💞] Ignore a discrepancy between file name and entity name
210
- * TODO: [🧠][🧜‍♂️] Maybe join remoteUrl and path into single value
215
+ * TODO: [🧠][🧜‍♂️] Maybe join remoteServerUrl and path into single value
211
216
  */
212
217
 
218
+ /**
219
+ * Make error report URL for the given error
220
+ *
221
+ * @private private within the repository
222
+ */
223
+ function getErrorReportUrl(error) {
224
+ const report = {
225
+ title: `🐜 Error report from ${NAME}`,
226
+ body: spaceTrim((block) => `
227
+
228
+
229
+ \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
230
+
231
+ \`\`\`
232
+ ${block(error.message || '(no error message)')}
233
+ \`\`\`
234
+
235
+
236
+ ## More info:
237
+
238
+ - **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
239
+ - **Book language version:** ${BOOK_LANGUAGE_VERSION}
240
+ - **Time:** ${new Date().toISOString()}
241
+
242
+ <details>
243
+ <summary>Stack trace:</summary>
244
+
245
+ ## Stack trace:
246
+
247
+ \`\`\`stacktrace
248
+ ${block(error.stack || '(empty)')}
249
+ \`\`\`
250
+ </details>
251
+
252
+ `),
253
+ };
254
+ const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
255
+ reportUrl.searchParams.set('labels', 'bug');
256
+ reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
257
+ reportUrl.searchParams.set('title', report.title);
258
+ reportUrl.searchParams.set('body', report.body);
259
+ return reportUrl;
260
+ }
261
+
262
+ /**
263
+ * This error type indicates that the error should not happen and its last check before crashing with some other error
264
+ *
265
+ * @public exported from `@promptbook/core`
266
+ */
267
+ class UnexpectedError extends Error {
268
+ constructor(message) {
269
+ super(spaceTrim$1((block) => `
270
+ ${block(message)}
271
+
272
+ Note: This error should not happen.
273
+ It's probbably a bug in the pipeline collection
274
+
275
+ Please report issue:
276
+ ${block(getErrorReportUrl(new Error(message)).href)}
277
+
278
+ Or contact us on ${ADMIN_EMAIL}
279
+
280
+ `));
281
+ this.name = 'UnexpectedError';
282
+ Object.setPrototypeOf(this, UnexpectedError.prototype);
283
+ }
284
+ }
285
+
286
+ /**
287
+ * This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
288
+ *
289
+ * @public exported from `@promptbook/core`
290
+ */
291
+ class WrappedError extends Error {
292
+ constructor(whatWasThrown) {
293
+ const tag = `[🤮]`;
294
+ console.error(tag, whatWasThrown);
295
+ super(spaceTrim$1(`
296
+ Non-Error object was thrown
297
+
298
+ Note: Look for ${tag} in the console for more details
299
+ Please report issue on ${ADMIN_EMAIL}
300
+ `));
301
+ this.name = 'WrappedError';
302
+ Object.setPrototypeOf(this, WrappedError.prototype);
303
+ }
304
+ }
305
+
306
+ /**
307
+ * Helper used in catch blocks to assert that the error is an instance of `Error`
308
+ *
309
+ * @param whatWasThrown Any object that was thrown
310
+ * @returns Nothing if the error is an instance of `Error`
311
+ * @throws `WrappedError` or `UnexpectedError` if the error is not standard
312
+ *
313
+ * @private within the repository
314
+ */
315
+ function assertsError(whatWasThrown) {
316
+ // Case 1: Handle error which was rethrown as `WrappedError`
317
+ if (whatWasThrown instanceof WrappedError) {
318
+ const wrappedError = whatWasThrown;
319
+ throw wrappedError;
320
+ }
321
+ // Case 2: Handle unexpected errors
322
+ if (whatWasThrown instanceof UnexpectedError) {
323
+ const unexpectedError = whatWasThrown;
324
+ throw unexpectedError;
325
+ }
326
+ // Case 3: Handle standard errors - keep them up to consumer
327
+ if (whatWasThrown instanceof Error) {
328
+ return;
329
+ }
330
+ // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
331
+ throw new WrappedError(whatWasThrown);
332
+ }
333
+
334
+ /**
335
+ * AuthenticationError is thrown from login function which is dependency of remote server
336
+ *
337
+ * @public exported from `@promptbook/core`
338
+ */
339
+ class AuthenticationError extends Error {
340
+ constructor(message) {
341
+ super(message);
342
+ this.name = 'AuthenticationError';
343
+ Object.setPrototypeOf(this, AuthenticationError.prototype);
344
+ }
345
+ }
346
+
213
347
  /**
214
348
  * Generates random token
215
349
  *
@@ -241,7 +375,7 @@ class PipelineExecutionError extends Error {
241
375
  }
242
376
  }
243
377
  /**
244
- * TODO: !!!!!! Add id to all errors
378
+ * TODO: [🧠][🌂] Add id to all errors
245
379
  */
246
380
 
247
381
  /**
@@ -349,7 +483,7 @@ class LimitReachedError extends Error {
349
483
  */
350
484
  class MissingToolsError extends Error {
351
485
  constructor(message) {
352
- super(spaceTrim((block) => `
486
+ super(spaceTrim$1((block) => `
353
487
  ${block(message)}
354
488
 
355
489
  Note: You have probbably forgot to provide some tools for pipeline execution or preparation
@@ -380,7 +514,7 @@ class NotFoundError extends Error {
380
514
  */
381
515
  class NotYetImplementedError extends Error {
382
516
  constructor(message) {
383
- super(spaceTrim((block) => `
517
+ super(spaceTrim$1((block) => `
384
518
  ${block(message)}
385
519
 
386
520
  Note: This feature is not implemented yet but it will be soon.
@@ -439,70 +573,15 @@ class PipelineUrlError extends Error {
439
573
  }
440
574
 
441
575
  /**
442
- * Make error report URL for the given error
443
- *
444
- * @private private within the repository
445
- */
446
- function getErrorReportUrl(error) {
447
- const report = {
448
- title: `🐜 Error report from ${NAME}`,
449
- body: spaceTrim$1((block) => `
450
-
451
-
452
- \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
453
-
454
- \`\`\`
455
- ${block(error.message || '(no error message)')}
456
- \`\`\`
457
-
458
-
459
- ## More info:
460
-
461
- - **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
462
- - **Book language version:** ${BOOK_LANGUAGE_VERSION}
463
- - **Time:** ${new Date().toISOString()}
464
-
465
- <details>
466
- <summary>Stack trace:</summary>
467
-
468
- ## Stack trace:
469
-
470
- \`\`\`stacktrace
471
- ${block(error.stack || '(empty)')}
472
- \`\`\`
473
- </details>
474
-
475
- `),
476
- };
477
- const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
478
- reportUrl.searchParams.set('labels', 'bug');
479
- reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
480
- reportUrl.searchParams.set('title', report.title);
481
- reportUrl.searchParams.set('body', report.body);
482
- return reportUrl;
483
- }
484
-
485
- /**
486
- * This error type indicates that the error should not happen and its last check before crashing with some other error
576
+ * Error thrown when a fetch request fails
487
577
  *
488
578
  * @public exported from `@promptbook/core`
489
579
  */
490
- class UnexpectedError extends Error {
580
+ class PromptbookFetchError extends Error {
491
581
  constructor(message) {
492
- super(spaceTrim((block) => `
493
- ${block(message)}
494
-
495
- Note: This error should not happen.
496
- It's probbably a bug in the pipeline collection
497
-
498
- Please report issue:
499
- ${block(getErrorReportUrl(new Error(message)).href)}
500
-
501
- Or contact us on ${ADMIN_EMAIL}
502
-
503
- `));
504
- this.name = 'UnexpectedError';
505
- Object.setPrototypeOf(this, UnexpectedError.prototype);
582
+ super(message);
583
+ this.name = 'PromptbookFetchError';
584
+ Object.setPrototypeOf(this, PromptbookFetchError.prototype);
506
585
  }
507
586
  }
508
587
 
@@ -526,7 +605,10 @@ const PROMPTBOOK_ERRORS = {
526
605
  PipelineExecutionError,
527
606
  PipelineLogicError,
528
607
  PipelineUrlError,
608
+ AuthenticationError,
609
+ PromptbookFetchError,
529
610
  UnexpectedError,
611
+ WrappedError,
530
612
  // TODO: [🪑]> VersionMismatchError,
531
613
  };
532
614
  /**
@@ -574,10 +656,14 @@ function serializeError(error) {
574
656
  const { name, message, stack } = error;
575
657
  const { id } = error;
576
658
  if (!Object.keys(ALL_ERRORS).includes(name)) {
577
- console.error(spaceTrim$1((block) => `
659
+ console.error(spaceTrim((block) => `
578
660
 
579
661
  Cannot serialize error with name "${name}"
580
662
 
663
+ Authors of Promptbook probably forgot to add this error into the list of errors:
664
+ https://github.com/webgptorg/promptbook/blob/main/src/errors/0-index.ts
665
+
666
+
581
667
  ${block(stack || message)}
582
668
 
583
669
  `));
@@ -734,11 +820,11 @@ function $execCommand(options) {
734
820
  console.warn(`Command "${humanReadableCommand}" exited with code ${code}`);
735
821
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
736
822
  }
737
- resolve(spaceTrim(output.join('\n')));
823
+ resolve(spaceTrim$1(output.join('\n')));
738
824
  }
739
825
  }
740
826
  else {
741
- resolve(spaceTrim(output.join('\n')));
827
+ resolve(spaceTrim$1(output.join('\n')));
742
828
  }
743
829
  };
744
830
  commandProcess.on('close', finishWithCode);
@@ -756,7 +842,7 @@ function $execCommand(options) {
756
842
  console.warn(error);
757
843
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
758
844
  }
759
- resolve(spaceTrim(output.join('\n')));
845
+ resolve(spaceTrim$1(output.join('\n')));
760
846
  }
761
847
  });
762
848
  }
@@ -781,9 +867,7 @@ async function locateAppOnLinux({ linuxWhich, }) {
781
867
  return result.trim();
782
868
  }
783
869
  catch (error) {
784
- if (!(error instanceof Error)) {
785
- throw error;
786
- }
870
+ assertsError(error);
787
871
  return null;
788
872
  }
789
873
  }
@@ -861,9 +945,7 @@ async function locateAppOnMacOs({ macOsName, }) {
861
945
  return result.trim() + toExec;
862
946
  }
863
947
  catch (error) {
864
- if (!(error instanceof Error)) {
865
- throw error;
866
- }
948
+ assertsError(error);
867
949
  return null;
868
950
  }
869
951
  }
@@ -894,9 +976,7 @@ async function locateAppOnWindows({ appName, windowsSuffix, }) {
894
976
  throw new Error(`Can not locate app ${appName} on Windows.`);
895
977
  }
896
978
  catch (error) {
897
- if (!(error instanceof Error)) {
898
- throw error;
899
- }
979
+ assertsError(error);
900
980
  return null;
901
981
  }
902
982
  }
@@ -1093,7 +1173,7 @@ function checkSerializableAsJson(options) {
1093
1173
  }
1094
1174
  else if (typeof value === 'object') {
1095
1175
  if (value instanceof Date) {
1096
- throw new UnexpectedError(spaceTrim$1((block) => `
1176
+ throw new UnexpectedError(spaceTrim((block) => `
1097
1177
  \`${name}\` is Date
1098
1178
 
1099
1179
  Use \`string_date_iso8601\` instead
@@ -1112,7 +1192,7 @@ function checkSerializableAsJson(options) {
1112
1192
  throw new UnexpectedError(`${name} is RegExp`);
1113
1193
  }
1114
1194
  else if (value instanceof Error) {
1115
- throw new UnexpectedError(spaceTrim$1((block) => `
1195
+ throw new UnexpectedError(spaceTrim((block) => `
1116
1196
  \`${name}\` is unserialized Error
1117
1197
 
1118
1198
  Use function \`serializeError\`
@@ -1134,10 +1214,8 @@ function checkSerializableAsJson(options) {
1134
1214
  JSON.stringify(value); // <- TODO: [0]
1135
1215
  }
1136
1216
  catch (error) {
1137
- if (!(error instanceof Error)) {
1138
- throw error;
1139
- }
1140
- throw new UnexpectedError(spaceTrim$1((block) => `
1217
+ assertsError(error);
1218
+ throw new UnexpectedError(spaceTrim((block) => `
1141
1219
  \`${name}\` is not serializable
1142
1220
 
1143
1221
  ${block(error.stack || error.message)}
@@ -1169,7 +1247,7 @@ function checkSerializableAsJson(options) {
1169
1247
  }
1170
1248
  }
1171
1249
  else {
1172
- throw new UnexpectedError(spaceTrim$1((block) => `
1250
+ throw new UnexpectedError(spaceTrim((block) => `
1173
1251
  \`${name}\` is unknown type
1174
1252
 
1175
1253
  Additional message for \`${name}\`:
@@ -1432,7 +1510,7 @@ function validatePipeline(pipeline) {
1432
1510
  if (!(error instanceof PipelineLogicError)) {
1433
1511
  throw error;
1434
1512
  }
1435
- console.error(spaceTrim((block) => `
1513
+ console.error(spaceTrim$1((block) => `
1436
1514
  Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
1437
1515
 
1438
1516
  ${block(error.message)}
@@ -1459,7 +1537,7 @@ function validatePipeline_InnerFunction(pipeline) {
1459
1537
  })();
1460
1538
  if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1461
1539
  // <- Note: [🚲]
1462
- throw new PipelineLogicError(spaceTrim((block) => `
1540
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1463
1541
  Invalid promptbook URL "${pipeline.pipelineUrl}"
1464
1542
 
1465
1543
  ${block(pipelineIdentification)}
@@ -1467,7 +1545,7 @@ function validatePipeline_InnerFunction(pipeline) {
1467
1545
  }
1468
1546
  if (pipeline.bookVersion !== undefined && !isValidPromptbookVersion(pipeline.bookVersion)) {
1469
1547
  // <- Note: [🚲]
1470
- throw new PipelineLogicError(spaceTrim((block) => `
1548
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1471
1549
  Invalid Promptbook Version "${pipeline.bookVersion}"
1472
1550
 
1473
1551
  ${block(pipelineIdentification)}
@@ -1476,7 +1554,7 @@ function validatePipeline_InnerFunction(pipeline) {
1476
1554
  // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1477
1555
  if (!Array.isArray(pipeline.parameters)) {
1478
1556
  // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1479
- throw new ParseError(spaceTrim((block) => `
1557
+ throw new ParseError(spaceTrim$1((block) => `
1480
1558
  Pipeline is valid JSON but with wrong structure
1481
1559
 
1482
1560
  \`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
@@ -1487,7 +1565,7 @@ function validatePipeline_InnerFunction(pipeline) {
1487
1565
  // TODO: [🧠] Maybe do here some propper JSON-schema / ZOD checking
1488
1566
  if (!Array.isArray(pipeline.tasks)) {
1489
1567
  // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1490
- throw new ParseError(spaceTrim((block) => `
1568
+ throw new ParseError(spaceTrim$1((block) => `
1491
1569
  Pipeline is valid JSON but with wrong structure
1492
1570
 
1493
1571
  \`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
@@ -1513,7 +1591,7 @@ function validatePipeline_InnerFunction(pipeline) {
1513
1591
  // Note: Check each parameter individually
1514
1592
  for (const parameter of pipeline.parameters) {
1515
1593
  if (parameter.isInput && parameter.isOutput) {
1516
- throw new PipelineLogicError(spaceTrim((block) => `
1594
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1517
1595
 
1518
1596
  Parameter \`{${parameter.name}}\` can not be both input and output
1519
1597
 
@@ -1524,7 +1602,7 @@ function validatePipeline_InnerFunction(pipeline) {
1524
1602
  if (!parameter.isInput &&
1525
1603
  !parameter.isOutput &&
1526
1604
  !pipeline.tasks.some((task) => task.dependentParameterNames.includes(parameter.name))) {
1527
- throw new PipelineLogicError(spaceTrim((block) => `
1605
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1528
1606
  Parameter \`{${parameter.name}}\` is created but not used
1529
1607
 
1530
1608
  You can declare {${parameter.name}} as output parameter by adding in the header:
@@ -1536,7 +1614,7 @@ function validatePipeline_InnerFunction(pipeline) {
1536
1614
  }
1537
1615
  // Note: Testing that parameter is either input or result of some task
1538
1616
  if (!parameter.isInput && !pipeline.tasks.some((task) => task.resultingParameterName === parameter.name)) {
1539
- throw new PipelineLogicError(spaceTrim((block) => `
1617
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1540
1618
  Parameter \`{${parameter.name}}\` is declared but not defined
1541
1619
 
1542
1620
  You can do one of these:
@@ -1552,14 +1630,14 @@ function validatePipeline_InnerFunction(pipeline) {
1552
1630
  // Note: Checking each task individually
1553
1631
  for (const task of pipeline.tasks) {
1554
1632
  if (definedParameters.has(task.resultingParameterName)) {
1555
- throw new PipelineLogicError(spaceTrim((block) => `
1633
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1556
1634
  Parameter \`{${task.resultingParameterName}}\` is defined multiple times
1557
1635
 
1558
1636
  ${block(pipelineIdentification)}
1559
1637
  `));
1560
1638
  }
1561
1639
  if (RESERVED_PARAMETER_NAMES.includes(task.resultingParameterName)) {
1562
- throw new PipelineLogicError(spaceTrim((block) => `
1640
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1563
1641
  Parameter name {${task.resultingParameterName}} is reserved, please use different name
1564
1642
 
1565
1643
  ${block(pipelineIdentification)}
@@ -1569,7 +1647,7 @@ function validatePipeline_InnerFunction(pipeline) {
1569
1647
  if (task.jokerParameterNames && task.jokerParameterNames.length > 0) {
1570
1648
  if (!task.format &&
1571
1649
  !task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1572
- throw new PipelineLogicError(spaceTrim((block) => `
1650
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1573
1651
  Joker parameters are used for {${task.resultingParameterName}} but no expectations are defined
1574
1652
 
1575
1653
  ${block(pipelineIdentification)}
@@ -1577,7 +1655,7 @@ function validatePipeline_InnerFunction(pipeline) {
1577
1655
  }
1578
1656
  for (const joker of task.jokerParameterNames) {
1579
1657
  if (!task.dependentParameterNames.includes(joker)) {
1580
- throw new PipelineLogicError(spaceTrim((block) => `
1658
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1581
1659
  Parameter \`{${joker}}\` is used for {${task.resultingParameterName}} as joker but not in \`dependentParameterNames\`
1582
1660
 
1583
1661
  ${block(pipelineIdentification)}
@@ -1588,21 +1666,21 @@ function validatePipeline_InnerFunction(pipeline) {
1588
1666
  if (task.expectations) {
1589
1667
  for (const [unit, { min, max }] of Object.entries(task.expectations)) {
1590
1668
  if (min !== undefined && max !== undefined && min > max) {
1591
- throw new PipelineLogicError(spaceTrim((block) => `
1669
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1592
1670
  Min expectation (=${min}) of ${unit} is higher than max expectation (=${max})
1593
1671
 
1594
1672
  ${block(pipelineIdentification)}
1595
1673
  `));
1596
1674
  }
1597
1675
  if (min !== undefined && min < 0) {
1598
- throw new PipelineLogicError(spaceTrim((block) => `
1676
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1599
1677
  Min expectation of ${unit} must be zero or positive
1600
1678
 
1601
1679
  ${block(pipelineIdentification)}
1602
1680
  `));
1603
1681
  }
1604
1682
  if (max !== undefined && max <= 0) {
1605
- throw new PipelineLogicError(spaceTrim((block) => `
1683
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1606
1684
  Max expectation of ${unit} must be positive
1607
1685
 
1608
1686
  ${block(pipelineIdentification)}
@@ -1624,7 +1702,7 @@ function validatePipeline_InnerFunction(pipeline) {
1624
1702
  while (unresovedTasks.length > 0) {
1625
1703
  if (loopLimit-- < 0) {
1626
1704
  // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1627
- throw new UnexpectedError(spaceTrim((block) => `
1705
+ throw new UnexpectedError(spaceTrim$1((block) => `
1628
1706
  Loop limit reached during detection of circular dependencies in \`validatePipeline\`
1629
1707
 
1630
1708
  ${block(pipelineIdentification)}
@@ -1634,7 +1712,7 @@ function validatePipeline_InnerFunction(pipeline) {
1634
1712
  if (currentlyResovedTasks.length === 0) {
1635
1713
  throw new PipelineLogicError(
1636
1714
  // TODO: [🐎] DRY
1637
- spaceTrim((block) => `
1715
+ spaceTrim$1((block) => `
1638
1716
 
1639
1717
  Can not resolve some parameters:
1640
1718
  Either you are using a parameter that is not defined, or there are some circular dependencies.
@@ -1744,9 +1822,7 @@ function isValidJsonString(value /* <- [👨‍⚖️] */) {
1744
1822
  return true;
1745
1823
  }
1746
1824
  catch (error) {
1747
- if (!(error instanceof Error)) {
1748
- throw error;
1749
- }
1825
+ assertsError(error);
1750
1826
  if (error.message.includes('Unexpected token')) {
1751
1827
  return false;
1752
1828
  }
@@ -1798,7 +1874,7 @@ function deserializeError(error) {
1798
1874
  message = `${name}: ${message}`;
1799
1875
  }
1800
1876
  if (stack !== undefined && stack !== '') {
1801
- message = spaceTrim$1((block) => `
1877
+ message = spaceTrim((block) => `
1802
1878
  ${block(message)}
1803
1879
 
1804
1880
  Original stack trace:
@@ -1835,11 +1911,11 @@ function assertsTaskSuccessful(executionResult) {
1835
1911
  throw deserializeError(errors[0]);
1836
1912
  }
1837
1913
  else {
1838
- throw new PipelineExecutionError(spaceTrim((block) => `
1914
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
1839
1915
  Multiple errors occurred during Promptbook execution
1840
1916
 
1841
1917
  ${block(errors
1842
- .map(({ name, stack, message }, index) => spaceTrim((block) => `
1918
+ .map(({ name, stack, message }, index) => spaceTrim$1((block) => `
1843
1919
  ${name} ${index + 1}:
1844
1920
  ${block(stack || message)}
1845
1921
  `))
@@ -1884,8 +1960,8 @@ function createTask(options) {
1884
1960
  updatedAt = new Date();
1885
1961
  errors.push(...executionResult.errors);
1886
1962
  warnings.push(...executionResult.warnings);
1887
- // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
1888
- // TODO: [🧠] !!! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
1963
+ // <- TODO: [🌂] Only unique errors and warnings should be added (or filtered)
1964
+ // TODO: [🧠] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
1889
1965
  // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
1890
1966
  // And delete `ExecutionTask.currentValue.preparedPipeline`
1891
1967
  assertsTaskSuccessful(executionResult);
@@ -1895,6 +1971,7 @@ function createTask(options) {
1895
1971
  partialResultSubject.next(executionResult);
1896
1972
  }
1897
1973
  catch (error) {
1974
+ assertsError(error);
1898
1975
  status = 'ERROR';
1899
1976
  errors.push(error);
1900
1977
  partialResultSubject.error(error);
@@ -2197,7 +2274,7 @@ function pipelineJsonToString(pipelineJson) {
2197
2274
  pipelineString += '\n\n';
2198
2275
  pipelineString += '```' + contentLanguage;
2199
2276
  pipelineString += '\n';
2200
- pipelineString += spaceTrim$1(content);
2277
+ pipelineString += spaceTrim(content);
2201
2278
  // <- TODO: [main] !!3 Escape
2202
2279
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
2203
2280
  pipelineString += '\n';
@@ -2302,7 +2379,7 @@ class SimplePipelineCollection {
2302
2379
  for (const pipeline of pipelines) {
2303
2380
  // TODO: [👠] DRY
2304
2381
  if (pipeline.pipelineUrl === undefined) {
2305
- throw new PipelineUrlError(spaceTrim(`
2382
+ throw new PipelineUrlError(spaceTrim$1(`
2306
2383
  Pipeline with name "${pipeline.title}" does not have defined URL
2307
2384
 
2308
2385
  File:
@@ -2324,7 +2401,7 @@ class SimplePipelineCollection {
2324
2401
  pipelineJsonToString(unpreparePipeline(pipeline)) !==
2325
2402
  pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
2326
2403
  const existing = this.collection.get(pipeline.pipelineUrl);
2327
- throw new PipelineUrlError(spaceTrim(`
2404
+ throw new PipelineUrlError(spaceTrim$1(`
2328
2405
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍎
2329
2406
 
2330
2407
  Conflicting files:
@@ -2356,13 +2433,13 @@ class SimplePipelineCollection {
2356
2433
  const pipeline = this.collection.get(url);
2357
2434
  if (!pipeline) {
2358
2435
  if (this.listPipelines().length === 0) {
2359
- throw new NotFoundError(spaceTrim(`
2436
+ throw new NotFoundError(spaceTrim$1(`
2360
2437
  Pipeline with url "${url}" not found
2361
2438
 
2362
2439
  No pipelines available
2363
2440
  `));
2364
2441
  }
2365
- throw new NotFoundError(spaceTrim((block) => `
2442
+ throw new NotFoundError(spaceTrim$1((block) => `
2366
2443
  Pipeline with url "${url}" not found
2367
2444
 
2368
2445
  Available pipelines:
@@ -2705,14 +2782,15 @@ class MultipleLlmExecutionTools {
2705
2782
  }
2706
2783
  }
2707
2784
  catch (error) {
2708
- if (!(error instanceof Error) || error instanceof UnexpectedError) {
2785
+ assertsError(error);
2786
+ if (error instanceof UnexpectedError) {
2709
2787
  throw error;
2710
2788
  }
2711
2789
  errors.push({ llmExecutionTools, error });
2712
2790
  }
2713
2791
  }
2714
2792
  if (errors.length === 1) {
2715
- throw errors[0];
2793
+ throw errors[0].error;
2716
2794
  }
2717
2795
  else if (errors.length > 1) {
2718
2796
  throw new PipelineExecutionError(
@@ -2720,7 +2798,7 @@ class MultipleLlmExecutionTools {
2720
2798
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
2721
2799
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
2722
2800
  // 3) ...
2723
- spaceTrim$1((block) => `
2801
+ spaceTrim((block) => `
2724
2802
  All execution tools failed:
2725
2803
 
2726
2804
  ${block(errors
@@ -2733,7 +2811,7 @@ class MultipleLlmExecutionTools {
2733
2811
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\``);
2734
2812
  }
2735
2813
  else {
2736
- throw new PipelineExecutionError(spaceTrim$1((block) => `
2814
+ throw new PipelineExecutionError(spaceTrim((block) => `
2737
2815
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}"
2738
2816
 
2739
2817
  Available \`LlmExecutionTools\`:
@@ -2766,7 +2844,7 @@ class MultipleLlmExecutionTools {
2766
2844
  */
2767
2845
  function joinLlmExecutionTools(...llmExecutionTools) {
2768
2846
  if (llmExecutionTools.length === 0) {
2769
- const warningMessage = spaceTrim$1(`
2847
+ const warningMessage = spaceTrim(`
2770
2848
  You have not provided any \`LlmExecutionTools\`
2771
2849
  This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.
2772
2850
 
@@ -3057,14 +3135,14 @@ function $registeredScrapersMessage(availableScrapers) {
3057
3135
  return { ...metadata, isMetadataAviailable, isInstalled, isAvilableInTools };
3058
3136
  });
3059
3137
  if (metadata.length === 0) {
3060
- return spaceTrim$1(`
3138
+ return spaceTrim(`
3061
3139
  **No scrapers are available**
3062
3140
 
3063
3141
  This is a unexpected behavior, you are probably using some broken version of Promptbook
3064
3142
  At least there should be available the metadata of the scrapers
3065
3143
  `);
3066
3144
  }
3067
- return spaceTrim$1((block) => `
3145
+ return spaceTrim((block) => `
3068
3146
  Available scrapers are:
3069
3147
  ${block(metadata
3070
3148
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvilableInBrowser, isAvilableInTools, }, i) => {
@@ -3546,17 +3624,22 @@ function titleToName(value) {
3546
3624
  /**
3547
3625
  * The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
3548
3626
  *
3549
- * @private as default `fetch` function used in Promptbook scrapers
3627
+ * @public exported from `@promptbook/core`
3550
3628
  */
3551
- const scraperFetch = async (url, init) => {
3629
+ const promptbookFetch = async (urlOrRequest, init) => {
3552
3630
  try {
3553
- return await fetch(url, init);
3631
+ return await fetch(urlOrRequest, init);
3554
3632
  }
3555
3633
  catch (error) {
3556
- if (!(error instanceof Error)) {
3557
- throw error;
3634
+ assertsError(error);
3635
+ let url;
3636
+ if (typeof urlOrRequest === 'string') {
3637
+ url = urlOrRequest;
3638
+ }
3639
+ else if (urlOrRequest instanceof Request) {
3640
+ url = urlOrRequest.url;
3558
3641
  }
3559
- throw new KnowledgeScrapeError(spaceTrim$1((block) => `
3642
+ throw new PromptbookFetchError(spaceTrim((block) => `
3560
3643
  Can not fetch "${url}"
3561
3644
 
3562
3645
  Fetch error:
@@ -3577,7 +3660,7 @@ const scraperFetch = async (url, init) => {
3577
3660
  async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
3578
3661
  // console.log('!! makeKnowledgeSourceHandler', knowledgeSource);
3579
3662
  var _a;
3580
- const { fetch = scraperFetch } = tools;
3663
+ const { fetch = promptbookFetch } = tools;
3581
3664
  const { knowledgeSourceContent } = knowledgeSource;
3582
3665
  let { name } = knowledgeSource;
3583
3666
  const { rootDirname = null,
@@ -3647,7 +3730,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
3647
3730
  const fileExtension = getFileExtension(filename);
3648
3731
  const mimeType = extensionToMimeType(fileExtension || '');
3649
3732
  if (!(await isFileExisting(filename, tools.fs))) {
3650
- throw new NotFoundError(spaceTrim$1((block) => `
3733
+ throw new NotFoundError(spaceTrim((block) => `
3651
3734
  Can not make source handler for file which does not exist:
3652
3735
 
3653
3736
  File:
@@ -3734,7 +3817,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
3734
3817
  // <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
3735
3818
  break;
3736
3819
  }
3737
- console.warn(spaceTrim$1((block) => `
3820
+ console.warn(spaceTrim((block) => `
3738
3821
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
3739
3822
 
3740
3823
  The source:
@@ -3750,7 +3833,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
3750
3833
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
3751
3834
  }
3752
3835
  if (partialPieces === null) {
3753
- throw new KnowledgeScrapeError(spaceTrim$1((block) => `
3836
+ throw new KnowledgeScrapeError(spaceTrim((block) => `
3754
3837
  Cannot scrape knowledge
3755
3838
 
3756
3839
  The source:
@@ -3779,9 +3862,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
3779
3862
  knowledgePreparedUnflatten[index] = pieces;
3780
3863
  }
3781
3864
  catch (error) {
3782
- if (!(error instanceof Error)) {
3783
- throw error;
3784
- }
3865
+ assertsError(error);
3785
3866
  console.warn(error);
3786
3867
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
3787
3868
  }
@@ -3828,7 +3909,7 @@ async function prepareTasks(pipeline, tools, options) {
3828
3909
  if (task.taskType === 'PROMPT_TASK' &&
3829
3910
  knowledgePiecesCount > 0 &&
3830
3911
  !dependentParameterNames.includes('knowledge')) {
3831
- preparedContent = spaceTrim(`
3912
+ preparedContent = spaceTrim$1(`
3832
3913
  {content}
3833
3914
 
3834
3915
  ## Knowledge
@@ -4073,13 +4154,19 @@ function valueToString(value) {
4073
4154
  return value.toISOString();
4074
4155
  }
4075
4156
  else {
4076
- return JSON.stringify(value);
4157
+ try {
4158
+ return JSON.stringify(value);
4159
+ }
4160
+ catch (error) {
4161
+ if (error instanceof TypeError && error.message.includes('circular structure')) {
4162
+ return VALUE_STRINGS.circular;
4163
+ }
4164
+ throw error;
4165
+ }
4077
4166
  }
4078
4167
  }
4079
4168
  catch (error) {
4080
- if (!(error instanceof Error)) {
4081
- throw error;
4082
- }
4169
+ assertsError(error);
4083
4170
  console.error(error);
4084
4171
  return VALUE_STRINGS.unserializable;
4085
4172
  }
@@ -4136,10 +4223,8 @@ function extractVariablesFromJavascript(script) {
4136
4223
  }
4137
4224
  }
4138
4225
  catch (error) {
4139
- if (!(error instanceof Error)) {
4140
- throw error;
4141
- }
4142
- throw new ParseError(spaceTrim((block) => `
4226
+ assertsError(error);
4227
+ throw new ParseError(spaceTrim$1((block) => `
4143
4228
  Can not extract variables from the script
4144
4229
  ${block(error.stack || error.message)}
4145
4230
 
@@ -4282,7 +4367,7 @@ const CsvFormatDefinition = {
4282
4367
  // TODO: [👨🏾‍🤝‍👨🏼] DRY csv parsing
4283
4368
  const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
4284
4369
  if (csv.errors.length !== 0) {
4285
- throw new CsvFormatError(spaceTrim$1((block) => `
4370
+ throw new CsvFormatError(spaceTrim((block) => `
4286
4371
  CSV parsing error
4287
4372
 
4288
4373
  Error(s) from CSV parsing:
@@ -4313,7 +4398,7 @@ const CsvFormatDefinition = {
4313
4398
  // TODO: [👨🏾‍🤝‍👨🏼] DRY csv parsing
4314
4399
  const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
4315
4400
  if (csv.errors.length !== 0) {
4316
- throw new CsvFormatError(spaceTrim$1((block) => `
4401
+ throw new CsvFormatError(spaceTrim((block) => `
4317
4402
  CSV parsing error
4318
4403
 
4319
4404
  Error(s) from CSV parsing:
@@ -4503,7 +4588,7 @@ function mapAvailableToExpectedParameters(options) {
4503
4588
  }
4504
4589
  // Phase 2️⃣: Non-matching mapping
4505
4590
  if (expectedParameterNames.size !== availableParametersNames.size) {
4506
- throw new PipelineExecutionError(spaceTrim$1((block) => `
4591
+ throw new PipelineExecutionError(spaceTrim((block) => `
4507
4592
  Can not map available parameters to expected parameters
4508
4593
 
4509
4594
  Mapped parameters:
@@ -4905,7 +4990,7 @@ async function executeAttempts(options) {
4905
4990
  const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
4906
4991
  // TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
4907
4992
  if (isJokerAttempt && !jokerParameterName) {
4908
- throw new UnexpectedError(spaceTrim((block) => `
4993
+ throw new UnexpectedError(spaceTrim$1((block) => `
4909
4994
  Joker not found in attempt ${attempt}
4910
4995
 
4911
4996
  ${block(pipelineIdentification)}
@@ -4916,7 +5001,7 @@ async function executeAttempts(options) {
4916
5001
  $ongoingTaskResult.$expectError = null;
4917
5002
  if (isJokerAttempt) {
4918
5003
  if (parameters[jokerParameterName] === undefined) {
4919
- throw new PipelineExecutionError(spaceTrim((block) => `
5004
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
4920
5005
  Joker parameter {${jokerParameterName}} not defined
4921
5006
 
4922
5007
  ${block(pipelineIdentification)}
@@ -4974,7 +5059,7 @@ async function executeAttempts(options) {
4974
5059
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
4975
5060
  break variant;
4976
5061
  case 'EMBEDDING':
4977
- throw new PipelineExecutionError(spaceTrim((block) => `
5062
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
4978
5063
  Embedding model can not be used in pipeline
4979
5064
 
4980
5065
  This should be catched during parsing
@@ -4985,7 +5070,7 @@ async function executeAttempts(options) {
4985
5070
  break variant;
4986
5071
  // <- case [🤖]:
4987
5072
  default:
4988
- throw new PipelineExecutionError(spaceTrim((block) => `
5073
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
4989
5074
  Unknown model variant "${task.modelRequirements.modelVariant}"
4990
5075
 
4991
5076
  ${block(pipelineIdentification)}
@@ -4996,14 +5081,14 @@ async function executeAttempts(options) {
4996
5081
  break;
4997
5082
  case 'SCRIPT_TASK':
4998
5083
  if (arrayableToArray(tools.script).length === 0) {
4999
- throw new PipelineExecutionError(spaceTrim((block) => `
5084
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5000
5085
  No script execution tools are available
5001
5086
 
5002
5087
  ${block(pipelineIdentification)}
5003
5088
  `));
5004
5089
  }
5005
5090
  if (!task.contentLanguage) {
5006
- throw new PipelineExecutionError(spaceTrim((block) => `
5091
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5007
5092
  Script language is not defined for SCRIPT TASK "${task.name}"
5008
5093
 
5009
5094
  ${block(pipelineIdentification)}
@@ -5020,9 +5105,7 @@ async function executeAttempts(options) {
5020
5105
  break scripts;
5021
5106
  }
5022
5107
  catch (error) {
5023
- if (!(error instanceof Error)) {
5024
- throw error;
5025
- }
5108
+ assertsError(error);
5026
5109
  if (error instanceof UnexpectedError) {
5027
5110
  throw error;
5028
5111
  }
@@ -5036,7 +5119,7 @@ async function executeAttempts(options) {
5036
5119
  throw $ongoingTaskResult.$scriptPipelineExecutionErrors[0];
5037
5120
  }
5038
5121
  else {
5039
- throw new PipelineExecutionError(spaceTrim((block) => `
5122
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5040
5123
  Script execution failed ${$ongoingTaskResult.$scriptPipelineExecutionErrors.length}x
5041
5124
 
5042
5125
  ${block(pipelineIdentification)}
@@ -5050,7 +5133,7 @@ async function executeAttempts(options) {
5050
5133
  break taskType;
5051
5134
  case 'DIALOG_TASK':
5052
5135
  if (tools.userInterface === undefined) {
5053
- throw new PipelineExecutionError(spaceTrim((block) => `
5136
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5054
5137
  User interface tools are not available
5055
5138
 
5056
5139
  ${block(pipelineIdentification)}
@@ -5068,7 +5151,7 @@ async function executeAttempts(options) {
5068
5151
  break taskType;
5069
5152
  // <- case: [🅱]
5070
5153
  default:
5071
- throw new PipelineExecutionError(spaceTrim((block) => `
5154
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5072
5155
  Unknown execution type "${task.taskType}"
5073
5156
 
5074
5157
  ${block(pipelineIdentification)}
@@ -5092,9 +5175,7 @@ async function executeAttempts(options) {
5092
5175
  break scripts;
5093
5176
  }
5094
5177
  catch (error) {
5095
- if (!(error instanceof Error)) {
5096
- throw error;
5097
- }
5178
+ assertsError(error);
5098
5179
  if (error instanceof UnexpectedError) {
5099
5180
  throw error;
5100
5181
  }
@@ -5117,7 +5198,7 @@ async function executeAttempts(options) {
5117
5198
  }
5118
5199
  catch (error) {
5119
5200
  keepUnused(error);
5120
- throw new ExpectError(spaceTrim((block) => `
5201
+ throw new ExpectError(spaceTrim$1((block) => `
5121
5202
  Expected valid JSON string
5122
5203
 
5123
5204
  ${block(
@@ -5127,7 +5208,7 @@ async function executeAttempts(options) {
5127
5208
  }
5128
5209
  }
5129
5210
  else {
5130
- throw new UnexpectedError(spaceTrim((block) => `
5211
+ throw new UnexpectedError(spaceTrim$1((block) => `
5131
5212
  Unknown format "${task.format}"
5132
5213
 
5133
5214
  ${block(pipelineIdentification)}
@@ -5167,7 +5248,7 @@ async function executeAttempts(options) {
5167
5248
  }
5168
5249
  }
5169
5250
  if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
5170
- throw new PipelineExecutionError(spaceTrim((block) => {
5251
+ throw new PipelineExecutionError(spaceTrim$1((block) => {
5171
5252
  var _a, _b, _c;
5172
5253
  return `
5173
5254
  LLM execution failed ${maxExecutionAttempts}x
@@ -5190,7 +5271,7 @@ async function executeAttempts(options) {
5190
5271
  Last result:
5191
5272
  ${block($ongoingTaskResult.$resultString === null
5192
5273
  ? 'null'
5193
- : spaceTrim($ongoingTaskResult.$resultString)
5274
+ : spaceTrim$1($ongoingTaskResult.$resultString)
5194
5275
  .split('\n')
5195
5276
  .map((line) => `> ${line}`)
5196
5277
  .join('\n'))}
@@ -5200,7 +5281,7 @@ async function executeAttempts(options) {
5200
5281
  }
5201
5282
  }
5202
5283
  if ($ongoingTaskResult.$resultString === null) {
5203
- throw new UnexpectedError(spaceTrim((block) => `
5284
+ throw new UnexpectedError(spaceTrim$1((block) => `
5204
5285
  Something went wrong and prompt result is null
5205
5286
 
5206
5287
  ${block(pipelineIdentification)}
@@ -5223,7 +5304,7 @@ async function executeFormatSubvalues(options) {
5223
5304
  return /* not await */ executeAttempts(options);
5224
5305
  }
5225
5306
  if (jokerParameterNames.length !== 0) {
5226
- throw new UnexpectedError(spaceTrim$1((block) => `
5307
+ throw new UnexpectedError(spaceTrim((block) => `
5227
5308
  JOKER parameters are not supported together with FOREACH command
5228
5309
 
5229
5310
  [🧞‍♀️] This should be prevented in \`validatePipeline\`
@@ -5236,7 +5317,7 @@ async function executeFormatSubvalues(options) {
5236
5317
  if (formatDefinition === undefined) {
5237
5318
  throw new UnexpectedError(
5238
5319
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
5239
- spaceTrim$1((block) => `
5320
+ spaceTrim((block) => `
5240
5321
  Unsupported format "${task.foreach.formatName}"
5241
5322
 
5242
5323
  Available formats:
@@ -5253,7 +5334,7 @@ async function executeFormatSubvalues(options) {
5253
5334
  if (subvalueDefinition === undefined) {
5254
5335
  throw new UnexpectedError(
5255
5336
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
5256
- spaceTrim$1((block) => `
5337
+ spaceTrim((block) => `
5257
5338
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
5258
5339
 
5259
5340
  Available subformat names for format "${formatDefinition.formatName}":
@@ -5286,7 +5367,7 @@ async function executeFormatSubvalues(options) {
5286
5367
  if (!(error instanceof PipelineExecutionError)) {
5287
5368
  throw error;
5288
5369
  }
5289
- throw new PipelineExecutionError(spaceTrim$1((block) => `
5370
+ throw new PipelineExecutionError(spaceTrim((block) => `
5290
5371
  ${error.message}
5291
5372
 
5292
5373
  This is error in FOREACH command
@@ -5306,7 +5387,7 @@ async function executeFormatSubvalues(options) {
5306
5387
  ...options,
5307
5388
  priority: priority + index,
5308
5389
  parameters: allSubparameters,
5309
- pipelineIdentification: spaceTrim$1((block) => `
5390
+ pipelineIdentification: spaceTrim((block) => `
5310
5391
  ${block(pipelineIdentification)}
5311
5392
  Subparameter index: ${index}
5312
5393
  `),
@@ -5368,7 +5449,7 @@ async function getReservedParametersForTask(options) {
5368
5449
  // Note: Doublecheck that ALL reserved parameters are defined:
5369
5450
  for (const parameterName of RESERVED_PARAMETER_NAMES) {
5370
5451
  if (reservedParameters[parameterName] === undefined) {
5371
- throw new UnexpectedError(spaceTrim((block) => `
5452
+ throw new UnexpectedError(spaceTrim$1((block) => `
5372
5453
  Reserved parameter {${parameterName}} is not defined
5373
5454
 
5374
5455
  ${block(pipelineIdentification)}
@@ -5396,7 +5477,7 @@ async function executeTask(options) {
5396
5477
  const dependentParameterNames = new Set(currentTask.dependentParameterNames);
5397
5478
  // TODO: [👩🏾‍🤝‍👩🏻] Use here `mapAvailableToExpectedParameters`
5398
5479
  if (union(difference(usedParameterNames, dependentParameterNames), difference(dependentParameterNames, usedParameterNames)).size !== 0) {
5399
- throw new UnexpectedError(spaceTrim((block) => `
5480
+ throw new UnexpectedError(spaceTrim$1((block) => `
5400
5481
  Dependent parameters are not consistent with used parameters:
5401
5482
 
5402
5483
  Dependent parameters:
@@ -5436,7 +5517,7 @@ async function executeTask(options) {
5436
5517
  else if (!definedParameterNames.has(parameterName) && usedParameterNames.has(parameterName)) {
5437
5518
  // Houston, we have a problem
5438
5519
  // Note: Checking part is also done in `validatePipeline`, but it’s good to doublecheck
5439
- throw new UnexpectedError(spaceTrim((block) => `
5520
+ throw new UnexpectedError(spaceTrim$1((block) => `
5440
5521
  Parameter \`{${parameterName}}\` is NOT defined
5441
5522
  BUT used in task "${currentTask.title || currentTask.name}"
5442
5523
 
@@ -5502,7 +5583,7 @@ function filterJustOutputParameters(options) {
5502
5583
  for (const parameter of preparedPipeline.parameters.filter(({ isOutput }) => isOutput)) {
5503
5584
  if (parametersToPass[parameter.name] === undefined) {
5504
5585
  // [4]
5505
- $warnings.push(new PipelineExecutionError(spaceTrim((block) => `
5586
+ $warnings.push(new PipelineExecutionError(spaceTrim$1((block) => `
5506
5587
  Parameter \`{${parameter.name}}\` should be an output parameter, but it was not generated during pipeline execution
5507
5588
 
5508
5589
  ${block(pipelineIdentification)}
@@ -5577,7 +5658,7 @@ async function executePipeline(options) {
5577
5658
  for (const parameterName of Object.keys(inputParameters)) {
5578
5659
  const parameter = preparedPipeline.parameters.find(({ name }) => name === parameterName);
5579
5660
  if (parameter === undefined) {
5580
- warnings.push(new PipelineExecutionError(spaceTrim((block) => `
5661
+ warnings.push(new PipelineExecutionError(spaceTrim$1((block) => `
5581
5662
  Extra parameter {${parameterName}} is being passed which is not part of the pipeline.
5582
5663
 
5583
5664
  ${block(pipelineIdentification)}
@@ -5592,7 +5673,7 @@ async function executePipeline(options) {
5592
5673
  // TODO: [🧠] This should be also non-critical error
5593
5674
  return exportJson({
5594
5675
  name: 'pipelineExecutorResult',
5595
- message: spaceTrim((block) => `
5676
+ message: spaceTrim$1((block) => `
5596
5677
  Unuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
5597
5678
 
5598
5679
  ${block(pipelineIdentification)}
@@ -5601,7 +5682,7 @@ async function executePipeline(options) {
5601
5682
  value: {
5602
5683
  isSuccessful: false,
5603
5684
  errors: [
5604
- new PipelineExecutionError(spaceTrim((block) => `
5685
+ new PipelineExecutionError(spaceTrim$1((block) => `
5605
5686
  Parameter \`{${parameter.name}}\` is passed as input parameter but it is not input
5606
5687
 
5607
5688
  ${block(pipelineIdentification)}
@@ -5628,7 +5709,7 @@ async function executePipeline(options) {
5628
5709
  while (unresovedTasks.length > 0) {
5629
5710
  if (loopLimit-- < 0) {
5630
5711
  // Note: Really UnexpectedError not LimitReachedError - this should be catched during validatePipeline
5631
- throw new UnexpectedError(spaceTrim((block) => `
5712
+ throw new UnexpectedError(spaceTrim$1((block) => `
5632
5713
  Loop limit reached during resolving parameters pipeline execution
5633
5714
 
5634
5715
  ${block(pipelineIdentification)}
@@ -5638,7 +5719,7 @@ async function executePipeline(options) {
5638
5719
  if (!currentTask && resolving.length === 0) {
5639
5720
  throw new UnexpectedError(
5640
5721
  // TODO: [🐎] DRY
5641
- spaceTrim((block) => `
5722
+ spaceTrim$1((block) => `
5642
5723
  Can not resolve some parameters:
5643
5724
 
5644
5725
  ${block(pipelineIdentification)}
@@ -5678,7 +5759,7 @@ async function executePipeline(options) {
5678
5759
  tools,
5679
5760
  onProgress(newOngoingResult) {
5680
5761
  if (isReturned) {
5681
- throw new UnexpectedError(spaceTrim((block) => `
5762
+ throw new UnexpectedError(spaceTrim$1((block) => `
5682
5763
  Can not call \`onProgress\` after pipeline execution is finished
5683
5764
 
5684
5765
  ${block(pipelineIdentification)}
@@ -5694,7 +5775,7 @@ async function executePipeline(options) {
5694
5775
  }
5695
5776
  },
5696
5777
  $executionReport: executionReport,
5697
- pipelineIdentification: spaceTrim((block) => `
5778
+ pipelineIdentification: spaceTrim$1((block) => `
5698
5779
  ${block(pipelineIdentification)}
5699
5780
  Task name: ${currentTask.name}
5700
5781
  Task title: ${currentTask.title}
@@ -5715,9 +5796,7 @@ async function executePipeline(options) {
5715
5796
  await Promise.all(resolving);
5716
5797
  }
5717
5798
  catch (error /* <- Note: [3] */) {
5718
- if (!(error instanceof Error)) {
5719
- throw error;
5720
- }
5799
+ assertsError(error);
5721
5800
  // Note: No need to rethrow UnexpectedError
5722
5801
  // if (error instanceof UnexpectedError) {
5723
5802
  // Note: Count usage, [🧠] Maybe put to separate function executionReportJsonToUsage + DRY [🤹‍♂️]
@@ -5805,7 +5884,7 @@ function createPipelineExecutor(options) {
5805
5884
  preparedPipeline = pipeline;
5806
5885
  }
5807
5886
  else if (isNotPreparedWarningSupressed !== true) {
5808
- console.warn(spaceTrim((block) => `
5887
+ console.warn(spaceTrim$1((block) => `
5809
5888
  Pipeline is not prepared
5810
5889
 
5811
5890
  ${block(pipelineIdentification)}
@@ -5829,7 +5908,7 @@ function createPipelineExecutor(options) {
5829
5908
  inputParameters,
5830
5909
  tools,
5831
5910
  onProgress,
5832
- pipelineIdentification: spaceTrim((block) => `
5911
+ pipelineIdentification: spaceTrim$1((block) => `
5833
5912
  ${block(pipelineIdentification)}
5834
5913
  ${runCount === 1 ? '' : `Run #${runCount}`}
5835
5914
  `),
@@ -5927,13 +6006,13 @@ function $registeredLlmToolsMessage() {
5927
6006
  });
5928
6007
  const usedEnvMessage = `Unknown \`.env\` file` ;
5929
6008
  if (metadata.length === 0) {
5930
- return spaceTrim$1((block) => `
6009
+ return spaceTrim((block) => `
5931
6010
  No LLM providers are available.
5932
6011
 
5933
6012
  ${block(usedEnvMessage)}
5934
6013
  `);
5935
6014
  }
5936
- return spaceTrim$1((block) => `
6015
+ return spaceTrim((block) => `
5937
6016
 
5938
6017
  ${block(usedEnvMessage)}
5939
6018
 
@@ -5979,7 +6058,7 @@ function $registeredLlmToolsMessage() {
5979
6058
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
5980
6059
  }
5981
6060
  }
5982
- let providerMessage = spaceTrim$1(`
6061
+ let providerMessage = spaceTrim(`
5983
6062
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
5984
6063
  ${morePieces.join('; ')}
5985
6064
  `);
@@ -6019,7 +6098,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
6019
6098
  .list()
6020
6099
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
6021
6100
  if (registeredItem === undefined) {
6022
- throw new Error(spaceTrim$1((block) => `
6101
+ throw new Error(spaceTrim((block) => `
6023
6102
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
6024
6103
 
6025
6104
  You have probably forgotten install and import the provider package.
@@ -6303,13 +6382,13 @@ function removeQuotes(text) {
6303
6382
  * @public exported from `@promptbook/utils`
6304
6383
  */
6305
6384
  function trimCodeBlock(value) {
6306
- value = spaceTrim(value);
6385
+ value = spaceTrim$1(value);
6307
6386
  if (!/^```[a-z]*(.*)```$/is.test(value)) {
6308
6387
  return value;
6309
6388
  }
6310
6389
  value = value.replace(/^```[a-z]*/i, '');
6311
6390
  value = value.replace(/```$/i, '');
6312
- value = spaceTrim(value);
6391
+ value = spaceTrim$1(value);
6313
6392
  return value;
6314
6393
  }
6315
6394
 
@@ -6322,9 +6401,9 @@ function trimCodeBlock(value) {
6322
6401
  * @public exported from `@promptbook/utils`
6323
6402
  */
6324
6403
  function trimEndOfCodeBlock(value) {
6325
- value = spaceTrim(value);
6404
+ value = spaceTrim$1(value);
6326
6405
  value = value.replace(/```$/g, '');
6327
- value = spaceTrim(value);
6406
+ value = spaceTrim$1(value);
6328
6407
  return value;
6329
6408
  }
6330
6409
 
@@ -6346,7 +6425,7 @@ function unwrapResult(text, options) {
6346
6425
  let trimmedText = text;
6347
6426
  // Remove leading and trailing spaces and newlines
6348
6427
  if (isTrimmed) {
6349
- trimmedText = spaceTrim(trimmedText);
6428
+ trimmedText = spaceTrim$1(trimmedText);
6350
6429
  }
6351
6430
  let processedText = trimmedText;
6352
6431
  if (isIntroduceSentenceRemoved) {
@@ -6355,7 +6434,7 @@ function unwrapResult(text, options) {
6355
6434
  // Remove the introduce sentence and quotes by replacing it with an empty string
6356
6435
  processedText = processedText.replace(introduceSentenceRegex, '');
6357
6436
  }
6358
- processedText = spaceTrim(processedText);
6437
+ processedText = spaceTrim$1(processedText);
6359
6438
  }
6360
6439
  if (processedText.length < 3) {
6361
6440
  return trimmedText;
@@ -6418,7 +6497,7 @@ function unwrapResult(text, options) {
6418
6497
  function extractOneBlockFromMarkdown(markdown) {
6419
6498
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
6420
6499
  if (codeBlocks.length !== 1) {
6421
- throw new ParseError(spaceTrim$1((block) => `
6500
+ throw new ParseError(spaceTrim((block) => `
6422
6501
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
6423
6502
 
6424
6503
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -6500,8 +6579,8 @@ class JavascriptEvalExecutionTools {
6500
6579
  }
6501
6580
  // Note: [💎]
6502
6581
  // Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
6503
- const spaceTrim = (_) => spaceTrim$1(_);
6504
- preserve(spaceTrim);
6582
+ const spaceTrim$1 = (_) => spaceTrim(_);
6583
+ preserve(spaceTrim$1);
6505
6584
  const removeQuotes$1 = removeQuotes;
6506
6585
  preserve(removeQuotes$1);
6507
6586
  const unwrapResult$1 = unwrapResult;
@@ -6554,7 +6633,7 @@ class JavascriptEvalExecutionTools {
6554
6633
  // TODO: DRY [🍯]
6555
6634
  const buildinFunctions = {
6556
6635
  // TODO: [🍯] DRY all these functions across the file
6557
- spaceTrim,
6636
+ spaceTrim: spaceTrim$1,
6558
6637
  removeQuotes: removeQuotes$1,
6559
6638
  unwrapResult: unwrapResult$1,
6560
6639
  trimEndOfCodeBlock: trimEndOfCodeBlock$1,
@@ -6591,7 +6670,7 @@ class JavascriptEvalExecutionTools {
6591
6670
  .join('\n');
6592
6671
  // script = templateParameters(script, parameters);
6593
6672
  // <- TODO: [🧠][🥳] Should be this is one of two variants how to use parameters in script
6594
- const statementToEvaluate = spaceTrim$1((block) => `
6673
+ const statementToEvaluate = spaceTrim((block) => `
6595
6674
 
6596
6675
  // Build-in functions:
6597
6676
  ${block(buildinFunctionsStatement)}
@@ -6606,7 +6685,7 @@ class JavascriptEvalExecutionTools {
6606
6685
  (()=>{ ${script} })()
6607
6686
  `);
6608
6687
  if (this.options.isVerbose) {
6609
- console.info(spaceTrim$1((block) => `
6688
+ console.info(spaceTrim((block) => `
6610
6689
  🚀 Evaluating ${scriptLanguage} script:
6611
6690
 
6612
6691
  ${block(statementToEvaluate)}`));
@@ -6619,9 +6698,7 @@ class JavascriptEvalExecutionTools {
6619
6698
  }
6620
6699
  }
6621
6700
  catch (error) {
6622
- if (!(error instanceof Error)) {
6623
- throw error;
6624
- }
6701
+ assertsError(error);
6625
6702
  if (error instanceof ReferenceError) {
6626
6703
  const undefinedName = error.message.split(' ')[0];
6627
6704
  /*
@@ -6630,7 +6707,7 @@ class JavascriptEvalExecutionTools {
6630
6707
  To: [PipelineExecutionError: Parameter `{thing}` is not defined],
6631
6708
  */
6632
6709
  if (!statementToEvaluate.includes(undefinedName + '(')) {
6633
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6710
+ throw new PipelineExecutionError(spaceTrim((block) => `
6634
6711
 
6635
6712
  Parameter \`{${undefinedName}}\` is not defined
6636
6713
 
@@ -6652,7 +6729,7 @@ class JavascriptEvalExecutionTools {
6652
6729
  `));
6653
6730
  }
6654
6731
  else {
6655
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6732
+ throw new PipelineExecutionError(spaceTrim((block) => `
6656
6733
  Function ${undefinedName}() is not defined
6657
6734
 
6658
6735
  - Make sure that the function is one of built-in functions
@@ -6711,11 +6788,12 @@ async function $provideScriptingForNode(options) {
6711
6788
  * @public exported from `@promptbook/remote-server`
6712
6789
  */
6713
6790
  function startRemoteServer(options) {
6714
- const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, } = {
6791
+ const { port, collection, createLlmExecutionTools, createExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
6715
6792
  isAnonymousModeAllowed: false,
6716
6793
  isApplicationModeAllowed: false,
6717
6794
  collection: null,
6718
6795
  createLlmExecutionTools: null,
6796
+ login: null,
6719
6797
  ...options,
6720
6798
  };
6721
6799
  // <- TODO: [🦪] Some helper type to be able to use discriminant union types with destructuring
@@ -6758,6 +6836,7 @@ function startRemoteServer(options) {
6758
6836
  // Note: Application mode
6759
6837
  const { appId, userId, customOptions } = identification;
6760
6838
  llm = await createLlmExecutionTools({
6839
+ isAnonymous: false,
6761
6840
  appId,
6762
6841
  userId,
6763
6842
  customOptions,
@@ -6766,13 +6845,20 @@ function startRemoteServer(options) {
6766
6845
  else {
6767
6846
  throw new PipelineExecutionError(`You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured`);
6768
6847
  }
6769
- const fs = $provideFilesystemForNode();
6770
- const executables = await $provideExecutablesForNode();
6848
+ const customExecutionTools = createExecutionTools ? await createExecutionTools(identification) : {};
6849
+ const fs = customExecutionTools.fs || $provideFilesystemForNode();
6850
+ const executables = customExecutionTools.executables || (await $provideExecutablesForNode());
6851
+ const scrapers = customExecutionTools.scrapers || (await $provideScrapersForNode({ fs, llm, executables }));
6852
+ const script = customExecutionTools.script || (await $provideScriptingForNode({}));
6853
+ const fetch = customExecutionTools.fetch || promptbookFetch;
6854
+ const userInterface = customExecutionTools.userInterface || undefined;
6771
6855
  const tools = {
6772
6856
  llm,
6773
6857
  fs,
6774
- scrapers: await $provideScrapersForNode({ fs, llm, executables }),
6775
- script: await $provideScriptingForNode({}),
6858
+ scrapers,
6859
+ script,
6860
+ fetch,
6861
+ userInterface,
6776
6862
  };
6777
6863
  return tools;
6778
6864
  }
@@ -6782,15 +6868,44 @@ function startRemoteServer(options) {
6782
6868
  response.setHeader('X-Powered-By', 'Promptbook engine');
6783
6869
  next();
6784
6870
  });
6871
+ const swaggerOptions = {
6872
+ definition: {
6873
+ openapi: '3.0.0',
6874
+ info: {
6875
+ title: 'Promptbook Remote Server API',
6876
+ version: '1.0.0',
6877
+ description: 'API documentation for the Promptbook Remote Server',
6878
+ },
6879
+ servers: [
6880
+ {
6881
+ url: `http://localhost:${port}${rootPath}`,
6882
+ // <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
6883
+ },
6884
+ ],
6885
+ },
6886
+ apis: ['./src/remote-server/**/*.ts'], // Adjust path as needed
6887
+ };
6888
+ const swaggerSpec = swaggerJsdoc(swaggerOptions);
6889
+ app.use([`/api-docs`, `${rootPath}/api-docs`], swaggerUi.serve, swaggerUi.setup(swaggerSpec));
6785
6890
  const runningExecutionTasks = [];
6786
6891
  // <- TODO: [🤬] Identify the users
6787
6892
  // TODO: [🧠] Do here some garbage collection of finished tasks
6893
+ /**
6894
+ * @swagger
6895
+ * /:
6896
+ * get:
6897
+ * summary: Get server details
6898
+ * description: Returns details about the Promptbook server.
6899
+ * responses:
6900
+ * 200:
6901
+ * description: Server details in markdown format.
6902
+ */
6788
6903
  app.get(['/', rootPath], async (request, response) => {
6789
6904
  var _a;
6790
6905
  if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
6791
6906
  return;
6792
6907
  }
6793
- response.type('text/markdown').send(await spaceTrim(async (block) => `
6908
+ response.type('text/markdown').send(await spaceTrim$1(async (block) => `
6794
6909
  # Promptbook
6795
6910
 
6796
6911
  > ${block(CLAIM)}
@@ -6821,9 +6936,12 @@ function startRemoteServer(options) {
6821
6936
 
6822
6937
  ## Paths
6823
6938
 
6824
- ${block(app._router.stack
6825
- .map(({ route }) => (route === null || route === void 0 ? void 0 : route.path) || null)
6826
- .filter((path) => path !== null)
6939
+ ${block([
6940
+ ...app._router.stack
6941
+ .map(({ route }) => (route === null || route === void 0 ? void 0 : route.path) || null)
6942
+ .filter((path) => path !== null),
6943
+ '/api-docs',
6944
+ ]
6827
6945
  .map((path) => `- ${path}`)
6828
6946
  .join('\n'))}
6829
6947
 
@@ -6841,8 +6959,94 @@ function startRemoteServer(options) {
6841
6959
  https://github.com/webgptorg/promptbook
6842
6960
  `));
6843
6961
  });
6844
- // TODO: !!!!!! Add login route
6845
- app.get(`${rootPath}/books`, async (request, response) => {
6962
+ /**
6963
+ * @swagger
6964
+ *
6965
+ * /login:
6966
+ * post:
6967
+ * summary: Login to the server
6968
+ * description: Login to the server and get identification.
6969
+ * requestBody:
6970
+ * required: true
6971
+ * content:
6972
+ * application/json:
6973
+ * schema:
6974
+ * type: object
6975
+ * properties:
6976
+ * username:
6977
+ * type: string
6978
+ * password:
6979
+ * type: string
6980
+ * appId:
6981
+ * type: string
6982
+ * responses:
6983
+ * 200:
6984
+ * description: Successful login
6985
+ * content:
6986
+ * application/json:
6987
+ * schema:
6988
+ * type: object
6989
+ * properties:
6990
+ * identification:
6991
+ * type: object
6992
+ */
6993
+ app.post([`/login`, `${rootPath}/login`], async (request, response) => {
6994
+ if (!isApplicationModeAllowed || login === null) {
6995
+ response.status(400).send('Application mode is not allowed');
6996
+ return;
6997
+ }
6998
+ try {
6999
+ const username = request.body.username;
7000
+ const password = request.body.password;
7001
+ const appId = request.body.appId;
7002
+ const { isSuccess, error, message, identification } = await login({
7003
+ username,
7004
+ password,
7005
+ appId,
7006
+ rawRequest: request,
7007
+ rawResponse: response,
7008
+ });
7009
+ response.status(201).send({
7010
+ isSuccess,
7011
+ message,
7012
+ error: error ? serializeError(error) : undefined,
7013
+ identification,
7014
+ });
7015
+ return;
7016
+ }
7017
+ catch (error) {
7018
+ assertsError(error);
7019
+ if (error instanceof AuthenticationError) {
7020
+ response.status(401).send({
7021
+ isSuccess: false,
7022
+ message: error.message,
7023
+ error: serializeError(error),
7024
+ });
7025
+ }
7026
+ console.warn(`Login function thrown different error than AuthenticationError`, {
7027
+ error,
7028
+ serializedError: serializeError(error),
7029
+ });
7030
+ response.status(400).send({ error: serializeError(error) });
7031
+ }
7032
+ });
7033
+ /**
7034
+ * @swagger
7035
+ * /books:
7036
+ * get:
7037
+ * summary: List all books
7038
+ * description: Returns a list of all available books in the collection.
7039
+ * responses:
7040
+ * 200:
7041
+ * description: A list of books.
7042
+ * content:
7043
+ * application/json:
7044
+ * schema:
7045
+ * type: array
7046
+ * items:
7047
+ * type: string
7048
+ */
7049
+ app.get([`/books`, `${rootPath}/books`], async (request, response) => {
6846
7050
  if (collection === null) {
6847
7051
  response.status(500).send('No collection available');
6848
7052
  return;
@@ -6852,7 +7056,30 @@ function startRemoteServer(options) {
6852
7056
  response.send(pipelines);
6853
7057
  });
6854
7058
  // TODO: [🧠] Is it secure / good idea to expose source codes of hosted books
6855
- app.get(`${rootPath}/books/*`, async (request, response) => {
7059
+ /**
7060
+ * @swagger
7061
+ * /books/{bookId}:
7062
+ * get:
7063
+ * summary: Get book content
7064
+ * description: Returns the content of a specific book.
7065
+ * parameters:
7066
+ * - in: path
7067
+ * name: bookId
7068
+ * required: true
7069
+ * schema:
7070
+ * type: string
7071
+ * description: The ID of the book to retrieve.
7072
+ * responses:
7073
+ * 200:
7074
+ * description: The content of the book.
7075
+ * content:
7076
+ * text/markdown:
7077
+ * schema:
7078
+ * type: string
7079
+ * 404:
7080
+ * description: Book not found.
7081
+ */
7082
+ app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
6856
7083
  try {
6857
7084
  if (collection === null) {
6858
7085
  response.status(500).send('No collection nor books available');
@@ -6871,9 +7098,7 @@ function startRemoteServer(options) {
6871
7098
  .send(source.content);
6872
7099
  }
6873
7100
  catch (error) {
6874
- if (!(error instanceof Error)) {
6875
- throw error;
6876
- }
7101
+ assertsError(error);
6877
7102
  response
6878
7103
  .status(404)
6879
7104
  .send({ error: serializeError(error) });
@@ -6906,10 +7131,26 @@ function startRemoteServer(options) {
6906
7131
  };
6907
7132
  }
6908
7133
  }
6909
- app.get(`${rootPath}/executions`, async (request, response) => {
7134
+ /**
7135
+ * @swagger
7136
+ * /executions:
7137
+ * get:
7138
+ * summary: List all executions
7139
+ * description: Returns a list of all running execution tasks.
7140
+ * responses:
7141
+ * 200:
7142
+ * description: A list of execution tasks.
7143
+ * content:
7144
+ * application/json:
7145
+ * schema:
7146
+ * type: array
7147
+ * items:
7148
+ * type: object
7149
+ */
7150
+ app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
6910
7151
  response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
6911
7152
  });
6912
- app.get(`${rootPath}/executions/last`, async (request, response) => {
7153
+ app.get([`/executions/last`, `${rootPath}/executions/last`], async (request, response) => {
6913
7154
  // TODO: [🤬] Filter only for user
6914
7155
  if (runningExecutionTasks.length === 0) {
6915
7156
  response.status(404).send('No execution tasks found');
@@ -6918,7 +7159,7 @@ function startRemoteServer(options) {
6918
7159
  const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
6919
7160
  response.send(exportExecutionTask(lastExecutionTask, true));
6920
7161
  });
6921
- app.get(`${rootPath}/executions/:taskId`, async (request, response) => {
7162
+ app.get([`/executions/:taskId`, `${rootPath}/executions/:taskId`], async (request, response) => {
6922
7163
  const { taskId } = request.params;
6923
7164
  // TODO: [🤬] Filter only for user
6924
7165
  const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
@@ -6930,7 +7171,36 @@ function startRemoteServer(options) {
6930
7171
  }
6931
7172
  response.send(exportExecutionTask(executionTask, true));
6932
7173
  });
6933
- app.post(`${rootPath}/executions/new`, async (request, response) => {
7174
+ /**
7175
+ * @swagger
7176
+ * /executions/new:
7177
+ * post:
7178
+ * summary: Start a new execution
7179
+ * description: Starts a new execution task for a given pipeline.
7180
+ * requestBody:
7181
+ * required: true
7182
+ * content:
7183
+ * application/json:
7184
+ * schema:
7185
+ * type: object
7186
+ * properties:
7187
+ * pipelineUrl:
7188
+ * type: string
7189
+ * inputParameters:
7190
+ * type: object
7191
+ * identification:
7192
+ * type: object
7193
+ * responses:
7194
+ * 200:
7195
+ * description: The newly created execution task.
7196
+ * content:
7197
+ * application/json:
7198
+ * schema:
7199
+ * type: object
7200
+ * 400:
7201
+ * description: Invalid input.
7202
+ */
7203
+ app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
6934
7204
  try {
6935
7205
  const { inputParameters, identification /* <- [🤬] */ } = request.body;
6936
7206
  const pipelineUrl = request.body.pipelineUrl || request.body.book;
@@ -6967,12 +7237,16 @@ function startRemoteServer(options) {
6967
7237
  */
6968
7238
  }
6969
7239
  catch (error) {
6970
- if (!(error instanceof Error)) {
6971
- throw error;
6972
- }
7240
+ assertsError(error);
6973
7241
  response.status(400).send({ error: serializeError(error) });
6974
7242
  }
6975
7243
  });
7244
+ /**
7245
+ * Catch-all handler for unmatched routes
7246
+ */
7247
+ app.use((request, response) => {
7248
+ response.status(404).send(`URL "${request.originalUrl}" was not found on Promptbook server.`);
7249
+ });
6976
7250
  const httpServer = http.createServer(app);
6977
7251
  const server = new Server(httpServer, {
6978
7252
  path: socketioPath,
@@ -7033,9 +7307,7 @@ function startRemoteServer(options) {
7033
7307
  socket.emit('prompt-response', { promptResult } /* <- Note: [🤛] */);
7034
7308
  }
7035
7309
  catch (error) {
7036
- if (!(error instanceof Error)) {
7037
- throw error;
7038
- }
7310
+ assertsError(error);
7039
7311
  socket.emit('error', serializeError(error) /* <- Note: [🤛] */);
7040
7312
  }
7041
7313
  finally {
@@ -7057,9 +7329,7 @@ function startRemoteServer(options) {
7057
7329
  socket.emit('listModels-response', { models } /* <- Note: [🤛] */);
7058
7330
  }
7059
7331
  catch (error) {
7060
- if (!(error instanceof Error)) {
7061
- throw error;
7062
- }
7332
+ assertsError(error);
7063
7333
  socket.emit('error', serializeError(error));
7064
7334
  }
7065
7335
  finally {
@@ -7080,9 +7350,7 @@ function startRemoteServer(options) {
7080
7350
  socket.emit('preparePipeline-response', { preparedPipeline } /* <- Note: [🤛] */);
7081
7351
  }
7082
7352
  catch (error) {
7083
- if (!(error instanceof Error)) {
7084
- throw error;
7085
- }
7353
+ assertsError(error);
7086
7354
  socket.emit('error', serializeError(error));
7087
7355
  // <- TODO: [🚋] There is a problem with the remote server handling errors and sending them back to the client
7088
7356
  }
@@ -7107,6 +7375,15 @@ function startRemoteServer(options) {
7107
7375
  }
7108
7376
  let isDestroyed = false;
7109
7377
  return {
7378
+ get httpServer() {
7379
+ return httpServer;
7380
+ },
7381
+ get expressApp() {
7382
+ return app;
7383
+ },
7384
+ get socketIoServer() {
7385
+ return server;
7386
+ },
7110
7387
  get isDestroyed() {
7111
7388
  return isDestroyed;
7112
7389
  },
@@ -7122,7 +7399,6 @@ function startRemoteServer(options) {
7122
7399
  }
7123
7400
  /**
7124
7401
  * TODO: !! Add CORS and security - probbably via `helmet`
7125
- * TODO: [👩🏾‍🤝‍🧑🏾] Allow to pass custom fetch function here - PromptbookFetch
7126
7402
  * TODO: Split this file into multiple functions - handler for each request
7127
7403
  * TODO: Maybe use `$exportJson`
7128
7404
  * TODO: [🧠][🛍] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`