@promptbook/node 0.112.0-56 → 0.112.0-57

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 (37) hide show
  1. package/esm/index.es.js +990 -1005
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/ParsedAgentSourceWithCommitments.d.ts +7 -0
  4. package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/applyCommitmentsToAgentModelRequirements.d.ts +14 -0
  5. package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.d.ts +14 -0
  6. package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/filterCommitmentsForAgentModelRequirements.d.ts +10 -0
  7. package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/materializeInlineKnowledgeSources.d.ts +12 -0
  8. package/esm/src/book-2.0/agent-source/parseAgentSource/ParseAgentSourceState.d.ts +10 -0
  9. package/esm/src/book-2.0/agent-source/parseAgentSource/ParsedAgentProfile.d.ts +7 -0
  10. package/esm/src/book-2.0/agent-source/parseAgentSource/applyMetaCommitment.d.ts +8 -0
  11. package/esm/src/book-2.0/agent-source/parseAgentSource/consumeConversationSampleCommitment.d.ts +8 -0
  12. package/esm/src/book-2.0/agent-source/parseAgentSource/createCapabilitiesFromCommitment.d.ts +9 -0
  13. package/esm/src/book-2.0/agent-source/parseAgentSource/ensureMetaFullname.d.ts +7 -0
  14. package/esm/src/book-2.0/agent-source/parseAgentSource/extractAgentProfileText.d.ts +8 -0
  15. package/esm/src/book-2.0/agent-source/parseAgentSource/extractInitialMessage.d.ts +7 -0
  16. package/esm/src/book-2.0/agent-source/parseAgentSource/extractParsedAgentProfile.d.ts +8 -0
  17. package/esm/src/types/LlmToolDefinition.d.ts +17 -7
  18. package/esm/src/version.d.ts +1 -1
  19. package/package.json +2 -2
  20. package/umd/index.umd.js +990 -1005
  21. package/umd/index.umd.js.map +1 -1
  22. package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/ParsedAgentSourceWithCommitments.d.ts +7 -0
  23. package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/applyCommitmentsToAgentModelRequirements.d.ts +14 -0
  24. package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.d.ts +14 -0
  25. package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/filterCommitmentsForAgentModelRequirements.d.ts +10 -0
  26. package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/materializeInlineKnowledgeSources.d.ts +12 -0
  27. package/umd/src/book-2.0/agent-source/parseAgentSource/ParseAgentSourceState.d.ts +10 -0
  28. package/umd/src/book-2.0/agent-source/parseAgentSource/ParsedAgentProfile.d.ts +7 -0
  29. package/umd/src/book-2.0/agent-source/parseAgentSource/applyMetaCommitment.d.ts +8 -0
  30. package/umd/src/book-2.0/agent-source/parseAgentSource/consumeConversationSampleCommitment.d.ts +8 -0
  31. package/umd/src/book-2.0/agent-source/parseAgentSource/createCapabilitiesFromCommitment.d.ts +9 -0
  32. package/umd/src/book-2.0/agent-source/parseAgentSource/ensureMetaFullname.d.ts +7 -0
  33. package/umd/src/book-2.0/agent-source/parseAgentSource/extractAgentProfileText.d.ts +8 -0
  34. package/umd/src/book-2.0/agent-source/parseAgentSource/extractInitialMessage.d.ts +7 -0
  35. package/umd/src/book-2.0/agent-source/parseAgentSource/extractParsedAgentProfile.d.ts +8 -0
  36. package/umd/src/types/LlmToolDefinition.d.ts +17 -7
  37. package/umd/src/version.d.ts +1 -1
package/esm/index.es.js CHANGED
@@ -35,7 +35,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
35
35
  * @generated
36
36
  * @see https://github.com/webgptorg/promptbook
37
37
  */
38
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-56';
38
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-57';
39
39
  /**
40
40
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
41
41
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -24158,6 +24158,44 @@ function mapGoogleCalendarEvent(event) {
24158
24158
  * @private constant of createUseCalendarTools
24159
24159
  */
24160
24160
  const CALENDAR_URL_PARAMETER_DESCRIPTION = 'Google Calendar URL configured by USE CALENDAR (for example "https://calendar.google.com/...").';
