@promptbook/cli 0.85.0-1 โ†’ 0.85.0-10

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.
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  // <- TODO: [๐ŸŽบ] Ensure correct version of Node.js is used
3
+ // promptbook-cli.js
3
4
 
4
5
  /**
5
6
  * Note: [๐Ÿ”บ] Purpose of this file is to run CLI in production environment
@@ -11,6 +12,6 @@ const { _CLI } = require('../umd/index.umd.js');
11
12
  _CLI._initialize_promptbookCli();
12
13
 
13
14
  /**
14
- * TODO: !!! During the build check that this file exists
15
+ * TODO: [๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ฆ] During the build check that this file exists
15
16
  * TODO: [๐Ÿ•Œ] When more functionalities, rename
16
17
  */
package/esm/index.es.js CHANGED
@@ -1,16 +1,16 @@
1
1
  import colors from 'colors';
2
2
  import commander from 'commander';
3
3
  import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
- import { forTime } from 'waitasecond';
5
- import { basename, join, dirname } from 'node:path';
6
- import { stat, access, constants, readFile, writeFile, readdir, mkdir, unlink, rm, rmdir, rename } from 'node:fs/promises';
4
+ import { forTime, forEver } from 'waitasecond';
5
+ import { basename, join, dirname } from 'path';
6
+ import { stat, access, constants, readFile, writeFile, readdir, mkdir, unlink, rm, rmdir, rename } from 'fs/promises';
7
7
  import hexEncoder from 'crypto-js/enc-hex';
8
8
  import sha256 from 'crypto-js/sha256';
9
9
  import * as dotenv from 'dotenv';
10
- import { spawn } from 'node:child_process';
10
+ import { spawn } from 'child_process';
11
11
  import { format } from 'prettier';
12
12
  import parserHtml from 'prettier/parser-html';
13
- import { BehaviorSubject, concat, from } from 'rxjs';
13
+ import { BehaviorSubject } from 'rxjs';
14
14
  import { randomBytes } from 'crypto';
15
15
  import { unparse, parse } from 'papaparse';
16
16
  import { SHA256 } from 'crypto-js';
@@ -19,7 +19,7 @@ import glob from 'glob-promise';
19
19
  import prompts from 'prompts';
20
20
  import moment from 'moment';
21
21
  import express from 'express';
22
- import http from 'node:http';
22
+ import http from 'http';
23
23
  import { Server } from 'socket.io';
24
24
  import { io } from 'socket.io-client';
25
25
  import Anthropic from '@anthropic-ai/sdk';
@@ -43,7 +43,7 @@ var BOOK_LANGUAGE_VERSION = '1.0.0';
43
43
  * @generated
44
44
  * @see https://github.com/webgptorg/promptbook
45
45
  */
46
- var PROMPTBOOK_ENGINE_VERSION = '0.85.0-0';
46
+ var PROMPTBOOK_ENGINE_VERSION = '0.85.0-9';
47
47
  /**
48
48
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
49
49
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
@@ -533,7 +533,6 @@ function $initializeAboutCommand(program) {
533
533
  }); });
534
534
  }
535
535
  /**
536
- * TODO: !!! Test this in `deno`
537
536
  * TODO: [๐Ÿ—ฝ] Unite branding and make single place for it
538
537
  * Note: [๐Ÿ’ž] Ignore a discrepancy between file name and entity name
539
538
  * Note: [๐ŸŸก] Code in this file should never be published outside of `@promptbook/cli`
@@ -4920,11 +4919,27 @@ function assertsTaskSuccessful(executionResult) {
4920
4919
  */
