@juspay/neurolink 11.0.0 → 11.1.0

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 (103) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/browser/neurolink.min.js +524 -524
  3. package/dist/cli/commands/setup.d.ts +4 -0
  4. package/dist/cli/commands/setup.js +19 -33
  5. package/dist/cli/factories/commandFactory.d.ts +1157 -1
  6. package/dist/cli/factories/commandFactory.js +20 -53
  7. package/dist/factories/providerDescriptors.d.ts +18 -0
  8. package/dist/factories/providerDescriptors.js +536 -0
  9. package/dist/factories/providerFactory.d.ts +25 -14
  10. package/dist/factories/providerFactory.js +46 -23
  11. package/dist/factories/providerRegistry.js +31 -30
  12. package/dist/index.d.ts +10 -1
  13. package/dist/index.js +13 -3
  14. package/dist/lib/factories/providerDescriptors.d.ts +18 -0
  15. package/dist/lib/factories/providerDescriptors.js +537 -0
  16. package/dist/lib/factories/providerFactory.d.ts +25 -14
  17. package/dist/lib/factories/providerFactory.js +46 -23
  18. package/dist/lib/factories/providerRegistry.js +31 -30
  19. package/dist/lib/index.d.ts +10 -1
  20. package/dist/lib/index.js +13 -3
  21. package/dist/lib/neurolink.js +25 -37
  22. package/dist/lib/providers/amazonBedrock/client.js +34 -16
  23. package/dist/lib/providers/anthropic/client.js +39 -34
  24. package/dist/lib/providers/azureOpenai.js +17 -15
  25. package/dist/lib/providers/cloudflare.js +12 -21
  26. package/dist/lib/providers/cohere.js +31 -25
  27. package/dist/lib/providers/deepseek.js +23 -26
  28. package/dist/lib/providers/fireworks.js +12 -21
  29. package/dist/lib/providers/googleAiStudio/client.d.ts +2 -0
  30. package/dist/lib/providers/googleAiStudio/client.js +39 -17
  31. package/dist/lib/providers/googleVertex/client.js +107 -99
  32. package/dist/lib/providers/groq.js +19 -22
  33. package/dist/lib/providers/huggingFace/client.js +26 -24
  34. package/dist/lib/providers/litellm/client.js +54 -39
  35. package/dist/lib/providers/llamaCpp.js +21 -18
  36. package/dist/lib/providers/lmStudio.js +22 -19
  37. package/dist/lib/providers/mistral.js +12 -24
  38. package/dist/lib/providers/nvidiaNim/client.js +37 -34
  39. package/dist/lib/providers/ollama/client.js +50 -35
  40. package/dist/lib/providers/openAI/client.js +37 -40
  41. package/dist/lib/providers/openRouter/client.js +53 -47
  42. package/dist/lib/providers/openaiChatCompletionsBase.js +40 -16
  43. package/dist/lib/providers/openaiCompatible/client.js +36 -32
  44. package/dist/lib/providers/perplexity.js +12 -21
  45. package/dist/lib/providers/togetherAi.js +12 -21
  46. package/dist/lib/providers/xai.js +17 -26
  47. package/dist/lib/server/errors.d.ts +1 -1
  48. package/dist/lib/server/errors.js +2 -2
  49. package/dist/lib/server/index.d.ts +2 -2
  50. package/dist/lib/server/index.js +5 -3
  51. package/dist/lib/server/middleware/rateLimit.d.ts +0 -4
  52. package/dist/lib/server/middleware/rateLimit.js +0 -4
  53. package/dist/lib/types/errors.d.ts +35 -0
  54. package/dist/lib/types/providers.d.ts +64 -0
  55. package/dist/lib/utils/errorClassifier.d.ts +30 -0
  56. package/dist/lib/utils/errorClassifier.js +94 -0
  57. package/dist/lib/utils/fileDetector.js +6 -43
  58. package/dist/lib/utils/providerHealth.d.ts +42 -7
  59. package/dist/lib/utils/providerHealth.js +115 -122
  60. package/dist/lib/utils/providerUtils.js +21 -63
  61. package/dist/neurolink.js +25 -37
  62. package/dist/providers/amazonBedrock/client.js +34 -16
  63. package/dist/providers/amazonSagemaker.d.ts +1 -1
  64. package/dist/providers/anthropic/client.js +39 -34
  65. package/dist/providers/azureOpenai.js +17 -15
  66. package/dist/providers/cloudflare.js +12 -21
  67. package/dist/providers/cohere.js +31 -25
  68. package/dist/providers/deepseek.js +23 -26
  69. package/dist/providers/fireworks.js +12 -21
  70. package/dist/providers/googleAiStudio/client.d.ts +2 -0
  71. package/dist/providers/googleAiStudio/client.js +39 -17
  72. package/dist/providers/googleVertex/client.js +107 -99
  73. package/dist/providers/groq.js +19 -22
  74. package/dist/providers/huggingFace/client.js +26 -24
  75. package/dist/providers/litellm/client.js +54 -39
  76. package/dist/providers/llamaCpp.js +21 -18
  77. package/dist/providers/lmStudio.js +22 -19
  78. package/dist/providers/mistral.js +12 -24
  79. package/dist/providers/nvidiaNim/client.js +37 -34
  80. package/dist/providers/ollama/client.js +50 -35
  81. package/dist/providers/openAI/client.js +37 -40
  82. package/dist/providers/openRouter/client.js +53 -47
  83. package/dist/providers/openaiChatCompletionsBase.js +40 -16
  84. package/dist/providers/openaiCompatible/client.js +36 -32
  85. package/dist/providers/perplexity.js +12 -21
  86. package/dist/providers/sagemaker/language-model.d.ts +2 -2
  87. package/dist/providers/togetherAi.js +12 -21
  88. package/dist/providers/xai.js +17 -26
  89. package/dist/server/errors.d.ts +1 -1
  90. package/dist/server/errors.js +2 -2
  91. package/dist/server/index.d.ts +2 -2
  92. package/dist/server/index.js +5 -3
  93. package/dist/server/middleware/rateLimit.d.ts +0 -4
  94. package/dist/server/middleware/rateLimit.js +0 -4
  95. package/dist/types/errors.d.ts +35 -0
  96. package/dist/types/providers.d.ts +64 -0
  97. package/dist/utils/errorClassifier.d.ts +30 -0
  98. package/dist/utils/errorClassifier.js +93 -0
  99. package/dist/utils/fileDetector.js +6 -43
  100. package/dist/utils/providerHealth.d.ts +42 -7
  101. package/dist/utils/providerHealth.js +115 -122
  102. package/dist/utils/providerUtils.js +21 -63
  103. package/package.json +15 -70
