@juspay/neurolink 10.12.9 → 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 (241) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/dist/browser/neurolink.min.js +504 -506
  3. package/dist/cli/commands/setup.d.ts +20 -1
  4. package/dist/cli/commands/setup.js +160 -36
  5. package/dist/cli/factories/commandFactory.d.ts +1157 -1
  6. package/dist/cli/factories/commandFactory.js +20 -53
  7. package/dist/core/baseProvider.js +3 -3
  8. package/dist/core/dynamicModels.d.ts +1 -1
  9. package/dist/core/dynamicModels.js +1 -23
  10. package/dist/core/modelConfiguration.d.ts +1 -70
  11. package/dist/core/modelConfiguration.js +0 -303
  12. package/dist/core/modules/GenerationHandler.js +2 -2
  13. package/dist/core/modules/structuredOutputPolicy.d.ts +2 -2
  14. package/dist/core/modules/structuredOutputPolicy.js +2 -2
  15. package/dist/factories/providerDescriptors.d.ts +18 -0
  16. package/dist/factories/providerDescriptors.js +536 -0
  17. package/dist/factories/providerFactory.d.ts +28 -2
  18. package/dist/factories/providerFactory.js +53 -42
  19. package/dist/factories/providerRegistry.js +33 -32
  20. package/dist/index.d.ts +10 -1
  21. package/dist/index.js +13 -3
  22. package/dist/lib/core/baseProvider.js +3 -3
  23. package/dist/lib/core/dynamicModels.d.ts +1 -1
  24. package/dist/lib/core/dynamicModels.js +1 -23
  25. package/dist/lib/core/modelConfiguration.d.ts +1 -70
  26. package/dist/lib/core/modelConfiguration.js +0 -303
  27. package/dist/lib/core/modules/GenerationHandler.js +2 -2
  28. package/dist/lib/core/modules/structuredOutputPolicy.d.ts +2 -2
  29. package/dist/lib/core/modules/structuredOutputPolicy.js +2 -2
  30. package/dist/lib/factories/providerDescriptors.d.ts +18 -0
  31. package/dist/lib/factories/providerDescriptors.js +537 -0
  32. package/dist/lib/factories/providerFactory.d.ts +28 -2
  33. package/dist/lib/factories/providerFactory.js +53 -42
  34. package/dist/lib/factories/providerRegistry.js +33 -32
  35. package/dist/lib/index.d.ts +10 -1
  36. package/dist/lib/index.js +13 -3
  37. package/dist/lib/models/anthropicModels.d.ts +0 -7
  38. package/dist/lib/models/anthropicModels.js +0 -9
  39. package/dist/lib/neurolink.js +25 -37
  40. package/dist/lib/providers/amazonBedrock/client.js +34 -16
  41. package/dist/lib/providers/anthropic/client.js +39 -34
  42. package/dist/lib/providers/anthropic/constants.d.ts +0 -1
  43. package/dist/lib/providers/anthropic/constants.js +0 -2
  44. package/dist/lib/providers/anthropic/index.d.ts +0 -1
  45. package/dist/lib/providers/anthropic/index.js +0 -1
  46. package/dist/lib/providers/azureOpenai.js +17 -15
  47. package/dist/lib/providers/cloudflare.js +12 -21
  48. package/dist/lib/providers/cohere.js +31 -25
  49. package/dist/lib/providers/deepseek.js +23 -26
  50. package/dist/lib/providers/fireworks.js +12 -21
  51. package/dist/lib/providers/googleAiStudio/client.d.ts +2 -0
  52. package/dist/lib/providers/googleAiStudio/client.js +39 -17
  53. package/dist/lib/providers/googleAiStudio/index.d.ts +0 -1
  54. package/dist/lib/providers/googleAiStudio/index.js +0 -1
  55. package/dist/lib/providers/googleNativeGemini3/index.d.ts +0 -1
  56. package/dist/lib/providers/googleNativeGemini3/index.js +0 -1
  57. package/dist/lib/providers/googleVertex/client.d.ts +0 -51
  58. package/dist/lib/providers/googleVertex/client.js +107 -777
  59. package/dist/lib/providers/groq.js +19 -22
  60. package/dist/lib/providers/huggingFace/client.d.ts +1 -1
  61. package/dist/lib/providers/huggingFace/client.js +27 -25
  62. package/dist/lib/providers/huggingFace/index.d.ts +0 -1
  63. package/dist/lib/providers/huggingFace/index.js +0 -1
  64. package/dist/lib/providers/jina.d.ts +0 -1
  65. package/dist/lib/providers/jina.js +0 -1
  66. package/dist/lib/providers/litellm/client.js +54 -39
  67. package/dist/lib/providers/litellm/index.d.ts +0 -2
  68. package/dist/lib/providers/litellm/index.js +0 -2
  69. package/dist/lib/providers/llamaCpp.d.ts +1 -0
  70. package/dist/lib/providers/llamaCpp.js +24 -18
  71. package/dist/lib/providers/lmStudio.js +25 -42
  72. package/dist/lib/providers/mistral.js +12 -24
  73. package/dist/lib/providers/nvidiaNim/client.js +37 -34
  74. package/dist/lib/providers/nvidiaNim/index.d.ts +0 -1
  75. package/dist/lib/providers/nvidiaNim/index.js +0 -1
  76. package/dist/lib/providers/ollama/client.js +51 -58
  77. package/dist/lib/providers/ollama/index.d.ts +0 -1
  78. package/dist/lib/providers/ollama/index.js +0 -1
  79. package/dist/lib/providers/openAI/client.js +37 -40
  80. package/dist/lib/providers/openAI/index.d.ts +0 -2
  81. package/dist/lib/providers/openAI/index.js +0 -2
  82. package/dist/lib/providers/openRouter/client.js +53 -47
  83. package/dist/lib/providers/openRouter/utils.d.ts +0 -2
  84. package/dist/lib/providers/openRouter/utils.js +0 -12
  85. package/dist/lib/providers/openaiChatCompletionsBase.d.ts +9 -0
  86. package/dist/lib/providers/openaiChatCompletionsBase.js +73 -16
  87. package/dist/lib/providers/openaiCompatible/client.js +36 -32
  88. package/dist/lib/providers/perplexity.d.ts +2 -1
  89. package/dist/lib/providers/perplexity.js +14 -22
  90. package/dist/lib/providers/replicate.d.ts +0 -1
  91. package/dist/lib/providers/replicate.js +22 -9
  92. package/dist/lib/providers/togetherAi.js +12 -21
  93. package/dist/lib/providers/voyage.d.ts +0 -1
  94. package/dist/lib/providers/voyage.js +0 -1
  95. package/dist/lib/providers/xai.js +17 -26
  96. package/dist/lib/server/errors.d.ts +1 -1
  97. package/dist/lib/server/errors.js +2 -2
  98. package/dist/lib/server/index.d.ts +2 -2
  99. package/dist/lib/server/index.js +5 -3
  100. package/dist/lib/server/middleware/rateLimit.d.ts +0 -4
  101. package/dist/lib/server/middleware/rateLimit.js +0 -4
  102. package/dist/lib/types/errors.d.ts +35 -0
  103. package/dist/lib/types/index.d.ts +0 -1
  104. package/dist/lib/types/index.js +0 -1
  105. package/dist/lib/types/providers.d.ts +66 -11
  106. package/dist/lib/utils/errorClassifier.d.ts +30 -0
  107. package/dist/lib/utils/errorClassifier.js +94 -0
  108. package/dist/lib/utils/fileDetector.js +6 -43
  109. package/dist/lib/utils/providerConfig.d.ts +0 -8
  110. package/dist/lib/utils/providerConfig.js +0 -37
  111. package/dist/lib/utils/providerHealth.d.ts +42 -7
  112. package/dist/lib/utils/providerHealth.js +115 -122
  113. package/dist/lib/utils/providerUtils.js +21 -87
  114. package/dist/models/anthropicModels.d.ts +0 -7
  115. package/dist/models/anthropicModels.js +0 -9
  116. package/dist/neurolink.js +25 -37
  117. package/dist/providers/amazonBedrock/client.js +34 -16
  118. package/dist/providers/amazonSagemaker.d.ts +1 -1
  119. package/dist/providers/anthropic/client.js +39 -34
  120. package/dist/providers/anthropic/constants.d.ts +0 -1
  121. package/dist/providers/anthropic/constants.js +0 -2
  122. package/dist/providers/anthropic/index.d.ts +0 -1
  123. package/dist/providers/anthropic/index.js +0 -1
  124. package/dist/providers/azureOpenai.js +17 -15
  125. package/dist/providers/cloudflare.js +12 -21
  126. package/dist/providers/cohere.js +31 -25
  127. package/dist/providers/deepseek.js +23 -26
  128. package/dist/providers/fireworks.js +12 -21
  129. package/dist/providers/googleAiStudio/client.d.ts +2 -0
  130. package/dist/providers/googleAiStudio/client.js +39 -17
  131. package/dist/providers/googleAiStudio/index.d.ts +0 -1
  132. package/dist/providers/googleAiStudio/index.js +0 -1
  133. package/dist/providers/googleNativeGemini3/index.d.ts +0 -1
  134. package/dist/providers/googleNativeGemini3/index.js +0 -1
  135. package/dist/providers/googleVertex/client.d.ts +0 -51
  136. package/dist/providers/googleVertex/client.js +107 -777
  137. package/dist/providers/groq.js +19 -22
  138. package/dist/providers/huggingFace/client.d.ts +1 -1
  139. package/dist/providers/huggingFace/client.js +27 -25
  140. package/dist/providers/huggingFace/index.d.ts +0 -1
  141. package/dist/providers/huggingFace/index.js +0 -1
  142. package/dist/providers/jina.d.ts +0 -1
  143. package/dist/providers/jina.js +0 -1
  144. package/dist/providers/litellm/client.js +54 -39
  145. package/dist/providers/litellm/index.d.ts +0 -2
  146. package/dist/providers/litellm/index.js +0 -2
  147. package/dist/providers/llamaCpp.d.ts +1 -0
  148. package/dist/providers/llamaCpp.js +24 -18
  149. package/dist/providers/lmStudio.js +25 -42
  150. package/dist/providers/mistral.js +12 -24
  151. package/dist/providers/nvidiaNim/client.js +37 -34
  152. package/dist/providers/nvidiaNim/index.d.ts +0 -1
  153. package/dist/providers/nvidiaNim/index.js +0 -1
  154. package/dist/providers/ollama/client.js +51 -58
  155. package/dist/providers/ollama/index.d.ts +0 -1
  156. package/dist/providers/ollama/index.js +0 -1
  157. package/dist/providers/openAI/client.js +37 -40
  158. package/dist/providers/openAI/index.d.ts +0 -2
  159. package/dist/providers/openAI/index.js +0 -2
  160. package/dist/providers/openRouter/client.js +53 -47
  161. package/dist/providers/openRouter/utils.d.ts +0 -2
  162. package/dist/providers/openRouter/utils.js +0 -12
  163. package/dist/providers/openaiChatCompletionsBase.d.ts +9 -0
  164. package/dist/providers/openaiChatCompletionsBase.js +73 -16
  165. package/dist/providers/openaiCompatible/client.js +36 -32
  166. package/dist/providers/perplexity.d.ts +2 -1
  167. package/dist/providers/perplexity.js +14 -22
  168. package/dist/providers/replicate.d.ts +0 -1
  169. package/dist/providers/replicate.js +22 -9
  170. package/dist/providers/sagemaker/language-model.d.ts +2 -2
  171. package/dist/providers/togetherAi.js +12 -21
  172. package/dist/providers/voyage.d.ts +0 -1
  173. package/dist/providers/voyage.js +0 -1
  174. package/dist/providers/xai.js +17 -26
  175. package/dist/server/errors.d.ts +1 -1
  176. package/dist/server/errors.js +2 -2
  177. package/dist/server/index.d.ts +2 -2
  178. package/dist/server/index.js +5 -3
  179. package/dist/server/middleware/rateLimit.d.ts +0 -4
  180. package/dist/server/middleware/rateLimit.js +0 -4
  181. package/dist/types/errors.d.ts +35 -0
  182. package/dist/types/index.d.ts +0 -1
  183. package/dist/types/index.js +0 -1
  184. package/dist/types/providers.d.ts +66 -11
  185. package/dist/utils/errorClassifier.d.ts +30 -0
  186. package/dist/utils/errorClassifier.js +93 -0
  187. package/dist/utils/fileDetector.js +6 -43
  188. package/dist/utils/providerConfig.d.ts +0 -8
  189. package/dist/utils/providerConfig.js +0 -37
  190. package/dist/utils/providerHealth.d.ts +42 -7
  191. package/dist/utils/providerHealth.js +115 -122
  192. package/dist/utils/providerUtils.js +21 -87
  193. package/package.json +21 -75
  194. package/dist/lib/providers/anthropic/utils.d.ts +0 -7
  195. package/dist/lib/providers/anthropic/utils.js +0 -150
  196. package/dist/lib/providers/googleAiStudio/utils.d.ts +0 -2
  197. package/dist/lib/providers/googleAiStudio/utils.js +0 -19
  198. package/dist/lib/providers/googleNativeGemini3/constants.d.ts +0 -1
  199. package/dist/lib/providers/googleNativeGemini3/constants.js +0 -2
  200. package/dist/lib/providers/huggingFace/utils.d.ts +0 -2
  201. package/dist/lib/providers/huggingFace/utils.js +0 -8
  202. package/dist/lib/providers/index.d.ts +0 -33
  203. package/dist/lib/providers/index.js +0 -34
  204. package/dist/lib/providers/litellm/constants.d.ts +0 -1
  205. package/dist/lib/providers/litellm/constants.js +0 -3
  206. package/dist/lib/providers/litellm/utils.d.ts +0 -5
  207. package/dist/lib/providers/litellm/utils.js +0 -11
  208. package/dist/lib/providers/nvidiaNim/utils.d.ts +0 -9
  209. package/dist/lib/providers/nvidiaNim/utils.js +0 -101
  210. package/dist/lib/providers/ollama/utils.d.ts +0 -8
  211. package/dist/lib/providers/ollama/utils.js +0 -43
  212. package/dist/lib/providers/openAI/constants.d.ts +0 -1
  213. package/dist/lib/providers/openAI/constants.js +0 -3
  214. package/dist/lib/providers/openAI/utils.d.ts +0 -2
  215. package/dist/lib/providers/openAI/utils.js +0 -8
  216. package/dist/lib/types/universalProviderOptions.d.ts +0 -89
  217. package/dist/lib/types/universalProviderOptions.js +0 -55
  218. package/dist/providers/anthropic/utils.d.ts +0 -7
  219. package/dist/providers/anthropic/utils.js +0 -149
  220. package/dist/providers/googleAiStudio/utils.d.ts +0 -2
  221. package/dist/providers/googleAiStudio/utils.js +0 -18
  222. package/dist/providers/googleNativeGemini3/constants.d.ts +0 -1
  223. package/dist/providers/googleNativeGemini3/constants.js +0 -1
  224. package/dist/providers/huggingFace/utils.d.ts +0 -2
  225. package/dist/providers/huggingFace/utils.js +0 -7
  226. package/dist/providers/index.d.ts +0 -33
  227. package/dist/providers/index.js +0 -33
  228. package/dist/providers/litellm/constants.d.ts +0 -1
  229. package/dist/providers/litellm/constants.js +0 -2
  230. package/dist/providers/litellm/utils.d.ts +0 -5
  231. package/dist/providers/litellm/utils.js +0 -10
  232. package/dist/providers/nvidiaNim/utils.d.ts +0 -9
  233. package/dist/providers/nvidiaNim/utils.js +0 -100
  234. package/dist/providers/ollama/utils.d.ts +0 -8
  235. package/dist/providers/ollama/utils.js +0 -42
  236. package/dist/providers/openAI/constants.d.ts +0 -1
  237. package/dist/providers/openAI/constants.js +0 -2
  238. package/dist/providers/openAI/utils.d.ts +0 -2
  239. package/dist/providers/openAI/utils.js +0 -7
  240. package/dist/types/universalProviderOptions.d.ts +0 -89
  241. package/dist/types/universalProviderOptions.js +0 -54
