@promptbook/wizard 0.112.0-70 → 0.112.0-72

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/esm/index.es.js +1085 -954
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/book-3.0/Book.d.ts +6 -0
  4. package/esm/src/book-components/Chat/utils/getToolCallChipletInfo.test.d.ts +1 -0
  5. package/esm/src/cli/cli-commands/agent/agentRunCliOptions.d.ts +12 -2
  6. package/esm/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -0
  7. package/esm/src/cli/cli-commands/run/prepareRunCommandResources.d.ts +20 -0
  8. package/esm/src/cli/cli-commands/run/resolveRunInputParameters.d.ts +12 -0
  9. package/esm/src/cli/cli-commands/run/runCommandAction.d.ts +21 -0
  10. package/esm/src/cli/cli-commands/run/runPipelineExecution.d.ts +14 -0
  11. package/esm/src/cli/cli-commands/run.d.ts +1 -1
  12. package/esm/src/conversion/parsePipeline/applyPipelineHead.d.ts +8 -0
  13. package/esm/src/conversion/parsePipeline/createInitialPipelineJson.d.ts +8 -0
  14. package/esm/src/conversion/parsePipeline/createUniqueSectionNameResolver.d.ts +14 -0
  15. package/esm/src/conversion/parsePipeline/defineParameter.d.ts +8 -0
  16. package/esm/src/conversion/parsePipeline/extractPipelineDescription.d.ts +6 -0
  17. package/esm/src/conversion/parsePipeline/finalizeParsedPipeline.d.ts +8 -0
  18. package/esm/src/conversion/parsePipeline/getPipelineIdentification.d.ts +7 -0
  19. package/esm/src/conversion/parsePipeline/parsePreparedPipelineSections.d.ts +18 -0
  20. package/esm/src/conversion/parsePipeline/preparePipelineString.d.ts +8 -0
  21. package/esm/src/conversion/parsePipeline/processPipelineSection.d.ts +9 -0
  22. package/esm/src/version.d.ts +1 -1
  23. package/package.json +2 -2
  24. package/umd/index.umd.js +1085 -954
  25. package/umd/index.umd.js.map +1 -1
  26. package/umd/src/book-3.0/Book.d.ts +6 -0
  27. package/umd/src/book-components/Chat/utils/getToolCallChipletInfo.test.d.ts +1 -0
  28. package/umd/src/cli/cli-commands/agent/agentRunCliOptions.d.ts +12 -2
  29. package/umd/src/cli/cli-commands/agent/initializeAgentRunnerCommand.d.ts +1 -0
  30. package/umd/src/cli/cli-commands/run/prepareRunCommandResources.d.ts +20 -0
  31. package/umd/src/cli/cli-commands/run/resolveRunInputParameters.d.ts +12 -0
  32. package/umd/src/cli/cli-commands/run/runCommandAction.d.ts +21 -0
  33. package/umd/src/cli/cli-commands/run/runPipelineExecution.d.ts +14 -0
  34. package/umd/src/cli/cli-commands/run.d.ts +1 -1
  35. package/umd/src/conversion/parsePipeline/applyPipelineHead.d.ts +8 -0
  36. package/umd/src/conversion/parsePipeline/createInitialPipelineJson.d.ts +8 -0
  37. package/umd/src/conversion/parsePipeline/createUniqueSectionNameResolver.d.ts +14 -0
  38. package/umd/src/conversion/parsePipeline/defineParameter.d.ts +8 -0
  39. package/umd/src/conversion/parsePipeline/extractPipelineDescription.d.ts +6 -0
  40. package/umd/src/conversion/parsePipeline/finalizeParsedPipeline.d.ts +8 -0
  41. package/umd/src/conversion/parsePipeline/getPipelineIdentification.d.ts +7 -0
  42. package/umd/src/conversion/parsePipeline/parsePreparedPipelineSections.d.ts +18 -0
  43. package/umd/src/conversion/parsePipeline/preparePipelineString.d.ts +8 -0
  44. package/umd/src/conversion/parsePipeline/processPipelineSection.d.ts +9 -0
  45. package/umd/src/version.d.ts +1 -1
package/umd/index.umd.js CHANGED
@@ -49,7 +49,7 @@
49
49
  * @generated
50
50
  * @see https://github.com/webgptorg/promptbook
51
51
  */
52
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-70';
52
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-72';
53
53
  /**
54
54
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
55
55
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -22870,7 +22870,9 @@
22870
22870
  };
22871
22871
  const mantleRadiusX = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.horizontalStretch;
22872
22872
  const mantleRadiusY = size * morphologyProfile.body.bodyRadiusRatio * morphologyProfile.body.verticalStretch * 1.1;
22873
- const mantleRadiusZ = size * morphologyProfile.body.bodyRadiusRatio * (0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
22873
+ const mantleRadiusZ = size *
22874
+ morphologyProfile.body.bodyRadiusRatio *
22875
+ (0.9 + (morphologyProfile.body.horizontalStretch - 1) * 0.3);
22874
22876
  const underbodyRadiusX = mantleRadiusX * (0.9 + (morphologyProfile.tentacles.rootSpreadScale - 1) * 0.08);
22875
22877
  const underbodyRadiusY = mantleRadiusY * (0.44 + morphologyProfile.body.lowerDropRatio * 3.1);
22876
22878
  const underbodyRadiusZ = mantleRadiusZ * 0.78;
@@ -22956,7 +22958,11 @@
22956
22958
  z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, faceEyeSpacing, faceEyeYOffset),
22957
22959
  }, faceEyeRadiusX, faceEyeRadiusY, mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, size, palette, timeMs, animationPhase + 0.7 + eyeRandom() * 0.6, interaction, morphologyProfile.face.eyeStyle);
22958
22960
  drawProjectedMouth(context, [
22959
- { x: -mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY) },
22961
+ {
22962
+ x: -mouthHalfWidth,
22963
+ y: mouthY,
22964
+ z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, -mouthHalfWidth, mouthY),
22965
+ },
22960
22966
  {
22961
22967
  x: size * morphologyProfile.face.mouthCenterOffsetRatio,
22962
22968
  y: mouthY +
@@ -22965,7 +22971,11 @@
22965
22971
  interaction.gazeY * size * 0.01,
22966
22972
  z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, size * morphologyProfile.face.mouthCenterOffsetRatio, mouthY),
22967
22973
  },
22968
- { x: mouthHalfWidth, y: mouthY, z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY) },
22974
+ {
22975
+ x: mouthHalfWidth,
22976
+ y: mouthY,
22977
+ z: resolveEllipsoidSurfaceDepth(mantleRadiusX, mantleRadiusY, mantleRadiusZ, mouthHalfWidth, mouthY),
22978
+ },
22969
22979
  ], mantleCenter, headPitch, headYaw, sceneCenterX, sceneCenterY, palette, size);
22970
22980
  },
22971
22981
  };
@@ -23126,7 +23136,8 @@
23126
23136
  z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.3 + sway * size * 0.012,
23127
23137
  };
23128
23138
  const controlPointTwo = {
23129
- x: anchorPoint.x + Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
23139
+ x: anchorPoint.x +
23140
+ Math.sin(orbitAngle) * lateralReach * (0.82 + morphologyProfile.tentacles.swayScale * 0.12),
23130
23141
  y: anchorPoint.y + flowLength * 0.66,
23131
23142
  z: anchorPoint.z + Math.cos(orbitAngle) * depthReach * 0.72 + sway * size * 0.02,
23132
23143
  };
@@ -23191,8 +23202,7 @@
23191
23202
  context.beginPath();
23192
23203
  context.moveTo(startPoint.x, startPoint.y);
23193
23204
  context.lineTo(endPoint.x, endPoint.y);
23194
- context.strokeStyle =
23195
- tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
23205
+ context.strokeStyle = tentacleStroke.colorBias > 0.6 ? `${palette.secondary}f0` : `${palette.primary}f0`;
23196
23206
  context.lineWidth = width;
23197
23207
  context.lineCap = 'round';
23198
23208
  context.stroke();
@@ -31177,6 +31187,212 @@
31177
31187
  * @private internal USE TIMEOUT constant
31178
31188
  */
31179
31189
  const MAX_LIST_TIMEOUTS_LIMIT = 100;
31190
+ /**
31191
+ * Creates one formatted timeout-argument validation error.
31192
+ *
31193
+ * @private internal utility of USE TIMEOUT
31194
+ */
31195
+ function createTimeoutToolArgsError(message) {
31196
+ return new PipelineExecutionError(_spaceTrim.spaceTrim(`
31197
+ ${message}
31198
+ `));
31199
+ }
31200
+ /**
31201
+ * Normalizes one optional timeout id string.
31202
+ *
31203
+ * @private internal utility of USE TIMEOUT
31204
+ */
31205
+ function normalizeOptionalTimeoutId(value) {
31206
+ return typeof value === 'string' ? value.trim() : '';
31207
+ }
31208
+ /**
31209
+ * Parses timeout target selection for tools that accept either `timeoutId` or `allActive: true`.
31210
+ *
31211
+ * @private internal utility of USE TIMEOUT
31212
+ */
31213
+ function parseTimeoutTargetSelection(args, options) {
31214
+ const timeoutId = normalizeOptionalTimeoutId(args.timeoutId);
31215
+ const allActive = args.allActive === true;
31216
+ if (timeoutId && allActive) {
31217
+ throw createTimeoutToolArgsError(options.bothMessage);
31218
+ }
31219
+ if (allActive) {
31220
+ return { allActive: true };
31221
+ }
31222
+ if (!timeoutId) {
31223
+ throw createTimeoutToolArgsError(options.missingMessage);
31224
+ }
31225
+ return {
31226
+ timeoutId,
31227
+ allActive: false,
31228
+ };
31229
+ }
31230
+ /**
31231
+ * Parses one explicit `dueAt` update value.
31232
+ *
31233
+ * @private internal utility of USE TIMEOUT
31234
+ */
31235
+ function parseOptionalTimeoutDueAt(value) {
31236
+ if (typeof value !== 'string' || value.trim().length === 0) {
31237
+ return undefined;
31238
+ }
31239
+ const normalizedDueAt = value.trim();
31240
+ const dueAtTimestamp = Date.parse(normalizedDueAt);
31241
+ if (!Number.isFinite(dueAtTimestamp)) {
31242
+ throw createTimeoutToolArgsError('Timeout `dueAt` must be one valid ISO timestamp.');
31243
+ }
31244
+ return new Date(dueAtTimestamp).toISOString();
31245
+ }
31246
+ /**
31247
+ * Parses one explicit `extendByMs` update value.
31248
+ *
31249
+ * @private internal utility of USE TIMEOUT
31250
+ */
31251
+ function parseOptionalTimeoutExtendByMs(value) {
31252
+ if (typeof value !== 'number') {
31253
+ return undefined;
31254
+ }
31255
+ if (!Number.isFinite(value) || value <= 0) {
31256
+ throw createTimeoutToolArgsError('Timeout `extendByMs` must be a positive number of milliseconds.');
31257
+ }
31258
+ return Math.floor(value);
31259
+ }
31260
+ /**
31261
+ * Parses one explicit `recurrenceIntervalMs` update value.
31262
+ *
31263
+ * @private internal utility of USE TIMEOUT
31264
+ */
31265
+ function parseOptionalTimeoutRecurrenceInterval(value) {
31266
+ if (value === null) {
31267
+ return null;
31268
+ }
31269
+ if (typeof value !== 'number') {
31270
+ return undefined;
31271
+ }
31272
+ if (!Number.isFinite(value) || value <= 0) {
31273
+ throw createTimeoutToolArgsError('Timeout `recurrenceIntervalMs` must be a positive number of milliseconds or `null`.');
31274
+ }
31275
+ return Math.floor(value);
31276
+ }
31277
+ /**
31278
+ * Parses one explicit `message` update value.
31279
+ *
31280
+ * @private internal utility of USE TIMEOUT
31281
+ */
31282
+ function parseOptionalTimeoutMessage(value) {
31283
+ if (value === null) {
31284
+ return null;
31285
+ }
31286
+ if (typeof value !== 'string') {
31287
+ return undefined;
31288
+ }
31289
+ const normalizedMessage = value.trim();
31290
+ return normalizedMessage.length > 0 ? normalizedMessage : null;
31291
+ }
31292
+ /**
31293
+ * Parses one explicit `parameters` update value.
31294
+ *
31295
+ * @private internal utility of USE TIMEOUT
31296
+ */
31297
+ function parseOptionalTimeoutParameters(value) {
31298
+ if (value === undefined) {
31299
+ return undefined;
31300
+ }
31301
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
31302
+ throw createTimeoutToolArgsError('Timeout `parameters` must be one JSON object.');
31303
+ }
31304
+ return value;
31305
+ }
31306
+ /**
31307
+ * Parses one explicit `paused` update value.
31308
+ *
31309
+ * @private internal utility of USE TIMEOUT
31310
+ */
31311
+ function parseOptionalTimeoutPaused(value) {
31312
+ return typeof value === 'boolean' ? value : undefined;
31313
+ }
31314
+ /**
31315
+ * Parses patch fields for `update_timeout`.
31316
+ *
31317
+ * @private internal utility of USE TIMEOUT
31318
+ */
31319
+ function parseTimeoutUpdatePatch(args) {
31320
+ const patch = {};
31321
+ const dueAt = parseOptionalTimeoutDueAt(args.dueAt);
31322
+ const extendByMs = parseOptionalTimeoutExtendByMs(args.extendByMs);
31323
+ const recurrenceIntervalMs = parseOptionalTimeoutRecurrenceInterval(args.recurrenceIntervalMs);
31324
+ const message = parseOptionalTimeoutMessage(args.message);
31325
+ const parameters = parseOptionalTimeoutParameters(args.parameters);
31326
+ const paused = parseOptionalTimeoutPaused(args.paused);
31327
+ if (dueAt !== undefined) {
31328
+ patch.dueAt = dueAt;
31329
+ }
31330
+ if (extendByMs !== undefined) {
31331
+ patch.extendByMs = extendByMs;
31332
+ }
31333
+ if (patch.dueAt !== undefined && patch.extendByMs !== undefined) {
31334
+ throw createTimeoutToolArgsError('Timeout update cannot include both `dueAt` and `extendByMs`.');
31335
+ }
31336
+ if (recurrenceIntervalMs !== undefined) {
31337
+ patch.recurrenceIntervalMs = recurrenceIntervalMs;
31338
+ }
31339
+ if (message !== undefined) {
31340
+ patch.message = message;
31341
+ }
31342
+ if (parameters !== undefined) {
31343
+ patch.parameters = parameters;
31344
+ }
31345
+ if (paused !== undefined) {
31346
+ patch.paused = paused;
31347
+ }
31348
+ return patch;
31349
+ }
31350
+ /**
31351
+ * Determines whether the patch contains fields that are only supported for single-timeout updates.
31352
+ *
31353
+ * @private internal utility of USE TIMEOUT
31354
+ */
31355
+ function hasSingleTimeoutOnlyPatchFields(patch) {
31356
+ return (patch.dueAt !== undefined ||
31357
+ patch.extendByMs !== undefined ||
31358
+ patch.recurrenceIntervalMs !== undefined ||
31359
+ patch.message !== undefined ||
31360
+ patch.parameters !== undefined);
31361
+ }
31362
+ /**
31363
+ * Parses bulk timeout update arguments.
31364
+ *
31365
+ * @private internal utility of USE TIMEOUT
31366
+ */
31367
+ function parseBulkTimeoutUpdateArgs(patch) {
31368
+ if (patch.paused === undefined) {
31369
+ throw createTimeoutToolArgsError('Bulk timeout update with `allActive: true` requires `paused` to be explicitly set.');
31370
+ }
31371
+ if (hasSingleTimeoutOnlyPatchFields(patch)) {
31372
+ throw createTimeoutToolArgsError('Bulk timeout update only supports the `paused` field.');
31373
+ }
31374
+ return {
31375
+ allActive: true,
31376
+ paused: patch.paused,
31377
+ };
31378
+ }
31379
+ /**
31380
+ * Parses single-timeout update arguments.
31381
+ *
31382
+ * @private internal utility of USE TIMEOUT
31383
+ */
31384
+ function parseSingleTimeoutUpdateArgs(timeoutId, patch) {
31385
+ if (!timeoutId) {
31386
+ throw createTimeoutToolArgsError('Timeout `timeoutId` is required for single-timeout updates.');
31387
+ }
31388
+ if (Object.keys(patch).length === 0) {
31389
+ throw createTimeoutToolArgsError('Timeout update must include at least one editable field.');
31390
+ }
31391
+ return {
31392
+ timeoutId,
31393
+ patch,
31394
+ };
31395
+ }
31180
31396
  /**
31181
31397
  * Parses and validates `USE TIMEOUT` tool arguments.
31182
31398
  *
@@ -31203,22 +31419,14 @@
31203
31419
  * Parses `cancel_timeout` input.
31204
31420
  */
