@promptbook/core 0.81.0-21 → 0.81.0-23

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 (36) hide show
  1. package/README.md +4 -20
  2. package/esm/index.es.js +145 -115
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +2 -0
  6. package/esm/typings/src/cli/cli-commands/make.d.ts +1 -1
  7. package/esm/typings/src/cli/cli-commands/run.d.ts +2 -2
  8. package/esm/typings/src/collection/constructors/createCollectionFromDirectory.d.ts +11 -0
  9. package/esm/typings/src/collection/constructors/createCollectionFromUrl.d.ts +1 -1
  10. package/esm/typings/src/commands/index.d.ts +1 -1
  11. package/esm/typings/src/config.d.ts +2 -2
  12. package/esm/typings/src/conversion/parsePipeline.d.ts +1 -1
  13. package/esm/typings/src/conversion/prettify/renderPipelineMermaidOptions.d.ts +3 -3
  14. package/esm/typings/src/conversion/validation/validatePipeline.d.ts +7 -7
  15. package/esm/typings/src/errors/utils/getErrorReportUrl.d.ts +1 -1
  16. package/esm/typings/src/llm-providers/anthropic-claude/anthropic-claude-models.d.ts +1 -1
  17. package/esm/typings/src/llm-providers/anthropic-claude/createAnthropicClaudeExecutionTools.d.ts +2 -2
  18. package/esm/typings/src/llm-providers/anthropic-claude/playground/playground.d.ts +2 -2
  19. package/esm/typings/src/llm-providers/openai/playground/playground.d.ts +1 -1
  20. package/esm/typings/src/llm-providers/vercel/playground/playground.d.ts +1 -1
  21. package/esm/typings/src/other/templates/getBookTemplates.d.ts +1 -1
  22. package/esm/typings/src/personas/preparePersona.d.ts +4 -4
  23. package/esm/typings/src/pipeline/PipelineString.d.ts +0 -3
  24. package/esm/typings/src/pipeline/book-notation.d.ts +0 -1
  25. package/esm/typings/src/pipeline/isValidPipelineString.d.ts +3 -1
  26. package/esm/typings/src/pipeline/validatePipelineString.d.ts +14 -0
  27. package/esm/typings/src/prepare/isPipelinePrepared.d.ts +1 -1
  28. package/esm/typings/src/prepare/prepareTasks.d.ts +1 -1
  29. package/esm/typings/src/scripting/javascript/JavascriptEvalExecutionTools.test.d.ts +1 -1
  30. package/esm/typings/src/scripting/javascript/utils/preserve.d.ts +1 -1
  31. package/esm/typings/src/types/typeAliases.d.ts +8 -2
  32. package/esm/typings/src/utils/serialization/checkSerializableAsJson.d.ts +1 -1
  33. package/esm/typings/src/utils/serialization/isSerializableAsJson.d.ts +1 -1
  34. package/package.json +1 -1
  35. package/umd/index.umd.js +145 -114
  36. package/umd/index.umd.js.map +1 -1
package/umd/index.umd.js CHANGED
@@ -27,7 +27,7 @@
27
27
  * @generated
28
28
  * @see https://github.com/webgptorg/promptbook
29
29
  */
30
- var PROMPTBOOK_ENGINE_VERSION = '0.81.0-20';
30
+ var PROMPTBOOK_ENGINE_VERSION = '0.81.0-22';
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
@@ -179,6 +179,66 @@
179
179
  * TODO: [🧠] Maybe clear `sourceFile` or clear when exposing through API or remote server
180
180
  */
181
181
 