@@ -1,7 +1,8 @@
1
1
  import { GroqModels } from "../constants/enums.js";
2
- import { AuthenticationError, InvalidModelError, ProviderError, RateLimitError, } from "../types/index.js";
2
+ import { AuthenticationError, InvalidModelError, ProviderError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
4
  import { redactUrlCredentials } from "../utils/logSanitize.js";
5
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../utils/errorClassifier.js";
5
6
  import { createGroqConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
6
7
  import { TimeoutError } from "../utils/timeout.js";
7
8
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -57,29 +58,25 @@ export class GroqProvider extends OpenAIChatCompletionsProvider {
57
58
  ];
58
59
  }
59
60
  formatProviderError(error) {
61
+ // Groq's TimeoutError maps to plain ProviderError (not NetworkError, the
62
+ // classifier's built-in default) — intercept before delegating.
60
63
  if (error instanceof TimeoutError) {
61
64
  return new ProviderError(`Groq request timed out: ${error.message}`, "groq");
62
65
  }
63
- const errorRecord = error;
64
- const message = typeof errorRecord?.message === "string"
65
- ? errorRecord.message
66
- : "Unknown error";
67
- if (message.includes("Invalid API key") ||
68
- message.includes("Authentication") ||
69
- message.includes("401") ||
70
- message.includes("invalid_api_key")) {
71
- return new AuthenticationError("Invalid Groq API key. Check GROQ_API_KEY. Get one at https://console.groq.com/keys", "groq");
72
- }
73
- if (message.includes("rate limit") || message.includes("429")) {
74
- return new RateLimitError("Groq rate limit exceeded. Free tier limits are tight; consider upgrading or backing off.", "groq");
75
- }
76
- if (message.includes("model_not_found") ||
77
- message.includes("404") ||
78
- message.includes("model_decommissioned")) {
79
- return new InvalidModelError(message.includes("model_decommissioned")
80
- ? `Groq model '${this.modelName}' was decommissioned. Pick a current model from https://console.groq.com/docs/models.`
81
- : `Groq model '${this.modelName}' not found. See https://console.groq.com/docs/models for the current catalog.`, "groq");
82
- }
83
- return new ProviderError(`Groq error: ${message}`, "groq");
66
+ const rules = [
67
+ {
68
+ match: (ctx) => ctx.statusCode === 401 ||
69
+ /Invalid API key|Authentication|invalid_api_key/i.test(ctx.message),
70
+ errorClass: AuthenticationError,
71
+ message: "Invalid Groq API key. Check GROQ_API_KEY. Get one at https://console.groq.com/keys",
72
+ },
73
+ {
74
+ match: (ctx) => /model_decommissioned/i.test(ctx.message),
75
+ errorClass: InvalidModelError,
76
+ message: (ctx) => `Groq model '${ctx.modelName}' was decommissioned. Pick a current model from https://console.groq.com/docs/models.`,
77
+ },
78
+ ...DEFAULT_ERROR_RULES,
79
+ ];
80
+ return classifyProviderError(error, rules, "groq", this.modelName);
84
81
  }
85
82
  }
