@promptbook/remote-server 0.89.0-9 โ†’ 0.92.0-3

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 (41) hide show
  1. package/README.md +9 -7
  2. package/esm/index.es.js +555 -426
  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 +10 -4
  6. package/esm/typings/src/_packages/types.index.d.ts +18 -0
  7. package/esm/typings/src/_packages/utils.index.d.ts +4 -0
  8. package/esm/typings/src/cli/cli-commands/login.d.ts +0 -1
  9. package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +16 -3
  10. package/esm/typings/src/cli/test/ptbk.d.ts +1 -1
  11. package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +2 -0
  12. package/esm/typings/src/config.d.ts +10 -19
  13. package/esm/typings/src/errors/0-index.d.ts +7 -4
  14. package/esm/typings/src/errors/PipelineExecutionError.d.ts +1 -1
  15. package/esm/typings/src/errors/WrappedError.d.ts +10 -0
  16. package/esm/typings/src/errors/assertsError.d.ts +11 -0
  17. package/esm/typings/src/execution/PromptbookFetch.d.ts +1 -1
  18. package/esm/typings/src/formats/csv/utils/isValidCsvString.d.ts +9 -0
  19. package/esm/typings/src/formats/csv/utils/isValidCsvString.test.d.ts +1 -0
  20. package/esm/typings/src/formats/json/utils/isValidJsonString.d.ts +3 -0
  21. package/esm/typings/src/formats/xml/utils/isValidXmlString.d.ts +9 -0
  22. package/esm/typings/src/formats/xml/utils/isValidXmlString.test.d.ts +1 -0
  23. package/esm/typings/src/llm-providers/_common/filterModels.d.ts +15 -0
  24. package/esm/typings/src/llm-providers/_common/register/{$provideEnvFilepath.d.ts โ†’ $provideEnvFilename.d.ts} +2 -2
  25. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
  26. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
  27. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizzardOrCli.d.ts +11 -2
  28. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsFromEnv.d.ts +1 -1
  29. package/esm/typings/src/remote-server/openapi-types.d.ts +284 -0
  30. package/esm/typings/src/remote-server/openapi.d.ts +187 -0
  31. package/esm/typings/src/remote-server/socket-types/_subtypes/Identification.d.ts +7 -1
  32. package/esm/typings/src/remote-server/socket-types/_subtypes/identificationToPromptbookToken.d.ts +11 -0
  33. package/esm/typings/src/remote-server/socket-types/_subtypes/promptbookTokenToIdentification.d.ts +10 -0
  34. package/esm/typings/src/remote-server/startRemoteServer.d.ts +1 -2
  35. package/esm/typings/src/remote-server/types/RemoteServerOptions.d.ts +15 -9
  36. package/esm/typings/src/storage/env-storage/$EnvStorage.d.ts +40 -0
  37. package/esm/typings/src/types/typeAliases.d.ts +26 -0
  38. package/package.json +11 -7
  39. package/umd/index.umd.js +476 -329
  40. package/umd/index.umd.js.map +1 -1
  41. package/esm/typings/src/cli/test/ptbk2.d.ts +0 -5
package/esm/index.es.js CHANGED
@@ -2,8 +2,8 @@ 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';
6
- import swaggerJsdoc from 'swagger-jsdoc';
5
+ import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
6
+ import * as OpenApiValidator from 'express-openapi-validator';
7
7
  import swaggerUi from 'swagger-ui-express';
8
8
  import { forTime } from 'waitasecond';
9
9
  import { randomBytes } from 'crypto';
@@ -33,7 +33,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
33
33
  * @generated
34
34
  * @see https://github.com/webgptorg/promptbook
35
35
  */
36
- const PROMPTBOOK_ENGINE_VERSION = '0.89.0-9';
36
+ const PROMPTBOOK_ENGINE_VERSION = '0.92.0-3';
37
37
  /**
38
38
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
39
39
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -87,6 +87,7 @@ const ADMIN_GITHUB_NAME = 'hejny';
87
87
  * @public exported from `@promptbook/core`
88
88
  */
89
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
90
91
  /**
91
92
  * When the title is not provided, the default title is used
92
93
  *
@@ -119,6 +120,7 @@ const VALUE_STRINGS = {
119
120
  infinity: '(infinity; โˆž)',
120
121
  negativeInfinity: '(negative infinity; -โˆž)',
121
122
  unserializable: '(unserializable value)',
123
+ circular: '(circular JSON)',
122
124
  };
123
125
  /**
124
126
  * Small number limit
@@ -158,7 +160,7 @@ const DEFAULT_MAX_PARALLEL_COUNT = 5; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
158
160
  */
159
161
  const DEFAULT_MAX_EXECUTION_ATTEMPTS = 10; // <- TODO: [๐Ÿคนโ€โ™‚๏ธ]
160
162
  // <- TODO: [๐Ÿ•] Make also `BOOKS_DIRNAME_ALTERNATIVES`
161
- // TODO: !!!!!! Just .promptbook dir, hardocode others
163
+ // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
162
164
  /**
163
165
  * Where to store the temporary downloads
164
166
  *
@@ -213,6 +215,122 @@ true);
213
215
  * TODO: [๐Ÿง ][๐Ÿงœโ€โ™‚๏ธ] Maybe join remoteServerUrl and path into single value
214
216
  */
215
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
+
216
334
  /**
217
335
  * AuthenticationError is thrown from login function which is dependency of remote server
218
336
  *
@@ -257,7 +375,7 @@ class PipelineExecutionError extends Error {
257
375
  }
258
376
  }
259
377
  /**
260
- * TODO: !!!!!! Add id to all errors
378
+ * TODO: [๐Ÿง ][๐ŸŒ‚] Add id to all errors
261
379
  */
262
380
 
263
381
  /**
@@ -365,7 +483,7 @@ class LimitReachedError extends Error {
365
483
  */