31205
31421
  cancel(args) {
31206
- const timeoutId = typeof args.timeoutId === 'string' ? args.timeoutId.trim() : '';
31207
- const allActive = args.allActive === true;
31208
- if (timeoutId && allActive) {
31209
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31210
- Timeout cancellation must target either one \`timeoutId\` or \`allActive: true\`, not both.
31211
- `));
31212
- }
31213
- if (allActive) {
31422
+ const target = parseTimeoutTargetSelection(args, {
31423
+ bothMessage: 'Timeout cancellation must target either one `timeoutId` or `allActive: true`, not both.',
31424
+ missingMessage: 'Timeout `timeoutId` is required unless you pass `allActive: true`.',
31425
+ });
31426
+ if (target.allActive) {
31214
31427
  return { allActive: true };
31215
31428
  }
31216
- if (!timeoutId) {
31217
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31218
- Timeout \`timeoutId\` is required unless you pass \`allActive: true\`.
31219
- `));
31220
- }
31221
- return { timeoutId };
31429
+ return { timeoutId: target.timeoutId };
31222
31430
  },
31223
31431
  /**
31224
31432
  * Parses `list_timeouts` input.
@@ -31249,106 +31457,14 @@
31249
31457
  * Parses `update_timeout` input.
31250
31458
  */
31251
31459
  update(args) {
31252
- const timeoutId = typeof args.timeoutId === 'string' ? args.timeoutId.trim() : '';
31253
- const allActive = args.allActive === true;
31254
- if (timeoutId && allActive) {
31255
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31256
- Timeout update must target either one \`timeoutId\` or \`allActive: true\`, not both.
31257
- `));
31258
- }
31259
- if (!timeoutId && !allActive) {
31260
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31261
- Timeout update requires one \`timeoutId\` or \`allActive: true\`.
31262
- `));
31263
- }
31264
- const patch = {};
31265
- if (typeof args.dueAt === 'string' && args.dueAt.trim().length > 0) {
31266
- const normalizedDueAt = args.dueAt.trim();
31267
- const dueAtTimestamp = Date.parse(normalizedDueAt);
31268
- if (!Number.isFinite(dueAtTimestamp)) {
31269
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31270
- Timeout \`dueAt\` must be one valid ISO timestamp.
31271
- `));
31272
- }
31273
- patch.dueAt = new Date(dueAtTimestamp).toISOString();
31274
- }
31275
- if (typeof args.extendByMs === 'number') {
31276
- if (!Number.isFinite(args.extendByMs) || args.extendByMs <= 0) {
31277
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31278
- Timeout \`extendByMs\` must be a positive number of milliseconds.
31279
- `));
31280
- }
31281
- patch.extendByMs = Math.floor(args.extendByMs);
31282
- }
31283
- if (patch.dueAt !== undefined && patch.extendByMs !== undefined) {
31284
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31285
- Timeout update cannot include both \`dueAt\` and \`extendByMs\`.
31286
- `));
31287
- }
31288
- if (args.recurrenceIntervalMs === null) {
31289
- patch.recurrenceIntervalMs = null;
31290
- }
31291
- else if (typeof args.recurrenceIntervalMs === 'number') {
31292
- if (!Number.isFinite(args.recurrenceIntervalMs) || args.recurrenceIntervalMs <= 0) {
31293
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31294
- Timeout \`recurrenceIntervalMs\` must be a positive number of milliseconds or \`null\`.
31295
- `));
31296
- }
31297
- patch.recurrenceIntervalMs = Math.floor(args.recurrenceIntervalMs);
31298
- }
31299
- if (args.message === null) {
31300
- patch.message = null;
31301
- }
31302
- else if (typeof args.message === 'string') {
31303
- const normalizedMessage = args.message.trim();
31304
- patch.message = normalizedMessage.length > 0 ? normalizedMessage : null;
31305
- }
31306
- if (args.parameters !== undefined) {
31307
- if (!args.parameters || typeof args.parameters !== 'object' || Array.isArray(args.parameters)) {
31308
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31309
- Timeout \`parameters\` must be one JSON object.
31310
- `));
31311
- }
31312
- patch.parameters = args.parameters;
31313
- }
31314
- if (typeof args.paused === 'boolean') {
31315
- patch.paused = args.paused;
31316
- }
31317
- if (allActive) {
31318
- if (patch.paused === undefined) {
31319
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31320
- Bulk timeout update with \`allActive: true\` requires \`paused\` to be explicitly set.
31321
- `));
31322
- }
31323
- const hasSingleOnlyPatch = patch.dueAt !== undefined ||
31324
- patch.extendByMs !== undefined ||
31325
- patch.recurrenceIntervalMs !== undefined ||
31326
- patch.message !== undefined ||
31327
- patch.parameters !== undefined;
31328
- if (hasSingleOnlyPatch) {
31329
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31330
- Bulk timeout update only supports the \`paused\` field.
31331
- `));
31332
- }
31333
- return {
31334
- allActive: true,
31335
- paused: patch.paused,
31336
- };
31337
- }
31338
- if (!timeoutId) {
31339
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31340
- Timeout \`timeoutId\` is required for single-timeout updates.
31341
- `));
31342
- }
31343
- if (Object.keys(patch).length === 0) {
31344
- throw new PipelineExecutionError(_spaceTrim.spaceTrim(`
31345
- Timeout update must include at least one editable field.
31346
- `));
31347
- }
31348
- return {
31349
- timeoutId,
31350
- patch,
31351
- };
31460
+ const target = parseTimeoutTargetSelection(args, {
31461
+ bothMessage: 'Timeout update must target either one `timeoutId` or `allActive: true`, not both.',
31462
+ missingMessage: 'Timeout update requires one `timeoutId` or `allActive: true`.',
31463
+ });
31464
+ const patch = parseTimeoutUpdatePatch(args);
31465
+ return target.allActive
31466
+ ? parseBulkTimeoutUpdateArgs(patch)
31467
+ : parseSingleTimeoutUpdateArgs(target.timeoutId, patch);
31352
31468
  },
31353
31469
  };
31354
31470
 
@@ -41454,326 +41570,6 @@
41454
41570
  }
41455
41571
  // Note: [🟢] Code for Node archive helper [loadArchive](src/conversion/archive/loadArchive.ts) should never be published into packages that could be imported into browser environment
41456
41572
 
