mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
add developer info for models
This commit is contained in:
parent
9cfcf396c1
commit
0975f1bf5f
3 changed files with 206 additions and 122 deletions
|
|
@ -11,7 +11,7 @@ import { registerSingleton, InstantiationType } from '../../../../platform/insta
|
||||||
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
|
||||||
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
|
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
|
||||||
import { IMetricsService } from './metricsService.js';
|
import { IMetricsService } from './metricsService.js';
|
||||||
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, modelInfoOfDefaultModelNames, VoidModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, displayInfoOfProviderName, defaultProviderSettings } from './voidSettingsTypes.js';
|
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, VoidModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, displayInfoOfProviderName, defaultProviderSettings, developerInfoOfRecognizedModel, modelInfoOfAutodetectedModelNames } from './voidSettingsTypes.js';
|
||||||
|
|
||||||
|
|
||||||
const STORAGE_KEY = 'void.settingsServiceStorage'
|
const STORAGE_KEY = 'void.settingsServiceStorage'
|
||||||
|
|
@ -289,27 +289,26 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
setAutodetectedModels(providerName: ProviderName, newDefaultModelNames: string[], logging: object) {
|
setAutodetectedModels(providerName: ProviderName, autodetectedModelNames: string[], logging: object) {
|
||||||
|
|
||||||
const { models } = this.state.settingsOfProvider[providerName]
|
const { models } = this.state.settingsOfProvider[providerName]
|
||||||
|
|
||||||
const oldModelNames = models.map(m => m.modelName)
|
const oldModelNames = models.map(m => m.modelName)
|
||||||
|
|
||||||
const newDefaultModelInfo = modelInfoOfDefaultModelNames(newDefaultModelNames, { isAutodetected: true, existingModels: models })
|
|
||||||
const newModelInfo = [
|
const newDefaultModels = modelInfoOfAutodetectedModelNames(autodetectedModelNames, { existingModels: models })
|
||||||
...newDefaultModelInfo, // swap out all the default models for the new default models
|
const newModels = [
|
||||||
...models.filter(m => !m.isDefault), // keep any non-defaul (custom) models
|
...newDefaultModels, // swap out all the default models for the new default models
|
||||||
|
...models.filter(m => !m.isDefault), // keep any non-default (custom) models
|
||||||
]
|
]
|
||||||
|
|
||||||
|
this.setSettingOfProvider(providerName, 'models', newModels)
|
||||||
this.setSettingOfProvider(providerName, 'models', newModelInfo)
|
|
||||||
|
|
||||||
// if the models changed, log it
|
// if the models changed, log it
|
||||||
const new_names = newModelInfo.map(m => m.modelName)
|
const new_names = newModels.map(m => m.modelName)
|
||||||
if (!(oldModelNames.length === new_names.length
|
if (!(oldModelNames.length === new_names.length
|
||||||
&& oldModelNames.every((_, i) => oldModelNames[i] === new_names[i]))
|
&& oldModelNames.every((_, i) => oldModelNames[i] === new_names[i]))
|
||||||
) {
|
) {
|
||||||
this._metricsService.capture('Autodetect Models', { providerName, newModels: newModelInfo, ...logging })
|
this._metricsService.capture('Autodetect Models', { providerName, newModels: newModels, ...logging })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
toggleModelHidden(providerName: ProviderName, modelName: string) {
|
toggleModelHidden(providerName: ProviderName, modelName: string) {
|
||||||
|
|
@ -335,7 +334,7 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
|
||||||
if (existingIdx !== -1) return // if exists, do nothing
|
if (existingIdx !== -1) return // if exists, do nothing
|
||||||
const newModels = [
|
const newModels = [
|
||||||
...models,
|
...models,
|
||||||
{ modelName, isDefault: false, isHidden: false }
|
{ ...developerInfoOfRecognizedModel(modelName), modelName, isDefault: false, isHidden: false }
|
||||||
]
|
]
|
||||||
this.setSettingOfProvider(providerName, 'models', newModels)
|
this.setSettingOfProvider(providerName, 'models', newModels)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,45 +7,217 @@
|
||||||
import { VoidSettingsState } from './voidSettingsService.js'
|
import { VoidSettingsState } from './voidSettingsService.js'
|
||||||
|
|
||||||
|
|
||||||
export type VoidModelInfo = {
|
|
||||||
|
// developer info used in sendLLMMessage
|
||||||
|
type VoidModelDeveloperInfo = {
|
||||||
|
supportsSystemMessage: 'system' | 'developer' | false, // if null, we will just do a string of system message
|
||||||
|
supportsTools: boolean, // we will just do a string of tool use if it doesn't support
|
||||||
|
supportsAutocompleteFIM: boolean, // we will just do a description of FIM if it doens't support <|fim_hole|>
|
||||||
|
supportsStreaming: boolean, // (o1 does NOT) we will just dump the final result if doesn't support it
|
||||||
|
maxTokens: number, // required, DEFAULT is Infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
export type VoidModelInfo = { // <-- STATEFUL
|
||||||
modelName: string,
|
modelName: string,
|
||||||
isDefault: boolean, // whether or not it's a default for its provider
|
isDefault: boolean, // whether or not it's a default for its provider
|
||||||
isHidden: boolean, // whether or not the user is hiding it (switched off)
|
isHidden: boolean, // whether or not the user is hiding it (switched off)
|
||||||
isAutodetected?: boolean, // whether the model was autodetected by polling
|
isAutodetected?: boolean, // whether the model was autodetected by polling
|
||||||
}
|
} & VoidModelDeveloperInfo
|
||||||
|
|
||||||
// creates `modelInfo` from `modelNames`
|
|
||||||
export const modelInfoOfDefaultModelNames = (defaultModelNames: string[], options?: { isAutodetected: true, existingModels: VoidModelInfo[] }): VoidModelInfo[] => {
|
|
||||||
|
|
||||||
const { isAutodetected, existingModels } = options ?? {}
|
|
||||||
|
|
||||||
if (!existingModels) { // default settings
|
|
||||||
|
|
||||||
return defaultModelNames.map((modelName, i) => ({
|
|
||||||
modelName,
|
|
||||||
isDefault: true,
|
|
||||||
isAutodetected: isAutodetected,
|
|
||||||
isHidden: defaultModelNames.length >= 10 // hide all models if there are a ton of them, and make user enable them individually
|
|
||||||
}))
|
|
||||||
|
|
||||||
} else { // settings if there are existing models (keep existing `isHidden` property)
|
|
||||||
|
|
||||||
const existingModelsMap: Record<string, VoidModelInfo> = {}
|
|
||||||
for (const existingModel of existingModels) {
|
|
||||||
existingModelsMap[existingModel.modelName] = existingModel
|
|
||||||
}
|
|
||||||
|
|
||||||
return defaultModelNames.map((modelName, i) => ({
|
|
||||||
modelName,
|
|
||||||
isDefault: true,
|
|
||||||
isAutodetected: isAutodetected,
|
|
||||||
isHidden: !!existingModelsMap[modelName]?.isHidden,
|
|
||||||
}))
|
|
||||||
|
|
||||||
|
export const recognizedModels = [
|
||||||
|
// chat
|
||||||
|
'OpenAI 4o',
|
||||||
|
'Anthropic Claude',
|
||||||
|
'Llama 3.x',
|
||||||
|
'Deepseek Chat', // deepseek coder v2 is now merged into chat (V3) https://api-docs.deepseek.com/updates#deepseek-coder--deepseek-chat-upgraded-to-deepseek-v25-model
|
||||||
|
// 'xAI Grok',
|
||||||
|
// 'Google Gemini, Gemma',
|
||||||
|
// 'Microsoft Phi4',
|
||||||
|
|
||||||
|
|
||||||
|
// coding (autocomplete)
|
||||||
|
'Alibaba Qwen2.5 Coder Instruct', // we recommend this over Qwen2.5
|
||||||
|
'Mistral Codestral',
|
||||||
|
|
||||||
|
// thinking
|
||||||
|
'OpenAI o1, o3',
|
||||||
|
'Deepseek R1',
|
||||||
|
|
||||||
|
// general
|
||||||
|
// 'Mixtral 8x7b'
|
||||||
|
// 'Qwen2.5',
|
||||||
|
|
||||||
|
] as const
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
type RecognizedModel = (typeof recognizedModels)[number] | '<GENERAL>'
|
||||||
|
|
||||||
|
|
||||||
|
// const modelCapabilities: { [recognizedModel in RecognizedModel]: ({ }) => string } = {
|
||||||
|
// 'OpenAI 4o': {
|
||||||
|
// template: ({ prefix, suffix, }: { prefix: string; suffix: string; }) => `\
|
||||||
|
// `
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
export function getRecognizedModel(modelName: string): RecognizedModel {
|
||||||
|
const lower = modelName.toLowerCase();
|
||||||
|
|
||||||
|
if (lower.includes('gpt-4o')) {
|
||||||
|
return 'OpenAI 4o';
|
||||||
|
}
|
||||||
|
if (lower.includes('claude')) {
|
||||||
|
return 'Anthropic Claude';
|
||||||
|
}
|
||||||
|
if (lower.includes('llama')) {
|
||||||
|
return 'Llama 3.x';
|
||||||
|
}
|
||||||
|
if (lower.includes('qwen2.5-coder')) {
|
||||||
|
return 'Alibaba Qwen2.5 Coder Instruct';
|
||||||
|
}
|
||||||
|
if (lower.includes('mistral')) {
|
||||||
|
return 'Mistral Codestral';
|
||||||
|
}
|
||||||
|
// Check for "o1" or "o3"
|
||||||
|
if (/\bo1\b/.test(lower) || /\bo3\b/.test(lower)) {
|
||||||
|
return 'OpenAI o1, o3';
|
||||||
|
}
|
||||||
|
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) {
|
||||||
|
return 'Deepseek R1';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback:
|
||||||
|
return '<GENERAL>';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export const developerInfoOfRecognizedModel = (modelName: string) => {
|
||||||
|
const devInfo: { [recognizedModel in RecognizedModel]: VoidModelDeveloperInfo } = {
|
||||||
|
'OpenAI 4o': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Anthropic Claude': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Llama 3.x': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Deepseek Chat': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Alibaba Qwen2.5 Coder Instruct': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Mistral Codestral': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'OpenAI o1, o3': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'Deepseek R1': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
|
||||||
|
'<GENERAL>': {
|
||||||
|
supportsSystemMessage: false,
|
||||||
|
supportsTools: false,
|
||||||
|
supportsAutocompleteFIM: false,
|
||||||
|
supportsStreaming: false,
|
||||||
|
maxTokens: 4096,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const modelName_ = getRecognizedModel(modelName)
|
||||||
|
return devInfo[modelName_]
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// creates `modelInfo` from `modelNames`
|
||||||
|
export const modelInfoOfDefaultModelNames = (defaultModelNames: string[]): VoidModelInfo[] => {
|
||||||
|
return defaultModelNames.map((modelName, i) => ({
|
||||||
|
modelName,
|
||||||
|
isDefault: true,
|
||||||
|
isAutodetected: false,
|
||||||
|
isHidden: defaultModelNames.length >= 10, // hide all models if there are a ton of them, and make user enable them individually
|
||||||
|
...developerInfoOfRecognizedModel(modelName)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const modelInfoOfAutodetectedModelNames = (defaultModelNames: string[], options: { existingModels: VoidModelInfo[] }) => {
|
||||||
|
const { existingModels } = options
|
||||||
|
|
||||||
|
const existingModelsMap: Record<string, VoidModelInfo> = {}
|
||||||
|
for (const existingModel of existingModels) {
|
||||||
|
existingModelsMap[existingModel.modelName] = existingModel
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultModelNames.map((modelName, i) => ({
|
||||||
|
modelName,
|
||||||
|
isDefault: true,
|
||||||
|
isAutodetected: true,
|
||||||
|
isHidden: !!existingModelsMap[modelName]?.isHidden,
|
||||||
|
...developerInfoOfRecognizedModel(modelName)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// https://docs.anthropic.com/en/docs/about-claude/models
|
// https://docs.anthropic.com/en/docs/about-claude/models
|
||||||
export const defaultAnthropicModels = modelInfoOfDefaultModelNames([
|
export const defaultAnthropicModels = modelInfoOfDefaultModelNames([
|
||||||
'claude-3-5-sonnet-20241022',
|
'claude-3-5-sonnet-20241022',
|
||||||
|
|
@ -530,77 +702,3 @@ export const globalSettingNames = Object.keys(defaultGlobalSettings) as GlobalSe
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export const recognizedModels = [
|
|
||||||
|
|
||||||
// chat
|
|
||||||
'OpenAI 4o',
|
|
||||||
'Anthropic Claude',
|
|
||||||
'Llama 3.x',
|
|
||||||
'Deepseek Chat', // deepseek coder v2 is now merged into chat (V3) https://api-docs.deepseek.com/updates#deepseek-coder--deepseek-chat-upgraded-to-deepseek-v25-model
|
|
||||||
// 'xAI Grok',
|
|
||||||
// 'Google Gemini, Gemma',
|
|
||||||
// 'Microsoft Phi4',
|
|
||||||
|
|
||||||
|
|
||||||
// coding (autocomplete)
|
|
||||||
'Alibaba Qwen2.5 Coder Instruct', // we recommend this over Qwen2.5
|
|
||||||
'Mistral Codestral',
|
|
||||||
|
|
||||||
// thinking
|
|
||||||
'OpenAI o1, o3',
|
|
||||||
'Deepseek R1',
|
|
||||||
|
|
||||||
// general
|
|
||||||
'<General>'
|
|
||||||
// 'Mixtral 8x7b'
|
|
||||||
// 'Qwen2.5',
|
|
||||||
|
|
||||||
] as const
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
type RecognizedModel = (typeof recognizedModels)[number]
|
|
||||||
|
|
||||||
|
|
||||||
// const modelCapabilities: { [recognizedModel in RecognizedModel]: ({ }) => string } = {
|
|
||||||
// 'OpenAI 4o': {
|
|
||||||
// template: ({ prefix, suffix, }: { prefix: string; suffix: string; }) => `\
|
|
||||||
// `
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
export function getRecognizedModel(modelName: string): RecognizedModel {
|
|
||||||
const lower = modelName.toLowerCase();
|
|
||||||
|
|
||||||
if (lower.includes('gpt-4o')) {
|
|
||||||
return 'OpenAI 4o';
|
|
||||||
}
|
|
||||||
if (lower.includes('claude')) {
|
|
||||||
return 'Anthropic Claude';
|
|
||||||
}
|
|
||||||
if (lower.includes('llama')) {
|
|
||||||
return 'Llama 3.x';
|
|
||||||
}
|
|
||||||
if (lower.includes('qwen2.5-coder')) {
|
|
||||||
return 'Alibaba Qwen2.5 Coder Instruct';
|
|
||||||
}
|
|
||||||
if (lower.includes('mistral')) {
|
|
||||||
return 'Mistral Codestral';
|
|
||||||
}
|
|
||||||
// Check for "o1" or "o3"
|
|
||||||
if (/\bo1\b/.test(lower) || /\bo3\b/.test(lower)) {
|
|
||||||
return 'OpenAI o1, o3';
|
|
||||||
}
|
|
||||||
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) {
|
|
||||||
return 'Deepseek R1';
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Fallback:
|
|
||||||
return '<General>';
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
/*
|
|
||||||
|
|
||||||
modelName -> {
|
|
||||||
system_message_type: 'system' | 'developer' (openai) | null // if null, we will just do a string of system message
|
|
||||||
supports_tools: boolean // we will just do a string of tool use if it doesn't support
|
|
||||||
supports_autocomplete_FIM (suffix) // we will just do a description of FIM if it doens't support <|fim_hole|>
|
|
||||||
|
|
||||||
supports_streaming: boolean // (o1 does NOT) we will just dump the final result if doesn't support it
|
|
||||||
max_tokens: number // required, DEFAULT is Infinity
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
Loading…
Reference in a new issue