converse-mcp-server 2.3.1 → 2.4.1
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/README.md +771 -738
- package/docs/API.md +10 -1
- package/docs/PROVIDERS.md +8 -4
- package/package.json +12 -12
- package/src/async/asyncJobStore.js +82 -52
- package/src/async/eventBus.js +25 -20
- package/src/async/fileCache.js +121 -40
- package/src/async/jobRunner.js +65 -39
- package/src/async/providerStreamNormalizer.js +203 -117
- package/src/config.js +374 -102
- package/src/continuationStore.js +32 -24
- package/src/index.js +45 -25
- package/src/prompts/helpPrompt.js +328 -305
- package/src/providers/anthropic.js +303 -119
- package/src/providers/codex.js +103 -45
- package/src/providers/deepseek.js +24 -8
- package/src/providers/google.js +337 -93
- package/src/providers/index.js +1 -1
- package/src/providers/interface.js +16 -11
- package/src/providers/mistral.js +179 -69
- package/src/providers/openai-compatible.js +231 -94
- package/src/providers/openai.js +1094 -914
- package/src/providers/openrouter-endpoints-client.js +220 -216
- package/src/providers/openrouter.js +426 -381
- package/src/providers/xai.js +153 -56
- package/src/resources/helpResource.js +70 -67
- package/src/router.js +95 -67
- package/src/services/summarizationService.js +51 -24
- package/src/systemPrompts.js +89 -89
- package/src/tools/cancelJob.js +31 -19
- package/src/tools/chat.js +997 -883
- package/src/tools/checkStatus.js +86 -65
- package/src/tools/consensus.js +400 -234
- package/src/tools/index.js +39 -16
- package/src/transport/httpTransport.js +82 -55
- package/src/utils/contextProcessor.js +54 -37
- package/src/utils/errorHandler.js +95 -45
- package/src/utils/fileValidator.js +107 -98
- package/src/utils/formatStatus.js +122 -64
- package/src/utils/logger.js +459 -449
- package/src/utils/pathUtils.js +2 -2
- package/src/utils/tokenLimiter.js +216 -216
package/src/providers/index.js
CHANGED
|
@@ -70,7 +70,7 @@ export function registerProvider(name, provider) {
|
|
|
70
70
|
* @returns {string[]} Array of available provider names
|
|
71
71
|
*/
|
|
72
72
|
export function getAvailableProviders(config) {
|
|
73
|
-
return Object.keys(providers).filter(name => {
|
|
73
|
+
return Object.keys(providers).filter((name) => {
|
|
74
74
|
const provider = providers[name];
|
|
75
75
|
return provider.isAvailable && provider.isAvailable(config);
|
|
76
76
|
});
|
|
@@ -128,7 +128,7 @@ export const ProviderInterface = {
|
|
|
128
128
|
*/
|
|
129
129
|
getModelConfig(_modelName) {
|
|
130
130
|
throw new Error('Provider must implement getModelConfig method');
|
|
131
|
-
}
|
|
131
|
+
},
|
|
132
132
|
};
|
|
133
133
|
|
|
134
134
|
/**
|
|
@@ -179,7 +179,7 @@ export const ErrorCodes = {
|
|
|
179
179
|
// Other errors
|
|
180
180
|
API_ERROR: 'API_ERROR',
|
|
181
181
|
TIMEOUT_ERROR: 'TIMEOUT_ERROR',
|
|
182
|
-
NETWORK_ERROR: 'NETWORK_ERROR'
|
|
182
|
+
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
183
183
|
};
|
|
184
184
|
|
|
185
185
|
/**
|
|
@@ -189,7 +189,13 @@ export const ErrorCodes = {
|
|
|
189
189
|
* @throws {Error} - If provider is invalid
|
|
190
190
|
*/
|
|
191
191
|
export function validateProvider(provider) {
|
|
192
|
-
const requiredMethods = [
|
|
192
|
+
const requiredMethods = [
|
|
193
|
+
'invoke',
|
|
194
|
+
'validateConfig',
|
|
195
|
+
'isAvailable',
|
|
196
|
+
'getSupportedModels',
|
|
197
|
+
'getModelConfig',
|
|
198
|
+
];
|
|
193
199
|
|
|
194
200
|
for (const method of requiredMethods) {
|
|
195
201
|
if (typeof provider[method] !== 'function') {
|
|
@@ -204,12 +210,11 @@ export function validateProvider(provider) {
|
|
|
204
210
|
* Common stop reasons that providers should map to
|
|
205
211
|
*/
|
|
206
212
|
export const StopReasons = {
|
|
207
|
-
STOP: 'stop',
|
|
208
|
-
LENGTH: 'length',
|
|
209
|
-
TOOL_USE: 'tool_use',
|
|
210
|
-
CONTENT_FILTER: 'content_filter',
|
|
211
|
-
SAFETY: 'safety',
|
|
212
|
-
ERROR: 'error',
|
|
213
|
-
OTHER: 'other'
|
|
213
|
+
STOP: 'stop', // Normal completion
|
|
214
|
+
LENGTH: 'length', // Max tokens reached
|
|
215
|
+
TOOL_USE: 'tool_use', // Tool use requested
|
|
216
|
+
CONTENT_FILTER: 'content_filter', // Content filtered
|
|
217
|
+
SAFETY: 'safety', // Safety filter triggered
|
|
218
|
+
ERROR: 'error', // Error occurred
|
|
219
|
+
OTHER: 'other', // Other reason
|
|
214
220
|
};
|
|
215
|
-
|
package/src/providers/mistral.js
CHANGED
|
@@ -21,8 +21,15 @@ const SUPPORTED_MODELS = {
|
|
|
21
21
|
supportsWebSearch: false,
|
|
22
22
|
supportsReasoning: true,
|
|
23
23
|
timeout: 300000,
|
|
24
|
-
description:
|
|
25
|
-
|
|
24
|
+
description:
|
|
25
|
+
'Magistral Medium 1.2 - Frontier-class reasoning model with vision support (September 2025)',
|
|
26
|
+
aliases: [
|
|
27
|
+
'magistral-medium',
|
|
28
|
+
'magistral-medium-latest',
|
|
29
|
+
'magistral',
|
|
30
|
+
'magistral medium',
|
|
31
|
+
'magistral-medium-1.2',
|
|
32
|
+
],
|
|
26
33
|
},
|
|
27
34
|
'magistral-small-2509': {
|
|
28
35
|
modelName: 'magistral-small-2509',
|
|
@@ -35,8 +42,14 @@ const SUPPORTED_MODELS = {
|
|
|
35
42
|
supportsWebSearch: false,
|
|
36
43
|
supportsReasoning: true,
|
|
37
44
|
timeout: 180000,
|
|
38
|
-
description:
|
|
39
|
-
|
|
45
|
+
description:
|
|
46
|
+
'Magistral Small 1.2 - Small reasoning model with vision support (September 2025)',
|
|
47
|
+
aliases: [
|
|
48
|
+
'magistral-small',
|
|
49
|
+
'magistral-small-latest',
|
|
50
|
+
'magistral small',
|
|
51
|
+
'magistral-small-1.2',
|
|
52
|
+
],
|
|
40
53
|
},
|
|
41
54
|
'mistral-medium-2508': {
|
|
42
55
|
modelName: 'mistral-medium-2508',
|
|
@@ -48,20 +61,29 @@ const SUPPORTED_MODELS = {
|
|
|
48
61
|
supportsTemperature: true,
|
|
49
62
|
supportsWebSearch: false,
|
|
50
63
|
timeout: 300000,
|
|
51
|
-
description:
|
|
52
|
-
|
|
53
|
-
|
|
64
|
+
description:
|
|
65
|
+
'Mistral Medium 3.1 - Frontier-class multimodal model with improved tone and performance (August 2025)',
|
|
66
|
+
aliases: [
|
|
67
|
+
'mistral-medium-3.1',
|
|
68
|
+
'mistral-medium-latest',
|
|
69
|
+
'mistral-medium',
|
|
70
|
+
'mistral medium 3.1',
|
|
71
|
+
'mistral',
|
|
72
|
+
'medium-3.1',
|
|
73
|
+
'mistral-medium-3',
|
|
74
|
+
],
|
|
75
|
+
},
|
|
54
76
|
};
|
|
55
77
|
|
|
56
78
|
/**
|
|
57
79
|
* Map Mistral finish reasons to unified format
|
|
58
80
|
*/
|
|
59
81
|
const STOP_REASON_MAP = {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
82
|
+
stop: StopReasons.STOP,
|
|
83
|
+
length: StopReasons.LENGTH,
|
|
84
|
+
model_length: StopReasons.LENGTH,
|
|
85
|
+
tool_calls: StopReasons.TOOL_USE,
|
|
86
|
+
error: StopReasons.ERROR,
|
|
65
87
|
};
|
|
66
88
|
|
|
67
89
|
/**
|
|
@@ -119,22 +141,34 @@ function validateApiKey(apiKey) {
|
|
|
119
141
|
*/
|
|
120
142
|
function convertMessagesToMistral(messages) {
|
|
121
143
|
if (!Array.isArray(messages)) {
|
|
122
|
-
throw new MistralProviderError(
|
|
144
|
+
throw new MistralProviderError(
|
|
145
|
+
'Messages must be an array',
|
|
146
|
+
ErrorCodes.INVALID_MESSAGES,
|
|
147
|
+
);
|
|
123
148
|
}
|
|
124
149
|
|
|
125
150
|
return messages.map((msg, index) => {
|
|
126
151
|
if (!msg || typeof msg !== 'object') {
|
|
127
|
-
throw new MistralProviderError(
|
|
152
|
+
throw new MistralProviderError(
|
|
153
|
+
`Message at index ${index} must be an object`,
|
|
154
|
+
ErrorCodes.INVALID_MESSAGE,
|
|
155
|
+
);
|
|
128
156
|
}
|
|
129
157
|
|
|
130
158
|
const { role, content } = msg;
|
|
131
159
|
|
|
132
160
|
if (!role || !['system', 'user', 'assistant'].includes(role)) {
|
|
133
|
-
throw new MistralProviderError(
|
|
161
|
+
throw new MistralProviderError(
|
|
162
|
+
`Invalid role "${role}" at message index ${index}`,
|
|
163
|
+
ErrorCodes.INVALID_ROLE,
|
|
164
|
+
);
|
|
134
165
|
}
|
|
135
166
|
|
|
136
167
|
if (!content) {
|
|
137
|
-
throw new MistralProviderError(
|
|
168
|
+
throw new MistralProviderError(
|
|
169
|
+
`Message content is required at index ${index}`,
|
|
170
|
+
ErrorCodes.MISSING_CONTENT,
|
|
171
|
+
);
|
|
138
172
|
}
|
|
139
173
|
|
|
140
174
|
// Handle complex content structure (array with text and images)
|
|
@@ -145,15 +179,17 @@ function convertMessagesToMistral(messages) {
|
|
|
145
179
|
if (item.type === 'text') {
|
|
146
180
|
mistralContent.push({
|
|
147
181
|
type: 'text',
|
|
148
|
-
text: item.text
|
|
182
|
+
text: item.text,
|
|
149
183
|
});
|
|
150
184
|
} else if (item.type === 'image' && item.source) {
|
|
151
185
|
// Convert Anthropic/Claude format to Mistral format
|
|
152
186
|
mistralContent.push({
|
|
153
187
|
type: 'image_url',
|
|
154
|
-
imageUrl: `data:${item.source.media_type};base64,${item.source.data}
|
|
188
|
+
imageUrl: `data:${item.source.media_type};base64,${item.source.data}`,
|
|
155
189
|
});
|
|
156
|
-
debugLog(
|
|
190
|
+
debugLog(
|
|
191
|
+
`[Mistral] Converting image: ${item.source.media_type}, data length: ${item.source.data.length}`,
|
|
192
|
+
);
|
|
157
193
|
}
|
|
158
194
|
}
|
|
159
195
|
|
|
@@ -177,7 +213,7 @@ async function getMistralSDK() {
|
|
|
177
213
|
throw new MistralProviderError(
|
|
178
214
|
'Failed to load Mistral SDK. Please install @mistralai/mistralai',
|
|
179
215
|
ErrorCodes.API_ERROR,
|
|
180
|
-
error
|
|
216
|
+
error,
|
|
181
217
|
);
|
|
182
218
|
}
|
|
183
219
|
}
|
|
@@ -200,7 +236,9 @@ function extractRateLimitInfo(headers) {
|
|
|
200
236
|
rateLimitInfo.remaining = parseInt(headers['x-ratelimit-remaining']);
|
|
201
237
|
}
|
|
202
238
|
if (headers['x-ratelimit-reset']) {
|
|
203
|
-
rateLimitInfo.reset = new Date(
|
|
239
|
+
rateLimitInfo.reset = new Date(
|
|
240
|
+
parseInt(headers['x-ratelimit-reset']) * 1000,
|
|
241
|
+
);
|
|
204
242
|
}
|
|
205
243
|
|
|
206
244
|
return Object.keys(rateLimitInfo).length > 0 ? rateLimitInfo : null;
|
|
@@ -232,11 +270,17 @@ export const mistralProvider = {
|
|
|
232
270
|
|
|
233
271
|
// Validate API key
|
|
234
272
|
if (!config?.apiKeys?.mistral) {
|
|
235
|
-
throw new MistralProviderError(
|
|
273
|
+
throw new MistralProviderError(
|
|
274
|
+
'Mistral API key not configured',
|
|
275
|
+
ErrorCodes.MISSING_API_KEY,
|
|
276
|
+
);
|
|
236
277
|
}
|
|
237
278
|
|
|
238
279
|
if (!validateApiKey(config.apiKeys.mistral)) {
|
|
239
|
-
throw new MistralProviderError(
|
|
280
|
+
throw new MistralProviderError(
|
|
281
|
+
'Invalid Mistral API key format',
|
|
282
|
+
ErrorCodes.INVALID_API_KEY,
|
|
283
|
+
);
|
|
240
284
|
}
|
|
241
285
|
|
|
242
286
|
// Get Mistral SDK
|
|
@@ -255,15 +299,16 @@ export const mistralProvider = {
|
|
|
255
299
|
const mistralMessages = convertMessagesToMistral(messages);
|
|
256
300
|
|
|
257
301
|
// Check if messages contain images and if model supports them
|
|
258
|
-
const hasImages = messages.some(
|
|
259
|
-
|
|
260
|
-
|
|
302
|
+
const hasImages = messages.some(
|
|
303
|
+
(msg) =>
|
|
304
|
+
Array.isArray(msg.content) &&
|
|
305
|
+
msg.content.some((item) => item.type === 'image'),
|
|
261
306
|
);
|
|
262
307
|
|
|
263
308
|
if (hasImages && !modelConfig.supportsImages) {
|
|
264
309
|
throw new MistralProviderError(
|
|
265
310
|
`Model ${resolvedModel} does not support images`,
|
|
266
|
-
ErrorCodes.INVALID_REQUEST
|
|
311
|
+
ErrorCodes.INVALID_REQUEST,
|
|
267
312
|
);
|
|
268
313
|
}
|
|
269
314
|
|
|
@@ -272,7 +317,7 @@ export const mistralProvider = {
|
|
|
272
317
|
model: resolvedModel,
|
|
273
318
|
messages: mistralMessages,
|
|
274
319
|
stream,
|
|
275
|
-
...otherOptions
|
|
320
|
+
...otherOptions,
|
|
276
321
|
};
|
|
277
322
|
|
|
278
323
|
// Add temperature if specified
|
|
@@ -282,18 +327,28 @@ export const mistralProvider = {
|
|
|
282
327
|
|
|
283
328
|
// Add max tokens if specified
|
|
284
329
|
if (maxTokens) {
|
|
285
|
-
const tokenLimit = Math.min(
|
|
286
|
-
|
|
287
|
-
|
|
330
|
+
const tokenLimit = Math.min(
|
|
331
|
+
maxTokens,
|
|
332
|
+
modelConfig.maxOutputTokens || 32768,
|
|
333
|
+
);
|
|
334
|
+
requestPayload.max_tokens = tokenLimit; // Standard parameter name
|
|
335
|
+
requestPayload.maxTokens = tokenLimit; // Alternative parameter name
|
|
288
336
|
}
|
|
289
337
|
|
|
290
338
|
// Handle streaming requests
|
|
291
339
|
if (stream && modelConfig.supportsStreaming !== false) {
|
|
292
|
-
return this._createStreamingGenerator(
|
|
340
|
+
return this._createStreamingGenerator(
|
|
341
|
+
mistral,
|
|
342
|
+
requestPayload,
|
|
343
|
+
resolvedModel,
|
|
344
|
+
modelConfig,
|
|
345
|
+
);
|
|
293
346
|
}
|
|
294
347
|
|
|
295
348
|
try {
|
|
296
|
-
debugLog(
|
|
349
|
+
debugLog(
|
|
350
|
+
`[Mistral] Calling ${resolvedModel} with ${mistralMessages.length} messages`,
|
|
351
|
+
);
|
|
297
352
|
|
|
298
353
|
const startTime = Date.now();
|
|
299
354
|
|
|
@@ -306,12 +361,18 @@ export const mistralProvider = {
|
|
|
306
361
|
// Extract response data
|
|
307
362
|
const choice = response.choices?.[0];
|
|
308
363
|
if (!choice) {
|
|
309
|
-
throw new MistralProviderError(
|
|
364
|
+
throw new MistralProviderError(
|
|
365
|
+
'No response choice received from Mistral',
|
|
366
|
+
ErrorCodes.NO_RESPONSE_CHOICE,
|
|
367
|
+
);
|
|
310
368
|
}
|
|
311
369
|
|
|
312
370
|
const content = choice.message?.content;
|
|
313
371
|
if (!content) {
|
|
314
|
-
throw new MistralProviderError(
|
|
372
|
+
throw new MistralProviderError(
|
|
373
|
+
'No content in response from Mistral',
|
|
374
|
+
ErrorCodes.NO_RESPONSE_CONTENT,
|
|
375
|
+
);
|
|
315
376
|
}
|
|
316
377
|
|
|
317
378
|
// Map finish reason
|
|
@@ -334,15 +395,14 @@ export const mistralProvider = {
|
|
|
334
395
|
usage: {
|
|
335
396
|
input_tokens: usage.prompt_tokens || 0,
|
|
336
397
|
output_tokens: usage.completion_tokens || 0,
|
|
337
|
-
total_tokens: usage.total_tokens || 0
|
|
398
|
+
total_tokens: usage.total_tokens || 0,
|
|
338
399
|
},
|
|
339
400
|
response_time_ms: responseTime,
|
|
340
401
|
finish_reason: finishReason,
|
|
341
402
|
provider: 'mistral',
|
|
342
|
-
rate_limit: rateLimitInfo
|
|
343
|
-
}
|
|
403
|
+
rate_limit: rateLimitInfo,
|
|
404
|
+
},
|
|
344
405
|
};
|
|
345
|
-
|
|
346
406
|
} catch (error) {
|
|
347
407
|
debugError('[Mistral] Error during API call:', error);
|
|
348
408
|
|
|
@@ -353,24 +413,57 @@ export const mistralProvider = {
|
|
|
353
413
|
|
|
354
414
|
// Handle specific Mistral errors
|
|
355
415
|
if (error.status === 401 || error.message?.includes('Unauthorized')) {
|
|
356
|
-
throw new MistralProviderError(
|
|
357
|
-
|
|
358
|
-
|
|
416
|
+
throw new MistralProviderError(
|
|
417
|
+
'Invalid Mistral API key',
|
|
418
|
+
ErrorCodes.INVALID_API_KEY,
|
|
419
|
+
error,
|
|
420
|
+
);
|
|
421
|
+
} else if (
|
|
422
|
+
error.status === 429 ||
|
|
423
|
+
error.message?.includes('rate limit')
|
|
424
|
+
) {
|
|
425
|
+
throw new MistralProviderError(
|
|
426
|
+
'Mistral rate limit exceeded',
|
|
427
|
+
ErrorCodes.RATE_LIMIT_EXCEEDED,
|
|
428
|
+
error,
|
|
429
|
+
);
|
|
359
430
|
} else if (error.status === 403 || error.message?.includes('quota')) {
|
|
360
|
-
throw new MistralProviderError(
|
|
431
|
+
throw new MistralProviderError(
|
|
432
|
+
'Mistral API quota exceeded',
|
|
433
|
+
ErrorCodes.QUOTA_EXCEEDED,
|
|
434
|
+
error,
|
|
435
|
+
);
|
|
361
436
|
} else if (error.status === 404 || error.message?.includes('model')) {
|
|
362
|
-
throw new MistralProviderError(
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
437
|
+
throw new MistralProviderError(
|
|
438
|
+
`Model ${resolvedModel} not found`,
|
|
439
|
+
ErrorCodes.MODEL_NOT_FOUND,
|
|
440
|
+
error,
|
|
441
|
+
);
|
|
442
|
+
} else if (
|
|
443
|
+
error.status === 400 ||
|
|
444
|
+
error.message?.includes('Invalid request')
|
|
445
|
+
) {
|
|
446
|
+
throw new MistralProviderError(
|
|
447
|
+
`Invalid request: ${error.message}`,
|
|
448
|
+
ErrorCodes.INVALID_REQUEST,
|
|
449
|
+
error,
|
|
450
|
+
);
|
|
451
|
+
} else if (
|
|
452
|
+
error.message?.includes('Context length exceeded') ||
|
|
453
|
+
error.message?.includes('context')
|
|
454
|
+
) {
|
|
455
|
+
throw new MistralProviderError(
|
|
456
|
+
'Context length exceeded for model',
|
|
457
|
+
ErrorCodes.CONTEXT_LENGTH_EXCEEDED,
|
|
458
|
+
error,
|
|
459
|
+
);
|
|
367
460
|
}
|
|
368
461
|
|
|
369
462
|
// Generic error handling
|
|
370
463
|
throw new MistralProviderError(
|
|
371
464
|
`Mistral API error: ${error.message || 'Unknown error'}`,
|
|
372
465
|
ErrorCodes.API_ERROR,
|
|
373
|
-
error
|
|
466
|
+
error,
|
|
374
467
|
);
|
|
375
468
|
}
|
|
376
469
|
},
|
|
@@ -383,8 +476,15 @@ export const mistralProvider = {
|
|
|
383
476
|
* @param {Object} modelConfig - Model configuration
|
|
384
477
|
* @returns {AsyncGenerator} - Streaming generator yielding events
|
|
385
478
|
*/
|
|
386
|
-
async *_createStreamingGenerator(
|
|
387
|
-
|
|
479
|
+
async *_createStreamingGenerator(
|
|
480
|
+
mistral,
|
|
481
|
+
requestPayload,
|
|
482
|
+
resolvedModel,
|
|
483
|
+
modelConfig,
|
|
484
|
+
) {
|
|
485
|
+
debugLog(
|
|
486
|
+
`[Mistral] Starting streaming for ${resolvedModel} with ${requestPayload.messages?.length} messages`,
|
|
487
|
+
);
|
|
388
488
|
|
|
389
489
|
const startTime = Date.now();
|
|
390
490
|
let totalContent = '';
|
|
@@ -397,7 +497,7 @@ export const mistralProvider = {
|
|
|
397
497
|
type: 'start',
|
|
398
498
|
timestamp: new Date().toISOString(),
|
|
399
499
|
model: resolvedModel,
|
|
400
|
-
provider: 'mistral'
|
|
500
|
+
provider: 'mistral',
|
|
401
501
|
};
|
|
402
502
|
|
|
403
503
|
// Create stream using Mistral SDK's streaming API
|
|
@@ -418,7 +518,7 @@ export const mistralProvider = {
|
|
|
418
518
|
yield {
|
|
419
519
|
type: 'delta',
|
|
420
520
|
content,
|
|
421
|
-
timestamp: new Date().toISOString()
|
|
521
|
+
timestamp: new Date().toISOString(),
|
|
422
522
|
};
|
|
423
523
|
}
|
|
424
524
|
|
|
@@ -434,7 +534,11 @@ export const mistralProvider = {
|
|
|
434
534
|
}
|
|
435
535
|
|
|
436
536
|
// Break if we have a finish reason indicating completion
|
|
437
|
-
if (
|
|
537
|
+
if (
|
|
538
|
+
finishReason &&
|
|
539
|
+
finishReason !== null &&
|
|
540
|
+
finishReason !== 'null'
|
|
541
|
+
) {
|
|
438
542
|
break;
|
|
439
543
|
}
|
|
440
544
|
} catch (chunkError) {
|
|
@@ -444,9 +548,9 @@ export const mistralProvider = {
|
|
|
444
548
|
error: {
|
|
445
549
|
message: `Chunk processing error: ${chunkError.message}`,
|
|
446
550
|
code: 'CHUNK_PROCESSING_ERROR',
|
|
447
|
-
recoverable: true
|
|
551
|
+
recoverable: true,
|
|
448
552
|
},
|
|
449
|
-
timestamp: new Date().toISOString()
|
|
553
|
+
timestamp: new Date().toISOString(),
|
|
450
554
|
};
|
|
451
555
|
}
|
|
452
556
|
}
|
|
@@ -461,9 +565,9 @@ export const mistralProvider = {
|
|
|
461
565
|
usage: {
|
|
462
566
|
input_tokens: finalUsage.prompt_tokens || 0,
|
|
463
567
|
output_tokens: finalUsage.completion_tokens || 0,
|
|
464
|
-
total_tokens: finalUsage.total_tokens || 0
|
|
568
|
+
total_tokens: finalUsage.total_tokens || 0,
|
|
465
569
|
},
|
|
466
|
-
timestamp: new Date().toISOString()
|
|
570
|
+
timestamp: new Date().toISOString(),
|
|
467
571
|
};
|
|
468
572
|
}
|
|
469
573
|
|
|
@@ -477,15 +581,14 @@ export const mistralProvider = {
|
|
|
477
581
|
usage: {
|
|
478
582
|
input_tokens: finalUsage?.prompt_tokens || 0,
|
|
479
583
|
output_tokens: finalUsage?.completion_tokens || 0,
|
|
480
|
-
total_tokens: finalUsage?.total_tokens || 0
|
|
584
|
+
total_tokens: finalUsage?.total_tokens || 0,
|
|
481
585
|
},
|
|
482
586
|
response_time_ms: responseTime,
|
|
483
587
|
finish_reason: finishReason || 'stop',
|
|
484
|
-
provider: 'mistral'
|
|
588
|
+
provider: 'mistral',
|
|
485
589
|
},
|
|
486
|
-
timestamp: new Date().toISOString()
|
|
590
|
+
timestamp: new Date().toISOString(),
|
|
487
591
|
};
|
|
488
|
-
|
|
489
592
|
} catch (error) {
|
|
490
593
|
debugError('[Mistral] Streaming error:', error);
|
|
491
594
|
|
|
@@ -497,7 +600,10 @@ export const mistralProvider = {
|
|
|
497
600
|
if (error.status === 401 || error.message?.includes('Unauthorized')) {
|
|
498
601
|
errorCode = ErrorCodes.INVALID_API_KEY;
|
|
499
602
|
errorMessage = 'Invalid Mistral API key';
|
|
500
|
-
} else if (
|
|
603
|
+
} else if (
|
|
604
|
+
error.status === 429 ||
|
|
605
|
+
error.message?.includes('rate limit')
|
|
606
|
+
) {
|
|
501
607
|
errorCode = ErrorCodes.RATE_LIMIT_EXCEEDED;
|
|
502
608
|
errorMessage = 'Mistral rate limit exceeded';
|
|
503
609
|
recoverable = true;
|
|
@@ -507,7 +613,10 @@ export const mistralProvider = {
|
|
|
507
613
|
} else if (error.status === 404 || error.message?.includes('model')) {
|
|
508
614
|
errorCode = ErrorCodes.MODEL_NOT_FOUND;
|
|
509
615
|
errorMessage = `Model ${resolvedModel} not found`;
|
|
510
|
-
} else if (
|
|
616
|
+
} else if (
|
|
617
|
+
error.message?.includes('Context length exceeded') ||
|
|
618
|
+
error.message?.includes('context')
|
|
619
|
+
) {
|
|
511
620
|
errorCode = ErrorCodes.CONTEXT_LENGTH_EXCEEDED;
|
|
512
621
|
errorMessage = 'Context length exceeded for model';
|
|
513
622
|
}
|
|
@@ -517,9 +626,9 @@ export const mistralProvider = {
|
|
|
517
626
|
error: {
|
|
518
627
|
message: errorMessage,
|
|
519
628
|
code: errorCode,
|
|
520
|
-
recoverable
|
|
629
|
+
recoverable,
|
|
521
630
|
},
|
|
522
|
-
timestamp: new Date().toISOString()
|
|
631
|
+
timestamp: new Date().toISOString(),
|
|
523
632
|
};
|
|
524
633
|
|
|
525
634
|
// Re-throw as MistralProviderError for consistency
|
|
@@ -533,7 +642,9 @@ export const mistralProvider = {
|
|
|
533
642
|
* @returns {boolean} - True if configuration is valid
|
|
534
643
|
*/
|
|
535
644
|
validateConfig(config) {
|
|
536
|
-
return !!(
|
|
645
|
+
return !!(
|
|
646
|
+
config?.apiKeys?.mistral && validateApiKey(config.apiKeys.mistral)
|
|
647
|
+
);
|
|
537
648
|
},
|
|
538
649
|
|
|
539
650
|
/**
|
|
@@ -561,6 +672,5 @@ export const mistralProvider = {
|
|
|
561
672
|
getModelConfig(modelName) {
|
|
562
673
|
const resolved = resolveModelName(modelName);
|
|
563
674
|
return SUPPORTED_MODELS[resolved] || null;
|
|
564
|
-
}
|
|
675
|
+
},
|
|
565
676
|
};
|
|
566
|
-
|