diff --git a/.gitignore b/.gitignore index 5daf304c..fcdb9b6f 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,4 @@ product.overrides.json *.snap.actual .vscode-test .tmp/ +.tool-versions diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3fb20e5..a96aa0e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,15 +1,27 @@ # Contributing to Void - -Welcome! 👋 This is the official guide on how to contribute to Void. We want to make it as easy as possible to contribute, so if you have any questions or comments, reach out via email or discord! - - -If you'd like to get started developing Void, feel free to follow the steps below on building Void yourself and doing a PR. -Void's code mostly lives in `src/vs/workbench/contrib/void/` and `src/vs/platform/void/`. +### Welcome! 👋 +This is the official guide on how to contribute to Void. We want to make it as easy as possible to contribute, so if you have any questions or comments, reach out via email or discord! There are a few ways to contribute: -- ðŸ‘Ļ‍ðŸ’ŧ Build new features - see [Roadmap](https://github.com/orgs/voideditor/projects/2/views/3) and [Issues](https://github.com/voideditor/void/issues). +- ðŸ’Ŧ Complete items on the [Roadmap](https://github.com/orgs/voideditor/projects/2). - ðŸ’Ą Make suggestions in our [Discord](https://discord.gg/RSNjgaugJs). +- ðŸŠī Start new Issues - see [Issues](https://github.com/voideditor/void/issues). + + + +### Codebase Guide + +We highly recommend reading [this](https://github.com/microsoft/vscode/wiki/Source-Code-Organization) article on VSCode's sourcecode organization. + +We are currently putting together our own articles on VSCode and Void's sourcecode organization. The best way to get this information right now is by attending a weekly meeting. + + + +Most of Void's code lives in the two folders called `void/`. + @@ -47,7 +59,7 @@ First, run `npm install -g node-gyp`. Then: To build Void, open `void/` inside VSCode. Then open your terminal and run: 1. `npm install` to install all dependencies. -2. `npm run watchreact` to build Void's browser dependencies like React. +2. `npm run watchreact` to build Void's browser dependencies like React. (If this doesn't work, try `npm run buildreact`). 3. Build Void. - Press Cmd+Shift+B (Mac). - Press Ctrl+Shift+B (Windows/Linux). @@ -121,20 +133,6 @@ Void's maintainers distribute Void on our website and in releases. If you'd like - Please don't use AI to write your PR 🙂 -## Codebase Guide - -We highly recommend reading [this](https://github.com/microsoft/vscode/wiki/Source-Code-Organization) article on VSCode's sourcecode organization. - -We are currently putting together our own articles on VSCode and Void's sourcecode organization. The best way to get this information right now is by attending a weekly meeting. - - - -For some miscellaneous useful links on VSCode we've put together, see [`VOID_USEFUL_LINKS.md`](https://github.com/voideditor/void/blob/main/VOID_USEFUL_LINKS.md). - - - diff --git a/README.md b/README.md index ca38d5b7..f1594fd4 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Void is the open-source Cursor alternative. -This repo contains the full sourcecode for Void. We are currently in [open beta](https://voideditor.com/) for Discord members (see the `announcements` channel), with a waitlist for our official release. If you're new, welcome! +This repo contains the full sourcecode for Void. We are currently in [open beta](https://voideditor.com/email) for Discord members (see the `announcements` channel), with a waitlist for our official release. If you're new, welcome! - 👋 [Discord](https://discord.gg/RSNjgaugJs) diff --git a/package-lock.json b/package-lock.json index 91937c1c..966a06e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -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.4.0", "@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,17 +2368,25 @@ "exenv-es6": "^1.1.1" } }, + "node_modules/@mistralai/mistralai": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.4.0.tgz", + "integrity": "sha512-xA3DAtIDh4Qgr1EoSuiGVE+2ABNrxpcTeC0kSXYbkDNUGdthalLAH7DgbG0fkKZ7TN8xdWXQq2WiIghp/O96Eg==", + "peerDependencies": { + "zod": ">= 3" + } + }, "node_modules/@next/env": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.4.tgz", - "integrity": "sha512-2fZ5YZjedi5AGaeoaC0B20zGntEHRhi2SdWcu61i48BllODcAmmtj8n7YarSPt4DaTsJaBFdxQAVEVzgmx2Zpw==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.6.tgz", + "integrity": "sha512-d9AFQVPEYNr+aqokIiPLNK/MTyt3DWa/dpKveiAaVccUadFbhFEvY6FXYX2LJO2Hv7PHnLBu2oWwB4uBuHjr/w==", "dev": true, "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.4.tgz", - "integrity": "sha512-wBEMBs+np+R5ozN1F8Y8d/Dycns2COhRnkxRc+rvnbXke5uZBHkUGFgWxfTXn5rx7OLijuUhyfB+gC/ap58dDw==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.1.6.tgz", + "integrity": "sha512-u7lg4Mpl9qWpKgy6NzEkz/w0/keEHtOybmIl0ykgItBxEM5mYotS5PmqTpo+Rhg8FiOiWgwr8USxmKQkqLBCrw==", "cpu": [ "arm64" ], @@ -2391,9 +2401,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.4.tgz", - "integrity": "sha512-7sgf5rM7Z81V9w48F02Zz6DgEJulavC0jadab4ZsJ+K2sxMNK0/BtF8J8J3CxnsJN3DGcIdC260wEKssKTukUw==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.1.6.tgz", + "integrity": "sha512-x1jGpbHbZoZ69nRuogGL2MYPLqohlhnT9OCU6E6QFewwup+z+M6r8oU47BTeJcWsF2sdBahp5cKiAcDbwwK/lg==", "cpu": [ "x64" ], @@ -2408,9 +2418,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.4.tgz", - "integrity": "sha512-JaZlIMNaJenfd55kjaLWMfok+vWBlcRxqnRoZrhFQrhM1uAehP3R0+Aoe+bZOogqlZvAz53nY/k3ZyuKDtT2zQ==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.1.6.tgz", + "integrity": "sha512-jar9sFw0XewXsBzPf9runGzoivajeWJUc/JkfbLTC4it9EhU8v7tCRLH7l5Y1ReTMN6zKJO0kKAGqDk8YSO2bg==", "cpu": [ "arm64" ], @@ -2425,9 +2435,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.4.tgz", - "integrity": "sha512-7EBBjNoyTO2ipMDgCiORpwwOf5tIueFntKjcN3NK+GAQD7OzFJe84p7a2eQUeWdpzZvhVXuAtIen8QcH71ZCOQ==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.1.6.tgz", + "integrity": "sha512-+n3u//bfsrIaZch4cgOJ3tXCTbSxz0s6brJtU3SzLOvkJlPQMJ+eHVRi6qM2kKKKLuMY+tcau8XD9CJ1OjeSQQ==", "cpu": [ "arm64" ], @@ -2442,9 +2452,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.4.tgz", - "integrity": "sha512-9TGEgOycqZFuADyFqwmK/9g6S0FYZ3tphR4ebcmCwhL8Y12FW8pIBKJvSwV+UBjMkokstGNH+9F8F031JZKpHw==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.1.6.tgz", + "integrity": "sha512-SpuDEXixM3PycniL4iVCLyUyvcl6Lt0mtv3am08sucskpG0tYkW1KlRhTgj4LI5ehyxriVVcfdoxuuP8csi3kQ==", "cpu": [ "x64" ], @@ -2459,9 +2469,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.4.tgz", - "integrity": "sha512-0578bLRVDJOh+LdIoKvgNDz77+Bd85c5JrFgnlbI1SM3WmEQvsjxTA8ATu9Z9FCiIS/AliVAW2DV/BDwpXbtiQ==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.1.6.tgz", + "integrity": "sha512-L4druWmdFSZIIRhF+G60API5sFB7suTbDRhYWSjiw0RbE+15igQvE2g2+S973pMGvwN3guw7cJUjA/TmbPWTHQ==", "cpu": [ "x64" ], @@ -2476,9 +2486,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.4.tgz", - "integrity": "sha512-JgFCiV4libQavwII+kncMCl30st0JVxpPOtzWcAI2jtum4HjYaclobKhj+JsRu5tFqMtA5CJIa0MvYyuu9xjjQ==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.1.6.tgz", + "integrity": "sha512-s8w6EeqNmi6gdvM19tqKKWbCyOBvXFbndkGHl+c9YrzsLARRdCHsD9S1fMj8gsXm9v8vhC8s3N8rjuC/XrtkEg==", "cpu": [ "arm64" ], @@ -2493,9 +2503,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.4.tgz", - "integrity": "sha512-xxsJy9wzq7FR5SqPCUqdgSXiNXrMuidgckBa8nH9HtjjxsilgcN6VgXF6tZ3uEWuVEadotQJI8/9EQ6guTC4Yw==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.1.6.tgz", + "integrity": "sha512-6xomMuu54FAFxttYr5PJbEfu96godcxBTRk1OhAvJq0/EnmFU/Ybiax30Snis4vdWZ9LGpf7Roy5fSs7v/5ROQ==", "cpu": [ "x64" ], @@ -16219,13 +16229,13 @@ "dev": true }, "node_modules/next": { - "version": "15.1.4", - "resolved": "https://registry.npmjs.org/next/-/next-15.1.4.tgz", - "integrity": "sha512-mTaq9dwaSuwwOrcu3ebjDYObekkxRnXpuVL21zotM8qE2W0HBOdVIdg2Li9QjMEZrj73LN96LcWcz62V19FjAg==", + "version": "15.1.6", + "resolved": "https://registry.npmjs.org/next/-/next-15.1.6.tgz", + "integrity": "sha512-Hch4wzbaX0vKQtalpXvUiw5sYivBy4cm5rzUKrBnUB/y436LGrvOUqYvlSeNVCWFO/770gDlltR9gqZH62ct4Q==", "dev": true, "license": "MIT", "dependencies": { - "@next/env": "15.1.4", + "@next/env": "15.1.6", "@swc/counter": "0.1.3", "@swc/helpers": "0.5.15", "busboy": "1.6.0", @@ -16240,14 +16250,14 @@ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "15.1.4", - "@next/swc-darwin-x64": "15.1.4", - "@next/swc-linux-arm64-gnu": "15.1.4", - "@next/swc-linux-arm64-musl": "15.1.4", - "@next/swc-linux-x64-gnu": "15.1.4", - "@next/swc-linux-x64-musl": "15.1.4", - "@next/swc-win32-arm64-msvc": "15.1.4", - "@next/swc-win32-x64-msvc": "15.1.4", + "@next/swc-darwin-arm64": "15.1.6", + "@next/swc-darwin-x64": "15.1.6", + "@next/swc-linux-arm64-gnu": "15.1.6", + "@next/swc-linux-arm64-musl": "15.1.6", + "@next/swc-linux-x64-gnu": "15.1.6", + "@next/swc-linux-x64-musl": "15.1.6", + "@next/swc-win32-arm64-msvc": "15.1.6", + "@next/swc-win32-x64-msvc": "15.1.6", "sharp": "^0.33.5" }, "peerDependencies": { @@ -24104,6 +24114,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" + } } } } diff --git a/package.json b/package.json index 9833d8a9..394a05a8 100644 --- a/package.json +++ b/package.json @@ -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.4.0", "@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", diff --git a/src/vs/platform/void/common/llmMessageTypes.ts b/src/vs/platform/void/common/llmMessageTypes.ts index 77b31c07..fbf7a1b2 100644 --- a/src/vs/platform/void/common/llmMessageTypes.ts +++ b/src/vs/platform/void/common/llmMessageTypes.ts @@ -108,13 +108,6 @@ export type _InternalSendLLMMessageFnType = (params: { - - - - - - - // These are from 'ollama' SDK interface OllamaModelDetails { parent_model: string; diff --git a/src/vs/platform/void/common/voidSettingsService.ts b/src/vs/platform/void/common/voidSettingsService.ts index 7200d8bf..c92810ab 100644 --- a/src/vs/platform/void/common/voidSettingsService.ts +++ b/src/vs/platform/void/common/voidSettingsService.ts @@ -117,9 +117,28 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService { // read and update the actual state immediately this._readState().then(readS => { - // THIS IS A HACK BECAUSE WE ADDED DEEPSEEK - const deepseekAdd = { deepseek: defaultSettingsOfProvider['deepseek'] } - readS = { ...readS, settingsOfProvider: { ...deepseekAdd, ...readS.settingsOfProvider, } } + // the stored data structure might be outdated, so we need to update it here (can do a more general solution later when we need to) + readS = { + ...readS, + settingsOfProvider: { + // A HACK BECAUSE WE ADDED DEEPSEEK (did not exist before, comes before readS) + ...{ deepseek: defaultSettingsOfProvider.deepseek }, + + // A HACK BECAUSE WE ADDED MISTRAL (did not exist before, comes before readS) + ...{ mistral: defaultSettingsOfProvider.mistral }, + + ...readS.settingsOfProvider, + + // A HACK BECAUSE WE ADDED NEW GEMINI MODELS (existed before, comes after readS) + gemini: { + ...readS.settingsOfProvider.gemini, + models: [ + ...readS.settingsOfProvider.gemini.models, + ...defaultSettingsOfProvider.gemini.models.filter(m => /* if cant find the model in readS (yes this is O(n^2), very small) */ !readS.settingsOfProvider.gemini.models.find(m2 => m2.modelName === m.modelName)) + ] + } + } + } this.state = readS resolver() diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index fe358757..eb588abf 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -96,10 +96,21 @@ export const defaultGeminiModels = modelInfoOfDefaultNames([ 'gemini-1.5-flash', 'gemini-1.5-pro', 'gemini-1.5-flash-8b', - 'gemini-1.0-pro' + 'gemini-2.0-flash-exp', + 'gemini-2.0-flash-thinking-exp-1219', + 'learnlm-1.5-pro-experimental' ]) - +export const defaultMistralModels = modelInfoOfDefaultNames([ + "codestral-latest", + "open-codestral-mamba", + "open-mistral-nemo", + "mistral-large-latest", + "pixtral-large-latest", + "ministral-3b-latest", + "ministral-8b-latest", + "mistral-small-latest", +]) // export const parseMaxTokensStr = (maxTokensStr: string) => { // // parse the string but only if the full string is a valid number, eg parseInt('100abc') should return NaN @@ -152,6 +163,9 @@ export const defaultProviderSettings = { apiKey: '', }, groq: { + apiKey: '', + }, + mistral: { apiKey: '' } } as const @@ -237,6 +251,11 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn title: 'Groq', } } + else if (providerName === 'mistral') { + return { + title: 'Mistral', + } + } throw new Error(`descOfProviderName: Unknown provider name: "${providerName}"`) } @@ -250,14 +269,18 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName if (settingName === 'apiKey') { return { title: 'API Key', + + // **Please follow this convention**: + // The word "key..." here is a placeholder for the hash. For example, sk-ant-key... means the key will look like sk-ant-abcdefg123... placeholder: providerName === 'anthropic' ? 'sk-ant-key...' : // sk-ant-api03-key providerName === 'openAI' ? 'sk-proj-key...' : - providerName === 'deepseek' ? 'sk-...' : + providerName === 'deepseek' ? 'sk-key...' : providerName === 'openRouter' ? 'sk-or-key...' : // sk-or-v1-key providerName === 'gemini' ? 'key...' : providerName === 'groq' ? 'gsk_key...' : - providerName === 'openAICompatible' ? 'sk-key...' : - '', + providerName === 'mistral' ? 'key...' : + providerName === 'openAICompatible' ? 'sk-key...' : + '', 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).' : @@ -265,8 +288,9 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName 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.' : - '', + providerName === 'mistral' ? 'Get your [API Key here](https://console.mistral.ai/api-keys/).' : + providerName === 'openAICompatible' ? undefined : + '', } } else if (settingName === 'endpoint') { @@ -308,6 +332,8 @@ const defaultCustomSettings: Record = { endpoint: undefined, } + + export const voidInitModelOptions = { anthropic: { models: defaultAnthropicModels, @@ -333,22 +359,25 @@ export const voidInitModelOptions = { groq: { models: defaultGroqModels, }, + mistral: { + models: defaultMistralModels, + } } // used when waiting and for a type reference export const defaultSettingsOfProvider: SettingsOfProvider = { anthropic: { - _enabled: undefined, ...defaultCustomSettings, ...defaultProviderSettings.anthropic, ...voidInitModelOptions.anthropic, + _enabled: undefined, }, openAI: { - _enabled: undefined, ...defaultCustomSettings, ...defaultProviderSettings.openAI, ...voidInitModelOptions.openAI, + _enabled: undefined, }, deepseek: { ...defaultCustomSettings, @@ -386,6 +415,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/groq.ts b/src/vs/platform/void/electron-main/llmMessage/groq.ts index 1050e25c..70a4250b 100644 --- a/src/vs/platform/void/electron-main/llmMessage/groq.ts +++ b/src/vs/platform/void/electron-main/llmMessage/groq.ts @@ -22,7 +22,7 @@ export const sendGroqMsg: _InternalSendLLMMessageFnType = async ({ messages, onT messages: messages, model: modelName, stream: true, - temperature: 0.7, + // temperature: 0.7, // max_tokens: parseMaxTokensStr(thisConfig.maxTokens), }) .then(async response => { @@ -30,10 +30,8 @@ export const sendGroqMsg: _InternalSendLLMMessageFnType = async ({ messages, onT // when receive text for await (const chunk of response) { const newText = chunk.choices[0]?.delta?.content || ''; - if (newText) { - fullText += newText; - onText({ newText, fullText }); - } + fullText += newText; + onText({ newText, fullText }); } onFinalMessage({ fullText }); 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..74f9233e --- /dev/null +++ b/src/vs/platform/void/electron-main/llmMessage/mistral.ts @@ -0,0 +1,46 @@ +/*-------------------------------------------------------------------------------------- + * Copyright 2025 Glass Devtools, Inc. All rights reserved. + * Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information. + *--------------------------------------------------------------------------------------*/ + +import { Mistral } 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 Mistral({ + apiKey: thisConfig.apiKey, + }) + + await mistral.chat + .stream({ + messages: messages, + model: modelName, + stream: true, + // temperature: 0.7, + // maxTokens: 2048, + }) + .then(async response => { + // Mistral has a really nonstandard API - no interrupt and weird stream types + _setAborter(() => { console.log('Mistral does not support interrupts! Further messages will just be ignored.') }); + // when receive text + for await (const chunk of response) { + const c = chunk.data.choices[0].delta.content || '' + const newText = ( + typeof c === 'string' ? c + : c?.map(c => c.type === 'text' ? c.text : c.type).join('\n') + ) + fullText += newText; + onText({ newText, fullText }); + } + + onFinalMessage({ fullText }); + }) + .catch(error => { + 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 1f88b26c..bb3884b3 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'; const cleanMessages = (messages: LLMMessage[]): _InternalLLMMessage[] => { @@ -132,6 +133,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; diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index ed1611e8..8cb4864f 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -436,7 +436,7 @@ const ChatBubble_ = ({ isEditMode, isLoading, children, role }: { role: ChatMess className={` relative ${isEditMode ? 'px-2 w-full max-w-full' - : role === 'user' ? `px-2 mt-4 self-end w-fit max-w-full` + : role === 'user' ? `px-2 self-end w-fit max-w-full` : role === 'assistant' ? `px-2 self-start w-full max-w-full` : '' } `} @@ -622,6 +622,7 @@ export const SidebarChat = () => { flex flex-col overflow-x-hidden overflow-y-auto + gap-4 `} style={{ maxHeight: sidebarDimensions.height - historyDimensions.height - formDimensions.height - 36 }} // the height of the previousMessages is determined by all other heights > diff --git a/src/vs/workbench/electron-sandbox/desktop.contribution.ts b/src/vs/workbench/electron-sandbox/desktop.contribution.ts index c14e3e1a..f6bae665 100644 --- a/src/vs/workbench/electron-sandbox/desktop.contribution.ts +++ b/src/vs/workbench/electron-sandbox/desktop.contribution.ts @@ -190,7 +190,7 @@ import { MAX_ZOOM_LEVEL, MIN_ZOOM_LEVEL } from '../../platform/window/electron-s }, 'window.zoomLevel': { 'type': 'number', - 'default': -1, + 'default': 0, 'minimum': MIN_ZOOM_LEVEL, 'maximum': MAX_ZOOM_LEVEL, 'markdownDescription': localize({ comment: ['{0} will be a setting name rendered as a link'], key: 'zoomLevel' }, "Adjust the default zoom level for all windows. Each increment above `0` (e.g. `1`) or below (e.g. `-1`) represents zooming `20%` larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity. See {0} for configuring if the 'Zoom In' and 'Zoom Out' commands apply the zoom level to all windows or only the active window.", '`#window.zoomPerWindow#`'),