182
+ /**
183
+ * Function isValidJsonString will tell you if the string is valid JSON or not
184
+ *
185
+ * @public exported from `@promptbook/utils`
186
+ */
187
+ function isValidJsonString(value /* <- [👨‍⚖️] */) {
188
+ try {
189
+ JSON.parse(value);
190
+ return true;
191
+ }
192
+ catch (error) {
193
+ if (!(error instanceof Error)) {
194
+ throw error;
195
+ }
196
+ if (error.message.includes('Unexpected token')) {
197
+ return false;
198
+ }
199
+ return false;
200
+ }
201
+ }
202
+
203
+ /**
204
+ * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
205
+ *
206
+ * @public exported from `@promptbook/core`
207
+ */
208
+ var ParseError = /** @class */ (function (_super) {
209
+ __extends(ParseError, _super);
210
+ function ParseError(message) {
211
+ var _this = _super.call(this, message) || this;
212
+ _this.name = 'ParseError';
213
+ Object.setPrototypeOf(_this, ParseError.prototype);
214
+ return _this;
215
+ }
216
+ return ParseError;
217
+ }(Error));
218
+ /**
219
+ * TODO: Maybe split `ParseError` and `ApplyError`
220
+ */
221
+
222
+ /**
223
+ * Function `validatePipelineString` will validate the if the string is a valid pipeline string
224
+ * It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
225
+ *
226
+ * @param {string} pipelineString the candidate for a pipeline string
227
+ * @returns {PipelineString} the same string as input, but validated as valid
228
+ * @throws {ParseError} if the string is not a valid pipeline string
229
+ * @public exported from `@promptbook/core`
230
+ */
231
+ function validatePipelineString(pipelineString) {
232
+ if (isValidJsonString(pipelineString)) {
233
+ throw new ParseError('Expected a book, but got a JSON string');
234
+ }
235
+ // <- TODO: Implement the validation + add tests when the pipeline logic considered as invalid
236
+ return pipelineString;
237
+ }
238
+ /**
239
+ * TODO: [🧠][🈴] Where is the best location for this file
240
+ */
241
+
182
242
  /**
183
243
  * Prettify the html code
184
244
  *
@@ -245,7 +305,7 @@
245
305
  if (bookVersion !== "undefined") {
246
306
  commands.push("BOOK VERSION ".concat(bookVersion));
247
307
  }
248
- // TODO: [main] !!!!! This increases size of the bundle and is probbably not necessary
308
+ // TODO: [main] !!5 This increases size of the bundle and is probbably not necessary
249
309
  pipelineString = prettifyMarkdown(pipelineString);
250
310
  try {
251
311
  for (var _g = __values(parameters.filter(function (_a) {
@@ -393,12 +453,12 @@
393
453
  pipelineString += '```' + contentLanguage;
394
454
  pipelineString += '\n';
395
455
  pipelineString += spaceTrim__default["default"](content);
396
- // <- TODO: [main] !!! Escape
456
+ // <- TODO: [main] !!3 Escape
397
457
  // <- TODO: [🧠] Some clear strategy how to spaceTrim the blocks
398
458
  pipelineString += '\n';
399
459
  pipelineString += '```';
400
460
  pipelineString += '\n\n';
401
- pipelineString += "`-> {".concat(resultingParameterName, "}`"); // <- TODO: [main] !!! If the parameter here has description, add it and use taskParameterJsonToString
461
+ pipelineString += "`-> {".concat(resultingParameterName, "}`"); // <- TODO: [main] !!3 If the parameter here has description, add it and use taskParameterJsonToString
402
462
  }
403
463
  }
404
464
  catch (e_3_1) { e_3 = { error: e_3_1 }; }
@@ -408,7 +468,7 @@
408
468
  }
409
469
  finally { if (e_3) throw e_3.error; }
410
470
  }
411
- return pipelineString;
471
+ return validatePipelineString(pipelineString);
412
472
  }
413
473
  /**
414
474
  * @private internal utility of `pipelineJsonToString`
@@ -566,14 +626,14 @@
566
626
  var DEFAULT_MAX_EXECUTION_ATTEMPTS = 3; // <- TODO: [🤹‍♂️]
567
627
  /**
568
628
  * @@@
569
- * TODO: [🐝][main] !!! Use
629
+ * TODO: [🐝][main] !!3 Use
570
630
  *
571
631
  * @public exported from `@promptbook/core`
572
632
  */
573
633
  var DEFAULT_MAX_KNOWLEDGE_SOURCES_SCRAPING_DEPTH = 3;
574
634
  /**
575
635
  * @@@
576
- * TODO: [🐝][main] !!! Use
636
+ * TODO: [🐝][main] !!3 Use
577
637
  *
578
638
  * @public exported from `@promptbook/core`
579
639
  */
@@ -736,7 +796,7 @@
736
796
  /**
737
797
  * Make error report URL for the given error
738
798
  *
739
- * @private !!!!!!
799
+ * @private private within the repository
740
800
  */
741
801
  function getErrorReportUrl(error) {
742
802
  var report = {
@@ -887,7 +947,7 @@
887
947
  }
888
948
  /**
889
949
  * TODO: Can be return type more type-safe? like `asserts options.value is JsonValue`
890
- * TODO: [🧠][main] !!! In-memory cache of same values to prevent multiple checks
950
+ * TODO: [🧠][main] !!3 In-memory cache of same values to prevent multiple checks
891
951
  * Note: [🐠] This is how `checkSerializableAsJson` + `isSerializableAsJson` together can just retun true/false or rich error message
892
952
  */
893
953
 
@@ -1010,25 +1070,6 @@
1010
1070
  * Note: [💞] Ignore a discrepancy between file name and entity name
1011
1071
  */
1012
1072
 
1013
- /**
1014
- * This error indicates that the promptbook in a markdown format cannot be parsed into a valid promptbook object
1015
- *
1016
- * @public exported from `@promptbook/core`
1017
- */
1018
- var ParseError = /** @class */ (function (_super) {
1019
- __extends(ParseError, _super);
1020
- function ParseError(message) {
1021
- var _this = _super.call(this, message) || this;
1022
- _this.name = 'ParseError';
1023
- Object.setPrototypeOf(_this, ParseError.prototype);
1024
- return _this;
1025
- }
1026
- return ParseError;
1027
- }(Error));
1028
- /**
1029
- * TODO: Maybe split `ParseError` and `ApplyError`
1030
- */
1031
-
1032
1073
  /**
1033
1074
  * This error indicates that the promptbook object has valid syntax (=can be parsed) but contains logical errors (like circular dependencies)
1034
1075
  *
@@ -1083,7 +1124,7 @@
1083
1124
  if ( /* version === '1.0.0' || */version === '2.0.0' || version === '3.0.0') {
1084
1125
  return false;
1085
1126
  }
