@juspay/neurolink 9.68.16 → 9.68.18

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 (43) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/browser/neurolink.min.js +561 -561
  3. package/dist/lib/providers/cloudflare.js +2 -1
  4. package/dist/lib/providers/cohere.js +2 -1
  5. package/dist/lib/providers/deepseek.js +2 -1
  6. package/dist/lib/providers/fireworks.js +2 -1
  7. package/dist/lib/providers/groq.js +2 -1
  8. package/dist/lib/providers/huggingFace.js +2 -1
  9. package/dist/lib/providers/litellm.js +2 -1
  10. package/dist/lib/providers/llamaCpp.js +1 -6
  11. package/dist/lib/providers/lmStudio.js +3 -2
  12. package/dist/lib/providers/mistral.d.ts +20 -28
  13. package/dist/lib/providers/mistral.js +61 -136
  14. package/dist/lib/providers/nvidiaNim.js +2 -1
  15. package/dist/lib/providers/openAI.js +2 -1
  16. package/dist/lib/providers/openaiCompatible.js +3 -2
  17. package/dist/lib/providers/perplexity.js +2 -1
  18. package/dist/lib/providers/togetherAi.js +2 -1
  19. package/dist/lib/providers/xai.js +2 -1
  20. package/dist/lib/types/providers.d.ts +1 -0
  21. package/dist/lib/utils/logSanitize.d.ts +14 -0
  22. package/dist/lib/utils/logSanitize.js +16 -0
  23. package/dist/providers/cloudflare.js +2 -1
  24. package/dist/providers/cohere.js +2 -1
  25. package/dist/providers/deepseek.js +2 -1
  26. package/dist/providers/fireworks.js +2 -1
  27. package/dist/providers/groq.js +2 -1
  28. package/dist/providers/huggingFace.js +2 -1
  29. package/dist/providers/litellm.js +2 -1
  30. package/dist/providers/llamaCpp.js +1 -6
  31. package/dist/providers/lmStudio.js +3 -2
  32. package/dist/providers/mistral.d.ts +20 -28
  33. package/dist/providers/mistral.js +61 -136
  34. package/dist/providers/nvidiaNim.js +2 -1
  35. package/dist/providers/openAI.js +2 -1
  36. package/dist/providers/openaiCompatible.js +3 -2
  37. package/dist/providers/perplexity.js +2 -1
  38. package/dist/providers/togetherAi.js +2 -1
  39. package/dist/providers/xai.js +2 -1
  40. package/dist/types/providers.d.ts +1 -0
  41. package/dist/utils/logSanitize.d.ts +14 -0
  42. package/dist/utils/logSanitize.js +16 -0
  43. package/package.json +1 -1
