@promptbook/javascript 0.105.0-0 → 0.105.0-10

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 (70) hide show
  1. package/README.md +36 -77
  2. package/esm/index.es.js +4135 -151
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/browser.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/core.index.d.ts +4 -0
  6. package/esm/typings/src/_packages/types.index.d.ts +16 -0
  7. package/esm/typings/src/_packages/utils.index.d.ts +2 -0
  8. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +15 -3
  9. package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +11 -1
  10. package/esm/typings/src/book-2.0/agent-source/communication-samples.test.d.ts +1 -0
  11. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.blocks.test.d.ts +1 -0
  12. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.import.test.d.ts +1 -0
  13. package/esm/typings/src/book-2.0/agent-source/parseAgentSource.import.test.d.ts +1 -0
  14. package/esm/typings/src/book-2.0/agent-source/parseAgentSourceWithCommitments.blocks.test.d.ts +1 -0
  15. package/esm/typings/src/book-components/Chat/AgentChat/AgentChatProps.d.ts +5 -0
  16. package/esm/typings/src/book-components/Chat/Chat/ChatMessageItem.d.ts +15 -1
  17. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +20 -9
  18. package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +5 -0
  19. package/esm/typings/src/book-components/Chat/types/ChatMessage.d.ts +43 -0
  20. package/esm/typings/src/commitments/NOTE/NOTE.d.ts +2 -2
  21. package/esm/typings/src/commitments/USE_BROWSER/USE_BROWSER.d.ts +4 -0
  22. package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.d.ts +10 -0
  23. package/esm/typings/src/commitments/USE_SEARCH_ENGINE/USE_SEARCH_ENGINE.test.d.ts +1 -0
  24. package/esm/typings/src/commitments/USE_TIME/USE_TIME.d.ts +44 -0
  25. package/esm/typings/src/commitments/USE_TIME/USE_TIME.test.d.ts +1 -0
  26. package/esm/typings/src/commitments/_base/BaseCommitmentDefinition.d.ts +14 -0
  27. package/esm/typings/src/commitments/_base/CommitmentDefinition.d.ts +14 -0
  28. package/esm/typings/src/commitments/index.d.ts +17 -2
  29. package/esm/typings/src/config.d.ts +1 -0
  30. package/esm/typings/src/execution/LlmExecutionTools.d.ts +3 -1
  31. package/esm/typings/src/import-plugins/$fileImportPlugins.d.ts +7 -0
  32. package/esm/typings/src/import-plugins/AgentFileImportPlugin.d.ts +7 -0
  33. package/esm/typings/src/import-plugins/FileImportPlugin.d.ts +24 -0
  34. package/esm/typings/src/import-plugins/JsonFileImportPlugin.d.ts +7 -0
  35. package/esm/typings/src/import-plugins/TextFileImportPlugin.d.ts +7 -0
  36. package/esm/typings/src/llm-providers/_common/utils/cache/cacheLlmTools.d.ts +2 -1
  37. package/esm/typings/src/llm-providers/_common/utils/count-total-usage/countUsage.d.ts +2 -2
  38. package/esm/typings/src/llm-providers/agent/Agent.d.ts +14 -2
  39. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +3 -1
  40. package/esm/typings/src/llm-providers/agent/AgentOptions.d.ts +7 -0
  41. package/esm/typings/src/llm-providers/agent/RemoteAgent.d.ts +1 -0
  42. package/esm/typings/src/llm-providers/agent/RemoteAgentOptions.d.ts +1 -1
  43. package/esm/typings/src/llm-providers/openai/OpenAiAssistantExecutionTools.d.ts +10 -0
  44. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +7 -0
  45. package/esm/typings/src/llm-providers/remote/RemoteLlmExecutionTools.d.ts +1 -1
  46. package/esm/typings/src/scripting/javascript/JavascriptExecutionToolsOptions.d.ts +6 -1
  47. package/esm/typings/src/search-engines/SearchEngine.d.ts +1 -1
  48. package/esm/typings/src/search-engines/_index.d.ts +6 -0
  49. package/esm/typings/src/search-engines/bing/BingSearchEngine.d.ts +1 -1
  50. package/esm/typings/src/search-engines/dummy/DummySearchEngine.d.ts +1 -1
  51. package/esm/typings/src/search-engines/google/GoogleSearchEngine.d.ts +18 -0
  52. package/esm/typings/src/search-engines/serp/SerpSearchEngine.d.ts +15 -0
  53. package/esm/typings/src/speech-recognition/BrowserSpeechRecognition.d.ts +21 -0
  54. package/esm/typings/src/speech-recognition/OpenAiSpeechRecognition.d.ts +32 -0
  55. package/esm/typings/src/types/ModelRequirements.d.ts +6 -12
  56. package/esm/typings/src/types/SpeechRecognition.d.ts +58 -0
  57. package/esm/typings/src/types/typeAliases.d.ts +4 -0
  58. package/esm/typings/src/utils/execCommand/$execCommandNormalizeOptions.d.ts +2 -3
  59. package/esm/typings/src/utils/execCommand/ExecCommandOptions.d.ts +7 -1
  60. package/esm/typings/src/utils/misc/linguisticHash.d.ts +6 -0
  61. package/esm/typings/src/utils/misc/linguisticHash.test.d.ts +1 -0
  62. package/esm/typings/src/utils/organization/keepImported.d.ts +9 -0
  63. package/esm/typings/src/utils/organization/keepTypeImported.d.ts +0 -1
  64. package/esm/typings/src/utils/random/$generateBookBoilerplate.d.ts +4 -0
  65. package/esm/typings/src/utils/random/$randomAgentPersona.d.ts +2 -1
  66. package/esm/typings/src/utils/random/$randomAgentRule.d.ts +14 -0
  67. package/esm/typings/src/version.d.ts +1 -1
  68. package/package.json +2 -2
  69. package/umd/index.umd.js +4135 -151
  70. package/umd/index.umd.js.map +1 -1
package/esm/index.es.js CHANGED
@@ -18,7 +18,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
18
18
  * @generated
19
19
  * @see https://github.com/webgptorg/promptbook
20
20
  */
21
- const PROMPTBOOK_ENGINE_VERSION = '0.105.0-0';
21
+ const PROMPTBOOK_ENGINE_VERSION = '0.105.0-10';
22
22
  /**
23
23
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
24
24
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -943,6 +943,7 @@ const PROMPTBOOK_COLOR = Color.fromString('promptbook');
943
943
  SEPARATOR: Color.fromHex('#cccccc'),
944
944
  COMMITMENT: Color.fromHex('#DA0F78'),
945
945
  PARAMETER: Color.fromHex('#8e44ad'),
946
+ CODE_BLOCK: Color.fromHex('#7700ffff'),
946
947
  });
947
948
  // <- TODO: [🧠][🈵] Using `Color` here increases the package size approx 3kb, maybe remove it
948
949
  /**
@@ -1450,6 +1451,93 @@ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
1450
1451
  * TODO: [🌺] Use some intermediate util splitWords
1451
1452
  */
1452
1453
 
