@promptbook/cli 0.103.0-55 → 0.103.0-66

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 (91) hide show
  1. package/apps/agents-server/TODO.txt +5 -1
  2. package/apps/agents-server/package-lock.json +2336 -0
  3. package/apps/agents-server/package.json +9 -0
  4. package/apps/agents-server/src/app/actions.ts +3 -1
  5. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +3 -1
  6. package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +282 -0
  7. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +91 -0
  8. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileWrapper.tsx +44 -0
  9. package/apps/agents-server/src/app/agents/[agentName]/CloneAgentButton.tsx +4 -4
  10. package/apps/agents-server/src/app/agents/[agentName]/InstallPwaButton.tsx +2 -2
  11. package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +80 -0
  12. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +3 -1
  13. package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +11 -1
  14. package/apps/agents-server/src/app/agents/[agentName]/api/openai/models/route.ts +93 -0
  15. package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/chat/completions/route.ts +10 -0
  16. package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/models/route.ts +93 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +4 -0
  18. package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +9 -2
  19. package/apps/agents-server/src/app/agents/[agentName]/generateAgentMetadata.ts +7 -3
  20. package/apps/agents-server/src/app/agents/[agentName]/integration/SdkCodeTabs.tsx +31 -0
  21. package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +271 -30
  22. package/apps/agents-server/src/app/agents/[agentName]/layout.tsx +41 -0
  23. package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +61 -97
  24. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +47 -157
  25. package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +70 -0
  26. package/apps/agents-server/src/app/api/openai/v1/chat/completions/route.ts +6 -0
  27. package/apps/agents-server/src/app/api/openai/v1/models/route.ts +65 -0
  28. package/apps/agents-server/src/app/docs/[docId]/page.tsx +12 -32
  29. package/apps/agents-server/src/app/docs/page.tsx +42 -17
  30. package/apps/agents-server/src/app/embed/page.tsx +2 -2
  31. package/apps/agents-server/src/app/globals.css +129 -0
  32. package/apps/agents-server/src/app/layout.tsx +16 -26
  33. package/apps/agents-server/src/app/manifest.ts +9 -4
  34. package/apps/agents-server/src/components/AgentProfile/AgentProfile.tsx +334 -0
  35. package/apps/agents-server/src/components/AgentProfile/AgentProfileFromSource.tsx +23 -0
  36. package/apps/agents-server/src/{app/agents/[agentName] → components/AgentProfile}/AgentQrCode.tsx +8 -1
  37. package/apps/agents-server/src/components/AgentProfile/QrCodeModal.tsx +90 -0
  38. package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +87 -0
  39. package/apps/agents-server/src/components/LayoutWrapper/LayoutWrapper.tsx +7 -6
  40. package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +20 -0
  41. package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +18 -0
  42. package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +18 -0
  43. package/apps/agents-server/src/database/metadataDefaults.ts +6 -0
  44. package/apps/agents-server/src/database/migrations/2025-12-0070-chat-history-source.sql +2 -0
  45. package/apps/agents-server/src/database/schema.ts +6 -0
  46. package/apps/agents-server/src/utils/handleChatCompletion.ts +186 -14
  47. package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +13 -6
  48. package/apps/agents-server/src/utils/validateApiKey.ts +128 -0
  49. package/apps/agents-server/tailwind.config.ts +1 -1
  50. package/esm/index.es.js +953 -474
  51. package/esm/index.es.js.map +1 -1
  52. package/esm/typings/src/_packages/components.index.d.ts +2 -2
  53. package/esm/typings/src/_packages/core.index.d.ts +6 -8
  54. package/esm/typings/src/_packages/types.index.d.ts +7 -1
  55. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +2 -1
  56. package/esm/typings/src/book-2.0/agent-source/createCommitmentRegex.d.ts +1 -1
  57. package/esm/typings/src/book-components/Chat/AgentChat/AgentChat.d.ts +3 -0
  58. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +6 -0
  59. package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +5 -0
  60. package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgentIntegration.d.ts +52 -0
  61. package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgentSeamlessIntegration.d.ts +14 -0
  62. package/esm/typings/src/book-components/icons/SendIcon.d.ts +3 -0
  63. package/esm/typings/src/commitments/CLOSED/CLOSED.d.ts +4 -0
  64. package/esm/typings/src/commitments/CLOSED/CLOSED.test.d.ts +4 -0
  65. package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +6 -0
  66. package/esm/typings/src/commitments/META_FONT/META_FONT.d.ts +42 -0
  67. package/esm/typings/src/commitments/USE/USE.d.ts +53 -0
  68. package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.d.ts +42 -0
  69. package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.test.d.ts +1 -0
  70. package/esm/typings/src/commitments/{IMPORTANT/IMPORTANT.d.ts → USE_MCP/USE_MCP.d.ts} +16 -5
  71. package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +38 -0
  72. package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +6 -0
  73. package/esm/typings/src/commitments/index.d.ts +93 -1
  74. package/esm/typings/src/llm-providers/agent/Agent.d.ts +3 -1
  75. package/esm/typings/src/other/templates/getTemplatesPipelineCollection.d.ts +1 -1
  76. package/esm/typings/src/playground/playground.d.ts +3 -0
  77. package/esm/typings/src/types/typeAliases.d.ts +6 -0
  78. package/esm/typings/src/utils/color/Color.d.ts +9 -1
  79. package/esm/typings/src/utils/color/css-colors.d.ts +1 -0
  80. package/esm/typings/src/utils/random/$generateBookBoilerplate.d.ts +6 -0
  81. package/esm/typings/src/utils/random/CzechNamePool.d.ts +7 -0
  82. package/esm/typings/src/utils/random/EnglishNamePool.d.ts +7 -0
  83. package/esm/typings/src/utils/random/NamePool.d.ts +17 -0
  84. package/esm/typings/src/utils/random/getNamePool.d.ts +10 -0
  85. package/esm/typings/src/version.d.ts +1 -1
  86. package/package.json +2 -2
  87. package/umd/index.umd.js +902 -423
  88. package/umd/index.umd.js.map +1 -1
  89. package/esm/typings/src/book-components/PromptbookAgent/PromptbookAgent.d.ts +0 -29
  90. package/esm/typings/src/commitments/registry.d.ts +0 -68
  91. package/esm/typings/src/playground/playground1.d.ts +0 -2
package/esm/index.es.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import colors from 'colors';
2
2
  import commander from 'commander';
3
- import spaceTrim, { spaceTrim as spaceTrim$1 } from 'spacetrim';
3
+ import spaceTrim$2, { spaceTrim as spaceTrim$1 } from 'spacetrim';
4
4
  import { forTime, forEver } from 'waitasecond';
5
5
  import prompts from 'prompts';
6
6
  import { join, basename, dirname, isAbsolute, relative } from 'path';
@@ -47,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
47
47
  * @generated
48
48
  * @see https://github.com/webgptorg/promptbook
49
49
  */
50
- const PROMPTBOOK_ENGINE_VERSION = '0.103.0-55';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-66';
51
51
  /**
52
52
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
53
53
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -101,6 +101,17 @@ const REMOTE_SERVER_URLS = [
101
101
  * Note: [💞] Ignore a discrepancy between file name and entity name
102
102
  */
103
103
 
104
+ /**
105
+ * Trims string from all 4 sides
106
+ *
107
+ * Note: This is a re-exported function from the `spacetrim` package which is
108
+ * Developed by same author @hejny as this package
109
+ *
110
+ * @public exported from `@promptbook/utils`
111
+ * @see https://github.com/hejny/spacetrim#usage
112
+ */
113
+ const spaceTrim = spaceTrim$1;
114
+
104
115
  /**
105
116
  * Just marks a place of place where should be something implemented
106
117
  * No side effects.
@@ -162,6 +173,7 @@ function take(initialValue) {
162
173
  * @public exported from `@promptbook/color`
163
174
  */
