mirror of
https://github.com/voideditor/void
synced 2026-05-24 01:48:25 +00:00
tool call improvements (error message + better ux)
This commit is contained in:
parent
6a55abcd81
commit
217a33cc2e
4 changed files with 185 additions and 104 deletions
|
|
@ -423,7 +423,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
toolParams = params
|
||||
} catch (error) {
|
||||
const errorMessage = getErrorMessage(error)
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', value: errorMessage }, })
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', params: undefined, value: errorMessage }, })
|
||||
res_()
|
||||
return
|
||||
}
|
||||
|
|
@ -441,7 +441,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
// TODO!!! test rejection
|
||||
// if (Math.random() > 0) throw new Error('TESTING')
|
||||
const errorMessage = 'Tool call was rejected by the user.'
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', value: errorMessage }, })
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', params: toolParams, value: errorMessage }, })
|
||||
res_()
|
||||
return
|
||||
}
|
||||
|
|
@ -453,7 +453,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
toolResult = await this._toolsService.callTool[toolName](toolParams as any) // typescript is so bad it doesn't even couple the type of ToolResult with the type of the function being called here
|
||||
} catch (error) {
|
||||
const errorMessage = getErrorMessage(error)
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', value: errorMessage }, })
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', params: toolParams, value: errorMessage }, })
|
||||
res_()
|
||||
return
|
||||
}
|
||||
|
|
@ -464,7 +464,7 @@ class ChatThreadService extends Disposable implements IChatThreadService {
|
|||
toolResultStr = this._toolsService.stringOfResult[toolName](toolParams as any, toolResult as any)
|
||||
} catch (error) {
|
||||
const errorMessage = `Tool call succeeded, but there was an error stringifying the output.\n${getErrorMessage(error)}`
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', value: errorMessage }, })
|
||||
this._addMessageToThread(threadId, { role: 'tool', name: toolName, paramsStr: tool.paramsStr, id: tool.id, content: errorMessage, result: { type: 'error', params: toolParams, value: errorMessage }, })
|
||||
res_()
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import { nameToVscodeLanguage } from '../../../../common/helpers/detectLanguage.
|
|||
import { ApplyBlockHoverButtons } from './ApplyBlockHoverButtons.js'
|
||||
import { useAccessor, useChatThreadsState } from '../util/services.js'
|
||||
import { Range } from '../../../../../../services/search/common/searchExtTypes.js'
|
||||
import { CodespanLocationLink } from '../../../chatThreadService.js'
|
||||
import { IRange } from '../../../../../../../base/common/range.js'
|
||||
import { ScrollType } from '../../../../../../../editor/common/editorCommon.js'
|
||||
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ import { filenameToVscodeLanguage } from '../../../../common/helpers/detectLangu
|
|||
import { getModelSelectionState, getModelCapabilities } from '../../../../common/modelCapabilities.js';
|
||||
import { AlertTriangle, ChevronRight, Dot, Pencil, X } from 'lucide-react';
|
||||
import { ChatMessage, StagingSelectionItem, ToolMessage, ToolRequestApproval } from '../../../../common/chatThreadServiceTypes.js';
|
||||
import { ToolName } from '../../../../common/toolsServiceTypes.js';
|
||||
import { ToolCallParams, ToolName } from '../../../../common/toolsServiceTypes.js';
|
||||
|
||||
|
||||
|
||||
|
|
@ -274,7 +274,7 @@ interface VoidChatAreaProps {
|
|||
onAbort: () => void;
|
||||
isStreaming: boolean;
|
||||
isDisabled?: boolean;
|
||||
divRef?: React.RefObject<HTMLDivElement|null>;
|
||||
divRef?: React.RefObject<HTMLDivElement | null>;
|
||||
|
||||
// UI customization
|
||||
className?: string;
|
||||
|
|
@ -659,11 +659,10 @@ export const SelectedFiles = (
|
|||
interface DropdownComponentProps {
|
||||
title: string;
|
||||
desc1: string;
|
||||
desc2?: string;
|
||||
desc2?: React.ReactNode;
|
||||
numResults?: number;
|
||||
children?: React.ReactNode;
|
||||
onClick?: () => void;
|
||||
icon?: React.ReactNode;
|
||||
}
|
||||
|
||||
const DropdownComponent = ({
|
||||
|
|
@ -673,7 +672,6 @@ const DropdownComponent = ({
|
|||
numResults,
|
||||
children,
|
||||
onClick,
|
||||
icon,
|
||||
}: DropdownComponentProps) => {
|
||||
const [isExpanded, setIsExpanded] = useState(false);
|
||||
|
||||
|
|
@ -695,18 +693,21 @@ const DropdownComponent = ({
|
|||
className={`text-void-fg-3 mr-0.5 h-5 w-5 flex-shrink-0 transition-transform duration-100 ease-[cubic-bezier(0.4,0,0.2,1)] ${isExpanded ? 'rotate-90' : ''}`}
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center flex-nowrap whitespace-nowrap gap-x-2">
|
||||
{icon}
|
||||
<span className="text-void-fg-3">{title}</span>
|
||||
<span className="text-void-fg-4 text-xs italic">{desc1}</span>
|
||||
{desc2 && <span className="text-void-fg-4 text-xs">
|
||||
{desc2}
|
||||
</span>}
|
||||
{numResults !== undefined && (
|
||||
<span className="text-void-fg-4 text-xs">
|
||||
{`(`}{numResults}{` result`}{numResults !== 1 ? 's' : ''}{`)`}
|
||||
</span>
|
||||
)}
|
||||
<div className="flex items-center justify-between w-full flex-nowrap whitespace-nowrap gap-x-2">
|
||||
<div className="flex items-center gap-x-2">
|
||||
<span className="text-void-fg-3">{title}</span>
|
||||
<span className="text-void-fg-4 text-xs italic">{desc1}</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-2">
|
||||
{desc2 && <span className="text-void-fg-4 text-xs">
|
||||
{desc2}
|
||||
</span>}
|
||||
{numResults !== undefined && (
|
||||
<span className="text-void-fg-4 text-xs ml-auto mr-1">
|
||||
{`(`}{numResults}{` result`}{numResults !== 1 ? 's' : ''}{`)`}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
|
|
@ -908,11 +909,8 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isLoading }: ChatBubble
|
|||
}}
|
||||
/>}
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -968,7 +966,6 @@ const AssistantMessageComponent = ({ chatMessage, isLoading, messageIdx }: ChatB
|
|||
{hasReasoning && <DropdownComponent
|
||||
title="Reasoning"
|
||||
desc1=""
|
||||
icon={<Dot className='stroke-blue-500' />}
|
||||
>
|
||||
<ChatMarkdownRender
|
||||
string={reasoningStr}
|
||||
|
|
@ -991,29 +988,77 @@ const AssistantMessageComponent = ({ chatMessage, isLoading, messageIdx }: ChatB
|
|||
|
||||
|
||||
|
||||
const ToolError = ({ title, errorMessage }: { title: string, errorMessage: string }) => {
|
||||
const ToolError = ({ title, desc1, errorMessage }: { title: string, desc1: string, errorMessage: string }) => {
|
||||
return (
|
||||
<div className='flex gap-2 p-3 bg-void-bg-2-alt bg-opacity-10 border border-void-warning border-opacity-20 rounded-md'>
|
||||
<AlertTriangle className='text-void-warning flex-shrink-0' size={20} />
|
||||
<div className='flex flex-col'>
|
||||
<span className='text-void-fg-1 font-medium mb-1'>{title}</span>
|
||||
<div className='text-void-fg-3 text-sm opacity-90'>{'Error: ' + errorMessage}</div>
|
||||
</div>
|
||||
</div>
|
||||
// px-2 py-1
|
||||
// <div className='flex gap-2 p-3 border border-void-border-3 text-void-fg-3 rounded bg-void-bg-2-alt'>
|
||||
// <AlertTriangle className='text-void-warning opacity-90 flex-shrink-0' size={20} />
|
||||
// <div className='flex flex-col'>
|
||||
// <span className='mb-1'>{title + ' error'}</span>
|
||||
// <div className='text-sm opacity-90'>{errorMessage}</div>
|
||||
// </div>
|
||||
// </div>
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={desc1}
|
||||
desc2={
|
||||
<span className="flex items-center flex-nowrap gap-1">
|
||||
<AlertTriangle className='text-void-warning opacity-90 flex-shrink-0' size={12} />
|
||||
Error
|
||||
</span>
|
||||
}
|
||||
>
|
||||
<div className='text-xs text-wrap whitespace-pre-wrap break-all break-words'>{errorMessage}</div>
|
||||
</DropdownComponent>
|
||||
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
const toolNameToTitle: Record<ToolName, string> = {
|
||||
'read_file': 'Read file',
|
||||
'list_dir': 'Inspect folder',
|
||||
'pathname_search': 'Search (path only)',
|
||||
'search': 'Search (file contents)',
|
||||
'list_dir': 'Inspected folder',
|
||||
'pathname_search': 'Searched by file name',
|
||||
'search': 'Searched files',
|
||||
'create_uri': 'Create file',
|
||||
'delete_uri': 'Delete file',
|
||||
'edit': 'Edit file',
|
||||
'terminal_command': 'Ran terminal command'
|
||||
}
|
||||
const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName] | undefined): string => {
|
||||
|
||||
if (_toolParams === undefined) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (toolName === 'read_file') {
|
||||
const toolParams = _toolParams as ToolCallParams['read_file']
|
||||
return toolParams ? getBasename(toolParams.uri.fsPath) : '';
|
||||
} else if (toolName === 'list_dir') {
|
||||
const toolParams = _toolParams as ToolCallParams['list_dir']
|
||||
return toolParams ? `${getBasename(toolParams.rootURI.fsPath)}/` : '';
|
||||
} else if (toolName === 'pathname_search') {
|
||||
const toolParams = _toolParams as ToolCallParams['pathname_search']
|
||||
return toolParams ? `"${toolParams.queryStr}"` : '';
|
||||
} else if (toolName === 'search') {
|
||||
const toolParams = _toolParams as ToolCallParams['search']
|
||||
return toolParams ? `"${toolParams.queryStr}"` : '';
|
||||
} else if (toolName === 'create_uri') {
|
||||
const toolParams = _toolParams as ToolCallParams['create_uri']
|
||||
return toolParams ? getBasename(toolParams.uri.fsPath) : '';
|
||||
} else if (toolName === 'delete_uri') {
|
||||
const toolParams = _toolParams as ToolCallParams['delete_uri']
|
||||
return toolParams ? getBasename(toolParams.uri.fsPath) + ' (deleted)' : '';
|
||||
} else if (toolName === 'edit') {
|
||||
const toolParams = _toolParams as ToolCallParams['edit']
|
||||
return toolParams ? getBasename(toolParams.uri.fsPath) : '';
|
||||
} else if (toolName === 'terminal_command') {
|
||||
const toolParams = _toolParams as ToolCallParams['terminal_command']
|
||||
return toolParams ? `"${toolParams.command}"` : '';
|
||||
} else {
|
||||
return ''
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -1028,24 +1073,31 @@ const ToolRequestAcceptRejectButtons = ({ toolRequest }: { toolRequest: ToolRequ
|
|||
|
||||
const toolNameToComponent: { [T in ToolName]: {
|
||||
requestWrapper: (props: { toolRequest: ToolRequestApproval<T> }) => React.ReactNode,
|
||||
resultWrapper: (props: { toolMessage: ToolMessage<T> & { result: { type: 'success' } } }) => React.ReactNode,
|
||||
resultWrapper: (props: { toolMessage: ToolMessage<T> }) => React.ReactNode,
|
||||
} } = {
|
||||
'read_file': {
|
||||
requestWrapper: ({ toolRequest }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={getBasename(params.uri.toString())} icon={<Dot className={`stroke-orange-500`} />}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', toolRequest.params.uri, { preview: true }) }}
|
||||
/>
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { value, params } = toolMessage.result
|
||||
return <DropdownComponent title={title} desc1={getBasename(params.uri.toString())} icon={<Dot className={`stroke-orange-500`} />}>
|
||||
|
||||
return <DropdownComponent title={title} desc1={desc1}>
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
|
|
@ -1053,7 +1105,7 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
<div className="flex-shrink-0"><svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg></div>
|
||||
{params.uri.fsPath}
|
||||
</div>
|
||||
{value.hasNextPage && (<div className="italic">AI can scroll for more content...</div>)}
|
||||
{toolMessage.result.value.hasNextPage && (<div className="italic">AI can scroll for more content...</div>)}
|
||||
|
||||
</DropdownComponent>
|
||||
},
|
||||
|
|
@ -1061,23 +1113,26 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
'list_dir': {
|
||||
requestWrapper: ({ toolRequest }) => {
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={`${getBasename(params.rootURI.fsPath)}/`} icon={<Dot className={`stroke-orange-500`} />} />
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1} />
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const explorerService = accessor.get('IExplorerService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
// message.result.hasNextPage = true
|
||||
// message.result.itemsRemaining = 400
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { value, params } = toolMessage.result
|
||||
|
||||
return <DropdownComponent
|
||||
title={title}
|
||||
desc1={`${getBasename(params.rootURI.fsPath)}/`}
|
||||
desc1={desc1}
|
||||
numResults={value.children?.length}
|
||||
icon={<Dot className={`stroke-orange-500`} />}
|
||||
>
|
||||
{value.children?.map((child, i) => (
|
||||
<div
|
||||
|
|
@ -1098,72 +1153,76 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
</div>
|
||||
)}
|
||||
</DropdownComponent>
|
||||
|
||||
}
|
||||
},
|
||||
'pathname_search': {
|
||||
requestWrapper: ({ toolRequest }) => {
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={`"${params.queryStr}"`} icon={<Dot className={`stroke-orange-500`} />} />
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1} />
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { value, params } = toolMessage.result
|
||||
|
||||
return (
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={`"${params.queryStr}"`}
|
||||
desc1={desc1}
|
||||
numResults={value.uris.length}
|
||||
icon={<Dot className={`stroke-orange-500`} />}
|
||||
>
|
||||
{
|
||||
value.uris.map((uri, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => {
|
||||
commandService.executeCommand('vscode.open', uri, { preview: true })
|
||||
}}
|
||||
>
|
||||
<div className="flex-shrink-0"><svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg></div>
|
||||
{uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
{
|
||||
value.hasNextPage && (
|
||||
<div className="italic">
|
||||
More results available...
|
||||
</div>
|
||||
)
|
||||
}
|
||||
</DropdownComponent >
|
||||
{value.uris.map((uri, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
onClick={() => {
|
||||
commandService.executeCommand('vscode.open', uri, { preview: true })
|
||||
}}
|
||||
>
|
||||
<div className="flex-shrink-0"><svg className="w-1 h-1 opacity-60 mr-1.5 fill-current" viewBox="0 0 100 40"><rect x="0" y="15" width="100" height="10" /></svg></div>
|
||||
{uri.fsPath.split('/').pop()}
|
||||
</div>
|
||||
))}
|
||||
{value.hasNextPage && (
|
||||
<div className="italic">
|
||||
More results available...
|
||||
</div>
|
||||
)}
|
||||
</DropdownComponent>
|
||||
)
|
||||
}
|
||||
},
|
||||
'search': {
|
||||
requestWrapper: ({ toolRequest }) => {
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={`"${params.queryStr}"`} icon={<Dot className={`stroke-orange-500`} />} />
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1} />
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { value, params } = toolMessage.result
|
||||
|
||||
return (
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={`"${params.queryStr}"`}
|
||||
desc1={desc1}
|
||||
numResults={value.uris.length}
|
||||
icon={<Dot className={`stroke-orange-500`} />}
|
||||
>
|
||||
{value.uris.map((uri, i) => (
|
||||
<div key={i}
|
||||
|
|
@ -1179,24 +1238,29 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
)
|
||||
}
|
||||
},
|
||||
|
||||
'create_uri': {
|
||||
requestWrapper: ({ toolRequest }) => {
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={getBasename(params.uri.fsPath)} icon={<Dot className={`stroke-orange-500`} />} />
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1} />
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { params } = toolMessage.result
|
||||
|
||||
return (
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={getBasename(params.uri.fsPath)}
|
||||
desc1={desc1}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
icon={<Dot className={`stroke-orange-500`} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -1206,20 +1270,27 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={getBasename(params.uri.fsPath) + ' (deleted)'}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', toolRequest.params.uri, { preview: true }) }}
|
||||
/>
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { params } = toolMessage.result
|
||||
|
||||
return (
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={getBasename(params.uri.fsPath) + ' (deleted)'}
|
||||
desc1={desc1}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
/>
|
||||
)
|
||||
|
|
@ -1230,25 +1301,30 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={getBasename(params.uri.fsPath)} icon={<Dot className={`stroke-orange-500`} />}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', toolRequest.params.uri, { preview: true }) }}
|
||||
>
|
||||
<ChatMarkdownRender string={params.changeDescription} chatMessageLocation={undefined} />
|
||||
</DropdownComponent >
|
||||
<ChatMarkdownRender string={toolRequest.params.changeDescription} chatMessageLocation={undefined} />
|
||||
</DropdownComponent>
|
||||
},
|
||||
resultWrapper: ({ toolMessage }) => {
|
||||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { params } = toolMessage.result
|
||||
|
||||
return (
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={getBasename(params.uri.fsPath)}
|
||||
desc1={desc1}
|
||||
onClick={() => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
|
||||
icon={<Dot className={`stroke-orange-500`} />}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -1258,8 +1334,8 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolRequest.name]
|
||||
const { params } = toolRequest
|
||||
return <DropdownComponent title={title} desc1={`"${params.command}"`} icon={<Dot className={`stroke-orange-500`} />}
|
||||
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
|
||||
return <DropdownComponent title={title} desc1={desc1}
|
||||
// TODO!!! open the terminal with that ID
|
||||
/>
|
||||
},
|
||||
|
|
@ -1267,13 +1343,18 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
const accessor = useAccessor()
|
||||
const commandService = accessor.get('ICommandService')
|
||||
const title = toolNameToTitle[toolMessage.name]
|
||||
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
|
||||
|
||||
if (toolMessage.result.type === 'error') {
|
||||
return <ToolError title={title} desc1={desc1} errorMessage={toolMessage.result.value} />
|
||||
}
|
||||
|
||||
const { params } = toolMessage.result
|
||||
|
||||
return (
|
||||
<DropdownComponent
|
||||
title={title}
|
||||
desc1={`"${params.command}"`}
|
||||
icon={<Dot className={`stroke-orange-500`} />}
|
||||
desc1={desc1}
|
||||
>
|
||||
<div
|
||||
className="hover:brightness-125 hover:cursor-pointer transition-all duration-200 flex items-center flex-nowrap"
|
||||
|
|
@ -1286,7 +1367,6 @@ const toolNameToComponent: { [T in ToolName]: {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -1320,8 +1400,10 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx }: ChatBubbleProps) =>
|
|||
</>
|
||||
}
|
||||
else if (role === 'tool') {
|
||||
|
||||
const title = toolNameToTitle[chatMessage.name]
|
||||
if (chatMessage.result.type === 'error') return <ToolError title={title} errorMessage={chatMessage.result.value} />
|
||||
// if (chatMessage.result.type === 'error') return <ToolError title={title} params={chatMessage.result.params} errorMessage={chatMessage.result.value} />
|
||||
|
||||
const ToolResultComponent = toolNameToComponent[chatMessage.name].resultWrapper as React.FC<{ toolMessage: any }> // ts isnt smart enough...
|
||||
return <ToolResultComponent toolMessage={chatMessage} />
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export type ToolMessage<T extends ToolName> = {
|
|||
paramsStr: string; // internal use
|
||||
id: string; // apis require this tool use id
|
||||
content: string; // give this result to LLM
|
||||
result: { type: 'success'; params: ToolCallParams[T]; value: ToolResultType[T], } | { type: 'error'; value: string }; // give this result to user
|
||||
result: { type: 'success'; params: ToolCallParams[T]; value: ToolResultType[T], } | { type: 'error'; params: ToolCallParams[T] | undefined; value: string }; // give this result to user
|
||||
}
|
||||
export type ToolRequestApproval<T extends ToolName> = {
|
||||
role: 'tool_request';
|
||||
|
|
|
|||
Loading…
Reference in a new issue