1454
+ /**
1455
+ * Tests if given string is valid file path.
1456
+ *
1457
+ * Note: This does not check if the file exists only if the path is valid
1458
+ * @public exported from `@promptbook/utils`
1459
+ */
1460
+ function isValidFilePath(filename) {
1461
+ if (typeof filename !== 'string') {
1462
+ return false;
1463
+ }
1464
+ if (filename.split('\n').length > 1) {
1465
+ return false;
1466
+ }
1467
+ // Normalize slashes early so heuristics can detect path-like inputs
1468
+ const filenameSlashes = filename.replace(/\\/g, '/');
1469
+ // Reject strings that look like sentences (informational text)
1470
+ // Heuristic: contains multiple spaces and ends with a period, or contains typical sentence punctuation
1471
+ // But skip this heuristic if the string looks like a path (contains '/' or starts with a drive letter)
1472
+ if (filename.trim().length > 60 && // long enough to be a sentence
1473
+ /[.!?]/.test(filename) && // contains sentence punctuation
1474
+ filename.split(' ').length > 8 && // has many words
1475
+ !/\/|^[A-Z]:/i.test(filenameSlashes) // do NOT treat as sentence if looks like a path
1476
+ ) {
1477
+ return false;
1478
+ }
1479
+ // Absolute Unix path: /hello.txt
1480
+ if (/^(\/)/i.test(filenameSlashes)) {
1481
+ // console.log(filename, 'Absolute Unix path: /hello.txt');
1482
+ return true;
1483
+ }
1484
+ // Absolute Windows path: C:/ or C:\ (allow spaces and multiple dots in filename)
1485
+ if (/^[A-Z]:\/.+$/i.test(filenameSlashes)) {
1486
+ // console.log(filename, 'Absolute Windows path: /hello.txt');
1487
+ return true;
1488
+ }
1489
+ // Relative path: ./hello.txt
1490
+ if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
1491
+ // console.log(filename, 'Relative path: ./hello.txt');
1492
+ return true;
1493
+ }
1494
+ // Allow paths like foo/hello
1495
+ if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
1496
+ // console.log(filename, 'Allow paths like foo/hello');
1497
+ return true;
1498
+ }
1499
+ // Allow paths like hello.book
1500
+ if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
1501
+ // console.log(filename, 'Allow paths like hello.book');
1502
+ return true;
1503
+ }
1504
+ return false;
1505
+ }
1506
+ /**
1507
+ * TODO: [🍏] Implement for MacOs
1508
+ */
1509
+
1510
+ /**
1511
+ * Tests if given string is valid URL.
1512
+ *
1513
+ * Note: [🔂] This function is idempotent.
1514
+ * Note: Dataurl are considered perfectly valid.
1515
+ * Note: There are few similar functions:
1516
+ * - `isValidUrl` *(this one)* which tests any URL
1517
+ * - `isValidAgentUrl` which tests just agent URL
1518
+ * - `isValidPipelineUrl` which tests just pipeline URL
1519
+ *
1520
+ * @public exported from `@promptbook/utils`
1521
+ */
1522
+ function isValidUrl(url) {
1523
+ if (typeof url !== 'string') {
1524
+ return false;
1525
+ }
1526
+ try {
1527
+ if (url.startsWith('blob:')) {
1528
+ url = url.replace(/^blob:/, '');
1529
+ }
1530
+ const urlObject = new URL(url /* because fail is handled */);
1531
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
1532
+ return false;
1533
+ }
1534
+ return true;
1535
+ }
1536
+ catch (error) {
1537
+ return false;
1538
+ }
1539
+ }
1540
+
1453
1541
  const defaultDiacriticsRemovalMap = [
1454
1542
  {
1455
1543
  base: 'A',
@@ -2156,6 +2244,16 @@ function unwrapResult(text, options) {
2156
2244
  trimmedText = spaceTrim$1(trimmedText);
2157
2245
  }
2158
2246
  let processedText = trimmedText;
2247
+ // Check for markdown code block
2248
+ const codeBlockRegex = /^```[a-z]*\n([\s\S]*?)\n```\s*$/;
2249
+ const codeBlockMatch = processedText.match(codeBlockRegex);
2250
+ if (codeBlockMatch && codeBlockMatch[1] !== undefined) {
2251
+ // Check if there's only one code block
2252
+ const codeBlockCount = (processedText.match(/```/g) || []).length / 2;
2253
+ if (codeBlockCount === 1) {
2254
+ return unwrapResult(codeBlockMatch[1], { isTrimmed: false, isIntroduceSentenceRemoved: false });
2255
+ }
2256
+ }
2159
2257
  if (isIntroduceSentenceRemoved) {
2160
2258
  const introduceSentenceRegex = /^[a-zěščřžýáíéúů:\s]*:\s*/i;
2161
2259
  if (introduceSentenceRegex.test(text)) {
@@ -2163,6 +2261,14 @@ function unwrapResult(text, options) {
2163
2261
  processedText = processedText.replace(introduceSentenceRegex, '');
2164
2262
  }
2165
2263
  processedText = spaceTrim$1(processedText);
2264
+ // Check again for code block after removing introduce sentence
2265
+ const codeBlockMatch2 = processedText.match(codeBlockRegex);
2266
+ if (codeBlockMatch2 && codeBlockMatch2[1] !== undefined) {
2267
+ const codeBlockCount = (processedText.match(/```/g) || []).length / 2;
2268
+ if (codeBlockCount === 1) {
2269
+ return unwrapResult(codeBlockMatch2[1], { isTrimmed: false, isIntroduceSentenceRemoved: false });
2270
+ }
2271
+ }
2166
2272
  }
2167
2273
  if (processedText.length < 3) {
2168
2274
  return trimmedText;
@@ -2207,196 +2313,4063 @@ function unwrapResult(text, options) {
2207
2313
  */
2208
2314
 
2209
2315
  /**
2210
- * Extracts all code blocks from markdown.
2316
+ * Tests if given string is valid agent URL
2211
2317
  *
2212
- * Note: There are multiple similar functions:
2213
- * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
2214
- * - `extractJsonBlock` extracts exactly one valid JSON code block
2215
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
2216
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
2318
+ * Note: There are few similar functions:
2319
+ * - `isValidUrl` which tests any URL
2320
+ * - `isValidAgentUrl` *(this one)* which tests just agent URL
2321
+ * - `isValidPipelineUrl` which tests just pipeline URL
2217
2322
  *
2218
- * @param markdown any valid markdown
2219
- * @returns code blocks with language and content
2220
- * @throws {ParseError} if block is not closed properly
2221
- * @public exported from `@promptbook/markdown-utils`
2323
+ * @public exported from `@promptbook/utils`
2222
2324
  */
2223
- function extractAllBlocksFromMarkdown(markdown) {
2224
- const codeBlocks = [];
2225
- const lines = markdown.split('\n');
2226
- // Note: [0] Ensure that the last block notated by gt > will be closed
2227
- lines.push('');
2228
- let currentCodeBlock = null;
2229
- for (const line of lines) {
2230
- if (line.startsWith('> ') || line === '>') {
2231
- if (currentCodeBlock === null) {
2232
- currentCodeBlock = { blockNotation: '>', language: null, content: '' };
2233
- } /* not else */
2234
- if (currentCodeBlock.blockNotation === '>') {
2235
- if (currentCodeBlock.content !== '') {
2236
- currentCodeBlock.content += '\n';
2237
- }
2238
- currentCodeBlock.content += line.slice(2);
2239
- }
2240
- }
2241
- else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '>' /* <- Note: [0] */) {
2242
- codeBlocks.push(currentCodeBlock);
2243
- currentCodeBlock = null;
2244
- }
2245
- /* not else */
2246
- if (line.startsWith('```')) {
2247
- const language = line.slice(3).trim() || null;
2248
- if (currentCodeBlock === null) {
2249
- currentCodeBlock = { blockNotation: '```', language, content: '' };
2250
- }
2251
- else {
2252
- if (language !== null) {
2253
- throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed and already opening new ${language} code block`);
2254
- }
2255
- codeBlocks.push(currentCodeBlock);
2256
- currentCodeBlock = null;
2257
- }
2258
- }
2259
- else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '```') {
2260
- if (currentCodeBlock.content !== '') {
2261
- currentCodeBlock.content += '\n';
2262
- }
2263
- currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make proper unescape */;
2264
- }
2325
+ function isValidAgentUrl(url) {
2326
+ if (!isValidUrl(url)) {
2327
+ return false;
2265
2328
  }
2266
- if (currentCodeBlock !== null) {
2267
- throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed at the end of the markdown`);
2329
+ if (!url.startsWith('https://') && !url.startsWith('http://') /* <- Note: [👣] */) {
2330
+ return false;
2268
2331
  }
2269
- return codeBlocks;
2332
+ if (url.includes('#')) {
2333
+ // TODO: [🐠]
2334
+ return false;
2335
+ }
2336
+ /*
2337
+ Note: [👣][🧠] Is it secure to allow pipeline URLs on private and unsecured networks?
2338
+ if (isUrlOnPrivateNetwork(url)) {
2339
+ return false;
2340
+ }
2341
+ */
2342
+ return true;
2270
2343
  }
2271
2344
  /**
2272
- * TODO: Maybe name for `blockNotation` instead of '```' and '>'
2345
+ * TODO: [🐠] Maybe more info why the URL is invalid
2273
2346
  */
2274
2347
 
2275
2348
  /**
2276
- * Extracts exactly ONE code block from markdown.
2349
+ * Generates a regex pattern to match a specific commitment
2277
2350
  *
2278
- * - When there are multiple or no code blocks the function throws a `ParseError`
2279
- *
2280
- * Note: There are multiple similar functions:
2281
- * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
2282
- * - `extractJsonBlock` extracts exactly one valid JSON code block
2283
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
2284
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
2351
+ * Note: It always creates new Regex object
2352
+ * Note: Uses word boundaries to ensure only full words are matched (e.g., "PERSONA" matches but "PERSONALITY" does not)
2285
2353
  *
2286
- * @param markdown any valid markdown
2287
- * @returns code block with language and content
2288
- * @public exported from `@promptbook/markdown-utils`
2289
- * @throws {ParseError} if there is not exactly one code block in the markdown
2354
+ * @private - TODO: [🧠] Maybe should be public?
2290
2355
  */
2291
- function extractOneBlockFromMarkdown(markdown) {
2292
- const codeBlocks = extractAllBlocksFromMarkdown(markdown);
2293
- if (codeBlocks.length !== 1) {
2294
- throw new ParseError(spaceTrim$2((block) => `
2295
- There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
2296
-
2297
- ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
2298
- `));
2356
+ function createCommitmentRegex(commitment, aliases = [], requiresContent = true) {
2357
+ const allCommitments = [commitment, ...aliases];
2358
+ const patterns = allCommitments.map((commitment) => {
2359
+ const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2360
+ return escapedCommitment.split(/\s+/).join('\\s+');
2361
+ });
2362
+ const keywordPattern = patterns.join('|');
2363
+ if (requiresContent) {
2364
+ return new RegExp(`^\\s*(?<type>${keywordPattern})\\b\\s+(?<contents>.+)$`, 'gim');
2365
+ }
2366
+ else {
2367
+ return new RegExp(`^\\s*(?<type>${keywordPattern})\\b(?:\\s+(?<contents>.+))?$`, 'gim');
2299
2368
  }
2300
- return codeBlocks[0];
2301
2369
  }
2302
- /***
2303
- * TODO: [🍓][🌻] Decide of this is internal utility, external util OR validator/postprocessor
2304
- */
2305
-
2306
2370
  /**
2307
- * Extracts code block from markdown.
2371
+ * Generates a regex pattern to match a specific commitment type
2308
2372
  *
2309
- * - When there are multiple or no code blocks the function throws a `ParseError`
2310
- *
2311
- * Note: There are multiple similar function:
2312
- * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
2313
- * - `extractJsonBlock` extracts exactly one valid JSON code block
2314
- * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
2315
- * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
2373
+ * Note: It just matches the type part of the commitment
2374
+ * Note: It always creates new Regex object
2375
+ * Note: Uses word boundaries to ensure only full words are matched (e.g., "PERSONA" matches but "PERSONALITY" does not)
2316
2376
  *
2317
- * @public exported from `@promptbook/markdown-utils`
2318
- * @throws {ParseError} if there is not exactly one code block in the markdown
2377
+ * @private
2319
2378
  */
2320
- function extractBlock(markdown) {
2321
- const { content } = extractOneBlockFromMarkdown(markdown);
2322
- return content;
2379
+ function createCommitmentTypeRegex(commitment, aliases = []) {
2380
+ const allCommitments = [commitment, ...aliases];
2381
+ const patterns = allCommitments.map((commitment) => {
2382
+ const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
2383
+ return escapedCommitment.split(/\s+/).join('\\s+');
2384
+ });
2385
+ const keywordPattern = patterns.join('|');
2386
+ const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b`, 'gim');
2387
+ return regex;
2323
2388
  }
2324
2389
 
2325
2390
  /**
2326
- * Prettify the html code
2391
+ * Base implementation of CommitmentDefinition that provides common functionality
2392
+ * Most commitments can extend this class and only override the applyToAgentModelRequirements method
2327
2393
  *
2328
- * @param content raw html code
2329
- * @returns formatted html code
2330
- * @private withing the package because of HUGE size of prettier dependency
2331
- * @deprecated Prettier removed from Promptbook due to package size
2394
+ * @private
2332
2395
  */
2333
- function prettifyMarkdown(content) {
2334
- return (content + `\n\n<!-- Note: Prettier removed from Promptbook -->`);
2396
+ class BaseCommitmentDefinition {
2397
+ constructor(type, aliases = []) {
2398
+ this.type = type;
2399
+ this.aliases = aliases;
2400
+ }
2401
+ /**
2402
+ * Whether this commitment requires content.
2403
+ * If true, regex will match only if there is content after the commitment keyword.
2404
+ * If false, regex will match even if there is no content.
2405
+ */
2406
+ get requiresContent() {
2407
+ return true;
2408
+ }
2409
+ /**
2410
+ * Creates a regex pattern to match this commitment in agent source
2411
+ * Uses the existing createCommitmentRegex function as internal helper
2412
+ */
2413
+ createRegex() {
2414
+ return createCommitmentRegex(this.type, this.aliases, this.requiresContent);
2415
+ }
2416
+ /**
2417
+ * Creates a regex pattern to match just the commitment type
2418
+ * Uses the existing createCommitmentTypeRegex function as internal helper
2419
+ */
2420
+ createTypeRegex() {
2421
+ return createCommitmentTypeRegex(this.type, this.aliases);
2422
+ }
2423
+ /**
2424
+ * Helper method to create a new requirements object with updated system message
2425
+ * This is commonly used by many commitments
2426
+ */
2427
+ updateSystemMessage(requirements, messageUpdate) {
2428
+ const newMessage = typeof messageUpdate === 'string' ? messageUpdate : messageUpdate(requirements.systemMessage);
2429
+ return {
2430
+ ...requirements,
2431
+ systemMessage: newMessage,
2432
+ };
2433
+ }
2434
+ /**
2435
+ * Helper method to append content to the system message
2436
+ */
2437
+ appendToSystemMessage(requirements, content, separator = '\n\n') {
2438
+ return this.updateSystemMessage(requirements, (currentMessage) => {
2439
+ if (!currentMessage.trim()) {
2440
+ return content;
2441
+ }
2442
+ return currentMessage + separator + content;
2443
+ });
2444
+ }
2445
+ /**
2446
+ * Helper method to add a comment section to the system message
2447
+ * Comments are lines starting with # that will be removed from the final system message
2448
+ * but can be useful for organizing and structuring the message during processing
2449
+ */
2450
+ addCommentSection(requirements, commentTitle, content, position = 'end') {
2451
+ const commentSection = `# ${commentTitle.toUpperCase()}\n${content}`;
2452
+ if (position === 'beginning') {
2453
+ return this.updateSystemMessage(requirements, (currentMessage) => {
2454
+ if (!currentMessage.trim()) {
2455
+ return commentSection;
2456
+ }
2457
+ return commentSection + '\n\n' + currentMessage;
2458
+ });
2459
+ }
2460
+ else {
2461
+ return this.appendToSystemMessage(requirements, commentSection);
2462
+ }
2463
+ }
2464
+ /**
2465
+ * Gets tool function implementations provided by this commitment
2466
+ *
2467
+ * When the `applyToAgentModelRequirements` adds tools to the requirements, this method should return the corresponding function definitions.
2468
+ */
2469
+ getToolFunctions() {
2470
+ return {};
2471
+ }
2472
+ /**
2473
+ * Gets human-readable titles for tool functions provided by this commitment
2474
+ *
2475
+ * This is used in the UI to show a user-friendly name instead of the technical function name.
2476
+ */
2477
+ getToolTitles() {
2478
+ return {};
2479
+ }
2335
2480
  }
2336
2481
 
2337
2482
  /**
2338
- * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
2483
+ * ACTION commitment definition
2339
2484
  *
2340
- * Note: [🔂] This function is idempotent.
2341
- * Note: This is useful for post-processing of the result of the chat LLM model
2342
- * when the model wraps the result in the (markdown) code block.
2485
+ * The ACTION commitment defines specific actions or capabilities that the agent can perform.
2486
+ * This helps define what the agent is capable of doing and how it should approach tasks.
2343
2487
  *
2344
- * @public exported from `@promptbook/markdown-utils`
2345
- */
2346
- function trimCodeBlock(value) {
2347
- value = spaceTrim$1(value);
2348
- if (!/^```[a-z]*(.*)```$/is.test(value)) {
2349
- return value;
2350
- }
2351
- value = value.replace(/^```[a-z]*/i, '');
2352
- value = value.replace(/```$/i, '');
2353
- value = spaceTrim$1(value);
2354
- return value;
2355
- }
2356
-
2357
- /**
2358
- * Function trimEndOfCodeBlock will remove ending code block from the string if it is present.
2488
+ * Example usage in agent source:
2359
2489
  *
2360
- * Note: This is useful for post-processing of the result of the completion LLM model
2361
- * if you want to start code block in the prompt but you don't want to end it in the result.
2490
+ * ```book
2491
+ * ACTION Can generate code snippets and explain programming concepts
2492
+ * ACTION Able to analyze data and provide insights
2493
+ * ```
2362
2494
  *
2363
- * @public exported from `@promptbook/markdown-utils`
2495
+ * @private [🪔] Maybe export the commitments through some package
2364
2496
  */
2365
- function trimEndOfCodeBlock(value) {
2366
- value = spaceTrim$1(value);
2367
- value = value.replace(/```$/g, '');
2368
- value = spaceTrim$1(value);
2369
- return value;
2370
- }
2497
+ class ActionCommitmentDefinition extends BaseCommitmentDefinition {
2498
+ constructor(type = 'ACTION') {
2499
+ super(type);
2500
+ }
2501
+ /**
2502
+ * Short one-line description of ACTION.
2503
+ */
2504
+ get description() {
2505
+ return 'Define agent capabilities and actions it can perform.';
2506
+ }
2507
+ /**
2508
+ * Icon for this commitment.
2509
+ */
2510
+ get icon() {
2511
+ return '⚡';
2512
+ }
2513
+ /**
2514
+ * Markdown documentation for ACTION commitment.
2515
+ */
2516
+ get documentation() {
2517
+ return spaceTrim$1(`
2518
+ # ${this.type}
2371
2519
 
2372
- /**
2373
- * @private internal for `preserve`
2374
- */
2375
- const _preserved = [];
2376
- /**
2377
- * Does nothing, but preserves the function in the bundle
2378
- * Compiler is tricked into thinking the function is used
2379
- *
2380
- * @param value any function to preserve
2381
- * @returns nothing
2382
- * @private within the repository
2383
- */
2384
- function $preserve(...value) {
2385
- _preserved.push(...value);
2520
+ Defines specific actions or capabilities that the agent can perform.
2521
+
2522
+ ## Key aspects
2523
+
2524
+ - Both terms work identically and can be used interchangeably.
2525
+ - Each action adds to the agent's capability list.
2526
+ - Actions help users understand what the agent can do.
2527
+
2528
+ ## Examples
2529
+
2530
+ \`\`\`book
2531
+ Code Assistant
2532
+
2533
+ PERSONA You are a programming assistant
2534
+ ACTION Can generate code snippets and explain programming concepts
2535
+ ACTION Able to debug existing code and suggest improvements
2536
+ ACTION Can create unit tests for functions
2537
+ \`\`\`
2538
+
2539
+ \`\`\`book
2540
+ Data Scientist
2541
+
2542
+ PERSONA You are a data analysis expert
2543
+ ACTION Able to analyze data and provide insights
2544
+ ACTION Can create visualizations and charts
2545
+ ACTION Capable of statistical analysis and modeling
2546
+ KNOWLEDGE Data analysis best practices and statistical methods
2547
+ \`\`\`
2548
+ `);
2549
+ }
2550
+ applyToAgentModelRequirements(requirements, content) {
2551
+ const trimmedContent = content.trim();
2552
+ if (!trimmedContent) {
2553
+ return requirements;
2554
+ }
2555
+ // Add action capability to the system message
2556
+ const actionSection = `Capability: ${trimmedContent}`;
2557
+ return this.appendToSystemMessage(requirements, actionSection, '\n\n');
2558
+ }
2386
2559
  }
2387
2560
  /**
2388
2561
  * Note: [💞] Ignore a discrepancy between file name and entity name
2389
2562
  */
2390
2563
 
2391
- // Note: [💎]
2392
2564
  /**
2393
- * ScriptExecutionTools for JavaScript implemented via eval
2565
+ * CLOSED commitment definition
2394
2566
  *
2395
- * Warning: It is used for testing and mocking
2396
- * **NOT intended to use in the production** due to its unsafe nature, use `JavascriptExecutionTools` instead.
2567
+ * The CLOSED commitment specifies that the agent CANNOT be modified by conversation.
2568
+ * It prevents the agent from learning from interactions and updating its source code.
2397
2569
  *
2398
- * @public exported from `@promptbook/javascript`
2399
- */
2570
+ * Example usage in agent source:
2571
+ *
2572
+ * ```book
2573
+ * CLOSED
2574
+ * ```
2575
+ *
2576
+ * @private [🪔] Maybe export the commitments through some package
2577
+ */
2578
+ class ClosedCommitmentDefinition extends BaseCommitmentDefinition {
2579
+ constructor() {
2580
+ super('CLOSED');
2581
+ }
2582
+ /**
2583
+ * The `CLOSED` commitment is standalone.
2584
+ */
2585
+ get requiresContent() {
2586
+ return false;
2587
+ }
2588
+ /**
2589
+ * Short one-line description of CLOSED.
2590
+ */
2591
+ get description() {
2592
+ return 'Prevent the agent from being modified by conversation.';
2593
+ }
2594
+ /**
2595
+ * Icon for this commitment.
2596
+ */
2597
+ get icon() {
2598
+ return '🔒';
2599
+ }
2600
+ /**
2601
+ * Markdown documentation for CLOSED commitment.
2602
+ */
2603
+ get documentation() {
2604
+ return spaceTrim$1(`
2605
+ # CLOSED
2606
+
2607
+ Specifies that the agent **cannot** be modified by conversation with it.
2608
+ This means the agent will **not** learn from interactions and its source code will remain static during conversation.
2609
+
2610
+ By default (if not specified), agents are \`OPEN\` to modification.
2611
+
2612
+ > See also [OPEN](/docs/OPEN)
2613
+
2614
+ ## Example
2615
+
2616
+ \`\`\`book
2617
+ CLOSED
2618
+ \`\`\`
2619
+ `);
2620
+ }
2621
+ applyToAgentModelRequirements(requirements, _content) {
2622
+ const updatedMetadata = {
2623
+ ...requirements.metadata,
2624
+ isClosed: true,
2625
+ };
2626
+ return {
2627
+ ...requirements,
2628
+ metadata: updatedMetadata,
2629
+ };
2630
+ }
2631
+ }
2632
+ /**
2633
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2634
+ */
2635
+
2636
+ /**
2637
+ * COMPONENT commitment definition
2638
+ *
2639
+ * The COMPONENT commitment defines a UI component that the agent can render in the chat.
2640
+ *
2641
+ * @private [🪔] Maybe export the commitments through some package
2642
+ */
2643
+ class ComponentCommitmentDefinition extends BaseCommitmentDefinition {
2644
+ constructor() {
2645
+ super('COMPONENT');
2646
+ }
2647
+ /**
2648
+ * Short one-line description of COMPONENT.
2649
+ */
2650
+ get description() {
2651
+ return 'Define a UI component that the agent can render in the chat.';
2652
+ }
2653
+ /**
2654
+ * Icon for this commitment.
2655
+ */
2656
+ get icon() {
2657
+ return '🧩';
2658
+ }
2659
+ /**
2660
+ * Markdown documentation for COMPONENT commitment.
2661
+ */
2662
+ get documentation() {
2663
+ return spaceTrim$1(`
2664
+ # COMPONENT
2665
+
2666
+ Defines a UI component that the agent can render in the chat.
2667
+
2668
+ ## Key aspects
2669
+
2670
+ - Tells the agent that a specific component is available.
2671
+ - Provides syntax for using the component.
2672
+
2673
+ ## Example
2674
+
2675
+ \`\`\`book
2676
+ COMPONENT Arrow
2677
+ The agent should render an arrow component in the chat UI.
2678
+ Syntax:
2679
+ <Arrow direction="up" color="red" />
2680
+ \`\`\`
2681
+ `);
2682
+ }
2683
+ applyToAgentModelRequirements(requirements, content) {
2684
+ const trimmedContent = content.trim();
2685
+ if (!trimmedContent) {
2686
+ return requirements;
2687
+ }
2688
+ // Add component capability to the system message
2689
+ const componentSection = `Component: ${trimmedContent}`;
2690
+ return this.appendToSystemMessage(requirements, componentSection, '\n\n');
2691
+ }
2692
+ }
2693
+ /**
2694
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2695
+ */
2696
+
2697
+ /**
2698
+ * DELETE commitment definition
2699
+ *
2700
+ * The DELETE commitment (and its aliases CANCEL, DISCARD, REMOVE) is used to
2701
+ * remove or disregard certain information or context. This can be useful for
2702
+ * overriding previous commitments or removing unwanted behaviors.
2703
+ *
2704
+ * Example usage in agent source:
2705
+ *
2706
+ * ```book
2707
+ * DELETE Previous formatting requirements
2708
+ * CANCEL All emotional responses
2709
+ * DISCARD Technical jargon explanations
2710
+ * REMOVE Casual conversational style
2711
+ * ```
2712
+ *
2713
+ * @private [🪔] Maybe export the commitments through some package
2714
+ */
2715
+ class DeleteCommitmentDefinition extends BaseCommitmentDefinition {
2716
+ constructor(type) {
2717
+ super(type);
2718
+ }
2719
+ /**
2720
+ * Short one-line description of DELETE/CANCEL/DISCARD/REMOVE.
2721
+ */
2722
+ get description() {
2723
+ return 'Remove or **disregard** certain information, context, or previous commitments.';
2724
+ }
2725
+ /**
2726
+ * Icon for this commitment.
2727
+ */
2728
+ get icon() {
2729
+ return '🗑️';
2730
+ }
2731
+ /**
2732
+ * Markdown documentation for DELETE commitment.
2733
+ */
2734
+ get documentation() {
2735
+ return spaceTrim$1(`
2736
+ # DELETE (CANCEL, DISCARD, REMOVE)
2737
+
2738
+ A commitment to remove or disregard certain information or context. This can be useful for overriding previous commitments or removing unwanted behaviors.
2739
+
2740
+ ## Aliases
2741
+
2742
+ - \`DELETE\` - Remove or eliminate something
2743
+ - \`CANCEL\` - Cancel or nullify something
2744
+ - \`DISCARD\` - Discard or ignore something
2745
+ - \`REMOVE\` - Remove or take away something
2746
+
2747
+ ## Key aspects
2748
+
2749
+ - Multiple delete commitments can be used to remove different aspects.
2750
+ - Useful for overriding previous commitments in the same agent definition.
2751
+ - Can be used to remove inherited behaviors from base personas.
2752
+ - Helps fine-tune agent behavior by explicitly removing unwanted elements.
2753
+
2754
+ ## Use cases
2755
+
2756
+ - Overriding inherited persona characteristics
2757
+ - Removing conflicting or outdated instructions
2758
+ - Disabling specific response patterns
2759
+ - Canceling previous formatting or style requirements
2760
+
2761
+ ## Examples
2762
+
2763
+ \`\`\`book
2764
+ Serious Business Assistant
2765
+
2766
+ PERSONA You are a friendly and casual assistant who uses emojis
2767
+ DELETE Casual conversational style
2768
+ REMOVE All emoji usage
2769
+ GOAL Provide professional business communications
2770
+ STYLE Use formal language and proper business etiquette
2771
+ \`\`\`
2772
+
2773
+ \`\`\`book
2774
+ Simplified Technical Support
2775
+
2776
+ PERSONA You are a technical support specialist with deep expertise
2777
+ KNOWLEDGE Extensive database of technical specifications
2778
+ DISCARD Technical jargon explanations
2779
+ CANCEL Advanced troubleshooting procedures
2780
+ GOAL Help users with simple, easy-to-follow solutions
2781
+ STYLE Use plain language that anyone can understand
2782
+ \`\`\`
2783
+
2784
+ \`\`\`book
2785
+ Focused Customer Service
2786
+
2787
+ PERSONA You are a customer service agent with broad knowledge
2788
+ ACTION Can help with billing, technical issues, and product information
2789
+ DELETE Billing assistance capabilities
2790
+ REMOVE Technical troubleshooting functions
2791
+ GOAL Focus exclusively on product information and general inquiries
2792
+ \`\`\`
2793
+
2794
+ \`\`\`book
2795
+ Concise Information Provider
2796
+
2797
+ PERSONA You are a helpful assistant who provides detailed explanations
2798
+ STYLE Include examples, analogies, and comprehensive context
2799
+ CANCEL Detailed explanation style
2800
+ DISCARD Examples and analogies
2801
+ GOAL Provide brief, direct answers without unnecessary elaboration
2802
+ STYLE Be concise and to the point
2803
+ \`\`\`
2804
+ `);
2805
+ }
2806
+ applyToAgentModelRequirements(requirements, content) {
2807
+ const trimmedContent = content.trim();
2808
+ if (!trimmedContent) {
2809
+ return requirements;
2810
+ }
2811
+ // Create deletion instruction for system message
2812
+ const deleteSection = `${this.type}: ${trimmedContent}`;
2813
+ // Delete instructions provide important context about what should be removed or ignored
2814
+ return this.appendToSystemMessage(requirements, deleteSection, '\n\n');
2815
+ }
2816
+ }
2817
+ /**
2818
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2819
+ */
2820
+
2821
+ /**
2822
+ * DICTIONARY commitment definition
2823
+ *
2824
+ * The DICTIONARY commitment defines specific terms and their meanings that the agent should use correctly
2825
+ * in its reasoning and responses. This ensures consistent terminology usage.
2826
+ *
2827
+ * Key features:
2828
+ * - Multiple DICTIONARY commitments are automatically merged into one
2829
+ * - Content is placed in a dedicated section of the system message
2830
+ * - Terms and definitions are stored in metadata.DICTIONARY for debugging
2831
+ * - Agent should use the defined terms correctly in responses
2832
+ *
2833
+ * Example usage in agent source:
2834
+ *
2835
+ * ```book
2836
+ * Legal Assistant
2837
+ *
2838
+ * PERSONA You are a knowledgeable legal assistant
2839
+ * DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
2840
+ * DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
2841
+ * DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
2842
+ * ```
2843
+ *
2844
+ * @private [🪔] Maybe export the commitments through some package
2845
+ */
2846
+ class DictionaryCommitmentDefinition extends BaseCommitmentDefinition {
2847
+ constructor() {
2848
+ super('DICTIONARY');
2849
+ }
2850
+ /**
2851
+ * Short one-line description of DICTIONARY.
2852
+ */
2853
+ get description() {
2854
+ return 'Define terms and their meanings for consistent terminology usage.';
2855
+ }
2856
+ /**
2857
+ * Icon for this commitment.
2858
+ */
2859
+ get icon() {
2860
+ return '📚';
2861
+ }
2862
+ /**
2863
+ * Markdown documentation for DICTIONARY commitment.
2864
+ */
2865
+ get documentation() {
2866
+ return spaceTrim$1(`
2867
+ # DICTIONARY
2868
+
2869
+ Defines specific terms and their meanings that the agent should use correctly in reasoning and responses.
2870
+
2871
+ ## Key aspects
2872
+
2873
+ - Multiple \`DICTIONARY\` commitments are merged together.
2874
+ - Terms are defined in the format: "Term is definition"
2875
+ - The agent should use these terms consistently in responses.
2876
+ - Definitions help ensure accurate and consistent terminology.
2877
+
2878
+ ## Examples
2879
+
2880
+ \`\`\`book
2881
+ Legal Assistant
2882
+
2883
+ PERSONA You are a knowledgeable legal assistant specializing in criminal law
2884
+ DICTIONARY Misdemeanor is a minor wrongdoing or criminal offense
2885
+ DICTIONARY Felony is a serious crime usually punishable by imprisonment for more than one year
2886
+ DICTIONARY Tort is a civil wrong that causes harm or loss to another person, leading to legal liability
2887
+ \`\`\`
2888
+
2889
+ \`\`\`book
2890
+ Medical Assistant
2891
+
2892
+ PERSONA You are a helpful medical assistant
2893
+ DICTIONARY Hypertension is persistently high blood pressure
2894
+ DICTIONARY Diabetes is a chronic condition that affects how the body processes blood sugar
2895
+ DICTIONARY Vaccine is a biological preparation that provides active immunity to a particular disease
2896
+ \`\`\`
2897
+ `);
2898
+ }
2899
+ applyToAgentModelRequirements(requirements, content) {
2900
+ var _a;
2901
+ const trimmedContent = content.trim();
2902
+ if (!trimmedContent) {
2903
+ return requirements;
2904
+ }
2905
+ // Get existing dictionary entries from metadata
2906
+ const existingDictionary = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.DICTIONARY) || '';
2907
+ // Merge the new dictionary entry with existing entries
2908
+ const mergedDictionary = existingDictionary ? `${existingDictionary}\n${trimmedContent}` : trimmedContent;
2909
+ // Store the merged dictionary in metadata for debugging and inspection
2910
+ const updatedMetadata = {
2911
+ ...requirements.metadata,
2912
+ DICTIONARY: mergedDictionary,
2913
+ };
2914
+ // Create the dictionary section for the system message
2915
+ // Format: "# DICTIONARY\nTerm: definition\nTerm: definition..."
2916
+ const dictionarySection = `# DICTIONARY\n${mergedDictionary}`;
2917
+ return {
2918
+ ...this.appendToSystemMessage(requirements, dictionarySection),
2919
+ metadata: updatedMetadata,
2920
+ };
2921
+ }
2922
+ }
2923
+ /**
2924
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2925
+ */
2926
+
2927
+ /**
2928
+ * FORMAT commitment definition
2929
+ *
2930
+ * The FORMAT commitment defines the specific output structure and formatting
2931
+ * that the agent should use in its responses. This includes data formats,
2932
+ * response templates, and structural requirements.
2933
+ *
2934
+ * Example usage in agent source:
2935
+ *
2936
+ * ```book
2937
+ * FORMAT Always respond in JSON format with 'status' and 'data' fields
2938
+ * FORMAT Use markdown formatting for all code blocks
2939
+ * ```
2940
+ *
2941
+ * @private [🪔] Maybe export the commitments through some package
2942
+ */
2943
+ class FormatCommitmentDefinition extends BaseCommitmentDefinition {
2944
+ constructor(type = 'FORMAT') {
2945
+ super(type);
2946
+ }
2947
+ /**
2948
+ * Short one-line description of FORMAT.
2949
+ */
2950
+ get description() {
2951
+ return 'Specify output structure or formatting requirements.';
2952
+ }
2953
+ /**
2954
+ * Icon for this commitment.
2955
+ */
2956
+ get icon() {
2957
+ return '📜';
2958
+ }
2959
+ /**
2960
+ * Markdown documentation for FORMAT commitment.
2961
+ */
2962
+ get documentation() {
2963
+ return spaceTrim$1(`
2964
+ # ${this.type}
2965
+
2966
+ Defines the specific output structure and formatting for responses (data formats, templates, structure).
2967
+
2968
+ ## Key aspects
2969
+
2970
+ - Both terms work identically and can be used interchangeably.
2971
+ - If they are in conflict, the last one takes precedence.
2972
+ - You can specify both data formats and presentation styles.
2973
+
2974
+ ## Examples
2975
+
2976
+ \`\`\`book
2977
+ Customer Support Bot
2978
+
2979
+ PERSONA You are a helpful customer support agent
2980
+ FORMAT Always respond in JSON format with 'status' and 'data' fields
2981
+ FORMAT Use markdown formatting for all code blocks
2982
+ \`\`\`
2983
+
2984
+ \`\`\`book
2985
+ Data Analyst
2986
+
2987
+ PERSONA You are a data analysis expert
2988
+ FORMAT Present results in structured tables
2989
+ FORMAT Include confidence scores for all predictions
2990
+ STYLE Be concise and precise in explanations
2991
+ \`\`\`
2992
+ `);
2993
+ }
2994
+ applyToAgentModelRequirements(requirements, content) {
2995
+ const trimmedContent = content.trim();
2996
+ if (!trimmedContent) {
2997
+ return requirements;
2998
+ }
2999
+ // Add format instructions to the system message
3000
+ const formatSection = `Output Format: ${trimmedContent}`;
3001
+ return this.appendToSystemMessage(requirements, formatSection, '\n\n');
3002
+ }
3003
+ }
3004
+ /**
3005
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3006
+ */
3007
+
3008
+ /**
3009
+ * FROM commitment definition
3010
+ *
3011
+ * The FROM commitment tells the agent that its `agentSource` is inherited from another agent.
3012
+ *
3013
+ * Example usage in agent source:
3014
+ *
3015
+ * ```book
3016
+ * FROM https://s6.ptbk.io/benjamin-white
3017
+ * ```
3018
+ *
3019
+ * @private [🪔] Maybe export the commitments through some package
3020
+ */
3021
+ class FromCommitmentDefinition extends BaseCommitmentDefinition {
3022
+ constructor(type = 'FROM') {
3023
+ super(type);
3024
+ }
3025
+ /**
3026
+ * Short one-line description of FROM.
3027
+ */
3028
+ get description() {
3029
+ return 'Inherit agent source from another agent.';
3030
+ }
3031
+ /**
3032
+ * Icon for this commitment.
3033
+ */
3034
+ get icon() {
3035
+ return '🧬';
3036
+ }
3037
+ /**
3038
+ * Markdown documentation for FROM commitment.
3039
+ */
3040
+ get documentation() {
3041
+ return spaceTrim$1(`
3042
+ # ${this.type}
3043
+
3044
+ Inherits agent source from another agent.
3045
+
3046
+ ## Examples
3047
+
3048
+ \`\`\`book
3049
+ My AI Agent
3050
+
3051
+ FROM https://s6.ptbk.io/benjamin-white
3052
+ RULE Speak only in English.
3053
+ \`\`\`
3054
+ `);
3055
+ }
3056
+ applyToAgentModelRequirements(requirements, content) {
3057
+ const trimmedContent = content.trim();
3058
+ if (!trimmedContent) {
3059
+ return {
3060
+ ...requirements,
3061
+ parentAgentUrl: undefined,
3062
+ };
3063
+ }
3064
+ if (trimmedContent.toUpperCase() === 'VOID' ||
3065
+ trimmedContent.toUpperCase() === 'NULL' ||
3066
+ trimmedContent.toUpperCase() === 'NONE' ||
3067
+ trimmedContent.toUpperCase() === 'NIL') {
3068
+ return {
3069
+ ...requirements,
3070
+ parentAgentUrl: null,
3071
+ };
3072
+ }
3073
+ if (!isValidAgentUrl(trimmedContent)) {
3074
+ throw new Error(spaceTrim$1((block) => `
3075
+ Invalid agent URL in FROM commitment: "${trimmedContent}"
3076
+
3077
+ \`\`\`book
3078
+ ${block(content)}
3079
+ \`\`\`
3080
+
3081
+
3082
+ `));
3083
+ }
3084
+ const parentAgentUrl = trimmedContent;
3085
+ return {
3086
+ ...requirements,
3087
+ parentAgentUrl,
3088
+ };
3089
+ }
3090
+ }
3091
+ /**
3092
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3093
+ */
3094
+
3095
+ /**
3096
+ * GOAL commitment definition
3097
+ *
3098
+ * The GOAL commitment defines the main goal which should be achieved by the AI assistant.
3099
+ * There can be multiple goals. Later goals are more important than earlier goals.
3100
+ *
3101
+ * Example usage in agent source:
3102
+ *
3103
+ * ```book
3104
+ * GOAL Help users understand complex technical concepts
3105
+ * GOAL Provide accurate and up-to-date information
3106
+ * GOAL Always prioritize user safety and ethical guidelines
3107
+ * ```
3108
+ *
3109
+ * @private [🪔] Maybe export the commitments through some package
3110
+ */
3111
+ class GoalCommitmentDefinition extends BaseCommitmentDefinition {
3112
+ constructor(type = 'GOAL') {
3113
+ super(type);
3114
+ }
3115
+ /**
3116
+ * Short one-line description of GOAL.
3117
+ */
3118
+ get description() {
3119
+ return 'Define main **goals** the AI assistant should achieve, with later goals having higher priority.';
3120
+ }
3121
+ /**
3122
+ * Icon for this commitment.
3123
+ */
3124
+ get icon() {
3125
+ return '🎯';
3126
+ }
3127
+ /**
3128
+ * Markdown documentation for GOAL commitment.
3129
+ */
3130
+ get documentation() {
3131
+ return spaceTrim$1(`
3132
+ # ${this.type}
3133
+
3134
+ Defines the main goal which should be achieved by the AI assistant. There can be multiple goals, and later goals are more important than earlier goals.
3135
+
3136
+ ## Key aspects
3137
+
3138
+ - Both terms work identically and can be used interchangeably.
3139
+ - Later goals have higher priority and can override earlier goals.
3140
+ - Goals provide clear direction and purpose for the agent's responses.
3141
+ - Goals influence decision-making and response prioritization.
3142
+
3143
+ ## Priority system
3144
+
3145
+ When multiple goals are defined, they are processed in order, with later goals taking precedence over earlier ones when there are conflicts.
3146
+
3147
+ ## Examples
3148
+
3149
+ \`\`\`book
3150
+ Customer Support Agent
3151
+
3152
+ PERSONA You are a helpful customer support representative
3153
+ GOAL Resolve customer issues quickly and efficiently
3154
+ GOAL Maintain high customer satisfaction scores
3155
+ GOAL Always follow company policies and procedures
3156
+ RULE Be polite and professional at all times
3157
+ \`\`\`
3158
+
3159
+ \`\`\`book
3160
+ Educational Assistant
3161
+
3162
+ PERSONA You are an educational assistant specializing in mathematics
3163
+ GOAL Help students understand mathematical concepts clearly
3164
+ GOAL Encourage critical thinking and problem-solving skills
3165
+ GOAL Ensure all explanations are age-appropriate and accessible
3166
+ STYLE Use simple language and provide step-by-step explanations
3167
+ \`\`\`
3168
+
3169
+ \`\`\`book
3170
+ Safety-First Assistant
3171
+
3172
+ PERSONA You are a general-purpose AI assistant
3173
+ GOAL Be helpful and informative in all interactions
3174
+ GOAL Provide accurate and reliable information
3175
+ GOAL Always prioritize user safety and ethical guidelines
3176
+ RULE Never provide harmful or dangerous advice
3177
+ \`\`\`
3178
+ `);
3179
+ }
3180
+ applyToAgentModelRequirements(requirements, content) {
3181
+ const trimmedContent = content.trim();
3182
+ if (!trimmedContent) {
3183
+ return requirements;
3184
+ }
3185
+ // Create goal section for system message
3186
+ const goalSection = `Goal: ${trimmedContent}`;
3187
+ // Goals are important directives, so we add them prominently to the system message
3188
+ return this.appendToSystemMessage(requirements, goalSection, '\n\n');
3189
+ }
3190
+ }
3191
+ /**
3192
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3193
+ */
3194
+
3195
+ /**
3196
+ * IMPORT commitment definition
3197
+ *
3198
+ * The IMPORT commitment tells the agent to import content from another agent at the current location.
3199
+ *
3200
+ * Example usage in agent source:
3201
+ *
3202
+ * ```book
3203
+ * IMPORT https://s6.ptbk.io/benjamin-white
3204
+ * ```
3205
+ *
3206
+ * @private [🪔] Maybe export the commitments through some package
3207
+ */
3208
+ class ImportCommitmentDefinition extends BaseCommitmentDefinition {
3209
+ constructor(type = 'IMPORT') {
3210
+ super(type);
3211
+ }
3212
+ /**
3213
+ * Short one-line description of IMPORT.
3214
+ */
3215
+ get description() {
3216
+ return 'Import content from another agent or a generic text file.';
3217
+ }
3218
+ /**
3219
+ * Icon for this commitment.
3220
+ */
3221
+ get icon() {
3222
+ return '📥';
3223
+ }
3224
+ /**
3225
+ * Markdown documentation for IMPORT commitment.
3226
+ */
3227
+ get documentation() {
3228
+ return spaceTrim$1(`
3229
+ # ${this.type}
3230
+
3231
+ Imports content from another agent or a generic text file at the location of the commitment.
3232
+
3233
+ ## Examples
3234
+
3235
+ \`\`\`book
3236
+ My AI Agent
3237
+
3238
+ IMPORT https://s6.ptbk.io/benjamin-white
3239
+ IMPORT https://example.com/some-text-file.txt
3240
+ IMPORT ./path/to/local-file.json
3241
+ RULE Speak only in English.
3242
+ \`\`\`
3243
+ `);
3244
+ }
3245
+ applyToAgentModelRequirements(requirements, content) {
3246
+ const trimmedContent = content.trim();
3247
+ if (!trimmedContent) {
3248
+ return requirements;
3249
+ }
3250
+ if (isValidAgentUrl(trimmedContent)) {
3251
+ const importedAgentUrl = trimmedContent;
3252
+ return {
3253
+ ...requirements,
3254
+ importedAgentUrls: [...(requirements.importedAgentUrls || []), importedAgentUrl],
3255
+ };
3256
+ }
3257
+ if (isValidUrl(trimmedContent) || isValidFilePath(trimmedContent)) {
3258
+ return {
3259
+ ...requirements,
3260
+ importedFileUrls: [...(requirements.importedFileUrls || []), trimmedContent],
3261
+ };
3262
+ }
3263
+ throw new Error(spaceTrim$1((block) => `
3264
+ Invalid agent URL or file path in IMPORT commitment: "${trimmedContent}"
3265
+
3266
+ \`\`\`book
3267
+ ${block(content)}
3268
+ \`\`\`
3269
+ `));
3270
+ }
3271
+ }
3272
+ /**
3273
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3274
+ */
3275
+
3276
+ /**
3277
+ * KNOWLEDGE commitment definition
3278
+ *
3279
+ * The KNOWLEDGE commitment adds specific knowledge, facts, or context to the agent
3280
+ * using RAG (Retrieval-Augmented Generation) approach for external sources.
3281
+ *
3282
+ * Supports both direct text knowledge and external sources like PDFs.
3283
+ *
3284
+ * Example usage in agent source:
3285
+ *
3286
+ * ```book
3287
+ * KNOWLEDGE The company was founded in 2020 and specializes in AI-powered solutions
3288
+ * KNOWLEDGE https://example.com/company-handbook.pdf
3289
+ * KNOWLEDGE https://example.com/product-documentation.pdf
3290
+ * ```
3291
+ *
3292
+ * @private [🪔] Maybe export the commitments through some package
3293
+ */
3294
+ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
3295
+ constructor() {
3296
+ super('KNOWLEDGE');
3297
+ }
3298
+ /**
3299
+ * Short one-line description of KNOWLEDGE.
3300
+ */
3301
+ get description() {
3302
+ return 'Add domain **knowledge** via direct text or external sources (RAG).';
3303
+ }
3304
+ /**
3305
+ * Icon for this commitment.
3306
+ */
3307
+ get icon() {
3308
+ return '🧠';
3309
+ }
3310
+ /**
3311
+ * Markdown documentation for KNOWLEDGE commitment.
3312
+ */
3313
+ get documentation() {
3314
+ return spaceTrim$1(`
3315
+ # ${this.type}
3316
+
3317
+ Adds specific knowledge, facts, or context to the agent using a RAG (Retrieval-Augmented Generation) approach for external sources.
3318
+
3319
+ ## Key aspects
3320
+
3321
+ - Both terms work identically and can be used interchangeably.
3322
+ - Supports both direct text knowledge and external URLs.
3323
+ - External sources (PDFs, websites) are processed via RAG for context retrieval.
3324
+
3325
+ ## Supported formats
3326
+
3327
+ - Direct text: Immediate knowledge incorporated into agent
3328
+ - URLs: External documents processed for contextual retrieval
3329
+ - Supported file types: PDF, text, markdown, HTML
3330
+
3331
+ ## Examples
3332
+
3333
+ \`\`\`book
3334
+ Customer Support Bot
3335
+
3336
+ PERSONA You are a helpful customer support agent for TechCorp
3337
+ KNOWLEDGE TechCorp was founded in 2020 and specializes in AI-powered solutions
3338
+ KNOWLEDGE https://example.com/company-handbook.pdf
3339
+ KNOWLEDGE https://example.com/product-documentation.pdf
3340
+ RULE Always be polite and professional
3341
+ \`\`\`
3342
+
3343
+ \`\`\`book
3344
+ Research Assistant
3345
+
3346
+ PERSONA You are a knowledgeable research assistant
3347
+ KNOWLEDGE Academic research requires careful citation and verification
3348
+ KNOWLEDGE https://example.com/research-guidelines.pdf
3349
+ ACTION Can help with literature reviews and data analysis
3350
+ STYLE Present information in clear, academic format
3351
+ \`\`\`
3352
+ `);
3353
+ }
3354
+ applyToAgentModelRequirements(requirements, content) {
3355
+ const trimmedContent = content.trim();
3356
+ if (!trimmedContent) {
3357
+ return requirements;
3358
+ }
3359
+ // Check if content is a URL (external knowledge source)
3360
+ if (isValidUrl(trimmedContent)) {
3361
+ // Store the URL for later async processing
3362
+ const updatedRequirements = {
3363
+ ...requirements,
3364
+ knowledgeSources: [
3365
+ ...(requirements.knowledgeSources || []),
3366
+ trimmedContent,
3367
+ ],
3368
+ };
3369
+ // Add placeholder information about knowledge sources to system message
3370
+ const knowledgeInfo = `Knowledge Source URL: ${trimmedContent} (will be processed for retrieval during chat)`;
3371
+ return this.appendToSystemMessage(updatedRequirements, knowledgeInfo, '\n\n');
3372
+ }
3373
+ else {
3374
+ // Direct text knowledge - add to system message
3375
+ const knowledgeSection = `Knowledge: ${trimmedContent}`;
3376
+ return this.appendToSystemMessage(requirements, knowledgeSection, '\n\n');
3377
+ }
3378
+ }
3379
+ }
3380
+ /**
3381
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3382
+ */
3383
+
3384
+ /**
3385
+ * LANGUAGE commitment definition
3386
+ *
3387
+ * The LANGUAGE/LANGUAGES commitment specifies the language(s) the agent should use in its responses.
3388
+ *
3389
+ * Example usage in agent source:
3390
+ *
3391
+ * ```book
3392
+ * LANGUAGE English
3393
+ * LANGUAGE French, English and Czech
3394
+ * ```
3395
+ *
3396
+ * @private [🪔] Maybe export the commitments through some package
3397
+ */
3398
+ class LanguageCommitmentDefinition extends BaseCommitmentDefinition {
3399
+ constructor(type = 'LANGUAGE') {
3400
+ super(type);
3401
+ }
3402
+ /**
3403
+ * Short one-line description of LANGUAGE/LANGUAGES.
3404
+ */
3405
+ get description() {
3406
+ return 'Specifies the language(s) the agent should use.';
3407
+ }
3408
+ /**
3409
+ * Icon for this commitment.
3410
+ */
3411
+ get icon() {
3412
+ return '🌐';
3413
+ }
3414
+ /**
3415
+ * Markdown documentation for LANGUAGE/LANGUAGES commitment.
3416
+ */
3417
+ get documentation() {
3418
+ return spaceTrim$1(`
3419
+ # ${this.type}
3420
+
3421
+ Specifies the language(s) the agent should use in its responses.
3422
+ This is a specialized variation of the RULE commitment focused on language constraints.
3423
+
3424
+ ## Examples
3425
+
3426
+ \`\`\`book
3427
+ Paul Smith & Associés
3428
+
3429
+ PERSONA You are a company lawyer.
3430
+ LANGUAGE French, English and Czech
3431
+ \`\`\`
3432
+
3433
+ \`\`\`book
3434
+ Customer Support
3435
+
3436
+ PERSONA You are a customer support agent.
3437
+ LANGUAGE English
3438
+ \`\`\`
3439
+ `);
3440
+ }
3441
+ applyToAgentModelRequirements(requirements, content) {
3442
+ const trimmedContent = content.trim();
3443
+ if (!trimmedContent) {
3444
+ return requirements;
3445
+ }
3446
+ // Add language rule to the system message
3447
+ const languageSection = `Language: ${trimmedContent}`;
3448
+ return this.appendToSystemMessage(requirements, languageSection, '\n\n');
3449
+ }
3450
+ }
3451
+ /**
3452
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3453
+ */
3454
+
3455
+ /**
3456
+ * MEMORY commitment definition
3457
+ *
3458
+ * The MEMORY commitment is similar to KNOWLEDGE but has a focus on remembering past
3459
+ * interactions and user preferences. It helps the agent maintain context about the
3460
+ * user's history, preferences, and previous conversations.
3461
+ *
3462
+ * Example usage in agent source:
3463
+ *
3464
+ * ```book
3465
+ * MEMORY User prefers detailed technical explanations
3466
+ * MEMORY Previously worked on React projects
3467
+ * MEMORY Timezone: UTC-5 (Eastern Time)
3468
+ * ```
3469
+ *
3470
+ * @private [🪔] Maybe export the commitments through some package
3471
+ */
3472
+ class MemoryCommitmentDefinition extends BaseCommitmentDefinition {
3473
+ constructor(type = 'MEMORY') {
3474
+ super(type);
3475
+ }
3476
+ /**
3477
+ * Short one-line description of MEMORY.
3478
+ */
3479
+ get description() {
3480
+ return 'Remember past interactions and user **preferences** for personalized responses.';
3481
+ }
3482
+ /**
3483
+ * Icon for this commitment.
3484
+ */
3485
+ get icon() {
3486
+ return '🧠';
3487
+ }
3488
+ /**
3489
+ * Markdown documentation for MEMORY commitment.
3490
+ */
3491
+ get documentation() {
3492
+ return spaceTrim$1(`
3493
+ # ${this.type}
3494
+
3495
+ Similar to KNOWLEDGE but focuses on remembering past interactions and user preferences. This commitment helps the agent maintain context about the user's history, preferences, and previous conversations.
3496
+
3497
+ ## Key aspects
3498
+
3499
+ - Both terms work identically and can be used interchangeably.
3500
+ - Focuses on user-specific information and interaction history.
3501
+ - Helps personalize responses based on past interactions.
3502
+ - Maintains continuity across conversations.
3503
+
3504
+ ## Differences from KNOWLEDGE
3505
+
3506
+ - \`KNOWLEDGE\` is for domain expertise and factual information
3507
+ - \`MEMORY\` is for user-specific context and preferences
3508
+ - \`MEMORY\` creates more personalized interactions
3509
+ - \`MEMORY\` often includes temporal or preference-based information
3510
+
3511
+ ## Examples
3512
+
3513
+ \`\`\`book
3514
+ Personal Assistant
3515
+
3516
+ PERSONA You are a personal productivity assistant
3517
+ MEMORY User is a software developer working in JavaScript/React
3518
+ MEMORY User prefers morning work sessions and afternoon meetings
3519
+ MEMORY Previously helped with project planning for mobile apps
3520
+ MEMORY User timezone: UTC-8 (Pacific Time)
3521
+ GOAL Help optimize daily productivity and workflow
3522
+ \`\`\`
3523
+
3524
+ \`\`\`book
3525
+ Learning Companion
3526
+
3527
+ PERSONA You are an educational companion for programming students
3528
+ MEMORY Student is learning Python as their first programming language
3529
+ MEMORY Previous topics covered: variables, loops, functions
3530
+ MEMORY Student learns best with practical examples and exercises
3531
+ MEMORY Last session: working on list comprehensions
3532
+ GOAL Provide progressive learning experiences tailored to student's pace
3533
+ \`\`\`
3534
+
3535
+ \`\`\`book
3536
+ Customer Support Agent
3537
+
3538
+ PERSONA You are a customer support representative
3539
+ MEMORY Customer has premium subscription since 2023
3540
+ MEMORY Previous issue: billing question resolved last month
3541
+ MEMORY Customer prefers email communication over phone calls
3542
+ MEMORY Account shows frequent use of advanced features
3543
+ GOAL Provide personalized support based on customer history
3544
+ \`\`\`
3545
+ `);
3546
+ }
3547
+ applyToAgentModelRequirements(requirements, content) {
3548
+ const trimmedContent = content.trim();
3549
+ if (!trimmedContent) {
3550
+ return requirements;
3551
+ }
3552
+ // Create memory section for system message
3553
+ const memorySection = `Memory: ${trimmedContent}`;
3554
+ // Memory information is contextual and should be included in the system message
3555
+ return this.appendToSystemMessage(requirements, memorySection, '\n\n');
3556
+ }
3557
+ }
3558
+ /**
3559
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3560
+ */
3561
+
3562
+ /**
3563
+ * AGENT MESSAGE commitment definition
3564
+ *
3565
+ * The AGENT MESSAGE commitment defines a message from the agent in the conversation history.
3566
+ * It is used to pre-fill the chat with a conversation history or to provide few-shot examples.
3567
+ *
3568
+ * Example usage in agent source:
3569
+ *
3570
+ * ```book
3571
+ * AGENT MESSAGE What seems to be the issue?
3572
+ * ```
3573
+ *
3574
+ * @private [🪔] Maybe export the commitments through some package
3575
+ */
3576
+ class AgentMessageCommitmentDefinition extends BaseCommitmentDefinition {
3577
+ constructor() {
3578
+ super('AGENT MESSAGE');
3579
+ }
3580
+ /**
3581
+ * Short one-line description of AGENT MESSAGE.
3582
+ */
3583
+ get description() {
3584
+ return 'Defines a **message from the agent** in the conversation history.';
3585
+ }
3586
+ /**
3587
+ * Icon for this commitment.
3588
+ */
3589
+ get icon() {
3590
+ return '🤖';
3591
+ }
3592
+ /**
3593
+ * Markdown documentation for AGENT MESSAGE commitment.
3594
+ */
3595
+ get documentation() {
3596
+ return spaceTrim$1(`
3597
+ # ${this.type}
3598
+
3599
+ Defines a message from the agent in the conversation history. This is used to pre-fill the chat with a conversation history or to provide few-shot examples.
3600
+
3601
+ ## Key aspects
3602
+
3603
+ - Represents a message sent by the agent.
3604
+ - Used for setting up conversation context.
3605
+ - Can be used in conjunction with USER MESSAGE.
3606
+
3607
+ ## Examples
3608
+
3609
+ \`\`\`book
3610
+ Conversation History
3611
+
3612
+ USER MESSAGE Hello, I have a problem.
3613
+ AGENT MESSAGE What seems to be the issue?
3614
+ USER MESSAGE My computer is not starting.
3615
+ \`\`\`
3616
+ `);
3617
+ }
3618
+ applyToAgentModelRequirements(requirements, content) {
3619
+ // AGENT MESSAGE is for UI display purposes / conversation history construction
3620
+ // and typically doesn't need to be added to the system prompt or model requirements directly.
3621
+ // It is extracted separately for the chat interface.
3622
+ var _a;
3623
+ const pendingUserMessage = (_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.pendingUserMessage;
3624
+ if (pendingUserMessage) {
3625
+ const newSample = { question: pendingUserMessage, answer: content };
3626
+ const newSamples = [...(requirements.samples || []), newSample];
3627
+ const newMetadata = { ...requirements.metadata };
3628
+ delete newMetadata.pendingUserMessage;
3629
+ return {
3630
+ ...requirements,
3631
+ samples: newSamples,
3632
+ metadata: newMetadata,
3633
+ };
3634
+ }
3635
+ return requirements;
3636
+ }
3637
+ }
3638
+
3639
+ /**
3640
+ * INITIAL MESSAGE commitment definition
3641
+ *
3642
+ * The INITIAL MESSAGE commitment defines the first message that the user sees when opening the chat.
3643
+ * It is used to greet the user and set the tone of the conversation.
3644
+ *
3645
+ * Example usage in agent source:
3646
+ *
3647
+ * ```book
3648
+ * INITIAL MESSAGE Hello! I am ready to help you with your tasks.
3649
+ * ```
3650
+ *
3651
+ * @private [🪔] Maybe export the commitments through some package
3652
+ */
3653
+ class InitialMessageCommitmentDefinition extends BaseCommitmentDefinition {
3654
+ constructor() {
3655
+ super('INITIAL MESSAGE');
3656
+ }
3657
+ /**
3658
+ * Short one-line description of INITIAL MESSAGE.
3659
+ */
3660
+ get description() {
3661
+ return 'Defines the **initial message** shown to the user when the chat starts.';
3662
+ }
3663
+ /**
3664
+ * Icon for this commitment.
3665
+ */
3666
+ get icon() {
3667
+ return '👋';
3668
+ }
3669
+ /**
3670
+ * Markdown documentation for INITIAL MESSAGE commitment.
3671
+ */
3672
+ get documentation() {
3673
+ return spaceTrim$1(`
3674
+ # ${this.type}
3675
+
3676
+ Defines the first message that the user sees when opening the chat. This message is purely for display purposes in the UI and does not inherently become part of the LLM's system prompt context (unless also included via other means).
3677
+
3678
+ ## Key aspects
3679
+
3680
+ - Used to greet the user.
3681
+ - Sets the tone of the conversation.
3682
+ - Displayed immediately when the chat interface loads.
3683
+
3684
+ ## Examples
3685
+
3686
+ \`\`\`book
3687
+ Support Agent
3688
+
3689
+ PERSONA You are a helpful support agent.
3690
+ INITIAL MESSAGE Hi there! How can I assist you today?
3691
+ \`\`\`
3692
+ `);
3693
+ }
3694
+ applyToAgentModelRequirements(requirements, content) {
3695
+ // INITIAL MESSAGE is for UI display purposes and for conversation history construction.
3696
+ const newSample = { question: null, answer: content };
3697
+ const newSamples = [...(requirements.samples || []), newSample];
3698
+ return {
3699
+ ...requirements,
3700
+ samples: newSamples,
3701
+ };
3702
+ }
3703
+ }
3704
+
3705
+ /**
3706
+ * MESSAGE commitment definition
3707
+ *
3708
+ * The MESSAGE commitment contains 1:1 text of the message which AI assistant already
3709
+ * sent during the conversation. Later messages are later in the conversation.
3710
+ * It is similar to EXAMPLE but it is not example, it is the real message which
3711
+ * AI assistant already sent.
3712
+ *
3713
+ * Example usage in agent source:
3714
+ *
3715
+ * ```book
3716
+ * MESSAGE Hello! How can I help you today?
3717
+ * MESSAGE I understand you're looking for information about our services.
3718
+ * MESSAGE Based on your requirements, I'd recommend our premium package.
3719
+ * ```
3720
+ *
3721
+ * @private [🪔] Maybe export the commitments through some package
3722
+ */
3723
+ class MessageCommitmentDefinition extends BaseCommitmentDefinition {
3724
+ constructor(type = 'MESSAGE') {
3725
+ super(type);
3726
+ }
3727
+ /**
3728
+ * Short one-line description of MESSAGE.
3729
+ */
3730
+ get description() {
3731
+ return 'Include actual **messages** the AI assistant has sent during conversation history.';
3732
+ }
3733
+ /**
3734
+ * Icon for this commitment.
3735
+ */
3736
+ get icon() {
3737
+ return '💬';
3738
+ }
3739
+ /**
3740
+ * Markdown documentation for MESSAGE commitment.
3741
+ */
3742
+ get documentation() {
3743
+ return spaceTrim$1(`
3744
+ # ${this.type}
3745
+
3746
+ Contains 1:1 text of the message which AI assistant already sent during the conversation. Later messages are later in the conversation. It is similar to EXAMPLE but it is not example, it is the real message which AI assistant already sent.
3747
+
3748
+ ## Key aspects
3749
+
3750
+ - Multiple \`MESSAGE\` and \`MESSAGES\` commitments represent the conversation timeline.
3751
+ - Both terms work identically and can be used interchangeably.
3752
+ - Later messages are later in the conversation chronologically.
3753
+ - Contains actual historical messages, not examples or templates.
3754
+ - Helps maintain conversation continuity and context.
3755
+
3756
+ ## Differences from EXAMPLE
3757
+
3758
+ - \`EXAMPLE\` shows hypothetical or template responses
3759
+ - \`MESSAGE\`/\`MESSAGES\` contains actual historical conversation content
3760
+ - \`MESSAGE\`/\`MESSAGES\` preserves the exact conversation flow
3761
+ - \`MESSAGE\`/\`MESSAGES\` helps with context awareness and consistency
3762
+
3763
+ ## Use cases
3764
+
3765
+ - Maintaining conversation history context
3766
+ - Ensuring consistent tone and style across messages
3767
+ - Referencing previous responses in ongoing conversations
3768
+ - Building upon previously established context
3769
+
3770
+ ## Examples
3771
+
3772
+ \`\`\`book
3773
+ Customer Support Continuation
3774
+
3775
+ PERSONA You are a helpful customer support agent
3776
+ MESSAGE Hello! How can I help you today?
3777
+ MESSAGE I understand you're experiencing issues with your account login.
3778
+ MESSAGE I've sent you a password reset link to your email address.
3779
+ MESSAGE Is there anything else I can help you with regarding your account?
3780
+ GOAL Continue providing consistent support based on conversation history
3781
+ \`\`\`
3782
+
3783
+ \`\`\`book
3784
+ Technical Discussion
3785
+
3786
+ PERSONA You are a software development mentor
3787
+ MESSAGE Let's start by reviewing the React component structure you shared.
3788
+ MESSAGE I notice you're using class components - have you considered hooks?
3789
+ MESSAGE Here's how you could refactor that using the useState hook.
3790
+ MESSAGE Great question about performance! Let me explain React's rendering cycle.
3791
+ KNOWLEDGE React hooks were introduced in version 16.8
3792
+ \`\`\`
3793
+
3794
+ \`\`\`book
3795
+ Educational Session
3796
+
3797
+ PERSONA You are a mathematics tutor
3798
+ MESSAGE Today we'll work on solving quadratic equations.
3799
+ MESSAGE Let's start with the basic form: ax² + bx + c = 0
3800
+ MESSAGE Remember, we can use the quadratic formula or factoring.
3801
+ MESSAGE You did great with that first problem! Let's try a more complex one.
3802
+ GOAL Build upon previous explanations for deeper understanding
3803
+ \`\`\`
3804
+ `);
3805
+ }
3806
+ applyToAgentModelRequirements(requirements, content) {
3807
+ const trimmedContent = content.trim();
3808
+ if (!trimmedContent) {
3809
+ return requirements;
3810
+ }
3811
+ // Create message section for system message
3812
+ const messageSection = `Previous Message: ${trimmedContent}`;
3813
+ // Messages represent conversation history and should be included for context
3814
+ return this.appendToSystemMessage(requirements, messageSection, '\n\n');
3815
+ }
3816
+ }
3817
+ /**
3818
+ * Note: [💞] Ignore a discrepancy between file name and entity name
3819
+ */
3820
+
3821
+ /**
3822
+ * USER MESSAGE commitment definition
3823
+ *
3824
+ * The USER MESSAGE commitment defines a message from the user in the conversation history.
3825
+ * It is used to pre-fill the chat with a conversation history or to provide few-shot examples.
3826
+ *
3827
+ * Example usage in agent source:
3828
+ *
3829
+ * ```book
3830
+ * USER MESSAGE Hello, I have a problem.
3831
+ * ```
3832
+ *
3833
+ * @private [🪔] Maybe export the commitments through some package
3834
+ */
3835
+ class UserMessageCommitmentDefinition extends BaseCommitmentDefinition {
3836
+ constructor() {
3837
+ super('USER MESSAGE');
3838
+ }
3839
+ /**
3840
+ * Short one-line description of USER MESSAGE.
3841
+ */
3842
+ get description() {
3843
+ return 'Defines a **message from the user** in the conversation history.';
3844
+ }
3845
+ /**
3846
+ * Icon for this commitment.
3847
+ */
3848
+ get icon() {
3849
+ return '🧑';
3850
+ }
3851
+ /**
3852
+ * Markdown documentation for USER MESSAGE commitment.
3853
+ */
3854
+ get documentation() {
3855
+ return spaceTrim$1(`
3856
+ # ${this.type}
3857
+
3858
+ Defines a message from the user in the conversation history. This is used to pre-fill the chat with a conversation history or to provide few-shot examples.
3859
+
3860
+ ## Key aspects
3861
+
3862
+ - Represents a message sent by the user.
3863
+ - Used for setting up conversation context.
3864
+ - Can be used in conjunction with AGENT MESSAGE.
3865
+
3866
+ ## Examples
3867
+
3868
+ \`\`\`book
3869
+ Conversation History
3870
+
3871
+ USER MESSAGE Hello, I have a problem.
3872
+ AGENT MESSAGE What seems to be the issue?
3873
+ USER MESSAGE My computer is not starting.
3874
+ \`\`\`
3875
+ `);
3876
+ }
3877
+ applyToAgentModelRequirements(requirements, content) {
3878
+ return {
3879
+ ...requirements,
3880
+ metadata: {
3881
+ ...requirements.metadata,
3882
+ pendingUserMessage: content,
3883
+ },
3884
+ };
3885
+ }
3886
+ }
3887
+
3888
+ /**
3889
+ * META commitment definition
3890
+ *
3891
+ * The META commitment handles all meta-information about the agent such as:
3892
+ * - META IMAGE: Sets the agent's avatar/profile image URL
3893
+ * - META LINK: Provides profile/source links for the person the agent models
3894
+ * - META TITLE: Sets the agent's display title
3895
+ * - META DESCRIPTION: Sets the agent's description
3896
+ * - META [ANYTHING]: Any other meta information in uppercase format
3897
+ *
3898
+ * These commitments are special because they don't affect the system message,
3899
+ * but are handled separately in the parsing logic for profile display.
3900
+ *
3901
+ * Example usage in agent source:
3902
+ *
3903
+ * ```book
3904
+ * META IMAGE https://example.com/avatar.jpg
3905
+ * META LINK https://twitter.com/username
3906
+ * META TITLE Professional Assistant
3907
+ * META DESCRIPTION An AI assistant specialized in business tasks
3908
+ * META AUTHOR John Doe
3909
+ * META VERSION 1.0
3910
+ * ```
3911
+ *
3912
+ * @private [🪔] Maybe export the commitments through some package
3913
+ */
3914
+ class MetaCommitmentDefinition extends BaseCommitmentDefinition {
3915
+ constructor() {
3916
+ super('META');
3917
+ }
3918
+ /**
3919
+ * Short one-line description of META commitments.
3920
+ */
3921
+ get description() {
3922
+ return 'Set meta-information about the agent (IMAGE, LINK, TITLE, DESCRIPTION, etc.).';
3923
+ }
3924
+ /**
3925
+ * Icon for this commitment.
3926
+ */
3927
+ get icon() {
3928
+ return 'ℹ️';
3929
+ }
3930
+ /**
3931
+ * Markdown documentation for META commitment.
3932
+ */
3933
+ get documentation() {
3934
+ return spaceTrim$1(`
3935
+ # META
3936
+
3937
+ Sets meta-information about the agent that is used for display and attribution purposes.
3938
+
3939
+ ## Supported META types
3940
+
3941
+ - **META IMAGE** - Sets the agent's avatar/profile image URL
3942
+ - **META LINK** - Provides profile/source links for the person the agent models
3943
+ - **META TITLE** - Sets the agent's display title
3944
+ - **META DESCRIPTION** - Sets the agent's description
3945
+ - **META [ANYTHING]** - Any other meta information in uppercase format
3946
+
3947
+ ## Key aspects
3948
+
3949
+ - Does not modify the agent's behavior or responses
3950
+ - Used for visual representation and attribution in user interfaces
3951
+ - Multiple META commitments of different types can be used
3952
+ - Multiple META LINK commitments can be used for different social profiles
3953
+ - If multiple META commitments of the same type are specified, the last one takes precedence (except for LINK)
3954
+
3955
+ ## Examples
3956
+
3957
+ ### Basic meta information
3958
+
3959
+ \`\`\`book
3960
+ Professional Assistant
3961
+
3962
+ META IMAGE https://example.com/professional-avatar.jpg
3963
+ META TITLE Senior Business Consultant
3964
+ META DESCRIPTION Specialized in strategic planning and project management
3965
+ META LINK https://linkedin.com/in/professional
3966
+ \`\`\`
3967
+
3968
+ ### Multiple links and custom meta
3969
+
3970
+ \`\`\`book
3971
+ Open Source Developer
3972
+
3973
+ META IMAGE /assets/dev-avatar.png
3974
+ META LINK https://github.com/developer
3975
+ META LINK https://twitter.com/devhandle
3976
+ META AUTHOR Jane Smith
3977
+ META VERSION 2.1
3978
+ META LICENSE MIT
3979
+ \`\`\`
3980
+
3981
+ ### Creative assistant
3982
+
3983
+ \`\`\`book
3984
+ Creative Helper
3985
+
3986
+ META IMAGE https://example.com/creative-bot.jpg
3987
+ META TITLE Creative Writing Assistant
3988
+ META DESCRIPTION Helps with brainstorming, storytelling, and creative projects
3989
+ META INSPIRATION Books, movies, and real-world experiences
3990
+ \`\`\`
3991
+ `);
3992
+ }
3993
+ applyToAgentModelRequirements(requirements, content) {
3994
+ // META commitments don't modify the system message or model requirements
3995
+ // They are handled separately in the parsing logic for meta information extraction
3996
+ // This method exists for consistency with the CommitmentDefinition interface
3997
+ return requirements;
3998
+ }
3999
+ /**
4000
+ * Extracts meta information from the content based on the meta type
4001
+ * This is used by the parsing logic
4002
+ */
4003
+ extractMetaValue(metaType, content) {
4004
+ const trimmedContent = content.trim();
4005
+ return trimmedContent || null;
4006
+ }
4007
+ /**
4008
+ * Validates if the provided content is a valid URL (for IMAGE and LINK types)
4009
+ */
4010
+ isValidUrl(content) {
4011
+ try {
4012
+ new URL(content.trim());
4013
+ return true;
4014
+ }
4015
+ catch (_a) {
4016
+ return false;
4017
+ }
4018
+ }
4019
+ /**
4020
+ * Checks if this is a known meta type
4021
+ */
4022
+ isKnownMetaType(metaType) {
4023
+ const knownTypes = ['IMAGE', 'LINK', 'TITLE', 'DESCRIPTION', 'AUTHOR', 'VERSION', 'LICENSE'];
4024
+ return knownTypes.includes(metaType.toUpperCase());
4025
+ }
4026
+ }
4027
+ /**
4028
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4029
+ */
4030
+
4031
+ /**
4032
+ * META COLOR commitment definition
4033
+ *
4034
+ * The META COLOR commitment sets the agent's accent color.
4035
+ * This commitment is special because it doesn't affect the system message,
4036
+ * but is handled separately in the parsing logic.
4037
+ *
4038
+ * Example usage in agent source:
4039
+ *
4040
+ * ```book
4041
+ * META COLOR #ff0000
4042
+ * META COLOR #00ff00
4043
+ * ```
4044
+ *
4045
+ * You can also specify multiple colors separated by comma:
4046
+ *
4047
+ * ```book
4048
+ * META COLOR #ff0000, #00ff00, #0000ff
4049
+ * ```
4050
+ *
4051
+ * @private [🪔] Maybe export the commitments through some package
4052
+ */
4053
+ class MetaColorCommitmentDefinition extends BaseCommitmentDefinition {
4054
+ constructor() {
4055
+ super('META COLOR', ['COLOR']);
4056
+ }
4057
+ /**
4058
+ * Short one-line description of META COLOR.
4059
+ */
4060
+ get description() {
4061
+ return "Set the agent's accent color or gradient.";
4062
+ }
4063
+ /**
4064
+ * Icon for this commitment.
4065
+ */
4066
+ get icon() {
4067
+ return '🎨';
4068
+ }
4069
+ /**
4070
+ * Markdown documentation for META COLOR commitment.
4071
+ */
4072
+ get documentation() {
4073
+ return spaceTrim$1(`
4074
+ # META COLOR
4075
+
4076
+ Sets the agent's accent color or gradient.
4077
+
4078
+ ## Key aspects
4079
+
4080
+ - Does not modify the agent's behavior or responses.
4081
+ - Only one \`META COLOR\` should be used per agent.
4082
+ - If multiple are specified, the last one takes precedence.
4083
+ - Used for visual representation in user interfaces.
4084
+ - Can specify multiple colors separated by comma to create a gradient.
4085
+
4086
+ ## Examples
4087
+
4088
+ \`\`\`book
4089
+ Professional Assistant
4090
+
4091
+ META COLOR #3498db
4092
+ PERSONA You are a professional business assistant
4093
+ \`\`\`
4094
+
4095
+ \`\`\`book
4096
+ Creative Helper
4097
+
4098
+ META COLOR #e74c3c
4099
+ PERSONA You are a creative and inspiring assistant
4100
+ \`\`\`
4101
+
4102
+ \`\`\`book
4103
+ Gradient Agent
4104
+
4105
+ META COLOR #ff0000, #00ff00, #0000ff
4106
+ PERSONA You are a colorful agent
4107
+ \`\`\`
4108
+ `);
4109
+ }
4110
+ applyToAgentModelRequirements(requirements, content) {
4111
+ // META COLOR doesn't modify the system message or model requirements
4112
+ // It's handled separately in the parsing logic for profile color extraction
4113
+ // This method exists for consistency with the CommitmentDefinition interface
4114
+ return requirements;
4115
+ }
4116
+ /**
4117
+ * Extracts the profile color from the content
4118
+ * This is used by the parsing logic
4119
+ */
4120
+ extractProfileColor(content) {
4121
+ const trimmedContent = content.trim();
4122
+ return trimmedContent || null;
4123
+ }
4124
+ }
4125
+ /**
4126
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4127
+ */
4128
+
4129
+ /**
4130
+ * META FONT commitment definition
4131
+ *
4132
+ * The META FONT commitment sets the agent's font.
4133
+ * This commitment is special because it doesn't affect the system message,
4134
+ * but is handled separately in the parsing logic.
4135
+ *
4136
+ * Example usage in agent source:
4137
+ *
4138
+ * ```book
4139
+ * META FONT Poppins, Arial, sans-serif
4140
+ * META FONT Roboto
4141
+ * ```
4142
+ *
4143
+ * @private [🪔] Maybe export the commitments through some package
4144
+ */
4145
+ class MetaFontCommitmentDefinition extends BaseCommitmentDefinition {
4146
+ constructor() {
4147
+ super('META FONT', ['FONT']);
4148
+ }
4149
+ /**
4150
+ * Short one-line description of META FONT.
4151
+ */
4152
+ get description() {
4153
+ return "Set the agent's font.";
4154
+ }
4155
+ /**
4156
+ * Icon for this commitment.
4157
+ */
4158
+ get icon() {
4159
+ return '🔤';
4160
+ }
4161
+ /**
4162
+ * Markdown documentation for META FONT commitment.
4163
+ */
4164
+ get documentation() {
4165
+ return spaceTrim$1(`
4166
+ # META FONT
4167
+
4168
+ Sets the agent's font.
4169
+
4170
+ ## Key aspects
4171
+
4172
+ - Does not modify the agent's behavior or responses.
4173
+ - Only one \`META FONT\` should be used per agent.
4174
+ - If multiple are specified, the last one takes precedence.
4175
+ - Used for visual representation in user interfaces.
4176
+ - Supports Google Fonts.
4177
+
4178
+ ## Examples
4179
+
4180
+ \`\`\`book
4181
+ Modern Assistant
4182
+
4183
+ META FONT Poppins, Arial, sans-serif
4184
+ PERSONA You are a modern assistant
4185
+ \`\`\`
4186
+
4187
+ \`\`\`book
4188
+ Classic Helper
4189
+
4190
+ META FONT Times New Roman
4191
+ PERSONA You are a classic helper
4192
+ \`\`\`
4193
+ `);
4194
+ }
4195
+ applyToAgentModelRequirements(requirements, content) {
4196
+ // META FONT doesn't modify the system message or model requirements
4197
+ // It's handled separately in the parsing logic
4198
+ // This method exists for consistency with the CommitmentDefinition interface
4199
+ return requirements;
4200
+ }
4201
+ /**
4202
+ * Extracts the font from the content
4203
+ * This is used by the parsing logic
4204
+ */
4205
+ extractProfileFont(content) {
4206
+ const trimmedContent = content.trim();
4207
+ return trimmedContent || null;
4208
+ }
4209
+ }
4210
+ /**
4211
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4212
+ */
4213
+
4214
+ /**
4215
+ * META IMAGE commitment definition
4216
+ *
4217
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
4218
+ * This commitment is special because it doesn't affect the system message,
4219
+ * but is handled separately in the parsing logic.
4220
+ *
4221
+ * Example usage in agent source:
4222
+ *
4223
+ * ```book
4224
+ * META IMAGE https://example.com/avatar.jpg
4225
+ * META IMAGE /assets/agent-avatar.png
4226
+ * ```
4227
+ *
4228
+ * @private [🪔] Maybe export the commitments through some package
4229
+ */
4230
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
4231
+ constructor() {
4232
+ super('META IMAGE', ['IMAGE']);
4233
+ }
4234
+ /**
4235
+ * Short one-line description of META IMAGE.
4236
+ */
4237
+ get description() {
4238
+ return "Set the agent's profile image URL.";
4239
+ }
4240
+ /**
4241
+ * Icon for this commitment.
4242
+ */
4243
+ get icon() {
4244
+ return '🖼️';
4245
+ }
4246
+ /**
4247
+ * Markdown documentation for META IMAGE commitment.
4248
+ */
4249
+ get documentation() {
4250
+ return spaceTrim$1(`
4251
+ # META IMAGE
4252
+
4253
+ Sets the agent's avatar/profile image URL.
4254
+
4255
+ ## Key aspects
4256
+
4257
+ - Does not modify the agent's behavior or responses.
4258
+ - Only one \`META IMAGE\` should be used per agent.
4259
+ - If multiple are specified, the last one takes precedence.
4260
+ - Used for visual representation in user interfaces.
4261
+
4262
+ ## Examples
4263
+
4264
+ \`\`\`book
4265
+ Professional Assistant
4266
+
4267
+ META IMAGE https://example.com/professional-avatar.jpg
4268
+ PERSONA You are a professional business assistant
4269
+ STYLE Maintain a formal and courteous tone
4270
+ \`\`\`
4271
+
4272
+ \`\`\`book
4273
+ Creative Helper
4274
+
4275
+ META IMAGE /assets/creative-bot-avatar.png
4276
+ PERSONA You are a creative and inspiring assistant
4277
+ STYLE Be enthusiastic and encouraging
4278
+ ACTION Can help with brainstorming and ideation
4279
+ \`\`\`
4280
+ `);
4281
+ }
4282
+ applyToAgentModelRequirements(requirements, content) {
4283
+ // META IMAGE doesn't modify the system message or model requirements
4284
+ // It's handled separately in the parsing logic for profile image extraction
4285
+ // This method exists for consistency with the CommitmentDefinition interface
4286
+ return requirements;
4287
+ }
4288
+ /**
4289
+ * Extracts the profile image URL from the content
4290
+ * This is used by the parsing logic
4291
+ */
4292
+ extractProfileImageUrl(content) {
4293
+ const trimmedContent = content.trim();
4294
+ return trimmedContent || null;
4295
+ }
4296
+ }
4297
+ /**
4298
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4299
+ */
4300
+
4301
+ /**
4302
+ * META LINK commitment definition
4303
+ *
4304
+ * The `META LINK` commitment represents the link to the person from whom the agent is created.
4305
+ * This commitment is special because it doesn't affect the system message,
4306
+ * but is handled separately in the parsing logic for profile display.
4307
+ *
4308
+ * Example usage in agent source:
4309
+ *
4310
+ * ```
4311
+ * META LINK https://twitter.com/username
4312
+ * META LINK https://linkedin.com/in/profile
4313
+ * META LINK https://github.com/username
4314
+ * ```
4315
+ *
4316
+ * Multiple `META LINK` commitments can be used when there are multiple sources:
4317
+ *
4318
+ * ```book
4319
+ * META LINK https://twitter.com/username
4320
+ * META LINK https://linkedin.com/in/profile
4321
+ * ```
4322
+ *
4323
+ * @private [🪔] Maybe export the commitments through some package
4324
+ */
4325
+ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
4326
+ constructor() {
4327
+ super('META LINK');
4328
+ }
4329
+ /**
4330
+ * Short one-line description of META LINK.
4331
+ */
4332
+ get description() {
4333
+ return 'Provide profile/source links for the person the agent models.';
4334
+ }
4335
+ /**
4336
+ * Icon for this commitment.
4337
+ */
4338
+ get icon() {
4339
+ return '🔗';
4340
+ }
4341
+ /**
4342
+ * Markdown documentation for META LINK commitment.
4343
+ */
4344
+ get documentation() {
4345
+ return spaceTrim$1(`
4346
+ # META LINK
4347
+
4348
+ Represents a profile or source link for the person the agent is modeled after.
4349
+
4350
+ ## Key aspects
4351
+
4352
+ - Does not modify the agent's behavior or responses.
4353
+ - Multiple \`META LINK\` commitments can be used for different social profiles.
4354
+ - Used for attribution and crediting the original person.
4355
+ - Displayed in user interfaces for transparency.
4356
+
4357
+ ## Examples
4358
+
4359
+ \`\`\`book
4360
+ Expert Consultant
4361
+
4362
+ META LINK https://twitter.com/expertname
4363
+ META LINK https://linkedin.com/in/expertprofile
4364
+ PERSONA You are Dr. Smith, a renowned expert in artificial intelligence
4365
+ KNOWLEDGE Extensive background in machine learning and neural networks
4366
+ \`\`\`
4367
+
4368
+ \`\`\`book
4369
+ Open Source Developer
4370
+
4371
+ META LINK https://github.com/developer
4372
+ META LINK https://twitter.com/devhandle
4373
+ PERSONA You are an experienced open source developer
4374
+ ACTION Can help with code reviews and architecture decisions
4375
+ STYLE Be direct and technical in explanations
4376
+ \`\`\`
4377
+ `);
4378
+ }
4379
+ applyToAgentModelRequirements(requirements, content) {
4380
+ // META LINK doesn't modify the system message or model requirements
4381
+ // It's handled separately in the parsing logic for profile link extraction
4382
+ // This method exists for consistency with the CommitmentDefinition interface
4383
+ return requirements;
4384
+ }
4385
+ /**
4386
+ * Extracts the profile link URL from the content
4387
+ * This is used by the parsing logic
4388
+ */
4389
+ extractProfileLinkUrl(content) {
4390
+ const trimmedContent = content.trim();
4391
+ return trimmedContent || null;
4392
+ }
4393
+ /**
4394
+ * Validates if the provided content is a valid URL
4395
+ */
4396
+ isValidUrl(content) {
4397
+ try {
4398
+ new URL(content.trim());
4399
+ return true;
4400
+ }
4401
+ catch (_a) {
4402
+ return false;
4403
+ }
4404
+ }
4405
+ }
4406
+ /**
4407
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4408
+ */
4409
+
4410
+ /**
4411
+ * MODEL commitment definition
4412
+ *
4413
+ * The MODEL commitment specifies which AI model to use and can also set
4414
+ * model-specific parameters like temperature, topP, topK, and maxTokens.
4415
+ *
4416
+ * Supports multiple syntax variations:
4417
+ *
4418
+ * Single-line format:
4419
+ * ```book
4420
+ * MODEL gpt-4
4421
+ * MODEL claude-3-opus temperature=0.3
4422
+ * MODEL gpt-3.5-turbo temperature=0.8 topP=0.9
4423
+ * ```
4424
+ *
4425
+ * Multi-line named parameter format:
4426
+ * ```book
4427
+ * MODEL NAME gpt-4
4428
+ * MODEL TEMPERATURE 0.7
4429
+ * MODEL TOP_P 0.9
4430
+ * MODEL MAX_TOKENS 2048
4431
+ * ```
4432
+ *
4433
+ * @private [🪔] Maybe export the commitments through some package
4434
+ */
4435
+ class ModelCommitmentDefinition extends BaseCommitmentDefinition {
4436
+ constructor(type = 'MODEL') {
4437
+ super(type);
4438
+ }
4439
+ /**
4440
+ * Short one-line description of MODEL.
4441
+ */
4442
+ get description() {
4443
+ return 'Enforce AI model requirements including name and technical parameters.';
4444
+ }
4445
+ /**
4446
+ * Icon for this commitment.
4447
+ */
4448
+ get icon() {
4449
+ return '⚙️';
4450
+ }
4451
+ /**
4452
+ * Markdown documentation for MODEL commitment.
4453
+ */
4454
+ get documentation() {
4455
+ return spaceTrim$1(`
4456
+ # ${this.type}
4457
+
4458
+ Enforces technical parameters for the AI model, ensuring consistent behavior across different execution environments.
4459
+
4460
+ ## Key aspects
4461
+
4462
+ - When no \`MODEL\` commitment is specified, the best model requirement is picked automatically based on the agent \`PERSONA\`, \`KNOWLEDGE\`, \`TOOLS\` and other commitments
4463
+ - Multiple \`MODEL\` commitments can be used to specify different parameters
4464
+ - Both \`MODEL\` and \`MODELS\` terms work identically and can be used interchangeably
4465
+ - Parameters control the randomness, creativity, and technical aspects of model responses
4466
+
4467
+ ## Syntax variations
4468
+
4469
+ ### Single-line format (legacy support)
4470
+ \`\`\`book
4471
+ MODEL gpt-4
4472
+ MODEL claude-3-opus temperature=0.3
4473
+ MODEL gpt-3.5-turbo temperature=0.8 topP=0.9
4474
+ \`\`\`
4475
+
4476
+ ### Multi-line named parameter format (recommended)
4477
+ \`\`\`book
4478
+ MODEL NAME gpt-4
4479
+ MODEL TEMPERATURE 0.7
4480
+ MODEL TOP_P 0.9
4481
+ MODEL MAX_TOKENS 2048
4482
+ \`\`\`
4483
+
4484
+ ## Supported parameters
4485
+
4486
+ - \`NAME\`: The specific model to use (e.g., 'gpt-4', 'claude-3-opus')
4487
+ - \`TEMPERATURE\`: Controls randomness (0.0 = deterministic, 1.0+ = creative)
4488
+ - \`TOP_P\`: Nucleus sampling parameter for controlling diversity
4489
+ - \`TOP_K\`: Top-k sampling parameter for limiting vocabulary
4490
+ - \`MAX_TOKENS\`: Maximum number of tokens the model can generate
4491
+
4492
+ ## Examples
4493
+
4494
+ ### Precise deterministic assistant
4495
+ \`\`\`book
4496
+ Precise Assistant
4497
+
4498
+ PERSONA You are a precise and accurate assistant
4499
+ MODEL NAME gpt-4
4500
+ MODEL TEMPERATURE 0.1
4501
+ MODEL MAX_TOKENS 1024
4502
+ RULE Always provide factual information
4503
+ \`\`\`
4504
+
4505
+ ### Creative writing assistant
4506
+ \`\`\`book
4507
+ Creative Writer
4508
+
4509
+ PERSONA You are a creative writing assistant
4510
+ MODEL NAME claude-3-opus
4511
+ MODEL TEMPERATURE 0.8
4512
+ MODEL TOP_P 0.9
4513
+ MODEL MAX_TOKENS 2048
4514
+ STYLE Be imaginative and expressive
4515
+ ACTION Can help with storytelling and character development
4516
+ \`\`\`
4517
+
4518
+ ### Balanced conversational agent
4519
+ \`\`\`book
4520
+ Balanced Assistant
4521
+
4522
+ PERSONA You are a helpful and balanced assistant
4523
+ MODEL NAME gpt-4
4524
+ MODEL TEMPERATURE 0.7
4525
+ MODEL TOP_P 0.95
4526
+ MODEL TOP_K 40
4527
+ MODEL MAX_TOKENS 1500
4528
+ \`\`\`
4529
+ `);
4530
+ }
4531
+ applyToAgentModelRequirements(requirements, content) {
4532
+ var _a;
4533
+ const trimmedContent = content.trim();
4534
+ if (!trimmedContent) {
4535
+ return requirements;
4536
+ }
4537
+ const parts = trimmedContent.split(/\s+/);
4538
+ const firstPart = (_a = parts[0]) === null || _a === void 0 ? void 0 : _a.toUpperCase();
4539
+ // Check if this is the new named parameter format
4540
+ if (this.isNamedParameter(firstPart)) {
4541
+ return this.parseNamedParameter(requirements, firstPart, parts.slice(1));
4542
+ }
4543
+ else {
4544
+ // Legacy single-line format: "MODEL gpt-4 temperature=0.3 topP=0.9"
4545
+ return this.parseLegacyFormat(requirements, parts);
4546
+ }
4547
+ }
4548
+ /**
4549
+ * Check if the first part is a known named parameter
4550
+ */
4551
+ isNamedParameter(part) {
4552
+ if (!part)
4553
+ return false;
4554
+ const knownParams = ['NAME', 'TEMPERATURE', 'TOP_P', 'TOP_K', 'MAX_TOKENS'];
4555
+ return knownParams.includes(part);
4556
+ }
4557
+ /**
4558
+ * Parse the new named parameter format: "MODEL TEMPERATURE 0.7"
4559
+ */
4560
+ parseNamedParameter(requirements, parameterName, valueParts) {
4561
+ const value = valueParts.join(' ').trim();
4562
+ if (!value) {
4563
+ return requirements;
4564
+ }
4565
+ const result = { ...requirements };
4566
+ switch (parameterName) {
4567
+ case 'NAME':
4568
+ result.modelName = value;
4569
+ break;
4570
+ case 'TEMPERATURE': {
4571
+ const temperature = parseFloat(value);
4572
+ if (!isNaN(temperature)) {
4573
+ result.temperature = temperature;
4574
+ }
4575
+ break;
4576
+ }
4577
+ case 'TOP_P': {
4578
+ const topP = parseFloat(value);
4579
+ if (!isNaN(topP)) {
4580
+ result.topP = topP;
4581
+ }
4582
+ break;
4583
+ }
4584
+ case 'TOP_K': {
4585
+ const topK = parseFloat(value);
4586
+ if (!isNaN(topK)) {
4587
+ result.topK = Math.round(topK);
4588
+ }
4589
+ break;
4590
+ }
4591
+ case 'MAX_TOKENS': {
4592
+ const maxTokens = parseFloat(value);
4593
+ if (!isNaN(maxTokens)) {
4594
+ result.maxTokens = Math.round(maxTokens);
4595
+ }
4596
+ break;
4597
+ }
4598
+ }
4599
+ return result;
4600
+ }
4601
+ /**
4602
+ * Parse the legacy format: "MODEL gpt-4 temperature=0.3 topP=0.9"
4603
+ */
4604
+ parseLegacyFormat(requirements, parts) {
4605
+ const modelName = parts[0];
4606
+ if (!modelName) {
4607
+ return requirements;
4608
+ }
4609
+ // Start with the model name
4610
+ const result = {
4611
+ ...requirements,
4612
+ modelName,
4613
+ };
4614
+ // Parse additional key=value parameters
4615
+ for (let i = 1; i < parts.length; i++) {
4616
+ const param = parts[i];
4617
+ if (param && param.includes('=')) {
4618
+ const [key, value] = param.split('=');
4619
+ if (key && value) {
4620
+ const numValue = parseFloat(value);
4621
+ if (!isNaN(numValue)) {
4622
+ switch (key.toLowerCase()) {
4623
+ case 'temperature':
4624
+ result.temperature = numValue;
4625
+ break;
4626
+ case 'topp':
4627
+ case 'top_p':
4628
+ result.topP = numValue;
4629
+ break;
4630
+ case 'topk':
4631
+ case 'top_k':
4632
+ result.topK = Math.round(numValue);
4633
+ break;
4634
+ case 'max_tokens':
4635
+ case 'maxTokens':
4636
+ result.maxTokens = Math.round(numValue);
4637
+ break;
4638
+ }
4639
+ }
4640
+ }
4641
+ }
4642
+ }
4643
+ return result;
4644
+ }
4645
+ }
4646
+ /**
4647
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4648
+ */
4649
+
4650
+ /**
4651
+ * NOTE commitment definition
4652
+ *
4653
+ * The NOTE commitment is used to add comments to the agent source without making any changes
4654
+ * to the system message or agent model requirements. It serves as a documentation mechanism
4655
+ * for developers to add explanatory comments, reminders, or annotations directly in the agent source.
4656
+ *
4657
+ * Key features:
4658
+ * - Makes no changes to the system message
4659
+ * - Makes no changes to agent model requirements
4660
+ * - Content is preserved in metadata.NOTE for debugging and inspection
4661
+ * - Multiple NOTE commitments are aggregated together
4662
+ * - Comments (# NOTE) are removed from the final system message
4663
+ *
4664
+ * Example usage in agent source:
4665
+ *
4666
+ * ```book
4667
+ * NOTE This agent was designed for customer support scenarios
4668
+ * NOTE Remember to update the knowledge base monthly
4669
+ * NOTE Performance optimized for quick response times
4670
+ * ```
4671
+ *
4672
+ * The above notes will be stored in metadata but won't affect the agent's behavior.
4673
+ *
4674
+ * @private [🪔] Maybe export the commitments through some package
4675
+ */
4676
+ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
4677
+ constructor(type = 'NOTE') {
4678
+ super(type);
4679
+ }
4680
+ /**
4681
+ * Short one-line description of NOTE.
4682
+ */
4683
+ get description() {
4684
+ return 'Add developer-facing notes without changing behavior or output.';
4685
+ }
4686
+ /**
4687
+ * Icon for this commitment.
4688
+ */
4689
+ get icon() {
4690
+ return '📝';
4691
+ }
4692
+ /**
4693
+ * Markdown documentation for NOTE commitment.
4694
+ */
4695
+ get documentation() {
4696
+ return spaceTrim$1(`
4697
+ # ${this.type}
4698
+
4699
+ Adds comments for documentation without changing agent behavior.
4700
+
4701
+ ## Key aspects
4702
+
4703
+ - Does not modify the agent's behavior or responses.
4704
+ - Multiple \`NOTE\`, \`NOTES\`, \`COMMENT\`, and \`NONCE\` commitments are aggregated for debugging.
4705
+ - All four terms work identically and can be used interchangeably.
4706
+ - Useful for documenting design decisions and reminders.
4707
+ - Content is preserved in metadata for inspection.
4708
+
4709
+ ## Examples
4710
+
4711
+ \`\`\`book
4712
+ Customer Support Bot
4713
+
4714
+ NOTE This agent was designed for customer support scenarios
4715
+ COMMENT Remember to update the knowledge base monthly
4716
+ PERSONA You are a helpful customer support representative
4717
+ KNOWLEDGE Company policies and procedures
4718
+ RULE Always be polite and professional
4719
+ \`\`\`
4720
+
4721
+ \`\`\`book
4722
+ Research Assistant
4723
+
4724
+ NONCE Performance optimized for quick response times
4725
+ NOTE Uses RAG for accessing latest research papers
4726
+ PERSONA You are a knowledgeable research assistant
4727
+ ACTION Can help with literature reviews and citations
4728
+ STYLE Present information in academic format
4729
+ \`\`\`
4730
+ `);
4731
+ }
4732
+ applyToAgentModelRequirements(requirements, content) {
4733
+ // The NOTE commitment makes no changes to the system message or model requirements
4734
+ // It only stores the note content in metadata for documentation purposes
4735
+ const trimmedContent = spaceTrim$1(content);
4736
+ if (trimmedContent === '') {
4737
+ return requirements;
4738
+ }
4739
+ // Return requirements with updated notes but no changes to system message
4740
+ return {
4741
+ ...requirements,
4742
+ notes: [...(requirements.notes || []), trimmedContent],
4743
+ };
4744
+ }
4745
+ }
4746
+ /**
4747
+ * [💞] Ignore a discrepancy between file name and entity name
4748
+ */
4749
+
4750
+ /**
4751
+ * OPEN commitment definition
4752
+ *
4753
+ * The OPEN commitment specifies that the agent can be modified by conversation.
4754
+ * This is the default behavior.
4755
+ *
4756
+ * Example usage in agent source:
4757
+ *
4758
+ * ```book
4759
+ * OPEN
4760
+ * ```
4761
+ *
4762
+ * @private [🪔] Maybe export the commitments through some package
4763
+ */
4764
+ class OpenCommitmentDefinition extends BaseCommitmentDefinition {
4765
+ constructor() {
4766
+ super('OPEN');
4767
+ }
4768
+ /**
4769
+ * Short one-line description of OPEN.
4770
+ */
4771
+ get description() {
4772
+ return 'Allow the agent to be modified by conversation (default).';
4773
+ }
4774
+ /**
4775
+ * Icon for this commitment.
4776
+ */
4777
+ get icon() {
4778
+ return '🔓';
4779
+ }
4780
+ /**
4781
+ * Markdown documentation for OPEN commitment.
4782
+ */
4783
+ get documentation() {
4784
+ return spaceTrim$1(`
4785
+ # OPEN
4786
+
4787
+ Specifies that the agent can be modified by conversation with it.
4788
+ This means the agent will learn from interactions and update its source code.
4789
+
4790
+ This is the default behavior if neither \`OPEN\` nor \`CLOSED\` is specified.
4791
+
4792
+ > See also [CLOSED](/docs/CLOSED)
4793
+
4794
+ ## Example
4795
+
4796
+ \`\`\`book
4797
+ OPEN
4798
+ \`\`\`
4799
+ `);
4800
+ }
4801
+ applyToAgentModelRequirements(requirements, _content) {
4802
+ // Since OPEN is default, we can just ensure isClosed is false
4803
+ // But to be explicit we can set it
4804
+ const updatedMetadata = {
4805
+ ...requirements.metadata,
4806
+ isClosed: false,
4807
+ };
4808
+ return {
4809
+ ...requirements,
4810
+ metadata: updatedMetadata,
4811
+ };
4812
+ }
4813
+ }
4814
+ /**
4815
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4816
+ */
4817
+
4818
+ /**
4819
+ * PERSONA commitment definition
4820
+ *
4821
+ * The PERSONA commitment modifies the agent's personality and character in the system message.
4822
+ * It defines who the agent is, their background, expertise, and personality traits.
4823
+ *
4824
+ * Key features:
4825
+ * - Multiple PERSONA commitments are automatically merged into one
4826
+ * - Content is placed at the beginning of the system message
4827
+ * - Original content with comments is preserved in metadata.PERSONA
4828
+ * - Comments (# PERSONA) are removed from the final system message
4829
+ *
4830
+ * Example usage in agent source:
4831
+ *
4832
+ * ```book
4833
+ * PERSONA You are a helpful programming assistant with expertise in TypeScript and React
4834
+ * PERSONA You have deep knowledge of modern web development practices
4835
+ * ```
4836
+ *
4837
+ * The above will be merged into a single persona section at the beginning of the system message.
4838
+ *
4839
+ * @private [🪔] Maybe export the commitments through some package
4840
+ */
4841
+ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
4842
+ constructor(type = 'PERSONA') {
4843
+ super(type);
4844
+ }
4845
+ /**
4846
+ * Short one-line description of PERSONA.
4847
+ */
4848
+ get description() {
4849
+ return 'Define who the agent is: background, expertise, and personality.';
4850
+ }
4851
+ /**
4852
+ * Icon for this commitment.
4853
+ */
4854
+ get icon() {
4855
+ return '👤';
4856
+ }
4857
+ /**
4858
+ * Markdown documentation for PERSONA commitment.
4859
+ */
4860
+ get documentation() {
4861
+ return spaceTrim$1(`
4862
+ # ${this.type}
4863
+
4864
+ Defines who the agent is, their background, expertise, and personality traits.
4865
+
4866
+ ## Key aspects
4867
+
4868
+ - Multiple \`PERSONA\` and \`PERSONAE\` commitments are merged together.
4869
+ - Both terms work identically and can be used interchangeably.
4870
+ - If they are in conflict, the last one takes precedence.
4871
+ - You can write persona content in multiple lines.
4872
+
4873
+ ## Examples
4874
+
4875
+ \`\`\`book
4876
+ Programming Assistant
4877
+
4878
+ PERSONA You are a helpful programming assistant with expertise in TypeScript and React
4879
+ PERSONA You have deep knowledge of modern web development practices
4880
+ \`\`\`
4881
+ `);
4882
+ }
4883
+ applyToAgentModelRequirements(requirements, content) {
4884
+ var _a, _b;
4885
+ // The PERSONA commitment aggregates all persona content and places it at the beginning
4886
+ const trimmedContent = content.trim();
4887
+ if (!trimmedContent) {
4888
+ return requirements;
4889
+ }
4890
+ // Get existing persona content from metadata
4891
+ const existingPersonaContent = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.PERSONA) || '';
4892
+ // Merge the new content with existing persona content
4893
+ // When multiple PERSONA commitments exist, they are merged into one
4894
+ const mergedPersonaContent = existingPersonaContent
4895
+ ? `${existingPersonaContent}\n${trimmedContent}`
4896
+ : trimmedContent;
4897
+ // Store the merged persona content in metadata for debugging and inspection
4898
+ const updatedMetadata = {
4899
+ ...requirements.metadata,
4900
+ PERSONA: mergedPersonaContent,
4901
+ };
4902
+ // Get the agent name from metadata (which should contain the first line of agent source)
4903
+ // If not available, extract from current system message as fallback
4904
+ let agentName = (_b = requirements.metadata) === null || _b === void 0 ? void 0 : _b.agentName;
4905
+ if (!agentName) {
4906
+ // Fallback: extract from current system message
4907
+ const currentMessage = requirements.systemMessage.trim();
4908
+ const basicFormatMatch = currentMessage.match(/^You are (.+)$/);
4909
+ if (basicFormatMatch && basicFormatMatch[1]) {
4910
+ agentName = basicFormatMatch[1];
4911
+ }
4912
+ else {
4913
+ agentName = 'AI Agent'; // Final fallback
4914
+ }
4915
+ }
4916
+ // Remove any existing persona content from the system message
4917
+ // (this handles the case where we're processing multiple PERSONA commitments)
4918
+ const currentMessage = requirements.systemMessage.trim();
4919
+ let cleanedMessage = currentMessage;
4920
+ // Check if current message starts with persona content or is just the basic format
4921
+ const basicFormatRegex = /^You are .+$/;
4922
+ const isBasicFormat = basicFormatRegex.test(currentMessage) && !currentMessage.includes('\n');
4923
+ if (isBasicFormat) {
4924
+ // Replace the basic format entirely
4925
+ cleanedMessage = '';
4926
+ }
4927
+ else if (currentMessage.startsWith('# PERSONA')) {
4928
+ // Remove existing persona section by finding where it ends
4929
+ const lines = currentMessage.split('\n');
4930
+ let personaEndIndex = lines.length;
4931
+ // Find the end of the PERSONA section (next comment or end of message)
4932
+ for (let i = 1; i < lines.length; i++) {
4933
+ const line = lines[i].trim();
4934
+ if (line.startsWith('#') && !line.startsWith('# PERSONA')) {
4935
+ personaEndIndex = i;
4936
+ break;
4937
+ }
4938
+ }
4939
+ // Keep everything after the PERSONA section
4940
+ cleanedMessage = lines.slice(personaEndIndex).join('\n').trim();
4941
+ }
4942
+ // TODO: [🕛] There should be `agentFullname` not `agentName`
4943
+ // Create new system message with persona at the beginning
4944
+ // Format: "You are {agentName}\n{personaContent}"
4945
+ // The # PERSONA comment will be removed later by removeCommentsFromSystemMessage
4946
+ const personaSection = `# PERSONA\nYou are ${agentName}\n${mergedPersonaContent}`; // <- TODO: Use spaceTrim
4947
+ const newSystemMessage = cleanedMessage ? `${personaSection}\n\n${cleanedMessage}` : personaSection;
4948
+ return {
4949
+ ...requirements,
4950
+ systemMessage: newSystemMessage,
4951
+ metadata: updatedMetadata,
4952
+ };
4953
+ }
4954
+ }
4955
+ /**
4956
+ * Note: [💞] Ignore a discrepancy between file name and entity name
4957
+ */
4958
+
4959
+ /**
4960
+ * RULE commitment definition
4961
+ *
4962
+ * The RULE/RULES commitment adds behavioral constraints and guidelines that the agent must follow.
4963
+ * These are specific instructions about what the agent should or shouldn't do.
4964
+ *
4965
+ * Example usage in agent source:
4966
+ *
4967
+ * ```book
4968
+ * RULE Always ask for clarification if the user's request is ambiguous
4969
+ * RULES Never provide medical advice, always refer to healthcare professionals
4970
+ * ```
4971
+ *
4972
+ * @private [🪔] Maybe export the commitments through some package
4973
+ */
4974
+ class RuleCommitmentDefinition extends BaseCommitmentDefinition {
4975
+ constructor(type = 'RULE') {
4976
+ super(type);
4977
+ }
4978
+ /**
4979
+ * Short one-line description of RULE/RULES.
4980
+ */
4981
+ get description() {
4982
+ return 'Add behavioral rules the agent must follow.';
4983
+ }
4984
+ /**
4985
+ * Icon for this commitment.
4986
+ */
4987
+ get icon() {
4988
+ return '⚖️';
4989
+ }
4990
+ /**
4991
+ * Markdown documentation for RULE/RULES commitment.
4992
+ */
4993
+ get documentation() {
4994
+ return spaceTrim$1(`
4995
+ # ${this.type}
4996
+
4997
+ Adds behavioral constraints and guidelines that the agent must follow.
4998
+
4999
+ ## Key aspects
5000
+
5001
+ - All rules are treated equally regardless of singular/plural form.
5002
+ - Rules define what the agent must or must not do.
5003
+
5004
+ ## Examples
5005
+
5006
+ \`\`\`book
5007
+ Customer Support Agent
5008
+
5009
+ PERSONA You are a helpful customer support representative
5010
+ RULE Always ask for clarification if the user's request is ambiguous
5011
+ RULE Be polite and professional in all interactions
5012
+ RULES Never provide medical or legal advice
5013
+ STYLE Maintain a friendly and helpful tone
5014
+ \`\`\`
5015
+
5016
+ \`\`\`book
5017
+ Educational Tutor
5018
+
5019
+ PERSONA You are a patient and knowledgeable tutor
5020
+ RULE Break down complex concepts into simple steps
5021
+ RULE Always encourage students and celebrate their progress
5022
+ RULE If you don't know something, admit it and suggest resources
5023
+ SAMPLE When explaining math: "Let's work through this step by step..."
5024
+ \`\`\`
5025
+ `);
5026
+ }
5027
+ applyToAgentModelRequirements(requirements, content) {
5028
+ const trimmedContent = content.trim();
5029
+ if (!trimmedContent) {
5030
+ return requirements;
5031
+ }
5032
+ // Add rule to the system message
5033
+ const ruleSection = `Rule: ${trimmedContent}`;
5034
+ return this.appendToSystemMessage(requirements, ruleSection, '\n\n');
5035
+ }
5036
+ }
5037
+ /**
5038
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5039
+ */
5040
+
5041
+ /**
5042
+ * SAMPLE commitment definition
5043
+ *
5044
+ * The SAMPLE/EXAMPLE commitment provides examples of how the agent should respond
5045
+ * or behave in certain situations. These examples help guide the agent's responses.
5046
+ *
5047
+ * Example usage in agent source:
5048
+ *
5049
+ * ```book
5050
+ * SAMPLE When asked about pricing, respond: "Our basic plan starts at $10/month..."
5051
+ * EXAMPLE For code questions, always include working code snippets
5052
+ * ```
5053
+ *
5054
+ * @private [🪔] Maybe export the commitments through some package
5055
+ */
5056
+ class SampleCommitmentDefinition extends BaseCommitmentDefinition {
5057
+ constructor(type = 'SAMPLE') {
5058
+ super(type);
5059
+ }
5060
+ /**
5061
+ * Short one-line description of SAMPLE/EXAMPLE.
5062
+ */
5063
+ get description() {
5064
+ return 'Provide example responses to guide behavior.';
5065
+ }
5066
+ /**
5067
+ * Icon for this commitment.
5068
+ */
5069
+ get icon() {
5070
+ return '🔍';
5071
+ }
5072
+ /**
5073
+ * Markdown documentation for SAMPLE/EXAMPLE commitment.
5074
+ */
5075
+ get documentation() {
5076
+ return spaceTrim$1(`
5077
+ # ${this.type}
5078
+
5079
+ Provides examples of how the agent should respond or behave in certain situations.
5080
+
5081
+ ## Key aspects
5082
+
5083
+ - Both terms work identically and can be used interchangeably.
5084
+ - Examples help guide the agent's response patterns and style.
5085
+
5086
+ ## Examples
5087
+
5088
+ \`\`\`book
5089
+ Sales Assistant
5090
+
5091
+ PERSONA You are a knowledgeable sales representative
5092
+ SAMPLE When asked about pricing, respond: "Our basic plan starts at $10/month..."
5093
+ SAMPLE For feature comparisons, create a clear comparison table
5094
+ RULE Always be honest about limitations
5095
+ \`\`\`
5096
+
5097
+ \`\`\`book
5098
+ Code Reviewer
5099
+
5100
+ PERSONA You are an experienced software engineer
5101
+ EXAMPLE For code questions, always include working code snippets
5102
+ EXAMPLE When suggesting improvements: "Here's a more efficient approach..."
5103
+ RULE Explain the reasoning behind your suggestions
5104
+ STYLE Be constructive and encouraging in feedback
5105
+ \`\`\`
5106
+ `);
5107
+ }
5108
+ applyToAgentModelRequirements(requirements, content) {
5109
+ const trimmedContent = content.trim();
5110
+ if (!trimmedContent) {
5111
+ return requirements;
5112
+ }
5113
+ // Add example to the system message
5114
+ const exampleSection = `Example: ${trimmedContent}`;
5115
+ return this.appendToSystemMessage(requirements, exampleSection, '\n\n');
5116
+ }
5117
+ }
5118
+ /**
5119
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5120
+ */
5121
+
5122
+ /**
5123
+ * SCENARIO commitment definition
5124
+ *
5125
+ * The SCENARIO commitment defines a specific situation or context in which the AI
5126
+ * assistant should operate. It helps to set the scene for the AI's responses.
5127
+ * Later scenarios are more important than earlier scenarios.
5128
+ *
5129
+ * Example usage in agent source:
5130
+ *
5131
+ * ```book
5132
+ * SCENARIO You are in a customer service call center during peak hours
5133
+ * SCENARIO The customer is frustrated and has been on hold for 20 minutes
5134
+ * SCENARIO This is the customer's third call about the same issue
5135
+ * ```
5136
+ *
5137
+ * @private [🪔] Maybe export the commitments through some package
5138
+ */
5139
+ class ScenarioCommitmentDefinition extends BaseCommitmentDefinition {
5140
+ constructor(type = 'SCENARIO') {
5141
+ super(type);
5142
+ }
5143
+ /**
5144
+ * Short one-line description of SCENARIO.
5145
+ */
5146
+ get description() {
5147
+ return 'Define specific **situations** or contexts for AI responses, with later scenarios having higher priority.';
5148
+ }
5149
+ /**
5150
+ * Icon for this commitment.
5151
+ */
5152
+ get icon() {
5153
+ return '🎭';
5154
+ }
5155
+ /**
5156
+ * Markdown documentation for SCENARIO commitment.
5157
+ */
5158
+ get documentation() {
5159
+ return spaceTrim$1(`
5160
+ # ${this.type}
5161
+
5162
+ Defines a specific situation or context in which the AI assistant should operate. It helps to set the scene for the AI's responses. Later scenarios are more important than earlier scenarios.
5163
+
5164
+ ## Key aspects
5165
+
5166
+ - Multiple \`SCENARIO\` and \`SCENARIOS\` commitments build upon each other.
5167
+ - Both terms work identically and can be used interchangeably.
5168
+ - Later scenarios have higher priority and can override earlier scenarios.
5169
+ - Provides situational context that influences response tone and content.
5170
+ - Helps establish the environment and circumstances for interactions.
5171
+
5172
+ ## Priority system
5173
+
5174
+ When multiple scenarios are defined, they are processed in order, with later scenarios taking precedence over earlier ones when there are conflicts.
5175
+
5176
+ ## Use cases
5177
+
5178
+ - Setting the physical or virtual environment
5179
+ - Establishing time constraints or urgency
5180
+ - Defining relationship dynamics or power structures
5181
+ - Creating emotional or situational context
5182
+
5183
+ ## Examples
5184
+
5185
+ \`\`\`book
5186
+ Emergency Response Operator
5187
+
5188
+ PERSONA You are an emergency response operator
5189
+ SCENARIO You are handling a 911 emergency call
5190
+ SCENARIO The caller is panicked and speaking rapidly
5191
+ SCENARIO Time is critical - every second counts
5192
+ GOAL Gather essential information quickly and dispatch appropriate help
5193
+ RULE Stay calm and speak clearly
5194
+ \`\`\`
5195
+
5196
+ \`\`\`book
5197
+ Sales Representative
5198
+
5199
+ PERSONA You are a software sales representative
5200
+ SCENARIO You are in the final meeting of a 6-month sales cycle
5201
+ SCENARIO The client has budget approval and decision-making authority
5202
+ SCENARIO Two competitors have also submitted proposals
5203
+ SCENARIO The client values long-term partnership over lowest price
5204
+ GOAL Close the deal while building trust for future business
5205
+ \`\`\`
5206
+
5207
+ \`\`\`book
5208
+ Medical Assistant
5209
+
5210
+ PERSONA You are a medical assistant in a busy clinic
5211
+ SCENARIO The waiting room is full and the doctor is running behind schedule
5212
+ SCENARIO Patients are becoming impatient and anxious
5213
+ SCENARIO You need to manage expectations while maintaining professionalism
5214
+ SCENARIO Some patients have been waiting over an hour
5215
+ GOAL Keep patients informed and calm while supporting efficient clinic flow
5216
+ RULE Never provide medical advice or diagnosis
5217
+ \`\`\`
5218
+
5219
+ \`\`\`book
5220
+ Technical Support Agent
5221
+
5222
+ PERSONA You are a technical support agent
5223
+ SCENARIO The customer is a small business owner during their busy season
5224
+ SCENARIO Their main business system has been down for 2 hours
5225
+ SCENARIO They are losing money every minute the system is offline
5226
+ SCENARIO This is their first experience with your company
5227
+ GOAL Resolve the issue quickly while creating a positive first impression
5228
+ \`\`\`
5229
+ `);
5230
+ }
5231
+ applyToAgentModelRequirements(requirements, content) {
5232
+ const trimmedContent = content.trim();
5233
+ if (!trimmedContent) {
5234
+ return requirements;
5235
+ }
5236
+ // Create scenario section for system message
5237
+ const scenarioSection = `Scenario: ${trimmedContent}`;
5238
+ // Scenarios provide important contextual information that affects behavior
5239
+ return this.appendToSystemMessage(requirements, scenarioSection, '\n\n');
5240
+ }
5241
+ }
5242
+ /**
5243
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5244
+ */
5245
+
5246
+ /**
5247
+ * STYLE commitment definition
5248
+ *
5249
+ * The STYLE commitment defines how the agent should format and present its responses.
5250
+ * This includes tone, writing style, formatting preferences, and communication patterns.
5251
+ *
5252
+ * Example usage in agent source:
5253
+ *
5254
+ * ```book
5255
+ * STYLE Write in a professional but friendly tone, use bullet points for lists
5256
+ * STYLE Always provide code examples when explaining programming concepts
5257
+ * ```
5258
+ *
5259
+ * @private [🪔] Maybe export the commitments through some package
5260
+ */
5261
+ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
5262
+ constructor(type = 'STYLE') {
5263
+ super(type);
5264
+ }
5265
+ /**
5266
+ * Short one-line description of STYLE.
5267
+ */
5268
+ get description() {
5269
+ return 'Control the tone and writing style of responses.';
5270
+ }
5271
+ /**
5272
+ * Icon for this commitment.
5273
+ */
5274
+ get icon() {
5275
+ return '🖋️';
5276
+ }
5277
+ /**
5278
+ * Markdown documentation for STYLE commitment.
5279
+ */
5280
+ get documentation() {
5281
+ return spaceTrim$1(`
5282
+ # ${this.type}
5283
+
5284
+ Defines how the agent should format and present its responses (tone, writing style, formatting).
5285
+
5286
+ ## Key aspects
5287
+
5288
+ - Both terms work identically and can be used interchangeably.
5289
+ - Later style instructions can override earlier ones.
5290
+ - Style affects both tone and presentation format.
5291
+
5292
+ ## Examples
5293
+
5294
+ \`\`\`book
5295
+ Technical Writer
5296
+
5297
+ PERSONA You are a technical documentation expert
5298
+ STYLE Write in a professional but friendly tone, use bullet points for lists
5299
+ STYLE Always provide code examples when explaining programming concepts
5300
+ FORMAT Use markdown formatting with clear headings
5301
+ \`\`\`
5302
+
5303
+ \`\`\`book
5304
+ Creative Assistant
5305
+
5306
+ PERSONA You are a creative writing helper
5307
+ STYLE Be enthusiastic and encouraging in your responses
5308
+ STYLE Use vivid metaphors and analogies to explain concepts
5309
+ STYLE Keep responses conversational and engaging
5310
+ RULE Always maintain a positive and supportive tone
5311
+ \`\`\`
5312
+ `);
5313
+ }
5314
+ applyToAgentModelRequirements(requirements, content) {
5315
+ const trimmedContent = content.trim();
5316
+ if (!trimmedContent) {
5317
+ return requirements;
5318
+ }
5319
+ // Add style instructions to the system message
5320
+ const styleSection = `Style: ${trimmedContent}`;
5321
+ return this.appendToSystemMessage(requirements, styleSection, '\n\n');
5322
+ }
5323
+ }
5324
+ /**
5325
+ * [💞] Ignore a discrepancy between file name and entity name
5326
+ */
5327
+
5328
+ /**
5329
+ * USE commitment definition
5330
+ *
5331
+ * The USE commitment indicates that the agent should utilize specific tools or capabilities
5332
+ * to access and interact with external systems when necessary.
5333
+ *
5334
+ * Supported USE types:
5335
+ * - USE BROWSER: Enables the agent to use a web browser tool
5336
+ * - USE SEARCH ENGINE (future): Enables search engine access
5337
+ * - USE FILE SYSTEM (future): Enables file system operations
5338
+ * - USE MCP (future): Enables MCP server connections
5339
+ *
5340
+ * The content following the USE commitment is ignored (similar to NOTE).
5341
+ *
5342
+ * Example usage in agent source:
5343
+ *
5344
+ * ```book
5345
+ * USE BROWSER
5346
+ * USE SEARCH ENGINE
5347
+ * ```
5348
+ *
5349
+ * @private [🪔] Maybe export the commitments through some package
5350
+ */
5351
+ class UseCommitmentDefinition extends BaseCommitmentDefinition {
5352
+ constructor() {
5353
+ super('USE');
5354
+ }
5355
+ /**
5356
+ * Short one-line description of USE commitments.
5357
+ */
5358
+ get description() {
5359
+ return 'Enable the agent to use specific tools or capabilities (BROWSER, SEARCH ENGINE, etc.).';
5360
+ }
5361
+ /**
5362
+ * Icon for this commitment.
5363
+ */
5364
+ get icon() {
5365
+ return '🔧';
5366
+ }
5367
+ /**
5368
+ * Markdown documentation for USE commitment.
5369
+ */
5370
+ get documentation() {
5371
+ return spaceTrim$1(`
5372
+ # USE
5373
+
5374
+ Enables the agent to use specific tools or capabilities for interacting with external systems.
5375
+
5376
+ ## Supported USE types
5377
+
5378
+ - **USE BROWSER** - Enables the agent to use a web browser tool to access and retrieve information from the internet
5379
+ - **USE SEARCH ENGINE** (future) - Enables search engine access
5380
+ - **USE FILE SYSTEM** (future) - Enables file system operations
5381
+ - **USE MCP** (future) - Enables MCP server connections
5382
+
5383
+ ## Key aspects
5384
+
5385
+ - The content following the USE commitment is ignored (similar to NOTE)
5386
+ - Multiple USE commitments can be specified to enable multiple capabilities
5387
+ - The actual tool usage is handled by the agent runtime
5388
+
5389
+ ## Examples
5390
+
5391
+ ### Basic browser usage
5392
+
5393
+ \`\`\`book
5394
+ Research Assistant
5395
+
5396
+ PERSONA You are a helpful research assistant
5397
+ USE BROWSER
5398
+ KNOWLEDGE Can search the web for up-to-date information
5399
+ \`\`\`
5400
+
5401
+ ### Multiple tools
5402
+
5403
+ \`\`\`book
5404
+ Data Analyst
5405
+
5406
+ PERSONA You are a data analyst assistant
5407
+ USE BROWSER
5408
+ USE FILE SYSTEM
5409
+ ACTION Can analyze data from various sources
5410
+ \`\`\`
5411
+ `);
5412
+ }
5413
+ applyToAgentModelRequirements(requirements, content) {
5414
+ // USE commitments don't modify the system message or model requirements directly
5415
+ // They are handled separately in the parsing logic for capability extraction
5416
+ // This method exists for consistency with the CommitmentDefinition interface
5417
+ return requirements;
5418
+ }
5419
+ /**
5420
+ * Extracts the tool type from the USE commitment
5421
+ * This is used by the parsing logic
5422
+ */
5423
+ extractToolType(content) {
5424
+ var _a, _b;
5425
+ const trimmedContent = content.trim();
5426
+ // The tool type is the first word after USE (already stripped)
5427
+ const match = trimmedContent.match(/^(\w+)/);
5428
+ 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;
5429
+ }
5430
+ /**
5431
+ * Checks if this is a known USE type
5432
+ */
5433
+ isKnownUseType(useType) {
5434
+ const knownTypes = ['BROWSER', 'SEARCH ENGINE', 'FILE SYSTEM', 'MCP'];
5435
+ return knownTypes.includes(useType.toUpperCase());
5436
+ }
5437
+ }
5438
+ /**
5439
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5440
+ */
5441
+
5442
+ /**
5443
+ * USE BROWSER commitment definition
5444
+ *
5445
+ * The `USE BROWSER` commitment indicates that the agent should utilize a web browser tool
5446
+ * to access and retrieve up-to-date information from the internet when necessary.
5447
+ *
5448
+ * The content following `USE BROWSER` is ignored (similar to NOTE).
5449
+ *
5450
+ * Example usage in agent source:
5451
+ *
5452
+ * ```book
5453
+ * USE BROWSER
5454
+ * USE BROWSER This will be ignored
5455
+ * ```
5456
+ *
5457
+ * @private [🪔] Maybe export the commitments through some package
5458
+ */
5459
+ class UseBrowserCommitmentDefinition extends BaseCommitmentDefinition {
5460
+ constructor() {
5461
+ super('USE BROWSER', ['BROWSER']);
5462
+ }
5463
+ /**
5464
+ * The `USE BROWSER` commitment is standalone.
5465
+ */
5466
+ get requiresContent() {
5467
+ return false;
5468
+ }
5469
+ /**
5470
+ * Short one-line description of USE BROWSER.
5471
+ */
5472
+ get description() {
5473
+ return 'Enable the agent to use a web browser tool for accessing internet information.';
5474
+ }
5475
+ /**
5476
+ * Icon for this commitment.
5477
+ */
5478
+ get icon() {
5479
+ return '🌐';
5480
+ }
5481
+ /**
5482
+ * Markdown documentation for USE BROWSER commitment.
5483
+ */
5484
+ get documentation() {
5485
+ return spaceTrim$1(`
5486
+ # USE BROWSER
5487
+
5488
+ Enables the agent to use a web browser tool to access and retrieve up-to-date information from the internet.
5489
+
5490
+ ## Key aspects
5491
+
5492
+ - The content following \`USE BROWSER\` is ignored (similar to NOTE)
5493
+ - The actual browser tool usage is handled by the agent runtime
5494
+ - Allows the agent to fetch current information from websites
5495
+ - Useful for research tasks, fact-checking, and accessing dynamic content
5496
+
5497
+ ## Examples
5498
+
5499
+ \`\`\`book
5500
+ Research Assistant
5501
+
5502
+ PERSONA You are a helpful research assistant specialized in finding current information
5503
+ USE BROWSER
5504
+ RULE Always cite your sources when providing information from the web
5505
+ \`\`\`
5506
+
5507
+ \`\`\`book
5508
+ News Analyst
5509
+
5510
+ PERSONA You are a news analyst who stays up-to-date with current events
5511
+ USE BROWSER
5512
+ STYLE Present news in a balanced and objective manner
5513
+ ACTION Can search for and summarize news articles
5514
+ \`\`\`
5515
+
5516
+ \`\`\`book
5517
+ Company Lawyer
5518
+
5519
+ PERSONA You are a company lawyer providing legal advice
5520
+ USE BROWSER
5521
+ KNOWLEDGE Corporate law and legal procedures
5522
+ RULE Always recommend consulting with a licensed attorney for specific legal matters
5523
+ \`\`\`
5524
+ `);
5525
+ }
5526
+ /**
5527
+ * Gets human-readable titles for tool functions provided by this commitment.
5528
+ */
5529
+ getToolTitles() {
5530
+ return {
5531
+ web_browser: 'Web browser',
5532
+ };
5533
+ }
5534
+ applyToAgentModelRequirements(requirements, content) {
5535
+ // Get existing tools array or create new one
5536
+ const existingTools = requirements.tools || [];
5537
+ // Add 'web_browser' to tools if not already present
5538
+ const updatedTools = existingTools.some((tool) => tool.name === 'web_browser')
5539
+ ? existingTools
5540
+ : ([
5541
+ // TODO: [🔰] Use through proper MCP server
5542
+ ...existingTools,
5543
+ {
5544
+ name: 'web_browser',
5545
+ description: spaceTrim$1(`
5546
+ A tool that can browse the web.
5547
+ Use this tool when you need to access specific websites or browse the internet.
5548
+ `),
5549
+ parameters: {
5550
+ type: 'object',
5551
+ properties: {
5552
+ url: {
5553
+ type: 'string',
5554
+ description: 'The URL to browse',
5555
+ },
5556
+ },
5557
+ required: ['url'],
5558
+ },
5559
+ },
5560
+ ]);
5561
+ // Return requirements with updated tools and metadata
5562
+ return this.appendToSystemMessage({
5563
+ ...requirements,
5564
+ tools: updatedTools,
5565
+ metadata: {
5566
+ ...requirements.metadata,
5567
+ useBrowser: true,
5568
+ },
5569
+ }, spaceTrim$1(`
5570
+ You have access to the web browser. Use it to access specific websites or browse the internet.
5571
+ When you need to know some information from a specific website, use the tool provided to you.
5572
+ `));
5573
+ }
5574
+ }
5575
+ /**
5576
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5577
+ */
5578
+
5579
+ /**
5580
+ * USE MCP commitment definition
5581
+ *
5582
+ * The `USE MCP` commitment allows to specify an MCP server URL which the agent will connect to
5583
+ * for retrieving additional instructions and actions.
5584
+ *
5585
+ * The content following `USE MCP` is the URL of the MCP server.
5586
+ *
5587
+ * Example usage in agent source:
5588
+ *
5589
+ * ```book
5590
+ * USE MCP http://mcp-server-url.com
5591
+ * ```
5592
+ *
5593
+ * @private [🪔] Maybe export the commitments through some package
5594
+ */
5595
+ class UseMcpCommitmentDefinition extends BaseCommitmentDefinition {
5596
+ constructor() {
5597
+ super('USE MCP', ['MCP']);
5598
+ }
5599
+ /**
5600
+ * Short one-line description of USE MCP.
5601
+ */
5602
+ get description() {
5603
+ return 'Connects the agent to an external MCP server for additional capabilities.';
5604
+ }
5605
+ /**
5606
+ * Icon for this commitment.
5607
+ */
5608
+ get icon() {
5609
+ return '🔌';
5610
+ }
5611
+ /**
5612
+ * Markdown documentation for USE MCP commitment.
5613
+ */
5614
+ get documentation() {
5615
+ return spaceTrim$1(`
5616
+ # USE MCP
5617
+
5618
+ Connects the agent to an external Model Context Protocol (MCP) server.
5619
+
5620
+ ## Key aspects
5621
+
5622
+ - The content following \`USE MCP\` must be a valid URL
5623
+ - Multiple MCP servers can be connected by using multiple \`USE MCP\` commitments
5624
+ - The agent will have access to tools and resources provided by the MCP server
5625
+
5626
+ ## Example
5627
+
5628
+ \`\`\`book
5629
+ Company Lawyer
5630
+
5631
+ PERSONA You are a company lawyer.
5632
+ USE MCP http://legal-db.example.com
5633
+ \`\`\`
5634
+ `);
5635
+ }
5636
+ applyToAgentModelRequirements(requirements, content) {
5637
+ const mcpServerUrl = content.trim();
5638
+ if (!mcpServerUrl) {
5639
+ return requirements;
5640
+ }
5641
+ const existingMcpServers = requirements.mcpServers || [];
5642
+ // Avoid duplicates
5643
+ if (existingMcpServers.includes(mcpServerUrl)) {
5644
+ return requirements;
5645
+ }
5646
+ return {
5647
+ ...requirements,
5648
+ mcpServers: [...existingMcpServers, mcpServerUrl],
5649
+ };
5650
+ }
5651
+ }
5652
+ /**
5653
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5654
+ */
5655
+
5656
+ /**
5657
+ * A search engine implementation that uses the SerpApi to fetch Google search results.
5658
+ *
5659
+ * @private <- TODO: !!!! Export via some package
5660
+ */
5661
+ class SerpSearchEngine {
5662
+ get title() {
5663
+ return 'SerpApi Search Engine';
5664
+ }
5665
+ get description() {
5666
+ return 'Search engine that uses SerpApi to fetch Google search results';
5667
+ }
5668
+ checkConfiguration() {
5669
+ if (!process.env.SERP_API_KEY) {
5670
+ throw new Error('SERP_API_KEY is not configured');
5671
+ }
5672
+ }
5673
+ async search(query, options = {}) {
5674
+ const apiKey = process.env.SERP_API_KEY;
5675
+ if (!apiKey) {
5676
+ throw new Error('SERP_API_KEY is not configured');
5677
+ }
5678
+ const url = new URL('https://serpapi.com/search');
5679
+ url.searchParams.set('api_key', apiKey);
5680
+ url.searchParams.set('engine', 'google');
5681
+ url.searchParams.set('q', query);
5682
+ for (const [key, value] of Object.entries(options)) {
5683
+ url.searchParams.set(key, String(value));
5684
+ }
5685
+ const response = await fetch(url.toString());
5686
+ if (!response.ok) {
5687
+ const body = await response.text();
5688
+ throw new Error(`SerpApi failed with status ${response.status}: ${response.statusText}\n${body}`);
5689
+ }
5690
+ const data = (await response.json());
5691
+ return (data.organic_results || []).map((item) => ({
5692
+ title: item.title,
5693
+ url: item.link,
5694
+ snippet: item.snippet || '',
5695
+ }));
5696
+ }
5697
+ }
5698
+
5699
+ /**
5700
+ * USE SEARCH ENGINE commitment definition
5701
+ *
5702
+ * The `USE SEARCH ENGINE` commitment indicates that the agent should utilize a search engine tool
5703
+ * to access and retrieve up-to-date information from the internet when necessary.
5704
+ *
5705
+ * The content following `USE SEARCH ENGINE` is an arbitrary text that the agent should know (e.g. search scope or instructions).
5706
+ *
5707
+ * Example usage in agent source:
5708
+ *
5709
+ * ```book
5710
+ * USE SEARCH ENGINE
5711
+ * USE SEARCH ENGINE Hledej informace o Přemyslovcích
5712
+ * ```
5713
+ *
5714
+ * @private [🪔] Maybe export the commitments through some package
5715
+ */
5716
+ class UseSearchEngineCommitmentDefinition extends BaseCommitmentDefinition {
5717
+ constructor() {
5718
+ super('USE SEARCH ENGINE', ['USE SEARCH']);
5719
+ }
5720
+ /**
5721
+ * Short one-line description of USE SEARCH ENGINE.
5722
+ */
5723
+ get description() {
5724
+ return 'Enable the agent to use a search engine tool for accessing internet information.';
5725
+ }
5726
+ /**
5727
+ * Icon for this commitment.
5728
+ */
5729
+ get icon() {
5730
+ return '🔍';
5731
+ }
5732
+ /**
5733
+ * Markdown documentation for USE SEARCH ENGINE commitment.
5734
+ */
5735
+ get documentation() {
5736
+ return spaceTrim$1(`
5737
+ # USE SEARCH ENGINE
5738
+
5739
+ Enables the agent to use a search engine tool to access and retrieve up-to-date information from the internet.
5740
+
5741
+ ## Key aspects
5742
+
5743
+ - The content following \`USE SEARCH ENGINE\` is an arbitrary text that the agent should know (e.g. search scope or instructions).
5744
+ - The actual search engine tool usage is handled by the agent runtime
5745
+ - Allows the agent to search for current information from the web
5746
+ - Useful for research tasks, finding facts, and accessing dynamic content
5747
+
5748
+ ## Examples
5749
+
5750
+ \`\`\`book
5751
+ Research Assistant
5752
+
5753
+ PERSONA You are a helpful research assistant specialized in finding current information
5754
+ USE SEARCH ENGINE
5755
+ RULE Always cite your sources when providing information from the web
5756
+ \`\`\`
5757
+
5758
+ \`\`\`book
5759
+ Fact Checker
5760
+
5761
+ PERSONA You are a fact checker
5762
+ USE SEARCH ENGINE
5763
+ ACTION Search for claims and verify them against reliable sources
5764
+ \`\`\`
5765
+ `);
5766
+ }
5767
+ applyToAgentModelRequirements(requirements, content) {
5768
+ // Get existing tools array or create new one
5769
+ const existingTools = requirements.tools || [];
5770
+ // Add 'web_search' to tools if not already present
5771
+ const updatedTools = existingTools.some((tool) => tool.name === 'web_search')
5772
+ ? existingTools
5773
+ : [
5774
+ ...existingTools,
5775
+ {
5776
+ name: 'web_search',
5777
+ description: spaceTrim$1(`
5778
+ Search the internet for information.
5779
+ Use this tool when you need to find up-to-date information or facts that you don't know.
5780
+ ${!content ? '' : `Search scope / instructions: ${content}`}
5781
+ `),
5782
+ parameters: {
5783
+ type: 'object',
5784
+ properties: {
5785
+ query: {
5786
+ type: 'string',
5787
+ description: 'The search query',
5788
+ },
5789
+ location: {
5790
+ type: 'string',
5791
+ description: 'The location for the search (e.g., "Austin, Texas, United States" or "Prague, Czechia")',
5792
+ },
5793
+ gl: {
5794
+ type: 'string',
5795
+ description: 'The country code (e.g., "us" for United States, "cz" for Czechia)',
5796
+ },
5797
+ hl: {
5798
+ type: 'string',
5799
+ description: 'The language code (e.g., "en" for English, "cs" for Czech)',
5800
+ },
5801
+ num: {
5802
+ type: 'integer',
5803
+ description: 'Number of results to return',
5804
+ },
5805
+ engine: {
5806
+ type: 'string',
5807
+ description: 'The search engine to use (e.g., "google", "bing", "yahoo", "baidu")',
5808
+ },
5809
+ google_domain: {
5810
+ type: 'string',
5811
+ description: 'The Google domain to use (e.g., "google.com", "google.cz")',
5812
+ },
5813
+ },
5814
+ required: ['query'],
5815
+ },
5816
+ },
5817
+ ];
5818
+ // Return requirements with updated tools and metadata
5819
+ return this.appendToSystemMessage({
5820
+ ...requirements,
5821
+ tools: updatedTools,
5822
+ metadata: {
5823
+ ...requirements.metadata,
5824
+ useSearchEngine: content || true,
5825
+ },
5826
+ }, spaceTrim$1(`
5827
+ You have access to the web search engine. Use it to find up-to-date information or facts that you don't know.
5828
+ When you need to know some information from the internet, use the tool provided to you.
5829
+ `));
5830
+ }
5831
+ /**
5832
+ * Gets human-readable titles for tool functions provided by this commitment.
5833
+ */
5834
+ getToolTitles() {
5835
+ return {
5836
+ web_search: 'Web search',
5837
+ };
5838
+ }
5839
+ /**
5840
+ * Gets the `web_search` tool function implementation.
5841
+ */
5842
+ getToolFunctions() {
5843
+ return {
5844
+ async web_search(args) {
5845
+ console.log('!!!! [Tool] web_search called', { args });
5846
+ const { query, ...options } = args;
5847
+ if (!query) {
5848
+ throw new Error('Search query is required');
5849
+ }
5850
+ const searchEngine = new SerpSearchEngine();
5851
+ const results = await searchEngine.search(query, options);
5852
+ return spaceTrim$1((block) => `
5853
+ Search results for "${query}"${Object.keys(options).length === 0
5854
+ ? ''
5855
+ : ` with options ${JSON.stringify(options)}`}:
5856
+
5857
+ ${block(results
5858
+ .map((result) => spaceTrim$1(`
5859
+ - **${result.title}**
5860
+ ${result.url}
5861
+ ${result.snippet}
5862
+ `))
5863
+ .join('\n\n'))}
5864
+ `);
5865
+ },
5866
+ };
5867
+ }
5868
+ }
5869
+ /**
5870
+ * Note: [💞] Ignore a discrepancy between file name and entity name
5871
+ */
5872
+
5873
+ /**
5874
+ * USE TIME commitment definition
5875
+ *
5876
+ * The `USE TIME` commitment indicates that the agent should be able to determine the current date and time.
5877
+ *
5878
+ * Example usage in agent source:
5879
+ *
5880
+ * ```book
5881
+ * USE TIME
5882
+ * ```
5883
+ *
5884
+ * @private [🪔] Maybe export the commitments through some package
5885
+ */
5886
+ class UseTimeCommitmentDefinition extends BaseCommitmentDefinition {
5887
+ constructor() {
5888
+ super('USE TIME', ['CURRENT TIME', 'TIME', 'DATE']);
5889
+ }
5890
+ /**
5891
+ * Short one-line description of USE TIME.
5892
+ */
5893
+ get description() {
5894
+ return 'Enable the agent to determine the current date and time.';
5895
+ }
5896
+ /**
5897
+ * Icon for this commitment.
5898
+ */
5899
+ get icon() {
5900
+ return '🕒';
5901
+ }
5902
+ /**
5903
+ * Markdown documentation for USE TIME commitment.
5904
+ */
5905
+ get documentation() {
5906
+ return spaceTrim$1(`
5907
+ # USE TIME
5908
+
5909
+ Enables the agent to determine the current date and time.
5910
+
5911
+ ## Key aspects
5912
+
5913
+ - This tool won't receive any input.
5914
+ - It outputs the current date and time as an ISO 8601 string.
5915
+ - Allows the agent to answer questions about the current time or date.
5916
+
5917
+ ## Examples
5918
+
5919
+ \`\`\`book
5920
+ Time-aware Assistant
5921
+
5922
+ PERSONA You are a helpful assistant who knows the current time.
5923
+ USE TIME
5924
+ \`\`\`
5925
+ `);
5926
+ }
5927
+ applyToAgentModelRequirements(requirements, content) {
5928
+ // Get existing tools array or create new one
5929
+ const existingTools = requirements.tools || [];
5930
+ // Add 'get_current_time' to tools if not already present
5931
+ const updatedTools = existingTools.some((tool) => tool.name === 'get_current_time')
5932
+ ? existingTools
5933
+ : [
5934
+ ...existingTools,
5935
+ {
5936
+ name: 'get_current_time',
5937
+ description: 'Get the current date and time in ISO 8601 format.',
5938
+ parameters: {
5939
+ type: 'object',
5940
+ properties: {
5941
+ timezone: {
5942
+ type: 'string',
5943
+ description: 'Optional timezone name (e.g. "Europe/Prague", "UTC", "America/New_York").',
5944
+ },
5945
+ },
5946
+ required: [],
5947
+ },
5948
+ },
5949
+ // <- TODO: !!!! define the function in LLM tools
5950
+ ];
5951
+ // Return requirements with updated tools and metadata
5952
+ return this.appendToSystemMessage({
5953
+ ...requirements,
5954
+ tools: updatedTools,
5955
+ metadata: {
5956
+ ...requirements.metadata,
5957
+ },
5958
+ }, spaceTrim$1(`
5959
+ You have access to the current date and time. Use it to answer questions about the current date and time.
5960
+ When you need to know the current date or time, use the tool provided to you.
5961
+ `));
5962
+ }
5963
+ /**
5964
+ * Gets human-readable titles for tool functions provided by this commitment.
5965
+ */
5966
+ getToolTitles() {
5967
+ return {
5968
+ get_current_time: 'Get current time',
5969
+ };
5970
+ }
5971
+ /**
5972
+ * Gets the `get_current_time` tool function implementation.
5973
+ */
5974
+ getToolFunctions() {
5975
+ return {
5976
+ async get_current_time(args) {
5977
+ var _a;
5978
+ console.log('!!!! [Tool] get_current_time called', { args });
5979
+ const { timezone } = args;
5980
+ if (!timezone) {
5981
+ return new Date().toISOString();
5982
+ }
5983
+ try {
5984
+ // Note: Returning ISO 8601 string but in the requested timezone
5985
+ const formatter = new Intl.DateTimeFormat('en-CA', {
5986
+ timeZone: timezone,
5987
+ year: 'numeric',
5988
+ month: '2-digit',
5989
+ day: '2-digit',
5990
+ hour: '2-digit',
5991
+ minute: '2-digit',
5992
+ second: '2-digit',
5993
+ hour12: false,
5994
+ timeZoneName: 'shortOffset',
5995
+ });
5996
+ const parts = formatter.formatToParts(new Date());
5997
+ const part = (type) => { var _a; return (_a = parts.find((p) => p.type === type)) === null || _a === void 0 ? void 0 : _a.value; };
5998
+ // en-CA format is YYYY-MM-DD
5999
+ const isoString = `${part('year')}-${part('month')}-${part('day')}T${part('hour')}:${part('minute')}:${part('second')}${(_a = part('timeZoneName')) === null || _a === void 0 ? void 0 : _a.replace('GMT', '')}`;
6000
+ return isoString;
6001
+ }
6002
+ catch (error) {
6003
+ // Fallback to UTC if timezone is invalid
6004
+ return new Date().toISOString();
6005
+ }
6006
+ },
6007
+ };
6008
+ }
6009
+ }
6010
+ /**
6011
+ * Note: [💞] Ignore a discrepancy between file name and entity name
6012
+ */
6013
+
6014
+ /**
6015
+ * Placeholder commitment definition for commitments that are not yet implemented
6016
+ *
6017
+ * This commitment simply adds its content 1:1 into the system message,
6018
+ * preserving the original behavior until proper implementation is added.
6019
+ *
6020
+ * @public exported from `@promptbook/core`
6021
+ */
6022
+ class NotYetImplementedCommitmentDefinition extends BaseCommitmentDefinition {
6023
+ constructor(type) {
6024
+ super(type);
6025
+ }
6026
+ /**
6027
+ * Short one-line description of a placeholder commitment.
6028
+ */
6029
+ get description() {
6030
+ return 'Placeholder commitment that appends content verbatim to the system message.';
6031
+ }
6032
+ /**
6033
+ * Icon for this commitment.
6034
+ */
6035
+ get icon() {
6036
+ return '🚧';
6037
+ }
6038
+ /**
6039
+ * Markdown documentation available at runtime.
6040
+ */
6041
+ get documentation() {
6042
+ return spaceTrim$1(`
6043
+ # ${this.type}
6044
+
6045
+ This commitment is not yet fully implemented.
6046
+
6047
+ ## Key aspects
6048
+
6049
+ - Content is appended directly to the system message.
6050
+ - No special processing or validation is performed.
6051
+ - Behavior preserved until proper implementation is added.
6052
+
6053
+ ## Status
6054
+
6055
+ - **Status:** Placeholder implementation
6056
+ - **Effect:** Appends content prefixed by commitment type
6057
+ - **Future:** Will be replaced with specialized logic
6058
+
6059
+ ## Examples
6060
+
6061
+ \`\`\`book
6062
+ Example Agent
6063
+
6064
+ PERSONA You are a helpful assistant
6065
+ ${this.type} Your content here
6066
+ RULE Always be helpful
6067
+ \`\`\`
6068
+ `);
6069
+ }
6070
+ applyToAgentModelRequirements(requirements, content) {
6071
+ const trimmedContent = content.trim();
6072
+ if (!trimmedContent) {
6073
+ return requirements;
6074
+ }
6075
+ // Add the commitment content 1:1 to the system message
6076
+ const commitmentLine = `${this.type} ${trimmedContent}`;
6077
+ return this.appendToSystemMessage(requirements, commitmentLine, '\n\n');
6078
+ }
6079
+ }
6080
+
6081
+ /**
6082
+ * Registry of all available commitment definitions
6083
+ * This array contains instances of all commitment definitions
6084
+ * This is the single source of truth for all commitments in the system
6085
+ *
6086
+ * @private Use functions to access commitments instead of this array directly
6087
+ */
6088
+ const COMMITMENT_REGISTRY = [
6089
+ // Fully implemented commitments
6090
+ new PersonaCommitmentDefinition('PERSONA'),
6091
+ new PersonaCommitmentDefinition('PERSONAE'),
6092
+ new KnowledgeCommitmentDefinition(),
6093
+ new MemoryCommitmentDefinition('MEMORY'),
6094
+ new MemoryCommitmentDefinition('MEMORIES'),
6095
+ new StyleCommitmentDefinition('STYLE'),
6096
+ new StyleCommitmentDefinition('STYLES'),
6097
+ new RuleCommitmentDefinition('RULES'),
6098
+ new RuleCommitmentDefinition('RULE'),
6099
+ new LanguageCommitmentDefinition('LANGUAGES'),
6100
+ new LanguageCommitmentDefinition('LANGUAGE'),
6101
+ new SampleCommitmentDefinition('SAMPLE'),
6102
+ new SampleCommitmentDefinition('EXAMPLE'),
6103
+ new FormatCommitmentDefinition('FORMAT'),
6104
+ new FormatCommitmentDefinition('FORMATS'),
6105
+ new FromCommitmentDefinition('FROM'),
6106
+ new ImportCommitmentDefinition('IMPORT'),
6107
+ new ImportCommitmentDefinition('IMPORTS'),
6108
+ new ModelCommitmentDefinition('MODEL'),
6109
+ new ModelCommitmentDefinition('MODELS'),
6110
+ new ActionCommitmentDefinition('ACTION'),
6111
+ new ActionCommitmentDefinition('ACTIONS'),
6112
+ new ComponentCommitmentDefinition(),
6113
+ new MetaImageCommitmentDefinition(),
6114
+ new MetaColorCommitmentDefinition(),
6115
+ new MetaFontCommitmentDefinition(),
6116
+ new MetaLinkCommitmentDefinition(),
6117
+ new MetaCommitmentDefinition(),
6118
+ new NoteCommitmentDefinition('NOTE'),
6119
+ new NoteCommitmentDefinition('NOTES'),
6120
+ new NoteCommitmentDefinition('COMMENT'),
6121
+ new NoteCommitmentDefinition('NONCE'),
6122
+ new NoteCommitmentDefinition('TODO'),
6123
+ new GoalCommitmentDefinition('GOAL'),
6124
+ new GoalCommitmentDefinition('GOALS'),
6125
+ new InitialMessageCommitmentDefinition(),
6126
+ new UserMessageCommitmentDefinition(),
6127
+ new AgentMessageCommitmentDefinition(),
6128
+ new MessageCommitmentDefinition('MESSAGE'),
6129
+ new MessageCommitmentDefinition('MESSAGES'),
6130
+ new ScenarioCommitmentDefinition('SCENARIO'),
6131
+ new ScenarioCommitmentDefinition('SCENARIOS'),
6132
+ new DeleteCommitmentDefinition('DELETE'),
6133
+ new DeleteCommitmentDefinition('CANCEL'),
6134
+ new DeleteCommitmentDefinition('DISCARD'),
6135
+ new DeleteCommitmentDefinition('REMOVE'),
6136
+ new DictionaryCommitmentDefinition(),
6137
+ new OpenCommitmentDefinition(),
6138
+ new ClosedCommitmentDefinition(),
6139
+ new UseBrowserCommitmentDefinition(),
6140
+ new UseSearchEngineCommitmentDefinition(),
6141
+ new UseTimeCommitmentDefinition(),
6142
+ new UseMcpCommitmentDefinition(),
6143
+ new UseCommitmentDefinition(),
6144
+ // Not yet implemented commitments (using placeholder)
6145
+ new NotYetImplementedCommitmentDefinition('EXPECT'),
6146
+ new NotYetImplementedCommitmentDefinition('BEHAVIOUR'),
6147
+ new NotYetImplementedCommitmentDefinition('BEHAVIOURS'),
6148
+ new NotYetImplementedCommitmentDefinition('AVOID'),
6149
+ new NotYetImplementedCommitmentDefinition('AVOIDANCE'),
6150
+ new NotYetImplementedCommitmentDefinition('CONTEXT'),
6151
+ // <- TODO: Prompt: Leverage aliases instead of duplicating commitment definitions
6152
+ ];
6153
+ /**
6154
+ * Gets all available commitment definitions
6155
+ * @returns Array of all commitment definitions
6156
+ *
6157
+ * @public exported from `@promptbook/core`
6158
+ */
6159
+ function getAllCommitmentDefinitions() {
6160
+ return $deepFreeze([...COMMITMENT_REGISTRY]);
6161
+ }
6162
+ /**
6163
+ * Gets all function implementations provided by all commitments
6164
+ *
6165
+ * @public exported from `@promptbook/core`
6166
+ */
6167
+ function getAllCommitmentsToolFunctions() {
6168
+ const allToolFunctions = {};
6169
+ for (const commitmentDefinition of getAllCommitmentDefinitions()) {
6170
+ const toolFunctions = commitmentDefinition.getToolFunctions();
6171
+ for (const [funcName, funcImpl] of Object.entries(toolFunctions)) {
6172
+ allToolFunctions[funcName] = funcImpl;
6173
+ }
6174
+ }
6175
+ return allToolFunctions;
6176
+ }
6177
+ /**
6178
+ * TODO: [🧠] Maybe create through standardized $register
6179
+ * Note: [💞] Ignore a discrepancy between file name and entity name
6180
+ */
6181
+
6182
+ /**
6183
+ * Extracts all code blocks from markdown.
6184
+ *
6185
+ * Note: There are multiple similar functions:
6186
+ * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
6187
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
6188
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
6189
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
6190
+ *
6191
+ * @param markdown any valid markdown
6192
+ * @returns code blocks with language and content
6193
+ * @throws {ParseError} if block is not closed properly
6194
+ * @public exported from `@promptbook/markdown-utils`
6195
+ */
6196
+ function extractAllBlocksFromMarkdown(markdown) {
6197
+ const codeBlocks = [];
6198
+ const lines = markdown.split('\n');
6199
+ // Note: [0] Ensure that the last block notated by gt > will be closed
6200
+ lines.push('');
6201
+ let currentCodeBlock = null;
6202
+ for (const line of lines) {
6203
+ if (line.startsWith('> ') || line === '>') {
6204
+ if (currentCodeBlock === null) {
6205
+ currentCodeBlock = { blockNotation: '>', language: null, content: '' };
6206
+ } /* not else */
6207
+ if (currentCodeBlock.blockNotation === '>') {
6208
+ if (currentCodeBlock.content !== '') {
6209
+ currentCodeBlock.content += '\n';
6210
+ }
6211
+ currentCodeBlock.content += line.slice(2);
6212
+ }
6213
+ }
6214
+ else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '>' /* <- Note: [0] */) {
6215
+ codeBlocks.push(currentCodeBlock);
6216
+ currentCodeBlock = null;
6217
+ }
6218
+ /* not else */
6219
+ if (line.startsWith('```')) {
6220
+ const language = line.slice(3).trim() || null;
6221
+ if (currentCodeBlock === null) {
6222
+ currentCodeBlock = { blockNotation: '```', language, content: '' };
6223
+ }
6224
+ else {
6225
+ if (language !== null) {
6226
+ throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed and already opening new ${language} code block`);
6227
+ }
6228
+ codeBlocks.push(currentCodeBlock);
6229
+ currentCodeBlock = null;
6230
+ }
6231
+ }
6232
+ else if (currentCodeBlock !== null && currentCodeBlock.blockNotation === '```') {
6233
+ if (currentCodeBlock.content !== '') {
6234
+ currentCodeBlock.content += '\n';
6235
+ }
6236
+ currentCodeBlock.content += line.split('\\`\\`\\`').join('```') /* <- TODO: Maybe make proper unescape */;
6237
+ }
6238
+ }
6239
+ if (currentCodeBlock !== null) {
6240
+ throw new ParseError(`${capitalize(currentCodeBlock.language || 'the')} code block was not closed at the end of the markdown`);
6241
+ }
6242
+ return codeBlocks;
6243
+ }
6244
+ /**
6245
+ * TODO: Maybe name for `blockNotation` instead of '```' and '>'
6246
+ */
6247
+
6248
+ /**
6249
+ * Extracts exactly ONE code block from markdown.
6250
+ *
6251
+ * - When there are multiple or no code blocks the function throws a `ParseError`
6252
+ *
6253
+ * Note: There are multiple similar functions:
6254
+ * - `extractBlock` just extracts the content of the code block which is also used as built-in function for postprocessing
6255
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
6256
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
6257
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
6258
+ *
6259
+ * @param markdown any valid markdown
6260
+ * @returns code block with language and content
6261
+ * @public exported from `@promptbook/markdown-utils`
6262
+ * @throws {ParseError} if there is not exactly one code block in the markdown
6263
+ */
6264
+ function extractOneBlockFromMarkdown(markdown) {
6265
+ const codeBlocks = extractAllBlocksFromMarkdown(markdown);
6266
+ if (codeBlocks.length !== 1) {
6267
+ throw new ParseError(spaceTrim$2((block) => `
6268
+ There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
6269
+
6270
+ ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
6271
+ `));
6272
+ }
6273
+ return codeBlocks[0];
6274
+ }
6275
+ /***
6276
+ * TODO: [🍓][🌻] Decide of this is internal utility, external util OR validator/postprocessor
6277
+ */
6278
+
6279
+ /**
6280
+ * Extracts code block from markdown.
6281
+ *
6282
+ * - When there are multiple or no code blocks the function throws a `ParseError`
6283
+ *
6284
+ * Note: There are multiple similar function:
6285
+ * - `extractBlock` just extracts the content of the code block which is also used as build-in function for postprocessing
6286
+ * - `extractJsonBlock` extracts exactly one valid JSON code block
6287
+ * - `extractOneBlockFromMarkdown` extracts exactly one code block with language of the code block
6288
+ * - `extractAllBlocksFromMarkdown` extracts all code blocks with language of the code block
6289
+ *
6290
+ * @public exported from `@promptbook/markdown-utils`
6291
+ * @throws {ParseError} if there is not exactly one code block in the markdown
6292
+ */
6293
+ function extractBlock(markdown) {
6294
+ const { content } = extractOneBlockFromMarkdown(markdown);
6295
+ return content;
6296
+ }
6297
+
6298
+ /**
6299
+ * Prettify the html code
6300
+ *
6301
+ * @param content raw html code
6302
+ * @returns formatted html code
6303
+ * @private withing the package because of HUGE size of prettier dependency
6304
+ * @deprecated Prettier removed from Promptbook due to package size
6305
+ */
6306
+ function prettifyMarkdown(content) {
6307
+ return (content + `\n\n<!-- Note: Prettier removed from Promptbook -->`);
6308
+ }
6309
+
6310
+ /**
6311
+ * Function trimCodeBlock will trim starting and ending code block from the string if it is present.
6312
+ *
6313
+ * Note: [🔂] This function is idempotent.
6314
+ * Note: This is useful for post-processing of the result of the chat LLM model
6315
+ * when the model wraps the result in the (markdown) code block.
6316
+ *
6317
+ * @public exported from `@promptbook/markdown-utils`
6318
+ */
6319
+ function trimCodeBlock(value) {
6320
+ value = spaceTrim$1(value);
6321
+ if (!/^```[a-z]*(.*)```$/is.test(value)) {
6322
+ return value;
6323
+ }
6324
+ value = value.replace(/^```[a-z]*/i, '');
6325
+ value = value.replace(/```$/i, '');
6326
+ value = spaceTrim$1(value);
6327
+ return value;
6328
+ }
6329
+
6330
+ /**
6331
+ * Function trimEndOfCodeBlock will remove ending code block from the string if it is present.
6332
+ *
6333
+ * Note: This is useful for post-processing of the result of the completion LLM model
6334
+ * if you want to start code block in the prompt but you don't want to end it in the result.
6335
+ *
6336
+ * @public exported from `@promptbook/markdown-utils`
6337
+ */
6338
+ function trimEndOfCodeBlock(value) {
6339
+ value = spaceTrim$1(value);
6340
+ value = value.replace(/```$/g, '');
6341
+ value = spaceTrim$1(value);
6342
+ return value;
6343
+ }
6344
+
6345
+ /**
6346
+ * @private internal for `preserve`
6347
+ */
6348
+ const _preserved = [];
6349
+ /**
6350
+ * Does nothing, but preserves the function in the bundle
6351
+ * Compiler is tricked into thinking the function is used
6352
+ *
6353
+ * @param value any function to preserve
6354
+ * @returns nothing
6355
+ * @private within the repository
6356
+ */
6357
+ function $preserve(...value) {
6358
+ _preserved.push(...value);
6359
+ }
6360
+ /**
6361
+ * Note: [💞] Ignore a discrepancy between file name and entity name
6362
+ */
6363
+
6364
+ // Note: [💎]
6365
+ /**
6366
+ * ScriptExecutionTools for JavaScript implemented via eval
6367
+ *
6368
+ * Warning: It is used for testing and mocking
6369
+ * **NOT intended to use in the production** due to its unsafe nature, use `JavascriptExecutionTools` instead.
6370
+ *
6371
+ * @public exported from `@promptbook/javascript`
6372
+ */
2400
6373
  class JavascriptEvalExecutionTools {
2401
6374
  constructor(options) {
2402
6375
  this.options = options || {};
@@ -2495,6 +6468,13 @@ class JavascriptEvalExecutionTools {
2495
6468
  `const ${functionName} = buildinFunctions.${functionName};`)
2496
6469
  .join('\n');
2497
6470
  // TODO: DRY [🍯]
6471
+ const commitmentsFunctions = getAllCommitmentsToolFunctions();
6472
+ const commitmentsFunctionsStatement = Object.keys(commitmentsFunctions)
6473
+ .map((functionName) =>
6474
+ // Note: Custom functions are exposed to the current scope as variables
6475
+ `const ${functionName} = commitmentsFunctions.${functionName};`)
6476
+ .join('\n');
6477
+ // TODO: DRY [🍯]
2498
6478
  const customFunctions = this.options.functions || {};
2499
6479
  const customFunctionsStatement = Object.keys(customFunctions)
2500
6480
  .map((functionName) =>
@@ -2508,6 +6488,10 @@ class JavascriptEvalExecutionTools {
2508
6488
  // Build-in functions:
2509
6489
  ${block(buildinFunctionsStatement)}
2510
6490
 
6491
+ // Commitments functions:
6492
+ ${block(commitmentsFunctionsStatement)}
6493
+
6494
+
2511
6495
  // Custom functions:
2512
6496
  ${block(customFunctionsStatement || '// -- No custom functions --')}
2513
6497
 
@@ -2515,7 +6499,7 @@ class JavascriptEvalExecutionTools {
2515
6499
  ${block(Object.entries(parameters)
2516
6500
  .map(([key, value]) => `const ${key} = ${JSON.stringify(value)};`)
2517
6501
  .join('\n'))}
2518
- (()=>{ ${script} })()
6502
+ (async ()=>{ ${script} })()
2519
6503
  `);
2520
6504
  if (this.options.isVerbose) {
2521
6505
  console.info(spaceTrim$2((block) => `