mistral corrections

This commit is contained in:
Andrew Pareles 2025-04-14 11:51:42 -07:00
parent 5e83d419ce
commit 06513168c1
7 changed files with 3795 additions and 5798 deletions

9282
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -41,4 +41,3 @@
"https://voideditor.dev"
]
}

View file

@ -23,12 +23,7 @@ const notifyYesUpdate = (notifService: INotificationService, res: { message?: st
severity: Severity.Info,
message: message,
sticky: true,
// progress: { worked: 0, total: 100 },
// progress: { worked: 0, total: 100 },
neverShowAgain: {
id: 'voidUpdateNotification',
isSecondary: false
},
progress: { worked: 0, total: 100 },
actions: {
primary: [{
id: 'void.updater.update',

View file

@ -59,16 +59,8 @@ export const defaultModelsOfProvider = {
mistral: [ // https://docs.mistral.ai/getting-started/models/models_overview/
'codestral-latest',
'mistral-large-latest',
'pixtral-large-latest',
'mistral-saba-latest',
'ministral-3b-latest',
'ministral-8b-latest',
'mistral-ocr-latest',
'mistral-embed',
'mistral-small-latest',
'pixtral-12b-2409',
'open-mistral-nemo',
'open-codestral-mamba'
],
openAICompatible: [], // fallback
} as const satisfies Record<ProviderName, string[]>
@ -88,7 +80,7 @@ type ModelOptions = {
cache_write?: number;
}
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated';
supportsTools: false | 'anthropic-style' | 'openai-style' | 'mistral-style';
supportsTools: false | 'anthropic-style' | 'openai-style';
supportsFIM: boolean;
reasoningCapabilities: false | {
@ -134,115 +126,6 @@ const modelOptionsDefaults: ModelOptions = {
reasoningCapabilities: false,
}
const mistralModelOptions = {
'codestral-latest': {
contextWindow: 128_000,
maxOutputTokens: 16_384,
cost: { input: 0.000015, output: 0.000090 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'mistral-large-latest': {
contextWindow: 131_000,
maxOutputTokens: 8_192,
cost: { input: 0.000015, output: 0.000060 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'mistral-small-latest': {
contextWindow: 131_000,
maxOutputTokens: 8_192,
cost: { input: 0.000002, output: 0.000008 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'pixtral-large-latest': {
contextWindow: 128_000,
maxOutputTokens: 8_192,
cost: { input: 0.000025, output: 0.000075 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'mistral-saba-latest': {
contextWindow: 32_000,
maxOutputTokens: 8_192,
cost: { input: 0.000005, output: 0.000025 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
},
'ministral-3b-latest': {
contextWindow: 131_000,
maxOutputTokens: 4_096,
cost: { input: 0.000001, output: 0.000003 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'ministral-8b-latest': {
contextWindow: 32_000,
maxOutputTokens: 4_096,
cost: { input: 0.000001, output: 0.000005 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'mistral-ocr-latest': {
contextWindow: 64_000,
maxOutputTokens: 4_096,
cost: { input: 0.000010, output: 0.000020 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
},
'pixtral-12b-2409': {
contextWindow: 128_000,
maxOutputTokens: 8_192,
cost: { input: 0.000020, output: 0.000060 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'mistral-style',
reasoningCapabilities: false,
},
'open-mistral-nemo': {
contextWindow: 32_768,
maxOutputTokens: 4_096,
cost: { input: 0.0, output: 0.0 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
},
'open-codestral-mamba': {
contextWindow: 16_384,
maxOutputTokens: 4_096,
cost: { input: 0.0, output: 0.0 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
}
} as const satisfies { [s: string]: ModelOptions }
const mistralSettings: ProviderSettings = {
...mistralModelOptions,
modelOptions: {},
modelOptionsFallback: (modelName) => extensiveModelFallback(modelName),
}
const openSourceModelOptions_assumingOAICompat = {
'deepseekR1': {
supportsFIM: false,
@ -695,6 +578,64 @@ const deepseekSettings: ProviderSettings = {
modelOptionsFallback: (modelName) => { return null }
}
// ---------------- MISTRAL ----------------
const mistralModelOptions = { // https://mistral.ai/products/la-plateforme#pricing https://docs.mistral.ai/getting-started/models/models_overview/#premier-models
'mistral-large-latest': {
contextWindow: 131_000,
maxOutputTokens: 8_192,
cost: { input: 2.00, output: 6.00 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
'codestral-latest': {
contextWindow: 256_000,
maxOutputTokens: 8_192,
cost: { input: 0.30, output: 0.90 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
'mistral-saba-latest': {
contextWindow: 32_000,
maxOutputTokens: 8_192,
cost: { input: 0.20, output: 0.60 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
supportsTools: false,
reasoningCapabilities: false,
},
'ministral-8b-latest': {
contextWindow: 131_000,
maxOutputTokens: 4_096,
cost: { input: 0.10, output: 0.10 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
'ministral-3b-latest': {
contextWindow: 131_000,
maxOutputTokens: 4_096,
cost: { input: 0.04, output: 0.04 },
supportsFIM: false,
supportsSystemMessage: 'system-role',
supportsTools: 'openai-style',
reasoningCapabilities: false,
},
} as const satisfies { [s: string]: ModelOptions }
const mistralSettings: ProviderSettings = {
modelOptions: mistralModelOptions,
modelOptionsFallback: (modelName) => { return null },
}
// ---------------- GROQ ----------------
const groqModelOptions = { // https://console.groq.com/docs/models, https://groq.com/pricing/
'llama-3.3-70b-versatile': {

View file

@ -188,7 +188,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
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 === 'xAI' ? 'Get your [API Key here](https://console.x.ai).' :
providerName === 'mistral' ? 'Get your [API Key here](https://mistral.ai/settings/keys).' :
providerName === 'mistral' ? 'Get your [API Key here](https://console.mistral.ai/api-keys).' :
providerName === 'openAICompatible' ? undefined :
'',
isPasswordField: true,
@ -280,42 +280,42 @@ export const defaultSettingsOfProvider: SettingsOfProvider = {
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.xAI),
_didFillInProviderSettings: undefined,
},
groq: { // aggregator
mistral: {
...defaultCustomSettings,
...defaultProviderSettings.mistral,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.mistral),
_didFillInProviderSettings: undefined,
},
groq: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.groq,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.groq),
_didFillInProviderSettings: undefined,
},
openRouter: { // aggregator
openRouter: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.openRouter,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.openRouter),
_didFillInProviderSettings: undefined,
},
openAICompatible: { // aggregator
openAICompatible: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.openAICompatible,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.openAICompatible),
_didFillInProviderSettings: undefined,
},
ollama: { // aggregator
ollama: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.ollama,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.ollama),
_didFillInProviderSettings: undefined,
},
vLLM: { // aggregator
vLLM: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.vLLM,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.vLLM),
_didFillInProviderSettings: undefined,
},
mistral: { // aggregator
...defaultCustomSettings,
...defaultProviderSettings.mistral,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.mistral),
_didFillInProviderSettings: undefined,
},
}

View file

@ -373,18 +373,15 @@ const prepareMessages_tools_anthropic = ({ messages }: { messages: InternalLLMCh
type PrepareMessagesTools = PrepareMessagesToolsAnthropic | PrepareMessagesToolsOpenAI | PrepareMessagesToolsMistral
type PrepareMessagesTools = PrepareMessagesToolsAnthropic | PrepareMessagesToolsOpenAI
const prepareMessages_tools = ({ messages, supportsTools }: { messages: InternalLLMChatMessage[], supportsTools: false | 'anthropic-style' | 'openai-style' | 'mistral-style' }): { messages: PrepareMessagesTools } => {
const prepareMessages_tools = ({ messages, supportsTools }: { messages: InternalLLMChatMessage[], supportsTools: false | 'anthropic-style' | 'openai-style' }): { messages: PrepareMessagesTools } => {
if (!supportsTools) {
return { messages: messages }
}
else if (supportsTools === 'anthropic-style') {
return prepareMessages_tools_anthropic({ messages })
}
else if (supportsTools === 'mistral-style') {
return prepareMessages_tools_mistral({ messages })
}
else if (supportsTools === 'openai-style') {
return prepareMessages_tools_openai({ messages })
}
@ -456,12 +453,7 @@ const prepareMessages_noEmptyMessage = ({ messages }: { messages: PrepareMessage
return { messages }
}
type PrepareMessagesToolsMistral = PrepareMessagesToolsOpenAI;
// Implémentation pour Mistral qui réutilise celle d'OpenAI
const prepareMessages_tools_mistral = ({ messages }: { messages: InternalLLMChatMessage[] }) => {
return prepareMessages_tools_openai({ messages });
};
// --- CHAT ---
@ -477,7 +469,7 @@ export const prepareMessages = ({
messages: LLMChatMessage[],
aiInstructions: string,
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated',
supportsTools: false | 'anthropic-style' | 'openai-style' | 'mistral-style',
supportsTools: false | 'anthropic-style' | 'openai-style',
supportsAnthropicReasoningSignature: boolean,
contextWindow: number,
maxOutputTokens: number | null | undefined,

View file

@ -6,11 +6,10 @@
import Anthropic from '@anthropic-ai/sdk';
import { Ollama } from 'ollama';
import OpenAI, { ClientOptions } from 'openai';
// Mistral FIM
import { MistralCore } from "@mistralai/mistralai/core.js";
import { fimComplete } from "@mistralai/mistralai/funcs/fimComplete.js";
//
import { extractReasoningOnFinalMessage, extractReasoningOnTextWrapper } from '../../common/helpers/extractCodeFromResult.js';
import { LLMChatMessage, LLMFIMMessage, ModelListParams, OllamaModelResponse, OnError, OnFinalMessage, OnText } from '../../common/sendLLMMessageTypes.js';
import { defaultProviderSettings, displayInfoOfProviderName, ModelSelectionOptions, ProviderName, SettingsOfProvider } from '../../common/voidSettingsTypes.js';
@ -18,12 +17,6 @@ import { prepareFIMMessage, prepareMessages } from './preprocessLLMMessages.js';
import { getSendableReasoningInfo, getModelCapabilities, getProviderCapabilities } from '../../common/modelCapabilities.js';
import { InternalToolInfo, ToolName, isAToolName } from '../../common/toolsServiceTypes.js';
// Déclarer les types manquants pour résoudre les erreurs de linter
declare const PrepareMessagesToolsOpenAI: any;
declare const prepareMessages_tools_openai: any;
declare const prepareMessages_tools_anthropic: any;
declare const InternalLLMChatMessage: any;
declare const PrepareMessagesTools: any;
type InternalCommonMessageParams = {
aiInstructions: string;
@ -434,43 +427,11 @@ const sendAnthropicChat = ({ messages: messages_, providerName, onText, onFinalM
_setAborter(() => stream.controller.abort())
}
//////// MISTRAL ////////
const _sendMistralChat = ({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelName: modelName_, _setAborter, providerName, aiInstructions, modelSelectionOptions, tools: tools_ }: SendChatParams_Internal) => {
const {
supportsSystemMessage,
supportsTools,
contextWindow,
maxOutputTokens,
} = getModelCapabilities(providerName, modelName_);
// Preprocess messages for Mistral format
prepareMessages({
messages: messages_,
aiInstructions,
supportsSystemMessage,
supportsTools,
supportsAnthropicReasoningSignature: false,
contextWindow,
maxOutputTokens
});
// For Mistral, we use the OpenAI compatible implementation
_sendOpenAICompatibleChat({
messages: messages_,
onText,
onFinalMessage,
onError,
settingsOfProvider,
modelName: modelName_,
_setAborter,
providerName,
aiInstructions,
modelSelectionOptions,
tools: tools_
});
}
const _sendMistralFIM = ({ messages: messages_, onFinalMessage, onError, settingsOfProvider, modelName: modelName_, _setAborter, providerName, aiInstructions, modelSelectionOptions }: SendFIMParams_Internal) => {
// ------------ MISTRAL ------------
// https://docs.mistral.ai/api/#tag/fim
const sendMistralFIM = ({ messages: messages_, onFinalMessage, onError, settingsOfProvider, modelName: modelName_, _setAborter, providerName, aiInstructions, modelSelectionOptions }: SendFIMParams_Internal) => {
const { modelName, supportsFIM } = getModelCapabilities(providerName, modelName_)
if (!supportsFIM) {
if (modelName === modelName_)
@ -479,25 +440,23 @@ const _sendMistralFIM = ({ messages: messages_, onFinalMessage, onError, setting
onError({ message: `Model ${modelName_} (${modelName}) does not support FIM.`, fullError: null })
return
}
prepareFIMMessage({ messages: messages_, aiInstructions })
const messages = prepareFIMMessage({ messages: messages_, aiInstructions })
const mistral = new MistralCore({ apiKey: settingsOfProvider.mistral.apiKey })
fimComplete(
mistral, {
model: modelName,
prompt: messages_.prefix,
suffix: messages_.suffix,
stream: false,
topP: 1,
stop: messages_.stopTokens
},
)
fimComplete(mistral,
{
model: modelName,
prompt: messages.prefix,
suffix: messages.suffix,
stream: false,
maxTokens: messages.maxTokens,
stop: messages.stopTokens,
})
.then(async response => {
let content = response?.ok ? response.value.choices?.[0]?.message?.content : '';
const fullText = typeof content === 'string' ? content :
Array.isArray(content) ? content.map(chunk => chunk.type === 'text' ? chunk.text : '').join('') : '';
let content = response?.ok ? response.value.choices?.[0]?.message?.content ?? '' : '';
const fullText = typeof content === 'string' ? content
: content.map(chunk => (chunk.type === 'text' ? chunk.text : '')).join('')
onFinalMessage({ fullText, fullReasoning: '', anthropicReasoning: null });
})
.catch(error => {
@ -505,9 +464,6 @@ const _sendMistralFIM = ({ messages: messages_, onFinalMessage, onError, setting
})
}
// // in future, can do tool_use streaming in anthropic, but it's pretty fast even without streaming...
// const toolCallOfIndex: { [index: string]: { name: string, args: string } } = {}
// stream.on('streamEvent', e => {
@ -622,8 +578,8 @@ export const sendLLMMessageToProviderImplementation = {
list: null,
},
mistral: {
sendChat: (params) => _sendMistralChat(params),
sendFIM: (params) => _sendMistralFIM(params),
sendChat: (params) => _sendOpenAICompatibleChat(params),
sendFIM: (params) => sendMistralFIM(params),
list: null,
},
ollama: {
@ -671,7 +627,7 @@ codestral https://ollama.com/library/codestral/blobs/51707752a87c
[SUFFIX]{{ .Suffix }}[PREFIX] {{ .Prompt }}
deepseek-coder-v2 https://ollama.com/library/deepseek-coder-v2/blobs/22091531faf0
{{ .Prompt }}
<fimbegin>{{ .Prompt }}<fimhole>{{ .Suffix }}<fimend>
starcoder2 https://ollama.com/library/starcoder2/blobs/3b190e68fefe
<file_sep>