diff --git a/src/vs/workbench/contrib/void/browser/chatThreadService.ts b/src/vs/workbench/contrib/void/browser/chatThreadService.ts
index 6cbff796..5cb20f8e 100644
--- a/src/vs/workbench/contrib/void/browser/chatThreadService.ts
+++ b/src/vs/workbench/contrib/void/browser/chatThreadService.ts
@@ -237,7 +237,228 @@ class ChatThreadService extends Disposable implements IChatThreadService {
if (!threadsStr) {
return null
}
- return this._convertThreadDataFromStorage(threadsStr);
+ const threads = this._convertThreadDataFromStorage(threadsStr);
+
+ // threads['abc'] = {
+ // id: 'abc',
+ // createdAt: new Date().toISOString(),
+ // lastModified: new Date().toISOString(),
+ // messages: [
+ // {
+ // role: 'tool',
+ // name: 'pathname_search',
+ // id: 'tool-1',
+ // paramsStr: '{"query": "hello", "pageNumber": 0}',
+ // content: '/users/andrew/void/Desktop/etc/abc.txt',
+ // result: { type: 'success', params: { queryStr: 'hello', pageNumber: 0 }, value: { uris: [URI.file('/Users/username/Downloads/helloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo.txt'), URI.file('/Users/username/Downloads/hello1.txt'), URI.file('/Users/username/Downloads/hello2.txt'), URI.file('/Users/username/Downloads/hello3.txt'), URI.file('/Users/username/hello.txt')], hasNextPage: true } },
+ // } satisfies ToolMessage<'pathname_search'>,
+ // {
+ // role: 'tool',
+ // name: 'pathname_search',
+ // id: 'tool-1',
+ // paramsStr: '{"query": "hello", "pageNumber": 0}',
+ // content: '/users/andrew/void/Desktop/etc/abc.txt',
+ // result: { type: 'success', params: { queryStr: 'hello', pageNumber: 0 }, value: { uris: [], hasNextPage: false } },
+ // } satisfies ToolMessage<'pathname_search'>,
+
+ // // {
+ // // role: 'tool_request',
+ // // name: 'pathname_search',
+ // // params: { queryStr: 'hello', pageNumber: 0 },
+ // // paramsStr: '{"query": "hello", "pageNumber": 0}',
+ // // voidToolId: 'request-1',
+ // // } satisfies ToolRequestApproval<'pathname_search'>,
+
+ // {
+ // role: 'tool',
+ // name: 'list_dir',
+ // id: 'tool-2',
+ // paramsStr: '{"uri": "/Users/username/Documents"}',
+ // content: 'Directory listing of /Users/username/Documents',
+ // result: {
+ // type: 'success',
+ // params: { rootURI: URI.file('/Users/username/Documents'), pageNumber: 1, },
+ // value: {
+ // children: [
+ // { uri: URI.file('/Users/username/Documents/file1.txt'), name: 'file1.txt', isDirectory: false, isSymbolicLink: false },
+ // { uri: URI.file('/Users/username/Documents/folder1'), name: 'folder1', isDirectory: true, isSymbolicLink: false }
+ // ],
+ // hasNextPage: true,
+ // hasPrevPage: true,
+ // itemsRemaining: 5,
+ // }
+ // },
+ // } satisfies ToolMessage<'list_dir'>,
+
+ // // {
+ // // role: 'tool_request',
+ // // name: 'list_dir',
+ // // params: { rootURI: URI.file('/Users/username/Documents'), pageNumber: 0 },
+ // // paramsStr: '{"uri": "/Users/username/Documents"}',
+ // // voidToolId: 'request-2',
+ // // } satisfies ToolRequestApproval<'list_dir'>,
+
+ // {
+ // role: 'tool',
+ // name: 'read_file',
+ // id: 'tool-3',
+ // paramsStr: '{"uri": "/Users/username/Documents/file1.txt"}',
+ // content: 'Content of file1.txt\nThis is a sample file.\nHello world!',
+ // result: {
+ // type: 'success',
+ // params: { uri: URI.file('/Users/username/Documents/file1.txt'), pageNumber: 0 },
+ // value: { fileContents: 'Content of file1.txt\nThis is a sample file.\nHello world!', hasNextPage: false }
+ // },
+ // } satisfies ToolMessage<'read_file'>,
+
+ // // {
+ // // role: 'tool_request',
+ // // name: 'read_file',
+ // // params: { uri: URI.file('/Users/username/Documents/file1.txt'), pageNumber: 0 },
+ // // paramsStr: '{"uri": "/Users/username/Documents/file1.txt"}',
+ // // voidToolId: 'request-3',
+ // // } satisfies ToolRequestApproval<'read_file'>,
+
+ // {
+ // role: 'tool',
+ // name: 'search',
+ // id: 'tool-4',
+ // paramsStr: '{"query": "function main"}',
+ // content: 'Found matches in 3 files',
+ // result: {
+ // type: 'success',
+ // params: { queryStr: 'function main', pageNumber: 0 },
+ // value: {
+ // uris: [
+ // URI.file('/Users/username/Project/main.js'),
+ // URI.file('/Users/username/Project/src/app.js'),
+ // URI.file('/Users/username/Project/test/test.js')
+ // ],
+ // hasNextPage: false
+ // }
+ // },
+ // } satisfies ToolMessage<'search'>,
+
+ // // {
+ // // role: 'tool_request',
+ // // name: 'search',
+ // // params: { queryStr: 'function main', pageNumber: 0 },
+ // // paramsStr: '{"query": "function main"}',
+ // // voidToolId: 'request-4',
+ // // } satisfies ToolRequestApproval<'search'>,
+
+ // // ---
+
+ // {
+ // role: 'tool',
+ // name: 'edit',
+ // id: 'tool-5',
+ // paramsStr: '{"uri": "/Users/username/Project/main.js", "changeDescription": "Add console.log statement"}',
+ // content: 'Successfully edited the file at /Users/username/Project/main.js',
+ // result: {
+ // type: 'success',
+ // params: { uri: URI.file('/Users/username/Project/main.js'), changeDescription: 'Add console.log statement' },
+ // value: {}
+ // },
+ // } satisfies ToolMessage<'edit'>,
+ // {
+ // role: 'tool_request',
+ // name: 'edit',
+ // params: { uri: URI.file('/Users/username/Project/main.js'), changeDescription: 'Add console.log statement' },
+ // paramsStr: '{"uri": "/Users/username/Project/main.js", "changeDescription": "Add console.log statement"}',
+ // voidToolId: 'request-5',
+ // } satisfies ToolRequestApproval<'edit'>,
+
+ // {
+ // role: 'tool',
+ // name: 'create_uri',
+ // id: 'tool-6',
+ // paramsStr: '{"uri": "/Users/username/Project/new-file.js"}',
+ // content: 'Successfully created file at /Users/username/Project/new-file.js',
+ // result: {
+ // type: 'success',
+ // params: { uri: URI.file('/Users/username/Project/new-file.js'), isFolder: false },
+ // value: {}
+ // },
+ // } satisfies ToolMessage<'create_uri'>,
+ // {
+ // role: 'tool_request',
+ // name: 'create_uri',
+ // params: { uri: URI.file('/Users/username/Project/new-file.js'), isFolder: false },
+ // paramsStr: '{"uri": "/Users/username/Project/new-file.js"}',
+ // voidToolId: 'request-6',
+ // } satisfies ToolRequestApproval<'create_uri'>,
+
+ // {
+ // role: 'tool',
+ // name: 'delete_uri',
+ // id: 'tool-7',
+ // paramsStr: '{"uri": "/Users/username/Project/old-file.js", "params": ""}',
+ // content: 'Successfully deleted file at /Users/username/Project/old-file.js',
+ // result: {
+ // type: 'success',
+ // params: { uri: URI.file('/Users/username/Project/old-file.js'), isRecursive: false, isFolder: false },
+ // value: {}
+ // },
+ // } satisfies ToolMessage<'delete_uri'>,
+ // {
+ // role: 'tool_request',
+ // name: 'delete_uri',
+ // params: { uri: URI.file('/Users/username/Project/old-file.js'), isRecursive: false, isFolder: false },
+ // paramsStr: '{"uri": "/Users/username/Project/old-file.js", "params": ""}',
+ // voidToolId: 'request-7',
+ // } satisfies ToolRequestApproval<'delete_uri'>,
+
+ // {
+ // role: 'tool',
+ // name: 'terminal_command',
+ // id: 'tool-8',
+ // paramsStr: '{"command": "npm install", "waitForCompletion": "true"}',
+ // content: 'Command executed: npm install\nAdded 123 packages in 3.5s',
+ // result: {
+ // type: 'success',
+ // params: { command: 'npm install', proposedTerminalId: '1', waitForCompletion: true },
+ // value: {
+ // terminalId: '1',
+ // didCreateTerminal: false,
+ // result: 'Added 123 packages in 3.5s',
+ // resolveReason: { type: 'done', exitCode: 0 }
+ // }
+ // },
+ // } satisfies ToolMessage<'terminal_command'>,
+ // {
+ // role: 'tool_request',
+ // name: 'terminal_command',
+ // params: { command: 'npm install', proposedTerminalId: '1', waitForCompletion: true },
+ // paramsStr: '{"command": "npm install", "waitForCompletion": "true"}',
+ // voidToolId: 'request-8',
+ // } satisfies ToolRequestApproval<'terminal_command'>,
+
+
+
+ // // Examples of error and rejected states
+ // {
+ // role: 'tool',
+ // name: 'pathname_search',
+ // id: 'tool-error',
+ // paramsStr: '{"query": "invalid**query"}',
+ // content: 'Error: Invalid search pattern',
+ // result: { type: 'error', params: { queryStr: 'invalid**query', pageNumber: 0 }, value: 'Error: Invalid search pattern' },
+ // } satisfies ToolMessage<'pathname_search'>,
+
+ // {
+ // role: 'tool',
+ // name: 'pathname_search',
+ // id: 'tool-rejected',
+ // paramsStr: '{"query": "sensitive-data"}',
+ // content: 'Tool call was rejected by the user.',
+ // result: { type: 'rejected', params: { queryStr: 'sensitive-data', pageNumber: 0 } },
+ // } satisfies ToolMessage<'pathname_search'>,
+ // ],
+ // state: defaultThreadState,
+ // }
+
+ return threads
}
private _storeAllThreads(threads: ChatThreads) {
diff --git a/src/vs/workbench/contrib/void/browser/media/void.css b/src/vs/workbench/contrib/void/browser/media/void.css
index e5e9793e..3a420737 100644
--- a/src/vs/workbench/contrib/void/browser/media/void.css
+++ b/src/vs/workbench/contrib/void/browser/media/void.css
@@ -83,7 +83,7 @@
.void-scrollable-element::-webkit-scrollbar,
.void-scrollable-element *::-webkit-scrollbar {
width: 14px !important;
- height: 14px !important;
+ height: 4px !important;
}
.void-scrollable-element::-webkit-scrollbar-track,
diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ApplyBlockHoverButtons.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ApplyBlockHoverButtons.tsx
index eb00ff52..8d75d801 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ApplyBlockHoverButtons.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ApplyBlockHoverButtons.tsx
@@ -5,6 +5,8 @@ import { isFeatureNameDisabled } from '../../../../common/voidSettingsTypes.js'
import { URI } from '../../../../../../../base/common/uri.js'
import { LucideIcon, RotateCw } from 'lucide-react'
import { Check, X, Square, Copy, Play, } from 'lucide-react'
+import { ToolContentsWrapper } from '../sidebar-tsx/SidebarChat.js'
+import { ChatMarkdownRender } from './ChatMarkdownRender.js'
enum CopyButtonText {
Idle = 'Copy',
@@ -27,7 +29,8 @@ export const IconShell1 = ({ onClick, title, Icon, disabled, className }: IconBu
disabled={disabled}
onClick={onClick}
className={`
- size-[24px]
+ size-[22px]
+ p-[4px]
flex items-center justify-center
text-sm bg-void-bg-3 text-void-fg-1
hover:brightness-110
@@ -36,28 +39,28 @@ export const IconShell1 = ({ onClick, title, Icon, disabled, className }: IconBu
${className}
`}
>
-
+
)
-export const IconShell2 = ({ onClick, title, Icon, disabled, className }: IconButtonProps) => (
-
-
-
-)
+// export const IconShell2 = ({ onClick, title, Icon, disabled, className }: IconButtonProps) => (
+//
+//
+//
+// )
const COPY_FEEDBACK_TIMEOUT = 1000 // amount of time to say 'Copied!'
@@ -230,17 +233,16 @@ export const useApplyButtonHTML = ({ codeStr, applyBoxId }: { codeStr: string, a
>
}
- const statusIndicatorHTML =
+ const statusIndicatorHTML =
return {
@@ -248,5 +250,52 @@ export const useApplyButtonHTML = ({ codeStr, applyBoxId }: { codeStr: string, a
buttonsHTML
}
+}
+
+
+
+
+
+
+export const BlockCodeApplyWrapper = ({
+ children,
+ initValue,
+ applyBoxId,
+ language,
+ canApply,
+
+}: {
+ initValue: string;
+ children: React.ReactNode;
+ applyBoxId: string;
+ canApply: boolean;
+ language: string;
+}) => {
+
+
+ const { statusIndicatorHTML, buttonsHTML } = useApplyButtonHTML({ codeStr: initValue, applyBoxId })
+
+ return
+
+ {/* header */}
+
+
+ {statusIndicatorHTML}
+
+ {language || 'text'}
+
+
+
+ {buttonsHTML}
+
+
+
+ {/* contents */}
+
+ {children}
+
+
}
diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx
index c1cd1de2..5a403ad5 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/BlockCode.tsx
@@ -4,54 +4,10 @@
*--------------------------------------------------------------------------------------*/
import { VoidCodeEditor, VoidCodeEditorProps } from '../util/inputs.js';
-import { useApplyButtonHTML } from './ApplyBlockHoverButtons.js';
-
-export const BlockCodeWithApply = ({ initValue, language, applyBoxId }: { initValue: string, language?: string, applyBoxId: string }) => {
-
- const { statusIndicatorHTML, buttonsHTML } = useApplyButtonHTML({ codeStr: initValue, applyBoxId })
-
- return (
-
-
-
-
{language || 'text'}
- {statusIndicatorHTML}
-
-
- {buttonsHTML}
-
-
-
-
-
-
- )
-}
+import { BlockCodeApplyWrapper, useApplyButtonHTML } from './ApplyBlockHoverButtons.js';
export const BlockCode = ({ ...codeEditorProps }: VoidCodeEditorProps) => {
-
const isSingleLine = !codeEditorProps.initValue.includes('\n')
-
- return (
- <>
-
-
- {/*
- {buttonsOnHover === null ? null : (
-
- )}
-
-
-
*/}
-
- >
- )
+ return
}
diff --git a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx
index 521b552d..9823f62a 100644
--- a/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx
+++ b/src/vs/workbench/contrib/void/browser/react/src/markdown/ChatMarkdownRender.tsx
@@ -5,12 +5,10 @@
import React, { JSX, useState } from 'react'
import { marked, MarkedToken, Token } from 'marked'
-import { BlockCode, BlockCodeWithApply } from './BlockCode.js'
+import { BlockCode } from './BlockCode.js'
import { convertToVscodeLang, getFirstLine, getLanguage } from '../../../../common/helpers/getLanguage.js'
-import { useApplyButtonHTML } from './ApplyBlockHoverButtons.js'
-import { useAccessor, useChatThreadsState } from '../util/services.js'
-import { Range } from '../../../../../../services/search/common/searchExtTypes.js'
-import { IRange } from '../../../../../../../base/common/range.js'
+import { BlockCodeApplyWrapper, useApplyButtonHTML } from './ApplyBlockHoverButtons.js'
+import { useAccessor } from '../util/services.js'
import { ScrollType } from '../../../../../../../editor/common/editorCommon.js'
import { URI } from '../../../../../../../base/common/uri.js'
@@ -102,7 +100,7 @@ const CodespanWithLink = ({ text, rawText, chatMessageLocation }: { text: string
export type RenderTokenOptions = { isApplyEnabled?: boolean, isLinkDetectionEnabled?: boolean }
-const RenderToken = ({ token, inPTag, chatMessageLocation, tokenIdx, ...options }: { token: Token | string, inPTag?: boolean, chatMessageLocation?: ChatMessageLocation, tokenIdx: string, } & RenderTokenOptions): JSX.Element => {
+const RenderToken = ({ token, inPTag, codeURI, chatMessageLocation, tokenIdx, ...options }: { token: Token | string, inPTag?: boolean, codeURI?: URI, chatMessageLocation?: ChatMessageLocation, tokenIdx: string, } & RenderTokenOptions): JSX.Element => {
const accessor = useAccessor()
const languageService = accessor.get('ILanguageService')
@@ -120,36 +118,45 @@ const RenderToken = ({ token, inPTag, chatMessageLocation, tokenIdx, ...options
if (t.type === "code") {
const [firstLine, remainingContents] = getFirstLine(t.text)
const firstLineIsURI = URI.isUri(firstLine)
-
- let language: string | undefined = undefined
- if (t.lang !== undefined) {
- // convert markdown language to language that vscode recognizes (eg markdown doesn't know bash but it does know shell)
- language = convertToVscodeLang(languageService, t.lang)
- }
-
- else if (!language) { // if still no lang
- if (firstLineIsURI) { // get lang from the uri
- const uri = URI.file(firstLine)
- language = getLanguage(languageService, { uri, fileContents: remainingContents ?? undefined })
- }
- else { // get lang from the contents
- language = getLanguage(languageService, { uri: null, fileContents: remainingContents ?? undefined })
- }
- }
const contents = firstLineIsURI ? (remainingContents || '') : t.text // exclude first-line URI from contents
- // TODO!!! user should only be able to apply this when the code has been closed (t.raw ends with "```")
+ // figure out langauge
+ let language: string | undefined = undefined
+ let uri: URI | undefined = undefined
+ if (t.lang) { // a language was provided. empty string is common so check truthy, not just undefined
+ uri = codeURI
+ language = convertToVscodeLang(languageService, t.lang) // convert markdown language to language that vscode recognizes (eg markdown doesn't know bash but it does know shell)
+ }
+ else { // no language provided - fallback
+ if (firstLineIsURI) { // get lang from the uri in the markdown
+ uri = codeURI ?? URI.file(firstLine)
+ language = getLanguage(languageService, { uri, fileContents: remainingContents ?? undefined })
+ }
+ else { // get lang from the given URI and contents
+ uri = codeURI
+ language = getLanguage(languageService, { uri: codeURI ?? null, fileContents: remainingContents ?? undefined })
+ }
+ }
+
if (options.isApplyEnabled && chatMessageLocation) {
+ const isCodeblockClosed = t.raw.trimEnd().endsWith('```') // user should only be able to Apply when the code has been closed (t.raw ends with "```")
+
const applyBoxId = getApplyBoxId({
threadId: chatMessageLocation.threadId,
messageIdx: chatMessageLocation.messageIdx,
tokenIdx: tokenIdx,
})
- return
+ >
+
+
}
return
-
+
}
@@ -361,7 +368,7 @@ const RenderToken = ({ token, inPTag, chatMessageLocation, tokenIdx, ...options
}
-export const ChatMarkdownRender = ({ string, inPTag = false, chatMessageLocation, ...options }: { string: string, inPTag?: boolean, chatMessageLocation: ChatMessageLocation | undefined } & RenderTokenOptions) => {
+export const ChatMarkdownRender = ({ string, inPTag = false, chatMessageLocation, ...options }: { string: string, inPTag?: boolean, codeURI?: URI, chatMessageLocation: ChatMessageLocation | undefined } & RenderTokenOptions) => {
const tokens = marked.lexer(string); // https://marked.js.org/using_pro#renderer
return (
<>
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 2427634c..f8a2cad6 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
@@ -696,8 +696,7 @@ const ToolHeaderComponent = ({
const isClickable = !!(isDropdown || onClick)
return (
-
-
+
{/* header */}
)}
-
-
-
{title}
-
{desc1}
+
+
+ {title}
+
+ {/* Fixed description with proper ellipsis */}
+ {desc1}
-
+
{desc2 &&
{desc2}
}
@@ -731,11 +732,10 @@ const ToolHeaderComponent = ({
{/* children */}
{
- {children || '(no results)'}
+ {children}
}
@@ -938,6 +938,29 @@ const UserMessageComponent = ({ chatMessage, messageIdx, isLoading }: ChatBubble
}
+
+export const ToolContentsWrapper = ({ children, className }: { children: React.ReactNode, className?: string }) => {
+ return
+}
+const ListableToolItem = ({ name, onClick, isSmall, className }: { name: string, onClick?: () => void, isSmall?: boolean, className?: string }) => {
+ return
+}
+
+
const AssistantMessageComponent = ({ chatMessage, isLoading, messageIdx, isLast }: ChatBubbleProps & { chatMessage: ChatMessage & { role: 'assistant' } }) => {
const accessor = useAccessor()
@@ -963,7 +986,6 @@ const AssistantMessageComponent = ({ chatMessage, isLoading, messageIdx, isLast
className='
text-void-fg-2
-
prose
prose-sm
break-words
@@ -1014,15 +1036,15 @@ const AssistantMessageComponent = ({ chatMessage, isLoading, messageIdx, isLast
// 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 toolNameToTitle: Record
= {
- 'read_file': 'Read file', // past tense
- 'list_dir': 'Inspected folder', // past tense
- 'pathname_search': 'Searched by file name', // past tense
- 'search': 'Searched', // past tense
- 'create_uri': 'Created file', // past tense
- 'delete_uri': 'Deleted file', // past tense
- 'edit': 'Edited file', // past tense
- 'terminal_command': 'Ran terminal command' // past tense
+const toolNameToTitle: Record = {
+ 'read_file': { past: 'Read file', current: 'Reading file', proposed: 'Read file' },
+ 'list_dir': { past: 'Inspected folder', current: 'Inspecting folder', proposed: 'Inspect folder' },
+ 'pathname_search': { past: 'Searched by file name', current: 'Searching by file name', proposed: 'Search by file name' },
+ 'search': { past: 'Searched', current: 'Searching', proposed: 'Search' },
+ 'create_uri': { past: 'Created file', current: 'Creating file', proposed: 'Create file' },
+ 'delete_uri': { past: 'Deleted file', current: 'Deleting file', proposed: 'Delete file' },
+ 'edit': { past: 'Edited file', current: 'Editing file', proposed: 'Edit file' },
+ 'terminal_command': { past: 'Ran terminal command', current: 'Running terminal command', proposed: 'Run terminal command' }
}
const toolNameToDesc = (toolName: ToolName, _toolParams: ToolCallParams[ToolName] | undefined): string => {
@@ -1128,17 +1150,17 @@ const toolNameToComponent: { [T in ToolName]: {
resultWrapper: ({ toolMessage }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const { uri } = toolMessage.result.params ?? {}
const desc1 = uri ? getBasename(uri.fsPath) : '';
const icon = null
- if (toolMessage.result.type === 'rejected') return null
+ if (toolMessage.result.type === 'rejected') return null // will never happen, not rejectable
const isError = toolMessage.result.type === 'error'
const componentParams: ToolHeaderParams = { title, desc1, isError, icon }
- if (toolMessage.result.type !== 'error') {
+ if (toolMessage.result.type === 'success') {
const { value, params } = toolMessage.result
componentParams.onClick = () => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }
if (toolMessage.result.value.hasNextPage) componentParams.desc2 = `(AI can scroll for more)`
@@ -1158,38 +1180,34 @@ const toolNameToComponent: { [T in ToolName]: {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
const explorerService = accessor.get('IExplorerService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
- if (toolMessage.result.type === 'rejected') return null
+ if (toolMessage.result.type === 'rejected') return null // will never happen, not rejectable
const isError = toolMessage.result.type === 'error'
const componentParams: ToolHeaderParams = { title, desc1, isError, icon }
- if (toolMessage.result.type !== 'error') {
+ if (toolMessage.result.type === 'success') {
const { value, params } = toolMessage.result
componentParams.numResults = value.children?.length
- componentParams.children = (value.children?.length ?? 0) === 0 ? null : <>
- {value.children?.map((child, i) => (
-
+ {!value.children || (value.children.length ?? 0) === 0 ? <>
+
+ > : <>
+ {value.children.map((child, i) => (
{
commandService.executeCommand('workbench.view.explorer');
explorerService.select(child.uri, true);
}}
- >
-
- {`${child.name}${child.isDirectory ? '/' : ''}`}
-
- ))}
- {value.hasNextPage && (
-
- {value.itemsRemaining} more items...
-
- )}
- >
+ />))}
+ {value.hasNextPage &&
+
+ }
+ >}
+
}
else {
componentParams.children = <>
@@ -1205,37 +1223,31 @@ const toolNameToComponent: { [T in ToolName]: {
resultWrapper: ({ toolMessage }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
- if (toolMessage.result.type === 'rejected') return null
+ if (toolMessage.result.type === 'rejected') return null // will never happen, not rejectable
const isError = toolMessage.result.type === 'error'
const componentParams: ToolHeaderParams = { title, desc1, isError, icon }
- if (toolMessage.result.type !== 'error') {
+ if (toolMessage.result.type === 'success') {
const { value, params } = toolMessage.result
componentParams.numResults = value.uris.length
- componentParams.children = value.uris.length === 0 ? null : <>
- {value.uris.map((uri, i) => (
- {
- commandService.executeCommand('vscode.open', uri, { preview: true })
- }}
- >
-
- {uri.fsPath.split('/').pop()}
-
- ))}
- {value.hasNextPage && (
-
- More results available...
-
- )}
- >
+ componentParams.children =
+ {value.uris.length === 0 ? <>
+
+ > : <>
+ {value.uris.map((uri, i) => ( { commandService.executeCommand('vscode.open', uri, { preview: true }) }}
+ />))}
+ {value.hasNextPage &&
+
+ }
+ >}
+
}
else {
componentParams.children = <>
@@ -1251,30 +1263,31 @@ const toolNameToComponent: { [T in ToolName]: {
resultWrapper: ({ toolMessage }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
- if (toolMessage.result.type === 'rejected') return null
+ if (toolMessage.result.type === 'rejected') return null // will never happen, not rejectable
const isError = toolMessage.result.type === 'error'
const componentParams: ToolHeaderParams = { title, desc1, isError, icon }
- if (toolMessage.result.type !== 'error') {
+ if (toolMessage.result.type === 'success') {
const { value, params } = toolMessage.result
componentParams.numResults = value.uris.length
- componentParams.children = value.uris.length === 0 ? null : <>
- {value.uris.map((uri, i) => (
-
+ {value.uris.length === 0 ? <>
+
+ > : <>
+ {value.uris.map((uri, i) => (
{ commandService.executeCommand('vscode.open', uri, { preview: true }) }}
- >
-
- {uri.fsPath.split('/').pop()}
-
- ))}
- {value.hasNextPage && (More results available...
)}
- >
+ />))}
+ {value.hasNextPage &&
+
+ }
+ >}
+
}
else {
componentParams.children = <>
@@ -1291,7 +1304,7 @@ const toolNameToComponent: { [T in ToolName]: {
requestWrapper: ({ toolRequest }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolRequest.name]
+ const title = toolNameToTitle[toolRequest.name].proposed
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
const icon = null
@@ -1306,7 +1319,7 @@ const toolNameToComponent: { [T in ToolName]: {
resultWrapper: ({ toolMessage }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
@@ -1335,7 +1348,7 @@ const toolNameToComponent: { [T in ToolName]: {
requestWrapper: ({ toolRequest, }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolRequest.name]
+ const title = toolNameToTitle[toolRequest.name].proposed
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
const icon = null
@@ -1350,7 +1363,7 @@ const toolNameToComponent: { [T in ToolName]: {
resultWrapper: ({ toolMessage }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
@@ -1378,7 +1391,7 @@ const toolNameToComponent: { [T in ToolName]: {
requestWrapper: ({ toolRequest, }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolRequest.name]
+ const title = toolNameToTitle[toolRequest.name].proposed
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
const icon = null
@@ -1386,21 +1399,22 @@ const toolNameToComponent: { [T in ToolName]: {
const componentParams: ToolHeaderParams = { title, desc1, isError, icon, }
const { params } = toolRequest
- componentParams.children =
-
{ commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}>
- {getBasename(params.uri.fsPath)}
+ componentParams.children =
+ { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }}
+ />
+
+
-
-
+
return
},
resultWrapper: ({ toolMessage }) => {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
@@ -1409,12 +1423,12 @@ const toolNameToComponent: { [T in ToolName]: {
if (toolMessage.result.type === 'success') {
const { params } = toolMessage.result
- componentParams.children =
+ componentParams.children =
componentParams.onClick = () => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }
}
else if (toolMessage.result.type === 'rejected') {
const { params } = toolMessage.result
- componentParams.children =
+ componentParams.children =
componentParams.onClick = () => { commandService.executeCommand('vscode.open', params.uri, { preview: true }) }
}
else if (toolMessage.result.type === 'error') {
@@ -1431,7 +1445,7 @@ const toolNameToComponent: { [T in ToolName]: {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
const terminalToolsService = accessor.get('ITerminalToolService')
- const title = toolNameToTitle[toolRequest.name]
+ const title = toolNameToTitle[toolRequest.name].proposed
const desc1 = toolNameToDesc(toolRequest.name, toolRequest.params)
const icon = null
@@ -1451,7 +1465,7 @@ const toolNameToComponent: { [T in ToolName]: {
const accessor = useAccessor()
const commandService = accessor.get('ICommandService')
const terminalToolsService = accessor.get('ITerminalToolService')
- const title = toolNameToTitle[toolMessage.name]
+ const title = toolNameToTitle[toolMessage.name].past
const desc1 = toolNameToDesc(toolMessage.name, toolMessage.result.params)
const icon = null
@@ -1529,7 +1543,8 @@ const ChatBubble = ({ chatMessage, isLoading, messageIdx, isLast }: ChatBubblePr
}
else if (role === 'tool_request') {
const ToolRequestWrapper = toolNameToComponent[chatMessage.name].requestWrapper as React.FC<{ toolRequest: any }> // ts isnt smart enough...
- if (!isLast) return null
+ // if (!isLast) return null
+ if (!ToolRequestWrapper) return null
return <>
diff --git a/src/vs/workbench/contrib/void/browser/toolsService.ts b/src/vs/workbench/contrib/void/browser/toolsService.ts
index d740a26d..c6c8a7f8 100644
--- a/src/vs/workbench/contrib/void/browser/toolsService.ts
+++ b/src/vs/workbench/contrib/void/browser/toolsService.ts
@@ -75,7 +75,7 @@ const directoryResultToString = (params: ToolCallParams['list_dir'], result: Too
let output = '';
const entries = result.children;
- if (!result.hasPrevPage) {
+ if (!result.hasPrevPage) { // is first page
output += `${params.rootURI}\n`;
}
@@ -351,7 +351,7 @@ export class ToolsService implements IToolsService {
},
list_dir: (params, result) => {
const dirTreeStr = directoryResultToString(params, result)
- return dirTreeStr + nextPageStr(result.hasNextPage)
+ return dirTreeStr // + nextPageStr(result.hasNextPage) // already handles num results remaining
},
pathname_search: (params, result) => {
return result.uris.map(uri => uri.fsPath).join('\n') + nextPageStr(result.hasNextPage)
diff --git a/src/vs/workbench/contrib/void/common/prompt/prompts.ts b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
index 806e8468..067fc649 100644
--- a/src/vs/workbench/contrib/void/common/prompt/prompts.ts
+++ b/src/vs/workbench/contrib/void/common/prompt/prompts.ts
@@ -14,8 +14,9 @@ import { CodeSelection, FileSelection, StagingSelectionItem } from '../chatThrea
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. \
-Typically the best description you can give here 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]}. \
+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.\
+The model does not have ANY context except the file content and this description, so make sure to include all necessary information to make the change here.\
+Typically the best description you can give is a 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]}. \
Do NOT output the whole file here if possible, and try to write as LITTLE code as needed to describe the change.`
@@ -29,22 +30,23 @@ The user's system information is as follows:
- ${os}
- Open workspace(s): ${workspaces.join(', ') || 'NO WORKSPACE OPEN'}
${(mode === 'agent' || mode === 'gather') && runningTerminalIds.length !== 0 ? `\
-- Running terminal IDs: ${runningTerminalIds.join(', ')}
+- Existing terminal IDs: ${runningTerminalIds.join(', ')}
`: '\n'}
${mode === 'agent' || mode === 'gather' /* tool use */ ? `\
You will be given tools you can call.
-- Only use tools if they help you accomplish the user's goal. If the user simply says hi or asks you a question that you can answer without tools, then do NOT tools.
-- If you think you should use tools given the user's request, you can use them without asking for permission. Feel free to use tools to gather context, understand the codebase, ${mode === 'agent' ? 'edit files, ' : ''}etc.
-- NEVER refer to a tool by name when speaking with the user. For example, do NOT say to the user "I'm going to use \`list_dir\`". Instead, say "I'm going to list all files in ___ directory", etc. Do not refer to "pages" of results, just say you're getting more results.
-- Some tools only work if the user has a workspace open. ${mode === 'gather' ? '' : `
-- NEVER modify a file outside one of the the user's workspaces without confirmation from the user.`}
+- Only use tools if they help you accomplish the user's goal. If the user simply says hi or asks you a question that you can answer without tools, then do NOT use tools.
+- If you think you should use tools, you do not need to ask for permission. Feel free to call tools whenever you'd like. You can use them to understand the codebase, ${mode === 'agent' ? 'run terminal commands, edit files, ' : 'gather relevant files and information, '}etc.
+- NEVER refer to a tool by name when speaking with the user (NEVER say something like "I'm going to use \`tool_name\`"). Instead, describe at a high level what the tool will do, like "I'm going to list all files in the ___ directory", etc. Also do not refer to "pages" of results, just say you're getting more results.
+- Some tools only work if the user has a workspace open.${mode === 'agent' ? `
+- NEVER modify a file outside the user's workspace(s) without permission from the user.` : ''}
\
`: `\
You're allowed to ask for more context. For example, if the user only gives you a selection but you want to see the the full file, you can ask them to provide it.\
`}
${mode === 'agent' /* code blocks */ ? `\
-If you have a change to make, you should almost always use a tool to edit the file. Even if you don't (e.g. if the user asks you not to), you should still NEVER re-write the entire file for the user. Instead, you should write comments like "// ... existing code" to indicate how to change the existing code. \
+- Prioritize editing files and running commands over simply making suggestions.
+- Prioritize taking as many steps as you need to complete your request over stopping early.\
`: `\
If you think it's appropriate to suggest an edit to a file, then you must describe your suggestion in CODE BLOCK(S) (wrapped in triple backticks).
- The first line of the code block must be the FULL PATH of the file you want to change. If the path does not already exist, it will be created.
@@ -53,8 +55,8 @@ If you think it's appropriate to suggest an edit to a file, then you must descri
- Do NOT re-write the entire file in the code block(s). Instead, write comments like "// ... existing code" to indicate how to change the existing code.`}
Misc:
-- Always wrap any code you produce in triple backticks.
-\
+- Do not make things up.
+- Always wrap any code you produce in triple backticks, and specify a language if possible. For example, ${tripleTick[0]}typescript\n...\n${tripleTick[1]}.\
`