@promptbook/cli 0.101.0-2 → 0.101.0-20

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 (76) hide show
  1. package/esm/index.es.js +320 -162
  2. package/esm/index.es.js.map +1 -1
  3. package/esm/typings/src/_packages/components.index.d.ts +20 -0
  4. package/esm/typings/src/_packages/core.index.d.ts +14 -0
  5. package/esm/typings/src/_packages/types.index.d.ts +14 -0
  6. package/esm/typings/src/book-2.0/agent-source/AgentBasicInformation.d.ts +41 -3
  7. package/esm/typings/src/book-2.0/agent-source/AgentModelRequirements.d.ts +3 -0
  8. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirements.d.ts +4 -22
  9. package/esm/typings/src/book-2.0/agent-source/createAgentModelRequirementsWithCommitments.d.ts +1 -26
  10. package/esm/typings/src/book-2.0/agent-source/parseParameters.d.ts +13 -0
  11. package/esm/typings/src/book-2.0/commitments/ACTION/ACTION.d.ts +8 -2
  12. package/esm/typings/src/book-2.0/commitments/DELETE/DELETE.d.ts +59 -0
  13. package/esm/typings/src/book-2.0/commitments/FORMAT/FORMAT.d.ts +8 -2
  14. package/esm/typings/src/book-2.0/commitments/GOAL/GOAL.d.ts +45 -0
  15. package/esm/typings/src/book-2.0/commitments/KNOWLEDGE/KNOWLEDGE.d.ts +1 -1
  16. package/esm/typings/src/book-2.0/commitments/MEMORY/MEMORY.d.ts +46 -0
  17. package/esm/typings/src/book-2.0/commitments/MESSAGE/MESSAGE.d.ts +47 -0
  18. package/esm/typings/src/book-2.0/commitments/META/META.d.ts +62 -0
  19. package/esm/typings/src/book-2.0/commitments/MODEL/MODEL.d.ts +31 -4
  20. package/esm/typings/src/book-2.0/commitments/NOTE/NOTE.d.ts +20 -2
  21. package/esm/typings/src/book-2.0/commitments/PERSONA/PERSONA.d.ts +8 -2
  22. package/esm/typings/src/book-2.0/commitments/SCENARIO/SCENARIO.d.ts +46 -0
  23. package/esm/typings/src/book-2.0/commitments/STYLE/STYLE.d.ts +8 -2
  24. package/esm/typings/src/book-2.0/commitments/index.d.ts +7 -3
  25. package/esm/typings/src/book-2.0/utils/generatePlaceholderAgentProfileImageUrl.d.ts +3 -0
  26. package/esm/typings/src/book-components/AvatarProfile/AvatarChip/AvatarChip.d.ts +2 -2
  27. package/esm/typings/src/book-components/AvatarProfile/AvatarProfile/MockedChat.d.ts +63 -0
  28. package/esm/typings/src/book-components/AvatarProfile/AvatarProfile/index.d.ts +3 -0
  29. package/esm/typings/src/book-components/BookEditor/BookEditor.d.ts +15 -0
  30. package/esm/typings/src/book-components/BookEditor/BookEditorInner.d.ts +4 -0
  31. package/esm/typings/src/book-components/Chat/Chat/ChatProps.d.ts +26 -0
  32. package/esm/typings/src/book-components/Chat/LlmChat/LlmChatProps.d.ts +13 -0
  33. package/esm/typings/src/book-components/Chat/hooks/index.d.ts +2 -0
  34. package/esm/typings/src/book-components/Chat/hooks/useChatAutoScroll.d.ts +41 -0
  35. package/esm/typings/src/book-components/Chat/hooks/useSendMessageToLlmChat.d.ts +44 -0
  36. package/esm/typings/src/book-components/Chat/utils/parseMessageButtons.d.ts +22 -0
  37. package/esm/typings/src/book-components/icons/PauseIcon.d.ts +8 -0
  38. package/esm/typings/src/book-components/icons/PlayIcon.d.ts +8 -0
  39. package/esm/typings/src/execution/createPipelineExecutor/40-executeAttempts.d.ts +1 -2
  40. package/esm/typings/src/execution/createPipelineExecutor/getKnowledgeForTask.d.ts +1 -3
  41. package/esm/typings/src/formats/csv/CsvFormatError.d.ts +1 -1
  42. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsConfigurationFromEnv.d.ts +1 -1
  43. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForTestingAndScriptsAndPlayground.d.ts +1 -1
  44. package/esm/typings/src/llm-providers/_common/register/$provideLlmToolsForWizardOrCli.d.ts +1 -2
  45. package/esm/typings/src/llm-providers/_common/register/createLlmToolsFromConfiguration.d.ts +8 -2
  46. package/esm/typings/src/llm-providers/_common/utils/removeUnsupportedModelRequirements.d.ts +25 -0
  47. package/esm/typings/src/llm-providers/_multiple/MultipleLlmExecutionTools.d.ts +5 -13
  48. package/esm/typings/src/llm-providers/_multiple/getSingleLlmExecutionTools.d.ts +11 -0
  49. package/esm/typings/src/llm-providers/_multiple/joinLlmExecutionTools.d.ts +2 -1
  50. package/esm/typings/src/llm-providers/agent/AgentLlmExecutionTools.d.ts +54 -0
  51. package/esm/typings/src/llm-providers/agent/createAgentLlmExecutionTools.d.ts +29 -0
  52. package/esm/typings/src/llm-providers/agent/playground/playground.d.ts +8 -0
  53. package/esm/typings/src/llm-providers/agent/register-configuration.d.ts +11 -0
  54. package/esm/typings/src/llm-providers/agent/register-constructor.d.ts +13 -0
  55. package/esm/typings/src/llm-providers/mocked/$fakeTextToExpectations.d.ts +1 -0
  56. package/esm/typings/src/llm-providers/mocked/MockedEchoLlmExecutionTools.d.ts +2 -5
  57. package/esm/typings/src/llm-providers/mocked/MockedFackedLlmExecutionTools.d.ts +2 -6
  58. package/esm/typings/src/llm-providers/openai/OpenAiCompatibleExecutionTools.d.ts +15 -8
  59. package/esm/typings/src/personas/preparePersona.d.ts +1 -0
  60. package/esm/typings/src/remote-server/openapi-types.d.ts +31 -31
  61. package/esm/typings/src/scrapers/markdown/MarkdownScraper.d.ts +1 -2
  62. package/esm/typings/src/types/ModelRequirements.d.ts +2 -4
  63. package/esm/typings/src/utils/color/utils/colorSaturation.d.ts +1 -1
  64. package/esm/typings/src/utils/editable/edit-pipeline-string/addPipelineCommand.d.ts +1 -1
  65. package/esm/typings/src/utils/markdown/humanizeAiText.d.ts +1 -0
  66. package/esm/typings/src/version.d.ts +1 -1
  67. package/package.json +1 -1
  68. package/umd/index.umd.js +320 -162
  69. package/umd/index.umd.js.map +1 -1
  70. package/esm/typings/src/book-2.0/utils/extractAgentMetadata.d.ts +0 -17
  71. package/esm/typings/src/book-2.0/utils/extractProfileImageFromSystemMessage.d.ts +0 -12
  72. package/esm/typings/src/llm-providers/mocked/test/joker.test.d.ts +0 -4
  73. package/esm/typings/src/llm-providers/mocked/test/mocked-chat.test.d.ts +0 -5
  74. package/esm/typings/src/llm-providers/mocked/test/mocked-completion.test.d.ts +0 -4
  75. package/esm/typings/src/scripting/_test/postprocessing.test.d.ts +0 -1
  76. /package/esm/typings/src/{cli/test/ptbk.test.d.ts → llm-providers/_common/utils/removeUnsupportedModelRequirements.test.d.ts} +0 -0