@@ -14,7 +14,7 @@ import { OpenAIChatCompletionsProvider } from "../openaiChatCompletionsBase.js";
14
14
  * @see https://huggingface.co/docs/api-inference/index
15
15
  */
16
16
  export declare class HuggingFaceProvider extends OpenAIChatCompletionsProvider {
17
- constructor(modelName?: string, sdk?: unknown, credentials?: NeurolinkCredentials["huggingFace"]);
17
+ constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["huggingFace"]);
18
18
  protected getProviderName(): AIProviderName;
19
19
  protected getDefaultModel(): string;
20
20
  protected getFallbackModelName(): string;
@@ -1,8 +1,8 @@
1
- import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../../types/index.js";
1
+ import { AuthenticationError, InvalidModelError, ProviderError, RateLimitError, } from "../../types/index.js";
2
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../../utils/errorClassifier.js";
2
3
  import { logger } from "../../utils/logger.js";
3
4
  import { redactUrlCredentials } from "../../utils/logSanitize.js";
4
5
  import { createHuggingFaceConfig, getProviderModel, validateApiKey, } from "../../utils/providerConfig.js";
5
- import { TimeoutError } from "../../utils/timeout.js";
6
6
  import { OpenAIChatCompletionsProvider } from "../openaiChatCompletionsBase.js";
