@promptbook/editable 0.82.0-3 → 0.83.0

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 (45) hide show
  1. package/README.md +0 -4
  2. package/esm/index.es.js +3744 -322
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/editable.index.d.ts +74 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +26 -0
  6. package/esm/typings/src/commands/BOOK_VERSION/BookVersionCommand.d.ts +1 -1
  7. package/esm/typings/src/commands/BOOK_VERSION/bookVersionCommandParser.d.ts +1 -1
  8. package/esm/typings/src/commands/EXPECT/expectCommandParser.d.ts +1 -1
  9. package/esm/typings/src/commands/FOREACH/ForeachCommand.d.ts +1 -1
  10. package/esm/typings/src/commands/FOREACH/foreachCommandParser.d.ts +1 -1
  11. package/esm/typings/src/commands/FORMAT/formatCommandParser.d.ts +1 -1
  12. package/esm/typings/src/commands/FORMFACTOR/FormfactorCommand.d.ts +1 -1
  13. package/esm/typings/src/commands/FORMFACTOR/formfactorCommandParser.d.ts +1 -1
  14. package/esm/typings/src/commands/JOKER/JokerCommand.d.ts +1 -1
  15. package/esm/typings/src/commands/JOKER/jokerCommandParser.d.ts +1 -1
  16. package/esm/typings/src/commands/KNOWLEDGE/KnowledgeCommand.d.ts +2 -2
  17. package/esm/typings/src/commands/KNOWLEDGE/knowledgeCommandParser.d.ts +1 -1
  18. package/esm/typings/src/commands/KNOWLEDGE/utils/{sourceContentToName.d.ts → knowledgeSourceContentToName.d.ts} +2 -2
  19. package/esm/typings/src/commands/MODEL/ModelCommand.d.ts +2 -1
  20. package/esm/typings/src/commands/MODEL/modelCommandParser.d.ts +2 -1
  21. package/esm/typings/src/commands/PARAMETER/ParameterCommand.d.ts +1 -1
  22. package/esm/typings/src/commands/PARAMETER/parameterCommandParser.d.ts +1 -1
  23. package/esm/typings/src/commands/PERSONA/PersonaCommand.d.ts +1 -1
  24. package/esm/typings/src/commands/PERSONA/personaCommandParser.d.ts +1 -1
  25. package/esm/typings/src/commands/POSTPROCESS/PostprocessCommand.d.ts +1 -1
  26. package/esm/typings/src/commands/POSTPROCESS/postprocessCommandParser.d.ts +1 -1
  27. package/esm/typings/src/commands/SECTION/SectionCommand.d.ts +1 -1
  28. package/esm/typings/src/commands/SECTION/sectionCommandParser.d.ts +1 -1
  29. package/esm/typings/src/commands/URL/UrlCommand.d.ts +1 -1
  30. package/esm/typings/src/commands/URL/urlCommandParser.d.ts +1 -1
  31. package/esm/typings/src/commands/X_ACTION/ActionCommand.d.ts +1 -1
  32. package/esm/typings/src/commands/X_ACTION/actionCommandParser.d.ts +1 -1
  33. package/esm/typings/src/commands/X_INSTRUMENT/InstrumentCommand.d.ts +1 -1
  34. package/esm/typings/src/commands/X_INSTRUMENT/instrumentCommandParser.d.ts +1 -1
  35. package/esm/typings/src/commands/_common/getParserForCommand.d.ts +1 -1
  36. package/esm/typings/src/commands/_common/parseCommand.d.ts +1 -1
  37. package/esm/typings/src/commands/_common/stringifyCommand.d.ts +1 -0
  38. package/esm/typings/src/commands/_common/types/CommandParser.d.ts +8 -0
  39. package/esm/typings/src/commands/_common/types/CommandUsagePlaces.d.ts +2 -0
  40. package/esm/typings/src/commands/index.d.ts +1 -1
  41. package/esm/typings/src/pipeline/PipelineJson/KnowledgeSourceJson.d.ts +1 -1
  42. package/package.json +4 -2
  43. package/umd/index.umd.js +3764 -325
  44. package/umd/index.umd.js.map +1 -1
  45. /package/esm/typings/src/commands/KNOWLEDGE/utils/{sourceContentToName.test.d.ts → knowledgeSourceContentToName.test.d.ts} +0 -0
package/esm/index.es.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
2
+ import { unparse, parse } from 'papaparse';
3
+ import { SHA256 } from 'crypto-js';
4
+ import hexEncoder from 'crypto-js/enc-hex';
2
5
 
3
6
  // ⚠️ WARNING: This code has been generated so that any manual changes will be overwritten
4
7
  /**
@@ -14,7 +17,7 @@ var BOOK_LANGUAGE_VERSION = '1.0.0';
14
17
  * @generated
15
18
  * @see https://github.com/webgptorg/promptbook
16
19
  */
17
- var PROMPTBOOK_ENGINE_VERSION = '0.82.0-2';
20
+ var PROMPTBOOK_ENGINE_VERSION = '0.82.0';
18
21
  /**
19
22
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
20
23
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -62,6 +65,44 @@ var __assign = function() {
62
65
  return __assign.apply(this, arguments);
63
66
  };
64
67
 
68
+ function __awaiter(thisArg, _arguments, P, generator) {
69
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
70
+ return new (P || (P = Promise))(function (resolve, reject) {
71
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
72
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
73
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
74
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
75
+ });
76
+ }
77
+
78
+ function __generator(thisArg, body) {
79
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
80
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
81
+ function verb(n) { return function (v) { return step([n, v]); }; }
82
+ function step(op) {
83
+ if (f) throw new TypeError("Generator is already executing.");
84
+ while (_) try {
85
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
86
+ if (y = 0, t) op = [op[0] & 2, t.value];
87
+ switch (op[0]) {
88
+ case 0: case 1: t = op; break;
89
+ case 4: _.label++; return { value: op[1], done: false };
90
+ case 5: _.label++; y = op[1]; op = [0]; continue;
91
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
92
+ default:
93
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
94
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
95
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
96
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
97
+ if (t[2]) _.ops.pop();
98
+ _.trys.pop(); continue;
99
+ }
100
+ op = body.call(thisArg, _);
101
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
102
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
103
+ }
104
+ }
105
+
65
106
  function __values(o) {
66
107
  var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
67
108
  if (m) return m.call(o);
@@ -102,128 +143,23 @@ function __spreadArray(to, from, pack) {
102
143
  }
103
144
 
104
145
  /**
105
- * Function `removePipelineCommand` will remove one command from pipeline string
146
+ * Returns the same value that is passed as argument.
147
+ * No side effects.
106
148
  *
107
- * @public exported from `@promptbook/editable`
108
- */
109
- function removePipelineCommand(options) {
110
- var e_1, _a;
111
- var command = options.command, pipeline = options.pipeline;
112
- var lines = pipeline.split('\n');
113
- // TODO: [🧽] DRY
114
- var currentType = 'MARKDOWN';
115
- var newLines = [];
116
- try {
117
- for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
118
- var line = lines_1_1.value;
119
- if (currentType === 'MARKDOWN') {
120
- if (line.startsWith('```')) {
121
- currentType = 'CODE_BLOCK';
122
- }
123
- else if (line.includes('<!--')) {
124
- currentType = 'COMMENT';
125
- }
126
- }
127
- else if (currentType === 'CODE_BLOCK') {
128
- if (line.startsWith('```')) {
129
- currentType = 'MARKDOWN';
130
- }
131
- }
132
- else if (currentType === 'COMMENT') {
133
- if (line.includes('-->')) {
134
- currentType = 'MARKDOWN';
135
- }
136
- }
137
- if (currentType === 'MARKDOWN' && /^(-|\d\))/m.test(line) && line.toUpperCase().includes(command)) {
138
- continue;
139
- }
140
- newLines.push(line);
141
- }
142
- }
143
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
144
- finally {
145
- try {
146
- if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
147
- }
148
- finally { if (e_1) throw e_1.error; }
149
- }
150
- var newPipeline = spaceTrim(newLines.join('\n'));
151
- return newPipeline;
152
- }
153
-
154
- /**
155
- * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
149
+ * Note: It can be usefull for:
156
150
  *
157
- * @public exported from `@promptbook/core`
158
- */
159
- var PipelineLogicError = /** @class */ (function (_super) {
160
- __extends(PipelineLogicError, _super);
161
- function PipelineLogicError(message) {
162
- var _this = _super.call(this, message) || this;
163
- _this.name = 'PipelineLogicError';
164
- Object.setPrototypeOf(_this, PipelineLogicError.prototype);
165
- return _this;
166
- }
167
- return PipelineLogicError;
168
- }(Error));
169
-
170
- /**
171
- * Function `renamePipelineParameter` will find all usable parameters for given task
172
- * In other words, it will find all parameters that are not used in the task itseld and all its dependencies
151
+ * 1) Leveling indentation
152
+ * 2) Putting always-true or always-false conditions without getting eslint errors
173
153
  *
174
- * @throws {PipelineLogicError} If the new parameter name is already used in the pipeline
175
- * @public exported from `@promptbook/editable`
154
+ * @param value any values
155
+ * @returns the same values
156
+ * @private within the repository
176
157
  */