package/esm/index.es.js CHANGED
@@ -45,7 +45,7 @@ const BOOK_LANGUAGE_VERSION = '1.0.0';
45
45
  * @generated
46
46
  * @see https://github.com/webgptorg/promptbook
47
47
  */
48
- const PROMPTBOOK_ENGINE_VERSION = '0.101.0-2';
48
+ const PROMPTBOOK_ENGINE_VERSION = '0.101.0-20';
49
49
  /**
50
50
  * TODO: string_promptbook_version should be constrained to the all versions of Promptbook engine
51
51
  * Note: [💞] Ignore a discrepancy between file name and entity name
@@ -2234,11 +2234,12 @@ class FileCacheStorage {
2234
2234
  catch (error) {
2235
2235
  // Note: If we can't write to cache, silently ignore the error
2236
2236
  // This handles read-only filesystems, permission issues, and missing parent directories
2237
- if (error instanceof Error && (error.message.includes('EROFS') ||
2238
- error.message.includes('read-only') ||
2239
- error.message.includes('EACCES') ||
2240
- error.message.includes('EPERM') ||
2241
- error.message.includes('ENOENT'))) {
2237
+ if (error instanceof Error &&
2238
+ (error.message.includes('EROFS') ||
2239
+ error.message.includes('read-only') ||
2240
+ error.message.includes('EACCES') ||
2241
+ error.message.includes('EPERM') ||
2242
+ error.message.includes('ENOENT'))) {
2242
2243
  // Silently ignore filesystem errors - caching is optional
2243
2244
  return;
2244
2245
  }
@@ -3645,12 +3646,10 @@ class MultipleLlmExecutionTools {
3645
3646
  /**
3646
3647
  * Gets array of execution tools in order of priority
3647
3648
  */
3648
- constructor(...llmExecutionTools) {
3649
+ constructor(title, ...llmExecutionTools) {
3650
+ this.title = title;
3649
3651
  this.llmExecutionTools = llmExecutionTools;
3650
3652
  }
3651
- get title() {
3652
- return 'Multiple LLM Providers';
3653
- }
3654
3653
  get description() {
3655
3654
  const innerModelsTitlesAndDescriptions = this.llmExecutionTools
3656
3655
  .map(({ title, description }, index) => {
@@ -3736,7 +3735,7 @@ class MultipleLlmExecutionTools {
3736
3735
  return await llmExecutionTools.callEmbeddingModel(prompt);
3737
3736
  // <- case [🤖]:
3738
3737
  default:
3739
- throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}"`);
3738
+ throw new UnexpectedError(`Unknown model variant "${prompt.modelRequirements.modelVariant}" in ${llmExecutionTools.title}`);
3740
3739
  }
3741
3740
  }
3742
3741
  catch (error) {
@@ -3757,7 +3756,7 @@ class MultipleLlmExecutionTools {
3757
3756
  // 2) AnthropicClaude throw PipelineExecutionError: Parameter `{knowledge}` is not defined
3758
3757
  // 3) ...
3759
3758
  spaceTrim((block) => `
3760
- All execution tools failed:
3759
+ All execution tools of ${this.title} failed:
3761
3760
 
3762
3761
  ${block(errors
3763
3762
  .map(({ error, llmExecutionTools }, i) => `${i + 1}) **${llmExecutionTools.title}** thrown **${error.name || 'Error'}:** ${error.message}`)
@@ -3766,11 +3765,11 @@ class MultipleLlmExecutionTools {
3766
3765
  `));
3767
3766
  }
3768
3767
  else if (this.llmExecutionTools.length === 0) {
3769
- throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\``);
3768
+ throw new PipelineExecutionError(`You have not provided any \`LlmExecutionTools\` into ${this.title}`);
3770
3769
  }