1086
- // <- TODO: [main] !!! Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
1127
+ // <- TODO: [main] !!3 Check isValidPromptbookVersion against PROMPTBOOK_ENGINE_VERSIONS
1087
1128
  return true;
1088
1129
  }
1089
1130
 
@@ -1213,11 +1254,11 @@
1213
1254
  */
1214
1255
  function validatePipeline(pipeline) {
1215
1256
  if (IS_PIPELINE_LOGIC_VALIDATED) {
1216
- validatePipelineCore(pipeline);
1257
+ validatePipeline_InnerFunction(pipeline);
1217
1258
  }
1218
1259
  else {
1219
1260
  try {
1220
- validatePipelineCore(pipeline);
1261
+ validatePipeline_InnerFunction(pipeline);
1221
1262
  }
1222
1263
  catch (error) {
1223
1264
  if (!(error instanceof PipelineLogicError)) {
@@ -1231,7 +1272,7 @@
1231
1272
  /**
1232
1273
  * @private internal function for `validatePipeline`
1233
1274
  */
1234
- function validatePipelineCore(pipeline) {
1275
+ function validatePipeline_InnerFunction(pipeline) {
1235
1276
  // TODO: [🧠] Maybe test if promptbook is a promise and make specific error case for that
1236
1277
  var e_1, _a, e_2, _b, e_3, _c;
1237
1278
  var pipelineIdentification = (function () {
@@ -1455,11 +1496,11 @@
1455
1496
  _loop_3();
1456
1497
  }
1457
1498
  // Note: Check that formfactor is corresponding to the pipeline interface
1458
- // TODO: !!!!!! Implement this
1499
+ // TODO: !!6 Implement this
1459
1500
  // pipeline.formfactorName
1460
1501
  }
1461
1502
  /**
1462
- * TODO: !! [🧞‍♀️] Do not allow joker + foreach
1503
+ * TODO: [🧞‍♀️] Do not allow joker + foreach
1463
1504
  * TODO: [🧠] Work with promptbookVersion
1464
1505
  * TODO: Use here some json-schema, Zod or something similar and change it to:
1465
1506
  * > /**
@@ -1471,11 +1512,11 @@
1471
1512
  * > ex port function validatePipeline(promptbook: really_unknown): asserts promptbook is PipelineJson {
1472
1513
  */
1473
1514
  /**
1474
- * TODO: [🧳][main] !!!! Validate that all examples match expectations
1475
- * TODO: [🧳][🐝][main] !!!! Validate that knowledge is valid (non-void)
1476
- * TODO: [🧳][main] !!!! Validate that persona can be used only with CHAT variant
1477
- * TODO: [🧳][main] !!!! Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1478
- * TODO: [🧳][main] !!!! Validate that reserved parameter is not used as joker
1515
+ * TODO: [🧳][main] !!4 Validate that all examples match expectations
1516
+ * TODO: [🧳][🐝][main] !!4 Validate that knowledge is valid (non-void)
1517
+ * TODO: [🧳][main] !!4 Validate that persona can be used only with CHAT variant
1518
+ * TODO: [🧳][main] !!4 Validate that parameter with reserved name not used RESERVED_PARAMETER_NAMES
1519
+ * TODO: [🧳][main] !!4 Validate that reserved parameter is not used as joker
1479
1520
  * TODO: [🧠] Validation not only logic itself but imports around - files and websites and rerefenced pipelines exists
1480
1521
  * TODO: [🛠] Actions, instruments (and maybe knowledge) => Functions and tools
1481
1522
  */
@@ -1611,7 +1652,7 @@
1611
1652
  pipelineJsonToString(unpreparePipeline(pipeline)) !==
1612
1653
  pipelineJsonToString(unpreparePipeline(this.collection.get(pipeline.pipelineUrl)))) {
1613
1654
  var existing = this.collection.get(pipeline.pipelineUrl);
1614
- throw new PipelineUrlError(spaceTrim.spaceTrim("\n Pipeline with URL \"".concat(pipeline.pipelineUrl, "\" is already in the collection \uD83C\uDF4E\n\n Conflicting files:\n ").concat(existing.sourceFile || 'Unknown', "\n ").concat(pipeline.sourceFile || 'Unknown', "\n\n Note: You have probably forgotten to run \"ptbk make\" to update the collection\n Note: Pipelines with the same URL are not allowed\n Only exepction is when the pipelines are identical\n\n ")));
1655
+ throw new PipelineUrlError(spaceTrim.spaceTrim("\n Pipeline with URL ".concat(pipeline.pipelineUrl, " is already in the collection \uD83C\uDF4E\n\n Conflicting files:\n ").concat(existing.sourceFile || 'Unknown', "\n ").concat(pipeline.sourceFile || 'Unknown', "\n\n Note: You have probably forgotten to run \"ptbk make\" to update the collection\n Note: Pipelines with the same URL are not allowed\n Only exepction is when the pipelines are identical\n\n ")));
1615
1656
  }
1616
1657
  // Note: [🧠] Overwrite existing pipeline with the same URL
1617
1658
  this.collection.set(pipeline.pipelineUrl, pipeline);
@@ -1795,7 +1836,7 @@
1795
1836
  });
1796
1837
  }
1797
1838
  /**
1798
- * TODO: [main] !!!! [🧠] Library precompilation and do not mix markdown and json promptbooks
1839
+ * TODO: [main] !!4 [🧠] Library precompilation and do not mix markdown and json promptbooks
1799
1840
  */
1800
1841
 
1801
1842
  /**
@@ -1865,7 +1906,7 @@
1865
1906
  case 0: return [4 /*yield*/, collection.isResponsibleForPrompt(prompt)];
1866
1907
  case 1:
1867
1908
  isResponsible = _a.sent();
1868
- // TODO: !! Only if responsible, check if predicate is true
1909
+ // TODO: Only if responsible, check if predicate is true
1869
1910
  return [2 /*return*/, isResponsible];
1870
1911
  }
