diff --git a/.voidrules b/.voidrules
index 59586971..6c655134 100644
--- a/.voidrules
+++ b/.voidrules
@@ -10,3 +10,5 @@ In typescript, do NOT cast to types if not neccessary. NEVER lazily cast to 'any
Do not add or remove semicolons to any of my files. Just go with convention and make the least number of changes.
Never modify files outside src/vs/workbench/contrib/void without consulting with the user first.
+
+All types that map from a value A to B should be called bOfA. For example, if you create a hashmap that goes from toolId to toolName, it should be called toolNameOfToolId, etc.
diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts
index eb1a6883..30f38f10 100644
--- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts
+++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts
@@ -641,7 +641,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
// 2. if tool requires approval, break from the loop, awaiting approval
- const approvalType = isBuiltInTool ? approvalTypeOfBuiltinToolName[toolName] : 'mcp-tools'
+ const approvalType = isBuiltInTool ? approvalTypeOfBuiltinToolName[toolName] : 'MCP tools'
if (approvalType) {
const autoApprove = this._settingsService.state.globalSettings.autoApprove[approvalType]
// add a tool_request because we use it for UI if a tool is loading (this should be improved in the future)
diff --git a/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts b/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts
index d8f398ac..94545c0d 100644
--- a/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts
+++ b/src/vs/workbench/contrib/void/browser/convertToLLMMessageService.ts
@@ -678,13 +678,15 @@ class ConvertToLLMMessageService extends Disposable implements IConvertToLLMMess
contextWindow,
supportsSystemMessage,
} = getModelCapabilities(providerName, modelName, overridesOfModel)
- const systemMessage = await this._generateChatMessagesSystemMessage(chatMode, specialToolFormat)
+
+ const { disableSystemMessage } = this.voidSettingsService.state.globalSettings;
+ const fullSystemMessage = await this._generateChatMessagesSystemMessage(chatMode, specialToolFormat)
+ const systemMessage = disableSystemMessage ? '' : fullSystemMessage;
const modelSelectionOptions = this.voidSettingsService.state.optionsOfModelSelection['Chat'][modelSelection.providerName]?.[modelSelection.modelName]
// Get combined AI instructions
const aiInstructions = this._getCombinedAIInstructions();
-
const isReasoningEnabled = getIsReasoningEnabledState('Chat', providerName, modelName, modelSelectionOptions, overridesOfModel)
const reservedOutputTokenSpace = getReservedOutputTokenSpace(providerName, modelName, { isReasoningEnabled, overridesOfModel })
const llmMessages = this._chatMessagesToSimpleMessages(chatMessages)
diff --git a/src/vs/workbench/contrib/void/browser/quickEditActions.ts b/src/vs/workbench/contrib/void/browser/quickEditActions.ts
index a420d8bb..63deba31 100644
--- a/src/vs/workbench/contrib/void/browser/quickEditActions.ts
+++ b/src/vs/workbench/contrib/void/browser/quickEditActions.ts
@@ -13,7 +13,7 @@ import { roundRangeToLines } from './sidebarActions.js';
import { VOID_CTRL_K_ACTION_ID } from './actionIDs.js';
import { localize2 } from '../../../../nls.js';
import { IMetricsService } from '../common/metricsService.js';
-
+import { ContextKeyExpr } from '../../../../platform/contextkey/common/contextkey.js';
export type QuickEditPropsType = {
diffareaid: number,
@@ -42,6 +42,7 @@ registerAction2(class extends Action2 {
keybinding: {
primary: KeyMod.CtrlCmd | KeyCode.KeyK,
weight: KeybindingWeight.VoidExtension,
+ when: ContextKeyExpr.deserialize('editorFocus && !terminalFocus'),
}
});
}
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 9533958f..ea24ef38 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
@@ -1617,7 +1617,7 @@ const ToolRequestAcceptRejectButtons = ({ toolName }: { toolName: ToolName }) =>
)
- const approvalType = isABuiltinToolName(toolName) ? approvalTypeOfBuiltinToolName[toolName] : 'mcp-tools'
+ const approvalType = isABuiltinToolName(toolName) ? approvalTypeOfBuiltinToolName[toolName] : 'MCP tools'
const approvalToggle = approvalType ?
: null
diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx
index d16ebefd..9ac3645c 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/void-onboarding/VoidOnboarding.tsx
@@ -100,7 +100,7 @@ const tabNames = ['Free', 'Paid', 'Local'] as const;
type TabName = typeof tabNames[number] | 'Cloud/Other';
// Data for cloud providers tab
-const cloudProviders: ProviderName[] = ['googleVertex', 'liteLLM', 'microsoftAzure', 'openAICompatible'];
+const cloudProviders: ProviderName[] = ['googleVertex', 'liteLLM', 'microsoftAzure', 'awsBedrock', 'openAICompatible'];
// Data structures for provider tabs
const providerNamesOfTab: Record = {
diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx
index 8cef3295..60294f06 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/void-settings-tsx/Settings.tsx
@@ -22,6 +22,16 @@ import { TransferEditorType, TransferFilesInfo } from '../../../extensionTransfe
import { MCPServer } from '../../../../common/mcpServiceTypes.js';
import { useMCPServiceState } from '../util/services.js';
+type Tab =
+ | 'models'
+ | 'localProviders'
+ | 'providers'
+ | 'featureOptions'
+ | 'mcp'
+ | 'general'
+ | 'all';
+
+
const ButtonLeftTextRightOption = ({ text, leftButton }: { text: string, leftButton?: React.ReactNode }) => {
return
@@ -919,66 +929,72 @@ const MCPServerComponent = ({ name, server }: { name: string, server: MCPServer
const removeUniquePrefix = (name: string) => name.split('_').slice(1).join('_')
return (
-
-
- {/* Status indicator */}
-
+
+ {/* Left side - status and name */}
+
+ {/* Status indicator */}
+
- `}>
-
- {/* Server name */}
-
{name}
-
- {/* Power toggle switch */}
-
-
mcpService.toggleServerIsOn(name, !isOn)}
- />
+ {/* Server name */}
+ {name}
+
+ {/* Right side - power toggle switch */}
+
mcpService.toggleServerIsOn(name, !isOn)}
+ />
{/* Tools section */}
-
-
- {isOn && (server.tools ?? []).length > 0 ? (
- (server.tools ?? []).map((tool: { name: string; description?: string }) => (
-
+
+ {(server.tools ?? []).length > 0 ? (
+ (server.tools ?? []).map((tool: { name: string; description?: string }) => (
+
- {removeUniquePrefix(tool.name)}
-
- ))
- ) : (
- No tools available
- )}
+ data-tooltip-id='void-tooltip'
+ data-tooltip-content={tool.description || ''}
+ data-tooltip-class-name='void-max-w-[300px]'
+ >
+ {removeUniquePrefix(tool.name)}
+
+ ))
+ ) : (
+ No tools available
+ )}
+
-
+ )}
{/* Command badge */}
{isOn && server.command && (
-
-
Command:
-
+
+
Command:
+
{server.command}
)}
{/* Error message if present */}
- {server.error && (
)}
+ {server.error && (
+
+
+
+ )}
);
};
@@ -989,31 +1005,43 @@ const MCPServersList = () => {
let content: React.ReactNode
if (mcpServiceState.error) {
- content =
+ content =
{mcpServiceState.error}
}
else {
const entries = Object.entries(mcpServiceState.mcpServerOfName)
if (entries.length === 0) {
- content =
+ content =
No servers found
}
else {
content = entries.map(([name, server]) => (
-
-
-
+
))
}
}
- return content
+ return
{content}
};
export const Settings = () => {
const isDark = useIsDark()
+ // ─── sidebar nav ──────────────────────────
+ const [selectedSection, setSelectedSection] =
+ useState
('models');
+
+ const navItems: { tab: Tab; label: string }[] = [
+ { tab: 'models', label: 'Models' },
+ { tab: 'localProviders', label: 'Local Providers' },
+ { tab: 'providers', label: 'Other Providers' },
+ { tab: 'featureOptions', label: 'Feature Options' },
+ { tab: 'general', label: 'General' },
+ { tab: 'mcp', label: 'MCP' },
+ { tab: 'all', label: 'All Settings' },
+ ];
+ const shouldShowTab = (tab: Tab) => selectedSection === 'all' || selectedSection === tab;
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
const environmentService = accessor.get('IEnvironmentService')
@@ -1088,297 +1116,378 @@ export const Settings = () => {
}
- return
-
+ return (
+
+
+ {/* ────────────── SIDEBAR ────────────── */}
-
+
+ {/* vertical tab list */}
+
+ {navItems.map(({ tab, label }) => (
+ {
+ if (tab === 'all') {
+ setSelectedSection('all');
+ window.scrollTo({ top: 0, behavior: 'smooth' });
+ } else {
+ setSelectedSection(tab);
+ }
+ }}
+ className={`
+ py-2 px-4 rounded-md text-left transition-all duration-200
+ ${selectedSection === tab
+ ? 'bg-[#0e70c0]/80 text-white font-medium shadow-sm'
+ : 'bg-void-bg-2 hover:bg-void-bg-2/80 text-void-fg-1'}
+ `}
+ >
+ {label}
+
+ ))}
+
+
-
{`Void's Settings`}
-
-
-
- {/* Models section (formerly FeaturesTab) */}
-
-
-
-
-
-
- {/* Models section (formerly FeaturesTab) */}
-
- Models
-
-
-
-
-
-
-
-
Local Providers
-
{`Void can access any model that you host locally. We automatically detect your local models by default.`}
-
-
-
-
-
-
-
-
Providers
-
{`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}
-
-
-
+ {/* ───────────── MAIN PANE ───────────── */}
+
- Feature Options
+
-
-
- {/* FIM */}
-
-
{displayInfoOfFeatureName('Autocomplete')}
-
-
- Experimental.{' '}
-
-
- Only works with FIM models.*
-
+
{`Void's Settings`}
+
+
+
+ {/* Models section (formerly FeaturesTab) */}
+
+
+
+
+
+
+ {/* All sections in flex container with gap-12 */}
+
+ {/* Models section (formerly FeaturesTab) */}
+
-
- {/* Enable Switch */}
+ {/* Local Providers section */}
+
-
-
voidSettingsService.setGlobalSetting('enableAutocomplete', newVal)}
- />
- {settingsState.globalSettings.enableAutocomplete ? 'Enabled' : 'Disabled'}
+ Local Providers
+ {`Void can access any model that you host locally. We automatically detect your local models by default.`}
+
+
+
+
+
+
+
+ {/* Other Providers section */}
+
+
+ Other Providers
+ {`Void can access models from Anthropic, OpenAI, OpenRouter, and more.`}
+
+
+
+
+
+ {/* Feature Options section */}
+
+
+ Feature Options
+
+
+
+ {/* FIM */}
+
+
{displayInfoOfFeatureName('Autocomplete')}
+
+
+ Experimental.{' '}
+
+
+ Only works with FIM models.*
+
+
+
+
+ {/* Enable Switch */}
+
+
+ voidSettingsService.setGlobalSetting('enableAutocomplete', newVal)}
+ />
+ {settingsState.globalSettings.enableAutocomplete ? 'Enabled' : 'Disabled'}
+
+
+
+ {/* Model Dropdown */}
+
+
+
+
+
+
+
+
+
+
+
+ {/* Apply */}
+
+
+
+
{displayInfoOfFeatureName('Apply')}
+
Settings that control the behavior of the Apply button.
+
+
+ {/* Sync to Chat Switch */}
+
+ voidSettingsService.setGlobalSetting('syncApplyToChat', newVal)}
+ />
+ {settingsState.globalSettings.syncApplyToChat ? 'Same as Chat model' : 'Different model'}
+
+
+ {/* Model Dropdown */}
+
+
+
+
+
+
+
+ {/* Fast Apply Method Dropdown */}
+
+
+
+
+
+
+
+
+
+
+
+ {/* Tools Section */}
+
+
Tools
+
{`Tools are functions that LLMs can call. Some tools require user approval.`}
+
+
+ {/* Auto Accept Switch */}
+
+ {[...toolApprovalTypes].map((approvalType) => {
+ return
+
+
+ })}
+
+
+
+ {/* Tool Lint Errors Switch */}
+
+
+
+ voidSettingsService.setGlobalSetting('includeToolLintErrors', newVal)}
+ />
+ {settingsState.globalSettings.includeToolLintErrors ? 'Fix lint errors' : `Fix lint errors`}
+
+
+
+
+
+
+
+
+
Editor
+
{`Settings that control the visibility of Void suggestions in the code editor.`}
+
+
+ {/* Auto Accept Switch */}
+
+
+ voidSettingsService.setGlobalSetting('showInlineSuggestions', newVal)}
+ />
+ {settingsState.globalSettings.showInlineSuggestions ? 'Show suggestions on select' : 'Show suggestions on select'}
+
+
+
+
+
- {/* Model Dropdown */}
-
-
-
+ {/* General section */}
+
+ {/* One-Click Switch section */}
+
+
+ One-Click Switch
+ {`Transfer your editor settings into Void.`}
+
+
+
+
+
+
+
+
+
+ {/* Import/Export section */}
+
+
Import/Export
+
{`Transfer Void's settings and chats in and out of Void.`}
+
-
-
-
-
-
-
-
- {/* Apply */}
-
-
-
-
{displayInfoOfFeatureName('Apply')}
-
Settings that control the behavior of the Apply button.
-
-
- {/* Sync to Chat Switch */}
-
- voidSettingsService.setGlobalSetting('syncApplyToChat', newVal)}
- />
- {settingsState.globalSettings.syncApplyToChat ? 'Same as Chat model' : 'Different model'}
- {/* Model Dropdown */}
-
-
+
+
+ {/* Built-in Settings section */}
+
+
Built-in Settings
+
{`IDE settings, keyboard settings, and theme customization.`}
+
+
+
+ { commandService.executeCommand('workbench.action.openSettings') }}>
+ General Settings
+
+ { commandService.executeCommand('workbench.action.openGlobalKeybindings') }}>
+ Keyboard Settings
+
+ { commandService.executeCommand('workbench.action.selectTheme') }}>
+ Theme Settings
+
+ { nativeHostService.showItemInFolder(environmentService.logsHome.fsPath) }}>
+ Open Logs
+
+
+
-
-
- {/* Fast Apply Method Dropdown */}
-
-
-
-
-
-
-
-
-
-
-
-
- {/* Tools Section */}
-
-
Tools
-
{`Tools are functions that LLMs can call. Some tools require user approval.`}
-
-
- {/* Auto Accept Switch */}
-
- {[...toolApprovalTypes].map((approvalType) => {
- return
-
-
- })}
-
-
-
- {/* Tool Lint Errors Switch */}
-
-
-
- voidSettingsService.setGlobalSetting('includeToolLintErrors', newVal)}
- />
- {settingsState.globalSettings.includeToolLintErrors ? 'Fix lint errors' : `Fix lint errors`}
-
-
-
-
-
-
-
-
-
Editor
-
{`Settings that control the visibility of Void suggestions in the code editor.`}
-
-
- {/* Auto Accept Switch */}
-
-
- voidSettingsService.setGlobalSetting('showInlineSuggestions', newVal)}
- />
- {settingsState.globalSettings.showInlineSuggestions ? 'Show suggestions on select' : 'Show suggestions on select'}
-
-
-
-
-
-
-
- {/* General section (formerly GeneralTab) */}
-
-
- One-Click Switch
- {`Transfer your editor settings into Void.`}
-
-
-
-
-
-
-
-
-
- {/* Import/Export section, as its own block right after One-Click Switch */}
-
-
Import/Export
-
{`Transfer Void's settings and chats in and out of Void.`}
-
-
-
-
-
-
-
-
Built-in Settings
-
{`IDE settings, keyboard settings, and theme customization.`}
-
-
-
- { commandService.executeCommand('workbench.action.openSettings') }}>
- General Settings
-
- { commandService.executeCommand('workbench.action.openGlobalKeybindings') }}>
- Keyboard Settings
-
- { commandService.executeCommand('workbench.action.selectTheme') }}>
- Theme Settings
-
- { nativeHostService.showItemInFolder(environmentService.logsHome.fsPath) }}>
- Open Logs
-
-
-
-
-
-
-
-
AI Instructions
-
-
-
+ AI Instructions
+
+
-
-
-
-
-
+
+
+
+
+ {/* --- Disable System Message Toggle --- */}
+
+
+
+ {
+ voidSettingsService.setGlobalSetting('disableSystemMessage', newValue);
+ }}
+ />
+
+ {'Disable system message'}
+
+
+
+
+ {`When disabled, Void will not include anything in the system message except for content you specified above.`}
+
+
+
+
-
-
MCP
-
-
+
+ MCP
+
+
-
-
- { await mcpService.revealMCPConfigFile() }}>
- Add MCP Server
-
-
-
+
+
+ { await mcpService.revealMCPConfigFile() }}>
+ Add MCP Server
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+ );
}
-
diff --git a/src/vs/workbench/contrib/void/common/modelCapabilities.ts b/src/vs/workbench/contrib/void/common/modelCapabilities.ts
index 4c12a2f5..ce0b5dfc 100644
--- a/src/vs/workbench/contrib/void/common/modelCapabilities.ts
+++ b/src/vs/workbench/contrib/void/common/modelCapabilities.ts
@@ -60,6 +60,12 @@ export const defaultProviderSettings = {
apiKey: '',
azureApiVersion: '2024-05-01-preview',
},
+ awsBedrock: {
+ apiKey: '',
+ region: 'us-east-1', // add region setting
+ endpoint: '', // optionally allow overriding default
+ },
+
} as const
@@ -88,6 +94,9 @@ export const defaultModelsOfProvider = {
xAI: [ // https://docs.x.ai/docs/models?cluster=us-east-1
'grok-2',
'grok-3',
+ 'grok-3-mini',
+ 'grok-3-fast',
+ 'grok-3-mini-fast'
],
gemini: [ // https://ai.google.dev/gemini-api/docs/models/gemini
'gemini-2.5-pro-exp-03-25',
@@ -115,6 +124,7 @@ export const defaultModelsOfProvider = {
'anthropic/claude-3.5-sonnet',
'deepseek/deepseek-r1',
'deepseek/deepseek-r1-zero:free',
+ 'mistralai/devstral-small:free'
// 'openrouter/quasar-alpha',
// 'google/gemini-2.5-pro-preview-03-25',
// 'mistralai/codestral-2501',
@@ -132,6 +142,7 @@ export const defaultModelsOfProvider = {
],
mistral: [ // https://docs.mistral.ai/getting-started/models/models_overview/
'codestral-latest',
+ 'devstral-small-latest',
'mistral-large-latest',
'mistral-medium-latest',
'ministral-3b-latest',
@@ -140,6 +151,7 @@ export const defaultModelsOfProvider = {
openAICompatible: [], // fallback
googleVertex: [],
microsoftAzure: [],
+ awsBedrock: [],
liteLLM: [],
@@ -267,6 +279,12 @@ const openSourceModelOptions_assumingOAICompat = {
reasoningCapabilities: false,
contextWindow: 32_000, reservedOutputTokenSpace: 4_096,
},
+ 'devstral': {
+ supportsFIM: false,
+ supportsSystemMessage: 'system-role',
+ reasoningCapabilities: false,
+ contextWindow: 131_000, reservedOutputTokenSpace: 8_192,
+ },
'openhands-lm-32b': { // https://www.all-hands.dev/blog/introducing-openhands-lm-32b----a-strong-open-coding-agent-model
supportsFIM: false,
supportsSystemMessage: 'system-role',
@@ -381,16 +399,21 @@ const extensiveModelOptionsFallback: VoidStaticProviderInfo['modelOptionsFallbac
: VoidStaticModelInfo & { modelName: string, recognizedModelName: string } => {
const opts = obj[recognizedModelName]
+ const supportsSystemMessage = opts.supportsSystemMessage === 'separated'
+ ? 'system-role'
+ : opts.supportsSystemMessage
+
return {
recognizedModelName,
modelName,
...opts,
- supportsSystemMessage: opts.supportsSystemMessage ? 'system-role' : false,
+ supportsSystemMessage: supportsSystemMessage,
cost: { input: 0, output: 0 },
downloadable: false,
...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('claude-3-5') || lower.includes('claude-3.5')) return toFallback(anthropicModelOptions, 'claude-3-5-sonnet-20241022')
@@ -417,6 +440,7 @@ const extensiveModelOptionsFallback: VoidStaticProviderInfo['modelOptionsFallbac
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('devstral')) return toFallback(openSourceModelOptions_assumingOAICompat, 'devstral')
if (lower.includes('gemma')) return toFallback(openSourceModelOptions_assumingOAICompat, 'gemma')
@@ -961,6 +985,17 @@ const mistralModelOptions = { // https://mistral.ai/products/la-plateforme#prici
supportsSystemMessage: 'system-role',
reasoningCapabilities: false,
},
+
+ 'devstral-small-latest': { //https://openrouter.ai/mistralai/devstral-small:free
+ contextWindow: 131_000,
+ reservedOutputTokenSpace: 8_192,
+ cost: { input: 0, output: 0 },
+ supportsFIM: false,
+ downloadable: { sizeGb: 14 }, //https://ollama.com/library/devstral
+ supportsSystemMessage: 'system-role',
+ reasoningCapabilities: false,
+ },
+
'ministral-8b-latest': { // ollama 'mistral'
contextWindow: 131_000,
reservedOutputTokenSpace: 4_096,
@@ -1070,6 +1105,18 @@ const microsoftAzureSettings: VoidStaticProviderInfo = {
},
}
+// ---------------- AWS BEDROCK ----------------
+const awsBedrockModelOptions = {
+} as const satisfies Record
+
+const awsBedrockSettings: VoidStaticProviderInfo = {
+ modelOptions: awsBedrockModelOptions,
+ modelOptionsFallback: (modelName) => { return null },
+ providerReasoningIOSettings: {
+ input: { includeInPayload: openAICompatIncludeInPayloadReasoning },
+ },
+}
+
// ---------------- VLLM, OLLAMA, OPENAICOMPAT (self-hosted / local) ----------------
const ollamaModelOptions = {
@@ -1136,10 +1183,19 @@ const ollamaModelOptions = {
supportsSystemMessage: 'system-role',
reasoningCapabilities: { supportsReasoning: true, canIOReasoning: false, canTurnOffReasoning: false, openSourceThinkTags: ['', ' '] },
},
+ 'devstral:latest': {
+ contextWindow: 131_000,
+ reservedOutputTokenSpace: 8_192,
+ cost: { input: 0, output: 0 },
+ downloadable: { sizeGb: 14 },
+ supportsFIM: false,
+ supportsSystemMessage: 'system-role',
+ reasoningCapabilities: false,
+ },
} as const satisfies Record
-export const ollamaRecommendedModels = ['qwen2.5-coder:1.5b', 'llama3.1', 'qwq', 'deepseek-r1'] as const satisfies (keyof typeof ollamaModelOptions)[]
+export const ollamaRecommendedModels = ['qwen2.5-coder:1.5b', 'llama3.1', 'qwq', 'deepseek-r1', 'devstral:latest'] as const satisfies (keyof typeof ollamaModelOptions)[]
const vLLMSettings: VoidStaticProviderInfo = {
@@ -1312,6 +1368,14 @@ const openRouterModelOptions_assumingOpenAICompat = {
downloadable: false,
reasoningCapabilities: false,
},
+ 'mistralai/devstral-small:free': {
+ ...openSourceModelOptions_assumingOAICompat.devstral,
+ contextWindow: 130_000,
+ reservedOutputTokenSpace: null,
+ cost: { input: 0, output: 0 },
+ downloadable: false,
+ reasoningCapabilities: false,
+ },
'qwen/qwen-2.5-coder-32b-instruct': {
...openSourceModelOptions_assumingOAICompat['qwen2.5coder'],
contextWindow: 33_000,
@@ -1392,6 +1456,7 @@ const modelSettingsOfProvider: { [providerName in ProviderName]: VoidStaticProvi
googleVertex: googleVertexSettings,
microsoftAzure: microsoftAzureSettings,
+ awsBedrock: awsBedrockSettings,
} as const
diff --git a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
index d930f5de..d5da3e17 100644
--- a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
+++ b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
@@ -18,7 +18,7 @@ export type ShallowDirectoryItem = {
}
-export const approvalTypeOfBuiltinToolName: Partial<{ [T in BuiltinToolName]?: 'edits' | 'terminal' | 'mcp-tools' }> = {
+export const approvalTypeOfBuiltinToolName: Partial<{ [T in BuiltinToolName]?: 'edits' | 'terminal' | 'MCP tools' }> = {
'create_file_or_folder': 'edits',
'delete_file_or_folder': 'edits',
'rewrite_file': 'edits',
@@ -35,7 +35,7 @@ export type ToolApprovalType = NonNullable<(typeof approvalTypeOfBuiltinToolName
export const toolApprovalTypes = new Set([
...Object.values(approvalTypeOfBuiltinToolName),
- 'mcp-tools',
+ 'MCP tools',
])
diff --git a/src/vs/workbench/contrib/void/common/voidSettingsService.ts b/src/vs/workbench/contrib/void/common/voidSettingsService.ts
index 07c893f9..e448627a 100644
--- a/src/vs/workbench/contrib/void/common/voidSettingsService.ts
+++ b/src/vs/workbench/contrib/void/common/voidSettingsService.ts
@@ -279,6 +279,8 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
// autoapprove is now an obj not a boolean (1.2.5)
if (typeof readS.globalSettings.autoApprove === 'boolean') readS.globalSettings.autoApprove = {}
+
+ if (readS.globalSettings.disableSystemMessage === undefined) readS.globalSettings.disableSystemMessage = false;
}
catch (e) {
readS = defaultState()
diff --git a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
index 62aaae65..1731fdf8 100644
--- a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
+++ b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
@@ -103,6 +103,9 @@ export const displayInfoOfProviderName = (providerName: ProviderName): DisplayIn
else if (providerName === 'microsoftAzure') {
return { title: 'Microsoft Azure OpenAI', }
}
+ else if (providerName === 'awsBedrock') {
+ return { title: 'AWS Bedrock', }
+ }
throw new Error(`descOfProviderName: Unknown provider name: "${providerName}"`)
}
@@ -120,6 +123,7 @@ export const subTextMdOfProviderName = (providerName: ProviderName): string => {
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 === '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 === 'awsBedrock') return 'Connect via a LiteLLM proxy or the AWS [Bedrock-Access-Gateway](https://github.com/aws-samples/bedrock-access-gateway). LiteLLM Bedrock setup docs are [here](https://docs.litellm.ai/docs/providers/bedrock).'
if (providerName === 'ollama') return 'Read more about custom [Endpoints here](https://github.com/ollama/ollama/blob/main/docs/faq.md#how-can-i-expose-ollama-on-my-network).'
if (providerName === 'vLLM') return 'Read more about custom [Endpoints here](https://docs.vllm.ai/en/latest/getting_started/quickstart.html#openai-compatible-server).'
if (providerName === 'lmStudio') return 'Read more about custom [Endpoints here](https://lmstudio.ai/docs/app/api/endpoints/openai).'
@@ -151,7 +155,8 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
providerName === 'mistral' ? 'api-key...' :
providerName === 'googleVertex' ? 'AIzaSy...' :
providerName === 'microsoftAzure' ? 'key-...' :
- '',
+ providerName === 'awsBedrock' ? 'key-...' :
+ '',
isPasswordField: true,
}
@@ -165,14 +170,16 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
providerName === 'googleVertex' ? 'baseURL' :
providerName === 'microsoftAzure' ? 'baseURL' :
providerName === 'liteLLM' ? 'baseURL' :
- '(never)',
+ providerName === 'awsBedrock' ? 'Endpoint' :
+ '(never)',
placeholder: providerName === 'ollama' ? defaultProviderSettings.ollama.endpoint
: providerName === 'vLLM' ? defaultProviderSettings.vLLM.endpoint
: providerName === 'openAICompatible' ? 'https://my-website.com/v1'
: providerName === 'lmStudio' ? defaultProviderSettings.lmStudio.endpoint
: providerName === 'liteLLM' ? 'http://localhost:4000'
- : '(never)',
+ : providerName === 'awsBedrock' ? 'http://localhost:4000/v1'
+ : '(never)',
}
@@ -185,7 +192,9 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
return {
title: 'Region',
placeholder: providerName === 'googleVertex' ? defaultProviderSettings.googleVertex.region
- : ''
+ : providerName === 'awsBedrock'
+ ? defaultProviderSettings.awsBedrock.region
+ : ''
}
}
else if (settingName === 'azureApiVersion') {
@@ -340,6 +349,12 @@ export const defaultSettingsOfProvider: SettingsOfProvider = {
...modelInfoOfDefaultModelNames(defaultModelsOfProvider.microsoftAzure),
_didFillInProviderSettings: undefined,
},
+ awsBedrock: { // aggregator (serves models from multiple providers)
+ ...defaultCustomSettings,
+ ...defaultProviderSettings.awsBedrock,
+ ...modelInfoOfDefaultModelNames(defaultModelsOfProvider.awsBedrock),
+ _didFillInProviderSettings: undefined,
+ },
}
@@ -434,6 +449,7 @@ export type GlobalSettings = {
showInlineSuggestions: boolean;
includeToolLintErrors: boolean;
isOnboardingComplete: boolean;
+ disableSystemMessage: boolean;
}
export const defaultGlobalSettings: GlobalSettings = {
@@ -447,6 +463,7 @@ export const defaultGlobalSettings: GlobalSettings = {
showInlineSuggestions: true,
includeToolLintErrors: true,
isOnboardingComplete: false,
+ disableSystemMessage: false,
}
export type GlobalSettingName = keyof GlobalSettings
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 5d6b43fc..74403b9f 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
@@ -122,6 +122,29 @@ const newOpenAICompatibleSDK = async ({ settingsOfProvider, providerName, includ
const options = { endpoint, apiKey: thisConfig.apiKey, apiVersion };
return new AzureOpenAI({ ...options, ...commonPayloadOpts });
}
+ else if (providerName === 'awsBedrock') {
+ /**
+ * We treat Bedrock as *OpenAI-compatible only through a proxy*:
+ * • LiteLLM default → http://localhost:4000/v1
+ * • Bedrock-Access-Gateway → https://.execute-api..amazonaws.com/openai/
+ *
+ * The native Bedrock runtime endpoint
+ * https://bedrock-runtime..amazonaws.com
+ * is **NOT** OpenAI-compatible, so we do *not* fall back to it here.
+ */
+ const { endpoint, apiKey } = settingsOfProvider.awsBedrock
+
+ // ① use the user-supplied proxy if present
+ // ② otherwise default to local LiteLLM
+ let baseURL = endpoint || 'http://localhost:4000/v1'
+
+ // Normalize: make sure we end with “/v1”
+ if (!baseURL.endsWith('/v1'))
+ baseURL = baseURL.replace(/\/+$/, '') + '/v1'
+
+ return new OpenAI({ baseURL, apiKey, ...commonPayloadOpts })
+ }
+
else if (providerName === 'deepseek') {
const thisConfig = settingsOfProvider[providerName]
@@ -906,6 +929,12 @@ export const sendLLMMessageToProviderImplementation = {
sendFIM: null,
list: null,
},
+ awsBedrock: {
+ sendChat: (params) => _sendOpenAICompatibleChat(params),
+ sendFIM: null,
+ list: null,
+ },
+
} satisfies CallFnOfProvider
diff --git a/src/vs/workbench/contrib/void/electron-main/mcpChannel.ts b/src/vs/workbench/contrib/void/electron-main/mcpChannel.ts
index 37607c8e..4db5a332 100644
--- a/src/vs/workbench/contrib/void/electron-main/mcpChannel.ts
+++ b/src/vs/workbench/contrib/void/electron-main/mcpChannel.ts
@@ -320,8 +320,7 @@ export class MCPChannel implements IServerChannel {
// handle text response
if (response.isError) {
- throw new Error(`Tool call error: ${response.content}`)
- // handle error
+ throw new Error(`Tool call error: ${returnValue.text}`)
}
// handle success