3771
3770
  else {
3772
3771
  throw new PipelineExecutionError(spaceTrim((block) => `
3773
- You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}"
3772
+ You have not provided any \`LlmExecutionTools\` that support model variant "${prompt.modelRequirements.modelVariant}" into ${this.title}
3774
3773
 
3775
3774
  Available \`LlmExecutionTools\`:
3776
3775
  ${block(this.description)}
@@ -3800,7 +3799,7 @@ class MultipleLlmExecutionTools {
3800
3799
  *
3801
3800
  * @public exported from `@promptbook/core`
3802
3801
  */
3803
- function joinLlmExecutionTools(...llmExecutionTools) {
3802
+ function joinLlmExecutionTools(title, ...llmExecutionTools) {
3804
3803
  if (llmExecutionTools.length === 0) {
3805
3804
  const warningMessage = spaceTrim(`
3806
3805
  You have not provided any \`LlmExecutionTools\`
@@ -3832,7 +3831,7 @@ function joinLlmExecutionTools(...llmExecutionTools) {
3832
3831
  };
3833
3832
  */
3834
3833
  }
3835
- return new MultipleLlmExecutionTools(...llmExecutionTools);
3834
+ return new MultipleLlmExecutionTools(title || 'Multiple LLM Providers joined by `joinLlmExecutionTools`', ...llmExecutionTools);
3836
3835
  }
3837
3836
  /**
3838
3837
  * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
@@ -3852,7 +3851,7 @@ function joinLlmExecutionTools(...llmExecutionTools) {
3852
3851
  * @public exported from `@promptbook/core`
3853
3852
  */
3854
3853
  function createLlmToolsFromConfiguration(configuration, options = {}) {
3855
- const { isVerbose = DEFAULT_IS_VERBOSE, userId } = options;
3854
+ const { title = 'LLM Tools from Configuration', isVerbose = DEFAULT_IS_VERBOSE, userId } = options;
3856
3855
  const llmTools = configuration.map((llmConfiguration) => {
3857
3856
  const registeredItem = $llmToolsRegister
3858
3857
  .list()
@@ -3884,7 +3883,7 @@ function createLlmToolsFromConfiguration(configuration, options = {}) {
3884
3883
  ...llmConfiguration.options,
3885
3884
  });
3886
3885
  });
3887
- return joinLlmExecutionTools(...llmTools);
3886
+ return joinLlmExecutionTools(title, ...llmTools);
3888
3887
  }
3889
3888
  /**
3890
3889
  * TODO: [🎌] Together with `createLlmToolsFromConfiguration` + 'EXECUTION_TOOLS_CLASSES' gets to `@promptbook/core` ALL model providers, make this more efficient
@@ -4001,7 +4000,9 @@ async function $provideLlmToolsForWizardOrCli(options) {
4001
4000
  });
4002
4001
  }
4003
4002
  else if (strategy === 'BRING_YOUR_OWN_KEYS') {
4004
- llmExecutionTools = await $provideLlmToolsFromEnv();
4003
+ llmExecutionTools = await $provideLlmToolsFromEnv({
4004
+ title: 'LLM Tools for wizard or CLI with BYOK strategy',
4005
+ });
4005
4006
  }
4006
4007
  else {
4007
4008
  throw new UnexpectedError(`\`$provideLlmToolsForWizardOrCli\` wrong strategy "${strategy}"`);
@@ -6507,6 +6508,22 @@ function arrayableToArray(input) {
6507
6508
  return [input];
6508
6509
  }
6509
6510
 
6511
+ /**
6512
+ * Just returns the given `LlmExecutionTools` or joins multiple into one
6513
+ *
6514
+ * @public exported from `@promptbook/core`
6515
+ */
6516
+ function getSingleLlmExecutionTools(oneOrMoreLlmExecutionTools) {
6517
+ const _llms = arrayableToArray(oneOrMoreLlmExecutionTools);
6518
+ const llmTools = _llms.length === 1
6519
+ ? _llms[0]
6520
+ : joinLlmExecutionTools('Multiple LLM Providers joined by `getSingleLlmExecutionTools`', ..._llms);
6521
+ return llmTools;
6522
+ }
6523
+ /**
6524
+ * TODO: [👷‍♂️] @@@ Manual about construction of llmTools
6525
+ */
6526
+
6510
6527
  /**
6511
6528
  * Replaces parameters in template with values from parameters object
6512
6529
  *
@@ -6597,9 +6614,7 @@ async function executeAttempts(options) {
6597
6614
  $scriptPipelineExecutionErrors: [],
6598
6615
  $failedResults: [], // Track all failed attempts
6599
6616
  };
6600
- // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
6601
- const _llms = arrayableToArray(tools.llm);
6602
- const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
6617
+ const llmTools = getSingleLlmExecutionTools(tools.llm);
6603
6618
  attempts: for (let attemptIndex = -jokerParameterNames.length; attemptIndex < maxAttempts; attemptIndex++) {
6604
6619
  const isJokerAttempt = attemptIndex < 0;
6605
6620
  const jokerParameterName = jokerParameterNames[jokerParameterNames.length + attemptIndex];
@@ -7119,9 +7134,7 @@ async function getKnowledgeForTask(options) {
7119
7134
  return ''; // <- Note: Np knowledge present, return empty string
7120
7135
  }
7121
7136
  try {
7122
- // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
7123
- const _llms = arrayableToArray(tools.llm);
7124
- const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
7137
+ const llmTools = getSingleLlmExecutionTools(tools.llm);
7125
7138
  const taskEmbeddingPrompt = {
7126
7139
  title: 'Knowledge Search',
7127
7140
  modelRequirements: {
@@ -7722,13 +7735,13 @@ function createPipelineExecutor(options) {
7722
7735
  // Calculate and update tldr based on pipeline progress
7723
7736
  const cv = newOngoingResult;
7724
7737
  // Calculate progress based on parameters resolved vs total parameters
7725
- const totalParameters = pipeline.parameters.filter(p => !p.isInput).length;
7738
+ const totalParameters = pipeline.parameters.filter((p) => !p.isInput).length;
7726
7739
  let resolvedParameters = 0;
7727
7740
  let currentTaskTitle = '';
7728
7741
  // Get the resolved parameters from output parameters
7729
7742
  if (cv === null || cv === void 0 ? void 0 : cv.outputParameters) {
7730
7743
  // Count how many output parameters have non-empty values
7731
- resolvedParameters = Object.values(cv.outputParameters).filter(value => value !== undefined && value !== null && String(value).trim() !== '').length;
7744
+ resolvedParameters = Object.values(cv.outputParameters).filter((value) => value !== undefined && value !== null && String(value).trim() !== '').length;
7732
7745
  }
7733
7746
  // Try to determine current task from execution report
7734
7747
  if (((_a = cv === null || cv === void 0 ? void 0 : cv.executionReport) === null || _a === void 0 ? void 0 : _a.promptExecutions) && cv.executionReport.promptExecutions.length > 0) {
@@ -7828,8 +7841,7 @@ async function preparePersona(personaDescription, tools, options) {
7828
7841
  pipeline: await collection.getPipelineByUrl('https://promptbook.studio/promptbook/prepare-persona.book'),
7829
7842
  tools,
7830
7843
  });
7831
- const _llms = arrayableToArray(tools.llm);
7832
- const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
7844
+ const llmTools = getSingleLlmExecutionTools(tools.llm);
7833
7845
  const availableModels = (await llmTools.listModels())
7834
7846
  .filter(({ modelVariant }) => modelVariant === 'CHAT')
7835
7847
  .map(({ modelName, modelDescription }) => ({
@@ -7873,6 +7885,7 @@ async function preparePersona(personaDescription, tools, options) {
7873
7885
  };
7874
7886
  }
7875
7887
  /**
7888
+ * TODO: [😩] DRY `preparePersona` and `selectBestModelFromAvailable`
7876
7889
  * TODO: [🔃][main] If the persona was prepared with different version or different set of models, prepare it once again
7877
7890
  * TODO: [🏢] Check validity of `modelName` in pipeline
7878
7891
  * TODO: [🏢] Check validity of `systemMessage` in pipeline
@@ -8325,9 +8338,7 @@ async function preparePipeline(pipeline, tools, options) {
8325
8338
  if (tools === undefined || tools.llm === undefined) {
8326
8339
  throw new MissingToolsError('LLM tools are required for preparing the pipeline');
8327
8340
  }
8328
- // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
8329
- const _llms = arrayableToArray(tools.llm);
8330
- const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
8341
+ const llmTools = getSingleLlmExecutionTools(tools.llm);
8331
8342
  const llmToolsWithUsage = countUsage(llmTools);
8332
8343
  // <- TODO: [🌯]
8333
8344
  /*
@@ -12521,7 +12532,7 @@ async function $provideExecutionToolsForNode(options) {
12521
12532
  throw new EnvironmentMismatchError('Function `$getExecutionToolsForNode` works only in Node.js environment');
12522
12533
  }
12523
12534
  const fs = $provideFilesystemForNode();
12524
- const llm = await $provideLlmToolsFromEnv(options);
12535
+ const llm = await $provideLlmToolsFromEnv({ title: 'LLM Tools for Node.js', ...options });
12525
12536
  const executables = await $provideExecutablesForNode();
12526
12537
  const tools = {
12527
12538
  llm,
@@ -13688,11 +13699,12 @@ async function $getCompiledBook(tools, pipelineSource, options) {
13688
13699
  catch (error) {
13689
13700
  // Note: Ignore filesystem errors (like EROFS on read-only systems like Vercel)
13690
13701
  // The compiled book can still be used even if it can't be cached
13691
- if (error instanceof Error && (error.message.includes('EROFS') ||
13692
- error.message.includes('read-only') ||
13693
- error.message.includes('EACCES') ||
13694
- error.message.includes('EPERM') ||
13695
- error.message.includes('ENOENT'))) ;
13702
+ if (error instanceof Error &&
13703
+ (error.message.includes('EROFS') ||
13704
+ error.message.includes('read-only') ||
13705
+ error.message.includes('EACCES') ||
13706
+ error.message.includes('EPERM') ||
13707
+ error.message.includes('ENOENT'))) ;
13696
13708
  else {
13697
13709
  // Re-throw other unexpected errors
13698
13710
  throw error;
@@ -14788,8 +14800,11 @@ function startRemoteServer(options) {
14788
14800
  if (isAnonymous === true) {
14789
14801
  // Note: Anonymous mode
14790
14802
  // TODO: Maybe check that configuration is not empty
14791
- const { llmToolsConfiguration } = identification;
14792
- llm = createLlmToolsFromConfiguration(llmToolsConfiguration, { isVerbose });
14803
+ const { userId, llmToolsConfiguration } = identification;
14804
+ llm = createLlmToolsFromConfiguration(llmToolsConfiguration, {
14805
+ title: `LLM Tools for anonymous user "${userId}" on server`,
14806
+ isVerbose,
14807
+ });
14793
14808
  }
14794
14809
  else if (isAnonymous === false && createLlmExecutionTools !== null) {
14795
14810
  // Note: Application mode
@@ -16195,7 +16210,7 @@ const OPENAI_MODELS = exportJson({
16195
16210
  modelVariant: 'CHAT',
16196
16211
  modelTitle: 'gpt-5-mini',
16197
16212
  modelName: 'gpt-5-mini',
16198
- 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.",
16213
+ 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.',
16199
16214
  pricing: {
16200
16215
  prompt: pricing(`$0.25 / 1M tokens`),
16201
16216
  output: pricing(`$2.00 / 1M tokens`),
@@ -16207,7 +16222,7 @@ const OPENAI_MODELS = exportJson({
16207
16222
  modelVariant: 'CHAT',
16208
16223
  modelTitle: 'gpt-5-nano',
16209
16224
  modelName: 'gpt-5-nano',
16210
- 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.",
16225
+ 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.',
16211
16226
  pricing: {
16212
16227
  prompt: pricing(`$0.05 / 1M tokens`),
16213
16228
  output: pricing(`$0.40 / 1M tokens`),
@@ -16219,7 +16234,7 @@ const OPENAI_MODELS = exportJson({
16219
16234
  modelVariant: 'CHAT',
16220
16235
  modelTitle: 'gpt-4.1',
16221
16236
  modelName: 'gpt-4.1',
16222
- 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.",
16237
+ 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.',
16223
16238
  pricing: {
16224
16239
  prompt: pricing(`$3.00 / 1M tokens`),
16225
16240
  output: pricing(`$12.00 / 1M tokens`),
@@ -16231,7 +16246,7 @@ const OPENAI_MODELS = exportJson({
16231
16246
  modelVariant: 'CHAT',
16232
16247
  modelTitle: 'gpt-4.1-mini',
16233
16248
  modelName: 'gpt-4.1-mini',
16234
- 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.",
16249
+ 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.',
16235
16250
  pricing: {
16236
16251
  prompt: pricing(`$0.80 / 1M tokens`),
16237
16252
  output: pricing(`$3.20 / 1M tokens`),
@@ -16243,7 +16258,7 @@ const OPENAI_MODELS = exportJson({
16243
16258
  modelVariant: 'CHAT',
16244
16259
  modelTitle: 'gpt-4.1-nano',
16245
16260
  modelName: 'gpt-4.1-nano',
16246
- 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.",
16261
+ 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.',
16247
16262
  pricing: {
16248
16263
  prompt: pricing(`$0.20 / 1M tokens`),
16249
16264
  output: pricing(`$0.80 / 1M tokens`),
@@ -16255,7 +16270,7 @@ const OPENAI_MODELS = exportJson({
16255
16270
  modelVariant: 'CHAT',
16256
16271
  modelTitle: 'o3',
16257
16272
  modelName: 'o3',
16258
- 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.",
16273
+ 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.',
16259
16274
  pricing: {
16260
16275
  prompt: pricing(`$15.00 / 1M tokens`),
16261
16276
  output: pricing(`$60.00 / 1M tokens`),
@@ -16267,7 +16282,7 @@ const OPENAI_MODELS = exportJson({
16267
16282
  modelVariant: 'CHAT',
16268
16283
  modelTitle: 'o3-pro',
16269
16284
  modelName: 'o3-pro',
16270
- 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.",
16285
+ 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.',
16271
16286
  pricing: {
16272
16287
  prompt: pricing(`$30.00 / 1M tokens`),
16273
16288
  output: pricing(`$120.00 / 1M tokens`),
@@ -16279,7 +16294,7 @@ const OPENAI_MODELS = exportJson({
16279
16294
  modelVariant: 'CHAT',
16280
16295
  modelTitle: 'o4-mini',
16281
16296
  modelName: 'o4-mini',
16282
- 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.",
16297
+ 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.',
16283
16298
  pricing: {
16284
16299
  prompt: pricing(`$4.00 / 1M tokens`),
16285
16300
  output: pricing(`$16.00 / 1M tokens`),
@@ -16291,7 +16306,7 @@ const OPENAI_MODELS = exportJson({
16291
16306
  modelVariant: 'CHAT',
16292
16307
  modelTitle: 'o3-deep-research',
16293
16308
  modelName: 'o3-deep-research',
16294
- 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.",
16309
+ 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.',
16295
16310
  pricing: {
16296
16311
  prompt: pricing(`$25.00 / 1M tokens`),
16297
16312
  output: pricing(`$100.00 / 1M tokens`),
@@ -16303,7 +16318,7 @@ const OPENAI_MODELS = exportJson({
16303
16318
  modelVariant: 'CHAT',
16304
16319
  modelTitle: 'o4-mini-deep-research',
16305
16320
  modelName: 'o4-mini-deep-research',
16306
- 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.",
16321
+ 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.',
16307
16322
  pricing: {
16308
16323
  prompt: pricing(`$12.00 / 1M tokens`),
16309
16324
  output: pricing(`$48.00 / 1M tokens`),
@@ -17945,6 +17960,62 @@ resultContent, rawResponse) {
17945
17960
  * TODO: [🤝] DRY Maybe some common abstraction between `computeOpenAiUsage` and `computeAnthropicClaudeUsage`
17946
17961
  */
17947
17962
 
17963
+ /**
17964
+ * Parses an OpenAI error message to identify which parameter is unsupported
17965
+ *
17966
+ * @param errorMessage The error message from OpenAI API
17967
+ * @returns The parameter name that is unsupported, or null if not an unsupported parameter error
17968
+ * @private utility of LLM Tools
17969
+ */
17970
+ function parseUnsupportedParameterError(errorMessage) {
17971
+ // Pattern to match "Unsupported value: 'parameter' does not support ..."
17972
+ const unsupportedValueMatch = errorMessage.match(/Unsupported value:\s*'([^']+)'\s*does not support/i);
17973
+ if (unsupportedValueMatch === null || unsupportedValueMatch === void 0 ? void 0 : unsupportedValueMatch[1]) {
17974
+ return unsupportedValueMatch[1];
17975
+ }
17976
+ // Pattern to match "'parameter' of type ... is not supported with this model"
17977
+ const parameterTypeMatch = errorMessage.match(/'([^']+)'\s*of type.*is not supported with this model/i);
17978
+ if (parameterTypeMatch === null || parameterTypeMatch === void 0 ? void 0 : parameterTypeMatch[1]) {
17979
+ return parameterTypeMatch[1];
17980
+ }
17981
+ return null;
17982
+ }
17983
+ /**
17984
+ * Creates a copy of model requirements with the specified parameter removed
17985
+ *
17986
+ * @param modelRequirements Original model requirements
17987
+ * @param unsupportedParameter The parameter to remove
17988
+ * @returns New model requirements without the unsupported parameter
17989
+ * @private utility of LLM Tools
17990
+ */
17991
+ function removeUnsupportedModelRequirement(modelRequirements, unsupportedParameter) {
17992
+ const newRequirements = { ...modelRequirements };
17993
+ // Map of parameter names that might appear in error messages to ModelRequirements properties
17994
+ const parameterMap = {
17995
+ temperature: 'temperature',
17996
+ max_tokens: 'maxTokens',
17997
+ maxTokens: 'maxTokens',
17998
+ seed: 'seed',
17999
+ };
18000
+ const propertyToRemove = parameterMap[unsupportedParameter];
18001
+ if (propertyToRemove && propertyToRemove in newRequirements) {
18002
+ delete newRequirements[propertyToRemove];
18003
+ }
18004
+ return newRequirements;
18005
+ }
18006
+ /**
18007
+ * Checks if an error is an "Unsupported value" error from OpenAI
18008
+ * @param error The error to check
18009
+ * @returns true if this is an unsupported parameter error
18010
+ * @private utility of LLM Tools
18011
+ */
18012
+ function isUnsupportedParameterError(error) {
18013
+ const errorMessage = error.message.toLowerCase();
18014
+ return (errorMessage.includes('unsupported value:') ||
18015
+ errorMessage.includes('is not supported with this model') ||
18016
+ errorMessage.includes('does not support'));
18017
+ }
18018
+
17948
18019
  /**
17949
18020
  * Execution Tools for calling OpenAI API or other OpenAI compatible provider
17950
18021
  *
@@ -17962,6 +18033,10 @@ class OpenAiCompatibleExecutionTools {
17962
18033
  * OpenAI API client.
17963
18034
  */