1871
1912
  });
@@ -1880,6 +1921,22 @@
1880
1921
 
1881
1922
  var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgeContent",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledgePieces",description:"The knowledge JSON object",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}",resultingParameterName:"knowledgePieces",dependentParameterNames:["knowledgeContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge from Markdown\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book.md`\n- INPUT PARAMETER `{knowledgeContent}` Markdown document content\n- OUTPUT PARAMETER `{knowledgePieces}` The knowledge JSON object\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, extract the important knowledge from the document.\n\n# Rules\n\n- Make pieces of information concise, clear, and easy to understand\n- One piece of information should be approximately 1 paragraph\n- Divide the paragraphs by markdown horizontal lines ---\n- Omit irrelevant information\n- Group redundant information\n- Write just extracted information, nothing else\n\n# The document\n\nTake information from this document:\n\n> {knowledgeContent}\n```\n\n`-> {knowledgePieces}`\n"}],sourceFile:"./books/prepare-knowledge-from-markdown.book.md"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}",resultingParameterName:"keywords",dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Keywords\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-keywords.book.md`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{keywords}` Keywords separated by comma\n\n## Knowledge\n\n<!-- TODO: [🍆] -FORMAT JSON -->\n\n```markdown\nYou are experienced data researcher, detect the important keywords in the document.\n\n# Rules\n\n- Write just keywords separated by comma\n\n# The document\n\nTake information from this document:\n\n> {knowledgePieceContent}\n```\n\n`-> {keywords}`\n"}],sourceFile:"./books/prepare-knowledge-keywords.book.md"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book.md",formfactorName:"GENERIC",parameters:[{name:"knowledgePieceContent",description:"The content",isInput:true,isOutput:false},{name:"title",description:"The title of the document",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"knowledge",title:"Knowledge",content:"You are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}",resultingParameterName:"title",expectations:{words:{min:1,max:8}},dependentParameterNames:["knowledgePieceContent"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Knowledge-piece Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-knowledge-title.book.md`\n- INPUT PARAMETER `{knowledgePieceContent}` The content\n- OUTPUT PARAMETER `{title}` The title of the document\n\n## Knowledge\n\n- EXPECT MIN 1 WORD\n- EXPECT MAX 8 WORDS\n\n```markdown\nYou are experienced content creator, write best title for the document.\n\n# Rules\n\n- Write just title, nothing else\n- Title should be concise and clear - Write maximum ideally 2 words, maximum 5 words\n- Write maximum 5 words for the title\n\n# The document\n\n> {knowledgePieceContent}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-knowledge-title.book.md"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book.md",formfactorName:"GENERIC",parameters:[{name:"availableModelNames",description:"List of available model names separated by comma (,)",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n```json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n```\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}",resultingParameterName:"modelRequirements",format:"JSON",dependentParameterNames:["availableModelNames","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book.md`\n- INPUT PARAMETER `{availableModelNames}` List of available model names separated by comma (,)\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are experienced AI engineer, you need to create virtual assistant.\nWrite\n\n## Example\n\n\\`\\`\\`json\n{\n\"modelName\": \"gpt-4o\",\n\"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n\"temperature\": 0.7\n}\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON object\n- Write just the JSON object, no other text should be present\n- It contains the following keys:\n - `modelName`: The name of the model to use\n - `systemMessage`: The system message to provide context to the model\n - `temperature`: The sampling temperature to use\n\n### Key `modelName`\n\nPick from the following models:\n\n- {availableModelNames}\n\n### Key `systemMessage`\n\nThe system message is used to communicate instructions or provide context to the model at the beginning of a conversation. It is displayed in a different format compared to user messages, helping the model understand its role in the conversation. The system message typically guides the model's behavior, sets the tone, or specifies desired output from the model. By utilizing the system message effectively, users can steer the model towards generating more accurate and relevant responses.\n\nFor example:\n\n> You are an experienced AI engineer and helpful assistant.\n\n> You are a friendly and knowledgeable chatbot.\n\n### Key `temperature`\n\nThe sampling temperature, between 0 and 1. Higher values like 0.8 will make the output more random, while lower values like 0.2 will make it more focused and deterministic. If set to 0, the model will use log probability to automatically increase the temperature until certain thresholds are hit.\n\nYou can pick a value between 0 and 2. For example:\n\n- `0.1`: Low temperature, extremely conservative and deterministic\n- `0.5`: Medium temperature, balanced between conservative and creative\n- `1.0`: High temperature, creative and bit random\n- `1.5`: Very high temperature, extremely creative and often chaotic and unpredictable\n- `2.0`: Maximum temperature, completely random and unpredictable, for some extreme creative use cases\n\n# The assistant\n\nTake this description of the persona:\n\n> {personaDescription}\n```\n\n`-> {modelRequirements}`\n"}],sourceFile:"./books/prepare-persona.book.md"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book.md",formfactorName:"GENERIC",parameters:[{name:"book",description:"The book to prepare the title for",isInput:true,isOutput:false},{name:"title",description:"Best title for the book",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-title",title:"Make title",content:"Make best title for given text which describes the task:\n\n> {book}\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Title starts with emoticon",resultingParameterName:"title",expectations:{words:{min:1,max:8},lines:{min:1,max:1}},dependentParameterNames:["book"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Title\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-title.book.md`\n- INPUT PARAMETER `{book}` The book to prepare the title for\n- OUTPUT PARAMETER `{title}` Best title for the book\n\n## Make title\n\n- EXPECT MIN 1 Word\n- EXPECT MAX 8 Words\n- EXPECT EXACTLY 1 Line\n\n```markdown\nMake best title for given text which describes the task:\n\n> {book}\n\n## Rules\n\n- Write just title, nothing else\n- Title should be concise and clear\n- Title starts with emoticon\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book.md"}];
1882
1923
 
1924
+ /**
1925
+ * This error type indicates that some tools are missing for pipeline execution or preparation
1926
+ *
1927
+ * @public exported from `@promptbook/core`
1928
+ */
1929
+ var MissingToolsError = /** @class */ (function (_super) {
1930
+ __extends(MissingToolsError, _super);
1931
+ function MissingToolsError(message) {
1932
+ var _this = _super.call(this, spaceTrim.spaceTrim(function (block) { return "\n ".concat(block(message), "\n\n Note: You have probbably forgot to provide some tools for pipeline execution or preparation\n\n "); })) || this;
1933
+ _this.name = 'MissingToolsError';
1934
+ Object.setPrototypeOf(_this, MissingToolsError.prototype);
1935
+ return _this;
1936
+ }
1937
+ return MissingToolsError;
1938
+ }(Error));
1939
+
1883
1940
  /**
1884
1941
  * This error indicates errors during the execution of the pipeline
1885
1942
  *
@@ -2015,22 +2072,6 @@
2015
2072
  return LimitReachedError;
2016
2073
  }(Error));
2017
2074
 
2018
- /**
2019
- * This error type indicates that some tools are missing for pipeline execution or preparation
2020
- *
2021
- * @public exported from `@promptbook/core`
2022
- */
2023
- var MissingToolsError = /** @class */ (function (_super) {
2024
- __extends(MissingToolsError, _super);
2025
- function MissingToolsError(message) {
2026
- var _this = _super.call(this, spaceTrim.spaceTrim(function (block) { return "\n ".concat(block(message), "\n\n Note: You have probbably forgot to provide some tools for pipeline execution or preparation\n\n "); })) || this;
2027
- _this.name = 'MissingToolsError';
2028
- Object.setPrototypeOf(_this, MissingToolsError.prototype);
2029
- return _this;
2030
- }
2031
- return MissingToolsError;
2032
- }(Error));
2033
-
2034
2075
  /**
2035
2076
  * This error type indicates that some part of the code is not implemented yet
2036
2077
  *
@@ -2176,7 +2217,7 @@
2176
2217
  return true;
2177
2218
  }
2178
2219
  /**
2179
- * TODO: [🔃][main] !! If the pipeline was prepared with different version or different set of models, prepare it once again
2220
+ * TODO: [🔃][main] If the pipeline was prepared with different version or different set of models, prepare it once again
2180
2221
  * TODO: [🐠] Maybe base this on `makeValidator`
2181
2222
  * TODO: [🧊] Pipeline can be partially prepared, this should return true ONLY if fully prepared
2182
2223
  * TODO: [🧿] Maybe do same process with same granularity and subfinctions as `preparePipeline`
@@ -2739,27 +2780,6 @@
2739
2780
  * TODO: [🏢] Allow to expect something inside CSV objects and other formats
2740
2781
  */
2741
2782
 
2742
- /**
2743
- * Function isValidJsonString will tell you if the string is valid JSON or not
2744
- *
2745
- * @public exported from `@promptbook/utils`
2746
- */
2747
- function isValidJsonString(value /* <- [👨‍⚖️] */) {
2748
- try {
2749
- JSON.parse(value);
2750
- return true;
2751
- }
2752
- catch (error) {
2753
- if (!(error instanceof Error)) {
2754
- throw error;
2755
- }
2756
- if (error.message.includes('Unexpected token')) {
2757
- return false;
2758
- }
2759
- return false;
2760
- }
2761
- }
2762
-
2763
2783
  /**
2764
2784
  * Definition for JSON format
2765
2785
  *
@@ -3445,6 +3465,8 @@
3445
3465
  throw new PipelineExecutionError("Parameter `{".concat(parameterName, "}` is not defined"));
3446
3466
  }
3447
3467
  parameterValue = valueToString(parameterValue);
3468
+ // Escape curly braces in parameter values to prevent prompt-injection
3469
+ parameterValue = parameterValue.replace(/[{}]/g, '\\$&');
3448
3470
  if (parameterValue.includes('\n') && /^\s*\W{0,3}\s*$/.test(precol)) {
3449
3471
  parameterValue = parameterValue
3450
3472
  .split('\n')
@@ -4087,7 +4109,7 @@
4087
4109
  promptTitle: task.title,
4088
4110
  promptMessage: templateParameters(task.description || '', parameters),
4089
4111
  defaultValue: templateParameters(preparedContent, parameters),
4090
- // TODO: [🧠] !! Figure out how to define placeholder in .book.md file
4112
+ // TODO: [🧠] Figure out how to define placeholder in .book.md file
4091
4113
  placeholder: undefined,
4092
4114
  priority: priority,
4093
4115
  }))];
@@ -5250,10 +5272,10 @@
5250
5272
  });
5251
5273
  }
5252
5274
  /**
5253
- * TODO: [🔃][main] !! If the persona was prepared with different version or different set of models, prepare it once again
5254
- * TODO: [🏢] !! Check validity of `modelName` in pipeline
5255
- * TODO: [🏢] !! Check validity of `systemMessage` in pipeline
5256
- * TODO: [🏢] !! Check validity of `temperature` in pipeline
5275
+ * TODO: [🔃][main] If the persona was prepared with different version or different set of models, prepare it once again
5276
+ * TODO: [🏢] Check validity of `modelName` in pipeline
5277
+ * TODO: [🏢] Check validity of `systemMessage` in pipeline
5278
+ * TODO: [🏢] Check validity of `temperature` in pipeline
5257
5279
  */
5258
5280
 
5259
5281
  /**
@@ -6082,7 +6104,7 @@
6082
6104
  * TODO: [😂] Adding knowledge should be convert to async high-level abstractions, simmilar thing with expectations to sync high-level abstractions
6083
6105
  * TODO: [🧠] Add context to each task (if missing)
6084
6106
  * TODO: [🧠] What is better name `prepareTask` or `prepareTaskAndParameters`
6085
- * TODO: [♨][main] !!! Prepare index the examples and maybe tasks
6107
+ * TODO: [♨][main] !!3 Prepare index the examples and maybe tasks
6086
6108
  * TODO: Write tests for `preparePipeline`
6087
6109
  * TODO: [🏏] Leverage the batch API and build queues @see https://platform.openai.com/docs/guides/batch
6088
6110
  * TODO: [🧊] In future one preparation can take data from previous preparation and save tokens and time
@@ -6145,17 +6167,10 @@
6145
6167
  _d.tools = tools,
6146
6168
  _d)]);
6147
6169
  return [4 /*yield*/, prepareTitleExecutor({
6148
- book: sources
6149
- .map(function (_a) {
6170
+ book: sources.map(function (_a) {
6150
6171
  var content = _a.content;
6151
6172
  return content;
6152
- })
6153
- .join('\n\n')
6154
- // TODO: !!!!!!! Parameters in parameters - DO NOT ALLOW, ESCAPE:
6155
- .split('{')
6156
- .join('[')
6157
- .split('}')
6158
- .join(']'),
6173
+ }).join('\n\n'),
6159
6174
  })];
6160
6175
  case 2:
6161
6176
  result = _e.sent();
@@ -6309,7 +6324,7 @@
6309
6324
  if (sourceContent === '') {
6310
6325
  throw new ParseError("Source is not defined");
6311
6326
  }
6312
- // TODO: [main] !!!! Following checks should be applied every link in the `sourceContent`
6327
+ // TODO: [main] !!4 Following checks should be applied every link in the `sourceContent`
6313
6328
  if (sourceContent.startsWith('http://')) {
6314
6329
  throw new ParseError("Source is not secure");
6315
6330
  }
@@ -6481,7 +6496,7 @@
6481
6496
  expectResultingParameterName();
6482
6497
  var parameter = $pipelineJson.parameters.find(function (param) { return param.name === $taskJson.resultingParameterName; });
