misc bug fixes with oai-compat and agent

This commit is contained in:
Andrew Pareles 2025-03-20 04:03:37 -07:00
parent 8dab3ac854
commit b86356d2af
7 changed files with 35 additions and 27 deletions

View file

@ -761,7 +761,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
const handleToolCall = async (
tool: ToolCallType,
opts?: { preapproved: true, toolParams: ToolCallParams[ToolName] },
): Promise<{ awaitingUserApproval: boolean, canceled: boolean }> => {
): Promise<{ awaitingUserApproval?: boolean, canceled?: boolean }> => {
const toolName: ToolName = tool.name
const toolParamsStr = tool.paramsStr
const toolId = tool.id
@ -779,14 +779,14 @@ class ChatThreadService extends Disposable implements IChatThreadService {
} catch (error) {
const errorMessage = getErrorMessage(error)
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: toolParamsStr, id: toolId, content: errorMessage, result: { type: 'error', params: undefined, value: errorMessage }, })
return { awaitingUserApproval: false, canceled: false }
return {}
}
// 2. if tool requires approval, break from the loop, awaiting approval
const requiresApproval = !this._settingsService.state.globalSettings.autoApprove
if (requiresApproval && toolNamesThatRequireApproval.has(toolName)) {
this._addMessageToThread(threadId, { role: 'tool_request', name: toolName, paramsStr: toolParamsStr, params: toolParams, id: toolId })
return { awaitingUserApproval: true, canceled: false }
return { awaitingUserApproval: true }
}
}
else {
@ -805,10 +805,10 @@ class ChatThreadService extends Disposable implements IChatThreadService {
toolResult = await Promise.race([result, resolveIfCancel]) // this await is needed, typescript is bad...
}
catch (error) {
if (canceled) return { awaitingUserApproval: false, canceled: true }
if (canceled) return { canceled: true }
const errorMessage = getErrorMessage(error)
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: toolParamsStr, id: toolId, content: errorMessage, result: { type: 'error', params: toolParams, value: errorMessage }, })
return { awaitingUserApproval: true, canceled: false }
return {}
}
// 4. stringify the result to give to the LLM
@ -817,12 +817,12 @@ class ChatThreadService extends Disposable implements IChatThreadService {
} catch (error) {
const errorMessage = this.errMsgs.errWhenStringifying(error)
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: toolParamsStr, id: toolId, content: errorMessage, result: { type: 'error', params: toolParams, value: errorMessage }, })
return { awaitingUserApproval: false, canceled: false }
return {}
}
// 5. add to history and keep going
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: toolParamsStr, id: toolId, content: toolResultStr, result: { type: 'success', params: toolParams, value: toolResult }, })
return { awaitingUserApproval: false, canceled: false }
return {}
};
// above just defines helpers, below starts the actual function

View file

@ -1244,11 +1244,11 @@ class EditCodeService extends Disposable implements IEditCodeService {
// ctrlkzone should never have any conflicts
}
else {
// keep conflict on whole file - to keep conflict, revert the change and use those contents as original, then un-revert the change
// keep conflict on whole file - to keep conflict, revert the change and use those contents as original, then un-revert the file
const currentFileStr = originalFileStr
this.acceptOrRejectAllDiffAreas({ uri, removeCtrlKs: true, behavior: 'reject', _addToHistory: false })
const oldFileStr = model.getValue(EndOfLinePreference.LF) // use this as original code
this._writeURIText(uri, currentFileStr, 'wholeFileRange', { shouldRealignDiffAreas: false }) // un-revert
this._writeURIText(uri, currentFileStr, 'wholeFileRange', { shouldRealignDiffAreas: true }) // un-revert
originalCode = oldFileStr
}

View file

