diff --git a/src/vs/platform/void/browser/llmMessageService.ts b/src/vs/platform/void/browser/llmMessageService.ts index cbbf1f2c..cab3f151 100644 --- a/src/vs/platform/void/browser/llmMessageService.ts +++ b/src/vs/platform/void/browser/llmMessageService.ts @@ -74,25 +74,27 @@ export class SendLLMMessageService extends Disposable implements ISendLLMMessage sendLLMMessage(params: LLMMessageServiceParams) { - const requestId_ = generateUuid(); const { onText, onFinalMessage, onError, ...proxyParams } = params; + const { featureName } = proxyParams + // end early if no provider + const modelSelection = this.voidConfigStateService.state.modelSelectionOfFeature[featureName] + if (modelSelection === null) { + this.notificationService.warn('Please add a Provider in Settings!') + setTimeout(() => onError({ error: 'Please add a Provider in Settings!' }), 100) + return null + } + const { providerName, modelName } = modelSelection + + // add state for request id + const requestId_ = generateUuid(); this.onTextHooks[requestId_] = onText this.onFinalMessageHooks[requestId_] = onFinalMessage this.onErrorHooks[requestId_] = onError - const { featureName } = params - - // params will be stripped of all its functions - const stateOfFeature = this.voidConfigStateService.state.modelSelectionOfFeature[featureName] - if (stateOfFeature === null) { - this.notificationService.warn('Please add a Provider in Settings!') - return null - } - const { providerName, modelName } = stateOfFeature - const { settingsOfProvider } = this.voidConfigStateService.state + // params will be stripped of all its functions over the IPC channel this.channel.call('sendLLMMessage', { ...proxyParams, requestId: requestId_, diff --git a/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts b/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts index 2e0fd71c..8903bdcb 100644 --- a/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts +++ b/src/vs/platform/void/electron-main/llmMessage/sendLLMMessage.ts @@ -91,7 +91,7 @@ export const sendLLMMessage = ({ sendGroqMsg({ messages, onText, onFinalMessage, onError, settingsOfProvider, modelName, _setAborter, providerName }); break; default: - onError({ error: `Error: whichApi was "${providerName}", which is not recognized!` }) + onError({ error: `Error: Void provider was "${providerName}", which is not recognized.` }) 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 cb19e292..f44ed0c9 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 @@ -94,7 +94,9 @@ export const SelectedFiles = ( } -const ChatBubble = ({ chatMessage }: { chatMessage: ChatMessage }) => { +const ChatBubble = ({ chatMessage }: { + chatMessage: ChatMessage +}) => { const role = chatMessage.role const children = chatMessage.displayContent @@ -191,8 +193,8 @@ export const SidebarChat = () => { const currentThread = threadsStateService.getCurrentThread(threadsStateService.state) // the the instant state right now, don't wait for the React state - // send message to LLM + setIsLoading(true) // must come before message is sent so onError will work const object: LLMMessageServiceParams = { logging: { loggingName: 'Chat' }, @@ -228,7 +230,6 @@ export const SidebarChat = () => { latestRequestIdRef.current = latestRequestId - setIsLoading(true) if (inputBoxRef.current) { inputBoxRef.current.value = ''; // this triggers onDidChangeText inputBoxRef.current.blur(); diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarModelSettings.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarModelSettings.tsx index b2b081d4..ed0ce6ce 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarModelSettings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarModelSettings.tsx @@ -3,7 +3,7 @@ * Void Editor additions licensed under the AGPLv3 License. *--------------------------------------------------------------------------------------------*/ -import { FeatureName, featureNames, providerNames } from '../../../../../../../platform/void/common/voidConfigTypes.js' +import { FeatureName, featureNames, ProviderName, providerNames } from '../../../../../../../platform/void/common/voidConfigTypes.js' import { useConfigState, useService } from '../util/services.js' import ErrorBoundary from './ErrorBoundary.js' import { VoidSelectBox } from './inputs.js' @@ -25,21 +25,24 @@ export const SidebarModelSettingsForFeature = ({ featureName }: { featureName: F }) } - return <> -

{'Models'}

- {models.length === 0 ? -

{'Please add a provider!'}

- : + const wasEmpty = models.length === 0 + if (wasEmpty) { + models.push(['Provider', 'Model']) + } + + return <> +

{featureName}

+ { s.join(' - '))} - onChangeSelection={(newVal) => { /*voidConfigService.setFeatureState(providerName, 'model', newVal)*/ }} + initVal={models[0]} + options={wasEmpty ? [{ text: 'Please add a Provider!', value: models[0] }] : models.map(s => ({ text: s.join(' - '), value: s }))} + onChangeSelection={(newVal) => { voidConfigService.setModelSelectionOfFeature(featureName, { providerName: newVal[0] as ProviderName, modelName: newVal[1] }) }} selectBoxRef={{ current: null }} />} {/*

Settings - {featureName}

*/} {/* {models.map(([providerName, model], i) =>

{providerName} - {model}

)} */} -
+ } export const SidebarModelSettings = () => { diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarProviderSettings.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarProviderSettings.tsx index b9435a56..d1bd2afb 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarProviderSettings.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarProviderSettings.tsx @@ -20,19 +20,24 @@ const Setting = ({ providerName, settingName }: { providerName: ProviderName, se useEffect(() => { // this is really just to sync the state on initial mount, when init value hasn't been set yet - const syncState = () => { + let synced = false + const syncStateOnMount = () => { if (!instanceRef.current) return + if (synced) return + synced = true const settingsAtProvider = voidConfigService.state.settingsOfProvider[providerName]; // @ts-ignore const stateVal = settingsAtProvider[settingName] - if (instanceRef.current.value !== stateVal) - instanceRef.current.value = stateVal + if (instanceRef.current.value !== stateVal) { + instanceRef.current.value = stateVal // triggers onDidChangeState + } } - syncState() - const disposable = voidConfigService.onDidChangeState(syncState) + syncStateOnMount() + synced = false // sync the next time state changes (but not after that - the "current.value = ..." triggers a state change, causing an infinite loop!) + const disposable = voidConfigService.onDidChangeState(syncStateOnMount) return () => disposable.dispose() }, [instanceRef, voidConfigService]) diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/inputs.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/inputs.tsx index ae0646bb..d8174ea8 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/inputs.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/inputs.tsx @@ -91,11 +91,11 @@ export const VoidInputBox = ({ onChangeText, onCreateInstance, placeholder, mult -export const VoidSelectBox = ({ onChangeSelection, initVal, selectBoxRef, options }: { - onChangeSelection: (value: string) => void; - initVal: string; +export const VoidSelectBox = ({ onChangeSelection, initVal, selectBoxRef, options }: { + initVal: T; selectBoxRef: React.MutableRefObject; - options: readonly string[]; + options: readonly { text: string, value: T }[]; + onChangeSelection: (value: T) => void; }) => { const containerRef = useRef(null); @@ -104,10 +104,10 @@ export const VoidSelectBox = ({ onChangeSelection, initVal, selectBoxRef, option useEffect(() => { if (!containerRef.current) return; - const defaultIndex = options.indexOf(initVal); + const defaultIndex = options.findIndex(opt => opt.value === initVal); selectBoxRef.current = new SelectBox( - options.map(opt => ({ text: opt, detail: 'detail', description: 'description' })), + options.map(opt => ({ text: opt.text })), defaultIndex, contextViewProvider, unthemedSelectBoxStyles @@ -115,7 +115,7 @@ export const VoidSelectBox = ({ onChangeSelection, initVal, selectBoxRef, option selectBoxRef.current.render(containerRef.current); - selectBoxRef.current.onDidSelect(e => { onChangeSelection(e.selected); }); + selectBoxRef.current.onDidSelect(e => { console.log('e.selected', JSON.stringify(e)); onChangeSelection(options[e.index].value); }); // cleanup return () => { @@ -137,58 +137,58 @@ export const VoidSelectBox = ({ onChangeSelection, initVal, selectBoxRef, option -export const VoidCheckBox = ({ onChangeChecked, initVal, label, checkboxRef, }: { - onChangeChecked: (checked: boolean) => void; - initVal: boolean; - checkboxRef: React.MutableRefObject; - label: string; -}) => { - const containerRef = useRef(null); +// export const VoidCheckBox = ({ onChangeChecked, initVal, label, checkboxRef, }: { +// onChangeChecked: (checked: boolean) => void; +// initVal: boolean; +// checkboxRef: React.MutableRefObject; +// label: string; +// }) => { +// const containerRef = useRef(null); - const themeService = useService('themeService'); - const contextViewService = useService('contextViewService'); - const hoverService = useService('hoverService'); +// const themeService = useService('themeService'); +// const contextViewService = useService('contextViewService'); +// const hoverService = useService('hoverService'); - useEffect(() => { - if (!containerRef.current) return; +// useEffect(() => { +// if (!containerRef.current) return; - // Create and mount the Checkbox using VSCode's implementation +// // Create and mount the Checkbox using VSCode's implementation - checkboxRef.current = new ObjectSettingCheckboxWidget( - containerRef.current, - themeService, - contextViewService, - hoverService, - ); +// checkboxRef.current = new ObjectSettingCheckboxWidget( +// containerRef.current, +// themeService, +// contextViewService, +// hoverService, +// ); - checkboxRef.current.setValue([{ - key: { type: 'string', data: label }, - value: { type: 'boolean', data: initVal }, - removable: false, - resetable: true, - }]) +// checkboxRef.current.setValue([{ +// key: { type: 'string', data: label }, +// value: { type: 'boolean', data: initVal }, +// removable: false, +// resetable: true, +// }]) - checkboxRef.current.onDidChangeList((list) => { - onChangeChecked(!!list); - }) +// checkboxRef.current.onDidChangeList((list) => { +// onChangeChecked(!!list); +// }) - // cleanup - return () => { - if (checkboxRef.current) { - checkboxRef.current.dispose(); - if (containerRef.current) { - while (containerRef.current.firstChild) { - containerRef.current.removeChild(containerRef.current.firstChild); - } - } - checkboxRef.current = null; - } - }; - }, [checkboxRef, label, initVal, onChangeChecked]); +// // cleanup +// return () => { +// if (checkboxRef.current) { +// checkboxRef.current.dispose(); +// if (containerRef.current) { +// while (containerRef.current.firstChild) { +// containerRef.current.removeChild(containerRef.current.firstChild); +// } +// } +// checkboxRef.current = null; +// } +// }; +// }, [checkboxRef, label, initVal, onChangeChecked]); - return
; -}; +// return
; +// };