@promptbook/remote-server 0.86.31 → 0.88.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.
package/esm/index.es.js CHANGED
@@ -7,7 +7,7 @@ import { forTime } from 'waitasecond';
7
7
  import { spawn } from 'child_process';
8
8
  import { stat, access, constants, readFile, writeFile, readdir, mkdir } from 'fs/promises';
9
9
  import { join, basename, dirname } from 'path';
10
- import { BehaviorSubject } from 'rxjs';
10
+ import { Subject } from 'rxjs';
11
11
  import { randomBytes } from 'crypto';
12
12
  import { format } from 'prettier';
13
13
  import parserHtml from 'prettier/parser-html';
@@ -31,7 +31,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
31
31
  * @generated
32
32
  * @see https://github.com/webgptorg/promptbook
33
33
  */
34
- const PROMPTBOOK_ENGINE_VERSION = '0.86.31';
34
+ const PROMPTBOOK_ENGINE_VERSION = '0.88.0-10';
35
35
  /**
36
36
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
37
37
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -1721,6 +1721,57 @@ function $randomToken(randomness) {
1721
1721
  * TODO: Maybe use nanoid instead https://github.com/ai/nanoid
1722
1722
  */
1723
1723
 
1724
+ /**
1725
+ * Function isValidJsonString will tell you if the string is valid JSON or not
1726
+ *
1727
+ * @public exported from `@promptbook/utils`
1728
+ */
1729
+ function isValidJsonString(value /* <- [👨‍⚖️] */) {
1730
+ try {
1731
+ JSON.parse(value);
1732
+ return true;
1733
+ }
1734
+ catch (error) {
1735
+ if (!(error instanceof Error)) {
1736
+ throw error;
1737
+ }
1738
+ if (error.message.includes('Unexpected token')) {
1739
+ return false;
1740
+ }
1741
+ return false;
1742
+ }
1743
+ }
1744
+
1745
+ /**
1746
+ * Recursively converts JSON strings to JSON objects
1747
+
1748
+ * @public exported from `@promptbook/utils`
1749
+ */
1750
+ function jsonStringsToJsons(object) {
1751
+ if (object === null) {
1752
+ return object;
1753
+ }
1754
+ if (Array.isArray(object)) {
1755
+ return object.map(jsonStringsToJsons);
1756
+ }
1757
+ if (typeof object !== 'object') {
1758
+ return object;
1759
+ }
1760
+ const newObject = { ...object };
1761
+ for (const [key, value] of Object.entries(object)) {
1762
+ if (typeof value === 'string' && isValidJsonString(value)) {
1763
+ newObject[key] = JSON.parse(value);
1764
+ }
1765
+ else {
1766
+ newObject[key] = jsonStringsToJsons(value);
1767
+ }
1768
+ }
1769
+ return newObject;
1770
+ }
1771
+ /**
1772
+ * TODO: Type the return type correctly
1773
+ */
1774
+
1724
1775
  /**
1725
1776
  * Deserializes the error object
1726
1777
  *
@@ -1793,21 +1844,43 @@ function assertsTaskSuccessful(executionResult) {
1793
1844
  function createTask(options) {
1794
1845
  const { taskType, taskProcessCallback } = options;
1795
1846
  const taskId = `${taskType.toLowerCase().substring(0, 4)}-${$randomToken(8 /* <- TODO: To global config + Use Base58 to avoid simmilar char conflicts */)}`;
1796
- const partialResultSubject = new BehaviorSubject({});
1847
+ let status = 'RUNNING';
1848
+ const createdAt = new Date();
1849
+ let updatedAt = createdAt;
1850
+ const errors = [];
1851
+ const warnings = [];
1852
+ let currentValue = {};
1853
+ const partialResultSubject = new Subject();
1854
+ // <- Note: Not using `BehaviorSubject` because on error we can't access the last value
1797
1855
  const finalResultPromise = /* not await */ taskProcessCallback((newOngoingResult) => {
1856
+ Object.assign(currentValue, newOngoingResult);
1857
+ // <- TODO: assign deep
1798
1858
  partialResultSubject.next(newOngoingResult);
1799
1859
  });
1800
1860
  finalResultPromise
1801
1861
  .catch((error) => {
1862
+ errors.push(error);
1802
1863
  partialResultSubject.error(error);
1803
1864
  })
1804
- .then((value) => {
1805
- if (value) {
1865
+ .then((executionResult) => {
1866
+ if (executionResult) {
1806
1867
  try {
1807
- assertsTaskSuccessful(value);
1808
- partialResultSubject.next(value);
1868
+ updatedAt = new Date();
1869
+ errors.push(...executionResult.errors);
1870
+ warnings.push(...executionResult.warnings);
1871
+ // <- TODO: !!! Only unique errors and warnings should be added (or filtered)
1872
+ // TODO: [🧠] !!! errors, warning, isSuccessful are redundant both in `ExecutionTask` and `ExecutionTask.currentValue`
1873
+ // Also maybe move `ExecutionTask.currentValue.usage` -> `ExecutionTask.usage`
1874
+ // And delete `ExecutionTask.currentValue.preparedPipeline`
1875
+ assertsTaskSuccessful(executionResult);
1876
+ status = 'FINISHED';
1877
+ currentValue = jsonStringsToJsons(executionResult);
1878
+ // <- TODO: [🧠] Is this a good idea to convert JSON strins to JSONs?
1879
+ partialResultSubject.next(executionResult);
1809
1880
  }
1810
1881
  catch (error) {
1882
+ status = 'ERROR';
1883
+ errors.push(error);
1811
1884
  partialResultSubject.error(error);
1812
1885
  }
1813
1886
  }
@@ -1824,12 +1897,33 @@ function createTask(options) {
1824
1897
  return {
1825
1898
  taskType,
1826
1899
  taskId,
1900
+ get status() {
1901
+ return status;
1902
+ // <- Note: [1] Theese must be getters to allow changing the value in the future
1903
+ },
1904
+ get createdAt() {
1905
+ return createdAt;
1906
+ // <- Note: [1]
1907
+ },
1908
+ get updatedAt() {
1909
+ return updatedAt;
1910
+ // <- Note: [1]
1911
+ },
1827
1912
  asPromise,
1828
1913
  asObservable() {
1829
1914
  return partialResultSubject.asObservable();
1830
1915
  },
1916
+ get errors() {
1917
+ return errors;
1918
+ // <- Note: [1]
1919
+ },
1920
+ get warnings() {
1921
+ return warnings;
1922
+ // <- Note: [1]
1923
+ },
1831
1924
  get currentValue() {
1832
- return partialResultSubject.value;
1925
+ return currentValue;
1926
+ // <- Note: [1]
1833
1927
  },
1834
1928
  };
1835
1929
  }
@@ -1904,27 +1998,6 @@ function isValidFilePath(filename) {
1904
1998
  * TODO: [🍏] Implement for MacOs
1905
1999
  */
1906
2000
 
1907
- /**
1908
- * Function isValidJsonString will tell you if the string is valid JSON or not
1909
- *
1910
- * @public exported from `@promptbook/utils`
1911
- */
1912
- function isValidJsonString(value /* <- [👨‍⚖️] */) {
1913
- try {
1914
- JSON.parse(value);
1915
- return true;
1916
- }
1917
- catch (error) {
1918
- if (!(error instanceof Error)) {
1919
- throw error;
1920
- }
1921
- if (error.message.includes('Unexpected token')) {
1922
- return false;
1923
- }
1924
- return false;
1925
- }
1926
- }
1927
-
1928
2001
  /**
1929
2002
  * Function `validatePipelineString` will validate the if the string is a valid pipeline string
1930
2003
  * It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
@@ -3972,7 +4045,7 @@ function valueToString(value) {
3972
4045
  * @param script from which to extract the variables
3973
4046
  * @returns the list of variable names
3974
4047
  * @throws {ParseError} if the script is invalid
3975
- * @public exported from `@promptbook/execute-javascript`
4048
+ * @public exported from `@promptbook/javascript`
3976
4049
  */
3977
4050
  function extractVariablesFromJavascript(script) {
3978
4051
  const variables = new Set();
@@ -5053,7 +5126,7 @@ async function executeAttempts(options) {
5053
5126
  Last result:
5054
5127
  ${block($ongoingTaskResult.$resultString === null
5055
5128
  ? 'null'
5056
- : $ongoingTaskResult.$resultString
5129
+ : spaceTrim($ongoingTaskResult.$resultString)
5057
5130
  .split('\n')
5058
5131
  .map((line) => `> ${line}`)
5059
5132
  .join('\n'))}
@@ -5946,6 +6019,623 @@ async function $provideScrapersForNode(tools, options) {
5946
6019
  * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
5947
6020
  */
5948
6021
 
6022
+ /**
6023
+ * @@@
6024
+ *
6025
+ * @param text @@@
6026
+ * @param _isFirstLetterCapital @@@
6027
+ * @returns @@@
6028
+ * @example 'helloWorld'
6029
+ * @example 'iLovePromptbook'
6030
+ * @public exported from `@promptbook/utils`
6031
+ */
6032
+ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
6033
+ let charType;
6034
+ let lastCharType = null;
6035
+ let normalizedName = '';
6036
+ for (const char of text) {
6037
+ let normalizedChar;
6038
+ if (/^[a-z]$/.test(char)) {
6039
+ charType = 'LOWERCASE';
6040
+ normalizedChar = char;
6041
+ }
6042
+ else if (/^[A-Z]$/.test(char)) {
6043
+ charType = 'UPPERCASE';
6044
+ normalizedChar = char.toLowerCase();
6045
+ }
6046
+ else if (/^[0-9]$/.test(char)) {
6047
+ charType = 'NUMBER';
6048
+ normalizedChar = char;
6049
+ }
6050
+ else {
6051
+ charType = 'OTHER';
6052
+ normalizedChar = '';
6053
+ }
6054
+ if (!lastCharType) {
6055
+ if (_isFirstLetterCapital) {
6056
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
6057
+ }
6058
+ }
6059
+ else if (charType !== lastCharType &&
6060
+ !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
6061
+ !(lastCharType === 'NUMBER') &&
6062
+ !(charType === 'NUMBER')) {
6063
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: [🌺] DRY
6064
+ }
6065
+ normalizedName += normalizedChar;
6066
+ lastCharType = charType;
6067
+ }
6068
+ return normalizedName;
6069
+ }
6070
+ /**
6071
+ * TODO: [🌺] Use some intermediate util splitWords
6072
+ */
6073
+
6074
+ /**
6075
+ * Detects if the code is running in a browser environment in main thread (Not in a web worker)
6076
+ *
6077
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6078
+ *
6079
+ * @public exported from `@promptbook/utils`
6080
+ */
6081
+ new Function(`
6082
+ try {
6083
+ return this === window;
6084
+ } catch (e) {
6085
+ return false;
6086
+ }
6087
+ `);
6088
+ /**
6089
+ * TODO: [🎺]
6090
+ */
6091
+
6092
+ /**
6093
+ * Detects if the code is running in jest environment
6094
+ *
6095
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6096
+ *
6097
+ * @public exported from `@promptbook/utils`
6098
+ */
6099
+ new Function(`
6100
+ try {
6101
+ return process.env.JEST_WORKER_ID !== undefined;
6102
+ } catch (e) {
6103
+ return false;
6104
+ }
6105
+ `);
6106
+ /**
6107
+ * TODO: [🎺]
6108
+ */
6109
+
6110
+ /**
6111
+ * Detects if the code is running in a web worker
6112
+ *
6113
+ * Note: `$` is used to indicate that this function is not a pure function - it looks at the global object to determine the environment
6114
+ *
6115
+ * @public exported from `@promptbook/utils`
6116
+ */
6117
+ new Function(`
6118
+ try {
6119
+ if (typeof WorkerGlobalScope !== 'undefined' && self instanceof WorkerGlobalScope) {
6120
+ return true;
6121
+ } else {
6122
+ return false;
6123
+ }
6124
+ } catch (e) {
6125
+ return false;
6126
+ }
6127
+ `);
6128
+ /**
6129
+ * TODO: [🎺]
6130
+ */
6131
+
6132
+ /**
6133
+ * Makes first letter of a string uppercase
6134
+ *
6135
+ * @public exported from `@promptbook/utils`
6136
+ */
6137
+ function decapitalize(word) {
6138
+ return word.substring(0, 1).toLowerCase() + word.substring(1);
6139
+ }
6140
+
6141
+ /**
6142
+ * Parses keywords from a string
6143
+ *
6144
+ * @param {string} input
6145
+ * @returns {Set} of keywords without diacritics in lowercase
6146
+ * @public exported from `@promptbook/utils`
6147
+ */
6148
+ function parseKeywordsFromString(input) {
6149
+ const keywords = normalizeTo_SCREAMING_CASE(removeDiacritics(input))
6150
+ .toLowerCase()
6151
+ .split(/[^a-z0-9]+/gs)
6152
+ .filter((value) => value);
6153
+ return new Set(keywords);
6154
+ }
6155
+
6156
+ /**
6157
+ * @@@
6158
+ *
6159
+ * @param name @@@
6160
+ * @returns @@@
6161
+ * @example @@@
6162
+ * @public exported from `@promptbook/utils`
6163
+ */
6164
+ function nameToUriPart(name) {
6165
+ let uriPart = name;
6166
+ uriPart = uriPart.toLowerCase();
6167
+ uriPart = removeDiacritics(uriPart);
6168
+ uriPart = uriPart.replace(/[^a-zA-Z0-9]+/g, '-');
6169
+ uriPart = uriPart.replace(/^-+/, '');
6170
+ uriPart = uriPart.replace(/-+$/, '');
6171
+ return uriPart;
6172
+ }
6173
+
6174
+ /**
6175
+ * @@@
6176
+ *
6177
+ * @param name @@@
6178
+ * @returns @@@
6179
+ * @example @@@
6180
+ * @public exported from `@promptbook/utils`
6181
+ */
6182
+ function nameToUriParts(name) {
6183
+ return nameToUriPart(name)
6184
+ .split('-')
6185
+ .filter((value) => value !== '');
6186
+ }
6187
+
6188
+ /**
6189
+ *
6190
+ * @param text @public exported from `@promptbook/utils`
6191
+ * @returns
6192
+ * @example 'HelloWorld'
6193
+ * @example 'ILovePromptbook'
6194
+ * @public exported from `@promptbook/utils`
6195
+ */
6196
+ function normalizeTo_PascalCase(text) {
6197
+ return normalizeTo_camelCase(text, true);
6198
+ }
6199
+
6200
+ /**
6201
+ * Take every whitespace (space, new line, tab) and replace it with a single space
6202
+ *
6203
+ * @public exported from `@promptbook/utils`
6204
+ */
6205
+ function normalizeWhitespaces(sentence) {
6206
+ return sentence.replace(/\s+/gs, ' ').trim();
6207
+ }
6208
+
6209
+ /**
6210
+ * Removes quotes from a string
6211
+ *
6212
+ * Tip: This is very usefull for post-processing of the result of the LLM model
6213
+ * Note: This function removes only the same quotes from the beginning and the end of the string
6214
+ * Note: There are two simmilar functions:
6215
+ * - `removeQuotes` which removes only bounding quotes
6216
+ * - `unwrapResult` which removes whole introduce sentence
6217
+ *
6218
+ * @param text optionally quoted text
6219
+ * @returns text without quotes
6220
+ * @public exported from `@promptbook/utils`
6221
+ */
6222
+ function removeQuotes(text) {
6223
+ if (text.startsWith('"') && text.endsWith('"')) {
6224
+ return text.slice(1, -1);
6225
+ }
6226
+ if (text.startsWith('\'') && text.endsWith('\'')) {
6227
+ return text.slice(1, -1);
6228
+ }
6229
+ return text;
6230
+ }
6231
+
6232
+ /**
6233
+ * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
6234
+ *
6235
+ * Note: This is usefull for post-processing of the result of the chat LLM model
6236
+ * when the model wraps the result in the (markdown) code block.
6237
+ *
6238
+ * @public exported from `@promptbook/utils`
6239
+ */
6240
+ function trimCodeBlock(value) {
6241
+ value = spaceTrim(value);
6242
+ if (!/^```[a-z]*(.*)```$/is.test(value)) {
6243
+ return value;
6244
+ }
6245
+ value = value.replace(/^```[a-z]*/i, '');
6246
+ value = value.replace(/```$/i, '');
6247
+ value = spaceTrim(value);
6248
+ return value;
6249
+ }
6250
+
6251
+ /**
6252
+ * Function trimEndOfCodeBlock will remove ending code block from the string if it is present.
6253
+ *
6254
+ * Note: This is usefull for post-processing of the result of the completion LLM model
6255
+ * if you want to start code block in the prompt but you don't want to end it in the result.
6256
+ *
6257
+ * @public exported from `@promptbook/utils`
6258
+ */
6259
+ function trimEndOfCodeBlock(value) {
6260
+ value = spaceTrim(value);
6261
+ value = value.replace(/```$/g, '');
6262
+ value = spaceTrim(value);
6263
+ return value;
6264
+ }
6265
+
6266
+ /**
6267
+ * Removes quotes and optional introduce text from a string
6268
+ *
6269
+ * Tip: This is very usefull for post-processing of the result of the LLM model
6270
+ * Note: This function trims the text and removes whole introduce sentence if it is present
6271
+ * Note: There are two simmilar functions:
6272
+ * - `removeQuotes` which removes only bounding quotes
6273
+ * - `unwrapResult` which removes whole introduce sentence
6274
+ *
6275
+ * @param text optionally quoted text
6276
+ * @returns text without quotes
6277
+ * @public exported from `@promptbook/utils`
6278
+ */
6279
+ function unwrapResult(text, options) {
6280
+ const { isTrimmed = true, isIntroduceSentenceRemoved = true } = options || {};
6281
+ let trimmedText = text;
6282
+ // Remove leading and trailing spaces and newlines
6283
+ if (isTrimmed) {
6284
+ trimmedText = spaceTrim(trimmedText);
6285
+ }
6286
+ let processedText = trimmedText;
6287
+ if (isIntroduceSentenceRemoved) {
6288
+ const introduceSentenceRegex = /^[a-zěščřžýáíéúů:\s]*:\s*/i;
6289
+ if (introduceSentenceRegex.test(text)) {
6290
+ // Remove the introduce sentence and quotes by replacing it with an empty string
6291
+ processedText = processedText.replace(introduceSentenceRegex, '');
6292
+ }
6293
+ processedText = spaceTrim(processedText);
6294
+ }
6295
+ if (processedText.length < 3) {
6296
+ return trimmedText;
6297
+ }
6298
+ if (processedText.includes('\n')) {
6299
+ return trimmedText;
6300
+ }
6301
+ // Remove the quotes by extracting the substring without the first and last characters
6302
+ const unquotedText = processedText.slice(1, -1);
6303
+ // Check if the text starts and ends with quotes
6304
+ if ([
6305
+ ['"', '"'],
6306
+ ["'", "'"],
6307
+ ['`', '`'],
6308
+ ['*', '*'],
6309
+ ['_', '_'],
6310
+ ['„', '“'],
6311
+ ['«', '»'] /* <- QUOTES to config */,
6312
+ ].some(([startQuote, endQuote]) => {
6313
+ if (!processedText.startsWith(startQuote)) {
6314
+ return false;
6315
+ }
6316
+ if (!processedText.endsWith(endQuote)) {
6317
+ return false;
6318
+ }
6319
+ if (unquotedText.includes(startQuote) && !unquotedText.includes(endQuote)) {
6320
+ return false;
6321
+ }
6322
+ if (!unquotedText.includes(startQuote) && unquotedText.includes(endQuote)) {
6323
+ return false;
6324
+ }
6325
+ return true;
6326
+ })) {
6327
+ return unwrapResult(unquotedText, { isTrimmed: false, isIntroduceSentenceRemoved: false });
6328
+ }
6329
+ else {
6330
+ return processedText;
6331
+ }
6332
+ }
6333
+ /**
6334
+ * TODO: [🧠] Should this also unwrap the (parenthesis)
6335
+ */
6336
+
6337
+ /**
6338
+ * Extracts exactly ONE code block from markdown.
6339
+ *
6340
+ * - When there are multiple or no code blocks the function throws a `ParseError`
6341
+ *
6342
+ * Note: There are multiple simmilar function:
6343
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
6344
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
6345
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
6346
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
6347
+ *
6348
+ * @param markdown any valid markdown
6349
+ * @returns code block with language and content
6350
+ * @public exported from `@promptbook/markdown-utils`
6351
+ * @throws {ParseError} if there is not exactly one code block in the markdown
6352
+ */
6353
+ function extractOneBlockFromMarkdown(markdown) {
6354
+ const codeBlocks = extractAllBlocksFromMarkdown(markdown);
6355
+ if (codeBlocks.length !== 1) {
6356
+ throw new ParseError(spaceTrim$1((block) => `
6357
+ There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
6358
+
6359
+ ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
6360
+ `));
6361
+ }
6362
+ return codeBlocks[0];
6363
+ }
6364
+ /***
6365
+ * TODO: [🍓][🌻] Decide of this is internal utility, external util OR validator/postprocessor
6366
+ */
6367
+
6368
+ /**
6369
+ * Extracts code block from markdown.
6370
+ *
6371
+ * - When there are multiple or no code blocks the function throws a `ParseError`
6372
+ *
6373
+ * Note: There are multiple simmilar function:
6374
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
6375
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
6376
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
6377
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
6378
+ *
6379
+ * @public exported from `@promptbook/markdown-utils`
6380
+ * @throws {ParseError} if there is not exactly one code block in the markdown
6381
+ */
6382
+ function extractBlock(markdown) {
6383
+ const { content } = extractOneBlockFromMarkdown(markdown);
6384
+ return content;
6385
+ }
6386
+
6387
+ /**
6388
+ * Does nothing, but preserves the function in the bundle
6389
+ * Compiler is tricked into thinking the function is used
6390
+ *
6391
+ * @param value any function to preserve
6392
+ * @returns nothing
6393
+ * @private internal function of `JavascriptExecutionTools` and `JavascriptEvalExecutionTools`
6394
+ */
6395
+ function preserve(func) {
6396
+ // Note: NOT calling the function
6397
+ (async () => {
6398
+ // TODO: [💩] Change to `await forEver` or something better
6399
+ await forTime(100000000);
6400
+ // [1]
6401
+ try {
6402
+ await func();
6403
+ }
6404
+ finally {
6405
+ // do nothing
6406
+ }
6407
+ })();
6408
+ }
6409
+ /**
6410
+ * TODO: Probbably remove in favour of `keepImported`
6411
+ * TODO: [1] This maybe does memory leak
6412
+ */
6413
+
6414
+ // Note: [💎]
6415
+ /**
6416
+ * ScriptExecutionTools for JavaScript implemented via eval
6417
+ *
6418
+ * Warning: It is used for testing and mocking
6419
+ * **NOT intended to use in the production** due to its unsafe nature, use `JavascriptExecutionTools` instead.
6420
+ *
6421
+ * @public exported from `@promptbook/javascript`
6422
+ */
6423
+ class JavascriptEvalExecutionTools {
6424
+ constructor(options) {
6425
+ this.options = options || {};
6426
+ }
6427
+ /**
6428
+ * Executes a JavaScript
6429
+ */
6430
+ async execute(options) {
6431
+ const { scriptLanguage, parameters } = options;
6432
+ let { script } = options;
6433
+ if (scriptLanguage !== 'javascript') {
6434
+ throw new PipelineExecutionError(`Script language ${scriptLanguage} not supported to be executed by JavascriptEvalExecutionTools`);
6435
+ }
6436
+ // Note: [💎]
6437
+ // Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
6438
+ const spaceTrim = (_) => spaceTrim$1(_);
6439
+ preserve(spaceTrim);
6440
+ const removeQuotes$1 = removeQuotes;
6441
+ preserve(removeQuotes$1);
6442
+ const unwrapResult$1 = unwrapResult;
6443
+ preserve(unwrapResult$1);
6444
+ const trimEndOfCodeBlock$1 = trimEndOfCodeBlock;
6445
+ preserve(trimEndOfCodeBlock$1);
6446
+ const trimCodeBlock$1 = trimCodeBlock;
6447
+ preserve(trimCodeBlock$1);
6448
+ // TODO: DRY [🍯]
6449
+ const trim = (str) => str.trim();
6450
+ preserve(trim);
6451
+ // TODO: DRY [🍯]
6452
+ const reverse = (str) => str.split('').reverse().join('');
6453
+ preserve(reverse);
6454
+ const removeEmojis$1 = removeEmojis;
6455
+ preserve(removeEmojis$1);
6456
+ const prettifyMarkdown$1 = prettifyMarkdown;
6457
+ preserve(prettifyMarkdown$1);
6458
+ //-------[n12:]---
6459
+ const capitalize$1 = capitalize;
6460
+ const decapitalize$1 = decapitalize;
6461
+ const nameToUriPart$1 = nameToUriPart;
6462
+ const nameToUriParts$1 = nameToUriParts;
6463
+ const removeDiacritics$1 = removeDiacritics;
6464
+ const normalizeWhitespaces$1 = normalizeWhitespaces;
6465
+ const normalizeToKebabCase$1 = normalizeToKebabCase;
6466
+ const normalizeTo_camelCase$1 = normalizeTo_camelCase;
6467
+ const normalizeTo_snake_case$1 = normalizeTo_snake_case;
6468
+ const normalizeTo_PascalCase$1 = normalizeTo_PascalCase;
6469
+ const parseKeywords = (input) =>
6470
+ // TODO: DRY [🍯]
6471
+ Array.from(parseKeywordsFromString(input)).join(', '); /* <- TODO: [🧠] What is the best format comma list, bullet list,...? */
6472
+ const normalizeTo_SCREAMING_CASE$1 = normalizeTo_SCREAMING_CASE;
6473
+ preserve(capitalize$1);
6474
+ preserve(decapitalize$1);
6475
+ preserve(nameToUriPart$1);
6476
+ preserve(nameToUriParts$1);
6477
+ preserve(removeDiacritics$1);
6478
+ preserve(normalizeWhitespaces$1);
6479
+ preserve(normalizeToKebabCase$1);
6480
+ preserve(normalizeTo_camelCase$1);
6481
+ preserve(normalizeTo_snake_case$1);
6482
+ preserve(normalizeTo_PascalCase$1);
6483
+ preserve(parseKeywords);
6484
+ preserve(normalizeTo_SCREAMING_CASE$1);
6485
+ //-------[/n12]---
6486
+ if (!script.includes('return')) {
6487
+ script = `return ${script}`;
6488
+ }
6489
+ // TODO: DRY [🍯]
6490
+ const buildinFunctions = {
6491
+ // TODO: [🍯] DRY all these functions across the file
6492
+ spaceTrim,
6493
+ removeQuotes: removeQuotes$1,
6494
+ unwrapResult: unwrapResult$1,
6495
+ trimEndOfCodeBlock: trimEndOfCodeBlock$1,
6496
+ trimCodeBlock: trimCodeBlock$1,
6497
+ trim,
6498
+ reverse,
6499
+ removeEmojis: removeEmojis$1,
6500
+ prettifyMarkdown: prettifyMarkdown$1,
6501
+ capitalize: capitalize$1,
6502
+ decapitalize: decapitalize$1,
6503
+ nameToUriPart: nameToUriPart$1,
6504
+ nameToUriParts: nameToUriParts$1,
6505
+ removeDiacritics: removeDiacritics$1,
6506
+ normalizeWhitespaces: normalizeWhitespaces$1,
6507
+ normalizeToKebabCase: normalizeToKebabCase$1,
6508
+ normalizeTo_camelCase: normalizeTo_camelCase$1,
6509
+ normalizeTo_snake_case: normalizeTo_snake_case$1,
6510
+ normalizeTo_PascalCase: normalizeTo_PascalCase$1,
6511
+ parseKeywords,
6512
+ normalizeTo_SCREAMING_CASE: normalizeTo_SCREAMING_CASE$1,
6513
+ extractBlock, // <- [🍓] Remove balast in all other functions, use this one as example
6514
+ };
6515
+ const buildinFunctionsStatement = Object.keys(buildinFunctions)
6516
+ .map((functionName) =>
6517
+ // Note: Custom functions are exposed to the current scope as variables
6518
+ `const ${functionName} = buildinFunctions.${functionName};`)
6519
+ .join('\n');
6520
+ // TODO: DRY [🍯]
6521
+ const customFunctions = this.options.functions || {};
6522
+ const customFunctionsStatement = Object.keys(customFunctions)
6523
+ .map((functionName) =>
6524
+ // Note: Custom functions are exposed to the current scope as variables
6525
+ `const ${functionName} = customFunctions.${functionName};`)
6526
+ .join('\n');
6527
+ // script = templateParameters(script, parameters);
6528
+ // <- TODO: [🧠][🥳] Should be this is one of two variants how to use parameters in script
6529
+ const statementToEvaluate = spaceTrim$1((block) => `
6530
+
6531
+ // Build-in functions:
6532
+ ${block(buildinFunctionsStatement)}
6533
+
6534
+ // Custom functions:
6535
+ ${block(customFunctionsStatement || '// -- No custom functions --')}
6536
+
6537
+ // The script:
6538
+ ${block(Object.entries(parameters)
6539
+ .map(([key, value]) => `const ${key} = ${JSON.stringify(value)};`)
6540
+ .join('\n'))}
6541
+ (()=>{ ${script} })()
6542
+ `);
6543
+ if (this.options.isVerbose) {
6544
+ console.info(spaceTrim$1((block) => `
6545
+ 🚀 Evaluating ${scriptLanguage} script:
6546
+
6547
+ ${block(statementToEvaluate)}`));
6548
+ }
6549
+ let result;
6550
+ try {
6551
+ result = await eval(statementToEvaluate);
6552
+ if (typeof result !== 'string') {
6553
+ throw new PipelineExecutionError(`Script must return a string, but returned ${valueToString(result)}`);
6554
+ }
6555
+ }
6556
+ catch (error) {
6557
+ if (!(error instanceof Error)) {
6558
+ throw error;
6559
+ }
6560
+ if (error instanceof ReferenceError) {
6561
+ const undefinedName = error.message.split(' ')[0];
6562
+ /*
6563
+ Note: Remapping error
6564
+ From: [PipelineUrlError: thing is not defined],
6565
+ To: [PipelineExecutionError: Parameter `{thing}` is not defined],
6566
+ */
6567
+ if (!statementToEvaluate.includes(undefinedName + '(')) {
6568
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
6569
+
6570
+ Parameter \`{${undefinedName}}\` is not defined
6571
+
6572
+ This happen during evaluation of the javascript, which has access to the following parameters as javascript variables:
6573
+
6574
+ ${block(Object.keys(parameters)
6575
+ .map((key) => ` - ${key}\n`)
6576
+ .join(''))}
6577
+
6578
+ The script is:
6579
+ \`\`\`javascript
6580
+ ${block(script)}
6581
+ \`\`\`
6582
+
6583
+ Original error message:
6584
+ ${block(error.message)}
6585
+
6586
+
6587
+ `));
6588
+ }
6589
+ else {
6590
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
6591
+ Function ${undefinedName}() is not defined
6592
+
6593
+ - Make sure that the function is one of built-in functions
6594
+ - Or you have to defined the function during construction of JavascriptEvalExecutionTools
6595
+
6596
+ Original error message:
6597
+ ${block(error.message)}
6598
+
6599
+ `));
6600
+ }
6601
+ }
6602
+ throw error;
6603
+ }
6604
+ if (typeof result !== 'string') {
6605
+ throw new PipelineExecutionError(`Script must return a string, but ${valueToString(result)}`);
6606
+ }
6607
+ return result;
6608
+ }
6609
+ }
6610
+ /**
6611
+ * TODO: Put predefined functions (like removeQuotes, spaceTrim, etc.) into annotation OR pass into constructor
6612
+ * TODO: [🧠][💙] Distinct between options passed into ExecutionTools and to ExecutionTools.execute
6613
+ */
6614
+
6615
+ /**
6616
+ * Placeholder for better implementation of JavascriptExecutionTools - some propper sandboxing
6617
+ *
6618
+ * @alias JavascriptExecutionTools
6619
+ * @public exported from `@promptbook/javascript`
6620
+ */
6621
+ const JavascriptExecutionTools = JavascriptEvalExecutionTools;
6622
+
6623
+ /**
6624
+ * Provides script execution tools
6625
+ *
6626
+ * @public exported from `@promptbook/node`
6627
+ */
6628
+ async function $provideScriptingForNode(options) {
6629
+ if (!$isRunningInNode()) {
6630
+ throw new EnvironmentMismatchError('Function `$provideScriptingForNode` works only in Node.js environment');
6631
+ }
6632
+ // TODO: [🔱] Do here auto-installation
6633
+ return [new JavascriptExecutionTools(options)];
6634
+ }
6635
+ /**
6636
+ * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
6637
+ */
6638
+
5949
6639
  /**
5950
6640
  * Remote server is a proxy server that uses its execution tools internally and exposes the executor interface externally.
5951
6641
  *
@@ -6017,7 +6707,7 @@ function startRemoteServer(options) {
6017
6707
  llm,
6018
6708
  fs,
6019
6709
  scrapers: await $provideScrapersForNode({ fs, llm, executables }),
6020
- // TODO: Allow when `JavascriptExecutionTools` more secure *(without eval)*> script: [new JavascriptExecutionTools()],
6710
+ script: await $provideScriptingForNode({}),
6021
6711
  };
6022
6712
  return tools;
6023
6713
  }
@@ -6028,6 +6718,7 @@ function startRemoteServer(options) {
6028
6718
  next();
6029
6719
  });
6030
6720
  const runningExecutionTasks = [];
6721
+ // <- TODO: [🤬] Identify the users
6031
6722
  // TODO: [🧠] Do here some garbage collection of finished tasks
6032
6723
  app.get(['/', rootPath], async (request, response) => {
6033
6724
  var _a;
@@ -6122,23 +6813,60 @@ function startRemoteServer(options) {
6122
6813
  .send({ error: serializeError(error) });
6123
6814
  }
6124
6815
  });
6816
+ function exportExecutionTask(executionTask, isFull) {
6817
+ // <- TODO: [🧠] This should be maybe method of `ExecutionTask` itself
6818
+ const { taskType, taskId, status, errors, warnings, createdAt, updatedAt, currentValue } = executionTask;
6819
+ if (isFull) {
6820
+ return {
6821
+ nonce: '✨',
6822
+ taskId,
6823
+ taskType,
6824
+ status,
6825
+ errors: errors.map(serializeError),
6826
+ warnings: warnings.map(serializeError),
6827
+ createdAt,
6828
+ updatedAt,
6829
+ currentValue,
6830
+ };
6831
+ }
6832
+ else {
6833
+ return {
6834
+ nonce: '✨',
6835
+ taskId,
6836
+ taskType,
6837
+ status,
6838
+ createdAt,
6839
+ updatedAt,
6840
+ };
6841
+ }
6842
+ }
6125
6843
  app.get(`${rootPath}/executions`, async (request, response) => {
6126
- response.send(runningExecutionTasks);
6844
+ response.send(runningExecutionTasks.map((runningExecutionTask) => exportExecutionTask(runningExecutionTask, false)));
6845
+ });
6846
+ app.get(`${rootPath}/executions/last`, async (request, response) => {
6847
+ // TODO: [🤬] Filter only for user
6848
+ if (runningExecutionTasks.length === 0) {
6849
+ response.status(404).send('No execution tasks found');
6850
+ return;
6851
+ }
6852
+ const lastExecutionTask = runningExecutionTasks[runningExecutionTasks.length - 1];
6853
+ response.send(exportExecutionTask(lastExecutionTask, true));
6127
6854
  });
6128
6855
  app.get(`${rootPath}/executions/:taskId`, async (request, response) => {
6129
6856
  const { taskId } = request.params;
6130
- const execution = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
6131
- if (execution === undefined) {
6857
+ // TODO: [🤬] Filter only for user
6858
+ const executionTask = runningExecutionTasks.find((executionTask) => executionTask.taskId === taskId);
6859
+ if (executionTask === undefined) {
6132
6860
  response
6133
6861
  .status(404)
6134
6862
  .send(`Execution "${taskId}" not found`);
6135
6863
  return;
6136
6864
  }
6137
- response.send(execution.currentValue);
6865
+ response.send(exportExecutionTask(executionTask, true));
6138
6866
  });
6139
6867
  app.post(`${rootPath}/executions/new`, async (request, response) => {
6140
6868
  try {
6141
- const { inputParameters, identification } = request.body;
6869
+ const { inputParameters, identification /* <- [🤬] */ } = request.body;
6142
6870
  const pipelineUrl = request.body.pipelineUrl || request.body.book;
6143
6871
  // TODO: [🧠] Check `pipelineUrl` and `inputParameters` here or it should be responsibility of `collection.getPipelineByUrl` and `pipelineExecutor`
6144
6872
  const pipeline = await (collection === null || collection === void 0 ? void 0 : collection.getPipelineByUrl(pipelineUrl));