Skip to content

Commit d2fe8b4

Browse files
feat: Kiro Mistral integration
1 parent 4ade3da commit d2fe8b4

File tree

2 files changed

+40
-14
lines changed

2 files changed

+40
-14
lines changed

.kiro/specs/api-integrations/tasks.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
- Implement Gemini-specific error handling and response parsing
1919
- _Requirements: 1.2, 2.2, 4.2_
2020

21-
- [ ] 4. Implement direct Mistral API integration
21+
- [x] 4. Implement direct Mistral API integration
2222
- Replace proxy API call with direct Mistral API call
2323
- Add proper request formatting for Mistral's API structure
2424
- Implement Mistral-specific error handling and response parsing

lib/ai-providers.ts

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -295,30 +295,55 @@ export class MistralProvider implements AIProvider {
295295
): Promise<string> {
296296
this.validateRequest(question, correctAnswers, apiKey);
297297

298+
const prompt = `Question: ${question}\n\nCorrect answers: ${correctAnswers.join(
299+
", ",
300+
)}\n\nPlease provide a clear and concise explanation of why these answers are correct. Focus on the key concepts and reasoning.`;
301+
298302
try {
299-
const response = await fetch("/api/ai/mistral", {
303+
const response = await fetch("https://api.mistral.ai/v1/chat/completions", {
300304
method: "POST",
301-
headers: { "Content-Type": "application/json" },
305+
headers: {
306+
"Authorization": `Bearer ${apiKey}`,
307+
"Content-Type": "application/json",
308+
},
302309
body: JSON.stringify({
303-
question,
304-
correctAnswers,
305-
apiKey,
310+
model: "mistral-medium",
311+
messages: [
312+
{
313+
role: "user",
314+
content: prompt,
315+
},
316+
],
317+
max_tokens: 500,
318+
temperature: 0.7,
306319
}),
307320
});
308321

309322
if (!response.ok) {
310-
const errorType = response.status === 401 ? 'auth' :
311-
response.status === 429 ? 'rate_limit' : 'network';
312-
throw new AIProviderError(this.name, errorType, `Mistral API error: ${response.status}`);
323+
const errorData = await response.json().catch(() => ({}));
324+
const errorMessage = errorData.message || errorData.error?.message || `HTTP ${response.status}`;
325+
326+
// Mistral-specific error handling
327+
if (response.status === 401) {
328+
throw new AIProviderError(this.name, 'auth', `Authentication failed: ${errorMessage}`);
329+
} else if (response.status === 429) {
330+
throw new AIProviderError(this.name, 'rate_limit', `Rate limit exceeded: ${errorMessage}`);
331+
} else if (response.status === 400) {
332+
throw new AIProviderError(this.name, 'validation', `Invalid request: ${errorMessage}`);
333+
} else if (response.status >= 500) {
334+
throw new AIProviderError(this.name, 'network', `Mistral server error: ${errorMessage}`);
335+
} else {
336+
throw new AIProviderError(this.name, 'network', `Mistral API error: ${errorMessage}`);
337+
}
313338
}
314339

315340
const data = await response.json();
316341

317-
if (!data.explanation) {
318-
throw new AIProviderError(this.name, 'validation', 'Invalid response from Mistral');
342+
if (!data.choices?.[0]?.message?.content) {
343+
throw new AIProviderError(this.name, 'validation', 'Invalid response structure from Mistral');
319344
}
320345

321-
return data.explanation;
346+
return data.choices[0].message.content;
322347
} catch (error) {
323348
if (error instanceof AIProviderError) throw error;
324349
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
@@ -331,7 +356,8 @@ export class MistralProvider implements AIProvider {
331356
}
332357

333358
validateConfig(apiKey?: string): boolean {
334-
return !!(apiKey && apiKey.length > 10); // Basic validation for Mistral keys
359+
// Mistral API keys typically start with a specific pattern and have reasonable length
360+
return !!(apiKey && apiKey.length > 20);
335361
}
336362

337363
private validateRequest(question: string, correctAnswers: string[], apiKey: string): void {
@@ -342,7 +368,7 @@ export class MistralProvider implements AIProvider {
342368
throw new AIProviderError(this.name, 'validation', 'At least one correct answer is required');
343369
}
344370
if (!this.validateConfig(apiKey)) {
345-
throw new AIProviderError(this.name, 'auth', 'Invalid Mistral API key');
371+
throw new AIProviderError(this.name, 'auth', 'Invalid Mistral API key format');
346372
}
347373
}
348374
}

0 commit comments

Comments
 (0)