add model overrides and headers JSON!

This commit is contained in:
Andrew Pareles 2025-05-03 16:41:41 -07:00
parent 4fb0d7d727
commit 5090e31a89
11 changed files with 647 additions and 89 deletions

159
package-lock.json generated
View file

@ -47,6 +47,7 @@
"cross-spawn": "^7.0.6",
"diff": "^7.0.0",
"eslint-plugin-react": "^7.37.5",
"google-auth-library": "^9.15.1",
"groq-sdk": "^0.20.1",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",
@ -6023,6 +6024,15 @@
"node": "*"
}
},
"node_modules/bignumber.js": {
"version": "9.3.0",
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz",
"integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==",
"license": "MIT",
"engines": {
"node": "*"
}
},
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
@ -6253,6 +6263,12 @@
"node": ">=0.4.0"
}
},
"node_modules/buffer-equal-constant-time": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
"license": "BSD-3-Clause"
},
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
@ -8100,6 +8116,15 @@
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
"dev": true
},
"node_modules/ecdsa-sig-formatter": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
"license": "Apache-2.0",
"dependencies": {
"safe-buffer": "^5.0.1"
}
},
"node_modules/editorconfig": {
"version": "0.15.2",
"resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.2.tgz",
@ -9340,8 +9365,7 @@
"node_modules/extend": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
"dev": true
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"node_modules/extend-shallow": {
"version": "3.0.2",
@ -10308,6 +10332,68 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/gaxios": {
"version": "6.7.1",
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz",
"integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==",
"license": "Apache-2.0",
"dependencies": {
"extend": "^3.0.2",
"https-proxy-agent": "^7.0.1",
"is-stream": "^2.0.0",
"node-fetch": "^2.6.9",
"uuid": "^9.0.1"
},
"engines": {
"node": ">=14"
}
},
"node_modules/gaxios/node_modules/is-stream": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/gaxios/node_modules/node-fetch": {
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"license": "MIT",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/gcp-metadata": {
"version": "6.1.1",
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz",
"integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==",
"license": "Apache-2.0",
"dependencies": {
"gaxios": "^6.1.1",
"google-logging-utils": "^0.0.2",
"json-bigint": "^1.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/gensync": {
"version": "1.0.0-beta.2",
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
@ -10944,6 +11030,32 @@
"node": ">= 0.10"
}
},
"node_modules/google-auth-library": {
"version": "9.15.1",
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz",
"integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==",
"license": "Apache-2.0",
"dependencies": {
"base64-js": "^1.3.0",
"ecdsa-sig-formatter": "^1.0.11",
"gaxios": "^6.1.1",
"gcp-metadata": "^6.1.0",
"gtoken": "^7.0.0",
"jws": "^4.0.0"
},
"engines": {
"node": ">=14"
}
},
"node_modules/google-logging-utils": {
"version": "0.0.2",
"resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz",
"integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==",
"license": "Apache-2.0",
"engines": {
"node": ">=14"
}
},
"node_modules/gopd": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
@ -11016,6 +11128,19 @@
"undici-types": "~5.26.4"
}
},
"node_modules/gtoken": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz",
"integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==",
"license": "MIT",
"dependencies": {
"gaxios": "^6.0.0",
"jws": "^4.0.0"
},
"engines": {
"node": ">=14.0.0"
}
},
"node_modules/gulp": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz",
@ -13975,6 +14100,15 @@
"node": ">=6"
}
},
"node_modules/json-bigint": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz",
"integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==",
"license": "MIT",
"dependencies": {
"bignumber.js": "^9.0.0"
}
},
"node_modules/json-buffer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz",
@ -14095,6 +14229,27 @@
"integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==",
"dev": true
},
"node_modules/jwa": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz",
"integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==",
"license": "MIT",
"dependencies": {
"buffer-equal-constant-time": "1.0.1",
"ecdsa-sig-formatter": "1.0.11",
"safe-buffer": "^5.0.1"
}
},
"node_modules/jws": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz",
"integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==",
"license": "MIT",
"dependencies": {
"jwa": "^2.0.0",
"safe-buffer": "^5.0.1"
}
},
"node_modules/kerberos": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/kerberos/-/kerberos-2.1.1.tgz",

View file

@ -109,6 +109,7 @@
"cross-spawn": "^7.0.6",
"diff": "^7.0.0",
"eslint-plugin-react": "^7.37.5",
"google-auth-library": "^9.15.1",
"groq-sdk": "^0.20.1",
"http-proxy-agent": "^7.0.0",
"https-proxy-agent": "^7.0.2",

View file

