@promptbook/core 0.100.0-3 → 0.100.0-32
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/README.md +1 -0
- package/esm/index.es.js +2348 -351
- package/esm/index.es.js.map +1 -1
- package/esm/typings/src/_packages/components.index.d.ts +4 -0
- package/esm/typings/src/_packages/core.index.d.ts +24 -0
- package/esm/typings/src/_packages/types.index.d.ts +30 -0
- package/esm/typings/src/book-2.0/agent-source/parseAgentSource.d.ts +30 -0
- package/esm/typings/src/book-2.0/agent-source/parseAgentSource.test.d.ts +1 -0
- package/esm/typings/src/book-2.0/agent-source/string_book.d.ts +26 -0
- package/esm/typings/src/book-2.0/commitments/ACTION/ACTION.d.ts +38 -0
- package/esm/typings/src/book-2.0/commitments/FORMAT/FORMAT.d.ts +39 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/FrontendRAGService.d.ts +48 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/KNOWLEDGE.d.ts +51 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/RAGService.d.ts +54 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/BaseKnowledgeProcessor.d.ts +45 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/PdfProcessor.d.ts +31 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/ProcessorFactory.d.ts +23 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/TextProcessor.d.ts +18 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/types.d.ts +56 -0
- package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/utils/ragHelper.d.ts +34 -0
- package/esm/typings/src/book-2.0/commitments/META_IMAGE/META_IMAGE.d.ts +44 -0
- package/esm/typings/src/book-2.0/commitments/META_LINK/META_LINK.d.ts +56 -0
- package/esm/typings/src/book-2.0/commitments/MODEL/MODEL.d.ts +39 -0
- package/esm/typings/src/book-2.0/commitments/NOTE/NOTE.d.ts +49 -0
- package/esm/typings/src/book-2.0/commitments/PERSONA/PERSONA.d.ts +46 -0
- package/esm/typings/src/book-2.0/commitments/RULE/RULE.d.ts +44 -0
- package/esm/typings/src/book-2.0/commitments/SAMPLE/SAMPLE.d.ts +44 -0
- package/esm/typings/src/book-2.0/commitments/STYLE/STYLE.d.ts +38 -0
- package/esm/typings/src/book-2.0/commitments/_base/BaseCommitmentDefinition.d.ts +52 -0
- package/esm/typings/src/book-2.0/commitments/_base/BookCommitment.d.ts +5 -0
- package/esm/typings/src/book-2.0/commitments/_base/CommitmentDefinition.d.ts +48 -0
- package/esm/typings/src/book-2.0/commitments/_base/NotYetImplementedCommitmentDefinition.d.ts +22 -0
- package/esm/typings/src/book-2.0/commitments/_base/createEmptyAgentModelRequirements.d.ts +19 -0
- package/esm/typings/src/book-2.0/commitments/_misc/AgentModelRequirements.d.ts +37 -0
- package/esm/typings/src/book-2.0/commitments/_misc/AgentSourceParseResult.d.ts +18 -0
- package/esm/typings/src/book-2.0/commitments/_misc/ParsedCommitment.d.ts +22 -0
- package/esm/typings/src/book-2.0/commitments/_misc/createAgentModelRequirements.d.ts +61 -0
- package/esm/typings/src/book-2.0/commitments/_misc/createAgentModelRequirementsWithCommitments.d.ts +35 -0
- package/esm/typings/src/book-2.0/commitments/_misc/createCommitmentRegex.d.ts +20 -0
- package/esm/typings/src/book-2.0/commitments/_misc/parseAgentSourceWithCommitments.d.ts +24 -0
- package/esm/typings/src/book-2.0/commitments/_misc/removeCommentsFromSystemMessage.d.ts +11 -0
- package/esm/typings/src/book-2.0/commitments/index.d.ts +56 -0
- package/esm/typings/src/book-2.0/utils/profileImageUtils.d.ts +39 -0
- package/esm/typings/src/book-components/BookEditor/BookEditor.d.ts +26 -0
- package/esm/typings/src/execution/AvailableModel.d.ts +4 -0
- package/esm/typings/src/execution/createPipelineExecutor/40-executeAttempts.d.ts +6 -1
- package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +0 -5
- package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
- package/esm/typings/src/llm-providers/deepseek/deepseek-models.d.ts +1 -1
- package/esm/typings/src/llm-providers/google/google-models.d.ts +1 -1
- package/esm/typings/src/llm-providers/ollama/ollama-models.d.ts +1 -1
- package/esm/typings/src/llm-providers/openai/openai-models.d.ts +1 -1
- package/esm/typings/src/pipeline/book-notation.d.ts +2 -1
- package/esm/typings/src/types/ModelRequirements.d.ts +0 -2
- package/esm/typings/src/types/typeAliases.d.ts +6 -0
- package/esm/typings/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/umd/index.umd.js +2213 -204
- package/umd/index.umd.js.map +1 -1
package/esm/index.es.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import spaceTrim, { spaceTrim
|
|
1
|
+
import spaceTrim$1, { spaceTrim } from 'spacetrim';
|
|
2
2
|
import { format } from 'prettier';
|
|
3
3
|
import parserHtml from 'prettier/parser-html';
|
|
4
4
|
import { randomBytes } from 'crypto';
|
|
@@ -27,136 +27,342 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
|
|
|
27
27
|
* @generated
|
|
28
28
|
* @see https://github.com/webgptorg/promptbook
|
|
29
29
|
*/
|
|
30
|
-
const PROMPTBOOK_ENGINE_VERSION = '0.100.0-
|
|
30
|
+
const PROMPTBOOK_ENGINE_VERSION = '0.100.0-32';
|
|
31
31
|
/**
|
|
32
32
|
* TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
|
|
33
33
|
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* Extracts profile image URL from agent definition text and returns cleaned system message
|
|
38
|
+
* @param systemMessage The original system message that may contain META IMAGE line
|
|
39
|
+
* @returns Object with profileImageUrl (if found) and cleanedSystemMessage (without META IMAGE line)
|
|
38
40
|
*
|
|
39
|
-
*
|
|
41
|
+
* @private - TODO: [🧠] Maybe should be public?
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* Generates a gravatar URL based on agent name for fallback avatar
|
|
45
|
+
* @param name The agent name to generate avatar for
|
|
46
|
+
* @returns Gravatar URL
|
|
40
47
|
*
|
|
41
|
-
* @
|
|
48
|
+
* @private - TODO: [🧠] Maybe should be public?
|
|
42
49
|
*/
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
50
|
+
function generateGravatarUrl(name) {
|
|
51
|
+
// Use a default name if none provided
|
|
52
|
+
const safeName = name || 'Anonymous Agent';
|
|
53
|
+
// Create a simple hash from the name for consistent avatar
|
|
54
|
+
let hash = 0;
|
|
55
|
+
for (let i = 0; i < safeName.length; i++) {
|
|
56
|
+
const char = safeName.charCodeAt(i);
|
|
57
|
+
hash = (hash << 5) - hash + char;
|
|
58
|
+
hash = hash & hash; // Convert to 32bit integer
|
|
59
|
+
}
|
|
60
|
+
const avatarId = Math.abs(hash).toString();
|
|
61
|
+
return `https://www.gravatar.com/avatar/${avatarId}?default=robohash&size=200&rating=x`;
|
|
47
62
|
}
|
|
48
63
|
/**
|
|
49
|
-
*
|
|
64
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
50
65
|
*/
|
|
51
66
|
|
|
52
67
|
/**
|
|
53
|
-
*
|
|
68
|
+
* Freezes the given object and all its nested objects recursively
|
|
69
|
+
*
|
|
70
|
+
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
71
|
+
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
54
72
|
*
|
|
73
|
+
* @returns The same object as the input, but deeply frozen
|
|
55
74
|
* @public exported from `@promptbook/utils`
|
|
56
75
|
*/
|
|
57
|
-
function
|
|
58
|
-
if (
|
|
59
|
-
return
|
|
76
|
+
function $deepFreeze(objectValue) {
|
|
77
|
+
if (Array.isArray(objectValue)) {
|
|
78
|
+
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
60
79
|
}
|
|
61
|
-
|
|
62
|
-
|
|
80
|
+
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
81
|
+
for (const propertyName of propertyNames) {
|
|
82
|
+
const value = objectValue[propertyName];
|
|
83
|
+
if (value && typeof value === 'object') {
|
|
84
|
+
$deepFreeze(value);
|
|
85
|
+
}
|
|
63
86
|
}
|
|
64
|
-
|
|
87
|
+
Object.freeze(objectValue);
|
|
88
|
+
return objectValue;
|
|
65
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
92
|
+
*/
|
|
66
93
|
|
|
67
94
|
/**
|
|
68
|
-
*
|
|
95
|
+
* Generates a regex pattern to match a specific commitment
|
|
69
96
|
*
|
|
70
|
-
* Note:
|
|
71
|
-
*
|
|
97
|
+
* Note: It always creates new Regex object
|
|
98
|
+
* Note: Uses word boundaries to ensure only full words are matched (e.g., "PERSONA" matches but "PERSONALITY" does not)
|
|
99
|
+
*
|
|
100
|
+
* @private
|
|
72
101
|
*/
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
102
|
+
function createCommitmentRegex(commitment) {
|
|
103
|
+
const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
104
|
+
const keywordPattern = escapedCommitment.split(/\s+/).join('\\s+');
|
|
105
|
+
const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b\\s+(?<contents>.+)$`, 'gim');
|
|
106
|
+
return regex;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Generates a regex pattern to match a specific commitment type
|
|
110
|
+
*
|
|
111
|
+
* Note: It just matches the type part of the commitment
|
|
112
|
+
* Note: It always creates new Regex object
|
|
113
|
+
* Note: Uses word boundaries to ensure only full words are matched (e.g., "PERSONA" matches but "PERSONALITY" does not)
|
|
114
|
+
*
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
function createCommitmentTypeRegex(commitment) {
|
|
118
|
+
const escapedCommitment = commitment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
119
|
+
const keywordPattern = escapedCommitment.split(/\s+/).join('\\s+');
|
|
120
|
+
const regex = new RegExp(`^\\s*(?<type>${keywordPattern})\\b`, 'gim');
|
|
121
|
+
return regex;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Base implementation of CommitmentDefinition that provides common functionality
|
|
126
|
+
* Most commitments can extend this class and only override the applyToAgentModelRequirements method
|
|
127
|
+
*
|
|
128
|
+
* @private
|
|
129
|
+
*/
|
|
130
|
+
class BaseCommitmentDefinition {
|
|
131
|
+
constructor(type) {
|
|
132
|
+
this.type = type;
|
|
76
133
|
}
|
|
77
|
-
|
|
78
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Creates a regex pattern to match this commitment in agent source
|
|
136
|
+
* Uses the existing createCommitmentRegex function as internal helper
|
|
137
|
+
*/
|
|
138
|
+
createRegex() {
|
|
139
|
+
return createCommitmentRegex(this.type);
|
|
79
140
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
141
|
+
/**
|
|
142
|
+
* Creates a regex pattern to match just the commitment type
|
|
143
|
+
* Uses the existing createCommitmentTypeRegex function as internal helper
|
|
144
|
+
*/
|
|
145
|
+
createTypeRegex() {
|
|
146
|
+
return createCommitmentTypeRegex(this.type);
|
|
83
147
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Helper method to create a new requirements object with updated system message
|
|
150
|
+
* This is commonly used by many commitments
|
|
151
|
+
*/
|
|
152
|
+
updateSystemMessage(requirements, messageUpdate) {
|
|
153
|
+
const newMessage = typeof messageUpdate === 'string' ? messageUpdate : messageUpdate(requirements.systemMessage);
|
|
154
|
+
return {
|
|
155
|
+
...requirements,
|
|
156
|
+
systemMessage: newMessage,
|
|
157
|
+
};
|
|
89
158
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
159
|
+
/**
|
|
160
|
+
* Helper method to append content to the system message
|
|
161
|
+
*/
|
|
162
|
+
appendToSystemMessage(requirements, content, separator = '\n\n') {
|
|
163
|
+
return this.updateSystemMessage(requirements, (currentMessage) => {
|
|
164
|
+
if (!currentMessage.trim()) {
|
|
165
|
+
return content;
|
|
166
|
+
}
|
|
167
|
+
return currentMessage + separator + content;
|
|
168
|
+
});
|
|
94
169
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Helper method to add a comment section to the system message
|
|
172
|
+
* Comments are lines starting with # that will be removed from the final system message
|
|
173
|
+
* but can be useful for organizing and structuring the message during processing
|
|
174
|
+
*/
|
|
175
|
+
addCommentSection(requirements, commentTitle, content, position = 'end') {
|
|
176
|
+
const commentSection = `# ${commentTitle.toUpperCase()}\n${content}`;
|
|
177
|
+
if (position === 'beginning') {
|
|
178
|
+
return this.updateSystemMessage(requirements, (currentMessage) => {
|
|
179
|
+
if (!currentMessage.trim()) {
|
|
180
|
+
return commentSection;
|
|
181
|
+
}
|
|
182
|
+
return commentSection + '\n\n' + currentMessage;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
return this.appendToSystemMessage(requirements, commentSection);
|
|
187
|
+
}
|
|
99
188
|
}
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* ACTION commitment definition
|
|
193
|
+
*
|
|
194
|
+
* The ACTION commitment defines specific actions or capabilities that the agent can perform.
|
|
195
|
+
* This helps define what the agent is capable of doing and how it should approach tasks.
|
|
196
|
+
*
|
|
197
|
+
* Example usage in agent source:
|
|
198
|
+
*
|
|
199
|
+
* ```book
|
|
200
|
+
* ACTION Can generate code snippets and explain programming concepts
|
|
201
|
+
* ACTION Able to analyze data and provide insights
|
|
202
|
+
* ```
|
|
203
|
+
*
|
|
204
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
205
|
+
*/
|
|
206
|
+
class ActionCommitmentDefinition extends BaseCommitmentDefinition {
|
|
207
|
+
constructor() {
|
|
208
|
+
super('ACTION');
|
|
104
209
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
210
|
+
/**
|
|
211
|
+
* Short one-line description of ACTION.
|
|
212
|
+
*/
|
|
213
|
+
get description() {
|
|
214
|
+
return 'Define agent capabilities and actions it can perform.';
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Markdown documentation for ACTION commitment.
|
|
218
|
+
*/
|
|
219
|
+
get documentation() {
|
|
220
|
+
return spaceTrim(`
|
|
221
|
+
# ACTION
|
|
222
|
+
|
|
223
|
+
Defines specific actions or capabilities that the agent can perform.
|
|
224
|
+
|
|
225
|
+
## Key behaviors
|
|
226
|
+
|
|
227
|
+
- Multiple \`ACTION\` commitments are applied sequentially.
|
|
228
|
+
- Each action adds to the agent's capability list.
|
|
229
|
+
- Actions help users understand what the agent can do.
|
|
230
|
+
|
|
231
|
+
## Examples
|
|
232
|
+
|
|
233
|
+
\`\`\`book
|
|
234
|
+
Code Assistant
|
|
235
|
+
|
|
236
|
+
PERSONA You are a programming assistant
|
|
237
|
+
ACTION Can generate code snippets and explain programming concepts
|
|
238
|
+
ACTION Able to debug existing code and suggest improvements
|
|
239
|
+
ACTION Can create unit tests for functions
|
|
240
|
+
\`\`\`
|
|
241
|
+
|
|
242
|
+
\`\`\`book
|
|
243
|
+
Data Scientist
|
|
244
|
+
|
|
245
|
+
PERSONA You are a data analysis expert
|
|
246
|
+
ACTION Able to analyze data and provide insights
|
|
247
|
+
ACTION Can create visualizations and charts
|
|
248
|
+
ACTION Capable of statistical analysis and modeling
|
|
249
|
+
KNOWLEDGE Data analysis best practices and statistical methods
|
|
250
|
+
\`\`\`
|
|
251
|
+
`);
|
|
252
|
+
}
|
|
253
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
254
|
+
const trimmedContent = content.trim();
|
|
255
|
+
if (!trimmedContent) {
|
|
256
|
+
return requirements;
|
|
257
|
+
}
|
|
258
|
+
// Add action capability to the system message
|
|
259
|
+
const actionSection = `Capability: ${trimmedContent}`;
|
|
260
|
+
return this.appendToSystemMessage(requirements, actionSection, '\n\n');
|
|
109
261
|
}
|
|
110
|
-
return false;
|
|
111
262
|
}
|
|
112
263
|
/**
|
|
113
|
-
*
|
|
264
|
+
* Singleton instance of the ACTION commitment definition
|
|
265
|
+
*
|
|
266
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
267
|
+
*/
|
|
268
|
+
new ActionCommitmentDefinition();
|
|
269
|
+
/**
|
|
270
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
114
271
|
*/
|
|
115
272
|
|
|
116
273
|
/**
|
|
117
|
-
*
|
|
274
|
+
* FORMAT commitment definition
|
|
118
275
|
*
|
|
119
|
-
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
* - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
|
|
276
|
+
* The FORMAT commitment defines the specific output structure and formatting
|
|
277
|
+
* that the agent should use in its responses. This includes data formats,
|
|
278
|
+
* response templates, and structural requirements.
|
|
123
279
|
*
|
|
124
|
-
*
|
|
280
|
+
* Example usage in agent source:
|
|
281
|
+
*
|
|
282
|
+
* ```book
|
|
283
|
+
* FORMAT Always respond in JSON format with 'status' and 'data' fields
|
|
284
|
+
* FORMAT Use markdown formatting for all code blocks
|
|
285
|
+
* ```
|
|
286
|
+
*
|
|
287
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
125
288
|
*/
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
289
|
+
class FormatCommitmentDefinition extends BaseCommitmentDefinition {
|
|
290
|
+
constructor() {
|
|
291
|
+
super('FORMAT');
|
|
129
292
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
return true;
|
|
293
|
+
/**
|
|
294
|
+
* Short one-line description of FORMAT.
|
|
295
|
+
*/
|
|
296
|
+
get description() {
|
|
297
|
+
return 'Specify output structure or formatting requirements.';
|
|
139
298
|
}
|
|
140
|
-
|
|
141
|
-
|
|
299
|
+
/**
|
|
300
|
+
* Markdown documentation for FORMAT commitment.
|
|
301
|
+
*/
|
|
302
|
+
get documentation() {
|
|
303
|
+
return spaceTrim(`
|
|
304
|
+
# FORMAT
|
|
305
|
+
|
|
306
|
+
Defines the specific output structure and formatting for responses (data formats, templates, structure).
|
|
307
|
+
|
|
308
|
+
## Key behaviors
|
|
309
|
+
|
|
310
|
+
- Multiple \`FORMAT\` commitments are applied sequentially.
|
|
311
|
+
- If they are in conflict, the last one takes precedence.
|
|
312
|
+
- You can specify both data formats and presentation styles.
|
|
313
|
+
|
|
314
|
+
## Examples
|
|
315
|
+
|
|
316
|
+
\`\`\`book
|
|
317
|
+
Customer Support Bot
|
|
318
|
+
|
|
319
|
+
PERSONA You are a helpful customer support agent
|
|
320
|
+
FORMAT Always respond in JSON format with 'status' and 'data' fields
|
|
321
|
+
FORMAT Use markdown formatting for all code blocks
|
|
322
|
+
\`\`\`
|
|
323
|
+
|
|
324
|
+
\`\`\`book
|
|
325
|
+
Data Analyst
|
|
326
|
+
|
|
327
|
+
PERSONA You are a data analysis expert
|
|
328
|
+
FORMAT Present results in structured tables
|
|
329
|
+
FORMAT Include confidence scores for all predictions
|
|
330
|
+
STYLE Be concise and precise in explanations
|
|
331
|
+
\`\`\`
|
|
332
|
+
`);
|
|
333
|
+
}
|
|
334
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
335
|
+
const trimmedContent = content.trim();
|
|
336
|
+
if (!trimmedContent) {
|
|
337
|
+
return requirements;
|
|
338
|
+
}
|
|
339
|
+
// Add format instructions to the system message
|
|
340
|
+
const formatSection = `Output Format: ${trimmedContent}`;
|
|
341
|
+
return this.appendToSystemMessage(requirements, formatSection, '\n\n');
|
|
142
342
|
}
|
|
143
343
|
}
|
|
344
|
+
/**
|
|
345
|
+
* Singleton instance of the FORMAT commitment definition
|
|
346
|
+
*
|
|
347
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
348
|
+
*/
|
|
349
|
+
new FormatCommitmentDefinition();
|
|
350
|
+
/**
|
|
351
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
352
|
+
*/
|
|
144
353
|
|
|
145
354
|
/**
|
|
146
|
-
*
|
|
355
|
+
* Error thrown when a fetch request fails
|
|
147
356
|
*
|
|
148
357
|
* @public exported from `@promptbook/core`
|
|
149
358
|
*/
|
|
150
|
-
class
|
|
359
|
+
class PromptbookFetchError extends Error {
|
|
151
360
|
constructor(message) {
|
|
152
361
|
super(message);
|
|
153
|
-
this.name = '
|
|
154
|
-
Object.setPrototypeOf(this,
|
|
362
|
+
this.name = 'PromptbookFetchError';
|
|
363
|
+
Object.setPrototypeOf(this, PromptbookFetchError.prototype);
|
|
155
364
|
}
|
|
156
365
|
}
|
|
157
|
-
/**
|
|
158
|
-
* TODO: Maybe split `ParseError` and `ApplyError`
|
|
159
|
-
*/
|
|
160
366
|
|
|
161
367
|
/**
|
|
162
368
|
* Available remote servers for the Promptbook
|
|
@@ -516,7 +722,7 @@ true);
|
|
|
516
722
|
function getErrorReportUrl(error) {
|
|
517
723
|
const report = {
|
|
518
724
|
title: `🐜 Error report from ${NAME}`,
|
|
519
|
-
body: spaceTrim((block) => `
|
|
725
|
+
body: spaceTrim$1((block) => `
|
|
520
726
|
|
|
521
727
|
|
|
522
728
|
\`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
|
|
@@ -559,7 +765,7 @@ function getErrorReportUrl(error) {
|
|
|
559
765
|
*/
|
|
560
766
|
class UnexpectedError extends Error {
|
|
561
767
|
constructor(message) {
|
|
562
|
-
super(spaceTrim
|
|
768
|
+
super(spaceTrim((block) => `
|
|
563
769
|
${block(message)}
|
|
564
770
|
|
|
565
771
|
Note: This error should not happen.
|
|
@@ -577,52 +783,1883 @@ class UnexpectedError extends Error {
|
|
|
577
783
|
}
|
|
578
784
|
|
|
579
785
|
/**
|
|
580
|
-
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
786
|
+
* This error type indicates that somewhere in the code non-Error object was thrown and it was wrapped into the `WrappedError`
|
|
787
|
+
*
|
|
788
|
+
* @public exported from `@promptbook/core`
|
|
789
|
+
*/
|
|
790
|
+
class WrappedError extends Error {
|
|
791
|
+
constructor(whatWasThrown) {
|
|
792
|
+
const tag = `[🤮]`;
|
|
793
|
+
console.error(tag, whatWasThrown);
|
|
794
|
+
super(spaceTrim(`
|
|
795
|
+
Non-Error object was thrown
|
|
796
|
+
|
|
797
|
+
Note: Look for ${tag} in the console for more details
|
|
798
|
+
Please report issue on ${ADMIN_EMAIL}
|
|
799
|
+
`));
|
|
800
|
+
this.name = 'WrappedError';
|
|
801
|
+
Object.setPrototypeOf(this, WrappedError.prototype);
|
|
802
|
+
}
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
/**
|
|
806
|
+
* Helper used in catch blocks to assert that the error is an instance of `Error`
|
|
807
|
+
*
|
|
808
|
+
* @param whatWasThrown Any object that was thrown
|
|
809
|
+
* @returns Nothing if the error is an instance of `Error`
|
|
810
|
+
* @throws `WrappedError` or `UnexpectedError` if the error is not standard
|
|
811
|
+
*
|
|
812
|
+
* @private within the repository
|
|
813
|
+
*/
|
|
814
|
+
function assertsError(whatWasThrown) {
|
|
815
|
+
// Case 1: Handle error which was rethrown as `WrappedError`
|
|
816
|
+
if (whatWasThrown instanceof WrappedError) {
|
|
817
|
+
const wrappedError = whatWasThrown;
|
|
818
|
+
throw wrappedError;
|
|
819
|
+
}
|
|
820
|
+
// Case 2: Handle unexpected errors
|
|
821
|
+
if (whatWasThrown instanceof UnexpectedError) {
|
|
822
|
+
const unexpectedError = whatWasThrown;
|
|
823
|
+
throw unexpectedError;
|
|
824
|
+
}
|
|
825
|
+
// Case 3: Handle standard errors - keep them up to consumer
|
|
826
|
+
if (whatWasThrown instanceof Error) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
// Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
|
|
830
|
+
throw new WrappedError(whatWasThrown);
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
/**
|
|
834
|
+
* The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
|
|
835
|
+
*
|
|
836
|
+
* @public exported from `@promptbook/core`
|
|
837
|
+
*/
|
|
838
|
+
const promptbookFetch = async (urlOrRequest, init) => {
|
|
839
|
+
try {
|
|
840
|
+
return await fetch(urlOrRequest, init);
|
|
841
|
+
}
|
|
842
|
+
catch (error) {
|
|
843
|
+
assertsError(error);
|
|
844
|
+
let url;
|
|
845
|
+
if (typeof urlOrRequest === 'string') {
|
|
846
|
+
url = urlOrRequest;
|
|
847
|
+
}
|
|
848
|
+
else if (urlOrRequest instanceof Request) {
|
|
849
|
+
url = urlOrRequest.url;
|
|
850
|
+
}
|
|
851
|
+
throw new PromptbookFetchError(spaceTrim$1((block) => `
|
|
852
|
+
Can not fetch "${url}"
|
|
853
|
+
|
|
854
|
+
Fetch error:
|
|
855
|
+
${block(error.message)}
|
|
856
|
+
|
|
857
|
+
`));
|
|
858
|
+
}
|
|
859
|
+
};
|
|
860
|
+
/**
|
|
861
|
+
* TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
|
|
862
|
+
*/
|
|
863
|
+
|
|
864
|
+
/**
|
|
865
|
+
* Frontend RAG Service that uses backend APIs for processing
|
|
866
|
+
* This avoids Node.js dependencies in the frontend
|
|
867
|
+
*
|
|
868
|
+
* @private - TODO: [🧠] Maybe should be public?
|
|
869
|
+
*/
|
|
870
|
+
class FrontendRAGService {
|
|
871
|
+
constructor(config) {
|
|
872
|
+
this.chunks = [];
|
|
873
|
+
this.sources = [];
|
|
874
|
+
this.isInitialized = false;
|
|
875
|
+
this.config = {
|
|
876
|
+
maxChunkSize: 1000,
|
|
877
|
+
chunkOverlap: 200,
|
|
878
|
+
maxRetrievedChunks: 5,
|
|
879
|
+
minRelevanceScore: 0.1,
|
|
880
|
+
...config,
|
|
881
|
+
};
|
|
882
|
+
}
|
|
883
|
+
/**
|
|
884
|
+
* Initialize knowledge sources by processing them on the backend
|
|
885
|
+
*/
|
|
886
|
+
async initializeKnowledgeSources(sources) {
|
|
887
|
+
if (sources.length === 0) {
|
|
888
|
+
this.isInitialized = true;
|
|
889
|
+
return;
|
|
890
|
+
}
|
|
891
|
+
try {
|
|
892
|
+
const response = await promptbookFetch('/api/knowledge/process-sources', {
|
|
893
|
+
method: 'POST',
|
|
894
|
+
headers: {
|
|
895
|
+
'Content-Type': 'application/json',
|
|
896
|
+
},
|
|
897
|
+
body: JSON.stringify({
|
|
898
|
+
sources,
|
|
899
|
+
config: {
|
|
900
|
+
maxChunkSize: this.config.maxChunkSize,
|
|
901
|
+
chunkOverlap: this.config.chunkOverlap,
|
|
902
|
+
},
|
|
903
|
+
}),
|
|
904
|
+
});
|
|
905
|
+
if (!response.ok) {
|
|
906
|
+
throw new Error(`Failed to process knowledge sources: ${response.status}`);
|
|
907
|
+
}
|
|
908
|
+
const result = (await response.json());
|
|
909
|
+
if (!result.success) {
|
|
910
|
+
throw new Error(result.message || 'Failed to process knowledge sources');
|
|
911
|
+
}
|
|
912
|
+
this.chunks = result.chunks;
|
|
913
|
+
this.sources = sources;
|
|
914
|
+
this.isInitialized = true;
|
|
915
|
+
console.log(`Initialized RAG service with ${this.chunks.length} chunks from ${sources.length} sources`);
|
|
916
|
+
}
|
|
917
|
+
catch (error) {
|
|
918
|
+
console.error('Failed to initialize knowledge sources:', error);
|
|
919
|
+
// Don't throw - allow the system to continue without RAG
|
|
920
|
+
this.isInitialized = true;
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Get relevant context for a user query
|
|
925
|
+
*/
|
|
926
|
+
async getContextForQuery(query) {
|
|
927
|
+
if (!this.isInitialized) {
|
|
928
|
+
console.warn('RAG service not initialized');
|
|
929
|
+
return '';
|
|
930
|
+
}
|
|
931
|
+
if (this.chunks.length === 0) {
|
|
932
|
+
return '';
|
|
933
|
+
}
|
|
934
|
+
try {
|
|
935
|
+
const response = await promptbookFetch('/api/knowledge/retrieve-context', {
|
|
936
|
+
method: 'POST',
|
|
937
|
+
headers: {
|
|
938
|
+
'Content-Type': 'application/json',
|
|
939
|
+
},
|
|
940
|
+
body: JSON.stringify({
|
|
941
|
+
query,
|
|
942
|
+
chunks: this.chunks,
|
|
943
|
+
config: {
|
|
944
|
+
maxRetrievedChunks: this.config.maxRetrievedChunks,
|
|
945
|
+
minRelevanceScore: this.config.minRelevanceScore,
|
|
946
|
+
},
|
|
947
|
+
}),
|
|
948
|
+
});
|
|
949
|
+
if (!response.ok) {
|
|
950
|
+
console.error(`Failed to retrieve context: ${response.status}`);
|
|
951
|
+
return '';
|
|
952
|
+
}
|
|
953
|
+
const result = (await response.json());
|
|
954
|
+
if (!result.success) {
|
|
955
|
+
console.error('Context retrieval failed:', result.message);
|
|
956
|
+
return '';
|
|
957
|
+
}
|
|
958
|
+
return result.context;
|
|
959
|
+
}
|
|
960
|
+
catch (error) {
|
|
961
|
+
console.error('Error retrieving context:', error);
|
|
962
|
+
return '';
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Get relevant chunks for a query (for debugging/inspection)
|
|
967
|
+
*/
|
|
968
|
+
async getRelevantChunks(query) {
|
|
969
|
+
if (!this.isInitialized || this.chunks.length === 0) {
|
|
970
|
+
return [];
|
|
971
|
+
}
|
|
972
|
+
try {
|
|
973
|
+
const response = await promptbookFetch('/api/knowledge/retrieve-context', {
|
|
974
|
+
method: 'POST',
|
|
975
|
+
headers: {
|
|
976
|
+
'Content-Type': 'application/json',
|
|
977
|
+
},
|
|
978
|
+
body: JSON.stringify({
|
|
979
|
+
query,
|
|
980
|
+
chunks: this.chunks,
|
|
981
|
+
config: {
|
|
982
|
+
maxRetrievedChunks: this.config.maxRetrievedChunks,
|
|
983
|
+
minRelevanceScore: this.config.minRelevanceScore,
|
|
984
|
+
},
|
|
985
|
+
}),
|
|
986
|
+
});
|
|
987
|
+
if (!response.ok) {
|
|
988
|
+
return [];
|
|
989
|
+
}
|
|
990
|
+
const result = (await response.json());
|
|
991
|
+
return result.success ? result.relevantChunks : [];
|
|
992
|
+
}
|
|
993
|
+
catch (error) {
|
|
994
|
+
console.error('Error retrieving relevant chunks:', error);
|
|
995
|
+
return [];
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
/**
|
|
999
|
+
* Get knowledge base statistics
|
|
1000
|
+
*/
|
|
1001
|
+
getStats() {
|
|
1002
|
+
return {
|
|
1003
|
+
sources: this.sources.length,
|
|
1004
|
+
chunks: this.chunks.length,
|
|
1005
|
+
isInitialized: this.isInitialized,
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
/**
|
|
1009
|
+
* Check if the service is ready to use
|
|
1010
|
+
*/
|
|
1011
|
+
isReady() {
|
|
1012
|
+
return this.isInitialized;
|
|
1013
|
+
}
|
|
1014
|
+
/**
|
|
1015
|
+
* Clear all knowledge sources
|
|
1016
|
+
*/
|
|
1017
|
+
clearKnowledgeBase() {
|
|
1018
|
+
this.chunks = [];
|
|
1019
|
+
this.sources = [];
|
|
1020
|
+
this.isInitialized = false;
|
|
1021
|
+
}
|
|
1022
|
+
/**
|
|
1023
|
+
* Add a single knowledge source (for incremental updates)
|
|
1024
|
+
*/
|
|
1025
|
+
async addKnowledgeSource(url) {
|
|
1026
|
+
if (this.sources.includes(url)) {
|
|
1027
|
+
console.log(`Knowledge source already exists: ${url}`);
|
|
1028
|
+
return;
|
|
1029
|
+
}
|
|
1030
|
+
try {
|
|
1031
|
+
const response = await promptbookFetch('/api/knowledge/process-sources', {
|
|
1032
|
+
method: 'POST',
|
|
1033
|
+
headers: {
|
|
1034
|
+
'Content-Type': 'application/json',
|
|
1035
|
+
},
|
|
1036
|
+
body: JSON.stringify({
|
|
1037
|
+
sources: [url],
|
|
1038
|
+
config: {
|
|
1039
|
+
maxChunkSize: this.config.maxChunkSize,
|
|
1040
|
+
chunkOverlap: this.config.chunkOverlap,
|
|
1041
|
+
},
|
|
1042
|
+
}),
|
|
1043
|
+
});
|
|
1044
|
+
if (!response.ok) {
|
|
1045
|
+
throw new Error(`Failed to process knowledge source: ${response.status}`);
|
|
1046
|
+
}
|
|
1047
|
+
const result = (await response.json());
|
|
1048
|
+
if (!result.success) {
|
|
1049
|
+
throw new Error(result.message || 'Failed to process knowledge source');
|
|
1050
|
+
}
|
|
1051
|
+
// Add new chunks to existing ones
|
|
1052
|
+
this.chunks.push(...result.chunks);
|
|
1053
|
+
this.sources.push(url);
|
|
1054
|
+
console.log(`Added knowledge source: ${url} (${result.chunks.length} chunks)`);
|
|
1055
|
+
}
|
|
1056
|
+
catch (error) {
|
|
1057
|
+
console.error(`Failed to add knowledge source ${url}:`, error);
|
|
1058
|
+
throw error;
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* KNOWLEDGE commitment definition
|
|
1065
|
+
*
|
|
1066
|
+
* The KNOWLEDGE commitment adds specific knowledge, facts, or context to the agent
|
|
1067
|
+
* using RAG (Retrieval-Augmented Generation) approach for external sources.
|
|
1068
|
+
*
|
|
1069
|
+
* Supports both direct text knowledge and external sources like PDFs.
|
|
1070
|
+
*
|
|
1071
|
+
* Example usage in agent source:
|
|
1072
|
+
*
|
|
1073
|
+
* ```book
|
|
1074
|
+
* KNOWLEDGE The company was founded in 2020 and specializes in AI-powered solutions
|
|
1075
|
+
* KNOWLEDGE https://example.com/company-handbook.pdf
|
|
1076
|
+
* KNOWLEDGE https://example.com/product-documentation.pdf
|
|
1077
|
+
* ```
|
|
1078
|
+
*
|
|
1079
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1080
|
+
*/
|
|
1081
|
+
class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1082
|
+
constructor() {
|
|
1083
|
+
super('KNOWLEDGE');
|
|
1084
|
+
this.ragService = new FrontendRAGService();
|
|
1085
|
+
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Short one-line description of KNOWLEDGE.
|
|
1088
|
+
*/
|
|
1089
|
+
get description() {
|
|
1090
|
+
return 'Add domain **knowledge** via direct text or external sources (RAG).';
|
|
1091
|
+
}
|
|
1092
|
+
/**
|
|
1093
|
+
* Markdown documentation for KNOWLEDGE commitment.
|
|
1094
|
+
*/
|
|
1095
|
+
get documentation() {
|
|
1096
|
+
return spaceTrim(`
|
|
1097
|
+
# KNOWLEDGE
|
|
1098
|
+
|
|
1099
|
+
Adds specific knowledge, facts, or context to the agent using a RAG (Retrieval-Augmented Generation) approach for external sources.
|
|
1100
|
+
|
|
1101
|
+
## Key behaviors
|
|
1102
|
+
|
|
1103
|
+
- Multiple \`KNOWLEDGE\` commitments are applied sequentially.
|
|
1104
|
+
- Supports both direct text knowledge and external URLs.
|
|
1105
|
+
- External sources (PDFs, websites) are processed via RAG for context retrieval.
|
|
1106
|
+
|
|
1107
|
+
## Supported formats
|
|
1108
|
+
|
|
1109
|
+
- Direct text: Immediate knowledge incorporated into agent
|
|
1110
|
+
- URLs: External documents processed for contextual retrieval
|
|
1111
|
+
- Supported file types: PDF, text, markdown, HTML
|
|
1112
|
+
|
|
1113
|
+
## Examples
|
|
1114
|
+
|
|
1115
|
+
\`\`\`book
|
|
1116
|
+
Customer Support Bot
|
|
1117
|
+
|
|
1118
|
+
PERSONA You are a helpful customer support agent for TechCorp
|
|
1119
|
+
KNOWLEDGE TechCorp was founded in 2020 and specializes in AI-powered solutions
|
|
1120
|
+
KNOWLEDGE https://example.com/company-handbook.pdf
|
|
1121
|
+
KNOWLEDGE https://example.com/product-documentation.pdf
|
|
1122
|
+
RULE Always be polite and professional
|
|
1123
|
+
\`\`\`
|
|
1124
|
+
|
|
1125
|
+
\`\`\`book
|
|
1126
|
+
Research Assistant
|
|
1127
|
+
|
|
1128
|
+
PERSONA You are a knowledgeable research assistant
|
|
1129
|
+
KNOWLEDGE Academic research requires careful citation and verification
|
|
1130
|
+
KNOWLEDGE https://example.com/research-guidelines.pdf
|
|
1131
|
+
ACTION Can help with literature reviews and data analysis
|
|
1132
|
+
STYLE Present information in clear, academic format
|
|
1133
|
+
\`\`\`
|
|
1134
|
+
`);
|
|
1135
|
+
}
|
|
1136
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1137
|
+
var _a;
|
|
1138
|
+
const trimmedContent = content.trim();
|
|
1139
|
+
if (!trimmedContent) {
|
|
1140
|
+
return requirements;
|
|
1141
|
+
}
|
|
1142
|
+
// Check if content is a URL (external knowledge source)
|
|
1143
|
+
if (this.isUrl(trimmedContent)) {
|
|
1144
|
+
// Store the URL for later async processing
|
|
1145
|
+
const updatedRequirements = {
|
|
1146
|
+
...requirements,
|
|
1147
|
+
metadata: {
|
|
1148
|
+
...requirements.metadata,
|
|
1149
|
+
ragService: this.ragService,
|
|
1150
|
+
knowledgeSources: [
|
|
1151
|
+
...(((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.knowledgeSources) || []),
|
|
1152
|
+
trimmedContent,
|
|
1153
|
+
],
|
|
1154
|
+
},
|
|
1155
|
+
};
|
|
1156
|
+
// Add placeholder information about knowledge sources to system message
|
|
1157
|
+
const knowledgeInfo = `Knowledge Source URL: ${trimmedContent} (will be processed for retrieval during chat)`;
|
|
1158
|
+
return this.appendToSystemMessage(updatedRequirements, knowledgeInfo, '\n\n');
|
|
1159
|
+
}
|
|
1160
|
+
else {
|
|
1161
|
+
// Direct text knowledge - add to system message
|
|
1162
|
+
const knowledgeSection = `Knowledge: ${trimmedContent}`;
|
|
1163
|
+
return this.appendToSystemMessage(requirements, knowledgeSection, '\n\n');
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
/**
|
|
1167
|
+
* Check if content is a URL
|
|
1168
|
+
*/
|
|
1169
|
+
isUrl(content) {
|
|
1170
|
+
try {
|
|
1171
|
+
new URL(content);
|
|
1172
|
+
return true;
|
|
1173
|
+
}
|
|
1174
|
+
catch (_a) {
|
|
1175
|
+
return false;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* Get RAG service instance for retrieving context during chat
|
|
1180
|
+
*/
|
|
1181
|
+
getRagService() {
|
|
1182
|
+
return this.ragService;
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
/**
|
|
1186
|
+
* Singleton instance of the KNOWLEDGE commitment definition
|
|
1187
|
+
*
|
|
1188
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1189
|
+
*/
|
|
1190
|
+
new KnowledgeCommitmentDefinition();
|
|
1191
|
+
/**
|
|
1192
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1193
|
+
*/
|
|
1194
|
+
|
|
1195
|
+
/**
|
|
1196
|
+
* META IMAGE commitment definition
|
|
1197
|
+
*
|
|
1198
|
+
* The META IMAGE commitment sets the agent's avatar/profile image URL.
|
|
1199
|
+
* This commitment is special because it doesn't affect the system message,
|
|
1200
|
+
* but is handled separately in the parsing logic.
|
|
1201
|
+
*
|
|
1202
|
+
* Example usage in agent source:
|
|
1203
|
+
*
|
|
1204
|
+
* ```book
|
|
1205
|
+
* META IMAGE https://example.com/avatar.jpg
|
|
1206
|
+
* META IMAGE /assets/agent-avatar.png
|
|
1207
|
+
* ```
|
|
1208
|
+
*
|
|
1209
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1210
|
+
*/
|
|
1211
|
+
class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1212
|
+
constructor() {
|
|
1213
|
+
super('META IMAGE');
|
|
1214
|
+
}
|
|
1215
|
+
/**
|
|
1216
|
+
* Short one-line description of META IMAGE.
|
|
1217
|
+
*/
|
|
1218
|
+
get description() {
|
|
1219
|
+
return "Set the agent's profile image URL.";
|
|
1220
|
+
}
|
|
1221
|
+
/**
|
|
1222
|
+
* Markdown documentation for META IMAGE commitment.
|
|
1223
|
+
*/
|
|
1224
|
+
get documentation() {
|
|
1225
|
+
return spaceTrim(`
|
|
1226
|
+
# META IMAGE
|
|
1227
|
+
|
|
1228
|
+
Sets the agent's avatar/profile image URL.
|
|
1229
|
+
|
|
1230
|
+
## Key behaviors
|
|
1231
|
+
|
|
1232
|
+
- Does not modify the agent's behavior or responses.
|
|
1233
|
+
- Only one \`META IMAGE\` should be used per agent.
|
|
1234
|
+
- If multiple are specified, the last one takes precedence.
|
|
1235
|
+
- Used for visual representation in user interfaces.
|
|
1236
|
+
|
|
1237
|
+
## Examples
|
|
1238
|
+
|
|
1239
|
+
\`\`\`book
|
|
1240
|
+
Professional Assistant
|
|
1241
|
+
|
|
1242
|
+
META IMAGE https://example.com/professional-avatar.jpg
|
|
1243
|
+
PERSONA You are a professional business assistant
|
|
1244
|
+
STYLE Maintain a formal and courteous tone
|
|
1245
|
+
\`\`\`
|
|
1246
|
+
|
|
1247
|
+
\`\`\`book
|
|
1248
|
+
Creative Helper
|
|
1249
|
+
|
|
1250
|
+
META IMAGE /assets/creative-bot-avatar.png
|
|
1251
|
+
PERSONA You are a creative and inspiring assistant
|
|
1252
|
+
STYLE Be enthusiastic and encouraging
|
|
1253
|
+
ACTION Can help with brainstorming and ideation
|
|
1254
|
+
\`\`\`
|
|
1255
|
+
`);
|
|
1256
|
+
}
|
|
1257
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1258
|
+
// META IMAGE doesn't modify the system message or model requirements
|
|
1259
|
+
// It's handled separately in the parsing logic for profile image extraction
|
|
1260
|
+
// This method exists for consistency with the CommitmentDefinition interface
|
|
1261
|
+
return requirements;
|
|
1262
|
+
}
|
|
1263
|
+
/**
|
|
1264
|
+
* Extracts the profile image URL from the content
|
|
1265
|
+
* This is used by the parsing logic
|
|
1266
|
+
*/
|
|
1267
|
+
extractProfileImageUrl(content) {
|
|
1268
|
+
const trimmedContent = content.trim();
|
|
1269
|
+
return trimmedContent || null;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
/**
|
|
1273
|
+
* Singleton instance of the META IMAGE commitment definition
|
|
1274
|
+
*
|
|
1275
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1276
|
+
*/
|
|
1277
|
+
new MetaImageCommitmentDefinition();
|
|
1278
|
+
/**
|
|
1279
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1280
|
+
*/
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* META LINK commitment definition
|
|
1284
|
+
*
|
|
1285
|
+
* The `META LINK` commitment represents the link to the person from whom the agent is created.
|
|
1286
|
+
* This commitment is special because it doesn't affect the system message,
|
|
1287
|
+
* but is handled separately in the parsing logic for profile display.
|
|
1288
|
+
*
|
|
1289
|
+
* Example usage in agent source:
|
|
1290
|
+
*
|
|
1291
|
+
* ```
|
|
1292
|
+
* META LINK https://twitter.com/username
|
|
1293
|
+
* META LINK https://linkedin.com/in/profile
|
|
1294
|
+
* META LINK https://github.com/username
|
|
1295
|
+
* ```
|
|
1296
|
+
*
|
|
1297
|
+
* Multiple `META LINK` commitments can be used when there are multiple sources:
|
|
1298
|
+
*
|
|
1299
|
+
* ```book
|
|
1300
|
+
* META LINK https://twitter.com/username
|
|
1301
|
+
* META LINK https://linkedin.com/in/profile
|
|
1302
|
+
* ```
|
|
1303
|
+
*
|
|
1304
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1305
|
+
*/
|
|
1306
|
+
class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1307
|
+
constructor() {
|
|
1308
|
+
super('META LINK');
|
|
1309
|
+
}
|
|
1310
|
+
/**
|
|
1311
|
+
* Short one-line description of META LINK.
|
|
1312
|
+
*/
|
|
1313
|
+
get description() {
|
|
1314
|
+
return 'Provide profile/source links for the person the agent models.';
|
|
1315
|
+
}
|
|
1316
|
+
/**
|
|
1317
|
+
* Markdown documentation for META LINK commitment.
|
|
1318
|
+
*/
|
|
1319
|
+
get documentation() {
|
|
1320
|
+
return spaceTrim(`
|
|
1321
|
+
# META LINK
|
|
1322
|
+
|
|
1323
|
+
Represents a profile or source link for the person the agent is modeled after.
|
|
1324
|
+
|
|
1325
|
+
## Key behaviors
|
|
1326
|
+
|
|
1327
|
+
- Does not modify the agent's behavior or responses.
|
|
1328
|
+
- Multiple \`META LINK\` commitments can be used for different social profiles.
|
|
1329
|
+
- Used for attribution and crediting the original person.
|
|
1330
|
+
- Displayed in user interfaces for transparency.
|
|
1331
|
+
|
|
1332
|
+
## Examples
|
|
1333
|
+
|
|
1334
|
+
\`\`\`book
|
|
1335
|
+
Expert Consultant
|
|
1336
|
+
|
|
1337
|
+
META LINK https://twitter.com/expertname
|
|
1338
|
+
META LINK https://linkedin.com/in/expertprofile
|
|
1339
|
+
PERSONA You are Dr. Smith, a renowned expert in artificial intelligence
|
|
1340
|
+
KNOWLEDGE Extensive background in machine learning and neural networks
|
|
1341
|
+
\`\`\`
|
|
1342
|
+
|
|
1343
|
+
\`\`\`book
|
|
1344
|
+
Open Source Developer
|
|
1345
|
+
|
|
1346
|
+
META LINK https://github.com/developer
|
|
1347
|
+
META LINK https://twitter.com/devhandle
|
|
1348
|
+
PERSONA You are an experienced open source developer
|
|
1349
|
+
ACTION Can help with code reviews and architecture decisions
|
|
1350
|
+
STYLE Be direct and technical in explanations
|
|
1351
|
+
\`\`\`
|
|
1352
|
+
`);
|
|
1353
|
+
}
|
|
1354
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1355
|
+
// META LINK doesn't modify the system message or model requirements
|
|
1356
|
+
// It's handled separately in the parsing logic for profile link extraction
|
|
1357
|
+
// This method exists for consistency with the CommitmentDefinition interface
|
|
1358
|
+
return requirements;
|
|
1359
|
+
}
|
|
1360
|
+
/**
|
|
1361
|
+
* Extracts the profile link URL from the content
|
|
1362
|
+
* This is used by the parsing logic
|
|
1363
|
+
*/
|
|
1364
|
+
extractProfileLinkUrl(content) {
|
|
1365
|
+
const trimmedContent = content.trim();
|
|
1366
|
+
return trimmedContent || null;
|
|
1367
|
+
}
|
|
1368
|
+
/**
|
|
1369
|
+
* Validates if the provided content is a valid URL
|
|
1370
|
+
*/
|
|
1371
|
+
isValidUrl(content) {
|
|
1372
|
+
try {
|
|
1373
|
+
new URL(content.trim());
|
|
1374
|
+
return true;
|
|
1375
|
+
}
|
|
1376
|
+
catch (_a) {
|
|
1377
|
+
return false;
|
|
1378
|
+
}
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* Singleton instance of the META LINK commitment definition
|
|
1383
|
+
*
|
|
1384
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1385
|
+
*/
|
|
1386
|
+
new MetaLinkCommitmentDefinition();
|
|
1387
|
+
/**
|
|
1388
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1389
|
+
*/
|
|
1390
|
+
|
|
1391
|
+
/**
|
|
1392
|
+
* MODEL commitment definition
|
|
1393
|
+
*
|
|
1394
|
+
* The MODEL commitment specifies which AI model to use and can also set
|
|
1395
|
+
* model-specific parameters like temperature, topP, and topK.
|
|
1396
|
+
*
|
|
1397
|
+
* Example usage in agent source:
|
|
1398
|
+
*
|
|
1399
|
+
* ```book
|
|
1400
|
+
* MODEL gpt-4
|
|
1401
|
+
* MODEL claude-3-opus temperature=0.3
|
|
1402
|
+
* MODEL gpt-3.5-turbo temperature=0.8 topP=0.9
|
|
1403
|
+
* ```
|
|
1404
|
+
*
|
|
1405
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1406
|
+
*/
|
|
1407
|
+
class ModelCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1408
|
+
constructor() {
|
|
1409
|
+
super('MODEL');
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Short one-line description of MODEL.
|
|
1413
|
+
*/
|
|
1414
|
+
get description() {
|
|
1415
|
+
return 'Select the AI model and optional decoding parameters.';
|
|
1416
|
+
}
|
|
1417
|
+
/**
|
|
1418
|
+
* Markdown documentation for MODEL commitment.
|
|
1419
|
+
*/
|
|
1420
|
+
get documentation() {
|
|
1421
|
+
return spaceTrim(`
|
|
1422
|
+
# MODEL
|
|
1423
|
+
|
|
1424
|
+
Specifies which AI model to use and optional decoding parameters.
|
|
1425
|
+
|
|
1426
|
+
## Key behaviors
|
|
1427
|
+
|
|
1428
|
+
- Only one \`MODEL\` commitment should be used per agent.
|
|
1429
|
+
- If multiple are specified, the last one takes precedence.
|
|
1430
|
+
- Parameters control the randomness and creativity of responses.
|
|
1431
|
+
|
|
1432
|
+
## Supported parameters
|
|
1433
|
+
|
|
1434
|
+
- \`temperature\`: Controls randomness (0.0 = deterministic, 1.0+ = creative)
|
|
1435
|
+
- \`topP\` (aka \`top_p\`): Nucleus sampling parameter
|
|
1436
|
+
- \`topK\` (aka \`top_k\`): Top-k sampling parameter
|
|
1437
|
+
|
|
1438
|
+
## Examples
|
|
1439
|
+
|
|
1440
|
+
\`\`\`book
|
|
1441
|
+
Precise Assistant
|
|
1442
|
+
|
|
1443
|
+
PERSONA You are a precise and accurate assistant
|
|
1444
|
+
MODEL gpt-4 temperature=0.1
|
|
1445
|
+
RULE Always provide factual information
|
|
1446
|
+
\`\`\`
|
|
1447
|
+
|
|
1448
|
+
\`\`\`book
|
|
1449
|
+
Creative Writer
|
|
1450
|
+
|
|
1451
|
+
PERSONA You are a creative writing assistant
|
|
1452
|
+
MODEL claude-3-opus temperature=0.8 topP=0.9
|
|
1453
|
+
STYLE Be imaginative and expressive
|
|
1454
|
+
ACTION Can help with storytelling and character development
|
|
1455
|
+
\`\`\`
|
|
1456
|
+
`);
|
|
1457
|
+
}
|
|
1458
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1459
|
+
const trimmedContent = content.trim();
|
|
1460
|
+
if (!trimmedContent) {
|
|
1461
|
+
return requirements;
|
|
1462
|
+
}
|
|
1463
|
+
// Parse the model specification
|
|
1464
|
+
const parts = trimmedContent.split(/\s+/);
|
|
1465
|
+
const modelName = parts[0];
|
|
1466
|
+
if (!modelName) {
|
|
1467
|
+
return requirements;
|
|
1468
|
+
}
|
|
1469
|
+
// Start with the model name
|
|
1470
|
+
const updatedRequirements = {
|
|
1471
|
+
...requirements,
|
|
1472
|
+
modelName,
|
|
1473
|
+
};
|
|
1474
|
+
// Parse additional parameters
|
|
1475
|
+
const result = { ...updatedRequirements };
|
|
1476
|
+
for (let i = 1; i < parts.length; i++) {
|
|
1477
|
+
const param = parts[i];
|
|
1478
|
+
if (param && param.includes('=')) {
|
|
1479
|
+
const [key, value] = param.split('=');
|
|
1480
|
+
if (key && value) {
|
|
1481
|
+
const numValue = parseFloat(value);
|
|
1482
|
+
if (!isNaN(numValue)) {
|
|
1483
|
+
switch (key.toLowerCase()) {
|
|
1484
|
+
case 'temperature':
|
|
1485
|
+
result.temperature = numValue;
|
|
1486
|
+
break;
|
|
1487
|
+
case 'topp':
|
|
1488
|
+
case 'top_p':
|
|
1489
|
+
result.topP = numValue;
|
|
1490
|
+
break;
|
|
1491
|
+
case 'topk':
|
|
1492
|
+
case 'top_k':
|
|
1493
|
+
result.topK = Math.round(numValue);
|
|
1494
|
+
break;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return result;
|
|
1501
|
+
}
|
|
1502
|
+
}
|
|
1503
|
+
/**
|
|
1504
|
+
* Singleton instance of the MODEL commitment definition
|
|
1505
|
+
*
|
|
1506
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1507
|
+
*/
|
|
1508
|
+
new ModelCommitmentDefinition();
|
|
1509
|
+
/**
|
|
1510
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1511
|
+
*/
|
|
1512
|
+
|
|
1513
|
+
/**
|
|
1514
|
+
* NOTE commitment definition
|
|
1515
|
+
*
|
|
1516
|
+
* The NOTE commitment is used to add comments to the agent source without making any changes
|
|
1517
|
+
* to the system message or agent model requirements. It serves as a documentation mechanism
|
|
1518
|
+
* for developers to add explanatory comments, reminders, or annotations directly in the agent source.
|
|
1519
|
+
*
|
|
1520
|
+
* Key features:
|
|
1521
|
+
* - Makes no changes to the system message
|
|
1522
|
+
* - Makes no changes to agent model requirements
|
|
1523
|
+
* - Content is preserved in metadata.NOTE for debugging and inspection
|
|
1524
|
+
* - Multiple NOTE commitments are aggregated together
|
|
1525
|
+
* - Comments (# NOTE) are removed from the final system message
|
|
1526
|
+
*
|
|
1527
|
+
* Example usage in agent source:
|
|
1528
|
+
*
|
|
1529
|
+
* ```book
|
|
1530
|
+
* NOTE This agent was designed for customer support scenarios
|
|
1531
|
+
* NOTE Remember to update the knowledge base monthly
|
|
1532
|
+
* NOTE Performance optimized for quick response times
|
|
1533
|
+
* ```
|
|
1534
|
+
*
|
|
1535
|
+
* The above notes will be stored in metadata but won't affect the agent's behavior.
|
|
1536
|
+
*
|
|
1537
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1538
|
+
*/
|
|
1539
|
+
class NoteCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1540
|
+
constructor() {
|
|
1541
|
+
super('NOTE');
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Short one-line description of NOTE.
|
|
1545
|
+
*/
|
|
1546
|
+
get description() {
|
|
1547
|
+
return 'Add developer-facing notes without changing behavior or output.';
|
|
1548
|
+
}
|
|
1549
|
+
/**
|
|
1550
|
+
* Markdown documentation for NOTE commitment.
|
|
1551
|
+
*/
|
|
1552
|
+
get documentation() {
|
|
1553
|
+
return spaceTrim(`
|
|
1554
|
+
# NOTE
|
|
1555
|
+
|
|
1556
|
+
Adds comments for documentation without changing agent behavior.
|
|
1557
|
+
|
|
1558
|
+
## Key behaviors
|
|
1559
|
+
|
|
1560
|
+
- Does not modify the agent's behavior or responses.
|
|
1561
|
+
- Multiple \`NOTE\` commitments are aggregated for debugging.
|
|
1562
|
+
- Useful for documenting design decisions and reminders.
|
|
1563
|
+
- Content is preserved in metadata for inspection.
|
|
1564
|
+
|
|
1565
|
+
## Examples
|
|
1566
|
+
|
|
1567
|
+
\`\`\`book
|
|
1568
|
+
Customer Support Bot
|
|
1569
|
+
|
|
1570
|
+
NOTE This agent was designed for customer support scenarios
|
|
1571
|
+
NOTE Remember to update the knowledge base monthly
|
|
1572
|
+
PERSONA You are a helpful customer support representative
|
|
1573
|
+
KNOWLEDGE Company policies and procedures
|
|
1574
|
+
RULE Always be polite and professional
|
|
1575
|
+
\`\`\`
|
|
1576
|
+
|
|
1577
|
+
\`\`\`book
|
|
1578
|
+
Research Assistant
|
|
1579
|
+
|
|
1580
|
+
NOTE Performance optimized for quick response times
|
|
1581
|
+
NOTE Uses RAG for accessing latest research papers
|
|
1582
|
+
PERSONA You are a knowledgeable research assistant
|
|
1583
|
+
ACTION Can help with literature reviews and citations
|
|
1584
|
+
STYLE Present information in academic format
|
|
1585
|
+
\`\`\`
|
|
1586
|
+
`);
|
|
1587
|
+
}
|
|
1588
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1589
|
+
var _a;
|
|
1590
|
+
// The NOTE commitment makes no changes to the system message or model requirements
|
|
1591
|
+
// It only stores the note content in metadata for documentation purposes
|
|
1592
|
+
const trimmedContent = content.trim();
|
|
1593
|
+
if (!trimmedContent) {
|
|
1594
|
+
return requirements;
|
|
1595
|
+
}
|
|
1596
|
+
// Get existing note content from metadata
|
|
1597
|
+
const existingNoteContent = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.NOTE) || '';
|
|
1598
|
+
// Merge the new content with existing note content
|
|
1599
|
+
// When multiple NOTE commitments exist, they are aggregated together
|
|
1600
|
+
const mergedNoteContent = existingNoteContent ? `${existingNoteContent}\n${trimmedContent}` : trimmedContent;
|
|
1601
|
+
// Store the merged note content in metadata for debugging and inspection
|
|
1602
|
+
const updatedMetadata = {
|
|
1603
|
+
...requirements.metadata,
|
|
1604
|
+
NOTE: mergedNoteContent,
|
|
1605
|
+
};
|
|
1606
|
+
// Return requirements with updated metadata but no changes to system message
|
|
1607
|
+
return {
|
|
1608
|
+
...requirements,
|
|
1609
|
+
metadata: updatedMetadata,
|
|
1610
|
+
};
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Singleton instance of the NOTE commitment definition
|
|
1615
|
+
*
|
|
1616
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1617
|
+
*/
|
|
1618
|
+
new NoteCommitmentDefinition();
|
|
1619
|
+
/**
|
|
1620
|
+
* [💞] Ignore a discrepancy between file name and entity name
|
|
1621
|
+
*/
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* PERSONA commitment definition
|
|
1625
|
+
*
|
|
1626
|
+
* The PERSONA commitment modifies the agent's personality and character in the system message.
|
|
1627
|
+
* It defines who the agent is, their background, expertise, and personality traits.
|
|
1628
|
+
*
|
|
1629
|
+
* Key features:
|
|
1630
|
+
* - Multiple PERSONA commitments are automatically merged into one
|
|
1631
|
+
* - Content is placed at the beginning of the system message
|
|
1632
|
+
* - Original content with comments is preserved in metadata.PERSONA
|
|
1633
|
+
* - Comments (# PERSONA) are removed from the final system message
|
|
1634
|
+
*
|
|
1635
|
+
* Example usage in agent source:
|
|
1636
|
+
*
|
|
1637
|
+
* ```book
|
|
1638
|
+
* PERSONA You are a helpful programming assistant with expertise in TypeScript and React
|
|
1639
|
+
* PERSONA You have deep knowledge of modern web development practices
|
|
1640
|
+
* ```
|
|
1641
|
+
*
|
|
1642
|
+
* The above will be merged into a single persona section at the beginning of the system message.
|
|
1643
|
+
*
|
|
1644
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1645
|
+
*/
|
|
1646
|
+
class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1647
|
+
constructor() {
|
|
1648
|
+
super('PERSONA');
|
|
1649
|
+
}
|
|
1650
|
+
/**
|
|
1651
|
+
* Short one-line description of PERSONA.
|
|
1652
|
+
*/
|
|
1653
|
+
get description() {
|
|
1654
|
+
return 'Define who the agent is: background, expertise, and personality.';
|
|
1655
|
+
}
|
|
1656
|
+
/**
|
|
1657
|
+
* Markdown documentation for PERSONA commitment.
|
|
1658
|
+
*/
|
|
1659
|
+
get documentation() {
|
|
1660
|
+
return spaceTrim(`
|
|
1661
|
+
# PERSONA
|
|
1662
|
+
|
|
1663
|
+
Defines who the agent is, their background, expertise, and personality traits.
|
|
1664
|
+
|
|
1665
|
+
## Key behaviors
|
|
1666
|
+
|
|
1667
|
+
- Multiple \`PERSONA\` commitments are merged together.
|
|
1668
|
+
- If they are in conflict, the last one takes precedence.
|
|
1669
|
+
- You can write persona content in multiple lines.
|
|
1670
|
+
|
|
1671
|
+
## Examples
|
|
1672
|
+
|
|
1673
|
+
\`\`\`book
|
|
1674
|
+
Programming Assistant
|
|
1675
|
+
|
|
1676
|
+
PERSONA You are a helpful programming assistant with expertise in TypeScript and React
|
|
1677
|
+
PERSONA You have deep knowledge of modern web development practices
|
|
1678
|
+
\`\`\`
|
|
1679
|
+
`);
|
|
1680
|
+
}
|
|
1681
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1682
|
+
var _a, _b;
|
|
1683
|
+
// The PERSONA commitment aggregates all persona content and places it at the beginning
|
|
1684
|
+
const trimmedContent = content.trim();
|
|
1685
|
+
if (!trimmedContent) {
|
|
1686
|
+
return requirements;
|
|
1687
|
+
}
|
|
1688
|
+
// Get existing persona content from metadata
|
|
1689
|
+
const existingPersonaContent = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.PERSONA) || '';
|
|
1690
|
+
// Merge the new content with existing persona content
|
|
1691
|
+
// When multiple PERSONA commitments exist, they are merged into one
|
|
1692
|
+
const mergedPersonaContent = existingPersonaContent
|
|
1693
|
+
? `${existingPersonaContent}\n${trimmedContent}`
|
|
1694
|
+
: trimmedContent;
|
|
1695
|
+
// Store the merged persona content in metadata for debugging and inspection
|
|
1696
|
+
const updatedMetadata = {
|
|
1697
|
+
...requirements.metadata,
|
|
1698
|
+
PERSONA: mergedPersonaContent,
|
|
1699
|
+
};
|
|
1700
|
+
// Get the agent name from metadata (which should contain the first line of agent source)
|
|
1701
|
+
// If not available, extract from current system message as fallback
|
|
1702
|
+
let agentName = (_b = requirements.metadata) === null || _b === void 0 ? void 0 : _b.agentName;
|
|
1703
|
+
if (!agentName) {
|
|
1704
|
+
// Fallback: extract from current system message
|
|
1705
|
+
const currentMessage = requirements.systemMessage.trim();
|
|
1706
|
+
const basicFormatMatch = currentMessage.match(/^You are (.+)$/);
|
|
1707
|
+
if (basicFormatMatch && basicFormatMatch[1]) {
|
|
1708
|
+
agentName = basicFormatMatch[1];
|
|
1709
|
+
}
|
|
1710
|
+
else {
|
|
1711
|
+
agentName = 'AI Agent'; // Final fallback
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
// Remove any existing persona content from the system message
|
|
1715
|
+
// (this handles the case where we're processing multiple PERSONA commitments)
|
|
1716
|
+
const currentMessage = requirements.systemMessage.trim();
|
|
1717
|
+
let cleanedMessage = currentMessage;
|
|
1718
|
+
// Check if current message starts with persona content or is just the basic format
|
|
1719
|
+
const basicFormatRegex = /^You are .+$/;
|
|
1720
|
+
const isBasicFormat = basicFormatRegex.test(currentMessage) && !currentMessage.includes('\n');
|
|
1721
|
+
if (isBasicFormat) {
|
|
1722
|
+
// Replace the basic format entirely
|
|
1723
|
+
cleanedMessage = '';
|
|
1724
|
+
}
|
|
1725
|
+
else if (currentMessage.startsWith('# PERSONA')) {
|
|
1726
|
+
// Remove existing persona section by finding where it ends
|
|
1727
|
+
const lines = currentMessage.split('\n');
|
|
1728
|
+
let personaEndIndex = lines.length;
|
|
1729
|
+
// Find the end of the PERSONA section (next comment or end of message)
|
|
1730
|
+
for (let i = 1; i < lines.length; i++) {
|
|
1731
|
+
const line = lines[i].trim();
|
|
1732
|
+
if (line.startsWith('#') && !line.startsWith('# PERSONA')) {
|
|
1733
|
+
personaEndIndex = i;
|
|
1734
|
+
break;
|
|
1735
|
+
}
|
|
1736
|
+
}
|
|
1737
|
+
// Keep everything after the PERSONA section
|
|
1738
|
+
cleanedMessage = lines.slice(personaEndIndex).join('\n').trim();
|
|
1739
|
+
}
|
|
1740
|
+
// Create new system message with persona at the beginning
|
|
1741
|
+
// Format: "You are {agentName}\n{personaContent}"
|
|
1742
|
+
// The # PERSONA comment will be removed later by removeCommentsFromSystemMessage
|
|
1743
|
+
const personaSection = `# PERSONA\nYou are ${agentName}\n${mergedPersonaContent}`; // <- TODO: Use spaceTrim
|
|
1744
|
+
const newSystemMessage = cleanedMessage ? `${personaSection}\n\n${cleanedMessage}` : personaSection;
|
|
1745
|
+
return {
|
|
1746
|
+
...requirements,
|
|
1747
|
+
systemMessage: newSystemMessage,
|
|
1748
|
+
metadata: updatedMetadata,
|
|
1749
|
+
};
|
|
1750
|
+
}
|
|
1751
|
+
}
|
|
1752
|
+
/**
|
|
1753
|
+
* Singleton instance of the PERSONA commitment definition
|
|
1754
|
+
*
|
|
1755
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1756
|
+
*/
|
|
1757
|
+
new PersonaCommitmentDefinition();
|
|
1758
|
+
/**
|
|
1759
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1760
|
+
*/
|
|
1761
|
+
|
|
1762
|
+
/**
|
|
1763
|
+
* RULE commitment definition
|
|
1764
|
+
*
|
|
1765
|
+
* The RULE/RULES commitment adds behavioral constraints and guidelines that the agent must follow.
|
|
1766
|
+
* These are specific instructions about what the agent should or shouldn't do.
|
|
1767
|
+
*
|
|
1768
|
+
* Example usage in agent source:
|
|
1769
|
+
*
|
|
1770
|
+
* ```book
|
|
1771
|
+
* RULE Always ask for clarification if the user's request is ambiguous
|
|
1772
|
+
* RULES Never provide medical advice, always refer to healthcare professionals
|
|
1773
|
+
* ```
|
|
1774
|
+
*
|
|
1775
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1776
|
+
*/
|
|
1777
|
+
class RuleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1778
|
+
constructor(type = 'RULE') {
|
|
1779
|
+
super(type);
|
|
1780
|
+
}
|
|
1781
|
+
/**
|
|
1782
|
+
* Short one-line description of RULE/RULES.
|
|
1783
|
+
*/
|
|
1784
|
+
get description() {
|
|
1785
|
+
return 'Add behavioral rules the agent must follow.';
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Markdown documentation for RULE/RULES commitment.
|
|
1789
|
+
*/
|
|
1790
|
+
get documentation() {
|
|
1791
|
+
return spaceTrim(`
|
|
1792
|
+
# ${this.type}
|
|
1793
|
+
|
|
1794
|
+
Adds behavioral constraints and guidelines that the agent must follow.
|
|
1795
|
+
|
|
1796
|
+
## Key behaviors
|
|
1797
|
+
|
|
1798
|
+
- Multiple \`RULE\` and \`RULES\` commitments are applied sequentially.
|
|
1799
|
+
- All rules are treated equally regardless of singular/plural form.
|
|
1800
|
+
- Rules define what the agent must or must not do.
|
|
1801
|
+
|
|
1802
|
+
## Examples
|
|
1803
|
+
|
|
1804
|
+
\`\`\`book
|
|
1805
|
+
Customer Support Agent
|
|
1806
|
+
|
|
1807
|
+
PERSONA You are a helpful customer support representative
|
|
1808
|
+
RULE Always ask for clarification if the user's request is ambiguous
|
|
1809
|
+
RULE Be polite and professional in all interactions
|
|
1810
|
+
RULES Never provide medical or legal advice
|
|
1811
|
+
STYLE Maintain a friendly and helpful tone
|
|
1812
|
+
\`\`\`
|
|
1813
|
+
|
|
1814
|
+
\`\`\`book
|
|
1815
|
+
Educational Tutor
|
|
1816
|
+
|
|
1817
|
+
PERSONA You are a patient and knowledgeable tutor
|
|
1818
|
+
RULE Break down complex concepts into simple steps
|
|
1819
|
+
RULE Always encourage students and celebrate their progress
|
|
1820
|
+
RULE If you don't know something, admit it and suggest resources
|
|
1821
|
+
SAMPLE When explaining math: "Let's work through this step by step..."
|
|
1822
|
+
\`\`\`
|
|
1823
|
+
`);
|
|
1824
|
+
}
|
|
1825
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1826
|
+
const trimmedContent = content.trim();
|
|
1827
|
+
if (!trimmedContent) {
|
|
1828
|
+
return requirements;
|
|
1829
|
+
}
|
|
1830
|
+
// Add rule to the system message
|
|
1831
|
+
const ruleSection = `Rule: ${trimmedContent}`;
|
|
1832
|
+
return this.appendToSystemMessage(requirements, ruleSection, '\n\n');
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Singleton instances of the RULE commitment definitions
|
|
1837
|
+
*
|
|
1838
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1839
|
+
*/
|
|
1840
|
+
new RuleCommitmentDefinition('RULE');
|
|
1841
|
+
/**
|
|
1842
|
+
* Singleton instances of the RULE commitment definitions
|
|
1843
|
+
*
|
|
1844
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1845
|
+
*/
|
|
1846
|
+
new RuleCommitmentDefinition('RULES');
|
|
1847
|
+
/**
|
|
1848
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1849
|
+
*/
|
|
1850
|
+
|
|
1851
|
+
/**
|
|
1852
|
+
* SAMPLE commitment definition
|
|
1853
|
+
*
|
|
1854
|
+
* The SAMPLE/EXAMPLE commitment provides examples of how the agent should respond
|
|
1855
|
+
* or behave in certain situations. These examples help guide the agent's responses.
|
|
1856
|
+
*
|
|
1857
|
+
* Example usage in agent source:
|
|
1858
|
+
*
|
|
1859
|
+
* ```book
|
|
1860
|
+
* SAMPLE When asked about pricing, respond: "Our basic plan starts at $10/month..."
|
|
1861
|
+
* EXAMPLE For code questions, always include working code snippets
|
|
1862
|
+
* ```
|
|
1863
|
+
*
|
|
1864
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1865
|
+
*/
|
|
1866
|
+
class SampleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1867
|
+
constructor(type = 'SAMPLE') {
|
|
1868
|
+
super(type);
|
|
1869
|
+
}
|
|
1870
|
+
/**
|
|
1871
|
+
* Short one-line description of SAMPLE/EXAMPLE.
|
|
1872
|
+
*/
|
|
1873
|
+
get description() {
|
|
1874
|
+
return 'Provide example responses to guide behavior.';
|
|
1875
|
+
}
|
|
1876
|
+
/**
|
|
1877
|
+
* Markdown documentation for SAMPLE/EXAMPLE commitment.
|
|
1878
|
+
*/
|
|
1879
|
+
get documentation() {
|
|
1880
|
+
return spaceTrim(`
|
|
1881
|
+
# ${this.type}
|
|
1882
|
+
|
|
1883
|
+
Provides examples of how the agent should respond or behave in certain situations.
|
|
1884
|
+
|
|
1885
|
+
## Key behaviors
|
|
1886
|
+
|
|
1887
|
+
- Multiple \`SAMPLE\` and \`EXAMPLE\` commitments are applied sequentially.
|
|
1888
|
+
- Both terms work identically and can be used interchangeably.
|
|
1889
|
+
- Examples help guide the agent's response patterns and style.
|
|
1890
|
+
|
|
1891
|
+
## Examples
|
|
1892
|
+
|
|
1893
|
+
\`\`\`book
|
|
1894
|
+
Sales Assistant
|
|
1895
|
+
|
|
1896
|
+
PERSONA You are a knowledgeable sales representative
|
|
1897
|
+
SAMPLE When asked about pricing, respond: "Our basic plan starts at $10/month..."
|
|
1898
|
+
SAMPLE For feature comparisons, create a clear comparison table
|
|
1899
|
+
RULE Always be honest about limitations
|
|
1900
|
+
\`\`\`
|
|
1901
|
+
|
|
1902
|
+
\`\`\`book
|
|
1903
|
+
Code Reviewer
|
|
1904
|
+
|
|
1905
|
+
PERSONA You are an experienced software engineer
|
|
1906
|
+
EXAMPLE For code questions, always include working code snippets
|
|
1907
|
+
EXAMPLE When suggesting improvements: "Here's a more efficient approach..."
|
|
1908
|
+
RULE Explain the reasoning behind your suggestions
|
|
1909
|
+
STYLE Be constructive and encouraging in feedback
|
|
1910
|
+
\`\`\`
|
|
1911
|
+
`);
|
|
1912
|
+
}
|
|
1913
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
1914
|
+
const trimmedContent = content.trim();
|
|
1915
|
+
if (!trimmedContent) {
|
|
1916
|
+
return requirements;
|
|
1917
|
+
}
|
|
1918
|
+
// Add example to the system message
|
|
1919
|
+
const exampleSection = `Example: ${trimmedContent}`;
|
|
1920
|
+
return this.appendToSystemMessage(requirements, exampleSection, '\n\n');
|
|
1921
|
+
}
|
|
1922
|
+
}
|
|
1923
|
+
/**
|
|
1924
|
+
* Singleton instances of the SAMPLE commitment definitions
|
|
1925
|
+
*
|
|
1926
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1927
|
+
*/
|
|
1928
|
+
new SampleCommitmentDefinition('SAMPLE');
|
|
1929
|
+
/**
|
|
1930
|
+
* Singleton instances of the SAMPLE commitment definitions
|
|
1931
|
+
*
|
|
1932
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1933
|
+
*/
|
|
1934
|
+
new SampleCommitmentDefinition('EXAMPLE');
|
|
1935
|
+
/**
|
|
1936
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
1937
|
+
*/
|
|
1938
|
+
|
|
1939
|
+
/**
|
|
1940
|
+
* STYLE commitment definition
|
|
1941
|
+
*
|
|
1942
|
+
* The STYLE commitment defines how the agent should format and present its responses.
|
|
1943
|
+
* This includes tone, writing style, formatting preferences, and communication patterns.
|
|
1944
|
+
*
|
|
1945
|
+
* Example usage in agent source:
|
|
1946
|
+
*
|
|
1947
|
+
* ```book
|
|
1948
|
+
* STYLE Write in a professional but friendly tone, use bullet points for lists
|
|
1949
|
+
* STYLE Always provide code examples when explaining programming concepts
|
|
1950
|
+
* ```
|
|
1951
|
+
*
|
|
1952
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
1953
|
+
*/
|
|
1954
|
+
class StyleCommitmentDefinition extends BaseCommitmentDefinition {
|
|
1955
|
+
constructor() {
|
|
1956
|
+
super('STYLE');
|
|
1957
|
+
}
|
|
1958
|
+
/**
|
|
1959
|
+
* Short one-line description of STYLE.
|
|
1960
|
+
*/
|
|
1961
|
+
get description() {
|
|
1962
|
+
return 'Control the tone and writing style of responses.';
|
|
1963
|
+
}
|
|
1964
|
+
/**
|
|
1965
|
+
* Markdown documentation for STYLE commitment.
|
|
1966
|
+
*/
|
|
1967
|
+
get documentation() {
|
|
1968
|
+
return spaceTrim(`
|
|
1969
|
+
# STYLE
|
|
1970
|
+
|
|
1971
|
+
Defines how the agent should format and present its responses (tone, writing style, formatting).
|
|
1972
|
+
|
|
1973
|
+
## Key behaviors
|
|
1974
|
+
|
|
1975
|
+
- Multiple \`STYLE\` commitments are applied sequentially.
|
|
1976
|
+
- Later style instructions can override earlier ones.
|
|
1977
|
+
- Style affects both tone and presentation format.
|
|
1978
|
+
|
|
1979
|
+
## Examples
|
|
1980
|
+
|
|
1981
|
+
\`\`\`book
|
|
1982
|
+
Technical Writer
|
|
1983
|
+
|
|
1984
|
+
PERSONA You are a technical documentation expert
|
|
1985
|
+
STYLE Write in a professional but friendly tone, use bullet points for lists
|
|
1986
|
+
STYLE Always provide code examples when explaining programming concepts
|
|
1987
|
+
FORMAT Use markdown formatting with clear headings
|
|
1988
|
+
\`\`\`
|
|
1989
|
+
|
|
1990
|
+
\`\`\`book
|
|
1991
|
+
Creative Assistant
|
|
1992
|
+
|
|
1993
|
+
PERSONA You are a creative writing helper
|
|
1994
|
+
STYLE Be enthusiastic and encouraging in your responses
|
|
1995
|
+
STYLE Use vivid metaphors and analogies to explain concepts
|
|
1996
|
+
STYLE Keep responses conversational and engaging
|
|
1997
|
+
RULE Always maintain a positive and supportive tone
|
|
1998
|
+
\`\`\`
|
|
1999
|
+
`);
|
|
2000
|
+
}
|
|
2001
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
2002
|
+
const trimmedContent = content.trim();
|
|
2003
|
+
if (!trimmedContent) {
|
|
2004
|
+
return requirements;
|
|
2005
|
+
}
|
|
2006
|
+
// Add style instructions to the system message
|
|
2007
|
+
const styleSection = `Style: ${trimmedContent}`;
|
|
2008
|
+
return this.appendToSystemMessage(requirements, styleSection, '\n\n');
|
|
2009
|
+
}
|
|
2010
|
+
}
|
|
2011
|
+
/**
|
|
2012
|
+
* Singleton instance of the STYLE commitment definition
|
|
2013
|
+
*
|
|
2014
|
+
* @private [🪔] Maybe export the commitments through some package
|
|
2015
|
+
*/
|
|
2016
|
+
new StyleCommitmentDefinition();
|
|
2017
|
+
/**
|
|
2018
|
+
* [💞] Ignore a discrepancy between file name and entity name
|
|
2019
|
+
*/
|
|
2020
|
+
|
|
2021
|
+
/**
|
|
2022
|
+
* Placeholder commitment definition for commitments that are not yet implemented
|
|
2023
|
+
*
|
|
2024
|
+
* This commitment simply adds its content 1:1 into the system message,
|
|
2025
|
+
* preserving the original behavior until proper implementation is added.
|
|
2026
|
+
*
|
|
2027
|
+
* @public exported from `@promptbook/core`
|
|
2028
|
+
*/
|
|
2029
|
+
class NotYetImplementedCommitmentDefinition extends BaseCommitmentDefinition {
|
|
2030
|
+
constructor(type) {
|
|
2031
|
+
super(type);
|
|
2032
|
+
}
|
|
2033
|
+
/**
|
|
2034
|
+
* Short one-line description of a placeholder commitment.
|
|
2035
|
+
*/
|
|
2036
|
+
get description() {
|
|
2037
|
+
return 'Placeholder commitment that appends content verbatim to the system message.';
|
|
2038
|
+
}
|
|
2039
|
+
/**
|
|
2040
|
+
* Markdown documentation available at runtime.
|
|
2041
|
+
*/
|
|
2042
|
+
get documentation() {
|
|
2043
|
+
return spaceTrim(`
|
|
2044
|
+
# ${this.type}
|
|
2045
|
+
|
|
2046
|
+
This commitment is not yet fully implemented.
|
|
2047
|
+
|
|
2048
|
+
## Key behaviors
|
|
2049
|
+
|
|
2050
|
+
- Content is appended directly to the system message.
|
|
2051
|
+
- No special processing or validation is performed.
|
|
2052
|
+
- Behavior preserved until proper implementation is added.
|
|
2053
|
+
|
|
2054
|
+
## Status
|
|
2055
|
+
|
|
2056
|
+
- **Status:** Placeholder implementation
|
|
2057
|
+
- **Effect:** Appends content prefixed by commitment type
|
|
2058
|
+
- **Future:** Will be replaced with specialized logic
|
|
2059
|
+
|
|
2060
|
+
## Examples
|
|
2061
|
+
|
|
2062
|
+
\`\`\`book
|
|
2063
|
+
Example Agent
|
|
2064
|
+
|
|
2065
|
+
PERSONA You are a helpful assistant
|
|
2066
|
+
${this.type} Your content here
|
|
2067
|
+
RULE Always be helpful
|
|
2068
|
+
\`\`\`
|
|
2069
|
+
`);
|
|
2070
|
+
}
|
|
2071
|
+
applyToAgentModelRequirements(requirements, content) {
|
|
2072
|
+
const trimmedContent = content.trim();
|
|
2073
|
+
if (!trimmedContent) {
|
|
2074
|
+
return requirements;
|
|
2075
|
+
}
|
|
2076
|
+
// Add the commitment content 1:1 to the system message
|
|
2077
|
+
const commitmentLine = `${this.type} ${trimmedContent}`;
|
|
2078
|
+
return this.appendToSystemMessage(requirements, commitmentLine, '\n\n');
|
|
2079
|
+
}
|
|
2080
|
+
}
|
|
2081
|
+
|
|
2082
|
+
// Import all commitment definition classes
|
|
2083
|
+
/**
|
|
2084
|
+
* Registry of all available commitment definitions
|
|
2085
|
+
* This array contains instances of all commitment definitions
|
|
2086
|
+
* This is the single source of truth for all commitments in the system
|
|
2087
|
+
*
|
|
2088
|
+
* @private Use functions to access commitments instead of this array directly
|
|
2089
|
+
*/
|
|
2090
|
+
const COMMITMENT_REGISTRY = [
|
|
2091
|
+
// Fully implemented commitments
|
|
2092
|
+
new PersonaCommitmentDefinition(),
|
|
2093
|
+
new KnowledgeCommitmentDefinition(),
|
|
2094
|
+
new StyleCommitmentDefinition(),
|
|
2095
|
+
new RuleCommitmentDefinition('RULE'),
|
|
2096
|
+
new RuleCommitmentDefinition('RULES'),
|
|
2097
|
+
new SampleCommitmentDefinition('SAMPLE'),
|
|
2098
|
+
new SampleCommitmentDefinition('EXAMPLE'),
|
|
2099
|
+
new FormatCommitmentDefinition(),
|
|
2100
|
+
new ModelCommitmentDefinition(),
|
|
2101
|
+
new ActionCommitmentDefinition(),
|
|
2102
|
+
new MetaImageCommitmentDefinition(),
|
|
2103
|
+
new MetaLinkCommitmentDefinition(),
|
|
2104
|
+
new NoteCommitmentDefinition(),
|
|
2105
|
+
// Not yet implemented commitments (using placeholder)
|
|
2106
|
+
new NotYetImplementedCommitmentDefinition('EXPECT'),
|
|
2107
|
+
new NotYetImplementedCommitmentDefinition('SCENARIO'),
|
|
2108
|
+
new NotYetImplementedCommitmentDefinition('SCENARIOS'),
|
|
2109
|
+
new NotYetImplementedCommitmentDefinition('BEHAVIOUR'),
|
|
2110
|
+
new NotYetImplementedCommitmentDefinition('BEHAVIOURS'),
|
|
2111
|
+
new NotYetImplementedCommitmentDefinition('AVOID'),
|
|
2112
|
+
new NotYetImplementedCommitmentDefinition('AVOIDANCE'),
|
|
2113
|
+
new NotYetImplementedCommitmentDefinition('GOAL'),
|
|
2114
|
+
new NotYetImplementedCommitmentDefinition('GOALS'),
|
|
2115
|
+
new NotYetImplementedCommitmentDefinition('CONTEXT'),
|
|
2116
|
+
];
|
|
2117
|
+
/**
|
|
2118
|
+
* Gets a commitment definition by its type
|
|
2119
|
+
* @param type The commitment type to look up
|
|
2120
|
+
* @returns The commitment definition or null if not found
|
|
2121
|
+
*
|
|
2122
|
+
* @public exported from `@promptbook/core`
|
|
2123
|
+
*/
|
|
2124
|
+
function getCommitmentDefinition(type) {
|
|
2125
|
+
return COMMITMENT_REGISTRY.find((commitmentDefinition) => commitmentDefinition.type === type) || null;
|
|
2126
|
+
}
|
|
2127
|
+
/**
|
|
2128
|
+
* Gets all available commitment definitions
|
|
2129
|
+
* @returns Array of all commitment definitions
|
|
2130
|
+
*
|
|
2131
|
+
* @public exported from `@promptbook/core`
|
|
2132
|
+
*/
|
|
2133
|
+
function getAllCommitmentDefinitions() {
|
|
2134
|
+
return $deepFreeze([...COMMITMENT_REGISTRY]);
|
|
2135
|
+
}
|
|
2136
|
+
/**
|
|
2137
|
+
* Gets all available commitment types
|
|
2138
|
+
* @returns Array of all commitment types
|
|
2139
|
+
*
|
|
2140
|
+
* @public exported from `@promptbook/core`
|
|
2141
|
+
*/
|
|
2142
|
+
function getAllCommitmentTypes() {
|
|
2143
|
+
return $deepFreeze(COMMITMENT_REGISTRY.map((commitmentDefinition) => commitmentDefinition.type));
|
|
2144
|
+
}
|
|
2145
|
+
/**
|
|
2146
|
+
* Checks if a commitment type is supported
|
|
2147
|
+
* @param type The commitment type to check
|
|
2148
|
+
* @returns True if the commitment type is supported
|
|
2149
|
+
*
|
|
2150
|
+
* @public exported from `@promptbook/core`
|
|
2151
|
+
*/
|
|
2152
|
+
function isCommitmentSupported(type) {
|
|
2153
|
+
return COMMITMENT_REGISTRY.some((commitmentDefinition) => commitmentDefinition.type === type);
|
|
2154
|
+
}
|
|
2155
|
+
/**
|
|
2156
|
+
* TODO: !!!! Maybe create through standardized $register
|
|
2157
|
+
* Note: [💞] Ignore a discrepancy between file name and entity name
|
|
2158
|
+
*/
|
|
2159
|
+
|
|
2160
|
+
/**
|
|
2161
|
+
* Parses agent source using the new commitment system with multiline support
|
|
2162
|
+
* This function replaces the hardcoded commitment parsing in the original parseAgentSource
|
|
2163
|
+
*
|
|
2164
|
+
* @private
|
|
2165
|
+
*/
|
|
2166
|
+
function parseAgentSourceWithCommitments(agentSource) {
|
|
2167
|
+
var _a, _b, _c;
|
|
2168
|
+
if (!agentSource || !agentSource.trim()) {
|
|
2169
|
+
return {
|
|
2170
|
+
agentName: null,
|
|
2171
|
+
commitments: [],
|
|
2172
|
+
nonCommitmentLines: [],
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
const lines = agentSource.split('\n');
|
|
2176
|
+
const agentName = (((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.trim()) || null);
|
|
2177
|
+
const commitments = [];
|
|
2178
|
+
const nonCommitmentLines = [];
|
|
2179
|
+
// Always add the first line (agent name) to non-commitment lines
|
|
2180
|
+
if (lines[0] !== undefined) {
|
|
2181
|
+
nonCommitmentLines.push(lines[0]);
|
|
2182
|
+
}
|
|
2183
|
+
// Parse commitments with multiline support
|
|
2184
|
+
let currentCommitment = null;
|
|
2185
|
+
// Process lines starting from the second line (skip agent name)
|
|
2186
|
+
for (let i = 1; i < lines.length; i++) {
|
|
2187
|
+
const line = lines[i];
|
|
2188
|
+
if (line === undefined) {
|
|
2189
|
+
continue;
|
|
2190
|
+
}
|
|
2191
|
+
// Check if this line starts a new commitment
|
|
2192
|
+
let foundNewCommitment = false;
|
|
2193
|
+
for (const definition of COMMITMENT_REGISTRY) {
|
|
2194
|
+
const typeRegex = definition.createTypeRegex();
|
|
2195
|
+
const match = typeRegex.exec(line.trim());
|
|
2196
|
+
if (match && ((_b = match.groups) === null || _b === void 0 ? void 0 : _b.type)) {
|
|
2197
|
+
// Save the previous commitment if it exists
|
|
2198
|
+
if (currentCommitment) {
|
|
2199
|
+
const fullContent = currentCommitment.contentLines.join('\n');
|
|
2200
|
+
commitments.push({
|
|
2201
|
+
type: currentCommitment.type,
|
|
2202
|
+
content: spaceTrim(fullContent),
|
|
2203
|
+
originalLine: currentCommitment.originalStartLine,
|
|
2204
|
+
lineNumber: currentCommitment.startLineNumber,
|
|
2205
|
+
});
|
|
2206
|
+
}
|
|
2207
|
+
// Extract the initial content from the commitment line
|
|
2208
|
+
const fullRegex = definition.createRegex();
|
|
2209
|
+
const fullMatch = fullRegex.exec(line.trim());
|
|
2210
|
+
const initialContent = ((_c = fullMatch === null || fullMatch === void 0 ? void 0 : fullMatch.groups) === null || _c === void 0 ? void 0 : _c.contents) || '';
|
|
2211
|
+
// Start a new commitment
|
|
2212
|
+
currentCommitment = {
|
|
2213
|
+
type: definition.type,
|
|
2214
|
+
startLineNumber: i + 1,
|
|
2215
|
+
originalStartLine: line,
|
|
2216
|
+
contentLines: initialContent ? [initialContent] : [],
|
|
2217
|
+
};
|
|
2218
|
+
foundNewCommitment = true;
|
|
2219
|
+
break;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
if (!foundNewCommitment) {
|
|
2223
|
+
if (currentCommitment) {
|
|
2224
|
+
// This line belongs to the current commitment
|
|
2225
|
+
currentCommitment.contentLines.push(line);
|
|
2226
|
+
}
|
|
2227
|
+
else {
|
|
2228
|
+
// This line is not part of any commitment
|
|
2229
|
+
nonCommitmentLines.push(line);
|
|
2230
|
+
}
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
// Don't forget to save the last commitment if it exists
|
|
2234
|
+
if (currentCommitment) {
|
|
2235
|
+
const fullContent = currentCommitment.contentLines.join('\n');
|
|
2236
|
+
commitments.push({
|
|
2237
|
+
type: currentCommitment.type,
|
|
2238
|
+
content: spaceTrim(fullContent),
|
|
2239
|
+
originalLine: currentCommitment.originalStartLine,
|
|
2240
|
+
lineNumber: currentCommitment.startLineNumber,
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
return {
|
|
2244
|
+
agentName,
|
|
2245
|
+
commitments,
|
|
2246
|
+
nonCommitmentLines,
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
/**
|
|
2250
|
+
* Extracts basic information from agent source using the new commitment system
|
|
2251
|
+
* This maintains compatibility with the original parseAgentSource interface
|
|
2252
|
+
*
|
|
2253
|
+
* @private
|
|
2254
|
+
*/
|
|
2255
|
+
function parseAgentSourceBasicInfo(agentSource) {
|
|
2256
|
+
const parseResult = parseAgentSourceWithCommitments(agentSource);
|
|
2257
|
+
// Find PERSONA and META IMAGE commitments
|
|
2258
|
+
let personaDescription = null;
|
|
2259
|
+
let profileImageUrl;
|
|
2260
|
+
for (const commitment of parseResult.commitments) {
|
|
2261
|
+
if (commitment.type === 'PERSONA' && !personaDescription) {
|
|
2262
|
+
personaDescription = commitment.content;
|
|
2263
|
+
}
|
|
2264
|
+
else if (commitment.type === 'META IMAGE' && !profileImageUrl) {
|
|
2265
|
+
profileImageUrl = commitment.content;
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
// Generate gravatar fallback if no profile image specified
|
|
2269
|
+
if (!profileImageUrl) {
|
|
2270
|
+
profileImageUrl = generateGravatarUrl(parseResult.agentName);
|
|
2271
|
+
}
|
|
2272
|
+
return {
|
|
2273
|
+
agentName: parseResult.agentName,
|
|
2274
|
+
personaDescription,
|
|
2275
|
+
profileImageUrl,
|
|
2276
|
+
};
|
|
2277
|
+
}
|
|
2278
|
+
|
|
2279
|
+
/**
|
|
2280
|
+
* Parses agent source string into its components
|
|
2281
|
+
*/
|
|
2282
|
+
// Cache for parsed agent sources to prevent repeated parsing
|
|
2283
|
+
const parsedAgentSourceCache = new Map();
|
|
2284
|
+
/**
|
|
2285
|
+
* Parses basic information from agent source
|
|
2286
|
+
*
|
|
2287
|
+
* There are 2 similar functions:
|
|
2288
|
+
* - `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.
|
|
2289
|
+
* - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
|
|
2290
|
+
*
|
|
2291
|
+
* @public exported from `@promptbook/core`
|
|
2292
|
+
*/
|
|
2293
|
+
function parseAgentSource(agentSource) {
|
|
2294
|
+
// Check if we already parsed this agent source
|
|
2295
|
+
if (parsedAgentSourceCache.has(agentSource)) {
|
|
2296
|
+
return parsedAgentSourceCache.get(agentSource);
|
|
2297
|
+
}
|
|
2298
|
+
// Use the new commitment-based parsing system
|
|
2299
|
+
const result = parseAgentSourceBasicInfo(agentSource);
|
|
2300
|
+
// Cache the result
|
|
2301
|
+
parsedAgentSourceCache.set(agentSource, result);
|
|
2302
|
+
return result;
|
|
2303
|
+
}
|
|
2304
|
+
|
|
2305
|
+
/**
|
|
2306
|
+
* Type guard to check if a string is a valid agent source
|
|
2307
|
+
*
|
|
2308
|
+
* @public exported from `@promptbook/core`
|
|
2309
|
+
*/
|
|
2310
|
+
function isValidBook(value) {
|
|
2311
|
+
// Basic validation - agent source should have at least a name (first line)
|
|
2312
|
+
return typeof value === 'string' /* && value.trim().length > 0 */;
|
|
2313
|
+
}
|
|
2314
|
+
/**
|
|
2315
|
+
* Validates and converts a string to agent source branded type
|
|
2316
|
+
* This function should be used when you have a string that you know represents agent source
|
|
2317
|
+
* but need to convert it to the branded type for type safety
|
|
2318
|
+
*
|
|
2319
|
+
* @public exported from `@promptbook/core`
|
|
2320
|
+
*/
|
|
2321
|
+
function validateBook(source) {
|
|
2322
|
+
if (!isValidBook(source)) {
|
|
2323
|
+
throw new Error('Invalid agent source: must be a string');
|
|
2324
|
+
}
|
|
2325
|
+
return source;
|
|
2326
|
+
}
|
|
2327
|
+
/**
|
|
2328
|
+
* Default book
|
|
2329
|
+
*
|
|
2330
|
+
* @public exported from `@promptbook/core`
|
|
2331
|
+
*/
|
|
2332
|
+
const DEFAULT_BOOK = validateBook(spaceTrim$1(`
|
|
2333
|
+
AI Avatar
|
|
2334
|
+
|
|
2335
|
+
PERSONA A friendly AI assistant that helps you with your tasks
|
|
2336
|
+
`));
|
|
2337
|
+
|
|
2338
|
+
/**
|
|
2339
|
+
* Creates an empty/basic agent model requirements object
|
|
2340
|
+
* This serves as the starting point for the reduce-like pattern
|
|
2341
|
+
* where each commitment applies its changes to build the final requirements
|
|
2342
|
+
*
|
|
2343
|
+
* @public exported from `@promptbook/core`
|
|
2344
|
+
*/
|
|
2345
|
+
function createEmptyAgentModelRequirements() {
|
|
2346
|
+
return {
|
|
2347
|
+
systemMessage: '',
|
|
2348
|
+
modelName: '!!!!DEFAULT_MODEL_ID',
|
|
2349
|
+
temperature: 0.7,
|
|
2350
|
+
topP: 0.9,
|
|
2351
|
+
topK: 50,
|
|
2352
|
+
};
|
|
2353
|
+
}
|
|
2354
|
+
/**
|
|
2355
|
+
* Creates a basic agent model requirements with just the agent name
|
|
2356
|
+
* This is used when we have an agent name but no commitments
|
|
2357
|
+
*
|
|
2358
|
+
* @public exported from `@promptbook/core`
|
|
2359
|
+
*/
|
|
2360
|
+
function createBasicAgentModelRequirements(agentName) {
|
|
2361
|
+
const empty = createEmptyAgentModelRequirements();
|
|
2362
|
+
return {
|
|
2363
|
+
...empty,
|
|
2364
|
+
systemMessage: `You are ${agentName || 'AI Agent'}`,
|
|
2365
|
+
};
|
|
2366
|
+
}
|
|
2367
|
+
/**
|
|
2368
|
+
* TODO: !!!! Deduplicate model requirements
|
|
2369
|
+
*/
|
|
2370
|
+
|
|
2371
|
+
/**
|
|
2372
|
+
* Removes comment lines (lines starting with #) from a system message
|
|
2373
|
+
* This is used to clean up the final system message before sending it to the AI model
|
|
2374
|
+
* while preserving the original content with comments in metadata
|
|
2375
|
+
*
|
|
2376
|
+
* @param systemMessage The system message that may contain comment lines
|
|
2377
|
+
* @returns The system message with comment lines removed
|
|
2378
|
+
*
|
|
2379
|
+
* @private - TODO: [🧠] Maybe should be public?
|
|
2380
|
+
*/
|
|
2381
|
+
function removeCommentsFromSystemMessage(systemMessage) {
|
|
2382
|
+
if (!systemMessage) {
|
|
2383
|
+
return systemMessage;
|
|
2384
|
+
}
|
|
2385
|
+
const lines = systemMessage.split('\n');
|
|
2386
|
+
const filteredLines = lines.filter((line) => {
|
|
2387
|
+
const trimmedLine = line.trim();
|
|
2388
|
+
// Remove lines that start with # (comments)
|
|
2389
|
+
return !trimmedLine.startsWith('#');
|
|
2390
|
+
});
|
|
2391
|
+
return filteredLines.join('\n').trim();
|
|
2392
|
+
}
|
|
2393
|
+
|
|
2394
|
+
/**
|
|
2395
|
+
* Creates agent model requirements using the new commitment system
|
|
2396
|
+
* This function uses a reduce-like pattern where each commitment applies its changes
|
|
2397
|
+
* to build the final requirements starting from a basic empty model
|
|
2398
|
+
*
|
|
2399
|
+
* @private
|
|
2400
|
+
*/
|
|
2401
|
+
async function createAgentModelRequirementsWithCommitments(agentSource, modelName) {
|
|
2402
|
+
// Parse the agent source to extract commitments
|
|
2403
|
+
const parseResult = parseAgentSourceWithCommitments(agentSource);
|
|
2404
|
+
// Start with basic agent model requirements
|
|
2405
|
+
let requirements = createBasicAgentModelRequirements(parseResult.agentName);
|
|
2406
|
+
// Store the agent name in metadata so commitments can access it
|
|
2407
|
+
requirements = {
|
|
2408
|
+
...requirements,
|
|
2409
|
+
metadata: {
|
|
2410
|
+
...requirements.metadata,
|
|
2411
|
+
agentName: parseResult.agentName,
|
|
2412
|
+
},
|
|
2413
|
+
};
|
|
2414
|
+
// Override model name if provided
|
|
2415
|
+
if (modelName) {
|
|
2416
|
+
requirements = {
|
|
2417
|
+
...requirements,
|
|
2418
|
+
modelName,
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2421
|
+
// Apply each commitment in order using reduce-like pattern
|
|
2422
|
+
for (const commitment of parseResult.commitments) {
|
|
2423
|
+
const definition = getCommitmentDefinition(commitment.type);
|
|
2424
|
+
if (definition) {
|
|
2425
|
+
try {
|
|
2426
|
+
requirements = definition.applyToAgentModelRequirements(requirements, commitment.content);
|
|
2427
|
+
}
|
|
2428
|
+
catch (error) {
|
|
2429
|
+
console.warn(`Failed to apply commitment ${commitment.type}:`, error);
|
|
2430
|
+
// Continue with other commitments even if one fails
|
|
2431
|
+
}
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
// Handle MCP servers (extract from original agent source)
|
|
2435
|
+
const mcpServers = extractMcpServers(agentSource);
|
|
2436
|
+
if (mcpServers.length > 0) {
|
|
2437
|
+
requirements = {
|
|
2438
|
+
...requirements,
|
|
2439
|
+
mcpServers,
|
|
2440
|
+
};
|
|
2441
|
+
}
|
|
2442
|
+
// Add non-commitment lines to system message if they exist
|
|
2443
|
+
const nonCommitmentContent = parseResult.nonCommitmentLines
|
|
2444
|
+
.filter((line, index) => index > 0 || !parseResult.agentName) // Skip first line if it's the agent name
|
|
2445
|
+
.filter((line) => line.trim()) // Remove empty lines
|
|
2446
|
+
.join('\n')
|
|
2447
|
+
.trim();
|
|
2448
|
+
if (nonCommitmentContent) {
|
|
2449
|
+
requirements = {
|
|
2450
|
+
...requirements,
|
|
2451
|
+
systemMessage: requirements.systemMessage + '\n\n' + nonCommitmentContent,
|
|
2452
|
+
};
|
|
2453
|
+
}
|
|
2454
|
+
// Remove comment lines (lines starting with #) from the final system message
|
|
2455
|
+
// while preserving the original content with comments in metadata
|
|
2456
|
+
const cleanedSystemMessage = removeCommentsFromSystemMessage(requirements.systemMessage);
|
|
2457
|
+
return {
|
|
2458
|
+
...requirements,
|
|
2459
|
+
systemMessage: cleanedSystemMessage,
|
|
2460
|
+
};
|
|
2461
|
+
}
|
|
2462
|
+
/**
|
|
2463
|
+
* Cache for expensive createAgentModelRequirementsWithCommitments calls
|
|
2464
|
+
* @private
|
|
2465
|
+
*/
|
|
2466
|
+
const modelRequirementsCache = new Map();
|
|
2467
|
+
/**
|
|
2468
|
+
* @private - TODO: Maybe should be public
|
|
2469
|
+
*/
|
|
2470
|
+
const CACHE_SIZE_LIMIT = 100;
|
|
2471
|
+
/**
|
|
2472
|
+
* Cached version of createAgentModelRequirementsWithCommitments
|
|
2473
|
+
* This maintains the same caching behavior as the original function
|
|
2474
|
+
*
|
|
2475
|
+
* @private
|
|
2476
|
+
*/
|
|
2477
|
+
async function createAgentModelRequirementsWithCommitmentsCached(agentSource, modelName) {
|
|
2478
|
+
// Create cache key
|
|
2479
|
+
const cacheKey = `${agentSource}|${modelName || 'default'}`;
|
|
2480
|
+
// Check cache first
|
|
2481
|
+
if (modelRequirementsCache.has(cacheKey)) {
|
|
2482
|
+
return modelRequirementsCache.get(cacheKey);
|
|
2483
|
+
}
|
|
2484
|
+
// Limit cache size to prevent memory leaks
|
|
2485
|
+
if (modelRequirementsCache.size >= CACHE_SIZE_LIMIT) {
|
|
2486
|
+
const firstKey = modelRequirementsCache.keys().next().value;
|
|
2487
|
+
if (firstKey) {
|
|
2488
|
+
modelRequirementsCache.delete(firstKey);
|
|
2489
|
+
}
|
|
2490
|
+
}
|
|
2491
|
+
// Create requirements
|
|
2492
|
+
const requirements = await createAgentModelRequirementsWithCommitments(agentSource, modelName);
|
|
2493
|
+
// Cache the result
|
|
2494
|
+
modelRequirementsCache.set(cacheKey, requirements);
|
|
2495
|
+
return requirements;
|
|
2496
|
+
}
|
|
2497
|
+
|
|
2498
|
+
// TODO: Remove or use:
|
|
2499
|
+
//const CACHE_SIZE_LIMIT = 100; // Prevent memory leaks by limiting cache size
|
|
2500
|
+
/**
|
|
2501
|
+
* Creates model requirements for an agent based on its source
|
|
2502
|
+
* Results are cached to improve performance for repeated calls with the same agentSource and modelName
|
|
2503
|
+
*
|
|
2504
|
+
* There are 2 similar functions:
|
|
2505
|
+
* - `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.
|
|
2506
|
+
* - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
|
|
2507
|
+
*
|
|
2508
|
+
* @public exported from `@promptbook/core`
|
|
2509
|
+
*/
|
|
2510
|
+
async function createAgentModelRequirements(agentSource, modelName = '!!!!DEFAULT_MODEL_ID') {
|
|
2511
|
+
// Use the new commitment-based system
|
|
2512
|
+
return createAgentModelRequirementsWithCommitmentsCached(agentSource, modelName);
|
|
2513
|
+
}
|
|
2514
|
+
/**
|
|
2515
|
+
* Extracts MCP servers from agent source
|
|
2516
|
+
*
|
|
2517
|
+
* @param agentSource The agent source string that may contain MCP lines
|
|
2518
|
+
* @returns Array of MCP server identifiers
|
|
2519
|
+
*
|
|
2520
|
+
* @private TODO: [🧠] Maybe should be public
|
|
2521
|
+
*/
|
|
2522
|
+
function extractMcpServers(agentSource) {
|
|
2523
|
+
if (!agentSource) {
|
|
2524
|
+
return [];
|
|
2525
|
+
}
|
|
2526
|
+
const lines = agentSource.split('\n');
|
|
2527
|
+
const mcpRegex = /^\s*MCP\s+(.+)$/i;
|
|
2528
|
+
const mcpServers = [];
|
|
2529
|
+
// Look for MCP lines
|
|
2530
|
+
for (const line of lines) {
|
|
2531
|
+
const match = line.match(mcpRegex);
|
|
2532
|
+
if (match && match[1]) {
|
|
2533
|
+
mcpServers.push(match[1].trim());
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
return mcpServers;
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
/**
|
|
2540
|
+
* Converts PipelineCollection to serialized JSON
|
|
2541
|
+
*
|
|
2542
|
+
* Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
|
|
2543
|
+
*
|
|
2544
|
+
* @public exported from `@promptbook/core`
|
|
2545
|
+
*/
|
|
2546
|
+
async function collectionToJson(collection) {
|
|
2547
|
+
const pipelineUrls = await collection.listPipelines();
|
|
2548
|
+
const promptbooks = await Promise.all(pipelineUrls.map((url) => collection.getPipelineByUrl(url)));
|
|
2549
|
+
return promptbooks;
|
|
2550
|
+
}
|
|
2551
|
+
/**
|
|
2552
|
+
* TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
|
|
2553
|
+
*/
|
|
2554
|
+
|
|
2555
|
+
/**
|
|
2556
|
+
* Checks if value is valid email
|
|
2557
|
+
*
|
|
2558
|
+
* @public exported from `@promptbook/utils`
|
|
2559
|
+
*/
|
|
2560
|
+
function isValidEmail(email) {
|
|
2561
|
+
if (typeof email !== 'string') {
|
|
2562
|
+
return false;
|
|
2563
|
+
}
|
|
2564
|
+
if (email.split('\n').length > 1) {
|
|
2565
|
+
return false;
|
|
2566
|
+
}
|
|
2567
|
+
return /^.+@.+\..+$/.test(email);
|
|
2568
|
+
}
|
|
2569
|
+
|
|
2570
|
+
/**
|
|
2571
|
+
* Tests if given string is valid URL.
|
|
2572
|
+
*
|
|
2573
|
+
* Note: This does not check if the file exists only if the path is valid
|
|
2574
|
+
* @public exported from `@promptbook/utils`
|
|
2575
|
+
*/
|
|
2576
|
+
function isValidFilePath(filename) {
|
|
2577
|
+
if (typeof filename !== 'string') {
|
|
2578
|
+
return false;
|
|
2579
|
+
}
|
|
2580
|
+
if (filename.split('\n').length > 1) {
|
|
2581
|
+
return false;
|
|
2582
|
+
}
|
|
2583
|
+
if (filename.split(' ').length >
|
|
2584
|
+
5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
|
|
2585
|
+
return false;
|
|
2586
|
+
}
|
|
2587
|
+
const filenameSlashes = filename.split('\\').join('/');
|
|
2588
|
+
// Absolute Unix path: /hello.txt
|
|
2589
|
+
if (/^(\/)/i.test(filenameSlashes)) {
|
|
2590
|
+
// console.log(filename, 'Absolute Unix path: /hello.txt');
|
|
2591
|
+
return true;
|
|
2592
|
+
}
|
|
2593
|
+
// Absolute Windows path: /hello.txt
|
|
2594
|
+
if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
|
|
2595
|
+
// console.log(filename, 'Absolute Windows path: /hello.txt');
|
|
2596
|
+
return true;
|
|
2597
|
+
}
|
|
2598
|
+
// Relative path: ./hello.txt
|
|
2599
|
+
if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
|
|
2600
|
+
// console.log(filename, 'Relative path: ./hello.txt');
|
|
2601
|
+
return true;
|
|
2602
|
+
}
|
|
2603
|
+
// Allow paths like foo/hello
|
|
2604
|
+
if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
|
|
2605
|
+
// console.log(filename, 'Allow paths like foo/hello');
|
|
2606
|
+
return true;
|
|
2607
|
+
}
|
|
2608
|
+
// Allow paths like hello.book
|
|
2609
|
+
if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
|
|
2610
|
+
// console.log(filename, 'Allow paths like hello.book');
|
|
2611
|
+
return true;
|
|
2612
|
+
}
|
|
2613
|
+
return false;
|
|
2614
|
+
}
|
|
2615
|
+
/**
|
|
2616
|
+
* TODO: [🍏] Implement for MacOs
|
|
2617
|
+
*/
|
|
2618
|
+
|
|
2619
|
+
/**
|
|
2620
|
+
* Tests if given string is valid URL.
|
|
2621
|
+
*
|
|
2622
|
+
* Note: Dataurl are considered perfectly valid.
|
|
2623
|
+
* Note: There are two similar functions:
|
|
2624
|
+
* - `isValidUrl` which tests any URL
|
|
2625
|
+
* - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
|
|
2626
|
+
*
|
|
2627
|
+
* @public exported from `@promptbook/utils`
|
|
2628
|
+
*/
|
|
2629
|
+
function isValidUrl(url) {
|
|
2630
|
+
if (typeof url !== 'string') {
|
|
2631
|
+
return false;
|
|
2632
|
+
}
|
|
2633
|
+
try {
|
|
2634
|
+
if (url.startsWith('blob:')) {
|
|
2635
|
+
url = url.replace(/^blob:/, '');
|
|
2636
|
+
}
|
|
2637
|
+
const urlObject = new URL(url /* because fail is handled */);
|
|
2638
|
+
if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
|
|
2639
|
+
return false;
|
|
2640
|
+
}
|
|
2641
|
+
return true;
|
|
2642
|
+
}
|
|
2643
|
+
catch (error) {
|
|
2644
|
+
return false;
|
|
2645
|
+
}
|
|
2646
|
+
}
|
|
2647
|
+
|
|
2648
|
+
/**
|
|
2649
|
+
* This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
|
|
581
2650
|
*
|
|
582
2651
|
* @public exported from `@promptbook/core`
|
|
583
2652
|
*/
|
|
584
|
-
class
|
|
585
|
-
constructor(
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
Non-Error object was thrown
|
|
590
|
-
|
|
591
|
-
Note: Look for ${tag} in the console for more details
|
|
592
|
-
Please report issue on ${ADMIN_EMAIL}
|
|
593
|
-
`));
|
|
594
|
-
this.name = 'WrappedError';
|
|
595
|
-
Object.setPrototypeOf(this, WrappedError.prototype);
|
|
2653
|
+
class ParseError extends Error {
|
|
2654
|
+
constructor(message) {
|
|
2655
|
+
super(message);
|
|
2656
|
+
this.name = 'ParseError';
|
|
2657
|
+
Object.setPrototypeOf(this, ParseError.prototype);
|
|
596
2658
|
}
|
|
597
2659
|
}
|
|
598
|
-
|
|
599
2660
|
/**
|
|
600
|
-
*
|
|
601
|
-
*
|
|
602
|
-
* @param whatWasThrown Any object that was thrown
|
|
603
|
-
* @returns Nothing if the error is an instance of `Error`
|
|
604
|
-
* @throws `WrappedError` or `UnexpectedError` if the error is not standard
|
|
605
|
-
*
|
|
606
|
-
* @private within the repository
|
|
2661
|
+
* TODO: Maybe split `ParseError` and `ApplyError`
|
|
607
2662
|
*/
|
|
608
|
-
function assertsError(whatWasThrown) {
|
|
609
|
-
// Case 1: Handle error which was rethrown as `WrappedError`
|
|
610
|
-
if (whatWasThrown instanceof WrappedError) {
|
|
611
|
-
const wrappedError = whatWasThrown;
|
|
612
|
-
throw wrappedError;
|
|
613
|
-
}
|
|
614
|
-
// Case 2: Handle unexpected errors
|
|
615
|
-
if (whatWasThrown instanceof UnexpectedError) {
|
|
616
|
-
const unexpectedError = whatWasThrown;
|
|
617
|
-
throw unexpectedError;
|
|
618
|
-
}
|
|
619
|
-
// Case 3: Handle standard errors - keep them up to consumer
|
|
620
|
-
if (whatWasThrown instanceof Error) {
|
|
621
|
-
return;
|
|
622
|
-
}
|
|
623
|
-
// Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
|
|
624
|
-
throw new WrappedError(whatWasThrown);
|
|
625
|
-
}
|
|
626
2663
|
|
|
627
2664
|
/**
|
|
628
2665
|
* Function isValidJsonString will tell you if the string is valid JSON or not
|
|
@@ -829,7 +2866,7 @@ function pipelineJsonToString(pipelineJson) {
|
|
|
829
2866
|
pipelineString += '\n\n';
|
|
830
2867
|
pipelineString += '```' + contentLanguage;
|
|
831
2868
|
pipelineString += '\n';
|
|
832
|
-
pipelineString += spaceTrim(content);
|
|
2869
|
+
pipelineString += spaceTrim$1(content);
|
|
833
2870
|
// <- TODO: [main] !!3 Escape
|
|
834
2871
|
// <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
|
|
835
2872
|
pipelineString += '\n';
|
|
@@ -873,33 +2910,6 @@ function orderJson(options) {
|
|
|
873
2910
|
return orderedValue;
|
|
874
2911
|
}
|
|
875
2912
|
|
|
876
|
-
/**
|
|
877
|
-
* Freezes the given object and all its nested objects recursively
|
|
878
|
-
*
|
|
879
|
-
* Note: `$` is used to indicate that this function is not a pure function - it mutates given object
|
|
880
|
-
* Note: This function mutates the object and returns the original (but mutated-deep-freezed) object
|
|
881
|
-
*
|
|
882
|
-
* @returns The same object as the input, but deeply frozen
|
|
883
|
-
* @public exported from `@promptbook/utils`
|
|
884
|
-
*/
|
|
885
|
-
function $deepFreeze(objectValue) {
|
|
886
|
-
if (Array.isArray(objectValue)) {
|
|
887
|
-
return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
|
|
888
|
-
}
|
|
889
|
-
const propertyNames = Object.getOwnPropertyNames(objectValue);
|
|
890
|
-
for (const propertyName of propertyNames) {
|
|
891
|
-
const value = objectValue[propertyName];
|
|
892
|
-
if (value && typeof value === 'object') {
|
|
893
|
-
$deepFreeze(value);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
Object.freeze(objectValue);
|
|
897
|
-
return objectValue;
|
|
898
|
-
}
|
|
899
|
-
/**
|
|
900
|
-
* TODO: [🧠] Is there a way how to meaningfully test this utility
|
|
901
|
-
*/
|
|
902
|
-
|
|
903
2913
|
/**
|
|
904
2914
|
* Checks if the value is [🚉] serializable as JSON
|
|
905
2915
|
* If not, throws an UnexpectedError with a rich error message and tracking
|
|
@@ -950,7 +2960,7 @@ function checkSerializableAsJson(options) {
|
|
|
950
2960
|
}
|
|
951
2961
|
else if (typeof value === 'object') {
|
|
952
2962
|
if (value instanceof Date) {
|
|
953
|
-
throw new UnexpectedError(spaceTrim((block) => `
|
|
2963
|
+
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
954
2964
|
\`${name}\` is Date
|
|
955
2965
|
|
|
956
2966
|
Use \`string_date_iso8601\` instead
|
|
@@ -969,7 +2979,7 @@ function checkSerializableAsJson(options) {
|
|
|
969
2979
|
throw new UnexpectedError(`${name} is RegExp`);
|
|
970
2980
|
}
|
|
971
2981
|
else if (value instanceof Error) {
|
|
972
|
-
throw new UnexpectedError(spaceTrim((block) => `
|
|
2982
|
+
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
973
2983
|
\`${name}\` is unserialized Error
|
|
974
2984
|
|
|
975
2985
|
Use function \`serializeError\`
|
|
@@ -992,7 +3002,7 @@ function checkSerializableAsJson(options) {
|
|
|
992
3002
|
}
|
|
993
3003
|
catch (error) {
|
|
994
3004
|
assertsError(error);
|
|
995
|
-
throw new UnexpectedError(spaceTrim((block) => `
|
|
3005
|
+
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
996
3006
|
\`${name}\` is not serializable
|
|
997
3007
|
|
|
998
3008
|
${block(error.stack || error.message)}
|
|
@@ -1024,7 +3034,7 @@ function checkSerializableAsJson(options) {
|
|
|
1024
3034
|
}
|
|
1025
3035
|
}
|
|
1026
3036
|
else {
|
|
1027
|
-
throw new UnexpectedError(spaceTrim((block) => `
|
|
3037
|
+
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
1028
3038
|
\`${name}\` is unknown type
|
|
1029
3039
|
|
|
1030
3040
|
Additional message for \`${name}\`:
|
|
@@ -1311,7 +3321,7 @@ function validatePipeline(pipeline) {
|
|
|
1311
3321
|
if (!(error instanceof PipelineLogicError)) {
|
|
1312
3322
|
throw error;
|
|
1313
3323
|
}
|
|
1314
|
-
console.error(spaceTrim
|
|
3324
|
+
console.error(spaceTrim((block) => `
|
|
1315
3325
|
Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
|
|
1316
3326
|
|
|
1317
3327
|
${block(error.message)}
|
|
@@ -1338,7 +3348,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1338
3348
|
})();
|
|
1339
3349
|
if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
|
|
1340
3350
|
// <- Note: [🚲]
|
|
1341
|
-
throw new PipelineLogicError(spaceTrim
|
|
3351
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1342
3352
|
Invalid promptbook URL "${pipeline.pipelineUrl}"
|
|
1343
3353
|
|
|
1344
3354
|
${block(pipelineIdentification)}
|
|
@@ -1346,7 +3356,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1346
3356
|
}
|
|
1347
3357
|
if (pipeline.bookVersion !== undefined && !isValidPromptbookVersion(pipeline.bookVersion)) {
|
|
1348
3358
|
// <- Note: [🚲]
|
|
1349
|
-
throw new PipelineLogicError(spaceTrim
|
|
3359
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1350
3360
|
Invalid Promptbook Version "${pipeline.bookVersion}"
|
|
1351
3361
|
|
|
1352
3362
|
${block(pipelineIdentification)}
|
|
@@ -1355,7 +3365,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1355
3365
|
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
1356
3366
|
if (!Array.isArray(pipeline.parameters)) {
|
|
1357
3367
|
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
1358
|
-
throw new ParseError(spaceTrim
|
|
3368
|
+
throw new ParseError(spaceTrim((block) => `
|
|
1359
3369
|
Pipeline is valid JSON but with wrong structure
|
|
1360
3370
|
|
|
1361
3371
|
\`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
|
|
@@ -1366,7 +3376,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1366
3376
|
// TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
|
|
1367
3377
|
if (!Array.isArray(pipeline.tasks)) {
|
|
1368
3378
|
// TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
|
|
1369
|
-
throw new ParseError(spaceTrim
|
|
3379
|
+
throw new ParseError(spaceTrim((block) => `
|
|
1370
3380
|
Pipeline is valid JSON but with wrong structure
|
|
1371
3381
|
|
|
1372
3382
|
\`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
|
|
@@ -1392,7 +3402,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1392
3402
|
// Note: Check each parameter individually
|
|
1393
3403
|
for (const parameter of pipeline.parameters) {
|
|
1394
3404
|
if (parameter.isInput && parameter.isOutput) {
|
|
1395
|
-
throw new PipelineLogicError(spaceTrim
|
|
3405
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1396
3406
|
|
|
1397
3407
|
Parameter \`{${parameter.name}}\` can not be both input and output
|
|
1398
3408
|
|
|
@@ -1403,7 +3413,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1403
3413
|
if (!parameter.isInput &&
|
|
1404
3414
|
!parameter.isOutput &&
|
|
1405
3415
|
!pipeline.tasks.some((task) => task.dependentParameterNames.includes(parameter.name))) {
|
|
1406
|
-
throw new PipelineLogicError(spaceTrim
|
|
3416
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1407
3417
|
Parameter \`{${parameter.name}}\` is created but not used
|
|
1408
3418
|
|
|
1409
3419
|
You can declare {${parameter.name}} as output parameter by adding in the header:
|
|
@@ -1415,7 +3425,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1415
3425
|
}
|
|
1416
3426
|
// Note: Testing that parameter is either input or result of some task
|
|
1417
3427
|
if (!parameter.isInput && !pipeline.tasks.some((task) => task.resultingParameterName === parameter.name)) {
|
|
1418
|
-
throw new PipelineLogicError(spaceTrim
|
|
3428
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1419
3429
|
Parameter \`{${parameter.name}}\` is declared but not defined
|
|
1420
3430
|
|
|
1421
3431
|
You can do one of these:
|
|
@@ -1431,14 +3441,14 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1431
3441
|
// Note: Checking each task individually
|
|
1432
3442
|
for (const task of pipeline.tasks) {
|
|
1433
3443
|
if (definedParameters.has(task.resultingParameterName)) {
|
|
1434
|
-
throw new PipelineLogicError(spaceTrim
|
|
3444
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1435
3445
|
Parameter \`{${task.resultingParameterName}}\` is defined multiple times
|
|
1436
3446
|
|
|
1437
3447
|
${block(pipelineIdentification)}
|
|
1438
3448
|
`));
|
|
1439
3449
|
}
|
|
1440
3450
|
if (RESERVED_PARAMETER_NAMES.includes(task.resultingParameterName)) {
|
|
1441
|
-
throw new PipelineLogicError(spaceTrim
|
|
3451
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1442
3452
|
Parameter name {${task.resultingParameterName}} is reserved, please use different name
|
|
1443
3453
|
|
|
1444
3454
|
${block(pipelineIdentification)}
|
|
@@ -1448,7 +3458,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1448
3458
|
if (task.jokerParameterNames && task.jokerParameterNames.length > 0) {
|
|
1449
3459
|
if (!task.format &&
|
|
1450
3460
|
!task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
|
|
1451
|
-
throw new PipelineLogicError(spaceTrim
|
|
3461
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1452
3462
|
Joker parameters are used for {${task.resultingParameterName}} but no expectations are defined
|
|
1453
3463
|
|
|
1454
3464
|
${block(pipelineIdentification)}
|
|
@@ -1456,7 +3466,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1456
3466
|
}
|
|
1457
3467
|
for (const joker of task.jokerParameterNames) {
|
|
1458
3468
|
if (!task.dependentParameterNames.includes(joker)) {
|
|
1459
|
-
throw new PipelineLogicError(spaceTrim
|
|
3469
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1460
3470
|
Parameter \`{${joker}}\` is used for {${task.resultingParameterName}} as joker but not in \`dependentParameterNames\`
|
|
1461
3471
|
|
|
1462
3472
|
${block(pipelineIdentification)}
|
|
@@ -1467,21 +3477,21 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1467
3477
|
if (task.expectations) {
|
|
1468
3478
|
for (const [unit, { min, max }] of Object.entries(task.expectations)) {
|
|
1469
3479
|
if (min !== undefined && max !== undefined && min > max) {
|
|
1470
|
-
throw new PipelineLogicError(spaceTrim
|
|
3480
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1471
3481
|
Min expectation (=${min}) of ${unit} is higher than max expectation (=${max})
|
|
1472
3482
|
|
|
1473
3483
|
${block(pipelineIdentification)}
|
|
1474
3484
|
`));
|
|
1475
3485
|
}
|
|
1476
3486
|
if (min !== undefined && min < 0) {
|
|
1477
|
-
throw new PipelineLogicError(spaceTrim
|
|
3487
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1478
3488
|
Min expectation of ${unit} must be zero or positive
|
|
1479
3489
|
|
|
1480
3490
|
${block(pipelineIdentification)}
|
|
1481
3491
|
`));
|
|
1482
3492
|
}
|
|
1483
3493
|
if (max !== undefined && max <= 0) {
|
|
1484
|
-
throw new PipelineLogicError(spaceTrim
|
|
3494
|
+
throw new PipelineLogicError(spaceTrim((block) => `
|
|
1485
3495
|
Max expectation of ${unit} must be positive
|
|
1486
3496
|
|
|
1487
3497
|
${block(pipelineIdentification)}
|
|
@@ -1503,7 +3513,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1503
3513
|
while (unresovedTasks.length > 0) {
|
|
1504
3514
|
if (loopLimit-- < 0) {
|
|
1505
3515
|
// Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
|
|
1506
|
-
throw new UnexpectedError(spaceTrim
|
|
3516
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
1507
3517
|
Loop limit reached during detection of circular dependencies in \`validatePipeline\`
|
|
1508
3518
|
|
|
1509
3519
|
${block(pipelineIdentification)}
|
|
@@ -1513,7 +3523,7 @@ function validatePipeline_InnerFunction(pipeline) {
|
|
|
1513
3523
|
if (currentlyResovedTasks.length === 0) {
|
|
1514
3524
|
throw new PipelineLogicError(
|
|
1515
3525
|
// TODO: [🐎] DRY
|
|
1516
|
-
spaceTrim
|
|
3526
|
+
spaceTrim((block) => `
|
|
1517
3527
|
|
|
1518
3528
|
Can not resolve some parameters:
|
|
1519
3529
|
Either you are using a parameter that is not defined, or there are some circular dependencies.
|
|
@@ -1677,7 +3687,7 @@ class SimplePipelineCollection {
|
|
|
1677
3687
|
for (const pipeline of pipelines) {
|
|
1678
3688
|
// TODO: [👠] DRY
|
|
1679
3689
|
if (pipeline.pipelineUrl === undefined) {
|
|
1680
|
-
throw new PipelineUrlError(spaceTrim
|
|
3690
|
+
throw new PipelineUrlError(spaceTrim(`
|
|
1681
3691
|
Pipeline with name "${pipeline.title}" does not have defined URL
|
|
1682
3692
|
|
|
1683
3693
|
File:
|
|
@@ -1699,7 +3709,7 @@ class SimplePipelineCollection {
|
|
|
1699
3709
|
pipelineJsonToString(unpreparePipeline(pipeline)) !==
|
|
1700
3710
|
pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
|
|
1701
3711
|
const existing = this.collection.get(pipeline.pipelineUrl);
|
|
1702
|
-
throw new PipelineUrlError(spaceTrim
|
|
3712
|
+
throw new PipelineUrlError(spaceTrim(`
|
|
1703
3713
|
Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍎
|
|
1704
3714
|
|
|
1705
3715
|
Conflicting files:
|
|
@@ -1731,13 +3741,13 @@ class SimplePipelineCollection {
|
|
|
1731
3741
|
const pipeline = this.collection.get(url);
|
|
1732
3742
|
if (!pipeline) {
|
|
1733
3743
|
if (this.listPipelines().length === 0) {
|
|
1734
|
-
throw new NotFoundError(spaceTrim
|
|
3744
|
+
throw new NotFoundError(spaceTrim(`
|
|
1735
3745
|
Pipeline with url "${url}" not found
|
|
1736
3746
|
|
|
1737
3747
|
No pipelines available
|
|
1738
3748
|
`));
|
|
1739
3749
|
}
|
|
1740
|
-
throw new NotFoundError(spaceTrim
|
|
3750
|
+
throw new NotFoundError(spaceTrim((block) => `
|
|
1741
3751
|
Pipeline with url "${url}" not found
|
|
1742
3752
|
|
|
1743
3753
|
Available pipelines:
|
|
@@ -1867,7 +3877,7 @@ function createSubcollection(collection, predicate) {
|
|
|
1867
3877
|
}
|
|
1868
3878
|
async function getPipelineByUrl(url) {
|
|
1869
3879
|
if (!predicate(url)) {
|
|
1870
|
-
throw new NotFoundError(await spaceTrim
|
|
3880
|
+
throw new NotFoundError(await spaceTrim(async (block) => `
|
|
1871
3881
|
Promptbook with url "${url}" not found or not accessible
|
|
1872
3882
|
|
|
1873
3883
|
Available promptbooks:
|
|
@@ -1902,7 +3912,7 @@ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"
|
|
|
1902
3912
|
*/
|
|
1903
3913
|
class MissingToolsError extends Error {
|
|
1904
3914
|
constructor(message) {
|
|
1905
|
-
super(spaceTrim
|
|
3915
|
+
super(spaceTrim((block) => `
|
|
1906
3916
|
${block(message)}
|
|
1907
3917
|
|
|
1908
3918
|
Note: You have probably forgot to provide some tools for pipeline execution or preparation
|
|
@@ -2071,7 +4081,7 @@ class LimitReachedError extends Error {
|
|
|
2071
4081
|
*/
|
|
2072
4082
|
class NotYetImplementedError extends Error {
|
|
2073
4083
|
constructor(message) {
|
|
2074
|
-
super(spaceTrim
|
|
4084
|
+
super(spaceTrim((block) => `
|
|
2075
4085
|
${block(message)}
|
|
2076
4086
|
|
|
2077
4087
|
Note: This feature is not implemented yet but it will be soon.
|
|
@@ -2121,19 +4131,6 @@ class PipelineExecutionError extends Error {
|
|
|
2121
4131
|
* TODO: [🧠][🌂] Add id to all errors
|
|
2122
4132
|
*/
|
|
2123
4133
|
|
|
2124
|
-
/**
|
|
2125
|
-
* Error thrown when a fetch request fails
|
|
2126
|
-
*
|
|
2127
|
-
* @public exported from `@promptbook/core`
|
|
2128
|
-
*/
|
|
2129
|
-
class PromptbookFetchError extends Error {
|
|
2130
|
-
constructor(message) {
|
|
2131
|
-
super(message);
|
|
2132
|
-
this.name = 'PromptbookFetchError';
|
|
2133
|
-
Object.setPrototypeOf(this, PromptbookFetchError.prototype);
|
|
2134
|
-
}
|
|
2135
|
-
}
|
|
2136
|
-
|
|
2137
4134
|
/**
|
|
2138
4135
|
* Index of all custom errors
|
|
2139
4136
|
*
|
|
@@ -2205,7 +4202,7 @@ function serializeError(error) {
|
|
|
2205
4202
|
const { name, message, stack } = error;
|
|
2206
4203
|
const { id } = error;
|
|
2207
4204
|
if (!Object.keys(ALL_ERRORS).includes(name)) {
|
|
2208
|
-
console.error(spaceTrim((block) => `
|
|
4205
|
+
console.error(spaceTrim$1((block) => `
|
|
2209
4206
|
|
|
2210
4207
|
Cannot serialize error with name "${name}"
|
|
2211
4208
|
|
|
@@ -2238,7 +4235,7 @@ function jsonParse(value) {
|
|
|
2238
4235
|
}
|
|
2239
4236
|
else if (typeof value !== 'string') {
|
|
2240
4237
|
console.error('Can not parse JSON from non-string value.', { text: value });
|
|
2241
|
-
throw new Error(spaceTrim(`
|
|
4238
|
+
throw new Error(spaceTrim$1(`
|
|
2242
4239
|
Can not parse JSON from non-string value.
|
|
2243
4240
|
|
|
2244
4241
|
The value type: ${typeof value}
|
|
@@ -2252,7 +4249,7 @@ function jsonParse(value) {
|
|
|
2252
4249
|
if (!(error instanceof Error)) {
|
|
2253
4250
|
throw error;
|
|
2254
4251
|
}
|
|
2255
|
-
throw new Error(spaceTrim((block) => `
|
|
4252
|
+
throw new Error(spaceTrim$1((block) => `
|
|
2256
4253
|
${block(error.message)}
|
|
2257
4254
|
|
|
2258
4255
|
The expected JSON text:
|
|
@@ -2305,7 +4302,7 @@ function deserializeError(error) {
|
|
|
2305
4302
|
message = `${name}: ${message}`;
|
|
2306
4303
|
}
|
|
2307
4304
|
if (stack !== undefined && stack !== '') {
|
|
2308
|
-
message = spaceTrim((block) => `
|
|
4305
|
+
message = spaceTrim$1((block) => `
|
|
2309
4306
|
${block(message)}
|
|
2310
4307
|
|
|
2311
4308
|
Original stack trace:
|
|
@@ -2342,11 +4339,11 @@ function assertsTaskSuccessful(executionResult) {
|
|
|
2342
4339
|
throw deserializeError(errors[0]);
|
|
2343
4340
|
}
|
|
2344
4341
|
else {
|
|
2345
|
-
throw new PipelineExecutionError(spaceTrim
|
|
4342
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
2346
4343
|
Multiple errors occurred during Promptbook execution
|
|
2347
4344
|
|
|
2348
4345
|
${block(errors
|
|
2349
|
-
.map(({ name, stack, message }, index) => spaceTrim
|
|
4346
|
+
.map(({ name, stack, message }, index) => spaceTrim((block) => `
|
|
2350
4347
|
${name} ${index + 1}:
|
|
2351
4348
|
${block(stack || message)}
|
|
2352
4349
|
`))
|
|
@@ -2716,7 +4713,7 @@ function extractVariablesFromJavascript(script) {
|
|
|
2716
4713
|
}
|
|
2717
4714
|
catch (error) {
|
|
2718
4715
|
assertsError(error);
|
|
2719
|
-
throw new ParseError(spaceTrim
|
|
4716
|
+
throw new ParseError(spaceTrim((block) => `
|
|
2720
4717
|
Can not extract variables from the script
|
|
2721
4718
|
${block(error.stack || error.message)}
|
|
2722
4719
|
|
|
@@ -2899,7 +4896,7 @@ const CsvFormatParser = {
|
|
|
2899
4896
|
const { value, outputParameterName, settings, mapCallback, onProgress } = options;
|
|
2900
4897
|
const csv = csvParse(value, settings);
|
|
2901
4898
|
if (csv.errors.length !== 0) {
|
|
2902
|
-
throw new CsvFormatError(spaceTrim((block) => `
|
|
4899
|
+
throw new CsvFormatError(spaceTrim$1((block) => `
|
|
2903
4900
|
CSV parsing error
|
|
2904
4901
|
|
|
2905
4902
|
Error(s) from CSV parsing:
|
|
@@ -2944,7 +4941,7 @@ const CsvFormatParser = {
|
|
|
2944
4941
|
const { value, settings, mapCallback, onProgress } = options;
|
|
2945
4942
|
const csv = csvParse(value, settings);
|
|
2946
4943
|
if (csv.errors.length !== 0) {
|
|
2947
|
-
throw new CsvFormatError(spaceTrim((block) => `
|
|
4944
|
+
throw new CsvFormatError(spaceTrim$1((block) => `
|
|
2948
4945
|
CSV parsing error
|
|
2949
4946
|
|
|
2950
4947
|
Error(s) from CSV parsing:
|
|
@@ -3154,7 +5151,7 @@ function mapAvailableToExpectedParameters(options) {
|
|
|
3154
5151
|
}
|
|
3155
5152
|
// Phase 2️⃣: Non-matching mapping
|
|
3156
5153
|
if (expectedParameterNames.size !== availableParametersNames.size) {
|
|
3157
|
-
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
5154
|
+
throw new PipelineExecutionError(spaceTrim$1((block) => `
|
|
3158
5155
|
Can not map available parameters to expected parameters
|
|
3159
5156
|
|
|
3160
5157
|
Mapped parameters:
|
|
@@ -3207,14 +5204,14 @@ class MultipleLlmExecutionTools {
|
|
|
3207
5204
|
if (description === undefined) {
|
|
3208
5205
|
return headLine;
|
|
3209
5206
|
}
|
|
3210
|
-
return spaceTrim((block) => `
|
|
5207
|
+
return spaceTrim$1((block) => `
|
|
3211
5208
|
${headLine}
|
|
3212
5209
|
|
|
3213
5210
|
${ /* <- Note: Indenting the description: */block(description)}
|
|
3214
5211
|
`);
|
|
3215
5212
|
})
|
|
3216
5213
|
.join('\n\n');
|
|
3217
|
-
return spaceTrim((block) => `
|
|
5214
|
+
return spaceTrim$1((block) => `
|
|
3218
5215
|
Multiple LLM Providers:
|
|
3219
5216
|
|
|
3220
5217
|
${block(innerModelsTitlesAndDescriptions)}
|
|
@@ -3305,7 +5302,7 @@ class MultipleLlmExecutionTools {
|
|
|
3305
5302
|
// 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
|
|
3306
5303
|
// 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
|
|
3307
5304
|
// 3) ...
|
|
3308
|
-
spaceTrim((block) => `
|
|
5305
|
+
spaceTrim$1((block) => `
|
|
3309
5306
|
All execution tools failed:
|
|
3310
5307
|
|
|
3311
5308
|
${block(errors
|
|
@@ -3318,7 +5315,7 @@ class MultipleLlmExecutionTools {
|
|
|
3318
5315
|
throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\``);
|
|
3319
5316
|
}
|
|
3320
5317
|
else {
|
|
3321
|
-
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
5318
|
+
throw new PipelineExecutionError(spaceTrim$1((block) => `
|
|
3322
5319
|
You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}"
|
|
3323
5320
|
|
|
3324
5321
|
Available \`LlmExecutionTools\`:
|
|
@@ -3351,7 +5348,7 @@ class MultipleLlmExecutionTools {
|
|
|
3351
5348
|
*/
|
|
3352
5349
|
function joinLlmExecutionTools(...llmExecutionTools) {
|
|
3353
5350
|
if (llmExecutionTools.length === 0) {
|
|
3354
|
-
const warningMessage = spaceTrim(`
|
|
5351
|
+
const warningMessage = spaceTrim$1(`
|
|
3355
5352
|
You have not provided any \`LlmExecutionTools\`
|
|
3356
5353
|
This means that you won't be able to execute any prompts that require large language models like GPT-4 or Anthropic's Claude.
|
|
3357
5354
|
|
|
@@ -4063,7 +6060,7 @@ function validatePromptResult(options) {
|
|
|
4063
6060
|
}
|
|
4064
6061
|
catch (error) {
|
|
4065
6062
|
keepUnused(error);
|
|
4066
|
-
throw new ExpectError(spaceTrim
|
|
6063
|
+
throw new ExpectError(spaceTrim((block) => `
|
|
4067
6064
|
Expected valid JSON string
|
|
4068
6065
|
|
|
4069
6066
|
The expected JSON text:
|
|
@@ -4112,7 +6109,7 @@ function validatePromptResult(options) {
|
|
|
4112
6109
|
*/
|
|
4113
6110
|
async function executeAttempts(options) {
|
|
4114
6111
|
const { jokerParameterNames, priority, maxAttempts, // <- Note: [💂]
|
|
4115
|
-
preparedContent, parameters, task, preparedPipeline, tools, $executionReport, pipelineIdentification, maxExecutionAttempts, } = options;
|
|
6112
|
+
preparedContent, parameters, task, preparedPipeline, tools, $executionReport, pipelineIdentification, maxExecutionAttempts, onProgress, } = options;
|
|
4116
6113
|
const $ongoingTaskResult = {
|
|
4117
6114
|
$result: null,
|
|
4118
6115
|
$resultString: null,
|
|
@@ -4128,7 +6125,7 @@ async function executeAttempts(options) {
|
|
|
4128
6125
|
const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
|
|
4129
6126
|
// TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
|
|
4130
6127
|
if (isJokerAttempt && !jokerParameterName) {
|
|
4131
|
-
throw new UnexpectedError(spaceTrim
|
|
6128
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
4132
6129
|
Joker not found in attempt ${attemptIndex}
|
|
4133
6130
|
|
|
4134
6131
|
${block(pipelineIdentification)}
|
|
@@ -4139,7 +6136,7 @@ async function executeAttempts(options) {
|
|
|
4139
6136
|
$ongoingTaskResult.$expectError = null;
|
|
4140
6137
|
if (isJokerAttempt) {
|
|
4141
6138
|
if (parameters[jokerParameterName] === undefined) {
|
|
4142
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6139
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4143
6140
|
Joker parameter {${jokerParameterName}} not defined
|
|
4144
6141
|
|
|
4145
6142
|
${block(pipelineIdentification)}
|
|
@@ -4197,7 +6194,7 @@ async function executeAttempts(options) {
|
|
|
4197
6194
|
$ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
|
|
4198
6195
|
break variant;
|
|
4199
6196
|
case 'EMBEDDING':
|
|
4200
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6197
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4201
6198
|
Embedding model can not be used in pipeline
|
|
4202
6199
|
|
|
4203
6200
|
This should be catched during parsing
|
|
@@ -4208,7 +6205,7 @@ async function executeAttempts(options) {
|
|
|
4208
6205
|
break variant;
|
|
4209
6206
|
// <- case [🤖]:
|
|
4210
6207
|
default:
|
|
4211
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6208
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4212
6209
|
Unknown model variant "${task.modelRequirements.modelVariant}"
|
|
4213
6210
|
|
|
4214
6211
|
${block(pipelineIdentification)}
|
|
@@ -4219,14 +6216,14 @@ async function executeAttempts(options) {
|
|
|
4219
6216
|
break;
|
|
4220
6217
|
case 'SCRIPT_TASK':
|
|
4221
6218
|
if (arrayableToArray(tools.script).length === 0) {
|
|
4222
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6219
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4223
6220
|
No script execution tools are available
|
|
4224
6221
|
|
|
4225
6222
|
${block(pipelineIdentification)}
|
|
4226
6223
|
`));
|
|
4227
6224
|
}
|
|
4228
6225
|
if (!task.contentLanguage) {
|
|
4229
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6226
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4230
6227
|
Script language is not defined for SCRIPT TASK "${task.name}"
|
|
4231
6228
|
|
|
4232
6229
|
${block(pipelineIdentification)}
|
|
@@ -4257,7 +6254,7 @@ async function executeAttempts(options) {
|
|
|
4257
6254
|
throw $ongoingTaskResult.$scriptPipelineExecutionErrors[0];
|
|
4258
6255
|
}
|
|
4259
6256
|
else {
|
|
4260
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6257
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4261
6258
|
Script execution failed ${$ongoingTaskResult.$scriptPipelineExecutionErrors.length}x
|
|
4262
6259
|
|
|
4263
6260
|
${block(pipelineIdentification)}
|
|
@@ -4271,7 +6268,7 @@ async function executeAttempts(options) {
|
|
|
4271
6268
|
break taskType;
|
|
4272
6269
|
case 'DIALOG_TASK':
|
|
4273
6270
|
if (tools.userInterface === undefined) {
|
|
4274
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6271
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4275
6272
|
User interface tools are not available
|
|
4276
6273
|
|
|
4277
6274
|
${block(pipelineIdentification)}
|
|
@@ -4289,7 +6286,7 @@ async function executeAttempts(options) {
|
|
|
4289
6286
|
break taskType;
|
|
4290
6287
|
// <- case: [🅱]
|
|
4291
6288
|
default:
|
|
4292
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6289
|
+
throw new PipelineExecutionError(spaceTrim((block) => `
|
|
4293
6290
|
Unknown execution type "${task.taskType}"
|
|
4294
6291
|
|
|
4295
6292
|
${block(pipelineIdentification)}
|
|
@@ -4356,6 +6353,10 @@ async function executeAttempts(options) {
|
|
|
4356
6353
|
result: $ongoingTaskResult.$resultString,
|
|
4357
6354
|
error: error,
|
|
4358
6355
|
});
|
|
6356
|
+
// Report failed attempt
|
|
6357
|
+
onProgress({
|
|
6358
|
+
errors: [error],
|
|
6359
|
+
});
|
|
4359
6360
|
}
|
|
4360
6361
|
finally {
|
|
4361
6362
|
if (!isJokerAttempt &&
|
|
@@ -4380,7 +6381,7 @@ async function executeAttempts(options) {
|
|
|
4380
6381
|
if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
|
|
4381
6382
|
// Note: Create a summary of all failures
|
|
4382
6383
|
const failuresSummary = $ongoingTaskResult.$failedResults
|
|
4383
|
-
.map((failure) => spaceTrim
|
|
6384
|
+
.map((failure) => spaceTrim((block) => {
|
|
4384
6385
|
var _a, _b;
|
|
4385
6386
|
return `
|
|
4386
6387
|
Attempt ${failure.attemptIndex + 1}:
|
|
@@ -4390,14 +6391,14 @@ async function executeAttempts(options) {
|
|
|
4390
6391
|
Result:
|
|
4391
6392
|
${block(failure.result === null
|
|
4392
6393
|
? 'null'
|
|
4393
|
-
: spaceTrim
|
|
6394
|
+
: spaceTrim(failure.result)
|
|
4394
6395
|
.split('\n')
|
|
4395
6396
|
.map((line) => `> ${line}`)
|
|
4396
6397
|
.join('\n'))}
|
|
4397
6398
|
`;
|
|
4398
6399
|
}))
|
|
4399
6400
|
.join('\n\n---\n\n');
|
|
4400
|
-
throw new PipelineExecutionError(spaceTrim
|
|
6401
|
+
throw new PipelineExecutionError(spaceTrim((block) => {
|
|
4401
6402
|
var _a;
|
|
4402
6403
|
return `
|
|
4403
6404
|
LLM execution failed ${maxExecutionAttempts}x
|
|
@@ -4417,7 +6418,7 @@ async function executeAttempts(options) {
|
|
|
4417
6418
|
}
|
|
4418
6419
|
}
|
|
4419
6420
|
if ($ongoingTaskResult.$resultString === null) {
|
|
4420
|
-
throw new UnexpectedError(spaceTrim
|
|
6421
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
4421
6422
|
Something went wrong and prompt result is null
|
|
4422
6423
|
|
|
4423
6424
|
${block(pipelineIdentification)}
|
|
@@ -4444,7 +6445,7 @@ async function executeFormatSubvalues(options) {
|
|
|
4444
6445
|
return /* not await */ executeAttempts(options);
|
|
4445
6446
|
}
|
|
4446
6447
|
if (jokerParameterNames.length !== 0) {
|
|
4447
|
-
throw new UnexpectedError(spaceTrim((block) => `
|
|
6448
|
+
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
4448
6449
|
JOKER parameters are not supported together with FOREACH command
|
|
4449
6450
|
|
|
4450
6451
|
[🧞♀️] This should be prevented in \`validatePipeline\`
|
|
@@ -4457,7 +6458,7 @@ async function executeFormatSubvalues(options) {
|
|
|
4457
6458
|
if (formatDefinition === undefined) {
|
|
4458
6459
|
throw new UnexpectedError(
|
|
4459
6460
|
// <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
|
|
4460
|
-
spaceTrim((block) => `
|
|
6461
|
+
spaceTrim$1((block) => `
|
|
4461
6462
|
Unsupported format "${task.foreach.formatName}"
|
|
4462
6463
|
|
|
4463
6464
|
Available formats:
|
|
@@ -4474,7 +6475,7 @@ async function executeFormatSubvalues(options) {
|
|
|
4474
6475
|
if (subvalueParser === undefined) {
|
|
4475
6476
|
throw new UnexpectedError(
|
|
4476
6477
|
// <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
|
|
4477
|
-
spaceTrim((block) => `
|
|
6478
|
+
spaceTrim$1((block) => `
|
|
4478
6479
|
Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
|
|
4479
6480
|
|
|
4480
6481
|
Available subformat names for format "${formatDefinition.formatName}":
|
|
@@ -4514,7 +6515,7 @@ async function executeFormatSubvalues(options) {
|
|
|
4514
6515
|
if (!(error instanceof PipelineExecutionError)) {
|
|
4515
6516
|
throw error;
|
|
4516
6517
|
}
|
|
4517
|
-
const highLevelError = new PipelineExecutionError(spaceTrim((block) => `
|
|
6518
|
+
const highLevelError = new PipelineExecutionError(spaceTrim$1((block) => `
|
|
4518
6519
|
${error.message}
|
|
4519
6520
|
|
|
4520
6521
|
This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
|
|
@@ -4538,7 +6539,7 @@ async function executeFormatSubvalues(options) {
|
|
|
4538
6539
|
...options,
|
|
4539
6540
|
priority: priority + index,
|
|
4540
6541
|
parameters: allSubparameters,
|
|
4541
|
-
pipelineIdentification: spaceTrim((block) => `
|
|
6542
|
+
pipelineIdentification: spaceTrim$1((block) => `
|
|
4542
6543
|
${block(pipelineIdentification)}
|
|
4543
6544
|
Subparameter index: ${index}
|
|
4544
6545
|
`),
|
|
@@ -4547,7 +6548,7 @@ async function executeFormatSubvalues(options) {
|
|
|
4547
6548
|
}
|
|
4548
6549
|
catch (error) {
|
|
4549
6550
|
if (length > BIG_DATASET_TRESHOLD) {
|
|
4550
|
-
console.error(spaceTrim((block) => `
|
|
6551
|
+
console.error(spaceTrim$1((block) => `
|
|
4551
6552
|
${error.message}
|
|
4552
6553
|
|
|
4553
6554
|
This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
|
|
@@ -4725,7 +6726,7 @@ async function getReservedParametersForTask(options) {
|
|
|
4725
6726
|
// Note: Doublecheck that ALL reserved parameters are defined:
|
|
4726
6727
|
for (const parameterName of RESERVED_PARAMETER_NAMES) {
|
|
4727
6728
|
if (reservedParameters[parameterName] === undefined) {
|
|
4728
|
-
throw new UnexpectedError(spaceTrim
|
|
6729
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
4729
6730
|
Reserved parameter {${parameterName}} is not defined
|
|
4730
6731
|
|
|
4731
6732
|
${block(pipelineIdentification)}
|
|
@@ -4751,7 +6752,7 @@ async function executeTask(options) {
|
|
|
4751
6752
|
const dependentParameterNames = new Set(currentTask.dependentParameterNames);
|
|
4752
6753
|
// TODO: [👩🏾🤝👩🏻] Use here `mapAvailableToExpectedParameters`
|
|
4753
6754
|
if (difference(union(difference(usedParameterNames, dependentParameterNames), difference(dependentParameterNames, usedParameterNames)), new Set(RESERVED_PARAMETER_NAMES)).size !== 0) {
|
|
4754
|
-
throw new UnexpectedError(spaceTrim
|
|
6755
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
4755
6756
|
Dependent parameters are not consistent with used parameters:
|
|
4756
6757
|
|
|
4757
6758
|
Dependent parameters:
|
|
@@ -4795,7 +6796,7 @@ async function executeTask(options) {
|
|
|
4795
6796
|
else if (!definedParameterNames.has(parameterName) && usedParameterNames.has(parameterName)) {
|
|
4796
6797
|
// Houston, we have a problem
|
|
4797
6798
|
// Note: Checking part is also done in `validatePipeline`, but it’s good to doublecheck
|
|
4798
|
-
throw new UnexpectedError(spaceTrim
|
|
6799
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
4799
6800
|
Parameter \`{${parameterName}}\` is NOT defined
|
|
4800
6801
|
BUT used in task "${currentTask.title || currentTask.name}"
|
|
4801
6802
|
|
|
@@ -4863,7 +6864,7 @@ function filterJustOutputParameters(options) {
|
|
|
4863
6864
|
for (const parameter of preparedPipeline.parameters.filter(({ isOutput }) => isOutput)) {
|
|
4864
6865
|
if (parametersToPass[parameter.name] === undefined) {
|
|
4865
6866
|
// [4]
|
|
4866
|
-
$warnings.push(new PipelineExecutionError(spaceTrim
|
|
6867
|
+
$warnings.push(new PipelineExecutionError(spaceTrim((block) => `
|
|
4867
6868
|
Parameter \`{${parameter.name}}\` should be an output parameter, but it was not generated during pipeline execution
|
|
4868
6869
|
|
|
4869
6870
|
${block(pipelineIdentification)}
|
|
@@ -4948,7 +6949,7 @@ async function executePipeline(options) {
|
|
|
4948
6949
|
for (const parameterName of Object.keys(inputParameters)) {
|
|
4949
6950
|
const parameter = preparedPipeline.parameters.find(({ name }) => name === parameterName);
|
|
4950
6951
|
if (parameter === undefined) {
|
|
4951
|
-
warnings.push(new PipelineExecutionError(spaceTrim
|
|
6952
|
+
warnings.push(new PipelineExecutionError(spaceTrim((block) => `
|
|
4952
6953
|
Extra parameter {${parameterName}} is being passed which is not part of the pipeline.
|
|
4953
6954
|
|
|
4954
6955
|
${block(pipelineIdentification)}
|
|
@@ -4963,7 +6964,7 @@ async function executePipeline(options) {
|
|
|
4963
6964
|
// TODO: [🧠] This should be also non-critical error
|
|
4964
6965
|
return exportJson({
|
|
4965
6966
|
name: 'pipelineExecutorResult',
|
|
4966
|
-
message: spaceTrim
|
|
6967
|
+
message: spaceTrim((block) => `
|
|
4967
6968
|
Unsuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
|
|
4968
6969
|
|
|
4969
6970
|
${block(pipelineIdentification)}
|
|
@@ -4972,7 +6973,7 @@ async function executePipeline(options) {
|
|
|
4972
6973
|
value: {
|
|
4973
6974
|
isSuccessful: false,
|
|
4974
6975
|
errors: [
|
|
4975
|
-
new PipelineExecutionError(spaceTrim
|
|
6976
|
+
new PipelineExecutionError(spaceTrim((block) => `
|
|
4976
6977
|
Parameter \`{${parameter.name}}\` is passed as input parameter but it is not input
|
|
4977
6978
|
|
|
4978
6979
|
${block(pipelineIdentification)}
|
|
@@ -4999,7 +7000,7 @@ async function executePipeline(options) {
|
|
|
4999
7000
|
while (unresovedTasks.length > 0) {
|
|
5000
7001
|
if (loopLimit-- < 0) {
|
|
5001
7002
|
// Note: Really UnexpectedError not LimitReachedError - this should be catched during validatePipeline
|
|
5002
|
-
throw new UnexpectedError(spaceTrim
|
|
7003
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
5003
7004
|
Loop limit reached during resolving parameters pipeline execution
|
|
5004
7005
|
|
|
5005
7006
|
${block(pipelineIdentification)}
|
|
@@ -5009,7 +7010,7 @@ async function executePipeline(options) {
|
|
|
5009
7010
|
if (!currentTask && resolving.length === 0) {
|
|
5010
7011
|
throw new UnexpectedError(
|
|
5011
7012
|
// TODO: [🐎] DRY
|
|
5012
|
-
spaceTrim
|
|
7013
|
+
spaceTrim((block) => `
|
|
5013
7014
|
Can not resolve some parameters:
|
|
5014
7015
|
|
|
5015
7016
|
${block(pipelineIdentification)}
|
|
@@ -5049,7 +7050,7 @@ async function executePipeline(options) {
|
|
|
5049
7050
|
tools,
|
|
5050
7051
|
onProgress(newOngoingResult) {
|
|
5051
7052
|
if (isReturned) {
|
|
5052
|
-
throw new UnexpectedError(spaceTrim
|
|
7053
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
5053
7054
|
Can not call \`onProgress\` after pipeline execution is finished
|
|
5054
7055
|
|
|
5055
7056
|
${block(pipelineIdentification)}
|
|
@@ -5065,7 +7066,7 @@ async function executePipeline(options) {
|
|
|
5065
7066
|
}
|
|
5066
7067
|
},
|
|
5067
7068
|
$executionReport: executionReport,
|
|
5068
|
-
pipelineIdentification: spaceTrim
|
|
7069
|
+
pipelineIdentification: spaceTrim((block) => `
|
|
5069
7070
|
${block(pipelineIdentification)}
|
|
5070
7071
|
Task name: ${currentTask.name}
|
|
5071
7072
|
Task title: ${currentTask.title}
|
|
@@ -5174,7 +7175,7 @@ function createPipelineExecutor(options) {
|
|
|
5174
7175
|
preparedPipeline = pipeline;
|
|
5175
7176
|
}
|
|
5176
7177
|
else if (isNotPreparedWarningSuppressed !== true) {
|
|
5177
|
-
console.warn(spaceTrim
|
|
7178
|
+
console.warn(spaceTrim((block) => `
|
|
5178
7179
|
Pipeline is not prepared
|
|
5179
7180
|
|
|
5180
7181
|
${block(pipelineIdentification)}
|
|
@@ -5198,7 +7199,7 @@ function createPipelineExecutor(options) {
|
|
|
5198
7199
|
inputParameters,
|
|
5199
7200
|
tools,
|
|
5200
7201
|
onProgress,
|
|
5201
|
-
pipelineIdentification: spaceTrim
|
|
7202
|
+
pipelineIdentification: spaceTrim((block) => `
|
|
5202
7203
|
${block(pipelineIdentification)}
|
|
5203
7204
|
${runCount === 1 ? '' : `Run #${runCount}`}
|
|
5204
7205
|
`),
|
|
@@ -5609,14 +7610,14 @@ function $registeredScrapersMessage(availableScrapers) {
|
|
|
5609
7610
|
return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
|
|
5610
7611
|
});
|
|
5611
7612
|
if (metadata.length === 0) {
|
|
5612
|
-
return spaceTrim(`
|
|
7613
|
+
return spaceTrim$1(`
|
|
5613
7614
|
**No scrapers are available**
|
|
5614
7615
|
|
|
5615
7616
|
This is a unexpected behavior, you are probably using some broken version of Promptbook
|
|
5616
7617
|
At least there should be available the metadata of the scrapers
|
|
5617
7618
|
`);
|
|
5618
7619
|
}
|
|
5619
|
-
return spaceTrim((block) => `
|
|
7620
|
+
return spaceTrim$1((block) => `
|
|
5620
7621
|
Available scrapers are:
|
|
5621
7622
|
${block(metadata
|
|
5622
7623
|
.map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
|
|
@@ -5835,37 +7836,6 @@ function titleToName(value) {
|
|
|
5835
7836
|
return value;
|
|
5836
7837
|
}
|
|
5837
7838
|
|
|
5838
|
-
/**
|
|
5839
|
-
* The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
|
|
5840
|
-
*
|
|
5841
|
-
* @public exported from `@promptbook/core`
|
|
5842
|
-
*/
|
|
5843
|
-
const promptbookFetch = async (urlOrRequest, init) => {
|
|
5844
|
-
try {
|
|
5845
|
-
return await fetch(urlOrRequest, init);
|
|
5846
|
-
}
|
|
5847
|
-
catch (error) {
|
|
5848
|
-
assertsError(error);
|
|
5849
|
-
let url;
|
|
5850
|
-
if (typeof urlOrRequest === 'string') {
|
|
5851
|
-
url = urlOrRequest;
|
|
5852
|
-
}
|
|
5853
|
-
else if (urlOrRequest instanceof Request) {
|
|
5854
|
-
url = urlOrRequest.url;
|
|
5855
|
-
}
|
|
5856
|
-
throw new PromptbookFetchError(spaceTrim((block) => `
|
|
5857
|
-
Can not fetch "${url}"
|
|
5858
|
-
|
|
5859
|
-
Fetch error:
|
|
5860
|
-
${block(error.message)}
|
|
5861
|
-
|
|
5862
|
-
`));
|
|
5863
|
-
}
|
|
5864
|
-
};
|
|
5865
|
-
/**
|
|
5866
|
-
* TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
|
|
5867
|
-
*/
|
|
5868
|
-
|
|
5869
7839
|
/**
|
|
5870
7840
|
* Factory function that creates a handler for processing knowledge sources.
|
|
5871
7841
|
* Provides standardized processing of different types of knowledge sources
|
|
@@ -5920,7 +7890,23 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
|
|
|
5920
7890
|
// <- TODO: [🥬] Encapsulate sha256 to some private utility function
|
|
5921
7891
|
const rootDirname = join(process.cwd(), DEFAULT_DOWNLOAD_CACHE_DIRNAME);
|
|
5922
7892
|
const filepath = join(...nameToSubfolderPath(hash /* <- TODO: [🎎] Maybe add some SHA256 prefix */), `${basename.substring(0, MAX_FILENAME_LENGTH)}.${mimeTypeToExtension(mimeType)}`);
|
|
5923
|
-
|
|
7893
|
+
// Note: Try to create cache directory, but don't fail if filesystem has issues
|
|
7894
|
+
try {
|
|
7895
|
+
await tools.fs.mkdir(dirname(join(rootDirname, filepath)), { recursive: true });
|
|
7896
|
+
}
|
|
7897
|
+
catch (error) {
|
|
7898
|
+
// Note: If we can't create cache directory, we'll handle it when trying to write the file
|
|
7899
|
+
// This handles read-only filesystems, permission issues, and missing parent directories
|
|
7900
|
+
if (error instanceof Error && (error.message.includes('EROFS') ||
|
|
7901
|
+
error.message.includes('read-only') ||
|
|
7902
|
+
error.message.includes('EACCES') ||
|
|
7903
|
+
error.message.includes('EPERM') ||
|
|
7904
|
+
error.message.includes('ENOENT'))) ;
|
|
7905
|
+
else {
|
|
7906
|
+
// Re-throw other unexpected errors
|
|
7907
|
+
throw error;
|
|
7908
|
+
}
|
|
7909
|
+
}
|
|
5924
7910
|
const fileContent = Buffer.from(await response.arrayBuffer());
|
|
5925
7911
|
if (fileContent.length > DEFAULT_MAX_FILE_SIZE /* <- TODO: Allow to pass different value to remote server */) {
|
|
5926
7912
|
throw new LimitReachedError(`File is too large (${Math.round(fileContent.length / 1024 / 1024)}MB). Maximum allowed size is ${Math.round(DEFAULT_MAX_FILE_SIZE / 1024 / 1024)}MB.`);
|
|
@@ -5935,7 +7921,8 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
|
|
|
5935
7921
|
if (error instanceof Error && (error.message.includes('EROFS') ||
|
|
5936
7922
|
error.message.includes('read-only') ||
|
|
5937
7923
|
error.message.includes('EACCES') ||
|
|
5938
|
-
error.message.includes('EPERM')
|
|
7924
|
+
error.message.includes('EPERM') ||
|
|
7925
|
+
error.message.includes('ENOENT'))) {
|
|
5939
7926
|
// Return a handler that works directly with the downloaded content
|
|
5940
7927
|
return {
|
|
5941
7928
|
source: name,
|
|
@@ -5975,7 +7962,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
|
|
|
5975
7962
|
const fileExtension = getFileExtension(filename);
|
|
5976
7963
|
const mimeType = extensionToMimeType(fileExtension || '');
|
|
5977
7964
|
if (!(await isFileExisting(filename, tools.fs))) {
|
|
5978
|
-
throw new NotFoundError(spaceTrim((block) => `
|
|
7965
|
+
throw new NotFoundError(spaceTrim$1((block) => `
|
|
5979
7966
|
Can not make source handler for file which does not exist:
|
|
5980
7967
|
|
|
5981
7968
|
File:
|
|
@@ -6062,7 +8049,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
|
|
|
6062
8049
|
// <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
|
|
6063
8050
|
break;
|
|
6064
8051
|
}
|
|
6065
|
-
console.warn(spaceTrim((block) => `
|
|
8052
|
+
console.warn(spaceTrim$1((block) => `
|
|
6066
8053
|
Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
|
|
6067
8054
|
|
|
6068
8055
|
The source:
|
|
@@ -6078,7 +8065,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
|
|
|
6078
8065
|
// <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
6079
8066
|
}
|
|
6080
8067
|
if (partialPieces === null) {
|
|
6081
|
-
throw new KnowledgeScrapeError(spaceTrim((block) => `
|
|
8068
|
+
throw new KnowledgeScrapeError(spaceTrim$1((block) => `
|
|
6082
8069
|
Cannot scrape knowledge
|
|
6083
8070
|
|
|
6084
8071
|
The source:
|
|
@@ -6157,7 +8144,7 @@ async function prepareTasks(pipeline, tools, options) {
|
|
|
6157
8144
|
if (task.taskType === 'PROMPT_TASK' &&
|
|
6158
8145
|
knowledgePiecesCount > 0 &&
|
|
6159
8146
|
!dependentParameterNames.includes('knowledge')) {
|
|
6160
|
-
preparedContent = spaceTrim
|
|
8147
|
+
preparedContent = spaceTrim(`
|
|
6161
8148
|
{content}
|
|
6162
8149
|
|
|
6163
8150
|
## Knowledge
|
|
@@ -6416,7 +8403,7 @@ const knowledgeCommandParser = {
|
|
|
6416
8403
|
*/
|
|
6417
8404
|
parse(input) {
|
|
6418
8405
|
const { args } = input;
|
|
6419
|
-
const knowledgeSourceContent = spaceTrim(args[0] || '');
|
|
8406
|
+
const knowledgeSourceContent = spaceTrim$1(args[0] || '');
|
|
6420
8407
|
if (knowledgeSourceContent === '') {
|
|
6421
8408
|
throw new ParseError(`Source is not defined`);
|
|
6422
8409
|
}
|
|
@@ -6560,7 +8547,7 @@ const sectionCommandParser = {
|
|
|
6560
8547
|
normalized = normalized.split('DIALOGUE').join('DIALOG');
|
|
6561
8548
|
const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
|
|
6562
8549
|
if (taskTypes.length !== 1) {
|
|
6563
|
-
throw new ParseError(spaceTrim((block) => `
|
|
8550
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
6564
8551
|
Unknown section type "${normalized}"
|
|
6565
8552
|
|
|
6566
8553
|
Supported section types are:
|
|
@@ -6580,7 +8567,7 @@ const sectionCommandParser = {
|
|
|
6580
8567
|
*/
|
|
6581
8568
|
$applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
6582
8569
|
if ($taskJson.isSectionTypeSet === true) {
|
|
6583
|
-
throw new ParseError(spaceTrim(`
|
|
8570
|
+
throw new ParseError(spaceTrim$1(`
|
|
6584
8571
|
Section type is already defined in the section.
|
|
6585
8572
|
It can be defined only once.
|
|
6586
8573
|
`));
|
|
@@ -6928,7 +8915,7 @@ const expectCommandParser = {
|
|
|
6928
8915
|
/**
|
|
6929
8916
|
* Description of the FORMAT command
|
|
6930
8917
|
*/
|
|
6931
|
-
description: spaceTrim(`
|
|
8918
|
+
description: spaceTrim$1(`
|
|
6932
8919
|
Expect command describes the desired output of the task *(after post-processing)*
|
|
6933
8920
|
It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.
|
|
6934
8921
|
`),
|
|
@@ -7002,7 +8989,7 @@ const expectCommandParser = {
|
|
|
7002
8989
|
}
|
|
7003
8990
|
catch (error) {
|
|
7004
8991
|
assertsError(error);
|
|
7005
|
-
throw new ParseError(spaceTrim((block) => `
|
|
8992
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7006
8993
|
Invalid FORMAT command
|
|
7007
8994
|
${block(error.message)}:
|
|
7008
8995
|
`));
|
|
@@ -7187,7 +9174,7 @@ function validateParameterName(parameterName) {
|
|
|
7187
9174
|
if (!(error instanceof ParseError)) {
|
|
7188
9175
|
throw error;
|
|
7189
9176
|
}
|
|
7190
|
-
throw new ParseError(spaceTrim((block) => `
|
|
9177
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7191
9178
|
${block(error.message)}
|
|
7192
9179
|
|
|
7193
9180
|
Tried to validate parameter name:
|
|
@@ -7246,7 +9233,7 @@ const foreachCommandParser = {
|
|
|
7246
9233
|
const assignSign = args[3];
|
|
7247
9234
|
const formatDefinition = FORMAT_DEFINITIONS.find((formatDefinition) => [formatDefinition.formatName, ...(formatDefinition.aliases || [])].includes(formatName));
|
|
7248
9235
|
if (formatDefinition === undefined) {
|
|
7249
|
-
throw new ParseError(spaceTrim((block) => `
|
|
9236
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7250
9237
|
Unsupported format "${formatName}"
|
|
7251
9238
|
|
|
7252
9239
|
Available formats:
|
|
@@ -7258,7 +9245,7 @@ const foreachCommandParser = {
|
|
|
7258
9245
|
}
|
|
7259
9246
|
const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(subformatName));
|
|
7260
9247
|
if (subvalueParser === undefined) {
|
|
7261
|
-
throw new ParseError(spaceTrim((block) => `
|
|
9248
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7262
9249
|
Unsupported subformat name "${subformatName}" for format "${formatName}"
|
|
7263
9250
|
|
|
7264
9251
|
Available subformat names for format "${formatDefinition.formatName}":
|
|
@@ -7306,7 +9293,7 @@ const foreachCommandParser = {
|
|
|
7306
9293
|
outputSubparameterName = 'newLine';
|
|
7307
9294
|
}
|
|
7308
9295
|
else {
|
|
7309
|
-
throw new ParseError(spaceTrim(`
|
|
9296
|
+
throw new ParseError(spaceTrim$1(`
|
|
7310
9297
|
FOREACH ${formatName} ${subformatName} must specify output subparameter
|
|
7311
9298
|
|
|
7312
9299
|
Correct example:
|
|
@@ -7382,7 +9369,7 @@ const formatCommandParser = {
|
|
|
7382
9369
|
/**
|
|
7383
9370
|
* Description of the FORMAT command
|
|
7384
9371
|
*/
|
|
7385
|
-
description: spaceTrim(`
|
|
9372
|
+
description: spaceTrim$1(`
|
|
7386
9373
|
Format command describes the desired output of the task (after post-processing)
|
|
7387
9374
|
It can set limits for the maximum/minimum length of the output, measured in characters, words, sentences, paragraphs or some other shape of the output.
|
|
7388
9375
|
`),
|
|
@@ -7754,7 +9741,7 @@ const formfactorCommandParser = {
|
|
|
7754
9741
|
const formfactorNameCandidate = args[0].toUpperCase();
|
|
7755
9742
|
const formfactor = FORMFACTOR_DEFINITIONS.find((definition) => [definition.name, ...{ aliasNames: [], ...definition }.aliasNames].includes(formfactorNameCandidate));
|
|
7756
9743
|
if (formfactor === undefined) {
|
|
7757
|
-
throw new ParseError(spaceTrim((block) => `
|
|
9744
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7758
9745
|
Unknown formfactor name "${formfactorNameCandidate}"
|
|
7759
9746
|
|
|
7760
9747
|
Available formfactors:
|
|
@@ -7773,7 +9760,7 @@ const formfactorCommandParser = {
|
|
|
7773
9760
|
*/
|
|
7774
9761
|
$applyToPipelineJson(command, $pipelineJson) {
|
|
7775
9762
|
if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
|
|
7776
|
-
throw new ParseError(spaceTrim(`
|
|
9763
|
+
throw new ParseError(spaceTrim$1(`
|
|
7777
9764
|
Redefinition of \`FORMFACTOR\` in the pipeline head
|
|
7778
9765
|
|
|
7779
9766
|
You have used:
|
|
@@ -7916,7 +9903,7 @@ const modelCommandParser = {
|
|
|
7916
9903
|
*/
|
|
7917
9904
|
parse(input) {
|
|
7918
9905
|
const { args, normalized } = input;
|
|
7919
|
-
const availableVariantsMessage = spaceTrim((block) => `
|
|
9906
|
+
const availableVariantsMessage = spaceTrim$1((block) => `
|
|
7920
9907
|
Available variants are:
|
|
7921
9908
|
${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
|
|
7922
9909
|
`);
|
|
@@ -7938,14 +9925,14 @@ const modelCommandParser = {
|
|
|
7938
9925
|
// <- Note: [🤖]
|
|
7939
9926
|
}
|
|
7940
9927
|
else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
|
|
7941
|
-
spaceTrim((block) => `
|
|
9928
|
+
spaceTrim$1((block) => `
|
|
7942
9929
|
Embedding model can not be used in pipeline
|
|
7943
9930
|
|
|
7944
9931
|
${block(availableVariantsMessage)}
|
|
7945
9932
|
`);
|
|
7946
9933
|
}
|
|
7947
9934
|
else {
|
|
7948
|
-
throw new ParseError(spaceTrim((block) => `
|
|
9935
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7949
9936
|
Unknown model variant in command:
|
|
7950
9937
|
|
|
7951
9938
|
${block(availableVariantsMessage)}
|
|
@@ -7960,7 +9947,7 @@ const modelCommandParser = {
|
|
|
7960
9947
|
};
|
|
7961
9948
|
}
|
|
7962
9949
|
else {
|
|
7963
|
-
throw new ParseError(spaceTrim((block) => `
|
|
9950
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
7964
9951
|
Unknown model key in command.
|
|
7965
9952
|
|
|
7966
9953
|
Supported model keys are:
|
|
@@ -7987,7 +9974,7 @@ const modelCommandParser = {
|
|
|
7987
9974
|
// <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
7988
9975
|
}
|
|
7989
9976
|
else {
|
|
7990
|
-
throw new ParseError(spaceTrim(`
|
|
9977
|
+
throw new ParseError(spaceTrim$1(`
|
|
7991
9978
|
Redefinition of \`MODEL ${command.key}\` in the pipeline head
|
|
7992
9979
|
|
|
7993
9980
|
You have used:
|
|
@@ -8019,7 +10006,7 @@ const modelCommandParser = {
|
|
|
8019
10006
|
// <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
8020
10007
|
}
|
|
8021
10008
|
else {
|
|
8022
|
-
throw new ParseError(spaceTrim(`
|
|
10009
|
+
throw new ParseError(spaceTrim$1(`
|
|
8023
10010
|
Redefinition of MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}"
|
|
8024
10011
|
|
|
8025
10012
|
You have used:
|
|
@@ -8029,7 +10016,7 @@ const modelCommandParser = {
|
|
|
8029
10016
|
}
|
|
8030
10017
|
}
|
|
8031
10018
|
if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
|
|
8032
|
-
console.log(spaceTrim(`
|
|
10019
|
+
console.log(spaceTrim$1(`
|
|
8033
10020
|
Setting MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}" to the same value as in the pipeline head
|
|
8034
10021
|
|
|
8035
10022
|
In pipeline head:
|
|
@@ -8112,7 +10099,7 @@ const parameterCommandParser = {
|
|
|
8112
10099
|
// <- TODO: When [🥶] fixed, change to:
|
|
8113
10100
|
// > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
|
|
8114
10101
|
if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
|
|
8115
|
-
throw new ParseError(spaceTrim((block) => `
|
|
10102
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
8116
10103
|
Parameter \`{${parameterNameRaw}}\` can not contain another parameter in description
|
|
8117
10104
|
|
|
8118
10105
|
The description:
|
|
@@ -8294,7 +10281,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
|
8294
10281
|
persona.description = personaDescription;
|
|
8295
10282
|
return;
|
|
8296
10283
|
}
|
|
8297
|
-
console.warn(spaceTrim(`
|
|
10284
|
+
console.warn(spaceTrim$1(`
|
|
8298
10285
|
|
|
8299
10286
|
Persona "${personaName}" is defined multiple times with different description:
|
|
8300
10287
|
|
|
@@ -8305,7 +10292,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
|
|
|
8305
10292
|
${personaDescription}
|
|
8306
10293
|
|
|
8307
10294
|
`));
|
|
8308
|
-
persona.description += spaceTrim('\n\n' + personaDescription);
|
|
10295
|
+
persona.description += spaceTrim$1('\n\n' + personaDescription);
|
|
8309
10296
|
}
|
|
8310
10297
|
|
|
8311
10298
|
/**
|
|
@@ -8670,7 +10657,7 @@ const COMMANDS = [
|
|
|
8670
10657
|
function getParserForCommand(command) {
|
|
8671
10658
|
const commandParser = COMMANDS.find((commandParser) => commandParser.name === command.type);
|
|
8672
10659
|
if (commandParser === undefined) {
|
|
8673
|
-
throw new UnexpectedError(spaceTrim
|
|
10660
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
8674
10661
|
Command ${command.type} parser is not found
|
|
8675
10662
|
|
|
8676
10663
|
${block(JSON.stringify(command, null, 4)
|
|
@@ -8746,7 +10733,7 @@ function parseCommand(raw, usagePlace) {
|
|
|
8746
10733
|
.map(removeMarkdownFormatting)
|
|
8747
10734
|
.map((item) => item.trim());
|
|
8748
10735
|
if (items.length === 0 || items[0] === '') {
|
|
8749
|
-
throw new ParseError(spaceTrim
|
|
10736
|
+
throw new ParseError(spaceTrim((block) => `
|
|
8750
10737
|
Malformed command:
|
|
8751
10738
|
- ${raw}
|
|
8752
10739
|
|
|
@@ -8782,7 +10769,7 @@ function parseCommand(raw, usagePlace) {
|
|
|
8782
10769
|
return command;
|
|
8783
10770
|
}
|
|
8784
10771
|
}
|
|
8785
|
-
throw new ParseError(spaceTrim
|
|
10772
|
+
throw new ParseError(spaceTrim((block) => `
|
|
8786
10773
|
Malformed or unknown command:
|
|
8787
10774
|
- ${raw}
|
|
8788
10775
|
|
|
@@ -8833,7 +10820,7 @@ function parseCommandVariant(input) {
|
|
|
8833
10820
|
if (!(error instanceof ParseError)) {
|
|
8834
10821
|
throw error;
|
|
8835
10822
|
}
|
|
8836
|
-
throw new ParseError(spaceTrim
|
|
10823
|
+
throw new ParseError(spaceTrim((block) => `
|
|
8837
10824
|
Invalid ${commandName} command:
|
|
8838
10825
|
|
|
8839
10826
|
Your command:
|
|
@@ -9107,7 +11094,7 @@ const SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
|
|
|
9107
11094
|
* @public exported from `@promptbook/markdown-utils`
|
|
9108
11095
|
*/
|
|
9109
11096
|
function removeMarkdownComments(content) {
|
|
9110
|
-
return spaceTrim
|
|
11097
|
+
return spaceTrim(content.replace(/<!--(.*?)-->/gs, ''));
|
|
9111
11098
|
}
|
|
9112
11099
|
|
|
9113
11100
|
/**
|
|
@@ -9118,7 +11105,7 @@ function removeMarkdownComments(content) {
|
|
|
9118
11105
|
*/
|
|
9119
11106
|
function isFlatPipeline(pipelineString) {
|
|
9120
11107
|
pipelineString = removeMarkdownComments(pipelineString);
|
|
9121
|
-
pipelineString = spaceTrim(pipelineString);
|
|
11108
|
+
pipelineString = spaceTrim$1(pipelineString);
|
|
9122
11109
|
const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
|
|
9123
11110
|
//const isLastLineReturnStatement = pipelineString.split('\n').pop()!.split('`').join('').startsWith('->');
|
|
9124
11111
|
const isBacktickBlockUsed = pipelineString.includes('```');
|
|
@@ -9156,19 +11143,19 @@ function deflatePipeline(pipelineString) {
|
|
|
9156
11143
|
returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
|
|
9157
11144
|
pipelineStringLines.push(potentialReturnStatement);
|
|
9158
11145
|
}
|
|
9159
|
-
const prompt = spaceTrim(pipelineStringLines.join('\n'));
|
|
11146
|
+
const prompt = spaceTrim$1(pipelineStringLines.join('\n'));
|
|
9160
11147
|
let quotedPrompt;
|
|
9161
11148
|
if (prompt.split('\n').length <= 1) {
|
|
9162
11149
|
quotedPrompt = `> ${prompt}`;
|
|
9163
11150
|
}
|
|
9164
11151
|
else {
|
|
9165
|
-
quotedPrompt = spaceTrim((block) => `
|
|
11152
|
+
quotedPrompt = spaceTrim$1((block) => `
|
|
9166
11153
|
\`\`\`
|
|
9167
11154
|
${block(prompt.split('`').join('\\`'))}
|
|
9168
11155
|
\`\`\`
|
|
9169
11156
|
`);
|
|
9170
11157
|
}
|
|
9171
|
-
pipelineString = validatePipelineString(spaceTrim((block) => `
|
|
11158
|
+
pipelineString = validatePipelineString(spaceTrim$1((block) => `
|
|
9172
11159
|
# ${DEFAULT_BOOK_TITLE}
|
|
9173
11160
|
|
|
9174
11161
|
## Prompt
|
|
@@ -9232,7 +11219,7 @@ function extractAllListItemsFromMarkdown(markdown) {
|
|
|
9232
11219
|
function extractOneBlockFromMarkdown(markdown) {
|
|
9233
11220
|
const codeBlocks = extractAllBlocksFromMarkdown(markdown);
|
|
9234
11221
|
if (codeBlocks.length !== 1) {
|
|
9235
|
-
throw new ParseError(spaceTrim((block) => `
|
|
11222
|
+
throw new ParseError(spaceTrim$1((block) => `
|
|
9236
11223
|
There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
|
|
9237
11224
|
|
|
9238
11225
|
${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
|
|
@@ -9257,7 +11244,7 @@ function parseMarkdownSection(value) {
|
|
|
9257
11244
|
}
|
|
9258
11245
|
const title = lines[0].replace(/^#+\s*/, '');
|
|
9259
11246
|
const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
|
|
9260
|
-
const content = spaceTrim(lines.slice(1).join('\n'));
|
|
11247
|
+
const content = spaceTrim$1(lines.slice(1).join('\n'));
|
|
9261
11248
|
if (level < 1 || level > 6) {
|
|
9262
11249
|
throw new ParseError('Markdown section must have heading level between 1 and 6');
|
|
9263
11250
|
}
|
|
@@ -9285,7 +11272,7 @@ function splitMarkdownIntoSections(markdown) {
|
|
|
9285
11272
|
if (buffer.length === 0) {
|
|
9286
11273
|
return;
|
|
9287
11274
|
}
|
|
9288
|
-
let section = spaceTrim(buffer.join('\n'));
|
|
11275
|
+
let section = spaceTrim$1(buffer.join('\n'));
|
|
9289
11276
|
if (section === '') {
|
|
9290
11277
|
return;
|
|
9291
11278
|
}
|
|
@@ -9360,7 +11347,7 @@ function flattenMarkdown(markdown) {
|
|
|
9360
11347
|
flattenedMarkdown += `## ${title}` + `\n\n`;
|
|
9361
11348
|
flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
|
|
9362
11349
|
}
|
|
9363
|
-
return spaceTrim(flattenedMarkdown);
|
|
11350
|
+
return spaceTrim$1(flattenedMarkdown);
|
|
9364
11351
|
}
|
|
9365
11352
|
/**
|
|
9366
11353
|
* TODO: [🏛] This can be part of markdown builder
|
|
@@ -9422,7 +11409,7 @@ function parsePipeline(pipelineString) {
|
|
|
9422
11409
|
if (pipelineString.startsWith('#!')) {
|
|
9423
11410
|
const [shebangLine, ...restLines] = pipelineString.split('\n');
|
|
9424
11411
|
if (!(shebangLine || '').includes('ptbk')) {
|
|
9425
|
-
throw new ParseError(spaceTrim
|
|
11412
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9426
11413
|
It seems that you try to parse a book file which has non-standard shebang line for book files:
|
|
9427
11414
|
Shebang line must contain 'ptbk'
|
|
9428
11415
|
|
|
@@ -9438,7 +11425,7 @@ function parsePipeline(pipelineString) {
|
|
|
9438
11425
|
pipelineString = validatePipelineString(restLines.join('\n'));
|
|
9439
11426
|
}
|
|
9440
11427
|
pipelineString = removeMarkdownComments(pipelineString);
|
|
9441
|
-
pipelineString = spaceTrim
|
|
11428
|
+
pipelineString = spaceTrim(pipelineString);
|
|
9442
11429
|
// <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
|
|
9443
11430
|
pipelineString = deflatePipeline(pipelineString);
|
|
9444
11431
|
// ==============
|
|
@@ -9450,7 +11437,7 @@ function parsePipeline(pipelineString) {
|
|
|
9450
11437
|
// ==============
|
|
9451
11438
|
// Note: 1️⃣◽4️⃣ Check markdown structure
|
|
9452
11439
|
if (pipelineHead === undefined) {
|
|
9453
|
-
throw new UnexpectedError(spaceTrim
|
|
11440
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
9454
11441
|
Pipeline head is not defined
|
|
9455
11442
|
|
|
9456
11443
|
${block(getPipelineIdentification())}
|
|
@@ -9459,7 +11446,7 @@ function parsePipeline(pipelineString) {
|
|
|
9459
11446
|
`));
|
|
9460
11447
|
}
|
|
9461
11448
|
if (pipelineHead.level !== 1) {
|
|
9462
|
-
throw new UnexpectedError(spaceTrim
|
|
11449
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
9463
11450
|
Pipeline head is not h1
|
|
9464
11451
|
|
|
9465
11452
|
${block(getPipelineIdentification())}
|
|
@@ -9468,7 +11455,7 @@ function parsePipeline(pipelineString) {
|
|
|
9468
11455
|
`));
|
|
9469
11456
|
}
|
|
9470
11457
|
if (!pipelineSections.every((section) => section.level === 2)) {
|
|
9471
|
-
throw new UnexpectedError(spaceTrim
|
|
11458
|
+
throw new UnexpectedError(spaceTrim((block) => `
|
|
9472
11459
|
Not every pipeline section is h2
|
|
9473
11460
|
|
|
9474
11461
|
${block(getPipelineIdentification())}
|
|
@@ -9481,7 +11468,7 @@ function parsePipeline(pipelineString) {
|
|
|
9481
11468
|
const defineParam = (parameterCommand) => {
|
|
9482
11469
|
const { parameterName, parameterDescription, isInput, isOutput } = parameterCommand;
|
|
9483
11470
|
if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
|
|
9484
|
-
throw new ParseError(spaceTrim
|
|
11471
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9485
11472
|
Parameter name {${parameterName}} is reserved and cannot be used as resulting parameter name
|
|
9486
11473
|
|
|
9487
11474
|
${block(getPipelineIdentification())}
|
|
@@ -9492,7 +11479,7 @@ function parsePipeline(pipelineString) {
|
|
|
9492
11479
|
existingParameter.description &&
|
|
9493
11480
|
existingParameter.description !== parameterDescription &&
|
|
9494
11481
|
parameterDescription) {
|
|
9495
|
-
throw new ParseError(spaceTrim
|
|
11482
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9496
11483
|
Parameter \`{${parameterName}}\` is defined multiple times with different description:
|
|
9497
11484
|
|
|
9498
11485
|
${block(getPipelineIdentification())}
|
|
@@ -9530,7 +11517,7 @@ function parsePipeline(pipelineString) {
|
|
|
9530
11517
|
description = description.split(/^>.*$/gm).join('');
|
|
9531
11518
|
//Note: Remove lists and return statement - TODO: [🎾] Make util (exported from `@promptbool/utils`)
|
|
9532
11519
|
description = description.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
|
|
9533
|
-
description = spaceTrim
|
|
11520
|
+
description = spaceTrim(description);
|
|
9534
11521
|
if (description === '') {
|
|
9535
11522
|
description = undefined;
|
|
9536
11523
|
}
|
|
@@ -9541,7 +11528,7 @@ function parsePipeline(pipelineString) {
|
|
|
9541
11528
|
const command = parseCommand(listItem, 'PIPELINE_HEAD');
|
|
9542
11529
|
const commandParser = getParserForCommand(command);
|
|
9543
11530
|
if (commandParser.isUsedInPipelineHead !== true /* <- Note: [🦦][4] */) {
|
|
9544
|
-
throw new ParseError(spaceTrim
|
|
11531
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9545
11532
|
Command \`${command.type}\` is not allowed in the head of the pipeline ONLY at the pipeline task
|
|
9546
11533
|
|
|
9547
11534
|
${block(getPipelineIdentification())}
|
|
@@ -9555,7 +11542,7 @@ function parsePipeline(pipelineString) {
|
|
|
9555
11542
|
if (!(error instanceof ParseError)) {
|
|
9556
11543
|
throw error;
|
|
9557
11544
|
}
|
|
9558
|
-
throw new ParseError(spaceTrim
|
|
11545
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9559
11546
|
Command ${command.type} failed to apply to the pipeline
|
|
9560
11547
|
|
|
9561
11548
|
The error:
|
|
@@ -9608,7 +11595,7 @@ function parsePipeline(pipelineString) {
|
|
|
9608
11595
|
description = description.split(/^>.*$/gm).join('');
|
|
9609
11596
|
//Note: Remove lists and return statement - TODO: [🎾]
|
|
9610
11597
|
description = description.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
|
|
9611
|
-
description = spaceTrim
|
|
11598
|
+
description = spaceTrim(description);
|
|
9612
11599
|
if (description === '') {
|
|
9613
11600
|
description = undefined;
|
|
9614
11601
|
}
|
|
@@ -9642,7 +11629,7 @@ function parsePipeline(pipelineString) {
|
|
|
9642
11629
|
for (const { listItem, command } of commands) {
|
|
9643
11630
|
const commandParser = getParserForCommand(command);
|
|
9644
11631
|
if (commandParser.isUsedInPipelineTask !== true /* <- Note: [🦦][4] */) {
|
|
9645
|
-
throw new ParseError(spaceTrim
|
|
11632
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9646
11633
|
Command \`${command.type}\` is not allowed in the task of the promptbook ONLY at the pipeline head
|
|
9647
11634
|
|
|
9648
11635
|
${block(getPipelineIdentification())}
|
|
@@ -9657,7 +11644,7 @@ function parsePipeline(pipelineString) {
|
|
|
9657
11644
|
if (!(error instanceof ParseError)) {
|
|
9658
11645
|
throw error;
|
|
9659
11646
|
}
|
|
9660
|
-
throw new ParseError(spaceTrim
|
|
11647
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9661
11648
|
Command \`${command.type}\` failed to apply to the task
|
|
9662
11649
|
|
|
9663
11650
|
The error:
|
|
@@ -9688,14 +11675,14 @@ function parsePipeline(pipelineString) {
|
|
|
9688
11675
|
// TODO: [🍧] Should be done in SECTION command
|
|
9689
11676
|
if ($taskJson.taskType === 'SCRIPT_TASK') {
|
|
9690
11677
|
if (!language) {
|
|
9691
|
-
throw new ParseError(spaceTrim
|
|
11678
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9692
11679
|
You must specify the language of the script in the \`SCRIPT\` task
|
|
9693
11680
|
|
|
9694
11681
|
${block(getPipelineIdentification())}
|
|
9695
11682
|
`));
|
|
9696
11683
|
}
|
|
9697
11684
|
if (!SUPPORTED_SCRIPT_LANGUAGES.includes(language)) {
|
|
9698
|
-
throw new ParseError(spaceTrim
|
|
11685
|
+
throw new ParseError(spaceTrim((block) => `
|
|
9699
11686
|
Script language ${language} is not supported.
|
|
9700
11687
|
|
|
9701
11688
|
Supported languages are:
|
|
@@ -9857,7 +11844,7 @@ function addAutoGeneratedSection(content, options) {
|
|
|
9857
11844
|
const warningLine = `<!-- ${GENERATOR_WARNING} -->`;
|
|
9858
11845
|
const sectionRegex = new RegExp(`<!--${sectionName}-->([\\s\\S]*?)<!--/${sectionName}-->`, 'g');
|
|
9859
11846
|
const sectionMatch = content.match(sectionRegex);
|
|
9860
|
-
const contentToInsert = spaceTrim
|
|
11847
|
+
const contentToInsert = spaceTrim((block) => `
|
|
9861
11848
|
<!--${sectionName}-->
|
|
9862
11849
|
${block(warningLine)}
|
|
9863
11850
|
${block(sectionContent)}
|
|
@@ -9870,7 +11857,7 @@ function addAutoGeneratedSection(content, options) {
|
|
|
9870
11857
|
const placeForSection = removeMarkdownComments(content).match(/^##.*$/im);
|
|
9871
11858
|
if (placeForSection !== null) {
|
|
9872
11859
|
const [heading] = placeForSection;
|
|
9873
|
-
return content.replace(heading, spaceTrim
|
|
11860
|
+
return content.replace(heading, spaceTrim((block) => `
|
|
9874
11861
|
${block(contentToInsert)}
|
|
9875
11862
|
|
|
9876
11863
|
${block(heading)}
|
|
@@ -9879,7 +11866,7 @@ function addAutoGeneratedSection(content, options) {
|
|
|
9879
11866
|
console.warn(`No place where to put the section <!--${sectionName}-->, using the end of the file`);
|
|
9880
11867
|
// <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
|
|
9881
11868
|
// <- TODO: [🏮] Some better way how to get warnings from pipeline parsing / logic
|
|
9882
|
-
return spaceTrim
|
|
11869
|
+
return spaceTrim((block) => `
|
|
9883
11870
|
${block(content)}
|
|
9884
11871
|
|
|
9885
11872
|
${block(contentToInsert)}
|
|
@@ -9955,7 +11942,7 @@ function renderPromptbookMermaid(pipelineJson, options) {
|
|
|
9955
11942
|
.filter(([MERMAID_NAME]) => (inputAndIntermediateParametersMermaid + outputParametersMermaid).includes(MERMAID_NAME))
|
|
9956
11943
|
.map(([MERMAID_NAME, title]) => `${MERMAID_NAME}((${title})):::${MERMAID_NAME}`)
|
|
9957
11944
|
.join('\n');
|
|
9958
|
-
const promptbookMermaid = spaceTrim
|
|
11945
|
+
const promptbookMermaid = spaceTrim((block) => `
|
|
9959
11946
|
|
|
9960
11947
|
%% 🔮 Tip: Open this on GitHub or in the VSCode website to see the Mermaid graph visually
|
|
9961
11948
|
|
|
@@ -10011,7 +11998,7 @@ async function prettifyPipelineString(pipelineString, options) {
|
|
|
10011
11998
|
return { href: `#${task.name}`, title: task.title };
|
|
10012
11999
|
},
|
|
10013
12000
|
});
|
|
10014
|
-
const promptbookMermaidBlock = spaceTrim
|
|
12001
|
+
const promptbookMermaidBlock = spaceTrim((block) => `
|
|
10015
12002
|
\`\`\`mermaid
|
|
10016
12003
|
${block(promptbookMermaid)}
|
|
10017
12004
|
\`\`\`
|
|
@@ -10049,7 +12036,7 @@ class CallbackInterfaceTools {
|
|
|
10049
12036
|
async promptDialog(options) {
|
|
10050
12037
|
const answer = await this.options.callback(options);
|
|
10051
12038
|
if (this.options.isVerbose) {
|
|
10052
|
-
console.info(spaceTrim
|
|
12039
|
+
console.info(spaceTrim((block) => `
|
|
10053
12040
|
📖 ${block(options.promptTitle)}
|
|
10054
12041
|
👤 ${block(answer)}
|
|
10055
12042
|
`));
|
|
@@ -10188,7 +12175,7 @@ function countWorkingDuration(items) {
|
|
|
10188
12175
|
function executionReportJsonToString(executionReportJson, options) {
|
|
10189
12176
|
var _a, _b, _c, _d, _e, _f;
|
|
10190
12177
|
const { taxRate, chartsWidth } = { ...ExecutionReportStringOptionsDefaults, ...(options || {}) };
|
|
10191
|
-
let executionReportString = spaceTrim
|
|
12178
|
+
let executionReportString = spaceTrim((block) => `
|
|
10192
12179
|
# ${executionReportJson.title || 'Execution report'}
|
|
10193
12180
|
|
|
10194
12181
|
${block(executionReportJson.description || '')}
|
|
@@ -10310,7 +12297,7 @@ function executionReportJsonToString(executionReportJson, options) {
|
|
|
10310
12297
|
if (just(true)) {
|
|
10311
12298
|
executionReportString +=
|
|
10312
12299
|
'\n\n\n\n' +
|
|
10313
|
-
spaceTrim
|
|
12300
|
+
spaceTrim((block) => {
|
|
10314
12301
|
var _a;
|
|
10315
12302
|
return `
|
|
10316
12303
|
|
|
@@ -10329,7 +12316,7 @@ function executionReportJsonToString(executionReportJson, options) {
|
|
|
10329
12316
|
executionReportString += '*No result*';
|
|
10330
12317
|
}
|
|
10331
12318
|
else if (typeof promptExecution.result.content === 'string') {
|
|
10332
|
-
executionReportString += spaceTrim
|
|
12319
|
+
executionReportString += spaceTrim((block) => `
|
|
10333
12320
|
\`\`\`
|
|
10334
12321
|
${block(escapeMarkdownBlock(promptExecution.result.content))}
|
|
10335
12322
|
\`\`\`
|
|
@@ -10342,7 +12329,7 @@ function executionReportJsonToString(executionReportJson, options) {
|
|
|
10342
12329
|
if (promptExecution.error && promptExecution.error.message) {
|
|
10343
12330
|
executionReportString +=
|
|
10344
12331
|
'\n\n\n\n' +
|
|
10345
|
-
spaceTrim
|
|
12332
|
+
spaceTrim((block) => `
|
|
10346
12333
|
|
|
10347
12334
|
### Error
|
|
10348
12335
|
|
|
@@ -10418,7 +12405,7 @@ function usageToHuman(usage) {
|
|
|
10418
12405
|
// Note: For negligible usage, we report at least something
|
|
10419
12406
|
reportItems.push('Negligible');
|
|
10420
12407
|
}
|
|
10421
|
-
return spaceTrim((block) => `
|
|
12408
|
+
return spaceTrim$1((block) => `
|
|
10422
12409
|
Usage:
|
|
10423
12410
|
${block(reportItems.map((item) => `- ${item}`).join('\n'))}
|
|
10424
12411
|
`);
|
|
@@ -10663,13 +12650,13 @@ function $registeredLlmToolsMessage() {
|
|
|
10663
12650
|
});
|
|
10664
12651
|
const usedEnvMessage = `Unknown \`.env\` file` ;
|
|
10665
12652
|
if (metadata.length === 0) {
|
|
10666
|
-
return spaceTrim((block) => `
|
|
12653
|
+
return spaceTrim$1((block) => `
|
|
10667
12654
|
No LLM providers are available.
|
|
10668
12655
|
|
|
10669
12656
|
${block(usedEnvMessage)}
|
|
10670
12657
|
`);
|
|
10671
12658
|
}
|
|
10672
|
-
return spaceTrim((block) => `
|
|
12659
|
+
return spaceTrim$1((block) => `
|
|
10673
12660
|
|
|
10674
12661
|
${block(usedEnvMessage)}
|
|
10675
12662
|
|
|
@@ -10715,7 +12702,7 @@ function $registeredLlmToolsMessage() {
|
|
|
10715
12702
|
morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
|
|
10716
12703
|
}
|
|
10717
12704
|
}
|
|
10718
|
-
let providerMessage = spaceTrim(`
|
|
12705
|
+
let providerMessage = spaceTrim$1(`
|
|
10719
12706
|
${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
|
|
10720
12707
|
${morePieces.join('; ')}
|
|
10721
12708
|
`);
|
|
@@ -10761,7 +12748,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
|
|
|
10761
12748
|
.find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
|
|
10762
12749
|
if (registeredItem === undefined) {
|
|
10763
12750
|
// console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
|
|
10764
|
-
throw new Error(spaceTrim((block) => `
|
|
12751
|
+
throw new Error(spaceTrim$1((block) => `
|
|
10765
12752
|
There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
|
|
10766
12753
|
Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
|
|
10767
12754
|
|
|
@@ -10898,7 +12885,7 @@ function cacheLlmTools(llmTools, options = {}) {
|
|
|
10898
12885
|
let normalizedContent = content;
|
|
10899
12886
|
normalizedContent = normalizedContent.replace(/\s+/g, ' ');
|
|
10900
12887
|
normalizedContent = normalizedContent.split('\r\n').join('\n');
|
|
10901
|
-
normalizedContent = spaceTrim(normalizedContent);
|
|
12888
|
+
normalizedContent = spaceTrim$1(normalizedContent);
|
|
10902
12889
|
// Note: Do not need to save everything in the cache, just the relevant parameters
|
|
10903
12890
|
const relevantParameterNames = extractParameterNames(content);
|
|
10904
12891
|
const relevantParameters = Object.fromEntries(Object.entries(parameters).filter(([key]) => relevantParameterNames.has(key)));
|
|
@@ -11578,7 +13565,7 @@ function isValidPipelineString(pipelineString) {
|
|
|
11578
13565
|
*/
|
|
11579
13566
|
function prompt(strings, ...values) {
|
|
11580
13567
|
if (values.length === 0) {
|
|
11581
|
-
return spaceTrim(strings.join(''));
|
|
13568
|
+
return spaceTrim$1(strings.join(''));
|
|
11582
13569
|
}
|
|
11583
13570
|
const stringsWithHiddenParameters = strings.map((stringsItem) =>
|
|
11584
13571
|
// TODO: [0] DRY
|
|
@@ -11589,7 +13576,7 @@ function prompt(strings, ...values) {
|
|
|
11589
13576
|
let pipelineString = stringsWithHiddenParameters.reduce((result, stringsItem, i) => placeholderParameterNames[i] === undefined
|
|
11590
13577
|
? `${result}${stringsItem}`
|
|
11591
13578
|
: `${result}${stringsItem}{${placeholderParameterNames[i]}}`, '');
|
|
11592
|
-
pipelineString = spaceTrim(pipelineString);
|
|
13579
|
+
pipelineString = spaceTrim$1(pipelineString);
|
|
11593
13580
|
try {
|
|
11594
13581
|
pipelineString = templateParameters(pipelineString, parameters);
|
|
11595
13582
|
}
|
|
@@ -11598,7 +13585,7 @@ function prompt(strings, ...values) {
|
|
|
11598
13585
|
throw error;
|
|
11599
13586
|
}
|
|
11600
13587
|
console.error({ pipelineString, parameters, placeholderParameterNames, error });
|
|
11601
|
-
throw new UnexpectedError(spaceTrim((block) => `
|
|
13588
|
+
throw new UnexpectedError(spaceTrim$1((block) => `
|
|
11602
13589
|
Internal error in prompt template literal
|
|
11603
13590
|
|
|
11604
13591
|
${block(JSON.stringify({ strings, values }, null, 4))}}
|
|
@@ -11632,18 +13619,28 @@ function prompt(strings, ...values) {
|
|
|
11632
13619
|
* @public exported from `@promptbook/core`
|
|
11633
13620
|
*/
|
|
11634
13621
|
function book(strings, ...values) {
|
|
11635
|
-
const
|
|
11636
|
-
if (!isValidPipelineString(
|
|
13622
|
+
const bookString = prompt(strings, ...values);
|
|
13623
|
+
if (!isValidPipelineString(bookString)) {
|
|
11637
13624
|
// TODO: Make the CustomError for this
|
|
11638
|
-
throw new Error(spaceTrim(`
|
|
13625
|
+
throw new Error(spaceTrim$1(`
|
|
11639
13626
|
The string is not a valid pipeline string
|
|
11640
13627
|
|
|
11641
13628
|
book\`
|
|
11642
|
-
${
|
|
13629
|
+
${bookString}
|
|
11643
13630
|
\`
|
|
11644
13631
|
`));
|
|
11645
13632
|
}
|
|
11646
|
-
|
|
13633
|
+
if (!isValidBook(bookString)) {
|
|
13634
|
+
// TODO: Make the CustomError for this
|
|
13635
|
+
throw new Error(spaceTrim$1(`
|
|
13636
|
+
The string is not a valid book
|
|
13637
|
+
|
|
13638
|
+
book\`
|
|
13639
|
+
${bookString}
|
|
13640
|
+
\`
|
|
13641
|
+
`));
|
|
13642
|
+
}
|
|
13643
|
+
return bookString;
|
|
11647
13644
|
}
|
|
11648
13645
|
/**
|
|
11649
13646
|
* TODO: [🧠][🈴] Where is the best location for this file
|
|
@@ -11973,5 +13970,5 @@ class PrefixStorage {
|
|
|
11973
13970
|
}
|
|
11974
13971
|
}
|
|
11975
13972
|
|
|
11976
|
-
export { $llmToolsMetadataRegister, $llmToolsRegister, $scrapersMetadataRegister, $scrapersRegister, ADMIN_EMAIL, ADMIN_GITHUB_NAME, AbstractFormatError, AuthenticationError, BIG_DATASET_TRESHOLD, BOOK_LANGUAGE_VERSION, BlackholeStorage, BoilerplateError, BoilerplateFormfactorDefinition, CLAIM, CLI_APP_ID, CallbackInterfaceTools, ChatbotFormfactorDefinition, CollectionError, CompletionFormfactorDefinition, CsvFormatError, CsvFormatParser, DEFAULT_BOOKS_DIRNAME, DEFAULT_BOOK_OUTPUT_PARAMETER_NAME, DEFAULT_BOOK_TITLE, DEFAULT_CSV_SETTINGS, DEFAULT_DOWNLOAD_CACHE_DIRNAME, DEFAULT_EXECUTION_CACHE_DIRNAME, DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME, DEFAULT_INTERMEDIATE_FILES_STRATEGY, DEFAULT_IS_AUTO_INSTALLED, DEFAULT_IS_VERBOSE, DEFAULT_MAX_EXECUTION_ATTEMPTS, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL, DEFAULT_MAX_PARALLEL_COUNT, DEFAULT_MAX_REQUESTS_PER_MINUTE, DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, DEFAULT_PROMPT_TASK_TITLE, DEFAULT_REMOTE_SERVER_URL, DEFAULT_SCRAPE_CACHE_DIRNAME, DEFAULT_TASK_TITLE, EXPECTATION_UNITS, EnvironmentMismatchError, ExecutionReportStringOptionsDefaults, ExpectError, FAILED_VALUE_PLACEHOLDER, FORMFACTOR_DEFINITIONS, GENERIC_PIPELINE_INTERFACE, GeneratorFormfactorDefinition, GenericFormfactorDefinition, ImageGeneratorFormfactorDefinition, KnowledgeScrapeError, LimitReachedError, MANDATORY_CSV_SETTINGS, MAX_FILENAME_LENGTH, MODEL_ORDERS, MODEL_TRUST_LEVELS, MODEL_VARIANTS, MatcherFormfactorDefinition, MemoryStorage, MissingToolsError, MultipleLlmExecutionTools, NAME, NonTaskSectionTypes, NotFoundError, NotYetImplementedError, ORDER_OF_PIPELINE_JSON, PENDING_VALUE_PLACEHOLDER, PLAYGROUND_APP_ID, PROMPTBOOK_ENGINE_VERSION, PROMPTBOOK_ERRORS, ParseError, PipelineExecutionError, PipelineLogicError, PipelineUrlError, PrefixStorage, PromptbookFetchError, REMOTE_SERVER_URLS, RESERVED_PARAMETER_NAMES, SET_IS_VERBOSE, SectionTypes, SheetsFormfactorDefinition, TaskTypes, TextFormatParser, TranslatorFormfactorDefinition, UNCERTAIN_USAGE, UNCERTAIN_ZERO_VALUE, UnexpectedError, WrappedError, ZERO_USAGE, ZERO_VALUE, _AnthropicClaudeMetadataRegistration, _AzureOpenAiMetadataRegistration, _BoilerplateScraperMetadataRegistration, _DeepseekMetadataRegistration, _DocumentScraperMetadataRegistration, _GoogleMetadataRegistration, _LegacyDocumentScraperMetadataRegistration, _MarkdownScraperMetadataRegistration, _MarkitdownScraperMetadataRegistration, _OllamaMetadataRegistration, _OpenAiAssistantMetadataRegistration, _OpenAiCompatibleMetadataRegistration, _OpenAiMetadataRegistration, _PdfScraperMetadataRegistration, _WebsiteScraperMetadataRegistration, addUsage, book, cacheLlmTools, collectionToJson, compilePipeline, computeCosineSimilarity, countUsage, createCollectionFromJson, createCollectionFromPromise, createCollectionFromUrl, createLlmToolsFromConfiguration, createPipelineExecutor, createSubcollection, embeddingVectorToString, executionReportJsonToString, extractParameterNamesFromTask, filterModels, getPipelineInterface, identificationToPromptbookToken, isPassingExpectations, isPipelineImplementingInterface, isPipelineInterfacesEqual, isPipelinePrepared, isValidPipelineString, joinLlmExecutionTools, limitTotalUsage, makeKnowledgeSourceHandler, migratePipeline, parsePipeline, pipelineJsonToString, prepareKnowledgePieces, preparePersona, preparePipeline, prettifyPipelineString, promptbookFetch, promptbookTokenToIdentification, unpreparePipeline, usageToHuman, usageToWorktime, validatePipeline, validatePipelineString };
|
|
13973
|
+
export { $llmToolsMetadataRegister, $llmToolsRegister, $scrapersMetadataRegister, $scrapersRegister, ADMIN_EMAIL, ADMIN_GITHUB_NAME, AbstractFormatError, AuthenticationError, BIG_DATASET_TRESHOLD, BOOK_LANGUAGE_VERSION, BlackholeStorage, BoilerplateError, BoilerplateFormfactorDefinition, CLAIM, CLI_APP_ID, CallbackInterfaceTools, ChatbotFormfactorDefinition, CollectionError, CompletionFormfactorDefinition, CsvFormatError, CsvFormatParser, DEFAULT_BOOK, DEFAULT_BOOKS_DIRNAME, DEFAULT_BOOK_OUTPUT_PARAMETER_NAME, DEFAULT_BOOK_TITLE, DEFAULT_CSV_SETTINGS, DEFAULT_DOWNLOAD_CACHE_DIRNAME, DEFAULT_EXECUTION_CACHE_DIRNAME, DEFAULT_GET_PIPELINE_COLLECTION_FUNCTION_NAME, DEFAULT_INTERMEDIATE_FILES_STRATEGY, DEFAULT_IS_AUTO_INSTALLED, DEFAULT_IS_VERBOSE, DEFAULT_MAX_EXECUTION_ATTEMPTS, DEFAULT_MAX_FILE_SIZE, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH, DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_TOTAL, DEFAULT_MAX_PARALLEL_COUNT, DEFAULT_MAX_REQUESTS_PER_MINUTE, DEFAULT_PIPELINE_COLLECTION_BASE_FILENAME, DEFAULT_PROMPT_TASK_TITLE, DEFAULT_REMOTE_SERVER_URL, DEFAULT_SCRAPE_CACHE_DIRNAME, DEFAULT_TASK_TITLE, EXPECTATION_UNITS, EnvironmentMismatchError, ExecutionReportStringOptionsDefaults, ExpectError, FAILED_VALUE_PLACEHOLDER, FORMFACTOR_DEFINITIONS, GENERIC_PIPELINE_INTERFACE, GeneratorFormfactorDefinition, GenericFormfactorDefinition, ImageGeneratorFormfactorDefinition, KnowledgeScrapeError, LimitReachedError, MANDATORY_CSV_SETTINGS, MAX_FILENAME_LENGTH, MODEL_ORDERS, MODEL_TRUST_LEVELS, MODEL_VARIANTS, MatcherFormfactorDefinition, MemoryStorage, MissingToolsError, MultipleLlmExecutionTools, NAME, NonTaskSectionTypes, NotFoundError, NotYetImplementedCommitmentDefinition, NotYetImplementedError, ORDER_OF_PIPELINE_JSON, PENDING_VALUE_PLACEHOLDER, PLAYGROUND_APP_ID, PROMPTBOOK_ENGINE_VERSION, PROMPTBOOK_ERRORS, ParseError, PipelineExecutionError, PipelineLogicError, PipelineUrlError, PrefixStorage, PromptbookFetchError, REMOTE_SERVER_URLS, RESERVED_PARAMETER_NAMES, SET_IS_VERBOSE, SectionTypes, SheetsFormfactorDefinition, TaskTypes, TextFormatParser, TranslatorFormfactorDefinition, UNCERTAIN_USAGE, UNCERTAIN_ZERO_VALUE, UnexpectedError, WrappedError, ZERO_USAGE, ZERO_VALUE, _AnthropicClaudeMetadataRegistration, _AzureOpenAiMetadataRegistration, _BoilerplateScraperMetadataRegistration, _DeepseekMetadataRegistration, _DocumentScraperMetadataRegistration, _GoogleMetadataRegistration, _LegacyDocumentScraperMetadataRegistration, _MarkdownScraperMetadataRegistration, _MarkitdownScraperMetadataRegistration, _OllamaMetadataRegistration, _OpenAiAssistantMetadataRegistration, _OpenAiCompatibleMetadataRegistration, _OpenAiMetadataRegistration, _PdfScraperMetadataRegistration, _WebsiteScraperMetadataRegistration, addUsage, book, cacheLlmTools, collectionToJson, compilePipeline, computeCosineSimilarity, countUsage, createAgentModelRequirements, createBasicAgentModelRequirements, createCollectionFromJson, createCollectionFromPromise, createCollectionFromUrl, createEmptyAgentModelRequirements, createLlmToolsFromConfiguration, createPipelineExecutor, createSubcollection, embeddingVectorToString, executionReportJsonToString, extractParameterNamesFromTask, filterModels, getAllCommitmentDefinitions, getAllCommitmentTypes, getCommitmentDefinition, getPipelineInterface, identificationToPromptbookToken, isCommitmentSupported, isPassingExpectations, isPipelineImplementingInterface, isPipelineInterfacesEqual, isPipelinePrepared, isValidBook, isValidPipelineString, joinLlmExecutionTools, limitTotalUsage, makeKnowledgeSourceHandler, migratePipeline, parseAgentSource, parsePipeline, pipelineJsonToString, prepareKnowledgePieces, preparePersona, preparePipeline, prettifyPipelineString, promptbookFetch, promptbookTokenToIdentification, unpreparePipeline, usageToHuman, usageToWorktime, validateBook, validatePipeline, validatePipelineString };
|
|
11977
13974
|
//# sourceMappingURL=index.es.js.map
|