@promptbook/core 0.100.0-4 → 0.100.0-41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/README.md +1 -0
  2. package/esm/index.es.js +2444 -321
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/components.index.d.ts +14 -0
  5. package/esm/typings/src/_packages/core.index.d.ts +26 -0
  6. package/esm/typings/src/_packages/types.index.d.ts +34 -0
  7. package/esm/typings/src/book-2.0/agent-source/parseAgentSource.d.ts +30 -0
  8. package/esm/typings/src/book-2.0/agent-source/parseAgentSource.test.d.ts +1 -0
  9. package/esm/typings/src/book-2.0/agent-source/string_book.d.ts +26 -0
  10. package/esm/typings/src/book-2.0/commitments/ACTION/ACTION.d.ts +38 -0
  11. package/esm/typings/src/book-2.0/commitments/FORMAT/FORMAT.d.ts +39 -0
  12. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/FrontendRAGService.d.ts +48 -0
  13. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/KNOWLEDGE.d.ts +51 -0
  14. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/RAGService.d.ts +54 -0
  15. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/BaseKnowledgeProcessor.d.ts +45 -0
  16. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/PdfProcessor.d.ts +31 -0
  17. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/ProcessorFactory.d.ts +23 -0
  18. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/processors/TextProcessor.d.ts +18 -0
  19. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/types.d.ts +56 -0
  20. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/utils/ragHelper.d.ts +34 -0
  21. package/esm/typings/src/book-2.0/commitments/META_IMAGE/META_IMAGE.d.ts +44 -0
  22. package/esm/typings/src/book-2.0/commitments/META_LINK/META_LINK.d.ts +56 -0
  23. package/esm/typings/src/book-2.0/commitments/MODEL/MODEL.d.ts +39 -0
  24. package/esm/typings/src/book-2.0/commitments/NOTE/NOTE.d.ts +49 -0
  25. package/esm/typings/src/book-2.0/commitments/PERSONA/PERSONA.d.ts +46 -0
  26. package/esm/typings/src/book-2.0/commitments/RULE/RULE.d.ts +44 -0
  27. package/esm/typings/src/book-2.0/commitments/SAMPLE/SAMPLE.d.ts +44 -0
  28. package/esm/typings/src/book-2.0/commitments/STYLE/STYLE.d.ts +38 -0
  29. package/esm/typings/src/book-2.0/commitments/_base/BaseCommitmentDefinition.d.ts +52 -0
  30. package/esm/typings/src/book-2.0/commitments/_base/BookCommitment.d.ts +5 -0
  31. package/esm/typings/src/book-2.0/commitments/_base/CommitmentDefinition.d.ts +48 -0
  32. package/esm/typings/src/book-2.0/commitments/_base/NotYetImplementedCommitmentDefinition.d.ts +22 -0
  33. package/esm/typings/src/book-2.0/commitments/_base/createEmptyAgentModelRequirements.d.ts +19 -0
  34. package/esm/typings/src/book-2.0/commitments/_misc/AgentModelRequirements.d.ts +37 -0
  35. package/esm/typings/src/book-2.0/commitments/_misc/AgentSourceParseResult.d.ts +18 -0
  36. package/esm/typings/src/book-2.0/commitments/_misc/ParsedCommitment.d.ts +22 -0
  37. package/esm/typings/src/book-2.0/commitments/_misc/createAgentModelRequirements.d.ts +61 -0
  38. package/esm/typings/src/book-2.0/commitments/_misc/createAgentModelRequirementsWithCommitments.d.ts +35 -0
  39. package/esm/typings/src/book-2.0/commitments/_misc/createCommitmentRegex.d.ts +20 -0
  40. package/esm/typings/src/book-2.0/commitments/_misc/parseAgentSourceWithCommitments.d.ts +24 -0
  41. package/esm/typings/src/book-2.0/commitments/_misc/removeCommentsFromSystemMessage.d.ts +11 -0
  42. package/esm/typings/src/book-2.0/commitments/index.d.ts +56 -0
  43. package/esm/typings/src/book-2.0/utils/profileImageUtils.d.ts +39 -0
  44. package/esm/typings/src/book-components/AvatarProfile/AvatarChip/AvatarChip.d.ts +35 -0
  45. package/esm/typings/src/book-components/AvatarProfile/AvatarChip/AvatarChipFromSource.d.ts +21 -0
  46. package/esm/typings/src/book-components/AvatarProfile/AvatarChip/index.d.ts +2 -0
  47. package/esm/typings/src/book-components/BookEditor/BookEditor.d.ts +35 -0
  48. package/esm/typings/src/book-components/BookEditor/config.d.ts +10 -0
  49. package/esm/typings/src/book-components/BookEditor/injectCssModuleIntoShadowRoot.d.ts +11 -0
  50. package/esm/typings/src/book-components/_common/react-utils/classNames.d.ts +7 -0
  51. package/esm/typings/src/book-components/_common/react-utils/collectCssTextsForClass.d.ts +7 -0
  52. package/esm/typings/src/book-components/_common/react-utils/escapeHtml.d.ts +6 -0
  53. package/esm/typings/src/book-components/_common/react-utils/escapeRegex.d.ts +6 -0
  54. package/esm/typings/src/config.d.ts +6 -0
  55. package/esm/typings/src/execution/AvailableModel.d.ts +4 -0
  56. package/esm/typings/src/execution/ExecutionTask.d.ts +27 -0
  57. package/esm/typings/src/execution/createPipelineExecutor/40-executeAttempts.d.ts +6 -1
  58. package/esm/typings/src/llm-providers/anthropic-claude/AnthropicClaudeExecutionTools.d.ts +0 -5
  59. package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  60. package/esm/typings/src/llm-providers/deepseek/deepseek-models.d.ts +1 -1
  61. package/esm/typings/src/llm-providers/google/google-models.d.ts +1 -1
  62. package/esm/typings/src/llm-providers/ollama/ollama-models.d.ts +1 -1
  63. package/esm/typings/src/llm-providers/openai/openai-models.d.ts +1 -1
  64. package/esm/typings/src/pipeline/book-notation.d.ts +2 -1
  65. package/esm/typings/src/types/ModelRequirements.d.ts +0 -2
  66. package/esm/typings/src/types/typeAliases.d.ts +6 -0
  67. package/esm/typings/src/version.d.ts +1 -1
  68. package/package.json +1 -1
  69. package/umd/index.umd.js +2341 -205
  70. package/umd/index.umd.js.map +1 -1
package/esm/index.es.js CHANGED
@@ -1,4 +1,4 @@
1
- import spaceTrim, { spaceTrim as spaceTrim$1 } from '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-4';
30
+ const PROMPTBOOK_ENGINE_VERSION = '0.100.0-41';
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
- * Converts PipelineCollection to serialized JSON
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
- * Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
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
- * @public exported from `@promptbook/core`
48
+ * @private - TODO: [🧠] Maybe should be public?
42
49
  */
