From 4729e4dac3d9c071931f33e3b2d0fd4d07e3476c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Commaret?= Date: Fri, 27 Dec 2024 14:46:02 +0100 Subject: [PATCH] Mistral v2 --- package-lock.json | 12 ++++ package.json | 1 + src/package-lock.json | 62 +++++++++++++++++++ .../platform/void/common/voidSettingsTypes.ts | 43 +++++++++++-- .../void/electron-main/llmMessage/mistral.ts | 43 +++++++++++++ .../llmMessage/sendLLMMessage.ts | 4 ++ 6 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 src/package-lock.json create mode 100644 src/vs/platform/void/electron-main/llmMessage/mistral.ts diff --git a/package-lock.json b/package-lock.json index 307f13cf..732ab358 100644 --- a/package-lock.json +++ b/package-lock.json @@ -67,6 +67,7 @@ "yazl": "^2.4.3" }, "devDependencies": { + "@mistralai/mistralai": "^1.3.5", "@playwright/test": "^1.46.1", "@swc/core": "1.3.62", "@types/cookie": "^0.3.3", @@ -1949,6 +1950,17 @@ "exenv-es6": "^1.1.1" } }, + "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==", + "dev": true, + "peerDependencies": { + "react": "^18 || ^19", + "react-dom": "^18 || ^19", + "zod": ">= 3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", diff --git a/package.json b/package.json index ab294d7b..5039e401 100644 --- a/package.json +++ b/package.json @@ -131,6 +131,7 @@ "yazl": "^2.4.3" }, "devDependencies": { + "@mistralai/mistralai": "^1.3.5", "@playwright/test": "^1.46.1", "@swc/core": "1.3.62", "@types/cookie": "^0.3.3", diff --git a/src/package-lock.json b/src/package-lock.json new file mode 100644 index 00000000..3b02711d --- /dev/null +++ b/src/package-lock.json @@ -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" + } + } + } +} diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index 1b1b2ff7..16d66900 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -1,4 +1,3 @@ - /*--------------------------------------------------------------------------------------------- * Copyright (c) Glass Devtools, Inc. All rights reserved. * Void Editor additions licensed under the AGPL 3.0 License. @@ -67,7 +66,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 @@ -117,6 +127,9 @@ export const defaultProviderSettings = { apiKey: '', }, groq: { + apiKey: '', + }, + mistral: { apiKey: '' } } as const @@ -196,6 +209,11 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn title: 'Groq', } } + else if (providerName === 'mistral') { + return { + title: 'Mistral', + } + } throw new Error(`descOfProviderName: Unknown provider name: "${providerName}"`) } @@ -214,16 +232,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' ? undefined : - undefined, + providerName === 'mistral' ? 'Get your [API Key here](https://console.mistral.ai/api-keys/).' : + providerName === 'openAICompatible' ? undefined : + undefined, } } else if (settingName === 'endpoint') { @@ -265,6 +285,8 @@ const defaultCustomSettings: Record = { endpoint: undefined, } + + export const voidInitModelOptions = { anthropic: { models: defaultAnthropicModels, @@ -287,6 +309,9 @@ export const voidInitModelOptions = { groq: { models: defaultGroqModels, }, + mistral: { + models: defaultMistralModels, + } } @@ -334,6 +359,12 @@ export const defaultSettingsOfProvider: SettingsOfProvider = { ...voidInitModelOptions.openAICompatible, enabled: undefined, }, + mistral: { + ...defaultCustomSettings, + ...defaultProviderSettings.mistral, + ...voidInitModelOptions.mistral, + enabled: undefined, + } } diff --git a/src/vs/platform/void/electron-main/llmMessage/mistral.ts b/src/vs/platform/void/electron-main/llmMessage/mistral.ts new file mode 100644 index 00000000..3ba71d37 --- /dev/null +++ b/src/vs/platform/void/electron-main/llmMessage/mistral.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Glass Devtools, Inc. All rights reserved. + * Void Editor additions licensed under the AGPL 3.0 License. + *--------------------------------------------------------------------------------------------*/ + +import MistralClient from '@mistralai/mistralai'; +import { _InternalSendLLMMessageFnType } from '../../common/llmMessageTypes.js'; + +// Mistral +export const sendMistralMsg: _InternalSendLLMMessageFnType = async ({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter }) => { + let fullText = ''; + + const thisConfig = settingsOfProvider.mistral; + + const mistral = new MistralClient({ + apiKey: thisConfig.apiKey + }); + + try { + const stream = await mistral.chat.stream({ + model: modelName, + messages: messages, + }); + + _setAborter(() => stream.controller.abort()); + + for await (const chunk of stream) { + const newText = chunk.choices[0]?.delta?.content || ''; + if (newText) { + 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 }); + } + } +}; diff --git a/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts b/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts index 9e106f97..a4ccad91 100644 --- a/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts +++ b/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts @@ -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, @@ -96,6 +97,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;