@promptbook/wizard 0.103.0-54 → 0.103.0-56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/esm/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
1
+ import spaceTrim$2, { spaceTrim as spaceTrim$1 } from 'spacetrim';
2
2
  import { randomBytes } from 'crypto';
3
3
  import { io } from 'socket.io-client';
4
4
  import Anthropic from '@anthropic-ai/sdk';
@@ -36,7 +36,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
36
36
  * @generated
37
37
  * @see https://github.com/webgptorg/promptbook
38
38
  */
39
- const PROMPTBOOK_ENGINE_VERSION = '0.103.0-54';
39
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-56';
40
40
  /**
41
41
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
42
42
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -90,6 +90,17 @@ const REMOTE_SERVER_URLS = [
90
90
  * Note: [💞] Ignore a discrepancy between file name and entity name
91
91
  */
92
92
 
93
+ /**
94
+ * Trims string from all 4 sides
95
+ *
96
+ * Note: This is a re-exported function from the `spacetrim` package which is
97
+ * Developed by same author @hejny as this package
98
+ *
99
+ * @public exported from `@promptbook/utils`
100
+ * @see https://github.com/hejny/spacetrim#usage
101
+ */
102
+ const spaceTrim = spaceTrim$1;
103
+
93
104
  /**
94
105
  * Just marks a place of place where should be something implemented
95
106
  * No side effects.
@@ -151,6 +162,7 @@ function take(initialValue) {
151
162
  * @public exported from `@promptbook/color`
152
163
  */
153
164
  const CSS_COLORS = {
165
+ promptbook: '#79EAFD',
154
166
  transparent: 'rgba(0,0,0,0)',
155
167
  aliceblue: '#f0f8ff',
156
168
  antiquewhite: '#faebd7',
@@ -366,6 +378,28 @@ class Color {
366
378
  throw new Error(`Can not create color from given object`);
367
379
  }
368
380
  }
381
+ /**
382
+ * Creates a new Color instance from miscellaneous formats
383
+ * It just does not throw error when it fails, it returns PROMPTBOOK_COLOR instead
384
+ *
385
+ * @param color
386
+ * @returns Color object
387
+ */
388
+ static fromSafe(color) {
389
+ try {
390
+ return Color.from(color);
391
+ }
392
+ catch (error) {
393
+ // <- Note: Can not use `assertsError(error)` here because it causes circular dependency
394
+ console.warn(spaceTrim((block) => `
395
+ Color.fromSafe error:
396
+ ${block(error.message)}
397
+
398
+ Returning default PROMPTBOOK_COLOR.
399
+ `));
400
+ return Color.fromString('promptbook');
401
+ }
402
+ }
369
403
  /**
370
404
  * Creates a new Color instance from miscellaneous string formats
371
405
  *
@@ -975,7 +1009,7 @@ const ADMIN_GITHUB_NAME = 'hejny';
975
1009
  *
976
1010
  * @public exported from `@promptbook/core`
977
1011
  */
978
- const PROMPTBOOK_COLOR = Color.fromHex('#79EAFD');
1012
+ const PROMPTBOOK_COLOR = Color.fromString('promptbook');
979
1013
  // <- TODO: [🧠][🈵] Using `Color` here increases the package size approx 3kb, maybe remove it
980
1014
  /**
981
1015
  * Colors for syntax highlighting in the `<BookEditor/>`
@@ -1291,7 +1325,7 @@ function $deepFreeze(objectValue) {
1291
1325
  function getErrorReportUrl(error) {
1292
1326
  const report = {
1293
1327
  title: `🐜 Error report from ${NAME}`,
1294
- body: spaceTrim((block) => `
1328
+ body: spaceTrim$2((block) => `
1295
1329
 
1296
1330
 
1297
1331
  \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
@@ -1449,7 +1483,7 @@ function checkSerializableAsJson(options) {
1449
1483
  }
1450
1484
  else if (typeof value === 'object') {
1451
1485
  if (value instanceof Date) {
1452
- throw new UnexpectedError(spaceTrim((block) => `
1486
+ throw new UnexpectedError(spaceTrim$2((block) => `
1453
1487
  \`${name}\` is Date
1454
1488
 
1455
1489
  Use \`string_date_iso8601\` instead
@@ -1468,7 +1502,7 @@ function checkSerializableAsJson(options) {
1468
1502
  throw new UnexpectedError(`${name} is RegExp`);
1469
1503
  }
1470
1504
  else if (value instanceof Error) {
1471
- throw new UnexpectedError(spaceTrim((block) => `
1505
+ throw new UnexpectedError(spaceTrim$2((block) => `
1472
1506
  \`${name}\` is unserialized Error
1473
1507
 
1474
1508
  Use function \`serializeError\`
@@ -1491,7 +1525,7 @@ function checkSerializableAsJson(options) {
1491
1525
  }
1492
1526
  catch (error) {
1493
1527
  assertsError(error);
1494
- throw new UnexpectedError(spaceTrim((block) => `
1528
+ throw new UnexpectedError(spaceTrim$2((block) => `
1495
1529
  \`${name}\` is not serializable
1496
1530
 
1497
1531
  ${block(error.stack || error.message)}
@@ -1523,7 +1557,7 @@ function checkSerializableAsJson(options) {
1523
1557
  }
1524
1558
  }
1525
1559
  else {
1526
- throw new UnexpectedError(spaceTrim((block) => `
1560
+ throw new UnexpectedError(spaceTrim$2((block) => `
1527
1561
  \`${name}\` is unknown type
1528
1562
 
1529
1563
  Additional message for \`${name}\`:
@@ -2254,7 +2288,7 @@ function deserializeError(error) {
2254
2288
  message = `${name}: ${message}`;
2255
2289
  }
2256
2290
  if (stack !== undefined && stack !== '') {
2257
- message = spaceTrim((block) => `
2291
+ message = spaceTrim$2((block) => `
2258
2292
  ${block(message)}
2259
2293
 
2260
2294
  Original stack trace:
@@ -2311,7 +2345,7 @@ async function createRemoteClient(options) {
2311
2345
  const remoteServerUrlParsed = new URL(remoteServerUrl);
2312
2346
  if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
2313
2347
  remoteServerUrlParsed.pathname = '/';
2314
- throw new Error(spaceTrim((block) => `
2348
+ throw new Error(spaceTrim$2((block) => `
2315
2349
  Remote server requires root url \`/\`
2316
2350
 
2317
2351
  You have provided \`remoteServerUrl\`:
@@ -3538,7 +3572,7 @@ class AnthropicClaudeExecutionTools {
3538
3572
  getDefaultModel(defaultModelName) {
3539
3573
  const model = ANTHROPIC_CLAUDE_MODELS.find(({ modelName }) => modelName.startsWith(defaultModelName));
3540
3574
  if (model === undefined) {
3541
- throw new UnexpectedError(spaceTrim((block) => `
3575
+ throw new UnexpectedError(spaceTrim$2((block) => `
3542
3576
  Cannot find model in Anthropic Claude models with name "${defaultModelName}" which should be used as default.
3543
3577
 
3544
3578
  Available models:
@@ -4778,7 +4812,7 @@ function createExecutionToolsFromVercelProvider(options) {
4778
4812
  const modelName = modelRequirements.modelName ||
4779
4813
  ((_a = availableModels.find(({ modelVariant }) => modelVariant === 'CHAT')) === null || _a === void 0 ? void 0 : _a.modelName);
4780
4814
  if (!modelName) {
4781
- throw new PipelineExecutionError(spaceTrim(`
4815
+ throw new PipelineExecutionError(spaceTrim$2(`
4782
4816
  Can not determine which model to use.
4783
4817
 
4784
4818
  You need to provide at least one of:
@@ -6156,7 +6190,7 @@ class OpenAiCompatibleExecutionTools {
6156
6190
  // Note: Match exact or prefix for model families
6157
6191
  const model = this.HARDCODED_MODELS.find(({ modelName }) => modelName === defaultModelName || modelName.startsWith(defaultModelName));
6158
6192
  if (model === undefined) {
6159
- throw new PipelineExecutionError(spaceTrim((block) => `
6193
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
6160
6194
  Cannot find model in ${this.title} models with name "${defaultModelName}" which should be used as default.
6161
6195
 
6162
6196
  Available models:
@@ -6900,18 +6934,26 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
6900
6934
  modelName: 'assistant',
6901
6935
  // <- [🧠] What is the best value here
6902
6936
  });
6937
+ // Build thread messages: include previous thread messages + current user message
6938
+ const threadMessages = [];
6939
+ // TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
6940
+ // Add previous messages from thread (if any)
6941
+ if ('thread' in prompt &&
6942
+ Array.isArray(prompt.thread)) {
6943
+ const previousMessages = prompt.thread.map((msg) => ({
6944
+ role: (msg.role === 'assistant' ? 'assistant' : 'user'),
6945
+ content: msg.content,
6946
+ }));
6947
+ threadMessages.push(...previousMessages);
6948
+ }
6949
+ // Always add the current user message
6950
+ threadMessages.push({ role: 'user', content: rawPromptContent });
6903
6951
  const rawRequest = {
6904
6952
  // TODO: [👨‍👨‍👧‍👧] ...modelSettings,
6905
6953
  // TODO: [👨‍👨‍👧‍👧][🧠] What about system message for assistants, does it make sense - combination of OpenAI assistants with Promptbook Personas
6906
6954
  assistant_id: this.assistantId,
6907
6955
  thread: {
6908
- messages: 'thread' in prompt &&
6909
- Array.isArray(prompt.thread)
6910
- ? prompt.thread.map((msg) => ({
6911
- role: msg.role === 'assistant' ? 'assistant' : 'user',
6912
- content: msg.content,
6913
- }))
6914
- : [{ role: 'user', content: rawPromptContent }],
6956
+ messages: threadMessages,
6915
6957
  },
6916
6958
  // <- TODO: Add user identification here> user: this.options.user,
6917
6959
  };
@@ -6931,7 +6973,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
6931
6973
  console.info('textDelta', textDelta.value);
6932
6974
  }
6933
6975
  const chunk = {
6934
- content: textDelta.value || '',
6976
+ content: snapshot.value,
6935
6977
  modelName: 'assistant',
6936
6978
  timing: {
6937
6979
  start,
@@ -8103,7 +8145,7 @@ function pipelineJsonToString(pipelineJson) {
8103
8145
  pipelineString += '\n\n';
8104
8146
  pipelineString += '```' + contentLanguage;
8105
8147
  pipelineString += '\n';
8106
- pipelineString += spaceTrim(content);
8148
+ pipelineString += spaceTrim$2(content);
8107
8149
  // <- TODO: [main] !!3 Escape
8108
8150
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
8109
8151
  pipelineString += '\n';
@@ -8718,7 +8760,7 @@ function serializeError(error) {
8718
8760
  const { name, message, stack } = error;
8719
8761
  const { id } = error;
8720
8762
  if (!Object.keys(ALL_ERRORS).includes(name)) {
8721
- console.error(spaceTrim((block) => `
8763
+ console.error(spaceTrim$2((block) => `
8722
8764
 
8723
8765
  Cannot serialize error with name "${name}"
8724
8766
 
@@ -8751,7 +8793,7 @@ function jsonParse(value) {
8751
8793
  }
8752
8794
  else if (typeof value !== 'string') {
8753
8795
  console.error('Can not parse JSON from non-string value.', { text: value });
8754
- throw new Error(spaceTrim(`
8796
+ throw new Error(spaceTrim$2(`
8755
8797
  Can not parse JSON from non-string value.
8756
8798
 
8757
8799
  The value type: ${typeof value}
@@ -8765,7 +8807,7 @@ function jsonParse(value) {
8765
8807
  if (!(error instanceof Error)) {
8766
8808
  throw error;
8767
8809
  }
8768
- throw new Error(spaceTrim((block) => `
8810
+ throw new Error(spaceTrim$2((block) => `
8769
8811
  ${block(error.message)}
8770
8812
 
8771
8813
  The expected JSON text:
@@ -9236,14 +9278,14 @@ class MultipleLlmExecutionTools {
9236
9278
  if (description === undefined) {
9237
9279
  return headLine;
9238
9280
  }
9239
- return spaceTrim((block) => `
9281
+ return spaceTrim$2((block) => `
9240
9282
  ${headLine}
9241
9283
 
9242
9284
  ${ /* <- Note: Indenting the description: */block(description)}
