diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx
index 2507f796..acf731f4 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx
@@ -304,12 +304,6 @@ const RenderToken = ({ token, inPTag, codeURI, chatMessageLocation, tokenIdx, ..
return
{contents}
}
- if (t.type === "html") {
- const contents = t.raw
- if (inPTag) return {contents}
- return {contents}
- }
-
if (t.type === "text" || t.type === "escape") {
return {t.raw}
}
@@ -324,7 +318,7 @@ const RenderToken = ({ token, inPTag, codeURI, chatMessageLocation, tokenIdx, ..
onClick={() => { window.open(t.href) }}
href={t.href}
title={t.title ?? undefined}
- className='underline cursor-pointer hover:brightness-90 transition-all duration-200'
+ className='underline cursor-pointer hover:brightness-90 transition-all duration-200 text-void-fg-2'
>
{t.text}
@@ -349,7 +343,7 @@ const RenderToken = ({ token, inPTag, codeURI, chatMessageLocation, tokenIdx, ..
}
// inline code
- if (t.type === "codespan") {
+ if (t.type === "codespan" || t.type === "html") {
if (options.isLinkDetectionEnabled && chatMessageLocation) {
return void;
- isOpen?: boolean,
+ isOpen?: boolean;
+ className?: string;
}
const ToolHeaderWrapper = ({
@@ -679,7 +679,7 @@ const ToolHeaderWrapper = ({
isOpen,
isRejected,
className, // applies to the main content
-}: ToolHeaderParams & { className?: string }) => {
+}: ToolHeaderParams) => {
const [isOpen_, setIsOpen] = useState(false);
const isExpanded = isOpen !== undefined ? isOpen : isOpen_
@@ -1176,7 +1176,8 @@ const titleOfToolName = {
'create_file_or_folder': { done: `Created`, proposed: `Create`, running: loadingTitleWrapper(`Creating`) },
'delete_file_or_folder': { done: `Deleted`, proposed: `Delete`, running: loadingTitleWrapper(`Deleting`) },
'edit_file': { done: `Edited file`, proposed: 'Edit file', running: loadingTitleWrapper('Editing file') },
- 'run_terminal_command': { done: `Ran terminal`, proposed: 'Run terminal', running: loadingTitleWrapper('Running terminal') }
+ 'run_terminal_command': { done: `Ran terminal`, proposed: 'Run terminal', running: loadingTitleWrapper('Running terminal') },
+ 'read_lint_errors': { done: `Read lint errors`, proposed: 'Read lint errors', running: loadingTitleWrapper('Reading lint errors') },
} as const satisfies Record
const getTitle = (toolMessage: Pick): React.ReactNode => {
@@ -1343,6 +1344,15 @@ const EditToolChildren = ({ uri, changeDescription }: { uri: URI | undefined, ch
}
+
+const LintErrorChildren = ({ lintErrors }: { lintErrors: LintErrorItem[] }) => {
+ return
+ {lintErrors.map((error, i) => (
+
Lines {error.startLineNumber}-{error.endLineNumber}: {error.message}
+ ))}
+
+}
+
const EditToolLintErrors = ({ lintErrors }: { lintErrors: LintErrorItem[] }) => {
if (lintErrors.length === 0) return null;
@@ -1352,11 +1362,7 @@ const EditToolLintErrors = ({ lintErrors }: { lintErrors: LintErrorItem[] }) =>
return (
{ setIsOpen(o => !o) }} >
-
- {lintErrors.map((error, i) => (
-
Lines {error.startLineNumber}-{error.endLineNumber}: {error.message}
- ))}
-
+
@@ -1427,6 +1433,13 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper,
const isError = toolMessage.type === 'tool_error'
const componentParams: ToolHeaderParams = { title, desc1, isError, icon }
+ if (toolMessage.params.startLine !== null || toolMessage.params.endLine !== null) {
+ const start = toolMessage.params.startLine === null ? `start` : `${toolMessage.params.startLine}`
+ const end = toolMessage.params.endLine === null ? `end` : `${toolMessage.params.endLine}`
+ const addStr = `(${start}-${end})`
+ componentParams.title += ` ${addStr}`
+ }
+
if (toolMessage.type === 'success') {
const { params, result } = toolMessage
componentParams.onClick = () => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }
@@ -1626,6 +1639,47 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper,
}
},
+ 'read_lint_errors': {
+ resultWrapper: ({ toolMessage }) => {
+ const accessor = useAccessor()
+ const commandService = accessor.get('ICommandService')
+
+ const title = getTitle(toolMessage)
+
+ const { uri } = toolMessage.params ?? {}
+ const desc1 = uri ? getBasename(uri.fsPath) : '';
+ const icon = null
+
+ if (toolMessage.type === 'tool_request') return null
+ if (toolMessage.type === 'rejected') return null // will never happen, not rejectable
+ if (toolMessage.type === 'running_now') return null // do not show running
+
+ const isError = toolMessage.type === 'tool_error'
+ const componentParams: ToolHeaderParams = { title, desc1, isError, icon }
+
+ if (toolMessage.type === 'success') {
+ const { params, result } = toolMessage
+ componentParams.onClick = () => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }
+ if (result.lintErrors)
+ componentParams.children =
+ else
+ componentParams.children = `No lint errors found.`
+
+ }
+ else if (toolMessage.type === 'tool_error') {
+ const { params, result } = toolMessage
+ if (params) componentParams.desc2 =
+ componentParams.children =
+
+ {result}
+
+
+ }
+
+ return
+ },
+ },
+
// ---
'create_file_or_folder': {
diff --git a/src/vs/workbench/contrib/void/common/modelCapabilities.ts b/src/vs/workbench/contrib/void/common/modelCapabilities.ts
index d1b06031..6be9b608 100644
--- a/src/vs/workbench/contrib/void/common/modelCapabilities.ts
+++ b/src/vs/workbench/contrib/void/common/modelCapabilities.ts
@@ -51,11 +51,14 @@ export const defaultProviderSettings = {
export const defaultModelsOfProvider = {
openAI: [ // https://platform.openai.com/docs/models/gp
+ 'gpt-4.1',
+ 'gpt-4.1-mini',
+ 'gpt-4.1-nano',
'o3-mini',
- 'o1',
- 'o1-mini',
- 'gpt-4o',
- 'gpt-4o-mini',
+ // 'o1',
+ // 'o1-mini',
+ // 'gpt-4o',
+ // 'gpt-4o-mini',
],
anthropic: [ // https://docs.anthropic.com/en/docs/about-claude/models
'claude-3-7-sonnet-latest',
@@ -344,12 +347,16 @@ const extensiveModelFallback: VoidStaticProviderInfo['modelOptionsFallback'] = (
if (lower.includes('quasar') || lower.includes('quaser')) return toFallback({ ...openSourceModelOptions_assumingOAICompat['quasar'] })
+ if (lower.includes('gpt') && lower.includes('mini') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions['gpt-4.1-mini'])
+ if (lower.includes('gpt') && lower.includes('nano') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions['gpt-4.1-nano'])
+ if (lower.includes('gpt') && (lower.includes('4.1') || lower.includes('4-1'))) return toFallback(openAIModelOptions['gpt-4.1'])
+
if (lower.includes('4o') && lower.includes('mini')) return toFallback(openAIModelOptions['gpt-4o-mini'])
if (lower.includes('4o')) return toFallback(openAIModelOptions['gpt-4o'])
+
if (lower.includes('o1') && lower.includes('mini')) return toFallback(openAIModelOptions['o1-mini'])
if (lower.includes('o1')) return toFallback(openAIModelOptions['o1'])
if (lower.includes('o3') && lower.includes('mini')) return toFallback(openAIModelOptions['o3-mini'])
- // if (lower.includes('o3')) return toFallback(openAIModelOptions['o3'])
if (Object.keys(openSourceModelOptions_assumingOAICompat).map(k => k.toLowerCase()).includes(lower))
return toFallback(openSourceModelOptions_assumingOAICompat[lower as keyof typeof openSourceModelOptions_assumingOAICompat])
@@ -444,6 +451,33 @@ const anthropicSettings: VoidStaticProviderInfo = {
// ---------------- OPENAI ----------------
const openAIModelOptions = { // https://platform.openai.com/docs/pricing
+ 'gpt-4.1': {
+ contextWindow: 1_047_576,
+ maxOutputTokens: 32_768,
+ cost: { input: 2.00, output: 8.00, cache_read: 0.50 },
+ downloadable: false,
+ supportsFIM: false,
+ supportsSystemMessage: 'developer-role',
+ reasoningCapabilities: false,
+ },
+ 'gpt-4.1-mini': {
+ contextWindow: 1_047_576,
+ maxOutputTokens: 32_768,
+ cost: { input: 0.40, output: 1.60, cache_read: 0.10 },
+ downloadable: false,
+ supportsFIM: false,
+ supportsSystemMessage: 'developer-role',
+ reasoningCapabilities: false,
+ },
+ 'gpt-4.1-nano': {
+ contextWindow: 1_047_576,
+ maxOutputTokens: 32_768,
+ cost: { input: 0.10, output: 0.40, cache_read: 0.03 },
+ downloadable: false,
+ supportsFIM: false,
+ supportsSystemMessage: 'developer-role',
+ reasoningCapabilities: false,
+ },
'o1': {
contextWindow: 128_000,
maxOutputTokens: 100_000,
diff --git a/src/vs/workbench/contrib/void/common/prompt/prompts.ts b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
index c3e910dc..03264665 100644
--- a/src/vs/workbench/contrib/void/common/prompt/prompts.ts
+++ b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
@@ -241,8 +241,8 @@ ${availableXMLToolsStr(tools)}`)
const toolCallXMLGuidelines = (`\
Tool calling details:
- Once you write a tool call, you must STOP and WAIT for the result.
+- To call a tool, write its name and parameters in one of the XML formats specified above at the BOTTOM of your response.
- All parameters are REQUIRED unless noted otherwise.
-- To call a tool, write its name and parameters in one of the XML formats specified above.
- You are only allowed to output ONE tool call, and it must be at the END of your response.
- Your tool call will be executed immediately, and the results will appear in the following user message.`)
diff --git a/src/vs/workbench/contrib/void/common/voidSettingsService.ts b/src/vs/workbench/contrib/void/common/voidSettingsService.ts
index ad237922..09be5a02 100644
--- a/src/vs/workbench/contrib/void/common/voidSettingsService.ts
+++ b/src/vs/workbench/contrib/void/common/voidSettingsService.ts
@@ -71,8 +71,8 @@ export interface IVoidSettingsService {
-const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], options: { existingModels: VoidStatefulModelInfo[] }) => {
- const { existingModels } = options
+const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], options: { existingModels: VoidStatefulModelInfo[], didAutoDetect: boolean }) => {
+ const { existingModels, didAutoDetect } = options
const existingModelsMap: Record = {}
for (const existingModel of existingModels) {
@@ -82,7 +82,7 @@ const _updatedModelsAfterDefaultModelsChange = (defaultModelNames: string[], opt
const newDefaultModels = defaultModelNames.map((modelName, i) => ({
modelName,
isDefault: true,
- isAutodetected: true,
+ isAutodetected: didAutoDetect,
isHidden: !!existingModelsMap[modelName]?.isHidden,
}))
@@ -101,7 +101,30 @@ export const modelFilterOfFeatureName: { [featureName in FeatureName]: { filter:
}
-const _validatedModelState = (state: Omit) => {
+const _stateWithUpdatedDefaultModels = (state: VoidSettingsState): VoidSettingsState => {
+ let newSettingsOfProvider = state.settingsOfProvider
+
+ // recompute default models
+ for (const providerName of providerNames) {
+ const defaultModels = defaultSettingsOfProvider[providerName]?.models ?? []
+ const currentModels = newSettingsOfProvider[providerName]?.models ?? []
+ const defaultModelNames = defaultModels.map(m => m.modelName)
+ const newModels = _updatedModelsAfterDefaultModelsChange(defaultModelNames, { existingModels: currentModels, didAutoDetect: false })
+ newSettingsOfProvider = {
+ ...newSettingsOfProvider,
+ [providerName]: {
+ ...newSettingsOfProvider[providerName],
+ models: newModels,
+ },
+ }
+ }
+ return {
+ ...state,
+ settingsOfProvider: newSettingsOfProvider,
+ }
+}
+
+const _validatedModelState = (state: Omit): VoidSettingsState => {
let newSettingsOfProvider = state.settingsOfProvider
@@ -222,8 +245,10 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
}
// the stored data structure might be outdated, so we need to update it here
- const finalState = readS
- this.state = _validatedModelState(finalState);
+ this.state = readS
+ this.state = _stateWithUpdatedDefaultModels(this.state)
+ this.state = _validatedModelState(this.state);
+
this._resolver();
this._onDidChangeState.fire();
@@ -353,7 +378,7 @@ class VoidSettingsService extends Disposable implements IVoidSettingsService {
const { models } = this.state.settingsOfProvider[providerName]
const oldModelNames = models.map(m => m.modelName)
- const newModels = _updatedModelsAfterDefaultModelsChange(autodetectedModelNames, { existingModels: models })
+ const newModels = _updatedModelsAfterDefaultModelsChange(autodetectedModelNames, { existingModels: models, didAutoDetect: true })
this.setSettingOfProvider(providerName, 'models', newModels)
// if the models changed, log it
diff --git a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
index 2d2b3c03..f126cdcf 100644
--- a/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
+++ b/src/vs/workbench/contrib/void/common/voidSettingsTypes.ts
@@ -150,7 +150,7 @@ export const displayInfoOfSettingName = (providerName: ProviderName, settingName
providerName === 'groq' ? 'Get your [API Key here](https://console.groq.com/keys).' :
providerName === 'xAI' ? 'Get your [API Key here](https://console.x.ai).' :
providerName === 'mistral' ? 'Get your [API Key here](https://console.mistral.ai/api-keys).' :
- providerName === 'openAICompatible' ? undefined :
+ providerName === 'openAICompatible' ? `Use any OpenAI-compatible endpoint (LM Studio, LiteLM, etc).` :
'',
isPasswordField: true,
}