@promptbook/openai 0.101.0-14 → 0.101.0-16

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/esm/index.es.js +247 -105
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/src/_packages/components.index.d.ts +4 -0
  4. package/esm/typings/src/_packages/core.index.d.ts +2 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +2 -0
  6. package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +3 -0
  7. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +3 -25
  8. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.d.ts +1 -26
  9. package/esm/typings/src/book-2.0/commitments/MODEL/MODEL.d.ts +23 -2
  10. package/esm/typings/src/book-2.0/commitments/NOTE/NOTE.d.ts +14 -2
  11. package/esm/typings/src/book-2.0/commitments/index.d.ts +1 -1
  12. package/esm/typings/src/book-components/BookEditor/BookEditor.d.ts +5 -0
  13. package/esm/typings/src/book-components/BookEditor/BookEditorInner.d.ts +1 -0
  14. package/esm/typings/src/book-components/Chat/utils/parseMessageButtons.d.ts +22 -0
  15. package/esm/typings/src/formats/csv/CsvFormatError.d.ts +1 -1
  16. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
  17. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
  18. package/esm/typings/src/llm-providers/_common/utils/removeUnsupportedModelRequirements.d.ts +25 -0
  19. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +15 -8
  20. package/esm/typings/src/remote-server/openapi-types.d.ts +31 -31
  21. package/esm/typings/src/types/ModelRequirements.d.ts +2 -4
  22. package/esm/typings/src/utils/color/utils/colorSaturation.d.ts +1 -1
  23. package/esm/typings/src/utils/editable/edit-pipeline-string/addPipelineCommand.d.ts +1 -1
  24. package/esm/typings/src/version.d.ts +1 -1
  25. package/package.json +2 -2
  26. package/umd/index.umd.js +247 -105
  27. package/umd/index.umd.js.map +1 -1
package/esm/index.es.js CHANGED
@@ -19,7 +19,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
19
19
  * @generated
20
20
  * @see https://github.com/webgptorg/promptbook
21
21
  */