@@ -1,6 +1,7 @@
1
1
  import { CloudflareModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createCloudflareConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -44,7 +45,7 @@ export class CloudflareProvider extends OpenAIChatCompletionsProvider {
44
45
  logger.debug("Cloudflare Workers AI Provider initialized", {
45
46
  modelName: this.modelName,
46
47
  providerName: this.providerName,
47
- baseURL: this.config.baseURL,
48
+ baseURL: redactUrlCredentials(this.config.baseURL),
48
49
  });
49
50
  }
50
51
  getProviderName() {
@@ -1,6 +1,7 @@
1
1
  import { CohereModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createProxyFetch } from "../proxy/proxyFetch.js";
5
6
  import { createCohereConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
6
7
  import { createTimeoutController, TimeoutError } from "../utils/timeout.js";
@@ -36,7 +37,7 @@ export class CohereProvider extends OpenAIChatCompletionsProvider {
36
37
  logger.debug("Cohere Provider initialized", {
37
38
  modelName: this.modelName,
38
39
  providerName: this.providerName,
39
- baseURL: this.config.baseURL,
40
+ baseURL: redactUrlCredentials(this.config.baseURL),
40
41
  });
41
42
  }
42
43
  getProviderName() {
@@ -1,6 +1,7 @@
1
1
  import { DeepSeekModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createDeepSeekConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -55,7 +56,7 @@ export class DeepSeekProvider extends OpenAIChatCompletionsProvider {
55
56
  logger.debug("DeepSeek Provider initialized", {
56
57
  modelName: this.modelName,
57
58
  providerName: this.providerName,
58
- baseURL: this.config.baseURL,
59
+ baseURL: redactUrlCredentials(this.config.baseURL),
59
60
  });
60
61
  }
61
62
  // ===========================================================================
@@ -1,6 +1,7 @@
1
1
  import { FireworksModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createFireworksConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -34,7 +35,7 @@ export class FireworksProvider extends OpenAIChatCompletionsProvider {
34
35
  logger.debug("Fireworks Provider initialized", {
35
36
  modelName: this.modelName,
36
37
  providerName: this.providerName,
37
- baseURL: this.config.baseURL,
38
+ baseURL: redactUrlCredentials(this.config.baseURL),
38
39
  });
39
40
  }
40
41
  getProviderName() {
@@ -1,6 +1,7 @@
1
1
  import { GroqModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createGroqConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -33,7 +34,7 @@ export class GroqProvider extends OpenAIChatCompletionsProvider {
33
34
  logger.debug("Groq Provider initialized", {
34
35
  modelName: this.modelName,
35
36
  providerName: this.providerName,
36
- baseURL: this.config.baseURL,
37
+ baseURL: redactUrlCredentials(this.config.baseURL),
37
38
  });
38
39
  }
39
40
  getProviderName() {
@@ -1,5 +1,6 @@
1
1
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
2
2
  import { logger } from "../utils/logger.js";
3
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
3
4
  import { createHuggingFaceConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
4
5
  import { TimeoutError } from "../utils/timeout.js";
5
6
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -33,7 +34,7 @@ export class HuggingFaceProvider extends OpenAIChatCompletionsProvider {
33
34
  logger.debug("HuggingFaceProvider initialized", {
34
35
  modelName: this.modelName,
35
36
  providerName: this.providerName,
36
- baseURL: this.config.baseURL,
37
+ baseURL: redactUrlCredentials(this.config.baseURL),
37
38
  });
38
39
  }
39
40
  getProviderName() {
@@ -3,6 +3,7 @@ import { createProxyFetch } from "../proxy/proxyFetch.js";
3
3
  import { AuthenticationError, InvalidModelError, ModelAccessDeniedError, NetworkError, ProviderError, RateLimitError, isModelAccessDeniedMessage, parseAllowedModels, } from "../types/index.js";
4
4
  import { isAbortError } from "../utils/errorHandling.js";
5
5
  import { logger } from "../utils/logger.js";
6
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
6
7
  import { isGemini25Model as isCanonicalGemini25Model } from "../utils/modelDetection.js";
7
8
  import { calculateCost } from "../utils/pricing.js";
8
9
  import { getProviderModel } from "../utils/providerConfig.js";
@@ -53,7 +54,7 @@ export class LiteLLMProvider extends OpenAIChatCompletionsProvider {
53
54
  logger.debug("LiteLLM Provider initialized", {
54
55
  modelName: this.modelName,
55
56
  provider: this.providerName,
56
- baseURL: this.config.baseURL,
57
+ baseURL: redactUrlCredentials(this.config.baseURL),
57
58
  });
58
59
  }
59
60
  getProviderName() {
@@ -1,5 +1,6 @@
1
1
  import { NetworkError, ProviderError } from "../types/index.js";
2
2
  import { logger } from "../utils/logger.js";
3
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
3
4
  import { TimeoutError } from "../utils/timeout.js";
4
5
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
5
6
  const LLAMACPP_DEFAULT_BASE_URL = "http://localhost:8080/v1";
@@ -7,12 +8,6 @@ const LLAMACPP_PLACEHOLDER_KEY = "llamacpp";
7
8
  const getLlamaCppBaseURL = () => {
8
9
  return process.env.LLAMACPP_BASE_URL || LLAMACPP_DEFAULT_BASE_URL;
9
10
  };
10
- /**
11
- * Strip embedded `user:pass@` credentials from a URL before logging it or
12
- * surfacing it in a user-facing error. Preserves host/port/path so the URL
13
- * stays useful for diagnostics.
14
- */
15
- const redactUrlCredentials = (url) => url.replace(/\/\/[^/@]+@/, "//***@");
16
11
  /**
17
12
  * llama.cpp Provider — direct HTTP, no AI SDK.
18
13
  *
@@ -1,6 +1,7 @@
1
1
  import { createProxyFetch } from "../proxy/proxyFetch.js";
2
2
  import { InvalidModelError, NetworkError, ProviderError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { TimeoutError } from "../utils/timeout.js";
5
6
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
6
7
  const LM_STUDIO_DEFAULT_BASE_URL = "http://localhost:1234/v1";
@@ -34,7 +35,7 @@ export class LMStudioProvider extends OpenAIChatCompletionsProvider {
34
35
  logger.debug("LM Studio Provider initialized", {
35
36
  modelName: this.modelName,
36
37
  providerName: this.providerName,
37
- baseURL: this.config.baseURL,
38
+ baseURL: redactUrlCredentials(this.config.baseURL),
38
39
  });
39
40
  }
40
41
  getProviderName() {
@@ -60,7 +61,7 @@ export class LMStudioProvider extends OpenAIChatCompletionsProvider {
60
61
  message.includes("ECONNREFUSED") ||
61
62
  message.includes("Failed to fetch") ||
62
63
  message.includes("fetch failed")) {
63
- return new NetworkError(`LM Studio server not reachable at ${this.config.baseURL}. ` +
64
+ return new NetworkError(`LM Studio server not reachable at ${redactUrlCredentials(this.config.baseURL)}. ` +
64
65
  `Open the LM Studio app, load a model, and click "Start Server".`, "lm-studio");
65
66
  }
66
67
  if (message.includes("model_not_found") || message.includes("404")) {
@@ -1,33 +1,25 @@
1
1
  import type { AIProviderName } from "../constants/enums.js";
2
- import { BaseProvider } from "../core/baseProvider.js";
3
- import type { NeurolinkCredentials, StreamOptions, StreamResult, ValidationSchema } from "../types/index.js";
4
- import type { LanguageModel } from "../types/index.js";
2
+ import type { NeurolinkCredentials } from "../types/index.js";
3
+ import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
5
4
  /**
6
- * Mistral AI Provider v2 - BaseProvider Implementation
7
- * Supports official AI-SDK integration with all Mistral models
5
+ * Mistral AI Provider direct HTTP, no AI SDK.
6
+ *
7
+ * OpenAI-compatible chat completions at api.mistral.ai/v1. All request/stream/
8
+ * tool-loop orchestration lives in `OpenAIChatCompletionsProvider`; this class
9
+ * only declares configuration and the provider-specific error mapping.
10
+ *
11
+ * Mistral's `/chat/completions` accepts `response_format: { type:
12
+ * "json_schema" }` on current models (mistral-small-2506 and newer), so no
13
+ * structured-output downgrade is needed — the base client's default
14
+ * pass-through is correct.
15
+ *
16
+ * @see https://docs.mistral.ai/api/
8
17
  */
9
- export declare class MistralProvider extends BaseProvider {
10
- private model;
18
+ export declare class MistralProvider extends OpenAIChatCompletionsProvider {
11
19
  constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["mistral"]);
12
- protected executeStream(options: StreamOptions, _analysisSchema?: ValidationSchema): Promise<StreamResult>;
13
- getProviderName(): AIProviderName;
14
- getDefaultModel(): string;
15
- /**
16
- * Returns the Vercel AI SDK model instance for Mistral
17
- */
18
- getAISDKModel(): LanguageModel;
19
- formatProviderError(error: unknown): Error;
20
- /**
21
- * Validate provider configuration
22
- */
23
- validateConfiguration(): Promise<boolean>;
24
- /**
25
- * Get provider-specific configuration
26
- */
27
- getConfiguration(): {
28
- provider: AIProviderName;
29
- model: string;
30
- defaultModel: string;
31
- };
20
+ protected getProviderName(): AIProviderName;
21
+ protected getDefaultModel(): string;
22
+ protected formatProviderError(error: unknown): Error;
23
+ protected getFallbackModelName(): string;
24
+ protected getFallbackModels(): string[];
32
25
  }
33
- export default MistralProvider;
@@ -1,135 +1,64 @@
1
- import { createMistral } from "@ai-sdk/mistral";
2
- import { BaseProvider } from "../core/baseProvider.js";
3
- import { DEFAULT_MAX_STEPS } from "../core/constants.js";
4
- import { streamAnalyticsCollector } from "../core/streamAnalytics.js";
5
- import { isNeuroLink } from "../neurolink.js";
6
- import { createProxyFetch } from "../proxy/proxyFetch.js";
7
- import { AuthenticationError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
8
- import { emitToolEndFromStepFinish } from "../utils/toolEndEmitter.js";
1
+ import { MistralModels } from "../constants/enums.js";
2
+ import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
9
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
10
5
  import { createMistralConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
11
- import { composeAbortSignals, createTimeoutController, TimeoutError, } from "../utils/timeout.js";
12
- import { resolveToolChoice } from "../utils/toolChoice.js";
13
- import { toAnalyticsStreamResult } from "./providerTypeUtils.js";
14
- import { stepCountIs } from "../utils/tool.js";
15
- import { streamText } from "../utils/generation.js";
16
- // Configuration helpers - now using consolidated utility
6
+ import { TimeoutError } from "../utils/timeout.js";
7
+ import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
8
+ const MISTRAL_DEFAULT_BASE_URL = "https://api.mistral.ai/v1";
17
9
  const getMistralApiKey = () => {
18
10
  return validateApiKey(createMistralConfig());
19
11
  };
20
12
  const getDefaultMistralModel = () => {
21
- // Default to vision-capable Mistral Small 2506 (June 2025) with multimodal support
22
- return getProviderModel("MISTRAL_MODEL", "mistral-small-2506");
13
+ // Vision-capable Mistral Small (June 2025) with multimodal support.
14
+ return getProviderModel("MISTRAL_MODEL", MistralModels.MISTRAL_SMALL_2506);
23
15
  };
24
16
  /**
25
- * Mistral AI Provider v2 - BaseProvider Implementation
26
- * Supports official AI-SDK integration with all Mistral models
17
+ * Mistral AI Provider direct HTTP, no AI SDK.
18
+ *
19
+ * OpenAI-compatible chat completions at api.mistral.ai/v1. All request/stream/
20
+ * tool-loop orchestration lives in `OpenAIChatCompletionsProvider`; this class
21
+ * only declares configuration and the provider-specific error mapping.
22
+ *
23
+ * Mistral's `/chat/completions` accepts `response_format: { type:
24
+ * "json_schema" }` on current models (mistral-small-2506 and newer), so no
25
+ * structured-output downgrade is needed — the base client's default
26
+ * pass-through is correct.
27
+ *
28
+ * @see https://docs.mistral.ai/api/
27
29
  */
28
- export class MistralProvider extends BaseProvider {
29
- model;
30
+ export class MistralProvider extends OpenAIChatCompletionsProvider {
30
31
  constructor(modelName, sdk, _region, credentials) {
31
- // Type guard for NeuroLink parameter validation
32
- const validatedNeurolink = isNeuroLink(sdk) ? sdk : undefined;
33
- super(modelName, "mistral", validatedNeurolink);
34
- // Initialize Mistral model with API key validation and proxy support
35
- const apiKey = credentials?.apiKey ?? getMistralApiKey();
36
- const mistral = createMistral({
37
- apiKey: apiKey,
38
- fetch: createProxyFetch(),
39
- });
40
- this.model = mistral(this.modelName);
41
- logger.debug("Mistral Provider v2 initialized", {
32
+ // Trim the override before applying precedence. A blank/whitespace
33
+ // `credentials.apiKey` must NOT bypass `getMistralApiKey()` that would
34
+ // build a client with an unusable bearer token and fail at request time
35
+ // with a confusing 401 instead of at construction time.
36
+ const overrideApiKey = credentials?.apiKey?.trim();
37
+ const apiKey = overrideApiKey && overrideApiKey.length > 0
38
+ ? overrideApiKey
39
+ : getMistralApiKey();
40
+ // Treat blank/whitespace overrides as unset so an empty
41
+ // `credentials.baseURL` or `MISTRAL_BASE_URL=` cannot silently override
42
+ // the default with "" (mirrors the apiKey precedence above).
43
+ const baseURL = credentials?.baseURL?.trim() ||
44
+ process.env.MISTRAL_BASE_URL?.trim() ||
45
+ MISTRAL_DEFAULT_BASE_URL;
46
+ super("mistral", modelName, sdk, { baseURL, apiKey });
47
+ logger.debug("Mistral Provider initialized", {
42
48
  modelName: this.modelName,
43
49
  providerName: this.providerName,
50
+ baseURL: redactUrlCredentials(this.config.baseURL),
44
51
  });
45
52
  }
46
- // generate() method is inherited from BaseProvider; this provider uses the base implementation for generation with tools
47
- async executeStream(options, _analysisSchema) {
48
- this.validateStreamOptions(options);
49
- const startTime = Date.now();
50
- const timeout = this.getTimeout(options);
51
- const timeoutController = createTimeoutController(timeout, this.providerName, "stream");
52
- try {
53
- // Get tools - options.tools is pre-merged by BaseProvider.stream()
54
- const shouldUseTools = !options.disableTools && this.supportsTools();
55
- const tools = shouldUseTools
56
- ? options.tools || (await this.getAllTools())
57
- : {};
58
- // Build message array from options with multimodal support
59
- // Using protected helper from BaseProvider to eliminate code duplication
60
- const messages = await this.buildMessagesForStream(options);
61
- const model = await this.getAISDKModelWithMiddleware(options); // This is where network connection happens!
62
- // Reviewer follow-up: capture upstream provider errors via onError
63
- // so the post-stream NoOutput sentinel carries the real cause.
64
- let capturedProviderError;
65
- const result = await streamText({
66
- model,
67
- messages: messages,
68
- temperature: options.temperature,
69
- maxOutputTokens: options.maxTokens, // No default limit - unlimited unless specified
70
- tools,
71
- stopWhen: stepCountIs(options.maxSteps || DEFAULT_MAX_STEPS),
72
- toolChoice: resolveToolChoice(options, tools, shouldUseTools),
73
- abortSignal: composeAbortSignals(options.abortSignal, timeoutController?.controller.signal),
74
- experimental_telemetry: this.telemetryHandler.getTelemetryConfig(options),
75
- experimental_repairToolCall: this.getToolCallRepairFn(options),
76
- onError: (event) => {
77
- capturedProviderError = event.error;
78
- logger.error("Mistral: Stream error", {
79
- error: event.error instanceof Error
80
- ? event.error.message
81
- : String(event.error),
82
- });
83
- },
84
- onStepFinish: ({ toolCalls, toolResults }) => {
85
- emitToolEndFromStepFinish(this.neurolink?.getEventEmitter(), toolResults);
86
- this.handleToolExecutionStorage(toolCalls, toolResults, options, new Date()).catch((error) => {
87
- logger.warn("[MistralProvider] Failed to store tool executions", {
88
- provider: this.providerName,
89
- error: error instanceof Error ? error.message : String(error),
90
- });
91
- });
92
- },
93
- });
94
- timeoutController?.cleanup();
95
- // Transform string stream to content object stream using BaseProvider method
96
- const transformedStream = this.createTextStream(result, () => capturedProviderError);
97
- // Create analytics promise that resolves after stream completion
98
- const analyticsPromise = streamAnalyticsCollector.createAnalytics(this.providerName, this.modelName, toAnalyticsStreamResult(result), Date.now() - startTime, {
99
- requestId: `mistral-stream-${Date.now()}`,
100
- streamingMode: true,
101
- });
102
- return {
103
- stream: transformedStream,
104
- provider: this.providerName,
105
- model: this.modelName,
106
- analytics: analyticsPromise,
107
- metadata: {
108
- startTime,
109
- streamId: `mistral-${Date.now()}`,
110
- },
111
- };
112
- }
113
- catch (error) {
114
- timeoutController?.cleanup();
115
- throw this.handleProviderError(error);
116
- }
117
- }
118
- // ===================
119
- // ABSTRACT METHOD IMPLEMENTATIONS
120
- // ===================
53
+ // ===========================================================================
54
+ // Abstract hooks (required)
55
+ // ===========================================================================
121
56
  getProviderName() {
122
- return this.providerName;
57
+ return "mistral";
123
58
  }
124
59
  getDefaultModel() {
125
60
  return getDefaultMistralModel();
126
61
  }
127
- /**
128
- * Returns the Vercel AI SDK model instance for Mistral
129
- */
130
- getAISDKModel() {
131
- return this.model;
132
- }
133
62
  formatProviderError(error) {
134
63
  if (error instanceof TimeoutError) {
135
64
  return new NetworkError(`Request timed out: ${error.message}`, "mistral");
@@ -139,35 +68,31 @@ export class MistralProvider extends BaseProvider {
139
68
  ? errorRecord.message
140
69
  : "Unknown error";
141
70
  if (message.includes("API_KEY_INVALID") ||
142
- message.includes("Invalid API key")) {
71
+ message.includes("Invalid API key") ||
72
+ message.includes("Unauthorized") ||
73
+ message.includes("401")) {
143
74
  return new AuthenticationError("Invalid Mistral API key. Please check your MISTRAL_API_KEY environment variable.", "mistral");
144
75
  }
145
- if (message.includes("Rate limit exceeded")) {
76
+ if (message.includes("rate limit") ||
77
+ message.includes("Rate limit") ||
78
+ message.includes("429")) {
146
79
  return new RateLimitError("Mistral rate limit exceeded", "mistral");
147
80
  }
81
+ if (message.includes("model_not_found") || message.includes("404")) {
82
+ return new InvalidModelError(`Mistral model '${this.modelName}' not found.`, "mistral");
83
+ }
148
84
  return new ProviderError(`Mistral error: ${message}`, "mistral");
149
85
  }
150
- /**
151
- * Validate provider configuration
152
- */
153
- async validateConfiguration() {
154
- try {
155
- getMistralApiKey();
156
- return true;
157
- }
158
- catch {
159
- return false;
160
- }
86
+ // ===========================================================================
87
+ // Optional hooks
88
+ // ===========================================================================
89
+ getFallbackModelName() {
90
+ return MistralModels.MISTRAL_SMALL_2506;
161
91
  }
162
- /**
163
- * Get provider-specific configuration
164
- */
165
- getConfiguration() {
166
- return {
167
- provider: this.providerName,
168
- model: this.modelName,
169
- defaultModel: getDefaultMistralModel(),
170
- };
92
+ getFallbackModels() {
93
+ return [
94
+ MistralModels.MISTRAL_SMALL_2506,
95
+ MistralModels.MISTRAL_LARGE_LATEST,
96
+ ];
171
97
  }
172
98
  }
173
- export default MistralProvider;
@@ -1,6 +1,7 @@
1
1
  import { NvidiaNimModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createNvidiaNimConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -164,7 +165,7 @@ export class NvidiaNimProvider extends OpenAIChatCompletionsProvider {
164
165
  logger.debug("NVIDIA NIM Provider initialized", {
165
166
  modelName: this.modelName,
166
167
  providerName: this.providerName,
167
- baseURL: this.config.baseURL,
168
+ baseURL: redactUrlCredentials(this.config.baseURL),
168
169
  });
169
170
  }
170
171
  getProviderName() {
@@ -3,6 +3,7 @@ import { AIProviderName as AIProviderNameEnum } from "../constants/enums.js";
3
3
  import { createProxyFetch } from "../proxy/proxyFetch.js";
4
4
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
5
5
  import { logger } from "../utils/logger.js";
6
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
6
7
  import { calculateCost } from "../utils/pricing.js";
7
8
  import { createOpenAIConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
8
9
  import { MAX_IMAGE_BYTES, readBoundedBuffer } from "../utils/sizeGuard.js";
@@ -67,7 +68,7 @@ export class OpenAIProvider extends OpenAIChatCompletionsProvider {
67
68
  logger.debug("OpenAIProvider initialized", {
68
69
  model: this.modelName,
69
70
  providerName: this.providerName,
70
- baseURL: this.config.baseURL,
71
+ baseURL: redactUrlCredentials(this.config.baseURL),
71
72
  });
72
73
  }
73
74
  // ===========================================================================
@@ -1,5 +1,6 @@
1
1
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
2
2
  import { logger } from "../utils/logger.js";
3
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
3
4
  import { TimeoutError } from "../utils/timeout.js";
4
5
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
5
6
  const FALLBACK_OPENAI_COMPATIBLE_MODEL = "gpt-3.5-turbo";
@@ -42,7 +43,7 @@ export class OpenAICompatibleProvider extends OpenAIChatCompletionsProvider {
42
43
  logger.debug("OpenAI Compatible Provider initialized", {
43
44
  modelName: this.modelName,
44
45
  provider: this.providerName,
45
- baseURL: this.config.baseURL,
46
+ baseURL: redactUrlCredentials(this.config.baseURL),
46
47
  });
47
48
  }
48
49
  getProviderName() {
@@ -78,7 +79,7 @@ export class OpenAICompatibleProvider extends OpenAIChatCompletionsProvider {
78
79
  if (typeof errorRecord?.message === "string") {
79
80
  if (errorRecord.message.includes("ECONNREFUSED") ||
80
81
  errorRecord.message.includes("Failed to fetch")) {
81
- return new NetworkError(`OpenAI Compatible endpoint not available. Please check your OPENAI_COMPATIBLE_BASE_URL: ${this.config.baseURL}`, "openai-compatible");
82
+ return new NetworkError(`OpenAI Compatible endpoint not available. Please check your OPENAI_COMPATIBLE_BASE_URL: ${redactUrlCredentials(this.config.baseURL)}`, "openai-compatible");
82
83
  }
83
84
  if (errorRecord.message.includes("API_KEY_INVALID") ||
84
85
  errorRecord.message.includes("Invalid API key") ||
@@ -1,6 +1,7 @@
1
1
  import { PerplexityModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createPerplexityConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -33,7 +34,7 @@ export class PerplexityProvider extends OpenAIChatCompletionsProvider {
33
34
  logger.debug("Perplexity Provider initialized", {
34
35
  modelName: this.modelName,
35
36
  providerName: this.providerName,
36
- baseURL: this.config.baseURL,
37
+ baseURL: redactUrlCredentials(this.config.baseURL),
37
38
  });
38
39
  }
39
40
  getProviderName() {
@@ -1,6 +1,7 @@
1
1
  import { TogetherAIModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createTogetherAIConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -32,7 +33,7 @@ export class TogetherAIProvider extends OpenAIChatCompletionsProvider {
32
33
  logger.debug("Together AI Provider initialized", {
33
34
  modelName: this.modelName,
34
35
  providerName: this.providerName,
35
- baseURL: this.config.baseURL,
36
+ baseURL: redactUrlCredentials(this.config.baseURL),
36
37
  });
37
38
  }
38
39
  getProviderName() {
@@ -1,6 +1,7 @@
1
1
  import { XaiModels } from "../constants/enums.js";
2
2
  import { AuthenticationError, InvalidModelError, NetworkError, ProviderError, RateLimitError, } from "../types/index.js";
3
3
  import { logger } from "../utils/logger.js";
4
+ import { redactUrlCredentials } from "../utils/logSanitize.js";
4
5
  import { createXaiConfig, getProviderModel, validateApiKey, } from "../utils/providerConfig.js";
5
6
  import { TimeoutError } from "../utils/timeout.js";
6
7
  import { OpenAIChatCompletionsProvider } from "./openaiChatCompletionsBase.js";
@@ -34,7 +35,7 @@ export class XaiProvider extends OpenAIChatCompletionsProvider {
34
35
  logger.debug("xAI Provider initialized", {
35
36
  modelName: this.modelName,
36
37
  providerName: this.providerName,
37
- baseURL: this.config.baseURL,
38
+ baseURL: redactUrlCredentials(this.config.baseURL),
38
39
  });
39
40
  }
40
41
  getProviderName() {
@@ -129,6 +129,7 @@ export type NeurolinkCredentials = {
129
129
  };
130
130
  mistral?: {
131
131
  apiKey?: string;
132
+ baseURL?: string;
132
133
  };
133
134
  huggingFace?: {
134
135
  apiKey?: string;
@@ -26,6 +26,20 @@
26
26
  * @param maxLen - Maximum number of characters to keep (default 500).
27
27
  */
28
28
  export declare function sanitizeForLog(text: string, maxLen?: number): string;
29
+ /**
30
+ * Strip embedded `user:pass@` credentials from a URL's authority component
31
+ * before logging it or surfacing it in a user-facing error.
32
+ *
33
+ * Turns `https://user:secret@host/path` into `https://***@host/path` while
34
+ * leaving credential-free URLs untouched, so the host/port/path stay useful
35
+ * for diagnostics. Use this for any `baseURL`/endpoint a caller may have
36
+ * supplied with inline credentials. The match is global, so every `//…@`
37
+ * authority in the string is redacted (e.g. a proxy chain or a URL embedded
38
+ * in a query parameter), not just the first.
39
+ *
40
+ * @param url - The URL (or URL-shaped string) to redact.
41
+ */
42
+ export declare function redactUrlCredentials(url: string): string;
29
43
  /**
30
44
  * Recursively sanitize a record/array, returning a structurally identical
31
45
  * value with sensitive keys redacted and string values run through
@@ -91,6 +91,22 @@ export function sanitizeForLog(text, maxLen = 500) {
91
91
  }
92
92
  return text.slice(0, maxLen).replace(SECRET_PATTERN, "***");
93
93
  }
94
+ /**
95
+ * Strip embedded `user:pass@` credentials from a URL's authority component
96
+ * before logging it or surfacing it in a user-facing error.
97
+ *
98
+ * Turns `https://user:secret@host/path` into `https://***@host/path` while
99
+ * leaving credential-free URLs untouched, so the host/port/path stay useful
100
+ * for diagnostics. Use this for any `baseURL`/endpoint a caller may have
101
+ * supplied with inline credentials. The match is global, so every `//…@`
102
+ * authority in the string is redacted (e.g. a proxy chain or a URL embedded
103
+ * in a query parameter), not just the first.
104
+ *
105
+ * @param url - The URL (or URL-shaped string) to redact.
106
+ */
107
+ export function redactUrlCredentials(url) {
108
+ return url.replace(/\/\/[^/@]+@/g, "//***@");
109
+ }
94
110
  /**
95
111
  * Recursively sanitize a record/array, returning a structurally identical
96
112
  * value with sensitive keys redacted and string values run through
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.68.16",
3
+ "version": "9.68.18",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "Universal AI Development Platform with working MCP integration, multi-provider support, voice (TTS/STT/realtime), and professional CLI. 58+ external MCP servers discoverable, multimodal file processing, RAG pipelines. Build, test, and deploy AI applications with 21+ providers: OpenAI, Anthropic, Google AI Studio, Google Vertex, AWS Bedrock, Azure OpenAI, Mistral, LiteLLM, SageMaker, Hugging Face, Ollama, OpenAI-compatible, OpenRouter, DeepSeek, NVIDIA NIM, LM Studio, llama.cpp, plus voice (OpenAI TTS, ElevenLabs, Deepgram, Azure Speech).",
6
6
  "author": {