diff --git a/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx b/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx
index 6df78f20..f8e85334 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/void-command-bar-tsx/VoidCommandBar.tsx
@@ -21,6 +21,8 @@ export type VoidCommandBarProps = {
export const VoidCommandBarMain = ({ uri, editor }: VoidCommandBarProps) => {
const isDark = useIsDark()
+ if (uri?.scheme !== 'file') return null // don't show in editors that we made, they must be files
+
return
diff --git a/src/vs/workbench/contrib/void/browser/toolsService.ts b/src/vs/workbench/contrib/void/browser/toolsService.ts
index 4d89a365..cdc27fe7 100644
--- a/src/vs/workbench/contrib/void/browser/toolsService.ts
+++ b/src/vs/workbench/contrib/void/browser/toolsService.ts
@@ -103,24 +103,30 @@ const directoryResultToString = (params: ToolCallParams['list_dir'], result: Too
const validateJSON = (s: string): { [s: string]: unknown } => {
try {
const o = JSON.parse(s)
+ if (typeof o !== 'object') throw new Error()
+
+ if ('result' in o) { // openrouter sometimes wraps the result with { 'result': ... }
+ return o.result
+ }
+
return o
}
catch (e) {
- throw new Error(`Tool parameter was not a string of a valid JSON: "${s}".`)
+ throw new Error(`Invalid LLM output format: Tool parameter was not a string of a valid JSON: "${s}".`)
}
}
const validateStr = (argName: string, value: unknown) => {
- if (typeof value !== 'string') throw new Error(`Error: ${argName} must be a string.`)
+ if (typeof value !== 'string') throw new Error(`Invalid LLM output format: ${argName} must be a string.`)
return value
}
// We are NOT checking to make sure in workspace
const validateURI = (uriStr: unknown) => {
- if (typeof uriStr !== 'string') throw new Error('Provided uri must be a string.')
+ if (typeof uriStr !== 'string') throw new Error('Invalid LLM output format: Provided uri must be a string.')
const uri = URI.file(uriStr)
return uri
@@ -130,12 +136,12 @@ const validatePageNum = (pageNumberUnknown: unknown) => {
if (!pageNumberUnknown) return 1
const parsedInt = Number.parseInt(pageNumberUnknown + '')
if (!Number.isInteger(parsedInt)) throw new Error(`Page number was not an integer: "${pageNumberUnknown}".`)
- if (parsedInt < 1) throw new Error(`Specified page number must be 1 or greater: "${pageNumberUnknown}".`)
+ if (parsedInt < 1) throw new Error(`Invalid LLM output format: Specified page number must be 1 or greater: "${pageNumberUnknown}".`)
return parsedInt
}
const validateRecursiveParamStr = (paramsUnknown: unknown) => {
- if (typeof paramsUnknown !== 'string') throw new Error('Error calling tool: provided params must be a string.')
+ if (typeof paramsUnknown !== 'string') throw new Error('Invalid LLM output format: Error calling tool: provided params must be a string.')
const params = paramsUnknown
const isRecursive = params.includes('r')
return isRecursive
diff --git a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
index a4dbabbf..0b6f7ef3 100644
--- a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
+++ b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
@@ -10,7 +10,6 @@ export type InternalToolInfo = {
params: {
[paramName: string]: { type: string, description: string | undefined } // name -> type
},
- required: string[], // required paramNames
}
@@ -33,7 +32,7 @@ export type ResolveReason = { type: 'toofull' | 'timeout' | 'bgtask' } | { type:
const paginationHelper = {
desc: `Very large results may be paginated (indicated in the result). Pagination fails gracefully if out of bounds or invalid page number.`,
- param: { pageNumber: { type: 'number', description: 'The page number (optional, default is 1).' }, }
+ param: { pageNumber: { type: 'number', description: 'The page number (default is the first page = 1).' }, }
} as const
export const voidTools = {
@@ -46,7 +45,6 @@ export const voidTools = {
uri: { type: 'string', description: undefined },
...paginationHelper.param,
},
- required: ['uri'],
},
list_dir: {
@@ -56,7 +54,6 @@ export const voidTools = {
uri: { type: 'string', description: undefined },
...paginationHelper.param,
},
- required: ['uri'],
},
pathname_search: {
@@ -66,7 +63,6 @@ export const voidTools = {
query: { type: 'string', description: undefined },
...paginationHelper.param,
},
- required: ['query'],
},
text_search: {
@@ -76,7 +72,6 @@ export const voidTools = {
query: { type: 'string', description: undefined },
...paginationHelper.param,
},
- required: ['query'],
},
// --- editing (create/delete) ---
@@ -87,7 +82,6 @@ export const voidTools = {
params: {
uri: { type: 'string', description: undefined },
},
- required: ['uri'],
},
delete_uri: {
@@ -97,7 +91,6 @@ export const voidTools = {
uri: { type: 'string', description: undefined },
params: { type: 'string', description: 'Return -r here to delete this URI and all descendants (if applicable). Default is the empty string.' }
},
- required: ['uri', 'params'],
},
edit: { // APPLY TOOL
@@ -107,7 +100,6 @@ export const voidTools = {
uri: { type: 'string', description: undefined },
changeDescription: { type: 'string', description: editToolDesc_toolDescription } // long description here
},
- required: ['uri', 'changeDescription'],
},
terminal_command: {
@@ -116,9 +108,8 @@ export const voidTools = {
params: {
command: { type: 'string', description: 'The terminal command to execute.' },
waitForCompletion: { type: 'string', description: `Whether or not to await the command to complete and get the final result. Default is true. Make this value false when you want a command to run indefinitely without waiting for it.` },
- terminalId: { type: 'string', description: 'Optional (if provided, value must be an integer >= 1). This is the ID of the terminal instance to execute the command in. The primary purpose of this is to start a new terminal for background processes or tasks that run indefinitely (e.g. if you want to run a server locally). Fails gracefully if a terminal ID does not exist, by creating a new terminal instance. Defaults to the preferred terminal ID.' },
+ terminalId: { type: 'string', description: 'Optional (value must be an integer >= 1, or empty which will go with the default). This is the ID of the terminal instance to execute the command in. The primary purpose of this is to start a new terminal for background processes or tasks that run indefinitely (e.g. if you want to run a server locally). Fails gracefully if a terminal ID does not exist, by creating a new terminal instance. Defaults to the preferred terminal ID.' },
},
- required: ['command'],
},
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 27e99357..9e82f58c 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
@@ -36,17 +36,19 @@ const invalidApiKeyMessage = (providerName: ProviderName) => `Invalid ${displayI
// ------------ OPENAI-COMPATIBLE (HELPERS) ------------
const toOpenAICompatibleTool = (toolInfo: InternalToolInfo) => {
- const { name, description, params, required } = toolInfo
+ const { name, description, params } = toolInfo
return {
type: 'function',
function: {
name: name,
+ strict: true, // strict mode - https://platform.openai.com/docs/guides/function-calling?api-mode=chat
description: description,
parameters: {
type: 'object',
properties: params,
- required: required,
- }
+ required: Object.keys(params), // in strict mode, all params are required and additionalProperties is false
+ additionalProperties: false,
+ },
}
} satisfies OpenAI.Chat.Completions.ChatCompletionTool
}
@@ -283,15 +285,15 @@ const _openaiCompatibleList = async ({ onSuccess: onSuccess_, onError: onError_,
// ------------ ANTHROPIC ------------
const toAnthropicTool = (toolInfo: InternalToolInfo) => {
- const { name, description, params, required } = toolInfo
+ const { name, description, params } = toolInfo
return {
name: name,
description: description,
input_schema: {
type: 'object',
properties: params,
- required: required,
- }
+ required: Object.keys(params),
+ },
} satisfies Anthropic.Messages.Tool
}