22
- const PROMPTBOOK_ENGINE_VERSION = '0.101.0-14';
22
+ const PROMPTBOOK_ENGINE_VERSION = '0.101.0-16';
23
23
  /**
24
24
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
25
25
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -1396,7 +1396,7 @@ const OPENAI_MODELS = exportJson({
1396
1396
  modelVariant: 'CHAT',
1397
1397
  modelTitle: 'gpt-5-mini',
1398
1398
  modelName: 'gpt-5-mini',
1399
- modelDescription: "A faster, cost-efficient version of GPT-5 for well-defined tasks with 200K context window. Maintains core GPT-5 capabilities while offering 5x faster inference and significantly lower costs. Features enhanced instruction following and reduced latency for production applications requiring quick responses with high quality.",
1399
+ modelDescription: 'A faster, cost-efficient version of GPT-5 for well-defined tasks with 200K context window. Maintains core GPT-5 capabilities while offering 5x faster inference and significantly lower costs. Features enhanced instruction following and reduced latency for production applications requiring quick responses with high quality.',
1400
1400
  pricing: {
1401
1401
  prompt: pricing(`$0.25 / 1M tokens`),
1402
1402
  output: pricing(`$2.00 / 1M tokens`),
@@ -1408,7 +1408,7 @@ const OPENAI_MODELS = exportJson({
1408
1408
  modelVariant: 'CHAT',
1409
1409
  modelTitle: 'gpt-5-nano',
1410
1410
  modelName: 'gpt-5-nano',
1411
- modelDescription: "The fastest, most cost-efficient version of GPT-5 with 200K context window. Optimized for summarization, classification, and simple reasoning tasks. Features 10x faster inference than base GPT-5 while maintaining good quality for straightforward applications. Ideal for high-volume, cost-sensitive deployments.",
1411
+ modelDescription: 'The fastest, most cost-efficient version of GPT-5 with 200K context window. Optimized for summarization, classification, and simple reasoning tasks. Features 10x faster inference than base GPT-5 while maintaining good quality for straightforward applications. Ideal for high-volume, cost-sensitive deployments.',
1412
1412
  pricing: {
1413
1413
  prompt: pricing(`$0.05 / 1M tokens`),
1414
1414
  output: pricing(`$0.40 / 1M tokens`),
@@ -1420,7 +1420,7 @@ const OPENAI_MODELS = exportJson({
1420
1420
  modelVariant: 'CHAT',
1421
1421
  modelTitle: 'gpt-4.1',
1422
1422
  modelName: 'gpt-4.1',
1423
- modelDescription: "Smartest non-reasoning model with 128K context window. Enhanced version of GPT-4 with improved instruction following, better factual accuracy, and reduced hallucinations. Features advanced function calling capabilities and superior performance on coding tasks. Ideal for applications requiring high intelligence without reasoning overhead.",
1423
+ modelDescription: 'Smartest non-reasoning model with 128K context window. Enhanced version of GPT-4 with improved instruction following, better factual accuracy, and reduced hallucinations. Features advanced function calling capabilities and superior performance on coding tasks. Ideal for applications requiring high intelligence without reasoning overhead.',
1424
1424
  pricing: {
1425
1425
  prompt: pricing(`$3.00 / 1M tokens`),
1426
1426
  output: pricing(`$12.00 / 1M tokens`),
@@ -1432,7 +1432,7 @@ const OPENAI_MODELS = exportJson({
1432
1432
  modelVariant: 'CHAT',
1433
1433
  modelTitle: 'gpt-4.1-mini',
1434
1434
  modelName: 'gpt-4.1-mini',
1435
- modelDescription: "Smaller, faster version of GPT-4.1 with 128K context window. Balances intelligence and efficiency with 3x faster inference than base GPT-4.1. Maintains strong capabilities across text generation, reasoning, and coding while offering better cost-performance ratio for most applications.",
1435
+ modelDescription: 'Smaller, faster version of GPT-4.1 with 128K context window. Balances intelligence and efficiency with 3x faster inference than base GPT-4.1. Maintains strong capabilities across text generation, reasoning, and coding while offering better cost-performance ratio for most applications.',
1436
1436
  pricing: {
1437
1437
  prompt: pricing(`$0.80 / 1M tokens`),
1438
1438
  output: pricing(`$3.20 / 1M tokens`),
@@ -1444,7 +1444,7 @@ const OPENAI_MODELS = exportJson({
1444
1444
  modelVariant: 'CHAT',
1445
1445
  modelTitle: 'gpt-4.1-nano',
1446
1446
  modelName: 'gpt-4.1-nano',
1447
- modelDescription: "Fastest, most cost-efficient version of GPT-4.1 with 128K context window. Optimized for high-throughput applications requiring good quality at minimal cost. Features 5x faster inference than GPT-4.1 while maintaining adequate performance for most general-purpose tasks.",
1447
+ modelDescription: 'Fastest, most cost-efficient version of GPT-4.1 with 128K context window. Optimized for high-throughput applications requiring good quality at minimal cost. Features 5x faster inference than GPT-4.1 while maintaining adequate performance for most general-purpose tasks.',
1448
1448
  pricing: {
1449
1449
  prompt: pricing(`$0.20 / 1M tokens`),
1450
1450
  output: pricing(`$0.80 / 1M tokens`),
@@ -1456,7 +1456,7 @@ const OPENAI_MODELS = exportJson({
1456
1456
  modelVariant: 'CHAT',
1457
1457
  modelTitle: 'o3',
1458
1458
  modelName: 'o3',
1459
- modelDescription: "Advanced reasoning model with 128K context window specializing in complex logical, mathematical, and analytical tasks. Successor to o1 with enhanced step-by-step problem-solving capabilities and superior performance on STEM-focused problems. Ideal for professional applications requiring deep analytical thinking and precise reasoning.",
1459
+ modelDescription: 'Advanced reasoning model with 128K context window specializing in complex logical, mathematical, and analytical tasks. Successor to o1 with enhanced step-by-step problem-solving capabilities and superior performance on STEM-focused problems. Ideal for professional applications requiring deep analytical thinking and precise reasoning.',
1460
1460
  pricing: {
1461
1461
  prompt: pricing(`$15.00 / 1M tokens`),
1462
1462
  output: pricing(`$60.00 / 1M tokens`),
@@ -1468,7 +1468,7 @@ const OPENAI_MODELS = exportJson({
1468
1468
  modelVariant: 'CHAT',
1469
1469
  modelTitle: 'o3-pro',
1470
1470
  modelName: 'o3-pro',
1471
- modelDescription: "Enhanced version of o3 with more compute allocated for better responses on the most challenging problems. Features extended reasoning time and improved accuracy on complex analytical tasks. Designed for applications where maximum reasoning quality is more important than response speed.",
1471
+ modelDescription: 'Enhanced version of o3 with more compute allocated for better responses on the most challenging problems. Features extended reasoning time and improved accuracy on complex analytical tasks. Designed for applications where maximum reasoning quality is more important than response speed.',
1472
1472
  pricing: {
1473
1473
  prompt: pricing(`$30.00 / 1M tokens`),
1474
1474
  output: pricing(`$120.00 / 1M tokens`),
@@ -1480,7 +1480,7 @@ const OPENAI_MODELS = exportJson({
1480
1480
  modelVariant: 'CHAT',
1481
1481
  modelTitle: 'o4-mini',
1482
1482
  modelName: 'o4-mini',
1483
- modelDescription: "Fast, cost-efficient reasoning model with 128K context window. Successor to o1-mini with improved analytical capabilities while maintaining speed advantages. Features enhanced mathematical reasoning and logical problem-solving at significantly lower cost than full reasoning models.",
1483
+ modelDescription: 'Fast, cost-efficient reasoning model with 128K context window. Successor to o1-mini with improved analytical capabilities while maintaining speed advantages. Features enhanced mathematical reasoning and logical problem-solving at significantly lower cost than full reasoning models.',
1484
1484
  pricing: {
1485
1485
  prompt: pricing(`$4.00 / 1M tokens`),
1486
1486
  output: pricing(`$16.00 / 1M tokens`),
@@ -1492,7 +1492,7 @@ const OPENAI_MODELS = exportJson({
1492
1492
  modelVariant: 'CHAT',
1493
1493
  modelTitle: 'o3-deep-research',
1494
1494
  modelName: 'o3-deep-research',
1495
- modelDescription: "Most powerful deep research model with 128K context window. Specialized for comprehensive research tasks, literature analysis, and complex information synthesis. Features advanced citation capabilities and enhanced factual accuracy for academic and professional research applications.",
1495
+ modelDescription: 'Most powerful deep research model with 128K context window. Specialized for comprehensive research tasks, literature analysis, and complex information synthesis. Features advanced citation capabilities and enhanced factual accuracy for academic and professional research applications.',
1496
1496
  pricing: {
1497
1497
  prompt: pricing(`$25.00 / 1M tokens`),
1498
1498
  output: pricing(`$100.00 / 1M tokens`),
@@ -1504,7 +1504,7 @@ const OPENAI_MODELS = exportJson({
1504
1504
  modelVariant: 'CHAT',
1505
1505
  modelTitle: 'o4-mini-deep-research',
1506
1506
  modelName: 'o4-mini-deep-research',
1507
- modelDescription: "Faster, more affordable deep research model with 128K context window. Balances research capabilities with cost efficiency, offering good performance on literature review, fact-checking, and information synthesis tasks at a more accessible price point.",
1507
+ modelDescription: 'Faster, more affordable deep research model with 128K context window. Balances research capabilities with cost efficiency, offering good performance on literature review, fact-checking, and information synthesis tasks at a more accessible price point.',
1508
1508
  pricing: {
1509
1509
  prompt: pricing(`$12.00 / 1M tokens`),
1510
1510
  output: pricing(`$48.00 / 1M tokens`),
@@ -2012,6 +2012,62 @@ resultContent, rawResponse) {
2012
2012
  * TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
2013
2013
  */