@ -224,6 +224,7 @@ const ChatModeDropdown = ({ className }: { className: string }) => {
const accessor = useAccessor()
const voidSettingsService = accessor.get('IVoidSettingsService')
const settingsState = useSettingsState()
const options: ChatMode[] = useMemo(() => ['normal', 'gather', 'agent'], [])
@ -234,7 +235,7 @@ const ChatModeDropdown = ({ className }: { className: string }) => {
return <VoidCustomDropdownBox
className={className}
options={options}
selectedOption={voidSettingsService.state.globalSettings.chatMode}
selectedOption={settingsState.globalSettings.chatMode}
onChangeOption={onChangeOption}
getOptionDisplayName={(val) => nameOfChatMode[val]}
getOptionDropdownName={(val) => nameOfChatMode[val]}
@ -674,7 +675,7 @@ export const SelectedFiles = (
type ToolHeaderParams = {
icon?: React.ReactNode;
title: string;
title: React.ReactNode;
desc1: React.ReactNode;
desc2?: React.ReactNode;
isError?: boolean;
@ -1109,24 +1110,30 @@ const ReasoningWrapper = ({ isDoneReasoning, isStreaming, children }: { isDoneRe
// should either be past or "-ing" tense, not present tense. Eg. when the LLM searches for something, the user expects it to say "I searched for X" or "I am searching for X". Not "I search X".
const loadingTitleWrapper = (item: React.ReactNode) => {
return <span className='flex items-center flex-nowrap'>
{item}
<IconLoading className='w-4'/>
</span>
}
const folderFileStr = (isFolder: boolean) => isFolder ? 'folder' : 'file'
const toolNameToTitle = {
'read_file': { done: 'Read file', proposed: 'Read file', running: 'Reading file...' },
'list_dir': { done: 'Inspected folder', proposed: 'Inspect folder', running: 'Inspecting folder...' },
'pathname_search': { done: 'Searched by file name', proposed: 'Search by file name', running: 'Searching by file name...' },
'text_search': { done: 'Searched', proposed: 'Search text', running: 'Searching...' },
'read_file': { done: 'Read file', proposed: 'Read file', running: loadingTitleWrapper('Reading file') },
'list_dir': { done: 'Inspected folder', proposed: 'Inspect folder', running: loadingTitleWrapper('Inspecting folder') },
'pathname_search': { done: 'Searched by file name', proposed: 'Search by file name', running: loadingTitleWrapper('Searching by file name') },
'text_search': { done: 'Searched', proposed: 'Search text', running: loadingTitleWrapper('Searching') },
'create_uri': {
done: (isFolder: boolean) => `Created ${folderFileStr(isFolder)}`,
proposed: (isFolder: boolean) => `Create ${folderFileStr(isFolder)}`,
running: (isFolder: boolean) => `Creating ${folderFileStr(isFolder)}...`
running: (isFolder: boolean) => loadingTitleWrapper(`Creating ${folderFileStr(isFolder)}`)
},
'delete_uri': {
done: (isFolder: boolean) => `Deleted ${folderFileStr(isFolder)}`,
proposed: (isFolder: boolean) => `Delete ${folderFileStr(isFolder)}`,
running: (isFolder: boolean) => `Deleting ${folderFileStr(isFolder)}...`
running: (isFolder: boolean) => loadingTitleWrapper(`Deleting ${folderFileStr(isFolder)}`)
},
'edit': { done: 'Edited file', proposed: 'Edit file', running: 'Editing file...' },
'terminal_command': { done: 'Ran terminal command', proposed: 'Run terminal command', running: 'Running terminal command...' }
'edit': { done: `Edited file`, proposed: 'Edit file', running: loadingTitleWrapper('Editing file') },
'terminal_command': { done: `Ran terminal command`, proposed: 'Run terminal command', running: loadingTitleWrapper('Running terminal command') }
} as const satisfies Record<ToolName, { done: any, proposed: any, running: any }>
@ -1778,7 +1785,9 @@ const ChatBubble = ({ chatMessage, isCommitted, messageIdx, isLast, chatIsRunnin
}
else if (role === 'tool') {
const ToolResultWrapper = toolNameToComponent[chatMessage.name].resultWrapper as ResultWrapper<ToolName>
return <ToolResultWrapper toolMessage={chatMessage} messageIdx={messageIdx} threadId={threadId} />
if (ToolResultWrapper)
return <ToolResultWrapper toolMessage={chatMessage} messageIdx={messageIdx} threadId={threadId} />
return null
}
}

View file

@ -21,7 +21,6 @@ export type VoidCommandBarProps = {
export const VoidCommandBarMain = ({ uri, editor }: VoidCommandBarProps) => {
const isDark = useIsDark()
console.log('VoidCommandBarMain', uri?.fsPath)
return <div
className={`@@void-scope ${isDark ? 'dark' : ''}`}
>

View file

@ -78,7 +78,7 @@ const directoryResultToString = (params: ToolCallParams['list_dir'], result: Too
const entries = result.children;
if (!result.hasPrevPage) { // is first page
output += `${params.rootURI}\n`;
output += `${params.rootURI.fsPath}\n`;
}
for (let i = 0; i < entries.length; i++) {

View file

@ -16,10 +16,10 @@ import { EndOfLinePreference } from '../../../../../editor/common/model.js';
export const tripleTick = ['```', '```']
export const editToolDesc_toolDescription = `\
A high level description of the change you'd like to make in the file. This description will be handed to a dumber, faster model that will quickly apply the change.\
Make sure to include all necessary information to make the change in this description, since it is the only context given to the fast-apply model that will actually write the change.\
The best description you can give is a single code block of the form:\n${tripleTick[0]}\n// ... existing code ...\n{{change 1}}\n// ... existing code ...\n{{change2}}\n// ... existing code ...\n{{change 3}}\n...\n${tripleTick[1]}. \
Wrap all code in triple backticks. Do NOT output the whole file here if possible, and try to write as LITTLE code as needed to describe the change.`
A high level description of the change you'd like to make in the file. \
Your output should be of the form:\n${tripleTick[0]}\n// ... existing code ...\n{{change 1}}\n// ... existing code ...\n{{change2}}\n// ... existing code ...\n{{change 3}}\n...\n${tripleTick[1]}. \
(wrap your output in triple backticks). Do NOT output the whole file here, and write as little as possible. If a change seems big, break it up into smaller edits. \
Your description will be handed to a dumber, faster model that will quickly apply the change, so try to be brief, but also make sure to include enough information to accurately describe the change.`

View file

@ -206,7 +206,7 @@ const _sendOpenAICompatibleChat = ({ messages: messages_, onText, onFinalMessage
if (!toolCallOfIndex[index]) toolCallOfIndex[index] = { name: '', paramsStr: '', id: '' }
toolCallOfIndex[index].name += tool.function?.name ?? ''
toolCallOfIndex[index].paramsStr += tool.function?.arguments ?? '';
toolCallOfIndex[index].id = tool.id ?? ''
toolCallOfIndex[index].id += tool.id ?? ''
}
// message
const newText = chunk.choices[0]?.delta?.content ?? ''