@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.
- package/esm/index.es.js +1177 -1192
- package/esm/index.es.js.map +1 -1
- package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/ParsedAgentSourceWithCommitments.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/applyCommitmentsToAgentModelRequirements.d.ts +14 -0
- package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.d.ts +14 -0
- package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/filterCommitmentsForAgentModelRequirements.d.ts +10 -0
- package/esm/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/materializeInlineKnowledgeSources.d.ts +12 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/ParseAgentSourceState.d.ts +10 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/ParsedAgentProfile.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/applyMetaCommitment.d.ts +8 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/consumeConversationSampleCommitment.d.ts +8 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/createCapabilitiesFromCommitment.d.ts +9 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/ensureMetaFullname.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/extractAgentProfileText.d.ts +8 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/extractInitialMessage.d.ts +7 -0
- package/esm/src/book-2.0/agent-source/parseAgentSource/extractParsedAgentProfile.d.ts +8 -0
- package/esm/src/types/LlmToolDefinition.d.ts +17 -7
- package/esm/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +1177 -1192
- package/umd/index.umd.js.map +1 -1
- package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/ParsedAgentSourceWithCommitments.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/applyCommitmentsToAgentModelRequirements.d.ts +14 -0
- package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/augmentAgentModelRequirementsFromSource.d.ts +14 -0
- package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/filterCommitmentsForAgentModelRequirements.d.ts +10 -0
- package/umd/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments/materializeInlineKnowledgeSources.d.ts +12 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/ParseAgentSourceState.d.ts +10 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/ParsedAgentProfile.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/applyMetaCommitment.d.ts +8 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/consumeConversationSampleCommitment.d.ts +8 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/createCapabilitiesFromCommitment.d.ts +9 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/ensureMetaFullname.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/extractAgentProfileText.d.ts +8 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/extractInitialMessage.d.ts +7 -0
- package/umd/src/book-2.0/agent-source/parseAgentSource/extractParsedAgentProfile.d.ts +8 -0
- package/umd/src/types/LlmToolDefinition.d.ts +17 -7
- 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-
|
|
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
|
-
|
|
16385
|
-
|
|
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
|
-
|
|
16439
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
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
|
-
*
|
|
21228
|
+
* Normalizes a domain-like string into a comparable hostname form.
|
|
21364
21229
|
*
|
|
21365
|
-
*
|
|
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
|
|
21368
|
-
const
|
|
21369
|
-
|
|
21370
|
-
|
|
21371
|
-
|
|
21372
|
-
|
|
21373
|
-
|
|
21374
|
-
|
|
21375
|
-
|
|
21376
|
-
|
|
21377
|
-
|
|
21378
|
-
|
|
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
|
-
*
|
|
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
|
|
21394
|
-
|
|
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
|
-
|
|
21398
|
-
|
|
21399
|
-
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
|
21802
|
-
const
|
|
21803
|
-
|
|
21804
|
-
|
|
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
|
|
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
|
-
*
|
|
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
|
-
*
|
|
21812
|
-
*
|
|
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
|
-
* @
|
|
21757
|
+
* @public exported from `@promptbook/core`
|
|
21815
21758
|
*/
|
|
21816
|
-
function
|
|
21817
|
-
const
|
|
21818
|
-
|
|
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
|
-
*
|
|
35633
|
+
* Prepares the persona for the pipeline
|
|
36001
35634
|
*
|
|
36002
|
-
* @
|
|
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
|
-
* @
|
|
35637
|
+
* @public exported from `@promptbook/core`
|
|
36007
35638
|
*/
|
|
36008
|
-
function
|
|
36009
|
-
const
|
|
36010
|
-
|
|
36011
|
-
|
|
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
|
-
|
|
36021
|
-
|
|
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
|
-
*
|
|
36027
|
-
*
|
|
36028
|
-
*
|
|
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
|
-
* @
|
|
35704
|
+
* @public exported from `@promptbook/core`
|
|
36032
35705
|
*/
|
|
36033
|
-
function
|
|
36034
|
-
|
|
36035
|
-
|
|
36036
|
-
|
|
36037
|
-
|
|
36038
|
-
|
|
36039
|
-
|
|
36040
|
-
|
|
36041
|
-
|
|
36042
|
-
|
|
36043
|
-
|
|
36044
|
-
|
|
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
|
-
*
|
|
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
|
-
* @
|
|
35723
|
+
* @public exported from `@promptbook/core`
|
|
36062
35724
|
*/
|
|
36063
|
-
function
|
|
36064
|
-
|
|
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
|
-
*
|
|
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
|
|
35737
|
+
* @private internal constant of `applyCommitmentsToAgentModelRequirements`
|
|
36073
35738
|
*/
|
|
36074
|
-
|
|
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
|
|
35748
|
+
* @private function of `createAgentModelRequirementsWithCommitments`
|
|
36088
35749
|
*/
|
|
36089
|
-
async function
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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
|
-
*
|
|
36248
|
+
* Mocked security check for imported files.
|
|
36443
36249
|
*
|
|
36444
|
-
* @param
|
|
36445
|
-
* @returns
|
|
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 `
|
|
36253
|
+
* @private internal utility of `createImportedFileSystemMessage`
|
|
36448
36254
|
*/
|
|
36449
|
-
function
|
|
36450
|
-
|
|
36451
|
-
|
|
36452
|
-
|
|
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
|
-
*
|
|
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
|
|
36388
|
+
* @private function of `createAgentModelRequirementsWithCommitments`
|
|
36463
36389
|
*/
|
|
36464
|
-
async function
|
|
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 `
|
|
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 `
|
|
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 `
|
|
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
|
-
*
|
|
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
|
|
36538
|
-
* @returns
|
|
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
|
|
36469
|
+
* @private - TODO: [🧠] Maybe should be public?
|
|
36541
36470
|
*/
|
|
36542
|
-
|
|
36543
|
-
|
|
36544
|
-
|
|
36545
|
-
|
|
36546
|
-
|
|
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
|
-
*
|
|
36532
|
+
* Performs the final system-message cleanup pass after all other augmentation steps are complete.
|
|
36551
36533
|
*
|
|
36552
|
-
* @param
|
|
36553
|
-
* @returns
|
|
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 `
|
|
36537
|
+
* @private internal utility of `createAgentModelRequirementsWithCommitments`
|
|
36556
36538
|
*/
|
|
36557
|
-
function
|
|
36558
|
-
return
|
|
36539
|
+
function finalizeRequirements(requirements) {
|
|
36540
|
+
return {
|
|
36541
|
+
...requirements,
|
|
36542
|
+
systemMessage: removeCommentsFromSystemMessage(requirements.systemMessage),
|
|
36543
|
+
};
|
|
36559
36544
|
}
|
|
36560
36545
|
|
|
36561
36546
|
/**
|