2014
2014
 
2015
+ /**
2016
+ * Parses an OpenAI error message to identify which parameter is unsupported
2017
+ *
2018
+ * @param errorMessage The error message from OpenAI API
2019
+ * @returns The parameter name that is unsupported, or null if not an unsupported parameter error
2020
+ * @private utility of LLM Tools
2021
+ */
2022
+ function parseUnsupportedParameterError(errorMessage) {
2023
+ // Pattern to match "Unsupported value: 'parameter' does not support ..."
2024
+ const unsupportedValueMatch = errorMessage.match(/Unsupported value:\s*'([^']+)'\s*does not support/i);
2025
+ if (unsupportedValueMatch === null || unsupportedValueMatch === void 0 ? void 0 : unsupportedValueMatch[1]) {
2026
+ return unsupportedValueMatch[1];
2027
+ }
2028
+ // Pattern to match "'parameter' of type ... is not supported with this model"
2029
+ const parameterTypeMatch = errorMessage.match(/'([^']+)'\s*of type.*is not supported with this model/i);
2030
+ if (parameterTypeMatch === null || parameterTypeMatch === void 0 ? void 0 : parameterTypeMatch[1]) {
2031
+ return parameterTypeMatch[1];
2032
+ }
2033
+ return null;
2034
+ }
2035
+ /**
2036
+ * Creates a copy of model requirements with the specified parameter removed
2037
+ *
2038
+ * @param modelRequirements Original model requirements
2039
+ * @param unsupportedParameter The parameter to remove
2040
+ * @returns New model requirements without the unsupported parameter
2041
+ * @private utility of LLM Tools
2042
+ */
2043
+ function removeUnsupportedModelRequirement(modelRequirements, unsupportedParameter) {
2044
+ const newRequirements = { ...modelRequirements };
2045
+ // Map of parameter names that might appear in error messages to ModelRequirements properties
2046
+ const parameterMap = {
2047
+ temperature: 'temperature',
2048
+ max_tokens: 'maxTokens',
2049
+ maxTokens: 'maxTokens',
2050
+ seed: 'seed',
2051
+ };
2052
+ const propertyToRemove = parameterMap[unsupportedParameter];
2053
+ if (propertyToRemove && propertyToRemove in newRequirements) {
2054
+ delete newRequirements[propertyToRemove];
2055
+ }
2056
+ return newRequirements;
2057
+ }
2058
+ /**
2059
+ * Checks if an error is an "Unsupported value" error from OpenAI
2060
+ * @param error The error to check
2061
+ * @returns true if this is an unsupported parameter error
2062
+ * @private utility of LLM Tools
2063
+ */
2064
+ function isUnsupportedParameterError(error) {
2065
+ const errorMessage = error.message.toLowerCase();
2066
+ return (errorMessage.includes('unsupported value:') ||
2067
+ errorMessage.includes('is not supported with this model') ||
2068
+ errorMessage.includes('does not support'));
2069
+ }
2070
+
2015
2071
  /**
2016
2072
  * Execution Tools for calling OpenAI API or other OpenAI compatible provider
2017
2073
  *
@@ -2029,6 +2085,10 @@ class OpenAiCompatibleExecutionTools {
2029
2085
  * OpenAI API client.
2030
2086
  */