4921
4920
  function createTask(options) {
4922
4921
  var taskType = options.taskType, taskProcessCallback = options.taskProcessCallback;
4923
- var taskId = "".concat(taskType.toLowerCase(), "-").concat($randomToken(256 /* <- TODO: !!! To global config */));
4922
+ var taskId = "".concat(taskType.toLowerCase().substring(0, 4), "-").concat($randomToken(8 /* <- TODO: To global config + Use Base58 to avoid simmilar char conflicts */));
4924
4923
  var partialResultSubject = new BehaviorSubject({});
4925
4924
  var finalResultPromise = /* not await */ taskProcessCallback(function (newOngoingResult) {
4926
4925
  partialResultSubject.next(newOngoingResult);
4927
4926
  });
4927
+ finalResultPromise
4928
+ .catch(function (error) {
4929
+ partialResultSubject.error(error);
4930
+ })
4931
+ .then(function (value) {
4932
+ if (value) {
4933
+ try {
4934
+ assertsTaskSuccessful(value);
4935
+ partialResultSubject.next(value);
4936
+ }
4937
+ catch (error) {
4938
+ partialResultSubject.error(error);
4939
+ }
4940
+ }
4941
+ partialResultSubject.complete();
4942
+ });
4928
4943
  function asPromise(options) {
4929
4944
  return __awaiter(this, void 0, void 0, function () {
4930
4945
  var _a, isCrashedOnError, finalResult;
@@ -4948,9 +4963,10 @@ function createTask(options) {
4948
4963
  taskId: taskId,
4949
4964
  asPromise: asPromise,
4950
4965
  asObservable: function () {
4951
- return concat(partialResultSubject.asObservable(), from(asPromise({
4952
- isCrashedOnError: true,
4953
- })));
4966
+ return partialResultSubject.asObservable();
4967
+ },
4968
+ get currentValue() {
4969
+ return partialResultSubject.value;
4954
4970
  },
4955
4971
  };
4956
4972
  }
@@ -11416,6 +11432,17 @@ function normalizeWhitespaces(sentence) {
11416
11432
  return sentence.replace(/\s+/gs, ' ').trim();
11417
11433
  }
11418
11434
 
11435
+ /**
11436
+ * Adds suffix to the URL
11437
+ *
11438
+ * @public exported from `@promptbook/utils`
11439
+ */
11440
+ function suffixUrl(value, suffix) {
11441
+ var baseUrl = value.href.endsWith('/') ? value.href.slice(0, -1) : value.href;
11442
+ var normalizedSuffix = suffix.replace(/\/+/g, '/');
11443
+ return (baseUrl + normalizedSuffix);
11444
+ }
11445
+
11419
11446
  /**
11420
11447
  * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
11421
11448
  *
@@ -13764,6 +13791,57 @@ function startRemoteServer(options) {
13764
13791
  .filter(function (part) { return part !== ''; })
13765
13792
  .join('/');
13766
13793
  var startupDate = new Date();
13794
+ function getExecutionToolsFromIdentification(identification) {
13795
+ return __awaiter(this, void 0, void 0, function () {
13796
+ var isAnonymous, llm, llmToolsConfiguration, appId, userId, customOptions, fs, executables, tools;
13797
+ var _a;
13798
+ return __generator(this, function (_b) {
13799
+ switch (_b.label) {
13800
+ case 0:
13801
+ if (identification === null || identification === undefined) {
13802
+ throw new Error("Identification is not provided");
13803
+ }
13804
+ isAnonymous = identification.isAnonymous;
13805
+ if (isAnonymous === true && !isAnonymousModeAllowed) {
13806
+ throw new PipelineExecutionError("Anonymous mode is not allowed"); // <- TODO: [main] !!3 Test
13807
+ }
13808
+ if (isAnonymous === false && !isApplicationModeAllowed) {
13809
+ throw new PipelineExecutionError("Application mode is not allowed"); // <- TODO: [main] !!3 Test
13810
+ }
13811
+ if (!(isAnonymous === true)) return [3 /*break*/, 1];
13812
+ llmToolsConfiguration = identification.llmToolsConfiguration;
13813
+ llm = createLlmToolsFromConfiguration(llmToolsConfiguration, { isVerbose: isVerbose });
13814
+ return [3 /*break*/, 4];
13815
+ case 1:
13816
+ if (!(isAnonymous === false && createLlmExecutionTools !== null)) return [3 /*break*/, 3];
13817
+ appId = identification.appId, userId = identification.userId, customOptions = identification.customOptions;
13818
+ return [4 /*yield*/, createLlmExecutionTools({
13819
+ appId: appId,
13820
+ userId: userId,
13821
+ customOptions: customOptions,
13822
+ })];
13823
+ case 2:
13824
+ llm = _b.sent();
13825
+ return [3 /*break*/, 4];
13826
+ case 3: throw new PipelineExecutionError("You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured");
13827
+ case 4:
13828
+ fs = $provideFilesystemForNode();
13829
+ return [4 /*yield*/, $provideExecutablesForNode()];
13830
+ case 5:
13831
+ executables = _b.sent();
13832
+ _a = {
13833
+ llm: llm,
13834
+ fs: fs
13835
+ };
13836
+ return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables })];
13837
+ case 6:
13838
+ tools = (_a.scrapers = _b.sent(),
13839
+ _a);
13840
+ return [2 /*return*/, tools];
13841
+ }
13842
+ });
13843
+ });
13844
+ }
13767
13845
  var app = express();