@ -682,8 +682,8 @@ class ChatThreadService extends Disposable implements IChatThreadService {
let shouldRetryLLM = true
let nAttempts = 0
while (shouldRetryLLM) {
shouldRetryLLM = false
nAttempts += 1
let resMessageIsDonePromise: (res: { type: 'llmDone', toolCall?: RawToolCallObj } | { type: 'llmError', error?: { message: string; fullError: Error | null; } } | { type: 'llmAborted' }) => void // resolves when user approves this tool use (or if tool doesn't require approval)
const messageIsDonePromise = new Promise<{ type: 'llmDone', toolCall?: RawToolCallObj } | { type: 'llmError', error?: { message: string; fullError: Error | null; } } | { type: 'llmAborted' }>((res, rej) => { resMessageIsDonePromise = res })
@ -737,7 +737,6 @@ class ChatThreadService extends Disposable implements IChatThreadService {
else if (llmRes.type === 'llmError') {
// error, should retry
if (nAttempts < CHAT_RETRIES) {
nAttempts += 1
shouldRetryLLM = true
this._setStreamState(threadId, { isRunning: 'idle', interrupt: idleInterruptor })
await timeout(RETRY_DELAY)

View file

@ -722,7 +722,7 @@ const ToolHeaderWrapper = ({
return (<div className=''>
<div className={`w-full border border-void-border-3 rounded px-2 py-1 bg-void-bg-3 overflow-hidden ${className}`}>
{/* header */}
<div className={`select-none flex items-center ml-4 min-h-[24px]`}>
<div className={`select-none flex items-center min-h-[24px]`}>
<div className={`flex items-center w-full gap-x-2 overflow-hidden justify-between ${isRejected ? 'line-through' : ''}`}>
{/* left */}
<div className={`

View file

@ -8,7 +8,7 @@ import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, Voi
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
import { VoidButtonBgDarken, VoidCustomDropdownBox, VoidInputBox2, VoidSimpleInputBox, VoidSwitch } from '../util/inputs.js'
import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js'
import { X, RefreshCw, Loader2, Check, Asterisk } from 'lucide-react'
import { X, RefreshCw, Loader2, Check, Asterisk, Settings as SettingsIcon } from 'lucide-react'
import { URI } from '../../../../../../../base/common/uri.js'
import { env } from '../../../../../../../base/common/process.js'
import { ModelDropdown } from './ModelDropdown.js'
@ -302,13 +302,265 @@ export const AddModelInputBox = ({ providerName: permanentProviderName, classNam
}
export const ModelDump = () => {
// Import the getModelCapabilities function to access default values
import { defaultModelOptions, 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);
// Initialize form state for all potential override options
const [formValues, setFormValues] = useState<{
contextWindow: string;
maxOutputTokens: string;
supportsTools: 'openai-style' | undefined | '';
supportsSystemMessage: 'system-role' | 'developer-role' | false | '';
supportsFIM: boolean | null;
reasoningCapabilities: boolean | null;
}>({
contextWindow: '',
maxOutputTokens: '',
supportsTools: '',
supportsSystemMessage: '',
supportsFIM: null,
reasoningCapabilities: null
});
// When dialog opens or model changes, reset form values
useEffect(() => {
if (isOpen && modelInfo) {
// Get current overrides
const overrides = settingsState.overridesOfModel?.[providerName]?.[modelName] || {};
setFormValues({
contextWindow: (overrides.contextWindow !== undefined) ? overrides.contextWindow?.toString() : '',
maxOutputTokens: (overrides.maxOutputTokens !== undefined) ? overrides.maxOutputTokens?.toString() : '',
supportsTools: overrides.supportsTools !== undefined ? overrides.supportsTools : '',
supportsSystemMessage: overrides.supportsSystemMessage !== undefined ? overrides.supportsSystemMessage : '',
supportsFIM: overrides.supportsFIM !== undefined ? overrides.supportsFIM : null,
reasoningCapabilities: overrides.reasoningCapabilities !== undefined ?
!!overrides.reasoningCapabilities : null
});
}
}, [isOpen, modelInfo, settingsState.overridesOfModel, providerName, modelName]);
// Update a single field in the form
const updateField = (field: string, value: any) => {
setFormValues(prev => ({
...prev,
[field]: value
}));
};
// Handle saving settings
const handleSave = async () => {
const settings: ModelOverrideOptions = {};
// Only add fields to the override if they have been changed from defaults
if (formValues.contextWindow) {
const tokens = parseInt(formValues.contextWindow);
if (!isNaN(tokens)) settings.contextWindow = tokens;
}
if (formValues.maxOutputTokens) {
const tokens = parseInt(formValues.maxOutputTokens);
if (!isNaN(tokens)) settings.maxOutputTokens = tokens;
}
if (formValues.supportsTools !== '') {
settings.supportsTools = formValues.supportsTools as any;
}
if (formValues.supportsSystemMessage !== '') {
settings.supportsSystemMessage = formValues.supportsSystemMessage as any;
}
if (formValues.supportsFIM !== null) {
settings.supportsFIM = formValues.supportsFIM;
}
if (formValues.reasoningCapabilities !== null) {
if (formValues.reasoningCapabilities) {
settings.reasoningCapabilities = {
supportsReasoning: true,
canTurnOffReasoning: true,
canIOReasoning: true
};
} else {
settings.reasoningCapabilities = false;
}
}
await settingsStateService.setOverridesOfModel(providerName, modelName, settings);
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">Override 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>
<VoidSimpleInputBox
value={formValues.contextWindow}
onChangeValue={(value) => updateField('contextWindow', value)}
placeholder={(modelCapabilities.contextWindow || defaultModelOptions.contextWindow) + ''}
compact={true}
className="max-w-24"
/>
</div>
{/* Maximum output tokens */}
<div className="flex items-center justify-between py-1">
<span className="text-void-fg-2">Maximum output tokens</span>
<VoidSimpleInputBox
value={formValues.maxOutputTokens}
onChangeValue={(value) => updateField('maxOutputTokens', value)}
placeholder={(modelCapabilities.maxOutputTokens || defaultModelOptions.maxOutputTokens) + ''}
compact={true}
className="max-w-24"
/>
</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.supportsTools}
onChangeOption={(value) => updateField('supportsTools', value)}
getOptionDisplayName={(opt) => {
if (opt === '') return `Default (${modelCapabilities.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 (${modelCapabilities.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 (${modelCapabilities.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 (${modelCapabilities.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>
</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()
const settingsStateService = accessor.get('IVoidSettingsService')
const settingsState = useSettingsState()
// State to track which model's settings dialog is open
const [openSettingsModel, setOpenSettingsModel] = useState<{
modelName: string,
providerName: ProviderName,
type: string
} | null>(null);
// a dump of all the enabled providers' models
const modelDump: (VoidStatefulModelInfo & { providerName: ProviderName, providerEnabled: boolean })[] = []
for (let providerName of providerNames) {
@ -342,8 +594,10 @@ export const ModelDump = () => {
const detailAboutModel = type === 'autodetected' ?
<Asterisk size={14} className="inline-block align-text-top brightness-115 stroke-[2] text-[#0e70c0]" data-tooltip-id='void-tooltip' data-tooltip-place='right' data-tooltip-content='Detected locally' />
: type === 'default' ? undefined
: <Asterisk size={14} className="inline-block align-text-top brightness-115 stroke-[2] text-[#0e70c0]" data-tooltip-id='void-tooltip' data-tooltip-place='right' data-tooltip-content='Custom model' />
: type === 'custom' ?
<Asterisk size={14} className="inline-block align-text-top brightness-115 stroke-[2] text-[#0e70c0]" data-tooltip-id='void-tooltip' data-tooltip-place='right' data-tooltip-content='Custom model' />
: undefined
return <div key={`${modelName}${providerName}`}
@ -367,6 +621,27 @@ export const ModelDump = () => {
{/* <span className='opacity-50 truncate'>{type === 'autodetected' ? '(detected locally)' : type === 'default' ? '' : '(custom model)'}</span> */}
{/* Settings button - only for custom or locally detected models */}
{(type === 'autodetected' || type === 'custom') && (
<div className="w-5 flex items-center justify-center">
<button
onClick={() => {
setOpenSettingsModel({
modelName,
providerName,
type
})
}}
data-tooltip-id='void-tooltip'
data-tooltip-place='right'
data-tooltip-content="Model Settings"
>
<SettingsIcon size={14} className="text-void-fg-3" />
</button>
</div>
)}
<VoidSwitch
value={value}
onChange={() => { settingsStateService.toggleModelHidden(providerName, modelName) }}
@ -384,6 +659,13 @@ export const ModelDump = () => {
</div>
</div>
})}
{/* Model Settings Dialog */}
<ModelSettingsDialog
isOpen={openSettingsModel !== null}
onClose={() => setOpenSettingsModel(null)}
modelInfo={openSettingsModel}
/>
</div>
}

View file

@ -3,7 +3,7 @@
* Licensed under the Apache License, Version 2.0. See LICENSE.txt for more information.
*--------------------------------------------------------------------------------------*/
import { FeatureName, ModelSelectionOptions, ProviderName } from './voidSettingsTypes.js';
import { FeatureName, ModelSelectionOptions, OverridesOfModel, ProviderName } from './voidSettingsTypes.js';
@ -31,6 +31,7 @@ export const defaultProviderSettings = {
openAICompatible: {
endpoint: '',
apiKey: '',
headersJSON: '',
},
gemini: {
apiKey: '',
@ -50,10 +51,10 @@ export const defaultProviderSettings = {
liteLLM: { // https://docs.litellm.ai/docs/providers/openai_compatible
endpoint: '',
},
// googleVertex: { // google https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-vertex-using-openai-library
// region: 'us-west2',
// project: '',
// },
googleVertex: { // google https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-vertex-using-openai-library
region: 'us-west2',
project: '',
},
microsoftAzure: { // microsoft Azure Foundry
project: '', // really 'resource'
apiKey: '',
@ -129,7 +130,7 @@ export const defaultModelsOfProvider = {
'ministral-8b-latest',
],
openAICompatible: [], // fallback
// googleVertex: [],
googleVertex: [],
microsoftAzure: [],
liteLLM: [],
@ -161,7 +162,7 @@ export type VoidStaticModelInfo = { // not stateful
// reasoning options if supports reasoning
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 reasoningMaxOutputTokens?: number; // overrides normal maxOutputTokens // <-- UNUSED (except anthropic)
readonly reasoningMaxOutputTokens?: number; // overrides normal maxOutputTokens
readonly reasoningBudgetSlider?: { type: 'slider'; min: number; max: number; default: number };
// options related specifically to model output
@ -171,6 +172,26 @@ export type VoidStaticModelInfo = { // not stateful
};
}
export type ModelOverrideOptions = Partial<{
contextWindow: number; // input tokens
maxOutputTokens: number; // output tokens, defaults to 4092
supportsTools: 'openai-style' | undefined;
supportsSystemMessage: 'system-role' | 'developer-role' | false;
supportsFIM: boolean;
reasoningCapabilities: false | {
readonly supportsReasoning: true;
readonly canTurnOffReasoning: boolean;
readonly canIOReasoning: boolean;
readonly reasoningMaxOutputTokens?: number;
readonly openSourceThinkTags?: [string, string];
}
}>
type ProviderReasoningIOSettings = {
// include this in payload to get reasoning
input?: { includeInPayload?: (reasoningState: SendableReasoningInfo) => null | { [key: string]: any }, };
@ -189,15 +210,15 @@ type VoidStaticProviderInfo = { // doesn't change (not stateful)
const modelOptionsDefaults: VoidStaticModelInfo = {
contextWindow: 16_000,
export const defaultModelOptions = {
contextWindow: 4_096,
maxOutputTokens: 4_096,
cost: { input: 0, output: 0 },
downloadable: false,
supportsSystemMessage: false,
supportsFIM: false,
reasoningCapabilities: false,
}
} as const satisfies VoidStaticModelInfo
// TODO!!! double check all context sizes below
// TODO!!! add openrouter common models
@ -396,7 +417,7 @@ const extensiveModelFallback: VoidStaticProviderInfo['modelOptionsFallback'] = (
if (Object.keys(openSourceModelOptions_assumingOAICompat).map(k => k.toLowerCase()).includes(lower))
return toFallback(openSourceModelOptions_assumingOAICompat[lower as keyof typeof openSourceModelOptions_assumingOAICompat])
return toFallback(modelOptionsDefaults)
return toFallback(defaultModelOptions)
}
@ -485,7 +506,7 @@ const anthropicSettings: VoidStaticProviderInfo = {
if (lower.includes('claude-3-opus')) fallbackName = 'claude-3-opus-20240229'
if (lower.includes('claude-3-sonnet')) fallbackName = 'claude-3-sonnet-20240229'
if (fallbackName) return { modelName: fallbackName, ...anthropicModelOptions[fallbackName] }
return { modelName, ...modelOptionsDefaults, maxOutputTokens: 4_096 }
return { modelName, ...defaultModelOptions, maxOutputTokens: 4_096 }
},
}
@ -854,12 +875,12 @@ const groqSettings: VoidStaticProviderInfo = {
// ---------------- GOOGLE VERTEX ----------------
// const googleVertexModelOptions = {
// } as const satisfies Record<string, VoidStaticModelInfo>
// const googleVertexSettings: VoidStaticProviderInfo = {
// modelOptions: googleVertexModelOptions,
// modelOptionsFallback: (modelName) => { return null }
// }
const googleVertexModelOptions = {
} as const satisfies Record<string, VoidStaticModelInfo>
const googleVertexSettings: VoidStaticProviderInfo = {
modelOptions: googleVertexModelOptions,
modelOptionsFallback: (modelName) => { return null }
}
// ---------------- MICROSOFT AZURE ----------------
const microsoftAzureModelOptions = {
@ -872,7 +893,7 @@ const microsoftAzureSettings: VoidStaticProviderInfo = {
// ---------------- VLLM, OLLAMA, OPENAICOMPAT (self-hosted / local) ----------------
const ollamaModelOptions = {
'qwen2.5-coder:1.5b': {
'qwen2.5-coder:7b': {
contextWindow: 32_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
@ -881,6 +902,24 @@ const ollamaModelOptions = {
supportsSystemMessage: 'system-role',
reasoningCapabilities: false,
},
'qwen2.5-coder:3b': {
contextWindow: 32_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: { sizeGb: 1.9 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
reasoningCapabilities: false,
},
'qwen2.5-coder:1.5b': {
contextWindow: 32_000,
maxOutputTokens: null,
cost: { input: 0, output: 0 },
downloadable: { sizeGb: .986 },
supportsFIM: true,
supportsSystemMessage: 'system-role',
reasoningCapabilities: false,
},
'llama3.1': {
contextWindow: 128_000,
maxOutputTokens: null,
@ -1105,7 +1144,7 @@ const modelSettingsOfProvider: { [providerName in ProviderName]: VoidStaticProvi
liteLLM: liteLLMSettings,
lmStudio: lmStudioSettings,
// googleVertex: googleVertexSettings,
googleVertex: googleVertexSettings,
microsoftAzure: microsoftAzureSettings,
} as const
@ -1113,22 +1152,33 @@ const modelSettingsOfProvider: { [providerName in ProviderName]: VoidStaticProvi
// ---------------- exports ----------------
// returns the capabilities and the adjusted modelName if it was a fallback
export const getModelCapabilities = (providerName: ProviderName, modelName: string): VoidStaticModelInfo & { modelName: string; isUnrecognizedModel: boolean } => {
export const getModelCapabilities = (
providerName: ProviderName,
modelName: string,
overridesOfModel?: OverridesOfModel
): VoidStaticModelInfo & { modelName: string; isUnrecognizedModel: boolean } => {
const lowercaseModelName = modelName.toLowerCase()
const { modelOptions, modelOptionsFallback } = modelSettingsOfProvider[providerName]
// Get any override settings for this model
const overrides = overridesOfModel?.[providerName]?.[modelName];
// search model options object directly first
for (const modelName_ in modelOptions) {
const lowercaseModelName_ = modelName_.toLowerCase()
if (lowercaseModelName === lowercaseModelName_)
return { modelName, ...modelOptions[modelName], isUnrecognizedModel: false }
if (lowercaseModelName === lowercaseModelName_) {
return { ...modelOptions[modelName], ...overrides, modelName, isUnrecognizedModel: false };
}
}
const result = modelOptionsFallback(modelName)
if (result) return { ...result, isUnrecognizedModel: false }
return { modelName, ...modelOptionsDefaults, isUnrecognizedModel: true }
if (result) {
return { ...result, ...overrides, modelName: result.modelName, isUnrecognizedModel: false };
}
return { modelName, ...defaultModelOptions, ...overrides, isUnrecognizedModel: true };
}
// non-model settings

View file

@ -112,7 +112,7 @@ ${searchReplaceBlockTemplate}
## Guidelines:
1. You are encouraged to output multiple changes whenever possible.
1. You may output multiple search replace blocks if needed.
2. The ORIGINAL code in each SEARCH/REPLACE block must EXACTLY match lines in the original file. Do not add or remove any whitespace or comments from the original code.

View file

@ -11,9 +11,9 @@ 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 } from './modelCapabilities.js';
import { defaultProviderSettings, getModelCapabilities, ModelOverrideOptions } 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 } from './voidSettingsTypes.js';
import { defaultSettingsOfProvider, FeatureName, ProviderName, ModelSelectionOfFeature, SettingsOfProvider, SettingName, providerNames, ModelSelection, modelSelectionsEqual, featureNames, VoidStatefulModelInfo, GlobalSettings, GlobalSettingName, defaultGlobalSettings, ModelSelectionOptions, OptionsOfModelSelection, ChatMode, OverridesOfModel, defaultOverridesOfModel } from './voidSettingsTypes.js';
// name is the name in the dropdown
@ -41,6 +41,7 @@ export type VoidSettingsState = {
readonly settingsOfProvider: SettingsOfProvider; // optionsOfProvider
readonly modelSelectionOfFeature: ModelSelectionOfFeature; // stateOfFeature
readonly optionsOfModelSelection: OptionsOfModelSelection;
readonly overridesOfModel: OverridesOfModel;
readonly globalSettings: GlobalSettings;
readonly _modelOptions: ModelOption[] // computed based on the two above items
@ -61,6 +62,7 @@ export interface IVoidSettingsService {
setModelSelectionOfFeature: SetModelSelectionOfFeatureFn;
setOptionsOfModelSelection: SetOptionsOfModelSelection;
setGlobalSetting: SetGlobalSettingFn;
setOverridesOfModel(providerName: ProviderName, modelName: string, overrides: ModelOverrideOptions): Promise<void>;
dangerousSetState(newState: VoidSettingsState): Promise<void>;
resetState(): Promise<void>;
@ -182,6 +184,7 @@ const _validatedModelState = (state: Omit<VoidSettingsState, '_modelOptions'>):
...state,
settingsOfProvider: newSettingsOfProvider,
modelSelectionOfFeature: newModelSelectionOfFeature,
overridesOfModel: state.overridesOfModel,
_modelOptions: newModelOptions,
} satisfies VoidSettingsState
@ -198,6 +201,7 @@ const defaultState = () => {
modelSelectionOfFeature: { 'Chat': null, 'Ctrl+K': null, 'Autocomplete': null, 'Apply': null },
globalSettings: deepClone(defaultGlobalSettings),
optionsOfModelSelection: { 'Chat': {}, 'Ctrl+K': {}, 'Autocomplete': {}, 'Apply': {} },
overridesOfModel: deepClone(defaultOverridesOfModel),
_modelOptions: [], // computed later
}
return d
@ -267,9 +271,11 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
// the stored data structure might be outdated, so we need to update it here
try {
readS = {
...defaultState(),
...readS,
...defaultSettingsOfProvider,
...readS.settingsOfProvider,
// no idea why this was here, seems like a bug
// ...defaultSettingsOfProvider,
// ...readS.settingsOfProvider,
}
for (const providerName of providerNames) {
@ -314,7 +320,8 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
return defaultState()
const stateStr = await this._encryptionService.decrypt(encryptedState)
return JSON.parse(stateStr)
const state = JSON.parse(stateStr)
return state
}
@ -339,12 +346,14 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
}
const newGlobalSettings = this.state.globalSettings
const newOverridesOfModel = this.state.overridesOfModel
const newState = {
modelSelectionOfFeature: newModelSelectionOfFeature,
optionsOfModelSelection: newOptionsOfModelSelection,
settingsOfProvider: newSettingsOfProvider,
globalSettings: newGlobalSettings,
overridesOfModel: newOverridesOfModel,
}
this.state = _validatedModelState(newState)
@ -422,6 +431,30 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
this._onDidChangeState.fire()
}
setOverridesOfModel = async (providerName: ProviderName, modelName: string, overrides: ModelOverrideOptions) => {
const currentProviderSettings = this.state.overridesOfModel[providerName] || {};
const newState: VoidSettingsState = {
...this.state,
overridesOfModel: {
...this.state.overridesOfModel,
[providerName]: {
...currentProviderSettings,
[modelName]: {
...currentProviderSettings[modelName],
...overrides
}
}
}
};
this.state = _validatedModelState(newState);
await this._storeState();
this._onDidChangeState.fire();
this._metricsService.capture('Update Model Settings', { 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 } from './modelCapabilities.js';
import { defaultModelsOfProvider, defaultProviderSettings, ModelOverrideOptions } from './modelCapabilities.js';
import { ToolApprovalType } from './toolsServiceTypes.js';
import { VoidSettingsState } from './voidSettingsService.js'
@ -97,9 +97,9 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
else if (providerName === 'mistral') {
return { title: 'Mistral', }
}
// else if (providerName === 'googleVertex') {
// return { title: 'Google Vertex AI', }
// }
else if (providerName === 'googleVertex') {
return { title: 'Google Vertex AI', }
}
else if (providerName === 'microsoftAzure') {
return { title: 'Microsoft Azure OpenAI', }
}
@ -118,7 +118,7 @@ export const subTextMdOfProviderName = (providerName: ProviderName): string => {
if (providerName === 'xAI') return 'Get your [API Key here](https://console.x.ai).'
if (providerName === 'mistral') return 'Get your [API Key here](https://console.mistral.ai/api-keys).'
if (providerName === 'openAICompatible') return `Use any provider that's OpenAI-compatible (use this for llama.cpp and more).`
// if (providerName === 'googleVertex') return 'You must authenticate before using Vertex with Void. Read more about endpoints [here](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-vertex-using-openai-library), and regions [here](https://cloud.google.com/vertex-ai/docs/general/locations#available-regions).'
if (providerName === 'googleVertex') return 'You must authenticate before using Vertex with Void. Read more about endpoints [here](https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-vertex-using-openai-library), and regions [here](https://cloud.google.com/vertex-ai/docs/general/locations#available-regions).'
if (providerName === 'microsoftAzure') return 'Read more about endpoints [here](https://learn.microsoft.com/en-us/rest/api/aifoundry/model-inference/get-chat-completions/get-chat-completions?view=rest-aifoundry-model-inference-2024-05-01-preview&tabs=HTTP), and get your API key [here](https://learn.microsoft.com/en-us/azure/search/search-security-api-keys?tabs=rest-use%2Cportal-find%2Cportal-query#find-existing-keys).'
if (providerName === 'ollama') return 'If you would like to change this endpoint, please read more about [Endpoints here](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-expose-ollama-on-my-network).'
if (providerName === 'vLLM') return 'If you would like to change this endpoint, please read more about [Endpoints here](https://docs.vllm.ai/en/latest/getting_started/quickstart.html#openai-compatible-server).'
@ -149,9 +149,9 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
providerName === 'openAICompatible' ? 'sk-key...' :
providerName === 'xAI' ? 'xai-key...' :
providerName === 'mistral' ? 'api-key...' :
// providerName === 'googleVertex' ? 'AIzaSy...' :
providerName === 'microsoftAzure' ? 'key-...' :
'',
providerName === 'googleVertex' ? 'AIzaSy...' :
providerName === 'microsoftAzure' ? 'key-...' :
'',
isPasswordField: true,
}
@ -162,10 +162,10 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
providerName === 'vLLM' ? 'Endpoint' :
providerName === 'lmStudio' ? 'Endpoint' :
providerName === 'openAICompatible' ? 'baseURL' : // (do not include /chat/completions)
// providerName === 'googleVertex' ? 'baseURL' :
providerName === 'microsoftAzure' ? 'baseURL' :
providerName === 'liteLLM' ? 'baseURL' :
'(never)',
providerName === 'googleVertex' ? 'baseURL' :
providerName === 'microsoftAzure' ? 'baseURL' :
providerName === 'liteLLM' ? 'baseURL' :
'(never)',
placeholder: providerName === 'ollama' ? defaultProviderSettings.ollama.endpoint
: providerName === 'vLLM' ? defaultProviderSettings.vLLM.endpoint
@ -177,14 +177,17 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
}
}
// else if (settingName === 'region') {
// // vertex only
// return {
// title: 'Region',
// placeholder: providerName === 'googleVertex' ? defaultProviderSettings.googleVertex.region
// : ''
// }
// }
else if (settingName === 'headersJSON') {
return { title: 'Custom Headers', placeholder: '{ "X-Request-Id": "..." }' }
}
else if (settingName === 'region') {
// vertex only
return {
title: 'Region',
placeholder: providerName === 'googleVertex' ? defaultProviderSettings.googleVertex.region
: ''
}
}
else if (settingName === 'azureApiVersion') {
// azure only
return {
@ -196,11 +199,11 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
else if (settingName === 'project') {
return {
title: providerName === 'microsoftAzure' ? 'Resource'
// : providerName === 'googleVertex' ? 'Project'
: '',
: providerName === 'googleVertex' ? 'Project'
: '',
placeholder: providerName === 'microsoftAzure' ? 'my-resource'
// : providerName === 'googleVertex' ? 'my-project'
: ''
: providerName === 'googleVertex' ? 'my-project'
: ''
}
@ -228,9 +231,10 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
const defaultCustomSettings: Record<CustomSettingName, undefined> = {
apiKey: undefined,
endpoint: undefined,
// region: undefined, // googleVertex
region: undefined, // googleVertex
project: undefined,
azureApiVersion: undefined,
headersJSON: undefined,
}
@ -324,12 +328,12 @@ export const defaultSettingsOfProvider: SettingsOfProvider = {
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.vLLM),
_didFillInProviderSettings: undefined,
},
// googleVertex: { // aggregator (serves models from multiple providers)
// ...defaultCustomSettings,
// ...defaultProviderSettings.googleVertex,
// ...modelInfoOfDefaultModelNames(defaultModelsOfProvider.googleVertex),
// _didFillInProviderSettings: undefined,
// },
googleVertex: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.googleVertex,
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.googleVertex),
_didFillInProviderSettings: undefined,
},
microsoftAzure: { // aggregator (serves models from multiple providers)
...defaultCustomSettings,
...defaultProviderSettings.microsoftAzure,
@ -467,8 +471,22 @@ export type ModelSelectionOptions = {
export type OptionsOfModelSelection = {
[featureName in FeatureName]: Partial<{
[providerName in ProviderName]: {
[modelName: string]:
ModelSelectionOptions | undefined
[modelName: string]: ModelSelectionOptions | undefined
}
}>
}
export type OverridesOfModel = {
[providerName in ProviderName]: {
[modelName: string]: ModelOverrideOptions | undefined
}
}
const overridesOfModel = {} as OverridesOfModel
for (const providerName of providerNames) { overridesOfModel[providerName] = {} }
export const defaultOverridesOfModel = overridesOfModel

View file

@ -11,7 +11,7 @@ import OpenAI, { ClientOptions } from 'openai';
import { MistralCore } from '@mistralai/mistralai/core.js';
import { fimComplete } from '@mistralai/mistralai/funcs/fimComplete.js';
import { GoogleGenerativeAI, Tool as GeminiTool, SchemaType, FunctionDeclaration, FunctionDeclarationSchemaProperty } from '@google/generative-ai';
// import { GoogleAuth } from 'google-auth-library'
import { GoogleAuth } from 'google-auth-library'
/* eslint-enable */
import { AnthropicLLMChatMessage, LLMChatMessage, LLMFIMMessage, ModelListParams, OllamaModelResponse, OnError, OnFinalMessage, OnText, RawToolCallObj, RawToolParamsObj } from '../../common/sendLLMMessageTypes.js';
@ -21,6 +21,14 @@ import { extractReasoningWrapper, extractXMLToolsWrapper } from './extractGramma
import { availableTools, InternalToolInfo, isAToolName, ToolParamName, voidTools } from '../../common/prompt/prompts.js';
import { generateUuid } from '../../../../../base/common/uuid.js';
const getGoogleApiKey = async () => {
// modulelevel singleton
const auth = new GoogleAuth({ scopes: `https://www.googleapis.com/auth/cloud-platform` });
const key = await auth.getAccessToken()
if (!key) throw new Error(`Google API failed to generate a key.`)
return key
}
@ -50,6 +58,15 @@ const invalidApiKeyMessage = (providerName: ProviderName) => `Invalid ${displayI
const parseHeadersJSON = (s: string | undefined): Record<string, string | null | undefined> | undefined => {
if (!s) return undefined
try {
return JSON.parse(s)
} catch (e) {
throw new Error(`Error parsing OpenAI-Compatible headers: ${s} is not a valid JSON.`)
}
}
const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includeInPayload }: { settingsOfProvider: SettingsOfProvider, providerName: ProviderName, includeInPayload?: { [s: string]: any } }) => {
const commonPayloadOpts: ClientOptions = {
dangerouslyAllowBrowser: true,
@ -87,12 +104,13 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ
...commonPayloadOpts,
})
}
// else if (providerName === 'googleVertex') {
// // https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-vertex-using-openai-library
// const thisConfig = settingsOfProvider[providerName]
// const baseURL = `https://${thisConfig.region}-aiplatform.googleapis.com/v1/projects/${thisConfig.project}/locations/${thisConfig.region}/endpoints/${'openapi'}`
// return new OpenAI({ baseURL: baseURL, apiKey: apiKey, ...commonPayloadOpts })
// }
else if (providerName === 'googleVertex') {
// https://cloud.google.com/vertex-ai/generative-ai/docs/multimodal/call-vertex-using-openai-library
const thisConfig = settingsOfProvider[providerName]
const baseURL = `https://${thisConfig.region}-aiplatform.googleapis.com/v1/projects/${thisConfig.project}/locations/${thisConfig.region}/endpoints/${'openapi'}`
const apiKey = await getGoogleApiKey()
return new OpenAI({ baseURL: baseURL, apiKey: apiKey, ...commonPayloadOpts })
}
else if (providerName === 'microsoftAzure') {
// https://learn.microsoft.com/en-us/rest/api/aifoundry/model-inference/get-chat-completions/get-chat-completions?view=rest-aifoundry-model-inference-2024-05-01-preview&tabs=HTTP
const thisConfig = settingsOfProvider[providerName]
@ -106,7 +124,8 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ
}
else if (providerName === 'openAICompatible') {
const thisConfig = settingsOfProvider[providerName]
return new OpenAI({ baseURL: thisConfig.endpoint, apiKey: thisConfig.apiKey, ...commonPayloadOpts })
const headers = parseHeadersJSON(thisConfig.headersJSON)
return new OpenAI({ baseURL: thisConfig.endpoint, apiKey: thisConfig.apiKey, defaultHeaders: headers, ...commonPayloadOpts })
}
else if (providerName === 'groq') {
const thisConfig = settingsOfProvider[providerName]
@ -843,20 +862,21 @@ export const sendLLMMessageToProviderImplementation = {
},
lmStudio: {
// lmStudio has no suffix parameter in /completions, so sendFIM might not work
sendChat: (params) => _sendOpenAICompatibleChat(params),
sendFIM: null, // lmStudio has no suffix parameter in /completions
sendFIM: (params) => _sendOpenAICompatibleFIM(params),
list: (params) => _openaiCompatibleList(params),
},
liteLLM: {
sendChat: (params) => _sendOpenAICompatibleChat(params),
sendFIM: (params) => _sendOpenAICompatibleFIM(params),
list: null,
},
googleVertex: {
sendChat: (params) => _sendOpenAICompatibleChat(params),
sendFIM: null,
list: null,
},
// googleVertex: {
// sendChat: (params) => _sendOpenAICompatibleChat(params),
// sendFIM: null,
// list: null,
// },
microsoftAzure: {
sendChat: (params) => _sendOpenAICompatibleChat(params),
sendFIM: null,

View file

@ -114,7 +114,7 @@ export const sendLLMMessage = async ({
await sendFIM({ messages: messages_, onText, onFinalMessage, onError, settingsOfProvider, modelSelectionOptions, modelName, _setAborter, providerName, separateSystemMessage })
return
}
onError({ message: `Error: This provider does not support Autocomplete yet.`, fullError: null })
onError({ message: `Error running Autocomplete with ${providerName} - ${modelName}.`, fullError: null })
return
}
onError({ message: `Error: Message type "${messagesType}" not recognized.`, fullError: null })