@promptbook/components 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 +1177 -1192
  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 +1 -1
  20. package/umd/index.umd.js +1177 -1192
  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
@@ -40,7 +40,7 @@ const BOOK_LANGUAGE_VERSION = '2.0.0';
40
40
  * @generated
41
41
  * @see https://github.com/webgptorg/promptbook
42
42
  */
43
- const PROMPTBOOK_ENGINE_VERSION = '0.112.0-56';
43
+ const PROMPTBOOK_ENGINE_VERSION = '0.112.0-57';
44
44
  /**
45
45
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
46
46
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -4899,403 +4899,6 @@ function AvatarChip(props) {
4899
4899
  return (jsxs("div", { className: classNames(styles$f.AvatarChip, className, isSelected ? styles$f.Selected : undefined), onClick: () => onSelect === null || onSelect === void 0 ? void 0 : onSelect(avatarBasicInformation), style: { cursor: onSelect ? 'pointer' : undefined }, children: [avatarUrl && jsx("img", { src: avatarUrl, alt: agentName || '', className: styles$f.Avatar }), meta.fullname || agentName, isTemplate && jsx("span", { className: styles$f.TemplateLabel, children: "Template" })] }));
4900
4900
  }
4901
4901
 
4902
- /**
4903
- * Hostnames accepted for GitHub repository references.
4904
- *
4905
- * @private internal USE PROJECT constant
4906
- */
4907
- const GITHUB_HOSTNAMES = new Set(['github.com', 'www.github.com']);
4908
- /**
4909
- * Pattern for validating owner/repository slugs.
4910
- *
4911
- * @private internal USE PROJECT constant
4912
- */
4913
- const GITHUB_REPOSITORY_SLUG_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
4914
- /**
4915
- * Parses a repository reference into canonical owner/repository details.
4916
- *
4917
- * Supported input forms:
4918
- * - `https://github.com/owner/repository`
4919
- * - `github.com/owner/repository`
4920
- * - `owner/repository`
4921
- * - optional `.git` suffix and trailing slash are supported
4922
- *
4923
- * @private internal utility of USE PROJECT commitment
4924
- */
4925
- function parseGitHubRepositoryReference(rawReference) {
4926
- const trimmedReference = rawReference.trim();
4927
- if (!trimmedReference) {
4928
- return null;
4929
- }
4930
- const normalizedReference = trimmedReference.replace(/\/+$/g, '');
4931
- if (normalizedReference.startsWith('http://') || normalizedReference.startsWith('https://')) {
4932
- return parseGitHubRepositoryReferenceFromUrl(normalizedReference);
4933
- }
4934
- if (normalizedReference.startsWith('github.com/')) {
4935
- return parseGitHubRepositoryReferenceFromUrl(`https://${normalizedReference}`);
4936
- }
4937
- if (!GITHUB_REPOSITORY_SLUG_PATTERN.test(normalizedReference)) {
4938
- return null;
4939
- }
4940
- const [owner, repositoryRaw] = normalizedReference.split('/');
4941
- if (!owner || !repositoryRaw) {
4942
- return null;
4943
- }
4944
- const repository = repositoryRaw.replace(/\.git$/i, '');
4945
- if (!isValidGitHubRepositoryPart(owner) || !isValidGitHubRepositoryPart(repository)) {
4946
- return null;
4947
- }
4948
- return createGitHubRepositoryReference(owner, repository);
4949
- }
4950
- /**
4951
- * Parses `USE PROJECT` commitment content into repository reference + optional instructions.
4952
- *
4953
- * @private internal utility of USE PROJECT commitment
4954
- */
4955
- function parseUseProjectCommitmentContent(content) {
4956
- const trimmedContent = spaceTrim$1(content);
4957
- if (!trimmedContent) {
4958
- return {
4959
- repository: null,
4960
- repositoryReferenceRaw: null,
4961
- instructions: '',
4962
- };
4963
- }
4964
- const lines = trimmedContent
4965
- .split(/\r?\n/)
4966
- .map((line) => line.trim())
4967
- .filter(Boolean);
4968
- if (lines.length === 0) {
4969
- return {
4970
- repository: null,
4971
- repositoryReferenceRaw: null,
4972
- instructions: '',
4973
- };
4974
- }
4975
- const firstLine = lines[0] || '';
4976
- const firstLineTokens = firstLine.split(/\s+/).filter(Boolean);
4977
- let repositoryReferenceRaw = null;
4978
- let repositoryReference = null;
4979
- let repositoryTokenIndex = -1;
4980
- for (let index = 0; index < firstLineTokens.length; index++) {
4981
- const token = firstLineTokens[index] || '';
4982
- const cleanedToken = token.replace(/[),.;:!?]+$/g, '');
4983
- const parsedReference = parseGitHubRepositoryReference(cleanedToken);
4984
- if (!parsedReference) {
4985
- continue;
4986
- }
4987
- repositoryReferenceRaw = cleanedToken;
4988
- repositoryReference = parsedReference;
4989
- repositoryTokenIndex = index;
4990
- break;
4991
- }
4992
- const instructionParts = [];
4993
- if (repositoryTokenIndex >= 0) {
4994
- const firstLineInstruction = firstLineTokens
4995
- .filter((_token, index) => index !== repositoryTokenIndex)
4996
- .join(' ')
4997
- .trim();
4998
- if (firstLineInstruction) {
4999
- instructionParts.push(firstLineInstruction);
5000
- }
5001
- }
5002
- else if (firstLine) {
5003
- instructionParts.push(firstLine);
5004
- }
5005
- if (lines.length > 1) {
5006
- const extraLines = lines.slice(1).join('\n').trim();
5007
- if (extraLines) {
5008
- instructionParts.push(extraLines);
5009
- }
5010
- }
5011
- return {
5012
- repository: repositoryReference,
5013
- repositoryReferenceRaw,
5014
- instructions: instructionParts.join('\n').trim(),
5015
- };
5016
- }
5017
- /**
5018
- * Parses URL-like repository references.
5019
- *
5020
- * @private utility of USE PROJECT commitment
5021
- */
5022
- function parseGitHubRepositoryReferenceFromUrl(rawUrl) {
5023
- let parsedUrl;
5024
- try {
5025
- parsedUrl = new URL(rawUrl);
5026
- }
5027
- catch (_a) {
5028
- return null;
5029
- }
5030
- if (!GITHUB_HOSTNAMES.has(parsedUrl.hostname.toLowerCase())) {
5031
- return null;
5032
- }
5033
- const segments = parsedUrl.pathname.split('/').filter(Boolean);
5034
- if (segments.length < 2) {
5035
- return null;
5036
- }
5037
- const owner = segments[0];
5038
- const repositoryRaw = segments[1];
5039
- if (!owner || !repositoryRaw) {
5040
- return null;
5041
- }
5042
- const repository = repositoryRaw.replace(/\.git$/i, '');
5043
- if (!isValidGitHubRepositoryPart(owner) || !isValidGitHubRepositoryPart(repository)) {
5044
- return null;
5045
- }
5046
- let defaultBranch;
5047
- if (segments[2] === 'tree' && segments[3]) {
5048
- defaultBranch = decodeURIComponent(segments[3]);
5049
- }
5050
- return createGitHubRepositoryReference(owner, repository, defaultBranch);
5051
- }
5052
- /**
5053
- * Validates one owner/repository slug part.
5054
- *
5055
- * @private utility of USE PROJECT commitment
5056
- */
5057
- function isValidGitHubRepositoryPart(value) {
5058
- return /^[A-Za-z0-9_.-]+$/.test(value);
5059
- }
5060
- /**
5061
- * Builds canonical repository reference object.
5062
- *
5063
- * @private utility of USE PROJECT commitment
5064
- */
5065
- function createGitHubRepositoryReference(owner, repository, defaultBranch) {
5066
- const slug = `${owner}/${repository}`;
5067
- return {
5068
- owner,
5069
- repository,
5070
- slug,
5071
- url: `https://github.com/${slug}`,
5072
- defaultBranch,
5073
- };
5074
- }
5075
- // Note: [💞] Ignore a discrepancy between file name and entity name
5076
-
5077
- /**
5078
- * Normalizes a given text to camelCase format.
5079
- *
5080
- * Note: [🔂] This function is idempotent.
5081
- *
5082
- * @param text The text to be normalized.
5083
- * @param _isFirstLetterCapital Whether the first letter should be capitalized.
5084
- * @returns The camelCase formatted string.
5085
- * @example 'helloWorld'
5086
- * @example 'iLovePromptbook'
5087
- *
5088
- * @public exported from `@promptbook/utils`
5089
- */
5090
- function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
5091
- let charType;
5092
- let lastCharType = null;
5093
- let normalizedName = '';
5094
- for (const char of text) {
5095
- let normalizedChar;
5096
- if (/^[a-z]$/.test(char)) {
5097
- charType = 'LOWERCASE';
5098
- normalizedChar = char;
5099
- }
5100
- else if (/^[A-Z]$/.test(char)) {
5101
- charType = 'UPPERCASE';
5102
- normalizedChar = char.toLowerCase();
5103
- }
5104
- else if (/^[0-9]$/.test(char)) {
5105
- charType = 'NUMBER';
5106
- normalizedChar = char;
5107
- }
5108
- else {
5109
- charType = 'OTHER';
5110
- normalizedChar = '';
5111
- }
5112
- if (!lastCharType) {
5113
- if (_isFirstLetterCapital) {
5114
- normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
5115
- }
5116
- }
5117
- else if (charType !== lastCharType &&
5118
- !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
5119
- !(lastCharType === 'NUMBER') &&
5120
- !(charType === 'NUMBER')) {
5121
- normalizedChar = normalizedChar.toUpperCase(); //TODO: [🌺] DRY
5122
- }
5123
- normalizedName += normalizedChar;
5124
- lastCharType = charType;
5125
- }
5126
- return normalizedName;
5127
- }
5128
- // TODO: [🌺] Use some intermediate util splitWords
5129
-
5130
- /**
5131
- * Tests if given string is valid URL.
5132
- *
5133
- * Note: [🔂] This function is idempotent.
5134
- * Note: Dataurl are considered perfectly valid.
5135
- * Note: There are few similar functions:
5136
- * - `isValidUrl` *(this one)* which tests any URL
5137
- * - `isValidAgentUrl` which tests just agent URL
5138
- * - `isValidPipelineUrl` which tests just pipeline URL
5139
- *
5140
- * @public exported from `@promptbook/utils`
5141
- */
5142
- function isValidUrl(url) {
5143
- if (typeof url !== 'string') {
5144
- return false;
5145
- }
5146
- try {
5147
- if (url.startsWith('blob:')) {
5148
- url = url.replace(/^blob:/, '');
5149
- }
5150
- const urlObject = new URL(url /* because fail is handled */);
5151
- if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
5152
- return false;
5153
- }
5154
- return true;
5155
- }
5156
- catch (error) {
5157
- return false;
5158
- }
5159
- }
5160
-
5161
- /**
5162
- * Matches URL-like candidates inside arbitrary text.
5163
- *
5164
- * @private
5165
- */
5166
- const URL_CANDIDATE_PATTERN = /https?:\/\/[^\s<>"'`]+/g;
5167
- /**
5168
- * Trims punctuation that commonly trails URLs in prose.
5169
- *
5170
- * @private
5171
- */
5172
- const TRAILING_PUNCTUATION_PATTERN = /[.,!?;:'"`]+$/;
5173
- /**
5174
- * Extracts all valid URLs from arbitrary text while removing common trailing punctuation.
5175
- *
5176
- * @param text - Input text that may contain one or more URLs.
5177
- * @returns Unique URLs in their first-seen order.
5178
- *
5179
- * @private utility of KNOWLEDGE parsing
5180
- */
5181
- function extractUrlsFromText(text) {
5182
- if (!text) {
5183
- return [];
5184
- }
5185
- const candidates = text.match(URL_CANDIDATE_PATTERN);
5186
- if (!candidates) {
5187
- return [];
5188
- }
5189
- const urls = [];
5190
- const seen = new Set();
5191
- for (const candidate of candidates) {
5192
- const normalizedCandidate = normalizeUrlCandidate(candidate);
5193
- if (!normalizedCandidate) {
5194
- continue;
5195
- }
5196
- if (!isValidUrl(normalizedCandidate)) {
5197
- continue;
5198
- }
5199
- if (seen.has(normalizedCandidate)) {
5200
- continue;
5201
- }
5202
- seen.add(normalizedCandidate);
5203
- urls.push(normalizedCandidate);
5204
- }
5205
- return urls;
5206
- }
5207
- /**
5208
- * Normalizes one extracted URL candidate by stripping trailing punctuation and unmatched closing wrappers.
5209
- *
5210
- * @private
5211
- */
5212
- function normalizeUrlCandidate(candidate) {
5213
- let normalized = candidate.trim();
5214
- if (!normalized) {
5215
- return '';
5216
- }
5217
- let shouldContinue = true;
5218
- while (shouldContinue) {
5219
- const before = normalized;
5220
- normalized = normalized.replace(TRAILING_PUNCTUATION_PATTERN, '');
5221
- normalized = stripTrailingUnmatchedClosing(normalized, '(', ')');
5222
- normalized = stripTrailingUnmatchedClosing(normalized, '[', ']');
5223
- normalized = stripTrailingUnmatchedClosing(normalized, '{', '}');
5224
- normalized = normalized.replace(TRAILING_PUNCTUATION_PATTERN, '');
5225
- shouldContinue = normalized !== before;
5226
- }
5227
- return normalized;
5228
- }
5229
- /**
5230
- * Removes trailing closing wrappers when they are unmatched in the candidate.
5231
- *
5232
- * @private
5233
- */
5234
- function stripTrailingUnmatchedClosing(candidate, openingChar, closingChar) {
5235
- let normalized = candidate;
5236
- while (normalized.endsWith(closingChar)) {
5237
- const openingCount = countOccurrences(normalized, openingChar);
5238
- const closingCount = countOccurrences(normalized, closingChar);
5239
- if (closingCount <= openingCount) {
5240
- break;
5241
- }
5242
- normalized = normalized.slice(0, -1);
5243
- }
5244
- return normalized;
5245
- }
5246
- /**
5247
- * Counts character occurrences in a string.
5248
- *
5249
- * @private
5250
- */
5251
- function countOccurrences(value, searchedChar) {
5252
- let count = 0;
5253
- for (const currentChar of value) {
5254
- if (currentChar === searchedChar) {
5255
- count++;
5256
- }
5257
- }
5258
- return count;
5259
- }
5260
-
5261
- /**
5262
- * Normalizes a domain-like string into a comparable hostname form.
5263
- *
5264
- * The returned value is lowercased and stripped to hostname only
5265
- * (protocol, path, query, hash, and port are removed).
5266
- *
5267
- * @param rawDomain - Raw domain value (for example `my-agent.com` or `https://my-agent.com/path`).
5268
- * @returns Normalized hostname or `null` when the value cannot be normalized.
5269
- *
5270
- * @private utility for host/domain matching
5271
- */
5272
- function normalizeDomainForMatching(rawDomain) {
5273
- const trimmedDomain = rawDomain.trim();
5274
- if (!trimmedDomain) {
5275
- return null;
5276
- }
5277
- const candidateUrl = hasHttpProtocol(trimmedDomain) ? trimmedDomain : `https://${trimmedDomain}`;
5278
- try {
5279
- const parsedUrl = new URL(candidateUrl);
5280
- const normalizedHostname = parsedUrl.hostname.trim().toLowerCase();
5281
- return normalizedHostname || null;
5282
- }
5283
- catch (_a) {
5284
- return null;
5285
- }
5286
- }
5287
- /**
5288
- * Checks whether the value already includes an HTTP(S) protocol prefix.
5289
- *
5290
- * @param value - Raw value to inspect.
5291
- * @returns True when the value starts with `http://` or `https://`.
5292
- *
5293
- * @private utility for host/domain matching
5294
- */
5295
- function hasHttpProtocol(value) {
5296
- return value.startsWith('http://') || value.startsWith('https://');
5297
- }
5298
-
5299
4902
  /**
5300
4903
  * Make error report URL for the given error
5301
4904
  *
@@ -5882,6 +5485,59 @@ const LIMITS = {
5882
5485
  };
5883
5486
  // Note: [💞] Ignore a discrepancy between file name and entity name
5884
5487
 
5488
+ /**
5489
+ * Normalizes a given text to camelCase format.
5490
+ *
5491
+ * Note: [🔂] This function is idempotent.
5492
+ *
5493
+ * @param text The text to be normalized.
5494
+ * @param _isFirstLetterCapital Whether the first letter should be capitalized.
5495
+ * @returns The camelCase formatted string.
5496
+ * @example 'helloWorld'
5497
+ * @example 'iLovePromptbook'
5498
+ *
5499
+ * @public exported from `@promptbook/utils`
5500
+ */
5501
+ function normalizeTo_camelCase(text, _isFirstLetterCapital = false) {
5502
+ let charType;
5503
+ let lastCharType = null;
5504
+ let normalizedName = '';
5505
+ for (const char of text) {
5506
+ let normalizedChar;
5507
+ if (/^[a-z]$/.test(char)) {
5508
+ charType = 'LOWERCASE';
5509
+ normalizedChar = char;
5510
+ }
5511
+ else if (/^[A-Z]$/.test(char)) {
5512
+ charType = 'UPPERCASE';
5513
+ normalizedChar = char.toLowerCase();
5514
+ }
5515
+ else if (/^[0-9]$/.test(char)) {
5516
+ charType = 'NUMBER';
5517
+ normalizedChar = char;
5518
+ }
5519
+ else {
5520
+ charType = 'OTHER';
5521
+ normalizedChar = '';
5522
+ }
5523
+ if (!lastCharType) {
5524
+ if (_isFirstLetterCapital) {
5525
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: DRY
5526
+ }
5527
+ }
5528
+ else if (charType !== lastCharType &&
5529
+ !(charType === 'LOWERCASE' && lastCharType === 'UPPERCASE') &&
5530
+ !(lastCharType === 'NUMBER') &&
5531
+ !(charType === 'NUMBER')) {
5532
+ normalizedChar = normalizedChar.toUpperCase(); //TODO: [🌺] DRY
5533
+ }
5534
+ normalizedName += normalizedChar;
5535
+ lastCharType = charType;
5536
+ }
5537
+ return normalizedName;
5538
+ }
5539
+ // TODO: [🌺] Use some intermediate util splitWords
5540
+
5885
5541
  /**
5886
5542
  * Tests if given string is valid file path.
5887
5543
  *
@@ -5937,6 +5593,37 @@ function isValidFilePath(filename) {
5937
5593
  }
5938
5594
  // TODO: [🍏] Implement for MacOs
5939
5595
 
5596
+ /**
5597
+ * Tests if given string is valid URL.
5598
+ *
5599
+ * Note: [🔂] This function is idempotent.
5600
+ * Note: Dataurl are considered perfectly valid.
5601
+ * Note: There are few similar functions:
5602
+ * - `isValidUrl` *(this one)* which tests any URL
5603
+ * - `isValidAgentUrl` which tests just agent URL
5604
+ * - `isValidPipelineUrl` which tests just pipeline URL
5605
+ *
5606
+ * @public exported from `@promptbook/utils`
5607
+ */
5608
+ function isValidUrl(url) {
5609
+ if (typeof url !== 'string') {
5610
+ return false;
5611
+ }
5612
+ try {
5613
+ if (url.startsWith('blob:')) {
5614
+ url = url.replace(/^blob:/, '');
5615
+ }
5616
+ const urlObject = new URL(url /* because fail is handled */);
5617
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
5618
+ return false;
5619
+ }
5620
+ return true;
5621
+ }
5622
+ catch (error) {
5623
+ return false;
5624
+ }
5625
+ }
5626
+
5940
5627
  /**
5941
5628
  * Collection of default diacritics removal map.
5942
5629
  */
@@ -10936,6 +10623,106 @@ class ImportCommitmentDefinition extends BaseCommitmentDefinition {
10936
10623
  }
10937
10624
  // Note: [💞] Ignore a discrepancy between file name and entity name
10938
10625
 
10626
+ /**
10627
+ * Matches URL-like candidates inside arbitrary text.
10628
+ *
10629
+ * @private
10630
+ */
10631
+ const URL_CANDIDATE_PATTERN = /https?:\/\/[^\s<>"'`]+/g;
10632
+ /**
10633
+ * Trims punctuation that commonly trails URLs in prose.
10634
+ *
10635
+ * @private
10636
+ */
10637
+ const TRAILING_PUNCTUATION_PATTERN = /[.,!?;:'"`]+$/;
10638
+ /**
10639
+ * Extracts all valid URLs from arbitrary text while removing common trailing punctuation.
10640
+ *
10641
+ * @param text - Input text that may contain one or more URLs.
10642
+ * @returns Unique URLs in their first-seen order.
10643
+ *
10644
+ * @private utility of KNOWLEDGE parsing
10645
+ */
10646
+ function extractUrlsFromText(text) {
10647
+ if (!text) {
10648
+ return [];
10649
+ }
10650
+ const candidates = text.match(URL_CANDIDATE_PATTERN);
10651
+ if (!candidates) {
10652
+ return [];
10653
+ }
10654
+ const urls = [];
10655
+ const seen = new Set();
10656
+ for (const candidate of candidates) {
10657
+ const normalizedCandidate = normalizeUrlCandidate(candidate);
10658
+ if (!normalizedCandidate) {
10659
+ continue;
10660
+ }
10661
+ if (!isValidUrl(normalizedCandidate)) {
10662
+ continue;
10663
+ }
10664
+ if (seen.has(normalizedCandidate)) {
10665
+ continue;
10666
+ }
10667
+ seen.add(normalizedCandidate);
10668
+ urls.push(normalizedCandidate);
10669
+ }
10670
+ return urls;
10671
+ }
10672
+ /**
10673
+ * Normalizes one extracted URL candidate by stripping trailing punctuation and unmatched closing wrappers.
10674
+ *
10675
+ * @private
10676
+ */
10677
+ function normalizeUrlCandidate(candidate) {
10678
+ let normalized = candidate.trim();
10679
+ if (!normalized) {
10680
+ return '';
10681
+ }
10682
+ let shouldContinue = true;
10683
+ while (shouldContinue) {
10684
+ const before = normalized;
10685
+ normalized = normalized.replace(TRAILING_PUNCTUATION_PATTERN, '');
10686
+ normalized = stripTrailingUnmatchedClosing(normalized, '(', ')');
10687
+ normalized = stripTrailingUnmatchedClosing(normalized, '[', ']');
10688
+ normalized = stripTrailingUnmatchedClosing(normalized, '{', '}');
10689
+ normalized = normalized.replace(TRAILING_PUNCTUATION_PATTERN, '');
10690
+ shouldContinue = normalized !== before;
10691
+ }
10692
+ return normalized;
10693
+ }
10694
+ /**
10695
+ * Removes trailing closing wrappers when they are unmatched in the candidate.
10696
+ *
10697
+ * @private
10698
+ */
10699
+ function stripTrailingUnmatchedClosing(candidate, openingChar, closingChar) {
10700
+ let normalized = candidate;
10701
+ while (normalized.endsWith(closingChar)) {
10702
+ const openingCount = countOccurrences(normalized, openingChar);
10703
+ const closingCount = countOccurrences(normalized, closingChar);
10704
+ if (closingCount <= openingCount) {
10705
+ break;
10706
+ }
10707
+ normalized = normalized.slice(0, -1);
10708
+ }
10709
+ return normalized;
10710
+ }
10711
+ /**
10712
+ * Counts character occurrences in a string.
10713
+ *
10714
+ * @private
10715
+ */
10716
+ function countOccurrences(value, searchedChar) {
10717
+ let count = 0;
10718
+ for (const currentChar of value) {
10719
+ if (currentChar === searchedChar) {
10720
+ count++;
10721
+ }
10722
+ }
10723
+ return count;
10724
+ }
10725
+
10939
10726
  /**
10940
10727
  * The default base name for inline knowledge files when the content lacks identifying text.
10941
10728
  *
@@ -16274,6 +16061,44 @@ function mapGoogleCalendarEvent(event) {
16274
16061
  * @private constant of createUseCalendarTools
16275
16062
  */
16276
16063
  const CALENDAR_URL_PARAMETER_DESCRIPTION = 'Google Calendar URL configured by USE CALENDAR (for example "https://calendar.google.com/...").';
16064
+ /**
16065
+ * Shared schema for string arrays used by USE CALENDAR tools.
16066
+ *
16067
+ * @private constant of createUseCalendarTools
16068
+ */
16069
+ const STRING_ARRAY_ITEMS_SCHEMA = {
16070
+ type: 'string',
16071
+ };
16072
+ /**
16073
+ * Shared schema for integer arrays used by USE CALENDAR tools.
16074
+ *
16075
+ * @private constant of createUseCalendarTools
16076
+ */
16077
+ const INTEGER_ARRAY_ITEMS_SCHEMA = {
16078
+ type: 'integer',
16079
+ };
16080
+ /**
16081
+ * Shared `sendUpdates` schema used by USE CALENDAR tools.
16082
+ *
16083
+ * @private constant of createUseCalendarTools
16084
+ */
16085
+ const SEND_UPDATES_PARAMETER_SCHEMA = {
16086
+ type: 'string',
16087
+ description: 'Guest update policy ("all", "externalOnly", "none").',
16088
+ enum: ['all', 'externalOnly', 'none'],
16089
+ };
16090
+ /**
16091
+ * Creates an array parameter schema with explicit item definition so OpenAI accepts it.
16092
+ *
16093
+ * @private function of createUseCalendarTools
16094
+ */
16095
+ function createArrayParameterSchema(description, items) {
16096
+ return {
16097
+ type: 'array',
16098
+ description,
16099
+ items,
16100
+ };
16101
+ }
16277
16102
  /**
16278
16103
  * Adds USE CALENDAR tool definitions while keeping already registered tools untouched.
16279
16104
  *
@@ -16380,18 +16205,9 @@ function createUseCalendarTools(existingTools) {
16380
16205
  type: 'string',
16381
16206
  description: 'Optional timezone for datetime values.',
16382
16207
  },
16383
- attendees: {
16384
- type: 'array',
16385
- description: 'Optional guest email list.',
16386
- },
16387
- reminderMinutes: {
16388
- type: 'array',
16389
- description: 'Optional popup reminder minute offsets.',
16390
- },
16391
- sendUpdates: {
16392
- type: 'string',
16393
- description: 'Guest update policy ("all", "externalOnly", "none").',
16394
- },
16208
+ attendees: createArrayParameterSchema('Optional guest email list.', STRING_ARRAY_ITEMS_SCHEMA),
16209
+ reminderMinutes: createArrayParameterSchema('Optional popup reminder minute offsets.', INTEGER_ARRAY_ITEMS_SCHEMA),
16210
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
16395
16211
  },
16396
16212
  required: ['summary', 'start', 'end'],
16397
16213
  },
@@ -16434,18 +16250,9 @@ function createUseCalendarTools(existingTools) {
16434
16250
  type: 'string',
16435
16251
  description: 'Optional timezone for datetime values.',
16436
16252
  },
16437
- attendees: {
16438
- type: 'array',
16439
- description: 'Optional replacement guest email list.',
16440
- },
16441
- reminderMinutes: {
16442
- type: 'array',
16443
- description: 'Optional replacement popup reminder minute offsets.',
16444
- },
16445
- sendUpdates: {
16446
- type: 'string',
16447
- description: 'Guest update policy ("all", "externalOnly", "none").',
16448
- },
16253
+ attendees: createArrayParameterSchema('Optional replacement guest email list.', STRING_ARRAY_ITEMS_SCHEMA),
16254
+ reminderMinutes: createArrayParameterSchema('Optional replacement popup reminder minute offsets.', INTEGER_ARRAY_ITEMS_SCHEMA),
16255
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
16449
16256
  },
16450
16257
  required: ['eventId'],
16451
16258
  },
@@ -16464,10 +16271,7 @@ function createUseCalendarTools(existingTools) {
16464
16271
  type: 'string',
16465
16272
  description: 'Google Calendar event id.',
16466
16273
  },
16467
- sendUpdates: {
16468
- type: 'string',
16469
- description: 'Guest update policy ("all", "externalOnly", "none").',
16470
- },
16274
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
16471
16275
  },
16472
16276
  required: ['eventId'],
16473
16277
  },
@@ -16486,14 +16290,8 @@ function createUseCalendarTools(existingTools) {
16486
16290
  type: 'string',
16487
16291
  description: 'Google Calendar event id.',
16488
16292
  },
16489
- guests: {
16490
- type: 'array',
16491
- description: 'Guest email list to add to the event.',
16492
- },
16493
- sendUpdates: {
16494
- type: 'string',
16495
- description: 'Guest update policy ("all", "externalOnly", "none").',
16496
- },
16293
+ guests: createArrayParameterSchema('Guest email list to add to the event.', STRING_ARRAY_ITEMS_SCHEMA),
16294
+ sendUpdates: SEND_UPDATES_PARAMETER_SCHEMA,
16497
16295
  },
16498
16296
  required: ['eventId', 'guests'],
16499
16297
  },
@@ -18286,6 +18084,181 @@ function normalizeRequiredToolText(value, fieldName) {
18286
18084
  return normalized;
18287
18085
  }
18288
18086
 
18087
+ /**
18088
+ * Hostnames accepted for GitHub repository references.
18089
+ *
18090
+ * @private internal USE PROJECT constant
18091
+ */
18092
+ const GITHUB_HOSTNAMES = new Set(['github.com', 'www.github.com']);
18093
+ /**
18094
+ * Pattern for validating owner/repository slugs.
18095
+ *
18096
+ * @private internal USE PROJECT constant
18097
+ */
18098
+ const GITHUB_REPOSITORY_SLUG_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/;
18099
+ /**
18100
+ * Parses a repository reference into canonical owner/repository details.
18101
+ *
18102
+ * Supported input forms:
18103
+ * - `https://github.com/owner/repository`
18104
+ * - `github.com/owner/repository`
18105
+ * - `owner/repository`
18106
+ * - optional `.git` suffix and trailing slash are supported
18107
+ *
18108
+ * @private internal utility of USE PROJECT commitment
18109
+ */
18110
+ function parseGitHubRepositoryReference(rawReference) {
18111
+ const trimmedReference = rawReference.trim();
18112
+ if (!trimmedReference) {
18113
+ return null;
18114
+ }
18115
+ const normalizedReference = trimmedReference.replace(/\/+$/g, '');
18116
+ if (normalizedReference.startsWith('http://') || normalizedReference.startsWith('https://')) {
18117
+ return parseGitHubRepositoryReferenceFromUrl(normalizedReference);
18118
+ }
18119
+ if (normalizedReference.startsWith('github.com/')) {
18120
+ return parseGitHubRepositoryReferenceFromUrl(`https://${normalizedReference}`);
18121
+ }
18122
+ if (!GITHUB_REPOSITORY_SLUG_PATTERN.test(normalizedReference)) {
18123
+ return null;
18124
+ }
18125
+ const [owner, repositoryRaw] = normalizedReference.split('/');
18126
+ if (!owner || !repositoryRaw) {
18127
+ return null;
18128
+ }
18129
+ const repository = repositoryRaw.replace(/\.git$/i, '');
18130
+ if (!isValidGitHubRepositoryPart(owner) || !isValidGitHubRepositoryPart(repository)) {
18131
+ return null;
18132
+ }
18133
+ return createGitHubRepositoryReference(owner, repository);
18134
+ }
18135
+ /**
18136
+ * Parses `USE PROJECT` commitment content into repository reference + optional instructions.
18137
+ *
18138
+ * @private internal utility of USE PROJECT commitment
18139
+ */
18140
+ function parseUseProjectCommitmentContent(content) {
18141
+ const trimmedContent = spaceTrim$1(content);
18142
+ if (!trimmedContent) {
18143
+ return {
18144
+ repository: null,
18145
+ repositoryReferenceRaw: null,
18146
+ instructions: '',
18147
+ };
18148
+ }
18149
+ const lines = trimmedContent
18150
+ .split(/\r?\n/)
18151
+ .map((line) => line.trim())
18152
+ .filter(Boolean);
18153
+ if (lines.length === 0) {
18154
+ return {
18155
+ repository: null,
18156
+ repositoryReferenceRaw: null,
18157
+ instructions: '',
18158
+ };
18159
+ }
18160
+ const firstLine = lines[0] || '';
18161
+ const firstLineTokens = firstLine.split(/\s+/).filter(Boolean);
18162
+ let repositoryReferenceRaw = null;
18163
+ let repositoryReference = null;
18164
+ let repositoryTokenIndex = -1;
18165
+ for (let index = 0; index < firstLineTokens.length; index++) {
18166
+ const token = firstLineTokens[index] || '';
18167
+ const cleanedToken = token.replace(/[),.;:!?]+$/g, '');
18168
+ const parsedReference = parseGitHubRepositoryReference(cleanedToken);
18169
+ if (!parsedReference) {
18170
+ continue;
18171
+ }
18172
+ repositoryReferenceRaw = cleanedToken;
18173
+ repositoryReference = parsedReference;
18174
+ repositoryTokenIndex = index;
18175
+ break;
18176
+ }
18177
+ const instructionParts = [];
18178
+ if (repositoryTokenIndex >= 0) {
18179
+ const firstLineInstruction = firstLineTokens
18180
+ .filter((_token, index) => index !== repositoryTokenIndex)
18181
+ .join(' ')
18182
+ .trim();
18183
+ if (firstLineInstruction) {
18184
+ instructionParts.push(firstLineInstruction);
18185
+ }
18186
+ }
18187
+ else if (firstLine) {
18188
+ instructionParts.push(firstLine);
18189
+ }
18190
+ if (lines.length > 1) {
18191
+ const extraLines = lines.slice(1).join('\n').trim();
18192
+ if (extraLines) {
18193
+ instructionParts.push(extraLines);
18194
+ }
18195
+ }
18196
+ return {
18197
+ repository: repositoryReference,
18198
+ repositoryReferenceRaw,
18199
+ instructions: instructionParts.join('\n').trim(),
18200
+ };
18201
+ }
18202
+ /**
18203
+ * Parses URL-like repository references.
18204
+ *
18205
+ * @private utility of USE PROJECT commitment
18206
+ */
18207
+ function parseGitHubRepositoryReferenceFromUrl(rawUrl) {
18208
+ let parsedUrl;
18209
+ try {
18210
+ parsedUrl = new URL(rawUrl);
18211
+ }
18212
+ catch (_a) {
18213
+ return null;
18214
+ }
18215
+ if (!GITHUB_HOSTNAMES.has(parsedUrl.hostname.toLowerCase())) {
18216
+ return null;
18217
+ }
18218
+ const segments = parsedUrl.pathname.split('/').filter(Boolean);
18219
+ if (segments.length < 2) {
18220
+ return null;
18221
+ }
18222
+ const owner = segments[0];
18223
+ const repositoryRaw = segments[1];
18224
+ if (!owner || !repositoryRaw) {
18225
+ return null;
18226
+ }
18227
+ const repository = repositoryRaw.replace(/\.git$/i, '');
18228
+ if (!isValidGitHubRepositoryPart(owner) || !isValidGitHubRepositoryPart(repository)) {
18229
+ return null;
18230
+ }
18231
+ let defaultBranch;
18232
+ if (segments[2] === 'tree' && segments[3]) {
18233
+ defaultBranch = decodeURIComponent(segments[3]);
18234
+ }
18235
+ return createGitHubRepositoryReference(owner, repository, defaultBranch);
18236
+ }
18237
+ /**
18238
+ * Validates one owner/repository slug part.
18239
+ *
18240
+ * @private utility of USE PROJECT commitment
18241
+ */
18242
+ function isValidGitHubRepositoryPart(value) {
18243
+ return /^[A-Za-z0-9_.-]+$/.test(value);
18244
+ }
18245
+ /**
18246
+ * Builds canonical repository reference object.
18247
+ *
18248
+ * @private utility of USE PROJECT commitment
18249
+ */
18250
+ function createGitHubRepositoryReference(owner, repository, defaultBranch) {
18251
+ const slug = `${owner}/${repository}`;
18252
+ return {
18253
+ owner,
18254
+ repository,
18255
+ slug,
18256
+ url: `https://github.com/${slug}`,
18257
+ defaultBranch,
18258
+ };
18259
+ }
18260
+ // Note: [💞] Ignore a discrepancy between file name and entity name
18261
+
18289
18262
  /**
18290
18263
  * Wallet metadata used by USE PROJECT when resolving GitHub credentials.
18291
18264
  *
@@ -21196,126 +21169,16 @@ function parseParameters(text) {
21196
21169
  }
21197
21170
 
21198
21171
  /**
21199
- * Parses basic information from agent source
21200
- *
21201
- * There are 2 similar functions:
21202
- * - `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.
21203
- * - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
21204
- *
21205
- * @public exported from `@promptbook/core`
21206
- */
21207
- function parseAgentSource(agentSource) {
21208
- const parseResult = parseAgentSourceWithCommitments(agentSource);
21209
- const resolvedAgentName = parseResult.agentName || createDefaultAgentName(agentSource);
21210
- const personaDescription = extractAgentProfileText(parseResult.commitments);
21211
- const initialMessage = extractInitialMessage(parseResult.commitments);
21212
- const parsedProfile = extractParsedAgentProfile(parseResult.commitments);
21213
- ensureMetaFullname(parsedProfile.meta, resolvedAgentName);
21214
- return {
21215
- agentName: normalizeAgentName(resolvedAgentName),
21216
- agentHash: computeAgentHash(agentSource),
21217
- permanentId: parsedProfile.meta.id,
21218
- personaDescription,
21219
- initialMessage,
21220
- meta: parsedProfile.meta,
21221
- links: parsedProfile.links,
21222
- parameters: parseParameters(agentSource),
21223
- capabilities: parsedProfile.capabilities,
21224
- samples: parsedProfile.samples,
21225
- knowledgeSources: parsedProfile.knowledgeSources,
21226
- };
21227
- }
21228
- /**
21229
- * Static capability descriptors for commitments that map one-to-one to a visible capability.
21230
- *
21231
- * @private internal utility of `parseAgentSource`
21232
- */
21233
- const SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE = {
21234
- 'USE BROWSER': {
21235
- type: 'browser',
21236
- label: 'Browser',
21237
- iconName: 'Globe',
21238
- },
21239
- 'USE SEARCH ENGINE': {
21240
- type: 'search-engine',
21241
- label: 'Internet',
21242
- iconName: 'Search',
21243
- },
21244
- 'USE SEARCH': {
21245
- type: 'search-engine',
21246
- label: 'Internet',
21247
- iconName: 'Search',
21248
- },
21249
- 'USE DEEPSEARCH': {
21250
- type: 'search-engine',
21251
- label: 'DeepSearch',
21252
- iconName: 'Search',
21253
- },
21254
- 'USE TIME': {
21255
- type: 'time',
21256
- label: 'Time',
21257
- iconName: 'Clock',
21258
- },
21259
- 'USE TIMEOUT': {
21260
- type: 'timeout',
21261
- label: 'Timers',
21262
- iconName: 'Clock',
21263
- },
21264
- 'USE USER LOCATION': {
21265
- type: 'user-location',
21266
- label: 'User location',
21267
- iconName: 'MapPin',
21268
- },
21269
- 'USE EMAIL': {
21270
- type: 'email',
21271
- label: 'Email',
21272
- iconName: 'Mail',
21273
- },
21274
- 'USE POPUP': {
21275
- type: 'popup',
21276
- label: 'Popup',
21277
- iconName: 'SquareArrowOutUpRight',
21278
- },
21279
- 'USE IMAGE GENERATOR': {
21280
- type: 'image-generator',
21281
- label: 'Image Generator',
21282
- iconName: 'Image',
21283
- },
21284
- 'USE PRIVACY': {
21285
- type: 'privacy',
21286
- label: 'Privacy',
21287
- iconName: 'Shield',
21288
- },
21289
- 'USE CALENDAR': {
21290
- type: 'calendar',
21291
- label: 'Calendar',
21292
- iconName: 'Calendar',
21293
- },
21294
- };
21295
- /**
21296
- * Dedicated handlers for META-style commitments that directly map onto parsed meta fields.
21297
- *
21298
- * @private internal utility of `parseAgentSource`
21299
- */
21300
- const META_COMMITMENT_APPLIERS = {
21301
- 'META AVATAR': applyMetaAvatarContent,
21302
- 'META LINK': applyMetaLinkContent,
21303
- 'META DOMAIN': applyMetaDomainContent,
21304
- 'META IMAGE': applyMetaImageContent,
21305
- 'META DESCRIPTION': applyMetaDescriptionContent,
21306
- 'META DISCLAIMER': applyMetaDisclaimerContent,
21307
- 'META INPUT PLACEHOLDER': applyMetaInputPlaceholderContent,
21308
- 'MESSAGE SUFFIX': applyMessageSuffixContent,
21309
- 'META COLOR': applyMetaColorContent,
21310
- 'META FONT': applyMetaFontContent,
21311
- 'META VOICE': applyMetaVoiceContent,
21312
- };
21313
- /**
21314
- * Detects local slash-based references used by FROM and IMPORT commitments.
21172
+ * Ensures the parsed profile always exposes a fullname value.
21315
21173
  *
21316
21174
  * @private internal utility of `parseAgentSource`
21317
21175
  */
21318
- const LOCAL_AGENT_REFERENCE_PREFIXES = ['./', '../', '/'];
21176
+ function ensureMetaFullname(meta, fallbackFullname) {
21177
+ if (!meta.fullname) {
21178
+ meta.fullname = fallbackFullname;
21179
+ }
21180
+ }
21181
+
21319
21182
  /**
21320
21183
  * Resolves the public agent profile text from the last GOAL/GOALS commitment,
21321
21184
  * falling back to the deprecated PERSONA/PERSONAE commitments when no goal exists.
@@ -21345,6 +21208,7 @@ function extractAgentProfileText(commitments) {
21345
21208
  }
21346
21209
  return null;
21347
21210
  }
21211
+
21348
21212
  /**
21349
21213
  * Resolves the last INITIAL MESSAGE commitment, which is the public initial-message value.
21350
21214
  *
@@ -21359,48 +21223,189 @@ function extractInitialMessage(commitments) {
21359
21223
  }
21360
21224
  return initialMessage;
21361
21225
  }
21226
+
21362
21227
  /**
21363
- * Collects capability, sample, meta, link, and knowledge-source data from commitments.
21228
+ * Normalizes a domain-like string into a comparable hostname form.
21364
21229
  *
21365
- * @private internal utility of `parseAgentSource`
21230
+ * The returned value is lowercased and stripped to hostname only
21231
+ * (protocol, path, query, hash, and port are removed).
21232
+ *
21233
+ * @param rawDomain - Raw domain value (for example `my-agent.com` or `https://my-agent.com/path`).
21234
+ * @returns Normalized hostname or `null` when the value cannot be normalized.
21235
+ *
21236
+ * @private utility for host/domain matching
21366
21237
  */
21367
- function extractParsedAgentProfile(commitments) {
21368
- const state = {
21369
- meta: {},
21370
- links: [],
21371
- capabilities: [],
21372
- samples: [],
21373
- knowledgeSources: [],
21374
- pendingUserMessage: null,
21375
- knownKnowledgeSourceUrls: new Set(),
21376
- };
21377
- for (const commitment of commitments) {
21378
- processParsedCommitment(state, commitment);
21238
+ function normalizeDomainForMatching(rawDomain) {
21239
+ const trimmedDomain = rawDomain.trim();
21240
+ if (!trimmedDomain) {
21241
+ return null;
21242
+ }
21243
+ const candidateUrl = hasHttpProtocol(trimmedDomain) ? trimmedDomain : `https://${trimmedDomain}`;
21244
+ try {
21245
+ const parsedUrl = new URL(candidateUrl);
21246
+ const normalizedHostname = parsedUrl.hostname.trim().toLowerCase();
21247
+ return normalizedHostname || null;
21248
+ }
21249
+ catch (_a) {
21250
+ return null;
21379
21251
  }
21380
- return {
21381
- meta: state.meta,
21382
- links: state.links,
21383
- capabilities: state.capabilities,
21384
- samples: state.samples,
21385
- knowledgeSources: state.knowledgeSources,
21386
- };
21387
21252
  }
21388
21253
  /**
21389
- * Processes one parsed commitment through the sample, capability, and meta stages.
21254
+ * Checks whether the value already includes an HTTP(S) protocol prefix.
21255
+ *
21256
+ * @param value - Raw value to inspect.
21257
+ * @returns True when the value starts with `http://` or `https://`.
21258
+ *
21259
+ * @private utility for host/domain matching
21260
+ */
21261
+ function hasHttpProtocol(value) {
21262
+ return value.startsWith('http://') || value.startsWith('https://');
21263
+ }
21264
+
21265
+ /**
21266
+ * Dedicated handlers for META-style commitments that directly map onto parsed meta fields.
21267
+ */
21268
+ const META_COMMITMENT_APPLIERS = {
21269
+ 'META AVATAR': applyMetaAvatarContent,
21270
+ 'META LINK': applyMetaLinkContent,
21271
+ 'META DOMAIN': applyMetaDomainContent,
21272
+ 'META IMAGE': applyMetaImageContent,
21273
+ 'META DESCRIPTION': applyMetaDescriptionContent,
21274
+ 'META DISCLAIMER': applyMetaDisclaimerContent,
21275
+ 'META INPUT PLACEHOLDER': applyMetaInputPlaceholderContent,
21276
+ 'MESSAGE SUFFIX': applyMessageSuffixContent,
21277
+ 'META COLOR': applyMetaColorContent,
21278
+ 'META FONT': applyMetaFontContent,
21279
+ 'META VOICE': applyMetaVoiceContent,
21280
+ };
21281
+ /**
21282
+ * Applies META-style commitments that mutate parsed profile metadata.
21390
21283
  *
21391
21284
  * @private internal utility of `parseAgentSource`
21392
21285
  */
21393
- function processParsedCommitment(state, commitment) {
21394
- if (consumeConversationSampleCommitment(state, commitment)) {
21286
+ function applyMetaCommitment(state, commitment) {
21287
+ const applyMetaContent = META_COMMITMENT_APPLIERS[commitment.type];
21288
+ if (applyMetaContent) {
21289
+ applyMetaContent(state, commitment.content);
21395
21290
  return;
21396
21291
  }
21397
- const capabilities = createCapabilitiesFromCommitment(state, commitment);
21398
- if (capabilities.length > 0) {
21399
- state.capabilities.push(...capabilities);
21292
+ if (commitment.type === 'META') {
21293
+ applyGenericMetaCommitment(state, commitment.content);
21294
+ }
21295
+ }
21296
+ /**
21297
+ * Applies the generic META commitment form (`META TYPE value`).
21298
+ */
21299
+ function applyGenericMetaCommitment(state, content) {
21300
+ const metaTypeRaw = content.split(' ')[0] || 'NONE';
21301
+ const metaValue = spaceTrim$1(content.substring(metaTypeRaw.length));
21302
+ if (metaTypeRaw === 'LINK') {
21303
+ state.links.push(metaValue);
21304
+ }
21305
+ if (metaTypeRaw.toUpperCase() === 'AVATAR') {
21306
+ applyMetaAvatarContent(state, metaValue);
21400
21307
  return;
21401
21308
  }
21402
- applyMetaCommitment(state, commitment);
21309
+ const metaType = normalizeTo_camelCase(metaTypeRaw);
21310
+ state.meta[metaType] = metaValue;
21403
21311
  }
21312
+ /**
21313
+ * Applies META AVATAR content into the canonical `meta.avatar` field.
21314
+ */
21315
+ function applyMetaAvatarContent(state, content) {
21316
+ const avatarVisualId = resolveAvatarVisualId(content);
21317
+ if (avatarVisualId) {
21318
+ state.meta.avatar = avatarVisualId;
21319
+ return;
21320
+ }
21321
+ delete state.meta.avatar;
21322
+ }
21323
+ /**
21324
+ * Applies META LINK content into links and the canonical `meta.link` field.
21325
+ */
21326
+ function applyMetaLinkContent(state, content) {
21327
+ const linkValue = spaceTrim$1(content);
21328
+ state.links.push(linkValue);
21329
+ state.meta.link = linkValue;
21330
+ }
21331
+ /**
21332
+ * Applies META DOMAIN content into the normalized `meta.domain` field.
21333
+ */
21334
+ function applyMetaDomainContent(state, content) {
21335
+ state.meta.domain = normalizeMetaDomain(content);
21336
+ }
21337
+ /**
21338
+ * Applies META IMAGE content into the canonical `meta.image` field.
21339
+ */
21340
+ function applyMetaImageContent(state, content) {
21341
+ state.meta.image = spaceTrim$1(content);
21342
+ }
21343
+ /**
21344
+ * Applies META DESCRIPTION content into the canonical `meta.description` field.
21345
+ */
21346
+ function applyMetaDescriptionContent(state, content) {
21347
+ state.meta.description = spaceTrim$1(content);
21348
+ }
21349
+ /**
21350
+ * Applies META DISCLAIMER content into the canonical `meta.disclaimer` field.
21351
+ */
21352
+ function applyMetaDisclaimerContent(state, content) {
21353
+ state.meta.disclaimer = content;
21354
+ }
21355
+ /**
21356
+ * Applies META INPUT PLACEHOLDER content into the canonical `meta.inputPlaceholder` field.
21357
+ */
21358
+ function applyMetaInputPlaceholderContent(state, content) {
21359
+ state.meta.inputPlaceholder = spaceTrim$1(content);
21360
+ }
21361
+ /**
21362
+ * Applies MESSAGE SUFFIX content into the canonical `meta.messageSuffix` field.
21363
+ */
21364
+ function applyMessageSuffixContent(state, content) {
21365
+ state.meta.messageSuffix = content;
21366
+ }
21367
+ /**
21368
+ * Applies META COLOR content into the canonical `meta.color` field.
21369
+ */
21370
+ function applyMetaColorContent(state, content) {
21371
+ state.meta.color = normalizeSeparator(content);
21372
+ }
21373
+ /**
21374
+ * Applies META FONT content into the canonical `meta.font` field.
21375
+ */
21376
+ function applyMetaFontContent(state, content) {
21377
+ state.meta.font = normalizeSeparator(content);
21378
+ }
21379
+ /**
21380
+ * Applies META VOICE content into the canonical `meta.voice` field.
21381
+ */
21382
+ function applyMetaVoiceContent(state, content) {
21383
+ state.meta.voice = spaceTrim$1(content);
21384
+ }
21385
+ /**
21386
+ * Normalizes the separator in the content
21387
+ *
21388
+ * @param content - The content to normalize
21389
+ * @returns The content with normalized separators
21390
+ */
21391
+ function normalizeSeparator(content) {
21392
+ const trimmed = spaceTrim$1(content);
21393
+ if (trimmed.includes(',')) {
21394
+ return trimmed;
21395
+ }
21396
+ return trimmed.split(/\s+/).join(', ');
21397
+ }
21398
+ /**
21399
+ * Normalizes META DOMAIN content to a hostname-like value when possible.
21400
+ *
21401
+ * @param content - Raw META DOMAIN content.
21402
+ * @returns Normalized domain or a trimmed fallback.
21403
+ */
21404
+ function normalizeMetaDomain(content) {
21405
+ const trimmed = spaceTrim$1(content);
21406
+ return normalizeDomainForMatching(trimmed) || trimmed.toLowerCase();
21407
+ }
21408
+
21404
21409
  /**
21405
21410
  * Updates sample-conversation state for communication commitments.
21406
21411
  *
@@ -21427,6 +21432,76 @@ function consumeConversationSampleCommitment(state, commitment) {
21427
21432
  return false;
21428
21433
  }
21429
21434
  }
21435
+
21436
+ /**
21437
+ * Static capability descriptors for commitments that map one-to-one to a visible capability.
21438
+ */
21439
+ const SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE = {
21440
+ 'USE BROWSER': {
21441
+ type: 'browser',
21442
+ label: 'Browser',
21443
+ iconName: 'Globe',
21444
+ },
21445
+ 'USE SEARCH ENGINE': {
21446
+ type: 'search-engine',
21447
+ label: 'Internet',
21448
+ iconName: 'Search',
21449
+ },
21450
+ 'USE SEARCH': {
21451
+ type: 'search-engine',
21452
+ label: 'Internet',
21453
+ iconName: 'Search',
21454
+ },
21455
+ 'USE DEEPSEARCH': {
21456
+ type: 'search-engine',
21457
+ label: 'DeepSearch',
21458
+ iconName: 'Search',
21459
+ },
21460
+ 'USE TIME': {
21461
+ type: 'time',
21462
+ label: 'Time',
21463
+ iconName: 'Clock',
21464
+ },
21465
+ 'USE TIMEOUT': {
21466
+ type: 'timeout',
21467
+ label: 'Timers',
21468
+ iconName: 'Clock',
21469
+ },
21470
+ 'USE USER LOCATION': {
21471
+ type: 'user-location',
21472
+ label: 'User location',
21473
+ iconName: 'MapPin',
21474
+ },
21475
+ 'USE EMAIL': {
21476
+ type: 'email',
21477
+ label: 'Email',
21478
+ iconName: 'Mail',
21479
+ },
21480
+ 'USE POPUP': {
21481
+ type: 'popup',
21482
+ label: 'Popup',
21483
+ iconName: 'SquareArrowOutUpRight',
21484
+ },
21485
+ 'USE IMAGE GENERATOR': {
21486
+ type: 'image-generator',
21487
+ label: 'Image Generator',
21488
+ iconName: 'Image',
21489
+ },
21490
+ 'USE PRIVACY': {
21491
+ type: 'privacy',
21492
+ label: 'Privacy',
21493
+ iconName: 'Shield',
21494
+ },
21495
+ 'USE CALENDAR': {
21496
+ type: 'calendar',
21497
+ label: 'Calendar',
21498
+ iconName: 'Calendar',
21499
+ },
21500
+ };
21501
+ /**
21502
+ * Detects local slash-based references used by FROM and IMPORT commitments.
21503
+ */
21504
+ const LOCAL_AGENT_REFERENCE_PREFIXES = ['./', '../', '/'];
21430
21505
  /**
21431
21506
  * Creates the visible capabilities produced by one parsed commitment.
21432
21507
  *
@@ -21456,8 +21531,6 @@ function createCapabilitiesFromCommitment(state, commitment) {
21456
21531
  }
21457
21532
  /**
21458
21533
  * Clones one static capability descriptor for a simple capability commitment.
21459
- *
21460
- * @private internal utility of `parseAgentSource`
21461
21534
  */
21462
21535
  function createSimpleCapability(commitmentType) {
21463
21536
  const capability = SIMPLE_CAPABILITY_BY_COMMITMENT_TYPE[commitmentType];
@@ -21465,8 +21538,6 @@ function createSimpleCapability(commitmentType) {
21465
21538
  }
21466
21539
  /**
21467
21540
  * Creates the USE PROJECT capability badge.
21468
- *
21469
- * @private internal utility of `parseAgentSource`
21470
21541
  */
21471
21542
  function createProjectCapability(content) {
21472
21543
  var _a;
@@ -21480,8 +21551,6 @@ function createProjectCapability(content) {
21480
21551
  }
21481
21552
  /**
21482
21553
  * Creates the FROM inheritance capability when the reference should stay visible in the profile.
21483
- *
21484
- * @private internal utility of `parseAgentSource`
21485
21554
  */
21486
21555
  function createInheritanceCapability(content) {
21487
21556
  const reference = extractFirstCommitmentLine(content);
@@ -21508,8 +21577,6 @@ function createInheritanceCapability(content) {
21508
21577
  }
21509
21578
  /**
21510
21579
  * Creates the IMPORT capability badge.
21511
- *
21512
- * @private internal utility of `parseAgentSource`
21513
21580
  */
21514
21581
  function createImportCapability(content) {
21515
21582
  const reference = extractFirstCommitmentLine(content);
@@ -21537,8 +21604,6 @@ function createImportCapability(content) {
21537
21604
  }
21538
21605
  /**
21539
21606
  * Creates TEAM capability badges for all parsed teammates.
21540
- *
21541
- * @private internal utility of `parseAgentSource`
21542
21607
  */
21543
21608
  function createTeamCapabilities(content) {
21544
21609
  const teammates = parseTeamCommitmentContent(content);
@@ -21551,8 +21616,6 @@ function createTeamCapabilities(content) {
21551
21616
  }
21552
21617
  /**
21553
21618
  * Creates the KNOWLEDGE capability badge and records URL-based knowledge sources.
21554
- *
21555
- * @private internal utility of `parseAgentSource`
21556
21619
  */
21557
21620
  function createKnowledgeCapability(state, content) {
21558
21621
  const trimmedContent = spaceTrim$1(content);
@@ -21567,8 +21630,6 @@ function createKnowledgeCapability(state, content) {
21567
21630
  }
21568
21631
  /**
21569
21632
  * Stores unique URL-based knowledge sources for later citation resolution.
21570
- *
21571
- * @private internal utility of `parseAgentSource`
21572
21633
  */
21573
21634
  function rememberKnowledgeSources(state, extractedUrls) {
21574
21635
  for (const extractedUrl of extractedUrls) {
@@ -21592,8 +21653,6 @@ function rememberKnowledgeSources(state, extractedUrls) {
21592
21653
  }
21593
21654
  /**
21594
21655
  * Derives the visible KNOWLEDGE badge label and icon from commitment content.
21595
- *
21596
- * @private internal utility of `parseAgentSource`
21597
21656
  */
21598
21657
  function createKnowledgeCapabilityPresentation(content, extractedUrls) {
21599
21658
  let label = content;
@@ -21626,8 +21685,6 @@ function createKnowledgeCapabilityPresentation(content, extractedUrls) {
21626
21685
  }
21627
21686
  /**
21628
21687
  * Shortens text-only KNOWLEDGE commitments into the same preview label as before.
21629
- *
21630
- * @private internal utility of `parseAgentSource`
21631
21688
  */
21632
21689
  function createKnowledgeTextLabel(content) {
21633
21690
  const words = content.split(/\s+/);
@@ -21636,186 +21693,89 @@ function createKnowledgeTextLabel(content) {
21636
21693
  }
21637
21694
  return content;
21638
21695
  }
21639
- /**
21640
- * Applies META-style commitments that mutate parsed profile metadata.
21641
- *
21642
- * @private internal utility of `parseAgentSource`
21643
- */
21644
- function applyMetaCommitment(state, commitment) {
21645
- const applyMetaContent = META_COMMITMENT_APPLIERS[commitment.type];
21646
- if (applyMetaContent) {
21647
- applyMetaContent(state, commitment.content);
21648
- return;
21649
- }
21650
- if (commitment.type === 'META') {
21651
- applyGenericMetaCommitment(state, commitment.content);
21652
- }
21653
- }
21654
- /**
21655
- * Applies the generic META commitment form (`META TYPE value`).
21656
- *
21657
- * @private internal utility of `parseAgentSource`
21658
- */
21659
- function applyGenericMetaCommitment(state, content) {
21660
- const metaTypeRaw = content.split(' ')[0] || 'NONE';
21661
- const metaValue = spaceTrim$1(content.substring(metaTypeRaw.length));
21662
- if (metaTypeRaw === 'LINK') {
21663
- state.links.push(metaValue);
21664
- }
21665
- if (metaTypeRaw.toUpperCase() === 'AVATAR') {
21666
- applyMetaAvatarContent(state, metaValue);
21667
- return;
21668
- }
21669
- const metaType = normalizeTo_camelCase(metaTypeRaw);
21670
- state.meta[metaType] = metaValue;
21671
- }
21672
- /**
21673
- * Applies META AVATAR content into the canonical `meta.avatar` field.
21674
- *
21675
- * @private internal utility of `parseAgentSource`
21676
- */
21677
- function applyMetaAvatarContent(state, content) {
21678
- const avatarVisualId = resolveAvatarVisualId(content);
21679
- if (avatarVisualId) {
21680
- state.meta.avatar = avatarVisualId;
21681
- return;
21682
- }
21683
- delete state.meta.avatar;
21684
- }
21685
- /**
21686
- * Applies META LINK content into links and the canonical `meta.link` field.
21687
- *
21688
- * @private internal utility of `parseAgentSource`
21689
- */
21690
- function applyMetaLinkContent(state, content) {
21691
- const linkValue = spaceTrim$1(content);
21692
- state.links.push(linkValue);
21693
- state.meta.link = linkValue;
21694
- }
21695
- /**
21696
- * Applies META DOMAIN content into the normalized `meta.domain` field.
21697
- *
21698
- * @private internal utility of `parseAgentSource`
21699
- */
21700
- function applyMetaDomainContent(state, content) {
21701
- state.meta.domain = normalizeMetaDomain(content);
21702
- }
21703
- /**
21704
- * Applies META IMAGE content into the canonical `meta.image` field.
21705
- *
21706
- * @private internal utility of `parseAgentSource`
21707
- */
21708
- function applyMetaImageContent(state, content) {
21709
- state.meta.image = spaceTrim$1(content);
21710
- }
21711
- /**
21712
- * Applies META DESCRIPTION content into the canonical `meta.description` field.
21713
- *
21714
- * @private internal utility of `parseAgentSource`
21715
- */
21716
- function applyMetaDescriptionContent(state, content) {
21717
- state.meta.description = spaceTrim$1(content);
21718
- }
21719
- /**
21720
- * Applies META DISCLAIMER content into the canonical `meta.disclaimer` field.
21721
- *
21722
- * @private internal utility of `parseAgentSource`
21723
- */
21724
- function applyMetaDisclaimerContent(state, content) {
21725
- state.meta.disclaimer = content;
21726
- }
21727
- /**
21728
- * Applies META INPUT PLACEHOLDER content into the canonical `meta.inputPlaceholder` field.
21729
- *
21730
- * @private internal utility of `parseAgentSource`
21731
- */
21732
- function applyMetaInputPlaceholderContent(state, content) {
21733
- state.meta.inputPlaceholder = spaceTrim$1(content);
21734
- }
21735
- /**
21736
- * Applies MESSAGE SUFFIX content into the canonical `meta.messageSuffix` field.
21737
- *
21738
- * @private internal utility of `parseAgentSource`
21739
- */
21740
- function applyMessageSuffixContent(state, content) {
21741
- state.meta.messageSuffix = content;
21742
- }
21743
- /**
21744
- * Applies META COLOR content into the canonical `meta.color` field.
21745
- *
21746
- * @private internal utility of `parseAgentSource`
21747
- */
21748
- function applyMetaColorContent(state, content) {
21749
- state.meta.color = normalizeSeparator(content);
21750
- }
21751
- /**
21752
- * Applies META FONT content into the canonical `meta.font` field.
21753
- *
21754
- * @private internal utility of `parseAgentSource`
21755
- */
21756
- function applyMetaFontContent(state, content) {
21757
- state.meta.font = normalizeSeparator(content);
21758
- }
21759
- /**
21760
- * Applies META VOICE content into the canonical `meta.voice` field.
21761
- *
21762
- * @private internal utility of `parseAgentSource`
21763
- */
21764
- function applyMetaVoiceContent(state, content) {
21765
- state.meta.voice = spaceTrim$1(content);
21766
- }
21767
- /**
21768
- * Ensures the parsed profile always exposes a fullname value.
21769
- *
21770
- * @private internal utility of `parseAgentSource`
21771
- */
21772
- function ensureMetaFullname(meta, fallbackFullname) {
21773
- if (!meta.fullname) {
21774
- meta.fullname = fallbackFullname;
21775
- }
21776
- }
21777
21696
  /**
21778
21697
  * Extracts the first logical line from multiline commitment content.
21779
- *
21780
- * @private internal utility of `parseAgentSource`
21781
21698
  */
21782
21699
  function extractFirstCommitmentLine(content) {
21783
21700
  return spaceTrim$1(content).split(/\r?\n/)[0] || '';
21784
21701
  }
21785
21702
  /**
21786
21703
  * Detects local FROM/IMPORT references that should use local-link labels and icons.
21787
- *
21788
- * @private internal utility of `parseAgentSource`
21789
21704
  */
21790
21705
  function isLocalAgentReference(reference) {
21791
21706
  return LOCAL_AGENT_REFERENCE_PREFIXES.some((prefix) => reference.startsWith(prefix));
21792
21707
  }
21708
+
21793
21709
  /**
21794
- * Normalizes the separator in the content
21795
- *
21796
- * @param content - The content to normalize
21797
- * @returns The content with normalized separators
21710
+ * Collects capability, sample, meta, link, and knowledge-source data from commitments.
21798
21711
  *
21799
21712
  * @private internal utility of `parseAgentSource`
21800
21713
  */
21801
- function normalizeSeparator(content) {
21802
- const trimmed = spaceTrim$1(content);
21803
- if (trimmed.includes(',')) {
21804
- return trimmed;
21714
+ function extractParsedAgentProfile(commitments) {
21715
+ const state = {
21716
+ meta: {},
21717
+ links: [],
21718
+ capabilities: [],
21719
+ samples: [],
21720
+ knowledgeSources: [],
21721
+ pendingUserMessage: null,
21722
+ knownKnowledgeSourceUrls: new Set(),
21723
+ };
21724
+ for (const commitment of commitments) {
21725
+ processParsedCommitment(state, commitment);
21805
21726
  }
21806
- return trimmed.split(/\s+/).join(', ');
21727
+ return {
21728
+ meta: state.meta,
21729
+ links: state.links,
21730
+ capabilities: state.capabilities,
21731
+ samples: state.samples,
21732
+ knowledgeSources: state.knowledgeSources,
21733
+ };
21807
21734
  }
21808
21735
  /**
21809
- * Normalizes META DOMAIN content to a hostname-like value when possible.
21736
+ * Processes one parsed commitment through the sample, capability, and meta stages.
21737
+ */
21738
+ function processParsedCommitment(state, commitment) {
21739
+ if (consumeConversationSampleCommitment(state, commitment)) {
21740
+ return;
21741
+ }
21742
+ const capabilities = createCapabilitiesFromCommitment(state, commitment);
21743
+ if (capabilities.length > 0) {
21744
+ state.capabilities.push(...capabilities);
21745
+ return;
21746
+ }
21747
+ applyMetaCommitment(state, commitment);
21748
+ }
21749
+
21750
+ /**
21751
+ * Parses basic information from agent source
21810
21752
  *
21811
- * @param content - Raw META DOMAIN content.
21812
- * @returns Normalized domain or a trimmed fallback.
21753
+ * There are 2 similar functions:
21754
+ * - `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.
21755
+ * - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
21813
21756
  *
21814
- * @private internal utility of `parseAgentSource`
21757
+ * @public exported from `@promptbook/core`
21815
21758
  */
21816
- function normalizeMetaDomain(content) {
21817
- const trimmed = spaceTrim$1(content);
21818
- return normalizeDomainForMatching(trimmed) || trimmed.toLowerCase();
21759
+ function parseAgentSource(agentSource) {
21760
+ const parseResult = parseAgentSourceWithCommitments(agentSource);
21761
+ const resolvedAgentName = parseResult.agentName || createDefaultAgentName(agentSource);
21762
+ const personaDescription = extractAgentProfileText(parseResult.commitments);
21763
+ const initialMessage = extractInitialMessage(parseResult.commitments);
21764
+ const parsedProfile = extractParsedAgentProfile(parseResult.commitments);
21765
+ ensureMetaFullname(parsedProfile.meta, resolvedAgentName);
21766
+ return {
21767
+ agentName: normalizeAgentName(resolvedAgentName),
21768
+ agentHash: computeAgentHash(agentSource),
21769
+ permanentId: parsedProfile.meta.id,
21770
+ personaDescription,
21771
+ initialMessage,
21772
+ meta: parsedProfile.meta,
21773
+ links: parsedProfile.links,
21774
+ parameters: parseParameters(agentSource),
21775
+ capabilities: parsedProfile.capabilities,
21776
+ samples: parsedProfile.samples,
21777
+ knowledgeSources: parsedProfile.knowledgeSources,
21778
+ };
21819
21779
  }
21820
21780
  // TODO: [🕛] Unite `AgentBasicInformation`, `ChatParticipant`, `LlmExecutionTools` + `LlmToolsMetadata`
21821
21781
 
@@ -35660,422 +35620,123 @@ function createPipelineExecutor(options) {
35660
35620
  updateTldr({
35661
35621
  percent: percent,
35662
35622
  message,
35663
- });
35664
- });
35665
- },
35666
- });
35667
- };
35668
- // <- TODO: Make types such as there is no need to do `as` for `createTask`
35669
- return pipelineExecutor;
35670
- }
35671
-
35672
- /**
35673
- * Prepares the persona for the pipeline
35674
- *
35675
- * @see https://github.com/webgptorg/promptbook/discussions/22
35676
- *
35677
- * @public exported from `@promptbook/core`
35678
- */
35679
- async function preparePersona(personaDescription, tools, options) {
35680
- const { isVerbose = DEFAULT_IS_VERBOSE } = options;
35681
- if (tools === undefined || tools.llm === undefined) {
35682
- throw new MissingToolsError('LLM tools are required for preparing persona');
35683
- }
35684
- // TODO: [🌼] In future use `ptbk make` and made getPipelineCollection
35685
- const collection = createPipelineCollectionFromJson(...PipelineCollection);
35686
- const preparePersonaExecutor = createPipelineExecutor({
35687
- pipeline: await collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book'),
35688
- tools,
35689
- });
35690
- const llmTools = getSingleLlmExecutionTools(tools.llm);
35691
- const availableModels = (await llmTools.listModels())
35692
- .filter(({ modelVariant }) => modelVariant === 'CHAT')
35693
- .map(({ modelName, modelDescription }) => ({
35694
- modelName,
35695
- modelDescription,
35696
- // <- Note: `modelTitle` and `modelVariant` is not relevant for this task
35697
- }));
35698
- const result = await preparePersonaExecutor({
35699
- availableModels /* <- Note: Passing as JSON */,
35700
- personaDescription,
35701
- }).asPromise({ isCrashedOnError: true });
35702
- const { outputParameters } = result;
35703
- const { modelsRequirements: modelsRequirementsJson } = outputParameters;
35704
- let modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
35705
- if (isVerbose) {
35706
- console.info(`PERSONA ${personaDescription}`, modelsRequirementsUnchecked);
35707
- }
35708
- if (!Array.isArray(modelsRequirementsUnchecked)) {
35709
- // <- TODO: Book should have syntax and system to enforce shape of JSON
35710
- modelsRequirementsUnchecked = [modelsRequirementsUnchecked];
35711
- /*
35712
- throw new UnexpectedError(
35713
- spaceTrim(
35714
- (block) => `
35715
- Invalid \`modelsRequirements\`:
35716
-
35717
- \`\`\`json
35718
- ${block(JSON.stringify(modelsRequirementsUnchecked, null, 4))}
35719
- \`\`\`
35720
- `,
35721
- ),
35722
- );
35723
- */
35724
- }
35725
- const modelsRequirements = modelsRequirementsUnchecked.map((modelRequirements) => ({
35726
- modelVariant: 'CHAT',
35727
- ...modelRequirements,
35728
- }));
35729
- return {
35730
- modelsRequirements,
35731
- };
35732
- }
35733
- // TODO: [😩] DRY `preparePersona` and `selectBestModelFromAvailable`
35734
- // TODO: [🔃][main] If the persona was prepared with different version or different set of models, prepare it once again
35735
- // TODO: [🏢] Check validity of `modelName` in pipeline
35736
- // TODO: [🏢] Check validity of `systemMessage` in pipeline
35737
- // TODO: [🏢] Check validity of `temperature` in pipeline
35738
-
35739
- /**
35740
- * Creates an empty/basic agent model requirements object
35741
- * This serves as the starting point for the reduce-like pattern
35742
- * where each commitment applies its changes to build the final requirements
35743
- *
35744
- * @public exported from `@promptbook/core`
35745
- */
35746
- function createEmptyAgentModelRequirements() {
35747
- return {
35748
- systemMessage: '',
35749
- promptSuffix: '',
35750
- // modelName: 'gpt-5',
35751
- modelName: 'gpt-5.4-mini',
35752
- temperature: 0.7,
35753
- topP: 0.9,
35754
- topK: 50,
35755
- parentAgentUrl: null,
35756
- isClosed: false,
35757
- };
35758
- }
35759
- /**
35760
- * Creates a basic agent model requirements with just the agent name
35761
- * This is used when we have an agent name but no commitments
35762
- *
35763
- * @public exported from `@promptbook/core`
35764
- */
35765
- function createBasicAgentModelRequirements(agentName) {
35766
- const empty = createEmptyAgentModelRequirements();
35767
- return {
35768
- ...empty,
35769
- systemMessage: `You are ${agentName || 'AI Agent'}`,
35770
- };
35771
- }
35772
- // TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
35773
-
35774
- /**
35775
- * Plugin for importing agent books *(`.book` files)*
35776
- *
35777
- * @private [🥝] Maybe export the import plugins through some package
35778
- */
35779
- const AgentFileImportPlugin = {
35780
- name: 'agent-file-import-plugin',
35781
- canImport(mimeType) {
35782
- // [🧠] Should we have a specific MIME type for agent books?
35783
- // For now, let's assume it's identified by .book extension or certain MIME types if provided
35784
- return mimeType === 'text/x-promptbook' || mimeType === 'application/x-promptbook';
35785
- },
35786
- import(content) {
35787
- const parseResult = parseAgentSourceWithCommitments(content);
35788
- // Bring only the agent corpus (non-commitment lines and relevant commitments)
35789
- // Stripping the agent name (which is usually the first line)
35790
- const corpus = parseResult.nonCommitmentLines
35791
- .filter((line, index) => index > 0 || !parseResult.agentName)
35792
- .join('\n')
35793
- .trim();
35794
- // Also include relevant commitments that make up the "corpus" of the agent
35795
- // For example PERSONA, RULE, KNOWLEDGE
35796
- const relevantCommitments = parseResult.commitments
35797
- .filter((c) => ['PERSONA', 'RULE', 'KNOWLEDGE'].includes(c.type))
35798
- .map((c) => `${c.type} ${c.content}`)
35799
- .join('\n\n');
35800
- return spaceTrim$1((block) => `
35801
- ${block(relevantCommitments)}
35802
-
35803
- ${block(corpus)}
35804
- `).trim();
35805
- },
35806
- };
35807
-
35808
- /**
35809
- * Plugin for importing JSON files
35810
- *
35811
- * @private [🥝] Maybe export the import plugins through some package
35812
- */
35813
- const JsonFileImportPlugin = {
35814
- name: 'json-file-import-plugin',
35815
- canImport(mimeType) {
35816
- return mimeType === 'application/json' || mimeType.endsWith('+json');
35817
- },
35818
- import(content) {
35819
- try {
35820
- const json = JSON.parse(content);
35821
- const formattedJson = JSON.stringify(json, null, 4);
35822
- return `\`\`\`json\n${formattedJson}\n\`\`\``;
35823
- }
35824
- catch (error) {
35825
- // If JSON is invalid, still import it but maybe not as pretty JSON
35826
- return `\`\`\`json\n${content}\n\`\`\``;
35827
- }
35828
- },
35829
- };
35830
-
35831
- /**
35832
- * Plugin for importing generic text files
35833
- *
35834
- * @private [🥝] Maybe export the import plugins through some package
35835
- */
35836
- const TextFileImportPlugin = {
35837
- name: 'text-file-import-plugin',
35838
- canImport(mimeType) {
35839
- return (mimeType === 'text/plain' ||
35840
- mimeType === 'text/markdown' ||
35841
- mimeType === 'text/x-typescript' ||
35842
- mimeType === 'text/javascript' ||
35843
- mimeType === 'text/css' ||
35844
- mimeType === 'text/html' ||
35845
- mimeType.startsWith('text/'));
35846
- },
35847
- import(content, mimeType) {
35848
- const extension = mimeTypeToExtension(mimeType);
35849
- const codeBlockType = extension || 'txt';
35850
- return `\`\`\`${codeBlockType}\n${content}\n\`\`\``;
35851
- },
35852
- };
35853
-
35854
- /**
35855
- * All available file import plugins
35856
- *
35857
- * @private [🥝] Maybe export the import plugins through some package
35858
- */
35859
- const $fileImportPlugins = [
35860
- AgentFileImportPlugin,
35861
- JsonFileImportPlugin,
35862
- TextFileImportPlugin,
35863
- ];
35864
-
35865
- /**
35866
- * Removes single-hash comment lines (`# Comment`) from a system message
35867
- * This is used to clean up the final system message before sending it to the AI model
35868
- * while preserving the original content with comments in metadata
35869
- *
35870
- * @param systemMessage The system message that may contain comment lines
35871
- * @returns The system message with single-hash comment lines removed
35872
- *
35873
- * @private - TODO: [🧠] Maybe should be public?
35874
- */
35875
- function removeCommentsFromSystemMessage(systemMessage) {
35876
- if (!systemMessage) {
35877
- return systemMessage;
35878
- }
35879
- const lines = systemMessage.split(/\r?\n/);
35880
- const filteredLines = lines.filter((line) => {
35881
- const trimmedLine = line.trim();
35882
- // Remove only single-hash comment markers (`# Comment`) and keep markdown headings (`## Heading`).
35883
- return !/^#(?!#)\s/.test(trimmedLine);
35884
- });
35885
- return filteredLines.join('\n').trim();
35886
- }
35887
-
35888
- /**
35889
- * Commitment types whose content may contain compact agent references that must be resolved before applying the commitment.
35890
- *
35891
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
35892
- */
35893
- const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS', 'TEAM']);
35894
- /**
35895
- * DELETE-like commitment types that invalidate earlier tagged commitments.
35896
- *
35897
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
35898
- */
35899
- const DELETE_COMMITMENT_TYPES = new Set(['DELETE', 'CANCEL', 'DISCARD', 'REMOVE']);
35900
- /**
35901
- * Commitments whose earlier occurrences are overwritten by the last occurrence in source order.
35902
- *
35903
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
35904
- */
35905
- const OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE = new Map([
35906
- ['GOAL', 'GOAL'],
35907
- ['GOALS', 'GOAL'],
35908
- ]);
35909
- /**
35910
- * Regex pattern matching markdown horizontal lines that should not be copied into the final system message.
35911
- *
35912
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
35913
- */
35914
- const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
35915
- /**
35916
- * MIME type prefixes treated as binary and therefore not eligible for text import plugins.
35917
- *
35918
- * @private internal constant of `createAgentModelRequirementsWithCommitments`
35919
- */
35920
- const BINARY_MIME_TYPE_PREFIXES = [
35921
- 'image/',
35922
- 'video/',
35923
- 'audio/',
35924
- 'application/octet-stream',
35925
- 'application/pdf',
35926
- 'application/zip',
35927
- ];
35928
- /**
35929
- * Returns a safe fallback content when a resolver fails to transform a reference commitment.
35930
- *
35931
- * @param commitmentType - Commitment being resolved.
35932
- * @param originalContent - Original unresolved commitment content.
35933
- * @returns Fallback content that keeps requirement creation resilient.
35934
- *
35935
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
35936
- */
35937
- function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
35938
- if (commitmentType === 'FROM') {
35939
- return 'VOID';
35940
- }
35941
- if (commitmentType === 'IMPORT' || commitmentType === 'IMPORTS' || commitmentType === 'TEAM') {
35942
- return '';
35943
- }
35944
- return originalContent;
35945
- }
35946
- /**
35947
- * Creates agent model requirements by parsing commitments, applying them in source order,
35948
- * and finalizing derived sections such as imports, example interactions, and inline knowledge uploads.
35949
- *
35950
- * @param agentSource - Agent source book to parse.
35951
- * @param modelName - Optional override for the agent model name.
35952
- * @param options - Additional options such as reference and teammate resolvers.
35953
- * @returns Fully prepared model requirements for the parsed agent source.
35954
- *
35955
- * @private internal utility of `createAgentModelRequirements`
35956
- */
35957
- async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
35958
- const parseResult = parseAgentSourceWithCommitments(agentSource);
35959
- const filteredCommitments = filterOverwrittenCommitments(filterDeletedCommitments(parseResult.commitments));
35960
- let requirements = createInitialAgentModelRequirements(parseResult.agentName, modelName);
35961
- requirements = await applyCommitmentsToRequirements(requirements, filteredCommitments, options);
35962
- requirements = aggregateUseCommitmentSystemMessages(requirements, filteredCommitments);
35963
- requirements = await importReferencedFiles(requirements);
35964
- requirements = appendMcpServers(requirements, agentSource);
35965
- requirements = appendNonCommitmentContent(requirements, parseResult);
35966
- requirements = appendExampleInteractions(requirements, parseResult);
35967
- requirements = await applyPendingInlineKnowledgeSources(requirements, options === null || options === void 0 ? void 0 : options.inlineKnowledgeSourceUploader);
35968
- return finalizeRequirements(requirements);
35969
- }
35970
- /**
35971
- * Removes earlier commitments that are overwritten by later commitments of the same semantic group.
35972
- *
35973
- * This currently keeps only the last `GOAL` / `GOALS` commitment so inheritance rewrites
35974
- * and multi-goal sources expose one effective goal to the runtime.
35975
- *
35976
- * @param commitments - Parsed commitments after DELETE-like filtering.
35977
- * @returns Commitments with overwritten entries removed while preserving source order.
35978
- *
35979
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
35980
- */
35981
- function filterOverwrittenCommitments(commitments) {
35982
- const seenOverwriteGroups = new Set();
35983
- const keptCommitments = [];
35984
- for (let index = commitments.length - 1; index >= 0; index--) {
35985
- const commitment = commitments[index];
35986
- const overwriteGroup = OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE.get(commitment.type);
35987
- if (!overwriteGroup) {
35988
- keptCommitments.push(commitment);
35989
- continue;
35990
- }
35991
- if (seenOverwriteGroups.has(overwriteGroup)) {
35992
- continue;
35993
- }
35994
- seenOverwriteGroups.add(overwriteGroup);
35995
- keptCommitments.push(commitment);
35996
- }
35997
- return keptCommitments.reverse();
35623
+ });
35624
+ });
35625
+ },
35626
+ });
35627
+ };
35628
+ // <- TODO: Make types such as there is no need to do `as` for `createTask`
35629
+ return pipelineExecutor;
35998
35630
  }
35631
+
35999
35632
  /**
36000
- * Creates the initial requirements object with the parsed agent name stored in metadata and an optional model override.
35633
+ * Prepares the persona for the pipeline
36001
35634
  *
36002
- * @param agentName - Parsed agent name from the source prelude.
36003
- * @param modelName - Optional explicit model name override.
36004
- * @returns Initial requirements before any commitment is applied.
35635
+ * @see https://github.com/webgptorg/promptbook/discussions/22
36005
35636
  *
36006
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
35637
+ * @public exported from `@promptbook/core`
36007
35638
  */
36008
- function createInitialAgentModelRequirements(agentName, modelName) {
36009
- const initialRequirements = createBasicAgentModelRequirements(agentName);
36010
- const requirementsWithMetadata = {
36011
- ...initialRequirements,
36012
- _metadata: {
36013
- ...initialRequirements._metadata,
36014
- agentName,
36015
- },
36016
- };
36017
- if (!modelName) {
36018
- return requirementsWithMetadata;
35639
+ async function preparePersona(personaDescription, tools, options) {
35640
+ const { isVerbose = DEFAULT_IS_VERBOSE } = options;
35641
+ if (tools === undefined || tools.llm === undefined) {
35642
+ throw new MissingToolsError('LLM tools are required for preparing persona');
36019
35643
  }
36020
- return {
36021
- ...requirementsWithMetadata,
35644
+ // TODO: [🌼] In future use `ptbk make` and made getPipelineCollection
35645
+ const collection = createPipelineCollectionFromJson(...PipelineCollection);
35646
+ const preparePersonaExecutor = createPipelineExecutor({
35647
+ pipeline: await collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book'),
35648
+ tools,
35649
+ });
35650
+ const llmTools = getSingleLlmExecutionTools(tools.llm);
35651
+ const availableModels = (await llmTools.listModels())
35652
+ .filter(({ modelVariant }) => modelVariant === 'CHAT')
35653
+ .map(({ modelName, modelDescription }) => ({
36022
35654
  modelName,
35655
+ modelDescription,
35656
+ // <- Note: `modelTitle` and `modelVariant` is not relevant for this task
35657
+ }));
35658
+ const result = await preparePersonaExecutor({
35659
+ availableModels /* <- Note: Passing as JSON */,
35660
+ personaDescription,
35661
+ }).asPromise({ isCrashedOnError: true });
35662
+ const { outputParameters } = result;
35663
+ const { modelsRequirements: modelsRequirementsJson } = outputParameters;
35664
+ let modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
35665
+ if (isVerbose) {
35666
+ console.info(`PERSONA ${personaDescription}`, modelsRequirementsUnchecked);
35667
+ }
35668
+ if (!Array.isArray(modelsRequirementsUnchecked)) {
35669
+ // <- TODO: Book should have syntax and system to enforce shape of JSON
35670
+ modelsRequirementsUnchecked = [modelsRequirementsUnchecked];
35671
+ /*
35672
+ throw new UnexpectedError(
35673
+ spaceTrim(
35674
+ (block) => `
35675
+ Invalid \`modelsRequirements\`:
35676
+
35677
+ \`\`\`json
35678
+ ${block(JSON.stringify(modelsRequirementsUnchecked, null, 4))}
35679
+ \`\`\`
35680
+ `,
35681
+ ),
35682
+ );
35683
+ */
35684
+ }
35685
+ const modelsRequirements = modelsRequirementsUnchecked.map((modelRequirements) => ({
35686
+ modelVariant: 'CHAT',
35687
+ ...modelRequirements,
35688
+ }));
35689
+ return {
35690
+ modelsRequirements,
36023
35691
  };
36024
35692
  }
35693
+ // TODO: [😩] DRY `preparePersona` and `selectBestModelFromAvailable`
35694
+ // TODO: [🔃][main] If the persona was prepared with different version or different set of models, prepare it once again
35695
+ // TODO: [🏢] Check validity of `modelName` in pipeline
35696
+ // TODO: [🏢] Check validity of `systemMessage` in pipeline
35697
+ // TODO: [🏢] Check validity of `temperature` in pipeline
35698
+
36025
35699
  /**
36026
- * Applies DELETE-like invalidation commitments and returns only commitments that should continue through the pipeline.
36027
- *
36028
- * @param commitments - Parsed commitments in original source order.
36029
- * @returns Filtered commitments with earlier deleted items removed.
35700
+ * Creates an empty/basic agent model requirements object
35701
+ * This serves as the starting point for the reduce-like pattern
35702
+ * where each commitment applies its changes to build the final requirements
36030
35703
  *
36031
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
35704
+ * @public exported from `@promptbook/core`
36032
35705
  */
36033
- function filterDeletedCommitments(commitments) {
36034
- const filteredCommitments = [];
36035
- for (const commitment of commitments) {
36036
- if (!isDeleteCommitmentType(commitment.type)) {
36037
- filteredCommitments.push(commitment);
36038
- continue;
36039
- }
36040
- const targetParameterNames = getCommitmentParameterNames(commitment.content);
36041
- if (targetParameterNames.length === 0) {
36042
- continue;
36043
- }
36044
- for (let index = filteredCommitments.length - 1; index >= 0; index--) {
36045
- const previousCommitment = filteredCommitments[index];
36046
- const previousParameterNames = getCommitmentParameterNames(previousCommitment.content);
36047
- const isTargeted = previousParameterNames.some((parameterName) => targetParameterNames.includes(parameterName));
36048
- if (isTargeted) {
36049
- filteredCommitments.splice(index, 1);
36050
- }
36051
- }
36052
- }
36053
- return filteredCommitments;
35706
+ function createEmptyAgentModelRequirements() {
35707
+ return {
35708
+ systemMessage: '',
35709
+ promptSuffix: '',
35710
+ // modelName: 'gpt-5',
35711
+ modelName: 'gpt-5.4-mini',
35712
+ temperature: 0.7,
35713
+ topP: 0.9,
35714
+ topK: 50,
35715
+ parentAgentUrl: null,
35716
+ isClosed: false,
35717
+ };
36054
35718
  }
36055
35719
  /**
36056
- * Checks whether a commitment type behaves like DELETE and therefore invalidates earlier tagged commitments.
36057
- *
36058
- * @param commitmentType - Commitment type to check.
36059
- * @returns `true` when the commitment removes prior tagged commitments.
35720
+ * Creates a basic agent model requirements with just the agent name
35721
+ * This is used when we have an agent name but no commitments
36060
35722
  *
36061
- * @private internal utility of `filterDeletedCommitments`
35723
+ * @public exported from `@promptbook/core`
36062
35724
  */
36063
- function isDeleteCommitmentType(commitmentType) {
36064
- return DELETE_COMMITMENT_TYPES.has(commitmentType);
35725
+ function createBasicAgentModelRequirements(agentName) {
35726
+ const empty = createEmptyAgentModelRequirements();
35727
+ return {
35728
+ ...empty,
35729
+ systemMessage: `You are ${agentName || 'AI Agent'}`,
35730
+ };
36065
35731
  }
35732
+ // TODO: [🐤] Deduplicate `AgentModelRequirements` and `ModelRequirements` model requirements
35733
+
36066
35734
  /**
36067
- * Extracts normalized parameter names used for DELETE-like invalidation matching.
36068
- *
36069
- * @param content - Commitment content to parse.
36070
- * @returns Lower-cased non-empty parameter names.
35735
+ * Commitment types whose content may contain compact agent references that must be resolved before applying the commitment.
36071
35736
  *
36072
- * @private internal utility of `filterDeletedCommitments`
35737
+ * @private internal constant of `applyCommitmentsToAgentModelRequirements`
36073
35738
  */
36074
- function getCommitmentParameterNames(content) {
36075
- return parseParameters(content)
36076
- .map((parameter) => parameter.name.trim().toLowerCase())
36077
- .filter(Boolean);
36078
- }
35739
+ const COMMITMENTS_WITH_AGENT_REFERENCES = new Set(['FROM', 'IMPORT', 'IMPORTS', 'TEAM']);
36079
35740
  /**
36080
35741
  * Applies parsed commitments one by one while keeping the per-commitment steps focused and easy to follow.
36081
35742
  *
@@ -36084,9 +35745,9 @@ function getCommitmentParameterNames(content) {
36084
35745
  * @param options - Optional reference and teammate resolvers.
36085
35746
  * @returns Requirements after all applicable commitments are processed.
36086
35747
  *
36087
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
35748
+ * @private function of `createAgentModelRequirementsWithCommitments`
36088
35749
  */
36089
- async function applyCommitmentsToRequirements(requirements, commitments, options) {
35750
+ async function applyCommitmentsToAgentModelRequirements(requirements, commitments, options) {
36090
35751
  for (const [index, commitment] of commitments.entries()) {
36091
35752
  if (shouldSkipCommitmentApplication(commitment, index, commitments.length)) {
36092
35753
  continue;
@@ -36104,7 +35765,7 @@ async function applyCommitmentsToRequirements(requirements, commitments, options
36104
35765
  * @param agentReferenceResolver - Optional resolver for compact agent references.
36105
35766
  * @returns Original or resolved commitment content.
36106
35767
  *
36107
- * @private internal utility of `applyCommitmentsToRequirements`
35768
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
36108
35769
  */
36109
35770
  async function resolveCommitmentContent(commitment, agentReferenceResolver) {
36110
35771
  if (!agentReferenceResolver || !isAgentReferenceCommitment(commitment.type)) {
@@ -36118,6 +35779,24 @@ async function resolveCommitmentContent(commitment, agentReferenceResolver) {
36118
35779
  return getSafeReferenceCommitmentFallback(commitment.type, commitment.content);
36119
35780
  }
36120
35781
  }
35782
+ /**
35783
+ * Returns a safe fallback content when a resolver fails to transform a reference commitment.
35784
+ *
35785
+ * @param commitmentType - Commitment being resolved.
35786
+ * @param originalContent - Original unresolved commitment content.
35787
+ * @returns Fallback content that keeps requirement creation resilient.
35788
+ *
35789
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
35790
+ */
35791
+ function getSafeReferenceCommitmentFallback(commitmentType, originalContent) {
35792
+ if (commitmentType === 'FROM') {
35793
+ return 'VOID';
35794
+ }
35795
+ if (commitmentType === 'IMPORT' || commitmentType === 'IMPORTS' || commitmentType === 'TEAM') {
35796
+ return '';
35797
+ }
35798
+ return originalContent;
35799
+ }
36121
35800
  /**
36122
35801
  * Checks whether the commitment content may need agent-reference resolution before application.
36123
35802
  *
@@ -36137,7 +35816,7 @@ function isAgentReferenceCommitment(commitmentType) {
36137
35816
  * @param commitmentCount - Total number of filtered commitments.
36138
35817
  * @returns `true` when the commitment should not be applied.
36139
35818
  *
36140
- * @private internal utility of `applyCommitmentsToRequirements`
35819
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
36141
35820
  */
36142
35821
  function shouldSkipCommitmentApplication(commitment, commitmentIndex, commitmentCount) {
36143
35822
  return commitment.type === 'CLOSED' && commitmentIndex !== commitmentCount - 1;
@@ -36151,7 +35830,7 @@ function shouldSkipCommitmentApplication(commitment, commitmentIndex, commitment
36151
35830
  * @param options - Optional teammate profile resolvers.
36152
35831
  * @returns Requirements with pre-resolved teammate profiles stored in metadata when possible.
36153
35832
  *
36154
- * @private internal utility of `applyCommitmentsToRequirements`
35833
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
36155
35834
  */
36156
35835
  async function preResolveTeammateProfilesForTeamCommitment(requirements, commitment, commitmentContent, options) {
36157
35836
  var _a;
@@ -36206,7 +35885,7 @@ function clonePreResolvedTeammateProfiles(metadata) {
36206
35885
  * @param commitmentContent - Final content passed into the definition.
36207
35886
  * @returns Updated requirements, or the original requirements when the commitment fails.
36208
35887
  *
36209
- * @private internal utility of `applyCommitmentsToRequirements`
35888
+ * @private internal utility of `applyCommitmentsToAgentModelRequirements`
36210
35889
  */
36211
35890
  function applyCommitmentDefinitionSafely(requirements, commitment, commitmentContent) {
36212
35891
  const definition = getCommitmentDefinition(commitment.type);
@@ -36221,13 +35900,140 @@ function applyCommitmentDefinitionSafely(requirements, commitment, commitmentCon
36221
35900
  return requirements;
36222
35901
  }
36223
35902
  }
35903
+
35904
+ /**
35905
+ * Plugin for importing agent books *(`.book` files)*
35906
+ *
35907
+ * @private [🥝] Maybe export the import plugins through some package
35908
+ */
35909
+ const AgentFileImportPlugin = {
35910
+ name: 'agent-file-import-plugin',
35911
+ canImport(mimeType) {
35912
+ // [🧠] Should we have a specific MIME type for agent books?
35913
+ // For now, let's assume it's identified by .book extension or certain MIME types if provided
35914
+ return mimeType === 'text/x-promptbook' || mimeType === 'application/x-promptbook';
35915
+ },
35916
+ import(content) {
35917
+ const parseResult = parseAgentSourceWithCommitments(content);
35918
+ // Bring only the agent corpus (non-commitment lines and relevant commitments)
35919
+ // Stripping the agent name (which is usually the first line)
35920
+ const corpus = parseResult.nonCommitmentLines
35921
+ .filter((line, index) => index > 0 || !parseResult.agentName)
35922
+ .join('\n')
35923
+ .trim();
35924
+ // Also include relevant commitments that make up the "corpus" of the agent
35925
+ // For example PERSONA, RULE, KNOWLEDGE
35926
+ const relevantCommitments = parseResult.commitments
35927
+ .filter((c) => ['PERSONA', 'RULE', 'KNOWLEDGE'].includes(c.type))
35928
+ .map((c) => `${c.type} ${c.content}`)
35929
+ .join('\n\n');
35930
+ return spaceTrim$1((block) => `
35931
+ ${block(relevantCommitments)}
35932
+
35933
+ ${block(corpus)}
35934
+ `).trim();
35935
+ },
35936
+ };
35937
+
35938
+ /**
35939
+ * Plugin for importing JSON files
35940
+ *
35941
+ * @private [🥝] Maybe export the import plugins through some package
35942
+ */
35943
+ const JsonFileImportPlugin = {
35944
+ name: 'json-file-import-plugin',
35945
+ canImport(mimeType) {
35946
+ return mimeType === 'application/json' || mimeType.endsWith('+json');
35947
+ },
35948
+ import(content) {
35949
+ try {
35950
+ const json = JSON.parse(content);
35951
+ const formattedJson = JSON.stringify(json, null, 4);
35952
+ return `\`\`\`json\n${formattedJson}\n\`\`\``;
35953
+ }
35954
+ catch (error) {
35955
+ // If JSON is invalid, still import it but maybe not as pretty JSON
35956
+ return `\`\`\`json\n${content}\n\`\`\``;
35957
+ }
35958
+ },
35959
+ };
35960
+
35961
+ /**
35962
+ * Plugin for importing generic text files
35963
+ *
35964
+ * @private [🥝] Maybe export the import plugins through some package
35965
+ */
35966
+ const TextFileImportPlugin = {
35967
+ name: 'text-file-import-plugin',
35968
+ canImport(mimeType) {
35969
+ return (mimeType === 'text/plain' ||
35970
+ mimeType === 'text/markdown' ||
35971
+ mimeType === 'text/x-typescript' ||
35972
+ mimeType === 'text/javascript' ||
35973
+ mimeType === 'text/css' ||
35974
+ mimeType === 'text/html' ||
35975
+ mimeType.startsWith('text/'));
35976
+ },
35977
+ import(content, mimeType) {
35978
+ const extension = mimeTypeToExtension(mimeType);
35979
+ const codeBlockType = extension || 'txt';
35980
+ return `\`\`\`${codeBlockType}\n${content}\n\`\`\``;
35981
+ },
35982
+ };
35983
+
35984
+ /**
35985
+ * All available file import plugins
35986
+ *
35987
+ * @private [🥝] Maybe export the import plugins through some package
35988
+ */
35989
+ const $fileImportPlugins = [
35990
+ AgentFileImportPlugin,
35991
+ JsonFileImportPlugin,
35992
+ TextFileImportPlugin,
35993
+ ];
35994
+
35995
+ /**
35996
+ * Regex pattern matching markdown horizontal lines that should not be copied into the final system message.
35997
+ *
35998
+ * @private internal constant of `augmentAgentModelRequirementsFromSource`
35999
+ */
36000
+ const HORIZONTAL_LINE_PATTERN = /^[\s]*[-_*][\s]*[-_*][\s]*[-_*][\s]*[-_*]*[\s]*$/;
36001
+ /**
36002
+ * MIME type prefixes treated as binary and therefore not eligible for text import plugins.
36003
+ *
36004
+ * @private internal constant of `augmentAgentModelRequirementsFromSource`
36005
+ */
36006
+ const BINARY_MIME_TYPE_PREFIXES = [
36007
+ 'image/',
36008
+ 'video/',
36009
+ 'audio/',
36010
+ 'application/octet-stream',
36011
+ 'application/pdf',
36012
+ 'application/zip',
36013
+ ];
36014
+ /**
36015
+ * Adds source-derived sections after commitments have been applied.
36016
+ *
36017
+ * @param requirements - Requirements after commitment application and USE aggregation.
36018
+ * @param parseResult - Parsed source used to recover non-commitment prose and examples.
36019
+ * @param agentSource - Original source used to recover MCP server declarations.
36020
+ * @returns Requirements with source-derived sections appended.
36021
+ *
36022
+ * @private function of `createAgentModelRequirementsWithCommitments`
36023
+ */
36024
+ async function augmentAgentModelRequirementsFromSource(requirements, parseResult, agentSource) {
36025
+ requirements = await importReferencedFiles(requirements);
36026
+ requirements = appendMcpServers(requirements, agentSource);
36027
+ requirements = appendNonCommitmentContent(requirements, parseResult);
36028
+ return appendExampleInteractions(requirements, parseResult);
36029
+ }
36224
36030
  /**
36225
36031
  * Imports text files referenced by IMPORT commitments and appends their transformed content to the system message.
36226
36032
  *
36227
36033
  * @param requirements - Requirements possibly containing `importedFileUrls`.
36228
36034
  * @returns Requirements with imported file content appended to the system message.
36229
36035
  *
36230
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36036
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
36231
36037
  */
36232
36038
  async function importReferencedFiles(requirements) {
36233
36039
  const importedFileUrls = requirements.importedFileUrls;
@@ -36313,7 +36119,7 @@ function normalizeImportedMimeType(mimeType) {
36313
36119
  * @param agentSource - Original agent source used for MCP extraction.
36314
36120
  * @returns Requirements with `mcpServers` set when MCP commitments are present.
36315
36121
  *
36316
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36122
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
36317
36123
  */
36318
36124
  function appendMcpServers(requirements, agentSource) {
36319
36125
  const mcpServers = extractMcpServers(agentSource);
@@ -36332,7 +36138,7 @@ function appendMcpServers(requirements, agentSource) {
36332
36138
  * @param parseResult - Parsed source including non-commitment lines.
36333
36139
  * @returns Requirements with the remaining prose appended to the system message.
36334
36140
  *
36335
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36141
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
36336
36142
  */
36337
36143
  function appendNonCommitmentContent(requirements, parseResult) {
36338
36144
  const nonCommitmentContent = getNonCommitmentContent(parseResult);
@@ -36375,7 +36181,7 @@ function isHorizontalLine(line) {
36375
36181
  * @param parseResult - Parsed source used to recover initial message content.
36376
36182
  * @returns Requirements with the example interaction block appended when examples exist.
36377
36183
  *
36378
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36184
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
36379
36185
  */
36380
36186
  function appendExampleInteractions(requirements, parseResult) {
36381
36187
  const exampleInteractionsContent = createExampleInteractionsContent(parseResult, requirements.samples);
@@ -36430,7 +36236,7 @@ function collectExampleInteractionLines(parseResult, samples) {
36430
36236
  * @param section - Section content to append.
36431
36237
  * @returns Requirements with the additional system-message block appended.
36432
36238
  *
36433
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36239
+ * @private internal utility of `augmentAgentModelRequirementsFromSource`
36434
36240
  */
36435
36241
  function appendSystemMessageSection(requirements, section) {
36436
36242
  return {
@@ -36439,29 +36245,149 @@ function appendSystemMessageSection(requirements, section) {
36439
36245
  };
36440
36246
  }
36441
36247
  /**
36442
- * Performs the final system-message cleanup pass after all other augmentation steps are complete.
36248
+ * Mocked security check for imported files.
36443
36249
  *
36444
- * @param requirements - Fully built requirements before final cleanup.
36445
- * @returns Requirements with comment lines removed from the final system message.
36250
+ * @param urlOrPath - The URL or local path of the file to check.
36251
+ * @returns A promise that resolves if the file is considered safe.
36446
36252
  *
36447
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36253
+ * @private internal utility of `createImportedFileSystemMessage`
36448
36254
  */
36449
- function finalizeRequirements(requirements) {
36450
- return {
36451
- ...requirements,
36452
- systemMessage: removeCommentsFromSystemMessage(requirements.systemMessage),
36453
- };
36255
+ async function mockedSecurityCheck(urlOrPath) {
36256
+ // TODO: Implement proper security checks
36257
+ await new Promise((resolve) => setTimeout(resolve, 10));
36258
+ if (urlOrPath.includes('malicious')) {
36259
+ throw new Error(`Security check failed for: ${urlOrPath}`);
36260
+ }
36261
+ }
36262
+ /**
36263
+ * Checks whether the given MIME type belongs to a binary file.
36264
+ *
36265
+ * @param mimeType - The MIME type to check.
36266
+ * @returns `true` when the MIME type is treated as binary.
36267
+ *
36268
+ * @private internal utility of `createImportedFileSystemMessage`
36269
+ */
36270
+ function isBinaryMimeType(mimeType) {
36271
+ return BINARY_MIME_TYPE_PREFIXES.some((prefix) => mimeType.startsWith(prefix));
36272
+ }
36273
+
36274
+ /**
36275
+ * DELETE-like commitment types that invalidate earlier tagged commitments.
36276
+ *
36277
+ * @private internal constant of `filterCommitmentsForAgentModelRequirements`
36278
+ */
36279
+ const DELETE_COMMITMENT_TYPES = new Set(['DELETE', 'CANCEL', 'DISCARD', 'REMOVE']);
36280
+ /**
36281
+ * Commitments whose earlier occurrences are overwritten by the last occurrence in source order.
36282
+ *
36283
+ * @private internal constant of `filterCommitmentsForAgentModelRequirements`
36284
+ */
36285
+ const OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE = new Map([
36286
+ ['GOAL', 'GOAL'],
36287
+ ['GOALS', 'GOAL'],
36288
+ ]);
36289
+ /**
36290
+ * Applies the commitment filtering rules used before commitment definitions are executed.
36291
+ *
36292
+ * @param commitments - Parsed commitments in original source order.
36293
+ * @returns Commitments after DELETE-like invalidation and overwritten-goal filtering.
36294
+ *
36295
+ * @private function of `createAgentModelRequirementsWithCommitments`
36296
+ */
36297
+ function filterCommitmentsForAgentModelRequirements(commitments) {
36298
+ return filterOverwrittenCommitments(filterDeletedCommitments(commitments));
36299
+ }
36300
+ /**
36301
+ * Removes earlier commitments that are overwritten by later commitments of the same semantic group.
36302
+ *
36303
+ * @param commitments - Parsed commitments after DELETE-like filtering.
36304
+ * @returns Commitments with overwritten entries removed while preserving source order.
36305
+ *
36306
+ * @private internal utility of `filterCommitmentsForAgentModelRequirements`
36307
+ */
36308
+ function filterOverwrittenCommitments(commitments) {
36309
+ const seenOverwriteGroups = new Set();
36310
+ const keptCommitments = [];
36311
+ for (let index = commitments.length - 1; index >= 0; index--) {
36312
+ const commitment = commitments[index];
36313
+ const overwriteGroup = OVERWRITTEN_COMMITMENT_GROUP_BY_TYPE.get(commitment.type);
36314
+ if (!overwriteGroup) {
36315
+ keptCommitments.push(commitment);
36316
+ continue;
36317
+ }
36318
+ if (seenOverwriteGroups.has(overwriteGroup)) {
36319
+ continue;
36320
+ }
36321
+ seenOverwriteGroups.add(overwriteGroup);
36322
+ keptCommitments.push(commitment);
36323
+ }
36324
+ return keptCommitments.reverse();
36325
+ }
36326
+ /**
36327
+ * Applies DELETE-like invalidation commitments and returns only commitments that should continue through the pipeline.
36328
+ *
36329
+ * @param commitments - Parsed commitments in original source order.
36330
+ * @returns Filtered commitments with earlier deleted items removed.
36331
+ *
36332
+ * @private internal utility of `filterCommitmentsForAgentModelRequirements`
36333
+ */
36334
+ function filterDeletedCommitments(commitments) {
36335
+ const filteredCommitments = [];
36336
+ for (const commitment of commitments) {
36337
+ if (!isDeleteCommitmentType(commitment.type)) {
36338
+ filteredCommitments.push(commitment);
36339
+ continue;
36340
+ }
36341
+ const targetParameterNames = getCommitmentParameterNames(commitment.content);
36342
+ if (targetParameterNames.length === 0) {
36343
+ continue;
36344
+ }
36345
+ for (let index = filteredCommitments.length - 1; index >= 0; index--) {
36346
+ const previousCommitment = filteredCommitments[index];
36347
+ const previousParameterNames = getCommitmentParameterNames(previousCommitment.content);
36348
+ const isTargeted = previousParameterNames.some((parameterName) => targetParameterNames.includes(parameterName));
36349
+ if (isTargeted) {
36350
+ filteredCommitments.splice(index, 1);
36351
+ }
36352
+ }
36353
+ }
36354
+ return filteredCommitments;
36355
+ }
36356
+ /**
36357
+ * Checks whether a commitment type behaves like DELETE and therefore invalidates earlier tagged commitments.
36358
+ *
36359
+ * @param commitmentType - Commitment type to check.
36360
+ * @returns `true` when the commitment removes prior tagged commitments.
36361
+ *
36362
+ * @private internal utility of `filterDeletedCommitments`
36363
+ */
36364
+ function isDeleteCommitmentType(commitmentType) {
36365
+ return DELETE_COMMITMENT_TYPES.has(commitmentType);
36366
+ }
36367
+ /**
36368
+ * Extracts normalized parameter names used for DELETE-like invalidation matching.
36369
+ *
36370
+ * @param content - Commitment content to parse.
36371
+ * @returns Lower-cased non-empty parameter names.
36372
+ *
36373
+ * @private internal utility of `filterDeletedCommitments`
36374
+ */
36375
+ function getCommitmentParameterNames(content) {
36376
+ return parseParameters(content)
36377
+ .map((parameter) => parameter.name.trim().toLowerCase())
36378
+ .filter(Boolean);
36454
36379
  }
36380
+
36455
36381
  /**
36456
- * Attempts to upload inline knowledge entries, falling back to legacy data URLs when the upload fails or is not configured.
36382
+ * Converts staged inline knowledge files into the final knowledge source URLs stored on requirements.
36457
36383
  *
36458
36384
  * @param requirements - Current requirements snapshot.
36459
36385
  * @param uploader - Optional uploader for inline knowledge files.
36460
36386
  * @returns Requirements with inline knowledge converted into upload URLs or data URLs.
36461
36387
  *
36462
- * @private internal utility of `createAgentModelRequirementsWithCommitments`
36388
+ * @private function of `createAgentModelRequirementsWithCommitments`
36463
36389
  */
36464
- async function applyPendingInlineKnowledgeSources(requirements, uploader) {
36390
+ async function materializeInlineKnowledgeSources(requirements, uploader) {
36465
36391
  var _a;
36466
36392
  const inlineSources = extractInlineKnowledgeSources(requirements._metadata);
36467
36393
  if (inlineSources.length === 0) {
@@ -36487,7 +36413,7 @@ async function applyPendingInlineKnowledgeSources(requirements, uploader) {
36487
36413
  * @param uploader - Upload implementation provided by the caller.
36488
36414
  * @returns Uploaded knowledge URL or a legacy data URL fallback.
36489
36415
  *
36490
- * @private internal utility of `applyPendingInlineKnowledgeSources`
36416
+ * @private internal utility of `materializeInlineKnowledgeSources`
36491
36417
  */
36492
36418
  async function uploadInlineKnowledgeSourceWithFallback(inlineSource, uploader) {
36493
36419
  try {
@@ -36507,7 +36433,7 @@ async function uploadInlineKnowledgeSourceWithFallback(inlineSource, uploader) {
36507
36433
  * @param metadata - Current requirements metadata.
36508
36434
  * @returns Inline knowledge files collected during commitment application.
36509
36435
  *
36510
- * @private internal utility of `applyPendingInlineKnowledgeSources`
36436
+ * @private internal utility of `materializeInlineKnowledgeSources`
36511
36437
  */
36512
36438
  function extractInlineKnowledgeSources(metadata) {
36513
36439
  if (!metadata) {
@@ -36522,7 +36448,7 @@ function extractInlineKnowledgeSources(metadata) {
36522
36448
  * @param metadata - Current requirements metadata.
36523
36449
  * @returns Metadata without the temporary inline knowledge staging field.
36524
36450
  *
36525
- * @private internal utility of `applyPendingInlineKnowledgeSources`
36451
+ * @private internal utility of `materializeInlineKnowledgeSources`
36526
36452
  */
36527
36453
  function stripInlineKnowledgeMetadata(metadata) {
36528
36454
  if (!metadata || !Object.prototype.hasOwnProperty.call(metadata, 'inlineKnowledgeSources')) {
@@ -36531,31 +36457,90 @@ function stripInlineKnowledgeMetadata(metadata) {
36531
36457
  const { inlineKnowledgeSources: _unusedInlineKnowledgeSources, ...rest } = metadata;
36532
36458
  return Object.keys(rest).length > 0 ? rest : undefined;
36533
36459
  }
36460
+
36534
36461
  /**
36535
- * Mocked security check for imported files.
36462
+ * Removes single-hash comment lines (`# Comment`) from a system message
36463
+ * This is used to clean up the final system message before sending it to the AI model
36464
+ * while preserving the original content with comments in metadata
36536
36465
  *
36537
- * @param urlOrPath - The URL or local path of the file to check.
36538
- * @returns A promise that resolves if the file is considered safe.
36466
+ * @param systemMessage The system message that may contain comment lines
36467
+ * @returns The system message with single-hash comment lines removed
36539
36468
  *
36540
- * @private internal utility of `createImportedFileSystemMessage`
36469
+ * @private - TODO: [🧠] Maybe should be public?
36541
36470
  */
36542
- async function mockedSecurityCheck(urlOrPath) {
36543
- // TODO: Implement proper security checks
36544
- await new Promise((resolve) => setTimeout(resolve, 10));
36545
- if (urlOrPath.includes('malicious')) {
36546
- throw new Error(`Security check failed for: ${urlOrPath}`);
36471
+ function removeCommentsFromSystemMessage(systemMessage) {
36472
+ if (!systemMessage) {
36473
+ return systemMessage;
36474
+ }
36475
+ const lines = systemMessage.split(/\r?\n/);
36476
+ const filteredLines = lines.filter((line) => {
36477
+ const trimmedLine = line.trim();
36478
+ // Remove only single-hash comment markers (`# Comment`) and keep markdown headings (`## Heading`).
36479
+ return !/^#(?!#)\s/.test(trimmedLine);
36480
+ });
36481
+ return filteredLines.join('\n').trim();
36482
+ }
36483
+
36484
+ /**
36485
+ * Creates agent model requirements by parsing commitments, applying them in source order,
36486
+ * and finalizing derived sections such as imports, example interactions, and inline knowledge uploads.
36487
+ *
36488
+ * @param agentSource - Agent source book to parse.
36489
+ * @param modelName - Optional override for the agent model name.
36490
+ * @param options - Additional options such as reference and teammate resolvers.
36491
+ * @returns Fully prepared model requirements for the parsed agent source.
36492
+ *
36493
+ * @private internal utility of `createAgentModelRequirements`
36494
+ */
36495
+ async function createAgentModelRequirementsWithCommitments(agentSource, modelName, options) {
36496
+ const parseResult = parseAgentSourceWithCommitments(agentSource);
36497
+ const filteredCommitments = filterCommitmentsForAgentModelRequirements(parseResult.commitments);
36498
+ let requirements = createInitialAgentModelRequirements(parseResult.agentName, modelName);
36499
+ requirements = await applyCommitmentsToAgentModelRequirements(requirements, filteredCommitments, options);
36500
+ requirements = aggregateUseCommitmentSystemMessages(requirements, filteredCommitments);
36501
+ requirements = await augmentAgentModelRequirementsFromSource(requirements, parseResult, agentSource);
36502
+ requirements = await materializeInlineKnowledgeSources(requirements, options === null || options === void 0 ? void 0 : options.inlineKnowledgeSourceUploader);
36503
+ return finalizeRequirements(requirements);
36504
+ }
36505
+ /**
36506
+ * Creates the initial requirements object with the parsed agent name stored in metadata and an optional model override.
36507
+ *
36508
+ * @param agentName - Parsed agent name from the source prelude.
36509
+ * @param modelName - Optional explicit model name override.
36510
+ * @returns Initial requirements before any commitment is applied.
36511
+ *
36512
+ * @private internal utility of `createAgentModelRequirementsWithCommitments`
36513
+ */
36514
+ function createInitialAgentModelRequirements(agentName, modelName) {
36515
+ const initialRequirements = createBasicAgentModelRequirements(agentName);
36516
+ const requirementsWithMetadata = {
36517
+ ...initialRequirements,
36518
+ _metadata: {
36519
+ ...initialRequirements._metadata,
36520
+ agentName,
36521
+ },
36522
+ };
36523
+ if (!modelName) {
36524
+ return requirementsWithMetadata;
36547
36525
  }
36526
+ return {
36527
+ ...requirementsWithMetadata,
36528
+ modelName,
36529
+ };
36548
36530
  }
36549
36531
  /**
36550
- * Checks whether the given MIME type belongs to a binary file.
36532
+ * Performs the final system-message cleanup pass after all other augmentation steps are complete.
36551
36533
  *
36552
- * @param mimeType - The MIME type to check.
36553
- * @returns `true` when the MIME type is treated as binary.
36534
+ * @param requirements - Fully built requirements before final cleanup.
36535
+ * @returns Requirements with comment lines removed from the final system message.
36554
36536
  *
36555
- * @private internal utility of `createImportedFileSystemMessage`
36537
+ * @private internal utility of `createAgentModelRequirementsWithCommitments`
36556
36538
  */
36557
- function isBinaryMimeType(mimeType) {
36558
- return BINARY_MIME_TYPE_PREFIXES.some((prefix) => mimeType.startsWith(prefix));
36539
+ function finalizeRequirements(requirements) {
36540
+ return {
36541
+ ...requirements,
36542
+ systemMessage: removeCommentsFromSystemMessage(requirements.systemMessage),
36543
+ };
36559
36544
  }
36560
36545
 
36561
36546
  /**