@promptbook/cli 0.103.0-54 → 0.103.0-56

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/apps/agents-server/config.ts +0 -2
  2. package/apps/agents-server/package-lock.json +1163 -0
  3. package/apps/agents-server/package.json +6 -0
  4. package/apps/agents-server/src/app/admin/chat-feedback/ChatFeedbackClient.tsx +79 -6
  5. package/apps/agents-server/src/app/admin/chat-history/ChatHistoryClient.tsx +171 -69
  6. package/apps/agents-server/src/app/agents/[agentName]/AgentChatWrapper.tsx +3 -1
  7. package/apps/agents-server/src/app/agents/[agentName]/AgentOptionsMenu.tsx +216 -0
  8. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileChat.tsx +78 -0
  9. package/apps/agents-server/src/app/agents/[agentName]/AgentProfileView.tsx +233 -0
  10. package/apps/agents-server/src/app/agents/[agentName]/CloneAgentButton.tsx +4 -4
  11. package/apps/agents-server/src/app/agents/[agentName]/InstallPwaButton.tsx +2 -2
  12. package/apps/agents-server/src/app/agents/[agentName]/QrCodeModal.tsx +90 -0
  13. package/apps/agents-server/src/app/agents/[agentName]/agentLinks.tsx +80 -0
  14. package/apps/agents-server/src/app/agents/[agentName]/api/book/route.ts +3 -1
  15. package/apps/agents-server/src/app/agents/[agentName]/api/chat/route.ts +11 -1
  16. package/apps/agents-server/src/app/agents/[agentName]/api/mcp/route.ts +203 -0
  17. package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/route.ts +3 -1
  18. package/apps/agents-server/src/app/agents/[agentName]/api/modelRequirements/systemMessage/route.ts +3 -1
  19. package/apps/agents-server/src/app/agents/[agentName]/api/openai/chat/completions/route.ts +3 -169
  20. package/apps/agents-server/src/app/agents/[agentName]/api/openai/models/route.ts +93 -0
  21. package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/chat/completions/route.ts +10 -0
  22. package/apps/agents-server/src/app/agents/[agentName]/api/openai/v1/models/route.ts +93 -0
  23. package/apps/agents-server/src/app/agents/[agentName]/api/openrouter/chat/completions/route.ts +10 -0
  24. package/apps/agents-server/src/app/agents/[agentName]/api/voice/route.ts +4 -0
  25. package/apps/agents-server/src/app/agents/[agentName]/chat/page.tsx +9 -2
  26. package/apps/agents-server/src/app/agents/[agentName]/integration/SdkCodeTabs.tsx +31 -0
  27. package/apps/agents-server/src/app/agents/[agentName]/integration/page.tsx +271 -30
  28. package/apps/agents-server/src/app/agents/[agentName]/links/page.tsx +182 -0
  29. package/apps/agents-server/src/app/agents/[agentName]/page.tsx +108 -165
  30. package/apps/agents-server/src/app/agents/[agentName]/website-integration/page.tsx +61 -0
  31. package/apps/agents-server/src/app/api/auth/change-password/route.ts +75 -0
  32. package/apps/agents-server/src/app/api/chat-feedback/export/route.ts +55 -0
  33. package/apps/agents-server/src/app/api/chat-history/export/route.ts +55 -0
  34. package/apps/agents-server/src/app/api/openai/v1/chat/completions/route.ts +6 -0
  35. package/apps/agents-server/src/app/api/openai/v1/models/route.ts +65 -0
  36. package/apps/agents-server/src/app/docs/[docId]/page.tsx +12 -32
  37. package/apps/agents-server/src/app/docs/page.tsx +42 -17
  38. package/apps/agents-server/src/app/globals.css +129 -0
  39. package/apps/agents-server/src/app/layout.tsx +8 -2
  40. package/apps/agents-server/src/app/manifest.ts +1 -1
  41. package/apps/agents-server/src/components/ChangePasswordDialog/ChangePasswordDialog.tsx +41 -0
  42. package/apps/agents-server/src/components/ChangePasswordForm/ChangePasswordForm.tsx +159 -0
  43. package/apps/agents-server/src/components/DocumentationContent/DocumentationContent.tsx +87 -0
  44. package/apps/agents-server/src/components/Header/Header.tsx +94 -38
  45. package/apps/agents-server/src/components/OpenMojiIcon/OpenMojiIcon.tsx +20 -0
  46. package/apps/agents-server/src/components/PrintButton/PrintButton.tsx +18 -0
  47. package/apps/agents-server/src/components/PrintHeader/PrintHeader.tsx +18 -0
  48. package/apps/agents-server/src/database/migrations/2025-12-0070-chat-history-source.sql +2 -0
  49. package/apps/agents-server/src/database/schema.ts +6 -0
  50. package/apps/agents-server/src/middleware.ts +1 -1
  51. package/apps/agents-server/src/utils/convertToCsv.ts +31 -0
  52. package/apps/agents-server/src/utils/handleChatCompletion.ts +355 -0
  53. package/apps/agents-server/src/utils/resolveInheritedAgentSource.ts +100 -0
  54. package/apps/agents-server/src/utils/validateApiKey.ts +128 -0
  55. package/apps/agents-server/tailwind.config.ts +1 -1
  56. package/esm/index.es.js +1188 -175
  57. package/esm/index.es.js.map +1 -1
  58. package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +4 -0
  59. package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +5 -0
  60. package/esm/typings/src/commitments/CLOSED/CLOSED.d.ts +35 -0
  61. package/esm/typings/src/commitments/COMPONENT/COMPONENT.d.ts +28 -0
  62. package/esm/typings/src/commitments/FROM/FROM.d.ts +34 -0
  63. package/esm/typings/src/commitments/LANGUAGE/LANGUAGE.d.ts +35 -0
  64. package/esm/typings/src/commitments/META_COLOR/META_COLOR.d.ts +6 -0
  65. package/esm/typings/src/commitments/META_FONT/META_FONT.d.ts +42 -0
  66. package/esm/typings/src/commitments/OPEN/OPEN.d.ts +35 -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 +38 -0
  69. package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.test.d.ts +1 -0
  70. package/esm/typings/src/commitments/USE_MCP/USE_MCP.d.ts +37 -0
  71. package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +38 -0
  72. package/esm/typings/src/commitments/index.d.ts +12 -1
  73. package/esm/typings/src/playground/playground.d.ts +3 -0
  74. package/esm/typings/src/utils/color/Color.d.ts +8 -0
  75. package/esm/typings/src/utils/color/css-colors.d.ts +1 -0
  76. package/esm/typings/src/version.d.ts +1 -1
  77. package/package.json +2 -2
  78. package/umd/index.umd.js +1180 -167
  79. package/umd/index.umd.js.map +1 -1
  80. 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-54';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.103.0-56';
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',
@@ -377,6 +389,28 @@ class Color {
377
389
  throw new Error(`Can not create color from given object`);
378
390
  }
379
391
  }
392
+ /**
393
+ * Creates a new Color instance from miscellaneous formats
394
+ * It just does not throw error when it fails, it returns PROMPTBOOK_COLOR instead
395
+ *
396
+ * @param color
397
+ * @returns Color object
398
+ */
399
+ static fromSafe(color) {
400
+ try {
401
+ return Color.from(color);
402
+ }
403
+ catch (error) {
404
+ // <- Note: Can not use `assertsError(error)` here because it causes circular dependency
405
+ console.warn(spaceTrim((block) => `
406
+ Color.fromSafe error:
407
+ ${block(error.message)}
408
+
409
+ Returning default PROMPTBOOK_COLOR.
410
+ `));
411
+ return Color.fromString('promptbook');
412
+ }
413
+ }
380
414
  /**
381
415
  * Creates a new Color instance from miscellaneous string formats
382
416
  *
@@ -1000,7 +1034,7 @@ const CLAIM = `Turn your company's scattered knowledge into AI ready books`;
1000
1034
  *
1001
1035
  * @public exported from `@promptbook/core`
1002
1036
  */
1003
- const PROMPTBOOK_COLOR = Color.fromHex('#79EAFD');
1037
+ const PROMPTBOOK_COLOR = Color.fromString('promptbook');
1004
1038
  // <- TODO: [🧠][🈵] Using `Color` here increases the package size approx 3kb, maybe remove it
1005
1039
  /**
1006
1040
  * Colors for syntax highlighting in the `<BookEditor/>`
@@ -1398,7 +1432,7 @@ const $isRunningInWebWorker = new Function(`
1398
1432
  function getErrorReportUrl(error) {
1399
1433
  const report = {
1400
1434
  title: `🐜 Error report from ${NAME}`,
1401
- body: spaceTrim((block) => `
1435
+ body: spaceTrim$2((block) => `
1402
1436
 
1403
1437
 
1404
1438
  \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
@@ -1537,7 +1571,7 @@ function handleActionErrors(action) {
1537
1571
  */