@@ -1,29 +1,25 @@
1
1
  import { logger } from "../utils/logger.js";
2
+ import { PROVIDER_DESCRIPTORS, PROVIDER_DESCRIPTORS_BY_NAME, PROVIDER_ALIAS_INDEX, } from "./providerDescriptors.js";
2
3
  // Pure factory pattern with no hardcoded imports
3
4
  // All providers loaded dynamically via registry to avoid circular dependencies
4
5
  /**
5
- * Maps registered provider names to NeurolinkCredentials keys. Most names
6
- * match (openai, anthropic, vertex, bedrock, etc.) but every kebab-case
7
- * provider whose canonical credentials key is camelCaseor otherwise
8
- * spelled differently MUST be mapped here, otherwise per-call/instance
9
- * credential overrides silently get dropped (createProvider() looks up
10
- * credentials["lm-studio"], which is undefined, while the caller wrote
11
- * credentials.lmStudio).
12
- */
13
- export const CREDENTIAL_KEY_MAP = {
14
- "google-ai": "googleAiStudio",
15
- "openai-compatible": "openaiCompatible",
16
- huggingface: "huggingFace",
17
- "lm-studio": "lmStudio",
18
- "nvidia-nim": "nvidiaNim",
19
- "together-ai": "together",
20
- };
21
- /**
22
- * Resolve a registered provider name to its NeurolinkCredentials key.
23
- * Falls back to the provider name itself when no remapping is needed.
6
+ * Resolve a registered provider name (or alias) to its NeurolinkCredentials
7
+ * key. Backed by ProviderFactory.getDescriptor() PROVIDER_DESCRIPTORS is
8
+ * the single source of truth for provider identity instead of a
9
+ * hand-maintained map, so this can no longer drift out of sync with the
10
+ * descriptors, and it correctly resolves aliases (e.g. "hf") through
11
+ * PROVIDER_ALIAS_INDEX, not just canonical names. Falls back to the
12
+ * lowercased input when no descriptor is found, matching the retired
13
+ * map's behavior for unknown provider names.
14
+ *
15
+ * Referencing ProviderFactory here (defined further down this file) is
16
+ * safe: this function's body only runs when called, by which point the
17
+ * module has finished evaluating and ProviderFactory is fully defined —
18
+ * there is no temporal-dead-zone hazard from the declaration order.
24
19
  */
25
20
  export function resolveCredentialKey(providerName) {
26
- return (CREDENTIAL_KEY_MAP[providerName.toLowerCase()] ?? providerName.toLowerCase());
21
+ const normalized = providerName.toLowerCase();
22
+ return (ProviderFactory.getDescriptor(normalized)?.credentialsKey ?? normalized);
27
23
  }
28
24
  /**
29
25
  * True Factory Pattern implementation for AI Providers
@@ -37,11 +33,12 @@ export class ProviderFactory {
37
33
  * Register a provider with the factory
38
34
  */
