From 07e995fc2f80f79ccbe5a6337c5c9695f228104c Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Thu, 20 Mar 2025 07:24:57 -0700 Subject: [PATCH] strict:true --- .../src/void-command-bar-tsx/VoidCommandBar.tsx | 2 ++ .../contrib/void/browser/toolsService.ts | 16 +++++++++++----- .../contrib/void/common/toolsServiceTypes.ts | 13 ++----------- .../llmMessage/sendLLMMessage.impl.ts | 14 ++++++++------ 4 files changed, 23 insertions(+), 22 deletions(-) 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 }