@promptbook/cli 0.89.0 → 0.92.0-10

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 (27) hide show
  1. package/README.md +4 -0
  2. package/esm/index.es.js +944 -94
  3. package/esm/index.es.js.map +1 -1
  4. package/esm/typings/src/_packages/core.index.d.ts +6 -0
  5. package/esm/typings/src/_packages/deepseek.index.d.ts +2 -0
  6. package/esm/typings/src/_packages/google.index.d.ts +2 -0
  7. package/esm/typings/src/_packages/utils.index.d.ts +2 -0
  8. package/esm/typings/src/cli/common/$provideLlmToolsForCli.d.ts +1 -1
  9. package/esm/typings/src/conversion/archive/loadArchive.d.ts +2 -2
  10. package/esm/typings/src/execution/CommonToolsOptions.d.ts +4 -0
  11. package/esm/typings/src/execution/createPipelineExecutor/getKnowledgeForTask.d.ts +12 -0
  12. package/esm/typings/src/execution/createPipelineExecutor/getReservedParametersForTask.d.ts +5 -0
  13. package/esm/typings/src/formats/csv/utils/csvParse.d.ts +12 -0
  14. package/esm/typings/src/formats/json/utils/jsonParse.d.ts +11 -0
  15. package/esm/typings/src/llm-providers/_common/filterModels.d.ts +15 -0
  16. package/esm/typings/src/llm-providers/_common/register/LlmToolsMetadata.d.ts +43 -0
  17. package/esm/typings/src/llm-providers/azure-openai/AzureOpenAiExecutionTools.d.ts +4 -0
  18. package/esm/typings/src/llm-providers/deepseek/deepseek-models.d.ts +23 -0
  19. package/esm/typings/src/llm-providers/google/google-models.d.ts +23 -0
  20. package/esm/typings/src/llm-providers/openai/OpenAiExecutionTools.d.ts +4 -0
  21. package/esm/typings/src/personas/preparePersona.d.ts +1 -1
  22. package/esm/typings/src/pipeline/PipelineJson/PersonaJson.d.ts +4 -2
  23. package/esm/typings/src/remote-server/openapi-types.d.ts +348 -6
  24. package/esm/typings/src/remote-server/openapi.d.ts +397 -3
  25. package/package.json +2 -1
  26. package/umd/index.umd.js +948 -98
  27. package/umd/index.umd.js.map +1 -1
package/esm/index.es.js CHANGED
@@ -27,6 +27,7 @@ import * as OpenApiValidator from 'express-openapi-validator';
27
27
  import swaggerUi from 'swagger-ui-express';
28
28
  import Anthropic from '@anthropic-ai/sdk';
29
29
  import { OpenAIClient, AzureKeyCredential } from '@azure/openai';
30
+ import Bottleneck from 'bottleneck';
30
31
  import OpenAI from 'openai';
31
32
  import { Readability } from '@mozilla/readability';
32
33
  import { JSDOM } from 'jsdom';
@@ -46,7 +47,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
46
47
  * @generated
47
48
  * @see https://github.com/webgptorg/promptbook
48
49
  */
49
- const PROMPTBOOK_ENGINE_VERSION = '0.89.0';
50
+ const PROMPTBOOK_ENGINE_VERSION = '0.92.0-10';
50
51
  /**
51
52
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
52
53
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -1004,6 +1005,45 @@ function $sideEffect(...sideEffectSubjects) {
1004
1005
  keepUnused(...sideEffectSubjects);
1005
1006
  }
1006
1007
 
1008
+ /**
1009
+ * Converts a JavaScript Object Notation (JSON) string into an object.
1010
+ *
1011
+ * Note: This is wrapper around `JSON.parse()` with better error and type handling
1012
+ *
1013
+ * @public exported from `@promptbook/utils`
1014
+ */
1015
+ function jsonParse(value) {
1016
+ if (value === undefined) {
1017
+ throw new Error(`Can not parse JSON from undefined value.`);
1018
+ }
1019
+ else if (typeof value !== 'string') {
1020
+ console.error('Can not parse JSON from non-string value.', { text: value });
1021
+ throw new Error(spaceTrim(`
1022
+ Can not parse JSON from non-string value.
1023
+
1024
+ The value type: ${typeof value}
1025
+ See more in console.
1026
+ `));
1027
+ }
1028
+ try {
1029
+ return JSON.parse(value);
1030
+ }
1031
+ catch (error) {
1032
+ if (!(error instanceof Error)) {
1033
+ throw error;
1034
+ }
1035
+ throw new Error(spaceTrim((block) => `
1036
+ ${block(error.message)}
1037
+
1038
+ The JSON text:
1039
+ ${block(value)}
1040
+ `));
1041
+ }
1042
+ }
1043
+ /**
1044
+ * TODO: !!!! Use in Promptbook.studio
1045
+ */
1046
+
1007
1047
  /**
1008
1048
  * Convert identification to Promptbook token
1009
1049
  *
@@ -2085,7 +2125,7 @@ class FileCacheStorage {
2085
2125
  return null;
2086
2126
  }
2087
2127
  const fileContent = await readFile(filename, 'utf-8');
2088
- const value = JSON.parse(fileContent);
2128
+ const value = jsonParse(fileContent);
2089
2129
  // TODO: [🌗]
2090
2130
  return value;
2091
2131
  }
@@ -3420,7 +3460,7 @@ async function $provideLlmToolsForCli(options) {
3420
3460
  password,
3421
3461
  }),
3422
3462
  });
3423
- const { isSuccess, message, error, identification } = (await response.json());
3463
+ const { isSuccess, message, error, identification } = jsonParse(await response.text());
3424
3464
  if (message) {
3425
3465
  if (isSuccess) {
3426
3466
  console.log(colors.green(message));
@@ -4451,7 +4491,7 @@ async function loadArchive(filePath, fs) {
4451
4491
  if (!indexFile) {
4452
4492
  throw new UnexpectedError(`Archive does not contain 'index.book.json' file`);
4453
4493
  }
4454
- const collectionJson = JSON.parse(await indexFile.async('text'));
4494
+ const collectionJson = jsonParse(await indexFile.async('text'));
4455
4495
  for (const pipeline of collectionJson) {
4456
4496
  validatePipeline(pipeline);
4457
4497
  }
@@ -4461,7 +4501,7 @@ async function loadArchive(filePath, fs) {
4461
4501
  * Note: [🟢] Code in this file should never be never released in packages that could be imported into browser environment
4462
4502
  */
4463
4503
 
4464
- var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",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`\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"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",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`\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"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",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- 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`\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- 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"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",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`\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"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",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 workflow:\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- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",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`\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 workflow:\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- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
4504
+ var PipelineCollection = [{title:"Prepare Knowledge from Markdown",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-from-markdown.book",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`\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"},{title:"Prepare Keywords",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-keywords.book",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`\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"},{title:"Prepare Knowledge-piece Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-knowledge-title.book",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- 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`\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- 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"},{title:"Prepare Persona",pipelineUrl:"https://promptbook.studio/promptbook/prepare-persona.book",formfactorName:"GENERIC",parameters:[{name:"availableModels",description:"List of available model names together with their descriptions as JSON",isInput:true,isOutput:false},{name:"personaDescription",description:"Description of the persona",isInput:true,isOutput:false},{name:"modelsRequirements",description:"Specific requirements for the model",isInput:false,isOutput:true}],tasks:[{taskType:"PROMPT_TASK",name:"make-model-requirements",title:"Make modelRequirements",content:"You are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n```json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n```\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with 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\nHere are the available models:\n\n```json\n{availableModels}\n```\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:"modelsRequirements",format:"JSON",dependentParameterNames:["availableModels","personaDescription"]}],personas:[],preparations:[],knowledgeSources:[],knowledgePieces:[],sources:[{type:"BOOK",path:null,content:"# Prepare Persona\n\n- PIPELINE URL `https://promptbook.studio/promptbook/prepare-persona.book`\n- INPUT PARAMETER `{availableModels}` List of available model names together with their descriptions as JSON\n- INPUT PARAMETER `{personaDescription}` Description of the persona\n- OUTPUT PARAMETER `{modelsRequirements}` Specific requirements for the model\n\n## Make modelRequirements\n\n- FORMAT JSON\n\n```markdown\nYou are an experienced AI engineer, you need to find the best models for virtual assistants:\n\n## Example\n\n\\`\\`\\`json\n[\n {\n \"modelName\": \"gpt-4o\",\n \"systemMessage\": \"You are experienced AI engineer and helpfull assistant.\",\n \"temperature\": 0.7\n },\n {\n \"modelName\": \"claude-3-5-sonnet\",\n \"systemMessage\": \"You are a friendly and knowledgeable chatbot.\",\n \"temperature\": 0.5\n }\n]\n\\`\\`\\`\n\n## Instructions\n\n- Your output format is JSON array\n- Sort best-fitting models first\n- Omit any models that are not suitable\n- Write just the JSON, no other text should be present\n- Array contain items with 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\nHere are the available models:\n\n\\`\\`\\`json\n{availableModels}\n\\`\\`\\`\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`-> {modelsRequirements}`\n"}],sourceFile:"./books/prepare-persona.book"},{title:"Prepare Title",pipelineUrl:"https://promptbook.studio/promptbook/prepare-title.book",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 workflow:\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- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}",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`\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 workflow:\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- Title starts with emoticon\n- Title should not mention the input and output of the workflow but the main purpose of the workflow\n _For example, not \"✍ Convert Knowledge-piece to title\" but \"✍ Title\"_\n\n## The workflow\n\n> {book}\n```\n\n`-> {title}`\n"}],sourceFile:"./books/prepare-title.book"}];
4465
4505
 
4466
4506
  /**
4467
4507
  * Function isValidJsonString will tell you if the string is valid JSON or not
@@ -4722,7 +4762,7 @@ function extractParameterNames(template) {
4722
4762
  */