9243
9285
  `);
9244
9286
  })
9245
9287
  .join('\n\n');
9246
- return spaceTrim((block) => `
9288
+ return spaceTrim$2((block) => `
9247
9289
  Multiple LLM Providers:
9248
9290
 
9249
9291
  ${block(innerModelsTitlesAndDescriptions)}
@@ -9334,7 +9376,7 @@ class MultipleLlmExecutionTools {
9334
9376
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
9335
9377
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
9336
9378
  // 3) ...
9337
- spaceTrim((block) => `
9379
+ spaceTrim$2((block) => `
9338
9380
  All execution tools of ${this.title} failed:
9339
9381
 
9340
9382
  ${block(errors
@@ -9347,7 +9389,7 @@ class MultipleLlmExecutionTools {
9347
9389
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\` into ${this.title}`);
9348
9390
  }
9349
9391
  else {
9350
- throw new PipelineExecutionError(spaceTrim((block) => `
9392
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
9351
9393
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}" into ${this.title}
9352
9394
 
9353
9395
  Available \`LlmExecutionTools\`:
@@ -9380,7 +9422,7 @@ class MultipleLlmExecutionTools {
9380
9422
  */
9381
9423
  function joinLlmExecutionTools(title, ...llmExecutionTools) {
9382
9424
  if (llmExecutionTools.length === 0) {
9383
- const warningMessage = spaceTrim(`
9425
+ const warningMessage = spaceTrim$2(`
9384
9426
  You have not provided any \`LlmExecutionTools\`
9385
9427
  This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.
9386
9428
 
@@ -9552,14 +9594,14 @@ function $registeredScrapersMessage(availableScrapers) {
9552
9594
  return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
9553
9595
  });
9554
9596
  if (metadata.length === 0) {
9555
- return spaceTrim(`
9597
+ return spaceTrim$2(`
9556
9598
  **No scrapers are available**
9557
9599
 
9558
9600
  This is a unexpected behavior, you are probably using some broken version of Promptbook
9559
9601
  At least there should be available the metadata of the scrapers
9560
9602
  `);
9561
9603
  }
9562
- return spaceTrim((block) => `
9604
+ return spaceTrim$2((block) => `
9563
9605
  Available scrapers are:
9564
9606
  ${block(metadata
9565
9607
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
@@ -9660,7 +9702,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
9660
9702
  else if (urlOrRequest instanceof Request) {
9661
9703
  url = urlOrRequest.url;
9662
9704
  }
9663
- throw new PromptbookFetchError(spaceTrim((block) => `
9705
+ throw new PromptbookFetchError(spaceTrim$2((block) => `
9664
9706
  Can not fetch "${url}"
9665
9707
 
9666
9708
  Fetch error:
@@ -9821,7 +9863,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
9821
9863
  const fileExtension = getFileExtension(filename);
9822
9864
  const mimeType = extensionToMimeType(fileExtension || '');
9823
9865
  if (!(await isFileExisting(filename, tools.fs))) {
9824
- throw new NotFoundError(spaceTrim((block) => `
9866
+ throw new NotFoundError(spaceTrim$2((block) => `
9825
9867
  Can not make source handler for file which does not exist:
9826
9868
 
9827
9869
  File:
@@ -9914,7 +9956,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
9914
9956
  // <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
9915
9957
  break;
9916
9958
  }
9917
- console.warn(spaceTrim((block) => `
9959
+ console.warn(spaceTrim$2((block) => `
9918
9960
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
9919
9961
 
9920
9962
  The source:
@@ -9930,7 +9972,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
9930
9972
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
9931
9973
  }
9932
9974
  if (partialPieces === null) {
9933
- throw new KnowledgeScrapeError(spaceTrim((block) => `
9975
+ throw new KnowledgeScrapeError(spaceTrim$2((block) => `
9934
9976
  Cannot scrape knowledge
9935
9977
 
9936
9978
  The source:
@@ -10424,7 +10466,7 @@ const CsvFormatParser = {
10424
10466
  const { value, outputParameterName, settings, mapCallback, onProgress } = options;
10425
10467
  const csv = csvParse(value, settings);
10426
10468
  if (csv.errors.length !== 0) {
10427
- throw new CsvFormatError(spaceTrim((block) => `
10469
+ throw new CsvFormatError(spaceTrim$2((block) => `
10428
10470
  CSV parsing error
10429
10471
 
10430
10472
  Error(s) from CSV parsing:
@@ -10469,7 +10511,7 @@ const CsvFormatParser = {
10469
10511
  const { value, settings, mapCallback, onProgress } = options;
10470
10512
  const csv = csvParse(value, settings);
10471
10513
  if (csv.errors.length !== 0) {
10472
- throw new CsvFormatError(spaceTrim((block) => `
10514
+ throw new CsvFormatError(spaceTrim$2((block) => `
10473
10515
  CSV parsing error
10474
10516
 
10475
10517
  Error(s) from CSV parsing:
@@ -10679,7 +10721,7 @@ function mapAvailableToExpectedParameters(options) {
10679
10721
  }
10680
10722
  // Phase 2️⃣: Non-matching mapping
10681
10723
  if (expectedParameterNames.size !== availableParametersNames.size) {
10682
- throw new PipelineExecutionError(spaceTrim((block) => `
10724
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
10683
10725
  Can not map available parameters to expected parameters
10684
10726
 
10685
10727
  Mapped parameters:
@@ -11269,7 +11311,7 @@ async function executeFormatSubvalues(options) {
11269
11311
  return /* not await */ executeAttempts({ ...options, logLlmCall });
11270
11312
  }
11271
11313
  if (jokerParameterNames.length !== 0) {
11272
- throw new UnexpectedError(spaceTrim((block) => `
11314
+ throw new UnexpectedError(spaceTrim$2((block) => `
11273
11315
  JOKER parameters are not supported together with FOREACH command
11274
11316
 
11275
11317
  [🧞‍♀️] This should be prevented in \`validatePipeline\`
@@ -11282,7 +11324,7 @@ async function executeFormatSubvalues(options) {
11282
11324
  if (formatDefinition === undefined) {
11283
11325
  throw new UnexpectedError(
11284
11326
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
11285
- spaceTrim((block) => `
11327
+ spaceTrim$2((block) => `
11286
11328
  Unsupported format "${task.foreach.formatName}"
11287
11329
 
11288
11330
  Available formats:
@@ -11299,7 +11341,7 @@ async function executeFormatSubvalues(options) {
11299
11341
  if (subvalueParser === undefined) {
11300
11342
  throw new UnexpectedError(
11301
11343
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
11302
- spaceTrim((block) => `
11344
+ spaceTrim$2((block) => `
11303
11345
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
11304
11346
 
11305
11347
  Available subformat names for format "${formatDefinition.formatName}":
@@ -11339,7 +11381,7 @@ async function executeFormatSubvalues(options) {
11339
11381
  if (!(error instanceof PipelineExecutionError)) {
11340
11382
  throw error;
11341
11383
  }
11342
- const highLevelError = new PipelineExecutionError(spaceTrim((block) => `
11384
+ const highLevelError = new PipelineExecutionError(spaceTrim$2((block) => `
11343
11385
  ${error.message}
11344
11386
 
11345
11387
  This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -11363,7 +11405,7 @@ async function executeFormatSubvalues(options) {
11363
11405
  ...options,
11364
11406
  priority: priority + index,
11365
11407
  parameters: allSubparameters,
11366
- pipelineIdentification: spaceTrim((block) => `
11408
+ pipelineIdentification: spaceTrim$2((block) => `
11367
11409
  ${block(pipelineIdentification)}
11368
11410
  Subparameter index: ${index}
11369
11411
  `),
@@ -11372,7 +11414,7 @@ async function executeFormatSubvalues(options) {
11372
11414
  }
11373
11415
  catch (error) {
11374
11416
  if (length > BIG_DATASET_TRESHOLD) {
11375
- console.error(spaceTrim((block) => `
11417
+ console.error(spaceTrim$2((block) => `
11376
11418
  ${error.message}
11377
11419
 
11378
11420
  This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -12244,8 +12286,8 @@ class MarkdownScraper {
12244
12286
  knowledgeTextPieces.map(async (knowledgeTextPiece, i) => {
12245
12287
  // Note: These are just default values, they will be overwritten by the actual values:
12246
12288
  let name = `piece-${i}`;
12247
- let title = spaceTrim(knowledgeTextPiece.substring(0, 100));
12248
- const knowledgePieceContent = spaceTrim(knowledgeTextPiece);
12289
+ let title = spaceTrim$2(knowledgeTextPiece.substring(0, 100));
12290
+ const knowledgePieceContent = spaceTrim$2(knowledgeTextPiece);
12249
12291
  let keywords = [];
12250
12292
  const index = [];
12251
12293
  /*
@@ -12258,7 +12300,7 @@ class MarkdownScraper {
12258
12300
  isCrashedOnError: true,
12259
12301
  });
12260
12302
  const { title: titleRaw = 'Untitled' } = titleResult.outputParameters;
12261
- title = spaceTrim(titleRaw) /* <- TODO: Maybe do in pipeline */;
12303
+ title = spaceTrim$2(titleRaw) /* <- TODO: Maybe do in pipeline */;
12262
12304
  name = titleToName(title);
12263
12305
  // --- Keywords
12264
12306
  const keywordsResult = await prepareKeywordsExecutor({ knowledgePieceContent }).asPromise({
@@ -12413,7 +12455,7 @@ class BoilerplateScraper {
12413
12455
  await $execCommand(command);
12414
12456
  // Note: [0]
12415
12457
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
12416
- throw new UnexpectedError(spaceTrim((block) => `
12458
+ throw new UnexpectedError(spaceTrim$2((block) => `
12417
12459
  File that was supposed to be created by Pandoc does not exist for unknown reason
12418
12460
 
12419
12461
  Expected file:
@@ -12577,7 +12619,7 @@ class DocumentScraper {
12577
12619
  await $execCommand(command);
12578
12620
  // Note: [0]
12579
12621
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
12580
- throw new UnexpectedError(spaceTrim((block) => `
12622
+ throw new UnexpectedError(spaceTrim$2((block) => `
12581
12623
  File that was supposed to be created by Pandoc does not exist for unknown reason
12582
12624
 
12583
12625
  Expected file:
@@ -12728,7 +12770,7 @@ class LegacyDocumentScraper {
12728
12770
  await $execCommand(command);
12729
12771
  const files = await readdir(documentSourceOutdirPathForLibreOffice);
12730
12772
  if (files.length !== 1) {
12731
- throw new UnexpectedError(spaceTrim((block) => `
12773
+ throw new UnexpectedError(spaceTrim$2((block) => `
12732
12774
  Expected exactly 1 file in the LibreOffice output directory, got ${files.length}
12733
12775
 
12734
12776
  The temporary folder:
@@ -12742,7 +12784,7 @@ class LegacyDocumentScraper {
12742
12784
  await rename(join(documentSourceOutdirPathForLibreOffice, file), cacheFilehandler.filename);
12743
12785
  await rmdir(documentSourceOutdirPathForLibreOffice);
12744
12786
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
12745
- throw new UnexpectedError(spaceTrim((block) => `
12787
+ throw new UnexpectedError(spaceTrim$2((block) => `
12746
12788
  File that was supposed to be created by LibreOffice does not exist for unknown reason
12747
12789
 
12748
12790
  Expected file:
@@ -13615,6 +13657,133 @@ class ActionCommitmentDefinition extends BaseCommitmentDefinition {
13615
13657
  * Note: [💞] Ignore a discrepancy between file name and entity name
13616
13658
  */
13617
13659
 
13660
+ /**
13661
+ * CLOSED commitment definition
13662
+ *
13663
+ * The CLOSED commitment specifies that the agent CANNOT be modified by conversation.
13664
+ * It prevents the agent from learning from interactions and updating its source code.
13665
+ *
13666
+ * Example usage in agent source:
13667
+ *
13668
+ * ```book
13669
+ * CLOSED
13670
+ * ```
13671
+ *
13672
+ * @private [🪔] Maybe export the commitments through some package
13673
+ */
13674
+ class ClosedCommitmentDefinition extends BaseCommitmentDefinition {
13675
+ constructor() {
13676
+ super('CLOSED');
13677
+ }
13678
+ /**
13679
+ * Short one-line description of CLOSED.
13680
+ */
13681
+ get description() {
13682
+ return 'Prevent the agent from being modified by conversation.';
13683
+ }
13684
+ /**
13685
+ * Icon for this commitment.
13686
+ */
13687
+ get icon() {
13688
+ return '🔒';
13689
+ }
13690
+ /**
13691
+ * Markdown documentation for CLOSED commitment.
13692
+ */
13693
+ get documentation() {
13694
+ return spaceTrim$1(`
13695
+ # CLOSED
13696
+
13697
+ Specifies that the agent **cannot** be modified by conversation with it.
13698
+ This means the agent will **not** learn from interactions and its source code will remain static during conversation.
13699
+
13700
+ By default (if not specified), agents are \`OPEN\` to modification.
13701
+
13702
+ > See also [OPEN](/docs/OPEN)
13703
+
13704
+ ## Example
13705
+
13706
+ \`\`\`book
13707
+ CLOSED
13708
+ \`\`\`
13709
+ `);
13710
+ }
13711
+ applyToAgentModelRequirements(requirements, _content) {
13712
+ const updatedMetadata = {
13713
+ ...requirements.metadata,
13714
+ isClosed: true,
13715
+ };
13716
+ return {
13717
+ ...requirements,
13718
+ metadata: updatedMetadata,
13719
+ };
13720
+ }
13721
+ }
13722
+ /**
13723
+ * Note: [💞] Ignore a discrepancy between file name and entity name
13724
+ */
13725
+
13726
+ /**
13727
+ * COMPONENT commitment definition
13728
+ *
13729
+ * The COMPONENT commitment defines a UI component that the agent can render in the chat.
13730
+ *
13731
+ * @private [🪔] Maybe export the commitments through some package
13732
+ */
13733
+ class ComponentCommitmentDefinition extends BaseCommitmentDefinition {
13734
+ constructor() {
13735
+ super('COMPONENT');
13736
+ }
13737
+ /**
13738
+ * Short one-line description of COMPONENT.
13739
+ */
13740
+ get description() {
13741
+ return 'Define a UI component that the agent can render in the chat.';
13742
+ }
13743
+ /**
13744
+ * Icon for this commitment.
13745
+ */
13746
+ get icon() {
13747
+ return '🧩';
13748
+ }
13749
+ /**
13750
+ * Markdown documentation for COMPONENT commitment.
13751
+ */
13752
+ get documentation() {
13753
+ return spaceTrim$1(`
13754
+ # COMPONENT
13755
+
13756
+ Defines a UI component that the agent can render in the chat.
13757
+
13758
+ ## Key aspects
13759
+
13760
+ - Tells the agent that a specific component is available.
13761
+ - Provides syntax for using the component.
13762
+
13763
+ ## Example
13764
+
13765
+ \`\`\`book
13766
+ COMPONENT Arrow
13767
+ The agent should render an arrow component in the chat UI.
13768
+ Syntax:
13769
+ <Arrow direction="up" color="red" />
13770
+ \`\`\`
13771
+ `);
13772
+ }
13773
+ applyToAgentModelRequirements(requirements, content) {
13774
+ const trimmedContent = content.trim();
13775
+ if (!trimmedContent) {
13776
+ return requirements;
13777
+ }
13778
+ // Add component capability to the system message
13779
+ const componentSection = `Component: ${trimmedContent}`;
13780
+ return this.appendToSystemMessage(requirements, componentSection, '\n\n');
13781
+ }
13782
+ }
13783
+ /**
13784
+ * Note: [💞] Ignore a discrepancy between file name and entity name
13785
+ */
13786
+
13618
13787
  /**
13619
13788
  * DELETE commitment definition
13620
13789
  *
@@ -13820,6 +13989,79 @@ class FormatCommitmentDefinition extends BaseCommitmentDefinition {
13820
13989
  * Note: [💞] Ignore a discrepancy between file name and entity name
13821
13990
  */
13822
13991
 
13992
+ /**
13993
+ * FROM commitment definition
13994
+ *
13995
+ * The FROM commitment tells the agent that its `agentSource` is inherited from another agent.
13996
+ *
13997
+ * Example usage in agent source:
13998
+ *
13999
+ * ```book
14000
+ * FROM https://s6.ptbk.io/benjamin-white
14001
+ * ```
14002
+ *
14003
+ * @private [🪔] Maybe export the commitments through some package
14004
+ */
14005
+ class FromCommitmentDefinition extends BaseCommitmentDefinition {
14006
+ constructor(type = 'FROM') {
14007
+ super(type);
14008
+ }
14009
+ /**
14010
+ * Short one-line description of FROM.
14011
+ */
14012
+ get description() {
14013
+ return 'Inherit agent source from another agent.';
14014
+ }
14015
+ /**
14016
+ * Icon for this commitment.
14017
+ */
14018
+ get icon() {
14019
+ return '🧬';
14020
+ }
14021
+ /**
14022
+ * Markdown documentation for FROM commitment.
14023
+ */
14024
+ get documentation() {
14025
+ return spaceTrim$1(`
14026
+ # ${this.type}
14027
+
14028
+ Inherits agent source from another agent.
14029
+
14030
+ ## Examples
14031
+
14032
+ \`\`\`book
14033
+ My AI Agent
14034
+
14035
+ FROM https://s6.ptbk.io/benjamin-white
14036
+ RULE Speak only in English.
14037
+ \`\`\`
14038
+ `);
14039
+ }
14040
+ applyToAgentModelRequirements(requirements, content) {
14041
+ const trimmedContent = content.trim();
14042
+ if (!trimmedContent) {
14043
+ return requirements;
14044
+ }
14045
+ // Validate URL
14046
+ try {
14047
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
14048
+ const url = new URL(trimmedContent);
14049
+ // TODO: Add more validation if needed (e.g. check for valid protocol)
14050
+ }
14051
+ catch (error) {
14052
+ console.warn(`Invalid URL in FROM commitment: ${trimmedContent}`);
14053
+ return requirements;
14054
+ }
14055
+ return {
14056
+ ...requirements,
14057
+ parentAgentUrl: trimmedContent,
14058
+ };
14059
+ }
14060
+ }
14061
+ /**
14062
+ * Note: [💞] Ignore a discrepancy between file name and entity name
14063
+ */
14064
+
13823
14065
  /**
13824
14066
  * GOAL commitment definition
13825
14067
  *
@@ -14028,6 +14270,77 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
14028
14270
  * Note: [💞] Ignore a discrepancy between file name and entity name
14029
14271
  */
14030
14272
 
14273
+ /**
14274
+ * LANGUAGE commitment definition
14275
+ *
14276
+ * The LANGUAGE/LANGUAGES commitment specifies the language(s) the agent should use in its responses.
14277
+ *
14278
+ * Example usage in agent source:
14279
+ *
14280
+ * ```book
14281
+ * LANGUAGE English
14282
+ * LANGUAGE French, English and Czech
14283
+ * ```
14284
+ *
14285
+ * @private [🪔] Maybe export the commitments through some package
14286
+ */
14287
+ class LanguageCommitmentDefinition extends BaseCommitmentDefinition {
14288
+ constructor(type = 'LANGUAGE') {
14289
+ super(type);
14290
+ }
14291
+ /**
14292
+ * Short one-line description of LANGUAGE/LANGUAGES.
14293
+ */
14294
+ get description() {
14295
+ return 'Specifies the language(s) the agent should use.';
14296
+ }
14297
+ /**
14298
+ * Icon for this commitment.
14299
+ */
14300
+ get icon() {
14301
+ return '🌐';
14302
+ }
14303
+ /**
14304
+ * Markdown documentation for LANGUAGE/LANGUAGES commitment.
14305
+ */
14306
+ get documentation() {
14307
+ return spaceTrim$1(`
14308
+ # ${this.type}
14309
+
14310
+ Specifies the language(s) the agent should use in its responses.
14311
+ This is a specialized variation of the RULE commitment focused on language constraints.
14312
+
14313
+ ## Examples
14314
+
14315
+ \`\`\`book
14316
+ Paul Smith & Associés
14317
+
14318
+ PERSONA You are a company lawyer.
14319
+ LANGUAGE French, English and Czech
14320
+ \`\`\`
14321
+
14322
+ \`\`\`book
14323
+ Customer Support
14324
+
14325
+ PERSONA You are a customer support agent.
14326
+ LANGUAGE English
14327
+ \`\`\`
14328
+ `);
14329
+ }
14330
+ applyToAgentModelRequirements(requirements, content) {
14331
+ const trimmedContent = content.trim();
14332
+ if (!trimmedContent) {
14333
+ return requirements;
14334
+ }
14335
+ // Add language rule to the system message
14336
+ const languageSection = `Language: ${trimmedContent}`;
14337
+ return this.appendToSystemMessage(requirements, languageSection, '\n\n');
14338
+ }
14339
+ }
14340
+ /**
14341
+ * Note: [💞] Ignore a discrepancy between file name and entity name
14342
+ */
14343
+
14031
14344
  /**
14032
14345
  * MEMORY commitment definition
14033
14346
  *
@@ -14612,6 +14925,12 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
14612
14925
  * META COLOR #00ff00
14613
14926
  * ```
14614
14927
  *
14928
+ * You can also specify multiple colors separated by comma:
14929
+ *
14930
+ * ```book
14931
+ * META COLOR #ff0000, #00ff00, #0000ff
14932
+ * ```
14933
+ *
14615
14934
  * @private [🪔] Maybe export the commitments through some package
14616
14935
  */
14617
14936
  class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
@@ -14622,7 +14941,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
14622
14941
  * Short one-line description of META COLOR.
14623
14942
  */
14624
14943
  get description() {
14625
- return "Set the agent's accent color.";
14944
+ return "Set the agent's accent color or gradient.";
14626
14945
  }
14627
14946
  /**
14628
14947
  * Icon for this commitment.
@@ -14637,7 +14956,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
14637
14956
  return spaceTrim$1(`
14638
14957
  # META COLOR
14639
14958
 
14640
- Sets the agent's accent color.
14959
+ Sets the agent's accent color or gradient.
14641
14960
 
14642
14961
  ## Key aspects
14643
14962
 
@@ -14645,6 +14964,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
14645
14964
  - Only one \`META COLOR\` should be used per agent.
14646
14965
  - If multiple are specified, the last one takes precedence.
14647
14966
  - Used for visual representation in user interfaces.
14967
+ - Can specify multiple colors separated by comma to create a gradient.
14648
14968
 
14649
14969
  ## Examples
14650
14970
 
@@ -14661,6 +14981,13 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
14661
14981
  META COLOR #e74c3c
14662
14982
  PERSONA You are a creative and inspiring assistant
14663
14983
  \`\`\`
14984
+
14985
+ \`\`\`book
14986
+ Gradient Agent
14987
+
14988
+ META COLOR #ff0000, #00ff00, #0000ff
14989
+ PERSONA You are a colorful agent
14990
+ \`\`\`
14664
14991
  `);
14665
14992
  }
14666
14993
  applyToAgentModelRequirements(requirements, content) {
@@ -14683,84 +15010,82 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
14683
15010
  */
14684
15011
 
14685
15012
  /**
14686
- * META IMAGE commitment definition
15013
+ * META FONT commitment definition
14687
15014
  *
14688
- * The META IMAGE commitment sets the agent's avatar/profile image URL.
15015
+ * The META FONT commitment sets the agent's font.
14689
15016
  * This commitment is special because it doesn't affect the system message,
14690
15017
  * but is handled separately in the parsing logic.
14691
15018
  *
14692
15019
  * Example usage in agent source:
14693
15020
  *
14694
15021
  * ```book
14695
- * META IMAGE https://example.com/avatar.jpg
14696
- * META IMAGE /assets/agent-avatar.png
15022
+ * META FONT Poppins, Arial, sans-serif
15023
+ * META FONT Roboto
14697
15024
  * ```
14698
15025
  *
14699
15026
  * @private [🪔] Maybe export the commitments through some package
14700
15027
  */
14701
- class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
15028
+ class MetaFontCommitmentDefinition extends BaseCommitmentDefinition {
14702
15029
  constructor() {
14703
- super('META IMAGE', ['IMAGE']);
15030
+ super('META FONT', ['FONT']);
14704
15031
  }
14705
15032
  /**
14706
- * Short one-line description of META IMAGE.
15033
+ * Short one-line description of META FONT.
14707
15034
  */
14708
15035
  get description() {
14709
- return "Set the agent's profile image URL.";
15036
+ return "Set the agent's font.";
14710
15037
  }
14711
15038
  /**
14712
15039
  * Icon for this commitment.
14713
15040
  */
14714
15041
  get icon() {
14715
- return '🖼️';
15042
+ return '🔤';
14716
15043
  }
14717
15044
  /**
14718
- * Markdown documentation for META IMAGE commitment.
15045
+ * Markdown documentation for META FONT commitment.
14719
15046
  */
14720
15047
  get documentation() {
14721
15048
  return spaceTrim$1(`
14722
- # META IMAGE
15049
+ # META FONT
14723
15050
 
14724
- Sets the agent's avatar/profile image URL.
15051
+ Sets the agent's font.
14725
15052
 
14726
15053
  ## Key aspects
14727
15054
 
14728
15055
  - Does not modify the agent's behavior or responses.
14729
- - Only one \`META IMAGE\` should be used per agent.
15056
+ - Only one \`META FONT\` should be used per agent.
14730
15057
  - If multiple are specified, the last one takes precedence.
14731
15058
  - Used for visual representation in user interfaces.
15059
+ - Supports Google Fonts.
14732
15060
 
14733
15061
  ## Examples
14734
15062
 
14735
15063
  \`\`\`book
14736
- Professional Assistant
15064
+ Modern Assistant
14737
15065
 
14738
- META IMAGE https://example.com/professional-avatar.jpg
14739
- PERSONA You are a professional business assistant
14740
- STYLE Maintain a formal and courteous tone
15066
+ META FONT Poppins, Arial, sans-serif
15067
+ PERSONA You are a modern assistant
14741
15068
  \`\`\`
14742
15069
 
14743
15070
  \`\`\`book
14744
- Creative Helper
15071
+ Classic Helper
14745
15072
 
14746
- META IMAGE /assets/creative-bot-avatar.png
14747
- PERSONA You are a creative and inspiring assistant
14748
- STYLE Be enthusiastic and encouraging
14749
- ACTION Can help with brainstorming and ideation
15073
+ META FONT Times New Roman
15074
+ PERSONA You are a classic helper
14750
15075
  \`\`\`
14751
15076
  `);
14752
15077
  }
14753
15078
  applyToAgentModelRequirements(requirements, content) {
14754
- // META IMAGE doesn't modify the system message or model requirements
14755
- // It's handled separately in the parsing logic for profile image extraction
15079
+ // META FONT doesn't modify the system message or model requirements
15080
+ // It's handled separately in the parsing logic
14756
15081
  // This method exists for consistency with the CommitmentDefinition interface
14757
15082
  return requirements;
14758
15083
  }
14759
15084
  /**
14760
- * Extracts the profile image URL from the content
15085
+ * Extracts the font from the content
14761
15086
  * This is used by the parsing logic
14762
15087
  */
14763
- extractProfileImageUrl(content) {
15088
+ extractProfileFont(content) {
14764
15089
  const trimmedContent = content.trim();
14765
15090
  return trimmedContent || null;
14766
15091
  }
@@ -14770,10 +15095,206 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
14770
15095
  */
14771
15096
 
14772
15097
  /**
14773
- * MODEL commitment definition
15098
+ * META IMAGE commitment definition
14774
15099
  *
14775
- * The MODEL commitment specifies which AI model to use and can also set
14776
- * model-specific parameters like temperature, topP, topK, and maxTokens.
15100
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
15101
+ * This commitment is special because it doesn't affect the system message,
15102
+ * but is handled separately in the parsing logic.
15103
+ *
15104
+ * Example usage in agent source:
15105
+ *
15106
+ * ```book
15107
+ * META IMAGE https://example.com/avatar.jpg
15108
+ * META IMAGE /assets/agent-avatar.png
15109
+ * ```
15110
+ *
15111
+ * @private [🪔] Maybe export the commitments through some package
15112
+ */
15113
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
15114
+ constructor() {
15115
+ super('META IMAGE', ['IMAGE']);
15116
+ }
15117
+ /**
15118
+ * Short one-line description of META IMAGE.
15119
+ */
15120
+ get description() {
15121
+ return "Set the agent's profile image URL.";
15122
+ }
15123
+ /**
15124
+ * Icon for this commitment.
15125
+ */
15126
+ get icon() {
15127
+ return '🖼️';
15128
+ }
15129
+ /**
15130
+ * Markdown documentation for META IMAGE commitment.
15131
+ */
15132
+ get documentation() {
15133
+ return spaceTrim$1(`
15134
+ # META IMAGE
15135
+
15136
+ Sets the agent's avatar/profile image URL.
15137
+
15138
+ ## Key aspects
15139
+
15140
+ - Does not modify the agent's behavior or responses.
15141
+ - Only one \`META IMAGE\` should be used per agent.
15142
+ - If multiple are specified, the last one takes precedence.
15143
+ - Used for visual representation in user interfaces.
15144
+
15145
+ ## Examples
15146
+
15147
+ \`\`\`book
15148
+ Professional Assistant
15149
+
15150
+ META IMAGE https://example.com/professional-avatar.jpg
15151
+ PERSONA You are a professional business assistant
15152
+ STYLE Maintain a formal and courteous tone
15153
+ \`\`\`
15154
+
15155
+ \`\`\`book
15156
+ Creative Helper
15157
+
15158
+ META IMAGE /assets/creative-bot-avatar.png
15159
+ PERSONA You are a creative and inspiring assistant
15160
+ STYLE Be enthusiastic and encouraging
15161
+ ACTION Can help with brainstorming and ideation
15162
+ \`\`\`
15163
+ `);
15164
+ }
15165
+ applyToAgentModelRequirements(requirements, content) {
15166
+ // META IMAGE doesn't modify the system message or model requirements
15167
+ // It's handled separately in the parsing logic for profile image extraction
15168
+ // This method exists for consistency with the CommitmentDefinition interface
15169
+ return requirements;
15170
+ }
15171
+ /**
15172
+ * Extracts the profile image URL from the content
15173
+ * This is used by the parsing logic
15174
+ */
15175
+ extractProfileImageUrl(content) {
15176
+ const trimmedContent = content.trim();
15177
+ return trimmedContent || null;
15178
+ }
15179
+ }
15180
+ /**
15181
+ * Note: [💞] Ignore a discrepancy between file name and entity name
15182
+ */
15183
+
15184
+ /**
15185
+ * META LINK commitment definition
15186
+ *
15187
+ * The `META LINK` commitment represents the link to the person from whom the agent is created.
15188
+ * This commitment is special because it doesn't affect the system message,
15189
+ * but is handled separately in the parsing logic for profile display.
15190
+ *
15191
+ * Example usage in agent source:
15192
+ *
15193
+ * ```
15194
+ * META LINK https://twitter.com/username
15195
+ * META LINK https://linkedin.com/in/profile
15196
+ * META LINK https://github.com/username
15197
+ * ```
15198
+ *
15199
+ * Multiple `META LINK` commitments can be used when there are multiple sources:
15200
+ *
15201
+ * ```book
15202
+ * META LINK https://twitter.com/username
15203
+ * META LINK https://linkedin.com/in/profile
15204
+ * ```
15205
+ *
15206
+ * @private [🪔] Maybe export the commitments through some package
15207
+ */
15208
+ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
15209
+ constructor() {
15210
+ super('META LINK');
15211
+ }
15212
+ /**
15213
+ * Short one-line description of META LINK.
15214
+ */
15215
+ get description() {
15216
+ return 'Provide profile/source links for the person the agent models.';
15217
+ }
15218
+ /**
15219
+ * Icon for this commitment.
15220
+ */
15221
+ get icon() {
15222
+ return '🔗';
15223
+ }
15224
+ /**
15225
+ * Markdown documentation for META LINK commitment.
15226
+ */
15227
+ get documentation() {
15228
+ return spaceTrim$1(`
15229
+ # META LINK
15230
+
15231
+ Represents a profile or source link for the person the agent is modeled after.
15232
+
15233
+ ## Key aspects
15234
+
15235
+ - Does not modify the agent's behavior or responses.
15236
+ - Multiple \`META LINK\` commitments can be used for different social profiles.
15237
+ - Used for attribution and crediting the original person.
15238
+ - Displayed in user interfaces for transparency.
15239
+
15240
+ ## Examples
15241
+
15242
+ \`\`\`book
15243
+ Expert Consultant
15244
+
15245
+ META LINK https://twitter.com/expertname
15246
+ META LINK https://linkedin.com/in/expertprofile
15247
+ PERSONA You are Dr. Smith, a renowned expert in artificial intelligence
15248
+ KNOWLEDGE Extensive background in machine learning and neural networks
15249
+ \`\`\`
15250
+
15251
+ \`\`\`book
15252
+ Open Source Developer
15253
+
15254
+ META LINK https://github.com/developer
15255
+ META LINK https://twitter.com/devhandle
15256
+ PERSONA You are an experienced open source developer
15257
+ ACTION Can help with code reviews and architecture decisions
15258
+ STYLE Be direct and technical in explanations
15259
+ \`\`\`
15260
+ `);
15261
+ }
15262
+ applyToAgentModelRequirements(requirements, content) {
15263
+ // META LINK doesn't modify the system message or model requirements
15264
+ // It's handled separately in the parsing logic for profile link extraction
15265
+ // This method exists for consistency with the CommitmentDefinition interface
15266
+ return requirements;
15267
+ }
15268
+ /**
15269
+ * Extracts the profile link URL from the content
15270
+ * This is used by the parsing logic
15271
+ */
15272
+ extractProfileLinkUrl(content) {
15273
+ const trimmedContent = content.trim();
15274
+ return trimmedContent || null;
15275
+ }
15276
+ /**
15277
+ * Validates if the provided content is a valid URL
15278
+ */
15279
+ isValidUrl(content) {
15280
+ try {
15281
+ new URL(content.trim());
15282
+ return true;
15283
+ }
15284
+ catch (_a) {
15285
+ return false;
15286
+ }
15287
+ }
15288
+ }
15289
+ /**
15290
+ * Note: [💞] Ignore a discrepancy between file name and entity name
15291
+ */
15292
+
15293
+ /**
15294
+ * MODEL commitment definition
15295
+ *
15296
+ * The MODEL commitment specifies which AI model to use and can also set
15297
+ * model-specific parameters like temperature, topP, topK, and maxTokens.
14777
15298
  *
14778
15299
  * Supports multiple syntax variations:
14779
15300
  *
@@ -15120,6 +15641,74 @@ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
15120
15641
  * [💞] Ignore a discrepancy between file name and entity name
15121
15642
  */
15122
15643
 
15644
+ /**
15645
+ * OPEN commitment definition
15646
+ *
15647
+ * The OPEN commitment specifies that the agent can be modified by conversation.
15648
+ * This is the default behavior.
15649
+ *
15650
+ * Example usage in agent source:
15651
+ *
15652
+ * ```book
15653
+ * OPEN
15654
+ * ```
15655
+ *
15656
+ * @private [🪔] Maybe export the commitments through some package
15657
+ */
15658
+ class OpenCommitmentDefinition extends BaseCommitmentDefinition {
15659
+ constructor() {
15660
+ super('OPEN');
15661
+ }
15662
+ /**
15663
+ * Short one-line description of OPEN.
15664
+ */
15665
+ get description() {
15666
+ return 'Allow the agent to be modified by conversation (default).';
15667
+ }
15668
+ /**
15669
+ * Icon for this commitment.
15670
+ */
15671
+ get icon() {
15672
+ return '🔓';
15673
+ }
15674
+ /**
15675
+ * Markdown documentation for OPEN commitment.
15676
+ */
15677
+ get documentation() {
15678
+ return spaceTrim$1(`
15679
+ # OPEN
15680
+
15681
+ Specifies that the agent can be modified by conversation with it.
15682
+ This means the agent will learn from interactions and update its source code.
15683
+
15684
+ This is the default behavior if neither \`OPEN\` nor \`CLOSED\` is specified.
15685
+
15686
+ > See also [CLOSED](/docs/CLOSED)
15687
+
15688
+ ## Example
15689
+
15690
+ \`\`\`book
15691
+ OPEN
15692
+ \`\`\`
15693
+ `);
15694
+ }
15695
+ applyToAgentModelRequirements(requirements, _content) {
15696
+ // Since OPEN is default, we can just ensure isClosed is false
15697
+ // But to be explicit we can set it
15698
+ const updatedMetadata = {
15699
+ ...requirements.metadata,
15700
+ isClosed: false,
15701
+ };
15702
+ return {
15703
+ ...requirements,
15704
+ metadata: updatedMetadata,
15705
+ };
15706
+ }
15707
+ }
15708
+ /**
15709
+ * Note: [💞] Ignore a discrepancy between file name and entity name
15710
+ */
15711
+
15123
15712
  /**
15124
15713
  * PERSONA commitment definition
15125
15714
  *
@@ -15630,6 +16219,389 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
15630
16219
  * [💞] Ignore a discrepancy between file name and entity name
15631
16220
  */
15632
16221
 
16222
+ /**
16223
+ * USE commitment definition
16224
+ *
16225
+ * The USE commitment indicates that the agent should utilize specific tools or capabilities
16226
+ * to access and interact with external systems when necessary.
16227
+ *
16228
+ * Supported USE types:
16229
+ * - USE BROWSER: Enables the agent to use a web browser tool
16230
+ * - USE SEARCH ENGINE (future): Enables search engine access
16231
+ * - USE FILE SYSTEM (future): Enables file system operations
16232
+ * - USE MCP (future): Enables MCP server connections
16233
+ *
16234
+ * The content following the USE commitment is ignored (similar to NOTE).
16235
+ *
16236
+ * Example usage in agent source:
16237
+ *
16238
+ * ```book
16239
+ * USE BROWSER
16240
+ * USE SEARCH ENGINE
16241
+ * ```
16242
+ *
16243
+ * @private [🪔] Maybe export the commitments through some package
16244
+ */
16245
+ class UseCommitmentDefinition extends BaseCommitmentDefinition {
16246
+ constructor() {
16247
+ super('USE');
16248
+ }
16249
+ /**
16250
+ * Short one-line description of USE commitments.
16251
+ */
16252
+ get description() {
16253
+ return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, etc.).';
16254
+ }
16255
+ /**
16256
+ * Icon for this commitment.
16257
+ */
16258
+ get icon() {
16259
+ return '🔧';
16260
+ }
16261
+ /**
16262
+ * Markdown documentation for USE commitment.
16263
+ */
16264
+ get documentation() {
16265
+ return spaceTrim$1(`
16266
+ # USE
16267
+
16268
+ Enables the agent to use specific tools or capabilities for interacting with external systems.
16269
+
16270
+ ## Supported USE types
16271
+
16272
+ - **USE BROWSER** - Enables the agent to use a web browser tool to access and retrieve information from the internet
16273
+ - **USE SEARCH ENGINE** (future) - Enables search engine access
16274
+ - **USE FILE SYSTEM** (future) - Enables file system operations
16275
+ - **USE MCP** (future) - Enables MCP server connections
16276
+
16277
+ ## Key aspects
16278
+
16279
+ - The content following the USE commitment is ignored (similar to NOTE)
16280
+ - Multiple USE commitments can be specified to enable multiple capabilities
16281
+ - The actual tool usage is handled by the agent runtime
16282
+
16283
+ ## Examples
16284
+
16285
+ ### Basic browser usage
16286
+
16287
+ \`\`\`book
16288
+ Research Assistant
16289
+
16290
+ PERSONA You are a helpful research assistant
16291
+ USE BROWSER
16292
+ KNOWLEDGE Can search the web for up-to-date information
16293
+ \`\`\`
16294
+
16295
+ ### Multiple tools
16296
+
16297
+ \`\`\`book
16298
+ Data Analyst
16299
+
16300
+ PERSONA You are a data analyst assistant
16301
+ USE BROWSER
16302
+ USE FILE SYSTEM
16303
+ ACTION Can analyze data from various sources
16304
+ \`\`\`
16305
+ `);
16306
+ }
16307
+ applyToAgentModelRequirements(requirements, content) {
16308
+ // USE commitments don't modify the system message or model requirements directly
16309
+ // They are handled separately in the parsing logic for capability extraction
16310
+ // This method exists for consistency with the CommitmentDefinition interface
16311
+ return requirements;
16312
+ }
16313
+ /**
16314
+ * Extracts the tool type from the USE commitment
16315
+ * This is used by the parsing logic
16316
+ */
16317
+ extractToolType(content) {
16318
+ var _a, _b;
16319
+ const trimmedContent = content.trim();
16320
+ // The tool type is the first word after USE (already stripped)
16321
+ const match = trimmedContent.match(/^(\w+)/);
16322
+ return (_b = (_a = match === null || match === void 0 ? void 0 : match[1]) === null || _a === void 0 ? void 0 : _a.toUpperCase()) !== null && _b !== void 0 ? _b : null;
16323
+ }
16324
+ /**
16325
+ * Checks if this is a known USE type
16326
+ */
16327
+ isKnownUseType(useType) {
16328
+ const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'FILE SYSTEM', 'MCP'];
16329
+ return knownTypes.includes(useType.toUpperCase());
16330
+ }
16331
+ }
16332
+ /**
16333
+ * Note: [💞] Ignore a discrepancy between file name and entity name
16334
+ */
16335
+
16336
+ /**
16337
+ * USE BROWSER commitment definition
16338
+ *
16339
+ * The `USE BROWSER` commitment indicates that the agent should utilize a web browser tool
16340
+ * to access and retrieve up-to-date information from the internet when necessary.
16341
+ *
16342
+ * The content following `USE BROWSER` is ignored (similar to NOTE).
16343
+ *
16344
+ * Example usage in agent source:
16345
+ *
16346
+ * ```book
16347
+ * USE BROWSER
16348
+ * USE BROWSER This will be ignored
16349
+ * ```
16350
+ *
16351
+ * @private [🪔] Maybe export the commitments through some package
16352
+ */
16353
+ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
16354
+ constructor() {
16355
+ super('USE BROWSER', ['BROWSER']);
16356
+ }
16357
+ /**
16358
+ * Short one-line description of USE BROWSER.
16359
+ */
16360
+ get description() {
16361
+ return 'Enable the agent to use a web browser tool for accessing internet information.';
16362
+ }
16363
+ /**
16364
+ * Icon for this commitment.
16365
+ */
16366
+ get icon() {
16367
+ return '🌐';
16368
+ }
16369
+ /**
16370
+ * Markdown documentation for USE BROWSER commitment.
16371
+ */
16372
+ get documentation() {
16373
+ return spaceTrim$1(`
16374
+ # USE BROWSER
16375
+
16376
+ Enables the agent to use a web browser tool to access and retrieve up-to-date information from the internet.
16377
+
16378
+ ## Key aspects
16379
+
16380
+ - The content following \`USE BROWSER\` is ignored (similar to NOTE)
16381
+ - The actual browser tool usage is handled by the agent runtime
16382
+ - Allows the agent to fetch current information from websites
16383
+ - Useful for research tasks, fact-checking, and accessing dynamic content
16384
+
16385
+ ## Examples
16386
+
16387
+ \`\`\`book
16388
+ Research Assistant
16389
+
16390
+ PERSONA You are a helpful research assistant specialized in finding current information
16391
+ USE BROWSER
16392
+ RULE Always cite your sources when providing information from the web
16393
+ \`\`\`
16394
+
16395
+ \`\`\`book
16396
+ News Analyst
16397
+
16398
+ PERSONA You are a news analyst who stays up-to-date with current events
16399
+ USE BROWSER
16400
+ STYLE Present news in a balanced and objective manner
16401
+ ACTION Can search for and summarize news articles
16402
+ \`\`\`
16403
+
16404
+ \`\`\`book
16405
+ Company Lawyer
16406
+
16407
+ PERSONA You are a company lawyer providing legal advice
16408
+ USE BROWSER
16409
+ KNOWLEDGE Corporate law and legal procedures
16410
+ RULE Always recommend consulting with a licensed attorney for specific legal matters
16411
+ \`\`\`
16412
+ `);
16413
+ }
16414
+ applyToAgentModelRequirements(requirements, content) {
16415
+ // We simply mark that browser capability is enabled in metadata
16416
+ // Get existing metadata
16417
+ const existingMetadata = requirements.metadata || {};
16418
+ // Get existing tools array or create new one
16419
+ const existingTools = existingMetadata.tools || [];
16420
+ // Add 'browser' to tools if not already present
16421
+ const updatedTools = existingTools.includes('browser') ? existingTools : [...existingTools, 'browser'];
16422
+ // Return requirements with updated metadata
16423
+ return {
16424
+ ...requirements,
16425
+ metadata: {
16426
+ ...existingMetadata,
16427
+ tools: updatedTools,
16428
+ useBrowser: true,
16429
+ },
16430
+ };
16431
+ }
16432
+ }
16433
+ /**
16434
+ * Note: [💞] Ignore a discrepancy between file name and entity name
16435
+ */
16436
+
16437
+ /**
16438
+ * USE MCP commitment definition
16439
+ *
16440
+ * The `USE MCP` commitment allows to specify an MCP server URL which the agent will connect to
16441
+ * for retrieving additional instructions and actions.
16442
+ *
16443
+ * The content following `USE MCP` is the URL of the MCP server.
16444
+ *
16445
+ * Example usage in agent source:
16446
+ *
16447
+ * ```book
16448
+ * USE MCP http://mcp-server-url.com
16449
+ * ```
16450
+ *
16451
+ * @private [🪔] Maybe export the commitments through some package
16452
+ */
16453
+ class UseMcpCommitmentDefinition extends BaseCommitmentDefinition {
16454
+ constructor() {
16455
+ super('USE MCP', ['MCP']);
16456
+ }
16457
+ /**
16458
+ * Short one-line description of USE MCP.
16459
+ */
16460
+ get description() {
16461
+ return 'Connects the agent to an external MCP server for additional capabilities.';
16462
+ }
16463
+ /**
16464
+ * Icon for this commitment.
16465
+ */
16466
+ get icon() {
16467
+ return '🔌';
16468
+ }
16469
+ /**
16470
+ * Markdown documentation for USE MCP commitment.
16471
+ */
16472
+ get documentation() {
16473
+ return spaceTrim$1(`
16474
+ # USE MCP
16475
+
16476
+ Connects the agent to an external Model Context Protocol (MCP) server.
16477
+
16478
+ ## Key aspects
16479
+
16480
+ - The content following \`USE MCP\` must be a valid URL
16481
+ - Multiple MCP servers can be connected by using multiple \`USE MCP\` commitments
16482
+ - The agent will have access to tools and resources provided by the MCP server
16483
+
16484
+ ## Example
16485
+
16486
+ \`\`\`book
16487
+ Company Lawyer
16488
+
16489
+ PERSONA You are a company lawyer.
16490
+ USE MCP http://legal-db.example.com
16491
+ \`\`\`
16492
+ `);
16493
+ }
16494
+ applyToAgentModelRequirements(requirements, content) {
16495
+ const mcpServerUrl = content.trim();
16496
+ if (!mcpServerUrl) {
16497
+ return requirements;
16498
+ }
16499
+ const existingMcpServers = requirements.mcpServers || [];
16500
+ // Avoid duplicates
16501
+ if (existingMcpServers.includes(mcpServerUrl)) {
16502
+ return requirements;
16503
+ }
16504
+ return {
16505
+ ...requirements,
16506
+ mcpServers: [...existingMcpServers, mcpServerUrl],
16507
+ };
16508
+ }
16509
+ }
16510
+ /**
16511
+ * Note: [💞] Ignore a discrepancy between file name and entity name
16512
+ */
16513
+
16514
+ /**
16515
+ * USE SEARCH ENGINE commitment definition
16516
+ *
16517
+ * The `USE SEARCH ENGINE` commitment indicates that the agent should utilize a search engine tool
16518
+ * to access and retrieve up-to-date information from the internet when necessary.
16519
+ *
16520
+ * The content following `USE SEARCH ENGINE` is ignored (similar to NOTE).
16521
+ *
16522
+ * Example usage in agent source:
16523
+ *
16524
+ * ```book
16525
+ * USE SEARCH ENGINE
16526
+ * USE SEARCH ENGINE This will be ignored
16527
+ * ```
16528
+ *
16529
+ * @private [🪔] Maybe export the commitments through some package
16530
+ */
16531
+ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
16532
+ constructor() {
16533
+ super('USE SEARCH ENGINE', ['SEARCH ENGINE', 'SEARCH']);
16534
+ }
16535
+ /**
16536
+ * Short one-line description of USE SEARCH ENGINE.
16537
+ */
16538
+ get description() {
16539
+ return 'Enable the agent to use a search engine tool for accessing internet information.';
16540
+ }
16541
+ /**
16542
+ * Icon for this commitment.
16543
+ */
16544
+ get icon() {
16545
+ return '🔍';
16546
+ }
16547
+ /**
16548
+ * Markdown documentation for USE SEARCH ENGINE commitment.
16549
+ */
16550
+ get documentation() {
16551
+ return spaceTrim$1(`
16552
+ # USE SEARCH ENGINE
16553
+
16554
+ Enables the agent to use a search engine tool to access and retrieve up-to-date information from the internet.
16555
+
16556
+ ## Key aspects
16557
+
16558
+ - The content following \`USE SEARCH ENGINE\` is ignored (similar to NOTE)
16559
+ - The actual search engine tool usage is handled by the agent runtime
16560
+ - Allows the agent to search for current information from the web
16561
+ - Useful for research tasks, finding facts, and accessing dynamic content
16562
+
16563
+ ## Examples
16564
+
16565
+ \`\`\`book
16566
+ Research Assistant
16567
+
16568
+ PERSONA You are a helpful research assistant specialized in finding current information
16569
+ USE SEARCH ENGINE
16570
+ RULE Always cite your sources when providing information from the web
16571
+ \`\`\`
16572
+
16573
+ \`\`\`book
16574
+ Fact Checker
16575
+
16576
+ PERSONA You are a fact checker
16577
+ USE SEARCH ENGINE
16578
+ ACTION Search for claims and verify them against reliable sources
16579
+ \`\`\`
16580
+ `);
16581
+ }
16582
+ applyToAgentModelRequirements(requirements, content) {
16583
+ // We simply mark that search engine capability is enabled in metadata
16584
+ // Get existing metadata
16585
+ const existingMetadata = requirements.metadata || {};
16586
+ // Get existing tools array or create new one
16587
+ const existingTools = existingMetadata.tools || [];
16588
+ // Add 'search-engine' to tools if not already present
16589
+ const updatedTools = existingTools.includes('search-engine') ? existingTools : [...existingTools, 'search-engine'];
16590
+ // Return requirements with updated metadata
16591
+ return {
16592
+ ...requirements,
16593
+ metadata: {
16594
+ ...existingMetadata,
16595
+ tools: updatedTools,
16596
+ useSearchEngine: true,
16597
+ },
16598
+ };
16599
+ }
16600
+ }
16601
+ /**
16602
+ * Note: [💞] Ignore a discrepancy between file name and entity name
16603
+ */
16604
+
15633
16605
  /**
15634
16606
  * Placeholder commitment definition for commitments that are not yet implemented
15635
16607
  *
@@ -15716,16 +16688,22 @@ const COMMITMENT_REGISTRY = [
15716
16688
  new StyleCommitmentDefinition('STYLES'),
15717
16689
  new RuleCommitmentDefinition('RULE'),
15718
16690
  new RuleCommitmentDefinition('RULES'),
16691
+ new LanguageCommitmentDefinition('LANGUAGE'),
16692
+ new LanguageCommitmentDefinition('LANGUAGES'),
15719
16693
  new SampleCommitmentDefinition('SAMPLE'),
15720
16694
  new SampleCommitmentDefinition('EXAMPLE'),
15721
16695
  new FormatCommitmentDefinition('FORMAT'),
15722
16696
  new FormatCommitmentDefinition('FORMATS'),
16697
+ new FromCommitmentDefinition('FROM'),
15723
16698
  new ModelCommitmentDefinition('MODEL'),
15724
16699
  new ModelCommitmentDefinition('MODELS'),
15725
16700
  new ActionCommitmentDefinition('ACTION'),
15726
16701
  new ActionCommitmentDefinition('ACTIONS'),
16702
+ new ComponentCommitmentDefinition(),
15727
16703
  new MetaImageCommitmentDefinition(),
15728
16704
  new MetaColorCommitmentDefinition(),
16705
+ new MetaFontCommitmentDefinition(),
16706
+ new MetaLinkCommitmentDefinition(),
15729
16707
  new MetaCommitmentDefinition(),
15730
16708
  new NoteCommitmentDefinition('NOTE'),
15731
16709
  new NoteCommitmentDefinition('NOTES'),
@@ -15744,6 +16722,12 @@ const COMMITMENT_REGISTRY = [
15744
16722
  new DeleteCommitmentDefinition('CANCEL'),
15745
16723
  new DeleteCommitmentDefinition('DISCARD'),
15746
16724
  new DeleteCommitmentDefinition('REMOVE'),
16725
+ new OpenCommitmentDefinition(),
16726
+ new ClosedCommitmentDefinition(),
16727
+ new UseBrowserCommitmentDefinition(),
16728
+ new UseSearchEngineCommitmentDefinition(),
16729
+ new UseMcpCommitmentDefinition(),
16730
+ new UseCommitmentDefinition(),
15747
16731
  // Not yet implemented commitments (using placeholder)
15748
16732
  new NotYetImplementedCommitmentDefinition('EXPECT'),
15749
16733
  new NotYetImplementedCommitmentDefinition('BEHAVIOUR'),
@@ -15801,6 +16785,11 @@ function createBasicAgentModelRequirements(agentName) {
15801
16785
  * TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
15802
16786
  */
15803
16787
 
16788
+ /**
16789
+ * Regex pattern to match horizontal lines (markdown thematic breaks)
16790
+ * Matches 3 or more hyphens, underscores, or asterisks (with optional spaces between)
16791
+ */
16792
+ const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
15804
16793
  /**
15805
16794
  * Parses agent source using the new commitment system with multiline support
15806
16795
  * This function replaces the hardcoded commitment parsing in the original parseAgentSource
@@ -15863,6 +16852,24 @@ function parseAgentSourceWithCommitments(agentSource) {
15863
16852
  break;
15864
16853
  }
15865
16854
  }
16855
+ // Check if this is a horizontal line (ends any current commitment)
16856
+ const isHorizontalLine = HORIZONTAL_LINE_PATTERN.test(line);
16857
+ if (isHorizontalLine) {
16858
+ // Save the current commitment if it exists
16859
+ if (currentCommitment) {
16860
+ const fullContent = currentCommitment.contentLines.join('\n');
16861
+ commitments.push({
16862
+ type: currentCommitment.type,
16863
+ content: spaceTrim$1(fullContent),
16864
+ originalLine: currentCommitment.originalStartLine,
16865
+ lineNumber: currentCommitment.startLineNumber,
16866
+ });
16867
+ currentCommitment = null;
16868
+ }
16869
+ // Add horizontal line to non-commitment lines
16870
+ nonCommitmentLines.push(line);
16871
+ continue;
16872
+ }
15866
16873
  if (!foundNewCommitment) {
15867
16874
  if (currentCommitment) {
15868
16875
  // This line belongs to the current commitment
@@ -16168,7 +17175,7 @@ function generatePlaceholderAgentProfileImageUrl(agentName) {
16168
17175
  * @public exported from `@promptbook/utils`
16169
17176
  */
16170
17177
  function computeHash(value) {
16171
- return SHA256(hexEncoder.parse(spaceTrim(valueToString(value)))).toString( /* hex */);
17178
+ return SHA256(hexEncoder.parse(spaceTrim$2(valueToString(value)))).toString( /* hex */);
16172
17179
  }
16173
17180
  /**
16174
17181
  * TODO: [🥬][🥬] Use this ACRY
@@ -16506,7 +17513,7 @@ function isValidJavascriptName(javascriptName) {
16506
17513
  * @public exported from `@promptbook/core`
16507
17514
  */
16508
17515
  function normalizeAgentName(rawAgentName) {
16509
- return titleToName(spaceTrim(rawAgentName));
17516
+ return titleToName(spaceTrim$2(rawAgentName));
16510
17517
  }
16511
17518
 
16512
17519
  /**
@@ -16558,15 +17565,21 @@ function parseAgentSource(agentSource) {
16558
17565
  const links = [];
16559
17566
  for (const commitment of parseResult.commitments) {
16560
17567
  if (commitment.type === 'META LINK') {
16561
- links.push(spaceTrim(commitment.content));
17568
+ const linkValue = spaceTrim$2(commitment.content);
17569
+ links.push(linkValue);
17570
+ meta.link = linkValue;
16562
17571
  continue;
16563
17572
  }
16564
17573
  if (commitment.type === 'META IMAGE') {
16565
- meta.image = spaceTrim(commitment.content);
17574
+ meta.image = spaceTrim$2(commitment.content);
16566
17575
  continue;
16567
17576
  }
16568
17577
  if (commitment.type === 'META COLOR') {
16569
- meta.color = spaceTrim(commitment.content);
17578
+ meta.color = spaceTrim$2(commitment.content);
17579
+ continue;
17580
+ }
17581
+ if (commitment.type === 'META FONT') {
17582
+ meta.font = spaceTrim$2(commitment.content);
16570
17583
  continue;
16571
17584
  }
16572
17585
  if (commitment.type !== 'META') {
@@ -16575,10 +17588,10 @@ function parseAgentSource(agentSource) {
16575
17588
  // Parse META commitments - format is "META TYPE content"
16576
17589
  const metaTypeRaw = commitment.content.split(' ')[0] || 'NONE';
16577
17590
  if (metaTypeRaw === 'LINK') {
16578
- links.push(spaceTrim(commitment.content.substring(metaTypeRaw.length)));
17591
+ links.push(spaceTrim$2(commitment.content.substring(metaTypeRaw.length)));
16579
17592
  }
16580
17593
  const metaType = normalizeTo_camelCase(metaTypeRaw);
16581
- meta[metaType] = spaceTrim(commitment.content.substring(metaTypeRaw.length));
17594
+ meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
16582
17595
  }
16583
17596
  // Generate gravatar fallback if no meta image specified
16584
17597
  if (!meta.image) {
@@ -16730,7 +17743,7 @@ const OpenAiSdkTranspiler = {
16730
17743
  });
16731
17744
  const KNOWLEDGE_THRESHOLD = 1000;
16732
17745
  if (directKnowledge.join('\n').length > KNOWLEDGE_THRESHOLD || knowledgeSources.length > 0) {
16733
- return spaceTrim((block) => `
17746
+ return spaceTrim$2((block) => `
16734
17747
  #!/usr/bin/env node
16735
17748
 
16736
17749
  import * as dotenv from 'dotenv';
@@ -16795,7 +17808,7 @@ const OpenAiSdkTranspiler = {
16795
17808
  }
16796
17809
 
16797
17810
  const userMessage = spaceTrim(\`
16798
- ${block(spaceTrim(`
17811
+ ${block(spaceTrim$2(`
16799
17812
  Here is some additional context to help you answer the question:
16800
17813
  \${context}
16801
17814
 
@@ -16840,7 +17853,7 @@ const OpenAiSdkTranspiler = {
16840
17853
  })();
16841
17854
  `);
16842
17855
  }
16843
- const source = spaceTrim((block) => `
17856
+ const source = spaceTrim$2((block) => `
16844
17857
 
16845
17858
  #!/usr/bin/env node
16846
17859
 
@@ -17251,13 +18264,13 @@ function $registeredLlmToolsMessage() {
17251
18264
  });
17252
18265
  const usedEnvMessage = $usedEnvFilename === null ? `Unknown \`.env\` file` : `Used \`.env\` file:\n${$usedEnvFilename}`;
17253
18266
  if (metadata.length === 0) {
17254
- return spaceTrim((block) => `
18267
+ return spaceTrim$2((block) => `
17255
18268
  No LLM providers are available.
17256
18269
 
17257
18270
  ${block(usedEnvMessage)}
17258
18271
  `);
17259
18272
  }
17260
- return spaceTrim((block) => `
18273
+ return spaceTrim$2((block) => `
17261
18274
 
17262
18275
  ${block(usedEnvMessage)}
17263
18276
 
@@ -17303,7 +18316,7 @@ function $registeredLlmToolsMessage() {
17303
18316
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
17304
18317
  }
17305
18318
  }
17306
- let providerMessage = spaceTrim(`
18319
+ let providerMessage = spaceTrim$2(`
17307
18320
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
17308
18321
  ${morePieces.join('; ')}
17309
18322
  `);
@@ -17437,7 +18450,7 @@ class $EnvStorage {
17437
18450
  .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
17438
18451
  .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
17439
18452
  .join('\n');
17440
- const newEnvContent = spaceTrim((block) => `
18453
+ const newEnvContent = spaceTrim$2((block) => `
17441
18454
  ${block(updatedEnvContent)}
17442
18455
 
17443
18456
  # ${GENERATOR_WARNING_IN_ENV}
@@ -17466,7 +18479,7 @@ class $EnvStorage {
17466
18479
  */
17467
18480
  function stringifyPipelineJson(pipeline) {
17468
18481
  if (!isSerializableAsJson(pipeline)) {
17469
- throw new UnexpectedError(spaceTrim(`
18482
+ throw new UnexpectedError(spaceTrim$2(`
17470
18483
  Cannot stringify the pipeline, because it is not serializable as JSON
17471
18484
 
17472
18485
  There can be multiple reasons:
@@ -17666,7 +18679,7 @@ function cacheLlmTools(llmTools, options = {}) {
17666
18679
  let normalizedContent = content;
17667
18680
  normalizedContent = normalizedContent.replace(/\s+/g, ' ');
17668
18681
  normalizedContent = normalizedContent.split('\r\n').join('\n');
17669
- normalizedContent = spaceTrim(normalizedContent);
18682
+ normalizedContent = spaceTrim$2(normalizedContent);
17670
18683
  // Note: Do not need to save everything in the cache, just the relevant parameters
17671
18684
  const relevantParameterNames = extractParameterNames(content);
17672
18685
  const relevantParameters = Object.fromEntries(Object.entries(parameters).filter(([key]) => relevantParameterNames.has(key)));
@@ -17855,7 +18868,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
17855
18868
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
17856
18869
  if (registeredItem === undefined) {
17857
18870
  // console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
17858
- throw new Error(spaceTrim((block) => `
18871
+ throw new Error(spaceTrim$2((block) => `
17859
18872
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
17860
18873
  Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
17861
18874
 
@@ -17923,14 +18936,14 @@ async function $provideLlmToolsFromEnv(options = {}) {
17923
18936
  const configuration = await $provideLlmToolsConfigurationFromEnv();
17924
18937
  if (configuration.length === 0) {
17925
18938
  if ($llmToolsMetadataRegister.list().length === 0) {
17926
- throw new UnexpectedError(spaceTrim((block) => `
18939
+ throw new UnexpectedError(spaceTrim$2((block) => `
17927
18940
  No LLM tools registered, this is probably a bug in the Promptbook library
17928
18941
 
17929
18942
  ${block($registeredLlmToolsMessage())}}
17930
18943
  `));
17931
18944
  }
17932
18945
  // TODO: [🥃]
17933
- throw new Error(spaceTrim((block) => `
18946
+ throw new Error(spaceTrim$2((block) => `
17934
18947
  No LLM tools found in the environment
17935
18948
 
17936
18949
  ${block($registeredLlmToolsMessage())}}
@@ -18068,7 +19081,7 @@ async function $provideScrapersForNode(tools, options) {
18068
19081
  function extractOneBlockFromMarkdown(markdown) {
18069
19082
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
18070
19083
  if (codeBlocks.length !== 1) {
18071
- throw new ParseError(spaceTrim((block) => `
19084
+ throw new ParseError(spaceTrim$2((block) => `
18072
19085
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
18073
19086
 
18074
19087
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -18177,8 +19190,8 @@ class JavascriptEvalExecutionTools {
18177
19190
  }
18178
19191
  // Note: [💎]
18179
19192
  // Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
18180
- const spaceTrim$1 = (_) => spaceTrim(_);
18181
- $preserve(spaceTrim$1);
19193
+ const spaceTrim = (_) => spaceTrim$2(_);
19194
+ $preserve(spaceTrim);
18182
19195
  const removeQuotes$1 = removeQuotes;
18183
19196
  $preserve(removeQuotes$1);
18184
19197
  const unwrapResult$1 = unwrapResult;
@@ -18231,7 +19244,7 @@ class JavascriptEvalExecutionTools {
18231
19244
  // TODO: DRY [🍯]
18232
19245
  const buildinFunctions = {
18233
19246
  // TODO: [🍯] DRY all these functions across the file
18234
- spaceTrim: spaceTrim$1,
19247
+ spaceTrim,
18235
19248
  removeQuotes: removeQuotes$1,
18236
19249
  unwrapResult: unwrapResult$1,
18237
19250
  trimEndOfCodeBlock: trimEndOfCodeBlock$1,
@@ -18268,7 +19281,7 @@ class JavascriptEvalExecutionTools {
18268
19281
  .join('\n');
18269
19282
  // script = templateParameters(script, parameters);
18270
19283
  // <- TODO: [🧠][🥳] Should be this is one of two variants how to use parameters in script
18271
- const statementToEvaluate = spaceTrim((block) => `
19284
+ const statementToEvaluate = spaceTrim$2((block) => `
18272
19285
 
18273
19286
  // Build-in functions:
18274
19287
  ${block(buildinFunctionsStatement)}
@@ -18283,7 +19296,7 @@ class JavascriptEvalExecutionTools {
18283
19296
  (()=>{ ${script} })()
18284
19297
  `);
18285
19298
  if (this.options.isVerbose) {
18286
- console.info(spaceTrim((block) => `
19299
+ console.info(spaceTrim$2((block) => `
18287
19300
  🚀 Evaluating ${scriptLanguage} script:
18288
19301
 
18289
19302
  ${block(statementToEvaluate)}`));
@@ -18305,7 +19318,7 @@ class JavascriptEvalExecutionTools {
18305
19318
  To: [PipelineExecutionError: Parameter `{thing}` is not defined],
18306
19319
  */
18307
19320
  if (!statementToEvaluate.includes(undefinedName + '(')) {
18308
- throw new PipelineExecutionError(spaceTrim((block) => `
19321
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
18309
19322
 
18310
19323
  Parameter \`{${undefinedName}}\` is not defined
18311
19324
 
@@ -18327,7 +19340,7 @@ class JavascriptEvalExecutionTools {
18327
19340
  `));
18328
19341
  }
18329
19342
  else {
18330
- throw new PipelineExecutionError(spaceTrim((block) => `
19343
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
18331
19344
  Function ${undefinedName}() is not defined
18332
19345
 
18333
19346
  - Make sure that the function is one of built-in functions
@@ -18466,7 +19479,7 @@ const knowledgeCommandParser = {
18466
19479
  */
18467
19480
  parse(input) {
18468
19481
  const { args } = input;
18469
- const knowledgeSourceContent = spaceTrim(args[0] || '');
19482
+ const knowledgeSourceContent = spaceTrim$2(args[0] || '');
18470
19483
  if (knowledgeSourceContent === '') {
18471
19484
  throw new ParseError(`Source is not defined`);
18472
19485
  }
@@ -18610,7 +19623,7 @@ const sectionCommandParser = {
18610
19623
  normalized = normalized.split('DIALOGUE').join('DIALOG');
18611
19624
  const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
18612
19625
  if (taskTypes.length !== 1) {
18613
- throw new ParseError(spaceTrim((block) => `
19626
+ throw new ParseError(spaceTrim$2((block) => `
18614
19627
  Unknown section type "${normalized}"
18615
19628
 
18616
19629
  Supported section types are:
@@ -18630,7 +19643,7 @@ const sectionCommandParser = {
18630
19643
  */
18631
19644
  $applyToTaskJson(command, $taskJson, $pipelineJson) {
18632
19645
  if ($taskJson.isSectionTypeSet === true) {
18633
- throw new ParseError(spaceTrim(`
19646
+ throw new ParseError(spaceTrim$2(`
18634
19647
  Section type is already defined in the section.
18635
19648
  It can be defined only once.
18636
19649
  `));
@@ -18910,7 +19923,7 @@ const expectCommandParser = {
18910
19923
  /**
18911
19924
  * Description of the FORMAT command
18912
19925
  */
18913
- description: spaceTrim(`
19926
+ description: spaceTrim$2(`
18914
19927
  Expect command describes the desired output of the task *(after post-processing)*
18915
19928
  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.
18916
19929
  `),
@@ -18984,7 +19997,7 @@ const expectCommandParser = {
18984
19997
  }
18985
19998
  catch (error) {
18986
19999
  assertsError(error);
18987
- throw new ParseError(spaceTrim((block) => `
20000
+ throw new ParseError(spaceTrim$2((block) => `
18988
20001
  Invalid FORMAT command
18989
20002
  ${block(error.message)}:
18990
20003
  `));
@@ -19096,7 +20109,7 @@ function validateParameterName(parameterName) {
19096
20109
  if (!(error instanceof ParseError)) {
19097
20110
  throw error;
19098
20111
  }
19099
- throw new ParseError(spaceTrim((block) => `
20112
+ throw new ParseError(spaceTrim$2((block) => `
19100
20113
  ${block(error.message)}
19101
20114
 
19102
20115
  Tried to validate parameter name:
@@ -19155,7 +20168,7 @@ const foreachCommandParser = {
19155
20168
  const assignSign = args[3];
19156
20169
  const formatDefinition = FORMAT_DEFINITIONS.find((formatDefinition) => [formatDefinition.formatName, ...(formatDefinition.aliases || [])].includes(formatName));
19157
20170
  if (formatDefinition === undefined) {
19158
- throw new ParseError(spaceTrim((block) => `
20171
+ throw new ParseError(spaceTrim$2((block) => `
19159
20172
  Unsupported format "${formatName}"
19160
20173
 
19161
20174
  Available formats:
@@ -19167,7 +20180,7 @@ const foreachCommandParser = {
19167
20180
  }
19168
20181
  const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(subformatName));
19169
20182
  if (subvalueParser === undefined) {
19170
- throw new ParseError(spaceTrim((block) => `
20183
+ throw new ParseError(spaceTrim$2((block) => `
19171
20184
  Unsupported subformat name "${subformatName}" for format "${formatName}"
19172
20185
 
19173
20186
  Available subformat names for format "${formatDefinition.formatName}":
@@ -19215,7 +20228,7 @@ const foreachCommandParser = {
19215
20228
  outputSubparameterName = 'newLine';
19216
20229
  }
19217
20230
  else {
19218
- throw new ParseError(spaceTrim(`
20231
+ throw new ParseError(spaceTrim$2(`
19219
20232
  FOREACH ${formatName} ${subformatName} must specify output subparameter
19220
20233
 
19221
20234
  Correct example:
@@ -19291,7 +20304,7 @@ const formatCommandParser = {
19291
20304
  /**
19292
20305
  * Description of the FORMAT command
19293
20306
  */
19294
- description: spaceTrim(`
20307
+ description: spaceTrim$2(`
19295
20308
  Format command describes the desired output of the task (after post-processing)
19296
20309
  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.
19297
20310
  `),
@@ -19663,7 +20676,7 @@ const formfactorCommandParser = {
19663
20676
  const formfactorNameCandidate = args[0].toUpperCase();
19664
20677
  const formfactor = FORMFACTOR_DEFINITIONS.find((definition) => [definition.name, ...{ aliasNames: [], ...definition }.aliasNames].includes(formfactorNameCandidate));
19665
20678
  if (formfactor === undefined) {
19666
- throw new ParseError(spaceTrim((block) => `
20679
+ throw new ParseError(spaceTrim$2((block) => `
19667
20680
  Unknown formfactor name "${formfactorNameCandidate}"
19668
20681
 
19669
20682
  Available formfactors:
@@ -19682,7 +20695,7 @@ const formfactorCommandParser = {
19682
20695
  */
19683
20696
  $applyToPipelineJson(command, $pipelineJson) {
19684
20697
  if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
19685
- throw new ParseError(spaceTrim(`
20698
+ throw new ParseError(spaceTrim$2(`
19686
20699
  Redefinition of \`FORMFACTOR\` in the pipeline head
19687
20700
 
19688
20701
  You have used:
@@ -19825,7 +20838,7 @@ const modelCommandParser = {
19825
20838
  */
19826
20839
  parse(input) {
19827
20840
  const { args, normalized } = input;
19828
- const availableVariantsMessage = spaceTrim((block) => `
20841
+ const availableVariantsMessage = spaceTrim$2((block) => `
19829
20842
  Available variants are:
19830
20843
  ${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
19831
20844
  `);
@@ -19847,14 +20860,14 @@ const modelCommandParser = {
19847
20860
  // <- Note: [🤖]
19848
20861
  }
19849
20862
  else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
19850
- spaceTrim((block) => `
20863
+ spaceTrim$2((block) => `
19851
20864
  Embedding model can not be used in pipeline
19852
20865
 
19853
20866
  ${block(availableVariantsMessage)}
19854
20867
  `);
19855
20868
  }
19856
20869
  else {
19857
- throw new ParseError(spaceTrim((block) => `
20870
+ throw new ParseError(spaceTrim$2((block) => `
19858
20871
  Unknown model variant in command:
19859
20872
 
19860
20873
  ${block(availableVariantsMessage)}
@@ -19869,7 +20882,7 @@ const modelCommandParser = {
19869
20882
  };
19870
20883
  }
19871
20884
  else {
19872
- throw new ParseError(spaceTrim((block) => `
20885
+ throw new ParseError(spaceTrim$2((block) => `
19873
20886
  Unknown model key in command.
19874
20887
 
19875
20888
  Supported model keys are:
@@ -19896,7 +20909,7 @@ const modelCommandParser = {
19896
20909
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
19897
20910
  }
19898
20911
  else {
19899
- throw new ParseError(spaceTrim(`
20912
+ throw new ParseError(spaceTrim$2(`
19900
20913
  Redefinition of \`MODEL ${command.key}\` in the pipeline head
19901
20914
 
19902
20915
  You have used:
@@ -19928,7 +20941,7 @@ const modelCommandParser = {
19928
20941
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
19929
20942
  }
19930
20943
  else {
19931
- throw new ParseError(spaceTrim(`
20944
+ throw new ParseError(spaceTrim$2(`
19932
20945
  Redefinition of MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}"
19933
20946
 
19934
20947
  You have used:
@@ -19938,7 +20951,7 @@ const modelCommandParser = {
19938
20951
  }
19939
20952
  }
19940
20953
  if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
19941
- console.log(spaceTrim(`
20954
+ console.log(spaceTrim$2(`
19942
20955
  Setting MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}" to the same value as in the pipeline head
19943
20956
 
19944
20957
  In pipeline head:
@@ -20021,7 +21034,7 @@ const parameterCommandParser = {
20021
21034
  // <- TODO: When [🥶] fixed, change to:
20022
21035
  // > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
20023
21036
  if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
20024
- throw new ParseError(spaceTrim((block) => `
21037
+ throw new ParseError(spaceTrim$2((block) => `
20025
21038
  Parameter \`{${parameterNameRaw}}\` can not contain another parameter in description
20026
21039
 
20027
21040
  The description:
@@ -20203,7 +21216,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
20203
21216
  persona.description = personaDescription;
20204
21217
  return;
20205
21218
  }
20206
- console.warn(spaceTrim(`
21219
+ console.warn(spaceTrim$2(`
20207
21220
 
20208
21221
  Persona "${personaName}" is defined multiple times with different description:
20209
21222
 
@@ -20214,7 +21227,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
20214
21227
  ${personaDescription}
20215
21228
 
20216
21229
  `));
20217
- persona.description += spaceTrim('\n\n' + personaDescription);
21230
+ persona.description += spaceTrim$2('\n\n' + personaDescription);
20218
21231
  }
20219
21232
 
20220
21233
  /**
@@ -21055,7 +22068,7 @@ function removeMarkdownComments(content) {
21055
22068
  */
21056
22069
  function isFlatPipeline(pipelineString) {
21057
22070
  pipelineString = removeMarkdownComments(pipelineString);
21058
- pipelineString = spaceTrim(pipelineString);
22071
+ pipelineString = spaceTrim$2(pipelineString);
21059
22072
  const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
21060
22073
  //const isLastLineReturnStatement = pipelineString.split('\n').pop()!.split('`').join('').startsWith('->');
21061
22074
  const isBacktickBlockUsed = pipelineString.includes('```');
@@ -21081,7 +22094,7 @@ function deflatePipeline(pipelineString) {
21081
22094
  if (!isFlatPipeline(pipelineString)) {
21082
22095
  return pipelineString;
21083
22096
  }
21084
- pipelineString = spaceTrim(pipelineString);
22097
+ pipelineString = spaceTrim$2(pipelineString);
21085
22098
  const pipelineStringLines = pipelineString.split('\n');
21086
22099
  const potentialReturnStatement = pipelineStringLines.pop();
21087
22100
  let returnStatement;
@@ -21094,19 +22107,19 @@ function deflatePipeline(pipelineString) {
21094
22107
  returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
21095
22108
  pipelineStringLines.push(potentialReturnStatement);
21096
22109
  }
21097
- const prompt = spaceTrim(pipelineStringLines.join('\n'));
22110
+ const prompt = spaceTrim$2(pipelineStringLines.join('\n'));
21098
22111
  let quotedPrompt;
21099
22112
  if (prompt.split('\n').length <= 1) {
21100
22113
  quotedPrompt = `> ${prompt}`;
21101
22114
  }
21102
22115
  else {
21103
- quotedPrompt = spaceTrim((block) => `
22116
+ quotedPrompt = spaceTrim$2((block) => `
21104
22117
  \`\`\`
21105
22118
  ${block(prompt.split('`').join('\\`'))}
21106
22119
  \`\`\`
21107
22120
  `);
21108
22121
  }
21109
- pipelineString = validatePipelineString(spaceTrim((block) => `
22122
+ pipelineString = validatePipelineString(spaceTrim$2((block) => `
21110
22123
  # ${DEFAULT_BOOK_TITLE}
21111
22124
 
21112
22125
  ## Prompt
@@ -21164,7 +22177,7 @@ function parseMarkdownSection(value) {
21164
22177
  }
21165
22178
  const title = lines[0].replace(/^#+\s*/, '');
21166
22179
  const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
21167
- const content = spaceTrim(lines.slice(1).join('\n'));
22180
+ const content = spaceTrim$2(lines.slice(1).join('\n'));
21168
22181
  if (level < 1 || level > 6) {
21169
22182
  throw new ParseError('Markdown section must have heading level between 1 and 6');
21170
22183
  }
@@ -21192,7 +22205,7 @@ function splitMarkdownIntoSections(markdown) {
21192
22205
  if (buffer.length === 0) {
21193
22206
  return;
21194
22207
  }
21195
- let section = spaceTrim(buffer.join('\n'));
22208
+ let section = spaceTrim$2(buffer.join('\n'));
21196
22209
  if (section === '') {
21197
22210
  return;
21198
22211
  }
@@ -21267,7 +22280,7 @@ function flattenMarkdown(markdown) {
21267
22280
  flattenedMarkdown += `## ${title}` + `\n\n`;
21268
22281
  flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
21269
22282
  }
21270
- return spaceTrim(flattenedMarkdown);
22283
+ return spaceTrim$2(flattenedMarkdown);
21271
22284
  }
21272
22285
  /**
21273
22286
  * TODO: [🏛] This can be part of markdown builder
@@ -21968,7 +22981,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
21968
22981
  catch (error) {
21969
22982
  assertsError(error);
21970
22983
  // TODO: [7] DRY
21971
- const wrappedErrorMessage = spaceTrim((block) => `
22984
+ const wrappedErrorMessage = spaceTrim$2((block) => `
21972
22985
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
21973
22986
 
21974
22987
  Original error message:
@@ -22003,7 +23016,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
22003
23016
  pipeline = { ...pipeline, pipelineUrl };
22004
23017
  }
22005
23018
  else if (!pipeline.pipelineUrl.startsWith(rootUrl)) {
22006
- throw new PipelineUrlError(spaceTrim(`
23019
+ throw new PipelineUrlError(spaceTrim$2(`
22007
23020
  Pipeline with URL ${pipeline.pipelineUrl} is not a child of the root URL ${rootUrl} 🍏
22008
23021
 
22009
23022
  File:
@@ -22041,7 +23054,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
22041
23054
  }
22042
23055
  else {
22043
23056
  const existing = collection.get(pipeline.pipelineUrl);
22044
- throw new PipelineUrlError(spaceTrim(`
23057
+ throw new PipelineUrlError(spaceTrim$2(`
22045
23058
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍏
22046
23059
 
22047
23060
  Conflicting files:
@@ -22059,7 +23072,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
22059
23072
  catch (error) {
22060
23073
  assertsError(error);
22061
23074
  // TODO: [7] DRY
22062
- const wrappedErrorMessage = spaceTrim((block) => `
23075
+ const wrappedErrorMessage = spaceTrim$2((block) => `
22063
23076
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
22064
23077
 
22065
23078
  Original error message:
@@ -22235,7 +23248,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
22235
23248
  // console.log(`Strategy 3️⃣`);
22236
23249
  const response = await fetch(pipelineSource);
22237
23250
  if (response.status >= 300) {
22238
- throw new NotFoundError(spaceTrim((block) => `
23251
+ throw new NotFoundError(spaceTrim$2((block) => `
22239
23252
  Book not found on URL:
22240
23253
  ${block(pipelineSource)}
22241
23254
 
@@ -22245,7 +23258,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
22245
23258
  const pipelineString = await response.text();
22246
23259
  // console.log({ pipelineString });
22247
23260
  if (!isValidPipelineString(pipelineString)) {
22248
- throw new NotFoundError(spaceTrim((block) => `
23261
+ throw new NotFoundError(spaceTrim$2((block) => `
22249
23262
  Book not found on URL:
22250
23263
  ${block(pipelineSource)}
22251
23264
 
@@ -22267,7 +23280,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
22267
23280
  });
22268
23281
  return pipelineJson;
22269
23282
  } /* not else */
22270
- throw new NotFoundError(spaceTrim((block) => `
23283
+ throw new NotFoundError(spaceTrim$2((block) => `
22271
23284
  Book not found:
22272
23285
  ${block(pipelineSource)}
22273
23286