39
35
  static registerProvider(name, constructor, defaultModel, // Optional - provider can read from env
40
- aliases = []) {
36
+ aliases = [], descriptor) {
41
37
  const registration = {
42
38
  constructor,
43
39
  defaultModel,
44
40
  aliases,
41
+ descriptor,
45
42
  };
46
43
  // Register main name
47
44
  ProviderFactory.providers.set(name.toLowerCase(), registration);
@@ -118,16 +115,42 @@ export class ProviderFactory {
118
115
  static getProviderInfo(providerName) {
119
116
  return ProviderFactory.providers.get(providerName.toLowerCase());
120
117
  }
118
+ /**
119
+ * Look up a provider's static descriptor. Checks the built-in
120
+ * PROVIDER_DESCRIPTORS first (works even before registerAllProviders()
121
+ * has run, and resolves aliases via PROVIDER_ALIAS_INDEX), then falls
122
+ * back to whatever descriptor a live custom registration attached via
123
+ * registerProvider()'s 5th parameter.
124
+ */
125
+ static getDescriptor(name) {
126
+ const normalized = name.toLowerCase();
127
+ const canonical = PROVIDER_ALIAS_INDEX.get(normalized);
128
+ if (canonical) {
129
+ const builtIn = PROVIDER_DESCRIPTORS_BY_NAME.get(canonical);
130
+ if (builtIn) {
131
+ return builtIn;
132
+ }
133
+ }
134
+ return ProviderFactory.providers.get(normalized)?.descriptor;
135
+ }
136
+ /** All built-in provider descriptors (does not include custom-registered providers that lack a descriptor). */
137
+ static getAllDescriptors() {
138
+ return PROVIDER_DESCRIPTORS;
139
+ }
121
140
  /**
122
141
  * Normalize provider names using aliases (PHASE 1: Factory Pattern)
123
142
  */
124
143
  static normalizeProviderName(providerName) {
125
144
  const normalized = providerName.toLowerCase();
126
- // Check direct registration
127
145
  if (ProviderFactory.providers.has(normalized)) {
128
146
  return normalized;
129
147
  }
130
- // Check aliases from all registrations
148
+ const canonical = PROVIDER_ALIAS_INDEX.get(normalized);
149
+ if (canonical && ProviderFactory.providers.has(canonical)) {
150
+ return canonical;
151
+ }
152
+ // Fallback for providers registered without a built-in descriptor
153
+ // (e.g. TTS/STT/media handlers registered outside PROVIDER_DESCRIPTORS).
131
154
  for (const [name, registration] of ProviderFactory.providers.entries()) {
132
155
  if (registration.aliases?.includes(normalized)) {
133
156
  return name;
@@ -1,6 +1,7 @@
1
1
  import { ProviderFactory } from "./providerFactory.js";
2
2
  import { logger } from "../utils/logger.js";
3
3
  import { AIProviderName, GoogleAIModels, OpenAIModels, AnthropicModels, VertexModels, MistralModels, OllamaModels, LiteLLMModels, HuggingFaceModels, DeepSeekModels, NvidiaNimModels, OpenRouterModels, XaiModels, GroqModels, CohereModels, TogetherAIModels, FireworksModels, PerplexityModels, CloudflareModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
4
+ import { PROVIDER_DESCRIPTORS_BY_NAME } from "./providerDescriptors.js";
4
5
  /**
5
6
  * Provider Registry - registers all providers with the factory
6
7
  * This is where we migrate providers one by one to the new pattern
@@ -67,26 +68,26 @@ export class ProviderRegistry {
67
68
  const googleAiCreds = credentials;
68
69
  const { GoogleAIStudioProvider } = await import("../providers/googleAiStudio/index.js");
69
70
  return new GoogleAIStudioProvider(modelName, sdk, googleAiCreds);
70
- }, GoogleAIModels.GEMINI_2_5_FLASH, ["googleAiStudio", "google", "gemini", "google-ai", "google-ai-studio"]);
71
+ }, GoogleAIModels.GEMINI_2_5_FLASH, ["googleAiStudio", "google", "gemini", "google-ai", "google-ai-studio"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.GOOGLE_AI));
71
72
  // Register OpenAI provider
72
73
  ProviderFactory.registerProvider(AIProviderName.OPENAI, async (modelName, _providerName, sdk, _region, credentials) => {
73
74
  const openaiCreds = credentials;
74
75
  const { OpenAIProvider } = await import("../providers/openAI/index.js");
75
76
  return new OpenAIProvider(modelName, sdk, undefined, openaiCreds);
76
- }, OpenAIModels.GPT_4O_MINI, ["gpt", "chatgpt"]);
77
+ }, OpenAIModels.GPT_4O_MINI, ["gpt", "chatgpt"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.OPENAI));
77
78
  // Register Anthropic provider
78
79
  ProviderFactory.registerProvider(AIProviderName.ANTHROPIC, async (modelName, _providerName, sdk, _region, credentials) => {
79
80
  const anthropicCreds = credentials;
80
81
  const { AnthropicProvider } = await import("../providers/anthropic/index.js");
81
82
  return new AnthropicProvider(modelName, sdk, undefined, anthropicCreds);
82
- }, AnthropicModels.CLAUDE_SONNET_4_6, ["claude", "anthropic"]);
83
+ }, AnthropicModels.CLAUDE_SONNET_4_6, ["claude", "anthropic"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.ANTHROPIC));
83
84
  // Register Amazon Bedrock provider
84
85
  ProviderFactory.registerProvider(AIProviderName.BEDROCK, async (modelName, _providerName, sdk, region, credentials) => {
85
86
  const bedrockCreds = credentials;
86
87
  const { AmazonBedrockProvider } = await import("../providers/amazonBedrock/index.js");
87
88
  return new AmazonBedrockProvider(modelName, sdk, region, bedrockCreds);
88
89
  }, undefined, // Let provider read BEDROCK_MODEL from .env
89
- ["bedrock", "aws"]);
90
+ ["bedrock", "aws"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.BEDROCK));
90
91
  // Register Azure OpenAI provider
91
92
  ProviderFactory.registerProvider(AIProviderName.AZURE, async (modelName, _providerName, sdk, _region, credentials) => {
92
93
  const azureCreds = credentials;
@@ -96,45 +97,45 @@ export class ProviderRegistry {
96
97
  process.env.AZURE_OPENAI_MODEL ||
97
98
  process.env.AZURE_OPENAI_DEPLOYMENT ||
98
99
  process.env.AZURE_OPENAI_DEPLOYMENT_ID ||
99
- "gpt-4o-mini", ["azure", "azureOpenai"]);
100
+ "gpt-4o-mini", ["azure", "azureOpenai"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.AZURE));
100
101
  // Register Google Vertex AI provider
101
102
  ProviderFactory.registerProvider(AIProviderName.VERTEX, async (modelName, providerName, sdk, region, credentials) => {
102
103
  const vertexCreds = credentials;
103
104
  const { GoogleVertexProvider } = await import("../providers/googleVertex/index.js");
104
105
  return new GoogleVertexProvider(modelName, providerName, sdk, region, vertexCreds);
105
- }, VertexModels.CLAUDE_4_6_SONNET, ["vertex", "googleVertex"]);
106
+ }, VertexModels.CLAUDE_4_6_SONNET, ["vertex", "googleVertex"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.VERTEX));
106
107
  // Register Hugging Face provider (Unified Router implementation)
107
108
  ProviderFactory.registerProvider(AIProviderName.HUGGINGFACE, async (modelName, _providerName, sdk, region, credentials) => {
108
109
  const hfCreds = credentials;
109
110
  const { HuggingFaceProvider } = await import("../providers/huggingFace/index.js");
110
111
  return new HuggingFaceProvider(modelName, sdk, region, hfCreds);
111
112
  }, process.env.HUGGINGFACE_MODEL ||
112
- HuggingFaceModels.QWEN_2_5_72B_INSTRUCT, ["huggingface", "hf"]);
113
+ HuggingFaceModels.QWEN_2_5_72B_INSTRUCT, ["huggingface", "hf"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.HUGGINGFACE));
113
114
  // Register Mistral AI provider
114
115
  ProviderFactory.registerProvider(AIProviderName.MISTRAL, async (modelName, _providerName, sdk, _region, credentials) => {
115
116
  const mistralCreds = credentials;
116
117
  const { MistralProvider } = await import("../providers/mistral.js");
117
118
  return new MistralProvider(modelName, sdk, undefined, mistralCreds);
118
- }, MistralModels.MISTRAL_LARGE_LATEST, ["mistral"]);
119
+ }, MistralModels.MISTRAL_LARGE_LATEST, ["mistral"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.MISTRAL));
119
120
  // Register Ollama provider
120
121
  ProviderFactory.registerProvider(AIProviderName.OLLAMA, async (modelName, _providerName, sdk, _region, credentials) => {
121
122
  const ollamaCreds = credentials;
122
123
  const { OllamaProvider } = await import("../providers/ollama/index.js");
123
124
  return new OllamaProvider(modelName, sdk, undefined, ollamaCreds);
124
- }, process.env.OLLAMA_MODEL || OllamaModels.LLAMA3_2_LATEST, ["ollama", "local"]);
125
+ }, process.env.OLLAMA_MODEL || OllamaModels.LLAMA3_2_LATEST, ["ollama", "local"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.OLLAMA));
125
126
  // Register LiteLLM provider
126
127
  ProviderFactory.registerProvider(AIProviderName.LITELLM, async (modelName, _providerName, sdk, _region, credentials) => {
127
128
  const litellmCreds = credentials;
128
129
  const { LiteLLMProvider } = await import("../providers/litellm/index.js");
129
130
  return new LiteLLMProvider(modelName, sdk, undefined, litellmCreds);
130
- }, process.env.LITELLM_MODEL || LiteLLMModels.OPENAI_GPT_4O_MINI, ["litellm"]);
131
+ }, process.env.LITELLM_MODEL || LiteLLMModels.OPENAI_GPT_4O_MINI, ["litellm"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.LITELLM));
131
132
  // Register OpenAI Compatible provider
132
133
  ProviderFactory.registerProvider(AIProviderName.OPENAI_COMPATIBLE, async (modelName, _providerName, sdk, _region, credentials) => {
133
134
  const openaiCompatCreds = credentials;
134
135
  const { OpenAICompatibleProvider } = await import("../providers/openaiCompatible/index.js");
135
136
  return new OpenAICompatibleProvider(modelName, sdk, undefined, openaiCompatCreds);
136
137
  }, process.env.OPENAI_COMPATIBLE_MODEL || undefined, // Enable auto-discovery when no model specified
137
- ["openai-compatible", "vllm", "compatible"]);
138
+ ["openai-compatible", "vllm", "compatible"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.OPENAI_COMPATIBLE));
138
139
  // Register OpenRouter provider (300+ models from 60+ providers)
139
140
  ProviderFactory.registerProvider(AIProviderName.OPENROUTER, async (modelName, _providerName, sdk, _region, credentials) => {
140
141
  const openrouterCreds = credentials;
@@ -146,117 +147,117 @@ export class ProviderRegistry {
146
147
  // for the rationale. Keep the three defaults aligned at the new
147
148
  // model (claude-sonnet-4.5) so the registry doesn't override the
148
149
  // provider's getDefault.
149
- process.env.OPENROUTER_MODEL || OpenRouterModels.CLAUDE_SONNET_4_5, ["openrouter", "or"]);
150
+ process.env.OPENROUTER_MODEL || OpenRouterModels.CLAUDE_SONNET_4_5, ["openrouter", "or"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.OPENROUTER));
150
151
  // Register Amazon SageMaker provider
151
152
  ProviderFactory.registerProvider(AIProviderName.SAGEMAKER, async (modelName, _providerName, _sdk, region, credentials) => {
152
153
  const sagemakerCreds = credentials;
153
154
  const { AmazonSageMakerProvider } = await import("../providers/amazonSagemaker.js");
154
155
  return new AmazonSageMakerProvider(modelName, undefined, region, undefined, sagemakerCreds);
155
- }, process.env.SAGEMAKER_MODEL || "sagemaker-model", ["sagemaker", "aws-sagemaker"]);
156
+ }, process.env.SAGEMAKER_MODEL || "sagemaker-model", ["sagemaker", "aws-sagemaker"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.SAGEMAKER));
156
157
  // Register DeepSeek provider
157
158
  ProviderFactory.registerProvider(AIProviderName.DEEPSEEK, async (modelName, _providerName, sdk, _region, credentials) => {
158
159
  const deepseekCreds = credentials;
159
160
  const { DeepSeekProvider } = await import("../providers/deepseek.js");
160
161
  return new DeepSeekProvider(modelName, sdk, undefined, deepseekCreds);
161
- }, process.env.DEEPSEEK_MODEL || DeepSeekModels.DEEPSEEK_CHAT, ["deepseek", "ds"]);
162
+ }, process.env.DEEPSEEK_MODEL || DeepSeekModels.DEEPSEEK_CHAT, ["deepseek", "ds"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.DEEPSEEK));
162
163
  // Register NVIDIA NIM provider
163
164
  ProviderFactory.registerProvider(AIProviderName.NVIDIA_NIM, async (modelName, _providerName, sdk, _region, credentials) => {
164
165
  const nimCreds = credentials;
165
166
  const { NvidiaNimProvider } = await import("../providers/nvidiaNim/index.js");
166
167
  return new NvidiaNimProvider(modelName, sdk, undefined, nimCreds);
167
- }, process.env.NVIDIA_NIM_MODEL || NvidiaNimModels.LLAMA_3_3_70B_INSTRUCT, ["nvidia", "nim", "nvidia-nim"]);
168
+ }, process.env.NVIDIA_NIM_MODEL || NvidiaNimModels.LLAMA_3_3_70B_INSTRUCT, ["nvidia", "nim", "nvidia-nim"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.NVIDIA_NIM));
168
169
  // Register LM Studio provider (local)
169
170
  ProviderFactory.registerProvider(AIProviderName.LM_STUDIO, async (modelName, _providerName, sdk, _region, credentials) => {
170
171
  const lmStudioCreds = credentials;
171
172
  const { LMStudioProvider } = await import("../providers/lmStudio.js");
172
173
  return new LMStudioProvider(modelName, sdk, undefined, lmStudioCreds);
173
- }, process.env.LM_STUDIO_MODEL || undefined, ["lmstudio", "lm-studio", "lms"]);
174
+ }, process.env.LM_STUDIO_MODEL || undefined, ["lmstudio", "lm-studio", "lms"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.LM_STUDIO));
174
175
  // Register llama.cpp provider (local)
175
176
  ProviderFactory.registerProvider(AIProviderName.LLAMACPP, async (modelName, _providerName, sdk, _region, credentials) => {
176
177
  const llamaCppCreds = credentials;
177
178
  const { LlamaCppProvider } = await import("../providers/llamaCpp.js");
178
179
  return new LlamaCppProvider(modelName, sdk, undefined, llamaCppCreds);
179
- }, process.env.LLAMACPP_MODEL || undefined, ["llamacpp", "llama.cpp", "llama-cpp"]);
180
+ }, process.env.LLAMACPP_MODEL || undefined, ["llamacpp", "llama.cpp", "llama-cpp"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.LLAMACPP));
180
181
  // Register xAI Grok provider
181
182
  ProviderFactory.registerProvider(AIProviderName.XAI, async (modelName, _providerName, sdk, _region, credentials) => {
182
183
  const xaiCreds = credentials;
183
184
  const { XaiProvider } = await import("../providers/xai.js");
184
185
  return new XaiProvider(modelName, sdk, undefined, xaiCreds);
185
- }, process.env.XAI_MODEL || XaiModels.GROK_3, ["xai", "grok"]);
186
+ }, process.env.XAI_MODEL || XaiModels.GROK_3, ["xai", "grok"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.XAI));
186
187
  // Register Groq provider
187
188
  ProviderFactory.registerProvider(AIProviderName.GROQ, async (modelName, _providerName, sdk, _region, credentials) => {
188
189
  const groqCreds = credentials;
189
190
  const { GroqProvider } = await import("../providers/groq.js");
190
191
  return new GroqProvider(modelName, sdk, undefined, groqCreds);
191
- }, process.env.GROQ_MODEL || GroqModels.LLAMA_3_3_70B_VERSATILE, ["groq"]);
192
+ }, process.env.GROQ_MODEL || GroqModels.LLAMA_3_3_70B_VERSATILE, ["groq"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.GROQ));
192
193
  // Register Cohere provider
193
194
  ProviderFactory.registerProvider(AIProviderName.COHERE, async (modelName, _providerName, sdk, _region, credentials) => {
194
195
  const cohereCreds = credentials;
195
196
  const { CohereProvider } = await import("../providers/cohere.js");
196
197
  return new CohereProvider(modelName, sdk, undefined, cohereCreds);
197
- }, process.env.COHERE_MODEL || CohereModels.COMMAND_R_PLUS, ["cohere"]);
198
+ }, process.env.COHERE_MODEL || CohereModels.COMMAND_R_PLUS, ["cohere"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.COHERE));
198
199
  // Register Together AI provider
199
200
  ProviderFactory.registerProvider(AIProviderName.TOGETHER_AI, async (modelName, _providerName, sdk, _region, credentials) => {
200
201
  const togetherCreds = credentials;
201
202
  const { TogetherAIProvider } = await import("../providers/togetherAi.js");
202
203
  return new TogetherAIProvider(modelName, sdk, undefined, togetherCreds);
203
204
  }, process.env.TOGETHER_MODEL ||
204
- TogetherAIModels.LLAMA_3_3_70B_INSTRUCT_TURBO, ["together-ai", "together"]);
205
+ TogetherAIModels.LLAMA_3_3_70B_INSTRUCT_TURBO, ["together-ai", "together"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.TOGETHER_AI));
205
206
  // Register Fireworks AI provider
206
207
  ProviderFactory.registerProvider(AIProviderName.FIREWORKS, async (modelName, _providerName, sdk, _region, credentials) => {
207
208
  const fireworksCreds = credentials;
208
209
  const { FireworksProvider } = await import("../providers/fireworks.js");
209
210
  return new FireworksProvider(modelName, sdk, undefined, fireworksCreds);
210
- }, process.env.FIREWORKS_MODEL || FireworksModels.DEEPSEEK_V4_PRO, ["fireworks"]);
211
+ }, process.env.FIREWORKS_MODEL || FireworksModels.DEEPSEEK_V4_PRO, ["fireworks"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.FIREWORKS));
211
212
  // Register Perplexity provider
212
213
  ProviderFactory.registerProvider(AIProviderName.PERPLEXITY, async (modelName, _providerName, sdk, _region, credentials) => {
213
214
  const perplexityCreds = credentials;
214
215
  const { PerplexityProvider } = await import("../providers/perplexity.js");
215
216
  return new PerplexityProvider(modelName, sdk, undefined, perplexityCreds);
216
- }, process.env.PERPLEXITY_MODEL || PerplexityModels.SONAR, ["perplexity", "pplx"]);
217
+ }, process.env.PERPLEXITY_MODEL || PerplexityModels.SONAR, ["perplexity", "pplx"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.PERPLEXITY));
217
218
  // Register Cloudflare Workers AI provider
218
219
  ProviderFactory.registerProvider(AIProviderName.CLOUDFLARE, async (modelName, _providerName, sdk, _region, credentials) => {
219
220
  const cloudflareCreds = credentials;
220
221
  const { CloudflareProvider } = await import("../providers/cloudflare.js");
221
222
  return new CloudflareProvider(modelName, sdk, undefined, cloudflareCreds);
222
- }, process.env.CLOUDFLARE_MODEL || CloudflareModels.LLAMA_3_3_70B_FAST, ["cloudflare", "workers-ai", "cf-ai"]);
223
+ }, process.env.CLOUDFLARE_MODEL || CloudflareModels.LLAMA_3_3_70B_FAST, ["cloudflare", "workers-ai", "cf-ai"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.CLOUDFLARE));
223
224
  // Register Voyage AI embeddings provider
224
225
  ProviderFactory.registerProvider(AIProviderName.VOYAGE, async (modelName, _providerName, sdk, _region, credentials) => {
225
226
  const voyageCreds = credentials;
226
227
  const { VoyageProvider } = await import("../providers/voyage.js");
227
228
  return new VoyageProvider(modelName, sdk, undefined, voyageCreds);
228
- }, process.env.VOYAGE_MODEL || VoyageModels.VOYAGE_3_5, ["voyage", "voyage-ai"]);
229
+ }, process.env.VOYAGE_MODEL || VoyageModels.VOYAGE_3_5, ["voyage", "voyage-ai"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.VOYAGE));
229
230
  // Register Jina AI embeddings + reranking provider
230
231
  ProviderFactory.registerProvider(AIProviderName.JINA, async (modelName, _providerName, sdk, _region, credentials) => {
231
232
  const jinaCreds = credentials;
232
233
  const { JinaProvider } = await import("../providers/jina.js");
233
234
  return new JinaProvider(modelName, sdk, undefined, jinaCreds);
234
- }, process.env.JINA_MODEL || JinaModels.JINA_EMBEDDINGS_V3, ["jina", "jina-ai"]);
235
+ }, process.env.JINA_MODEL || JinaModels.JINA_EMBEDDINGS_V3, ["jina", "jina-ai"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.JINA));
235
236
  // Register Stability AI image-gen provider
236
237
  ProviderFactory.registerProvider(AIProviderName.STABILITY, async (modelName, _providerName, sdk, _region, credentials) => {
237
238
  const stabilityCreds = credentials;
238
239
  const { StabilityProvider } = await import("../providers/stability.js");
239
240
  return new StabilityProvider(modelName, sdk, undefined, stabilityCreds);
240
- }, process.env.STABILITY_MODEL || StabilityModels.STABLE_IMAGE_ULTRA, ["stability", "stability-ai", "sd"]);
241
+ }, process.env.STABILITY_MODEL || StabilityModels.STABLE_IMAGE_ULTRA, ["stability", "stability-ai", "sd"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.STABILITY));
241
242
  // Register Ideogram image-gen provider
242
243
  ProviderFactory.registerProvider(AIProviderName.IDEOGRAM, async (modelName, _providerName, sdk, _region, credentials) => {
243
244
  const ideogramCreds = credentials;
244
245
  const { IdeogramProvider } = await import("../providers/ideogram.js");
245
246
  return new IdeogramProvider(modelName, sdk, undefined, ideogramCreds);
246
- }, process.env.IDEOGRAM_MODEL || IdeogramModels.IDEOGRAM_V3, ["ideogram"]);
247
+ }, process.env.IDEOGRAM_MODEL || IdeogramModels.IDEOGRAM_V3, ["ideogram"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.IDEOGRAM));
247
248
  // Register Replicate LLM provider (multi-modal — also serves video /
248
249
  // avatar / music handlers via dedicated processors registered below)
249
250
  ProviderFactory.registerProvider(AIProviderName.REPLICATE, async (modelName, _providerName, sdk, _region, credentials) => {
250
251
  const replicateCreds = credentials;
251
252
  const { ReplicateProvider } = await import("../providers/replicate.js");
252
253
  return new ReplicateProvider(modelName, sdk, undefined, replicateCreds);
253
- }, process.env.REPLICATE_MODEL || ReplicateModels.LLAMA_3_70B_INSTRUCT, ["replicate"]);
254
+ }, process.env.REPLICATE_MODEL || ReplicateModels.LLAMA_3_70B_INSTRUCT, ["replicate"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.REPLICATE));
254
255
  // Register Recraft image-gen provider
255
256
  ProviderFactory.registerProvider(AIProviderName.RECRAFT, async (modelName, _providerName, sdk, _region, credentials) => {
256
257
  const recraftCreds = credentials;
257
258
  const { RecraftProvider } = await import("../providers/recraft.js");
258
259
  return new RecraftProvider(modelName, sdk, undefined, recraftCreds);
259
- }, process.env.RECRAFT_MODEL || RecraftModels.RECRAFT_V3, ["recraft"]);
260
+ }, process.env.RECRAFT_MODEL || RecraftModels.RECRAFT_V3, ["recraft"], PROVIDER_DESCRIPTORS_BY_NAME.get(AIProviderName.RECRAFT));
260
261
  logger.debug("All AI providers registered successfully");
261
262
  // ===== TTS HANDLER REGISTRATION =====
262
263
  try {
@@ -33,6 +33,8 @@
33
33
  */
34
34
  import { AIProviderFactory } from "./core/factory.js";
35
35
  export { AIProviderFactory };
36
+ export { ProviderFactory } from "./factories/providerFactory.js";
37
+ export { PROVIDER_DESCRIPTORS, PROVIDER_DESCRIPTORS_BY_NAME, PROVIDER_ALIAS_INDEX, } from "./factories/providerDescriptors.js";
36
38
  export { NeuroLinkConfigManager as ConfigManager } from "./config/configManager.js";
37
39
  export { BaseFactory, BaseRegistry, NeuroLinkFeatureError, createErrorFactory, withRetry, TypedEventEmitter, } from "./core/infrastructure/index.js";
38
40
  export { NeuroLinkClient, createClient, NeuroLinkApiError, } from "./client/httpClient.js";
@@ -396,7 +398,14 @@ export { classifyProviderError, ModelPool, createDefaultRequestRouter, Classifie
396
398
  * await server.start();
397
399
  * ```
398
400
  */
399
- export { AgentExecuteRequestSchema, AlreadyRunningError, AuthenticationError, AuthorizationError, BaseServerAdapter, ConfigurationError, createAgentRoutes, createAgentWebSocketHandler, createAllRoutes, createAuthMiddleware, createCacheInvalidator, createCacheMiddleware, createCompressionMiddleware, createDataStreamResponse, createDataStreamWriter, createErrorHandlingMiddleware, createErrorResponse, createFieldValidator, createHealthRoutes, createLoggingMiddleware, createMCPRoutes, createMemoryRoutes, createNDJSONHeaders, createOpenAPIGenerator, createRateLimitMiddleware, createRequestIdMiddleware, createRequestValidationMiddleware, createRoleMiddleware, createSecurityHeadersMiddleware, createServer, createSlidingWindowRateLimitMiddleware, createSSEHeaders, createTimingMiddleware, createToolRoutes, ErrorCategory, ErrorRecoveryStrategies, ErrorSeverity, ExpressServerAdapter, FastifyServerAdapter, generateOpenAPIFromConfig, generateOpenAPISpec, HandlerError, HonoServerAdapter, InMemoryCacheStore, InMemoryRateLimitStore, InvalidAuthenticationError, KoaServerAdapter, MissingDependencyError, NotRunningError, pipeAsyncIterableToDataStream, RateLimitError, RouteConflictError, RouteNotFoundError, registerAllRoutes, ServerAdapterError, ServerAdapterErrorCode, ServerAdapterFactory, ServerNameParamSchema, ServerRateLimitError, ServerStartError, ServerStopError, ServerValidationError, SessionIdParamSchema, StreamAbortedError, StreamingError, TimeoutError, ToolArgumentsSchema, ToolExecuteRequestSchema, ToolNameParamSchema, ToolSearchQuerySchema, ValidationError, validateParams, validateQuery, validateRequest, WebSocketConnectionError, WebSocketConnectionManager, WebSocketError, WebSocketMessageRouter, wrapError, } from "./server/index.js";
401
+ export { AgentExecuteRequestSchema, AlreadyRunningError, BaseServerAdapter, ConfigurationError, createAgentRoutes, createAgentWebSocketHandler, createAllRoutes, createAuthMiddleware, createCacheInvalidator, createCacheMiddleware, createCompressionMiddleware, createDataStreamResponse, createDataStreamWriter, createErrorHandlingMiddleware, createErrorResponse, createFieldValidator, createHealthRoutes, createLoggingMiddleware, createMCPRoutes, createMemoryRoutes, createNDJSONHeaders, createOpenAPIGenerator, createRateLimitMiddleware, createRequestIdMiddleware, createRequestValidationMiddleware, createRoleMiddleware, createSecurityHeadersMiddleware, createServer, createSlidingWindowRateLimitMiddleware, createSSEHeaders, createTimingMiddleware, createToolRoutes, ErrorCategory, ErrorRecoveryStrategies, ErrorSeverity, ExpressServerAdapter, FastifyServerAdapter, generateOpenAPIFromConfig, generateOpenAPISpec, HandlerError, HonoServerAdapter, InMemoryCacheStore, InMemoryRateLimitStore, InvalidAuthenticationError, KoaServerAdapter, MissingDependencyError, NotRunningError, pipeAsyncIterableToDataStream, RouteConflictError, RouteNotFoundError, registerAllRoutes, ServerAdapterError, ServerAdapterErrorCode, ServerAdapterFactory, ServerAuthenticationError, ServerAuthorizationError, ServerNameParamSchema, ServerRateLimitError, ServerStartError, ServerStopError, ServerTimeoutError, ServerValidationError, SessionIdParamSchema, StreamAbortedError, StreamingError, ToolArgumentsSchema, ToolExecuteRequestSchema, ToolNameParamSchema, ToolSearchQuerySchema, ValidationError, validateParams, validateQuery, validateRequest, WebSocketConnectionError, WebSocketConnectionManager, WebSocketError, WebSocketMessageRouter, wrapError, } from "./server/index.js";
402
+ /**
403
+ * @deprecated Use `ServerTimeoutError` instead — renamed to end the naming
404
+ * collision with the canonical `utils/timeout.ts` `TimeoutError`. Kept as an
405
+ * alias so existing callers importing `TimeoutError` from `@juspay/neurolink`
406
+ * are not broken.
407
+ */
408
+ export { ServerTimeoutError as TimeoutError } from "./server/index.js";
400
409
  /**
401
410
  * RAG (Retrieval-Augmented Generation) Document Processing
402
411
  *
package/dist/lib/index.js CHANGED
@@ -34,6 +34,9 @@
34
34
  // Core exports
35
35
  import { AIProviderFactory } from "./core/factory.js";
36
36
  export { AIProviderFactory };
37
+ // Provider descriptor exports (single source of truth for provider identity)
38
+ export { ProviderFactory } from "./factories/providerFactory.js";
39
+ export { PROVIDER_DESCRIPTORS, PROVIDER_DESCRIPTORS_BY_NAME, PROVIDER_ALIAS_INDEX, } from "./factories/providerDescriptors.js";
37
40
  // Config Manager export
38
41
  export { NeuroLinkConfigManager as ConfigManager } from "./config/configManager.js";
39
42
  // Core Infrastructure exports (factory + registry patterns)
@@ -613,7 +616,7 @@ export { classifyProviderError, ModelPool, createDefaultRequestRouter, Classifie
613
616
  */
614
617
  export {
615
618
  // Validation
616
- AgentExecuteRequestSchema, AlreadyRunningError, AuthenticationError, AuthorizationError,
619
+ AgentExecuteRequestSchema, AlreadyRunningError,
617
620
  // Framework Adapters
618
621
  BaseServerAdapter, ConfigurationError,
619
622
  // Routes
@@ -627,11 +630,18 @@ createServer, createSlidingWindowRateLimitMiddleware, createSSEHeaders, createTi
627
630
  // Error Constants
628
631
  ErrorCategory, ErrorRecoveryStrategies, ErrorSeverity, ExpressServerAdapter, FastifyServerAdapter, generateOpenAPIFromConfig, generateOpenAPISpec, HandlerError, HonoServerAdapter, InMemoryCacheStore, InMemoryRateLimitStore, InvalidAuthenticationError, KoaServerAdapter, MissingDependencyError, NotRunningError,
629
632
  // OpenAPI
630
- pipeAsyncIterableToDataStream, RateLimitError, RouteConflictError, RouteNotFoundError, registerAllRoutes,
633
+ pipeAsyncIterableToDataStream, RouteConflictError, RouteNotFoundError, registerAllRoutes,
631
634
  // Errors
632
- ServerAdapterError, ServerAdapterErrorCode, ServerAdapterFactory, ServerNameParamSchema, ServerRateLimitError, ServerStartError, ServerStopError, ServerValidationError, SessionIdParamSchema, StreamAbortedError, StreamingError, TimeoutError, ToolArgumentsSchema, ToolExecuteRequestSchema, ToolNameParamSchema, ToolSearchQuerySchema, ValidationError, validateParams, validateQuery, validateRequest, WebSocketConnectionError,
635
+ ServerAdapterError, ServerAdapterErrorCode, ServerAdapterFactory, ServerAuthenticationError, ServerAuthorizationError, ServerNameParamSchema, ServerRateLimitError, ServerStartError, ServerStopError, ServerTimeoutError, ServerValidationError, SessionIdParamSchema, StreamAbortedError, StreamingError, ToolArgumentsSchema, ToolExecuteRequestSchema, ToolNameParamSchema, ToolSearchQuerySchema, ValidationError, validateParams, validateQuery, validateRequest, WebSocketConnectionError,
633
636
  // WebSocket
634
637
  WebSocketConnectionManager, WebSocketError, WebSocketMessageRouter, wrapError, } from "./server/index.js";
638
+ /**
639
+ * @deprecated Use `ServerTimeoutError` instead — renamed to end the naming
640
+ * collision with the canonical `utils/timeout.ts` `TimeoutError`. Kept as an
641
+ * alias so existing callers importing `TimeoutError` from `@juspay/neurolink`
642
+ * are not broken.
643
+ */
644
+ export { ServerTimeoutError as TimeoutError } from "./server/index.js";
635
645
  // ============================================================================
636
646
  // RAG DOCUMENT PROCESSING - Retrieval-Augmented Generation
637
647
  // ============================================================================
@@ -35,6 +35,7 @@ import { ToolRoutingCache } from "./core/toolRoutingCache.js";
35
35
  import { DEFAULT_RECENT_TURNS, KnowledgeGroundingEngine, } from "./knowledge/index.js";
36
36
  import { AIProviderFactory } from "./core/factory.js";
37
37
  import { createToolEventPayload } from "./core/toolEvents.js";
38
+ import { ProviderFactory } from "./factories/providerFactory.js";
38
39
  import { ProviderRegistry } from "./factories/providerRegistry.js";
39
40
  import { FileReferenceRegistry } from "./files/fileReferenceRegistry.js";
40
41
  import { createFileTools } from "./files/fileTools.js";
@@ -298,30 +299,24 @@ export function markStreamProviderEmittedGenerationEnd(options) {
298
299
  */
299
300
  export const NEUROLINK_BRAND = Symbol.for("@juspay/neurolink/sdk-brand");
300
301
  /**
301
- * Providers whose native tool-calling support is model-dependent or absent
302
- * i.e. every provider that overrides `supportsTools()` and can return false
303
- * (verified against src/lib/providers: ollama and openrouter are
304
- * model-dependent; huggingface is deployment-dependent; the rest are
305
- * image/embedding providers). Only these still receive the full tool listing
306
- * in the system prompt on the generate path, where no provider instance
307
- * exists yet to ask directly; every other provider gets tool definitions
308
- * natively via its `tools` parameter, so repeating them in the prompt was
309
- * pure token duplication. The stream path asks the provider instance
310
- * (`provider.supportsTools()`) instead of this list. BaseProvider resolves its
311
- * default through MODEL_REGISTRY's `modelSupports()` facade; keep this list in
312
- * sync with provider-specific `supportsTools()` overrides when adding providers.
302
+ * True when a provider needs tools described in the prompt rather than
303
+ * passed via the API's native tool-calling parameter (ollama/openrouter
304
+ * are model-dependent; huggingface is deployment-dependent; the
305
+ * image/embedding providers don't support tool calling at all). Only these
306
+ * still receive the full tool listing in the system prompt on the generate
307
+ * path, where no provider instance exists yet to ask directly; every other
308
+ * provider gets tool definitions natively via its `tools` parameter, so
309
+ * repeating them in the prompt was pure token duplication. The stream path
310
+ * asks the provider instance (`provider.supportsTools()`) instead of this
311
+ * check. Derived from ProviderDescriptor.toolSupport instead of a
312
+ * hand-maintained Set see PROVIDER_DESCRIPTORS in
313
+ * src/lib/factories/providerDescriptors.ts for the underlying data;
314
+ * BaseProvider resolves its own runtime default through MODEL_REGISTRY's
315
+ * `modelSupports()` facade.
313
316
  */
314
- const PROMPT_ONLY_TOOL_PROVIDERS = new Set([
315
- "ollama",
316
- "huggingface",
317
- "openrouter",
318
- "ideogram",
319
- "recraft",
320
- "replicate",
321
- "stability",
322
- "jina",
323
- "voyage",
324
- ]);
317
+ function isPromptOnlyToolProvider(providerName) {
318
+ return ProviderFactory.getDescriptor(providerName)?.toolSupport !== "native";
319
+ }
325
320
  /**
326
321
  * Type-guard for opaque values that should be a {@link NeuroLink} instance.
327
322
  *
@@ -5452,7 +5447,7 @@ Current user's request: ${currentInput}`;
5452
5447
  }
5453
5448
  // Providers with native tool calling receive full definitions via their
5454
5449
  // `tools` parameter; only prompt-based providers still get the listing.
5455
- const nativeToolSupport = !PROMPT_ONLY_TOOL_PROVIDERS.has(String(providerName).toLowerCase());
5450
+ const nativeToolSupport = !isPromptOnlyToolProvider(String(providerName).toLowerCase());
5456
5451
  const enhancedSystemPrompt = options.skipToolPromptInjection
5457
5452
  ? (options.systemPrompt || "") + circuitBreakerNote
5458
5453
  : this.createToolAwareSystemPrompt(options.systemPrompt, availableTools, nativeToolSupport) + circuitBreakerNote;
@@ -10351,19 +10346,12 @@ Current user's request: ${currentInput}`;
10351
10346
  // Keep references to prevent unused variable warnings
10352
10347
  void AIProviderFactory;
10353
10348
  void hasProviderEnvVars;
10354
- const providers = [
10355
- "openai",
10356
- "bedrock",
10357
- "vertex",
10358
- "googleVertex",
10359
- "anthropic",
10360
- "azure",
10361
- "google-ai",
10362
- "huggingface",
10363
- "ollama",
10364
- "mistral",
10365
- "litellm",
10366
- ];
10349
+ // Derived from the descriptor registry instead of a hand-maintained
10350
+ // list — covers all real providers (was previously hardcoded to 11,
10351
+ // including "googleVertex" as a duplicate entry alongside "vertex";
10352
+ // that alias remains resolvable via PROVIDER_ALIAS_INDEX/CLI choices,
10353
+ // it just no longer gets its own separate status-check entry).
10354
+ const providers = ProviderFactory.getAllDescriptors().map((d) => d.name);
10367
10355
  // Test providers with controlled concurrency
10368
10356
  // This reduces total time from 16s (sequential) to ~3s (parallel) while preventing resource exhaustion
10369
10357
  const limit = pLimit(SYSTEM_LIMITS.DEFAULT_CONCURRENCY_LIMIT);
@@ -4,6 +4,7 @@ import { createAnalytics } from "../../core/analytics.js";
4
4
  import { BaseProvider } from "../../core/baseProvider.js";
5
5
  import { DEFAULT_MAX_STEPS } from "../../core/constants.js";
6
6
  import { AuthenticationError, ProviderError, RateLimitError, } from "../../types/index.js";
7
+ import { classifyProviderError } from "../../utils/errorClassifier.js";
7
8
  import { isAbortError, withTimeout } from "../../utils/errorHandling.js";
8
9
  import { emitToolEndFromStepFinish } from "../../utils/toolEndEmitter.js";
9
10
  import { logger } from "../../utils/logger.js";
@@ -1724,22 +1725,39 @@ export class AmazonBedrockProvider extends BaseProvider {
1724
1725
  }
1725
1726
  }
1726
1727
  formatProviderError(error) {
1727
- // Handle AWS SDK specific errors
1728
- const message = error instanceof Error ? error.message : String(error);
1729
- if (message.includes("AccessDeniedException")) {
1730
- return new AuthenticationError("AWS Bedrock access denied. Check your credentials and permissions.", this.providerName);
1731
- }
1732
- if (message.includes("ValidationException")) {
1733
- return new ProviderError(`Validation error: ${message}`, this.providerName);
1734
- }
1735
- // Check for AWS-specific throttling BEFORE generic mapping
1736
- const errName = error?.name ?? "";
1737
- const errCode = error?.code ?? "";
1738
- if (errName === "ThrottlingException" ||
1739
- errCode === "ThrottlingException") {
1740
- return new RateLimitError(`Bedrock rate limit (throttled): ${error instanceof Error ? error.message : String(error)}`, "bedrock");
1741
- }
1742
- return new ProviderError(`AWS Bedrock error: ${message}`, this.providerName);
1728
+ const rules = [
1729
+ {
1730
+ match: (ctx) => /AccessDeniedException/i.test(ctx.message),
1731
+ errorClass: AuthenticationError,
1732
+ message: "AWS Bedrock access denied. Check your credentials and permissions.",
1733
+ },
1734
+ {
1735
+ // Checked before the generic ValidationException fallback — a
1736
+ // throttling error can be shaped like a validation error in some
1737
+ // AWS SDK error message templates, but .name/.code are authoritative.
1738
+ match: (ctx) => ctx.errorName === "ThrottlingException" ||
1739
+ ctx.errorCode === "ThrottlingException",
1740
+ errorClass: RateLimitError,
1741
+ message: (ctx) => `Bedrock rate limit (throttled): ${ctx.message}`,
1742
+ },
1743
+ {
1744
+ match: (ctx) => /ValidationException/i.test(ctx.message),
1745
+ errorClass: ProviderError,
1746
+ message: (ctx) => `Validation error: ${ctx.message}`,
1747
+ },
1748
+ {
1749
+ match: () => true,
1750
+ errorClass: ProviderError,
1751
+ message: (ctx) => `AWS Bedrock error: ${ctx.message}`,
1752
+ },
1753
+ ];
1754
+ // this.providerName resolves to the literal "bedrock" (getProviderName()
1755
+ // returns it directly, and the constructor only overrides providerName
1756
+ // when an explicit providerName is passed in) — verified matches the
1757
+ // pre-migration hardcoded "bedrock" literal in the throttling branch, so
1758
+ // a single classifyProviderError call using this.providerName for every
1759
+ // rule (rather than a per-rule literal) is not a behavior change.
1760
+ return classifyProviderError(error, rules, this.providerName, this.modelName);
1743
1761
  }
1744
1762
  /**
1745
1763
  * Generate embeddings for text using Amazon Bedrock embedding models