4723
4763
  function unpreparePipeline(pipeline) {
4724
4764
  let { personas, knowledgeSources, tasks } = pipeline;
4725
- personas = personas.map((persona) => ({ ...persona, modelRequirements: undefined, preparationIds: undefined }));
4765
+ personas = personas.map((persona) => ({ ...persona, modelsRequirements: undefined, preparationIds: undefined }));
4726
4766
  knowledgeSources = knowledgeSources.map((knowledgeSource) => ({ ...knowledgeSource, preparationIds: undefined }));
4727
4767
  tasks = tasks.map((task) => {
4728
4768
  let { dependentParameterNames } = task;
@@ -4880,7 +4920,7 @@ function isPipelinePrepared(pipeline) {
4880
4920
  if (pipeline.title === undefined || pipeline.title === '' || pipeline.title === DEFAULT_BOOK_TITLE) {
4881
4921
  return false;
4882
4922
  }
4883
- if (!pipeline.personas.every((persona) => persona.modelRequirements !== undefined)) {
4923
+ if (!pipeline.personas.every((persona) => persona.modelsRequirements !== undefined)) {
4884
4924
  return false;
4885
4925
  }
4886
4926
  if (!pipeline.knowledgeSources.every((knowledgeSource) => knowledgeSource.preparationIds !== undefined)) {
@@ -4922,7 +4962,7 @@ function jsonStringsToJsons(object) {
4922
4962
  const newObject = { ...object };
4923
4963
  for (const [key, value] of Object.entries(object)) {
4924
4964
  if (typeof value === 'string' && isValidJsonString(value)) {
4925
- newObject[key] = JSON.parse(value);
4965
+ newObject[key] = jsonParse(value);
4926
4966
  }
4927
4967
  else {
4928
4968
  newObject[key] = jsonStringsToJsons(value);
@@ -5375,6 +5415,24 @@ function isValidCsvString(value) {
5375
5415
  }
5376
5416
  }
5377
5417
 
5418
+ /**
5419
+ * Converts a CSV string into an object
5420
+ *
5421
+ * Note: This is wrapper around `papaparse.parse()` with better autohealing
5422
+ *
5423
+ * @private - for now until `@promptbook/csv` is released
5424
+ */
5425
+ function csvParse(value /* <- TODO: string_csv */, settings, schema /* <- TODO: Make CSV Schemas */) {
5426
+ settings = { ...settings, ...MANDATORY_CSV_SETTINGS };
5427
+ // Note: Autoheal invalid '\n' characters
5428
+ if (settings.newline && !settings.newline.includes('\r') && value.includes('\r')) {
5429
+ console.warn('CSV string contains carriage return characters, but in the CSV settings the `newline` setting does not include them. Autohealing the CSV string.');
5430
+ value = value.replace(/\r\n/g, '\n').replace(/\r/g, '\n');
5431
+ }
5432
+ const csv = parse(value, settings);
5433
+ return csv;
5434
+ }
5435
+
5378
5436
  /**
5379
5437
  * Definition for CSV spreadsheet
5380
5438
  *
@@ -5397,8 +5455,7 @@ const CsvFormatDefinition = {
5397
5455
  {
5398
5456
  subvalueName: 'ROW',
5399
5457
  async mapValues(value, outputParameterName, settings, mapCallback) {
5400
- // TODO: [👨🏾‍🤝‍👨🏼] DRY csv parsing
5401
- const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
5458
+ const csv = csvParse(value, settings);
5402
5459
  if (csv.errors.length !== 0) {
5403
5460
  throw new CsvFormatError(spaceTrim((block) => `
5404
5461
  CSV parsing error
@@ -5428,8 +5485,7 @@ const CsvFormatDefinition = {
5428
5485
  {
5429
5486
  subvalueName: 'CELL',
5430
5487
  async mapValues(value, outputParameterName, settings, mapCallback) {
5431
- // TODO: [👨🏾‍🤝‍👨🏼] DRY csv parsing
5432
- const csv = parse(value, { ...settings, ...MANDATORY_CSV_SETTINGS });
5488
+ const csv = csvParse(value, settings);
5433
5489
  if (csv.errors.length !== 0) {
5434
5490
  throw new CsvFormatError(spaceTrim((block) => `
5435
5491
  CSV parsing error
@@ -6477,13 +6533,79 @@ async function getExamplesForTask(task) {
6477
6533
  /**
6478
6534
  * @@@
6479
6535
  *
6536
+ * Here is the place where RAG (retrieval-augmented generation) happens
6537
+ *
6480
6538
  * @private internal utility of `createPipelineExecutor`
6481
6539
  */
6482
6540
  async function getKnowledgeForTask(options) {
6483
- const { preparedPipeline, task } = options;
6484
- return preparedPipeline.knowledgePieces.map(({ content }) => `- ${content}`).join('\n');
6541
+ const { tools, preparedPipeline, task } = options;
6542
+ const firstKnowlegePiece = preparedPipeline.knowledgePieces[0];
6543
+ const firstKnowlegeIndex = firstKnowlegePiece === null || firstKnowlegePiece === void 0 ? void 0 : firstKnowlegePiece.index[0];
6544
+ // <- TODO: Do not use just first knowledge piece and first index to determine embedding model, use also keyword search
6545
+ if (firstKnowlegePiece === undefined || firstKnowlegeIndex === undefined) {
6546
+ return 'No knowledge pieces found';
6547
+ }
6548
+ // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
6549
+ const _llms = arrayableToArray(tools.llm);
6550
+ const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
6551
+ const taskEmbeddingPrompt = {
6552
+ title: 'Knowledge Search',
6553
+ modelRequirements: {
6554
+ modelVariant: 'EMBEDDING',
6555
+ modelName: firstKnowlegeIndex.modelName,
6556
+ },
6557
+ content: task.content,
6558
+ parameters: {
6559
+ /* !!!!!!!! */
6560
+ },
6561
+ };
6562
+ const taskEmbeddingResult = await llmTools.callEmbeddingModel(taskEmbeddingPrompt);
6563
+ const knowledgePiecesWithRelevance = preparedPipeline.knowledgePieces.map((knowledgePiece) => {
6564
+ const { index } = knowledgePiece;
6565
+ const knowledgePieceIndex = index.find((i) => i.modelName === firstKnowlegeIndex.modelName);
6566
+ // <- TODO: Do not use just first knowledge piece and first index to determine embedding model
6567
+ if (knowledgePieceIndex === undefined) {
6568
+ return {
6569
+ content: knowledgePiece.content,
6570
+ relevance: 0,
6571
+ };
6572
+ }
6573
+ const relevance = computeCosineSimilarity(knowledgePieceIndex.position, taskEmbeddingResult.content);
6574
+ return {
6575
+ content: knowledgePiece.content,
6576
+ relevance,
6577
+ };
6578
+ });
6579
+ const knowledgePiecesSorted = knowledgePiecesWithRelevance.sort((a, b) => a.relevance - b.relevance);
6580
+ const knowledgePiecesLimited = knowledgePiecesSorted.slice(0, 5);
6581
+ console.log('!!! Embedding', {
6582
+ task,
6583
+ taskEmbeddingPrompt,
6584
+ taskEmbeddingResult,
6585
+ firstKnowlegePiece,
6586
+ firstKnowlegeIndex,
6587
+ knowledgePiecesWithRelevance,
6588
+ knowledgePiecesSorted,
6589
+ knowledgePiecesLimited,
6590
+ });
6591
+ return knowledgePiecesLimited.map(({ content }) => `- ${content}`).join('\n');
6485
6592
  // <- TODO: [🧠] Some smart aggregation of knowledge pieces, single-line vs multi-line vs mixed
6486
6593
  }
6594
+ // TODO: !!!!!! Annotate + to new file
6595
+ function computeCosineSimilarity(embeddingVector1, embeddingVector2) {
6596
+ if (embeddingVector1.length !== embeddingVector2.length) {
6597
+ throw new TypeError('Embedding vectors must have the same length');
6598
+ }
6599
+ const dotProduct = embeddingVector1.reduce((sum, value, index) => sum + value * embeddingVector2[index], 0);
6600
+ const magnitude1 = Math.sqrt(embeddingVector1.reduce((sum, value) => sum + value * value, 0));
6601
+ const magnitude2 = Math.sqrt(embeddingVector2.reduce((sum, value) => sum + value * value, 0));
6602
+ return 1 - dotProduct / (magnitude1 * magnitude2);
6603
+ }
6604
+ /**
6605
+ * TODO: !!!! Verify if this is working
6606
+ * TODO: [♨] Implement Better - use keyword search
6607
+ * TODO: [♨] Examples of values
6608
+ */
6487
6609
 
6488
6610
  /**
6489
6611
  * @@@
@@ -6491,9 +6613,9 @@ async function getKnowledgeForTask(options) {
6491
6613
  * @private internal utility of `createPipelineExecutor`
6492
6614
  */
6493
6615
  async function getReservedParametersForTask(options) {
6494
- const { preparedPipeline, task, pipelineIdentification } = options;
6616
+ const { tools, preparedPipeline, task, pipelineIdentification } = options;
6495
6617
  const context = await getContextForTask(); // <- [🏍]
6496
- const knowledge = await getKnowledgeForTask({ preparedPipeline, task });
6618
+ const knowledge = await getKnowledgeForTask({ tools, preparedPipeline, task });
6497
6619
  const examples = await getExamplesForTask();
6498
6620
  const currentDate = new Date().toISOString(); // <- TODO: [🧠][💩] Better
6499
6621
  const modelName = RESERVED_PARAMETER_MISSING_VALUE;
@@ -6555,6 +6677,7 @@ async function executeTask(options) {
6555
6677
  }
6556
6678
  const definedParameters = Object.freeze({
6557
6679
  ...(await getReservedParametersForTask({
6680
+ tools,
6558
6681
  preparedPipeline,
6559
6682
  task: currentTask,
6560
6683
  pipelineIdentification,
@@ -7040,27 +7163,48 @@ async function preparePersona(personaDescription, tools, options) {
7040
7163
  pipeline: await collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book'),
7041
7164
  tools,
7042
7165
  });
7043
- // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
7044
7166
  const _llms = arrayableToArray(tools.llm);
7045
7167
  const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
7046
- const availableModels = await llmTools.listModels();
7047
- const availableModelNames = availableModels
7168
+ const availableModels = (await llmTools.listModels())
7048
7169
  .filter(({ modelVariant }) => modelVariant === 'CHAT')
7049
- .map(({ modelName }) => modelName)
7050
- .join(',');
7051
- const result = await preparePersonaExecutor({ availableModelNames, personaDescription }).asPromise();
7170
+ .map(({ modelName, modelDescription }) => ({
7171
+ modelName,
7172
+ modelDescription,
7173
+ // <- Note: `modelTitle` and `modelVariant` is not relevant for this task
7174
+ }));
7175
+ const result = await preparePersonaExecutor({
7176
+ availableModels /* <- Note: Passing as JSON */,
7177
+ personaDescription,
7178
+ }).asPromise();
7052
7179
  const { outputParameters } = result;
7053
- const { modelRequirements: modelRequirementsRaw } = outputParameters;
7054
- const modelRequirements = JSON.parse(modelRequirementsRaw);
7180
+ const { modelsRequirements: modelsRequirementsJson } = outputParameters;
7181
+ let modelsRequirementsUnchecked = jsonParse(modelsRequirementsJson);
7055
7182
  if (isVerbose) {
7056
- console.info(`PERSONA ${personaDescription}`, modelRequirements);
7183
+ console.info(`PERSONA ${personaDescription}`, modelsRequirementsUnchecked);
7057
7184
  }
7058
- const { modelName, systemMessage, temperature } = modelRequirements;
7059
- return {
7185
+ if (!Array.isArray(modelsRequirementsUnchecked)) {
7186
+ // <- TODO: Book should have syntax and system to enforce shape of JSON
7187
+ modelsRequirementsUnchecked = [modelsRequirementsUnchecked];
7188
+ /*
7189
+ throw new UnexpectedError(
7190
+ spaceTrim(
7191
+ (block) => `
7192
+ Invalid \`modelsRequirements\`:
7193
+
7194
+ \`\`\`json
7195
+ ${block(JSON.stringify(modelsRequirementsUnchecked, null, 4))}
7196
+ \`\`\`
7197
+ `,
7198
+ ),
7199
+ );
7200
+ */
7201
+ }
7202
+ const modelsRequirements = modelsRequirementsUnchecked.map((modelRequirements) => ({
7060
7203
  modelVariant: 'CHAT',
7061
- modelName,
7062
- systemMessage,
7063
- temperature,
7204
+ ...modelRequirements,
7205
+ }));
7206
+ return {
7207
+ modelsRequirements,
7064
7208
  };
7065
7209
  }
7066
7210
  /**
@@ -7229,7 +7373,7 @@ async function makeKnowledgeSourceHandler(knowledgeSource, tools, options) {
7229
7373
  > },
7230
7374
  */
7231
7375
  async asJson() {
7232
- return JSON.parse(await tools.fs.readFile(filename, 'utf-8'));
7376
+ return jsonParse(await tools.fs.readFile(filename, 'utf-8'));
7233
7377
  },
7234
7378
  async asText() {
7235
7379
  return await tools.fs.readFile(filename, 'utf-8');
@@ -7487,14 +7631,14 @@ async function preparePipeline(pipeline, tools, options) {
7487
7631
  // TODO: [🖌][🧠] Implement some `mapAsync` function
7488
7632
  const preparedPersonas = new Array(personas.length);
7489
7633
  await forEachAsync(personas, { maxParallelCount /* <- TODO: [🪂] When there are subtasks, this maximul limit can be broken */ }, async (persona, index) => {
7490
- const modelRequirements = await preparePersona(persona.description, { ...tools, llm: llmToolsWithUsage }, {
7634
+ const { modelsRequirements } = await preparePersona(persona.description, { ...tools, llm: llmToolsWithUsage }, {
7491
7635
  rootDirname,
7492
7636
  maxParallelCount /* <- TODO: [🪂] */,
7493
7637
  isVerbose,
7494
7638
  });
7495
7639
  const preparedPersona = {
7496
7640
  ...persona,
7497
- modelRequirements,
7641
+ modelsRequirements,
7498
7642
  preparationIds: [/* TODO: [🧊] -> */ currentPreparation.id],
7499
7643
  // <- TODO: [🍙] Make some standard order of json properties
7500
7644
  };
@@ -12934,7 +13078,7 @@ function $initializeRunCommand(program) {
12934
13078
  }
12935
13079
  let inputParameters = {};
12936
13080
  if (json) {
12937
- inputParameters = JSON.parse(json);
13081
+ inputParameters = jsonParse(json);
12938
13082
  // <- TODO: Maybe check shape of passed JSON and if its valid parameters Record
12939
13083
  }
12940
13084
  // TODO: DRY [◽]
@@ -13165,7 +13309,7 @@ function $initializeRunCommand(program) {
13165
13309
  const openapiJson = {
13166
13310
  openapi: '3.0.0',
13167
13311
  info: {
13168
- title: 'Promptbook Remote Server API (!!!! From TS)',
13312
+ title: 'Promptbook Remote Server API (!!!! From YML)',
13169
13313
  version: '1.0.0',
13170
13314
  description: 'API documentation for the Promptbook Remote Server',
13171
13315
  },
@@ -13177,6 +13321,13 @@ const openapiJson = {
13177
13321
  responses: {
13178
13322
  '200': {
13179
13323
  description: 'Server details in markdown format.',
13324
+ content: {
13325
+ 'text/markdown': {
13326
+ schema: {
13327
+ type: 'string',
13328
+ },
13329
+ },
13330
+ },
13180
13331
  },
13181
13332
  },
13182
13333
  },
@@ -13207,13 +13358,22 @@ const openapiJson = {
13207
13358
  },
13208
13359
  },
13209
13360
  responses: {
13210
- '200': {
13361
+ '201': {
13211
13362
  description: 'Successful login',
13212
13363
  content: {
13213
13364
  'application/json': {
13214
13365
  schema: {
13215
13366
  type: 'object',
13216
13367
  properties: {
13368
+ isSuccess: {
13369
+ type: 'boolean',
13370
+ },
13371
+ message: {
13372
+ type: 'string',
13373
+ },
13374
+ error: {
13375
+ type: 'object',
13376
+ },
13217
13377
  identification: {
13218
13378
  type: 'object',
13219
13379
  },
@@ -13222,6 +13382,43 @@ const openapiJson = {
13222
13382
  },
13223
13383
  },
13224
13384
  },
13385
+ '400': {
13386
+ description: 'Bad request or login failed',
13387
+ content: {
13388
+ 'application/json': {
13389
+ schema: {
13390
+ type: 'object',
13391
+ properties: {
13392
+ error: {
13393
+ type: 'object',
13394
+ },
13395
+ },
13396
+ },
13397
+ },
13398
+ },
13399
+ },
13400
+ '401': {
13401
+ description: 'Authentication error',
13402
+ content: {
13403
+ 'application/json': {
13404
+ schema: {
13405
+ type: 'object',
13406
+ properties: {
13407
+ isSuccess: {
13408
+ type: 'boolean',
13409
+ enum: [false],
13410
+ },
13411
+ message: {
13412
+ type: 'string',
13413
+ },
13414
+ error: {
13415
+ type: 'object',
13416
+ },
13417
+ },
13418
+ },
13419
+ },
13420
+ },
13421
+ },
13225
13422
  },
13226
13423
  },
13227
13424
  },
@@ -13243,6 +13440,16 @@ const openapiJson = {
13243
13440
  },
13244
13441
  },
13245
13442
  },
13443
+ '500': {
13444
+ description: 'No collection available',
13445
+ content: {
13446
+ 'text/plain': {
13447
+ schema: {
13448
+ type: 'string',
13449
+ },
13450
+ },
13451
+ },
13452
+ },
13246
13453
  },
13247
13454
  },
13248
13455
  },
@@ -13274,6 +13481,28 @@ const openapiJson = {
13274
13481
  },
13275
13482
  '404': {
13276
13483
  description: 'Book not found.',
13484
+ content: {
13485
+ 'application/json': {
13486
+ schema: {
13487
+ type: 'object',
13488
+ properties: {
13489
+ error: {
13490
+ type: 'object',
13491
+ },
13492
+ },
13493
+ },
13494
+ },
13495
+ },
13496
+ },
13497
+ '500': {
13498
+ description: 'No collection available',
13499
+ content: {
13500
+ 'text/plain': {
13501
+ schema: {
13502
+ type: 'string',
13503
+ },
13504
+ },
13505
+ },
13277
13506
  },
13278
13507
  },
13279
13508
  },
@@ -13291,6 +13520,28 @@ const openapiJson = {
13291
13520
  type: 'array',
13292
13521
  items: {
13293
13522
  type: 'object',
13523
+ properties: {
13524
+ nonce: {
13525
+ type: 'string',
13526
+ },
13527
+ taskId: {
13528
+ type: 'string',
13529
+ },
13530
+ taskType: {
13531
+ type: 'string',
13532
+ },
13533
+ status: {
13534
+ type: 'string',
13535
+ },
13536
+ createdAt: {
13537
+ type: 'string',
13538
+ format: 'date-time',
13539
+ },
13540
+ updatedAt: {
13541
+ type: 'string',
13542
+ format: 'date-time',
13543
+ },
13544
+ },
13294
13545
  },
13295
13546
  },
13296
13547
  },
@@ -13299,6 +13550,147 @@ const openapiJson = {
13299
13550
  },
13300
13551
  },
13301
13552
  },
13553
+ '/executions/last': {
13554
+ get: {
13555
+ summary: 'Get the last execution',
13556
+ description: 'Returns details of the last execution task.',
13557
+ responses: {
13558
+ '200': {
13559
+ description: 'The last execution task with full details.',
13560
+ content: {
13561
+ 'application/json': {
13562
+ schema: {
13563
+ type: 'object',
13564
+ properties: {
13565
+ nonce: {
13566
+ type: 'string',
13567
+ },
13568
+ taskId: {
13569
+ type: 'string',
13570
+ },
13571
+ taskType: {
13572
+ type: 'string',
13573
+ },
13574
+ status: {
13575
+ type: 'string',
13576
+ },
13577
+ errors: {
13578
+ type: 'array',
13579
+ items: {
13580
+ type: 'object',
13581
+ },
13582
+ },
13583
+ warnings: {
13584
+ type: 'array',
13585
+ items: {
13586
+ type: 'object',
13587
+ },
13588
+ },
13589
+ createdAt: {
13590
+ type: 'string',
13591
+ format: 'date-time',
13592
+ },
13593
+ updatedAt: {
13594
+ type: 'string',
13595
+ format: 'date-time',
13596
+ },
13597
+ currentValue: {
13598
+ type: 'object',
13599
+ },
13600
+ },
13601
+ },
13602
+ },
13603
+ },
13604
+ },
13605
+ '404': {
13606
+ description: 'No execution tasks found.',
13607
+ content: {
13608
+ 'text/plain': {
13609
+ schema: {
13610
+ type: 'string',
13611
+ },
13612
+ },
13613
+ },
13614
+ },
13615
+ },
13616
+ },
13617
+ },
13618
+ '/executions/{taskId}': {
13619
+ get: {
13620
+ summary: 'Get specific execution',
13621
+ description: 'Returns details of a specific execution task.',
13622
+ parameters: [
13623
+ {
13624
+ in: 'path',
13625
+ name: 'taskId',
13626
+ required: true,
13627
+ schema: {
13628
+ type: 'string',
13629
+ },
13630
+ description: 'The ID of the execution task to retrieve.',
13631
+ },
13632
+ ],
13633
+ responses: {
13634
+ '200': {
13635
+ description: 'The execution task with full details.',
13636
+ content: {
13637
+ 'application/json': {
13638
+ schema: {
13639
+ type: 'object',
13640
+ properties: {
13641
+ nonce: {
13642
+ type: 'string',
13643
+ },
13644
+ taskId: {
13645
+ type: 'string',
13646
+ },
13647
+ taskType: {
13648
+ type: 'string',
13649
+ },
13650
+ status: {
13651
+ type: 'string',
13652
+ },
13653
+ errors: {
13654
+ type: 'array',
13655
+ items: {
13656
+ type: 'object',
13657
+ },
13658
+ },
13659
+ warnings: {
13660
+ type: 'array',
13661
+ items: {
13662
+ type: 'object',
13663
+ },
13664
+ },
13665
+ createdAt: {
13666
+ type: 'string',
13667
+ format: 'date-time',
13668
+ },
13669
+ updatedAt: {
13670
+ type: 'string',
13671
+ format: 'date-time',
13672
+ },
13673
+ currentValue: {
13674
+ type: 'object',
13675
+ },
13676
+ },
13677
+ },
13678
+ },
13679
+ },
13680
+ },
13681
+ '404': {
13682
+ description: 'Execution task not found.',
13683
+ content: {
13684
+ 'text/plain': {
13685
+ schema: {
13686
+ type: 'string',
13687
+ },
13688
+ },
13689
+ },
13690
+ },
13691
+ },
13692
+ },
13693
+ },
13302
13694
  '/executions/new': {
13303
13695
  post: {
13304
13696
  summary: 'Start a new execution',
@@ -13312,12 +13704,19 @@ const openapiJson = {
13312
13704
  properties: {
13313
13705
  pipelineUrl: {
13314
13706
  type: 'string',
13707
+ description: 'URL of the pipeline to execute',
13708
+ },
13709
+ book: {
13710
+ type: 'string',
13711
+ description: 'Alternative field for pipelineUrl',
13315
13712
  },
13316
13713
  inputParameters: {
13317
13714
  type: 'object',
13715
+ description: 'Parameters for pipeline execution',
13318
13716
  },
13319
13717
  identification: {
13320
13718
  type: 'object',
13719
+ description: 'User identification data',
13321
13720
  },
13322
13721
  },
13323
13722
  },
@@ -13337,13 +13736,164 @@ const openapiJson = {
13337
13736
  },
13338
13737
  '400': {
13339
13738
  description: 'Invalid input.',
13739
+ content: {
13740
+ 'application/json': {
13741
+ schema: {
13742
+ type: 'object',
13743
+ properties: {
13744
+ error: {
13745
+ type: 'object',
13746
+ },
13747
+ },
13748
+ },
13749
+ },
13750
+ },
13751
+ },
13752
+ '404': {
13753
+ description: 'Pipeline not found.',
13754
+ content: {
13755
+ 'text/plain': {
13756
+ schema: {
13757
+ type: 'string',
13758
+ },
13759
+ },
13760
+ },
13761
+ },
13762
+ },
13763
+ },
13764
+ },
13765
+ '/api-docs': {
13766
+ get: {
13767
+ summary: 'API documentation UI',
13768
+ description: 'Swagger UI for API documentation',
13769
+ responses: {
13770
+ '200': {
13771
+ description: 'HTML Swagger UI',
13772
+ },
13773
+ },
13774
+ },
13775
+ },
13776
+ '/swagger': {
13777
+ get: {
13778
+ summary: 'API documentation UI (alternative path)',
13779
+ description: 'Swagger UI for API documentation',
13780
+ responses: {
13781
+ '200': {
13782
+ description: 'HTML Swagger UI',
13783
+ },
13784
+ },
13785
+ },
13786
+ },
13787
+ '/openapi': {
13788
+ get: {
13789
+ summary: 'OpenAPI specification',
13790
+ description: 'Returns the OpenAPI JSON specification',
13791
+ responses: {
13792
+ '200': {
13793
+ description: 'OpenAPI specification',
13794
+ content: {
13795
+ 'application/json': {
13796
+ schema: {
13797
+ type: 'object',
13798
+ },
13799
+ },
13800
+ },
13340
13801
  },
13341
13802
  },
13342
13803
  },
13343
13804
  },
13344
13805
  },
13345
- components: {},
13346
- tags: [],
13806
+ components: {
13807
+ schemas: {
13808
+ Error: {
13809
+ type: 'object',
13810
+ properties: {
13811
+ error: {
13812
+ type: 'object',
13813
+ },
13814
+ },
13815
+ },
13816
+ ExecutionTaskSummary: {
13817
+ type: 'object',
13818
+ properties: {
13819
+ nonce: {
13820
+ type: 'string',
13821
+ },
13822
+ taskId: {
13823
+ type: 'string',
13824
+ },
13825
+ taskType: {
13826
+ type: 'string',
13827
+ },
13828
+ status: {
13829
+ type: 'string',
13830
+ },
13831
+ createdAt: {
13832
+ type: 'string',
13833
+ format: 'date-time',
13834
+ },
13835
+ updatedAt: {
13836
+ type: 'string',
13837
+ format: 'date-time',
13838
+ },
13839
+ },
13840
+ },
13841
+ ExecutionTaskFull: {
13842
+ type: 'object',
13843
+ properties: {
13844
+ nonce: {
13845
+ type: 'string',
13846
+ },
13847
+ taskId: {
13848
+ type: 'string',
13849
+ },
13850
+ taskType: {
13851
+ type: 'string',
13852
+ },
13853
+ status: {
13854
+ type: 'string',
13855
+ },
13856
+ errors: {
13857
+ type: 'array',
13858
+ items: {
13859
+ type: 'object',
13860
+ },
13861
+ },
13862
+ warnings: {
13863
+ type: 'array',
13864
+ items: {
13865
+ type: 'object',
13866
+ },
13867
+ },
13868
+ createdAt: {
13869
+ type: 'string',
13870
+ format: 'date-time',
13871
+ },
13872
+ updatedAt: {
13873
+ type: 'string',
13874
+ format: 'date-time',
13875
+ },
13876
+ currentValue: {
13877
+ type: 'object',
13878
+ },
13879
+ },
13880
+ },
13881
+ },
13882
+ },
13883
+ tags: [
13884
+ {
13885
+ name: 'Books',
13886
+ description: 'Operations related to books and pipelines',
13887
+ },
13888
+ {
13889
+ name: 'Executions',
13890
+ description: 'Operations related to execution tasks',
13891
+ },
13892
+ {
13893
+ name: 'Authentication',
13894
+ description: 'Authentication operations',
13895
+ },
13896
+ ],
13347
13897
  };
13348
13898
  /**
13349
13899
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -13988,7 +14538,7 @@ function $initializeTestCommand(program) {
13988
14538
  }
13989
14539
  }
13990
14540
  if (filename.endsWith('.bookc')) {
13991
- pipeline = JSON.parse(await readFile(filename, 'utf-8'));
14541
+ pipeline = jsonParse(await readFile(filename, 'utf-8'));
13992
14542
  }
13993
14543
  else {
13994
14544
  if (isVerbose) {
@@ -14097,6 +14647,37 @@ const _CLI = {
14097
14647
  * Note: [🟡] Code in this file should never be published outside of `@promptbook/cli`
14098
14648
  */
14099
14649
 
14650
+ /**
14651
+ * How is the model provider trusted?
14652
+ *
14653
+ * @public exported from `@promptbook/core`
14654
+ */
14655
+ // <- TODO: Maybe do better levels of trust
14656
+ /**
14657
+ * How is the model provider important?
14658
+ *
14659
+ * @public exported from `@promptbook/core`
14660
+ */
14661
+ const MODEL_ORDER = {
14662
+ /**
14663
+ * Top-tier models, e.g. OpenAI, Anthropic,...
14664
+ */
14665
+ TOP_TIER: 333,
14666
+ /**
14667
+ * Mid-tier models, e.g. Llama, Mistral, etc.
14668
+ */
14669
+ NORMAL: 100,
14670
+ /**
14671
+ * Low-tier models, e.g. Phi, Tiny, etc.
14672
+ */
14673
+ LOW_TIER: 0,
14674
+ };
14675
+ /**
14676
+ * TODO: Add configuration schema and maybe some documentation link
14677
+ * TODO: Maybe constrain LlmToolsConfiguration[number] by generic to ensure that `createConfigurationFromEnv` and `getBoilerplateConfiguration` always create same `packageName` and `className`
14678
+ * TODO: [®] DRY Register logic
14679
+ */
14680
+
14100
14681
  /**
14101
14682
  * Registration of LLM provider metadata
14102
14683
  *
@@ -14111,9 +14692,11 @@ const _AnthropicClaudeMetadataRegistration = $llmToolsMetadataRegister.register(
14111
14692
  packageName: '@promptbook/anthropic-claude',
14112
14693
  className: 'AnthropicClaudeExecutionTools',
14113
14694
  envVariables: ['ANTHROPIC_CLAUDE_API_KEY'],
14695
+ trustLevel: 'CLOSED',
14696
+ order: MODEL_ORDER.TOP_TIER,
14114
14697
  getBoilerplateConfiguration() {
14115
14698
  return {
14116
- title: 'Anthropic Claude (boilerplate)',
14699
+ title: 'Anthropic Claude',
14117
14700
  packageName: '@promptbook/anthropic-claude',
14118
14701
  className: 'AnthropicClaudeExecutionTools',
14119
14702
  options: {
@@ -14167,6 +14750,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14167
14750
  modelVariant: 'CHAT',
14168
14751
  modelTitle: 'Claude 3.5 Sonnet',
14169
14752
  modelName: 'claude-3-5-sonnet-20240620',
14753
+ modelDescription: 'Latest Claude model with great reasoning, coding, and language understanding capabilities. 200K context window. Optimized balance of intelligence and speed.',
14170
14754
  pricing: {
14171
14755
  prompt: computeUsage(`$3.00 / 1M tokens`),
14172
14756
  output: computeUsage(`$15.00 / 1M tokens`),
@@ -14176,6 +14760,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14176
14760
  modelVariant: 'CHAT',
14177
14761
  modelTitle: 'Claude 3 Opus',
14178
14762
  modelName: 'claude-3-opus-20240229',
14763
+ modelDescription: 'Most capable Claude model excelling at complex reasoning, coding, and detailed instruction following. 200K context window. Best for sophisticated tasks requiring nuanced understanding.',
14179
14764
  pricing: {
14180
14765
  prompt: computeUsage(`$15.00 / 1M tokens`),
14181
14766
  output: computeUsage(`$75.00 / 1M tokens`),
@@ -14185,6 +14770,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14185
14770
  modelVariant: 'CHAT',
14186
14771
  modelTitle: 'Claude 3 Sonnet',
14187
14772
  modelName: 'claude-3-sonnet-20240229',
14773
+ modelDescription: 'Strong general-purpose model with excellent performance across reasoning, conversation, and coding tasks. 200K context window. Good balance of intelligence and cost-efficiency.',
14188
14774
  pricing: {
14189
14775
  prompt: computeUsage(`$3.00 / 1M tokens`),
14190
14776
  output: computeUsage(`$15.00 / 1M tokens`),
@@ -14194,6 +14780,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14194
14780
  modelVariant: 'CHAT',
14195
14781
  modelTitle: 'Claude 3 Haiku',
14196
14782
  modelName: ' claude-3-haiku-20240307',
14783
+ modelDescription: 'Fastest and most compact Claude model optimized for responsiveness in interactive applications. 200K context window. Excellent for quick responses and lightweight applications.',
14197
14784
  pricing: {
14198
14785
  prompt: computeUsage(`$0.25 / 1M tokens`),
14199
14786
  output: computeUsage(`$1.25 / 1M tokens`),
@@ -14203,6 +14790,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14203
14790
  modelVariant: 'CHAT',
14204
14791
  modelTitle: 'Claude 2.1',
14205
14792
  modelName: 'claude-2.1',
14793
+ modelDescription: 'Improved version of Claude 2 with better performance across reasoning and truthfulness. 100K context window. Legacy model with strong reliability.',
14206
14794
  pricing: {
14207
14795
  prompt: computeUsage(`$8.00 / 1M tokens`),
14208
14796
  output: computeUsage(`$24.00 / 1M tokens`),
@@ -14212,6 +14800,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14212
14800
  modelVariant: 'CHAT',
14213
14801
  modelTitle: 'Claude 2',
14214
14802
  modelName: 'claude-2.0',
14803
+ modelDescription: 'Legacy model with strong general reasoning and language capabilities. 100K context window. Superseded by newer Claude 3 models.',
14215
14804
  pricing: {
14216
14805
  prompt: computeUsage(`$8.00 / 1M tokens`),
14217
14806
  output: computeUsage(`$24.00 / 1M tokens`),
@@ -14219,8 +14808,9 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14219
14808
  },
14220
14809
  {
14221
14810
  modelVariant: 'CHAT',
14222
- modelTitle: ' Claude Instant 1.2',
14811
+ modelTitle: 'Claude Instant 1.2',
14223
14812
  modelName: 'claude-instant-1.2',
14813
+ modelDescription: 'Older, faster Claude model optimized for high throughput applications. Lower cost but less capable than newer models. 100K context window.',
14224
14814
  pricing: {
14225
14815
  prompt: computeUsage(`$0.80 / 1M tokens`),
14226
14816
  output: computeUsage(`$2.40 / 1M tokens`),
@@ -14230,6 +14820,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14230
14820
  modelVariant: 'CHAT',
14231
14821
  modelTitle: 'Claude 3.7 Sonnet',
14232
14822
  modelName: 'claude-3-7-sonnet-20250219',
14823
+ modelDescription: 'Latest generation Claude model with advanced reasoning and language understanding. Enhanced capabilities over 3.5 with improved domain knowledge. 200K context window.',
14233
14824
  pricing: {
14234
14825
  prompt: computeUsage(`$3.00 / 1M tokens`),
14235
14826
  output: computeUsage(`$15.00 / 1M tokens`),
@@ -14239,6 +14830,7 @@ const ANTHROPIC_CLAUDE_MODELS = exportJson({
14239
14830
  modelVariant: 'CHAT',
14240
14831
  modelTitle: 'Claude 3.5 Haiku',
14241
14832
  modelName: 'claude-3-5-haiku-20241022',
14833
+ modelDescription: 'Fast and efficient Claude 3.5 variant optimized for speed and cost-effectiveness. Great for interactive applications requiring quick responses. 200K context window.',
14242
14834
  pricing: {
14243
14835
  prompt: computeUsage(`$0.25 / 1M tokens`),
14244
14836
  output: computeUsage(`$1.25 / 1M tokens`),
@@ -14640,9 +15232,11 @@ const _AzureOpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
14640
15232
  packageName: '@promptbook/azure-openai',
14641
15233
  className: 'AzureOpenAiExecutionTools',
14642
15234
  envVariables: ['AZUREOPENAI_RESOURCE_NAME', 'AZUREOPENAI_DEPLOYMENT_NAME', 'AZUREOPENAI_API_KEY'],
15235
+ trustLevel: 'CLOSED_BUSINESS',
15236
+ order: MODEL_ORDER.NORMAL,
14643
15237
  getBoilerplateConfiguration() {
14644
15238
  return {
14645
- title: 'Azure Open AI (boilerplate)',
15239
+ title: 'Azure Open AI',
14646
15240
  packageName: '@promptbook/azure-openai',
14647
15241
  className: 'AzureOpenAiExecutionTools',
14648
15242
  options: {
@@ -14723,9 +15317,10 @@ const OPENAI_MODELS = exportJson({
14723
15317
  modelVariant: 'COMPLETION',
14724
15318
  modelTitle: 'davinci-002',
14725
15319
  modelName: 'davinci-002',
15320
+ modelDescription: 'Legacy completion model with strong performance on text generation tasks. Optimized for complex instructions and longer outputs.',
14726
15321
  pricing: {
14727
15322
  prompt: computeUsage(`$2.00 / 1M tokens`),
14728
- output: computeUsage(`$2.00 / 1M tokens`), // <- not sure
15323
+ output: computeUsage(`$2.00 / 1M tokens`),
14729
15324
  },
14730
15325
  },
14731
15326
  /**/
@@ -14740,6 +15335,7 @@ const OPENAI_MODELS = exportJson({
14740
15335
  modelVariant: 'CHAT',
14741
15336
  modelTitle: 'gpt-3.5-turbo-16k',
14742
15337
  modelName: 'gpt-3.5-turbo-16k',
15338
+ modelDescription: 'GPT-3.5 Turbo with extended 16k token context length for handling longer conversations and documents.',
14743
15339
  pricing: {
14744
15340
  prompt: computeUsage(`$3.00 / 1M tokens`),
14745
15341
  output: computeUsage(`$4.00 / 1M tokens`),
@@ -14763,6 +15359,7 @@ const OPENAI_MODELS = exportJson({
14763
15359
  modelVariant: 'CHAT',
14764
15360
  modelTitle: 'gpt-4',
14765
15361
  modelName: 'gpt-4',
15362
+ modelDescription: 'GPT-4 is a powerful language model with enhanced reasoning, instruction-following capabilities, and 8K context window. Optimized for complex tasks requiring deep understanding.',
14766
15363
  pricing: {
14767
15364
  prompt: computeUsage(`$30.00 / 1M tokens`),
14768
15365
  output: computeUsage(`$60.00 / 1M tokens`),
@@ -14774,6 +15371,7 @@ const OPENAI_MODELS = exportJson({
14774
15371
  modelVariant: 'CHAT',
14775
15372
  modelTitle: 'gpt-4-32k',
14776
15373
  modelName: 'gpt-4-32k',
15374
+ modelDescription: 'Extended context version of GPT-4 with a 32K token window for processing very long inputs and generating comprehensive responses for complex tasks.',
14777
15375
  pricing: {
14778
15376
  prompt: computeUsage(`$60.00 / 1M tokens`),
14779
15377
  output: computeUsage(`$120.00 / 1M tokens`),
@@ -14796,6 +15394,7 @@ const OPENAI_MODELS = exportJson({
14796
15394
  modelVariant: 'CHAT',
14797
15395
  modelTitle: 'gpt-4-turbo-2024-04-09',
14798
15396
  modelName: 'gpt-4-turbo-2024-04-09',
15397
+ modelDescription: 'Latest stable GPT-4 Turbo model from April 2024 with enhanced reasoning and context handling capabilities. Offers 128K context window and improved performance.',
14799
15398
  pricing: {
14800
15399
  prompt: computeUsage(`$10.00 / 1M tokens`),
14801
15400
  output: computeUsage(`$30.00 / 1M tokens`),
@@ -14807,6 +15406,7 @@ const OPENAI_MODELS = exportJson({
14807
15406
  modelVariant: 'CHAT',
14808
15407
  modelTitle: 'gpt-3.5-turbo-1106',
14809
15408
  modelName: 'gpt-3.5-turbo-1106',
15409
+ modelDescription: 'November 2023 version of GPT-3.5 Turbo with improved instruction following and a 16K token context window.',
14810
15410
  pricing: {
14811
15411
  prompt: computeUsage(`$1.00 / 1M tokens`),
14812
15412
  output: computeUsage(`$2.00 / 1M tokens`),
@@ -14818,6 +15418,7 @@ const OPENAI_MODELS = exportJson({
14818
15418
  modelVariant: 'CHAT',
14819
15419
  modelTitle: 'gpt-4-turbo',
14820
15420
  modelName: 'gpt-4-turbo',
15421
+ modelDescription: 'More capable model than GPT-4 with improved instruction following, function calling and a 128K token context window for handling very large documents.',
14821
15422
  pricing: {
14822
15423
  prompt: computeUsage(`$10.00 / 1M tokens`),
14823
15424
  output: computeUsage(`$30.00 / 1M tokens`),
@@ -14829,6 +15430,7 @@ const OPENAI_MODELS = exportJson({
14829
15430
  modelVariant: 'COMPLETION',
14830
15431
  modelTitle: 'gpt-3.5-turbo-instruct-0914',
14831
15432
  modelName: 'gpt-3.5-turbo-instruct-0914',
15433
+ modelDescription: 'September 2023 version of GPT-3.5 Turbo optimized for completion-style instruction following with a 4K context window.',
14832
15434
  pricing: {
14833
15435
  prompt: computeUsage(`$1.50 / 1M tokens`),
14834
15436
  output: computeUsage(`$2.00 / 1M tokens`), // <- For gpt-3.5-turbo-instruct
@@ -14840,6 +15442,7 @@ const OPENAI_MODELS = exportJson({
14840
15442
  modelVariant: 'COMPLETION',
14841
15443
  modelTitle: 'gpt-3.5-turbo-instruct',
14842
15444
  modelName: 'gpt-3.5-turbo-instruct',
15445
+ modelDescription: 'Optimized version of GPT-3.5 for completion-style API with good instruction following and a 4K token context window.',
14843
15446
  pricing: {
14844
15447
  prompt: computeUsage(`$1.50 / 1M tokens`),
14845
15448
  output: computeUsage(`$2.00 / 1M tokens`),
@@ -14857,9 +15460,10 @@ const OPENAI_MODELS = exportJson({
14857
15460
  modelVariant: 'CHAT',
14858
15461
  modelTitle: 'gpt-3.5-turbo',
14859
15462
  modelName: 'gpt-3.5-turbo',
15463
+ modelDescription: 'Latest version of GPT-3.5 Turbo with improved performance and instruction following capabilities. Default 4K context window with options for 16K.',
14860
15464
  pricing: {
14861
- prompt: computeUsage(`$3.00 / 1M tokens`),
14862
- output: computeUsage(`$6.00 / 1M tokens`), // <- Not sure, refer to gpt-3.5-turbo in Fine-tuning models
15465
+ prompt: computeUsage(`$0.50 / 1M tokens`),
15466
+ output: computeUsage(`$1.50 / 1M tokens`),
14863
15467
  },
14864
15468
  },
14865
15469
  /**/
@@ -14868,6 +15472,7 @@ const OPENAI_MODELS = exportJson({
14868
15472
  modelVariant: 'CHAT',
14869
15473
  modelTitle: 'gpt-3.5-turbo-0301',
14870
15474
  modelName: 'gpt-3.5-turbo-0301',
15475
+ modelDescription: 'March 2023 version of GPT-3.5 Turbo with a 4K token context window. Legacy model maintained for backward compatibility.',
14871
15476
  pricing: {
14872
15477
  prompt: computeUsage(`$1.50 / 1M tokens`),
14873
15478
  output: computeUsage(`$2.00 / 1M tokens`),
@@ -14879,9 +15484,10 @@ const OPENAI_MODELS = exportJson({
14879
15484
  modelVariant: 'COMPLETION',
14880
15485
  modelTitle: 'babbage-002',
14881
15486
  modelName: 'babbage-002',
15487
+ modelDescription: 'Efficient legacy completion model with a good balance of performance and speed. Suitable for straightforward text generation tasks.',
14882
15488
  pricing: {
14883
15489
  prompt: computeUsage(`$0.40 / 1M tokens`),
14884
- output: computeUsage(`$0.40 / 1M tokens`), // <- Not sure
15490
+ output: computeUsage(`$0.40 / 1M tokens`),
14885
15491
  },
14886
15492
  },
14887
15493
  /**/
@@ -14890,6 +15496,7 @@ const OPENAI_MODELS = exportJson({
14890
15496
  modelVariant: 'CHAT',
14891
15497
  modelTitle: 'gpt-4-1106-preview',
14892
15498
  modelName: 'gpt-4-1106-preview',
15499
+ modelDescription: 'November 2023 preview version of GPT-4 Turbo with improved instruction following and a 128K token context window.',
14893
15500
  pricing: {
14894
15501
  prompt: computeUsage(`$10.00 / 1M tokens`),
14895
15502
  output: computeUsage(`$30.00 / 1M tokens`),
@@ -14901,6 +15508,7 @@ const OPENAI_MODELS = exportJson({
14901
15508
  modelVariant: 'CHAT',
14902
15509
  modelTitle: 'gpt-4-0125-preview',
14903
15510
  modelName: 'gpt-4-0125-preview',
15511
+ modelDescription: 'January 2024 preview version of GPT-4 Turbo with improved reasoning capabilities and a 128K token context window.',
14904
15512
  pricing: {
14905
15513
  prompt: computeUsage(`$10.00 / 1M tokens`),
14906
15514
  output: computeUsage(`$30.00 / 1M tokens`),
@@ -14918,6 +15526,7 @@ const OPENAI_MODELS = exportJson({
14918
15526
  modelVariant: 'CHAT',
14919
15527
  modelTitle: 'gpt-3.5-turbo-0125',
14920
15528
  modelName: 'gpt-3.5-turbo-0125',
15529
+ modelDescription: 'January 2024 version of GPT-3.5 Turbo with improved reasoning capabilities and a 16K token context window.',
14921
15530
  pricing: {
14922
15531
  prompt: computeUsage(`$0.50 / 1M tokens`),
14923
15532
  output: computeUsage(`$1.50 / 1M tokens`),
@@ -14929,9 +15538,10 @@ const OPENAI_MODELS = exportJson({
14929
15538
  modelVariant: 'CHAT',
14930
15539
  modelTitle: 'gpt-4-turbo-preview',
14931
15540
  modelName: 'gpt-4-turbo-preview',
15541
+ modelDescription: 'Preview version of GPT-4 Turbo that points to the latest model version. Features improved instruction following, 128K token context window and lower latency.',
14932
15542
  pricing: {
14933
15543
  prompt: computeUsage(`$10.00 / 1M tokens`),
14934
- output: computeUsage(`$30.00 / 1M tokens`), // <- Not sure, just for gpt-4-turbo
15544
+ output: computeUsage(`$30.00 / 1M tokens`),
14935
15545
  },
14936
15546
  },
14937
15547
  /**/
@@ -14940,6 +15550,7 @@ const OPENAI_MODELS = exportJson({
14940
15550
  modelVariant: 'EMBEDDING',
14941
15551
  modelTitle: 'text-embedding-3-large',
14942
15552
  modelName: 'text-embedding-3-large',
15553
+ modelDescription: "OpenAI's most capable text embedding model designed for high-quality embeddings for complex similarity tasks and information retrieval.",
14943
15554
  pricing: {
14944
15555
  prompt: computeUsage(`$0.13 / 1M tokens`),
14945
15556
  // TODO: [🏏] Leverage the batch API @see https://platform.openai.com/docs/guides/batch
@@ -14952,6 +15563,7 @@ const OPENAI_MODELS = exportJson({
14952
15563
  modelVariant: 'EMBEDDING',
14953
15564
  modelTitle: 'text-embedding-3-small',
14954
15565
  modelName: 'text-embedding-3-small',
15566
+ modelDescription: 'Cost-effective embedding model with good performance for simpler tasks like text similarity and retrieval. Good balance of quality and efficiency.',
14955
15567
  pricing: {
14956
15568
  prompt: computeUsage(`$0.02 / 1M tokens`),
14957
15569
  // TODO: [🏏] Leverage the batch API @see https://platform.openai.com/docs/guides/batch
@@ -14964,6 +15576,7 @@ const OPENAI_MODELS = exportJson({
14964
15576
  modelVariant: 'CHAT',
14965
15577
  modelTitle: 'gpt-3.5-turbo-0613',
14966
15578
  modelName: 'gpt-3.5-turbo-0613',
15579
+ modelDescription: 'June 2023 version of GPT-3.5 Turbo with function calling capabilities and a 4K token context window.',
14967
15580
  pricing: {
14968
15581
  prompt: computeUsage(`$1.50 / 1M tokens`),
14969
15582
  output: computeUsage(`$2.00 / 1M tokens`),
@@ -14975,6 +15588,7 @@ const OPENAI_MODELS = exportJson({
14975
15588
  modelVariant: 'EMBEDDING',
14976
15589
  modelTitle: 'text-embedding-ada-002',
14977
15590
  modelName: 'text-embedding-ada-002',
15591
+ modelDescription: 'Legacy text embedding model suitable for text similarity and retrieval augmented generation use cases. Replaced by newer embedding-3 models.',
14978
15592
  pricing: {
14979
15593
  prompt: computeUsage(`$0.1 / 1M tokens`),
14980
15594
  // TODO: [🏏] Leverage the batch API @see https://platform.openai.com/docs/guides/batch
@@ -15005,6 +15619,7 @@ const OPENAI_MODELS = exportJson({
15005
15619
  modelVariant: 'CHAT',
15006
15620
  modelTitle: 'gpt-4o-2024-05-13',
15007
15621
  modelName: 'gpt-4o-2024-05-13',
15622
+ modelDescription: 'May 2024 version of GPT-4o with enhanced multimodal capabilities, improved reasoning, and optimized for vision, audio and chat at lower latencies.',
15008
15623
  pricing: {
15009
15624
  prompt: computeUsage(`$5.00 / 1M tokens`),
15010
15625
  output: computeUsage(`$15.00 / 1M tokens`),
@@ -15016,6 +15631,7 @@ const OPENAI_MODELS = exportJson({
15016
15631
  modelVariant: 'CHAT',
15017
15632
  modelTitle: 'gpt-4o',
15018
15633
  modelName: 'gpt-4o',
15634
+ modelDescription: "OpenAI's most advanced multimodal model optimized for performance, speed, and cost. Capable of vision, reasoning, and high quality text generation.",
15019
15635
  pricing: {
15020
15636
  prompt: computeUsage(`$5.00 / 1M tokens`),
15021
15637
  output: computeUsage(`$15.00 / 1M tokens`),
@@ -15027,6 +15643,7 @@ const OPENAI_MODELS = exportJson({
15027
15643
  modelVariant: 'CHAT',
15028
15644
  modelTitle: 'gpt-4o-mini',
15029
15645
  modelName: 'gpt-4o-mini',
15646
+ modelDescription: 'Smaller, more cost-effective version of GPT-4o with good performance across text, vision, and audio tasks at reduced complexity.',
15030
15647
  pricing: {
15031
15648
  prompt: computeUsage(`$3.00 / 1M tokens`),
15032
15649
  output: computeUsage(`$9.00 / 1M tokens`),
@@ -15038,6 +15655,7 @@ const OPENAI_MODELS = exportJson({
15038
15655
  modelVariant: 'CHAT',
15039
15656
  modelTitle: 'o1-preview',
15040
15657
  modelName: 'o1-preview',
15658
+ modelDescription: 'Advanced reasoning model with exceptional performance on complex logical, mathematical, and analytical tasks. Built for deep reasoning and specialized professional tasks.',
15041
15659
  pricing: {
15042
15660
  prompt: computeUsage(`$15.00 / 1M tokens`),
15043
15661
  output: computeUsage(`$60.00 / 1M tokens`),
@@ -15049,6 +15667,7 @@ const OPENAI_MODELS = exportJson({
15049
15667
  modelVariant: 'CHAT',
15050
15668
  modelTitle: 'o1-preview-2024-09-12',
15051
15669
  modelName: 'o1-preview-2024-09-12',
15670
+ modelDescription: 'September 2024 version of O1 preview with specialized reasoning capabilities for complex tasks requiring precise analytical thinking.',
15052
15671
  // <- TODO: [💩] Some better system to organize theese date suffixes and versions
15053
15672
  pricing: {
15054
15673
  prompt: computeUsage(`$15.00 / 1M tokens`),
@@ -15061,6 +15680,7 @@ const OPENAI_MODELS = exportJson({
15061
15680
  modelVariant: 'CHAT',
15062
15681
  modelTitle: 'o1-mini',
15063
15682
  modelName: 'o1-mini',
15683
+ modelDescription: 'Smaller, cost-effective version of the O1 model with good performance on reasoning tasks while maintaining efficiency for everyday analytical use.',
15064
15684
  pricing: {
15065
15685
  prompt: computeUsage(`$3.00 / 1M tokens`),
15066
15686
  output: computeUsage(`$12.00 / 1M tokens`),
@@ -15072,10 +15692,10 @@ const OPENAI_MODELS = exportJson({
15072
15692
  modelVariant: 'CHAT',
15073
15693
  modelTitle: 'o1',
15074
15694
  modelName: 'o1',
15695
+ modelDescription: "OpenAI's advanced reasoning model focused on logic and problem-solving. Designed for complex analytical tasks with rigorous step-by-step reasoning. 128K context window.",
15075
15696
  pricing: {
15076
- prompt: computeUsage(`$3.00 / 1M tokens`),
15077
- output: computeUsage(`$12.00 / 1M tokens`),
15078
- // <- TODO: !! Unsure, check the pricing
15697
+ prompt: computeUsage(`$15.00 / 1M tokens`),
15698
+ output: computeUsage(`$60.00 / 1M tokens`),
15079
15699
  },
15080
15700
  },
15081
15701
  /**/
@@ -15084,6 +15704,7 @@ const OPENAI_MODELS = exportJson({
15084
15704
  modelVariant: 'CHAT',
15085
15705
  modelTitle: 'o3-mini',
15086
15706
  modelName: 'o3-mini',
15707
+ modelDescription: 'Cost-effective reasoning model optimized for academic and scientific problem-solving. Efficient performance on STEM tasks with deep mathematical and scientific knowledge. 128K context window.',
15087
15708
  pricing: {
15088
15709
  prompt: computeUsage(`$3.00 / 1M tokens`),
15089
15710
  output: computeUsage(`$12.00 / 1M tokens`),
@@ -15096,6 +15717,7 @@ const OPENAI_MODELS = exportJson({
15096
15717
  modelVariant: 'CHAT',
15097
15718
  modelTitle: 'o1-mini-2024-09-12',
15098
15719
  modelName: 'o1-mini-2024-09-12',
15720
+ modelDescription: "September 2024 version of O1-mini with balanced reasoning capabilities and cost-efficiency. Good for analytical tasks that don't require the full O1 model.",
15099
15721
  pricing: {
15100
15722
  prompt: computeUsage(`$3.00 / 1M tokens`),
15101
15723
  output: computeUsage(`$12.00 / 1M tokens`),
@@ -15107,6 +15729,7 @@ const OPENAI_MODELS = exportJson({
15107
15729
  modelVariant: 'CHAT',
15108
15730
  modelTitle: 'gpt-3.5-turbo-16k-0613',
15109
15731
  modelName: 'gpt-3.5-turbo-16k-0613',
15732
+ modelDescription: 'June 2023 version of GPT-3.5 Turbo with extended 16k token context window for processing longer conversations and documents.',
15110
15733
  pricing: {
15111
15734
  prompt: computeUsage(`$3.00 / 1M tokens`),
15112
15735
  output: computeUsage(`$4.00 / 1M tokens`),
@@ -15131,6 +15754,9 @@ const OPENAI_MODELS = exportJson({
15131
15754
  * Note: [💞] Ignore a discrepancy between file name and entity name
15132
15755
  */
15133
15756
 
15757
+ // Default rate limits (requests per minute) - adjust as needed based on Azure OpenAI tier
15758
+ const DEFAULT_RPM$1 = 60;
15759
+ // <- TODO: !!! Put in some better place
15134
15760
  /**
15135
15761
  * Execution Tools for calling Azure OpenAI API.
15136
15762
  *
@@ -15148,6 +15774,10 @@ class AzureOpenAiExecutionTools {
15148
15774
  * OpenAI Azure API client.
15149
15775
  */
15150
15776
  this.client = null;
15777
+ // TODO: Allow configuring rate limits via options
15778
+ this.limiter = new Bottleneck({
15779
+ minTime: 60000 / (this.options.maxRequestsPerMinute || DEFAULT_RPM$1),
15780
+ });
15151
15781
  }
15152
15782
  get title() {
15153
15783
  return 'Azure OpenAI';
@@ -15225,7 +15855,9 @@ class AzureOpenAiExecutionTools {
15225
15855
  console.info(colors.bgWhite('messages'), JSON.stringify(messages, null, 4));
15226
15856
  }
15227
15857
  const rawRequest = [modelName, messages, modelSettings];
15228
- const rawResponse = await this.withTimeout(client.getChatCompletions(...rawRequest)).catch((error) => {
15858
+ const rawResponse = await this.limiter
15859
+ .schedule(() => this.withTimeout(client.getChatCompletions(...rawRequest)))
15860
+ .catch((error) => {
15229
15861
  if (this.options.isVerbose) {
15230
15862
  console.info(colors.bgRed('error'), error);
15231
15863
  }
@@ -15321,7 +15953,9 @@ class AzureOpenAiExecutionTools {
15321
15953
  [rawPromptContent],
15322
15954
  modelSettings,
15323
15955
  ];
15324
- const rawResponse = await this.withTimeout(client.getCompletions(...rawRequest)).catch((error) => {
15956
+ const rawResponse = await this.limiter
15957
+ .schedule(() => this.withTimeout(client.getCompletions(...rawRequest)))
15958
+ .catch((error) => {
15325
15959
  if (this.options.isVerbose) {
15326
15960
  console.info(colors.bgRed('error'), error);
15327
15961
  }
@@ -15461,9 +16095,11 @@ const _DeepseekMetadataRegistration = $llmToolsMetadataRegister.register({
15461
16095
  packageName: '@promptbook/deepseek',
15462
16096
  className: 'DeepseekExecutionTools',
15463
16097
  envVariables: ['DEEPSEEK_GENERATIVE_AI_API_KEY'],
16098
+ trustLevel: 'UNTRUSTED',
16099
+ order: MODEL_ORDER.NORMAL,
15464
16100
  getBoilerplateConfiguration() {
15465
16101
  return {
15466
- title: 'Deepseek (boilerplate)',
16102
+ title: 'Deepseek',
15467
16103
  packageName: '@promptbook/deepseek',
15468
16104
  className: 'DeepseekExecutionTools',
15469
16105
  options: {
@@ -15660,6 +16296,67 @@ function createExecutionToolsFromVercelProvider(options) {
15660
16296
  };
15661
16297
  }
15662
16298
 
16299
+ /**
16300
+ * List of available Deepseek models with descriptions
16301
+ *
16302
+ * Note: Done at 2025-04-22
16303
+ *
16304
+ * @see https://www.deepseek.com/models
16305
+ * @public exported from `@promptbook/deepseek`
16306
+ */
16307
+ const DEEPSEEK_MODELS = exportJson({
16308
+ name: 'DEEPSEEK_MODELS',
16309
+ value: [
16310
+ {
16311
+ modelVariant: 'CHAT',
16312
+ modelTitle: 'Deepseek Chat',
16313
+ modelName: 'deepseek-chat',
16314
+ modelDescription: 'General-purpose language model with strong performance across conversation, reasoning, and content generation. 128K context window with excellent instruction following capabilities.',
16315
+ pricing: {
16316
+ prompt: computeUsage(`$1.00 / 1M tokens`),
16317
+ output: computeUsage(`$2.00 / 1M tokens`),
16318
+ },
16319
+ },
16320
+ {
16321
+ modelVariant: 'CHAT',
16322
+ modelTitle: 'Deepseek Reasoner',
16323
+ modelName: 'deepseek-reasoner',
16324
+ modelDescription: 'Specialized model focused on complex reasoning tasks like mathematical problem-solving and logical analysis. Enhanced step-by-step reasoning with explicit chain-of-thought processes. 128K context window.',
16325
+ pricing: {
16326
+ prompt: computeUsage(`$4.00 / 1M tokens`),
16327
+ output: computeUsage(`$8.00 / 1M tokens`),
16328
+ },
16329
+ },
16330
+ {
16331
+ modelVariant: 'CHAT',
16332
+ modelTitle: 'DeepSeek V3',
16333
+ modelName: 'deepseek-v3-0324',
16334
+ modelDescription: 'Advanced general-purpose model with improved reasoning, coding abilities, and multimodal understanding. Built on the latest DeepSeek architecture with enhanced knowledge representation.',
16335
+ pricing: {
16336
+ prompt: computeUsage(`$1.50 / 1M tokens`),
16337
+ output: computeUsage(`$3.00 / 1M tokens`),
16338
+ },
16339
+ },
16340
+ {
16341
+ modelVariant: 'CHAT',
16342
+ modelTitle: 'DeepSeek R1',
16343
+ modelName: 'deepseek-r1',
16344
+ modelDescription: 'Research-focused model optimized for scientific problem-solving and analytical tasks. Excellent performance on tasks requiring domain-specific expertise and critical thinking.',
16345
+ pricing: {
16346
+ prompt: computeUsage(`$5.00 / 1M tokens`),
16347
+ output: computeUsage(`$10.00 / 1M tokens`),
16348
+ },
16349
+ },
16350
+ // <- [🕕]
16351
+ ],
16352
+ });
16353
+ /**
16354
+ * TODO: [🧠] Add information about context window sizes, capabilities, and relative performance characteristics
16355
+ * TODO: [🎰] Some mechanism to auto-update available models
16356
+ * TODO: [🧠] Verify pricing information is current with Deepseek's official documentation
16357
+ * Note: [💞] Ignore a discrepancy between file name and entity name
16358
+ */
16359
+
15663
16360
  /**
15664
16361
  * Execution Tools for calling Deepseek API.
15665
16362
  *
@@ -15681,18 +16378,7 @@ const createDeepseekExecutionTools = Object.assign((options) => {
15681
16378
  title: 'Deepseek',
15682
16379
  description: 'Implementation of Deepseek models',
15683
16380
  vercelProvider: deepseekVercelProvider,
15684
- availableModels: [
15685
- {
15686
- modelName: 'deepseek-chat',
15687
- modelVariant: 'CHAT',
15688
- },
15689
- {
15690
- modelName: 'deepseek-reasoner',
15691
- modelVariant: 'CHAT',
15692
- },
15693
- // <- [🕕]
15694
- // <- TODO: How picking of the default model looks like in `createExecutionToolsFromVercelProvider`
15695
- ],
16381
+ availableModels: DEEPSEEK_MODELS,
15696
16382
  ...options,
15697
16383
  });
15698
16384
  }, {
@@ -15732,9 +16418,11 @@ const _GoogleMetadataRegistration = $llmToolsMetadataRegister.register({
15732
16418
  packageName: '@promptbook/google',
15733
16419
  className: 'GoogleExecutionTools',
15734
16420
  envVariables: ['GOOGLE_GENERATIVE_AI_API_KEY'],
16421
+ trustLevel: 'CLOSED',
16422
+ order: MODEL_ORDER.NORMAL,
15735
16423
  getBoilerplateConfiguration() {
15736
16424
  return {
15737
- title: 'Google Gemini (boilerplate)',
16425
+ title: 'Google Gemini',
15738
16426
  packageName: '@promptbook/google',
15739
16427
  className: 'GoogleExecutionTools',
15740
16428
  options: {
@@ -15767,6 +16455,173 @@ const _GoogleMetadataRegistration = $llmToolsMetadataRegister.register({
15767
16455
  * Note: [💞] Ignore a discrepancy between file name and entity name
15768
16456
  */
15769
16457
 
16458
+ /**
16459
+ * List of available Google models with descriptions
16460
+ *
16461
+ * Note: Done at 2025-04-22
16462
+ *
16463
+ * @see https://ai.google.dev/models/gemini
16464
+ * @public exported from `@promptbook/google`
16465
+ */
16466
+ const GOOGLE_MODELS = exportJson({
16467
+ name: 'GOOGLE_MODELS',
16468
+ value: [
16469
+ {
16470
+ modelVariant: 'CHAT',
16471
+ modelTitle: 'Gemini 2.5 Pro',
16472
+ modelName: 'gemini-2.5-pro-preview-03-25',
16473
+ modelDescription: 'Latest advanced multimodal model with exceptional reasoning, tool use, and instruction following. 1M token context window with improved vision capabilities for complex visual tasks.',
16474
+ pricing: {
16475
+ prompt: computeUsage(`$7.00 / 1M tokens`),
16476
+ output: computeUsage(`$21.00 / 1M tokens`),
16477
+ },
16478
+ },
16479
+ {
16480
+ modelVariant: 'CHAT',
16481
+ modelTitle: 'Gemini 2.0 Flash',
16482
+ modelName: 'gemini-2.0-flash',
16483
+ modelDescription: 'Fast, efficient model optimized for rapid response times. Good balance between performance and cost, with strong capabilities across text, code, and reasoning tasks. 128K context window.',
16484
+ pricing: {
16485
+ prompt: computeUsage(`$0.35 / 1M tokens`),
16486
+ output: computeUsage(`$1.05 / 1M tokens`),
16487
+ },
16488
+ },
16489
+ {
16490
+ modelVariant: 'CHAT',
16491
+ modelTitle: 'Gemini 2.0 Flash Lite',
16492
+ modelName: 'gemini-2.0-flash-lite',
16493
+ modelDescription: 'Streamlined version of Gemini 2.0 Flash, designed for extremely low-latency applications and edge deployments. Optimized for efficiency while maintaining core capabilities.',
16494
+ pricing: {
16495
+ prompt: computeUsage(`$0.20 / 1M tokens`),
16496
+ output: computeUsage(`$0.60 / 1M tokens`),
16497
+ },
16498
+ },
16499
+ {
16500
+ modelVariant: 'CHAT',
16501
+ modelTitle: 'Gemini 2.0 Flash Thinking',
16502
+ modelName: 'gemini-2.0-flash-thinking-exp-01-21',
16503
+ modelDescription: 'Experimental model focused on enhanced reasoning with explicit chain-of-thought processes. Designed for tasks requiring structured thinking and problem-solving approaches.',
16504
+ pricing: {
16505
+ prompt: computeUsage(`$0.35 / 1M tokens`),
16506
+ output: computeUsage(`$1.05 / 1M tokens`),
16507
+ },
16508
+ },
16509
+ {
16510
+ modelVariant: 'CHAT',
16511
+ modelTitle: 'Gemini 1.5 Flash',
16512
+ modelName: 'gemini-1.5-flash',
16513
+ modelDescription: 'Efficient model balancing speed and quality for general-purpose applications. 1M token context window with good multimodal capabilities and quick response times.',
16514
+ pricing: {
16515
+ prompt: computeUsage(`$0.35 / 1M tokens`),
16516
+ output: computeUsage(`$1.05 / 1M tokens`),
16517
+ },
16518
+ },
16519
+ {
16520
+ modelVariant: 'CHAT',
16521
+ modelTitle: 'Gemini 1.5 Flash Latest',
16522
+ modelName: 'gemini-1.5-flash-latest',
16523
+ modelDescription: 'Points to the latest version of Gemini 1.5 Flash, ensuring access to the most recent improvements and bug fixes while maintaining stable interfaces.',
16524
+ },
16525
+ {
16526
+ modelVariant: 'CHAT',
16527
+ modelTitle: 'Gemini 1.5 Flash 001',
16528
+ modelName: 'gemini-1.5-flash-001',
16529
+ modelDescription: 'First stable release of Gemini 1.5 Flash model with reliable performance characteristics for production applications. 1M token context window.',
16530
+ },
16531
+ {
16532
+ modelVariant: 'CHAT',
16533
+ modelTitle: 'Gemini 1.5 Flash 002',
16534
+ modelName: 'gemini-1.5-flash-002',
16535
+ modelDescription: 'Improved version of Gemini 1.5 Flash with enhanced instruction following and more consistent outputs. Refined for better application integration.',
16536
+ },
16537
+ {
16538
+ modelVariant: 'CHAT',
16539
+ modelTitle: 'Gemini 1.5 Flash Exp',
16540
+ modelName: 'gemini-1.5-flash-exp-0827',
16541
+ modelDescription: 'Experimental version of Gemini 1.5 Flash with new capabilities being tested. May offer improved performance but with potential behavior differences from stable releases.',
16542
+ },
16543
+ {
16544
+ modelVariant: 'CHAT',
16545
+ modelTitle: 'Gemini 1.5 Flash 8B',
16546
+ modelName: 'gemini-1.5-flash-8b',
16547
+ modelDescription: 'Compact 8B parameter model optimized for efficiency and deployment in resource-constrained environments. Good performance despite smaller size.',
16548
+ },
16549
+ {
16550
+ modelVariant: 'CHAT',
16551
+ modelTitle: 'Gemini 1.5 Flash 8B Latest',
16552
+ modelName: 'gemini-1.5-flash-8b-latest',
16553
+ modelDescription: 'Points to the most recent version of the compact 8B parameter model, providing latest improvements while maintaining a small footprint.',
16554
+ },
16555
+ {
16556
+ modelVariant: 'CHAT',
16557
+ modelTitle: 'Gemini 1.5 Flash 8B Exp',
16558
+ modelName: 'gemini-1.5-flash-8b-exp-0924',
16559
+ modelDescription: 'Experimental version of the 8B parameter model with new capabilities and optimizations being evaluated for future stable releases.',
16560
+ },
16561
+ {
16562
+ modelVariant: 'CHAT',
16563
+ modelTitle: 'Gemini 1.5 Flash 8B Exp',
16564
+ modelName: 'gemini-1.5-flash-8b-exp-0827',
16565
+ modelDescription: 'August experimental release of the efficient 8B parameter model with specific improvements to reasoning capabilities and response quality.',
16566
+ },
16567
+ {
16568
+ modelVariant: 'CHAT',
16569
+ modelTitle: 'Gemini 1.5 Pro Latest',
16570
+ modelName: 'gemini-1.5-pro-latest',
16571
+ modelDescription: 'Points to the most recent version of the flagship Gemini 1.5 Pro model, ensuring access to the latest capabilities and improvements.',
16572
+ pricing: {
16573
+ prompt: computeUsage(`$7.00 / 1M tokens`),
16574
+ output: computeUsage(`$21.00 / 1M tokens`),
16575
+ },
16576
+ },
16577
+ {
16578
+ modelVariant: 'CHAT',
16579
+ modelTitle: 'Gemini 1.5 Pro',
16580
+ modelName: 'gemini-1.5-pro',
16581
+ modelDescription: 'Flagship multimodal model with strong performance across text, code, vision, and audio tasks. 1M token context window with excellent reasoning capabilities.',
16582
+ pricing: {
16583
+ prompt: computeUsage(`$7.00 / 1M tokens`),
16584
+ output: computeUsage(`$21.00 / 1M tokens`),
16585
+ },
16586
+ },
16587
+ {
16588
+ modelVariant: 'CHAT',
16589
+ modelTitle: 'Gemini 1.5 Pro 001',
16590
+ modelName: 'gemini-1.5-pro-001',
16591
+ modelDescription: 'First stable release of Gemini 1.5 Pro with consistent performance characteristics and reliable behavior for production applications.',
16592
+ },
16593
+ {
16594
+ modelVariant: 'CHAT',
16595
+ modelTitle: 'Gemini 1.5 Pro 002',
16596
+ modelName: 'gemini-1.5-pro-002',
16597
+ modelDescription: 'Refined version of Gemini 1.5 Pro with improved instruction following, better multimodal understanding, and more consistent outputs.',
16598
+ },
16599
+ {
16600
+ modelVariant: 'CHAT',
16601
+ modelTitle: 'Gemini 1.5 Pro Exp',
16602
+ modelName: 'gemini-1.5-pro-exp-0827',
16603
+ modelDescription: 'Experimental version of Gemini 1.5 Pro with new capabilities and optimizations being tested before wider release. May offer improved performance.',
16604
+ },
16605
+ {
16606
+ modelVariant: 'CHAT',
16607
+ modelTitle: 'Gemini 1.0 Pro',
16608
+ modelName: 'gemini-1.0-pro',
16609
+ modelDescription: 'Original Gemini series foundation model with solid multimodal capabilities. 32K context window with good performance on text, code, and basic vision tasks.',
16610
+ pricing: {
16611
+ prompt: computeUsage(`$0.35 / 1M tokens`),
16612
+ output: computeUsage(`$1.05 / 1M tokens`),
16613
+ },
16614
+ },
16615
+ // <- [🕕]
16616
+ ],
16617
+ });
16618
+ /**
16619
+ * TODO: [🧠] Add information about context window sizes, capabilities, and relative performance characteristics
16620
+ * TODO: [🎰] Some mechanism to auto-update available models
16621
+ * TODO: [🧠] Verify pricing information is current with Google's official documentation
16622
+ * Note: [💞] Ignore a discrepancy between file name and entity name
16623
+ */
16624
+
15770
16625
  /**
15771
16626
  * Execution Tools for calling Google Gemini API.
15772
16627
  *
@@ -15788,29 +16643,7 @@ const createGoogleExecutionTools = Object.assign((options) => {
15788
16643
  title: 'Google',
15789
16644
  description: 'Implementation of Google models',
15790
16645
  vercelProvider: googleGeminiVercelProvider,
15791
- availableModels: [
15792
- // TODO: [🕘] Maybe list models in same way as in other providers - in separate file with metadata
15793
- 'gemini-2.5-pro-preview-03-25',
15794
- 'gemini-2.0-flash',
15795
- 'gemini-2.0-flash-lite',
15796
- 'gemini-2.0-flash-thinking-exp-01-21',
15797
- 'gemini-1.5-flash',
15798
- 'gemini-1.5-flash-latest',
15799
- 'gemini-1.5-flash-001',
15800
- 'gemini-1.5-flash-002',
15801
- 'gemini-1.5-flash-exp-0827',
15802
- 'gemini-1.5-flash-8b',
15803
- 'gemini-1.5-flash-8b-latest',
15804
- 'gemini-1.5-flash-8b-exp-0924',
15805
- 'gemini-1.5-flash-8b-exp-0827',
15806
- 'gemini-1.5-pro-latest',
15807
- 'gemini-1.5-pro',
15808
- 'gemini-1.5-pro-001',
15809
- 'gemini-1.5-pro-002',
15810
- 'gemini-1.5-pro-exp-0827',
15811
- 'gemini-1.0-pro',
15812
- // <- [🕕]
15813
- ].map((modelName) => ({ modelName, modelVariant: 'CHAT' })),
16646
+ availableModels: GOOGLE_MODELS,
15814
16647
  ...options,
15815
16648
  });
15816
16649
  }, {
@@ -15850,9 +16683,11 @@ const _OpenAiMetadataRegistration = $llmToolsMetadataRegister.register({
15850
16683
  packageName: '@promptbook/openai',
15851
16684
  className: 'OpenAiExecutionTools',
15852
16685
  envVariables: ['OPENAI_API_KEY'],
16686
+ trustLevel: 'CLOSED',
16687
+ order: MODEL_ORDER.TOP_TIER,
15853
16688
  getBoilerplateConfiguration() {
15854
16689
  return {
15855
- title: 'Open AI (boilerplate)',
16690
+ title: 'Open AI',
15856
16691
  packageName: '@promptbook/openai',
15857
16692
  className: 'OpenAiExecutionTools',
15858
16693
  options: {
@@ -15890,9 +16725,11 @@ const _OpenAiAssistantMetadataRegistration = $llmToolsMetadataRegister.register(
15890
16725
  className: 'OpenAiAssistantExecutionTools',
15891
16726
  envVariables: null,
15892
16727
  // <- TODO: ['OPENAI_API_KEY', 'OPENAI_ASSISTANT_ID']
16728
+ trustLevel: 'CLOSED',
16729
+ order: MODEL_ORDER.NORMAL,
15893
16730
  getBoilerplateConfiguration() {
15894
16731
  return {
15895
- title: 'Open AI Assistant (boilerplate)',
16732
+ title: 'Open AI Assistant',
15896
16733
  packageName: '@promptbook/openai',
15897
16734
  className: 'OpenAiAssistantExecutionTools',
15898
16735
  options: {
@@ -15968,6 +16805,9 @@ resultContent, rawResponse) {
15968
16805
  * TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
15969
16806
  */
15970
16807
 
16808
+ // Default rate limits (requests per minute) - adjust as needed based on OpenAI tier
16809
+ const DEFAULT_RPM = 60;
16810
+ // <- TODO: !!! Put in some better place
15971
16811
  /**
15972
16812
  * Execution Tools for calling OpenAI API
15973
16813
  *
@@ -15985,6 +16825,10 @@ class OpenAiExecutionTools {
15985
16825
  * OpenAI API client.
15986
16826
  */
15987
16827
  this.client = null;
16828
+ // TODO: Allow configuring rate limits via options
16829
+ this.limiter = new Bottleneck({
16830
+ minTime: 60000 / (this.options.maxRequestsPerMinute || DEFAULT_RPM),
16831
+ });
15988
16832
  }
15989
16833
  get title() {
15990
16834
  return 'OpenAI';
@@ -16088,7 +16932,9 @@ class OpenAiExecutionTools {
16088
16932
  if (this.options.isVerbose) {
16089
16933
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
16090
16934
  }
16091
- const rawResponse = await client.chat.completions.create(rawRequest).catch((error) => {
16935
+ const rawResponse = await this.limiter
16936
+ .schedule(() => client.chat.completions.create(rawRequest))
16937
+ .catch((error) => {
16092
16938
  assertsError(error);
16093
16939
  if (this.options.isVerbose) {
16094
16940
  console.info(colors.bgRed('error'), error);
@@ -16165,7 +17011,9 @@ class OpenAiExecutionTools {
16165
17011
  if (this.options.isVerbose) {
16166
17012
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
16167
17013
  }
16168
- const rawResponse = await client.completions.create(rawRequest).catch((error) => {
17014
+ const rawResponse = await this.limiter
17015
+ .schedule(() => client.completions.create(rawRequest))
17016
+ .catch((error) => {
16169
17017
  assertsError(error);
16170
17018
  if (this.options.isVerbose) {
16171
17019
  console.info(colors.bgRed('error'), error);
@@ -16229,7 +17077,9 @@ class OpenAiExecutionTools {
16229
17077
  if (this.options.isVerbose) {
16230
17078
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
16231
17079
  }
16232
- const rawResponse = await client.embeddings.create(rawRequest).catch((error) => {
17080
+ const rawResponse = await this.limiter
17081
+ .schedule(() => client.embeddings.create(rawRequest))
17082
+ .catch((error) => {
16233
17083
  assertsError(error);
16234
17084
  if (this.options.isVerbose) {
16235
17085
  console.info(colors.bgRed('error'), error);