misc + model overrides

This commit is contained in:
Andrew Pareles 2025-05-05 00:50:33 -07:00
parent 732269de87
commit 398a8a1934
7 changed files with 77 additions and 67 deletions

View file

@ -3,4 +3,6 @@ This is a fork of the VSCode repo called Void.
Most code we care about lives in src/vs/workbench/contrib/void.
You may often need to explore the full repo to find relevant parts of code.
Look for services, and built-in functions that you might need to use to solve the problem.
Look for services, and built-in functions that you might need to use to solve the problem.
NEVER lazily cast to 'any' in typescript. Find the correct type to apply and use it.

View file

@ -728,6 +728,7 @@ const ToolHeaderWrapper = ({
<div className={`flex items-center w-full gap-x-2 overflow-hidden justify-between ${isRejected ? 'line-through' : ''}`}>
{/* left */}
<div className={`
ml-1
flex items-center min-w-0 overflow-hidden grow
${isClickable ? 'cursor-pointer hover:brightness-125 transition-all duration-150' : ''}
`}

View file

@ -143,7 +143,7 @@ registerAction2(class extends Action2 {
async run(accessor: ServicesAccessor): Promise<void> {
const commandService = accessor.get(ICommandService)
await commandService.executeCommand(VOID_OPEN_SIDEBAR_ACTION_ID)
await commandService.executeCommand(VOID_ADD_SELECTION_TO_SIDEBAR_ACTION_ID)
// await commandService.executeCommand(VOID_ADD_SELECTION_TO_SIDEBAR_ACTION_ID)
}
})

View file

@ -140,42 +140,46 @@ export const defaultModelsOfProvider = {
export type VoidStaticModelInfo = { // not stateful
contextWindow: number; // input tokens
reservedOutputTokenSpace: number | null; // output tokens, defaults to 4092
cost: { // <-- UNUSED
cost: { // just informative, not used in sending / receiving
input: number;
output: number;
cache_read?: number;
cache_write?: number;
}
downloadable: false | {
downloadable: false | { // just informative, not used in sending / receiving
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;
// reasoning options if supports reasoning
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?: { type: 'slider'; min: number; max: number; default: number };
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
// you are allowed to not include openSourceThinkTags if it's not open source (no such cases as of writing)
// if it's open source, put the think tags here so we parse them out in e.g. ollama
// if it's open source, put the think tags here and we'll parse them out in e.g. ollama
readonly openSourceThinkTags?: [string, string];
};
}
export type ModelOverrideOptions = Partial<Pick<VoidStaticModelInfo,
export type ModelOverrides = Pick<VoidStaticModelInfo,
'contextWindow' | 'reservedOutputTokenSpace' | 'specialToolFormat' | 'supportsSystemMessage' | 'supportsFIM' | 'reasoningCapabilities'
>>
>
@ -343,9 +347,12 @@ const extensiveModelFallback: VoidStaticProviderInfo['modelOptionsFallback'] = (
const lower = modelName.toLowerCase()
const toFallback = (opts: Omit<VoidStaticModelInfo, 'cost' | 'downloadable'>): VoidStaticModelInfo & { modelName: string } => {
const toFallback = <T extends { [s: string]: Omit<VoidStaticModelInfo, 'cost' | 'downloadable'> },>(obj: T, recognizedModelName: string & keyof T)
: VoidStaticModelInfo & { modelName: string } => {
const opts = obj[recognizedModelName]
return {
modelName,
modelName: recognizedModelName,
...opts,
supportsSystemMessage: opts.supportsSystemMessage ? 'system-role' : false,
cost: { input: 0, output: 0 },
@ -353,58 +360,58 @@ const extensiveModelFallback: VoidStaticProviderInfo['modelOptionsFallback'] = (
...fallbackKnownValues
}
}
if (lower.includes('gemini') && (lower.includes('2.5') || lower.includes('2-5'))) return toFallback(geminiModelOptions['gemini-2.5-pro-exp-03-25'])
if (lower.includes('gemini') && (lower.includes('2.5') || lower.includes('2-5'))) return toFallback(geminiModelOptions, 'gemini-2.5-pro-exp-03-25')
if (lower.includes('claude-3-5') || lower.includes('claude-3.5')) return toFallback(anthropicModelOptions['claude-3-5-sonnet-20241022'])
if (lower.includes('claude')) return toFallback(anthropicModelOptions['claude-3-7-sonnet-20250219'])
if (lower.includes('claude-3-5') || lower.includes('claude-3.5')) return toFallback(anthropicModelOptions, 'claude-3-5-sonnet-20241022')
if (lower.includes('claude')) return toFallback(anthropicModelOptions, 'claude-3-7-sonnet-20250219')
if (lower.includes('grok')) return toFallback(xAIModelOptions['grok-2'])
if (lower.includes('grok')) return toFallback(xAIModelOptions, 'grok-2')
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekR1 })
if (lower.includes('deepseek') && lower.includes('v2')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekCoderV2 })
if (lower.includes('deepseek')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.deepseekCoderV3 })
if (lower.includes('deepseek-r1') || lower.includes('deepseek-reasoner')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekR1')
if (lower.includes('deepseek') && lower.includes('v2')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekCoderV2')
if (lower.includes('deepseek')) return toFallback(openSourceModelOptions_assumingOAICompat, 'deepseekCoderV3')
if (lower.includes('llama3')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.llama3, })
if (lower.includes('llama3.1')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['llama3.1'], })
if (lower.includes('llama3.2')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['llama3.2'], })
if (lower.includes('llama3.3')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['llama3.3'], })
if (lower.includes('llama') || lower.includes('scout')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['llama4-scout'] })
if (lower.includes('llama') || lower.includes('maverick')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['llama4-scout'] })
if (lower.includes('llama')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['llama4-scout'] })
if (lower.includes('llama3')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama3')
if (lower.includes('llama3.1')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama3.1')
if (lower.includes('llama3.2')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama3.2')
if (lower.includes('llama3.3')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama3.3')
if (lower.includes('llama') || lower.includes('scout')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama4-scout')
if (lower.includes('llama') || lower.includes('maverick')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama4-scout')
if (lower.includes('llama')) return toFallback(openSourceModelOptions_assumingOAICompat, 'llama4-scout')
if (lower.includes('qwen') && lower.includes('2.5') && lower.includes('coder')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['qwen2.5coder'] })
if (lower.includes('qwen') && lower.includes('3')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['qwen3'] })
if (lower.includes('qwen')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['qwen3'] })
if (lower.includes('qwq')) { return toFallback({ ...openSourceModelOptions_assumingOAICompat.qwq, }) }
if (lower.includes('phi4')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.phi4, })
if (lower.includes('codestral')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.codestral })
if (lower.includes('qwen') && lower.includes('2.5') && lower.includes('coder')) return toFallback(openSourceModelOptions_assumingOAICompat, 'qwen2.5coder')
if (lower.includes('qwen') && lower.includes('3')) return toFallback(openSourceModelOptions_assumingOAICompat, 'qwen3')
if (lower.includes('qwen')) return toFallback(openSourceModelOptions_assumingOAICompat, 'qwen3')
if (lower.includes('qwq')) { return toFallback(openSourceModelOptions_assumingOAICompat, 'qwq') }
if (lower.includes('phi4')) return toFallback(openSourceModelOptions_assumingOAICompat, 'phi4')
if (lower.includes('codestral')) return toFallback(openSourceModelOptions_assumingOAICompat, 'codestral')
if (lower.includes('gemma')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.gemma, })
if (lower.includes('gemma')) return toFallback(openSourceModelOptions_assumingOAICompat, 'gemma')
if (lower.includes('starcoder2')) return toFallback({ ...openSourceModelOptions_assumingOAICompat.starcoder2, })
if (lower.includes('starcoder2')) return toFallback(openSourceModelOptions_assumingOAICompat, 'starcoder2')
if (lower.includes('openhands')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['openhands-lm-32b'], }) // max output unclear
if (lower.includes('openhands')) return toFallback(openSourceModelOptions_assumingOAICompat, 'openhands-lm-32b') // max output uncler
if (lower.includes('quasar') || lower.includes('quaser')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['quasar'] })
if (lower.includes('quasar') || lower.includes('quaser')) return toFallback(openSourceModelOptions_assumingOAICompat, 'quasar')
if (lower.includes('gpt') && lower.includes('mini') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions['gpt-4.1-mini'])
if (lower.includes('gpt') && lower.includes('nano') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions['gpt-4.1-nano'])
if (lower.includes('gpt') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions['gpt-4.1'])
if (lower.includes('gpt') && lower.includes('mini') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions, 'gpt-4.1-mini')
if (lower.includes('gpt') && lower.includes('nano') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions, 'gpt-4.1-nano')
if (lower.includes('gpt') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions, 'gpt-4.1')
if (lower.includes('4o') && lower.includes('mini')) return toFallback(openAIModelOptions['gpt-4o-mini'])
if (lower.includes('4o')) return toFallback(openAIModelOptions['gpt-4o'])
if (lower.includes('4o') && lower.includes('mini')) return toFallback(openAIModelOptions, 'gpt-4o-mini')
if (lower.includes('4o')) return toFallback(openAIModelOptions, 'gpt-4o')
if (lower.includes('o1') && lower.includes('mini')) return toFallback(openAIModelOptions['o1-mini'])
if (lower.includes('o1')) return toFallback(openAIModelOptions['o1'])
if (lower.includes('o3') && lower.includes('mini')) return toFallback(openAIModelOptions['o3-mini'])
if (lower.includes('o3')) return toFallback(openAIModelOptions['o3'])
if (lower.includes('o4') && lower.includes('mini')) return toFallback(openAIModelOptions['o4-mini'])
if (lower.includes('o1') && lower.includes('mini')) return toFallback(openAIModelOptions, 'o1-mini')
if (lower.includes('o1')) return toFallback(openAIModelOptions, 'o1')
if (lower.includes('o3') && lower.includes('mini')) return toFallback(openAIModelOptions, 'o3-mini')
if (lower.includes('o3')) return toFallback(openAIModelOptions, 'o3')
if (lower.includes('o4') && lower.includes('mini')) return toFallback(openAIModelOptions, 'o4-mini')
if (Object.keys(openSourceModelOptions_assumingOAICompat).map(k => k.toLowerCase()).includes(lower))
return toFallback(openSourceModelOptions_assumingOAICompat[lower as keyof typeof openSourceModelOptions_assumingOAICompat])
return toFallback(openSourceModelOptions_assumingOAICompat, lower as keyof typeof openSourceModelOptions_assumingOAICompat)
return toFallback(defaultModelOptions)
return null
}
@ -427,7 +434,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: 'slider', min: 1024, max: 32_000, default: 1024 }, // they recommend batching if max > 32_000
reasoningBudgetSlider: { type: 'number_slider', min: 1024, max: 32_000, default: 1024 }, // they recommend batching if max > 32_000
},
},
@ -1039,7 +1046,7 @@ const openRouterModelOptions_assumingOpenAICompat = {
canTurnOffReasoning: false,
canIOReasoning: true,
reasoningReservedOutputTokenSpace: 64_000,
reasoningBudgetSlider: { type: 'slider', min: 1024, max: 32_000, default: 1024 }, // they recommend batching if max > 32_000
reasoningBudgetSlider: { type: 'number_slider', min: 1024, max: 32_000, default: 1024 }, // they recommend batching if max > 32_000
},
},
'anthropic/claude-3.7-sonnet': {
@ -1224,7 +1231,7 @@ export const getSendableReasoningInfo = (
if (!isReasoningEnabled) return null
// check for reasoning budget
const reasoningBudget = reasoningBudgetSlider?.type === 'slider' ? modelSelectionOptions?.reasoningBudget ?? reasoningBudgetSlider?.default : undefined
const reasoningBudget = reasoningBudgetSlider?.type === 'number_slider' ? modelSelectionOptions?.reasoningBudget ?? reasoningBudgetSlider?.default : undefined
if (reasoningBudget) {
return { type: 'budgetEnabled', isReasoningEnabled: isReasoningEnabled, reasoningBudget: reasoningBudget }
}

View file

@ -11,7 +11,7 @@ import { registerSingleton, InstantiationType } from '../../../../platform/insta
import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js';
import { IStorageService, StorageScope, StorageTarget } from '../../../../platform/storage/common/storage.js';
import { IMetricsService } from './metricsService.js';
import { defaultProviderSettings, getModelCapabilities, ModelOverrideOptions } from './modelCapabilities.js';
import { defaultProviderSettings, getModelCapabilities, ModelOverrides } from './modelCapabilities.js';
import { VOID_SETTINGS_STORAGE_KEY } from './storageKeys.js';
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, VoidStatefulModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, ModelSelectionOptions, OptionsOfModelSelection, ChatMode, OverridesOfModel, defaultOverridesOfModel } from './voidSettingsTypes.js';
@ -62,7 +62,9 @@ export interface IVoidSettingsService {
setModelSelectionOfFeature: SetModelSelectionOfFeatureFn;
setOptionsOfModelSelection: SetOptionsOfModelSelection;
setGlobalSetting: SetGlobalSettingFn;
setOverridesOfModel(providerName: ProviderName, modelName: string, overrides: ModelOverrideOptions): Promise<void>;
// setting to undefined CLEARS it, unlike others:
setOverridesOfModel(providerName: ProviderName, modelName: string, overrides: Partial<ModelOverrides> | undefined): Promise<void>;
dangerousSetState(newState: VoidSettingsState): Promise<void>;
resetState(): Promise<void>;
@ -438,19 +440,17 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
this._onDidChangeState.fire()
}
setOverridesOfModel = async (providerName: ProviderName, modelName: string, overrides: ModelOverrideOptions) => {
const currentProviderSettings = this.state.overridesOfModel[providerName] || {};
setOverridesOfModel = async (providerName: ProviderName, modelName: string, overrides: Partial<ModelOverrides> | undefined) => {
const newState: VoidSettingsState = {
...this.state,
overridesOfModel: {
...this.state.overridesOfModel,
[providerName]: {
...currentProviderSettings,
[modelName]: {
...currentProviderSettings[modelName],
...this.state.overridesOfModel[providerName],
[modelName]: overrides === undefined ? undefined : {
...this.state.overridesOfModel[providerName][modelName],
...overrides
}
},
}
}
};
@ -459,7 +459,7 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
await this._storeState();
this._onDidChangeState.fire();
this._metricsService.capture('Update Model Settings', { providerName, modelName, overrides });
this._metricsService.capture('Update Model Overrides', { providerName, modelName, overrides });
}

View file

@ -4,7 +4,7 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/
import { defaultModelsOfProvider, defaultProviderSettings, ModelOverrideOptions } from './modelCapabilities.js';
import { defaultModelsOfProvider, defaultProviderSettings, ModelOverrides } from './modelCapabilities.js';
import { ToolApprovalType } from './toolsServiceTypes.js';
import { VoidSettingsState } from './voidSettingsService.js'
@ -482,7 +482,7 @@ export type OptionsOfModelSelection = {
export type OverridesOfModel = {
[providerName in ProviderName]: {
[modelName: string]: ModelOverrideOptions | undefined
[modelName: string]: Partial<ModelOverrides> | undefined
}
}

View file

@ -241,7 +241,7 @@ const _sendOpenAICompatibleChat = async ({ messages, onText, onFinalMessage, onE
const { providerReasoningIOSettings } = getProviderCapabilities(providerName)
// reasoning
const { canIOReasoning, openSourceThinkTags, } = reasoningCapabilities || {}
const { canIOReasoning, openSourceThinkTags } = reasoningCapabilities || {}
const reasoningInfo = getSendableReasoningInfo('Chat', providerName, modelName_, modelSelectionOptions, overridesOfModel) // user's modelName_ here
const includeInPayload = providerReasoningIOSettings?.input?.includeInPayload?.(reasoningInfo) || {}