24161
+ /**
24162
+ * Shared schema for string arrays used by USE CALENDAR tools.
24163
+ *
24164
+ * @private constant of createUseCalendarTools
24165
+ */
24166
+ const STRING_ARRAY_ITEMS_SCHEMA = {
24167
+ type: 'string',
24168
+ };
24169
+ /**
24170
+ * Shared schema for integer arrays used by USE CALENDAR tools.
24171
+ *
24172
+ * @private constant of createUseCalendarTools
24173
+ */
24174
+ const INTEGER_ARRAY_ITEMS_SCHEMA = {
24175
+ type: 'integer',
24176
+ };
24177
+ /**
24178
+ * Shared `sendUpdates` schema used by USE CALENDAR tools.
24179
+ *
24180
+ * @private constant of createUseCalendarTools
24181
+ */
24182
+ const SEND_UPDATES_PARAMETER_SCHEMA = {
24183
+ type: 'string',
24184
+ description: 'Guest update policy ("all", "externalOnly", "none").',
24185
+ enum: ['all', 'externalOnly', 'none'],
24186
+ };
24187
+ /**
24188
+ * Creates an array parameter schema with explicit item definition so OpenAI accepts it.
24189
+ *
24190
+ * @private function of createUseCalendarTools
24191
+ */
24192
+ function createArrayParameterSchema(description, items) {
24193
+ return {
24194
+ type: 'array',
24195
+ description,
24196
+ items,
24197
+ };
24198
+ }
24161
24199
  /**
24162
24200
  * Adds USE CALENDAR tool definitions while keeping already registered tools untouched.
24163
24201
  *
@@ -24264,18 +24302,9 @@ function createUseCalendarTools(existingTools) {
24264
24302
  type: 'string',
24265
24303
  description: 'Optional timezone for datetime values.',
24266
24304
  },
24267
- attendees: {
24268
- type: 'array',
24269
- description: 'Optional guest email list.',
24270
- },
24271
- reminderMinutes: {
24272
- type: 'array',
24273
- description: 'Optional popup reminder minute offsets.',
24274
- },
24275
- sendUpdates: {
24276
- type: 'string',
24277
- description: 'Guest update policy ("all", "externalOnly", "none").',
24278
- },
24305
+ attendees: createArrayParameterSchema('Optional guest email list.', STRING_ARRAY_ITEMS_SCHEMA),
24306
+ reminderMinutes: createArrayParameterSchema('Optional popup reminder minute offsets.', INTEGER_ARRAY_ITEMS_SCHEMA),
24307
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
24279
24308
  },
24280
24309
  required: ['summary', 'start', 'end'],
24281
24310
  },
@@ -24318,18 +24347,9 @@ function createUseCalendarTools(existingTools) {
24318
24347
  type: 'string',
24319
24348
  description: 'Optional timezone for datetime values.',
24320
24349
  },
24321
- attendees: {
24322
- type: 'array',
24323
- description: 'Optional replacement guest email list.',
24324
- },
24325
- reminderMinutes: {
24326
- type: 'array',
24327
- description: 'Optional replacement popup reminder minute offsets.',
24328
- },
24329
- sendUpdates: {
24330
- type: 'string',
24331
- description: 'Guest update policy ("all", "externalOnly", "none").',
24332
- },
24350
+ attendees: createArrayParameterSchema('Optional replacement guest email list.', STRING_ARRAY_ITEMS_SCHEMA),
24351
+ reminderMinutes: createArrayParameterSchema('Optional replacement popup reminder minute offsets.', INTEGER_ARRAY_ITEMS_SCHEMA),
24352
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
24333
24353
  },
24334
24354
  required: ['eventId'],
24335
24355
  },
@@ -24348,10 +24368,7 @@ function createUseCalendarTools(existingTools) {
24348
24368
  type: 'string',
24349
24369
  description: 'Google Calendar event id.',
24350
24370
  },
24351
- sendUpdates: {
24352
- type: 'string',
24353
- description: 'Guest update policy ("all", "externalOnly", "none").',
24354
- },
24371
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
24355
24372
  },
24356
24373
  required: ['eventId'],
24357
24374
  },
@@ -24370,14 +24387,8 @@ function createUseCalendarTools(existingTools) {
24370
24387
  type: 'string',
24371
24388
  description: 'Google Calendar event id.',
24372
24389
  },
24373
- guests: {
24374
- type: 'array',
24375
- description: 'Guest email list to add to the event.',
24376
- },
24377
- sendUpdates: {
24378
- type: 'string',
24379
- description: 'Guest update policy ("all", "externalOnly", "none").',
24380
- },
24390
+ guests: createArrayParameterSchema('Guest email list to add to the event.', STRING_ARRAY_ITEMS_SCHEMA),
24391
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
24381
24392
  },
24382
24393
  required: ['eventId', 'guests'],
24383
24394
  },
@@ -31330,6 +31341,297 @@ function createDefaultAgentName(agentSource) {
31330
31341
  return normalizeAgentName(`Agent ${agentHash.substring(0, LIMITS.SHORT_NAME_LENGTH)}`);
31331
31342
  }
31332
31343
 
31344
+ /**
31345
+ * Consumes the agent-name prelude from raw source.
31346
+ *
31347
+ * Leading whitespace-only lines are skipped. The first subsequent line that contains any
31348
+ * non-whitespace characters is always treated as plain-text agent name, even when it starts
31349
+ * with a commitment keyword or other book syntax.
31350
+ *
31351
+ * @param agentSource - Raw agent source.
31352
+ * @returns Parsed prelude with shared line metadata.
31353
+ *
31354
+ * @private internal utility of book agent-source parsing
31355
+ */
31356
+ function parseAgentSourcePrelude(agentSource) {
31357
+ const lines = agentSource.split(/\r?\n/);
31358
+ for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
31359
+ const line = lines[lineIndex];
31360
+ if (line === undefined) {
31361
+ continue;
31362
+ }
31363
+ const trimmedLine = line.trim();
31364
+ if (!trimmedLine) {
31365
+ continue;
31366
+ }
31367
+ return {
31368
+ lines,
31369
+ agentName: trimmedLine,
31370
+ agentNameLineIndex: lineIndex,
31371
+ agentNameLineNumber: lineIndex + 1,
31372
+ };
31373
+ }
31374
+ return {
31375
+ lines,
31376
+ agentName: null,
31377
+ agentNameLineIndex: -1,
31378
+ };
31379
+ }
31380
+
31381
+ /**
31382
+ * Regex pattern to match horizontal lines (markdown thematic breaks)
31383
+ * Matches 3 or more hyphens, underscores, or asterisks (with optional spaces between)
31384
+ */
31385
+ const HORIZONTAL_LINE_PATTERN$1 = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
31386
+ /**
31387
+ * Parses agent source using the new commitment system with multiline support
31388
+ * This function replaces the hardcoded commitment parsing in the original parseAgentSource
31389
+ *
31390
+ * The first non-empty line is always consumed as plain-text agent name. Commitment parsing
31391
+ * starts only after that title line has been fixed.
31392
+ *
31393
+ * @private internal utility of `parseAgentSource`
31394
+ */
31395
+ function parseAgentSourceWithCommitments(agentSource) {
31396
+ var _a, _b;
31397
+ if (!agentSource || !agentSource.trim()) {
31398
+ return {
31399
+ agentName: null,
31400
+ commitments: [],
31401
+ nonCommitmentLines: [],
31402
+ };
31403
+ }
31404
+ const { lines, agentName, agentNameLineIndex, agentNameLineNumber } = parseAgentSourcePrelude(agentSource);
31405
+ const commitments = [];
31406
+ const nonCommitmentLines = agentNameLineIndex >= 0 ? [lines[agentNameLineIndex]] : [];
31407
+ // Parse commitments with multiline support
31408
+ let currentCommitment = null;
31409
+ // Process lines starting from after the agent name line
31410
+ const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
31411
+ let isInsideCodeBlock = false;
31412
+ for (let i = startIndex; i < lines.length; i++) {
31413
+ const line = lines[i];
31414
+ if (line === undefined) {
31415
+ continue;
31416
+ }
31417
+ const trimmedLine = line.trim();
31418
+ // Check if this line starts or ends a code block
31419
+ if (trimmedLine.startsWith('```')) {
31420
+ isInsideCodeBlock = !isInsideCodeBlock;
31421
+ if (currentCommitment) {
31422
+ // If we are inside a commitment, the code block is part of it
31423
+ currentCommitment.contentLines.push(line);
31424
+ }
31425
+ else {
31426
+ // If we are not inside a commitment, the code block is non-commitment
31427
+ nonCommitmentLines.push(line);
31428
+ }
31429
+ continue;
31430
+ }
31431
+ if (isInsideCodeBlock) {
31432
+ if (currentCommitment) {
31433
+ // If we are inside a commitment and a code block, the line is part of the commitment
31434
+ currentCommitment.contentLines.push(line);
31435
+ }
31436
+ else {
31437
+ // If we are inside a code block but not a commitment, the line is non-commitment
31438
+ nonCommitmentLines.push(line);
31439
+ }
31440
+ continue;
31441
+ }
31442
+ // Check if this line starts a new commitment
31443
+ let foundNewCommitment = false;
31444
+ for (const definition of COMMITMENT_REGISTRY) {
31445
+ const typeRegex = definition.createTypeRegex();
31446
+ const match = typeRegex.exec(line.trim());
31447
+ if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
31448
+ // Save the previous commitment if it exists
31449
+ if (currentCommitment) {
31450
+ const fullContent = currentCommitment.contentLines.join('\n');
31451
+ commitments.push({
31452
+ type: currentCommitment.type,
31453
+ content: spaceTrim$1(fullContent),
31454
+ originalLine: currentCommitment.originalStartLine,
31455
+ lineNumber: currentCommitment.startLineNumber,
31456
+ });
31457
+ }
31458
+ // Extract the initial content from the commitment line
31459
+ const fullRegex = definition.createRegex();
31460
+ const fullMatch = fullRegex.exec(line.trim());
31461
+ const initialContent = ((_b = fullMatch === null || fullMatch === void 0 ? void 0 : fullMatch.groups) === null || _b === void 0 ? void 0 : _b.contents) || '';
31462
+ // Start a new commitment
31463
+ currentCommitment = {
31464
+ type: definition.type,
31465
+ startLineNumber: i + 1,
31466
+ originalStartLine: line,
31467
+ contentLines: initialContent ? [initialContent] : [],
31468
+ };
31469
+ foundNewCommitment = true;
31470
+ break;
31471
+ }
31472
+ }
31473
+ // Check if this is a horizontal line (ends any current commitment)
31474
+ const isHorizontalLine = HORIZONTAL_LINE_PATTERN$1.test(line);
31475
+ if (isHorizontalLine) {
31476
+ // Save the current commitment if it exists
31477
+ if (currentCommitment) {
31478
+ const fullContent = currentCommitment.contentLines.join('\n');
31479
+ commitments.push({
31480
+ type: currentCommitment.type,
31481
+ content: spaceTrim$1(fullContent),
31482
+ originalLine: currentCommitment.originalStartLine,
31483
+ lineNumber: currentCommitment.startLineNumber,
31484
+ });
31485
+ currentCommitment = null;
31486
+ }
31487
+ // Add horizontal line to non-commitment lines
31488
+ nonCommitmentLines.push(line);
31489
+ continue;
31490
+ }
31491
+ if (!foundNewCommitment) {
31492
+ if (currentCommitment) {
31493
+ // This line belongs to the current commitment
31494
+ currentCommitment.contentLines.push(line);
31495
+ }
31496
+ else {
31497
+ // This line is not part of any commitment
31498
+ nonCommitmentLines.push(line);
31499
+ }
31500
+ }
31501
+ }
31502
+ // Don't forget to save the last commitment if it exists
31503
+ if (currentCommitment) {
31504
+ const fullContent = currentCommitment.contentLines.join('\n');
31505
+ commitments.push({
31506
+ type: currentCommitment.type,
31507
+ content: spaceTrim$1(fullContent),
31508
+ originalLine: currentCommitment.originalStartLine,
31509
+ lineNumber: currentCommitment.startLineNumber,
31510
+ });
31511
+ }
31512
+ return {
31513
+ agentName,
31514
+ agentNameLineNumber,
31515
+ commitments,
31516
+ nonCommitmentLines,
31517
+ };
31518
+ }
31519
+
31520
+ /**
31521
+ * Parses parameters from text using both supported notations:
31522
+ * 1. @Parameter - single word parameter starting with @
31523
+ * 2. {parameterName} or {parameter with multiple words} or {parameterName: description text}
31524
+ *
31525
+ * Both notations represent the same syntax feature - parameters
31526
+ *
31527
+ * @param text - Text to extract parameters from
31528
+ * @returns Array of parsed parameters with unified representation
31529
+ *
31530
+ * @public exported from `@promptbook/core`
31531
+ */
31532
+ function parseParameters(text) {
31533
+ const parameters = [];
31534
+ // [🧠] Parameter syntax parsing - unified approach for two different notations of the same syntax feature
31535
+ // The Book language supports parameters in two different notations but they represent the same concept
31536
+ // Extract @Parameter notation (single word parameters starting with @)
31537
+ const atParameterRegex = /@[\w\u00C0-\u017F\u0100-\u024F\u1E00-\u1EFF]+/gim;
31538
+ text.replace(atParameterRegex, (match) => {
31539
+ const parameterName = match.slice(1); // Remove the @ symbol
31540
+ parameters.push({
31541
+ text: match,
31542
+ notation: 'at',
31543
+ name: parameterName,
31544
+ });
31545
+ return match;
31546
+ });
31547
+ // Extract {parameter} notation (parameters in braces)
31548
+ const braceParameterRegex = /\{([^}]+)\}/gim;
31549
+ text.replace(braceParameterRegex, (match, content) => {
31550
+ // Check if the parameter has a description (parameterName: description)
31551
+ const colonIndex = content.indexOf(':');
31552
+ if (colonIndex !== -1) {
31553
+ const name = content.substring(0, colonIndex).trim();
31554
+ const description = content.substring(colonIndex + 1).trim();
31555
+ parameters.push({
31556
+ text: match,
31557
+ notation: 'brace',
31558
+ name,
31559
+ description,
31560
+ });
31561
+ }
31562
+ else {
31563
+ // Simple parameter without description
31564
+ parameters.push({
31565
+ text: match,
31566
+ notation: 'brace',
31567
+ name: content.trim(),
31568
+ });
31569
+ }
31570
+ return match;
31571
+ });
31572
+ // Remove duplicates based on name (keep the first occurrence)
31573
+ const uniqueParameters = parameters.filter((parameter, index, array) => {
31574
+ return array.findIndex((parameterItem) => parameterItem.name === parameter.name) === index;
31575
+ });
31576
+ return uniqueParameters;
31577
+ }
31578
+
31579
+ /**
31580
+ * Ensures the parsed profile always exposes a fullname value.
31581
+ *
31582
+ * @private internal utility of `parseAgentSource`
31583
+ */
31584
+ function ensureMetaFullname(meta, fallbackFullname) {
31585
+ if (!meta.fullname) {
31586
+ meta.fullname = fallbackFullname;
31587
+ }
31588
+ }
31589
+
31590
+ /**
31591
+ * Resolves the public agent profile text from the last GOAL/GOALS commitment,
31592
+ * falling back to the deprecated PERSONA/PERSONAE commitments when no goal exists.
31593
+ *
31594
+ * @private internal utility of `parseAgentSource`
31595
+ */
31596
+ function extractAgentProfileText(commitments) {
31597
+ let goalDescription = '';
31598
+ let hasGoalDescription = false;
31599
+ let personaDescription = '';
31600
+ let hasPersonaDescription = false;
31601
+ for (const commitment of commitments) {
31602
+ if (commitment.type === 'GOAL' || commitment.type === 'GOALS') {
31603
+ goalDescription = commitment.content;
31604
+ hasGoalDescription = true;
31605
+ }
31606
+ if (commitment.type === 'PERSONA' || commitment.type === 'PERSONAE') {
31607
+ personaDescription = commitment.content;
31608
+ hasPersonaDescription = true;
31609
+ }
31610
+ }
31611
+ if (hasGoalDescription) {
31612
+ return goalDescription;
31613
+ }
31614
+ if (hasPersonaDescription) {
31615
+ return personaDescription;
31616
+ }
31617
+ return null;
31618
+ }
31619
+
31620
+ /**
31621
+ * Resolves the last INITIAL MESSAGE commitment, which is the public initial-message value.
31622
+ *
31623
+ * @private internal utility of `parseAgentSource`
31624
+ */
31625
+ function extractInitialMessage(commitments) {
31626
+ let initialMessage = null;
31627
+ for (const commitment of commitments) {
31628
+ if (commitment.type === 'INITIAL MESSAGE') {
31629
+ initialMessage = commitment.content;
31630
+ }
31631
+ }
31632
+ return initialMessage;
31633
+ }
31634
+
31333
31635
  /**
31334
31636
  * Normalizes a domain-like string into a comparable hostname form.
31335
31637
  *
@@ -31369,274 +31671,178 @@ function hasHttpProtocol(value) {
31369
31671
  }
31370
31672
 
31371
31673
  /**
31372
- * Consumes the agent-name prelude from raw source.
31373
- *
31374
- * Leading whitespace-only lines are skipped. The first subsequent line that contains any
31375
- * non-whitespace characters is always treated as plain-text agent name, even when it starts
31376
- * with a commitment keyword or other book syntax.
31377
- *
31378
- * @param agentSource - Raw agent source.
31379
- * @returns Parsed prelude with shared line metadata.
31674
+ * Dedicated handlers for META-style commitments that directly map onto parsed meta fields.
31675
+ */
31676
+ const META_COMMITMENT_APPLIERS = {
31677
+ 'META AVATAR': applyMetaAvatarContent,
31678
+ 'META LINK': applyMetaLinkContent,
31679
+ 'META DOMAIN': applyMetaDomainContent,
31680
+ 'META IMAGE': applyMetaImageContent,
31681
+ 'META DESCRIPTION': applyMetaDescriptionContent,
31682
+ 'META DISCLAIMER': applyMetaDisclaimerContent,
31683
+ 'META INPUT PLACEHOLDER': applyMetaInputPlaceholderContent,
31684
+ 'MESSAGE SUFFIX': applyMessageSuffixContent,
31685
+ 'META COLOR': applyMetaColorContent,
31686
+ 'META FONT': applyMetaFontContent,
31687
+ 'META VOICE': applyMetaVoiceContent,
31688
+ };
31689
+ /**
31690
+ * Applies META-style commitments that mutate parsed profile metadata.
31380
31691
  *
31381
- * @private internal utility of book agent-source parsing
31692
+ * @private internal utility of `parseAgentSource`
31382
31693
  */
