From 1d5fef43c150d200826d60f81333ab4e648f6b50 Mon Sep 17 00:00:00 2001 From: Andrew Pareles Date: Sat, 23 Nov 2024 16:05:26 -0800 Subject: [PATCH] improved error handling --- .../contrib/void/browser/getCmdKey.ts | 18 +++++++++ .../react/src/sidebar-tsx/SidebarChat.tsx | 13 ++++--- .../browser/react/src/util/ErrorDisplay.tsx | 38 +++++++++++++------ .../browser/react/src/util/sendLLMMessage.tsx | 37 ++++++++---------- 4 files changed, 68 insertions(+), 38 deletions(-) create mode 100644 src/vs/workbench/contrib/void/browser/getCmdKey.ts diff --git a/src/vs/workbench/contrib/void/browser/getCmdKey.ts b/src/vs/workbench/contrib/void/browser/getCmdKey.ts new file mode 100644 index 00000000..76344138 --- /dev/null +++ b/src/vs/workbench/contrib/void/browser/getCmdKey.ts @@ -0,0 +1,18 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Glass Devtools, Inc. All rights reserved. + * Void Editor additions licensed under the AGPLv3 License. + *--------------------------------------------------------------------------------------------*/ + +import { OperatingSystem, OS } from '../../../../base/common/platform.js'; + +export function getCmdKey(): string { + if (OS === OperatingSystem.Macintosh) { + return '⌘'; + } else { + return 'Ctrl'; + } +} + + + + 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 3b0dffe6..888a3357 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,8 +17,9 @@ import { IModelService } from '../../../../../../../editor/common/services/model import { URI } from '../../../../../../../base/common/uri.js'; import { EndOfLinePreference } from '../../../../../../../editor/common/model.js'; import { IDisposable } from '../../../../../../../base/common/lifecycle.js'; +import { ErrorDisplay } from '../util/ErrorDisplay.js'; - +// import { } from '@vscode/webview-ui-toolkit/react'; // read files from VSCode const VSReadFile = async (modelService: IModelService, uri: URI): Promise => { @@ -176,7 +177,7 @@ export const SidebarChat = () => { const [isLoading, setIsLoading] = useState(false) const abortFnRef = useRef<(() => void) | null>(null) - const [latestError, setLatestError] = useState('') + const [latestError, setLatestError] = useState(null) @@ -338,9 +339,11 @@ export const SidebarChat = () => { {/* error message */} - {!latestError ? null :
- {latestError} -
} + {!latestError ? null : + { setLatestError(null) }} + />} } diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/ErrorDisplay.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/ErrorDisplay.tsx index bd5240bb..db59bff6 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/ErrorDisplay.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/ErrorDisplay.tsx @@ -1,21 +1,39 @@ import React, { useState } from 'react'; import { AlertCircle, ChevronDown, ChevronUp, X } from 'lucide-react'; -import { } from '@vscode/webview-ui-toolkit/react'; +import { getCmdKey } from '../../../getCmdKey.js'; + +const opaqueMessage = `\ +Unfortunately, Void can't see the full error. However, you should be able to find more details by pressing ${getCmdKey()}+Shift+P, typing "Toggle Developer Tools", and looking at the console.\n +This error often means you have an incorrect API key. If you're self-hosting your own server, it might mean your CORS headers are off, and you should make sure your server's response has the header "Access-Control-Allow-Origins" set to "*", or at least allows "vscode-file://vscode-app".` // Get detailed error information -const getErrorDetails = (error: any) => { +const getErrorDetails = (error: unknown) => { let details: { message: string, name: string, stack: string | null, cause: string | null, code: string | null, additional: Record }; - const e = error instanceof Error ? error : new Error(String(error)); + let e: Error & { [other: string]: undefined | any } + + + + // If fetch() fails, it gives an opaque message. We add extra details to the error. + if ((error instanceof Error) && (error.cause + '').includes('TypeError: Failed to fetch')) { + e = error as any + e.voidMessage = opaqueMessage + } + else if (error instanceof Error) { + e = error + } + else { + e = new Error(String(error)) + } details = { - message: e.message || String(e), name: e.name || 'Error', + message: e.message || String(e), stack: e.stack || null, cause: e.cause ? String(e.cause) : null, - code: (e as any).code || null, + code: e.code || null, additional: {} } @@ -29,13 +47,13 @@ const getErrorDetails = (error: any) => { -const ErrorDisplay = ({ +export const ErrorDisplay = ({ error, onDismiss = null, showDismiss = true, className = '' }: { - error: Error, + error: Error | string, onDismiss: (() => void) | null, showDismiss?: boolean, className?: string @@ -105,8 +123,8 @@ const ErrorDisplay = ({ {Object.keys(details.additional).length > 0 && (
Additional Information: -
-								{JSON.stringify(details.additional, null, 2)}
+							
+								{Object.keys(details.additional).map(key => `${key}:\n${details.additional[key]}`).join('\n')}
 							
)} @@ -124,5 +142,3 @@ const ErrorDisplay = ({ ); }; - -export default ErrorDisplay; diff --git a/src/vs/workbench/contrib/void/browser/react/src/util/sendLLMMessage.tsx b/src/vs/workbench/contrib/void/browser/react/src/util/sendLLMMessage.tsx index 039c16c9..d40966ef 100644 --- a/src/vs/workbench/contrib/void/browser/react/src/util/sendLLMMessage.tsx +++ b/src/vs/workbench/contrib/void/browser/react/src/util/sendLLMMessage.tsx @@ -25,7 +25,7 @@ type SendLLMMessageFnTypeInternal = (params: { messages: LLMMessage[]; onText: OnText; onFinalMessage: OnFinalMessage; - onError: (error: string) => void; + onError: (error: Error | string) => void; voidConfig: VoidConfig; _setAborter: (aborter: () => void) => void; @@ -35,7 +35,7 @@ type SendLLMMessageFnTypeExternal = (params: { messages: LLMMessage[]; onText: OnText; onFinalMessage: (fullText: string) => void; - onError: (error: string) => void; + onError: (error: Error | string) => void; voidConfig: VoidConfig | null; abortRef: AbortRef; @@ -92,7 +92,7 @@ const sendAnthropicMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFi onError('Invalid API key.') } else { - onError(error.message) + onError(error) } }) @@ -136,13 +136,8 @@ const sendGeminiMsg: SendLLMMessageFnTypeInternal = async ({ messages, onText, o onFinalMessage(fullText); }) .catch((error) => { - if (error instanceof GoogleGenerativeAIFetchError) { - if (error.status === 400) { - onError('Invalid API key.'); - } - else { - onError(`${error.name}:\n${error.message}`); - } + if (error instanceof GoogleGenerativeAIFetchError && error.status === 400) { + onError('Invalid API key.'); } else { onError(error); @@ -197,13 +192,8 @@ const sendOpenAIMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFinal }) // when error/fail - this catches errors of both .create() and .then(for await) .catch(error => { - if (error instanceof OpenAI.APIError) { - if (error.status === 401) { - onError('Invalid API key.'); - } - else { - onError(`${error.name}:\n${error.message}`); - } + if (error instanceof OpenAI.APIError && error.status === 401) { + onError('Invalid API key.'); } else { onError(error); @@ -297,8 +287,8 @@ const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFin } }) - .catch(e => { - onError(e) + .catch(error => { + onError(error) }); } @@ -307,6 +297,7 @@ const sendGreptileMsg: SendLLMMessageFnTypeInternal = ({ messages, onText, onFin + export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ messages, onText: onText_, @@ -350,7 +341,8 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ onFinalMessage_(fullText) } - const onError = (error: string) => { + const onError = (error: Error | string) => { + console.error('sendLLMMessage onError:', error) if (_didAbort) return captureChatEvent(`${loggingName} - Error`, { error }) onError_(error) @@ -391,8 +383,9 @@ export const sendLLMMessage: SendLLMMessageFnTypeExternal = ({ } catch (e) { - onError(`Unexpected Error in sendLLMMessage: ${e}`); - (_aborter as any)?.() + if (e instanceof Error) { onError(e) } + else { onError(`Unexpected Error in sendLLMMessage: ${e}`); } + ; (_aborter as any)?.() _didAbort = true }