7
7
  const HUGGINGFACE_DEFAULT_BASE_URL = "https://router.huggingface.co/v1";
8
8
  const getHuggingFaceApiKey = () => validateApiKey(createHuggingFaceConfig());
@@ -20,7 +20,7 @@ const getDefaultHuggingFaceModel = () => getProviderModel("HUGGINGFACE_MODEL", "
20
20
  * @see https://huggingface.co/docs/api-inference/index
21
21
  */
22
22
  export class HuggingFaceProvider extends OpenAIChatCompletionsProvider {
23
- constructor(modelName, sdk, credentials) {
23
+ constructor(modelName, sdk, _region, credentials) {
24
24
  const apiKey = credentials?.apiKey?.trim()
25
25
  ? credentials.apiKey.trim()
26
26
  : getHuggingFaceApiKey();
@@ -74,27 +74,29 @@ export class HuggingFaceProvider extends OpenAIChatCompletionsProvider {
74
74
  return toolCapableModels.some((capable) => modelName.includes(capable));
75
75
  }
76
76
  formatProviderError(error) {
77
- if (error instanceof TimeoutError) {
78
- return new NetworkError(`Request timed out: ${error.message}`, "huggingface");
79
- }
80
- const errorObj = error;
81
- const message = errorObj?.message && typeof errorObj.message === "string"
82
- ? errorObj.message
83
- : "Unknown error";
84
- // Enhanced error messages with tool calling context
85
- if (message.includes("API_TOKEN_INVALID") ||
86
- message.includes("Invalid token")) {
87
- return new AuthenticationError("Invalid HuggingFace API token. Please check your HUGGINGFACE_API_KEY environment variable.", "huggingface");
88
- }
89
- if (message.includes("rate limit")) {
90
- return new RateLimitError("HuggingFace rate limit exceeded. Consider using a paid plan or try again later.", "huggingface");
91
- }
92
- if (message.includes("model") && message.includes("not found")) {
93
- return new InvalidModelError(`HuggingFace model '${this.modelName}' not found.\n\nSuggestions:\n1. Check model name spelling\n2. Ensure model exists on HuggingFace Hub\n3. For tool calling, use: Llama-3.1-8B-Instruct, Hermes-3-Llama-3.2-3B, or CodeLlama-34b-Instruct-hf`, "huggingface");
94
- }
95
- if (message.includes("function") || message.includes("tool")) {
96
- return new ProviderError(`HuggingFace tool calling error: ${message}\n\nNotes:\n1. Ensure you're using a tool-capable model (Llama-3.1+, Hermes-3+, CodeLlama)\n2. Check that your model supports function calling\n3. Verify tool schema format is correct`, "huggingface");
97
- }
98
- return new ProviderError(`HuggingFace Provider Error: ${message}`, "huggingface");
77
+ const rules = [
78
+ {
79
+ match: (ctx) => /API_TOKEN_INVALID|Invalid token/.test(ctx.message),
80
+ errorClass: AuthenticationError,
81
+ message: "Invalid HuggingFace API token. Please check your HUGGINGFACE_API_KEY environment variable.",
82
+ },
83
+ {
84
+ match: (ctx) => /rate limit/.test(ctx.message),
85
+ errorClass: RateLimitError,
86
+ message: "HuggingFace rate limit exceeded. Consider using a paid plan or try again later.",
87
+ },
88
+ {
89
+ match: (ctx) => /model/.test(ctx.message) && /not found/.test(ctx.message),
90
+ errorClass: InvalidModelError,
91
+ message: () => `HuggingFace model '${this.modelName}' not found.\n\nSuggestions:\n1. Check model name spelling\n2. Ensure model exists on HuggingFace Hub\n3. For tool calling, use: Llama-3.1-8B-Instruct, Hermes-3-Llama-3.2-3B, or CodeLlama-34b-Instruct-hf`,
92
+ },
93
+ {
94
+ match: (ctx) => /function|tool/.test(ctx.message),
95
+ errorClass: ProviderError,
96
+ message: (ctx) => `HuggingFace tool calling error: ${ctx.message}\n\nNotes:\n1. Ensure you're using a tool-capable model (Llama-3.1+, Hermes-3+, CodeLlama)\n2. Check that your model supports function calling\n3. Verify tool schema format is correct`,
97
+ },
98
+ ...DEFAULT_ERROR_RULES,
99
+ ];
100
+ return classifyProviderError(error, rules, "huggingface", this.modelName);
99
101
  }
100
102
  }
@@ -1,2 +1 @@
1
1
  export * from "./client.js";
2
- export * from "./utils.js";
@@ -1,2 +1 @@
1
1
  export * from "./client.js";
2
- export * from "./utils.js";
@@ -56,4 +56,3 @@ export declare class JinaProvider extends BaseProvider {
56
56
  baseURL: string;
57
57
  };
58
58
  }
59
- export default JinaProvider;
@@ -214,4 +214,3 @@ export class JinaProvider extends BaseProvider {
214
214
  };
215
215
  }
216
216
  }
