Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 54 additions & 23 deletions ui/desktop/src/components/BaseChat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,6 @@ function BaseChatContent({
});

useEffect(() => {
// Log all messages when the component first mounts
window.electron.logInfo(
'Initial messages when resuming session: ' + JSON.stringify(chat.messages, null, 2)
);
Expand Down Expand Up @@ -414,28 +413,60 @@ function BaseChatContent({
</SearchView>
)}

{error && (
<div className="flex flex-col items-center justify-center p-4">
<div className="text-red-700 dark:text-red-300 bg-red-400/50 p-3 rounded-lg mb-2">
{error.message || 'Honk! Goose experienced an error while responding'}
</div>
<div
className="px-3 py-2 mt-2 text-center whitespace-nowrap cursor-pointer text-textStandard border border-borderSubtle hover:bg-bgSubtle rounded-full inline-block transition-all duration-150"
onClick={async () => {
// Find the last user message
const lastUserMessage = messages.reduceRight(
(found, m) => found || (m.role === 'user' ? m : null),
null as Message | null
);
if (lastUserMessage) {
append(lastUserMessage);
}
}}
>
Retry Last Message
</div>
</div>
)}
{error &&
!(error as Error & { isTokenLimitError?: boolean }).isTokenLimitError && (
<>
<div className="flex flex-col items-center justify-center p-4">
<div className="text-red-700 dark:text-red-300 bg-red-400/50 p-3 rounded-lg mb-2">
{error.message || 'Honk! Goose experienced an error while responding'}
</div>

{/* Expandable Error Details */}
<details className="w-full max-w-2xl mb-2">
<summary className="text-xs text-textSubtle cursor-pointer hover:text-textStandard transition-colors">
Error details
</summary>
<div className="mt-2 p-3 bg-bgSubtle border border-borderSubtle rounded-lg text-xs font-mono text-textStandard">
<div className="mb-2">
<strong>Error Type:</strong> {error.name || 'Unknown'}
</div>
<div className="mb-2">
<strong>Message:</strong> {error.message || 'No message'}
</div>
{error.stack && (
<div>
<strong>Stack Trace:</strong>
<pre className="mt-1 whitespace-pre-wrap text-xs overflow-x-auto">
{error.stack}
</pre>
</div>
)}
</div>
</details>

{/* Regular retry button for non-token-limit errors */}
<div
className="px-3 py-2 mt-2 text-center whitespace-nowrap cursor-pointer text-textStandard border border-borderSubtle hover:bg-bgSubtle rounded-full inline-block transition-all duration-150"
onClick={async () => {
// Find the last user message
const lastUserMessage = messages.reduceRight(
(found, m) => found || (m.role === 'user' ? m : null),
null as Message | null
);
if (lastUserMessage) {
append(lastUserMessage);
}
}}
>
Retry Last Message
</div>
</div>
</>
)}

{/* Token limit errors should be handled by ContextHandler, not shown here */}
{error &&
(error as Error & { isTokenLimitError?: boolean }).isTokenLimitError && <></>}
<div className="block h-8" />
</>
) : showPopularTopics ? (
Expand Down
17 changes: 17 additions & 0 deletions ui/desktop/src/hooks/useChatEngine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,23 @@ export const useChatEngine = ({

onMessageStreamFinish?.();
},
onError: (error) => {
console.log(
'CHAT ENGINE RECEIVED ERROR FROM MESSAGE STREAM:',
JSON.stringify(
{
errorMessage: error.message,
errorName: error.name,
isTokenLimitError: (error as Error & { isTokenLimitError?: boolean }).isTokenLimitError,
errorStack: error.stack,
timestamp: new Date().toISOString(),
chatId: chat.id,
},
null,
2
)
);
},
});

// Wrap append to store messages in global history (if enabled)
Expand Down
50 changes: 47 additions & 3 deletions ui/desktop/src/hooks/useMessageStream.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,8 +323,45 @@ export function useMessageStream({
break;
}

case 'Error':
throw new Error(parsedEvent.error);
case 'Error': {
// Check if this is a token limit error (more specific detection)
const errorMessage = parsedEvent.error;
const isTokenLimitError =
errorMessage &&
((errorMessage.toLowerCase().includes('token') &&
errorMessage.toLowerCase().includes('limit')) ||
(errorMessage.toLowerCase().includes('context') &&
errorMessage.toLowerCase().includes('length') &&
errorMessage.toLowerCase().includes('exceeded')));

// If this is a token limit error, create a contextLengthExceeded message instead of throwing
if (isTokenLimitError) {
const contextMessage: Message = {
id: `context-${Date.now()}`,
role: 'assistant',
created: Math.floor(Date.now() / 1000),
content: [
{
type: 'contextLengthExceeded',
msg: errorMessage,
},
],
display: true,
sendToLLM: false,
};

currentMessages = [...currentMessages, contextMessage];
mutate(currentMessages, false);

// Clear any existing error state since we handled this as a context message
setError(undefined);
break; // Don't throw error, just add the message
}

// For non-token-limit errors, still throw the error
const error = new Error(parsedEvent.error);
throw error;
}

case 'Finish': {
// Call onFinish with the last message if available
Expand Down Expand Up @@ -371,6 +408,11 @@ export function useMessageStream({
if (onError && e instanceof Error) {
onError(e);
}
// Don't re-throw here, let the error be handled by the outer catch
// Instead, set the error state directly
if (e instanceof Error) {
setError(e);
}
}
}
}
Expand All @@ -381,14 +423,16 @@ export function useMessageStream({
if (onError) {
onError(e);
}
// Re-throw the error so it gets caught by sendRequest and sets the error state
throw e;
}
} finally {
reader.releaseLock();
}

return currentMessages;
},
[mutate, onFinish, onError, forceUpdate]
[mutate, onFinish, onError, forceUpdate, setError]
);

// Send a request to the server
Expand Down
Loading