@promptbook/cli 0.89.0-15 → 0.89.0-17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/umd/index.umd.js CHANGED
@@ -56,7 +56,7 @@
56
56
  * @generated
57
57
  * @see https://github.com/webgptorg/promptbook
58
58
  */
59
- const PROMPTBOOK_ENGINE_VERSION = '0.89.0-15';
59
+ const PROMPTBOOK_ENGINE_VERSION = '0.89.0-17';
60
60
  /**
61
61
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
62
62
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -116,6 +116,7 @@
116
116
  * @public exported from `@promptbook/core`
117
117
  */
118
118
  const CLAIM = `It's time for a paradigm shift. The future of software in plain English, French or Latin`;
119
+ // <- TODO: [🐊] Pick the best claim
119
120
  /**
120
121
  * When the title is not provided, the default title is used
121
122
  *
@@ -146,6 +147,12 @@
146
147
  * @private within the repository
147
148
  */
148
149
  const GENERATOR_WARNING_BY_PROMPTBOOK_CLI = `⚠️ WARNING: This code has been generated by \`@promptbook/cli\` so that any manual changes will be overwritten`;
150
+ /**
151
+ * Warning message for the automatically generated sections of `.env` files
152
+ *
153
+ * @private within the repository
154
+ */
155
+ const GENERATOR_WARNING_IN_ENV = `Note: Added by Promptbook`;
149
156
  // <- TODO: [🧠] Better system for generator warnings - not always "code" and "by `@promptbook/cli`"
150
157
  /**
151
158
  * The maximum number of iterations for a loops
@@ -226,7 +233,7 @@
226
233
  */
227
234
  const DEFAULT_BOOKS_DIRNAME = './books';
228
235
  // <- TODO: [🕝] Make also `BOOKS_DIRNAME_ALTERNATIVES`
229
- // TODO: !!!!!! Just .promptbook dir, hardocode others
236
+ // TODO: Just `.promptbook` in config, hardcode subfolders like `download-cache` or `execution-cache`
230
237
  /**
231
238
  * Where to store the temporary downloads
232
239
  *
@@ -282,11 +289,20 @@
282
289
  ss: 3, // <- least number of seconds to be counted in seconds, minus 1. Must be set after setting the `s` unit or without setting the `s` unit.
283
290
  };
284
291
  /**
285
- * @@@
292
+ * Available remote servers for the Promptbook
286
293
  *
287
294
  * @public exported from `@promptbook/core`
288
295
  */
289
- const DEFAULT_REMOTE_SERVER_URL = 'https://api.pavolhejny.com/promptbook';
296
+ const REMOTE_SERVER_URLS = [
297
+ 'https://s1.ptbk.io/promptbook',
298
+ 'https://api.pavolhejny.com/promptbook',
299
+ ];
300
+ /**
301
+ * Default remote server URL for the Promptbook
302
+ *
303
+ * @public exported from `@promptbook/core`
304
+ */
305
+ const DEFAULT_REMOTE_SERVER_URL = REMOTE_SERVER_URLS[0];
290
306
  // <- TODO: [🧜‍♂️]
291
307
  /**
292
308
  * @@@
@@ -497,44 +513,42 @@
497
513
  constructor(whatWasThrown) {
498
514
  const tag = `[🤮]`;
499
515
  console.error(tag, whatWasThrown);
500
- super(spaceTrim.spaceTrim((block) => `
501
- ${ /* Fixing tests !!! block(valueToString(whatWasThrown)) */block(`non-Error object was thrown`)}
502
-
503
- Note: Look for ${tag} in the console for more details
504
- !!! Note: \`WrappedError\` indicates that somewhere in the code non-Error object was thrown and it was wrapped
505
-
506
- Please report issue on ${ADMIN_EMAIL}
516
+ super(spaceTrim.spaceTrim(`
517
+ Non-Error object was thrown
507
518
 
508
- `));
519
+ Note: Look for ${tag} in the console for more details
520
+ Please report issue on ${ADMIN_EMAIL}
521
+ `));
509
522
  this.name = 'WrappedError';
510
523
  Object.setPrototypeOf(this, WrappedError.prototype);
511
524
  }
512
525
  }
513
526
 
514
527
  /**
515
- * !!!@@@
528
+ * Helper used in catch blocks to assert that the error is an instance of `Error`
516
529
  *
517
- * @param whatWasThrown !!!@@@
518
- * @returns !!!@@@
530
+ * @param whatWasThrown Any object that was thrown
531
+ * @returns Nothing if the error is an instance of `Error`
532
+ * @throws `WrappedError` or `UnexpectedError` if the error is not standard
519
533
  *
520
534
  * @private within the repository
521
535
  */