217
- export default JinaProvider;
@@ -2,13 +2,14 @@ import { SpanKind, SpanStatusCode, trace } from "@opentelemetry/api";
2
2
  import { registerRuntimeContextWindow, registerRuntimeOutputCeiling, } from "../../constants/contextWindows.js";
3
3
  import { createProxyFetch } from "../../proxy/proxyFetch.js";
4
4
  import { AuthenticationError, InvalidModelError, ModelAccessDeniedError, NetworkError, ProviderError, RateLimitError, isModelAccessDeniedMessage, parseAllowedModels, } from "../../types/index.js";
5
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../../utils/errorClassifier.js";
5
6
  import { isAbortError } from "../../utils/errorHandling.js";
6
7
  import { logger } from "../../utils/logger.js";
7
8
  import { redactUrlCredentials } from "../../utils/logSanitize.js";
8
9
  import { isGemini25Model as isCanonicalGemini25Model } from "../../utils/modelDetection.js";
9
10
  import { calculateCost } from "../../utils/pricing.js";
10
11
  import { getProviderModel } from "../../utils/providerConfig.js";
11
- import { createTimeoutController, TimeoutError } from "../../utils/timeout.js";
12
+ import { createTimeoutController } from "../../utils/timeout.js";
12
13
  import { stripTrailingSlash } from "../openaiChatCompletionsClient.js";
13
14
  import { OpenAIChatCompletionsProvider } from "../openaiChatCompletionsBase.js";
14
15
  const streamTracer = trace.getTracer("neurolink.provider.litellm");
@@ -320,46 +321,60 @@ export class LiteLLMProvider extends OpenAIChatCompletionsProvider {
320
321
  };
321
322
  }