177
- function renamePipelineParameter(options) {
178
- var e_1, _a, e_2, _b;
179
- var pipeline = options.pipeline, oldParameterName = options.oldParameterName, newParameterName = options.newParameterName;
180
- if (pipeline.parameters.some(function (parameter) { return parameter.name === newParameterName; })) {
181
- throw new PipelineLogicError("Can not replace {".concat(oldParameterName, "} to {").concat(newParameterName, "} because {").concat(newParameterName, "} is already used in the pipeline"));
182
- }
183
- var renamedPipeline = __assign(__assign({}, pipeline), {
184
- // <- TODO: [🪓] This should be without `as $PipelineJson`
185
- parameters: __spreadArray([], __read(pipeline.parameters), false), tasks: __spreadArray([], __read(pipeline.tasks), false) });
186
- try {
187
- for (var _c = __values(renamedPipeline.parameters), _d = _c.next(); !_d.done; _d = _c.next()) {
188
- var parameter = _d.value;
189
- if (parameter.name !== oldParameterName) {
190
- continue;
191
- }
192
- parameter.name = newParameterName;
193
- }
194
- }
195
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
196
- finally {
197
- try {
198
- if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
199
- }
200
- finally { if (e_1) throw e_1.error; }
201
- }
202
- try {
203
- for (var _e = __values(renamedPipeline.tasks), _f = _e.next(); !_f.done; _f = _e.next()) {
204
- var task = _f.value;
205
- if (task.resultingParameterName === oldParameterName) {
206
- task.resultingParameterName = newParameterName;
207
- }
208
- task.dependentParameterNames = task.dependentParameterNames.map(function (dependentParameterName) {
209
- return dependentParameterName === oldParameterName ? newParameterName : dependentParameterName;
210
- });
211
- task.content = task.content.replace(new RegExp("{".concat(oldParameterName, "}"), 'g'), "{".concat(newParameterName, "}"));
212
- task.title = task.title.replace(new RegExp("{".concat(oldParameterName, "}"), 'g'), "{".concat(newParameterName, "}"));
213
- task.description =
214
- task.description === undefined
215
- ? undefined
216
- : task.description.replace(new RegExp("{".concat(oldParameterName, "}"), 'g'), "{".concat(newParameterName, "}"));
217
- }
218
- }
219
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
220
- finally {
221
- try {
222
- if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
223
- }
224
- finally { if (e_2) throw e_2.error; }
158
+ function just(value) {
159
+ if (value === undefined) {
160
+ return undefined;
225
161
  }
226
- return renamedPipeline;
162
+ return value;
227
163
  }
228
164
 
229
165
  /**
@@ -270,56 +206,6 @@ Object.freeze({
270
206
  * TODO: [🧠][🧜‍♂️] Maybe join remoteUrl and path into single value
271
207
  */
272
208
 
273
- /**
274
- * Orders JSON object by keys
275
- *
276
- * @returns The same type of object as the input re-ordered
277
- * @public exported from `@promptbook/utils`
278
- */
279
- function orderJson(options) {
280
- var value = options.value, order = options.order;
281
- var orderedValue = __assign(__assign({}, (order === undefined ? {} : Object.fromEntries(order.map(function (key) { return [key, undefined]; })))), value);
282
- return orderedValue;
283
- }
284
-
285
- /**
286
- * Freezes the given object and all its nested objects recursively
287
- *
288
- * Note: `$` is used to indicate that this function is not a pure function - it mutates given object
289
- * Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
290
- *
291
- * @returns The same object as the input, but deeply frozen
292
- * @public exported from `@promptbook/utils`
293
- */
294
- function $deepFreeze(objectValue) {
295
- var e_1, _a;
296
- if (Array.isArray(objectValue)) {
297
- return Object.freeze(objectValue.map(function (item) { return $deepFreeze(item); }));
298
- }
299
- var propertyNames = Object.getOwnPropertyNames(objectValue);
300
- try {
301
- for (var propertyNames_1 = __values(propertyNames), propertyNames_1_1 = propertyNames_1.next(); !propertyNames_1_1.done; propertyNames_1_1 = propertyNames_1.next()) {
302
- var propertyName = propertyNames_1_1.value;
303
- var value = objectValue[propertyName];
304
- if (value && typeof value === 'object') {
305
- $deepFreeze(value);
306
- }
307
- }
308
- }
309
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
310
- finally {
311
- try {
312
- if (propertyNames_1_1 && !propertyNames_1_1.done && (_a = propertyNames_1.return)) _a.call(propertyNames_1);
313
- }
314
- finally { if (e_1) throw e_1.error; }
315
- }
316
- Object.freeze(objectValue);
317
- return objectValue;
318
- }
319
- /**
320
- * TODO: [🧠] Is there a way how to meaningfully test this utility
321
- */
322
-
323
209
  /**
324
210
  * Make error report URL for the given error
325
211
  *
@@ -355,216 +241,3752 @@ var UnexpectedError = /** @class */ (function (_super) {
355
241
  }(Error));
356
242
 
357
243
  /**
358
- * Checks if the value is [🚉] serializable as JSON
359
- * If not, throws an UnexpectedError with a rich error message and tracking
244
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
360
245
  *
361
- * - Almost all primitives are serializable BUT:
362
- * - `undefined` is not serializable
363
- * - `NaN` is not serializable
364
- * - Objects and arrays are serializable if all their properties are serializable
365
- * - Functions are not serializable
366
- * - Circular references are not serializable
367
- * - `Date` objects are not serializable
368
- * - `Map` and `Set` objects are not serializable
369
- * - `RegExp` objects are not serializable
370
- * - `Error` objects are not serializable
371
- * - `Symbol` objects are not serializable
372
- * - And much more...
373
- *
374
- * @throws UnexpectedError if the value is not serializable as JSON
375
- * @public exported from `@promptbook/utils`
246
+ * @public exported from `@promptbook/core`
376
247
  */
377
- function checkSerializableAsJson(options) {
378
- var e_1, _a;
379
- var value = options.value, name = options.name, message = options.message;
380
- if (value === undefined) {
381
- throw new UnexpectedError("".concat(name, " is undefined"));
382
- }
383
- else if (value === null) {
384
- return;
248
+ var ParseError = /** @class */ (function (_super) {
249
+ __extends(ParseError, _super);
250
+ function ParseError(message) {
251
+ var _this = _super.call(this, message) || this;
252
+ _this.name = 'ParseError';
253
+ Object.setPrototypeOf(_this, ParseError.prototype);
254
+ return _this;
385
255
  }
386
- else if (typeof value === 'boolean') {
387
- return;
256
+ return ParseError;
257
+ }(Error));
258
+ /**
259
+ * TODO: Maybe split `ParseError` and `ApplyError`
260
+ */
261
+
262
+ /**
263
+ * Parses the boilerplate command
264
+ *
265
+ * Note: @@@ This command is used as boilerplate for new commands - it should NOT be used in any `.book.md` file
266
+ *
267
+ * @see `documentationUrl` for more details
268
+ * @private within the commands folder
269
+ */
270
+ var boilerplateCommandParser = {
271
+ /**
272
+ * Name of the command
273
+ */
274
+ name: 'BOILERPLATE',
275
+ /**
276
+ * Aliases for the BOILERPLATE command
277
+ */
278
+ aliasNames: ['BP'],
279
+ /**
280
+ * BOILERPLATE command can be used in:
281
+ */
282
+ isUsedInPipelineHead: true,
283
+ isUsedInPipelineTask: true,
284
+ /**
285
+ * Description of the BOILERPLATE command
286
+ */
287
+ description: "@@",
288
+ /**
289
+ * Link to documentation
290
+ */
291
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/@@',
292
+ /**
293
+ * Example usages of the BOILERPLATE command
294
+ */
295
+ examples: ['BOILERPLATE foo', 'BOILERPLATE bar', 'BP foo', 'BP bar'],
296
+ /**
297
+ * Parses the BOILERPLATE command
298
+ */
299
+ parse: function (input) {
300
+ var args = input.args;
301
+ if (args.length !== 1) {
302
+ throw new ParseError("BOILERPLATE command requires exactly one argument");
303
+ }
304
+ var value = args[0].toLowerCase();
305
+ if (value.includes('brr')) {
306
+ throw new ParseError("BOILERPLATE value can not contain brr");
307
+ }
308
+ return {
309
+ type: 'BOILERPLATE',
310
+ value: value,
311
+ };
312
+ },
313
+ /**
314
+ * Apply the BOILERPLATE command to the `pipelineJson`
315
+ *
316
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
317
+ */
318
+ $applyToPipelineJson: function (command, $pipelineJson) {
319
+ throw new ParseError("BOILERPLATE command is only for testing purposes and should not be used in the .book.md file");
320
+ },
321
+ /**
322
+ * Apply the BOILERPLATE command to the `pipelineJson`
323
+ *
324
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
325
+ */
326
+ $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
327
+ throw new ParseError("BOILERPLATE command is only for testing purposes and should not be used in the .book.md file");
328
+ },
329
+ /**
330
+ * Converts the BOILERPLATE command back to string
331
+ *
332
+ * Note: This is used in `pipelineJsonToString` utility
333
+ */
334
+ stringify: function (command) {
335
+ return "---"; // <- TODO: [🛋] Implement
336
+ },
337
+ /**
338
+ * Reads the BOILERPLATE command from the `PipelineJson`
339
+ *
340
+ * Note: This is used in `pipelineJsonToString` utility
341
+ */
342
+ takeFromPipelineJson: function (pipelineJson) {
343
+ throw new ParseError("BOILERPLATE command is only for testing purposes and should not be used in the .book.md file");
344
+ },
345
+ /**
346
+ * Reads the BOILERPLATE command from the `TaskJson`
347
+ *
348
+ * Note: This is used in `pipelineJsonToString` utility
349
+ */
350
+ takeFromTaskJson: function ($taskJson) {
351
+ throw new ParseError("BOILERPLATE command is only for testing purposes and should not be used in the .book.md file");
352
+ },
353
+ };
354
+
355
+ /**
356
+ * This error type indicates that some part of the code is not implemented yet
357
+ *
358
+ * @public exported from `@promptbook/core`
359
+ */
360
+ var NotYetImplementedError = /** @class */ (function (_super) {
361
+ __extends(NotYetImplementedError, _super);
362
+ function NotYetImplementedError(message) {
363
+ var _this = _super.call(this, spaceTrim$1(function (block) { return "\n ".concat(block(message), "\n\n Note: This feature is not implemented yet but it will be soon.\n\n If you want speed up the implementation or just read more, look here:\n https://github.com/webgptorg/promptbook\n\n Or contact us on me@pavolhejny.com\n\n "); })) || this;
364
+ _this.name = 'NotYetImplementedError';
365
+ Object.setPrototypeOf(_this, NotYetImplementedError.prototype);
366
+ return _this;
388
367
  }
389
- else if (typeof value === 'number' && !isNaN(value)) {
390
- return;
368
+ return NotYetImplementedError;
369
+ }(Error));
370
+
371
+ /**
372
+ * Tests if given string is valid semantic version
373
+ *
374
+ * Note: There are two simmilar functions:
375
+ * - `isValidSemanticVersion` which tests any semantic version
376
+ * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
377
+ *
378
+ * @public exported from `@promptbook/utils`
379
+ */
380
+ function isValidSemanticVersion(version) {
381
+ if (typeof version !== 'string') {
382
+ return false;
391
383
  }
392
- else if (typeof value === 'string') {
393
- return;
384
+ if (version.startsWith('0.0.0')) {
385
+ return false;
394
386
  }
395
- else if (typeof value === 'symbol') {
396
- throw new UnexpectedError("".concat(name, " is symbol"));
387
+ return /^\d+\.\d+\.\d+(-\d+)?$/i.test(version);
388
+ }
389
+
390
+ /**
391
+ * Tests if given string is valid promptbook version
392
+ * It looks into list of known promptbook versions.
393
+ *
394
+ * @see https://www.npmjs.com/package/promptbook?activeTab=versions
395
+ * Note: When you are using for example promptbook 2.0.0 and there already is promptbook 3.0.0 it don`t know about it.
396
+ * Note: There are two simmilar functions:
397
+ * - `isValidSemanticVersion` which tests any semantic version
398
+ * - `isValidPromptbookVersion` *(this one)* which tests just Promptbook versions
399
+ *
400
+ * @public exported from `@promptbook/utils`
401
+ */
402
+ function isValidPromptbookVersion(version) {
403
+ if (!isValidSemanticVersion(version)) {
404
+ return false;
397
405
  }
398
- else if (typeof value === 'function') {
399
- throw new UnexpectedError("".concat(name, " is function"));
406
+ if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
407
+ return false;
400
408
  }
401
- else if (typeof value === 'object' && Array.isArray(value)) {
402
- for (var i = 0; i < value.length; i++) {
403
- checkSerializableAsJson({ name: "".concat(name, "[").concat(i, "]"), value: value[i], message: message });
409
+ // <- TODO: [main] !!3 Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
410
+ return true;
411
+ }
412
+
413
+ /**
414
+ * Parses the BOOK_VERSION command
415
+ *
416
+ * @see `documentationUrl` for more details
417
+ * @public exported from `@promptbook/editable`
418
+ */
419
+ var bookVersionCommandParser = {
420
+ /**
421
+ * Name of the command
422
+ */
423
+ name: 'BOOK_VERSION',
424
+ aliasNames: ['PTBK_VERSION', 'PROMPTBOOK_VERSION', 'BOOK'],
425
+ /**
426
+ * BOILERPLATE command can be used in:
427
+ */
428
+ isUsedInPipelineHead: true,
429
+ isUsedInPipelineTask: false,
430
+ /**
431
+ * Description of the BOOK_VERSION command
432
+ */
433
+ description: "Which version of the Book language is the .book.md using",
434
+ /**
435
+ * Link to documentation
436
+ */
437
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/69',
438
+ /**
439
+ * Example usages of the BOOK_VERSION command
440
+ */
441
+ examples: ["BOOK VERSION ".concat(BOOK_LANGUAGE_VERSION), "BOOK ".concat(BOOK_LANGUAGE_VERSION)],
442
+ /**
443
+ * Parses the BOOK_VERSION command
444
+ */
445
+ parse: function (input) {
446
+ var args = input.args;
447
+ var bookVersion = args.pop();
448
+ if (bookVersion === undefined) {
449
+ throw new ParseError("Version is required");
404
450
  }
405
- }
406
- else if (typeof value === 'object') {
407
- if (value instanceof Date) {
408
- throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is Date\n\n Use `string_date_iso8601` instead\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
451
+ if (!isValidPromptbookVersion(bookVersion)) {
452
+ throw new ParseError("Invalid Promptbook version \"".concat(bookVersion, "\""));
409
453
  }
410
- else if (value instanceof Map) {
411
- throw new UnexpectedError("".concat(name, " is Map"));
412
- }
413
- else if (value instanceof Set) {
414
- throw new UnexpectedError("".concat(name, " is Set"));
454
+ if (args.length > 0 && !(((args.length === 1 && args[0]) || '').toUpperCase() === 'VERSION')) {
455
+ throw new ParseError("Can not have more than one Promptbook version");
415
456
  }
416
- else if (value instanceof RegExp) {
417
- throw new UnexpectedError("".concat(name, " is RegExp"));
457
+ return {
458
+ type: 'BOOK_VERSION',
459
+ bookVersion: bookVersion,
460
+ };
461
+ },
462
+ /**
463
+ * Apply the BOOK_VERSION command to the `pipelineJson`
464
+ *
465
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
466
+ */
467
+ $applyToPipelineJson: function (command, $pipelineJson) {
468
+ // TODO: Warn if the version is overridden
469
+ $pipelineJson.bookVersion = command.bookVersion;
470
+ },
471
+ /**
472
+ * Converts the BOOK_VERSION command back to string
473
+ *
474
+ * Note: This is used in `pipelineJsonToString` utility
475
+ */
476
+ stringify: function (command) {
477
+ return "---"; // <- TODO: [🛋] Implement
478
+ },
479
+ /**
480
+ * Reads the BOOK_VERSION command from the `PipelineJson`
481
+ *
482
+ * Note: This is used in `pipelineJsonToString` utility
483
+ */
484
+ takeFromPipelineJson: function (pipelineJson) {
485
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
486
+ },
487
+ };
488
+
489
+ /**
490
+ * Units of text measurement
491
+ *
492
+ * @see https://github.com/webgptorg/promptbook/discussions/30
493
+ * @public exported from `@promptbook/core`
494
+ */
495
+ var EXPECTATION_UNITS = ['CHARACTERS', 'WORDS', 'SENTENCES', 'LINES', 'PARAGRAPHS', 'PAGES'];
496
+ /**
497
+ * TODO: [💝] Unite object for expecting amount and format - remove format
498
+ */
499
+
500
+ /**
501
+ * Function parseNumber will parse number from string
502
+ *
503
+ * Unlike Number.parseInt, Number.parseFloat it will never ever result in NaN
504
+ * Note: it also works only with decimal numbers
505
+ *
506
+ * @returns parsed number
507
+ * @throws {ParseError} if the value is not a number
508
+ *
509
+ * @public exported from `@promptbook/utils`
510
+ */
511
+ function parseNumber(value) {
512
+ var originalValue = value;
513
+ if (typeof value === 'number') {
514
+ value = value.toString(); // <- TODO: Maybe more efficient way to do this
515
+ }
516
+ if (typeof value !== 'string') {
517
+ return 0;
518
+ }
519
+ value = value.trim();
520
+ if (value.startsWith('+')) {
521
+ return parseNumber(value.substring(1));
522
+ }
523
+ if (value.startsWith('-')) {
524
+ var number = parseNumber(value.substring(1));
525
+ if (number === 0) {
526
+ return 0; // <- Note: To prevent -0
418
527
  }
419
- else if (value instanceof Error) {
420
- throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is unserialized Error\n\n Use function `serializeError`\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n\n "); }));
528
+ return -number;
529
+ }
530
+ value = value.replace(/,/g, '.');
531
+ value = value.toUpperCase();
532
+ if (value === '') {
533
+ return 0;
534
+ }
535
+ if (value === '♾' || value.startsWith('INF')) {
536
+ return Infinity;
537
+ }
538
+ if (value.includes('/')) {
539
+ var _a = __read(value.split('/'), 2), numerator_ = _a[0], denominator_ = _a[1];
540
+ var numerator = parseNumber(numerator_);
541
+ var denominator = parseNumber(denominator_);
542
+ if (denominator === 0) {
543
+ throw new ParseError("Unable to parse number from \"".concat(originalValue, "\" because denominator is zero"));
421
544
  }
422
- else {
545
+ return numerator / denominator;
546
+ }
547
+ if (/^(NAN|NULL|NONE|UNDEFINED|ZERO|NO.*)$/.test(value)) {
548
+ return 0;
549
+ }
550
+ if (value.includes('E')) {
551
+ var _b = __read(value.split('E'), 2), significand = _b[0], exponent = _b[1];
552
+ return parseNumber(significand) * Math.pow(10, parseNumber(exponent));
553
+ }
554
+ if (!/^[0-9.]+$/.test(value) || value.split('.').length > 2) {
555
+ throw new ParseError("Unable to parse number from \"".concat(originalValue, "\""));
556
+ }
557
+ var num = parseFloat(value);
558
+ if (isNaN(num)) {
559
+ throw new ParseError("Unexpected NaN when parsing number from \"".concat(originalValue, "\""));
560
+ }
561
+ return num;
562
+ }
563
+ /**
564
+ * TODO: Maybe use sth. like safe-eval in fraction/calculation case @see https://www.npmjs.com/package/safe-eval
565
+ * TODO: [🧠][🌻] Maybe export through `@promptbook/markdown-utils` not `@promptbook/utils`
566
+ */
567
+
568
+ /**
569
+ * Parses the expect command
570
+ *
571
+ * @see `documentationUrl` for more details
572
+ * @public exported from `@promptbook/editable`
573
+ */
574
+ var expectCommandParser = {
575
+ /**
576
+ * Name of the command
577
+ */
578
+ name: 'EXPECT',
579
+ /**
580
+ * BOILERPLATE command can be used in:
581
+ */
582
+ isUsedInPipelineHead: false,
583
+ isUsedInPipelineTask: true,
584
+ /**
585
+ * Description of the FORMAT command
586
+ */
587
+ description: spaceTrim("\n Expect command describes the desired output of the task *(after post-processing)*\n It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.\n "),
588
+ /**
589
+ * Link to documentation
590
+ */
591
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/30',
592
+ /**
593
+ * Example usages of the FORMAT command
594
+ */
595
+ examples: [
596
+ 'EXPECT MIN 100 Characters',
597
+ 'EXPECT MAX 10 Words',
598
+ 'EXPECT EXACTLY 3 Sentences',
599
+ 'EXPECT EXACTLY 1 Paragraph',
600
+ // <- TODO: 'EXPECT 1 Paragraph',
601
+ ],
602
+ /**
603
+ * Parses the FORMAT command
604
+ */
605
+ parse: function (input) {
606
+ var e_1, _a;
607
+ var args = input.args;
608
+ try {
609
+ var sign = void 0;
610
+ var signRaw = args.shift();
611
+ if (/^exact/i.test(signRaw)) {
612
+ sign = 'EXACTLY';
613
+ }
614
+ else if (/^min/i.test(signRaw)) {
615
+ sign = 'MINIMUM';
616
+ }
617
+ else if (/^max/i.test(signRaw)) {
618
+ sign = 'MAXIMUM';
619
+ }
620
+ else {
621
+ throw new ParseError("Invalid sign \"".concat(signRaw, "\", expected EXACTLY, MIN or MAX"));
622
+ }
623
+ var amountRaw = args.shift();
624
+ var amount = parseNumber(amountRaw);
625
+ if (amount < 0) {
626
+ throw new ParseError('Amount must be positive number or zero');
627
+ }
628
+ if (amount !== Math.floor(amount)) {
629
+ throw new ParseError('Amount must be whole number');
630
+ }
631
+ var unitRaw = args.shift();
632
+ var unit = undefined;
423
633
  try {
424
- for (var _b = __values(Object.entries(value)), _c = _b.next(); !_c.done; _c = _b.next()) {
425
- var _d = __read(_c.value, 2), subName = _d[0], subValue = _d[1];
426
- if (subValue === undefined) {
427
- // Note: undefined in object is serializable - it is just omited
428
- continue;
634
+ for (var EXPECTATION_UNITS_1 = __values(EXPECTATION_UNITS), EXPECTATION_UNITS_1_1 = EXPECTATION_UNITS_1.next(); !EXPECTATION_UNITS_1_1.done; EXPECTATION_UNITS_1_1 = EXPECTATION_UNITS_1.next()) {
635
+ var existingUnit = EXPECTATION_UNITS_1_1.value;
636
+ var existingUnitText = existingUnit;
637
+ existingUnitText = existingUnitText.substring(0, existingUnitText.length - 1);
638
+ if (existingUnitText === 'CHARACTER') {
639
+ existingUnitText = 'CHAR';
640
+ }
641
+ if (new RegExp("^".concat(existingUnitText.toLowerCase())).test(unitRaw.toLowerCase()) ||
642
+ new RegExp("^".concat(unitRaw.toLowerCase())).test(existingUnitText.toLowerCase())) {
643
+ if (unit !== undefined) {
644
+ throw new ParseError("Ambiguous unit \"".concat(unitRaw, "\""));
645
+ }
646
+ unit = existingUnit;
429
647
  }
430
- checkSerializableAsJson({ name: "".concat(name, ".").concat(subName), value: subValue, message: message });
431
648
  }
432
649
  }
433
650
  catch (e_1_1) { e_1 = { error: e_1_1 }; }
434
651
  finally {
435
652
  try {
436
- if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
653
+ if (EXPECTATION_UNITS_1_1 && !EXPECTATION_UNITS_1_1.done && (_a = EXPECTATION_UNITS_1.return)) _a.call(EXPECTATION_UNITS_1);
437
654
  }
438
655
  finally { if (e_1) throw e_1.error; }
439
656
  }
440
- try {
441
- JSON.stringify(value); // <- TODO: [0]
657
+ if (unit === undefined) {
658
+ throw new ParseError("Invalid unit \"".concat(unitRaw, "\""));
442
659
  }
443
- catch (error) {
444
- if (!(error instanceof Error)) {
445
- throw error;
446
- }
447
- throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is not serializable\n\n ").concat(block(error.stack || error.message), "\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
660
+ return {
661
+ type: 'EXPECT',
662
+ sign: sign,
663
+ unit: unit,
664
+ amount: amount,
665
+ };
666
+ }
667
+ catch (error) {
668
+ if (!(error instanceof Error)) {
669
+ throw error;
448
670
  }
449
- /*
450
- TODO: [0] Is there some more elegant way to check circular references?
451
- const seen = new Set();
452
- const stack = [{ value }];
453
- while (stack.length > 0) {
454
- const { value } = stack.pop()!;
455
- if (typeof value === 'object' && value !== null) {
456
- if (seen.has(value)) {
457
- throw new UnexpectedError(`${name} has circular reference`);
458
- }
459
- seen.add(value);
460
- if (Array.isArray(value)) {
461
- stack.push(...value.map((value) => ({ value })));
462
- } else {
463
- stack.push(...Object.values(value).map((value) => ({ value })));
464
- }
465
- }
671
+ throw new ParseError(spaceTrim(function (block) {
672
+ return "\n Invalid FORMAT command\n ".concat(block(error.message), ":\n ");
673
+ }));
674
+ }
675
+ },
676
+ /**
677
+ * Apply the FORMAT command to the `pipelineJson`
678
+ *
679
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
680
+ */
681
+ $applyToTaskJson: function (command, $taskJson) {
682
+ // eslint-disable-next-line no-case-declarations
683
+ var unit = command.unit.toLowerCase();
684
+ $taskJson.expectations = $taskJson.expectations || {};
685
+ $taskJson.expectations[unit] = $taskJson.expectations[unit] || {};
686
+ if (command.sign === 'MINIMUM' || command.sign === 'EXACTLY') {
687
+ if ($taskJson.expectations[unit].min !== undefined) {
688
+ throw new ParseError("Already defined minumum ".concat($taskJson.expectations[unit].min, " ").concat(command.unit.toLowerCase(), ", now trying to redefine it to ").concat(command.amount));
466
689
  }
467
- */
468
- return;
690
+ $taskJson.expectations[unit].min = command.amount;
691
+ } /* not else */
692
+ if (command.sign === 'MAXIMUM' || command.sign === 'EXACTLY') {
693
+ if ($taskJson.expectations[unit].max !== undefined) {
694
+ throw new ParseError("Already defined maximum ".concat($taskJson.expectations[unit].max, " ").concat(command.unit.toLowerCase(), ", now trying to redefine it to ").concat(command.amount));
695
+ }
696
+ $taskJson.expectations[unit].max = command.amount;
469
697
  }
698
+ },
699
+ /**
700
+ * Converts the FORMAT command back to string
701
+ *
702
+ * Note: This is used in `pipelineJsonToString` utility
703
+ */
704
+ stringify: function (command) {
705
+ return "---"; // <- TODO: [🛋] Implement
706
+ },
707
+ /**
708
+ * Reads the FORMAT command from the `TaskJson`
709
+ *
710
+ * Note: This is used in `pipelineJsonToString` utility
711
+ */
712
+ takeFromTaskJson: function ($taskJson) {
713
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
714
+ },
715
+ };
716
+
717
+ /**
718
+ * This error indicates problems parsing the format value
719
+ *
720
+ * For example, when the format value is not a valid JSON or CSV
721
+ * This is not thrown directly but in extended classes
722
+ *
723
+ * @public exported from `@promptbook/core`
724
+ */
725
+ var AbstractFormatError = /** @class */ (function (_super) {
726
+ __extends(AbstractFormatError, _super);
727
+ // Note: To allow instanceof do not put here error `name`
728
+ // public readonly name = 'AbstractFormatError';
729
+ function AbstractFormatError(message) {
730
+ var _this = _super.call(this, message) || this;
731
+ Object.setPrototypeOf(_this, AbstractFormatError.prototype);
732
+ return _this;
470
733
  }
471
- else {
472
- throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is unknown type\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
473
- }
474
- }
734
+ return AbstractFormatError;
735
+ }(Error));
736
+
475
737
  /**
476
- * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
477
- * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
478
- * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
738
+ * This error indicates problem with parsing of CSV
739
+ *
740
+ * @public exported from `@promptbook/core`
479
741
  */
742
+ var CsvFormatError = /** @class */ (function (_super) {
743
+ __extends(CsvFormatError, _super);
744
+ function CsvFormatError(message) {
745
+ var _this = _super.call(this, message) || this;
746
+ _this.name = 'CsvFormatError';
747
+ Object.setPrototypeOf(_this, CsvFormatError.prototype);
748
+ return _this;
749
+ }
750
+ return CsvFormatError;
751
+ }(AbstractFormatError));
480
752
 
481
753
  /**
482
754
  * @@@
483
755
  *
756
+ * @public exported from `@promptbook/core`
757
+ */
758
+ var MANDATORY_CSV_SETTINGS = Object.freeze({
759
+ header: true,
760
+ // encoding: 'utf-8',
761
+ });
762
+
763
+ /**
764
+ * Definition for CSV spreadsheet
765
+ *
766
+ * @public exported from `@promptbook/core`
767
+ * <- TODO: [🏢] Export from package `@promptbook/csv`
768
+ */
769
+ var CsvFormatDefinition = {
770
+ formatName: 'CSV',
771
+ aliases: ['SPREADSHEET', 'TABLE'],
772
+ isValid: function (value, settings, schema) {
773
+ return true;
774
+ },
775
+ canBeValid: function (partialValue, settings, schema) {
776
+ return true;
777
+ },
778
+ heal: function (value, settings, schema) {
779
+ throw new Error('Not implemented');
780
+ },
781
+ subvalueDefinitions: [
782
+ {
783
+ subvalueName: 'ROW',
784
+ mapValues: function (value, outputParameterName, settings, mapCallback) {
785
+ return __awaiter(this, void 0, void 0, function () {
786
+ var csv, mappedData;
787
+ var _this = this;
788
+ return __generator(this, function (_a) {
789
+ switch (_a.label) {
790
+ case 0:
791
+ csv = parse(value, __assign(__assign({}, settings), MANDATORY_CSV_SETTINGS));
792
+ if (csv.errors.length !== 0) {
793
+ throw new CsvFormatError(spaceTrim(function (block) { return "\n CSV parsing error\n\n Error(s) from CSV parsing:\n ".concat(block(csv.errors.map(function (error) { return error.message; }).join('\n\n')), "\n\n The CSV setings:\n ").concat(block(JSON.stringify(__assign(__assign({}, settings), MANDATORY_CSV_SETTINGS), null, 2)), "\n\n The CSV data:\n ").concat(block(value), "\n "); }));
794
+ }
795
+ return [4 /*yield*/, Promise.all(csv.data.map(function (row, index) { return __awaiter(_this, void 0, void 0, function () {
796
+ var _a, _b;
797
+ var _c;
798
+ return __generator(this, function (_d) {
799
+ switch (_d.label) {
800
+ case 0:
801
+ if (row[outputParameterName]) {
802
+ throw new CsvFormatError("Can not overwrite existing column \"".concat(outputParameterName, "\" in CSV row"));
803
+ }
804
+ _a = [__assign({}, row)];
805
+ _c = {};
806
+ _b = outputParameterName;
807
+ return [4 /*yield*/, mapCallback(row, index)];
808
+ case 1: return [2 /*return*/, __assign.apply(void 0, _a.concat([(_c[_b] = _d.sent(), _c)]))];
809
+ }
810
+ });
811
+ }); }))];
812
+ case 1:
813
+ mappedData = _a.sent();
814
+ return [2 /*return*/, unparse(mappedData, __assign(__assign({}, settings), MANDATORY_CSV_SETTINGS))];
815
+ }
816
+ });
817
+ });
818
+ },
819
+ },
820
+ {
821
+ subvalueName: 'CELL',
822
+ mapValues: function (value, outputParameterName, settings, mapCallback) {
823
+ return __awaiter(this, void 0, void 0, function () {
824
+ var csv, mappedData;
825
+ var _this = this;
826
+ return __generator(this, function (_a) {
827
+ switch (_a.label) {
828
+ case 0:
829
+ csv = parse(value, __assign(__assign({}, settings), MANDATORY_CSV_SETTINGS));
830
+ if (csv.errors.length !== 0) {
831
+ throw new CsvFormatError(spaceTrim(function (block) { return "\n CSV parsing error\n\n Error(s) from CSV parsing:\n ".concat(block(csv.errors.map(function (error) { return error.message; }).join('\n\n')), "\n\n The CSV setings:\n ").concat(block(JSON.stringify(__assign(__assign({}, settings), MANDATORY_CSV_SETTINGS), null, 2)), "\n\n The CSV data:\n ").concat(block(value), "\n "); }));
832
+ }
833
+ return [4 /*yield*/, Promise.all(csv.data.map(function (row, rowIndex) { return __awaiter(_this, void 0, void 0, function () {
834
+ var _this = this;
835
+ return __generator(this, function (_a) {
836
+ return [2 /*return*/, /* not await */ Promise.all(Object.entries(row).map(function (_a, columnIndex) {
837
+ var _b = __read(_a, 2), key = _b[0], value = _b[1];
838
+ return __awaiter(_this, void 0, void 0, function () {
839
+ var index;
840
+ var _c;
841
+ return __generator(this, function (_d) {
842
+ index = rowIndex * Object.keys(row).length + columnIndex;
843
+ return [2 /*return*/, /* not await */ mapCallback((_c = {}, _c[key] = value, _c), index)];
844
+ });
845
+ });
846
+ }))];
847
+ });
848
+ }); }))];
849
+ case 1:
850
+ mappedData = _a.sent();
851
+ return [2 /*return*/, unparse(mappedData, __assign(__assign({}, settings), MANDATORY_CSV_SETTINGS))];
852
+ }
853
+ });
854
+ });
855
+ },
856
+ },
857
+ ],
858
+ };
859
+ /**
860
+ * TODO: [🍓] In `CsvFormatDefinition` implement simple `isValid`
861
+ * TODO: [🍓] In `CsvFormatDefinition` implement partial `canBeValid`
862
+ * TODO: [🍓] In `CsvFormatDefinition` implement `heal
863
+ * TODO: [🍓] In `CsvFormatDefinition` implement `subvalueDefinitions`
864
+ * TODO: [🏢] Allow to expect something inside CSV objects and other formats
865
+ */
866
+
867
+ /**
868
+ * Function isValidJsonString will tell you if the string is valid JSON or not
869
+ *
484
870
  * @public exported from `@promptbook/utils`
485
871
  */
486
- function deepClone(objectValue) {
487
- return JSON.parse(JSON.stringify(objectValue));
488
- /*
489
- TODO: [🧠] Is there a better implementation?
490
- > const propertyNames = Object.getOwnPropertyNames(objectValue);
491
- > for (const propertyName of propertyNames) {
492
- > const value = (objectValue as really_any)[propertyName];
493
- > if (value && typeof value === 'object') {
494
- > deepClone(value);
495
- > }
496
- > }
497
- > return Object.assign({}, objectValue);
498
- */
872
+ function isValidJsonString(value /* <- [👨‍⚖️] */) {
873
+ try {
874
+ JSON.parse(value);
875
+ return true;
876
+ }
877
+ catch (error) {
878
+ if (!(error instanceof Error)) {
879
+ throw error;
880
+ }
881
+ if (error.message.includes('Unexpected token')) {
882
+ return false;
883
+ }
884
+ return false;
885
+ }
499
886
  }
887
+
500
888
  /**
501
- * TODO: [🧠] Is there a way how to meaningfully test this utility
889
+ * Definition for JSON format
890
+ *
891
+ * @private still in development [🏢]
892
+ */
893
+ var JsonFormatDefinition = {
894
+ formatName: 'JSON',
895
+ mimeType: 'application/json',
896
+ isValid: function (value, settings, schema) {
897
+ return isValidJsonString(value);
898
+ },
899
+ canBeValid: function (partialValue, settings, schema) {
900
+ return true;
901
+ },
902
+ heal: function (value, settings, schema) {
903
+ throw new Error('Not implemented');
904
+ },
905
+ subvalueDefinitions: [],
906
+ };
907
+ /**
908
+ * TODO: [🧠] Maybe propper instance of object
909
+ * TODO: [0] Make string_serialized_json
910
+ * TODO: [1] Make type for JSON Settings and Schema
911
+ * TODO: [🧠] What to use for validating JSONs - JSON Schema, ZoD, typescript types/interfaces,...?
912
+ * TODO: [🍓] In `JsonFormatDefinition` implement simple `isValid`
913
+ * TODO: [🍓] In `JsonFormatDefinition` implement partial `canBeValid`
914
+ * TODO: [🍓] In `JsonFormatDefinition` implement `heal
915
+ * TODO: [🍓] In `JsonFormatDefinition` implement `subvalueDefinitions`
916
+ * TODO: [🏢] Allow to expect something inside JSON objects and other formats
502
917
  */
503
918
 
504
919
  /**
505
- * Utility to export a JSON object from a function
506
- *
507
- * 1) Checks if the value is serializable as JSON
508
- * 2) Makes a deep clone of the object
509
- * 2) Orders the object properties
510
- * 2) Deeply freezes the cloned object
920
+ * Definition for any text - this will be always valid
511
921
  *
512
- * Note: This function does not mutates the given object
922
+ * Note: This is not useful for validation, but for splitting and mapping with `subvalueDefinitions`
513
923
  *
514
- * @returns The same type of object as the input but read-only and re-ordered
515
- * @public exported from `@promptbook/utils`
924
+ * @public exported from `@promptbook/core`
516
925
  */
517
- function exportJson(options) {
518
- var name = options.name, value = options.value, order = options.order, message = options.message;
519
- checkSerializableAsJson({ name: name, value: value, message: message });
520
- var orderedValue =
521
- // TODO: Fix error "Type instantiation is excessively deep and possibly infinite."
522
- // eslint-disable-next-line @typescript-eslint/ban-ts-comment
523
- // @ts-ignore
524
- order === undefined
525
- ? deepClone(value)
526
- : orderJson({
527
- value: value,
528
- // <- Note: checkSerializableAsJson asserts that the value is serializable as JSON
529
- order: order,
530
- });
531
- $deepFreeze(orderedValue);
532
- return orderedValue;
533
- }
926
+ var TextFormatDefinition = {
927
+ formatName: 'TEXT',
928
+ isValid: function (value) {
929
+ return typeof value === 'string';
930
+ },
931
+ canBeValid: function (partialValue) {
932
+ return typeof partialValue === 'string';
933
+ },
934
+ heal: function () {
935
+ throw new UnexpectedError('It does not make sense to call `TextFormatDefinition.heal`');
936
+ },
937
+ subvalueDefinitions: [
938
+ {
939
+ subvalueName: 'LINE',
940
+ mapValues: function (value, outputParameterName, settings, mapCallback) {
941
+ return __awaiter(this, void 0, void 0, function () {
942
+ var lines, mappedLines;
943
+ return __generator(this, function (_a) {
944
+ switch (_a.label) {
945
+ case 0:
946
+ lines = value.split('\n');
947
+ return [4 /*yield*/, Promise.all(lines.map(function (lineContent, lineNumber) {
948
+ // TODO: [🧠] Maybe option to skip empty line
949
+ /* not await */ return mapCallback({
950
+ lineContent: lineContent,
951
+ // TODO: [🧠] Maybe also put here `lineNumber`
952
+ }, lineNumber);
953
+ }))];
954
+ case 1:
955
+ mappedLines = _a.sent();
956
+ return [2 /*return*/, mappedLines.join('\n')];
957
+ }
958
+ });
959
+ });
960
+ },
961
+ },
962
+ // <- TODO: [🧠][🤠] Here should be all words, characters, lines, paragraphs, pages aviable as subvalues
963
+ ],
964
+ };
534
965
  /**
535
- * TODO: [🧠] Is there a way how to meaningfully test this utility
966
+ * TODO: [1] Make type for XML Text and Schema
967
+ * TODO: [🧠][🤠] Here should be all words, characters, lines, paragraphs, pages aviable as subvalues
968
+ * TODO: [🍓] In `TextFormatDefinition` implement simple `isValid`
969
+ * TODO: [🍓] In `TextFormatDefinition` implement partial `canBeValid`
970
+ * TODO: [🍓] In `TextFormatDefinition` implement `heal
971
+ * TODO: [🍓] In `TextFormatDefinition` implement `subvalueDefinitions`
972
+ * TODO: [🏢] Allow to expect something inside each item of list and other formats
536
973
  */
537
974
 
538
975
  /**
539
- * Nonce which is used for replacing things in strings
976
+ * Definition for XML format
540
977
  *
541
- * @private within the repository
978
+ * @private still in development [🏢]
542
979
  */
543
- var REPLACING_NONCE = 'u$k42k%!V2zo34w7Fu#@QUHYPW';
980
+ var XmlFormatDefinition = {
981
+ formatName: 'XML',
982
+ mimeType: 'application/xml',
983
+ isValid: function (value, settings, schema) {
984
+ return true;
985
+ },
986
+ canBeValid: function (partialValue, settings, schema) {
987
+ return true;
988
+ },
989
+ heal: function (value, settings, schema) {
990
+ throw new Error('Not implemented');
991
+ },
992
+ subvalueDefinitions: [],
993
+ };
544
994
  /**
545
- * The names of the parameters that are reserved for special purposes
995
+ * TODO: [🧠] Maybe propper instance of object
996
+ * TODO: [0] Make string_serialized_xml
997
+ * TODO: [1] Make type for XML Settings and Schema
998
+ * TODO: [🧠] What to use for validating XMLs - XSD,...
999
+ * TODO: [🍓] In `XmlFormatDefinition` implement simple `isValid`
1000
+ * TODO: [🍓] In `XmlFormatDefinition` implement partial `canBeValid`
1001
+ * TODO: [🍓] In `XmlFormatDefinition` implement `heal
1002
+ * TODO: [🍓] In `XmlFormatDefinition` implement `subvalueDefinitions`
1003
+ * TODO: [🏢] Allow to expect something inside XML and other formats
1004
+ */
1005
+
1006
+ /**
1007
+ * Definitions for all formats supported by Promptbook
546
1008
  *
547
- * @public exported from `@promptbook/core`
1009
+ * @private internal index of `...` <- TODO [🏢]
548
1010
  */
549
- exportJson({
550
- name: 'RESERVED_PARAMETER_NAMES',
551
- message: "The names of the parameters that are reserved for special purposes",
552
- value: [
553
- 'content',
554
- 'context',
555
- 'knowledge',
556
- 'examples',
557
- 'modelName',
558
- 'currentDate',
559
- // <- TODO: list here all command names
560
- // <- TODO: Add more like 'date', 'modelName',...
561
- // <- TODO: Add [emoji] + instructions ACRY when adding new reserved parameter
562
- ],
563
- });
1011
+ var FORMAT_DEFINITIONS = [
1012
+ JsonFormatDefinition,
1013
+ XmlFormatDefinition,
1014
+ TextFormatDefinition,
1015
+ CsvFormatDefinition,
1016
+ ];
564
1017
  /**
565
1018
  * Note: [💞] Ignore a discrepancy between file name and entity name
566
1019
  */
567
1020
 
1021
+ /**
1022
+ * @@@
1023
+ *
1024
+ * @param text @@@
1025
+ * @returns @@@
1026
+ * @example 'HELLO_WORLD'
1027
+ * @example 'I_LOVE_PROMPTBOOK'
1028
+ * @public exported from `@promptbook/utils`
1029
+ */
1030
+ function normalizeTo_SCREAMING_CASE(text) {
1031
+ var e_1, _a;
1032
+ var charType;
1033
+ var lastCharType = 'OTHER';
1034
+ var normalizedName = '';
1035
+ try {
1036
+ for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
1037
+ var char = text_1_1.value;
1038
+ var normalizedChar = void 0;
1039
+ if (/^[a-z]$/.test(char)) {
1040
+ charType = 'LOWERCASE';
1041
+ normalizedChar = char.toUpperCase();
1042
+ }
1043
+ else if (/^[A-Z]$/.test(char)) {
1044
+ charType = 'UPPERCASE';
1045
+ normalizedChar = char;
1046
+ }
1047
+ else if (/^[0-9]$/.test(char)) {
1048
+ charType = 'NUMBER';
1049
+ normalizedChar = char;
1050
+ }
1051
+ else {
1052
+ charType = 'OTHER';
1053
+ normalizedChar = '_';
1054
+ }
1055
+ if (charType !== lastCharType &&
1056
+ !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
1057
+ !(lastCharType === 'NUMBER') &&
1058
+ !(charType === 'NUMBER')) {
1059
+ normalizedName += '_';
1060
+ }
1061
+ normalizedName += normalizedChar;
1062
+ lastCharType = charType;
1063
+ }
1064
+ }
1065
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1066
+ finally {
1067
+ try {
1068
+ if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
1069
+ }
1070
+ finally { if (e_1) throw e_1.error; }
1071
+ }
1072
+ normalizedName = normalizedName.replace(/_+/g, '_');
1073
+ normalizedName = normalizedName.replace(/_?\/_?/g, '/');
1074
+ normalizedName = normalizedName.replace(/^_/, '');
1075
+ normalizedName = normalizedName.replace(/_$/, '');
1076
+ return normalizedName;
1077
+ }
1078
+ /**
1079
+ * TODO: Tests
1080
+ * > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: 'Moje tabule' })).toEqual('/VtG7sR9rRJqwNEdM2/Moje tabule');
1081
+ * > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: 'ěščřžžýáíúů' })).toEqual('/VtG7sR9rRJqwNEdM2/escrzyaieuu');
1082
+ * > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: ' ahoj ' })).toEqual('/VtG7sR9rRJqwNEdM2/ahoj');
1083
+ * > expect(encodeRoutePath({ uriId: 'VtG7sR9rRJqwNEdM2', name: ' ahoj_ahojAhoj ahoj ' })).toEqual('/VtG7sR9rRJqwNEdM2/ahoj-ahoj-ahoj-ahoj');
1084
+ * TODO: [🌺] Use some intermediate util splitWords
1085
+ */
1086
+
1087
+ /**
1088
+ * Orders JSON object by keys
1089
+ *
1090
+ * @returns The same type of object as the input re-ordered
1091
+ * @public exported from `@promptbook/utils`
1092
+ */
1093
+ function orderJson(options) {
1094
+ var value = options.value, order = options.order;
1095
+ var orderedValue = __assign(__assign({}, (order === undefined ? {} : Object.fromEntries(order.map(function (key) { return [key, undefined]; })))), value);
1096
+ return orderedValue;
1097
+ }
1098
+
1099
+ /**
1100
+ * Freezes the given object and all its nested objects recursively
1101
+ *
1102
+ * Note: `$` is used to indicate that this function is not a pure function - it mutates given object
1103
+ * Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
1104
+ *
1105
+ * @returns The same object as the input, but deeply frozen
1106
+ * @public exported from `@promptbook/utils`
1107
+ */
1108
+ function $deepFreeze(objectValue) {
1109
+ var e_1, _a;
1110
+ if (Array.isArray(objectValue)) {
1111
+ return Object.freeze(objectValue.map(function (item) { return $deepFreeze(item); }));
1112
+ }
1113
+ var propertyNames = Object.getOwnPropertyNames(objectValue);
1114
+ try {
1115
+ for (var propertyNames_1 = __values(propertyNames), propertyNames_1_1 = propertyNames_1.next(); !propertyNames_1_1.done; propertyNames_1_1 = propertyNames_1.next()) {
1116
+ var propertyName = propertyNames_1_1.value;
1117
+ var value = objectValue[propertyName];
1118
+ if (value && typeof value === 'object') {
1119
+ $deepFreeze(value);
1120
+ }
1121
+ }
1122
+ }
1123
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1124
+ finally {
1125
+ try {
1126
+ if (propertyNames_1_1 && !propertyNames_1_1.done && (_a = propertyNames_1.return)) _a.call(propertyNames_1);
1127
+ }
1128
+ finally { if (e_1) throw e_1.error; }
1129
+ }
1130
+ Object.freeze(objectValue);
1131
+ return objectValue;
1132
+ }
1133
+ /**
1134
+ * TODO: [🧠] Is there a way how to meaningfully test this utility
1135
+ */
1136
+
1137
+ /**
1138
+ * Checks if the value is [🚉] serializable as JSON
1139
+ * If not, throws an UnexpectedError with a rich error message and tracking
1140
+ *
1141
+ * - Almost all primitives are serializable BUT:
1142
+ * - `undefined` is not serializable
1143
+ * - `NaN` is not serializable
1144
+ * - Objects and arrays are serializable if all their properties are serializable
1145
+ * - Functions are not serializable
1146
+ * - Circular references are not serializable
1147
+ * - `Date` objects are not serializable
1148
+ * - `Map` and `Set` objects are not serializable
1149
+ * - `RegExp` objects are not serializable
1150
+ * - `Error` objects are not serializable
1151
+ * - `Symbol` objects are not serializable
1152
+ * - And much more...
1153
+ *
1154
+ * @throws UnexpectedError if the value is not serializable as JSON
1155
+ * @public exported from `@promptbook/utils`
1156
+ */
1157
+ function checkSerializableAsJson(options) {
1158
+ var e_1, _a;
1159
+ var value = options.value, name = options.name, message = options.message;
1160
+ if (value === undefined) {
1161
+ throw new UnexpectedError("".concat(name, " is undefined"));
1162
+ }
1163
+ else if (value === null) {
1164
+ return;
1165
+ }
1166
+ else if (typeof value === 'boolean') {
1167
+ return;
1168
+ }
1169
+ else if (typeof value === 'number' && !isNaN(value)) {
1170
+ return;
1171
+ }
1172
+ else if (typeof value === 'string') {
1173
+ return;
1174
+ }
1175
+ else if (typeof value === 'symbol') {
1176
+ throw new UnexpectedError("".concat(name, " is symbol"));
1177
+ }
1178
+ else if (typeof value === 'function') {
1179
+ throw new UnexpectedError("".concat(name, " is function"));
1180
+ }
1181
+ else if (typeof value === 'object' && Array.isArray(value)) {
1182
+ for (var i = 0; i < value.length; i++) {
1183
+ checkSerializableAsJson({ name: "".concat(name, "[").concat(i, "]"), value: value[i], message: message });
1184
+ }
1185
+ }
1186
+ else if (typeof value === 'object') {
1187
+ if (value instanceof Date) {
1188
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is Date\n\n Use `string_date_iso8601` instead\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
1189
+ }
1190
+ else if (value instanceof Map) {
1191
+ throw new UnexpectedError("".concat(name, " is Map"));
1192
+ }
1193
+ else if (value instanceof Set) {
1194
+ throw new UnexpectedError("".concat(name, " is Set"));
1195
+ }
1196
+ else if (value instanceof RegExp) {
1197
+ throw new UnexpectedError("".concat(name, " is RegExp"));
1198
+ }
1199
+ else if (value instanceof Error) {
1200
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is unserialized Error\n\n Use function `serializeError`\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n\n "); }));
1201
+ }
1202
+ else {
1203
+ try {
1204
+ for (var _b = __values(Object.entries(value)), _c = _b.next(); !_c.done; _c = _b.next()) {
1205
+ var _d = __read(_c.value, 2), subName = _d[0], subValue = _d[1];
1206
+ if (subValue === undefined) {
1207
+ // Note: undefined in object is serializable - it is just omited
1208
+ continue;
1209
+ }
1210
+ checkSerializableAsJson({ name: "".concat(name, ".").concat(subName), value: subValue, message: message });
1211
+ }
1212
+ }
1213
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1214
+ finally {
1215
+ try {
1216
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1217
+ }
1218
+ finally { if (e_1) throw e_1.error; }
1219
+ }
1220
+ try {
1221
+ JSON.stringify(value); // <- TODO: [0]
1222
+ }
1223
+ catch (error) {
1224
+ if (!(error instanceof Error)) {
1225
+ throw error;
1226
+ }
1227
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is not serializable\n\n ").concat(block(error.stack || error.message), "\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
1228
+ }
1229
+ /*
1230
+ TODO: [0] Is there some more elegant way to check circular references?
1231
+ const seen = new Set();
1232
+ const stack = [{ value }];
1233
+ while (stack.length > 0) {
1234
+ const { value } = stack.pop()!;
1235
+ if (typeof value === 'object' && value !== null) {
1236
+ if (seen.has(value)) {
1237
+ throw new UnexpectedError(`${name} has circular reference`);
1238
+ }
1239
+ seen.add(value);
1240
+ if (Array.isArray(value)) {
1241
+ stack.push(...value.map((value) => ({ value })));
1242
+ } else {
1243
+ stack.push(...Object.values(value).map((value) => ({ value })));
1244
+ }
1245
+ }
1246
+ }
1247
+ */
1248
+ return;
1249
+ }
1250
+ }
1251
+ else {
1252
+ throw new UnexpectedError(spaceTrim(function (block) { return "\n `".concat(name, "` is unknown type\n\n Additional message for `").concat(name, "`:\n ").concat(block(message || '(nothing)'), "\n "); }));
1253
+ }
1254
+ }
1255
+ /**
1256
+ * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
1257
+ * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
1258
+ * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
1259
+ */
1260
+
1261
+ /**
1262
+ * @@@
1263
+ *
1264
+ * @public exported from `@promptbook/utils`
1265
+ */
1266
+ function deepClone(objectValue) {
1267
+ return JSON.parse(JSON.stringify(objectValue));
1268
+ /*
1269
+ TODO: [🧠] Is there a better implementation?
1270
+ > const propertyNames = Object.getOwnPropertyNames(objectValue);
1271
+ > for (const propertyName of propertyNames) {
1272
+ > const value = (objectValue as really_any)[propertyName];
1273
+ > if (value && typeof value === 'object') {
1274
+ > deepClone(value);
1275
+ > }
1276
+ > }
1277
+ > return Object.assign({}, objectValue);
1278
+ */
1279
+ }
1280
+ /**
1281
+ * TODO: [🧠] Is there a way how to meaningfully test this utility
1282
+ */
1283
+
1284
+ /**
1285
+ * Utility to export a JSON object from a function
1286
+ *
1287
+ * 1) Checks if the value is serializable as JSON
1288
+ * 2) Makes a deep clone of the object
1289
+ * 2) Orders the object properties
1290
+ * 2) Deeply freezes the cloned object
1291
+ *
1292
+ * Note: This function does not mutates the given object
1293
+ *
1294
+ * @returns The same type of object as the input but read-only and re-ordered
1295
+ * @public exported from `@promptbook/utils`
1296
+ */
1297
+ function exportJson(options) {
1298
+ var name = options.name, value = options.value, order = options.order, message = options.message;
1299
+ checkSerializableAsJson({ name: name, value: value, message: message });
1300
+ var orderedValue =
1301
+ // TODO: Fix error "Type instantiation is excessively deep and possibly infinite."
1302
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
1303
+ // @ts-ignore
1304
+ order === undefined
1305
+ ? deepClone(value)
1306
+ : orderJson({
1307
+ value: value,
1308
+ // <- Note: checkSerializableAsJson asserts that the value is serializable as JSON
1309
+ order: order,
1310
+ });
1311
+ $deepFreeze(orderedValue);
1312
+ return orderedValue;
1313
+ }
1314
+ /**
1315
+ * TODO: [🧠] Is there a way how to meaningfully test this utility
1316
+ */
1317
+
1318
+ /**
1319
+ * Nonce which is used for replacing things in strings
1320
+ *
1321
+ * @private within the repository
1322
+ */
1323
+ var REPLACING_NONCE = 'u$k42k%!V2zo34w7Fu#@QUHYPW';
1324
+ /**
1325
+ * The names of the parameters that are reserved for special purposes
1326
+ *
1327
+ * @public exported from `@promptbook/core`
1328
+ */
1329
+ var RESERVED_PARAMETER_NAMES = exportJson({
1330
+ name: 'RESERVED_PARAMETER_NAMES',
1331
+ message: "The names of the parameters that are reserved for special purposes",
1332
+ value: [
1333
+ 'content',
1334
+ 'context',
1335
+ 'knowledge',
1336
+ 'examples',
1337
+ 'modelName',
1338
+ 'currentDate',
1339
+ // <- TODO: list here all command names
1340
+ // <- TODO: Add more like 'date', 'modelName',...
1341
+ // <- TODO: Add [emoji] + instructions ACRY when adding new reserved parameter
1342
+ ],
1343
+ });
1344
+ /**
1345
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1346
+ */
1347
+
1348
+ /**
1349
+ * @@@
1350
+ *
1351
+ * @param text @@@
1352
+ * @param _isFirstLetterCapital @@@
1353
+ * @returns @@@
1354
+ * @example 'helloWorld'
1355
+ * @example 'iLovePromptbook'
1356
+ * @public exported from `@promptbook/utils`
1357
+ */
1358
+ function normalizeTo_camelCase(text, _isFirstLetterCapital) {
1359
+ var e_1, _a;
1360
+ if (_isFirstLetterCapital === void 0) { _isFirstLetterCapital = false; }
1361
+ var charType;
1362
+ var lastCharType = null;
1363
+ var normalizedName = '';
1364
+ try {
1365
+ for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
1366
+ var char = text_1_1.value;
1367
+ var normalizedChar = void 0;
1368
+ if (/^[a-z]$/.test(char)) {
1369
+ charType = 'LOWERCASE';
1370
+ normalizedChar = char;
1371
+ }
1372
+ else if (/^[A-Z]$/.test(char)) {
1373
+ charType = 'UPPERCASE';
1374
+ normalizedChar = char.toLowerCase();
1375
+ }
1376
+ else if (/^[0-9]$/.test(char)) {
1377
+ charType = 'NUMBER';
1378
+ normalizedChar = char;
1379
+ }
1380
+ else {
1381
+ charType = 'OTHER';
1382
+ normalizedChar = '';
1383
+ }
1384
+ if (!lastCharType) {
1385
+ if (_isFirstLetterCapital) {
1386
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
1387
+ }
1388
+ }
1389
+ else if (charType !== lastCharType &&
1390
+ !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
1391
+ !(lastCharType === 'NUMBER') &&
1392
+ !(charType === 'NUMBER')) {
1393
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: [🌺] DRY
1394
+ }
1395
+ normalizedName += normalizedChar;
1396
+ lastCharType = charType;
1397
+ }
1398
+ }
1399
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1400
+ finally {
1401
+ try {
1402
+ if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
1403
+ }
1404
+ finally { if (e_1) throw e_1.error; }
1405
+ }
1406
+ return normalizedName;
1407
+ }
1408
+ /**
1409
+ * TODO: [🌺] Use some intermediate util splitWords
1410
+ */
1411
+
1412
+ var defaultDiacriticsRemovalMap = [
1413
+ {
1414
+ base: 'A',
1415
+ letters: '\u0041\u24B6\uFF21\u00C0\u00C1\u00C2\u1EA6\u1EA4\u1EAA\u1EA8\u00C3\u0100\u0102\u1EB0\u1EAE\u1EB4\u1EB2\u0226\u01E0\u00C4\u01DE\u1EA2\u00C5\u01FA\u01CD\u0200\u0202\u1EA0\u1EAC\u1EB6\u1E00\u0104\u023A\u2C6F',
1416
+ },
1417
+ { base: 'AA', letters: '\uA732' },
1418
+ { base: 'AE', letters: '\u00C6\u01FC\u01E2' },
1419
+ { base: 'AO', letters: '\uA734' },
1420
+ { base: 'AU', letters: '\uA736' },
1421
+ { base: 'AV', letters: '\uA738\uA73A' },
1422
+ { base: 'AY', letters: '\uA73C' },
1423
+ {
1424
+ base: 'B',
1425
+ letters: '\u0042\u24B7\uFF22\u1E02\u1E04\u1E06\u0243\u0182\u0181',
1426
+ },
1427
+ {
1428
+ base: 'C',
1429
+ letters: '\u0043\u24B8\uFF23\u0106\u0108\u010A\u010C\u00C7\u1E08\u0187\u023B\uA73E',
1430
+ },
1431
+ {
1432
+ base: 'D',
1433
+ letters: '\u0044\u24B9\uFF24\u1E0A\u010E\u1E0C\u1E10\u1E12\u1E0E\u0110\u018B\u018A\u0189\uA779\u00D0',
1434
+ },
1435
+ { base: 'DZ', letters: '\u01F1\u01C4' },
1436
+ { base: 'Dz', letters: '\u01F2\u01C5' },
1437
+ {
1438
+ base: 'E',
1439
+ letters: '\u0045\u24BA\uFF25\u00C8\u00C9\u00CA\u1EC0\u1EBE\u1EC4\u1EC2\u1EBC\u0112\u1E14\u1E16\u0114\u0116\u00CB\u1EBA\u011A\u0204\u0206\u1EB8\u1EC6\u0228\u1E1C\u0118\u1E18\u1E1A\u0190\u018E',
1440
+ },
1441
+ { base: 'F', letters: '\u0046\u24BB\uFF26\u1E1E\u0191\uA77B' },
1442
+ {
1443
+ base: 'G',
1444
+ letters: '\u0047\u24BC\uFF27\u01F4\u011C\u1E20\u011E\u0120\u01E6\u0122\u01E4\u0193\uA7A0\uA77D\uA77E',
1445
+ },
1446
+ {
1447
+ base: 'H',
1448
+ letters: '\u0048\u24BD\uFF28\u0124\u1E22\u1E26\u021E\u1E24\u1E28\u1E2A\u0126\u2C67\u2C75\uA78D',
1449
+ },
1450
+ {
1451
+ base: 'I',
1452
+ letters: '\u0049\u24BE\uFF29\u00CC\u00CD\u00CE\u0128\u012A\u012C\u0130\u00CF\u1E2E\u1EC8\u01CF\u0208\u020A\u1ECA\u012E\u1E2C\u0197',
1453
+ },
1454
+ { base: 'J', letters: '\u004A\u24BF\uFF2A\u0134\u0248' },
1455
+ {
1456
+ base: 'K',
1457
+ letters: '\u004B\u24C0\uFF2B\u1E30\u01E8\u1E32\u0136\u1E34\u0198\u2C69\uA740\uA742\uA744\uA7A2',
1458
+ },
1459
+ {
1460
+ base: 'L',
1461
+ letters: '\u004C\u24C1\uFF2C\u013F\u0139\u013D\u1E36\u1E38\u013B\u1E3C\u1E3A\u0141\u023D\u2C62\u2C60\uA748\uA746\uA780',
1462
+ },
1463
+ { base: 'LJ', letters: '\u01C7' },
1464
+ { base: 'Lj', letters: '\u01C8' },
1465
+ { base: 'M', letters: '\u004D\u24C2\uFF2D\u1E3E\u1E40\u1E42\u2C6E\u019C' },
1466
+ {
1467
+ base: 'N',
1468
+ letters: '\u004E\u24C3\uFF2E\u01F8\u0143\u00D1\u1E44\u0147\u1E46\u0145\u1E4A\u1E48\u0220\u019D\uA790\uA7A4',
1469
+ },
1470
+ { base: 'NJ', letters: '\u01CA' },
1471
+ { base: 'Nj', letters: '\u01CB' },
1472
+ {
1473
+ base: 'O',
1474
+ letters: '\u004F\u24C4\uFF2F\u00D2\u00D3\u00D4\u1ED2\u1ED0\u1ED6\u1ED4\u00D5\u1E4C\u022C\u1E4E\u014C\u1E50\u1E52\u014E\u022E\u0230\u00D6\u022A\u1ECE\u0150\u01D1\u020C\u020E\u01A0\u1EDC\u1EDA\u1EE0\u1EDE\u1EE2\u1ECC\u1ED8\u01EA\u01EC\u00D8\u01FE\u0186\u019F\uA74A\uA74C',
1475
+ },
1476
+ { base: 'OI', letters: '\u01A2' },
1477
+ { base: 'OO', letters: '\uA74E' },
1478
+ { base: 'OU', letters: '\u0222' },
1479
+ { base: 'OE', letters: '\u008C\u0152' },
1480
+ { base: 'oe', letters: '\u009C\u0153' },
1481
+ {
1482
+ base: 'P',
1483
+ letters: '\u0050\u24C5\uFF30\u1E54\u1E56\u01A4\u2C63\uA750\uA752\uA754',
1484
+ },
1485
+ { base: 'Q', letters: '\u0051\u24C6\uFF31\uA756\uA758\u024A' },
1486
+ {
1487
+ base: 'R',
1488
+ letters: '\u0052\u24C7\uFF32\u0154\u1E58\u0158\u0210\u0212\u1E5A\u1E5C\u0156\u1E5E\u024C\u2C64\uA75A\uA7A6\uA782',
1489
+ },
1490
+ {
1491
+ base: 'S',
1492
+ letters: '\u0053\u24C8\uFF33\u1E9E\u015A\u1E64\u015C\u1E60\u0160\u1E66\u1E62\u1E68\u0218\u015E\u2C7E\uA7A8\uA784',
1493
+ },
1494
+ {
1495
+ base: 'T',
1496
+ letters: '\u0054\u24C9\uFF34\u1E6A\u0164\u1E6C\u021A\u0162\u1E70\u1E6E\u0166\u01AC\u01AE\u023E\uA786',
1497
+ },
1498
+ { base: 'TZ', letters: '\uA728' },
1499
+ {
1500
+ base: 'U',
1501
+ letters: '\u0055\u24CA\uFF35\u00D9\u00DA\u00DB\u0168\u1E78\u016A\u1E7A\u016C\u00DC\u01DB\u01D7\u01D5\u01D9\u1EE6\u016E\u0170\u01D3\u0214\u0216\u01AF\u1EEA\u1EE8\u1EEE\u1EEC\u1EF0\u1EE4\u1E72\u0172\u1E76\u1E74\u0244',
1502
+ },
1503
+ { base: 'V', letters: '\u0056\u24CB\uFF36\u1E7C\u1E7E\u01B2\uA75E\u0245' },
1504
+ { base: 'VY', letters: '\uA760' },
1505
+ {
1506
+ base: 'W',
1507
+ letters: '\u0057\u24CC\uFF37\u1E80\u1E82\u0174\u1E86\u1E84\u1E88\u2C72',
1508
+ },
1509
+ { base: 'X', letters: '\u0058\u24CD\uFF38\u1E8A\u1E8C' },
1510
+ {
1511
+ base: 'Y',
1512
+ letters: '\u0059\u24CE\uFF39\u1EF2\u00DD\u0176\u1EF8\u0232\u1E8E\u0178\u1EF6\u1EF4\u01B3\u024E\u1EFE',
1513
+ },
1514
+ {
1515
+ base: 'Z',
1516
+ letters: '\u005A\u24CF\uFF3A\u0179\u1E90\u017B\u017D\u1E92\u1E94\u01B5\u0224\u2C7F\u2C6B\uA762',
1517
+ },
1518
+ {
1519
+ base: 'a',
1520
+ letters: '\u0061\u24D0\uFF41\u1E9A\u00E0\u00E1\u00E2\u1EA7\u1EA5\u1EAB\u1EA9\u00E3\u0101\u0103\u1EB1\u1EAF\u1EB5\u1EB3\u0227\u01E1\u00E4\u01DF\u1EA3\u00E5\u01FB\u01CE\u0201\u0203\u1EA1\u1EAD\u1EB7\u1E01\u0105\u2C65\u0250',
1521
+ },
1522
+ { base: 'aa', letters: '\uA733' },
1523
+ { base: 'ae', letters: '\u00E6\u01FD\u01E3' },
1524
+ { base: 'ao', letters: '\uA735' },
1525
+ { base: 'au', letters: '\uA737' },
1526
+ { base: 'av', letters: '\uA739\uA73B' },
1527
+ { base: 'ay', letters: '\uA73D' },
1528
+ {
1529
+ base: 'b',
1530
+ letters: '\u0062\u24D1\uFF42\u1E03\u1E05\u1E07\u0180\u0183\u0253',
1531
+ },
1532
+ {
1533
+ base: 'c',
1534
+ letters: '\u0063\u24D2\uFF43\u0107\u0109\u010B\u010D\u00E7\u1E09\u0188\u023C\uA73F\u2184',
1535
+ },
1536
+ {
1537
+ base: 'd',
1538
+ letters: '\u0064\u24D3\uFF44\u1E0B\u010F\u1E0D\u1E11\u1E13\u1E0F\u0111\u018C\u0256\u0257\uA77A',
1539
+ },
1540
+ { base: 'dz', letters: '\u01F3\u01C6' },
1541
+ {
1542
+ base: 'e',
1543
+ letters: '\u0065\u24D4\uFF45\u00E8\u00E9\u00EA\u1EC1\u1EBF\u1EC5\u1EC3\u1EBD\u0113\u1E15\u1E17\u0115\u0117\u00EB\u1EBB\u011B\u0205\u0207\u1EB9\u1EC7\u0229\u1E1D\u0119\u1E19\u1E1B\u0247\u025B\u01DD',
1544
+ },
1545
+ { base: 'f', letters: '\u0066\u24D5\uFF46\u1E1F\u0192\uA77C' },
1546
+ {
1547
+ base: 'g',
1548
+ letters: '\u0067\u24D6\uFF47\u01F5\u011D\u1E21\u011F\u0121\u01E7\u0123\u01E5\u0260\uA7A1\u1D79\uA77F',
1549
+ },
1550
+ {
1551
+ base: 'h',
1552
+ letters: '\u0068\u24D7\uFF48\u0125\u1E23\u1E27\u021F\u1E25\u1E29\u1E2B\u1E96\u0127\u2C68\u2C76\u0265',
1553
+ },
1554
+ { base: 'hv', letters: '\u0195' },
1555
+ {
1556
+ base: 'i',
1557
+ letters: '\u0069\u24D8\uFF49\u00EC\u00ED\u00EE\u0129\u012B\u012D\u00EF\u1E2F\u1EC9\u01D0\u0209\u020B\u1ECB\u012F\u1E2D\u0268\u0131',
1558
+ },
1559
+ { base: 'j', letters: '\u006A\u24D9\uFF4A\u0135\u01F0\u0249' },
1560
+ {
1561
+ base: 'k',
1562
+ letters: '\u006B\u24DA\uFF4B\u1E31\u01E9\u1E33\u0137\u1E35\u0199\u2C6A\uA741\uA743\uA745\uA7A3',
1563
+ },
1564
+ {
1565
+ base: 'l',
1566
+ letters: '\u006C\u24DB\uFF4C\u0140\u013A\u013E\u1E37\u1E39\u013C\u1E3D\u1E3B\u017F\u0142\u019A\u026B\u2C61\uA749\uA781\uA747',
1567
+ },
1568
+ { base: 'lj', letters: '\u01C9' },
1569
+ { base: 'm', letters: '\u006D\u24DC\uFF4D\u1E3F\u1E41\u1E43\u0271\u026F' },
1570
+ {
1571
+ base: 'n',
1572
+ letters: '\u006E\u24DD\uFF4E\u01F9\u0144\u00F1\u1E45\u0148\u1E47\u0146\u1E4B\u1E49\u019E\u0272\u0149\uA791\uA7A5',
1573
+ },
1574
+ { base: 'nj', letters: '\u01CC' },
1575
+ {
1576
+ base: 'o',
1577
+ letters: '\u006F\u24DE\uFF4F\u00F2\u00F3\u00F4\u1ED3\u1ED1\u1ED7\u1ED5\u00F5\u1E4D\u022D\u1E4F\u014D\u1E51\u1E53\u014F\u022F\u0231\u00F6\u022B\u1ECF\u0151\u01D2\u020D\u020F\u01A1\u1EDD\u1EDB\u1EE1\u1EDF\u1EE3\u1ECD\u1ED9\u01EB\u01ED\u00F8\u01FF\u0254\uA74B\uA74D\u0275',
1578
+ },
1579
+ { base: 'oi', letters: '\u01A3' },
1580
+ { base: 'ou', letters: '\u0223' },
1581
+ { base: 'oo', letters: '\uA74F' },
1582
+ {
1583
+ base: 'p',
1584
+ letters: '\u0070\u24DF\uFF50\u1E55\u1E57\u01A5\u1D7D\uA751\uA753\uA755',
1585
+ },
1586
+ { base: 'q', letters: '\u0071\u24E0\uFF51\u024B\uA757\uA759' },
1587
+ {
1588
+ base: 'r',
1589
+ letters: '\u0072\u24E1\uFF52\u0155\u1E59\u0159\u0211\u0213\u1E5B\u1E5D\u0157\u1E5F\u024D\u027D\uA75B\uA7A7\uA783',
1590
+ },
1591
+ {
1592
+ base: 's',
1593
+ letters: '\u0073\u24E2\uFF53\u00DF\u015B\u1E65\u015D\u1E61\u0161\u1E67\u1E63\u1E69\u0219\u015F\u023F\uA7A9\uA785\u1E9B',
1594
+ },
1595
+ {
1596
+ base: 't',
1597
+ letters: '\u0074\u24E3\uFF54\u1E6B\u1E97\u0165\u1E6D\u021B\u0163\u1E71\u1E6F\u0167\u01AD\u0288\u2C66\uA787',
1598
+ },
1599
+ { base: 'tz', letters: '\uA729' },
1600
+ {
1601
+ base: 'u',
1602
+ letters: '\u0075\u24E4\uFF55\u00F9\u00FA\u00FB\u0169\u1E79\u016B\u1E7B\u016D\u00FC\u01DC\u01D8\u01D6\u01DA\u1EE7\u016F\u0171\u01D4\u0215\u0217\u01B0\u1EEB\u1EE9\u1EEF\u1EED\u1EF1\u1EE5\u1E73\u0173\u1E77\u1E75\u0289',
1603
+ },
1604
+ { base: 'v', letters: '\u0076\u24E5\uFF56\u1E7D\u1E7F\u028B\uA75F\u028C' },
1605
+ { base: 'vy', letters: '\uA761' },
1606
+ {
1607
+ base: 'w',
1608
+ letters: '\u0077\u24E6\uFF57\u1E81\u1E83\u0175\u1E87\u1E85\u1E98\u1E89\u2C73',
1609
+ },
1610
+ { base: 'x', letters: '\u0078\u24E7\uFF58\u1E8B\u1E8D' },
1611
+ {
1612
+ base: 'y',
1613
+ letters: '\u0079\u24E8\uFF59\u1EF3\u00FD\u0177\u1EF9\u0233\u1E8F\u00FF\u1EF7\u1E99\u1EF5\u01B4\u024F\u1EFF',
1614
+ },
1615
+ {
1616
+ base: 'z',
1617
+ letters: '\u007A\u24E9\uFF5A\u017A\u1E91\u017C\u017E\u1E93\u1E95\u01B6\u0225\u0240\u2C6C\uA763',
1618
+ },
1619
+ ];
1620
+ /**
1621
+ * Map of letters from diacritic variant to diacritless variant
1622
+ * Contains lowercase and uppercase separatelly
1623
+ *
1624
+ * > "á" => "a"
1625
+ * > "ě" => "e"
1626
+ * > "Ă" => "A"
1627
+ * > ...
1628
+ *
1629
+ * @public exported from `@promptbook/utils`
1630
+ */
1631
+ var DIACRITIC_VARIANTS_LETTERS = {};
1632
+ // tslint:disable-next-line: prefer-for-of
1633
+ for (var i = 0; i < defaultDiacriticsRemovalMap.length; i++) {
1634
+ var letters = defaultDiacriticsRemovalMap[i].letters;
1635
+ // tslint:disable-next-line: prefer-for-of
1636
+ for (var j = 0; j < letters.length; j++) {
1637
+ DIACRITIC_VARIANTS_LETTERS[letters[j]] = defaultDiacriticsRemovalMap[i].base;
1638
+ }
1639
+ }
1640
+ // <- TODO: [🍓] Put to maker function to save execution time if not needed
1641
+ /*
1642
+ @see https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
1643
+ Licensed under the Apache License, Version 2.0 (the "License");
1644
+ you may not use this file except in compliance with the License.
1645
+ You may obtain a copy of the License at
1646
+
1647
+ http://www.apache.org/licenses/LICENSE-2.0
1648
+
1649
+ Unless required by applicable law or agreed to in writing, software
1650
+ distributed under the License is distributed on an "AS IS" BASIS,
1651
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1652
+ See the License for the specific language governing permissions and
1653
+ limitations under the License.
1654
+ */
1655
+
1656
+ /**
1657
+ * @@@
1658
+ *
1659
+ * @param input @@@
1660
+ * @returns @@@
1661
+ * @public exported from `@promptbook/utils`
1662
+ */
1663
+ function removeDiacritics(input) {
1664
+ /*eslint no-control-regex: "off"*/
1665
+ return input.replace(/[^\u0000-\u007E]/g, function (a) {
1666
+ return DIACRITIC_VARIANTS_LETTERS[a] || a;
1667
+ });
1668
+ }
1669
+ /**
1670
+ * TODO: [Ж] Variant for cyrillic (and in general non-latin) letters
1671
+ */
1672
+
1673
+ /**
1674
+ * Removes emojis from a string and fix whitespaces
1675
+ *
1676
+ * @param text with emojis
1677
+ * @returns text without emojis
1678
+ * @public exported from `@promptbook/utils`
1679
+ */
1680
+ function removeEmojis(text) {
1681
+ // Replace emojis (and also ZWJ sequence) with hyphens
1682
+ text = text.replace(/(\p{Extended_Pictographic})\p{Modifier_Symbol}/gu, '$1');
1683
+ text = text.replace(/(\p{Extended_Pictographic})[\u{FE00}-\u{FE0F}]/gu, '$1');
1684
+ text = text.replace(/(\p{Extended_Pictographic})(\u{200D}\p{Extended_Pictographic})*/gu, '$1');
1685
+ text = text.replace(/\p{Extended_Pictographic}/gu, '');
1686
+ return text;
1687
+ }
1688
+
1689
+ /**
1690
+ * Removes quotes from a string
1691
+ *
1692
+ * Tip: This is very usefull for post-processing of the result of the LLM model
1693
+ * Note: This function removes only the same quotes from the beginning and the end of the string
1694
+ * Note: There are two simmilar functions:
1695
+ * - `removeQuotes` which removes only bounding quotes
1696
+ * - `unwrapResult` which removes whole introduce sentence
1697
+ *
1698
+ * @param text optionally quoted text
1699
+ * @returns text without quotes
1700
+ * @public exported from `@promptbook/utils`
1701
+ */
1702
+ function removeQuotes(text) {
1703
+ if (text.startsWith('"') && text.endsWith('"')) {
1704
+ return text.slice(1, -1);
1705
+ }
1706
+ if (text.startsWith('\'') && text.endsWith('\'')) {
1707
+ return text.slice(1, -1);
1708
+ }
1709
+ return text;
1710
+ }
1711
+
1712
+ /**
1713
+ * Function `validateParameterName` will @@@
1714
+ *
1715
+ * @param parameterName @@@
1716
+ * @returns @@@
1717
+ * @throws {ParseError} @@@
1718
+ * @private within the repository
1719
+ */
1720
+ function validateParameterName(parameterName) {
1721
+ var e_1, _a;
1722
+ var rawParameterName = parameterName;
1723
+ try {
1724
+ for (var _b = __values([
1725
+ ['`', '`'],
1726
+ ['{', '}'],
1727
+ ['[', ']'],
1728
+ ['(', ')'],
1729
+ ['<', '>'],
1730
+ ]), _c = _b.next(); !_c.done; _c = _b.next()) {
1731
+ var _d = __read(_c.value, 2), start = _d[0], end = _d[1];
1732
+ if (parameterName.substring(0, 1) === start &&
1733
+ parameterName.substring(parameterName.length - 1, parameterName.length) === end
1734
+ // <- TODO: More universal that 1 character
1735
+ ) {
1736
+ parameterName = parameterName.substring(1, parameterName.length - 1);
1737
+ // <- TODO: More universal that 1 character
1738
+ }
1739
+ }
1740
+ }
1741
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
1742
+ finally {
1743
+ try {
1744
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
1745
+ }
1746
+ finally { if (e_1) throw e_1.error; }
1747
+ }
1748
+ // TODO: [🐠] Following try-catch block should be part of common validators logic
1749
+ try {
1750
+ /*
1751
+ Note: We don't need to check for spaces because we are going to normalize the parameter name to camelCase
1752
+ if (parameterName.includes(' ')) {
1753
+ throw new ParseError(`Parameter name cannot contain spaces`);
1754
+ }
1755
+ */
1756
+ if (parameterName.includes('.')) {
1757
+ throw new ParseError("Parameter name cannot contain dots");
1758
+ }
1759
+ if (parameterName.includes('/') || parameterName.includes('\\')) {
1760
+ throw new ParseError("Parameter name cannot contain slashes");
1761
+ }
1762
+ if (parameterName.includes('(') ||
1763
+ parameterName.includes(')') ||
1764
+ parameterName.includes('{') ||
1765
+ parameterName.includes('}') ||
1766
+ parameterName.includes('[') ||
1767
+ parameterName.includes(']')) {
1768
+ throw new ParseError("Parameter name cannot contain braces");
1769
+ }
1770
+ parameterName = removeDiacritics(parameterName);
1771
+ parameterName = removeEmojis(parameterName);
1772
+ parameterName = removeQuotes(parameterName);
1773
+ parameterName = normalizeTo_camelCase(parameterName);
1774
+ if (parameterName === '') {
1775
+ throw new ParseError("Parameter name cannot be empty");
1776
+ }
1777
+ if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
1778
+ throw new ParseError("{".concat(parameterName, "} is a reserved parameter name"));
1779
+ }
1780
+ }
1781
+ catch (error) {
1782
+ if (!(error instanceof ParseError)) {
1783
+ throw error;
1784
+ }
1785
+ throw new ParseError(spaceTrim(function (block) { return "\n ".concat(block(error.message), "\n\n Tried to validate parameter name:\n ").concat(block(rawParameterName), "\n "); }));
1786
+ }
1787
+ return parameterName;
1788
+ }
1789
+
1790
+ /**
1791
+ * Parses the foreach command
1792
+ *
1793
+ * Note: @@@ This command is used as foreach for new commands - it should NOT be used in any `.book.md` file
1794
+ *
1795
+ * @see `documentationUrl` for more details
1796
+ * @public exported from `@promptbook/editable`
1797
+ */
1798
+ var foreachCommandParser = {
1799
+ /**
1800
+ * Name of the command
1801
+ */
1802
+ name: 'FOREACH',
1803
+ /**
1804
+ * Aliases for the FOREACH command
1805
+ */
1806
+ aliasNames: ['FOR', 'EACH'],
1807
+ /**
1808
+ * FOREACH command can be used in:
1809
+ */
1810
+ isUsedInPipelineHead: false,
1811
+ isUsedInPipelineTask: true,
1812
+ /**
1813
+ * Description of the FOREACH command
1814
+ */
1815
+ description: "@@",
1816
+ /**
1817
+ * Link to documentation
1818
+ */
1819
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/148',
1820
+ /**
1821
+ * Example usages of the FOREACH command
1822
+ */
1823
+ examples: [
1824
+ 'FOREACH Text Line `{customers}` -> `{customer}`',
1825
+ 'FOREACH Csv Cell `{customers}` -> `{cell}`',
1826
+ 'FOREACH Csv Row `{customers}` -> `{firstName}`, `{lastName}`, `+{email}`',
1827
+ 'FOR Text Line `{customers}` -> `{customer}`',
1828
+ 'EACH Text Line `{customers}` -> `{customer}`',
1829
+ ],
1830
+ /**
1831
+ * Parses the FOREACH command
1832
+ */
1833
+ parse: function (input) {
1834
+ var args = input.args;
1835
+ var formatName = normalizeTo_SCREAMING_CASE(args[0] || '');
1836
+ var subformatName = normalizeTo_SCREAMING_CASE(args[1] || '');
1837
+ var parameterNameArg = args[2] || '';
1838
+ var assignSign = args[3];
1839
+ var formatDefinition = FORMAT_DEFINITIONS.find(function (formatDefinition) {
1840
+ return __spreadArray([formatDefinition.formatName], __read((formatDefinition.aliases || [])), false).includes(formatName);
1841
+ });
1842
+ if (formatDefinition === undefined) {
1843
+ throw new ParseError(spaceTrim(function (block) { return "\n Unsupported format \"".concat(formatName, "\"\n\n Available formats:\n ").concat(block(FORMAT_DEFINITIONS.map(function (formatDefinition) { return formatDefinition.formatName; })
1844
+ .map(function (formatName) { return "- ".concat(formatName); })
1845
+ .join('\n')), "\n "); }));
1846
+ // <- TODO: [🏢] List all supported format names
1847
+ }
1848
+ var subvalueDefinition = formatDefinition.subvalueDefinitions.find(function (subvalueDefinition) {
1849
+ return __spreadArray([subvalueDefinition.subvalueName], __read((subvalueDefinition.aliases || [])), false).includes(subformatName);
1850
+ });
1851
+ if (subvalueDefinition === undefined) {
1852
+ throw new ParseError(spaceTrim(function (block) { return "\n Unsupported subformat name \"".concat(subformatName, "\" for format \"").concat(formatName, "\"\n\n Available subformat names for format \"").concat(formatDefinition.formatName, "\":\n ").concat(block(formatDefinition.subvalueDefinitions
1853
+ .map(function (subvalueDefinition) { return subvalueDefinition.subvalueName; })
1854
+ .map(function (subvalueName) { return "- ".concat(subvalueName); })
1855
+ .join('\n')), "\n "); }));
1856
+ // <- TODO: [🏢] List all supported subformat names for the format
1857
+ }
1858
+ if (assignSign !== '->') {
1859
+ throw new ParseError("FOREACH command must have '->' to assign the value to the parameter");
1860
+ }
1861
+ var parameterName = validateParameterName(parameterNameArg);
1862
+ var outputSubparameterName = null;
1863
+ // TODO: [4] DRY
1864
+ var inputSubparameterNames = args
1865
+ .slice(4)
1866
+ .map(function (parameterName) { return parameterName.split(',').join(' ').trim(); })
1867
+ .filter(function (parameterName) { return !parameterName.includes('+'); })
1868
+ .filter(function (parameterName) { return parameterName !== ''; })
1869
+ .map(validateParameterName);
1870
+ // TODO: [4] DRY
1871
+ var outputSubparameterNames = args
1872
+ .slice(4)
1873
+ .map(function (parameterName) { return parameterName.split(',').join(' ').trim(); })
1874
+ .filter(function (parameterName) { return parameterName.includes('+'); })
1875
+ .map(function (parameterName) { return parameterName.split('+').join(''); })
1876
+ .map(validateParameterName);
1877
+ if (outputSubparameterNames.length === 1) {
1878
+ outputSubparameterName = outputSubparameterNames[0];
1879
+ }
1880
+ else if (outputSubparameterNames.length > 1) {
1881
+ throw new ParseError("FOREACH command can not have more than one output subparameter");
1882
+ }
1883
+ if (inputSubparameterNames.length === 0) {
1884
+ throw new ParseError("FOREACH command must have at least one input subparameter");
1885
+ }
1886
+ if (outputSubparameterName === null) {
1887
+ // TODO: Following code should be unhardcoded from here and moved to the format definition
1888
+ if (formatName === 'CSV' && subformatName === 'CELL') {
1889
+ outputSubparameterName = 'newCell';
1890
+ }
1891
+ else if (formatName === 'TEXT' && subformatName === 'LINE') {
1892
+ outputSubparameterName = 'newLine';
1893
+ }
1894
+ else {
1895
+ throw new ParseError(spaceTrim("\n FOREACH ".concat(formatName, " ").concat(subformatName, " must specify output subparameter\n\n Correct example:\n - FOREACH ").concat(formatName, " ").concat(subformatName, " {").concat(parameterName, "} -> {inputSubparameterName1}, {inputSubparameterName2}, +{outputSubparameterName}\n\n ")));
1896
+ }
1897
+ }
1898
+ return {
1899
+ type: 'FOREACH',
1900
+ formatName: formatName,
1901
+ subformatName: subformatName,
1902
+ parameterName: parameterName,
1903
+ inputSubparameterNames: inputSubparameterNames,
1904
+ outputSubparameterName: outputSubparameterName,
1905
+ };
1906
+ },
1907
+ /**
1908
+ * Apply the FOREACH command to the `pipelineJson`
1909
+ *
1910
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
1911
+ */
1912
+ $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
1913
+ var formatName = command.formatName, subformatName = command.subformatName, parameterName = command.parameterName, inputSubparameterNames = command.inputSubparameterNames, outputSubparameterName = command.outputSubparameterName;
1914
+ // TODO: [🍭] Detect double use
1915
+ // TODO: [🍭] Detect usage with JOKER and don't allow it
1916
+ $taskJson.foreach = {
1917
+ formatName: formatName,
1918
+ subformatName: subformatName,
1919
+ parameterName: parameterName,
1920
+ inputSubparameterNames: inputSubparameterNames,
1921
+ outputSubparameterName: outputSubparameterName,
1922
+ };
1923
+ // Note: [🍭] FOREACH apply has some sideeffects on different places in codebase
1924
+ },
1925
+ /**
1926
+ * Converts the FOREACH command back to string
1927
+ *
1928
+ * Note: This is used in `pipelineJsonToString` utility
1929
+ */
1930
+ stringify: function (command) {
1931
+ return "---"; // <- TODO: [🛋] Implement
1932
+ },
1933
+ /**
1934
+ * Reads the FOREACH command from the `TaskJson`
1935
+ *
1936
+ * Note: This is used in `pipelineJsonToString` utility
1937
+ */
1938
+ takeFromTaskJson: function ($taskJson) {
1939
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
1940
+ },
1941
+ };
1942
+ /**
1943
+ * TODO: [🍭] Make .book.md file with examples of the FOREACH with wrong parsing and logic
1944
+ */
1945
+
1946
+ /**
1947
+ * Parses the format command
1948
+ *
1949
+ * @see `documentationUrl` for more details
1950
+ * @public exported from `@promptbook/editable`
1951
+ */
1952
+ var formatCommandParser = {
1953
+ /**
1954
+ * Name of the command
1955
+ */
1956
+ name: 'FORMAT',
1957
+ /**
1958
+ * BOILERPLATE command can be used in:
1959
+ */
1960
+ isUsedInPipelineHead: false,
1961
+ isUsedInPipelineTask: true,
1962
+ /**
1963
+ * Description of the FORMAT command
1964
+ */
1965
+ description: spaceTrim("\n Format command describes the desired output of the task (after post-processing)\n It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.\n "),
1966
+ /**
1967
+ * Link to documentation
1968
+ */
1969
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/30',
1970
+ /**
1971
+ * Example usages of the FORMAT command
1972
+ */
1973
+ examples: ['FORMAT JSON'],
1974
+ /**
1975
+ * Parses the FORMAT command
1976
+ */
1977
+ parse: function (input) {
1978
+ var normalized = input.normalized;
1979
+ if (!normalized.startsWith('FORMAT_JSON')) {
1980
+ throw new ParseError("For now only JSON format is supported, in future we will support more formats");
1981
+ }
1982
+ return {
1983
+ type: 'FORMAT',
1984
+ format: 'JSON',
1985
+ };
1986
+ // <- TODO: [🦽] Why this is constantly removed by repair-imports.ts
1987
+ // [🥤]
1988
+ },
1989
+ /**
1990
+ * Apply the FORMAT command to the `pipelineJson`
1991
+ *
1992
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
1993
+ */
1994
+ $applyToTaskJson: function (command, $taskJson) {
1995
+ if ($taskJson.format !== undefined && command.format !== $taskJson.format) {
1996
+ throw new ParseError("Format format is already defined to \"".concat($taskJson.format, "\".\n Now you try to redefine it by \"").concat(command.format, "\""));
1997
+ }
1998
+ $taskJson.format = command.format;
1999
+ },
2000
+ /**
2001
+ * Converts the FORMAT command back to string
2002
+ *
2003
+ * Note: This is used in `pipelineJsonToString` utility
2004
+ */
2005
+ stringify: function (command) {
2006
+ return "---"; // <- TODO: [🛋] Implement
2007
+ },
2008
+ /**
2009
+ * Reads the FORMAT command from the `TaskJson`
2010
+ *
2011
+ * Note: This is used in `pipelineJsonToString` utility
2012
+ */
2013
+ takeFromTaskJson: function ($taskJson) {
2014
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2015
+ },
2016
+ };
2017
+
2018
+ /**
2019
+ * @@@
2020
+ *
2021
+ * @public exported from `@promptbook/core`
2022
+ */
2023
+ var ChatbotFormfactorDefinition = {
2024
+ name: 'CHATBOT',
2025
+ aliasNames: ['CHAT'],
2026
+ description: "@@@",
2027
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/174",
2028
+ pipelineInterface: {
2029
+ inputParameters: [
2030
+ {
2031
+ name: 'previousTitle',
2032
+ description: "Previous title of the conversation",
2033
+ isInput: true,
2034
+ isOutput: false,
2035
+ },
2036
+ {
2037
+ name: 'previousConversationSummary',
2038
+ description: "Previous conversation summary",
2039
+ isInput: true,
2040
+ isOutput: false,
2041
+ },
2042
+ { name: 'userMessage', description: "User message", isInput: true, isOutput: false },
2043
+ ],
2044
+ outputParameters: [
2045
+ { name: 'title', description: "Title of the conversation", isInput: false, isOutput: true },
2046
+ { name: 'conversationSummary', description: "Summary of the conversation", isInput: false, isOutput: true },
2047
+ { name: 'chatbotResponse', description: "Chatbot response", isInput: false, isOutput: true },
2048
+ ],
2049
+ },
2050
+ };
2051
+
2052
+ /**
2053
+ * Generator is form of app that @@@
2054
+ *
2055
+ * @public exported from `@promptbook/core`
2056
+ */
2057
+ var GeneratorFormfactorDefinition = {
2058
+ name: 'GENERATOR',
2059
+ description: "Generates any kind (in HTML with possible scripts and css format) of content from input message",
2060
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/184",
2061
+ pipelineInterface: {
2062
+ inputParameters: [
2063
+ {
2064
+ name: 'inputMessage',
2065
+ description: "Input message to be image made from",
2066
+ isInput: true,
2067
+ isOutput: false,
2068
+ },
2069
+ ],
2070
+ outputParameters: [
2071
+ {
2072
+ name: 'result',
2073
+ description: "Result in HTML to be shown to user",
2074
+ isInput: false,
2075
+ isOutput: true,
2076
+ },
2077
+ ],
2078
+ },
2079
+ };
2080
+
2081
+ /**
2082
+ * @@@
2083
+ *
2084
+ * @see https://github.com/webgptorg/promptbook/discussions/171
2085
+ *
2086
+ * @public exported from `@promptbook/core`
2087
+ */
2088
+ var GENERIC_PIPELINE_INTERFACE = {
2089
+ inputParameters: [],
2090
+ outputParameters: [],
2091
+ };
2092
+ /**
2093
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2094
+ */
2095
+
2096
+ /**
2097
+ * @@@
2098
+ *
2099
+ * @public exported from `@promptbook/core`
2100
+ */
2101
+ var GenericFormfactorDefinition = {
2102
+ name: 'GENERIC',
2103
+ description: "@@@",
2104
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/173",
2105
+ pipelineInterface: GENERIC_PIPELINE_INTERFACE,
2106
+ };
2107
+
2108
+ /**
2109
+ * Image generator is form of app that generates image from input message
2110
+ *
2111
+ * @public exported from `@promptbook/core`
2112
+ */
2113
+ var ImageGeneratorFormfactorDefinition = {
2114
+ name: 'IMAGE_GENERATOR',
2115
+ description: "Generates prompt for image generation from input message",
2116
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/184",
2117
+ pipelineInterface: {
2118
+ inputParameters: [
2119
+ {
2120
+ name: 'inputMessage',
2121
+ description: "Input message to be image made from",
2122
+ isInput: true,
2123
+ isOutput: false,
2124
+ },
2125
+ ],
2126
+ outputParameters: [
2127
+ {
2128
+ name: 'prompt',
2129
+ description: "Prompt to be used for image generation",
2130
+ isInput: false,
2131
+ isOutput: true,
2132
+ },
2133
+ ],
2134
+ },
2135
+ };
2136
+
2137
+ /**
2138
+ * Matcher is form of app that @@@
2139
+ *
2140
+ * @public exported from `@promptbook/core`
2141
+ */
2142
+ var MatcherFormfactorDefinition = {
2143
+ name: 'EXPERIMENTAL_MATCHER',
2144
+ description: "@@@",
2145
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/177",
2146
+ pipelineInterface: {
2147
+ inputParameters: [
2148
+ /* @@@ */
2149
+ {
2150
+ name: 'nonce',
2151
+ description: 'Just to prevent EXPERIMENTAL_MATCHER to be set as implicit formfactor',
2152
+ isInput: true,
2153
+ isOutput: false,
2154
+ },
2155
+ ],
2156
+ outputParameters: [
2157
+ /* @@@ */
2158
+ ],
2159
+ },
2160
+ };
2161
+
2162
+ /**
2163
+ * Sheets is form of app that @@@
2164
+ *
2165
+ * @public exported from `@promptbook/core`
2166
+ */
2167
+ var SheetsFormfactorDefinition = {
2168
+ name: 'SHEETS',
2169
+ aliasNames: ['SHEETS', 'SHEET'],
2170
+ description: "@@@",
2171
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/176",
2172
+ pipelineInterface: {
2173
+ inputParameters: [
2174
+ {
2175
+ name: 'inputSheet',
2176
+ description: "Input sheet to be processed as csv",
2177
+ isInput: true,
2178
+ isOutput: false,
2179
+ },
2180
+ ],
2181
+ outputParameters: [
2182
+ {
2183
+ name: 'outputSheet',
2184
+ description: "Output sheet as csv",
2185
+ isInput: false,
2186
+ isOutput: true,
2187
+ },
2188
+ ],
2189
+ },
2190
+ };
2191
+
2192
+ /**
2193
+ * Translator is form of app that @@@
2194
+ *
2195
+ * @public exported from `@promptbook/core`
2196
+ */
2197
+ var TranslatorFormfactorDefinition = {
2198
+ name: 'TRANSLATOR',
2199
+ description: "@@@",
2200
+ documentationUrl: "https://github.com/webgptorg/promptbook/discussions/175",
2201
+ pipelineInterface: {
2202
+ inputParameters: [
2203
+ {
2204
+ name: 'inputMessage',
2205
+ description: "Input message to be translated",
2206
+ isInput: true,
2207
+ isOutput: false,
2208
+ },
2209
+ ],
2210
+ outputParameters: [
2211
+ {
2212
+ name: 'outputMessage',
2213
+ description: "Translated output message",
2214
+ isInput: false,
2215
+ isOutput: true,
2216
+ },
2217
+ ],
2218
+ // <- TODO: [🤓] Maybe add {summary}
2219
+ // <- TODO: [🧠] maybe change to {inputText}, {inputText} / or make system for any name of first input and first outpur parameter
2220
+ },
2221
+ };
2222
+
2223
+ /**
2224
+ * All available formfactor definitions
2225
+ *
2226
+ * @public exported from `@promptbook/core`
2227
+ */
2228
+ var FORMFACTOR_DEFINITIONS = [
2229
+ GenericFormfactorDefinition,
2230
+ ChatbotFormfactorDefinition,
2231
+ TranslatorFormfactorDefinition,
2232
+ SheetsFormfactorDefinition,
2233
+ MatcherFormfactorDefinition,
2234
+ GeneratorFormfactorDefinition,
2235
+ ImageGeneratorFormfactorDefinition,
2236
+ ];
2237
+ /**
2238
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2239
+ */
2240
+
2241
+ /**
2242
+ * Parses the formfactor command
2243
+ *
2244
+ * Note: @@@ This command is used as formfactor for new commands - it should NOT be used in any `.book.md` file
2245
+ *
2246
+ * @see `documentationUrl` for more details
2247
+ * @public exported from `@promptbook/editable`
2248
+ */
2249
+ var formfactorCommandParser = {
2250
+ /**
2251
+ * Name of the command
2252
+ */
2253
+ name: 'FORMFACTOR',
2254
+ /**
2255
+ * Aliases for the FORMFACTOR command
2256
+ */
2257
+ aliasNames: ['FORM', 'FF'],
2258
+ /**
2259
+ * FORMFACTOR command can be used in:
2260
+ */
2261
+ isUsedInPipelineHead: true,
2262
+ isUsedInPipelineTask: false,
2263
+ /**
2264
+ * Description of the FORMFACTOR command
2265
+ */
2266
+ description: "@@",
2267
+ /**
2268
+ * Link to documentation
2269
+ */
2270
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/168',
2271
+ /**
2272
+ * Example usages of the FORMFACTOR command
2273
+ */
2274
+ examples: ['FORMFACTOR Chatbot', 'FF Chat'],
2275
+ /**
2276
+ * Parses the FORMFACTOR command
2277
+ */
2278
+ parse: function (input) {
2279
+ var args = input.args;
2280
+ if (args.length !== 1) {
2281
+ throw new ParseError("FORMFACTOR command requires exactly one argument");
2282
+ }
2283
+ var formfactorNameCandidate = args[0].toUpperCase();
2284
+ var formfactor = FORMFACTOR_DEFINITIONS.find(function (definition) {
2285
+ return __spreadArray([definition.name], __read(__assign({ aliasNames: [] }, definition).aliasNames), false).includes(formfactorNameCandidate);
2286
+ });
2287
+ if (formfactor === undefined) {
2288
+ throw new ParseError(spaceTrim(function (block) { return "\n Unknown formfactor name \"".concat(formfactorNameCandidate, "\"\n\n Available formfactors:\n ").concat(block(FORMFACTOR_DEFINITIONS.map(function (_a) {
2289
+ var name = _a.name;
2290
+ return "- ".concat(name);
2291
+ }).join('\n')), "\n "); }));
2292
+ }
2293
+ return {
2294
+ type: 'FORMFACTOR',
2295
+ formfactorName: formfactor.name,
2296
+ };
2297
+ },
2298
+ /**
2299
+ * Apply the FORMFACTOR command to the `pipelineJson`
2300
+ *
2301
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
2302
+ */
2303
+ $applyToPipelineJson: function (command, $pipelineJson) {
2304
+ if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
2305
+ throw new ParseError(spaceTrim("\n Redefinition of `FORMFACTOR` in the pipeline head\n\n You have used:\n 1) FORMFACTOR `".concat($pipelineJson.formfactorName, "`\n 2) FORMFACTOR `").concat(command.formfactorName, "`\n ")));
2306
+ }
2307
+ $pipelineJson.formfactorName = command.formfactorName;
2308
+ },
2309
+ /**
2310
+ * Converts the FORMFACTOR command back to string
2311
+ *
2312
+ * Note: This is used in `pipelineJsonToString` utility
2313
+ */
2314
+ stringify: function (command) {
2315
+ return "FORMFACTOR ".concat(command.formfactorName);
2316
+ },
2317
+ /**
2318
+ * Reads the FORMFACTOR command from the `PipelineJson`
2319
+ *
2320
+ * Note: This is used in `pipelineJsonToString` utility
2321
+ */
2322
+ takeFromPipelineJson: function (pipelineJson) {
2323
+ return [
2324
+ {
2325
+ type: 'FORMFACTOR',
2326
+ formfactorName: pipelineJson.formfactorName,
2327
+ },
2328
+ ];
2329
+ },
2330
+ };
2331
+
2332
+ /**
2333
+ * Parses the joker command
2334
+ *
2335
+ * @see `documentationUrl` for more details
2336
+ * @public exported from `@promptbook/editable`
2337
+ */
2338
+ var jokerCommandParser = {
2339
+ /**
2340
+ * Name of the command
2341
+ */
2342
+ name: 'JOKER',
2343
+ /**
2344
+ * BOILERPLATE command can be used in:
2345
+ */
2346
+ isUsedInPipelineHead: false,
2347
+ isUsedInPipelineTask: true,
2348
+ /**
2349
+ * Description of the JOKER command
2350
+ */
2351
+ description: "Joker parameter is used instead of executing the task result if jokers value meets the expectations requirements",
2352
+ /**
2353
+ * Link to documentation
2354
+ */
2355
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/66',
2356
+ /**
2357
+ * Example usages of the JOKER command
2358
+ */
2359
+ examples: ['JOKER {documentTitle}'],
2360
+ /**
2361
+ * Parses the JOKER command
2362
+ */
2363
+ parse: function (input) {
2364
+ var args = input.args;
2365
+ if (args.length !== 1) {
2366
+ throw new ParseError("JOKE command expects exactly one parameter name");
2367
+ }
2368
+ var parameterNameArg = args[0] || '';
2369
+ var parameterName = validateParameterName(parameterNameArg);
2370
+ return {
2371
+ type: 'JOKER',
2372
+ parameterName: parameterName,
2373
+ };
2374
+ },
2375
+ /**
2376
+ * Apply the JOKER command to the `pipelineJson`
2377
+ *
2378
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
2379
+ */
2380
+ $applyToTaskJson: function (command, $taskJson) {
2381
+ $taskJson.jokerParameterNames = $taskJson.jokerParameterNames || [];
2382
+ $taskJson.jokerParameterNames.push(command.parameterName);
2383
+ },
2384
+ /**
2385
+ * Converts the JOKER command back to string
2386
+ *
2387
+ * Note: This is used in `pipelineJsonToString` utility
2388
+ */
2389
+ stringify: function (command) {
2390
+ return "---"; // <- TODO: [🛋] Implement
2391
+ },
2392
+ /**
2393
+ * Reads the JOKER command from the `TaskJson`
2394
+ *
2395
+ * Note: This is used in `pipelineJsonToString` utility
2396
+ */
2397
+ takeFromTaskJson: function ($taskJson) {
2398
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2399
+ },
2400
+ };
2401
+
2402
+ /**
2403
+ * Tests if given string is valid URL.
2404
+ *
2405
+ * Note: This does not check if the file exists only if the path is valid
2406
+ * @public exported from `@promptbook/utils`
2407
+ */
2408
+ function isValidFilePath(filename) {
2409
+ if (typeof filename !== 'string') {
2410
+ return false;
2411
+ }
2412
+ if (filename.split('\n').length > 1) {
2413
+ return false;
2414
+ }
2415
+ if (filename.split(' ').length >
2416
+ 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
2417
+ return false;
2418
+ }
2419
+ var filenameSlashes = filename.split('\\').join('/');
2420
+ // Absolute Unix path: /hello.txt
2421
+ if (/^(\/)/i.test(filenameSlashes)) {
2422
+ // console.log(filename, 'Absolute Unix path: /hello.txt');
2423
+ return true;
2424
+ }
2425
+ // Absolute Windows path: /hello.txt
2426
+ if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
2427
+ // console.log(filename, 'Absolute Windows path: /hello.txt');
2428
+ return true;
2429
+ }
2430
+ // Relative path: ./hello.txt
2431
+ if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
2432
+ // console.log(filename, 'Relative path: ./hello.txt');
2433
+ return true;
2434
+ }
2435
+ // Allow paths like foo/hello
2436
+ if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
2437
+ // console.log(filename, 'Allow paths like foo/hello');
2438
+ return true;
2439
+ }
2440
+ // Allow paths like hello.book
2441
+ if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
2442
+ // console.log(filename, 'Allow paths like hello.book');
2443
+ return true;
2444
+ }
2445
+ return false;
2446
+ }
2447
+ /**
2448
+ * TODO: [🍏] Implement for MacOs
2449
+ */
2450
+
2451
+ /**
2452
+ * Tests if given string is valid URL.
2453
+ *
2454
+ * Note: Dataurl are considered perfectly valid.
2455
+ * Note: There are two simmilar functions:
2456
+ * - `isValidUrl` which tests any URL
2457
+ * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
2458
+ *
2459
+ * @public exported from `@promptbook/utils`
2460
+ */
2461
+ function isValidUrl(url) {
2462
+ if (typeof url !== 'string') {
2463
+ return false;
2464
+ }
2465
+ try {
2466
+ if (url.startsWith('blob:')) {
2467
+ url = url.replace(/^blob:/, '');
2468
+ }
2469
+ var urlObject = new URL(url /* because fail is handled */);
2470
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
2471
+ return false;
2472
+ }
2473
+ return true;
2474
+ }
2475
+ catch (error) {
2476
+ return false;
2477
+ }
2478
+ }
2479
+
2480
+ /**
2481
+ * @@@
2482
+ *
2483
+ * @param text @@@
2484
+ * @returns @@@
2485
+ * @example 'hello-world'
2486
+ * @example 'i-love-promptbook'
2487
+ * @public exported from `@promptbook/utils`
2488
+ */
2489
+ function normalizeToKebabCase(text) {
2490
+ var e_1, _a;
2491
+ text = removeDiacritics(text);
2492
+ var charType;
2493
+ var lastCharType = 'OTHER';
2494
+ var normalizedName = '';
2495
+ try {
2496
+ for (var text_1 = __values(text), text_1_1 = text_1.next(); !text_1_1.done; text_1_1 = text_1.next()) {
2497
+ var char = text_1_1.value;
2498
+ var normalizedChar = void 0;
2499
+ if (/^[a-z]$/.test(char)) {
2500
+ charType = 'LOWERCASE';
2501
+ normalizedChar = char;
2502
+ }
2503
+ else if (/^[A-Z]$/.test(char)) {
2504
+ charType = 'UPPERCASE';
2505
+ normalizedChar = char.toLowerCase();
2506
+ }
2507
+ else if (/^[0-9]$/.test(char)) {
2508
+ charType = 'NUMBER';
2509
+ normalizedChar = char;
2510
+ }
2511
+ else {
2512
+ charType = 'OTHER';
2513
+ normalizedChar = '-';
2514
+ }
2515
+ if (charType !== lastCharType &&
2516
+ !(lastCharType === 'UPPERCASE' && charType === 'LOWERCASE') &&
2517
+ !(lastCharType === 'NUMBER') &&
2518
+ !(charType === 'NUMBER')) {
2519
+ normalizedName += '-';
2520
+ }
2521
+ normalizedName += normalizedChar;
2522
+ lastCharType = charType;
2523
+ }
2524
+ }
2525
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
2526
+ finally {
2527
+ try {
2528
+ if (text_1_1 && !text_1_1.done && (_a = text_1.return)) _a.call(text_1);
2529
+ }
2530
+ finally { if (e_1) throw e_1.error; }
2531
+ }
2532
+ normalizedName = normalizedName.split(/-+/g).join('-');
2533
+ normalizedName = normalizedName.split(/-?\/-?/g).join('/');
2534
+ normalizedName = normalizedName.replace(/^-/, '');
2535
+ normalizedName = normalizedName.replace(/-$/, '');
2536
+ return normalizedName;
2537
+ }
2538
+ /**
2539
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2540
+ */
2541
+
2542
+ /**
2543
+ * Creates unique name for the source
2544
+ *
2545
+ * @public exported from `@promptbook/editable`
2546
+ */
2547
+ function knowledgeSourceContentToName(knowledgeSourceContent) {
2548
+ var hash = SHA256(hexEncoder.parse(JSON.stringify(knowledgeSourceContent)))
2549
+ // <- TODO: [🥬] Encapsulate sha256 to some private utility function
2550
+ .toString( /* hex */)
2551
+ .substring(0, 20);
2552
+ // <- TODO: [🥬] Make some system for hashes and ids of promptbook
2553
+ var semanticName = normalizeToKebabCase(knowledgeSourceContent.substring(0, 20));
2554
+ var pieces = ['source', semanticName, hash].filter(function (piece) { return piece !== ''; });
2555
+ var name = pieces.join('-').split('--').join('-');
2556
+ // <- TODO: Use MAX_FILENAME_LENGTH
2557
+ return name;
2558
+ }
2559
+ /**
2560
+ * TODO: [🐱‍🐉][🧠] Make some smart crop NOT source-i-m-pavol-a-develop-... BUT source-i-m-pavol-a-developer-...
2561
+ */
2562
+
2563
+ /**
2564
+ * Parses the knowledge command
2565
+ *
2566
+ * @see `documentationUrl` for more details
2567
+ * @public exported from `@promptbook/editable`
2568
+ */
2569
+ var knowledgeCommandParser = {
2570
+ /**
2571
+ * Name of the command
2572
+ */
2573
+ name: 'KNOWLEDGE',
2574
+ /**
2575
+ * BOILERPLATE command can be used in:
2576
+ */
2577
+ isUsedInPipelineHead: true,
2578
+ isUsedInPipelineTask: false,
2579
+ /**
2580
+ * Description of the KNOWLEDGE command
2581
+ */
2582
+ description: "Tells promptbook which external knowledge to use",
2583
+ /**
2584
+ * Link to documentation
2585
+ */
2586
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/41',
2587
+ /**
2588
+ * Example usages of the KNOWLEDGE command
2589
+ */
2590
+ examples: [
2591
+ 'KNOWLEDGE https://www.pavolhejny.com/',
2592
+ 'KNOWLEDGE ./hejny-cv.txt',
2593
+ 'KNOWLEDGE ./hejny-cv.md',
2594
+ 'KNOWLEDGE ./hejny-cv.pdf',
2595
+ 'KNOWLEDGE ./hejny-cv.docx',
2596
+ // <- TODO: [😿] Allow ONLY files scoped in the (sub)directory NOT ../ and test it
2597
+ ],
2598
+ /**
2599
+ * Parses the KNOWLEDGE command
2600
+ */
2601
+ parse: function (input) {
2602
+ var args = input.args;
2603
+ var knowledgeSourceContent = spaceTrim(args[0] || '');
2604
+ if (knowledgeSourceContent === '') {
2605
+ throw new ParseError("Source is not defined");
2606
+ }
2607
+ // TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
2608
+ if (knowledgeSourceContent.startsWith('http://')) {
2609
+ throw new ParseError("Source is not secure");
2610
+ }
2611
+ if (!(isValidFilePath(knowledgeSourceContent) || isValidUrl(knowledgeSourceContent))) {
2612
+ throw new ParseError("Source not valid");
2613
+ }
2614
+ if (knowledgeSourceContent.startsWith('../') ||
2615
+ knowledgeSourceContent.startsWith('/') ||
2616
+ /^[A-Z]:[\\/]+/i.test(knowledgeSourceContent)) {
2617
+ throw new ParseError("Source cannot be outside of the .book.md folder");
2618
+ }
2619
+ return {
2620
+ type: 'KNOWLEDGE',
2621
+ knowledgeSourceContent: knowledgeSourceContent,
2622
+ };
2623
+ },
2624
+ /**
2625
+ * Apply the KNOWLEDGE command to the `pipelineJson`
2626
+ *
2627
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
2628
+ */
2629
+ $applyToPipelineJson: function (command, $pipelineJson) {
2630
+ var knowledgeSourceContent = command.knowledgeSourceContent;
2631
+ $pipelineJson.knowledgeSources.push({
2632
+ name: knowledgeSourceContentToName(knowledgeSourceContent),
2633
+ knowledgeSourceContent: knowledgeSourceContent,
2634
+ });
2635
+ },
2636
+ /**
2637
+ * Converts the KNOWLEDGE command back to string
2638
+ *
2639
+ * Note: This is used in `pipelineJsonToString` utility
2640
+ */
2641
+ stringify: function (command) {
2642
+ return "---"; // <- TODO: [🛋] Implement
2643
+ },
2644
+ /**
2645
+ * Reads the KNOWLEDGE command from the `PipelineJson`
2646
+ *
2647
+ * Note: This is used in `pipelineJsonToString` utility
2648
+ */
2649
+ takeFromPipelineJson: function (pipelineJson) {
2650
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2651
+ },
2652
+ };
2653
+ /**
2654
+ * Note: [⛱] There are two types of KNOWLEDGE commands *...(read more in [⛱])*
2655
+ */
2656
+
2657
+ /**
2658
+ * @@@
2659
+ *
2660
+ * @public exported from `@promptbook/core`
2661
+ */
2662
+ var MODEL_VARIANTS = ['COMPLETION', 'CHAT', 'EMBEDDING' /* <- TODO [🏳] */ /* <- [🤖] */];
2663
+
2664
+ /**
2665
+ * Parses the model command
2666
+ *
2667
+ * @see `documentationUrl` for more details
2668
+ * @deprecated Option to manually set the model requirements is not recommended to use, use `PERSONA` instead
2669
+ * @public exported from `@promptbook/editable`
2670
+ */
2671
+ var modelCommandParser = {
2672
+ /**
2673
+ * Name of the command
2674
+ */
2675
+ name: 'MODEL',
2676
+ /**
2677
+ * BOILERPLATE command can be used in:
2678
+ */
2679
+ isUsedInPipelineHead: true,
2680
+ isUsedInPipelineTask: true,
2681
+ /**
2682
+ * Description of the MODEL command
2683
+ */
2684
+ description: "Tells which `modelRequirements` (for example which model) to use for the prompt task execution",
2685
+ /**
2686
+ * Link to documentation
2687
+ */
2688
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/67',
2689
+ /**
2690
+ * Example usages of the MODEL command
2691
+ */
2692
+ examples: ['MODEL VARIANT Chat', 'MODEL NAME `gpt-4`'],
2693
+ /**
2694
+ * Parses the MODEL command
2695
+ */
2696
+ parse: function (input) {
2697
+ var args = input.args, normalized = input.normalized;
2698
+ var availableVariantsMessage = spaceTrim(function (block) { return "\n Available variants are:\n ".concat(block(MODEL_VARIANTS.map(function (variantName) {
2699
+ return "- ".concat(variantName).concat(variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)');
2700
+ }).join('\n')), "\n "); });
2701
+ // TODO: Make this more elegant and dynamically
2702
+ if (normalized.startsWith('MODEL_VARIANT')) {
2703
+ if (normalized === 'MODEL_VARIANT_CHAT') {
2704
+ return {
2705
+ type: 'MODEL',
2706
+ key: 'modelVariant',
2707
+ value: 'CHAT',
2708
+ };
2709
+ }
2710
+ else if (normalized === 'MODEL_VARIANT_COMPLETION') {
2711
+ return {
2712
+ type: 'MODEL',
2713
+ key: 'modelVariant',
2714
+ value: 'COMPLETION',
2715
+ };
2716
+ // <- Note: [🤖]
2717
+ }
2718
+ else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
2719
+ spaceTrim(function (block) { return "\n Embedding model can not be used in pipeline\n\n ".concat(block(availableVariantsMessage), "\n "); });
2720
+ }
2721
+ else {
2722
+ throw new ParseError(spaceTrim(function (block) { return "\n Unknown model variant in command:\n\n ".concat(block(availableVariantsMessage), "\n "); }));
2723
+ }
2724
+ }
2725
+ if (normalized.startsWith('MODEL_NAME')) {
2726
+ return {
2727
+ type: 'MODEL',
2728
+ key: 'modelName',
2729
+ value: args.pop(),
2730
+ };
2731
+ }
2732
+ else {
2733
+ throw new ParseError(spaceTrim(function (block) { return "\n Unknown model key in command.\n\n Supported model keys are:\n ".concat(block(['variant', 'name'].join(', ')), "\n\n Example:\n - MODEL VARIANT Chat\n - MODEL NAME gpt-4\n "); }));
2734
+ }
2735
+ },
2736
+ /**
2737
+ * Apply the MODEL command to the `pipelineJson`
2738
+ *
2739
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
2740
+ */
2741
+ $applyToPipelineJson: function (command, $pipelineJson) {
2742
+ $pipelineJson.defaultModelRequirements = $pipelineJson.defaultModelRequirements || {};
2743
+ // TODO: [🚜] DRY
2744
+ if ($pipelineJson.defaultModelRequirements[command.key] !== undefined) {
2745
+ if ($pipelineJson.defaultModelRequirements[command.key] === command.value) {
2746
+ console.warn("Multiple commands `MODEL ".concat(command.key, " ").concat(command.value, "` in the pipeline head"));
2747
+ // <- TODO: [🚎][💩] Some better way how to get warnings from pipeline parsing / logic
2748
+ }
2749
+ else {
2750
+ throw new ParseError(spaceTrim("\n Redefinition of `MODEL ".concat(command.key, "` in the pipeline head\n\n You have used:\n 1) `MODEL ").concat(command.key, " ").concat($pipelineJson.defaultModelRequirements[command.key], "`\n 2) `MODEL ").concat(command.key, " ").concat(command.value, "`\n ")));
2751
+ }
2752
+ }
2753
+ $pipelineJson.defaultModelRequirements[command.key] = command.value;
2754
+ },
2755
+ /**
2756
+ * Apply the MODEL command to the `pipelineJson`
2757
+ *
2758
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
2759
+ */
2760
+ $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
2761
+ if ($taskJson.taskType !== 'PROMPT_TASK') {
2762
+ throw new ParseError("MODEL command can only be used in PROMPT_TASK block");
2763
+ }
2764
+ $taskJson.modelRequirements = $taskJson.modelRequirements || {};
2765
+ // TODO: [🚜] DRY
2766
+ if ($taskJson.modelRequirements[command.key] !== undefined) {
2767
+ if ($taskJson.modelRequirements[command.key] === command.value) {
2768
+ console.warn("Multiple commands `MODEL ".concat({
2769
+ modelName: 'NAME',
2770
+ modelVariant: 'VARIANT',
2771
+ maxTokens: '???',
2772
+ }[command.key], " ").concat(command.value, "` in the task \"").concat($taskJson.title || $taskJson.name, "\""));
2773
+ }
2774
+ else {
2775
+ throw new ParseError(spaceTrim("\n Redefinition of MODEL `".concat(command.key, "` in the task \"").concat($taskJson.title || $taskJson.name, "\"\n\n You have used:\n - MODEL ").concat(command.key, " ").concat($taskJson.modelRequirements[command.key], "\n - MODEL ").concat(command.key, " ").concat(command.value, "\n ")));
2776
+ }
2777
+ }
2778
+ if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
2779
+ console.log(spaceTrim("\n Setting MODEL `".concat(command.key, "` in the task \"").concat($taskJson.title || $taskJson.name, "\" to the same value as in the pipeline head\n\n In pipeline head:\n - MODEL ").concat(command.key, " ").concat(($pipelineJson.defaultModelRequirements || {})[command.key], "\n\n But same value is used in the task:\n - MODEL ").concat(command.key, " ").concat(command.value, "\n ")));
2780
+ }
2781
+ $taskJson.modelRequirements[command.key] = command.value;
2782
+ },
2783
+ /**
2784
+ * Converts the MODEL command back to string
2785
+ *
2786
+ * Note: This is used in `pipelineJsonToString` utility
2787
+ */
2788
+ stringify: function (command) {
2789
+ return "---"; // <- TODO: [🛋] Implement
2790
+ },
2791
+ /**
2792
+ * Reads the MODEL command from the `PipelineJson`
2793
+ *
2794
+ * Note: This is used in `pipelineJsonToString` utility
2795
+ */
2796
+ takeFromPipelineJson: function (pipelineJson) {
2797
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2798
+ },
2799
+ /**
2800
+ * Reads the MODEL command from the `TaskJson`
2801
+ *
2802
+ * Note: This is used in `pipelineJsonToString` utility
2803
+ */
2804
+ takeFromTaskJson: function ($taskJson) {
2805
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2806
+ },
2807
+ };
2808
+
2809
+ /**
2810
+ * Parses the parameter command
2811
+ *
2812
+ * @see `documentationUrl` for more details
2813
+ * @public exported from `@promptbook/editable`
2814
+ */
2815
+ var parameterCommandParser = {
2816
+ /**
2817
+ * Name of the command
2818
+ */
2819
+ name: 'PARAMETER',
2820
+ /**
2821
+ * Aliases for the PARAMETER command
2822
+ */
2823
+ aliasNames: ['PARAM', 'INPUT_PARAM', 'OUTPUT_PARAM', 'INPUT_PARAMETER', 'OUTPUT_PARAMETER'],
2824
+ /*
2825
+ Note: [🦈] No need for extra alias name because it is already preprocessed
2826
+ */
2827
+ /**
2828
+ * BOILERPLATE command can be used in:
2829
+ */
2830
+ isUsedInPipelineHead: true,
2831
+ isUsedInPipelineTask: true,
2832
+ /**
2833
+ * Description of the PARAMETER command
2834
+ */
2835
+ description: "Describes one parameter of the task",
2836
+ /**
2837
+ * Link to documentation
2838
+ */
2839
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/68',
2840
+ /**
2841
+ * Example usages of the PARAMETER command
2842
+ */
2843
+ examples: ['PARAMETER {title} Title of the book', 'OUTPUT PARAMETER {websiteContent} Content of the book'],
2844
+ /**
2845
+ * Parses the PARAMETER command
2846
+ */
2847
+ parse: function (input) {
2848
+ var normalized = input.normalized, args = input.args, raw = input.raw;
2849
+ var parameterNameRaw = args.shift() || '';
2850
+ var parameterDescriptionRaw = args.join(' ');
2851
+ // <- TODO: When [🥶] fixed, change to:
2852
+ // > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
2853
+ if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
2854
+ throw new ParseError(spaceTrim(function (block) { return "\n Parameter `{".concat(parameterNameRaw, "}` can not contain another parameter in description\n\n The description:\n ").concat(block(parameterDescriptionRaw), "\n "); }));
2855
+ }
2856
+ var isInput = normalized.startsWith('INPUT');
2857
+ var isOutput = normalized.startsWith('OUTPUT');
2858
+ if (raw.startsWith('> {')) {
2859
+ isInput = false;
2860
+ isOutput = false;
2861
+ }
2862
+ var parameterName = validateParameterName(parameterNameRaw);
2863
+ var parameterDescription = parameterDescriptionRaw.trim() || null;
2864
+ return {
2865
+ type: 'PARAMETER',
2866
+ parameterName: parameterName,
2867
+ parameterDescription: parameterDescription,
2868
+ isInput: isInput,
2869
+ isOutput: isOutput,
2870
+ };
2871
+ },
2872
+ /**
2873
+ * Apply the PARAMETER command to the `pipelineJson`
2874
+ *
2875
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
2876
+ */
2877
+ $applyToPipelineJson: function (command, $pipelineJson) {
2878
+ // Note: [🍣] Do nothing, its application is implemented separately in `parsePipeline`
2879
+ },
2880
+ /**
2881
+ * Apply the PARAMETER command to the `pipelineJson`
2882
+ *
2883
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
2884
+ */
2885
+ $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
2886
+ // Note: [🍣] Do nothing, its application is implemented separately in `parsePipeline`
2887
+ },
2888
+ /**
2889
+ * Converts the PARAMETER command back to string
2890
+ *
2891
+ * Note: This is used in `pipelineJsonToString` utility
2892
+ */
2893
+ stringify: function (command) {
2894
+ return "---"; // <- TODO: [🛋] Implement
2895
+ },
2896
+ /**
2897
+ * Reads the PARAMETER command from the `PipelineJson`
2898
+ *
2899
+ * Note: This is used in `pipelineJsonToString` utility
2900
+ */
2901
+ takeFromPipelineJson: function (pipelineJson) {
2902
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2903
+ },
2904
+ /**
2905
+ * Reads the PARAMETER command from the `TaskJson`
2906
+ *
2907
+ * Note: This is used in `pipelineJsonToString` utility
2908
+ */
2909
+ takeFromTaskJson: function ($taskJson) {
2910
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2911
+ },
2912
+ };
2913
+
2914
+ /**
2915
+ * Parses the persona command
2916
+ *
2917
+ * @see `documentationUrl` for more details
2918
+ * @public exported from `@promptbook/editable`
2919
+ */
2920
+ var personaCommandParser = {
2921
+ /**
2922
+ * Name of the command
2923
+ */
2924
+ name: 'PERSONA',
2925
+ /**
2926
+ * Aliases for the PERSONA command
2927
+ */
2928
+ aliasNames: ['PERSON'],
2929
+ /**
2930
+ * PERSONA command can be used in:
2931
+ */
2932
+ isUsedInPipelineHead: true,
2933
+ isUsedInPipelineTask: true,
2934
+ /**
2935
+ * Description of the PERSONA command
2936
+ */
2937
+ description: "Persona command is used to specify who the system is, it will be transformed into system message, top_t,...",
2938
+ /**
2939
+ * Link to documentation
2940
+ */
2941
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/22',
2942
+ /**
2943
+ * Example usages of the PERSONA command
2944
+ */
2945
+ examples: ['PERSONA Jane, skilled copywriter', 'PERSONA Joe, male 28 years old, programmer'],
2946
+ /**
2947
+ * Parses the PERSONA command
2948
+ */
2949
+ parse: function (input) {
2950
+ var rawArgs = input.rawArgs;
2951
+ var _a = __read(rawArgs.split(/[,;:]/, 2), 2), personaNameRaw = _a[0], personaDescriptionRaw = _a[1];
2952
+ var personaName = (personaNameRaw || '').trim();
2953
+ if (personaName === '') {
2954
+ throw new ParseError("You must set name for the persona");
2955
+ }
2956
+ var personaDescription = (personaDescriptionRaw || '').trim();
2957
+ if (personaDescription === '') {
2958
+ personaDescription = null;
2959
+ }
2960
+ return {
2961
+ type: 'PERSONA',
2962
+ personaName: personaName,
2963
+ personaDescription: personaDescription,
2964
+ };
2965
+ },
2966
+ /**
2967
+ * Apply the PERSONA command to the `pipelineJson`
2968
+ *
2969
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
2970
+ */
2971
+ $applyToPipelineJson: function (command, $pipelineJson) {
2972
+ $applyToTaskJson(command, null, $pipelineJson);
2973
+ },
2974
+ $applyToTaskJson: $applyToTaskJson,
2975
+ /**
2976
+ * Converts the PERSONA command back to string
2977
+ *
2978
+ * Note: This is used in `pipelineJsonToString` utility
2979
+ */
2980
+ stringify: function (command) {
2981
+ return "---"; // <- TODO: [🛋] Implement
2982
+ },
2983
+ /**
2984
+ * Reads the PERSONA command from the `PipelineJson`
2985
+ *
2986
+ * Note: This is used in `pipelineJsonToString` utility
2987
+ */
2988
+ takeFromPipelineJson: function (pipelineJson) {
2989
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2990
+ },
2991
+ /**
2992
+ * Reads the PERSONA command from the `TaskJson`
2993
+ *
2994
+ * Note: This is used in `pipelineJsonToString` utility
2995
+ */
2996
+ takeFromTaskJson: function ($taskJson) {
2997
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
2998
+ },
2999
+ };
3000
+ /**
3001
+ * Apply the PERSONA command to the `pipelineJson`
3002
+ *
3003
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
3004
+ */
3005
+ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
3006
+ var personaName = command.personaName, personaDescription = command.personaDescription;
3007
+ if ($taskJson !== null) {
3008
+ if ($taskJson.taskType !== 'PROMPT_TASK') {
3009
+ throw new ParseError("PERSONA command can be used only in PROMPT_TASK block");
3010
+ }
3011
+ $taskJson.personaName = personaName;
3012
+ }
3013
+ var persona = $pipelineJson.personas.find(function (persona) { return persona.name === personaName; });
3014
+ if (persona === undefined) {
3015
+ $pipelineJson.personas.push({
3016
+ name: personaName,
3017
+ description: personaDescription || '',
3018
+ });
3019
+ return;
3020
+ }
3021
+ if (persona.description === personaDescription) {
3022
+ return;
3023
+ }
3024
+ if (personaDescription === null) {
3025
+ return;
3026
+ }
3027
+ if (persona.description === '') {
3028
+ persona.description = personaDescription;
3029
+ return;
3030
+ }
3031
+ console.warn(spaceTrim("\n\n Persona \"".concat(personaName, "\" is defined multiple times with different description:\n\n First definition:\n ").concat(persona.description, "\n\n Second definition:\n ").concat(personaDescription, "\n\n ")));
3032
+ persona.description += spaceTrim('\n\n' + personaDescription);
3033
+ }
3034
+
3035
+ /**
3036
+ * @@@
3037
+ *
3038
+ * @param javascriptName @@@
3039
+ * @returns @@@
3040
+ * @public exported from `@promptbook/utils`
3041
+ */
3042
+ function isValidJavascriptName(javascriptName) {
3043
+ if (typeof javascriptName !== 'string') {
3044
+ return false;
3045
+ }
3046
+ return /^[a-zA-Z_$][0-9a-zA-Z_$]*$/i.test(javascriptName);
3047
+ }
3048
+
3049
+ /**
3050
+ * Parses the postprocess command
3051
+ *
3052
+ * @see `documentationUrl` for more details
3053
+ * @public exported from `@promptbook/editable`
3054
+ */
3055
+ var postprocessCommandParser = {
3056
+ /**
3057
+ * Name of the command
3058
+ */
3059
+ name: 'POSTPROCESS',
3060
+ aliasNames: ['POSTPROCESSING', 'PP'],
3061
+ /**
3062
+ * BOILERPLATE command can be used in:
3063
+ */
3064
+ isUsedInPipelineHead: false,
3065
+ isUsedInPipelineTask: true,
3066
+ /**
3067
+ * Description of the POSTPROCESS command
3068
+ */
3069
+ description: "Defines the postprocess function to be used on the result from LLM and before the result is validated",
3070
+ /**
3071
+ * Link to documentation
3072
+ */
3073
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/31',
3074
+ /**
3075
+ * Example usages of the POSTPROCESS command
3076
+ */
3077
+ examples: [
3078
+ 'POSTPROCESS unwrapResult' /* <- TODO: Make it `POSTPROCESS` examples dynamic, load from all possible postprocess functions */,
3079
+ ],
3080
+ /**
3081
+ * Parses the POSTPROCESS command
3082
+ */
3083
+ parse: function (input) {
3084
+ var args = input.args;
3085
+ var functionName = args.pop();
3086
+ if (functionName === undefined) {
3087
+ throw new ParseError("Postprocess function name is required");
3088
+ }
3089
+ if (!isValidJavascriptName(functionName)) {
3090
+ throw new ParseError("Invalid postprocess function name \"".concat(functionName, "\""));
3091
+ }
3092
+ if (args.length > 0) {
3093
+ throw new ParseError("Can not have more than one postprocess function");
3094
+ }
3095
+ return {
3096
+ type: 'POSTPROCESS',
3097
+ functionName: functionName,
3098
+ };
3099
+ },
3100
+ /**
3101
+ * Apply the POSTPROCESS command to the `pipelineJson`
3102
+ *
3103
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
3104
+ */
3105
+ $applyToTaskJson: function (command, $taskJson) {
3106
+ $taskJson.postprocessingFunctionNames = $taskJson.postprocessingFunctionNames || [];
3107
+ $taskJson.postprocessingFunctionNames.push(command.functionName);
3108
+ },
3109
+ /**
3110
+ * Converts the POSTPROCESS command back to string
3111
+ *
3112
+ * Note: This is used in `pipelineJsonToString` utility
3113
+ */
3114
+ stringify: function (command) {
3115
+ return "---"; // <- TODO: [🛋] Implement
3116
+ },
3117
+ /**
3118
+ * Reads the POSTPROCESS command from the `TaskJson`
3119
+ *
3120
+ * Note: This is used in `pipelineJsonToString` utility
3121
+ */
3122
+ takeFromTaskJson: function ($taskJson) {
3123
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
3124
+ },
3125
+ };
3126
+
3127
+ /**
3128
+ * All available task types
3129
+ *
3130
+ * There is is distinction between task types and section types
3131
+ * - Every section in markdown has its SectionType
3132
+ * - Some sections are tasks but other can be non-task sections
3133
+ *
3134
+ * @public exported from `@promptbook/core`
3135
+ */
3136
+ var TaskTypes = [
3137
+ 'PROMPT',
3138
+ 'SIMPLE',
3139
+ 'SCRIPT',
3140
+ 'DIALOG',
3141
+ // <- [🅱]
3142
+ ];
3143
+
3144
+ /**
3145
+ * All available sections which are not tasks
3146
+ *
3147
+ * @public exported from `@promptbook/core`
3148
+ */
3149
+ var NonTaskSectionTypes = ['EXAMPLE', 'KNOWLEDGE', 'INSTRUMENT', 'ACTION'];
3150
+ /**
3151
+ * All available section types
3152
+ *
3153
+ * There is is distinction between task types and section types
3154
+ * - Every section in markdown has its SectionType
3155
+ * - Some sections are tasks but other can be non-task sections
3156
+ *
3157
+ * @public exported from `@promptbook/core`
3158
+ */
3159
+ var SectionTypes = __spreadArray(__spreadArray([], __read(TaskTypes.map(function (TaskType) { return "".concat(TaskType, "_TASK"); })), false), __read(NonTaskSectionTypes), false);
3160
+
3161
+ /**
3162
+ * Parses the section command
3163
+ *
3164
+ * @see `documentationUrl` for more details
3165
+ * @public exported from `@promptbook/editable`
3166
+ */
3167
+ var sectionCommandParser = {
3168
+ /**
3169
+ * Name of the command
3170
+ */
3171
+ name: 'SECTION',
3172
+ /**
3173
+ * Aliases for the SECTION command
3174
+ */
3175
+ aliasNames: [
3176
+ 'PROMPT',
3177
+ 'SIMPLE',
3178
+ 'SCRIPT',
3179
+ 'DIALOG',
3180
+ 'SAMPLE',
3181
+ 'EXAMPLE',
3182
+ 'KNOWLEDGE',
3183
+ 'INSTRUMENT',
3184
+ 'ACTION', // <- Note: [⛱]
3185
+ ],
3186
+ /**
3187
+ * Aliases for the SECTION command
3188
+ */
3189
+ deprecatedNames: ['TEMPLATE', 'BLOCK', 'EXECUTE'],
3190
+ /**
3191
+ * BOILERPLATE command can be used in:
3192
+ */
3193
+ isUsedInPipelineHead: false,
3194
+ isUsedInPipelineTask: true,
3195
+ /**
3196
+ * Description of the SECTION command
3197
+ */
3198
+ description: "Defines the purpose of the markdown section - if its a task and which type or something else",
3199
+ /**
3200
+ * Link to documentation
3201
+ */
3202
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/64',
3203
+ /**
3204
+ * Example usages of the SECTION command
3205
+ */
3206
+ examples: [
3207
+ // Short form:
3208
+ 'PROMPT',
3209
+ 'SIMPLE',
3210
+ 'SCRIPT',
3211
+ 'DIALOG',
3212
+ // <- [🅱]
3213
+ 'EXAMPLE',
3214
+ 'KNOWLEDGE',
3215
+ 'INSTRUMENT',
3216
+ 'ACTION',
3217
+ // -----------------
3218
+ // Recommended (reversed) form:
3219
+ 'PROMPT SECTION',
3220
+ 'SIMPLE SECTION',
3221
+ 'SCRIPT SECTION',
3222
+ 'DIALOG SECTION',
3223
+ // <- [🅱]
3224
+ 'EXAMPLE SECTION',
3225
+ 'KNOWLEDGE SECTION',
3226
+ 'INSTRUMENT SECTION',
3227
+ 'ACTION SECTION',
3228
+ // -----------------
3229
+ // Standard form:
3230
+ 'SECTION PROMPT',
3231
+ 'SECTION SIMPLE',
3232
+ 'SECTION SCRIPT',
3233
+ 'SECTION DIALOG',
3234
+ // <- [🅱]
3235
+ 'SECTION EXAMPLE',
3236
+ 'SECTION KNOWLEDGE',
3237
+ 'SECTION INSTRUMENT',
3238
+ 'SECTION ACTION',
3239
+ ],
3240
+ // TODO: [♓️] order: -10 /* <- Note: Putting before other commands */
3241
+ /**
3242
+ * Parses the SECTION command
3243
+ */
3244
+ parse: function (input) {
3245
+ var normalized = input.normalized;
3246
+ normalized = normalized.split('SAMPLE').join('EXAMPLE');
3247
+ normalized = normalized.split('EXECUTE_').join('');
3248
+ normalized = normalized.split('DIALOGUE').join('DIALOG');
3249
+ var taskTypes = SectionTypes.filter(function (sectionType) {
3250
+ return normalized.includes(sectionType.split('_TASK').join(''));
3251
+ });
3252
+ if (taskTypes.length !== 1) {
3253
+ throw new ParseError(spaceTrim(function (block) { return "\n Unknown section type \"".concat(normalized, "\"\n\n Supported section types are:\n ").concat(block(SectionTypes.join(', ')), "\n "); }));
3254
+ }
3255
+ var taskType = taskTypes[0];
3256
+ return {
3257
+ type: 'SECTION',
3258
+ taskType: taskType,
3259
+ };
3260
+ },
3261
+ /**
3262
+ * Apply the SECTION command to the `pipelineJson`
3263
+ *
3264
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
3265
+ */
3266
+ $applyToTaskJson: function (command, $taskJson, $pipelineJson) {
3267
+ if ($taskJson.isSectionTypeSet === true) {
3268
+ throw new ParseError(spaceTrim("\n Section type is already defined in the section.\n It can be defined only once.\n "));
3269
+ }
3270
+ $taskJson.isSectionTypeSet = true;
3271
+ // TODO: [🍧][💩] Rearrange better - but at bottom and unwrap from function
3272
+ var expectResultingParameterName = function () {
3273
+ if ($taskJson.resultingParameterName) {
3274
+ return;
3275
+ }
3276
+ throw new ParseError("Task section and example section must end with return statement -> {parameterName}");
3277
+ };
3278
+ if ($taskJson.content === undefined) {
3279
+ throw new UnexpectedError("Content is missing in the taskJson - probbably commands are applied in wrong order");
3280
+ }
3281
+ if (command.taskType === 'EXAMPLE') {
3282
+ expectResultingParameterName();
3283
+ var parameter = $pipelineJson.parameters.find(function (param) { return param.name === $taskJson.resultingParameterName; });
3284
+ if (parameter === undefined) {
3285
+ // TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
3286
+ throw new ParseError("Parameter `{".concat($taskJson.resultingParameterName, "}` is not defined so can not define example value of it"));
3287
+ }
3288
+ parameter.exampleValues = parameter.exampleValues || [];
3289
+ parameter.exampleValues.push($taskJson.content);
3290
+ $taskJson.isTask = false;
3291
+ return;
3292
+ }
3293
+ if (command.taskType === 'KNOWLEDGE') {
3294
+ knowledgeCommandParser.$applyToPipelineJson({
3295
+ type: 'KNOWLEDGE',
3296
+ knowledgeSourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
3297
+ }, $pipelineJson);
3298
+ $taskJson.isTask = false;
3299
+ return;
3300
+ }
3301
+ if (command.taskType === 'ACTION') {
3302
+ console.error(new NotYetImplementedError('Actions are not implemented yet'));
3303
+ $taskJson.isTask = false;
3304
+ return;
3305
+ }
3306
+ if (command.taskType === 'INSTRUMENT') {
3307
+ console.error(new NotYetImplementedError('Instruments are not implemented yet'));
3308
+ $taskJson.isTask = false;
3309
+ return;
3310
+ }
3311
+ expectResultingParameterName();
3312
+ $taskJson.taskType = command.taskType;
3313
+ $taskJson.isTask = true;
3314
+ },
3315
+ /**
3316
+ * Converts the SECTION command back to string
3317
+ *
3318
+ * Note: This is used in `pipelineJsonToString` utility
3319
+ */
3320
+ stringify: function (command) {
3321
+ return "---"; // <- TODO: [🛋] Implement
3322
+ },
3323
+ /**
3324
+ * Reads the SECTION command from the `TaskJson`
3325
+ *
3326
+ * Note: This is used in `pipelineJsonToString` utility
3327
+ */
3328
+ takeFromTaskJson: function ($taskJson) {
3329
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
3330
+ },
3331
+ };
3332
+ /**
3333
+ * Note: [⛱] There are two types of KNOWLEDGE, ACTION and INSTRUMENT commands:
3334
+ * 1) There are commands `KNOWLEDGE`, `ACTION` and `INSTRUMENT` used in the pipeline head, they just define the knowledge, action or instrument as single line after the command
3335
+ * - KNOWLEDGE Look at https://en.wikipedia.org/wiki/Artificial_intelligence
3336
+ * 2) `KNOWLEDGE SECTION` which has short form `KNOWLEDGE` is used in the sectiom, does not refer the line itself, but the content of the section block
3337
+ * - KNOWLEDGE SECTION
3338
+ *
3339
+ * ```
3340
+ * Look at https://en.wikipedia.org/wiki/Artificial_intelligence
3341
+ * ```
3342
+ */
3343
+
3344
+ /**
3345
+ * Checks if an URL is reserved for private networks or localhost.
3346
+ *
3347
+ * Note: There are two simmilar functions:
3348
+ * - `isUrlOnPrivateNetwork` which tests full URL
3349
+ * - `isHostnameOnPrivateNetwork` *(this one)* which tests just hostname
3350
+ *
3351
+ * @public exported from `@promptbook/utils`
3352
+ */
3353
+ function isHostnameOnPrivateNetwork(hostname) {
3354
+ if (hostname === 'example.com' ||
3355
+ hostname === 'localhost' ||
3356
+ hostname.endsWith('.localhost') ||
3357
+ hostname.endsWith('.local') ||
3358
+ hostname.endsWith('.test') ||
3359
+ hostname === '127.0.0.1' ||
3360
+ hostname === '::1') {
3361
+ return true;
3362
+ }
3363
+ if (hostname.includes(':')) {
3364
+ // IPv6
3365
+ var ipParts = hostname.split(':');
3366
+ return ipParts[0] === 'fc00' || ipParts[0] === 'fd00' || ipParts[0] === 'fe80';
3367
+ }
3368
+ else {
3369
+ // IPv4
3370
+ var ipParts = hostname.split('.').map(function (part) { return Number.parseInt(part, 10); });
3371
+ return (ipParts[0] === 10 ||
3372
+ (ipParts[0] === 172 && ipParts[1] >= 16 && ipParts[1] <= 31) ||
3373
+ (ipParts[0] === 192 && ipParts[1] === 168));
3374
+ }
3375
+ }
3376
+
3377
+ /**
3378
+ * Checks if an IP address or hostname is reserved for private networks or localhost.
3379
+ *
3380
+ * Note: There are two simmilar functions:
3381
+ * - `isUrlOnPrivateNetwork` *(this one)* which tests full URL
3382
+ * - `isHostnameOnPrivateNetwork` which tests just hostname
3383
+ *
3384
+ * @param {string} ipAddress - The IP address to check.
3385
+ * @returns {boolean} Returns true if the IP address is reserved for private networks or localhost, otherwise false.
3386
+ * @public exported from `@promptbook/utils`
3387
+ */
3388
+ function isUrlOnPrivateNetwork(url) {
3389
+ if (typeof url === 'string') {
3390
+ url = new URL(url);
3391
+ }
3392
+ return isHostnameOnPrivateNetwork(url.hostname);
3393
+ }
3394
+
3395
+ /**
3396
+ * Tests if given string is valid pipeline URL URL.
3397
+ *
3398
+ * Note: There are two simmilar functions:
3399
+ * - `isValidUrl` which tests any URL
3400
+ * - `isValidPipelineUrl` *(this one)* which tests just pipeline URL
3401
+ *
3402
+ * @public exported from `@promptbook/utils`
3403
+ */
3404
+ function isValidPipelineUrl(url) {
3405
+ if (!isValidUrl(url)) {
3406
+ return false;
3407
+ }
3408
+ if (!url.startsWith('https://')) {
3409
+ return false;
3410
+ }
3411
+ if (url.includes('#')) {
3412
+ // TODO: [🐠]
3413
+ return false;
3414
+ }
3415
+ if (isUrlOnPrivateNetwork(url)) {
3416
+ return false;
3417
+ }
3418
+ return true;
3419
+ }
3420
+ /**
3421
+ * TODO: [🐠] Maybe more info why the URL is invalid
3422
+ */
3423
+
3424
+ /**
3425
+ * Parses the url command
3426
+ *
3427
+ * @see `documentationUrl` for more details
3428
+ * @public exported from `@promptbook/editable`
3429
+ */
3430
+ var urlCommandParser = {
3431
+ /**
3432
+ * Name of the command
3433
+ */
3434
+ name: 'URL',
3435
+ aliasNames: ['PIPELINE_URL'],
3436
+ /*
3437
+ Note: [🛵] No need for this alias name because it is already preprocessed
3438
+ aliasNames: ['HTTPS'],
3439
+ */
3440
+ /**
3441
+ * BOILERPLATE command can be used in:
3442
+ */
3443
+ isUsedInPipelineHead: true,
3444
+ isUsedInPipelineTask: false,
3445
+ /**
3446
+ * Description of the URL command
3447
+ */
3448
+ description: "Declares unique URL for the pipeline",
3449
+ /**
3450
+ * Link to documentation
3451
+ */
3452
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/70',
3453
+ /**
3454
+ * Example usages of the URL command
3455
+ */
3456
+ examples: [
3457
+ 'PIPELINE URL https://promptbook.studio/library/write-cv.book.md',
3458
+ 'URL https://promptbook.studio/library/write-cv.book.md',
3459
+ 'https://promptbook.studio/library/write-cv.book.md',
3460
+ ],
3461
+ /**
3462
+ * Parses the URL command
3463
+ */
3464
+ parse: function (input) {
3465
+ var args = input.args;
3466
+ var pipelineUrl = args.pop();
3467
+ if (pipelineUrl === undefined) {
3468
+ throw new ParseError("URL is required");
3469
+ }
3470
+ // TODO: [🧠][🚲] This should be maybe tested as logic not parse
3471
+ if (!isValidPipelineUrl(pipelineUrl)) {
3472
+ throw new ParseError("Invalid pipeline URL \"".concat(pipelineUrl, "\""));
3473
+ }
3474
+ if (args.length > 0) {
3475
+ throw new ParseError("Can not have more than one pipeline URL");
3476
+ }
3477
+ /*
3478
+ TODO: [🐠 Maybe more info from `isValidPipelineUrl`:
3479
+ if (pipelineUrl.protocol !== 'https:') {
3480
+ throw new ParseError(`Protocol must be HTTPS`);
3481
+ }
3482
+
3483
+ if (pipelineUrl.hash !== '') {
3484
+ throw new ParseError(
3485
+ spaceTrim(
3486
+ `
3487
+ URL must not contain hash
3488
+ Hash is used for identification of the section of the pipeline
3489
+ `,
3490
+ ),
3491
+ );
3492
+ }
3493
+ */
3494
+ return {
3495
+ type: 'URL',
3496
+ pipelineUrl: new URL(pipelineUrl),
3497
+ };
3498
+ },
3499
+ /**
3500
+ * Apply the URL command to the `pipelineJson`
3501
+ *
3502
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
3503
+ */
3504
+ $applyToPipelineJson: function (command, $pipelineJson) {
3505
+ $pipelineJson.pipelineUrl = command.pipelineUrl.href;
3506
+ },
3507
+ /**
3508
+ * Converts the URL command back to string
3509
+ *
3510
+ * Note: This is used in `pipelineJsonToString` utility
3511
+ */
3512
+ stringify: function (command) {
3513
+ return "---"; // <- TODO: [🛋] Implement
3514
+ },
3515
+ /**
3516
+ * Reads the URL command from the `PipelineJson`
3517
+ *
3518
+ * Note: This is used in `pipelineJsonToString` utility
3519
+ */
3520
+ takeFromPipelineJson: function (pipelineJson) {
3521
+ throw new NotYetImplementedError("[\uD83D\uDECB] Not implemented yet"); // <- TODO: [🛋] Implement
3522
+ },
3523
+ };
3524
+
3525
+ /**
3526
+ * Parses the action command
3527
+ *
3528
+ * @see `documentationUrl` for more details
3529
+ * @public exported from `@promptbook/editable`
3530
+ */
3531
+ var actionCommandParser = {
3532
+ /**
3533
+ * Name of the command
3534
+ */
3535
+ name: 'ACTION',
3536
+ /**
3537
+ * ACTION command can be used in:
3538
+ */
3539
+ isUsedInPipelineHead: true,
3540
+ isUsedInPipelineTask: false,
3541
+ /**
3542
+ * Description of the ACTION command
3543
+ */
3544
+ description: "Actions influences from the pipeline or task into external world. Like turning on a light, sending an email, etc.",
3545
+ /**
3546
+ * Link to documentation
3547
+ */
3548
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/72',
3549
+ /**
3550
+ * Example usages of the ACTION command
3551
+ */
3552
+ examples: ['ACTION'],
3553
+ /**
3554
+ * Parses the ACTION command
3555
+ */
3556
+ parse: function (input) {
3557
+ input.args;
3558
+ return {
3559
+ type: 'ACTION',
3560
+ };
3561
+ },
3562
+ /**
3563
+ * Apply the ACTION command to the `pipelineJson`
3564
+ *
3565
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
3566
+ */
3567
+ $applyToPipelineJson: function (command, $pipelineJson) {
3568
+ console.error(new NotYetImplementedError('[🛠] Actions are not implemented yet'));
3569
+ },
3570
+ /**
3571
+ * Converts the ACTION command back to string
3572
+ *
3573
+ * Note: This is used in `pipelineJsonToString` utility
3574
+ */
3575
+ stringify: function (command) {
3576
+ throw new NotYetImplementedError('[🛠] Actions are not implemented yet');
3577
+ },
3578
+ /**
3579
+ * Reads the ACTION command from the `PipelineJson`
3580
+ *
3581
+ * Note: This is used in `pipelineJsonToString` utility
3582
+ */
3583
+ takeFromPipelineJson: function (pipelineJson) {
3584
+ throw new NotYetImplementedError('[🛠] Actions are not implemented yet');
3585
+ },
3586
+ };
3587
+ /**
3588
+ * Note: [⛱] There are two types of ACTION commands *...(read more in [⛱])*
3589
+ */
3590
+
3591
+ /**
3592
+ * Parses the instrument command
3593
+ *
3594
+ * @see `documentationUrl` for more details
3595
+ * @public exported from `@promptbook/editable`
3596
+ */
3597
+ var instrumentCommandParser = {
3598
+ /**
3599
+ * Name of the command
3600
+ */
3601
+ name: 'INSTRUMENT',
3602
+ /**
3603
+ * INSTRUMENT command can be used in:
3604
+ */
3605
+ isUsedInPipelineHead: true,
3606
+ isUsedInPipelineTask: false,
3607
+ /**
3608
+ * Description of the INSTRUMENT command
3609
+ */
3610
+ description: "Instrument command is used to specify the instrument to be used in the pipeline or task like search, calculate, etc.",
3611
+ /**
3612
+ * Link to documentation
3613
+ */
3614
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/71',
3615
+ /**
3616
+ * Example usages of the INSTRUMENT command
3617
+ */
3618
+ examples: ['INSTRUMENT'],
3619
+ /**
3620
+ * Parses the INSTRUMENT command
3621
+ */
3622
+ parse: function (input) {
3623
+ input.args;
3624
+ return {
3625
+ type: 'INSTRUMENT',
3626
+ };
3627
+ },
3628
+ /**
3629
+ * Apply the INSTRUMENT command to the `pipelineJson`
3630
+ *
3631
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
3632
+ */
3633
+ $applyToPipelineJson: function (command, $pipelineJson) {
3634
+ console.error(new NotYetImplementedError('[🛠] Instruments are not implemented yet'));
3635
+ },
3636
+ /**
3637
+ * Converts the INSTRUMENT command back to string
3638
+ *
3639
+ * Note: This is used in `pipelineJsonToString` utility
3640
+ */
3641
+ stringify: function (command) {
3642
+ throw new NotYetImplementedError('[🛠] Instruments are not implemented yet');
3643
+ },
3644
+ /**
3645
+ * Reads the INSTRUMENT command from the `PipelineJson`
3646
+ *
3647
+ * Note: This is used in `pipelineJsonToString` utility
3648
+ */
3649
+ takeFromPipelineJson: function (pipelineJson) {
3650
+ throw new NotYetImplementedError('[🛠] Instruments are not implemented yet');
3651
+ },
3652
+ };
3653
+ /**
3654
+ * Note: [⛱] There are two types of INSTRUMENT commands *...(read more in [⛱])*
3655
+ */
3656
+
3657
+ /**
3658
+ * All available command parsers
3659
+ *
3660
+ * @public exported from `@promptbook/editable`
3661
+ */
3662
+ var COMMANDS = [
3663
+ sectionCommandParser,
3664
+ expectCommandParser,
3665
+ formatCommandParser,
3666
+ jokerCommandParser,
3667
+ modelCommandParser,
3668
+ parameterCommandParser,
3669
+ postprocessCommandParser,
3670
+ bookVersionCommandParser,
3671
+ formfactorCommandParser,
3672
+ urlCommandParser,
3673
+ knowledgeCommandParser,
3674
+ actionCommandParser,
3675
+ instrumentCommandParser,
3676
+ personaCommandParser,
3677
+ foreachCommandParser,
3678
+ boilerplateCommandParser, // <- TODO: Only in development, remove in production
3679
+ // <- Note: [♓️][💩] This is the order of the commands in the pipeline, BUT its not used in parsing and before usage maybe it should be done better
3680
+ ];
3681
+ /**
3682
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3683
+ */
3684
+
3685
+ /**
3686
+ * Gets the parser for the command
3687
+ *
3688
+ * @returns the parser for the command
3689
+ * @throws {UnexpectedError} if the parser is not found
3690
+ *
3691
+ * @public exported from `@promptbook/editable`
3692
+ */
3693
+ function getParserForCommand(command) {
3694
+ var commandParser = COMMANDS.find(function (commandParser) { return commandParser.name === command.type; });
3695
+ if (commandParser === undefined) {
3696
+ throw new UnexpectedError(spaceTrim$1(function (block) { return "\n Command ".concat(command.type, " parser is not found\n\n ").concat(block(JSON.stringify(command, null, 4)
3697
+ .split('\n')
3698
+ .map(function (line) { return "> ".concat(line); })
3699
+ .join('\n')), "\n "); }));
3700
+ }
3701
+ return commandParser;
3702
+ }
3703
+
3704
+ /**
3705
+ * Removes Markdown formatting tags from a string.
3706
+ *
3707
+ * @param {string} str - The string to remove Markdown tags from.
3708
+ * @returns {string} The input string with all Markdown tags removed.
3709
+ * @public exported from `@promptbook/markdown-utils`
3710
+ */
3711
+ function removeMarkdownFormatting(str) {
3712
+ // Remove bold formatting
3713
+ str = str.replace(/\*\*(.*?)\*\*/g, '$1');
3714
+ // Remove italic formatting
3715
+ str = str.replace(/\*(.*?)\*/g, '$1');
3716
+ // Remove code formatting
3717
+ str = str.replace(/`(.*?)`/g, '$1');
3718
+ return str;
3719
+ }
3720
+
3721
+ /**
3722
+ * Parses one line of ul/ol to command
3723
+ *
3724
+ * @returns parsed command object
3725
+ * @throws {ParseError} if the command is invalid
3726
+ *
3727
+ * @public exported from `@promptbook/editable`
3728
+ */
3729
+ function parseCommand(raw, usagePlace) {
3730
+ if (raw.includes('\n') || raw.includes('\r')) {
3731
+ throw new ParseError('Command can not contain new line characters' /* <- TODO: [🚞] */);
3732
+ }
3733
+ // TODO: Unit test all this processing and parsing
3734
+ var normalized = raw.trim();
3735
+ normalized = normalized.split('`').join('');
3736
+ normalized = normalized.split('"').join('');
3737
+ normalized = normalized.split("'").join('');
3738
+ normalized = normalized.split('~').join('');
3739
+ normalized = normalized.split('[').join('');
3740
+ normalized = normalized.split(']').join('');
3741
+ normalized = normalized.split('(').join('');
3742
+ normalized = normalized.split(')').join('');
3743
+ normalized = normalizeTo_SCREAMING_CASE(normalized);
3744
+ var items = raw
3745
+ .trim()
3746
+ // Note: [🐡]
3747
+ .split(/^>/)
3748
+ .join('')
3749
+ // ---
3750
+ .trim()
3751
+ .split(/["'`]/)
3752
+ .join('')
3753
+ .trim()
3754
+ // Note: [🛵]:
3755
+ .split(/^http/)
3756
+ .join('URL http')
3757
+ // ---
3758
+ // Note: [🦈]
3759
+ .split(/^{/)
3760
+ .join('PARAMETER {')
3761
+ // ---
3762
+ .split(' ')
3763
+ .map(function (part) { return part.trim(); })
3764
+ .filter(function (item) { return item !== ''; })
3765
+ .map(removeMarkdownFormatting)
3766
+ .map(function (item) { return item.trim(); });
3767
+ if (items.length === 0 || items[0] === '') {
3768
+ throw new ParseError(spaceTrim$1(function (block) {
3769
+ return "\n Malformed command:\n - ".concat(raw, "\n\n Supported commands are:\n ").concat(block(getSupportedCommandsMessage()), "\n\n ");
3770
+ }));
3771
+ }
3772
+ // Note: Taking command name from beginning of the line
3773
+ // FOO | BAR Arg1 Arg2 Arg3
3774
+ // FOO BAR | Arg1 Arg2 Arg3
3775
+ for (var commandNameSegmentsCount = 0; commandNameSegmentsCount < Math.min(items.length, 3); commandNameSegmentsCount++) {
3776
+ var commandNameRaw = items.slice(0, commandNameSegmentsCount + 1).join('_');
3777
+ var args = items.slice(commandNameSegmentsCount + 1);
3778
+ var rawArgs = raw
3779
+ .substring(commandNameRaw.length)
3780
+ .trim();
3781
+ var command = parseCommandVariant({ usagePlace: usagePlace, raw: raw, rawArgs: rawArgs, normalized: normalized, args: args, commandNameRaw: commandNameRaw });
3782
+ if (command !== null) {
3783
+ return command;
3784
+ }
3785
+ }
3786
+ // Note: Taking command name from end of the line
3787
+ // Arg1 Arg2 Arg3 | FOO
3788
+ {
3789
+ var commandNameRaw = items.slice(-1).join('_');
3790
+ var args = items.slice(0, -1); // <- Note: This is probbably not correct
3791
+ var rawArgs = raw
3792
+ .substring(0, raw.length - commandNameRaw.length)
3793
+ .trim();
3794
+ var command = parseCommandVariant({ usagePlace: usagePlace, raw: raw, rawArgs: rawArgs, normalized: normalized, args: args, commandNameRaw: commandNameRaw });
3795
+ if (command !== null) {
3796
+ return command;
3797
+ }
3798
+ }
3799
+ throw new ParseError(spaceTrim$1(function (block) {
3800
+ return "\n Malformed or unknown command:\n - ".concat(raw, "\n\n Supported commands are:\n ").concat(block(getSupportedCommandsMessage()), "\n\n ");
3801
+ }));
3802
+ }
3803
+ /**
3804
+ * @@@
3805
+ */
3806
+ function getSupportedCommandsMessage() {
3807
+ return COMMANDS.flatMap(function (_a) {
3808
+ var name = _a.name, aliasNames = _a.aliasNames, description = _a.description, documentationUrl = _a.documentationUrl;
3809
+ // <- Note: [🦦] Its strange that this type assertion is needed
3810
+ return __spreadArray([
3811
+ "- **".concat(name, "** ").concat(description, ", see [discussion](").concat(documentationUrl, ")")
3812
+ ], __read((aliasNames || []).map(function (aliasName) { return " - **".concat(aliasName, "** Alias for **").concat(name, "**"); })), false);
3813
+ }).join('\n');
3814
+ }
3815
+ /**
3816
+ * @@@
3817
+ */
3818
+ function parseCommandVariant(input) {
3819
+ var e_1, _a;
3820
+ var commandNameRaw = input.commandNameRaw, usagePlace = input.usagePlace, normalized = input.normalized, args = input.args, raw = input.raw, rawArgs = input.rawArgs;
3821
+ var commandName = normalizeTo_SCREAMING_CASE(commandNameRaw);
3822
+ var _loop_1 = function (commandParser) {
3823
+ // <- Note: [🦦] Its strange that this type assertion is needed
3824
+ var name_1 = commandParser.name, isUsedInPipelineHead = commandParser.isUsedInPipelineHead, isUsedInPipelineTask = commandParser.isUsedInPipelineTask, aliasNames = commandParser.aliasNames, deprecatedNames = commandParser.deprecatedNames, parse = commandParser.parse;
3825
+ if (just(false)) ;
3826
+ else if (usagePlace === 'PIPELINE_HEAD' && !isUsedInPipelineHead) {
3827
+ return "continue";
3828
+ }
3829
+ else if (usagePlace === 'PIPELINE_TASK' && !isUsedInPipelineTask) {
3830
+ return "continue";
3831
+ }
3832
+ var names = __spreadArray(__spreadArray([name_1], __read((aliasNames || [])), false), __read((deprecatedNames || [])), false);
3833
+ if (names.includes(commandName)) {
3834
+ try {
3835
+ return { value: parse({ usagePlace: usagePlace, raw: raw, rawArgs: rawArgs, normalized: normalized, args: args }) };
3836
+ }
3837
+ catch (error) {
3838
+ if (!(error instanceof ParseError)) {
3839
+ throw error;
3840
+ }
3841
+ throw new ParseError(spaceTrim$1(function (block) {
3842
+ return "\n Invalid ".concat(commandName, " command:\n\n Your command:\n - ").concat(raw, "\n\n The detailed error:\n ").concat(block(error.message), "\n\n Usage of ").concat(commandName, ":\n ").concat(block(commandParser.examples.map(function (example) { return "- ".concat(example); }).join('\n')), "\n\n All supported commands are:\n ").concat(block(getSupportedCommandsMessage()), "\n\n ");
3843
+ }));
3844
+ }
3845
+ }
3846
+ };
3847
+ try {
3848
+ for (var _b = __values(COMMANDS), _c = _b.next(); !_c.done; _c = _b.next()) {
3849
+ var commandParser = _c.value;
3850
+ var state_1 = _loop_1(commandParser);
3851
+ if (typeof state_1 === "object")
3852
+ return state_1.value;
3853
+ }
3854
+ }
3855
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
3856
+ finally {
3857
+ try {
3858
+ if (_c && !_c.done && (_a = _b.return)) _a.call(_b);
3859
+ }
3860
+ finally { if (e_1) throw e_1.error; }
3861
+ }
3862
+ return null;
3863
+ }
3864
+
3865
+ /**
3866
+ * Function `removePipelineCommand` will remove one command from pipeline string
3867
+ *
3868
+ * @public exported from `@promptbook/editable`
3869
+ */
3870
+ function removePipelineCommand(options) {
3871
+ var e_1, _a;
3872
+ var command = options.command, pipeline = options.pipeline;
3873
+ var lines = pipeline.split('\n');
3874
+ // TODO: [🧽] DRY
3875
+ var currentType = 'MARKDOWN';
3876
+ var newLines = [];
3877
+ try {
3878
+ for (var lines_1 = __values(lines), lines_1_1 = lines_1.next(); !lines_1_1.done; lines_1_1 = lines_1.next()) {
3879
+ var line = lines_1_1.value;
3880
+ if (currentType === 'MARKDOWN') {
3881
+ if (line.startsWith('```')) {
3882
+ currentType = 'CODE_BLOCK';
3883
+ }
3884
+ else if (line.includes('<!--')) {
3885
+ currentType = 'COMMENT';
3886
+ }
3887
+ }
3888
+ else if (currentType === 'CODE_BLOCK') {
3889
+ if (line.startsWith('```')) {
3890
+ currentType = 'MARKDOWN';
3891
+ }
3892
+ }
3893
+ else if (currentType === 'COMMENT') {
3894
+ if (line.includes('-->')) {
3895
+ currentType = 'MARKDOWN';
3896
+ }
3897
+ }
3898
+ if (currentType === 'MARKDOWN' && /^(-|\d\))/m.test(line) && line.toUpperCase().includes(command)) {
3899
+ continue;
3900
+ }
3901
+ newLines.push(line);
3902
+ }
3903
+ }
3904
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
3905
+ finally {
3906
+ try {
3907
+ if (lines_1_1 && !lines_1_1.done && (_a = lines_1.return)) _a.call(lines_1);
3908
+ }
3909
+ finally { if (e_1) throw e_1.error; }
3910
+ }
3911
+ var newPipeline = spaceTrim(newLines.join('\n'));
3912
+ return newPipeline;
3913
+ }
3914
+
3915
+ /**
3916
+ * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
3917
+ *
3918
+ * @public exported from `@promptbook/core`
3919
+ */
3920
+ var PipelineLogicError = /** @class */ (function (_super) {
3921
+ __extends(PipelineLogicError, _super);
3922
+ function PipelineLogicError(message) {
3923
+ var _this = _super.call(this, message) || this;
3924
+ _this.name = 'PipelineLogicError';
3925
+ Object.setPrototypeOf(_this, PipelineLogicError.prototype);
3926
+ return _this;
3927
+ }
3928
+ return PipelineLogicError;
3929
+ }(Error));
3930
+
3931
+ /**
3932
+ * Function `renamePipelineParameter` will find all usable parameters for given task
3933
+ * In other words, it will find all parameters that are not used in the task itseld and all its dependencies
3934
+ *
3935
+ * @throws {PipelineLogicError} If the new parameter name is already used in the pipeline
3936
+ * @public exported from `@promptbook/editable`
3937
+ */
3938
+ function renamePipelineParameter(options) {
3939
+ var e_1, _a, e_2, _b;
3940
+ var pipeline = options.pipeline, oldParameterName = options.oldParameterName, newParameterName = options.newParameterName;
3941
+ if (pipeline.parameters.some(function (parameter) { return parameter.name === newParameterName; })) {
3942
+ throw new PipelineLogicError("Can not replace {".concat(oldParameterName, "} to {").concat(newParameterName, "} because {").concat(newParameterName, "} is already used in the pipeline"));
3943
+ }
3944
+ var renamedPipeline = __assign(__assign({}, pipeline), {
3945
+ // <- TODO: [🪓] This should be without `as $PipelineJson`
3946
+ parameters: __spreadArray([], __read(pipeline.parameters), false), tasks: __spreadArray([], __read(pipeline.tasks), false) });
3947
+ try {
3948
+ for (var _c = __values(renamedPipeline.parameters), _d = _c.next(); !_d.done; _d = _c.next()) {
3949
+ var parameter = _d.value;
3950
+ if (parameter.name !== oldParameterName) {
3951
+ continue;
3952
+ }
3953
+ parameter.name = newParameterName;
3954
+ }
3955
+ }
3956
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
3957
+ finally {
3958
+ try {
3959
+ if (_d && !_d.done && (_a = _c.return)) _a.call(_c);
3960
+ }
3961
+ finally { if (e_1) throw e_1.error; }
3962
+ }
3963
+ try {
3964
+ for (var _e = __values(renamedPipeline.tasks), _f = _e.next(); !_f.done; _f = _e.next()) {
3965
+ var task = _f.value;
3966
+ if (task.resultingParameterName === oldParameterName) {
3967
+ task.resultingParameterName = newParameterName;
3968
+ }
3969
+ task.dependentParameterNames = task.dependentParameterNames.map(function (dependentParameterName) {
3970
+ return dependentParameterName === oldParameterName ? newParameterName : dependentParameterName;
3971
+ });
3972
+ task.content = task.content.replace(new RegExp("{".concat(oldParameterName, "}"), 'g'), "{".concat(newParameterName, "}"));
3973
+ task.title = task.title.replace(new RegExp("{".concat(oldParameterName, "}"), 'g'), "{".concat(newParameterName, "}"));
3974
+ task.description =
3975
+ task.description === undefined
3976
+ ? undefined
3977
+ : task.description.replace(new RegExp("{".concat(oldParameterName, "}"), 'g'), "{".concat(newParameterName, "}"));
3978
+ }
3979
+ }
3980
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
3981
+ finally {
3982
+ try {
3983
+ if (_f && !_f.done && (_b = _e.return)) _b.call(_e);
3984
+ }
3985
+ finally { if (e_2) throw e_2.error; }
3986
+ }
3987
+ return renamedPipeline;
3988
+ }
3989
+
568
3990
  // <- TODO: Auto convert to type `import { ... } from 'type-fest';`
569
3991
  /**
570
3992
  * Tests if the value is [🚉] serializable as JSON
@@ -626,5 +4048,5 @@ function stringifyPipelineJson(pipeline) {
626
4048
  * TODO: [🍙] Make some standard order of json properties
627
4049
  */
628
4050
 
629
- export { BOOK_LANGUAGE_VERSION, PROMPTBOOK_ENGINE_VERSION, removePipelineCommand, renamePipelineParameter, stringifyPipelineJson };
4051
+ export { BOOK_LANGUAGE_VERSION, COMMANDS, PROMPTBOOK_ENGINE_VERSION, actionCommandParser, bookVersionCommandParser, expectCommandParser, foreachCommandParser, formatCommandParser, formfactorCommandParser, getParserForCommand, instrumentCommandParser, jokerCommandParser, knowledgeCommandParser, knowledgeSourceContentToName, modelCommandParser, parameterCommandParser, parseCommand, personaCommandParser, postprocessCommandParser, removePipelineCommand, renamePipelineParameter, sectionCommandParser, stringifyPipelineJson, urlCommandParser };
630
4052
  //# sourceMappingURL=index.es.js.map