17964
18035
  this.client = null;
18036
+ /**
18037
+ * Tracks models and parameters that have already been retried to prevent infinite loops
18038
+ */
18039
+ this.retriedUnsupportedParameters = new Set();
17965
18040
  // TODO: Allow configuring rate limits via options
17966
18041
  this.limiter = new Bottleneck({
17967
18042
  minTime: 60000 / (this.options.maxRequestsPerMinute || DEFAULT_MAX_REQUESTS_PER_MINUTE),
@@ -18023,21 +18098,27 @@ class OpenAiCompatibleExecutionTools {
18023
18098
  * Calls OpenAI compatible API to use a chat model.
18024
18099
  */
18025
18100
  async callChatModel(prompt) {
18101
+ return this.callChatModelWithRetry(prompt, prompt.modelRequirements);
18102
+ }
18103
+ /**
18104
+ * Internal method that handles parameter retry for chat model calls
18105
+ */
18106
+ async callChatModelWithRetry(prompt, currentModelRequirements) {
18026
18107
  var _a;
18027
18108
  if (this.options.isVerbose) {
18028
- console.info(`💬 ${this.title} callChatModel call`, { prompt });
18109
+ console.info(`💬 ${this.title} callChatModel call`, { prompt, currentModelRequirements });
18029
18110
  }
18030
- const { content, parameters, modelRequirements, format } = prompt;
18111
+ const { content, parameters, format } = prompt;
18031
18112
  const client = await this.getClient();
18032
18113
  // TODO: [☂] Use here more modelRequirements
18033
- if (modelRequirements.modelVariant !== 'CHAT') {
18114
+ if (currentModelRequirements.modelVariant !== 'CHAT') {
18034
18115
  throw new PipelineExecutionError('Use callChatModel only for CHAT variant');
18035
18116
  }
18036
- const modelName = modelRequirements.modelName || this.getDefaultChatModel().modelName;
18117
+ const modelName = currentModelRequirements.modelName || this.getDefaultChatModel().modelName;
18037
18118
  const modelSettings = {
18038
18119
  model: modelName,
18039
- max_tokens: modelRequirements.maxTokens,
18040
- temperature: modelRequirements.temperature,
18120
+ max_tokens: currentModelRequirements.maxTokens,
18121
+ temperature: currentModelRequirements.temperature,
18041
18122
  // <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
18042
18123
  // <- Note: [🧆]
18043
18124
  }; // <- TODO: [💩] Guard here types better
@@ -18052,12 +18133,12 @@ class OpenAiCompatibleExecutionTools {
18052
18133
  const rawRequest = {
18053
18134
  ...modelSettings,
18054
18135
  messages: [
18055
- ...(modelRequirements.systemMessage === undefined
18136
+ ...(currentModelRequirements.systemMessage === undefined
18056
18137
  ? []
18057
18138
  : [
18058
18139
  {
18059
18140
  role: 'system',
18060
- content: modelRequirements.systemMessage,
18141
+ content: currentModelRequirements.systemMessage,
18061
18142
  },
18062
18143
  ]),
18063
18144
  {
@@ -18071,69 +18152,110 @@ class OpenAiCompatibleExecutionTools {
18071
18152
  if (this.options.isVerbose) {
18072
18153
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
18073
18154
  }
18074
- const rawResponse = await this.limiter
18075
- .schedule(() => this.makeRequestWithRetry(() => client.chat.completions.create(rawRequest)))
18076
- .catch((error) => {
18077
- assertsError(error);
18155
+ try {
18156
+ const rawResponse = await this.limiter
18157
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.chat.completions.create(rawRequest)))
18158
+ .catch((error) => {
18159
+ assertsError(error);
18160
+ if (this.options.isVerbose) {
18161
+ console.info(colors.bgRed('error'), error);
18162
+ }
18163
+ throw error;
18164
+ });
18078
18165
  if (this.options.isVerbose) {
18079
- console.info(colors.bgRed('error'), error);
18166
+ console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
18080
18167
  }
18081
- throw error;
18082
- });
18083
- if (this.options.isVerbose) {
18084
- console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
18085
- }
18086
- const complete = $getCurrentDate();
18087
- if (!rawResponse.choices[0]) {
18088
- throw new PipelineExecutionError(`No choises from ${this.title}`);
18089
- }
18090
- if (rawResponse.choices.length > 1) {
18091
- // TODO: This should be maybe only warning
18092
- throw new PipelineExecutionError(`More than one choise from ${this.title}`);
18168
+ const complete = $getCurrentDate();
18169
+ if (!rawResponse.choices[0]) {
18170
+ throw new PipelineExecutionError(`No choises from ${this.title}`);
18171
+ }
18172
+ if (rawResponse.choices.length > 1) {
18173
+ // TODO: This should be maybe only warning
18174
+ throw new PipelineExecutionError(`More than one choise from ${this.title}`);
18175
+ }
18176
+ const resultContent = rawResponse.choices[0].message.content;
18177
+ const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
18178
+ if (resultContent === null) {
18179
+ throw new PipelineExecutionError(`No response message from ${this.title}`);
18180
+ }
18181
+ return exportJson({
18182
+ name: 'promptResult',
18183
+ message: `Result of \`OpenAiCompatibleExecutionTools.callChatModel\``,
18184
+ order: [],
18185
+ value: {
18186
+ content: resultContent,
18187
+ modelName: rawResponse.model || modelName,
18188
+ timing: {
18189
+ start,
18190
+ complete,
18191
+ },
18192
+ usage,
18193
+ rawPromptContent,
18194
+ rawRequest,
18195
+ rawResponse,
18196
+ // <- [🗯]
18197
+ },
18198
+ });
18093
18199
  }
18094
- const resultContent = rawResponse.choices[0].message.content;
18095
- const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
18096
- if (resultContent === null) {
18097
- throw new PipelineExecutionError(`No response message from ${this.title}`);
18200
+ catch (error) {
18201
+ assertsError(error);
18202
+ // Check if this is an unsupported parameter error
18203
+ if (!isUnsupportedParameterError(error)) {
18204
+ throw error;
18205
+ }
18206
+ // Parse which parameter is unsupported
18207
+ const unsupportedParameter = parseUnsupportedParameterError(error.message);
18208
+ if (!unsupportedParameter) {
18209
+ if (this.options.isVerbose) {
18210
+ console.warn(colors.bgYellow('Warning'), 'Could not parse unsupported parameter from error:', error.message);
18211
+ }
18212
+ throw error;
18213
+ }
18214
+ // Create a unique key for this model + parameter combination to prevent infinite loops
18215
+ const retryKey = `${modelName}-${unsupportedParameter}`;
18216
+ if (this.retriedUnsupportedParameters.has(retryKey)) {
18217
+ // Already retried this parameter, throw the error
18218
+ if (this.options.isVerbose) {
18219
+ console.warn(colors.bgRed('Error'), `Parameter '${unsupportedParameter}' for model '${modelName}' already retried once, throwing error:`, error.message);
18220
+ }
18221
+ throw error;
18222
+ }
18223
+ // Mark this parameter as retried
18224
+ this.retriedUnsupportedParameters.add(retryKey);
18225
+ // Log warning in verbose mode
18226
+ if (this.options.isVerbose) {
18227
+ console.warn(colors.bgYellow('Warning'), `Removing unsupported parameter '${unsupportedParameter}' for model '${modelName}' and retrying request`);
18228
+ }
18229
+ // Remove the unsupported parameter and retry
18230
+ const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
18231
+ return this.callChatModelWithRetry(prompt, modifiedModelRequirements);
18098
18232
  }
18099
- return exportJson({
18100
- name: 'promptResult',
18101
- message: `Result of \`OpenAiCompatibleExecutionTools.callChatModel\``,
18102
- order: [],
18103
- value: {
18104
- content: resultContent,
18105
- modelName: rawResponse.model || modelName,
18106
- timing: {
18107
- start,
18108
- complete,
18109
- },
18110
- usage,
18111
- rawPromptContent,
18112
- rawRequest,
18113
- rawResponse,
18114
- // <- [🗯]
18115
- },
18116
- });
18117
18233
  }
18118
18234
  /**
18119
18235
  * Calls OpenAI API to use a complete model.
18120
18236
  */
18121
18237
  async callCompletionModel(prompt) {
18238
+ return this.callCompletionModelWithRetry(prompt, prompt.modelRequirements);
18239
+ }
18240
+ /**
18241
+ * Internal method that handles parameter retry for completion model calls
18242
+ */
18243
+ async callCompletionModelWithRetry(prompt, currentModelRequirements) {
18122
18244
  var _a;
18123
18245
  if (this.options.isVerbose) {
18124
- console.info(`🖋 ${this.title} callCompletionModel call`, { prompt });
18246
+ console.info(`🖋 ${this.title} callCompletionModel call`, { prompt, currentModelRequirements });
18125
18247
  }
18126
- const { content, parameters, modelRequirements } = prompt;
18248
+ const { content, parameters } = prompt;
18127
18249
  const client = await this.getClient();
18128
18250
  // TODO: [☂] Use here more modelRequirements
18129
- if (modelRequirements.modelVariant !== 'COMPLETION') {
18251
+ if (currentModelRequirements.modelVariant !== 'COMPLETION') {
18130
18252
  throw new PipelineExecutionError('Use callCompletionModel only for COMPLETION variant');
18131
18253
  }
18132
- const modelName = modelRequirements.modelName || this.getDefaultCompletionModel().modelName;
18254
+ const modelName = currentModelRequirements.modelName || this.getDefaultCompletionModel().modelName;
18133
18255
  const modelSettings = {
18134
18256
  model: modelName,
18135
- max_tokens: modelRequirements.maxTokens,
18136
- temperature: modelRequirements.temperature,
18257
+ max_tokens: currentModelRequirements.maxTokens,
18258
+ temperature: currentModelRequirements.temperature,
18137
18259
  // <- TODO: [🈁] Use `seed` here AND/OR use is `isDeterministic` for entire execution tools
18138
18260
  // <- Note: [🧆]
18139
18261
  };
@@ -18147,46 +18269,81 @@ class OpenAiCompatibleExecutionTools {
18147
18269
  if (this.options.isVerbose) {
18148
18270
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
18149
18271
  }
18150
- const rawResponse = await this.limiter
18151
- .schedule(() => this.makeRequestWithRetry(() => client.completions.create(rawRequest)))
18152
- .catch((error) => {
18153
- assertsError(error);
18272
+ try {
18273
+ const rawResponse = await this.limiter
18274
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.completions.create(rawRequest)))
18275
+ .catch((error) => {
18276
+ assertsError(error);
18277
+ if (this.options.isVerbose) {
18278
+ console.info(colors.bgRed('error'), error);
18279
+ }
18280
+ throw error;
18281
+ });
18154
18282
  if (this.options.isVerbose) {
18155
- console.info(colors.bgRed('error'), error);
18283
+ console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
18156
18284
  }
18157
- throw error;
18158
- });
18159
- if (this.options.isVerbose) {
18160
- console.info(colors.bgWhite('rawResponse'), JSON.stringify(rawResponse, null, 4));
18161
- }
18162
- const complete = $getCurrentDate();
18163
- if (!rawResponse.choices[0]) {
18164
- throw new PipelineExecutionError(`No choises from ${this.title}`);
18285
+ const complete = $getCurrentDate();
18286
+ if (!rawResponse.choices[0]) {
18287
+ throw new PipelineExecutionError(`No choises from ${this.title}`);
18288
+ }
18289
+ if (rawResponse.choices.length > 1) {
18290
+ // TODO: This should be maybe only warning
18291
+ throw new PipelineExecutionError(`More than one choise from ${this.title}`);
18292
+ }
18293
+ const resultContent = rawResponse.choices[0].text;
18294
+ const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
18295
+ return exportJson({
18296
+ name: 'promptResult',
18297
+ message: `Result of \`OpenAiCompatibleExecutionTools.callCompletionModel\``,
18298
+ order: [],
18299
+ value: {
18300
+ content: resultContent,
18301
+ modelName: rawResponse.model || modelName,
18302
+ timing: {
18303
+ start,
18304
+ complete,
18305
+ },
18306
+ usage,
18307
+ rawPromptContent,
18308
+ rawRequest,
18309
+ rawResponse,
18310
+ // <- [🗯]
18311
+ },
18312
+ });
18165
18313
  }
18166
- if (rawResponse.choices.length > 1) {
18167
- // TODO: This should be maybe only warning
18168
- throw new PipelineExecutionError(`More than one choise from ${this.title}`);
18314
+ catch (error) {
18315
+ assertsError(error);
18316
+ // Check if this is an unsupported parameter error
18317
+ if (!isUnsupportedParameterError(error)) {
18318
+ throw error;
18319
+ }
18320
+ // Parse which parameter is unsupported
18321
+ const unsupportedParameter = parseUnsupportedParameterError(error.message);
18322
+ if (!unsupportedParameter) {
18323
+ if (this.options.isVerbose) {
18324
+ console.warn(colors.bgYellow('Warning'), 'Could not parse unsupported parameter from error:', error.message);
18325
+ }
18326
+ throw error;
18327
+ }
18328
+ // Create a unique key for this model + parameter combination to prevent infinite loops
18329
+ const retryKey = `${modelName}-${unsupportedParameter}`;
18330
+ if (this.retriedUnsupportedParameters.has(retryKey)) {
18331
+ // Already retried this parameter, throw the error
18332
+ if (this.options.isVerbose) {
18333
+ console.warn(colors.bgRed('Error'), `Parameter '${unsupportedParameter}' for model '${modelName}' already retried once, throwing error:`, error.message);
18334
+ }
18335
+ throw error;
18336
+ }
18337
+ // Mark this parameter as retried
18338
+ this.retriedUnsupportedParameters.add(retryKey);
18339
+ // Log warning in verbose mode
18340
+ if (this.options.isVerbose) {
18341
+ console.warn(colors.bgYellow('Warning'), `Removing unsupported parameter '${unsupportedParameter}' for model '${modelName}' and retrying request`);
18342
+ }
18343
+ // Remove the unsupported parameter and retry
18344
+ const modifiedModelRequirements = removeUnsupportedModelRequirement(currentModelRequirements, unsupportedParameter);
18345
+ return this.callCompletionModelWithRetry(prompt, modifiedModelRequirements);
18169
18346
  }
18170
- const resultContent = rawResponse.choices[0].text;
18171
- const usage = this.computeUsage(content || '', resultContent || '', rawResponse);
18172
- return exportJson({
18173
- name: 'promptResult',
18174
- message: `Result of \`OpenAiCompatibleExecutionTools.callCompletionModel\``,
18175
- order: [],
18176
- value: {
18177
- content: resultContent,
18178
- modelName: rawResponse.model || modelName,
18179
- timing: {
18180
- start,
18181
- complete,
18182
- },
18183
- usage,
18184
- rawPromptContent,
18185
- rawRequest,
18186
- rawResponse,
18187
- // <- [🗯]
18188
- },
18189
- });
18190
18347
  }
18191
18348
  /**
18192
18349
  * Calls OpenAI compatible API to use a embedding model
@@ -18212,7 +18369,7 @@ class OpenAiCompatibleExecutionTools {
18212
18369
  console.info(colors.bgWhite('rawRequest'), JSON.stringify(rawRequest, null, 4));
18213
18370
  }
18214
18371
  const rawResponse = await this.limiter
18215
- .schedule(() => this.makeRequestWithRetry(() => client.embeddings.create(rawRequest)))
18372
+ .schedule(() => this.makeRequestWithNetworkRetry(() => client.embeddings.create(rawRequest)))
18216
18373
  .catch((error) => {
18217
18374
  assertsError(error);
18218
18375
  if (this.options.isVerbose) {
@@ -18274,7 +18431,7 @@ class OpenAiCompatibleExecutionTools {
18274
18431
  /**
18275
18432
  * Makes a request with retry logic for network errors like ECONNRESET
18276
18433
  */
18277
- async makeRequestWithRetry(requestFn) {
18434
+ async makeRequestWithNetworkRetry(requestFn) {
18278
18435
  let lastError;
18279
18436
  for (let attempt = 1; attempt <= CONNECTION_RETRIES_LIMIT; attempt++) {
18280
18437
  try {
@@ -18286,8 +18443,8 @@ class OpenAiCompatibleExecutionTools {
18286
18443
  // Check if this is a retryable network error
18287
18444
  const isRetryableError = this.isRetryableNetworkError(error);
18288
18445
  if (!isRetryableError || attempt === CONNECTION_RETRIES_LIMIT) {
18289
- if (this.options.isVerbose) {
18290
- console.info(colors.bgRed('Final error after retries'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}:`, error);
18446
+ if (this.options.isVerbose && this.isRetryableNetworkError(error)) {
18447
+ console.info(colors.bgRed('Final network error after retries'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}:`, error);
18291
18448
  }
18292
18449
  throw error;
18293
18450
  }
@@ -18297,7 +18454,7 @@ class OpenAiCompatibleExecutionTools {
18297
18454
  const jitterDelay = Math.random() * 500; // Add some randomness
18298
18455
  const totalDelay = backoffDelay + jitterDelay;
18299
18456
  if (this.options.isVerbose) {
18300
- console.info(colors.bgYellow('Retrying request'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}, waiting ${Math.round(totalDelay)}ms:`, error.message);
18457
+ console.info(colors.bgYellow('Retrying network request'), `Attempt ${attempt}/${CONNECTION_RETRIES_LIMIT}, waiting ${Math.round(totalDelay)}ms:`, error.message);
18301
18458
  }
18302
18459
  // Wait before retrying
18303
18460
  await new Promise((resolve) => setTimeout(resolve, totalDelay));
@@ -19278,11 +19435,12 @@ async function getScraperIntermediateSource(source, options) {
19278
19435
  catch (error) {
19279
19436
  // Note: If we can't create cache directory, continue without it
19280
19437
  // This handles read-only filesystems, permission issues, and missing parent directories
19281
- if (error instanceof Error && (error.message.includes('EROFS') ||
19282
- error.message.includes('read-only') ||
19283
- error.message.includes('EACCES') ||
19284
- error.message.includes('EPERM') ||
19285
- error.message.includes('ENOENT'))) ;
19438
+ if (error instanceof Error &&
19439
+ (error.message.includes('EROFS') ||
19440
+ error.message.includes('read-only') ||
19441
+ error.message.includes('EACCES') ||
19442
+ error.message.includes('EPERM') ||
19443
+ error.message.includes('ENOENT'))) ;
19286
19444
  else {
19287
19445
  // Re-throw other unexpected errors
19288
19446
  throw error;
@@ -19371,9 +19529,7 @@ class MarkdownScraper {
19371
19529
  throw new MissingToolsError('LLM tools are required for scraping external files');
19372
19530
  // <- Note: This scraper is used in all other scrapers, so saying "external files" not "markdown files"
19373
19531
  }
19374
- // TODO: [🚐] Make arrayable LLMs -> single LLM DRY
19375
- const _llms = arrayableToArray(llm);
19376
- const llmTools = _llms.length === 1 ? _llms[0] : joinLlmExecutionTools(..._llms);
19532
+ const llmTools = getSingleLlmExecutionTools(llm);
19377
19533
  // TODO: [🌼] In future use `ptbk make` and made getPipelineCollection
19378
19534
  const collection = createCollectionFromJson(...PipelineCollection);
19379
19535
  const prepareKnowledgeFromMarkdownExecutor = createPipelineExecutor({
@@ -20150,11 +20306,12 @@ class MarkitdownScraper {
20150
20306
  catch (error) {
20151
20307
  // Note: If we can't write to cache, we'll continue without caching
20152
20308
  // This handles read-only filesystems like Vercel
20153
- if (error instanceof Error && (error.message.includes('EROFS') ||
20154
- error.message.includes('read-only') ||
20155
- error.message.includes('EACCES') ||
20156
- error.message.includes('EPERM') ||
20157
- error.message.includes('ENOENT'))) ;
20309
+ if (error instanceof Error &&
20310
+ (error.message.includes('EROFS') ||
20311
+ error.message.includes('read-only') ||
20312
+ error.message.includes('EACCES') ||
20313
+ error.message.includes('EPERM') ||
20314
+ error.message.includes('ENOENT'))) ;
20158
20315
  else {
20159
20316
  // Re-throw other unexpected errors
20160
20317
  throw error;
@@ -20454,11 +20611,12 @@ class WebsiteScraper {
20454
20611
  catch (error) {
20455
20612
  // Note: If we can't write to cache, we'll continue without caching
20456
20613
  // This handles read-only filesystems like Vercel
20457
- if (error instanceof Error && (error.message.includes('EROFS') ||
20458
- error.message.includes('read-only') ||
20459
- error.message.includes('EACCES') ||
20460
- error.message.includes('EPERM') ||
20461
- error.message.includes('ENOENT'))) ;
20614
+ if (error instanceof Error &&
20615
+ (error.message.includes('EROFS') ||
20616
+ error.message.includes('read-only') ||
20617
+ error.message.includes('EACCES') ||
20618
+ error.message.includes('EPERM') ||
20619
+ error.message.includes('ENOENT'))) ;
20462
20620
  else {
20463
20621
  // Re-throw other unexpected errors
20464
20622
  throw error;