322
323
  formatProviderError(error) {
323
- if (error instanceof TimeoutError) {
324
- return new NetworkError(`Request timed out: ${error.message}`, this.providerName);
325
- }
324
+ // Curator P1-1: detect "team not allowed to access model" responses and
325
+ // surface as ModelAccessDeniedError with the allowed_models array parsed
326
+ // from the body. Must run before classification (not just before the
327
+ // "API key" rule) because ModelAccessDeniedError's constructor takes an
328
+ // `{ provider, requestedModel, allowedModels }` options object rather
329
+ // than the `(message, provider?)` shape ProviderErrorRule expects, so it
330
+ // can't be expressed as a declarative rule. No realistic overlap with the
331
+ // timeout/ECONNREFUSED checks below (disjoint wording), so running this
332
+ // first is behaviorally identical to the original nesting order.
326
333
  const errorRecord = error;
327
- if (errorRecord?.name === "TimeoutError" ||
328
- (typeof errorRecord?.message === "string" &&
329
- errorRecord.message.toLowerCase().includes("timeout"))) {
330
- return new NetworkError(`Request timed out: ${errorRecord?.message || "Unknown timeout"}`, this.providerName);
331
- }
332
- if (typeof errorRecord?.message === "string") {
333
- if (errorRecord.message.includes("ECONNREFUSED") ||
334
- errorRecord.message.includes("Failed to fetch")) {
335
- return new NetworkError("LiteLLM proxy server not available. Please start the LiteLLM proxy server at " +
336
- `${process.env.LITELLM_BASE_URL || "http://localhost:4000"}`, this.providerName);
337
- }
338
- // Curator P1-1: detect "team not allowed to access model" responses and
339
- // surface as ModelAccessDeniedError with the allowed_models array parsed
340
- // from the body. Must run before the generic "API key" check because
341
- // LiteLLM phrases this as a 403 distinct from auth.
342
- if (isModelAccessDeniedMessage(errorRecord.message)) {
343
- return new ModelAccessDeniedError(errorRecord.message, {
344
- provider: this.providerName,
345
- requestedModel: this.modelName,
346
- allowedModels: parseAllowedModels(errorRecord.message),
347
- });
348
- }
349
- if (errorRecord.message.includes("API_KEY_INVALID") ||
350
- errorRecord.message.includes("Invalid API key")) {
351
- return new AuthenticationError("Invalid LiteLLM configuration. Please check your LITELLM_API_KEY environment variable.", this.providerName);
352
- }
353
- if (errorRecord.message.toLowerCase().includes("rate limit")) {
354
- return new RateLimitError("LiteLLM rate limit exceeded. Please try again later.", this.providerName);
355
- }
356
- if (errorRecord.message.toLowerCase().includes("model") &&
357
- errorRecord.message.toLowerCase().includes("not found")) {
358
- return new InvalidModelError(`Model '${this.modelName}' not available in LiteLLM proxy. ` +
359
- "Please check your LiteLLM configuration and ensure the model is configured.", this.providerName);
360
- }
334
+ if (typeof errorRecord?.message === "string" &&
335
+ isModelAccessDeniedMessage(errorRecord.message)) {
336
+ return new ModelAccessDeniedError(errorRecord.message, {
337
+ provider: this.providerName,
338
+ requestedModel: this.modelName,
339
+ allowedModels: parseAllowedModels(errorRecord.message),
340
+ });
361
341
  }
362
- return new ProviderError(`LiteLLM error: ${errorRecord?.message || "Unknown error"}`, this.providerName);
342
+ const rules = [
343
+ // Duck-typed timeout detection (name === "TimeoutError" OR message
344
+ // contains "timeout") distinct from the `instanceof TimeoutError` check
345
+ // classifyProviderError already performs first — preserved because
346
+ // some rejection paths produce a plain object/Error with that shape
347
+ // rather than a real TimeoutError instance.
348
+ {
349
+ match: (ctx) => ctx.errorName === "TimeoutError" || /timeout/i.test(ctx.message),
350
+ errorClass: NetworkError,
351
+ message: (ctx) => `Request timed out: ${ctx.message}`,
352
+ },
353
+ {
354
+ match: (ctx) => /ECONNREFUSED|Failed to fetch/.test(ctx.message),
355
+ errorClass: NetworkError,
356
+ message: () => "LiteLLM proxy server not available. Please start the LiteLLM proxy server at " +
357
+ `${process.env.LITELLM_BASE_URL || "http://localhost:4000"}`,
358
+ },
359
+ {
360
+ match: (ctx) => /API_KEY_INVALID|Invalid API key/.test(ctx.message),
361
+ errorClass: AuthenticationError,
362
+ message: "Invalid LiteLLM configuration. Please check your LITELLM_API_KEY environment variable.",
363
+ },
364
+ {
365
+ match: (ctx) => /rate limit/i.test(ctx.message),
366
+ errorClass: RateLimitError,
367
+ message: "LiteLLM rate limit exceeded. Please try again later.",
368
+ },
369
+ {
370
+ match: (ctx) => /model/i.test(ctx.message) && /not found/i.test(ctx.message),
371
+ errorClass: InvalidModelError,
372
+ message: () => `Model '${this.modelName}' not available in LiteLLM proxy. ` +
373
+ "Please check your LiteLLM configuration and ensure the model is configured.",
374
+ },
375
+ ...DEFAULT_ERROR_RULES,
376
+ ];
377
+ return classifyProviderError(error, rules, this.providerName, this.modelName);
363
378
  }
364
379
  /**
365
380
  * Get available models from LiteLLM proxy `/v1/models` endpoint.
@@ -1,3 +1 @@
1
1
  export * from "./client.js";
2
- export * from "./constants.js";
3
- export * from "./utils.js";
@@ -1,3 +1 @@
1
1
  export * from "./client.js";
2
- export * from "./constants.js";
3
- export * from "./utils.js";
@@ -15,6 +15,7 @@ import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
15
15
  */
16
16
  export declare class LlamaCppProvider extends OpenAIChatCompletionsProvider {
17
17
  constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["llamacpp"]);
18
+ validateConfiguration(): Promise<boolean>;
18
19
  protected getProviderName(): AIProviderName;
19
20
  protected getDefaultModel(): string;
20
21
  protected getFallbackModelName(): string;
@@ -1,7 +1,7 @@
1
1
  import { NetworkError, ProviderError } from "../types/index.js";
2
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../utils/errorClassifier.js";
2
3
  import { logger } from "../utils/logger.js";
3
4
  import { redactUrlCredentials } from "../utils/logSanitize.js";
4
- import { TimeoutError } from "../utils/timeout.js";
5
5
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
6
6
  const LLAMACPP_DEFAULT_BASE_URL = "http://localhost:8080/v1";
7
7
  const LLAMACPP_PLACEHOLDER_KEY = "llamacpp";
@@ -36,6 +36,9 @@ export class LlamaCppProvider extends OpenAIChatCompletionsProvider {
36
36
  baseURL: redactUrlCredentials(this.config.baseURL),
37
37
  });
38
38
  }
39
+ async validateConfiguration() {
40
+ return this.probeModelsEndpoint(this.getAuthHeaders());
41
+ }
39
42
  getProviderName() {
40
43
  return "llamacpp";
41
44
  }
@@ -49,25 +52,28 @@ export class LlamaCppProvider extends OpenAIChatCompletionsProvider {
49
52
  return ["loaded-model"];
50
53
  }
51
54
  formatProviderError(error) {
52
- if (error instanceof TimeoutError) {
53
- return new NetworkError(`Request timed out: ${error.message}`, "llamacpp");
54
- }
55
+ // `code`/`cause.code` aren't part of ProviderErrorContext, so they're read
56
+ // off the raw error here (mirrors ollama's `responseBody` extraction) for
57
+ // the ECONNREFUSED rule below, which the pre-migration code also checked
58
+ // via a duck-typed error code in addition to the message text.
55
59
  const errorRecord = error;
56
- const message = typeof errorRecord?.message === "string"
57
- ? errorRecord.message
58
- : "Unknown error";
59
60
  const cause = errorRecord?.cause ?? {};
60
61
  const code = (errorRecord?.code ?? cause?.code);
61
- if (code === "ECONNREFUSED" ||
62
- message.includes("ECONNREFUSED") ||
63
- message.includes("Failed to fetch") ||
64
- message.includes("fetch failed")) {
65
- return new NetworkError(`llama.cpp server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
66
- "Start it with: ./llama-server -m model.gguf --port 8080", "llamacpp");
67
- }
68
- if (message.includes("400")) {
69
- return new ProviderError("llama.cpp rejected the request. Common cause: model doesn't support tools (start llama-server with --jinja for tool support).", "llamacpp");
70
- }
71
- return new ProviderError(`llama.cpp error: ${message}`, "llamacpp");
62
+ const rules = [
63
+ {
64
+ match: (ctx) => code === "ECONNREFUSED" ||
65
+ /ECONNREFUSED|Failed to fetch|fetch failed/.test(ctx.message),
66
+ errorClass: NetworkError,
67
+ message: () => `llama.cpp server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
68
+ "Start it with: ./llama-server -m model.gguf --port 8080",
69
+ },
70
+ {
71
+ match: (ctx) => /400/.test(ctx.message),
72
+ errorClass: ProviderError,
73
+ message: "llama.cpp rejected the request. Common cause: model doesn't support tools (start llama-server with --jinja for tool support).",
74
+ },
75
+ ...DEFAULT_ERROR_RULES,
76
+ ];
77
+ return classifyProviderError(error, rules, "llamacpp", this.modelName);
72
78
  }
73
79
  }
