mirror of
https://github.com/voideditor/void
synced 2026-05-24 01:48:25 +00:00
model settings overrides part ii
This commit is contained in:
parent
398a8a1934
commit
7846b117bd
6 changed files with 312 additions and 470 deletions
|
|
@ -159,23 +159,26 @@ const ReasoningOptionSlider = ({ featureName }: { featureName: FeatureName }) =>
|
|||
|
||||
const { modelName, providerName } = modelSelection
|
||||
const { reasoningCapabilities } = getModelCapabilities(providerName, modelName, overridesOfModel)
|
||||
const { canTurnOffReasoning, reasoningBudgetSlider } = reasoningCapabilities || {}
|
||||
const { canTurnOffReasoning, reasoningSlider: reasoningBudgetSlider } = reasoningCapabilities || {}
|
||||
|
||||
const modelSelectionOptions = voidSettingsState.optionsOfModelSelection[featureName][providerName]?.[modelName]
|
||||
const isReasoningEnabled = getIsReasoningEnabledState(featureName, providerName, modelName, modelSelectionOptions, overridesOfModel)
|
||||
if (canTurnOffReasoning && !reasoningBudgetSlider) { // if it's just a on/off toggle without a power slider (no models right now)
|
||||
return null // unused right now
|
||||
// return <div className='flex items-center gap-x-2'>
|
||||
// <span className='text-void-fg-3 text-xs pointer-events-none inline-block w-10'>{isReasoningEnabled ? 'Thinking' : 'Thinking'}</span>
|
||||
// <VoidSwitch
|
||||
// size='xs'
|
||||
// value={isReasoningEnabled}
|
||||
// onChange={(newVal) => { } }
|
||||
// />
|
||||
// </div>
|
||||
|
||||
if (canTurnOffReasoning && !reasoningBudgetSlider) { // if it's just a on/off toggle without a power slider
|
||||
return <div className='flex items-center gap-x-2'>
|
||||
<span className='text-void-fg-3 text-xs pointer-events-none inline-block w-10 pr-1'>Thinking</span>
|
||||
<VoidSwitch
|
||||
size='xs'
|
||||
value={isReasoningEnabled}
|
||||
onChange={(newVal) => {
|
||||
const isOff = canTurnOffReasoning && !newVal
|
||||
voidSettingsService.setOptionsOfModelSelection(featureName, modelSelection.providerName, modelSelection.modelName, { reasoningEnabled: !isOff })
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
|
||||
if (reasoningBudgetSlider?.type === 'slider') { // if it's a slider
|
||||
if (reasoningBudgetSlider?.type === 'budget_slider') { // if it's a slider
|
||||
const { min: min_, max, default: defaultVal } = reasoningBudgetSlider
|
||||
|
||||
const nSteps = 8 // only used in calculating stepSize, stepSize is what actually matters
|
||||
|
|
@ -186,7 +189,6 @@ const ReasoningOptionSlider = ({ featureName }: { featureName: FeatureName }) =>
|
|||
const value = isReasoningEnabled ? voidSettingsState.optionsOfModelSelection[featureName][modelSelection.providerName]?.[modelSelection.modelName]?.reasoningBudget ?? defaultVal
|
||||
: valueIfOff
|
||||
|
||||
|
||||
return <div className='flex items-center gap-x-2'>
|
||||
<span className='text-void-fg-3 text-xs pointer-events-none inline-block w-10 pr-1'>Thinking</span>
|
||||
<VoidSlider
|
||||
|
|
@ -197,14 +199,45 @@ const ReasoningOptionSlider = ({ featureName }: { featureName: FeatureName }) =>
|
|||
step={stepSize}
|
||||
value={value}
|
||||
onChange={(newVal) => {
|
||||
const disabled = newVal === min && canTurnOffReasoning
|
||||
voidSettingsService.setOptionsOfModelSelection(featureName, modelSelection.providerName, modelSelection.modelName, { reasoningEnabled: !disabled, reasoningBudget: newVal })
|
||||
const isOff = canTurnOffReasoning && newVal === min
|
||||
voidSettingsService.setOptionsOfModelSelection(featureName, modelSelection.providerName, modelSelection.modelName, { reasoningEnabled: !isOff, reasoningBudget: newVal })
|
||||
}}
|
||||
/>
|
||||
<span className='text-void-fg-3 text-xs pointer-events-none'>{isReasoningEnabled ? `${value} tokens` : 'Thinking disabled'}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
if (reasoningBudgetSlider?.type === 'effort_slider') {
|
||||
|
||||
const { values, default: defaultVal } = reasoningBudgetSlider
|
||||
|
||||
const min = canTurnOffReasoning ? -1 : 0
|
||||
const max = values.length - 1
|
||||
|
||||
const valueIfOff = -1
|
||||
|
||||
const value = isReasoningEnabled ?
|
||||
values.indexOf(voidSettingsState.optionsOfModelSelection[featureName][modelSelection.providerName]?.[modelSelection.modelName]?.reasoningEffort ?? defaultVal)
|
||||
: valueIfOff
|
||||
|
||||
return <div className='flex items-center gap-x-2'>
|
||||
<span className='text-void-fg-3 text-xs pointer-events-none inline-block w-10 pr-1'>Thinking</span>
|
||||
<VoidSlider
|
||||
width={50}
|
||||
size='xs'
|
||||
min={min}
|
||||
max={max}
|
||||
step={1}
|
||||
value={value}
|
||||
onChange={(newVal) => {
|
||||
const isOff = canTurnOffReasoning && newVal === min
|
||||
voidSettingsService.setOptionsOfModelSelection(featureName, modelSelection.providerName, modelSelection.modelName, { reasoningEnabled: !isOff, reasoningBudget: newVal })
|
||||
}}
|
||||
/>
|
||||
<span className='text-void-fg-3 text-xs pointer-events-none'>{isReasoningEnabled ? `${value}` : 'Thinking disabled'}</span>
|
||||
</div>
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -355,7 +355,7 @@ const TableOfModelsForProvider = ({ providerName }: { providerName: ProviderName
|
|||
const { showAsDefault, isDownloaded } = infoOfModelName[modelName] ?? {}
|
||||
|
||||
|
||||
const capabilities = getModelCapabilities(providerName, modelName)
|
||||
const capabilities = getModelCapabilities(providerName, modelName, undefined)
|
||||
const {
|
||||
downloadable,
|
||||
cost,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
|
||||
*--------------------------------------------------------------------------------------*/
|
||||
|
||||
import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState, useRef } from 'react'; // Added useRef import just in case it was missed, though likely already present
|
||||
import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, VoidStatefulModelInfo, customSettingNamesOfProvider, RefreshableProviderName, refreshableProviderNames, displayInfoOfProviderName, nonlocalProviderNames, localProviderNames, GlobalSettingName, featureNames, displayInfoOfFeatureName, isProviderNameDisabled, FeatureName, hasDownloadButtonsOnModelsProviderNames, subTextMdOfProviderName } from '../../../../common/voidSettingsTypes.js'
|
||||
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
|
||||
import { VoidButtonBgDarken, VoidCustomDropdownBox, VoidInputBox2, VoidSimpleInputBox, VoidSwitch } from '../util/inputs.js'
|
||||
|
|
@ -18,6 +18,7 @@ import { os } from '../../../../common/helpers/systemInfo.js'
|
|||
import { IconLoading } from '../sidebar-tsx/SidebarChat.js'
|
||||
import { ToolApprovalType, toolApprovalTypes } from '../../../../common/toolsServiceTypes.js'
|
||||
import Severity from '../../../../../../../base/common/severity.js'
|
||||
import { getModelCapabilities, ModelOverrides } from '../../../../common/modelCapabilities.js';
|
||||
|
||||
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {
|
||||
|
||||
|
|
@ -183,6 +184,197 @@ const ConfirmButton = ({ children, onConfirm, className }: { children: React.Rea
|
|||
);
|
||||
};
|
||||
|
||||
// ---------------- Simplified Model Settings Dialog ------------------
|
||||
// This new dialog replaces the verbose UI with a single JSON override box.
|
||||
const SimpleModelSettingsDialog = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
modelInfo,
|
||||
}: {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
modelInfo: { modelName: string; providerName: ProviderName; type: 'autodetected' | 'custom' | 'default' } | null;
|
||||
}) => {
|
||||
if (!isOpen || !modelInfo) return null;
|
||||
|
||||
const { modelName, providerName, type } = modelInfo;
|
||||
const accessor = useAccessor();
|
||||
const settingsState = useSettingsState();
|
||||
const mouseDownInsideModal = useRef(false); // Ref to track mousedown origin
|
||||
const settingsStateService = accessor.get('IVoidSettingsService');
|
||||
|
||||
// current overrides and defaults
|
||||
const defaultModelCapabilities = getModelCapabilities(providerName, modelName, undefined);
|
||||
const currentOverrides = settingsState.overridesOfModel?.[providerName]?.[modelName] ?? undefined;
|
||||
const { modelName: recognizedModelName, isUnrecognizedModel } = defaultModelCapabilities
|
||||
|
||||
// keys of ModelOverrides we allow the user to override
|
||||
const allowedKeys: (string & (keyof ModelOverrides))[] = [
|
||||
'contextWindow',
|
||||
'reservedOutputTokenSpace',
|
||||
'supportsSystemMessage',
|
||||
'specialToolFormat',
|
||||
'supportsFIM',
|
||||
'reasoningCapabilities',
|
||||
];
|
||||
|
||||
// Create the placeholder with the default values for allowed keys
|
||||
const partialDefaults: Partial<ModelOverrides> = {};
|
||||
for (const k of allowedKeys) { if (defaultModelCapabilities[k]) partialDefaults[k] = defaultModelCapabilities[k] as any; }
|
||||
const placeholder = JSON.stringify(partialDefaults, null, 2);
|
||||
|
||||
const [overrideEnabled, setOverrideEnabled] = useState<boolean>(() => !!currentOverrides);
|
||||
const [jsonText, setJsonText] = useState<string>(() => currentOverrides ? JSON.stringify(currentOverrides, null, 2) : placeholder);
|
||||
|
||||
const [readOnlyHeight, setReadOnlyHeight] = useState<number | undefined>(undefined);
|
||||
const [errorMsg, setErrorMsg] = useState<string | null>(null);
|
||||
|
||||
// reset when dialog toggles
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
const cur = settingsState.overridesOfModel?.[providerName]?.[modelName];
|
||||
setOverrideEnabled(!!cur);
|
||||
// If there are overrides, show them; otherwise use default values
|
||||
setJsonText(cur ? JSON.stringify(cur, null, 2) : placeholder);
|
||||
setErrorMsg(null);
|
||||
}, [isOpen, providerName, modelName, settingsState.overridesOfModel, placeholder]);
|
||||
|
||||
const onSave = async () => {
|
||||
|
||||
// if disabled override, reset overrides
|
||||
if (!overrideEnabled) {
|
||||
await settingsStateService.setOverridesOfModel(providerName, modelName, undefined);
|
||||
onClose();
|
||||
return;
|
||||
}
|
||||
|
||||
// enabled overrides
|
||||
// parse json
|
||||
let parsedInput: Record<string, unknown>
|
||||
if (jsonText.trim()) {
|
||||
try {
|
||||
parsedInput = JSON.parse(jsonText);
|
||||
} catch (e) {
|
||||
setErrorMsg('Invalid JSON');
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
setErrorMsg('Invalid JSON');
|
||||
return;
|
||||
}
|
||||
|
||||
// only keep allowed keys
|
||||
const cleaned: Partial<ModelOverrides> = {};
|
||||
for (const k of allowedKeys) {
|
||||
if (!(k in parsedInput)) continue
|
||||
const isEmpty = parsedInput[k] === '' || parsedInput[k] === null || parsedInput[k] === undefined;
|
||||
if (!isEmpty && (k in partialDefaults)) {
|
||||
cleaned[k] = parsedInput[k] as any;
|
||||
}
|
||||
}
|
||||
await settingsStateService.setOverridesOfModel(providerName, modelName, cleaned);
|
||||
onClose();
|
||||
};
|
||||
|
||||
return (
|
||||
<div // Backdrop
|
||||
className="fixed inset-0 bg-black/50 flex items-center justify-center z-[9999999]"
|
||||
onMouseDown={() => {
|
||||
mouseDownInsideModal.current = false;
|
||||
}}
|
||||
onMouseUp={() => {
|
||||
if (!mouseDownInsideModal.current) {
|
||||
onClose();
|
||||
}
|
||||
mouseDownInsideModal.current = false;
|
||||
}}
|
||||
>
|
||||
{/* MODAL */}
|
||||
<div
|
||||
className="bg-void-bg-1 rounded-md p-4 max-w-xl w-full shadow-xl overflow-y-auto max-h-[90vh]"
|
||||
onClick={(e) => e.stopPropagation()} // Keep stopping propagation for normal clicks inside
|
||||
onMouseDown={(e) => {
|
||||
mouseDownInsideModal.current = true;
|
||||
e.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-medium">
|
||||
Change Defaults for {modelName} ({displayInfoOfProviderName(providerName).title})
|
||||
</h3>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="text-void-fg-3 hover:text-void-fg-1"
|
||||
>
|
||||
<X className="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Display model recognition status */}
|
||||
<div className="text-sm text-void-fg-3 mb-4">
|
||||
{type === 'default' ? `${modelName} comes packaged with Void, so you shouldn't need to change these settings.`
|
||||
: isUnrecognizedModel
|
||||
? `Model not recognized by Void.`
|
||||
: `Void knows about this model ("${recognizedModelName}")!`}
|
||||
</div>
|
||||
|
||||
|
||||
{/* override toggle */}
|
||||
<div className="flex items-center gap-2 mb-4">
|
||||
<VoidSwitch size="xs" value={overrideEnabled} onChange={setOverrideEnabled} />
|
||||
<span className="text-void-fg-2">Override Model Defaults</span>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{overrideEnabled ? (
|
||||
<VoidInputBox2
|
||||
multiline
|
||||
className="w-full min-h-[200px] p-2 rounded-sm border border-void-border-2"
|
||||
initValue={jsonText}
|
||||
placeholder={placeholder}
|
||||
onChangeText={setJsonText}
|
||||
/>
|
||||
) : (
|
||||
<textarea
|
||||
readOnly
|
||||
className="w-full min-h-[200px] p-2 rounded-sm border border-void-border-2 bg-void-bg-2 text-void-fg-3 resize-none font-mono text-sm"
|
||||
value={placeholder}
|
||||
style={readOnlyHeight ? { height: readOnlyHeight } : undefined}
|
||||
onLoad={(e) => {
|
||||
// autosize height once
|
||||
if (!readOnlyHeight) {
|
||||
const h = (e.target as HTMLTextAreaElement).scrollHeight;
|
||||
setReadOnlyHeight(h);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{errorMsg && (
|
||||
<div className="text-red-500 mt-2 text-sm">{errorMsg}</div>
|
||||
)}
|
||||
|
||||
{/* Informational link */}
|
||||
<div className="text-sm text-void-fg-3 mt-4">
|
||||
<ChatMarkdownRender string={"For more information on what you can customize, see [here](https://github.com/voideditor/void/blob/cf0728f4c605bff49c34c923e15ae649f053d3e7/src/vs/workbench/contrib/void/common/modelCapabilities.ts#L142C1-L171C4)"} chatMessageLocation={undefined} />
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 mt-4">
|
||||
<VoidButtonBgDarken onClick={onClose} className="px-3 py-1">
|
||||
Cancel
|
||||
</VoidButtonBgDarken>
|
||||
<VoidButtonBgDarken
|
||||
onClick={onSave}
|
||||
className="px-3 py-1 bg-[#0e70c0] text-white"
|
||||
>
|
||||
Save
|
||||
</VoidButtonBgDarken>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// shows a providerName dropdown if no `providerName` is given
|
||||
export const AddModelInputBox = ({ providerName: permanentProviderName, className, compact }: { providerName?: ProviderName, className?: string, compact?: boolean }) => {
|
||||
|
|
@ -302,421 +494,7 @@ export const AddModelInputBox = ({ providerName: permanentProviderName, classNam
|
|||
}
|
||||
|
||||
|
||||
// Import the getModelCapabilities function to access default values
|
||||
import { getModelCapabilities, ModelOverrideOptions } from '../../../../common/modelCapabilities.js';
|
||||
|
||||
// Modal dialog to show model settings
|
||||
const ModelSettingsDialog = ({
|
||||
isOpen,
|
||||
onClose,
|
||||
modelInfo
|
||||
}: {
|
||||
isOpen: boolean,
|
||||
onClose: () => void,
|
||||
modelInfo: { modelName: string, providerName: ProviderName, type: string } | null
|
||||
}) => {
|
||||
if (!isOpen || !modelInfo) return null;
|
||||
|
||||
const { modelName, providerName } = modelInfo;
|
||||
const accessor = useAccessor();
|
||||
const settingsStateService = accessor.get('IVoidSettingsService');
|
||||
const settingsState = useSettingsState();
|
||||
|
||||
// Get current model capabilities and override settings
|
||||
const modelCapabilities = getModelCapabilities(providerName, modelName, settingsState.overridesOfModel);
|
||||
const defaultModelCapabilities = getModelCapabilities(providerName, modelName, undefined)
|
||||
|
||||
// Initialize form state for all potential override options
|
||||
const [formValues, setFormValues] = useState<{
|
||||
contextWindow: string;
|
||||
reservedOutputTokenSpace: string;
|
||||
specialToolFormat: 'openai-style' | 'gemini-style' | 'anthropic-style' | undefined | '';
|
||||
supportsSystemMessage: 'system-role' | 'developer-role' | 'separated' | false | '';
|
||||
supportsFIM: boolean | null;
|
||||
reasoningCapabilities: boolean | null;
|
||||
canTurnOffReasoning: boolean;
|
||||
reasoningReservedOutputTokenSpace: string;
|
||||
openSourceThinkTags: [string, string] | null;
|
||||
}>({
|
||||
// start form as default values
|
||||
contextWindow: '',
|
||||
reservedOutputTokenSpace: '',
|
||||
specialToolFormat: '',
|
||||
supportsSystemMessage: '',
|
||||
supportsFIM: null,
|
||||
reasoningCapabilities: null,
|
||||
canTurnOffReasoning: false,
|
||||
reasoningReservedOutputTokenSpace: '',
|
||||
openSourceThinkTags: null,
|
||||
});
|
||||
|
||||
// When dialog opens or model changes, reset form values
|
||||
useEffect(() => {
|
||||
if (isOpen && modelInfo) {
|
||||
// Get current overrides
|
||||
const overrides = settingsState.overridesOfModel?.[providerName]?.[modelName] || {};
|
||||
|
||||
// Extract reasoning capabilities if available (use any to avoid TS union narrowing issues)
|
||||
const reasoningCapabilities: any = typeof overrides.reasoningCapabilities === 'object' ?
|
||||
overrides.reasoningCapabilities : overrides.reasoningCapabilities ? { supportsReasoning: true, canIOReasoning: true } : false;
|
||||
|
||||
// Extract the think tags if they exist
|
||||
let thinkTags: [string, string] | null = null;
|
||||
if (typeof reasoningCapabilities === 'object' && reasoningCapabilities.openSourceThinkTags) {
|
||||
thinkTags = reasoningCapabilities.openSourceThinkTags as [string, string];
|
||||
}
|
||||
|
||||
// Only set values that are explicitly overridden, otherwise leave them empty
|
||||
// to indicate default values should be used
|
||||
setFormValues({
|
||||
contextWindow: overrides.contextWindow !== undefined ? String(overrides.contextWindow) : '',
|
||||
reservedOutputTokenSpace: overrides.reservedOutputTokenSpace !== undefined ? String(overrides.reservedOutputTokenSpace) : '',
|
||||
specialToolFormat: overrides.specialToolFormat !== undefined ? overrides.specialToolFormat : '',
|
||||
supportsSystemMessage: overrides.supportsSystemMessage !== undefined ? overrides.supportsSystemMessage : '',
|
||||
supportsFIM: overrides.supportsFIM !== undefined ? overrides.supportsFIM : null,
|
||||
reasoningCapabilities: overrides.reasoningCapabilities !== undefined ?
|
||||
!!overrides.reasoningCapabilities : null,
|
||||
canTurnOffReasoning: typeof reasoningCapabilities === 'object' ? !!reasoningCapabilities.canTurnOffReasoning : false,
|
||||
reasoningReservedOutputTokenSpace: typeof reasoningCapabilities === 'object' && reasoningCapabilities.reasoningReservedOutputTokenSpace ?
|
||||
String(reasoningCapabilities.reasoningReservedOutputTokenSpace) : '',
|
||||
openSourceThinkTags: thinkTags,
|
||||
});
|
||||
}
|
||||
}, [isOpen, modelInfo, settingsState.overridesOfModel, providerName, modelName]);
|
||||
|
||||
// Update a single field in the form
|
||||
const updateField = (field: keyof typeof formValues, value: any) => {
|
||||
setFormValues(prev => ({
|
||||
...prev,
|
||||
[field]: value
|
||||
}));
|
||||
};
|
||||
|
||||
// Handle saving settings
|
||||
const handleSave = async () => {
|
||||
// Get current overrides to see what needs to be updated/removed
|
||||
const currentOverrides = settingsState.overridesOfModel?.[providerName]?.[modelName] || {};
|
||||
const newSettings: ModelOverrideOptions = {};
|
||||
|
||||
// Handle numeric fields - empty strings should remove the override
|
||||
if (formValues.contextWindow.trim() === '') {
|
||||
newSettings.contextWindow = defaultModelCapabilities.contextWindow;
|
||||
} else if (formValues.contextWindow) {
|
||||
const tokens = parseInt(formValues.contextWindow);
|
||||
if (!isNaN(tokens)) newSettings.contextWindow = tokens;
|
||||
}
|
||||
|
||||
if (formValues.reservedOutputTokenSpace.trim() === '') {
|
||||
newSettings.reservedOutputTokenSpace = defaultModelCapabilities.reservedOutputTokenSpace;
|
||||
} else if (formValues.reservedOutputTokenSpace) {
|
||||
const tokens = parseInt(formValues.reservedOutputTokenSpace);
|
||||
if (!isNaN(tokens)) newSettings.reservedOutputTokenSpace = tokens;
|
||||
}
|
||||
|
||||
// Handle dropdown fields
|
||||
if (formValues.specialToolFormat === '') {
|
||||
newSettings.specialToolFormat = defaultModelCapabilities.specialToolFormat
|
||||
} else {
|
||||
newSettings.specialToolFormat = formValues.specialToolFormat
|
||||
}
|
||||
|
||||
if (formValues.supportsSystemMessage === '') {
|
||||
newSettings.supportsSystemMessage = defaultModelCapabilities.supportsSystemMessage;
|
||||
} else {
|
||||
newSettings.supportsSystemMessage = formValues.supportsSystemMessage as any;
|
||||
}
|
||||
|
||||
if (formValues.supportsFIM === null) {
|
||||
newSettings.supportsFIM = defaultModelCapabilities.supportsFIM
|
||||
} else {
|
||||
newSettings.supportsFIM = formValues.supportsFIM;
|
||||
}
|
||||
|
||||
if (formValues.reasoningCapabilities === null) {
|
||||
newSettings.reasoningCapabilities = defaultModelCapabilities.reasoningCapabilities;
|
||||
} else if (formValues.reasoningCapabilities) {
|
||||
const reasoningSettings: any = {
|
||||
supportsReasoning: true,
|
||||
canIOReasoning: true,
|
||||
canTurnOffReasoning: formValues.canTurnOffReasoning
|
||||
};
|
||||
|
||||
// Only add these if they have values
|
||||
if (formValues.reasoningReservedOutputTokenSpace) {
|
||||
reasoningSettings.reasoningReservedOutputTokenSpace = parseInt(formValues.reasoningReservedOutputTokenSpace);
|
||||
}
|
||||
|
||||
if (formValues.openSourceThinkTags) {
|
||||
reasoningSettings.openSourceThinkTags = formValues.openSourceThinkTags;
|
||||
}
|
||||
|
||||
newSettings.reasoningCapabilities = reasoningSettings;
|
||||
} else {
|
||||
newSettings.reasoningCapabilities = false;
|
||||
}
|
||||
|
||||
await settingsStateService.setOverridesOfModel(providerName, modelName, newSettings);
|
||||
onClose();
|
||||
};
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50" onClick={onClose}>
|
||||
<div className="bg-void-bg-1 rounded-md p-4 max-w-md w-full shadow-xl overflow-y-auto max-h-[90vh]" onClick={e => e.stopPropagation()}>
|
||||
<div className="flex justify-between items-center mb-4">
|
||||
<h3 className="text-lg font-medium">Change Defaults for {modelName} ({displayInfoOfProviderName(providerName).title})</h3>
|
||||
<button onClick={onClose} className="text-void-fg-3 hover:text-void-fg-1">
|
||||
<X className="size-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="mb-4">
|
||||
{/* Model-specific settings */}
|
||||
<div className="border border-void-border-2 rounded-sm p-3">
|
||||
|
||||
{/* Context window */}
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<span className="text-void-fg-2">Context window (tokens)</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<VoidSwitch
|
||||
size="xxs"
|
||||
value={formValues.contextWindow !== ''}
|
||||
onChange={(enabled) => {
|
||||
updateField('contextWindow', enabled ? String(defaultModelCapabilities.contextWindow) : '');
|
||||
}}
|
||||
/>
|
||||
{formValues.contextWindow === '' ? (
|
||||
<span className="text-void-fg-3 text-xs w-24 text-right">Default ({defaultModelCapabilities.contextWindow})</span>
|
||||
) : (
|
||||
<VoidSimpleInputBox
|
||||
value={formValues.contextWindow}
|
||||
onChangeValue={(value) => updateField('contextWindow', value)}
|
||||
placeholder={String(defaultModelCapabilities.contextWindow)}
|
||||
compact={true}
|
||||
className="max-w-24"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Maximum output tokens */}
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<span className="text-void-fg-2">Maximum output tokens</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<VoidSwitch
|
||||
size="xxs"
|
||||
value={formValues.reservedOutputTokenSpace !== ''}
|
||||
onChange={(enabled) => {
|
||||
updateField('reservedOutputTokenSpace', enabled ? String(defaultModelCapabilities.reservedOutputTokenSpace) : '');
|
||||
}}
|
||||
/>
|
||||
{formValues.reservedOutputTokenSpace === '' ? (
|
||||
<span className="text-void-fg-3 text-xs w-24 text-right">Default ({defaultModelCapabilities.reservedOutputTokenSpace})</span>
|
||||
) : (
|
||||
<VoidSimpleInputBox
|
||||
value={formValues.reservedOutputTokenSpace}
|
||||
onChangeValue={(value) => updateField('reservedOutputTokenSpace', value)}
|
||||
placeholder={String(defaultModelCapabilities.reservedOutputTokenSpace)}
|
||||
compact={true}
|
||||
className="max-w-24"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Supports Tools */}
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<span className="text-void-fg-2">Supports tools</span>
|
||||
<VoidCustomDropdownBox
|
||||
options={['', 'openai-style']}
|
||||
selectedOption={formValues.specialToolFormat}
|
||||
onChangeOption={(value) => updateField('specialToolFormat', value)}
|
||||
getOptionDisplayName={(opt) => {
|
||||
if (opt === '') return `Default (${defaultModelCapabilities.specialToolFormat || 'No'})`;
|
||||
return opt;
|
||||
}}
|
||||
getOptionDropdownName={(opt) => {
|
||||
if (opt === '') return `Default`;
|
||||
return opt;
|
||||
}}
|
||||
getOptionsEqual={(a, b) => a === b}
|
||||
className="max-w-32 text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Supports System Message */}
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<span className="text-void-fg-2">Supports system message</span>
|
||||
<VoidCustomDropdownBox
|
||||
options={['', 'system-role', 'developer-role', false]}
|
||||
selectedOption={formValues.supportsSystemMessage}
|
||||
onChangeOption={(value) => updateField('supportsSystemMessage', value)}
|
||||
getOptionDisplayName={(opt) => {
|
||||
if (opt === '') return `Default (${defaultModelCapabilities.supportsSystemMessage || 'No'})`;
|
||||
if (opt === false) return 'No'
|
||||
if (opt === true) return 'Yes' // should never happen
|
||||
return opt;
|
||||
}}
|
||||
getOptionDropdownName={(opt) => {
|
||||
if (opt === '') return `Default`;
|
||||
if (opt === false) return 'No'
|
||||
if (opt === true) return 'Yes' // should never happen
|
||||
return opt;
|
||||
}}
|
||||
getOptionsEqual={(a, b) => a === b}
|
||||
className="max-w-32 text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Supports FIM */}
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<span className="text-void-fg-2">Supports fill-in-the-middle (autocomplete)</span>
|
||||
<VoidCustomDropdownBox
|
||||
options={[null, true, false]}
|
||||
selectedOption={formValues.supportsFIM}
|
||||
onChangeOption={(value) => updateField('supportsFIM', value)}
|
||||
getOptionDisplayName={(opt) => {
|
||||
if (opt === null) return `Default (${defaultModelCapabilities.supportsFIM ? 'Yes' : 'No'})`;
|
||||
return opt ? 'Yes' : 'No';
|
||||
}}
|
||||
getOptionDropdownName={(opt) => {
|
||||
if (opt === null) return 'Default';
|
||||
return opt ? 'Yes' : 'No';
|
||||
}}
|
||||
getOptionsEqual={(a, b) => a === b}
|
||||
className="max-w-32 text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Supports Reasoning */}
|
||||
<div className="flex items-center justify-between py-1">
|
||||
<span className="text-void-fg-2">Supports reasoning</span>
|
||||
<VoidCustomDropdownBox
|
||||
options={[null, true, false]}
|
||||
selectedOption={formValues.reasoningCapabilities}
|
||||
onChangeOption={(value) => updateField('reasoningCapabilities', value)}
|
||||
getOptionDisplayName={(opt) => {
|
||||
if (opt === null) return `Default (${defaultModelCapabilities.reasoningCapabilities ? 'Yes' : 'No'})`;
|
||||
return opt ? 'Yes' : 'No';
|
||||
}}
|
||||
getOptionDropdownName={(opt) => {
|
||||
if (opt === null) return 'Default';
|
||||
return opt ? 'Yes' : 'No';
|
||||
}}
|
||||
getOptionsEqual={(a, b) => a === b}
|
||||
className="max-w-32 text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Additional reasoning options - only show when reasoning is enabled */}
|
||||
{formValues.reasoningCapabilities && (
|
||||
<>
|
||||
{/* Can Turn Off Reasoning */}
|
||||
<div className="flex items-center justify-between py-1 pl-6">
|
||||
<span className="text-void-fg-2">Allow turning off reasoning</span>
|
||||
<VoidCustomDropdownBox
|
||||
options={[true, false]}
|
||||
selectedOption={formValues.canTurnOffReasoning}
|
||||
onChangeOption={(value) => updateField('canTurnOffReasoning', value)}
|
||||
getOptionDisplayName={(opt) => opt ? 'Yes' : 'No'}
|
||||
getOptionDropdownName={(opt) => opt ? 'Yes' : 'No'}
|
||||
getOptionsEqual={(a, b) => a === b}
|
||||
className="max-w-32 text-xs"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Reasoning Max Output Tokens - only shown if canTurnOffReasoning is true */}
|
||||
{formValues.canTurnOffReasoning && (
|
||||
<div className="flex items-center justify-between py-1 pl-6">
|
||||
<span className="text-void-fg-2">Max output tokens when reasoning</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<VoidSwitch
|
||||
size="xxs"
|
||||
value={formValues.reasoningReservedOutputTokenSpace !== ''}
|
||||
onChange={(enabled) => {
|
||||
// Use a reasonable default value when enabling
|
||||
const defaultValue = defaultModelCapabilities.reservedOutputTokenSpace || 500;
|
||||
updateField('reasoningReservedOutputTokenSpace', enabled ? String(defaultValue) : '');
|
||||
}}
|
||||
/>
|
||||
{formValues.reasoningReservedOutputTokenSpace === '' ? (
|
||||
<span className="text-void-fg-3 text-xs w-24 text-right">Default</span>
|
||||
) : (
|
||||
<VoidSimpleInputBox
|
||||
value={formValues.reasoningReservedOutputTokenSpace}
|
||||
onChangeValue={(value) => updateField('reasoningReservedOutputTokenSpace', value)}
|
||||
placeholder="Default"
|
||||
compact={true}
|
||||
className="max-w-24"
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Open Source Think Tags Toggle + Input Fields */}
|
||||
<div className="flex items-center justify-between py-1 pl-6">
|
||||
<span className="text-void-fg-2">Open source think tags</span>
|
||||
<div className="flex items-center gap-2">
|
||||
<VoidSwitch
|
||||
size="xxs"
|
||||
value={formValues.openSourceThinkTags !== null}
|
||||
onChange={(enabled) => {
|
||||
if (enabled) {
|
||||
// Enable with default values
|
||||
updateField('openSourceThinkTags', ['<think>', '</think>']);
|
||||
} else {
|
||||
// Disable
|
||||
updateField('openSourceThinkTags', null);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
|
||||
{formValues.openSourceThinkTags !== null && (
|
||||
<div className="flex gap-1 items-center">
|
||||
<VoidSimpleInputBox
|
||||
value={formValues.openSourceThinkTags ? formValues.openSourceThinkTags[0] : ''}
|
||||
onChangeValue={(value) => {
|
||||
const currentTags = formValues.openSourceThinkTags || ['', ''];
|
||||
updateField('openSourceThinkTags', [value, currentTags[1]]);
|
||||
}}
|
||||
placeholder="<think>"
|
||||
compact={true}
|
||||
className="max-w-16"
|
||||
/>
|
||||
<span className="text-void-fg-3">...</span>
|
||||
<VoidSimpleInputBox
|
||||
value={formValues.openSourceThinkTags ? formValues.openSourceThinkTags[1] : ''}
|
||||
onChangeValue={(value) => {
|
||||
const currentTags = formValues.openSourceThinkTags || ['', ''];
|
||||
updateField('openSourceThinkTags', [currentTags[0], value]);
|
||||
}}
|
||||
placeholder="</think>"
|
||||
compact={true}
|
||||
className="max-w-16"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2">
|
||||
<VoidButtonBgDarken onClick={onClose} className="px-3 py-1">
|
||||
Cancel
|
||||
</VoidButtonBgDarken>
|
||||
<VoidButtonBgDarken onClick={handleSave} className="px-3 py-1 bg-[#0e70c0] text-white">
|
||||
Save
|
||||
</VoidButtonBgDarken>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const ModelDump = () => {
|
||||
const accessor = useAccessor()
|
||||
|
|
@ -727,7 +505,7 @@ export const ModelDump = () => {
|
|||
const [openSettingsModel, setOpenSettingsModel] = useState<{
|
||||
modelName: string,
|
||||
providerName: ProviderName,
|
||||
type: string
|
||||
type: 'autodetected' | 'custom' | 'default'
|
||||
} | null>(null);
|
||||
|
||||
// a dump of all the enabled providers' models
|
||||
|
|
@ -820,7 +598,7 @@ export const ModelDump = () => {
|
|||
})}
|
||||
|
||||
{/* Model Settings Dialog */}
|
||||
<ModelSettingsDialog
|
||||
<SimpleModelSettingsDialog
|
||||
isOpen={openSettingsModel !== null}
|
||||
onClose={() => setOpenSettingsModel(null)}
|
||||
modelInfo={openSettingsModel}
|
||||
|
|
|
|||
|
|
@ -44,7 +44,6 @@ const validateStr = (argName: string, value: unknown) => {
|
|||
|
||||
|
||||
// We are NOT checking to make sure in workspace
|
||||
// TODO!!!! check to make sure folder/file exists
|
||||
const validateURI = (uriStr: unknown) => {
|
||||
if (uriStr === null) throw new Error(`Invalid LLM output: uri was null.`)
|
||||
if (typeof uriStr !== 'string') throw new Error(`Invalid LLM output format: Provided uri must be a string, but it's a(n) ${typeof uriStr}. Full value: ${JSON.stringify(uriStr)}.`)
|
||||
|
|
|
|||
|
|
@ -140,40 +140,42 @@ export const defaultModelsOfProvider = {
|
|||
|
||||
|
||||
export type VoidStaticModelInfo = { // not stateful
|
||||
cost: { // just informative, not used in sending / receiving
|
||||
// for examples, see openAIModelOptions and anthropicModelOptions below.
|
||||
|
||||
contextWindow: number; // input tokens
|
||||
reservedOutputTokenSpace: number | null; // reserve this much space in the context window for output, defaults to 4096 if null
|
||||
|
||||
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated'; // typically you should use 'system-role'. 'separated' means the system message is passed as a separate field (e.g. anthropic)
|
||||
specialToolFormat?: 'openai-style' | 'anthropic-style' | 'gemini-style', // typically you should use 'openai-style'. null means "can't call tools by default", and asks the LLM to output XML in agent mode
|
||||
supportsFIM: boolean;
|
||||
|
||||
// reasoning options
|
||||
reasoningCapabilities: false | {
|
||||
readonly supportsReasoning: true; // for clarity, this must be true if anything below is specified
|
||||
readonly canTurnOffReasoning: boolean; // whether or not the user can disable reasoning mode (false if the model only supports reasoning)
|
||||
readonly canIOReasoning: boolean; // whether or not the model actually outputs reasoning (eg o1 lets us control reasoning but not output it)
|
||||
readonly reasoningReservedOutputTokenSpace?: number; // overrides normal reservedOutputTokenSpace
|
||||
readonly reasoningSlider?:
|
||||
| undefined
|
||||
| { type: 'budget_slider'; min: number; max: number; default: number } // anthropic supports this (reasoning budget)
|
||||
| { type: 'effort_slider'; values: string[]; default: string } // openai-compatible supports this (reasoning effort)
|
||||
|
||||
// if it's open source and specifically outputs think tags, put the think tags here and we'll parse them out (e.g. ollama)
|
||||
readonly openSourceThinkTags?: [string, string];
|
||||
};
|
||||
|
||||
// --- below is just informative, not used in sending / receiving, cannot be customized in settings ---
|
||||
cost: {
|
||||
input: number;
|
||||
output: number;
|
||||
cache_read?: number;
|
||||
cache_write?: number;
|
||||
}
|
||||
|
||||
downloadable: false | { // just informative, not used in sending / receiving
|
||||
downloadable: false | {
|
||||
sizeGb: number | 'not-known'
|
||||
}
|
||||
|
||||
contextWindow: number; // input tokens
|
||||
reservedOutputTokenSpace: number | null; // reserve this much space in the context window for output, defaults to 4092 if null
|
||||
|
||||
supportsSystemMessage: false | 'system-role' | 'developer-role' | 'separated'; // separated = anthropic where "system" is a special paramete
|
||||
specialToolFormat?: 'openai-style' | 'anthropic-style' | 'gemini-style', // null defaults to XML
|
||||
supportsFIM: boolean;
|
||||
|
||||
// reasoning options if supports reasoning
|
||||
reasoningCapabilities: false | {
|
||||
readonly supportsReasoning: true; // this must be true for clarity
|
||||
readonly canTurnOffReasoning: boolean; // whether or not the user can disable reasoning mode (false if the model only supports reasoning)
|
||||
readonly canIOReasoning: boolean; // whether or not the model actually outputs reasoning (eg o1 lets us control reasoning but not output it)
|
||||
readonly reasoningReservedOutputTokenSpace?: number; // overrides normal reservedOutputTokenSpace
|
||||
readonly reasoningBudgetSlider?:
|
||||
| undefined
|
||||
| { type: 'number_slider'; min: number; max: number; default: number } // anthropic only supports this
|
||||
| { type: 'string_slider'; values: string[]; default: string } // openai-compatible only supports this
|
||||
|
||||
// options related specifically to model output
|
||||
// if it's open source, put the think tags here and we'll parse them out in e.g. ollama
|
||||
readonly openSourceThinkTags?: [string, string];
|
||||
};
|
||||
}
|
||||
// if you change the above type, remember to update the Settings link
|
||||
|
||||
|
||||
export type ModelOverrides = Pick<VoidStaticModelInfo,
|
||||
|
|
@ -434,7 +436,7 @@ const anthropicModelOptions = {
|
|||
canTurnOffReasoning: true,
|
||||
canIOReasoning: true,
|
||||
reasoningReservedOutputTokenSpace: 64_000, // can bump it to 128_000 with beta mode output-128k-2025-02-19
|
||||
reasoningBudgetSlider: { type: 'number_slider', min: 1024, max: 32_000, default: 1024 }, // they recommend batching if max > 32_000
|
||||
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // they recommend batching if max > 32_000. we cap at 8192 because above is typically not necessary (often even buggy)
|
||||
},
|
||||
|
||||
},
|
||||
|
|
@ -483,7 +485,7 @@ const anthropicSettings: VoidStaticProviderInfo = {
|
|||
providerReasoningIOSettings: {
|
||||
input: {
|
||||
includeInPayload: (reasoningInfo) => {
|
||||
if (reasoningInfo?.type === 'budgetEnabled') {
|
||||
if (reasoningInfo?.type === 'budget_slider_value') {
|
||||
return { thinking: { type: 'enabled', budget_tokens: reasoningInfo.reasoningBudget } }
|
||||
}
|
||||
return null
|
||||
|
|
@ -617,7 +619,18 @@ const openAISettings: VoidStaticProviderInfo = {
|
|||
if (lower.includes('gpt-4o')) { fallbackName = 'gpt-4o' }
|
||||
if (fallbackName) return { modelName: fallbackName, ...openAIModelOptions[fallbackName] }
|
||||
return null
|
||||
}
|
||||
},
|
||||
providerReasoningIOSettings: {
|
||||
input: {
|
||||
// https://platform.openai.com/docs/guides/reasoning?api-mode=chat
|
||||
includeInPayload: (reasoningInfo) => {
|
||||
if (reasoningInfo?.type === 'effort_slider_value') {
|
||||
return { reasoning_effort: reasoningInfo.reasoningEffort }
|
||||
}
|
||||
return null
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// ---------------- XAI ----------------
|
||||
|
|
@ -855,7 +868,7 @@ const groqSettings: VoidStaticProviderInfo = {
|
|||
providerReasoningIOSettings: {
|
||||
input: {
|
||||
includeInPayload: (reasoningInfo) => {
|
||||
if (reasoningInfo?.type === 'budgetEnabled') {
|
||||
if (reasoningInfo?.type === 'budget_slider_value') {
|
||||
return { reasoning_format: 'parsed' }
|
||||
}
|
||||
return null
|
||||
|
|
@ -1046,7 +1059,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
|
|||
canTurnOffReasoning: false,
|
||||
canIOReasoning: true,
|
||||
reasoningReservedOutputTokenSpace: 64_000,
|
||||
reasoningBudgetSlider: { type: 'number_slider', min: 1024, max: 32_000, default: 1024 }, // they recommend batching if max > 32_000
|
||||
reasoningSlider: { type: 'budget_slider', min: 1024, max: 8192, default: 1024 }, // they recommend batching if max > 32_000.
|
||||
},
|
||||
},
|
||||
'anthropic/claude-3.7-sonnet': {
|
||||
|
|
@ -1095,14 +1108,21 @@ const openRouterSettings: VoidStaticProviderInfo = {
|
|||
// reasoning: OAICompat + response.choices[0].delta.reasoning : payload should have {include_reasoning: true} https://openrouter.ai/announcements/reasoning-tokens-for-thinking-models
|
||||
providerReasoningIOSettings: {
|
||||
input: {
|
||||
// https://openrouter.ai/docs/use-cases/reasoning-tokens
|
||||
includeInPayload: (reasoningInfo) => {
|
||||
if (reasoningInfo?.type === 'budgetEnabled') {
|
||||
if (reasoningInfo?.type === 'budget_slider_value') {
|
||||
return {
|
||||
reasoning: {
|
||||
max_tokens: reasoningInfo.reasoningBudget
|
||||
}
|
||||
}
|
||||
}
|
||||
if (reasoningInfo?.type === 'effort_slider_value')
|
||||
return {
|
||||
reasoning: {
|
||||
effort: reasoningInfo.reasoningEffort
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
},
|
||||
|
|
@ -1183,9 +1203,13 @@ export const getProviderCapabilities = (providerName: ProviderName) => {
|
|||
|
||||
|
||||
export type SendableReasoningInfo = {
|
||||
type: 'budgetEnabled',
|
||||
type: 'budget_slider_value',
|
||||
isReasoningEnabled: true,
|
||||
reasoningBudget: number,
|
||||
} | {
|
||||
type: 'effort_slider_value',
|
||||
isReasoningEnabled: true,
|
||||
reasoningEffort: string,
|
||||
} | null
|
||||
|
||||
|
||||
|
|
@ -1225,15 +1249,22 @@ export const getSendableReasoningInfo = (
|
|||
overridesOfModel: OverridesOfModel | undefined,
|
||||
): SendableReasoningInfo => {
|
||||
|
||||
const { canIOReasoning, reasoningBudgetSlider } = getModelCapabilities(providerName, modelName, overridesOfModel).reasoningCapabilities || {}
|
||||
const { canIOReasoning, reasoningSlider: reasoningBudgetSlider } = getModelCapabilities(providerName, modelName, overridesOfModel).reasoningCapabilities || {}
|
||||
if (!canIOReasoning) return null
|
||||
const isReasoningEnabled = getIsReasoningEnabledState(featureName, providerName, modelName, modelSelectionOptions, overridesOfModel)
|
||||
if (!isReasoningEnabled) return null
|
||||
|
||||
// check for reasoning budget
|
||||
const reasoningBudget = reasoningBudgetSlider?.type === 'number_slider' ? modelSelectionOptions?.reasoningBudget ?? reasoningBudgetSlider?.default : undefined
|
||||
const reasoningBudget = reasoningBudgetSlider?.type === 'budget_slider' ? modelSelectionOptions?.reasoningBudget ?? reasoningBudgetSlider?.default : undefined
|
||||
if (reasoningBudget) {
|
||||
return { type: 'budgetEnabled', isReasoningEnabled: isReasoningEnabled, reasoningBudget: reasoningBudget }
|
||||
return { type: 'budget_slider_value', isReasoningEnabled: isReasoningEnabled, reasoningBudget: reasoningBudget }
|
||||
}
|
||||
|
||||
// check for reasoning effort
|
||||
const reasoningEffort = reasoningBudgetSlider?.type === 'effort_slider' ? modelSelectionOptions?.reasoningEffort ?? reasoningBudgetSlider?.default : undefined
|
||||
if (reasoningEffort) {
|
||||
return { type: 'effort_slider_value', isReasoningEnabled: isReasoningEnabled, reasoningEffort: reasoningEffort }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
|
|
|||
|
|
@ -466,6 +466,7 @@ export const globalSettingNames = Object.keys(defaultGlobalSettings) as GlobalSe
|
|||
export type ModelSelectionOptions = {
|
||||
reasoningEnabled?: boolean;
|
||||
reasoningBudget?: number;
|
||||
reasoningEffort?: string;
|
||||
}
|
||||
|
||||
export type OptionsOfModelSelection = {
|
||||
|
|
|
|||
Loading…
Reference in a new issue