522
536
  function assertsError(whatWasThrown) {
523
- // Case 1: !!!@@@
537
+ // Case 1: Handle error which was rethrown as `WrappedError`
524
538
  if (whatWasThrown instanceof WrappedError) {
525
539
  const wrappedError = whatWasThrown;
526
540
  throw wrappedError;
527
541
  }
528
- // Case 2: !!!@@@
542
+ // Case 2: Handle unexpected errors
529
543
  if (whatWasThrown instanceof UnexpectedError) {
530
544
  const unexpectedError = whatWasThrown;
531
545
  throw unexpectedError;
532
546
  }
533
- // Case 3: !!!@@@
547
+ // Case 3: Handle standard errors - keep them up to consumer
534
548
  if (whatWasThrown instanceof Error) {
535
549
  return;
536
550
  }
537
- // Case 4: !!!@@@
551
+ // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
538
552
  throw new WrappedError(whatWasThrown);
539
553
  }
540
554
 
@@ -978,6 +992,40 @@
978
992
  keepUnused(...sideEffectSubjects);
979
993
  }
980
994
 
995
+ /**
996
+ * Convert identification to Promptbook token
997
+ *
998
+ * @param identification
999
+ *
1000
+ * @public exported from `@promptbook/core`
1001
+ */
1002
+ function identificationToPromptbookToken(identification) {
1003
+ const { appId, userId, userToken } = identification;
1004
+ const promptbookToken = `${appId}-${userId}-${userToken}`;
1005
+ return promptbookToken;
1006
+ }
1007
+
1008
+ /**
1009
+ * Convert Promptbook token to identification
1010
+ *
1011
+ * @param promptbookToken
1012
+ *
1013
+ * @public exported from `@promptbook/core`
1014
+ */
1015
+ function promptbookTokenToIdentification(promptbookToken) {
1016
+ const [appId, userId, userToken] = promptbookToken.split('-');
1017
+ if (!appId || !userId || !userToken) {
1018
+ throw new Error(`Invalid promptbook token: ${promptbookToken}`);
1019
+ }
1020
+ const identification = {
1021
+ appId,
1022
+ userId,
1023
+ userToken,
1024
+ isAnonymous: false,
1025
+ };
1026
+ return identification;
1027
+ }
1028
+
981
1029
  /**
982
1030
  * Just marks a place of place where should be something implemented
983
1031
  * No side effects.
@@ -1103,7 +1151,7 @@
1103
1151
  */
1104
1152
 
1105
1153
  /**
1106
- * Stores data in .env variables (Remove !!! nonce 1)
1154
+ * Stores data in .env variables
1107
1155
  *
1108
1156
  * Note: `$` is used to indicate that this function is not a pure function - it uses filesystem to access `.env` file and also writes to `process.env`
1109
1157
  *
@@ -1161,15 +1209,19 @@
1161
1209
  async setItem(key, value) {
1162
1210
  const envFilename = await this.$provideOrCreateEnvFile();
1163
1211
  const envContent = await promises.readFile(envFilename, 'utf-8');
1212
+ const transformedKey = this.transformKey(key);
1213
+ const updatedEnvContent = envContent
1214
+ .split('\n')
1215
+ .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
1216
+ .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
1217
+ .join('\n');
1164
1218
  const newEnvContent = spaceTrim__default["default"]((block) => `
1165
- ${block(envContent)}
1166
-
1167
- # Note: Added by Promptbook
1168
- ${this.transformKey(key)}=${JSON.stringify(value)}
1219
+ ${block(updatedEnvContent)}
1169
1220
 
1221
+ # ${GENERATOR_WARNING_IN_ENV}
1222
+ ${transformedKey}=${JSON.stringify(value)}
1170
1223
  `);
1171
- // <- TODO: !!! Add note and use spacetrim
1172
- promises.writeFile(envFilename, newEnvContent, 'utf-8');
1224
+ await promises.writeFile(envFilename, newEnvContent, 'utf-8');
1173
1225
  }
1174
1226
  /**
1175
1227
  * Removes the key/value pair with the given key from the list associated with the object, if a key/value pair with the given key exists.
@@ -1178,6 +1230,9 @@
1178
1230
  throw new NotYetImplementedError('Method `$EnvStorage.removeItem` not implemented.');
1179
1231
  }
1180
1232
  }
1233
+ /**
1234
+ * TODO: Write file more securely - ensure that there can be no accidental overwriting of existing variables and other content
1235
+ */
1181
1236
 