31383
- function parseAgentSourcePrelude(agentSource) {
31384
- const lines = agentSource.split(/\r?\n/);
31385
- for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
31386
- const line = lines[lineIndex];
31387
- if (line === undefined) {
31388
- continue;
31389
- }
31390
- const trimmedLine = line.trim();
31391
- if (!trimmedLine) {
31392
- continue;
31393
- }
31394
- return {
31395
- lines,
31396
- agentName: trimmedLine,
31397
- agentNameLineIndex: lineIndex,
31398
- agentNameLineNumber: lineIndex + 1,
31399
- };
31694
+ function applyMetaCommitment(state, commitment) {
31695
+ const applyMetaContent = META_COMMITMENT_APPLIERS[commitment.type];
31696
+ if (applyMetaContent) {
31697
+ applyMetaContent(state, commitment.content);
31698
+ return;
31699
+ }
31700
+ if (commitment.type === 'META') {
31701
+ applyGenericMetaCommitment(state, commitment.content);
31400
31702
  }
31401
- return {
31402
- lines,
31403
- agentName: null,
31404
- agentNameLineIndex: -1,
31405
- };
31406
31703
  }
31407
-
31408
- /**
31409
- * Regex pattern to match horizontal lines (markdown thematic breaks)
31410
- * Matches 3 or more hyphens, underscores, or asterisks (with optional spaces between)
31411
- */
31412
- const HORIZONTAL_LINE_PATTERN$1 = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
31413
31704
  /**
31414
- * Parses agent source using the new commitment system with multiline support
31415
- * This function replaces the hardcoded commitment parsing in the original parseAgentSource
31416
- *
31417
- * The first non-empty line is always consumed as plain-text agent name. Commitment parsing
31418
- * starts only after that title line has been fixed.
31419
- *
31420
- * @private internal utility of `parseAgentSource`
31705
+ * Applies the generic META commitment form (`META TYPE value`).
31421
31706
  */
31422
- function parseAgentSourceWithCommitments(agentSource) {
31423
- var _a, _b;
31424
- if (!agentSource || !agentSource.trim()) {
31425
- return {
31426
- agentName: null,
31427
- commitments: [],
31428
- nonCommitmentLines: [],
31429
- };
31707
+ function applyGenericMetaCommitment(state, content) {
31708
+ const metaTypeRaw = content.split(' ')[0] || 'NONE';
31709
+ const metaValue = spaceTrim$1(content.substring(metaTypeRaw.length));
31710
+ if (metaTypeRaw === 'LINK') {
31711
+ state.links.push(metaValue);
31430
31712
  }
31431
- const { lines, agentName, agentNameLineIndex, agentNameLineNumber } = parseAgentSourcePrelude(agentSource);
31432
- const commitments = [];
31433
- const nonCommitmentLines = agentNameLineIndex >= 0 ? [lines[agentNameLineIndex]] : [];
31434
- // Parse commitments with multiline support
31435
- let currentCommitment = null;
31436
- // Process lines starting from after the agent name line
31437
- const startIndex = agentNameLineIndex >= 0 ? agentNameLineIndex + 1 : 0;
31438
- let isInsideCodeBlock = false;
31439
- for (let i = startIndex; i < lines.length; i++) {
31440
- const line = lines[i];
31441
- if (line === undefined) {
31442
- continue;
31443
- }
31444
- const trimmedLine = line.trim();
31445
- // Check if this line starts or ends a code block
31446
- if (trimmedLine.startsWith('```')) {
31447
- isInsideCodeBlock = !isInsideCodeBlock;
31448
- if (currentCommitment) {
31449
- // If we are inside a commitment, the code block is part of it
31450
- currentCommitment.contentLines.push(line);
31451
- }
31452
- else {
31453
- // If we are not inside a commitment, the code block is non-commitment
31454
- nonCommitmentLines.push(line);
31455
- }
31456
- continue;
31457
- }
31458
- if (isInsideCodeBlock) {
31459
- if (currentCommitment) {
31460
- // If we are inside a commitment and a code block, the line is part of the commitment
31461
- currentCommitment.contentLines.push(line);
31462
- }
31463
- else {
31464
- // If we are inside a code block but not a commitment, the line is non-commitment
31465
- nonCommitmentLines.push(line);
31466
- }
31467
- continue;
31468
- }
31469
- // Check if this line starts a new commitment
31470
- let foundNewCommitment = false;
31471
- for (const definition of COMMITMENT_REGISTRY) {
31472
- const typeRegex = definition.createTypeRegex();
31473
- const match = typeRegex.exec(line.trim());
31474
- if (match && ((_a = match.groups) === null || _a === void 0 ? void 0 : _a.type)) {
31475
- // Save the previous commitment if it exists
31476
- if (currentCommitment) {
31477
- const fullContent = currentCommitment.contentLines.join('\n');
31478
- commitments.push({
31479
- type: currentCommitment.type,
31480
- content: spaceTrim$1(fullContent),
31481
- originalLine: currentCommitment.originalStartLine,
31482
- lineNumber: currentCommitment.startLineNumber,
31483
- });
31484
- }
31485
- // Extract the initial content from the commitment line
31486
- const fullRegex = definition.createRegex();
31487
- const fullMatch = fullRegex.exec(line.trim());
31488
- const initialContent = ((_b = fullMatch === null || fullMatch === void 0 ? void 0 : fullMatch.groups) === null || _b === void 0 ? void 0 : _b.contents) || '';
31489
- // Start a new commitment
31490
- currentCommitment = {
31491
- type: definition.type,
31492
- startLineNumber: i + 1,
31493
- originalStartLine: line,
31494
- contentLines: initialContent ? [initialContent] : [],
31495
- };
31496
- foundNewCommitment = true;
31497
- break;
31498
- }
31499
- }
31500
- // Check if this is a horizontal line (ends any current commitment)
31501
- const isHorizontalLine = HORIZONTAL_LINE_PATTERN$1.test(line);
31502
- if (isHorizontalLine) {
31503
- // Save the current commitment if it exists
31504
- if (currentCommitment) {
31505
- const fullContent = currentCommitment.contentLines.join('\n');
31506
- commitments.push({
31507
- type: currentCommitment.type,
31508
- content: spaceTrim$1(fullContent),
31509
- originalLine: currentCommitment.originalStartLine,
31510
- lineNumber: currentCommitment.startLineNumber,
31511
- });
31512
- currentCommitment = null;
31513
- }
31514
- // Add horizontal line to non-commitment lines
31515
- nonCommitmentLines.push(line);
31516
- continue;
31517
- }
31518
- if (!foundNewCommitment) {
31519
- if (currentCommitment) {
31520
- // This line belongs to the current commitment
31521
- currentCommitment.contentLines.push(line);
31522
- }
31523
- else {
31524
- // This line is not part of any commitment
31525
- nonCommitmentLines.push(line);
31526
- }
31527
- }
31713
+ if (metaTypeRaw.toUpperCase() === 'AVATAR') {
31714
+ applyMetaAvatarContent(state, metaValue);
31715
+ return;
31528
31716
  }
31529
- // Don't forget to save the last commitment if it exists
31530
- if (currentCommitment) {
31531
- const fullContent = currentCommitment.contentLines.join('\n');
31532
- commitments.push({
31533
- type: currentCommitment.type,
31534
- content: spaceTrim$1(fullContent),
31535
- originalLine: currentCommitment.originalStartLine,
31536
- lineNumber: currentCommitment.startLineNumber,
31537
- });
31717
+ const metaType = normalizeTo_camelCase(metaTypeRaw);
31718
+ state.meta[metaType] = metaValue;
31719
+ }
31720
+ /**
31721
+ * Applies META AVATAR content into the canonical `meta.avatar` field.
31722
+ */
31723
+ function applyMetaAvatarContent(state, content) {
31724
+ const avatarVisualId = resolveAvatarVisualId(content);
31725
+ if (avatarVisualId) {
31726
+ state.meta.avatar = avatarVisualId;
31727
+ return;
31538
31728
  }
31539
- return {
31540
- agentName,
31541
- agentNameLineNumber,
31542
- commitments,
31543
- nonCommitmentLines,
31544
- };
31729
+ delete state.meta.avatar;
31545
31730
  }
31546
-
31547
31731
  /**
31548
- * Parses parameters from text using both supported notations:
31549
- * 1. @Parameter - single word parameter starting with @
31550
- * 2. {parameterName} or {parameter with multiple words} or {parameterName: description text}
31551
- *
31552
- * Both notations represent the same syntax feature - parameters
31732
+ * Applies META LINK content into links and the canonical `meta.link` field.
31733
+ */
31734
+ function applyMetaLinkContent(state, content) {
31735
+ const linkValue = spaceTrim$1(content);
31736
+ state.links.push(linkValue);
31737
+ state.meta.link = linkValue;
31738
+ }
31739
+ /**
31740
+ * Applies META DOMAIN content into the normalized `meta.domain` field.
31741
+ */
31742
+ function applyMetaDomainContent(state, content) {
31743
+ state.meta.domain = normalizeMetaDomain(content);
31744
+ }
31745
+ /**
31746
+ * Applies META IMAGE content into the canonical `meta.image` field.
31747
+ */
31748
+ function applyMetaImageContent(state, content) {
31749
+ state.meta.image = spaceTrim$1(content);
31750
+ }
31751
+ /**
31752
+ * Applies META DESCRIPTION content into the canonical `meta.description` field.
31753
+ */
31754
+ function applyMetaDescriptionContent(state, content) {
31755
+ state.meta.description = spaceTrim$1(content);
31756
+ }
31757
+ /**
31758
+ * Applies META DISCLAIMER content into the canonical `meta.disclaimer` field.
31759
+ */
31760
+ function applyMetaDisclaimerContent(state, content) {
31761
+ state.meta.disclaimer = content;
31762
+ }
31763
+ /**
31764
+ * Applies META INPUT PLACEHOLDER content into the canonical `meta.inputPlaceholder` field.
31765
+ */
31766
+ function applyMetaInputPlaceholderContent(state, content) {
31767
+ state.meta.inputPlaceholder = spaceTrim$1(content);
31768
+ }
31769
+ /**
31770
+ * Applies MESSAGE SUFFIX content into the canonical `meta.messageSuffix` field.
31771
+ */
31772
+ function applyMessageSuffixContent(state, content) {
31773
+ state.meta.messageSuffix = content;
31774
+ }
31775
+ /**
31776
+ * Applies META COLOR content into the canonical `meta.color` field.
31777
+ */
31778
+ function applyMetaColorContent(state, content) {
31779
+ state.meta.color = normalizeSeparator(content);
31780
+ }
31781
+ /**
31782
+ * Applies META FONT content into the canonical `meta.font` field.
31783
+ */
31784
+ function applyMetaFontContent(state, content) {
31785
+ state.meta.font = normalizeSeparator(content);
31786
+ }
31787
+ /**
31788
+ * Applies META VOICE content into the canonical `meta.voice` field.
31789
+ */
31790
+ function applyMetaVoiceContent(state, content) {
31791
+ state.meta.voice = spaceTrim$1(content);
31792
+ }
31793
+ /**
31794
+ * Normalizes the separator in the content
31553
31795
  *
31554
- * @param text - Text to extract parameters from
31555
- * @returns Array of parsed parameters with unified representation
31796
+ * @param content - The content to normalize
31797
+ * @returns The content with normalized separators
31798
+ */
31799
+ function normalizeSeparator(content) {
31800
+ const trimmed = spaceTrim$1(content);
31801
+ if (trimmed.includes(',')) {
31802
+ return trimmed;
31803
+ }
31804
+ return trimmed.split(/\s+/).join(', ');
31805
+ }
31806
+ /**
31807
+ * Normalizes META DOMAIN content to a hostname-like value when possible.
31556
31808
  *
31557
- * @public exported from `@promptbook/core`
31809
+ * @param content - Raw META DOMAIN content.
31810
+ * @returns Normalized domain or a trimmed fallback.
31558
31811
  */
31559
- function parseParameters(text) {
31560
- const parameters = [];
31561
- // [🧠] Parameter syntax parsing - unified approach for two different notations of the same syntax feature
31562
- // The Book language supports parameters in two different notations but they represent the same concept
31563
- // Extract @Parameter notation (single word parameters starting with @)
31564
- const atParameterRegex = /@[\w\u00C0-\u017F\u0100-\u024F\u1E00-\u1EFF]+/gim;
31565
- text.replace(atParameterRegex, (match) => {
31566
- const parameterName = match.slice(1); // Remove the @ symbol
31567
- parameters.push({
31568
- text: match,
31569
- notation: 'at',
31570
- name: parameterName,
31571
- });
31572
- return match;
31573
- });
31574
- // Extract {parameter} notation (parameters in braces)
31575
- const braceParameterRegex = /\{([^}]+)\}/gim;
31576
- text.replace(braceParameterRegex, (match, content) => {
31577
- // Check if the parameter has a description (parameterName: description)
31578
- const colonIndex = content.indexOf(':');
31579
- if (colonIndex !== -1) {
31580
- const name = content.substring(0, colonIndex).trim();
31581
- const description = content.substring(colonIndex + 1).trim();
31582
- parameters.push({
31583
- text: match,
31584
- notation: 'brace',
31585
- name,
31586
- description,
31587
- });
31588
- }
31589
- else {
31590
- // Simple parameter without description
31591
- parameters.push({
31592
- text: match,
31593
- notation: 'brace',
31594
- name: content.trim(),
31595
- });
31596
- }
31597
- return match;
31598
- });
31599
- // Remove duplicates based on name (keep the first occurrence)
31600
- const uniqueParameters = parameters.filter((parameter, index, array) => {
31601
- return array.findIndex((parameterItem) => parameterItem.name === parameter.name) === index;
31602
- });
31603
- return uniqueParameters;
31812
+ function normalizeMetaDomain(content) {
31813
+ const trimmed = spaceTrim$1(content);
31814
+ return normalizeDomainForMatching(trimmed) || trimmed.toLowerCase();
31604
31815
  }
31605
31816
 
31606
31817
  /**
31607
- * Parses basic information from agent source
31608
- *
31609
- * There are 2 similar functions:
31610
- * - `parseAgentSource` which is a lightweight parser for agent source, it parses basic information and its purpose is to be quick and synchronous. The commitments there are hardcoded.
31611
- * - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
31818
+ * Updates sample-conversation state for communication commitments.
31612
31819
  *
31613
- * @public exported from `@promptbook/core`
31820
+ * @private internal utility of `parseAgentSource`
31614
31821
  */
31615
- function parseAgentSource(agentSource) {
31616
- const parseResult = parseAgentSourceWithCommitments(agentSource);
31617
- const resolvedAgentName = parseResult.agentName || createDefaultAgentName(agentSource);
31618
- const personaDescription = extractAgentProfileText(parseResult.commitments);
31619
- const initialMessage = extractInitialMessage(parseResult.commitments);
31620
- const parsedProfile = extractParsedAgentProfile(parseResult.commitments);
31621
- ensureMetaFullname(parsedProfile.meta, resolvedAgentName);
31622
- return {
31623
- agentName: normalizeAgentName(resolvedAgentName),
31624
- agentHash: computeAgentHash(agentSource),
31625
- permanentId: parsedProfile.meta.id,
31626
- personaDescription,
31627
- initialMessage,
31628
- meta: parsedProfile.meta,
31629
- links: parsedProfile.links,
31630
- parameters: parseParameters(agentSource),
31631
- capabilities: parsedProfile.capabilities,
31632
- samples: parsedProfile.samples,
31633
- knowledgeSources: parsedProfile.knowledgeSources,
31634
- };
31822
+ function consumeConversationSampleCommitment(state, commitment) {
31823
+ switch (commitment.type) {
31824
+ case 'INITIAL MESSAGE':
31825
+ state.samples.push({ question: null, answer: commitment.content });
31826
+ return true;
31827
+ case 'USER MESSAGE':
31828
+ state.pendingUserMessage = commitment.content;
31829
+ return true;
31830
+ case 'INTERNAL MESSAGE':
31831
+ // INTERNAL MESSAGE stores trace payloads and is intentionally ignored in basic profile samples.
31832
+ return true;
31833
+ case 'AGENT MESSAGE':
31834
+ if (state.pendingUserMessage !== null) {
31835
+ state.samples.push({ question: state.pendingUserMessage, answer: commitment.content });
31836
+ state.pendingUserMessage = null;
31837
+ }
31838
+ return true;
31839
+ default:
31840
+ return false;
31841
+ }
31635
31842
  }
31843
+
31636
31844
  /**
31637
31845
  * Static capability descriptors for commitments that map one-to-one to a visible capability.
31638
- *
31639
- * @private internal utility of `parseAgentSource`
31640
31846
  */
31641
31847
  const SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE = {
31642
31848
  'USE BROWSER': {
@@ -31699,142 +31905,11 @@ const SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE = {
31699
31905
  label: 'Calendar',
31700
31906
  iconName: 'Calendar',
31701
31907
  },
31702
- };
31703
- /**
31704
- * Dedicated handlers for META-style commitments that directly map onto parsed meta fields.
31705
- *
31706
- * @private internal utility of `parseAgentSource`
31707
- */
31708
- const META_COMMITMENT_APPLIERS = {
31709
- 'META AVATAR': applyMetaAvatarContent,
31710
- 'META LINK': applyMetaLinkContent,
31711
- 'META DOMAIN': applyMetaDomainContent,
31712
- 'META IMAGE': applyMetaImageContent,
31713
- 'META DESCRIPTION': applyMetaDescriptionContent,
31714
- 'META DISCLAIMER': applyMetaDisclaimerContent,
31715
- 'META INPUT PLACEHOLDER': applyMetaInputPlaceholderContent,
31716
- 'MESSAGE SUFFIX': applyMessageSuffixContent,
31717
- 'META COLOR': applyMetaColorContent,
31718
- 'META FONT': applyMetaFontContent,
31719
- 'META VOICE': applyMetaVoiceContent,
31720
- };
31721
- /**
31722
- * Detects local slash-based references used by FROM and IMPORT commitments.
31723
- *
31724
- * @private internal utility of `parseAgentSource`
31725
- */
31726
- const LOCAL_AGENT_REFERENCE_PREFIXES = ['./', '../', '/'];
31727
- /**
31728
- * Resolves the public agent profile text from the last GOAL/GOALS commitment,
31729
- * falling back to the deprecated PERSONA/PERSONAE commitments when no goal exists.
31730
- *
31731
- * @private internal utility of `parseAgentSource`
31732
- */
31733
- function extractAgentProfileText(commitments) {
31734
- let goalDescription = '';
31735
- let hasGoalDescription = false;
31736
- let personaDescription = '';
31737
- let hasPersonaDescription = false;
31738
- for (const commitment of commitments) {
31739
- if (commitment.type === 'GOAL' || commitment.type === 'GOALS') {
31740
- goalDescription = commitment.content;
31741
- hasGoalDescription = true;
31742
- }
31743
- if (commitment.type === 'PERSONA' || commitment.type === 'PERSONAE') {
31744
- personaDescription = commitment.content;
31745
- hasPersonaDescription = true;
31746
- }
31747
- }
31748
- if (hasGoalDescription) {
31749
- return goalDescription;
31750
- }
31751
- if (hasPersonaDescription) {
31752
- return personaDescription;
31753
- }
31754
- return null;
31755
- }
31756
- /**
31757
- * Resolves the last INITIAL MESSAGE commitment, which is the public initial-message value.
31758
- *
31759
- * @private internal utility of `parseAgentSource`
31760
- */
31761
- function extractInitialMessage(commitments) {
31762
- let initialMessage = null;
31763
- for (const commitment of commitments) {
31764
- if (commitment.type === 'INITIAL MESSAGE') {
31765
- initialMessage = commitment.content;
31766
- }
31767
- }
31768
- return initialMessage;
31769
- }
31770
- /**
31771
- * Collects capability, sample, meta, link, and knowledge-source data from commitments.
31772
- *
31773
- * @private internal utility of `parseAgentSource`
31774
- */
31775
- function extractParsedAgentProfile(commitments) {
31776
- const state = {
31777
- meta: {},
31778
- links: [],
31779
- capabilities: [],
31780
- samples: [],
31781
- knowledgeSources: [],
31782
- pendingUserMessage: null,
31783
- knownKnowledgeSourceUrls: new Set(),
31784
- };
31785
- for (const commitment of commitments) {
31786
- processParsedCommitment(state, commitment);
31787
- }
31788
- return {
31789
- meta: state.meta,
31790
- links: state.links,
31791
- capabilities: state.capabilities,
31792
- samples: state.samples,
31793
- knowledgeSources: state.knowledgeSources,
31794
- };
31795
- }
31796
- /**
31797
- * Processes one parsed commitment through the sample, capability, and meta stages.
31798
- *
31799
- * @private internal utility of `parseAgentSource`
31800
- */
31801
- function processParsedCommitment(state, commitment) {
31802
- if (consumeConversationSampleCommitment(state, commitment)) {
31803
- return;
31804
- }
31805
- const capabilities = createCapabilitiesFromCommitment(state, commitment);
31806
- if (capabilities.length > 0) {
31807
- state.capabilities.push(...capabilities);
31808
- return;
31809
- }
31810
- applyMetaCommitment(state, commitment);
31811
- }
31812
- /**
31813
- * Updates sample-conversation state for communication commitments.
31814
- *
31815
- * @private internal utility of `parseAgentSource`
31816
- */
31817
- function consumeConversationSampleCommitment(state, commitment) {
31818
- switch (commitment.type) {
31819
- case 'INITIAL MESSAGE':
31820
- state.samples.push({ question: null, answer: commitment.content });
31821
- return true;
31822
- case 'USER MESSAGE':
31823
- state.pendingUserMessage = commitment.content;
31824
- return true;
31825
- case 'INTERNAL MESSAGE':
31826
- // INTERNAL MESSAGE stores trace payloads and is intentionally ignored in basic profile samples.
31827
- return true;
31828
- case 'AGENT MESSAGE':
31829
- if (state.pendingUserMessage !== null) {
31830
- state.samples.push({ question: state.pendingUserMessage, answer: commitment.content });
31831
- state.pendingUserMessage = null;
31832
- }
31833
- return true;
31834
- default:
31835
- return false;
31836
- }
31837
- }
31908
+ };
31909
+ /**
31910
+ * Detects local slash-based references used by FROM and IMPORT commitments.
31911
+ */
31912
+ const LOCAL_AGENT_REFERENCE_PREFIXES = ['./', '../', '/'];
31838
31913
  /**
31839
31914
  * Creates the visible capabilities produced by one parsed commitment.
31840
31915
  *
@@ -31864,8 +31939,6 @@ function createCapabilitiesFromCommitment(state, commitment) {
31864
31939
  }
31865
31940
  /**
31866
31941
  * Clones one static capability descriptor for a simple capability commitment.
31867
- *
31868
- * @private internal utility of `parseAgentSource`
31869
31942
  */
31870
31943
  function createSimpleCapability(commitmentType) {
31871
31944
  const capability = SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE[commitmentType];
@@ -31873,8 +31946,6 @@ function createSimpleCapability(commitmentType) {
31873
31946
  }
31874
31947
  /**
31875
31948
  * Creates the USE PROJECT capability badge.
31876
- *
31877
- * @private internal utility of `parseAgentSource`
31878
31949
  */
31879
31950
  function createProjectCapability(content) {
31880
31951
  var _a;
@@ -31888,8 +31959,6 @@ function createProjectCapability(content) {
31888
31959
  }
31889
31960
  /**
31890
31961
  * Creates the FROM inheritance capability when the reference should stay visible in the profile.
31891
- *
31892
- * @private internal utility of `parseAgentSource`
31893
31962
  */
31894
31963
  function createInheritanceCapability(content) {
31895
31964
  const reference = extractFirstCommitmentLine(content);
@@ -31916,8 +31985,6 @@ function createInheritanceCapability(content) {
31916
31985
  }
31917
31986
  /**
31918
31987
  * Creates the IMPORT capability badge.
31919
- *
31920
- * @private internal utility of `parseAgentSource`
31921
31988
  */
31922
31989
  function createImportCapability(content) {
31923
31990
  const reference = extractFirstCommitmentLine(content);
@@ -31945,8 +32012,6 @@ function createImportCapability(content) {
31945
32012
  }
31946
32013
  /**
31947
32014
  * Creates TEAM capability badges for all parsed teammates.
31948
- *
31949
- * @private internal utility of `parseAgentSource`
31950
32015
  */
31951
32016
  function createTeamCapabilities(content) {
31952
32017
  const teammates = parseTeamCommitmentContent(content);
@@ -31959,8 +32024,6 @@ function createTeamCapabilities(content) {
31959
32024
  }
31960
32025
  /**
31961
32026
  * Creates the KNOWLEDGE capability badge and records URL-based knowledge sources.
31962
- *
31963
- * @private internal utility of `parseAgentSource`
31964
32027
  */
31965
32028
  function createKnowledgeCapability(state, content) {
31966
32029
  const trimmedContent = spaceTrim$1(content);
@@ -31975,8 +32038,6 @@ function createKnowledgeCapability(state, content) {
31975
32038
  }
31976
32039
  /**
31977
32040
  * Stores unique URL-based knowledge sources for later citation resolution.
31978
- *
31979
- * @private internal utility of `parseAgentSource`
31980
32041
  */
31981
32042
  function rememberKnowledgeSources(state, extractedUrls) {
31982
32043
  for (const extractedUrl of extractedUrls) {
@@ -32000,8 +32061,6 @@ function rememberKnowledgeSources(state, extractedUrls) {
32000
32061
  }
32001
32062
  /**
32002
32063
  * Derives the visible KNOWLEDGE badge label and icon from commitment content.
32003
- *
32004
- * @private internal utility of `parseAgentSource`
32005
32064
  */
32006
32065
  function createKnowledgeCapabilityPresentation(content, extractedUrls) {
32007
32066
  let label = content;
@@ -32034,8 +32093,6 @@ function createKnowledgeCapabilityPresentation(content, extractedUrls) {
32034
32093
  }
32035
32094
  /**
32036
32095
  * Shortens text-only KNOWLEDGE commitments into the same preview label as before.
32037
- *
32038
- * @private internal utility of `parseAgentSource`
32039
32096
  */
32040
32097
  function createKnowledgeTextLabel(content) {
32041
32098
  const words = content.split(/\s+/);
@@ -32044,592 +32101,196 @@ function createKnowledgeTextLabel(content) {
32044
32101
  }
32045
32102
  return content;
32046
32103
  }
32047
- /**
32048
- * Applies META-style commitments that mutate parsed profile metadata.
32049
- *
32050
- * @private internal utility of `parseAgentSource`
32051
- */
32052
- function applyMetaCommitment(state, commitment) {
32053
- const applyMetaContent = META_COMMITMENT_APPLIERS[commitment.type];
32054
- if (applyMetaContent) {
32055
- applyMetaContent(state, commitment.content);
32056
- return;
32057
- }
32058
- if (commitment.type === 'META') {
32059
- applyGenericMetaCommitment(state, commitment.content);
32060
- }
32061
- }
32062
- /**
32063
- * Applies the generic META commitment form (`META TYPE value`).
32064
- *
32065
- * @private internal utility of `parseAgentSource`
32066
- */
32067
- function applyGenericMetaCommitment(state, content) {
32068
- const metaTypeRaw = content.split(' ')[0] || 'NONE';
32069
- const metaValue = spaceTrim$1(content.substring(metaTypeRaw.length));
32070
- if (metaTypeRaw === 'LINK') {
32071
- state.links.push(metaValue);
32072
- }
32073
- if (metaTypeRaw.toUpperCase() === 'AVATAR') {
32074
- applyMetaAvatarContent(state, metaValue);
32075
- return;
32076
- }
32077
- const metaType = normalizeTo_camelCase(metaTypeRaw);
32078
- state.meta[metaType] = metaValue;
32079
- }
32080
- /**
32081
- * Applies META AVATAR content into the canonical `meta.avatar` field.
32082
- *
32083
- * @private internal utility of `parseAgentSource`
32084
- */
32085
- function applyMetaAvatarContent(state, content) {
32086
- const avatarVisualId = resolveAvatarVisualId(content);
32087
- if (avatarVisualId) {
32088
- state.meta.avatar = avatarVisualId;
32089
- return;
32090
- }
32091
- delete state.meta.avatar;
32092
- }
32093
- /**
32094
- * Applies META LINK content into links and the canonical `meta.link` field.
32095
- *
32096
- * @private internal utility of `parseAgentSource`
32097
- */
32098
- function applyMetaLinkContent(state, content) {
32099
- const linkValue = spaceTrim$1(content);
32100
- state.links.push(linkValue);
32101
- state.meta.link = linkValue;
32102
- }
32103
- /**
32104
- * Applies META DOMAIN content into the normalized `meta.domain` field.
32105
- *
32106
- * @private internal utility of `parseAgentSource`
32107
- */
32108
- function applyMetaDomainContent(state, content) {
32109
- state.meta.domain = normalizeMetaDomain(content);
32110
- }
32111
- /**
32112
- * Applies META IMAGE content into the canonical `meta.image` field.
32113
- *
32114
- * @private internal utility of `parseAgentSource`
32115
- */
32116
- function applyMetaImageContent(state, content) {
32117
- state.meta.image = spaceTrim$1(content);
32118
- }
32119
- /**
32120
- * Applies META DESCRIPTION content into the canonical `meta.description` field.
32121
- *
32122
- * @private internal utility of `parseAgentSource`
32123
- */
32124
- function applyMetaDescriptionContent(state, content) {
32125
- state.meta.description = spaceTrim$1(content);
32126
- }
32127
- /**
32128
- * Applies META DISCLAIMER content into the canonical `meta.disclaimer` field.
32129
- *
32130
- * @private internal utility of `parseAgentSource`
32131
- */
32132
- function applyMetaDisclaimerContent(state, content) {
32133
- state.meta.disclaimer = content;
32134
- }
32135
- /**
32136
- * Applies META INPUT PLACEHOLDER content into the canonical `meta.inputPlaceholder` field.
32137
- *
32138
- * @private internal utility of `parseAgentSource`
32139
- */
32140
- function applyMetaInputPlaceholderContent(state, content) {
32141
- state.meta.inputPlaceholder = spaceTrim$1(content);
32142
- }
32143
- /**
32144
- * Applies MESSAGE SUFFIX content into the canonical `meta.messageSuffix` field.
32145
- *
32146
- * @private internal utility of `parseAgentSource`
32147
- */
32148
- function applyMessageSuffixContent(state, content) {
32149
- state.meta.messageSuffix = content;
32150
- }
32151
- /**
32152
- * Applies META COLOR content into the canonical `meta.color` field.
32153
- *
32154
- * @private internal utility of `parseAgentSource`
32155
- */
32156
- function applyMetaColorContent(state, content) {
32157
- state.meta.color = normalizeSeparator(content);
32158
- }
32159
- /**
32160
- * Applies META FONT content into the canonical `meta.font` field.
32161
- *
32162
- * @private internal utility of `parseAgentSource`
32163
- */
32164
- function applyMetaFontContent(state, content) {
32165
- state.meta.font = normalizeSeparator(content);
32166
- }
32167
- /**
32168
- * Applies META VOICE content into the canonical `meta.voice` field.
32169
- *
32170
- * @private internal utility of `parseAgentSource`
32171
- */
32172
- function applyMetaVoiceContent(state, content) {
32173
- state.meta.voice = spaceTrim$1(content);
32174
- }
32175
- /**
32176
- * Ensures the parsed profile always exposes a fullname value.
32177
- *
32178
- * @private internal utility of `parseAgentSource`
32179
- */
32180
- function ensureMetaFullname(meta, fallbackFullname) {
32181
- if (!meta.fullname) {
32182
- meta.fullname = fallbackFullname;
32183
- }
32184
- }
32185
32104
  /**
32186
32105
  * Extracts the first logical line from multiline commitment content.
32187
- *
32188
- * @private internal utility of `parseAgentSource`
32189
32106
  */
32190
32107
  function extractFirstCommitmentLine(content) {
32191
32108
  return spaceTrim$1(content).split(/\r?\n/)[0] || '';
32192
32109
  }
32193
32110
  /**
32194
32111
  * Detects local FROM/IMPORT references that should use local-link labels and icons.
32195
- *
32196
- * @private internal utility of `parseAgentSource`
32197
32112
  */
32198
32113
  function isLocalAgentReference(reference) {
32199
32114
  return LOCAL_AGENT_REFERENCE_PREFIXES.some((prefix) => reference.startsWith(prefix));
32200
32115
  }
32201
- /**
32202
- * Normalizes the separator in the content
32203
- *
32204
- * @param content - The content to normalize
32205
- * @returns The content with normalized separators
32206
- *
32207
- * @private internal utility of `parseAgentSource`
32208
- */
32209
- function normalizeSeparator(content) {
32210
- const trimmed = spaceTrim$1(content);
32211
- if (trimmed.includes(',')) {
32212
- return trimmed;
32213
- }
32214
- return trimmed.split(/\s+/).join(', ');
32215
- }
32216
- /**
32217
- * Normalizes META DOMAIN content to a hostname-like value when possible.
32218
- *
32219
- * @param content - Raw META DOMAIN content.
32220
- * @returns Normalized domain or a trimmed fallback.
32221
- *
32222
- * @private internal utility of `parseAgentSource`
32223
- */
32224
- function normalizeMetaDomain(content) {
32225
- const trimmed = spaceTrim$1(content);
32226
- return normalizeDomainForMatching(trimmed) || trimmed.toLowerCase();
32227
- }
32228
- // TODO: [🕛] Unite `AgentBasicInformation`, `ChatParticipant`, `LlmExecutionTools` + `LlmToolsMetadata`
32229
32116
 
32230
32117
  /**
32231
- * Gets all tool titles provided by all commitments
32118
+ * Collects capability, sample, meta, link, and knowledge-source data from commitments.
32232
32119
  *
32233
- * @public exported from `@promptbook/core`
32120
+ * @private internal utility of `parseAgentSource`
32234
32121
  */
32235
- function getAllCommitmentsToolTitles() {
32236
- const allToolTitles = {};
32237
- for (const commitmentDefinition of getAllCommitmentDefinitions()) {
32238
- const toolTitles = commitmentDefinition.getToolTitles();
32239
- for (const [funcName, title] of Object.entries(toolTitles)) {
32240
- if (allToolTitles[funcName] !== undefined &&
32241
- just(false) /* <- Note: [⛹️] How to deal with commitment aliases */) {
32242
- throw new UnexpectedError(`Duplicate tool function name detected: \`${funcName}\` provided by commitment \`${commitmentDefinition.type}\``);
32243
- }
32244
- allToolTitles[funcName] = title;
32245
- }
32122
+ function extractParsedAgentProfile(commitments) {
32123
+ const state = {
32124
+ meta: {},
32125
+ links: [],
32126
+ capabilities: [],
32127
+ samples: [],
32128
+ knowledgeSources: [],
32129
+ pendingUserMessage: null,
32130
+ knownKnowledgeSourceUrls: new Set(),
32131
+ };
32132
+ for (const commitment of commitments) {
32133
+ processParsedCommitment(state, commitment);
32246
32134
  }
32247
- return allToolTitles;
32135
+ return {
32136
+ meta: state.meta,
32137
+ links: state.links,
32138
+ capabilities: state.capabilities,
32139
+ samples: state.samples,
32140
+ knowledgeSources: state.knowledgeSources,
32141
+ };
32248
32142
  }
32249
-
32250
32143
  /**
32251
- * Restricts an Updatable to a (2) BehaviorSubject variant
32252
- *
32253
- * @see Updatable
32254
- *
32255
- * @private internal utility <- TODO: [🧠] Maybe export from `@promptbook/types`
32144
+ * Processes one parsed commitment through the sample, capability, and meta stages.
32256
32145
  */
32257
- function asUpdatableSubject(value) {
32258
- if (value instanceof BehaviorSubject) {
32259
- return value;
32260
- }
32261
- else if (Array.isArray(value)) {
32262
- if (value.length !== 2) {
32263
- throw new TypeError('`asUpdatableSubject`: Invalid tuple length, expected 2 elements');
32264
- }
32265
- if (typeof value[1] !== 'function') {
32266
- throw new TypeError('`asUpdatableSubject`: Invalid tuple, expected second element to be a function');
32267
- }
32268
- const [theValue, setValue] = value;
32269
- const subject = new BehaviorSubject(theValue);
32270
- subject.subscribe((newValue) => {
32271
- setValue(newValue);
32272
- });
32273
- return subject;
32146
+ function processParsedCommitment(state, commitment) {
32147
+ if (consumeConversationSampleCommitment(state, commitment)) {
32148
+ return;
32274
32149
  }
32275
- else {
32276
- return new BehaviorSubject(value);
32150
+ const capabilities = createCapabilitiesFromCommitment(state, commitment);
32151
+ if (capabilities.length > 0) {
32152
+ state.capabilities.push(...capabilities);
32153
+ return;
32277
32154
  }
32155
+ applyMetaCommitment(state, commitment);
32278
32156
  }
32279
- // TODO: [🧠] Maybe `BehaviorSubject` is too heavy for this use case, maybe just tuple `[value,setValue]` is enough
32280
32157
 
32281
32158
  /**
32282
- * Creates an empty/basic agent model requirements object
32283
- * This serves as the starting point for the reduce-like pattern
32284
- * where each commitment applies its changes to build the final requirements
32159
+ * Parses basic information from agent source
32285
32160
  *
32286
- * @public exported from `@promptbook/core`
32287
- */
32288
- function createEmptyAgentModelRequirements() {
32289
- return {
32290
- systemMessage: '',
32291
- promptSuffix: '',
32292
- // modelName: 'gpt-5',
32293
- modelName: 'gpt-5.4-mini',
32294
- temperature: 0.7,
32295
- topP: 0.9,
32296
- topK: 50,
32297
- parentAgentUrl: null,
32298
- isClosed: false,
32299
- };
32300
- }
32301
- /**
32302
- * Creates a basic agent model requirements with just the agent name
32303
- * This is used when we have an agent name but no commitments
32161
+ * There are 2 similar functions:
32162
+ * - `parseAgentSource` which is a lightweight parser for agent source, it parses basic information and its purpose is to be quick and synchronous. The commitments there are hardcoded.
32163
+ * - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
32304
32164
  *
32305
32165
  * @public exported from `@promptbook/core`
32306
32166
  */
32307
- function createBasicAgentModelRequirements(agentName) {
32308
- const empty = createEmptyAgentModelRequirements();
32167
+ function parseAgentSource(agentSource) {
32168
+ const parseResult = parseAgentSourceWithCommitments(agentSource);
32169
+ const resolvedAgentName = parseResult.agentName || createDefaultAgentName(agentSource);
32170
+ const personaDescription = extractAgentProfileText(parseResult.commitments);
32171
+ const initialMessage = extractInitialMessage(parseResult.commitments);
32172
+ const parsedProfile = extractParsedAgentProfile(parseResult.commitments);
32173
+ ensureMetaFullname(parsedProfile.meta, resolvedAgentName);
32309
32174
  return {
32310
- ...empty,
32311
- systemMessage: `You are ${agentName || 'AI Agent'}`,
32175
+ agentName: normalizeAgentName(resolvedAgentName),
32176
+ agentHash: computeAgentHash(agentSource),
32177
+ permanentId: parsedProfile.meta.id,
32178
+ personaDescription,
32179
+ initialMessage,
32180
+ meta: parsedProfile.meta,
32181
+ links: parsedProfile.links,
32182
+ parameters: parseParameters(agentSource),
32183
+ capabilities: parsedProfile.capabilities,
32184
+ samples: parsedProfile.samples,
32185
+ knowledgeSources: parsedProfile.knowledgeSources,
32312
32186
  };
32313
32187
  }
32314
- // TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
32315
-
32316
- /**
32317
- * Gets a commitment definition by its type
32318
- *
32319
- * @param type The commitment type to look up
32320
- * @returns The commitment definition or null if not found
32321
- *
32322
- * @public exported from `@promptbook/core`
32323
- */
32324
- function getCommitmentDefinition(type) {
32325
- return COMMITMENT_REGISTRY.find((commitmentDefinition) => commitmentDefinition.type === type) || null;
32326
- }
32327
-
32328
- /**
32329
- * Plugin for importing agent books *(`.book` files)*
32330
- *
32331
- * @private [🥝] Maybe export the import plugins through some package
32332
- */
32333
- const AgentFileImportPlugin = {
32334
- name: 'agent-file-import-plugin',
32335
- canImport(mimeType) {
32336
- // [🧠] Should we have a specific MIME type for agent books?
32337
- // For now, let's assume it's identified by .book extension or certain MIME types if provided
32338
- return mimeType === 'text/x-promptbook' || mimeType === 'application/x-promptbook';
32339
- },
32340
- import(content) {
32341
- const parseResult = parseAgentSourceWithCommitments(content);
32342
- // Bring only the agent corpus (non-commitment lines and relevant commitments)
32343
- // Stripping the agent name (which is usually the first line)
32344
- const corpus = parseResult.nonCommitmentLines
32345
- .filter((line, index) => index > 0 || !parseResult.agentName)
32346
- .join('\n')
32347
- .trim();
32348
- // Also include relevant commitments that make up the "corpus" of the agent
32349
- // For example PERSONA, RULE, KNOWLEDGE
32350
- const relevantCommitments = parseResult.commitments
32351
- .filter((c) => ['PERSONA', 'RULE', 'KNOWLEDGE'].includes(c.type))
32352
- .map((c) => `${c.type} ${c.content}`)
32353
- .join('\n\n');
32354
- return spaceTrim$1((block) => `
32355
- ${block(relevantCommitments)}
32356
-
32357
- ${block(corpus)}
32358
- `).trim();
32359
- },
32360
- };
32361
-
32362
- /**
32363
- * Plugin for importing JSON files
32364
- *
32365
- * @private [🥝] Maybe export the import plugins through some package
32366
- */
32367
- const JsonFileImportPlugin = {
32368
- name: 'json-file-import-plugin',
32369
- canImport(mimeType) {
32370
- return mimeType === 'application/json' || mimeType.endsWith('+json');
32371
- },
32372
- import(content) {
32373
- try {
32374
- const json = JSON.parse(content);
32375
- const formattedJson = JSON.stringify(json, null, 4);
32376
- return `\`\`\`json\n${formattedJson}\n\`\`\``;
32377
- }
32378
- catch (error) {
32379
- // If JSON is invalid, still import it but maybe not as pretty JSON
32380
- return `\`\`\`json\n${content}\n\`\`\``;
32381
- }
32382
- },
32383
- };
32384
-
32385
- /**
32386
- * Plugin for importing generic text files
32387
- *
32388
- * @private [🥝] Maybe export the import plugins through some package
32389
- */
32390
- const TextFileImportPlugin = {
32391
- name: 'text-file-import-plugin',
32392
- canImport(mimeType) {
32393
- return (mimeType === 'text/plain' ||
32394
- mimeType === 'text/markdown' ||
32395
- mimeType === 'text/x-typescript' ||
32396
- mimeType === 'text/javascript' ||
32397
- mimeType === 'text/css' ||
32398
- mimeType === 'text/html' ||
32399
- mimeType.startsWith('text/'));
32400
- },
32401
- import(content, mimeType) {
32402
- const extension = mimeTypeToExtension(mimeType);
32403
- const codeBlockType = extension || 'txt';
32404
- return `\`\`\`${codeBlockType}\n${content}\n\`\`\``;
32405
- },
32406
- };
32407
-
32408
- /**
32409
- * All available file import plugins
32410
- *
32411
- * @private [🥝] Maybe export the import plugins through some package
32412
- */
32413
- const $fileImportPlugins = [
32414
- AgentFileImportPlugin,
32415
- JsonFileImportPlugin,
32416
- TextFileImportPlugin,
32417
- ];
32418
-
32419
- /**
32420
- * Removes single-hash comment lines (`# Comment`) from a system message
32421
- * This is used to clean up the final system message before sending it to the AI model
32422
- * while preserving the original content with comments in metadata
32423
- *
32424
- * @param systemMessage The system message that may contain comment lines
32425
- * @returns The system message with single-hash comment lines removed
32426
- *
32427
- * @private - TODO: [🧠] Maybe should be public?
32428
- */
32429
- function removeCommentsFromSystemMessage(systemMessage) {
32430
- if (!systemMessage) {
32431
- return systemMessage;
32432
- }
32433
- const lines = systemMessage.split(/\r?\n/);
32434
- const filteredLines = lines.filter((line) => {
32435
- const trimmedLine = line.trim();
32436
- // Remove only single-hash comment markers (`# Comment`) and keep markdown headings (`## Heading`).
32437
- return !/^#(?!#)\s/.test(trimmedLine);
32438
- });
32439
- return filteredLines.join('\n').trim();
32440
- }
32441
-
32442
- /**
32443
- * Commitment types whose content may contain compact agent references that must be resolved before applying the commitment.
32444
- *
32445
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
32446
- */
32447
- const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS', 'TEAM']);
32448
- /**
32449
- * DELETE-like commitment types that invalidate earlier tagged commitments.
32450
- *
32451
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
32452
- */
32453
- const DELETE_COMMITMENT_TYPES = new Set(['DELETE', 'CANCEL', 'DISCARD', 'REMOVE']);
32454
- /**
32455
- * Commitments whose earlier occurrences are overwritten by the last occurrence in source order.
32456
- *
32457
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
32458
- */
32459
- const OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE = new Map([
32460
- ['GOAL', 'GOAL'],
32461
- ['GOALS', 'GOAL'],
32462
- ]);
32463
- /**
32464
- * Regex pattern matching markdown horizontal lines that should not be copied into the final system message.
32465
- *
32466
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
32467
- */
32468
- const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
32469
- /**
32470
- * MIME type prefixes treated as binary and therefore not eligible for text import plugins.
32471
- *
32472
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
32473
- */
32474
- const BINARY_MIME_TYPE_PREFIXES = [
32475
- 'image/',
32476
- 'video/',
32477
- 'audio/',
32478
- 'application/octet-stream',
32479
- 'application/pdf',
32480
- 'application/zip',
32481
- ];
32482
- /**
32483
- * Returns a safe fallback content when a resolver fails to transform a reference commitment.
32484
- *
32485
- * @param commitmentType - Commitment being resolved.
32486
- * @param originalContent - Original unresolved commitment content.
32487
- * @returns Fallback content that keeps requirement creation resilient.
32488
- *
32489
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32490
- */
32491
- function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
32492
- if (commitmentType === 'FROM') {
32493
- return 'VOID';
32494
- }
32495
- if (commitmentType === 'IMPORT' || commitmentType === 'IMPORTS' || commitmentType === 'TEAM') {
32496
- return '';
32497
- }
32498
- return originalContent;
32499
- }
32500
- /**
32501
- * Creates agent model requirements by parsing commitments, applying them in source order,
32502
- * and finalizing derived sections such as imports, example interactions, and inline knowledge uploads.
32503
- *
32504
- * @param agentSource - Agent source book to parse.
32505
- * @param modelName - Optional override for the agent model name.
32506
- * @param options - Additional options such as reference and teammate resolvers.
32507
- * @returns Fully prepared model requirements for the parsed agent source.
32508
- *
32509
- * @private internal utility of `createAgentModelRequirements`
32510
- */
32511
- async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
32512
- const parseResult = parseAgentSourceWithCommitments(agentSource);
32513
- const filteredCommitments = filterOverwrittenCommitments(filterDeletedCommitments(parseResult.commitments));
32514
- let requirements = createInitialAgentModelRequirements(parseResult.agentName, modelName);
32515
- requirements = await applyCommitmentsToRequirements(requirements, filteredCommitments, options);
32516
- requirements = aggregateUseCommitmentSystemMessages(requirements, filteredCommitments);
32517
- requirements = await importReferencedFiles(requirements);
32518
- requirements = appendMcpServers(requirements, agentSource);
32519
- requirements = appendNonCommitmentContent(requirements, parseResult);
32520
- requirements = appendExampleInteractions(requirements, parseResult);
32521
- requirements = await applyPendingInlineKnowledgeSources(requirements, options === null || options === void 0 ? void 0 : options.inlineKnowledgeSourceUploader);
32522
- return finalizeRequirements(requirements);
32523
- }
32188
+ // TODO: [🕛] Unite `AgentBasicInformation`, `ChatParticipant`, `LlmExecutionTools` + `LlmToolsMetadata`
32189
+
32524
32190
  /**
32525
- * Removes earlier commitments that are overwritten by later commitments of the same semantic group.
32191
+ * Gets all tool titles provided by all commitments
32526
32192
  *
32527
- * This currently keeps only the last `GOAL` / `GOALS` commitment so inheritance rewrites
32528
- * and multi-goal sources expose one effective goal to the runtime.
32193
+ * @public exported from `@promptbook/core`
32194
+ */
32195
+ function getAllCommitmentsToolTitles() {
32196
+ const allToolTitles = {};
32197
+ for (const commitmentDefinition of getAllCommitmentDefinitions()) {
32198
+ const toolTitles = commitmentDefinition.getToolTitles();
32199
+ for (const [funcName, title] of Object.entries(toolTitles)) {
32200
+ if (allToolTitles[funcName] !== undefined &&
32201
+ just(false) /* <- Note: [⛹️] How to deal with commitment aliases */) {
32202
+ throw new UnexpectedError(`Duplicate tool function name detected: \`${funcName}\` provided by commitment \`${commitmentDefinition.type}\``);
32203
+ }
32204
+ allToolTitles[funcName] = title;
32205
+ }
32206
+ }
32207
+ return allToolTitles;
32208
+ }
32209
+
32210
+ /**
32211
+ * Restricts an Updatable to a (2) BehaviorSubject variant
32529
32212
  *
32530
- * @param commitments - Parsed commitments after DELETE-like filtering.
32531
- * @returns Commitments with overwritten entries removed while preserving source order.
32213
+ * @see Updatable
32532
32214
  *
32533
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32215
+ * @private internal utility <- TODO: [🧠] Maybe export from `@promptbook/types`
32534
32216
  */
32535
- function filterOverwrittenCommitments(commitments) {
32536
- const seenOverwriteGroups = new Set();
32537
- const keptCommitments = [];
32538
- for (let index = commitments.length - 1; index >= 0; index--) {
32539
- const commitment = commitments[index];
32540
- const overwriteGroup = OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE.get(commitment.type);
32541
- if (!overwriteGroup) {
32542
- keptCommitments.push(commitment);
32543
- continue;
32217
+ function asUpdatableSubject(value) {
32218
+ if (value instanceof BehaviorSubject) {
32219
+ return value;
32220
+ }
32221
+ else if (Array.isArray(value)) {
32222
+ if (value.length !== 2) {
32223
+ throw new TypeError('`asUpdatableSubject`: Invalid tuple length, expected 2 elements');
32544
32224
  }
32545
- if (seenOverwriteGroups.has(overwriteGroup)) {
32546
- continue;
32225
+ if (typeof value[1] !== 'function') {
32226
+ throw new TypeError('`asUpdatableSubject`: Invalid tuple, expected second element to be a function');
32547
32227
  }
32548
- seenOverwriteGroups.add(overwriteGroup);
32549
- keptCommitments.push(commitment);
32228
+ const [theValue, setValue] = value;
32229
+ const subject = new BehaviorSubject(theValue);
32230
+ subject.subscribe((newValue) => {
32231
+ setValue(newValue);
32232
+ });
32233
+ return subject;
32234
+ }
32235
+ else {
32236
+ return new BehaviorSubject(value);
32550
32237
  }
32551
- return keptCommitments.reverse();
32552
32238
  }
32239
+ // TODO: [🧠] Maybe `BehaviorSubject` is too heavy for this use case, maybe just tuple `[value,setValue]` is enough
32240
+
32553
32241
  /**
32554
- * Creates the initial requirements object with the parsed agent name stored in metadata and an optional model override.
32555
- *
32556
- * @param agentName - Parsed agent name from the source prelude.
32557
- * @param modelName - Optional explicit model name override.
32558
- * @returns Initial requirements before any commitment is applied.
32242
+ * Creates an empty/basic agent model requirements object
32243
+ * This serves as the starting point for the reduce-like pattern
32244
+ * where each commitment applies its changes to build the final requirements
32559
32245
  *
32560
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32246
+ * @public exported from `@promptbook/core`
32561
32247
  */
32562
- function createInitialAgentModelRequirements(agentName, modelName) {
32563
- const initialRequirements = createBasicAgentModelRequirements(agentName);
32564
- const requirementsWithMetadata = {
32565
- ...initialRequirements,
32566
- _metadata: {
32567
- ...initialRequirements._metadata,
32568
- agentName,
32569
- },
32570
- };
32571
- if (!modelName) {
32572
- return requirementsWithMetadata;
32573
- }
32248
+ function createEmptyAgentModelRequirements() {
32574
32249
  return {
32575
- ...requirementsWithMetadata,
32576
- modelName,
32250
+ systemMessage: '',
32251
+ promptSuffix: '',
32252
+ // modelName: 'gpt-5',
32253
+ modelName: 'gpt-5.4-mini',
32254
+ temperature: 0.7,
32255
+ topP: 0.9,
32256
+ topK: 50,
32257
+ parentAgentUrl: null,
32258
+ isClosed: false,
32577
32259
  };
32578
32260
  }
32579
32261
  /**
32580
- * Applies DELETE-like invalidation commitments and returns only commitments that should continue through the pipeline.
32581
- *
32582
- * @param commitments - Parsed commitments in original source order.
32583
- * @returns Filtered commitments with earlier deleted items removed.
32262
+ * Creates a basic agent model requirements with just the agent name
32263
+ * This is used when we have an agent name but no commitments
32584
32264
  *
32585
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32265
+ * @public exported from `@promptbook/core`
32586
32266
  */
32587
- function filterDeletedCommitments(commitments) {
32588
- const filteredCommitments = [];
32589
- for (const commitment of commitments) {
32590
- if (!isDeleteCommitmentType(commitment.type)) {
32591
- filteredCommitments.push(commitment);
32592
- continue;
32593
- }
32594
- const targetParameterNames = getCommitmentParameterNames(commitment.content);
32595
- if (targetParameterNames.length === 0) {
32596
- continue;
32597
- }
32598
- for (let index = filteredCommitments.length - 1; index >= 0; index--) {
32599
- const previousCommitment = filteredCommitments[index];
32600
- const previousParameterNames = getCommitmentParameterNames(previousCommitment.content);
32601
- const isTargeted = previousParameterNames.some((parameterName) => targetParameterNames.includes(parameterName));
32602
- if (isTargeted) {
32603
- filteredCommitments.splice(index, 1);
32604
- }
32605
- }
32606
- }
32607
- return filteredCommitments;
32267
+ function createBasicAgentModelRequirements(agentName) {
32268
+ const empty = createEmptyAgentModelRequirements();
32269
+ return {
32270
+ ...empty,
32271
+ systemMessage: `You are ${agentName || 'AI Agent'}`,
32272
+ };
32608
32273
  }
32274
+ // TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
32275
+
32609
32276
  /**
32610
- * Checks whether a commitment type behaves like DELETE and therefore invalidates earlier tagged commitments.
32277
+ * Gets a commitment definition by its type
32611
32278
  *
32612
- * @param commitmentType - Commitment type to check.
32613
- * @returns `true` when the commitment removes prior tagged commitments.
32279
+ * @param type The commitment type to look up
32280
+ * @returns The commitment definition or null if not found
32614
32281
  *
32615
- * @private internal utility of `filterDeletedCommitments`
32282
+ * @public exported from `@promptbook/core`
32616
32283
  */
32617
- function isDeleteCommitmentType(commitmentType) {
32618
- return DELETE_COMMITMENT_TYPES.has(commitmentType);
32284
+ function getCommitmentDefinition(type) {
32285
+ return COMMITMENT_REGISTRY.find((commitmentDefinition) => commitmentDefinition.type === type) || null;
32619
32286
  }
32287
+
32620
32288
  /**
32621
- * Extracts normalized parameter names used for DELETE-like invalidation matching.
32622
- *
32623
- * @param content - Commitment content to parse.
32624
- * @returns Lower-cased non-empty parameter names.
32289
+ * Commitment types whose content may contain compact agent references that must be resolved before applying the commitment.
32625
32290
  *
32626
- * @private internal utility of `filterDeletedCommitments`
32291
+ * @private internal constant of `applyCommitmentsToAgentModelRequirements`
32627
32292
  */
32628
- function getCommitmentParameterNames(content) {
32629
- return parseParameters(content)
32630
- .map((parameter) => parameter.name.trim().toLowerCase())
32631
- .filter(Boolean);
32632
- }
32293
+ const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS', 'TEAM']);
32633
32294
  /**
32634
32295
  * Applies parsed commitments one by one while keeping the per-commitment steps focused and easy to follow.
32635
32296
  *
@@ -32638,9 +32299,9 @@ function getCommitmentParameterNames(content) {
32638
32299
  * @param options - Optional reference and teammate resolvers.
32639
32300
  * @returns Requirements after all applicable commitments are processed.
32640
32301
  *
32641
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32302
+ * @private function of `createAgentModelRequirementsWithCommitments`
32642
32303
  */
32643
- async function applyCommitmentsToRequirements(requirements, commitments, options) {
32304
+ async function applyCommitmentsToAgentModelRequirements(requirements, commitments, options) {
32644
32305
  for (const [index, commitment] of commitments.entries()) {
32645
32306
  if (shouldSkipCommitmentApplication(commitment, index, commitments.length)) {
32646
32307
  continue;
@@ -32658,7 +32319,7 @@ async function applyCommitmentsToRequirements(requirements, commitments, options
32658
32319
  * @param agentReferenceResolver - Optional resolver for compact agent references.
32659
32320
  * @returns Original or resolved commitment content.
32660
32321
  *
32661
- * @private internal utility of `applyCommitmentsToRequirements`
32322
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
32662
32323
  */
32663
32324
  async function resolveCommitmentContent(commitment, agentReferenceResolver) {
32664
32325
  if (!agentReferenceResolver || !isAgentReferenceCommitment(commitment.type)) {
@@ -32672,6 +32333,24 @@ async function resolveCommitmentContent(commitment, agentReferenceResolver) {
32672
32333
  return getSafeReferenceCommitmentFallback(commitment.type, commitment.content);
32673
32334
  }
32674
32335
  }
32336
+ /**
32337
+ * Returns a safe fallback content when a resolver fails to transform a reference commitment.
32338
+ *
32339
+ * @param commitmentType - Commitment being resolved.
32340
+ * @param originalContent - Original unresolved commitment content.
32341
+ * @returns Fallback content that keeps requirement creation resilient.
32342
+ *
32343
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
32344
+ */
32345
+ function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
32346
+ if (commitmentType === 'FROM') {
32347
+ return 'VOID';
32348
+ }
32349
+ if (commitmentType === 'IMPORT' || commitmentType === 'IMPORTS' || commitmentType === 'TEAM') {
32350
+ return '';
32351
+ }
32352
+ return originalContent;
32353
+ }
32675
32354
  /**
32676
32355
  * Checks whether the commitment content may need agent-reference resolution before application.
32677
32356
  *
@@ -32691,7 +32370,7 @@ function isAgentReferenceCommitment(commitmentType) {
32691
32370
  * @param commitmentCount - Total number of filtered commitments.
32692
32371
  * @returns `true` when the commitment should not be applied.
32693
32372
  *
32694
- * @private internal utility of `applyCommitmentsToRequirements`
32373
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
32695
32374
  */
32696
32375
  function shouldSkipCommitmentApplication(commitment, commitmentIndex, commitmentCount) {
32697
32376
  return commitment.type === 'CLOSED' && commitmentIndex !== commitmentCount - 1;
@@ -32705,7 +32384,7 @@ function shouldSkipCommitmentApplication(commitment, commitmentIndex, commitment
32705
32384
  * @param options - Optional teammate profile resolvers.
32706
32385
  * @returns Requirements with pre-resolved teammate profiles stored in metadata when possible.
32707
32386
  *
32708
- * @private internal utility of `applyCommitmentsToRequirements`
32387
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
32709
32388
  */
32710
32389
  async function preResolveTeammateProfilesForTeamCommitment(requirements, commitment, commitmentContent, options) {
32711
32390
  var _a;
@@ -32760,7 +32439,7 @@ function clonePreResolvedTeammateProfiles(metadata) {
32760
32439
  * @param commitmentContent - Final content passed into the definition.
32761
32440
  * @returns Updated requirements, or the original requirements when the commitment fails.
32762
32441
  *
32763
- * @private internal utility of `applyCommitmentsToRequirements`
32442
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
32764
32443
  */
32765
32444
  function applyCommitmentDefinitionSafely(requirements, commitment, commitmentContent) {
32766
32445
  const definition = getCommitmentDefinition(commitment.type);
@@ -32775,13 +32454,140 @@ function applyCommitmentDefinitionSafely(requirements, commitment, commitmentCon
32775
32454
  return requirements;
32776
32455
  }
32777
32456
  }
32457
+
32458
+ /**
32459
+ * Plugin for importing agent books *(`.book` files)*
32460
+ *
32461
+ * @private [🥝] Maybe export the import plugins through some package
32462
+ */
32463
+ const AgentFileImportPlugin = {
32464
+ name: 'agent-file-import-plugin',
32465
+ canImport(mimeType) {
32466
+ // [🧠] Should we have a specific MIME type for agent books?
32467
+ // For now, let's assume it's identified by .book extension or certain MIME types if provided
32468
+ return mimeType === 'text/x-promptbook' || mimeType === 'application/x-promptbook';
32469
+ },
32470
+ import(content) {
32471
+ const parseResult = parseAgentSourceWithCommitments(content);
32472
+ // Bring only the agent corpus (non-commitment lines and relevant commitments)
32473
+ // Stripping the agent name (which is usually the first line)
32474
+ const corpus = parseResult.nonCommitmentLines
32475
+ .filter((line, index) => index > 0 || !parseResult.agentName)
32476
+ .join('\n')
32477
+ .trim();
32478
+ // Also include relevant commitments that make up the "corpus" of the agent
32479
+ // For example PERSONA, RULE, KNOWLEDGE
32480
+ const relevantCommitments = parseResult.commitments
32481
+ .filter((c) => ['PERSONA', 'RULE', 'KNOWLEDGE'].includes(c.type))
32482
+ .map((c) => `${c.type} ${c.content}`)
32483
+ .join('\n\n');
32484
+ return spaceTrim$1((block) => `
32485
+ ${block(relevantCommitments)}
32486
+
32487
+ ${block(corpus)}
32488
+ `).trim();
32489
+ },
32490
+ };
32491
+
32492
+ /**
32493
+ * Plugin for importing JSON files
32494
+ *
32495
+ * @private [🥝] Maybe export the import plugins through some package
32496
+ */
32497
+ const JsonFileImportPlugin = {
32498
+ name: 'json-file-import-plugin',
32499
+ canImport(mimeType) {
32500
+ return mimeType === 'application/json' || mimeType.endsWith('+json');
32501
+ },
32502
+ import(content) {
32503
+ try {
32504
+ const json = JSON.parse(content);
32505
+ const formattedJson = JSON.stringify(json, null, 4);
32506
+ return `\`\`\`json\n${formattedJson}\n\`\`\``;
32507
+ }
32508
+ catch (error) {
32509
+ // If JSON is invalid, still import it but maybe not as pretty JSON
32510
+ return `\`\`\`json\n${content}\n\`\`\``;
32511
+ }
32512
+ },
32513
+ };
32514
+
32515
+ /**
32516
+ * Plugin for importing generic text files
32517
+ *
32518
+ * @private [🥝] Maybe export the import plugins through some package
32519
+ */
32520
+ const TextFileImportPlugin = {
32521
+ name: 'text-file-import-plugin',
32522
+ canImport(mimeType) {
32523
+ return (mimeType === 'text/plain' ||
32524
+ mimeType === 'text/markdown' ||
32525
+ mimeType === 'text/x-typescript' ||
32526
+ mimeType === 'text/javascript' ||
32527
+ mimeType === 'text/css' ||
32528
+ mimeType === 'text/html' ||
32529
+ mimeType.startsWith('text/'));
32530
+ },
32531
+ import(content, mimeType) {
32532
+ const extension = mimeTypeToExtension(mimeType);
32533
+ const codeBlockType = extension || 'txt';
32534
+ return `\`\`\`${codeBlockType}\n${content}\n\`\`\``;
32535
+ },
32536
+ };
32537
+
32538
+ /**
32539
+ * All available file import plugins
32540
+ *
32541
+ * @private [🥝] Maybe export the import plugins through some package
32542
+ */
32543
+ const $fileImportPlugins = [
32544
+ AgentFileImportPlugin,
32545
+ JsonFileImportPlugin,
32546
+ TextFileImportPlugin,
32547
+ ];
32548
+
32549
+ /**
32550
+ * Regex pattern matching markdown horizontal lines that should not be copied into the final system message.
32551
+ *
32552
+ * @private internal constant of `augmentAgentModelRequirementsFromSource`
32553
+ */
32554
+ const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
32555
+ /**
32556
+ * MIME type prefixes treated as binary and therefore not eligible for text import plugins.
32557
+ *
32558
+ * @private internal constant of `augmentAgentModelRequirementsFromSource`
32559
+ */
32560
+ const BINARY_MIME_TYPE_PREFIXES = [
32561
+ 'image/',
32562
+ 'video/',
32563
+ 'audio/',
32564
+ 'application/octet-stream',
32565
+ 'application/pdf',
32566
+ 'application/zip',
32567
+ ];
32568
+ /**
32569
+ * Adds source-derived sections after commitments have been applied.
32570
+ *
32571
+ * @param requirements - Requirements after commitment application and USE aggregation.
32572
+ * @param parseResult - Parsed source used to recover non-commitment prose and examples.
32573
+ * @param agentSource - Original source used to recover MCP server declarations.
32574
+ * @returns Requirements with source-derived sections appended.
32575
+ *
32576
+ * @private function of `createAgentModelRequirementsWithCommitments`
32577
+ */
32578
+ async function augmentAgentModelRequirementsFromSource(requirements, parseResult, agentSource) {
32579
+ requirements = await importReferencedFiles(requirements);
32580
+ requirements = appendMcpServers(requirements, agentSource);
32581
+ requirements = appendNonCommitmentContent(requirements, parseResult);
32582
+ return appendExampleInteractions(requirements, parseResult);
32583
+ }
32778
32584
  /**
32779
32585
  * Imports text files referenced by IMPORT commitments and appends their transformed content to the system message.
32780
32586
  *
32781
32587
  * @param requirements - Requirements possibly containing `importedFileUrls`.
32782
32588
  * @returns Requirements with imported file content appended to the system message.
32783
32589
  *
32784
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32590
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
32785
32591
  */
32786
32592
  async function importReferencedFiles(requirements) {
32787
32593
  const importedFileUrls = requirements.importedFileUrls;
@@ -32867,7 +32673,7 @@ function normalizeImportedMimeType(mimeType) {
32867
32673
  * @param agentSource - Original agent source used for MCP extraction.
32868
32674
  * @returns Requirements with `mcpServers` set when MCP commitments are present.
32869
32675
  *
32870
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32676
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
32871
32677
  */
32872
32678
  function appendMcpServers(requirements, agentSource) {
32873
32679
  const mcpServers = extractMcpServers(agentSource);
@@ -32886,7 +32692,7 @@ function appendMcpServers(requirements, agentSource) {
32886
32692
  * @param parseResult - Parsed source including non-commitment lines.
32887
32693
  * @returns Requirements with the remaining prose appended to the system message.
32888
32694
  *
32889
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32695
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
32890
32696
  */
32891
32697
  function appendNonCommitmentContent(requirements, parseResult) {
32892
32698
  const nonCommitmentContent = getNonCommitmentContent(parseResult);
@@ -32929,7 +32735,7 @@ function isHorizontalLine(line) {
32929
32735
  * @param parseResult - Parsed source used to recover initial message content.
32930
32736
  * @returns Requirements with the example interaction block appended when examples exist.
32931
32737
  *
32932
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32738
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
32933
32739
  */
32934
32740
  function appendExampleInteractions(requirements, parseResult) {
32935
32741
  const exampleInteractionsContent = createExampleInteractionsContent(parseResult, requirements.samples);
@@ -32984,7 +32790,7 @@ function collectExampleInteractionLines(parseResult, samples) {
32984
32790
  * @param section - Section content to append.
32985
32791
  * @returns Requirements with the additional system-message block appended.
32986
32792
  *
32987
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32793
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
32988
32794
  */
32989
32795
  function appendSystemMessageSection(requirements, section) {
32990
32796
  return {
@@ -32993,29 +32799,149 @@ function appendSystemMessageSection(requirements, section) {
32993
32799
  };
32994
32800
  }
32995
32801
  /**
32996
- * Performs the final system-message cleanup pass after all other augmentation steps are complete.
32802
+ * Mocked security check for imported files.
32997
32803
  *
32998
- * @param requirements - Fully built requirements before final cleanup.
32999
- * @returns Requirements with comment lines removed from the final system message.
32804
+ * @param urlOrPath - The URL or local path of the file to check.
32805
+ * @returns A promise that resolves if the file is considered safe.
33000
32806
  *
33001
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32807
+ * @private internal utility of `createImportedFileSystemMessage`
33002
32808
  */
33003
- function finalizeRequirements(requirements) {
33004
- return {
33005
- ...requirements,
33006
- systemMessage: removeCommentsFromSystemMessage(requirements.systemMessage),
33007
- };
32809
+ async function mockedSecurityCheck(urlOrPath) {
32810
+ // TODO: Implement proper security checks
32811
+ await new Promise((resolve) => setTimeout(resolve, 10));
32812
+ if (urlOrPath.includes('malicious')) {
32813
+ throw new Error(`Security check failed for: ${urlOrPath}`);
32814
+ }
32815
+ }
32816
+ /**
32817
+ * Checks whether the given MIME type belongs to a binary file.
32818
+ *
32819
+ * @param mimeType - The MIME type to check.
32820
+ * @returns `true` when the MIME type is treated as binary.
32821
+ *
32822
+ * @private internal utility of `createImportedFileSystemMessage`
32823
+ */
32824
+ function isBinaryMimeType(mimeType) {
32825
+ return BINARY_MIME_TYPE_PREFIXES.some((prefix) => mimeType.startsWith(prefix));
32826
+ }
32827
+
32828
+ /**
32829
+ * DELETE-like commitment types that invalidate earlier tagged commitments.
32830
+ *
32831
+ * @private internal constant of `filterCommitmentsForAgentModelRequirements`
32832
+ */
32833
+ const DELETE_COMMITMENT_TYPES = new Set(['DELETE', 'CANCEL', 'DISCARD', 'REMOVE']);
32834
+ /**
32835
+ * Commitments whose earlier occurrences are overwritten by the last occurrence in source order.
32836
+ *
32837
+ * @private internal constant of `filterCommitmentsForAgentModelRequirements`
32838
+ */
32839
+ const OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE = new Map([
32840
+ ['GOAL', 'GOAL'],
32841
+ ['GOALS', 'GOAL'],
32842
+ ]);
32843
+ /**
32844
+ * Applies the commitment filtering rules used before commitment definitions are executed.
32845
+ *
32846
+ * @param commitments - Parsed commitments in original source order.
32847
+ * @returns Commitments after DELETE-like invalidation and overwritten-goal filtering.
32848
+ *
32849
+ * @private function of `createAgentModelRequirementsWithCommitments`
32850
+ */
32851
+ function filterCommitmentsForAgentModelRequirements(commitments) {
32852
+ return filterOverwrittenCommitments(filterDeletedCommitments(commitments));
32853
+ }
32854
+ /**
32855
+ * Removes earlier commitments that are overwritten by later commitments of the same semantic group.
32856
+ *
32857
+ * @param commitments - Parsed commitments after DELETE-like filtering.
32858
+ * @returns Commitments with overwritten entries removed while preserving source order.
32859
+ *
32860
+ * @private internal utility of `filterCommitmentsForAgentModelRequirements`
32861
+ */
32862
+ function filterOverwrittenCommitments(commitments) {
32863
+ const seenOverwriteGroups = new Set();
32864
+ const keptCommitments = [];
32865
+ for (let index = commitments.length - 1; index >= 0; index--) {
32866
+ const commitment = commitments[index];
32867
+ const overwriteGroup = OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE.get(commitment.type);
32868
+ if (!overwriteGroup) {
32869
+ keptCommitments.push(commitment);
32870
+ continue;
32871
+ }
32872
+ if (seenOverwriteGroups.has(overwriteGroup)) {
32873
+ continue;
32874
+ }
32875
+ seenOverwriteGroups.add(overwriteGroup);
32876
+ keptCommitments.push(commitment);
32877
+ }
32878
+ return keptCommitments.reverse();
32879
+ }
32880
+ /**
32881
+ * Applies DELETE-like invalidation commitments and returns only commitments that should continue through the pipeline.
32882
+ *
32883
+ * @param commitments - Parsed commitments in original source order.
32884
+ * @returns Filtered commitments with earlier deleted items removed.
32885
+ *
32886
+ * @private internal utility of `filterCommitmentsForAgentModelRequirements`
32887
+ */
32888
+ function filterDeletedCommitments(commitments) {
32889
+ const filteredCommitments = [];
32890
+ for (const commitment of commitments) {
32891
+ if (!isDeleteCommitmentType(commitment.type)) {
32892
+ filteredCommitments.push(commitment);
32893
+ continue;
32894
+ }
32895
+ const targetParameterNames = getCommitmentParameterNames(commitment.content);
32896
+ if (targetParameterNames.length === 0) {
32897
+ continue;
32898
+ }
32899
+ for (let index = filteredCommitments.length - 1; index >= 0; index--) {
32900
+ const previousCommitment = filteredCommitments[index];
32901
+ const previousParameterNames = getCommitmentParameterNames(previousCommitment.content);
32902
+ const isTargeted = previousParameterNames.some((parameterName) => targetParameterNames.includes(parameterName));
32903
+ if (isTargeted) {
32904
+ filteredCommitments.splice(index, 1);
32905
+ }
32906
+ }
32907
+ }
32908
+ return filteredCommitments;
32909
+ }
32910
+ /**
32911
+ * Checks whether a commitment type behaves like DELETE and therefore invalidates earlier tagged commitments.
32912
+ *
32913
+ * @param commitmentType - Commitment type to check.
32914
+ * @returns `true` when the commitment removes prior tagged commitments.
32915
+ *
32916
+ * @private internal utility of `filterDeletedCommitments`
32917
+ */
32918
+ function isDeleteCommitmentType(commitmentType) {
32919
+ return DELETE_COMMITMENT_TYPES.has(commitmentType);
32920
+ }
32921
+ /**
32922
+ * Extracts normalized parameter names used for DELETE-like invalidation matching.
32923
+ *
32924
+ * @param content - Commitment content to parse.
32925
+ * @returns Lower-cased non-empty parameter names.
32926
+ *
32927
+ * @private internal utility of `filterDeletedCommitments`
32928
+ */
32929
+ function getCommitmentParameterNames(content) {
32930
+ return parseParameters(content)
32931
+ .map((parameter) => parameter.name.trim().toLowerCase())
32932
+ .filter(Boolean);
33008
32933
  }
32934
+
33009
32935
  /**
33010
- * Attempts to upload inline knowledge entries, falling back to legacy data URLs when the upload fails or is not configured.
32936
+ * Converts staged inline knowledge files into the final knowledge source URLs stored on requirements.
33011
32937
  *
33012
32938
  * @param requirements - Current requirements snapshot.
33013
32939
  * @param uploader - Optional uploader for inline knowledge files.
33014
32940
  * @returns Requirements with inline knowledge converted into upload URLs or data URLs.
33015
32941
  *
33016
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
32942
+ * @private function of `createAgentModelRequirementsWithCommitments`
33017
32943
  */
33018
- async function applyPendingInlineKnowledgeSources(requirements, uploader) {
32944
+ async function materializeInlineKnowledgeSources(requirements, uploader) {
33019
32945
  var _a;
33020
32946
  const inlineSources = extractInlineKnowledgeSources(requirements._metadata);
33021
32947
  if (inlineSources.length === 0) {
@@ -33041,7 +32967,7 @@ async function applyPendingInlineKnowledgeSources(requirements, uploader) {
33041
32967
  * @param uploader - Upload implementation provided by the caller.
33042
32968
  * @returns Uploaded knowledge URL or a legacy data URL fallback.
33043
32969
  *
33044
- * @private internal utility of `applyPendingInlineKnowledgeSources`
32970
+ * @private internal utility of `materializeInlineKnowledgeSources`
33045
32971
  */
33046
32972
  async function uploadInlineKnowledgeSourceWithFallback(inlineSource, uploader) {
33047
32973
  try {
@@ -33061,7 +32987,7 @@ async function uploadInlineKnowledgeSourceWithFallback(inlineSource, uploader) {
33061
32987
  * @param metadata - Current requirements metadata.
33062
32988
  * @returns Inline knowledge files collected during commitment application.
33063
32989
  *
33064
- * @private internal utility of `applyPendingInlineKnowledgeSources`
32990
+ * @private internal utility of `materializeInlineKnowledgeSources`
33065
32991
  */
33066
32992
  function extractInlineKnowledgeSources(metadata) {
33067
32993
  if (!metadata) {
@@ -33076,7 +33002,7 @@ function extractInlineKnowledgeSources(metadata) {
33076
33002
  * @param metadata - Current requirements metadata.
33077
33003
  * @returns Metadata without the temporary inline knowledge staging field.
33078
33004
  *
33079
- * @private internal utility of `applyPendingInlineKnowledgeSources`
33005
+ * @private internal utility of `materializeInlineKnowledgeSources`
33080
33006
  */
33081
33007
  function stripInlineKnowledgeMetadata(metadata) {
33082
33008
  if (!metadata || !Object.prototype.hasOwnProperty.call(metadata, 'inlineKnowledgeSources')) {
@@ -33085,31 +33011,90 @@ function stripInlineKnowledgeMetadata(metadata) {
33085
33011
  const { inlineKnowledgeSources: _unusedInlineKnowledgeSources, ...rest } = metadata;
33086
33012
  return Object.keys(rest).length > 0 ? rest : undefined;
33087
33013
  }
33014
+
33088
33015
  /**
33089
- * Mocked security check for imported files.
33016
+ * Removes single-hash comment lines (`# Comment`) from a system message
33017
+ * This is used to clean up the final system message before sending it to the AI model
33018
+ * while preserving the original content with comments in metadata
33090
33019
  *
33091
- * @param urlOrPath - The URL or local path of the file to check.
33092
- * @returns A promise that resolves if the file is considered safe.
33020
+ * @param systemMessage The system message that may contain comment lines
33021
+ * @returns The system message with single-hash comment lines removed
33093
33022
  *
33094
- * @private internal utility of `createImportedFileSystemMessage`
33023
+ * @private - TODO: [🧠] Maybe should be public?
33095
33024
  */
33096
- async function mockedSecurityCheck(urlOrPath) {
33097
- // TODO: Implement proper security checks
33098
- await new Promise((resolve) => setTimeout(resolve, 10));
33099
- if (urlOrPath.includes('malicious')) {
33100
- throw new Error(`Security check failed for: ${urlOrPath}`);
33025
+ function removeCommentsFromSystemMessage(systemMessage) {
33026
+ if (!systemMessage) {
33027
+ return systemMessage;
33028
+ }
33029
+ const lines = systemMessage.split(/\r?\n/);
33030
+ const filteredLines = lines.filter((line) => {
33031
+ const trimmedLine = line.trim();
33032
+ // Remove only single-hash comment markers (`# Comment`) and keep markdown headings (`## Heading`).
33033
+ return !/^#(?!#)\s/.test(trimmedLine);
33034
+ });
33035
+ return filteredLines.join('\n').trim();
33036
+ }
33037
+
33038
+ /**
33039
+ * Creates agent model requirements by parsing commitments, applying them in source order,
33040
+ * and finalizing derived sections such as imports, example interactions, and inline knowledge uploads.
33041
+ *
33042
+ * @param agentSource - Agent source book to parse.
33043
+ * @param modelName - Optional override for the agent model name.
33044
+ * @param options - Additional options such as reference and teammate resolvers.
33045
+ * @returns Fully prepared model requirements for the parsed agent source.
33046
+ *
33047
+ * @private internal utility of `createAgentModelRequirements`
33048
+ */
33049
+ async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
33050
+ const parseResult = parseAgentSourceWithCommitments(agentSource);
33051
+ const filteredCommitments = filterCommitmentsForAgentModelRequirements(parseResult.commitments);
33052
+ let requirements = createInitialAgentModelRequirements(parseResult.agentName, modelName);
33053
+ requirements = await applyCommitmentsToAgentModelRequirements(requirements, filteredCommitments, options);
33054
+ requirements = aggregateUseCommitmentSystemMessages(requirements, filteredCommitments);
33055
+ requirements = await augmentAgentModelRequirementsFromSource(requirements, parseResult, agentSource);
33056
+ requirements = await materializeInlineKnowledgeSources(requirements, options === null || options === void 0 ? void 0 : options.inlineKnowledgeSourceUploader);
33057
+ return finalizeRequirements(requirements);
33058
+ }
33059
+ /**
33060
+ * Creates the initial requirements object with the parsed agent name stored in metadata and an optional model override.
33061
+ *
33062
+ * @param agentName - Parsed agent name from the source prelude.
33063
+ * @param modelName - Optional explicit model name override.
33064
+ * @returns Initial requirements before any commitment is applied.
33065
+ *
33066
+ * @private internal utility of `createAgentModelRequirementsWithCommitments`
33067
+ */
33068
+ function createInitialAgentModelRequirements(agentName, modelName) {
33069
+ const initialRequirements = createBasicAgentModelRequirements(agentName);
33070
+ const requirementsWithMetadata = {
33071
+ ...initialRequirements,
33072
+ _metadata: {
33073
+ ...initialRequirements._metadata,
33074
+ agentName,
33075
+ },
33076
+ };
33077
+ if (!modelName) {
33078
+ return requirementsWithMetadata;
33101
33079
  }
33080
+ return {
33081
+ ...requirementsWithMetadata,
33082
+ modelName,
33083
+ };
33102
33084
  }
33103
33085
  /**
33104
- * Checks whether the given MIME type belongs to a binary file.
33086
+ * Performs the final system-message cleanup pass after all other augmentation steps are complete.
33105
33087
  *
33106
- * @param mimeType - The MIME type to check.
33107
- * @returns `true` when the MIME type is treated as binary.
33088
+ * @param requirements - Fully built requirements before final cleanup.
33089
+ * @returns Requirements with comment lines removed from the final system message.
33108
33090
  *
33109
- * @private internal utility of `createImportedFileSystemMessage`
33091
+ * @private internal utility of `createAgentModelRequirementsWithCommitments`
33110
33092
  */
33111
- function isBinaryMimeType(mimeType) {
33112
- return BINARY_MIME_TYPE_PREFIXES.some((prefix) => mimeType.startsWith(prefix));
33093
+ function finalizeRequirements(requirements) {
33094
+ return {
33095
+ ...requirements,
33096
+ systemMessage: removeCommentsFromSystemMessage(requirements.systemMessage),
33097
+ };
33113
33098
  }
33114
33099
 
33115
33100
  /**