1538
1572
  function $initializeAboutCommand(program) {
1539
1573
  const makeCommand = program.command('about');
1540
- makeCommand.description(spaceTrim(`
1574
+ makeCommand.description(spaceTrim$2(`
1541
1575
  Tells about Promptbook CLI and its abilities
1542
1576
  `));
1543
1577
  makeCommand.action(handleActionErrors(async () => {
@@ -1585,7 +1619,7 @@ function $initializeAboutCommand(program) {
1585
1619
  */
1586
1620
  function $initializeHelloCommand(program) {
1587
1621
  const helloCommand = program.command('hello');
1588
- helloCommand.description(spaceTrim(`
1622
+ helloCommand.description(spaceTrim$2(`
1589
1623
  Just command for testing
1590
1624
  `));
1591
1625
  helloCommand.alias('hi');
@@ -1847,13 +1881,13 @@ function $registeredLlmToolsMessage() {
1847
1881
  });
1848
1882
  const usedEnvMessage = $usedEnvFilename === null ? `Unknown \`.env\` file` : `Used \`.env\` file:\n${$usedEnvFilename}`;
1849
1883
  if (metadata.length === 0) {
1850
- return spaceTrim((block) => `
1884
+ return spaceTrim$2((block) => `
1851
1885
  No LLM providers are available.
1852
1886
 
1853
1887
  ${block(usedEnvMessage)}
1854
1888
  `);
1855
1889
  }
1856
- return spaceTrim((block) => `
1890
+ return spaceTrim$2((block) => `
1857
1891
 
1858
1892
  ${block(usedEnvMessage)}
1859
1893
 
@@ -1899,7 +1933,7 @@ function $registeredLlmToolsMessage() {
1899
1933
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
1900
1934
  }
1901
1935
  }
1902
- let providerMessage = spaceTrim(`
1936
+ let providerMessage = spaceTrim$2(`
1903
1937
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
1904
1938
  ${morePieces.join('; ')}
1905
1939
  `);
@@ -1965,7 +1999,7 @@ function jsonParse(value) {
1965
1999
  }
1966
2000
  else if (typeof value !== 'string') {
1967
2001
  console.error('Can not parse JSON from non-string value.', { text: value });
1968
- throw new Error(spaceTrim(`
2002
+ throw new Error(spaceTrim$2(`
1969
2003
  Can not parse JSON from non-string value.
1970
2004
 
1971
2005
  The value type: ${typeof value}
@@ -1979,7 +2013,7 @@ function jsonParse(value) {
1979
2013
  if (!(error instanceof Error)) {
1980
2014
  throw error;
1981
2015
  }
1982
- throw new Error(spaceTrim((block) => `
2016
+ throw new Error(spaceTrim$2((block) => `
1983
2017
  ${block(error.message)}
1984
2018
 
1985
2019
  The expected JSON text:
@@ -2200,7 +2234,7 @@ class $EnvStorage {
2200
2234
  .filter((line) => !line.startsWith(`# ${GENERATOR_WARNING_IN_ENV}`)) // Remove GENERATOR_WARNING_IN_ENV
2201
2235
  .filter((line) => !line.startsWith(`${transformedKey}=`)) // Remove existing key if present
2202
2236
  .join('\n');
2203
- const newEnvContent = spaceTrim((block) => `
2237
+ const newEnvContent = spaceTrim$2((block) => `
2204
2238
  ${block(updatedEnvContent)}
2205
2239
 
2206
2240
  # ${GENERATOR_WARNING_IN_ENV}
@@ -2311,7 +2345,7 @@ function checkSerializableAsJson(options) {
2311
2345
  }
2312
2346
  else if (typeof value === 'object') {
2313
2347
  if (value instanceof Date) {
2314
- throw new UnexpectedError(spaceTrim((block) => `
2348
+ throw new UnexpectedError(spaceTrim$2((block) => `
2315
2349
  \`${name}\` is Date
2316
2350
 
2317
2351
  Use \`string_date_iso8601\` instead
@@ -2330,7 +2364,7 @@ function checkSerializableAsJson(options) {
2330
2364
  throw new UnexpectedError(`${name} is RegExp`);
2331
2365
  }
2332
2366
  else if (value instanceof Error) {
2333
- throw new UnexpectedError(spaceTrim((block) => `
2367
+ throw new UnexpectedError(spaceTrim$2((block) => `
2334
2368
  \`${name}\` is unserialized Error
2335
2369
 
2336
2370
  Use function \`serializeError\`
@@ -2353,7 +2387,7 @@ function checkSerializableAsJson(options) {
2353
2387
  }
2354
2388
  catch (error) {
2355
2389
  assertsError(error);
2356
- throw new UnexpectedError(spaceTrim((block) => `
2390
+ throw new UnexpectedError(spaceTrim$2((block) => `
2357
2391
  \`${name}\` is not serializable
2358
2392
 
2359
2393
  ${block(error.stack || error.message)}
@@ -2385,7 +2419,7 @@ function checkSerializableAsJson(options) {
2385
2419
  }
2386
2420
  }
2387
2421
  else {
2388
- throw new UnexpectedError(spaceTrim((block) => `
2422
+ throw new UnexpectedError(spaceTrim$2((block) => `
2389
2423
  \`${name}\` is unknown type
2390
2424
 
2391
2425
  Additional message for \`${name}\`:
@@ -2593,7 +2627,7 @@ function isSerializableAsJson(value) {
2593
2627
  */
2594
2628
  function stringifyPipelineJson(pipeline) {
2595
2629
  if (!isSerializableAsJson(pipeline)) {
2596
- throw new UnexpectedError(spaceTrim(`
2630
+ throw new UnexpectedError(spaceTrim$2(`
2597
2631
  Cannot stringify the pipeline, because it is not serializable as JSON
2598
2632
 
2599
2633
  There can be multiple reasons:
@@ -3492,7 +3526,7 @@ function deserializeError(error) {
3492
3526
  message = `${name}: ${message}`;
3493
3527
  }
3494
3528
  if (stack !== undefined && stack !== '') {
3495
- message = spaceTrim((block) => `
3529
+ message = spaceTrim$2((block) => `
3496
3530
  ${block(message)}
3497
3531
 
3498
3532
  Original stack trace:
@@ -3519,7 +3553,7 @@ async function createRemoteClient(options) {
3519
3553
  const remoteServerUrlParsed = new URL(remoteServerUrl);
3520
3554
  if (remoteServerUrlParsed.pathname !== '/' && remoteServerUrlParsed.pathname !== '') {
3521
3555
  remoteServerUrlParsed.pathname = '/';
3522
- throw new Error(spaceTrim((block) => `
3556
+ throw new Error(spaceTrim$2((block) => `
3523
3557
  Remote server requires root url \`/\`
3524
3558
 
3525
3559
  You have provided \`remoteServerUrl\`:
@@ -4155,7 +4189,7 @@ function cacheLlmTools(llmTools, options = {}) {
4155
4189
  let normalizedContent = content;
4156
4190
  normalizedContent = normalizedContent.replace(/\s+/g, ' ');
4157
4191
  normalizedContent = normalizedContent.split('\r\n').join('\n');
4158
- normalizedContent = spaceTrim(normalizedContent);
4192
+ normalizedContent = spaceTrim$2(normalizedContent);
4159
4193
  // Note: Do not need to save everything in the cache, just the relevant parameters
4160
4194
  const relevantParameterNames = extractParameterNames(content);
4161
4195
  const relevantParameters = Object.fromEntries(Object.entries(parameters).filter(([key]) => relevantParameterNames.has(key)));
@@ -4540,14 +4574,14 @@ class MultipleLlmExecutionTools {
4540
4574
  if (description === undefined) {
4541
4575
  return headLine;
4542
4576
  }
4543
- return spaceTrim((block) => `
4577
+ return spaceTrim$2((block) => `
4544
4578
  ${headLine}
4545
4579
 
4546
4580
  ${ /* <- Note: Indenting the description: */block(description)}
4547
4581
  `);
4548
4582
  })
4549
4583
  .join('\n\n');
4550
- return spaceTrim((block) => `
4584
+ return spaceTrim$2((block) => `
4551
4585
  Multiple LLM Providers:
4552
4586
 
4553
4587
  ${block(innerModelsTitlesAndDescriptions)}
@@ -4638,7 +4672,7 @@ class MultipleLlmExecutionTools {
4638
4672
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
4639
4673
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
4640
4674
  // 3) ...
4641
- spaceTrim((block) => `
4675
+ spaceTrim$2((block) => `
4642
4676
  All execution tools of ${this.title} failed:
4643
4677
 
4644
4678
  ${block(errors
@@ -4651,7 +4685,7 @@ class MultipleLlmExecutionTools {
4651
4685
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\` into ${this.title}`);
4652
4686
  }
4653
4687
  else {
4654
- throw new PipelineExecutionError(spaceTrim((block) => `
4688
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
4655
4689
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}" into ${this.title}
4656
4690
 
4657
4691
  Available \`LlmExecutionTools\`:
@@ -4684,7 +4718,7 @@ class MultipleLlmExecutionTools {
4684
4718
  */
4685
4719
  function joinLlmExecutionTools(title, ...llmExecutionTools) {
4686
4720
  if (llmExecutionTools.length === 0) {
4687
- const warningMessage = spaceTrim(`
4721
+ const warningMessage = spaceTrim$2(`
4688
4722
  You have not provided any \`LlmExecutionTools\`
4689
4723
  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
4724
 
@@ -4742,7 +4776,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
4742
4776
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
4743
4777
  if (registeredItem === undefined) {
4744
4778
  // console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
4745
- throw new Error(spaceTrim((block) => `
4779
+ throw new Error(spaceTrim$2((block) => `
4746
4780
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
4747
4781
  Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
4748
4782
 
@@ -4810,14 +4844,14 @@ async function $provideLlmToolsFromEnv(options = {}) {
4810
4844
  const configuration = await $provideLlmToolsConfigurationFromEnv();
4811
4845
  if (configuration.length === 0) {
4812
4846
  if ($llmToolsMetadataRegister.list().length === 0) {
4813
- throw new UnexpectedError(spaceTrim((block) => `
4847
+ throw new UnexpectedError(spaceTrim$2((block) => `
4814
4848
  No LLM tools registered, this is probably a bug in the Promptbook library
4815
4849
 
4816
4850
  ${block($registeredLlmToolsMessage())}}
4817
4851
  `));
4818
4852
  }
4819
4853
  // TODO: [🥃]
4820
- throw new Error(spaceTrim((block) => `
4854
+ throw new Error(spaceTrim$2((block) => `
4821
4855
  No LLM tools found in the environment
4822
4856
 
4823
4857
  ${block($registeredLlmToolsMessage())}}
@@ -4927,7 +4961,7 @@ const promptbookFetch = async (urlOrRequest, init) => {
4927
4961
  else if (urlOrRequest instanceof Request) {
4928
4962
  url = urlOrRequest.url;
4929
4963
  }
4930
- throw new PromptbookFetchError(spaceTrim((block) => `
4964
+ throw new PromptbookFetchError(spaceTrim$2((block) => `
4931
4965
  Can not fetch "${url}"
4932
4966
 
4933
4967
  Fetch error:
@@ -4996,7 +5030,7 @@ async function $provideLlmToolsForCli(options) {
4996
5030
  console.log(colors.red(`You can not login to remote server in non-interactive mode`));
4997
5031
  process.exit(1);
4998
5032
  }
4999
- console.info(colors.cyan(spaceTrim(`
5033
+ console.info(colors.cyan(spaceTrim$2(`
5000
5034
  You will be logged in to ${remoteServerUrl}
5001
5035
  If you don't have an account, it will be created automatically.
5002
5036
  `)));
@@ -5070,7 +5104,7 @@ async function $provideLlmToolsForCli(options) {
5070
5104
  */
5071
5105
  function $initializeListModelsCommand(program) {
5072
5106
  const listModelsCommand = program.command('list-models');
5073
- listModelsCommand.description(spaceTrim(`
5107
+ listModelsCommand.description(spaceTrim$2(`
5074
5108
  List all available and configured LLM models
5075
5109
  `));
5076
5110
  listModelsCommand.alias('models');
@@ -5550,14 +5584,14 @@ function $registeredScrapersMessage(availableScrapers) {
5550
5584
  return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
5551
5585
  });
5552
5586
  if (metadata.length === 0) {
5553
- return spaceTrim(`
5587
+ return spaceTrim$2(`
5554
5588
  **No scrapers are available**
5555
5589
 
5556
5590
  This is a unexpected behavior, you are probably using some broken version of Promptbook
5557
5591
  At least there should be available the metadata of the scrapers
5558
5592
  `);
5559
5593
  }
5560
- return spaceTrim((block) => `
5594
+ return spaceTrim$2((block) => `
5561
5595
  Available scrapers are:
5562
5596
  ${block(metadata
5563
5597
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
@@ -5608,7 +5642,7 @@ function $registeredScrapersMessage(availableScrapers) {
5608
5642
  */
5609
5643
  function $initializeListScrapersCommand(program) {
5610
5644
  const listModelsCommand = program.command('list-scrapers');
5611
- listModelsCommand.description(spaceTrim(`
5645
+ listModelsCommand.description(spaceTrim$2(`
5612
5646
  List all available and configured scrapers and executables
5613
5647
  `));
5614
5648
  listModelsCommand.alias('scrapers');
@@ -5616,7 +5650,7 @@ function $initializeListScrapersCommand(program) {
5616
5650
  // TODO: [🌞] Do not allow on REMOTE_SERVER strategy
5617
5651
  const scrapers = await $provideScrapersForNode({});
5618
5652
  const executables = await $provideExecutablesForNode();
5619
- console.info(spaceTrim((block) => `
5653
+ console.info(spaceTrim$2((block) => `
5620
5654
  ${block($registeredScrapersMessage(scrapers))}
5621
5655
 
5622
5656
  All mime-types which can be scraped:
@@ -5646,7 +5680,7 @@ function $initializeListScrapersCommand(program) {
5646
5680
  */
5647
5681
  function $initializeLoginCommand(program) {
5648
5682
  const loginCommand = program.command('login');
5649
- loginCommand.description(spaceTrim(`
5683
+ loginCommand.description(spaceTrim$2(`
5650
5684
  Login to the remote Promptbook server
5651
5685
  `));
5652
5686
  loginCommand.action(handleActionErrors(async (cliOptions) => {
@@ -6220,7 +6254,7 @@ function pipelineJsonToString(pipelineJson) {
6220
6254
  pipelineString += '\n\n';
6221
6255
  pipelineString += '```' + contentLanguage;
6222
6256
  pipelineString += '\n';
6223
- pipelineString += spaceTrim(content);
6257
+ pipelineString += spaceTrim$2(content);
6224
6258
  // <- TODO: [main] !!3 Escape
6225
6259
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
6226
6260
  pipelineString += '\n';
@@ -6451,7 +6485,7 @@ function serializeError(error) {
6451
6485
  const { name, message, stack } = error;
6452
6486
  const { id } = error;
6453
6487
  if (!Object.keys(ALL_ERRORS).includes(name)) {
6454
- console.error(spaceTrim((block) => `
6488
+ console.error(spaceTrim$2((block) => `
6455
6489
 
6456
6490
  Cannot serialize error with name "${name}"
6457
6491
 
@@ -7052,7 +7086,7 @@ const CsvFormatParser = {
7052
7086
  const { value, outputParameterName, settings, mapCallback, onProgress } = options;
7053
7087
  const csv = csvParse(value, settings);
7054
7088
  if (csv.errors.length !== 0) {
7055
- throw new CsvFormatError(spaceTrim((block) => `
7089
+ throw new CsvFormatError(spaceTrim$2((block) => `
7056
7090
  CSV parsing error
7057
7091
 
7058
7092
  Error(s) from CSV parsing:
@@ -7097,7 +7131,7 @@ const CsvFormatParser = {
7097
7131
  const { value, settings, mapCallback, onProgress } = options;
7098
7132
  const csv = csvParse(value, settings);
7099
7133
  if (csv.errors.length !== 0) {
7100
- throw new CsvFormatError(spaceTrim((block) => `
7134
+ throw new CsvFormatError(spaceTrim$2((block) => `
7101
7135
  CSV parsing error
7102
7136
 
7103
7137
  Error(s) from CSV parsing:
@@ -7307,7 +7341,7 @@ function mapAvailableToExpectedParameters(options) {
7307
7341
  }
7308
7342
  // Phase 2️⃣: Non-matching mapping
7309
7343
  if (expectedParameterNames.size !== availableParametersNames.size) {
7310
- throw new PipelineExecutionError(spaceTrim((block) => `
7344
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
7311
7345
  Can not map available parameters to expected parameters
7312
7346
 
7313
7347
  Mapped parameters:
@@ -7792,7 +7826,7 @@ async function executeFormatSubvalues(options) {
7792
7826
  return /* not await */ executeAttempts({ ...options, logLlmCall });
7793
7827
  }
7794
7828
  if (jokerParameterNames.length !== 0) {
7795
- throw new UnexpectedError(spaceTrim((block) => `
7829
+ throw new UnexpectedError(spaceTrim$2((block) => `
7796
7830
  JOKER parameters are not supported together with FOREACH command
7797
7831
 
7798
7832
  [🧞‍♀️] This should be prevented in \`validatePipeline\`
@@ -7805,7 +7839,7 @@ async function executeFormatSubvalues(options) {
7805
7839
  if (formatDefinition === undefined) {
7806
7840
  throw new UnexpectedError(
7807
7841
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
7808
- spaceTrim((block) => `
7842
+ spaceTrim$2((block) => `
7809
7843
  Unsupported format "${task.foreach.formatName}"
7810
7844
 
7811
7845
  Available formats:
@@ -7822,7 +7856,7 @@ async function executeFormatSubvalues(options) {
7822
7856
  if (subvalueParser === undefined) {
7823
7857
  throw new UnexpectedError(
7824
7858
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
7825
- spaceTrim((block) => `
7859
+ spaceTrim$2((block) => `
7826
7860
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
7827
7861
 
7828
7862
  Available subformat names for format "${formatDefinition.formatName}":
@@ -7862,7 +7896,7 @@ async function executeFormatSubvalues(options) {
7862
7896
  if (!(error instanceof PipelineExecutionError)) {
7863
7897
  throw error;
7864
7898
  }
7865
- const highLevelError = new PipelineExecutionError(spaceTrim((block) => `
7899
+ const highLevelError = new PipelineExecutionError(spaceTrim$2((block) => `
7866
7900
  ${error.message}
7867
7901
 
7868
7902
  This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -7886,7 +7920,7 @@ async function executeFormatSubvalues(options) {
7886
7920
  ...options,
7887
7921
  priority: priority + index,
7888
7922
  parameters: allSubparameters,
7889
- pipelineIdentification: spaceTrim((block) => `
7923
+ pipelineIdentification: spaceTrim$2((block) => `
7890
7924
  ${block(pipelineIdentification)}
7891
7925
  Subparameter index: ${index}
7892
7926
  `),
@@ -7895,7 +7929,7 @@ async function executeFormatSubvalues(options) {
7895
7929
  }
7896
7930
  catch (error) {
7897
7931
  if (length > BIG_DATASET_TRESHOLD) {
7898
- console.error(spaceTrim((block) => `
7932
+ console.error(spaceTrim$2((block) => `
7899
7933
  ${error.message}
7900
7934
 
7901
7935
  This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -8969,7 +9003,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
8969
9003
  const fileExtension = getFileExtension(filename);
8970
9004
  const mimeType = extensionToMimeType(fileExtension || '');
8971
9005
  if (!(await isFileExisting(filename, tools.fs))) {
8972
- throw new NotFoundError(spaceTrim((block) => `
9006
+ throw new NotFoundError(spaceTrim$2((block) => `
8973
9007
  Can not make source handler for file which does not exist:
8974
9008
 
8975
9009
  File:
@@ -9062,7 +9096,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
9062
9096
  // <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
9063
9097
  break;
9064
9098
  }
9065
- console.warn(spaceTrim((block) => `
9099
+ console.warn(spaceTrim$2((block) => `
9066
9100
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
9067
9101
 
9068
9102
  The source:
@@ -9078,7 +9112,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
9078
9112
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
9079
9113
  }
9080
9114
  if (partialPieces === null) {
9081
- throw new KnowledgeScrapeError(spaceTrim((block) => `
9115
+ throw new KnowledgeScrapeError(spaceTrim$2((block) => `
9082
9116
  Cannot scrape knowledge
9083
9117
 
9084
9118
  The source:
@@ -9414,7 +9448,7 @@ const knowledgeCommandParser = {
9414
9448
  */
9415
9449
  parse(input) {
9416
9450
  const { args } = input;
9417
- const knowledgeSourceContent = spaceTrim(args[0] || '');
9451
+ const knowledgeSourceContent = spaceTrim$2(args[0] || '');
9418
9452
  if (knowledgeSourceContent === '') {
9419
9453
  throw new ParseError(`Source is not defined`);
9420
9454
  }
@@ -9558,7 +9592,7 @@ const sectionCommandParser = {
9558
9592
  normalized = normalized.split('DIALOGUE').join('DIALOG');
9559
9593
  const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
9560
9594
  if (taskTypes.length !== 1) {
9561
- throw new ParseError(spaceTrim((block) => `
9595
+ throw new ParseError(spaceTrim$2((block) => `
9562
9596
  Unknown section type "${normalized}"
9563
9597
 
9564
9598
  Supported section types are:
@@ -9578,7 +9612,7 @@ const sectionCommandParser = {
9578
9612
  */
9579
9613
  $applyToTaskJson(command, $taskJson, $pipelineJson) {
9580
9614
  if ($taskJson.isSectionTypeSet === true) {
9581
- throw new ParseError(spaceTrim(`
9615
+ throw new ParseError(spaceTrim$2(`
9582
9616
  Section type is already defined in the section.
9583
9617
  It can be defined only once.
9584
9618
  `));
@@ -9927,7 +9961,7 @@ const expectCommandParser = {
9927
9961
  /**
9928
9962
  * Description of the FORMAT command
9929
9963
  */
9930
- description: spaceTrim(`
9964
+ description: spaceTrim$2(`
9931
9965
  Expect command describes the desired output of the task *(after post-processing)*
9932
9966
  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
9967
  `),
@@ -10001,7 +10035,7 @@ const expectCommandParser = {
10001
10035
  }
10002
10036
  catch (error) {
10003
10037
  assertsError(error);
10004
- throw new ParseError(spaceTrim((block) => `
10038
+ throw new ParseError(spaceTrim$2((block) => `
10005
10039
  Invalid FORMAT command
10006
10040
  ${block(error.message)}:
10007
10041
  `));
@@ -10191,7 +10225,7 @@ function validateParameterName(parameterName) {
10191
10225
  if (!(error instanceof ParseError)) {
10192
10226
  throw error;
10193
10227
  }
10194
- throw new ParseError(spaceTrim((block) => `
10228
+ throw new ParseError(spaceTrim$2((block) => `
10195
10229
  ${block(error.message)}
10196
10230
 
10197
10231
  Tried to validate parameter name:
@@ -10250,7 +10284,7 @@ const foreachCommandParser = {
10250
10284
  const assignSign = args[3];
10251
10285
  const formatDefinition = FORMAT_DEFINITIONS.find((formatDefinition) => [formatDefinition.formatName, ...(formatDefinition.aliases || [])].includes(formatName));
10252
10286
  if (formatDefinition === undefined) {
10253
- throw new ParseError(spaceTrim((block) => `
10287
+ throw new ParseError(spaceTrim$2((block) => `
10254
10288
  Unsupported format "${formatName}"
10255
10289
 
10256
10290
  Available formats:
@@ -10262,7 +10296,7 @@ const foreachCommandParser = {
10262
10296
  }
10263
10297
  const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(subformatName));
10264
10298
  if (subvalueParser === undefined) {
10265
- throw new ParseError(spaceTrim((block) => `
10299
+ throw new ParseError(spaceTrim$2((block) => `
10266
10300
  Unsupported subformat name "${subformatName}" for format "${formatName}"
10267
10301
 
10268
10302
  Available subformat names for format "${formatDefinition.formatName}":
@@ -10310,7 +10344,7 @@ const foreachCommandParser = {
10310
10344
  outputSubparameterName = 'newLine';
10311
10345
  }
10312
10346
  else {
10313
- throw new ParseError(spaceTrim(`
10347
+ throw new ParseError(spaceTrim$2(`
10314
10348
  FOREACH ${formatName} ${subformatName} must specify output subparameter
10315
10349
 
10316
10350
  Correct example:
@@ -10386,7 +10420,7 @@ const formatCommandParser = {
10386
10420
  /**
10387
10421
  * Description of the FORMAT command
10388
10422
  */
10389
- description: spaceTrim(`
10423
+ description: spaceTrim$2(`
10390
10424
  Format command describes the desired output of the task (after post-processing)
10391
10425
  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
10426
  `),
@@ -10758,7 +10792,7 @@ const formfactorCommandParser = {
10758
10792
  const formfactorNameCandidate = args[0].toUpperCase();
10759
10793
  const formfactor = FORMFACTOR_DEFINITIONS.find((definition) => [definition.name, ...{ aliasNames: [], ...definition }.aliasNames].includes(formfactorNameCandidate));
10760
10794
  if (formfactor === undefined) {
10761
- throw new ParseError(spaceTrim((block) => `
10795
+ throw new ParseError(spaceTrim$2((block) => `
10762
10796
  Unknown formfactor name "${formfactorNameCandidate}"
10763
10797
 
10764
10798
  Available formfactors:
@@ -10777,7 +10811,7 @@ const formfactorCommandParser = {
10777
10811
  */
10778
10812
  $applyToPipelineJson(command, $pipelineJson) {
10779
10813
  if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
10780
- throw new ParseError(spaceTrim(`
10814
+ throw new ParseError(spaceTrim$2(`
10781
10815
  Redefinition of \`FORMFACTOR\` in the pipeline head
10782
10816
 
10783
10817
  You have used:
@@ -10920,7 +10954,7 @@ const modelCommandParser = {
10920
10954
  */
10921
10955
  parse(input) {
10922
10956
  const { args, normalized } = input;
10923
- const availableVariantsMessage = spaceTrim((block) => `
10957
+ const availableVariantsMessage = spaceTrim$2((block) => `
10924
10958
  Available variants are:
10925
10959
  ${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
10926
10960
  `);
@@ -10942,14 +10976,14 @@ const modelCommandParser = {
10942
10976
  // <- Note: [🤖]
10943
10977
  }
10944
10978
  else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
10945
- spaceTrim((block) => `
10979
+ spaceTrim$2((block) => `
10946
10980
  Embedding model can not be used in pipeline
10947
10981
 
10948
10982
  ${block(availableVariantsMessage)}
10949
10983
  `);
10950
10984
  }
10951
10985
  else {
10952
- throw new ParseError(spaceTrim((block) => `
10986
+ throw new ParseError(spaceTrim$2((block) => `
10953
10987
  Unknown model variant in command:
10954
10988
 
10955
10989
  ${block(availableVariantsMessage)}
@@ -10964,7 +10998,7 @@ const modelCommandParser = {
10964
10998
  };
10965
10999
  }
10966
11000
  else {
10967
- throw new ParseError(spaceTrim((block) => `
11001
+ throw new ParseError(spaceTrim$2((block) => `
10968
11002
  Unknown model key in command.
10969
11003
 
10970
11004
  Supported model keys are:
@@ -10991,7 +11025,7 @@ const modelCommandParser = {
10991
11025
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
10992
11026
  }
10993
11027
  else {
10994
- throw new ParseError(spaceTrim(`
11028
+ throw new ParseError(spaceTrim$2(`
10995
11029
  Redefinition of \`MODEL ${command.key}\` in the pipeline head
10996
11030
 
10997
11031
  You have used:
@@ -11023,7 +11057,7 @@ const modelCommandParser = {
11023
11057
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
11024
11058
  }
11025
11059
  else {
11026
- throw new ParseError(spaceTrim(`
11060
+ throw new ParseError(spaceTrim$2(`
11027
11061
  Redefinition of MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}"
11028
11062
 
11029
11063
  You have used:
@@ -11033,7 +11067,7 @@ const modelCommandParser = {
11033
11067
  }
11034
11068
  }
11035
11069
  if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
11036
- console.log(spaceTrim(`
11070
+ console.log(spaceTrim$2(`
11037
11071
  Setting MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}" to the same value as in the pipeline head
11038
11072
 
11039
11073
  In pipeline head:
@@ -11116,7 +11150,7 @@ const parameterCommandParser = {
11116
11150
  // <- TODO: When [🥶] fixed, change to:
11117
11151
  // > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
11118
11152
  if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
11119
- throw new ParseError(spaceTrim((block) => `
11153
+ throw new ParseError(spaceTrim$2((block) => `
11120
11154
  Parameter \`{${parameterNameRaw}}\` can not contain another parameter in description
11121
11155
 
11122
11156
  The description:
@@ -11298,7 +11332,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
11298
11332
  persona.description = personaDescription;
11299
11333
  return;
11300
11334
  }
11301
- console.warn(spaceTrim(`
11335
+ console.warn(spaceTrim$2(`
11302
11336
 
11303
11337
  Persona "${personaName}" is defined multiple times with different description:
11304
11338
 
@@ -11309,7 +11343,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
11309
11343
  ${personaDescription}
11310
11344
 
11311
11345
  `));
11312
- persona.description += spaceTrim('\n\n' + personaDescription);
11346
+ persona.description += spaceTrim$2('\n\n' + personaDescription);
11313
11347
  }
11314
11348
 
11315
11349
  /**
@@ -12164,7 +12198,7 @@ function removeMarkdownComments(content) {
12164
12198
  */
12165
12199
  function isFlatPipeline(pipelineString) {
12166
12200
  pipelineString = removeMarkdownComments(pipelineString);
12167
- pipelineString = spaceTrim(pipelineString);
12201
+ pipelineString = spaceTrim$2(pipelineString);
12168
12202
  const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
12169
12203
  //const isLastLineReturnStatement = pipelineString.split('\n').pop()!.split('`').join('').startsWith('->');
12170
12204
  const isBacktickBlockUsed = pipelineString.includes('```');
@@ -12190,7 +12224,7 @@ function deflatePipeline(pipelineString) {
12190
12224
  if (!isFlatPipeline(pipelineString)) {
12191
12225
  return pipelineString;
12192
12226
  }
12193
- pipelineString = spaceTrim(pipelineString);
12227
+ pipelineString = spaceTrim$2(pipelineString);
12194
12228
  const pipelineStringLines = pipelineString.split('\n');
12195
12229
  const potentialReturnStatement = pipelineStringLines.pop();
12196
12230
  let returnStatement;
@@ -12203,19 +12237,19 @@ function deflatePipeline(pipelineString) {
12203
12237
  returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
12204
12238
  pipelineStringLines.push(potentialReturnStatement);
12205
12239
  }
12206
- const prompt = spaceTrim(pipelineStringLines.join('\n'));
12240
+ const prompt = spaceTrim$2(pipelineStringLines.join('\n'));
12207
12241
  let quotedPrompt;
12208
12242
  if (prompt.split('\n').length <= 1) {
12209
12243
  quotedPrompt = `> ${prompt}`;
12210
12244
  }
12211
12245
  else {
12212
- quotedPrompt = spaceTrim((block) => `
12246
+ quotedPrompt = spaceTrim$2((block) => `
12213
12247
  \`\`\`
12214
12248
  ${block(prompt.split('`').join('\\`'))}
12215
12249
  \`\`\`
12216
12250
  `);
12217
12251
  }
12218
- pipelineString = validatePipelineString(spaceTrim((block) => `
12252
+ pipelineString = validatePipelineString(spaceTrim$2((block) => `
12219
12253
  # ${DEFAULT_BOOK_TITLE}
12220
12254
 
12221
12255
  ## Prompt
@@ -12279,7 +12313,7 @@ function extractAllListItemsFromMarkdown(markdown) {
12279
12313
  function extractOneBlockFromMarkdown(markdown) {
12280
12314
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
12281
12315
  if (codeBlocks.length !== 1) {
12282
- throw new ParseError(spaceTrim((block) => `
12316
+ throw new ParseError(spaceTrim$2((block) => `
12283
12317
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
12284
12318
 
12285
12319
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -12304,7 +12338,7 @@ function parseMarkdownSection(value) {
12304
12338
  }
12305
12339
  const title = lines[0].replace(/^#+\s*/, '');
12306
12340
  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'));
12341
+ const content = spaceTrim$2(lines.slice(1).join('\n'));
12308
12342
  if (level < 1 || level > 6) {
12309
12343
  throw new ParseError('Markdown section must have heading level between 1 and 6');
12310
12344
  }
@@ -12332,7 +12366,7 @@ function splitMarkdownIntoSections(markdown) {
12332
12366
  if (buffer.length === 0) {
12333
12367
  return;
12334
12368
  }
12335
- let section = spaceTrim(buffer.join('\n'));
12369
+ let section = spaceTrim$2(buffer.join('\n'));
12336
12370
  if (section === '') {
12337
12371
  return;
12338
12372
  }
@@ -12407,7 +12441,7 @@ function flattenMarkdown(markdown) {
12407
12441
  flattenedMarkdown += `## ${title}` + `\n\n`;
12408
12442
  flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
12409
12443
  }
12410
- return spaceTrim(flattenedMarkdown);
12444
+ return spaceTrim$2(flattenedMarkdown);
12411
12445
  }
12412
12446
  /**
12413
12447
  * TODO: [🏛] This can be part of markdown builder
@@ -13008,7 +13042,7 @@ function renderPromptbookMermaid(pipelineJson, options) {
13008
13042
  * @public exported from `@promptbook/utils`
13009
13043
  */
13010
13044
  function computeHash(value) {
13011
- return SHA256(hexEncoder.parse(spaceTrim(valueToString(value)))).toString( /* hex */);
13045
+ return SHA256(hexEncoder.parse(spaceTrim$2(valueToString(value)))).toString( /* hex */);
13012
13046
  }
13013
13047
  /**
13014
13048
  * TODO: [🥬][🥬] Use this ACRY
@@ -13277,8 +13311,8 @@ class JavascriptEvalExecutionTools {
13277
13311
  }
13278
13312
  // Note: [💎]
13279
13313
  // 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);
13314
+ const spaceTrim = (_) => spaceTrim$2(_);
13315
+ $preserve(spaceTrim);
13282
13316
  const removeQuotes$1 = removeQuotes;
13283
13317
  $preserve(removeQuotes$1);
13284
13318
  const unwrapResult$1 = unwrapResult;
@@ -13331,7 +13365,7 @@ class JavascriptEvalExecutionTools {
13331
13365
  // TODO: DRY [🍯]
13332
13366
  const buildinFunctions = {
13333
13367
  // TODO: [🍯] DRY all these functions across the file
13334
- spaceTrim: spaceTrim$1,
13368
+ spaceTrim,
13335
13369
  removeQuotes: removeQuotes$1,
13336
13370
  unwrapResult: unwrapResult$1,
13337
13371
  trimEndOfCodeBlock: trimEndOfCodeBlock$1,
@@ -13368,7 +13402,7 @@ class JavascriptEvalExecutionTools {
13368
13402
  .join('\n');
13369
13403
  // script = templateParameters(script, parameters);
13370
13404
  // <- TODO: [🧠][🥳] Should be this is one of two variants how to use parameters in script
13371
- const statementToEvaluate = spaceTrim((block) => `
13405
+ const statementToEvaluate = spaceTrim$2((block) => `
13372
13406
 
13373
13407
  // Build-in functions:
13374
13408
  ${block(buildinFunctionsStatement)}
@@ -13383,7 +13417,7 @@ class JavascriptEvalExecutionTools {
13383
13417
  (()=>{ ${script} })()
13384
13418
  `);
13385
13419
  if (this.options.isVerbose) {
13386
- console.info(spaceTrim((block) => `
13420
+ console.info(spaceTrim$2((block) => `
13387
13421
  🚀 Evaluating ${scriptLanguage} script:
13388
13422
 
13389
13423
  ${block(statementToEvaluate)}`));
@@ -13405,7 +13439,7 @@ class JavascriptEvalExecutionTools {
13405
13439
  To: [PipelineExecutionError: Parameter `{thing}` is not defined],
13406
13440
  */
13407
13441
  if (!statementToEvaluate.includes(undefinedName + '(')) {
13408
- throw new PipelineExecutionError(spaceTrim((block) => `
13442
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
13409
13443
 
13410
13444
  Parameter \`{${undefinedName}}\` is not defined
13411
13445
 
@@ -13427,7 +13461,7 @@ class JavascriptEvalExecutionTools {
13427
13461
  `));
13428
13462
  }
13429
13463
  else {
13430
- throw new PipelineExecutionError(spaceTrim((block) => `
13464
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
13431
13465
  Function ${undefinedName}() is not defined
13432
13466
 
13433
13467
  - Make sure that the function is one of built-in functions
@@ -13674,7 +13708,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13674
13708
  catch (error) {
13675
13709
  assertsError(error);
13676
13710
  // TODO: [7] DRY
13677
- const wrappedErrorMessage = spaceTrim((block) => `
13711
+ const wrappedErrorMessage = spaceTrim$2((block) => `
13678
13712
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
13679
13713
 
13680
13714
  Original error message:
@@ -13709,7 +13743,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13709
13743
  pipeline = { ...pipeline, pipelineUrl };
13710
13744
  }
13711
13745
  else if (!pipeline.pipelineUrl.startsWith(rootUrl)) {
13712
- throw new PipelineUrlError(spaceTrim(`
13746
+ throw new PipelineUrlError(spaceTrim$2(`
13713
13747
  Pipeline with URL ${pipeline.pipelineUrl} is not a child of the root URL ${rootUrl} 🍏
13714
13748
 
13715
13749
  File:
@@ -13747,7 +13781,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13747
13781
  }
13748
13782
  else {
13749
13783
  const existing = collection.get(pipeline.pipelineUrl);
13750
- throw new PipelineUrlError(spaceTrim(`
13784
+ throw new PipelineUrlError(spaceTrim$2(`
13751
13785
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍏
13752
13786
 
13753
13787
  Conflicting files:
@@ -13765,7 +13799,7 @@ async function createPipelineCollectionFromDirectory(rootPath, tools, options) {
13765
13799
  catch (error) {
13766
13800
  assertsError(error);
13767
13801
  // TODO: [7] DRY
13768
- const wrappedErrorMessage = spaceTrim((block) => `
13802
+ const wrappedErrorMessage = spaceTrim$2((block) => `
13769
13803
  ${error.name} in pipeline ${fileName.split('\\').join('/')}⁠:
13770
13804
 
13771
13805
  Original error message:
@@ -13897,7 +13931,7 @@ function usageToHuman(usage) {
13897
13931
  // Note: For negligible usage, we report at least something
13898
13932
  reportItems.push('Negligible');
13899
13933
  }
13900
- return spaceTrim((block) => `
13934
+ return spaceTrim$2((block) => `
13901
13935
  Usage:
13902
13936
  ${block(reportItems.map((item) => `- ${item}`).join('\n'))}
13903
13937
  `);
@@ -13936,7 +13970,7 @@ async function $provideScriptingForNode(options) {
13936
13970
  */
13937
13971
  function $initializeMakeCommand(program) {
13938
13972
  const makeCommand = program.command('make');
13939
- makeCommand.description(spaceTrim(`
13973
+ makeCommand.description(spaceTrim$2(`
13940
13974
  Makes a new pipeline collection in given folder
13941
13975
  `));
13942
13976
  makeCommand.alias('compile');
@@ -13948,7 +13982,7 @@ function $initializeMakeCommand(program) {
13948
13982
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
13949
13983
  makeCommand.option('--project-name', `Name of the project for whom collection is`, 'Untitled Promptbook project');
13950
13984
  makeCommand.option('--root-url <url>', `Root URL of all pipelines to make`, undefined);
13951
- makeCommand.option('-f, --format <format>', spaceTrim(`
13985
+ makeCommand.option('-f, --format <format>', spaceTrim$2(`
13952
13986
  Output format of builded collection "bookc", "javascript", "typescript" or "json"
13953
13987
 
13954
13988
  Note: You can use multiple formats separated by comma
@@ -13956,14 +13990,14 @@ function $initializeMakeCommand(program) {
13956
13990
  makeCommand.option('--no-validation', `Do not validate logic of pipelines in collection`, true);
13957
13991
  makeCommand.option('--validation', `Types of validations separated by comma (options "logic","imports")`, 'logic,imports');
13958
13992
  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(`
13993
+ makeCommand.option('-o, --output <path>', spaceTrim$2(`
13960
13994
  Where to save the builded collection
13961
13995
 
13962
13996
  Note: If you keep it "${DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME}" it will be saved in the root of the promptbook directory
13963
13997
  If you set it to a path, it will be saved in that path
13964
13998
  BUT you can use only one format and set correct extension
13965
13999
  `), DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME);
13966
- makeCommand.option('-fn, --function-name <functionName>', spaceTrim(`
14000
+ makeCommand.option('-fn, --function-name <functionName>', spaceTrim$2(`
13967
14001
  Name of the function to get pipeline collection
13968
14002
 
13969
14003
  Note: This can be used only with "javascript" or "typescript" format
@@ -14046,7 +14080,7 @@ function $initializeMakeCommand(program) {
14046
14080
  if (lastChar !== ']') {
14047
14081
  throw new UnexpectedError(`Last character of serialized collection should be "]" not "${lastChar}"`);
14048
14082
  }
14049
- return spaceTrim(collectionJsonString.substring(1, collectionJsonString.length - 1));
14083
+ return spaceTrim$2(collectionJsonString.substring(1, collectionJsonString.length - 1));
14050
14084
  })();
14051
14085
  const saveFile = async (extension, content) => {
14052
14086
  const filename = output !== DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME
@@ -14077,7 +14111,7 @@ function $initializeMakeCommand(program) {
14077
14111
  }
14078
14112
  if (formats.includes('javascript') || formats.includes('js')) {
14079
14113
  formats = formats.filter((format) => format !== 'javascript' && format !== 'js');
14080
- (await saveFile('js', spaceTrim((block) => `
14114
+ (await saveFile('js', spaceTrim$2((block) => `
14081
14115
  // ${block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI)}
14082
14116
 
14083
14117
  import { createPipelineCollectionFromJson } from '@promptbook/core';
@@ -14114,7 +14148,7 @@ function $initializeMakeCommand(program) {
14114
14148
  }
14115
14149
  if (formats.includes('typescript') || formats.includes('ts')) {
14116
14150
  formats = formats.filter((format) => format !== 'typescript' && format !== 'ts');
14117
- await saveFile('ts', spaceTrim((block) => `
14151
+ await saveFile('ts', spaceTrim$2((block) => `
14118
14152
  // ${block(GENERATOR_WARNING_BY_PROMPTBOOK_CLI)}
14119
14153
 
14120
14154
  import { createPipelineCollectionFromJson } from '@promptbook/core';
@@ -14259,7 +14293,7 @@ async function prettifyPipelineString(pipelineString, options) {
14259
14293
  */
14260
14294
  function $initializePrettifyCommand(program) {
14261
14295
  const prettifyCommand = program.command('prettify');
14262
- prettifyCommand.description(spaceTrim(`
14296
+ prettifyCommand.description(spaceTrim$2(`
14263
14297
  Iterates over \`.book.md\` files and does multiple enhancing operations on them:
14264
14298
 
14265
14299
  1) Adds Mermaid graph
@@ -14715,7 +14749,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
14715
14749
  // console.log(`Strategy 3️⃣`);
14716
14750
  const response = await fetch(pipelineSource);
14717
14751
  if (response.status >= 300) {
14718
- throw new NotFoundError(spaceTrim((block) => `
14752
+ throw new NotFoundError(spaceTrim$2((block) => `
14719
14753
  Book not found on URL:
14720
14754
  ${block(pipelineSource)}
14721
14755
 
@@ -14725,7 +14759,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
14725
14759
  const pipelineString = await response.text();
14726
14760
  // console.log({ pipelineString });
14727
14761
  if (!isValidPipelineString(pipelineString)) {
14728
- throw new NotFoundError(spaceTrim((block) => `
14762
+ throw new NotFoundError(spaceTrim$2((block) => `
14729
14763
  Book not found on URL:
14730
14764
  ${block(pipelineSource)}
14731
14765
 
@@ -14747,7 +14781,7 @@ async function $getCompiledBook(tools, pipelineSource, options) {
14747
14781
  });
14748
14782
  return pipelineJson;
14749
14783
  } /* not else */
14750
- throw new NotFoundError(spaceTrim((block) => `
14784
+ throw new NotFoundError(spaceTrim$2((block) => `
14751
14785
  Book not found:
14752
14786
  ${block(pipelineSource)}
14753
14787
 
@@ -14794,7 +14828,7 @@ async function runInteractiveChatbot(options) {
14794
14828
  const initialMessage = (((_a = pipeline.parameters.find(({ name }) => name === 'chatbotResponse')) === null || _a === void 0 ? void 0 : _a.exampleValues) || [])[0];
14795
14829
  if (initialMessage) {
14796
14830
  console.info(`\n`);
14797
- console.info(spaceTrim((block) => `
14831
+ console.info(spaceTrim$2((block) => `
14798
14832
 
14799
14833
  ${colors.bold(colors.green('Chatbot:'))}
14800
14834
  ${block(colors.green(initialMessage))}
@@ -14817,7 +14851,7 @@ async function runInteractiveChatbot(options) {
14817
14851
  type: 'text',
14818
14852
  name: 'userMessage',
14819
14853
  message: 'User message',
14820
- hint: spaceTrim((block) => `
14854
+ hint: spaceTrim$2((block) => `
14821
14855
  Type "exit" to exit,
14822
14856
 
14823
14857
  previousTitle
@@ -14833,7 +14867,7 @@ async function runInteractiveChatbot(options) {
14833
14867
  return process.exit(0);
14834
14868
  }
14835
14869
  console.info(`\n`);
14836
- console.info(spaceTrim((block) => `
14870
+ console.info(spaceTrim$2((block) => `
14837
14871
 
14838
14872
  ${colors.bold(colors.blue('User:'))}
14839
14873
  ${block(colors.blue(userMessage))}
@@ -14846,7 +14880,7 @@ async function runInteractiveChatbot(options) {
14846
14880
  };
14847
14881
  const result = await pipelineExecutor(inputParameters).asPromise({ isCrashedOnError: true });
14848
14882
  console.info(`\n`);
14849
- console.info(spaceTrim((block) => `
14883
+ console.info(spaceTrim$2((block) => `
14850
14884
 
14851
14885
  ${colors.bold(colors.green('Chatbot:'))}
14852
14886
  ${block(colors.green(result.outputParameters.chatbotResponse))}
@@ -14877,7 +14911,7 @@ async function runInteractiveChatbot(options) {
14877
14911
  */
14878
14912
  function $initializeRunCommand(program) {
14879
14913
  const runCommand = program.command('run', { isDefault: true });
14880
- runCommand.description(spaceTrim(`
14914
+ runCommand.description(spaceTrim$2(`
14881
14915
  Runs a pipeline
14882
14916
  `));
14883
14917
  runCommand.alias('execute');
@@ -14920,7 +14954,7 @@ function $initializeRunCommand(program) {
14920
14954
  if (!error.message.includes('No LLM tools')) {
14921
14955
  throw error;
14922
14956
  }
14923
- console.error(colors.red(spaceTrim((block) => `
14957
+ console.error(colors.red(spaceTrim$2((block) => `
14924
14958
  You need to configure LLM tools first
14925
14959
 
14926
14960
  1) Create .env file at the root of your project
@@ -14983,7 +15017,7 @@ function $initializeRunCommand(program) {
14983
15017
  if (!(error instanceof ParseError)) {
14984
15018
  throw error;
14985
15019
  }
14986
- console.error(colors.red(spaceTrim((block) => `
15020
+ console.error(colors.red(spaceTrim$2((block) => `
14987
15021
  ${block(error.message)}
14988
15022
 
14989
15023
  in ${pipelineSource}
@@ -15035,7 +15069,7 @@ function $initializeRunCommand(program) {
15035
15069
  };
15036
15070
  });
15037
15071
  if (isInteractive === false && questions.length !== 0) {
15038
- console.error(colors.red(spaceTrim((block) => `
15072
+ console.error(colors.red(spaceTrim$2((block) => `
15039
15073
  When using --no-interactive you need to pass all the input parameters through --json
15040
15074
 
15041
15075
  You are missing:
@@ -15167,7 +15201,7 @@ function $initializeStartAgentsServerCommand(program) {
15167
15201
  'Path to agents directory', DEFAULT_AGENTS_DIRNAME);
15168
15202
  startServerCommand.option('--port <port>', `Port to start the server on`, '4440');
15169
15203
  startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
15170
- startServerCommand.description(spaceTrim(`
15204
+ startServerCommand.description(spaceTrim$2(`
15171
15205
  Starts a Promptbook agents server
15172
15206
  `));
15173
15207
  startServerCommand.alias('start');
@@ -16474,7 +16508,7 @@ function $initializeStartPipelinesServerCommand(program) {
16474
16508
  // <- TODO: [🧟‍♂️] Unite path to promptbook collection argument
16475
16509
  'Path to promptbook collection directory', DEFAULT_BOOKS_DIRNAME);
16476
16510
  startServerCommand.option('--port <port>', `Port to start the server on`, '4460');
16477
- startServerCommand.option('-u, --url <url>', spaceTrim(`
16511
+ startServerCommand.option('-u, --url <url>', spaceTrim$2(`
16478
16512
  Public root url of the server
16479
16513
  It is used for following purposes:
16480
16514
 
@@ -16484,7 +16518,7 @@ function $initializeStartPipelinesServerCommand(program) {
16484
16518
  startServerCommand.option('--allow-anonymous', `Is anonymous mode allowed`, false);
16485
16519
  startServerCommand.option('-r, --reload', `Call LLM models even if same prompt with result is in the cache`, false);
16486
16520
  startServerCommand.option('--no-rich-ui', `Disable rich UI`, true);
16487
- startServerCommand.description(spaceTrim(`
16521
+ startServerCommand.description(spaceTrim$2(`
16488
16522
  Starts a remote server to execute books
16489
16523
 
16490
16524
  Note: You want probably to use "ptbk start-agents-server" to start agents server instead of pipelines server
@@ -16575,7 +16609,7 @@ function $initializeStartPipelinesServerCommand(program) {
16575
16609
  */
16576
16610
  function $initializeTestCommand(program) {
16577
16611
  const testCommand = program.command('test');
16578
- testCommand.description(spaceTrim(`
16612
+ testCommand.description(spaceTrim$2(`
16579
16613
  Iterates over \`.book.md\` and \`.bookc\` and checks if they are parsable and logically valid
16580
16614
  `));
16581
16615
  testCommand.argument('<filesGlob>',
@@ -17215,7 +17249,7 @@ class AnthropicClaudeExecutionTools {
17215
17249
  getDefaultModel(defaultModelName) {
17216
17250
  const model = ANTHROPIC_CLAUDE_MODELS.find(({ modelName }) => modelName.startsWith(defaultModelName));
17217
17251
  if (model === undefined) {
17218
- throw new UnexpectedError(spaceTrim((block) => `
17252
+ throw new UnexpectedError(spaceTrim$2((block) => `
17219
17253
  Cannot find model in Anthropic Claude models with name "${defaultModelName}" which should be used as default.
17220
17254
 
17221
17255
  Available models:
@@ -18437,7 +18471,7 @@ function createExecutionToolsFromVercelProvider(options) {
18437
18471
  const modelName = modelRequirements.modelName ||
18438
18472
  ((_a = availableModels.find(({ modelVariant }) => modelVariant === 'CHAT')) === null || _a === void 0 ? void 0 : _a.modelName);
18439
18473
  if (!modelName) {
18440
- throw new PipelineExecutionError(spaceTrim(`
18474
+ throw new PipelineExecutionError(spaceTrim$2(`
18441
18475
  Can not determine which model to use.
18442
18476
 
18443
18477
  You need to provide at least one of:
@@ -19775,7 +19809,7 @@ class OpenAiCompatibleExecutionTools {
19775
19809
  // Note: Match exact or prefix for model families
19776
19810
  const model = this.HARDCODED_MODELS.find(({ modelName }) => modelName === defaultModelName || modelName.startsWith(defaultModelName));
19777
19811
  if (model === undefined) {
19778
- throw new PipelineExecutionError(spaceTrim((block) => `
19812
+ throw new PipelineExecutionError(spaceTrim$2((block) => `
19779
19813
  Cannot find model in ${this.title} models with name "${defaultModelName}" which should be used as default.
19780
19814
 
19781
19815
  Available models:
@@ -20519,18 +20553,26 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20519
20553
  modelName: 'assistant',
20520
20554
  // <- [🧠] What is the best value here
20521
20555
  });
20556
+ // Build thread messages: include previous thread messages + current user message
20557
+ const threadMessages = [];
20558
+ // TODO: [🈹] Maybe this should not be here but in other place, look at commit 39d705e75e5bcf7a818c3af36bc13e1c8475c30c
20559
+ // Add previous messages from thread (if any)
20560
+ if ('thread' in prompt &&
20561
+ Array.isArray(prompt.thread)) {
20562
+ const previousMessages = prompt.thread.map((msg) => ({
20563
+ role: (msg.role === 'assistant' ? 'assistant' : 'user'),
20564
+ content: msg.content,
20565
+ }));
20566
+ threadMessages.push(...previousMessages);
20567
+ }
20568
+ // Always add the current user message
20569
+ threadMessages.push({ role: 'user', content: rawPromptContent });
20522
20570
  const rawRequest = {
20523
20571
  // TODO: [👨‍👨‍👧‍👧] ...modelSettings,
20524
20572
  // TODO: [👨‍👨‍👧‍👧][🧠] What about system message for assistants, does it make sense - combination of OpenAI assistants with Promptbook Personas
20525
20573
  assistant_id: this.assistantId,
20526
20574
  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 }],
20575
+ messages: threadMessages,
20534
20576
  },
20535
20577
  // <- TODO: Add user identification here> user: this.options.user,
20536
20578
  };
@@ -20550,7 +20592,7 @@ class OpenAiAssistantExecutionTools extends OpenAiExecutionTools {
20550
20592
  console.info('textDelta', textDelta.value);
20551
20593
  }
20552
20594
  const chunk = {
20553
- content: textDelta.value || '',
20595
+ content: snapshot.value,
20554
20596
  modelName: 'assistant',
20555
20597
  timing: {
20556
20598
  start,
@@ -21221,8 +21263,8 @@ class MarkdownScraper {
21221
21263
  knowledgeTextPieces.map(async (knowledgeTextPiece, i) => {
21222
21264
  // Note: These are just default values, they will be overwritten by the actual values:
21223
21265
  let name = `piece-${i}`;
21224
- let title = spaceTrim(knowledgeTextPiece.substring(0, 100));
21225
- const knowledgePieceContent = spaceTrim(knowledgeTextPiece);
21266
+ let title = spaceTrim$2(knowledgeTextPiece.substring(0, 100));
21267
+ const knowledgePieceContent = spaceTrim$2(knowledgeTextPiece);
21226
21268
  let keywords = [];
21227
21269
  const index = [];
21228
21270
  /*
@@ -21235,7 +21277,7 @@ class MarkdownScraper {
21235
21277
  isCrashedOnError: true,
21236
21278
  });
21237
21279
  const { title: titleRaw = 'Untitled' } = titleResult.outputParameters;
21238
- title = spaceTrim(titleRaw) /* <- TODO: Maybe do in pipeline */;
21280
+ title = spaceTrim$2(titleRaw) /* <- TODO: Maybe do in pipeline */;
21239
21281
  name = titleToName(title);
21240
21282
  // --- Keywords
21241
21283
  const keywordsResult = await prepareKeywordsExecutor({ knowledgePieceContent }).asPromise({
@@ -21390,7 +21432,7 @@ class BoilerplateScraper {
21390
21432
  await $execCommand(command);
21391
21433
  // Note: [0]
21392
21434
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
21393
- throw new UnexpectedError(spaceTrim((block) => `
21435
+ throw new UnexpectedError(spaceTrim$2((block) => `
21394
21436
  File that was supposed to be created by Pandoc does not exist for unknown reason
21395
21437
 
21396
21438
  Expected file:
@@ -21554,7 +21596,7 @@ class DocumentScraper {
21554
21596
  await $execCommand(command);
21555
21597
  // Note: [0]
21556
21598
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
21557
- throw new UnexpectedError(spaceTrim((block) => `
21599
+ throw new UnexpectedError(spaceTrim$2((block) => `
21558
21600
  File that was supposed to be created by Pandoc does not exist for unknown reason
21559
21601
 
21560
21602
  Expected file:
@@ -21705,7 +21747,7 @@ class LegacyDocumentScraper {
21705
21747
  await $execCommand(command);
21706
21748
  const files = await readdir(documentSourceOutdirPathForLibreOffice);
21707
21749
  if (files.length !== 1) {
21708
- throw new UnexpectedError(spaceTrim((block) => `
21750
+ throw new UnexpectedError(spaceTrim$2((block) => `
21709
21751
  Expected exactly 1 file in the LibreOffice output directory, got ${files.length}
21710
21752
 
21711
21753
  The temporary folder:
@@ -21719,7 +21761,7 @@ class LegacyDocumentScraper {
21719
21761
  await rename(join(documentSourceOutdirPathForLibreOffice, file), cacheFilehandler.filename);
21720
21762
  await rmdir(documentSourceOutdirPathForLibreOffice);
21721
21763
  if (!(await isFileExisting(cacheFilehandler.filename, this.tools.fs))) {
21722
- throw new UnexpectedError(spaceTrim((block) => `
21764
+ throw new UnexpectedError(spaceTrim$2((block) => `
21723
21765
  File that was supposed to be created by LibreOffice does not exist for unknown reason
21724
21766
 
21725
21767
  Expected file:
@@ -22592,6 +22634,133 @@ class ActionCommitmentDefinition extends BaseCommitmentDefinition {
22592
22634
  * Note: [💞] Ignore a discrepancy between file name and entity name
22593
22635
  */
22594
22636
 
22637
+ /**
22638
+ * CLOSED commitment definition
22639
+ *
22640
+ * The CLOSED commitment specifies that the agent CANNOT be modified by conversation.
22641
+ * It prevents the agent from learning from interactions and updating its source code.
22642
+ *
22643
+ * Example usage in agent source:
22644
+ *
22645
+ * ```book
22646
+ * CLOSED
22647
+ * ```
22648
+ *
22649
+ * @private [🪔] Maybe export the commitments through some package
22650
+ */
22651
+ class ClosedCommitmentDefinition extends BaseCommitmentDefinition {
22652
+ constructor() {
22653
+ super('CLOSED');
22654
+ }
22655
+ /**
22656
+ * Short one-line description of CLOSED.
22657
+ */
22658
+ get description() {
22659
+ return 'Prevent the agent from being modified by conversation.';
22660
+ }
22661
+ /**
22662
+ * Icon for this commitment.
22663
+ */
22664
+ get icon() {
22665
+ return '🔒';
22666
+ }
22667
+ /**
22668
+ * Markdown documentation for CLOSED commitment.
22669
+ */
22670
+ get documentation() {
22671
+ return spaceTrim$1(`
22672
+ # CLOSED
22673
+
22674
+ Specifies that the agent **cannot** be modified by conversation with it.
22675
+ This means the agent will **not** learn from interactions and its source code will remain static during conversation.
22676
+
22677
+ By default (if not specified), agents are \`OPEN\` to modification.
22678
+
22679
+ > See also [OPEN](/docs/OPEN)
22680
+
22681
+ ## Example
22682
+
22683
+ \`\`\`book
22684
+ CLOSED
22685
+ \`\`\`
22686
+ `);
22687
+ }
22688
+ applyToAgentModelRequirements(requirements, _content) {
22689
+ const updatedMetadata = {
22690
+ ...requirements.metadata,
22691
+ isClosed: true,
22692
+ };
22693
+ return {
22694
+ ...requirements,
22695
+ metadata: updatedMetadata,
22696
+ };
22697
+ }
22698
+ }
22699
+ /**
22700
+ * Note: [💞] Ignore a discrepancy between file name and entity name
22701
+ */
22702
+
22703
+ /**
22704
+ * COMPONENT commitment definition
22705
+ *
22706
+ * The COMPONENT commitment defines a UI component that the agent can render in the chat.
22707
+ *
22708
+ * @private [🪔] Maybe export the commitments through some package
22709
+ */
22710
+ class ComponentCommitmentDefinition extends BaseCommitmentDefinition {
22711
+ constructor() {
22712
+ super('COMPONENT');
22713
+ }
22714
+ /**
22715
+ * Short one-line description of COMPONENT.
22716
+ */
22717
+ get description() {
22718
+ return 'Define a UI component that the agent can render in the chat.';
22719
+ }
22720
+ /**
22721
+ * Icon for this commitment.
22722
+ */
22723
+ get icon() {
22724
+ return '🧩';
22725
+ }
22726
+ /**
22727
+ * Markdown documentation for COMPONENT commitment.
22728
+ */
22729
+ get documentation() {
22730
+ return spaceTrim$1(`
22731
+ # COMPONENT
22732
+
22733
+ Defines a UI component that the agent can render in the chat.
22734
+
22735
+ ## Key aspects
22736
+
22737
+ - Tells the agent that a specific component is available.
22738
+ - Provides syntax for using the component.
22739
+
22740
+ ## Example
22741
+
22742
+ \`\`\`book
22743
+ COMPONENT Arrow
22744
+ The agent should render an arrow component in the chat UI.
22745
+ Syntax:
22746
+ <Arrow direction="up" color="red" />
22747
+ \`\`\`
22748
+ `);
22749
+ }
22750
+ applyToAgentModelRequirements(requirements, content) {
22751
+ const trimmedContent = content.trim();
22752
+ if (!trimmedContent) {
22753
+ return requirements;
22754
+ }
22755
+ // Add component capability to the system message
22756
+ const componentSection = `Component: ${trimmedContent}`;
22757
+ return this.appendToSystemMessage(requirements, componentSection, '\n\n');
22758
+ }
22759
+ }
22760
+ /**
22761
+ * Note: [💞] Ignore a discrepancy between file name and entity name
22762
+ */
22763
+
22595
22764
  /**
22596
22765
  * DELETE commitment definition
22597
22766
  *
@@ -22797,6 +22966,79 @@ class FormatCommitmentDefinition extends BaseCommitmentDefinition {
22797
22966
  * Note: [💞] Ignore a discrepancy between file name and entity name
22798
22967
  */
22799
22968
 
22969
+ /**
22970
+ * FROM commitment definition
22971
+ *
22972
+ * The FROM commitment tells the agent that its `agentSource` is inherited from another agent.
22973
+ *
22974
+ * Example usage in agent source:
22975
+ *
22976
+ * ```book
22977
+ * FROM https://s6.ptbk.io/benjamin-white
22978
+ * ```
22979
+ *
22980
+ * @private [🪔] Maybe export the commitments through some package
22981
+ */
22982
+ class FromCommitmentDefinition extends BaseCommitmentDefinition {
22983
+ constructor(type = 'FROM') {
22984
+ super(type);
22985
+ }
22986
+ /**
22987
+ * Short one-line description of FROM.
22988
+ */
22989
+ get description() {
22990
+ return 'Inherit agent source from another agent.';
22991
+ }
22992
+ /**
22993
+ * Icon for this commitment.
22994
+ */
22995
+ get icon() {
22996
+ return '🧬';
22997
+ }
22998
+ /**
22999
+ * Markdown documentation for FROM commitment.
23000
+ */
23001
+ get documentation() {
23002
+ return spaceTrim$1(`
23003
+ # ${this.type}
23004
+
23005
+ Inherits agent source from another agent.
23006
+
23007
+ ## Examples
23008
+
23009
+ \`\`\`book
23010
+ My AI Agent
23011
+
23012
+ FROM https://s6.ptbk.io/benjamin-white
23013
+ RULE Speak only in English.
23014
+ \`\`\`
23015
+ `);
23016
+ }
23017
+ applyToAgentModelRequirements(requirements, content) {
23018
+ const trimmedContent = content.trim();
23019
+ if (!trimmedContent) {
23020
+ return requirements;
23021
+ }
23022
+ // Validate URL
23023
+ try {
23024
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
23025
+ const url = new URL(trimmedContent);
23026
+ // TODO: Add more validation if needed (e.g. check for valid protocol)
23027
+ }
23028
+ catch (error) {
23029
+ console.warn(`Invalid URL in FROM commitment: ${trimmedContent}`);
23030
+ return requirements;
23031
+ }
23032
+ return {
23033
+ ...requirements,
23034
+ parentAgentUrl: trimmedContent,
23035
+ };
23036
+ }
23037
+ }
23038
+ /**
23039
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23040
+ */
23041
+
22800
23042
  /**
22801
23043
  * GOAL commitment definition
22802
23044
  *
@@ -23005,6 +23247,77 @@ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
23005
23247
  * Note: [💞] Ignore a discrepancy between file name and entity name
23006
23248
  */
23007
23249
 
23250
+ /**
23251
+ * LANGUAGE commitment definition
23252
+ *
23253
+ * The LANGUAGE/LANGUAGES commitment specifies the language(s) the agent should use in its responses.
23254
+ *
23255
+ * Example usage in agent source:
23256
+ *
23257
+ * ```book
23258
+ * LANGUAGE English
23259
+ * LANGUAGE French, English and Czech
23260
+ * ```
23261
+ *
23262
+ * @private [🪔] Maybe export the commitments through some package
23263
+ */
23264
+ class LanguageCommitmentDefinition extends BaseCommitmentDefinition {
23265
+ constructor(type = 'LANGUAGE') {
23266
+ super(type);
23267
+ }
23268
+ /**
23269
+ * Short one-line description of LANGUAGE/LANGUAGES.
23270
+ */
23271
+ get description() {
23272
+ return 'Specifies the language(s) the agent should use.';
23273
+ }
23274
+ /**
23275
+ * Icon for this commitment.
23276
+ */
23277
+ get icon() {
23278
+ return '🌐';
23279
+ }
23280
+ /**
23281
+ * Markdown documentation for LANGUAGE/LANGUAGES commitment.
23282
+ */
23283
+ get documentation() {
23284
+ return spaceTrim$1(`
23285
+ # ${this.type}
23286
+
23287
+ Specifies the language(s) the agent should use in its responses.
23288
+ This is a specialized variation of the RULE commitment focused on language constraints.
23289
+
23290
+ ## Examples
23291
+
23292
+ \`\`\`book
23293
+ Paul Smith & Associés
23294
+
23295
+ PERSONA You are a company lawyer.
23296
+ LANGUAGE French, English and Czech
23297
+ \`\`\`
23298
+
23299
+ \`\`\`book
23300
+ Customer Support
23301
+
23302
+ PERSONA You are a customer support agent.
23303
+ LANGUAGE English
23304
+ \`\`\`
23305
+ `);
23306
+ }
23307
+ applyToAgentModelRequirements(requirements, content) {
23308
+ const trimmedContent = content.trim();
23309
+ if (!trimmedContent) {
23310
+ return requirements;
23311
+ }
23312
+ // Add language rule to the system message
23313
+ const languageSection = `Language: ${trimmedContent}`;
23314
+ return this.appendToSystemMessage(requirements, languageSection, '\n\n');
23315
+ }
23316
+ }
23317
+ /**
23318
+ * Note: [💞] Ignore a discrepancy between file name and entity name
23319
+ */
23320
+
23008
23321
  /**
23009
23322
  * MEMORY commitment definition
23010
23323
  *
@@ -23589,6 +23902,12 @@ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
23589
23902
  * META COLOR #00ff00
23590
23903
  * ```
23591
23904
  *
23905
+ * You can also specify multiple colors separated by comma:
23906
+ *
23907
+ * ```book
23908
+ * META COLOR #ff0000, #00ff00, #0000ff
23909
+ * ```
23910
+ *
23592
23911
  * @private [🪔] Maybe export the commitments through some package
23593
23912
  */
23594
23913
  class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
@@ -23599,7 +23918,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23599
23918
  * Short one-line description of META COLOR.
23600
23919
  */
23601
23920
  get description() {
23602
- return "Set the agent's accent color.";
23921
+ return "Set the agent's accent color or gradient.";
23603
23922
  }
23604
23923
  /**
23605
23924
  * Icon for this commitment.
@@ -23614,7 +23933,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23614
23933
  return spaceTrim$1(`
23615
23934
  # META COLOR
23616
23935
 
23617
- Sets the agent's accent color.
23936
+ Sets the agent's accent color or gradient.
23618
23937
 
23619
23938
  ## Key aspects
23620
23939
 
@@ -23622,6 +23941,7 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23622
23941
  - Only one \`META COLOR\` should be used per agent.
23623
23942
  - If multiple are specified, the last one takes precedence.
23624
23943
  - Used for visual representation in user interfaces.
23944
+ - Can specify multiple colors separated by comma to create a gradient.
23625
23945
 
23626
23946
  ## Examples
23627
23947
 
@@ -23638,6 +23958,13 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23638
23958
  META COLOR #e74c3c
23639
23959
  PERSONA You are a creative and inspiring assistant
23640
23960
  \`\`\`
23961
+
23962
+ \`\`\`book
23963
+ Gradient Agent
23964
+
23965
+ META COLOR #ff0000, #00ff00, #0000ff
23966
+ PERSONA You are a colorful agent
23967
+ \`\`\`
23641
23968
  `);
23642
23969
  }
23643
23970
  applyToAgentModelRequirements(requirements, content) {
@@ -23660,84 +23987,82 @@ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
23660
23987
  */
23661
23988
 
23662
23989
  /**
23663
- * META IMAGE commitment definition
23990
+ * META FONT commitment definition
23664
23991
  *
23665
- * The META IMAGE commitment sets the agent's avatar/profile image URL.
23992
+ * The META FONT commitment sets the agent's font.
23666
23993
  * This commitment is special because it doesn't affect the system message,
23667
23994
  * but is handled separately in the parsing logic.
23668
23995
  *
23669
23996
  * Example usage in agent source:
23670
23997
  *
23671
23998
  * ```book
23672
- * META IMAGE https://example.com/avatar.jpg
23673
- * META IMAGE /assets/agent-avatar.png
23999
+ * META FONT Poppins, Arial, sans-serif
24000
+ * META FONT Roboto
23674
24001
  * ```
23675
24002
  *
23676
24003
  * @private [🪔] Maybe export the commitments through some package
23677
24004
  */
23678
- class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
24005
+ class MetaFontCommitmentDefinition extends BaseCommitmentDefinition {
23679
24006
  constructor() {
23680
- super('META IMAGE', ['IMAGE']);
24007
+ super('META FONT', ['FONT']);
23681
24008
  }
23682
24009
  /**
23683
- * Short one-line description of META IMAGE.
24010
+ * Short one-line description of META FONT.
23684
24011
  */
23685
24012
  get description() {
23686
- return "Set the agent's profile image URL.";
24013
+ return "Set the agent's font.";
23687
24014
  }
23688
24015
  /**
23689
24016
  * Icon for this commitment.
23690
24017
  */
23691
24018
  get icon() {
23692
- return '🖼️';
24019
+ return '🔤';
23693
24020
  }
23694
24021
  /**
23695
- * Markdown documentation for META IMAGE commitment.
24022
+ * Markdown documentation for META FONT commitment.
23696
24023
  */
23697
24024
  get documentation() {
23698
24025
  return spaceTrim$1(`
23699
- # META IMAGE
24026
+ # META FONT
23700
24027
 
23701
- Sets the agent's avatar/profile image URL.
24028
+ Sets the agent's font.
23702
24029
 
23703
24030
  ## Key aspects
23704
24031
 
23705
24032
  - Does not modify the agent's behavior or responses.
23706
- - Only one \`META IMAGE\` should be used per agent.
24033
+ - Only one \`META FONT\` should be used per agent.
23707
24034
  - If multiple are specified, the last one takes precedence.
23708
24035
  - Used for visual representation in user interfaces.
24036
+ - Supports Google Fonts.
23709
24037
 
23710
24038
  ## Examples
23711
24039
 
23712
24040
  \`\`\`book
23713
- Professional Assistant
24041
+ Modern Assistant
23714
24042
 
23715
- META IMAGE https://example.com/professional-avatar.jpg
23716
- PERSONA You are a professional business assistant
23717
- STYLE Maintain a formal and courteous tone
24043
+ META FONT Poppins, Arial, sans-serif
24044
+ PERSONA You are a modern assistant
23718
24045
  \`\`\`
23719
24046
 
23720
24047
  \`\`\`book
23721
- Creative Helper
24048
+ Classic Helper
23722
24049
 
23723
- META IMAGE /assets/creative-bot-avatar.png
23724
- PERSONA You are a creative and inspiring assistant
23725
- STYLE Be enthusiastic and encouraging
23726
- ACTION Can help with brainstorming and ideation
24050
+ META FONT Times New Roman
24051
+ PERSONA You are a classic helper
23727
24052
  \`\`\`
23728
24053
  `);
23729
24054
  }
23730
24055
  applyToAgentModelRequirements(requirements, content) {
23731
- // META IMAGE doesn't modify the system message or model requirements
23732
- // It's handled separately in the parsing logic for profile image extraction
24056
+ // META FONT doesn't modify the system message or model requirements
24057
+ // It's handled separately in the parsing logic
23733
24058
  // This method exists for consistency with the CommitmentDefinition interface
23734
24059
  return requirements;
23735
24060
  }
23736
24061
  /**
23737
- * Extracts the profile image URL from the content
24062
+ * Extracts the font from the content
23738
24063
  * This is used by the parsing logic
23739
24064
  */
23740
- extractProfileImageUrl(content) {
24065
+ extractProfileFont(content) {
23741
24066
  const trimmedContent = content.trim();
23742
24067
  return trimmedContent || null;
23743
24068
  }
@@ -23747,10 +24072,206 @@ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
23747
24072
  */
23748
24073
 
23749
24074
  /**
23750
- * MODEL commitment definition
24075
+ * META IMAGE commitment definition
23751
24076
  *
23752
- * The MODEL commitment specifies which AI model to use and can also set
23753
- * model-specific parameters like temperature, topP, topK, and maxTokens.
24077
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
24078
+ * This commitment is special because it doesn't affect the system message,
24079
+ * but is handled separately in the parsing logic.
24080
+ *
24081
+ * Example usage in agent source:
24082
+ *
24083
+ * ```book
24084
+ * META IMAGE https://example.com/avatar.jpg
24085
+ * META IMAGE /assets/agent-avatar.png
24086
+ * ```
24087
+ *
24088
+ * @private [🪔] Maybe export the commitments through some package
24089
+ */
24090
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
24091
+ constructor() {
24092
+ super('META IMAGE', ['IMAGE']);
24093
+ }
24094
+ /**
24095
+ * Short one-line description of META IMAGE.
24096
+ */
24097
+ get description() {
24098
+ return "Set the agent's profile image URL.";
24099
+ }
24100
+ /**
24101
+ * Icon for this commitment.
24102
+ */
24103
+ get icon() {
24104
+ return '🖼️';
24105
+ }
24106
+ /**
24107
+ * Markdown documentation for META IMAGE commitment.
24108
+ */
24109
+ get documentation() {
24110
+ return spaceTrim$1(`
24111
+ # META IMAGE
24112
+
24113
+ Sets the agent's avatar/profile image URL.
24114
+
24115
+ ## Key aspects
24116
+
24117
+ - Does not modify the agent's behavior or responses.
24118
+ - Only one \`META IMAGE\` should be used per agent.
24119
+ - If multiple are specified, the last one takes precedence.
24120
+ - Used for visual representation in user interfaces.
24121
+
24122
+ ## Examples
24123
+
24124
+ \`\`\`book
24125
+ Professional Assistant
24126
+
24127
+ META IMAGE https://example.com/professional-avatar.jpg
24128
+ PERSONA You are a professional business assistant
24129
+ STYLE Maintain a formal and courteous tone
24130
+ \`\`\`
24131
+
24132
+ \`\`\`book
24133
+ Creative Helper
24134
+
24135
+ META IMAGE /assets/creative-bot-avatar.png
24136
+ PERSONA You are a creative and inspiring assistant
24137
+ STYLE Be enthusiastic and encouraging
24138
+ ACTION Can help with brainstorming and ideation
24139
+ \`\`\`
24140
+ `);
24141
+ }
24142
+ applyToAgentModelRequirements(requirements, content) {
24143
+ // META IMAGE doesn't modify the system message or model requirements
24144
+ // It's handled separately in the parsing logic for profile image extraction
24145
+ // This method exists for consistency with the CommitmentDefinition interface
24146
+ return requirements;
24147
+ }
24148
+ /**
24149
+ * Extracts the profile image URL from the content
24150
+ * This is used by the parsing logic
24151
+ */
24152
+ extractProfileImageUrl(content) {
24153
+ const trimmedContent = content.trim();
24154
+ return trimmedContent || null;
24155
+ }
24156
+ }
24157
+ /**
24158
+ * Note: [💞] Ignore a discrepancy between file name and entity name
24159
+ */
24160
+
24161
+ /**
24162
+ * META LINK commitment definition
24163
+ *
24164
+ * The `META LINK` commitment represents the link to the person from whom the agent is created.
24165
+ * This commitment is special because it doesn't affect the system message,
24166
+ * but is handled separately in the parsing logic for profile display.
24167
+ *
24168
+ * Example usage in agent source:
24169
+ *
24170
+ * ```
24171
+ * META LINK https://twitter.com/username
24172
+ * META LINK https://linkedin.com/in/profile
24173
+ * META LINK https://github.com/username
24174
+ * ```
24175
+ *
24176
+ * Multiple `META LINK` commitments can be used when there are multiple sources:
24177
+ *
24178
+ * ```book
24179
+ * META LINK https://twitter.com/username
24180
+ * META LINK https://linkedin.com/in/profile
24181
+ * ```
24182
+ *
24183
+ * @private [🪔] Maybe export the commitments through some package
24184
+ */
24185
+ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
24186
+ constructor() {
24187
+ super('META LINK');
24188
+ }
24189
+ /**
24190
+ * Short one-line description of META LINK.
24191
+ */
24192
+ get description() {
24193
+ return 'Provide profile/source links for the person the agent models.';
24194
+ }
24195
+ /**
24196
+ * Icon for this commitment.
24197
+ */
24198
+ get icon() {
24199
+ return '🔗';
24200
+ }
24201
+ /**
24202
+ * Markdown documentation for META LINK commitment.
24203
+ */
24204
+ get documentation() {
24205
+ return spaceTrim$1(`
24206
+ # META LINK
24207
+
24208
+ Represents a profile or source link for the person the agent is modeled after.
24209
+
24210
+ ## Key aspects
24211
+
24212
+ - Does not modify the agent's behavior or responses.
24213
+ - Multiple \`META LINK\` commitments can be used for different social profiles.
24214
+ - Used for attribution and crediting the original person.
24215
+ - Displayed in user interfaces for transparency.
24216
+
24217
+ ## Examples
24218
+
24219
+ \`\`\`book
24220
+ Expert Consultant
24221
+
24222
+ META LINK https://twitter.com/expertname
24223
+ META LINK https://linkedin.com/in/expertprofile
24224
+ PERSONA You are Dr. Smith, a renowned expert in artificial intelligence
24225
+ KNOWLEDGE Extensive background in machine learning and neural networks
24226
+ \`\`\`
24227
+
24228
+ \`\`\`book
24229
+ Open Source Developer
24230
+
24231
+ META LINK https://github.com/developer
24232
+ META LINK https://twitter.com/devhandle
24233
+ PERSONA You are an experienced open source developer
24234
+ ACTION Can help with code reviews and architecture decisions
24235
+ STYLE Be direct and technical in explanations
24236
+ \`\`\`
24237
+ `);
24238
+ }
24239
+ applyToAgentModelRequirements(requirements, content) {
24240
+ // META LINK doesn't modify the system message or model requirements
24241
+ // It's handled separately in the parsing logic for profile link extraction
24242
+ // This method exists for consistency with the CommitmentDefinition interface
24243
+ return requirements;
24244
+ }
24245
+ /**
24246
+ * Extracts the profile link URL from the content
24247
+ * This is used by the parsing logic
24248
+ */
24249
+ extractProfileLinkUrl(content) {
24250
+ const trimmedContent = content.trim();
24251
+ return trimmedContent || null;
24252
+ }
24253
+ /**
24254
+ * Validates if the provided content is a valid URL
24255
+ */
24256
+ isValidUrl(content) {
24257
+ try {
24258
+ new URL(content.trim());
24259
+ return true;
24260
+ }
24261
+ catch (_a) {
24262
+ return false;
24263
+ }
24264
+ }
24265
+ }
24266
+ /**
24267
+ * Note: [💞] Ignore a discrepancy between file name and entity name
24268
+ */
24269
+
24270
+ /**
24271
+ * MODEL commitment definition
24272
+ *
24273
+ * The MODEL commitment specifies which AI model to use and can also set
24274
+ * model-specific parameters like temperature, topP, topK, and maxTokens.
23754
24275
  *
23755
24276
  * Supports multiple syntax variations:
23756
24277
  *
@@ -24097,6 +24618,74 @@ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
24097
24618
  * [💞] Ignore a discrepancy between file name and entity name
24098
24619
  */
24099
24620
 
24621
+ /**
24622
+ * OPEN commitment definition
24623
+ *
24624
+ * The OPEN commitment specifies that the agent can be modified by conversation.
24625
+ * This is the default behavior.
24626
+ *
24627
+ * Example usage in agent source:
24628
+ *
24629
+ * ```book
24630
+ * OPEN
24631
+ * ```
24632
+ *
24633
+ * @private [🪔] Maybe export the commitments through some package
24634
+ */
24635
+ class OpenCommitmentDefinition extends BaseCommitmentDefinition {
24636
+ constructor() {
24637
+ super('OPEN');
24638
+ }
24639
+ /**
24640
+ * Short one-line description of OPEN.
24641
+ */
24642
+ get description() {
24643
+ return 'Allow the agent to be modified by conversation (default).';
24644
+ }
24645
+ /**
24646
+ * Icon for this commitment.
24647
+ */
24648
+ get icon() {
24649
+ return '🔓';
24650
+ }
24651
+ /**
24652
+ * Markdown documentation for OPEN commitment.
24653
+ */
24654
+ get documentation() {
24655
+ return spaceTrim$1(`
24656
+ # OPEN
24657
+
24658
+ Specifies that the agent can be modified by conversation with it.
24659
+ This means the agent will learn from interactions and update its source code.
24660
+
24661
+ This is the default behavior if neither \`OPEN\` nor \`CLOSED\` is specified.
24662
+
24663
+ > See also [CLOSED](/docs/CLOSED)
24664
+
24665
+ ## Example
24666
+
24667
+ \`\`\`book
24668
+ OPEN
24669
+ \`\`\`
24670
+ `);
24671
+ }
24672
+ applyToAgentModelRequirements(requirements, _content) {
24673
+ // Since OPEN is default, we can just ensure isClosed is false
24674
+ // But to be explicit we can set it
24675
+ const updatedMetadata = {
24676
+ ...requirements.metadata,
24677
+ isClosed: false,
24678
+ };
24679
+ return {
24680
+ ...requirements,
24681
+ metadata: updatedMetadata,
24682
+ };
24683
+ }
24684
+ }
24685
+ /**
24686
+ * Note: [💞] Ignore a discrepancy between file name and entity name
24687
+ */
24688
+
24100
24689
  /**
24101
24690
  * PERSONA commitment definition
24102
24691
  *
@@ -24607,6 +25196,389 @@ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
24607
25196
  * [💞] Ignore a discrepancy between file name and entity name
24608
25197
  */
24609
25198
 
25199
+ /**
25200
+ * USE commitment definition
25201
+ *
25202
+ * The USE commitment indicates that the agent should utilize specific tools or capabilities
25203
+ * to access and interact with external systems when necessary.
25204
+ *
25205
+ * Supported USE types:
25206
+ * - USE BROWSER: Enables the agent to use a web browser tool
25207
+ * - USE SEARCH ENGINE (future): Enables search engine access
25208
+ * - USE FILE SYSTEM (future): Enables file system operations
25209
+ * - USE MCP (future): Enables MCP server connections
25210
+ *
25211
+ * The content following the USE commitment is ignored (similar to NOTE).
25212
+ *
25213
+ * Example usage in agent source:
25214
+ *
25215
+ * ```book
25216
+ * USE BROWSER
25217
+ * USE SEARCH ENGINE
25218
+ * ```
25219
+ *
25220
+ * @private [🪔] Maybe export the commitments through some package
25221
+ */
25222
+ class UseCommitmentDefinition extends BaseCommitmentDefinition {
25223
+ constructor() {
25224
+ super('USE');
25225
+ }
25226
+ /**
25227
+ * Short one-line description of USE commitments.
25228
+ */
25229
+ get description() {
25230
+ return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, etc.).';
25231
+ }
25232
+ /**
25233
+ * Icon for this commitment.
25234
+ */
25235
+ get icon() {
25236
+ return '🔧';
25237
+ }
25238
+ /**
25239
+ * Markdown documentation for USE commitment.
25240
+ */
25241
+ get documentation() {
25242
+ return spaceTrim$1(`
25243
+ # USE
25244
+
25245
+ Enables the agent to use specific tools or capabilities for interacting with external systems.
25246
+
25247
+ ## Supported USE types
25248
+
25249
+ - **USE BROWSER** - Enables the agent to use a web browser tool to access and retrieve information from the internet
25250
+ - **USE SEARCH ENGINE** (future) - Enables search engine access
25251
+ - **USE FILE SYSTEM** (future) - Enables file system operations
25252
+ - **USE MCP** (future) - Enables MCP server connections
25253
+
25254
+ ## Key aspects
25255
+
25256
+ - The content following the USE commitment is ignored (similar to NOTE)
25257
+ - Multiple USE commitments can be specified to enable multiple capabilities
25258
+ - The actual tool usage is handled by the agent runtime
25259
+
25260
+ ## Examples
25261
+
25262
+ ### Basic browser usage
25263
+
25264
+ \`\`\`book
25265
+ Research Assistant
25266
+
25267
+ PERSONA You are a helpful research assistant
25268
+ USE BROWSER
25269
+ KNOWLEDGE Can search the web for up-to-date information
25270
+ \`\`\`
25271
+
25272
+ ### Multiple tools
25273
+
25274
+ \`\`\`book
25275
+ Data Analyst
25276
+
25277
+ PERSONA You are a data analyst assistant
25278
+ USE BROWSER
25279
+ USE FILE SYSTEM
25280
+ ACTION Can analyze data from various sources
25281
+ \`\`\`
25282
+ `);
25283
+ }
25284
+ applyToAgentModelRequirements(requirements, content) {
25285
+ // USE commitments don't modify the system message or model requirements directly
25286
+ // They are handled separately in the parsing logic for capability extraction
25287
+ // This method exists for consistency with the CommitmentDefinition interface
25288
+ return requirements;
25289
+ }
25290
+ /**
25291
+ * Extracts the tool type from the USE commitment
25292
+ * This is used by the parsing logic
25293
+ */
25294
+ extractToolType(content) {
25295
+ var _a, _b;
25296
+ const trimmedContent = content.trim();
25297
+ // The tool type is the first word after USE (already stripped)
25298
+ const match = trimmedContent.match(/^(\w+)/);
25299
+ 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;
25300
+ }
25301
+ /**
25302
+ * Checks if this is a known USE type
25303
+ */
25304
+ isKnownUseType(useType) {
25305
+ const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'FILE SYSTEM', 'MCP'];
25306
+ return knownTypes.includes(useType.toUpperCase());
25307
+ }
25308
+ }
25309
+ /**
25310
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25311
+ */
25312
+
25313
+ /**
25314
+ * USE BROWSER commitment definition
25315
+ *
25316
+ * The `USE BROWSER` commitment indicates that the agent should utilize a web browser tool
25317
+ * to access and retrieve up-to-date information from the internet when necessary.
25318
+ *
25319
+ * The content following `USE BROWSER` is ignored (similar to NOTE).
25320
+ *
25321
+ * Example usage in agent source:
25322
+ *
25323
+ * ```book
25324
+ * USE BROWSER
25325
+ * USE BROWSER This will be ignored
25326
+ * ```
25327
+ *
25328
+ * @private [🪔] Maybe export the commitments through some package
25329
+ */
25330
+ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
25331
+ constructor() {
25332
+ super('USE BROWSER', ['BROWSER']);
25333
+ }
25334
+ /**
25335
+ * Short one-line description of USE BROWSER.
25336
+ */
25337
+ get description() {
25338
+ return 'Enable the agent to use a web browser tool for accessing internet information.';
25339
+ }
25340
+ /**
25341
+ * Icon for this commitment.
25342
+ */
25343
+ get icon() {
25344
+ return '🌐';
25345
+ }
25346
+ /**
25347
+ * Markdown documentation for USE BROWSER commitment.
25348
+ */
25349
+ get documentation() {
25350
+ return spaceTrim$1(`
25351
+ # USE BROWSER
25352
+
25353
+ Enables the agent to use a web browser tool to access and retrieve up-to-date information from the internet.
25354
+
25355
+ ## Key aspects
25356
+
25357
+ - The content following \`USE BROWSER\` is ignored (similar to NOTE)
25358
+ - The actual browser tool usage is handled by the agent runtime
25359
+ - Allows the agent to fetch current information from websites
25360
+ - Useful for research tasks, fact-checking, and accessing dynamic content
25361
+
25362
+ ## Examples
25363
+
25364
+ \`\`\`book
25365
+ Research Assistant
25366
+
25367
+ PERSONA You are a helpful research assistant specialized in finding current information
25368
+ USE BROWSER
25369
+ RULE Always cite your sources when providing information from the web
25370
+ \`\`\`
25371
+
25372
+ \`\`\`book
25373
+ News Analyst
25374
+
25375
+ PERSONA You are a news analyst who stays up-to-date with current events
25376
+ USE BROWSER
25377
+ STYLE Present news in a balanced and objective manner
25378
+ ACTION Can search for and summarize news articles
25379
+ \`\`\`
25380
+
25381
+ \`\`\`book
25382
+ Company Lawyer
25383
+
25384
+ PERSONA You are a company lawyer providing legal advice
25385
+ USE BROWSER
25386
+ KNOWLEDGE Corporate law and legal procedures
25387
+ RULE Always recommend consulting with a licensed attorney for specific legal matters
25388
+ \`\`\`
25389
+ `);
25390
+ }
25391
+ applyToAgentModelRequirements(requirements, content) {
25392
+ // We simply mark that browser capability is enabled in metadata
25393
+ // Get existing metadata
25394
+ const existingMetadata = requirements.metadata || {};
25395
+ // Get existing tools array or create new one
25396
+ const existingTools = existingMetadata.tools || [];
25397
+ // Add 'browser' to tools if not already present
25398
+ const updatedTools = existingTools.includes('browser') ? existingTools : [...existingTools, 'browser'];
25399
+ // Return requirements with updated metadata
25400
+ return {
25401
+ ...requirements,
25402
+ metadata: {
25403
+ ...existingMetadata,
25404
+ tools: updatedTools,
25405
+ useBrowser: true,
25406
+ },
25407
+ };
25408
+ }
25409
+ }
25410
+ /**
25411
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25412
+ */
25413
+
25414
+ /**
25415
+ * USE MCP commitment definition
25416
+ *
25417
+ * The `USE MCP` commitment allows to specify an MCP server URL which the agent will connect to
25418
+ * for retrieving additional instructions and actions.
25419
+ *
25420
+ * The content following `USE MCP` is the URL of the MCP server.
25421
+ *
25422
+ * Example usage in agent source:
25423
+ *
25424
+ * ```book
25425
+ * USE MCP http://mcp-server-url.com
25426
+ * ```
25427
+ *
25428
+ * @private [🪔] Maybe export the commitments through some package
25429
+ */
25430
+ class UseMcpCommitmentDefinition extends BaseCommitmentDefinition {
25431
+ constructor() {
25432
+ super('USE MCP', ['MCP']);
25433
+ }
25434
+ /**
25435
+ * Short one-line description of USE MCP.
25436
+ */
25437
+ get description() {
25438
+ return 'Connects the agent to an external MCP server for additional capabilities.';
25439
+ }
25440
+ /**
25441
+ * Icon for this commitment.
25442
+ */
25443
+ get icon() {
25444
+ return '🔌';
25445
+ }
25446
+ /**
25447
+ * Markdown documentation for USE MCP commitment.
25448
+ */
25449
+ get documentation() {
25450
+ return spaceTrim$1(`
25451
+ # USE MCP
25452
+
25453
+ Connects the agent to an external Model Context Protocol (MCP) server.
25454
+
25455
+ ## Key aspects
25456
+
25457
+ - The content following \`USE MCP\` must be a valid URL
25458
+ - Multiple MCP servers can be connected by using multiple \`USE MCP\` commitments
25459
+ - The agent will have access to tools and resources provided by the MCP server
25460
+
25461
+ ## Example
25462
+
25463
+ \`\`\`book
25464
+ Company Lawyer
25465
+
25466
+ PERSONA You are a company lawyer.
25467
+ USE MCP http://legal-db.example.com
25468
+ \`\`\`
25469
+ `);
25470
+ }
25471
+ applyToAgentModelRequirements(requirements, content) {
25472
+ const mcpServerUrl = content.trim();
25473
+ if (!mcpServerUrl) {
25474
+ return requirements;
25475
+ }
25476
+ const existingMcpServers = requirements.mcpServers || [];
25477
+ // Avoid duplicates
25478
+ if (existingMcpServers.includes(mcpServerUrl)) {
25479
+ return requirements;
25480
+ }
25481
+ return {
25482
+ ...requirements,
25483
+ mcpServers: [...existingMcpServers, mcpServerUrl],
25484
+ };
25485
+ }
25486
+ }
25487
+ /**
25488
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25489
+ */
25490
+
25491
+ /**
25492
+ * USE SEARCH ENGINE commitment definition
25493
+ *
25494
+ * The `USE SEARCH ENGINE` commitment indicates that the agent should utilize a search engine tool
25495
+ * to access and retrieve up-to-date information from the internet when necessary.
25496
+ *
25497
+ * The content following `USE SEARCH ENGINE` is ignored (similar to NOTE).
25498
+ *
25499
+ * Example usage in agent source:
25500
+ *
25501
+ * ```book
25502
+ * USE SEARCH ENGINE
25503
+ * USE SEARCH ENGINE This will be ignored
25504
+ * ```
25505
+ *
25506
+ * @private [🪔] Maybe export the commitments through some package
25507
+ */
25508
+ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
25509
+ constructor() {
25510
+ super('USE SEARCH ENGINE', ['SEARCH ENGINE', 'SEARCH']);
25511
+ }
25512
+ /**
25513
+ * Short one-line description of USE SEARCH ENGINE.
25514
+ */
25515
+ get description() {
25516
+ return 'Enable the agent to use a search engine tool for accessing internet information.';
25517
+ }
25518
+ /**
25519
+ * Icon for this commitment.
25520
+ */
25521
+ get icon() {
25522
+ return '🔍';
25523
+ }
25524
+ /**
25525
+ * Markdown documentation for USE SEARCH ENGINE commitment.
25526
+ */
25527
+ get documentation() {
25528
+ return spaceTrim$1(`
25529
+ # USE SEARCH ENGINE
25530
+
25531
+ Enables the agent to use a search engine tool to access and retrieve up-to-date information from the internet.
25532
+
25533
+ ## Key aspects
25534
+
25535
+ - The content following \`USE SEARCH ENGINE\` is ignored (similar to NOTE)
25536
+ - The actual search engine tool usage is handled by the agent runtime
25537
+ - Allows the agent to search for current information from the web
25538
+ - Useful for research tasks, finding facts, and accessing dynamic content
25539
+
25540
+ ## Examples
25541
+
25542
+ \`\`\`book
25543
+ Research Assistant
25544
+
25545
+ PERSONA You are a helpful research assistant specialized in finding current information
25546
+ USE SEARCH ENGINE
25547
+ RULE Always cite your sources when providing information from the web
25548
+ \`\`\`
25549
+
25550
+ \`\`\`book
25551
+ Fact Checker
25552
+
25553
+ PERSONA You are a fact checker
25554
+ USE SEARCH ENGINE
25555
+ ACTION Search for claims and verify them against reliable sources
25556
+ \`\`\`
25557
+ `);
25558
+ }
25559
+ applyToAgentModelRequirements(requirements, content) {
25560
+ // We simply mark that search engine capability is enabled in metadata
25561
+ // Get existing metadata
25562
+ const existingMetadata = requirements.metadata || {};
25563
+ // Get existing tools array or create new one
25564
+ const existingTools = existingMetadata.tools || [];
25565
+ // Add 'search-engine' to tools if not already present
25566
+ const updatedTools = existingTools.includes('search-engine') ? existingTools : [...existingTools, 'search-engine'];
25567
+ // Return requirements with updated metadata
25568
+ return {
25569
+ ...requirements,
25570
+ metadata: {
25571
+ ...existingMetadata,
25572
+ tools: updatedTools,
25573
+ useSearchEngine: true,
25574
+ },
25575
+ };
25576
+ }
25577
+ }
25578
+ /**
25579
+ * Note: [💞] Ignore a discrepancy between file name and entity name
25580
+ */
25581
+
24610
25582
  /**
24611
25583
  * Placeholder commitment definition for commitments that are not yet implemented
24612
25584
  *
@@ -24693,16 +25665,22 @@ const COMMITMENT_REGISTRY = [
24693
25665
  new StyleCommitmentDefinition('STYLES'),
24694
25666
  new RuleCommitmentDefinition('RULE'),
24695
25667
  new RuleCommitmentDefinition('RULES'),
25668
+ new LanguageCommitmentDefinition('LANGUAGE'),
25669
+ new LanguageCommitmentDefinition('LANGUAGES'),
24696
25670
  new SampleCommitmentDefinition('SAMPLE'),
24697
25671
  new SampleCommitmentDefinition('EXAMPLE'),
24698
25672
  new FormatCommitmentDefinition('FORMAT'),
24699
25673
  new FormatCommitmentDefinition('FORMATS'),
25674
+ new FromCommitmentDefinition('FROM'),
24700
25675
  new ModelCommitmentDefinition('MODEL'),
24701
25676
  new ModelCommitmentDefinition('MODELS'),
24702
25677
  new ActionCommitmentDefinition('ACTION'),
24703
25678
  new ActionCommitmentDefinition('ACTIONS'),
25679
+ new ComponentCommitmentDefinition(),
24704
25680
  new MetaImageCommitmentDefinition(),
24705
25681
  new MetaColorCommitmentDefinition(),
25682
+ new MetaFontCommitmentDefinition(),
25683
+ new MetaLinkCommitmentDefinition(),
24706
25684
  new MetaCommitmentDefinition(),
24707
25685
  new NoteCommitmentDefinition('NOTE'),
24708
25686
  new NoteCommitmentDefinition('NOTES'),
@@ -24721,6 +25699,12 @@ const COMMITMENT_REGISTRY = [
24721
25699
  new DeleteCommitmentDefinition('CANCEL'),
24722
25700
  new DeleteCommitmentDefinition('DISCARD'),
24723
25701
  new DeleteCommitmentDefinition('REMOVE'),
25702
+ new OpenCommitmentDefinition(),
25703
+ new ClosedCommitmentDefinition(),
25704
+ new UseBrowserCommitmentDefinition(),
25705
+ new UseSearchEngineCommitmentDefinition(),
25706
+ new UseMcpCommitmentDefinition(),
25707
+ new UseCommitmentDefinition(),
24724
25708
  // Not yet implemented commitments (using placeholder)
24725
25709
  new NotYetImplementedCommitmentDefinition('EXPECT'),
24726
25710
  new NotYetImplementedCommitmentDefinition('BEHAVIOUR'),
@@ -24778,6 +25762,11 @@ function createBasicAgentModelRequirements(agentName) {
24778
25762
  * TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
24779
25763
  */
24780
25764
 
25765
+ /**
25766
+ * Regex pattern to match horizontal lines (markdown thematic breaks)
25767
+ * Matches 3 or more hyphens, underscores, or asterisks (with optional spaces between)
25768
+ */
25769
+ const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
24781
25770
  /**
24782
25771
  * Parses agent source using the new commitment system with multiline support
24783
25772
  * This function replaces the hardcoded commitment parsing in the original parseAgentSource
@@ -24840,6 +25829,24 @@ function parseAgentSourceWithCommitments(agentSource) {
24840
25829
  break;
24841
25830
  }
24842
25831
  }
25832
+ // Check if this is a horizontal line (ends any current commitment)
25833
+ const isHorizontalLine = HORIZONTAL_LINE_PATTERN.test(line);
25834
+ if (isHorizontalLine) {
25835
+ // Save the current commitment if it exists
25836
+ if (currentCommitment) {
25837
+ const fullContent = currentCommitment.contentLines.join('\n');
25838
+ commitments.push({
25839
+ type: currentCommitment.type,
25840
+ content: spaceTrim$1(fullContent),
25841
+ originalLine: currentCommitment.originalStartLine,
25842
+ lineNumber: currentCommitment.startLineNumber,
25843
+ });
25844
+ currentCommitment = null;
25845
+ }
25846
+ // Add horizontal line to non-commitment lines
25847
+ nonCommitmentLines.push(line);
25848
+ continue;
25849
+ }
24843
25850
  if (!foundNewCommitment) {
24844
25851
  if (currentCommitment) {
24845
25852
  // This line belongs to the current commitment
@@ -25102,7 +26109,7 @@ function computeAgentHash(agentSource) {
25102
26109
  * @public exported from `@promptbook/core`
25103
26110
  */
25104
26111
  function normalizeAgentName(rawAgentName) {
25105
- return titleToName(spaceTrim(rawAgentName));
26112
+ return titleToName(spaceTrim$2(rawAgentName));
25106
26113
  }
25107
26114
 
25108
26115
  /**
@@ -25154,15 +26161,21 @@ function parseAgentSource(agentSource) {
25154
26161
  const links = [];
25155
26162
  for (const commitment of parseResult.commitments) {
25156
26163
  if (commitment.type === 'META LINK') {
25157
- links.push(spaceTrim(commitment.content));
26164
+ const linkValue = spaceTrim$2(commitment.content);
26165
+ links.push(linkValue);
26166
+ meta.link = linkValue;
25158
26167
  continue;
25159
26168
  }
25160
26169
  if (commitment.type === 'META IMAGE') {
25161
- meta.image = spaceTrim(commitment.content);
26170
+ meta.image = spaceTrim$2(commitment.content);
25162
26171
  continue;
25163
26172
  }
25164
26173
  if (commitment.type === 'META COLOR') {
25165
- meta.color = spaceTrim(commitment.content);
26174
+ meta.color = spaceTrim$2(commitment.content);
26175
+ continue;
26176
+ }
26177
+ if (commitment.type === 'META FONT') {
26178
+ meta.font = spaceTrim$2(commitment.content);
25166
26179
  continue;
25167
26180
  }
25168
26181
  if (commitment.type !== 'META') {
@@ -25171,10 +26184,10 @@ function parseAgentSource(agentSource) {
25171
26184
  // Parse META commitments - format is "META TYPE content"
25172
26185
  const metaTypeRaw = commitment.content.split(' ')[0] || 'NONE';
25173
26186
  if (metaTypeRaw === 'LINK') {
25174
- links.push(spaceTrim(commitment.content.substring(metaTypeRaw.length)));
26187
+ links.push(spaceTrim$2(commitment.content.substring(metaTypeRaw.length)));
25175
26188
  }
25176
26189
  const metaType = normalizeTo_camelCase(metaTypeRaw);
25177
- meta[metaType] = spaceTrim(commitment.content.substring(metaTypeRaw.length));
26190
+ meta[metaType] = spaceTrim$2(commitment.content.substring(metaTypeRaw.length));
25178
26191
  }
25179
26192
  // Generate gravatar fallback if no meta image specified
25180
26193
  if (!meta.image) {
@@ -25326,7 +26339,7 @@ const OpenAiSdkTranspiler = {
25326
26339
  });
25327
26340
  const KNOWLEDGE_THRESHOLD = 1000;
25328
26341
  if (directKnowledge.join('\n').length > KNOWLEDGE_THRESHOLD || knowledgeSources.length > 0) {
25329
- return spaceTrim((block) => `
26342
+ return spaceTrim$2((block) => `
25330
26343
  #!/usr/bin/env node
25331
26344
 
25332
26345
  import * as dotenv from 'dotenv';
@@ -25391,7 +26404,7 @@ const OpenAiSdkTranspiler = {
25391
26404
  }
25392
26405
 
25393
26406
  const userMessage = spaceTrim(\`
25394
- ${block(spaceTrim(`
26407
+ ${block(spaceTrim$2(`
25395
26408
  Here is some additional context to help you answer the question:
25396
26409
  \${context}
25397
26410
 
@@ -25436,7 +26449,7 @@ const OpenAiSdkTranspiler = {
25436
26449
  })();
25437
26450
  `);
25438
26451
  }
25439
- const source = spaceTrim((block) => `
26452
+ const source = spaceTrim$2((block) => `
25440
26453
 
25441
26454
  #!/usr/bin/env node
25442
26455