strict:true

This commit is contained in:
Andrew Pareles 2025-03-20 07:24:57 -07:00
parent cffe053226
commit 07e995fc2f
4 changed files with 23 additions and 22 deletions

View file

@ -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 <div
className={`@@void-scope ${isDark ? 'dark' : ''}`}
>

View file

@ -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

View file

@ -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'],
},

View file

@ -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
}