366
484
  class MissingToolsError extends Error {
367
485
  constructor(message) {
368
- super(spaceTrim((block) => `
486
+ super(spaceTrim$1((block) => `
369
487
  ${block(message)}
370
488
 
371
489
  Note: You have probbably forgot to provide some tools for pipeline execution or preparation
@@ -396,7 +514,7 @@ class NotFoundError extends Error {
396
514
  */
397
515
  class NotYetImplementedError extends Error {
398
516
  constructor(message) {
399
- super(spaceTrim((block) => `
517
+ super(spaceTrim$1((block) => `
400
518
  ${block(message)}
401
519
 
402
520
  Note: This feature is not implemented yet but it will be soon.
@@ -467,74 +585,6 @@ class PromptbookFetchError extends Error {
467
585
  }
468
586
  }
469
587
 
470
- /**
471
- * Make error report URL for the given error
472
- *
473
- * @private private within the repository
474
- */
475
- function getErrorReportUrl(error) {
476
- const report = {
477
- title: `๐Ÿœ Error report from ${NAME}`,
478
- body: spaceTrim$1((block) => `
479
-
480
-
481
- \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
482
-
483
- \`\`\`
484
- ${block(error.message || '(no error message)')}
485
- \`\`\`
486
-
487
-
488
- ## More info:
489
-
490
- - **Promptbook engine version:** ${PROMPTBOOK_ENGINE_VERSION}
491
- - **Book language version:** ${BOOK_LANGUAGE_VERSION}
492
- - **Time:** ${new Date().toISOString()}
493
-
494
- <details>
495
- <summary>Stack trace:</summary>
496
-
497
- ## Stack trace:
498
-
499
- \`\`\`stacktrace
500
- ${block(error.stack || '(empty)')}
501
- \`\`\`
502
- </details>
503
-
504
- `),
505
- };
506
- const reportUrl = new URL(`https://github.com/webgptorg/promptbook/issues/new`);
507
- reportUrl.searchParams.set('labels', 'bug');
508
- reportUrl.searchParams.set('assignees', ADMIN_GITHUB_NAME);
509
- reportUrl.searchParams.set('title', report.title);
510
- reportUrl.searchParams.set('body', report.body);
511
- return reportUrl;
512
- }
513
-
514
- /**
515
- * This error type indicates that the error should not happen and its last check before crashing with some other error
516
- *
517
- * @public exported from `@promptbook/core`
518
- */
519
- class UnexpectedError extends Error {
520
- constructor(message) {
521
- super(spaceTrim((block) => `
522
- ${block(message)}
523
-
524
- Note: This error should not happen.
525
- It's probbably a bug in the pipeline collection
526
-
527
- Please report issue:
528
- ${block(getErrorReportUrl(new Error(message)).href)}
529
-
530
- Or contact us on ${ADMIN_EMAIL}
531
-
532
- `));
533
- this.name = 'UnexpectedError';
534
- Object.setPrototypeOf(this, UnexpectedError.prototype);
535
- }
536
- }
537
-
538
588
  /**
539
589
  * Index of all custom errors
540
590
  *
@@ -555,7 +605,10 @@ const PROMPTBOOK_ERRORS = {
555
605
  PipelineExecutionError,
556
606
  PipelineLogicError,
557
607
  PipelineUrlError,
608
+ AuthenticationError,
609
+ PromptbookFetchError,
558
610
  UnexpectedError,
611
+ WrappedError,
559
612
  // TODO: [๐Ÿช‘]> VersionMismatchError,
560
613
  };
561
614
  /**
@@ -572,8 +625,6 @@ const COMMON_JAVASCRIPT_ERRORS = {
572
625
  TypeError,
573
626
  URIError,
574
627
  AggregateError,
575
- AuthenticationError,
576
- PromptbookFetchError,
577
628
  /*
578
629
  Note: Not widely supported
579
630
  > InternalError,
@@ -605,7 +656,7 @@ function serializeError(error) {
605
656
  const { name, message, stack } = error;
606
657
  const { id } = error;
607
658
  if (!Object.keys(ALL_ERRORS).includes(name)) {
608
- console.error(spaceTrim$1((block) => `
659
+ console.error(spaceTrim((block) => `
609
660
 
610
661
  Cannot serialize error with name "${name}"
611
662
 
@@ -769,11 +820,11 @@ function $execCommand(options) {
769
820
  console.warn(`Command "${humanReadableCommand}" exited with code ${code}`);
770
821
  // <- TODO: [๐Ÿฎ] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
771
822
  }
772
- resolve(spaceTrim(output.join('\n')));
823
+ resolve(spaceTrim$1(output.join('\n')));
773
824
  }
774
825
  }
775
826
  else {
776
- resolve(spaceTrim(output.join('\n')));
827
+ resolve(spaceTrim$1(output.join('\n')));
777
828
  }
778
829
  };
779
830
  commandProcess.on('close', finishWithCode);
@@ -791,7 +842,7 @@ function $execCommand(options) {
791
842
  console.warn(error);
792
843
  // <- TODO: [๐Ÿฎ] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
793
844
  }
794
- resolve(spaceTrim(output.join('\n')));
845
+ resolve(spaceTrim$1(output.join('\n')));
795
846
  }
796
847
  });
797
848
  }
@@ -816,9 +867,7 @@ async function locateAppOnLinux({ linuxWhich, }) {
816
867
  return result.trim();
817
868
  }
818
869
  catch (error) {
819
- if (!(error instanceof Error)) {
820
- throw error;
821
- }
870
+ assertsError(error);
822
871
  return null;
823
872
  }
824
873
  }
@@ -896,9 +945,7 @@ async function locateAppOnMacOs({ macOsName, }) {
896
945
  return result.trim() + toExec;
897
946
  }
898
947
  catch (error) {
899
- if (!(error instanceof Error)) {
900
- throw error;
901
- }
948
+ assertsError(error);
902
949
  return null;
903
950
  }
904
951
  }
@@ -929,9 +976,7 @@ async function locateAppOnWindows({ appName, windowsSuffix, }) {
929
976
  throw new Error(`Can not locate app ${appName} on Windows.`);
930
977
  }
931
978
  catch (error) {
932
- if (!(error instanceof Error)) {
933
- throw error;
934
- }
979
+ assertsError(error);
935
980
  return null;
936
981
  }
937
982
  }
@@ -1128,7 +1173,7 @@ function checkSerializableAsJson(options) {
1128
1173
  }
1129
1174
  else if (typeof value === 'object') {
1130
1175
  if (value instanceof Date) {
1131
- throw new UnexpectedError(spaceTrim$1((block) => `
1176
+ throw new UnexpectedError(spaceTrim((block) => `
1132
1177
  \`${name}\` is Date
1133
1178
 
1134
1179
  Use \`string_date_iso8601\` instead
@@ -1147,7 +1192,7 @@ function checkSerializableAsJson(options) {
1147
1192
  throw new UnexpectedError(`${name} is RegExp`);
1148
1193
  }
1149
1194
  else if (value instanceof Error) {
1150
- throw new UnexpectedError(spaceTrim$1((block) => `
1195
+ throw new UnexpectedError(spaceTrim((block) => `
1151
1196
  \`${name}\` is unserialized Error
1152
1197
 
1153
1198
  Use function \`serializeError\`
@@ -1169,10 +1214,8 @@ function checkSerializableAsJson(options) {
1169
1214
  JSON.stringify(value); // <- TODO: [0]
1170
1215
  }
1171
1216
  catch (error) {
1172
- if (!(error instanceof Error)) {
1173
- throw error;
1174
- }
1175
- throw new UnexpectedError(spaceTrim$1((block) => `
1217
+ assertsError(error);
1218
+ throw new UnexpectedError(spaceTrim((block) => `
1176
1219
  \`${name}\` is not serializable
1177
1220
 
1178
1221
  ${block(error.stack || error.message)}
@@ -1204,7 +1247,7 @@ function checkSerializableAsJson(options) {
1204
1247
  }
1205
1248
  }
1206
1249
  else {
1207
- throw new UnexpectedError(spaceTrim$1((block) => `
1250
+ throw new UnexpectedError(spaceTrim((block) => `
1208
1251
  \`${name}\` is unknown type
1209
1252
 
1210
1253
  Additional message for \`${name}\`:
@@ -1467,7 +1510,7 @@ function validatePipeline(pipeline) {
1467
1510
  if (!(error instanceof PipelineLogicError)) {
1468
1511
  throw error;
1469
1512
  }
1470
- console.error(spaceTrim((block) => `
1513
+ console.error(spaceTrim$1((block) => `
1471
1514
  Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
1472
1515
 
1473
1516
  ${block(error.message)}
@@ -1494,7 +1537,7 @@ function validatePipeline_InnerFunction(pipeline) {
1494
1537
  })();
1495
1538
  if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1496
1539
  // <- Note: [๐Ÿšฒ]
1497
- throw new PipelineLogicError(spaceTrim((block) => `
1540
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1498
1541
  Invalid promptbook URL "${pipeline.pipelineUrl}"
1499
1542
 
1500
1543
  ${block(pipelineIdentification)}
@@ -1502,7 +1545,7 @@ function validatePipeline_InnerFunction(pipeline) {
1502
1545
  }
1503
1546
  if (pipeline.bookVersion !== undefined && !isValidPromptbookVersion(pipeline.bookVersion)) {
1504
1547
  // <- Note: [๐Ÿšฒ]
1505
- throw new PipelineLogicError(spaceTrim((block) => `
1548
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1506
1549
  Invalid Promptbook Version "${pipeline.bookVersion}"
1507
1550
 
1508
1551
  ${block(pipelineIdentification)}
@@ -1511,7 +1554,7 @@ function validatePipeline_InnerFunction(pipeline) {
1511
1554
  // TODO: [๐Ÿง ] Maybe do here some propper JSON-schema / ZOD checking
1512
1555
  if (!Array.isArray(pipeline.parameters)) {
1513
1556
  // TODO: [๐Ÿง ] what is the correct error tp throw - maybe PromptbookSchemaError
1514
- throw new ParseError(spaceTrim((block) => `
1557
+ throw new ParseError(spaceTrim$1((block) => `
1515
1558
  Pipeline is valid JSON but with wrong structure
1516
1559
 
1517
1560
  \`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
@@ -1522,7 +1565,7 @@ function validatePipeline_InnerFunction(pipeline) {
1522
1565
  // TODO: [๐Ÿง ] Maybe do here some propper JSON-schema / ZOD checking
1523
1566
  if (!Array.isArray(pipeline.tasks)) {
1524
1567
  // TODO: [๐Ÿง ] what is the correct error tp throw - maybe PromptbookSchemaError
1525
- throw new ParseError(spaceTrim((block) => `
1568
+ throw new ParseError(spaceTrim$1((block) => `
1526
1569
  Pipeline is valid JSON but with wrong structure
1527
1570
 
1528
1571
  \`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
@@ -1548,7 +1591,7 @@ function validatePipeline_InnerFunction(pipeline) {
1548
1591
  // Note: Check each parameter individually
1549
1592
  for (const parameter of pipeline.parameters) {
1550
1593
  if (parameter.isInput && parameter.isOutput) {
1551
- throw new PipelineLogicError(spaceTrim((block) => `
1594
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1552
1595
 
1553
1596
  Parameter \`{${parameter.name}}\` can not be both input and output
1554
1597
 
@@ -1559,7 +1602,7 @@ function validatePipeline_InnerFunction(pipeline) {
1559
1602
  if (!parameter.isInput &&
1560
1603
  !parameter.isOutput &&
1561
1604
  !pipeline.tasks.some((task) => task.dependentParameterNames.includes(parameter.name))) {
1562
- throw new PipelineLogicError(spaceTrim((block) => `
1605
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1563
1606
  Parameter \`{${parameter.name}}\` is created but not used
1564
1607
 
1565
1608
  You can declare {${parameter.name}} as output parameter by adding in the header:
@@ -1571,7 +1614,7 @@ function validatePipeline_InnerFunction(pipeline) {
1571
1614
  }
1572
1615
  // Note: Testing that parameter is either input or result of some task
1573
1616
  if (!parameter.isInput && !pipeline.tasks.some((task) => task.resultingParameterName === parameter.name)) {
1574
- throw new PipelineLogicError(spaceTrim((block) => `
1617
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1575
1618
  Parameter \`{${parameter.name}}\` is declared but not defined
1576
1619
 
1577
1620
  You can do one of these:
@@ -1587,14 +1630,14 @@ function validatePipeline_InnerFunction(pipeline) {
1587
1630
  // Note: Checking each task individually
1588
1631
  for (const task of pipeline.tasks) {
1589
1632
  if (definedParameters.has(task.resultingParameterName)) {
1590
- throw new PipelineLogicError(spaceTrim((block) => `
1633
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1591
1634
  Parameter \`{${task.resultingParameterName}}\` is defined multiple times
1592
1635
 
1593
1636
  ${block(pipelineIdentification)}
1594
1637
  `));
1595
1638
  }
1596
1639
  if (RESERVED_PARAMETER_NAMES.includes(task.resultingParameterName)) {
1597
- throw new PipelineLogicError(spaceTrim((block) => `
1640
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1598
1641
  Parameter name {${task.resultingParameterName}} is reserved, please use different name
1599
1642
 
1600
1643
  ${block(pipelineIdentification)}
@@ -1604,7 +1647,7 @@ function validatePipeline_InnerFunction(pipeline) {
1604
1647
  if (task.jokerParameterNames && task.jokerParameterNames.length > 0) {
1605
1648
  if (!task.format &&
1606
1649
  !task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1607
- throw new PipelineLogicError(spaceTrim((block) => `
1650
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1608
1651
  Joker parameters are used for {${task.resultingParameterName}} but no expectations are defined
1609
1652
 
1610
1653
  ${block(pipelineIdentification)}
@@ -1612,7 +1655,7 @@ function validatePipeline_InnerFunction(pipeline) {
1612
1655
  }
1613
1656
  for (const joker of task.jokerParameterNames) {
1614
1657
  if (!task.dependentParameterNames.includes(joker)) {
1615
- throw new PipelineLogicError(spaceTrim((block) => `
1658
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1616
1659
  Parameter \`{${joker}}\` is used for {${task.resultingParameterName}} as joker but not in \`dependentParameterNames\`
1617
1660
 
1618
1661
  ${block(pipelineIdentification)}
@@ -1623,21 +1666,21 @@ function validatePipeline_InnerFunction(pipeline) {
1623
1666
  if (task.expectations) {
1624
1667
  for (const [unit, { min, max }] of Object.entries(task.expectations)) {
1625
1668
  if (min !== undefined && max !== undefined && min > max) {
1626
- throw new PipelineLogicError(spaceTrim((block) => `
1669
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1627
1670
  Min expectation (=${min}) of ${unit} is higher than max expectation (=${max})
1628
1671
 
1629
1672
  ${block(pipelineIdentification)}
1630
1673
  `));
1631
1674
  }
1632
1675
  if (min !== undefined && min < 0) {
1633
- throw new PipelineLogicError(spaceTrim((block) => `
1676
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1634
1677
  Min expectation of ${unit} must be zero or positive
1635
1678
 
1636
1679
  ${block(pipelineIdentification)}
1637
1680
  `));
1638
1681
  }
1639
1682
  if (max !== undefined && max <= 0) {
1640
- throw new PipelineLogicError(spaceTrim((block) => `
1683
+ throw new PipelineLogicError(spaceTrim$1((block) => `
1641
1684
  Max expectation of ${unit} must be positive
1642
1685
 
1643
1686
  ${block(pipelineIdentification)}
@@ -1659,7 +1702,7 @@ function validatePipeline_InnerFunction(pipeline) {
1659
1702
  while (unresovedTasks.length > 0) {
1660
1703
  if (loopLimit-- < 0) {
1661
1704
  // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1662
- throw new UnexpectedError(spaceTrim((block) => `
1705
+ throw new UnexpectedError(spaceTrim$1((block) => `
1663
1706
  Loop limit reached during detection of circular dependencies in \`validatePipeline\`
1664
1707
 
1665
1708
  ${block(pipelineIdentification)}
@@ -1669,7 +1712,7 @@ function validatePipeline_InnerFunction(pipeline) {
1669
1712
  if (currentlyResovedTasks.length === 0) {
1670
1713
  throw new PipelineLogicError(
1671
1714
  // TODO: [๐ŸŽ] DRY
1672
- spaceTrim((block) => `
1715
+ spaceTrim$1((block) => `
1673
1716
 
1674
1717
  Can not resolve some parameters:
1675
1718
  Either you are using a parameter that is not defined, or there are some circular dependencies.
@@ -1771,6 +1814,9 @@ function isPipelinePrepared(pipeline) {
1771
1814
  /**
1772
1815
  * Function isValidJsonString will tell you if the string is valid JSON or not
1773
1816
  *
1817
+ * @param value The string to check
1818
+ * @returns True if the string is a valid JSON string, false otherwise
1819
+ *
1774
1820
  * @public exported from `@promptbook/utils`
1775
1821
  */
1776
1822
  function isValidJsonString(value /* <- [๐Ÿ‘จโ€โš–๏ธ] */) {
@@ -1779,9 +1825,7 @@ function isValidJsonString(value /* <- [๐Ÿ‘จโ€โš–๏ธ] */) {
1779
1825
  return true;
1780
1826
  }
1781
1827
  catch (error) {
1782
- if (!(error instanceof Error)) {
1783
- throw error;
1784
- }
1828
+ assertsError(error);
1785
1829
  if (error.message.includes('Unexpected token')) {
1786
1830
  return false;
1787
1831
  }
@@ -1833,7 +1877,7 @@ function deserializeError(error) {
1833
1877
  message = `${name}: ${message}`;
1834
1878
  }
1835
1879
  if (stack !== undefined && stack !== '') {
1836
- message = spaceTrim$1((block) => `
1880
+ message = spaceTrim((block) => `
1837
1881
  ${block(message)}
1838
1882
 
1839
1883
  Original stack trace:
@@ -1870,11 +1914,11 @@ function assertsTaskSuccessful(executionResult) {
1870
1914
  throw deserializeError(errors[0]);
1871
1915
  }
1872
1916
  else {
1873
- throw new PipelineExecutionError(spaceTrim((block) => `
1917
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
1874
1918
  Multiple errors occurred during Promptbook execution
1875
1919
 
1876
1920
  ${block(errors
1877
- .map(({ name, stack, message }, index) => spaceTrim((block) => `
1921
+ .map(({ name, stack, message }, index) => spaceTrim$1((block) => `
1878
1922
  ${name} ${index + 1}:
1879
1923
  ${block(stack || message)}
1880
1924
  `))
@@ -1919,8 +1963,8 @@ function createTask(options) {
1919
1963
  updatedAt = new Date();
1920
1964
  errors.push(...executionResult.errors);
1921
1965
  warnings.push(...executionResult.warnings);
1922
- // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
1923
- // TODO: [๐Ÿง ] !!! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
1966
+ // <- TODO: [๐ŸŒ‚] Only unique errors and warnings should be added (or filtered)
1967
+ // TODO: [๐Ÿง ] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
1924
1968
  // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
1925
1969
  // And delete `ExecutionTask.currentValue.preparedPipeline`
1926
1970
  assertsTaskSuccessful(executionResult);
@@ -1930,6 +1974,7 @@ function createTask(options) {
1930
1974
  partialResultSubject.next(executionResult);
1931
1975
  }
1932
1976
  catch (error) {
1977
+ assertsError(error);
1933
1978
  status = 'ERROR';
1934
1979
  errors.push(error);
1935
1980
  partialResultSubject.error(error);
@@ -2232,7 +2277,7 @@ function pipelineJsonToString(pipelineJson) {
2232
2277
  pipelineString += '\n\n';
2233
2278
  pipelineString += '```' + contentLanguage;
2234
2279
  pipelineString += '\n';
2235
- pipelineString += spaceTrim$1(content);
2280
+ pipelineString += spaceTrim(content);
2236
2281
  // <- TODO: [main] !!3 Escape
2237
2282
  // <- TODO: [๐Ÿง ] Some clear strategy how to spaceTrim the blocks
2238
2283
  pipelineString += '\n';
@@ -2337,7 +2382,7 @@ class SimplePipelineCollection {
2337
2382
  for (const pipeline of pipelines) {
2338
2383
  // TODO: [๐Ÿ‘ ] DRY
2339
2384
  if (pipeline.pipelineUrl === undefined) {
2340
- throw new PipelineUrlError(spaceTrim(`
2385
+ throw new PipelineUrlError(spaceTrim$1(`
2341
2386
  Pipeline with name "${pipeline.title}" does not have defined URL
2342
2387
 
2343
2388
  File:
@@ -2359,7 +2404,7 @@ class SimplePipelineCollection {
2359
2404
  pipelineJsonToString(unpreparePipeline(pipeline)) !==
2360
2405
  pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
2361
2406
  const existing = this.collection.get(pipeline.pipelineUrl);
2362
- throw new PipelineUrlError(spaceTrim(`
2407
+ throw new PipelineUrlError(spaceTrim$1(`
2363
2408
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection ๐ŸŽ
2364
2409
 
2365
2410
  Conflicting files:
@@ -2391,13 +2436,13 @@ class SimplePipelineCollection {
2391
2436
  const pipeline = this.collection.get(url);
2392
2437
  if (!pipeline) {
2393
2438
  if (this.listPipelines().length === 0) {
2394
- throw new NotFoundError(spaceTrim(`
2439
+ throw new NotFoundError(spaceTrim$1(`
2395
2440
  Pipeline with url "${url}" not found
2396
2441
 
2397
2442
  No pipelines available
2398
2443
  `));
2399
2444
  }
2400
- throw new NotFoundError(spaceTrim((block) => `
2445
+ throw new NotFoundError(spaceTrim$1((block) => `
2401
2446
  Pipeline with url "${url}" not found
2402
2447
 
2403
2448
  Available pipelines:
@@ -2740,14 +2785,15 @@ class MultipleLlmExecutionTools {
2740
2785
  }
2741
2786
  }
2742
2787
  catch (error) {
2743
- if (!(error instanceof Error) || error instanceof UnexpectedError) {
2788
+ assertsError(error);
2789
+ if (error instanceof UnexpectedError) {
2744
2790
  throw error;
2745
2791
  }
2746
2792
  errors.push({ llmExecutionTools, error });
2747
2793
  }
2748
2794
  }
2749
2795
  if (errors.length === 1) {
2750
- throw errors[0];
2796
+ throw errors[0].error;
2751
2797
  }
2752
2798
  else if (errors.length > 1) {
2753
2799
  throw new PipelineExecutionError(
@@ -2755,7 +2801,7 @@ class MultipleLlmExecutionTools {
2755
2801
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
2756
2802
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
2757
2803
  // 3) ...
2758
- spaceTrim$1((block) => `
2804
+ spaceTrim((block) => `
2759
2805
  All execution tools failed:
2760
2806
 
2761
2807
  ${block(errors
@@ -2768,7 +2814,7 @@ class MultipleLlmExecutionTools {
2768
2814
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\``);
2769
2815
  }
2770
2816
  else {
2771
- throw new PipelineExecutionError(spaceTrim$1((block) => `
2817
+ throw new PipelineExecutionError(spaceTrim((block) => `
2772
2818
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}"
2773
2819
 
2774
2820
  Available \`LlmExecutionTools\`:
@@ -2801,7 +2847,7 @@ class MultipleLlmExecutionTools {
2801
2847
  */
2802
2848
  function joinLlmExecutionTools(...llmExecutionTools) {
2803
2849
  if (llmExecutionTools.length === 0) {
2804
- const warningMessage = spaceTrim$1(`
2850
+ const warningMessage = spaceTrim(`
2805
2851
  You have not provided any \`LlmExecutionTools\`
2806
2852
  This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.
2807
2853
 
@@ -3092,14 +3138,14 @@ function $registeredScrapersMessage(availableScrapers) {
3092
3138
  return { ...metadata, isMetadataAviailable, isInstalled, isAvilableInTools };
3093
3139
  });
3094
3140
  if (metadata.length === 0) {
3095
- return spaceTrim$1(`
3141
+ return spaceTrim(`
3096
3142
  **No scrapers are available**
3097
3143
 
3098
3144
  This is a unexpected behavior, you are probably using some broken version of Promptbook
3099
3145
  At least there should be available the metadata of the scrapers
3100
3146
  `);
3101
3147
  }
3102
- return spaceTrim$1((block) => `
3148
+ return spaceTrim((block) => `
3103
3149
  Available scrapers are:
3104
3150
  ${block(metadata
3105
3151
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvilableInBrowser, isAvilableInTools, }, i) => {
@@ -3588,9 +3634,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
3588
3634
  return await fetch(urlOrRequest, init);
3589
3635
  }
3590
3636
  catch (error) {
3591
- if (!(error instanceof Error)) {
3592
- throw error;
3593
- }
3637
+ assertsError(error);
3594
3638
  let url;
3595
3639
  if (typeof urlOrRequest === 'string') {
3596
3640
  url = urlOrRequest;
@@ -3598,7 +3642,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
3598
3642
  else if (urlOrRequest instanceof Request) {
3599
3643
  url = urlOrRequest.url;
3600
3644
  }
3601
- throw new PromptbookFetchError(spaceTrim$1((block) => `
3645
+ throw new PromptbookFetchError(spaceTrim((block) => `
3602
3646
  Can not fetch "${url}"
3603
3647
 
3604
3648
  Fetch error:
@@ -3689,7 +3733,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
3689
3733
  const fileExtension = getFileExtension(filename);
3690
3734
  const mimeType = extensionToMimeType(fileExtension || '');
3691
3735
  if (!(await isFileExisting(filename, tools.fs))) {
3692
- throw new NotFoundError(spaceTrim$1((block) => `
3736
+ throw new NotFoundError(spaceTrim((block) => `
3693
3737
  Can not make source handler for file which does not exist:
3694
3738
 
3695
3739
  File:
@@ -3776,7 +3820,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
3776
3820
  // <- TODO: [๐Ÿช“] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
3777
3821
  break;
3778
3822
  }
3779
- console.warn(spaceTrim$1((block) => `
3823
+ console.warn(spaceTrim((block) => `
3780
3824
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
3781
3825
 
3782
3826
  The source:
@@ -3792,7 +3836,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
3792
3836
  // <- TODO: [๐Ÿฎ] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
3793
3837
  }
3794
3838
  if (partialPieces === null) {
3795
- throw new KnowledgeScrapeError(spaceTrim$1((block) => `
3839
+ throw new KnowledgeScrapeError(spaceTrim((block) => `
3796
3840
  Cannot scrape knowledge
3797
3841
 
3798
3842
  The source:
@@ -3821,9 +3865,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
3821
3865
  knowledgePreparedUnflatten[index] = pieces;
3822
3866
  }
3823
3867
  catch (error) {
3824
- if (!(error instanceof Error)) {
3825
- throw error;
3826
- }
3868
+ assertsError(error);
3827
3869
  console.warn(error);
3828
3870
  // <- TODO: [๐Ÿฎ] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
3829
3871
  }
@@ -3870,7 +3912,7 @@ async function prepareTasks(pipeline, tools, options) {
3870
3912
  if (task.taskType === 'PROMPT_TASK' &&
3871
3913
  knowledgePiecesCount > 0 &&
3872
3914
  !dependentParameterNames.includes('knowledge')) {
3873
- preparedContent = spaceTrim(`
3915
+ preparedContent = spaceTrim$1(`
3874
3916
  {content}
3875
3917
 
3876
3918
  ## Knowledge
@@ -4115,13 +4157,19 @@ function valueToString(value) {
4115
4157
  return value.toISOString();
4116
4158
  }
4117
4159
  else {
4118
- return JSON.stringify(value);
4160
+ try {
4161
+ return JSON.stringify(value);
4162
+ }
4163
+ catch (error) {
4164
+ if (error instanceof TypeError && error.message.includes('circular structure')) {
4165
+ return VALUE_STRINGS.circular;
4166
+ }
4167
+ throw error;
4168
+ }
4119
4169
  }
4120
4170
  }
4121
4171
  catch (error) {
4122
- if (!(error instanceof Error)) {
4123
- throw error;
4124
- }
4172
+ assertsError(error);
4125
4173
  console.error(error);
4126
4174
  return VALUE_STRINGS.unserializable;
4127
4175
  }
@@ -4178,10 +4226,8 @@ function extractVariablesFromJavascript(script) {
4178
4226
  }
4179
4227
  }
4180
4228
  catch (error) {
4181
- if (!(error instanceof Error)) {
4182
- throw error;
4183
- }
4184
- throw new ParseError(spaceTrim((block) => `
4229
+ assertsError(error);
4230
+ throw new ParseError(spaceTrim$1((block) => `
4185
4231
  Can not extract variables from the script
4186
4232
  ${block(error.stack || error.message)}
4187
4233
 
@@ -4299,6 +4345,28 @@ const MANDATORY_CSV_SETTINGS = Object.freeze({
4299
4345
  // encoding: 'utf-8',
4300
4346
  });
4301
4347
 
4348
+ /**
4349
+ * Function to check if a string is valid CSV
4350
+ *
4351
+ * @param value The string to check
4352
+ * @returns True if the string is a valid CSV string, false otherwise
4353
+ *
4354
+ * @public exported from `@promptbook/utils`
4355
+ */
4356
+ function isValidCsvString(value) {
4357
+ try {
4358
+ // A simple check for CSV format: at least one comma and no invalid characters
4359
+ if (value.includes(',') && /^[\w\s,"']+$/.test(value)) {
4360
+ return true;
4361
+ }
4362
+ return false;
4363
+ }
4364
+ catch (error) {
4365
+ assertsError(error);
4366
+ return false;
4367
+ }
4368
+ }
4369
+
4302
4370
  /**
4303
4371
  * Definition for CSV spreadsheet
4304
4372
  *
@@ -4309,7 +4377,7 @@ const CsvFormatDefinition = {
4309
4377
  formatName: 'CSV',
4310
4378
  aliases: ['SPREADSHEET', 'TABLE'],
4311
4379
  isValid(value, settings, schema) {
4312
- return true;
4380
+ return isValidCsvString(value);
4313
4381
  },
4314
4382
  canBeValid(partialValue, settings, schema) {
4315
4383
  return true;
@@ -4324,7 +4392,7 @@ const CsvFormatDefinition = {
4324
4392
  // TODO: [๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ] DRY csv parsing
4325
4393
  const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
4326
4394
  if (csv.errors.length !== 0) {
4327
- throw new CsvFormatError(spaceTrim$1((block) => `
4395
+ throw new CsvFormatError(spaceTrim((block) => `
4328
4396
  CSV parsing error
4329
4397
 
4330
4398
  Error(s) from CSV parsing:
@@ -4355,7 +4423,7 @@ const CsvFormatDefinition = {
4355
4423
  // TODO: [๐Ÿ‘จ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘จ๐Ÿผ] DRY csv parsing
4356
4424
  const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
4357
4425
  if (csv.errors.length !== 0) {
4358
- throw new CsvFormatError(spaceTrim$1((block) => `
4426
+ throw new CsvFormatError(spaceTrim((block) => `
4359
4427
  CSV parsing error
4360
4428
 
4361
4429
  Error(s) from CSV parsing:
@@ -4463,6 +4531,30 @@ const TextFormatDefinition = {
4463
4531
  * TODO: [๐Ÿข] Allow to expect something inside each item of list and other formats
4464
4532
  */
4465
4533
 
4534
+ /**
4535
+ * Function to check if a string is valid XML
4536
+ *
4537
+ * @param value
4538
+ * @returns True if the string is a valid XML string, false otherwise
4539
+ *
4540
+ * @public exported from `@promptbook/utils`
4541
+ */
4542
+ function isValidXmlString(value) {
4543
+ try {
4544
+ const parser = new DOMParser();
4545
+ const parsedDocument = parser.parseFromString(value, 'application/xml');
4546
+ const parserError = parsedDocument.getElementsByTagName('parsererror');
4547
+ if (parserError.length > 0) {
4548
+ return false;
4549
+ }
4550
+ return true;
4551
+ }
4552
+ catch (error) {
4553
+ assertsError(error);
4554
+ return false;
4555
+ }
4556
+ }
4557
+
4466
4558
  /**
4467
4559
  * Definition for XML format
4468
4560
  *
@@ -4472,7 +4564,7 @@ const XmlFormatDefinition = {
4472
4564
  formatName: 'XML',
4473
4565
  mimeType: 'application/xml',
4474
4566
  isValid(value, settings, schema) {
4475
- return true;
4567
+ return isValidXmlString(value);
4476
4568
  },
4477
4569
  canBeValid(partialValue, settings, schema) {
4478
4570
  return true;
@@ -4545,7 +4637,7 @@ function mapAvailableToExpectedParameters(options) {
4545
4637
  }
4546
4638
  // Phase 2๏ธโƒฃ: Non-matching mapping
4547
4639
  if (expectedParameterNames.size !== availableParametersNames.size) {
4548
- throw new PipelineExecutionError(spaceTrim$1((block) => `
4640
+ throw new PipelineExecutionError(spaceTrim((block) => `
4549
4641
  Can not map available parameters to expected parameters
4550
4642
 
4551
4643
  Mapped parameters:
@@ -4947,7 +5039,7 @@ async function executeAttempts(options) {
4947
5039
  const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attempt];
4948
5040
  // TODO: [๐Ÿง ][๐Ÿญ] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
4949
5041
  if (isJokerAttempt && !jokerParameterName) {
4950
- throw new UnexpectedError(spaceTrim((block) => `
5042
+ throw new UnexpectedError(spaceTrim$1((block) => `
4951
5043
  Joker not found in attempt ${attempt}
4952
5044
 
4953
5045
  ${block(pipelineIdentification)}
@@ -4958,7 +5050,7 @@ async function executeAttempts(options) {
4958
5050
  $ongoingTaskResult.$expectError = null;
4959
5051
  if (isJokerAttempt) {
4960
5052
  if (parameters[jokerParameterName] === undefined) {
4961
- throw new PipelineExecutionError(spaceTrim((block) => `
5053
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
4962
5054
  Joker parameter {${jokerParameterName}} not defined
4963
5055
 
4964
5056
  ${block(pipelineIdentification)}
@@ -5016,7 +5108,7 @@ async function executeAttempts(options) {
5016
5108
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
5017
5109
  break variant;
5018
5110
  case 'EMBEDDING':
5019
- throw new PipelineExecutionError(spaceTrim((block) => `
5111
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5020
5112
  Embedding model can not be used in pipeline
5021
5113
 
5022
5114
  This should be catched during parsing
@@ -5027,7 +5119,7 @@ async function executeAttempts(options) {
5027
5119
  break variant;
5028
5120
  // <- case [๐Ÿค–]:
5029
5121
  default:
5030
- throw new PipelineExecutionError(spaceTrim((block) => `
5122
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5031
5123
  Unknown model variant "${task.modelRequirements.modelVariant}"
5032
5124
 
5033
5125
  ${block(pipelineIdentification)}
@@ -5038,14 +5130,14 @@ async function executeAttempts(options) {
5038
5130
  break;
5039
5131
  case 'SCRIPT_TASK':
5040
5132
  if (arrayableToArray(tools.script).length === 0) {
5041
- throw new PipelineExecutionError(spaceTrim((block) => `
5133
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5042
5134
  No script execution tools are available
5043
5135
 
5044
5136
  ${block(pipelineIdentification)}
5045
5137
  `));
5046
5138
  }
5047
5139
  if (!task.contentLanguage) {
5048
- throw new PipelineExecutionError(spaceTrim((block) => `
5140
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5049
5141
  Script language is not defined for SCRIPT TASK "${task.name}"
5050
5142
 
5051
5143
  ${block(pipelineIdentification)}
@@ -5062,9 +5154,7 @@ async function executeAttempts(options) {
5062
5154
  break scripts;
5063
5155
  }
5064
5156
  catch (error) {
5065
- if (!(error instanceof Error)) {
5066
- throw error;
5067
- }
5157
+ assertsError(error);
5068
5158
  if (error instanceof UnexpectedError) {
5069
5159
  throw error;
5070
5160
  }
@@ -5078,7 +5168,7 @@ async function executeAttempts(options) {
5078
5168
  throw $ongoingTaskResult.$scriptPipelineExecutionErrors[0];
5079
5169
  }
5080
5170
  else {
5081
- throw new PipelineExecutionError(spaceTrim((block) => `
5171
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5082
5172
  Script execution failed ${$ongoingTaskResult.$scriptPipelineExecutionErrors.length}x
5083
5173
 
5084
5174
  ${block(pipelineIdentification)}
@@ -5092,7 +5182,7 @@ async function executeAttempts(options) {
5092
5182
  break taskType;
5093
5183
  case 'DIALOG_TASK':
5094
5184
  if (tools.userInterface === undefined) {
5095
- throw new PipelineExecutionError(spaceTrim((block) => `
5185
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5096
5186
  User interface tools are not available
5097
5187
 
5098
5188
  ${block(pipelineIdentification)}
@@ -5110,7 +5200,7 @@ async function executeAttempts(options) {
5110
5200
  break taskType;
5111
5201
  // <- case: [๐Ÿ…ฑ]
5112
5202
  default:
5113
- throw new PipelineExecutionError(spaceTrim((block) => `
5203
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
5114
5204
  Unknown execution type "${task.taskType}"
5115
5205
 
5116
5206
  ${block(pipelineIdentification)}
@@ -5134,9 +5224,7 @@ async function executeAttempts(options) {
5134
5224
  break scripts;
5135
5225
  }
5136
5226
  catch (error) {
5137
- if (!(error instanceof Error)) {
5138
- throw error;
5139
- }
5227
+ assertsError(error);
5140
5228
  if (error instanceof UnexpectedError) {
5141
5229
  throw error;
5142
5230
  }
@@ -5159,7 +5247,7 @@ async function executeAttempts(options) {
5159
5247
  }
5160
5248
  catch (error) {
5161
5249
  keepUnused(error);
5162
- throw new ExpectError(spaceTrim((block) => `
5250
+ throw new ExpectError(spaceTrim$1((block) => `
5163
5251
  Expected valid JSON string
5164
5252
 
5165
5253
  ${block(
@@ -5169,7 +5257,7 @@ async function executeAttempts(options) {
5169
5257
  }
5170
5258
  }
5171
5259
  else {
5172
- throw new UnexpectedError(spaceTrim((block) => `
5260
+ throw new UnexpectedError(spaceTrim$1((block) => `
5173
5261
  Unknown format "${task.format}"
5174
5262
 
5175
5263
  ${block(pipelineIdentification)}
@@ -5209,7 +5297,7 @@ async function executeAttempts(options) {
5209
5297
  }
5210
5298
  }
5211
5299
  if ($ongoingTaskResult.$expectError !== null && attempt === maxAttempts - 1) {
5212
- throw new PipelineExecutionError(spaceTrim((block) => {
5300
+ throw new PipelineExecutionError(spaceTrim$1((block) => {
5213
5301
  var _a, _b, _c;
5214
5302
  return `
5215
5303
  LLM execution failed ${maxExecutionAttempts}x
@@ -5232,7 +5320,7 @@ async function executeAttempts(options) {
5232
5320
  Last result:
5233
5321
  ${block($ongoingTaskResult.$resultString === null
5234
5322
  ? 'null'
5235
- : spaceTrim($ongoingTaskResult.$resultString)
5323
+ : spaceTrim$1($ongoingTaskResult.$resultString)
5236
5324
  .split('\n')
5237
5325
  .map((line) => `> ${line}`)
5238
5326
  .join('\n'))}
@@ -5242,7 +5330,7 @@ async function executeAttempts(options) {
5242
5330
  }
5243
5331
  }
5244
5332
  if ($ongoingTaskResult.$resultString === null) {
5245
- throw new UnexpectedError(spaceTrim((block) => `
5333
+ throw new UnexpectedError(spaceTrim$1((block) => `
5246
5334
  Something went wrong and prompt result is null
5247
5335
 
5248
5336
  ${block(pipelineIdentification)}
@@ -5265,7 +5353,7 @@ async function executeFormatSubvalues(options) {
5265
5353
  return /* not await */ executeAttempts(options);
5266
5354
  }
5267
5355
  if (jokerParameterNames.length !== 0) {
5268
- throw new UnexpectedError(spaceTrim$1((block) => `
5356
+ throw new UnexpectedError(spaceTrim((block) => `
5269
5357
  JOKER parameters are not supported together with FOREACH command
5270
5358
 
5271
5359
  [๐Ÿงžโ€โ™€๏ธ] This should be prevented in \`validatePipeline\`
@@ -5278,7 +5366,7 @@ async function executeFormatSubvalues(options) {
5278
5366
  if (formatDefinition === undefined) {
5279
5367
  throw new UnexpectedError(
5280
5368
  // <- TODO: [๐Ÿง ][๐Ÿง] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
5281
- spaceTrim$1((block) => `
5369
+ spaceTrim((block) => `
5282
5370
  Unsupported format "${task.foreach.formatName}"
5283
5371
 
5284
5372
  Available formats:
@@ -5295,7 +5383,7 @@ async function executeFormatSubvalues(options) {
5295
5383
  if (subvalueDefinition === undefined) {
5296
5384
  throw new UnexpectedError(
5297
5385
  // <- TODO: [๐Ÿง ][๐Ÿง] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
5298
- spaceTrim$1((block) => `
5386
+ spaceTrim((block) => `
5299
5387
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
5300
5388
 
5301
5389
  Available subformat names for format "${formatDefinition.formatName}":
@@ -5328,7 +5416,7 @@ async function executeFormatSubvalues(options) {
5328
5416
  if (!(error instanceof PipelineExecutionError)) {
5329
5417
  throw error;
5330
5418
  }
5331
- throw new PipelineExecutionError(spaceTrim$1((block) => `
5419
+ throw new PipelineExecutionError(spaceTrim((block) => `
5332
5420
  ${error.message}
5333
5421
 
5334
5422
  This is error in FOREACH command
@@ -5348,7 +5436,7 @@ async function executeFormatSubvalues(options) {
5348
5436
  ...options,
5349
5437
  priority: priority + index,
5350
5438
  parameters: allSubparameters,
5351
- pipelineIdentification: spaceTrim$1((block) => `
5439
+ pipelineIdentification: spaceTrim((block) => `
5352
5440
  ${block(pipelineIdentification)}
5353
5441
  Subparameter index: ${index}
5354
5442
  `),
@@ -5410,7 +5498,7 @@ async function getReservedParametersForTask(options) {
5410
5498
  // Note: Doublecheck that ALL reserved parameters are defined:
5411
5499
  for (const parameterName of RESERVED_PARAMETER_NAMES) {
5412
5500
  if (reservedParameters[parameterName] === undefined) {
5413
- throw new UnexpectedError(spaceTrim((block) => `
5501
+ throw new UnexpectedError(spaceTrim$1((block) => `
5414
5502
  Reserved parameter {${parameterName}} is not defined
5415
5503
 
5416
5504
  ${block(pipelineIdentification)}
@@ -5438,7 +5526,7 @@ async function executeTask(options) {
5438
5526
  const dependentParameterNames = new Set(currentTask.dependentParameterNames);
5439
5527
  // TODO: [๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿ‘ฉ๐Ÿป] Use here `mapAvailableToExpectedParameters`
5440
5528
  if (union(difference(usedParameterNames, dependentParameterNames), difference(dependentParameterNames, usedParameterNames)).size !== 0) {
5441
- throw new UnexpectedError(spaceTrim((block) => `
5529
+ throw new UnexpectedError(spaceTrim$1((block) => `
5442
5530
  Dependent parameters are not consistent with used parameters:
5443
5531
 
5444
5532
  Dependent parameters:
@@ -5478,7 +5566,7 @@ async function executeTask(options) {
5478
5566
  else if (!definedParameterNames.has(parameterName) && usedParameterNames.has(parameterName)) {
5479
5567
  // Houston, we have a problem
5480
5568
  // Note: Checking part is also done in `validatePipeline`, but itโ€™s good to doublecheck
5481
- throw new UnexpectedError(spaceTrim((block) => `
5569
+ throw new UnexpectedError(spaceTrim$1((block) => `
5482
5570
  Parameter \`{${parameterName}}\` is NOT defined
5483
5571
  BUT used in task "${currentTask.title || currentTask.name}"
5484
5572
 
@@ -5544,7 +5632,7 @@ function filterJustOutputParameters(options) {
5544
5632
  for (const parameter of preparedPipeline.parameters.filter(({ isOutput }) => isOutput)) {
5545
5633
  if (parametersToPass[parameter.name] === undefined) {
5546
5634
  // [4]
5547
- $warnings.push(new PipelineExecutionError(spaceTrim((block) => `
5635
+ $warnings.push(new PipelineExecutionError(spaceTrim$1((block) => `
5548
5636
  Parameter \`{${parameter.name}}\` should be an output parameter, but it was not generated during pipeline execution
5549
5637
 
5550
5638
  ${block(pipelineIdentification)}
@@ -5619,7 +5707,7 @@ async function executePipeline(options) {
5619
5707
  for (const parameterName of Object.keys(inputParameters)) {
5620
5708
  const parameter = preparedPipeline.parameters.find(({ name }) => name === parameterName);
5621
5709
  if (parameter === undefined) {
5622
- warnings.push(new PipelineExecutionError(spaceTrim((block) => `
5710
+ warnings.push(new PipelineExecutionError(spaceTrim$1((block) => `
5623
5711
  Extra parameter {${parameterName}} is being passed which is not part of the pipeline.
5624
5712
 
5625
5713
  ${block(pipelineIdentification)}
@@ -5634,7 +5722,7 @@ async function executePipeline(options) {
5634
5722
  // TODO: [๐Ÿง ] This should be also non-critical error
5635
5723
  return exportJson({
5636
5724
  name: 'pipelineExecutorResult',
5637
- message: spaceTrim((block) => `
5725
+ message: spaceTrim$1((block) => `
5638
5726
  Unuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
5639
5727
 
5640
5728
  ${block(pipelineIdentification)}
@@ -5643,7 +5731,7 @@ async function executePipeline(options) {
5643
5731
  value: {
5644
5732
  isSuccessful: false,
5645
5733
  errors: [
5646
- new PipelineExecutionError(spaceTrim((block) => `
5734
+ new PipelineExecutionError(spaceTrim$1((block) => `
5647
5735
  Parameter \`{${parameter.name}}\` is passed as input parameter but it is not input
5648
5736
 
5649
5737
  ${block(pipelineIdentification)}
@@ -5670,7 +5758,7 @@ async function executePipeline(options) {
5670
5758
  while (unresovedTasks.length > 0) {
5671
5759
  if (loopLimit-- < 0) {
5672
5760
  // Note: Really UnexpectedError not LimitReachedError - this should be catched during validatePipeline
5673
- throw new UnexpectedError(spaceTrim((block) => `
5761
+ throw new UnexpectedError(spaceTrim$1((block) => `
5674
5762
  Loop limit reached during resolving parameters pipeline execution
5675
5763
 
5676
5764
  ${block(pipelineIdentification)}
@@ -5680,7 +5768,7 @@ async function executePipeline(options) {
5680
5768
  if (!currentTask && resolving.length === 0) {
5681
5769
  throw new UnexpectedError(
5682
5770
  // TODO: [๐ŸŽ] DRY
5683
- spaceTrim((block) => `
5771
+ spaceTrim$1((block) => `
5684
5772
  Can not resolve some parameters:
5685
5773
 
5686
5774
  ${block(pipelineIdentification)}
@@ -5720,7 +5808,7 @@ async function executePipeline(options) {
5720
5808
  tools,
5721
5809
  onProgress(newOngoingResult) {
5722
5810
  if (isReturned) {
5723
- throw new UnexpectedError(spaceTrim((block) => `
5811
+ throw new UnexpectedError(spaceTrim$1((block) => `
5724
5812
  Can not call \`onProgress\` after pipeline execution is finished
5725
5813
 
5726
5814
  ${block(pipelineIdentification)}
@@ -5736,7 +5824,7 @@ async function executePipeline(options) {
5736
5824
  }
5737
5825
  },
5738
5826
  $executionReport: executionReport,
5739
- pipelineIdentification: spaceTrim((block) => `
5827
+ pipelineIdentification: spaceTrim$1((block) => `
5740
5828
  ${block(pipelineIdentification)}
5741
5829
  Task name: ${currentTask.name}
5742
5830
  Task title: ${currentTask.title}
@@ -5757,9 +5845,7 @@ async function executePipeline(options) {
5757
5845
  await Promise.all(resolving);
5758
5846
  }
5759
5847
  catch (error /* <- Note: [3] */) {
5760
- if (!(error instanceof Error)) {
5761
- throw error;
5762
- }
5848
+ assertsError(error);
5763
5849
  // Note: No need to rethrow UnexpectedError
5764
5850
  // if (error instanceof UnexpectedError) {
5765
5851
  // Note: Count usage, [๐Ÿง ] Maybe put to separate function executionReportJsonToUsage + DRY [๐Ÿคนโ€โ™‚๏ธ]
@@ -5847,7 +5933,7 @@ function createPipelineExecutor(options) {
5847
5933
  preparedPipeline = pipeline;
5848
5934
  }
5849
5935
  else if (isNotPreparedWarningSupressed !== true) {
5850
- console.warn(spaceTrim((block) => `
5936
+ console.warn(spaceTrim$1((block) => `
5851
5937
  Pipeline is not prepared
5852
5938
 
5853
5939
  ${block(pipelineIdentification)}
@@ -5871,7 +5957,7 @@ function createPipelineExecutor(options) {
5871
5957
  inputParameters,
5872
5958
  tools,
5873
5959
  onProgress,
5874
- pipelineIdentification: spaceTrim((block) => `
5960
+ pipelineIdentification: spaceTrim$1((block) => `
5875
5961
  ${block(pipelineIdentification)}
5876
5962
  ${runCount === 1 ? '' : `Run #${runCount}`}
5877
5963
  `),
@@ -5969,13 +6055,13 @@ function $registeredLlmToolsMessage() {
5969
6055
  });
5970
6056
  const usedEnvMessage = `Unknown \`.env\` file` ;
5971
6057
  if (metadata.length === 0) {
5972
- return spaceTrim$1((block) => `
6058
+ return spaceTrim((block) => `
5973
6059
  No LLM providers are available.
5974
6060
 
5975
6061
  ${block(usedEnvMessage)}
5976
6062
  `);
5977
6063
  }
5978
- return spaceTrim$1((block) => `
6064
+ return spaceTrim((block) => `
5979
6065
 
5980
6066
  ${block(usedEnvMessage)}
5981
6067
 
@@ -6021,7 +6107,7 @@ function $registeredLlmToolsMessage() {
6021
6107
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
6022
6108
  }
6023
6109
  }
6024
- let providerMessage = spaceTrim$1(`
6110
+ let providerMessage = spaceTrim(`
6025
6111
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
6026
6112
  ${morePieces.join('; ')}
6027
6113
  `);
@@ -6061,7 +6147,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
6061
6147
  .list()
6062
6148
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
6063
6149
  if (registeredItem === undefined) {
6064
- throw new Error(spaceTrim$1((block) => `
6150
+ throw new Error(spaceTrim((block) => `
6065
6151
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
6066
6152
 
6067
6153
  You have probably forgotten install and import the provider package.
@@ -6345,13 +6431,13 @@ function removeQuotes(text) {
6345
6431
  * @public exported from `@promptbook/utils`
6346
6432
  */
6347
6433
  function trimCodeBlock(value) {
6348
- value = spaceTrim(value);
6434
+ value = spaceTrim$1(value);
6349
6435
  if (!/^```[a-z]*(.*)```$/is.test(value)) {
6350
6436
  return value;
6351
6437
  }
6352
6438
  value = value.replace(/^```[a-z]*/i, '');
6353
6439
  value = value.replace(/```$/i, '');
6354
- value = spaceTrim(value);
6440
+ value = spaceTrim$1(value);
6355
6441
  return value;
6356
6442
  }
6357
6443
 
@@ -6364,9 +6450,9 @@ function trimCodeBlock(value) {
6364
6450
  * @public exported from `@promptbook/utils`
6365
6451
  */
6366
6452
  function trimEndOfCodeBlock(value) {
6367
- value = spaceTrim(value);
6453
+ value = spaceTrim$1(value);
6368
6454
  value = value.replace(/```$/g, '');
6369
- value = spaceTrim(value);
6455
+ value = spaceTrim$1(value);
6370
6456
  return value;
6371
6457
  }
6372
6458
 
@@ -6388,7 +6474,7 @@ function unwrapResult(text, options) {
6388
6474
  let trimmedText = text;
6389
6475
  // Remove leading and trailing spaces and newlines
6390
6476
  if (isTrimmed) {
6391
- trimmedText = spaceTrim(trimmedText);
6477
+ trimmedText = spaceTrim$1(trimmedText);
6392
6478
  }
6393
6479
  let processedText = trimmedText;
6394
6480
  if (isIntroduceSentenceRemoved) {
@@ -6397,7 +6483,7 @@ function unwrapResult(text, options) {
6397
6483
  // Remove the introduce sentence and quotes by replacing it with an empty string
6398
6484
  processedText = processedText.replace(introduceSentenceRegex, '');
6399
6485
  }
6400
- processedText = spaceTrim(processedText);
6486
+ processedText = spaceTrim$1(processedText);
6401
6487
  }
6402
6488
  if (processedText.length < 3) {
6403
6489
  return trimmedText;
@@ -6460,7 +6546,7 @@ function unwrapResult(text, options) {
6460
6546
  function extractOneBlockFromMarkdown(markdown) {
6461
6547
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
6462
6548
  if (codeBlocks.length !== 1) {
6463
- throw new ParseError(spaceTrim$1((block) => `
6549
+ throw new ParseError(spaceTrim((block) => `
6464
6550
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
6465
6551
 
6466
6552
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -6542,8 +6628,8 @@ class JavascriptEvalExecutionTools {
6542
6628
  }
6543
6629
  // Note: [๐Ÿ’Ž]
6544
6630
  // Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
6545
- const spaceTrim = (_) => spaceTrim$1(_);
6546
- preserve(spaceTrim);
6631
+ const spaceTrim$1 = (_) => spaceTrim(_);
6632
+ preserve(spaceTrim$1);
6547
6633
  const removeQuotes$1 = removeQuotes;
6548
6634
  preserve(removeQuotes$1);
6549
6635
  const unwrapResult$1 = unwrapResult;
@@ -6596,7 +6682,7 @@ class JavascriptEvalExecutionTools {
6596
6682
  // TODO: DRY [๐Ÿฏ]
6597
6683
  const buildinFunctions = {
6598
6684
  // TODO: [๐Ÿฏ] DRY all these functions across the file
6599
- spaceTrim,
6685
+ spaceTrim: spaceTrim$1,
6600
6686
  removeQuotes: removeQuotes$1,
6601
6687
  unwrapResult: unwrapResult$1,
6602
6688
  trimEndOfCodeBlock: trimEndOfCodeBlock$1,
@@ -6633,7 +6719,7 @@ class JavascriptEvalExecutionTools {
6633
6719
  .join('\n');
6634
6720
  // script = templateParameters(script, parameters);
6635
6721
  // <- TODO: [๐Ÿง ][๐Ÿฅณ] Should be this is one of two variants how to use parameters in script
6636
- const statementToEvaluate = spaceTrim$1((block) => `
6722
+ const statementToEvaluate = spaceTrim((block) => `
6637
6723
 
6638
6724
  // Build-in functions:
6639
6725
  ${block(buildinFunctionsStatement)}
@@ -6648,7 +6734,7 @@ class JavascriptEvalExecutionTools {
6648
6734
  (()=>{ ${script} })()
6649
6735
  `);
6650
6736
  if (this.options.isVerbose) {
6651
- console.info(spaceTrim$1((block) => `
6737
+ console.info(spaceTrim((block) => `
6652
6738
  ๐Ÿš€ Evaluating ${scriptLanguage} script:
6653
6739
 
6654
6740
  ${block(statementToEvaluate)}`));
@@ -6661,9 +6747,7 @@ class JavascriptEvalExecutionTools {
6661
6747
  }
6662
6748
  }
6663
6749
  catch (error) {
6664
- if (!(error instanceof Error)) {
6665
- throw error;
6666
- }
6750
+ assertsError(error);
6667
6751
  if (error instanceof ReferenceError) {
6668
6752
  const undefinedName = error.message.split(' ')[0];
6669
6753
  /*
@@ -6672,7 +6756,7 @@ class JavascriptEvalExecutionTools {
6672
6756
  To: [PipelineExecutionError: Parameter `{thing}` is not defined],
6673
6757
  */
6674
6758
  if (!statementToEvaluate.includes(undefinedName + '(')) {
6675
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6759
+ throw new PipelineExecutionError(spaceTrim((block) => `
6676
6760
 
6677
6761
  Parameter \`{${undefinedName}}\` is not defined
6678
6762
 
@@ -6694,7 +6778,7 @@ class JavascriptEvalExecutionTools {
6694
6778
  `));
6695
6779
  }
6696
6780
  else {
6697
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6781
+ throw new PipelineExecutionError(spaceTrim((block) => `
6698
6782
  Function ${undefinedName}() is not defined
6699
6783
 
6700
6784
  - Make sure that the function is one of built-in functions
@@ -6743,6 +6827,198 @@ async function $provideScriptingForNode(options) {
6743
6827
  * Note: [๐ŸŸข] Code in this file should never be never released in packages that could be imported into browser environment
6744
6828
  */
6745
6829
 
6830
+ // TODO: !!!! List running services from REMOTE_SERVER_URLS
6831
+ // TODO: !!!! Import directly from YML
6832
+ /**
6833
+ * @private !!!! Decide how to expose this
6834
+ */
6835
+ const openapiJson = {
6836
+ openapi: '3.0.0',
6837
+ info: {
6838
+ title: 'Promptbook Remote Server API (!!!! From TS)',
6839
+ version: '1.0.0',
6840
+ description: 'API documentation for the Promptbook Remote Server',
6841
+ },
6842
+ paths: {
6843
+ '/': {
6844
+ get: {
6845
+ summary: 'Get server details',
6846
+ description: 'Returns details about the Promptbook server.',
6847
+ responses: {
6848
+ '200': {
6849
+ description: 'Server details in markdown format.',
6850
+ },
6851
+ },
6852
+ },
6853
+ },
6854
+ '/login': {
6855
+ post: {
6856
+ summary: 'Login to the server',
6857
+ description: 'Login to the server and get identification.',
6858
+ requestBody: {
6859
+ required: true,
6860
+ content: {
6861
+ 'application/json': {
6862
+ schema: {
6863
+ type: 'object',
6864
+ properties: {
6865
+ username: {
6866
+ type: 'string',
6867
+ },
6868
+ password: {
6869
+ type: 'string',
6870
+ },
6871
+ appId: {
6872
+ type: 'string',
6873
+ },
6874
+ },
6875
+ },
6876
+ },
6877
+ },
6878
+ },
6879
+ responses: {
6880
+ '200': {
6881
+ description: 'Successful login',
6882
+ content: {
6883
+ 'application/json': {
6884
+ schema: {
6885
+ type: 'object',
6886
+ properties: {
6887
+ identification: {
6888
+ type: 'object',
6889
+ },
6890
+ },
6891
+ },
6892
+ },
6893
+ },
6894
+ },
6895
+ },
6896
+ },
6897
+ },
6898
+ '/books': {
6899
+ get: {
6900
+ summary: 'List all books',
6901
+ description: 'Returns a list of all available books in the collection.',
6902
+ responses: {
6903
+ '200': {
6904
+ description: 'A list of books.',
6905
+ content: {
6906
+ 'application/json': {
6907
+ schema: {
6908
+ type: 'array',
6909
+ items: {
6910
+ type: 'string',
6911
+ },
6912
+ },
6913
+ },
6914
+ },
6915
+ },
6916
+ },
6917
+ },
6918
+ },
6919
+ '/books/{bookId}': {
6920
+ get: {
6921
+ summary: 'Get book content',
6922
+ description: 'Returns the content of a specific book.',
6923
+ parameters: [
6924
+ {
6925
+ in: 'path',
6926
+ name: 'bookId',
6927
+ required: true,
6928
+ schema: {
6929
+ type: 'string',
6930
+ },
6931
+ description: 'The ID of the book to retrieve.',
6932
+ },
6933
+ ],
6934
+ responses: {
6935
+ '200': {
6936
+ description: 'The content of the book.',
6937
+ content: {
6938
+ 'text/markdown': {
6939
+ schema: {
6940
+ type: 'string',
6941
+ },
6942
+ },
6943
+ },
6944
+ },
6945
+ '404': {
6946
+ description: 'Book not found.',
6947
+ },
6948
+ },
6949
+ },
6950
+ },
6951
+ '/executions': {
6952
+ get: {
6953
+ summary: 'List all executions',
6954
+ description: 'Returns a list of all running execution tasks.',
6955
+ responses: {
6956
+ '200': {
6957
+ description: 'A list of execution tasks.',
6958
+ content: {
6959
+ 'application/json': {
6960
+ schema: {
6961
+ type: 'array',
6962
+ items: {
6963
+ type: 'object',
6964
+ },
6965
+ },
6966
+ },
6967
+ },
6968
+ },
6969
+ },
6970
+ },
6971
+ },
6972
+ '/executions/new': {
6973
+ post: {
6974
+ summary: 'Start a new execution',
6975
+ description: 'Starts a new execution task for a given pipeline.',
6976
+ requestBody: {
6977
+ required: true,
6978
+ content: {
6979
+ 'application/json': {
6980
+ schema: {
6981
+ type: 'object',
6982
+ properties: {
6983
+ pipelineUrl: {
6984
+ type: 'string',
6985
+ },
6986
+ inputParameters: {
6987
+ type: 'object',
6988
+ },
6989
+ identification: {
6990
+ type: 'object',
6991
+ },
6992
+ },
6993
+ },
6994
+ },
6995
+ },
6996
+ },
6997
+ responses: {
6998
+ '200': {
6999
+ description: 'The newly created execution task.',
7000
+ content: {
7001
+ 'application/json': {
7002
+ schema: {
7003
+ type: 'object',
7004
+ },
7005
+ },
7006
+ },
7007
+ },
7008
+ '400': {
7009
+ description: 'Invalid input.',
7010
+ },
7011
+ },
7012
+ },
7013
+ },
7014
+ },
7015
+ components: {},
7016
+ tags: [],
7017
+ };
7018
+ /**
7019
+ * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
7020
+ */
7021
+
6746
7022
  /**
6747
7023
  * Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
6748
7024
  *
@@ -6753,7 +7029,7 @@ async function $provideScriptingForNode(options) {
6753
7029
  * @public exported from `@promptbook/remote-server`
6754
7030
  */
6755
7031
  function startRemoteServer(options) {
6756
- const { port, collection, createLlmExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
7032
+ const { port, collection, createLlmExecutionTools, createExecutionTools, isAnonymousModeAllowed, isApplicationModeAllowed, isVerbose = DEFAULT_IS_VERBOSE, login, } = {
6757
7033
  isAnonymousModeAllowed: false,
6758
7034
  isApplicationModeAllowed: false,
6759
7035
  collection: null,
@@ -6761,22 +7037,6 @@ function startRemoteServer(options) {
6761
7037
  login: null,
6762
7038
  ...options,
6763
7039
  };
6764
- // <- TODO: [๐Ÿฆช] Some helper type to be able to use discriminant union types with destructuring
6765
- let { rootPath = '/' } = options;
6766
- if (!rootPath.startsWith('/')) {
6767
- rootPath = `/${rootPath}`;
6768
- } /* not else */
6769
- if (rootPath.endsWith('/')) {
6770
- rootPath = rootPath.slice(0, -1);
6771
- } /* not else */
6772
- if (rootPath === '/') {
6773
- rootPath = '';
6774
- }
6775
- const socketioPath = '/' +
6776
- `${rootPath}/socket.io`
6777
- .split('/')
6778
- .filter((part) => part !== '')
6779
- .join('/');
6780
7040
  const startupDate = new Date();
6781
7041
  async function getExecutionToolsFromIdentification(identification) {
6782
7042
  if (identification === null || identification === undefined) {
@@ -6799,23 +7059,25 @@ function startRemoteServer(options) {
6799
7059
  }
6800
7060
  else if (isAnonymous === false && createLlmExecutionTools !== null) {
6801
7061
  // Note: Application mode
6802
- const { appId, userId, customOptions } = identification;
6803
- llm = await createLlmExecutionTools({
6804
- appId,
6805
- userId,
6806
- customOptions,
6807
- });
7062
+ llm = await createLlmExecutionTools(identification);
6808
7063
  }
6809
7064
  else {
6810
7065
  throw new PipelineExecutionError(`You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured`);
6811
7066
  }
6812
- const fs = $provideFilesystemForNode();
6813
- const executables = await $provideExecutablesForNode();
7067
+ const customExecutionTools = createExecutionTools ? await createExecutionTools(identification) : {};
7068
+ const fs = customExecutionTools.fs || $provideFilesystemForNode();
7069
+ const executables = customExecutionTools.executables || (await $provideExecutablesForNode());
7070
+ const scrapers = customExecutionTools.scrapers || (await $provideScrapersForNode({ fs, llm, executables }));
7071
+ const script = customExecutionTools.script || (await $provideScriptingForNode({}));
7072
+ const fetch = customExecutionTools.fetch || promptbookFetch;
7073
+ const userInterface = customExecutionTools.userInterface || undefined;
6814
7074
  const tools = {
6815
7075
  llm,
6816
7076
  fs,
6817
- scrapers: await $provideScrapersForNode({ fs, llm, executables }),
6818
- script: await $provideScriptingForNode({}),
7077
+ scrapers,
7078
+ script,
7079
+ fetch,
7080
+ userInterface,
6819
7081
  };
6820
7082
  return tools;
6821
7083
  }
@@ -6825,44 +7087,32 @@ function startRemoteServer(options) {
6825
7087
  response.setHeader('X-Powered-By', 'Promptbook engine');
6826
7088
  next();
6827
7089
  });
6828
- const swaggerOptions = {
6829
- definition: {
6830
- openapi: '3.0.0',
6831
- info: {
6832
- title: 'Promptbook Remote Server API',
6833
- version: '1.0.0',
6834
- description: 'API documentation for the Promptbook Remote Server',
6835
- },
6836
- servers: [
6837
- {
6838
- url: `http://localhost:${port}${rootPath}`,
6839
- // <- TODO: !!!!! Probbably: Pass `remoteServerUrl` instead of `port` and `rootPath`
6840
- },
6841
- ],
7090
+ // TODO: !!!! Expose openapiJson to consumer and also allow to add new routes
7091
+ app.use(OpenApiValidator.middleware({
7092
+ apiSpec: openapiJson,
7093
+ ignorePaths(path) {
7094
+ return path.startsWith('/api-docs') || path.startsWith('/swagger') || path.startsWith('/openapi');
6842
7095
  },
6843
- apis: ['./src/remote-server/**/*.ts'], // Adjust path as needed
6844
- };
6845
- const swaggerSpec = swaggerJsdoc(swaggerOptions);
6846
- app.use([`/api-docs`, `${rootPath}/api-docs`], swaggerUi.serve, swaggerUi.setup(swaggerSpec));
7096
+ validateRequests: true,
7097
+ validateResponses: true,
7098
+ }));
7099
+ app.use([`/api-docs`, `/swagger`], swaggerUi.serve, swaggerUi.setup(openapiJson, {
7100
+ // customCss: '.swagger-ui .topbar { display: none }',
7101
+ // customSiteTitle: 'BRJ API',
7102
+ // customfavIcon: 'https://brj.app/favicon.ico',
7103
+ }));
7104
+ app.get(`/openapi`, (request, response) => {
7105
+ response.json(openapiJson);
7106
+ });
6847
7107
  const runningExecutionTasks = [];
6848
7108
  // <- TODO: [๐Ÿคฌ] Identify the users
6849
7109
  // TODO: [๐Ÿง ] Do here some garbage collection of finished tasks
6850
- /**
6851
- * @swagger
6852
- * /:
6853
- * get:
6854
- * summary: Get server details
6855
- * description: Returns details about the Promptbook server.
6856
- * responses:
6857
- * 200:
6858
- * description: Server details in markdown format.
6859
- */
6860
- app.get(['/', rootPath], async (request, response) => {
7110
+ app.get('/', async (request, response) => {
6861
7111
  var _a;
6862
7112
  if ((_a = request.url) === null || _a === void 0 ? void 0 : _a.includes('socket.io')) {
6863
7113
  return;
6864
7114
  }
6865
- response.type('text/markdown').send(await spaceTrim(async (block) => `
7115
+ response.type('text/markdown').send(await spaceTrim$1(async (block) => `
6866
7116
  # Promptbook
6867
7117
 
6868
7118
  > ${block(CLAIM)}
@@ -6876,8 +7126,6 @@ function startRemoteServer(options) {
6876
7126
  ## Details
6877
7127
 
6878
7128
  **Server port:** ${port}
6879
- **Server root path:** ${rootPath}
6880
- **Socket.io path:** ${socketioPath}
6881
7129
  **Startup date:** ${startupDate.toISOString()}
6882
7130
  **Anonymouse mode:** ${isAnonymousModeAllowed ? 'enabled' : 'disabled'}
6883
7131
  **Application mode:** ${isApplicationModeAllowed ? 'enabled' : 'disabled'}
@@ -6916,38 +7164,7 @@ function startRemoteServer(options) {
6916
7164
  https://github.com/webgptorg/promptbook
6917
7165
  `));
6918
7166
  });
6919
- /**
6920
- * @swagger
6921
- *
6922
- * /login:
6923
- * post:
6924
- * summary: Login to the server
6925
- * description: Login to the server and get identification.
6926
- * requestBody:
6927
- * required: true
6928
- * content:
6929
- * application/json:
6930
- * schema:
6931
- * type: object
6932
- * properties:
6933
- * username:
6934
- * type: string
6935
- * password:
6936
- * type: string
6937
- * appId:
6938
- * type: string
6939
- * responses:
6940
- * 200:
6941
- * description: Successful login
6942
- * content:
6943
- * application/json:
6944
- * schema:
6945
- * type: object
6946
- * properties:
6947
- * identification:
6948
- * type: object
6949
- */
6950
- app.post([`/login`, `${rootPath}/login`], async (request, response) => {
7167
+ app.post(`/login`, async (request, response) => {
6951
7168
  if (!isApplicationModeAllowed || login === null) {
6952
7169
  response.status(400).send('Application mode is not allowed');
6953
7170
  return;
@@ -6972,9 +7189,7 @@ function startRemoteServer(options) {
6972
7189
  return;
6973
7190
  }
6974
7191
  catch (error) {
6975
- if (!(error instanceof Error)) {
6976
- throw error;
6977
- }
7192
+ assertsError(error);
6978
7193
  if (error instanceof AuthenticationError) {
6979
7194
  response.status(401).send({
6980
7195
  isSuccess: false,
@@ -6989,23 +7204,7 @@ function startRemoteServer(options) {
6989
7204
  response.status(400).send({ error: serializeError(error) });
6990
7205
  }
6991
7206
  });
6992
- /**
6993
- * @swagger
6994
- * /books:
6995
- * get:
6996
- * summary: List all books
6997
- * description: Returns a list of all available books in the collection.
6998
- * responses:
6999
- * 200:
7000
- * description: A list of books.
7001
- * content:
7002
- * application/json:
7003
- * schema:
7004
- * type: array
7005
- * items:
7006
- * type: string
7007
- */
7008
- app.get([`/books`, `${rootPath}/books`], async (request, response) => {
7207
+ app.get(`/books`, async (request, response) => {
7009
7208
  if (collection === null) {
7010
7209
  response.status(500).send('No collection available');
7011
7210
  return;
@@ -7015,30 +7214,7 @@ function startRemoteServer(options) {
7015
7214
  response.send(pipelines);
7016
7215
  });
7017
7216
  // TODO: [๐Ÿง ] Is it secure / good idea to expose source codes of hosted books
7018
- /**
7019
- * @swagger
7020
- * /books/{bookId}:
7021
- * get:
7022
- * summary: Get book content
7023
- * description: Returns the content of a specific book.
7024
- * parameters:
7025
- * - in: path
7026
- * name: bookId
7027
- * required: true
7028
- * schema:
7029
- * type: string
7030
- * description: The ID of the book to retrieve.
7031
- * responses:
7032
- * 200:
7033
- * description: The content of the book.
7034
- * content:
7035
- * text/markdown:
7036
- * schema:
7037
- * type: string
7038
- * 404:
7039
- * description: Book not found.
7040
- */
7041
- app.get([`/books/*`, `${rootPath}/books/*`], async (request, response) => {
7217
+ app.get(`/books/*`, async (request, response) => {
7042
7218
  try {
7043
7219
  if (collection === null) {
7044
7220
  response.status(500).send('No collection nor books available');
@@ -7057,9 +7233,7 @@ function startRemoteServer(options) {
7057
7233
  .send(source.content);
7058
7234
  }
7059
7235
  catch (error) {
7060
- if (!(error instanceof Error)) {
7061
- throw error;
7062
- }
7236
+ assertsError(error);
7063
7237
  response
7064
7238
  .status(404)
7065
7239
  .send({ error: serializeError(error) });
@@ -7092,26 +7266,10 @@ function startRemoteServer(options) {
7092
7266
  };
7093
7267
  }
7094
7268
  }
7095
- /**
7096
- * @swagger
7097
- * /executions:
7098
- * get:
7099
- * summary: List all executions
7100
- * description: Returns a list of all running execution tasks.
7101
- * responses:
7102
- * 200:
7103
- * description: A list of execution tasks.
7104
- * content:
7105
- * application/json:
7106
- * schema:
7107
- * type: array
7108
- * items:
7109
- * type: object
7110
- */
7111
- app.get([`/executions`, `${rootPath}/executions`], async (request, response) => {
7112
- response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
7269
+ app.get(`/executions`, async (request, response) => {
7270
+ response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)) /* <- TODO: satisfies paths['/executions']['get']['responses']['200']['content']['application/json'] */);
7113
7271
  });
7114
- app.get([`/executions/last`, `${rootPath}/executions/last`], async (request, response) => {
7272
+ app.get(`/executions/last`, async (request, response) => {
7115
7273
  // TODO: [๐Ÿคฌ] Filter only for user
7116
7274
  if (runningExecutionTasks.length === 0) {
7117
7275
  response.status(404).send('No execution tasks found');
@@ -7120,7 +7278,7 @@ function startRemoteServer(options) {
7120
7278
  const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
7121
7279
  response.send(exportExecutionTask(lastExecutionTask, true));
7122
7280
  });
7123
- app.get([`/executions/:taskId`, `${rootPath}/executions/:taskId`], async (request, response) => {
7281
+ app.get(`/executions/:taskId`, async (request, response) => {
7124
7282
  const { taskId } = request.params;
7125
7283
  // TODO: [๐Ÿคฌ] Filter only for user
7126
7284
  const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
@@ -7132,39 +7290,12 @@ function startRemoteServer(options) {
7132
7290
  }
7133
7291
  response.send(exportExecutionTask(executionTask, true));
7134
7292
  });
7135
- /**
7136
- * @swagger
7137
- * /executions/new:
7138
- * post:
7139
- * summary: Start a new execution
7140
- * description: Starts a new execution task for a given pipeline.
7141
- * requestBody:
7142
- * required: true
7143
- * content:
7144
- * application/json:
7145
- * schema:
7146
- * type: object
7147
- * properties:
7148
- * pipelineUrl:
7149
- * type: string
7150
- * inputParameters:
7151
- * type: object
7152
- * identification:
7153
- * type: object
7154
- * responses:
7155
- * 200:
7156
- * description: The newly created execution task.
7157
- * content:
7158
- * application/json:
7159
- * schema:
7160
- * type: object
7161
- * 400:
7162
- * description: Invalid input.
7163
- */
7164
- app.post([`/executions/new`, `${rootPath}/executions/new`], async (request, response) => {
7293
+ app.post(`/executions/new`, async (request, response) => {
7165
7294
  try {
7166
7295
  const { inputParameters, identification /* <- [๐Ÿคฌ] */ } = request.body;
7167
- const pipelineUrl = request.body.pipelineUrl || request.body.book;
7296
+ const pipelineUrl = request.body
7297
+ .pipelineUrl /* <- TODO: as paths['/executions/new']['post']['requestBody']['content']['application/json'] */ ||
7298
+ request.body.book;
7168
7299
  // TODO: [๐Ÿง ] Check `pipelineUrl` and `inputParameters` here or it should be responsibility of `collection.getPipelineByUrl` and `pipelineExecutor`
7169
7300
  const pipeline = await (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl));
7170
7301
  if (pipeline === undefined) {
@@ -7178,7 +7309,7 @@ function startRemoteServer(options) {
7178
7309
  await forTime(10);
7179
7310
  // <- Note: Wait for a while to wait for quick responses or sudden but asynchronous errors
7180
7311
  // <- TODO: Put this into configuration
7181
- response.send(executionTask);
7312
+ response.send(executionTask /* <- TODO: satisfies paths['/executions/new']['post']['responses']['200']['content']['application/json'] */);
7182
7313
  /*/
7183
7314
  executionTask.asObservable().subscribe({
7184
7315
  next(partialResult) {
@@ -7198,19 +7329,24 @@ function startRemoteServer(options) {
7198
7329
  */
7199
7330
  }
7200
7331
  catch (error) {
7201
- if (!(error instanceof Error)) {
7202
- throw error;
7203
- }
7332
+ assertsError(error);
7204
7333
  response.status(400).send({ error: serializeError(error) });
7205
7334
  }
7206
7335
  });
7336
+ /**
7337
+ * Catch-all handler for unmatched routes
7338
+ */
7339
+ app.use((request, response) => {
7340
+ response.status(404).send(`URL "${request.originalUrl}" was not found on Promptbook server.`);
7341
+ });
7207
7342
  const httpServer = http.createServer(app);
7208
7343
  const server = new Server(httpServer, {
7209
- path: socketioPath,
7210
- transports: [/*'websocket', <- TODO: [๐ŸŒฌ] Make websocket transport work */ 'polling'],
7344
+ path: '/socket.io',
7345
+ transports: ['polling', 'websocket' /*, <- TODO: [๐ŸŒฌ] Allow to pass `transports`, add 'webtransport' */],
7211
7346
  cors: {
7212
7347
  origin: '*',
7213
7348
  methods: ['GET', 'POST'],
7349
+ // <- TODO: [๐ŸŒก] Allow to pass
7214
7350
  },
7215
7351
  });
7216
7352
  server.on('connection', (socket) => {
@@ -7264,9 +7400,7 @@ function startRemoteServer(options) {
7264
7400
  socket.emit('prompt-response', { promptResult } /* <- Note: [๐Ÿค›] */);
7265
7401
  }
7266
7402
  catch (error) {
7267
- if (!(error instanceof Error)) {
7268
- throw error;
7269
- }
7403
+ assertsError(error);
7270
7404
  socket.emit('error', serializeError(error) /* <- Note: [๐Ÿค›] */);
7271
7405
  }
7272
7406
  finally {
@@ -7288,9 +7422,7 @@ function startRemoteServer(options) {
7288
7422
  socket.emit('listModels-response', { models } /* <- Note: [๐Ÿค›] */);
7289
7423
  }
7290
7424
  catch (error) {
7291
- if (!(error instanceof Error)) {
7292
- throw error;
7293
- }
7425
+ assertsError(error);
7294
7426
  socket.emit('error', serializeError(error));
7295
7427
  }
7296
7428
  finally {
@@ -7311,9 +7443,7 @@ function startRemoteServer(options) {
7311
7443
  socket.emit('preparePipeline-response', { preparedPipeline } /* <- Note: [๐Ÿค›] */);
7312
7444
  }
7313
7445
  catch (error) {
7314
- if (!(error instanceof Error)) {
7315
- throw error;
7316
- }
7446
+ assertsError(error);
7317
7447
  socket.emit('error', serializeError(error));
7318
7448
  // <- TODO: [๐Ÿš‹] There is a problem with the remote server handling errors and sending them back to the client
7319
7449
  }
@@ -7361,8 +7491,7 @@ function startRemoteServer(options) {
7361
7491
  };
7362
7492
  }
7363
7493
  /**
7364
- * TODO: !! Add CORS and security - probbably via `helmet`
7365
- * TODO: [๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿง‘๐Ÿพ] Allow to pass custom fetch function here - PromptbookFetch
7494
+ * TODO: [๐ŸŒก] Add CORS and security - probbably via `helmet`
7366
7495
  * TODO: Split this file into multiple functions - handler for each request
7367
7496
  * TODO: Maybe use `$exportJson`
7368
7497
  * TODO: [๐Ÿง ][๐Ÿ›] Maybe not `isAnonymous: boolean` BUT `mode: 'ANONYMOUS'|'COLLECTION'`