mirror of
https://github.com/voideditor/void
synced 2026-05-23 09:28:23 +00:00
Mistral implementation : Working
This commit is contained in:
parent
4729e4dac3
commit
4065c5b504
3 changed files with 95 additions and 19 deletions
15
package-lock.json
generated
15
package-lock.json
generated
|
|
@ -14,6 +14,7 @@
|
|||
"@google/generative-ai": "^0.21.0",
|
||||
"@microsoft/1ds-core-js": "^3.2.13",
|
||||
"@microsoft/1ds-post-js": "^3.2.13",
|
||||
"@mistralai/mistralai": "^1.3.5",
|
||||
"@parcel/watcher": "2.1.0",
|
||||
"@rrweb/record": "^2.0.0-alpha.17",
|
||||
"@rrweb/types": "^2.0.0-alpha.17",
|
||||
|
|
@ -64,10 +65,10 @@
|
|||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.1.0",
|
||||
"yauzl": "^3.0.0",
|
||||
"yazl": "^2.4.3"
|
||||
"yazl": "^2.4.3",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mistralai/mistralai": "^1.3.5",
|
||||
"@playwright/test": "^1.46.1",
|
||||
"@swc/core": "1.3.62",
|
||||
"@types/cookie": "^0.3.3",
|
||||
|
|
@ -1954,7 +1955,6 @@
|
|||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.3.5.tgz",
|
||||
"integrity": "sha512-yC91oJ5ScEPqbXmv3mJTwTFgu/ZtsYoOPOhaVXSsy6x4zXTqTI57yEC1flC9uiA8GpG/yhpn2BBUXF95+U9Blw==",
|
||||
"dev": true,
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19",
|
||||
|
|
@ -23241,6 +23241,15 @@
|
|||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.24.1",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.24.1.tgz",
|
||||
"integrity": "sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@
|
|||
"@google/generative-ai": "^0.21.0",
|
||||
"@microsoft/1ds-core-js": "^3.2.13",
|
||||
"@microsoft/1ds-post-js": "^3.2.13",
|
||||
"@mistralai/mistralai": "^1.3.5",
|
||||
"@parcel/watcher": "2.1.0",
|
||||
"@rrweb/record": "^2.0.0-alpha.17",
|
||||
"@rrweb/types": "^2.0.0-alpha.17",
|
||||
|
|
@ -128,10 +129,10 @@
|
|||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.1.0",
|
||||
"yauzl": "^3.0.0",
|
||||
"yazl": "^2.4.3"
|
||||
"yazl": "^2.4.3",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@mistralai/mistralai": "^1.3.5",
|
||||
"@playwright/test": "^1.46.1",
|
||||
"@swc/core": "1.3.62",
|
||||
"@types/cookie": "^0.3.3",
|
||||
|
|
|
|||
|
|
@ -1,43 +1,109 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Glass Devtools, Inc. All rights reserved.
|
||||
* Mistral implementation by Jérôme Commaret (https://github.com/jcommaret)
|
||||
* Void Editor additions licensed under the AGPL 3.0 License.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import MistralClient from '@mistralai/mistralai';
|
||||
import { Mistral } from '@mistralai/mistralai';
|
||||
import { _InternalSendLLMMessageFnType } from '../../common/llmMessageTypes.js';
|
||||
|
||||
interface MistralMessage {
|
||||
role: 'user' | 'assistant';
|
||||
content: string;
|
||||
}
|
||||
|
||||
interface MistralChunk {
|
||||
data: {
|
||||
id: string;
|
||||
object: string;
|
||||
created: number;
|
||||
model: string;
|
||||
choices: Array<{
|
||||
index: number;
|
||||
delta: {
|
||||
content?: string;
|
||||
role?: string;
|
||||
};
|
||||
finishReason: string | null;
|
||||
}>;
|
||||
};
|
||||
}
|
||||
|
||||
// Mistral
|
||||
export const sendMistralMsg: _InternalSendLLMMessageFnType = async ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => {
|
||||
let fullText = '';
|
||||
|
||||
const thisConfig = settingsOfProvider.mistral;
|
||||
|
||||
const mistral = new MistralClient({
|
||||
if (!thisConfig.apiKey) {
|
||||
onError({ message: 'Mistral API key not configured.', fullError: new Error('No API key') });
|
||||
return;
|
||||
}
|
||||
|
||||
const mistral = new Mistral({
|
||||
apiKey: thisConfig.apiKey
|
||||
});
|
||||
|
||||
try {
|
||||
// Check if there are messages to process
|
||||
if (!messages || messages.length === 0) {
|
||||
onError({ message: 'No messages to process.', fullError: new Error('No messages provided') });
|
||||
return;
|
||||
}
|
||||
|
||||
// Convert messages for Mistral
|
||||
const mistralMessages = messages
|
||||
.filter(msg => msg.role !== 'system') // Ignore system messages
|
||||
.map(msg => ({
|
||||
role: msg.role === 'assistant' ? 'assistant' : 'user',
|
||||
content: msg.content.trim()
|
||||
})) as MistralMessage[];
|
||||
|
||||
// Ensure there is at least one message
|
||||
if (mistralMessages.length === 0) {
|
||||
onError({ message: 'No valid messages to send.', fullError: new Error('No valid messages') });
|
||||
return;
|
||||
}
|
||||
|
||||
// Ensure the last message is from the user
|
||||
if (mistralMessages[mistralMessages.length - 1].role === 'assistant') {
|
||||
mistralMessages.push({
|
||||
role: 'user',
|
||||
content: 'Continue.'
|
||||
});
|
||||
}
|
||||
|
||||
const stream = await mistral.chat.stream({
|
||||
model: modelName,
|
||||
messages: messages,
|
||||
messages: mistralMessages,
|
||||
temperature: 0.7,
|
||||
maxTokens: 2048
|
||||
});
|
||||
|
||||
_setAborter(() => stream.controller.abort());
|
||||
_setAborter(() => { }); // Mistral does not provide an abort method
|
||||
|
||||
for await (const chunk of stream) {
|
||||
const newText = chunk.choices[0]?.delta?.content || '';
|
||||
if (newText) {
|
||||
fullText += newText;
|
||||
onText({ newText, fullText });
|
||||
if (typeof chunk === 'object' && chunk && 'data' in chunk) {
|
||||
const { data } = chunk as MistralChunk;
|
||||
if (data.choices?.[0]?.delta?.content) {
|
||||
const newText = data.choices[0].delta.content;
|
||||
fullText += newText;
|
||||
onText({ newText, fullText });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onFinalMessage({ fullText });
|
||||
} catch (error) {
|
||||
if (error.status === 401) {
|
||||
onError({ message: 'Invalid API key.', fullError: error });
|
||||
} else {
|
||||
onError({ message: error + '', fullError: error });
|
||||
if (!fullText) {
|
||||
onError({ message: 'No response received from Mistral.', fullError: new Error('No response content') });
|
||||
return;
|
||||
}
|
||||
|
||||
onFinalMessage({ fullText });
|
||||
} catch (error: any) {
|
||||
const errorMessage = error.message || JSON.stringify(error);
|
||||
onError({
|
||||
message: `Mistral Error: ${errorMessage}`,
|
||||
fullError: error
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in a new issue