From 664428c8f02798fe9b27906bd83130c733a91c3e Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Wed, 16 Apr 2025 18:09:03 -0700 Subject: [PATCH] add download chat buttons --- .../src/markdown/ApplyBlockHoverButtons.tsx | 10 ++-- .../react/src/sidebar-tsx/SidebarChat.tsx | 51 +++++++++++++++++-- .../void/browser/react/src/util/services.tsx | 2 + 3 files changed, 53 insertions(+), 10 deletions(-) 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 7082d59b..1b1d7e44 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 @@ -69,7 +69,7 @@ export const IconShell1 = ({ onClick, Icon, disabled, className, ...props }: Ico const COPY_FEEDBACK_TIMEOUT = 1500 // amount of time to say 'Copied!' -export const CopyButton = ({ codeStr }: { codeStr: string }) => { +export const CopyButton = ({ codeStr, toolTipName }: { codeStr: string | (() => Promise | string), toolTipName: string }) => { const accessor = useAccessor() const metricsService = accessor.get('IMetricsService') @@ -83,8 +83,8 @@ export const CopyButton = ({ codeStr }: { codeStr: string }) => { }, COPY_FEEDBACK_TIMEOUT) }, [copyButtonText]) - const onCopy = useCallback(() => { - clipboardService.writeText(codeStr) + const onCopy = useCallback(async () => { + clipboardService.writeText(typeof codeStr === 'string' ? codeStr : await codeStr()) .then(() => { setCopyButtonText(CopyButtonText.Copied) }) .catch(() => { setCopyButtonText(CopyButtonText.Error) }) metricsService.capture('Copy Code', { length: codeStr.length }) // capture the length only @@ -93,7 +93,7 @@ export const CopyButton = ({ codeStr }: { codeStr: string }) => { return } @@ -374,7 +374,7 @@ export const BlockCodeApplyWrapper = ({
- {currStreamState === 'idle-no-changes' && } + {currStreamState === 'idle-no-changes' && }
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 0cefd52d..7eeacb64 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 @@ -17,10 +17,10 @@ import { ModelDropdown, } from '../void-settings-tsx/ModelDropdown.js'; import { SidebarThreadSelector } from './SidebarThreadSelector.js'; import { VOID_CTRL_L_ACTION_ID } from '../../../actionIDs.js'; import { VOID_OPEN_SETTINGS_ACTION_ID } from '../../../voidSettingsPane.js'; -import { ChatMode, FeatureName, isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js'; +import { ChatMode, displayInfoOfProviderName, FeatureName, isFeatureNameDisabled } from '../../../../../../../workbench/contrib/void/common/voidSettingsTypes.js'; import { WarningBox } from '../void-settings-tsx/WarningBox.js'; import { getModelCapabilities, getIsReasoningEnabledState } from '../../../../common/modelCapabilities.js'; -import { AlertTriangle, Ban, Check, ChevronRight, Dot, FileIcon, Pencil, Undo, Undo2, X, Flag } from 'lucide-react'; +import { AlertTriangle, Ban, Check, ChevronRight, Dot, FileIcon, Pencil, Undo, Undo2, X, Flag, Copy as CopyIcon } from 'lucide-react'; import { ChatMessage, CheckpointEntry, StagingSelectionItem, ToolMessage } from '../../../../common/chatThreadServiceTypes.js'; import { LintErrorItem, ToolCallParams, ToolNameWithApproval } from '../../../../common/toolsServiceTypes.js'; import { ApplyButtonsHTML, CopyButton, IconShell1, JumpToFileButton, JumpToTerminalButton, StatusIndicator, StatusIndicatorForApplyButton, useApplyButtonState } from '../markdown/ApplyBlockHoverButtons.js'; @@ -1390,7 +1390,7 @@ const EditToolHeaderButtons = ({ applyBoxId, uri, codeStr }: { applyBoxId: strin - {currStreamState === 'idle-no-changes' && } + {currStreamState === 'idle-no-changes' && } } @@ -1578,11 +1578,12 @@ const toolNameToComponent: { [T in ToolName]: { resultWrapper: ResultWrapper, const componentParams: ToolHeaderParams = { title, desc1, isError, icon } if (toolMessage.type === 'success') { - const { params, result } = toolMessage + const { params, result, rawParams } = toolMessage componentParams.numResults = result.uris.length componentParams.hasNextPage = result.hasNextPage componentParams.children = result.uris.length === 0 ? undefined : + {rawParams.search_in_folder ? `Search in ${rawParams.search_in_folder}` : null} {result.uris.map((uri, i) => (, const componentParams: ToolHeaderParams = { title, desc1, isError, icon } if (toolMessage.type === 'success') { - const { params, result } = toolMessage + const { params, result, rawParams } = toolMessage componentParams.numResults = result.uris.length componentParams.hasNextPage = result.hasNextPage componentParams.children = result.uris.length === 0 ? undefined : + {rawParams.search_in_folder ? `Search in ${rawParams.search_in_folder}` : null} {result.uris.map((uri, i) => ( { const accessor = useAccessor() const editCodeService = accessor.get('IEditCodeService') const commandService = accessor.get('ICommandService') + const chatThreadsService = accessor.get('IChatThreadService') const chatThreadsState = useChatThreadsState() const chatThreadsStreamState = useChatThreadsStreamState(chatThreadsState.currentThreadId) + const settingsState = useSettingsState() + const convertService = accessor.get('IConvertToLLMMessageService') + + + + const currentThread = chatThreadsService.getCurrentThread() + const chatMode = settingsState.globalSettings.chatMode + const modelSelection = settingsState.modelSelectionOfFeature?.Chat ?? null + + const copyChatButton = { + const { messages } = await convertService.prepareLLMChatMessages({ + chatMessages: currentThread.messages, + chatMode, + modelSelection, + }) + return JSON.stringify(messages, null, 2) + }} + toolTipName={modelSelection === null ? 'Copy As Messages Payload' : `Copy As ${displayInfoOfProviderName(modelSelection.providerName).title} Payload`} + /> + + const copyChatButton2 = { + return JSON.stringify(currentThread.messages, null, 2) + }} + toolTipName={`Copy As Void Chat`} + /> + + // ( + // + // ) + const [fileDetailsOpenedState, setFileDetailsOpenedState] = useState<'auto-opened' | 'auto-closed' | 'user-opened' | 'user-closed'>('auto-closed'); const isFileDetailsOpened = fileDetailsOpenedState === 'auto-opened' || fileDetailsOpenedState === 'user-opened'; diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx index ab0e61ee..dc8dcdcc 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/services.tsx @@ -48,6 +48,7 @@ import { IVoidCommandBarService } from '../../../voidCommandBarService.js' import { INativeHostService } from '../../../../../../../platform/native/common/native.js'; import { IEditCodeService } from '../../../editCodeServiceInterface.js' import { IToolsService } from '../../../toolsService.js' +import { IConvertToLLMMessageService } from '../../../convertToLLMMessageService.js' // normally to do this you'd use a useEffect that calls .onDidChangeState(), but useEffect mounts too late and misses initial state changes @@ -217,6 +218,7 @@ const getReactAccessor = (accessor: ServicesAccessor) => { IVoidCommandBarService: accessor.get(IVoidCommandBarService), INativeHostService: accessor.get(INativeHostService), IToolsService: accessor.get(IToolsService), + IConvertToLLMMessageService: accessor.get(IConvertToLLMMessageService), } as const return reactAccessor