13768
13846
  app.use(express.json());
13769
13847
  app.use(function (request, response, next) {
@@ -13771,7 +13849,7 @@ function startRemoteServer(options) {
13771
13849
  next();
13772
13850
  });
13773
13851
  var runningExecutionTasks = [];
13774
- // TODO: !!!!!! Do here some garbage collection of finished tasks
13852
+ // TODO: [๐Ÿง ] Do here some garbage collection of finished tasks
13775
13853
  app.get(['/', rootPath], function (request, response) { return __awaiter(_this, void 0, void 0, function () {
13776
13854
  var _a, _b;
13777
13855
  var _this = this;
@@ -13820,20 +13898,19 @@ function startRemoteServer(options) {
13820
13898
  });
13821
13899
  }); });
13822
13900
  app.get("".concat(rootPath, "/books"), function (request, response) { return __awaiter(_this, void 0, void 0, function () {
13823
- var _a, _b, _c;
13824
- return __generator(this, function (_d) {
13825
- switch (_d.label) {
13901
+ var pipelines;
13902
+ return __generator(this, function (_a) {
13903
+ switch (_a.label) {
13826
13904
  case 0:
13827
- _b = (_a = response).send;
13828
- if (!(collection === null)) return [3 /*break*/, 1];
13829
- _c = [];
13830
- return [3 /*break*/, 3];
13831
- case 1: return [4 /*yield*/, collection.listPipelines()];
13832
- case 2:
13833
- _c = _d.sent();
13834
- _d.label = 3;
13835
- case 3:
13836
- _b.apply(_a, [_c]);
13905
+ if (collection === null) {
13906
+ response.status(500).send('No collection available');
13907
+ return [2 /*return*/];
13908
+ }
13909
+ return [4 /*yield*/, collection.listPipelines()];
13910
+ case 1:
13911
+ pipelines = _a.sent();
13912
+ // <- TODO: [๐Ÿง ][๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿง‘๐Ÿฟ] List `inputParameters` required for the execution
13913
+ response.send(pipelines);
13837
13914
  return [2 /*return*/];
13838
13915
  }
13839
13916
  });
@@ -13847,23 +13924,23 @@ function startRemoteServer(options) {
13847
13924
  app.get("".concat(rootPath, "/executions/:taskId"), function (request, response) { return __awaiter(_this, void 0, void 0, function () {
13848
13925
  var taskId, execution;
13849
13926
  return __generator(this, function (_a) {
13850
- taskId = request.query.taskId;
13927
+ taskId = request.params.taskId;
13851
13928
  execution = runningExecutionTasks.find(function (executionTask) { return executionTask.taskId === taskId; });
13852
13929
  if (execution === undefined) {
13853
13930
  response.status(404).send("Execution \"".concat(taskId, "\" not found"));
13854
13931
  return [2 /*return*/];
13855
13932
  }
13856
- response.send(execution);
13933
+ response.send(execution.currentValue);
13857
13934
  return [2 /*return*/];
13858
13935
  });
13859
13936
  }); });
13860
13937
  app.post("".concat(rootPath, "/executions/new"), function (request, response) { return __awaiter(_this, void 0, void 0, function () {
13861
- var inputParameters, pipelineUrl, pipeline, llm, fs, executables, tools, pipelineExecutor, executionTask;
13862
- var _a;
13938
+ var _a, inputParameters, identification, pipelineUrl, pipeline, tools, pipelineExecutor, executionTask, error_1;
13863
13939
  return __generator(this, function (_b) {
13864
13940
  switch (_b.label) {
13865
13941
  case 0:
13866
- inputParameters = request.body.inputParameters;
13942
+ _b.trys.push([0, 4, , 5]);
13943
+ _a = request.body, inputParameters = _a.inputParameters, identification = _a.identification;
13867
13944
  pipelineUrl = request.body.pipelineUrl || request.body.book;
13868
13945
  return [4 /*yield*/, (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl))];
13869
13946
  case 1:
@@ -13872,30 +13949,27 @@ function startRemoteServer(options) {
13872
13949
  response.status(404).send("Pipeline \"".concat(pipelineUrl, "\" not found"));
13873
13950
  return [2 /*return*/];
13874
13951
  }
13875
- return [4 /*yield*/, createLlmExecutionTools({
13876
- appId: '!!!!',
13877
- userId: '!!!!',
13878
- customOptions: {},
13879
- })];
13952
+ return [4 /*yield*/, getExecutionToolsFromIdentification(identification)];
13880
13953
  case 2:
13881
- llm = _b.sent();
13882
- fs = $provideFilesystemForNode();
13883
- return [4 /*yield*/, $provideExecutablesForNode()];
13884
- case 3:
13885
- executables = _b.sent();
13886
- _a = {
13887
- llm: llm,
13888
- fs: fs
13889
- };
13890
- return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables })];
13891
- case 4:
13892
- tools = (_a.scrapers = _b.sent(),
13893
- _a);
13954
+ tools = _b.sent();
13894
13955
  pipelineExecutor = createPipelineExecutor(__assign({ pipeline: pipeline, tools: tools }, options));
13895
13956
  executionTask = pipelineExecutor(inputParameters);
13896
13957
  runningExecutionTasks.push(executionTask);
13958
+ return [4 /*yield*/, forTime(10)];
13959
+ case 3:
13960
+ _b.sent();
13961
+ // <- Note: Wait for a while to wait for quick responses or sudden but asynchronous errors
13962
+ // <- TODO: Put this into configuration
13897
13963
  response.send(executionTask);
13898
- return [2 /*return*/];
13964
+ return [3 /*break*/, 5];
13965
+ case 4:
13966
+ error_1 = _b.sent();
13967
+ if (!(error_1 instanceof Error)) {
13968
+ throw error_1;
13969
+ }
13970
+ response.status(400).send({ error: serializeError(error_1) });
13971
+ return [3 /*break*/, 5];
13972
+ case 5: return [2 /*return*/];
13899
13973
  }
13900
13974
  });
13901
13975
  }); });
@@ -13912,55 +13986,9 @@ function startRemoteServer(options) {
13912
13986
  if (isVerbose) {
13913
13987
  console.info(colors.gray("Client connected"), socket.id);
13914
13988
  }
13915
- var getExecutionToolsFromIdentification = function (identification) { return __awaiter(_this, void 0, void 0, function () {
13916
- var isAnonymous, llm, llmToolsConfiguration, appId, userId, customOptions, fs, executables, tools;
13917
- var _a;
13918
- return __generator(this, function (_b) {
13919
- switch (_b.label) {
13920
- case 0:
13921
- isAnonymous = identification.isAnonymous;
13922
- if (isAnonymous === true && !isAnonymousModeAllowed) {
13923
- throw new PipelineExecutionError("Anonymous mode is not allowed"); // <- TODO: [main] !!3 Test
13924
- }
13925
- if (isAnonymous === false && !isApplicationModeAllowed) {
13926
- throw new PipelineExecutionError("Application mode is not allowed"); // <- TODO: [main] !!3 Test
13927
- }
13928
- if (!(isAnonymous === true)) return [3 /*break*/, 1];
13929
- llmToolsConfiguration = identification.llmToolsConfiguration;
13930
- llm = createLlmToolsFromConfiguration(llmToolsConfiguration, { isVerbose: isVerbose });
13931
- return [3 /*break*/, 4];
13932
- case 1:
13933
- if (!(isAnonymous === false && createLlmExecutionTools !== null)) return [3 /*break*/, 3];
13934
- appId = identification.appId, userId = identification.userId, customOptions = identification.customOptions;
13935
- return [4 /*yield*/, createLlmExecutionTools({
13936
- appId: appId,
13937
- userId: userId,
13938
- customOptions: customOptions,
13939
- })];
13940
- case 2:
13941
- llm = _b.sent();
13942
- return [3 /*break*/, 4];
13943
- case 3: throw new PipelineExecutionError("You must provide either llmToolsConfiguration or non-anonymous mode must be propperly configured");
13944
- case 4:
13945
- fs = $provideFilesystemForNode();
13946
- return [4 /*yield*/, $provideExecutablesForNode()];
13947
- case 5:
13948
- executables = _b.sent();
13949
- _a = {
13950
- llm: llm,
13951
- fs: fs
13952
- };
13953
- return [4 /*yield*/, $provideScrapersForNode({ fs: fs, llm: llm, executables: executables })];
13954
- case 6:
13955
- tools = (_a.scrapers = _b.sent(),
13956
- _a);
13957
- return [2 /*return*/, tools];
13958
- }
13959
- });
13960
- }); };
13961
13989
  // -----------
13962
13990
  socket.on('prompt-request', function (request) { return __awaiter(_this, void 0, void 0, function () {
13963
- var identification, prompt, executionTools, llm, _a, promptResult, _b, error_1;
13991
+ var identification, prompt, tools, llm, _a, promptResult, _b, error_2;
13964
13992
  return __generator(this, function (_c) {
13965
13993
  switch (_c.label) {
13966
13994
  case 0:
@@ -13973,8 +14001,8 @@ function startRemoteServer(options) {
13973
14001
  _c.trys.push([1, 13, 14, 15]);
13974
14002
  return [4 /*yield*/, getExecutionToolsFromIdentification(identification)];
13975
14003
  case 2:
13976
- executionTools = _c.sent();
13977
- llm = executionTools.llm;
14004
+ tools = _c.sent();
14005
+ llm = tools.llm;
13978
14006
  _a = identification.isAnonymous === false &&
13979
14007
  collection !== null;
13980
14008
  if (!_a) return [3 /*break*/, 4];
@@ -14029,11 +14057,11 @@ function startRemoteServer(options) {
14029
14057
  socket.emit('prompt-response', { promptResult: promptResult } /* <- Note: [๐Ÿค›] */);
14030
14058
  return [3 /*break*/, 15];
14031
14059
  case 13:
14032
- error_1 = _c.sent();
14033
- if (!(error_1 instanceof Error)) {
14034
- throw error_1;
14060
+ error_2 = _c.sent();
14061
+ if (!(error_2 instanceof Error)) {
14062
+ throw error_2;
14035
14063
  }
14036
- socket.emit('error', serializeError(error_1) /* <- Note: [๐Ÿค›] */);
14064
+ socket.emit('error', serializeError(error_2) /* <- Note: [๐Ÿค›] */);
14037
14065
  return [3 /*break*/, 15];
14038
14066
  case 14:
14039
14067
  socket.disconnect();
@@ -14045,7 +14073,7 @@ function startRemoteServer(options) {
14045
14073
  // -----------
14046
14074
  // TODO: [๐Ÿ‘’] Listing models (and checking configuration) probbably should go through REST API not Socket.io
14047
14075
  socket.on('listModels-request', function (request) { return __awaiter(_this, void 0, void 0, function () {
14048
- var identification, executionTools, llm, models, error_2;
14076
+ var identification, tools, llm, models, error_3;
14049
14077
  return __generator(this, function (_a) {
14050
14078
  switch (_a.label) {
14051
14079
  case 0:
@@ -14058,19 +14086,19 @@ function startRemoteServer(options) {
14058
14086
  _a.trys.push([1, 4, 5, 6]);
14059
14087
  return [4 /*yield*/, getExecutionToolsFromIdentification(identification)];
14060
14088
  case 2:
14061
- executionTools = _a.sent();
14062
- llm = executionTools.llm;
14089
+ tools = _a.sent();
14090
+ llm = tools.llm;
14063
14091
  return [4 /*yield*/, llm.listModels()];
14064
14092
  case 3:
14065
14093
  models = _a.sent();
14066
14094
  socket.emit('listModels-response', { models: models } /* <- Note: [๐Ÿค›] */);
14067
14095
  return [3 /*break*/, 6];
14068
14096
  case 4:
14069
- error_2 = _a.sent();
14070
- if (!(error_2 instanceof Error)) {
14071
- throw error_2;
14097
+ error_3 = _a.sent();
14098
+ if (!(error_3 instanceof Error)) {
14099
+ throw error_3;
14072
14100
  }
14073
- socket.emit('error', serializeError(error_2));
14101
+ socket.emit('error', serializeError(error_3));
14074
14102
  return [3 /*break*/, 6];
14075
14103
  case 5:
14076
14104
  socket.disconnect();
@@ -14082,7 +14110,7 @@ function startRemoteServer(options) {
14082
14110
  // -----------
14083
14111
  // TODO: [๐Ÿ‘’] Listing models (and checking configuration) probbably should go through REST API not Socket.io
14084
14112
  socket.on('preparePipeline-request', function (request) { return __awaiter(_this, void 0, void 0, function () {
14085
- var identification, pipeline, executionTools, preparedPipeline, error_3;
14113
+ var identification, pipeline, tools, preparedPipeline, error_4;
14086
14114
  return __generator(this, function (_a) {
14087
14115
  switch (_a.label) {
14088
14116
  case 0:
@@ -14095,18 +14123,18 @@ function startRemoteServer(options) {
14095
14123
  _a.trys.push([1, 4, 5, 6]);
14096
14124
  return [4 /*yield*/, getExecutionToolsFromIdentification(identification)];
14097
14125
  case 2:
14098
- executionTools = _a.sent();
14099
- return [4 /*yield*/, preparePipeline(pipeline, executionTools, options)];
14126
+ tools = _a.sent();
14127
+ return [4 /*yield*/, preparePipeline(pipeline, tools, options)];
14100
14128
  case 3:
14101
14129
  preparedPipeline = _a.sent();
14102
14130
  socket.emit('preparePipeline-response', { preparedPipeline: preparedPipeline } /* <- Note: [๐Ÿค›] */);
14103
14131
  return [3 /*break*/, 6];
14104
14132
  case 4:
14105
- error_3 = _a.sent();
14106
- if (!(error_3 instanceof Error)) {
14107
- throw error_3;
14133
+ error_4 = _a.sent();
14134
+ if (!(error_4 instanceof Error)) {
14135
+ throw error_4;
14108
14136
  }
14109
- socket.emit('error', serializeError(error_3));
14137
+ socket.emit('error', serializeError(error_4));
14110
14138
  return [3 /*break*/, 6];
14111
14139
  case 5:
14112
14140
  socket.disconnect();
@@ -14145,8 +14173,7 @@ function startRemoteServer(options) {
14145
14173
  };
14146
14174
  }
14147
14175
  /**
14148
- * TODO: !!!!!!! CORS and security
14149
- * TODO: !!!!!!! Allow to pass tokem here
14176
+ * TODO: !! Add CORS and security - probbably via `helmet`
14150
14177
  * TODO: [๐Ÿ‘ฉ๐Ÿพโ€๐Ÿคโ€๐Ÿง‘๐Ÿพ] Allow to pass custom fetch function here - PromptbookFetch
14151
14178
  * TODO: Split this file into multiple functions - handler for each request
14152
14179
  * TODO: Maybe use `$exportJson`
@@ -14174,19 +14201,40 @@ function $initializeStartServerCommand(program) {
14174
14201
  // <- TODO: [๐ŸงŸโ€โ™‚๏ธ] Unite path to promptbook collection argument
14175
14202
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
14176
14203
  startServerCommand.option('--port <port>', "Port to start the server on", '4460');
14204
+ startServerCommand.option('-u, --url <url>', spaceTrim("\n Public root url of the server\n It is used for following purposes:\n\n 1) It is suffixed with /books and used as rootUrl for all served books\n 2) Path (if not just /) is used as rootPath for the server\n "));
14177
14205
  startServerCommand.option('--allow-anonymous', "Is anonymous mode allowed", false);
14178
14206
  startServerCommand.option('-r, --reload', "Call LLM models even if same prompt with result is in the cache", false);
14179
14207
  startServerCommand.option('-v, --verbose', "Is output verbose", false);
14180
14208
  startServerCommand.description(spaceTrim("\n Starts a remote server to execute books\n "));
14181
14209
  startServerCommand.action(function (path, _a) {
14182
- var port = _a.port, isAnonymousModeAllowed = _a.allowAnonymous, isCacheReloaded = _a.reload, isVerbose = _a.verbose;
14210
+ var portRaw = _a.port, rawUrl = _a.url, isAnonymousModeAllowed = _a.allowAnonymous, isCacheReloaded = _a.reload, isVerbose = _a.verbose;
14183
14211
  return __awaiter(_this, void 0, void 0, function () {
14184
- var prepareAndScrapeOptions, fs, llm, executables, tools, collection;
14212
+ var port, url, rootUrl, rootPath, prepareAndScrapeOptions, fs, llm, executables, tools, collection;
14185
14213
  var _b;
14186
14214
  return __generator(this, function (_c) {
14187
14215
  switch (_c.label) {
14188
14216
  case 0:
14189
- console.log('startServerCommand.action', { port: port, isAnonymousModeAllowed: isAnonymousModeAllowed, isCacheReloaded: isCacheReloaded, isVerbose: isVerbose });
14217
+ if (rawUrl && !isValidUrl(rawUrl)) {
14218
+ console.error(colors.red("Invalid URL: ".concat(rawUrl)));
14219
+ return [2 /*return*/, process.exit(1)];
14220
+ }
14221
+ port = parseInt(portRaw, 10);
14222
+ if (isNaN(port) || port <= 0 || port > 65535) {
14223
+ console.error(colors.red("Invalid port number: ".concat(portRaw)));
14224
+ return [2 /*return*/, process.exit(1)];
14225
+ }
14226
+ url = !rawUrl ? null : new URL(rawUrl);
14227
+ if (url !== null && url.port !== port.toString()) {
14228
+ console.warn(colors.yellow("Port in --url is different from --port which the server will listen on, this is ok only if you proxy from one port to another, for exaple via nginx or docker"));
14229
+ }
14230
+ rootUrl = undefined;
14231
+ if (url !== null) {
14232
+ rootUrl = suffixUrl(url, '/books');
14233
+ }
14234
+ rootPath = '/';
14235
+ if (url !== null) {
14236
+ rootPath = url.pathname;
14237
+ }
14190
14238
  prepareAndScrapeOptions = {
14191
14239
  isVerbose: isVerbose,
14192
14240
  isCacheReloaded: isCacheReloaded,
@@ -14211,8 +14259,7 @@ function $initializeStartServerCommand(program) {
14211
14259
  _b);
14212
14260
  return [4 /*yield*/, createCollectionFromDirectory(path, tools, {
14213
14261
  isVerbose: isVerbose,
14214
- // TODO: [๐Ÿง ] Utilize implicit urls for books
14215
- // rootUrl: `http://localhost:${port}/books`,
14262
+ rootUrl: rootUrl,
14216
14263
  isRecursive: true,
14217
14264
  isLazyLoaded: false,
14218
14265
  isCrashedOnError: true,
@@ -14221,8 +14268,8 @@ function $initializeStartServerCommand(program) {
14221
14268
  case 4:
14222
14269
  collection = _c.sent();
14223
14270
  startRemoteServer({
14224
- rootPath: '/',
14225
- port: parseInt(port, 10),
14271
+ rootPath: rootPath,
14272
+ port: port,
14226
14273
  isAnonymousModeAllowed: isAnonymousModeAllowed,
14227
14274
  isApplicationModeAllowed: true,
14228
14275
  collection: collection,
@@ -14231,7 +14278,11 @@ function $initializeStartServerCommand(program) {
14231
14278
  return llm;
14232
14279
  },
14233
14280
  });
14234
- return [2 /*return*/];
14281
+ return [4 /*yield*/, forEver()];
14282
+ case 5:
14283
+ // Note: Already logged by `startRemoteServer`
14284
+ // console.error(colors.green(`Server started on port ${port}`));
14285
+ return [2 /*return*/, _c.sent()];
14235
14286
  }
14236
14287
  });
14237
14288
  });
@@ -15461,7 +15512,7 @@ var OPENAI_MODELS = exportJson({
15461
15512
  pricing: {
15462
15513
  prompt: computeUsage("$3.00 / 1M tokens"),
15463
15514
  output: computeUsage("$12.00 / 1M tokens"),
15464
- // <- TODO: !!! Unsure, check the pricing
15515
+ // <- TODO: !! Unsure, check the pricing
15465
15516
  },
15466
15517
  },
15467
15518
  /**/
@@ -15473,7 +15524,7 @@ var OPENAI_MODELS = exportJson({
15473
15524
  pricing: {
15474
15525
  prompt: computeUsage("$3.00 / 1M tokens"),
15475
15526
  output: computeUsage("$12.00 / 1M tokens"),
15476
- // <- TODO: !!! Unsure, check the pricing
15527
+ // <- TODO: !! Unsure, check the pricing
15477
15528
  },
15478
15529
  },
15479
15530
  /**/