mirror of
https://github.com/voideditor/void
synced 2026-05-24 01:48:25 +00:00
improved error handling
This commit is contained in:
parent
51280d4e77
commit
1d5fef43c1
4 changed files with 68 additions and 38 deletions
18
src/vs/workbench/contrib/void/browser/getCmdKey.ts
Normal file
18
src/vs/workbench/contrib/void/browser/getCmdKey.ts
Normal file
|
|
@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -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<string | null> => {
|
||||
|
|
@ -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<Error | string | null>(null)
|
||||
|
||||
|
||||
|
||||
|
|
@ -338,9 +339,11 @@ export const SidebarChat = () => {
|
|||
</div>
|
||||
|
||||
{/* error message */}
|
||||
{!latestError ? null : <div>
|
||||
{latestError}
|
||||
</div>}
|
||||
{!latestError ? null :
|
||||
<ErrorDisplay
|
||||
error={latestError}
|
||||
onDismiss={() => { setLatestError(null) }}
|
||||
/>}
|
||||
</div>
|
||||
</>
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<string, any> };
|
||||
|
||||
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 && (
|
||||
<div>
|
||||
<span className="font-semibold text-red-800">Additional Information:</span>
|
||||
<pre className="mt-1 text-sm text-red-700 overflow-x-auto">
|
||||
{JSON.stringify(details.additional, null, 2)}
|
||||
<pre className="mt-1 text-sm text-red-700 overflow-x-auto whitespace-pre-wrap">
|
||||
{Object.keys(details.additional).map(key => `${key}:\n${details.additional[key]}`).join('\n')}
|
||||
</pre>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -124,5 +142,3 @@ const ErrorDisplay = ({
|
|||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ErrorDisplay;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue