@promptbook/cli 0.59.0-32 → 0.59.0-34

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/umd/index.umd.js CHANGED
@@ -147,7 +147,7 @@
147
147
  /**
148
148
  * The version of the Promptbook library
149
149
  */
150
- var PROMPTBOOK_VERSION = '0.59.0-31';
150
+ var PROMPTBOOK_VERSION = '0.59.0-33';
151
151
 
152
152
  /**
153
153
  * Initializes testing `hello` command for Promptbook CLI utilities
@@ -441,7 +441,7 @@
441
441
  * > ex port function validatePromptbook(promptbook: unknown): asserts promptbook is PromptbookJson {
442
442
  */
443
443
 
444
- var promptbookLibrary = [{title:"Prepare Keywords",promptbookUrl:"https://promptbook.studio/promptbook/prepare-keywords.ptbk.md",promptbookVersion:"0.59.0-31",parameters:[{name:"content",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],promptTemplates:[{name:"knowledge",title:"Knowledge",dependentParameterNames:["content"],executionType:"PROMPT_TEMPLATE",modelRequirements:{modelVariant:"CHAT",modelName:"claude-3-opus-20240229"},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> {content}",resultingParameterName:"keywords"}],knowledge:[]},{title:"Prepare Knowledge from Markdown",promptbookUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md",promptbookVersion:"0.59.0-31",parameters:[{name:"content",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledge",description:"The knowledge JSON object",isInput:false,isOutput:true}],promptTemplates:[{name:"knowledge",title:"Knowledge",dependentParameterNames:["content"],executionType:"PROMPT_TEMPLATE",modelRequirements:{modelVariant:"CHAT",modelName:"claude-3-opus-20240229"},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> {content}",resultingParameterName:"knowledge"}],knowledge:[]}];
444
+ var promptbookLibrary = [{title:"Prepare Keywords",promptbookUrl:"https://promptbook.studio/promptbook/prepare-keywords.ptbk.md",promptbookVersion:"0.59.0-33",parameters:[{name:"content",description:"The content",isInput:true,isOutput:false},{name:"keywords",description:"Keywords separated by comma",isInput:false,isOutput:true}],promptTemplates:[{name:"knowledge",title:"Knowledge",dependentParameterNames:["content"],executionType:"PROMPT_TEMPLATE",modelRequirements:{modelVariant:"CHAT",modelName:"claude-3-opus-20240229"},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> {content}",resultingParameterName:"keywords"}],knowledge:[]},{title:"Prepare Knowledge from Markdown",promptbookUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.ptbk.md",promptbookVersion:"0.59.0-33",parameters:[{name:"content",description:"Markdown document content",isInput:true,isOutput:false},{name:"knowledge",description:"The knowledge JSON object",isInput:false,isOutput:true}],promptTemplates:[{name:"knowledge",title:"Knowledge",dependentParameterNames:["content"],executionType:"PROMPT_TEMPLATE",modelRequirements:{modelVariant:"CHAT",modelName:"claude-3-opus-20240229"},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> {content}",resultingParameterName:"knowledge"}],knowledge:[]}];
445
445
 
446
446
  /**
447
447
  * This error indicates errors during the execution of the promptbook
@@ -2942,9 +2942,279 @@
2942
2942
  return value;
2943
2943
  }
2944
2944
 
2945
+ /**
2946
+ * Compile promptbook from string (markdown) format to JSON format synchronously
2947
+ *
2948
+ * Note: There are two similar functions:
2949
+ * - `promptbookStringToJson` **(preferred)** - which propperly compiles the promptbook and use embedding for external knowledge
2950
+ * - `promptbookStringToJsonSync` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
2951
+ *
2952
+ * @param promptbookString {Promptbook} in string markdown format (.ptbk.md)
2953
+ * @param options - Options and tools for the compilation
2954
+ * @returns {Promptbook} compiled in JSON format (.ptbk.json)
2955
+ * @throws {PromptbookSyntaxError} if the promptbook string is not valid
2956
+ *
2957
+ * Note: This function does not validate logic of the pipeline only the syntax
2958
+ * Note: This function acts as compilation process
2959
+ */
2960
+ function promptbookStringToJsonSync(promptbookString) {
2961
+ var e_1, _a, e_2, _b;
2962
+ var promptbookJson = {
2963
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2964
+ title: undefined /* <- Note: Putting here placeholder to keep `title` on top at final JSON */,
2965
+ promptbookUrl: undefined /* <- Note: Putting here placeholder to keep `promptbookUrl` on top at final JSON */,
2966
+ promptbookVersion: PROMPTBOOK_VERSION,
2967
+ description: undefined /* <- Note: Putting here placeholder to keep `description` on top at final JSON */,
2968
+ parameters: [],
2969
+ promptTemplates: [],
2970
+ knowledge: [],
2971
+ };
2972
+ // =============================================================
2973
+ // Note: 1️⃣ Normalization of the PROMPTBOOK string
2974
+ promptbookString = removeContentComments(promptbookString);
2975
+ promptbookString = promptbookString.replaceAll(/`\{(?<parameterName>[a-z0-9_]+)\}`/gi, '{$<parameterName>}');
2976
+ promptbookString = promptbookString.replaceAll(/`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi, '-> {$<parameterName>}');
2977
+ // =============================================================
2978
+ ///Note: 2️⃣ Function for adding parameters
2979
+ var addParam = function (parameterCommand) {
2980
+ var parameterName = parameterCommand.parameterName, parameterDescription = parameterCommand.parameterDescription, isInput = parameterCommand.isInput, isOutput = parameterCommand.isOutput;
2981
+ var existingParameter = promptbookJson.parameters.find(function (parameter) { return parameter.name === parameterName; });
2982
+ if (existingParameter &&
2983
+ existingParameter.description &&
2984
+ existingParameter.description !== parameterDescription &&
2985
+ parameterDescription) {
2986
+ throw new PromptbookSyntaxError(spaceTrim.spaceTrim(function (block) { return "\n Parameter {".concat(parameterName, "} is defined multiple times with different description.\n\n First definition:\n ").concat(block(existingParameter.description || '[undefined]'), "\n\n Second definition:\n ").concat(block(parameterDescription || '[undefined]'), "\n "); }));
2987
+ }
2988
+ if (existingParameter) {
2989
+ if (parameterDescription) {
2990
+ existingParameter.description = parameterDescription;
2991
+ }
2992
+ }
2993
+ else {
2994
+ promptbookJson.parameters.push({
2995
+ name: parameterName,
2996
+ description: parameterDescription || undefined,
2997
+ isInput: isInput,
2998
+ isOutput: isOutput,
2999
+ });
3000
+ }
3001
+ };
3002
+ // =============================================================
3003
+ // Note: 3️⃣ Parse the dynamic part - the template pipeline
3004
+ var markdownStructure = markdownToMarkdownStructure(promptbookString);
3005
+ var markdownStructureDeepness = countMarkdownStructureDeepness(markdownStructure);
3006
+ if (markdownStructureDeepness !== 2) {
3007
+ throw new PromptbookSyntaxError(spaceTrim.spaceTrim("\n Invalid markdown structure.\n The markdown must have exactly 2 levels of headings (one top-level section and one section for each template).\n Now it has ".concat(markdownStructureDeepness, " levels of headings.\n ")));
3008
+ }
3009
+ promptbookJson.title = markdownStructure.title;
3010
+ // TODO: [1] DRY description
3011
+ var description = markdownStructure.content;
3012
+ // Note: Remove codeblocks
3013
+ description = description.split(/^```.*^```/gms).join('');
3014
+ //Note: Remove lists and return statement
3015
+ description = description.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
3016
+ description = spaceTrim.spaceTrim(description);
3017
+ if (description === '') {
3018
+ description = undefined;
3019
+ }
3020
+ promptbookJson.description = description;
3021
+ var defaultModelRequirements = {};
3022
+ var listItems = extractAllListItemsFromMarkdown(markdownStructure.content);
3023
+ try {
3024
+ for (var listItems_1 = __values(listItems), listItems_1_1 = listItems_1.next(); !listItems_1_1.done; listItems_1_1 = listItems_1.next()) {
3025
+ var listItem = listItems_1_1.value;
3026
+ var command = parseCommand(listItem);
3027
+ switch (command.type) {
3028
+ case 'PROMPTBOOK_URL':
3029
+ promptbookJson.promptbookUrl = command.promptbookUrl.href;
3030
+ break;
3031
+ case 'PROMPTBOOK_VERSION':
3032
+ promptbookJson.promptbookVersion = command.promptbookVersion;
3033
+ break;
3034
+ case 'MODEL':
3035
+ defaultModelRequirements[command.key] = command.value;
3036
+ break;
3037
+ case 'PARAMETER':
3038
+ addParam(command);
3039
+ break;
3040
+ default:
3041
+ throw new PromptbookSyntaxError("Command ".concat(command.type, " is not allowed in the head of the promptbook ONLY at the prompt template block"));
3042
+ }
3043
+ }
3044
+ }
3045
+ catch (e_1_1) { e_1 = { error: e_1_1 }; }
3046
+ finally {
3047
+ try {
3048
+ if (listItems_1_1 && !listItems_1_1.done && (_a = listItems_1.return)) _a.call(listItems_1);
3049
+ }
3050
+ finally { if (e_1) throw e_1.error; }
3051
+ }
3052
+ var _loop_1 = function (section) {
3053
+ var e_3, _e;
3054
+ // TODO: Parse prompt template description (the content out of the codeblock and lists)
3055
+ var templateModelRequirements = __assign({}, defaultModelRequirements);
3056
+ var listItems_3 = extractAllListItemsFromMarkdown(section.content);
3057
+ var dependentParameterNames = new Set();
3058
+ var executionType = 'PROMPT_TEMPLATE';
3059
+ var jokers = [];
3060
+ var postprocessing = [];
3061
+ var expectAmount = {};
3062
+ var expectFormat = undefined;
3063
+ var isExecutionTypeChanged = false;
3064
+ try {
3065
+ for (var listItems_2 = (e_3 = void 0, __values(listItems_3)), listItems_2_1 = listItems_2.next(); !listItems_2_1.done; listItems_2_1 = listItems_2.next()) {
3066
+ var listItem = listItems_2_1.value;
3067
+ var command = parseCommand(listItem);
3068
+ switch (command.type) {
3069
+ case 'JOKER':
3070
+ jokers.push(command.parameterName);
3071
+ dependentParameterNames.add(command.parameterName);
3072
+ break;
3073
+ case 'EXECUTE':
3074
+ if (isExecutionTypeChanged) {
3075
+ throw new PromptbookSyntaxError('Execution type is already defined in the prompt template. It can be defined only once.');
3076
+ }
3077
+ executionType = command.executionType;
3078
+ isExecutionTypeChanged = true;
3079
+ break;
3080
+ case 'MODEL':
3081
+ templateModelRequirements[command.key] = command.value;
3082
+ break;
3083
+ case 'PARAMETER':
3084
+ // Note: This is just for detecting resulitng parameter name
3085
+ addParam(command);
3086
+ break;
3087
+ case 'POSTPROCESS':
3088
+ postprocessing.push(command.functionName);
3089
+ break;
3090
+ case 'EXPECT_AMOUNT':
3091
+ // eslint-disable-next-line no-case-declarations
3092
+ var unit = command.unit.toLowerCase();
3093
+ expectAmount[unit] = expectAmount[unit] || {};
3094
+ if (command.sign === 'MINIMUM' || command.sign === 'EXACTLY') {
3095
+ if (expectAmount[unit].min !== undefined) {
3096
+ throw new PromptbookSyntaxError("Already defined minumum ".concat(expectAmount[unit].min, " ").concat(command.unit.toLowerCase(), ", now trying to redefine it to ").concat(command.amount));
3097
+ }
3098
+ expectAmount[unit].min = command.amount;
3099
+ } /* not else */
3100
+ if (command.sign === 'MAXIMUM' || command.sign === 'EXACTLY') {
3101
+ if (expectAmount[unit].max !== undefined) {
3102
+ throw new PromptbookSyntaxError("Already defined maximum ".concat(expectAmount[unit].max, " ").concat(command.unit.toLowerCase(), ", now trying to redefine it to ").concat(command.amount));
3103
+ }
3104
+ expectAmount[unit].max = command.amount;
3105
+ }
3106
+ break;
3107
+ case 'EXPECT_FORMAT':
3108
+ if (expectFormat !== undefined && command.format !== expectFormat) {
3109
+ throw new PromptbookSyntaxError("Expect format is already defined to \"".concat(expectFormat, "\". Now you try to redefine it by \"").concat(command.format, "\"."));
3110
+ }
3111
+ expectFormat = command.format;
3112
+ break;
3113
+ default:
3114
+ throw new PromptbookSyntaxError("Command ".concat(command.type, " is not allowed in the block of the prompt template ONLY at the head of the promptbook"));
3115
+ }
3116
+ }
3117
+ }
3118
+ catch (e_3_1) { e_3 = { error: e_3_1 }; }
3119
+ finally {
3120
+ try {
3121
+ if (listItems_2_1 && !listItems_2_1.done && (_e = listItems_2.return)) _e.call(listItems_2);
3122
+ }
3123
+ finally { if (e_3) throw e_3.error; }
3124
+ }
3125
+ var _f = extractOneBlockFromMarkdown(section.content), language = _f.language, content = _f.content;
3126
+ if (executionType === 'SCRIPT') {
3127
+ if (!language) {
3128
+ throw new PromptbookSyntaxError('You must specify the language of the script in the prompt template');
3129
+ }
3130
+ else if (!SUPPORTED_SCRIPT_LANGUAGES.includes(language)) {
3131
+ throw new PromptbookSyntaxError(spaceTrim.spaceTrim(function (block) { return "\n Script language ".concat(language, " is not supported.\n\n Supported languages are:\n ").concat(block(SUPPORTED_SCRIPT_LANGUAGES.join(', ')), "\n\n "); }));
3132
+ }
3133
+ }
3134
+ var lastLine = section.content.split('\n').pop();
3135
+ var match = /^->\s*\{(?<resultingParamName>[a-z0-9_]+)\}/im.exec(lastLine);
3136
+ if (!match || match.groups === undefined || match.groups.resultingParamName === undefined) {
3137
+ throw new PromptbookSyntaxError(spaceTrim.spaceTrim(function (block) { return "\n Invalid template - each section must end with \"-> {...}\"\n\n Invalid section:\n ".concat(block(
3138
+ // TODO: Show code of invalid sections each time + DRY
3139
+ section.content
3140
+ .split('\n')
3141
+ .map(function (line) { return "> ".concat(line); })
3142
+ .join('\n')), "\n "); }));
3143
+ }
3144
+ var resultingParameterName = match.groups.resultingParamName;
3145
+ // TODO: [1] DRY description
3146
+ var description_1 = section.content;
3147
+ // Note: Remove codeblocks
3148
+ description_1 = description_1.split(/^```.*^```/gms).join('');
3149
+ //Note: Remove lists and return statement
3150
+ description_1 = description_1.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
3151
+ description_1 = spaceTrim.spaceTrim(description_1);
3152
+ if (description_1 === '') {
3153
+ description_1 = undefined;
3154
+ }
3155
+ if (Object.keys(jokers).length === 0) {
3156
+ jokers = undefined;
3157
+ }
3158
+ if (Object.keys(expectAmount).length === 0) {
3159
+ expectAmount = undefined;
3160
+ }
3161
+ if (Object.keys(postprocessing).length === 0) {
3162
+ postprocessing = undefined;
3163
+ }
3164
+ dependentParameterNames = union(dependentParameterNames, extractParametersFromPromptTemplate(__assign(__assign({}, section), { description: description_1, executionType: executionType, content: content })));
3165
+ if (templateModelRequirements.modelVariant === undefined) {
3166
+ templateModelRequirements.modelVariant = 'CHAT';
3167
+ }
3168
+ var template = {
3169
+ name: titleToName(section.title),
3170
+ title: section.title,
3171
+ description: description_1,
3172
+ dependentParameterNames: Array.from(dependentParameterNames),
3173
+ executionType: executionType,
3174
+ jokers: jokers,
3175
+ postprocessing: postprocessing,
3176
+ expectations: expectAmount,
3177
+ expectFormat: expectFormat,
3178
+ modelRequirements: templateModelRequirements,
3179
+ contentLanguage: executionType === 'SCRIPT' ? language : undefined,
3180
+ content: content,
3181
+ resultingParameterName: resultingParameterName,
3182
+ };
3183
+ if (executionType !== 'PROMPT_TEMPLATE') {
3184
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
3185
+ delete template.modelRequirements;
3186
+ }
3187
+ promptbookJson.promptTemplates.push(template);
3188
+ };
3189
+ try {
3190
+ for (var _c = __values(markdownStructure.sections), _d = _c.next(); !_d.done; _d = _c.next()) {
3191
+ var section = _d.value;
3192
+ _loop_1(section);
3193
+ }
3194
+ }
3195
+ catch (e_2_1) { e_2 = { error: e_2_1 }; }
3196
+ finally {
3197
+ try {
3198
+ if (_d && !_d.done && (_b = _c.return)) _b.call(_c);
3199
+ }
3200
+ finally { if (e_2) throw e_2.error; }
3201
+ }
3202
+ // =============================================================
3203
+ return promptbookJson;
3204
+ }
3205
+ /**
3206
+ * TODO: Report here line/column of error
3207
+ * TODO: Use spaceTrim more effectively
3208
+ * TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
3209
+ */
3210
+
2945
3211
  /**
2946
3212
  * Compile promptbook from string (markdown) format to JSON format
2947
3213
  *
3214
+ * Note: There are two similar functions:
3215
+ * - `promptbookStringToJson` **(preferred)** - which propperly compiles the promptbook and use embedding for external knowledge
3216
+ * - `promptbookStringToJsonSync` - use only if you need to compile promptbook synchronously and it contains NO external knowledge
3217
+ *
2948
3218
  * @param promptbookString {Promptbook} in string markdown format (.ptbk.md)
2949
3219
  * @param options - Options and tools for the compilation
2950
3220
  * @returns {Promptbook} compiled in JSON format (.ptbk.json)
@@ -2956,267 +3226,28 @@
2956
3226
  function promptbookStringToJson(promptbookString, options) {
2957
3227
  if (options === void 0) { options = {}; }
2958
3228
  return __awaiter(this, void 0, void 0, function () {
2959
- var llmTools, promptbookJson, knowledge, addParam, markdownStructure, markdownStructureDeepness, description, defaultModelRequirements, listItems, listItems_1, listItems_1_1, listItem, command, _loop_1, _a, _b, section;
2960
- var e_1, _c, e_2, _d;
2961
- return __generator(this, function (_e) {
2962
- switch (_e.label) {
3229
+ var llmTools, knowledge, promptbookJson;
3230
+ return __generator(this, function (_a) {
3231
+ switch (_a.label) {
2963
3232
  case 0:
2964
3233
  llmTools = options.llmTools;
2965
- promptbookJson = {
2966
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
2967
- title: undefined /* <- Note: Putting here placeholder to keep `title` on top at final JSON */,
2968
- promptbookUrl: undefined /* <- Note: Putting here placeholder to keep `promptbookUrl` on top at final JSON */,
2969
- promptbookVersion: PROMPTBOOK_VERSION,
2970
- description: undefined /* <- Note: Putting here placeholder to keep `description` on top at final JSON */,
2971
- parameters: [],
2972
- promptTemplates: [],
2973
- knowledge: [],
2974
- };
2975
3234
  if (!llmTools) return [3 /*break*/, 2];
2976
3235
  return [4 /*yield*/, prepareKnowledgeFromMarkdown({
2977
3236
  content: 'Roses are red, violets are blue, programmers use Promptbook, users too',
2978
3237
  llmTools: llmTools,
2979
3238
  })];
2980
3239
  case 1:
2981
- knowledge = _e.sent();
3240
+ knowledge = _a.sent();
2982
3241
  console.info('!!!! knowledge', knowledge);
2983
- _e.label = 2;
3242
+ _a.label = 2;
2984
3243
  case 2:
2985
- // =============================================================
2986
- // Note: 1️⃣ Normalization of the PROMPTBOOK string
2987
- promptbookString = removeContentComments(promptbookString);
2988
- promptbookString = promptbookString.replaceAll(/`\{(?<parameterName>[a-z0-9_]+)\}`/gi, '{$<parameterName>}');
2989
- promptbookString = promptbookString.replaceAll(/`->\s+\{(?<parameterName>[a-z0-9_]+)\}`/gi, '-> {$<parameterName>}');
2990
- addParam = function (parameterCommand) {
2991
- var parameterName = parameterCommand.parameterName, parameterDescription = parameterCommand.parameterDescription, isInput = parameterCommand.isInput, isOutput = parameterCommand.isOutput;
2992
- var existingParameter = promptbookJson.parameters.find(function (parameter) { return parameter.name === parameterName; });
2993
- if (existingParameter &&
2994
- existingParameter.description &&
2995
- existingParameter.description !== parameterDescription &&
2996
- parameterDescription) {
2997
- throw new PromptbookSyntaxError(spaceTrim.spaceTrim(function (block) { return "\n Parameter {".concat(parameterName, "} is defined multiple times with different description.\n\n First definition:\n ").concat(block(existingParameter.description || '[undefined]'), "\n\n Second definition:\n ").concat(block(parameterDescription || '[undefined]'), "\n "); }));
2998
- }
2999
- if (existingParameter) {
3000
- if (parameterDescription) {
3001
- existingParameter.description = parameterDescription;
3002
- }
3003
- }
3004
- else {
3005
- promptbookJson.parameters.push({
3006
- name: parameterName,
3007
- description: parameterDescription || undefined,
3008
- isInput: isInput,
3009
- isOutput: isOutput,
3010
- });
3011
- }
3012
- };
3013
- markdownStructure = markdownToMarkdownStructure(promptbookString);
3014
- markdownStructureDeepness = countMarkdownStructureDeepness(markdownStructure);
3015
- if (markdownStructureDeepness !== 2) {
3016
- throw new PromptbookSyntaxError(spaceTrim.spaceTrim("\n Invalid markdown structure.\n The markdown must have exactly 2 levels of headings (one top-level section and one section for each template).\n Now it has ".concat(markdownStructureDeepness, " levels of headings.\n ")));
3017
- }
3018
- promptbookJson.title = markdownStructure.title;
3019
- description = markdownStructure.content;
3020
- // Note: Remove codeblocks
3021
- description = description.split(/^```.*^```/gms).join('');
3022
- //Note: Remove lists and return statement
3023
- description = description.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
3024
- description = spaceTrim.spaceTrim(description);
3025
- if (description === '') {
3026
- description = undefined;
3027
- }
3028
- promptbookJson.description = description;
3029
- defaultModelRequirements = {};
3030
- listItems = extractAllListItemsFromMarkdown(markdownStructure.content);
3031
- try {
3032
- for (listItems_1 = __values(listItems), listItems_1_1 = listItems_1.next(); !listItems_1_1.done; listItems_1_1 = listItems_1.next()) {
3033
- listItem = listItems_1_1.value;
3034
- command = parseCommand(listItem);
3035
- switch (command.type) {
3036
- case 'PROMPTBOOK_URL':
3037
- promptbookJson.promptbookUrl = command.promptbookUrl.href;
3038
- break;
3039
- case 'PROMPTBOOK_VERSION':
3040
- promptbookJson.promptbookVersion = command.promptbookVersion;
3041
- break;
3042
- case 'MODEL':
3043
- defaultModelRequirements[command.key] = command.value;
3044
- break;
3045
- case 'PARAMETER':
3046
- addParam(command);
3047
- break;
3048
- default:
3049
- throw new PromptbookSyntaxError("Command ".concat(command.type, " is not allowed in the head of the promptbook ONLY at the prompt template block"));
3050
- }
3051
- }
3052
- }
3053
- catch (e_1_1) { e_1 = { error: e_1_1 }; }
3054
- finally {
3055
- try {
3056
- if (listItems_1_1 && !listItems_1_1.done && (_c = listItems_1.return)) _c.call(listItems_1);
3057
- }
3058
- finally { if (e_1) throw e_1.error; }
3059
- }
3060
- _loop_1 = function (section) {
3061
- var e_3, _f;
3062
- // TODO: Parse prompt template description (the content out of the codeblock and lists)
3063
- var templateModelRequirements = __assign({}, defaultModelRequirements);
3064
- var listItems_3 = extractAllListItemsFromMarkdown(section.content);
3065
- var dependentParameterNames = new Set();
3066
- var executionType = 'PROMPT_TEMPLATE';
3067
- var jokers = [];
3068
- var postprocessing = [];
3069
- var expectAmount = {};
3070
- var expectFormat = undefined;
3071
- var isExecutionTypeChanged = false;
3072
- try {
3073
- for (var listItems_2 = (e_3 = void 0, __values(listItems_3)), listItems_2_1 = listItems_2.next(); !listItems_2_1.done; listItems_2_1 = listItems_2.next()) {
3074
- var listItem = listItems_2_1.value;
3075
- var command = parseCommand(listItem);
3076
- switch (command.type) {
3077
- case 'JOKER':
3078
- jokers.push(command.parameterName);
3079
- dependentParameterNames.add(command.parameterName);
3080
- break;
3081
- case 'EXECUTE':
3082
- if (isExecutionTypeChanged) {
3083
- throw new PromptbookSyntaxError('Execution type is already defined in the prompt template. It can be defined only once.');
3084
- }
3085
- executionType = command.executionType;
3086
- isExecutionTypeChanged = true;
3087
- break;
3088
- case 'MODEL':
3089
- templateModelRequirements[command.key] = command.value;
3090
- break;
3091
- case 'PARAMETER':
3092
- // Note: This is just for detecting resulitng parameter name
3093
- addParam(command);
3094
- break;
3095
- case 'POSTPROCESS':
3096
- postprocessing.push(command.functionName);
3097
- break;
3098
- case 'EXPECT_AMOUNT':
3099
- // eslint-disable-next-line no-case-declarations
3100
- var unit = command.unit.toLowerCase();
3101
- expectAmount[unit] = expectAmount[unit] || {};
3102
- if (command.sign === 'MINIMUM' || command.sign === 'EXACTLY') {
3103
- if (expectAmount[unit].min !== undefined) {
3104
- throw new PromptbookSyntaxError("Already defined minumum ".concat(expectAmount[unit].min, " ").concat(command.unit.toLowerCase(), ", now trying to redefine it to ").concat(command.amount));
3105
- }
3106
- expectAmount[unit].min = command.amount;
3107
- } /* not else */
3108
- if (command.sign === 'MAXIMUM' || command.sign === 'EXACTLY') {
3109
- if (expectAmount[unit].max !== undefined) {
3110
- throw new PromptbookSyntaxError("Already defined maximum ".concat(expectAmount[unit].max, " ").concat(command.unit.toLowerCase(), ", now trying to redefine it to ").concat(command.amount));
3111
- }
3112
- expectAmount[unit].max = command.amount;
3113
- }
3114
- break;
3115
- case 'EXPECT_FORMAT':
3116
- if (expectFormat !== undefined && command.format !== expectFormat) {
3117
- throw new PromptbookSyntaxError("Expect format is already defined to \"".concat(expectFormat, "\". Now you try to redefine it by \"").concat(command.format, "\"."));
3118
- }
3119
- expectFormat = command.format;
3120
- break;
3121
- default:
3122
- throw new PromptbookSyntaxError("Command ".concat(command.type, " is not allowed in the block of the prompt template ONLY at the head of the promptbook"));
3123
- }
3124
- }
3125
- }
3126
- catch (e_3_1) { e_3 = { error: e_3_1 }; }
3127
- finally {
3128
- try {
3129
- if (listItems_2_1 && !listItems_2_1.done && (_f = listItems_2.return)) _f.call(listItems_2);
3130
- }
3131
- finally { if (e_3) throw e_3.error; }
3132
- }
3133
- var _g = extractOneBlockFromMarkdown(section.content), language = _g.language, content = _g.content;
3134
- if (executionType === 'SCRIPT') {
3135
- if (!language) {
3136
- throw new PromptbookSyntaxError('You must specify the language of the script in the prompt template');
3137
- }
3138
- else if (!SUPPORTED_SCRIPT_LANGUAGES.includes(language)) {
3139
- throw new PromptbookSyntaxError(spaceTrim.spaceTrim(function (block) { return "\n Script language ".concat(language, " is not supported.\n\n Supported languages are:\n ").concat(block(SUPPORTED_SCRIPT_LANGUAGES.join(', ')), "\n\n "); }));
3140
- }
3141
- }
3142
- var lastLine = section.content.split('\n').pop();
3143
- var match = /^->\s*\{(?<resultingParamName>[a-z0-9_]+)\}/im.exec(lastLine);
3144
- if (!match || match.groups === undefined || match.groups.resultingParamName === undefined) {
3145
- throw new PromptbookSyntaxError(spaceTrim.spaceTrim(function (block) { return "\n Invalid template - each section must end with \"-> {...}\"\n\n Invalid section:\n ".concat(block(
3146
- // TODO: Show code of invalid sections each time + DRY
3147
- section.content
3148
- .split('\n')
3149
- .map(function (line) { return "> ".concat(line); })
3150
- .join('\n')), "\n "); }));
3151
- }
3152
- var resultingParameterName = match.groups.resultingParamName;
3153
- // TODO: [1] DRY description
3154
- var description_1 = section.content;
3155
- // Note: Remove codeblocks
3156
- description_1 = description_1.split(/^```.*^```/gms).join('');
3157
- //Note: Remove lists and return statement
3158
- description_1 = description_1.split(/^(?:(?:-)|(?:\d\))|(?:`?->))\s+.*$/gm).join('');
3159
- description_1 = spaceTrim.spaceTrim(description_1);
3160
- if (description_1 === '') {
3161
- description_1 = undefined;
3162
- }
3163
- if (Object.keys(jokers).length === 0) {
3164
- jokers = undefined;
3165
- }
3166
- if (Object.keys(expectAmount).length === 0) {
3167
- expectAmount = undefined;
3168
- }
3169
- if (Object.keys(postprocessing).length === 0) {
3170
- postprocessing = undefined;
3171
- }
3172
- dependentParameterNames = union(dependentParameterNames, extractParametersFromPromptTemplate(__assign(__assign({}, section), { description: description_1, executionType: executionType, content: content })));
3173
- if (templateModelRequirements.modelVariant === undefined) {
3174
- templateModelRequirements.modelVariant = 'CHAT';
3175
- }
3176
- var template = {
3177
- name: titleToName(section.title),
3178
- title: section.title,
3179
- description: description_1,
3180
- dependentParameterNames: Array.from(dependentParameterNames),
3181
- executionType: executionType,
3182
- jokers: jokers,
3183
- postprocessing: postprocessing,
3184
- expectations: expectAmount,
3185
- expectFormat: expectFormat,
3186
- modelRequirements: templateModelRequirements,
3187
- contentLanguage: executionType === 'SCRIPT' ? language : undefined,
3188
- content: content,
3189
- resultingParameterName: resultingParameterName,
3190
- };
3191
- if (executionType !== 'PROMPT_TEMPLATE') {
3192
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3193
- delete template.modelRequirements;
3194
- }
3195
- promptbookJson.promptTemplates.push(template);
3196
- };
3197
- try {
3198
- for (_a = __values(markdownStructure.sections), _b = _a.next(); !_b.done; _b = _a.next()) {
3199
- section = _b.value;
3200
- _loop_1(section);
3201
- }
3202
- }
3203
- catch (e_2_1) { e_2 = { error: e_2_1 }; }
3204
- finally {
3205
- try {
3206
- if (_b && !_b.done && (_d = _a.return)) _d.call(_a);
3207
- }
3208
- finally { if (e_2) throw e_2.error; }
3209
- }
3210
- // =============================================================
3244
+ promptbookJson = promptbookStringToJsonSync(promptbookString);
3211
3245
  return [2 /*return*/, promptbookJson];
3212
3246
  }
3213
3247
  });
3214
3248
  });
3215
3249
  }
3216
3250
  /**
3217
- * TODO: Report here line/column of error
3218
- * TODO: Use spaceTrim more effectively
3219
- * TODO: [🧠] Parameter flags - isInput, isOutput, isInternal
3220
3251
  * TODO: [🏏] Leverage the batch API and build queues @see https://platform.openai.com/docs/guides/batch
3221
3252
  */
3222
3253
 
@@ -3571,9 +3602,10 @@
3571
3602
  helloCommand.option('--no-validation', "Do not validate logic of promptbooks in library", true);
3572
3603
  helloCommand.option('--validation', "Types of validations separated by comma (options \"logic\",\"imports\")", 'logic,imports');
3573
3604
  helloCommand.option('--verbose', "Is verbose", false);
3605
+ helloCommand.option('-o, --out-file', spaceTrim__default["default"]("\n Where to save the builded library\n\n Note: If you keep it \"".concat(PROMPTBOOK_MAKED_BASE_FILENAME, "\" it will be saved in the root of the promptbook directory\n If you set it to a path, it will be saved in that path\n BUT you can use only one format and set correct extension\n ")), PROMPTBOOK_MAKED_BASE_FILENAME);
3574
3606
  // TODO: !!! Auto-detect AI api keys + explicit api keys as argv
3575
3607
  helloCommand.action(function (path$1, _a) {
3576
- var projectName = _a.projectName, format = _a.format, validation = _a.validation, verbose = _a.verbose;
3608
+ var projectName = _a.projectName, format = _a.format, validation = _a.validation, verbose = _a.verbose, outFile = _a.outFile;
3577
3609
  return __awaiter(_this, void 0, void 0, function () {
3578
3610
  var formats, validations, library, validations_1, validations_1_1, validation_1, _b, _c, promptbookUrl, promptbook, e_1_1, e_2_1, libraryJson, libraryJsonString, saveFile;
3579
3611
  var e_2, _d, e_1, _e;
@@ -3581,7 +3613,7 @@
3581
3613
  return __generator(this, function (_f) {
3582
3614
  switch (_f.label) {
3583
3615
  case 0:
3584
- console.info('!!!', { projectName: projectName, path: path$1, format: format, validation: validation, verbose: verbose });
3616
+ console.info('!!!', { projectName: projectName, path: path$1, format: format, validation: validation, verbose: verbose, outFile: outFile });
3585
3617
  formats = (format || '')
3586
3618
  .split(',')
3587
3619
  .map(function (_) { return _.trim(); })
@@ -3590,6 +3622,9 @@
3590
3622
  .split(',')
3591
3623
  .map(function (_) { return _.trim(); })
3592
3624
  .filter(function (_) { return _ !== ''; });
3625
+ if (outFile !== PROMPTBOOK_MAKED_BASE_FILENAME && formats.length !== 1) {
3626
+ throw new Error("You can use only one format when saving to a file");
3627
+ }
3593
3628
  return [4 /*yield*/, createLibraryFromDirectory(path$1, {
3594
3629
  isVerbose: verbose,
3595
3630
  isRecursive: true,
@@ -3662,7 +3697,12 @@
3662
3697
  return __generator(this, function (_a) {
3663
3698
  switch (_a.label) {
3664
3699
  case 0:
3665
- filePath = path.join(path$1, "".concat(PROMPTBOOK_MAKED_BASE_FILENAME, ".").concat(extension));
3700
+ filePath = outFile !== PROMPTBOOK_MAKED_BASE_FILENAME
3701
+ ? outFile
3702
+ : path.join(path$1, "".concat(PROMPTBOOK_MAKED_BASE_FILENAME, ".").concat(extension));
3703
+ if (!outFile.endsWith(".".concat(extension))) {
3704
+ console.warn(colors__default["default"].yellow("Warning: Extension of output file should be \"".concat(extension, "\"")));
3705
+ }
3666
3706
  return [4 /*yield*/, promises.writeFile(filePath, content, 'utf-8')];
3667
3707
  case 1:
3668
3708
  _a.sent();