1182
1237
  /**
1183
1238
  * Orders JSON object by keys
@@ -2226,7 +2281,7 @@
2226
2281
  }
2227
2282
  }
2228
2283
  /**
2229
- * TODO: !!!!!! Add id to all errors
2284
+ * TODO: [🧠][🌂] Add id to all errors
2230
2285
  */
2231
2286
 
2232
2287
  /**
@@ -3168,19 +3223,27 @@
3168
3223
  throw new EnvironmentMismatchError('Function `$provideLlmToolsForWizzardOrCli` works only in Node.js environment');
3169
3224
  }
3170
3225
  options = options !== null && options !== void 0 ? options : { strategy: 'BRING_YOUR_OWN_KEYS' };
3171
- const { strategy, isCacheReloaded } = options;
3226
+ const { isLoginloaded, strategy, isCacheReloaded } = options;
3172
3227
  let llmExecutionTools;
3173
3228
  if (strategy === 'REMOTE_SERVER') {
3174
3229
  const { remoteServerUrl = DEFAULT_REMOTE_SERVER_URL, loginPrompt } = options;
3175
- const storage = new $EnvStorage(); // <- TODO: !!!!!! Save to `.promptbook` folder
3230
+ const storage = new $EnvStorage();
3176
3231
  let key = `PROMPTBOOK_TOKEN`;
3177
3232
  if (remoteServerUrl !== DEFAULT_REMOTE_SERVER_URL) {
3178
3233
  key = `${key}_${remoteServerUrl.replace(/^https?:\/\//i, '')}`;
3179
3234
  }
3180
- let identification = await storage.getItem(key);
3181
- if (identification === null) {
3235
+ let identification = null;
3236
+ let promptbookToken = await storage.getItem(key);
3237
+ if (promptbookToken === null || isLoginloaded) {
3182
3238
  identification = await loginPrompt();
3183
- await storage.setItem(key, identification);
3239
+ // Note: When login prompt fails, `process.exit(1)` is called so no need to check for null
3240
+ if (identification.isAnonymous === false) {
3241
+ promptbookToken = identificationToPromptbookToken(identification);
3242
+ await storage.setItem(key, promptbookToken);
3243
+ }
3244
+ }
3245
+ else {
3246
+ identification = promptbookTokenToIdentification(promptbookToken);
3184
3247
  }
3185
3248
  llmExecutionTools = new RemoteLlmExecutionTools({
3186
3249
  remoteServerUrl,
@@ -3260,8 +3323,8 @@
3260
3323
  /**
3261
3324
  * @private utility of CLI
3262
3325
  */
