diff --git a/package-lock.json b/package-lock.json
index a365be59..7057acfd 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -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",
diff --git a/package.json b/package.json
index 462cf549..767d6b49 100644
--- a/package.json
+++ b/package.json
@@ -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",
diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts
index ae443a56..7c9eb899 100644
--- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts
+++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts
@@ -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)
diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx
index e35193a9..568c5aac 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx
@@ -722,7 +722,7 @@ const ToolHeaderWrapper = ({
return (
{/* header */}
-
+
{/* left */}
{
+// 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 (
+
+
e.stopPropagation()}>
+
+
Override defaults for {modelName} ({displayInfoOfProviderName(providerName).title})
+
+
+
+
+ {/* Model-specific settings */}
+
+
+ {/* Context window */}
+
+ Context window (tokens)
+ updateField('contextWindow', value)}
+ placeholder={(modelCapabilities.contextWindow || defaultModelOptions.contextWindow) + ''}
+ compact={true}
+ className="max-w-24"
+ />
+
+
+ {/* Maximum output tokens */}
+
+ Maximum output tokens
+ updateField('maxOutputTokens', value)}
+ placeholder={(modelCapabilities.maxOutputTokens || defaultModelOptions.maxOutputTokens) + ''}
+ compact={true}
+ className="max-w-24"
+ />
+
+
+ {/* Supports Tools */}
+
+ Supports tools
+ 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"
+ />
+
+
+ {/* Supports System Message */}
+
+ Supports system message
+ 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"
+ />
+
+
+ {/* Supports FIM */}
+
+ Supports fill-in-the-middle (autocomplete)
+ 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"
+ />
+
+
+ {/* Supports Reasoning */}
+
+ Supports reasoning
+ 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"
+ />
+
+
+
+
+
+
+ Cancel
+
+
+ Save
+
+
+
+
+ );
+};
+
+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' ?
- : type === 'default' ? undefined
- :
+ : type === 'custom' ?
+
+ : undefined
+
return
{
{/*
{type === 'autodetected' ? '(detected locally)' : type === 'default' ? '' : '(custom model)'} */}
+ {/* Settings button - only for custom or locally detected models */}
+ {(type === 'autodetected' || type === 'custom') && (
+
+
+
+ )}
+
+
{ settingsStateService.toggleModelHidden(providerName, modelName) }}
@@ -384,6 +659,13 @@ export const ModelDump = () => {
})}
+
+ {/* Model Settings Dialog */}
+
setOpenSettingsModel(null)}
+ modelInfo={openSettingsModel}
+ />
}
diff --git a/src/vs/workbench/contrib/void/common/modelCapabilities.ts b/src/vs/workbench/contrib/void/common/modelCapabilities.ts
index 79039f7b..cc2a4fce 100644
--- a/src/vs/workbench/contrib/void/common/modelCapabilities.ts
+++ b/src/vs/workbench/contrib/void/common/modelCapabilities.ts
@@ -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
-// const googleVertexSettings: VoidStaticProviderInfo = {
-// modelOptions: googleVertexModelOptions,
-// modelOptionsFallback: (modelName) => { return null }
-// }
+const googleVertexModelOptions = {
+} as const satisfies Record
+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
diff --git a/src/vs/workbench/contrib/void/common/prompt/prompts.ts b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
index d0e27fcd..14544216 100644
--- a/src/vs/workbench/contrib/void/common/prompt/prompts.ts
+++ b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
@@ -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.
diff --git a/src/vs/workbench/contrib/void/common/voidSettingsService.ts b/src/vs/workbench/contrib/void/common/voidSettingsService.ts
index ad7c6a7f..462d7899 100644
--- a/src/vs/workbench/contrib/void/common/voidSettingsService.ts
+++ b/src/vs/workbench/contrib/void/common/voidSettingsService.ts
@@ -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;
dangerousSetState(newState: VoidSettingsState): Promise;
resetState(): Promise;
@@ -182,6 +184,7 @@ const _validatedModelState = (state: Omit):
...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 });
+ }
+
diff --git a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
index 7c9e854b..43fc9a24 100644
--- a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
+++ b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
@@ -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 = {
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
diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts
index 6eb0ad7a..95b68e45 100644
--- a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts
+++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.impl.ts
@@ -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 () => {
+ // module‑level 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 | 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,
diff --git a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts
index e1c18f50..7c92d9da 100644
--- a/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts
+++ b/src/vs/workbench/contrib/void/electron-main/llmMessage/sendLLMMessage.ts
@@ -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 })