@@ -590,7 +604,7 @@ const VoidOnboardingContent = () => {
{/* Slice of Void image */}
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 4359afa5..7e07184f 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
@@ -8,7 +8,7 @@ import { ProviderName, SettingName, displayInfoOfSettingName, providerNames, Voi
import ErrorBoundary from '../sidebar-tsx/ErrorBoundary.js'
import { VoidButtonBgDarken, VoidCustomDropdownBox, VoidInputBox2, VoidSimpleInputBox, VoidSwitch } from '../util/inputs.js'
import { useAccessor, useIsDark, useRefreshModelListener, useRefreshModelState, useSettingsState } from '../util/services.js'
-import { X, RefreshCw, Loader2, Check, } from 'lucide-react'
+import { X, RefreshCw, Loader2, Check, Asterisk } from 'lucide-react'
import { URI } from '../../../../../../../base/common/uri.js'
import { env } from '../../../../../../../base/common/process.js'
import { ModelDropdown } from './ModelDropdown.js'
@@ -147,7 +147,7 @@ const AddButton = ({ disabled, text = 'Add', ...props }: { disabled?: boolean, t
return
@@ -206,7 +206,7 @@ export const AddModelInputBox = ({ providerName: permanentProviderName, classNam
const numModels = providerName === null ? 0 : settingsState.settingsOfProvider[providerName].models.length
if (showCheckmark) {
- return
}
if (!isOpen) {
@@ -339,6 +339,13 @@ export const ModelDump = () => {
: 'Disabled'
)
+
+ const detailAboutModel = type === 'autodetected' ?
+
{
{/* left part is width:full */}
{isNewProviderName ? providerTitle : ''}
- {modelName}
+ {modelName}{detailAboutModel}
{/* right part is anything that fits */}
{
// : (isHidden ? `'${modelName}' won't appear in dropdowns` : ``)
// }
>
- {type === 'autodetected' ? '(detected locally)' : type === 'default' ? '' : '(custom model)'}
+
+
+ {/* {type === 'autodetected' ? '(detected locally)' : type === 'default' ? '' : '(custom model)'} */}
{
- if (!currentSelections) return null
-
- for (let i = 0; i < currentSelections.length; i += 1) {
- const s = currentSelections[i]
-
- if (s.uri.fsPath !== newSelection.uri.fsPath) continue
-
- if (s.type === 'File' && newSelection.type === 'File') {
- return i
- }
- if (s.type === 'CodeSelection' && newSelection.type === 'CodeSelection') {
- if (s.uri.fsPath !== newSelection.uri.fsPath) continue
- // if there's any collision return true
- const [oldStart, oldEnd] = s.range
- const [newStart, newEnd] = newSelection.range
- if (oldStart !== newStart || oldEnd !== newEnd) continue
- return i
- }
- if (s.type === 'Folder' && newSelection.type === 'Folder') {
- return i
- }
- }
- return null
-}
export const roundRangeToLines = (range: IRange | null | undefined, options: { emptySelectionBehavior: 'null' | 'line' }) => {
if (!range)
@@ -104,8 +79,6 @@ registerAction2(class extends Action2 {
})
-
-
// Action: when press ctrl+L, show the sidebar chat and add to the selection
const VOID_ADD_SELECTION_TO_SIDEBAR_ACTION_ID = 'void.sidebar.select'
registerAction2(class extends Action2 {
@@ -147,36 +120,9 @@ registerAction2(class extends Action2 {
state: { wasAddedAsCurrentFile: false }
}
- // update the staging selections
const chatThreadService = accessor.get(IChatThreadService)
- const focusedMessageIdx = chatThreadService.getCurrentFocusedMessageIdx()
-
- // set the selections to the proper value
- let selections: StagingSelectionItem[] = []
- let setSelections = (s: StagingSelectionItem[]) => { }
-
- if (focusedMessageIdx === undefined) {
- selections = chatThreadService.getCurrentThreadState().stagingSelections
- setSelections = (s: StagingSelectionItem[]) => chatThreadService.setCurrentThreadState({ stagingSelections: s })
- } else {
- selections = chatThreadService.getCurrentMessageState(focusedMessageIdx).stagingSelections
- setSelections = (s) => chatThreadService.setCurrentMessageState(focusedMessageIdx, { stagingSelections: s })
- }
-
- // if matches with existing selection, overwrite (since text may change)
- const idx = findStagingSelectionIndex(selections, newSelection)
- if (idx !== null && idx !== -1) {
- setSelections([
- ...selections!.slice(0, idx),
- newSelection,
- ...selections!.slice(idx + 1, Infinity)
- ])
- }
- // if no match, add it
- else {
- setSelections([...(selections ?? []), newSelection])
- }
+ chatThreadService.addNewStagingSelection(newSelection)
}
});
diff --git a/src/vs/workbench/contrib/void/browser/toolsService.ts b/src/vs/workbench/contrib/void/browser/toolsService.ts
index ffd74a46..188bb658 100644
--- a/src/vs/workbench/contrib/void/browser/toolsService.ts
+++ b/src/vs/workbench/contrib/void/browser/toolsService.ts
@@ -11,7 +11,6 @@ import { ITerminalToolService } from './terminalToolService.js'
import { LintErrorItem, ToolCallParams, ToolResultType } from '../common/toolsServiceTypes.js'
import { IVoidModelService } from '../common/voidModelService.js'
import { EndOfLinePreference } from '../../../../editor/common/model.js'
-import { basename } from '../../../../base/common/path.js'
import { IVoidCommandBarService } from './voidCommandBarService.js'
import { computeDirectoryTree1Deep, IDirectoryStrService, stringifyDirectoryTree1Deep } from './directoryStrService.js'
import { IMarkerService, MarkerSeverity } from '../../../../platform/markers/common/markers.js'
@@ -38,7 +37,8 @@ const isFalsy = (u: unknown) => {
}
const validateStr = (argName: string, value: unknown) => {
- if (typeof value !== 'string') throw new Error(`Invalid LLM output format: ${argName} must be a string, but it's a ${typeof value}. Value: ${value}.`)
+ if (value === null) throw new Error(`Invalid LLM output: ${argName} was null.`)
+ if (typeof value !== 'string') throw new Error(`Invalid LLM output format: ${argName} must be a string, but its type is "${typeof value}". Full value: ${JSON.stringify(value)}.`)
return value
}
@@ -46,7 +46,8 @@ const validateStr = (argName: string, value: unknown) => {
// We are NOT checking to make sure in workspace
// TODO!!!! check to make sure folder/file exists
const validateURI = (uriStr: unknown) => {
- if (typeof uriStr !== 'string') throw new Error(`Invalid LLM output format: Provided uri must be a string, but it's a ${typeof uriStr}. Value: ${uriStr}.`)
+ if (uriStr === null) throw new Error(`Invalid LLM output: uri was null.`)
+ if (typeof uriStr !== 'string') throw new Error(`Invalid LLM output format: Provided uri must be a string, but it's a(n) ${typeof uriStr}. Full value: ${JSON.stringify(uriStr)}.`)
const uri = URI.file(uriStr)
return uri
}
@@ -234,11 +235,18 @@ export class ToolsService implements IToolsService {
return { uri, isRecursive, isFolder }
},
- edit_file: (params: RawToolParamsObj) => {
- const { uri: uriStr, change_diff: changeDiffUnknown } = params
+ rewrite_file: (params: RawToolParamsObj) => {
+ const { uri: uriStr, new_content: newContentUnknown } = params
const uri = validateURI(uriStr)
- const changeDiff = validateStr('changeDiff', changeDiffUnknown)
- return { uri, changeDiff }
+ const newContent = validateStr('newContent', newContentUnknown)
+ return { uri, newContent }
+ },
+
+ edit_file: (params: RawToolParamsObj) => {
+ const { uri: uriStr, search_replace_blocks: searchReplaceBlocksUnknown } = params
+ const uri = validateURI(uriStr)
+ const searchReplaceBlocks = validateStr('searchReplaceBlocks', searchReplaceBlocksUnknown)
+ return { uri, searchReplaceBlocks }
},
// ---
@@ -310,6 +318,7 @@ export class ToolsService implements IToolsService {
const query = queryBuilder.file(workspaceContextService.getWorkspace().folders.map(f => f.uri), {
filePattern: queryStr,
includePattern: includePattern ?? undefined,
+ sortByScore: true, // makes results 10x better
})
const data = await searchService.fileSearch(query, CancellationToken.None)
@@ -385,45 +394,45 @@ export class ToolsService implements IToolsService {
return { result: {} }
},
- edit_file: async ({ uri, changeDiff }) => {
+ rewrite_file: async ({ uri, newContent }) => {
await voidModelService.initializeModel(uri)
if (this.commandBarService.getStreamState(uri) === 'streaming') {
throw new Error(`Another LLM is currently making changes to this file. Please stop streaming for now and ask the user to resume later.`)
}
- const opts = {
- uri,
- applyStr: changeDiff,
- from: 'ClickApply',
- startBehavior: 'keep-conflicts',
- } as const
+ editCodeService.instantlyApplyNewContent({ uri, newContent })
+ // at end, get lint errors
+ const lintErrorsPromise = Promise.resolve().then(async () => {
+ await timeout(2000)
+ const { lintErrors } = this._getLintErrors(uri)
+ return { lintErrors }
+ })
+ return { result: lintErrorsPromise }
+ },
- await editCodeService.callBeforeStartApplying(opts)
- const res = editCodeService.startApplying(opts)
- if (!res) throw new Error(`The Apply model did not start running on ${basename(uri.fsPath)}. Please try again.`)
- const [diffZoneURI, applyDonePromise] = res
-
- const interruptTool = () => { // must reject the applyPromiseDone promise
- editCodeService.interruptURIStreaming({ uri: diffZoneURI })
+ edit_file: async ({ uri, searchReplaceBlocks }) => {
+ await voidModelService.initializeModel(uri)
+ if (this.commandBarService.getStreamState(uri) === 'streaming') {
+ throw new Error(`Another LLM is currently making changes to this file. Please stop streaming for now and ask the user to resume later.`)
}
+ console.log('aaaa', searchReplaceBlocks)
+ editCodeService.instantlyApplySearchReplaceBlocks({ uri, searchReplaceBlocks })
// at end, get lint errors
- const lintErrorsPromise = applyDonePromise.then(async () => {
+ const lintErrorsPromise = Promise.resolve().then(async () => {
await timeout(2000)
const { lintErrors } = this._getLintErrors(uri)
return { lintErrors }
})
- return { result: lintErrorsPromise, interruptTool }
+ return { result: lintErrorsPromise }
},
// ---
run_command: async ({ command, cwd, terminalId }) => {
const { resPromise, interrupt } = await this.terminalToolService.runCommand(command, { type: 'ephemeral', cwd, terminalId })
- console.log('qqq', interrupt)
return { result: resPromise, interruptTool: interrupt }
},
run_persistent_command: async ({ command, persistentTerminalId }) => {
const { resPromise, interrupt } = await this.terminalToolService.runCommand(command, { type: 'persistent', persistentTerminalId })
- console.log('qqq', interrupt)
return { result: resPromise, interruptTool: interrupt }
},
open_persistent_terminal: async ({ cwd }) => {
@@ -496,6 +505,15 @@ export class ToolsService implements IToolsService {
return `Change successfully made to ${params.uri.fsPath}.${lintErrsString}`
},
+ rewrite_file: (params, result) => {
+ const lintErrsString = (
+ this.voidSettingsService.state.globalSettings.includeToolLintErrors ?
+ (result.lintErrors ? ` Lint errors found after change:\n${stringifyLintErrors(result.lintErrors)}.\nIf this is related to a change made while calling this tool, you might want to fix the error.`
+ : ` No lint errors found.`)
+ : '')
+
+ return `Change successfully made to ${params.uri.fsPath}.${lintErrsString}`
+ },
run_command: (params, result) => {
const { resolveReason, result: result_, } = result
// success
diff --git a/src/vs/workbench/contrib/void/common/prompt/prompts.ts b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
index 61aeacc1..f08f41bc 100644
--- a/src/vs/workbench/contrib/void/common/prompt/prompts.ts
+++ b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
@@ -34,6 +34,94 @@ export const MAX_TERMINAL_BG_COMMAND_TIME = 5
export const MAX_PREFIX_SUFFIX_CHARS = 20_000
+export const ORIGINAL = `<<<<<<< ORIGINAL`
+export const DIVIDER = `=======`
+export const FINAL = `>>>>>>> UPDATED`
+
+
+
+const searchReplaceBlockTemplate = `\
+${ORIGINAL}
+// ... original code goes here
+${DIVIDER}
+// ... final code goes here
+${FINAL}
+
+${ORIGINAL}
+// ... original code goes here
+${DIVIDER}
+// ... final code goes here
+${FINAL}`
+
+
+
+
+const createSearchReplaceBlocks_systemMessage = `\
+You are a coding assistant that takes in a diff, and outputs SEARCH/REPLACE code blocks to implement the change(s) in the diff.
+The diff will be labeled \`DIFF\` and the original file will be labeled \`ORIGINAL_FILE\`.
+
+Format your SEARCH/REPLACE blocks as follows:
+${tripleTick[0]}
+${searchReplaceBlockTemplate}
+${tripleTick[1]}
+
+1. Your SEARCH/REPLACE block(s) must implement the diff EXACTLY. Do NOT leave anything out.
+
+2. You are allowed to output multiple SEARCH/REPLACE blocks to implement the change.
+
+3. Assume any comments in the diff are PART OF THE CHANGE. Include them in the output.
+
+4. Your output should consist ONLY of SEARCH/REPLACE blocks. Do NOT output any text or explanations before or after this.
+
+5. The ORIGINAL code in each SEARCH/REPLACE block must EXACTLY match lines in the original file. Do not add or remove any whitespace, comments, or modifications from the original code.
+
+6. Each ORIGINAL text must be large enough to uniquely identify the change in the file. However, bias towards writing as little as possible.
+
+7. Each ORIGINAL text must be DISJOINT from all other ORIGINAL text.
+
+## EXAMPLE 1
+DIFF
+${tripleTick[0]}
+// ... existing code
+let x = 6.5
+// ... existing code
+${tripleTick[1]}
+
+ORIGINAL_FILE
+${tripleTick[0]}
+let w = 5
+let x = 6
+let y = 7
+let z = 8
+${tripleTick[1]}
+
+ACCEPTED OUTPUT
+${tripleTick[0]}
+${ORIGINAL}
+let x = 6
+${DIVIDER}
+let x = 6.5
+${FINAL}
+${tripleTick[1]}`
+
+
+const replaceTool_description = `\
+A string of SEARCH/REPLACE block(s) which will be applied to the given file.
+Your SEARCH/REPLACE blocks string must be formatted as follows:
+${searchReplaceBlockTemplate}
+
+## Guidelines:
+
+1. You are encouraged to output multiple changes whenever possible.
+
+2. The ORIGINAL code in each SEARCH/REPLACE block must EXACTLY match lines in the original file. Do not add or remove any whitespace or comments from the original code.
+
+3. Each ORIGINAL text must be large enough to uniquely identify the change. However, bias towards writing as little as possible.
+
+4. Each ORIGINAL text must be DISJOINT from all other ORIGINAL text.
+
+5. This field is a STRING (not an array).`
+
// ======================================================== tools ========================================================
const changesExampleContent = `\
@@ -45,7 +133,7 @@ const changesExampleContent = `\
// {{change 3}}
// ... existing code ...`
-const editToolDiffExample = `\
+const editToolDescriptionExample = `\
${tripleTick[0]}
${changesExampleContent}
${tripleTick[1]}`
@@ -76,6 +164,7 @@ const paginationParam = {
} as const
+
const terminalDescHelper = `You can use this tool to run any command: sed, grep, etc. Do not edit any files with this tool; use edit_file instead. When working with git and other tools that open an editor (e.g. git diff), you should pipe to cat to get all results and not get stuck in vim.`
const cwdHelper = 'Optional. The directory in which to run the command. Defaults to the first workspace folder.'
@@ -94,13 +183,15 @@ export type SnakeCaseKeys> = {
[K in keyof T as SnakeCase>]: T[K]
};
+
+
const applyToolDescription = (type: 'edit tool' | 'chat suggestion') => `\
${type === 'edit tool' ? 'A' : 'a'} code diff describing the change to make to the file. \
Your DIFF is the only context that will be given to another LLM to apply the change, so it must be accurate and complete. \
Your DIFF MUST be wrapped in triple backticks. \
NEVER re-write the whole file. Always bias towards writing as little as possible. \
Use comments like "// ... existing code ..." to condense your writing. \
-Here's an example of a good output:\n${type === 'edit tool' ? editToolDiffExample : chatSuggestionDiffExample}`
+Here's an example of a good output:\n${type === 'edit tool' ? editToolDescriptionExample : chatSuggestionDiffExample}`
// export const voidTools = {
@@ -209,17 +300,23 @@ export const voidTools
},
},
- edit_file: { // APPLY TOOL
+ edit_file: {
name: 'edit_file',
- description: `Edits the contents of a file given the file's URI and a description.`,
+ description: `Edit the contents of a file. You must provide the file's URI as well as a SINGLE string of SEARCH/REPLACE block(s) that will be used to apply the edit.`,
params: {
...uriParam('file'),
- change_diff: {
- description: applyToolDescription('edit tool')
- }
+ search_replace_blocks: { description: replaceTool_description }
},
},
+ rewrite_file: {
+ name: 'rewrite_file',
+ description: `Edits a file, deleting all the old contents and replacing them with your new contents. Use this tool if you want to edit a file you just created.`,
+ params: {
+ ...uriParam('file'),
+ new_content: { description: `The new contents of the file. Must be a string.` }
+ },
+ },
run_command: {
name: 'run_command',
description: `Runs a terminal command and waits for the result (times out after ${MAX_TERMINAL_INACTIVE_TIME}s of inactivity). ${terminalDescHelper}`,
@@ -247,6 +344,8 @@ export const voidTools
cwd: { description: cwdHelper },
}
},
+
+
kill_persistent_terminal: {
name: 'kill_persistent_terminal',
description: `Interrupts and closes a persistent terminal that you opened with open_persistent_terminal.`,
@@ -287,19 +386,19 @@ const toolCallDefinitionsXMLString = (tools: InternalToolInfo[]) => {
return `${tools.map((t, i) => {
const params = Object.keys(t.params).map(paramName => `<${paramName}>${t.params[paramName].description}${paramName}>`).join('\n')
return `\
-${i + 1}. ${t.name}
-Description: ${t.description}
-Format:
-<${t.name}>${!params ? '' : `\n${params}`}
-${t.name}>`
+ ${i + 1}. ${t.name}
+ Description: ${t.description}
+ Format:
+ <${t.name}>${!params ? '' : `\n${params}`}
+ ${t.name}>`
}).join('\n\n')}`
}
export const reParsedToolXMLString = (toolName: ToolName, toolParams: RawToolParamsObj) => {
const params = Object.keys(toolParams).map(paramName => `<${paramName}>${toolParams[paramName as ToolParamName]}${paramName}>`).join('\n')
return `\
-<${toolName}>${!params ? '' : `\n${params}`}
-${toolName}>`
+ <${toolName}>${!params ? '' : `\n${params}`}
+ ${toolName}>`
.replace('\t', ' ')
}
@@ -310,28 +409,28 @@ const systemToolsXMLPrompt = (chatMode: ChatMode) => {
if (!tools || tools.length === 0) return null
const toolXMLDefinitions = (`\
-Available tools:
+ Available tools:
-${toolCallDefinitionsXMLString(tools)}`)
+ ${toolCallDefinitionsXMLString(tools)}`)
const toolCallXMLGuidelines = (`\
-Tool calling details:
-- To call a tool, write its name and parameters in one of the XML formats specified above.
-- After you write the tool call, you must STOP and WAIT for the result.
-- All parameters are REQUIRED unless noted otherwise.
-- 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.`)
+ Tool calling details:
+ - To call a tool, write its name and parameters in one of the XML formats specified above.
+ - After you write the tool call, you must STOP and WAIT for the result.
+ - All parameters are REQUIRED unless noted otherwise.
+ - 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.`)
return `\
-${toolXMLDefinitions}
+ ${toolXMLDefinitions}
-${toolCallXMLGuidelines}`
+ ${toolCallXMLGuidelines}`
}
// ======================================================== chat (normal, gather, agent) ========================================================
-export const chat_systemMessage = ({ workspaceFolders, openedURIs, activeURI, runningTerminalIds, directoryStr, chatMode: mode, includeXMLToolDefinitions }: { workspaceFolders: string[], directoryStr: string, openedURIs: string[], activeURI: string | undefined, runningTerminalIds: string[], chatMode: ChatMode, includeXMLToolDefinitions: boolean }) => {
+export const chat_systemMessage = ({ workspaceFolders, openedURIs, activeURI, persistentTerminalIDs, directoryStr, chatMode: mode, includeXMLToolDefinitions }: { workspaceFolders: string[], directoryStr: string, openedURIs: string[], activeURI: string | undefined, persistentTerminalIDs: string[], chatMode: ChatMode, includeXMLToolDefinitions: boolean }) => {
const header = (`You are an expert coding ${mode === 'agent' ? 'agent' : 'assistant'} whose job is \
${mode === 'agent' ? `to help the user develop, run, and make changes to their codebase.`
: mode === 'gather' ? `to search, understand, and reference files in the user's codebase.`
@@ -353,9 +452,9 @@ ${workspaceFolders.join('\n') || 'NO FOLDERS OPEN'}
${activeURI}
- Open files:
-${openedURIs.join('\n') || 'NO OPENED FILES'}${''/* separator */}${mode === 'agent' && runningTerminalIds.length !== 0 ? `
+${openedURIs.join('\n') || 'NO OPENED FILES'}${''/* separator */}${mode === 'agent' && persistentTerminalIDs.length !== 0 ? `
-- Existing persistent terminal IDs: ${runningTerminalIds.join(', ')}` : ''}
+- Persistent terminal IDs available for you to run commands in: ${persistentTerminalIDs.join(', ')}` : ''}
`)
@@ -406,6 +505,7 @@ ${directoryStr}
details.push(`NEVER write the FULL PATH of a file when speaking with the user. Just write the file name ONLY.`)
details.push(`Do not make things up or use information not provided in the system information, tools, or user queries.`)
+ details.push(`Always use MARKDOWN to format lists, bullet points, etc. Do NOT write tables.`)
details.push(`Today's date is ${new Date().toDateString()}.`)
const importantDetails = (`Important notes:
@@ -433,7 +533,7 @@ ${details.map((d, i) => `${i + 1}. ${d}`).join('\n\n')}`)
// // log all prompts
// for (const chatMode of ['agent', 'gather', 'normal'] satisfies ChatMode[]) {
// console.log(`========================================= SYSTEM MESSAGE FOR ${chatMode} ===================================\n`,
-// chat_systemMessage({ chatMode, workspaceFolders: [], openedURIs: [], activeURI: 'pee', runningTerminalIds: [], directoryStr: 'lol', }))
+// chat_systemMessage({ chatMode, workspaceFolders: [], openedURIs: [], activeURI: 'pee', persistentTerminalIDs: [], directoryStr: 'lol', }))
// }
@@ -514,74 +614,17 @@ Please finish writing the new file by applying the change to the original file.
// ======================================================== apply (fast apply - search/replace) ========================================================
+export const searchReplaceGivenDescription_systemMessage = createSearchReplaceBlocks_systemMessage
-export const ORIGINAL = `<<<<<<< ORIGINAL`
-export const DIVIDER = `=======`
-export const FINAL = `>>>>>>> UPDATED`
-
-export const searchReplace_systemMessage = `\
-You are a coding assistant that takes in a diff, and outputs SEARCH/REPLACE code blocks to implement the change(s) in the diff.
-The diff will be labeled \`DIFF\` and the original file will be labeled \`ORIGINAL_FILE\`.
-
-Format your SEARCH/REPLACE blocks as follows:
-${tripleTick[0]}
-${ORIGINAL}
-// ... original code goes here
-${DIVIDER}
-// ... final code goes here
-${FINAL}
-${tripleTick[1]}
-
-1. Your SEARCH/REPLACE block(s) must implement the diff EXACTLY. Do NOT leave anything out.
-
-2. You are allowed to output multiple SEARCH/REPLACE blocks to implement the change.
-
-3. Assume any comments in the diff are PART OF THE CHANGE. Include them in the output.
-
-4. Your output should consist ONLY of SEARCH/REPLACE blocks. Do NOT output any text or explanations before or after this.
-
-5. The ORIGINAL code in each SEARCH/REPLACE block must EXACTLY match lines in the original file. Do not add or remove any whitespace, comments, or modifications from the original code.
-
-6. Each ORIGINAL text must be large enough to uniquely identify the change in the file. However; bias towards writing as little as possible.
-
-7. Each ORIGINAL text must be DISJOINT from all other ORIGINAL text.
-
-## EXAMPLE 1
-DIFF
-${tripleTick[0]}
-// ... existing code
-let x = 6.5
-// ... existing code
-${tripleTick[1]}
-
-ORIGINAL_FILE
-${tripleTick[0]}
-let w = 5
-let x = 6
-let y = 7
-let z = 8
-${tripleTick[1]}
-
-## ACCEPTED OUTPUT
-${tripleTick[0]}
-${ORIGINAL}
-let x = 6
-${DIVIDER}
-let x = 6.5
-${FINAL}
-${tripleTick[1]}
-`
-
-export const searchReplace_userMessage = ({ originalCode, applyStr }: { originalCode: string, applyStr: string }) => `\
+export const searchReplaceGivenDescription_userMessage = ({ originalCode, applyStr }: { originalCode: string, applyStr: string }) => `\
DIFF
${applyStr}
ORIGINAL_FILE
${tripleTick[0]}
${originalCode}
-${tripleTick[1]}
-`
+${tripleTick[1]}`
diff --git a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
index 63bfc997..b6c466f4 100644
--- a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
+++ b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts
@@ -19,6 +19,7 @@ export type ShallowDirectoryItem = {
export const approvalTypeOfToolName: Partial<{ [T in ToolName]?: 'edits' | 'terminal' }> = {
'create_file_or_folder': 'edits',
'delete_file_or_folder': 'edits',
+ 'rewrite_file': 'edits',
'edit_file': 'edits',
'run_command': 'terminal',
'run_persistent_command': 'terminal',
@@ -43,7 +44,8 @@ export type ToolCallParams = {
'search_in_file': { uri: URI, query: string, isRegex: boolean },
'read_lint_errors': { uri: URI },
// ---
- 'edit_file': { uri: URI, changeDiff: string },
+ 'rewrite_file': { uri: URI, newContent: string },
+ 'edit_file': { uri: URI, searchReplaceBlocks: string },
'create_file_or_folder': { uri: URI, isFolder: boolean },
'delete_file_or_folder': { uri: URI, isRecursive: boolean, isFolder: boolean },
// ---
@@ -63,6 +65,7 @@ export type ToolResultType = {
'search_in_file': { lines: number[]; },
'read_lint_errors': { lintErrors: LintErrorItem[] | null },
// ---
+ 'rewrite_file': Promise<{ lintErrors: LintErrorItem[] | null }>,
'edit_file': Promise<{ lintErrors: LintErrorItem[] | null }>,
'create_file_or_folder': {},
'delete_file_or_folder': {},
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 232bdfab..4a515e50 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
@@ -162,6 +162,10 @@ const _sendOpenAICompatibleFIM = async ({ messages: { prefix, suffix, stopTokens
const toOpenAICompatibleTool = (toolInfo: InternalToolInfo) => {
const { name, description, params } = toolInfo
+
+ const paramsWithType: { [s: string]: { description: string; type: 'string' } } = {}
+ for (const key in params) { paramsWithType[key] = { ...params[key], type: 'string' } }
+
return {
type: 'function',
function: {
@@ -358,12 +362,14 @@ const _openaiCompatibleList = async ({ onSuccess: onSuccess_, onError: onError_,
// ------------ ANTHROPIC (HELPERS) ------------
const toAnthropicTool = (toolInfo: InternalToolInfo) => {
const { name, description, params } = toolInfo
+ const paramsWithType: { [s: string]: { description: string; type: 'string' } } = {}
+ for (const key in params) { paramsWithType[key] = { ...params[key], type: 'string' } }
return {
name: name,
description: description,
input_schema: {
type: 'object',
- properties: params,
+ properties: paramsWithType,
// required: Object.keys(params),
},
} satisfies Anthropic.Messages.Tool