41457
- /**
41458
- * All available task types
41459
- *
41460
- * There is is distinction between task types and section types
41461
- * - Every section in markdown has its SectionType
41462
- * - Some sections are tasks but other can be non-task sections
41463
- *
41464
- * @public exported from `@promptbook/core`
41465
- */
41466
- const TaskTypes = [
41467
- 'PROMPT',
41468
- 'SIMPLE',
41469
- 'SCRIPT',
41470
- 'DIALOG',
41471
- // <- [🅱]
41472
- ];
41473
-
41474
- /**
41475
- * All available sections which are not tasks
41476
- *
41477
- * @public exported from `@promptbook/core`
41478
- */
41479
- const NonTaskSectionTypes = ['EXAMPLE', 'KNOWLEDGE', 'INSTRUMENT', 'ACTION'];
41480
- /**
41481
- * All available section types
41482
- *
41483
- * There is is distinction between task types and section types
41484
- * - Every section in markdown has its SectionType
41485
- * - Some sections are tasks but other can be non-task sections
41486
- *
41487
- * @public exported from `@promptbook/core`
41488
- */
41489
- const SectionTypes = [
41490
- ...TaskTypes.map((TaskType) => `${TaskType}_TASK`),
41491
- ...NonTaskSectionTypes,
41492
- ];
41493
-
41494
- /**
41495
- * Parses the knowledge command
41496
- *
41497
- * @see `documentationUrl` for more details
41498
- *
41499
- * @public exported from `@promptbook/editable`
41500
- */
41501
- const knowledgeCommandParser = {
41502
- /**
41503
- * Name of the command
41504
- */
41505
- name: 'KNOWLEDGE',
41506
- /**
41507
- * BOILERPLATE command can be used in:
41508
- */
41509
- isUsedInPipelineHead: true,
41510
- isUsedInPipelineTask: false,
41511
- /**
41512
- * Description of the KNOWLEDGE command
41513
- */
41514
- description: `Tells promptbook which external knowledge to use`,
41515
- /**
41516
- * Link to documentation
41517
- */
41518
- documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/41',
41519
- /**
41520
- * Example usages of the KNOWLEDGE command
41521
- */
41522
- examples: [
41523
- 'KNOWLEDGE https://www.pavolhejny.com/',
41524
- 'KNOWLEDGE ./hejny-cv.txt',
41525
- 'KNOWLEDGE ./hejny-cv.md',
41526
- 'KNOWLEDGE ./hejny-cv.pdf',
41527
- 'KNOWLEDGE ./hejny-cv.docx',
41528
- // <- TODO: [😿] Allow ONLY files scoped in the (sub)directory NOT ../ and test it
41529
- ],
41530
- /**
41531
- * Parses the KNOWLEDGE command
41532
- */
41533
- parse(input) {
41534
- const { args } = input;
41535
- const knowledgeSourceContent = _spaceTrim.spaceTrim(args[0] || '');
41536
- if (knowledgeSourceContent === '') {
41537
- throw new ParseError(`Source is not defined`);
41538
- }
41539
- // TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
41540
- if (knowledgeSourceContent.startsWith('http://')) {
41541
- throw new ParseError(`Source is not secure`);
41542
- }
41543
- if (!(isValidFilePath(knowledgeSourceContent) || isValidUrl(knowledgeSourceContent))) {
41544
- throw new ParseError(`Source not valid`);
41545
- }
41546
- if (knowledgeSourceContent.startsWith('../') ||
41547
- knowledgeSourceContent.startsWith('/') ||
41548
- /^[A-Z]:[\\/]+/i.test(knowledgeSourceContent)) {
41549
- throw new ParseError(`Source cannot be outside of the .book.md folder`);
41550
- }
41551
- return {
41552
- type: 'KNOWLEDGE',
41553
- knowledgeSourceContent,
41554
- };
41555
- },
41556
- /**
41557
- * Apply the KNOWLEDGE command to the `pipelineJson`
41558
- *
41559
- * Note: `$` is used to indicate that this function mutates given `pipelineJson`
41560
- */
41561
- $applyToPipelineJson(command, $pipelineJson) {
41562
- const { knowledgeSourceContent } = command;
41563
- $pipelineJson.knowledgeSources.push({
41564
- name: knowledgeSourceContentToName(knowledgeSourceContent),
41565
- knowledgeSourceContent,
41566
- });
41567
- },
41568
- /**
41569
- * Converts the KNOWLEDGE command back to string
41570
- *
41571
- * Note: This is used in `pipelineJsonToString` utility
41572
- */
41573
- stringify(command) {
41574
- return `---`; // <- TODO: [🛋] Implement
41575
- },
41576
- /**
41577
- * Reads the KNOWLEDGE command from the `PipelineJson`
41578
- *
41579
- * Note: This is used in `pipelineJsonToString` utility
41580
- */
41581
- takeFromPipelineJson(pipelineJson) {
41582
- throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
41583
- },
41584
- };
41585
- // Note: [⛱] There are two types of KNOWLEDGE commands *...(read more in [⛱])*
41586
-
41587
- /**
41588
- * Parses the section command
41589
- *
41590
- * @see `documentationUrl` for more details
41591
- *
41592
- * @public exported from `@promptbook/editable`
41593
- */
41594
- const sectionCommandParser = {
41595
- /**
41596
- * Name of the command
41597
- */
41598
- name: 'SECTION',
41599
- /**
41600
- * Aliases for the SECTION command
41601
- */
41602
- aliasNames: [
41603
- 'PROMPT',
41604
- 'SIMPLE',
41605
- 'SCRIPT',
41606
- 'DIALOG',
41607
- 'SAMPLE',
41608
- 'EXAMPLE',
41609
- 'KNOWLEDGE',
41610
- 'INSTRUMENT',
41611
- 'ACTION', // <- Note: [⛱]
41612
- ],
41613
- /**
41614
- * Aliases for the SECTION command
41615
- */
41616
- deprecatedNames: ['TEMPLATE', 'BLOCK', 'EXECUTE'],
41617
- /**
41618
- * BOILERPLATE command can be used in:
41619
- */
41620
- isUsedInPipelineHead: false,
41621
- isUsedInPipelineTask: true,
41622
- /**
41623
- * Description of the SECTION command
41624
- */
41625
- description: `Defines the purpose of the markdown section - if its a task and which type or something else`,
41626
- /**
41627
- * Link to documentation
41628
- */
41629
- documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/64',
41630
- /**
41631
- * Example usages of the SECTION command
41632
- */
41633
- examples: [
41634
- // Short form:
41635
- 'PROMPT',
41636
- 'SIMPLE',
41637
- 'SCRIPT',
41638
- 'DIALOG',
41639
- // <- [🅱]
41640
- 'EXAMPLE',
41641
- 'KNOWLEDGE',
41642
- 'INSTRUMENT',
41643
- 'ACTION',
41644
- // -----------------
41645
- // Recommended (reversed) form:
41646
- 'PROMPT SECTION',
41647
- 'SIMPLE SECTION',
41648
- 'SCRIPT SECTION',
41649
- 'DIALOG SECTION',
41650
- // <- [🅱]
41651
- 'EXAMPLE SECTION',
41652
- 'KNOWLEDGE SECTION',
41653
- 'INSTRUMENT SECTION',
41654
- 'ACTION SECTION',
41655
- // -----------------
41656
- // Standard form:
41657
- 'SECTION PROMPT',
41658
- 'SECTION SIMPLE',
41659
- 'SECTION SCRIPT',
41660
- 'SECTION DIALOG',
41661
- // <- [🅱]
41662
- 'SECTION EXAMPLE',
41663
- 'SECTION KNOWLEDGE',
41664
- 'SECTION INSTRUMENT',
41665
- 'SECTION ACTION',
41666
- ],
41667
- // TODO: [♓️] order: -10 /* <- Note: Putting before other commands */
41668
- /**
41669
- * Parses the SECTION command
41670
- */
41671
- parse(input) {
41672
- let { normalized } = input;
41673
- normalized = normalized.split('SAMPLE').join('EXAMPLE');
41674
- normalized = normalized.split('EXECUTE_').join('');
41675
- normalized = normalized.split('DIALOGUE').join('DIALOG');
41676
- const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
41677
- if (taskTypes.length !== 1) {
41678
- throw new ParseError(_spaceTrim.spaceTrim((block) => `
41679
- Unknown section type "${normalized}"
41680
-
41681
- Supported section types are:
41682
- ${block(SectionTypes.join(', '))}
41683
- `));
41684
- }
41685
- const taskType = taskTypes[0];
41686
- return {
41687
- type: 'SECTION',
41688
- taskType,
41689
- };
41690
- },
41691
- /**
41692
- * Apply the SECTION command to the `pipelineJson`
41693
- *
41694
- * Note: `$` is used to indicate that this function mutates given `taskJson`
41695
- */
41696
- $applyToTaskJson(command, $taskJson, $pipelineJson) {
41697
- if ($taskJson.isSectionTypeSet === true) {
41698
- throw new ParseError(_spaceTrim.spaceTrim(`
41699
- Section type is already defined in the section.
41700
- It can be defined only once.
41701
- `));
41702
- }
41703
- $taskJson.isSectionTypeSet = true;
41704
- // TODO: [🍧][💩] Rearrange better - but at bottom and unwrap from function
41705
- const expectResultingParameterName = () => {
41706
- if ($taskJson.resultingParameterName) {
41707
- return;
41708
- }
41709
- throw new ParseError(`Task section and example section must end with return statement -> {parameterName}`);
41710
- };
41711
- if ($taskJson.content === undefined) {
41712
- throw new UnexpectedError(`Content is missing in the taskJson - probably commands are applied in wrong order`);
41713
- }
41714
- if (command.taskType === 'EXAMPLE') {
41715
- expectResultingParameterName();
41716
- const parameter = $pipelineJson.parameters.find((param) => param.name === $taskJson.resultingParameterName);
41717
- if (parameter === undefined) {
41718
- // TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
41719
- throw new ParseError(`Parameter \`{${$taskJson.resultingParameterName}}\` is not defined so can not define example value of it`);
41720
- }
41721
- parameter.exampleValues = parameter.exampleValues || [];
41722
- parameter.exampleValues.push($taskJson.content);
41723
- $taskJson.isTask = false;
41724
- return;
41725
- }
41726
- if (command.taskType === 'KNOWLEDGE') {
41727
- knowledgeCommandParser.$applyToPipelineJson({
41728
- type: 'KNOWLEDGE',
41729
- knowledgeSourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
41730
- }, $pipelineJson);
41731
- $taskJson.isTask = false;
41732
- return;
41733
- }
41734
- if (command.taskType === 'ACTION') {
41735
- console.error(new NotYetImplementedError('Actions are not implemented yet'));
41736
- $taskJson.isTask = false;
41737
- return;
41738
- }
41739
- if (command.taskType === 'INSTRUMENT') {
41740
- console.error(new NotYetImplementedError('Instruments are not implemented yet'));
41741
- $taskJson.isTask = false;
41742
- return;
41743
- }
41744
- expectResultingParameterName();
41745
- $taskJson.taskType = command.taskType;
41746
- $taskJson.isTask = true;
41747
- },
41748
- /**
41749
- * Converts the SECTION command back to string
41750
- *
41751
- * Note: This is used in `pipelineJsonToString` utility
41752
- */
41753
- stringify(command) {
41754
- return `---`; // <- TODO: [🛋] Implement
41755
- },
41756
- /**
41757
- * Reads the SECTION command from the `TaskJson`
41758
- *
41759
- * Note: This is used in `pipelineJsonToString` utility
41760
- */
41761
- takeFromTaskJson($taskJson) {
41762
- throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
41763
- },
41764
- };
41765
- /**
41766
- * Note: [⛱] There are two types of KNOWLEDGE, ACTION and INSTRUMENT commands:
41767
- * 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
41768
- * - KNOWLEDGE Look at https://en.wikipedia.org/wiki/Artificial_intelligence
41769
- * 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
41770
- * - KNOWLEDGE SECTION
41771
- *
41772
- * ```
41773
- * Look at https://en.wikipedia.org/wiki/Artificial_intelligence
41774
- * ```
41775
- */
41776
-
41777
41573
  /**
41778
41574
  * Parses the boilerplate command
41779
41575
  *
@@ -42855,6 +42651,99 @@
42855
42651
  },
42856
42652
  };
42857
42653
 
42654
+ /**
42655
+ * Parses the knowledge command
42656
+ *
42657
+ * @see `documentationUrl` for more details
42658
+ *
42659
+ * @public exported from `@promptbook/editable`
42660
+ */
42661
+ const knowledgeCommandParser = {
42662
+ /**
42663
+ * Name of the command
42664
+ */
42665
+ name: 'KNOWLEDGE',
42666
+ /**
42667
+ * BOILERPLATE command can be used in:
42668
+ */
42669
+ isUsedInPipelineHead: true,
42670
+ isUsedInPipelineTask: false,
42671
+ /**
42672
+ * Description of the KNOWLEDGE command
42673
+ */
42674
+ description: `Tells promptbook which external knowledge to use`,
42675
+ /**
42676
+ * Link to documentation
42677
+ */
42678
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/41',
42679
+ /**
42680
+ * Example usages of the KNOWLEDGE command
42681
+ */
42682
+ examples: [
42683
+ 'KNOWLEDGE https://www.pavolhejny.com/',
42684
+ 'KNOWLEDGE ./hejny-cv.txt',
42685
+ 'KNOWLEDGE ./hejny-cv.md',
42686
+ 'KNOWLEDGE ./hejny-cv.pdf',
42687
+ 'KNOWLEDGE ./hejny-cv.docx',
42688
+ // <- TODO: [😿] Allow ONLY files scoped in the (sub)directory NOT ../ and test it
42689
+ ],
42690
+ /**
42691
+ * Parses the KNOWLEDGE command
42692
+ */
42693
+ parse(input) {
42694
+ const { args } = input;
42695
+ const knowledgeSourceContent = _spaceTrim.spaceTrim(args[0] || '');
42696
+ if (knowledgeSourceContent === '') {
42697
+ throw new ParseError(`Source is not defined`);
42698
+ }
42699
+ // TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
42700
+ if (knowledgeSourceContent.startsWith('http://')) {
42701
+ throw new ParseError(`Source is not secure`);
42702
+ }
42703
+ if (!(isValidFilePath(knowledgeSourceContent) || isValidUrl(knowledgeSourceContent))) {
42704
+ throw new ParseError(`Source not valid`);
42705
+ }
42706
+ if (knowledgeSourceContent.startsWith('../') ||
42707
+ knowledgeSourceContent.startsWith('/') ||
42708
+ /^[A-Z]:[\\/]+/i.test(knowledgeSourceContent)) {
42709
+ throw new ParseError(`Source cannot be outside of the .book.md folder`);
42710
+ }
42711
+ return {
42712
+ type: 'KNOWLEDGE',
42713
+ knowledgeSourceContent,
42714
+ };
42715
+ },
42716
+ /**
42717
+ * Apply the KNOWLEDGE command to the `pipelineJson`
42718
+ *
42719
+ * Note: `$` is used to indicate that this function mutates given `pipelineJson`
42720
+ */
42721
+ $applyToPipelineJson(command, $pipelineJson) {
42722
+ const { knowledgeSourceContent } = command;
42723
+ $pipelineJson.knowledgeSources.push({
42724
+ name: knowledgeSourceContentToName(knowledgeSourceContent),
42725
+ knowledgeSourceContent,
42726
+ });
42727
+ },
42728
+ /**
42729
+ * Converts the KNOWLEDGE command back to string
42730
+ *
42731
+ * Note: This is used in `pipelineJsonToString` utility
42732
+ */
42733
+ stringify(command) {
42734
+ return `---`; // <- TODO: [🛋] Implement
42735
+ },
42736
+ /**
42737
+ * Reads the KNOWLEDGE command from the `PipelineJson`
42738
+ *
42739
+ * Note: This is used in `pipelineJsonToString` utility
42740
+ */
42741
+ takeFromPipelineJson(pipelineJson) {
42742
+ throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
42743
+ },
42744
+ };
42745
+ // Note: [⛱] There are two types of KNOWLEDGE commands *...(read more in [⛱])*
42746
+
42858
42747
  /**
42859
42748
  * Constant for model variants.
42860
42749
  *
@@ -43373,6 +43262,233 @@
43373
43262
  },
43374
43263
  };
43375
43264
 
43265
+ /**
43266
+ * All available task types
43267
+ *
43268
+ * There is is distinction between task types and section types
43269
+ * - Every section in markdown has its SectionType
43270
+ * - Some sections are tasks but other can be non-task sections
43271
+ *
43272
+ * @public exported from `@promptbook/core`
43273
+ */
43274
+ const TaskTypes = [
43275
+ 'PROMPT',
43276
+ 'SIMPLE',
43277
+ 'SCRIPT',
43278
+ 'DIALOG',
43279
+ // <- [🅱]
43280
+ ];
43281
+
43282
+ /**
43283
+ * All available sections which are not tasks
43284
+ *
43285
+ * @public exported from `@promptbook/core`
43286
+ */
43287
+ const NonTaskSectionTypes = ['EXAMPLE', 'KNOWLEDGE', 'INSTRUMENT', 'ACTION'];
43288
+ /**
43289
+ * All available section types
43290
+ *
43291
+ * There is is distinction between task types and section types
43292
+ * - Every section in markdown has its SectionType
43293
+ * - Some sections are tasks but other can be non-task sections
43294
+ *
43295
+ * @public exported from `@promptbook/core`
43296
+ */
43297
+ const SectionTypes = [
43298
+ ...TaskTypes.map((TaskType) => `${TaskType}_TASK`),
43299
+ ...NonTaskSectionTypes,
43300
+ ];
43301
+
43302
+ /**
43303
+ * Parses the section command
43304
+ *
43305
+ * @see `documentationUrl` for more details
43306
+ *
43307
+ * @public exported from `@promptbook/editable`
43308
+ */
43309
+ const sectionCommandParser = {
43310
+ /**
43311
+ * Name of the command
43312
+ */
43313
+ name: 'SECTION',
43314
+ /**
43315
+ * Aliases for the SECTION command
43316
+ */
43317
+ aliasNames: [
43318
+ 'PROMPT',
43319
+ 'SIMPLE',
43320
+ 'SCRIPT',
43321
+ 'DIALOG',
43322
+ 'SAMPLE',
43323
+ 'EXAMPLE',
43324
+ 'KNOWLEDGE',
43325
+ 'INSTRUMENT',
43326
+ 'ACTION', // <- Note: [⛱]
43327
+ ],
43328
+ /**
43329
+ * Aliases for the SECTION command
43330
+ */
43331
+ deprecatedNames: ['TEMPLATE', 'BLOCK', 'EXECUTE'],
43332
+ /**
43333
+ * BOILERPLATE command can be used in:
43334
+ */
43335
+ isUsedInPipelineHead: false,
43336
+ isUsedInPipelineTask: true,
43337
+ /**
43338
+ * Description of the SECTION command
43339
+ */
43340
+ description: `Defines the purpose of the markdown section - if its a task and which type or something else`,
43341
+ /**
43342
+ * Link to documentation
43343
+ */
43344
+ documentationUrl: 'https://github.com/webgptorg/promptbook/discussions/64',
43345
+ /**
43346
+ * Example usages of the SECTION command
43347
+ */
43348
+ examples: [
43349
+ // Short form:
43350
+ 'PROMPT',
43351
+ 'SIMPLE',
43352
+ 'SCRIPT',
43353
+ 'DIALOG',
43354
+ // <- [🅱]
43355
+ 'EXAMPLE',
43356
+ 'KNOWLEDGE',
43357
+ 'INSTRUMENT',
43358
+ 'ACTION',
43359
+ // -----------------
43360
+ // Recommended (reversed) form:
43361
+ 'PROMPT SECTION',
43362
+ 'SIMPLE SECTION',
43363
+ 'SCRIPT SECTION',
43364
+ 'DIALOG SECTION',
43365
+ // <- [🅱]
43366
+ 'EXAMPLE SECTION',
43367
+ 'KNOWLEDGE SECTION',
43368
+ 'INSTRUMENT SECTION',
43369
+ 'ACTION SECTION',
43370
+ // -----------------
43371
+ // Standard form:
43372
+ 'SECTION PROMPT',
43373
+ 'SECTION SIMPLE',
43374
+ 'SECTION SCRIPT',
43375
+ 'SECTION DIALOG',
43376
+ // <- [🅱]
43377
+ 'SECTION EXAMPLE',
43378
+ 'SECTION KNOWLEDGE',
43379
+ 'SECTION INSTRUMENT',
43380
+ 'SECTION ACTION',
43381
+ ],
43382
+ // TODO: [♓️] order: -10 /* <- Note: Putting before other commands */
43383
+ /**
43384
+ * Parses the SECTION command
43385
+ */
43386
+ parse(input) {
43387
+ let { normalized } = input;
43388
+ normalized = normalized.split('SAMPLE').join('EXAMPLE');
43389
+ normalized = normalized.split('EXECUTE_').join('');
43390
+ normalized = normalized.split('DIALOGUE').join('DIALOG');
43391
+ const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
43392
+ if (taskTypes.length !== 1) {
43393
+ throw new ParseError(_spaceTrim.spaceTrim((block) => `
43394
+ Unknown section type "${normalized}"
43395
+
43396
+ Supported section types are:
43397
+ ${block(SectionTypes.join(', '))}
43398
+ `));
43399
+ }
43400
+ const taskType = taskTypes[0];
43401
+ return {
43402
+ type: 'SECTION',
43403
+ taskType,
43404
+ };
43405
+ },
43406
+ /**
43407
+ * Apply the SECTION command to the `pipelineJson`
43408
+ *
43409
+ * Note: `$` is used to indicate that this function mutates given `taskJson`
43410
+ */
43411
+ $applyToTaskJson(command, $taskJson, $pipelineJson) {
43412
+ if ($taskJson.isSectionTypeSet === true) {
43413
+ throw new ParseError(_spaceTrim.spaceTrim(`
43414
+ Section type is already defined in the section.
43415
+ It can be defined only once.
43416
+ `));
43417
+ }
43418
+ $taskJson.isSectionTypeSet = true;
43419
+ // TODO: [🍧][💩] Rearrange better - but at bottom and unwrap from function
43420
+ const expectResultingParameterName = () => {
43421
+ if ($taskJson.resultingParameterName) {
43422
+ return;
43423
+ }
43424
+ throw new ParseError(`Task section and example section must end with return statement -> {parameterName}`);
43425
+ };
43426
+ if ($taskJson.content === undefined) {
43427
+ throw new UnexpectedError(`Content is missing in the taskJson - probably commands are applied in wrong order`);
43428
+ }
43429
+ if (command.taskType === 'EXAMPLE') {
43430
+ expectResultingParameterName();
43431
+ const parameter = $pipelineJson.parameters.find((param) => param.name === $taskJson.resultingParameterName);
43432
+ if (parameter === undefined) {
43433
+ // TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
43434
+ throw new ParseError(`Parameter \`{${$taskJson.resultingParameterName}}\` is not defined so can not define example value of it`);
43435
+ }
43436
+ parameter.exampleValues = parameter.exampleValues || [];
43437
+ parameter.exampleValues.push($taskJson.content);
43438
+ $taskJson.isTask = false;
43439
+ return;
43440
+ }
43441
+ if (command.taskType === 'KNOWLEDGE') {
43442
+ knowledgeCommandParser.$applyToPipelineJson({
43443
+ type: 'KNOWLEDGE',
43444
+ knowledgeSourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
43445
+ }, $pipelineJson);
43446
+ $taskJson.isTask = false;
43447
+ return;
43448
+ }
43449
+ if (command.taskType === 'ACTION') {
43450
+ console.error(new NotYetImplementedError('Actions are not implemented yet'));
43451
+ $taskJson.isTask = false;
43452
+ return;
43453
+ }
43454
+ if (command.taskType === 'INSTRUMENT') {
43455
+ console.error(new NotYetImplementedError('Instruments are not implemented yet'));
43456
+ $taskJson.isTask = false;
43457
+ return;
43458
+ }
43459
+ expectResultingParameterName();
43460
+ $taskJson.taskType = command.taskType;
43461
+ $taskJson.isTask = true;
43462
+ },
43463
+ /**
43464
+ * Converts the SECTION command back to string
43465
+ *
43466
+ * Note: This is used in `pipelineJsonToString` utility
43467
+ */
43468
+ stringify(command) {
43469
+ return `---`; // <- TODO: [🛋] Implement
43470
+ },
43471
+ /**
43472
+ * Reads the SECTION command from the `TaskJson`
43473
+ *
43474
+ * Note: This is used in `pipelineJsonToString` utility
43475
+ */
43476
+ takeFromTaskJson($taskJson) {
43477
+ throw new NotYetImplementedError(`[🛋] Not implemented yet`); // <- TODO: [🛋] Implement
43478
+ },
43479
+ };
43480
+ /**
43481
+ * Note: [⛱] There are two types of KNOWLEDGE, ACTION and INSTRUMENT commands:
43482
+ * 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
43483
+ * - KNOWLEDGE Look at https://en.wikipedia.org/wiki/Artificial_intelligence
43484
+ * 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
43485
+ * - KNOWLEDGE SECTION
43486
+ *
43487
+ * ```
43488
+ * Look at https://en.wikipedia.org/wiki/Artificial_intelligence
43489
+ * ```
43490
+ */
43491
+
43376
43492
  /**
43377
43493
  * Parses the url command
43378
43494
  *
@@ -43826,6 +43942,242 @@
43826
43942
  return null;
43827
43943
  }
43828
43944
 
43945
+ /**
43946
+ * Utility function to extract all list items from markdown
43947
+ *
43948
+ * Note: It works with both ul and ol
43949
+ * Note: It omits list items in code blocks
43950
+ * Note: It flattens nested lists
43951
+ * Note: It can not work with html syntax and comments
43952
+ *
43953
+ * @param markdown any valid markdown
43954
+ * @returns An array of strings, each representing an individual list item found in the markdown
43955
+ *
43956
+ * @public exported from `@promptbook/markdown-utils`
43957
+ */
43958
+ function extractAllListItemsFromMarkdown(markdown) {
43959
+ const lines = markdown.split(/\r?\n/);
43960
+ const listItems = [];
43961
+ let isInCodeBlock = false;
43962
+ for (const line of lines) {
43963
+ const trimmedLine = line.trim();
43964
+ if (trimmedLine.startsWith('```')) {
43965
+ isInCodeBlock = !isInCodeBlock;
43966
+ }
43967
+ if (!isInCodeBlock && (trimmedLine.startsWith('-') || trimmedLine.match(/^\d+\./))) {
43968
+ const listItem = trimmedLine.replace(/^-|\d+\./, '').trim();
43969
+ listItems.push(listItem);
43970
+ }
43971
+ }
43972
+ return listItems;
43973
+ }
43974
+
43975
+ /**
43976
+ * Builds a short file/url identification block for parse errors.
43977
+ *
43978
+ * @private internal utility of `parsePipeline`
43979
+ */
43980
+ function getPipelineIdentification($pipelineJson) {
43981
+ // Note: This is a 😐 implementation of [🚞]
43982
+ const pipelineIdentificationParts = [];
43983
+ if ($pipelineJson.sourceFile !== undefined) {
43984
+ pipelineIdentificationParts.push(`File: ${$pipelineJson.sourceFile}`);
43985
+ }
43986
+ if ($pipelineJson.pipelineUrl !== undefined) {
43987
+ pipelineIdentificationParts.push(`Url: ${$pipelineJson.pipelineUrl}`);
43988
+ }
43989
+ return pipelineIdentificationParts.join('\n');
43990
+ }
43991
+
43992
+ /**
43993
+ * Merges one parameter declaration into the mutable pipeline parameter list.
43994
+ *
43995
+ * @private internal utility of `parsePipeline`
43996
+ */
43997
+ function defineParameter($pipelineJson, parameterCommand) {
43998
+ const { parameterName, parameterDescription, isInput, isOutput } = parameterCommand;
43999
+ if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
44000
+ throw new ParseError(_spaceTrim.spaceTrim((block) => `
44001
+ Parameter name {${parameterName}} is reserved and cannot be used as resulting parameter name
44002
+
44003
+ ${block(getPipelineIdentification($pipelineJson))}
44004
+ `) /* <- TODO: [🚞] */);
44005
+ }
44006
+ const existingParameter = $pipelineJson.parameters.find((parameter) => parameter.name === parameterName);
44007
+ if (existingParameter &&
44008
+ existingParameter.description &&
44009
+ existingParameter.description !== parameterDescription &&
44010
+ parameterDescription) {
44011
+ throw new ParseError(_spaceTrim.spaceTrim((block) => `
44012
+ Parameter \`{${parameterName}}\` is defined multiple times with different description:
44013
+
44014
+ ${block(getPipelineIdentification($pipelineJson))}
44015
+
44016
+ First definition:
44017
+ ${block(existingParameter.description || '[undefined]')}
44018
+
44019
+ Second definition:
44020
+ ${block(parameterDescription || '[undefined]')}
44021
+ `));
44022
+ }
44023
+ if (existingParameter) {
44024
+ if (parameterDescription) {
44025
+ existingParameter.description = parameterDescription;
44026
+ }
44027
+ existingParameter.isInput = existingParameter.isInput || isInput;
44028
+ existingParameter.isOutput = existingParameter.isOutput || isOutput;
44029
+ return;
44030
+ }
44031
+ $pipelineJson.parameters.push({
44032
+ name: parameterName,
44033
+ description: parameterDescription || undefined,
44034
+ isInput,
44035
+ isOutput,
44036
+ });
44037
+ }
44038
+
44039
+ /**
44040
+ * Removes fenced code blocks when deriving human-readable section descriptions.
44041
+ *
44042
+ * @private internal utility of `extractPipelineDescription`
44043
+ */
44044
+ const DESCRIPTION_CODE_BLOCK_REGEXP = /^```.*^```/gms;
44045
+ /**
44046
+ * Removes blockquote lines when deriving human-readable section descriptions.
44047
+ *
44048
+ * @private internal utility of `extractPipelineDescription`
44049
+ */
44050
+ const DESCRIPTION_BLOCKQUOTE_REGEXP = /^>.*$/gm;
44051
+ /**
44052
+ * Removes list items and return statements when deriving human-readable section descriptions.
44053
+ *
44054
+ * @private internal utility of `extractPipelineDescription`
44055
+ */
44056
+ const DESCRIPTION_LIST_ITEM_REGEXP = /^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm;
44057
+ /**
44058
+ * Extracts the plain-text description from a head or task section body.
44059
+ *
44060
+ * @private internal utility of `parsePipeline`
44061
+ */
44062
+ function extractPipelineDescription(sectionContent) {
44063
+ let description = sectionContent;
44064
+ description = description.split(DESCRIPTION_CODE_BLOCK_REGEXP).join('');
44065
+ description = description.split(DESCRIPTION_BLOCKQUOTE_REGEXP).join('');
44066
+ description = description.split(DESCRIPTION_LIST_ITEM_REGEXP).join('');
44067
+ description = _spaceTrim.spaceTrim(description);
44068
+ if (description === '') {
44069
+ return undefined;
44070
+ }
44071
+ return description;
44072
+ }
44073
+
44074
+ /**
44075
+ * Applies the pipeline head title, description, and head-level commands.
44076
+ *
44077
+ * @private internal utility of `parsePipeline`
44078
+ */
44079
+ function applyPipelineHead(pipelineHead, $pipelineJson) {
44080
+ $pipelineJson.title = pipelineHead.title;
44081
+ $pipelineJson.description = extractPipelineDescription(pipelineHead.content);
44082
+ for (const listItem of extractAllListItemsFromMarkdown(pipelineHead.content)) {
44083
+ applyPipelineHeadCommand(listItem, $pipelineJson);
44084
+ }
44085
+ }
44086
+ /**
44087
+ * Parses and applies one command declared in the pipeline head.
44088
+ *
44089
+ * @private internal utility of `applyPipelineHead`
44090
+ */
44091
+ function applyPipelineHeadCommand(listItem, $pipelineJson) {
44092
+ const command = parseCommand(listItem, 'PIPELINE_HEAD');
44093
+ const commandParser = getParserForCommand(command);
44094
+ if (commandParser.isUsedInPipelineHead !== true /* <- Note: [🦦][4] */) {
44095
+ throw new ParseError(_spaceTrim.spaceTrim((block) => `
44096
+ Command \`${command.type}\` is not allowed in the head of the pipeline ONLY at the pipeline task
44097
+
44098
+ ${block(getPipelineIdentification($pipelineJson))}
44099
+ `)); // <- TODO: [🚞]
44100
+ }
44101
+ try {
44102
+ commandParser.$applyToPipelineJson(command, $pipelineJson);
44103
+ // <- Note: [🦦] Its strange that this assertion must be here, [🦦][4] should do this assertion implicitly
44104
+ }
44105
+ catch (error) {
44106
+ if (!(error instanceof ParseError)) {
44107
+ throw error;
44108
+ }
44109
+ throw new ParseError(_spaceTrim.spaceTrim((block) => `
44110
+ Command ${command.type} failed to apply to the pipeline
44111
+
44112
+ The error:
44113
+ ${block(error.message)}
44114
+
44115
+ Raw command:
44116
+ - ${listItem}
44117
+
44118
+ Usage of ${command.type}:
44119
+ ${block(commandParser.examples.map((example) => `- ${example}`).join('\n'))}
44120
+
44121
+ ${block(getPipelineIdentification($pipelineJson))}
44122
+ `)); // <- TODO: [🚞]
44123
+ }
44124
+ if (command.type === 'PARAMETER') {
44125
+ defineParameter($pipelineJson, command);
44126
+ // <- Note: [🍣]
44127
+ }
44128
+ }
44129
+
44130
+ /**
44131
+ * Creates the mutable pipeline JSON structure used throughout parsing.
44132
+ *
44133
+ * @private internal utility of `parsePipeline`
44134
+ */
44135
+ function createInitialPipelineJson(pipelineString) {
44136
+ return {
44137
+ title: DEFAULT_BOOK_TITLE,
44138
+ parameters: [],
44139
+ tasks: [],
44140
+ knowledgeSources: [],
44141
+ knowledgePieces: [],
44142
+ personas: [],
44143
+ preparations: [],
44144
+ sources: [
44145
+ {
44146
+ type: 'BOOK',
44147
+ path: null,
44148
+ // <- TODO: !!6 Pass here path of the file
44149
+ content: pipelineString,
44150
+ },
44151
+ ],
44152
+ };
44153
+ }
44154
+
44155
+ /**
44156
+ * Creates stable unique task names for duplicate section titles.
44157
+ *
44158
+ * @private internal utility of `parsePipeline`
44159
+ */
44160
+ function createUniqueSectionNameResolver(pipelineSections) {
44161
+ const sectionCounts = {};
44162
+ for (const pipelineSection of pipelineSections) {
44163
+ const sectionName = titleToName(pipelineSection.title);
44164
+ if (sectionCounts[sectionName] === undefined) {
44165
+ sectionCounts[sectionName] = { count: 0, currentIndex: 0 };
44166
+ }
44167
+ sectionCounts[sectionName].count++;
44168
+ }
44169
+ return (title) => {
44170
+ const sectionName = titleToName(title);
44171
+ const sectionCount = sectionCounts[sectionName];
44172
+ if (sectionCount.count === 1) {
44173
+ return sectionName;
44174
+ }
44175
+ const nameWithSuffix = `${sectionName}-${sectionCount.currentIndex}`;
44176
+ sectionCount.currentIndex++;
44177
+ return nameWithSuffix;
44178
+ };
44179
+ }
44180
+
43829
44181
  /**
43830
44182
  * Extracts the interface (input and output parameters) from a pipeline.
43831
44183
  *
@@ -44087,12 +44439,261 @@
44087
44439
  // Note: [💞] Ignore a discrepancy between file name and entity name
44088
44440
 
44089
44441
  /**
44090
- * Supported script languages
44442
+ * Applies postprocessing and exports the parsed pipeline JSON.
44091
44443
  *
44092
- * @private internal base for `ScriptLanguage`
44444
+ * @private internal utility of `parsePipeline`
44093
44445
  */
