mirror of
https://github.com/voideditor/void
synced 2026-05-23 01:18:25 +00:00
Merging everything here
This commit is contained in:
parent
52d89e5815
commit
278c52bd35
8 changed files with 254 additions and 7 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -22,3 +22,4 @@ product.overrides.json
|
|||
*.snap.actual
|
||||
.vscode-test
|
||||
.tmp/
|
||||
.tool-versions
|
||||
|
|
|
|||
24
package-lock.json
generated
24
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",
|
||||
|
|
@ -65,7 +66,8 @@
|
|||
"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": {
|
||||
"@playwright/test": "^1.46.1",
|
||||
|
|
@ -2366,6 +2368,7 @@
|
|||
"exenv-es6": "^1.1.1"
|
||||
}
|
||||
},
|
||||
<<<<<<< HEAD
|
||||
"node_modules/@next/env": {
|
||||
"version": "15.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.4.tgz",
|
||||
|
|
@ -2507,6 +2510,16 @@
|
|||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
=======
|
||||
"node_modules/@mistralai/mistralai": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.3.5.tgz",
|
||||
"integrity": "sha512-yC91oJ5ScEPqbXmv3mJTwTFgu/ZtsYoOPOhaVXSsy6x4zXTqTI57yEC1flC9uiA8GpG/yhpn2BBUXF95+U9Blw==",
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19",
|
||||
"zod": ">= 3"
|
||||
>>>>>>> fork/feat-mistral-new
|
||||
}
|
||||
},
|
||||
"node_modules/@nodelib/fs.scandir": {
|
||||
|
|
@ -24104,6 +24117,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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,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",
|
||||
|
|
@ -132,7 +133,8 @@
|
|||
"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": {
|
||||
"@playwright/test": "^1.46.1",
|
||||
|
|
|
|||
62
src/package-lock.json
generated
Normal file
62
src/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"name": "src",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"dependencies": {
|
||||
"@mistralai/mistralai": "^1.3.5",
|
||||
"zod": "^3.23.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@mistralai/mistralai": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.3.5.tgz",
|
||||
"integrity": "sha512-yC91oJ5ScEPqbXmv3mJTwTFgu/ZtsYoOPOhaVXSsy6x4zXTqTI57yEC1flC9uiA8GpG/yhpn2BBUXF95+U9Blw==",
|
||||
"peerDependencies": {
|
||||
"react": "^18 || ^19",
|
||||
"react-dom": "^18 || ^19",
|
||||
"zod": ">= 3"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz",
|
||||
"integrity": "sha512-V8AVnmPIICiWpGfm6GLzCR/W5FXLchHop40W4nXBmdlEceh16rCN8O8LNWm5bh5XUX91fh7KpA+W0TgMKmgTpQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "19.0.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.0.0.tgz",
|
||||
"integrity": "sha512-4GV5sHFG0e/0AD4X+ySy6UJd3jVl1iNsNHdpad0qhABJ11twS3TTBnseqsKurKcsNqCEFeGL3uLpVChpIO3QfQ==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"scheduler": "^0.25.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0.tgz",
|
||||
"integrity": "sha512-xFVuu11jh+xcO7JOAGJNOXld8/TcEHK/4CituBUeUb5hqxJLj9YuemAEuvm9gQ/+pgXYfbQuqAkiYu+u7YEsNA==",
|
||||
"license": "MIT",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.23.8",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz",
|
||||
"integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,7 +94,18 @@ export const defaultGeminiModels = modelInfoOfDefaultNames([
|
|||
'gemini-1.0-pro'
|
||||
])
|
||||
|
||||
|
||||
export const defaultMistralModels = modelInfoOfDefaultNames([
|
||||
"open-codestral-mamba",
|
||||
"open-mistral-nemo",
|
||||
"pixtral-12b-2409",
|
||||
"mistral-large-latest",
|
||||
"pixtral-large-latest",
|
||||
"ministral-3b-latest",
|
||||
"ministral-8b-latest",
|
||||
"mistral-small-latest",
|
||||
"codestral-latest",
|
||||
"mistral-embed"
|
||||
])
|
||||
|
||||
// export const parseMaxTokensStr = (maxTokensStr: string) => {
|
||||
// // parse the string but only if the full string is a valid number, eg parseInt('100abc') should return NaN
|
||||
|
|
@ -144,6 +155,9 @@ export const defaultProviderSettings = {
|
|||
apiKey: '',
|
||||
},
|
||||
groq: {
|
||||
apiKey: '',
|
||||
},
|
||||
mistral: {
|
||||
apiKey: ''
|
||||
}
|
||||
} as const
|
||||
|
|
@ -224,6 +238,11 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
|
|||
title: 'Groq',
|
||||
}
|
||||
}
|
||||
else if (providerName === 'mistral') {
|
||||
return {
|
||||
title: 'Mistral',
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`descOfProviderName: Unknown provider name: "${providerName}"`)
|
||||
}
|
||||
|
|
@ -242,16 +261,18 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
|
|||
providerName === 'openRouter' ? 'sk-or-key...' : // sk-or-v1-key
|
||||
providerName === 'gemini' ? 'key...' :
|
||||
providerName === 'groq' ? 'gsk_key...' :
|
||||
providerName === 'openAICompatible' ? 'sk-key...' :
|
||||
'(never)',
|
||||
providerName === 'mistral' ? 'api-key...' :
|
||||
providerName === 'openAICompatible' ? 'sk-key...' :
|
||||
'(never)',
|
||||
|
||||
subTextMd: providerName === 'anthropic' ? 'Get your [API Key here](https://console.anthropic.com/settings/keys).' :
|
||||
providerName === 'openAI' ? 'Get your [API Key here](https://platform.openai.com/api-keys).' :
|
||||
providerName === 'openRouter' ? 'Get your [API Key here](https://openrouter.ai/settings/keys).' :
|
||||
providerName === 'gemini' ? 'Get your [API Key here](https://aistudio.google.com/apikey).' :
|
||||
providerName === 'groq' ? 'Get your [API Key here](https://console.groq.com/keys).' :
|
||||
providerName === 'openAICompatible' ? 'Add any OpenAI-Compatible endpoint.' :
|
||||
undefined,
|
||||
providerName === 'mistral' ? 'Get your [API Key here](https://console.mistral.ai/api-keys/).' :
|
||||
providerName === 'openAICompatible' ? undefined :
|
||||
undefined,
|
||||
}
|
||||
}
|
||||
else if (settingName === 'endpoint') {
|
||||
|
|
@ -293,6 +314,8 @@ const defaultCustomSettings: Record<CustomSettingName, undefined> = {
|
|||
endpoint: undefined,
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const voidInitModelOptions = {
|
||||
anthropic: {
|
||||
models: defaultAnthropicModels,
|
||||
|
|
@ -315,6 +338,9 @@ export const voidInitModelOptions = {
|
|||
groq: {
|
||||
models: defaultGroqModels,
|
||||
},
|
||||
mistral: {
|
||||
models: defaultMistralModels,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -362,6 +388,12 @@ export const defaultSettingsOfProvider: SettingsOfProvider = {
|
|||
...voidInitModelOptions.openAICompatible,
|
||||
_enabled: undefined,
|
||||
},
|
||||
mistral: {
|
||||
...defaultCustomSettings,
|
||||
...defaultProviderSettings.mistral,
|
||||
...voidInitModelOptions.mistral,
|
||||
_enabled: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
123
src/vs/platform/void/electron-main/llmMessage/mistral.ts
Normal file
123
src/vs/platform/void/electron-main/llmMessage/mistral.ts
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 { 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 = '';
|
||||
let aborted = false;
|
||||
|
||||
const thisConfig = settingsOfProvider.mistral;
|
||||
|
||||
if (!thisConfig.apiKey) {
|
||||
onError({ message: 'Mistral API key not configured.', fullError: new Error('No API key') });
|
||||
return;
|
||||
}
|
||||
|
||||
const mistral = new Mistral({
|
||||
apiKey: thisConfig.apiKey
|
||||
});
|
||||
|
||||
// Define the aborter before staring the stream
|
||||
_setAborter(() => {
|
||||
aborted = true;
|
||||
});
|
||||
|
||||
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: mistralMessages,
|
||||
temperature: 0.7,
|
||||
maxTokens: 2048
|
||||
});
|
||||
|
||||
for await (const chunk of stream) {
|
||||
// Check if the request has been aborted
|
||||
if (aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
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 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check one last time if the request has been aborted
|
||||
if (aborted) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
@ -11,6 +11,7 @@ import { sendOllamaMsg } from './ollama.js';
|
|||
import { sendOpenAIMsg } from './openai.js';
|
||||
import { sendGeminiMsg } from './gemini.js';
|
||||
import { sendGroqMsg } from './groq.js';
|
||||
import { sendMistralMsg } from './mistral.js';
|
||||
|
||||
export const sendLLMMessage = ({
|
||||
messages,
|
||||
|
|
@ -97,6 +98,9 @@ export const sendLLMMessage = ({
|
|||
case 'groq':
|
||||
sendGroqMsg({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName });
|
||||
break;
|
||||
case 'mistral':
|
||||
sendMistralMsg({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName });
|
||||
break;
|
||||
default:
|
||||
onError({ message: `Error: Void provider was "${providerName}", which is not recognized.`, fullError: null })
|
||||
break;
|
||||
|
|
|
|||
1
void
Submodule
1
void
Submodule
|
|
@ -0,0 +1 @@
|
|||
Subproject commit 5083b8e971e48ae1001e5c8ceee7b010bcea3640
|
||||
Loading…
Reference in a new issue