@@ -1,8 +1,7 @@
1
- import { createProxyFetch } from "../proxy/proxyFetch.js";
2
- import { InvalidModelError, NetworkError, ProviderError, } from "../types/index.js";
1
+ import { InvalidModelError, NetworkError } from "../types/index.js";
2
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../utils/errorClassifier.js";
3
3
  import { logger } from "../utils/logger.js";
4
4
  import { redactUrlCredentials } from "../utils/logSanitize.js";
5
- import { TimeoutError } from "../utils/timeout.js";
6
5
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
7
6
  const LM_STUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
8
7
  const LM_STUDIO_PLACEHOLDER_KEY = "lm-studio";
@@ -48,50 +47,34 @@ export class LMStudioProvider extends OpenAIChatCompletionsProvider {
48
47
  return FALLBACK_MODEL;
49
48
  }
50
49
  formatProviderError(error) {
51
- if (error instanceof TimeoutError) {
52
- return new NetworkError(`Request timed out: ${error.message}`, "lm-studio");
53
- }
50
+ // `code`/`cause.code` aren't part of ProviderErrorContext, so they're read
51
+ // off the raw error here (mirrors ollama's `responseBody` extraction) for
52
+ // the ECONNREFUSED rule below, which the pre-migration code also checked
53
+ // via a duck-typed error code in addition to the message text.
54
54
  const errorRecord = error;
55
- const message = typeof errorRecord?.message === "string"
56
- ? errorRecord.message
57
- : "Unknown error";
58
55
  const cause = errorRecord?.cause ?? {};
59
56
  const code = (errorRecord?.code ?? cause?.code);
60
- if (code === "ECONNREFUSED" ||
61
- message.includes("ECONNREFUSED") ||
62
- message.includes("Failed to fetch") ||
63
- message.includes("fetch failed")) {
64
- return new NetworkError(`LM Studio server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
65
- `Open the LM Studio app, load a model, and click "Start Server".`, "lm-studio");
66
- }
67
- if (message.includes("model_not_found") || message.includes("404")) {
68
- return new InvalidModelError(`LM Studio model '${this.modelName}' is not loaded. Load it in the LM Studio app first.`, "lm-studio");
69
- }
70
- return new ProviderError(`LM Studio error: ${message}`, "lm-studio");
57
+ const rules = [
58
+ {
59
+ match: (ctx) => code === "ECONNREFUSED" ||
60
+ /ECONNREFUSED|Failed to fetch|fetch failed/.test(ctx.message),
61
+ errorClass: NetworkError,
62
+ message: () => `LM Studio server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
63
+ `Open the LM Studio app, load a model, and click "Start Server".`,
64
+ },
65
+ {
66
+ match: (ctx) => /model_not_found|404/.test(ctx.message),
67
+ errorClass: InvalidModelError,
68
+ message: () => `LM Studio model '${this.modelName}' is not loaded. Load it in the LM Studio app first.`,
69
+ },
70
+ ...DEFAULT_ERROR_RULES,
71
+ ];
72
+ return classifyProviderError(error, rules, "lm-studio", this.modelName);
71
73
  }
72
74
  async validateConfiguration() {
73
- try {
74
- const url = `${this.config.baseURL.replace(/\/$/, "")}/models`;
75
- const proxyFetch = createProxyFetch();
76
- const r = await proxyFetch(url, {
77
- headers: this.config.apiKey && this.config.apiKey !== LM_STUDIO_PLACEHOLDER_KEY
78
- ? { Authorization: `Bearer ${this.config.apiKey}` }
79
- : undefined,
80
- signal: AbortSignal.timeout(5000),
81
- });
82
- if (!r.ok) {
83
- return false;
84
- }
85
- // A 200 with an empty data array means LM Studio is up but no model is
86
- // loaded — `resolveModelName()` will fall back to FALLBACK_MODEL and the
87
- // first real request will fail. Require at least one loaded model so
88
- // health checks honestly reflect whether the provider is usable.
89
- const data = (await r.json().catch(() => null));
90
- return Boolean(data?.data?.some((m) => typeof m?.id === "string" && m.id.trim().length > 0));
91
- }
92
- catch {
93
- return false;
94
- }
75
+ return this.probeModelsEndpoint(this.config.apiKey && this.config.apiKey !== LM_STUDIO_PLACEHOLDER_KEY
76
+ ? { Authorization: `Bearer ${this.config.apiKey}` }
77
+ : {});
95
78
  }