43
- async function collectionToJson(collection) {
44
- const pipelineUrls = await collection.listPipelines();
45
- const promptbooks = await Promise.all(pipelineUrls.map((url) => collection.getPipelineByUrl(url)));
46
- return promptbooks;
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
- * TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
64
+ * Note: [💞] Ignore a discrepancy between file name and entity name
50
65
  */
51
66
 
52
67
  /**
53
- * Checks if value is valid email
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 isValidEmail(email) {
58
- if (typeof email !== 'string') {
59
- return false;
76
+ function $deepFreeze(objectValue) {
77
+ if (Array.isArray(objectValue)) {
78
+ return Object.freeze(objectValue.map((item) => $deepFreeze(item)));
60
79
  }
61
- if (email.split('\n').length > 1) {
62
- return false;
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
- return /^.+@.+\..+$/.test(email);
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
- * Tests if given string is valid URL.
95
+ * Generates a regex pattern to match a specific commitment
69
96
  *
70
- * Note: This does not check if the file exists only if the path is valid
71
- * @public exported from `@promptbook/utils`
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 isValidFilePath(filename) {
74
- if (typeof filename !== 'string') {
75
- return false;
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
- if (filename.split('\n').length > 1) {
78
- return false;
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
- if (filename.split(' ').length >
81
- 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
82
- return false;
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
- const filenameSlashes = filename.split('\\').join('/');
85
- // Absolute Unix path: /hello.txt
86
- if (/^(\/)/i.test(filenameSlashes)) {
87
- // console.log(filename, 'Absolute Unix path: /hello.txt');
88
- return true;
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
- // Absolute Windows path: /hello.txt
91
- if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
92
- // console.log(filename, 'Absolute Windows path: /hello.txt');
93
- return true;
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
- // Relative path: ./hello.txt
96
- if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
97
- // console.log(filename, 'Relative path: ./hello.txt');
98
- return true;
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
- // Allow paths like foo/hello
101
- if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
102
- // console.log(filename, 'Allow paths like foo/hello');
103
- return true;
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
- // Allow paths like hello.book
106
- if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
107
- // console.log(filename, 'Allow paths like hello.book');
108
- return true;
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
- * TODO: [🍏] Implement for MacOs
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
- * Tests if given string is valid URL.
274
+ * FORMAT commitment definition
118
275
  *
119
- * Note: Dataurl are considered perfectly valid.
120
- * Note: There are two similar functions:
121
- * - `isValidUrl` which tests any URL
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
- * @public exported from `@promptbook/utils`
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
- function isValidUrl(url) {
127
- if (typeof url !== 'string') {
128
- return false;
289
+ class FormatCommitmentDefinition extends BaseCommitmentDefinition {
290
+ constructor() {
291
+ super('FORMAT');
129
292
  }
130
- try {
131
- if (url.startsWith('blob:')) {
132
- url = url.replace(/^blob:/, '');
133
- }
134
- const urlObject = new URL(url /* because fail is handled */);
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
- catch (error) {
141
- return false;
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
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
355
+ * Error thrown when a fetch request fails
147
356
  *
148
357
  * @public exported from `@promptbook/core`
149
358
  */
150
- class ParseError extends Error {
359
+ class PromptbookFetchError extends Error {
151
360
  constructor(message) {
152
361
  super(message);
153
- this.name = 'ParseError';
154
- Object.setPrototypeOf(this, ParseError.prototype);
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
@@ -480,6 +686,12 @@ function SET_IS_VERBOSE(isVerbose) {
480
686
  * @public exported from `@promptbook/core`
481
687
  */
482
688
  const DEFAULT_IS_AUTO_INSTALLED = false;
689
+ /**
690
+ * Default simulated duration for a task in milliseconds (used for progress reporting)
691
+ *
692
+ * @public exported from `@promptbook/core`
693
+ */
694
+ const DEFAULT_TASK_SIMULATED_DURATION_MS = 5 * 60 * 1000; // 5 minutes
483
695
  /**
484
696
  * Function name for generated function via `ptbk make` to get the pipeline collection
485
697
  *
@@ -516,7 +728,7 @@ true);
516
728
  function getErrorReportUrl(error) {
517
729
  const report = {
518
730
  title: `🐜 Error report from ${NAME}`,
519
- body: spaceTrim((block) => `
731
+ body: spaceTrim$1((block) => `
520
732
 
521
733
 
522
734
  \`${error.name || 'Error'}\` has occurred in the [${NAME}], please look into it @${ADMIN_GITHUB_NAME}.
@@ -559,7 +771,7 @@ function getErrorReportUrl(error) {
559
771
  */
560
772
  class UnexpectedError extends Error {
561
773
  constructor(message) {
562
- super(spaceTrim$1((block) => `
774
+ super(spaceTrim((block) => `
563
775
  ${block(message)}
564
776
 
565
777
  Note: This error should not happen.
@@ -585,7 +797,7 @@ class WrappedError extends Error {
585
797
  constructor(whatWasThrown) {
586
798
  const tag = `[🤮]`;
587
799
  console.error(tag, whatWasThrown);
588
- super(spaceTrim$1(`
800
+ super(spaceTrim(`
589
801
  Non-Error object was thrown
590
802
 
591
803
  Note: Look for ${tag} in the console for more details
@@ -611,18 +823,1849 @@ function assertsError(whatWasThrown) {
611
823
  const wrappedError = whatWasThrown;
612
824
  throw wrappedError;
613
825
  }
614
- // Case 2: Handle unexpected errors
615
- if (whatWasThrown instanceof UnexpectedError) {
616
- const unexpectedError = whatWasThrown;
617
- throw unexpectedError;
826
+ // Case 2: Handle unexpected errors
827
+ if (whatWasThrown instanceof UnexpectedError) {
828
+ const unexpectedError = whatWasThrown;
829
+ throw unexpectedError;
830
+ }
831
+ // Case 3: Handle standard errors - keep them up to consumer
832
+ if (whatWasThrown instanceof Error) {
833
+ return;
834
+ }
835
+ // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
836
+ throw new WrappedError(whatWasThrown);
837
+ }
838
+
839
+ /**
840
+ * The built-in `fetch' function with a lightweight error handling wrapper as default fetch function used in Promptbook scrapers
841
+ *
842
+ * @public exported from `@promptbook/core`
843
+ */
844
+ const promptbookFetch = async (urlOrRequest, init) => {
845
+ try {
846
+ return await fetch(urlOrRequest, init);
847
+ }
848
+ catch (error) {
849
+ assertsError(error);
850
+ let url;
851
+ if (typeof urlOrRequest === 'string') {
852
+ url = urlOrRequest;
853
+ }
854
+ else if (urlOrRequest instanceof Request) {
855
+ url = urlOrRequest.url;
856
+ }
857
+ throw new PromptbookFetchError(spaceTrim$1((block) => `
858
+ Can not fetch "${url}"
859
+
860
+ Fetch error:
861
+ ${block(error.message)}
862
+
863
+ `));
864
+ }
865
+ };
866
+ /**
867
+ * TODO: [🧠] Maybe rename because it is not used only for scrapers but also in `$getCompiledBook`
868
+ */
869
+
870
+ /**
871
+ * Frontend RAG Service that uses backend APIs for processing
872
+ * This avoids Node.js dependencies in the frontend
873
+ *
874
+ * @private - TODO: [🧠] Maybe should be public?
875
+ */
876
+ class FrontendRAGService {
877
+ constructor(config) {
878
+ this.chunks = [];
879
+ this.sources = [];
880
+ this.isInitialized = false;
881
+ this.config = {
882
+ maxChunkSize: 1000,
883
+ chunkOverlap: 200,
884
+ maxRetrievedChunks: 5,
885
+ minRelevanceScore: 0.1,
886
+ ...config,
887
+ };
888
+ }
889
+ /**
890
+ * Initialize knowledge sources by processing them on the backend
891
+ */
892
+ async initializeKnowledgeSources(sources) {
893
+ if (sources.length === 0) {
894
+ this.isInitialized = true;
895
+ return;
896
+ }
897
+ try {
898
+ const response = await promptbookFetch('/api/knowledge/process-sources', {
899
+ method: 'POST',
900
+ headers: {
901
+ 'Content-Type': 'application/json',
902
+ },
903
+ body: JSON.stringify({
904
+ sources,
905
+ config: {
906
+ maxChunkSize: this.config.maxChunkSize,
907
+ chunkOverlap: this.config.chunkOverlap,
908
+ },
909
+ }),
910
+ });
911
+ if (!response.ok) {
912
+ throw new Error(`Failed to process knowledge sources: ${response.status}`);
913
+ }
914
+ const result = (await response.json());
915
+ if (!result.success) {
916
+ throw new Error(result.message || 'Failed to process knowledge sources');
917
+ }
918
+ this.chunks = result.chunks;
919
+ this.sources = sources;
920
+ this.isInitialized = true;
921
+ console.log(`Initialized RAG service with ${this.chunks.length} chunks from ${sources.length} sources`);
922
+ }
923
+ catch (error) {
924
+ console.error('Failed to initialize knowledge sources:', error);
925
+ // Don't throw - allow the system to continue without RAG
926
+ this.isInitialized = true;
927
+ }
928
+ }
929
+ /**
930
+ * Get relevant context for a user query
931
+ */
932
+ async getContextForQuery(query) {
933
+ if (!this.isInitialized) {
934
+ console.warn('RAG service not initialized');
935
+ return '';
936
+ }
937
+ if (this.chunks.length === 0) {
938
+ return '';
939
+ }
940
+ try {
941
+ const response = await promptbookFetch('/api/knowledge/retrieve-context', {
942
+ method: 'POST',
943
+ headers: {
944
+ 'Content-Type': 'application/json',
945
+ },
946
+ body: JSON.stringify({
947
+ query,
948
+ chunks: this.chunks,
949
+ config: {
950
+ maxRetrievedChunks: this.config.maxRetrievedChunks,
951
+ minRelevanceScore: this.config.minRelevanceScore,
952
+ },
953
+ }),
954
+ });
955
+ if (!response.ok) {
956
+ console.error(`Failed to retrieve context: ${response.status}`);
957
+ return '';
958
+ }
959
+ const result = (await response.json());
960
+ if (!result.success) {
961
+ console.error('Context retrieval failed:', result.message);
962
+ return '';
963
+ }
964
+ return result.context;
965
+ }
966
+ catch (error) {
967
+ console.error('Error retrieving context:', error);
968
+ return '';
969
+ }
970
+ }
971
+ /**
972
+ * Get relevant chunks for a query (for debugging/inspection)
973
+ */
974
+ async getRelevantChunks(query) {
975
+ if (!this.isInitialized || this.chunks.length === 0) {
976
+ return [];
977
+ }
978
+ try {
979
+ const response = await promptbookFetch('/api/knowledge/retrieve-context', {
980
+ method: 'POST',
981
+ headers: {
982
+ 'Content-Type': 'application/json',
983
+ },
984
+ body: JSON.stringify({
985
+ query,
986
+ chunks: this.chunks,
987
+ config: {
988
+ maxRetrievedChunks: this.config.maxRetrievedChunks,
989
+ minRelevanceScore: this.config.minRelevanceScore,
990
+ },
991
+ }),
992
+ });
993
+ if (!response.ok) {
994
+ return [];
995
+ }
996
+ const result = (await response.json());
997
+ return result.success ? result.relevantChunks : [];
998
+ }
999
+ catch (error) {
1000
+ console.error('Error retrieving relevant chunks:', error);
1001
+ return [];
1002
+ }
1003
+ }
1004
+ /**
1005
+ * Get knowledge base statistics
1006
+ */
1007
+ getStats() {
1008
+ return {
1009
+ sources: this.sources.length,
1010
+ chunks: this.chunks.length,
1011
+ isInitialized: this.isInitialized,
1012
+ };
1013
+ }
1014
+ /**
1015
+ * Check if the service is ready to use
1016
+ */
1017
+ isReady() {
1018
+ return this.isInitialized;
1019
+ }
1020
+ /**
1021
+ * Clear all knowledge sources
1022
+ */
1023
+ clearKnowledgeBase() {
1024
+ this.chunks = [];
1025
+ this.sources = [];
1026
+ this.isInitialized = false;
1027
+ }
1028
+ /**
1029
+ * Add a single knowledge source (for incremental updates)
1030
+ */
1031
+ async addKnowledgeSource(url) {
1032
+ if (this.sources.includes(url)) {
1033
+ console.log(`Knowledge source already exists: ${url}`);
1034
+ return;
1035
+ }
1036
+ try {
1037
+ const response = await promptbookFetch('/api/knowledge/process-sources', {
1038
+ method: 'POST',
1039
+ headers: {
1040
+ 'Content-Type': 'application/json',
1041
+ },
1042
+ body: JSON.stringify({
1043
+ sources: [url],
1044
+ config: {
1045
+ maxChunkSize: this.config.maxChunkSize,
1046
+ chunkOverlap: this.config.chunkOverlap,
1047
+ },
1048
+ }),
1049
+ });
1050
+ if (!response.ok) {
1051
+ throw new Error(`Failed to process knowledge source: ${response.status}`);
1052
+ }
1053
+ const result = (await response.json());
1054
+ if (!result.success) {
1055
+ throw new Error(result.message || 'Failed to process knowledge source');
1056
+ }
1057
+ // Add new chunks to existing ones
1058
+ this.chunks.push(...result.chunks);
1059
+ this.sources.push(url);
1060
+ console.log(`Added knowledge source: ${url} (${result.chunks.length} chunks)`);
1061
+ }
1062
+ catch (error) {
1063
+ console.error(`Failed to add knowledge source ${url}:`, error);
1064
+ throw error;
1065
+ }
1066
+ }
1067
+ }
1068
+
1069
+ /**
1070
+ * KNOWLEDGE commitment definition
1071
+ *
1072
+ * The KNOWLEDGE commitment adds specific knowledge, facts, or context to the agent
1073
+ * using RAG (Retrieval-Augmented Generation) approach for external sources.
1074
+ *
1075
+ * Supports both direct text knowledge and external sources like PDFs.
1076
+ *
1077
+ * Example usage in agent source:
1078
+ *
1079
+ * ```book
1080
+ * KNOWLEDGE The company was founded in 2020 and specializes in AI-powered solutions
1081
+ * KNOWLEDGE https://example.com/company-handbook.pdf
1082
+ * KNOWLEDGE https://example.com/product-documentation.pdf
1083
+ * ```
1084
+ *
1085
+ * @private [🪔] Maybe export the commitments through some package
1086
+ */
1087
+ class KnowledgeCommitmentDefinition extends BaseCommitmentDefinition {
1088
+ constructor() {
1089
+ super('KNOWLEDGE');
1090
+ this.ragService = new FrontendRAGService();
1091
+ }
1092
+ /**
1093
+ * Short one-line description of KNOWLEDGE.
1094
+ */
1095
+ get description() {
1096
+ return 'Add domain **knowledge** via direct text or external sources (RAG).';
1097
+ }
1098
+ /**
1099
+ * Markdown documentation for KNOWLEDGE commitment.
1100
+ */
1101
+ get documentation() {
1102
+ return spaceTrim(`
1103
+ # KNOWLEDGE
1104
+
1105
+ Adds specific knowledge, facts, or context to the agent using a RAG (Retrieval-Augmented Generation) approach for external sources.
1106
+
1107
+ ## Key behaviors
1108
+
1109
+ - Multiple \`KNOWLEDGE\` commitments are applied sequentially.
1110
+ - Supports both direct text knowledge and external URLs.
1111
+ - External sources (PDFs, websites) are processed via RAG for context retrieval.
1112
+
1113
+ ## Supported formats
1114
+
1115
+ - Direct text: Immediate knowledge incorporated into agent
1116
+ - URLs: External documents processed for contextual retrieval
1117
+ - Supported file types: PDF, text, markdown, HTML
1118
+
1119
+ ## Examples
1120
+
1121
+ \`\`\`book
1122
+ Customer Support Bot
1123
+
1124
+ PERSONA You are a helpful customer support agent for TechCorp
1125
+ KNOWLEDGE TechCorp was founded in 2020 and specializes in AI-powered solutions
1126
+ KNOWLEDGE https://example.com/company-handbook.pdf
1127
+ KNOWLEDGE https://example.com/product-documentation.pdf
1128
+ RULE Always be polite and professional
1129
+ \`\`\`
1130
+
1131
+ \`\`\`book
1132
+ Research Assistant
1133
+
1134
+ PERSONA You are a knowledgeable research assistant
1135
+ KNOWLEDGE Academic research requires careful citation and verification
1136
+ KNOWLEDGE https://example.com/research-guidelines.pdf
1137
+ ACTION Can help with literature reviews and data analysis
1138
+ STYLE Present information in clear, academic format
1139
+ \`\`\`
1140
+ `);
1141
+ }
1142
+ applyToAgentModelRequirements(requirements, content) {
1143
+ var _a;
1144
+ const trimmedContent = content.trim();
1145
+ if (!trimmedContent) {
1146
+ return requirements;
1147
+ }
1148
+ // Check if content is a URL (external knowledge source)
1149
+ if (this.isUrl(trimmedContent)) {
1150
+ // Store the URL for later async processing
1151
+ const updatedRequirements = {
1152
+ ...requirements,
1153
+ metadata: {
1154
+ ...requirements.metadata,
1155
+ ragService: this.ragService,
1156
+ knowledgeSources: [
1157
+ ...(((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.knowledgeSources) || []),
1158
+ trimmedContent,
1159
+ ],
1160
+ },
1161
+ };
1162
+ // Add placeholder information about knowledge sources to system message
1163
+ const knowledgeInfo = `Knowledge Source URL: ${trimmedContent} (will be processed for retrieval during chat)`;
1164
+ return this.appendToSystemMessage(updatedRequirements, knowledgeInfo, '\n\n');
1165
+ }
1166
+ else {
1167
+ // Direct text knowledge - add to system message
1168
+ const knowledgeSection = `Knowledge: ${trimmedContent}`;
1169
+ return this.appendToSystemMessage(requirements, knowledgeSection, '\n\n');
1170
+ }
1171
+ }
1172
+ /**
1173
+ * Check if content is a URL
1174
+ */
1175
+ isUrl(content) {
1176
+ try {
1177
+ new URL(content);
1178
+ return true;
1179
+ }
1180
+ catch (_a) {
1181
+ return false;
1182
+ }
1183
+ }
1184
+ /**
1185
+ * Get RAG service instance for retrieving context during chat
1186
+ */
1187
+ getRagService() {
1188
+ return this.ragService;
1189
+ }
1190
+ }
1191
+ /**
1192
+ * Singleton instance of the KNOWLEDGE commitment definition
1193
+ *
1194
+ * @private [🪔] Maybe export the commitments through some package
1195
+ */
1196
+ new KnowledgeCommitmentDefinition();
1197
+ /**
1198
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1199
+ */
1200
+
1201
+ /**
1202
+ * META IMAGE commitment definition
1203
+ *
1204
+ * The META IMAGE commitment sets the agent's avatar/profile image URL.
1205
+ * This commitment is special because it doesn't affect the system message,
1206
+ * but is handled separately in the parsing logic.
1207
+ *
1208
+ * Example usage in agent source:
1209
+ *
1210
+ * ```book
1211
+ * META IMAGE https://example.com/avatar.jpg
1212
+ * META IMAGE /assets/agent-avatar.png
1213
+ * ```
1214
+ *
1215
+ * @private [🪔] Maybe export the commitments through some package
1216
+ */
1217
+ class MetaImageCommitmentDefinition extends BaseCommitmentDefinition {
1218
+ constructor() {
1219
+ super('META IMAGE');
1220
+ }
1221
+ /**
1222
+ * Short one-line description of META IMAGE.
1223
+ */
1224
+ get description() {
1225
+ return "Set the agent's profile image URL.";
1226
+ }
1227
+ /**
1228
+ * Markdown documentation for META IMAGE commitment.
1229
+ */
1230
+ get documentation() {
1231
+ return spaceTrim(`
1232
+ # META IMAGE
1233
+
1234
+ Sets the agent's avatar/profile image URL.
1235
+
1236
+ ## Key behaviors
1237
+
1238
+ - Does not modify the agent's behavior or responses.
1239
+ - Only one \`META IMAGE\` should be used per agent.
1240
+ - If multiple are specified, the last one takes precedence.
1241
+ - Used for visual representation in user interfaces.
1242
+
1243
+ ## Examples
1244
+
1245
+ \`\`\`book
1246
+ Professional Assistant
1247
+
1248
+ META IMAGE https://example.com/professional-avatar.jpg
1249
+ PERSONA You are a professional business assistant
1250
+ STYLE Maintain a formal and courteous tone
1251
+ \`\`\`
1252
+
1253
+ \`\`\`book
1254
+ Creative Helper
1255
+
1256
+ META IMAGE /assets/creative-bot-avatar.png
1257
+ PERSONA You are a creative and inspiring assistant
1258
+ STYLE Be enthusiastic and encouraging
1259
+ ACTION Can help with brainstorming and ideation
1260
+ \`\`\`
1261
+ `);
1262
+ }
1263
+ applyToAgentModelRequirements(requirements, content) {
1264
+ // META IMAGE doesn't modify the system message or model requirements
1265
+ // It's handled separately in the parsing logic for profile image extraction
1266
+ // This method exists for consistency with the CommitmentDefinition interface
1267
+ return requirements;
1268
+ }
1269
+ /**
1270
+ * Extracts the profile image URL from the content
1271
+ * This is used by the parsing logic
1272
+ */
1273
+ extractProfileImageUrl(content) {
1274
+ const trimmedContent = content.trim();
1275
+ return trimmedContent || null;
1276
+ }
1277
+ }
1278
+ /**
1279
+ * Singleton instance of the META IMAGE commitment definition
1280
+ *
1281
+ * @private [🪔] Maybe export the commitments through some package
1282
+ */
1283
+ new MetaImageCommitmentDefinition();
1284
+ /**
1285
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1286
+ */
1287
+
1288
+ /**
1289
+ * META LINK commitment definition
1290
+ *
1291
+ * The `META LINK` commitment represents the link to the person from whom the agent is created.
1292
+ * This commitment is special because it doesn't affect the system message,
1293
+ * but is handled separately in the parsing logic for profile display.
1294
+ *
1295
+ * Example usage in agent source:
1296
+ *
1297
+ * ```
1298
+ * META LINK https://twitter.com/username
1299
+ * META LINK https://linkedin.com/in/profile
1300
+ * META LINK https://github.com/username
1301
+ * ```
1302
+ *
1303
+ * Multiple `META LINK` commitments can be used when there are multiple sources:
1304
+ *
1305
+ * ```book
1306
+ * META LINK https://twitter.com/username
1307
+ * META LINK https://linkedin.com/in/profile
1308
+ * ```
1309
+ *
1310
+ * @private [🪔] Maybe export the commitments through some package
1311
+ */
1312
+ class MetaLinkCommitmentDefinition extends BaseCommitmentDefinition {
1313
+ constructor() {
1314
+ super('META LINK');
1315
+ }
1316
+ /**
1317
+ * Short one-line description of META LINK.
1318
+ */
1319
+ get description() {
1320
+ return 'Provide profile/source links for the person the agent models.';
1321
+ }
1322
+ /**
1323
+ * Markdown documentation for META LINK commitment.
1324
+ */
1325
+ get documentation() {
1326
+ return spaceTrim(`
1327
+ # META LINK
1328
+
1329
+ Represents a profile or source link for the person the agent is modeled after.
1330
+
1331
+ ## Key behaviors
1332
+
1333
+ - Does not modify the agent's behavior or responses.
1334
+ - Multiple \`META LINK\` commitments can be used for different social profiles.
1335
+ - Used for attribution and crediting the original person.
1336
+ - Displayed in user interfaces for transparency.
1337
+
1338
+ ## Examples
1339
+
1340
+ \`\`\`book
1341
+ Expert Consultant
1342
+
1343
+ META LINK https://twitter.com/expertname
1344
+ META LINK https://linkedin.com/in/expertprofile
1345
+ PERSONA You are Dr. Smith, a renowned expert in artificial intelligence
1346
+ KNOWLEDGE Extensive background in machine learning and neural networks
1347
+ \`\`\`
1348
+
1349
+ \`\`\`book
1350
+ Open Source Developer
1351
+
1352
+ META LINK https://github.com/developer
1353
+ META LINK https://twitter.com/devhandle
1354
+ PERSONA You are an experienced open source developer
1355
+ ACTION Can help with code reviews and architecture decisions
1356
+ STYLE Be direct and technical in explanations
1357
+ \`\`\`
1358
+ `);
1359
+ }
1360
+ applyToAgentModelRequirements(requirements, content) {
1361
+ // META LINK doesn't modify the system message or model requirements
1362
+ // It's handled separately in the parsing logic for profile link extraction
1363
+ // This method exists for consistency with the CommitmentDefinition interface
1364
+ return requirements;
1365
+ }
1366
+ /**
1367
+ * Extracts the profile link URL from the content
1368
+ * This is used by the parsing logic
1369
+ */
1370
+ extractProfileLinkUrl(content) {
1371
+ const trimmedContent = content.trim();
1372
+ return trimmedContent || null;
1373
+ }
1374
+ /**
1375
+ * Validates if the provided content is a valid URL
1376
+ */
1377
+ isValidUrl(content) {
1378
+ try {
1379
+ new URL(content.trim());
1380
+ return true;
1381
+ }
1382
+ catch (_a) {
1383
+ return false;
1384
+ }
1385
+ }
1386
+ }
1387
+ /**
1388
+ * Singleton instance of the META LINK commitment definition
1389
+ *
1390
+ * @private [🪔] Maybe export the commitments through some package
1391
+ */
1392
+ new MetaLinkCommitmentDefinition();
1393
+ /**
1394
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1395
+ */
1396
+
1397
+ /**
1398
+ * MODEL commitment definition
1399
+ *
1400
+ * The MODEL commitment specifies which AI model to use and can also set
1401
+ * model-specific parameters like temperature, topP, and topK.
1402
+ *
1403
+ * Example usage in agent source:
1404
+ *
1405
+ * ```book
1406
+ * MODEL gpt-4
1407
+ * MODEL claude-3-opus temperature=0.3
1408
+ * MODEL gpt-3.5-turbo temperature=0.8 topP=0.9
1409
+ * ```
1410
+ *
1411
+ * @private [🪔] Maybe export the commitments through some package
1412
+ */
1413
+ class ModelCommitmentDefinition extends BaseCommitmentDefinition {
1414
+ constructor() {
1415
+ super('MODEL');
1416
+ }
1417
+ /**
1418
+ * Short one-line description of MODEL.
1419
+ */
1420
+ get description() {
1421
+ return 'Select the AI model and optional decoding parameters.';
1422
+ }
1423
+ /**
1424
+ * Markdown documentation for MODEL commitment.
1425
+ */
1426
+ get documentation() {
1427
+ return spaceTrim(`
1428
+ # MODEL
1429
+
1430
+ Specifies which AI model to use and optional decoding parameters.
1431
+
1432
+ ## Key behaviors
1433
+
1434
+ - Only one \`MODEL\` commitment should be used per agent.
1435
+ - If multiple are specified, the last one takes precedence.
1436
+ - Parameters control the randomness and creativity of responses.
1437
+
1438
+ ## Supported parameters
1439
+
1440
+ - \`temperature\`: Controls randomness (0.0 = deterministic, 1.0+ = creative)
1441
+ - \`topP\` (aka \`top_p\`): Nucleus sampling parameter
1442
+ - \`topK\` (aka \`top_k\`): Top-k sampling parameter
1443
+
1444
+ ## Examples
1445
+
1446
+ \`\`\`book
1447
+ Precise Assistant
1448
+
1449
+ PERSONA You are a precise and accurate assistant
1450
+ MODEL gpt-4 temperature=0.1
1451
+ RULE Always provide factual information
1452
+ \`\`\`
1453
+
1454
+ \`\`\`book
1455
+ Creative Writer
1456
+
1457
+ PERSONA You are a creative writing assistant
1458
+ MODEL claude-3-opus temperature=0.8 topP=0.9
1459
+ STYLE Be imaginative and expressive
1460
+ ACTION Can help with storytelling and character development
1461
+ \`\`\`
1462
+ `);
1463
+ }
1464
+ applyToAgentModelRequirements(requirements, content) {
1465
+ const trimmedContent = content.trim();
1466
+ if (!trimmedContent) {
1467
+ return requirements;
1468
+ }
1469
+ // Parse the model specification
1470
+ const parts = trimmedContent.split(/\s+/);
1471
+ const modelName = parts[0];
1472
+ if (!modelName) {
1473
+ return requirements;
1474
+ }
1475
+ // Start with the model name
1476
+ const updatedRequirements = {
1477
+ ...requirements,
1478
+ modelName,
1479
+ };
1480
+ // Parse additional parameters
1481
+ const result = { ...updatedRequirements };
1482
+ for (let i = 1; i < parts.length; i++) {
1483
+ const param = parts[i];
1484
+ if (param && param.includes('=')) {
1485
+ const [key, value] = param.split('=');
1486
+ if (key && value) {
1487
+ const numValue = parseFloat(value);
1488
+ if (!isNaN(numValue)) {
1489
+ switch (key.toLowerCase()) {
1490
+ case 'temperature':
1491
+ result.temperature = numValue;
1492
+ break;
1493
+ case 'topp':
1494
+ case 'top_p':
1495
+ result.topP = numValue;
1496
+ break;
1497
+ case 'topk':
1498
+ case 'top_k':
1499
+ result.topK = Math.round(numValue);
1500
+ break;
1501
+ }
1502
+ }
1503
+ }
1504
+ }
1505
+ }
1506
+ return result;
1507
+ }
1508
+ }
1509
+ /**
1510
+ * Singleton instance of the MODEL commitment definition
1511
+ *
1512
+ * @private [🪔] Maybe export the commitments through some package
1513
+ */
1514
+ new ModelCommitmentDefinition();
1515
+ /**
1516
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1517
+ */
1518
+
1519
+ /**
1520
+ * NOTE commitment definition
1521
+ *
1522
+ * The NOTE commitment is used to add comments to the agent source without making any changes
1523
+ * to the system message or agent model requirements. It serves as a documentation mechanism
1524
+ * for developers to add explanatory comments, reminders, or annotations directly in the agent source.
1525
+ *
1526
+ * Key features:
1527
+ * - Makes no changes to the system message
1528
+ * - Makes no changes to agent model requirements
1529
+ * - Content is preserved in metadata.NOTE for debugging and inspection
1530
+ * - Multiple NOTE commitments are aggregated together
1531
+ * - Comments (# NOTE) are removed from the final system message
1532
+ *
1533
+ * Example usage in agent source:
1534
+ *
1535
+ * ```book
1536
+ * NOTE This agent was designed for customer support scenarios
1537
+ * NOTE Remember to update the knowledge base monthly
1538
+ * NOTE Performance optimized for quick response times
1539
+ * ```
1540
+ *
1541
+ * The above notes will be stored in metadata but won't affect the agent's behavior.
1542
+ *
1543
+ * @private [🪔] Maybe export the commitments through some package
1544
+ */
1545
+ class NoteCommitmentDefinition extends BaseCommitmentDefinition {
1546
+ constructor() {
1547
+ super('NOTE');
1548
+ }
1549
+ /**
1550
+ * Short one-line description of NOTE.
1551
+ */
1552
+ get description() {
1553
+ return 'Add developer-facing notes without changing behavior or output.';
1554
+ }
1555
+ /**
1556
+ * Markdown documentation for NOTE commitment.
1557
+ */
1558
+ get documentation() {
1559
+ return spaceTrim(`
1560
+ # NOTE
1561
+
1562
+ Adds comments for documentation without changing agent behavior.
1563
+
1564
+ ## Key behaviors
1565
+
1566
+ - Does not modify the agent's behavior or responses.
1567
+ - Multiple \`NOTE\` commitments are aggregated for debugging.
1568
+ - Useful for documenting design decisions and reminders.
1569
+ - Content is preserved in metadata for inspection.
1570
+
1571
+ ## Examples
1572
+
1573
+ \`\`\`book
1574
+ Customer Support Bot
1575
+
1576
+ NOTE This agent was designed for customer support scenarios
1577
+ NOTE Remember to update the knowledge base monthly
1578
+ PERSONA You are a helpful customer support representative
1579
+ KNOWLEDGE Company policies and procedures
1580
+ RULE Always be polite and professional
1581
+ \`\`\`
1582
+
1583
+ \`\`\`book
1584
+ Research Assistant
1585
+
1586
+ NOTE Performance optimized for quick response times
1587
+ NOTE Uses RAG for accessing latest research papers
1588
+ PERSONA You are a knowledgeable research assistant
1589
+ ACTION Can help with literature reviews and citations
1590
+ STYLE Present information in academic format
1591
+ \`\`\`
1592
+ `);
1593
+ }
1594
+ applyToAgentModelRequirements(requirements, content) {
1595
+ var _a;
1596
+ // The NOTE commitment makes no changes to the system message or model requirements
1597
+ // It only stores the note content in metadata for documentation purposes
1598
+ const trimmedContent = content.trim();
1599
+ if (!trimmedContent) {
1600
+ return requirements;
1601
+ }
1602
+ // Get existing note content from metadata
1603
+ const existingNoteContent = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.NOTE) || '';
1604
+ // Merge the new content with existing note content
1605
+ // When multiple NOTE commitments exist, they are aggregated together
1606
+ const mergedNoteContent = existingNoteContent ? `${existingNoteContent}\n${trimmedContent}` : trimmedContent;
1607
+ // Store the merged note content in metadata for debugging and inspection
1608
+ const updatedMetadata = {
1609
+ ...requirements.metadata,
1610
+ NOTE: mergedNoteContent,
1611
+ };
1612
+ // Return requirements with updated metadata but no changes to system message
1613
+ return {
1614
+ ...requirements,
1615
+ metadata: updatedMetadata,
1616
+ };
1617
+ }
1618
+ }
1619
+ /**
1620
+ * Singleton instance of the NOTE commitment definition
1621
+ *
1622
+ * @private [🪔] Maybe export the commitments through some package
1623
+ */
1624
+ new NoteCommitmentDefinition();
1625
+ /**
1626
+ * [💞] Ignore a discrepancy between file name and entity name
1627
+ */
1628
+
1629
+ /**
1630
+ * PERSONA commitment definition
1631
+ *
1632
+ * The PERSONA commitment modifies the agent's personality and character in the system message.
1633
+ * It defines who the agent is, their background, expertise, and personality traits.
1634
+ *
1635
+ * Key features:
1636
+ * - Multiple PERSONA commitments are automatically merged into one
1637
+ * - Content is placed at the beginning of the system message
1638
+ * - Original content with comments is preserved in metadata.PERSONA
1639
+ * - Comments (# PERSONA) are removed from the final system message
1640
+ *
1641
+ * Example usage in agent source:
1642
+ *
1643
+ * ```book
1644
+ * PERSONA You are a helpful programming assistant with expertise in TypeScript and React
1645
+ * PERSONA You have deep knowledge of modern web development practices
1646
+ * ```
1647
+ *
1648
+ * The above will be merged into a single persona section at the beginning of the system message.
1649
+ *
1650
+ * @private [🪔] Maybe export the commitments through some package
1651
+ */
1652
+ class PersonaCommitmentDefinition extends BaseCommitmentDefinition {
1653
+ constructor() {
1654
+ super('PERSONA');
1655
+ }
1656
+ /**
1657
+ * Short one-line description of PERSONA.
1658
+ */
1659
+ get description() {
1660
+ return 'Define who the agent is: background, expertise, and personality.';
1661
+ }
1662
+ /**
1663
+ * Markdown documentation for PERSONA commitment.
1664
+ */
1665
+ get documentation() {
1666
+ return spaceTrim(`
1667
+ # PERSONA
1668
+
1669
+ Defines who the agent is, their background, expertise, and personality traits.
1670
+
1671
+ ## Key behaviors
1672
+
1673
+ - Multiple \`PERSONA\` commitments are merged together.
1674
+ - If they are in conflict, the last one takes precedence.
1675
+ - You can write persona content in multiple lines.
1676
+
1677
+ ## Examples
1678
+
1679
+ \`\`\`book
1680
+ Programming Assistant
1681
+
1682
+ PERSONA You are a helpful programming assistant with expertise in TypeScript and React
1683
+ PERSONA You have deep knowledge of modern web development practices
1684
+ \`\`\`
1685
+ `);
1686
+ }
1687
+ applyToAgentModelRequirements(requirements, content) {
1688
+ var _a, _b;
1689
+ // The PERSONA commitment aggregates all persona content and places it at the beginning
1690
+ const trimmedContent = content.trim();
1691
+ if (!trimmedContent) {
1692
+ return requirements;
1693
+ }
1694
+ // Get existing persona content from metadata
1695
+ const existingPersonaContent = ((_a = requirements.metadata) === null || _a === void 0 ? void 0 : _a.PERSONA) || '';
1696
+ // Merge the new content with existing persona content
1697
+ // When multiple PERSONA commitments exist, they are merged into one
1698
+ const mergedPersonaContent = existingPersonaContent
1699
+ ? `${existingPersonaContent}\n${trimmedContent}`
1700
+ : trimmedContent;
1701
+ // Store the merged persona content in metadata for debugging and inspection
1702
+ const updatedMetadata = {
1703
+ ...requirements.metadata,
1704
+ PERSONA: mergedPersonaContent,
1705
+ };
1706
+ // Get the agent name from metadata (which should contain the first line of agent source)
1707
+ // If not available, extract from current system message as fallback
1708
+ let agentName = (_b = requirements.metadata) === null || _b === void 0 ? void 0 : _b.agentName;
1709
+ if (!agentName) {
1710
+ // Fallback: extract from current system message
1711
+ const currentMessage = requirements.systemMessage.trim();
1712
+ const basicFormatMatch = currentMessage.match(/^You are (.+)$/);
1713
+ if (basicFormatMatch && basicFormatMatch[1]) {
1714
+ agentName = basicFormatMatch[1];
1715
+ }
1716
+ else {
1717
+ agentName = 'AI Agent'; // Final fallback
1718
+ }
1719
+ }
1720
+ // Remove any existing persona content from the system message
1721
+ // (this handles the case where we're processing multiple PERSONA commitments)
1722
+ const currentMessage = requirements.systemMessage.trim();
1723
+ let cleanedMessage = currentMessage;
1724
+ // Check if current message starts with persona content or is just the basic format
1725
+ const basicFormatRegex = /^You are .+$/;
1726
+ const isBasicFormat = basicFormatRegex.test(currentMessage) && !currentMessage.includes('\n');
1727
+ if (isBasicFormat) {
1728
+ // Replace the basic format entirely
1729
+ cleanedMessage = '';
1730
+ }
1731
+ else if (currentMessage.startsWith('# PERSONA')) {
1732
+ // Remove existing persona section by finding where it ends
1733
+ const lines = currentMessage.split('\n');
1734
+ let personaEndIndex = lines.length;
1735
+ // Find the end of the PERSONA section (next comment or end of message)
1736
+ for (let i = 1; i < lines.length; i++) {
1737
+ const line = lines[i].trim();
1738
+ if (line.startsWith('#') && !line.startsWith('# PERSONA')) {
1739
+ personaEndIndex = i;
1740
+ break;
1741
+ }
1742
+ }
1743
+ // Keep everything after the PERSONA section
1744
+ cleanedMessage = lines.slice(personaEndIndex).join('\n').trim();
1745
+ }
1746
+ // Create new system message with persona at the beginning
1747
+ // Format: "You are {agentName}\n{personaContent}"
1748
+ // The # PERSONA comment will be removed later by removeCommentsFromSystemMessage
1749
+ const personaSection = `# PERSONA\nYou are ${agentName}\n${mergedPersonaContent}`; // <- TODO: Use spaceTrim
1750
+ const newSystemMessage = cleanedMessage ? `${personaSection}\n\n${cleanedMessage}` : personaSection;
1751
+ return {
1752
+ ...requirements,
1753
+ systemMessage: newSystemMessage,
1754
+ metadata: updatedMetadata,
1755
+ };
1756
+ }
1757
+ }
1758
+ /**
1759
+ * Singleton instance of the PERSONA commitment definition
1760
+ *
1761
+ * @private [🪔] Maybe export the commitments through some package
1762
+ */
1763
+ new PersonaCommitmentDefinition();
1764
+ /**
1765
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1766
+ */
1767
+
1768
+ /**
1769
+ * RULE commitment definition
1770
+ *
1771
+ * The RULE/RULES commitment adds behavioral constraints and guidelines that the agent must follow.
1772
+ * These are specific instructions about what the agent should or shouldn't do.
1773
+ *
1774
+ * Example usage in agent source:
1775
+ *
1776
+ * ```book
1777
+ * RULE Always ask for clarification if the user's request is ambiguous
1778
+ * RULES Never provide medical advice, always refer to healthcare professionals
1779
+ * ```
1780
+ *
1781
+ * @private [🪔] Maybe export the commitments through some package
1782
+ */
1783
+ class RuleCommitmentDefinition extends BaseCommitmentDefinition {
1784
+ constructor(type = 'RULE') {
1785
+ super(type);
1786
+ }
1787
+ /**
1788
+ * Short one-line description of RULE/RULES.
1789
+ */
1790
+ get description() {
1791
+ return 'Add behavioral rules the agent must follow.';
1792
+ }
1793
+ /**
1794
+ * Markdown documentation for RULE/RULES commitment.
1795
+ */
1796
+ get documentation() {
1797
+ return spaceTrim(`
1798
+ # ${this.type}
1799
+
1800
+ Adds behavioral constraints and guidelines that the agent must follow.
1801
+
1802
+ ## Key behaviors
1803
+
1804
+ - Multiple \`RULE\` and \`RULES\` commitments are applied sequentially.
1805
+ - All rules are treated equally regardless of singular/plural form.
1806
+ - Rules define what the agent must or must not do.
1807
+
1808
+ ## Examples
1809
+
1810
+ \`\`\`book
1811
+ Customer Support Agent
1812
+
1813
+ PERSONA You are a helpful customer support representative
1814
+ RULE Always ask for clarification if the user's request is ambiguous
1815
+ RULE Be polite and professional in all interactions
1816
+ RULES Never provide medical or legal advice
1817
+ STYLE Maintain a friendly and helpful tone
1818
+ \`\`\`
1819
+
1820
+ \`\`\`book
1821
+ Educational Tutor
1822
+
1823
+ PERSONA You are a patient and knowledgeable tutor
1824
+ RULE Break down complex concepts into simple steps
1825
+ RULE Always encourage students and celebrate their progress
1826
+ RULE If you don't know something, admit it and suggest resources
1827
+ SAMPLE When explaining math: "Let's work through this step by step..."
1828
+ \`\`\`
1829
+ `);
1830
+ }
1831
+ applyToAgentModelRequirements(requirements, content) {
1832
+ const trimmedContent = content.trim();
1833
+ if (!trimmedContent) {
1834
+ return requirements;
1835
+ }
1836
+ // Add rule to the system message
1837
+ const ruleSection = `Rule: ${trimmedContent}`;
1838
+ return this.appendToSystemMessage(requirements, ruleSection, '\n\n');
1839
+ }
1840
+ }
1841
+ /**
1842
+ * Singleton instances of the RULE commitment definitions
1843
+ *
1844
+ * @private [🪔] Maybe export the commitments through some package
1845
+ */
1846
+ new RuleCommitmentDefinition('RULE');
1847
+ /**
1848
+ * Singleton instances of the RULE commitment definitions
1849
+ *
1850
+ * @private [🪔] Maybe export the commitments through some package
1851
+ */
1852
+ new RuleCommitmentDefinition('RULES');
1853
+ /**
1854
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1855
+ */
1856
+
1857
+ /**
1858
+ * SAMPLE commitment definition
1859
+ *
1860
+ * The SAMPLE/EXAMPLE commitment provides examples of how the agent should respond
1861
+ * or behave in certain situations. These examples help guide the agent's responses.
1862
+ *
1863
+ * Example usage in agent source:
1864
+ *
1865
+ * ```book
1866
+ * SAMPLE When asked about pricing, respond: "Our basic plan starts at $10/month..."
1867
+ * EXAMPLE For code questions, always include working code snippets
1868
+ * ```
1869
+ *
1870
+ * @private [🪔] Maybe export the commitments through some package
1871
+ */
1872
+ class SampleCommitmentDefinition extends BaseCommitmentDefinition {
1873
+ constructor(type = 'SAMPLE') {
1874
+ super(type);
1875
+ }
1876
+ /**
1877
+ * Short one-line description of SAMPLE/EXAMPLE.
1878
+ */
1879
+ get description() {
1880
+ return 'Provide example responses to guide behavior.';
1881
+ }
1882
+ /**
1883
+ * Markdown documentation for SAMPLE/EXAMPLE commitment.
1884
+ */
1885
+ get documentation() {
1886
+ return spaceTrim(`
1887
+ # ${this.type}
1888
+
1889
+ Provides examples of how the agent should respond or behave in certain situations.
1890
+
1891
+ ## Key behaviors
1892
+
1893
+ - Multiple \`SAMPLE\` and \`EXAMPLE\` commitments are applied sequentially.
1894
+ - Both terms work identically and can be used interchangeably.
1895
+ - Examples help guide the agent's response patterns and style.
1896
+
1897
+ ## Examples
1898
+
1899
+ \`\`\`book
1900
+ Sales Assistant
1901
+
1902
+ PERSONA You are a knowledgeable sales representative
1903
+ SAMPLE When asked about pricing, respond: "Our basic plan starts at $10/month..."
1904
+ SAMPLE For feature comparisons, create a clear comparison table
1905
+ RULE Always be honest about limitations
1906
+ \`\`\`
1907
+
1908
+ \`\`\`book
1909
+ Code Reviewer
1910
+
1911
+ PERSONA You are an experienced software engineer
1912
+ EXAMPLE For code questions, always include working code snippets
1913
+ EXAMPLE When suggesting improvements: "Here's a more efficient approach..."
1914
+ RULE Explain the reasoning behind your suggestions
1915
+ STYLE Be constructive and encouraging in feedback
1916
+ \`\`\`
1917
+ `);
1918
+ }
1919
+ applyToAgentModelRequirements(requirements, content) {
1920
+ const trimmedContent = content.trim();
1921
+ if (!trimmedContent) {
1922
+ return requirements;
1923
+ }
1924
+ // Add example to the system message
1925
+ const exampleSection = `Example: ${trimmedContent}`;
1926
+ return this.appendToSystemMessage(requirements, exampleSection, '\n\n');
1927
+ }
1928
+ }
1929
+ /**
1930
+ * Singleton instances of the SAMPLE commitment definitions
1931
+ *
1932
+ * @private [🪔] Maybe export the commitments through some package
1933
+ */
1934
+ new SampleCommitmentDefinition('SAMPLE');
1935
+ /**
1936
+ * Singleton instances of the SAMPLE commitment definitions
1937
+ *
1938
+ * @private [🪔] Maybe export the commitments through some package
1939
+ */
1940
+ new SampleCommitmentDefinition('EXAMPLE');
1941
+ /**
1942
+ * Note: [💞] Ignore a discrepancy between file name and entity name
1943
+ */
1944
+
1945
+ /**
1946
+ * STYLE commitment definition
1947
+ *
1948
+ * The STYLE commitment defines how the agent should format and present its responses.
1949
+ * This includes tone, writing style, formatting preferences, and communication patterns.
1950
+ *
1951
+ * Example usage in agent source:
1952
+ *
1953
+ * ```book
1954
+ * STYLE Write in a professional but friendly tone, use bullet points for lists
1955
+ * STYLE Always provide code examples when explaining programming concepts
1956
+ * ```
1957
+ *
1958
+ * @private [🪔] Maybe export the commitments through some package
1959
+ */
1960
+ class StyleCommitmentDefinition extends BaseCommitmentDefinition {
1961
+ constructor() {
1962
+ super('STYLE');
1963
+ }
1964
+ /**
1965
+ * Short one-line description of STYLE.
1966
+ */
1967
+ get description() {
1968
+ return 'Control the tone and writing style of responses.';
1969
+ }
1970
+ /**
1971
+ * Markdown documentation for STYLE commitment.
1972
+ */
1973
+ get documentation() {
1974
+ return spaceTrim(`
1975
+ # STYLE
1976
+
1977
+ Defines how the agent should format and present its responses (tone, writing style, formatting).
1978
+
1979
+ ## Key behaviors
1980
+
1981
+ - Multiple \`STYLE\` commitments are applied sequentially.
1982
+ - Later style instructions can override earlier ones.
1983
+ - Style affects both tone and presentation format.
1984
+
1985
+ ## Examples
1986
+
1987
+ \`\`\`book
1988
+ Technical Writer
1989
+
1990
+ PERSONA You are a technical documentation expert
1991
+ STYLE Write in a professional but friendly tone, use bullet points for lists
1992
+ STYLE Always provide code examples when explaining programming concepts
1993
+ FORMAT Use markdown formatting with clear headings
1994
+ \`\`\`
1995
+
1996
+ \`\`\`book
1997
+ Creative Assistant
1998
+
1999
+ PERSONA You are a creative writing helper
2000
+ STYLE Be enthusiastic and encouraging in your responses
2001
+ STYLE Use vivid metaphors and analogies to explain concepts
2002
+ STYLE Keep responses conversational and engaging
2003
+ RULE Always maintain a positive and supportive tone
2004
+ \`\`\`
2005
+ `);
2006
+ }
2007
+ applyToAgentModelRequirements(requirements, content) {
2008
+ const trimmedContent = content.trim();
2009
+ if (!trimmedContent) {
2010
+ return requirements;
2011
+ }
2012
+ // Add style instructions to the system message
2013
+ const styleSection = `Style: ${trimmedContent}`;
2014
+ return this.appendToSystemMessage(requirements, styleSection, '\n\n');
2015
+ }
2016
+ }
2017
+ /**
2018
+ * Singleton instance of the STYLE commitment definition
2019
+ *
2020
+ * @private [🪔] Maybe export the commitments through some package
2021
+ */
2022
+ new StyleCommitmentDefinition();
2023
+ /**
2024
+ * [💞] Ignore a discrepancy between file name and entity name
2025
+ */
2026
+
2027
+ /**
2028
+ * Placeholder commitment definition for commitments that are not yet implemented
2029
+ *
2030
+ * This commitment simply adds its content 1:1 into the system message,
2031
+ * preserving the original behavior until proper implementation is added.
2032
+ *
2033
+ * @public exported from `@promptbook/core`
2034
+ */
2035
+ class NotYetImplementedCommitmentDefinition extends BaseCommitmentDefinition {
2036
+ constructor(type) {
2037
+ super(type);
2038
+ }
2039
+ /**
2040
+ * Short one-line description of a placeholder commitment.
2041
+ */
2042
+ get description() {
2043
+ return 'Placeholder commitment that appends content verbatim to the system message.';
2044
+ }
2045
+ /**
2046
+ * Markdown documentation available at runtime.
2047
+ */
2048
+ get documentation() {
2049
+ return spaceTrim(`
2050
+ # ${this.type}
2051
+
2052
+ This commitment is not yet fully implemented.
2053
+
2054
+ ## Key behaviors
2055
+
2056
+ - Content is appended directly to the system message.
2057
+ - No special processing or validation is performed.
2058
+ - Behavior preserved until proper implementation is added.
2059
+
2060
+ ## Status
2061
+
2062
+ - **Status:** Placeholder implementation
2063
+ - **Effect:** Appends content prefixed by commitment type
2064
+ - **Future:** Will be replaced with specialized logic
2065
+
2066
+ ## Examples
2067
+
2068
+ \`\`\`book
2069
+ Example Agent
2070
+
2071
+ PERSONA You are a helpful assistant
2072
+ ${this.type} Your content here
2073
+ RULE Always be helpful
2074
+ \`\`\`
2075
+ `);
2076
+ }
2077
+ applyToAgentModelRequirements(requirements, content) {
2078
+ const trimmedContent = content.trim();
2079
+ if (!trimmedContent) {
2080
+ return requirements;
2081
+ }
2082
+ // Add the commitment content 1:1 to the system message
2083
+ const commitmentLine = `${this.type} ${trimmedContent}`;
2084
+ return this.appendToSystemMessage(requirements, commitmentLine, '\n\n');
2085
+ }
2086
+ }
2087
+
2088
+ // Import all commitment definition classes
2089
+ /**
2090
+ * Registry of all available commitment definitions
2091
+ * This array contains instances of all commitment definitions
2092
+ * This is the single source of truth for all commitments in the system
2093
+ *
2094
+ * @private Use functions to access commitments instead of this array directly
2095
+ */
2096
+ const COMMITMENT_REGISTRY = [
2097
+ // Fully implemented commitments
2098
+ new PersonaCommitmentDefinition(),
2099
+ new KnowledgeCommitmentDefinition(),
2100
+ new StyleCommitmentDefinition(),
2101
+ new RuleCommitmentDefinition('RULE'),
2102
+ new RuleCommitmentDefinition('RULES'),
2103
+ new SampleCommitmentDefinition('SAMPLE'),
2104
+ new SampleCommitmentDefinition('EXAMPLE'),
2105
+ new FormatCommitmentDefinition(),
2106
+ new ModelCommitmentDefinition(),
2107
+ new ActionCommitmentDefinition(),
2108
+ new MetaImageCommitmentDefinition(),
2109
+ new MetaLinkCommitmentDefinition(),
2110
+ new NoteCommitmentDefinition(),
2111
+ // Not yet implemented commitments (using placeholder)
2112
+ new NotYetImplementedCommitmentDefinition('EXPECT'),
2113
+ new NotYetImplementedCommitmentDefinition('SCENARIO'),
2114
+ new NotYetImplementedCommitmentDefinition('SCENARIOS'),
2115
+ new NotYetImplementedCommitmentDefinition('BEHAVIOUR'),
2116
+ new NotYetImplementedCommitmentDefinition('BEHAVIOURS'),
2117
+ new NotYetImplementedCommitmentDefinition('AVOID'),
2118
+ new NotYetImplementedCommitmentDefinition('AVOIDANCE'),
2119
+ new NotYetImplementedCommitmentDefinition('GOAL'),
2120
+ new NotYetImplementedCommitmentDefinition('GOALS'),
2121
+ new NotYetImplementedCommitmentDefinition('CONTEXT'),
2122
+ ];
2123
+ /**
2124
+ * Gets a commitment definition by its type
2125
+ * @param type The commitment type to look up
2126
+ * @returns The commitment definition or null if not found
2127
+ *
2128
+ * @public exported from `@promptbook/core`
2129
+ */
2130
+ function getCommitmentDefinition(type) {
2131
+ return COMMITMENT_REGISTRY.find((commitmentDefinition) => commitmentDefinition.type === type) || null;
2132
+ }
2133
+ /**
2134
+ * Gets all available commitment definitions
2135
+ * @returns Array of all commitment definitions
2136
+ *
2137
+ * @public exported from `@promptbook/core`
2138
+ */
2139
+ function getAllCommitmentDefinitions() {
2140
+ return $deepFreeze([...COMMITMENT_REGISTRY]);
2141
+ }
2142
+ /**
2143
+ * Gets all available commitment types
2144
+ * @returns Array of all commitment types
2145
+ *
2146
+ * @public exported from `@promptbook/core`
2147
+ */
2148
+ function getAllCommitmentTypes() {
2149
+ return $deepFreeze(COMMITMENT_REGISTRY.map((commitmentDefinition) => commitmentDefinition.type));
2150
+ }
2151
+ /**
2152
+ * Checks if a commitment type is supported
2153
+ * @param type The commitment type to check
2154
+ * @returns True if the commitment type is supported
2155
+ *
2156
+ * @public exported from `@promptbook/core`
2157
+ */
2158
+ function isCommitmentSupported(type) {
2159
+ return COMMITMENT_REGISTRY.some((commitmentDefinition) => commitmentDefinition.type === type);
2160
+ }
2161
+ /**
2162
+ * TODO: !!!! Maybe create through standardized $register
2163
+ * Note: [💞] Ignore a discrepancy between file name and entity name
2164
+ */
2165
+
2166
+ /**
2167
+ * Parses agent source using the new commitment system with multiline support
2168
+ * This function replaces the hardcoded commitment parsing in the original parseAgentSource
2169
+ *
2170
+ * @private
2171
+ */
2172
+ function parseAgentSourceWithCommitments(agentSource) {
2173
+ var _a, _b, _c;
2174
+ if (!agentSource || !agentSource.trim()) {
2175
+ return {
2176
+ agentName: null,
2177
+ commitments: [],
2178
+ nonCommitmentLines: [],
2179
+ };
2180
+ }
2181
+ const lines = agentSource.split('\n');
2182
+ const agentName = (((_a = lines[0]) === null || _a === void 0 ? void 0 : _a.trim()) || null);
2183
+ const commitments = [];
2184
+ const nonCommitmentLines = [];
2185
+ // Always add the first line (agent name) to non-commitment lines
2186
+ if (lines[0] !== undefined) {
2187
+ nonCommitmentLines.push(lines[0]);
2188
+ }
2189
+ // Parse commitments with multiline support
2190
+ let currentCommitment = null;
2191
+ // Process lines starting from the second line (skip agent name)
2192
+ for (let i = 1; i < lines.length; i++) {
2193
+ const line = lines[i];
2194
+ if (line === undefined) {
2195
+ continue;
2196
+ }
2197
+ // Check if this line starts a new commitment
2198
+ let foundNewCommitment = false;
2199
+ for (const definition of COMMITMENT_REGISTRY) {
2200
+ const typeRegex = definition.createTypeRegex();
2201
+ const match = typeRegex.exec(line.trim());
2202
+ if (match && ((_b = match.groups) === null || _b === void 0 ? void 0 : _b.type)) {
2203
+ // Save the previous commitment if it exists
2204
+ if (currentCommitment) {
2205
+ const fullContent = currentCommitment.contentLines.join('\n');
2206
+ commitments.push({
2207
+ type: currentCommitment.type,
2208
+ content: spaceTrim(fullContent),
2209
+ originalLine: currentCommitment.originalStartLine,
2210
+ lineNumber: currentCommitment.startLineNumber,
2211
+ });
2212
+ }
2213
+ // Extract the initial content from the commitment line
2214
+ const fullRegex = definition.createRegex();
2215
+ const fullMatch = fullRegex.exec(line.trim());
2216
+ const initialContent = ((_c = fullMatch === null || fullMatch === void 0 ? void 0 : fullMatch.groups) === null || _c === void 0 ? void 0 : _c.contents) || '';
2217
+ // Start a new commitment
2218
+ currentCommitment = {
2219
+ type: definition.type,
2220
+ startLineNumber: i + 1,
2221
+ originalStartLine: line,
2222
+ contentLines: initialContent ? [initialContent] : [],
2223
+ };
2224
+ foundNewCommitment = true;
2225
+ break;
2226
+ }
2227
+ }
2228
+ if (!foundNewCommitment) {
2229
+ if (currentCommitment) {
2230
+ // This line belongs to the current commitment
2231
+ currentCommitment.contentLines.push(line);
2232
+ }
2233
+ else {
2234
+ // This line is not part of any commitment
2235
+ nonCommitmentLines.push(line);
2236
+ }
2237
+ }
2238
+ }
2239
+ // Don't forget to save the last commitment if it exists
2240
+ if (currentCommitment) {
2241
+ const fullContent = currentCommitment.contentLines.join('\n');
2242
+ commitments.push({
2243
+ type: currentCommitment.type,
2244
+ content: spaceTrim(fullContent),
2245
+ originalLine: currentCommitment.originalStartLine,
2246
+ lineNumber: currentCommitment.startLineNumber,
2247
+ });
2248
+ }
2249
+ return {
2250
+ agentName,
2251
+ commitments,
2252
+ nonCommitmentLines,
2253
+ };
2254
+ }
2255
+ /**
2256
+ * Extracts basic information from agent source using the new commitment system
2257
+ * This maintains compatibility with the original parseAgentSource interface
2258
+ *
2259
+ * @private
2260
+ */
2261
+ function parseAgentSourceBasicInfo(agentSource) {
2262
+ const parseResult = parseAgentSourceWithCommitments(agentSource);
2263
+ // Find PERSONA and META IMAGE commitments
2264
+ let personaDescription = null;
2265
+ let profileImageUrl;
2266
+ for (const commitment of parseResult.commitments) {
2267
+ if (commitment.type === 'PERSONA' && !personaDescription) {
2268
+ personaDescription = commitment.content;
2269
+ }
2270
+ else if (commitment.type === 'META IMAGE' && !profileImageUrl) {
2271
+ profileImageUrl = commitment.content;
2272
+ }
2273
+ }
2274
+ // Generate gravatar fallback if no profile image specified
2275
+ if (!profileImageUrl) {
2276
+ profileImageUrl = generateGravatarUrl(parseResult.agentName);
2277
+ }
2278
+ return {
2279
+ agentName: parseResult.agentName,
2280
+ personaDescription,
2281
+ profileImageUrl,
2282
+ };
2283
+ }
2284
+
2285
+ /**
2286
+ * Parses agent source string into its components
2287
+ */
2288
+ // Cache for parsed agent sources to prevent repeated parsing
2289
+ const parsedAgentSourceCache = new Map();
2290
+ /**
2291
+ * Parses basic information from agent source
2292
+ *
2293
+ * There are 2 similar functions:
2294
+ * - `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.
2295
+ * - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
2296
+ *
2297
+ * @public exported from `@promptbook/core`
2298
+ */
2299
+ function parseAgentSource(agentSource) {
2300
+ // Check if we already parsed this agent source
2301
+ if (parsedAgentSourceCache.has(agentSource)) {
2302
+ return parsedAgentSourceCache.get(agentSource);
2303
+ }
2304
+ // Use the new commitment-based parsing system
2305
+ const result = parseAgentSourceBasicInfo(agentSource);
2306
+ // Cache the result
2307
+ parsedAgentSourceCache.set(agentSource, result);
2308
+ return result;
2309
+ }
2310
+
2311
+ /**
2312
+ * Type guard to check if a string is a valid agent source
2313
+ *
2314
+ * @public exported from `@promptbook/core`
2315
+ */
2316
+ function isValidBook(value) {
2317
+ // Basic validation - agent source should have at least a name (first line)
2318
+ return typeof value === 'string' /* && value.trim().length > 0 */;
2319
+ }
2320
+ /**
2321
+ * Validates and converts a string to agent source branded type
2322
+ * This function should be used when you have a string that you know represents agent source
2323
+ * but need to convert it to the branded type for type safety
2324
+ *
2325
+ * @public exported from `@promptbook/core`
2326
+ */
2327
+ function validateBook(source) {
2328
+ if (!isValidBook(source)) {
2329
+ throw new Error('Invalid agent source: must be a string');
2330
+ }
2331
+ return source;
2332
+ }
2333
+ /**
2334
+ * Default book
2335
+ *
2336
+ * @public exported from `@promptbook/core`
2337
+ */
2338
+ const DEFAULT_BOOK = validateBook(spaceTrim$1(`
2339
+ AI Avatar
2340
+
2341
+ PERSONA A friendly AI assistant that helps you with your tasks
2342
+ `));
2343
+
2344
+ /**
2345
+ * Creates an empty/basic agent model requirements object
2346
+ * This serves as the starting point for the reduce-like pattern
2347
+ * where each commitment applies its changes to build the final requirements
2348
+ *
2349
+ * @public exported from `@promptbook/core`
2350
+ */
2351
+ function createEmptyAgentModelRequirements() {
2352
+ return {
2353
+ systemMessage: '',
2354
+ modelName: '!!!!DEFAULT_MODEL_ID',
2355
+ temperature: 0.7,
2356
+ topP: 0.9,
2357
+ topK: 50,
2358
+ };
2359
+ }
2360
+ /**
2361
+ * Creates a basic agent model requirements with just the agent name
2362
+ * This is used when we have an agent name but no commitments
2363
+ *
2364
+ * @public exported from `@promptbook/core`
2365
+ */
2366
+ function createBasicAgentModelRequirements(agentName) {
2367
+ const empty = createEmptyAgentModelRequirements();
2368
+ return {
2369
+ ...empty,
2370
+ systemMessage: `You are ${agentName || 'AI Agent'}`,
2371
+ };
2372
+ }
2373
+ /**
2374
+ * TODO: !!!! Deduplicate model requirements
2375
+ */
2376
+
2377
+ /**
2378
+ * Removes comment lines (lines starting with #) from a system message
2379
+ * This is used to clean up the final system message before sending it to the AI model
2380
+ * while preserving the original content with comments in metadata
2381
+ *
2382
+ * @param systemMessage The system message that may contain comment lines
2383
+ * @returns The system message with comment lines removed
2384
+ *
2385
+ * @private - TODO: [🧠] Maybe should be public?
2386
+ */
2387
+ function removeCommentsFromSystemMessage(systemMessage) {
2388
+ if (!systemMessage) {
2389
+ return systemMessage;
2390
+ }
2391
+ const lines = systemMessage.split('\n');
2392
+ const filteredLines = lines.filter((line) => {
2393
+ const trimmedLine = line.trim();
2394
+ // Remove lines that start with # (comments)
2395
+ return !trimmedLine.startsWith('#');
2396
+ });
2397
+ return filteredLines.join('\n').trim();
2398
+ }
2399
+
2400
+ /**
2401
+ * Creates agent model requirements using the new commitment system
2402
+ * This function uses a reduce-like pattern where each commitment applies its changes
2403
+ * to build the final requirements starting from a basic empty model
2404
+ *
2405
+ * @private
2406
+ */
2407
+ async function createAgentModelRequirementsWithCommitments(agentSource, modelName) {
2408
+ // Parse the agent source to extract commitments
2409
+ const parseResult = parseAgentSourceWithCommitments(agentSource);
2410
+ // Start with basic agent model requirements
2411
+ let requirements = createBasicAgentModelRequirements(parseResult.agentName);
2412
+ // Store the agent name in metadata so commitments can access it
2413
+ requirements = {
2414
+ ...requirements,
2415
+ metadata: {
2416
+ ...requirements.metadata,
2417
+ agentName: parseResult.agentName,
2418
+ },
2419
+ };
2420
+ // Override model name if provided
2421
+ if (modelName) {
2422
+ requirements = {
2423
+ ...requirements,
2424
+ modelName,
2425
+ };
2426
+ }
2427
+ // Apply each commitment in order using reduce-like pattern
2428
+ for (const commitment of parseResult.commitments) {
2429
+ const definition = getCommitmentDefinition(commitment.type);
2430
+ if (definition) {
2431
+ try {
2432
+ requirements = definition.applyToAgentModelRequirements(requirements, commitment.content);
2433
+ }
2434
+ catch (error) {
2435
+ console.warn(`Failed to apply commitment ${commitment.type}:`, error);
2436
+ // Continue with other commitments even if one fails
2437
+ }
2438
+ }
2439
+ }
2440
+ // Handle MCP servers (extract from original agent source)
2441
+ const mcpServers = extractMcpServers(agentSource);
2442
+ if (mcpServers.length > 0) {
2443
+ requirements = {
2444
+ ...requirements,
2445
+ mcpServers,
2446
+ };
2447
+ }
2448
+ // Add non-commitment lines to system message if they exist
2449
+ const nonCommitmentContent = parseResult.nonCommitmentLines
2450
+ .filter((line, index) => index > 0 || !parseResult.agentName) // Skip first line if it's the agent name
2451
+ .filter((line) => line.trim()) // Remove empty lines
2452
+ .join('\n')
2453
+ .trim();
2454
+ if (nonCommitmentContent) {
2455
+ requirements = {
2456
+ ...requirements,
2457
+ systemMessage: requirements.systemMessage + '\n\n' + nonCommitmentContent,
2458
+ };
2459
+ }
2460
+ // Remove comment lines (lines starting with #) from the final system message
2461
+ // while preserving the original content with comments in metadata
2462
+ const cleanedSystemMessage = removeCommentsFromSystemMessage(requirements.systemMessage);
2463
+ return {
2464
+ ...requirements,
2465
+ systemMessage: cleanedSystemMessage,
2466
+ };
2467
+ }
2468
+ /**
2469
+ * Cache for expensive createAgentModelRequirementsWithCommitments calls
2470
+ * @private
2471
+ */
2472
+ const modelRequirementsCache = new Map();
2473
+ /**
2474
+ * @private - TODO: Maybe should be public
2475
+ */
2476
+ const CACHE_SIZE_LIMIT = 100;
2477
+ /**
2478
+ * Cached version of createAgentModelRequirementsWithCommitments
2479
+ * This maintains the same caching behavior as the original function
2480
+ *
2481
+ * @private
2482
+ */
2483
+ async function createAgentModelRequirementsWithCommitmentsCached(agentSource, modelName) {
2484
+ // Create cache key
2485
+ const cacheKey = `${agentSource}|${modelName || 'default'}`;
2486
+ // Check cache first
2487
+ if (modelRequirementsCache.has(cacheKey)) {
2488
+ return modelRequirementsCache.get(cacheKey);
2489
+ }
2490
+ // Limit cache size to prevent memory leaks
2491
+ if (modelRequirementsCache.size >= CACHE_SIZE_LIMIT) {
2492
+ const firstKey = modelRequirementsCache.keys().next().value;
2493
+ if (firstKey) {
2494
+ modelRequirementsCache.delete(firstKey);
2495
+ }
2496
+ }
2497
+ // Create requirements
2498
+ const requirements = await createAgentModelRequirementsWithCommitments(agentSource, modelName);
2499
+ // Cache the result
2500
+ modelRequirementsCache.set(cacheKey, requirements);
2501
+ return requirements;
2502
+ }
2503
+
2504
+ // TODO: Remove or use:
2505
+ //const CACHE_SIZE_LIMIT = 100; // Prevent memory leaks by limiting cache size
2506
+ /**
2507
+ * Creates model requirements for an agent based on its source
2508
+ * Results are cached to improve performance for repeated calls with the same agentSource and modelName
2509
+ *
2510
+ * There are 2 similar functions:
2511
+ * - `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.
2512
+ * - `createAgentModelRequirements` which is an asynchronous function that creates model requirements it applies each commitment one by one and works asynchronously.
2513
+ *
2514
+ * @public exported from `@promptbook/core`
2515
+ */
2516
+ async function createAgentModelRequirements(agentSource, modelName = '!!!!DEFAULT_MODEL_ID') {
2517
+ // Use the new commitment-based system
2518
+ return createAgentModelRequirementsWithCommitmentsCached(agentSource, modelName);
2519
+ }
2520
+ /**
2521
+ * Extracts MCP servers from agent source
2522
+ *
2523
+ * @param agentSource The agent source string that may contain MCP lines
2524
+ * @returns Array of MCP server identifiers
2525
+ *
2526
+ * @private TODO: [🧠] Maybe should be public
2527
+ */
2528
+ function extractMcpServers(agentSource) {
2529
+ if (!agentSource) {
2530
+ return [];
2531
+ }
2532
+ const lines = agentSource.split('\n');
2533
+ const mcpRegex = /^\s*MCP\s+(.+)$/i;
2534
+ const mcpServers = [];
2535
+ // Look for MCP lines
2536
+ for (const line of lines) {
2537
+ const match = line.match(mcpRegex);
2538
+ if (match && match[1]) {
2539
+ mcpServers.push(match[1].trim());
2540
+ }
2541
+ }
2542
+ return mcpServers;
2543
+ }
2544
+
2545
+ /**
2546
+ * Converts PipelineCollection to serialized JSON
2547
+ *
2548
+ * Note: Functions `collectionToJson` and `createCollectionFromJson` are complementary
2549
+ *
2550
+ * @public exported from `@promptbook/core`
2551
+ */
2552
+ async function collectionToJson(collection) {
2553
+ const pipelineUrls = await collection.listPipelines();
2554
+ const promptbooks = await Promise.all(pipelineUrls.map((url) => collection.getPipelineByUrl(url)));
2555
+ return promptbooks;
2556
+ }
2557
+ /**
2558
+ * TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
2559
+ */
2560
+
2561
+ /**
2562
+ * Checks if value is valid email
2563
+ *
2564
+ * @public exported from `@promptbook/utils`
2565
+ */
2566
+ function isValidEmail(email) {
2567
+ if (typeof email !== 'string') {
2568
+ return false;
2569
+ }
2570
+ if (email.split('\n').length > 1) {
2571
+ return false;
2572
+ }
2573
+ return /^.+@.+\..+$/.test(email);
2574
+ }
2575
+
2576
+ /**
2577
+ * Tests if given string is valid URL.
2578
+ *
2579
+ * Note: This does not check if the file exists only if the path is valid
2580
+ * @public exported from `@promptbook/utils`
2581
+ */
2582
+ function isValidFilePath(filename) {
2583
+ if (typeof filename !== 'string') {
2584
+ return false;
2585
+ }
2586
+ if (filename.split('\n').length > 1) {
2587
+ return false;
2588
+ }
2589
+ if (filename.split(' ').length >
2590
+ 5 /* <- TODO: [🧠][🈷] Make some better non-arbitrary way how to distinct filenames from informational texts */) {
2591
+ return false;
2592
+ }
2593
+ const filenameSlashes = filename.split('\\').join('/');
2594
+ // Absolute Unix path: /hello.txt
2595
+ if (/^(\/)/i.test(filenameSlashes)) {
2596
+ // console.log(filename, 'Absolute Unix path: /hello.txt');
2597
+ return true;
2598
+ }
2599
+ // Absolute Windows path: /hello.txt
2600
+ if (/^([A-Z]{1,2}:\/?)\//i.test(filenameSlashes)) {
2601
+ // console.log(filename, 'Absolute Windows path: /hello.txt');
2602
+ return true;
2603
+ }
2604
+ // Relative path: ./hello.txt
2605
+ if (/^(\.\.?\/)+/i.test(filenameSlashes)) {
2606
+ // console.log(filename, 'Relative path: ./hello.txt');
2607
+ return true;
2608
+ }
2609
+ // Allow paths like foo/hello
2610
+ if (/^[^/]+\/[^/]+/i.test(filenameSlashes)) {
2611
+ // console.log(filename, 'Allow paths like foo/hello');
2612
+ return true;
2613
+ }
2614
+ // Allow paths like hello.book
2615
+ if (/^[^/]+\.[^/]+$/i.test(filenameSlashes)) {
2616
+ // console.log(filename, 'Allow paths like hello.book');
2617
+ return true;
2618
+ }
2619
+ return false;
2620
+ }
2621
+ /**
2622
+ * TODO: [🍏] Implement for MacOs
2623
+ */
2624
+
2625
+ /**
2626
+ * Tests if given string is valid URL.
2627
+ *
2628
+ * Note: Dataurl are considered perfectly valid.
2629
+ * Note: There are two similar functions:
2630
+ * - `isValidUrl` which tests any URL
2631
+ * - `isValidPipelineUrl` *(this one)* which tests just promptbook URL
2632
+ *
2633
+ * @public exported from `@promptbook/utils`
2634
+ */
2635
+ function isValidUrl(url) {
2636
+ if (typeof url !== 'string') {
2637
+ return false;
2638
+ }
2639
+ try {
2640
+ if (url.startsWith('blob:')) {
2641
+ url = url.replace(/^blob:/, '');
2642
+ }
2643
+ const urlObject = new URL(url /* because fail is handled */);
2644
+ if (!['http:', 'https:', 'data:'].includes(urlObject.protocol)) {
2645
+ return false;
2646
+ }
2647
+ return true;
2648
+ }
2649
+ catch (error) {
2650
+ return false;
618
2651
  }
619
- // Case 3: Handle standard errors - keep them up to consumer
620
- if (whatWasThrown instanceof Error) {
621
- return;
2652
+ }
2653
+
2654
+ /**
2655
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
2656
+ *
2657
+ * @public exported from `@promptbook/core`
2658
+ */
2659
+ class ParseError extends Error {
2660
+ constructor(message) {
2661
+ super(message);
2662
+ this.name = 'ParseError';
2663
+ Object.setPrototypeOf(this, ParseError.prototype);
622
2664
  }
623
- // Case 4: Handle non-standard errors - wrap them into `WrappedError` and throw
624
- throw new WrappedError(whatWasThrown);
625
2665
  }
2666
+ /**
2667
+ * TODO: Maybe split `ParseError` and `ApplyError`
2668
+ */
626
2669
 
627
2670
  /**
628
2671
  * Function isValidJsonString will tell you if the string is valid JSON or not
@@ -829,7 +2872,7 @@ function pipelineJsonToString(pipelineJson) {
829
2872
  pipelineString += '\n\n';
830
2873
  pipelineString += '```' + contentLanguage;
831
2874
  pipelineString += '\n';
832
- pipelineString += spaceTrim(content);
2875
+ pipelineString += spaceTrim$1(content);
833
2876
  // <- TODO: [main] !!3 Escape
834
2877
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
835
2878
  pipelineString += '\n';
@@ -873,33 +2916,6 @@ function orderJson(options) {
873
2916
  return orderedValue;
874
2917
  }
875
2918
 
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
2919
  /**
904
2920
  * Checks if the value is [🚉] serializable as JSON
905
2921
  * If not, throws an UnexpectedError with a rich error message and tracking
@@ -950,7 +2966,7 @@ function checkSerializableAsJson(options) {
950
2966
  }
951
2967
  else if (typeof value === 'object') {
952
2968
  if (value instanceof Date) {
953
- throw new UnexpectedError(spaceTrim((block) => `
2969
+ throw new UnexpectedError(spaceTrim$1((block) => `
954
2970
  \`${name}\` is Date
955
2971
 
956
2972
  Use \`string_date_iso8601\` instead
@@ -969,7 +2985,7 @@ function checkSerializableAsJson(options) {
969
2985
  throw new UnexpectedError(`${name} is RegExp`);
970
2986
  }
971
2987
  else if (value instanceof Error) {
972
- throw new UnexpectedError(spaceTrim((block) => `
2988
+ throw new UnexpectedError(spaceTrim$1((block) => `
973
2989
  \`${name}\` is unserialized Error
974
2990
 
975
2991
  Use function \`serializeError\`
@@ -992,7 +3008,7 @@ function checkSerializableAsJson(options) {
992
3008
  }
993
3009
  catch (error) {
994
3010
  assertsError(error);
995
- throw new UnexpectedError(spaceTrim((block) => `
3011
+ throw new UnexpectedError(spaceTrim$1((block) => `
996
3012
  \`${name}\` is not serializable
997
3013
 
998
3014
  ${block(error.stack || error.message)}
@@ -1024,7 +3040,7 @@ function checkSerializableAsJson(options) {
1024
3040
  }
1025
3041
  }
1026
3042
  else {
1027
- throw new UnexpectedError(spaceTrim((block) => `
3043
+ throw new UnexpectedError(spaceTrim$1((block) => `
1028
3044
  \`${name}\` is unknown type
1029
3045
 
1030
3046
  Additional message for \`${name}\`:
@@ -1311,7 +3327,7 @@ function validatePipeline(pipeline) {
1311
3327
  if (!(error instanceof PipelineLogicError)) {
1312
3328
  throw error;
1313
3329
  }
1314
- console.error(spaceTrim$1((block) => `
3330
+ console.error(spaceTrim((block) => `
1315
3331
  Pipeline is not valid but logic errors are temporarily disabled via \`IS_PIPELINE_LOGIC_VALIDATED\`
1316
3332
 
1317
3333
  ${block(error.message)}
@@ -1338,7 +3354,7 @@ function validatePipeline_InnerFunction(pipeline) {
1338
3354
  })();
1339
3355
  if (pipeline.pipelineUrl !== undefined && !isValidPipelineUrl(pipeline.pipelineUrl)) {
1340
3356
  // <- Note: [🚲]
1341
- throw new PipelineLogicError(spaceTrim$1((block) => `
3357
+ throw new PipelineLogicError(spaceTrim((block) => `
1342
3358
  Invalid promptbook URL "${pipeline.pipelineUrl}"
1343
3359
 
1344
3360
  ${block(pipelineIdentification)}
@@ -1346,7 +3362,7 @@ function validatePipeline_InnerFunction(pipeline) {
1346
3362
  }
1347
3363
  if (pipeline.bookVersion !== undefined && !isValidPromptbookVersion(pipeline.bookVersion)) {
1348
3364
  // <- Note: [🚲]
1349
- throw new PipelineLogicError(spaceTrim$1((block) => `
3365
+ throw new PipelineLogicError(spaceTrim((block) => `
1350
3366
  Invalid Promptbook Version "${pipeline.bookVersion}"
1351
3367
 
1352
3368
  ${block(pipelineIdentification)}
@@ -1355,7 +3371,7 @@ function validatePipeline_InnerFunction(pipeline) {
1355
3371
  // TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
1356
3372
  if (!Array.isArray(pipeline.parameters)) {
1357
3373
  // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1358
- throw new ParseError(spaceTrim$1((block) => `
3374
+ throw new ParseError(spaceTrim((block) => `
1359
3375
  Pipeline is valid JSON but with wrong structure
1360
3376
 
1361
3377
  \`PipelineJson.parameters\` expected to be an array, but got ${typeof pipeline.parameters}
@@ -1366,7 +3382,7 @@ function validatePipeline_InnerFunction(pipeline) {
1366
3382
  // TODO: [🧠] Maybe do here some proper JSON-schema / ZOD checking
1367
3383
  if (!Array.isArray(pipeline.tasks)) {
1368
3384
  // TODO: [🧠] what is the correct error tp throw - maybe PromptbookSchemaError
1369
- throw new ParseError(spaceTrim$1((block) => `
3385
+ throw new ParseError(spaceTrim((block) => `
1370
3386
  Pipeline is valid JSON but with wrong structure
1371
3387
 
1372
3388
  \`PipelineJson.tasks\` expected to be an array, but got ${typeof pipeline.tasks}
@@ -1392,7 +3408,7 @@ function validatePipeline_InnerFunction(pipeline) {
1392
3408
  // Note: Check each parameter individually
1393
3409
  for (const parameter of pipeline.parameters) {
1394
3410
  if (parameter.isInput && parameter.isOutput) {
1395
- throw new PipelineLogicError(spaceTrim$1((block) => `
3411
+ throw new PipelineLogicError(spaceTrim((block) => `
1396
3412
 
1397
3413
  Parameter \`{${parameter.name}}\` can not be both input and output
1398
3414
 
@@ -1403,7 +3419,7 @@ function validatePipeline_InnerFunction(pipeline) {
1403
3419
  if (!parameter.isInput &&
1404
3420
  !parameter.isOutput &&
1405
3421
  !pipeline.tasks.some((task) => task.dependentParameterNames.includes(parameter.name))) {
1406
- throw new PipelineLogicError(spaceTrim$1((block) => `
3422
+ throw new PipelineLogicError(spaceTrim((block) => `
1407
3423
  Parameter \`{${parameter.name}}\` is created but not used
1408
3424
 
1409
3425
  You can declare {${parameter.name}} as output parameter by adding in the header:
@@ -1415,7 +3431,7 @@ function validatePipeline_InnerFunction(pipeline) {
1415
3431
  }
1416
3432
  // Note: Testing that parameter is either input or result of some task
1417
3433
  if (!parameter.isInput && !pipeline.tasks.some((task) => task.resultingParameterName === parameter.name)) {
1418
- throw new PipelineLogicError(spaceTrim$1((block) => `
3434
+ throw new PipelineLogicError(spaceTrim((block) => `
1419
3435
  Parameter \`{${parameter.name}}\` is declared but not defined
1420
3436
 
1421
3437
  You can do one of these:
@@ -1431,14 +3447,14 @@ function validatePipeline_InnerFunction(pipeline) {
1431
3447
  // Note: Checking each task individually
1432
3448
  for (const task of pipeline.tasks) {
1433
3449
  if (definedParameters.has(task.resultingParameterName)) {
1434
- throw new PipelineLogicError(spaceTrim$1((block) => `
3450
+ throw new PipelineLogicError(spaceTrim((block) => `
1435
3451
  Parameter \`{${task.resultingParameterName}}\` is defined multiple times
1436
3452
 
1437
3453
  ${block(pipelineIdentification)}
1438
3454
  `));
1439
3455
  }
1440
3456
  if (RESERVED_PARAMETER_NAMES.includes(task.resultingParameterName)) {
1441
- throw new PipelineLogicError(spaceTrim$1((block) => `
3457
+ throw new PipelineLogicError(spaceTrim((block) => `
1442
3458
  Parameter name {${task.resultingParameterName}} is reserved, please use different name
1443
3459
 
1444
3460
  ${block(pipelineIdentification)}
@@ -1448,7 +3464,7 @@ function validatePipeline_InnerFunction(pipeline) {
1448
3464
  if (task.jokerParameterNames && task.jokerParameterNames.length > 0) {
1449
3465
  if (!task.format &&
1450
3466
  !task.expectations /* <- TODO: Require at least 1 -> min <- expectation to use jokers */) {
1451
- throw new PipelineLogicError(spaceTrim$1((block) => `
3467
+ throw new PipelineLogicError(spaceTrim((block) => `
1452
3468
  Joker parameters are used for {${task.resultingParameterName}} but no expectations are defined
1453
3469
 
1454
3470
  ${block(pipelineIdentification)}
@@ -1456,7 +3472,7 @@ function validatePipeline_InnerFunction(pipeline) {
1456
3472
  }
1457
3473
  for (const joker of task.jokerParameterNames) {
1458
3474
  if (!task.dependentParameterNames.includes(joker)) {
1459
- throw new PipelineLogicError(spaceTrim$1((block) => `
3475
+ throw new PipelineLogicError(spaceTrim((block) => `
1460
3476
  Parameter \`{${joker}}\` is used for {${task.resultingParameterName}} as joker but not in \`dependentParameterNames\`
1461
3477
 
1462
3478
  ${block(pipelineIdentification)}
@@ -1467,21 +3483,21 @@ function validatePipeline_InnerFunction(pipeline) {
1467
3483
  if (task.expectations) {
1468
3484
  for (const [unit, { min, max }] of Object.entries(task.expectations)) {
1469
3485
  if (min !== undefined && max !== undefined && min > max) {
1470
- throw new PipelineLogicError(spaceTrim$1((block) => `
3486
+ throw new PipelineLogicError(spaceTrim((block) => `
1471
3487
  Min expectation (=${min}) of ${unit} is higher than max expectation (=${max})
1472
3488
 
1473
3489
  ${block(pipelineIdentification)}
1474
3490
  `));
1475
3491
  }
1476
3492
  if (min !== undefined && min < 0) {
1477
- throw new PipelineLogicError(spaceTrim$1((block) => `
3493
+ throw new PipelineLogicError(spaceTrim((block) => `
1478
3494
  Min expectation of ${unit} must be zero or positive
1479
3495
 
1480
3496
  ${block(pipelineIdentification)}
1481
3497
  `));
1482
3498
  }
1483
3499
  if (max !== undefined && max <= 0) {
1484
- throw new PipelineLogicError(spaceTrim$1((block) => `
3500
+ throw new PipelineLogicError(spaceTrim((block) => `
1485
3501
  Max expectation of ${unit} must be positive
1486
3502
 
1487
3503
  ${block(pipelineIdentification)}
@@ -1503,7 +3519,7 @@ function validatePipeline_InnerFunction(pipeline) {
1503
3519
  while (unresovedTasks.length > 0) {
1504
3520
  if (loopLimit-- < 0) {
1505
3521
  // Note: Really UnexpectedError not LimitReachedError - this should not happen and be caught below
1506
- throw new UnexpectedError(spaceTrim$1((block) => `
3522
+ throw new UnexpectedError(spaceTrim((block) => `
1507
3523
  Loop limit reached during detection of circular dependencies in \`validatePipeline\`
1508
3524
 
1509
3525
  ${block(pipelineIdentification)}
@@ -1513,7 +3529,7 @@ function validatePipeline_InnerFunction(pipeline) {
1513
3529
  if (currentlyResovedTasks.length === 0) {
1514
3530
  throw new PipelineLogicError(
1515
3531
  // TODO: [🐎] DRY
1516
- spaceTrim$1((block) => `
3532
+ spaceTrim((block) => `
1517
3533
 
1518
3534
  Can not resolve some parameters:
1519
3535
  Either you are using a parameter that is not defined, or there are some circular dependencies.
@@ -1677,7 +3693,7 @@ class SimplePipelineCollection {
1677
3693
  for (const pipeline of pipelines) {
1678
3694
  // TODO: [👠] DRY
1679
3695
  if (pipeline.pipelineUrl === undefined) {
1680
- throw new PipelineUrlError(spaceTrim$1(`
3696
+ throw new PipelineUrlError(spaceTrim(`
1681
3697
  Pipeline with name "${pipeline.title}" does not have defined URL
1682
3698
 
1683
3699
  File:
@@ -1699,7 +3715,7 @@ class SimplePipelineCollection {
1699
3715
  pipelineJsonToString(unpreparePipeline(pipeline)) !==
1700
3716
  pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
1701
3717
  const existing = this.collection.get(pipeline.pipelineUrl);
1702
- throw new PipelineUrlError(spaceTrim$1(`
3718
+ throw new PipelineUrlError(spaceTrim(`
1703
3719
  Pipeline with URL ${pipeline.pipelineUrl} is already in the collection 🍎
1704
3720
 
1705
3721
  Conflicting files:
@@ -1731,13 +3747,13 @@ class SimplePipelineCollection {
1731
3747
  const pipeline = this.collection.get(url);
1732
3748
  if (!pipeline) {
1733
3749
  if (this.listPipelines().length === 0) {
1734
- throw new NotFoundError(spaceTrim$1(`
3750
+ throw new NotFoundError(spaceTrim(`
1735
3751
  Pipeline with url "${url}" not found
1736
3752
 
1737
3753
  No pipelines available
1738
3754
  `));
1739
3755
  }
1740
- throw new NotFoundError(spaceTrim$1((block) => `
3756
+ throw new NotFoundError(spaceTrim((block) => `
1741
3757
  Pipeline with url "${url}" not found
1742
3758
 
1743
3759
  Available pipelines:
@@ -1867,7 +3883,7 @@ function createSubcollection(collection, predicate) {
1867
3883
  }
1868
3884
  async function getPipelineByUrl(url) {
1869
3885
  if (!predicate(url)) {
1870
- throw new NotFoundError(await spaceTrim$1(async (block) => `
3886
+ throw new NotFoundError(await spaceTrim(async (block) => `
1871
3887
  Promptbook with url "${url}" not found or not accessible
1872
3888
 
1873
3889
  Available promptbooks:
@@ -1902,7 +3918,7 @@ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"
1902
3918
  */
1903
3919
  class MissingToolsError extends Error {
1904
3920
  constructor(message) {
1905
- super(spaceTrim$1((block) => `
3921
+ super(spaceTrim((block) => `
1906
3922
  ${block(message)}
1907
3923
 
1908
3924
  Note: You have probably forgot to provide some tools for pipeline execution or preparation
@@ -2071,7 +4087,7 @@ class LimitReachedError extends Error {
2071
4087
  */
2072
4088
  class NotYetImplementedError extends Error {
2073
4089
  constructor(message) {
2074
- super(spaceTrim$1((block) => `
4090
+ super(spaceTrim((block) => `
2075
4091
  ${block(message)}
2076
4092
 
2077
4093
  Note: This feature is not implemented yet but it will be soon.
@@ -2121,19 +4137,6 @@ class PipelineExecutionError extends Error {
2121
4137
  * TODO: [🧠][🌂] Add id to all errors
2122
4138
  */
2123
4139
 
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
4140
  /**
2138
4141
  * Index of all custom errors
2139
4142
  *
@@ -2205,7 +4208,7 @@ function serializeError(error) {
2205
4208
  const { name, message, stack } = error;
2206
4209
  const { id } = error;
2207
4210
  if (!Object.keys(ALL_ERRORS).includes(name)) {
2208
- console.error(spaceTrim((block) => `
4211
+ console.error(spaceTrim$1((block) => `
2209
4212
 
2210
4213
  Cannot serialize error with name "${name}"
2211
4214
 
@@ -2238,7 +4241,7 @@ function jsonParse(value) {
2238
4241
  }
2239
4242
  else if (typeof value !== 'string') {
2240
4243
  console.error('Can not parse JSON from non-string value.', { text: value });
2241
- throw new Error(spaceTrim(`
4244
+ throw new Error(spaceTrim$1(`
2242
4245
  Can not parse JSON from non-string value.
2243
4246
 
2244
4247
  The value type: ${typeof value}
@@ -2252,7 +4255,7 @@ function jsonParse(value) {
2252
4255
  if (!(error instanceof Error)) {
2253
4256
  throw error;
2254
4257
  }
2255
- throw new Error(spaceTrim((block) => `
4258
+ throw new Error(spaceTrim$1((block) => `
2256
4259
  ${block(error.message)}
2257
4260
 
2258
4261
  The expected JSON text:
@@ -2305,7 +4308,7 @@ function deserializeError(error) {
2305
4308
  message = `${name}: ${message}`;
2306
4309
  }
2307
4310
  if (stack !== undefined && stack !== '') {
2308
- message = spaceTrim((block) => `
4311
+ message = spaceTrim$1((block) => `
2309
4312
  ${block(message)}
2310
4313
 
2311
4314
  Original stack trace:
@@ -2342,11 +4345,11 @@ function assertsTaskSuccessful(executionResult) {
2342
4345
  throw deserializeError(errors[0]);
2343
4346
  }
2344
4347
  else {
2345
- throw new PipelineExecutionError(spaceTrim$1((block) => `
4348
+ throw new PipelineExecutionError(spaceTrim((block) => `
2346
4349
  Multiple errors occurred during Promptbook execution
2347
4350
 
2348
4351
  ${block(errors
2349
- .map(({ name, stack, message }, index) => spaceTrim$1((block) => `
4352
+ .map(({ name, stack, message }, index) => spaceTrim((block) => `
2350
4353
  ${name} ${index + 1}:
2351
4354
  ${block(stack || message)}
2352
4355
  `))
@@ -2364,7 +4367,7 @@ function assertsTaskSuccessful(executionResult) {
2364
4367
  * @private internal helper function
2365
4368
  */
2366
4369
  function createTask(options) {
2367
- const { taskType, taskProcessCallback } = options;
4370
+ const { taskType, taskProcessCallback, tldrProvider } = options;
2368
4371
  let { title } = options;
2369
4372
  // TODO: [🐙] DRY
2370
4373
  const taskId = `${taskType.toLowerCase().substring(0, 4)}-${$randomToken(8 /* <- TODO: To global config + Use Base58 to avoid similar char conflicts */)}`;
@@ -2437,6 +4440,78 @@ function createTask(options) {
2437
4440
  return status;
2438
4441
  // <- Note: [1] --||--
2439
4442
  },
4443
+ get tldr() {
4444
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k;
4445
+ // Use custom tldr provider if available
4446
+ if (tldrProvider) {
4447
+ return tldrProvider(createdAt, status, currentValue, errors, warnings);
4448
+ }
4449
+ // Fallback to default implementation
4450
+ const cv = currentValue;
4451
+ // If explicit percent is provided, use it
4452
+ let percentRaw = (_f = (_d = (_b = (_a = cv === null || cv === void 0 ? void 0 : cv.tldr) === null || _a === void 0 ? void 0 : _a.percent) !== null && _b !== void 0 ? _b : (_c = cv === null || cv === void 0 ? void 0 : cv.usage) === null || _c === void 0 ? void 0 : _c.percent) !== null && _d !== void 0 ? _d : (_e = cv === null || cv === void 0 ? void 0 : cv.progress) === null || _e === void 0 ? void 0 : _e.percent) !== null && _f !== void 0 ? _f : cv === null || cv === void 0 ? void 0 : cv.percent;
4453
+ // Simulate progress if not provided
4454
+ if (typeof percentRaw !== 'number') {
4455
+ // Simulate progress: evenly split across subtasks, based on elapsed time
4456
+ const now = new Date();
4457
+ const elapsedMs = now.getTime() - createdAt.getTime();
4458
+ const totalMs = DEFAULT_TASK_SIMULATED_DURATION_MS;
4459
+ // If subtasks are defined, split progress evenly
4460
+ const subtaskCount = Array.isArray(cv === null || cv === void 0 ? void 0 : cv.subtasks) ? cv.subtasks.length : 1;
4461
+ const completedSubtasks = Array.isArray(cv === null || cv === void 0 ? void 0 : cv.subtasks)
4462
+ ? cv.subtasks.filter((s) => s.done || s.completed).length
4463
+ : 0;
4464
+ // Progress from completed subtasks
4465
+ const subtaskProgress = subtaskCount > 0 ? completedSubtasks / subtaskCount : 0;
4466
+ // Progress from elapsed time for current subtask
4467
+ const timeProgress = Math.min(elapsedMs / totalMs, 1);
4468
+ // Combine: completed subtasks + time progress for current subtask
4469
+ percentRaw = Math.min(subtaskProgress + (1 / subtaskCount) * timeProgress, 1);
4470
+ if (status === 'FINISHED')
4471
+ percentRaw = 1;
4472
+ if (status === 'ERROR')
4473
+ percentRaw = 0;
4474
+ }
4475
+ // Clamp to [0,1]
4476
+ let percent = Number(percentRaw) || 0;
4477
+ if (percent < 0)
4478
+ percent = 0;
4479
+ if (percent > 1)
4480
+ percent = 1;
4481
+ // Build a short message: prefer explicit tldr.message, then common summary/message fields, then errors/warnings, then status
4482
+ const messageFromResult = (_k = (_j = (_h = (_g = cv === null || cv === void 0 ? void 0 : cv.tldr) === null || _g === void 0 ? void 0 : _g.message) !== null && _h !== void 0 ? _h : cv === null || cv === void 0 ? void 0 : cv.message) !== null && _j !== void 0 ? _j : cv === null || cv === void 0 ? void 0 : cv.summary) !== null && _k !== void 0 ? _k : cv === null || cv === void 0 ? void 0 : cv.statusMessage;
4483
+ let message = messageFromResult;
4484
+ if (!message) {
4485
+ // If subtasks, show current subtask
4486
+ if (Array.isArray(cv === null || cv === void 0 ? void 0 : cv.subtasks) && cv.subtasks.length > 0) {
4487
+ const current = cv.subtasks.find((s) => !s.done && !s.completed);
4488
+ if (current && current.title) {
4489
+ message = `Working on ${current.title}`;
4490
+ }
4491
+ }
4492
+ if (!message) {
4493
+ if (errors.length) {
4494
+ message = errors[errors.length - 1].message || 'Error';
4495
+ }
4496
+ else if (warnings.length) {
4497
+ message = warnings[warnings.length - 1].message || 'Warning';
4498
+ }
4499
+ else if (status === 'FINISHED') {
4500
+ message = 'Finished';
4501
+ }
4502
+ else if (status === 'ERROR') {
4503
+ message = 'Error';
4504
+ }
4505
+ else {
4506
+ message = 'Running';
4507
+ }
4508
+ }
4509
+ }
4510
+ return {
4511
+ percent: percent,
4512
+ message,
4513
+ };
4514
+ },
2440
4515
  get createdAt() {
2441
4516
  return createdAt;
2442
4517
  // <- Note: [1] --||--
@@ -2716,7 +4791,7 @@ function extractVariablesFromJavascript(script) {
2716
4791
  }
2717
4792
  catch (error) {
2718
4793
  assertsError(error);
2719
- throw new ParseError(spaceTrim$1((block) => `
4794
+ throw new ParseError(spaceTrim((block) => `
2720
4795
  Can not extract variables from the script
2721
4796
  ${block(error.stack || error.message)}
2722
4797
 
@@ -2899,7 +4974,7 @@ const CsvFormatParser = {
2899
4974
  const { value, outputParameterName, settings, mapCallback, onProgress } = options;
2900
4975
  const csv = csvParse(value, settings);
2901
4976
  if (csv.errors.length !== 0) {
2902
- throw new CsvFormatError(spaceTrim((block) => `
4977
+ throw new CsvFormatError(spaceTrim$1((block) => `
2903
4978
  CSV parsing error
2904
4979
 
2905
4980
  Error(s) from CSV parsing:
@@ -2944,7 +5019,7 @@ const CsvFormatParser = {
2944
5019
  const { value, settings, mapCallback, onProgress } = options;
2945
5020
  const csv = csvParse(value, settings);
2946
5021
  if (csv.errors.length !== 0) {
2947
- throw new CsvFormatError(spaceTrim((block) => `
5022
+ throw new CsvFormatError(spaceTrim$1((block) => `
2948
5023
  CSV parsing error
2949
5024
 
2950
5025
  Error(s) from CSV parsing:
@@ -3154,7 +5229,7 @@ function mapAvailableToExpectedParameters(options) {
3154
5229
  }
3155
5230
  // Phase 2️⃣: Non-matching mapping
3156
5231
  if (expectedParameterNames.size !== availableParametersNames.size) {
3157
- throw new PipelineExecutionError(spaceTrim((block) => `
5232
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
3158
5233
  Can not map available parameters to expected parameters
3159
5234
 
3160
5235
  Mapped parameters:
@@ -3207,14 +5282,14 @@ class MultipleLlmExecutionTools {
3207
5282
  if (description === undefined) {
3208
5283
  return headLine;
3209
5284
  }
3210
- return spaceTrim((block) => `
5285
+ return spaceTrim$1((block) => `
3211
5286
  ${headLine}
3212
5287
 
3213
5288
  ${ /* <- Note: Indenting the description: */block(description)}
3214
5289
  `);
3215
5290
  })
3216
5291
  .join('\n\n');
3217
- return spaceTrim((block) => `
5292
+ return spaceTrim$1((block) => `
3218
5293
  Multiple LLM Providers:
3219
5294
 
3220
5295
  ${block(innerModelsTitlesAndDescriptions)}
@@ -3305,7 +5380,7 @@ class MultipleLlmExecutionTools {
3305
5380
  // 1) OpenAI throw PipelineExecutionError: Parameter `{knowledge}` is not defined
3306
5381
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
3307
5382
  // 3) ...
3308
- spaceTrim((block) => `
5383
+ spaceTrim$1((block) => `
3309
5384
  All execution tools failed:
3310
5385
 
3311
5386
  ${block(errors
@@ -3318,7 +5393,7 @@ class MultipleLlmExecutionTools {
3318
5393
  throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\``);
3319
5394
  }
3320
5395
  else {
3321
- throw new PipelineExecutionError(spaceTrim((block) => `
5396
+ throw new PipelineExecutionError(spaceTrim$1((block) => `
3322
5397
  You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}"
3323
5398
 
3324
5399
  Available \`LlmExecutionTools\`:
@@ -3351,7 +5426,7 @@ class MultipleLlmExecutionTools {
3351
5426
  */
3352
5427
  function joinLlmExecutionTools(...llmExecutionTools) {
3353
5428
  if (llmExecutionTools.length === 0) {
3354
- const warningMessage = spaceTrim(`
5429
+ const warningMessage = spaceTrim$1(`
3355
5430
  You have not provided any \`LlmExecutionTools\`
3356
5431
  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
5432
 
@@ -4063,7 +6138,7 @@ function validatePromptResult(options) {
4063
6138
  }
4064
6139
  catch (error) {
4065
6140
  keepUnused(error);
4066
- throw new ExpectError(spaceTrim$1((block) => `
6141
+ throw new ExpectError(spaceTrim((block) => `
4067
6142
  Expected valid JSON string
4068
6143
 
4069
6144
  The expected JSON text:
@@ -4112,7 +6187,7 @@ function validatePromptResult(options) {
4112
6187
  */
4113
6188
  async function executeAttempts(options) {
4114
6189
  const { jokerParameterNames, priority, maxAttempts, // <- Note: [💂]
4115
- preparedContent, parameters, task, preparedPipeline, tools, $executionReport, pipelineIdentification, maxExecutionAttempts, } = options;
6190
+ preparedContent, parameters, task, preparedPipeline, tools, $executionReport, pipelineIdentification, maxExecutionAttempts, onProgress, } = options;
4116
6191
  const $ongoingTaskResult = {
4117
6192
  $result: null,
4118
6193
  $resultString: null,
@@ -4128,7 +6203,7 @@ async function executeAttempts(options) {
4128
6203
  const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
4129
6204
  // TODO: [🧠][🍭] JOKERS, EXPECTATIONS, POSTPROCESSING and FOREACH
4130
6205
  if (isJokerAttempt && !jokerParameterName) {
4131
- throw new UnexpectedError(spaceTrim$1((block) => `
6206
+ throw new UnexpectedError(spaceTrim((block) => `
4132
6207
  Joker not found in attempt ${attemptIndex}
4133
6208
 
4134
6209
  ${block(pipelineIdentification)}
@@ -4139,7 +6214,7 @@ async function executeAttempts(options) {
4139
6214
  $ongoingTaskResult.$expectError = null;
4140
6215
  if (isJokerAttempt) {
4141
6216
  if (parameters[jokerParameterName] === undefined) {
4142
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6217
+ throw new PipelineExecutionError(spaceTrim((block) => `
4143
6218
  Joker parameter {${jokerParameterName}} not defined
4144
6219
 
4145
6220
  ${block(pipelineIdentification)}
@@ -4197,7 +6272,7 @@ async function executeAttempts(options) {
4197
6272
  $ongoingTaskResult.$resultString = $ongoingTaskResult.$completionResult.content;
4198
6273
  break variant;
4199
6274
  case 'EMBEDDING':
4200
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6275
+ throw new PipelineExecutionError(spaceTrim((block) => `
4201
6276
  Embedding model can not be used in pipeline
4202
6277
 
4203
6278
  This should be catched during parsing
@@ -4208,7 +6283,7 @@ async function executeAttempts(options) {
4208
6283
  break variant;
4209
6284
  // <- case [🤖]:
4210
6285
  default:
4211
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6286
+ throw new PipelineExecutionError(spaceTrim((block) => `
4212
6287
  Unknown model variant "${task.modelRequirements.modelVariant}"
4213
6288
 
4214
6289
  ${block(pipelineIdentification)}
@@ -4219,14 +6294,14 @@ async function executeAttempts(options) {
4219
6294
  break;
4220
6295
  case 'SCRIPT_TASK':
4221
6296
  if (arrayableToArray(tools.script).length === 0) {
4222
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6297
+ throw new PipelineExecutionError(spaceTrim((block) => `
4223
6298
  No script execution tools are available
4224
6299
 
4225
6300
  ${block(pipelineIdentification)}
4226
6301
  `));
4227
6302
  }
4228
6303
  if (!task.contentLanguage) {
4229
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6304
+ throw new PipelineExecutionError(spaceTrim((block) => `
4230
6305
  Script language is not defined for SCRIPT TASK "${task.name}"
4231
6306
 
4232
6307
  ${block(pipelineIdentification)}
@@ -4257,7 +6332,7 @@ async function executeAttempts(options) {
4257
6332
  throw $ongoingTaskResult.$scriptPipelineExecutionErrors[0];
4258
6333
  }
4259
6334
  else {
4260
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6335
+ throw new PipelineExecutionError(spaceTrim((block) => `
4261
6336
  Script execution failed ${$ongoingTaskResult.$scriptPipelineExecutionErrors.length}x
4262
6337
 
4263
6338
  ${block(pipelineIdentification)}
@@ -4271,7 +6346,7 @@ async function executeAttempts(options) {
4271
6346
  break taskType;
4272
6347
  case 'DIALOG_TASK':
4273
6348
  if (tools.userInterface === undefined) {
4274
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6349
+ throw new PipelineExecutionError(spaceTrim((block) => `
4275
6350
  User interface tools are not available
4276
6351
 
4277
6352
  ${block(pipelineIdentification)}
@@ -4289,7 +6364,7 @@ async function executeAttempts(options) {
4289
6364
  break taskType;
4290
6365
  // <- case: [🅱]
4291
6366
  default:
4292
- throw new PipelineExecutionError(spaceTrim$1((block) => `
6367
+ throw new PipelineExecutionError(spaceTrim((block) => `
4293
6368
  Unknown execution type "${task.taskType}"
4294
6369
 
4295
6370
  ${block(pipelineIdentification)}
@@ -4356,6 +6431,10 @@ async function executeAttempts(options) {
4356
6431
  result: $ongoingTaskResult.$resultString,
4357
6432
  error: error,
4358
6433
  });
6434
+ // Report failed attempt
6435
+ onProgress({
6436
+ errors: [error],
6437
+ });
4359
6438
  }
4360
6439
  finally {
4361
6440
  if (!isJokerAttempt &&
@@ -4380,7 +6459,7 @@ async function executeAttempts(options) {
4380
6459
  if ($ongoingTaskResult.$expectError !== null && attemptIndex === maxAttempts - 1) {
4381
6460
  // Note: Create a summary of all failures
4382
6461
  const failuresSummary = $ongoingTaskResult.$failedResults
4383
- .map((failure) => spaceTrim$1((block) => {
6462
+ .map((failure) => spaceTrim((block) => {
4384
6463
  var _a, _b;
4385
6464
  return `
4386
6465
  Attempt ${failure.attemptIndex + 1}:
@@ -4390,14 +6469,14 @@ async function executeAttempts(options) {
4390
6469
  Result:
4391
6470
  ${block(failure.result === null
4392
6471
  ? 'null'
4393
- : spaceTrim$1(failure.result)
6472
+ : spaceTrim(failure.result)
4394
6473
  .split('\n')
4395
6474
  .map((line) => `> ${line}`)
4396
6475
  .join('\n'))}
4397
6476
  `;
4398
6477
  }))
4399
6478
  .join('\n\n---\n\n');
4400
- throw new PipelineExecutionError(spaceTrim$1((block) => {
6479
+ throw new PipelineExecutionError(spaceTrim((block) => {
4401
6480
  var _a;
4402
6481
  return `
4403
6482
  LLM execution failed ${maxExecutionAttempts}x
@@ -4417,7 +6496,7 @@ async function executeAttempts(options) {
4417
6496
  }
4418
6497
  }
4419
6498
  if ($ongoingTaskResult.$resultString === null) {
4420
- throw new UnexpectedError(spaceTrim$1((block) => `
6499
+ throw new UnexpectedError(spaceTrim((block) => `
4421
6500
  Something went wrong and prompt result is null
4422
6501
 
4423
6502
  ${block(pipelineIdentification)}
@@ -4444,7 +6523,7 @@ async function executeFormatSubvalues(options) {
4444
6523
  return /* not await */ executeAttempts(options);
4445
6524
  }
4446
6525
  if (jokerParameterNames.length !== 0) {
4447
- throw new UnexpectedError(spaceTrim((block) => `
6526
+ throw new UnexpectedError(spaceTrim$1((block) => `
4448
6527
  JOKER parameters are not supported together with FOREACH command
4449
6528
 
4450
6529
  [🧞‍♀️] This should be prevented in \`validatePipeline\`
@@ -4457,7 +6536,7 @@ async function executeFormatSubvalues(options) {
4457
6536
  if (formatDefinition === undefined) {
4458
6537
  throw new UnexpectedError(
4459
6538
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
4460
- spaceTrim((block) => `
6539
+ spaceTrim$1((block) => `
4461
6540
  Unsupported format "${task.foreach.formatName}"
4462
6541
 
4463
6542
  Available formats:
@@ -4474,7 +6553,7 @@ async function executeFormatSubvalues(options) {
4474
6553
  if (subvalueParser === undefined) {
4475
6554
  throw new UnexpectedError(
4476
6555
  // <- TODO: [🧠][🧐] Should be formats fixed per promptbook version or behave as plugins (=> change UnexpectedError)
4477
- spaceTrim((block) => `
6556
+ spaceTrim$1((block) => `
4478
6557
  Unsupported subformat name "${task.foreach.subformatName}" for format "${task.foreach.formatName}"
4479
6558
 
4480
6559
  Available subformat names for format "${formatDefinition.formatName}":
@@ -4514,7 +6593,7 @@ async function executeFormatSubvalues(options) {
4514
6593
  if (!(error instanceof PipelineExecutionError)) {
4515
6594
  throw error;
4516
6595
  }
4517
- const highLevelError = new PipelineExecutionError(spaceTrim((block) => `
6596
+ const highLevelError = new PipelineExecutionError(spaceTrim$1((block) => `
4518
6597
  ${error.message}
4519
6598
 
4520
6599
  This is error in FOREACH command when mapping ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -4538,7 +6617,7 @@ async function executeFormatSubvalues(options) {
4538
6617
  ...options,
4539
6618
  priority: priority + index,
4540
6619
  parameters: allSubparameters,
4541
- pipelineIdentification: spaceTrim((block) => `
6620
+ pipelineIdentification: spaceTrim$1((block) => `
4542
6621
  ${block(pipelineIdentification)}
4543
6622
  Subparameter index: ${index}
4544
6623
  `),
@@ -4547,7 +6626,7 @@ async function executeFormatSubvalues(options) {
4547
6626
  }
4548
6627
  catch (error) {
4549
6628
  if (length > BIG_DATASET_TRESHOLD) {
4550
- console.error(spaceTrim((block) => `
6629
+ console.error(spaceTrim$1((block) => `
4551
6630
  ${error.message}
4552
6631
 
4553
6632
  This is error in FOREACH command when processing ${formatDefinition.formatName} ${subvalueParser.subvalueName} data (${index + 1}/${length})
@@ -4725,7 +6804,7 @@ async function getReservedParametersForTask(options) {
4725
6804
  // Note: Doublecheck that ALL reserved parameters are defined:
4726
6805
  for (const parameterName of RESERVED_PARAMETER_NAMES) {
4727
6806
  if (reservedParameters[parameterName] === undefined) {
4728
- throw new UnexpectedError(spaceTrim$1((block) => `
6807
+ throw new UnexpectedError(spaceTrim((block) => `
4729
6808
  Reserved parameter {${parameterName}} is not defined
4730
6809
 
4731
6810
  ${block(pipelineIdentification)}
@@ -4751,7 +6830,7 @@ async function executeTask(options) {
4751
6830
  const dependentParameterNames = new Set(currentTask.dependentParameterNames);
4752
6831
  // TODO: [👩🏾‍🤝‍👩🏻] Use here `mapAvailableToExpectedParameters`
4753
6832
  if (difference(union(difference(usedParameterNames, dependentParameterNames), difference(dependentParameterNames, usedParameterNames)), new Set(RESERVED_PARAMETER_NAMES)).size !== 0) {
4754
- throw new UnexpectedError(spaceTrim$1((block) => `
6833
+ throw new UnexpectedError(spaceTrim((block) => `
4755
6834
  Dependent parameters are not consistent with used parameters:
4756
6835
 
4757
6836
  Dependent parameters:
@@ -4795,7 +6874,7 @@ async function executeTask(options) {
4795
6874
  else if (!definedParameterNames.has(parameterName) && usedParameterNames.has(parameterName)) {
4796
6875
  // Houston, we have a problem
4797
6876
  // Note: Checking part is also done in `validatePipeline`, but it’s good to doublecheck
4798
- throw new UnexpectedError(spaceTrim$1((block) => `
6877
+ throw new UnexpectedError(spaceTrim((block) => `
4799
6878
  Parameter \`{${parameterName}}\` is NOT defined
4800
6879
  BUT used in task "${currentTask.title || currentTask.name}"
4801
6880
 
@@ -4863,7 +6942,7 @@ function filterJustOutputParameters(options) {
4863
6942
  for (const parameter of preparedPipeline.parameters.filter(({ isOutput }) => isOutput)) {
4864
6943
  if (parametersToPass[parameter.name] === undefined) {
4865
6944
  // [4]
4866
- $warnings.push(new PipelineExecutionError(spaceTrim$1((block) => `
6945
+ $warnings.push(new PipelineExecutionError(spaceTrim((block) => `
4867
6946
  Parameter \`{${parameter.name}}\` should be an output parameter, but it was not generated during pipeline execution
4868
6947
 
4869
6948
  ${block(pipelineIdentification)}
@@ -4948,7 +7027,7 @@ async function executePipeline(options) {
4948
7027
  for (const parameterName of Object.keys(inputParameters)) {
4949
7028
  const parameter = preparedPipeline.parameters.find(({ name }) => name === parameterName);
4950
7029
  if (parameter === undefined) {
4951
- warnings.push(new PipelineExecutionError(spaceTrim$1((block) => `
7030
+ warnings.push(new PipelineExecutionError(spaceTrim((block) => `
4952
7031
  Extra parameter {${parameterName}} is being passed which is not part of the pipeline.
4953
7032
 
4954
7033
  ${block(pipelineIdentification)}
@@ -4963,7 +7042,7 @@ async function executePipeline(options) {
4963
7042
  // TODO: [🧠] This should be also non-critical error
4964
7043
  return exportJson({
4965
7044
  name: 'pipelineExecutorResult',
4966
- message: spaceTrim$1((block) => `
7045
+ message: spaceTrim((block) => `
4967
7046
  Unsuccessful PipelineExecutorResult (with extra parameter {${parameter.name}}) PipelineExecutorResult
4968
7047
 
4969
7048
  ${block(pipelineIdentification)}
@@ -4972,7 +7051,7 @@ async function executePipeline(options) {
4972
7051
  value: {
4973
7052
  isSuccessful: false,
4974
7053
  errors: [
4975
- new PipelineExecutionError(spaceTrim$1((block) => `
7054
+ new PipelineExecutionError(spaceTrim((block) => `
4976
7055
  Parameter \`{${parameter.name}}\` is passed as input parameter but it is not input
4977
7056
 
4978
7057
  ${block(pipelineIdentification)}
@@ -4999,7 +7078,7 @@ async function executePipeline(options) {
4999
7078
  while (unresovedTasks.length > 0) {
5000
7079
  if (loopLimit-- < 0) {
5001
7080
  // Note: Really UnexpectedError not LimitReachedError - this should be catched during validatePipeline
5002
- throw new UnexpectedError(spaceTrim$1((block) => `
7081
+ throw new UnexpectedError(spaceTrim((block) => `
5003
7082
  Loop limit reached during resolving parameters pipeline execution
5004
7083
 
5005
7084
  ${block(pipelineIdentification)}
@@ -5009,7 +7088,7 @@ async function executePipeline(options) {
5009
7088
  if (!currentTask && resolving.length === 0) {
5010
7089
  throw new UnexpectedError(
5011
7090
  // TODO: [🐎] DRY
5012
- spaceTrim$1((block) => `
7091
+ spaceTrim((block) => `
5013
7092
  Can not resolve some parameters:
5014
7093
 
5015
7094
  ${block(pipelineIdentification)}
@@ -5049,7 +7128,7 @@ async function executePipeline(options) {
5049
7128
  tools,
5050
7129
  onProgress(newOngoingResult) {
5051
7130
  if (isReturned) {
5052
- throw new UnexpectedError(spaceTrim$1((block) => `
7131
+ throw new UnexpectedError(spaceTrim((block) => `
5053
7132
  Can not call \`onProgress\` after pipeline execution is finished
5054
7133
 
5055
7134
  ${block(pipelineIdentification)}
@@ -5065,7 +7144,7 @@ async function executePipeline(options) {
5065
7144
  }
5066
7145
  },
5067
7146
  $executionReport: executionReport,
5068
- pipelineIdentification: spaceTrim$1((block) => `
7147
+ pipelineIdentification: spaceTrim((block) => `
5069
7148
  ${block(pipelineIdentification)}
5070
7149
  Task name: ${currentTask.name}
5071
7150
  Task title: ${currentTask.title}
@@ -5174,7 +7253,7 @@ function createPipelineExecutor(options) {
5174
7253
  preparedPipeline = pipeline;
5175
7254
  }
5176
7255
  else if (isNotPreparedWarningSuppressed !== true) {
5177
- console.warn(spaceTrim$1((block) => `
7256
+ console.warn(spaceTrim((block) => `
5178
7257
  Pipeline is not prepared
5179
7258
 
5180
7259
  ${block(pipelineIdentification)}
@@ -5198,7 +7277,7 @@ function createPipelineExecutor(options) {
5198
7277
  inputParameters,
5199
7278
  tools,
5200
7279
  onProgress,
5201
- pipelineIdentification: spaceTrim$1((block) => `
7280
+ pipelineIdentification: spaceTrim((block) => `
5202
7281
  ${block(pipelineIdentification)}
5203
7282
  ${runCount === 1 ? '' : `Run #${runCount}`}
5204
7283
  `),
@@ -5237,6 +7316,71 @@ function createPipelineExecutor(options) {
5237
7316
  updateOngoingResult(newOngoingResult);
5238
7317
  });
5239
7318
  },
7319
+ tldrProvider(createdAt, status, currentValue, errors) {
7320
+ var _a;
7321
+ // Better progress estimation based on pipeline structure
7322
+ const cv = currentValue;
7323
+ // Handle finished/error states
7324
+ if (status === 'FINISHED') {
7325
+ return {
7326
+ percent: 1,
7327
+ message: 'Finished',
7328
+ };
7329
+ }
7330
+ if (status === 'ERROR') {
7331
+ const errorMessage = errors.length > 0 ? errors[errors.length - 1].message : 'Error';
7332
+ return {
7333
+ percent: 0,
7334
+ message: errorMessage,
7335
+ };
7336
+ }
7337
+ // Calculate progress based on pipeline tasks
7338
+ const totalTasks = pipeline.tasks.length;
7339
+ let completedTasks = 0;
7340
+ let currentTaskName = '';
7341
+ // Check execution report for completed tasks
7342
+ if ((_a = cv === null || cv === void 0 ? void 0 : cv.executionReport) === null || _a === void 0 ? void 0 : _a.promptExecutions) {
7343
+ const executedTaskTitles = new Set(cv.executionReport.promptExecutions.map((execution) => execution.prompt.title));
7344
+ // Count completed tasks by matching titles
7345
+ const completedTasksByTitle = pipeline.tasks.filter(task => executedTaskTitles.has(task.title));
7346
+ completedTasks = completedTasksByTitle.length;
7347
+ // Find current task being executed (first task not yet completed)
7348
+ const remainingTasks = pipeline.tasks.filter(task => !executedTaskTitles.has(task.title));
7349
+ if (remainingTasks.length > 0) {
7350
+ currentTaskName = remainingTasks[0].name;
7351
+ }
7352
+ }
7353
+ // Calculate progress percentage
7354
+ let percent = totalTasks > 0 ? completedTasks / totalTasks : 0;
7355
+ // Add time-based progress for current task (assuming 5 minutes total)
7356
+ if (completedTasks < totalTasks) {
7357
+ const elapsedMs = new Date().getTime() - createdAt.getTime();
7358
+ const totalMs = 5 * 60 * 1000; // 5 minutes
7359
+ const timeProgress = Math.min(elapsedMs / totalMs, 1);
7360
+ // Add partial progress for current task
7361
+ percent += (1 / totalTasks) * timeProgress;
7362
+ }
7363
+ // Clamp to [0,1]
7364
+ percent = Math.min(Math.max(percent, 0), 1);
7365
+ // Generate message
7366
+ let message = '';
7367
+ if (currentTaskName) {
7368
+ // Find the task to get its title
7369
+ const currentTask = pipeline.tasks.find(task => task.name === currentTaskName);
7370
+ const taskTitle = (currentTask === null || currentTask === void 0 ? void 0 : currentTask.title) || currentTaskName;
7371
+ message = `Working on task ${taskTitle}`;
7372
+ }
7373
+ else if (completedTasks === 0) {
7374
+ message = 'Starting pipeline execution';
7375
+ }
7376
+ else {
7377
+ message = `Processing pipeline (${completedTasks}/${totalTasks} tasks completed)`;
7378
+ }
7379
+ return {
7380
+ percent,
7381
+ message,
7382
+ };
7383
+ },
5240
7384
  });
5241
7385
  // <- TODO: Make types such as there is no need to do `as` for `createTask`
5242
7386
  return pipelineExecutor;
@@ -5609,14 +7753,14 @@ function $registeredScrapersMessage(availableScrapers) {
5609
7753
  return { ...metadata, isMetadataAviailable, isInstalled, isAvailableInTools };
5610
7754
  });
5611
7755
  if (metadata.length === 0) {
5612
- return spaceTrim(`
7756
+ return spaceTrim$1(`
5613
7757
  **No scrapers are available**
5614
7758
 
5615
7759
  This is a unexpected behavior, you are probably using some broken version of Promptbook
5616
7760
  At least there should be available the metadata of the scrapers
5617
7761
  `);
5618
7762
  }
5619
- return spaceTrim((block) => `
7763
+ return spaceTrim$1((block) => `
5620
7764
  Available scrapers are:
5621
7765
  ${block(metadata
5622
7766
  .map(({ packageName, className, isMetadataAviailable, isInstalled, mimeTypes, isAvailableInBrowser, isAvailableInTools, }, i) => {
@@ -5835,37 +7979,6 @@ function titleToName(value) {
5835
7979
  return value;
5836
7980
  }
5837
7981
 
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
7982
  /**
5870
7983
  * Factory function that creates a handler for processing knowledge sources.
5871
7984
  * Provides standardized processing of different types of knowledge sources
@@ -5992,7 +8105,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
5992
8105
  const fileExtension = getFileExtension(filename);
5993
8106
  const mimeType = extensionToMimeType(fileExtension || '');
5994
8107
  if (!(await isFileExisting(filename, tools.fs))) {
5995
- throw new NotFoundError(spaceTrim((block) => `
8108
+ throw new NotFoundError(spaceTrim$1((block) => `
5996
8109
  Can not make source handler for file which does not exist:
5997
8110
 
5998
8111
  File:
@@ -6079,7 +8192,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
6079
8192
  // <- TODO: [🪓] Here should be no need for spreading new array, just `partialPieces = partialPiecesUnchecked`
6080
8193
  break;
6081
8194
  }
6082
- console.warn(spaceTrim((block) => `
8195
+ console.warn(spaceTrim$1((block) => `
6083
8196
  Cannot scrape knowledge from source despite the scraper \`${scraper.metadata.className}\` supports the mime type "${sourceHandler.mimeType}".
6084
8197
 
6085
8198
  The source:
@@ -6095,7 +8208,7 @@ async function prepareKnowledgePieces(knowledgeSources, tools, options) {
6095
8208
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
6096
8209
  }
6097
8210
  if (partialPieces === null) {
6098
- throw new KnowledgeScrapeError(spaceTrim((block) => `
8211
+ throw new KnowledgeScrapeError(spaceTrim$1((block) => `
6099
8212
  Cannot scrape knowledge
6100
8213
 
6101
8214
  The source:
@@ -6174,7 +8287,7 @@ async function prepareTasks(pipeline, tools, options) {
6174
8287
  if (task.taskType === 'PROMPT_TASK' &&
6175
8288
  knowledgePiecesCount > 0 &&
6176
8289
  !dependentParameterNames.includes('knowledge')) {
6177
- preparedContent = spaceTrim$1(`
8290
+ preparedContent = spaceTrim(`
6178
8291
  {content}
6179
8292
 
6180
8293
  ## Knowledge
@@ -6433,7 +8546,7 @@ const knowledgeCommandParser = {
6433
8546
  */
6434
8547
  parse(input) {
6435
8548
  const { args } = input;
6436
- const knowledgeSourceContent = spaceTrim(args[0] || '');
8549
+ const knowledgeSourceContent = spaceTrim$1(args[0] || '');
6437
8550
  if (knowledgeSourceContent === '') {
6438
8551
  throw new ParseError(`Source is not defined`);
6439
8552
  }
@@ -6577,7 +8690,7 @@ const sectionCommandParser = {
6577
8690
  normalized = normalized.split('DIALOGUE').join('DIALOG');
6578
8691
  const taskTypes = SectionTypes.filter((sectionType) => normalized.includes(sectionType.split('_TASK').join('')));
6579
8692
  if (taskTypes.length !== 1) {
6580
- throw new ParseError(spaceTrim((block) => `
8693
+ throw new ParseError(spaceTrim$1((block) => `
6581
8694
  Unknown section type "${normalized}"
6582
8695
 
6583
8696
  Supported section types are:
@@ -6597,7 +8710,7 @@ const sectionCommandParser = {
6597
8710
  */
6598
8711
  $applyToTaskJson(command, $taskJson, $pipelineJson) {
6599
8712
  if ($taskJson.isSectionTypeSet === true) {
6600
- throw new ParseError(spaceTrim(`
8713
+ throw new ParseError(spaceTrim$1(`
6601
8714
  Section type is already defined in the section.
6602
8715
  It can be defined only once.
6603
8716
  `));
@@ -6945,7 +9058,7 @@ const expectCommandParser = {
6945
9058
  /**
6946
9059
  * Description of the FORMAT command
6947
9060
  */
6948
- description: spaceTrim(`
9061
+ description: spaceTrim$1(`
6949
9062
  Expect command describes the desired output of the task *(after post-processing)*
6950
9063
  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.
6951
9064
  `),
@@ -7019,7 +9132,7 @@ const expectCommandParser = {
7019
9132
  }
7020
9133
  catch (error) {
7021
9134
  assertsError(error);
7022
- throw new ParseError(spaceTrim((block) => `
9135
+ throw new ParseError(spaceTrim$1((block) => `
7023
9136
  Invalid FORMAT command
7024
9137
  ${block(error.message)}:
7025
9138
  `));
@@ -7204,7 +9317,7 @@ function validateParameterName(parameterName) {
7204
9317
  if (!(error instanceof ParseError)) {
7205
9318
  throw error;
7206
9319
  }
7207
- throw new ParseError(spaceTrim((block) => `
9320
+ throw new ParseError(spaceTrim$1((block) => `
7208
9321
  ${block(error.message)}
7209
9322
 
7210
9323
  Tried to validate parameter name:
@@ -7263,7 +9376,7 @@ const foreachCommandParser = {
7263
9376
  const assignSign = args[3];
7264
9377
  const formatDefinition = FORMAT_DEFINITIONS.find((formatDefinition) => [formatDefinition.formatName, ...(formatDefinition.aliases || [])].includes(formatName));
7265
9378
  if (formatDefinition === undefined) {
7266
- throw new ParseError(spaceTrim((block) => `
9379
+ throw new ParseError(spaceTrim$1((block) => `
7267
9380
  Unsupported format "${formatName}"
7268
9381
 
7269
9382
  Available formats:
@@ -7275,7 +9388,7 @@ const foreachCommandParser = {
7275
9388
  }
7276
9389
  const subvalueParser = formatDefinition.subvalueParsers.find((subvalueParser) => [subvalueParser.subvalueName, ...(subvalueParser.aliases || [])].includes(subformatName));
7277
9390
  if (subvalueParser === undefined) {
7278
- throw new ParseError(spaceTrim((block) => `
9391
+ throw new ParseError(spaceTrim$1((block) => `
7279
9392
  Unsupported subformat name "${subformatName}" for format "${formatName}"
7280
9393
 
7281
9394
  Available subformat names for format "${formatDefinition.formatName}":
@@ -7323,7 +9436,7 @@ const foreachCommandParser = {
7323
9436
  outputSubparameterName = 'newLine';
7324
9437
  }
7325
9438
  else {
7326
- throw new ParseError(spaceTrim(`
9439
+ throw new ParseError(spaceTrim$1(`
7327
9440
  FOREACH ${formatName} ${subformatName} must specify output subparameter
7328
9441
 
7329
9442
  Correct example:
@@ -7399,7 +9512,7 @@ const formatCommandParser = {
7399
9512
  /**
7400
9513
  * Description of the FORMAT command
7401
9514
  */
7402
- description: spaceTrim(`
9515
+ description: spaceTrim$1(`
7403
9516
  Format command describes the desired output of the task (after post-processing)
7404
9517
  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.
7405
9518
  `),
@@ -7771,7 +9884,7 @@ const formfactorCommandParser = {
7771
9884
  const formfactorNameCandidate = args[0].toUpperCase();
7772
9885
  const formfactor = FORMFACTOR_DEFINITIONS.find((definition) => [definition.name, ...{ aliasNames: [], ...definition }.aliasNames].includes(formfactorNameCandidate));
7773
9886
  if (formfactor === undefined) {
7774
- throw new ParseError(spaceTrim((block) => `
9887
+ throw new ParseError(spaceTrim$1((block) => `
7775
9888
  Unknown formfactor name "${formfactorNameCandidate}"
7776
9889
 
7777
9890
  Available formfactors:
@@ -7790,7 +9903,7 @@ const formfactorCommandParser = {
7790
9903
  */
7791
9904
  $applyToPipelineJson(command, $pipelineJson) {
7792
9905
  if ($pipelineJson.formfactorName !== undefined && $pipelineJson.formfactorName !== command.formfactorName) {
7793
- throw new ParseError(spaceTrim(`
9906
+ throw new ParseError(spaceTrim$1(`
7794
9907
  Redefinition of \`FORMFACTOR\` in the pipeline head
7795
9908
 
7796
9909
  You have used:
@@ -7933,7 +10046,7 @@ const modelCommandParser = {
7933
10046
  */
7934
10047
  parse(input) {
7935
10048
  const { args, normalized } = input;
7936
- const availableVariantsMessage = spaceTrim((block) => `
10049
+ const availableVariantsMessage = spaceTrim$1((block) => `
7937
10050
  Available variants are:
7938
10051
  ${block(MODEL_VARIANTS.map((variantName) => `- ${variantName}${variantName !== 'EMBEDDING' ? '' : ' (Not available in pipeline)'}`).join('\n'))}
7939
10052
  `);
@@ -7955,14 +10068,14 @@ const modelCommandParser = {
7955
10068
  // <- Note: [🤖]
7956
10069
  }
7957
10070
  else if (normalized.startsWith('MODEL_VARIANT_EMBED')) {
7958
- spaceTrim((block) => `
10071
+ spaceTrim$1((block) => `
7959
10072
  Embedding model can not be used in pipeline
7960
10073
 
7961
10074
  ${block(availableVariantsMessage)}
7962
10075
  `);
7963
10076
  }
7964
10077
  else {
7965
- throw new ParseError(spaceTrim((block) => `
10078
+ throw new ParseError(spaceTrim$1((block) => `
7966
10079
  Unknown model variant in command:
7967
10080
 
7968
10081
  ${block(availableVariantsMessage)}
@@ -7977,7 +10090,7 @@ const modelCommandParser = {
7977
10090
  };
7978
10091
  }
7979
10092
  else {
7980
- throw new ParseError(spaceTrim((block) => `
10093
+ throw new ParseError(spaceTrim$1((block) => `
7981
10094
  Unknown model key in command.
7982
10095
 
7983
10096
  Supported model keys are:
@@ -8004,7 +10117,7 @@ const modelCommandParser = {
8004
10117
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
8005
10118
  }
8006
10119
  else {
8007
- throw new ParseError(spaceTrim(`
10120
+ throw new ParseError(spaceTrim$1(`
8008
10121
  Redefinition of \`MODEL ${command.key}\` in the pipeline head
8009
10122
 
8010
10123
  You have used:
@@ -8036,7 +10149,7 @@ const modelCommandParser = {
8036
10149
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
8037
10150
  }
8038
10151
  else {
8039
- throw new ParseError(spaceTrim(`
10152
+ throw new ParseError(spaceTrim$1(`
8040
10153
  Redefinition of MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}"
8041
10154
 
8042
10155
  You have used:
@@ -8046,7 +10159,7 @@ const modelCommandParser = {
8046
10159
  }
8047
10160
  }
8048
10161
  if (command.value === ($pipelineJson.defaultModelRequirements || {})[command.key]) {
8049
- console.log(spaceTrim(`
10162
+ console.log(spaceTrim$1(`
8050
10163
  Setting MODEL \`${command.key}\` in the task "${$taskJson.title || $taskJson.name}" to the same value as in the pipeline head
8051
10164
 
8052
10165
  In pipeline head:
@@ -8129,7 +10242,7 @@ const parameterCommandParser = {
8129
10242
  // <- TODO: When [🥶] fixed, change to:
8130
10243
  // > const parameterDescriptionRaw = rawArgs.split(parameterNameRaw).join('').trim();
8131
10244
  if (parameterDescriptionRaw && parameterDescriptionRaw.match(/\{(?<embeddedParameterName>[a-z0-9_]+)\}/im)) {
8132
- throw new ParseError(spaceTrim((block) => `
10245
+ throw new ParseError(spaceTrim$1((block) => `
8133
10246
  Parameter \`{${parameterNameRaw}}\` can not contain another parameter in description
8134
10247
 
8135
10248
  The description:
@@ -8311,7 +10424,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
8311
10424
  persona.description = personaDescription;
8312
10425
  return;
8313
10426
  }
8314
- console.warn(spaceTrim(`
10427
+ console.warn(spaceTrim$1(`
8315
10428
 
8316
10429
  Persona "${personaName}" is defined multiple times with different description:
8317
10430
 
@@ -8322,7 +10435,7 @@ function $applyToTaskJson(command, $taskJson, $pipelineJson) {
8322
10435
  ${personaDescription}
8323
10436
 
8324
10437
  `));
8325
- persona.description += spaceTrim('\n\n' + personaDescription);
10438
+ persona.description += spaceTrim$1('\n\n' + personaDescription);
8326
10439
  }
8327
10440
 
8328
10441
  /**
@@ -8687,7 +10800,7 @@ const COMMANDS = [
8687
10800
  function getParserForCommand(command) {
8688
10801
  const commandParser = COMMANDS.find((commandParser) => commandParser.name === command.type);
8689
10802
  if (commandParser === undefined) {
8690
- throw new UnexpectedError(spaceTrim$1((block) => `
10803
+ throw new UnexpectedError(spaceTrim((block) => `
8691
10804
  Command ${command.type} parser is not found
8692
10805
 
8693
10806
  ${block(JSON.stringify(command, null, 4)
@@ -8763,7 +10876,7 @@ function parseCommand(raw, usagePlace) {
8763
10876
  .map(removeMarkdownFormatting)
8764
10877
  .map((item) => item.trim());
8765
10878
  if (items.length === 0 || items[0] === '') {
8766
- throw new ParseError(spaceTrim$1((block) => `
10879
+ throw new ParseError(spaceTrim((block) => `
8767
10880
  Malformed command:
8768
10881
  - ${raw}
8769
10882
 
@@ -8799,7 +10912,7 @@ function parseCommand(raw, usagePlace) {
8799
10912
  return command;
8800
10913
  }
8801
10914
  }
8802
- throw new ParseError(spaceTrim$1((block) => `
10915
+ throw new ParseError(spaceTrim((block) => `
8803
10916
  Malformed or unknown command:
8804
10917
  - ${raw}
8805
10918
 
@@ -8850,7 +10963,7 @@ function parseCommandVariant(input) {
8850
10963
  if (!(error instanceof ParseError)) {
8851
10964
  throw error;
8852
10965
  }
8853
- throw new ParseError(spaceTrim$1((block) => `
10966
+ throw new ParseError(spaceTrim((block) => `
8854
10967
  Invalid ${commandName} command:
8855
10968
 
8856
10969
  Your command:
@@ -9124,7 +11237,7 @@ const SUPPORTED_SCRIPT_LANGUAGES = ['javascript', 'typescript', 'python'];
9124
11237
  * @public exported from `@promptbook/markdown-utils`
9125
11238
  */
9126
11239
  function removeMarkdownComments(content) {
9127
- return spaceTrim$1(content.replace(/<!--(.*?)-->/gs, ''));
11240
+ return spaceTrim(content.replace(/<!--(.*?)-->/gs, ''));
9128
11241
  }
9129
11242
 
9130
11243
  /**
@@ -9135,7 +11248,7 @@ function removeMarkdownComments(content) {
9135
11248
  */
9136
11249
  function isFlatPipeline(pipelineString) {
9137
11250
  pipelineString = removeMarkdownComments(pipelineString);
9138
- pipelineString = spaceTrim(pipelineString);
11251
+ pipelineString = spaceTrim$1(pipelineString);
9139
11252
  const isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
9140
11253
  //const isLastLineReturnStatement = pipelineString.split('\n').pop()!.split('`').join('').startsWith('->');
9141
11254
  const isBacktickBlockUsed = pipelineString.includes('```');
@@ -9173,19 +11286,19 @@ function deflatePipeline(pipelineString) {
9173
11286
  returnStatement = `-> {${DEFAULT_BOOK_OUTPUT_PARAMETER_NAME}}`;
9174
11287
  pipelineStringLines.push(potentialReturnStatement);
9175
11288
  }
9176
- const prompt = spaceTrim(pipelineStringLines.join('\n'));
11289
+ const prompt = spaceTrim$1(pipelineStringLines.join('\n'));
9177
11290
  let quotedPrompt;
9178
11291
  if (prompt.split('\n').length <= 1) {
9179
11292
  quotedPrompt = `> ${prompt}`;
9180
11293
  }
9181
11294
  else {
9182
- quotedPrompt = spaceTrim((block) => `
11295
+ quotedPrompt = spaceTrim$1((block) => `
9183
11296
  \`\`\`
9184
11297
  ${block(prompt.split('`').join('\\`'))}
9185
11298
  \`\`\`
9186
11299
  `);
9187
11300
  }
9188
- pipelineString = validatePipelineString(spaceTrim((block) => `
11301
+ pipelineString = validatePipelineString(spaceTrim$1((block) => `
9189
11302
  # ${DEFAULT_BOOK_TITLE}
9190
11303
 
9191
11304
  ## Prompt
@@ -9249,7 +11362,7 @@ function extractAllListItemsFromMarkdown(markdown) {
9249
11362
  function extractOneBlockFromMarkdown(markdown) {
9250
11363
  const codeBlocks = extractAllBlocksFromMarkdown(markdown);
9251
11364
  if (codeBlocks.length !== 1) {
9252
- throw new ParseError(spaceTrim((block) => `
11365
+ throw new ParseError(spaceTrim$1((block) => `
9253
11366
  There should be exactly 1 code block in task section, found ${codeBlocks.length} code blocks
9254
11367
 
9255
11368
  ${block(codeBlocks.map((block, i) => `Block ${i + 1}:\n${block.content}`).join('\n\n\n'))}
@@ -9274,7 +11387,7 @@ function parseMarkdownSection(value) {
9274
11387
  }
9275
11388
  const title = lines[0].replace(/^#+\s*/, '');
9276
11389
  const level = (_b = (_a = lines[0].match(/^#+/)) === null || _a === void 0 ? void 0 : _a[0].length) !== null && _b !== void 0 ? _b : 0;
9277
- const content = spaceTrim(lines.slice(1).join('\n'));
11390
+ const content = spaceTrim$1(lines.slice(1).join('\n'));
9278
11391
  if (level < 1 || level > 6) {
9279
11392
  throw new ParseError('Markdown section must have heading level between 1 and 6');
9280
11393
  }
@@ -9302,7 +11415,7 @@ function splitMarkdownIntoSections(markdown) {
9302
11415
  if (buffer.length === 0) {
9303
11416
  return;
9304
11417
  }
9305
- let section = spaceTrim(buffer.join('\n'));
11418
+ let section = spaceTrim$1(buffer.join('\n'));
9306
11419
  if (section === '') {
9307
11420
  return;
9308
11421
  }
@@ -9377,7 +11490,7 @@ function flattenMarkdown(markdown) {
9377
11490
  flattenedMarkdown += `## ${title}` + `\n\n`;
9378
11491
  flattenedMarkdown += content + `\n\n`; // <- [🧠] Maybe 3 new lines?
9379
11492
  }
9380
- return spaceTrim(flattenedMarkdown);
11493
+ return spaceTrim$1(flattenedMarkdown);
9381
11494
  }
9382
11495
  /**
9383
11496
  * TODO: [🏛] This can be part of markdown builder
@@ -9439,7 +11552,7 @@ function parsePipeline(pipelineString) {
9439
11552
  if (pipelineString.startsWith('#!')) {
9440
11553
  const [shebangLine, ...restLines] = pipelineString.split('\n');
9441
11554
  if (!(shebangLine || '').includes('ptbk')) {
9442
- throw new ParseError(spaceTrim$1((block) => `
11555
+ throw new ParseError(spaceTrim((block) => `
9443
11556
  It seems that you try to parse a book file which has non-standard shebang line for book files:
9444
11557
  Shebang line must contain 'ptbk'
9445
11558
 
@@ -9455,7 +11568,7 @@ function parsePipeline(pipelineString) {
9455
11568
  pipelineString = validatePipelineString(restLines.join('\n'));
9456
11569
  }
9457
11570
  pipelineString = removeMarkdownComments(pipelineString);
9458
- pipelineString = spaceTrim$1(pipelineString);
11571
+ pipelineString = spaceTrim(pipelineString);
9459
11572
  // <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
9460
11573
  pipelineString = deflatePipeline(pipelineString);
9461
11574
  // ==============
@@ -9467,7 +11580,7 @@ function parsePipeline(pipelineString) {
9467
11580
  // ==============
9468
11581
  // Note: 1️⃣◽4️⃣ Check markdown structure
9469
11582
  if (pipelineHead === undefined) {
9470
- throw new UnexpectedError(spaceTrim$1((block) => `
11583
+ throw new UnexpectedError(spaceTrim((block) => `
9471
11584
  Pipeline head is not defined
9472
11585
 
9473
11586
  ${block(getPipelineIdentification())}
@@ -9476,7 +11589,7 @@ function parsePipeline(pipelineString) {
9476
11589
  `));
9477
11590
  }
9478
11591
  if (pipelineHead.level !== 1) {
9479
- throw new UnexpectedError(spaceTrim$1((block) => `
11592
+ throw new UnexpectedError(spaceTrim((block) => `
9480
11593
  Pipeline head is not h1
9481
11594
 
9482
11595
  ${block(getPipelineIdentification())}
@@ -9485,7 +11598,7 @@ function parsePipeline(pipelineString) {
9485
11598
  `));
9486
11599
  }
9487
11600
  if (!pipelineSections.every((section) => section.level === 2)) {
9488
- throw new UnexpectedError(spaceTrim$1((block) => `
11601
+ throw new UnexpectedError(spaceTrim((block) => `
9489
11602
  Not every pipeline section is h2
9490
11603
 
9491
11604
  ${block(getPipelineIdentification())}
@@ -9498,7 +11611,7 @@ function parsePipeline(pipelineString) {
9498
11611
  const defineParam = (parameterCommand) => {
9499
11612
  const { parameterName, parameterDescription, isInput, isOutput } = parameterCommand;
9500
11613
  if (RESERVED_PARAMETER_NAMES.includes(parameterName)) {
9501
- throw new ParseError(spaceTrim$1((block) => `
11614
+ throw new ParseError(spaceTrim((block) => `
9502
11615
  Parameter name {${parameterName}} is reserved and cannot be used as resulting parameter name
9503
11616
 
9504
11617
  ${block(getPipelineIdentification())}
@@ -9509,7 +11622,7 @@ function parsePipeline(pipelineString) {
9509
11622
  existingParameter.description &&
9510
11623
  existingParameter.description !== parameterDescription &&
9511
11624
  parameterDescription) {
9512
- throw new ParseError(spaceTrim$1((block) => `
11625
+ throw new ParseError(spaceTrim((block) => `
9513
11626
  Parameter \`{${parameterName}}\` is defined multiple times with different description:
9514
11627
 
9515
11628
  ${block(getPipelineIdentification())}
@@ -9547,7 +11660,7 @@ function parsePipeline(pipelineString) {
9547
11660
  description = description.split(/^>.*$/gm).join('');
9548
11661
  //Note: Remove lists and return statement - TODO: [🎾] Make util (exported from `@promptbool/utils`)
9549
11662
  description = description.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
9550
- description = spaceTrim$1(description);
11663
+ description = spaceTrim(description);
9551
11664
  if (description === '') {
9552
11665
  description = undefined;
9553
11666
  }
@@ -9558,7 +11671,7 @@ function parsePipeline(pipelineString) {
9558
11671
  const command = parseCommand(listItem, 'PIPELINE_HEAD');
9559
11672
  const commandParser = getParserForCommand(command);
9560
11673
  if (commandParser.isUsedInPipelineHead !== true /* <- Note: [🦦][4] */) {
9561
- throw new ParseError(spaceTrim$1((block) => `
11674
+ throw new ParseError(spaceTrim((block) => `
9562
11675
  Command \`${command.type}\` is not allowed in the head of the pipeline ONLY at the pipeline task
9563
11676
 
9564
11677
  ${block(getPipelineIdentification())}
@@ -9572,7 +11685,7 @@ function parsePipeline(pipelineString) {
9572
11685
  if (!(error instanceof ParseError)) {
9573
11686
  throw error;
9574
11687
  }
9575
- throw new ParseError(spaceTrim$1((block) => `
11688
+ throw new ParseError(spaceTrim((block) => `
9576
11689
  Command ${command.type} failed to apply to the pipeline
9577
11690
 
9578
11691
  The error:
@@ -9625,7 +11738,7 @@ function parsePipeline(pipelineString) {
9625
11738
  description = description.split(/^>.*$/gm).join('');
9626
11739
  //Note: Remove lists and return statement - TODO: [🎾]
9627
11740
  description = description.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
9628
- description = spaceTrim$1(description);
11741
+ description = spaceTrim(description);
9629
11742
  if (description === '') {
9630
11743
  description = undefined;
9631
11744
  }
@@ -9659,7 +11772,7 @@ function parsePipeline(pipelineString) {
9659
11772
  for (const { listItem, command } of commands) {
9660
11773
  const commandParser = getParserForCommand(command);
9661
11774
  if (commandParser.isUsedInPipelineTask !== true /* <- Note: [🦦][4] */) {
9662
- throw new ParseError(spaceTrim$1((block) => `
11775
+ throw new ParseError(spaceTrim((block) => `
9663
11776
  Command \`${command.type}\` is not allowed in the task of the promptbook ONLY at the pipeline head
9664
11777
 
9665
11778
  ${block(getPipelineIdentification())}
@@ -9674,7 +11787,7 @@ function parsePipeline(pipelineString) {
9674
11787
  if (!(error instanceof ParseError)) {
9675
11788
  throw error;
9676
11789
  }
9677
- throw new ParseError(spaceTrim$1((block) => `
11790
+ throw new ParseError(spaceTrim((block) => `
9678
11791
  Command \`${command.type}\` failed to apply to the task
9679
11792
 
9680
11793
  The error:
@@ -9705,14 +11818,14 @@ function parsePipeline(pipelineString) {
9705
11818
  // TODO: [🍧] Should be done in SECTION command
9706
11819
  if ($taskJson.taskType === 'SCRIPT_TASK') {
9707
11820
  if (!language) {
9708
- throw new ParseError(spaceTrim$1((block) => `
11821
+ throw new ParseError(spaceTrim((block) => `
9709
11822
  You must specify the language of the script in the \`SCRIPT\` task
9710
11823
 
9711
11824
  ${block(getPipelineIdentification())}
9712
11825
  `));
9713
11826
  }
9714
11827
  if (!SUPPORTED_SCRIPT_LANGUAGES.includes(language)) {
9715
- throw new ParseError(spaceTrim$1((block) => `
11828
+ throw new ParseError(spaceTrim((block) => `
9716
11829
  Script language ${language} is not supported.
9717
11830
 
9718
11831
  Supported languages are:
@@ -9874,7 +11987,7 @@ function addAutoGeneratedSection(content, options) {
9874
11987
  const warningLine = `<!-- ${GENERATOR_WARNING} -->`;
9875
11988
  const sectionRegex = new RegExp(`<!--${sectionName}-->([\\s\\S]*?)<!--/${sectionName}-->`, 'g');
9876
11989
  const sectionMatch = content.match(sectionRegex);
9877
- const contentToInsert = spaceTrim$1((block) => `
11990
+ const contentToInsert = spaceTrim((block) => `
9878
11991
  <!--${sectionName}-->
9879
11992
  ${block(warningLine)}
9880
11993
  ${block(sectionContent)}
@@ -9887,7 +12000,7 @@ function addAutoGeneratedSection(content, options) {
9887
12000
  const placeForSection = removeMarkdownComments(content).match(/^##.*$/im);
9888
12001
  if (placeForSection !== null) {
9889
12002
  const [heading] = placeForSection;
9890
- return content.replace(heading, spaceTrim$1((block) => `
12003
+ return content.replace(heading, spaceTrim((block) => `
9891
12004
  ${block(contentToInsert)}
9892
12005
 
9893
12006
  ${block(heading)}
@@ -9896,7 +12009,7 @@ function addAutoGeneratedSection(content, options) {
9896
12009
  console.warn(`No place where to put the section <!--${sectionName}-->, using the end of the file`);
9897
12010
  // <- TODO: [🏮] Some standard way how to transform errors into warnings and how to handle non-critical fails during the tasks
9898
12011
  // <- TODO: [🏮] Some better way how to get warnings from pipeline parsing / logic
9899
- return spaceTrim$1((block) => `
12012
+ return spaceTrim((block) => `
9900
12013
  ${block(content)}
9901
12014
 
9902
12015
  ${block(contentToInsert)}
@@ -9972,7 +12085,7 @@ function renderPromptbookMermaid(pipelineJson, options) {
9972
12085
  .filter(([MERMAID_NAME]) => (inputAndIntermediateParametersMermaid + outputParametersMermaid).includes(MERMAID_NAME))
9973
12086
  .map(([MERMAID_NAME, title]) => `${MERMAID_NAME}((${title})):::${MERMAID_NAME}`)
9974
12087
  .join('\n');
9975
- const promptbookMermaid = spaceTrim$1((block) => `
12088
+ const promptbookMermaid = spaceTrim((block) => `
9976
12089
 
9977
12090
  %% 🔮 Tip: Open this on GitHub or in the VSCode website to see the Mermaid graph visually
9978
12091
 
@@ -10028,7 +12141,7 @@ async function prettifyPipelineString(pipelineString, options) {
10028
12141
  return { href: `#${task.name}`, title: task.title };
10029
12142
  },
10030
12143
  });
10031
- const promptbookMermaidBlock = spaceTrim$1((block) => `
12144
+ const promptbookMermaidBlock = spaceTrim((block) => `
10032
12145
  \`\`\`mermaid
10033
12146
  ${block(promptbookMermaid)}
10034
12147
  \`\`\`
@@ -10066,7 +12179,7 @@ class CallbackInterfaceTools {
10066
12179
  async promptDialog(options) {
10067
12180
  const answer = await this.options.callback(options);
10068
12181
  if (this.options.isVerbose) {
10069
- console.info(spaceTrim$1((block) => `
12182
+ console.info(spaceTrim((block) => `
10070
12183
  📖 ${block(options.promptTitle)}
10071
12184
  👤 ${block(answer)}
10072
12185
  `));
@@ -10205,7 +12318,7 @@ function countWorkingDuration(items) {
10205
12318
  function executionReportJsonToString(executionReportJson, options) {
10206
12319
  var _a, _b, _c, _d, _e, _f;
10207
12320
  const { taxRate, chartsWidth } = { ...ExecutionReportStringOptionsDefaults, ...(options || {}) };
10208
- let executionReportString = spaceTrim$1((block) => `
12321
+ let executionReportString = spaceTrim((block) => `
10209
12322
  # ${executionReportJson.title || 'Execution report'}
10210
12323
 
10211
12324
  ${block(executionReportJson.description || '')}
@@ -10327,7 +12440,7 @@ function executionReportJsonToString(executionReportJson, options) {
10327
12440
  if (just(true)) {
10328
12441
  executionReportString +=
10329
12442
  '\n\n\n\n' +
10330
- spaceTrim$1((block) => {
12443
+ spaceTrim((block) => {
10331
12444
  var _a;
10332
12445
  return `
10333
12446
 
@@ -10346,7 +12459,7 @@ function executionReportJsonToString(executionReportJson, options) {
10346
12459
  executionReportString += '*No result*';
10347
12460
  }
10348
12461
  else if (typeof promptExecution.result.content === 'string') {
10349
- executionReportString += spaceTrim$1((block) => `
12462
+ executionReportString += spaceTrim((block) => `
10350
12463
  \`\`\`
10351
12464
  ${block(escapeMarkdownBlock(promptExecution.result.content))}
10352
12465
  \`\`\`
@@ -10359,7 +12472,7 @@ function executionReportJsonToString(executionReportJson, options) {
10359
12472
  if (promptExecution.error && promptExecution.error.message) {
10360
12473
  executionReportString +=
10361
12474
  '\n\n\n\n' +
10362
- spaceTrim$1((block) => `
12475
+ spaceTrim((block) => `
10363
12476
 
10364
12477
  ### Error
10365
12478
 
@@ -10435,7 +12548,7 @@ function usageToHuman(usage) {
10435
12548
  // Note: For negligible usage, we report at least something
10436
12549
  reportItems.push('Negligible');
10437
12550
  }
10438
- return spaceTrim((block) => `
12551
+ return spaceTrim$1((block) => `
10439
12552
  Usage:
10440
12553
  ${block(reportItems.map((item) => `- ${item}`).join('\n'))}
10441
12554
  `);
@@ -10680,13 +12793,13 @@ function $registeredLlmToolsMessage() {
10680
12793
  });
10681
12794
  const usedEnvMessage = `Unknown \`.env\` file` ;
10682
12795
  if (metadata.length === 0) {
10683
- return spaceTrim((block) => `
12796
+ return spaceTrim$1((block) => `
10684
12797
  No LLM providers are available.
10685
12798
 
10686
12799
  ${block(usedEnvMessage)}
10687
12800
  `);
10688
12801
  }
10689
- return spaceTrim((block) => `
12802
+ return spaceTrim$1((block) => `
10690
12803
 
10691
12804
  ${block(usedEnvMessage)}
10692
12805
 
@@ -10732,7 +12845,7 @@ function $registeredLlmToolsMessage() {
10732
12845
  morePieces.push(`Not configured`); // <- Note: Can not be configured via environment variables
10733
12846
  }
10734
12847
  }
10735
- let providerMessage = spaceTrim(`
12848
+ let providerMessage = spaceTrim$1(`
10736
12849
  ${i + 1}) **${title}** \`${className}\` from \`${packageName}\`
10737
12850
  ${morePieces.join('; ')}
10738
12851
  `);
@@ -10778,7 +12891,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
10778
12891
  .find(({ packageName, className }) => llmConfiguration.packageName === packageName && llmConfiguration.className === className);
10779
12892
  if (registeredItem === undefined) {
10780
12893
  // console.log('$llmToolsRegister.list()', $llmToolsRegister.list());
10781
- throw new Error(spaceTrim((block) => `
12894
+ throw new Error(spaceTrim$1((block) => `
10782
12895
  There is no constructor for LLM provider \`${llmConfiguration.className}\` from \`${llmConfiguration.packageName}\`
10783
12896
  Running in ${!$isRunningInBrowser() ? '' : 'browser environment'}${!$isRunningInNode() ? '' : 'node environment'}${!$isRunningInWebWorker() ? '' : 'worker environment'}
10784
12897
 
@@ -10915,7 +13028,7 @@ function cacheLlmTools(llmTools, options = {}) {
10915
13028
  let normalizedContent = content;
10916
13029
  normalizedContent = normalizedContent.replace(/\s+/g, ' ');
10917
13030
  normalizedContent = normalizedContent.split('\r\n').join('\n');
10918
- normalizedContent = spaceTrim(normalizedContent);
13031
+ normalizedContent = spaceTrim$1(normalizedContent);
10919
13032
  // Note: Do not need to save everything in the cache, just the relevant parameters
10920
13033
  const relevantParameterNames = extractParameterNames(content);
10921
13034
  const relevantParameters = Object.fromEntries(Object.entries(parameters).filter(([key]) => relevantParameterNames.has(key)));
@@ -11595,7 +13708,7 @@ function isValidPipelineString(pipelineString) {
11595
13708
  */
11596
13709
  function prompt(strings, ...values) {
11597
13710
  if (values.length === 0) {
11598
- return spaceTrim(strings.join(''));
13711
+ return spaceTrim$1(strings.join(''));
11599
13712
  }
11600
13713
  const stringsWithHiddenParameters = strings.map((stringsItem) =>
11601
13714
  // TODO: [0] DRY
@@ -11606,7 +13719,7 @@ function prompt(strings, ...values) {
11606
13719
  let pipelineString = stringsWithHiddenParameters.reduce((result, stringsItem, i) => placeholderParameterNames[i] === undefined
11607
13720
  ? `${result}${stringsItem}`
11608
13721
  : `${result}${stringsItem}{${placeholderParameterNames[i]}}`, '');
11609
- pipelineString = spaceTrim(pipelineString);
13722
+ pipelineString = spaceTrim$1(pipelineString);
11610
13723
  try {
11611
13724
  pipelineString = templateParameters(pipelineString, parameters);
11612
13725
  }
@@ -11615,7 +13728,7 @@ function prompt(strings, ...values) {
11615
13728
  throw error;
11616
13729
  }
11617
13730
  console.error({ pipelineString, parameters, placeholderParameterNames, error });
11618
- throw new UnexpectedError(spaceTrim((block) => `
13731
+ throw new UnexpectedError(spaceTrim$1((block) => `
11619
13732
  Internal error in prompt template literal
11620
13733
 
11621
13734
  ${block(JSON.stringify({ strings, values }, null, 4))}}
@@ -11649,18 +13762,28 @@ function prompt(strings, ...values) {
11649
13762
  * @public exported from `@promptbook/core`
11650
13763
  */
11651
13764
  function book(strings, ...values) {
11652
- const pipelineString = prompt(strings, ...values);
11653
- if (!isValidPipelineString(pipelineString)) {
13765
+ const bookString = prompt(strings, ...values);
13766
+ if (!isValidPipelineString(bookString)) {
11654
13767
  // TODO: Make the CustomError for this
11655
- throw new Error(spaceTrim(`
13768
+ throw new Error(spaceTrim$1(`
11656
13769
  The string is not a valid pipeline string
11657
13770
 
11658
13771
  book\`
11659
- ${pipelineString}
13772
+ ${bookString}
11660
13773
  \`
11661
13774
  `));
11662
13775
  }
11663
- return pipelineString;
13776
+ if (!isValidBook(bookString)) {
13777
+ // TODO: Make the CustomError for this
13778
+ throw new Error(spaceTrim$1(`
13779
+ The string is not a valid book
13780
+
13781
+ book\`
13782
+ ${bookString}
13783
+ \`
13784
+ `));
13785
+ }
13786
+ return bookString;
11664
13787
  }
11665
13788
  /**
11666
13789
  * TODO: [🧠][🈴] Where is the best location for this file
@@ -11990,5 +14113,5 @@ class PrefixStorage {
11990
14113
  }
11991
14114
  }
11992
14115
 
11993
- 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 };
14116
+ 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_SIMULATED_DURATION_MS, 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 };
11994
14117
  //# sourceMappingURL=index.es.js.map