2031
2087
  this.client = null;
2088
+ /**
2089
+ * Tracks models and parameters that have already been retried to prevent infinite loops
2090
+ */
2091
+ this.retriedUnsupportedParameters = new Set();
2032
2092
  // TODO: Allow configuring rate limits via options
2033
2093
  this.limiter = new Bottleneck({
2034
2094
  minTime: 60000 / (this.options.maxRequestsPerMinute || DEFAULT_MAX_REQUESTS_PER_MINUTE),
@@ -2090,21 +2150,27 @@ class OpenAiCompatibleExecutionTools {
2090
2150
  * Calls OpenAI compatible API to use a chat model.
2091
2151
  */
2092
2152
  async callChatModel(prompt) {
2153
+ return this.callChatModelWithRetry(prompt, prompt.modelRequirements);
2154
+ }
2155
+ /**
2156
+ * Internal method that handles parameter retry for chat model calls
2157
+ */
2158
+ async callChatModelWithRetry(prompt, currentModelRequirements) {
2093
2159
  var _a;
2094
2160
  if (this.options.isVerbose) {
2095
- console.info(`💬 ${this.title} callChatModel call`, { prompt });
2161
+ console.info(`💬 ${this.title} callChatModel call`, { prompt, currentModelRequirements });
2096
2162
  }
2097
- const { content, parameters, modelRequirements, format } = prompt;
2163
+ const { content, parameters, format } = prompt;
2098
2164
  const client = await this.getClient();
2099
2165
  // TODO: [☂] Use here more modelRequirements
2100
- if (modelRequirements.modelVariant !== 'CHAT') {
2166
+ if (currentModelRequirements.modelVariant !== 'CHAT') {
2101
2167
  throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
2102
2168
  }
2103
- const modelName = modelRequirements.modelName || this.getDefaultChatModel().modelName;
2169
+ const modelName = currentModelRequirements.modelName || this.getDefaultChatModel().modelName;
2104
2170
  const modelSettings = {
2105
2171
  model: modelName,
2106
- max_tokens: modelRequirements.maxTokens,
2107
- temperature: modelRequirements.temperature,
2172
+ max_tokens: currentModelRequirements.maxTokens,
2173
+ temperature: currentModelRequirements.temperature,
2108
2174
  // <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
2109
2175
  // <- Note: [🧆]
2110
2176
  }; // <- TODO: [💩] Guard here types better
@@ -2119,12 +2185,12 @@ class OpenAiCompatibleExecutionTools {
2119
2185
  const rawRequest = {
2120
2186
  ...modelSettings,
2121
2187
  messages: [
2122
- ...(modelRequirements.systemMessage === undefined
2188
+ ...(currentModelRequirements.systemMessage === undefined
2123
2189
  ? []
2124
2190
  : [
2125
2191
  {
2126
2192
  role: 'system',
2127
- content: modelRequirements.systemMessage,
2193
+ content: currentModelRequirements.systemMessage,
2128
2194
  },
2129
2195
  ]),
2130
2196
  {
@@ -2138,69 +2204,110 @@ class OpenAiCompatibleExecutionTools {
2138
2204
  if (this.options.isVerbose) {
2139
2205
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
2140
2206
  }
2141
- const rawResponse = await this.limiter
2142
- .schedule(() => this.makeRequestWithRetry(() => client.chat.completions.create(rawRequest)))
2143
- .catch((error) => {
2144
- assertsError(error);
2207
+ try {
2208
+ const rawResponse = await this.limiter
2209
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.chat.completions.create(rawRequest)))
2210
+ .catch((error) => {
2211
+ assertsError(error);
2212
+ if (this.options.isVerbose) {
2213
+ console.info(colors.bgRed('error'), error);
2214
+ }
2215
+ throw error;
2216
+ });
2145
2217
  if (this.options.isVerbose) {
2146
- console.info(colors.bgRed('error'), error);
2218
+ console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
2147
2219
  }
2148
- throw error;
2149
- });
2150
- if (this.options.isVerbose) {
2151
- console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
2152
- }
2153
- const complete = $getCurrentDate();
2154
- if (!rawResponse.choices[0]) {
2155
- throw new PipelineExecutionError(`No choises from ${this.title}`);
2156
- }
2157
- if (rawResponse.choices.length > 1) {
2158
- // TODO: This should be maybe only warning
2159
- throw new PipelineExecutionError(`More than one choise from ${this.title}`);
2220
+ const complete = $getCurrentDate();
2221
+ if (!rawResponse.choices[0]) {
2222
+ throw new PipelineExecutionError(`No choises from ${this.title}`);
2223
+ }
2224
+ if (rawResponse.choices.length > 1) {
2225
+ // TODO: This should be maybe only warning
2226
+ throw new PipelineExecutionError(`More than one choise from ${this.title}`);
2227
+ }
2228
+ const resultContent = rawResponse.choices[0].message.content;
2229
+ const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
2230
+ if (resultContent === null) {
2231
+ throw new PipelineExecutionError(`No response message from ${this.title}`);
2232
+ }
2233
+ return exportJson({
2234
+ name: 'promptResult',
2235
+ message: `Result of \`OpenAiCompatibleExecutionTools.callChatModel\``,
2236
+ order: [],
2237
+ value: {
2238
+ content: resultContent,
2239
+ modelName: rawResponse.model || modelName,
2240
+ timing: {
2241
+ start,
2242
+ complete,
2243
+ },
2244
+ usage,
2245
+ rawPromptContent,
2246
+ rawRequest,
2247
+ rawResponse,
2248
+ // <- [🗯]
2249
+ },
2250
+ });
2160
2251
  }
2161
- const resultContent = rawResponse.choices[0].message.content;
2162
- const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
2163
- if (resultContent === null) {
2164
- throw new PipelineExecutionError(`No response message from ${this.title}`);
2252
+ catch (error) {
2253
+ assertsError(error);
2254
+ // Check if this is an unsupported parameter error
2255
+ if (!isUnsupportedParameterError(error)) {
2256
+ throw error;
2257
+ }
2258
+ // Parse which parameter is unsupported
2259
+ const unsupportedParameter = parseUnsupportedParameterError(error.message);
2260
+ if (!unsupportedParameter) {
2261
+ if (this.options.isVerbose) {
2262
+ console.warn(colors.bgYellow('Warning'), 'Could not parse unsupported parameter from error:', error.message);
2263
+ }
2264
+ throw error;
2265
+ }
2266
+ // Create a unique key for this model + parameter combination to prevent infinite loops
2267
+ const retryKey = `${modelName}-${unsupportedParameter}`;
2268
+ if (this.retriedUnsupportedParameters.has(retryKey)) {
2269
+ // Already retried this parameter, throw the error
2270
+ if (this.options.isVerbose) {
2271
+ console.warn(colors.bgRed('Error'), `Parameter '${unsupportedParameter}' for model '${modelName}' already retried once, throwing error:`, error.message);
2272
+ }
2273
+ throw error;
2274
+ }
2275
+ // Mark this parameter as retried
2276
+ this.retriedUnsupportedParameters.add(retryKey);
2277
+ // Log warning in verbose mode
2278
+ if (this.options.isVerbose) {
2279
+ console.warn(colors.bgYellow('Warning'), `Removing unsupported parameter '${unsupportedParameter}' for model '${modelName}' and retrying request`);
2280
+ }
2281
+ // Remove the unsupported parameter and retry
2282
+ const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
2283
+ return this.callChatModelWithRetry(prompt, modifiedModelRequirements);
2165
2284
  }
2166
- return exportJson({
2167
- name: 'promptResult',
2168
- message: `Result of \`OpenAiCompatibleExecutionTools.callChatModel\``,
2169
- order: [],
2170
- value: {
2171
- content: resultContent,
2172
- modelName: rawResponse.model || modelName,
2173
- timing: {
2174
- start,
2175
- complete,
2176
- },
2177
- usage,
2178
- rawPromptContent,
2179
- rawRequest,
2180
- rawResponse,
2181
- // <- [🗯]
2182
- },
2183
- });
2184
2285
  }
2185
2286
  /**
2186
2287
  * Calls OpenAI API to use a complete model.
2187
2288
  */
2188
2289
  async callCompletionModel(prompt) {
2290
+ return this.callCompletionModelWithRetry(prompt, prompt.modelRequirements);
2291
+ }
2292
+ /**
2293
+ * Internal method that handles parameter retry for completion model calls
2294
+ */
2295
+ async callCompletionModelWithRetry(prompt, currentModelRequirements) {
2189
2296
  var _a;
2190
2297
  if (this.options.isVerbose) {
2191
- console.info(`🖋 ${this.title} callCompletionModel call`, { prompt });
2298
+ console.info(`🖋 ${this.title} callCompletionModel call`, { prompt, currentModelRequirements });
2192
2299
  }
2193
- const { content, parameters, modelRequirements } = prompt;
2300
+ const { content, parameters } = prompt;
2194
2301
  const client = await this.getClient();
2195
2302
  // TODO: [☂] Use here more modelRequirements
2196
- if (modelRequirements.modelVariant !== 'COMPLETION') {
2303
+ if (currentModelRequirements.modelVariant !== 'COMPLETION') {
2197
2304
  throw new PipelineExecutionError('Use callCompletionModel only for COMPLETION variant');
2198
2305
  }
2199
- const modelName = modelRequirements.modelName || this.getDefaultCompletionModel().modelName;
2306
+ const modelName = currentModelRequirements.modelName || this.getDefaultCompletionModel().modelName;
2200
2307
  const modelSettings = {
2201
2308
  model: modelName,
2202
- max_tokens: modelRequirements.maxTokens,
2203
- temperature: modelRequirements.temperature,
2309
+ max_tokens: currentModelRequirements.maxTokens,
2310
+ temperature: currentModelRequirements.temperature,
2204
2311
  // <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
2205
2312
  // <- Note: [🧆]
2206
2313
  };
@@ -2214,46 +2321,81 @@ class OpenAiCompatibleExecutionTools {
2214
2321
  if (this.options.isVerbose) {
2215
2322
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
2216
2323
  }
2217
- const rawResponse = await this.limiter
2218
- .schedule(() => this.makeRequestWithRetry(() => client.completions.create(rawRequest)))
2219
- .catch((error) => {
2220
- assertsError(error);
2324
+ try {
2325
+ const rawResponse = await this.limiter
2326
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.completions.create(rawRequest)))
2327
+ .catch((error) => {
2328
+ assertsError(error);
2329
+ if (this.options.isVerbose) {
2330
+ console.info(colors.bgRed('error'), error);
2331
+ }
2332
+ throw error;
2333
+ });
2221
2334
  if (this.options.isVerbose) {
2222
- console.info(colors.bgRed('error'), error);
2335
+ console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
2223
2336
  }
2224
- throw error;
2225
- });
2226
- if (this.options.isVerbose) {
2227
- console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
2228
- }
2229
- const complete = $getCurrentDate();
2230
- if (!rawResponse.choices[0]) {
2231
- throw new PipelineExecutionError(`No choises from ${this.title}`);
2337
+ const complete = $getCurrentDate();
2338
+ if (!rawResponse.choices[0]) {
2339
+ throw new PipelineExecutionError(`No choises from ${this.title}`);
2340
+ }
2341
+ if (rawResponse.choices.length > 1) {
2342
+ // TODO: This should be maybe only warning
2343
+ throw new PipelineExecutionError(`More than one choise from ${this.title}`);
2344
+ }
2345
+ const resultContent = rawResponse.choices[0].text;
2346
+ const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
2347
+ return exportJson({
2348
+ name: 'promptResult',
2349
+ message: `Result of \`OpenAiCompatibleExecutionTools.callCompletionModel\``,
2350
+ order: [],
2351
+ value: {
2352
+ content: resultContent,
2353
+ modelName: rawResponse.model || modelName,
2354
+ timing: {
2355
+ start,
2356
+ complete,
2357
+ },
2358
+ usage,
2359
+ rawPromptContent,
2360
+ rawRequest,
2361
+ rawResponse,
2362
+ // <- [🗯]
2363
+ },
2364
+ });
2232
2365
  }
2233
- if (rawResponse.choices.length > 1) {
2234
- // TODO: This should be maybe only warning
2235
- throw new PipelineExecutionError(`More than one choise from ${this.title}`);
2366
+ catch (error) {
2367
+ assertsError(error);
2368
+ // Check if this is an unsupported parameter error
2369
+ if (!isUnsupportedParameterError(error)) {
2370
+ throw error;
2371
+ }
2372
+ // Parse which parameter is unsupported
2373
+ const unsupportedParameter = parseUnsupportedParameterError(error.message);
2374
+ if (!unsupportedParameter) {
2375
+ if (this.options.isVerbose) {
2376
+ console.warn(colors.bgYellow('Warning'), 'Could not parse unsupported parameter from error:', error.message);
2377
+ }
2378
+ throw error;
2379
+ }
2380
+ // Create a unique key for this model + parameter combination to prevent infinite loops
2381
+ const retryKey = `${modelName}-${unsupportedParameter}`;
2382
+ if (this.retriedUnsupportedParameters.has(retryKey)) {
2383
+ // Already retried this parameter, throw the error
2384
+ if (this.options.isVerbose) {
2385
+ console.warn(colors.bgRed('Error'), `Parameter '${unsupportedParameter}' for model '${modelName}' already retried once, throwing error:`, error.message);
2386
+ }
2387
+ throw error;
2388
+ }
2389
+ // Mark this parameter as retried
2390
+ this.retriedUnsupportedParameters.add(retryKey);
2391
+ // Log warning in verbose mode
2392
+ if (this.options.isVerbose) {
2393
+ console.warn(colors.bgYellow('Warning'), `Removing unsupported parameter '${unsupportedParameter}' for model '${modelName}' and retrying request`);
2394
+ }
2395
+ // Remove the unsupported parameter and retry
2396
+ const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
2397
+ return this.callCompletionModelWithRetry(prompt, modifiedModelRequirements);
2236
2398
  }
2237
- const resultContent = rawResponse.choices[0].text;
2238
- const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
2239
- return exportJson({
2240
- name: 'promptResult',
2241
- message: `Result of \`OpenAiCompatibleExecutionTools.callCompletionModel\``,
2242
- order: [],
2243
- value: {
2244
- content: resultContent,
2245
- modelName: rawResponse.model || modelName,
2246
- timing: {
2247
- start,
2248
- complete,
2249
- },
2250
- usage,
2251
- rawPromptContent,
2252
- rawRequest,
2253
- rawResponse,
2254
- // <- [🗯]
2255
- },
2256
- });
2257
2399
  }
2258
2400
  /**
2259
2401
  * Calls OpenAI compatible API to use a embedding model
@@ -2279,7 +2421,7 @@ class OpenAiCompatibleExecutionTools {
2279
2421
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
2280
2422
  }
2281
2423
  const rawResponse = await this.limiter
2282
- .schedule(() => this.makeRequestWithRetry(() => client.embeddings.create(rawRequest)))
2424
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.embeddings.create(rawRequest)))
2283
2425
  .catch((error) => {
2284
2426
  assertsError(error);
2285
2427
  if (this.options.isVerbose) {
@@ -2341,7 +2483,7 @@ class OpenAiCompatibleExecutionTools {
2341
2483
  /**
2342
2484
  * Makes a request with retry logic for network errors like ECONNRESET
2343
2485
  */
2344
- async makeRequestWithRetry(requestFn) {
2486
+ async makeRequestWithNetworkRetry(requestFn) {
2345
2487
  let lastError;
2346
2488
  for (let attempt = 1; attempt <= CONNECTION_RETRIES_LIMIT; attempt++) {
2347
2489
  try {
@@ -2353,8 +2495,8 @@ class OpenAiCompatibleExecutionTools {
2353
2495
  // Check if this is a retryable network error
2354
2496
  const isRetryableError = this.isRetryableNetworkError(error);
2355
2497
  if (!isRetryableError || attempt === CONNECTION_RETRIES_LIMIT) {
2356
- if (this.options.isVerbose) {
2357
- console.info(colors.bgRed('Final error after retries'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}:`, error);
2498
+ if (this.options.isVerbose && this.isRetryableNetworkError(error)) {
2499
+ console.info(colors.bgRed('Final network error after retries'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}:`, error);
2358
2500
  }
2359
2501
  throw error;
2360
2502
  }
@@ -2364,7 +2506,7 @@ class OpenAiCompatibleExecutionTools {
2364
2506
  const jitterDelay = Math.random() * 500; // Add some randomness
2365
2507
  const totalDelay = backoffDelay + jitterDelay;
2366
2508
  if (this.options.isVerbose) {
2367
- console.info(colors.bgYellow('Retrying request'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}, waiting ${Math.round(totalDelay)}ms:`, error.message);
2509
+ console.info(colors.bgYellow('Retrying network request'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}, waiting ${Math.round(totalDelay)}ms:`, error.message);
2368
2510
  }
2369
2511
  // Wait before retrying
2370
2512
  await new Promise((resolve) => setTimeout(resolve, totalDelay));