From 1ef8011bb0eea00bbda5a2897a58e61c1e7fbafe Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Tue, 11 Mar 2025 21:00:45 -0700 Subject: [PATCH] tool UI step 1 (BROKEN) --- .../void/browser/autocompleteService.ts | 1 - .../react/src/sidebar-tsx/SidebarChat.tsx | 155 ++++++++---------- .../void/browser/terminalToolService.ts | 8 +- .../contrib/void/common/toolsServiceTypes.ts | 4 +- 4 files changed, 73 insertions(+), 95 deletions(-) diff --git a/src/vs/workbench/contrib/void/browser/autocompleteService.ts b/src/vs/workbench/contrib/void/browser/autocompleteService.ts index cc9f3a92..6479fb6d 100644 --- a/src/vs/workbench/contrib/void/browser/autocompleteService.ts +++ b/src/vs/workbench/contrib/void/browser/autocompleteService.ts @@ -942,4 +942,3 @@ export class AutocompleteService extends Disposable implements IAutocompleteServ registerWorkbenchContribution2(AutocompleteService.ID, AutocompleteService, WorkbenchPhase.BlockRestore); - diff --git a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx index 172cc5b9..eb91346a 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/sidebar-tsx/SidebarChat.tsx @@ -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 { ToolCallParams, ToolName } from '../../../../common/toolsServiceTypes.js'; +import { ToolCallParams, ToolName, ToolNameWithApproval } from '../../../../common/toolsServiceTypes.js'; @@ -654,25 +654,29 @@ export const SelectedFiles = ( +const ReasoningComponent = ({ children }: { children: React.ReactNode }) => { + return children -interface DropdownComponentProps { - title: string; - desc1: string; - desc2?: React.ReactNode; - numResults?: number; - children?: React.ReactNode; - onClick?: () => void; } -const DropdownComponent = ({ + + +const ToolComponent = ({ title, desc1, desc2, numResults, children, onClick, -}: DropdownComponentProps) => { +}: { + title: string; + desc1: string; + desc2?: React.ReactNode; + numResults?: number; + children?: React.ReactNode; + onClick?: () => void; +}) => { const [isExpanded, setIsExpanded] = useState(false); const isDropdown = !!children @@ -690,7 +694,7 @@ const DropdownComponent = ({ > {isDropdown && ( )}
@@ -964,17 +968,14 @@ const AssistantMessageComponent = ({ chatMessage, isLoading, messageIdx, isLast > {/* reasoning token */} - {hasReasoning && + {hasReasoning && - } + } {/* assistant message */} {errorMessage}
// // - } > -
{errorMessage}
-
+
{errorMessage}
+ ) } @@ -1066,7 +1067,6 @@ const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName } - const ToolRequestAcceptRejectButtons = ({ toolRequest, messageIdx, isLast }: { toolRequest: ToolRequestApproval } & Omit) => { const accessor = useAccessor() const chatThreadsService = accessor.get('IChatThreadService') @@ -1130,19 +1130,11 @@ const ToolRequestAcceptRejectButtons = ({ toolRequest, messageIdx, isLast }: { t } const toolNameToComponent: { [T in ToolName]: { - requestWrapper: (props: { toolRequest: ToolRequestApproval }) => React.ReactNode, + requestWrapper: T extends ToolNameWithApproval ? ((props: { toolRequest: ToolRequestApproval }) => React.ReactNode) : null, resultWrapper: (props: { toolMessage: ToolMessage }) => React.ReactNode, } } = { 'read_file': { - requestWrapper: ({ toolRequest }) => { - const accessor = useAccessor() - const commandService = accessor.get('ICommandService') - const title = toolNameToTitle[toolRequest.name] - const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return { commandService.executeCommand('vscode.open', toolRequest.params.uri, { preview: true }) }} - /> - }, + requestWrapper: null, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') @@ -1155,7 +1147,7 @@ const toolNameToComponent: { [T in ToolName]: { const { value, params } = toolMessage.result - return + return
{ commandService.executeCommand('vscode.open', params.uri, { preview: true }) }} @@ -1165,15 +1157,11 @@ const toolNameToComponent: { [T in ToolName]: {
{toolMessage.result.value.hasNextPage && (
AI can scroll for more content...
)} -
+ }, }, 'list_dir': { - requestWrapper: ({ toolRequest }) => { - const title = toolNameToTitle[toolRequest.name] - const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return - }, + requestWrapper: null, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') @@ -1187,7 +1175,7 @@ const toolNameToComponent: { [T in ToolName]: { const { value, params } = toolMessage.result - return )} - + } }, 'pathname_search': { - requestWrapper: ({ toolRequest }) => { - const title = toolNameToTitle[toolRequest.name] - const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return - }, + requestWrapper: null, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') @@ -1232,7 +1216,7 @@ const toolNameToComponent: { [T in ToolName]: { const { value, params } = toolMessage.result return ( - )} - + ) } }, 'search': { - requestWrapper: ({ toolRequest }) => { - const title = toolNameToTitle[toolRequest.name] - const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return - }, + requestWrapper: null, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() const commandService = accessor.get('ICommandService') @@ -1277,7 +1257,7 @@ const toolNameToComponent: { [T in ToolName]: { const { value, params } = toolMessage.result return ( - ))} {value.hasNextPage && (
More results available...
)} -
+ ) } }, + + // --- + 'create_uri': { requestWrapper: ({ toolRequest }) => { const title = toolNameToTitle[toolRequest.name] const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return + return }, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() @@ -1315,7 +1298,7 @@ const toolNameToComponent: { [T in ToolName]: { const { params } = toolMessage.result return ( - { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }} @@ -1329,7 +1312,7 @@ const toolNameToComponent: { [T in ToolName]: { const commandService = accessor.get('ICommandService') const title = toolNameToTitle[toolRequest.name] const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return { commandService.executeCommand('vscode.open', toolRequest.params.uri, { preview: true }) }} /> }, @@ -1346,7 +1329,7 @@ const toolNameToComponent: { [T in ToolName]: { const { params } = toolMessage.result return ( - { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }} @@ -1360,14 +1343,11 @@ const toolNameToComponent: { [T in ToolName]: { const commandService = accessor.get('ICommandService') const title = toolNameToTitle[toolRequest.name] const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) - return { commandService.executeCommand('vscode.open', toolRequest.params.uri, { preview: true }) }} > - - + + }, resultWrapper: ({ toolMessage }) => { const accessor = useAccessor() @@ -1382,7 +1362,7 @@ const toolNameToComponent: { [T in ToolName]: { const { params } = toolMessage.result return ( - { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }} @@ -1398,7 +1378,7 @@ const toolNameToComponent: { [T in ToolName]: { const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params) const { waitForCompletion, command, proposedTerminalId } = toolRequest.params - return }, @@ -1417,29 +1397,27 @@ const toolNameToComponent: { [T in ToolName]: { const { terminalId, resolveReason, result } = toolMessage.result.value return ( - -
-
-
- {resolveReason.type === 'bgtask' ? 'Result so far:' : null} - - { - resolveReason.type === 'done' ? (resolveReason.exitCode !== 0 ? `Error: exit code ${resolveReason.exitCode}` : null) - : resolveReason.type === 'bgtask' ? null : - resolveReason.type === 'timeout' ? `(partial results; request timed out)` : - resolveReason.type === 'toofull' ? `(truncated)` - : null - } -
+ +
+ {resolveReason.type === 'bgtask' ? 'Result so far:' : null} + {result} + { + resolveReason.type === 'done' ? (resolveReason.exitCode !== 0 ? ` + Error: exit code ${resolveReason.exitCode}` : null) + : resolveReason.type === 'bgtask' ? null : + resolveReason.type === 'timeout' ? ` + (partial results; request timed out)` : + resolveReason.type === 'toofull' ? ` + (truncated)` + : null + }
- + ) } } @@ -1473,16 +1451,10 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx, isLast }: ChatBubblePr const isLastMessage = true // TODO!!! fix this if (!isLastMessage) return null const ToolRequestWrapper = toolNameToComponent[chatMessage.name].requestWrapper as React.FC<{ toolRequest: any }> // ts isnt smart enough... - return <> - - - + return + } else if (role === 'tool') { - - const title = toolNameToTitle[chatMessage.name] - // if (chatMessage.result.type === 'error') return - const ToolResultWrapper = toolNameToComponent[chatMessage.name].resultWrapper as React.FC<{ toolMessage: any }> // ts isnt smart enough... return } @@ -1692,3 +1664,4 @@ export const SidebarChat = () => {
} + diff --git a/src/vs/workbench/contrib/void/browser/terminalToolService.ts b/src/vs/workbench/contrib/void/browser/terminalToolService.ts index 9d418cfe..511a8285 100644 --- a/src/vs/workbench/contrib/void/browser/terminalToolService.ts +++ b/src/vs/workbench/contrib/void/browser/terminalToolService.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------*/ import { Disposable, IDisposable } from '../../../../base/common/lifecycle.js'; +import { removeAnsiEscapeCodes } from '../../../../base/common/strings.js'; import { registerSingleton, InstantiationType } from '../../../../platform/instantiation/common/extensions.js'; import { createDecorator } from '../../../../platform/instantiation/common/instantiation.js'; import { TerminalLocation } from '../../../../platform/terminal/common/terminal.js'; @@ -171,6 +172,11 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ console.log('res', { terminalId, didCreateTerminal, result, resolveReason }) + result = removeAnsiEscapeCodes(result) + .split('\n').slice(1, -1) // remove first and last line (first = command, last = andrewpareles/void %) + .join('\n') + + console.log('TerminalToolService: Command completed:', JSON.stringify(result)) return { terminalId, didCreateTerminal, result, resolveReason } } @@ -180,5 +186,3 @@ export class TerminalToolService extends Disposable implements ITerminalToolServ } registerSingleton(ITerminalToolService, TerminalToolService, InstantiationType.Delayed); - - diff --git a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts index 3c17853d..c6358b37 100644 --- a/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts +++ b/src/vs/workbench/contrib/void/common/toolsServiceTypes.ts @@ -137,7 +137,9 @@ export const isAToolName = (toolName: string): toolName is ToolName => { } -export const toolNamesThatRequireApproval = new Set(['create_uri', 'delete_uri', 'edit', 'terminal_command'] satisfies ToolName[]) +const toolNamesWithApproval = ['create_uri', 'delete_uri', 'edit', 'terminal_command'] as const satisfies readonly ToolName[] +export type ToolNameWithApproval = typeof toolNamesWithApproval[number] +export const toolNamesThatRequireApproval = new Set(toolNamesWithApproval) export type ToolCallParams = { 'read_file': { uri: URI, pageNumber: number },