@juspay/neurolink 9.68.17 → 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.
- package/CHANGELOG.md +2 -0
- package/dist/browser/neurolink.min.js +565 -565
- package/dist/lib/providers/mistral.d.ts +20 -28
- package/dist/lib/providers/mistral.js +61 -136
- package/dist/lib/types/providers.d.ts +1 -0
- package/dist/providers/mistral.d.ts +20 -28
- package/dist/providers/mistral.js +61 -136
- package/dist/types/providers.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
import type { AIProviderName } from "../constants/enums.js";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
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
|
|
7
|
-
*
|
|
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
|
|
10
|
-
private model;
|
|
18
|
+
export declare class MistralProvider extends OpenAIChatCompletionsProvider {
|
|
11
19
|
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["mistral"]);
|
|
12
|
-
protected
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
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 {
|
|
12
|
-
import {
|
|
13
|
-
|
|
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
|
-
//
|
|
22
|
-
return getProviderModel("MISTRAL_MODEL",
|
|
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
|
|
26
|
-
*
|
|
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
|
|
29
|
-
model;
|
|
30
|
+
export class MistralProvider extends OpenAIChatCompletionsProvider {
|
|
30
31
|
constructor(modelName, sdk, _region, credentials) {
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
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,36 +68,32 @@ 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("
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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;
|
|
174
99
|
//# sourceMappingURL=mistral.js.map
|
|
@@ -1,33 +1,25 @@
|
|
|
1
1
|
import type { AIProviderName } from "../constants/enums.js";
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
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
|
|
7
|
-
*
|
|
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
|
|
10
|
-
private model;
|
|
18
|
+
export declare class MistralProvider extends OpenAIChatCompletionsProvider {
|
|
11
19
|
constructor(modelName?: string, sdk?: unknown, _region?: string, credentials?: NeurolinkCredentials["mistral"]);
|
|
12
|
-
protected
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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 {
|
|
2
|
-
import {
|
|
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 {
|
|
12
|
-
import {
|
|
13
|
-
|
|
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
|
-
//
|
|
22
|
-
return getProviderModel("MISTRAL_MODEL",
|
|
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
|
|
26
|
-
*
|
|
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
|
|
29
|
-
model;
|
|
30
|
+
export class MistralProvider extends OpenAIChatCompletionsProvider {
|
|
30
31
|
constructor(modelName, sdk, _region, credentials) {
|
|
31
|
-
//
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
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
|
|
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("
|
|
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
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
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
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "9.68.
|
|
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": {
|