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.
Files changed (42) hide show
  1. package/README.md +771 -738
  2. package/docs/API.md +10 -1
  3. package/docs/PROVIDERS.md +8 -4
  4. package/package.json +12 -12
  5. package/src/async/asyncJobStore.js +82 -52
  6. package/src/async/eventBus.js +25 -20
  7. package/src/async/fileCache.js +121 -40
  8. package/src/async/jobRunner.js +65 -39
  9. package/src/async/providerStreamNormalizer.js +203 -117
  10. package/src/config.js +374 -102
  11. package/src/continuationStore.js +32 -24
  12. package/src/index.js +45 -25
  13. package/src/prompts/helpPrompt.js +328 -305
  14. package/src/providers/anthropic.js +303 -119
  15. package/src/providers/codex.js +103 -45
  16. package/src/providers/deepseek.js +24 -8
  17. package/src/providers/google.js +337 -93
  18. package/src/providers/index.js +1 -1
  19. package/src/providers/interface.js +16 -11
  20. package/src/providers/mistral.js +179 -69
  21. package/src/providers/openai-compatible.js +231 -94
  22. package/src/providers/openai.js +1094 -914
  23. package/src/providers/openrouter-endpoints-client.js +220 -216
  24. package/src/providers/openrouter.js +426 -381
  25. package/src/providers/xai.js +153 -56
  26. package/src/resources/helpResource.js +70 -67
  27. package/src/router.js +95 -67
  28. package/src/services/summarizationService.js +51 -24
  29. package/src/systemPrompts.js +89 -89
  30. package/src/tools/cancelJob.js +31 -19
  31. package/src/tools/chat.js +997 -883
  32. package/src/tools/checkStatus.js +86 -65
  33. package/src/tools/consensus.js +400 -234
  34. package/src/tools/index.js +39 -16
  35. package/src/transport/httpTransport.js +82 -55
  36. package/src/utils/contextProcessor.js +54 -37
  37. package/src/utils/errorHandler.js +95 -45
  38. package/src/utils/fileValidator.js +107 -98
  39. package/src/utils/formatStatus.js +122 -64
  40. package/src/utils/logger.js +459 -449
  41. package/src/utils/pathUtils.js +2 -2
  42. package/src/utils/tokenLimiter.js +216 -216
@@ -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 = ['invoke', 'validateConfig', 'isAvailable', 'getSupportedModels', 'getModelConfig'];
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', // Normal completion
208
- LENGTH: 'length', // Max tokens reached
209
- TOOL_USE: 'tool_use', // Tool use requested
210
- CONTENT_FILTER: 'content_filter', // Content filtered
211
- SAFETY: 'safety', // Safety filter triggered
212
- ERROR: 'error', // Error occurred
213
- OTHER: 'other' // Other reason
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
-
@@ -21,8 +21,15 @@ const SUPPORTED_MODELS = {
21
21
  supportsWebSearch: false,
22
22
  supportsReasoning: true,
23
23
  timeout: 300000,
24
- description: 'Magistral Medium 1.2 - Frontier-class reasoning model with vision support (September 2025)',
25
- aliases: ['magistral-medium', 'magistral-medium-latest', 'magistral', 'magistral medium', 'magistral-medium-1.2']
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: 'Magistral Small 1.2 - Small reasoning model with vision support (September 2025)',
39
- aliases: ['magistral-small', 'magistral-small-latest', 'magistral small', 'magistral-small-1.2']
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: 'Mistral Medium 3.1 - Frontier-class multimodal model with improved tone and performance (August 2025)',
52
- aliases: ['mistral-medium-3.1', 'mistral-medium-latest', 'mistral-medium', 'mistral medium 3.1', 'mistral', 'medium-3.1', 'mistral-medium-3']
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
- 'stop': StopReasons.STOP,
61
- 'length': StopReasons.LENGTH,
62
- 'model_length': StopReasons.LENGTH,
63
- 'tool_calls': StopReasons.TOOL_USE,
64
- 'error': StopReasons.ERROR
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('Messages must be an array', ErrorCodes.INVALID_MESSAGES);
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(`Message at index ${index} must be an object`, ErrorCodes.INVALID_MESSAGE);
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(`Invalid role "${role}" at message index ${index}`, ErrorCodes.INVALID_ROLE);
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(`Message content is required at index ${index}`, ErrorCodes.MISSING_CONTENT);
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(`[Mistral] Converting image: ${item.source.media_type}, data length: ${item.source.data.length}`);
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(parseInt(headers['x-ratelimit-reset']) * 1000);
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('Mistral API key not configured', ErrorCodes.MISSING_API_KEY);
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('Invalid Mistral API key format', ErrorCodes.INVALID_API_KEY);
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(msg =>
259
- Array.isArray(msg.content) &&
260
- msg.content.some(item => item.type === 'image')
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(maxTokens, modelConfig.maxOutputTokens || 32768);
286
- requestPayload.max_tokens = tokenLimit; // Standard parameter name
287
- requestPayload.maxTokens = tokenLimit; // Alternative parameter name
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(mistral, requestPayload, resolvedModel, modelConfig);
340
+ return this._createStreamingGenerator(
341
+ mistral,
342
+ requestPayload,
343
+ resolvedModel,
344
+ modelConfig,
345
+ );
293
346
  }
294
347
 
295
348
  try {
296
- debugLog(`[Mistral] Calling ${resolvedModel} with ${mistralMessages.length} messages`);
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('No response choice received from Mistral', ErrorCodes.NO_RESPONSE_CHOICE);
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('No content in response from Mistral', ErrorCodes.NO_RESPONSE_CONTENT);
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('Invalid Mistral API key', ErrorCodes.INVALID_API_KEY, error);
357
- } else if (error.status === 429 || error.message?.includes('rate limit')) {
358
- throw new MistralProviderError('Mistral rate limit exceeded', ErrorCodes.RATE_LIMIT_EXCEEDED, error);
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('Mistral API quota exceeded', ErrorCodes.QUOTA_EXCEEDED, error);
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(`Model ${resolvedModel} not found`, ErrorCodes.MODEL_NOT_FOUND, error);
363
- } else if (error.status === 400 || error.message?.includes('Invalid request')) {
364
- throw new MistralProviderError(`Invalid request: ${error.message}`, ErrorCodes.INVALID_REQUEST, error);
365
- } else if (error.message?.includes('Context length exceeded') || error.message?.includes('context')) {
366
- throw new MistralProviderError('Context length exceeded for model', ErrorCodes.CONTEXT_LENGTH_EXCEEDED, error);
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(mistral, requestPayload, resolvedModel, modelConfig) {
387
- debugLog(`[Mistral] Starting streaming for ${resolvedModel} with ${requestPayload.messages?.length} messages`);
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 (finishReason && finishReason !== null && finishReason !== 'null') {
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 (error.status === 429 || error.message?.includes('rate limit')) {
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 (error.message?.includes('Context length exceeded') || error.message?.includes('context')) {
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 !!(config?.apiKeys?.mistral && validateApiKey(config.apiKeys.mistral));
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
-