44094
- const SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
44095
- // <- TODO: [🏥] DRY
44446
+ function finalizeParsedPipeline($pipelineJson) {
44447
+ applyImplicitParameterDirections($pipelineJson);
44448
+ removeUndefinedValuesFromPipeline($pipelineJson);
44449
+ applySyncHighLevelAbstractions($pipelineJson);
44450
+ ensurePipelineFormfactor($pipelineJson);
44451
+ return exportParsedPipelineJson($pipelineJson);
44452
+ }
44453
+ /**
44454
+ * Applies default INPUT/OUTPUT flags when the author did not specify them explicitly.
44455
+ *
44456
+ * @private internal utility of `finalizeParsedPipeline`
44457
+ */
44458
+ function applyImplicitParameterDirections($pipelineJson) {
44459
+ markImplicitInputParameters($pipelineJson);
44460
+ markImplicitOutputParameters($pipelineJson);
44461
+ }
44462
+ /**
44463
+ * Marks non-result parameters as pipeline inputs when no input was declared.
44464
+ *
44465
+ * @private internal utility of `finalizeParsedPipeline`
44466
+ */
44467
+ function markImplicitInputParameters($pipelineJson) {
44468
+ if ($pipelineJson.parameters.some((parameter) => parameter.isInput)) {
44469
+ return;
44470
+ }
44471
+ for (const parameter of $pipelineJson.parameters) {
44472
+ const isThisParameterResulting = $pipelineJson.tasks.some((task) => task.resultingParameterName === parameter.name);
44473
+ if (!isThisParameterResulting) {
44474
+ parameter.isInput = true;
44475
+ // <- TODO: [💔] Why this is making typescript error in vscode but not in cli
44476
+ // > Type 'true' is not assignable to type 'false'.ts(2322)
44477
+ // > (property) isInput: false
44478
+ // > The parameter is input of the pipeline The parameter is NOT input of the pipeline
44479
+ }
44480
+ }
44481
+ }
44482
+ /**
44483
+ * Marks every non-input parameter as output when no output was declared.
44484
+ *
44485
+ * @private internal utility of `finalizeParsedPipeline`
44486
+ */
44487
+ function markImplicitOutputParameters($pipelineJson) {
44488
+ if ($pipelineJson.parameters.some((parameter) => parameter.isOutput)) {
44489
+ return;
44490
+ }
44491
+ for (const parameter of $pipelineJson.parameters) {
44492
+ if (!parameter.isInput) {
44493
+ parameter.isOutput = true;
44494
+ // <- TODO: [💔]
44495
+ }
44496
+ }
44497
+ }
44498
+ /**
44499
+ * Removes `undefined` properties from serialized tasks and parameters.
44500
+ *
44501
+ * @private internal utility of `finalizeParsedPipeline`
44502
+ */
44503
+ function removeUndefinedValuesFromPipeline($pipelineJson) {
44504
+ $pipelineJson.tasks.forEach(removeUndefinedProperties);
44505
+ $pipelineJson.parameters.forEach(removeUndefinedProperties);
44506
+ }
44507
+ /**
44508
+ * Deletes all own properties with `undefined` values from a mutable JSON entity.
44509
+ *
44510
+ * @private internal utility of `finalizeParsedPipeline`
44511
+ */
44512
+ function removeUndefinedProperties(entity) {
44513
+ for (const [key, value] of Object.entries(entity)) {
44514
+ if (value === undefined) {
44515
+ delete entity[key];
44516
+ }
44517
+ }
44518
+ }
44519
+ /**
44520
+ * Applies all sync-only high-level abstractions after parsing.
44521
+ *
44522
+ * @private internal utility of `finalizeParsedPipeline`
44523
+ */
44524
+ function applySyncHighLevelAbstractions($pipelineJson) {
44525
+ for (const highLevelAbstraction of HIGH_LEVEL_ABSTRACTIONS.filter(({ type }) => type === 'SYNC')) {
44526
+ highLevelAbstraction.$applyToPipelineJson($pipelineJson);
44527
+ }
44528
+ }
44529
+ /**
44530
+ * Ensures parsed pipelines always have the default `GENERIC` formfactor.
44531
+ *
44532
+ * @private internal utility of `finalizeParsedPipeline`
44533
+ */
44534
+ function ensurePipelineFormfactor($pipelineJson) {
44535
+ // Note: [🔆] If formfactor is still not set, set it to 'GENERIC'
44536
+ if ($pipelineJson.formfactorName === undefined) {
44537
+ $pipelineJson.formfactorName = 'GENERIC';
44538
+ }
44539
+ }
44540
+ /**
44541
+ * Finalizes ordering and exports the parsed pipeline JSON.
44542
+ *
44543
+ * @private internal utility of `finalizeParsedPipeline`
44544
+ */
44545
+ function exportParsedPipelineJson($pipelineJson) {
44546
+ return exportJson({
44547
+ name: 'pipelineJson',
44548
+ message: `Result of \`parsePipeline\``,
44549
+ order: ORDER_OF_PIPELINE_JSON,
44550
+ value: {
44551
+ formfactorName: 'GENERIC',
44552
+ // <- Note: [🔆] Setting `formfactorName` is redundant to satisfy the typescript
44553
+ ...$pipelineJson,
44554
+ },
44555
+ });
44556
+ }
44557
+ // TODO: Use spaceTrim more effectively
44558
+ // TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
44559
+ // TODO: [♈] Probably move expectations from tasks to parameters
44560
+ // TODO: [🍙] Make some standard order of json properties
44561
+
44562
+ /**
44563
+ * Parses markdown section to title its level and content
44564
+ *
44565
+ * @public exported from `@promptbook/markdown-utils`
44566
+ */
44567
+ function parseMarkdownSection(value) {
44568
+ var _a, _b;
44569
+ const lines = value.split(/\r?\n/);
44570
+ if (!lines[0].startsWith('#')) {
44571
+ throw new ParseError('Markdown section must start with heading');
44572
+ }
44573
+ const title = lines[0].replace(/^#+\s*/, '');
44574
+ const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
44575
+ const content = _spaceTrim.spaceTrim(lines.slice(1).join('\n'));
44576
+ if (level < 1 || level > 6) {
44577
+ throw new ParseError('Markdown section must have heading level between 1 and 6');
44578
+ }
44579
+ return { title, level: level, content };
44580
+ }
44581
+ /**
44582
+ * Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
44583
+ * sophisticated implementation of this function through parsing markdown into JSON structure
44584
+ * and flattening the actual structure
44585
+ * NOW we are working just with markdown string and its good enough
44586
+ */
44587
+
44588
+ /**
44589
+ * Splits the markdown into sections by headings
44590
+ *
44591
+ * @public exported from `@promptbook/markdown-utils`
44592
+ */
44593
+ function splitMarkdownIntoSections(markdown) {
44594
+ const lines = markdown.split(/\r?\n/);
44595
+ const sections = [];
44596
+ // TODO: [🧽] DRY
44597
+ let currentType = 'MARKDOWN';
44598
+ let buffer = [];
44599
+ const finishSection = () => {
44600
+ if (buffer.length === 0) {
44601
+ return;
44602
+ }
44603
+ let section = _spaceTrim.spaceTrim(buffer.join('\n'));
44604
+ if (section === '') {
44605
+ return;
44606
+ }
44607
+ if (!section.startsWith('#')) {
44608
+ section = `# ${DEFAULT_BOOK_TITLE}\n\n${section}`;
44609
+ }
44610
+ sections.push(section);
44611
+ buffer = [];
44612
+ };
44613
+ for (const line of lines) {
44614
+ if (currentType === 'MARKDOWN') {
44615
+ if (line.startsWith('#')) {
44616
+ finishSection();
44617
+ }
44618
+ buffer.push(line);
44619
+ if (line.startsWith('```')) {
44620
+ currentType = 'CODE_BLOCK';
44621
+ }
44622
+ else if (line.includes('<!--')) {
44623
+ currentType = 'COMMENT';
44624
+ }
44625
+ }
44626
+ else if (currentType === 'CODE_BLOCK') {
44627
+ buffer.push(line);
44628
+ if (line.startsWith('```')) {
44629
+ currentType = 'MARKDOWN';
44630
+ }
44631
+ }
44632
+ else if (currentType === 'COMMENT') {
44633
+ buffer.push(line);
44634
+ if (line.includes('-->')) {
44635
+ currentType = 'MARKDOWN';
44636
+ }
44637
+ }
44638
+ }
44639
+ finishSection();
44640
+ return sections;
44641
+ }
44642
+ /**
44643
+ * TODO: [🏛] This can be part of markdown builder
44644
+ * Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
44645
+ * sophisticated implementation of this function through parsing markdown into JSON structure
44646
+ * and flattening the actual structure
44647
+ * NOW we are working just with markdown string and its good enough
44648
+ */
44649
+
44650
+ /**
44651
+ * Splits the prepared markdown into the pipeline head and task sections.
44652
+ *
44653
+ * @private internal utility of `parsePipeline`
44654
+ */
44655
+ function parsePreparedPipelineSections(pipelineString, $pipelineJson) {
44656
+ const [pipelineHead, ...pipelineSections] = splitMarkdownIntoSections(pipelineString).map(parseMarkdownSection); /* <- Note: [🥞] */
44657
+ assertPipelineSectionsStructure(pipelineHead, pipelineSections, $pipelineJson);
44658
+ return {
44659
+ pipelineHead,
44660
+ pipelineSections,
44661
+ };
44662
+ }
44663
+ /**
44664
+ * Ensures the flattened markdown has exactly one h1 head followed by only h2 sections.
44665
+ *
44666
+ * @private internal utility of `parsePreparedPipelineSections`
44667
+ */
44668
+ function assertPipelineSectionsStructure(pipelineHead, pipelineSections, $pipelineJson) {
44669
+ if (pipelineHead === undefined) {
44670
+ throw new UnexpectedError(_spaceTrim.spaceTrim((block) => `
44671
+ Pipeline head is not defined
44672
+
44673
+ ${block(getPipelineIdentification($pipelineJson))}
44674
+
44675
+ This should never happen, because the pipeline already flattened
44676
+ `));
44677
+ }
44678
+ if (pipelineHead.level !== 1) {
44679
+ throw new UnexpectedError(_spaceTrim.spaceTrim((block) => `
44680
+ Pipeline head is not h1
44681
+
44682
+ ${block(getPipelineIdentification($pipelineJson))}
44683
+
44684
+ This should never happen, because the pipeline already flattened
44685
+ `));
44686
+ }
44687
+ if (!pipelineSections.every((pipelineSection) => pipelineSection.level === 2)) {
44688
+ throw new UnexpectedError(_spaceTrim.spaceTrim((block) => `
44689
+ Not every pipeline section is h2
44690
+
44691
+ ${block(getPipelineIdentification($pipelineJson))}
44692
+
44693
+ This should never happen, because the pipeline already flattened
44694
+ `));
44695
+ }
44696
+ }
44096
44697
 
44097
44698
  /**
44098
44699
  * Number of padding lines to add at the end of the book content
@@ -44219,124 +44820,6 @@
44219
44820
  }
44220
44821
  // TODO: Unit test
44221
44822
 
44222
- /**
44223
- * Utility function to extract all list items from markdown
44224
- *
44225
- * Note: It works with both ul and ol
44226
- * Note: It omits list items in code blocks
44227
- * Note: It flattens nested lists
44228
- * Note: It can not work with html syntax and comments
44229
- *
44230
- * @param markdown any valid markdown
44231
- * @returns An array of strings, each representing an individual list item found in the markdown
44232
- *
44233
- * @public exported from `@promptbook/markdown-utils`
44234
- */
44235
- function extractAllListItemsFromMarkdown(markdown) {
44236
- const lines = markdown.split(/\r?\n/);
44237
- const listItems = [];
44238
- let isInCodeBlock = false;
44239
- for (const line of lines) {
44240
- const trimmedLine = line.trim();
44241
- if (trimmedLine.startsWith('```')) {
44242
- isInCodeBlock = !isInCodeBlock;
44243
- }
44244
- if (!isInCodeBlock && (trimmedLine.startsWith('-') || trimmedLine.match(/^\d+\./))) {
44245
- const listItem = trimmedLine.replace(/^-|\d+\./, '').trim();
44246
- listItems.push(listItem);
44247
- }
44248
- }
44249
- return listItems;
44250
- }
44251
-
44252
- /**
44253
- * Parses markdown section to title its level and content
44254
- *
44255
- * @public exported from `@promptbook/markdown-utils`
44256
- */
44257
- function parseMarkdownSection(value) {
44258
- var _a, _b;
44259
- const lines = value.split(/\r?\n/);
44260
- if (!lines[0].startsWith('#')) {
44261
- throw new ParseError('Markdown section must start with heading');
44262
- }
44263
- const title = lines[0].replace(/^#+\s*/, '');
44264
- const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
44265
- const content = _spaceTrim.spaceTrim(lines.slice(1).join('\n'));
44266
- if (level < 1 || level > 6) {
44267
- throw new ParseError('Markdown section must have heading level between 1 and 6');
44268
- }
44269
- return { title, level: level, content };
44270
- }
44271
- /**
44272
- * Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
44273
- * sophisticated implementation of this function through parsing markdown into JSON structure
44274
- * and flattening the actual structure
44275
- * NOW we are working just with markdown string and its good enough
44276
- */
44277
-
44278
- /**
44279
- * Splits the markdown into sections by headings
44280
- *
44281
- * @public exported from `@promptbook/markdown-utils`
44282
- */
44283
- function splitMarkdownIntoSections(markdown) {
44284
- const lines = markdown.split(/\r?\n/);
44285
- const sections = [];
44286
- // TODO: [🧽] DRY
44287
- let currentType = 'MARKDOWN';
44288
- let buffer = [];
44289
- const finishSection = () => {
44290
- if (buffer.length === 0) {
44291
- return;
44292
- }
44293
- let section = _spaceTrim.spaceTrim(buffer.join('\n'));
44294
- if (section === '') {
44295
- return;
44296
- }
44297
- if (!section.startsWith('#')) {
44298
- section = `# ${DEFAULT_BOOK_TITLE}\n\n${section}`;
44299
- }
44300
- sections.push(section);
44301
- buffer = [];
44302
- };
44303
- for (const line of lines) {
44304
- if (currentType === 'MARKDOWN') {
44305
- if (line.startsWith('#')) {
44306
- finishSection();
44307
- }
44308
- buffer.push(line);
44309
- if (line.startsWith('```')) {
44310
- currentType = 'CODE_BLOCK';
44311
- }
44312
- else if (line.includes('<!--')) {
44313
- currentType = 'COMMENT';
44314
- }
44315
- }
44316
- else if (currentType === 'CODE_BLOCK') {
44317
- buffer.push(line);
44318
- if (line.startsWith('```')) {
44319
- currentType = 'MARKDOWN';
44320
- }
44321
- }
44322
- else if (currentType === 'COMMENT') {
44323
- buffer.push(line);
44324
- if (line.includes('-->')) {
44325
- currentType = 'MARKDOWN';
44326
- }
44327
- }
44328
- }
44329
- finishSection();
44330
- return sections;
44331
- }
44332
- /**
44333
- * TODO: [🏛] This can be part of markdown builder
44334
- * Note: [🕞] In past (commit 42086e1603cbed506482997c00a8ee979af0a247) there was much more
44335
- * sophisticated implementation of this function through parsing markdown into JSON structure
44336
- * and flattening the actual structure
44337
- * NOW we are working just with markdown string and its good enough
44338
- */
44339
-
44340
44823
  /**
44341
44824
  * Normalizes the markdown by flattening the structure
44342
44825
  *
@@ -44378,111 +44861,15 @@
44378
44861
  /**
44379
44862
  * Normalizes inline parameter mentions wrapped in code spans before markdown flattening.
44380
44863
  *
44381
- * @private internal utility of `parsePipeline`
44864
+ * @private internal utility of `preparePipelineString`
44382
44865
  */
44383
44866
  const INLINE_CODE_PARAMETER_REGEXP = /`\{(?<parameterName>[a-z0-9_]+)\}`/gi;
44384
44867
  /**
44385
44868
  * Normalizes inline return statements wrapped in code spans before markdown flattening.
44386
44869
  *
44387
- * @private internal utility of `parsePipeline`
44870
+ * @private internal utility of `preparePipelineString`
44388
44871
  */
44389
44872
  const INLINE_CODE_RETURN_PARAMETER_REGEXP = /`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi;
44390
- /**
44391
- * Matches the trailing return statement of a task section.
44392
- *
44393
- * @private internal utility of `parsePipeline`
44394
- */
44395
- const RESULTING_PARAMETER_LINE_REGEXP = /^->\s*\{(?<resultingParamName>[a-z0-9_]+)\}/im;
44396
- /**
44397
- * Removes fenced code blocks when deriving human-readable section descriptions.
44398
- *
44399
- * @private internal utility of `parsePipeline`
44400
- */
44401
- const DESCRIPTION_CODE_BLOCK_REGEXP = /^```.*^```/gms;
44402
- /**
44403
- * Removes blockquote lines when deriving human-readable section descriptions.
44404
- *
44405
- * @private internal utility of `parsePipeline`
44406
- */
44407
- const DESCRIPTION_BLOCKQUOTE_REGEXP = /^>.*$/gm;
44408
- /**
44409
- * Removes list items and return statements when deriving human-readable section descriptions.
44410
- *
44411
- * @private internal utility of `parsePipeline`
44412
- */
44413
- const DESCRIPTION_LIST_ITEM_REGEXP = /^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm;
44414
- /**
44415
- * Compile pipeline from string (markdown) format to JSON format synchronously
44416
- *
44417
- * Note: There are 3 similar functions:
44418
- * - `compilePipeline` **(preferred)** - which properly compiles the promptbook and uses embedding for external knowledge
44419
- * - `parsePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
44420
- * - `preparePipeline` - just one step in the compilation process
44421
- *
44422
- * Note: This function does not validate logic of the pipeline only the parsing
44423
- * Note: This function acts as compilation process
44424
- *
44425
- * @param pipelineString {Promptbook} in string markdown format (.book.md)
44426
- * @returns {Promptbook} compiled in JSON format (.bookc)
44427
- * @throws {ParseError} if the promptbook string is not valid
44428
- *
44429
- * @public exported from `@promptbook/core`
44430
- */
44431
- function parsePipeline(pipelineString) {
44432
- const $pipelineJson = createInitialPipelineJson(pipelineString);
44433
- const preparedPipelineString = preparePipelineString(pipelineString, $pipelineJson);
44434
- const { pipelineHead, pipelineSections } = parsePreparedPipelineSections(preparedPipelineString, $pipelineJson);
44435
- const getUniqueSectionName = createUniqueSectionNameResolver(pipelineSections);
44436
- applyPipelineHead(pipelineHead, $pipelineJson);
44437
- for (const pipelineSection of pipelineSections) {
44438
- processPipelineSection(pipelineSection, $pipelineJson, getUniqueSectionName);
44439
- }
44440
- applyImplicitParameterDirections($pipelineJson);
44441
- removeUndefinedValuesFromPipeline($pipelineJson);
44442
- applySyncHighLevelAbstractions($pipelineJson);
44443
- ensurePipelineFormfactor($pipelineJson);
44444
- return exportParsedPipelineJson($pipelineJson);
44445
- }
44446
- /**
44447
- * Creates the mutable pipeline JSON structure used throughout parsing.
44448
- *
44449
- * @private internal utility of `parsePipeline`
44450
- */
44451
- function createInitialPipelineJson(pipelineString) {
44452
- return {
44453
- title: DEFAULT_BOOK_TITLE,
44454
- parameters: [],
44455
- tasks: [],
44456
- knowledgeSources: [],
44457
- knowledgePieces: [],
44458
- personas: [],
44459
- preparations: [],
44460
- sources: [
44461
- {
44462
- type: 'BOOK',
44463
- path: null,
44464
- // <- TODO: !!6 Pass here path of the file
44465
- content: pipelineString,
44466
- },
44467
- ],
44468
- };
44469
- }
44470
- /**
44471
- * Builds a short file/url identification block for parse errors.
44472
- *
44473
- * @private internal utility of `parsePipeline`
44474
- */
44475
- function getPipelineIdentification($pipelineJson) {
44476
- // Note: This is a 😐 implementation of [🚞]
44477
- const pipelineIdentificationParts = [];
44478
- if ($pipelineJson.sourceFile !== undefined) {
44479
- pipelineIdentificationParts.push(`File: ${$pipelineJson.sourceFile}`);
44480
- }
44481
- if ($pipelineJson.pipelineUrl !== undefined) {
44482
- pipelineIdentificationParts.push(`Url: ${$pipelineJson.pipelineUrl}`);
44483
- }
44484
- return pipelineIdentificationParts.join('\n');
44485
- }
44486
44873
  /**
44487
44874
  * Removes shebang/comments and normalizes markdown into a parseable pipeline form.
44488
44875
  *
@@ -44502,7 +44889,7 @@
44502
44889
  /**
44503
44890
  * Validates and removes the optional `#!` shebang line for `.book` files.
44504
44891
  *
44505
- * @private internal utility of `parsePipeline`
44892
+ * @private internal utility of `preparePipelineString`
44506
44893
  */
44507
44894
  function removePipelineShebang(pipelineString, $pipelineJson) {
44508
44895
  if (!pipelineString.startsWith('#!')) {
@@ -44526,195 +44913,21 @@
44526
44913
  }
44527
44914
  return validatePipelineString(restLines.join('\n'));
44528
44915
  }
44529
- /**
44530
- * Splits the prepared markdown into the pipeline head and task sections.
44531
- *
44532
- * @private internal utility of `parsePipeline`
44533
- */
44534
- function parsePreparedPipelineSections(pipelineString, $pipelineJson) {
44535
- const [pipelineHead, ...pipelineSections] = splitMarkdownIntoSections(pipelineString).map(parseMarkdownSection); /* <- Note: [🥞] */
44536
- assertPipelineSectionsStructure(pipelineHead, pipelineSections, $pipelineJson);
44537
- return {
44538
- pipelineHead,
44539
- pipelineSections,
44540
- };
44541
- }
44542
- /**
44543
- * Ensures the flattened markdown has exactly one h1 head followed by only h2 sections.
44544
- *
44545
- * @private internal utility of `parsePipeline`
44546
- */
44547
- function assertPipelineSectionsStructure(pipelineHead, pipelineSections, $pipelineJson) {
44548
- if (pipelineHead === undefined) {
44549
- throw new UnexpectedError(_spaceTrim.spaceTrim((block) => `
44550
- Pipeline head is not defined
44551
-
44552
- ${block(getPipelineIdentification($pipelineJson))}
44553
-
44554
- This should never happen, because the pipeline already flattened
44555
- `));
44556
- }
44557
- if (pipelineHead.level !== 1) {
44558
- throw new UnexpectedError(_spaceTrim.spaceTrim((block) => `
44559
- Pipeline head is not h1
44560
-
44561
- ${block(getPipelineIdentification($pipelineJson))}
44562
-
44563
- This should never happen, because the pipeline already flattened
44564
- `));
44565
- }
44566
- if (!pipelineSections.every((pipelineSection) => pipelineSection.level === 2)) {
44567
- throw new UnexpectedError(_spaceTrim.spaceTrim((block) => `
44568
- Not every pipeline section is h2
44569
-
44570
- ${block(getPipelineIdentification($pipelineJson))}
44571
-
44572
- This should never happen, because the pipeline already flattened
44573
- `));
44574
- }
44575
- }
44576
- /**
44577
- * Applies the pipeline head title, description, and head-level commands.
44578
- *
44579
- * @private internal utility of `parsePipeline`
44580
- */
44581
- function applyPipelineHead(pipelineHead, $pipelineJson) {
44582
- $pipelineJson.title = pipelineHead.title;
44583
- $pipelineJson.description = extractPipelineDescription(pipelineHead.content);
44584
- for (const listItem of extractAllListItemsFromMarkdown(pipelineHead.content)) {
44585
- applyPipelineHeadCommand(listItem, $pipelineJson);
44586
- }
44587
- }
44588
- /**
44589
- * Extracts the plain-text description from a head or task section body.
44590
- *
44591
- * @private internal utility of `parsePipeline`
44592
- */
44593
- function extractPipelineDescription(sectionContent) {
44594
- let description = sectionContent;
44595
- description = description.split(DESCRIPTION_CODE_BLOCK_REGEXP).join('');
44596
- description = description.split(DESCRIPTION_BLOCKQUOTE_REGEXP).join('');
44597
- description = description.split(DESCRIPTION_LIST_ITEM_REGEXP).join('');
44598
- description = _spaceTrim.spaceTrim(description);
44599
- if (description === '') {
44600
- return undefined;
44601
- }
44602
- return description;
44603
- }
44604
- /**
44605
- * Parses and applies one command declared in the pipeline head.
44606
- *
44607
- * @private internal utility of `parsePipeline`
44608
- */
44609
- function applyPipelineHeadCommand(listItem, $pipelineJson) {
44610
- const command = parseCommand(listItem, 'PIPELINE_HEAD');
44611
- const commandParser = getParserForCommand(command);
44612
- if (commandParser.isUsedInPipelineHead !== true /* <- Note: [🦦][4] */) {
44613
- throw new ParseError(_spaceTrim.spaceTrim((block) => `
44614
- Command \`${command.type}\` is not allowed in the head of the pipeline ONLY at the pipeline task
44615
-
44616
- ${block(getPipelineIdentification($pipelineJson))}
44617
- `)); // <- TODO: [🚞]
44618
- }
44619
- try {
44620
- commandParser.$applyToPipelineJson(command, $pipelineJson);
44621
- // <- Note: [🦦] Its strange that this assertion must be here, [🦦][4] should do this assertion implicitly
44622
- }
44623
- catch (error) {
44624
- if (!(error instanceof ParseError)) {
44625
- throw error;
44626
- }
44627
- throw new ParseError(_spaceTrim.spaceTrim((block) => `
44628
- Command ${command.type} failed to apply to the pipeline
44629
-
44630
- The error:
44631
- ${block(error.message)}
44632
-
44633
- Raw command:
44634
- - ${listItem}
44635
-
44636
- Usage of ${command.type}:
44637
- ${block(commandParser.examples.map((example) => `- ${example}`).join('\n'))}
44638
44916
 
44639
- ${block(getPipelineIdentification($pipelineJson))}
44640
- `)); // <- TODO: [🚞]
44641
- }
44642
- if (command.type === 'PARAMETER') {
44643
- defineParameter($pipelineJson, command);
44644
- // <- Note: [🍣]
44645
- }
44646
- }
44647
44917
  /**
44648
- * Merges one parameter declaration into the mutable pipeline parameter list.
44918
+ * Supported script languages
44649
44919
  *
44650
- * @private internal utility of `parsePipeline`
44920
+ * @private internal base for `ScriptLanguage`
44651
44921
  */
44652
- function defineParameter($pipelineJson, parameterCommand) {
44653
- const { parameterName, parameterDescription, isInput, isOutput } = parameterCommand;
44654
- if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
44655
- throw new ParseError(_spaceTrim.spaceTrim((block) => `
44656
- Parameter name {${parameterName}} is reserved and cannot be used as resulting parameter name
44657
-
44658
- ${block(getPipelineIdentification($pipelineJson))}
44659
- `) /* <- TODO: [🚞] */);
44660
- }
44661
- const existingParameter = $pipelineJson.parameters.find((parameter) => parameter.name === parameterName);
44662
- if (existingParameter &&
44663
- existingParameter.description &&
44664
- existingParameter.description !== parameterDescription &&
44665
- parameterDescription) {
44666
- throw new ParseError(_spaceTrim.spaceTrim((block) => `
44667
- Parameter \`{${parameterName}}\` is defined multiple times with different description:
44668
-
44669
- ${block(getPipelineIdentification($pipelineJson))}
44670
-
44671
- First definition:
44672
- ${block(existingParameter.description || '[undefined]')}
44922
+ const SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
44923
+ // <- TODO: [🏥] DRY
44673
44924
 
44674
- Second definition:
44675
- ${block(parameterDescription || '[undefined]')}
44676
- `));
44677
- }
44678
- if (existingParameter) {
44679
- if (parameterDescription) {
44680
- existingParameter.description = parameterDescription;
44681
- }
44682
- existingParameter.isInput = existingParameter.isInput || isInput;
44683
- existingParameter.isOutput = existingParameter.isOutput || isOutput;
44684
- return;
44685
- }
44686
- $pipelineJson.parameters.push({
44687
- name: parameterName,
44688
- description: parameterDescription || undefined,
44689
- isInput,
44690
- isOutput,
44691
- });
44692
- }
44693
44925
  /**
44694
- * Creates stable unique task names for duplicate section titles.
44926
+ * Matches the trailing return statement of a task section.
44695
44927
  *
44696
- * @private internal utility of `parsePipeline`
44928
+ * @private internal utility of `processPipelineSection`
44697
44929
  */
44698
- function createUniqueSectionNameResolver(pipelineSections) {
44699
- const sectionCounts = {};
44700
- for (const pipelineSection of pipelineSections) {
44701
- const sectionName = titleToName(pipelineSection.title);
44702
- if (sectionCounts[sectionName] === undefined) {
44703
- sectionCounts[sectionName] = { count: 0, currentIndex: 0 };
44704
- }
44705
- sectionCounts[sectionName].count++;
44706
- }
44707
- return (title) => {
44708
- const sectionName = titleToName(title);
44709
- const sectionCount = sectionCounts[sectionName];
44710
- if (sectionCount.count === 1) {
44711
- return sectionName;
44712
- }
44713
- const nameWithSuffix = `${sectionName}-${sectionCount.currentIndex}`;
44714
- sectionCount.currentIndex++;
44715
- return nameWithSuffix;
44716
- };
44717
- }
44930
+ const RESULTING_PARAMETER_LINE_REGEXP = /^->\s*\{(?<resultingParamName>[a-z0-9_]+)\}/im;
44718
44931
  /**
44719
44932
  * Parses, applies, and persists one h2 task section.
44720
44933
  *
@@ -44734,7 +44947,7 @@
44734
44947
  /**
44735
44948
  * Creates the mutable task JSON shell from one markdown section.
44736
44949
  *
44737
- * @private internal utility of `parsePipeline`
44950
+ * @private internal utility of `processPipelineSection`
44738
44951
  */
44739
44952
  function createTaskJsonFromSection(pipelineSection, getUniqueSectionName) {
44740
44953
  const { language, content } = extractOneBlockFromMarkdown(pipelineSection.content);
@@ -44762,7 +44975,7 @@
44762
44975
  /**
44763
44976
  * Extracts the optional trailing `-> {parameter}` statement from a section body.
44764
44977
  *
44765
- * @private internal utility of `parsePipeline`
44978
+ * @private internal utility of `processPipelineSection`
44766
44979
  */
44767
44980
  function extractResultingParameterName(sectionContent) {
44768
44981
  var _a;
@@ -44773,7 +44986,7 @@
44773
44986
  /**
44774
44987
  * Parses all list-item commands declared inside one task section.
44775
44988
  *
44776
- * @private internal utility of `parsePipeline`
44989
+ * @private internal utility of `processPipelineSection`
44777
44990
  */
44778
44991
  function parsePipelineTaskCommands(sectionContent) {
44779
44992
  return extractAllListItemsFromMarkdown(sectionContent).map((listItem) => ({
@@ -44784,7 +44997,7 @@
44784
44997
  /**
44785
44998
  * Applies the implicit default `PROMPT_TASK` section type when no SECTION command is present.
44786
44999
  *
44787
- * @private internal utility of `parsePipeline`
45000
+ * @private internal utility of `processPipelineSection`
44788
45001
  */
44789
45002
  function applyDefaultTaskSectionType($taskJson, commands, $pipelineJson) {
44790
45003
  const isSectionCommandPresent = commands.some(({ command }) => command.type === 'SECTION');
@@ -44796,7 +45009,7 @@
44796
45009
  /**
44797
45010
  * Parses and applies one command declared inside a task section.
44798
45011
  *
44799
- * @private internal utility of `parsePipeline`
45012
+ * @private internal utility of `processPipelineSection`
44800
45013
  */
44801
45014
  function applyPipelineTaskCommand(commandItem, $taskJson, $pipelineJson) {
44802
45015
  const { listItem, command } = commandItem;
@@ -44847,7 +45060,7 @@
44847
45060
  /**
44848
45061
  * Validates and stores the language for SCRIPT tasks.
44849
45062
  *
44850
- * @private internal utility of `parsePipeline`
45063
+ * @private internal utility of `processPipelineSection`
44851
45064
  */
44852
45065
  function applyScriptTaskLanguage($taskJson, language, $pipelineJson) {
44853
45066
  const isScriptTask = $taskJson.taskType === 'SCRIPT_TASK';
@@ -44864,7 +45077,6 @@
44864
45077
  if (!SUPPORTED_SCRIPT_LANGUAGES.includes(language)) {
44865
45078
  throw new ParseError(_spaceTrim.spaceTrim((block) => `
44866
45079
  Script language ${language} is not supported.
44867
-
44868
45080
  Supported languages are:
44869
45081
  ${block(SUPPORTED_SCRIPT_LANGUAGES.join(', '))}
44870
45082
 
@@ -44875,7 +45087,7 @@
44875
45087
  /**
44876
45088
  * Extracts task dependencies and ensures referenced parameters exist.
44877
45089
  *
44878
- * @private internal utility of `parsePipeline`
45090
+ * @private internal utility of `processPipelineSection`
44879
45091
  */
44880
45092
  function registerTaskDependentParameters($taskJson, $pipelineJson) {
44881
45093
  $taskJson.dependentParameterNames = Array.from(extractParameterNamesFromTask($taskJson));
@@ -44893,7 +45105,7 @@
44893
45105
  /**
44894
45106
  * Removes transient parsing flags and persists real tasks into the pipeline JSON.
44895
45107
  *
44896
- * @private internal utility of `parsePipeline`
45108
+ * @private internal utility of `processPipelineSection`
44897
45109
  */
44898
45110
  function persistTaskIfNeeded($taskJson, $pipelineJson) {
44899
45111
  /*
@@ -44922,119 +45134,38 @@
44922
45134
  // TODO: [🍙] Maybe do reorder of `$taskJson` here
44923
45135
  $pipelineJson.tasks.push($taskJson);
44924
45136
  }
45137
+
44925
45138
  /**
44926
- * Applies default INPUT/OUTPUT flags when the author did not specify them explicitly.
44927
- *
44928
- * @private internal utility of `parsePipeline`
44929
- */
44930
- function applyImplicitParameterDirections($pipelineJson) {
44931
- markImplicitInputParameters($pipelineJson);
44932
- markImplicitOutputParameters($pipelineJson);
44933
- }
44934
- /**
44935
- * Marks non-result parameters as pipeline inputs when no input was declared.
44936
- *
44937
- * @private internal utility of `parsePipeline`
44938
- */
44939
- function markImplicitInputParameters($pipelineJson) {
44940
- if ($pipelineJson.parameters.some((parameter) => parameter.isInput)) {
44941
- return;
44942
- }
44943
- for (const parameter of $pipelineJson.parameters) {
44944
- const isThisParameterResulting = $pipelineJson.tasks.some((task) => task.resultingParameterName === parameter.name);
44945
- if (!isThisParameterResulting) {
44946
- parameter.isInput = true;
44947
- // <- TODO: [💔] Why this is making typescript error in vscode but not in cli
44948
- // > Type 'true' is not assignable to type 'false'.ts(2322)
44949
- // > (property) isInput: false
44950
- // > The parameter is input of the pipeline The parameter is NOT input of the pipeline
44951
- }
44952
- }
44953
- }
44954
- /**
44955
- * Marks every non-input parameter as output when no output was declared.
44956
- *
44957
- * @private internal utility of `parsePipeline`
44958
- */
44959
- function markImplicitOutputParameters($pipelineJson) {
44960
- if ($pipelineJson.parameters.some((parameter) => parameter.isOutput)) {
44961
- return;
44962
- }
44963
- for (const parameter of $pipelineJson.parameters) {
44964
- if (!parameter.isInput) {
44965
- parameter.isOutput = true;
44966
- // <- TODO: [💔]
44967
- }
44968
- }
44969
- }
44970
- /**
44971
- * Removes `undefined` properties from serialized tasks and parameters.
45139
+ * Compile pipeline from string (markdown) format to JSON format synchronously
44972
45140
  *
44973
- * @private internal utility of `parsePipeline`
44974
- */
44975
- function removeUndefinedValuesFromPipeline($pipelineJson) {
44976
- $pipelineJson.tasks.forEach(removeUndefinedProperties);
44977
- $pipelineJson.parameters.forEach(removeUndefinedProperties);
44978
- }
44979
- /**
44980
- * Deletes all own properties with `undefined` values from a mutable JSON entity.
45141
+ * Note: There are 3 similar functions:
45142
+ * - `compilePipeline` **(preferred)** - which properly compiles the promptbook and uses embedding for external knowledge
45143
+ * - `parsePipeline` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
45144
+ * - `preparePipeline` - just one step in the compilation process
44981
45145
  *
44982
- * @private internal utility of `parsePipeline`
44983
- */
44984
- function removeUndefinedProperties(entity) {
44985
- for (const [key, value] of Object.entries(entity)) {
44986
- if (value === undefined) {
44987
- delete entity[key];
44988
- }
44989
- }
44990
- }
44991
- /**
44992
- * Applies all sync-only high-level abstractions after parsing.
45146
+ * Note: This function does not validate logic of the pipeline only the parsing
45147
+ * Note: This function acts as compilation process
44993
45148
  *
44994
- * @private internal utility of `parsePipeline`
44995
- */
44996
- function applySyncHighLevelAbstractions($pipelineJson) {
44997
- for (const highLevelAbstraction of HIGH_LEVEL_ABSTRACTIONS.filter(({ type }) => type === 'SYNC')) {
44998
- highLevelAbstraction.$applyToPipelineJson($pipelineJson);
44999
- }
45000
- }
45001
- /**
45002
- * Ensures parsed pipelines always have the default `GENERIC` formfactor.
45149
+ * @param pipelineString {Promptbook} in string markdown format (.book.md)
45150
+ * @returns {Promptbook} compiled in JSON format (.bookc)
45151
+ * @throws {ParseError} if the promptbook string is not valid
45003
45152
  *
45004
- * @private internal utility of `parsePipeline`
45153
+ * @public exported from `@promptbook/core`
45005
45154
  */
45006
- function ensurePipelineFormfactor($pipelineJson) {
45007
- // Note: [🔆] If formfactor is still not set, set it to 'GENERIC'
45008
- if ($pipelineJson.formfactorName === undefined) {
45009
- $pipelineJson.formfactorName = 'GENERIC';
45155
+ function parsePipeline(pipelineString) {
45156
+ const $pipelineJson = createInitialPipelineJson(pipelineString);
45157
+ const preparedPipelineString = preparePipelineString(pipelineString, $pipelineJson);
45158
+ const { pipelineHead, pipelineSections } = parsePreparedPipelineSections(preparedPipelineString, $pipelineJson);
45159
+ const getUniqueSectionName = createUniqueSectionNameResolver(pipelineSections);
45160
+ applyPipelineHead(pipelineHead, $pipelineJson);
45161
+ for (const pipelineSection of pipelineSections) {
45162
+ processPipelineSection(pipelineSection, $pipelineJson, getUniqueSectionName);
45010
45163
  }
45011
- }
45012
- /**
45013
- * Finalizes ordering and exports the parsed pipeline JSON.
45014
- *
45015
- * @private internal utility of `parsePipeline`
45016
- */
45017
- function exportParsedPipelineJson($pipelineJson) {
45018
- return exportJson({
45019
- name: 'pipelineJson',
45020
- message: `Result of \`parsePipeline\``,
45021
- order: ORDER_OF_PIPELINE_JSON,
45022
- value: {
45023
- formfactorName: 'GENERIC',
45024
- // <- Note: [🔆] Setting `formfactorName` is redundant to satisfy the typescript
45025
- ...$pipelineJson,
45026
- },
45027
- });
45164
+ return finalizeParsedPipeline($pipelineJson);
45028
45165
  }
45029
45166
  // TODO: [🧠] Maybe more things here can be refactored as high-level abstractions
45030
45167
  // TODO: [main] !!4 Warn if used only sync version
45031
45168
  // TODO: [🚞] Report here line/column of error
45032
- // TODO: Use spaceTrim more effectively
45033
- // TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
45034
- // TODO: [🥞] Not optimal parsing because `splitMarkdownIntoSections` is executed twice with same string, once through `flattenMarkdown` and second directly here
45035
- // TODO: [♈] Probably move expectations from tasks to parameters
45036
- // TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
45037
- // TODO: [🍙] Make some standard order of json properties
45038
45169
 
45039
45170
  /**
45040
45171
  * Compile pipeline from string (markdown) format to JSON format