3263
- function $provideLlmToolsForCli(options) {
3264
- const { cliOptions: {
3326
+ async function $provideLlmToolsForCli(options) {
3327
+ const { isLoginloaded, cliOptions: {
3265
3328
  /* TODO: Use verbose: isVerbose, */ interactive: isInteractive, provider, remoteServerUrl: remoteServerUrlRaw, }, } = options;
3266
3329
  let strategy;
3267
3330
  if (/^b/i.test(provider)) {
@@ -3275,7 +3338,11 @@
3275
3338
  process.exit(1);
3276
3339
  }
3277
3340
  if (strategy === 'BRING_YOUR_OWN_KEYS') {
3278
- return /* not await */ $provideLlmToolsForWizzardOrCli({ strategy, ...options });
3341
+ if (isLoginloaded) {
3342
+ throw new UnexpectedError(`\`$provideLlmToolsForCli\` isLoginloaded is not supported for strategy "BRING_YOUR_OWN_KEYS"`);
3343
+ }
3344
+ const llm = await $provideLlmToolsForWizzardOrCli({ strategy, ...options });
3345
+ return { strategy, llm };
3279
3346
  }
3280
3347
  else if (strategy === 'REMOTE_SERVER') {
3281
3348
  if (!isValidUrl(remoteServerUrlRaw)) {
@@ -3283,7 +3350,8 @@
3283
3350
  process.exit(1);
3284
3351
  }
3285
3352
  const remoteServerUrl = remoteServerUrlRaw.endsWith('/') ? remoteServerUrlRaw.slice(0, -1) : remoteServerUrlRaw;
3286
- return /* not await */ $provideLlmToolsForWizzardOrCli({
3353
+ const llm = await $provideLlmToolsForWizzardOrCli({
3354
+ isLoginloaded,
3287
3355
  strategy,
3288
3356
  appId: CLI_APP_ID,
3289
3357
  remoteServerUrl,
@@ -3293,6 +3361,10 @@
3293
3361
  console.log(colors__default["default"].red(`You can not login to remote server in non-interactive mode`));
3294
3362
  process.exit(1);
3295
3363
  }
3364
+ console.info(colors__default["default"].cyan(spaceTrim__default["default"](`
3365
+ You will be logged in to ${remoteServerUrl}
3366
+ If you don't have an account, it will be created automatically.
3367
+ `)));
3296
3368
  const { username, password } = await prompts__default["default"]([
3297
3369
  {
3298
3370
  type: 'text',
@@ -3310,7 +3382,6 @@
3310
3382
  },
3311
3383
  ]);
3312
3384
  const loginUrl = `${remoteServerUrl}/login`;
3313
- console.log('!!!', { loginUrl });
3314
3385
  // TODO: [🧠] Should we use normal `fetch` or `scraperFetch`
3315
3386
  const response = await promptbookFetch(loginUrl, {
3316
3387
  method: 'POST',
@@ -3323,20 +3394,7 @@
3323
3394
  password,
3324
3395
  }),
3325
3396
  });
3326
- console.log('!!!', {
3327
- loginUrl,
3328
- username,
3329
- password,
3330
- // type: response.type,
3331
- // text: await response.text(),
3332
- });
3333
3397
  const { isSuccess, message, error, identification } = (await response.json());
3334
- console.log('!!!', {
3335
- isSuccess,
3336
- message,
3337
- error,
3338
- identification,
3339
- });
3340
3398
  if (message) {
3341
3399
  if (isSuccess) {
3342
3400
  console.log(colors__default["default"].green(message));
@@ -3357,6 +3415,7 @@
3357
3415
  return identification;
3358
3416
  },
3359
3417
  });
3418
+ return { strategy, llm };
3360
3419
  }
3361
3420
  else {
3362
3421
  throw new UnexpectedError(`\`$provideLlmToolsForCli\` wrong strategy "${strategy}"`);
@@ -3378,11 +3437,12 @@
3378
3437
  listModelsCommand.alias('models');
3379
3438
  listModelsCommand.alias('llm');
3380
3439
  listModelsCommand.action(handleActionErrors(async (cliOptions) => {
3381
- console.log('!!!', cliOptions);
3382
- // TODO: !!!!!! Not relevant for remote server and also for `about` command
3383
- const llm = await $provideLlmToolsForCli({ cliOptions });
3440
+ const { strategy, llm } = await $provideLlmToolsForCli({ cliOptions });
3384
3441
  $sideEffect(llm);
3385
3442
  // <- Note: Providing LLM tools will make a side effect of registering all available LLM tools to show the message
3443
+ if (strategy !== 'BRING_YOUR_OWN_KEYS') {
3444
+ console.warn(colors__default["default"].yellow(`You are using --strategy ${strategy} but models listed below are relevant for --strategy BRING_YOUR_OWN_KEYS`));
3445
+ }
3386
3446
  console.info($registeredLlmToolsMessage());
3387
3447
  return process.exit(0);
3388
3448
  }));
@@ -3910,6 +3970,7 @@
3910
3970
  `));
3911
3971
  listModelsCommand.alias('scrapers');
3912
3972
  listModelsCommand.action(handleActionErrors(async () => {
3973
+ // TODO: [🌞] Do not allow on REMOTE_SERVER strategy
3913
3974
  const scrapers = await $provideScrapersForNode({});
3914
3975
  const executables = await $provideExecutablesForNode();
3915
3976
  console.info(spaceTrim__default["default"]((block) => `
@@ -3945,42 +4006,20 @@
3945
4006
  loginCommand.description(spaceTrim__default["default"](`
3946
4007
  Login to the remote Promptbook server
3947
4008
  `));
3948
- loginCommand.action(handleActionErrors(async () => {
3949
- // @@@
3950
- console.error(colors__default["default"].green(spaceTrim__default["default"](`
3951
- You will be logged in to https://promptbook.studio server.
3952
- If you don't have an account, it will be created automatically.
3953
- `)));
3954
- // !!!!!!!!! Remove from here and use $provideLlmToolsForCli
3955
- const { email, password } = await prompts__default["default"]([
3956
- {
3957
- type: 'text',
3958
- name: 'email',
3959
- message: 'Enter your email:',
3960
- validate: (value) => (isValidEmail(value) ? true : 'Valid email is required'),
4009
+ loginCommand.action(handleActionErrors(async (cliOptions) => {
4010
+ // Note: Not interested in return value of this function but the side effect of logging in
4011
+ await $provideLlmToolsForCli({
4012
+ isLoginloaded: true,
4013
+ cliOptions: {
4014
+ ...cliOptions,
4015
+ strategy: 'REMOTE_SERVER', // <- Note: Overriding strategy to `REMOTE_SERVER`
4016
+ // TODO: Do not allow flag `--strategy` in `login` command at all
3961
4017
  },
3962
- {
3963
- type: 'password',
3964
- name: 'password',
3965
- message: 'Enter your password:',
3966
- validate: (value) => value.length /* <- TODO: [🧠] Better password validation */ > 0 ? true : 'Password is required',
3967
- },
3968
- ]);
3969
- TODO_USE(email, password);
3970
- await waitasecond.forTime(1000);
3971
- console.error(colors__default["default"].green(spaceTrim__default["default"](`
3972
- Your account ${email} was successfully created.
3973
-
3974
- Please verify your email:
3975
- https://brj.app/api/v1/customer/register-account?apiKey=PRODdh003eNKaec7PoO1AzU244tsL4WO
3976
-
3977
- After verification, you will receive 500 000 credits for free 🎉
3978
- `)));
4018
+ });
3979
4019
  return process.exit(0);
3980
4020
  }));
3981
4021
  }
3982
4022
  /**
3983
- * TODO: Pass remote server URL (and path)
3984
4023
  * TODO: Implement non-interactive login
3985
4024
  * Note: [💞] Ignore a discrepancy between file name and entity name
3986
4025
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
@@ -4940,8 +4979,8 @@
4940
4979
  updatedAt = new Date();
4941
4980
  errors.push(...executionResult.errors);
4942
4981
  warnings.push(...executionResult.warnings);
4943
- // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
4944
- // TODO: [🧠] !!! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
4982
+ // <- TODO: [🌂] Only unique errors and warnings should be added (or filtered)
4983
+ // TODO: [🧠] !! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
4945
4984
  // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
4946
4985
  // And delete `ExecutionTask.currentValue.preparedPipeline`
4947
4986
  assertsTaskSuccessful(executionResult);
@@ -11938,7 +11977,7 @@
11938
11977
  isCacheReloaded,
11939
11978
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
11940
11979
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
11941
- const llm = await $provideLlmToolsForCli({
11980
+ const { llm } = await $provideLlmToolsForCli({
11942
11981
  cliOptions,
11943
11982
  ...prepareAndScrapeOptions,
11944
11983
  });
@@ -12809,7 +12848,6 @@
12809
12848
  runCommand.option('-j, --json <json>', `Pass all or some input parameters as JSON record, if used the output is also returned as JSON`);
12810
12849
  runCommand.option('-s, --save-report <path>', `Save report to file`);
12811
12850
  runCommand.action(handleActionErrors(async (pipelineSource, cliOptions) => {
12812
- console.log('!!!', cliOptions);
12813
12851
  const { reload: isCacheReloaded, interactive: isInteractive, formfactor: isFormfactorUsed, json, verbose: isVerbose, saveReport, } = cliOptions;
12814
12852
  if (pipelineSource.includes('-') && normalizeToKebabCase(pipelineSource) === pipelineSource) {
12815
12853
  console.error(colors__default["default"].red(`""${pipelineSource}" is not a valid command or book. See 'ptbk --help'.`));
@@ -12835,7 +12873,7 @@
12835
12873
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
12836
12874
  let llm;
12837
12875
  try {
12838
- llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
12876
+ llm = (await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions })).llm;
12839
12877
  }
12840
12878
  catch (error) {
12841
12879
  assertsError(error);
@@ -13727,7 +13765,7 @@
13727
13765
  isCacheReloaded,
13728
13766
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13729
13767
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13730
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13768
+ const { /* [0] strategy,*/ llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13731
13769
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13732
13770
  const tools = {
13733
13771
  llm,
@@ -13759,6 +13797,7 @@
13759
13797
  TODO_USE({ appId, userId });
13760
13798
  return llm;
13761
13799
  },
13800
+ // <- TODO: [🧠][0] Maybe pass here strategy
13762
13801
  });
13763
13802
  keepUnused(server);
13764
13803
  // Note: Already logged by `startRemoteServer`
@@ -13800,7 +13839,7 @@
13800
13839
  isCacheReloaded,
13801
13840
  }; /* <- TODO: ` satisfies PrepareAndScrapeOptions` */
13802
13841
  const fs = $provideFilesystemForNode(prepareAndScrapeOptions);
13803
- const llm = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13842
+ const { llm } = await $provideLlmToolsForCli({ cliOptions, ...prepareAndScrapeOptions });
13804
13843
  const executables = await $provideExecutablesForNode(prepareAndScrapeOptions);
13805
13844
  tools = {
13806
13845
  llm,