diff --git a/src/vs/platform/void/common/refreshModelService.ts b/src/vs/platform/void/common/refreshModelService.ts index b9b44e83..1f6b08f3 100644 --- a/src/vs/platform/void/common/refreshModelService.ts +++ b/src/vs/platform/void/common/refreshModelService.ts @@ -75,7 +75,7 @@ export class RefreshModelService extends Disposable implements IRefreshModelServ this._cancelTimeout() // if ollama is disabled, obivously done - if (this.voidSettingsService.state.settingsOfProvider.ollama.enabled !== 'true') { + if (!this.voidSettingsService.state.settingsOfProvider.ollama.enabled) { this._setState('done') return } diff --git a/src/vs/platform/void/common/voidSettingsService.ts b/src/vs/platform/void/common/voidSettingsService.ts index a11e3f60..ab9d28f8 100644 --- a/src/vs/platform/void/common/voidSettingsService.ts +++ b/src/vs/platform/void/common/voidSettingsService.ts @@ -13,7 +13,7 @@ import { IStorageService, StorageScope, StorageTarget } from '../../storage/comm import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, modelInfoOfDefaultNames, ModelInfo } from './voidSettingsTypes.js'; -const STORAGE_KEY = 'void.voidSettings' +const STORAGE_KEY = 'void.voidSettingsI' type SetSettingOfProviderFn = ( providerName: ProviderName, @@ -60,7 +60,7 @@ let _computeModelOptions = (settingsOfProvider: SettingsOfProvider) => { let modelOptions: ModelOption[] = [] for (const providerName of providerNames) { const providerConfig = settingsOfProvider[providerName] - if (providerConfig.enabled !== 'true') continue + if (!providerConfig.enabled) continue // if disabled, don't display model options for (const { modelName, isHidden } of providerConfig.models) { if (isHidden) continue modelOptions.push({ text: `${modelName} (${providerName})`, value: { providerName, modelName } }) diff --git a/src/vs/platform/void/common/voidSettingsTypes.ts b/src/vs/platform/void/common/voidSettingsTypes.ts index 689888cb..6de2f47f 100644 --- a/src/vs/platform/void/common/voidSettingsTypes.ts +++ b/src/vs/platform/void/common/voidSettingsTypes.ts @@ -5,6 +5,8 @@ *--------------------------------------------------------------------------------------------*/ + + export type ModelInfo = { modelName: string, isDefault: boolean, // whether or not it's a default for its provider @@ -90,16 +92,11 @@ export const anthropicMaxPossibleTokens = (modelName: string) => { } -// export const dummyModelData = { -// anthropic: ['claude 3.5'], -// openAI: ['gpt 4o'], -// ollama: ['llama 3.2', 'codestral'], -// openRouter: ['qwen 2.5'], -// } +type UnionOfKeys = T extends T ? keyof T : never; -export const voidProviderDefaults = { +export const customProviderSettingsDefaults = { anthropic: { apiKey: '', }, @@ -124,57 +121,30 @@ export const voidProviderDefaults = { } } as const +export type ProviderName = keyof typeof customProviderSettingsDefaults +export const providerNames = Object.keys(customProviderSettingsDefaults) as ProviderName[] -export const voidInitModelOptions = { - anthropic: { - models: defaultAnthropicModels, - }, - openAI: { - models: defaultOpenAIModels, - }, - ollama: { - models: [], - }, - openRouter: { - models: [], // any string - }, - openAICompatible: { - models: [], - }, - gemini: { - models: defaultGeminiModels, - }, - groq: { - models: defaultGroqModels, - }, + +type CustomSettingName = UnionOfKeys + +type CustomProviderSettings = { + [k in CustomSettingName]: k extends keyof typeof customProviderSettingsDefaults[providerName] ? string : undefined } +type CommonProviderSettings = { + enabled: boolean, + models: ModelInfo[], // if null, user can type in any string as a model +} +type SettingsForProvider = CustomProviderSettings & CommonProviderSettings -export type ProviderName = keyof typeof voidProviderDefaults -export const providerNames = Object.keys(voidProviderDefaults) as ProviderName[] - - - -// state +// part of state export type SettingsOfProvider = { - [providerName in ProviderName]: ( - { - [optionName in keyof typeof voidProviderDefaults[providerName]]: string - } - & - { - enabled: string, // 'true' | 'false' - - models: ModelInfo[], // if null, user can type in any string as a model - }) + [providerName in ProviderName]: SettingsForProvider } -type UnionOfKeys = T extends T ? keyof T : never; - -export type SettingName = UnionOfKeys - +export type SettingName = keyof SettingsForProvider @@ -219,7 +189,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName title: providerName === 'ollama' ? 'Your Ollama endpoint' : providerName === 'openAICompatible' ? 'baseURL' // (do not include /chat/completions) : '(never)', - placeholder: providerName === 'ollama' ? voidProviderDefaults.ollama.endpoint + placeholder: providerName === 'ollama' ? customProviderSettingsDefaults.ollama.endpoint : providerName === 'openAICompatible' ? 'https://my-website.com/v1' : '(never)', } @@ -242,42 +212,81 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName } + + +const defaultCustomSettings: Record = { + apiKey: undefined, + endpoint: undefined, +} + +export const voidInitModelOptions = { + anthropic: { + models: defaultAnthropicModels, + }, + openAI: { + models: defaultOpenAIModels, + }, + ollama: { + models: [], + }, + openRouter: { + models: [], // any string + }, + openAICompatible: { + models: [], + }, + gemini: { + models: defaultGeminiModels, + }, + groq: { + models: defaultGroqModels, + }, +} + + // used when waiting and for a type reference export const defaultSettingsOfProvider: SettingsOfProvider = { anthropic: { - ...voidProviderDefaults.anthropic, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.anthropic, ...voidInitModelOptions.anthropic, - enabled: 'false', + enabled: false, }, openAI: { - ...voidProviderDefaults.openAI, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.openAI, ...voidInitModelOptions.openAI, - enabled: 'false', + enabled: false, }, gemini: { - ...voidProviderDefaults.gemini, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.gemini, ...voidInitModelOptions.gemini, - enabled: 'false', + enabled: false, }, groq: { - ...voidProviderDefaults.groq, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.groq, ...voidInitModelOptions.groq, - enabled: 'false', + enabled: false, }, ollama: { - ...voidProviderDefaults.ollama, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.ollama, ...voidInitModelOptions.ollama, - enabled: 'false', + enabled: false, }, openRouter: { - ...voidProviderDefaults.openRouter, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.openRouter, ...voidInitModelOptions.openRouter, - enabled: 'false', + enabled: false, }, openAICompatible: { - ...voidProviderDefaults.openAICompatible, + ...defaultCustomSettings, + ...customProviderSettingsDefaults.openAICompatible, ...voidInitModelOptions.openAICompatible, - enabled: 'false', + enabled: false, }, } diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx index 08cbd52e..59abfcde 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/ModelDropdown.tsx @@ -43,7 +43,6 @@ const DummySelectBox = () => { return { }} - onCreateInstance={() => { }} /> } diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx index 6c5648de..60f8501b 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx @@ -1,8 +1,8 @@ -import React, { useCallback } from 'react' +import React, { useCallback, useRef, useState } from 'react' import { InputBox } from '../../../../../../../base/browser/ui/inputbox/inputBox.js' import { ProviderName, SettingName, displayInfoOfSettingName, titleOfProviderName, providerNames, ModelInfo } from '../../../../../../../platform/void/common/voidSettingsTypes.js' import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js' -import { VoidInputBox } from '../util/inputs.js' +import { VoidInputBox, VoidSelectBox } from '../util/inputs.js' import { useIsDark, useRefreshModelState, useService, useSettingsState } from '../util/services.js' @@ -15,7 +15,7 @@ const RefreshableModels = () => { const refreshModelState = useRefreshModelState() const refreshModelService = useService('refreshModelService') - if (settingsState.settingsOfProvider.ollama.enabled !== 'true') + if (!settingsState.settingsOfProvider.ollama.enabled) return null return <> @@ -26,8 +26,82 @@ const RefreshableModels = () => { +const AddModelMenu = ({ onSubmit }: { onSubmit: () => void }) => { + const settingsStateService = useService('settingsStateService') + const settingsState = useSettingsState() -export const ModelMenu = () => { + const providerNameRef = useRef(null) + const modelNameRef = useRef(null) + + const [errorString, setErrorString] = useState('') + + const providerOptions = providerNames.map(providerName => ({ text: titleOfProviderName(providerName), value: providerName })) + + return
+ {/* model */} +
+ { modelNameRef.current = modelName }} + multiline={false} + /> +
+ + {/* provider */} +
+ { providerNameRef.current = providerOptions[0].value }} // initialize state + onChangeSelection={(providerName: ProviderName) => { console.log('selecting provider', providerName); providerNameRef.current = providerName }} + options={providerOptions} + /> +
+ + {/* button */} +
+ +
+ + {!errorString ? null : <> + {errorString} + } +
+ +} + +const AddModelButton = () => { + const [open, setOpen] = useState(false) + + return <> + {open ? + { setOpen(false) }} /> + : + } + +} + + +export const ModelDump = () => { const settingsStateService = useService('settingsStateService') const settingsState = useSettingsState() @@ -36,21 +110,30 @@ export const ModelMenu = () => { const modelDump: (ModelInfo & { providerName: ProviderName })[] = [] for (let providerName of providerNames) { const providerSettings = settingsState.settingsOfProvider[providerName] - if (providerSettings.enabled !== 'true') continue + if (!providerSettings.enabled) continue modelDump.push(...providerSettings.models.map(model => ({ ...model, providerName }))) } - return <> + return
{modelDump.map(m => { const { isHidden, isDefault, modelName, providerName } = m - return
- {modelName} {isDefault ? '' : '(custom)'} - {providerName} - { settingsStateService.toggleModelHidden(providerName, modelName) }}>{isHidden ? 'hidden' : '✅'} + return
+ {/* left part is width:full */} +
+ {`${modelName} (${providerName})`} +
+ {/* right part is anything that fits */} +
+ {isDefault ? '' : '(custom model)'} +
{ settingsStateService.toggleModelHidden(providerName, modelName) }}>{isHidden ? '❌' : '✅'}
+
+ {isDefault ? null : } +
+
})} - +
} @@ -78,7 +161,7 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider onCreateInstance={useCallback((instance: InputBox) => { const syncInstance = () => { const settingsAtProvider = voidSettingsService.state.settingsOfProvider[providerName]; - const stateVal = settingsAtProvider[settingName as keyof typeof settingsAtProvider] + const stateVal = settingsAtProvider[settingName as SettingName] // console.log('SYNCING TO', providerName, settingName, stateVal) weChangedTextRef = true instance.value = stateVal as string @@ -96,10 +179,16 @@ const ProviderSetting = ({ providerName, settingName }: { providerName: Provider const SettingsForProvider = ({ providerName }: { providerName: ProviderName }) => { const voidSettingsState = useSettingsState() - const { models, ...others } = voidSettingsState.settingsOfProvider[providerName] + const voidSettingsService = useService('settingsStateService') + + const { models, enabled, ...others } = voidSettingsState.settingsOfProvider[providerName] return <> -

{titleOfProviderName(providerName)}

+ +
+

{titleOfProviderName(providerName)}

+ { voidSettingsService.setSettingOfProvider(providerName, 'enabled', !enabled) }}>{enabled ? '✅' : '❌'} +
{/* settings besides models (e.g. api key) */} {Object.keys(others).map((sName, i) => { const settingName = sName as keyof typeof others @@ -123,19 +212,22 @@ export const VoidProviderSettings = () => { export const Settings = () => { const isDark = useIsDark() - return
-
+ return
+
+

Models

- + + -
- - - +

Providers

+ + + +