96
79
  getConfiguration() {
97
80
  return {
@@ -1,9 +1,9 @@
1
1
  import { MistralModels } from "../constants/enums.js";
2
- import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
2
+ import { AuthenticationError } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
4
  import { redactUrlCredentials } from "../utils/logSanitize.js";
5
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../utils/errorClassifier.js";
5
6
  import { createMistralConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
6
- import { TimeoutError } from "../utils/timeout.js";
7
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
8
8
  const MISTRAL_DEFAULT_BASE_URL = "https://api.mistral.ai/v1";
9
9
  const getMistralApiKey = () => {
@@ -60,28 +60,16 @@ export class MistralProvider extends OpenAIChatCompletionsProvider {
60
60
  return getDefaultMistralModel();
61
61
  }
62
62
  formatProviderError(error) {
63
- if (error instanceof TimeoutError) {
64
- return new NetworkError(`Request timed out: ${error.message}`, "mistral");
65
- }
66
- const errorRecord = error;
67
- const message = typeof errorRecord?.message === "string"
68
- ? errorRecord.message
69
- : "Unknown error";
70
- if (message.includes("API_KEY_INVALID") ||
71
- message.includes("Invalid API key") ||
72
- message.includes("Unauthorized") ||
73
- message.includes("401")) {
74
- return new AuthenticationError("Invalid Mistral API key. Please check your MISTRAL_API_KEY environment variable.", "mistral");
75
- }
76
- if (message.includes("rate limit") ||
77
- message.includes("Rate limit") ||
78
- message.includes("429")) {
79
- return new RateLimitError("Mistral rate limit exceeded", "mistral");
80
- }
81
- if (message.includes("model_not_found") || message.includes("404")) {
82
- return new InvalidModelError(`Mistral model '${this.modelName}' not found.`, "mistral");
83
- }
84
- return new ProviderError(`Mistral error: ${message}`, "mistral");
63
+ const rules = [
64
+ {
65
+ match: (ctx) => ctx.statusCode === 401 ||
66
+ /API_KEY_INVALID|Invalid API key|Unauthorized/i.test(ctx.message),
67
+ errorClass: AuthenticationError,
68
+ message: "Invalid Mistral API key. Please check your MISTRAL_API_KEY environment variable.",
69
+ },
70
+ ...DEFAULT_ERROR_RULES,
71
+ ];
72
+ return classifyProviderError(error, rules, "mistral", this.modelName);
85
73
  }
86
74
  // ===========================================================================
87
75
  // Optional hooks
@@ -1,9 +1,9 @@
1
1
  import { NvidiaNimModels } from "../../constants/enums.js";
2
- import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../../types/index.js";
2
+ import { AuthenticationError, InvalidModelError, ProviderError, RateLimitError, } from "../../types/index.js";
3
+ import { classifyProviderError, DEFAULT_ERROR_RULES, } from "../../utils/errorClassifier.js";
3
4
  import { logger } from "../../utils/logger.js";
4
5
  import { redactUrlCredentials } from "../../utils/logSanitize.js";
5
6
  import { createNvidiaNimConfig, getProviderModel, validateApiKey, } from "../../utils/providerConfig.js";
6
- import { TimeoutError } from "../../utils/timeout.js";
7
7
  import { OpenAIChatCompletionsProvider } from "../openaiChatCompletionsBase.js";
8
8
  /**
9
9
  * Decide whether a NIM 400 response body is a rejection of the named
@@ -237,38 +237,41 @@ export class NvidiaNimProvider extends OpenAIChatCompletionsProvider {
237
237
  return JSON.parse(serialized);
238
238
  }
239
239
  formatProviderError(error) {
240
- if (error instanceof TimeoutError) {
241
- return new NetworkError(`Request timed out: ${error.message}`, "nvidia-nim");
242
- }
243
- const errorRecord = error;
244
- const message = typeof errorRecord?.message === "string"
245
- ? errorRecord.message
246
- : "Unknown error";
247
- // NIM canonically returns HTTP 401/Unauthorized for invalid API keys,
248
- // but its OpenAI-compatible gateway sometimes surfaces a bare 400 +
249
- // "Bad Request" with no body details for both malformed-credentials
250
- // and bad-parameter cases. Because the two are indistinguishable from
251
- // the message alone, we DON'T promote bare 400/Bad Request to "invalid
252
- // key" here — that would mis-classify legitimate parameter errors
253
- // (e.g. unsupported `reasoning_budget`, unsupported `chat_template`)
254
- // as auth failures. Tests that probe the auth path (K1) detect
255
- // "bad request" / "400" themselves; tests that probe parameter retry
256
- // (K5) need the original "Bad Request" message to surface.
257
- if (message.includes("Invalid API key") ||
258
- message.includes("401") ||
259
- message.includes("Unauthorized")) {
260
- return new AuthenticationError("Invalid NVIDIA NIM API key. Get one at https://build.nvidia.com/settings/api-keys", "nvidia-nim");
261
- }
262
- if (message.includes("rate limit") || message.includes("429")) {
263
- return new RateLimitError("NVIDIA NIM rate limit exceeded", "nvidia-nim");
264
- }
265
- if (message.includes("404") || message.includes("model_not_found")) {
266
- return new InvalidModelError(`NVIDIA NIM model '${this.modelName}' not available. Browse the catalog at https://build.nvidia.com/models`, "nvidia-nim");
267
- }
268
- if (message.includes("quota") || message.includes("403")) {
269
- return new ProviderError("NVIDIA NIM quota exceeded for your account", "nvidia-nim");
270
- }
271
- return new ProviderError(`NVIDIA NIM error: ${message}`, "nvidia-nim");
240
+ const rules = [
241
+ // NIM canonically returns HTTP 401/Unauthorized for invalid API keys,
242
+ // but its OpenAI-compatible gateway sometimes surfaces a bare 400 +
243
+ // "Bad Request" with no body details for both malformed-credentials
244
+ // and bad-parameter cases. Because the two are indistinguishable from
245
+ // the message alone, bare 400/"Bad Request" is deliberately NOT
246
+ // promoted to "invalid key" here — that would mis-classify legitimate
247
+ // parameter errors (e.g. unsupported `reasoning_budget`, unsupported
248
+ // `chat_template`) as auth failures. Tests that probe the auth path
249
+ // (K1) detect "bad request" / "400" themselves; tests that probe
250
+ // parameter retry (K5) need the original "Bad Request" message to
251
+ // surface.
252
+ {
253
+ match: (ctx) => /Invalid API key|401|Unauthorized/.test(ctx.message),
254
+ errorClass: AuthenticationError,
255
+ message: "Invalid NVIDIA NIM API key. Get one at https://build.nvidia.com/settings/api-keys",
256
+ },
257
+ {
258
+ match: (ctx) => /rate limit|429/.test(ctx.message),
259
+ errorClass: RateLimitError,
260
+ message: "NVIDIA NIM rate limit exceeded",
261
+ },
262
+ {
263
+ match: (ctx) => /404|model_not_found/.test(ctx.message),
264
+ errorClass: InvalidModelError,
265
+ message: () => `NVIDIA NIM model '${this.modelName}' not available. Browse the catalog at https://build.nvidia.com/models`,
266
+ },
267
+ {
268
+ match: (ctx) => /quota|403/.test(ctx.message),
269
+ errorClass: ProviderError,
270
+ message: "NVIDIA NIM quota exceeded for your account",
271
+ },
272
+ ...DEFAULT_ERROR_RULES,
273
+ ];
274
+ return classifyProviderError(error, rules, "nvidia-nim", this.modelName);
272
275
  }
273
276
  async validateConfiguration() {
274
277
  return (typeof this.config.apiKey === "string" &&
@@ -1,3 +1,2 @@
1
1
  export * from "./client.js";
2
2
  export * from "./constants.js";
3
- export * from "./utils.js";
@@ -1,3 +1,2 @@
1
1
  export * from "./client.js";
2
2
  export * from "./constants.js";
3
- export * from "./utils.js";