diff --git a/extensions/void/src/common/sendLLMMessage.ts b/extensions/void/src/common/sendLLMMessage.ts index 43800a27..c3feea76 100644 --- a/extensions/void/src/common/sendLLMMessage.ts +++ b/extensions/void/src/common/sendLLMMessage.ts @@ -39,6 +39,13 @@ type SendLLMMessageFnTypeExternal = (params: { +const parseMaxTokensStr = (maxTokensStr: string) => { + // parse the string but only if the full string is a valid number, eg parseInt('100abc') should return NaN + let int = isNaN(Number(maxTokensStr)) ? undefined : parseInt(maxTokensStr) + if (Number.isNaN(int)) + return undefined + return int +} // Anthropic const sendAnthropicMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinalMessage, onError, voidConfig }) => { @@ -113,9 +120,11 @@ const sendOpenAIMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinal let openai: OpenAI let options: OpenAI.Chat.Completions.ChatCompletionCreateParamsStreaming + let maxTokens = parseMaxTokensStr(voidConfig.default.maxTokens) + if (voidConfig.default.whichApi === 'openAI') { openai = new OpenAI({ apiKey: voidConfig.openAI.apikey, dangerouslyAllowBrowser: true }); - options = { model: voidConfig.openAI.model, messages: messages, stream: true, max_completion_tokens: parseInt(voidConfig.default.maxTokens) } + options = { model: voidConfig.openAI.model, messages: messages, stream: true, max_completion_tokens: maxTokens } } else if (voidConfig.default.whichApi === 'openRouter') { openai = new OpenAI({ @@ -125,11 +134,11 @@ const sendOpenAIMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinal "X-Title": 'Void Editor', // Optional. Shows in rankings on openrouter.ai. }, }); - options = { model: voidConfig.openRouter.model, messages: messages, stream: true, max_completion_tokens: parseInt(voidConfig.default.maxTokens) } + options = { model: voidConfig.openRouter.model, messages: messages, stream: true, max_completion_tokens: maxTokens } } else if (voidConfig.default.whichApi === 'openAICompatible') { openai = new OpenAI({ baseURL: voidConfig.openAICompatible.endpoint, apiKey: voidConfig.openAICompatible.apikey, dangerouslyAllowBrowser: true }) - options = { model: voidConfig.openAICompatible.model, messages: messages, stream: true, max_completion_tokens: parseInt(voidConfig.default.maxTokens) } + options = { model: voidConfig.openAICompatible.model, messages: messages, stream: true, max_completion_tokens: maxTokens } } else { console.error(`sendOpenAIMsg: invalid whichApi: ${voidConfig.default.whichApi}`) diff --git a/extensions/void/src/extension.ts b/extensions/void/src/extension.ts index 989bf4b9..fbbc182d 100644 --- a/extensions/void/src/extension.ts +++ b/extensions/void/src/extension.ts @@ -5,7 +5,7 @@ import { v4 as uuidv4 } from 'uuid' import { AbortRef } from './common/sendLLMMessage'; import { DiffProvider } from './extension/DiffProvider'; import { SidebarWebviewProvider } from './extension/providers/SidebarWebviewProvider'; -import { getVoidConfig } from './webviews/common/contextForConfig'; +import { getVoidConfigFromPartial } from './webviews/common/contextForConfig'; import { applyDiffLazily } from './extension/ctrlL'; import { readFileContentOfUri } from './extension/extensionLib/readFileContentOfUri'; @@ -154,7 +154,7 @@ export function activate(context: vscode.ExtensionContext) { const docUri = editor.document.uri const fileStr = await readFileContentOfUri(docUri) - const voidConfig = getVoidConfig(context.globalState.get('partialVoidConfig') ?? {}) + const voidConfig = getVoidConfigFromPartial(context.globalState.get('partialVoidConfig') ?? {}) await applyDiffLazily({ docUri, oldFileStr: fileStr, diffRepr: m.diffRepr, voidConfig, diffProvider, diffArea, abortRef: abortApplyRef }) } diff --git a/extensions/void/src/extension/extension.ts b/extensions/void/src/extension/extension.ts index c3463365..7bfec5d8 100644 --- a/extensions/void/src/extension/extension.ts +++ b/extensions/void/src/extension/extension.ts @@ -3,7 +3,7 @@ import { applyDiffLazily } from './ctrlL'; import { readFileContentOfUri } from './extensionLib/readFileContentOfUri'; import { MessageToSidebar, MessageFromSidebar, DiffArea, ChatThreads } from '../common/shared_types'; import { DiffProvider } from './DiffProvider'; -import { getVoidConfig } from '../webviews/common/contextForConfig'; +import { getVoidConfigFromPartial } from '../webviews/common/contextForConfig'; import { CtrlKWebviewProvider } from './providers/CtrlKWebviewProvider'; import { SidebarWebviewProvider } from './providers/SidebarWebviewProvider'; import { v4 as uuidv4 } from 'uuid' @@ -147,7 +147,7 @@ export function activate(context: vscode.ExtensionContext) { const docUri = editor.document.uri const fileStr = await readFileContentOfUri(docUri) - const voidConfig = getVoidConfig(context.globalState.get('partialVoidConfig') ?? {}) + const voidConfig = getVoidConfigFromPartial(context.globalState.get('partialVoidConfig') ?? {}) await applyDiffLazily({ docUri, oldFileStr: fileStr, diffRepr: m.diffRepr, voidConfig, diffProvider, diffArea, abortRef: abortApplyRef }) } diff --git a/extensions/void/src/webviews/common/contextForConfig.tsx b/extensions/void/src/webviews/common/contextForConfig.tsx index e5b5d6b9..06c33781 100644 --- a/extensions/void/src/webviews/common/contextForConfig.tsx +++ b/extensions/void/src/webviews/common/contextForConfig.tsx @@ -46,15 +46,8 @@ const voidConfigInfo: Record< configFields, ), - maxTokens: configEnum( - "Max number of tokens to output.", - '1024', - [ - "1024", - "2048", - "4096", - "8192" - ] as const, + maxTokens: configString( + "Max number of tokens to output. Must be a number.", '' ), }, @@ -185,18 +178,18 @@ export type VoidConfig = { -export const getVoidConfig = (currentConfig: PartialVoidConfig): VoidConfig => { +export const getVoidConfigFromPartial = (partialVoidConfig: PartialVoidConfig): VoidConfig => { const config = {} as PartialVoidConfig for (let field of [...configFields, 'default'] as const) { config[field] = {} for (let prop in voidConfigInfo[field]) { - config[field][prop] = currentConfig[field]?.[prop] || voidConfigInfo[field][prop].defaultVal + config[field][prop] = partialVoidConfig[field]?.[prop]?.trim() || voidConfigInfo[field][prop].defaultVal } } return config as VoidConfig } -const defaultVoidConfig: VoidConfig = getVoidConfig({}) +const defaultVoidConfig: VoidConfig = getVoidConfigFromPartial({}) // const [stateRef, setState] = useInstantState(initVal) // setState instantly changes the value of stateRef instead of having to wait until the next render @@ -234,7 +227,7 @@ export function ConfigProvider({ children }: { children: ReactNode }) { getVSCodeAPI().postMessage({ type: 'getPartialVoidConfig' }) awaitVSCodeResponse('partialVoidConfig').then((m) => { setPartialVoidConfig(m.partialVoidConfig) - const newFullConfig = getVoidConfig(m.partialVoidConfig) + const newFullConfig = getVoidConfigFromPartial(m.partialVoidConfig) setVoidConfig(newFullConfig) }) }, [setPartialVoidConfig]) @@ -254,7 +247,7 @@ export function ConfigProvider({ children }: { children: ReactNode }) { } } setPartialVoidConfig(newPartialConfig) - const newFullConfig = getVoidConfig(newPartialConfig) + const newFullConfig = getVoidConfigFromPartial(newPartialConfig) setVoidConfig(newFullConfig) getVSCodeAPI().postMessage({ type: 'persistPartialVoidConfig', partialVoidConfig: newPartialConfig }) }