6483
6498
  if (parameter === undefined) {
6484
- // TODO: !!!!!! Change to logic error for higher level abstraction of chatbot to work
6499
+ // TODO: !!6 Change to logic error for higher level abstraction of chatbot to work
6485
6500
  throw new ParseError("Parameter `{".concat($taskJson.resultingParameterName, "}` is not defined so can not define example value of it"));
6486
6501
  }
6487
6502
  parameter.exampleValues = parameter.exampleValues || [];
@@ -6492,7 +6507,7 @@
6492
6507
  if (command.taskType === 'KNOWLEDGE') {
6493
6508
  knowledgeCommandParser.$applyToPipelineJson({
6494
6509
  type: 'KNOWLEDGE',
6495
- sourceContent: $taskJson.content, // <- TODO: [🐝][main] !!! Work with KNOWLEDGE which not referring to the source file or website, but its content itself
6510
+ sourceContent: $taskJson.content, // <- TODO: [🐝][main] !!3 Work with KNOWLEDGE which not referring to the source file or website, but its content itself
6496
6511
  }, $pipelineJson);
6497
6512
  $taskJson.isTask = false;
6498
6513
  return;
@@ -8453,7 +8468,7 @@
8453
8468
  instrumentCommandParser,
8454
8469
  personaCommandParser,
8455
8470
  foreachCommandParser,
8456
- boilerplateCommandParser, // <- TODO: !! Only in development, remove in production
8471
+ boilerplateCommandParser, // <- TODO: Only in development, remove in production
8457
8472
  // <- Note: [♓️][💩] This is the order of the commands in the pipeline, BUT its not used in parsing and before usage maybe it should be done better
8458
8473
  ];
8459
8474
  /**
@@ -9223,7 +9238,7 @@
9223
9238
  {
9224
9239
  type: 'BOOK',
9225
9240
  path: null,
9226
- // <- TODO: !!!!!! Pass here path of the file
9241
+ // <- TODO: !!6 Pass here path of the file
9227
9242
  content: pipelineString,
9228
9243
  },
9229
9244
  ],
@@ -9248,10 +9263,11 @@
9248
9263
  if (!(shebangLine_1 || '').includes('ptbk')) {
9249
9264
  throw new ParseError(spaceTrim.spaceTrim(function (block) { return "\n It seems that you try to parse a book file which has non-standard shebang line for book files:\n Shebang line must contain 'ptbk'\n\n You have:\n ".concat(block(shebangLine_1 || '(empty line)'), "\n\n It should look like this:\n #!/usr/bin/env ptbk\n\n ").concat(block(getPipelineIdentification()), "\n "); }));
9250
9265
  }
9251
- pipelineString = restLines.join('\n');
9266
+ pipelineString = validatePipelineString(restLines.join('\n'));
9252
9267
  }
9253
9268
  pipelineString = removeMarkdownComments(pipelineString);
9254
9269
  pipelineString = spaceTrim.spaceTrim(pipelineString);
9270
+ // <- TODO: [😧] `spaceTrim` should preserve discriminated type *(or at lease `PipelineString`)*
9255
9271
  // ==============
9256
9272
  // Note: 1️⃣◽2️⃣ Process flat pipeline
9257
9273
  var isMarkdownBeginningWithHeadline = pipelineString.startsWith('# ');
@@ -9266,8 +9282,8 @@
9266
9282
  var pipelineStringLines = pipelineString.split('\n');
9267
9283
  var returnStatement_1 = pipelineStringLines.pop();
9268
9284
  var prompt_1 = spaceTrim.spaceTrim(pipelineStringLines.join('\n'));
9269
- pipelineString = spaceTrim.spaceTrim(function (block) { return "\n # ".concat(DEFAULT_BOOK_TITLE, "\n\n ## Prompt\n\n ```\n ").concat(block(prompt_1), "\n ```\n\n ").concat(returnStatement_1, "\n "); });
9270
- // <- TODO: !!!!!! Use book` notation
9285
+ pipelineString = validatePipelineString(spaceTrim.spaceTrim(function (block) { return "\n # ".concat(DEFAULT_BOOK_TITLE, "\n\n ## Prompt\n\n ```\n ").concat(block(prompt_1), "\n ```\n\n ").concat(returnStatement_1, "\n "); }));
9286
+ // <- TODO: Maybe use book` notation
9271
9287
  // console.log(pipelineString);
9272
9288
  }
9273
9289
  // ==============
@@ -9668,7 +9684,7 @@
9668
9684
  }
9669
9685
  /**
9670
9686
  * TODO: [🧠] Maybe more things here can be refactored as high-level abstractions
9671
- * TODO: [main] !!!! Warn if used only sync version
9687
+ * TODO: [main] !!4 Warn if used only sync version
9672
9688
  * TODO: [🚞] Report here line/column of error
9673
9689
  * TODO: Use spaceTrim more effectively
9674
9690
  * TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
@@ -9761,7 +9777,7 @@
9761
9777
  var parameter = pipelineJson.parameters.find(function (parameter) { return parameter.name === parameterName; });
9762
9778
  if (!parameter) {
9763
9779
  throw new UnexpectedError("Could not find {".concat(parameterName, "}"));
9764
- // <- TODO: !!!!!! This causes problems when {knowledge} and other reserved parameters are used
9780
+ // <- TODO: !!6 This causes problems when {knowledge} and other reserved parameters are used
9765
9781
  }
9766
9782
  if (parameter.isInput) {
9767
9783
  return 'input';
@@ -9805,9 +9821,9 @@
9805
9821
  return promptbookMermaid;
9806
9822
  }
9807
9823
  /**
9808
- * TODO: [🧠] !! FOREACH in mermaid graph
9809
- * TODO: [🧠] !! Knowledge in mermaid graph
9810
- * TODO: [🧠] !! Personas in mermaid graph
9824
+ * TODO: [🧠] FOREACH in mermaid graph
9825
+ * TODO: [🧠] Knowledge in mermaid graph
9826
+ * TODO: [🧠] Personas in mermaid graph
9811
9827
  * TODO: Maybe use some Mermaid package instead of string templating
9812
9828
  * TODO: [🕌] When more than 2 functionalities, split into separate functions
9813
9829
  */