164
175
  const CSS_COLORS = {
176
+ promptbook: '#79EAFD',
165
177
  transparent: 'rgba(0,0,0,0)',
166
178
  aliceblue: '#f0f8ff',
167
179
  antiquewhite: '#faebd7',
@@ -362,21 +374,61 @@ class Color {
362
374
  * @param color
363
375
  * @returns Color object
364
376
  */
365
- static from(color) {
366
- if (color instanceof Color) {
377
+ static from(color, _isSingleValue = false) {
378
+ if (color === '') {
379
+ throw new Error(`Can not create color from empty string`);
380
+ }
381
+ else if (color instanceof Color) {
367
382
  return take(color);
368
383
  }
369
384
  else if (Color.isColor(color)) {
370
385
  return take(color);
371
386
  }
372
387
  else if (typeof color === 'string') {
373
- return Color.fromString(color);
388
+ try {
389
+ return Color.fromString(color);
390
+ }
391
+ catch (error) {
392
+ // <- Note: Can not use `assertsError(error)` here because it causes circular dependency
393
+ if (_isSingleValue) {
394
+ throw error;
395
+ }
396
+ const parts = color.split(/[\s+,;|]/);
397
+ if (parts.length > 0) {
398
+ return Color.from(parts[0].trim(), true);
399
+ }
400
+ else {
401
+ throw new Error(`Can not create color from given string "${color}"`);
402
+ }
403
+ }
374
404
  }
375
405
  else {
376
406
  console.error({ color });
377
407
  throw new Error(`Can not create color from given object`);
378
408
  }
379
409
  }
410
+ /**
411
+ * Creates a new Color instance from miscellaneous formats
412
+ * It just does not throw error when it fails, it returns PROMPTBOOK_COLOR instead
413
+ *
414
+ * @param color
415
+ * @returns Color object
416
+ */
417
+ static fromSafe(color) {
418
+ try {
419
+ return Color.from(color);
420
+ }
421
+ catch (error) {
422
+ // <- Note: Can not use `assertsError(error)` here because it causes circular dependency
423
+ console.warn(spaceTrim((block) => `
424
+ Color.fromSafe error:
425
+ ${block(error.message)}
426
+
427
+ Returning default PROMPTBOOK_COLOR.
428
+ `));
429
+ return Color.fromString('promptbook');
430
+ }
431
+ }
380
432
  /**
381
433
  * Creates a new Color instance from miscellaneous string formats
382
434
  *
@@ -1000,7 +1052,7 @@ const CLAIM = `Turn your company's scattered knowledge into AI ready books`;
1000
1052
  *
1001
1053
  * @public exported from `@promptbook/core`
1002
1054
  */
1003
- const PROMPTBOOK_COLOR = Color.fromHex('#79EAFD');
1055
+ const PROMPTBOOK_COLOR = Color.fromString('promptbook');
1004
1056
  // <- TODO: [🧠][🈵] Using `Color` here increases the package size approx 3kb, maybe remove it
1005
1057
  /**
1006
1058
  * Colors for syntax highlighting in the `<BookEditor/>`
@@ -1398,7 +1450,7 @@ const $isRunningInWebWorker = new Function(`
1398
1450
  function getErrorReportUrl(error) {
1399
1451
  const report = {
1400
1452
  title: `🐜 Error report from ${NAME}`,
1401
- body: spaceTrim((block) => `
1453
+ body: spaceTrim$2((block) => `
1402
1454
 
1403
1455
 
1404
1456
  \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
@@ -1537,7 +1589,7 @@ function handleActionErrors(action) {
1537
1589
  */
1538
1590
  function $initializeAboutCommand(program) {
1539
1591
  const makeCommand = program.command('about');
1540
- makeCommand.description(spaceTrim(`
1592
+ makeCommand.description(spaceTrim$2(`
1541
1593
  Tells about Promptbook CLI and its abilities
1542
1594
  `));
1543
1595
  makeCommand.action(handleActionErrors(async () => {
@@ -1585,7 +1637,7 @@ function $initializeAboutCommand(program) {
1585
1637
  */
1586
1638
  function $initializeHelloCommand(program) {
1587
1639
  const helloCommand = program.command('hello');
1588
- helloCommand.description(spaceTrim(`
1640
+ helloCommand.description(spaceTrim$2(`
1589
1641
  Just command for testing
1590
1642
  `));
1591
1643
  helloCommand.alias('hi');
@@ -1847,13 +1899,13 @@ function $registeredLlmToolsMessage() {
1847
1899
  });
1848
1900
  const usedEnvMessage = $usedEnvFilename === null ? `Unknown \`.env\` file` : `Used \`.env\` file:\n${$usedEnvFilename}`;
1849
1901
  if (metadata.length === 0) {
1850
- return spaceTrim((block) => `
1902
+ return spaceTrim$2((block) => `
1851
1903
  No LLM providers are available.
1852
1904
 
1853
1905
  ${block(usedEnvMessage)}
1854
1906
  `);
1855
1907
  }
1856
- return spaceTrim((block) => `
1908
+ return spaceTrim$2((block) => `
1857
1909
 
1858
1910
  ${block(usedEnvMessage)}
1859
1911
 
@@ -1899,7 +1951,7 @@ function $registeredLlmToolsMessage() {
1899
1951
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
1900
1952
  }
1901
1953
  }
1902
- let providerMessage = spaceTrim(`
1954
+ let providerMessage = spaceTrim$2(`
1903
1955
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
1904
1956
  ${morePieces.join('; ')}
1905
1957
  `);
@@ -1965,7 +2017,7 @@ function jsonParse(value) {
1965
2017
  }
1966
2018
  else if (typeof value !== 'string') {
1967
2019
  console.error('Can not parse JSON from non-string value.', { text: value });
1968
- throw new Error(spaceTrim(`
2020
+ throw new Error(spaceTrim$2(`
1969
2021
  Can not parse JSON from non-string value.
1970
2022
 
1971
2023
  The value type: ${typeof value}
@@ -1979,7 +2031,7 @@ function jsonParse(value) {
1979
2031
  if (!(error instanceof Error)) {
1980
2032
  throw error;
1981
2033
  }
1982
- throw new Error(spaceTrim((block) => `
2034
+ throw new Error(spaceTrim$2((block) => `
1983
2035
  ${block(error.message)}
1984
2036
 
1985
2037
  The expected JSON text:
@@ -2200,7 +2252,7 @@ class $EnvStorage {
2200
2252
  .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
2201
2253
  .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
2202
2254
  .join('\n');
2203
- const newEnvContent = spaceTrim((block) => `
2255
+ const newEnvContent = spaceTrim$2((block) => `
2204
2256
  ${block(updatedEnvContent)}
2205
2257
 
2206
2258
  # ${GENERATOR_WARNING_IN_ENV}
@@ -2311,7 +2363,7 @@ function checkSerializableAsJson(options) {
2311
2363
  }
2312
2364
  else if (typeof value === 'object') {
2313
2365
  if (value instanceof Date) {
2314
- throw new UnexpectedError(spaceTrim((block) => `
2366
+ throw new UnexpectedError(spaceTrim$2((block) => `
2315
2367
  \`${name}\` is Date
2316
2368
 
2317
2369
  Use \`string_date_iso8601\` instead
@@ -2330,7 +2382,7 @@ function checkSerializableAsJson(options) {
2330
2382
  throw new UnexpectedError(`${name} is RegExp`);
2331
2383
  }
2332
2384
  else if (value instanceof Error) {
2333
- throw new UnexpectedError(spaceTrim((block) => `
2385
+ throw new UnexpectedError(spaceTrim$2((block) => `
2334
2386
  \`${name}\` is unserialized Error
2335
2387
 
2336
2388
  Use function \`serializeError\`
@@ -2353,7 +2405,7 @@ function checkSerializableAsJson(options) {
2353
2405
  }
2354
2406
  catch (error) {
2355
2407
  assertsError(error);
2356
- throw new UnexpectedError(spaceTrim((block) => `
2408
+ throw new UnexpectedError(spaceTrim$2((block) => `
2357
2409
  \`${name}\` is not serializable
2358
2410
 
2359
2411
  ${block(error.stack || error.message)}
@@ -2385,7 +2437,7 @@ function checkSerializableAsJson(options) {
2385
2437
  }
2386
2438
  }
2387
2439
  else {
2388
- throw new UnexpectedError(spaceTrim((block) => `
2440
+ throw new UnexpectedError(spaceTrim$2((block) => `
2389
2441
  \`${name}\` is unknown type
2390
2442
 
2391
2443
  Additional message for \`${name}\`:
@@ -2593,7 +2645,7 @@ function isSerializableAsJson(value) {
2593
2645
  */
2594
2646
  function stringifyPipelineJson(pipeline) {
2595
2647
  if (!isSerializableAsJson(pipeline)) {
2596
- throw new UnexpectedError(spaceTrim(`
2648
+ throw new UnexpectedError(spaceTrim$2(`
2597
2649
  Cannot stringify the pipeline, because it is not serializable as JSON
2598
2650
 
2599
2651
  There can be multiple reasons:
@@ -3492,7 +3544,7 @@ function deserializeError(error) {
3492
3544
  message = `${name}: ${message}`;
3493
3545
  }
3494
3546
  if (stack !== undefined && stack !== '') {
3495
- message = spaceTrim((block) => `
3547
+ message = spaceTrim$2((block) => `
3496
3548
  ${block(message)}
3497
3549
 
3498
3550
  Original stack trace:
@@ -3519,7 +3571,7 @@ async function createRemoteClient(options) {
3519
3571
  const remoteServerUrlParsed = new URL(remoteServerUrl);
3520
3572
  if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
3521
3573
  remoteServerUrlParsed.pathname = '/';
3522
- throw new Error(spaceTrim((block) => `
3574
+ throw new Error(spaceTrim$2((block) => `
3523
3575
  Remote server requires root url \`/\`
3524
3576
 
3525
3577
  You have provided \`remoteServerUrl\`:
@@ -4155,7 +4207,7 @@ function cacheLlmTools(llmTools, options = {}) {
4155
4207
  let normalizedContent = content;
4156
4208
  normalizedContent = normalizedContent.replace(/\s+/g, ' ');
4157
4209
  normalizedContent = normalizedContent.split('\r\n').join('\n');
4158
- normalizedContent = spaceTrim(normalizedContent);
4210
+ normalizedContent = spaceTrim$2(normalizedContent);
4159
4211
  // Note: Do not need to save everything in the cache, just the relevant parameters
4160
4212
  const relevantParameterNames = extractParameterNames(content);
4161
4213
  const relevantParameters = Object.fromEntries(Object.entries(parameters).filter(([key]) => relevantParameterNames.has(key)));
@@ -4540,14 +4592,14 @@ class MultipleLlmExecutionTools {
4540
4592
  if (description === undefined) {
4541
4593
  return headLine;
4542
4594
  }
4543
- return spaceTrim((block) => `
4595
+ return spaceTrim$2((block) => `
4544
4596
  ${headLine}
4545
4597
 
4546
4598
  ${ /* <- Note: Indenting the description: */block(description)}
4547
4599
  `);
4548
4600
  })
4549
4601
  .join('\n\n');
4550
- return spaceTrim((block) => `
4602
+ return spaceTrim$2((block) => `
4551
4603
  Multiple LLM Providers:
4552
4604
 
4553
4605
  ${block(innerModelsTitlesAndDescriptions)}
@@ -4638,7 +4690,7 @@ class MultipleLlmExecutionTools {
4638
4690
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
4639
4691
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
4640
4692
  // 3) ...
4641
- spaceTrim((block) => `
4693
+ spaceTrim$2((block) => `
4642
4694
  All execution tools of ${this.title} failed:
4643
4695
 
4644
4696
  ${block(errors
@@ -4651,7 +4703,7 @@ class MultipleLlmExecutionTools {
4651
4703
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\` into ${this.title}`);
4652
4704
  }
4653
4705
  else {
4654
- throw new PipelineExecutionError(spaceTrim((block) => `
4706
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
4655
4707
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}" into ${this.title}
4656
4708
 
4657
4709
  Available \`LlmExecutionTools\`:
@@ -4684,7 +4736,7 @@ class MultipleLlmExecutionTools {
4684
4736
  */
4685
4737
  function joinLlmExecutionTools(title, ...llmExecutionTools) {
4686
4738
  if (llmExecutionTools.length === 0) {
4687
- const warningMessage = spaceTrim(`
4739
+ const warningMessage = spaceTrim$2(`
4688
4740
  You have not provided any \`LlmExecutionTools\`
4689
4741
  This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.
4690
4742
 
@@ -4742,7 +4794,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
4742
4794
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
4743
4795
  if (registeredItem === undefined) {
4744
4796
  // console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
4745
- throw new Error(spaceTrim((block) => `
4797
+ throw new Error(spaceTrim$2((block) => `
4746
4798
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
4747
4799
  Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
4748
4800
 
@@ -4810,14 +4862,14 @@ async function $provideLlmToolsFromEnv(options = {}) {
4810
4862
  const configuration = await $provideLlmToolsConfigurationFromEnv();
4811
4863
  if (configuration.length === 0) {
4812
4864
  if ($llmToolsMetadataRegister.list().length === 0) {
4813
- throw new UnexpectedError(spaceTrim((block) => `
4865
+ throw new UnexpectedError(spaceTrim$2((block) => `
4814
4866
  No LLM tools registered, this is probably a bug in the Promptbook library
4815
4867
 
4816
4868
  ${block($registeredLlmToolsMessage())}}
4817
4869
  `));
4818
4870
  }
4819
4871
  // TODO: [🥃]
4820
- throw new Error(spaceTrim((block) => `
4872
+ throw new Error(spaceTrim$2((block) => `
4821
4873
  No LLM tools found in the environment
4822
4874
 
4823
4875
  ${block($registeredLlmToolsMessage())}}
@@ -4927,7 +4979,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
4927
4979
  else if (urlOrRequest instanceof Request) {
4928
4980
  url = urlOrRequest.url;
4929
4981
  }
4930
- throw new PromptbookFetchError(spaceTrim((block) => `
4982
+ throw new PromptbookFetchError(spaceTrim$2((block) => `
4931
4983
  Can not fetch "${url}"
4932
4984
 
4933
4985
  Fetch error:
@@ -4996,7 +5048,7 @@ async function $provideLlmToolsForCli(options) {
4996
5048
  console.log(colors.red(`You can not login to remote server in non-interactive mode`));
4997
5049
  process.exit(1);
4998
5050
  }
4999
- console.info(colors.cyan(spaceTrim(`
5051
+ console.info(colors.cyan(spaceTrim$2(`
5000
5052
  You will be logged in to ${remoteServerUrl}
5001
5053
  If you don't have an account, it will be created automatically.
5002
5054
  `)));
@@ -5070,7 +5122,7 @@ async function $provideLlmToolsForCli(options) {
5070
5122
  */
5071
5123
  function $initializeListModelsCommand(program) {
5072
5124
  const listModelsCommand = program.command('list-models');
5073
- listModelsCommand.description(spaceTrim(`
5125
+ listModelsCommand.description(spaceTrim$2(`
5074
5126
  List all available and configured LLM models
5075
5127
  `));
5076
5128
  listModelsCommand.alias('models');
@@ -5550,14 +5602,14 @@ function $registeredScrapersMessage(availableScrapers) {
5550
5602
  return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
5551
5603
  });
5552
5604
  if (metadata.length === 0) {
5553
- return spaceTrim(`
5605
+ return spaceTrim$2(`
5554
5606
  **No scrapers are available**
5555
5607
 
5556
5608
  This is a unexpected behavior, you are probably using some broken version of Promptbook
5557
5609
  At least there should be available the metadata of the scrapers
5558
5610
  `);
5559
5611
  }
5560
- return spaceTrim((block) => `
5612
+ return spaceTrim$2((block) => `
5561
5613
  Available scrapers are:
5562
5614
  ${block(metadata
5563
5615
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
@@ -5608,7 +5660,7 @@ function $registeredScrapersMessage(availableScrapers) {
5608
5660
  */
5609
5661
  function $initializeListScrapersCommand(program) {
5610
5662
  const listModelsCommand = program.command('list-scrapers');
5611
- listModelsCommand.description(spaceTrim(`
5663
+ listModelsCommand.description(spaceTrim$2(`
5612
5664
  List all available and configured scrapers and executables
5613
5665
  `));
5614
5666
  listModelsCommand.alias('scrapers');
@@ -5616,7 +5668,7 @@ function $initializeListScrapersCommand(program) {
5616
5668
  // TODO: [🌞] Do not allow on REMOTE_SERVER strategy
5617
5669
  const scrapers = await $provideScrapersForNode({});
5618
5670
  const executables = await $provideExecutablesForNode();
5619
- console.info(spaceTrim((block) => `
5671
+ console.info(spaceTrim$2((block) => `
5620
5672
  ${block($registeredScrapersMessage(scrapers))}
5621
5673
 
5622
5674
  All mime-types which can be scraped:
@@ -5646,7 +5698,7 @@ function $initializeListScrapersCommand(program) {
5646
5698
  */
5647
5699
  function $initializeLoginCommand(program) {
5648
5700
  const loginCommand = program.command('login');
5649
- loginCommand.description(spaceTrim(`
5701
+ loginCommand.description(spaceTrim$2(`
5650
5702
  Login to the remote Promptbook server
5651
5703
  `));
5652
5704
  loginCommand.action(handleActionErrors(async (cliOptions) => {
@@ -6220,7 +6272,7 @@ function pipelineJsonToString(pipelineJson) {
6220
6272
  pipelineString += '\n\n';
6221
6273
  pipelineString += '```' + contentLanguage;
6222
6274
  pipelineString += '\n';
6223
- pipelineString += spaceTrim(content);
6275
+ pipelineString += spaceTrim$2(content);
6224
6276
  // <- TODO: [main] !!3 Escape
6225
6277
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
6226
6278
  pipelineString += '\n';
@@ -6451,7 +6503,7 @@ function serializeError(error) {
6451
6503
  const { name, message, stack } = error;
6452
6504
  const { id } = error;
6453
6505
  if (!Object.keys(ALL_ERRORS).includes(name)) {
6454
- console.error(spaceTrim((block) => `
6506
+ console.error(spaceTrim$2((block) => `
6455
6507
 
6456
6508
  Cannot serialize error with name "${name}"
6457
6509
 
@@ -7052,7 +7104,7 @@ const CsvFormatParser = {
7052
7104
  const { value, outputParameterName, settings, mapCallback, onProgress } = options;
7053
7105
  const csv = csvParse(value, settings);
7054
7106
  if (csv.errors.length !== 0) {
7055
- throw new CsvFormatError(spaceTrim((block) => `
7107
+ throw new CsvFormatError(spaceTrim$2((block) => `
7056
7108
  CSV parsing error
7057
7109
 
7058
7110
  Error(s) from CSV parsing:
@@ -7097,7 +7149,7 @@ const CsvFormatParser = {
7097
7149
  const { value, settings, mapCallback, onProgress } = options;
7098
7150
  const csv = csvParse(value, settings);
7099
7151
  if (csv.errors.length !== 0) {
7100
- throw new CsvFormatError(spaceTrim((block) => `
7152
+ throw new CsvFormatError(spaceTrim$2((block) => `
7101
7153
  CSV parsing error
7102
7154
 
7103
7155
  Error(s) from CSV parsing:
@@ -7307,7 +7359,7 @@ function mapAvailableToExpectedParameters(options) {
7307
7359
  }
7308
7360
  // Phase 2️⃣: Non-matching mapping
7309
7361
  if (expectedParameterNames.size !== availableParametersNames.size) {
7310
- throw new PipelineExecutionError(spaceTrim((block) => `
7362
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
7311
7363
  Can not map available parameters to expected parameters
7312
7364
 
7313
7365
  Mapped parameters:
@@ -7792,7 +7844,7 @@ async function executeFormatSubvalues(options) {
7792
7844
  return /* not await */ executeAttempts({ ...options, logLlmCall });
7793
7845
  }
7794
7846
  if (jokerParameterNames.length !== 0) {
7795
- throw new UnexpectedError(spaceTrim((block) => `
7847
+ throw new UnexpectedError(spaceTrim$2((block) => `
7796
7848
  JOKER parameters are not supported together with FOREACH command
7797
7849
 
7798
7850
  [🧞‍♀️] This should be prevented in \`validatePipeline\`
@@ -7805,7 +7857,7 @@ async function executeFormatSubvalues(options) {
7805
7857
  if (formatDefinition === undefined) {
7806
7858
  throw new UnexpectedError(
7807
7859
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
7808
- spaceTrim((block) => `
7860
+ spaceTrim$2((block) => `
7809
7861
  Unsupported format "${task.foreach.formatName}"
7810
7862
 
7811
7863
  Available formats:
@@ -7822,7 +7874,7 @@ async function executeFormatSubvalues(options) {
7822
7874
  if (subvalueParser === undefined) {
7823
7875
  throw new UnexpectedError(
7824
7876
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
7825
- spaceTrim((block) => `
7877
+ spaceTrim$2((block) => `
7826
7878
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
7827
7879
 
7828
7880
  Available subformat names for format "${formatDefinition.formatName}":
@@ -7862,7 +7914,7 @@ async function executeFormatSubvalues(options) {
7862
7914
  if (!(error instanceof PipelineExecutionError)) {
7863
7915
  throw error;
7864
7916
  }
7865
- const highLevelError = new PipelineExecutionError(spaceTrim((block) => `
7917
+ const highLevelError = new PipelineExecutionError(spaceTrim$2((block) => `
7866
7918
  ${error.message}
7867
7919
 
7868
7920
  This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -7886,7 +7938,7 @@ async function executeFormatSubvalues(options) {
7886
7938
  ...options,
7887
7939
  priority: priority + index,
7888
7940
  parameters: allSubparameters,
7889
- pipelineIdentification: spaceTrim((block) => `
7941
+ pipelineIdentification: spaceTrim$2((block) => `
7890
7942
  ${block(pipelineIdentification)}
7891
7943
  Subparameter index: ${index}
7892
7944
  `),
@@ -7895,7 +7947,7 @@ async function executeFormatSubvalues(options) {
7895
7947
  }
7896
7948
  catch (error) {
7897
7949
  if (length > BIG_DATASET_TRESHOLD) {
7898
- console.error(spaceTrim((block) => `
7950
+ console.error(spaceTrim$2((block) => `
7899
7951
  ${error.message}
7900
7952
 
7901
7953
  This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -8969,7 +9021,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
8969
9021
  const fileExtension = getFileExtension(filename);
8970
9022
  const mimeType = extensionToMimeType(fileExtension || '');
8971
9023
  if (!(await isFileExisting(filename, tools.fs))) {
8972
- throw new NotFoundError(spaceTrim((block) => `
9024
+ throw new NotFoundError(spaceTrim$2((block) => `
8973
9025
  Can not make source handler for file which does not exist:
8974
9026
 
8975
9027
  File:
@@ -9062,7 +9114,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
9062
9114
  // <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
9063
9115
  break;
9064
9116
  }
9065
- console.warn(spaceTrim((block) => `
9117
+ console.warn(spaceTrim$2((block) => `
9066
9118
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
9067
9119
 
9068
9120
  The source:
@@ -9078,7 +9130,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
9078
9130
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
9079
9131
  }
9080
9132
  if (partialPieces === null) {
9081
- throw new KnowledgeScrapeError(spaceTrim((block) => `
9133
+ throw new KnowledgeScrapeError(spaceTrim$2((block) => `
9082
9134
  Cannot scrape knowledge
9083
9135
 
9084
9136
  The source:
@@ -9414,7 +9466,7 @@ const knowledgeCommandParser = {
9414
9466
  */
9415
9467
  parse(input) {
9416
9468
  const { args } = input;
9417
- const knowledgeSourceContent = spaceTrim(args[0] || '');
9469
+ const knowledgeSourceContent = spaceTrim$2(args[0] || '');
9418
9470
  if (knowledgeSourceContent === '') {
9419
9471
  throw new ParseError(`Source is not defined`);
9420
9472
  }
@@ -9558,7 +9610,7 @@ const sectionCommandParser = {
9558
9610
  normalized = normalized.split('DIALOGUE').join('DIALOG');
9559
9611
  const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
9560
9612
  if (taskTypes.length !== 1) {
9561
- throw new ParseError(spaceTrim((block) => `
9613
+ throw new ParseError(spaceTrim$2((block) => `
9562
9614
  Unknown section type "${normalized}"
9563
9615
 
9564
9616
  Supported section types are:
@@ -9578,7 +9630,7 @@ const sectionCommandParser = {
9578
9630
  */
9579
9631
  $applyToTaskJson(command, $taskJson, $pipelineJson) {
9580
9632
  if ($taskJson.isSectionTypeSet === true) {
9581
- throw new ParseError(spaceTrim(`
9633
+ throw new ParseError(spaceTrim$2(`
9582
9634
  Section type is already defined in the section.
9583
9635
  It can be defined only once.
9584
9636
  `));
@@ -9927,7 +9979,7 @@ const expectCommandParser = {
9927
9979
  /**
9928
9980
  * Description of the FORMAT command
9929
9981
  */
9930
- description: spaceTrim(`
9982
+ description: spaceTrim$2(`
9931
9983
  Expect command describes the desired output of the task *(after post-processing)*
9932
9984
  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.
9933
9985
  `),
@@ -10001,7 +10053,7 @@ const expectCommandParser = {
10001
10053
  }
10002
10054
  catch (error) {
10003
10055
  assertsError(error);
10004
- throw new ParseError(spaceTrim((block) => `
10056
+ throw new ParseError(spaceTrim$2((block) => `
10005
10057
  Invalid FORMAT command
10006
10058
  ${block(error.message)}:
10007
10059
  `));
@@ -10191,7 +10243,7 @@ function validateParameterName(parameterName) {
10191
10243
  if (!(error instanceof ParseError)) {
10192
10244
  throw error;
10193
10245
  }
10194
- throw new ParseError(spaceTrim((block) => `
10246
+ throw new ParseError(spaceTrim$2((block) => `
10195
10247
  ${block(error.message)}
10196
10248
 
10197
10249
  Tried to validate parameter name:
@@ -10250,7 +10302,7 @@ const foreachCommandParser = {
10250
10302
  const assignSign = args[3];
10251
10303
  const formatDefinition = FORMAT_DEFINITIONS.find((formatDefinition) => [formatDefinition.formatName, ...(formatDefinition.aliases || [])].includes(formatName));
10252
10304
  if (formatDefinition === undefined) {
10253
- throw new ParseError(spaceTrim((block) => `
10305
+ throw new ParseError(spaceTrim$2((block) => `
10254
10306
  Unsupported format "${formatName}"
10255
10307
 
10256
10308
  Available formats:
@@ -10262,7 +10314,7 @@ const foreachCommandParser = {
10262
10314
  }
10263
10315
  const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(subformatName));
10264
10316
  if (subvalueParser === undefined) {
10265
- throw new ParseError(spaceTrim((block) => `
10317
+ throw new ParseError(spaceTrim$2((block) => `
10266
10318
  Unsupported subformat name "${subformatName}" for format "${formatName}"
10267
10319
 
10268
10320
  Available subformat names for format "${formatDefinition.formatName}":
@@ -10310,7 +10362,7 @@ const foreachCommandParser = {
10310
10362
  outputSubparameterName = 'newLine';
10311
10363
  }
10312
10364
  else {
10313
- throw new ParseError(spaceTrim(`
10365
+ throw new ParseError(spaceTrim$2(`
10314
10366
  FOREACH ${formatName} ${subformatName} must specify output subparameter
10315
10367
 
10316
10368
  Correct example:
@@ -10386,7 +10438,7 @@ const formatCommandParser = {
10386
10438
  /**
10387
10439
  * Description of the FORMAT command
10388
10440
  */
10389
- description: spaceTrim(`
10441
+ description: spaceTrim$2(`
10390
10442
  Format command describes the desired output of the task (after post-processing)
10391
10443
  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.
10392
10444
  `),
@@ -10758,7 +10810,7 @@ const formfactorCommandParser = {
10758
10810
  const formfactorNameCandidate = args[0].toUpperCase();
10759
10811
  const formfactor = FORMFACTOR_DEFINITIONS.find((definition) => [definition.name, ...{ aliasNames: [], ...definition }.aliasNames].includes(formfactorNameCandidate));
10760
10812
  if (formfactor === undefined) {
10761
- throw new ParseError(spaceTrim((block) => `
10813
+ throw new ParseError(spaceTrim$2((block) => `
10762
10814
  Unknown formfactor name "${formfactorNameCandidate}"
10763
10815
 
10764
10816
  Available formfactors:
@@ -10777,7 +10829,7 @@ const formfactorCommandParser = {
10777
10829
  */
10778
10830
  $applyToPipelineJson(command, $pipelineJson) {
10779
10831
  if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
10780
- throw new ParseError(spaceTrim(`
10832
+ throw new ParseError(spaceTrim$2(`
10781
10833
  Redefinition of \`FORMFACTOR\` in the pipeline head
10782
10834
 
10783
10835
  You have used:
@@ -10920,7 +10972,7 @@ const modelCommandParser = {
10920
10972
  */
10921
10973
  parse(input) {
10922
10974
  const { args, normalized } = input;
10923
- const availableVariantsMessage = spaceTrim((block) => `
10975
+ const availableVariantsMessage = spaceTrim$2((block) => `
10924
10976
  Available variants are:
10925
10977
  ${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
10926
10978
  `);
@@ -10942,14 +10994,14 @@ const modelCommandParser = {
10942
10994
  // <- Note: [🤖]
10943
10995
  }
10944
10996
  else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
10945
- spaceTrim((block) => `
10997
+ spaceTrim$2((block) => `
10946
10998
  Embedding model can not be used in pipeline
10947
10999
 
10948
11000
  ${block(availableVariantsMessage)}
10949
11001
  `);
10950
11002
  }
10951
11003
  else {
10952
- throw new ParseError(spaceTrim((block) => `
11004
+ throw new ParseError(spaceTrim$2((block) => `
10953
11005
  Unknown model variant in command:
10954
11006
 
10955
11007
  ${block(availableVariantsMessage)}
@@ -10964,7 +11016,7 @@ const modelCommandParser = {
10964
11016
  };
10965
11017
  }
10966
11018
  else {
10967
- throw new ParseError(spaceTrim((block) => `
11019
+ throw new ParseError(spaceTrim$2((block) => `
10968
11020
  Unknown model key in command.
10969
11021
 
10970
11022
  Supported model keys are:
@@ -10991,7 +11043,7 @@ const modelCommandParser = {
10991
11043
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
10992
11044
  }
10993
11045
  else {
10994
- throw new ParseError(spaceTrim(`
11046
+ throw new ParseError(spaceTrim$2(`
10995
11047
  Redefinition of \`MODEL ${command.key}\` in the pipeline head
10996
11048
 
10997
11049
  You have used:
@@ -11023,7 +11075,7 @@ const modelCommandParser = {
11023
11075
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
11024
11076
  }
11025
11077
  else {
11026
- throw new ParseError(spaceTrim(`
11078
+ throw new ParseError(spaceTrim$2(`
11027
11079
  Redefinition of MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}"
11028
11080
 
11029
11081
  You have used:
@@ -11033,7 +11085,7 @@ const modelCommandParser = {
11033
11085
  }
11034
11086
  }
11035
11087
  if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
11036
- console.log(spaceTrim(`
11088
+ console.log(spaceTrim$2(`
11037
11089
  Setting MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}" to the same value as in the pipeline head
11038
11090
 
11039
11091
  In pipeline head:
@@ -11116,7 +11168,7 @@ const parameterCommandParser = {
11116
11168
  // <- TODO: When [🥶] fixed, change to:
11117
11169
  // > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
11118
11170
  if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
11119
- throw new ParseError(spaceTrim((block) => `
11171
+ throw new ParseError(spaceTrim$2((block) => `
11120
11172
  Parameter \`{${parameterNameRaw}}\` can not contain another parameter in description
11121
11173
 
11122
11174
  The description:
@@ -11298,7 +11350,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
11298
11350
  persona.description = personaDescription;
11299
11351
  return;
11300
11352
  }
11301
- console.warn(spaceTrim(`
11353
+ console.warn(spaceTrim$2(`
11302
11354
 
11303
11355
  Persona "${personaName}" is defined multiple times with different description:
11304
11356
 
@@ -11309,7 +11361,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
11309
11361
  ${personaDescription}
11310
11362
 
11311
11363
  `));
11312
- persona.description += spaceTrim('\n\n' + personaDescription);
11364
+ persona.description += spaceTrim$2('\n\n' + personaDescription);
11313
11365
  }
11314
11366
 
11315
11367
  /**
@@ -12164,7 +12216,7 @@ function removeMarkdownComments(content) {
12164
12216
  */
12165
12217
  function isFlatPipeline(pipelineString) {
12166
12218
  pipelineString = removeMarkdownComments(pipelineString);
12167
- pipelineString = spaceTrim(pipelineString);
12219
+ pipelineString = spaceTrim$2(pipelineString);
12168
12220
  const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
12169
12221
  //const isLastLineReturnStatement = pipelineString.split('\n').pop()!.split('`').join('').startsWith('->');
12170
12222
  const isBacktickBlockUsed = pipelineString.includes('```');
@@ -12190,7 +12242,7 @@ function deflatePipeline(pipelineString) {
12190
12242
  if (!isFlatPipeline(pipelineString)) {
12191
12243
  return pipelineString;
12192
12244
  }
12193
- pipelineString = spaceTrim(pipelineString);
12245
+ pipelineString = spaceTrim$2(pipelineString);
12194
12246
  const pipelineStringLines = pipelineString.split('\n');
12195
12247
  const potentialReturnStatement = pipelineStringLines.pop();
12196
12248
  let returnStatement;
@@ -12203,19 +12255,19 @@ function deflatePipeline(pipelineString) {
12203
12255
  returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
12204
12256
  pipelineStringLines.push(potentialReturnStatement);
12205
12257
  }
12206
- const prompt = spaceTrim(pipelineStringLines.join('\n'));
12258
+ const prompt = spaceTrim$2(pipelineStringLines.join('\n'));
12207
12259
  let quotedPrompt;
12208
12260
  if (prompt.split('\n').length <= 1) {
12209
12261
  quotedPrompt = `> ${prompt}`;
12210
12262
  }
12211
12263
  else {
12212
- quotedPrompt = spaceTrim((block) => `
12264
+ quotedPrompt = spaceTrim$2((block) => `
12213
12265
  \`\`\`
12214
12266
  ${block(prompt.split('`').join('\\`'))}
12215
12267
  \`\`\`
12216
12268
  `);
12217
12269
  }
12218
- pipelineString = validatePipelineString(spaceTrim((block) => `
12270
+ pipelineString = validatePipelineString(spaceTrim$2((block) => `
12219
12271
  # ${DEFAULT_BOOK_TITLE}
12220
12272
 
12221
12273
  ## Prompt
@@ -12279,7 +12331,7 @@ function extractAllListItemsFromMarkdown(markdown) {
12279
12331
  function extractOneBlockFromMarkdown(markdown) {
12280
12332
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
12281
12333
  if (codeBlocks.length !== 1) {
12282
- throw new ParseError(spaceTrim((block) => `
12334
+ throw new ParseError(spaceTrim$2((block) => `
12283
12335
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
12284
12336
 
12285
12337
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -12304,7 +12356,7 @@ function parseMarkdownSection(value) {
12304
12356
  }
12305
12357
  const title = lines[0].replace(/^#+\s*/, '');
12306
12358
  const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
12307
- const content = spaceTrim(lines.slice(1).join('\n'));
12359
+ const content = spaceTrim$2(lines.slice(1).join('\n'));
12308
12360
  if (level < 1 || level > 6) {
12309
12361
  throw new ParseError('Markdown section must have heading level between 1 and 6');
12310
12362
  }
@@ -12332,7 +12384,7 @@ function splitMarkdownIntoSections(markdown) {
12332
12384
  if (buffer.length === 0) {
12333
12385
  return;
12334
12386
  }
12335
- let section = spaceTrim(buffer.join('\n'));
12387
+ let section = spaceTrim$2(buffer.join('\n'));
12336
12388
  if (section === '') {
12337
12389
  return;
12338
12390
  }
@@ -12407,7 +12459,7 @@ function flattenMarkdown(markdown) {
12407
12459
  flattenedMarkdown += `## ${title}` + `\n\n`;
12408
12460
  flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
12409
12461
  }
12410
- return spaceTrim(flattenedMarkdown);
12462
+ return spaceTrim$2(flattenedMarkdown);
12411
12463
  }
12412
12464
  /**
12413
12465
  * TODO: [🏛] This can be part of markdown builder
@@ -13008,7 +13060,7 @@ function renderPromptbookMermaid(pipelineJson, options) {
13008
13060
  * @public exported from `@promptbook/utils`
13009
13061
  */
13010
13062
  function computeHash(value) {
13011
- return SHA256(hexEncoder.parse(spaceTrim(valueToString(value)))).toString( /* hex */);
13063
+ return SHA256(hexEncoder.parse(spaceTrim$2(valueToString(value)))).toString( /* hex */);
13012
13064
  }
13013
13065
  /**
13014
13066
  * TODO: [🥬][🥬] Use this ACRY
@@ -13277,8 +13329,8 @@ class JavascriptEvalExecutionTools {
13277
13329
  }
13278
13330
  // Note: [💎]
13279
13331
  // Note: Using direct eval, following variables are in same scope as eval call so they are accessible from inside the evaluated script:
13280
- const spaceTrim$1 = (_) => spaceTrim(_);
13281
- $preserve(spaceTrim$1);
13332
+ const spaceTrim = (_) => spaceTrim$2(_);
13333
+ $preserve(spaceTrim);
13282
13334
  const removeQuotes$1 = removeQuotes;
13283
13335
  $preserve(removeQuotes$1);
13284
13336
  const unwrapResult$1 = unwrapResult;
@@ -13331,7 +13383,7 @@ class JavascriptEvalExecutionTools {
13331
13383
  // TODO: DRY [🍯]
13332
13384
  const buildinFunctions = {
13333
13385
  // TODO: [🍯] DRY all these functions across the file
13334
- spaceTrim: spaceTrim$1,
13386
+ spaceTrim,
13335
13387
  removeQuotes: removeQuotes$1,
13336
13388
  unwrapResult: unwrapResult$1,
13337
13389
  trimEndOfCodeBlock: trimEndOfCodeBlock$1,
@@ -13368,7 +13420,7 @@ class JavascriptEvalExecutionTools {
13368
13420
  .join('\n');
13369
13421
  // script = templateParameters(script, parameters);
13370
13422
  // <- TODO: [🧠][🥳] Should be this is one of two variants how to use parameters in script
13371
- const statementToEvaluate = spaceTrim((block) => `
13423
+ const statementToEvaluate = spaceTrim$2((block) => `
13372
13424
 
13373
13425
  // Build-in functions:
13374
13426
  ${block(buildinFunctionsStatement)}
@@ -13383,7 +13435,7 @@ class JavascriptEvalExecutionTools {
13383
13435
  (()=>{ ${script} })()
13384
13436
  `);
13385
13437
  if (this.options.isVerbose) {
13386
- console.info(spaceTrim((block) => `
13438
+ console.info(spaceTrim$2((block) => `
13387
13439
  🚀 Evaluating ${scriptLanguage} script:
13388
13440
 
13389
13441
  ${block(statementToEvaluate)}`));
@@ -13405,7 +13457,7 @@ class JavascriptEvalExecutionTools {
13405
13457
  To: [PipelineExecutionError: Parameter `{thing}` is not defined],
13406
13458
  */
13407
13459
  if (!statementToEvaluate.includes(undefinedName + '(')) {
13408
- throw new PipelineExecutionError(spaceTrim((block) => `
13460
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
13409
13461
 
13410
13462
  Parameter \`{${undefinedName}}\` is not defined
13411
13463
 
@@ -13427,7 +13479,7 @@ class JavascriptEvalExecutionTools {
13427
13479
  `));
13428
13480
  }
13429
13481
  else {
13430
- throw new PipelineExecutionError(spaceTrim((block) => `
13482
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
13431
13483
  Function ${undefinedName}() is not defined
13432
13484
 
13433
13485
  - Make sure that the function is one of built-in functions
@@ -13674,7 +13726,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13674
13726
  catch (error) {
13675
13727
  assertsError(error);
13676
13728
  // TODO: [7] DRY
13677
- const wrappedErrorMessage = spaceTrim((block) => `
13729
+ const wrappedErrorMessage = spaceTrim$2((block) => `
13678
13730
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
13679
13731
 
13680
13732
  Original error message:
@@ -13709,7 +13761,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13709
13761
  pipeline = { ...pipeline, pipelineUrl };
13710
13762
  }
13711
13763
  else if (!pipeline.pipelineUrl.startsWith(rootUrl)) {
13712
- throw new PipelineUrlError(spaceTrim(`
13764
+ throw new PipelineUrlError(spaceTrim$2(`
13713
13765
  Pipeline with URL ${pipeline.pipelineUrl} is not a child of the root URL ${rootUrl} 🍏
13714
13766
 
13715
13767
  File:
@@ -13747,7 +13799,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13747
13799
  }
13748
13800
  else {
13749
13801
  const existing = collection.get(pipeline.pipelineUrl);
13750
- throw new PipelineUrlError(spaceTrim(`
13802
+ throw new PipelineUrlError(spaceTrim$2(`
13751
13803
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍏
13752
13804
 
13753
13805
  Conflicting files:
@@ -13765,7 +13817,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13765
13817
  catch (error) {
13766
13818
  assertsError(error);
13767
13819
  // TODO: [7] DRY
13768
- const wrappedErrorMessage = spaceTrim((block) => `
13820
+ const wrappedErrorMessage = spaceTrim$2((block) => `
13769
13821
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
13770
13822
 
13771
13823
  Original error message:
@@ -13897,7 +13949,7 @@ function usageToHuman(usage) {
13897
13949
  // Note: For negligible usage, we report at least something
13898
13950
  reportItems.push('Negligible');
13899
13951
  }
13900
- return spaceTrim((block) => `
13952
+ return spaceTrim$2((block) => `
13901
13953
  Usage:
13902
13954
  ${block(reportItems.map((item) => `- ${item}`).join('\n'))}
13903
13955
  `);
@@ -13936,7 +13988,7 @@ async function $provideScriptingForNode(options) {
13936
13988
  */
13937
13989
  function $initializeMakeCommand(program) {
13938
13990
  const makeCommand = program.command('make');
13939
- makeCommand.description(spaceTrim(`
13991
+ makeCommand.description(spaceTrim$2(`
13940
13992
  Makes a new pipeline collection in given folder
13941
13993
  `));
13942
13994
  makeCommand.alias('compile');
@@ -13948,7 +14000,7 @@ function $initializeMakeCommand(program) {
13948
14000
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
13949
14001
  makeCommand.option('--project-name', `Name of the project for whom collection is`, 'Untitled Promptbook project');
13950
14002
  makeCommand.option('--root-url <url>', `Root URL of all pipelines to make`, undefined);
13951
- makeCommand.option('-f, --format <format>', spaceTrim(`
14003
+ makeCommand.option('-f, --format <format>', spaceTrim$2(`
13952
14004
  Output format of builded collection "bookc", "javascript", "typescript" or "json"
13953
14005
 
13954
14006
  Note: You can use multiple formats separated by comma
@@ -13956,14 +14008,14 @@ function $initializeMakeCommand(program) {
13956
14008
  makeCommand.option('--no-validation', `Do not validate logic of pipelines in collection`, true);
13957
14009
  makeCommand.option('--validation', `Types of validations separated by comma (options "logic","imports")`, 'logic,imports');
13958
14010
  makeCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
13959
- makeCommand.option('-o, --output <path>', spaceTrim(`
14011
+ makeCommand.option('-o, --output <path>', spaceTrim$2(`
13960
14012
  Where to save the builded collection
13961
14013
 
13962
14014
  Note: If you keep it "${DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME}" it will be saved in the root of the promptbook directory
13963
14015
  If you set it to a path, it will be saved in that path
13964
14016
  BUT you can use only one format and set correct extension
13965
14017
  `), DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME);
13966
- makeCommand.option('-fn, --function-name <functionName>', spaceTrim(`
14018
+ makeCommand.option('-fn, --function-name <functionName>', spaceTrim$2(`
13967
14019
  Name of the function to get pipeline collection
13968
14020
 
13969
14021
  Note: This can be used only with "javascript" or "typescript" format
@@ -14046,7 +14098,7 @@ function $initializeMakeCommand(program) {
14046
14098
  if (lastChar !== ']') {
14047
14099
  throw new UnexpectedError(`Last character of serialized collection should be "]" not "${lastChar}"`);
14048
14100
  }
14049
- return spaceTrim(collectionJsonString.substring(1, collectionJsonString.length - 1));
14101
+ return spaceTrim$2(collectionJsonString.substring(1, collectionJsonString.length - 1));
14050
14102
  })();
14051
14103
  const saveFile = async (extension, content) => {
14052
14104
  const filename = output !== DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME
@@ -14077,7 +14129,7 @@ function $initializeMakeCommand(program) {
14077
14129
  }
14078
14130
  if (formats.includes('javascript') || formats.includes('js')) {
14079
14131
  formats = formats.filter((format) => format !== 'javascript' && format !== 'js');
14080
- (await saveFile('js', spaceTrim((block) => `
14132
+ (await saveFile('js', spaceTrim$2((block) => `
14081
14133
  // ${block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI)}
14082
14134
 
14083
14135
  import { createPipelineCollectionFromJson } from '@promptbook/core';
@@ -14114,7 +14166,7 @@ function $initializeMakeCommand(program) {
14114
14166
  }
14115
14167
  if (formats.includes('typescript') || formats.includes('ts')) {
14116
14168
  formats = formats.filter((format) => format !== 'typescript' && format !== 'ts');
14117
- await saveFile('ts', spaceTrim((block) => `
14169
+ await saveFile('ts', spaceTrim$2((block) => `
14118
14170
  // ${block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI)}
14119
14171
 
14120
14172
  import { createPipelineCollectionFromJson } from '@promptbook/core';
@@ -14259,7 +14311,7 @@ async function prettifyPipelineString(pipelineString, options) {
14259
14311
  */
14260
14312
  function $initializePrettifyCommand(program) {
14261
14313
  const prettifyCommand = program.command('prettify');
14262
- prettifyCommand.description(spaceTrim(`
14314
+ prettifyCommand.description(spaceTrim$2(`
14263
14315
  Iterates over \`.book.md\` files and does multiple enhancing operations on them:
14264
14316
 
14265
14317
  1) Adds Mermaid graph
@@ -14715,7 +14767,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
14715
14767
  // console.log(`Strategy 3️⃣`);
14716
14768
  const response = await fetch(pipelineSource);
14717
14769
  if (response.status >= 300) {
14718
- throw new NotFoundError(spaceTrim((block) => `
14770
+ throw new NotFoundError(spaceTrim$2((block) => `
14719
14771
  Book not found on URL:
14720
14772
  ${block(pipelineSource)}
14721
14773
 
@@ -14725,7 +14777,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
14725
14777
  const pipelineString = await response.text();
14726
14778
  // console.log({ pipelineString });
14727
14779
  if (!isValidPipelineString(pipelineString)) {
14728
- throw new NotFoundError(spaceTrim((block) => `
14780
+ throw new NotFoundError(spaceTrim$2((block) => `
14729
14781
  Book not found on URL:
14730
14782
  ${block(pipelineSource)}
14731
14783
 
@@ -14747,7 +14799,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
14747
14799
  });
14748
14800
  return pipelineJson;
14749
14801
  } /* not else */
14750
- throw new NotFoundError(spaceTrim((block) => `
14802
+ throw new NotFoundError(spaceTrim$2((block) => `
14751
14803
  Book not found:
14752
14804
  ${block(pipelineSource)}
14753
14805
 
@@ -14794,7 +14846,7 @@ async function runInteractiveChatbot(options) {
14794
14846
  const initialMessage = (((_a = pipeline.parameters.find(({ name }) => name === 'chatbotResponse')) === null || _a === void 0 ? void 0 : _a.exampleValues) || [])[0];
14795
14847
  if (initialMessage) {
14796
14848
  console.info(`\n`);
14797
- console.info(spaceTrim((block) => `
14849
+ console.info(spaceTrim$2((block) => `
14798
14850
 
14799
14851
  ${colors.bold(colors.green('Chatbot:'))}
14800
14852
  ${block(colors.green(initialMessage))}
@@ -14817,7 +14869,7 @@ async function runInteractiveChatbot(options) {
14817
14869
  type: 'text',
14818
14870
  name: 'userMessage',
14819
14871
  message: 'User message',
14820
- hint: spaceTrim((block) => `
14872
+ hint: spaceTrim$2((block) => `
14821
14873
  Type "exit" to exit,
14822
14874
 
14823
14875
  previousTitle
@@ -14833,7 +14885,7 @@ async function runInteractiveChatbot(options) {
14833
14885
  return process.exit(0);
14834
14886
  }
14835
14887
  console.info(`\n`);
14836
- console.info(spaceTrim((block) => `
14888
+ console.info(spaceTrim$2((block) => `
14837
14889
 
14838
14890
  ${colors.bold(colors.blue('User:'))}
14839
14891
  ${block(colors.blue(userMessage))}
@@ -14846,7 +14898,7 @@ async function runInteractiveChatbot(options) {
14846
14898
  };
14847
14899
  const result = await pipelineExecutor(inputParameters).asPromise({ isCrashedOnError: true });
14848
14900
  console.info(`\n`);
14849
- console.info(spaceTrim((block) => `
14901
+ console.info(spaceTrim$2((block) => `
14850
14902
 
14851
14903
  ${colors.bold(colors.green('Chatbot:'))}
14852
14904
  ${block(colors.green(result.outputParameters.chatbotResponse))}
@@ -14877,7 +14929,7 @@ async function runInteractiveChatbot(options) {
14877
14929
  */
14878
14930
  function $initializeRunCommand(program) {
14879
14931
  const runCommand = program.command('run', { isDefault: true });
14880
- runCommand.description(spaceTrim(`
14932
+ runCommand.description(spaceTrim$2(`
14881
14933
  Runs a pipeline
14882
14934
  `));
14883
14935
  runCommand.alias('execute');
@@ -14920,7 +14972,7 @@ function $initializeRunCommand(program) {
14920
14972
  if (!error.message.includes('No LLM tools')) {
14921
14973
  throw error;
14922
14974
  }
14923
- console.error(colors.red(spaceTrim((block) => `
14975
+ console.error(colors.red(spaceTrim$2((block) => `
14924
14976
  You need to configure LLM tools first
14925
14977
 
14926
14978
  1) Create .env file at the root of your project
@@ -14983,7 +15035,7 @@ function $initializeRunCommand(program) {
14983
15035
  if (!(error instanceof ParseError)) {
14984
15036
  throw error;
14985
15037
  }
14986
- console.error(colors.red(spaceTrim((block) => `
15038
+ console.error(colors.red(spaceTrim$2((block) => `
14987
15039
  ${block(error.message)}
14988
15040
 
14989
15041
  in ${pipelineSource}
@@ -15035,7 +15087,7 @@ function $initializeRunCommand(program) {
15035
15087
  };
15036
15088
  });
15037
15089
  if (isInteractive === false && questions.length !== 0) {
15038
- console.error(colors.red(spaceTrim((block) => `
15090
+ console.error(colors.red(spaceTrim$2((block) => `
15039
15091
  When using --no-interactive you need to pass all the input parameters through --json
15040
15092
 
15041
15093
  You are missing:
@@ -15167,7 +15219,7 @@ function $initializeStartAgentsServerCommand(program) {
15167
15219
  'Path to agents directory', DEFAULT_AGENTS_DIRNAME);
15168
15220
  startServerCommand.option('--port <port>', `Port to start the server on`, '4440');
15169
15221
  startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
15170
- startServerCommand.description(spaceTrim(`
15222
+ startServerCommand.description(spaceTrim$2(`
15171
15223
  Starts a Promptbook agents server
15172
15224
  `));
15173
15225
  startServerCommand.alias('start');
@@ -16474,7 +16526,7 @@ function $initializeStartPipelinesServerCommand(program) {
16474
16526
  // <- TODO: [🧟‍♂️] Unite path to promptbook collection argument
16475
16527
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
16476
16528
  startServerCommand.option('--port <port>', `Port to start the server on`, '4460');
16477
- startServerCommand.option('-u, --url <url>', spaceTrim(`
16529
+ startServerCommand.option('-u, --url <url>', spaceTrim$2(`
16478
16530
  Public root url of the server
16479
16531
  It is used for following purposes:
16480
16532
 
@@ -16484,7 +16536,7 @@ function $initializeStartPipelinesServerCommand(program) {
16484
16536
  startServerCommand.option('--allow-anonymous', `Is anonymous mode allowed`, false);
16485
16537
  startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
16486
16538
  startServerCommand.option('--no-rich-ui', `Disable rich UI`, true);
16487
- startServerCommand.description(spaceTrim(`
16539
+ startServerCommand.description(spaceTrim$2(`
16488
16540
  Starts a remote server to execute books
16489
16541
 
16490
16542
  Note: You want probably to use "ptbk start-agents-server" to start agents server instead of pipelines server
@@ -16575,7 +16627,7 @@ function $initializeStartPipelinesServerCommand(program) {
16575
16627
  */
16576
16628
  function $initializeTestCommand(program) {
16577
16629
  const testCommand = program.command('test');
16578
- testCommand.description(spaceTrim(`
16630
+ testCommand.description(spaceTrim$2(`
16579
16631
  Iterates over \`.book.md\` and \`.bookc\` and checks if they are parsable and logically valid
16580
16632
  `));
16581
16633
  testCommand.argument('<filesGlob>',
@@ -17215,7 +17267,7 @@ class AnthropicClaudeExecutionTools {
17215
17267
  getDefaultModel(defaultModelName) {
17216
17268
  const model = ANTHROPIC_CLAUDE_MODELS.find(({ modelName }) => modelName.startsWith(defaultModelName));
17217
17269
  if (model === undefined) {
17218
- throw new UnexpectedError(spaceTrim((block) => `
17270
+ throw new UnexpectedError(spaceTrim$2((block) => `
17219
17271
  Cannot find model in Anthropic Claude models with name "${defaultModelName}" which should be used as default.
17220
17272
 
17221
17273
  Available models:
@@ -18437,7 +18489,7 @@ function createExecutionToolsFromVercelProvider(options) {
18437
18489
  const modelName = modelRequirements.modelName ||
18438
18490
  ((_a = availableModels.find(({ modelVariant }) => modelVariant === 'CHAT')) === null || _a === void 0 ? void 0 : _a.modelName);
18439
18491
  if (!modelName) {
18440
- throw new PipelineExecutionError(spaceTrim(`
18492
+ throw new PipelineExecutionError(spaceTrim$2(`
18441
18493
  Can not determine which model to use.
18442
18494
 
18443
18495
  You need to provide at least one of:
@@ -19775,7 +19827,7 @@ class OpenAiCompatibleExecutionTools {
19775
19827
  // Note: Match exact or prefix for model families
19776
19828
  const model = this.HARDCODED_MODELS.find(({ modelName }) => modelName === defaultModelName || modelName.startsWith(defaultModelName));
19777
19829
  if (model === undefined) {
19778
- throw new PipelineExecutionError(spaceTrim((block) => `
19830
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
19779
19831
  Cannot find model in ${this.title} models with name "${defaultModelName}" which should be used as default.
19780
19832
 
19781
19833
  Available models:
@@ -20519,18 +20571,26 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20519
20571
  modelName: 'assistant',
20520
20572
  // <- [🧠] What is the best value here
20521
20573
  });
20574
+ // Build thread messages: include previous thread messages + current user message
20575
+ const threadMessages = [];
20576
+ // TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
20577
+ // Add previous messages from thread (if any)
20578
+ if ('thread' in prompt &&
20579
+ Array.isArray(prompt.thread)) {
20580
+ const previousMessages = prompt.thread.map((msg) => ({
20581
+ role: (msg.role === 'assistant' ? 'assistant' : 'user'),
20582
+ content: msg.content,
20583
+ }));
20584
+ threadMessages.push(...previousMessages);
20585
+ }
20586
+ // Always add the current user message
20587
+ threadMessages.push({ role: 'user', content: rawPromptContent });
20522
20588
  const rawRequest = {
20523
20589
  // TODO: [👨‍👨‍👧‍👧] ...modelSettings,
20524
20590
  // TODO: [👨‍👨‍👧‍👧][🧠] What about system message for assistants, does it make sense - combination of OpenAI assistants with Promptbook Personas
20525
20591
  assistant_id: this.assistantId,
20526
20592
  thread: {
20527
- messages: 'thread' in prompt &&
20528
- Array.isArray(prompt.thread)
20529
- ? prompt.thread.map((msg) => ({
20530
- role: msg.role === 'assistant' ? 'assistant' : 'user',
20531
- content: msg.content,
20532
- }))
20533
- : [{ role: 'user', content: rawPromptContent }],
20593
+ messages: threadMessages,
20534
20594
  },
20535
20595
  // <- TODO: Add user identification here> user: this.options.user,
20536
20596
  };
@@ -20550,7 +20610,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20550
20610
  console.info('textDelta', textDelta.value);
20551
20611
  }
20552
20612
  const chunk = {
20553
- content: textDelta.value || '',
20613
+ content: snapshot.value,
20554
20614
  modelName: 'assistant',
20555
20615
  timing: {
20556
20616
  start,
@@ -21221,8 +21281,8 @@ class MarkdownScraper {
21221
21281
  knowledgeTextPieces.map(async (knowledgeTextPiece, i) => {
21222
21282
  // Note: These are just default values, they will be overwritten by the actual values:
21223
21283
  let name = `piece-${i}`;
21224
- let title = spaceTrim(knowledgeTextPiece.substring(0, 100));
21225
- const knowledgePieceContent = spaceTrim(knowledgeTextPiece);
21284
+ let title = spaceTrim$2(knowledgeTextPiece.substring(0, 100));
21285
+ const knowledgePieceContent = spaceTrim$2(knowledgeTextPiece);
21226
21286
  let keywords = [];
21227
21287
  const index = [];
21228
21288
  /*
@@ -21235,7 +21295,7 @@ class MarkdownScraper {
21235
21295
  isCrashedOnError: true,
21236
21296
  });
21237
21297
  const { title: titleRaw = 'Untitled' } = titleResult.outputParameters;
21238
- title = spaceTrim(titleRaw) /* <- TODO: Maybe do in pipeline */;
21298
+ title = spaceTrim$2(titleRaw) /* <- TODO: Maybe do in pipeline */;
21239
21299
  name = titleToName(title);
21240
21300
  // --- Keywords
21241
21301
  const keywordsResult = await prepareKeywordsExecutor({ knowledgePieceContent }).asPromise({
@@ -21390,7 +21450,7 @@ class BoilerplateScraper {
21390
21450
  await $execCommand(command);
21391
21451
  // Note: [0]
21392
21452
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
21393
- throw new UnexpectedError(spaceTrim((block) => `
21453
+ throw new UnexpectedError(spaceTrim$2((block) => `
21394
21454
  File that was supposed to be created by Pandoc does not exist for unknown reason
21395
21455
 
21396
21456
  Expected file:
@@ -21554,7 +21614,7 @@ class DocumentScraper {
21554
21614
  await $execCommand(command);
21555
21615
  // Note: [0]
21556
21616
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
21557
- throw new UnexpectedError(spaceTrim((block) => `
21617
+ throw new UnexpectedError(spaceTrim$2((block) => `
21558
21618
  File that was supposed to be created by Pandoc does not exist for unknown reason
21559
21619
 
21560
21620
  Expected file:
@@ -21705,7 +21765,7 @@ class LegacyDocumentScraper {
21705
21765
  await $execCommand(command);
21706
21766
  const files = await readdir(documentSourceOutdirPathForLibreOffice);
21707
21767
  if (files.length !== 1) {
21708
- throw new UnexpectedError(spaceTrim((block) => `
21768
+ throw new UnexpectedError(spaceTrim$2((block) => `
21709
21769
  Expected exactly 1 file in the LibreOffice output directory, got ${files.length}
21710
21770
 
21711
21771
  The temporary folder:
@@ -21719,7 +21779,7 @@ class LegacyDocumentScraper {
21719
21779
  await rename(join(documentSourceOutdirPathForLibreOffice, file), cacheFilehandler.filename);
21720
21780
  await rmdir(documentSourceOutdirPathForLibreOffice);
21721
21781
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
21722
- throw new UnexpectedError(spaceTrim((block) => `
21782
+ throw new UnexpectedError(spaceTrim$2((block) => `
21723
21783
  File that was supposed to be created by LibreOffice does not exist for unknown reason
21724
21784
 
21725
21785
  Expected file:
@@ -22412,15 +22472,19 @@ const _FormattedBookInMarkdownTranspilerRegistration = $bookTranspilersRegister.
22412
22472
  *
22413
22473
  * @private - TODO: [🧠] Maybe should be public?
22414
22474
  */
22415
- function createCommitmentRegex(commitment, aliases = []) {
22475
+ function createCommitmentRegex(commitment, aliases = [], requiresContent = true) {
22416
22476
  const allCommitments = [commitment, ...aliases];
22417
22477
  const patterns = allCommitments.map((c) => {
22418
22478
  const escapedCommitment = c.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
22419
22479
  return escapedCommitment.split(/\s+/).join('\\s+');
22420
22480
  });
22421
22481
  const keywordPattern = patterns.join('|');
22422
- const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b\\s+(?<contents>.+)$`, 'gim');
22423
- return regex;
22482
+ if (requiresContent) {
22483
+ return new RegExp(`^\\s*(?<type>${keywordPattern})\\b\\s+(?<contents>.+)$`, 'gim');
22484
+ }
22485
+ else {
22486
+ return new RegExp(`^\\s*(?<type>${keywordPattern})\\b(?:\\s+(?<contents>.+))?$`, 'gim');
22487
+ }
22424
22488
  }
22425
22489
  /**
22426
22490
  * Generates a regex pattern to match a specific commitment type
@@ -22453,12 +22517,20 @@ class BaseCommitmentDefinition {
22453
22517
  this.type = type;
22454
22518
  this.aliases = aliases;
22455
22519
  }
22520
+ /**
22521
+ * Whether this commitment requires content.
22522
+ * If true, regex will match only if there is content after the commitment keyword.
22523
+ * If false, regex will match even if there is no content.
22524
+ */
22525
+ get requiresContent() {
22526
+ return true;
22527
+ }
22456
22528
  /**
22457
22529
  * Creates a regex pattern to match this commitment in agent source
22458
22530
  * Uses the existing createCommitmentRegex function as internal helper
22459
22531
  */
22460
22532
  createRegex() {
22461
- return createCommitmentRegex(this.type, this.aliases);
22533
+ return createCommitmentRegex(this.type, this.aliases, this.requiresContent);
22462
22534
  }
22463
22535
  /**
22464
22536
  * Creates a regex pattern to match just the commitment type
@@ -22610,6 +22682,12 @@ class ClosedCommitmentDefinition extends BaseCommitmentDefinition {
22610
22682
  constructor() {
22611
22683
  super('CLOSED');
22612
22684
  }
22685
+ /**
22686
+ * The `CLOSED` commitment is standalone.
22687
+ */
22688
+ get requiresContent() {
22689
+ return false;
22690
+ }
22613
22691
  /**
22614
22692
  * Short one-line description of CLOSED.
22615
22693
  */
@@ -23097,227 +23175,6 @@ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
23097
23175
  * Note: [💞] Ignore a discrepancy between file name and entity name
23098
23176
  */
23099
23177
 
23100
- /**
23101
- * Placeholder commitment definition for commitments that are not yet implemented
23102
- *
23103
- * This commitment simply adds its content 1:1 into the system message,
23104
- * preserving the original behavior until proper implementation is added.
23105
- *
23106
- * @public exported from `@promptbook/core`
23107
- */
23108
- class NotYetImplementedCommitmentDefinition extends BaseCommitmentDefinition {
23109
- constructor(type) {
23110
- super(type);
23111
- }
23112
- /**
23113
- * Short one-line description of a placeholder commitment.
23114
- */
23115
- get description() {
23116
- return 'Placeholder commitment that appends content verbatim to the system message.';
23117
- }
23118
- /**
23119
- * Icon for this commitment.
23120
- */
23121
- get icon() {
23122
- return '🚧';
23123
- }
23124
- /**
23125
- * Markdown documentation available at runtime.
23126
- */
23127
- get documentation() {
23128
- return spaceTrim$1(`
23129
- # ${this.type}
23130
-
23131
- This commitment is not yet fully implemented.
23132
-
23133
- ## Key aspects
23134
-
23135
- - Content is appended directly to the system message.
23136
- - No special processing or validation is performed.
23137
- - Behavior preserved until proper implementation is added.
23138
-
23139
- ## Status
23140
-
23141
- - **Status:** Placeholder implementation
23142
- - **Effect:** Appends content prefixed by commitment type
23143
- - **Future:** Will be replaced with specialized logic
23144
-
23145
- ## Examples
23146
-
23147
- \`\`\`book
23148
- Example Agent
23149
-
23150
- PERSONA You are a helpful assistant
23151
- ${this.type} Your content here
23152
- RULE Always be helpful
23153
- \`\`\`
23154
- `);
23155
- }
23156
- applyToAgentModelRequirements(requirements, content) {
23157
- const trimmedContent = content.trim();
23158
- if (!trimmedContent) {
23159
- return requirements;
23160
- }
23161
- // Add the commitment content 1:1 to the system message
23162
- const commitmentLine = `${this.type} ${trimmedContent}`;
23163
- return this.appendToSystemMessage(requirements, commitmentLine, '\n\n');
23164
- }
23165
- }
23166
-
23167
- /**
23168
- * Registry of all available commitment definitions
23169
- * This array contains instances of all commitment definitions
23170
- * This is the single source of truth for all commitments in the system
23171
- *
23172
- * @private Use functions to access commitments instead of this array directly
23173
- */
23174
- const COMMITMENT_REGISTRY = [];
23175
- /**
23176
- * Registers a new commitment definition
23177
- * @param definition The commitment definition to register
23178
- *
23179
- * @public exported from `@promptbook/core`
23180
- */
23181
- function registerCommitment(definition) {
23182
- COMMITMENT_REGISTRY.push(definition);
23183
- }
23184
- /**
23185
- * Gets a commitment definition by its type
23186
- * @param type The commitment type to look up
23187
- * @returns The commitment definition or null if not found
23188
- *
23189
- * @public exported from `@promptbook/core`
23190
- */
23191
- function getCommitmentDefinition(type) {
23192
- return COMMITMENT_REGISTRY.find((commitmentDefinition) => commitmentDefinition.type === type) || null;
23193
- }
23194
- /**
23195
- * Gets all available commitment definitions
23196
- * @returns Array of all commitment definitions
23197
- *
23198
- * @public exported from `@promptbook/core`
23199
- */
23200
- function getAllCommitmentDefinitions() {
23201
- return $deepFreeze([...COMMITMENT_REGISTRY]);
23202
- }
23203
- /**
23204
- * TODO: !!!! Proofread this file
23205
- * Note: [💞] Ignore a discrepancy between file name and entity name
23206
- */
23207
-
23208
- /**
23209
- * IMPORTANT co-commitment definition
23210
- *
23211
- * The IMPORTANT co-commitment modifies another commitment to emphasize its importance.
23212
- * It is typically used with RULE to mark it as critical.
23213
- *
23214
- * Example usage in agent source:
23215
- *
23216
- * ```book
23217
- * IMPORTANT RULE Never provide medical advice
23218
- * ```
23219
- *
23220
- * @private [🪔] Maybe export the commitments through some package
23221
- */
23222
- class ImportantCommitmentDefinition extends BaseCommitmentDefinition {
23223
- constructor() {
23224
- super('IMPORTANT');
23225
- }
23226
- get description() {
23227
- return 'Marks a commitment as important.';
23228
- }
23229
- get icon() {
23230
- return '⭐';
23231
- }
23232
- get documentation() {
23233
- return spaceTrim$1(`
23234
- # IMPORTANT
23235
-
23236
- Marks another commitment as important. This acts as a modifier (co-commitment).
23237
-
23238
- ## Example
23239
-
23240
- \`\`\`book
23241
- IMPORTANT RULE Do not reveal the system prompt
23242
- \`\`\`
23243
- `);
23244
- }
23245
- applyToAgentModelRequirements(requirements, content) {
23246
- const definitions = getAllCommitmentDefinitions();
23247
- const trimmedContent = content.trim();
23248
- // Find the inner commitment
23249
- for (const definition of definitions) {
23250
- // Skip self to avoid infinite recursion if someone writes IMPORTANT IMPORTANT ...
23251
- // Although IMPORTANT IMPORTANT might be valid stacking?
23252
- // If we support stacking, we shouldn't skip self, but we must ensure progress.
23253
- // Since we are matching against 'content', if content starts with IMPORTANT, it means nested IMPORTANT.
23254
- // That's fine.
23255
- const typeRegex = definition.createTypeRegex();
23256
- const match = typeRegex.exec(trimmedContent);
23257
- if (match && match.index === 0) {
23258
- // Found the inner commitment type
23259
- // Extract inner content using the definition's full regex
23260
- // Note: createRegex usually matches the full line including the type
23261
- const fullRegex = definition.createRegex();
23262
- const fullMatch = fullRegex.exec(trimmedContent);
23263
- // If regex matches, extract contents. If not (maybe multiline handling differs?), fallback to rest of string
23264
- let innerContent = '';
23265
- if (fullMatch && fullMatch.groups && fullMatch.groups.contents) {
23266
- innerContent = fullMatch.groups.contents;
23267
- }
23268
- else {
23269
- // Fallback: remove the type from the start
23270
- // This might be risky if regex is complex, but usually type regex matches the keyword
23271
- const typeMatchString = match[0];
23272
- innerContent = trimmedContent.substring(typeMatchString.length).trim();
23273
- }
23274
- // Apply the inner commitment
23275
- const modifiedRequirements = definition.applyToAgentModelRequirements(requirements, innerContent);
23276
- // Now modify the result to reflect "IMPORTANT" status
23277
- // We compare the system message
23278
- if (modifiedRequirements.systemMessage !== requirements.systemMessage) {
23279
- const originalMsg = requirements.systemMessage;
23280
- const newMsg = modifiedRequirements.systemMessage;
23281
- // If the inner commitment appended something
23282
- if (newMsg.startsWith(originalMsg)) {
23283
- const appended = newMsg.substring(originalMsg.length);
23284
- // Add "IMPORTANT: " prefix to the appended part
23285
- // We need to be careful about newlines
23286
- // Heuristic: If appended starts with separator (newlines), preserve them
23287
- const matchSep = appended.match(/^(\s*)(.*)/s);
23288
- if (matchSep) {
23289
- const [, separator, text] = matchSep;
23290
- // Check if it already has "Rule:" prefix or similar
23291
- // We want "IMPORTANT Rule: ..."
23292
- // Let's just prepend IMPORTANT to the text
23293
- // But formatted nicely
23294
- // If it's a rule: "\n\nRule: content"
23295
- // We want "\n\nIMPORTANT Rule: content"
23296
- const importantText = `IMPORTANT ${text}`;
23297
- return {
23298
- ...modifiedRequirements,
23299
- systemMessage: originalMsg + separator + importantText
23300
- };
23301
- }
23302
- }
23303
- }
23304
- // If no system message change or we couldn't detect how to modify it, just return the modified requirements
23305
- // Maybe the inner commitment modified metadata?
23306
- return modifiedRequirements;
23307
- }
23308
- }
23309
- // If no inner commitment found, treat as a standalone note?
23310
- // Or warn?
23311
- // For now, treat as no-op or maybe just append as text?
23312
- // Let's treat as Note if fallback? No, explicit is better.
23313
- console.warn(`IMPORTANT commitment used without a valid inner commitment: ${content}`);
23314
- return requirements;
23315
- }
23316
- }
23317
- /**
23318
- * Note: [💞] Ignore a discrepancy between file name and entity name
23319
- */
23320
-
23321
23178
  /**
23322
23179
  * KNOWLEDGE commitment definition
23323
23180
  *
@@ -24081,6 +23938,12 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
24081
23938
  * META COLOR #00ff00
24082
23939
  * ```
24083
23940
  *
23941
+ * You can also specify multiple colors separated by comma:
23942
+ *
23943
+ * ```book
23944
+ * META COLOR #ff0000, #00ff00, #0000ff
23945
+ * ```
23946
+ *
24084
23947
  * @private [🪔] Maybe export the commitments through some package
24085
23948
  */
24086
23949
  class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
@@ -24091,7 +23954,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
24091
23954
  * Short one-line description of META COLOR.
24092
23955
  */
24093
23956
  get description() {
24094
- return "Set the agent's accent color.";
23957
+ return "Set the agent's accent color or gradient.";
24095
23958
  }
24096
23959
  /**
24097
23960
  * Icon for this commitment.
@@ -24106,7 +23969,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
24106
23969
  return spaceTrim$1(`
24107
23970
  # META COLOR
24108
23971
 
24109
- Sets the agent's accent color.
23972
+ Sets the agent's accent color or gradient.
24110
23973
 
24111
23974
  ## Key aspects
24112
23975
 
@@ -24114,6 +23977,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
24114
23977
  - Only one \`META COLOR\` should be used per agent.
24115
23978
  - If multiple are specified, the last one takes precedence.
24116
23979
  - Used for visual representation in user interfaces.
23980
+ - Can specify multiple colors separated by comma to create a gradient.
24117
23981
 
24118
23982
  ## Examples
24119
23983
 
@@ -24130,6 +23994,13 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
24130
23994
  META COLOR #e74c3c
24131
23995
  PERSONA You are a creative and inspiring assistant
24132
23996
  \`\`\`
23997
+
23998
+ \`\`\`book
23999
+ Gradient Agent
24000
+
24001
+ META COLOR #ff0000, #00ff00, #0000ff
24002
+ PERSONA You are a colorful agent
24003
+ \`\`\`
24133
24004
  `);
24134
24005
  }
24135
24006
  applyToAgentModelRequirements(requirements, content) {
@@ -24152,84 +24023,82 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
24152
24023
  */
24153
24024
 
24154
24025
  /**
24155
- * META IMAGE commitment definition
24026
+ * META FONT commitment definition
24156
24027
  *
24157
- * The META IMAGE commitment sets the agent's avatar/profile image URL.
24028
+ * The META FONT commitment sets the agent's font.
24158
24029
  * This commitment is special because it doesn't affect the system message,
24159
24030
  * but is handled separately in the parsing logic.
24160
24031
  *
24161
24032
  * Example usage in agent source:
24162
24033
  *
24163
24034
  * ```book
24164
- * META IMAGE https://example.com/avatar.jpg
24165
- * META IMAGE /assets/agent-avatar.png
24035
+ * META FONT Poppins, Arial, sans-serif
24036
+ * META FONT Roboto
24166
24037
  * ```
24167
24038
  *
24168
24039
  * @private [🪔] Maybe export the commitments through some package
24169
24040
  */
24170
- class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
24041
+ class MetaFontCommitmentDefinition extends BaseCommitmentDefinition {
24171
24042
  constructor() {
24172
- super('META IMAGE', ['IMAGE']);
24043
+ super('META FONT', ['FONT']);
24173
24044
  }
24174
24045
  /**
24175
- * Short one-line description of META IMAGE.
24046
+ * Short one-line description of META FONT.
24176
24047
  */
24177
24048
  get description() {
24178
- return "Set the agent's profile image URL.";
24049
+ return "Set the agent's font.";
24179
24050
  }
24180
24051
  /**
24181
24052
  * Icon for this commitment.
24182
24053
  */
24183
24054
  get icon() {
24184
- return '🖼️';
24055
+ return '🔤';
24185
24056
  }
24186
24057
  /**
24187
- * Markdown documentation for META IMAGE commitment.
24058
+ * Markdown documentation for META FONT commitment.
24188
24059
  */
24189
24060
  get documentation() {
24190
24061
  return spaceTrim$1(`
24191
- # META IMAGE
24062
+ # META FONT
24192
24063
 
24193
- Sets the agent's avatar/profile image URL.
24064
+ Sets the agent's font.
24194
24065
 
24195
24066
  ## Key aspects
24196
24067
 
24197
24068
  - Does not modify the agent's behavior or responses.
24198
- - Only one \`META IMAGE\` should be used per agent.
24069
+ - Only one \`META FONT\` should be used per agent.
24199
24070
  - If multiple are specified, the last one takes precedence.
24200
24071
  - Used for visual representation in user interfaces.
24072
+ - Supports Google Fonts.
24201
24073
 
24202
24074
  ## Examples
24203
24075
 
24204
24076
  \`\`\`book
24205
- Professional Assistant
24077
+ Modern Assistant
24206
24078
 
24207
- META IMAGE https://example.com/professional-avatar.jpg
24208
- PERSONA You are a professional business assistant
24209
- STYLE Maintain a formal and courteous tone
24079
+ META FONT Poppins, Arial, sans-serif
24080
+ PERSONA You are a modern assistant
24210
24081
  \`\`\`
24211
24082
 
24212
24083
  \`\`\`book
24213
- Creative Helper
24084
+ Classic Helper
24214
24085
 
24215
- META IMAGE /assets/creative-bot-avatar.png
24216
- PERSONA You are a creative and inspiring assistant
24217
- STYLE Be enthusiastic and encouraging
24218
- ACTION Can help with brainstorming and ideation
24086
+ META FONT Times New Roman
24087
+ PERSONA You are a classic helper
24219
24088
  \`\`\`
24220
24089
  `);
24221
24090
  }
24222
24091
  applyToAgentModelRequirements(requirements, content) {
24223
- // META IMAGE doesn't modify the system message or model requirements
24224
- // It's handled separately in the parsing logic for profile image extraction
24092
+ // META FONT doesn't modify the system message or model requirements
24093
+ // It's handled separately in the parsing logic
24225
24094
  // This method exists for consistency with the CommitmentDefinition interface
24226
24095
  return requirements;
24227
24096
  }
24228
24097
  /**
24229
- * Extracts the profile image URL from the content
24098
+ * Extracts the font from the content
24230
24099
  * This is used by the parsing logic
24231
24100
  */
24232
- extractProfileImageUrl(content) {
24101
+ extractProfileFont(content) {
24233
24102
  const trimmedContent = content.trim();
24234
24103
  return trimmedContent || null;
24235
24104
  }
@@ -24239,53 +24108,140 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
24239
24108
  */
24240
24109
 
24241
24110
  /**
24242
- * META LINK commitment definition
24111
+ * META IMAGE commitment definition
24243
24112
  *
24244
- * The `META LINK` commitment represents the link to the person from whom the agent is created.
24113
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
24245
24114
  * This commitment is special because it doesn't affect the system message,
24246
- * but is handled separately in the parsing logic for profile display.
24115
+ * but is handled separately in the parsing logic.
24247
24116
  *
24248
24117
  * Example usage in agent source:
24249
24118
  *
24250
- * ```
24251
- * META LINK https://twitter.com/username
24252
- * META LINK https://linkedin.com/in/profile
24253
- * META LINK https://github.com/username
24254
- * ```
24255
- *
24256
- * Multiple `META LINK` commitments can be used when there are multiple sources:
24257
- *
24258
24119
  * ```book
24259
- * META LINK https://twitter.com/username
24260
- * META LINK https://linkedin.com/in/profile
24120
+ * META IMAGE https://example.com/avatar.jpg
24121
+ * META IMAGE /assets/agent-avatar.png
24261
24122
  * ```
24262
24123
  *
24263
24124
  * @private [🪔] Maybe export the commitments through some package
24264
24125
  */
24265
- class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
24126
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
24266
24127
  constructor() {
24267
- super('META LINK');
24128
+ super('META IMAGE', ['IMAGE']);
24268
24129
  }
24269
24130
  /**
24270
- * Short one-line description of META LINK.
24131
+ * Short one-line description of META IMAGE.
24271
24132
  */
24272
24133
  get description() {
24273
- return 'Provide profile/source links for the person the agent models.';
24134
+ return "Set the agent's profile image URL.";
24274
24135
  }
24275
24136
  /**
24276
24137
  * Icon for this commitment.
24277
24138
  */
24278
24139
  get icon() {
24279
- return '🔗';
24140
+ return '🖼️';
24280
24141
  }
24281
24142
  /**
24282
- * Markdown documentation for META LINK commitment.
24143
+ * Markdown documentation for META IMAGE commitment.
24283
24144
  */
24284
24145
  get documentation() {
24285
24146
  return spaceTrim$1(`
24286
- # META LINK
24147
+ # META IMAGE
24287
24148
 
24288
- Represents a profile or source link for the person the agent is modeled after.
24149
+ Sets the agent's avatar/profile image URL.
24150
+
24151
+ ## Key aspects
24152
+
24153
+ - Does not modify the agent's behavior or responses.
24154
+ - Only one \`META IMAGE\` should be used per agent.
24155
+ - If multiple are specified, the last one takes precedence.
24156
+ - Used for visual representation in user interfaces.
24157
+
24158
+ ## Examples
24159
+
24160
+ \`\`\`book
24161
+ Professional Assistant
24162
+
24163
+ META IMAGE https://example.com/professional-avatar.jpg
24164
+ PERSONA You are a professional business assistant
24165
+ STYLE Maintain a formal and courteous tone
24166
+ \`\`\`
24167
+
24168
+ \`\`\`book
24169
+ Creative Helper
24170
+
24171
+ META IMAGE /assets/creative-bot-avatar.png
24172
+ PERSONA You are a creative and inspiring assistant
24173
+ STYLE Be enthusiastic and encouraging
24174
+ ACTION Can help with brainstorming and ideation
24175
+ \`\`\`
24176
+ `);
24177
+ }
24178
+ applyToAgentModelRequirements(requirements, content) {
24179
+ // META IMAGE doesn't modify the system message or model requirements
24180
+ // It's handled separately in the parsing logic for profile image extraction
24181
+ // This method exists for consistency with the CommitmentDefinition interface
24182
+ return requirements;
24183
+ }
24184
+ /**
24185
+ * Extracts the profile image URL from the content
24186
+ * This is used by the parsing logic
24187
+ */
24188
+ extractProfileImageUrl(content) {
24189
+ const trimmedContent = content.trim();
24190
+ return trimmedContent || null;
24191
+ }
24192
+ }
24193
+ /**
24194
+ * Note: [💞] Ignore a discrepancy between file name and entity name
24195
+ */
24196
+
24197
+ /**
24198
+ * META LINK commitment definition
24199
+ *
24200
+ * The `META LINK` commitment represents the link to the person from whom the agent is created.
24201
+ * This commitment is special because it doesn't affect the system message,
24202
+ * but is handled separately in the parsing logic for profile display.
24203
+ *
24204
+ * Example usage in agent source:
24205
+ *
24206
+ * ```
24207
+ * META LINK https://twitter.com/username
24208
+ * META LINK https://linkedin.com/in/profile
24209
+ * META LINK https://github.com/username
24210
+ * ```
24211
+ *
24212
+ * Multiple `META LINK` commitments can be used when there are multiple sources:
24213
+ *
24214
+ * ```book
24215
+ * META LINK https://twitter.com/username
24216
+ * META LINK https://linkedin.com/in/profile
24217
+ * ```
24218
+ *
24219
+ * @private [🪔] Maybe export the commitments through some package
24220
+ */
24221
+ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
24222
+ constructor() {
24223
+ super('META LINK');
24224
+ }
24225
+ /**
24226
+ * Short one-line description of META LINK.
24227
+ */
24228
+ get description() {
24229
+ return 'Provide profile/source links for the person the agent models.';
24230
+ }
24231
+ /**
24232
+ * Icon for this commitment.
24233
+ */
24234
+ get icon() {
24235
+ return '🔗';
24236
+ }
24237
+ /**
24238
+ * Markdown documentation for META LINK commitment.
24239
+ */
24240
+ get documentation() {
24241
+ return spaceTrim$1(`
24242
+ # META LINK
24243
+
24244
+ Represents a profile or source link for the person the agent is modeled after.
24289
24245
 
24290
24246
  ## Key aspects
24291
24247
 
@@ -25276,60 +25232,543 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
25276
25232
  * [💞] Ignore a discrepancy between file name and entity name
25277
25233
  */
25278
25234
 
25235
+ /**
25236
+ * USE commitment definition
25237
+ *
25238
+ * The USE commitment indicates that the agent should utilize specific tools or capabilities
25239
+ * to access and interact with external systems when necessary.
25240
+ *
25241
+ * Supported USE types:
25242
+ * - USE BROWSER: Enables the agent to use a web browser tool
25243
+ * - USE SEARCH ENGINE (future): Enables search engine access
25244
+ * - USE FILE SYSTEM (future): Enables file system operations
25245
+ * - USE MCP (future): Enables MCP server connections
25246
+ *
25247
+ * The content following the USE commitment is ignored (similar to NOTE).
25248
+ *
25249
+ * Example usage in agent source:
25250
+ *
25251
+ * ```book
25252
+ * USE BROWSER
25253
+ * USE SEARCH ENGINE
25254
+ * ```
25255
+ *
25256
+ * @private [🪔] Maybe export the commitments through some package
25257
+ */
25258
+ class UseCommitmentDefinition extends BaseCommitmentDefinition {
25259
+ constructor() {
25260
+ super('USE');
25261
+ }
25262
+ /**
25263
+ * Short one-line description of USE commitments.
25264
+ */
25265
+ get description() {
25266
+ return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, etc.).';
25267
+ }
25268
+ /**
25269
+ * Icon for this commitment.
25270
+ */
25271
+ get icon() {
25272
+ return '🔧';
25273
+ }
25274
+ /**
25275
+ * Markdown documentation for USE commitment.
25276
+ */
25277
+ get documentation() {
25278
+ return spaceTrim$1(`
25279
+ # USE
25280
+
25281
+ Enables the agent to use specific tools or capabilities for interacting with external systems.
25282
+
25283
+ ## Supported USE types
25284
+
25285
+ - **USE BROWSER** - Enables the agent to use a web browser tool to access and retrieve information from the internet
25286
+ - **USE SEARCH ENGINE** (future) - Enables search engine access
25287
+ - **USE FILE SYSTEM** (future) - Enables file system operations
25288
+ - **USE MCP** (future) - Enables MCP server connections
25289
+
25290
+ ## Key aspects
25291
+
25292
+ - The content following the USE commitment is ignored (similar to NOTE)
25293
+ - Multiple USE commitments can be specified to enable multiple capabilities
25294
+ - The actual tool usage is handled by the agent runtime
25295
+
25296
+ ## Examples
25297
+
25298
+ ### Basic browser usage
25299
+
25300
+ \`\`\`book
25301
+ Research Assistant
25302
+
25303
+ PERSONA You are a helpful research assistant
25304
+ USE BROWSER
25305
+ KNOWLEDGE Can search the web for up-to-date information
25306
+ \`\`\`
25307
+
25308
+ ### Multiple tools
25309
+
25310
+ \`\`\`book
25311
+ Data Analyst
25312
+
25313
+ PERSONA You are a data analyst assistant
25314
+ USE BROWSER
25315
+ USE FILE SYSTEM
25316
+ ACTION Can analyze data from various sources
25317
+ \`\`\`
25318
+ `);
25319
+ }
25320
+ applyToAgentModelRequirements(requirements, content) {
25321
+ // USE commitments don't modify the system message or model requirements directly
25322
+ // They are handled separately in the parsing logic for capability extraction
25323
+ // This method exists for consistency with the CommitmentDefinition interface
25324
+ return requirements;
25325
+ }
25326
+ /**
25327
+ * Extracts the tool type from the USE commitment
25328
+ * This is used by the parsing logic
25329
+ */
25330
+ extractToolType(content) {
25331
+ var _a, _b;
25332
+ const trimmedContent = content.trim();
25333
+ // The tool type is the first word after USE (already stripped)
25334
+ const match = trimmedContent.match(/^(\w+)/);
25335
+ 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;
25336
+ }
25337
+ /**
25338
+ * Checks if this is a known USE type
25339
+ */
25340
+ isKnownUseType(useType) {
25341
+ const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'FILE SYSTEM', 'MCP'];
25342
+ return knownTypes.includes(useType.toUpperCase());
25343
+ }
25344
+ }
25345
+ /**
25346
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25347
+ */
25348
+
25349
+ /**
25350
+ * USE BROWSER commitment definition
25351
+ *
25352
+ * The `USE BROWSER` commitment indicates that the agent should utilize a web browser tool
25353
+ * to access and retrieve up-to-date information from the internet when necessary.
25354
+ *
25355
+ * The content following `USE BROWSER` is ignored (similar to NOTE).
25356
+ *
25357
+ * Example usage in agent source:
25358
+ *
25359
+ * ```book
25360
+ * USE BROWSER
25361
+ * USE BROWSER This will be ignored
25362
+ * ```
25363
+ *
25364
+ * @private [🪔] Maybe export the commitments through some package
25365
+ */
25366
+ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
25367
+ constructor() {
25368
+ super('USE BROWSER', ['BROWSER']);
25369
+ }
25370
+ /**
25371
+ * The `USE BROWSER` commitment is standalone.
25372
+ */
25373
+ get requiresContent() {
25374
+ return false;
25375
+ }
25376
+ /**
25377
+ * Short one-line description of USE BROWSER.
25378
+ */
25379
+ get description() {
25380
+ return 'Enable the agent to use a web browser tool for accessing internet information.';
25381
+ }
25382
+ /**
25383
+ * Icon for this commitment.
25384
+ */
25385
+ get icon() {
25386
+ return '🌐';
25387
+ }
25388
+ /**
25389
+ * Markdown documentation for USE BROWSER commitment.
25390
+ */
25391
+ get documentation() {
25392
+ return spaceTrim$1(`
25393
+ # USE BROWSER
25394
+
25395
+ Enables the agent to use a web browser tool to access and retrieve up-to-date information from the internet.
25396
+
25397
+ ## Key aspects
25398
+
25399
+ - The content following \`USE BROWSER\` is ignored (similar to NOTE)
25400
+ - The actual browser tool usage is handled by the agent runtime
25401
+ - Allows the agent to fetch current information from websites
25402
+ - Useful for research tasks, fact-checking, and accessing dynamic content
25403
+
25404
+ ## Examples
25405
+
25406
+ \`\`\`book
25407
+ Research Assistant
25408
+
25409
+ PERSONA You are a helpful research assistant specialized in finding current information
25410
+ USE BROWSER
25411
+ RULE Always cite your sources when providing information from the web
25412
+ \`\`\`
25413
+
25414
+ \`\`\`book
25415
+ News Analyst
25416
+
25417
+ PERSONA You are a news analyst who stays up-to-date with current events
25418
+ USE BROWSER
25419
+ STYLE Present news in a balanced and objective manner
25420
+ ACTION Can search for and summarize news articles
25421
+ \`\`\`
25422
+
25423
+ \`\`\`book
25424
+ Company Lawyer
25425
+
25426
+ PERSONA You are a company lawyer providing legal advice
25427
+ USE BROWSER
25428
+ KNOWLEDGE Corporate law and legal procedures
25429
+ RULE Always recommend consulting with a licensed attorney for specific legal matters
25430
+ \`\`\`
25431
+ `);
25432
+ }
25433
+ applyToAgentModelRequirements(requirements, content) {
25434
+ // We simply mark that browser capability is enabled in metadata
25435
+ // Get existing metadata
25436
+ const existingMetadata = requirements.metadata || {};
25437
+ // Get existing tools array or create new one
25438
+ const existingTools = existingMetadata.tools || [];
25439
+ // Add 'browser' to tools if not already present
25440
+ const updatedTools = existingTools.includes('browser') ? existingTools : [...existingTools, 'browser'];
25441
+ // Return requirements with updated metadata
25442
+ return {
25443
+ ...requirements,
25444
+ metadata: {
25445
+ ...existingMetadata,
25446
+ tools: updatedTools,
25447
+ useBrowser: true,
25448
+ },
25449
+ };
25450
+ }
25451
+ }
25452
+ /**
25453
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25454
+ */
25455
+
25456
+ /**
25457
+ * USE MCP commitment definition
25458
+ *
25459
+ * The `USE MCP` commitment allows to specify an MCP server URL which the agent will connect to
25460
+ * for retrieving additional instructions and actions.
25461
+ *
25462
+ * The content following `USE MCP` is the URL of the MCP server.
25463
+ *
25464
+ * Example usage in agent source:
25465
+ *
25466
+ * ```book
25467
+ * USE MCP http://mcp-server-url.com
25468
+ * ```
25469
+ *
25470
+ * @private [🪔] Maybe export the commitments through some package
25471
+ */
25472
+ class UseMcpCommitmentDefinition extends BaseCommitmentDefinition {
25473
+ constructor() {
25474
+ super('USE MCP', ['MCP']);
25475
+ }
25476
+ /**
25477
+ * Short one-line description of USE MCP.
25478
+ */
25479
+ get description() {
25480
+ return 'Connects the agent to an external MCP server for additional capabilities.';
25481
+ }
25482
+ /**
25483
+ * Icon for this commitment.
25484
+ */
25485
+ get icon() {
25486
+ return '🔌';
25487
+ }
25488
+ /**
25489
+ * Markdown documentation for USE MCP commitment.
25490
+ */
25491
+ get documentation() {
25492
+ return spaceTrim$1(`
25493
+ # USE MCP
25494
+
25495
+ Connects the agent to an external Model Context Protocol (MCP) server.
25496
+
25497
+ ## Key aspects
25498
+
25499
+ - The content following \`USE MCP\` must be a valid URL
25500
+ - Multiple MCP servers can be connected by using multiple \`USE MCP\` commitments
25501
+ - The agent will have access to tools and resources provided by the MCP server
25502
+
25503
+ ## Example
25504
+
25505
+ \`\`\`book
25506
+ Company Lawyer
25507
+
25508
+ PERSONA You are a company lawyer.
25509
+ USE MCP http://legal-db.example.com
25510
+ \`\`\`
25511
+ `);
25512
+ }
25513
+ applyToAgentModelRequirements(requirements, content) {
25514
+ const mcpServerUrl = content.trim();
25515
+ if (!mcpServerUrl) {
25516
+ return requirements;
25517
+ }
25518
+ const existingMcpServers = requirements.mcpServers || [];
25519
+ // Avoid duplicates
25520
+ if (existingMcpServers.includes(mcpServerUrl)) {
25521
+ return requirements;
25522
+ }
25523
+ return {
25524
+ ...requirements,
25525
+ mcpServers: [...existingMcpServers, mcpServerUrl],
25526
+ };
25527
+ }
25528
+ }
25529
+ /**
25530
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25531
+ */
25532
+
25533
+ /**
25534
+ * USE SEARCH ENGINE commitment definition
25535
+ *
25536
+ * The `USE SEARCH ENGINE` commitment indicates that the agent should utilize a search engine tool
25537
+ * to access and retrieve up-to-date information from the internet when necessary.
25538
+ *
25539
+ * The content following `USE SEARCH ENGINE` is ignored (similar to NOTE).
25540
+ *
25541
+ * Example usage in agent source:
25542
+ *
25543
+ * ```book
25544
+ * USE SEARCH ENGINE
25545
+ * USE SEARCH ENGINE This will be ignored
25546
+ * ```
25547
+ *
25548
+ * @private [🪔] Maybe export the commitments through some package
25549
+ */
25550
+ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
25551
+ constructor() {
25552
+ super('USE SEARCH ENGINE', ['SEARCH ENGINE', 'SEARCH']);
25553
+ }
25554
+ /**
25555
+ * Short one-line description of USE SEARCH ENGINE.
25556
+ */
25557
+ get description() {
25558
+ return 'Enable the agent to use a search engine tool for accessing internet information.';
25559
+ }
25560
+ /**
25561
+ * Icon for this commitment.
25562
+ */
25563
+ get icon() {
25564
+ return '🔍';
25565
+ }
25566
+ /**
25567
+ * Markdown documentation for USE SEARCH ENGINE commitment.
25568
+ */
25569
+ get documentation() {
25570
+ return spaceTrim$1(`
25571
+ # USE SEARCH ENGINE
25572
+
25573
+ Enables the agent to use a search engine tool to access and retrieve up-to-date information from the internet.
25574
+
25575
+ ## Key aspects
25576
+
25577
+ - The content following \`USE SEARCH ENGINE\` is ignored (similar to NOTE)
25578
+ - The actual search engine tool usage is handled by the agent runtime
25579
+ - Allows the agent to search for current information from the web
25580
+ - Useful for research tasks, finding facts, and accessing dynamic content
25581
+
25582
+ ## Examples
25583
+
25584
+ \`\`\`book
25585
+ Research Assistant
25586
+
25587
+ PERSONA You are a helpful research assistant specialized in finding current information
25588
+ USE SEARCH ENGINE
25589
+ RULE Always cite your sources when providing information from the web
25590
+ \`\`\`
25591
+
25592
+ \`\`\`book
25593
+ Fact Checker
25594
+
25595
+ PERSONA You are a fact checker
25596
+ USE SEARCH ENGINE
25597
+ ACTION Search for claims and verify them against reliable sources
25598
+ \`\`\`
25599
+ `);
25600
+ }
25601
+ applyToAgentModelRequirements(requirements, content) {
25602
+ // We simply mark that search engine capability is enabled in metadata
25603
+ // Get existing metadata
25604
+ const existingMetadata = requirements.metadata || {};
25605
+ // Get existing tools array or create new one
25606
+ const existingTools = existingMetadata.tools || [];
25607
+ // Add 'search-engine' to tools if not already present
25608
+ const updatedTools = existingTools.includes('search-engine') ? existingTools : [...existingTools, 'search-engine'];
25609
+ // Return requirements with updated metadata
25610
+ return {
25611
+ ...requirements,
25612
+ metadata: {
25613
+ ...existingMetadata,
25614
+ tools: updatedTools,
25615
+ useSearchEngine: true,
25616
+ },
25617
+ };
25618
+ }
25619
+ }
25620
+ /**
25621
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25622
+ */
25623
+
25624
+ /**
25625
+ * Placeholder commitment definition for commitments that are not yet implemented
25626
+ *
25627
+ * This commitment simply adds its content 1:1 into the system message,
25628
+ * preserving the original behavior until proper implementation is added.
25629
+ *
25630
+ * @public exported from `@promptbook/core`
25631
+ */
25632
+ class NotYetImplementedCommitmentDefinition extends BaseCommitmentDefinition {
25633
+ constructor(type) {
25634
+ super(type);
25635
+ }
25636
+ /**
25637
+ * Short one-line description of a placeholder commitment.
25638
+ */
25639
+ get description() {
25640
+ return 'Placeholder commitment that appends content verbatim to the system message.';
25641
+ }
25642
+ /**
25643
+ * Icon for this commitment.
25644
+ */
25645
+ get icon() {
25646
+ return '🚧';
25647
+ }
25648
+ /**
25649
+ * Markdown documentation available at runtime.
25650
+ */
25651
+ get documentation() {
25652
+ return spaceTrim$1(`
25653
+ # ${this.type}
25654
+
25655
+ This commitment is not yet fully implemented.
25656
+
25657
+ ## Key aspects
25658
+
25659
+ - Content is appended directly to the system message.
25660
+ - No special processing or validation is performed.
25661
+ - Behavior preserved until proper implementation is added.
25662
+
25663
+ ## Status
25664
+
25665
+ - **Status:** Placeholder implementation
25666
+ - **Effect:** Appends content prefixed by commitment type
25667
+ - **Future:** Will be replaced with specialized logic
25668
+
25669
+ ## Examples
25670
+
25671
+ \`\`\`book
25672
+ Example Agent
25673
+
25674
+ PERSONA You are a helpful assistant
25675
+ ${this.type} Your content here
25676
+ RULE Always be helpful
25677
+ \`\`\`
25678
+ `);
25679
+ }
25680
+ applyToAgentModelRequirements(requirements, content) {
25681
+ const trimmedContent = content.trim();
25682
+ if (!trimmedContent) {
25683
+ return requirements;
25684
+ }
25685
+ // Add the commitment content 1:1 to the system message
25686
+ const commitmentLine = `${this.type} ${trimmedContent}`;
25687
+ return this.appendToSystemMessage(requirements, commitmentLine, '\n\n');
25688
+ }
25689
+ }
25690
+
25279
25691
  // Import all commitment definition classes
25280
- // Register fully implemented commitments
25281
- registerCommitment(new PersonaCommitmentDefinition('PERSONA'));
25282
- registerCommitment(new PersonaCommitmentDefinition('PERSONAE'));
25283
- registerCommitment(new KnowledgeCommitmentDefinition());
25284
- registerCommitment(new MemoryCommitmentDefinition('MEMORY'));
25285
- registerCommitment(new MemoryCommitmentDefinition('MEMORIES'));
25286
- registerCommitment(new StyleCommitmentDefinition('STYLE'));
25287
- registerCommitment(new StyleCommitmentDefinition('STYLES'));
25288
- registerCommitment(new RuleCommitmentDefinition('RULE'));
25289
- registerCommitment(new RuleCommitmentDefinition('RULES'));
25290
- registerCommitment(new LanguageCommitmentDefinition('LANGUAGE'));
25291
- registerCommitment(new LanguageCommitmentDefinition('LANGUAGES'));
25292
- registerCommitment(new SampleCommitmentDefinition('SAMPLE'));
25293
- registerCommitment(new SampleCommitmentDefinition('EXAMPLE'));
25294
- registerCommitment(new FormatCommitmentDefinition('FORMAT'));
25295
- registerCommitment(new FormatCommitmentDefinition('FORMATS'));
25296
- registerCommitment(new FromCommitmentDefinition('FROM'));
25297
- registerCommitment(new ModelCommitmentDefinition('MODEL'));
25298
- registerCommitment(new ModelCommitmentDefinition('MODELS'));
25299
- registerCommitment(new ActionCommitmentDefinition('ACTION'));
25300
- registerCommitment(new ActionCommitmentDefinition('ACTIONS'));
25301
- registerCommitment(new ComponentCommitmentDefinition());
25302
- registerCommitment(new MetaImageCommitmentDefinition());
25303
- registerCommitment(new MetaColorCommitmentDefinition());
25304
- registerCommitment(new MetaLinkCommitmentDefinition());
25305
- registerCommitment(new MetaCommitmentDefinition());
25306
- registerCommitment(new NoteCommitmentDefinition('NOTE'));
25307
- registerCommitment(new NoteCommitmentDefinition('NOTES'));
25308
- registerCommitment(new NoteCommitmentDefinition('COMMENT'));
25309
- registerCommitment(new NoteCommitmentDefinition('NONCE'));
25310
- registerCommitment(new GoalCommitmentDefinition('GOAL'));
25311
- registerCommitment(new GoalCommitmentDefinition('GOALS'));
25312
- registerCommitment(new ImportantCommitmentDefinition());
25313
- registerCommitment(new InitialMessageCommitmentDefinition());
25314
- registerCommitment(new UserMessageCommitmentDefinition());
25315
- registerCommitment(new AgentMessageCommitmentDefinition());
25316
- registerCommitment(new MessageCommitmentDefinition('MESSAGE'));
25317
- registerCommitment(new MessageCommitmentDefinition('MESSAGES'));
25318
- registerCommitment(new ScenarioCommitmentDefinition('SCENARIO'));
25319
- registerCommitment(new ScenarioCommitmentDefinition('SCENARIOS'));
25320
- registerCommitment(new DeleteCommitmentDefinition('DELETE'));
25321
- registerCommitment(new DeleteCommitmentDefinition('CANCEL'));
25322
- registerCommitment(new DeleteCommitmentDefinition('DISCARD'));
25323
- registerCommitment(new DeleteCommitmentDefinition('REMOVE'));
25324
- registerCommitment(new OpenCommitmentDefinition());
25325
- registerCommitment(new ClosedCommitmentDefinition());
25326
- // Register not yet implemented commitments
25327
- registerCommitment(new NotYetImplementedCommitmentDefinition('EXPECT'));
25328
- registerCommitment(new NotYetImplementedCommitmentDefinition('BEHAVIOUR'));
25329
- registerCommitment(new NotYetImplementedCommitmentDefinition('BEHAVIOURS'));
25330
- registerCommitment(new NotYetImplementedCommitmentDefinition('AVOID'));
25331
- registerCommitment(new NotYetImplementedCommitmentDefinition('AVOIDANCE'));
25332
- registerCommitment(new NotYetImplementedCommitmentDefinition('CONTEXT'));
25692
+ /**
25693
+ * Registry of all available commitment definitions
25694
+ * This array contains instances of all commitment definitions
25695
+ * This is the single source of truth for all commitments in the system
25696
+ *
25697
+ * @private Use functions to access commitments instead of this array directly
25698
+ */
25699
+ const COMMITMENT_REGISTRY = [
25700
+ // Fully implemented commitments
25701
+ new PersonaCommitmentDefinition('PERSONA'),
25702
+ new PersonaCommitmentDefinition('PERSONAE'),
25703
+ new KnowledgeCommitmentDefinition(),
25704
+ new MemoryCommitmentDefinition('MEMORY'),
25705
+ new MemoryCommitmentDefinition('MEMORIES'),
25706
+ new StyleCommitmentDefinition('STYLE'),
25707
+ new StyleCommitmentDefinition('STYLES'),
25708
+ new RuleCommitmentDefinition('RULE'),
25709
+ new RuleCommitmentDefinition('RULES'),
25710
+ new LanguageCommitmentDefinition('LANGUAGE'),
25711
+ new LanguageCommitmentDefinition('LANGUAGES'),
25712
+ new SampleCommitmentDefinition('SAMPLE'),
25713
+ new SampleCommitmentDefinition('EXAMPLE'),
25714
+ new FormatCommitmentDefinition('FORMAT'),
25715
+ new FormatCommitmentDefinition('FORMATS'),
25716
+ new FromCommitmentDefinition('FROM'),
25717
+ new ModelCommitmentDefinition('MODEL'),
25718
+ new ModelCommitmentDefinition('MODELS'),
25719
+ new ActionCommitmentDefinition('ACTION'),
25720
+ new ActionCommitmentDefinition('ACTIONS'),
25721
+ new ComponentCommitmentDefinition(),
25722
+ new MetaImageCommitmentDefinition(),
25723
+ new MetaColorCommitmentDefinition(),
25724
+ new MetaFontCommitmentDefinition(),
25725
+ new MetaLinkCommitmentDefinition(),
25726
+ new MetaCommitmentDefinition(),
25727
+ new NoteCommitmentDefinition('NOTE'),
25728
+ new NoteCommitmentDefinition('NOTES'),
25729
+ new NoteCommitmentDefinition('COMMENT'),
25730
+ new NoteCommitmentDefinition('NONCE'),
25731
+ new GoalCommitmentDefinition('GOAL'),
25732
+ new GoalCommitmentDefinition('GOALS'),
25733
+ new InitialMessageCommitmentDefinition(),
25734
+ new UserMessageCommitmentDefinition(),
25735
+ new AgentMessageCommitmentDefinition(),
25736
+ new MessageCommitmentDefinition('MESSAGE'),
25737
+ new MessageCommitmentDefinition('MESSAGES'),
25738
+ new ScenarioCommitmentDefinition('SCENARIO'),
25739
+ new ScenarioCommitmentDefinition('SCENARIOS'),
25740
+ new DeleteCommitmentDefinition('DELETE'),
25741
+ new DeleteCommitmentDefinition('CANCEL'),
25742
+ new DeleteCommitmentDefinition('DISCARD'),
25743
+ new DeleteCommitmentDefinition('REMOVE'),
25744
+ new OpenCommitmentDefinition(),
25745
+ new ClosedCommitmentDefinition(),
25746
+ new UseBrowserCommitmentDefinition(),
25747
+ new UseSearchEngineCommitmentDefinition(),
25748
+ new UseMcpCommitmentDefinition(),
25749
+ new UseCommitmentDefinition(),
25750
+ // Not yet implemented commitments (using placeholder)
25751
+ new NotYetImplementedCommitmentDefinition('EXPECT'),
25752
+ new NotYetImplementedCommitmentDefinition('BEHAVIOUR'),
25753
+ new NotYetImplementedCommitmentDefinition('BEHAVIOURS'),
25754
+ new NotYetImplementedCommitmentDefinition('AVOID'),
25755
+ new NotYetImplementedCommitmentDefinition('AVOIDANCE'),
25756
+ new NotYetImplementedCommitmentDefinition('CONTEXT'),
25757
+ ];
25758
+ /**
25759
+ * Gets a commitment definition by its type
25760
+ * @param type The commitment type to look up
25761
+ * @returns The commitment definition or null if not found
25762
+ *
25763
+ * @public exported from `@promptbook/core`
25764
+ */
25765
+ function getCommitmentDefinition(type) {
25766
+ return COMMITMENT_REGISTRY.find((commitmentDefinition) => commitmentDefinition.type === type) || null;
25767
+ }
25768
+ /**
25769
+ * TODO: [🧠] Maybe create through standardized $register
25770
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25771
+ */
25333
25772
 
25334
25773
  /**
25335
25774
  * Creates an empty/basic agent model requirements object
@@ -25365,6 +25804,11 @@ function createBasicAgentModelRequirements(agentName) {
25365
25804
  * TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
25366
25805
  */
25367
25806
 
25807
+ /**
25808
+ * Regex pattern to match horizontal lines (markdown thematic breaks)
25809
+ * Matches 3 or more hyphens, underscores, or asterisks (with optional spaces between)
25810
+ */
25811
+ const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
25368
25812
  /**
25369
25813
  * Parses agent source using the new commitment system with multiline support
25370
25814
  * This function replaces the hardcoded commitment parsing in the original parseAgentSource
@@ -25427,6 +25871,24 @@ function parseAgentSourceWithCommitments(agentSource) {
25427
25871
  break;
25428
25872
  }
25429
25873
  }
25874
+ // Check if this is a horizontal line (ends any current commitment)
25875
+ const isHorizontalLine = HORIZONTAL_LINE_PATTERN.test(line);
25876
+ if (isHorizontalLine) {
25877
+ // Save the current commitment if it exists
25878
+ if (currentCommitment) {
25879
+ const fullContent = currentCommitment.contentLines.join('\n');
25880
+ commitments.push({
25881
+ type: currentCommitment.type,
25882
+ content: spaceTrim$1(fullContent),
25883
+ originalLine: currentCommitment.originalStartLine,
25884
+ lineNumber: currentCommitment.startLineNumber,
25885
+ });
25886
+ currentCommitment = null;
25887
+ }
25888
+ // Add horizontal line to non-commitment lines
25889
+ nonCommitmentLines.push(line);
25890
+ continue;
25891
+ }
25430
25892
  if (!foundNewCommitment) {
25431
25893
  if (currentCommitment) {
25432
25894
  // This line belongs to the current commitment
@@ -25689,7 +26151,7 @@ function computeAgentHash(agentSource) {
25689
26151
  * @public exported from `@promptbook/core`
25690
26152
  */
25691
26153
  function normalizeAgentName(rawAgentName) {
25692
- return titleToName(spaceTrim(rawAgentName));
26154
+ return titleToName(spaceTrim$2(rawAgentName));
25693
26155
  }
25694
26156
 
25695
26157
  /**
@@ -25741,17 +26203,21 @@ function parseAgentSource(agentSource) {
25741
26203
  const links = [];
25742
26204
  for (const commitment of parseResult.commitments) {
25743
26205
  if (commitment.type === 'META LINK') {
25744
- const linkValue = spaceTrim(commitment.content);
26206
+ const linkValue = spaceTrim$2(commitment.content);
25745
26207
  links.push(linkValue);
25746
26208
  meta.link = linkValue;
25747
26209
  continue;
25748
26210
  }
25749
26211
  if (commitment.type === 'META IMAGE') {
25750
- meta.image = spaceTrim(commitment.content);
26212
+ meta.image = spaceTrim$2(commitment.content);
25751
26213
  continue;
25752
26214
  }
25753
26215
  if (commitment.type === 'META COLOR') {
25754
- meta.color = spaceTrim(commitment.content);
26216
+ meta.color = normalizeSeparator(commitment.content);
26217
+ continue;
26218
+ }
26219
+ if (commitment.type === 'META FONT') {
26220
+ meta.font = normalizeSeparator(commitment.content);
25755
26221
  continue;
25756
26222
  }
25757
26223
  if (commitment.type !== 'META') {
@@ -25760,10 +26226,10 @@ function parseAgentSource(agentSource) {
25760
26226
  // Parse META commitments - format is "META TYPE content"
25761
26227
  const metaTypeRaw = commitment.content.split(' ')[0] || 'NONE';
25762
26228
  if (metaTypeRaw === 'LINK') {
25763
- links.push(spaceTrim(commitment.content.substring(metaTypeRaw.length)));
26229
+ links.push(spaceTrim$2(commitment.content.substring(metaTypeRaw.length)));
25764
26230
  }
25765
26231
  const metaType = normalizeTo_camelCase(metaTypeRaw);
25766
- meta[metaType] = spaceTrim(commitment.content.substring(metaTypeRaw.length));
26232
+ meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
25767
26233
  }
25768
26234
  // Generate gravatar fallback if no meta image specified
25769
26235
  if (!meta.image) {
@@ -25787,6 +26253,19 @@ function parseAgentSource(agentSource) {
25787
26253
  parameters,
25788
26254
  };
25789
26255
  }
26256
+ /**
26257
+ * Normalizes the separator in the content
26258
+ *
26259
+ * @param content - The content to normalize
26260
+ * @returns The content with normalized separators
26261
+ */
26262
+ function normalizeSeparator(content) {
26263
+ const trimmed = spaceTrim$2(content);
26264
+ if (trimmed.includes(',')) {
26265
+ return trimmed;
26266
+ }
26267
+ return trimmed.split(/\s+/).join(', ');
26268
+ }
25790
26269
  /**
25791
26270
  * TODO: [🕛] Unite `AgentBasicInformation`, `ChatParticipant`, `LlmExecutionTools` + `LlmToolsMetadata`
25792
26271
  */
@@ -25915,7 +26394,7 @@ const OpenAiSdkTranspiler = {
25915
26394
  });
25916
26395
  const KNOWLEDGE_THRESHOLD = 1000;
25917
26396
  if (directKnowledge.join('\n').length > KNOWLEDGE_THRESHOLD || knowledgeSources.length > 0) {
25918
- return spaceTrim((block) => `
26397
+ return spaceTrim$2((block) => `
25919
26398
  #!/usr/bin/env node
25920
26399
 
25921
26400
  import * as dotenv from 'dotenv';
@@ -25980,7 +26459,7 @@ const OpenAiSdkTranspiler = {
25980
26459
  }
25981
26460
 
25982
26461
  const userMessage = spaceTrim(\`
25983
- ${block(spaceTrim(`
26462
+ ${block(spaceTrim$2(`
25984
26463
  Here is some additional context to help you answer the question:
25985
26464
  \${context}
25986
26465
 
@@ -26025,7 +26504,7 @@ const OpenAiSdkTranspiler = {
26025
26504
  })();
26026
26505
  `);
26027
26506
  }
26028
- const source = spaceTrim((block) => `
26507
+ const source = spaceTrim$2((block) => `
26029
26508
 
26030
26509
  #!/usr/bin/env node
26031
26510