@@ -9842,6 +9858,7 @@
9842
9858
  case 2:
9843
9859
  if (isPrettifyed) {
9844
9860
  pipelineString = prettifyMarkdown(pipelineString);
9861
+ // <- TODO: [😧] `prettifyMarkdown` should preserve discriminated type *(or at lease `PipelineString`)*
9845
9862
  }
9846
9863
  return [2 /*return*/, pipelineString];
9847
9864
  }
@@ -10643,7 +10660,7 @@
10643
10660
  return [3 /*break*/, 11];
10644
10661
  case 10: throw new PipelineExecutionError("Unknown model variant \"".concat(prompt.modelRequirements.modelVariant, "\""));
10645
10662
  case 11:
10646
- // TODO: [🧠] !!!!! How to do timing in mixed cache / non-cache situation
10663
+ // TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
10647
10664
  // promptResult.timing: FromtoItems
10648
10665
  return [4 /*yield*/, storage.setItem(key, {
10649
10666
  date: $getCurrentDate(),
@@ -10652,7 +10669,7 @@
10652
10669
  promptResult: promptResult,
10653
10670
  })];
10654
10671
  case 12:
10655
- // TODO: [🧠] !!!!! How to do timing in mixed cache / non-cache situation
10672
+ // TODO: [🧠] !!5 How to do timing in mixed cache / non-cache situation
10656
10673
  // promptResult.timing: FromtoItems
10657
10674
  _c.sent();
10658
10675
  return [2 /*return*/, promptResult];
@@ -11001,11 +11018,21 @@
11001
11018
  * Function `isValidPipelineString` will validate the if the string is a valid pipeline string
11002
11019
  * It does not check if the string is fully logically correct, but if it is a string that can be a pipeline string or the string looks completely different.
11003
11020
  *
11021
+ * @param {string} pipelineString the candidate for a pipeline string
11022
+ * @returns {boolean} if the string is a valid pipeline string
11004
11023
  * @public exported from `@promptbook/core`
11005
11024
  */
11006
- function isValidPipelineString(value) {
11007
- // TODO: Implement the validation + add tests when the pipeline logic considered as invalid
11008
- return true;
11025
+ function isValidPipelineString(pipelineString) {
11026
+ try {
11027
+ validatePipelineString(pipelineString);
11028
+ return true;
11029
+ }
11030
+ catch (error) {
11031
+ if (!(error instanceof Error)) {
11032
+ throw error;
11033
+ }
11034
+ return false;
11035
+ }
11009
11036
  }
11010
11037
  /**
11011
11038
  * TODO: [🧠][🈴] Where is the best location for this file
@@ -11029,10 +11056,13 @@
11029
11056
  }
11030
11057
  var pipelineString = strings[0];
11031
11058
  pipelineString = spaceTrim__default["default"](pipelineString);
11059
+ if (!isValidPipelineString(pipelineString)) {
11060
+ // TODO: Make the CustomError for this
11061
+ throw new Error(spaceTrim__default["default"]("\n The string is not a valid pipeline string\n\n book`\n ".concat(pipelineString, "\n `\n ")));
11062
+ }
11032
11063
  return pipelineString;
11033
11064
  }
11034
11065
  /**
11035
- * TODO: Use ACRY book\`...\ notation instead of as PipelineString
11036
11066
  * TODO: [🧠][🈴] Where is the best location for this file
11037
11067
  * Note: [💞] Ignore a discrepancy between file name and entity name
11038
11068
  */
@@ -11387,6 +11417,7 @@
11387
11417
  exports.usageToHuman = usageToHuman;
11388
11418
  exports.usageToWorktime = usageToWorktime;
11389
11419
  exports.validatePipeline = validatePipeline;
11420
+ exports.validatePipelineString = validatePipelineString;
11390
11421
 
11391
11422
  Object.defineProperty(exports, '__esModule', { value: true });
11392
11423